diff options
Diffstat (limited to 'erts/emulator/beam/jit/x86/instr_float.cpp')
-rw-r--r-- | erts/emulator/beam/jit/x86/instr_float.cpp | 168 |
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); +} |