From f44cafe3ca045769bc9aa8c993bff7f4ed57a193 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 4 Mar 2019 10:44:17 -0500 Subject: [PATCH] frontend/ir/ir_emitter: Alter parameters of FPDoubleToSingle() and FPSingleToDouble() to pass along desired rounding mode This will be necessary to special-case the non-IEEE Von Neumann rounding to odd rounding mode. --- src/backend/x64/emit_x64_floating_point.cpp | 44 ++++++++++++++----- .../A32/translate/translate_arm/vfp2.cpp | 5 ++- ...ing_point_data_processing_one_register.cpp | 8 ++-- .../translate/impl/simd_two_register_misc.cpp | 6 ++- src/frontend/ir/ir_emitter.cpp | 10 ++--- src/frontend/ir/ir_emitter.h | 4 +- src/frontend/ir/opcodes.inc | 4 +- 7 files changed, 52 insertions(+), 29 deletions(-) diff --git a/src/backend/x64/emit_x64_floating_point.cpp b/src/backend/x64/emit_x64_floating_point.cpp index c499e20f..88ceb413 100644 --- a/src/backend/x64/emit_x64_floating_point.cpp +++ b/src/backend/x64/emit_x64_floating_point.cpp @@ -1034,26 +1034,46 @@ void EmitX64::EmitFPCompare64(EmitContext& ctx, IR::Inst* inst) { void EmitX64::EmitFPSingleToDouble(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm result = ctx.reg_alloc.UseScratchXmm(args[0]); + const auto rounding_mode = static_cast(args[1].GetImmediateU8()); - code.cvtss2sd(result, result); - if (ctx.FPSCR_DN()) { - ForceToDefaultNaN<64>(code, result); + // We special-case the non-IEEE-defined ToOdd rounding mode. + if (rounding_mode == ctx.FPSCR_RMode() && rounding_mode != FP::RoundingMode::ToOdd) { + const Xbyak::Xmm result = ctx.reg_alloc.UseScratchXmm(args[0]); + + code.cvtss2sd(result, result); + if (ctx.FPSCR_DN()) { + ForceToDefaultNaN<64>(code, result); + } + ctx.reg_alloc.DefineValue(inst, result); + } else { + ctx.reg_alloc.HostCall(inst, args[0]); + code.mov(code.ABI_PARAM2.cvt32(), ctx.FPCR()); + code.mov(code.ABI_PARAM3.cvt32(), static_cast(rounding_mode)); + code.lea(code.ABI_PARAM4, code.ptr[code.r15 + code.GetJitStateInfo().offsetof_fpsr_exc]); + code.CallFunction(&FP::FPConvert); } - - ctx.reg_alloc.DefineValue(inst, result); } void EmitX64::EmitFPDoubleToSingle(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm result = ctx.reg_alloc.UseScratchXmm(args[0]); + const auto rounding_mode = static_cast(args[1].GetImmediateU8()); - code.cvtsd2ss(result, result); - if (ctx.FPSCR_DN()) { - ForceToDefaultNaN<32>(code, result); + // We special-case the non-IEEE-defined ToOdd rounding mode. + if (rounding_mode == ctx.FPSCR_RMode() && rounding_mode != FP::RoundingMode::ToOdd) { + const Xbyak::Xmm result = ctx.reg_alloc.UseScratchXmm(args[0]); + + code.cvtsd2ss(result, result); + if (ctx.FPSCR_DN()) { + ForceToDefaultNaN<32>(code, result); + } + ctx.reg_alloc.DefineValue(inst, result); + } else { + ctx.reg_alloc.HostCall(inst, args[0]); + code.mov(code.ABI_PARAM2.cvt32(), ctx.FPCR()); + code.mov(code.ABI_PARAM3.cvt32(), static_cast(rounding_mode)); + code.lea(code.ABI_PARAM4, code.ptr[code.r15 + code.GetJitStateInfo().offsetof_fpsr_exc]); + code.CallFunction(&FP::FPConvert); } - - ctx.reg_alloc.DefineValue(inst, result); } template diff --git a/src/frontend/A32/translate/translate_arm/vfp2.cpp b/src/frontend/A32/translate/translate_arm/vfp2.cpp index eb2caa92..638d52ba 100644 --- a/src/frontend/A32/translate/translate_arm/vfp2.cpp +++ b/src/frontend/A32/translate/translate_arm/vfp2.cpp @@ -479,12 +479,13 @@ bool ArmTranslatorVisitor::vfp2_VCVT_f_to_f(Cond cond, bool D, size_t Vd, bool s const auto d = ToExtReg(!sz, Vd, D); // Destination is of opposite size to source const auto m = ToExtReg(sz, Vm, M); const auto reg_m = ir.GetExtendedRegister(m); + const auto rounding_mode = ir.current_location.FPSCR().RMode(); if (sz) { - const auto result = ir.FPDoubleToSingle(reg_m, true); + const auto result = ir.FPDoubleToSingle(reg_m, rounding_mode); ir.SetExtendedRegister(d, result); } else { - const auto result = ir.FPSingleToDouble(reg_m, true); + const auto result = ir.FPSingleToDouble(reg_m, rounding_mode); ir.SetExtendedRegister(d, result); } diff --git a/src/frontend/A64/translate/impl/floating_point_data_processing_one_register.cpp b/src/frontend/A64/translate/impl/floating_point_data_processing_one_register.cpp index a8ac0d6b..342fd4c4 100644 --- a/src/frontend/A64/translate/impl/floating_point_data_processing_one_register.cpp +++ b/src/frontend/A64/translate/impl/floating_point_data_processing_one_register.cpp @@ -104,7 +104,9 @@ bool TranslatorVisitor::FCVT_float(Imm<2> type, Imm<2> opc, Vec Vn, Vec Vd) { return UnallocatedEncoding(); } - IR::UAny operand = V_scalar(*srcsize, Vn); + const IR::UAny operand = V_scalar(*srcsize, Vn); + const auto rounding_mode = ir.current_location->FPCR().RMode(); + IR::UAny result; switch (*srcsize) { case 16: @@ -120,7 +122,7 @@ bool TranslatorVisitor::FCVT_float(Imm<2> type, Imm<2> opc, Vec Vn, Vec Vd) { case 16: return InterpretThisInstruction(); case 64: - result = ir.FPSingleToDouble(operand, true); + result = ir.FPSingleToDouble(operand, rounding_mode); break; } break; @@ -129,7 +131,7 @@ bool TranslatorVisitor::FCVT_float(Imm<2> type, Imm<2> opc, Vec Vn, Vec Vd) { case 16: return InterpretThisInstruction(); case 32: - result = ir.FPDoubleToSingle(operand, true); + result = ir.FPDoubleToSingle(operand, rounding_mode); break; } break; diff --git a/src/frontend/A64/translate/impl/simd_two_register_misc.cpp b/src/frontend/A64/translate/impl/simd_two_register_misc.cpp index d1b5ab50..2dba56e5 100644 --- a/src/frontend/A64/translate/impl/simd_two_register_misc.cpp +++ b/src/frontend/A64/translate/impl/simd_two_register_misc.cpp @@ -348,10 +348,11 @@ bool TranslatorVisitor::FCVTL(bool Q, bool sz, Vec Vn, Vec Vd) { } const IR::U128 part = Vpart(64, Vn, Q); + const auto rounding_mode = ir.current_location->FPCR().RMode(); IR::U128 result = ir.ZeroVector(); for (size_t i = 0; i < 2; i++) { - const IR::U64 element = ir.FPSingleToDouble(ir.VectorGetElement(32, part, i), true); + const IR::U64 element = ir.FPSingleToDouble(ir.VectorGetElement(32, part, i), rounding_mode); result = ir.VectorSetElement(64, result, i, element); } @@ -367,10 +368,11 @@ bool TranslatorVisitor::FCVTN(bool Q, bool sz, Vec Vn, Vec Vd) { } const IR::U128 operand = V(128, Vn); + const auto rounding_mode = ir.current_location->FPCR().RMode(); IR::U128 result = ir.ZeroVector(); for (size_t i = 0; i < 2; i++) { - const IR::U32 element = ir.FPDoubleToSingle(ir.VectorGetElement(64, operand, i), true); + const IR::U32 element = ir.FPDoubleToSingle(ir.VectorGetElement(64, operand, i), rounding_mode); result = ir.VectorSetElement(32, result, i, element); } diff --git a/src/frontend/ir/ir_emitter.cpp b/src/frontend/ir/ir_emitter.cpp index 6452e7f7..ccc7420a 100644 --- a/src/frontend/ir/ir_emitter.cpp +++ b/src/frontend/ir/ir_emitter.cpp @@ -1948,14 +1948,12 @@ U32U64 IREmitter::FPSub(const U32U64& a, const U32U64& b, bool fpcr_controlled) } } -U32 IREmitter::FPDoubleToSingle(const U64& a, bool fpcr_controlled) { - ASSERT(fpcr_controlled); - return Inst(Opcode::FPDoubleToSingle, a); +U32 IREmitter::FPDoubleToSingle(const U64& a, FP::RoundingMode rounding) { + return Inst(Opcode::FPDoubleToSingle, a, Imm8(static_cast(rounding))); } -U64 IREmitter::FPSingleToDouble(const U32& a, bool fpcr_controlled) { - ASSERT(fpcr_controlled); - return Inst(Opcode::FPSingleToDouble, a); +U64 IREmitter::FPSingleToDouble(const U32& a, FP::RoundingMode rounding) { + return Inst(Opcode::FPSingleToDouble, a, Imm8(static_cast(rounding))); } U32 IREmitter::FPToFixedS32(const U32U64& a, size_t fbits, FP::RoundingMode rounding) { diff --git a/src/frontend/ir/ir_emitter.h b/src/frontend/ir/ir_emitter.h index f58c6efa..bff31c94 100644 --- a/src/frontend/ir/ir_emitter.h +++ b/src/frontend/ir/ir_emitter.h @@ -312,8 +312,8 @@ public: U32U64 FPRSqrtStepFused(const U32U64& a, const U32U64& b); U32U64 FPSqrt(const U32U64& a); U32U64 FPSub(const U32U64& a, const U32U64& b, bool fpcr_controlled); - U32 FPDoubleToSingle(const U64& a, bool fpcr_controlled); - U64 FPSingleToDouble(const U32& a, bool fpcr_controlled); + U32 FPDoubleToSingle(const U64& a, FP::RoundingMode rounding); + U64 FPSingleToDouble(const U32& a, FP::RoundingMode rounding); U32 FPToFixedS32(const U32U64& a, size_t fbits, FP::RoundingMode rounding); U64 FPToFixedS64(const U32U64& a, size_t fbits, FP::RoundingMode rounding); U32 FPToFixedU32(const U32U64& a, size_t fbits, FP::RoundingMode rounding); diff --git a/src/frontend/ir/opcodes.inc b/src/frontend/ir/opcodes.inc index 7306e3d0..2797496f 100644 --- a/src/frontend/ir/opcodes.inc +++ b/src/frontend/ir/opcodes.inc @@ -500,8 +500,8 @@ OPCODE(FPSub32, U32, U32, OPCODE(FPSub64, U64, U64, U64 ) // Floating-point conversions -OPCODE(FPSingleToDouble, U64, U32 ) -OPCODE(FPDoubleToSingle, U32, U64 ) +OPCODE(FPSingleToDouble, U64, U32, U8 ) +OPCODE(FPDoubleToSingle, U32, U64, U8 ) OPCODE(FPDoubleToFixedS32, U32, U64, U8, U8 ) OPCODE(FPDoubleToFixedS64, U64, U64, U8, U8 ) OPCODE(FPDoubleToFixedU32, U32, U64, U8, U8 )