From d4d5f4d1dd3d34b4c8c30b59a8e2eed0594cbf85 Mon Sep 17 00:00:00 2001 From: CallumDev Date: Sun, 20 Feb 2022 23:41:29 +1030 Subject: [PATCH 01/15] Introduce F64 codegen for reduced precision X87 --- External/FEXCore/Source/CMakeLists.txt | 1 + .../Source/Interface/Config/Config.json.in | 7 + .../Interface/Core/Interpreter/F80Ops.h | 67 ++ .../Core/Interpreter/InterpreterFallbacks.cpp | 41 + .../Core/Interpreter/InterpreterOps.h | 2 + .../Source/Interface/Core/JIT/Arm64/JIT.cpp | 37 + .../Source/Interface/Core/JIT/x86_64/JIT.cpp | 27 + .../Interface/Core/OpcodeDispatcher.cpp | 237 ++++- .../Source/Interface/Core/OpcodeDispatcher.h | 47 + .../Core/OpcodeDispatcher/X87F64.cpp | 850 ++++++++++++++++++ External/FEXCore/Source/Interface/IR/IR.json | 29 + .../FEXCore/include/FEXCore/Core/CoreState.h | 10 + 12 files changed, 1354 insertions(+), 1 deletion(-) create mode 100644 External/FEXCore/Source/Interface/Core/OpcodeDispatcher/X87F64.cpp diff --git a/External/FEXCore/Source/CMakeLists.txt b/External/FEXCore/Source/CMakeLists.txt index 123327598..22c323210 100644 --- a/External/FEXCore/Source/CMakeLists.txt +++ b/External/FEXCore/Source/CMakeLists.txt @@ -90,6 +90,7 @@ set (SRCS Interface/Core/OpcodeDispatcher/Flags.cpp Interface/Core/OpcodeDispatcher/Vector.cpp Interface/Core/OpcodeDispatcher/X87.cpp + Interface/Core/OpcodeDispatcher/X87F64.cpp Interface/Core/OpcodeDispatcher.cpp Interface/Core/SignalDelegator.cpp Interface/Core/X86Tables.cpp diff --git a/External/FEXCore/Source/Interface/Config/Config.json.in b/External/FEXCore/Source/Interface/Config/Config.json.in index 12cee32c0..a9ab3446a 100644 --- a/External/FEXCore/Source/Interface/Config/Config.json.in +++ b/External/FEXCore/Source/Interface/Config/Config.json.in @@ -241,6 +241,13 @@ "Highly likely to break any multithreaded application if disabled." ] }, + "X87ReducedPrecision": { + "Type": "bool", + "Default": "false", + "Desc": [ + "Emulates X87 floating point using 64-bit precision" + ] + }, "ABILocalFlags": { "Type": "bool", "Default": "false", diff --git a/External/FEXCore/Source/Interface/Core/Interpreter/F80Ops.h b/External/FEXCore/Source/Interface/Core/Interpreter/F80Ops.h index 250e7b181..99487fc04 100644 --- a/External/FEXCore/Source/Interface/Core/Interpreter/F80Ops.h +++ b/External/FEXCore/Source/Interface/Core/Interpreter/F80Ops.h @@ -222,6 +222,73 @@ struct OpHandlers { } }; +template<> +struct OpHandlers { + static double handle(double src) { + return sin(src); + } +}; + +template<> +struct OpHandlers { + static double handle(double src) { + return cos(src); + } +}; + +template<> +struct OpHandlers { + static double handle(double src) { + return tan(src); + } +}; + +template<> +struct OpHandlers { + static double handle(double src) { + return exp2(src) - 1.0; + } +}; + +template<> +struct OpHandlers { + static double handle(double src1, double src2) { + return atan2(src1, src2); + } +}; + +template<> +struct OpHandlers { + static double handle(double src1, double src2) { + return remainder(src1, src2); + } +}; + +template<> +struct OpHandlers { + static double handle(double src1, double src2) { + return remainder(src1, src2); + } +}; + + +template<> +struct OpHandlers { + static double handle(double src1, double src2) { + return src2 * log2(src1); + } +}; + +template<> +struct OpHandlers { + static double handle(double src1, double src2) { + double trunc = round(src2); + return src1 * exp2(trunc); + } +}; + + + template<> struct OpHandlers { static X80SoftFloat handle(X80SoftFloat Src1) { diff --git a/External/FEXCore/Source/Interface/Core/Interpreter/InterpreterFallbacks.cpp b/External/FEXCore/Source/Interface/Core/Interpreter/InterpreterFallbacks.cpp index 4eac6fe80..b8ec7ed6f 100644 --- a/External/FEXCore/Source/Interface/Core/Interpreter/InterpreterFallbacks.cpp +++ b/External/FEXCore/Source/Interface/Core/Interpreter/InterpreterFallbacks.cpp @@ -47,6 +47,16 @@ FallbackInfo GetFallbackInfo(double(*fn)(X80SoftFloat), FEXCore::Core::FallbackH return {FABI_F64_F80, (void*)fn, HandlerIndex}; } +template<> +FallbackInfo GetFallbackInfo(double(*fn)(double), FEXCore::Core::FallbackHandlerIndex HandlerIndex) { + return {FABI_F64_F64, (void*)fn, HandlerIndex}; +} + +template<> +FallbackInfo GetFallbackInfo(double(*fn)(double,double), FEXCore::Core::FallbackHandlerIndex HandlerIndex) { + return {FABI_F64_F64_F64, (void*)fn, HandlerIndex}; +} + template<> FallbackInfo GetFallbackInfo(int16_t(*fn)(X80SoftFloat), FEXCore::Core::FallbackHandlerIndex HandlerIndex) { return {FABI_I16_F80, (void*)fn, HandlerIndex}; @@ -122,6 +132,18 @@ void InterpreterOps::FillFallbackIndexPointers(uint64_t *Info) { Info[Core::OPINDEX_F80FPREM1] = reinterpret_cast(GetFallbackInfo(&FEXCore::CPU::OpHandlers::handle, Core::OPINDEX_F80FPREM1).fn); Info[Core::OPINDEX_F80FPREM] = reinterpret_cast(GetFallbackInfo(&FEXCore::CPU::OpHandlers::handle, Core::OPINDEX_F80FPREM).fn); Info[Core::OPINDEX_F80SCALE] = reinterpret_cast(GetFallbackInfo(&FEXCore::CPU::OpHandlers::handle, Core::OPINDEX_F80SCALE).fn); + + // Double Precision + Info[Core::OPINDEX_F64SIN] = reinterpret_cast(GetFallbackInfo(&FEXCore::CPU::OpHandlers::handle, Core::OPINDEX_F64SIN).fn); + Info[Core::OPINDEX_F64COS] = reinterpret_cast(GetFallbackInfo(&FEXCore::CPU::OpHandlers::handle, Core::OPINDEX_F64COS).fn); + Info[Core::OPINDEX_F64TAN] = reinterpret_cast(GetFallbackInfo(&FEXCore::CPU::OpHandlers::handle, Core::OPINDEX_F64TAN).fn); + Info[Core::OPINDEX_F64ATAN] = reinterpret_cast(GetFallbackInfo(&FEXCore::CPU::OpHandlers::handle, Core::OPINDEX_F64ATAN).fn); + Info[Core::OPINDEX_F64F2XM1] = reinterpret_cast(GetFallbackInfo(&FEXCore::CPU::OpHandlers::handle, Core::OPINDEX_F64F2XM1).fn); + Info[Core::OPINDEX_F64FYL2X] = reinterpret_cast(GetFallbackInfo(&FEXCore::CPU::OpHandlers::handle, Core::OPINDEX_F64FYL2X).fn); + Info[Core::OPINDEX_F64FPREM] = reinterpret_cast(GetFallbackInfo(&FEXCore::CPU::OpHandlers::handle, Core::OPINDEX_F64FPREM).fn); + Info[Core::OPINDEX_F64FPREM1] = reinterpret_cast(GetFallbackInfo(&FEXCore::CPU::OpHandlers::handle, Core::OPINDEX_F64FPREM1).fn); + Info[Core::OPINDEX_F64SCALE] = reinterpret_cast(GetFallbackInfo(&FEXCore::CPU::OpHandlers::handle, Core::OPINDEX_F64SCALE).fn); + } bool InterpreterOps::GetFallbackHandler(IR::IROp_Header *IROp, FallbackInfo *Info) { @@ -238,6 +260,12 @@ bool InterpreterOps::GetFallbackHandler(IR::IROp_Header *IROp, FallbackInfo *Inf return true; \ } +#define COMMON_F64_OP(OP) \ + case IR::OP_F64##OP: { \ + *Info = GetFallbackInfo(&FEXCore::CPU::OpHandlers::handle, Core::OPINDEX_F64##OP); \ + return true; \ + } + // Unary COMMON_X87_OP(ROUND) COMMON_X87_OP(F2XM1) @@ -261,6 +289,19 @@ bool InterpreterOps::GetFallbackHandler(IR::IROp_Header *IROp, FallbackInfo *Inf COMMON_X87_OP(FPREM) COMMON_X87_OP(SCALE) + // Double Precision Unary + COMMON_F64_OP(F2XM1) + COMMON_F64_OP(TAN) + COMMON_F64_OP(SIN) + COMMON_F64_OP(COS) + + // Double Precision Binary + COMMON_F64_OP(FYL2X) + COMMON_F64_OP(ATAN) + COMMON_F64_OP(FPREM1) + COMMON_F64_OP(FPREM) + COMMON_F64_OP(SCALE) + default: break; } diff --git a/External/FEXCore/Source/Interface/Core/Interpreter/InterpreterOps.h b/External/FEXCore/Source/Interface/Core/Interpreter/InterpreterOps.h index feb494117..0b3d9ae4a 100644 --- a/External/FEXCore/Source/Interface/Core/Interpreter/InterpreterOps.h +++ b/External/FEXCore/Source/Interface/Core/Interpreter/InterpreterOps.h @@ -28,6 +28,8 @@ namespace FEXCore::CPU { FABI_F80_I32, FABI_F32_F80, FABI_F64_F80, + FABI_F64_F64, + FABI_F64_F64_F64, FABI_I16_F80, FABI_I32_F80, FABI_I64_F80, diff --git a/External/FEXCore/Source/Interface/Core/JIT/Arm64/JIT.cpp b/External/FEXCore/Source/Interface/Core/JIT/Arm64/JIT.cpp index f3f948471..b17c98d32 100644 --- a/External/FEXCore/Source/Interface/Core/JIT/Arm64/JIT.cpp +++ b/External/FEXCore/Source/Interface/Core/JIT/Arm64/JIT.cpp @@ -203,6 +203,43 @@ void Arm64JITCore::Op_Unhandled(IR::IROp_Header *IROp, IR::NodeID Node) { } break; + case FABI_F64_F64: { + SpillStaticRegs(); + + PushDynamicRegsAndLR(); + + mov(v0.D(), GetSrc(IROp->Args[0].ID()).D()); + ldr(x0, MemOperand(STATE, offsetof(FEXCore::Core::CpuStateFrame, Pointers.AArch64.FallbackHandlerPointers[Info.HandlerIndex]))); + blr(x0); + + PopDynamicRegsAndLR(); + + FillStaticRegs(); + + mov(GetDst(Node).D(), v0.D()); + + } + break; + + case FABI_F64_F64: { + SpillStaticRegs(); + + PushDynamicRegsAndLR(); + + mov(v0.D(), GetSrc(IROp->Args[0].ID()).D()); + mov(v1.D(), GetSrc(IROp->Args[1].ID()).D()); + ldr(x0, MemOperand(STATE, offsetof(FEXCore::Core::CpuStateFrame, Pointers.AArch64.FallbackHandlerPointers[Info.HandlerIndex]))); + blr(x0); + + PopDynamicRegsAndLR(); + + FillStaticRegs(); + + mov(GetDst(Node).D(), v0.D()); + + } + break; + case FABI_I16_F80:{ SpillStaticRegs(); diff --git a/External/FEXCore/Source/Interface/Core/JIT/x86_64/JIT.cpp b/External/FEXCore/Source/Interface/Core/JIT/x86_64/JIT.cpp index 875d0ae6b..d013dd843 100644 --- a/External/FEXCore/Source/Interface/Core/JIT/x86_64/JIT.cpp +++ b/External/FEXCore/Source/Interface/Core/JIT/x86_64/JIT.cpp @@ -196,6 +196,33 @@ void X86JITCore::Op_Unhandled(IR::IROp_Header *IROp, IR::NodeID Node) { } break; + case FABI_F64_F64: { + PushRegs(); + + movsd(xmm0, GetSrc(IROp->Args[0].ID())); + + call(qword [STATE + offsetof(FEXCore::Core::CpuStateFrame, Pointers.X86.FallbackHandlerPointers[Info.HandlerIndex])]); + + PopRegs(); + + movsd(GetDst(Node), xmm0); + } + break; + + case FABI_F64_F64_F64: { + PushRegs(); + + movsd(xmm0, GetSrc(IROp->Args[0].ID())); + movsd(xmm1, GetSrc(IROp->Args[1].ID())); + + call(qword [STATE + offsetof(FEXCore::Core::CpuStateFrame, Pointers.X86.FallbackHandlerPointers[Info.HandlerIndex])]); + + PopRegs(); + + movsd(GetDst(Node), xmm0); + } + break; + case FABI_I16_F80:{ PushRegs(); diff --git a/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp b/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp index 22059a382..092c02b6d 100644 --- a/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp +++ b/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp @@ -5875,6 +5875,236 @@ constexpr uint16_t PF_F2 = 3; // All OPDReg versions need it #define OPDReg(op, reg) ((1 << 15) | ((op - 0xD8) << 8) | (reg << 3)) #define OPD(op, modrmop) (((op - 0xD8) << 8) | modrmop) + constexpr std::tuple X87F64OpTable[] = { + {OPDReg(0xD8, 0) | 0x00, 8, &OpDispatchBuilder::FADDF64<32, false, OpDispatchBuilder::OpResult::RES_ST0>}, + + {OPDReg(0xD8, 1) | 0x00, 8, &OpDispatchBuilder::FMULF64<32, false, OpDispatchBuilder::OpResult::RES_ST0>}, + + {OPDReg(0xD8, 2) | 0x00, 8, &OpDispatchBuilder::FCOMIF64<32, false, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, false>}, + + {OPDReg(0xD8, 3) | 0x00, 8, &OpDispatchBuilder::FCOMIF64<32, false, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, false>}, + + {OPDReg(0xD8, 4) | 0x00, 8, &OpDispatchBuilder::FSUBF64<32, false, false, OpDispatchBuilder::OpResult::RES_ST0>}, + + {OPDReg(0xD8, 5) | 0x00, 8, &OpDispatchBuilder::FSUBF64<32, false, true, OpDispatchBuilder::OpResult::RES_ST0>}, + + {OPDReg(0xD8, 6) | 0x00, 8, &OpDispatchBuilder::FDIVF64<32, false, false, OpDispatchBuilder::OpResult::RES_ST0>}, + + {OPDReg(0xD8, 7) | 0x00, 8, &OpDispatchBuilder::FDIVF64<32, false, true, OpDispatchBuilder::OpResult::RES_ST0>}, + + {OPD(0xD8, 0xC0), 8, &OpDispatchBuilder::FADDF64<80, false, OpDispatchBuilder::OpResult::RES_ST0>}, + {OPD(0xD8, 0xC8), 8, &OpDispatchBuilder::FMULF64<80, false, OpDispatchBuilder::OpResult::RES_ST0>}, + {OPD(0xD8, 0xD0), 8, &OpDispatchBuilder::FCOMIF64<80, false, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, false>}, + {OPD(0xD8, 0xD8), 8, &OpDispatchBuilder::FCOMIF64<80, false, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, false>}, + {OPD(0xD8, 0xE0), 8, &OpDispatchBuilder::FSUBF64<80, false, false, OpDispatchBuilder::OpResult::RES_ST0>}, + {OPD(0xD8, 0xE8), 8, &OpDispatchBuilder::FSUBF64<80, false, true, OpDispatchBuilder::OpResult::RES_ST0>}, + {OPD(0xD8, 0xF0), 8, &OpDispatchBuilder::FDIVF64<80, false, false, OpDispatchBuilder::OpResult::RES_ST0>}, + {OPD(0xD8, 0xF8), 8, &OpDispatchBuilder::FDIVF64<80, false, true, OpDispatchBuilder::OpResult::RES_ST0>}, + + {OPDReg(0xD9, 0) | 0x00, 8, &OpDispatchBuilder::FLDF64<32>}, + + // 1 = Invalid + + {OPDReg(0xD9, 2) | 0x00, 8, &OpDispatchBuilder::FSTF64<32>}, + + {OPDReg(0xD9, 3) | 0x00, 8, &OpDispatchBuilder::FSTF64<32>}, + + {OPDReg(0xD9, 4) | 0x00, 8, &OpDispatchBuilder::X87LDENV}, + + {OPDReg(0xD9, 5) | 0x00, 8, &OpDispatchBuilder::X87FLDCW}, // XXX: stubbed FLDCW + + {OPDReg(0xD9, 6) | 0x00, 8, &OpDispatchBuilder::X87FNSTENV}, + + {OPDReg(0xD9, 7) | 0x00, 8, &OpDispatchBuilder::X87FSTCW}, + + {OPD(0xD9, 0xC0), 8, &OpDispatchBuilder::FLDF64<80>}, + {OPD(0xD9, 0xC8), 8, &OpDispatchBuilder::FXCH}, + {OPD(0xD9, 0xD0), 1, &OpDispatchBuilder::NOPOp}, // FNOP + // D1 = Invalid + // D8 = Invalid + {OPD(0xD9, 0xE0), 1, &OpDispatchBuilder::FCHSF64}, + {OPD(0xD9, 0xE1), 1, &OpDispatchBuilder::FABSF64}, + // E2 = Invalid + {OPD(0xD9, 0xE4), 1, &OpDispatchBuilder::FTSTF64}, + {OPD(0xD9, 0xE5), 1, &OpDispatchBuilder::X87FXAMF64}, + // E6 = Invalid + {OPD(0xD9, 0xE8), 1, &OpDispatchBuilder::FLDF64_Const<0x3FF0000000000000>}, // 1.0 + {OPD(0xD9, 0xE9), 1, &OpDispatchBuilder::FLDF64_Const<0x400A934F0979A372>}, // log2l(10) + {OPD(0xD9, 0xEA), 1, &OpDispatchBuilder::FLDF64_Const<0x3FF71547652B82FE>}, // log2l(e) + {OPD(0xD9, 0xEB), 1, &OpDispatchBuilder::FLDF64_Const<0x400921FB54442D18>}, // pi + {OPD(0xD9, 0xEC), 1, &OpDispatchBuilder::FLDF64_Const<0x3FD34413509F79FF>}, // log10l(2) + {OPD(0xD9, 0xED), 1, &OpDispatchBuilder::FLDF64_Const<0x3FE62E42FEFA39EF>}, // log(2) + {OPD(0xD9, 0xEE), 1, &OpDispatchBuilder::FLDF64_Const<0>}, // 0.0 + + // EF = Invalid + {OPD(0xD9, 0xF0), 1, &OpDispatchBuilder::X87UnaryOpF64}, + {OPD(0xD9, 0xF1), 1, &OpDispatchBuilder::X87FYL2XF64}, + {OPD(0xD9, 0xF2), 1, &OpDispatchBuilder::X87TANF64}, + {OPD(0xD9, 0xF3), 1, &OpDispatchBuilder::X87ATANF64}, + {OPD(0xD9, 0xF4), 1, &OpDispatchBuilder::FXTRACTF64}, + {OPD(0xD9, 0xF5), 1, &OpDispatchBuilder::X87BinaryOpF64}, + {OPD(0xD9, 0xF6), 1, &OpDispatchBuilder::X87ModifySTP}, + {OPD(0xD9, 0xF7), 1, &OpDispatchBuilder::X87ModifySTP}, + {OPD(0xD9, 0xF8), 1, &OpDispatchBuilder::X87BinaryOpF64}, + {OPD(0xD9, 0xF9), 1, &OpDispatchBuilder::X87FYL2XF64}, + {OPD(0xD9, 0xFA), 1, &OpDispatchBuilder::FSQRTF64}, + {OPD(0xD9, 0xFB), 1, &OpDispatchBuilder::X87SinCosF64}, + {OPD(0xD9, 0xFC), 1, &OpDispatchBuilder::FRNDINTF64}, + {OPD(0xD9, 0xFD), 1, &OpDispatchBuilder::X87BinaryOpF64}, + {OPD(0xD9, 0xFE), 1, &OpDispatchBuilder::X87UnaryOpF64}, + {OPD(0xD9, 0xFF), 1, &OpDispatchBuilder::X87UnaryOpF64}, + + {OPDReg(0xDA, 0) | 0x00, 8, &OpDispatchBuilder::FADDF64<32, true, OpDispatchBuilder::OpResult::RES_ST0>}, + + {OPDReg(0xDA, 1) | 0x00, 8, &OpDispatchBuilder::FMULF64<32, true, OpDispatchBuilder::OpResult::RES_ST0>}, + + {OPDReg(0xDA, 2) | 0x00, 8, &OpDispatchBuilder::FCOMIF64<32, true, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, false>}, + + {OPDReg(0xDA, 3) | 0x00, 8, &OpDispatchBuilder::FCOMIF64<32, true, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, false>}, + + {OPDReg(0xDA, 4) | 0x00, 8, &OpDispatchBuilder::FSUBF64<32, true, false, OpDispatchBuilder::OpResult::RES_ST0>}, + + {OPDReg(0xDA, 5) | 0x00, 8, &OpDispatchBuilder::FSUBF64<32, true, true, OpDispatchBuilder::OpResult::RES_ST0>}, + + {OPDReg(0xDA, 6) | 0x00, 8, &OpDispatchBuilder::FDIVF64<32, true, false, OpDispatchBuilder::OpResult::RES_ST0>}, + + {OPDReg(0xDA, 7) | 0x00, 8, &OpDispatchBuilder::FDIVF64<32, true, true, OpDispatchBuilder::OpResult::RES_ST0>}, + + {OPD(0xDA, 0xC0), 8, &OpDispatchBuilder::X87FCMOV}, + {OPD(0xDA, 0xC8), 8, &OpDispatchBuilder::X87FCMOV}, + {OPD(0xDA, 0xD0), 8, &OpDispatchBuilder::X87FCMOV}, + {OPD(0xDA, 0xD8), 8, &OpDispatchBuilder::X87FCMOV}, + // E0 = Invalid + // E8 = Invalid + {OPD(0xDA, 0xE9), 1, &OpDispatchBuilder::FCOMIF64<80, false, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, true>}, + // EA = Invalid + // F0 = Invalid + // F8 = Invalid + + {OPDReg(0xDB, 0) | 0x00, 8, &OpDispatchBuilder::FILDF64}, + + {OPDReg(0xDB, 1) | 0x00, 8, &OpDispatchBuilder::FISTF64}, + + {OPDReg(0xDB, 2) | 0x00, 8, &OpDispatchBuilder::FISTF64}, + + {OPDReg(0xDB, 3) | 0x00, 8, &OpDispatchBuilder::FISTF64}, + + // 4 = Invalid + + {OPDReg(0xDB, 5) | 0x00, 8, &OpDispatchBuilder::FLDF64<80>}, + + // 6 = Invalid + + {OPDReg(0xDB, 7) | 0x00, 8, &OpDispatchBuilder::FSTF64<80>}, + + + {OPD(0xDB, 0xC0), 8, &OpDispatchBuilder::X87FCMOV}, + {OPD(0xDB, 0xC8), 8, &OpDispatchBuilder::X87FCMOV}, + {OPD(0xDB, 0xD0), 8, &OpDispatchBuilder::X87FCMOV}, + {OPD(0xDB, 0xD8), 8, &OpDispatchBuilder::X87FCMOV}, + // E0 = Invalid + {OPD(0xDB, 0xE2), 1, &OpDispatchBuilder::NOPOp}, // FNCLEX + {OPD(0xDB, 0xE3), 1, &OpDispatchBuilder::FNINIT}, + // E4 = Invalid + {OPD(0xDB, 0xE8), 8, &OpDispatchBuilder::FCOMIF64<80, false, OpDispatchBuilder::FCOMIFlags::FLAGS_RFLAGS, false>}, + {OPD(0xDB, 0xF0), 8, &OpDispatchBuilder::FCOMIF64<80, false, OpDispatchBuilder::FCOMIFlags::FLAGS_RFLAGS, false>}, + + // F8 = Invalid + + {OPDReg(0xDC, 0) | 0x00, 8, &OpDispatchBuilder::FADDF64<64, false, OpDispatchBuilder::OpResult::RES_ST0>}, + + {OPDReg(0xDC, 1) | 0x00, 8, &OpDispatchBuilder::FMULF64<64, false, OpDispatchBuilder::OpResult::RES_ST0>}, + + {OPDReg(0xDC, 2) | 0x00, 8, &OpDispatchBuilder::FCOMIF64<64, false, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, false>}, + + {OPDReg(0xDC, 3) | 0x00, 8, &OpDispatchBuilder::FCOMIF64<64, false, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, false>}, + + {OPDReg(0xDC, 4) | 0x00, 8, &OpDispatchBuilder::FSUBF64<64, false, false, OpDispatchBuilder::OpResult::RES_ST0>}, + + {OPDReg(0xDC, 5) | 0x00, 8, &OpDispatchBuilder::FSUBF64<64, false, true, OpDispatchBuilder::OpResult::RES_ST0>}, + + {OPDReg(0xDC, 6) | 0x00, 8, &OpDispatchBuilder::FDIVF64<64, false, false, OpDispatchBuilder::OpResult::RES_ST0>}, + + {OPDReg(0xDC, 7) | 0x00, 8, &OpDispatchBuilder::FDIVF64<64, false, true, OpDispatchBuilder::OpResult::RES_ST0>}, + + {OPD(0xDC, 0xC0), 8, &OpDispatchBuilder::FADDF64<80, false, OpDispatchBuilder::OpResult::RES_STI>}, + {OPD(0xDC, 0xC8), 8, &OpDispatchBuilder::FMULF64<80, false, OpDispatchBuilder::OpResult::RES_STI>}, + {OPD(0xDC, 0xE0), 8, &OpDispatchBuilder::FSUBF64<80, false, false, OpDispatchBuilder::OpResult::RES_STI>}, + {OPD(0xDC, 0xE8), 8, &OpDispatchBuilder::FSUBF64<80, false, true, OpDispatchBuilder::OpResult::RES_STI>}, + {OPD(0xDC, 0xF0), 8, &OpDispatchBuilder::FDIVF64<80, false, false, OpDispatchBuilder::OpResult::RES_STI>}, + {OPD(0xDC, 0xF8), 8, &OpDispatchBuilder::FDIVF64<80, false, true, OpDispatchBuilder::OpResult::RES_STI>}, + + {OPDReg(0xDD, 0) | 0x00, 8, &OpDispatchBuilder::FLDF64<64>}, + + {OPDReg(0xDD, 1) | 0x00, 8, &OpDispatchBuilder::FISTF64}, + + {OPDReg(0xDD, 2) | 0x00, 8, &OpDispatchBuilder::FSTF64<64>}, + + {OPDReg(0xDD, 3) | 0x00, 8, &OpDispatchBuilder::FSTF64<64>}, + + {OPDReg(0xDD, 4) | 0x00, 8, &OpDispatchBuilder::X87FRSTOR}, + + // 5 = Invalid + {OPDReg(0xDD, 6) | 0x00, 8, &OpDispatchBuilder::X87FNSAVE}, + + {OPDReg(0xDD, 7) | 0x00, 8, &OpDispatchBuilder::X87FNSTSW}, + + {OPD(0xDD, 0xC0), 8, &OpDispatchBuilder::X87FFREE}, + {OPD(0xDD, 0xD0), 8, &OpDispatchBuilder::FST}, //register-register from regular X87 + {OPD(0xDD, 0xD8), 8, &OpDispatchBuilder::FST}, //^ + + {OPD(0xDD, 0xE0), 8, &OpDispatchBuilder::FCOMIF64<80, false, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, false>}, + {OPD(0xDD, 0xE8), 8, &OpDispatchBuilder::FCOMIF64<80, false, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, false>}, + + {OPDReg(0xDE, 0) | 0x00, 8, &OpDispatchBuilder::FADDF64<16, true, OpDispatchBuilder::OpResult::RES_ST0>}, + + {OPDReg(0xDE, 1) | 0x00, 8, &OpDispatchBuilder::FMULF64<16, true, OpDispatchBuilder::OpResult::RES_ST0>}, + + {OPDReg(0xDE, 2) | 0x00, 8, &OpDispatchBuilder::FCOMIF64<16, true, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, false>}, + + {OPDReg(0xDE, 3) | 0x00, 8, &OpDispatchBuilder::FCOMIF64<16, true, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, false>}, + + {OPDReg(0xDE, 4) | 0x00, 8, &OpDispatchBuilder::FSUBF64<16, true, false, OpDispatchBuilder::OpResult::RES_ST0>}, + + {OPDReg(0xDE, 5) | 0x00, 8, &OpDispatchBuilder::FSUBF64<16, true, true, OpDispatchBuilder::OpResult::RES_ST0>}, + + {OPDReg(0xDE, 6) | 0x00, 8, &OpDispatchBuilder::FDIVF64<16, true, false, OpDispatchBuilder::OpResult::RES_ST0>}, + + {OPDReg(0xDE, 7) | 0x00, 8, &OpDispatchBuilder::FDIVF64<16, true, true, OpDispatchBuilder::OpResult::RES_ST0>}, + + {OPD(0xDE, 0xC0), 8, &OpDispatchBuilder::FADDF64<80, false, OpDispatchBuilder::OpResult::RES_STI>}, + {OPD(0xDE, 0xC8), 8, &OpDispatchBuilder::FMULF64<80, false, OpDispatchBuilder::OpResult::RES_STI>}, + {OPD(0xDE, 0xD9), 1, &OpDispatchBuilder::FCOMIF64<80, false, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, true>}, + {OPD(0xDE, 0xE0), 8, &OpDispatchBuilder::FSUBF64<80, false, false, OpDispatchBuilder::OpResult::RES_STI>}, + {OPD(0xDE, 0xE8), 8, &OpDispatchBuilder::FSUBF64<80, false, true, OpDispatchBuilder::OpResult::RES_STI>}, + {OPD(0xDE, 0xF0), 8, &OpDispatchBuilder::FDIVF64<80, false, false, OpDispatchBuilder::OpResult::RES_STI>}, + {OPD(0xDE, 0xF8), 8, &OpDispatchBuilder::FDIVF64<80, false, true, OpDispatchBuilder::OpResult::RES_STI>}, + + {OPDReg(0xDF, 0) | 0x00, 8, &OpDispatchBuilder::FILDF64}, + + {OPDReg(0xDF, 1) | 0x00, 8, &OpDispatchBuilder::FISTF64}, + + {OPDReg(0xDF, 2) | 0x00, 8, &OpDispatchBuilder::FISTF64}, + + {OPDReg(0xDF, 3) | 0x00, 8, &OpDispatchBuilder::FISTF64}, + + {OPDReg(0xDF, 4) | 0x00, 8, &OpDispatchBuilder::FBLDF64}, + + {OPDReg(0xDF, 5) | 0x00, 8, &OpDispatchBuilder::FILDF64}, + + {OPDReg(0xDF, 6) | 0x00, 8, &OpDispatchBuilder::FBSTPF64}, + + {OPDReg(0xDF, 7) | 0x00, 8, &OpDispatchBuilder::FISTF64}, + + // XXX: This should also set the x87 tag bits to empty + // We don't support this currently, so just pop the stack + {OPD(0xDF, 0xC0), 8, &OpDispatchBuilder::X87ModifySTP}, + + {OPD(0xDF, 0xE0), 8, &OpDispatchBuilder::X87FNSTSW}, + {OPD(0xDF, 0xE8), 8, &OpDispatchBuilder::FCOMIF64<80, false, OpDispatchBuilder::FCOMIFlags::FLAGS_RFLAGS, false>}, + {OPD(0xDF, 0xF0), 8, &OpDispatchBuilder::FCOMIF64<80, false, OpDispatchBuilder::FCOMIFlags::FLAGS_RFLAGS, false>}, + }; + constexpr std::tuple X87OpTable[] = { {OPDReg(0xD8, 0) | 0x00, 8, &OpDispatchBuilder::FADD<32, false, OpDispatchBuilder::OpResult::RES_ST0>}, @@ -6375,7 +6605,12 @@ constexpr uint16_t PF_F2 = 3; InstallToTable(FEXCore::X86Tables::SecondModRMTableOps, SecondaryModRMExtensionOpTable); - InstallToX87Table(FEXCore::X86Tables::X87Ops, X87OpTable); + FEX_CONFIG_OPT(ReducedPrecision, X87REDUCEDPRECISION); + if(ReducedPrecision) { + InstallToX87Table(FEXCore::X86Tables::X87Ops, X87F64OpTable); + } else { + InstallToX87Table(FEXCore::X86Tables::X87Ops, X87OpTable); + } InstallToTable(FEXCore::X86Tables::H0F38TableOps, H0F38Table); InstallToTable(FEXCore::X86Tables::H0F3ATableOps, H0F3ATable); diff --git a/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.h b/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.h index 4d679e5db..f58e5ade1 100644 --- a/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.h +++ b/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.h @@ -463,6 +463,53 @@ public: template void FCOMI(OpcodeArgs); + // F64 X87 Ops + template + void FLDF64(OpcodeArgs); + template + void FLDF64_Const(OpcodeArgs); + + void FBLDF64(OpcodeArgs); + void FBSTPF64(OpcodeArgs); + + void FILDF64(OpcodeArgs); + + template + void FSTF64(OpcodeArgs); + + void FSTF64(OpcodeArgs); + + template + void FISTF64(OpcodeArgs); + + template + void FADDF64(OpcodeArgs); + template + void FMULF64(OpcodeArgs); + template + void FDIVF64(OpcodeArgs); + template + void FSUBF64(OpcodeArgs); + void FCHSF64(OpcodeArgs); + void FABSF64(OpcodeArgs); + void FTSTF64(OpcodeArgs); + void FRNDINTF64(OpcodeArgs); + void FXTRACTF64(OpcodeArgs); + + void FSQRTF64(OpcodeArgs); + template + void X87UnaryOpF64(OpcodeArgs); + template + void X87BinaryOpF64(OpcodeArgs); + void X87SinCosF64(OpcodeArgs); + void X87FYL2XF64(OpcodeArgs); + void X87TANF64(OpcodeArgs); + void X87ATANF64(OpcodeArgs); + void X87FXAMF64(OpcodeArgs); + + template + void FCOMIF64(OpcodeArgs); + void FXSaveOp(OpcodeArgs); void FXRStoreOp(OpcodeArgs); diff --git a/External/FEXCore/Source/Interface/Core/OpcodeDispatcher/X87F64.cpp b/External/FEXCore/Source/Interface/Core/OpcodeDispatcher/X87F64.cpp new file mode 100644 index 000000000..fd6930be6 --- /dev/null +++ b/External/FEXCore/Source/Interface/Core/OpcodeDispatcher/X87F64.cpp @@ -0,0 +1,850 @@ +/* +$info$ +tags: frontend|x86-to-ir, opcodes|dispatcher-implementations +desc: Handles x86/64 x87 to IR +$end_info$ +*/ + +#include "Interface/Core/OpcodeDispatcher.h" + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace FEXCore::IR { +class OrderedNode; + +#define OpcodeArgs [[maybe_unused]] FEXCore::X86Tables::DecodedOp Op + +//Functions in X87.cpp (no change required) +//GetX87Top +//SetX87TopTag +//GetX87FTW +//SetX87Top +//X87ModifySTP +//EMMS +//FFREE +//LDENV +//FNSTENV +//FNINIT +//FLDCW +//FSTCW +//LDSW +//FNSTSW +//FNSAVE +//FRSTOR +//FXCH +//FCMOV +//FST(register to register) + +template +void OpDispatchBuilder::FLDF64(OpcodeArgs) { + // Update TOP + auto orig_top = GetX87Top(); + auto mask = _Constant(7); + + size_t read_width = (width == 80) ? 16 : width / 8; + + OrderedNode *data{}; + OrderedNode *converted{}; + + if (!Op->Src[0].IsNone()) { + // Read from memory + data = LoadSource_WithOpSize(FPRClass, Op, Op->Src[0], read_width, Op->Flags, -1); + // Convert to 64bit float + if constexpr (width == 32) { + converted = _Float_FToF(8, 4, data); + } else if constexpr (width == 80) { + converted = _F80CVT(8, data); + } else { + converted = data; + } + } + else { + // Implicit arg (does this need to change with width?) + auto offset = _Constant(Op->OP & 7); + data = _And(_Add(orig_top, offset), mask); + data = _LoadContextIndexed(data, 8, MMBaseOffset(), 16, FPRClass); + converted = data; + } + + auto top = _And(_Sub(orig_top, _Constant(1)), mask); + SetX87TopTag(top, X87Tag::Valid); + SetX87Top(top); + // Write to ST[TOP] + _StoreContextIndexed(converted, top, 8, MMBaseOffset(), 16, FPRClass); +} + +template +void OpDispatchBuilder::FLDF64<32>(OpcodeArgs); +template +void OpDispatchBuilder::FLDF64<64>(OpcodeArgs); +template +void OpDispatchBuilder::FLDF64<80>(OpcodeArgs); + +void OpDispatchBuilder::FBLDF64(OpcodeArgs) { + // Update TOP + auto orig_top = GetX87Top(); + auto mask = _Constant(7); + auto top = _And(_Sub(orig_top, _Constant(1)), mask); + SetX87TopTag(top, X87Tag::Valid); + SetX87Top(top); + + // Read from memory + OrderedNode *data = LoadSource_WithOpSize(FPRClass, Op, Op->Src[0], 16, Op->Flags, -1); + OrderedNode *converted = _F80BCDLoad(data); + converted = _F80CVT(8, converted); + _StoreContextIndexed(converted, top, 8, MMBaseOffset(), 16, FPRClass); +} + +void OpDispatchBuilder::FBSTPF64(OpcodeArgs) { + auto orig_top = GetX87Top(); + auto data = _LoadContextIndexed(orig_top, 8, MMBaseOffset(), 16, FPRClass); + + OrderedNode *converted = _F80CVTTo(data, 8); + converted = _F80BCDStore(data); + + StoreResult_WithOpSize(FPRClass, Op, Op->Dest, converted, 10, 1); + + // if we are popping then we must first mark this location as empty + SetX87TopTag(orig_top, X87Tag::Empty); + auto top = _And(_Add(orig_top, _Constant(1)), _Constant(7)); + SetX87Top(top); +} + +template +void OpDispatchBuilder::FLDF64_Const(OpcodeArgs) { + // Update TOP + auto orig_top = GetX87Top(); + auto top = _And(_Sub(orig_top, _Constant(1)), _Constant(7)); + SetX87TopTag(top, X87Tag::Valid); + SetX87Top(top); + auto data = _VCastFromGPR(8, 8, _Constant(num)); + // Write to ST[TOP] + _StoreContextIndexed(data, top, 8, MMBaseOffset(), 16, FPRClass); +} + +template +void OpDispatchBuilder::FLDF64_Const<0x3FF0000000000000>(OpcodeArgs); // 1.0 +template +void OpDispatchBuilder::FLDF64_Const<0x400A934F0979A372>(OpcodeArgs); // log2l(10) +template +void OpDispatchBuilder::FLDF64_Const<0x3FF71547652B82FE>(OpcodeArgs); // log2l(e) +template +void OpDispatchBuilder::FLDF64_Const<0x400921FB54442D18>(OpcodeArgs); // pi +template +void OpDispatchBuilder::FLDF64_Const<0x3FD34413509F79FF>(OpcodeArgs); // log10l(2) +template +void OpDispatchBuilder::FLDF64_Const<0x3FE62E42FEFA39EF>(OpcodeArgs); // log(2) +template +void OpDispatchBuilder::FLDF64_Const<0>(OpcodeArgs); // 0.0 + +void OpDispatchBuilder::FILDF64(OpcodeArgs) { + // Update TOP + auto orig_top = GetX87Top(); + auto top = _And(_Sub(orig_top, _Constant(1)), _Constant(7)); + SetX87TopTag(top, X87Tag::Valid); + SetX87Top(top); + + size_t read_width = GetSrcSize(Op); + // Read from memory + auto data = LoadSource_WithOpSize(GPRClass, Op, Op->Src[0], read_width, Op->Flags, -1); + auto converted = _Float_FromGPR_S(8, read_width, data); + // Write to ST[TOP] + _StoreContextIndexed(converted, top, 8, MMBaseOffset(), 16, FPRClass); +} + +template +void OpDispatchBuilder::FSTF64(OpcodeArgs) { + auto orig_top = GetX87Top(); + auto data = _LoadContextIndexed(orig_top, 8, MMBaseOffset(), 16, FPRClass); + if constexpr (width == 64) { + //Store 64-bit float directly + StoreResult_WithOpSize(FPRClass, Op, Op->Dest, data, 8, 1); + } else if constexpr (width == 32) { + //Convert to 32-bit float and store + auto result = _Float_FToF(4, 8, data); + StoreResult_WithOpSize(FPRClass, Op, Op->Dest, result, 4, 1); + } else if constexpr (width == 80) { + //Convert to 80-bit float + auto result = _F80CVTTo(data, 8); + StoreResult_WithOpSize(FPRClass, Op, Op->Dest, result, 10, 1); + } + + if ((Op->TableInfo->Flags & X86Tables::InstFlags::FLAGS_POP) != 0) { + // if we are popping then we must first mark this location as empty + SetX87TopTag(orig_top, X87Tag::Empty); + // Set the new top now + auto top = _And(_Add(orig_top, _Constant(1)), _Constant(7)); + SetX87Top(top); + } +} + +template +void OpDispatchBuilder::FSTF64<32>(OpcodeArgs); +template +void OpDispatchBuilder::FSTF64<64>(OpcodeArgs); +template +void OpDispatchBuilder::FSTF64<80>(OpcodeArgs); + +template +void OpDispatchBuilder::FISTF64(OpcodeArgs) { + auto Size = GetSrcSize(Op); + + auto orig_top = GetX87Top(); + OrderedNode *data = _LoadContextIndexed(orig_top, 8, MMBaseOffset(), 16, FPRClass); + if constexpr (Truncate) { + data = _Float_ToGPR_ZS(Size, 8, data); + } else { + data = _Float_ToGPR_S(Size, 8, data); + } + StoreResult_WithOpSize(GPRClass, Op, Op->Dest, data, Size, 1); + + if ((Op->TableInfo->Flags & X86Tables::InstFlags::FLAGS_POP) != 0) { + // if we are popping then we must first mark this location as empty + SetX87TopTag(orig_top, X87Tag::Empty); + // Set the new top now + auto top = _And(_Add(orig_top, _Constant(1)), _Constant(7)); + SetX87Top(top); + } +} + +template +void OpDispatchBuilder::FISTF64(OpcodeArgs); +template +void OpDispatchBuilder::FISTF64(OpcodeArgs); + +template +void OpDispatchBuilder::FADDF64(OpcodeArgs) { + auto top = GetX87Top(); + OrderedNode *StackLocation = top; + + OrderedNode *arg{}; + OrderedNode *b{}; + + auto mask = _Constant(7); + + if (!Op->Src[0].IsNone()) { + // Memory arg + if constexpr (Integer) { + arg = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags, -1); + b = _Float_FromGPR_S(8, width / 8, arg); + } else if constexpr (width == 32) { + arg = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags, -1); + b = _Float_FToF(8, 4, arg); + } else if constexpr (width == 64) { + b = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags, -1); + } + } else { + // Implicit arg + auto offset = _Constant(Op->OP & 7); + arg = _And(_Add(top, offset), mask); + if constexpr (ResInST0 == OpResult::RES_STI) { + StackLocation = arg; + } + b = _LoadContextIndexed(arg, 8, MMBaseOffset(), 16, FPRClass); + } + + auto a = _LoadContextIndexed(top, 8, MMBaseOffset(), 16, FPRClass); + auto result = _VFAdd(8, 8, a, b); + if ((Op->TableInfo->Flags & X86Tables::InstFlags::FLAGS_POP) != 0) { + // if we are popping then we must first mark this location as empty + SetX87TopTag(top, X87Tag::Empty); + // Set the new top now + top = _And(_Add(top, _Constant(1)), mask); + SetX87Top(top); + } + + // Write to ST[TOP] + _StoreContextIndexed(result, StackLocation, 8, MMBaseOffset(), 16, FPRClass); +} + +template +void OpDispatchBuilder::FADDF64<32, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template +void OpDispatchBuilder::FADDF64<64, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template +void OpDispatchBuilder::FADDF64<80, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template +void OpDispatchBuilder::FADDF64<80, false, OpDispatchBuilder::OpResult::RES_STI>(OpcodeArgs); + +template +void OpDispatchBuilder::FADDF64<16, true, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template +void OpDispatchBuilder::FADDF64<32, true, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); + +template +void OpDispatchBuilder::FMULF64(OpcodeArgs) { + auto top = GetX87Top(); + OrderedNode *StackLocation = top; + OrderedNode *arg{}; + OrderedNode *b{}; + + auto mask = _Constant(7); + + if (!Op->Src[0].IsNone()) { + // Memory arg + if constexpr (Integer) { + arg = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags, -1); + b = _Float_FromGPR_S(8, width / 8, arg); + } else if constexpr (width == 32) { + arg = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags, -1); + b = _Float_FToF(8, 4, arg); + } else if constexpr (width == 64) { + b = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags, -1); + } + } else { + // Implicit arg + auto offset = _Constant(Op->OP & 7); + arg = _And(_Add(top, offset), mask); + if constexpr (ResInST0 == OpResult::RES_STI) { + StackLocation = arg; + } + + b = _LoadContextIndexed(arg, 8, MMBaseOffset(), 16, FPRClass); + } + + auto a = _LoadContextIndexed(top, 8, MMBaseOffset(), 16, FPRClass); + + auto result = _VFMul(8, 8, a, b); + + if ((Op->TableInfo->Flags & X86Tables::InstFlags::FLAGS_POP) != 0) { + // if we are popping then we must first mark this location as empty + SetX87TopTag(top, X87Tag::Empty); + // Set the new top now + top = _And(_Add(top, _Constant(1)), mask); + SetX87Top(top); + } + + // Write to ST[TOP] + _StoreContextIndexed(result, StackLocation, 8, MMBaseOffset(), 16, FPRClass); +} + +template +void OpDispatchBuilder::FMULF64<32, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template +void OpDispatchBuilder::FMULF64<64, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template +void OpDispatchBuilder::FMULF64<80, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template +void OpDispatchBuilder::FMULF64<80, false, OpDispatchBuilder::OpResult::RES_STI>(OpcodeArgs); + +template +void OpDispatchBuilder::FMULF64<16, true, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template +void OpDispatchBuilder::FMULF64<32, true, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); + +template +void OpDispatchBuilder::FDIVF64(OpcodeArgs) { + auto top = GetX87Top(); + OrderedNode *StackLocation = top; + OrderedNode *arg{}; + OrderedNode *b{}; + + auto mask = _Constant(7); + + if (!Op->Src[0].IsNone()) { + // Memory arg + if constexpr (Integer) { + arg = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags, -1); + b = _Float_FromGPR_S(8, width / 8, arg); + } else if constexpr (width == 32) { + arg = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags, -1); + b = _Float_FToF(8, 4, arg); + } else if constexpr (width == 64) { + b = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags, -1); + } + } else { + // Implicit arg + auto offset = _Constant(Op->OP & 7); + arg = _And(_Add(top, offset), mask); + if constexpr (ResInST0 == OpResult::RES_STI) { + StackLocation = arg; + } + + b = _LoadContextIndexed(arg, 8, MMBaseOffset(), 16, FPRClass); + } + + auto a = _LoadContextIndexed(top, 8, MMBaseOffset(), 16, FPRClass); + + OrderedNode *result{}; + if constexpr (reverse) { + result = _VFDiv(8, 8, b, a); + } + else { + result = _VFDiv(8, 8, a, b); + } + + if ((Op->TableInfo->Flags & X86Tables::InstFlags::FLAGS_POP) != 0) { + // if we are popping then we must first mark this location as empty + SetX87TopTag(top, X87Tag::Empty); + // Set the new top now + top = _And(_Add(top, _Constant(1)), mask); + SetX87Top(top); + } + + // Write to ST[TOP] + _StoreContextIndexed(result, StackLocation, 8, MMBaseOffset(), 16, FPRClass); +} + +template +void OpDispatchBuilder::FDIVF64<32, false, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template +void OpDispatchBuilder::FDIVF64<32, false, true, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); + +template +void OpDispatchBuilder::FDIVF64<64, false, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template +void OpDispatchBuilder::FDIVF64<64, false, true, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); + +template +void OpDispatchBuilder::FDIVF64<80, false, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template +void OpDispatchBuilder::FDIVF64<80, false, true, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); + +template +void OpDispatchBuilder::FDIVF64<80, false, false, OpDispatchBuilder::OpResult::RES_STI>(OpcodeArgs); +template +void OpDispatchBuilder::FDIVF64<80, false, true, OpDispatchBuilder::OpResult::RES_STI>(OpcodeArgs); + +template +void OpDispatchBuilder::FDIVF64<16, true, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template +void OpDispatchBuilder::FDIVF64<16, true, true, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); + +template +void OpDispatchBuilder::FDIVF64<32, true, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template +void OpDispatchBuilder::FDIVF64<32, true, true, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); + +template +void OpDispatchBuilder::FSUBF64(OpcodeArgs) { + auto top = GetX87Top(); + OrderedNode *StackLocation = top; + OrderedNode *arg{}; + OrderedNode *b{}; + + auto mask = _Constant(7); + + if (!Op->Src[0].IsNone()) { + // Memory arg + if constexpr (Integer) { + arg = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags, -1); + b = _Float_FromGPR_S(8, width / 8, arg); + } else if constexpr (width == 32) { + arg = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags, -1); + b = _Float_FToF(8, 4, arg); + } else if constexpr (width == 64) { + b = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags, -1); + } + } else { + // Implicit arg + auto offset = _Constant(Op->OP & 7); + arg = _And(_Add(top, offset), mask); + if constexpr (ResInST0 == OpResult::RES_STI) { + StackLocation = arg; + } + + b = _LoadContextIndexed(arg, 8, MMBaseOffset(), 16, FPRClass); + } + + auto a = _LoadContextIndexed(top, 8, MMBaseOffset(), 16, FPRClass); + + OrderedNode *result{}; + if constexpr (reverse) { + result = _VFSub(8, 8, b, a); + } + else { + result = _VFSub(8, 8, a, b); + } + + if ((Op->TableInfo->Flags & X86Tables::InstFlags::FLAGS_POP) != 0) { + // if we are popping then we must first mark this location as empty + SetX87TopTag(top, X87Tag::Empty); + // Set the new top now + + top = _And(_Add(top, _Constant(1)), mask); + SetX87Top(top); + } + + // Write to ST[TOP] + _StoreContextIndexed(result, StackLocation, 8, MMBaseOffset(), 16, FPRClass); +} + +template +void OpDispatchBuilder::FSUBF64<32, false, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template +void OpDispatchBuilder::FSUBF64<32, false, true, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); + +template +void OpDispatchBuilder::FSUBF64<64, false, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template +void OpDispatchBuilder::FSUBF64<64, false, true, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); + +template +void OpDispatchBuilder::FSUBF64<80, false, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template +void OpDispatchBuilder::FSUBF64<80, false, true, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); + +template +void OpDispatchBuilder::FSUBF64<80, false, false, OpDispatchBuilder::OpResult::RES_STI>(OpcodeArgs); +template +void OpDispatchBuilder::FSUBF64<80, false, true, OpDispatchBuilder::OpResult::RES_STI>(OpcodeArgs); + +template +void OpDispatchBuilder::FSUBF64<16, true, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template +void OpDispatchBuilder::FSUBF64<16, true, true, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); + +template +void OpDispatchBuilder::FSUBF64<32, true, false, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); +template +void OpDispatchBuilder::FSUBF64<32, true, true, OpDispatchBuilder::OpResult::RES_ST0>(OpcodeArgs); + +void OpDispatchBuilder::FCHSF64(OpcodeArgs) { + auto top = GetX87Top(); + auto a = _LoadContextIndexed(top, 8, MMBaseOffset(), 16, FPRClass); + auto b = _Constant(0b1'000'0000'0000'0000ULL); + + auto result = _VXor(8, 8, a, b); + // Write to ST[TOP] + _StoreContextIndexed(result, top, 8, MMBaseOffset(), 16, FPRClass); +} + +void OpDispatchBuilder::FABSF64(OpcodeArgs) { + auto top = GetX87Top(); + auto a = _LoadContextIndexed(top, 8, MMBaseOffset(), 16, FPRClass); + auto b = _Constant(0b0'111'1111'1111'1111ULL); + auto result = _VAnd(8, 8, a, b); + + // Write to ST[TOP] + _StoreContextIndexed(result, top, 8, MMBaseOffset(), 16, FPRClass); +} + +void OpDispatchBuilder::FTSTF64(OpcodeArgs) { + auto top = GetX87Top(); + auto a = _LoadContextIndexed(top, 16, MMBaseOffset(), 16, FPRClass); + + auto low = _Constant(0); + OrderedNode *data = _VCastFromGPR(16, 8, low); + + OrderedNode *Res = _F80Cmp(a, data, + (1 << FCMP_FLAG_EQ) | + (1 << FCMP_FLAG_LT) | + (1 << FCMP_FLAG_UNORDERED)); + + OrderedNode *HostFlag_CF = _GetHostFlag(Res, FCMP_FLAG_LT); + OrderedNode *HostFlag_ZF = _GetHostFlag(Res, FCMP_FLAG_EQ); + OrderedNode *HostFlag_Unordered = _GetHostFlag(Res, FCMP_FLAG_UNORDERED); + HostFlag_CF = _Or(HostFlag_CF, HostFlag_Unordered); + HostFlag_ZF = _Or(HostFlag_ZF, HostFlag_Unordered); + + SetRFLAG(HostFlag_CF); + SetRFLAG(_Constant(0)); + SetRFLAG(HostFlag_Unordered); + SetRFLAG(HostFlag_ZF); +} + +void OpDispatchBuilder::FRNDINTF64(OpcodeArgs) { + auto top = GetX87Top(); + auto a = _LoadContextIndexed(top, 16, MMBaseOffset(), 16, FPRClass); + + auto result = _F80Round(a); + + // Write to ST[TOP] + _StoreContextIndexed(result, top, 16, MMBaseOffset(), 16, FPRClass); +} + +//TODO: Don't round trip through F80 +void OpDispatchBuilder::FXTRACTF64(OpcodeArgs) { + auto orig_top = GetX87Top(); + auto top = _And(_Sub(orig_top, _Constant(1)), _Constant(7)); + SetX87TopTag(top, X87Tag::Valid); + SetX87Top(top); + + auto a = _LoadContextIndexed(orig_top, 8, MMBaseOffset(), 16, FPRClass); + + auto a_f80 = _F80CVTTo(a, 8); + + auto exp_f80 = _F80XTRACT_EXP(a); + auto sig_f80 = _F80XTRACT_SIG(a); + + auto exp = _F80CVT(8, exp_f80); + auto sig = _F80CVT(8, sig_f80); + // Write to ST[TOP] + _StoreContextIndexed(exp, orig_top, 8, MMBaseOffset(), 16, FPRClass); + _StoreContextIndexed(sig, top, 8, MMBaseOffset(), 16, FPRClass); +} + + +template +void OpDispatchBuilder::FCOMIF64(OpcodeArgs) { + auto top = GetX87Top(); + auto mask = _Constant(7); + + OrderedNode *arg{}; + OrderedNode *b{}; + + if (!Op->Src[0].IsNone()) { + // Memory arg + if constexpr (Integer) { + arg = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags, -1); + b = _Float_FromGPR_S(8, width / 8, arg); + } else if constexpr (width == 32) { + arg = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags, -1); + b = _Float_FToF(8, 4, arg); + } else if constexpr (width == 64) { + b = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags, -1); + } + } else { + // Implicit arg + auto offset = _Constant(Op->OP & 7); + arg = _And(_Add(top, offset), mask); + b = _LoadContextIndexed(arg, 8, MMBaseOffset(), 16, FPRClass); + } + + auto a = _LoadContextIndexed(top, 8, MMBaseOffset(), 16, FPRClass); + + auto a_f80 = _F80CVTTo(a, 8); + auto b_f80 = _F80CVTTo(b, 8); + + OrderedNode *Res = _F80Cmp(a_f80, b_f80, + (1 << FCMP_FLAG_EQ) | + (1 << FCMP_FLAG_LT) | + (1 << FCMP_FLAG_UNORDERED)); + + OrderedNode *HostFlag_CF = _GetHostFlag(Res, FCMP_FLAG_LT); + OrderedNode *HostFlag_ZF = _GetHostFlag(Res, FCMP_FLAG_EQ); + OrderedNode *HostFlag_Unordered = _GetHostFlag(Res, FCMP_FLAG_UNORDERED); + HostFlag_CF = _Or(HostFlag_CF, HostFlag_Unordered); + HostFlag_ZF = _Or(HostFlag_ZF, HostFlag_Unordered); + + if constexpr (whichflags == FCOMIFlags::FLAGS_X87) { + SetRFLAG(HostFlag_CF); + SetRFLAG(_Constant(0)); + SetRFLAG(HostFlag_Unordered); + SetRFLAG(HostFlag_ZF); + } + else { + // Invalidate deferred flags early + // OF, SF, AF, PF all undefined + InvalidateDeferredFlags(); + + SetRFLAG(HostFlag_CF); + SetRFLAG(HostFlag_ZF); + SetRFLAG(HostFlag_Unordered); + } + + if constexpr (poptwice) { + // if we are popping then we must first mark this location as empty + SetX87TopTag(top, X87Tag::Empty); + top = _And(_Add(top, _Constant(1)), mask); + SetX87TopTag(top, X87Tag::Empty); + // Set the new top now + top = _And(_Add(top, _Constant(1)), mask); + SetX87Top(top); + } + else if ((Op->TableInfo->Flags & X86Tables::InstFlags::FLAGS_POP) != 0) { + // if we are popping then we must first mark this location as empty + SetX87TopTag(top, X87Tag::Empty); + // Set the new top now + top = _And(_Add(top, _Constant(1)), mask); + SetX87Top(top); + } +} + +template +void OpDispatchBuilder::FCOMIF64<32, false, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, false>(OpcodeArgs); + +template +void OpDispatchBuilder::FCOMIF64<64, false, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, false>(OpcodeArgs); + +template +void OpDispatchBuilder::FCOMIF64<80, false, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, false>(OpcodeArgs); +template +void OpDispatchBuilder::FCOMIF64<80, false, OpDispatchBuilder::FCOMIFlags::FLAGS_RFLAGS, false>(OpcodeArgs); +template +void OpDispatchBuilder::FCOMIF64<80, false, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, true>(OpcodeArgs); + +template +void OpDispatchBuilder::FCOMIF64<16, true, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, false>(OpcodeArgs); + +template +void OpDispatchBuilder::FCOMIF64<32, true, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, false>(OpcodeArgs); + + +void OpDispatchBuilder::FSQRTF64(OpcodeArgs) { + auto top = GetX87Top(); + auto a = _LoadContextIndexed(top, 8, MMBaseOffset(), 16, FPRClass); + + auto result = _VFSqrt(8, 8, a); + + // Write to ST[TOP] + _StoreContextIndexed(result, top, 8, MMBaseOffset(), 16, FPRClass); +} + + +template +void OpDispatchBuilder::X87UnaryOpF64(OpcodeArgs) { + auto top = GetX87Top(); + auto a = _LoadContextIndexed(top, 8, MMBaseOffset(), 16, FPRClass); + + auto result = _F64SIN(a); + // Overwrite the op + result.first->Header.Op = IROp; + + // Write to ST[TOP] + _StoreContextIndexed(result, top, 8, MMBaseOffset(), 16, FPRClass); +} + +template +void OpDispatchBuilder::X87UnaryOpF64(OpcodeArgs); +template +void OpDispatchBuilder::X87UnaryOpF64(OpcodeArgs); +template +void OpDispatchBuilder::X87UnaryOpF64(OpcodeArgs); + + +template +void OpDispatchBuilder::X87BinaryOpF64(OpcodeArgs) { + auto top = GetX87Top(); + + auto mask = _Constant(7); + OrderedNode *st1 = _And(_Add(top, _Constant(1)), mask); + + auto a = _LoadContextIndexed(top, 8, MMBaseOffset(), 16, FPRClass); + st1 = _LoadContextIndexed(st1, 8, MMBaseOffset(), 16, FPRClass); + + auto result = _F64ATAN(a, st1); + // Overwrite the op + result.first->Header.Op = IROp; + + if constexpr (IROp == IR::OP_F64FPREM) { + //TODO: Set C0 to Q2, C3 to Q1, C1 to Q0 + SetRFLAG(_Constant(0)); + } + + // Write to ST[TOP] + _StoreContextIndexed(result, top, 8, MMBaseOffset(), 16, FPRClass); +} + +template +void OpDispatchBuilder::X87BinaryOpF64(OpcodeArgs); +template +void OpDispatchBuilder::X87BinaryOpF64(OpcodeArgs); +template +void OpDispatchBuilder::X87BinaryOpF64(OpcodeArgs); + +void OpDispatchBuilder::X87SinCosF64(OpcodeArgs) { + auto orig_top = GetX87Top(); + auto top = _And(_Sub(orig_top, _Constant(1)), _Constant(7)); + SetX87TopTag(top, X87Tag::Valid); + SetX87Top(top); + + auto a = _LoadContextIndexed(orig_top, 8, MMBaseOffset(), 16, FPRClass); + + auto sin = _F64SIN(a); + auto cos = _F64COS(a); + + // Write to ST[TOP] + _StoreContextIndexed(sin, orig_top, 8, MMBaseOffset(), 16, FPRClass); + _StoreContextIndexed(cos, top, 8, MMBaseOffset(), 16, FPRClass); +} + +void OpDispatchBuilder::X87FYL2XF64(OpcodeArgs) { + bool Plus1 = Op->OP == 0x01F9; // FYL2XP + + auto orig_top = GetX87Top(); + // if we are popping then we must first mark this location as empty + SetX87TopTag(orig_top, X87Tag::Empty); + auto top = _And(_Add(orig_top, _Constant(1)), _Constant(7)); + SetX87Top(top); + + OrderedNode *st0 = _LoadContextIndexed(orig_top, 8, MMBaseOffset(), 16, FPRClass); + OrderedNode *st1 = _LoadContextIndexed(top, 8, MMBaseOffset(), 16, FPRClass); + + if (Plus1) { + auto one = _VCastFromGPR(8, 8, _Constant(0x3FF0000000000000)); + st0 = _VFAdd(8, 8, st0, one); + } + + auto result = _F64FYL2X(st0, st1); + + // Write to ST[TOP] + _StoreContextIndexed(result, top, 8, MMBaseOffset(), 16, FPRClass); +} + +void OpDispatchBuilder::X87TANF64(OpcodeArgs) { + auto orig_top = GetX87Top(); + auto top = _And(_Sub(orig_top, _Constant(1)), _Constant(7)); + SetX87TopTag(top, X87Tag::Valid); + SetX87Top(top); + + auto a = _LoadContextIndexed(orig_top, 8, MMBaseOffset(), 16, FPRClass); + + auto result = _F64TAN(a); + + auto one = _VCastFromGPR(8, 8, _Constant(0x3FF0000000000000)); + + // Write to ST[TOP] + _StoreContextIndexed(result, orig_top, 8, MMBaseOffset(), 16, FPRClass); + _StoreContextIndexed(one, top, 8, MMBaseOffset(), 16, FPRClass); +} + +void OpDispatchBuilder::X87ATANF64(OpcodeArgs) { + auto orig_top = GetX87Top(); + // if we are popping then we must first mark this location as empty + SetX87TopTag(orig_top, X87Tag::Empty); + auto top = _And(_Add(orig_top, _Constant(1)), _Constant(7)); + SetX87Top(top); + + auto a = _LoadContextIndexed(orig_top, 8, MMBaseOffset(), 16, FPRClass); + OrderedNode *st1 = _LoadContextIndexed(top, 8, MMBaseOffset(), 16, FPRClass); + + auto result = _F64ATAN(st1, a); + + // Write to ST[TOP] + _StoreContextIndexed(result, top, 8, MMBaseOffset(), 16, FPRClass); +} + + +//FXAM needs change +void OpDispatchBuilder::X87FXAMF64(OpcodeArgs) { + auto top = GetX87Top(); + auto a = _LoadContextIndexed(top, 8, MMBaseOffset(), 16, FPRClass); + OrderedNode *Result = _VExtractToGPR(8, 8, a, 0); + + // Extract the sign bit + Result = _Lshr(Result, _Constant(63)); + SetRFLAG(Result); + + // Claim this is a normal number + // We don't support anything else + auto FTW = GetX87FTW(top); + auto X87Zero = _Constant(0b11); + auto ZeroConst = _Constant(0); + auto OneConst = _Constant(1); + + // In the case of Zero 0b11 then C3:C2:C0 is 0b101 + auto C3 = _Select(FEXCore::IR::COND_EQ, + FTW, X87Zero, + OneConst, ZeroConst); + + auto C2 = _Select(FEXCore::IR::COND_EQ, + FTW, X87Zero, + ZeroConst, OneConst); + + auto C0 = C3; // Mirror C3 until something other than zero is supported + SetRFLAG(C0); + SetRFLAG(C2); + SetRFLAG(C3); +} + + +} diff --git a/External/FEXCore/Source/Interface/IR/IR.json b/External/FEXCore/Source/Interface/IR/IR.json index eece17151..b56f49295 100644 --- a/External/FEXCore/Source/Interface/IR/IR.json +++ b/External/FEXCore/Source/Interface/IR/IR.json @@ -1478,6 +1478,35 @@ "DestSize": "std::max(4, GetOpSize(_Src1))" } }, + "F64": { + "FPR = F64ATAN FPR:$Src1, FPR:$Src2": { + "DestSize": "8" + }, + "FPR = F64FPREM FPR:$Src1, FPR:$Src2": { + "DestSize": "8" + }, + "FPR = F64FPREM1 FPR:$Src1, FPR:$Src2": { + "DestSize": "8" + }, + "FPR = F64SCALE FPR:$Src1, FPR:$Src2": { + "DestSize": "8" + }, + "FPR = F64F2XM1 FPR:$Src": { + "DestSize": "8" + }, + "FPR = F64FYL2X FPR:$Src, FPR:$Src2": { + "DestSize": "8" + }, + "FPR = F64TAN FPR:$Src": { + "DestSize": "8" + }, + "FPR = F64SIN FPR:$Src": { + "DestSize": "8" + }, + "FPR = F64COS FPR:$Src": { + "DestSize": "8" + } + }, "F80": { "F80LoadFCW GPR:$Src": { "HasSideEffects": true diff --git a/External/FEXCore/include/FEXCore/Core/CoreState.h b/External/FEXCore/include/FEXCore/Core/CoreState.h index 1c9a81f95..b8f2caa13 100644 --- a/External/FEXCore/include/FEXCore/Core/CoreState.h +++ b/External/FEXCore/include/FEXCore/Core/CoreState.h @@ -78,6 +78,16 @@ namespace FEXCore::Core { OPINDEX_F80FPREM, OPINDEX_F80SCALE, + // Double Precision + OPINDEX_F64SIN, + OPINDEX_F64COS, + OPINDEX_F64TAN, + OPINDEX_F64ATAN, + OPINDEX_F64F2XM1, + OPINDEX_F64FYL2X, + OPINDEX_F64FPREM, + OPINDEX_F64FPREM1, + OPINDEX_F64SCALE, // Maximum OPINDEX_MAX, }; From 0a778e802f0f3e945b55690b8b56c871a06b5a4a Mon Sep 17 00:00:00 2001 From: CallumDev Date: Sun, 20 Feb 2022 23:42:53 +1030 Subject: [PATCH 02/15] Unit Tests for x87F64 --- unittests/ASM/X87_F64/D8_00_F64.asm | 23 +++++++++++++++++ unittests/ASM/X87_F64/D8_01_F64.asm | 23 +++++++++++++++++ unittests/ASM/X87_F64/D8_04_F64.asm | 23 +++++++++++++++++ unittests/ASM/X87_F64/D8_05_F64.asm | 23 +++++++++++++++++ unittests/ASM/X87_F64/D8_06_F64.asm | 23 +++++++++++++++++ unittests/ASM/X87_F64/D8_07_F64.asm | 23 +++++++++++++++++ unittests/ASM/X87_F64/D8_C0_F64.asm | 26 ++++++++++++++++++++ unittests/ASM/X87_F64/D8_C8_F64.asm | 21 ++++++++++++++++ unittests/ASM/X87_F64/D8_D9_F64.asm | 25 +++++++++++++++++++ unittests/ASM/X87_F64/D8_E0_F64.asm | 24 ++++++++++++++++++ unittests/ASM/X87_F64/D8_E8_F64.asm | 23 +++++++++++++++++ unittests/ASM/X87_F64/D8_F0_F64.asm | 21 ++++++++++++++++ unittests/ASM/X87_F64/D8_F8_F64.asm | 25 +++++++++++++++++++ unittests/ASM/X87_F64/D9_00_F64.asm | 21 ++++++++++++++++ unittests/ASM/X87_F64/D9_02_F64.asm | 22 +++++++++++++++++ unittests/ASM/X87_F64/D9_F0_F64.asm | 24 ++++++++++++++++++ unittests/ASM/X87_F64/D9_F1_F64.asm | 36 +++++++++++++++++++++++++++ unittests/ASM/X87_F64/D9_F2_F64.asm | 25 +++++++++++++++++++ unittests/ASM/X87_F64/D9_F3_F64.asm | 36 +++++++++++++++++++++++++++ unittests/ASM/X87_F64/D9_F5_F64.asm | 37 ++++++++++++++++++++++++++++ unittests/ASM/X87_F64/D9_F8_F64.asm | 29 ++++++++++++++++++++++ unittests/ASM/X87_F64/D9_FA_F64.asm | 25 +++++++++++++++++++ unittests/ASM/X87_F64/D9_FB_F64.asm | 27 ++++++++++++++++++++ unittests/ASM/X87_F64/D9_FD_F64.asm | 38 +++++++++++++++++++++++++++++ unittests/ASM/X87_F64/D9_FE_F64.asm | 25 +++++++++++++++++++ unittests/ASM/X87_F64/D9_FF_F64.asm | 25 +++++++++++++++++++ unittests/ASM/X87_F64/DA_01_F64.asm | 23 +++++++++++++++++ unittests/ASM/X87_F64/DA_04_F64.asm | 23 +++++++++++++++++ unittests/ASM/X87_F64/DA_05_F64.asm | 23 +++++++++++++++++ unittests/ASM/X87_F64/DA_06_F64.asm | 23 +++++++++++++++++ unittests/ASM/X87_F64/DA_07_F64.asm | 23 +++++++++++++++++ unittests/ASM/X87_F64/DA_D9_F64.asm | 25 +++++++++++++++++++ unittests/ASM/X87_F64/DC_07_F64.asm | 28 +++++++++++++++++++++ unittests/ASM/X87_F64/FLD_F64.asm | 30 +++++++++++++++++++++++ 34 files changed, 871 insertions(+) create mode 100644 unittests/ASM/X87_F64/D8_00_F64.asm create mode 100644 unittests/ASM/X87_F64/D8_01_F64.asm create mode 100644 unittests/ASM/X87_F64/D8_04_F64.asm create mode 100644 unittests/ASM/X87_F64/D8_05_F64.asm create mode 100644 unittests/ASM/X87_F64/D8_06_F64.asm create mode 100644 unittests/ASM/X87_F64/D8_07_F64.asm create mode 100644 unittests/ASM/X87_F64/D8_C0_F64.asm create mode 100644 unittests/ASM/X87_F64/D8_C8_F64.asm create mode 100644 unittests/ASM/X87_F64/D8_D9_F64.asm create mode 100644 unittests/ASM/X87_F64/D8_E0_F64.asm create mode 100644 unittests/ASM/X87_F64/D8_E8_F64.asm create mode 100644 unittests/ASM/X87_F64/D8_F0_F64.asm create mode 100644 unittests/ASM/X87_F64/D8_F8_F64.asm create mode 100644 unittests/ASM/X87_F64/D9_00_F64.asm create mode 100644 unittests/ASM/X87_F64/D9_02_F64.asm create mode 100644 unittests/ASM/X87_F64/D9_F0_F64.asm create mode 100644 unittests/ASM/X87_F64/D9_F1_F64.asm create mode 100644 unittests/ASM/X87_F64/D9_F2_F64.asm create mode 100644 unittests/ASM/X87_F64/D9_F3_F64.asm create mode 100644 unittests/ASM/X87_F64/D9_F5_F64.asm create mode 100644 unittests/ASM/X87_F64/D9_F8_F64.asm create mode 100644 unittests/ASM/X87_F64/D9_FA_F64.asm create mode 100644 unittests/ASM/X87_F64/D9_FB_F64.asm create mode 100644 unittests/ASM/X87_F64/D9_FD_F64.asm create mode 100644 unittests/ASM/X87_F64/D9_FE_F64.asm create mode 100644 unittests/ASM/X87_F64/D9_FF_F64.asm create mode 100644 unittests/ASM/X87_F64/DA_01_F64.asm create mode 100644 unittests/ASM/X87_F64/DA_04_F64.asm create mode 100644 unittests/ASM/X87_F64/DA_05_F64.asm create mode 100644 unittests/ASM/X87_F64/DA_06_F64.asm create mode 100644 unittests/ASM/X87_F64/DA_07_F64.asm create mode 100644 unittests/ASM/X87_F64/DA_D9_F64.asm create mode 100644 unittests/ASM/X87_F64/DC_07_F64.asm create mode 100644 unittests/ASM/X87_F64/FLD_F64.asm diff --git a/unittests/ASM/X87_F64/D8_00_F64.asm b/unittests/ASM/X87_F64/D8_00_F64.asm new file mode 100644 index 000000000..cc517169c --- /dev/null +++ b/unittests/ASM/X87_F64/D8_00_F64.asm @@ -0,0 +1,23 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": ["0x4008000000000000"] + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rdx, 0xe0000000 + +mov rax, 0x3ff0000000000000 ; 1.0 +mov [rdx + 8 * 0], rax +mov rax, 0x40000000 ; 2.0 +mov [rdx + 8 * 1], rax + +fld qword [rdx + 8 * 0] +fadd dword [rdx + 8 * 1] + +fst qword [rdx + 8 * 2] +mov rax, [rdx + 8 * 2] + +hlt diff --git a/unittests/ASM/X87_F64/D8_01_F64.asm b/unittests/ASM/X87_F64/D8_01_F64.asm new file mode 100644 index 000000000..3faef6731 --- /dev/null +++ b/unittests/ASM/X87_F64/D8_01_F64.asm @@ -0,0 +1,23 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": ["0x4000000000000000"] + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rdx, 0xe0000000 + +mov rax, 0x3ff0000000000000 ; 1.0 +mov [rdx + 8 * 0], rax +mov rax, 0x40000000 ; 2.0 +mov [rdx + 8 * 1], rax + +fld qword [rdx + 8 * 0] +fmul dword [rdx + 8 * 1] + +fst qword [rdx + 8 * 2] +mov rax, [rdx + 8 * 2] + +hlt diff --git a/unittests/ASM/X87_F64/D8_04_F64.asm b/unittests/ASM/X87_F64/D8_04_F64.asm new file mode 100644 index 000000000..94c27783b --- /dev/null +++ b/unittests/ASM/X87_F64/D8_04_F64.asm @@ -0,0 +1,23 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": ["0xbff0000000000000"] + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rdx, 0xe0000000 + +mov rax, 0x3ff0000000000000 ; 1.0 +mov [rdx + 8 * 0], rax +mov rax, 0x40000000 ; 2.0 +mov [rdx + 8 * 1], rax + +fld qword [rdx + 8 * 0] +fsub dword [rdx + 8 * 1] + +fst qword [rdx + 8 * 2] +mov rax, [rdx + 8 * 2] + +hlt diff --git a/unittests/ASM/X87_F64/D8_05_F64.asm b/unittests/ASM/X87_F64/D8_05_F64.asm new file mode 100644 index 000000000..7ec49aab9 --- /dev/null +++ b/unittests/ASM/X87_F64/D8_05_F64.asm @@ -0,0 +1,23 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": ["0x3ff0000000000000"] + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rdx, 0xe0000000 + +mov rax, 0x3ff0000000000000 ; 1.0 +mov [rdx + 8 * 0], rax +mov rax, 0x40000000 ; 2.0 +mov [rdx + 8 * 1], rax + +fld qword [rdx + 8 * 0] +fsubr dword [rdx + 8 * 1] + +fst qword [rdx + 8 * 2] +mov rax, [rdx + 8 * 2] + +hlt diff --git a/unittests/ASM/X87_F64/D8_06_F64.asm b/unittests/ASM/X87_F64/D8_06_F64.asm new file mode 100644 index 000000000..0d135733a --- /dev/null +++ b/unittests/ASM/X87_F64/D8_06_F64.asm @@ -0,0 +1,23 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": ["0x3fe0000000000000"] + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rdx, 0xe0000000 + +mov rax, 0x3ff0000000000000 ; 1.0 +mov [rdx + 8 * 0], rax +mov rax, 0x40000000 ; 2.0 +mov [rdx + 8 * 1], rax + +fld qword [rdx + 8 * 0] +fdiv dword [rdx + 8 * 1] + +fst qword [rdx + 8 * 2] +mov rax, [rdx + 8 * 2] + +hlt diff --git a/unittests/ASM/X87_F64/D8_07_F64.asm b/unittests/ASM/X87_F64/D8_07_F64.asm new file mode 100644 index 000000000..d8a953094 --- /dev/null +++ b/unittests/ASM/X87_F64/D8_07_F64.asm @@ -0,0 +1,23 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0x4000000000000000" + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rdx, 0xe0000000 + +mov rax, 0x3ff0000000000000 ; 1.0 +mov [rdx + 8 * 0], rax +mov rax, 0x40000000 ; 2.0 +mov [rdx + 8 * 1], rax + +fld qword [rdx + 8 * 0] +fdivr dword [rdx + 8 * 1] + +fst qword [rdx + 8 * 2] +mov rax, [rdx + 8 * 2] + +hlt diff --git a/unittests/ASM/X87_F64/D8_C0_F64.asm b/unittests/ASM/X87_F64/D8_C0_F64.asm new file mode 100644 index 000000000..59ce7e42f --- /dev/null +++ b/unittests/ASM/X87_F64/D8_C0_F64.asm @@ -0,0 +1,26 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0x4008000000000000" + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rdx, 0xe0000000 + +mov rax, 0x3ff0000000000000 ; 1.0 +mov [rdx + 8 * 0], rax +mov rax, 0x4000000000000000 ; 2.0 +mov [rdx + 8 * 1], rax + +fld qword [rdx + 8 * 0] +fld qword [rdx + 8 * 1] + +; fadd st(0), st(i) +fadd st0, st1 + +fst qword [rdx + 8 * 2] +mov rax, [rdx + 8 * 2] + +hlt diff --git a/unittests/ASM/X87_F64/D8_C8_F64.asm b/unittests/ASM/X87_F64/D8_C8_F64.asm new file mode 100644 index 000000000..5daef2342 --- /dev/null +++ b/unittests/ASM/X87_F64/D8_C8_F64.asm @@ -0,0 +1,21 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": ["0x4010000000000000"] + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rdx, 0xe0000000 + +mov rax, 0x4000000000000000 ; 2.0 +mov [rdx + 8 * 0], rax + +fld qword [rdx + 8 * 0] +fmul st0, st0 + +fst qword [rdx + 8 * 2] +mov rax, [rdx + 8 * 2] + +hlt diff --git a/unittests/ASM/X87_F64/D8_D9_F64.asm b/unittests/ASM/X87_F64/D8_D9_F64.asm new file mode 100644 index 000000000..23414cbae --- /dev/null +++ b/unittests/ASM/X87_F64/D8_D9_F64.asm @@ -0,0 +1,25 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": ["0x3ff0000000000000"], + "RBX": ["0x3ff0000000000000"] + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + + +mov rdx, 0xe0000000 + +; Only tests pop behaviour +fld1 +fldz +fcomp +fld1 + +fstp qword [rdx] +mov rax, [rdx] +fstp qword [rdx] +mov rbx, [rdx] + +hlt diff --git a/unittests/ASM/X87_F64/D8_E0_F64.asm b/unittests/ASM/X87_F64/D8_E0_F64.asm new file mode 100644 index 000000000..e369186ee --- /dev/null +++ b/unittests/ASM/X87_F64/D8_E0_F64.asm @@ -0,0 +1,24 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0xbff0000000000000" + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rdx, 0xe0000000 + +mov rax, 0x4000000000000000 ; 2.0 +mov [rdx + 8 * 0], rax +mov rax, 0x3ff0000000000000 ; 1.0 +mov [rdx + 8 * 1], rax + +fld qword [rdx + 8 * 0] +fld qword [rdx + 8 * 1] +fsub st0, st1 + +fst qword [rdx] +mov rax, [rdx] + +hlt diff --git a/unittests/ASM/X87_F64/D8_E8_F64.asm b/unittests/ASM/X87_F64/D8_E8_F64.asm new file mode 100644 index 000000000..63b7249d7 --- /dev/null +++ b/unittests/ASM/X87_F64/D8_E8_F64.asm @@ -0,0 +1,23 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0x3ff0000000000000" + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rdx, 0xe0000000 + +mov rax, 0x4000000000000000 ; 2.0 +mov [rdx + 8 * 0], rax +mov rax, 0x3ff0000000000000 ; 1.0 +mov [rdx + 8 * 1], rax + +fld qword [rdx + 8 * 0] +fld qword [rdx + 8 * 1] +fsubr st0, st1 + +fst qword [rdx] +mov rax, [rdx] +hlt diff --git a/unittests/ASM/X87_F64/D8_F0_F64.asm b/unittests/ASM/X87_F64/D8_F0_F64.asm new file mode 100644 index 000000000..13db22d9e --- /dev/null +++ b/unittests/ASM/X87_F64/D8_F0_F64.asm @@ -0,0 +1,21 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0x3ff0000000000000" + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rdx, 0xe0000000 + +mov rax, 0x4000000000000000 ; 2.0 +mov [rdx + 8 * 0], rax + +fld qword [rdx + 8 * 0] +fdiv st0, st0 + +fst qword [rdx] +mov rax, [rdx] + +hlt diff --git a/unittests/ASM/X87_F64/D8_F8_F64.asm b/unittests/ASM/X87_F64/D8_F8_F64.asm new file mode 100644 index 000000000..8e3e72afc --- /dev/null +++ b/unittests/ASM/X87_F64/D8_F8_F64.asm @@ -0,0 +1,25 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0x3fe0000000000000" + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rdx, 0xe0000000 + +mov rax, 0x4000000000000000 ; 2.0 +mov [rdx + 8 * 0], rax +mov rax, 0x4010000000000000 ; 4.0 +mov [rdx + 8 * 1], rax + +fld qword [rdx + 8 * 0] +fld qword [rdx + 8 * 1] + +fdivr st0, st1 + +fst qword [rdx] +mov rax, [rdx] + +hlt diff --git a/unittests/ASM/X87_F64/D9_00_F64.asm b/unittests/ASM/X87_F64/D9_00_F64.asm new file mode 100644 index 000000000..08a5018cc --- /dev/null +++ b/unittests/ASM/X87_F64/D9_00_F64.asm @@ -0,0 +1,21 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0x3f800000" + }, + "X86ReducedPrecision": "1" +} +%endif + +mov rdx, 0xe0000000 + +mov eax, 0x3f800000 ; 1.0 +mov [rdx + 8 * 0], eax + +fld dword [rdx + 8 * 0] +fst dword [rdx] + +xor eax, eax +mov eax, [rdx] + +hlt diff --git a/unittests/ASM/X87_F64/D9_02_F64.asm b/unittests/ASM/X87_F64/D9_02_F64.asm new file mode 100644 index 000000000..0d85d0b91 --- /dev/null +++ b/unittests/ASM/X87_F64/D9_02_F64.asm @@ -0,0 +1,22 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0x3F800000" + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rdx, 0xe0000000 + +mov eax, 0x3f800000 ; 1.0 +mov [rdx + 8 * 0], eax +mov eax, 0x0 +mov [rdx + 8 * 1], eax + +fld dword [rdx + 8 * 0] +fst dword [rdx + 8 * 1] + +mov eax, [rdx + 8 * 1] + +hlt diff --git a/unittests/ASM/X87_F64/D9_F0_F64.asm b/unittests/ASM/X87_F64/D9_F0_F64.asm new file mode 100644 index 000000000..7170e398b --- /dev/null +++ b/unittests/ASM/X87_F64/D9_F0_F64.asm @@ -0,0 +1,24 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": ["0x0"] + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rbx, 0xe0000000 + +lea rdx, [rel data] +fld tword [rdx + 8 * 0] +f2xm1 + +fst qword [rbx] +mov rax, [rbx] + +hlt + +align 8 +data: + dt 0.0 + dq 0 diff --git a/unittests/ASM/X87_F64/D9_F1_F64.asm b/unittests/ASM/X87_F64/D9_F1_F64.asm new file mode 100644 index 000000000..aa22954ed --- /dev/null +++ b/unittests/ASM/X87_F64/D9_F1_F64.asm @@ -0,0 +1,36 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": ["0x3ff0000000000000"], + "RBX": ["0x4020000000000000"] + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rcx, 0xe0000000 + +lea rdx, [rel data2] +fld tword [rdx + 8 * 0] + +lea rdx, [rel data] +fld tword [rdx + 8 * 0] + +fyl2x +fld1 + +fstp qword [rcx] +mov rax, [rcx] +fst qword [rcx] +mov rbx, [rcx] + +hlt + +align 8 +data: + dt 16.0 + dq 0 + +data2: + dt 2.0 + dq 0 diff --git a/unittests/ASM/X87_F64/D9_F2_F64.asm b/unittests/ASM/X87_F64/D9_F2_F64.asm new file mode 100644 index 000000000..6df87b522 --- /dev/null +++ b/unittests/ASM/X87_F64/D9_F2_F64.asm @@ -0,0 +1,25 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": ["0x3ff0000000000000"] + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rbx, 0xe0000000 + +lea rdx, [rel data] +fld tword [rdx + 8 * 0] + +fptan + +fst qword [rbx] +mov rax, [rbx] + +hlt + +align 8 +data: + dt 1.0 + dq 0 diff --git a/unittests/ASM/X87_F64/D9_F3_F64.asm b/unittests/ASM/X87_F64/D9_F3_F64.asm new file mode 100644 index 000000000..f5a976303 --- /dev/null +++ b/unittests/ASM/X87_F64/D9_F3_F64.asm @@ -0,0 +1,36 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": ["0x3ff0000000000000"], + "RBX": ["0x3ff921fb54442d18"] + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rcx, 0xe0000000 + +lea rdx, [rel data] +fld tword [rdx + 8 * 0] + +lea rdx, [rel data2] +fld tword [rdx + 8 * 0] + +fpatan +fld1 + +fstp qword [rcx] +mov rax, [rcx] + +fstp qword [rcx] +mov rbx, [rcx] + +hlt + +align 8 +data: + dt 7.0 + dq 0 +data2: + dt 0.0 + dq 0 diff --git a/unittests/ASM/X87_F64/D9_F5_F64.asm b/unittests/ASM/X87_F64/D9_F5_F64.asm new file mode 100644 index 000000000..f1dab30b3 --- /dev/null +++ b/unittests/ASM/X87_F64/D9_F5_F64.asm @@ -0,0 +1,37 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": ["0xbf666666"], + "RBX": ["0x40400000"] + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rcx, 0xe0000000 + +lea rdx, [rel data] +fld tword [rdx + 8 * 0] + +lea rdx, [rel data2] +fld tword [rdx + 8 * 0] + +fprem1 + +; Store as single precision to get around precision issues + +fstp dword [rcx] +mov eax, [rcx] + +fst dword [rcx] +mov ebx, [rcx] + +hlt + +align 8 +data: + dt 3.0 + dq 0 +data2: + dt 5.1 + dq 0 diff --git a/unittests/ASM/X87_F64/D9_F8_F64.asm b/unittests/ASM/X87_F64/D9_F8_F64.asm new file mode 100644 index 000000000..df1cd0ca4 --- /dev/null +++ b/unittests/ASM/X87_F64/D9_F8_F64.asm @@ -0,0 +1,29 @@ +%ifdef CONFIG +{ + "RegData": { + "MM6": ["0x8666666666666666", "0x4000"], + "MM7": ["0xC000000000000000", "0x4000"] + }, + "MemoryRegions": { + "0x100000000": "4096" + } +} +%endif + +lea rdx, [rel data] +fld tword [rdx + 8 * 0] + +lea rdx, [rel data2] +fld tword [rdx + 8 * 0] + +fprem + +hlt + +align 8 +data: + dt 3.0 + dq 0 +data2: + dt 5.1 + dq 0 diff --git a/unittests/ASM/X87_F64/D9_FA_F64.asm b/unittests/ASM/X87_F64/D9_FA_F64.asm new file mode 100644 index 000000000..f91ead03d --- /dev/null +++ b/unittests/ASM/X87_F64/D9_FA_F64.asm @@ -0,0 +1,25 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": ["0x4010000000000000"] + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rbx, 0xe0000000 + +lea rdx, [rel data] +fld tword [rdx + 8 * 0] + +fsqrt + +fst qword [rbx] +mov rax, [rbx] + +hlt + +align 8 +data: + dt 16.0 + dq 0 diff --git a/unittests/ASM/X87_F64/D9_FB_F64.asm b/unittests/ASM/X87_F64/D9_FB_F64.asm new file mode 100644 index 000000000..8fb3c5104 --- /dev/null +++ b/unittests/ASM/X87_F64/D9_FB_F64.asm @@ -0,0 +1,27 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": ["0x3fe14a280fb5068c"], + "RBX": ["0x3feaed548f090cee"] + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif +mov rcx, 0xe0000000 + +lea rdx, [rel data] +fld tword [rdx + 8 * 0] + +fsincos + +fstp qword [rcx] +mov rax, [rcx] +fstp qword [rcx] +mov rbx, [rcx] + +hlt + +align 8 +data: + dt 1.0 + dq 0 diff --git a/unittests/ASM/X87_F64/D9_FD_F64.asm b/unittests/ASM/X87_F64/D9_FD_F64.asm new file mode 100644 index 000000000..46f4bebf2 --- /dev/null +++ b/unittests/ASM/X87_F64/D9_FD_F64.asm @@ -0,0 +1,38 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": ["0x43000000"], + "RBX": ["0x40b00000"] + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rcx, 0xe0000000 + +lea rdx, [rel data2] +fld tword [rdx + 8 * 0] + +lea rdx, [rel data] +fld tword [rdx + 8 * 0] + +fscale + +; Store as single precision to get around precision issues + +fstp dword [rcx] +mov eax, [rcx] + +fst dword [rcx] +mov ebx, [rcx] + +hlt + +align 8 +data: + dt 4.0 + dq 0 + +data2: + dt 5.5 + dq 0 diff --git a/unittests/ASM/X87_F64/D9_FE_F64.asm b/unittests/ASM/X87_F64/D9_FE_F64.asm new file mode 100644 index 000000000..09478acd7 --- /dev/null +++ b/unittests/ASM/X87_F64/D9_FE_F64.asm @@ -0,0 +1,25 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": ["0x3feaed548f090cee"] + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rbx, 0xe0000000 + +lea rdx, [rel data] +fld tword [rdx + 8 * 0] + +fsin + +fst qword [rbx] +mov rax, [rbx] + +hlt + +align 8 +data: + dt 1.0 + dq 0 diff --git a/unittests/ASM/X87_F64/D9_FF_F64.asm b/unittests/ASM/X87_F64/D9_FF_F64.asm new file mode 100644 index 000000000..b95d66f20 --- /dev/null +++ b/unittests/ASM/X87_F64/D9_FF_F64.asm @@ -0,0 +1,25 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": ["0xbfdaa22657537205"] + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rbx, 0xe0000000 + +lea rdx, [rel data] +fld tword [rdx + 8 * 0] + +fcos + +fst qword [rbx] +mov rax, [rbx] + +hlt + +align 8 +data: + dt 2.0 + dq 0 diff --git a/unittests/ASM/X87_F64/DA_01_F64.asm b/unittests/ASM/X87_F64/DA_01_F64.asm new file mode 100644 index 000000000..c7604e840 --- /dev/null +++ b/unittests/ASM/X87_F64/DA_01_F64.asm @@ -0,0 +1,23 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": ["0x4000000000000000"] + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rdx, 0xe0000000 + +mov rax, 0x3ff0000000000000 ; 1.0 +mov [rdx + 8 * 0], rax +mov eax, 2 +mov [rdx + 8 * 1], eax + +fld qword [rdx + 8 * 0] +fimul dword [rdx + 8 * 1] + +fst qword [rdx] +mov rax, [rdx] + +hlt diff --git a/unittests/ASM/X87_F64/DA_04_F64.asm b/unittests/ASM/X87_F64/DA_04_F64.asm new file mode 100644 index 000000000..589d094e6 --- /dev/null +++ b/unittests/ASM/X87_F64/DA_04_F64.asm @@ -0,0 +1,23 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": ["0xbff0000000000000"] + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rdx, 0xe0000000 + +mov rax, 0x3ff0000000000000 ; 1.0 +mov [rdx + 8 * 0], rax +mov eax, 2 +mov [rdx + 8 * 1], eax + +fld qword [rdx + 8 * 0] +fisub dword [rdx + 8 * 1] + +fst qword [rdx] +mov rax, [rdx] + +hlt diff --git a/unittests/ASM/X87_F64/DA_05_F64.asm b/unittests/ASM/X87_F64/DA_05_F64.asm new file mode 100644 index 000000000..1fce42fb7 --- /dev/null +++ b/unittests/ASM/X87_F64/DA_05_F64.asm @@ -0,0 +1,23 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": ["0x3ff0000000000000"] + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rdx, 0xe0000000 + +mov rax, 0x3ff0000000000000 ; 1.0 +mov [rdx + 8 * 0], rax +mov eax, 2 +mov [rdx + 8 * 1], eax + +fld qword [rdx + 8 * 0] +fisubr dword [rdx + 8 * 1] + +fst qword [rdx] +mov rax, [rdx] + +hlt diff --git a/unittests/ASM/X87_F64/DA_06_F64.asm b/unittests/ASM/X87_F64/DA_06_F64.asm new file mode 100644 index 000000000..2dd8527cd --- /dev/null +++ b/unittests/ASM/X87_F64/DA_06_F64.asm @@ -0,0 +1,23 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": ["0x3fe0000000000000"] + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rdx, 0xe0000000 + +mov rax, 0x3ff0000000000000 ; 1.0 +mov [rdx + 8 * 0], rax +mov eax, 2 +mov [rdx + 8 * 1], eax + +fld qword [rdx + 8 * 0] +fidiv dword [rdx + 8 * 1] + +fst qword [rdx] +mov rax, [rdx] + +hlt diff --git a/unittests/ASM/X87_F64/DA_07_F64.asm b/unittests/ASM/X87_F64/DA_07_F64.asm new file mode 100644 index 000000000..0f14addba --- /dev/null +++ b/unittests/ASM/X87_F64/DA_07_F64.asm @@ -0,0 +1,23 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": ["0x4000000000000000"] + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rdx, 0xe0000000 + +mov rax, 0x3ff0000000000000 ; 1.0 +mov [rdx + 8 * 0], rax +mov eax, 2 +mov [rdx + 8 * 1], eax + +fld qword [rdx + 8 * 0] +fidivr dword [rdx + 8 * 1] + +fst qword [rdx] +mov rax, [rdx] + +hlt diff --git a/unittests/ASM/X87_F64/DA_D9_F64.asm b/unittests/ASM/X87_F64/DA_D9_F64.asm new file mode 100644 index 000000000..bdd4bcb1f --- /dev/null +++ b/unittests/ASM/X87_F64/DA_D9_F64.asm @@ -0,0 +1,25 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": ["0x3ff0000000000000"], + "RBX": ["0x3ff0000000000000"] + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rdx, 0xe0000000 + +; Only tests pop behaviour +fld1 +fldz +fldz +fcompp +fld1 + +fstp qword [rdx] +mov rax, [rdx] +fstp qword [rdx] +mov rbx, [rdx] + +hlt diff --git a/unittests/ASM/X87_F64/DC_07_F64.asm b/unittests/ASM/X87_F64/DC_07_F64.asm new file mode 100644 index 000000000..941f7583d --- /dev/null +++ b/unittests/ASM/X87_F64/DC_07_F64.asm @@ -0,0 +1,28 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": ["0x4010000000000000"] + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rbx, 0xe0000000 + +lea rdx, [rel data] +fld tword [rdx + 8 * 0] + +lea rdx, [rel data2] +fdivr qword [rdx + 8 * 0] + +fst qword [rbx] +mov rax, [rbx] + +hlt + +align 8 +data: + dt 2.0 + dq 0 +data2: + dq 8.0 diff --git a/unittests/ASM/X87_F64/FLD_F64.asm b/unittests/ASM/X87_F64/FLD_F64.asm new file mode 100644 index 000000000..9645a3472 --- /dev/null +++ b/unittests/ASM/X87_F64/FLD_F64.asm @@ -0,0 +1,30 @@ +%ifdef CONFIG +{ + "Env": { "FEX_X87REDUCEDPRECISION" : "1" }, + "RegData": { + "RAX": "0x40490fdb", + "RBX": "0x4008000000000000" + } +} +%endif + +lea rbp, [rel data] +mov rdx, 0xe0000000 + +fld dword [rbp] +fst dword [rdx] + +xor rax, rax +mov eax, [rdx] + +fld qword [rbp + 4] +fst qword [rdx] + +mov rbx, [rdx] + +hlt + +align 8 +data: + dd 0x40490fdb + dq 0x4008000000000000 From cd16769e574b2c3fe9a5d4da1b21a071a638805a Mon Sep 17 00:00:00 2001 From: CallumDev Date: Sun, 20 Feb 2022 23:46:27 +1030 Subject: [PATCH 03/15] F64: Fix Arm64 JIT compile error --- External/FEXCore/Source/Interface/Core/JIT/Arm64/JIT.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/External/FEXCore/Source/Interface/Core/JIT/Arm64/JIT.cpp b/External/FEXCore/Source/Interface/Core/JIT/Arm64/JIT.cpp index b17c98d32..6912a33e0 100644 --- a/External/FEXCore/Source/Interface/Core/JIT/Arm64/JIT.cpp +++ b/External/FEXCore/Source/Interface/Core/JIT/Arm64/JIT.cpp @@ -221,7 +221,7 @@ void Arm64JITCore::Op_Unhandled(IR::IROp_Header *IROp, IR::NodeID Node) { } break; - case FABI_F64_F64: { + case FABI_F64_F64_F64: { SpillStaticRegs(); PushDynamicRegsAndLR(); From 91f48c63ff0ebdc662a4ef7fcb14fa641b71780e Mon Sep 17 00:00:00 2001 From: CallumDev Date: Mon, 21 Feb 2022 00:06:37 +1030 Subject: [PATCH 04/15] Implement F64 ops in Interpreter --- .../Interface/Core/Interpreter/F80Ops.cpp | 75 +++++++++++++++++++ .../Core/Interpreter/InterpreterOps.cpp | 11 +++ .../Core/Interpreter/InterpreterOps.h | 11 +++ 3 files changed, 97 insertions(+) diff --git a/External/FEXCore/Source/Interface/Core/Interpreter/F80Ops.cpp b/External/FEXCore/Source/Interface/Core/Interpreter/F80Ops.cpp index a0143bdad..26fedb250 100644 --- a/External/FEXCore/Source/Interface/Core/Interpreter/F80Ops.cpp +++ b/External/FEXCore/Source/Interface/Core/Interpreter/F80Ops.cpp @@ -356,6 +356,81 @@ DEF_OP(F80BCDSTORE) { memcpy(GDP, BCD, 10); } +DEF_OP(F64SIN) { + auto Op = IROp->C(); + double Src = *GetSrc(Data->SSAData, Op->Header.Args[0]); + double Tmp = sin(Src); + memcpy(GDP, &Tmp, sizeof(double)); +} + +DEF_OP(F64COS) { + auto Op = IROp->C(); + double Src = *GetSrc(Data->SSAData, Op->Header.Args[0]); + double Tmp = cos(Src); + memcpy(GDP, &Tmp, sizeof(double)); +} + +DEF_OP(F64TAN) { + auto Op = IROp->C(); + double Src = *GetSrc(Data->SSAData, Op->Header.Args[0]); + double Tmp = tan(Src); + memcpy(GDP, &Tmp, sizeof(double)); +} + +DEF_OP(F64F2XM1) { + auto Op = IROp->C(); + double Src = *GetSrc(Data->SSAData, Op->Header.Args[0]); + double Tmp = exp2(Src) - 1.0; + memcpy(GDP, &Tmp, sizeof(double)); +} + +DEF_OP(F64ATAN) { + auto Op = IROp->C(); + double Src1 = *GetSrc(Data->SSAData, Op->Header.Args[0]); + double Src2 = *GetSrc(Data->SSAData, Op->Header.Args[1]); + double Tmp = atan2(Src1, Src2); + + memcpy(GDP, &Tmp, sizeof(double)); +} + +DEF_OP(F64FPREM) { + auto Op = IROp->C(); + double Src1 = *GetSrc(Data->SSAData, Op->Header.Args[0]); + double Src2 = *GetSrc(Data->SSAData, Op->Header.Args[1]); + double Tmp = remainder(Src1, Src2); + + memcpy(GDP, &Tmp, sizeof(double)); +} + +DEF_OP(F64FPREM1) { + auto Op = IROp->C(); + double Src1 = *GetSrc(Data->SSAData, Op->Header.Args[0]); + double Src2 = *GetSrc(Data->SSAData, Op->Header.Args[1]); + double Tmp = remainder(Src1, Src2); + + memcpy(GDP, &Tmp, sizeof(double)); +} + +DEF_OP(F64FYL2X) { + auto Op = IROp->C(); + double Src1 = *GetSrc(Data->SSAData, Op->Header.Args[0]); + double Src2 = *GetSrc(Data->SSAData, Op->Header.Args[1]); + double Tmp = Src2 * log2(Src1); + + memcpy(GDP, &Tmp, sizeof(double)); +} + +DEF_OP(F64SCALE) { + auto Op = IROp->C(); + double Src1 = *GetSrc(Data->SSAData, Op->Header.Args[0]); + double Src2 = *GetSrc(Data->SSAData, Op->Header.Args[1]); + double trunc = round(Src2); + double Tmp = Src1 * exp2(trunc); + + memcpy(GDP, &Tmp, sizeof(double)); +} + + #undef DEF_OP } // namespace FEXCore::CPU diff --git a/External/FEXCore/Source/Interface/Core/Interpreter/InterpreterOps.cpp b/External/FEXCore/Source/Interface/Core/Interpreter/InterpreterOps.cpp index 2ae4f80f4..9693cd95f 100644 --- a/External/FEXCore/Source/Interface/Core/Interpreter/InterpreterOps.cpp +++ b/External/FEXCore/Source/Interface/Core/Interpreter/InterpreterOps.cpp @@ -311,6 +311,17 @@ constexpr OpHandlerArray InterpreterOpHandlers = [] { REGISTER_OP(F80BCDLOAD, F80BCDLOAD); REGISTER_OP(F80BCDSTORE, F80BCDSTORE); + // F64 ops + REGISTER_OP(F64SIN, F64SIN); + REGISTER_OP(F64COS, F64COS); + REGISTER_OP(F64TAN, F64TAN); + REGISTER_OP(F64F2XM1, F64F2XM1); + REGISTER_OP(F64ATAN, F64ATAN); + REGISTER_OP(F64FPREM, F64FPREM); + REGISTER_OP(F64FPREM1, F64FPREM1); + REGISTER_OP(F64FYL2X, F64FYL2X); + REGISTER_OP(F64SCALE, F64SCALE); + return Handlers; }(); diff --git a/External/FEXCore/Source/Interface/Core/Interpreter/InterpreterOps.h b/External/FEXCore/Source/Interface/Core/Interpreter/InterpreterOps.h index 0b3d9ae4a..bbce6b065 100644 --- a/External/FEXCore/Source/Interface/Core/Interpreter/InterpreterOps.h +++ b/External/FEXCore/Source/Interface/Core/Interpreter/InterpreterOps.h @@ -330,6 +330,17 @@ namespace FEXCore::CPU { DEF_OP(F80CMP); DEF_OP(F80BCDLOAD); DEF_OP(F80BCDSTORE); + + //< F64 ops + DEF_OP(F64SIN); + DEF_OP(F64COS); + DEF_OP(F64TAN); + DEF_OP(F64F2XM1); + DEF_OP(F64ATAN); + DEF_OP(F64FPREM); + DEF_OP(F64FPREM1); + DEF_OP(F64FYL2X); + DEF_OP(F64SCALE); #undef DEF_OP template [[nodiscard]] static bool IsConditionTrue(uint8_t Cond, uint64_t Src1, uint64_t Src2) { From d02712ddc622a318f47780832020a51d2da71f0d Mon Sep 17 00:00:00 2001 From: CallumDev Date: Mon, 21 Feb 2022 00:31:49 +1030 Subject: [PATCH 05/15] X87F64: Basic implementation of FRNDINT --- .../Core/OpcodeDispatcher/X87F64.cpp | 11 +++++----- unittests/ASM/X87_F64/D9_FC_F64.asm | 22 +++++++++++++++++++ 2 files changed, 28 insertions(+), 5 deletions(-) create mode 100644 unittests/ASM/X87_F64/D9_FC_F64.asm diff --git a/External/FEXCore/Source/Interface/Core/OpcodeDispatcher/X87F64.cpp b/External/FEXCore/Source/Interface/Core/OpcodeDispatcher/X87F64.cpp index fd6930be6..445b05f2b 100644 --- a/External/FEXCore/Source/Interface/Core/OpcodeDispatcher/X87F64.cpp +++ b/External/FEXCore/Source/Interface/Core/OpcodeDispatcher/X87F64.cpp @@ -551,14 +551,15 @@ void OpDispatchBuilder::FTSTF64(OpcodeArgs) { SetRFLAG(HostFlag_ZF); } +//TODO: This should obey rounding mode void OpDispatchBuilder::FRNDINTF64(OpcodeArgs) { auto top = GetX87Top(); - auto a = _LoadContextIndexed(top, 16, MMBaseOffset(), 16, FPRClass); + auto a = _LoadContextIndexed(top, 8, MMBaseOffset(), 16, FPRClass); - auto result = _F80Round(a); + auto result = _Vector_FToI(8, 8, a, FEXCore::IR::Round_Nearest); // Write to ST[TOP] - _StoreContextIndexed(result, top, 16, MMBaseOffset(), 16, FPRClass); + _StoreContextIndexed(result, top, 8, MMBaseOffset(), 16, FPRClass); } //TODO: Don't round trip through F80 @@ -572,8 +573,8 @@ void OpDispatchBuilder::FXTRACTF64(OpcodeArgs) { auto a_f80 = _F80CVTTo(a, 8); - auto exp_f80 = _F80XTRACT_EXP(a); - auto sig_f80 = _F80XTRACT_SIG(a); + auto exp_f80 = _F80XTRACT_EXP(a_f80); + auto sig_f80 = _F80XTRACT_SIG(a_f80); auto exp = _F80CVT(8, exp_f80); auto sig = _F80CVT(8, sig_f80); diff --git a/unittests/ASM/X87_F64/D9_FC_F64.asm b/unittests/ASM/X87_F64/D9_FC_F64.asm new file mode 100644 index 000000000..827211bcc --- /dev/null +++ b/unittests/ASM/X87_F64/D9_FC_F64.asm @@ -0,0 +1,22 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": ["0x3ff0000000000000"] + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rdx, 0xe0000000 + +mov eax, 0x3f834241 ; 1.02546 +mov [rdx + 8 * 0], eax + +fld dword [rdx + 8 * 0] + +frndint + +fst qword [rdx] +mov rax, [rdx] + +hlt From 3f89e46d66a90dee256cb2b988be139ea415d6e9 Mon Sep 17 00:00:00 2001 From: CallumDev Date: Mon, 21 Feb 2022 01:37:18 +1030 Subject: [PATCH 06/15] Add X87ReducedPrecision to FEXConfig --- Source/Tools/FEXConfig/Main.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Source/Tools/FEXConfig/Main.cpp b/Source/Tools/FEXConfig/Main.cpp index f7c51cd84..a8bb100e3 100644 --- a/Source/Tools/FEXConfig/Main.cpp +++ b/Source/Tools/FEXConfig/Main.cpp @@ -526,6 +526,13 @@ namespace { ConfigChanged = true; } + Value = LoadedConfig->Get(FEXCore::Config::ConfigOption::CONFIG_X87REDUCEDPRECISION); + bool X87ReducedPrecision = Value.has_value() && **Value == "1"; + if (ImGui::Checkbox("X87 Reduced Precision", &X87ReducedPrecision)) { + LoadedConfig->EraseSet(FEXCore::Config::ConfigOption::CONFIG_X87REDUCEDPRECISION, X87ReducedPrecision ? "1" : "0"); + ConfigChanged = true; + } + ImGui::Text("SMC Checks: "); int SMCChecks = FEXCore::Config::CONFIG_SMC_MMAN; From b85abf725dd3399cc14a472c591f514fe350b992 Mon Sep 17 00:00:00 2001 From: CallumDev Date: Mon, 21 Feb 2022 01:37:31 +1030 Subject: [PATCH 07/15] Implement FCOM in 64-bit ops --- .../Core/OpcodeDispatcher/X87F64.cpp | 17 ++++++++-------- unittests/ASM/X87_F64/FCOM_F64.asm | 20 +++++++++++++++++++ 2 files changed, 28 insertions(+), 9 deletions(-) create mode 100644 unittests/ASM/X87_F64/FCOM_F64.asm diff --git a/External/FEXCore/Source/Interface/Core/OpcodeDispatcher/X87F64.cpp b/External/FEXCore/Source/Interface/Core/OpcodeDispatcher/X87F64.cpp index 445b05f2b..243603628 100644 --- a/External/FEXCore/Source/Interface/Core/OpcodeDispatcher/X87F64.cpp +++ b/External/FEXCore/Source/Interface/Core/OpcodeDispatcher/X87F64.cpp @@ -612,17 +612,16 @@ void OpDispatchBuilder::FCOMIF64(OpcodeArgs) { auto a = _LoadContextIndexed(top, 8, MMBaseOffset(), 16, FPRClass); - auto a_f80 = _F80CVTTo(a, 8); - auto b_f80 = _F80CVTTo(b, 8); + auto one = _Constant(1); - OrderedNode *Res = _F80Cmp(a_f80, b_f80, - (1 << FCMP_FLAG_EQ) | - (1 << FCMP_FLAG_LT) | - (1 << FCMP_FLAG_UNORDERED)); + auto cmp_eq = _VFCMPEQ(8, 8, a, b); + auto cmp_lt = _VFCMPLT(8, 8, a, b); + auto cmp_un = _VFCMPUNO(8, 8, a, b); - OrderedNode *HostFlag_CF = _GetHostFlag(Res, FCMP_FLAG_LT); - OrderedNode *HostFlag_ZF = _GetHostFlag(Res, FCMP_FLAG_EQ); - OrderedNode *HostFlag_Unordered = _GetHostFlag(Res, FCMP_FLAG_UNORDERED); + OrderedNode* HostFlag_ZF = _And(_VExtractToGPR(8, 8, cmp_eq, 0), one); + OrderedNode* HostFlag_CF = _And(_VExtractToGPR(8, 8, cmp_lt, 0), one); + OrderedNode* HostFlag_Unordered = _And(_VExtractToGPR(8, 8, cmp_un, 0), one); + HostFlag_CF = _Or(HostFlag_CF, HostFlag_Unordered); HostFlag_ZF = _Or(HostFlag_ZF, HostFlag_Unordered); diff --git a/unittests/ASM/X87_F64/FCOM_F64.asm b/unittests/ASM/X87_F64/FCOM_F64.asm new file mode 100644 index 000000000..7c7cec5d7 --- /dev/null +++ b/unittests/ASM/X87_F64/FCOM_F64.asm @@ -0,0 +1,20 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": ["0x0"] + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +fld1 +fldz +fcomp +fnstsw ax +test ah, 041h; I *think* I've got the right flags there... +jp good +mov rax, 0 +hlt +good: +mov rax, 1 +hlt From ef899b7b1ac8c3a7031411c282014db6920fd4d9 Mon Sep 17 00:00:00 2001 From: CallumDev Date: Mon, 21 Feb 2022 02:18:27 +1030 Subject: [PATCH 08/15] F64: Working FABS and FCHS --- .../Core/OpcodeDispatcher/X87F64.cpp | 4 +-- unittests/ASM/X87_F64/D9_E0_F64.asm | 35 +++++++++++++++++++ unittests/ASM/X87_F64/D9_E1_F64.asm | 35 +++++++++++++++++++ 3 files changed, 72 insertions(+), 2 deletions(-) create mode 100644 unittests/ASM/X87_F64/D9_E0_F64.asm create mode 100644 unittests/ASM/X87_F64/D9_E1_F64.asm diff --git a/External/FEXCore/Source/Interface/Core/OpcodeDispatcher/X87F64.cpp b/External/FEXCore/Source/Interface/Core/OpcodeDispatcher/X87F64.cpp index 243603628..8fb257a48 100644 --- a/External/FEXCore/Source/Interface/Core/OpcodeDispatcher/X87F64.cpp +++ b/External/FEXCore/Source/Interface/Core/OpcodeDispatcher/X87F64.cpp @@ -510,7 +510,7 @@ void OpDispatchBuilder::FSUBF64<32, true, true, OpDispatchBuilder::OpResult::RES void OpDispatchBuilder::FCHSF64(OpcodeArgs) { auto top = GetX87Top(); auto a = _LoadContextIndexed(top, 8, MMBaseOffset(), 16, FPRClass); - auto b = _Constant(0b1'000'0000'0000'0000ULL); + auto b = _VCastFromGPR(8, 8, _Constant(0x8000000000000000)); auto result = _VXor(8, 8, a, b); // Write to ST[TOP] @@ -520,7 +520,7 @@ void OpDispatchBuilder::FCHSF64(OpcodeArgs) { void OpDispatchBuilder::FABSF64(OpcodeArgs) { auto top = GetX87Top(); auto a = _LoadContextIndexed(top, 8, MMBaseOffset(), 16, FPRClass); - auto b = _Constant(0b0'111'1111'1111'1111ULL); + auto b = _VCastFromGPR(8, 8, _Constant(0x7fffffffffffffff)); auto result = _VAnd(8, 8, a, b); // Write to ST[TOP] diff --git a/unittests/ASM/X87_F64/D9_E0_F64.asm b/unittests/ASM/X87_F64/D9_E0_F64.asm new file mode 100644 index 000000000..ef2286c71 --- /dev/null +++ b/unittests/ASM/X87_F64/D9_E0_F64.asm @@ -0,0 +1,35 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": ["0x3ff0000000000000"], + "RBX": ["0xc000000000000000"] + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rcx, 0xe0000000 + +lea rdx, [rel data] +fld tword [rdx + 8 * 0] +fchs + +lea rdx, [rel data2] +fld tword [rdx + 8 * 0] +fchs + +fstp qword [rcx] +mov rax, [rcx] + +fst qword [rcx] +mov rbx, [rcx] + +hlt + +align 8 +data: + dt 2.0 + dq 0 +data2: + dt -1.0 + dq 0 diff --git a/unittests/ASM/X87_F64/D9_E1_F64.asm b/unittests/ASM/X87_F64/D9_E1_F64.asm new file mode 100644 index 000000000..2f8b0906b --- /dev/null +++ b/unittests/ASM/X87_F64/D9_E1_F64.asm @@ -0,0 +1,35 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": ["0x3ff0000000000000"], + "RBX": ["0x4000000000000000"] + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rcx, 0xe0000000 + +lea rdx, [rel data] +fld tword [rdx + 8 * 0] +fabs + +lea rdx, [rel data2] +fld tword [rdx + 8 * 0] +fabs + +fstp qword [rcx] +mov rax, [rcx] + +fst qword [rcx] +mov rbx, [rcx] + +hlt + +align 8 +data: + dt 2.0 + dq 0 +data2: + dt -1.0 + dq 0 From 0f8f2bf2b45a286a9a3568c257b32f1e4f580c52 Mon Sep 17 00:00:00 2001 From: CallumDev Date: Mon, 21 Feb 2022 12:59:48 +1030 Subject: [PATCH 09/15] X87F64 fix integer load, add tests --- .../Core/OpcodeDispatcher/X87F64.cpp | 37 +++++----- unittests/ASM/X87_F64/D9_E8_F64.asm | 17 +++++ unittests/ASM/X87_F64/D9_E9_F64.asm | 17 +++++ unittests/ASM/X87_F64/D9_EA_F64.asm | 17 +++++ unittests/ASM/X87_F64/D9_EB_F64.asm | 17 +++++ unittests/ASM/X87_F64/D9_EC_F64.asm | 17 +++++ unittests/ASM/X87_F64/D9_ED_F64.asm | 17 +++++ unittests/ASM/X87_F64/D9_EE_F64.asm | 17 +++++ unittests/ASM/X87_F64/D9_F8_F64.asm | 29 -------- unittests/ASM/X87_F64/DB_01_F64.asm | 29 ++++++++ unittests/ASM/X87_F64/DB_02_F64.asm | 35 +++++++++ unittests/ASM/X87_F64/DB_03_F64.asm | 31 ++++++++ unittests/ASM/X87_F64/DE_00_F64.asm | 23 ++++++ unittests/ASM/X87_F64/DE_01_F64.asm | 23 ++++++ unittests/ASM/X87_F64/DE_04_F64.asm | 23 ++++++ unittests/ASM/X87_F64/DE_05_F64.asm | 23 ++++++ unittests/ASM/X87_F64/DE_06_F64.asm | 23 ++++++ unittests/ASM/X87_F64/DE_07_F64.asm | 23 ++++++ unittests/ASM/X87_F64/DE_C0_F64.asm | 41 +++++++++++ unittests/ASM/X87_F64/DE_C8_F64.asm | 40 +++++++++++ unittests/ASM/X87_F64/DE_E0_F64.asm | 40 +++++++++++ unittests/ASM/X87_F64/DE_E8_F64.asm | 41 +++++++++++ unittests/ASM/X87_F64/DE_F0_F64.asm | 40 +++++++++++ unittests/ASM/X87_F64/DE_F8_F64.asm | 43 +++++++++++ unittests/ASM/X87_F64/DF_02_F64.asm | 26 +++++++ unittests/ASM/X87_F64/FCOM_F64.asm | 2 +- unittests/ASM/X87_F64/FXAM_Push_2_F64.asm | 43 +++++++++++ unittests/ASM/X87_F64/FXAM_Push_F64.asm | 71 +++++++++++++++++++ 28 files changed, 756 insertions(+), 49 deletions(-) create mode 100644 unittests/ASM/X87_F64/D9_E8_F64.asm create mode 100644 unittests/ASM/X87_F64/D9_E9_F64.asm create mode 100644 unittests/ASM/X87_F64/D9_EA_F64.asm create mode 100644 unittests/ASM/X87_F64/D9_EB_F64.asm create mode 100644 unittests/ASM/X87_F64/D9_EC_F64.asm create mode 100644 unittests/ASM/X87_F64/D9_ED_F64.asm create mode 100644 unittests/ASM/X87_F64/D9_EE_F64.asm delete mode 100644 unittests/ASM/X87_F64/D9_F8_F64.asm create mode 100644 unittests/ASM/X87_F64/DB_01_F64.asm create mode 100644 unittests/ASM/X87_F64/DB_02_F64.asm create mode 100644 unittests/ASM/X87_F64/DB_03_F64.asm create mode 100644 unittests/ASM/X87_F64/DE_00_F64.asm create mode 100644 unittests/ASM/X87_F64/DE_01_F64.asm create mode 100644 unittests/ASM/X87_F64/DE_04_F64.asm create mode 100644 unittests/ASM/X87_F64/DE_05_F64.asm create mode 100644 unittests/ASM/X87_F64/DE_06_F64.asm create mode 100644 unittests/ASM/X87_F64/DE_07_F64.asm create mode 100644 unittests/ASM/X87_F64/DE_C0_F64.asm create mode 100644 unittests/ASM/X87_F64/DE_C8_F64.asm create mode 100644 unittests/ASM/X87_F64/DE_E0_F64.asm create mode 100644 unittests/ASM/X87_F64/DE_E8_F64.asm create mode 100644 unittests/ASM/X87_F64/DE_F0_F64.asm create mode 100644 unittests/ASM/X87_F64/DE_F8_F64.asm create mode 100644 unittests/ASM/X87_F64/DF_02_F64.asm create mode 100644 unittests/ASM/X87_F64/FXAM_Push_2_F64.asm create mode 100644 unittests/ASM/X87_F64/FXAM_Push_F64.asm diff --git a/External/FEXCore/Source/Interface/Core/OpcodeDispatcher/X87F64.cpp b/External/FEXCore/Source/Interface/Core/OpcodeDispatcher/X87F64.cpp index 8fb257a48..52375ea07 100644 --- a/External/FEXCore/Source/Interface/Core/OpcodeDispatcher/X87F64.cpp +++ b/External/FEXCore/Source/Interface/Core/OpcodeDispatcher/X87F64.cpp @@ -155,7 +155,7 @@ void OpDispatchBuilder::FILDF64(OpcodeArgs) { size_t read_width = GetSrcSize(Op); // Read from memory auto data = LoadSource_WithOpSize(GPRClass, Op, Op->Src[0], read_width, Op->Flags, -1); - auto converted = _Float_FromGPR_S(8, read_width, data); + auto converted = _Float_FromGPR_S(8, 8, data); // Write to ST[TOP] _StoreContextIndexed(converted, top, 8, MMBaseOffset(), 16, FPRClass); } @@ -200,9 +200,9 @@ void OpDispatchBuilder::FISTF64(OpcodeArgs) { auto orig_top = GetX87Top(); OrderedNode *data = _LoadContextIndexed(orig_top, 8, MMBaseOffset(), 16, FPRClass); if constexpr (Truncate) { - data = _Float_ToGPR_ZS(Size, 8, data); + data = _Float_ToGPR_ZS(8, 8, data); } else { - data = _Float_ToGPR_S(Size, 8, data); + data = _Float_ToGPR_S(8, 8, data); } StoreResult_WithOpSize(GPRClass, Op, Op->Dest, data, Size, 1); @@ -234,7 +234,7 @@ void OpDispatchBuilder::FADDF64(OpcodeArgs) { // Memory arg if constexpr (Integer) { arg = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags, -1); - b = _Float_FromGPR_S(8, width / 8, arg); + b = _Float_FromGPR_S(8, 8, arg); } else if constexpr (width == 32) { arg = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags, -1); b = _Float_FToF(8, 4, arg); @@ -292,7 +292,7 @@ void OpDispatchBuilder::FMULF64(OpcodeArgs) { // Memory arg if constexpr (Integer) { arg = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags, -1); - b = _Float_FromGPR_S(8, width / 8, arg); + b = _Float_FromGPR_S(8, 8, arg); } else if constexpr (width == 32) { arg = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags, -1); b = _Float_FToF(8, 4, arg); @@ -353,7 +353,7 @@ void OpDispatchBuilder::FDIVF64(OpcodeArgs) { // Memory arg if constexpr (Integer) { arg = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags, -1); - b = _Float_FromGPR_S(8, width / 8, arg); + b = _Float_FromGPR_S(8, 8, arg); } else if constexpr (width == 32) { arg = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags, -1); b = _Float_FToF(8, 4, arg); @@ -436,7 +436,7 @@ void OpDispatchBuilder::FSUBF64(OpcodeArgs) { // Memory arg if constexpr (Integer) { arg = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags, -1); - b = _Float_FromGPR_S(8, width / 8, arg); + b = _Float_FromGPR_S(8, 8, arg); } else if constexpr (width == 32) { arg = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags, -1); b = _Float_FToF(8, 4, arg); @@ -529,12 +529,12 @@ void OpDispatchBuilder::FABSF64(OpcodeArgs) { void OpDispatchBuilder::FTSTF64(OpcodeArgs) { auto top = GetX87Top(); - auto a = _LoadContextIndexed(top, 16, MMBaseOffset(), 16, FPRClass); + auto a = _LoadContextIndexed(top, 8, MMBaseOffset(), 16, FPRClass); auto low = _Constant(0); - OrderedNode *data = _VCastFromGPR(16, 8, low); + OrderedNode *data = _VCastFromGPR(8, 8, low); - OrderedNode *Res = _F80Cmp(a, data, + OrderedNode *Res = _FCmp(8, a, data, (1 << FCMP_FLAG_EQ) | (1 << FCMP_FLAG_LT) | (1 << FCMP_FLAG_UNORDERED)); @@ -596,7 +596,7 @@ void OpDispatchBuilder::FCOMIF64(OpcodeArgs) { // Memory arg if constexpr (Integer) { arg = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags, -1); - b = _Float_FromGPR_S(8, width / 8, arg); + b = _Float_FromGPR_S(8, 8, arg); } else if constexpr (width == 32) { arg = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags, -1); b = _Float_FToF(8, 4, arg); @@ -612,15 +612,14 @@ void OpDispatchBuilder::FCOMIF64(OpcodeArgs) { auto a = _LoadContextIndexed(top, 8, MMBaseOffset(), 16, FPRClass); - auto one = _Constant(1); + OrderedNode *Res = _FCmp(8, a, b, + (1 << FCMP_FLAG_EQ) | + (1 << FCMP_FLAG_LT) | + (1 << FCMP_FLAG_UNORDERED)); - auto cmp_eq = _VFCMPEQ(8, 8, a, b); - auto cmp_lt = _VFCMPLT(8, 8, a, b); - auto cmp_un = _VFCMPUNO(8, 8, a, b); - - OrderedNode* HostFlag_ZF = _And(_VExtractToGPR(8, 8, cmp_eq, 0), one); - OrderedNode* HostFlag_CF = _And(_VExtractToGPR(8, 8, cmp_lt, 0), one); - OrderedNode* HostFlag_Unordered = _And(_VExtractToGPR(8, 8, cmp_un, 0), one); + OrderedNode *HostFlag_CF = _GetHostFlag(Res, FCMP_FLAG_LT); + OrderedNode *HostFlag_ZF = _GetHostFlag(Res, FCMP_FLAG_EQ); + OrderedNode *HostFlag_Unordered = _GetHostFlag(Res, FCMP_FLAG_UNORDERED); HostFlag_CF = _Or(HostFlag_CF, HostFlag_Unordered); HostFlag_ZF = _Or(HostFlag_ZF, HostFlag_Unordered); diff --git a/unittests/ASM/X87_F64/D9_E8_F64.asm b/unittests/ASM/X87_F64/D9_E8_F64.asm new file mode 100644 index 000000000..a27149a4e --- /dev/null +++ b/unittests/ASM/X87_F64/D9_E8_F64.asm @@ -0,0 +1,17 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": ["0x3ff0000000000000"] + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rcx, 0xe0000000 + +fld1 + +fst qword [rcx] +mov rax, [rcx] + +hlt diff --git a/unittests/ASM/X87_F64/D9_E9_F64.asm b/unittests/ASM/X87_F64/D9_E9_F64.asm new file mode 100644 index 000000000..11a1ff3d4 --- /dev/null +++ b/unittests/ASM/X87_F64/D9_E9_F64.asm @@ -0,0 +1,17 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": ["0x40549a78"] + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rcx, 0xe0000000 + +fldl2t + +fst dword [rcx] ; Can't compare 64-bit precision with host +mov eax, [rcx] + +hlt diff --git a/unittests/ASM/X87_F64/D9_EA_F64.asm b/unittests/ASM/X87_F64/D9_EA_F64.asm new file mode 100644 index 000000000..52c4c28f6 --- /dev/null +++ b/unittests/ASM/X87_F64/D9_EA_F64.asm @@ -0,0 +1,17 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": ["0x3fb8aa3b"] + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rcx, 0xe0000000 + +fldl2e + +fst dword [rcx] ; Can't compare 64-bit precision with host +mov eax, [rcx] + +hlt diff --git a/unittests/ASM/X87_F64/D9_EB_F64.asm b/unittests/ASM/X87_F64/D9_EB_F64.asm new file mode 100644 index 000000000..a667fa4d2 --- /dev/null +++ b/unittests/ASM/X87_F64/D9_EB_F64.asm @@ -0,0 +1,17 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": ["0x40490fdb"] + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rcx, 0xe0000000 + +fldpi + +fst dword [rcx] ; Can't compare 64-bit precision with host +mov eax, [rcx] + +hlt diff --git a/unittests/ASM/X87_F64/D9_EC_F64.asm b/unittests/ASM/X87_F64/D9_EC_F64.asm new file mode 100644 index 000000000..69aca1a97 --- /dev/null +++ b/unittests/ASM/X87_F64/D9_EC_F64.asm @@ -0,0 +1,17 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": ["0x3e9a209b"] + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rcx, 0xe0000000 + +fldlg2 + +fst dword [rcx] ; Can't compare 64-bit precision with host +mov eax, [rcx] + +hlt diff --git a/unittests/ASM/X87_F64/D9_ED_F64.asm b/unittests/ASM/X87_F64/D9_ED_F64.asm new file mode 100644 index 000000000..13e3dba2c --- /dev/null +++ b/unittests/ASM/X87_F64/D9_ED_F64.asm @@ -0,0 +1,17 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": ["0x3f317218"] + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rcx, 0xe0000000 + +fldln2 + +fst dword [rcx] ; Can't compare 64-bit precision with host +mov eax, [rcx] + +hlt diff --git a/unittests/ASM/X87_F64/D9_EE_F64.asm b/unittests/ASM/X87_F64/D9_EE_F64.asm new file mode 100644 index 000000000..bb53a353a --- /dev/null +++ b/unittests/ASM/X87_F64/D9_EE_F64.asm @@ -0,0 +1,17 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": ["0"] + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rcx, 0xe0000000 + +fldz + +fst qword [rcx] +mov rax, [rcx] + +hlt diff --git a/unittests/ASM/X87_F64/D9_F8_F64.asm b/unittests/ASM/X87_F64/D9_F8_F64.asm deleted file mode 100644 index df1cd0ca4..000000000 --- a/unittests/ASM/X87_F64/D9_F8_F64.asm +++ /dev/null @@ -1,29 +0,0 @@ -%ifdef CONFIG -{ - "RegData": { - "MM6": ["0x8666666666666666", "0x4000"], - "MM7": ["0xC000000000000000", "0x4000"] - }, - "MemoryRegions": { - "0x100000000": "4096" - } -} -%endif - -lea rdx, [rel data] -fld tword [rdx + 8 * 0] - -lea rdx, [rel data2] -fld tword [rdx + 8 * 0] - -fprem - -hlt - -align 8 -data: - dt 3.0 - dq 0 -data2: - dt 5.1 - dq 0 diff --git a/unittests/ASM/X87_F64/DB_01_F64.asm b/unittests/ASM/X87_F64/DB_01_F64.asm new file mode 100644 index 000000000..2d5bccddf --- /dev/null +++ b/unittests/ASM/X87_F64/DB_01_F64.asm @@ -0,0 +1,29 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0x400", + "RBX": "0x3ff0000000000000" + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rdx, 0xe0000000 + +mov eax, 0x44800000 ; 1024.0 +mov [rdx + 8 * 0], eax +mov eax, 0 +mov [rdx + 8 * 1], eax + +fld dword [rdx + 8 * 0] + +fisttp dword [rdx + 8 * 1] + +fld1 + +mov eax, [rdx + 8 * 1] + +fst qword [rdx] +mov rbx, [rdx] + +hlt diff --git a/unittests/ASM/X87_F64/DB_02_F64.asm b/unittests/ASM/X87_F64/DB_02_F64.asm new file mode 100644 index 000000000..0b60973c9 --- /dev/null +++ b/unittests/ASM/X87_F64/DB_02_F64.asm @@ -0,0 +1,35 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0x400", + "RBX": "0x3ff0000000000000", + "RCX": "0x4090000000000000" + }, + "MemoryRegions": { + "0x100000000": "4096" + } +} +%endif + +mov rdx, 0xe0000000 + +mov eax, 0x44800000 ; 1024.0 +mov [rdx + 8 * 0], eax +mov eax, 0 +mov [rdx + 8 * 1], eax + +fld dword [rdx + 8 * 0] + +fist dword [rdx + 8 * 1] + +fld1 + +mov eax, [rdx + 8 * 1] + +fstp qword [rdx] +mov rbx, [rdx] + +fst qword [rdx] +mov rcx, [rdx] + +hlt diff --git a/unittests/ASM/X87_F64/DB_03_F64.asm b/unittests/ASM/X87_F64/DB_03_F64.asm new file mode 100644 index 000000000..8b1107454 --- /dev/null +++ b/unittests/ASM/X87_F64/DB_03_F64.asm @@ -0,0 +1,31 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0x400", + "RBX": ["0x3ff0000000000000"] + }, + "MemoryRegions": { + "0x100000000": "4096" + } +} +%endif + +mov rdx, 0xe0000000 + +mov eax, 0x44800000 ; 1024.0 +mov [rdx + 8 * 0], eax +mov eax, 0 +mov [rdx + 8 * 1], eax + +fld dword [rdx + 8 * 0] + +fistp dword [rdx + 8 * 1] + +fld1 + +mov eax, [rdx + 8 * 1] + +fst qword [rdx] +mov rbx, [rdx] + +hlt diff --git a/unittests/ASM/X87_F64/DE_00_F64.asm b/unittests/ASM/X87_F64/DE_00_F64.asm new file mode 100644 index 000000000..e30df7b66 --- /dev/null +++ b/unittests/ASM/X87_F64/DE_00_F64.asm @@ -0,0 +1,23 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": ["0x4008000000000000"] + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rdx, 0xe0000000 + +mov rax, 0x3ff0000000000000 ; 1.0 +mov [rdx + 8 * 0], rax +mov ax, 2 +mov [rdx + 8 * 1], ax + +fld qword [rdx + 8 * 0] +fiadd word [rdx + 8 * 1] + +fst qword [rdx] +mov rax, [rdx] + +hlt diff --git a/unittests/ASM/X87_F64/DE_01_F64.asm b/unittests/ASM/X87_F64/DE_01_F64.asm new file mode 100644 index 000000000..2ea669338 --- /dev/null +++ b/unittests/ASM/X87_F64/DE_01_F64.asm @@ -0,0 +1,23 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": ["0x4000000000000000"] + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rdx, 0xe0000000 + +mov rax, 0x3ff0000000000000 ; 1.0 +mov [rdx + 8 * 0], rax +mov ax, 2 +mov [rdx + 8 * 1], ax + +fld qword [rdx + 8 * 0] +fimul word [rdx + 8 * 1] + +fst qword [rdx] +mov rax, [rdx] + +hlt diff --git a/unittests/ASM/X87_F64/DE_04_F64.asm b/unittests/ASM/X87_F64/DE_04_F64.asm new file mode 100644 index 000000000..497338ead --- /dev/null +++ b/unittests/ASM/X87_F64/DE_04_F64.asm @@ -0,0 +1,23 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": ["0xbff0000000000000"] + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rdx, 0xe0000000 + +mov rax, 0x3ff0000000000000 ; 1.0 +mov [rdx + 8 * 0], rax +mov ax, 2 +mov [rdx + 8 * 1], ax + +fld qword [rdx + 8 * 0] +fisub word [rdx + 8 * 1] + +fst qword [rdx] +mov rax, [rdx] + +hlt diff --git a/unittests/ASM/X87_F64/DE_05_F64.asm b/unittests/ASM/X87_F64/DE_05_F64.asm new file mode 100644 index 000000000..8ac3e0c26 --- /dev/null +++ b/unittests/ASM/X87_F64/DE_05_F64.asm @@ -0,0 +1,23 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": ["0x3ff0000000000000"] + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rdx, 0xe0000000 + +mov rax, 0x3ff0000000000000 ; 1.0 +mov [rdx + 8 * 0], rax +mov ax, 2 +mov [rdx + 8 * 1], ax + +fld qword [rdx + 8 * 0] +fisubr word [rdx + 8 * 1] + +fst qword [rdx] +mov rax, [rdx] + +hlt diff --git a/unittests/ASM/X87_F64/DE_06_F64.asm b/unittests/ASM/X87_F64/DE_06_F64.asm new file mode 100644 index 000000000..df27bc61b --- /dev/null +++ b/unittests/ASM/X87_F64/DE_06_F64.asm @@ -0,0 +1,23 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": ["0x3fe0000000000000"] + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rdx, 0xe0000000 + +mov rax, 0x3ff0000000000000 ; 1.0 +mov [rdx + 8 * 0], rax +mov ax, 2 +mov [rdx + 8 * 1], ax + +fld qword [rdx + 8 * 0] +fidiv word [rdx + 8 * 1] + +fst qword [rdx] +mov rax, [rdx] + +hlt diff --git a/unittests/ASM/X87_F64/DE_07_F64.asm b/unittests/ASM/X87_F64/DE_07_F64.asm new file mode 100644 index 000000000..1d9544068 --- /dev/null +++ b/unittests/ASM/X87_F64/DE_07_F64.asm @@ -0,0 +1,23 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": ["0x4000000000000000"] + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rdx, 0xe0000000 + +mov rax, 0x3ff0000000000000 ; 1.0 +mov [rdx + 8 * 0], rax +mov ax, 2 +mov [rdx + 8 * 1], ax + +fld qword [rdx + 8 * 0] +fidivr word [rdx + 8 * 1] + +fst qword [rdx] +mov rax, [rdx] + +hlt diff --git a/unittests/ASM/X87_F64/DE_C0_F64.asm b/unittests/ASM/X87_F64/DE_C0_F64.asm new file mode 100644 index 000000000..01b747566 --- /dev/null +++ b/unittests/ASM/X87_F64/DE_C0_F64.asm @@ -0,0 +1,41 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": ["0x4010000000000000"], + "RBX": ["0x4008000000000000"] + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rcx, 0xe0000000 + +lea rdx, [rel data] +fld tword [rdx + 8 * 0] + +lea rdx, [rel data2] +fld tword [rdx + 8 * 0] +faddp st1, st0 + +lea rdx, [rel data3] +fld tword [rdx + 8 * 0] + +fstp qword [rcx] +mov rax, [rcx] + +fst qword [rcx] +mov rbx, [rcx] + +hlt + +align 8 +data: + dt 2.0 + dq 0 +data2: + dt 1.0 + dq 0 +data3: + dt 4.0 + dq 0 + diff --git a/unittests/ASM/X87_F64/DE_C8_F64.asm b/unittests/ASM/X87_F64/DE_C8_F64.asm new file mode 100644 index 000000000..976917419 --- /dev/null +++ b/unittests/ASM/X87_F64/DE_C8_F64.asm @@ -0,0 +1,40 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": ["0x4010000000000000"], + "RBX": ["0x4020000000000000"] + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rcx, 0xe0000000 + +lea rdx, [rel data] +fld tword [rdx + 8 * 0] + +lea rdx, [rel data2] +fld tword [rdx + 8 * 0] +fmulp st1, st0 + +lea rdx, [rel data3] +fld tword [rdx + 8 * 0] + +fstp qword [rcx] +mov rax, [rcx] + +fst qword [rcx] +mov rbx, [rcx] + +hlt + +align 8 +data: + dt 2.0 + dq 0 +data2: + dt 4.0 + dq 0 +data3: + dt 4.0 + dq 0 diff --git a/unittests/ASM/X87_F64/DE_E0_F64.asm b/unittests/ASM/X87_F64/DE_E0_F64.asm new file mode 100644 index 000000000..3885fd882 --- /dev/null +++ b/unittests/ASM/X87_F64/DE_E0_F64.asm @@ -0,0 +1,40 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": ["0x4010000000000000"], + "RBX": ["0x4000000000000000"] + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rcx, 0xe0000000 + +lea rdx, [rel data] +fld tword [rdx + 8 * 0] + +lea rdx, [rel data2] +fld tword [rdx + 8 * 0] +fsubrp st1, st0 + +lea rdx, [rel data3] +fld tword [rdx + 8 * 0] + +fstp qword [rcx] +mov rax, [rcx] + +fst qword [rcx] +mov rbx, [rcx] + +hlt + +align 8 +data: + dt 2.0 + dq 0 +data2: + dt 4.0 + dq 0 +data3: + dt 4.0 + dq 0 diff --git a/unittests/ASM/X87_F64/DE_E8_F64.asm b/unittests/ASM/X87_F64/DE_E8_F64.asm new file mode 100644 index 000000000..24791689a --- /dev/null +++ b/unittests/ASM/X87_F64/DE_E8_F64.asm @@ -0,0 +1,41 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": ["0x4010000000000000"], + "RBX": ["0xc000000000000000"] + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rcx, 0xe0000000 + + +lea rdx, [rel data] +fld tword [rdx + 8 * 0] + +lea rdx, [rel data2] +fld tword [rdx + 8 * 0] +fsubp st1, st0 + +lea rdx, [rel data3] +fld tword [rdx + 8 * 0] + +fstp qword [rcx] +mov rax, [rcx] + +fst qword [rcx] +mov rbx, [rcx] + +hlt + +align 8 +data: + dt 2.0 + dq 0 +data2: + dt 4.0 + dq 0 +data3: + dt 4.0 + dq 0 diff --git a/unittests/ASM/X87_F64/DE_F0_F64.asm b/unittests/ASM/X87_F64/DE_F0_F64.asm new file mode 100644 index 000000000..c7c62e394 --- /dev/null +++ b/unittests/ASM/X87_F64/DE_F0_F64.asm @@ -0,0 +1,40 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": ["0x4010000000000000"], + "RBX": ["0x4000000000000000"] + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rcx, 0xe0000000 + +lea rdx, [rel data] +fld tword [rdx + 8 * 0] + +lea rdx, [rel data2] +fld tword [rdx + 8 * 0] +fdivrp st1, st0 + +lea rdx, [rel data3] +fld tword [rdx + 8 * 0] + +fstp qword [rcx] +mov rax, [rcx] + +fst qword [rcx] +mov rbx, [rcx] + +hlt + +align 8 +data: + dt 2.0 + dq 0 +data2: + dt 4.0 + dq 0 +data3: + dt 4.0 + dq 0 diff --git a/unittests/ASM/X87_F64/DE_F8_F64.asm b/unittests/ASM/X87_F64/DE_F8_F64.asm new file mode 100644 index 000000000..eac062a3f --- /dev/null +++ b/unittests/ASM/X87_F64/DE_F8_F64.asm @@ -0,0 +1,43 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": ["0x4010000000000000"], + "RBX": ["0x3fe0000000000000"] + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rcx, 0xe0000000 + +lea rdx, [rel data] +fld tword [rdx + 8 * 0] + +lea rdx, [rel data2] +fld tword [rdx + 8 * 0] + +; fdivp 2.0, 4.0 +; == st1 = 2.0 / 4.0 +fdivp st1, st0 + +lea rdx, [rel data3] +fld tword [rdx + 8 * 0] + +fstp qword [rcx] +mov rax, [rcx] + +fst qword [rcx] +mov rbx, [rcx] + +hlt + +align 8 +data: + dt 2.0 + dq 0 +data2: + dt 4.0 + dq 0 +data3: + dt 4.0 + dq 0 diff --git a/unittests/ASM/X87_F64/DF_02_F64.asm b/unittests/ASM/X87_F64/DF_02_F64.asm new file mode 100644 index 000000000..a1cdcf33c --- /dev/null +++ b/unittests/ASM/X87_F64/DF_02_F64.asm @@ -0,0 +1,26 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0x400" + }, + "X87ReducedPrecision" : "1" +} +%endif + +mov rdx, 0xe0000000 + +mov eax, 0x44800000 ; 1024.0 +mov [rdx + 8 * 0], eax +mov eax, -1 +mov [rdx + 8 * 1], eax + +fld dword [rdx + 8 * 0] + +fist word [rdx + 8 * 1] + +fld1 + +mov eax, 0 +mov ax, word [rdx + 8 * 1] + +hlt diff --git a/unittests/ASM/X87_F64/FCOM_F64.asm b/unittests/ASM/X87_F64/FCOM_F64.asm index 7c7cec5d7..e0c230a7b 100644 --- a/unittests/ASM/X87_F64/FCOM_F64.asm +++ b/unittests/ASM/X87_F64/FCOM_F64.asm @@ -11,7 +11,7 @@ fld1 fldz fcomp fnstsw ax -test ah, 041h; I *think* I've got the right flags there... +test ah, 041h jp good mov rax, 0 hlt diff --git a/unittests/ASM/X87_F64/FXAM_Push_2_F64.asm b/unittests/ASM/X87_F64/FXAM_Push_2_F64.asm new file mode 100644 index 000000000..48334657e --- /dev/null +++ b/unittests/ASM/X87_F64/FXAM_Push_2_F64.asm @@ -0,0 +1,43 @@ +%ifdef CONFIG +{ + "RegData": { + "RCX": "0" + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rdx, 0xe0000000 + +; This behaviour was seen around Wine 32-bit libraries +; Anything doing a call to a double application would spin +; the x87 stack on to the stack looking for fxam to return empty +; Empty in this case is that C0 and C3 is set whiel C2 is not + +fninit +; Empty stack to make sure we don't push anything + +mov eax, 0 +mov ecx, 0 + +.ExamineStack: +; Examine st(0) +fxam +fwait +; Get the results in to AX +fnstsw ax +and ax, 0x4500 +; Check for empty +cmp ax, 0x4100 +je .Done + +; Now push the x87 stack value +; We know it isn't empty +fstp qword [rdx + rcx * 8] +fwait +inc ecx +jmp .ExamineStack + +.Done: + +hlt diff --git a/unittests/ASM/X87_F64/FXAM_Push_F64.asm b/unittests/ASM/X87_F64/FXAM_Push_F64.asm new file mode 100644 index 000000000..0fdd60ab6 --- /dev/null +++ b/unittests/ASM/X87_F64/FXAM_Push_F64.asm @@ -0,0 +1,71 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "8" + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rdx, 0xe0000000 + +; This behaviour was seen around Wine 32-bit libraries +; Anything doing a call to a double application would spin +; the x87 stack on to the stack looking for fxam to return empty +; Empty in this case is that C0 and C3 is set whiel C2 is not + +fninit +; Fill the x87 stack +fldz +fldz +fldz +fldz +fldz +fldz +fldz +fldz + +mov eax, 0 +mov ecx, 0 + +.ExamineStack: +; Examine st(0) +fxam +fwait +; Get the results in to AX +fnstsw ax +and ax, 0x4500 +; Check for empty +cmp ax, 0x4100 +je .Done + +; Now push the x87 stack value +; We know it isn't empty +fstp qword [rdx + rcx * 8] +fwait +inc ecx +jmp .ExamineStack + +.Done: + +; Save how many we stored +mov eax, ecx + +; Now fill with "Garbage" +fld1 +fld1 +fld1 +fld1 +fld1 +fld1 +fld1 +fld1 + +.Reload: +; Now reload the stack +dec ecx +fld qword [rdx + rcx * 8] +cmp ecx, 0x0 +jne .Reload; + +hlt From 9640216124e6103ebc48a3865a593015cce38b30 Mon Sep 17 00:00:00 2001 From: CallumDev Date: Mon, 21 Feb 2022 20:37:35 +1030 Subject: [PATCH 10/15] X87F64: Add working BCD test --- .../Core/OpcodeDispatcher/X87F64.cpp | 2 +- unittests/ASM/X87_F64/DF_04_F64.asm | 194 ++++++++++++++++++ 2 files changed, 195 insertions(+), 1 deletion(-) create mode 100644 unittests/ASM/X87_F64/DF_04_F64.asm diff --git a/External/FEXCore/Source/Interface/Core/OpcodeDispatcher/X87F64.cpp b/External/FEXCore/Source/Interface/Core/OpcodeDispatcher/X87F64.cpp index 52375ea07..d23494357 100644 --- a/External/FEXCore/Source/Interface/Core/OpcodeDispatcher/X87F64.cpp +++ b/External/FEXCore/Source/Interface/Core/OpcodeDispatcher/X87F64.cpp @@ -108,7 +108,7 @@ void OpDispatchBuilder::FBSTPF64(OpcodeArgs) { auto data = _LoadContextIndexed(orig_top, 8, MMBaseOffset(), 16, FPRClass); OrderedNode *converted = _F80CVTTo(data, 8); - converted = _F80BCDStore(data); + converted = _F80BCDStore(converted); StoreResult_WithOpSize(FPRClass, Op, Op->Dest, converted, 10, 1); diff --git a/unittests/ASM/X87_F64/DF_04_F64.asm b/unittests/ASM/X87_F64/DF_04_F64.asm new file mode 100644 index 000000000..31cf7dc43 --- /dev/null +++ b/unittests/ASM/X87_F64/DF_04_F64.asm @@ -0,0 +1,194 @@ +%ifdef CONFIG +{ + "RegData": { + "XMM0": ["0x0506070801000000", "0x0000000000000012"], + "XMM1": ["0x6576879821300000", "0x0000000000000000"], + "XMM2": ["0xB90984060D300000", "0x000000000000C03B"], + "XMM3": ["0xA83732340C000000", "0x000000000000C03B"], + "XMM4": ["0xFFAA6DA436100000", "0x000000000000C03A"], + "XMM5": ["0x0000000000000001", "0x0000000000000000"], + "XMM6": ["0x0000000000000001", "0x0000000000008000"], + "XMM7": ["0x0000000000000000", "0x0000000000008000"], + "XMM8": ["0x0000000000000000", "0x0000000000008000"], + "XMM9": ["0x0000000000000000", "0x0000000000000000"], + "XMM10": ["0x0000000000000001", "0x0000000000008000"], + "XMM11": ["0x0000000000000001", "0x0000000000000000"] + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +fbld [rel .data_0] +fbstp [rel .res_data_0] +movups xmm0, [rel .res_data_0] +andps xmm0, [rel .precisionMask] ; Mask imprecise bits + +fbld [rel .data_1] +fbstp [rel .res_data_1] +movups xmm1, [rel .res_data_1] +andps xmm1, [rel .precisionMask] ; Mask imprecise bits + +; Check encoding of invalid BCD +fbld [rel .data_2] +fstp tword [rel .res_data_2] +movups xmm2, [rel .res_data_2] +andps xmm2, [rel .precisionMask] ; Mask imprecise bits + +fbld [rel .data_3] +fstp tword [rel .res_data_3] +movups xmm3, [rel .res_data_3] +andps xmm3, [rel .precisionMask] ; Mask imprecise bits + +fbld [rel .data_4] +fstp tword [rel .res_data_4] +movups xmm4, [rel .res_data_4] +andps xmm4, [rel .precisionMask] ; Mask imprecise bits + +; Some special values +fld tword [rel .data_5] +fbstp [rel .res_data_5] +movups xmm5, [rel .res_data_5] + +fld tword [rel .data_6] +fbstp [rel .res_data_6] +movups xmm6, [rel .res_data_6] + +fld tword [rel .data_7] +fbstp [rel .res_data_7] +movups xmm7, [rel .res_data_7] + +; Values that choose +- 0 or +-1 depending on rounding mode +; -1 < F < -0 +; +0 < F < +1 +fld tword [rel .data_8] +fbstp [rel .res_data_8] +movups xmm8, [rel .res_data_8] + +fld tword [rel .data_9] +fbstp [rel .res_data_9] +movups xmm9, [rel .res_data_9] + +; Swap control word +fnstcw [rel .cw] +mov ax, [rel .cw] +and ax, ~(3 << 10) +or eax, 1 << 10 ; Round down +mov [rel .cw], ax +fldcw [rel .cw] + +fld tword [rel .data_10] +fbstp [rel .res_data_10] +movups xmm10, [rel .res_data_10] + +; Swap control word +fnstcw [rel .cw] +mov ax, [rel .cw] +and ax, ~(3 << 10) +or eax, 2 << 10 ; Round up +mov [rel .cw], ax +fldcw [rel .cw] + +fld tword [rel .data_11] +fbstp [rel .res_data_11] +movups xmm11, [rel .res_data_11] + +; Values that generate Invalicating floating point operation exception +; -inf +; +inf +; Negative value too large for destination format +; Positive value too large for destination format +; NaN +; On IA the indefinite BCD result is still stored to memory + +; XXX: We don't support IA on this + +hlt + +align 16 +.precisionMask: +dd 0xfff00000 +dd 0xffffffff +dd 0xffffffff +dd 0xffffffff + + +.cw: +dw 0 + +.data_0: +dd 0x01020304 +dd 0x05060708 +dd 0x09101112 +dd 0x13141516 +.data_1: +dd 0x21324354 +dd 0x65768798 +dd 0x00000000 +dd 0x00000000 +.data_2: +dd 0xFFFFFFFF +dd 0xFFFFFFFF +dd 0xFFFFFFFF +dd 0xFFFFFFFF +.data_3: +dd 0xF0F0F0F0 +dd 0xF0F0F0F0 +dd 0xF0F0F0F0 +dd 0xF0F0F0F0 +.data_4: +dd 0x0A0B0C0D +dd 0x0E0FAAAB +dd 0xACADAEAF +dd 0xBABBBCBD +.data_5: +dt 1.0 +.data_6: +dt -1.0 +.data_7: +dt -0.0 +.data_8: +dt -0.5 +.data_9: +dt 0.5 +.data_10: +dt -0.5 +.data_11: +dt 0.5 + +.res_data_0: +dq 0 +dq 0 +.res_data_1: +dq 0 +dq 0 +.res_data_2: +dq 0 +dq 0 +.res_data_3: +dq 0 +dq 0 +.res_data_4: +dq 0 +dq 0 +.res_data_5: +dq 0 +dq 0 +.res_data_6: +dq 0 +dq 0 +.res_data_7: +dq 0 +dq 0 +.res_data_8: +dq 0 +dq 0 +.res_data_9: +dq 0 +dq 0 +.res_data_10: +dq 0 +dq 0 +.res_data_11: +dq 0 +dq 0 + From 1c4b0272e88dc53f773a6461434d932b1ed32677 Mon Sep 17 00:00:00 2001 From: CallumDev Date: Mon, 21 Feb 2022 21:05:11 +1030 Subject: [PATCH 11/15] X87F64: Implement FXTRACT using bit ops, add test --- .../Core/OpcodeDispatcher/X87F64.cpp | 17 ++++++----- unittests/ASM/X87_F64/D9_F4_F64.asm | 28 +++++++++++++++++++ 2 files changed, 36 insertions(+), 9 deletions(-) create mode 100644 unittests/ASM/X87_F64/D9_F4_F64.asm diff --git a/External/FEXCore/Source/Interface/Core/OpcodeDispatcher/X87F64.cpp b/External/FEXCore/Source/Interface/Core/OpcodeDispatcher/X87F64.cpp index d23494357..210339ce0 100644 --- a/External/FEXCore/Source/Interface/Core/OpcodeDispatcher/X87F64.cpp +++ b/External/FEXCore/Source/Interface/Core/OpcodeDispatcher/X87F64.cpp @@ -562,7 +562,6 @@ void OpDispatchBuilder::FRNDINTF64(OpcodeArgs) { _StoreContextIndexed(result, top, 8, MMBaseOffset(), 16, FPRClass); } -//TODO: Don't round trip through F80 void OpDispatchBuilder::FXTRACTF64(OpcodeArgs) { auto orig_top = GetX87Top(); auto top = _And(_Sub(orig_top, _Constant(1)), _Constant(7)); @@ -570,14 +569,14 @@ void OpDispatchBuilder::FXTRACTF64(OpcodeArgs) { SetX87Top(top); auto a = _LoadContextIndexed(orig_top, 8, MMBaseOffset(), 16, FPRClass); - - auto a_f80 = _F80CVTTo(a, 8); - - auto exp_f80 = _F80XTRACT_EXP(a_f80); - auto sig_f80 = _F80XTRACT_SIG(a_f80); - - auto exp = _F80CVT(8, exp_f80); - auto sig = _F80CVT(8, sig_f80); + auto gpr = _VExtractToGPR(8, 8, a, 0); + OrderedNode* exp = _And(gpr, _Constant(0x7ff0000000000000LL)); + exp = _Lshr(exp, _Constant(52)); + exp = _Sub(exp, _Constant(1023)); + exp = _Float_FromGPR_S(8, 8, exp); + OrderedNode* sig = _And(gpr, _Constant(0x800fffffffffffffLL)); + sig = _Or(sig, _Constant(0x3ff0000000000000LL)); + sig = _VCastFromGPR(8, 8, sig); // Write to ST[TOP] _StoreContextIndexed(exp, orig_top, 8, MMBaseOffset(), 16, FPRClass); _StoreContextIndexed(sig, top, 8, MMBaseOffset(), 16, FPRClass); diff --git a/unittests/ASM/X87_F64/D9_F4_F64.asm b/unittests/ASM/X87_F64/D9_F4_F64.asm new file mode 100644 index 000000000..eb7a11810 --- /dev/null +++ b/unittests/ASM/X87_F64/D9_F4_F64.asm @@ -0,0 +1,28 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": ["0xbffe000000000000"], + "RBX": ["0x4008000000000000"] + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rcx, 0xe0000000 + +lea rdx, [rel data] +fld tword [rdx + 8 * 0] + +fxtract + +fstp qword [rcx] +mov rax, [rcx] +fst qword [rcx] +mov rbx, [rcx] + +hlt + +align 8 +data: + dt -15.0 + dq 0 From 0021723b50ca80bf864791af40f8b6609469bae3 Mon Sep 17 00:00:00 2001 From: CallumDev Date: Wed, 16 Mar 2022 18:37:33 +1030 Subject: [PATCH 12/15] Fix F64 FSCALE --- External/FEXCore/Source/Interface/Core/Interpreter/F80Ops.cpp | 2 +- External/FEXCore/Source/Interface/Core/Interpreter/F80Ops.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/External/FEXCore/Source/Interface/Core/Interpreter/F80Ops.cpp b/External/FEXCore/Source/Interface/Core/Interpreter/F80Ops.cpp index 26fedb250..24658617c 100644 --- a/External/FEXCore/Source/Interface/Core/Interpreter/F80Ops.cpp +++ b/External/FEXCore/Source/Interface/Core/Interpreter/F80Ops.cpp @@ -424,7 +424,7 @@ DEF_OP(F64SCALE) { auto Op = IROp->C(); double Src1 = *GetSrc(Data->SSAData, Op->Header.Args[0]); double Src2 = *GetSrc(Data->SSAData, Op->Header.Args[1]); - double trunc = round(Src2); + double trunc = (double)(int64_t)(Src2); //truncate double Tmp = Src1 * exp2(trunc); memcpy(GDP, &Tmp, sizeof(double)); diff --git a/External/FEXCore/Source/Interface/Core/Interpreter/F80Ops.h b/External/FEXCore/Source/Interface/Core/Interpreter/F80Ops.h index 99487fc04..3eae5066b 100644 --- a/External/FEXCore/Source/Interface/Core/Interpreter/F80Ops.h +++ b/External/FEXCore/Source/Interface/Core/Interpreter/F80Ops.h @@ -282,7 +282,7 @@ struct OpHandlers { template<> struct OpHandlers { static double handle(double src1, double src2) { - double trunc = round(src2); + double trunc = (double)(int64_t)(src2); //truncate return src1 * exp2(trunc); } }; From 3a269f04d2437708930c70a1646e5e2a60d54587 Mon Sep 17 00:00:00 2001 From: CallumDev Date: Tue, 22 Mar 2022 13:29:59 +1030 Subject: [PATCH 13/15] Add remaining possible X87F64 tests. Tweak FPREM --- .../Interface/Core/Interpreter/F80Ops.cpp | 2 +- .../Interface/Core/Interpreter/F80Ops.h | 2 +- unittests/ASM/X87_F64/D9_03_F64.asm | 28 ++++++++ unittests/ASM/X87_F64/D9_05_F64.asm | 11 ++++ unittests/ASM/X87_F64/D9_06_2_F64.asm | 53 +++++++++++++++ unittests/ASM/X87_F64/D9_06_F64.asm | 52 +++++++++++++++ unittests/ASM/X87_F64/D9_07_F64.asm | 15 +++++ unittests/ASM/X87_F64/D9_C0_F64.asm | 37 +++++++++++ unittests/ASM/X87_F64/D9_C8_F64.asm | 28 ++++++++ unittests/ASM/X87_F64/D9_D0_F64.asm | 9 +++ unittests/ASM/X87_F64/D9_F6_F64.asm | 44 +++++++++++++ unittests/ASM/X87_F64/D9_F7_F64.asm | 65 +++++++++++++++++++ unittests/ASM/X87_F64/D9_F8_F64.asm | 32 +++++++++ unittests/ASM/X87_F64/D9_F9_F64.asm | 35 ++++++++++ unittests/ASM/X87_F64/D9_FD_2_F64.asm | 34 ++++++++++ unittests/ASM/X87_F64/DA_C0_F64.asm | 36 ++++++++++ unittests/ASM/X87_F64/DA_C8_F64.asm | 36 ++++++++++ unittests/ASM/X87_F64/DA_D0_F64.asm | 36 ++++++++++ unittests/ASM/X87_F64/DA_D8_F64.asm | 36 ++++++++++ unittests/ASM/X87_F64/DA_E9_F64.asm | 24 +++++++ unittests/ASM/X87_F64/DB_00_F64.asm | 20 ++++++ unittests/ASM/X87_F64/DB_05_F64.asm | 23 +++++++ unittests/ASM/X87_F64/DB_07_F64.asm | 29 +++++++++ unittests/ASM/X87_F64/DB_C0_F64.asm | 36 ++++++++++ unittests/ASM/X87_F64/DB_C8_F64.asm | 37 +++++++++++ unittests/ASM/X87_F64/DB_D0_F64.asm | 36 ++++++++++ unittests/ASM/X87_F64/DB_D8_F64.asm | 36 ++++++++++ unittests/ASM/X87_F64/DC_00_F64.asm | 28 ++++++++ unittests/ASM/X87_F64/DC_01_F64.asm | 27 ++++++++ unittests/ASM/X87_F64/DC_04_F64.asm | 27 ++++++++ unittests/ASM/X87_F64/DC_05_F64.asm | 27 ++++++++ unittests/ASM/X87_F64/DC_06_F64.asm | 27 ++++++++ unittests/ASM/X87_F64/DC_C0_F64.asm | 36 ++++++++++ unittests/ASM/X87_F64/DC_C8_F64.asm | 34 ++++++++++ unittests/ASM/X87_F64/DC_E0_F64.asm | 32 +++++++++ unittests/ASM/X87_F64/DC_E8_F64.asm | 33 ++++++++++ unittests/ASM/X87_F64/DC_F0_F64.asm | 32 +++++++++ unittests/ASM/X87_F64/DC_F8_F64.asm | 32 +++++++++ unittests/ASM/X87_F64/DD_00_F64.asm | 20 ++++++ unittests/ASM/X87_F64/DD_01_F64.asm | 36 ++++++++++ unittests/ASM/X87_F64/DD_02_F64.asm | 39 +++++++++++ unittests/ASM/X87_F64/DD_03_F64.asm | 36 ++++++++++ unittests/ASM/X87_F64/DD_07_F64.asm | 25 +++++++ unittests/ASM/X87_F64/DD_C0_F64.asm | 16 +++++ unittests/ASM/X87_F64/DD_D0_F64.asm | 31 +++++++++ unittests/ASM/X87_F64/DD_D8_F64.asm | 38 +++++++++++ unittests/ASM/X87_F64/DD_E9_F64.asm | 24 +++++++ unittests/ASM/X87_F64/DF_00_F64.asm | 21 ++++++ unittests/ASM/X87_F64/DF_01_F64.asm | 36 ++++++++++ unittests/ASM/X87_F64/DF_03_F64.asm | 30 +++++++++ unittests/ASM/X87_F64/DF_05_F64.asm | 19 ++++++ unittests/ASM/X87_F64/DF_07_F64.asm | 30 +++++++++ unittests/ASM/X87_F64/DF_E0_F64.asm | 24 +++++++ 53 files changed, 1590 insertions(+), 2 deletions(-) create mode 100644 unittests/ASM/X87_F64/D9_03_F64.asm create mode 100644 unittests/ASM/X87_F64/D9_05_F64.asm create mode 100644 unittests/ASM/X87_F64/D9_06_2_F64.asm create mode 100644 unittests/ASM/X87_F64/D9_06_F64.asm create mode 100644 unittests/ASM/X87_F64/D9_07_F64.asm create mode 100644 unittests/ASM/X87_F64/D9_C0_F64.asm create mode 100644 unittests/ASM/X87_F64/D9_C8_F64.asm create mode 100644 unittests/ASM/X87_F64/D9_D0_F64.asm create mode 100644 unittests/ASM/X87_F64/D9_F6_F64.asm create mode 100644 unittests/ASM/X87_F64/D9_F7_F64.asm create mode 100644 unittests/ASM/X87_F64/D9_F8_F64.asm create mode 100644 unittests/ASM/X87_F64/D9_F9_F64.asm create mode 100644 unittests/ASM/X87_F64/D9_FD_2_F64.asm create mode 100644 unittests/ASM/X87_F64/DA_C0_F64.asm create mode 100644 unittests/ASM/X87_F64/DA_C8_F64.asm create mode 100644 unittests/ASM/X87_F64/DA_D0_F64.asm create mode 100644 unittests/ASM/X87_F64/DA_D8_F64.asm create mode 100644 unittests/ASM/X87_F64/DA_E9_F64.asm create mode 100644 unittests/ASM/X87_F64/DB_00_F64.asm create mode 100644 unittests/ASM/X87_F64/DB_05_F64.asm create mode 100644 unittests/ASM/X87_F64/DB_07_F64.asm create mode 100644 unittests/ASM/X87_F64/DB_C0_F64.asm create mode 100644 unittests/ASM/X87_F64/DB_C8_F64.asm create mode 100644 unittests/ASM/X87_F64/DB_D0_F64.asm create mode 100644 unittests/ASM/X87_F64/DB_D8_F64.asm create mode 100644 unittests/ASM/X87_F64/DC_00_F64.asm create mode 100644 unittests/ASM/X87_F64/DC_01_F64.asm create mode 100644 unittests/ASM/X87_F64/DC_04_F64.asm create mode 100644 unittests/ASM/X87_F64/DC_05_F64.asm create mode 100644 unittests/ASM/X87_F64/DC_06_F64.asm create mode 100644 unittests/ASM/X87_F64/DC_C0_F64.asm create mode 100644 unittests/ASM/X87_F64/DC_C8_F64.asm create mode 100644 unittests/ASM/X87_F64/DC_E0_F64.asm create mode 100644 unittests/ASM/X87_F64/DC_E8_F64.asm create mode 100644 unittests/ASM/X87_F64/DC_F0_F64.asm create mode 100644 unittests/ASM/X87_F64/DC_F8_F64.asm create mode 100644 unittests/ASM/X87_F64/DD_00_F64.asm create mode 100644 unittests/ASM/X87_F64/DD_01_F64.asm create mode 100644 unittests/ASM/X87_F64/DD_02_F64.asm create mode 100644 unittests/ASM/X87_F64/DD_03_F64.asm create mode 100644 unittests/ASM/X87_F64/DD_07_F64.asm create mode 100644 unittests/ASM/X87_F64/DD_C0_F64.asm create mode 100644 unittests/ASM/X87_F64/DD_D0_F64.asm create mode 100644 unittests/ASM/X87_F64/DD_D8_F64.asm create mode 100644 unittests/ASM/X87_F64/DD_E9_F64.asm create mode 100644 unittests/ASM/X87_F64/DF_00_F64.asm create mode 100644 unittests/ASM/X87_F64/DF_01_F64.asm create mode 100644 unittests/ASM/X87_F64/DF_03_F64.asm create mode 100644 unittests/ASM/X87_F64/DF_05_F64.asm create mode 100644 unittests/ASM/X87_F64/DF_07_F64.asm create mode 100644 unittests/ASM/X87_F64/DF_E0_F64.asm diff --git a/External/FEXCore/Source/Interface/Core/Interpreter/F80Ops.cpp b/External/FEXCore/Source/Interface/Core/Interpreter/F80Ops.cpp index 24658617c..92f958f10 100644 --- a/External/FEXCore/Source/Interface/Core/Interpreter/F80Ops.cpp +++ b/External/FEXCore/Source/Interface/Core/Interpreter/F80Ops.cpp @@ -397,7 +397,7 @@ DEF_OP(F64FPREM) { auto Op = IROp->C(); double Src1 = *GetSrc(Data->SSAData, Op->Header.Args[0]); double Src2 = *GetSrc(Data->SSAData, Op->Header.Args[1]); - double Tmp = remainder(Src1, Src2); + double Tmp = fmod(Src1, Src2); memcpy(GDP, &Tmp, sizeof(double)); } diff --git a/External/FEXCore/Source/Interface/Core/Interpreter/F80Ops.h b/External/FEXCore/Source/Interface/Core/Interpreter/F80Ops.h index 3eae5066b..ba42fc8f6 100644 --- a/External/FEXCore/Source/Interface/Core/Interpreter/F80Ops.h +++ b/External/FEXCore/Source/Interface/Core/Interpreter/F80Ops.h @@ -260,7 +260,7 @@ struct OpHandlers { template<> struct OpHandlers { static double handle(double src1, double src2) { - return remainder(src1, src2); + return fmod(src1, src2); } }; diff --git a/unittests/ASM/X87_F64/D9_03_F64.asm b/unittests/ASM/X87_F64/D9_03_F64.asm new file mode 100644 index 000000000..21afde555 --- /dev/null +++ b/unittests/ASM/X87_F64/D9_03_F64.asm @@ -0,0 +1,28 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0x3F800000", + "RBX": "0x40000000" + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rdx, 0xe0000000 + +mov eax, 0x3f800000 ; 1.0 +mov [rdx + 8 * 0], eax +mov eax, 0x40000000 ; 2.0 +mov [rdx + 8 * 1], eax +mov eax, 0x0 ; 1.0 +mov [rdx + 8 * 2], eax + +fld dword [rdx + 8 * 0] +fstp dword [rdx + 8 * 2] +fld dword [rdx + 8 * 1] + +mov eax, [rdx + 8 * 2] +fst dword [rdx + 8 * 2] +mov ebx, [rdx + 8 * 2] + +hlt diff --git a/unittests/ASM/X87_F64/D9_05_F64.asm b/unittests/ASM/X87_F64/D9_05_F64.asm new file mode 100644 index 000000000..9497bdf2b --- /dev/null +++ b/unittests/ASM/X87_F64/D9_05_F64.asm @@ -0,0 +1,11 @@ +%ifdef CONFIG +{ + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rdx, 0xe0000000 +; Just to ensure execution +fldcw [rdx] + +hlt diff --git a/unittests/ASM/X87_F64/D9_06_2_F64.asm b/unittests/ASM/X87_F64/D9_06_2_F64.asm new file mode 100644 index 000000000..1cd5b916f --- /dev/null +++ b/unittests/ASM/X87_F64/D9_06_2_F64.asm @@ -0,0 +1,53 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0x4000000000000000", + "RBX": "0x3ff0000000000000" + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rdx, 0xe0000000 + +mov eax, 0x3f800000 ; 1.0 +mov [rdx + 8 * 0], eax +mov eax, 0x40000000 ; 2.0 +mov [rdx + 8 * 1], eax +mov eax, 0x40800000 ; 4.0 +mov [rdx + 8 * 2], eax + +fld dword [rdx + 8 * 0] +o32 fstenv [rdx + 8 * 3] +fld dword [rdx + 8 * 2] +o32 fldenv [rdx + 8 * 3] + +; This will overwrite the previous load +; This is since the control word is stored and reloaded +fld dword [rdx + 8 * 1] + +; 14 bytes for 16bit +; 2 Bytes : FCW +; 2 Bytes : FSW +; 2 bytes : FTW +; 2 bytes : Instruction offset +; 2 bytes : Instruction CS selector +; 2 bytes : Data offset +; 2 bytes : Data selector + +; 28 bytes for 32bit +; 4 bytes : FCW +; 4 bytes : FSW +; 4 bytes : FTW +; 4 bytes : Instruction pointer +; 2 bytes : instruction pointer selector +; 2 bytes : Opcode +; 4 bytes : data pointer offset +; 4 bytes : data pointer selector + +fstp qword [rdx + 8] +mov rax, [rdx + 8] +fst qword [rdx + 8] +mov rbx, [rdx + 8] + +hlt diff --git a/unittests/ASM/X87_F64/D9_06_F64.asm b/unittests/ASM/X87_F64/D9_06_F64.asm new file mode 100644 index 000000000..f4e0ad606 --- /dev/null +++ b/unittests/ASM/X87_F64/D9_06_F64.asm @@ -0,0 +1,52 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0x4000000000000000", + "RBX": "0x3ff0000000000000" + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rdx, 0xe0000000 + +mov eax, 0x3f800000 ; 1.0 +mov [rdx + 8 * 0], eax +mov eax, 0x40000000 ; 2.0 +mov [rdx + 8 * 1], eax +mov eax, 0x40800000 ; 4.0 +mov [rdx + 8 * 2], eax + +fld dword [rdx + 8 * 0] +o16 fstenv [rdx + 8 * 3] +fld dword [rdx + 8 * 2] +o16 fldenv [rdx + 8 * 3] + +; This will overwrite the previous load +; This is since the control word is stored and reloaded +fld dword [rdx + 8 * 1] + +; 14 bytes for 16bit +; 2 Bytes : FCW +; 2 Bytes : FSW +; 2 bytes : FTW +; 2 bytes : Instruction offset +; 2 bytes : Instruction CS selector +; 2 bytes : Data offset +; 2 bytes : Data selector + +; 28 bytes for 32bit +; 4 bytes : FCW +; 4 bytes : FSW +; 4 bytes : FTW +; 4 bytes : Instruction pointer +; 2 bytes : instruction pointer selector +; 2 bytes : Opcode +; 4 bytes : data pointer offset +; 4 bytes : data pointer selector + +fstp qword [rdx + 8] +mov rax, [rdx + 8] +fst qword [rdx + 8] +mov rbx, [rdx + 8] +hlt diff --git a/unittests/ASM/X87_F64/D9_07_F64.asm b/unittests/ASM/X87_F64/D9_07_F64.asm new file mode 100644 index 000000000..444666e2e --- /dev/null +++ b/unittests/ASM/X87_F64/D9_07_F64.asm @@ -0,0 +1,15 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0x37F" + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rdx, 0xe0000000 +fnstcw [rdx] +mov eax, 0 +mov ax, [rdx] + +hlt diff --git a/unittests/ASM/X87_F64/D9_C0_F64.asm b/unittests/ASM/X87_F64/D9_C0_F64.asm new file mode 100644 index 000000000..38315c371 --- /dev/null +++ b/unittests/ASM/X87_F64/D9_C0_F64.asm @@ -0,0 +1,37 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0x4000000000000000", + "RBX": "0x4000000000000000", + "RCX": "0x3ff0000000000000" + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +lea rdx, [rel data] +fld tword [rdx + 8 * 0] + +lea rdx, [rel data2] +fld tword [rdx + 8 * 0] + +fld st0 + +; dump stack to registers +mov rdx, 0xe0000000 +fstp qword [rdx] +mov rax, [rdx] +fstp qword [rdx] +mov rbx, [rdx] +fstp qword [rdx] +mov rcx, [rdx] + +hlt + +align 8 +data: + dt 1.0 + dq 0 +data2: + dt 2.0 + dq 0 diff --git a/unittests/ASM/X87_F64/D9_C8_F64.asm b/unittests/ASM/X87_F64/D9_C8_F64.asm new file mode 100644 index 000000000..4613766f4 --- /dev/null +++ b/unittests/ASM/X87_F64/D9_C8_F64.asm @@ -0,0 +1,28 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": ["0x3ff0000000000000"], + "RBX": ["0x4000000000000000"] + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rdx, 0xe0000000 + +mov eax, 0x3f800000 ; 1.0 +mov [rdx + 8 * 0], eax +mov eax, 0x40000000 ; 2.0 +mov [rdx + 8 * 1], eax + +fld dword [rdx + 8 * 0] +fld dword [rdx + 8 * 1] + +fxch + +fstp qword [rdx] +mov rax, [rdx] +fstp qword [rdx] +mov rbx, [rdx] + +hlt diff --git a/unittests/ASM/X87_F64/D9_D0_F64.asm b/unittests/ASM/X87_F64/D9_D0_F64.asm new file mode 100644 index 000000000..f655f07b8 --- /dev/null +++ b/unittests/ASM/X87_F64/D9_D0_F64.asm @@ -0,0 +1,9 @@ +%ifdef CONFIG +{ + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +; Just to ensure execution +fnop +hlt diff --git a/unittests/ASM/X87_F64/D9_F6_F64.asm b/unittests/ASM/X87_F64/D9_F6_F64.asm new file mode 100644 index 000000000..69727417a --- /dev/null +++ b/unittests/ASM/X87_F64/D9_F6_F64.asm @@ -0,0 +1,44 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0x4010000000000000", + "RBX": "0x0", + "RCX": "0x4000000000000000", + "RDX": "0x3ff0000000000000" + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rdx, 0xe0000000 + +mov rax, 0x3ff0000000000000 ; 1.0 +mov [rdx + 8 * 0], rax +mov rax, 0x4000000000000000 ; 2.0 +mov [rdx + 8 * 1], rax +mov rax, 0x4010000000000000 ; 4.0 +mov [rdx + 8 * 2], rax + +fld qword [rdx + 8 * 0] +fld qword [rdx + 8 * 1] + +; Do Some stack shenanigans +fldz +fincstp +fdecstp + +fld qword [rdx + 8 * 2] + +; dump stack to registers +mov r9, 0xe0000000 +fstp qword [r9] +mov rax, [r9] +fstp qword [r9] +mov rbx, [r9] +fstp qword [r9] +mov rcx, [r9] +fstp qword [r9] +mov rdx, [r9] + + +hlt diff --git a/unittests/ASM/X87_F64/D9_F7_F64.asm b/unittests/ASM/X87_F64/D9_F7_F64.asm new file mode 100644 index 000000000..ce42d3dea --- /dev/null +++ b/unittests/ASM/X87_F64/D9_F7_F64.asm @@ -0,0 +1,65 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0x4060000000000000", + "RBX": "0x4050000000000000", + "RCX": "0x4040000000000000", + "RDX": "0x4030000000000000", + "R8": "0x4020000000000000", + "R9": "0x4000000000000000", + "R10": "0x3ff0000000000000", + "R11": "0x4070000000000000" + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rdx, 0xe0000000 + +mov rax, 0x3ff0000000000000 ; 1.0 +mov [rdx + 8 * 0], rax +mov rax, 0x4000000000000000 ; 2.0 +mov [rdx + 8 * 1], rax +mov rax, 0x4020000000000000 ; 4.0 +mov [rdx + 8 * 2], rax +mov rax, 0x4030000000000000 +mov [rdx + 8 * 3], rax +mov rax, 0x4040000000000000 +mov [rdx + 8 * 4], rax +mov rax, 0x4050000000000000 +mov [rdx + 8 * 5], rax +mov rax, 0x4060000000000000 +mov [rdx + 8 * 6], rax +mov rax, 0x4070000000000000 +mov [rdx + 8 * 7], rax + +fld qword [rdx + 8 * 0] +fld qword [rdx + 8 * 1] +fld qword [rdx + 8 * 2] +fld qword [rdx + 8 * 3] +fld qword [rdx + 8 * 4] +fld qword [rdx + 8 * 5] +fld qword [rdx + 8 * 6] +fld qword [rdx + 8 * 7] +fincstp + +; dump stack to registers +mov r12, 0xe0000000 +fstp qword [r12] +mov rax, [r12] +fstp qword [r12] +mov rbx, [r12] +fstp qword [r12] +mov rcx, [r12] +fstp qword [r12] +mov rdx, [r12] +fstp qword [r12] +mov r8, [r12] +fstp qword [r12] +mov r9, [r12] +fstp qword [r12] +mov r10, [r12] +fstp qword [r12] +mov r11, [r12] + +hlt diff --git a/unittests/ASM/X87_F64/D9_F8_F64.asm b/unittests/ASM/X87_F64/D9_F8_F64.asm new file mode 100644 index 000000000..d5632f537 --- /dev/null +++ b/unittests/ASM/X87_F64/D9_F8_F64.asm @@ -0,0 +1,32 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0x40066666", + "RBX": "0x40400000" + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +lea rdx, [rel data] +fld tword [rdx + 8 * 0] + +lea rdx, [rel data2] +fld tword [rdx + 8 * 0] + +fprem + +fstp dword [rdx + 8] +mov eax, [rdx + 8] +fst dword [rdx + 8] +mov ebx, [rdx + 8] + +hlt + +align 8 +data: + dt 3.0 + dq 0 +data2: + dt 5.1 + dq 0 diff --git a/unittests/ASM/X87_F64/D9_F9_F64.asm b/unittests/ASM/X87_F64/D9_F9_F64.asm new file mode 100644 index 000000000..36ca46fc0 --- /dev/null +++ b/unittests/ASM/X87_F64/D9_F9_F64.asm @@ -0,0 +1,35 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0x3f800000", + "RBX": "0x41be320c" + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +lea rdx, [rel data] +fld tword [rdx + 8 * 0] + +lea rdx, [rel data2] +fld tword [rdx + 8 * 0] + +fyl2xp1 +fld1 + +mov rcx, 0xe0000000 +fstp dword [rcx] +mov eax, [rcx] +fstp dword [rcx] +mov ebx, [rcx] + +hlt + +align 8 +data: + dt 15.0 + dq 0 + +data2: + dt 2.0 + dq 0 diff --git a/unittests/ASM/X87_F64/D9_FD_2_F64.asm b/unittests/ASM/X87_F64/D9_FD_2_F64.asm new file mode 100644 index 000000000..72c96d29a --- /dev/null +++ b/unittests/ASM/X87_F64/D9_FD_2_F64.asm @@ -0,0 +1,34 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0x3ff0000000000000", + "RBX": "0xc01a000000000000" + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +lea rdx, [rel data2] +fld tword [rdx + 8 * 0] + +lea rdx, [rel data] +fld tword [rdx + 8 * 0] + +fscale + +mov rcx, 0xe0000000 +fstp qword [rcx] +mov rax, [rcx] +fstp qword [rcx] +mov rbx, [rcx] + +hlt + +align 8 +data: + dt 64.0 + dq 0 + +data2: + dt -6.5 + dq 0 diff --git a/unittests/ASM/X87_F64/DA_C0_F64.asm b/unittests/ASM/X87_F64/DA_C0_F64.asm new file mode 100644 index 000000000..aadec55bb --- /dev/null +++ b/unittests/ASM/X87_F64/DA_C0_F64.asm @@ -0,0 +1,36 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0x3ff0000000000000", + "RBX": "0x0000000000000000", + "RCX": "0x3ff0000000000000" + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rdx, 0xe0000000 + +mov eax, 0x3f800000 ; 1.0 +mov [rdx + 8 * 0], eax + +fld1 +fldz + +mov eax, 2 +cmp eax, 1 + +fcmovb st0, st1 + +fldz +cmp eax, 3 +fcmovb st0, st2 + +fstp qword [rdx] +mov rax, [rdx] +fstp qword [rdx] +mov rbx, [rdx] +fstp qword [rdx] +mov rcx, [rdx] + +hlt diff --git a/unittests/ASM/X87_F64/DA_C8_F64.asm b/unittests/ASM/X87_F64/DA_C8_F64.asm new file mode 100644 index 000000000..885dcfc3a --- /dev/null +++ b/unittests/ASM/X87_F64/DA_C8_F64.asm @@ -0,0 +1,36 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0x0000000000000000", + "RBX": "0x3ff0000000000000", + "RCX": "0x3ff0000000000000" + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rdx, 0xe0000000 + +mov eax, 0x3f800000 ; 1.0 +mov [rdx + 8 * 0], eax + +fld1 +fldz + +mov eax, 1 +cmp eax, 1 + +fcmove st0, st1 + +fldz +cmp eax, 0 +fcmove st0, st2 + +fstp qword [rdx] +mov rax, [rdx] +fstp qword [rdx] +mov rbx, [rdx] +fstp qword [rdx] +mov rcx, [rdx] + +hlt diff --git a/unittests/ASM/X87_F64/DA_D0_F64.asm b/unittests/ASM/X87_F64/DA_D0_F64.asm new file mode 100644 index 000000000..c8f659bd5 --- /dev/null +++ b/unittests/ASM/X87_F64/DA_D0_F64.asm @@ -0,0 +1,36 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0x0000000000000000", + "RBX": "0x3ff0000000000000", + "RCX": "0x3ff0000000000000" + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rdx, 0xe0000000 + +mov eax, 0x3f800000 ; 1.0 +mov [rdx + 8 * 0], eax + +fld1 +fldz + +mov eax, 2 +cmp eax, 2 + +fcmovbe st0, st1 + +fldz +cmp eax, 0 +fcmovbe st0, st2 + +fstp qword [rdx] +mov rax, [rdx] +fstp qword [rdx] +mov rbx, [rdx] +fstp qword [rdx] +mov rcx, [rdx] + +hlt diff --git a/unittests/ASM/X87_F64/DA_D8_F64.asm b/unittests/ASM/X87_F64/DA_D8_F64.asm new file mode 100644 index 000000000..f1f54b5de --- /dev/null +++ b/unittests/ASM/X87_F64/DA_D8_F64.asm @@ -0,0 +1,36 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0x3ff0000000000000", + "RBX": "0x0000000000000000", + "RCX": "0x3ff0000000000000" + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rdx, 0xe0000000 + +mov eax, 0x3f800000 ; 1.0 +mov [rdx + 8 * 0], eax + +fld1 +fldz + +mov eax, 0x0 +cmp eax, -1 + +fcmovu st0, st1 + +fldz +cmp eax, 1 +fcmovu st0, st2 + +fstp qword [rdx] +mov rax, [rdx] +fstp qword [rdx] +mov rbx, [rdx] +fstp qword [rdx] +mov rcx, [rdx] + +hlt diff --git a/unittests/ASM/X87_F64/DA_E9_F64.asm b/unittests/ASM/X87_F64/DA_E9_F64.asm new file mode 100644 index 000000000..ffc2f926f --- /dev/null +++ b/unittests/ASM/X87_F64/DA_E9_F64.asm @@ -0,0 +1,24 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0x3ff0000000000000", + "RBX": "0x3ff0000000000000" + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +; Only tests pop behaviour +fld1 +fldz +fldz +fucompp +fld1 + +mov rdx, 0xe0000000 +fstp qword [rdx] +mov rax, [rdx] +fstp qword [rdx] +mov rbx, [rdx] + +hlt diff --git a/unittests/ASM/X87_F64/DB_00_F64.asm b/unittests/ASM/X87_F64/DB_00_F64.asm new file mode 100644 index 000000000..92dc0b420 --- /dev/null +++ b/unittests/ASM/X87_F64/DB_00_F64.asm @@ -0,0 +1,20 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0x4090000000000000" + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rdx, 0xe0000000 + +mov eax, 1024 +mov [rdx + 8 * 0], eax + +fild dword [rdx + 8 * 0] + +fstp qword [rdx] +mov rax, [rdx] + +hlt diff --git a/unittests/ASM/X87_F64/DB_05_F64.asm b/unittests/ASM/X87_F64/DB_05_F64.asm new file mode 100644 index 000000000..2c3d55f5a --- /dev/null +++ b/unittests/ASM/X87_F64/DB_05_F64.asm @@ -0,0 +1,23 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0x4000000000000000" + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +lea rdx, [rel data] + +fld tword [rdx + 8 * 0] + +mov rdx, 0xe0000000 +fstp qword [rdx] +mov rax, [rdx] + +hlt + +align 8 +data: + dt 2.0 + dq 0 diff --git a/unittests/ASM/X87_F64/DB_07_F64.asm b/unittests/ASM/X87_F64/DB_07_F64.asm new file mode 100644 index 000000000..348067315 --- /dev/null +++ b/unittests/ASM/X87_F64/DB_07_F64.asm @@ -0,0 +1,29 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0x4000000000000000" + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +lea rdx, [rel data] +fld tword [rdx + 8 * 0] + +lea rdx, [rel data2] +fstp tword [rdx + 8 * 0] +fld tword [rdx + 8 * 0] + +mov rdx, 0xe0000000 +fstp qword [rdx] +mov rax, [rdx] + +hlt + +align 8 +data: + dt 2.0 + dq 0 +data2: + dt 0.0 + dq 0 diff --git a/unittests/ASM/X87_F64/DB_C0_F64.asm b/unittests/ASM/X87_F64/DB_C0_F64.asm new file mode 100644 index 000000000..cb3c5a816 --- /dev/null +++ b/unittests/ASM/X87_F64/DB_C0_F64.asm @@ -0,0 +1,36 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0x0000000000000000", + "RBX": "0x3ff0000000000000", + "RCX": "0x3ff0000000000000" + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rdx, 0xe0000000 + +mov eax, 0x3f800000 ; 1.0 +mov [rdx + 8 * 0], eax + +fld1 +fldz + +mov eax, 2 +cmp eax, 1 + +fcmovnb st0, st1 + +fldz +cmp eax, 3 +fcmovnb st0, st2 + +fstp qword [rdx] +mov rax, [rdx] +fstp qword [rdx] +mov rbx, [rdx] +fstp qword [rdx] +mov rcx, [rdx] + +hlt diff --git a/unittests/ASM/X87_F64/DB_C8_F64.asm b/unittests/ASM/X87_F64/DB_C8_F64.asm new file mode 100644 index 000000000..f702979f5 --- /dev/null +++ b/unittests/ASM/X87_F64/DB_C8_F64.asm @@ -0,0 +1,37 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0x3ff0000000000000", + "RBX": "0x0000000000000000", + "RCX": "0x3ff0000000000000" + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rdx, 0xe0000000 + +mov eax, 0x3f800000 ; 1.0 +mov [rdx + 8 * 0], eax + +fld1 +fldz + +mov eax, 1 +cmp eax, 1 + +fcmovne st0, st1 + +fldz +cmp eax, 0 +fcmovne st0, st2 + +fstp qword [rdx] +mov rax, [rdx] +fstp qword [rdx] +mov rbx, [rdx] +fstp qword [rdx] +mov rcx, [rdx] + + +hlt diff --git a/unittests/ASM/X87_F64/DB_D0_F64.asm b/unittests/ASM/X87_F64/DB_D0_F64.asm new file mode 100644 index 000000000..467d3281d --- /dev/null +++ b/unittests/ASM/X87_F64/DB_D0_F64.asm @@ -0,0 +1,36 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0x3ff0000000000000", + "RBX": "0x0000000000000000", + "RCX": "0x3ff0000000000000" + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rdx, 0xe0000000 + +mov eax, 0x3f800000 ; 1.0 +mov [rdx + 8 * 0], eax + +fld1 +fldz + +mov eax, 2 +cmp eax, 2 + +fcmovnbe st0, st1 + +fldz +cmp eax, 0 +fcmovnbe st0, st2 + +fstp qword [rdx] +mov rax, [rdx] +fstp qword [rdx] +mov rbx, [rdx] +fstp qword [rdx] +mov rcx, [rdx] + +hlt diff --git a/unittests/ASM/X87_F64/DB_D8_F64.asm b/unittests/ASM/X87_F64/DB_D8_F64.asm new file mode 100644 index 000000000..d68c2a059 --- /dev/null +++ b/unittests/ASM/X87_F64/DB_D8_F64.asm @@ -0,0 +1,36 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0x0000000000000000", + "RBX": "0x3ff0000000000000", + "RCX": "0x3ff0000000000000" + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rdx, 0xe0000000 + +mov eax, 0x3f800000 ; 1.0 +mov [rdx + 8 * 0], eax + +fld1 +fldz + +mov eax, 0x0 +cmp eax, -1 + +fcmovnu st0, st1 + +fldz +cmp eax, 1 +fcmovnu st0, st2 + +fstp qword [rdx] +mov rax, [rdx] +fstp qword [rdx] +mov rbx, [rdx] +fstp qword [rdx] +mov rcx, [rdx] + +hlt diff --git a/unittests/ASM/X87_F64/DC_00_F64.asm b/unittests/ASM/X87_F64/DC_00_F64.asm new file mode 100644 index 000000000..e5b658a27 --- /dev/null +++ b/unittests/ASM/X87_F64/DC_00_F64.asm @@ -0,0 +1,28 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0x4008000000000000" + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + + +lea rdx, [rel data] +fld tword [rdx + 8 * 0] + +lea rdx, [rel data2] +fadd qword [rdx + 8 * 0] + +mov rdx, 0xe0000000 +fstp qword [rdx] +mov rax, [rdx] + +hlt + +align 8 +data: + dt 1.0 + dq 0 +data2: + dq 2.0 diff --git a/unittests/ASM/X87_F64/DC_01_F64.asm b/unittests/ASM/X87_F64/DC_01_F64.asm new file mode 100644 index 000000000..4572fedb7 --- /dev/null +++ b/unittests/ASM/X87_F64/DC_01_F64.asm @@ -0,0 +1,27 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0x4000000000000000" + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +lea rdx, [rel data] +fld tword [rdx + 8 * 0] + +lea rdx, [rel data2] +fmul qword [rdx + 8 * 0] + +mov rdx, 0xe0000000 +fstp qword [rdx] +mov rax, [rdx] + +hlt + +align 8 +data: + dt 1.0 + dq 0 +data2: + dq 2.0 diff --git a/unittests/ASM/X87_F64/DC_04_F64.asm b/unittests/ASM/X87_F64/DC_04_F64.asm new file mode 100644 index 000000000..152ee57a5 --- /dev/null +++ b/unittests/ASM/X87_F64/DC_04_F64.asm @@ -0,0 +1,27 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0xbff0000000000000" + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +lea rdx, [rel data] +fld tword [rdx + 8 * 0] + +lea rdx, [rel data2] +fsub qword [rdx + 8 * 0] + +mov rdx, 0xe0000000 +fstp qword [rdx] +mov rax, [rdx] + +hlt + +align 8 +data: + dt 1.0 + dq 0 +data2: + dq 2.0 diff --git a/unittests/ASM/X87_F64/DC_05_F64.asm b/unittests/ASM/X87_F64/DC_05_F64.asm new file mode 100644 index 000000000..00c2929ed --- /dev/null +++ b/unittests/ASM/X87_F64/DC_05_F64.asm @@ -0,0 +1,27 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0x3ff0000000000000" + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +lea rdx, [rel data] +fld tword [rdx + 8 * 0] + +lea rdx, [rel data2] +fsubr qword [rdx + 8 * 0] + +mov rdx, 0xe0000000 +fstp qword [rdx] +mov rax, [rdx] + +hlt + +align 8 +data: + dt 1.0 + dq 0 +data2: + dq 2.0 diff --git a/unittests/ASM/X87_F64/DC_06_F64.asm b/unittests/ASM/X87_F64/DC_06_F64.asm new file mode 100644 index 000000000..8e5bbb5a5 --- /dev/null +++ b/unittests/ASM/X87_F64/DC_06_F64.asm @@ -0,0 +1,27 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0x3fe0000000000000" + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +lea rdx, [rel data] +fld tword [rdx + 8 * 0] + +lea rdx, [rel data2] +fdiv qword [rdx + 8 * 0] + +mov rdx, 0xe0000000 +fstp qword [rdx] +mov rax, [rdx] + +hlt + +align 8 +data: + dt 1.0 + dq 0 +data2: + dq 2.0 diff --git a/unittests/ASM/X87_F64/DC_C0_F64.asm b/unittests/ASM/X87_F64/DC_C0_F64.asm new file mode 100644 index 000000000..5960cb817 --- /dev/null +++ b/unittests/ASM/X87_F64/DC_C0_F64.asm @@ -0,0 +1,36 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0x4010000000000000", + "RBX": "0x4000000000000000", + "RCX": "0x4014000000000000" + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + + +mov rdx, 0xe0000000 + +mov rax, 0x3ff0000000000000 ; 1.0 +mov [rdx + 8 * 0], rax +mov rax, 0x4000000000000000 ; 2.0 +mov [rdx + 8 * 1], rax +mov rax, 0x4010000000000000 ; 4.0 +mov [rdx + 8 * 2], rax + +fld qword [rdx + 8 * 0] +fld qword [rdx + 8 * 1] +fld qword [rdx + 8 * 2] + +; fadd st(i), st(0) +fadd st2, st0 + +fstp qword [rdx] +mov rax, [rdx] +fstp qword [rdx] +mov rbx, [rdx] +fstp qword [rdx] +mov rcx, [rdx] + +hlt diff --git a/unittests/ASM/X87_F64/DC_C8_F64.asm b/unittests/ASM/X87_F64/DC_C8_F64.asm new file mode 100644 index 000000000..ded66d45d --- /dev/null +++ b/unittests/ASM/X87_F64/DC_C8_F64.asm @@ -0,0 +1,34 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0x4010000000000000", + "RBX": "0x4020000000000000" + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rdx, 0xe0000000 + +lea rdx, [rel data] +fld tword [rdx + 8 * 0] + +lea rdx, [rel data2] +fld tword [rdx + 8 * 0] + +fmul st1, st0 + +fstp qword [rdx] +mov rax, [rdx] +fstp qword [rdx] +mov rbx, [rdx] + +hlt + +align 8 +data: + dt 2.0 + dq 0 +data2: + dt 4.0 + dq 0 diff --git a/unittests/ASM/X87_F64/DC_E0_F64.asm b/unittests/ASM/X87_F64/DC_E0_F64.asm new file mode 100644 index 000000000..089b21af7 --- /dev/null +++ b/unittests/ASM/X87_F64/DC_E0_F64.asm @@ -0,0 +1,32 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0x4000000000000000", + "RBX": "0x3ff0000000000000" + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +lea rdx, [rel data] +fld tword [rdx + 8 * 0] + +lea rdx, [rel data2] +fld tword [rdx + 8 * 0] + +fsubr st1, st0 + +fstp qword [rdx] +mov rax, [rdx] +fstp qword [rdx] +mov rbx, [rdx] + +hlt + +align 8 +data: + dt 1.0 + dq 0 +data2: + dt 2.0 + dq 0 diff --git a/unittests/ASM/X87_F64/DC_E8_F64.asm b/unittests/ASM/X87_F64/DC_E8_F64.asm new file mode 100644 index 000000000..fc877901a --- /dev/null +++ b/unittests/ASM/X87_F64/DC_E8_F64.asm @@ -0,0 +1,33 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0x4000000000000000", + "RBX": "0xbff0000000000000" + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +lea rdx, [rel data] +fld tword [rdx + 8 * 0] + +lea rdx, [rel data2] +fld tword [rdx + 8 * 0] + +fsub st1, st0 + +fstp qword [rdx] +mov rax, [rdx] +fstp qword [rdx] +mov rbx, [rdx] + + +hlt + +align 8 +data: + dt 1.0 + dq 0 +data2: + dt 2.0 + dq 0 diff --git a/unittests/ASM/X87_F64/DC_F0_F64.asm b/unittests/ASM/X87_F64/DC_F0_F64.asm new file mode 100644 index 000000000..fdfb5162b --- /dev/null +++ b/unittests/ASM/X87_F64/DC_F0_F64.asm @@ -0,0 +1,32 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0x3ff0000000000000", + "RBX": "0x3fe0000000000000" + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +lea rdx, [rel data] +fld tword [rdx + 8 * 0] + +lea rdx, [rel data2] +fld tword [rdx + 8 * 0] + +fdivr st1, st0 + +fstp qword [rdx] +mov rax, [rdx] +fstp qword [rdx] +mov rbx, [rdx] + +hlt + +align 8 +data: + dt 2.0 + dq 0 +data2: + dt 1.0 + dq 0 diff --git a/unittests/ASM/X87_F64/DC_F8_F64.asm b/unittests/ASM/X87_F64/DC_F8_F64.asm new file mode 100644 index 000000000..53ebda9e3 --- /dev/null +++ b/unittests/ASM/X87_F64/DC_F8_F64.asm @@ -0,0 +1,32 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0x4000000000000000", + "RBX": "0x4010000000000000" + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +lea rdx, [rel data] +fld tword [rdx + 8 * 0] + +lea rdx, [rel data2] +fld tword [rdx + 8 * 0] + +fdiv st1, st0 + +fstp qword [rdx] +mov rax, [rdx] +fstp qword [rdx] +mov rbx, [rdx] + +hlt + +align 8 +data: + dt 8.0 + dq 0 +data2: + dt 2.0 + dq 0 diff --git a/unittests/ASM/X87_F64/DD_00_F64.asm b/unittests/ASM/X87_F64/DD_00_F64.asm new file mode 100644 index 000000000..5dd8f5f40 --- /dev/null +++ b/unittests/ASM/X87_F64/DD_00_F64.asm @@ -0,0 +1,20 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0x4000000000000000" + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rdx, 0xe0000000 + +mov rax, 0x4000000000000000 ; 2.0 +mov [rdx + 8 * 0], rax + +fld qword [rdx + 8 * 0] + +fstp qword [rdx] +mov rax, [rdx] + +hlt diff --git a/unittests/ASM/X87_F64/DD_01_F64.asm b/unittests/ASM/X87_F64/DD_01_F64.asm new file mode 100644 index 000000000..e8d79c4ce --- /dev/null +++ b/unittests/ASM/X87_F64/DD_01_F64.asm @@ -0,0 +1,36 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0x2", + "RBX": "0x3ff0000000000000" + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +lea rdx, [rel data] +fld tword [rdx + 8 * 0] + +lea rdx, [rel data3] +fisttp qword [rdx + 8 * 0] + +mov rax, [rdx + 8 * 0] + +lea rdx, [rel data2] +fld tword [rdx + 8 * 0] + +fstp qword [rdx] +mov rbx, [rdx] + +hlt + +align 8 +data: + dt 2.0 + dq 0 +data2: + dt 1.0 + dq 0 +data3: + dq 0 + dq 0 diff --git a/unittests/ASM/X87_F64/DD_02_F64.asm b/unittests/ASM/X87_F64/DD_02_F64.asm new file mode 100644 index 000000000..704c814af --- /dev/null +++ b/unittests/ASM/X87_F64/DD_02_F64.asm @@ -0,0 +1,39 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0x4000000000000000", + "RBX": "0x3ff0000000000000", + "RCX": "0x4000000000000000" + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +lea rdx, [rel data] +fld tword [rdx + 8 * 0] + +lea rdx, [rel data3] +fst qword [rdx + 8 * 0] + +mov rax, [rdx + 8 * 0] + +lea rdx, [rel data2] +fld tword [rdx + 8 * 0] + +fstp qword [rdx] +mov rbx, [rdx] +fstp qword [rdx] +mov rcx, [rdx] + +hlt + +align 8 +data: + dt 2.0 + dq 0 +data2: + dt 1.0 + dq 0 +data3: + dq 0 + dq 0 diff --git a/unittests/ASM/X87_F64/DD_03_F64.asm b/unittests/ASM/X87_F64/DD_03_F64.asm new file mode 100644 index 000000000..00cf51c6a --- /dev/null +++ b/unittests/ASM/X87_F64/DD_03_F64.asm @@ -0,0 +1,36 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0x4000000000000000", + "RBX": "0x3ff0000000000000" + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +lea rdx, [rel data] +fld tword [rdx + 8 * 0] + +lea rdx, [rel data3] +fstp qword [rdx + 8 * 0] + +mov rax, [rdx + 8 * 0] + +lea rdx, [rel data2] +fld tword [rdx + 8 * 0] + +fstp qword [rdx] +mov rbx, [rdx] + +hlt + +align 8 +data: + dt 2.0 + dq 0 +data2: + dt 1.0 + dq 0 +data3: + dq 0 + dq 0 diff --git a/unittests/ASM/X87_F64/DD_07_F64.asm b/unittests/ASM/X87_F64/DD_07_F64.asm new file mode 100644 index 000000000..ffe384cbf --- /dev/null +++ b/unittests/ASM/X87_F64/DD_07_F64.asm @@ -0,0 +1,25 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0xFFFFFFFFFFFF3800", + "RBX": "0xFFFFFFFFFFFF0000" + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rdx, 0xe0000000 + +mov eax, 0x3f800000 ; 1.0 +mov [rdx + 8 * 0], eax + +mov rax, -1 +mov rbx, -1 +fnstsw [rdx + 8 * 1] + +fld dword [rdx + 8 * 0] +fnstsw [rdx + 8 * 2] +mov ax, word [rdx + 8 * 2] +mov bx, word [rdx + 8 * 1] + +hlt diff --git a/unittests/ASM/X87_F64/DD_C0_F64.asm b/unittests/ASM/X87_F64/DD_C0_F64.asm new file mode 100644 index 000000000..e0b1e0905 --- /dev/null +++ b/unittests/ASM/X87_F64/DD_C0_F64.asm @@ -0,0 +1,16 @@ +%ifdef CONFIG +{ + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +; Just to ensure execution +ffree st0 +ffree st1 +ffree st2 +ffree st3 +ffree st4 +ffree st5 +ffree st6 +ffree st7 +hlt diff --git a/unittests/ASM/X87_F64/DD_D0_F64.asm b/unittests/ASM/X87_F64/DD_D0_F64.asm new file mode 100644 index 000000000..7b8f5d166 --- /dev/null +++ b/unittests/ASM/X87_F64/DD_D0_F64.asm @@ -0,0 +1,31 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0x3ff0000000000000", + "RBX": "0x3ff0000000000000" + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +lea rdx, [rel data] +fld tword [rdx + 8 * 0] + +lea rdx, [rel data2] +fld tword [rdx + 8 * 0] +fst st1 + +fstp qword [rdx] +mov rax, [rdx] +fstp qword [rdx] +mov rbx, [rdx] + +hlt + +align 8 +data: + dt 2.0 + dq 0 +data2: + dt 1.0 + dq 0 diff --git a/unittests/ASM/X87_F64/DD_D8_F64.asm b/unittests/ASM/X87_F64/DD_D8_F64.asm new file mode 100644 index 000000000..751dcee13 --- /dev/null +++ b/unittests/ASM/X87_F64/DD_D8_F64.asm @@ -0,0 +1,38 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0x4010000000000000", + "RBX": "0x3ff0000000000000" + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +lea rdx, [rel data] +fld tword [rdx + 8 * 0] + +lea rdx, [rel data2] +fld tword [rdx + 8 * 0] +fstp st1 + +lea rdx, [rel data3] +fld tword [rdx + 8 * 0] + +fstp qword [rdx] +mov rax, [rdx] +fstp qword [rdx] +mov rbx, [rdx] + +hlt + +align 8 +data: + dt 2.0 + dq 0 +data2: + dt 1.0 + dq 0 +data3: + dt 4.0 + dq 0 + diff --git a/unittests/ASM/X87_F64/DD_E9_F64.asm b/unittests/ASM/X87_F64/DD_E9_F64.asm new file mode 100644 index 000000000..4871a97c8 --- /dev/null +++ b/unittests/ASM/X87_F64/DD_E9_F64.asm @@ -0,0 +1,24 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0x3ff0000000000000", + "RBX": "0x3ff0000000000000" + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +; Only tests pop behaviour +fld1 +fldz +fucomp +fld1 + +mov rdx, 0xe0000000 +fstp qword [rdx] +mov rax, [rdx] +fstp qword [rdx] +mov rbx, [rdx] + + +hlt diff --git a/unittests/ASM/X87_F64/DF_00_F64.asm b/unittests/ASM/X87_F64/DF_00_F64.asm new file mode 100644 index 000000000..c01349239 --- /dev/null +++ b/unittests/ASM/X87_F64/DF_00_F64.asm @@ -0,0 +1,21 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0x4090000000000000" + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rdx, 0xe0000000 + +mov eax, 1024 +mov [rdx + 8 * 0], eax +mov eax, -1 +mov [rdx + 8 * 0 + 2], eax + +fild word [rdx + 8 * 0] +fst qword [rdx + 8 * 0] +mov rax, [rdx + 8 * 0] + +hlt diff --git a/unittests/ASM/X87_F64/DF_01_F64.asm b/unittests/ASM/X87_F64/DF_01_F64.asm new file mode 100644 index 000000000..5956cc1c2 --- /dev/null +++ b/unittests/ASM/X87_F64/DF_01_F64.asm @@ -0,0 +1,36 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0x2", + "RBX": "0x3ff0000000000000" + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +lea rdx, [rel data] +fld tword [rdx + 8 * 0] + +lea rdx, [rel data3] +fisttp word [rdx + 8 * 0] + +mov ax, word [rdx + 8 * 0] + +lea rdx, [rel data2] +fld tword [rdx + 8 * 0] + +fst qword [rdx + 8 * 0] +mov rbx, [rdx + 8 * 0] + +hlt + +align 8 +data: + dt 2.0 + dq 0 +data2: + dt 1.0 + dq 0 +data3: + dq -1 + dq -1 diff --git a/unittests/ASM/X87_F64/DF_03_F64.asm b/unittests/ASM/X87_F64/DF_03_F64.asm new file mode 100644 index 000000000..52e7b3c5f --- /dev/null +++ b/unittests/ASM/X87_F64/DF_03_F64.asm @@ -0,0 +1,30 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0x400", + "RBX": "0x3ff0000000000000" + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rdx, 0xe0000000 + +mov eax, 0x44800000 ; 1024.0 +mov [rdx + 8 * 0], eax +mov eax, -1 +mov [rdx + 8 * 1], eax + +fld dword [rdx + 8 * 0] + +fistp word [rdx + 8 * 1] + +fld1 + +mov eax, 0 +mov ax, word [rdx + 8 * 1] + +fst qword [rdx + 8 * 0] +mov rbx, [rdx + 8 * 0] + +hlt diff --git a/unittests/ASM/X87_F64/DF_05_F64.asm b/unittests/ASM/X87_F64/DF_05_F64.asm new file mode 100644 index 000000000..1908caa7c --- /dev/null +++ b/unittests/ASM/X87_F64/DF_05_F64.asm @@ -0,0 +1,19 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0x4090000000000000" + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rdx, 0xe0000000 + +mov rax, 1024 +mov [rdx + 8 * 0], rax + +fild qword [rdx + 8 * 0] +fst qword [rdx + 8 * 0] +mov rax, [rdx + 8 * 0] + +hlt diff --git a/unittests/ASM/X87_F64/DF_07_F64.asm b/unittests/ASM/X87_F64/DF_07_F64.asm new file mode 100644 index 000000000..e72576afe --- /dev/null +++ b/unittests/ASM/X87_F64/DF_07_F64.asm @@ -0,0 +1,30 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0x400", + "RBX": "0x3ff0000000000000" + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rdx, 0xe0000000 + +mov eax, 0x44800000 ; 1024.0 +mov [rdx + 8 * 0], eax +mov rax, -1 +mov [rdx + 8 * 1], rax + +fld dword [rdx + 8 * 0] + +fistp qword [rdx + 8 * 1] + +fld1 + +mov rax, qword [rdx + 8 * 1] + +fstp qword [rdx + 8 * 1] + +mov rbx, qword [rdx + 8 * 1] + +hlt diff --git a/unittests/ASM/X87_F64/DF_E0_F64.asm b/unittests/ASM/X87_F64/DF_E0_F64.asm new file mode 100644 index 000000000..631c2f0d4 --- /dev/null +++ b/unittests/ASM/X87_F64/DF_E0_F64.asm @@ -0,0 +1,24 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0xFFFFFFFFFFFF3800", + "RBX": "0xFFFFFFFFFFFF0000" + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +mov rdx, 0xe0000000 + +mov eax, 0x3f800000 ; 1.0 +mov [rdx + 8 * 0], eax + +mov rax, -1 +mov rbx, -1 +fnstsw ax +mov bx, ax + +fld dword [rdx + 8 * 0] +fnstsw ax + +hlt From 3679673d5b84d946f573f8c3966681c4798daf1b Mon Sep 17 00:00:00 2001 From: CallumDev Date: Tue, 22 Mar 2022 15:06:07 +1030 Subject: [PATCH 14/15] Implement FNSAVE and FRSTOR in F64 --- .../Interface/Core/OpcodeDispatcher.cpp | 4 +- .../Source/Interface/Core/OpcodeDispatcher.h | 2 + .../Core/OpcodeDispatcher/X87F64.cpp | 184 +++++++++++++++++- unittests/ASM/X87_F64/DD_04_2_F64.asm | 87 +++++++++ unittests/ASM/X87_F64/DD_04_F64.asm | 88 +++++++++ 5 files changed, 361 insertions(+), 4 deletions(-) create mode 100644 unittests/ASM/X87_F64/DD_04_2_F64.asm create mode 100644 unittests/ASM/X87_F64/DD_04_F64.asm diff --git a/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp b/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp index 092c02b6d..13be18b23 100644 --- a/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp +++ b/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp @@ -6042,10 +6042,10 @@ constexpr uint16_t PF_F2 = 3; {OPDReg(0xDD, 3) | 0x00, 8, &OpDispatchBuilder::FSTF64<64>}, - {OPDReg(0xDD, 4) | 0x00, 8, &OpDispatchBuilder::X87FRSTOR}, + {OPDReg(0xDD, 4) | 0x00, 8, &OpDispatchBuilder::X87FRSTORF64}, // 5 = Invalid - {OPDReg(0xDD, 6) | 0x00, 8, &OpDispatchBuilder::X87FNSAVE}, + {OPDReg(0xDD, 6) | 0x00, 8, &OpDispatchBuilder::X87FNSAVEF64}, {OPDReg(0xDD, 7) | 0x00, 8, &OpDispatchBuilder::X87FNSTSW}, diff --git a/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.h b/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.h index f58e5ade1..31a5cb853 100644 --- a/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.h +++ b/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.h @@ -505,6 +505,8 @@ public: void X87FYL2XF64(OpcodeArgs); void X87TANF64(OpcodeArgs); void X87ATANF64(OpcodeArgs); + void X87FNSAVEF64(OpcodeArgs); + void X87FRSTORF64(OpcodeArgs); void X87FXAMF64(OpcodeArgs); template diff --git a/External/FEXCore/Source/Interface/Core/OpcodeDispatcher/X87F64.cpp b/External/FEXCore/Source/Interface/Core/OpcodeDispatcher/X87F64.cpp index 210339ce0..cc89eea1f 100644 --- a/External/FEXCore/Source/Interface/Core/OpcodeDispatcher/X87F64.cpp +++ b/External/FEXCore/Source/Interface/Core/OpcodeDispatcher/X87F64.cpp @@ -37,8 +37,6 @@ class OrderedNode; //FSTCW //LDSW //FNSTSW -//FNSAVE -//FRSTOR //FXCH //FCMOV //FST(register to register) @@ -811,6 +809,188 @@ void OpDispatchBuilder::X87ATANF64(OpcodeArgs) { _StoreContextIndexed(result, top, 8, MMBaseOffset(), 16, FPRClass); } +//This function converts to F80 on save for compatibility + +void OpDispatchBuilder::X87FNSAVEF64(OpcodeArgs) { + // 14 bytes for 16bit + // 2 Bytes : FCW + // 2 Bytes : FSW + // 2 bytes : FTW + // 2 bytes : Instruction offset + // 2 bytes : Instruction CS selector + // 2 bytes : Data offset + // 2 bytes : Data selector + + // 28 bytes for 32bit + // 4 bytes : FCW + // 4 bytes : FSW + // 4 bytes : FTW + // 4 bytes : Instruction pointer + // 2 bytes : instruction pointer selector + // 2 bytes : Opcode + // 4 bytes : data pointer offset + // 4 bytes : data pointer selector + + auto Size = GetDstSize(Op); + OrderedNode *Mem = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, -1, false); + Mem = AppendSegmentOffset(Mem, Op->Flags); + + OrderedNode *Top = GetX87Top(); + { + auto FCW = _LoadContext(2, GPRClass, offsetof(FEXCore::Core::CPUState, FCW)); + _StoreMem(GPRClass, Size, Mem, FCW, Size); + } + + { + OrderedNode *MemLocation = _Add(Mem, _Constant(Size * 1)); + // We must construct the FSW from our various bits + OrderedNode *FSW = _Constant(0); + FSW = _Or(FSW, _Lshl(Top, _Constant(11))); + + auto C0 = GetRFLAG(FEXCore::X86State::X87FLAG_C0_LOC); + auto C1 = GetRFLAG(FEXCore::X86State::X87FLAG_C1_LOC); + auto C2 = GetRFLAG(FEXCore::X86State::X87FLAG_C2_LOC); + auto C3 = GetRFLAG(FEXCore::X86State::X87FLAG_C3_LOC); + + FSW = _Or(FSW, _Lshl(C0, _Constant(8))); + FSW = _Or(FSW, _Lshl(C1, _Constant(9))); + FSW = _Or(FSW, _Lshl(C2, _Constant(10))); + FSW = _Or(FSW, _Lshl(C3, _Constant(14))); + _StoreMem(GPRClass, Size, MemLocation, FSW, Size); + } + + auto ZeroConst = _Constant(0); + + { + // FTW + OrderedNode *MemLocation = _Add(Mem, _Constant(Size * 2)); + auto FTW = _LoadContext(2, GPRClass, offsetof(FEXCore::Core::CPUState, FTW)); + _StoreMem(GPRClass, Size, MemLocation, FTW, Size); + } + + { + // Instruction Offset + OrderedNode *MemLocation = _Add(Mem, _Constant(Size * 3)); + _StoreMem(GPRClass, Size, MemLocation, ZeroConst, Size); + } + + { + // Instruction CS selector (+ Opcode) + OrderedNode *MemLocation = _Add(Mem, _Constant(Size * 4)); + _StoreMem(GPRClass, Size, MemLocation, ZeroConst, Size); + } + + { + // Data pointer offset + OrderedNode *MemLocation = _Add(Mem, _Constant(Size * 5)); + _StoreMem(GPRClass, Size, MemLocation, ZeroConst, Size); + } + + { + // Data pointer selector + OrderedNode *MemLocation = _Add(Mem, _Constant(Size * 6)); + _StoreMem(GPRClass, Size, MemLocation, ZeroConst, Size); + } + + OrderedNode *ST0Location = _Add(Mem, _Constant(Size * 7)); + + auto OneConst = _Constant(1); + auto SevenConst = _Constant(7); + auto TenConst = _Constant(10); + for (int i = 0; i < 7; ++i) { + OrderedNode* data = _LoadContextIndexed(Top, 8, MMBaseOffset(), 16, FPRClass); + data = _F80CVTTo(data, 8); + _StoreMem(FPRClass, 16, ST0Location, data, 1); + ST0Location = _Add(ST0Location, TenConst); + Top = _And(_Add(Top, OneConst), SevenConst); + } + + // The final st(7) needs a bit of special handling here + OrderedNode* data = _LoadContextIndexed(Top, 8, MMBaseOffset(), 16, FPRClass); + data = _F80CVTTo(data, 8); + // ST7 broken in to two parts + // Lower 64bits [63:0] + // upper 16 bits [79:64] + _StoreMem(FPRClass, 8, ST0Location, data, 1); + ST0Location = _Add(ST0Location, _Constant(8)); + auto topBytes = _VExtractElement(16, 2, data, 4); + _StoreMem(FPRClass, 2, ST0Location, topBytes, 1); + + // reset to default + FNINIT(Op); +} + +//This function converts from F80 on load for compatibility + +void OpDispatchBuilder::X87FRSTORF64(OpcodeArgs) { + auto Size = GetSrcSize(Op); + OrderedNode *Mem = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags, -1, false); + Mem = AppendSegmentOffset(Mem, Op->Flags); + + auto NewFCW = _LoadMem(GPRClass, 2, Mem, 2); + _F80LoadFCW(NewFCW); + _StoreContext(2, GPRClass, NewFCW, offsetof(FEXCore::Core::CPUState, FCW)); + + OrderedNode *MemLocation = _Add(Mem, _Constant(Size * 1)); + auto NewFSW = _LoadMem(GPRClass, Size, MemLocation, Size); + + // Strip out the FSW information + OrderedNode *Top = _Bfe(3, 11, NewFSW); + SetX87Top(Top); + + auto C0 = _Bfe(1, 8, NewFSW); + auto C1 = _Bfe(1, 9, NewFSW); + auto C2 = _Bfe(1, 10, NewFSW); + auto C3 = _Bfe(1, 14, NewFSW); + + SetRFLAG(C0); + SetRFLAG(C1); + SetRFLAG(C2); + SetRFLAG(C3); + + { + // FTW + OrderedNode *MemLocation = _Add(Mem, _Constant(Size * 2)); + auto NewFTW = _LoadMem(GPRClass, Size, MemLocation, Size); + _StoreContext(2, GPRClass, NewFTW, offsetof(FEXCore::Core::CPUState, FTW)); + } + + OrderedNode *ST0Location = _Add(Mem, _Constant(Size * 7)); + + auto OneConst = _Constant(1); + auto SevenConst = _Constant(7); + auto TenConst = _Constant(10); + + auto low = _Constant(~0ULL); + auto high = _Constant(0xFFFF); + OrderedNode *Mask = _VCastFromGPR(16, 8, low); + Mask = _VInsGPR(16, 8, 1, Mask, high); + + for (int i = 0; i < 7; ++i) { + OrderedNode *Reg = _LoadMem(FPRClass, 16, ST0Location, 1); + // Mask off the top bits + Reg = _VAnd(16, 16, Reg, Mask); + //Convert to double precision + Reg = _F80CVT(8, Reg); + _StoreContextIndexed(Reg, Top, 8, MMBaseOffset(), 16, FPRClass); + + ST0Location = _Add(ST0Location, TenConst); + Top = _And(_Add(Top, OneConst), SevenConst); + } + + // The final st(7) needs a bit of special handling here + // ST7 broken in to two parts + // Lower 64bits [63:0] + // upper 16 bits [79:64] + + OrderedNode *Reg = _LoadMem(FPRClass, 8, ST0Location, 1); + ST0Location = _Add(ST0Location, _Constant(8)); + OrderedNode *RegHigh = _LoadMem(FPRClass, 2, ST0Location, 1); + Reg = _VInsElement(16, 2, 4, 0, Reg, RegHigh); + Reg = _F80CVT(8, Reg); //Convert to double precision + _StoreContextIndexed(Reg, Top, 8, MMBaseOffset(), 16, FPRClass); +} + //FXAM needs change void OpDispatchBuilder::X87FXAMF64(OpcodeArgs) { diff --git a/unittests/ASM/X87_F64/DD_04_2_F64.asm b/unittests/ASM/X87_F64/DD_04_2_F64.asm new file mode 100644 index 000000000..8d5ae1ab8 --- /dev/null +++ b/unittests/ASM/X87_F64/DD_04_2_F64.asm @@ -0,0 +1,87 @@ +%ifdef CONFIG +{ + "RegData": { + "XMM1": ["0x8000000000000000", "0x4005"], + "XMM2": ["0x8000000000000000", "0x4004"], + "XMM3": ["0x8000000000000000", "0x4003"], + "XMM4": ["0x8000000000000000", "0x4002"], + "XMM5": ["0x8000000000000000", "0x4001"], + "XMM6": ["0x8000000000000000", "0x4000"] + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +; We don't test XMM0 or the MM* registers due to precision + +mov rdx, 0xe0000000 + +mov rax, 2 +mov [rdx + 2 * 1], rax +mov rax, 4 +mov [rdx + 2 * 2], rax +mov rax, 8 +mov [rdx + 2 * 3], rax +mov rax, 16 +mov [rdx + 2 * 4], rax +mov rax, 32 +mov [rdx + 2 * 5], rax +mov rax, 64 +mov [rdx + 2 * 6], rax + +fldz +fild word [rdx + 2 * 1] +fild word [rdx + 2 * 2] +fild word [rdx + 2 * 3] +fild word [rdx + 2 * 4] +fild word [rdx + 2 * 5] +fild word [rdx + 2 * 6] +fldpi + +o16 fnsave [rdx] + +fldpi +fldpi +fldpi +fldpi +fldpi +fldpi +fldpi +fldpi + +o16 frstor [rdx] + +movups xmm0, [rdx + (0xE + 10 * 0)] +movups xmm1, [rdx + (0xE + 10 * 1)] +movups xmm2, [rdx + (0xE + 10 * 2)] +movups xmm3, [rdx + (0xE + 10 * 3)] +movups xmm4, [rdx + (0xE + 10 * 4)] +movups xmm5, [rdx + (0xE + 10 * 5)] +movups xmm6, [rdx + (0xE + 10 * 6)] +movups xmm7, [rdx + (0xE + 10 * 7)] + +pslldq xmm0, 6 +psrldq xmm0, 6 + +pslldq xmm1, 6 +psrldq xmm1, 6 + +pslldq xmm2, 6 +psrldq xmm2, 6 + +pslldq xmm3, 6 +psrldq xmm3, 6 + +pslldq xmm4, 6 +psrldq xmm4, 6 + +pslldq xmm5, 6 +psrldq xmm5, 6 + +pslldq xmm6, 6 +psrldq xmm6, 6 + +pslldq xmm7, 6 +psrldq xmm7, 6 + +hlt diff --git a/unittests/ASM/X87_F64/DD_04_F64.asm b/unittests/ASM/X87_F64/DD_04_F64.asm new file mode 100644 index 000000000..ccd19bb50 --- /dev/null +++ b/unittests/ASM/X87_F64/DD_04_F64.asm @@ -0,0 +1,88 @@ +%ifdef CONFIG +{ + "RegData": { + "XMM1": ["0x8000000000000000", "0x4005"], + "XMM2": ["0x8000000000000000", "0x4004"], + "XMM3": ["0x8000000000000000", "0x4003"], + "XMM4": ["0x8000000000000000", "0x4002"], + "XMM5": ["0x8000000000000000", "0x4001"], + "XMM6": ["0x8000000000000000", "0x4000"], + "XMM7": ["0x0000000000000000", "0x0000"] + }, + "Env": { "FEX_X87REDUCEDPRECISION" : "1" } +} +%endif + +; We don't test XMM0 or the MM* registers due to precision + +mov rdx, 0xe0000000 + +mov rax, 2 +mov [rdx + 2 * 1], rax +mov rax, 4 +mov [rdx + 2 * 2], rax +mov rax, 8 +mov [rdx + 2 * 3], rax +mov rax, 16 +mov [rdx + 2 * 4], rax +mov rax, 32 +mov [rdx + 2 * 5], rax +mov rax, 64 +mov [rdx + 2 * 6], rax + +fldz +fild word [rdx + 2 * 1] +fild word [rdx + 2 * 2] +fild word [rdx + 2 * 3] +fild word [rdx + 2 * 4] +fild word [rdx + 2 * 5] +fild word [rdx + 2 * 6] +fldpi + +o32 fnsave [rdx] + +fldpi +fldpi +fldpi +fldpi +fldpi +fldpi +fldpi +fldpi + +o32 frstor [rdx] + +movups xmm0, [rdx + (0x1C + 10 * 0)] +movups xmm1, [rdx + (0x1C + 10 * 1)] +movups xmm2, [rdx + (0x1C + 10 * 2)] +movups xmm3, [rdx + (0x1C + 10 * 3)] +movups xmm4, [rdx + (0x1C + 10 * 4)] +movups xmm5, [rdx + (0x1C + 10 * 5)] +movups xmm6, [rdx + (0x1C + 10 * 6)] +movups xmm7, [rdx + (0x1C + 10 * 7)] + +pslldq xmm0, 6 +psrldq xmm0, 6 + +pslldq xmm1, 6 +psrldq xmm1, 6 + +pslldq xmm2, 6 +psrldq xmm2, 6 + +pslldq xmm3, 6 +psrldq xmm3, 6 + +pslldq xmm4, 6 +psrldq xmm4, 6 + +pslldq xmm5, 6 +psrldq xmm5, 6 + +pslldq xmm6, 6 +psrldq xmm6, 6 + +pslldq xmm7, 6 +psrldq xmm7, 6 + +hlt From 843fe378db7a122ead79065fac7a2975d2d11385 Mon Sep 17 00:00:00 2001 From: CallumDev Date: Fri, 22 Apr 2022 01:38:18 +0930 Subject: [PATCH 15/15] Document that X87ReducedPrecision reduces accuracy --- External/FEXCore/Source/Interface/Config/Config.json.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/External/FEXCore/Source/Interface/Config/Config.json.in b/External/FEXCore/Source/Interface/Config/Config.json.in index a9ab3446a..6f67c9bc8 100644 --- a/External/FEXCore/Source/Interface/Config/Config.json.in +++ b/External/FEXCore/Source/Interface/Config/Config.json.in @@ -245,7 +245,7 @@ "Type": "bool", "Default": "false", "Desc": [ - "Emulates X87 floating point using 64-bit precision" + "Emulates X87 floating point using 64-bit precision. This reduces emulation accuracy and may result in rendering bugs." ] }, "ABILocalFlags": {