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