diff --git a/FEXCore/Source/Interface/Core/Core.cpp b/FEXCore/Source/Interface/Core/Core.cpp index a4e52061f..56c8b900b 100644 --- a/FEXCore/Source/Interface/Core/Core.cpp +++ b/FEXCore/Source/Interface/Core/Core.cpp @@ -614,20 +614,6 @@ ContextImpl::GenerateIR(FEXCore::Core::InternalThreadState* Thread, uint64_t Gue DecodedInfo = &Block.DecodedInstructions[i]; bool IsLocked = DecodedInfo->Flags & FEXCore::X86Tables::DecodeFlags::FLAG_LOCK; - // Do a partial register cache flush before every instruction. This - // prevents cross-instruction static register caching, while allowing - // context load/stores to be optimized within a block. Theoretically, - // this flush is not required for correctness, all mandatory flushes are - // included in instruction-specific handlers. Instead, this is a blunt - // heuristic to make the register cache less aggressive, as the current - // RA generates bad code in common cases with tied registers otherwise. - // - // However, it makes our exception handling behaviour more predictable. - // It is potentially correctness bearing in that sense, but that is a - // side effect here and (if that behaviour is required) we should handle - // that more explicitly later. - Thread->OpDispatcher->FlushRegisterCache(true); - if (ExtendedDebugInfo || Thread->OpDispatcher->CanHaveSideEffects(TableInfo, DecodedInfo)) { Thread->OpDispatcher->_GuestOpcode(Block.Entry + BlockInstructionsLength - GuestRIP); } diff --git a/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp b/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp index 6e1b45104..88e038130 100644 --- a/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp +++ b/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp @@ -113,7 +113,7 @@ void OpDispatchBuilder::SyscallOp(OpcodeArgs) { StoreGPRRegister(X86State::REG_RCX, RIPAfterInst, 8); } - FlushRegisterCache(); + CalculateDeferredFlags(); auto SyscallOp = _Syscall(Arguments[0], Arguments[1], Arguments[2], Arguments[3], Arguments[4], Arguments[5], Arguments[6], DefaultSyscallFlags); if (OSABI != FEXCore::HLE::SyscallOSABI::OS_HANGOVER && @@ -395,7 +395,7 @@ void OpDispatchBuilder::PUSHOp(OpcodeArgs) { // Store the new stack pointer StoreGPRRegister(X86State::REG_RSP, NewSP); - FlushRegisterCache(); + CalculateDeferredFlags(); } void OpDispatchBuilder::PUSHREGOp(OpcodeArgs) { @@ -408,7 +408,7 @@ void OpDispatchBuilder::PUSHREGOp(OpcodeArgs) { auto NewSP = _Push(GPRSize, Size, Src, OldSP); // Store the new stack pointer StoreGPRRegister(X86State::REG_RSP, NewSP); - FlushRegisterCache(); + CalculateDeferredFlags(); } void OpDispatchBuilder::PUSHAOp(OpcodeArgs) { @@ -458,7 +458,7 @@ void OpDispatchBuilder::PUSHAOp(OpcodeArgs) { // Store the new stack pointer StoreGPRRegister(X86State::REG_RSP, NewSP, 4); - FlushRegisterCache(); + CalculateDeferredFlags(); } template @@ -843,7 +843,7 @@ void OpDispatchBuilder::CondJUMPOp(OpcodeArgs) { Target &= 0xFFFFFFFFU; } - FlushRegisterCache(); + CalculateDeferredFlags(); auto TrueBlock = JumpTargets.find(Target); auto FalseBlock = JumpTargets.find(Op->PC + Op->InstSize); @@ -3366,8 +3366,8 @@ void OpDispatchBuilder::CMPSOp(OpcodeArgs) { auto Src2 = _LoadMem(GPRClass, Size, Dest_RSI, Size); // We'll calculate PF/AF after the loop, so use them as temporaries here. - StoreRegister(Core::CPUState::PF_AS_GREG, false, Src1); - StoreRegister(Core::CPUState::AF_AS_GREG, false, Src2); + _StoreRegister(Src1, Core::CPUState::PF_AS_GREG, GPRClass, CTX->GetGPRSize()); + _StoreRegister(Src2, Core::CPUState::AF_AS_GREG, GPRClass, CTX->GetGPRSize()); Ref TailCounter = LoadGPRRegister(X86State::REG_RCX); @@ -3406,8 +3406,8 @@ void OpDispatchBuilder::CMPSOp(OpcodeArgs) { // Make sure to start a new block after ending this one { // Grab the sources from the last iteration so we can set flags. - auto Src1 = LoadGPR(Core::CPUState::PF_AS_GREG); - auto Src2 = LoadGPR(Core::CPUState::AF_AS_GREG); + auto Src1 = _LoadRegister(Core::CPUState::PF_AS_GREG, GPRClass, CTX->GetGPRSize()); + auto Src2 = _LoadRegister(Core::CPUState::AF_AS_GREG, GPRClass, CTX->GetGPRSize()); GenerateFlags_SUB(Op, Src2, Src1); } auto Jump_ = Jump(); @@ -3996,7 +3996,7 @@ void OpDispatchBuilder::BeginFunction(uint64_t RIP, const fextl::vectorGetGPRSize(); // Node 0 is invalid node @@ -4363,7 +4363,7 @@ Ref OpDispatchBuilder::LoadSource_WithOpSize(RegisterClassType Class, const X86T const auto highIndex = Operand.Data.GPR.HighBits ? 1 : 0; if (gpr >= FEXCore::X86State::REG_MM_0) { - A.Base = LoadContext(MM0Index + gpr - FEXCore::X86State::REG_MM_0); + A.Base = _LoadContext(OpSize, FPRClass, offsetof(FEXCore::Core::CPUState, mm[gpr - FEXCore::X86State::REG_MM_0])); } else if (gpr >= FEXCore::X86State::REG_XMM_0) { const auto gprIndex = gpr - X86State::REG_XMM_0; @@ -4400,7 +4400,7 @@ Ref OpDispatchBuilder::LoadGPRRegister(uint32_t GPR, int8_t Size, uint8_t Offset if (Size == -1) { Size = GPRSize; } - Ref Reg = LoadGPR(GPR); + Ref Reg = _LoadRegister(GPR, GPRClass, GPRSize); if ((!AllowUpperGarbage && (Size != GPRSize)) || Offset != 0) { // Extract the subregister if requested. @@ -4414,6 +4414,10 @@ Ref OpDispatchBuilder::LoadGPRRegister(uint32_t GPR, int8_t Size, uint8_t Offset return Reg; } +Ref OpDispatchBuilder::LoadXMMRegister(uint32_t XMM) { + return _LoadRegister(XMM, FPRClass, GetGuestVectorLength()); +} + void OpDispatchBuilder::StoreGPRRegister(uint32_t GPR, const Ref Src, int8_t Size, uint8_t Offset) { const uint8_t GPRSize = CTX->GetGPRSize(); if (Size == -1) { @@ -4423,14 +4427,15 @@ void OpDispatchBuilder::StoreGPRRegister(uint32_t GPR, const Ref Src, int8_t Siz Ref Reg = Src; if (Size != GPRSize || Offset != 0) { // Need to do an insert if not automatic size or zero offset. - Reg = _Bfi(IR::SizeToOpSize(GPRSize), Size * 8, Offset, LoadGPRRegister(GPR), Src); + Reg = LoadGPRRegister(GPR); + Reg = _Bfi(IR::SizeToOpSize(GPRSize), Size * 8, Offset, Reg, Src); } - StoreRegister(GPR, false, Reg); + _StoreRegister(Reg, GPR, GPRClass, GPRSize); } void OpDispatchBuilder::StoreXMMRegister(uint32_t XMM, const Ref Src) { - StoreRegister(XMM, true, Src); + _StoreRegister(Src, XMM, FPRClass, GetGuestVectorLength()); } Ref OpDispatchBuilder::LoadSource(RegisterClassType Class, const X86Tables::DecodedOp& Op, const X86Tables::DecodedOperand& Operand, @@ -4449,8 +4454,7 @@ void OpDispatchBuilder::StoreResult_WithOpSize(FEXCore::IR::RegisterClassType Cl const auto gpr = Operand.Data.GPR.GPR; if (gpr >= FEXCore::X86State::REG_MM_0) { - LOGMAN_THROW_A_FMT(OpSize == 8, "full"); - StoreContext(MM0Index + gpr - FEXCore::X86State::REG_MM_0, Src); + _StoreContext(OpSize, Class, Src, offsetof(FEXCore::Core::CPUState, mm[gpr - FEXCore::X86State::REG_MM_0])); } else if (gpr >= FEXCore::X86State::REG_XMM_0) { const auto gprIndex = gpr - X86State::REG_XMM_0; const auto VectorSize = (CTX->HostFeatures.SupportsSVE256 && CTX->HostFeatures.SupportsAVX) ? 32 : 16; @@ -4548,8 +4552,6 @@ void OpDispatchBuilder::ResetWorkingList() { DecodeFailure = false; ShouldDump = false; CurrentCodeBlock = nullptr; - RegCache.Written = 0; - RegCache.Cached = 0; } void OpDispatchBuilder::UnhandledOp(OpcodeArgs) { @@ -4703,7 +4705,7 @@ void OpDispatchBuilder::INTOp(OpcodeArgs) { } // Calculate flags early. - FlushRegisterCache(); + CalculateDeferredFlags(); const uint8_t GPRSize = CTX->GetGPRSize(); diff --git a/FEXCore/Source/Interface/Core/OpcodeDispatcher.h b/FEXCore/Source/Interface/Core/OpcodeDispatcher.h index 998dae561..e1cdbd6f7 100644 --- a/FEXCore/Source/Interface/Core/OpcodeDispatcher.h +++ b/FEXCore/Source/Interface/Core/OpcodeDispatcher.h @@ -16,7 +16,6 @@ #include #include -#include #include #include #include @@ -136,7 +135,7 @@ public: // Changes get stored out by CalculateDeferredFlags. CachedNZCV = nullptr; PossiblySetNZCVBits = ~0U; - FlushRegisterCache(); + CalculateDeferredFlags(); // New block needs to reset segment telemetry. SegmentsNeedReadCheck = ~0U; @@ -146,28 +145,28 @@ public: } IRPair Jump() { - FlushRegisterCache(); + CalculateDeferredFlags(); return _Jump(); } IRPair Jump(Ref _TargetBlock) { - FlushRegisterCache(); + CalculateDeferredFlags(); return _Jump(_TargetBlock); } IRPair CondJump(Ref _Cmp1, Ref _Cmp2, Ref _TrueBlock, Ref _FalseBlock, CondClassType _Cond = {COND_NEQ}, uint8_t _CompareSize = 0) { - FlushRegisterCache(); + CalculateDeferredFlags(); return _CondJump(_Cmp1, _Cmp2, _TrueBlock, _FalseBlock, _Cond, _CompareSize); } IRPair CondJump(Ref ssa0, CondClassType cond = {COND_NEQ}) { - FlushRegisterCache(); + CalculateDeferredFlags(); return _CondJump(ssa0, cond); } IRPair CondJump(Ref ssa0, Ref ssa1, Ref ssa2, CondClassType cond = {COND_NEQ}) { - FlushRegisterCache(); + CalculateDeferredFlags(); return _CondJump(ssa0, ssa1, ssa2, cond); } IRPair CondJumpNZCV(CondClassType Cond) { - FlushRegisterCache(); + CalculateDeferredFlags(); // The jump will ignore the sources, so it doesn't matter what we put here. // Put an inline constant so RA+codegen will ignore altogether. @@ -175,15 +174,15 @@ public: return _CondJump(Placeholder, Placeholder, InvalidNode, InvalidNode, Cond, 0, true); } IRPair ExitFunction(Ref NewRIP) { - FlushRegisterCache(); + CalculateDeferredFlags(); return _ExitFunction(NewRIP); } IRPair Break(BreakDefinition Reason) { - FlushRegisterCache(); + CalculateDeferredFlags(); return _Break(Reason); } IRPair Thunk(Ref ArgPtr, SHA256Sum ThunkNameHash) { - FlushRegisterCache(); + CalculateDeferredFlags(); return _Thunk(ArgPtr, ThunkNameHash); } @@ -1292,50 +1291,6 @@ public: } } - void FlushRegisterCache(bool SRAOnly = false) { - CalculateDeferredFlags(); - - const uint8_t GPRSize = CTX->GetGPRSize(); - const auto VectorSize = (CTX->HostFeatures.SupportsSVE256 && CTX->HostFeatures.SupportsAVX) ? 32 : 16; - - // Write backwards. This is a heuristic to improve coalescing, since we - // often copy from (low) fixed GPRs to (high) PF/AF for celebrity - // instructions like "add rax, 1". This hack will go away with clauses. - uint64_t Bits = RegCache.Written; - - // We have an SRA only mode that exists as a hack to make register caching - // less aggressive. We should get rid of this once RA can take it. - uint64_t Mask = ~0ULL; - - if (SRAOnly) { - const uint64_t GPRMask = ((1ull << (AFIndex - GPR0Index + 1)) - 1) << GPR0Index; - const uint64_t FPRMask = ((1ull << (FPR15Index - FPR0Index + 1)) - 1) << FPR0Index; - - Mask &= (GPRMask | FPRMask); - Bits &= Mask; - } - - while (Bits != 0) { - uint32_t Index = 63 - std::countl_zero(Bits); - Ref Value = RegCache.Value[Index]; - - if (Index >= GPR0Index && Index <= AFIndex) { - _StoreRegister(Value, Index - GPR0Index, GPRClass, GPRSize); - } else if (Index >= FPR0Index && Index <= FPR15Index) { - _StoreRegister(Value, Index - FPR0Index, FPRClass, VectorSize); - } else if (Index == DFIndex) { - _StoreFlag(Value, X86State::RFLAG_DF_RAW_LOC); - } else { - _StoreContext(CacheIndexToSize(Index), CacheIndexClass(Index), Value, CacheIndexToContextOffset(Index)); - } - - Bits &= ~(1ull << Index); - } - - RegCache.Written &= ~Mask; - RegCache.Cached &= ~Mask; - } - protected: void SaveNZCV(IROps Op = OP_DUMMY) override { /* Some opcodes are conservatively marked as clobbering flags, but in fact @@ -1565,6 +1520,7 @@ private: void UpdatePrefixFromSegment(Ref Segment, uint32_t SegmentReg); Ref LoadGPRRegister(uint32_t GPR, int8_t Size = -1, uint8_t Offset = 0, bool AllowUpperGarbage = false); + Ref LoadXMMRegister(uint32_t XMM); void StoreGPRRegister(uint32_t GPR, const Ref Src, int8_t Size = -1, uint8_t Offset = 0); void StoreXMMRegister(uint32_t XMM, const Ref Src); @@ -1780,9 +1736,9 @@ private: if (IsNZCV(BitOffset)) { InsertNZCV(BitOffset, Value, ValueOffset, MustMask); } else if (BitOffset == FEXCore::X86State::RFLAG_PF_RAW_LOC) { - StoreRegister(Core::CPUState::PF_AS_GREG, false, Value); + _StoreRegister(Value, Core::CPUState::PF_AS_GREG, GPRClass, CTX->GetGPRSize()); } else if (BitOffset == FEXCore::X86State::RFLAG_AF_RAW_LOC) { - StoreRegister(Core::CPUState::AF_AS_GREG, false, Value); + _StoreRegister(Value, Core::CPUState::AF_AS_GREG, GPRClass, CTX->GetGPRSize()); } else { if (ValueOffset || MustMask) { Value = _Bfe(OpSize::i32Bit, 1, ValueOffset, Value); @@ -1790,10 +1746,10 @@ private: // For DF, we need to transform 0/1 into 1/-1 if (BitOffset == FEXCore::X86State::RFLAG_DF_RAW_LOC) { - StoreDF(_SubShift(OpSize::i64Bit, _Constant(1), Value, ShiftType::LSL, 1)); - } else { - _StoreFlag(Value, BitOffset); + Value = _SubShift(OpSize::i64Bit, _Constant(1), Value, ShiftType::LSL, 1); } + + _StoreFlag(Value, BitOffset); } } @@ -1809,13 +1765,10 @@ private: void InvalidateAF() { _InvalidateFlags((1u << X86State::RFLAG_AF_RAW_LOC)); - InvalidateReg(Core::CPUState::AF_AS_GREG); } void InvalidatePF_AF() { _InvalidateFlags((1u << X86State::RFLAG_PF_RAW_LOC) | (1u << X86State::RFLAG_AF_RAW_LOC)); - InvalidateReg(Core::CPUState::PF_AS_GREG); - InvalidateReg(Core::CPUState::AF_AS_GREG); } CondClassType CondForNZCVBit(unsigned BitOffset, bool Invert) { @@ -1832,116 +1785,6 @@ private: } } - /* Layout of cache indices. We use a single 64-bit bitmask for the cache */ - static const int GPR0Index = 0; - static const int GPR15Index = 15; - static const int PFIndex = 16; - static const int AFIndex = 17; - /* Gap 18..19 */ - static const int MM0Index = 20; - static const int MM7Index = 27; - static const int AbridgedFTWIndex = 28; - /* Gap 29..30 */ - static const int DFIndex = 31; - static const int FPR0Index = 32; - static const int FPR15Index = 47; - static const int AVXHigh0Index = 48; - static const int AVXHigh15Index = 63; - - int CacheIndexToContextOffset(int Index) { - switch (Index) { - case MM0Index ... MM7Index: return offsetof(FEXCore::Core::CPUState, mm[Index - MM0Index]); - case AVXHigh0Index ... AVXHigh15Index: return offsetof(FEXCore::Core::CPUState, avx_high[Index - AVXHigh0Index][0]); - case AbridgedFTWIndex: return offsetof(FEXCore::Core::CPUState, AbridgedFTW); - default: return -1; - } - } - - RegisterClassType CacheIndexClass(int Index) { - if ((Index >= MM0Index && Index <= MM7Index) || Index >= FPR0Index) { - return FPRClass; - } else { - return GPRClass; - } - } - - unsigned CacheIndexToSize(int Index) { - if (Index >= AVXHigh0Index) { - return 16; - } else if (Index <= MM7Index) { - return 8; - } else { - return 1; - } - } - - struct { - uint64_t Cached; - uint64_t Written; - Ref Value[64]; - } RegCache {}; - - void InvalidateReg(uint8_t Index) { - uint64_t Bit = (1ull << (uint64_t)Index); - RegCache.Cached &= ~Bit; - RegCache.Written &= ~Bit; - } - - Ref LoadRegCache(uint64_t Offset, uint8_t Index, RegisterClassType RegClass, uint8_t Size) { - LOGMAN_THROW_AA_FMT(Index < 64, "valid index"); - uint64_t Bit = (1ull << (uint64_t)Index); - - if (!(RegCache.Cached & Bit)) { - if (Index == DFIndex) { - RegCache.Value[Index] = _LoadDF(); - } else if ((Index >= MM0Index && Index <= AbridgedFTWIndex) || Index >= AVXHigh0Index) { - RegCache.Value[Index] = _LoadContext(Size, RegClass, Offset); - } else { - RegCache.Value[Index] = _LoadRegister(Offset, RegClass, Size); - } - - RegCache.Cached |= Bit; - } - - return RegCache.Value[Index]; - } - - Ref LoadGPR(uint8_t Reg) { - return LoadRegCache(Reg, GPR0Index + Reg, GPRClass, CTX->GetGPRSize()); - } - - Ref LoadContext(uint8_t Index) { - return LoadRegCache(CacheIndexToContextOffset(Index), Index, CacheIndexClass(Index), CacheIndexToSize(Index)); - } - - Ref LoadXMMRegister(uint8_t Reg) { - const auto VectorSize = (CTX->HostFeatures.SupportsSVE256 && CTX->HostFeatures.SupportsAVX) ? 32 : 16; - return LoadRegCache(Reg, FPR0Index + Reg, FPRClass, VectorSize); - } - - Ref LoadDF() { - return LoadGPR(DFIndex); - } - - void StoreContext(uint8_t Index, Ref Value) { - LOGMAN_THROW_AA_FMT(Index < 64, "valid index"); - LOGMAN_THROW_AA_FMT(Value != InvalidNode, "storing valid"); - - uint64_t Bit = (1ull << (uint64_t)Index); - - RegCache.Value[Index] = Value; - RegCache.Cached |= Bit; - RegCache.Written |= Bit; - } - - void StoreRegister(uint8_t Reg, bool FPR, Ref Value) { - StoreContext(Reg + (FPR ? FPR0Index : GPR0Index), Value); - } - - void StoreDF(Ref Value) { - StoreContext(DFIndex, Value); - } - Ref GetRFLAG(unsigned BitOffset, bool Invert = false) { if (IsNZCV(BitOffset)) { if (!(PossiblySetNZCVBits & (1u << IndexNZCV(BitOffset)))) { @@ -1958,12 +1801,12 @@ private: return _NZCVSelect(OpSize::i32Bit, CondForNZCVBit(BitOffset, Invert), _Constant(1), _Constant(0)); } } else if (BitOffset == FEXCore::X86State::RFLAG_PF_RAW_LOC) { - return LoadGPR(Core::CPUState::PF_AS_GREG); + return _LoadRegister(Core::CPUState::PF_AS_GREG, GPRClass, CTX->GetGPRSize()); } else if (BitOffset == FEXCore::X86State::RFLAG_AF_RAW_LOC) { - return LoadGPR(Core::CPUState::AF_AS_GREG); + return _LoadRegister(Core::CPUState::AF_AS_GREG, GPRClass, CTX->GetGPRSize()); } else if (BitOffset == FEXCore::X86State::RFLAG_DF_RAW_LOC) { // Recover the sign bit, it is the logical DF value - return _Lshr(OpSize::i64Bit, LoadDF(), _Constant(63)); + return _Lshr(OpSize::i64Bit, _LoadDF(), _Constant(63)); } else { return _LoadFlag(BitOffset); } @@ -1971,7 +1814,7 @@ private: // Returns (DF ? -Size : Size) Ref LoadDir(const unsigned Size) { - auto Dir = LoadDF(); + auto Dir = _LoadDF(); auto Shift = FEXCore::ilog2(Size); if (Shift) { @@ -1985,7 +1828,7 @@ private: Ref OffsetByDir(Ref X, const unsigned Size) { auto Shift = FEXCore::ilog2(Size); - return _AddShift(OpSize::i64Bit, X, LoadDF(), ShiftType::LSL, Shift); + return _AddShift(OpSize::i64Bit, X, _LoadDF(), ShiftType::LSL, Shift); } // Compares two floats and sets flags for a COMISS instruction diff --git a/FEXCore/Source/Interface/Core/OpcodeDispatcher/AVX_128.cpp b/FEXCore/Source/Interface/Core/OpcodeDispatcher/AVX_128.cpp index d8348fa3c..f7dc51897 100644 --- a/FEXCore/Source/Interface/Core/OpcodeDispatcher/AVX_128.cpp +++ b/FEXCore/Source/Interface/Core/OpcodeDispatcher/AVX_128.cpp @@ -562,17 +562,17 @@ void OpDispatchBuilder::AVX128_StoreResult_WithOpSize(FEXCore::X86Tables::Decode Ref OpDispatchBuilder::AVX128_LoadXMMRegister(uint32_t XMM, bool High) { if (High) { - return LoadContext(AVXHigh0Index + XMM); + return _LoadContext(16, FPRClass, offsetof(FEXCore::Core::CPUState, avx_high[XMM][0])); } else { - return LoadXMMRegister(XMM); + return _LoadRegister(XMM, FPRClass, 16); } } void OpDispatchBuilder::AVX128_StoreXMMRegister(uint32_t XMM, const Ref Src, bool High) { if (High) { - StoreContext(AVXHigh0Index + XMM, Src); + _StoreContext(16, FPRClass, Src, offsetof(FEXCore::Core::CPUState, avx_high[XMM][0])); } else { - StoreXMMRegister(XMM, Src); + _StoreRegister(Src, XMM, FPRClass, 16); } } diff --git a/FEXCore/Source/Interface/Core/OpcodeDispatcher/Vector.cpp b/FEXCore/Source/Interface/Core/OpcodeDispatcher/Vector.cpp index 649922310..d343ce1e1 100644 --- a/FEXCore/Source/Interface/Core/OpcodeDispatcher/Vector.cpp +++ b/FEXCore/Source/Interface/Core/OpcodeDispatcher/Vector.cpp @@ -2690,7 +2690,8 @@ void OpDispatchBuilder::SaveX87State(OpcodeArgs, Ref MemBase) { { // Abridged FTW - _StoreMem(GPRClass, 1, LoadContext(AbridgedFTWIndex), MemBase, _Constant(4), 2, MEM_OFFSET_SXTX, 1); + auto AbridgedFTW = _LoadContext(1, GPRClass, offsetof(FEXCore::Core::CPUState, AbridgedFTW)); + _StoreMem(GPRClass, 1, AbridgedFTW, MemBase, _Constant(4), 2, MEM_OFFSET_SXTX, 1); } // BYTE | 0 1 | 2 3 | 4 | 5 | 6 7 | 8 9 | a b | c d | e f | @@ -2738,7 +2739,7 @@ void OpDispatchBuilder::SaveX87State(OpcodeArgs, Ref MemBase) { // If OSFXSR bit in CR4 is not set than FXSAVE /may/ not save the XMM registers // This is implementation dependent for (uint32_t i = 0; i < Core::CPUState::NUM_MMS; ++i) { - Ref MMReg = LoadContext(MM0Index + i); + Ref MMReg = _LoadContext(16, FPRClass, offsetof(FEXCore::Core::CPUState, mm[i])); _StoreMem(FPRClass, 16, MMReg, MemBase, _Constant(i * 16 + 32), 16, MEM_OFFSET_SXTX, 1); } @@ -2865,12 +2866,13 @@ void OpDispatchBuilder::RestoreX87State(Ref MemBase) { { // Abridged FTW - StoreContext(AbridgedFTWIndex, _LoadMem(GPRClass, 1, MemBase, _Constant(4), 2, MEM_OFFSET_SXTX, 1)); + auto NewAbridgedFTW = _LoadMem(GPRClass, 1, MemBase, _Constant(4), 2, MEM_OFFSET_SXTX, 1); + _StoreContext(1, GPRClass, NewAbridgedFTW, offsetof(FEXCore::Core::CPUState, AbridgedFTW)); } for (uint32_t i = 0; i < Core::CPUState::NUM_MMS; ++i) { auto MMReg = _LoadMem(FPRClass, 16, MemBase, _Constant(i * 16 + 32), 16, MEM_OFFSET_SXTX, 1); - StoreContext(MM0Index + i, MMReg); + _StoreContext(16, FPRClass, MMReg, offsetof(FEXCore::Core::CPUState, mm[i])); } } @@ -2909,7 +2911,7 @@ void OpDispatchBuilder::DefaultX87State(OpcodeArgs) { // all of the ST0-7/MM0-7 registers to zero. Ref ZeroVector = LoadZeroVector(Core::CPUState::MM_REG_SIZE); for (uint32_t i = 0; i < Core::CPUState::NUM_MMS; ++i) { - StoreContext(MM0Index + i, ZeroVector); + _StoreContext(16, FPRClass, ZeroVector, offsetof(FEXCore::Core::CPUState, mm[i])); } } diff --git a/FEXCore/Source/Interface/Core/OpcodeDispatcher/X87.cpp b/FEXCore/Source/Interface/Core/OpcodeDispatcher/X87.cpp index 3e1db6356..3699c0925 100644 --- a/FEXCore/Source/Interface/Core/OpcodeDispatcher/X87.cpp +++ b/FEXCore/Source/Interface/Core/OpcodeDispatcher/X87.cpp @@ -31,14 +31,14 @@ Ref OpDispatchBuilder::GetX87Top() { void OpDispatchBuilder::SetX87ValidTag(Ref Value, bool Valid) { // if we are popping then we must first mark this location as empty - Ref AbridgedFTW = LoadContext(AbridgedFTWIndex); + Ref AbridgedFTW = _LoadContext(1, GPRClass, offsetof(FEXCore::Core::CPUState, AbridgedFTW)); Ref RegMask = _Lshl(OpSize::i32Bit, _Constant(1), Value); Ref NewAbridgedFTW = Valid ? _Or(OpSize::i32Bit, AbridgedFTW, RegMask) : _Andn(OpSize::i32Bit, AbridgedFTW, RegMask); - StoreContext(AbridgedFTWIndex, NewAbridgedFTW); + _StoreContext(1, GPRClass, NewAbridgedFTW, offsetof(FEXCore::Core::CPUState, AbridgedFTW)); } Ref OpDispatchBuilder::GetX87ValidTag(Ref Value) { - Ref AbridgedFTW = LoadContext(AbridgedFTWIndex); + Ref AbridgedFTW = _LoadContext(1, GPRClass, offsetof(FEXCore::Core::CPUState, AbridgedFTW)); return _And(OpSize::i32Bit, _Lshr(OpSize::i32Bit, AbridgedFTW, Value), _Constant(1)); } @@ -51,7 +51,8 @@ Ref OpDispatchBuilder::GetX87Tag(Ref Value, Ref AbridgedFTW) { } Ref OpDispatchBuilder::GetX87Tag(Ref Value) { - return GetX87Tag(Value, LoadContext(AbridgedFTWIndex)); + Ref AbridgedFTW = _LoadContext(1, GPRClass, offsetof(FEXCore::Core::CPUState, AbridgedFTW)); + return GetX87Tag(Value, AbridgedFTW); } void OpDispatchBuilder::SetX87FTW(Ref FTW) { @@ -69,11 +70,11 @@ void OpDispatchBuilder::SetX87FTW(Ref FTW) { } } - StoreContext(AbridgedFTWIndex, NewAbridgedFTW); + _StoreContext(1, GPRClass, NewAbridgedFTW, offsetof(FEXCore::Core::CPUState, AbridgedFTW)); } Ref OpDispatchBuilder::GetX87FTW() { - Ref AbridgedFTW = LoadContext(AbridgedFTWIndex); + Ref AbridgedFTW = _LoadContext(1, GPRClass, offsetof(FEXCore::Core::CPUState, AbridgedFTW)); Ref FTW = _Constant(0); for (int i = 0; i < 8; i++) { @@ -153,6 +154,7 @@ void OpDispatchBuilder::FLD(OpcodeArgs) { SetX87Top(top); // Write to ST[TOP] _StoreContextIndexed(converted, top, 16, MMBaseOffset(), 16, FPRClass); + //_StoreContext(converted, 16, offsetof(FEXCore::Core::CPUState, mm[7][0])); } template void OpDispatchBuilder::FLD<32>(OpcodeArgs); @@ -642,7 +644,7 @@ void OpDispatchBuilder::FNINIT(OpcodeArgs) { SetRFLAG(Zero); // Tags all get marked as invalid - StoreContext(AbridgedFTWIndex, Zero); + _StoreContext(1, GPRClass, Zero, offsetof(FEXCore::Core::CPUState, AbridgedFTW)); } template @@ -1213,7 +1215,7 @@ void OpDispatchBuilder::X87FCMOV(OpcodeArgs) { void OpDispatchBuilder::X87EMMS(OpcodeArgs) { // Tags all get set to 0b11 - StoreContext(AbridgedFTWIndex, _Constant(0)); + _StoreContext(1, GPRClass, _Constant(0), offsetof(FEXCore::Core::CPUState, AbridgedFTW)); } void OpDispatchBuilder::X87FFREE(OpcodeArgs) { diff --git a/FEXCore/Source/Interface/Core/OpcodeDispatcher/X87F64.cpp b/FEXCore/Source/Interface/Core/OpcodeDispatcher/X87F64.cpp index a746e5dc0..96d2f3577 100644 --- a/FEXCore/Source/Interface/Core/OpcodeDispatcher/X87F64.cpp +++ b/FEXCore/Source/Interface/Core/OpcodeDispatcher/X87F64.cpp @@ -60,7 +60,7 @@ void OpDispatchBuilder::FNINITF64(OpcodeArgs) { SetRFLAG(Zero); // Tags all get marked as invalid - StoreContext(AbridgedFTWIndex, Zero); + _StoreContext(1, GPRClass, Zero, offsetof(FEXCore::Core::CPUState, AbridgedFTW)); } void OpDispatchBuilder::X87LDENVF64(OpcodeArgs) {