diff --git a/FEXCore/Source/Interface/Core/OpcodeDispatcher.h b/FEXCore/Source/Interface/Core/OpcodeDispatcher.h index faffcc2b2..a15c18f49 100644 --- a/FEXCore/Source/Interface/Core/OpcodeDispatcher.h +++ b/FEXCore/Source/Interface/Core/OpcodeDispatcher.h @@ -1811,14 +1811,12 @@ private: /** @} */ OrderedNode * GetX87Top(); - enum class X87Tag { - Valid = 0b00, - Zero = 0b01, - Special = 0b10, - Empty = 0b11 - }; - void SetX87TopTag(OrderedNode *Value, X87Tag Tag); - OrderedNode *GetX87FTW(OrderedNode *Value); + void SetX87ValidTag(OrderedNode *Value, bool Valid); + OrderedNode *GetX87ValidTag(OrderedNode *Value); + OrderedNode *GetX87Tag(OrderedNode *Value, OrderedNode *AbridgedFTW); + OrderedNode *GetX87Tag(OrderedNode *Value); + void SetX87FTW(OrderedNode *FTW); + OrderedNode *GetX87FTW(); void SetX87Top(OrderedNode *Value); bool DestIsLockedMem(FEXCore::X86Tables::DecodedOp Op) const { diff --git a/FEXCore/Source/Interface/Core/OpcodeDispatcher/Vector.cpp b/FEXCore/Source/Interface/Core/OpcodeDispatcher/Vector.cpp index ba9221df1..48d44622e 100644 --- a/FEXCore/Source/Interface/Core/OpcodeDispatcher/Vector.cpp +++ b/FEXCore/Source/Interface/Core/OpcodeDispatcher/Vector.cpp @@ -2622,10 +2622,10 @@ void OpDispatchBuilder::SaveX87State(OpcodeArgs, OrderedNode *MemBase) { } { - // FTW + // Abridged FTW OrderedNode *MemLocation = _Add(OpSize, MemBase, _Constant(4)); - auto FTW = _LoadContext(2, GPRClass, offsetof(FEXCore::Core::CPUState, FTW)); - _StoreMem(GPRClass, 2, MemLocation, FTW, 2); + auto AbridgedFTW = _LoadContext(1, GPRClass, offsetof(FEXCore::Core::CPUState, AbridgedFTW)); + _StoreMem(GPRClass, 1, MemLocation, AbridgedFTW, 2); } // BYTE | 0 1 | 2 3 | 4 | 5 | 6 7 | 8 9 | a b | c d | e f | @@ -2826,10 +2826,10 @@ void OpDispatchBuilder::RestoreX87State(OrderedNode *MemBase) { } { - // FTW + // Abridged FTW OrderedNode *MemLocation = _Add(OpSize, MemBase, _Constant(4)); - auto NewFTW = _LoadMem(GPRClass, 2, MemLocation, 2); - _StoreContext(2, GPRClass, NewFTW, offsetof(FEXCore::Core::CPUState, FTW)); + auto NewAbridgedFTW = _LoadMem(GPRClass, 1, MemLocation, 2); + _StoreContext(1, GPRClass, NewAbridgedFTW, offsetof(FEXCore::Core::CPUState, AbridgedFTW)); } for (uint32_t i = 0; i < Core::CPUState::NUM_MMS; ++i) { diff --git a/FEXCore/Source/Interface/Core/OpcodeDispatcher/X87.cpp b/FEXCore/Source/Interface/Core/OpcodeDispatcher/X87.cpp index d19d9da67..054f55332 100644 --- a/FEXCore/Source/Interface/Core/OpcodeDispatcher/X87.cpp +++ b/FEXCore/Source/Interface/Core/OpcodeDispatcher/X87.cpp @@ -12,6 +12,7 @@ $end_info$ #include #include #include +#include #include #include @@ -28,28 +29,59 @@ OrderedNode *OpDispatchBuilder::GetX87Top() { return _LoadContext(1, GPRClass, offsetof(FEXCore::Core::CPUState, flags) + FEXCore::X86State::X87FLAG_TOP_LOC); } -void OpDispatchBuilder::SetX87TopTag(OrderedNode *Value, X87Tag Tag) { +void OpDispatchBuilder::SetX87ValidTag(OrderedNode *Value, bool Valid) { // if we are popping then we must first mark this location as empty - auto FTW = _LoadContext(2, GPRClass, offsetof(FEXCore::Core::CPUState, FTW)); - OrderedNode *Mask = _Constant(0b11); - // TODO: This can all be done with OpSize::i32Bit. - auto TopOffset = _Lshl(IR::SizeToOpSize(std::max(4, GetOpSize(Value))), Value, _Constant(1)); - Mask = _Lshl(OpSize::i64Bit, Mask, TopOffset); - OrderedNode *NewFTW = _Andn(OpSize::i64Bit, FTW, Mask); - if (Tag != X87Tag::Valid) { - auto TagVal = _Lshl(OpSize::i64Bit, _Constant(ToUnderlying(Tag)), TopOffset); - NewFTW = _Or(OpSize::i64Bit, NewFTW, TagVal); - } - - _StoreContext(2, GPRClass, NewFTW, offsetof(FEXCore::Core::CPUState, FTW)); + OrderedNode *AbridgedFTW = _LoadContext(1, GPRClass, offsetof(FEXCore::Core::CPUState, AbridgedFTW)); + OrderedNode *RegMask = _Lshl(OpSize::i32Bit, _Constant(1), Value); + OrderedNode *NewAbridgedFTW = Valid ? _Or(OpSize::i32Bit, AbridgedFTW, RegMask) : _Andn(OpSize::i32Bit, AbridgedFTW, RegMask); + _StoreContext(1, GPRClass, NewAbridgedFTW, offsetof(FEXCore::Core::CPUState, AbridgedFTW)); } -OrderedNode *OpDispatchBuilder::GetX87FTW(OrderedNode *Value) { - auto FTW = _LoadContext(2, GPRClass, offsetof(FEXCore::Core::CPUState, FTW)); - OrderedNode *Mask = _Constant(0b11); - auto TopOffset = _Lshl(OpSize::i32Bit, Value, _Constant(1)); - auto NewFTW = _Lshr(OpSize::i32Bit, FTW, TopOffset); - return _And(OpSize::i64Bit, NewFTW, Mask); +OrderedNode *OpDispatchBuilder::GetX87ValidTag(OrderedNode *Value) { + OrderedNode *AbridgedFTW = _LoadContext(1, GPRClass, offsetof(FEXCore::Core::CPUState, AbridgedFTW)); + return _And(OpSize::i32Bit, _Lshr(OpSize::i32Bit, AbridgedFTW, Value), _Constant(1)); +} + +OrderedNode *OpDispatchBuilder::GetX87Tag(OrderedNode *Value, OrderedNode *AbridgedFTW) { + OrderedNode *RegValid = _And(OpSize::i32Bit, _Lshr(OpSize::i32Bit, AbridgedFTW, Value), _Constant(1)); + OrderedNode *X87Empty = _Constant(static_cast(FPState::X87Tag::Empty)); + OrderedNode *X87Valid = _Constant(static_cast(FPState::X87Tag::Valid)); + + return _Select(FEXCore::IR::COND_EQ, + RegValid, _Constant(0), + X87Empty, X87Valid); +} + +OrderedNode *OpDispatchBuilder::GetX87Tag(OrderedNode *Value) { + OrderedNode *AbridgedFTW = _LoadContext(1, GPRClass, offsetof(FEXCore::Core::CPUState, AbridgedFTW)); + return GetX87Tag(Value, AbridgedFTW); +} + +void OpDispatchBuilder::SetX87FTW(OrderedNode *FTW) { + OrderedNode *X87Empty = _Constant(static_cast(FPState::X87Tag::Empty)); + OrderedNode *NewAbridgedFTW = _Constant(0); + + for (int i = 0; i < 8; i++) { + OrderedNode *RegTag = _And(OpSize::i32Bit, _Lshr(OpSize::i32Bit, FTW, _Constant(i * 2)), _Constant(0b11)); + OrderedNode *RegValid = _Select(FEXCore::IR::COND_EQ, + RegTag, X87Empty, + _Constant(0), _Constant(1)); + NewAbridgedFTW = _Or(OpSize::i32Bit, NewAbridgedFTW, _Lshl(OpSize::i32Bit, RegValid, _Constant(i))); + } + + _StoreContext(1, GPRClass, NewAbridgedFTW, offsetof(FEXCore::Core::CPUState, AbridgedFTW)); +} + +OrderedNode *OpDispatchBuilder::GetX87FTW() { + OrderedNode *AbridgedFTW = _LoadContext(1, GPRClass, offsetof(FEXCore::Core::CPUState, AbridgedFTW)); + OrderedNode *FTW = _Constant(0); + + for (int i = 0; i < 8; i++) { + const auto RegTag = GetX87Tag(_Constant(i), AbridgedFTW); + FTW = _Or(OpSize::i32Bit, FTW, _Lshl(OpSize::i32Bit, RegTag, _Constant(i * 2))); + } + + return FTW; } void OpDispatchBuilder::SetX87Top(OrderedNode *Value) { @@ -119,7 +151,7 @@ void OpDispatchBuilder::FLD(OpcodeArgs) { } auto top = _And(OpSize::i64Bit, _Sub(OpSize::i64Bit, orig_top, _Constant(1)), mask); - SetX87TopTag(top, X87Tag::Valid); + SetX87ValidTag(top, true); SetX87Top(top); // Write to ST[TOP] _StoreContextIndexed(converted, top, 16, MMBaseOffset(), 16, FPRClass); @@ -138,7 +170,7 @@ void OpDispatchBuilder::FBLD(OpcodeArgs) { auto orig_top = GetX87Top(); auto mask = _Constant(7); auto top = _And(OpSize::i64Bit, _Sub(OpSize::i64Bit, orig_top, _Constant(1)), mask); - SetX87TopTag(top, X87Tag::Valid); + SetX87ValidTag(top, true); SetX87Top(top); // Read from memory @@ -156,7 +188,7 @@ void OpDispatchBuilder::FBSTP(OpcodeArgs) { 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); + SetX87ValidTag(orig_top, false); auto top = _And(OpSize::i64Bit, _Add(OpSize::i64Bit, orig_top, _Constant(1)), _Constant(7)); SetX87Top(top); } @@ -166,7 +198,7 @@ void OpDispatchBuilder::FLD_Const(OpcodeArgs) { // Update TOP auto orig_top = GetX87Top(); auto top = _And(OpSize::i64Bit, _Sub(OpSize::i64Bit, orig_top, _Constant(1)), _Constant(7)); - SetX87TopTag(top, X87Tag::Valid); + SetX87ValidTag(top, true); SetX87Top(top); auto low = _Constant(Lower); @@ -196,7 +228,7 @@ void OpDispatchBuilder::FILD(OpcodeArgs) { // Update TOP auto orig_top = GetX87Top(); auto top = _And(OpSize::i64Bit, _Sub(OpSize::i64Bit, orig_top, _Constant(1)), _Constant(7)); - SetX87TopTag(top, X87Tag::Valid); + SetX87ValidTag(top, true); SetX87Top(top); size_t read_width = GetSrcSize(Op); @@ -246,7 +278,7 @@ void OpDispatchBuilder::FST(OpcodeArgs) { 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); + SetX87ValidTag(orig_top, false); // Set the new top now auto top = _And(OpSize::i64Bit, _Add(OpSize::i64Bit, orig_top, _Constant(1)), _Constant(7)); SetX87Top(top); @@ -272,7 +304,7 @@ void OpDispatchBuilder::FIST(OpcodeArgs) { 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); + SetX87ValidTag(orig_top, false); // Set the new top now auto top = _And(OpSize::i64Bit, _Add(OpSize::i64Bit, orig_top, _Constant(1)), _Constant(7)); SetX87Top(top); @@ -321,7 +353,7 @@ void OpDispatchBuilder::FADD(OpcodeArgs) { 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); + SetX87ValidTag(top, false); // Set the new top now top = _And(OpSize::i64Bit, _Add(OpSize::i64Bit, top, _Constant(1)), mask); SetX87Top(top); @@ -384,7 +416,7 @@ void OpDispatchBuilder::FMUL(OpcodeArgs) { 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); + SetX87ValidTag(top, false); // Set the new top now top = _And(OpSize::i64Bit, _Add(OpSize::i64Bit, top, _Constant(1)), mask); SetX87Top(top); @@ -453,7 +485,7 @@ void OpDispatchBuilder::FDIV(OpcodeArgs) { 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); + SetX87ValidTag(top, false); // Set the new top now top = _And(OpSize::i64Bit, _Add(OpSize::i64Bit, top, _Constant(1)), mask); SetX87Top(top); @@ -537,7 +569,7 @@ void OpDispatchBuilder::FSUB(OpcodeArgs) { 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); + SetX87ValidTag(top, false); // Set the new top now top = _And(OpSize::i64Bit, _Add(OpSize::i64Bit, top, _Constant(1)), mask); @@ -645,7 +677,7 @@ void OpDispatchBuilder::FRNDINT(OpcodeArgs) { void OpDispatchBuilder::FXTRACT(OpcodeArgs) { auto orig_top = GetX87Top(); auto top = _And(OpSize::i64Bit, _Sub(OpSize::i64Bit, orig_top, _Constant(1)), _Constant(7)); - SetX87TopTag(top, X87Tag::Valid); + SetX87ValidTag(top, true); SetX87Top(top); auto a = _LoadContextIndexed(orig_top, 16, MMBaseOffset(), 16, FPRClass); @@ -673,8 +705,8 @@ void OpDispatchBuilder::FNINIT(OpcodeArgs) { SetRFLAG(Zero); SetRFLAG(Zero); - // Tags all get set to 0b11 - _StoreContext(2, GPRClass, _Constant(0xFFFF), offsetof(FEXCore::Core::CPUState, FTW)); + // Tags all get marked as invalid + _StoreContext(1, GPRClass, Zero, offsetof(FEXCore::Core::CPUState, AbridgedFTW)); } template @@ -735,16 +767,16 @@ void OpDispatchBuilder::FCOMI(OpcodeArgs) { if constexpr (poptwice) { // if we are popping then we must first mark this location as empty - SetX87TopTag(top, X87Tag::Empty); + SetX87ValidTag(top, false); top = _And(OpSize::i64Bit, _Add(OpSize::i64Bit, top, _Constant(1)), mask); - SetX87TopTag(top, X87Tag::Empty); + SetX87ValidTag(top, false); // Set the new top now top = _And(OpSize::i64Bit, _Add(OpSize::i64Bit, 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); + SetX87ValidTag(top, false); // Set the new top now top = _And(OpSize::i64Bit, _Add(OpSize::i64Bit, top, _Constant(1)), mask); SetX87Top(top); @@ -806,7 +838,7 @@ void OpDispatchBuilder::FST(OpcodeArgs) { 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); + SetX87ValidTag(top, false); top = _And(OpSize::i64Bit, _Add(OpSize::i64Bit, top, _Constant(1)), _Constant(7)); SetX87Top(top); } @@ -892,7 +924,7 @@ void OpDispatchBuilder::X87ModifySTP(OpcodeArgs); void OpDispatchBuilder::X87SinCos(OpcodeArgs) { auto orig_top = GetX87Top(); auto top = _And(OpSize::i64Bit, _Sub(OpSize::i64Bit, orig_top, _Constant(1)), _Constant(7)); - SetX87TopTag(top, X87Tag::Valid); + SetX87ValidTag(top, true); SetX87Top(top); auto a = _LoadContextIndexed(orig_top, 16, MMBaseOffset(), 16, FPRClass); @@ -913,7 +945,7 @@ void OpDispatchBuilder::X87FYL2X(OpcodeArgs) { auto orig_top = GetX87Top(); // if we are popping then we must first mark this location as empty - SetX87TopTag(orig_top, X87Tag::Empty); + SetX87ValidTag(orig_top, false); auto top = _And(OpSize::i64Bit, _Add(OpSize::i64Bit, orig_top, _Constant(1)), _Constant(7)); SetX87Top(top); @@ -937,7 +969,7 @@ void OpDispatchBuilder::X87FYL2X(OpcodeArgs) { void OpDispatchBuilder::X87TAN(OpcodeArgs) { auto orig_top = GetX87Top(); auto top = _And(OpSize::i64Bit, _Sub(OpSize::i64Bit, orig_top, _Constant(1)), _Constant(7)); - SetX87TopTag(top, X87Tag::Valid); + SetX87ValidTag(top, true); SetX87Top(top); auto a = _LoadContextIndexed(orig_top, 16, MMBaseOffset(), 16, FPRClass); @@ -960,7 +992,7 @@ void OpDispatchBuilder::X87TAN(OpcodeArgs) { void OpDispatchBuilder::X87ATAN(OpcodeArgs) { auto orig_top = GetX87Top(); // if we are popping then we must first mark this location as empty - SetX87TopTag(orig_top, X87Tag::Empty); + SetX87ValidTag(orig_top, false); auto top = _And(OpSize::i64Bit, _Add(OpSize::i64Bit, orig_top, _Constant(1)), _Constant(7)); SetX87Top(top); @@ -989,8 +1021,7 @@ void OpDispatchBuilder::X87LDENV(OpcodeArgs) { { // FTW OrderedNode *MemLocation = _Add(OpSize::i64Bit, Mem, _Constant(Size * 2)); - auto NewFTW = _LoadMem(GPRClass, Size, MemLocation, Size); - _StoreContext(2, GPRClass, NewFTW, offsetof(FEXCore::Core::CPUState, FTW)); + SetX87FTW(_LoadMem(GPRClass, Size, MemLocation, Size)); } } @@ -1033,8 +1064,7 @@ void OpDispatchBuilder::X87FNSTENV(OpcodeArgs) { { // FTW OrderedNode *MemLocation = _Add(OpSize::i64Bit, Mem, _Constant(Size * 2)); - auto FTW = _LoadContext(2, GPRClass, offsetof(FEXCore::Core::CPUState, FTW)); - _StoreMem(GPRClass, Size, MemLocation, FTW, Size); + _StoreMem(GPRClass, Size, MemLocation, GetX87FTW(), Size); } { @@ -1123,8 +1153,7 @@ void OpDispatchBuilder::X87FNSAVE(OpcodeArgs) { { // FTW OrderedNode *MemLocation = _Add(OpSize::i64Bit, Mem, _Constant(Size * 2)); - auto FTW = _LoadContext(2, GPRClass, offsetof(FEXCore::Core::CPUState, FTW)); - _StoreMem(GPRClass, Size, MemLocation, FTW, Size); + _StoreMem(GPRClass, Size, MemLocation, GetX87FTW(), Size); } { @@ -1192,8 +1221,7 @@ void OpDispatchBuilder::X87FRSTOR(OpcodeArgs) { { // FTW OrderedNode *MemLocation = _Add(OpSize::i64Bit, Mem, _Constant(Size * 2)); - auto NewFTW = _LoadMem(GPRClass, Size, MemLocation, Size); - _StoreContext(2, GPRClass, NewFTW, offsetof(FEXCore::Core::CPUState, FTW)); + SetX87FTW(_LoadMem(GPRClass, Size, MemLocation, Size)); } OrderedNode *ST0Location = _Add(OpSize::i64Bit, Mem, _Constant(Size * 7)); @@ -1241,20 +1269,16 @@ void OpDispatchBuilder::X87FXAM(OpcodeArgs) { // Claim this is a normal number // We don't support anything else - auto FTW = GetX87FTW(top); - auto X87Zero = _Constant(0b11); + auto TopValid = GetX87ValidTag(top); auto ZeroConst = _Constant(0); auto OneConst = _Constant(1); - // In the case of Zero 0b11 then C3:C2:C0 is 0b101 + // In the case of top being invalid 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, + TopValid, OneConst, ZeroConst, OneConst); + auto C2 = TopValid; auto C0 = C3; // Mirror C3 until something other than zero is supported SetRFLAG(C0); SetRFLAG(C2); @@ -1350,7 +1374,7 @@ void OpDispatchBuilder::X87FCMOV(OpcodeArgs) { void OpDispatchBuilder::X87EMMS(OpcodeArgs) { // Tags all get set to 0b11 - _StoreContext(2, GPRClass, _Constant(0xFFFF), offsetof(FEXCore::Core::CPUState, FTW)); + _StoreContext(1, GPRClass, _Constant(0), offsetof(FEXCore::Core::CPUState, AbridgedFTW)); } void OpDispatchBuilder::X87FFREE(OpcodeArgs) { @@ -1362,7 +1386,7 @@ void OpDispatchBuilder::X87FFREE(OpcodeArgs) { top = _And(OpSize::i64Bit, _Add(OpSize::i64Bit, top, offset), _Constant(7)); // Set this argument's tag as empty now - SetX87TopTag(top, X87Tag::Empty); + SetX87ValidTag(top, false); } } diff --git a/FEXCore/Source/Interface/Core/OpcodeDispatcher/X87F64.cpp b/FEXCore/Source/Interface/Core/OpcodeDispatcher/X87F64.cpp index c03241a78..00af6d3a5 100644 --- a/FEXCore/Source/Interface/Core/OpcodeDispatcher/X87F64.cpp +++ b/FEXCore/Source/Interface/Core/OpcodeDispatcher/X87F64.cpp @@ -24,8 +24,11 @@ class OrderedNode; //Functions in X87.cpp (no change required) //GetX87Top -//SetX87TopTag -//GetX87FTW +//SetX87ValidTag +//GetX87ValidTag +//GetX87Tag (will need changing once special tag handling is implemented) +//SetX87FTW +//GetX87FTW (will need changing once special tag handling is implemented) //SetX87Top //X87ModifySTP //EMMS @@ -57,8 +60,8 @@ void OpDispatchBuilder::FNINITF64(OpcodeArgs) { SetRFLAG(Zero); SetRFLAG(Zero); - // Tags all get set to 0b11 - _StoreContext(2, GPRClass, _Constant(0xFFFF), offsetof(FEXCore::Core::CPUState, FTW)); + // Tags all get marked as invalid + _StoreContext(1, GPRClass, Zero, offsetof(FEXCore::Core::CPUState, AbridgedFTW)); } void OpDispatchBuilder::X87LDENVF64(OpcodeArgs) { @@ -86,8 +89,7 @@ void OpDispatchBuilder::X87LDENVF64(OpcodeArgs) { { // FTW OrderedNode *MemLocation = _Add(OpSize::i64Bit, Mem, _Constant(Size * 2)); - auto NewFTW = _LoadMem(GPRClass, Size, MemLocation, Size); - _StoreContext(2, GPRClass, NewFTW, offsetof(FEXCore::Core::CPUState, FTW)); + SetX87FTW(_LoadMem(GPRClass, Size, MemLocation, Size)); } } @@ -140,7 +142,7 @@ void OpDispatchBuilder::FLDF64(OpcodeArgs) { } auto top = _And(OpSize::i64Bit, _Sub(OpSize::i64Bit, orig_top, _Constant(1)), mask); - SetX87TopTag(top, X87Tag::Valid); + SetX87ValidTag(top, true); SetX87Top(top); // Write to ST[TOP] _StoreContextIndexed(converted, top, 8, MMBaseOffset(), 16, FPRClass); @@ -158,7 +160,7 @@ void OpDispatchBuilder::FBLDF64(OpcodeArgs) { auto orig_top = GetX87Top(); auto mask = _Constant(7); auto top = _And(OpSize::i64Bit, _Sub(OpSize::i64Bit, orig_top, _Constant(1)), mask); - SetX87TopTag(top, X87Tag::Valid); + SetX87ValidTag(top, true); SetX87Top(top); // Read from memory @@ -178,7 +180,7 @@ void OpDispatchBuilder::FBSTPF64(OpcodeArgs) { 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); + SetX87ValidTag(orig_top, false); auto top = _And(OpSize::i64Bit, _Add(OpSize::i64Bit, orig_top, _Constant(1)), _Constant(7)); SetX87Top(top); } @@ -188,7 +190,7 @@ void OpDispatchBuilder::FLDF64_Const(OpcodeArgs) { // Update TOP auto orig_top = GetX87Top(); auto top = _And(OpSize::i64Bit, _Sub(OpSize::i64Bit, orig_top, _Constant(1)), _Constant(7)); - SetX87TopTag(top, X87Tag::Valid); + SetX87ValidTag(top, true); SetX87Top(top); auto data = _VCastFromGPR(8, 8, _Constant(num)); // Write to ST[TOP] @@ -214,7 +216,7 @@ void OpDispatchBuilder::FILDF64(OpcodeArgs) { // Update TOP auto orig_top = GetX87Top(); auto top = _And(OpSize::i64Bit, _Sub(OpSize::i64Bit, orig_top, _Constant(1)), _Constant(7)); - SetX87TopTag(top, X87Tag::Valid); + SetX87ValidTag(top, true); SetX87Top(top); size_t read_width = GetSrcSize(Op); @@ -247,7 +249,7 @@ void OpDispatchBuilder::FSTF64(OpcodeArgs) { 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); + SetX87ValidTag(orig_top, false); // Set the new top now auto top = _And(OpSize::i64Bit, _Add(OpSize::i64Bit, orig_top, _Constant(1)), _Constant(7)); SetX87Top(top); @@ -276,7 +278,7 @@ void OpDispatchBuilder::FISTF64(OpcodeArgs) { 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); + SetX87ValidTag(orig_top, false); // Set the new top now auto top = _And(OpSize::i64Bit, _Add(OpSize::i64Bit, orig_top, _Constant(1)), _Constant(7)); SetX87Top(top); @@ -326,7 +328,7 @@ void OpDispatchBuilder::FADDF64(OpcodeArgs) { 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); + SetX87ValidTag(top, false); // Set the new top now top = _And(OpSize::i64Bit, _Add(OpSize::i64Bit, top, _Constant(1)), mask); SetX87Top(top); @@ -390,7 +392,7 @@ void OpDispatchBuilder::FMULF64(OpcodeArgs) { 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); + SetX87ValidTag(top, false); // Set the new top now top = _And(OpSize::i64Bit, _Add(OpSize::i64Bit, top, _Constant(1)), mask); SetX87Top(top); @@ -460,7 +462,7 @@ void OpDispatchBuilder::FDIVF64(OpcodeArgs) { 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); + SetX87ValidTag(top, false); // Set the new top now top = _And(OpSize::i64Bit, _Add(OpSize::i64Bit, top, _Constant(1)), mask); SetX87Top(top); @@ -546,7 +548,7 @@ void OpDispatchBuilder::FSUBF64(OpcodeArgs) { 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); + SetX87ValidTag(top, false); // Set the new top now top = _And(OpSize::i64Bit, _Add(OpSize::i64Bit, top, _Constant(1)), mask); @@ -645,7 +647,7 @@ void OpDispatchBuilder::FRNDINTF64(OpcodeArgs) { void OpDispatchBuilder::FXTRACTF64(OpcodeArgs) { auto orig_top = GetX87Top(); auto top = _And(OpSize::i64Bit, _Sub(OpSize::i64Bit, orig_top, _Constant(1)), _Constant(7)); - SetX87TopTag(top, X87Tag::Valid); + SetX87ValidTag(top, true); SetX87Top(top); auto a = _LoadContextIndexed(orig_top, 8, MMBaseOffset(), 16, FPRClass); @@ -724,16 +726,16 @@ void OpDispatchBuilder::FCOMIF64(OpcodeArgs) { if constexpr (poptwice) { // if we are popping then we must first mark this location as empty - SetX87TopTag(top, X87Tag::Empty); + SetX87ValidTag(top, false); top = _And(OpSize::i64Bit, _Add(OpSize::i64Bit, top, _Constant(1)), mask); - SetX87TopTag(top, X87Tag::Empty); + SetX87ValidTag(top, false); // Set the new top now top = _And(OpSize::i64Bit, _Add(OpSize::i64Bit, 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); + SetX87ValidTag(top, false); // Set the new top now top = _And(OpSize::i64Bit, _Add(OpSize::i64Bit, top, _Constant(1)), mask); SetX87Top(top); @@ -832,7 +834,7 @@ void OpDispatchBuilder::X87BinaryOpF64(OpcodeArgs); void OpDispatchBuilder::X87SinCosF64(OpcodeArgs) { auto orig_top = GetX87Top(); auto top = _And(OpSize::i64Bit, _Sub(OpSize::i64Bit, orig_top, _Constant(1)), _Constant(7)); - SetX87TopTag(top, X87Tag::Valid); + SetX87ValidTag(top, true); SetX87Top(top); auto a = _LoadContextIndexed(orig_top, 8, MMBaseOffset(), 16, FPRClass); @@ -853,7 +855,7 @@ void OpDispatchBuilder::X87FYL2XF64(OpcodeArgs) { auto orig_top = GetX87Top(); // if we are popping then we must first mark this location as empty - SetX87TopTag(orig_top, X87Tag::Empty); + SetX87ValidTag(orig_top, false); auto top = _And(OpSize::i64Bit, _Add(OpSize::i64Bit, orig_top, _Constant(1)), _Constant(7)); SetX87Top(top); @@ -874,7 +876,7 @@ void OpDispatchBuilder::X87FYL2XF64(OpcodeArgs) { void OpDispatchBuilder::X87TANF64(OpcodeArgs) { auto orig_top = GetX87Top(); auto top = _And(OpSize::i64Bit, _Sub(OpSize::i64Bit, orig_top, _Constant(1)), _Constant(7)); - SetX87TopTag(top, X87Tag::Valid); + SetX87ValidTag(top, true); SetX87Top(top); auto a = _LoadContextIndexed(orig_top, 8, MMBaseOffset(), 16, FPRClass); @@ -894,7 +896,7 @@ void OpDispatchBuilder::X87TANF64(OpcodeArgs) { 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); + SetX87ValidTag(orig_top, false); auto top = _And(OpSize::i64Bit, _Add(OpSize::i64Bit, orig_top, _Constant(1)), _Constant(7)); SetX87Top(top); @@ -949,8 +951,7 @@ void OpDispatchBuilder::X87FNSAVEF64(OpcodeArgs) { { // FTW OrderedNode *MemLocation = _Add(OpSize::i64Bit, Mem, _Constant(Size * 2)); - auto FTW = _LoadContext(2, GPRClass, offsetof(FEXCore::Core::CPUState, FTW)); - _StoreMem(GPRClass, Size, MemLocation, FTW, Size); + _StoreMem(GPRClass, Size, MemLocation, GetX87FTW(), Size); } { @@ -1032,8 +1033,7 @@ void OpDispatchBuilder::X87FRSTORF64(OpcodeArgs) { { // FTW OrderedNode *MemLocation = _Add(OpSize::i64Bit, Mem, _Constant(Size * 2)); - auto NewFTW = _LoadMem(GPRClass, Size, MemLocation, Size); - _StoreContext(2, GPRClass, NewFTW, offsetof(FEXCore::Core::CPUState, FTW)); + SetX87FTW(_LoadMem(GPRClass, Size, MemLocation, Size)); } OrderedNode *ST0Location = _Add(OpSize::i64Bit, Mem, _Constant(Size * 7)); @@ -1085,20 +1085,16 @@ void OpDispatchBuilder::X87FXAMF64(OpcodeArgs) { // Claim this is a normal number // We don't support anything else - auto FTW = GetX87FTW(top); - auto X87Zero = _Constant(0b11); + auto TopValid = GetX87ValidTag(top); auto ZeroConst = _Constant(0); auto OneConst = _Constant(1); - // In the case of Zero 0b11 then C3:C2:C0 is 0b101 + // In the case of top being invalid 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, + TopValid, OneConst, ZeroConst, OneConst); + auto C2 = TopValid; auto C0 = C3; // Mirror C3 until something other than zero is supported SetRFLAG(C0); SetRFLAG(C2); diff --git a/FEXCore/Source/Interface/IR/Passes/DeadContextStoreElimination.cpp b/FEXCore/Source/Interface/IR/Passes/DeadContextStoreElimination.cpp index cc09860aa..56d26c6e4 100644 --- a/FEXCore/Source/Interface/IR/Passes/DeadContextStoreElimination.cpp +++ b/FEXCore/Source/Interface/IR/Passes/DeadContextStoreElimination.cpp @@ -306,11 +306,11 @@ namespace { FEXCore::IR::InvalidClass, }); - // FTW + // AbridgedFTW ContextClassification->emplace_back(ContextMemberInfo { ContextMemberClassification { - offsetof(FEXCore::Core::CPUState, FTW), - sizeof(FEXCore::Core::CPUState::FTW), + offsetof(FEXCore::Core::CPUState, AbridgedFTW), + sizeof(FEXCore::Core::CPUState::AbridgedFTW), }, ACCESS_NONE, FEXCore::IR::InvalidClass, diff --git a/FEXCore/include/FEXCore/Core/CoreState.h b/FEXCore/include/FEXCore/Core/CoreState.h index c5807ecdd..911b54778 100644 --- a/FEXCore/include/FEXCore/Core/CoreState.h +++ b/FEXCore/include/FEXCore/Core/CoreState.h @@ -108,9 +108,9 @@ namespace FEXCore::Core { uint32_t base; } gdt[32]{}; uint16_t FCW { 0x37F }; - uint16_t FTW { 0xFFFF }; + uint8_t AbridgedFTW{}; - uint32_t _pad2[1]; + uint8_t _pad2[5]; // Reference counter for FEX's per-thread deferred signals. // Counts the nesting depth of program sections that cause signals to be deferred. NonAtomicRefCounter DeferredSignalRefCount; diff --git a/FEXCore/include/FEXCore/Utils/FPState.h b/FEXCore/include/FEXCore/Utils/FPState.h new file mode 100644 index 000000000..e9bc35eaa --- /dev/null +++ b/FEXCore/include/FEXCore/Utils/FPState.h @@ -0,0 +1,12 @@ +#pragma once + +#include + +namespace FEXCore::FPState { + enum class X87Tag : uint8_t { + Valid = 0b00, + Zero = 0b01, + Special = 0b10, + Empty = 0b11 + }; +}