diff --git a/FEXCore/Source/CMakeLists.txt b/FEXCore/Source/CMakeLists.txt index f16689e84..0ac4f4efa 100644 --- a/FEXCore/Source/CMakeLists.txt +++ b/FEXCore/Source/CMakeLists.txt @@ -69,7 +69,6 @@ set (SRCS Interface/IR/Passes/ConstProp.cpp Interface/IR/Passes/IRDumperPass.cpp Interface/IR/Passes/IRValidation.cpp - Interface/IR/Passes/RAValidation.cpp Interface/IR/Passes/RedundantFlagCalculationElimination.cpp Interface/IR/Passes/RegisterAllocationPass.cpp Interface/IR/Passes/x87StackOptimizationPass.cpp diff --git a/FEXCore/Source/Interface/IR/PassManager.cpp b/FEXCore/Source/Interface/IR/PassManager.cpp index 337de1d21..2dd3ee0f2 100644 --- a/FEXCore/Source/Interface/IR/PassManager.cpp +++ b/FEXCore/Source/Interface/IR/PassManager.cpp @@ -79,7 +79,6 @@ void PassManager::AddDefaultPasses(FEXCore::Context::ContextImpl* ctx) { void PassManager::AddDefaultValidationPasses() { #if defined(ASSERTIONS_ENABLED) && ASSERTIONS_ENABLED InsertValidationPass(Validation::CreateIRValidation(), "IRValidation"); - InsertValidationPass(Validation::CreateRAValidation()); #endif } diff --git a/FEXCore/Source/Interface/IR/Passes.h b/FEXCore/Source/Interface/IR/Passes.h index ffdcb8f10..250892794 100644 --- a/FEXCore/Source/Interface/IR/Passes.h +++ b/FEXCore/Source/Interface/IR/Passes.h @@ -24,7 +24,6 @@ fextl::unique_ptr CreateX87StackOptimizationPass(const FEXCor namespace Validation { fextl::unique_ptr CreateIRValidation(); - fextl::unique_ptr CreateRAValidation(); } // namespace Validation namespace Debug { diff --git a/FEXCore/Source/Interface/IR/Passes/IRValidation.h b/FEXCore/Source/Interface/IR/Passes/IRValidation.h index 938225d85..6a34f05ff 100644 --- a/FEXCore/Source/Interface/IR/Passes/IRValidation.h +++ b/FEXCore/Source/Interface/IR/Passes/IRValidation.h @@ -16,8 +16,6 @@ struct BlockInfo { fextl::vector Successors; }; -class RAValidation; - class IRValidation final : public FEXCore::IR::Pass { public: ~IRValidation(); @@ -29,7 +27,5 @@ private: OrderedNode* EntryBlock {}; fextl::unordered_map OffsetToBlockMap; size_t MaxNodes {}; - - friend class RAValidation; }; } // namespace FEXCore::IR::Validation diff --git a/FEXCore/Source/Interface/IR/Passes/RAValidation.cpp b/FEXCore/Source/Interface/IR/Passes/RAValidation.cpp deleted file mode 100644 index 75e4ede6f..000000000 --- a/FEXCore/Source/Interface/IR/Passes/RAValidation.cpp +++ /dev/null @@ -1,197 +0,0 @@ -// SPDX-License-Identifier: MIT - -#include "Interface/IR/IR.h" -#include "Interface/IR/IREmitter.h" -#include "Interface/IR/PassManager.h" -#include "Interface/IR/RegisterAllocationData.h" -#include "Interface/IR/Passes/IRValidation.h" -#include "Interface/IR/Passes/RegisterAllocationPass.h" - -#include -#include -#include -#include -#include -#include - -#include - -namespace FEXCore::IR::Validation { - -// Hold the mapping of physical registers to the SSA id it holds at any given point in the IR -struct RegState { - static constexpr IR::NodeID UninitializedValue {0}; - static constexpr IR::NodeID InvalidReg {0xffff'ffff}; - - // This class makes some assumptions about how the host registers are arranged and mapped to virtual registers: - // 1. There will be less than 32 GPRs and 32 FPRs - // 2. If the GPRFixed class is used, there will be 16 GPRs and 16 FixedGPRs max - // 3. Same with FPRFixed - - // These assumptions were all true for the state of the arm64 and x86 jits at the time this was written - - // Mark a physical register as containing a SSA id - bool Set(PhysicalRegister Reg, IR::NodeID ssa) { - LOGMAN_THROW_A_FMT(ssa.IsValid(), "RegState assumes ssa0 will be the block header and never assigned to a register"); - - // PhysicalRegisters aren't fully mapped until assembly emission - // We need to apply a generic mapping here to catch any aliasing - switch (Reg.Class) { - case GPRClass: GPRs[Reg.Reg] = ssa; return true; - case GPRFixedClass: - // On arm64, there are 16 Fixed and 9 normal - GPRsFixed[Reg.Reg] = ssa; - return true; - case FPRClass: FPRs[Reg.Reg] = ssa; return true; - case FPRFixedClass: - // On arm64, there are 16 Fixed and 12 normal - FPRsFixed[Reg.Reg] = ssa; - return true; - } - return false; - } - - // Get the current SSA id - // Or an error value there isn't a (sane) SSA id - IR::NodeID Get(PhysicalRegister Reg) const { - switch (Reg.Class) { - case GPRClass: return GPRs[Reg.Reg]; - case GPRFixedClass: return GPRsFixed[Reg.Reg]; - case FPRClass: return FPRs[Reg.Reg]; - case FPRFixedClass: return FPRsFixed[Reg.Reg]; - } - return InvalidReg; - } - - // Mark a spill slot as containing a SSA id - void Spill(uint32_t SpillSlot, IR::NodeID ssa) { - Spills[SpillSlot] = ssa; - } - - // Return the SSA id currently in a spill slot - IR::NodeID Unspill(uint32_t SpillSlot) { - if (Spills.contains(SpillSlot)) { - return Spills[SpillSlot]; - } else { - return UninitializedValue; - } - } - -private: - std::array GPRsFixed = {}; - std::array FPRsFixed = {}; - std::array GPRs = {}; - std::array FPRs = {}; - - fextl::unordered_map Spills; -}; - -class RAValidation final : public FEXCore::IR::Pass { -public: - ~RAValidation() {} - void Run(IREmitter* IREmit) override; -}; - - -void RAValidation::Run(IREmitter* IREmit) { - if (!Manager->HasPass("RA")) { - return; - } - - FEXCORE_PROFILE_SCOPED("PassManager::RAValidation"); - - IR::RegisterAllocationData* RAData = Manager->GetPass("RA")->GetAllocationData(); - - bool HadError = false; - fextl::ostringstream Errors; - - auto CurrentIR = IREmit->ViewIR(); - - for (auto [BlockNode, BlockIROp] : CurrentIR.GetBlocks()) { - // We only allocate registers locally, so state is reset each block - struct RegState BlockRegState = {}; - - for (auto [CodeNode, IROp] : CurrentIR.GetCode(BlockNode)) { - const auto ID = CurrentIR.GetID(CodeNode); - - const auto CheckArg = [&](uint32_t i, OrderedNodeWrapper Arg) { - const auto ArgID = Arg.ID(); - const auto PhyReg = RAData->GetNodeRegister(ArgID); - - if (PhyReg.IsInvalid()) { - return; - } - - auto CurrentSSAAtReg = BlockRegState.Get(PhyReg); - if (CurrentSSAAtReg == RegState::InvalidReg) { - HadError |= true; - Errors << fextl::fmt::format("%{}: Arg[{}] unknown Reg: {}, class: {}\n", ID, i, PhyReg.Reg, PhyReg.Class); - } else if (CurrentSSAAtReg == RegState::UninitializedValue) { - HadError |= true; - - Errors << fextl::fmt::format("%{}: Arg[{}] expects reg{} to contain %{}, but it is uninitialized\n", ID, i, PhyReg.Reg, ArgID); - } else if (CurrentSSAAtReg != ArgID) { - HadError |= true; - Errors << fextl::fmt::format("%{}: Arg[{}] expects reg{} to contain %{}, but it actually contains %{}\n", ID, i, PhyReg.Reg, - ArgID, CurrentSSAAtReg); - } - }; - - switch (IROp->Op) { - case OP_SPILLREGISTER: { - auto SpillRegister = IROp->C(); - CheckArg(0, SpillRegister->Value); - - BlockRegState.Spill(SpillRegister->Slot, SpillRegister->Value.ID()); - break; - } - - case OP_FILLREGISTER: { - auto FillRegister = IROp->C(); - const auto ExpectedValue = FillRegister->OriginalValue.ID(); - const auto Value = BlockRegState.Unspill(FillRegister->Slot); - - // TODO: This only proves that the Spill has a consistent SSA value - // In the future we need to prove it contains the correct SSA value. For - // this we need to analyze copies/swaps properly. As a hot fix, don't - // compare Value with ExpectedValue. - - if (Value == RegState::UninitializedValue) { - HadError |= true; - Errors << fextl::fmt::format("%{}: FillRegister expected %{} in Slot {}, but was undefined\n", ID, ExpectedValue, FillRegister->Slot); - } - break; - } - - default: { - // And check that all args point at the correct SSA - uint8_t NumArgs = IR::GetArgs(IROp->Op); - for (uint32_t i = 0; i < NumArgs; ++i) { - CheckArg(i, IROp->Args[i]); - } - break; - } - } - - // Update BlockState map - if (IROp->Op != OP_SPILLREGISTER) { - BlockRegState.Set(RAData->GetNodeRegister(ID), ID); - } - } - } - - if (HadError) { - fextl::stringstream IrDump; - FEXCore::IR::Dump(&IrDump, &CurrentIR, RAData); - - LogMan::Msg::EFmt("RA Validation Error\n{}\nErrors:\n{}\n", IrDump.str(), Errors.str()); - LOGMAN_MSG_A_FMT("Encountered RA validation Error"); - - Errors.clear(); - } -} - -fextl::unique_ptr CreateRAValidation() { - return fextl::make_unique(); -} -} // namespace FEXCore::IR::Validation