summaryrefslogtreecommitdiff
path: root/erts/emulator/beam/jit/x86/instr_float.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'erts/emulator/beam/jit/x86/instr_float.cpp')
-rw-r--r--erts/emulator/beam/jit/x86/instr_float.cpp168
1 files changed, 168 insertions, 0 deletions
diff --git a/erts/emulator/beam/jit/x86/instr_float.cpp b/erts/emulator/beam/jit/x86/instr_float.cpp
new file mode 100644
index 0000000000..43acf485ff
--- /dev/null
+++ b/erts/emulator/beam/jit/x86/instr_float.cpp
@@ -0,0 +1,168 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2020-2020. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#include "beam_asm.hpp"
+
+extern "C"
+{
+#include "big.h"
+}
+
+void BeamModuleAssembler::emit_fload(const ArgVal &Src, const ArgVal &Dst) {
+ /* {thing_word,double} */
+ mov_arg(ARG1, Src);
+
+ x86::Gp boxed_ptr = emit_ptr_val(ARG1, ARG1);
+ a.mov(ARG1, emit_boxed_val(boxed_ptr, sizeof(Eterm)));
+ a.mov(getArgRef(Dst), ARG1);
+}
+
+void BeamModuleAssembler::emit_fstore(const ArgVal &Src, const ArgVal &Dst) {
+ a.mov(ARG1, getArgRef(Src));
+
+ /* {thing_word,double} */
+ a.mov(x86::qword_ptr(HTOP), imm(HEADER_FLONUM));
+ a.mov(x86::qword_ptr(HTOP, sizeof(Eterm)), ARG1);
+
+ a.lea(ARG1, x86::qword_ptr(HTOP, make_float(0)));
+ mov_arg(Dst, ARG1);
+
+ a.add(HTOP, imm(FLOAT_SIZE_OBJECT * sizeof(Eterm)));
+}
+
+static int handle_fconv(Eterm src, double *dst) {
+ if (is_small(src)) {
+ *dst = (double)signed_val(src);
+ } else if (is_float(src)) {
+ GET_DOUBLE(src, *(FloatDef *)dst);
+ } else if (is_big(src)) {
+ if (big_to_double(src, dst) < 0) {
+ return 1;
+ }
+ } else {
+ return 1;
+ }
+
+ return 0;
+}
+
+void BeamModuleAssembler::emit_fconv(const ArgVal &Src, const ArgVal &Dst) {
+ Label next = a.newLabel();
+
+ mov_arg(ARG1, Src);
+ a.lea(ARG2, getArgRef(Dst));
+
+ emit_enter_runtime();
+
+ runtime_call<2>(handle_fconv);
+
+ emit_leave_runtime();
+
+ a.test(RET, RET);
+ a.short_().je(next);
+
+ emit_error(EXC_BADARITH);
+
+ a.bind(next);
+}
+
+void BeamModuleAssembler::emit_check_float(Label next, x86::Xmm value) {
+ a.movsd(x86::xmm2, value);
+ a.movsd(x86::xmm1, x86::qword_ptr(floatMax));
+ a.andpd(x86::xmm2, x86::xmmword_ptr(floatSignMask));
+ a.ucomisd(x86::xmm1, x86::xmm2);
+ a.short_().jnb(next);
+
+ emit_error(EXC_BADARITH);
+}
+
+void BeamModuleAssembler::emit_i_fadd(const ArgVal &LHS,
+ const ArgVal &RHS,
+ const ArgVal &Dst) {
+ Label next = a.newLabel();
+
+ a.movsd(x86::xmm0, getArgRef(LHS));
+ a.movsd(x86::xmm1, getArgRef(RHS));
+ a.addpd(x86::xmm0, x86::xmm1);
+
+ emit_check_float(next, x86::xmm0);
+
+ a.bind(next);
+ a.movsd(getArgRef(Dst), x86::xmm0);
+}
+
+void BeamModuleAssembler::emit_i_fsub(const ArgVal &LHS,
+ const ArgVal &RHS,
+ const ArgVal &Dst) {
+ Label next = a.newLabel();
+
+ a.movsd(x86::xmm0, getArgRef(LHS));
+ a.movsd(x86::xmm1, getArgRef(RHS));
+ a.subpd(x86::xmm0, x86::xmm1);
+
+ emit_check_float(next, x86::xmm0);
+
+ a.bind(next);
+ a.movsd(getArgRef(Dst), x86::xmm0);
+}
+
+void BeamModuleAssembler::emit_i_fmul(const ArgVal &LHS,
+ const ArgVal &RHS,
+ const ArgVal &Dst) {
+ Label next = a.newLabel();
+
+ a.movsd(x86::xmm0, getArgRef(LHS));
+ a.movsd(x86::xmm1, getArgRef(RHS));
+ a.mulpd(x86::xmm0, x86::xmm1);
+
+ emit_check_float(next, x86::xmm0);
+
+ a.bind(next);
+ a.movsd(getArgRef(Dst), x86::xmm0);
+}
+
+void BeamModuleAssembler::emit_i_fdiv(const ArgVal &LHS,
+ const ArgVal &RHS,
+ const ArgVal &Dst) {
+ Label next = a.newLabel();
+
+ a.movsd(x86::xmm0, getArgRef(LHS));
+ a.movsd(x86::xmm1, getArgRef(RHS));
+ a.divpd(x86::xmm0, x86::xmm1);
+
+ emit_check_float(next, x86::xmm0);
+
+ a.bind(next);
+ a.movsd(getArgRef(Dst), x86::xmm0);
+}
+
+void BeamModuleAssembler::emit_i_fnegate(const ArgVal &Src, const ArgVal &Dst) {
+ Label next = a.newLabel();
+
+ /* xmm0 = 0.0 */
+ a.psubd(x86::xmm0, x86::xmm0);
+ a.movsd(x86::xmm1, getArgRef(Src));
+ a.subpd(x86::xmm0, x86::xmm1);
+
+ emit_check_float(next, x86::xmm0);
+
+ a.bind(next);
+ a.movsd(getArgRef(Dst), x86::xmm0);
+}