diff --git a/FEXCore/Source/Interface/Core/JIT/Arm64/MemoryOps.cpp b/FEXCore/Source/Interface/Core/JIT/Arm64/MemoryOps.cpp index 2d50accac..12c2f35d2 100644 --- a/FEXCore/Source/Interface/Core/JIT/Arm64/MemoryOps.cpp +++ b/FEXCore/Source/Interface/Core/JIT/Arm64/MemoryOps.cpp @@ -86,17 +86,13 @@ DEF_OP(LoadRegister) { const auto OpSize = IROp->Size; if (Op->Class == IR::GPRClass) { - const auto regId = Op->Offset == offsetof(Core::CpuStateFrame, State.pf_raw) ? - (StaticRegisters.size() - 2) : - Op->Offset == offsetof(Core::CpuStateFrame, State.af_raw) ? - (StaticRegisters.size() - 1) : - (Op->Offset - offsetof(Core::CpuStateFrame, State.gregs[0])) / Core::CPUState::GPR_REG_SIZE; + unsigned Reg = Op->Reg == Core::CPUState::PF_AS_GREG ? (StaticRegisters.size() - 2) : + Op->Reg == Core::CPUState::AF_AS_GREG ? (StaticRegisters.size() - 1) : + Op->Reg; - LOGMAN_THROW_A_FMT(regId < StaticRegisters.size(), "out of range regId"); + LOGMAN_THROW_A_FMT(Reg < StaticRegisters.size(), "out of range reg"); + const auto reg = StaticRegisters[Reg]; - const auto reg = StaticRegisters[regId]; - - LOGMAN_THROW_AA_FMT((Op->Offset & 7) == 0, "expected aligned"); if (GetReg(Node).Idx() != reg.Idx()) { if (OpSize == 4) { mov(GetReg(Node).W(), reg.W()); @@ -106,13 +102,10 @@ DEF_OP(LoadRegister) { } } else if (Op->Class == IR::FPRClass) { const auto regSize = HostSupportsSVE256 ? Core::CPUState::XMM_AVX_REG_SIZE : Core::CPUState::XMM_SSE_REG_SIZE; - const auto regId = (Op->Offset - offsetof(Core::CpuStateFrame, State.xmm.avx.data[0][0])) / regSize; - - LOGMAN_THROW_A_FMT(regId < StaticFPRegisters.size(), "out of range regId"); + LOGMAN_THROW_A_FMT(Op->Reg < StaticFPRegisters.size(), "out of range reg"); LOGMAN_THROW_A_FMT(OpSize == regSize, "expected sized"); - LOGMAN_THROW_A_FMT((Op->Offset & (regSize - 1)) == 0, "expected aligned"); - const auto guest = StaticFPRegisters[regId]; + const auto guest = StaticFPRegisters[Op->Reg]; const auto host = GetVReg(Node); if (host.Idx() != guest.Idx()) { @@ -131,19 +124,14 @@ DEF_OP(StoreRegister) { const auto Op = IROp->C(); const auto OpSize = IROp->Size; + if (Op->Class == IR::GPRClass) { - const auto regOffs = Op->Offset & 7; - LOGMAN_THROW_AA_FMT(regOffs == 0, "unexpected regOffs"); + unsigned Reg = Op->Reg == Core::CPUState::PF_AS_GREG ? (StaticRegisters.size() - 2) : + Op->Reg == Core::CPUState::AF_AS_GREG ? (StaticRegisters.size() - 1) : + Op->Reg; - const auto regId = Op->Offset == offsetof(Core::CpuStateFrame, State.pf_raw) ? - (StaticRegisters.size() - 2) : - Op->Offset == offsetof(Core::CpuStateFrame, State.af_raw) ? - (StaticRegisters.size() - 1) : - (Op->Offset - offsetof(Core::CpuStateFrame, State.gregs[0])) / Core::CPUState::GPR_REG_SIZE; - - LOGMAN_THROW_A_FMT(regId < StaticRegisters.size(), "out of range regId"); - - const auto reg = StaticRegisters[regId]; + LOGMAN_THROW_A_FMT(Reg < StaticRegisters.size(), "out of range reg"); + const auto reg = StaticRegisters[Reg]; const auto Src = GetReg(Op->Value.ID()); if (Src.Idx() != reg.Idx()) { @@ -151,13 +139,10 @@ DEF_OP(StoreRegister) { } } else if (Op->Class == IR::FPRClass) { const auto regSize = HostSupportsSVE256 ? Core::CPUState::XMM_AVX_REG_SIZE : Core::CPUState::XMM_SSE_REG_SIZE; - const auto regId = (Op->Offset - offsetof(Core::CpuStateFrame, State.xmm.avx.data[0][0])) / regSize; - - LOGMAN_THROW_A_FMT(regId < StaticFPRegisters.size(), "regId out of range"); + LOGMAN_THROW_A_FMT(Op->Reg < StaticFPRegisters.size(), "reg out of range"); LOGMAN_THROW_A_FMT(OpSize == regSize, "expected sized"); - LOGMAN_THROW_A_FMT((Op->Offset & (regSize - 1)) == 0, "expected aligned"); - const auto guest = StaticFPRegisters[regId]; + const auto guest = StaticFPRegisters[Op->Reg]; const auto host = GetVReg(Op->Value.ID()); if (guest.Idx() != host.Idx()) { diff --git a/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp b/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp index eded43dee..de6d7b71e 100644 --- a/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp +++ b/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp @@ -3396,8 +3396,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(Src1, offsetof(FEXCore::Core::CPUState, pf_raw), GPRClass, CTX->GetGPRSize()); - _StoreRegister(Src2, offsetof(FEXCore::Core::CPUState, af_raw), GPRClass, CTX->GetGPRSize()); + _StoreRegister(Src1, Core::CPUState::PF_AS_GREG, GPRClass, CTX->GetGPRSize()); + _StoreRegister(Src2, Core::CPUState::AF_AS_GREG, GPRClass, CTX->GetGPRSize()); OrderedNode* TailCounter = LoadGPRRegister(X86State::REG_RCX); @@ -3436,8 +3436,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 = _LoadRegister(offsetof(FEXCore::Core::CPUState, pf_raw), GPRClass, CTX->GetGPRSize()); - auto Src2 = _LoadRegister(offsetof(FEXCore::Core::CPUState, af_raw), GPRClass, CTX->GetGPRSize()); + 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); CalculateDeferredFlags(); } @@ -4406,7 +4406,7 @@ OrderedNode* OpDispatchBuilder::LoadGPRRegister(uint32_t GPR, int8_t Size, uint8 if (Size == -1) { Size = GPRSize; } - OrderedNode* Reg = _LoadRegister(offsetof(FEXCore::Core::CPUState, gregs[GPR]), GPRClass, GPRSize); + OrderedNode* Reg = _LoadRegister(GPR, GPRClass, GPRSize); if ((!AllowUpperGarbage && (Size != GPRSize)) || Offset != 0) { // Extract the subregister if requested. @@ -4422,11 +4422,7 @@ OrderedNode* OpDispatchBuilder::LoadGPRRegister(uint32_t GPR, int8_t Size, uint8 OrderedNode* OpDispatchBuilder::LoadXMMRegister(uint32_t XMM) { const auto VectorSize = CTX->HostFeatures.SupportsAVX ? 32 : 16; - const auto VectorOffset = - CTX->HostFeatures.SupportsAVX ? offsetof(Core::CPUState, xmm.avx.data[XMM][0]) : offsetof(Core::CPUState, xmm.sse.data[XMM][0]); - - OrderedNode* Reg = _LoadRegister(VectorOffset, FPRClass, VectorSize); - return Reg; + return _LoadRegister(XMM, FPRClass, VectorSize); } void OpDispatchBuilder::StoreGPRRegister(uint32_t GPR, OrderedNode* const Src, int8_t Size, uint8_t Offset) { @@ -4442,15 +4438,12 @@ void OpDispatchBuilder::StoreGPRRegister(uint32_t GPR, OrderedNode* const Src, i Reg = _Bfi(IR::SizeToOpSize(GPRSize), Size * 8, Offset, Reg, Src); } - _StoreRegister(Reg, offsetof(FEXCore::Core::CPUState, gregs[GPR]), GPRClass, GPRSize); + _StoreRegister(Reg, GPR, GPRClass, GPRSize); } void OpDispatchBuilder::StoreXMMRegister(uint32_t XMM, OrderedNode* const Src) { const auto VectorSize = CTX->HostFeatures.SupportsAVX ? 32 : 16; - const auto VectorOffset = - CTX->HostFeatures.SupportsAVX ? offsetof(Core::CPUState, xmm.avx.data[XMM][0]) : offsetof(Core::CPUState, xmm.sse.data[XMM][0]); - - _StoreRegister(Src, VectorOffset, FPRClass, VectorSize); + _StoreRegister(Src, XMM, FPRClass, VectorSize); } OrderedNode* OpDispatchBuilder::LoadSource(RegisterClassType Class, const X86Tables::DecodedOp& Op, diff --git a/FEXCore/Source/Interface/Core/OpcodeDispatcher.h b/FEXCore/Source/Interface/Core/OpcodeDispatcher.h index e0ab182e9..6515b6d98 100644 --- a/FEXCore/Source/Interface/Core/OpcodeDispatcher.h +++ b/FEXCore/Source/Interface/Core/OpcodeDispatcher.h @@ -1402,9 +1402,9 @@ private: if (IsNZCV(BitOffset)) { InsertNZCV(BitOffset, Value, ValueOffset, MustMask); } else if (BitOffset == FEXCore::X86State::RFLAG_PF_RAW_LOC) { - _StoreRegister(Value, offsetof(FEXCore::Core::CPUState, pf_raw), GPRClass, CTX->GetGPRSize()); + _StoreRegister(Value, Core::CPUState::PF_AS_GREG, GPRClass, CTX->GetGPRSize()); } else if (BitOffset == FEXCore::X86State::RFLAG_AF_RAW_LOC) { - _StoreRegister(Value, offsetof(FEXCore::Core::CPUState, af_raw), GPRClass, CTX->GetGPRSize()); + _StoreRegister(Value, Core::CPUState::AF_AS_GREG, GPRClass, CTX->GetGPRSize()); } else { if (ValueOffset || MustMask) { Value = _Bfe(OpSize::i32Bit, 1, ValueOffset, Value); @@ -1459,9 +1459,9 @@ private: return _NZCVSelect(OpSize::i32Bit, CondForNZCVBit(BitOffset, Invert), _Constant(1), _Constant(0)); } } else if (BitOffset == FEXCore::X86State::RFLAG_PF_RAW_LOC) { - return _LoadRegister(offsetof(FEXCore::Core::CPUState, pf_raw), GPRClass, CTX->GetGPRSize()); + return _LoadRegister(Core::CPUState::PF_AS_GREG, GPRClass, CTX->GetGPRSize()); } else if (BitOffset == FEXCore::X86State::RFLAG_AF_RAW_LOC) { - return _LoadRegister(offsetof(FEXCore::Core::CPUState, af_raw), GPRClass, CTX->GetGPRSize()); + 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)); diff --git a/FEXCore/Source/Interface/HLE/Thunks/Thunks.cpp b/FEXCore/Source/Interface/HLE/Thunks/Thunks.cpp index b473532a4..f674eb56e 100644 --- a/FEXCore/Source/Interface/HLE/Thunks/Thunks.cpp +++ b/FEXCore/Source/Interface/HLE/Thunks/Thunks.cpp @@ -227,7 +227,7 @@ struct ThunkHandler_impl final : public ThunkHandler { const uint8_t GPRSize = CTX->GetGPRSize(); if (GPRSize == 8) { - emit->_StoreRegister(emit->_Constant(Entrypoint), offsetof(Core::CPUState, gregs[X86State::REG_R11]), IR::GPRClass, GPRSize); + emit->_StoreRegister(emit->_Constant(Entrypoint), X86State::REG_R11, IR::GPRClass, GPRSize); } else { emit->_StoreContext(GPRSize, IR::FPRClass, emit->_VCastFromGPR(8, 8, emit->_Constant(Entrypoint)), offsetof(Core::CPUState, mm[0][0])); } diff --git a/FEXCore/Source/Interface/IR/IR.json b/FEXCore/Source/Interface/IR/IR.json index 28575b1b1..3538fb8f5 100644 --- a/FEXCore/Source/Interface/IR/IR.json +++ b/FEXCore/Source/Interface/IR/IR.json @@ -343,17 +343,14 @@ } }, "StaticRA": { - "SSA = LoadRegister u32:$Offset, RegisterClass:$Class, u8:#Size": { - "Desc": ["Loads a value from the static-ra context with offset", - "Dest = Ctx[Offset]" - ], + "SSA = LoadRegister u32:$Reg, RegisterClass:$Class, u8:#Size": { + "Desc": ["Loads a value from the given register"], "DestSize": "Size" }, - "StoreRegister SSA:$Value, u32:$Offset, RegisterClass:$Class, u8:#Size": { + "StoreRegister SSA:$Value, u32:$Reg, RegisterClass:$Class, u8:#Size": { "HasSideEffects": true, - "Desc": ["Stores a value to the static-ra context with offset", - "Ctx[Offset] = Value", + "Desc": ["Stores a value to a given register", "Zero Extends if value's type is too small", "Truncates if value's type is too large" ], diff --git a/FEXCore/Source/Interface/IR/Passes/DeadContextStoreElimination.cpp b/FEXCore/Source/Interface/IR/Passes/DeadContextStoreElimination.cpp index 9fca6ea6d..3f6f69a93 100644 --- a/FEXCore/Source/Interface/IR/Passes/DeadContextStoreElimination.cpp +++ b/FEXCore/Source/Interface/IR/Passes/DeadContextStoreElimination.cpp @@ -495,6 +495,18 @@ private: // Block local Passes bool RedundantStoreLoadElimination(FEXCore::IR::IREmitter* IREmit); + + unsigned OffsetForReg(FEXCore::IR::RegisterClassType Class, unsigned Reg, unsigned Size) { + if (Class == FEXCore::IR::FPRClass) { + return Size == 32 ? offsetof(FEXCore::Core::CPUState, xmm.avx.data[Reg][0]) : offsetof(FEXCore::Core::CPUState, xmm.sse.data[Reg][0]); + } else if (Reg == FEXCore::Core::CPUState::PF_AS_GREG) { + return offsetof(FEXCore::Core::CPUState, pf_raw); + } else if (Reg == FEXCore::Core::CPUState::AF_AS_GREG) { + return offsetof(FEXCore::Core::CPUState, af_raw); + } else { + return offsetof(FEXCore::Core::CPUState, gregs[Reg]); + } + } }; ContextMemberInfo* RCLSE::FindMemberInfo(ContextInfo* ContextClassificationInfo, uint32_t Offset, uint8_t Size) { @@ -648,10 +660,13 @@ bool RCLSE::RedundantStoreLoadElimination(FEXCore::IR::IREmitter* IREmit) { Changed |= ClassifyContextStore(IREmit, &LocalInfo, Op->Class, Op->Offset, IROp->Size, CodeNode, CurrentIR.GetNode(Op->Value)); } else if (IROp->Op == OP_STOREREGISTER) { auto Op = IROp->CW(); - Changed |= ClassifyContextStore(IREmit, &LocalInfo, Op->Class, Op->Offset, IROp->Size, CodeNode, CurrentIR.GetNode(Op->Value)); + auto Offset = OffsetForReg(Op->Class, Op->Reg, IROp->Size); + + Changed |= ClassifyContextStore(IREmit, &LocalInfo, Op->Class, Offset, IROp->Size, CodeNode, CurrentIR.GetNode(Op->Value)); } else if (IROp->Op == OP_LOADREGISTER) { auto Op = IROp->CW(); - Changed |= ClassifyContextLoad(IREmit, &LocalInfo, Op->Class, Op->Offset, IROp->Size, CodeNode, BlockEnd); + auto Offset = OffsetForReg(Op->Class, Op->Reg, IROp->Size); + Changed |= ClassifyContextLoad(IREmit, &LocalInfo, Op->Class, Offset, IROp->Size, CodeNode, BlockEnd); } else if (IROp->Op == OP_LOADCONTEXT) { auto Op = IROp->CW(); Changed |= ClassifyContextLoad(IREmit, &LocalInfo, Op->Class, Op->Offset, IROp->Size, CodeNode, BlockEnd); diff --git a/FEXCore/Source/Interface/IR/Passes/DeadStoreElimination.cpp b/FEXCore/Source/Interface/IR/Passes/DeadStoreElimination.cpp index 01929d12a..cd447783a 100644 --- a/FEXCore/Source/Interface/IR/Passes/DeadStoreElimination.cpp +++ b/FEXCore/Source/Interface/IR/Passes/DeadStoreElimination.cpp @@ -90,6 +90,18 @@ private: return 7UL << (bitn); // Return maximum on failure case } + + unsigned OffsetForReg(FEXCore::IR::RegisterClassType Class, unsigned Reg, unsigned Size) { + if (Class == FEXCore::IR::FPRClass) { + return Size == 32 ? offsetof(FEXCore::Core::CPUState, xmm.avx.data[Reg][0]) : offsetof(FEXCore::Core::CPUState, xmm.sse.data[Reg][0]); + } else if (Reg == FEXCore::Core::CPUState::PF_AS_GREG) { + return offsetof(FEXCore::Core::CPUState, pf_raw); + } else if (Reg == FEXCore::Core::CPUState::AF_AS_GREG) { + return offsetof(FEXCore::Core::CPUState, af_raw); + } else { + return offsetof(FEXCore::Core::CPUState, gregs[Reg]); + } + } }; struct FlagInfo { @@ -224,14 +236,16 @@ bool DeadStoreElimination::Run(IREmitter* IREmit) { BlockInfo.flag.reads |= 1UL << X86State::RFLAG_DF_RAW_LOC; } else if (IROp->Op == OP_STOREREGISTER) { auto Op = IROp->C(); + auto Offset = OffsetForReg(Op->Class, Op->Reg, IROp->Size); auto& BlockInfo = InfoMap[BlockNode]; - ClassifyRegisterStore(BlockInfo, Op->Offset, IROp->Size); + ClassifyRegisterStore(BlockInfo, Offset, IROp->Size); } else if (IROp->Op == OP_LOADREGISTER) { auto Op = IROp->C(); + auto Offset = OffsetForReg(Op->Class, Op->Reg, IROp->Size); auto& BlockInfo = InfoMap[BlockNode]; - ClassifyRegisterLoad(BlockInfo, Op->Offset, IROp->Size); + ClassifyRegisterLoad(BlockInfo, Offset, IROp->Size); } } } @@ -360,10 +374,11 @@ bool DeadStoreElimination::Run(IREmitter* IREmit) { } } else if (IROp->Op == OP_STOREREGISTER) { auto Op = IROp->C(); + auto Offset = OffsetForReg(Op->Class, Op->Reg, IROp->Size); auto& BlockInfo = InfoMap[BlockNode]; - Changed |= RemoveDeadRegisterStore(IREmit, CodeNode, BlockInfo, Op->Offset, IROp->Size); + Changed |= RemoveDeadRegisterStore(IREmit, CodeNode, BlockInfo, Offset, IROp->Size); } } } diff --git a/FEXCore/Source/Interface/IR/Passes/RedundantFlagCalculationElimination.cpp b/FEXCore/Source/Interface/IR/Passes/RedundantFlagCalculationElimination.cpp index 09604ab8d..23277a8d1 100644 --- a/FEXCore/Source/Interface/IR/Passes/RedundantFlagCalculationElimination.cpp +++ b/FEXCore/Source/Interface/IR/Passes/RedundantFlagCalculationElimination.cpp @@ -57,12 +57,12 @@ public: private: FlagInfo Classify(IROp_Header* Node); - unsigned FlagForOffset(unsigned Offset); + unsigned FlagForReg(unsigned Reg); unsigned FlagsForCondClassType(CondClassType Cond); }; -unsigned DeadFlagCalculationEliminination::FlagForOffset(unsigned Offset) { - return Offset == offsetof(FEXCore::Core::CPUState, pf_raw) ? FLAG_P : Offset == offsetof(FEXCore::Core::CPUState, af_raw) ? FLAG_A : 0; +unsigned DeadFlagCalculationEliminination::FlagForReg(unsigned Reg) { + return Reg == Core::CPUState::PF_AS_GREG ? FLAG_P : Reg == Core::CPUState::AF_AS_GREG ? FLAG_A : 0; }; unsigned DeadFlagCalculationEliminination::FlagsForCondClassType(CondClassType Cond) { @@ -287,7 +287,7 @@ FlagInfo DeadFlagCalculationEliminination::Classify(IROp_Header* IROp) { break; } - return {.Read = FlagForOffset(Op->Offset)}; + return {.Read = FlagForReg(Op->Reg)}; } case OP_STOREREGISTER: { @@ -296,7 +296,7 @@ FlagInfo DeadFlagCalculationEliminination::Classify(IROp_Header* IROp) { break; } - unsigned Flag = FlagForOffset(Op->Offset); + unsigned Flag = FlagForReg(Op->Reg); return { .Write = Flag, diff --git a/FEXCore/Source/Interface/IR/Passes/RegisterAllocationPass.cpp b/FEXCore/Source/Interface/IR/Passes/RegisterAllocationPass.cpp index 0ee198b71..429e2fda9 100644 --- a/FEXCore/Source/Interface/IR/Passes/RegisterAllocationPass.cpp +++ b/FEXCore/Source/Interface/IR/Passes/RegisterAllocationPass.cpp @@ -475,84 +475,10 @@ void ConstrainedRAPass::OptimizeStaticRegisters(FEXCore::IR::IRListView* IR) { return false; // Unknown }; - const auto GetFPRBeginAndEnd = [this]() -> std::pair { - if (SupportsAVX) { - return { - offsetof(FEXCore::Core::CpuStateFrame, State.xmm.avx.data[0][0]), - offsetof(FEXCore::Core::CpuStateFrame, State.xmm.avx.data[16][0]), - }; - } else { - return { - offsetof(FEXCore::Core::CpuStateFrame, State.xmm.sse.data[0][0]), - offsetof(FEXCore::Core::CpuStateFrame, State.xmm.sse.data[16][0]), - }; - } - }; - - // Get SRA Reg and Class from a Context offset - const auto GetRegAndClassFromOffset = [&, this](uint32_t Offset) { - const auto beginGpr = offsetof(FEXCore::Core::CpuStateFrame, State.gregs[0]); - const auto endGpr = offsetof(FEXCore::Core::CpuStateFrame, State.gregs[16]); - const auto pf = offsetof(FEXCore::Core::CpuStateFrame, State.pf_raw); - const auto af = offsetof(FEXCore::Core::CpuStateFrame, State.af_raw); - - const auto [beginFpr, endFpr] = GetFPRBeginAndEnd(); - - LOGMAN_THROW_AA_FMT((Offset >= beginGpr && Offset < endGpr) || (Offset >= beginFpr && Offset < endFpr) || (Offset == pf) || (Offset == af), - "Unexpected Offset {}", Offset); - - unsigned FlagOffset = Graph->Set.Classes[GPRFixedClass.Val].PhysicalCount - 2; - - if (Offset == pf) { - return PhysicalRegister(GPRFixedClass, FlagOffset); - } else if (Offset == af) { - return PhysicalRegister(GPRFixedClass, FlagOffset + 1); - } else if (Offset >= beginGpr && Offset < endGpr) { - auto reg = (Offset - beginGpr) / Core::CPUState::GPR_REG_SIZE; - return PhysicalRegister(GPRFixedClass, reg); - } else if (Offset >= beginFpr && Offset < endFpr) { - const auto size = SupportsAVX ? Core::CPUState::XMM_AVX_REG_SIZE : Core::CPUState::XMM_SSE_REG_SIZE; - const auto reg = (Offset - beginFpr) / size; - return PhysicalRegister(FPRFixedClass, reg); - } - - return PhysicalRegister::Invalid(); - }; - auto GprSize = Graph->Set.Classes[GPRFixedClass.Val].PhysicalCount; auto MapsSize = Graph->Set.Classes[GPRFixedClass.Val].PhysicalCount + Graph->Set.Classes[FPRFixedClass.Val].PhysicalCount; StaticMaps.resize(MapsSize); - // Get a StaticMap entry from context offset - const auto GetStaticMapFromOffset = [&](uint32_t Offset) -> LiveRange** { - const auto beginGpr = offsetof(FEXCore::Core::CpuStateFrame, State.gregs[0]); - const auto endGpr = offsetof(FEXCore::Core::CpuStateFrame, State.gregs[16]); - const auto pf = offsetof(FEXCore::Core::CpuStateFrame, State.pf_raw); - const auto af = offsetof(FEXCore::Core::CpuStateFrame, State.af_raw); - - const auto [beginFpr, endFpr] = GetFPRBeginAndEnd(); - - LOGMAN_THROW_AA_FMT((Offset >= beginGpr && Offset < endGpr) || (Offset >= beginFpr && Offset < endFpr) || (Offset == pf) || (Offset == af), - "Unexpected Offset {}", Offset); - - unsigned FlagOffset = Graph->Set.Classes[GPRFixedClass.Val].PhysicalCount - 2; - - if (Offset == pf) { - return &StaticMaps[FlagOffset]; - } else if (Offset == af) { - return &StaticMaps[FlagOffset + 1]; - } else if (Offset >= beginGpr && Offset < endGpr) { - auto reg = (Offset - beginGpr) / Core::CPUState::GPR_REG_SIZE; - return &StaticMaps[reg]; - } else if (Offset >= beginFpr && Offset < endFpr) { - const auto size = SupportsAVX ? Core::CPUState::XMM_AVX_REG_SIZE : Core::CPUState::XMM_SSE_REG_SIZE; - const auto reg = (Offset - beginFpr) / size; - return &StaticMaps[GprSize + reg]; - } - - return nullptr; - }; - // Get a StaticMap entry from reg and class const auto GetStaticMapFromReg = [&](IR::PhysicalRegister PhyReg) -> LiveRange** { LOGMAN_THROW_A_FMT(PhyReg.Class == GPRFixedClass.Val || PhyReg.Class == FPRFixedClass.Val, "Unexpected Class {}", PhyReg.Class); @@ -566,6 +492,20 @@ void ConstrainedRAPass::OptimizeStaticRegisters(FEXCore::IR::IRListView* IR) { return nullptr; }; + const auto GetRegForSRA = [&](auto Class, auto Reg) { + unsigned FlagOffset = Graph->Set.Classes[GPRFixedClass.Val].PhysicalCount - 2; + + if (Class == FPRClass) { + return PhysicalRegister(FPRFixedClass, Reg); + } else if (Reg == Core::CPUState::PF_AS_GREG) { + return PhysicalRegister(GPRFixedClass, FlagOffset); + } else if (Reg == Core::CPUState::AF_AS_GREG) { + return PhysicalRegister(GPRFixedClass, FlagOffset + 1); + } else { + return PhysicalRegister(GPRFixedClass, Reg); + } + }; + // First pass: Mark pre-writes for (auto [BlockNode, BlockHeader] : IR->GetBlocks()) { for (auto [CodeNode, IROp] : IR->GetCode(BlockNode)) { @@ -577,12 +517,11 @@ void ConstrainedRAPass::OptimizeStaticRegisters(FEXCore::IR::IRListView* IR) { auto& OpLiveRange = LiveRanges[OpID.Value]; if (IsPreWritable(IROp->Size, Op->Class) && OpLiveRange.PrefferedRegister.IsInvalid() && !OpLiveRange.Global) { - // Pre-write and sra-allocate in the defining node - this might be undone if a read before the actual store happens SRA_DEBUG("Prewritting ssa{} (Store in ssa{})\n", OpID, Node); - OpLiveRange.PrefferedRegister = GetRegAndClassFromOffset(Op->Offset); + OpLiveRange.PrefferedRegister = GetRegForSRA(Op->Class, Op->Reg); OpLiveRange.PreWritten = Node; - SetNodeClass(Graph, OpID, Op->Class == FPRClass ? FPRFixedClass : GPRFixedClass); + SetNodeClass(Graph, OpID, RegisterClassType {OpLiveRange.PrefferedRegister.Class}); } } } @@ -648,7 +587,8 @@ void ConstrainedRAPass::OptimizeStaticRegisters(FEXCore::IR::IRListView* IR) { if (IROp->Op == OP_LOADREGISTER) { auto Op = IROp->C(); - auto StaticMap = GetStaticMapFromOffset(Op->Offset); + auto Reg = GetRegForSRA(Op->Class, Op->Reg); + auto StaticMap = GetStaticMapFromReg(Reg); // Make sure there wasn't a store pre-written before this read if ((*StaticMap) && (*StaticMap)->PreWritten.IsValid()) { @@ -672,9 +612,9 @@ void ConstrainedRAPass::OptimizeStaticRegisters(FEXCore::IR::IRListView* IR) { (*StaticMap)->Written = true; } - NodeLiveRange.PrefferedRegister = GetRegAndClassFromOffset(Op->Offset); // 0, 1, and so on + NodeLiveRange.PrefferedRegister = Reg; (*StaticMap) = &NodeLiveRange; - SetNodeClass(Graph, Node, Op->Class == FPRClass ? FPRFixedClass : GPRFixedClass); + SetNodeClass(Graph, Node, RegisterClassType {NodeLiveRange.PrefferedRegister.Class}); SRA_DEBUG("Marking ssa{} as allocated to sra{}\n", Node, -1 /*vreg*/); } } @@ -688,7 +628,8 @@ void ConstrainedRAPass::OptimizeStaticRegisters(FEXCore::IR::IRListView* IR) { const auto OpID = Op->Value.ID(); auto& OpLiveRange = LiveRanges[OpID.Value]; - auto StaticMap = GetStaticMapFromOffset(Op->Offset); + auto Reg = GetRegForSRA(Op->Class, Op->Reg); + auto StaticMap = GetStaticMapFromReg(Reg); // if a read pending, it has been writting if ((*StaticMap)) { // writes to self don't invalidate the span diff --git a/FEXCore/include/FEXCore/Core/CoreState.h b/FEXCore/include/FEXCore/Core/CoreState.h index 3a7ff0583..6fec0ec0e 100644 --- a/FEXCore/include/FEXCore/Core/CoreState.h +++ b/FEXCore/include/FEXCore/Core/CoreState.h @@ -120,6 +120,11 @@ struct CPUState { // Since this memory region is thread local, we use NonAtomicRefCounter for fast atomic access. NonAtomicRefCounter* DeferredSignalFaultAddress; + // PF/AF are statically mapped as-if they were r16/r17 (which do not exist in + // x86 otherwise). This allows a straightforward mapping for SRA. + static constexpr uint8_t PF_AS_GREG = 16; + static constexpr uint8_t AF_AS_GREG = 17; + static constexpr size_t FLAG_SIZE = sizeof(flags[0]); static constexpr size_t GDT_SIZE = sizeof(gdt[0]); static constexpr size_t GPR_REG_SIZE = sizeof(gregs[0]);