diff --git a/External/FEXCore/Source/Interface/Core/ArchHelpers/Arm64Emitter.cpp b/External/FEXCore/Source/Interface/Core/ArchHelpers/Arm64Emitter.cpp index 5a08021a8..8e9204d1c 100644 --- a/External/FEXCore/Source/Interface/Core/ArchHelpers/Arm64Emitter.cpp +++ b/External/FEXCore/Source/Interface/Core/ArchHelpers/Arm64Emitter.cpp @@ -25,6 +25,26 @@ Arm64Emitter::Arm64Emitter(FEXCore::Context::ContextImpl *ctx, size_t size) : Emitter(size ? (uint8_t*)FEXCore::Allocator::mmap(nullptr, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) : nullptr, size) , EmitterCTX {ctx} { CPU.SetUp(); + + // Number of register available is dependent on what operating mode the proccess is in. + if (EmitterCTX->Config.Is64BitMode()) { + ConfiguredGPRs = NumGPRs64; + ConfiguredSRAGPRs = NumSRAGPRs64; + ConfiguredGPRPairs = NumGPRPairs64; + ConfiguredFPRs = NumFPRs64; + ConfiguredSRAFPRs = NumSRAFPRs64; + ConfiguredDynamicGPRs = NumGPRs64 - NumGPRs64; // Will be zero, just to be consistent with 32-bit side + ConfiguredDynamicRegisterBase = nullptr; + } + else { + ConfiguredGPRs = NumGPRs32; + ConfiguredSRAGPRs = NumSRAGPRs32; + ConfiguredGPRPairs = NumGPRPairs32; + ConfiguredFPRs = NumFPRs32; + ConfiguredSRAFPRs = NumSRAFPRs32; + ConfiguredDynamicGPRs = NumGPRs32 - NumGPRs64; // Will be 8 + ConfiguredDynamicRegisterBase = &RA64[9]; + } } Arm64Emitter::~Arm64Emitter() { @@ -195,7 +215,7 @@ void Arm64Emitter::SpillStaticRegs(bool FPRs, uint32_t GPRSpillMask, uint32_t FP return; } - for (size_t i = 0; i < SRA64.size(); i+=2) { + for (size_t i = 0; i < ConfiguredSRAGPRs; i+=2) { auto Reg1 = SRA64[i]; auto Reg2 = SRA64[i+1]; if (((1U << Reg1.Idx()) & GPRSpillMask) && @@ -212,7 +232,7 @@ void Arm64Emitter::SpillStaticRegs(bool FPRs, uint32_t GPRSpillMask, uint32_t FP if (FPRs) { if (EmitterCTX->HostFeatures.SupportsAVX) { - for (size_t i = 0; i < SRAFPR.size(); i++) { + for (size_t i = 0; i < ConfiguredSRAFPRs; i++) { const auto Reg = SRAFPR[i]; if (((1U << Reg.Idx()) & FPRSpillMask) != 0) { @@ -227,7 +247,7 @@ void Arm64Emitter::SpillStaticRegs(bool FPRs, uint32_t GPRSpillMask, uint32_t FP // Load the sse offset in to the temporary register add(ARMEmitter::Size::i64Bit, TmpReg, STATE.R(), offsetof(FEXCore::Core::CpuStateFrame, State.xmm.sse.data[0][0])); - for (size_t i = 0; i < SRAFPR.size(); i += 4) { + for (size_t i = 0; i < ConfiguredSRAFPRs; i += 4) { const auto Reg1 = SRAFPR[i]; const auto Reg2 = SRAFPR[i + 1]; const auto Reg3 = SRAFPR[i + 2]; @@ -236,7 +256,7 @@ void Arm64Emitter::SpillStaticRegs(bool FPRs, uint32_t GPRSpillMask, uint32_t FP } } else { - for (size_t i = 0; i < SRAFPR.size(); i += 2) { + for (size_t i = 0; i < ConfiguredSRAFPRs; i += 2) { const auto Reg1 = SRAFPR[i]; const auto Reg2 = SRAFPR[i + 1]; @@ -270,7 +290,7 @@ void Arm64Emitter::FillStaticRegs(bool FPRs, uint32_t GPRFillMask, uint32_t FPRF ptrue(PRED_TMP_16B, ARMEmitter::PredicatePattern::SVE_VL16); ptrue(PRED_TMP_32B, ARMEmitter::PredicatePattern::SVE_VL32); - for (size_t i = 0; i < SRAFPR.size(); i++) { + for (size_t i = 0; i < ConfiguredSRAFPRs; i++) { const auto Reg = SRAFPR[i]; if (((1U << Reg.Idx()) & FPRFillMask) != 0) { mov(ARMEmitter::Size::i64Bit, TMP4.R(), offsetof(Core::CpuStateFrame, State.xmm.avx.data[i][0])); @@ -285,7 +305,7 @@ void Arm64Emitter::FillStaticRegs(bool FPRs, uint32_t GPRFillMask, uint32_t FPRF // Load the sse offset in to the temporary register add(ARMEmitter::Size::i64Bit, TmpReg, STATE.R(), offsetof(FEXCore::Core::CpuStateFrame, State.xmm.sse.data[0][0])); - for (size_t i = 0; i < SRAFPR.size(); i += 4) { + for (size_t i = 0; i < ConfiguredSRAFPRs; i += 4) { const auto Reg1 = SRAFPR[i]; const auto Reg2 = SRAFPR[i + 1]; const auto Reg3 = SRAFPR[i + 2]; @@ -294,7 +314,7 @@ void Arm64Emitter::FillStaticRegs(bool FPRs, uint32_t GPRFillMask, uint32_t FPRF } } else { - for (size_t i = 0; i < SRAFPR.size(); i += 2) { + for (size_t i = 0; i < ConfiguredSRAFPRs; i += 2) { const auto Reg1 = SRAFPR[i]; const auto Reg2 = SRAFPR[i + 1]; @@ -313,7 +333,7 @@ void Arm64Emitter::FillStaticRegs(bool FPRs, uint32_t GPRFillMask, uint32_t FPRF } } - for (size_t i = 0; i < SRA64.size(); i+=2) { + for (size_t i = 0; i < ConfiguredSRAGPRs; i+=2) { auto Reg1 = SRA64[i]; auto Reg2 = SRA64[i+1]; if (((1U << Reg1.Idx()) & GPRFillMask) && @@ -331,10 +351,10 @@ void Arm64Emitter::FillStaticRegs(bool FPRs, uint32_t GPRFillMask, uint32_t FPRF void Arm64Emitter::PushDynamicRegsAndLR(FEXCore::ARMEmitter::Register TmpReg) { const auto CanUseSVE = EmitterCTX->HostFeatures.SupportsAVX; - const auto GPRSize = 1 * Core::CPUState::GPR_REG_SIZE; + const auto GPRSize = (ConfiguredDynamicGPRs + 1) * Core::CPUState::GPR_REG_SIZE; const auto FPRRegSize = CanUseSVE ? Core::CPUState::XMM_AVX_REG_SIZE : Core::CPUState::XMM_SSE_REG_SIZE; - const auto FPRSize = RAFPR.size() * FPRRegSize; + const auto FPRSize = ConfiguredFPRs * FPRRegSize; const uint64_t SPOffset = AlignUp(GPRSize + FPRSize, 16); sub(ARMEmitter::Size::i64Bit, ARMEmitter::Reg::rsp, ARMEmitter::Reg::rsp, SPOffset); @@ -343,7 +363,7 @@ void Arm64Emitter::PushDynamicRegsAndLR(FEXCore::ARMEmitter::Register TmpReg) { add(ARMEmitter::Size::i64Bit, TmpReg, ARMEmitter::Reg::rsp, 0); if (CanUseSVE) { - for (size_t i = 0; i < RAFPR.size(); i += 4) { + for (size_t i = 0; i < ConfiguredFPRs; i += 4) { const auto Reg1 = RAFPR[i]; const auto Reg2 = RAFPR[i + 1]; const auto Reg3 = RAFPR[i + 2]; @@ -352,8 +372,8 @@ void Arm64Emitter::PushDynamicRegsAndLR(FEXCore::ARMEmitter::Register TmpReg) { add(ARMEmitter::Size::i64Bit, TmpReg, TmpReg, 32 * 4); } } else { - static_assert(RAFPR.size() % 4 == 0, "Needs to have multiple of 4 FPRs for RA"); - for (size_t i = 0; i < RAFPR.size(); i += 4) { + LOGMAN_THROW_AA_FMT(ConfiguredFPRs % 4 == 0, "Needs to have multiple of 4 FPRs for RA"); + for (size_t i = 0; i < ConfiguredFPRs; i += 4) { const auto Reg1 = RAFPR[i]; const auto Reg2 = RAFPR[i + 1]; const auto Reg3 = RAFPR[i + 2]; @@ -362,6 +382,14 @@ void Arm64Emitter::PushDynamicRegsAndLR(FEXCore::ARMEmitter::Register TmpReg) { } } + if (ConfiguredDynamicRegisterBase) { + for (size_t i = 0; i < ConfiguredDynamicGPRs; i += 2) { + const auto Reg1 = ConfiguredDynamicRegisterBase[i]; + const auto Reg2 = ConfiguredDynamicRegisterBase[i + 1]; + stp(Reg1.X(), Reg2.X(), TmpReg, 16); + } + } + str(ARMEmitter::XReg::lr, TmpReg, 0); } @@ -369,7 +397,7 @@ void Arm64Emitter::PopDynamicRegsAndLR() { const auto CanUseSVE = EmitterCTX->HostFeatures.SupportsAVX; if (CanUseSVE) { - for (size_t i = 0; i < RAFPR.size(); i += 4) { + for (size_t i = 0; i < ConfiguredFPRs; i += 4) { const auto Reg1 = RAFPR[i]; const auto Reg2 = RAFPR[i + 1]; const auto Reg3 = RAFPR[i + 2]; @@ -378,7 +406,7 @@ void Arm64Emitter::PopDynamicRegsAndLR() { add(ARMEmitter::Size::i64Bit, ARMEmitter::Reg::rsp, ARMEmitter::Reg::rsp, 32 * 4); } } else { - for (size_t i = 0; i < RAFPR.size(); i += 4) { + for (size_t i = 0; i < ConfiguredFPRs; i += 4) { const auto Reg1 = RAFPR[i]; const auto Reg2 = RAFPR[i + 1]; const auto Reg3 = RAFPR[i + 2]; @@ -387,6 +415,14 @@ void Arm64Emitter::PopDynamicRegsAndLR() { } } + if (ConfiguredDynamicRegisterBase) { + for (size_t i = 0; i < ConfiguredDynamicGPRs; i += 2) { + const auto Reg1 = ConfiguredDynamicRegisterBase[i]; + const auto Reg2 = ConfiguredDynamicRegisterBase[i + 1]; + ldp(Reg1.X(), Reg2.X(), ARMEmitter::Reg::rsp, 16); + } + } + ldr(ARMEmitter::XReg::lr, ARMEmitter::Reg::rsp, 16); } diff --git a/External/FEXCore/Source/Interface/Core/ArchHelpers/Arm64Emitter.h b/External/FEXCore/Source/Interface/Core/ArchHelpers/Arm64Emitter.h index ddf2810b0..a51cd33ac 100644 --- a/External/FEXCore/Source/Interface/Core/ArchHelpers/Arm64Emitter.h +++ b/External/FEXCore/Source/Interface/Core/ArchHelpers/Arm64Emitter.h @@ -31,32 +31,47 @@ namespace FEXCore::CPU { // All but x29 are caller saved constexpr std::array SRA64 = { FEXCore::ARMEmitter::Reg::r4, FEXCore::ARMEmitter::Reg::r5, FEXCore::ARMEmitter::Reg::r6, FEXCore::ARMEmitter::Reg::r7, FEXCore::ARMEmitter::Reg::r8, FEXCore::ARMEmitter::Reg::r9, FEXCore::ARMEmitter::Reg::r10, FEXCore::ARMEmitter::Reg::r11, - FEXCore::ARMEmitter::Reg::r12, FEXCore::ARMEmitter::Reg::r18, FEXCore::ARMEmitter::Reg::r17, FEXCore::ARMEmitter::Reg::r16, FEXCore::ARMEmitter::Reg::r15, FEXCore::ARMEmitter::Reg::r14, FEXCore::ARMEmitter::Reg::r13, FEXCore::ARMEmitter::Reg::r29 + // Registers that don't exist on 32-bit + FEXCore::ARMEmitter::Reg::r12, FEXCore::ARMEmitter::Reg::r13, FEXCore::ARMEmitter::Reg::r14, FEXCore::ARMEmitter::Reg::r15, FEXCore::ARMEmitter::Reg::r16, FEXCore::ARMEmitter::Reg::r17, FEXCore::ARMEmitter::Reg::r18, FEXCore::ARMEmitter::Reg::r29 }; -// All are callee saved -constexpr std::array RA64 = { +// All are callee saved (except additional registers from 32-bit) +constexpr std::array RA64 = { FEXCore::ARMEmitter::Reg::r20, FEXCore::ARMEmitter::Reg::r21, FEXCore::ARMEmitter::Reg::r22, FEXCore::ARMEmitter::Reg::r23, FEXCore::ARMEmitter::Reg::r24, FEXCore::ARMEmitter::Reg::r25, FEXCore::ARMEmitter::Reg::r26, FEXCore::ARMEmitter::Reg::r27, - FEXCore::ARMEmitter::Reg::r19 + FEXCore::ARMEmitter::Reg::r19, + + // Registers only available on 32-bit + // All these are caller saved. + FEXCore::ARMEmitter::Reg::r12, FEXCore::ARMEmitter::Reg::r13, FEXCore::ARMEmitter::Reg::r14, FEXCore::ARMEmitter::Reg::r15, FEXCore::ARMEmitter::Reg::r16, FEXCore::ARMEmitter::Reg::r17, FEXCore::ARMEmitter::Reg::r18, FEXCore::ARMEmitter::Reg::r29 }; -constexpr std::array, 4> RA64Pair = {{ +constexpr std::array, 4 + 3> RA64Pair = {{ {FEXCore::ARMEmitter::Reg::r20, FEXCore::ARMEmitter::Reg::r21}, {FEXCore::ARMEmitter::Reg::r22, FEXCore::ARMEmitter::Reg::r23}, {FEXCore::ARMEmitter::Reg::r24, FEXCore::ARMEmitter::Reg::r25}, {FEXCore::ARMEmitter::Reg::r26, FEXCore::ARMEmitter::Reg::r27}, + + // Registers only available on 32-bit + {FEXCore::ARMEmitter::Reg::r12, FEXCore::ARMEmitter::Reg::r13}, + {FEXCore::ARMEmitter::Reg::r14, FEXCore::ARMEmitter::Reg::r15}, + {FEXCore::ARMEmitter::Reg::r16, FEXCore::ARMEmitter::Reg::r17} }}; // All are caller saved constexpr std::array SRAFPR = { FEXCore::ARMEmitter::VReg::v16, FEXCore::ARMEmitter::VReg::v17, FEXCore::ARMEmitter::VReg::v18, FEXCore::ARMEmitter::VReg::v19, FEXCore::ARMEmitter::VReg::v20, FEXCore::ARMEmitter::VReg::v21, FEXCore::ARMEmitter::VReg::v22, FEXCore::ARMEmitter::VReg::v23, + + // Registers that don't exist on 32-bit FEXCore::ARMEmitter::VReg::v24, FEXCore::ARMEmitter::VReg::v25, FEXCore::ARMEmitter::VReg::v26, FEXCore::ARMEmitter::VReg::v27, FEXCore::ARMEmitter::VReg::v28, FEXCore::ARMEmitter::VReg::v29, FEXCore::ARMEmitter::VReg::v30, FEXCore::ARMEmitter::VReg::v31 }; // v8..v15 = (lower 64bits) Callee saved -constexpr std::array RAFPR = { +constexpr std::array RAFPR = { /*FEXCore::ARMEmitter::VReg::v0, FEXCore::ARMEmitter::VReg::v1, FEXCore::ARMEmitter::VReg::v2, FEXCore::ARMEmitter::VReg::v3,*/FEXCore::ARMEmitter::VReg::v4, FEXCore::ARMEmitter::VReg::v5, FEXCore::ARMEmitter::VReg::v6, FEXCore::ARMEmitter::VReg::v7, // FEXCore::ARMEmitter::VReg::v0 ~ FEXCore::ARMEmitter::VReg::v3 are used as temps - FEXCore::ARMEmitter::VReg::v8, FEXCore::ARMEmitter::VReg::v9, FEXCore::ARMEmitter::VReg::v10, FEXCore::ARMEmitter::VReg::v11, FEXCore::ARMEmitter::VReg::v12, FEXCore::ARMEmitter::VReg::v13, FEXCore::ARMEmitter::VReg::v14, FEXCore::ARMEmitter::VReg::v15 + FEXCore::ARMEmitter::VReg::v8, FEXCore::ARMEmitter::VReg::v9, FEXCore::ARMEmitter::VReg::v10, FEXCore::ARMEmitter::VReg::v11, FEXCore::ARMEmitter::VReg::v12, FEXCore::ARMEmitter::VReg::v13, FEXCore::ARMEmitter::VReg::v14, FEXCore::ARMEmitter::VReg::v15, + + // Registers only available on 32-bit + FEXCore::ARMEmitter::VReg::v24, FEXCore::ARMEmitter::VReg::v25, FEXCore::ARMEmitter::VReg::v26, FEXCore::ARMEmitter::VReg::v27, FEXCore::ARMEmitter::VReg::v28, FEXCore::ARMEmitter::VReg::v29, FEXCore::ARMEmitter::VReg::v30, FEXCore::ARMEmitter::VReg::v31 }; // Contains the address to the currently available CPU state @@ -90,6 +105,45 @@ protected: FEXCore::Context::ContextImpl *EmitterCTX; vixl::aarch64::CPU CPU; + + uint32_t ConfiguredGPRs; + uint32_t ConfiguredSRAGPRs; + uint32_t ConfiguredGPRPairs; + uint32_t ConfiguredFPRs; + uint32_t ConfiguredSRAFPRs; + uint32_t ConfiguredDynamicGPRs; + const FEXCore::ARMEmitter::Register *ConfiguredDynamicRegisterBase{}; + + /** + * @name Register Allocation + * @{ */ + // 64-bit gets removal of additional pairs + constexpr static uint32_t NumGPRs64 = RA64.size() - 8; + constexpr static uint32_t NumSRAGPRs64 = SRA64.size(); + constexpr static uint32_t NumFPRs64 = RAFPR.size() - 8; + constexpr static uint32_t NumSRAFPRs64 = SRAFPR.size(); + constexpr static uint32_t NumGPRPairs64 = RA64Pair.size() - 3; + + // 32-bit gets full array of GPR registers + // SRA registers remove the additional 8 + constexpr static uint32_t NumGPRs32 = RA64.size(); + constexpr static uint32_t NumSRAGPRs32 = SRA64.size() - 8; + constexpr static uint32_t NumFPRs32 = RAFPR.size(); + constexpr static uint32_t NumSRAFPRs32 = SRAFPR.size() - 8; + constexpr static uint32_t NumGPRPairs32 = RA64Pair.size(); + + constexpr static uint32_t RegisterClasses = 6; + + constexpr static uint64_t GPRBase = (0ULL << 32); + constexpr static uint64_t FPRBase = (1ULL << 32); + constexpr static uint64_t GPRPairBase = (2ULL << 32); + + /** @} */ + + constexpr static uint8_t RA_32 = 0; + constexpr static uint8_t RA_64 = 1; + constexpr static uint8_t RA_FPR = 2; + void LoadConstant(FEXCore::ARMEmitter::Size s, FEXCore::ARMEmitter::Register Reg, uint64_t Constant, bool NOPPad = false); @@ -99,7 +153,8 @@ protected: void SpillStaticRegs(bool FPRs = true, uint32_t GPRSpillMask = ~0U, uint32_t FPRSpillMask = ~0U); void FillStaticRegs(bool FPRs = true, uint32_t GPRFillMask = ~0U, uint32_t FPRFillMask = ~0U); - static constexpr uint32_t CALLER_GPR_MASK = 0b0011'1111'1111'1111'1111; + // Register 0-18 + 29 + 30 are caller saved + static constexpr uint32_t CALLER_GPR_MASK = 0b0110'0000'0000'0111'1111'1111'1111'1111U; // This isn't technically true because the lower 64-bits of v8..v15 are callee saved // We can't guarantee only the lower 64bits are used so flush everything diff --git a/External/FEXCore/Source/Interface/Core/JIT/Arm64/JIT.cpp b/External/FEXCore/Source/Interface/Core/JIT/Arm64/JIT.cpp index a3962acb5..5b94663d3 100644 --- a/External/FEXCore/Source/Interface/Core/JIT/Arm64/JIT.cpp +++ b/External/FEXCore/Source/Interface/Core/JIT/Arm64/JIT.cpp @@ -517,20 +517,16 @@ Arm64JITCore::Arm64JITCore(FEXCore::Context::ContextImpl *ctx, FEXCore::Core::In RAPass = Thread->PassManager->GetPass("RA"); - uint32_t NumUsedGPRs = NumGPRs; - uint32_t NumUsedGPRPairs = NumGPRPairs; - uint32_t UsedRegisterCount = RegisterCount; + RAPass->AllocateRegisterSet(RegisterClasses); - RAPass->AllocateRegisterSet(UsedRegisterCount, RegisterClasses); - - RAPass->AddRegisters(FEXCore::IR::GPRClass, NumUsedGPRs); - RAPass->AddRegisters(FEXCore::IR::GPRFixedClass, SRA64.size()); - RAPass->AddRegisters(FEXCore::IR::FPRClass, NumFPRs); - RAPass->AddRegisters(FEXCore::IR::FPRFixedClass, SRAFPR.size() ); - RAPass->AddRegisters(FEXCore::IR::GPRPairClass, NumUsedGPRPairs); + RAPass->AddRegisters(FEXCore::IR::GPRClass, ConfiguredGPRs); + RAPass->AddRegisters(FEXCore::IR::GPRFixedClass, ConfiguredSRAGPRs); + RAPass->AddRegisters(FEXCore::IR::FPRClass, ConfiguredFPRs); + RAPass->AddRegisters(FEXCore::IR::FPRFixedClass, ConfiguredSRAFPRs); + RAPass->AddRegisters(FEXCore::IR::GPRPairClass, ConfiguredGPRPairs); RAPass->AddRegisters(FEXCore::IR::ComplexClass, 1); - for (uint32_t i = 0; i < NumUsedGPRPairs; ++i) { + for (uint32_t i = 0; i < ConfiguredGPRPairs; ++i) { RAPass->AddRegisterConflict(FEXCore::IR::GPRClass, i * 2, FEXCore::IR::GPRPairClass, i); RAPass->AddRegisterConflict(FEXCore::IR::GPRClass, i * 2 + 1, FEXCore::IR::GPRPairClass, i); } diff --git a/External/FEXCore/Source/Interface/Core/JIT/Arm64/JITClass.h b/External/FEXCore/Source/Interface/Core/JIT/Arm64/JITClass.h index 7c4120e81..37b00f987 100644 --- a/External/FEXCore/Source/Interface/Core/JIT/Arm64/JITClass.h +++ b/External/FEXCore/Source/Interface/Core/JIT/Arm64/JITClass.h @@ -64,27 +64,6 @@ private: std::map JumpTargets; - /** - * @name Register Allocation - * @{ */ - constexpr static uint32_t NumGPRs = RA64.size(); - constexpr static uint32_t NumFPRs = RAFPR.size(); - constexpr static uint32_t NumGPRPairs = RA64Pair.size(); - constexpr static uint32_t NumCalleeGPRs = 10; - constexpr static uint32_t NumCalleeGPRPairs = 5; - constexpr static uint32_t RegisterCount = NumGPRs + NumFPRs + NumGPRPairs; - constexpr static uint32_t RegisterClasses = 6; - - constexpr static uint64_t GPRBase = (0ULL << 32); - constexpr static uint64_t FPRBase = (1ULL << 32); - constexpr static uint64_t GPRPairBase = (2ULL << 32); - - /** @} */ - - constexpr static uint8_t RA_32 = 0; - constexpr static uint8_t RA_64 = 1; - constexpr static uint8_t RA_FPR = 2; - [[nodiscard]] FEXCore::ARMEmitter::Register GetReg(IR::NodeID Node) const { const auto Reg = GetPhys(Node); diff --git a/External/FEXCore/Source/Interface/Core/JIT/x86_64/JIT.cpp b/External/FEXCore/Source/Interface/Core/JIT/x86_64/JIT.cpp index 8028781d9..086468b15 100644 --- a/External/FEXCore/Source/Interface/Core/JIT/x86_64/JIT.cpp +++ b/External/FEXCore/Source/Interface/Core/JIT/x86_64/JIT.cpp @@ -349,7 +349,7 @@ X86JITCore::X86JITCore(FEXCore::Context::ContextImpl *ctx, FEXCore::Core::Intern RAPass = Thread->PassManager->GetPass("RA"); - RAPass->AllocateRegisterSet(RegisterCount, RegisterClasses); + RAPass->AllocateRegisterSet(RegisterClasses); RAPass->AddRegisters(FEXCore::IR::GPRClass, NumGPRs); RAPass->AddRegisters(FEXCore::IR::FPRClass, NumXMMs); RAPass->AddRegisters(FEXCore::IR::GPRPairClass, NumGPRPairs); diff --git a/External/FEXCore/Source/Interface/Core/JIT/x86_64/JITClass.h b/External/FEXCore/Source/Interface/Core/JIT/x86_64/JITClass.h index acf3d1cec..752639148 100644 --- a/External/FEXCore/Source/Interface/Core/JIT/x86_64/JITClass.h +++ b/External/FEXCore/Source/Interface/Core/JIT/x86_64/JITClass.h @@ -151,7 +151,6 @@ private: constexpr static uint32_t NumGPRs = RA64.size(); // 4 is the minimum required for GPR ops constexpr static uint32_t NumXMMs = RAXMM.size(); constexpr static uint32_t NumGPRPairs = RA64Pair.size(); - constexpr static uint32_t RegisterCount = NumGPRs + NumXMMs + NumGPRPairs; constexpr static uint32_t RegisterClasses = 6; constexpr static uint64_t GPRBase = (0ULL << 32); diff --git a/External/FEXCore/Source/Interface/IR/IR.json b/External/FEXCore/Source/Interface/IR/IR.json index a713022e3..c2de6d165 100644 --- a/External/FEXCore/Source/Interface/IR/IR.json +++ b/External/FEXCore/Source/Interface/IR/IR.json @@ -83,6 +83,7 @@ "constexpr FEXCore::IR::RegisterClassType ComplexClass {5}", "constexpr FEXCore::IR::RegisterClassType InvalidClass {7}", "", + "// Only up to 30 registers per register class", "constexpr uint8_t InvalidReg {31}", "", "constexpr FEXCore::IR::TypeDefinition i8 {TypeDefinition::Create(1, 0)}", diff --git a/External/FEXCore/Source/Interface/IR/Passes/RegisterAllocationPass.cpp b/External/FEXCore/Source/Interface/IR/Passes/RegisterAllocationPass.cpp index 2ccc6a6e6..3672afa31 100644 --- a/External/FEXCore/Source/Interface/IR/Passes/RegisterAllocationPass.cpp +++ b/External/FEXCore/Source/Interface/IR/Passes/RegisterAllocationPass.cpp @@ -273,7 +273,7 @@ namespace { ~ConstrainedRAPass(); bool Run(IREmitter *IREmit) override; - void AllocateRegisterSet(uint32_t RegisterCount, uint32_t ClassCount) override; + void AllocateRegisterSet(uint32_t ClassCount) override; void AddRegisters(FEXCore::IR::RegisterClassType Class, uint32_t RegisterCount) override; void AddRegisterConflict(FEXCore::IR::RegisterClassType ClassConflict, uint32_t RegConflict, FEXCore::IR::RegisterClassType Class, uint32_t Reg) override; @@ -351,8 +351,7 @@ namespace { FreeRegisterGraph(Graph); } - void ConstrainedRAPass::AllocateRegisterSet(uint32_t RegisterCount, uint32_t ClassCount) { - LOGMAN_THROW_AA_FMT(RegisterCount <= INVALID_REG, "Up to {} regs supported", INVALID_REG); + void ConstrainedRAPass::AllocateRegisterSet(uint32_t ClassCount) { LOGMAN_THROW_AA_FMT(ClassCount <= INVALID_CLASS, "Up to {} classes supported", INVALID_CLASS); Graph = AllocateRegisterGraph(ClassCount); diff --git a/External/FEXCore/Source/Interface/IR/Passes/RegisterAllocationPass.h b/External/FEXCore/Source/Interface/IR/Passes/RegisterAllocationPass.h index 26139e294..8adccb4a0 100644 --- a/External/FEXCore/Source/Interface/IR/Passes/RegisterAllocationPass.h +++ b/External/FEXCore/Source/Interface/IR/Passes/RegisterAllocationPass.h @@ -19,7 +19,7 @@ class RegisterAllocationPass : public FEXCore::IR::Pass { public: bool HasFullRA() const { return HadFullRA; } - virtual void AllocateRegisterSet(uint32_t RegisterCount, uint32_t ClassCount) = 0; + virtual void AllocateRegisterSet(uint32_t ClassCount) = 0; virtual void AddRegisters(FEXCore::IR::RegisterClassType Class, uint32_t RegisterCount) = 0; /** diff --git a/External/FEXCore/include/FEXCore/IR/RegisterAllocationData.h b/External/FEXCore/include/FEXCore/IR/RegisterAllocationData.h index 5bdaf5000..4cb6a6cd9 100644 --- a/External/FEXCore/include/FEXCore/IR/RegisterAllocationData.h +++ b/External/FEXCore/include/FEXCore/IR/RegisterAllocationData.h @@ -8,7 +8,9 @@ namespace FEXCore::IR { union PhysicalRegister { uint8_t Raw; struct { + // 32 maximum physical registers uint8_t Reg: 5; + // 8 Maximum classes uint8_t Class: 3; }; diff --git a/Source/Tests/IRLoader.cpp b/Source/Tests/IRLoader.cpp index ceb573ba0..4877c0685 100644 --- a/Source/Tests/IRLoader.cpp +++ b/Source/Tests/IRLoader.cpp @@ -174,6 +174,10 @@ int main(int argc, char **argv, char **const envp) FEXCore::Config::AddLayer(std::make_unique(argc, argv)); FEXCore::Config::AddLayer(FEXCore::Config::CreateEnvironmentLayer(envp)); FEXCore::Config::Load(); + // Ensure the IRLoader runs in 64-bit mode. + // This is to ensure that static register allocation in the JIT + // is configured correctly for accesses to the top 8 GPRs and 8 XMM registers. + FEXCore::Config::EraseSet(FEXCore::Config::CONFIG_IS64BIT_MODE, "1"); auto Args = FEX::ArgLoader::Get(); auto ParsedArgs = FEX::ArgLoader::GetParsedArgs();