mirror of
https://github.com/FEX-Emu/FEX.git
synced 2026-10-24 10:00:45 +02:00
Merge pull request #3547 from pmatos/wip_x87_stack
x87 Stack Optimization
This commit is contained in:
29 files changed
+71972
-119891
No files matched your search
@@ -143,6 +143,7 @@ set (SRCS
|
||||
Interface/IR/Passes/RedundantFlagCalculationElimination.cpp
|
||||
Interface/IR/Passes/DeadStoreElimination.cpp
|
||||
Interface/IR/Passes/RegisterAllocationPass.cpp
|
||||
Interface/IR/Passes/x87StackOptimizationPass.cpp
|
||||
Utils/Telemetry.cpp
|
||||
Utils/Threads.cpp
|
||||
Utils/Profiler.cpp
|
||||
|
||||
@@ -10,6 +10,7 @@ $end_info$
|
||||
#include "Interface/Context/Context.h"
|
||||
#include "Interface/Core/OpcodeDispatcher.h"
|
||||
#include "Interface/Core/X86Tables/X86Tables.h"
|
||||
#include "Interface/IR/IR.h"
|
||||
#include "Interface/IR/IREmitter.h"
|
||||
|
||||
#include <FEXCore/Config/Config.h>
|
||||
@@ -6236,9 +6237,9 @@ void InstallOpcodeHandlers(Context::OperatingMode Mode) {
|
||||
|
||||
// 1 = Invalid
|
||||
|
||||
{OPDReg(0xD9, 2) | 0x00, 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FSTF64WithWidth, 32>},
|
||||
{OPDReg(0xD9, 2) | 0x00, 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FSTF64, 32>},
|
||||
|
||||
{OPDReg(0xD9, 3) | 0x00, 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FSTF64WithWidth, 32>},
|
||||
{OPDReg(0xD9, 3) | 0x00, 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FSTF64, 32>},
|
||||
|
||||
{OPDReg(0xD9, 4) | 0x00, 8, &OpDispatchBuilder::X87LDENVF64},
|
||||
|
||||
@@ -6248,16 +6249,16 @@ void InstallOpcodeHandlers(Context::OperatingMode Mode) {
|
||||
|
||||
{OPDReg(0xD9, 7) | 0x00, 8, &OpDispatchBuilder::X87FSTCW},
|
||||
|
||||
{OPD(0xD9, 0xC0), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FLDF64, 80>},
|
||||
{OPD(0xD9, 0xC0), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FLDFromStack>},
|
||||
{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},
|
||||
{OPD(0xD9, 0xE0), 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::X87OpHelper, OP_F80STACKCHANGESIGN, false>},
|
||||
{OPD(0xD9, 0xE1), 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::X87OpHelper, OP_F80STACKABS, false>},
|
||||
// E2 = Invalid
|
||||
{OPD(0xD9, 0xE4), 1, &OpDispatchBuilder::FTSTF64},
|
||||
{OPD(0xD9, 0xE5), 1, &OpDispatchBuilder::X87FXAMF64},
|
||||
{OPD(0xD9, 0xE5), 1, &OpDispatchBuilder::X87FXAM},
|
||||
// E6 = Invalid
|
||||
{OPD(0xD9, 0xE8), 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FLDF64_Const, 0x3FF0000000000000>}, // 1.0
|
||||
{OPD(0xD9, 0xE9), 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FLDF64_Const, 0x400A934F0979A372>}, // log2l(10)
|
||||
@@ -6268,22 +6269,22 @@ void InstallOpcodeHandlers(Context::OperatingMode Mode) {
|
||||
{OPD(0xD9, 0xEE), 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FLDF64_Const, 0>}, // 0.0
|
||||
|
||||
// EF = Invalid
|
||||
{OPD(0xD9, 0xF0), 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::X87UnaryOpF64, IR::OP_F64F2XM1>},
|
||||
{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::Bind<&OpDispatchBuilder::X87BinaryOpF64, IR::OP_F64FPREM1>},
|
||||
{OPD(0xD9, 0xF0), 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::X87OpHelper, OP_F80F2XM1STACK, false>},
|
||||
{OPD(0xD9, 0xF1), 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::X87FYL2X, false>},
|
||||
{OPD(0xD9, 0xF2), 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::X87OpHelper, OP_F80PTANSTACK, true>},
|
||||
{OPD(0xD9, 0xF3), 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::X87OpHelper, OP_F80ATANSTACK, false>},
|
||||
{OPD(0xD9, 0xF4), 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::X87OpHelper, OP_F80XTRACTSTACK, false>},
|
||||
{OPD(0xD9, 0xF5), 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::X87OpHelper, OP_F80FPREM1STACK, true>},
|
||||
{OPD(0xD9, 0xF6), 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::X87ModifySTP, false>},
|
||||
{OPD(0xD9, 0xF7), 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::X87ModifySTP, true>},
|
||||
{OPD(0xD9, 0xF8), 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::X87BinaryOpF64, IR::OP_F64FPREM>},
|
||||
{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::Bind<&OpDispatchBuilder::X87BinaryOpF64, IR::OP_F64SCALE>},
|
||||
{OPD(0xD9, 0xFE), 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::X87UnaryOpF64, IR::OP_F64SIN>},
|
||||
{OPD(0xD9, 0xFF), 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::X87UnaryOpF64, IR::OP_F64COS>},
|
||||
{OPD(0xD9, 0xF8), 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::X87OpHelper, OP_F80FPREMSTACK, true>},
|
||||
{OPD(0xD9, 0xF9), 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::X87FYL2X, true>},
|
||||
{OPD(0xD9, 0xFA), 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::X87OpHelper, OP_F80SQRTSTACK, false>},
|
||||
{OPD(0xD9, 0xFB), 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::X87OpHelper, OP_F80SINCOSSTACK, true>},
|
||||
{OPD(0xD9, 0xFC), 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::X87OpHelper, OP_F80ROUNDSTACK, false>},
|
||||
{OPD(0xD9, 0xFD), 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::X87OpHelper, OP_F80SCALESTACK, false>},
|
||||
{OPD(0xD9, 0xFE), 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::X87OpHelper, OP_F80SINSTACK, true>},
|
||||
{OPD(0xD9, 0xFF), 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::X87OpHelper, OP_F80COSSTACK, true>},
|
||||
|
||||
{OPDReg(0xDA, 0) | 0x00, 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FADDF64, 32, true, OpDispatchBuilder::OpResult::RES_ST0>},
|
||||
|
||||
@@ -6326,7 +6327,7 @@ void InstallOpcodeHandlers(Context::OperatingMode Mode) {
|
||||
|
||||
// 6 = Invalid
|
||||
|
||||
{OPDReg(0xDB, 7) | 0x00, 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FSTF64WithWidth, 80>},
|
||||
{OPDReg(0xDB, 7) | 0x00, 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FSTF64, 80>},
|
||||
|
||||
|
||||
{OPD(0xDB, 0xC0), 8, &OpDispatchBuilder::X87FCMOV},
|
||||
@@ -6360,18 +6361,18 @@ void InstallOpcodeHandlers(Context::OperatingMode Mode) {
|
||||
|
||||
{OPD(0xDC, 0xC0), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FADDF64, 80, false, OpDispatchBuilder::OpResult::RES_STI>},
|
||||
{OPD(0xDC, 0xC8), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FMULF64, 80, false, OpDispatchBuilder::OpResult::RES_STI>},
|
||||
{OPD(0xDC, 0xE0), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FSUBF64, 80, false, false, OpDispatchBuilder::OpResult::RES_STI>},
|
||||
{OPD(0xDC, 0xE8), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FSUBF64, 80, false, true, OpDispatchBuilder::OpResult::RES_STI>},
|
||||
{OPD(0xDC, 0xF0), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FDIVF64, 80, false, false, OpDispatchBuilder::OpResult::RES_STI>},
|
||||
{OPD(0xDC, 0xF8), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FDIVF64, 80, false, true, OpDispatchBuilder::OpResult::RES_STI>},
|
||||
{OPD(0xDC, 0xE0), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FSUBF64, 80, false, true, OpDispatchBuilder::OpResult::RES_STI>},
|
||||
{OPD(0xDC, 0xE8), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FSUBF64, 80, false, false, OpDispatchBuilder::OpResult::RES_STI>},
|
||||
{OPD(0xDC, 0xF0), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FDIVF64, 80, false, true, OpDispatchBuilder::OpResult::RES_STI>},
|
||||
{OPD(0xDC, 0xF8), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FDIVF64, 80, false, false, OpDispatchBuilder::OpResult::RES_STI>},
|
||||
|
||||
{OPDReg(0xDD, 0) | 0x00, 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FLDF64, 64>},
|
||||
|
||||
{OPDReg(0xDD, 1) | 0x00, 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FISTF64, true>},
|
||||
|
||||
{OPDReg(0xDD, 2) | 0x00, 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FSTF64WithWidth, 64>},
|
||||
{OPDReg(0xDD, 2) | 0x00, 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FSTF64, 64>},
|
||||
|
||||
{OPDReg(0xDD, 3) | 0x00, 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FSTF64WithWidth, 64>},
|
||||
{OPDReg(0xDD, 3) | 0x00, 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FSTF64, 64>},
|
||||
|
||||
{OPDReg(0xDD, 4) | 0x00, 8, &OpDispatchBuilder::X87FRSTORF64},
|
||||
|
||||
@@ -6381,8 +6382,8 @@ void InstallOpcodeHandlers(Context::OperatingMode Mode) {
|
||||
{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, 0xD0), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FSTToStack>}, // register-register from regular X87
|
||||
{OPD(0xDD, 0xD8), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FSTToStack>}, //^
|
||||
|
||||
{OPD(0xDD, 0xE0), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FCOMIF64, 80, false, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, false>},
|
||||
{OPD(0xDD, 0xE8), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FCOMIF64, 80, false, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, false>},
|
||||
@@ -6406,10 +6407,10 @@ void InstallOpcodeHandlers(Context::OperatingMode Mode) {
|
||||
{OPD(0xDE, 0xC0), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FADDF64, 80, false, OpDispatchBuilder::OpResult::RES_STI>},
|
||||
{OPD(0xDE, 0xC8), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FMULF64, 80, false, OpDispatchBuilder::OpResult::RES_STI>},
|
||||
{OPD(0xDE, 0xD9), 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FCOMIF64, 80, false, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, true>},
|
||||
{OPD(0xDE, 0xE0), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FSUBF64, 80, false, false, OpDispatchBuilder::OpResult::RES_STI>},
|
||||
{OPD(0xDE, 0xE8), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FSUBF64, 80, false, true, OpDispatchBuilder::OpResult::RES_STI>},
|
||||
{OPD(0xDE, 0xF0), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FDIVF64, 80, false, false, OpDispatchBuilder::OpResult::RES_STI>},
|
||||
{OPD(0xDE, 0xF8), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FDIVF64, 80, false, true, OpDispatchBuilder::OpResult::RES_STI>},
|
||||
{OPD(0xDE, 0xE0), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FSUBF64, 80, false, true, OpDispatchBuilder::OpResult::RES_STI>},
|
||||
{OPD(0xDE, 0xE8), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FSUBF64, 80, false, false, OpDispatchBuilder::OpResult::RES_STI>},
|
||||
{OPD(0xDE, 0xF0), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FDIVF64, 80, false, true, OpDispatchBuilder::OpResult::RES_STI>},
|
||||
{OPD(0xDE, 0xF8), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FDIVF64, 80, false, false, OpDispatchBuilder::OpResult::RES_STI>},
|
||||
|
||||
{OPDReg(0xDF, 0) | 0x00, 8, &OpDispatchBuilder::FILDF64},
|
||||
|
||||
@@ -6466,9 +6467,9 @@ void InstallOpcodeHandlers(Context::OperatingMode Mode) {
|
||||
|
||||
// 1 = Invalid
|
||||
|
||||
{OPDReg(0xD9, 2) | 0x00, 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FSTWithWidth, 32>},
|
||||
{OPDReg(0xD9, 2) | 0x00, 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FST, 32>},
|
||||
|
||||
{OPDReg(0xD9, 3) | 0x00, 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FSTWithWidth, 32>},
|
||||
{OPDReg(0xD9, 3) | 0x00, 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FST, 32>},
|
||||
|
||||
{OPDReg(0xD9, 4) | 0x00, 8, &OpDispatchBuilder::X87LDENV},
|
||||
|
||||
@@ -6478,13 +6479,13 @@ void InstallOpcodeHandlers(Context::OperatingMode Mode) {
|
||||
|
||||
{OPDReg(0xD9, 7) | 0x00, 8, &OpDispatchBuilder::X87FSTCW},
|
||||
|
||||
{OPD(0xD9, 0xC0), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FLD, 80>},
|
||||
{OPD(0xD9, 0xC0), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FLDFromStack>},
|
||||
{OPD(0xD9, 0xC8), 8, &OpDispatchBuilder::FXCH},
|
||||
{OPD(0xD9, 0xD0), 1, &OpDispatchBuilder::NOPOp}, // FNOP
|
||||
// D1 = Invalid
|
||||
// D8 = Invalid
|
||||
{OPD(0xD9, 0xE0), 1, &OpDispatchBuilder::FCHS},
|
||||
{OPD(0xD9, 0xE1), 1, &OpDispatchBuilder::FABS},
|
||||
{OPD(0xD9, 0xE0), 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::X87OpHelper, OP_F80STACKCHANGESIGN, false>},
|
||||
{OPD(0xD9, 0xE1), 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::X87OpHelper, OP_F80STACKABS, false>},
|
||||
// E2 = Invalid
|
||||
{OPD(0xD9, 0xE4), 1, &OpDispatchBuilder::FTST},
|
||||
{OPD(0xD9, 0xE5), 1, &OpDispatchBuilder::X87FXAM},
|
||||
@@ -6498,22 +6499,22 @@ void InstallOpcodeHandlers(Context::OperatingMode Mode) {
|
||||
{OPD(0xD9, 0xEE), 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FLD_Const, NamedVectorConstant::NAMED_VECTOR_ZERO>}, // 0.0
|
||||
|
||||
// EF = Invalid
|
||||
{OPD(0xD9, 0xF0), 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::X87UnaryOp, IR::OP_F80F2XM1>},
|
||||
{OPD(0xD9, 0xF1), 1, &OpDispatchBuilder::X87FYL2X},
|
||||
{OPD(0xD9, 0xF2), 1, &OpDispatchBuilder::X87TAN},
|
||||
{OPD(0xD9, 0xF3), 1, &OpDispatchBuilder::X87ATAN},
|
||||
{OPD(0xD9, 0xF4), 1, &OpDispatchBuilder::FXTRACT},
|
||||
{OPD(0xD9, 0xF5), 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::X87BinaryOp, IR::OP_F80FPREM1>},
|
||||
{OPD(0xD9, 0xF0), 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::X87OpHelper, OP_F80F2XM1STACK, false>},
|
||||
{OPD(0xD9, 0xF1), 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::X87FYL2X, false>},
|
||||
{OPD(0xD9, 0xF2), 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::X87OpHelper, OP_F80PTANSTACK, true>},
|
||||
{OPD(0xD9, 0xF3), 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::X87OpHelper, OP_F80ATANSTACK, false>},
|
||||
{OPD(0xD9, 0xF4), 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::X87OpHelper, OP_F80XTRACTSTACK, false>},
|
||||
{OPD(0xD9, 0xF5), 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::X87OpHelper, OP_F80FPREM1STACK, true>},
|
||||
{OPD(0xD9, 0xF6), 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::X87ModifySTP, false>},
|
||||
{OPD(0xD9, 0xF7), 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::X87ModifySTP, true>},
|
||||
{OPD(0xD9, 0xF8), 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::X87BinaryOp, IR::OP_F80FPREM>},
|
||||
{OPD(0xD9, 0xF9), 1, &OpDispatchBuilder::X87FYL2X},
|
||||
{OPD(0xD9, 0xFA), 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::X87UnaryOp, IR::OP_F80SQRT>},
|
||||
{OPD(0xD9, 0xFB), 1, &OpDispatchBuilder::X87SinCos},
|
||||
{OPD(0xD9, 0xFC), 1, &OpDispatchBuilder::FRNDINT},
|
||||
{OPD(0xD9, 0xFD), 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::X87BinaryOp, IR::OP_F80SCALE>},
|
||||
{OPD(0xD9, 0xFE), 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::X87UnaryOp, IR::OP_F80SIN>},
|
||||
{OPD(0xD9, 0xFF), 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::X87UnaryOp, IR::OP_F80COS>},
|
||||
{OPD(0xD9, 0xF8), 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::X87OpHelper, OP_F80FPREMSTACK, true>},
|
||||
{OPD(0xD9, 0xF9), 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::X87FYL2X, true>},
|
||||
{OPD(0xD9, 0xFA), 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::X87OpHelper, OP_F80SQRTSTACK, false>},
|
||||
{OPD(0xD9, 0xFB), 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::X87OpHelper, OP_F80SINCOSSTACK, true>},
|
||||
{OPD(0xD9, 0xFC), 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::X87OpHelper, OP_F80ROUNDSTACK, false>},
|
||||
{OPD(0xD9, 0xFD), 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::X87OpHelper, OP_F80SCALESTACK, false>},
|
||||
{OPD(0xD9, 0xFE), 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::X87OpHelper, OP_F80SINSTACK, true>},
|
||||
{OPD(0xD9, 0xFF), 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::X87OpHelper, OP_F80COSSTACK, true>},
|
||||
|
||||
{OPDReg(0xDA, 0) | 0x00, 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FADD, 32, true, OpDispatchBuilder::OpResult::RES_ST0>},
|
||||
|
||||
@@ -6556,7 +6557,7 @@ void InstallOpcodeHandlers(Context::OperatingMode Mode) {
|
||||
|
||||
// 6 = Invalid
|
||||
|
||||
{OPDReg(0xDB, 7) | 0x00, 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FSTWithWidth, 80>},
|
||||
{OPDReg(0xDB, 7) | 0x00, 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FST, 80>},
|
||||
|
||||
|
||||
{OPD(0xDB, 0xC0), 8, &OpDispatchBuilder::X87FCMOV},
|
||||
@@ -6590,18 +6591,18 @@ void InstallOpcodeHandlers(Context::OperatingMode Mode) {
|
||||
|
||||
{OPD(0xDC, 0xC0), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FADD, 80, false, OpDispatchBuilder::OpResult::RES_STI>},
|
||||
{OPD(0xDC, 0xC8), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FMUL, 80, false, OpDispatchBuilder::OpResult::RES_STI>},
|
||||
{OPD(0xDC, 0xE0), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FSUB, 80, false, false, OpDispatchBuilder::OpResult::RES_STI>},
|
||||
{OPD(0xDC, 0xE8), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FSUB, 80, false, true, OpDispatchBuilder::OpResult::RES_STI>},
|
||||
{OPD(0xDC, 0xF0), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FDIV, 80, false, false, OpDispatchBuilder::OpResult::RES_STI>},
|
||||
{OPD(0xDC, 0xF8), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FDIV, 80, false, true, OpDispatchBuilder::OpResult::RES_STI>},
|
||||
{OPD(0xDC, 0xE0), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FSUB, 80, false, true, OpDispatchBuilder::OpResult::RES_STI>},
|
||||
{OPD(0xDC, 0xE8), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FSUB, 80, false, false, OpDispatchBuilder::OpResult::RES_STI>},
|
||||
{OPD(0xDC, 0xF0), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FDIV, 80, false, true, OpDispatchBuilder::OpResult::RES_STI>},
|
||||
{OPD(0xDC, 0xF8), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FDIV, 80, false, false, OpDispatchBuilder::OpResult::RES_STI>},
|
||||
|
||||
{OPDReg(0xDD, 0) | 0x00, 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FLD, 64>},
|
||||
|
||||
{OPDReg(0xDD, 1) | 0x00, 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FIST, true>},
|
||||
|
||||
{OPDReg(0xDD, 2) | 0x00, 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FSTWithWidth, 64>},
|
||||
{OPDReg(0xDD, 2) | 0x00, 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FST, 64>},
|
||||
|
||||
{OPDReg(0xDD, 3) | 0x00, 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FSTWithWidth, 64>},
|
||||
{OPDReg(0xDD, 3) | 0x00, 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FST, 64>},
|
||||
|
||||
{OPDReg(0xDD, 4) | 0x00, 8, &OpDispatchBuilder::X87FRSTOR},
|
||||
|
||||
@@ -6611,8 +6612,8 @@ void InstallOpcodeHandlers(Context::OperatingMode Mode) {
|
||||
{OPDReg(0xDD, 7) | 0x00, 8, &OpDispatchBuilder::X87FNSTSW},
|
||||
|
||||
{OPD(0xDD, 0xC0), 8, &OpDispatchBuilder::X87FFREE},
|
||||
{OPD(0xDD, 0xD0), 8, &OpDispatchBuilder::FST},
|
||||
{OPD(0xDD, 0xD8), 8, &OpDispatchBuilder::FST},
|
||||
{OPD(0xDD, 0xD0), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FSTToStack>},
|
||||
{OPD(0xDD, 0xD8), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FSTToStack>},
|
||||
|
||||
{OPD(0xDD, 0xE0), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FCOMI, 80, false, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, false>},
|
||||
{OPD(0xDD, 0xE8), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FCOMI, 80, false, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, false>},
|
||||
@@ -6636,10 +6637,10 @@ void InstallOpcodeHandlers(Context::OperatingMode Mode) {
|
||||
{OPD(0xDE, 0xC0), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FADD, 80, false, OpDispatchBuilder::OpResult::RES_STI>},
|
||||
{OPD(0xDE, 0xC8), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FMUL, 80, false, OpDispatchBuilder::OpResult::RES_STI>},
|
||||
{OPD(0xDE, 0xD9), 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FCOMI, 80, false, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, true>},
|
||||
{OPD(0xDE, 0xE0), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FSUB, 80, false, false, OpDispatchBuilder::OpResult::RES_STI>},
|
||||
{OPD(0xDE, 0xE8), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FSUB, 80, false, true, OpDispatchBuilder::OpResult::RES_STI>},
|
||||
{OPD(0xDE, 0xF0), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FDIV, 80, false, false, OpDispatchBuilder::OpResult::RES_STI>},
|
||||
{OPD(0xDE, 0xF8), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FDIV, 80, false, true, OpDispatchBuilder::OpResult::RES_STI>},
|
||||
{OPD(0xDE, 0xE0), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FSUB, 80, false, true, OpDispatchBuilder::OpResult::RES_STI>},
|
||||
{OPD(0xDE, 0xE8), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FSUB, 80, false, false, OpDispatchBuilder::OpResult::RES_STI>},
|
||||
{OPD(0xDE, 0xF0), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FDIV, 80, false, true, OpDispatchBuilder::OpResult::RES_STI>},
|
||||
{OPD(0xDE, 0xF8), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FDIV, 80, false, false, OpDispatchBuilder::OpResult::RES_STI>},
|
||||
|
||||
{OPDReg(0xDF, 0) | 0x00, 8, &OpDispatchBuilder::FILD},
|
||||
|
||||
|
||||
@@ -731,45 +731,42 @@ public:
|
||||
void VZEROOp(OpcodeArgs);
|
||||
|
||||
// X87 Ops
|
||||
Ref ReconstructFSW();
|
||||
Ref ReconstructFSW_Helper(Ref T = nullptr);
|
||||
// Returns new x87 stack top from FSW.
|
||||
Ref ReconstructX87StateFromFSW(Ref FSW);
|
||||
void FLD(OpcodeArgs, size_t width);
|
||||
void FLD_Const(OpcodeArgs, NamedVectorConstant constant);
|
||||
Ref ReconstructX87StateFromFSW_Helper(Ref FSW);
|
||||
void FLD(OpcodeArgs, size_t Width);
|
||||
void FLDFromStack(OpcodeArgs);
|
||||
void FLD_Const(OpcodeArgs, NamedVectorConstant Constant);
|
||||
|
||||
void FBLD(OpcodeArgs);
|
||||
void FBSTP(OpcodeArgs);
|
||||
|
||||
void FILD(OpcodeArgs);
|
||||
|
||||
void FSTWithWidth(OpcodeArgs, size_t width);
|
||||
|
||||
void FST(OpcodeArgs);
|
||||
void FST(OpcodeArgs, size_t Width);
|
||||
void FSTToStack(OpcodeArgs);
|
||||
|
||||
void FIST(OpcodeArgs, bool Truncate);
|
||||
|
||||
// OpResult is used for Stack operations,
|
||||
// describes if the result of the operation is stored in ST(0) or ST(i),
|
||||
// where ST(i) is one of the arguments to the operation.
|
||||
enum class OpResult {
|
||||
RES_ST0,
|
||||
RES_STI,
|
||||
};
|
||||
void FADD(OpcodeArgs, size_t width, bool Integer, OpResult ResInST0);
|
||||
void FMUL(OpcodeArgs, size_t width, bool Integer, OpResult ResInST0);
|
||||
void FDIV(OpcodeArgs, size_t width, bool Integer, bool reverse, OpResult ResInST0);
|
||||
void FSUB(OpcodeArgs, size_t width, bool Integer, bool reverse, OpResult ResInST0);
|
||||
void FCHS(OpcodeArgs);
|
||||
void FABS(OpcodeArgs);
|
||||
|
||||
void X87OpHelper(OpcodeArgs, FEXCore::IR::IROps IROp, bool ZeroC2);
|
||||
void FADD(OpcodeArgs, size_t Width, bool Integer, OpResult ResInST0);
|
||||
void FMUL(OpcodeArgs, size_t Width, bool Integer, OpResult ResInST0);
|
||||
void FDIV(OpcodeArgs, size_t Width, bool Integer, bool Reverse, OpResult ResInST0);
|
||||
void FSUB(OpcodeArgs, size_t Width, bool Integer, bool Reverse, OpResult ResInST0);
|
||||
void FTST(OpcodeArgs);
|
||||
void FRNDINT(OpcodeArgs);
|
||||
void FXTRACT(OpcodeArgs);
|
||||
void FNINIT(OpcodeArgs);
|
||||
|
||||
void X87UnaryOp(OpcodeArgs, FEXCore::IR::IROps IROp);
|
||||
void X87BinaryOp(OpcodeArgs, FEXCore::IR::IROps IROp);
|
||||
void X87ModifySTP(OpcodeArgs, bool Inc);
|
||||
void X87SinCos(OpcodeArgs);
|
||||
void X87FYL2X(OpcodeArgs);
|
||||
void X87TAN(OpcodeArgs);
|
||||
void X87ATAN(OpcodeArgs);
|
||||
void X87FYL2X(OpcodeArgs, bool IsFYL2XP1);
|
||||
void X87LDENV(OpcodeArgs);
|
||||
void X87FLDCW(OpcodeArgs);
|
||||
void X87FNSTENV(OpcodeArgs);
|
||||
@@ -789,27 +786,25 @@ public:
|
||||
FLAGS_X87,
|
||||
FLAGS_RFLAGS,
|
||||
};
|
||||
void FCOMI(OpcodeArgs, size_t width, bool Integer, FCOMIFlags whichflags, bool poptwice);
|
||||
void FCOMI(OpcodeArgs, size_t Width, bool Integer, FCOMIFlags WhichFlags, bool PopTwice);
|
||||
|
||||
// F64 X87 Ops
|
||||
void FLDF64(OpcodeArgs, size_t width);
|
||||
void FLDF64_Const(OpcodeArgs, uint64_t num);
|
||||
void FLDF64(OpcodeArgs, size_t Width);
|
||||
void FLDF64_Const(OpcodeArgs, uint64_t Num);
|
||||
|
||||
void FBLDF64(OpcodeArgs);
|
||||
void FBSTPF64(OpcodeArgs);
|
||||
|
||||
void FILDF64(OpcodeArgs);
|
||||
|
||||
void FSTF64WithWidth(OpcodeArgs, size_t width);
|
||||
|
||||
void FSTF64(OpcodeArgs);
|
||||
void FSTF64(OpcodeArgs, size_t Width);
|
||||
|
||||
void FISTF64(OpcodeArgs, bool Truncate);
|
||||
|
||||
void FADDF64(OpcodeArgs, size_t width, bool Integer, OpResult ResInST0);
|
||||
void FMULF64(OpcodeArgs, size_t width, bool Integer, OpResult ResInST0);
|
||||
void FDIVF64(OpcodeArgs, size_t width, bool Integer, bool reverse, OpResult ResInST0);
|
||||
void FSUBF64(OpcodeArgs, size_t width, bool Integer, bool reverse, OpResult ResInST0);
|
||||
void FADDF64(OpcodeArgs, size_t Width, bool Integer, OpResult ResInST0);
|
||||
void FMULF64(OpcodeArgs, size_t Width, bool Integer, OpResult ResInST0);
|
||||
void FDIVF64(OpcodeArgs, size_t Width, bool Integer, bool Reverse, OpResult ResInST0);
|
||||
void FSUBF64(OpcodeArgs, size_t Width, bool Integer, bool Reverse, OpResult ResInST0);
|
||||
void FCHSF64(OpcodeArgs);
|
||||
void FABSF64(OpcodeArgs);
|
||||
void FTSTF64(OpcodeArgs);
|
||||
@@ -821,7 +816,6 @@ public:
|
||||
void X87BinaryOpF64(OpcodeArgs, FEXCore::IR::IROps IROp);
|
||||
void X87SinCosF64(OpcodeArgs);
|
||||
void X87FLDCWF64(OpcodeArgs);
|
||||
void X87FYL2XF64(OpcodeArgs);
|
||||
void X87TANF64(OpcodeArgs);
|
||||
void X87ATANF64(OpcodeArgs);
|
||||
void X87FNSAVEF64(OpcodeArgs);
|
||||
@@ -1323,6 +1317,8 @@ protected:
|
||||
}
|
||||
|
||||
private:
|
||||
FEX_CONFIG_OPT(ReducedPrecisionMode, X87REDUCEDPRECISION);
|
||||
|
||||
struct JumpTargetInfo {
|
||||
Ref BlockEntry;
|
||||
bool HaveEmitted;
|
||||
@@ -1962,7 +1958,11 @@ private:
|
||||
// First, set flags according to Arm FCMP.
|
||||
HandleNZCVWrite();
|
||||
_FCmp(ElementSize, Src1, Src2);
|
||||
ComissFlags(InvalidateAF);
|
||||
}
|
||||
|
||||
// Sets flags for a COMISS instruction
|
||||
void ComissFlags(bool InvalidateAF = false) {
|
||||
// Now set COMISS flags by converts NZCV from the Arm representation to an
|
||||
// eXternal representation that's totally not a euphemism for x86, nuh-uh.
|
||||
if (CTX->HostFeatures.SupportsFlagM2) {
|
||||
@@ -2262,12 +2262,9 @@ private:
|
||||
/** @} */
|
||||
|
||||
Ref GetX87Top();
|
||||
void SetX87ValidTag(Ref Value, bool Valid);
|
||||
Ref GetX87ValidTag(Ref Value);
|
||||
Ref GetX87Tag(Ref Value, Ref AbridgedFTW);
|
||||
Ref GetX87Tag(Ref Value);
|
||||
void SetX87FTW(Ref FTW);
|
||||
Ref GetX87FTW();
|
||||
Ref GetX87FTW_Helper();
|
||||
void SetX87Top(Ref Value);
|
||||
|
||||
bool DestIsLockedMem(FEXCore::X86Tables::DecodedOp Op) const {
|
||||
|
||||
@@ -2688,7 +2688,7 @@ void OpDispatchBuilder::SaveX87State(OpcodeArgs, Ref MemBase) {
|
||||
_StoreMem(GPRClass, 2, MemBase, FCW, 2);
|
||||
}
|
||||
|
||||
{ _StoreMem(GPRClass, 2, ReconstructFSW(), MemBase, _Constant(2), 2, MEM_OFFSET_SXTX, 1); }
|
||||
{ _StoreMem(GPRClass, 2, ReconstructFSW_Helper(), MemBase, _Constant(2), 2, MEM_OFFSET_SXTX, 1); }
|
||||
|
||||
{
|
||||
// Abridged FTW
|
||||
@@ -2863,7 +2863,7 @@ void OpDispatchBuilder::RestoreX87State(Ref MemBase) {
|
||||
|
||||
{
|
||||
auto NewFSW = _LoadMem(GPRClass, 2, MemBase, _Constant(2), 2, MEM_OFFSET_SXTX, 1);
|
||||
ReconstructX87StateFromFSW(NewFSW);
|
||||
ReconstructX87StateFromFSW_Helper(NewFSW);
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -40,10 +40,13 @@ class OrderedNode;
|
||||
// FXCH
|
||||
// FCMOV
|
||||
// FST(register to register)
|
||||
// FCHS
|
||||
|
||||
// State loading duplicated from X87.cpp, setting host rounding mode
|
||||
// See issue
|
||||
void OpDispatchBuilder::FNINITF64(OpcodeArgs) {
|
||||
// FIXME: almost a duplicate of x87 version.
|
||||
|
||||
// Init FCW to 0x037F
|
||||
auto NewFCW = _Constant(16, 0x037F);
|
||||
// Init host rounding mode to zero
|
||||
@@ -53,17 +56,20 @@ void OpDispatchBuilder::FNINITF64(OpcodeArgs) {
|
||||
|
||||
// Init FSW to 0
|
||||
SetX87Top(Zero);
|
||||
// Tags all get marked as invalid
|
||||
StoreContext(AbridgedFTWIndex, Zero);
|
||||
|
||||
_InitStack();
|
||||
|
||||
SetRFLAG<FEXCore::X86State::X87FLAG_C0_LOC>(Zero);
|
||||
SetRFLAG<FEXCore::X86State::X87FLAG_C1_LOC>(Zero);
|
||||
SetRFLAG<FEXCore::X86State::X87FLAG_C2_LOC>(Zero);
|
||||
SetRFLAG<FEXCore::X86State::X87FLAG_C3_LOC>(Zero);
|
||||
|
||||
// Tags all get marked as invalid
|
||||
StoreContext(AbridgedFTWIndex, Zero);
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::X87LDENVF64(OpcodeArgs) {
|
||||
_StackForceSlow();
|
||||
|
||||
const auto Size = GetSrcSize(Op);
|
||||
Ref Mem = MakeSegmentAddress(Op, Op->Src[0]);
|
||||
|
||||
@@ -75,7 +81,7 @@ void OpDispatchBuilder::X87LDENVF64(OpcodeArgs) {
|
||||
_StoreContext(2, GPRClass, NewFCW, offsetof(FEXCore::Core::CPUState, FCW));
|
||||
|
||||
auto NewFSW = _LoadMem(GPRClass, Size, Mem, _Constant(Size * 1), Size, MEM_OFFSET_SXTX, 1);
|
||||
ReconstructX87StateFromFSW(NewFSW);
|
||||
ReconstructX87StateFromFSW_Helper(NewFSW);
|
||||
|
||||
{
|
||||
// FTW
|
||||
@@ -85,6 +91,8 @@ void OpDispatchBuilder::X87LDENVF64(OpcodeArgs) {
|
||||
|
||||
|
||||
void OpDispatchBuilder::X87FLDCWF64(OpcodeArgs) {
|
||||
_StackForceSlow();
|
||||
|
||||
Ref NewFCW = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags);
|
||||
// ignore the rounding precision, we're always 64-bit in F64.
|
||||
// extract rounding mode
|
||||
@@ -94,132 +102,65 @@ void OpDispatchBuilder::X87FLDCWF64(OpcodeArgs) {
|
||||
}
|
||||
|
||||
// F64 ops
|
||||
|
||||
void OpDispatchBuilder::FLDF64(OpcodeArgs, size_t width) {
|
||||
// Update TOP
|
||||
auto orig_top = GetX87Top();
|
||||
auto mask = _Constant(7);
|
||||
|
||||
size_t read_width = (width == 80) ? 16 : width / 8;
|
||||
|
||||
Ref data {};
|
||||
Ref converted {};
|
||||
|
||||
if (!Op->Src[0].IsNone()) {
|
||||
// Read from memory
|
||||
data = LoadSource_WithOpSize(FPRClass, Op, Op->Src[0], read_width, Op->Flags);
|
||||
// Convert to 64bit float
|
||||
if (width == 32) {
|
||||
converted = _Float_FToF(8, 4, data);
|
||||
} else if (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(OpSize::i32Bit, _Add(OpSize::i32Bit, orig_top, offset), mask);
|
||||
data = _LoadContextIndexed(data, 8, MMBaseOffset(), 16, FPRClass);
|
||||
converted = data;
|
||||
// Float load op with memory operand
|
||||
void OpDispatchBuilder::FLDF64(OpcodeArgs, size_t Width) {
|
||||
size_t ReadWidth = (Width == 80) ? 16 : Width / 8;
|
||||
Ref Data = LoadSource_WithOpSize(FPRClass, Op, Op->Src[0], ReadWidth, Op->Flags);
|
||||
// Convert to 64bit float
|
||||
Ref ConvertedData = Data;
|
||||
if (Width == 32) {
|
||||
ConvertedData = _Float_FToF(8, 4, Data);
|
||||
} else if (Width == 80) {
|
||||
ConvertedData = _F80CVT(8, Data);
|
||||
}
|
||||
|
||||
auto top = _And(OpSize::i32Bit, _Sub(OpSize::i32Bit, orig_top, _Constant(1)), mask);
|
||||
SetX87ValidTag(top, true);
|
||||
SetX87Top(top);
|
||||
// Write to ST[TOP]
|
||||
_StoreContextIndexed(converted, top, 8, MMBaseOffset(), 16, FPRClass);
|
||||
_PushStack(ConvertedData, Data, ReadWidth, true);
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::FBLDF64(OpcodeArgs) {
|
||||
// Update TOP
|
||||
auto orig_top = GetX87Top();
|
||||
auto mask = _Constant(7);
|
||||
auto top = _And(OpSize::i32Bit, _Sub(OpSize::i32Bit, orig_top, _Constant(1)), mask);
|
||||
SetX87ValidTag(top, true);
|
||||
SetX87Top(top);
|
||||
|
||||
// Read from memory
|
||||
Ref data = LoadSource_WithOpSize(FPRClass, Op, Op->Src[0], 16, Op->Flags);
|
||||
Ref converted = _F80BCDLoad(data);
|
||||
converted = _F80CVT(8, converted);
|
||||
_StoreContextIndexed(converted, top, 8, MMBaseOffset(), 16, FPRClass);
|
||||
Ref Data = LoadSource_WithOpSize(FPRClass, Op, Op->Src[0], 16, Op->Flags);
|
||||
Ref ConvertedData = _F80BCDLoad(Data);
|
||||
ConvertedData = _F80CVT(8, ConvertedData);
|
||||
_PushStack(ConvertedData, Data, 8, true);
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::FBSTPF64(OpcodeArgs) {
|
||||
auto orig_top = GetX87Top();
|
||||
auto data = _LoadContextIndexed(orig_top, 8, MMBaseOffset(), 16, FPRClass);
|
||||
|
||||
Ref converted = _F80CVTTo(data, 8);
|
||||
Ref converted = _F80CVTTo(_ReadStackValue(0), 8);
|
||||
converted = _F80BCDStore(converted);
|
||||
|
||||
StoreResult_WithOpSize(FPRClass, Op, Op->Dest, converted, 10, 1);
|
||||
|
||||
// if we are popping then we must first mark this location as empty
|
||||
SetX87ValidTag(orig_top, false);
|
||||
auto top = _And(OpSize::i32Bit, _Add(OpSize::i32Bit, orig_top, _Constant(1)), _Constant(7));
|
||||
SetX87Top(top);
|
||||
_PopStackDestroy();
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::FLDF64_Const(OpcodeArgs, uint64_t num) {
|
||||
// Update TOP
|
||||
auto orig_top = GetX87Top();
|
||||
auto top = _And(OpSize::i32Bit, _Sub(OpSize::i32Bit, orig_top, _Constant(1)), _Constant(7));
|
||||
SetX87ValidTag(top, true);
|
||||
SetX87Top(top);
|
||||
auto data = _VCastFromGPR(8, 8, _Constant(num));
|
||||
// Write to ST[TOP]
|
||||
_StoreContextIndexed(data, top, 8, MMBaseOffset(), 16, FPRClass);
|
||||
void OpDispatchBuilder::FLDF64_Const(OpcodeArgs, uint64_t Num) {
|
||||
auto Data = _VCastFromGPR(8, 8, _Constant(Num));
|
||||
_PushStack(Data, Data, 8, true);
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::FILDF64(OpcodeArgs) {
|
||||
// Update TOP
|
||||
auto orig_top = GetX87Top();
|
||||
auto top = _And(OpSize::i32Bit, _Sub(OpSize::i32Bit, orig_top, _Constant(1)), _Constant(7));
|
||||
SetX87ValidTag(top, true);
|
||||
SetX87Top(top);
|
||||
size_t ReadWidth = GetSrcSize(Op);
|
||||
|
||||
size_t read_width = GetSrcSize(Op);
|
||||
// Read from memory
|
||||
auto data = LoadSource_WithOpSize(GPRClass, Op, Op->Src[0], read_width, Op->Flags);
|
||||
if (read_width == 2) {
|
||||
data = _Sbfe(OpSize::i64Bit, read_width * 8, 0, data);
|
||||
Ref Data = LoadSource_WithOpSize(GPRClass, Op, Op->Src[0], ReadWidth, Op->Flags);
|
||||
if (ReadWidth == 2) {
|
||||
Data = _Sbfe(OpSize::i64Bit, ReadWidth * 8, 0, Data);
|
||||
}
|
||||
auto converted = _Float_FromGPR_S(8, read_width == 4 ? 4 : 8, data);
|
||||
// Write to ST[TOP]
|
||||
_StoreContextIndexed(converted, top, 8, MMBaseOffset(), 16, FPRClass);
|
||||
auto ConvertedData = _Float_FromGPR_S(8, ReadWidth == 4 ? 4 : 8, Data);
|
||||
_PushStack(ConvertedData, Data, ReadWidth, false);
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::FSTF64WithWidth(OpcodeArgs, size_t width) {
|
||||
auto orig_top = GetX87Top();
|
||||
auto data = _LoadContextIndexed(orig_top, 8, MMBaseOffset(), 16, FPRClass);
|
||||
if (width == 64) {
|
||||
// Store 64-bit float directly
|
||||
StoreResult_WithOpSize(FPRClass, Op, Op->Dest, data, 8, 1);
|
||||
} else if (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 (width == 80) {
|
||||
// Convert to 80-bit float
|
||||
auto result = _F80CVTTo(data, 8);
|
||||
StoreResult_WithOpSize(FPRClass, Op, Op->Dest, result, 10, 1);
|
||||
}
|
||||
void OpDispatchBuilder::FSTF64(OpcodeArgs, size_t Width) {
|
||||
Ref Mem = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, {.LoadData = false});
|
||||
_StoreStackMemory(Mem, OpSize::i64Bit, true, Width / 8);
|
||||
|
||||
if ((Op->TableInfo->Flags & X86Tables::InstFlags::FLAGS_POP) != 0) {
|
||||
// if we are popping then we must first mark this location as empty
|
||||
SetX87ValidTag(orig_top, false);
|
||||
// Set the new top now
|
||||
auto top = _And(OpSize::i32Bit, _Add(OpSize::i32Bit, orig_top, _Constant(1)), _Constant(7));
|
||||
SetX87Top(top);
|
||||
if (Op->TableInfo->Flags & X86Tables::InstFlags::FLAGS_POP) {
|
||||
_PopStackDestroy();
|
||||
}
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::FISTF64(OpcodeArgs, bool Truncate) {
|
||||
auto Size = GetSrcSize(Op);
|
||||
|
||||
auto orig_top = GetX87Top();
|
||||
Ref data = _LoadContextIndexed(orig_top, 8, MMBaseOffset(), 16, FPRClass);
|
||||
Ref data = _ReadStackValue(0);
|
||||
if (Truncate) {
|
||||
data = _Float_ToGPR_ZS(Size == 4 ? 4 : 8, 8, data);
|
||||
} else {
|
||||
@@ -228,468 +169,255 @@ void OpDispatchBuilder::FISTF64(OpcodeArgs, bool Truncate) {
|
||||
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
|
||||
SetX87ValidTag(orig_top, false);
|
||||
// Set the new top now
|
||||
auto top = _And(OpSize::i32Bit, _Add(OpSize::i32Bit, orig_top, _Constant(1)), _Constant(7));
|
||||
SetX87Top(top);
|
||||
_PopStackDestroy();
|
||||
}
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::FADDF64(OpcodeArgs, size_t width, bool Integer, OpDispatchBuilder::OpResult ResInST0) {
|
||||
auto top = GetX87Top();
|
||||
Ref StackLocation = top;
|
||||
void OpDispatchBuilder::FADDF64(OpcodeArgs, size_t Width, bool Integer, OpDispatchBuilder::OpResult ResInST0) {
|
||||
if (Op->Src[0].IsNone()) { // Implicit argument case
|
||||
auto Offset = Op->OP & 7;
|
||||
auto St0 = 0;
|
||||
if (ResInST0 == OpResult::RES_STI) {
|
||||
_F80AddStack(Offset, St0);
|
||||
} else {
|
||||
_F80AddStack(St0, Offset);
|
||||
}
|
||||
if (Op->TableInfo->Flags & X86Tables::InstFlags::FLAGS_POP) {
|
||||
_PopStackDestroy();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// We have one memory argument
|
||||
Ref arg {};
|
||||
Ref b {};
|
||||
|
||||
auto mask = _Constant(7);
|
||||
if (Integer) {
|
||||
arg = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags);
|
||||
if (Width == 16) {
|
||||
arg = _Sbfe(OpSize::i64Bit, 16, 0, arg);
|
||||
}
|
||||
arg = _Float_FromGPR_S(8, Width == 64 ? 8 : 4, arg);
|
||||
} else if (Width == 32) {
|
||||
arg = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags);
|
||||
arg = _Float_FToF(8, 4, arg);
|
||||
} else if (Width == 64) {
|
||||
arg = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags);
|
||||
}
|
||||
|
||||
if (!Op->Src[0].IsNone()) {
|
||||
// Memory arg
|
||||
// top of stack is at offset zero
|
||||
_F80AddValue(0, arg);
|
||||
}
|
||||
|
||||
// FIXME: following is very similar to FADDF64
|
||||
void OpDispatchBuilder::FMULF64(OpcodeArgs, size_t Width, bool Integer, OpDispatchBuilder::OpResult ResInST0) {
|
||||
if (Op->Src[0].IsNone()) { // Implicit argument case
|
||||
auto offset = Op->OP & 7;
|
||||
auto st0 = 0;
|
||||
if (ResInST0 == OpResult::RES_STI) {
|
||||
_F80MulStack(offset, st0);
|
||||
} else {
|
||||
_F80MulStack(st0, offset);
|
||||
}
|
||||
if (Op->TableInfo->Flags & X86Tables::InstFlags::FLAGS_POP) {
|
||||
_PopStackDestroy();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// We have one memory argument
|
||||
Ref arg {};
|
||||
|
||||
if (Integer) {
|
||||
arg = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags);
|
||||
if (Width == 16) {
|
||||
arg = _Sbfe(OpSize::i64Bit, 16, 0, arg);
|
||||
}
|
||||
arg = _Float_FromGPR_S(8, Width == 64 ? 8 : 4, arg);
|
||||
} else if (Width == 32) {
|
||||
arg = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags);
|
||||
arg = _Float_FToF(8, 4, arg);
|
||||
} else if (Width == 64) {
|
||||
arg = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags);
|
||||
}
|
||||
|
||||
// top of stack is at offset zero
|
||||
_F80MulValue(0, arg);
|
||||
|
||||
if (Op->TableInfo->Flags & X86Tables::InstFlags::FLAGS_POP) {
|
||||
_PopStackDestroy();
|
||||
}
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::FDIVF64(OpcodeArgs, size_t Width, bool Integer, bool Reverse, OpDispatchBuilder::OpResult ResInST0) {
|
||||
if (Op->Src[0].IsNone()) {
|
||||
const auto offset = Op->OP & 7;
|
||||
const auto st0 = 0;
|
||||
|
||||
if (Reverse) {
|
||||
if (ResInST0 == OpResult::RES_STI) {
|
||||
_F80DivStack(offset, st0, offset);
|
||||
} else {
|
||||
_F80DivStack(st0, offset, st0);
|
||||
}
|
||||
} else {
|
||||
if (ResInST0 == OpResult::RES_STI) {
|
||||
_F80DivStack(offset, offset, st0);
|
||||
} else {
|
||||
_F80DivStack(st0, st0, offset);
|
||||
}
|
||||
}
|
||||
|
||||
if (Op->TableInfo->Flags & X86Tables::InstFlags::FLAGS_POP) {
|
||||
_PopStackDestroy();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// We have one memory argument
|
||||
Ref Arg {};
|
||||
|
||||
if (Width == 16 || Width == 32 || Width == 64) {
|
||||
if (Integer) {
|
||||
Arg = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags);
|
||||
if (Width == 16) {
|
||||
Arg = _Sbfe(OpSize::i64Bit, 16, 0, Arg);
|
||||
}
|
||||
Arg = _Float_FromGPR_S(8, Width == 64 ? 8 : 4, Arg);
|
||||
} else if (Width == 32) {
|
||||
Arg = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags);
|
||||
Arg = _Float_FToF(8, 4, Arg);
|
||||
} else if (Width == 64) {
|
||||
Arg = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags);
|
||||
}
|
||||
}
|
||||
|
||||
// top of stack is at offset zero
|
||||
if (Reverse) {
|
||||
_F80DivRValue(Arg, 0);
|
||||
} else {
|
||||
_F80DivValue(0, Arg);
|
||||
}
|
||||
|
||||
if (Op->TableInfo->Flags & X86Tables::InstFlags::FLAGS_POP) {
|
||||
_PopStackDestroy();
|
||||
}
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::FSUBF64(OpcodeArgs, size_t Width, bool Integer, bool Reverse, OpDispatchBuilder::OpResult ResInST0) {
|
||||
if (Op->Src[0].IsNone()) {
|
||||
const auto Offset = Op->OP & 7;
|
||||
const auto St0 = 0;
|
||||
|
||||
if (Reverse) {
|
||||
if (ResInST0 == OpResult::RES_STI) {
|
||||
_F80SubStack(Offset, St0, Offset);
|
||||
} else {
|
||||
_F80SubStack(St0, Offset, St0);
|
||||
}
|
||||
} else {
|
||||
if (ResInST0 == OpResult::RES_STI) {
|
||||
_F80SubStack(Offset, Offset, St0);
|
||||
} else {
|
||||
_F80SubStack(St0, St0, Offset);
|
||||
}
|
||||
}
|
||||
|
||||
if (Op->TableInfo->Flags & X86Tables::InstFlags::FLAGS_POP) {
|
||||
_PopStackDestroy();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// We have one memory argument
|
||||
Ref arg {};
|
||||
|
||||
if (Width == 16 || Width == 32 || Width == 64) {
|
||||
if (Integer) {
|
||||
arg = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags);
|
||||
if (width == 16) {
|
||||
if (Width == 16) {
|
||||
arg = _Sbfe(OpSize::i64Bit, 16, 0, arg);
|
||||
}
|
||||
b = _Float_FromGPR_S(8, width == 64 ? 8 : 4, arg);
|
||||
} else if (width == 32) {
|
||||
arg = _Float_FromGPR_S(8, Width == 64 ? 8 : 4, arg);
|
||||
} else if (Width == 32) {
|
||||
arg = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags);
|
||||
b = _Float_FToF(8, 4, arg);
|
||||
} else if (width == 64) {
|
||||
b = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags);
|
||||
}
|
||||
} else {
|
||||
// Implicit arg
|
||||
auto offset = _Constant(Op->OP & 7);
|
||||
arg = _And(OpSize::i32Bit, _Add(OpSize::i32Bit, top, offset), mask);
|
||||
if (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
|
||||
SetX87ValidTag(top, false);
|
||||
// Set the new top now
|
||||
top = _And(OpSize::i32Bit, _Add(OpSize::i32Bit, top, _Constant(1)), mask);
|
||||
SetX87Top(top);
|
||||
}
|
||||
|
||||
// Write to ST[TOP]
|
||||
_StoreContextIndexed(result, StackLocation, 8, MMBaseOffset(), 16, FPRClass);
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::FMULF64(OpcodeArgs, size_t width, bool Integer, OpDispatchBuilder::OpResult ResInST0) {
|
||||
auto top = GetX87Top();
|
||||
Ref StackLocation = top;
|
||||
Ref arg {};
|
||||
Ref b {};
|
||||
|
||||
auto mask = _Constant(7);
|
||||
|
||||
if (!Op->Src[0].IsNone()) {
|
||||
// Memory arg
|
||||
if (Integer) {
|
||||
arg = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags);
|
||||
if (width == 16) {
|
||||
arg = _Sbfe(OpSize::i64Bit, 16, 0, arg);
|
||||
}
|
||||
b = _Float_FromGPR_S(8, width == 64 ? 8 : 4, arg);
|
||||
} else if (width == 32) {
|
||||
arg = _Float_FToF(8, 4, arg);
|
||||
} else if (Width == 64) {
|
||||
arg = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags);
|
||||
b = _Float_FToF(8, 4, arg);
|
||||
} else if (width == 64) {
|
||||
b = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags);
|
||||
}
|
||||
}
|
||||
|
||||
// top of stack is at offset zero
|
||||
if (Reverse) {
|
||||
_F80SubRValue(arg, 0);
|
||||
} else {
|
||||
// Implicit arg
|
||||
auto offset = _Constant(Op->OP & 7);
|
||||
arg = _And(OpSize::i32Bit, _Add(OpSize::i32Bit, top, offset), mask);
|
||||
if (ResInST0 == OpResult::RES_STI) {
|
||||
StackLocation = arg;
|
||||
}
|
||||
|
||||
b = _LoadContextIndexed(arg, 8, MMBaseOffset(), 16, FPRClass);
|
||||
_F80SubValue(0, arg);
|
||||
}
|
||||
|
||||
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
|
||||
SetX87ValidTag(top, false);
|
||||
// Set the new top now
|
||||
top = _And(OpSize::i32Bit, _Add(OpSize::i32Bit, top, _Constant(1)), mask);
|
||||
SetX87Top(top);
|
||||
if (Op->TableInfo->Flags & X86Tables::InstFlags::FLAGS_POP) {
|
||||
_PopStackDestroy();
|
||||
}
|
||||
|
||||
// Write to ST[TOP]
|
||||
_StoreContextIndexed(result, StackLocation, 8, MMBaseOffset(), 16, FPRClass);
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::FDIVF64(OpcodeArgs, size_t width, bool Integer, bool reverse, OpDispatchBuilder::OpResult ResInST0) {
|
||||
auto top = GetX87Top();
|
||||
Ref StackLocation = top;
|
||||
Ref arg {};
|
||||
Ref b {};
|
||||
|
||||
auto mask = _Constant(7);
|
||||
|
||||
if (!Op->Src[0].IsNone()) {
|
||||
// Memory arg
|
||||
if (Integer) {
|
||||
arg = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags);
|
||||
if (width == 16) {
|
||||
arg = _Sbfe(OpSize::i64Bit, 16, 0, arg);
|
||||
}
|
||||
b = _Float_FromGPR_S(8, width == 64 ? 8 : 4, arg);
|
||||
} else if (width == 32) {
|
||||
arg = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags);
|
||||
b = _Float_FToF(8, 4, arg);
|
||||
} else if (width == 64) {
|
||||
b = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags);
|
||||
}
|
||||
} else {
|
||||
// Implicit arg
|
||||
auto offset = _Constant(Op->OP & 7);
|
||||
arg = _And(OpSize::i32Bit, _Add(OpSize::i32Bit, top, offset), mask);
|
||||
if (ResInST0 == OpResult::RES_STI) {
|
||||
StackLocation = arg;
|
||||
}
|
||||
|
||||
b = _LoadContextIndexed(arg, 8, MMBaseOffset(), 16, FPRClass);
|
||||
}
|
||||
|
||||
auto a = _LoadContextIndexed(top, 8, MMBaseOffset(), 16, FPRClass);
|
||||
|
||||
Ref result {};
|
||||
if (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
|
||||
SetX87ValidTag(top, false);
|
||||
// Set the new top now
|
||||
top = _And(OpSize::i32Bit, _Add(OpSize::i32Bit, top, _Constant(1)), mask);
|
||||
SetX87Top(top);
|
||||
}
|
||||
|
||||
// Write to ST[TOP]
|
||||
_StoreContextIndexed(result, StackLocation, 8, MMBaseOffset(), 16, FPRClass);
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::FSUBF64(OpcodeArgs, size_t width, bool Integer, bool reverse, OpDispatchBuilder::OpResult ResInST0) {
|
||||
auto top = GetX87Top();
|
||||
Ref StackLocation = top;
|
||||
Ref arg {};
|
||||
Ref b {};
|
||||
|
||||
auto mask = _Constant(7);
|
||||
|
||||
if (!Op->Src[0].IsNone()) {
|
||||
// Memory arg
|
||||
if (Integer) {
|
||||
arg = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags);
|
||||
if (width == 16) {
|
||||
arg = _Sbfe(OpSize::i64Bit, 16, 0, arg);
|
||||
}
|
||||
b = _Float_FromGPR_S(8, width == 64 ? 8 : 4, arg);
|
||||
} else if (width == 32) {
|
||||
arg = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags);
|
||||
b = _Float_FToF(8, 4, arg);
|
||||
} else if (width == 64) {
|
||||
b = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags);
|
||||
}
|
||||
} else {
|
||||
// Implicit arg
|
||||
auto offset = _Constant(Op->OP & 7);
|
||||
arg = _And(OpSize::i32Bit, _Add(OpSize::i32Bit, top, offset), mask);
|
||||
if (ResInST0 == OpResult::RES_STI) {
|
||||
StackLocation = arg;
|
||||
}
|
||||
|
||||
b = _LoadContextIndexed(arg, 8, MMBaseOffset(), 16, FPRClass);
|
||||
}
|
||||
|
||||
auto a = _LoadContextIndexed(top, 8, MMBaseOffset(), 16, FPRClass);
|
||||
|
||||
Ref result {};
|
||||
if (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
|
||||
SetX87ValidTag(top, false);
|
||||
// Set the new top now
|
||||
|
||||
top = _And(OpSize::i32Bit, _Add(OpSize::i32Bit, top, _Constant(1)), mask);
|
||||
SetX87Top(top);
|
||||
}
|
||||
|
||||
// Write to ST[TOP]
|
||||
_StoreContextIndexed(result, StackLocation, 8, MMBaseOffset(), 16, FPRClass);
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::FCHSF64(OpcodeArgs) {
|
||||
auto top = GetX87Top();
|
||||
auto a = _LoadContextIndexed(top, 8, MMBaseOffset(), 16, FPRClass);
|
||||
auto result = _VFNeg(8, 8, a);
|
||||
// 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 result = _VFAbs(8, 8, a);
|
||||
// Write to ST[TOP]
|
||||
_StoreContextIndexed(result, top, 8, MMBaseOffset(), 16, FPRClass);
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::FTSTF64(OpcodeArgs) {
|
||||
auto top = GetX87Top();
|
||||
auto a = _LoadContextIndexed(top, 8, MMBaseOffset(), 16, FPRClass);
|
||||
|
||||
auto low = _Constant(0);
|
||||
Ref data = _VCastFromGPR(8, 8, low);
|
||||
|
||||
// We are going to clobber NZCV, make sure it's in a GPR first.
|
||||
GetNZCV();
|
||||
|
||||
// Now we do our comparison.
|
||||
_FCmp(8, a, data);
|
||||
_F80StackTest(0);
|
||||
PossiblySetNZCVBits = ~0;
|
||||
ConvertNZCVToX87();
|
||||
}
|
||||
|
||||
// TODO: This should obey rounding mode
|
||||
void OpDispatchBuilder::FRNDINTF64(OpcodeArgs) {
|
||||
auto top = GetX87Top();
|
||||
auto a = _LoadContextIndexed(top, 8, MMBaseOffset(), 16, FPRClass);
|
||||
|
||||
auto result = _Vector_FToI(8, 8, a, FEXCore::IR::Round_Host);
|
||||
|
||||
// Write to ST[TOP]
|
||||
_StoreContextIndexed(result, top, 8, MMBaseOffset(), 16, FPRClass);
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::FXTRACTF64(OpcodeArgs) {
|
||||
auto orig_top = GetX87Top();
|
||||
auto top = _And(OpSize::i32Bit, _Sub(OpSize::i32Bit, orig_top, _Constant(1)), _Constant(7));
|
||||
SetX87ValidTag(top, true);
|
||||
SetX87Top(top);
|
||||
|
||||
auto a = _LoadContextIndexed(orig_top, 8, MMBaseOffset(), 16, FPRClass);
|
||||
auto gpr = _VExtractToGPR(8, 8, a, 0);
|
||||
Ref exp = _And(OpSize::i64Bit, gpr, _Constant(0x7ff0000000000000LL));
|
||||
exp = _Lshr(OpSize::i64Bit, exp, _Constant(52));
|
||||
exp = _Sub(OpSize::i64Bit, exp, _Constant(1023));
|
||||
exp = _Float_FromGPR_S(8, 8, exp);
|
||||
Ref sig = _And(OpSize::i64Bit, gpr, _Constant(0x800fffffffffffffLL));
|
||||
sig = _Or(OpSize::i64Bit, 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);
|
||||
}
|
||||
|
||||
|
||||
void OpDispatchBuilder::FCOMIF64(OpcodeArgs, size_t width, bool Integer, OpDispatchBuilder::FCOMIFlags whichflags, bool poptwice) {
|
||||
auto top = GetX87Top();
|
||||
auto mask = _Constant(7);
|
||||
|
||||
void OpDispatchBuilder::FCOMIF64(OpcodeArgs, size_t Width, bool Integer, OpDispatchBuilder::FCOMIFlags WhichFlags, bool PopTwice) {
|
||||
Ref arg {};
|
||||
Ref b {};
|
||||
|
||||
if (!Op->Src[0].IsNone()) {
|
||||
// Memory arg
|
||||
if (Integer) {
|
||||
arg = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags);
|
||||
if (width == 16) {
|
||||
arg = _Sbfe(OpSize::i64Bit, 16, 0, arg);
|
||||
}
|
||||
b = _Float_FromGPR_S(8, width == 64 ? 8 : 4, arg);
|
||||
} else if (width == 32) {
|
||||
arg = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags);
|
||||
b = _Float_FToF(8, 4, arg);
|
||||
} else if (width == 64) {
|
||||
b = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags);
|
||||
}
|
||||
} else {
|
||||
if (Op->Src[0].IsNone()) {
|
||||
// Implicit arg
|
||||
auto offset = _Constant(Op->OP & 7);
|
||||
arg = _And(OpSize::i32Bit, _Add(OpSize::i32Bit, top, offset), mask);
|
||||
b = _LoadContextIndexed(arg, 8, MMBaseOffset(), 16, FPRClass);
|
||||
uint8_t offset = Op->OP & 7;
|
||||
b = _ReadStackValue(offset);
|
||||
} else {
|
||||
// Memory arg
|
||||
if (Width == 16 || Width == 32 || Width == 64) {
|
||||
if (Integer) {
|
||||
arg = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags);
|
||||
if (Width == 16) {
|
||||
arg = _Sbfe(OpSize::i64Bit, 16, 0, arg);
|
||||
}
|
||||
b = _Float_FromGPR_S(8, Width == 64 ? 8 : 4, arg);
|
||||
} else if (Width == 32) {
|
||||
arg = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags);
|
||||
b = _Float_FToF(8, 4, arg);
|
||||
} else if (Width == 64) {
|
||||
b = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto a = _LoadContextIndexed(top, 8, MMBaseOffset(), 16, FPRClass);
|
||||
|
||||
if (whichflags == FCOMIFlags::FLAGS_X87) {
|
||||
if (WhichFlags == FCOMIFlags::FLAGS_X87) {
|
||||
// We are going to clobber NZCV, make sure it's in a GPR first.
|
||||
GetNZCV();
|
||||
|
||||
_FCmp(8, a, b);
|
||||
_F80CmpValue(b);
|
||||
PossiblySetNZCVBits = ~0;
|
||||
ConvertNZCVToX87();
|
||||
} else {
|
||||
Comiss(8, a, b, true /* InvalidateAF */);
|
||||
HandleNZCVWrite();
|
||||
_F80CmpValue(b);
|
||||
ComissFlags(true /* InvalidateAF */);
|
||||
}
|
||||
|
||||
if (poptwice) {
|
||||
// if we are popping then we must first mark this location as empty
|
||||
SetX87ValidTag(top, false);
|
||||
top = _And(OpSize::i32Bit, _Add(OpSize::i32Bit, top, _Constant(1)), mask);
|
||||
SetX87ValidTag(top, false);
|
||||
// Set the new top now
|
||||
top = _And(OpSize::i32Bit, _Add(OpSize::i32Bit, top, _Constant(1)), mask);
|
||||
SetX87Top(top);
|
||||
if (PopTwice) {
|
||||
_PopStackDestroy();
|
||||
_PopStackDestroy();
|
||||
} else if ((Op->TableInfo->Flags & X86Tables::InstFlags::FLAGS_POP) != 0) {
|
||||
// if we are popping then we must first mark this location as empty
|
||||
SetX87ValidTag(top, false);
|
||||
// Set the new top now
|
||||
top = _And(OpSize::i32Bit, _Add(OpSize::i32Bit, top, _Constant(1)), mask);
|
||||
SetX87Top(top);
|
||||
_PopStackDestroy();
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
void OpDispatchBuilder::X87UnaryOpF64(OpcodeArgs, FEXCore::IR::IROps IROp) {
|
||||
auto top = GetX87Top();
|
||||
auto a = _LoadContextIndexed(top, 8, MMBaseOffset(), 16, FPRClass);
|
||||
|
||||
DeriveOp(result, IROp, _F64SIN(a));
|
||||
|
||||
if (IROp == IR::OP_F64SIN || IROp == IR::OP_F64COS) {
|
||||
// TODO: ACCURACY: should check source is in range –2^63 to +2^63
|
||||
SetRFLAG<FEXCore::X86State::X87FLAG_C2_LOC>(_Constant(0));
|
||||
}
|
||||
|
||||
// Write to ST[TOP]
|
||||
_StoreContextIndexed(result, top, 8, MMBaseOffset(), 16, FPRClass);
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::X87BinaryOpF64(OpcodeArgs, FEXCore::IR::IROps IROp) {
|
||||
auto top = GetX87Top();
|
||||
|
||||
auto mask = _Constant(7);
|
||||
Ref st1 = _And(OpSize::i32Bit, _Add(OpSize::i32Bit, top, _Constant(1)), mask);
|
||||
|
||||
auto a = _LoadContextIndexed(top, 8, MMBaseOffset(), 16, FPRClass);
|
||||
st1 = _LoadContextIndexed(st1, 8, MMBaseOffset(), 16, FPRClass);
|
||||
|
||||
DeriveOp(result, IROp, _F64ATAN(a, st1));
|
||||
|
||||
if (IROp == IR::OP_F64FPREM || IROp == IR::OP_F64FPREM1) {
|
||||
// TODO: Set C0 to Q2, C3 to Q1, C1 to Q0
|
||||
SetRFLAG<FEXCore::X86State::X87FLAG_C2_LOC>(_Constant(0));
|
||||
}
|
||||
|
||||
// Write to ST[TOP]
|
||||
_StoreContextIndexed(result, top, 8, MMBaseOffset(), 16, FPRClass);
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::X87SinCosF64(OpcodeArgs) {
|
||||
auto orig_top = GetX87Top();
|
||||
auto top = _And(OpSize::i32Bit, _Sub(OpSize::i32Bit, orig_top, _Constant(1)), _Constant(7));
|
||||
SetX87ValidTag(top, true);
|
||||
SetX87Top(top);
|
||||
|
||||
auto a = _LoadContextIndexed(orig_top, 8, MMBaseOffset(), 16, FPRClass);
|
||||
|
||||
auto sin = _F64SIN(a);
|
||||
auto cos = _F64COS(a);
|
||||
|
||||
// TODO: ACCURACY: should check source is in range –2^63 to +2^63
|
||||
SetRFLAG<FEXCore::X86State::X87FLAG_C2_LOC>(_Constant(0));
|
||||
|
||||
// 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
|
||||
SetX87ValidTag(orig_top, false);
|
||||
auto top = _And(OpSize::i32Bit, _Add(OpSize::i32Bit, orig_top, _Constant(1)), _Constant(7));
|
||||
SetX87Top(top);
|
||||
|
||||
Ref st0 = _LoadContextIndexed(orig_top, 8, MMBaseOffset(), 16, FPRClass);
|
||||
Ref 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(OpSize::i32Bit, _Sub(OpSize::i32Bit, orig_top, _Constant(1)), _Constant(7));
|
||||
SetX87ValidTag(top, true);
|
||||
SetX87Top(top);
|
||||
|
||||
auto a = _LoadContextIndexed(orig_top, 8, MMBaseOffset(), 16, FPRClass);
|
||||
|
||||
auto result = _F64TAN(a);
|
||||
|
||||
auto one = _VCastFromGPR(8, 8, _Constant(0x3FF0000000000000));
|
||||
|
||||
// TODO: ACCURACY: should check source is in range –2^63 to +2^63
|
||||
SetRFLAG<FEXCore::X86State::X87FLAG_C2_LOC>(_Constant(0));
|
||||
|
||||
// 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
|
||||
SetX87ValidTag(orig_top, false);
|
||||
auto top = _And(OpSize::i32Bit, _Add(OpSize::i32Bit, orig_top, _Constant(1)), _Constant(7));
|
||||
SetX87Top(top);
|
||||
|
||||
auto a = _LoadContextIndexed(orig_top, 8, MMBaseOffset(), 16, FPRClass);
|
||||
Ref st1 = _LoadContextIndexed(top, 8, MMBaseOffset(), 16, FPRClass);
|
||||
|
||||
auto result = _F64ATAN(st1, a);
|
||||
|
||||
// Write to ST[TOP]
|
||||
_StoreContextIndexed(result, top, 8, MMBaseOffset(), 16, FPRClass);
|
||||
}
|
||||
|
||||
// This function converts to F80 on save for compatibility
|
||||
|
||||
void OpDispatchBuilder::X87FNSAVEF64(OpcodeArgs) {
|
||||
_SyncStackToSlow();
|
||||
// 14 bytes for 16bit
|
||||
// 2 Bytes : FCW
|
||||
// 2 Bytes : FSW
|
||||
@@ -717,13 +445,13 @@ void OpDispatchBuilder::X87FNSAVEF64(OpcodeArgs) {
|
||||
_StoreMem(GPRClass, Size, Mem, FCW, Size);
|
||||
}
|
||||
|
||||
{ _StoreMem(GPRClass, Size, ReconstructFSW(), Mem, _Constant(Size * 1), Size, MEM_OFFSET_SXTX, 1); }
|
||||
{ _StoreMem(GPRClass, Size, ReconstructFSW_Helper(), Mem, _Constant(Size * 1), Size, MEM_OFFSET_SXTX, 1); }
|
||||
|
||||
auto ZeroConst = _Constant(0);
|
||||
|
||||
{
|
||||
// FTW
|
||||
_StoreMem(GPRClass, Size, GetX87FTW(), Mem, _Constant(Size * 2), Size, MEM_OFFSET_SXTX, 1);
|
||||
_StoreMem(GPRClass, Size, GetX87FTW_Helper(), Mem, _Constant(Size * 2), Size, MEM_OFFSET_SXTX, 1);
|
||||
}
|
||||
|
||||
{
|
||||
@@ -772,6 +500,7 @@ void OpDispatchBuilder::X87FNSAVEF64(OpcodeArgs) {
|
||||
// This function converts from F80 on load for compatibility
|
||||
|
||||
void OpDispatchBuilder::X87FRSTORF64(OpcodeArgs) {
|
||||
_StackForceSlow();
|
||||
const auto Size = GetSrcSize(Op);
|
||||
Ref Mem = MakeSegmentAddress(Op, Op->Src[0]);
|
||||
|
||||
@@ -788,7 +517,7 @@ void OpDispatchBuilder::X87FRSTORF64(OpcodeArgs) {
|
||||
_StoreContext(2, GPRClass, NewFCW, offsetof(FEXCore::Core::CPUState, FCW));
|
||||
|
||||
auto NewFSW = _LoadMem(GPRClass, Size, Mem, _Constant(Size * 1), Size, MEM_OFFSET_SXTX, 1);
|
||||
auto Top = ReconstructX87StateFromFSW(NewFSW);
|
||||
Ref Top = ReconstructX87StateFromFSW_Helper(NewFSW);
|
||||
|
||||
{
|
||||
// FTW
|
||||
@@ -826,32 +555,4 @@ void OpDispatchBuilder::X87FRSTORF64(OpcodeArgs) {
|
||||
_StoreContextIndexed(Reg, Top, 8, MMBaseOffset(), 16, FPRClass);
|
||||
}
|
||||
|
||||
|
||||
// FXAM needs change
|
||||
void OpDispatchBuilder::X87FXAMF64(OpcodeArgs) {
|
||||
auto top = GetX87Top();
|
||||
auto a = _LoadContextIndexed(top, 8, MMBaseOffset(), 16, FPRClass);
|
||||
Ref Result = _VExtractToGPR(8, 8, a, 0);
|
||||
|
||||
// Extract the sign bit
|
||||
Result = _Bfe(OpSize::i64Bit, 1, 63, Result);
|
||||
SetRFLAG<FEXCore::X86State::X87FLAG_C1_LOC>(Result);
|
||||
|
||||
// Claim this is a normal number
|
||||
// We don't support anything else
|
||||
auto TopValid = GetX87ValidTag(top);
|
||||
auto ZeroConst = _Constant(0);
|
||||
auto OneConst = _Constant(1);
|
||||
|
||||
// In the case of top being invalid then C3:C2:C0 is 0b101
|
||||
auto C3 = _Select(FEXCore::IR::COND_EQ, TopValid, OneConst, ZeroConst, OneConst);
|
||||
|
||||
auto C2 = TopValid;
|
||||
auto C0 = C3; // Mirror C3 until something other than zero is supported
|
||||
SetRFLAG<FEXCore::X86State::X87FLAG_C0_LOC>(C0);
|
||||
SetRFLAG<FEXCore::X86State::X87FLAG_C2_LOC>(C2);
|
||||
SetRFLAG<FEXCore::X86State::X87FLAG_C3_LOC>(C3);
|
||||
}
|
||||
|
||||
|
||||
} // namespace FEXCore::IR
|
||||
@@ -70,6 +70,7 @@ void PassManager::AddDefaultPasses(FEXCore::Context::ContextImpl* ctx) {
|
||||
FEX_CONFIG_OPT(DisablePasses, O0);
|
||||
|
||||
if (!DisablePasses()) {
|
||||
InsertPass(CreateX87StackOptimizationPass());
|
||||
InsertPass(CreateDeadStoreElimination());
|
||||
InsertPass(CreateConstProp(ctx->HostFeatures.SupportsTSOImm9, &ctx->CPUID));
|
||||
InsertPass(CreateDeadFlagCalculationEliminination());
|
||||
|
||||
@@ -20,6 +20,7 @@ fextl::unique_ptr<FEXCore::IR::Pass> CreateConstProp(bool SupportsTSOImm9, const
|
||||
fextl::unique_ptr<FEXCore::IR::Pass> CreateDeadFlagCalculationEliminination();
|
||||
fextl::unique_ptr<FEXCore::IR::Pass> CreateDeadStoreElimination();
|
||||
fextl::unique_ptr<FEXCore::IR::RegisterAllocationPass> CreateRegisterAllocationPass();
|
||||
fextl::unique_ptr<FEXCore::IR::Pass> CreateX87StackOptimizationPass();
|
||||
|
||||
namespace Validation {
|
||||
fextl::unique_ptr<FEXCore::IR::Pass> CreateIRValidation();
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -5,7 +5,7 @@ See [FEXCore/Readme.md](../FEXCore/Readme.md) for more details
|
||||
|
||||
### Glossary
|
||||
|
||||
- Splatter: a code generator backend that concaternates configurable macros instead of doing isel
|
||||
- Splatter: a code generator backend that concatenates configurable macros instead of doing isel
|
||||
- IR: Intermediate Representation, our high-level opcode representation, loosely modeling arm64
|
||||
- SSA: Single Static Assignment, a form of representing IR in memory
|
||||
- Basic Block: A block of instructions with no control flow, terminated by control flow
|
||||
@@ -115,6 +115,7 @@ IR to IR Optimization
|
||||
- [RedundantFlagCalculationElimination.cpp](../FEXCore/Source/Interface/IR/Passes/RedundantFlagCalculationElimination.cpp): This is not used right now, possibly broken
|
||||
- [RegisterAllocationPass.cpp](../FEXCore/Source/Interface/IR/Passes/RegisterAllocationPass.cpp)
|
||||
- [RegisterAllocationPass.h](../FEXCore/Source/Interface/IR/Passes/RegisterAllocationPass.h)
|
||||
- [x87StackOptimizationPass.cpp](../FEXCore/Source/Interface/IR/Passes/x87StackOptimizationPass.cpp): x87 stack optimization pass
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
Test_X87/FXAM_Simple.asm
|
||||
@@ -11,7 +11,7 @@ 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
|
||||
; Empty in this case is that C0 and C3 is set while C2 is not
|
||||
|
||||
fninit
|
||||
; Fill the x87 stack
|
||||
|
||||
@@ -11,7 +11,7 @@ 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
|
||||
; Empty in this case is that C0 and C3 is set while C2 is not
|
||||
|
||||
fninit
|
||||
; Empty stack to make sure we don't push anything
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
%ifdef CONFIG
|
||||
{
|
||||
"RegData": {
|
||||
"RAX": "8"
|
||||
}
|
||||
}
|
||||
%endif
|
||||
|
||||
fninit
|
||||
fld1
|
||||
fld1
|
||||
fld1
|
||||
fld1
|
||||
fld1
|
||||
fld1
|
||||
fld1
|
||||
fld1
|
||||
|
||||
mov ebx, 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 st0
|
||||
fwait
|
||||
inc ebx
|
||||
jmp .ExamineStack
|
||||
.Done:
|
||||
mov eax, ebx
|
||||
hlt
|
||||
@@ -0,0 +1,51 @@
|
||||
%ifdef CONFIG
|
||||
{
|
||||
"RegData": {
|
||||
"RAX": "8"
|
||||
}
|
||||
}
|
||||
%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 while 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
|
||||
hlt
|
||||
@@ -0,0 +1,49 @@
|
||||
;; Simpler versions of FXAM_Push* tests.
|
||||
;; In hostrunner tests this will fail because we mentioned below there's no support
|
||||
;; for the zero flag. In hostrunner RCX should contain 0x4000 instead of 0x400.
|
||||
%ifdef CONFIG
|
||||
{
|
||||
"RegData": {
|
||||
"RAX": "0x6",
|
||||
"RBX": "0x0400",
|
||||
"RCX": "0x0400",
|
||||
"RDX": "0x4100"
|
||||
}
|
||||
}
|
||||
%endif
|
||||
|
||||
mov rdx, 0xe0000000
|
||||
|
||||
fninit
|
||||
;; Before adding anything to the stack, lets examine it.
|
||||
;; The result should be empty.
|
||||
fxam
|
||||
fwait
|
||||
|
||||
fnstsw ax
|
||||
and ax, 0x4500 ; should be 0x4100 for zero
|
||||
mov edx, eax
|
||||
|
||||
fldz
|
||||
fxam
|
||||
fwait
|
||||
|
||||
fnstsw ax
|
||||
and ax, 0x4500 ; should be 0x4000 for zero, but there's no support for it at the moment, so it'll return 0x0400 as it does for a normal number.
|
||||
mov ecx, eax
|
||||
|
||||
fld1
|
||||
fxam
|
||||
fwait
|
||||
|
||||
fnstsw ax
|
||||
mov ebx, eax
|
||||
and ebx, 0x4500 ; should be 0x0400 for normal
|
||||
|
||||
;; Top should be 6
|
||||
;; right shift status word by 11 and and with 0x7.
|
||||
shr eax, 11
|
||||
and eax, 0x7
|
||||
|
||||
|
||||
hlt
|
||||
@@ -0,0 +1,21 @@
|
||||
%ifdef CONFIG
|
||||
{
|
||||
"RegData": {
|
||||
"RAX": "0x3ff8000000000000",
|
||||
"RBX": "0x3ff8000000000000"
|
||||
},
|
||||
"MemoryRegions": {
|
||||
"0x100000000": "4096"
|
||||
}
|
||||
}
|
||||
%endif
|
||||
|
||||
mov rdx, 0x100000000
|
||||
mov rax, 0x3ff8000000000000 ; 1.5
|
||||
mov [rdx], rax
|
||||
|
||||
fld qword [rdx]
|
||||
fstp qword [rdx + 8]
|
||||
|
||||
mov rbx, [rdx + 8]
|
||||
hlt
|
||||
@@ -0,0 +1,26 @@
|
||||
%ifdef CONFIG
|
||||
{
|
||||
"RegData": {
|
||||
"RAX": "0x4142434445464748",
|
||||
"RBX": "0"
|
||||
}
|
||||
}
|
||||
%endif
|
||||
|
||||
lea rax, [rel .data]
|
||||
lea rbx, [rel .data_mov]
|
||||
|
||||
fld qword [rax]
|
||||
fstp qword [rbx]
|
||||
|
||||
mov rax, [rbx]
|
||||
mov rbx, [rbx + 8]
|
||||
hlt
|
||||
|
||||
.data:
|
||||
dq 0x4142434445464748
|
||||
dq 0x5152535455565758
|
||||
|
||||
.data_mov:
|
||||
dq 0
|
||||
dq 0
|
||||
@@ -0,0 +1,2 @@
|
||||
## Unable to support zero flag
|
||||
FXAM_Simple.asm
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
+2324
-2946
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
+2324
-2946
File diff suppressed because it is too large.
Load diff
+1605
-1814
File diff suppressed because it is too large.
Load diff
@@ -1,5 +1,4 @@
|
||||
pr72867.c.gcc-target-test-32
|
||||
pr88240.c.gcc-target-test-32
|
||||
sse2-mmx-pextrw.c.gcc-target-test-32
|
||||
|
||||
# Consistently crashes on Solidrun only in CI
|
||||
|
||||
@@ -13,15 +13,6 @@ asm-5.c.gcc-target-test-64
|
||||
# This causes its comparison to fail
|
||||
sse2-mmx-pextrw.c.gcc-target-test-64
|
||||
|
||||
# Fails even on host device
|
||||
# Stores a large 64bit value in to a union of double and 'unsigned long long'
|
||||
# 'test' loads this value in to a x87 register, then stores that value on to the stack
|
||||
# Checks the flag and skips a bunch of x87 logic, and loads that value back from the stack in to rax
|
||||
# Value has been munged from the fld + fstp step
|
||||
# 0xFFF279535D540FE4 was the original value
|
||||
# 0xFFFA79535D540FE4 was the value it turned in to
|
||||
pr88240.c.gcc-target-test-64
|
||||
|
||||
# These tests fail because of things unrelated to the sse4.1 instructions
|
||||
sse4_1-ceil-sfix-vec.c.gcc-target-test-64
|
||||
sse4_1-ceilf-sfix-vec.c.gcc-target-test-64
|
||||
|
||||
Reference in new issue
Block a user