1 /*
2  * %CopyrightBegin%
3  *
4  * Copyright Ericsson AB 2020-2020. All Rights Reserved.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  * %CopyrightEnd%
19  */
20 
21 #include "beam_asm.hpp"
22 
23 extern "C"
24 {
25 #include "big.h"
26 }
27 
emit_fload(const ArgVal & Src,const ArgVal & Dst)28 void BeamModuleAssembler::emit_fload(const ArgVal &Src, const ArgVal &Dst) {
29     /* {thing_word,double} */
30     mov_arg(ARG1, Src);
31 
32     x86::Gp boxed_ptr = emit_ptr_val(ARG1, ARG1);
33     a.mov(ARG1, emit_boxed_val(boxed_ptr, sizeof(Eterm)));
34     a.mov(getArgRef(Dst), ARG1);
35 }
36 
emit_fstore(const ArgVal & Src,const ArgVal & Dst)37 void BeamModuleAssembler::emit_fstore(const ArgVal &Src, const ArgVal &Dst) {
38     a.mov(ARG1, getArgRef(Src));
39 
40     /* {thing_word,double} */
41     a.mov(x86::qword_ptr(HTOP), imm(HEADER_FLONUM));
42     a.mov(x86::qword_ptr(HTOP, sizeof(Eterm)), ARG1);
43 
44     a.lea(ARG1, x86::qword_ptr(HTOP, make_float(0)));
45     mov_arg(Dst, ARG1);
46 
47     a.add(HTOP, imm(FLOAT_SIZE_OBJECT * sizeof(Eterm)));
48 }
49 
handle_fconv(Eterm src,double * dst)50 static int handle_fconv(Eterm src, double *dst) {
51     if (is_small(src)) {
52         *dst = (double)signed_val(src);
53     } else if (is_float(src)) {
54         GET_DOUBLE(src, *(FloatDef *)dst);
55     } else if (is_big(src)) {
56         if (big_to_double(src, dst) < 0) {
57             return 1;
58         }
59     } else {
60         return 1;
61     }
62 
63     return 0;
64 }
65 
emit_fconv(const ArgVal & Src,const ArgVal & Dst)66 void BeamModuleAssembler::emit_fconv(const ArgVal &Src, const ArgVal &Dst) {
67     Label next = a.newLabel();
68 
69     mov_arg(ARG1, Src);
70     a.lea(ARG2, getArgRef(Dst));
71 
72     emit_enter_runtime();
73 
74     runtime_call<2>(handle_fconv);
75 
76     emit_leave_runtime();
77 
78     a.test(RET, RET);
79     a.short_().je(next);
80 
81     emit_error(EXC_BADARITH);
82 
83     a.bind(next);
84 }
85 
emit_check_float(Label next,x86::Xmm value)86 void BeamModuleAssembler::emit_check_float(Label next, x86::Xmm value) {
87     a.movsd(x86::xmm2, value);
88     a.movsd(x86::xmm1, x86::qword_ptr(floatMax));
89     a.andpd(x86::xmm2, x86::xmmword_ptr(floatSignMask));
90     a.ucomisd(x86::xmm1, x86::xmm2);
91     a.short_().jnb(next);
92 
93     emit_error(EXC_BADARITH);
94 }
95 
emit_i_fadd(const ArgVal & LHS,const ArgVal & RHS,const ArgVal & Dst)96 void BeamModuleAssembler::emit_i_fadd(const ArgVal &LHS,
97                                       const ArgVal &RHS,
98                                       const ArgVal &Dst) {
99     Label next = a.newLabel();
100 
101     a.movsd(x86::xmm0, getArgRef(LHS));
102     a.movsd(x86::xmm1, getArgRef(RHS));
103     a.addpd(x86::xmm0, x86::xmm1);
104 
105     emit_check_float(next, x86::xmm0);
106 
107     a.bind(next);
108     a.movsd(getArgRef(Dst), x86::xmm0);
109 }
110 
emit_i_fsub(const ArgVal & LHS,const ArgVal & RHS,const ArgVal & Dst)111 void BeamModuleAssembler::emit_i_fsub(const ArgVal &LHS,
112                                       const ArgVal &RHS,
113                                       const ArgVal &Dst) {
114     Label next = a.newLabel();
115 
116     a.movsd(x86::xmm0, getArgRef(LHS));
117     a.movsd(x86::xmm1, getArgRef(RHS));
118     a.subpd(x86::xmm0, x86::xmm1);
119 
120     emit_check_float(next, x86::xmm0);
121 
122     a.bind(next);
123     a.movsd(getArgRef(Dst), x86::xmm0);
124 }
125 
emit_i_fmul(const ArgVal & LHS,const ArgVal & RHS,const ArgVal & Dst)126 void BeamModuleAssembler::emit_i_fmul(const ArgVal &LHS,
127                                       const ArgVal &RHS,
128                                       const ArgVal &Dst) {
129     Label next = a.newLabel();
130 
131     a.movsd(x86::xmm0, getArgRef(LHS));
132     a.movsd(x86::xmm1, getArgRef(RHS));
133     a.mulpd(x86::xmm0, x86::xmm1);
134 
135     emit_check_float(next, x86::xmm0);
136 
137     a.bind(next);
138     a.movsd(getArgRef(Dst), x86::xmm0);
139 }
140 
emit_i_fdiv(const ArgVal & LHS,const ArgVal & RHS,const ArgVal & Dst)141 void BeamModuleAssembler::emit_i_fdiv(const ArgVal &LHS,
142                                       const ArgVal &RHS,
143                                       const ArgVal &Dst) {
144     Label next = a.newLabel();
145 
146     a.movsd(x86::xmm0, getArgRef(LHS));
147     a.movsd(x86::xmm1, getArgRef(RHS));
148     a.divpd(x86::xmm0, x86::xmm1);
149 
150     emit_check_float(next, x86::xmm0);
151 
152     a.bind(next);
153     a.movsd(getArgRef(Dst), x86::xmm0);
154 }
155 
emit_i_fnegate(const ArgVal & Src,const ArgVal & Dst)156 void BeamModuleAssembler::emit_i_fnegate(const ArgVal &Src, const ArgVal &Dst) {
157     Label next = a.newLabel();
158 
159     /* xmm0 = 0.0 */
160     a.psubd(x86::xmm0, x86::xmm0);
161     a.movsd(x86::xmm1, getArgRef(Src));
162     a.subpd(x86::xmm0, x86::xmm1);
163 
164     emit_check_float(next, x86::xmm0);
165 
166     a.bind(next);
167     a.movsd(getArgRef(Dst), x86::xmm0);
168 }
169