From 236082a0fe4dcd0362c5c74923a93e3db6a01291 Mon Sep 17 00:00:00 2001 From: Richard-Qin-X Date: Thu, 13 Aug 2026 05:45:37 +0800 Subject: [CodeGen] Align pass manager ownership --- .../rcc/CodeGen/GlobalISel/InstructionSelect.h | 4 +- backend/include/rcc/CodeGen/GlobalISel/Legalizer.h | 4 +- .../include/rcc/CodeGen/GlobalISel/RegBankSelect.h | 4 +- backend/include/rcc/CodeGen/LiveIntervals.h | 7 +- backend/include/rcc/CodeGen/LiveVariables.h | 12 +- backend/include/rcc/CodeGen/MachineAnalyses.h | 35 +- .../include/rcc/CodeGen/MachineBlockPlacement.h | 11 +- .../rcc/CodeGen/MachineBranchOptimization.h | 4 +- .../include/rcc/CodeGen/MachineBranchRelaxation.h | 4 +- backend/include/rcc/CodeGen/MachineCSE.h | 10 +- backend/include/rcc/CodeGen/MachineCombiner.h | 4 +- .../include/rcc/CodeGen/MachineCopyPropagation.h | 4 +- backend/include/rcc/CodeGen/MachineDCE.h | 4 +- backend/include/rcc/CodeGen/MachineFallthrough.h | 4 +- backend/include/rcc/CodeGen/MachineFinalization.h | 6 +- .../rcc/CodeGen/MachineFunctionAnalysisManager.h | 133 ++ backend/include/rcc/CodeGen/MachineLICM.h | 10 +- backend/include/rcc/CodeGen/MachineMemoryFolding.h | 4 +- .../rcc/CodeGen/MachineOptimizationPipeline.h | 11 +- backend/include/rcc/CodeGen/MachinePass.h | 720 ---------- backend/include/rcc/CodeGen/MachinePassManager.h | 134 ++ .../include/rcc/CodeGen/MachinePseudoExpansion.h | 10 +- backend/include/rcc/CodeGen/MachineScheduler.h | 4 +- .../include/rcc/CodeGen/MachineShrinkWrapping.h | 4 +- backend/include/rcc/CodeGen/MachineSink.h | 8 +- .../include/rcc/CodeGen/MachineStackSlotColoring.h | 4 +- .../include/rcc/CodeGen/MachineTailDuplication.h | 4 +- backend/include/rcc/CodeGen/MachineTailMerge.h | 4 +- backend/include/rcc/CodeGen/PHIElimination.h | 4 +- backend/include/rcc/CodeGen/PostRAScheduler.h | 4 +- .../rcc/CodeGen/PrologueEpilogueInsertion.h | 4 +- backend/include/rcc/CodeGen/RegAllocCommon.h | 2 +- backend/include/rcc/CodeGen/RegAllocFast.h | 4 +- backend/include/rcc/CodeGen/RegAllocPBQP.h | 2 +- backend/include/rcc/CodeGen/SlotIndexes.h | 7 +- .../rcc/CodeGen/TwoAddressInstructionPass.h | 4 +- backend/include/rcc/CodeGen/VirtRegMap.h | 4 +- backend/include/rcc/IR/PassInstrumentation.h | 227 +++ backend/include/rcc/IR/PassManager.h | 531 +++++++ backend/include/rcc/Target/RISCV/RISCVPipeline.h | 4 +- backend/include/rcc/Tooling/BackendDriver.h | 2 +- backend/include/rcc/Tooling/PipelineDriver.h | 2 +- backend/lib/CodeGen/CMakeLists.txt | 11 +- .../lib/CodeGen/GlobalISel/InstructionSelect.cpp | 2 +- backend/lib/CodeGen/GlobalISel/Legalizer.cpp | 2 +- backend/lib/CodeGen/GlobalISel/RegBankSelect.cpp | 2 +- backend/lib/CodeGen/InlineSpiller.cpp | 2 +- backend/lib/CodeGen/LiveIntervals.cpp | 4 +- backend/lib/CodeGen/LiveVariables.cpp | 27 +- backend/lib/CodeGen/MachineAnalyses.cpp | 48 +- backend/lib/CodeGen/MachineBlockPlacement.cpp | 20 +- backend/lib/CodeGen/MachineBranchOptimization.cpp | 2 +- backend/lib/CodeGen/MachineBranchRelaxation.cpp | 6 +- backend/lib/CodeGen/MachineCSE.cpp | 12 +- backend/lib/CodeGen/MachineCombiner.cpp | 2 +- backend/lib/CodeGen/MachineCopyPropagation.cpp | 6 +- backend/lib/CodeGen/MachineDCE.cpp | 2 +- backend/lib/CodeGen/MachineFallthrough.cpp | 6 +- backend/lib/CodeGen/MachineFinalization.cpp | 4 +- backend/lib/CodeGen/MachineLICM.cpp | 22 +- backend/lib/CodeGen/MachineMemoryFolding.cpp | 2 +- .../lib/CodeGen/MachineOptimizationPipeline.cpp | 10 +- backend/lib/CodeGen/MachinePass.cpp | 1497 -------------------- backend/lib/CodeGen/MachinePassManager.cpp | 1099 ++++++++++++++ backend/lib/CodeGen/MachinePseudoExpansion.cpp | 26 +- backend/lib/CodeGen/MachineScheduler.cpp | 9 +- backend/lib/CodeGen/MachineShrinkWrapping.cpp | 10 +- backend/lib/CodeGen/MachineSink.cpp | 18 +- backend/lib/CodeGen/MachineStackSlotColoring.cpp | 2 +- backend/lib/CodeGen/MachineTailDuplication.cpp | 2 +- backend/lib/CodeGen/MachineTailMerge.cpp | 2 +- backend/lib/CodeGen/PHIElimination.cpp | 2 +- backend/lib/CodeGen/PostRAScheduler.cpp | 9 +- backend/lib/CodeGen/PrologueEpilogueInsertion.cpp | 2 +- backend/lib/CodeGen/RegAllocBase.h | 7 +- backend/lib/CodeGen/RegAllocBasic.cpp | 8 +- backend/lib/CodeGen/RegAllocBasic.h | 2 +- backend/lib/CodeGen/RegAllocFast.cpp | 6 +- backend/lib/CodeGen/RegAllocPBQP.cpp | 8 +- backend/lib/CodeGen/SlotIndexes.cpp | 4 +- backend/lib/CodeGen/TwoAddressInstructionPass.cpp | 6 +- backend/lib/CodeGen/VirtRegMap.cpp | 4 +- backend/lib/Target/RISCV/RISCVPipeline.cpp | 22 +- backend/lib/Tooling/PipelineDriver.cpp | 8 +- backend/unittests/CodeGen/CMakeLists.txt | 41 +- .../CodeGen/GlobalISel/InstructionSelectTest.cpp | 14 +- .../unittests/CodeGen/GlobalISel/LegalizerTest.cpp | 10 +- .../CodeGen/GlobalISel/RegBankSelectTest.cpp | 4 +- backend/unittests/CodeGen/LiveIntervalTest.cpp | 2 +- backend/unittests/CodeGen/LiveIntervalsTest.cpp | 8 +- backend/unittests/CodeGen/LivePhysRegsTest.cpp | 2 +- backend/unittests/CodeGen/LiveRegMatrixTest.cpp | 4 +- backend/unittests/CodeGen/LiveVariablesTest.cpp | 26 +- backend/unittests/CodeGen/MachineAnalysesTest.cpp | 24 +- .../unittests/CodeGen/MachineOptimizationTest.cpp | 20 +- .../unittests/CodeGen/MachinePassManagerTest.cpp | 426 ++++++ backend/unittests/CodeGen/MachinePassTest.cpp | 918 ------------ .../unittests/CodeGen/MachineSchedulingTest.cpp | 8 +- backend/unittests/CodeGen/PHIEliminationTest.cpp | 8 +- .../unittests/CodeGen/PassInstrumentationTest.cpp | 173 +++ backend/unittests/CodeGen/PassManagerTest.cpp | 260 ++++ .../unittests/CodeGen/RegisterAllocationTest.cpp | 14 +- .../CodeGen/RegisterAllocationTestSupport.h | 4 +- backend/unittests/CodeGen/SlotIndexesTest.cpp | 2 +- .../CodeGen/TwoAddressInstructionPassTest.cpp | 8 +- .../unittests/Target/RISCVFrameLoweringTest.cpp | 6 +- backend/unittests/Target/RISCVLateCodeGenTest.cpp | 50 +- .../Target/RISCVRegisterAllocationTest.cpp | 6 +- backend/unittests/Target/RISCVSSAExitTest.cpp | 6 +- 109 files changed, 3429 insertions(+), 3528 deletions(-) create mode 100644 backend/include/rcc/CodeGen/MachineFunctionAnalysisManager.h delete mode 100644 backend/include/rcc/CodeGen/MachinePass.h create mode 100644 backend/include/rcc/CodeGen/MachinePassManager.h create mode 100644 backend/include/rcc/IR/PassInstrumentation.h create mode 100644 backend/include/rcc/IR/PassManager.h delete mode 100644 backend/lib/CodeGen/MachinePass.cpp create mode 100644 backend/lib/CodeGen/MachinePassManager.cpp create mode 100644 backend/unittests/CodeGen/MachinePassManagerTest.cpp delete mode 100644 backend/unittests/CodeGen/MachinePassTest.cpp create mode 100644 backend/unittests/CodeGen/PassInstrumentationTest.cpp create mode 100644 backend/unittests/CodeGen/PassManagerTest.cpp (limited to 'backend') diff --git a/backend/include/rcc/CodeGen/GlobalISel/InstructionSelect.h b/backend/include/rcc/CodeGen/GlobalISel/InstructionSelect.h index 0c034cd..f342cdc 100644 --- a/backend/include/rcc/CodeGen/GlobalISel/InstructionSelect.h +++ b/backend/include/rcc/CodeGen/GlobalISel/InstructionSelect.h @@ -4,7 +4,7 @@ #define RCC_CODEGEN_GLOBALISEL_INSTRUCTIONSELECT_H #include "rcc/CodeGen/GlobalISel/InstructionSelector.h" -#include "rcc/CodeGen/MachinePass.h" +#include "rcc/CodeGen/MachinePassManager.h" namespace rcc { @@ -16,7 +16,7 @@ public: [[nodiscard]] const MachinePassContract &contract() const noexcept override; [[nodiscard]] Expected run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses) override; + MachineFunctionAnalysisManager &Analyses) override; private: [[nodiscard]] Expected runImplementation(MachineFunction &Function, diff --git a/backend/include/rcc/CodeGen/GlobalISel/Legalizer.h b/backend/include/rcc/CodeGen/GlobalISel/Legalizer.h index 7f86d16..dfeda22 100644 --- a/backend/include/rcc/CodeGen/GlobalISel/Legalizer.h +++ b/backend/include/rcc/CodeGen/GlobalISel/Legalizer.h @@ -4,7 +4,7 @@ #define RCC_CODEGEN_GLOBALISEL_LEGALIZER_H #include "rcc/CodeGen/GlobalISel/LegalizerInfo.h" -#include "rcc/CodeGen/MachinePass.h" +#include "rcc/CodeGen/MachinePassManager.h" #include @@ -20,7 +20,7 @@ public: [[nodiscard]] const MachinePassContract &contract() const noexcept override; [[nodiscard]] Expected run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses) override; + MachineFunctionAnalysisManager &Analyses) override; private: [[nodiscard]] Expected runImplementation(MachineFunction &Function, diff --git a/backend/include/rcc/CodeGen/GlobalISel/RegBankSelect.h b/backend/include/rcc/CodeGen/GlobalISel/RegBankSelect.h index 256d748..a7fc6bf 100644 --- a/backend/include/rcc/CodeGen/GlobalISel/RegBankSelect.h +++ b/backend/include/rcc/CodeGen/GlobalISel/RegBankSelect.h @@ -3,7 +3,7 @@ #ifndef RCC_CODEGEN_GLOBALISEL_REGBANKSELECT_H #define RCC_CODEGEN_GLOBALISEL_REGBANKSELECT_H -#include "rcc/CodeGen/MachinePass.h" +#include "rcc/CodeGen/MachinePassManager.h" #include "rcc/CodeGen/RegisterBankInfo.h" namespace rcc { @@ -16,7 +16,7 @@ public: [[nodiscard]] const MachinePassContract &contract() const noexcept override; [[nodiscard]] Expected run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses) override; + MachineFunctionAnalysisManager &Analyses) override; private: const RegisterBankInfo *Info; diff --git a/backend/include/rcc/CodeGen/LiveIntervals.h b/backend/include/rcc/CodeGen/LiveIntervals.h index a45c593..b5ba05a 100644 --- a/backend/include/rcc/CodeGen/LiveIntervals.h +++ b/backend/include/rcc/CodeGen/LiveIntervals.h @@ -4,7 +4,7 @@ #define RCC_CODEGEN_LIVEINTERVALS_H #include "rcc/CodeGen/LiveInterval.h" -#include "rcc/CodeGen/MachinePass.h" +#include "rcc/CodeGen/MachinePassManager.h" #include "rcc/CodeGen/RegisterMask.h" #include @@ -64,8 +64,9 @@ public: return "LiveIntervals"; } - [[nodiscard]] static Expected - run(MachineFunction &Function, const TargetDescription &Target, MachineAnalysisManager &Analyses); + [[nodiscard]] static Expected run(MachineFunction &Function, + const TargetDescription &Target, + MachineFunctionAnalysisManager &Analyses); }; } // namespace rcc diff --git a/backend/include/rcc/CodeGen/LiveVariables.h b/backend/include/rcc/CodeGen/LiveVariables.h index 28a66c1..c95e7d8 100644 --- a/backend/include/rcc/CodeGen/LiveVariables.h +++ b/backend/include/rcc/CodeGen/LiveVariables.h @@ -4,7 +4,7 @@ #define RCC_CODEGEN_LIVEVARIABLES_H #include "rcc/CodeGen/LiveRegUnits.h" -#include "rcc/CodeGen/MachinePass.h" +#include "rcc/CodeGen/MachinePassManager.h" #include "rcc/CodeGen/Register.h" #include "rcc/Support/Error.h" @@ -82,8 +82,9 @@ public: return "LiveVariables"; } - [[nodiscard]] static Expected - run(MachineFunction &Function, const TargetDescription &Target, MachineAnalysisManager &Analyses); + [[nodiscard]] static Expected run(MachineFunction &Function, + const TargetDescription &Target, + MachineFunctionAnalysisManager &Analyses); }; class RebuildMachineLivenessPass final : public MachineFunctionPass { @@ -91,14 +92,15 @@ public: [[nodiscard]] const MachinePassContract &contract() const noexcept override; [[nodiscard]] Expected run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses) override; + MachineFunctionAnalysisManager &Analyses) override; }; [[nodiscard]] Expected verifyTrackedMachineLiveness(const MachineFunction &Function, const TargetDescription &Target); [[nodiscard]] Expected rebuildMachineLiveness(MachineFunction &Function, const TargetDescription &Target); -[[nodiscard]] Expected registerStage11MachineAnalyses(MachineAnalysisManager &Analyses); +[[nodiscard]] Expected +registerStage11MachineAnalyses(MachineFunctionAnalysisManager &Analyses); } // namespace rcc diff --git a/backend/include/rcc/CodeGen/MachineAnalyses.h b/backend/include/rcc/CodeGen/MachineAnalyses.h index eda550d..4adb300 100644 --- a/backend/include/rcc/CodeGen/MachineAnalyses.h +++ b/backend/include/rcc/CodeGen/MachineAnalyses.h @@ -5,7 +5,7 @@ #include "rcc/CodeGen/MachineBasicBlock.h" #include "rcc/CodeGen/MachineIRTypes.h" -#include "rcc/CodeGen/MachinePass.h" +#include "rcc/CodeGen/MachinePassManager.h" #include "rcc/CodeGen/StableID.h" #include "rcc/Support/Error.h" @@ -62,8 +62,9 @@ public: return "MachineDominatorTree"; } - [[nodiscard]] static Expected - run(MachineFunction &Function, const TargetDescription &Target, MachineAnalysisManager &Analyses); + [[nodiscard]] static Expected run(MachineFunction &Function, + const TargetDescription &Target, + MachineFunctionAnalysisManager &Analyses); }; struct MachineLoop final { @@ -107,8 +108,9 @@ public: return "MachineLoopInfo"; } - [[nodiscard]] static Expected - run(MachineFunction &Function, const TargetDescription &Target, MachineAnalysisManager &Analyses); + [[nodiscard]] static Expected run(MachineFunction &Function, + const TargetDescription &Target, + MachineFunctionAnalysisManager &Analyses); }; class MachineBranchProbabilityAnalysis final { @@ -130,8 +132,9 @@ public: return "MachineBranchProbability"; } - [[nodiscard]] static Expected - run(MachineFunction &Function, const TargetDescription &Target, MachineAnalysisManager &Analyses); + [[nodiscard]] static Expected run(MachineFunction &Function, + const TargetDescription &Target, + MachineFunctionAnalysisManager &Analyses); }; class MachineBlockFrequencyAnalysis final { @@ -152,8 +155,9 @@ public: return "MachineBlockFrequency"; } - [[nodiscard]] static Expected - run(MachineFunction &Function, const TargetDescription &Target, MachineAnalysisManager &Analyses); + [[nodiscard]] static Expected run(MachineFunction &Function, + const TargetDescription &Target, + MachineFunctionAnalysisManager &Analyses); }; enum class MachineAliasResult : std::uint8_t { @@ -175,8 +179,9 @@ public: return "MachineAliasAnalysis"; } - [[nodiscard]] static Expected - run(MachineFunction &Function, const TargetDescription &Target, MachineAnalysisManager &Analyses); + [[nodiscard]] static Expected run(MachineFunction &Function, + const TargetDescription &Target, + MachineFunctionAnalysisManager &Analyses); }; enum class MachineMemoryDependencyKind : std::uint8_t { @@ -233,11 +238,13 @@ public: return "MachineMemoryDependence"; } - [[nodiscard]] static Expected - run(MachineFunction &Function, const TargetDescription &Target, MachineAnalysisManager &Analyses); + [[nodiscard]] static Expected run(MachineFunction &Function, + const TargetDescription &Target, + MachineFunctionAnalysisManager &Analyses); }; -[[nodiscard]] Expected registerStage8MachineAnalyses(MachineAnalysisManager &Analyses); +[[nodiscard]] Expected +registerStage8MachineAnalyses(MachineFunctionAnalysisManager &Analyses); } // namespace rcc diff --git a/backend/include/rcc/CodeGen/MachineBlockPlacement.h b/backend/include/rcc/CodeGen/MachineBlockPlacement.h index 52ddafd..41d5f2d 100644 --- a/backend/include/rcc/CodeGen/MachineBlockPlacement.h +++ b/backend/include/rcc/CodeGen/MachineBlockPlacement.h @@ -3,7 +3,7 @@ #ifndef RCC_CODEGEN_MACHINEBLOCKPLACEMENT_H #define RCC_CODEGEN_MACHINEBLOCKPLACEMENT_H -#include "rcc/CodeGen/MachinePass.h" +#include "rcc/CodeGen/MachinePassManager.h" namespace rcc { @@ -12,13 +12,12 @@ public: [[nodiscard]] const MachinePassContract &contract() const noexcept override; [[nodiscard]] Expected run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses) override; + MachineFunctionAnalysisManager &Analyses) override; private: - [[nodiscard]] Expected runImplementation(MachineFunction &Function, - const TargetDescription &Target, - MachineAnalysisManager &Analyses, - MachineActionReplay &Actions) const; + [[nodiscard]] Expected + runImplementation(MachineFunction &Function, const TargetDescription &Target, + MachineFunctionAnalysisManager &Analyses, MachineActionReplay &Actions) const; }; } // namespace rcc diff --git a/backend/include/rcc/CodeGen/MachineBranchOptimization.h b/backend/include/rcc/CodeGen/MachineBranchOptimization.h index 9f120dc..e578d72 100644 --- a/backend/include/rcc/CodeGen/MachineBranchOptimization.h +++ b/backend/include/rcc/CodeGen/MachineBranchOptimization.h @@ -3,7 +3,7 @@ #ifndef RCC_CODEGEN_MACHINEBRANCHOPTIMIZATION_H #define RCC_CODEGEN_MACHINEBRANCHOPTIMIZATION_H -#include "rcc/CodeGen/MachinePass.h" +#include "rcc/CodeGen/MachinePassManager.h" #include @@ -24,7 +24,7 @@ public: [[nodiscard]] const MachinePassContract &contract() const noexcept override; [[nodiscard]] Expected run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses) override; + MachineFunctionAnalysisManager &Analyses) override; private: [[nodiscard]] Expected diff --git a/backend/include/rcc/CodeGen/MachineBranchRelaxation.h b/backend/include/rcc/CodeGen/MachineBranchRelaxation.h index 03c7fa7..5b359b4 100644 --- a/backend/include/rcc/CodeGen/MachineBranchRelaxation.h +++ b/backend/include/rcc/CodeGen/MachineBranchRelaxation.h @@ -3,7 +3,7 @@ #ifndef RCC_CODEGEN_MACHINEBRANCHRELAXATION_H #define RCC_CODEGEN_MACHINEBRANCHRELAXATION_H -#include "rcc/CodeGen/MachinePass.h" +#include "rcc/CodeGen/MachinePassManager.h" #include @@ -24,7 +24,7 @@ public: [[nodiscard]] const MachinePassContract &contract() const noexcept override; [[nodiscard]] Expected run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses) override; + MachineFunctionAnalysisManager &Analyses) override; private: [[nodiscard]] Expected runImplementation(MachineFunction &Function, diff --git a/backend/include/rcc/CodeGen/MachineCSE.h b/backend/include/rcc/CodeGen/MachineCSE.h index 1c2057b..dc10b62 100644 --- a/backend/include/rcc/CodeGen/MachineCSE.h +++ b/backend/include/rcc/CodeGen/MachineCSE.h @@ -3,7 +3,7 @@ #ifndef RCC_CODEGEN_MACHINECSE_H #define RCC_CODEGEN_MACHINECSE_H -#include "rcc/CodeGen/MachinePass.h" +#include "rcc/CodeGen/MachinePassManager.h" #include @@ -20,12 +20,12 @@ public: [[nodiscard]] const MachinePassContract &contract() const noexcept override; [[nodiscard]] Expected run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses) override; + MachineFunctionAnalysisManager &Analyses) override; private: - [[nodiscard]] Expected runImplementation(MachineFunction &Function, - const TargetDescription &Target, - MachineAnalysisManager &Analyses); + [[nodiscard]] Expected + runImplementation(MachineFunction &Function, const TargetDescription &Target, + MachineFunctionAnalysisManager &Analyses); MachineCSEOptions Options; }; diff --git a/backend/include/rcc/CodeGen/MachineCombiner.h b/backend/include/rcc/CodeGen/MachineCombiner.h index ef7f432..3850b91 100644 --- a/backend/include/rcc/CodeGen/MachineCombiner.h +++ b/backend/include/rcc/CodeGen/MachineCombiner.h @@ -4,7 +4,7 @@ #define RCC_CODEGEN_MACHINECOMBINER_H #include "rcc/CodeGen/MachineCombinerPattern.h" -#include "rcc/CodeGen/MachinePass.h" +#include "rcc/CodeGen/MachinePassManager.h" #include @@ -24,7 +24,7 @@ public: [[nodiscard]] const MachinePassContract &contract() const noexcept override; [[nodiscard]] Expected run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses) override; + MachineFunctionAnalysisManager &Analyses) override; private: [[nodiscard]] Expected runImplementation(MachineFunction &Function, diff --git a/backend/include/rcc/CodeGen/MachineCopyPropagation.h b/backend/include/rcc/CodeGen/MachineCopyPropagation.h index 43baa7e..ab8b23f 100644 --- a/backend/include/rcc/CodeGen/MachineCopyPropagation.h +++ b/backend/include/rcc/CodeGen/MachineCopyPropagation.h @@ -3,7 +3,7 @@ #ifndef RCC_CODEGEN_MACHINECOPYPROPAGATION_H #define RCC_CODEGEN_MACHINECOPYPROPAGATION_H -#include "rcc/CodeGen/MachinePass.h" +#include "rcc/CodeGen/MachinePassManager.h" #include #include @@ -30,7 +30,7 @@ public: [[nodiscard]] const MachinePassContract &contract() const noexcept override; [[nodiscard]] Expected run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses) override; + MachineFunctionAnalysisManager &Analyses) override; private: [[nodiscard]] Expected runImplementation(MachineFunction &Function, diff --git a/backend/include/rcc/CodeGen/MachineDCE.h b/backend/include/rcc/CodeGen/MachineDCE.h index 893108d..8860b0f 100644 --- a/backend/include/rcc/CodeGen/MachineDCE.h +++ b/backend/include/rcc/CodeGen/MachineDCE.h @@ -3,7 +3,7 @@ #ifndef RCC_CODEGEN_MACHINEDCE_H #define RCC_CODEGEN_MACHINEDCE_H -#include "rcc/CodeGen/MachinePass.h" +#include "rcc/CodeGen/MachinePassManager.h" namespace rcc { @@ -12,7 +12,7 @@ public: [[nodiscard]] const MachinePassContract &contract() const noexcept override; [[nodiscard]] Expected run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses) override; + MachineFunctionAnalysisManager &Analyses) override; private: [[nodiscard]] Expected runImplementation(MachineFunction &Function, diff --git a/backend/include/rcc/CodeGen/MachineFallthrough.h b/backend/include/rcc/CodeGen/MachineFallthrough.h index 5793330..bb62e8a 100644 --- a/backend/include/rcc/CodeGen/MachineFallthrough.h +++ b/backend/include/rcc/CodeGen/MachineFallthrough.h @@ -3,7 +3,7 @@ #ifndef RCC_CODEGEN_MACHINEFALLTHROUGH_H #define RCC_CODEGEN_MACHINEFALLTHROUGH_H -#include "rcc/CodeGen/MachinePass.h" +#include "rcc/CodeGen/MachinePassManager.h" namespace rcc { @@ -16,7 +16,7 @@ public: [[nodiscard]] const MachinePassContract &contract() const noexcept override; [[nodiscard]] Expected run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses) override; + MachineFunctionAnalysisManager &Analyses) override; private: const TargetInstrInfo *Info; diff --git a/backend/include/rcc/CodeGen/MachineFinalization.h b/backend/include/rcc/CodeGen/MachineFinalization.h index 1927691..d12ee0b 100644 --- a/backend/include/rcc/CodeGen/MachineFinalization.h +++ b/backend/include/rcc/CodeGen/MachineFinalization.h @@ -3,7 +3,7 @@ #ifndef RCC_CODEGEN_MACHINEFINALIZATION_H #define RCC_CODEGEN_MACHINEFINALIZATION_H -#include "rcc/CodeGen/MachinePass.h" +#include "rcc/CodeGen/MachinePassManager.h" namespace rcc { @@ -14,7 +14,7 @@ public: [[nodiscard]] const MachinePassContract &contract() const noexcept override; [[nodiscard]] Expected run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses) override; + MachineFunctionAnalysisManager &Analyses) override; }; class FinalEncodabilityVerifierPass final : public MachineFunctionPass { @@ -25,7 +25,7 @@ public: [[nodiscard]] const MachinePassContract &contract() const noexcept override; [[nodiscard]] Expected run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses) override; + MachineFunctionAnalysisManager &Analyses) override; private: const TargetInstrInfo *BranchInfo; diff --git a/backend/include/rcc/CodeGen/MachineFunctionAnalysisManager.h b/backend/include/rcc/CodeGen/MachineFunctionAnalysisManager.h new file mode 100644 index 0000000..9685e45 --- /dev/null +++ b/backend/include/rcc/CodeGen/MachineFunctionAnalysisManager.h @@ -0,0 +1,133 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef RCC_CODEGEN_MACHINEFUNCTIONANALYSISMANAGER_H +#define RCC_CODEGEN_MACHINEFUNCTIONANALYSISMANAGER_H + +#include "rcc/CodeGen/StableID.h" +#include "rcc/IR/PassManager.h" + +#include +#include + +namespace rcc { + +class CompilationUnit; +class MachineFunction; +class MachinePassInstrumentation; + +enum class MachinePassChange : std::uint32_t { + None = 0, + Instructions = 1U << 0U, + Operands = 1U << 1U, + Registers = 1U << 2U, + CFG = 1U << 3U, + BlockLayout = 1U << 4U, + Frame = 1U << 5U, + ConstantPool = 1U << 6U, + JumpTable = 1U << 7U, + TargetState = 1U << 8U, +}; + +class MachinePassChanges final { +public: + constexpr MachinePassChanges() noexcept = default; + constexpr MachinePassChanges(std::initializer_list Changes) noexcept { + for (const MachinePassChange Change : Changes) + add(Change); + } + + [[nodiscard]] static constexpr MachinePassChanges all() noexcept { + return fromRaw((1U << 9U) - 1U); + } + + [[nodiscard]] static constexpr MachinePassChanges fromRaw(std::uint32_t Bits) noexcept { + MachinePassChanges Result; + Result.Bits = Bits & rawMask(); + return Result; + } + + constexpr void add(MachinePassChange Change) noexcept { + Bits |= static_cast(Change); + } + + [[nodiscard]] constexpr bool has(MachinePassChange Change) const noexcept { + return (Bits & static_cast(Change)) != 0; + } + + [[nodiscard]] constexpr bool contains(MachinePassChanges Other) const noexcept { + return (Bits & Other.Bits) == Other.Bits; + } + + [[nodiscard]] constexpr bool intersects(MachinePassChanges Other) const noexcept { + return (Bits & Other.Bits) != 0; + } + + [[nodiscard]] constexpr bool empty() const noexcept { + return Bits == 0; + } + + [[nodiscard]] constexpr std::uint32_t rawValue() const noexcept { + return Bits; + } + + friend constexpr bool operator==(MachinePassChanges Left, + MachinePassChanges Right) noexcept = default; + +private: + [[nodiscard]] static constexpr std::uint32_t rawMask() noexcept { + return (1U << 9U) - 1U; + } + + std::uint32_t Bits = 0; +}; + +template <> +struct AnalysisManagerInstrumentation final { + static void beforeAnalysis(MachinePassInstrumentation *Instrumentation, std::string_view Name, + const MachineFunction &Function); + static void afterAnalysis(MachinePassInstrumentation *Instrumentation, std::string_view Name, + const MachineFunction &Function, bool CacheHit, + std::uint64_t Nanoseconds); + static void analysisFailure(MachinePassInstrumentation *Instrumentation, std::string_view Name, + const MachineFunction &Function, const Error &Failure, + std::uint64_t Nanoseconds); + [[nodiscard]] static Expected requestAction(MachinePassInstrumentation *Instrumentation, + std::string_view Pass, std::string_view Rule, + const MachineFunction &Function, + MachineInstrStableID Instruction, + std::uint64_t Cost); + [[nodiscard]] static Expected requestAction(MachinePassInstrumentation *Instrumentation, + std::string_view Pass, std::string_view Rule, + const MachineFunction &Function, std::nullptr_t, + std::uint64_t Cost); +}; + +template <> +struct AnalysisManagerInstrumentation final { + static void beforeAnalysis(MachinePassInstrumentation *Instrumentation, std::string_view Name, + const CompilationUnit &Unit); + static void afterAnalysis(MachinePassInstrumentation *Instrumentation, std::string_view Name, + const CompilationUnit &Unit, bool CacheHit, std::uint64_t Nanoseconds); + static void analysisFailure(MachinePassInstrumentation *Instrumentation, std::string_view Name, + const CompilationUnit &Unit, const Error &Failure, + std::uint64_t Nanoseconds); +}; + +using MachineAnalysisRegistration = AnalysisRegistration; +using CompilationUnitAnalysisRegistration = AnalysisRegistration; + +using MachineFunctionAnalysisManager = + AnalysisManager; +using CompilationUnitAnalysisManager = + AnalysisManager; + +[[nodiscard]] Expected +registerStage8MachineAnalyses(MachineFunctionAnalysisManager &Analyses); +[[nodiscard]] Expected +registerStage11MachineAnalyses(MachineFunctionAnalysisManager &Analyses); + +} // namespace rcc + +#endif // RCC_CODEGEN_MACHINEFUNCTIONANALYSISMANAGER_H diff --git a/backend/include/rcc/CodeGen/MachineLICM.h b/backend/include/rcc/CodeGen/MachineLICM.h index 66b7ef8..5efaf20 100644 --- a/backend/include/rcc/CodeGen/MachineLICM.h +++ b/backend/include/rcc/CodeGen/MachineLICM.h @@ -3,7 +3,7 @@ #ifndef RCC_CODEGEN_MACHINELICM_H #define RCC_CODEGEN_MACHINELICM_H -#include "rcc/CodeGen/MachinePass.h" +#include "rcc/CodeGen/MachinePassManager.h" #include #include @@ -29,12 +29,12 @@ public: [[nodiscard]] const MachinePassContract &contract() const noexcept override; [[nodiscard]] Expected run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses) override; + MachineFunctionAnalysisManager &Analyses) override; private: - [[nodiscard]] Expected runImplementation(MachineFunction &Function, - const TargetDescription &Target, - MachineAnalysisManager &Analyses); + [[nodiscard]] Expected + runImplementation(MachineFunction &Function, const TargetDescription &Target, + MachineFunctionAnalysisManager &Analyses); MachineCodeMotionStage Stage = MachineCodeMotionStage::SelectedSSA; MachineLICMOptions Options; diff --git a/backend/include/rcc/CodeGen/MachineMemoryFolding.h b/backend/include/rcc/CodeGen/MachineMemoryFolding.h index 9a5b47a..9f415d7 100644 --- a/backend/include/rcc/CodeGen/MachineMemoryFolding.h +++ b/backend/include/rcc/CodeGen/MachineMemoryFolding.h @@ -3,7 +3,7 @@ #ifndef RCC_CODEGEN_MACHINEMEMORYFOLDING_H #define RCC_CODEGEN_MACHINEMEMORYFOLDING_H -#include "rcc/CodeGen/MachinePass.h" +#include "rcc/CodeGen/MachinePassManager.h" #include @@ -24,7 +24,7 @@ public: [[nodiscard]] const MachinePassContract &contract() const noexcept override; [[nodiscard]] Expected run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses) override; + MachineFunctionAnalysisManager &Analyses) override; private: [[nodiscard]] Expected diff --git a/backend/include/rcc/CodeGen/MachineOptimizationPipeline.h b/backend/include/rcc/CodeGen/MachineOptimizationPipeline.h index 10bcbc6..51b4ed2 100644 --- a/backend/include/rcc/CodeGen/MachineOptimizationPipeline.h +++ b/backend/include/rcc/CodeGen/MachineOptimizationPipeline.h @@ -3,7 +3,7 @@ #ifndef RCC_CODEGEN_MACHINEOPTIMIZATIONPIPELINE_H #define RCC_CODEGEN_MACHINEOPTIMIZATIONPIPELINE_H -#include "rcc/CodeGen/MachinePass.h" +#include "rcc/CodeGen/MachinePassManager.h" namespace rcc { @@ -23,17 +23,18 @@ struct MachineOptimizationPipelineTargetInfo final { const TargetSchedulingModel &SchedulingModel; }; -[[nodiscard]] Expected registerMachineOptimizationAnalyses(MachineAnalysisManager &Analyses); +[[nodiscard]] Expected +registerMachineOptimizationAnalyses(MachineFunctionAnalysisManager &Analyses); [[nodiscard]] Expected -addSelectedSSAOptimizationPipeline(MachinePassManager &Pipeline, +addSelectedSSAOptimizationPipeline(MachineFunctionPassManager &Pipeline, const MachineOptimizationPipelineTargetInfo &TargetInfo); [[nodiscard]] Expected addPreRegisterAllocationOptimizationPipeline( - MachinePassManager &Pipeline, const MachineOptimizationPipelineTargetInfo &TargetInfo); + MachineFunctionPassManager &Pipeline, const MachineOptimizationPipelineTargetInfo &TargetInfo); [[nodiscard]] Expected -addPostRegisterAllocationPipeline(MachinePassManager &Pipeline, +addPostRegisterAllocationPipeline(MachineFunctionPassManager &Pipeline, const MachineOptimizationPipelineTargetInfo &TargetInfo); } // namespace rcc diff --git a/backend/include/rcc/CodeGen/MachinePass.h b/backend/include/rcc/CodeGen/MachinePass.h deleted file mode 100644 index ee67924..0000000 --- a/backend/include/rcc/CodeGen/MachinePass.h +++ /dev/null @@ -1,720 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later - -#ifndef RCC_CODEGEN_MACHINEPASS_H -#define RCC_CODEGEN_MACHINEPASS_H - -#include "rcc/CodeGen/InstructionDescriptor.h" -#include "rcc/CodeGen/MachineFunctionProperties.h" -#include "rcc/CodeGen/StableID.h" -#include "rcc/Support/Error.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace rcc { - -class CompilationUnit; -class MachineFunction; -class MachineVerifier; -class TargetDescription; - -using AnalysisID = const void *; - -enum class MachinePassChange : std::uint32_t { - None = 0, - Instructions = 1U << 0U, - Operands = 1U << 1U, - Registers = 1U << 2U, - CFG = 1U << 3U, - BlockLayout = 1U << 4U, - Frame = 1U << 5U, - ConstantPool = 1U << 6U, - JumpTable = 1U << 7U, - TargetState = 1U << 8U, -}; - -class MachinePassChanges final { -public: - constexpr MachinePassChanges() noexcept = default; - constexpr MachinePassChanges(std::initializer_list Changes) noexcept { - for (const MachinePassChange Change : Changes) - add(Change); - } - - [[nodiscard]] static constexpr MachinePassChanges all() noexcept { - return fromRaw((1U << 9U) - 1U); - } - - [[nodiscard]] static constexpr MachinePassChanges fromRaw(std::uint32_t Bits) noexcept { - MachinePassChanges Result; - Result.Bits = Bits & rawMask(); - return Result; - } - - constexpr void add(MachinePassChange Change) noexcept { - Bits |= static_cast(Change); - } - - [[nodiscard]] constexpr bool has(MachinePassChange Change) const noexcept { - return (Bits & static_cast(Change)) != 0; - } - - [[nodiscard]] constexpr bool contains(MachinePassChanges Other) const noexcept { - return (Bits & Other.Bits) == Other.Bits; - } - - [[nodiscard]] constexpr bool intersects(MachinePassChanges Other) const noexcept { - return (Bits & Other.Bits) != 0; - } - - [[nodiscard]] constexpr bool empty() const noexcept { - return Bits == 0; - } - - [[nodiscard]] constexpr std::uint32_t rawValue() const noexcept { - return Bits; - } - - friend constexpr bool operator==(MachinePassChanges Left, - MachinePassChanges Right) noexcept = default; - -private: - [[nodiscard]] static constexpr std::uint32_t rawMask() noexcept { - return (1U << 9U) - 1U; - } - - std::uint32_t Bits = 0; -}; - -class PreservedAnalyses final { -public: - [[nodiscard]] static PreservedAnalyses all() noexcept { - PreservedAnalyses Result; - Result.PreserveAll = true; - return Result; - } - - [[nodiscard]] static PreservedAnalyses none() noexcept { - return {}; - } - - void preserve(AnalysisID ID) { - if (ID != nullptr) - Preserved.insert(ID); - } - - template void preserve() { - preserve(analysisID()); - } - - [[nodiscard]] bool preserves(AnalysisID ID) const noexcept { - return PreserveAll || (ID != nullptr && Preserved.contains(ID)); - } - - [[nodiscard]] bool preservesAll() const noexcept { - return PreserveAll; - } - - template [[nodiscard]] static AnalysisID analysisID() noexcept { - static const std::uint8_t Token = 0; - return &Token; - } - -private: - bool PreserveAll = false; - std::unordered_set Preserved; -}; - -enum class PassThreadSafety : std::uint8_t { - NotThreadSafe, - ThreadSafe, -}; - -struct PassParameter final { - std::string Name; - std::string Description; - std::optional DefaultValue; - bool Required = false; -}; - -struct MachinePassRegistrationMetadata { - std::vector Parameters; - PassThreadSafety ThreadSafety = PassThreadSafety::NotThreadSafe; - MachinePassChanges DeclaredChanges = MachinePassChanges::all(); -}; - -struct MachinePassContract final : MachinePassRegistrationMetadata { - std::string Name; - MachineFunctionProperties Requires; - MachineFunctionProperties Sets; - MachineFunctionProperties Clears; - std::vector RequiredAnalyses; - std::optional VerificationStage; -}; - -struct MachinePassResult final { - bool Changed = false; - MachinePassChanges Changes; - PreservedAnalyses Preserved = PreservedAnalyses::none(); -}; - -struct CompilationUnitPassContract final { - std::string Name; - std::vector RequiredAnalyses; - std::vector Parameters; - MachinePassChanges DeclaredChanges = MachinePassChanges::all(); -}; - -struct CompilationUnitPassResult final { - bool Changed = false; - MachinePassChanges Changes; - PreservedAnalyses PreservedUnitAnalyses = PreservedAnalyses::none(); - PreservedAnalyses PreservedFunctionAnalyses = PreservedAnalyses::none(); -}; - -struct MachineAnalysisRegistration final { - AnalysisID ID = nullptr; - std::string Name; - std::vector Dependencies; - MachinePassChanges InvalidatedBy = MachinePassChanges::all(); - PassThreadSafety ThreadSafety = PassThreadSafety::NotThreadSafe; -}; - -struct CompilationUnitAnalysisRegistration final { - AnalysisID ID = nullptr; - std::string Name; - std::vector Dependencies; - MachinePassChanges InvalidatedBy = MachinePassChanges::all(); -}; - -class MachinePassInstrumentation; - -class MachineAnalysisManager final { -public: - MachineAnalysisManager() = default; - MachineAnalysisManager(const MachineAnalysisManager &) = delete; - MachineAnalysisManager &operator=(const MachineAnalysisManager &) = delete; - MachineAnalysisManager(MachineAnalysisManager &&) = delete; - MachineAnalysisManager &operator=(MachineAnalysisManager &&) = delete; - ~MachineAnalysisManager() = default; - - template [[nodiscard]] static AnalysisID id() noexcept { - return PreservedAnalyses::analysisID(); - } - - template - [[nodiscard]] Expected registerAnalysis(MachineAnalysisRegistration Registration = {}) { - using ResultT = typename AnalysisT::Result; - if (Registration.ID == nullptr) - Registration.ID = id(); - if (Registration.Name.empty()) { - if constexpr (requires { - { AnalysisT::name() } -> std::convertible_to; - }) { - Registration.Name = std::string(AnalysisT::name()); - } else { - Registration.Name = "unnamed-machine-analysis"; - } - } - - ErasedRunner Runner = [](MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Manager) -> Expected> { - auto Computed = AnalysisT::run(Function, Target, Manager); - if (!Computed) - return std::unexpected(Computed.error()); - return std::shared_ptr(new ResultT(std::move(*Computed)), - [](void *Value) { delete static_cast(Value); }); - }; - ErasedInvalidator Invalidator = [](void *Value, const MachineFunction &Function, - const PreservedAnalyses &Preserved) -> bool { - if constexpr (requires(ResultT &Result, const MachineFunction &InputFunction, - const PreservedAnalyses &Analyses) { - { Result.invalidate(InputFunction, Analyses) } -> std::convertible_to; - }) { - return static_cast(Value)->invalidate(Function, Preserved); - } - return true; - }; - return registerAnalysisImpl(std::move(Registration), std::move(Runner), std::move(Invalidator)); - } - - template - [[nodiscard]] Expected getResult(MachineFunction &Function, - const TargetDescription &Target) { - const AnalysisID Key = id(); - if (!isRegistered(Key)) { - auto Registered = registerAnalysis(); - if (!Registered) - return std::unexpected(Registered.error()); - } - auto Result = getResultImpl(Key, Function, Target); - if (!Result) - return std::unexpected(Result.error()); - return static_cast(*Result); - } - - void invalidate(MachineFunction &Function, const PreservedAnalyses &Preserved, - MachinePassChanges Changes) noexcept; - void invalidate(MachineFunction &Function, const PreservedAnalyses &Preserved) noexcept { - invalidate(Function, Preserved, MachinePassChanges::all()); - } - [[nodiscard]] bool hasCached(const MachineFunction &Function, AnalysisID ID) const noexcept; - [[nodiscard]] bool isRegistered(AnalysisID ID) const noexcept; - [[nodiscard]] std::size_t cachedResultCount(const MachineFunction &Function) const noexcept; - void clear(MachineFunction &Function) noexcept; - void clearAll() noexcept; - - [[nodiscard]] Expected> forkEmpty() const; - [[nodiscard]] Expected - requestAction(std::string_view Action, const MachineFunction &Function, std::uint64_t Cost = 1); - [[nodiscard]] Expected requestAction(std::string_view Rule, const MachineFunction &Function, - MachineInstrStableID Instruction, - std::uint64_t Cost = 1); - -private: - using ErasedRunner = std::function>( - MachineFunction &, const TargetDescription &, MachineAnalysisManager &)>; - using ErasedInvalidator = - std::function; - - struct RegisteredAnalysis final { - MachineAnalysisRegistration Info; - ErasedRunner Runner; - ErasedInvalidator Invalidator; - }; - - struct CacheEntry final { - std::shared_ptr Value; - AnalysisID ID = nullptr; - }; - - [[nodiscard]] Expected registerAnalysisImpl(MachineAnalysisRegistration Registration, - ErasedRunner Runner, - ErasedInvalidator Invalidator); - [[nodiscard]] Expected getResultImpl(AnalysisID ID, MachineFunction &Function, - const TargetDescription &Target); - [[nodiscard]] Expected materializeDependencies(const RegisteredAnalysis &Registration, - MachineFunction &Function, - const TargetDescription &Target); - [[nodiscard]] Expected - validateParallelRequirements(std::span RequiredAnalyses) const; - void setInstrumentation(MachinePassInstrumentation *NewInstrumentation) noexcept { - Instrumentation = NewInstrumentation; - } - - std::unordered_map Registry; - std::unordered_map> Cache; - std::unordered_map> ActiveComputations; - MachinePassInstrumentation *Instrumentation = nullptr; - std::string ActivePass; - - friend class MachinePassManager; - friend class CompilationUnitPassManager; - friend Expected registerStage8MachineAnalyses(MachineAnalysisManager &Analyses); - friend Expected registerStage11MachineAnalyses(MachineAnalysisManager &Analyses); -}; - -class CompilationUnitAnalysisManager final { -public: - CompilationUnitAnalysisManager() = default; - CompilationUnitAnalysisManager(const CompilationUnitAnalysisManager &) = delete; - CompilationUnitAnalysisManager &operator=(const CompilationUnitAnalysisManager &) = delete; - CompilationUnitAnalysisManager(CompilationUnitAnalysisManager &&) = delete; - CompilationUnitAnalysisManager &operator=(CompilationUnitAnalysisManager &&) = delete; - ~CompilationUnitAnalysisManager() = default; - - template [[nodiscard]] static AnalysisID id() noexcept { - return PreservedAnalyses::analysisID(); - } - - template - [[nodiscard]] Expected - registerAnalysis(CompilationUnitAnalysisRegistration Registration = {}) { - using ResultT = typename AnalysisT::Result; - if (Registration.ID == nullptr) - Registration.ID = id(); - if (Registration.Name.empty()) { - if constexpr (requires { - { AnalysisT::name() } -> std::convertible_to; - }) { - Registration.Name = std::string(AnalysisT::name()); - } else { - Registration.Name = "unnamed-compilation-unit-analysis"; - } - } - - ErasedRunner Runner = - [](CompilationUnit &Unit, const TargetDescription &Target, - CompilationUnitAnalysisManager &Manager) -> Expected> { - auto Computed = AnalysisT::run(Unit, Target, Manager); - if (!Computed) - return std::unexpected(Computed.error()); - return std::shared_ptr(new ResultT(std::move(*Computed)), - [](void *Value) { delete static_cast(Value); }); - }; - ErasedInvalidator Invalidator = [](void *Value, const CompilationUnit &Unit, - const PreservedAnalyses &Preserved) -> bool { - if constexpr (requires(ResultT &Result, const CompilationUnit &InputUnit, - const PreservedAnalyses &Analyses) { - { Result.invalidate(InputUnit, Analyses) } -> std::convertible_to; - }) { - return static_cast(Value)->invalidate(Unit, Preserved); - } - return true; - }; - return registerAnalysisImpl(std::move(Registration), std::move(Runner), std::move(Invalidator)); - } - - template - [[nodiscard]] Expected getResult(CompilationUnit &Unit, - const TargetDescription &Target) { - const AnalysisID Key = id(); - if (!isRegistered(Key)) { - auto Registered = registerAnalysis(); - if (!Registered) - return std::unexpected(Registered.error()); - } - auto Result = getResultImpl(Key, Unit, Target); - if (!Result) - return std::unexpected(Result.error()); - return static_cast(*Result); - } - - void invalidate(CompilationUnit &Unit, const PreservedAnalyses &Preserved, - MachinePassChanges Changes) noexcept; - [[nodiscard]] bool hasCached(const CompilationUnit &Unit, AnalysisID ID) const noexcept; - [[nodiscard]] bool isRegistered(AnalysisID ID) const noexcept; - void clear(CompilationUnit &Unit) noexcept; - void clearAll() noexcept; - -private: - using ErasedRunner = std::function>( - CompilationUnit &, const TargetDescription &, CompilationUnitAnalysisManager &)>; - using ErasedInvalidator = - std::function; - - struct RegisteredAnalysis final { - CompilationUnitAnalysisRegistration Info; - ErasedRunner Runner; - ErasedInvalidator Invalidator; - }; - - struct CacheEntry final { - std::shared_ptr Value; - AnalysisID ID = nullptr; - }; - - [[nodiscard]] Expected - registerAnalysisImpl(CompilationUnitAnalysisRegistration Registration, ErasedRunner Runner, - ErasedInvalidator Invalidator); - [[nodiscard]] Expected getResultImpl(AnalysisID ID, CompilationUnit &Unit, - const TargetDescription &Target); - [[nodiscard]] Expected materializeDependencies(const RegisteredAnalysis &Registration, - CompilationUnit &Unit, - const TargetDescription &Target); - void setInstrumentation(MachinePassInstrumentation *NewInstrumentation) noexcept { - Instrumentation = NewInstrumentation; - } - - std::unordered_map Registry; - std::unordered_map> Cache; - std::unordered_map> ActiveComputations; - MachinePassInstrumentation *Instrumentation = nullptr; - - friend class CompilationUnitPassManager; -}; - -class MachineFunctionPass { -public: - MachineFunctionPass() = default; - MachineFunctionPass(const MachineFunctionPass &) = delete; - MachineFunctionPass &operator=(const MachineFunctionPass &) = delete; - virtual ~MachineFunctionPass() = default; - - [[nodiscard]] virtual const MachinePassContract &contract() const noexcept = 0; - [[nodiscard]] virtual Expected run(MachineFunction &Function, - const TargetDescription &Target, - MachineAnalysisManager &Analyses) = 0; -}; - -class CompilationUnitPass { -public: - CompilationUnitPass() = default; - CompilationUnitPass(const CompilationUnitPass &) = delete; - CompilationUnitPass &operator=(const CompilationUnitPass &) = delete; - virtual ~CompilationUnitPass() = default; - - [[nodiscard]] virtual const CompilationUnitPassContract &contract() const noexcept = 0; - [[nodiscard]] virtual Expected - run(CompilationUnit &Unit, const TargetDescription &Target, - CompilationUnitAnalysisManager &UnitAnalyses, MachineAnalysisManager &FunctionAnalyses) = 0; -}; - -enum class InstrumentationPhase : std::uint8_t { - Before, - After, -}; - -struct InstrumentationStatistic final { - std::string Name; - bool IsAnalysis = false; - std::uint64_t Invocations = 0; - std::uint64_t CacheHits = 0; - std::uint64_t Changes = 0; - std::uint64_t Failures = 0; - std::uint64_t TotalNanoseconds = 0; -}; - -struct MachineActionID final { - std::string Pass; - std::string Rule; - MachineFunctionStableID Function; - MachineInstrStableID Instruction; - - [[nodiscard]] std::string toString() const; - - friend bool operator==(const MachineActionID &, const MachineActionID &) = default; -}; - -struct MachineActionEvent final { - MachineActionID ID; - std::uint64_t Cost = 0; - bool Accepted = false; - - friend bool operator==(const MachineActionEvent &, const MachineActionEvent &) = default; -}; - -class MachineActionReplay final { -public: - explicit MachineActionReplay(MachineAnalysisManager &Analyses) noexcept : Analyses(&Analyses) {} - MachineActionReplay( - MachineAnalysisManager &Analyses, - const std::unordered_map &SourceToClone) - : Analyses(&Analyses) { - for (const auto &[Source, Clone] : SourceToClone) - RecordingInstructionIDs.try_emplace(Clone, Source); - } - - [[nodiscard]] Expected request(std::string_view Rule, const MachineFunction &Function, - MachineInstrStableID Instruction = {}, - std::uint64_t Cost = 1); - void beginReplay() noexcept; - [[nodiscard]] Expected finishReplay() const; - -private: - struct Decision final { - std::string Rule; - MachineFunctionStableID Function; - MachineInstrStableID Instruction; - std::uint64_t Cost = 0; - bool Accepted = false; - }; - - MachineAnalysisManager *Analyses = nullptr; - std::unordered_map RecordingInstructionIDs; - std::vector Decisions; - std::size_t NextDecision = 0; - bool IsReplaying = false; -}; - -class MachinePassInstrumentation final { -public: - using BeforeCallback = std::function; - using AfterCallback = - std::function; - using FailureCallback = - std::function; - using BeforeAnalysisCallback = std::function; - using AfterAnalysisCallback = - std::function; - using AnalysisFailureCallback = - std::function; - using IRPrintCallback = - std::function; - using ChangeCallback = - std::function; - using ActionFilter = std::function; - - using BeforeUnitCallback = std::function; - using AfterUnitCallback = std::function; - using UnitFailureCallback = - std::function; - using BeforeUnitAnalysisCallback = std::function; - using AfterUnitAnalysisCallback = - std::function; - using UnitAnalysisFailureCallback = - std::function; - - void addBeforeCallback(BeforeCallback Callback); - void addAfterCallback(AfterCallback Callback); - void addFailureCallback(FailureCallback Callback); - void addBeforeAnalysisCallback(BeforeAnalysisCallback Callback); - void addAfterAnalysisCallback(AfterAnalysisCallback Callback); - void addAnalysisFailureCallback(AnalysisFailureCallback Callback); - void addIRPrintCallback(IRPrintCallback Callback); - void addChangeCallback(ChangeCallback Callback); - void setActionFilter(ActionFilter Filter); - void setPerFunctionFuel(std::optional Fuel); - - void addBeforeUnitCallback(BeforeUnitCallback Callback); - void addAfterUnitCallback(AfterUnitCallback Callback); - void addUnitFailureCallback(UnitFailureCallback Callback); - void addBeforeUnitAnalysisCallback(BeforeUnitAnalysisCallback Callback); - void addAfterUnitAnalysisCallback(AfterUnitAnalysisCallback Callback); - void addUnitAnalysisFailureCallback(UnitAnalysisFailureCallback Callback); - - [[nodiscard]] std::vector statistics() const; - [[nodiscard]] std::vector actionEvents() const; - void clearStatistics(); - -private: - struct BufferedEvents final { - const TargetDescription *Target = nullptr; - std::vector> Events; - }; - - [[nodiscard]] bool bufferFunctionEvent(const MachineFunction &Function, - std::function Replay) const; - void beginBuffering(BufferedEvents &Buffer, const TargetDescription &Target) const noexcept; - void endBuffering() const noexcept; - void replayBufferedEvents(BufferedEvents &Buffer) const; - - void before(std::string_view Name, const MachineFunction &Function) const; - void after(std::string_view Name, const MachineFunction &Function, - const MachinePassResult &Result, std::uint64_t Nanoseconds) const; - void failure(std::string_view Name, const MachineFunction &Function, const Error &ErrorValue, - std::uint64_t Nanoseconds = 0) const; - void beforeAnalysis(std::string_view Name, const MachineFunction &Function) const; - void afterAnalysis(std::string_view Name, const MachineFunction &Function, bool CacheHit, - std::uint64_t Nanoseconds) const; - void analysisFailure(std::string_view Name, const MachineFunction &Function, - const Error &ErrorValue, std::uint64_t Nanoseconds) const; - void change(std::string_view Name, const MachineFunction &Function, MachinePassChanges Changes, - bool FingerprintChanged) const; - [[nodiscard]] Expected requestAction(const MachineActionID &Action, - const MachineFunction &Function, std::uint64_t Cost); - - void beforeUnit(std::string_view Name, const CompilationUnit &Unit) const; - void afterUnit(std::string_view Name, const CompilationUnit &Unit, - const CompilationUnitPassResult &Result, std::uint64_t Nanoseconds) const; - void unitFailure(std::string_view Name, const CompilationUnit &Unit, const Error &ErrorValue, - std::uint64_t Nanoseconds = 0) const; - void beforeUnitAnalysis(std::string_view Name, const CompilationUnit &Unit) const; - void afterUnitAnalysis(std::string_view Name, const CompilationUnit &Unit, bool CacheHit, - std::uint64_t Nanoseconds) const; - void unitAnalysisFailure(std::string_view Name, const CompilationUnit &Unit, - const Error &ErrorValue, std::uint64_t Nanoseconds) const; - - [[nodiscard]] InstrumentationStatistic &statistic(std::string_view Name, bool IsAnalysis) const; - - mutable std::mutex Mutex; - mutable std::mutex ActionMutex; - std::vector Before; - std::vector After; - std::vector Failure; - std::vector BeforeAnalysis; - std::vector AfterAnalysis; - std::vector AnalysisFailure; - std::vector IRPrint; - std::vector Change; - ActionFilter Filter; - std::optional PerFunctionFuel; - std::unordered_map ConsumedFuel; - std::vector ActionEvents; - - std::vector BeforeUnit; - std::vector AfterUnit; - std::vector UnitFailure; - std::vector BeforeUnitAnalysis; - std::vector AfterUnitAnalysis; - std::vector UnitAnalysisFailure; - mutable std::unordered_map Statistics; - - static thread_local BufferedEvents *ActiveBuffer; - - friend class CompilationUnitAnalysisManager; - friend class CompilationUnitPassManager; - friend class MachineAnalysisManager; - friend class MachinePassManager; -}; - -struct MachinePassManagerOptions final { - bool VerifyBefore = true; - bool VerifyEach = true; - bool DetectUnreportedChanges = false; -}; - -class MachinePassManager final { -public: - using PassList = std::vector>; - - explicit MachinePassManager(MachinePassManagerOptions Options = {}) : Options(Options) {} - - MachinePassManager(const MachinePassManager &) = delete; - MachinePassManager &operator=(const MachinePassManager &) = delete; - - [[nodiscard]] Expected addPass(std::unique_ptr Pass); - [[nodiscard]] Expected run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses, - MachinePassInstrumentation *Instrumentation = nullptr) const; - [[nodiscard]] Expected - runFunctions(CompilationUnit &Unit, const TargetDescription &Target, - const MachineAnalysisManager &AnalysisPrototype, std::size_t ThreadCount, - MachinePassInstrumentation *Instrumentation = nullptr) const; - - [[nodiscard]] std::size_t size() const noexcept { - return Passes.size(); - } - - [[nodiscard]] PassList takePasses() && noexcept { - return std::move(Passes); - } - -private: - [[nodiscard]] Expected validateContract(const MachinePassContract &Contract) const; - - MachinePassManagerOptions Options; - PassList Passes; -}; - -struct CompilationUnitPassManagerOptions final { - bool VerifyBefore = true; - bool VerifyEach = true; -}; - -class CompilationUnitPassManager final { -public: - explicit CompilationUnitPassManager(CompilationUnitPassManagerOptions Options = {}) - : Options(Options) {} - - CompilationUnitPassManager(const CompilationUnitPassManager &) = delete; - CompilationUnitPassManager &operator=(const CompilationUnitPassManager &) = delete; - - [[nodiscard]] Expected addPass(std::unique_ptr Pass); - [[nodiscard]] Expected run(CompilationUnit &Unit, const TargetDescription &Target, - CompilationUnitAnalysisManager &UnitAnalyses, - MachineAnalysisManager &FunctionAnalyses, - MachinePassInstrumentation *Instrumentation = nullptr) const; - -private: - CompilationUnitPassManagerOptions Options; - std::vector> Passes; -}; - -} // namespace rcc - -#endif // RCC_CODEGEN_MACHINEPASS_H diff --git a/backend/include/rcc/CodeGen/MachinePassManager.h b/backend/include/rcc/CodeGen/MachinePassManager.h new file mode 100644 index 0000000..3587395 --- /dev/null +++ b/backend/include/rcc/CodeGen/MachinePassManager.h @@ -0,0 +1,134 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef RCC_CODEGEN_MACHINEPASSMANAGER_H +#define RCC_CODEGEN_MACHINEPASSMANAGER_H + +#include "rcc/CodeGen/InstructionDescriptor.h" +#include "rcc/CodeGen/MachineFunctionAnalysisManager.h" +#include "rcc/CodeGen/MachineFunctionProperties.h" +#include "rcc/IR/PassInstrumentation.h" + +#include +#include +#include +#include +#include + +namespace rcc { + +class CompilationUnit; +class MachineFunction; +class TargetDescription; + +struct MachinePassRegistrationMetadata { + std::vector Parameters; + PassThreadSafety ThreadSafety = PassThreadSafety::NotThreadSafe; + MachinePassChanges DeclaredChanges = MachinePassChanges::all(); +}; + +struct MachinePassContract final : MachinePassRegistrationMetadata { + std::string Name; + MachineFunctionProperties Requires; + MachineFunctionProperties Sets; + MachineFunctionProperties Clears; + std::vector RequiredAnalyses; + std::optional VerificationStage; +}; + +struct MachinePassResult final { + bool Changed = false; + MachinePassChanges Changes; + PreservedAnalyses Preserved = PreservedAnalyses::none(); +}; + +struct CompilationUnitPassContract final { + std::string Name; + std::vector RequiredAnalyses; + std::vector Parameters; + MachinePassChanges DeclaredChanges = MachinePassChanges::all(); +}; + +struct CompilationUnitPassResult final { + bool Changed = false; + MachinePassChanges Changes; + PreservedAnalyses PreservedUnitAnalyses = PreservedAnalyses::none(); + PreservedAnalyses PreservedFunctionAnalyses = PreservedAnalyses::none(); +}; + +class MachineFunctionPass { +public: + MachineFunctionPass() = default; + MachineFunctionPass(const MachineFunctionPass &) = delete; + MachineFunctionPass &operator=(const MachineFunctionPass &) = delete; + virtual ~MachineFunctionPass() = default; + + [[nodiscard]] virtual const MachinePassContract &contract() const noexcept = 0; + [[nodiscard]] virtual Expected + run(MachineFunction &Function, const TargetDescription &Target, + MachineFunctionAnalysisManager &Analyses) = 0; +}; + +class CompilationUnitPass { +public: + CompilationUnitPass() = default; + CompilationUnitPass(const CompilationUnitPass &) = delete; + CompilationUnitPass &operator=(const CompilationUnitPass &) = delete; + virtual ~CompilationUnitPass() = default; + + [[nodiscard]] virtual const CompilationUnitPassContract &contract() const noexcept = 0; + [[nodiscard]] virtual Expected + run(CompilationUnit &Unit, const TargetDescription &Target, + CompilationUnitAnalysisManager &UnitAnalyses, + MachineFunctionAnalysisManager &FunctionAnalyses) = 0; +}; + +struct MachinePassManagerOptions final { + bool VerifyBefore = true; + bool VerifyEach = true; + bool DetectUnreportedChanges = false; +}; + +template <> +struct PassManagerCallbacks final { + using PassList = std::vector>; + + [[nodiscard]] static Expected validate(const MachineFunctionPass &Pass); + [[nodiscard]] static Expected + run(const PassList &Passes, const MachinePassManagerOptions &Options, MachineFunction &Function, + const TargetDescription &Target, MachineFunctionAnalysisManager &Analyses, + MachinePassInstrumentation *Instrumentation = nullptr); + [[nodiscard]] static Expected + runFunctions(const PassList &Passes, const MachinePassManagerOptions &Options, + CompilationUnit &Unit, const TargetDescription &Target, + const MachineFunctionAnalysisManager &AnalysisPrototype, std::size_t ThreadCount, + MachinePassInstrumentation *Instrumentation = nullptr); +}; + +using MachineFunctionPassManager = + PassManager; + +struct CompilationUnitPassManagerOptions final { + bool VerifyBefore = true; + bool VerifyEach = true; +}; + +template <> +struct PassManagerCallbacks + final { + using PassList = std::vector>; + + [[nodiscard]] static Expected validate(const CompilationUnitPass &Pass); + [[nodiscard]] static Expected run(const PassList &Passes, + const CompilationUnitPassManagerOptions &Options, + CompilationUnit &Unit, const TargetDescription &Target, + CompilationUnitAnalysisManager &UnitAnalyses, + MachineFunctionAnalysisManager &FunctionAnalyses, + MachinePassInstrumentation *Instrumentation = nullptr); +}; + +using CompilationUnitPassManager = + PassManager; + +} // namespace rcc + +#endif // RCC_CODEGEN_MACHINEPASSMANAGER_H diff --git a/backend/include/rcc/CodeGen/MachinePseudoExpansion.h b/backend/include/rcc/CodeGen/MachinePseudoExpansion.h index 8c47441..7d4b309 100644 --- a/backend/include/rcc/CodeGen/MachinePseudoExpansion.h +++ b/backend/include/rcc/CodeGen/MachinePseudoExpansion.h @@ -3,7 +3,7 @@ #ifndef RCC_CODEGEN_MACHINEPSEUDOEXPANSION_H #define RCC_CODEGEN_MACHINEPSEUDOEXPANSION_H -#include "rcc/CodeGen/MachinePass.h" +#include "rcc/CodeGen/MachinePassManager.h" #include "rcc/CodeGen/TargetPseudoExpansion.h" namespace rcc { @@ -18,7 +18,7 @@ public: [[nodiscard]] const MachinePassContract &contract() const noexcept override; [[nodiscard]] Expected run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses) override; + MachineFunctionAnalysisManager &Analyses) override; private: const TargetPseudoExpansionInfo *Info; @@ -32,7 +32,7 @@ public: [[nodiscard]] const MachinePassContract &contract() const noexcept override; [[nodiscard]] Expected run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses) override; + MachineFunctionAnalysisManager &Analyses) override; private: const TargetPseudoExpansionInfo *Info; @@ -45,7 +45,7 @@ public: [[nodiscard]] const MachinePassContract &contract() const noexcept override; [[nodiscard]] Expected run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses) override; + MachineFunctionAnalysisManager &Analyses) override; private: const TargetPseudoExpansionInfo *Info; @@ -60,7 +60,7 @@ public: [[nodiscard]] const MachinePassContract &contract() const noexcept override; [[nodiscard]] Expected run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses) override; + MachineFunctionAnalysisManager &Analyses) override; private: const TargetPseudoExpansionInfo *Info; diff --git a/backend/include/rcc/CodeGen/MachineScheduler.h b/backend/include/rcc/CodeGen/MachineScheduler.h index 2b48fe7..bfe9265 100644 --- a/backend/include/rcc/CodeGen/MachineScheduler.h +++ b/backend/include/rcc/CodeGen/MachineScheduler.h @@ -3,7 +3,7 @@ #ifndef RCC_CODEGEN_MACHINESCHEDULER_H #define RCC_CODEGEN_MACHINESCHEDULER_H -#include "rcc/CodeGen/MachinePass.h" +#include "rcc/CodeGen/MachinePassManager.h" #include @@ -25,7 +25,7 @@ public: [[nodiscard]] const MachinePassContract &contract() const noexcept override; [[nodiscard]] Expected run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses) override; + MachineFunctionAnalysisManager &Analyses) override; private: const TargetSchedulingModel *Model; diff --git a/backend/include/rcc/CodeGen/MachineShrinkWrapping.h b/backend/include/rcc/CodeGen/MachineShrinkWrapping.h index ec295cd..14edeb7 100644 --- a/backend/include/rcc/CodeGen/MachineShrinkWrapping.h +++ b/backend/include/rcc/CodeGen/MachineShrinkWrapping.h @@ -3,7 +3,7 @@ #ifndef RCC_CODEGEN_MACHINESHRINKWRAPPING_H #define RCC_CODEGEN_MACHINESHRINKWRAPPING_H -#include "rcc/CodeGen/MachinePass.h" +#include "rcc/CodeGen/MachinePassManager.h" #include @@ -24,7 +24,7 @@ public: [[nodiscard]] const MachinePassContract &contract() const noexcept override; [[nodiscard]] Expected run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses) override; + MachineFunctionAnalysisManager &Analyses) override; private: const TargetFrameLowering *Info; diff --git a/backend/include/rcc/CodeGen/MachineSink.h b/backend/include/rcc/CodeGen/MachineSink.h index 92aceba..5b47f9b 100644 --- a/backend/include/rcc/CodeGen/MachineSink.h +++ b/backend/include/rcc/CodeGen/MachineSink.h @@ -22,12 +22,12 @@ public: [[nodiscard]] const MachinePassContract &contract() const noexcept override; [[nodiscard]] Expected run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses) override; + MachineFunctionAnalysisManager &Analyses) override; private: - [[nodiscard]] Expected runImplementation(MachineFunction &Function, - const TargetDescription &Target, - MachineAnalysisManager &Analyses); + [[nodiscard]] Expected + runImplementation(MachineFunction &Function, const TargetDescription &Target, + MachineFunctionAnalysisManager &Analyses); MachineCodeMotionStage Stage = MachineCodeMotionStage::SelectedSSA; MachineSinkOptions Options; diff --git a/backend/include/rcc/CodeGen/MachineStackSlotColoring.h b/backend/include/rcc/CodeGen/MachineStackSlotColoring.h index 19c1c70..9aae710 100644 --- a/backend/include/rcc/CodeGen/MachineStackSlotColoring.h +++ b/backend/include/rcc/CodeGen/MachineStackSlotColoring.h @@ -3,7 +3,7 @@ #ifndef RCC_CODEGEN_MACHINESTACKSLOTCOLORING_H #define RCC_CODEGEN_MACHINESTACKSLOTCOLORING_H -#include "rcc/CodeGen/MachinePass.h" +#include "rcc/CodeGen/MachinePassManager.h" #include @@ -21,7 +21,7 @@ public: [[nodiscard]] const MachinePassContract &contract() const noexcept override; [[nodiscard]] Expected run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses) override; + MachineFunctionAnalysisManager &Analyses) override; private: [[nodiscard]] Expected runImplementation(MachineFunction &Function) const; diff --git a/backend/include/rcc/CodeGen/MachineTailDuplication.h b/backend/include/rcc/CodeGen/MachineTailDuplication.h index 1c21bdf..f52f638 100644 --- a/backend/include/rcc/CodeGen/MachineTailDuplication.h +++ b/backend/include/rcc/CodeGen/MachineTailDuplication.h @@ -3,7 +3,7 @@ #ifndef RCC_CODEGEN_MACHINETAILDUPLICATION_H #define RCC_CODEGEN_MACHINETAILDUPLICATION_H -#include "rcc/CodeGen/MachinePass.h" +#include "rcc/CodeGen/MachinePassManager.h" #include @@ -25,7 +25,7 @@ public: [[nodiscard]] const MachinePassContract &contract() const noexcept override; [[nodiscard]] Expected run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses) override; + MachineFunctionAnalysisManager &Analyses) override; private: [[nodiscard]] Expected diff --git a/backend/include/rcc/CodeGen/MachineTailMerge.h b/backend/include/rcc/CodeGen/MachineTailMerge.h index 7237d58..0b9938e 100644 --- a/backend/include/rcc/CodeGen/MachineTailMerge.h +++ b/backend/include/rcc/CodeGen/MachineTailMerge.h @@ -3,7 +3,7 @@ #ifndef RCC_CODEGEN_MACHINETAILMERGE_H #define RCC_CODEGEN_MACHINETAILMERGE_H -#include "rcc/CodeGen/MachinePass.h" +#include "rcc/CodeGen/MachinePassManager.h" #include @@ -24,7 +24,7 @@ public: [[nodiscard]] const MachinePassContract &contract() const noexcept override; [[nodiscard]] Expected run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses) override; + MachineFunctionAnalysisManager &Analyses) override; private: [[nodiscard]] Expected diff --git a/backend/include/rcc/CodeGen/PHIElimination.h b/backend/include/rcc/CodeGen/PHIElimination.h index 3d69152..1443303 100644 --- a/backend/include/rcc/CodeGen/PHIElimination.h +++ b/backend/include/rcc/CodeGen/PHIElimination.h @@ -3,7 +3,7 @@ #ifndef RCC_CODEGEN_PHIELIMINATION_H #define RCC_CODEGEN_PHIELIMINATION_H -#include "rcc/CodeGen/MachinePass.h" +#include "rcc/CodeGen/MachinePassManager.h" namespace rcc { @@ -16,7 +16,7 @@ public: [[nodiscard]] const MachinePassContract &contract() const noexcept override; [[nodiscard]] Expected run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses) override; + MachineFunctionAnalysisManager &Analyses) override; private: [[nodiscard]] Expected runImplementation(MachineFunction &Function, diff --git a/backend/include/rcc/CodeGen/PostRAScheduler.h b/backend/include/rcc/CodeGen/PostRAScheduler.h index 13b08df..3254d1e 100644 --- a/backend/include/rcc/CodeGen/PostRAScheduler.h +++ b/backend/include/rcc/CodeGen/PostRAScheduler.h @@ -3,7 +3,7 @@ #ifndef RCC_CODEGEN_POSTRASCHEDULER_H #define RCC_CODEGEN_POSTRASCHEDULER_H -#include "rcc/CodeGen/MachinePass.h" +#include "rcc/CodeGen/MachinePassManager.h" #include "rcc/CodeGen/MachineScheduler.h" namespace rcc { @@ -19,7 +19,7 @@ public: [[nodiscard]] const MachinePassContract &contract() const noexcept override; [[nodiscard]] Expected run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses) override; + MachineFunctionAnalysisManager &Analyses) override; private: const TargetSchedulingModel *Model; diff --git a/backend/include/rcc/CodeGen/PrologueEpilogueInsertion.h b/backend/include/rcc/CodeGen/PrologueEpilogueInsertion.h index b94715a..a5d0028 100644 --- a/backend/include/rcc/CodeGen/PrologueEpilogueInsertion.h +++ b/backend/include/rcc/CodeGen/PrologueEpilogueInsertion.h @@ -3,7 +3,7 @@ #ifndef RCC_CODEGEN_PROLOGUEEPILOGUEINSERTION_H #define RCC_CODEGEN_PROLOGUEEPILOGUEINSERTION_H -#include "rcc/CodeGen/MachinePass.h" +#include "rcc/CodeGen/MachinePassManager.h" namespace rcc { @@ -16,7 +16,7 @@ public: [[nodiscard]] const MachinePassContract &contract() const noexcept override; [[nodiscard]] Expected run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses) override; + MachineFunctionAnalysisManager &Analyses) override; private: [[nodiscard]] Expected diff --git a/backend/include/rcc/CodeGen/RegAllocCommon.h b/backend/include/rcc/CodeGen/RegAllocCommon.h index 0df9799..ac3aa56 100644 --- a/backend/include/rcc/CodeGen/RegAllocCommon.h +++ b/backend/include/rcc/CodeGen/RegAllocCommon.h @@ -3,7 +3,7 @@ #ifndef RCC_CODEGEN_REGALLOCCOMMON_H #define RCC_CODEGEN_REGALLOCCOMMON_H -#include "rcc/CodeGen/MachinePass.h" +#include "rcc/CodeGen/MachinePassManager.h" #include diff --git a/backend/include/rcc/CodeGen/RegAllocFast.h b/backend/include/rcc/CodeGen/RegAllocFast.h index 84cf30c..6ee2881 100644 --- a/backend/include/rcc/CodeGen/RegAllocFast.h +++ b/backend/include/rcc/CodeGen/RegAllocFast.h @@ -3,7 +3,7 @@ #ifndef RCC_CODEGEN_REGALLOCFAST_H #define RCC_CODEGEN_REGALLOCFAST_H -#include "rcc/CodeGen/MachinePass.h" +#include "rcc/CodeGen/MachinePassManager.h" #include "rcc/CodeGen/TargetRegisterAllocationInfo.h" namespace rcc { @@ -15,7 +15,7 @@ public: [[nodiscard]] const MachinePassContract &contract() const noexcept override; [[nodiscard]] Expected run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses) override; + MachineFunctionAnalysisManager &Analyses) override; private: const TargetRegisterAllocationInfo *Info; diff --git a/backend/include/rcc/CodeGen/RegAllocPBQP.h b/backend/include/rcc/CodeGen/RegAllocPBQP.h index 368cbee..0ae0088 100644 --- a/backend/include/rcc/CodeGen/RegAllocPBQP.h +++ b/backend/include/rcc/CodeGen/RegAllocPBQP.h @@ -17,7 +17,7 @@ public: [[nodiscard]] const MachinePassContract &contract() const noexcept override; [[nodiscard]] Expected run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses) override; + MachineFunctionAnalysisManager &Analyses) override; private: const TargetRegisterAllocationInfo *Info; diff --git a/backend/include/rcc/CodeGen/SlotIndexes.h b/backend/include/rcc/CodeGen/SlotIndexes.h index 1767596..423cc64 100644 --- a/backend/include/rcc/CodeGen/SlotIndexes.h +++ b/backend/include/rcc/CodeGen/SlotIndexes.h @@ -4,7 +4,7 @@ #define RCC_CODEGEN_SLOTINDEXES_H #include "rcc/CodeGen/MachineIRTypes.h" -#include "rcc/CodeGen/MachinePass.h" +#include "rcc/CodeGen/MachinePassManager.h" #include "rcc/CodeGen/StableID.h" #include "rcc/Support/Error.h" @@ -115,8 +115,9 @@ public: return "SlotIndexes"; } - [[nodiscard]] static Expected - run(MachineFunction &Function, const TargetDescription &Target, MachineAnalysisManager &Analyses); + [[nodiscard]] static Expected run(MachineFunction &Function, + const TargetDescription &Target, + MachineFunctionAnalysisManager &Analyses); }; } // namespace rcc diff --git a/backend/include/rcc/CodeGen/TwoAddressInstructionPass.h b/backend/include/rcc/CodeGen/TwoAddressInstructionPass.h index 696b46c..3c9e9dc 100644 --- a/backend/include/rcc/CodeGen/TwoAddressInstructionPass.h +++ b/backend/include/rcc/CodeGen/TwoAddressInstructionPass.h @@ -3,7 +3,7 @@ #ifndef RCC_CODEGEN_TWOADDRESSINSTRUCTIONPASS_H #define RCC_CODEGEN_TWOADDRESSINSTRUCTIONPASS_H -#include "rcc/CodeGen/MachinePass.h" +#include "rcc/CodeGen/MachinePassManager.h" namespace rcc { @@ -16,7 +16,7 @@ public: [[nodiscard]] const MachinePassContract &contract() const noexcept override; [[nodiscard]] Expected run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses) override; + MachineFunctionAnalysisManager &Analyses) override; private: [[nodiscard]] Expected runImplementation(MachineFunction &Function, diff --git a/backend/include/rcc/CodeGen/VirtRegMap.h b/backend/include/rcc/CodeGen/VirtRegMap.h index f37af84..30ef450 100644 --- a/backend/include/rcc/CodeGen/VirtRegMap.h +++ b/backend/include/rcc/CodeGen/VirtRegMap.h @@ -4,7 +4,7 @@ #define RCC_CODEGEN_VIRTREGMAP_H #include "rcc/CodeGen/MachineFrameInfo.h" -#include "rcc/CodeGen/MachinePass.h" +#include "rcc/CodeGen/MachinePassManager.h" #include "rcc/CodeGen/TargetRegisterInfo.h" #include @@ -82,7 +82,7 @@ public: [[nodiscard]] const MachinePassContract &contract() const noexcept override; [[nodiscard]] Expected run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses) override; + MachineFunctionAnalysisManager &Analyses) override; private: const VirtRegMap *Mapping; diff --git a/backend/include/rcc/IR/PassInstrumentation.h b/backend/include/rcc/IR/PassInstrumentation.h new file mode 100644 index 0000000..082ec81 --- /dev/null +++ b/backend/include/rcc/IR/PassInstrumentation.h @@ -0,0 +1,227 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef RCC_IR_PASSINSTRUMENTATION_H +#define RCC_IR_PASSINSTRUMENTATION_H + +#include "rcc/CodeGen/MachineFunctionAnalysisManager.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace rcc { + +class CompilationUnit; +class MachineFunction; +class TargetDescription; +struct MachinePassResult; +struct CompilationUnitPassResult; + +enum class InstrumentationPhase : std::uint8_t { + Before, + After, +}; + +struct InstrumentationStatistic final { + std::string Name; + bool IsAnalysis = false; + std::uint64_t Invocations = 0; + std::uint64_t CacheHits = 0; + std::uint64_t Changes = 0; + std::uint64_t Failures = 0; + std::uint64_t TotalNanoseconds = 0; +}; + +struct MachineActionID final { + std::string Pass; + std::string Rule; + MachineFunctionStableID Function; + MachineInstrStableID Instruction; + + [[nodiscard]] std::string toString() const; + + friend bool operator==(const MachineActionID &, const MachineActionID &) = default; +}; + +struct MachineActionEvent final { + MachineActionID ID; + std::uint64_t Cost = 0; + bool Accepted = false; + + friend bool operator==(const MachineActionEvent &, const MachineActionEvent &) = default; +}; + +class MachinePassInstrumentation final { +public: + using BeforeCallback = std::function; + using AfterCallback = + std::function; + using FailureCallback = + std::function; + using BeforeAnalysisCallback = std::function; + using AfterAnalysisCallback = + std::function; + using AnalysisFailureCallback = + std::function; + using IRPrintCallback = + std::function; + using ChangeCallback = + std::function; + using ActionFilter = std::function; + + using BeforeUnitCallback = std::function; + using AfterUnitCallback = std::function; + using UnitFailureCallback = + std::function; + using BeforeUnitAnalysisCallback = std::function; + using AfterUnitAnalysisCallback = + std::function; + using UnitAnalysisFailureCallback = + std::function; + + void addBeforeCallback(BeforeCallback Callback); + void addAfterCallback(AfterCallback Callback); + void addFailureCallback(FailureCallback Callback); + void addBeforeAnalysisCallback(BeforeAnalysisCallback Callback); + void addAfterAnalysisCallback(AfterAnalysisCallback Callback); + void addAnalysisFailureCallback(AnalysisFailureCallback Callback); + void addIRPrintCallback(IRPrintCallback Callback); + void addChangeCallback(ChangeCallback Callback); + void setActionFilter(ActionFilter Filter); + void setPerFunctionFuel(std::optional Fuel); + + void addBeforeUnitCallback(BeforeUnitCallback Callback); + void addAfterUnitCallback(AfterUnitCallback Callback); + void addUnitFailureCallback(UnitFailureCallback Callback); + void addBeforeUnitAnalysisCallback(BeforeUnitAnalysisCallback Callback); + void addAfterUnitAnalysisCallback(AfterUnitAnalysisCallback Callback); + void addUnitAnalysisFailureCallback(UnitAnalysisFailureCallback Callback); + + [[nodiscard]] std::vector statistics() const; + [[nodiscard]] std::vector actionEvents() const; + + [[nodiscard]] Expected requestAction(std::string_view Pass, std::string_view Rule, + const MachineFunction &Function, + MachineInstrStableID Instruction, std::uint64_t Cost); + [[nodiscard]] Expected requestAction(std::string_view Pass, std::string_view Rule, + const MachineFunction &Function, std::nullptr_t, + std::uint64_t Cost); + +private: + struct BufferedEvents final { + const TargetDescription *Target = nullptr; + std::vector> Events; + }; + + [[nodiscard]] bool bufferFunctionEvent(const MachineFunction &Function, + std::function Replay) const; + void beginBuffering(BufferedEvents &Buffer, const TargetDescription &Target) const noexcept; + void endBuffering() const noexcept; + void replayBufferedEvents(BufferedEvents &Buffer) const; + + void before(std::string_view Name, const MachineFunction &Function) const; + void after(std::string_view Name, const MachineFunction &Function, + const MachinePassResult &Result, std::uint64_t Nanoseconds) const; + void failure(std::string_view Name, const MachineFunction &Function, const Error &ErrorValue, + std::uint64_t Nanoseconds = 0) const; + void beforeAnalysis(std::string_view Name, const MachineFunction &Function) const; + void afterAnalysis(std::string_view Name, const MachineFunction &Function, bool CacheHit, + std::uint64_t Nanoseconds) const; + void analysisFailure(std::string_view Name, const MachineFunction &Function, + const Error &ErrorValue, std::uint64_t Nanoseconds) const; + void change(std::string_view Name, const MachineFunction &Function, MachinePassChanges Changes, + bool FingerprintChanged) const; + + void beforeUnit(std::string_view Name, const CompilationUnit &Unit) const; + void afterUnit(std::string_view Name, const CompilationUnit &Unit, + const CompilationUnitPassResult &Result, std::uint64_t Nanoseconds) const; + void unitFailure(std::string_view Name, const CompilationUnit &Unit, const Error &ErrorValue, + std::uint64_t Nanoseconds = 0) const; + void beforeAnalysis(std::string_view Name, const CompilationUnit &Unit) const; + void afterAnalysis(std::string_view Name, const CompilationUnit &Unit, bool CacheHit, + std::uint64_t Nanoseconds) const; + void analysisFailure(std::string_view Name, const CompilationUnit &Unit, const Error &ErrorValue, + std::uint64_t Nanoseconds) const; + + [[nodiscard]] InstrumentationStatistic &statistic(std::string_view Name, bool IsAnalysis) const; + + mutable std::mutex Mutex; + mutable std::mutex ActionMutex; + std::vector Before; + std::vector After; + std::vector Failure; + std::vector BeforeAnalysis; + std::vector AfterAnalysis; + std::vector AnalysisFailure; + std::vector IRPrint; + std::vector Change; + ActionFilter Filter; + std::optional PerFunctionFuel; + std::unordered_map ConsumedFuel; + std::vector ActionEvents; + + std::vector BeforeUnit; + std::vector AfterUnit; + std::vector UnitFailure; + std::vector BeforeUnitAnalysis; + std::vector AfterUnitAnalysis; + std::vector UnitAnalysisFailure; + mutable std::unordered_map Statistics; + + static thread_local BufferedEvents *ActiveBuffer; + + template friend struct AnalysisManagerInstrumentation; + template friend struct PassManagerCallbacks; +}; + +class MachineActionReplay final { +public: + template + explicit MachineActionReplay(AnalysisManagerT &Analyses) + : Request([&Analyses](std::string_view Rule, const MachineFunction &Function, + MachineInstrStableID Instruction, std::uint64_t Cost) { + return Analyses.requestAction(Rule, Function, Instruction, Cost); + }) {} + + template + MachineActionReplay( + AnalysisManagerT &Analyses, + const std::unordered_map &SourceToClone) + : MachineActionReplay(Analyses) { + for (const auto &[Source, Clone] : SourceToClone) + RecordingInstructionIDs.try_emplace(Clone, Source); + } + + [[nodiscard]] Expected request(std::string_view Rule, const MachineFunction &Function, + MachineInstrStableID Instruction = {}, + std::uint64_t Cost = 1); + void beginReplay() noexcept; + [[nodiscard]] Expected finishReplay() const; + +private: + struct Decision final { + std::string Rule; + MachineFunctionStableID Function; + MachineInstrStableID Instruction; + std::uint64_t Cost = 0; + bool Accepted = false; + }; + + std::function(std::string_view, const MachineFunction &, MachineInstrStableID, + std::uint64_t)> + Request; + std::unordered_map RecordingInstructionIDs; + std::vector Decisions; + std::size_t NextDecision = 0; + bool IsReplaying = false; +}; + +} // namespace rcc + +#endif // RCC_IR_PASSINSTRUMENTATION_H diff --git a/backend/include/rcc/IR/PassManager.h b/backend/include/rcc/IR/PassManager.h new file mode 100644 index 0000000..b3ab088 --- /dev/null +++ b/backend/include/rcc/IR/PassManager.h @@ -0,0 +1,531 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef RCC_IR_PASSMANAGER_H +#define RCC_IR_PASSMANAGER_H + +#include "rcc/Support/Error.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace rcc { + +class TargetDescription; + +using AnalysisID = const void *; + +class PreservedAnalyses final { +public: + [[nodiscard]] static PreservedAnalyses all() noexcept { + PreservedAnalyses Result; + Result.PreserveAll = true; + return Result; + } + + [[nodiscard]] static PreservedAnalyses none() noexcept { + return {}; + } + + void preserve(AnalysisID ID) { + if (ID != nullptr) + Preserved.insert(ID); + } + + template void preserve() { + preserve(analysisID()); + } + + [[nodiscard]] bool preserves(AnalysisID ID) const noexcept { + return PreserveAll || (ID != nullptr && Preserved.contains(ID)); + } + + [[nodiscard]] bool preservesAll() const noexcept { + return PreserveAll; + } + + template [[nodiscard]] static AnalysisID analysisID() noexcept { + static const std::uint8_t Token = 0; + return &Token; + } + +private: + bool PreserveAll = false; + std::unordered_set Preserved; +}; + +enum class PassThreadSafety : std::uint8_t { + NotThreadSafe, + ThreadSafe, +}; + +struct PassParameter final { + std::string Name; + std::string Description; + std::optional DefaultValue; + bool Required = false; +}; + +template struct AnalysisManagerInstrumentation { + static void beforeAnalysis(InstrumentationT *, std::string_view, const IRUnitT &) {} + static void afterAnalysis(InstrumentationT *, std::string_view, const IRUnitT &, bool, + std::uint64_t) {} + static void analysisFailure(InstrumentationT *, std::string_view, const IRUnitT &, const Error &, + std::uint64_t) {} + + template + [[nodiscard]] static Expected requestAction(InstrumentationT *, std::string_view, + std::string_view, const IRUnitT &, InstructionT, + std::uint64_t) { + return true; + } +}; + +template struct AnalysisRegistration final { + AnalysisID ID = nullptr; + std::string Name; + std::vector Dependencies; + ChangeT InvalidatedBy = ChangeT::all(); + PassThreadSafety ThreadSafety = PassThreadSafety::NotThreadSafe; +}; + +template struct PassManagerCallbacks; + +template class PassManager { +public: + using PassList = std::vector>; + using Callbacks = PassManagerCallbacks; + + explicit PassManager(OptionsT Options = {}) : Options(Options) {} + PassManager(const PassManager &) = delete; + PassManager &operator=(const PassManager &) = delete; + PassManager(PassManager &&) = default; + PassManager &operator=(PassManager &&) = default; + ~PassManager() = default; + + [[nodiscard]] Expected addPass(std::unique_ptr Pass) { + if (!Pass) + return makeUnexpected(ErrorCode::InvalidArgument, "pass manager cannot add a null pass"); + auto Validation = Callbacks::validate(*Pass); + if (!Validation) + return std::unexpected(Validation.error()); + Passes.push_back(std::move(Pass)); + return {}; + } + + template + [[nodiscard]] Expected run(IRUnitT &Unit, Args &&...Arguments) const { + return Callbacks::run(Passes, Options, Unit, std::forward(Arguments)...); + } + + template + [[nodiscard]] Expected runFunctions(Args &&...Arguments) const + requires requires(const PassList &InputPasses, const OptionsT &InputOptions, + Args &&...InputArguments) { + Callbacks::runFunctions(InputPasses, InputOptions, std::forward(InputArguments)...); + } + { + return Callbacks::runFunctions(Passes, Options, std::forward(Arguments)...); + } + + [[nodiscard]] std::size_t size() const noexcept { + return Passes.size(); + } + + [[nodiscard]] PassList takePasses() && noexcept { + return std::move(Passes); + } + +private: + PassList Passes; + OptionsT Options; +}; + +template +class AnalysisManager { +public: + using Self = AnalysisManager; + + AnalysisManager() = default; + AnalysisManager(const AnalysisManager &) = delete; + AnalysisManager &operator=(const AnalysisManager &) = delete; + AnalysisManager(AnalysisManager &&) = delete; + AnalysisManager &operator=(AnalysisManager &&) = delete; + ~AnalysisManager() = default; + + template [[nodiscard]] static AnalysisID id() noexcept { + return PreservedAnalyses::analysisID(); + } + + template + [[nodiscard]] Expected registerAnalysis(RegistrationT Registration = {}) { + using ResultT = typename AnalysisT::Result; + if (Registration.ID == nullptr) + Registration.ID = id(); + if (Registration.Name.empty()) { + if constexpr (requires { + { AnalysisT::name() } -> std::convertible_to; + }) + Registration.Name = std::string(AnalysisT::name()); + else + Registration.Name = "unnamed-analysis"; + } + + ErasedRunner Runner = [](IRUnitT &Unit, const TargetDescription &Target, + Self &Manager) -> Expected> { + auto Computed = AnalysisT::run(Unit, Target, Manager); + if (!Computed) + return std::unexpected(Computed.error()); + return std::shared_ptr(new ResultT(std::move(*Computed)), + [](void *Value) { delete static_cast(Value); }); + }; + ErasedInvalidator Invalidator = [](void *Value, const IRUnitT &Unit, + const PreservedAnalyses &Preserved) -> bool { + if constexpr (requires(ResultT &Result, const IRUnitT &InputUnit, + const PreservedAnalyses &Analyses) { + { Result.invalidate(InputUnit, Analyses) } -> std::convertible_to; + }) + return static_cast(Value)->invalidate(Unit, Preserved); + return true; + }; + return registerAnalysisImpl(std::move(Registration), std::move(Runner), std::move(Invalidator)); + } + + template + [[nodiscard]] Expected getResult(IRUnitT &Unit, + const TargetDescription &Target) { + const AnalysisID Key = id(); + if (!isRegistered(Key)) { + auto Registered = registerAnalysis(); + if (!Registered) + return std::unexpected(Registered.error()); + } + auto Result = getResultImpl(Key, Unit, Target); + if (!Result) + return std::unexpected(Result.error()); + return static_cast(*Result); + } + + [[nodiscard]] Expected getResultByID(AnalysisID ID, IRUnitT &Unit, + const TargetDescription &Target) { + return getResultImpl(ID, Unit, Target); + } + + void invalidate(IRUnitT &Unit, const PreservedAnalyses &Preserved, ChangeT Changes) noexcept { + const auto UnitPosition = Cache.find(&Unit); + if (UnitPosition == Cache.end() || Preserved.preservesAll() || Changes.empty()) + return; + + std::set Invalid; + for (auto &[ID, Entry] : UnitPosition->second) { + if (Preserved.preserves(ID)) + continue; + const auto Registration = Registry.find(ID); + if (Registration == Registry.end() || + Registration->second.Info.InvalidatedBy.intersects(Changes)) { + const bool ShouldInvalidate = + Registration == Registry.end() || !Entry.Value || !Registration->second.Invalidator || + Registration->second.Invalidator(Entry.Value.get(), Unit, Preserved); + if (ShouldInvalidate) + Invalid.insert(ID); + } + } + + bool Added = true; + while (Added) { + Added = false; + for (const auto &[ID, Entry] : UnitPosition->second) { + (void)Entry; + if (Invalid.contains(ID) || Preserved.preserves(ID)) + continue; + const auto Registration = Registry.find(ID); + if (Registration != Registry.end() && + std::ranges::any_of( + Registration->second.Info.Dependencies, + [&Invalid](AnalysisID Dependency) { return Invalid.contains(Dependency); })) + Added = Invalid.insert(ID).second || Added; + } + } + + for (const AnalysisID ID : Invalid) + UnitPosition->second.erase(ID); + if (UnitPosition->second.empty()) + Cache.erase(UnitPosition); + } + + void invalidate(IRUnitT &Unit, const PreservedAnalyses &Preserved) noexcept { + invalidate(Unit, Preserved, ChangeT::all()); + } + + [[nodiscard]] bool hasCached(const IRUnitT &Unit, AnalysisID ID) const noexcept { + const auto UnitPosition = Cache.find(const_cast(&Unit)); + if (UnitPosition == Cache.end()) + return false; + const auto AnalysisPosition = UnitPosition->second.find(ID); + return AnalysisPosition != UnitPosition->second.end() && AnalysisPosition->second.Value; + } + + [[nodiscard]] std::size_t cachedResultCount(const IRUnitT &Unit) const noexcept { + const auto Position = Cache.find(const_cast(&Unit)); + return Position == Cache.end() ? 0 : Position->second.size(); + } + + [[nodiscard]] bool isRegistered(AnalysisID ID) const noexcept { + return ID != nullptr && Registry.contains(ID); + } + + void clear(IRUnitT &Unit) noexcept { + Cache.erase(&Unit); + ActiveComputations.erase(&Unit); + } + + void clearAll() noexcept { + Cache.clear(); + ActiveComputations.clear(); + } + + [[nodiscard]] Expected> forkEmpty() const { + if (!ActiveComputations.empty()) + return makeUnexpected(ErrorCode::InvalidArgument, + "cannot fork an analysis manager during analysis computation"); + auto Result = std::make_unique(); + Result->Registry = Registry; + return Result; + } + + [[nodiscard]] Expected replaceRegistrations(Self &&Source) { + if (!Cache.empty() || !ActiveComputations.empty() || !Source.Cache.empty() || + !Source.ActiveComputations.empty()) + return makeUnexpected(ErrorCode::InvalidArgument, + "analysis registrations can only be replaced on empty managers"); + Registry = std::move(Source.Registry); + return {}; + } + + [[nodiscard]] Expected + validateParallelRequirements(std::span RequiredAnalyses) const { + std::vector Worklist(RequiredAnalyses.begin(), RequiredAnalyses.end()); + std::unordered_set Visited; + for (std::size_t Index = 0; Index < Worklist.size(); ++Index) { + const AnalysisID ID = Worklist[Index]; + if (ID == nullptr || !Visited.insert(ID).second) + continue; + const auto Position = Registry.find(ID); + if (Position == Registry.end()) + return makeUnexpected(ErrorCode::InvalidArgument, + "parallel pass requires an unregistered analysis"); + if (Position->second.Info.ThreadSafety != PassThreadSafety::ThreadSafe) + return makeUnexpected(ErrorCode::InvalidArgument, "parallel pipeline requires analysis '" + + Position->second.Info.Name + + "' to be marked thread-safe"); + Worklist.insert(Worklist.end(), Position->second.Info.Dependencies.begin(), + Position->second.Info.Dependencies.end()); + } + return {}; + } + + void setInstrumentation(InstrumentationT *NewInstrumentation) noexcept { + Instrumentation = NewInstrumentation; + } + + void setActivePass(std::string Name) { + ActivePass = std::move(Name); + } + + template + [[nodiscard]] Expected requestAction(std::string_view Rule, const IRUnitT &Unit, + InstructionT Instruction, std::uint64_t Cost = 1) { + if (Rule.empty() || Cost == 0) + return makeUnexpected(ErrorCode::InvalidArgument, + "pass action requires a name and nonzero cost"); + if (Instrumentation == nullptr) + return true; + return AnalysisManagerInstrumentation::requestAction( + Instrumentation, ActivePass.empty() ? "unscoped" : ActivePass, Rule, Unit, Instruction, + Cost); + } + + [[nodiscard]] Expected requestAction(std::string_view Rule, const IRUnitT &Unit, + std::uint64_t Cost = 1) { + if (Rule.empty() || Cost == 0) + return makeUnexpected(ErrorCode::InvalidArgument, + "pass action requires a name and nonzero cost"); + if (Instrumentation == nullptr) + return true; + return AnalysisManagerInstrumentation::requestAction( + Instrumentation, ActivePass.empty() ? "unscoped" : ActivePass, Rule, Unit, nullptr, Cost); + } + + [[nodiscard]] const std::string &activePass() const noexcept { + return ActivePass; + } + +private: + using ErasedRunner = + std::function>(IRUnitT &, const TargetDescription &, Self &)>; + using ErasedInvalidator = std::function; + + struct RegisteredAnalysis final { + RegistrationT Info; + ErasedRunner Runner; + ErasedInvalidator Invalidator; + }; + + struct CacheEntry final { + std::shared_ptr Value; + AnalysisID ID = nullptr; + }; + + [[nodiscard]] static bool hasDuplicateAnalysisIDs(std::span IDs) { + std::unordered_set Unique; + for (const AnalysisID ID : IDs) { + if (ID == nullptr || !Unique.insert(ID).second) + return true; + } + return false; + } + + [[nodiscard]] Expected registerAnalysisImpl(RegistrationT Registration, ErasedRunner Runner, + ErasedInvalidator Invalidator) { + if (Registration.ID == nullptr || Registration.Name.empty() || !Runner || !Invalidator) + return makeUnexpected(ErrorCode::InvalidArgument, "analysis registration is incomplete"); + if (hasDuplicateAnalysisIDs(Registration.Dependencies)) + return makeUnexpected(ErrorCode::InvalidArgument, + "analysis dependencies must be non-null and unique"); + if (std::ranges::find(Registration.Dependencies, Registration.ID) != + Registration.Dependencies.end()) + return makeUnexpected(ErrorCode::InvalidArgument, + "analysis cannot directly depend on itself"); + if (Registry.contains(Registration.ID)) + return makeUnexpected(ErrorCode::InvalidArgument, "analysis ID is already registered"); + if (std::ranges::any_of(Registry, [&Registration](const auto &Entry) { + return Entry.second.Info.Name == Registration.Name; + })) + return makeUnexpected(ErrorCode::InvalidArgument, "analysis name is already registered"); + Registry.emplace(Registration.ID, RegisteredAnalysis{std::move(Registration), std::move(Runner), + std::move(Invalidator)}); + return {}; + } + + [[nodiscard]] Expected getResultImpl(AnalysisID ID, IRUnitT &Unit, + const TargetDescription &Target) { + if (ID == nullptr) + return makeUnexpected(ErrorCode::InvalidArgument, "analysis ID cannot be null"); + auto &UnitCache = Cache[&Unit]; + if (const auto Cached = UnitCache.find(ID); Cached != UnitCache.end() && Cached->second.Value) { + const auto Registration = Registry.find(ID); + const std::string_view Name = Registration == Registry.end() + ? std::string_view{"unknown-analysis"} + : std::string_view{Registration->second.Info.Name}; + if (Instrumentation != nullptr) + AnalysisManagerInstrumentation::afterAnalysis( + Instrumentation, Name, Unit, true, 0); + return Cached->second.Value.get(); + } + + const auto RegistrationPosition = Registry.find(ID); + if (RegistrationPosition == Registry.end()) + return makeUnexpected(ErrorCode::InvalidArgument, "analysis ID is not registered"); + const RegisteredAnalysis &Registration = RegistrationPosition->second; + auto &Stack = ActiveComputations[&Unit]; + if (std::ranges::find(Stack, ID) != Stack.end()) { + Error Failure(ErrorCode::InvalidArgument, + "analysis dependency cycle reaches '" + Registration.Info.Name + "'"); + if (Instrumentation != nullptr) + AnalysisManagerInstrumentation::analysisFailure( + Instrumentation, Registration.Info.Name, Unit, Failure, 0); + return std::unexpected(std::move(Failure)); + } + + if (Instrumentation != nullptr) + AnalysisManagerInstrumentation::beforeAnalysis( + Instrumentation, Registration.Info.Name, Unit); + const auto Start = std::chrono::steady_clock::now(); + Stack.push_back(ID); + for (const AnalysisID Dependency : Registration.Info.Dependencies) { + if (!Registry.contains(Dependency)) { + Stack.pop_back(); + if (Stack.empty()) + ActiveComputations.erase(&Unit); + return makeUnexpected(ErrorCode::InvalidArgument, + "analysis depends on an unregistered analysis"); + } + auto DependencyResult = getResultImpl(Dependency, Unit, Target); + if (!DependencyResult) { + Stack.pop_back(); + if (Stack.empty()) + ActiveComputations.erase(&Unit); + Error Failure = DependencyResult.error(); + std::string Message = "analysis '" + Registration.Info.Name + "' failed: "; + Message.append(Failure.message()); + Failure = Error(Failure.code(), std::move(Message)); + if (Instrumentation != nullptr) + AnalysisManagerInstrumentation::analysisFailure( + Instrumentation, Registration.Info.Name, Unit, Failure, elapsedNanoseconds(Start)); + return std::unexpected(std::move(Failure)); + } + } + + auto Computed = Registration.Runner(Unit, Target, *this); + Stack.pop_back(); + if (Stack.empty()) + ActiveComputations.erase(&Unit); + const std::uint64_t Duration = elapsedNanoseconds(Start); + if (!Computed) { + Error Failure = Computed.error(); + std::string Message = "analysis '" + Registration.Info.Name + "' failed: "; + Message.append(Failure.message()); + Failure = Error(Failure.code(), std::move(Message)); + if (Instrumentation != nullptr) + AnalysisManagerInstrumentation::analysisFailure( + Instrumentation, Registration.Info.Name, Unit, Failure, Duration); + return std::unexpected(std::move(Failure)); + } + if (!*Computed) { + Error Failure(ErrorCode::InternalError, + "analysis '" + Registration.Info.Name + "' returned a null result"); + if (Instrumentation != nullptr) + AnalysisManagerInstrumentation::analysisFailure( + Instrumentation, Registration.Info.Name, Unit, Failure, Duration); + return std::unexpected(std::move(Failure)); + } + + void *Result = Computed->get(); + UnitCache.emplace(ID, CacheEntry{std::move(*Computed), ID}); + if (Instrumentation != nullptr) + AnalysisManagerInstrumentation::afterAnalysis( + Instrumentation, Registration.Info.Name, Unit, false, Duration); + return Result; + } + + [[nodiscard]] static std::uint64_t + elapsedNanoseconds(std::chrono::steady_clock::time_point Start) noexcept { + const auto Elapsed = std::chrono::duration_cast( + std::chrono::steady_clock::now() - Start); + return Elapsed.count() <= 0 ? 0 : static_cast(Elapsed.count()); + } + + std::unordered_map Registry; + std::unordered_map> Cache; + std::unordered_map> ActiveComputations; + InstrumentationT *Instrumentation = nullptr; + std::string ActivePass; +}; + +} // namespace rcc + +#endif // RCC_IR_PASSMANAGER_H diff --git a/backend/include/rcc/Target/RISCV/RISCVPipeline.h b/backend/include/rcc/Target/RISCV/RISCVPipeline.h index ba0428b..8b27032 100644 --- a/backend/include/rcc/Target/RISCV/RISCVPipeline.h +++ b/backend/include/rcc/Target/RISCV/RISCVPipeline.h @@ -3,7 +3,7 @@ #ifndef RCC_TARGET_RISCV_RISCVPIPELINE_H #define RCC_TARGET_RISCV_RISCVPIPELINE_H -#include "rcc/CodeGen/MachinePass.h" +#include "rcc/CodeGen/MachinePassManager.h" #include "rcc/Support/Error.h" #include "rcc/Target/RISCV/RISCVSubtarget.h" @@ -19,7 +19,7 @@ class TargetDescription; namespace riscv { -[[nodiscard]] Expected addCanonicalPipeline(MachinePassManager &Pipeline, +[[nodiscard]] Expected addCanonicalPipeline(MachineFunctionPassManager &Pipeline, const MachineFunction &Function, const RISCVSubtarget &Subtarget); [[nodiscard]] Expected> diff --git a/backend/include/rcc/Tooling/BackendDriver.h b/backend/include/rcc/Tooling/BackendDriver.h index 7b62b6d..6b04de9 100644 --- a/backend/include/rcc/Tooling/BackendDriver.h +++ b/backend/include/rcc/Tooling/BackendDriver.h @@ -3,7 +3,7 @@ #ifndef RCC_TOOLING_BACKENDDRIVER_H #define RCC_TOOLING_BACKENDDRIVER_H -#include "rcc/CodeGen/MachinePass.h" +#include "rcc/CodeGen/MachinePassManager.h" #include "rcc/Support/Error.h" #include "rcc/Tooling/ArtifactStore.h" #include "rcc/Tooling/PipelineDriver.h" diff --git a/backend/include/rcc/Tooling/PipelineDriver.h b/backend/include/rcc/Tooling/PipelineDriver.h index 5d2dc45..849b2f7 100644 --- a/backend/include/rcc/Tooling/PipelineDriver.h +++ b/backend/include/rcc/Tooling/PipelineDriver.h @@ -3,7 +3,7 @@ #ifndef RCC_TOOLING_PIPELINEDRIVER_H #define RCC_TOOLING_PIPELINEDRIVER_H -#include "rcc/CodeGen/MachinePass.h" +#include "rcc/CodeGen/MachinePassManager.h" #include "rcc/MIR/MIRDocument.h" #include "rcc/Tooling/BackendInvocation.h" diff --git a/backend/lib/CodeGen/CMakeLists.txt b/backend/lib/CodeGen/CMakeLists.txt index 470571d..4488903 100644 --- a/backend/lib/CodeGen/CMakeLists.txt +++ b/backend/lib/CodeGen/CMakeLists.txt @@ -48,7 +48,7 @@ set( MachineMetadata.cpp MachineOperand.cpp MachineOptimizationPipeline.cpp - MachinePass.cpp + MachinePassManager.cpp MachinePseudoExpansion.cpp MachineRegisterInfo.cpp MachineScheduler.cpp @@ -136,7 +136,10 @@ set( "${RCC_BACKEND_SOURCE_DIR}/include/rcc/CodeGen/MachineMetadata.h" "${RCC_BACKEND_SOURCE_DIR}/include/rcc/CodeGen/MachineOperand.h" "${RCC_BACKEND_SOURCE_DIR}/include/rcc/CodeGen/MachineOptimizationPipeline.h" - "${RCC_BACKEND_SOURCE_DIR}/include/rcc/CodeGen/MachinePass.h" + "${RCC_BACKEND_SOURCE_DIR}/include/rcc/IR/PassManager.h" + "${RCC_BACKEND_SOURCE_DIR}/include/rcc/IR/PassInstrumentation.h" + "${RCC_BACKEND_SOURCE_DIR}/include/rcc/CodeGen/MachineFunctionAnalysisManager.h" + "${RCC_BACKEND_SOURCE_DIR}/include/rcc/CodeGen/MachinePassManager.h" "${RCC_BACKEND_SOURCE_DIR}/include/rcc/CodeGen/MachinePseudoExpansion.h" "${RCC_BACKEND_SOURCE_DIR}/include/rcc/CodeGen/PrologueEpilogueInsertion.h" "${RCC_BACKEND_SOURCE_DIR}/include/rcc/CodeGen/RegisterPressure.h" @@ -262,7 +265,7 @@ rcc_backend_register_format_files( "${CMAKE_CURRENT_SOURCE_DIR}/MachineMetadata.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/MachineOperand.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/MachineOptimizationPipeline.cpp" - "${CMAKE_CURRENT_SOURCE_DIR}/MachinePass.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/MachinePassManager.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/MachinePseudoExpansion.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/MachineRegisterInfo.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/MachineScheduler.cpp" @@ -350,7 +353,7 @@ rcc_backend_register_tidy_files( "${CMAKE_CURRENT_SOURCE_DIR}/MachineMetadata.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/MachineOperand.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/MachineOptimizationPipeline.cpp" - "${CMAKE_CURRENT_SOURCE_DIR}/MachinePass.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/MachinePassManager.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/MachinePseudoExpansion.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/MachineRegisterInfo.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/MachineScheduler.cpp" diff --git a/backend/lib/CodeGen/GlobalISel/InstructionSelect.cpp b/backend/lib/CodeGen/GlobalISel/InstructionSelect.cpp index ff32eda..344e63e 100644 --- a/backend/lib/CodeGen/GlobalISel/InstructionSelect.cpp +++ b/backend/lib/CodeGen/GlobalISel/InstructionSelect.cpp @@ -194,7 +194,7 @@ const MachinePassContract &InstructionSelect::contract() const noexcept { Expected InstructionSelect::run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses) { + MachineFunctionAnalysisManager &Analyses) { if (Info == nullptr) return std::unexpected(passFailure("instruction select has no target behavior interface", ErrorCode::InvalidArgument)); diff --git a/backend/lib/CodeGen/GlobalISel/Legalizer.cpp b/backend/lib/CodeGen/GlobalISel/Legalizer.cpp index 60f388d..7781818 100644 --- a/backend/lib/CodeGen/GlobalISel/Legalizer.cpp +++ b/backend/lib/CodeGen/GlobalISel/Legalizer.cpp @@ -175,7 +175,7 @@ const MachinePassContract &Legalizer::contract() const noexcept { Expected Legalizer::run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses) { + MachineFunctionAnalysisManager &Analyses) { if (Info == nullptr) return std::unexpected( passFailure("legalizer has no target behavior interface", ErrorCode::InvalidArgument)); diff --git a/backend/lib/CodeGen/GlobalISel/RegBankSelect.cpp b/backend/lib/CodeGen/GlobalISel/RegBankSelect.cpp index c36c500..041ab74 100644 --- a/backend/lib/CodeGen/GlobalISel/RegBankSelect.cpp +++ b/backend/lib/CodeGen/GlobalISel/RegBankSelect.cpp @@ -122,7 +122,7 @@ const MachinePassContract &RegBankSelect::contract() const noexcept { Expected RegBankSelect::run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &) { + MachineFunctionAnalysisManager &) { if (Info == nullptr) return std::unexpected(passFailure("register-bank select has no target behavior interface", ErrorCode::InvalidArgument)); diff --git a/backend/lib/CodeGen/InlineSpiller.cpp b/backend/lib/CodeGen/InlineSpiller.cpp index 14de321..1d5ba10 100644 --- a/backend/lib/CodeGen/InlineSpiller.cpp +++ b/backend/lib/CodeGen/InlineSpiller.cpp @@ -7,7 +7,7 @@ #include "rcc/CodeGen/MachineIRBuilder.h" #include "rcc/CodeGen/MachineInstr.h" #include "rcc/CodeGen/MachineOperand.h" -#include "rcc/CodeGen/MachinePass.h" +#include "rcc/CodeGen/MachinePassManager.h" #include "rcc/CodeGen/MachineRegisterInfo.h" #include "rcc/CodeGen/Spiller.h" #include "rcc/CodeGen/TargetDescription.h" diff --git a/backend/lib/CodeGen/LiveIntervals.cpp b/backend/lib/CodeGen/LiveIntervals.cpp index d8cb539..5a01693 100644 --- a/backend/lib/CodeGen/LiveIntervals.cpp +++ b/backend/lib/CodeGen/LiveIntervals.cpp @@ -307,12 +307,12 @@ Expected LiveIntervalsAnalysis::Result::shrinkToUses(Register Reg, bool LiveIntervalsAnalysis::Result::invalidate(const MachineFunction &, const PreservedAnalyses &Preserved) const noexcept { - return !Preserved.preserves(MachineAnalysisManager::id()); + return !Preserved.preserves(MachineFunctionAnalysisManager::id()); } Expected LiveIntervalsAnalysis::run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses) { + MachineFunctionAnalysisManager &Analyses) { auto Indexes = Analyses.getResult(Function, Target); if (!Indexes) return std::unexpected(Indexes.error()); diff --git a/backend/lib/CodeGen/LiveVariables.cpp b/backend/lib/CodeGen/LiveVariables.cpp index 7323e0d..201e09e 100644 --- a/backend/lib/CodeGen/LiveVariables.cpp +++ b/backend/lib/CodeGen/LiveVariables.cpp @@ -884,12 +884,12 @@ bool LiveVariablesAnalysis::Result::isUnitLiveOut(const MachineBasicBlock &Block bool LiveVariablesAnalysis::Result::invalidate(const MachineFunction &, const PreservedAnalyses &Preserved) const noexcept { - return !Preserved.preserves(MachineAnalysisManager::id()); + return !Preserved.preserves(MachineFunctionAnalysisManager::id()); } -Expected LiveVariablesAnalysis::run(MachineFunction &Function, - const TargetDescription &Target, - MachineAnalysisManager &) { +Expected +LiveVariablesAnalysis::run(MachineFunction &Function, const TargetDescription &Target, + MachineFunctionAnalysisManager &) { return computeLiveVariables(Function, Target); } const MachinePassContract &RebuildMachineLivenessPass::contract() const noexcept { @@ -911,7 +911,7 @@ const MachinePassContract &RebuildMachineLivenessPass::contract() const noexcept Expected RebuildMachineLivenessPass::run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &) { + MachineFunctionAnalysisManager &) { const MachineFunctionProperties Missing = contract().Requires.missingFrom(Function.properties()); if (!Missing.empty()) { return makeUnexpected(ErrorCode::VerificationError, @@ -976,11 +976,11 @@ Expected verifyTrackedMachineLiveness(const MachineFunction &Function, return {}; } -Expected registerStage11MachineAnalyses(MachineAnalysisManager &Analyses) { +Expected registerStage11MachineAnalyses(MachineFunctionAnalysisManager &Analyses) { const std::array IDs{ - MachineAnalysisManager::id(), - MachineAnalysisManager::id(), - MachineAnalysisManager::id(), + MachineFunctionAnalysisManager::id(), + MachineFunctionAnalysisManager::id(), + MachineFunctionAnalysisManager::id(), }; const std::size_t Registered = static_cast( std::ranges::count_if(IDs, [&Analyses](AnalysisID ID) { return Analyses.isRegistered(ID); })); @@ -994,7 +994,7 @@ Expected registerStage11MachineAnalyses(MachineAnalysisManager &Analyses) auto Candidate = Analyses.forkEmpty(); if (!Candidate) return std::unexpected(Candidate.error()); - MachineAnalysisManager &Staging = **Candidate; + MachineFunctionAnalysisManager &Staging = **Candidate; auto Slots = Staging.registerAnalysis({ .Name = "SlotIndexes", .Dependencies = {}, @@ -1015,8 +1015,8 @@ Expected registerStage11MachineAnalyses(MachineAnalysisManager &Analyses) return std::unexpected(Variables.error()); auto Intervals = Staging.registerAnalysis({ .Name = "LiveIntervals", - .Dependencies = {MachineAnalysisManager::id(), - MachineAnalysisManager::id()}, + .Dependencies = {MachineFunctionAnalysisManager::id(), + MachineFunctionAnalysisManager::id()}, .InvalidatedBy = {MachinePassChange::Instructions, MachinePassChange::Operands, MachinePassChange::Registers, MachinePassChange::CFG, MachinePassChange::BlockLayout, MachinePassChange::TargetState}, @@ -1024,8 +1024,7 @@ Expected registerStage11MachineAnalyses(MachineAnalysisManager &Analyses) }); if (!Intervals) return std::unexpected(Intervals.error()); - Analyses.Registry = std::move(Staging.Registry); - return {}; + return Analyses.replaceRegistrations(std::move(Staging)); } } // namespace rcc diff --git a/backend/lib/CodeGen/MachineAnalyses.cpp b/backend/lib/CodeGen/MachineAnalyses.cpp index 33dc14f..3f09636 100644 --- a/backend/lib/CodeGen/MachineAnalyses.cpp +++ b/backend/lib/CodeGen/MachineAnalyses.cpp @@ -263,7 +263,7 @@ const MachineBasicBlock *MachineDominatorTreeAnalysis::Result::nearestCommonDomi Expected MachineDominatorTreeAnalysis::run(MachineFunction &Function, const TargetDescription &, - MachineAnalysisManager &) { + MachineFunctionAnalysisManager &) { Result ResultValue; auto Built = ResultValue.build(Function); if (!Built) @@ -287,9 +287,9 @@ bool MachineLoopAnalysis::Result::isIrreducible(const MachineBasicBlock &Block) return IrreducibleBlocks.contains(&Block); } -Expected MachineLoopAnalysis::run(MachineFunction &Function, - const TargetDescription &Target, - MachineAnalysisManager &Analyses) { +Expected +MachineLoopAnalysis::run(MachineFunction &Function, const TargetDescription &Target, + MachineFunctionAnalysisManager &Analyses) { auto Dominators = Analyses.getResult(Function, Target); if (!Dominators) return std::unexpected(Dominators.error()); @@ -496,7 +496,7 @@ std::span MachineBranchProbabilityAnalysis::Result::succ Expected MachineBranchProbabilityAnalysis::run(MachineFunction &Function, const TargetDescription &, - MachineAnalysisManager &) { + MachineFunctionAnalysisManager &) { Result ResultValue; const std::vector Blocks = linkedBlocks(Function); const auto Order = blockOrder(Blocks); @@ -522,7 +522,7 @@ MachineBlockFrequencyAnalysis::Result::frequency(const MachineBasicBlock &Block) Expected MachineBlockFrequencyAnalysis::run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses) { + MachineFunctionAnalysisManager &Analyses) { auto Dominators = Analyses.getResult(Function, Target); auto Loops = Analyses.getResult(Function, Target); auto Probabilities = Analyses.getResult(Function, Target); @@ -628,8 +628,9 @@ MachineAliasAnalysis::Result::alias(const MachineMemOperand &Left, return Distance >= LowerSize ? MachineAliasResult::NoAlias : MachineAliasResult::PartialAlias; } -Expected -MachineAliasAnalysis::run(MachineFunction &, const TargetDescription &, MachineAnalysisManager &) { +Expected MachineAliasAnalysis::run(MachineFunction &, + const TargetDescription &, + MachineFunctionAnalysisManager &) { return Result{}; } @@ -659,7 +660,7 @@ std::span MachineMemoryDependenceAnalysis::Result Expected MachineMemoryDependenceAnalysis::run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses) { + MachineFunctionAnalysisManager &Analyses) { auto Alias = Analyses.getResult(Function, Target); if (!Alias) return std::unexpected(Alias.error()); @@ -766,14 +767,14 @@ MachineMemoryDependenceAnalysis::run(MachineFunction &Function, const TargetDesc return ResultValue; } -Expected registerStage8MachineAnalyses(MachineAnalysisManager &Analyses) { +Expected registerStage8MachineAnalyses(MachineFunctionAnalysisManager &Analyses) { const std::array IDs{ - MachineAnalysisManager::id(), - MachineAnalysisManager::id(), - MachineAnalysisManager::id(), - MachineAnalysisManager::id(), - MachineAnalysisManager::id(), - MachineAnalysisManager::id(), + MachineFunctionAnalysisManager::id(), + MachineFunctionAnalysisManager::id(), + MachineFunctionAnalysisManager::id(), + MachineFunctionAnalysisManager::id(), + MachineFunctionAnalysisManager::id(), + MachineFunctionAnalysisManager::id(), }; const std::size_t Registered = static_cast( std::ranges::count_if(IDs, [&Analyses](AnalysisID ID) { return Analyses.isRegistered(ID); })); @@ -787,7 +788,7 @@ Expected registerStage8MachineAnalyses(MachineAnalysisManager &Analyses) { auto Candidate = Analyses.forkEmpty(); if (!Candidate) return std::unexpected(Candidate.error()); - MachineAnalysisManager &Staging = **Candidate; + MachineFunctionAnalysisManager &Staging = **Candidate; auto Dominators = Staging.registerAnalysis({ .Name = "MachineDominatorTree", @@ -799,7 +800,7 @@ Expected registerStage8MachineAnalyses(MachineAnalysisManager &Analyses) { return std::unexpected(Dominators.error()); auto Loops = Staging.registerAnalysis({ .Name = "MachineLoopInfo", - .Dependencies = {MachineAnalysisManager::id()}, + .Dependencies = {MachineFunctionAnalysisManager::id()}, .InvalidatedBy = {MachinePassChange::CFG, MachinePassChange::BlockLayout}, .ThreadSafety = PassThreadSafety::ThreadSafe, }); @@ -815,9 +816,9 @@ Expected registerStage8MachineAnalyses(MachineAnalysisManager &Analyses) { return std::unexpected(Probabilities.error()); auto Frequencies = Staging.registerAnalysis({ .Name = "MachineBlockFrequency", - .Dependencies = {MachineAnalysisManager::id(), - MachineAnalysisManager::id(), - MachineAnalysisManager::id()}, + .Dependencies = {MachineFunctionAnalysisManager::id(), + MachineFunctionAnalysisManager::id(), + MachineFunctionAnalysisManager::id()}, .InvalidatedBy = {MachinePassChange::CFG, MachinePassChange::BlockLayout}, .ThreadSafety = PassThreadSafety::ThreadSafe, }); @@ -835,7 +836,7 @@ Expected registerStage8MachineAnalyses(MachineAnalysisManager &Analyses) { return std::unexpected(Alias.error()); auto MemoryDependence = Staging.registerAnalysis({ .Name = "MachineMemoryDependence", - .Dependencies = {MachineAnalysisManager::id()}, + .Dependencies = {MachineFunctionAnalysisManager::id()}, .InvalidatedBy = {MachinePassChange::Instructions, MachinePassChange::Operands, MachinePassChange::CFG, MachinePassChange::BlockLayout, MachinePassChange::Frame, MachinePassChange::ConstantPool, @@ -844,8 +845,7 @@ Expected registerStage8MachineAnalyses(MachineAnalysisManager &Analyses) { }); if (!MemoryDependence) return std::unexpected(MemoryDependence.error()); - Analyses.Registry = std::move(Staging.Registry); - return {}; + return Analyses.replaceRegistrations(std::move(Staging)); } } // namespace rcc diff --git a/backend/lib/CodeGen/MachineBlockPlacement.cpp b/backend/lib/CodeGen/MachineBlockPlacement.cpp index daccba0..1e563e1 100644 --- a/backend/lib/CodeGen/MachineBlockPlacement.cpp +++ b/backend/lib/CodeGen/MachineBlockPlacement.cpp @@ -37,10 +37,10 @@ enum class PlacementClass : std::uint8_t { .Clears = {}, .RequiredAnalyses = { - MachineAnalysisManager::id(), - MachineAnalysisManager::id(), - MachineAnalysisManager::id(), - MachineAnalysisManager::id(), + MachineFunctionAnalysisManager::id(), + MachineFunctionAnalysisManager::id(), + MachineFunctionAnalysisManager::id(), + MachineFunctionAnalysisManager::id(), }, .VerificationStage = PipelineStage::Selected, }; @@ -101,9 +101,9 @@ const MachinePassContract &MachineBlockPlacementPass::contract() const noexcept return placementContract(); } -Expected MachineBlockPlacementPass::run(MachineFunction &Function, - const TargetDescription &Target, - MachineAnalysisManager &Analyses) { +Expected +MachineBlockPlacementPass::run(MachineFunction &Function, const TargetDescription &Target, + MachineFunctionAnalysisManager &Analyses) { if (!Function.properties().containsAll(contract().Requires)) { return makeUnexpected(ErrorCode::VerificationError, "machine block placement requires selected PHI-free MachineIR"); @@ -113,7 +113,7 @@ Expected MachineBlockPlacementPass::run(MachineFunction &Func MachineFunctionCloneOptions{.NewStableID = Function.stableID(), .NewName = std::nullopt}); if (!Trial) return std::unexpected(prefixedError(Trial.error(), "block placement setup failed: ")); - MachineAnalysisManager TrialAnalyses; + MachineFunctionAnalysisManager TrialAnalyses; MachineActionReplay Actions(Analyses, Trial->InstructionStableIDs); auto TrialResult = runImplementation(*Trial->ClonedFunction, Target, TrialAnalyses, Actions); if (!TrialResult) @@ -131,8 +131,8 @@ Expected MachineBlockPlacementPass::run(MachineFunction &Func } Expected MachineBlockPlacementPass::runImplementation( - MachineFunction &Function, const TargetDescription &Target, MachineAnalysisManager &Analyses, - MachineActionReplay &Actions) const { + MachineFunction &Function, const TargetDescription &Target, + MachineFunctionAnalysisManager &Analyses, MachineActionReplay &Actions) const { auto Probabilities = Analyses.getResult(Function, Target); if (!Probabilities) return std::unexpected(Probabilities.error()); diff --git a/backend/lib/CodeGen/MachineBranchOptimization.cpp b/backend/lib/CodeGen/MachineBranchOptimization.cpp index 5880dbc..c102931 100644 --- a/backend/lib/CodeGen/MachineBranchOptimization.cpp +++ b/backend/lib/CodeGen/MachineBranchOptimization.cpp @@ -301,7 +301,7 @@ const MachinePassContract &MachineBranchOptimizationPass::contract() const noexc Expected MachineBranchOptimizationPass::run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &) { + MachineFunctionAnalysisManager &) { if (!Function.properties().containsAll(contract().Requires)) { return makeUnexpected(ErrorCode::VerificationError, "branch optimization requires selected PHI-free MachineIR"); diff --git a/backend/lib/CodeGen/MachineBranchRelaxation.cpp b/backend/lib/CodeGen/MachineBranchRelaxation.cpp index 78640f1..c11ed8e 100644 --- a/backend/lib/CodeGen/MachineBranchRelaxation.cpp +++ b/backend/lib/CodeGen/MachineBranchRelaxation.cpp @@ -107,9 +107,9 @@ const MachinePassContract &MachineBranchRelaxationPass::contract() const noexcep return relaxationContract(); } -Expected MachineBranchRelaxationPass::run(MachineFunction &Function, - const TargetDescription &Target, - MachineAnalysisManager &Analyses) { +Expected +MachineBranchRelaxationPass::run(MachineFunction &Function, const TargetDescription &Target, + MachineFunctionAnalysisManager &Analyses) { if (!Function.properties().containsAll(contract().Requires)) { return makeUnexpected(ErrorCode::VerificationError, "branch relaxation requires finalized frame and tracked liveness"); diff --git a/backend/lib/CodeGen/MachineCSE.cpp b/backend/lib/CodeGen/MachineCSE.cpp index 9d80b4e..92fe1bd 100644 --- a/backend/lib/CodeGen/MachineCSE.cpp +++ b/backend/lib/CodeGen/MachineCSE.cpp @@ -33,7 +33,7 @@ namespace { .Requires = {MachineFunctionProperty::IsSSA, MachineFunctionProperty::Selected}, .Sets = {}, .Clears = {}, - .RequiredAnalyses = {MachineAnalysisManager::id()}, + .RequiredAnalyses = {MachineFunctionAnalysisManager::id()}, .VerificationStage = PipelineStage::Selected, }; Value.ThreadSafety = PassThreadSafety::ThreadSafe; @@ -314,7 +314,7 @@ const MachinePassContract &MachineCSEPass::contract() const noexcept { Expected MachineCSEPass::run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses) { + MachineFunctionAnalysisManager &Analyses) { if (!Function.properties().containsAll(contract().Requires)) { return makeUnexpected(ErrorCode::VerificationError, "machine CSE requires selected SSA MachineIR"); @@ -325,7 +325,7 @@ Expected MachineCSEPass::run(MachineFunction &Function, if (!Trial) { return std::unexpected(prefixedError(Trial.error(), "machine CSE transaction setup failed: ")); } - MachineAnalysisManager TrialAnalyses; + MachineFunctionAnalysisManager TrialAnalyses; auto TrialResult = runImplementation(*Trial->ClonedFunction, Target, TrialAnalyses); if (!TrialResult) return std::unexpected(TrialResult.error()); @@ -338,9 +338,9 @@ Expected MachineCSEPass::run(MachineFunction &Function, return Result; } -Expected MachineCSEPass::runImplementation(MachineFunction &Function, - const TargetDescription &Target, - MachineAnalysisManager &Analyses) { +Expected +MachineCSEPass::runImplementation(MachineFunction &Function, const TargetDescription &Target, + MachineFunctionAnalysisManager &Analyses) { auto Dominators = Analyses.getResult(Function, Target); if (!Dominators) return std::unexpected(Dominators.error()); diff --git a/backend/lib/CodeGen/MachineCombiner.cpp b/backend/lib/CodeGen/MachineCombiner.cpp index df9c002..c3e9795 100644 --- a/backend/lib/CodeGen/MachineCombiner.cpp +++ b/backend/lib/CodeGen/MachineCombiner.cpp @@ -295,7 +295,7 @@ const MachinePassContract &MachineCombinerPass::contract() const noexcept { Expected MachineCombinerPass::run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses) { + MachineFunctionAnalysisManager &Analyses) { if (!Function.properties().containsAll(contract().Requires)) { return makeUnexpected(ErrorCode::VerificationError, "machine combiner input does not satisfy its stage contract"); diff --git a/backend/lib/CodeGen/MachineCopyPropagation.cpp b/backend/lib/CodeGen/MachineCopyPropagation.cpp index 581cb4f..9725399 100644 --- a/backend/lib/CodeGen/MachineCopyPropagation.cpp +++ b/backend/lib/CodeGen/MachineCopyPropagation.cpp @@ -290,9 +290,9 @@ const MachinePassContract &MachineCopyPropagationPass::contract() const noexcept return copyPropagationContract(Stage); } -Expected MachineCopyPropagationPass::run(MachineFunction &Function, - const TargetDescription &Target, - MachineAnalysisManager &Analyses) { +Expected +MachineCopyPropagationPass::run(MachineFunction &Function, const TargetDescription &Target, + MachineFunctionAnalysisManager &Analyses) { if (!Function.properties().containsAll(contract().Requires)) { return makeUnexpected(ErrorCode::VerificationError, "machine COPY propagation has unmet stage properties"); diff --git a/backend/lib/CodeGen/MachineDCE.cpp b/backend/lib/CodeGen/MachineDCE.cpp index 4dd0e59..1c53c31 100644 --- a/backend/lib/CodeGen/MachineDCE.cpp +++ b/backend/lib/CodeGen/MachineDCE.cpp @@ -115,7 +115,7 @@ const MachinePassContract &MachineDCEPass::contract() const noexcept { Expected MachineDCEPass::run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &) { + MachineFunctionAnalysisManager &) { if (!Function.properties().containsAll(contract().Requires)) { return makeUnexpected(ErrorCode::VerificationError, "machine DCE requires a selected machine function"); diff --git a/backend/lib/CodeGen/MachineFallthrough.cpp b/backend/lib/CodeGen/MachineFallthrough.cpp index 5c58e67..608b703 100644 --- a/backend/lib/CodeGen/MachineFallthrough.cpp +++ b/backend/lib/CodeGen/MachineFallthrough.cpp @@ -26,7 +26,7 @@ namespace { MachineFunctionProperty::NoVRegs, MachineFunctionProperty::TracksLiveness}, .Sets = {}, .Clears = {}, - .RequiredAnalyses = {MachineAnalysisManager::id()}, + .RequiredAnalyses = {MachineFunctionAnalysisManager::id()}, .VerificationStage = PipelineStage::RegisterAllocated, }; Value.ThreadSafety = PassThreadSafety::ThreadSafe; @@ -120,7 +120,7 @@ const MachinePassContract &MachineFallthroughPass::contract() const noexcept { Expected MachineFallthroughPass::run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses) { + MachineFunctionAnalysisManager &Analyses) { if (!Function.properties().containsAll(contract().Requires)) { return makeUnexpected(ErrorCode::VerificationError, "fallthrough normalization requires allocated tracked-liveness MIR"); @@ -130,7 +130,7 @@ Expected MachineFallthroughPass::run(MachineFunction &Functio MachineFunctionCloneOptions{.NewStableID = Function.stableID(), .NewName = std::nullopt}); if (!Trial) return std::unexpected(prefixedError(Trial.error(), "fallthrough setup failed: ")); - MachineAnalysisManager TrialAnalyses; + MachineFunctionAnalysisManager TrialAnalyses; auto TrialLiveness = TrialAnalyses.getResult(*Trial->ClonedFunction, Target); if (!TrialLiveness) diff --git a/backend/lib/CodeGen/MachineFinalization.cpp b/backend/lib/CodeGen/MachineFinalization.cpp index 8947b86..c33d857 100644 --- a/backend/lib/CodeGen/MachineFinalization.cpp +++ b/backend/lib/CodeGen/MachineFinalization.cpp @@ -91,7 +91,7 @@ const MachinePassContract &FinalizeEmissionPseudosPass::contract() const noexcep Expected FinalizeEmissionPseudosPass::run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &) { + MachineFunctionAnalysisManager &) { if (!Function.properties().containsAll(contract().Requires)) return makeUnexpected(ErrorCode::VerificationError, "emission-pseudo finalization requires finalized allocated MIR"); @@ -124,7 +124,7 @@ const MachinePassContract &FinalEncodabilityVerifierPass::contract() const noexc Expected FinalEncodabilityVerifierPass::run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &) { + MachineFunctionAnalysisManager &) { if (!Function.properties().containsAll(contract().Requires)) return makeUnexpected(ErrorCode::FinalEncodabilityFailed, "final encodability requires NoExecutablePseudos and finalized MIR"); diff --git a/backend/lib/CodeGen/MachineLICM.cpp b/backend/lib/CodeGen/MachineLICM.cpp index 758e13c..31d792b 100644 --- a/backend/lib/CodeGen/MachineLICM.cpp +++ b/backend/lib/CodeGen/MachineLICM.cpp @@ -33,9 +33,9 @@ namespace { .Requires = {MachineFunctionProperty::IsSSA, MachineFunctionProperty::Selected}, .Sets = {}, .Clears = {}, - .RequiredAnalyses = {MachineAnalysisManager::id(), - MachineAnalysisManager::id(), - MachineAnalysisManager::id()}, + .RequiredAnalyses = {MachineFunctionAnalysisManager::id(), + MachineFunctionAnalysisManager::id(), + MachineFunctionAnalysisManager::id()}, .VerificationStage = PipelineStage::Selected, }; Value.ThreadSafety = PassThreadSafety::ThreadSafe; @@ -50,9 +50,9 @@ namespace { MachineFunctionProperty::TracksLiveness}, .Sets = {}, .Clears = {}, - .RequiredAnalyses = {MachineAnalysisManager::id(), - MachineAnalysisManager::id(), - MachineAnalysisManager::id()}, + .RequiredAnalyses = {MachineFunctionAnalysisManager::id(), + MachineFunctionAnalysisManager::id(), + MachineFunctionAnalysisManager::id()}, .VerificationStage = PipelineStage::RegisterAllocated, }; Value.ThreadSafety = PassThreadSafety::ThreadSafe; @@ -332,7 +332,7 @@ const MachinePassContract &MachineLICMPass::contract() const noexcept { Expected MachineLICMPass::run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses) { + MachineFunctionAnalysisManager &Analyses) { if (!Function.properties().containsAll(contract().Requires)) { return makeUnexpected( ErrorCode::VerificationError, @@ -346,7 +346,7 @@ Expected MachineLICMPass::run(MachineFunction &Function, if (!Trial) { return std::unexpected(prefixedError(Trial.error(), "machine LICM transaction setup failed: ")); } - MachineAnalysisManager TrialAnalyses; + MachineFunctionAnalysisManager TrialAnalyses; auto TrialResult = runImplementation(*Trial->ClonedFunction, Target, TrialAnalyses); if (!TrialResult) return std::unexpected(TrialResult.error()); @@ -359,9 +359,9 @@ Expected MachineLICMPass::run(MachineFunction &Function, return Result; } -Expected MachineLICMPass::runImplementation(MachineFunction &Function, - const TargetDescription &Target, - MachineAnalysisManager &Analyses) { +Expected +MachineLICMPass::runImplementation(MachineFunction &Function, const TargetDescription &Target, + MachineFunctionAnalysisManager &Analyses) { auto Loops = Analyses.getResult(Function, Target); if (!Loops) return std::unexpected(Loops.error()); diff --git a/backend/lib/CodeGen/MachineMemoryFolding.cpp b/backend/lib/CodeGen/MachineMemoryFolding.cpp index 0e15146..e3d796a 100644 --- a/backend/lib/CodeGen/MachineMemoryFolding.cpp +++ b/backend/lib/CodeGen/MachineMemoryFolding.cpp @@ -185,7 +185,7 @@ const MachinePassContract &MachineMemoryFoldingPass::contract() const noexcept { Expected MachineMemoryFoldingPass::run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &) { + MachineFunctionAnalysisManager &) { if (!Function.properties().containsAll(contract().Requires)) { return makeUnexpected(ErrorCode::VerificationError, "memory folding requires selected SSA MachineIR"); diff --git a/backend/lib/CodeGen/MachineOptimizationPipeline.cpp b/backend/lib/CodeGen/MachineOptimizationPipeline.cpp index 4f116f0..4a9d7f5 100644 --- a/backend/lib/CodeGen/MachineOptimizationPipeline.cpp +++ b/backend/lib/CodeGen/MachineOptimizationPipeline.cpp @@ -32,13 +32,13 @@ namespace rcc { namespace { template -[[nodiscard]] Expected addPass(MachinePassManager &Pipeline, Arguments &&...Values) { +[[nodiscard]] Expected addPass(MachineFunctionPassManager &Pipeline, Arguments &&...Values) { return Pipeline.addPass(std::make_unique(std::forward(Values)...)); } } // namespace -Expected registerMachineOptimizationAnalyses(MachineAnalysisManager &Analyses) { +Expected registerMachineOptimizationAnalyses(MachineFunctionAnalysisManager &Analyses) { auto Registered = registerStage8MachineAnalyses(Analyses); if (!Registered) return std::unexpected(Registered.error()); @@ -46,7 +46,7 @@ Expected registerMachineOptimizationAnalyses(MachineAnalysisManager &Analy } Expected -addSelectedSSAOptimizationPipeline(MachinePassManager &Pipeline, +addSelectedSSAOptimizationPipeline(MachineFunctionPassManager &Pipeline, const MachineOptimizationPipelineTargetInfo &TargetInfo) { auto Added = addPass(Pipeline, TargetInfo.Combiner, MachineCombinerStage::SelectedSSA); @@ -68,7 +68,7 @@ addSelectedSSAOptimizationPipeline(MachinePassManager &Pipeline, } Expected addPreRegisterAllocationOptimizationPipeline( - MachinePassManager &Pipeline, const MachineOptimizationPipelineTargetInfo &TargetInfo) { + MachineFunctionPassManager &Pipeline, const MachineOptimizationPipelineTargetInfo &TargetInfo) { auto Added = addPass(Pipeline, TargetInfo.InstrInfo); if (!Added) return std::unexpected(Added.error()); @@ -87,7 +87,7 @@ Expected addPreRegisterAllocationOptimizationPipeline( } Expected -addPostRegisterAllocationPipeline(MachinePassManager &Pipeline, +addPostRegisterAllocationPipeline(MachineFunctionPassManager &Pipeline, const MachineOptimizationPipelineTargetInfo &TargetInfo) { auto Added = addPass(Pipeline); if (!Added) diff --git a/backend/lib/CodeGen/MachinePass.cpp b/backend/lib/CodeGen/MachinePass.cpp deleted file mode 100644 index 0ce6f70..0000000 --- a/backend/lib/CodeGen/MachinePass.cpp +++ /dev/null @@ -1,1497 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later - -#include "rcc/CodeGen/MachinePass.h" - -#include "rcc/CodeGen/CompilationUnit.h" -#include "rcc/CodeGen/MachineBasicBlock.h" -#include "rcc/CodeGen/MachineFunction.h" -#include "rcc/CodeGen/MachineFunctionCloner.h" -#include "rcc/CodeGen/MachineInstr.h" -#include "rcc/CodeGen/MachineOperand.h" -#include "rcc/CodeGen/MachineVerifier.h" -#include "rcc/CodeGen/TargetDescription.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace rcc { - -thread_local MachinePassInstrumentation::BufferedEvents *MachinePassInstrumentation::ActiveBuffer = - nullptr; - -namespace { - -using Clock = std::chrono::steady_clock; - -[[nodiscard]] std::uint64_t elapsedNanoseconds(Clock::time_point Start) noexcept { - const auto Elapsed = std::chrono::duration_cast(Clock::now() - Start); - if (Elapsed.count() <= 0) - return 0; - return static_cast(Elapsed.count()); -} - -[[nodiscard]] Error prefixedError(const Error &Source, std::string Prefix) { - Prefix.append(Source.message()); - return Error(Source.code(), std::move(Prefix)); -} - -[[nodiscard]] bool hasDuplicateAnalysisIDs(std::span IDs) { - std::unordered_set Unique; - for (const AnalysisID ID : IDs) { - if (ID == nullptr || !Unique.insert(ID).second) - return true; - } - return false; -} - -[[nodiscard]] Expected validateParameters(std::span Parameters) { - std::unordered_set Names; - for (const PassParameter &Parameter : Parameters) { - if (Parameter.Name.empty()) - return makeUnexpected(ErrorCode::InvalidArgument, "pass parameter name cannot be empty"); - if (!Names.insert(Parameter.Name).second) - return makeUnexpected(ErrorCode::InvalidArgument, "pass parameter names must be unique"); - if (Parameter.Required && Parameter.DefaultValue) { - return makeUnexpected(ErrorCode::InvalidArgument, - "a required pass parameter cannot have a default value"); - } - } - return {}; -} - -void combineFingerprint(std::uint64_t &State, std::uint64_t Value) noexcept { - State ^= Value + 0x9e3779b97f4a7c15ULL + (State << 6U) + (State >> 2U); -} - -[[nodiscard]] std::uint64_t machineFunctionFingerprint(const MachineFunction &Function) noexcept { - std::uint64_t Result = 0xcbf29ce484222325ULL; - combineFingerprint(Result, Function.stableID().value()); - combineFingerprint(Result, Function.properties().rawValue()); - combineFingerprint(Result, Function.blockCount()); - combineFingerprint(Result, Function.allInstructions().size()); - combineFingerprint(Result, Function.allMemOperands().size()); - - for (const MachineBasicBlock *Block = Function.firstBlock(); Block != nullptr; - Block = Block->next()) { - combineFingerprint(Result, Block->stableID().value()); - combineFingerprint(Result, Block->instructionCount()); - combineFingerprint(Result, Block->successors().size()); - for (const MachineSuccessor &Successor : Block->successors()) { - combineFingerprint(Result, - Successor.Block == nullptr ? 0 : Successor.Block->stableID().value()); - combineFingerprint(Result, Successor.Probability.rawValue()); - } - for (const MachineBasicBlockLiveIn &LiveIn : Block->liveIns()) { - combineFingerprint(Result, LiveIn.PhysReg.number()); - combineFingerprint(Result, LiveIn.Lanes.rawValue()); - } - - for (const MachineInstr *Instruction = Block->firstInstruction(); Instruction != nullptr; - Instruction = Instruction->next()) { - combineFingerprint(Result, Instruction->stableID().value()); - combineFingerprint(Result, Instruction->opcode().value()); - combineFingerprint(Result, Instruction->flags().rawValue()); - combineFingerprint(Result, Instruction->operandCount()); - combineFingerprint(Result, Instruction->memOperands().size()); - for (const MachineOperand &Operand : Instruction->operands()) { - combineFingerprint(Result, static_cast(Operand.kind())); - combineFingerprint(Result, Operand.targetFlags()); - combineFingerprint(Result, Operand.registerFlags().rawValue()); - combineFingerprint(Result, Operand.subReg().value()); - if (const Register *Reg = Operand.getIf()) - combineFingerprint(Result, Reg->opaqueValue()); - else if (const std::int64_t *Immediate = Operand.getIf()) - combineFingerprint(Result, static_cast(*Immediate)); - } - } - } - return Result; -} - -[[nodiscard]] Expected verifyCompilationUnit(const CompilationUnit &Unit, - const TargetDescription &Target) { - auto UnitVerification = Unit.verify(); - if (!UnitVerification) - return std::unexpected(UnitVerification.error()); - for (std::size_t Index = 0; Index < Unit.functionCount(); ++Index) { - const MachineFunction *Function = Unit.functionAt(Index); - if (Function == nullptr) - return makeUnexpected(ErrorCode::InternalError, - "compilation unit function order contains a null entry"); - auto FunctionVerification = MachineVerifier::verify(*Function, Target); - if (!FunctionVerification) - return std::unexpected(FunctionVerification.error()); - } - return {}; -} - -} // namespace - -std::string MachineActionID::toString() const { - std::string Result; - Result.reserve(Pass.size() + Rule.size() + 48U); - Result.append(Pass); - Result.push_back(':'); - Result.append(Rule); - Result.append(":f"); - Result.append(std::to_string(Function.value())); - Result.append(":i"); - Result.append(std::to_string(Instruction.value())); - return Result; -} - -Expected MachineActionReplay::request(std::string_view Rule, const MachineFunction &Function, - MachineInstrStableID Instruction, std::uint64_t Cost) { - if (!IsReplaying) { - const auto Position = RecordingInstructionIDs.find(Instruction); - const MachineInstrStableID CanonicalInstruction = - Position == RecordingInstructionIDs.end() ? Instruction : Position->second; - auto Accepted = Analyses->requestAction(Rule, Function, CanonicalInstruction, Cost); - if (!Accepted) - return std::unexpected(Accepted.error()); - Decisions.push_back({ - .Rule = std::string(Rule), - .Function = Function.stableID(), - .Instruction = CanonicalInstruction, - .Cost = Cost, - .Accepted = *Accepted, - }); - return *Accepted; - } - - if (NextDecision >= Decisions.size()) { - return makeUnexpected(ErrorCode::InternalError, - "machine action replay requested an unrecorded decision"); - } - const Decision &Recorded = Decisions[NextDecision++]; - if (Recorded.Rule != Rule || Recorded.Function != Function.stableID() || - Recorded.Instruction != Instruction || Recorded.Cost != Cost) { - std::string Message = "machine action replay diverged from transaction preflight: recorded "; - Message.append(Recorded.Rule); - Message.append(":f"); - Message.append(std::to_string(Recorded.Function.value())); - Message.append(":i"); - Message.append(std::to_string(Recorded.Instruction.value())); - Message.append(" cost="); - Message.append(std::to_string(Recorded.Cost)); - Message.append(", requested "); - Message.append(Rule); - Message.append(":f"); - Message.append(std::to_string(Function.stableID().value())); - Message.append(":i"); - Message.append(std::to_string(Instruction.value())); - Message.append(" cost="); - Message.append(std::to_string(Cost)); - return makeUnexpected(ErrorCode::InternalError, std::move(Message)); - } - return Recorded.Accepted; -} - -void MachineActionReplay::beginReplay() noexcept { - IsReplaying = true; - NextDecision = 0; -} - -Expected MachineActionReplay::finishReplay() const { - if (!IsReplaying || NextDecision != Decisions.size()) { - return makeUnexpected(ErrorCode::InternalError, - "machine action replay did not consume every recorded decision"); - } - return {}; -} - -Expected -MachineAnalysisManager::registerAnalysisImpl(MachineAnalysisRegistration Registration, - ErasedRunner Runner, ErasedInvalidator Invalidator) { - if (Registration.ID == nullptr || Registration.Name.empty() || !Runner || !Invalidator) { - return makeUnexpected(ErrorCode::InvalidArgument, - "machine analysis registration is incomplete"); - } - if (hasDuplicateAnalysisIDs(Registration.Dependencies)) { - return makeUnexpected(ErrorCode::InvalidArgument, - "machine analysis dependencies must be non-null and unique"); - } - if (std::ranges::find(Registration.Dependencies, Registration.ID) != - Registration.Dependencies.end()) { - return makeUnexpected(ErrorCode::InvalidArgument, - "machine analysis cannot directly depend on itself"); - } - if (Registry.contains(Registration.ID)) - return makeUnexpected(ErrorCode::InvalidArgument, "machine analysis ID is already registered"); - if (std::ranges::any_of(Registry, [&Registration](const auto &Entry) { - return Entry.second.Info.Name == Registration.Name; - })) { - return makeUnexpected(ErrorCode::InvalidArgument, - "machine analysis name is already registered"); - } - const AnalysisID RegistrationID = Registration.ID; - Registry.emplace(RegistrationID, RegisteredAnalysis{std::move(Registration), std::move(Runner), - std::move(Invalidator)}); - return {}; -} - -bool MachineAnalysisManager::isRegistered(AnalysisID ID) const noexcept { - return ID != nullptr && Registry.contains(ID); -} - -bool MachineAnalysisManager::hasCached(const MachineFunction &Function, - AnalysisID ID) const noexcept { - const auto FunctionPosition = Cache.find(const_cast(&Function)); - if (FunctionPosition == Cache.end()) - return false; - const auto AnalysisPosition = FunctionPosition->second.find(ID); - return AnalysisPosition != FunctionPosition->second.end() && AnalysisPosition->second.Value; -} - -std::size_t -MachineAnalysisManager::cachedResultCount(const MachineFunction &Function) const noexcept { - const auto Position = Cache.find(const_cast(&Function)); - return Position == Cache.end() ? 0 : Position->second.size(); -} - -Expected -MachineAnalysisManager::materializeDependencies(const RegisteredAnalysis &Registration, - MachineFunction &Function, - const TargetDescription &Target) { - for (const AnalysisID Dependency : Registration.Info.Dependencies) { - if (!Registry.contains(Dependency)) { - return makeUnexpected(ErrorCode::InvalidArgument, - "machine analysis depends on an unregistered analysis"); - } - auto Result = getResultImpl(Dependency, Function, Target); - if (!Result) - return std::unexpected(Result.error()); - } - return {}; -} - -Expected MachineAnalysisManager::getResultImpl(AnalysisID ID, MachineFunction &Function, - const TargetDescription &Target) { - if (ID == nullptr) - return makeUnexpected(ErrorCode::InvalidArgument, "machine analysis ID cannot be null"); - - auto &FunctionCache = Cache[&Function]; - if (const auto Cached = FunctionCache.find(ID); - Cached != FunctionCache.end() && Cached->second.Value) { - const auto Registration = Registry.find(ID); - const std::string_view Name = Registration == Registry.end() - ? std::string_view{"unknown-machine-analysis"} - : std::string_view{Registration->second.Info.Name}; - if (Instrumentation != nullptr) - Instrumentation->afterAnalysis(Name, Function, true, 0); - return Cached->second.Value.get(); - } - - const auto RegistrationPosition = Registry.find(ID); - if (RegistrationPosition == Registry.end()) - return makeUnexpected(ErrorCode::InvalidArgument, "machine analysis ID is not registered"); - const RegisteredAnalysis &Registration = RegistrationPosition->second; - - auto &Stack = ActiveComputations[&Function]; - if (std::ranges::find(Stack, ID) != Stack.end()) { - Error Failure(ErrorCode::InvalidArgument, - "machine analysis dependency cycle reaches '" + Registration.Info.Name + "'"); - if (Instrumentation != nullptr) - Instrumentation->analysisFailure(Registration.Info.Name, Function, Failure, 0); - return std::unexpected(std::move(Failure)); - } - - if (Instrumentation != nullptr) - Instrumentation->beforeAnalysis(Registration.Info.Name, Function); - const Clock::time_point Start = Clock::now(); - Stack.push_back(ID); - auto Dependencies = materializeDependencies(Registration, Function, Target); - if (!Dependencies) { - Stack.pop_back(); - if (Stack.empty()) - ActiveComputations.erase(&Function); - Error Failure = prefixedError(Dependencies.error(), - "machine analysis '" + Registration.Info.Name + "' failed: "); - if (Instrumentation != nullptr) { - Instrumentation->analysisFailure(Registration.Info.Name, Function, Failure, - elapsedNanoseconds(Start)); - } - return std::unexpected(std::move(Failure)); - } - - auto Computed = Registration.Runner(Function, Target, *this); - Stack.pop_back(); - if (Stack.empty()) - ActiveComputations.erase(&Function); - const std::uint64_t Duration = elapsedNanoseconds(Start); - if (!Computed) { - Error Failure = prefixedError(Computed.error(), - "machine analysis '" + Registration.Info.Name + "' failed: "); - if (Instrumentation != nullptr) - Instrumentation->analysisFailure(Registration.Info.Name, Function, Failure, Duration); - return std::unexpected(std::move(Failure)); - } - if (!*Computed) { - Error Failure(ErrorCode::InternalError, - "machine analysis '" + Registration.Info.Name + "' returned a null result"); - if (Instrumentation != nullptr) - Instrumentation->analysisFailure(Registration.Info.Name, Function, Failure, Duration); - return std::unexpected(std::move(Failure)); - } - - void *Result = Computed->get(); - FunctionCache.emplace(ID, CacheEntry{std::move(*Computed), ID}); - if (Instrumentation != nullptr) - Instrumentation->afterAnalysis(Registration.Info.Name, Function, false, Duration); - return Result; -} - -void MachineAnalysisManager::invalidate(MachineFunction &Function, - const PreservedAnalyses &Preserved, - MachinePassChanges Changes) noexcept { - const auto FunctionPosition = Cache.find(&Function); - if (FunctionPosition == Cache.end() || Preserved.preservesAll() || Changes.empty()) - return; - - std::set Invalid; - for (auto &[ID, Entry] : FunctionPosition->second) { - if (Preserved.preserves(ID)) - continue; - const auto Registration = Registry.find(ID); - if (Registration == Registry.end() || - Registration->second.Info.InvalidatedBy.intersects(Changes)) { - const bool ShouldInvalidate = - Registration == Registry.end() || !Entry.Value || !Registration->second.Invalidator || - Registration->second.Invalidator(Entry.Value.get(), Function, Preserved); - if (ShouldInvalidate) - Invalid.insert(ID); - } - } - - bool Added = true; - while (Added) { - Added = false; - for (const auto &[ID, Entry] : FunctionPosition->second) { - (void)Entry; - if (Invalid.contains(ID) || Preserved.preserves(ID)) - continue; - const auto Registration = Registry.find(ID); - if (Registration != Registry.end() && - std::ranges::any_of( - Registration->second.Info.Dependencies, - [&Invalid](AnalysisID Dependency) { return Invalid.contains(Dependency); })) { - Added = Invalid.insert(ID).second || Added; - } - } - } - - for (const AnalysisID ID : Invalid) - FunctionPosition->second.erase(ID); - if (FunctionPosition->second.empty()) - Cache.erase(FunctionPosition); -} - -void MachineAnalysisManager::clear(MachineFunction &Function) noexcept { - Cache.erase(&Function); - ActiveComputations.erase(&Function); -} - -void MachineAnalysisManager::clearAll() noexcept { - Cache.clear(); - ActiveComputations.clear(); -} - -Expected> MachineAnalysisManager::forkEmpty() const { - if (!ActiveComputations.empty()) { - return makeUnexpected(ErrorCode::InvalidArgument, - "cannot fork a machine analysis manager during analysis computation"); - } - auto Result = std::make_unique(); - Result->Registry = Registry; - return Result; -} - -Expected MachineAnalysisManager::validateParallelRequirements( - std::span RequiredAnalyses) const { - std::vector Worklist(RequiredAnalyses.begin(), RequiredAnalyses.end()); - std::unordered_set Visited; - for (std::size_t Index = 0; Index < Worklist.size(); ++Index) { - const AnalysisID ID = Worklist[Index]; - if (ID == nullptr || !Visited.insert(ID).second) - continue; - const auto Position = Registry.find(ID); - if (Position == Registry.end()) { - return makeUnexpected(ErrorCode::InvalidArgument, - "parallel machine pass requires an unregistered analysis"); - } - if (Position->second.Info.ThreadSafety != PassThreadSafety::ThreadSafe) { - return makeUnexpected(ErrorCode::InvalidArgument, - "parallel machine pipeline requires analysis '" + - Position->second.Info.Name + "' to be marked thread-safe"); - } - Worklist.insert(Worklist.end(), Position->second.Info.Dependencies.begin(), - Position->second.Info.Dependencies.end()); - } - return {}; -} - -Expected MachineAnalysisManager::requestAction(std::string_view Action, - const MachineFunction &Function, - std::uint64_t Cost) { - return requestAction(Action, Function, MachineInstrStableID{}, Cost); -} - -Expected MachineAnalysisManager::requestAction(std::string_view Rule, - const MachineFunction &Function, - MachineInstrStableID Instruction, - std::uint64_t Cost) { - if (Rule.empty() || Cost == 0) - return makeUnexpected(ErrorCode::InvalidArgument, - "machine action requires a name and nonzero cost"); - if (Instrumentation == nullptr) - return true; - MachineActionID ID{ - .Pass = ActivePass.empty() ? "unscoped" : ActivePass, - .Rule = std::string(Rule), - .Function = Function.stableID(), - .Instruction = Instruction, - }; - return Instrumentation->requestAction(ID, Function, Cost); -} - -Expected CompilationUnitAnalysisManager::registerAnalysisImpl( - CompilationUnitAnalysisRegistration Registration, ErasedRunner Runner, - ErasedInvalidator Invalidator) { - if (Registration.ID == nullptr || Registration.Name.empty() || !Runner || !Invalidator) { - return makeUnexpected(ErrorCode::InvalidArgument, - "compilation-unit analysis registration is incomplete"); - } - if (hasDuplicateAnalysisIDs(Registration.Dependencies)) { - return makeUnexpected(ErrorCode::InvalidArgument, - "compilation-unit analysis dependencies must be non-null and unique"); - } - if (std::ranges::find(Registration.Dependencies, Registration.ID) != - Registration.Dependencies.end()) { - return makeUnexpected(ErrorCode::InvalidArgument, - "compilation-unit analysis cannot directly depend on itself"); - } - if (Registry.contains(Registration.ID)) { - return makeUnexpected(ErrorCode::InvalidArgument, - "compilation-unit analysis ID is already registered"); - } - if (std::ranges::any_of(Registry, [&Registration](const auto &Entry) { - return Entry.second.Info.Name == Registration.Name; - })) { - return makeUnexpected(ErrorCode::InvalidArgument, - "compilation-unit analysis name is already registered"); - } - const AnalysisID RegistrationID = Registration.ID; - Registry.emplace(RegistrationID, RegisteredAnalysis{std::move(Registration), std::move(Runner), - std::move(Invalidator)}); - return {}; -} - -bool CompilationUnitAnalysisManager::isRegistered(AnalysisID ID) const noexcept { - return ID != nullptr && Registry.contains(ID); -} - -bool CompilationUnitAnalysisManager::hasCached(const CompilationUnit &Unit, - AnalysisID ID) const noexcept { - const auto UnitPosition = Cache.find(const_cast(&Unit)); - if (UnitPosition == Cache.end()) - return false; - const auto AnalysisPosition = UnitPosition->second.find(ID); - return AnalysisPosition != UnitPosition->second.end() && AnalysisPosition->second.Value; -} - -Expected -CompilationUnitAnalysisManager::materializeDependencies(const RegisteredAnalysis &Registration, - CompilationUnit &Unit, - const TargetDescription &Target) { - for (const AnalysisID Dependency : Registration.Info.Dependencies) { - if (!Registry.contains(Dependency)) { - return makeUnexpected(ErrorCode::InvalidArgument, - "compilation-unit analysis depends on an unregistered analysis"); - } - auto Result = getResultImpl(Dependency, Unit, Target); - if (!Result) - return std::unexpected(Result.error()); - } - return {}; -} - -Expected CompilationUnitAnalysisManager::getResultImpl(AnalysisID ID, CompilationUnit &Unit, - const TargetDescription &Target) { - if (ID == nullptr) - return makeUnexpected(ErrorCode::InvalidArgument, - "compilation-unit analysis ID cannot be null"); - auto &UnitCache = Cache[&Unit]; - if (const auto Cached = UnitCache.find(ID); Cached != UnitCache.end() && Cached->second.Value) { - const auto Registration = Registry.find(ID); - const std::string_view Name = Registration == Registry.end() - ? std::string_view{"unknown-compilation-unit-analysis"} - : std::string_view{Registration->second.Info.Name}; - if (Instrumentation != nullptr) - Instrumentation->afterUnitAnalysis(Name, Unit, true, 0); - return Cached->second.Value.get(); - } - - const auto RegistrationPosition = Registry.find(ID); - if (RegistrationPosition == Registry.end()) { - return makeUnexpected(ErrorCode::InvalidArgument, - "compilation-unit analysis ID is not registered"); - } - const RegisteredAnalysis &Registration = RegistrationPosition->second; - auto &Stack = ActiveComputations[&Unit]; - if (std::ranges::find(Stack, ID) != Stack.end()) { - Error Failure(ErrorCode::InvalidArgument, - "compilation-unit analysis dependency cycle reaches '" + Registration.Info.Name + - "'"); - if (Instrumentation != nullptr) - Instrumentation->unitAnalysisFailure(Registration.Info.Name, Unit, Failure, 0); - return std::unexpected(std::move(Failure)); - } - - if (Instrumentation != nullptr) - Instrumentation->beforeUnitAnalysis(Registration.Info.Name, Unit); - const Clock::time_point Start = Clock::now(); - Stack.push_back(ID); - auto Dependencies = materializeDependencies(Registration, Unit, Target); - if (!Dependencies) { - Stack.pop_back(); - if (Stack.empty()) - ActiveComputations.erase(&Unit); - Error Failure = prefixedError(Dependencies.error(), "compilation-unit analysis '" + - Registration.Info.Name + "' failed: "); - if (Instrumentation != nullptr) { - Instrumentation->unitAnalysisFailure(Registration.Info.Name, Unit, Failure, - elapsedNanoseconds(Start)); - } - return std::unexpected(std::move(Failure)); - } - - auto Computed = Registration.Runner(Unit, Target, *this); - Stack.pop_back(); - if (Stack.empty()) - ActiveComputations.erase(&Unit); - const std::uint64_t Duration = elapsedNanoseconds(Start); - if (!Computed) { - Error Failure = prefixedError(Computed.error(), "compilation-unit analysis '" + - Registration.Info.Name + "' failed: "); - if (Instrumentation != nullptr) - Instrumentation->unitAnalysisFailure(Registration.Info.Name, Unit, Failure, Duration); - return std::unexpected(std::move(Failure)); - } - if (!*Computed) { - Error Failure(ErrorCode::InternalError, "compilation-unit analysis '" + Registration.Info.Name + - "' returned a null result"); - if (Instrumentation != nullptr) - Instrumentation->unitAnalysisFailure(Registration.Info.Name, Unit, Failure, Duration); - return std::unexpected(std::move(Failure)); - } - - void *Result = Computed->get(); - UnitCache.emplace(ID, CacheEntry{std::move(*Computed), ID}); - if (Instrumentation != nullptr) - Instrumentation->afterUnitAnalysis(Registration.Info.Name, Unit, false, Duration); - return Result; -} - -void CompilationUnitAnalysisManager::invalidate(CompilationUnit &Unit, - const PreservedAnalyses &Preserved, - MachinePassChanges Changes) noexcept { - const auto UnitPosition = Cache.find(&Unit); - if (UnitPosition == Cache.end() || Preserved.preservesAll() || Changes.empty()) - return; - - std::set Invalid; - for (auto &[ID, Entry] : UnitPosition->second) { - if (Preserved.preserves(ID)) - continue; - const auto Registration = Registry.find(ID); - if (Registration == Registry.end() || - Registration->second.Info.InvalidatedBy.intersects(Changes)) { - const bool ShouldInvalidate = - Registration == Registry.end() || !Entry.Value || !Registration->second.Invalidator || - Registration->second.Invalidator(Entry.Value.get(), Unit, Preserved); - if (ShouldInvalidate) - Invalid.insert(ID); - } - } - - bool Added = true; - while (Added) { - Added = false; - for (const auto &[ID, Entry] : UnitPosition->second) { - (void)Entry; - if (Invalid.contains(ID) || Preserved.preserves(ID)) - continue; - const auto Registration = Registry.find(ID); - if (Registration != Registry.end() && - std::ranges::any_of( - Registration->second.Info.Dependencies, - [&Invalid](AnalysisID Dependency) { return Invalid.contains(Dependency); })) { - Added = Invalid.insert(ID).second || Added; - } - } - } - for (const AnalysisID InvalidID : Invalid) - UnitPosition->second.erase(InvalidID); - if (UnitPosition->second.empty()) - Cache.erase(UnitPosition); -} - -void CompilationUnitAnalysisManager::clear(CompilationUnit &Unit) noexcept { - Cache.erase(&Unit); - ActiveComputations.erase(&Unit); -} - -void CompilationUnitAnalysisManager::clearAll() noexcept { - Cache.clear(); - ActiveComputations.clear(); -} - -void MachinePassInstrumentation::addBeforeCallback(BeforeCallback Callback) { - if (!Callback) - return; - std::scoped_lock Lock(Mutex); - Before.push_back(std::move(Callback)); -} - -void MachinePassInstrumentation::addAfterCallback(AfterCallback Callback) { - if (!Callback) - return; - std::scoped_lock Lock(Mutex); - After.push_back(std::move(Callback)); -} - -void MachinePassInstrumentation::addFailureCallback(FailureCallback Callback) { - if (!Callback) - return; - std::scoped_lock Lock(Mutex); - Failure.push_back(std::move(Callback)); -} - -void MachinePassInstrumentation::addBeforeAnalysisCallback(BeforeAnalysisCallback Callback) { - if (!Callback) - return; - std::scoped_lock Lock(Mutex); - BeforeAnalysis.push_back(std::move(Callback)); -} - -void MachinePassInstrumentation::addAfterAnalysisCallback(AfterAnalysisCallback Callback) { - if (!Callback) - return; - std::scoped_lock Lock(Mutex); - AfterAnalysis.push_back(std::move(Callback)); -} - -void MachinePassInstrumentation::addAnalysisFailureCallback(AnalysisFailureCallback Callback) { - if (!Callback) - return; - std::scoped_lock Lock(Mutex); - AnalysisFailure.push_back(std::move(Callback)); -} - -void MachinePassInstrumentation::addIRPrintCallback(IRPrintCallback Callback) { - if (!Callback) - return; - std::scoped_lock Lock(Mutex); - IRPrint.push_back(std::move(Callback)); -} - -void MachinePassInstrumentation::addChangeCallback(ChangeCallback Callback) { - if (!Callback) - return; - std::scoped_lock Lock(Mutex); - Change.push_back(std::move(Callback)); -} - -void MachinePassInstrumentation::setActionFilter(ActionFilter NewFilter) { - std::scoped_lock Lock(Mutex); - Filter = std::move(NewFilter); -} - -void MachinePassInstrumentation::setPerFunctionFuel(std::optional Fuel) { - std::scoped_lock Lock(Mutex); - PerFunctionFuel = Fuel; - ConsumedFuel.clear(); - ActionEvents.clear(); -} - -void MachinePassInstrumentation::addBeforeUnitCallback(BeforeUnitCallback Callback) { - if (!Callback) - return; - std::scoped_lock Lock(Mutex); - BeforeUnit.push_back(std::move(Callback)); -} - -void MachinePassInstrumentation::addAfterUnitCallback(AfterUnitCallback Callback) { - if (!Callback) - return; - std::scoped_lock Lock(Mutex); - AfterUnit.push_back(std::move(Callback)); -} - -void MachinePassInstrumentation::addUnitFailureCallback(UnitFailureCallback Callback) { - if (!Callback) - return; - std::scoped_lock Lock(Mutex); - UnitFailure.push_back(std::move(Callback)); -} - -void MachinePassInstrumentation::addBeforeUnitAnalysisCallback( - BeforeUnitAnalysisCallback Callback) { - if (!Callback) - return; - std::scoped_lock Lock(Mutex); - BeforeUnitAnalysis.push_back(std::move(Callback)); -} - -void MachinePassInstrumentation::addAfterUnitAnalysisCallback(AfterUnitAnalysisCallback Callback) { - if (!Callback) - return; - std::scoped_lock Lock(Mutex); - AfterUnitAnalysis.push_back(std::move(Callback)); -} - -void MachinePassInstrumentation::addUnitAnalysisFailureCallback( - UnitAnalysisFailureCallback Callback) { - if (!Callback) - return; - std::scoped_lock Lock(Mutex); - UnitAnalysisFailure.push_back(std::move(Callback)); -} - -InstrumentationStatistic &MachinePassInstrumentation::statistic(std::string_view Name, - bool IsAnalysis) const { - const std::string Key = std::string(IsAnalysis ? "analysis:" : "pass:") + std::string(Name); - auto [Position, Inserted] = Statistics.try_emplace(Key); - if (Inserted) { - Position->second.Name = std::string(Name); - Position->second.IsAnalysis = IsAnalysis; - } - return Position->second; -} - -bool MachinePassInstrumentation::bufferFunctionEvent( - const MachineFunction &Function, std::function Replay) const { - if (ActiveBuffer == nullptr) - return false; - - std::shared_ptr Snapshot; - auto Cloned = cloneMachineFunction( - Function, *ActiveBuffer->Target, - MachineFunctionCloneOptions{.NewStableID = Function.stableID(), .NewName = std::nullopt}); - if (Cloned) { - Snapshot = std::shared_ptr(std::move(Cloned->ClonedFunction)); - } else { - Snapshot = - std::shared_ptr(&Function, [](const MachineFunction *) noexcept {}); - } - ActiveBuffer->Events.emplace_back( - [Snapshot = std::move(Snapshot), Replay = std::move(Replay)]() { Replay(*Snapshot); }); - return true; -} - -void MachinePassInstrumentation::beginBuffering(BufferedEvents &Buffer, - const TargetDescription &Target) const noexcept { - Buffer.Target = &Target; - Buffer.Events.clear(); - ActiveBuffer = &Buffer; -} - -void MachinePassInstrumentation::endBuffering() const noexcept { - ActiveBuffer = nullptr; -} - -void MachinePassInstrumentation::replayBufferedEvents(BufferedEvents &Buffer) const { - for (const std::function &Event : Buffer.Events) - Event(); - Buffer.Events.clear(); - Buffer.Target = nullptr; -} - -void MachinePassInstrumentation::before(std::string_view Name, - const MachineFunction &Function) const { - if (bufferFunctionEvent(Function, [this, Name = std::string(Name)](const MachineFunction &Input) { - before(Name, Input); - })) { - return; - } - std::vector Callbacks; - std::vector Printers; - { - std::scoped_lock Lock(Mutex); - Callbacks = Before; - Printers = IRPrint; - } - for (const BeforeCallback &Callback : Callbacks) - Callback(Name, Function); - for (const IRPrintCallback &Printer : Printers) - Printer(InstrumentationPhase::Before, Name, Function); -} - -void MachinePassInstrumentation::after(std::string_view Name, const MachineFunction &Function, - const MachinePassResult &Result, - std::uint64_t Nanoseconds) const { - if (bufferFunctionEvent(Function, [this, Name = std::string(Name), Result, - Nanoseconds](const MachineFunction &Input) { - after(Name, Input, Result, Nanoseconds); - })) { - return; - } - std::vector Callbacks; - std::vector Printers; - { - std::scoped_lock Lock(Mutex); - InstrumentationStatistic &Record = statistic(Name, false); - ++Record.Invocations; - Record.Changes += Result.Changed ? 1U : 0U; - Record.TotalNanoseconds += Nanoseconds; - Callbacks = After; - Printers = IRPrint; - } - for (const AfterCallback &Callback : Callbacks) - Callback(Name, Function, Result); - for (const IRPrintCallback &Printer : Printers) - Printer(InstrumentationPhase::After, Name, Function); -} - -void MachinePassInstrumentation::failure(std::string_view Name, const MachineFunction &Function, - const Error &ErrorValue, std::uint64_t Nanoseconds) const { - if (bufferFunctionEvent(Function, [this, Name = std::string(Name), ErrorValue, - Nanoseconds](const MachineFunction &Input) { - failure(Name, Input, ErrorValue, Nanoseconds); - })) { - return; - } - std::vector Callbacks; - { - std::scoped_lock Lock(Mutex); - InstrumentationStatistic &Record = statistic(Name, false); - ++Record.Invocations; - ++Record.Failures; - Record.TotalNanoseconds += Nanoseconds; - Callbacks = Failure; - } - for (const FailureCallback &Callback : Callbacks) - Callback(Name, Function, ErrorValue); -} - -void MachinePassInstrumentation::beforeAnalysis(std::string_view Name, - const MachineFunction &Function) const { - if (bufferFunctionEvent(Function, [this, Name = std::string(Name)](const MachineFunction &Input) { - beforeAnalysis(Name, Input); - })) { - return; - } - std::vector Callbacks; - { - std::scoped_lock Lock(Mutex); - Callbacks = BeforeAnalysis; - } - for (const BeforeAnalysisCallback &Callback : Callbacks) - Callback(Name, Function); -} - -void MachinePassInstrumentation::afterAnalysis(std::string_view Name, - const MachineFunction &Function, bool CacheHit, - std::uint64_t Nanoseconds) const { - if (bufferFunctionEvent(Function, [this, Name = std::string(Name), CacheHit, - Nanoseconds](const MachineFunction &Input) { - afterAnalysis(Name, Input, CacheHit, Nanoseconds); - })) { - return; - } - std::vector Callbacks; - { - std::scoped_lock Lock(Mutex); - InstrumentationStatistic &Record = statistic(Name, true); - ++Record.Invocations; - Record.CacheHits += CacheHit ? 1U : 0U; - Record.TotalNanoseconds += Nanoseconds; - Callbacks = AfterAnalysis; - } - for (const AfterAnalysisCallback &Callback : Callbacks) - Callback(Name, Function, CacheHit, Nanoseconds); -} - -void MachinePassInstrumentation::analysisFailure(std::string_view Name, - const MachineFunction &Function, - const Error &ErrorValue, - std::uint64_t Nanoseconds) const { - if (bufferFunctionEvent(Function, [this, Name = std::string(Name), ErrorValue, - Nanoseconds](const MachineFunction &Input) { - analysisFailure(Name, Input, ErrorValue, Nanoseconds); - })) { - return; - } - std::vector Callbacks; - { - std::scoped_lock Lock(Mutex); - InstrumentationStatistic &Record = statistic(Name, true); - ++Record.Invocations; - ++Record.Failures; - Record.TotalNanoseconds += Nanoseconds; - Callbacks = AnalysisFailure; - } - for (const AnalysisFailureCallback &Callback : Callbacks) - Callback(Name, Function, ErrorValue); -} - -void MachinePassInstrumentation::change(std::string_view Name, const MachineFunction &Function, - MachinePassChanges Changes, bool FingerprintChanged) const { - if (bufferFunctionEvent(Function, [this, Name = std::string(Name), Changes, - FingerprintChanged](const MachineFunction &Input) { - change(Name, Input, Changes, FingerprintChanged); - })) { - return; - } - std::vector Callbacks; - { - std::scoped_lock Lock(Mutex); - Callbacks = Change; - } - for (const ChangeCallback &Callback : Callbacks) - Callback(Name, Function, Changes, FingerprintChanged); -} - -Expected MachinePassInstrumentation::requestAction(const MachineActionID &Action, - const MachineFunction &Function, - std::uint64_t Cost) { - if (Action.Pass.empty() || Action.Rule.empty() || Action.Function != Function.stableID() || - Cost == 0) { - return makeUnexpected(ErrorCode::InvalidArgument, "machine action identity is invalid"); - } - std::scoped_lock ActionLock(ActionMutex); - ActionFilter CurrentFilter; - { - std::scoped_lock Lock(Mutex); - CurrentFilter = Filter; - } - if (CurrentFilter && !CurrentFilter(Action, Cost)) { - std::scoped_lock Lock(Mutex); - ActionEvents.push_back({Action, Cost, false}); - return false; - } - - std::scoped_lock Lock(Mutex); - if (!PerFunctionFuel) { - ActionEvents.push_back({Action, Cost, true}); - return true; - } - std::uint64_t &Consumed = ConsumedFuel[Function.stableID().value()]; - if (Consumed > *PerFunctionFuel || Cost > *PerFunctionFuel - Consumed) { - ActionEvents.push_back({Action, Cost, false}); - return false; - } - Consumed += Cost; - ActionEvents.push_back({Action, Cost, true}); - return true; -} - -void MachinePassInstrumentation::beforeUnit(std::string_view Name, - const CompilationUnit &Unit) const { - std::vector Callbacks; - { - std::scoped_lock Lock(Mutex); - Callbacks = BeforeUnit; - } - for (const BeforeUnitCallback &Callback : Callbacks) - Callback(Name, Unit); -} - -void MachinePassInstrumentation::afterUnit(std::string_view Name, const CompilationUnit &Unit, - const CompilationUnitPassResult &Result, - std::uint64_t Nanoseconds) const { - std::vector Callbacks; - { - std::scoped_lock Lock(Mutex); - InstrumentationStatistic &Record = statistic("unit:" + std::string(Name), false); - ++Record.Invocations; - Record.Changes += Result.Changed ? 1U : 0U; - Record.TotalNanoseconds += Nanoseconds; - Callbacks = AfterUnit; - } - for (const AfterUnitCallback &Callback : Callbacks) - Callback(Name, Unit, Result); -} - -void MachinePassInstrumentation::unitFailure(std::string_view Name, const CompilationUnit &Unit, - const Error &ErrorValue, - std::uint64_t Nanoseconds) const { - std::vector Callbacks; - { - std::scoped_lock Lock(Mutex); - InstrumentationStatistic &Record = statistic("unit:" + std::string(Name), false); - ++Record.Invocations; - ++Record.Failures; - Record.TotalNanoseconds += Nanoseconds; - Callbacks = UnitFailure; - } - for (const UnitFailureCallback &Callback : Callbacks) - Callback(Name, Unit, ErrorValue); -} - -void MachinePassInstrumentation::beforeUnitAnalysis(std::string_view Name, - const CompilationUnit &Unit) const { - std::vector Callbacks; - { - std::scoped_lock Lock(Mutex); - Callbacks = BeforeUnitAnalysis; - } - for (const BeforeUnitAnalysisCallback &Callback : Callbacks) - Callback(Name, Unit); -} - -void MachinePassInstrumentation::afterUnitAnalysis(std::string_view Name, - const CompilationUnit &Unit, bool CacheHit, - std::uint64_t Nanoseconds) const { - std::vector Callbacks; - { - std::scoped_lock Lock(Mutex); - InstrumentationStatistic &Record = statistic("unit:" + std::string(Name), true); - ++Record.Invocations; - Record.CacheHits += CacheHit ? 1U : 0U; - Record.TotalNanoseconds += Nanoseconds; - Callbacks = AfterUnitAnalysis; - } - for (const AfterUnitAnalysisCallback &Callback : Callbacks) - Callback(Name, Unit, CacheHit, Nanoseconds); -} - -void MachinePassInstrumentation::unitAnalysisFailure(std::string_view Name, - const CompilationUnit &Unit, - const Error &ErrorValue, - std::uint64_t Nanoseconds) const { - std::vector Callbacks; - { - std::scoped_lock Lock(Mutex); - InstrumentationStatistic &Record = statistic("unit:" + std::string(Name), true); - ++Record.Invocations; - ++Record.Failures; - Record.TotalNanoseconds += Nanoseconds; - Callbacks = UnitAnalysisFailure; - } - for (const UnitAnalysisFailureCallback &Callback : Callbacks) - Callback(Name, Unit, ErrorValue); -} - -std::vector MachinePassInstrumentation::statistics() const { - std::vector Result; - { - std::scoped_lock Lock(Mutex); - Result.reserve(Statistics.size()); - for (const auto &[Key, Record] : Statistics) { - (void)Key; - Result.push_back(Record); - } - } - std::ranges::sort( - Result, [](const InstrumentationStatistic &Left, const InstrumentationStatistic &Right) { - if (Left.IsAnalysis != Right.IsAnalysis) - return Left.IsAnalysis < Right.IsAnalysis; - return Left.Name < Right.Name; - }); - return Result; -} - -std::vector MachinePassInstrumentation::actionEvents() const { - std::vector Result; - { - std::scoped_lock Lock(Mutex); - Result = ActionEvents; - } - std::ranges::sort(Result, [](const MachineActionEvent &Left, const MachineActionEvent &Right) { - if (Left.ID.Function.value() != Right.ID.Function.value()) - return Left.ID.Function.value() < Right.ID.Function.value(); - if (Left.ID.Instruction.value() != Right.ID.Instruction.value()) - return Left.ID.Instruction.value() < Right.ID.Instruction.value(); - if (Left.ID.Pass != Right.ID.Pass) - return Left.ID.Pass < Right.ID.Pass; - if (Left.ID.Rule != Right.ID.Rule) - return Left.ID.Rule < Right.ID.Rule; - if (Left.Cost != Right.Cost) - return Left.Cost < Right.Cost; - return Left.Accepted < Right.Accepted; - }); - return Result; -} - -void MachinePassInstrumentation::clearStatistics() { - std::scoped_lock Lock(Mutex); - Statistics.clear(); - ConsumedFuel.clear(); - ActionEvents.clear(); -} - -Expected MachinePassManager::validateContract(const MachinePassContract &Contract) const { - if (Contract.Name.empty()) - return makeUnexpected(ErrorCode::InvalidArgument, "machine pass must have a non-empty name"); - if (Contract.Sets.intersects(Contract.Clears)) { - return makeUnexpected(ErrorCode::InvalidArgument, - "machine pass cannot set and clear the same property"); - } - if (hasDuplicateAnalysisIDs(Contract.RequiredAnalyses)) { - return makeUnexpected(ErrorCode::InvalidArgument, - "machine pass required analyses must be non-null and unique"); - } - return validateParameters(Contract.Parameters); -} - -Expected MachinePassManager::addPass(std::unique_ptr Pass) { - if (!Pass) - return makeUnexpected(ErrorCode::InvalidArgument, - "machine pass manager cannot add a null pass"); - auto Validation = validateContract(Pass->contract()); - if (!Validation) - return std::unexpected(Validation.error()); - Passes.push_back(std::move(Pass)); - return {}; -} - -Expected MachinePassManager::run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses, - MachinePassInstrumentation *Instrumentation) const { - Analyses.setInstrumentation(Instrumentation); - for (const std::unique_ptr &Pass : Passes) { - const MachinePassContract &Contract = Pass->contract(); - const std::string_view Name = Contract.Name; - - if (const MachineFunctionProperties Missing = - Contract.Requires.missingFrom(Function.properties()); - !Missing.empty()) { - Error Failure(ErrorCode::VerificationError, - "pass '" + std::string(Name) + "' requires properties: " + Missing.toString()); - if (Instrumentation != nullptr) - Instrumentation->failure(Name, Function, Failure); - Analyses.setInstrumentation(nullptr); - return std::unexpected(std::move(Failure)); - } - - if (Options.VerifyBefore) { - auto Verification = MachineVerifier::verify(Function, Target); - if (!Verification) { - Error Failure = prefixedError(Verification.error(), "pass '" + std::string(Name) + - "' received invalid MachineIR: "); - if (Instrumentation != nullptr) - Instrumentation->failure(Name, Function, Failure); - Analyses.setInstrumentation(nullptr); - return std::unexpected(std::move(Failure)); - } - } - - for (const AnalysisID Required : Contract.RequiredAnalyses) { - auto Result = Analyses.getResultImpl(Required, Function, Target); - if (!Result) { - Error Failure = - prefixedError(Result.error(), "pass '" + std::string(Name) + - "' could not materialize a required analysis: "); - if (Instrumentation != nullptr) - Instrumentation->failure(Name, Function, Failure); - Analyses.setInstrumentation(nullptr); - return std::unexpected(std::move(Failure)); - } - } - - const std::uint64_t FingerprintBefore = - Options.DetectUnreportedChanges ? machineFunctionFingerprint(Function) : 0; - if (Instrumentation != nullptr) - Instrumentation->before(Name, Function); - const Clock::time_point Start = Clock::now(); - Analyses.ActivePass = std::string(Name); - auto PassResult = Pass->run(Function, Target, Analyses); - Analyses.ActivePass.clear(); - const std::uint64_t Duration = elapsedNanoseconds(Start); - if (!PassResult) { - Error Failure = - prefixedError(PassResult.error(), "pass '" + std::string(Name) + "' failed: "); - if (Instrumentation != nullptr) - Instrumentation->failure(Name, Function, Failure, Duration); - Analyses.clear(Function); - Analyses.setInstrumentation(nullptr); - return std::unexpected(std::move(Failure)); - } - - if (PassResult->Changed != !PassResult->Changes.empty()) { - Error Failure(ErrorCode::VerificationError, - "pass '" + std::string(Name) + - "' reported inconsistent changed state and modification categories"); - if (Instrumentation != nullptr) - Instrumentation->failure(Name, Function, Failure, Duration); - Analyses.clear(Function); - Analyses.setInstrumentation(nullptr); - return std::unexpected(std::move(Failure)); - } - if (!Contract.DeclaredChanges.contains(PassResult->Changes)) { - Error Failure(ErrorCode::VerificationError, - "pass '" + std::string(Name) + - "' reported a modification category absent from its registration"); - if (Instrumentation != nullptr) - Instrumentation->failure(Name, Function, Failure, Duration); - Analyses.clear(Function); - Analyses.setInstrumentation(nullptr); - return std::unexpected(std::move(Failure)); - } - - bool FingerprintChanged = PassResult->Changed; - if (Options.DetectUnreportedChanges) { - FingerprintChanged = FingerprintBefore != machineFunctionFingerprint(Function); - if (FingerprintChanged && !PassResult->Changed) { - Error Failure(ErrorCode::VerificationError, - "pass '" + std::string(Name) + - "' changed MachineIR without reporting a modification"); - if (Instrumentation != nullptr) - Instrumentation->failure(Name, Function, Failure, Duration); - Analyses.clear(Function); - Analyses.setInstrumentation(nullptr); - return std::unexpected(std::move(Failure)); - } - } - if (Instrumentation != nullptr) - Instrumentation->change(Name, Function, PassResult->Changes, FingerprintChanged); - - auto Transition = - Function.properties().applyTransition(Contract.Requires, Contract.Sets, Contract.Clears); - if (!Transition) { - Error Failure = - prefixedError(Transition.error(), "pass '" + std::string(Name) + - "' produced an invalid property transition: "); - if (Instrumentation != nullptr) - Instrumentation->failure(Name, Function, Failure, Duration); - Analyses.clear(Function); - Analyses.setInstrumentation(nullptr); - return std::unexpected(std::move(Failure)); - } - Analyses.invalidate(Function, PassResult->Preserved, PassResult->Changes); - - if (Options.VerifyEach) { - MachineVerifierOptions VerifyOptions; - VerifyOptions.Stage = Contract.VerificationStage; - auto Verification = MachineVerifier::verify(Function, Target, VerifyOptions); - if (!Verification) { - Error Failure = prefixedError(Verification.error(), - "pass '" + std::string(Name) + "' left invalid MachineIR: "); - if (Instrumentation != nullptr) - Instrumentation->failure(Name, Function, Failure, Duration); - Analyses.clear(Function); - Analyses.setInstrumentation(nullptr); - return std::unexpected(std::move(Failure)); - } - } - if (Instrumentation != nullptr) - Instrumentation->after(Name, Function, *PassResult, Duration); - } - Analyses.setInstrumentation(nullptr); - return {}; -} - -Expected MachinePassManager::runFunctions(CompilationUnit &Unit, - const TargetDescription &Target, - const MachineAnalysisManager &AnalysisPrototype, - std::size_t ThreadCount, - MachinePassInstrumentation *Instrumentation) const { - if (ThreadCount == 0) - return makeUnexpected(ErrorCode::InvalidArgument, "machine pass thread count must be nonzero"); - auto UnitVerification = verifyCompilationUnit(Unit, Target); - if (!UnitVerification) - return std::unexpected(UnitVerification.error()); - const std::size_t FunctionCount = Unit.functionCount(); - if (FunctionCount == 0) - return {}; - const std::size_t WorkerCount = std::min(ThreadCount, FunctionCount); - if (WorkerCount > 1) { - for (const std::unique_ptr &Pass : Passes) { - if (Pass->contract().ThreadSafety != PassThreadSafety::ThreadSafe) { - return makeUnexpected(ErrorCode::InvalidArgument, - "parallel machine pipeline contains a pass not marked thread-safe"); - } - auto AnalysisSafety = - AnalysisPrototype.validateParallelRequirements(Pass->contract().RequiredAnalyses); - if (!AnalysisSafety) - return std::unexpected(AnalysisSafety.error()); - } - } - std::vector> Managers; - Managers.reserve(FunctionCount); - for (std::size_t Index = 0; Index < FunctionCount; ++Index) { - auto Manager = AnalysisPrototype.forkEmpty(); - if (!Manager) - return std::unexpected(Manager.error()); - Managers.push_back(std::move(*Manager)); - } - - std::vector> Failures(FunctionCount); - std::vector EventBuffers(FunctionCount); - std::atomic NextFunction = 0; - const auto Worker = [&]() { - while (true) { - const std::size_t Index = NextFunction.fetch_add(1, std::memory_order_relaxed); - if (Index >= FunctionCount) - return; - MachineFunction *Function = Unit.functionAt(Index); - if (Function == nullptr) { - Failures[Index] = Error(ErrorCode::InternalError, - "compilation unit contains a null function during parallel run"); - continue; - } - if (Instrumentation != nullptr) - Instrumentation->beginBuffering(EventBuffers[Index], Target); - auto Result = run(*Function, Target, *Managers[Index], Instrumentation); - if (Instrumentation != nullptr) - Instrumentation->endBuffering(); - if (!Result) - Failures[Index] = Result.error(); - } - }; - - std::vector Workers; - Workers.reserve(WorkerCount); - for (std::size_t Index = 0; Index < WorkerCount; ++Index) - Workers.emplace_back(Worker); - for (std::thread &WorkerThread : Workers) - WorkerThread.join(); - - for (std::size_t Index = 0; Index < FunctionCount; ++Index) { - if (Instrumentation != nullptr) - Instrumentation->replayBufferedEvents(EventBuffers[Index]); - const auto &Failure = Failures[Index]; - if (Failure) { - return std::unexpected(prefixedError( - *Failure, "function '" + std::string(Unit.functionAt(Index)->name()) + "' failed: ")); - } - } - return {}; -} - -Expected CompilationUnitPassManager::addPass(std::unique_ptr Pass) { - if (!Pass) { - return makeUnexpected(ErrorCode::InvalidArgument, - "compilation-unit pass manager cannot add a null pass"); - } - const CompilationUnitPassContract &Contract = Pass->contract(); - if (Contract.Name.empty()) { - return makeUnexpected(ErrorCode::InvalidArgument, - "compilation-unit pass must have a non-empty name"); - } - if (hasDuplicateAnalysisIDs(Contract.RequiredAnalyses)) { - return makeUnexpected(ErrorCode::InvalidArgument, - "compilation-unit pass required analyses must be non-null and unique"); - } - auto Parameters = validateParameters(Contract.Parameters); - if (!Parameters) - return std::unexpected(Parameters.error()); - Passes.push_back(std::move(Pass)); - return {}; -} - -Expected CompilationUnitPassManager::run(CompilationUnit &Unit, - const TargetDescription &Target, - CompilationUnitAnalysisManager &UnitAnalyses, - MachineAnalysisManager &FunctionAnalyses, - MachinePassInstrumentation *Instrumentation) const { - UnitAnalyses.setInstrumentation(Instrumentation); - FunctionAnalyses.setInstrumentation(Instrumentation); - for (const std::unique_ptr &Pass : Passes) { - const CompilationUnitPassContract &Contract = Pass->contract(); - const std::string_view Name = Contract.Name; - - if (Options.VerifyBefore) { - auto Verification = verifyCompilationUnit(Unit, Target); - if (!Verification) { - Error Failure = - prefixedError(Verification.error(), "compilation-unit pass '" + std::string(Name) + - "' received invalid MachineIR: "); - if (Instrumentation != nullptr) - Instrumentation->unitFailure(Name, Unit, Failure); - UnitAnalyses.setInstrumentation(nullptr); - FunctionAnalyses.setInstrumentation(nullptr); - return std::unexpected(std::move(Failure)); - } - } - - for (const AnalysisID Required : Contract.RequiredAnalyses) { - auto Result = UnitAnalyses.getResultImpl(Required, Unit, Target); - if (!Result) { - Error Failure = - prefixedError(Result.error(), "compilation-unit pass '" + std::string(Name) + - "' could not materialize a required analysis: "); - if (Instrumentation != nullptr) - Instrumentation->unitFailure(Name, Unit, Failure); - UnitAnalyses.setInstrumentation(nullptr); - FunctionAnalyses.setInstrumentation(nullptr); - return std::unexpected(std::move(Failure)); - } - } - - if (Instrumentation != nullptr) - Instrumentation->beforeUnit(Name, Unit); - const Clock::time_point Start = Clock::now(); - auto Result = Pass->run(Unit, Target, UnitAnalyses, FunctionAnalyses); - const std::uint64_t Duration = elapsedNanoseconds(Start); - if (!Result) { - Error Failure = prefixedError(Result.error(), - "compilation-unit pass '" + std::string(Name) + "' failed: "); - if (Instrumentation != nullptr) - Instrumentation->unitFailure(Name, Unit, Failure, Duration); - UnitAnalyses.clearAll(); - FunctionAnalyses.clearAll(); - UnitAnalyses.setInstrumentation(nullptr); - FunctionAnalyses.setInstrumentation(nullptr); - return std::unexpected(std::move(Failure)); - } - if (Result->Changed != !Result->Changes.empty() || - !Contract.DeclaredChanges.contains(Result->Changes)) { - Error Failure(ErrorCode::VerificationError, - "compilation-unit pass '" + std::string(Name) + - "' reported inconsistent or undeclared modifications"); - if (Instrumentation != nullptr) - Instrumentation->unitFailure(Name, Unit, Failure, Duration); - UnitAnalyses.clearAll(); - FunctionAnalyses.clearAll(); - UnitAnalyses.setInstrumentation(nullptr); - FunctionAnalyses.setInstrumentation(nullptr); - return std::unexpected(std::move(Failure)); - } - - UnitAnalyses.invalidate(Unit, Result->PreservedUnitAnalyses, Result->Changes); - for (std::size_t Index = 0; Index < Unit.functionCount(); ++Index) { - MachineFunction *Function = Unit.functionAt(Index); - if (Function != nullptr) { - FunctionAnalyses.invalidate(*Function, Result->PreservedFunctionAnalyses, Result->Changes); - } - } - if (Options.VerifyEach) { - auto Verification = verifyCompilationUnit(Unit, Target); - if (!Verification) { - Error Failure = - prefixedError(Verification.error(), "compilation-unit pass '" + std::string(Name) + - "' left invalid MachineIR: "); - if (Instrumentation != nullptr) - Instrumentation->unitFailure(Name, Unit, Failure, Duration); - UnitAnalyses.clearAll(); - FunctionAnalyses.clearAll(); - UnitAnalyses.setInstrumentation(nullptr); - FunctionAnalyses.setInstrumentation(nullptr); - return std::unexpected(std::move(Failure)); - } - } - if (Instrumentation != nullptr) - Instrumentation->afterUnit(Name, Unit, *Result, Duration); - } - UnitAnalyses.setInstrumentation(nullptr); - FunctionAnalyses.setInstrumentation(nullptr); - return {}; -} - -} // namespace rcc diff --git a/backend/lib/CodeGen/MachinePassManager.cpp b/backend/lib/CodeGen/MachinePassManager.cpp new file mode 100644 index 0000000..0810965 --- /dev/null +++ b/backend/lib/CodeGen/MachinePassManager.cpp @@ -0,0 +1,1099 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "rcc/CodeGen/MachinePassManager.h" + +#include "rcc/CodeGen/CompilationUnit.h" +#include "rcc/CodeGen/MachineBasicBlock.h" +#include "rcc/CodeGen/MachineFunction.h" +#include "rcc/CodeGen/MachineFunctionCloner.h" +#include "rcc/CodeGen/MachineInstr.h" +#include "rcc/CodeGen/MachineOperand.h" +#include "rcc/CodeGen/MachineVerifier.h" +#include "rcc/CodeGen/TargetDescription.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace rcc { + +thread_local MachinePassInstrumentation::BufferedEvents *MachinePassInstrumentation::ActiveBuffer = + nullptr; + +namespace { + +using Clock = std::chrono::steady_clock; + +[[nodiscard]] std::uint64_t elapsedNanoseconds(Clock::time_point Start) noexcept { + const auto Elapsed = std::chrono::duration_cast(Clock::now() - Start); + if (Elapsed.count() <= 0) + return 0; + return static_cast(Elapsed.count()); +} + +[[nodiscard]] Error prefixedError(const Error &Source, std::string Prefix) { + Prefix.append(Source.message()); + return Error(Source.code(), std::move(Prefix)); +} + +[[nodiscard]] bool hasDuplicateAnalysisIDs(std::span IDs) { + std::unordered_set Unique; + for (const AnalysisID ID : IDs) { + if (ID == nullptr || !Unique.insert(ID).second) + return true; + } + return false; +} + +[[nodiscard]] Expected validateParameters(std::span Parameters) { + std::unordered_set Names; + for (const PassParameter &Parameter : Parameters) { + if (Parameter.Name.empty()) + return makeUnexpected(ErrorCode::InvalidArgument, "pass parameter name cannot be empty"); + if (!Names.insert(Parameter.Name).second) + return makeUnexpected(ErrorCode::InvalidArgument, "pass parameter names must be unique"); + if (Parameter.Required && Parameter.DefaultValue) { + return makeUnexpected(ErrorCode::InvalidArgument, + "a required pass parameter cannot have a default value"); + } + } + return {}; +} + +void combineFingerprint(std::uint64_t &State, std::uint64_t Value) noexcept { + State ^= Value + 0x9e3779b97f4a7c15ULL + (State << 6U) + (State >> 2U); +} + +[[nodiscard]] std::uint64_t machineFunctionFingerprint(const MachineFunction &Function) noexcept { + std::uint64_t Result = 0xcbf29ce484222325ULL; + combineFingerprint(Result, Function.stableID().value()); + combineFingerprint(Result, Function.properties().rawValue()); + combineFingerprint(Result, Function.blockCount()); + combineFingerprint(Result, Function.allInstructions().size()); + combineFingerprint(Result, Function.allMemOperands().size()); + + for (const MachineBasicBlock *Block = Function.firstBlock(); Block != nullptr; + Block = Block->next()) { + combineFingerprint(Result, Block->stableID().value()); + combineFingerprint(Result, Block->instructionCount()); + combineFingerprint(Result, Block->successors().size()); + for (const MachineSuccessor &Successor : Block->successors()) { + combineFingerprint(Result, + Successor.Block == nullptr ? 0 : Successor.Block->stableID().value()); + combineFingerprint(Result, Successor.Probability.rawValue()); + } + for (const MachineBasicBlockLiveIn &LiveIn : Block->liveIns()) { + combineFingerprint(Result, LiveIn.PhysReg.number()); + combineFingerprint(Result, LiveIn.Lanes.rawValue()); + } + + for (const MachineInstr *Instruction = Block->firstInstruction(); Instruction != nullptr; + Instruction = Instruction->next()) { + combineFingerprint(Result, Instruction->stableID().value()); + combineFingerprint(Result, Instruction->opcode().value()); + combineFingerprint(Result, Instruction->flags().rawValue()); + combineFingerprint(Result, Instruction->operandCount()); + combineFingerprint(Result, Instruction->memOperands().size()); + for (const MachineOperand &Operand : Instruction->operands()) { + combineFingerprint(Result, static_cast(Operand.kind())); + combineFingerprint(Result, Operand.targetFlags()); + combineFingerprint(Result, Operand.registerFlags().rawValue()); + combineFingerprint(Result, Operand.subReg().value()); + if (const Register *Reg = Operand.getIf()) + combineFingerprint(Result, Reg->opaqueValue()); + else if (const std::int64_t *Immediate = Operand.getIf()) + combineFingerprint(Result, static_cast(*Immediate)); + } + } + } + return Result; +} + +[[nodiscard]] Expected verifyCompilationUnit(const CompilationUnit &Unit, + const TargetDescription &Target) { + auto UnitVerification = Unit.verify(); + if (!UnitVerification) + return std::unexpected(UnitVerification.error()); + for (std::size_t Index = 0; Index < Unit.functionCount(); ++Index) { + const MachineFunction *Function = Unit.functionAt(Index); + if (Function == nullptr) + return makeUnexpected(ErrorCode::InternalError, + "compilation unit function order contains a null entry"); + auto FunctionVerification = MachineVerifier::verify(*Function, Target); + if (!FunctionVerification) + return std::unexpected(FunctionVerification.error()); + } + return {}; +} + +} // namespace + +void AnalysisManagerInstrumentation::beforeAnalysis( + MachinePassInstrumentation *Instrumentation, std::string_view Name, + const MachineFunction &Function) { + Instrumentation->beforeAnalysis(Name, Function); +} + +void AnalysisManagerInstrumentation::afterAnalysis( + MachinePassInstrumentation *Instrumentation, std::string_view Name, + const MachineFunction &Function, bool CacheHit, std::uint64_t Nanoseconds) { + Instrumentation->afterAnalysis(Name, Function, CacheHit, Nanoseconds); +} + +void AnalysisManagerInstrumentation::analysisFailure( + MachinePassInstrumentation *Instrumentation, std::string_view Name, + const MachineFunction &Function, const Error &Failure, std::uint64_t Nanoseconds) { + Instrumentation->analysisFailure(Name, Function, Failure, Nanoseconds); +} + +Expected +AnalysisManagerInstrumentation::requestAction( + MachinePassInstrumentation *Instrumentation, std::string_view Pass, std::string_view Rule, + const MachineFunction &Function, MachineInstrStableID Instruction, std::uint64_t Cost) { + return Instrumentation->requestAction(Pass, Rule, Function, Instruction, Cost); +} + +Expected +AnalysisManagerInstrumentation::requestAction( + MachinePassInstrumentation *Instrumentation, std::string_view Pass, std::string_view Rule, + const MachineFunction &Function, std::nullptr_t, std::uint64_t Cost) { + return Instrumentation->requestAction(Pass, Rule, Function, nullptr, Cost); +} + +void AnalysisManagerInstrumentation::beforeAnalysis( + MachinePassInstrumentation *Instrumentation, std::string_view Name, + const CompilationUnit &Unit) { + Instrumentation->beforeAnalysis(Name, Unit); +} + +void AnalysisManagerInstrumentation::afterAnalysis( + MachinePassInstrumentation *Instrumentation, std::string_view Name, const CompilationUnit &Unit, + bool CacheHit, std::uint64_t Nanoseconds) { + Instrumentation->afterAnalysis(Name, Unit, CacheHit, Nanoseconds); +} + +void AnalysisManagerInstrumentation::analysisFailure( + MachinePassInstrumentation *Instrumentation, std::string_view Name, const CompilationUnit &Unit, + const Error &Failure, std::uint64_t Nanoseconds) { + Instrumentation->analysisFailure(Name, Unit, Failure, Nanoseconds); +} + +std::string MachineActionID::toString() const { + std::string Result; + Result.reserve(Pass.size() + Rule.size() + 48U); + Result.append(Pass); + Result.push_back(':'); + Result.append(Rule); + Result.append(":f"); + Result.append(std::to_string(Function.value())); + Result.append(":i"); + Result.append(std::to_string(Instruction.value())); + return Result; +} + +Expected MachineActionReplay::request(std::string_view Rule, const MachineFunction &Function, + MachineInstrStableID Instruction, std::uint64_t Cost) { + if (!IsReplaying) { + const auto Position = RecordingInstructionIDs.find(Instruction); + const MachineInstrStableID CanonicalInstruction = + Position == RecordingInstructionIDs.end() ? Instruction : Position->second; + auto Accepted = Request(Rule, Function, CanonicalInstruction, Cost); + if (!Accepted) + return std::unexpected(Accepted.error()); + Decisions.push_back({ + .Rule = std::string(Rule), + .Function = Function.stableID(), + .Instruction = CanonicalInstruction, + .Cost = Cost, + .Accepted = *Accepted, + }); + return *Accepted; + } + + if (NextDecision >= Decisions.size()) { + return makeUnexpected(ErrorCode::InternalError, + "machine action replay requested an unrecorded decision"); + } + const Decision &Recorded = Decisions[NextDecision++]; + if (Recorded.Rule != Rule || Recorded.Function != Function.stableID() || + Recorded.Instruction != Instruction || Recorded.Cost != Cost) { + std::string Message = "machine action replay diverged from transaction preflight: recorded "; + Message.append(Recorded.Rule); + Message.append(":f"); + Message.append(std::to_string(Recorded.Function.value())); + Message.append(":i"); + Message.append(std::to_string(Recorded.Instruction.value())); + Message.append(" cost="); + Message.append(std::to_string(Recorded.Cost)); + Message.append(", requested "); + Message.append(Rule); + Message.append(":f"); + Message.append(std::to_string(Function.stableID().value())); + Message.append(":i"); + Message.append(std::to_string(Instruction.value())); + Message.append(" cost="); + Message.append(std::to_string(Cost)); + return makeUnexpected(ErrorCode::InternalError, std::move(Message)); + } + return Recorded.Accepted; +} + +void MachineActionReplay::beginReplay() noexcept { + IsReplaying = true; + NextDecision = 0; +} + +Expected MachineActionReplay::finishReplay() const { + if (!IsReplaying || NextDecision != Decisions.size()) { + return makeUnexpected(ErrorCode::InternalError, + "machine action replay did not consume every recorded decision"); + } + return {}; +} + +void MachinePassInstrumentation::addBeforeCallback(BeforeCallback Callback) { + if (!Callback) + return; + std::scoped_lock Lock(Mutex); + Before.push_back(std::move(Callback)); +} + +void MachinePassInstrumentation::addAfterCallback(AfterCallback Callback) { + if (!Callback) + return; + std::scoped_lock Lock(Mutex); + After.push_back(std::move(Callback)); +} + +void MachinePassInstrumentation::addFailureCallback(FailureCallback Callback) { + if (!Callback) + return; + std::scoped_lock Lock(Mutex); + Failure.push_back(std::move(Callback)); +} + +void MachinePassInstrumentation::addBeforeAnalysisCallback(BeforeAnalysisCallback Callback) { + if (!Callback) + return; + std::scoped_lock Lock(Mutex); + BeforeAnalysis.push_back(std::move(Callback)); +} + +void MachinePassInstrumentation::addAfterAnalysisCallback(AfterAnalysisCallback Callback) { + if (!Callback) + return; + std::scoped_lock Lock(Mutex); + AfterAnalysis.push_back(std::move(Callback)); +} + +void MachinePassInstrumentation::addAnalysisFailureCallback(AnalysisFailureCallback Callback) { + if (!Callback) + return; + std::scoped_lock Lock(Mutex); + AnalysisFailure.push_back(std::move(Callback)); +} + +void MachinePassInstrumentation::addIRPrintCallback(IRPrintCallback Callback) { + if (!Callback) + return; + std::scoped_lock Lock(Mutex); + IRPrint.push_back(std::move(Callback)); +} + +void MachinePassInstrumentation::addChangeCallback(ChangeCallback Callback) { + if (!Callback) + return; + std::scoped_lock Lock(Mutex); + Change.push_back(std::move(Callback)); +} + +void MachinePassInstrumentation::setActionFilter(ActionFilter NewFilter) { + std::scoped_lock Lock(Mutex); + Filter = std::move(NewFilter); +} + +void MachinePassInstrumentation::setPerFunctionFuel(std::optional Fuel) { + std::scoped_lock Lock(Mutex); + PerFunctionFuel = Fuel; + ConsumedFuel.clear(); + ActionEvents.clear(); +} + +void MachinePassInstrumentation::addBeforeUnitCallback(BeforeUnitCallback Callback) { + if (!Callback) + return; + std::scoped_lock Lock(Mutex); + BeforeUnit.push_back(std::move(Callback)); +} + +void MachinePassInstrumentation::addAfterUnitCallback(AfterUnitCallback Callback) { + if (!Callback) + return; + std::scoped_lock Lock(Mutex); + AfterUnit.push_back(std::move(Callback)); +} + +void MachinePassInstrumentation::addUnitFailureCallback(UnitFailureCallback Callback) { + if (!Callback) + return; + std::scoped_lock Lock(Mutex); + UnitFailure.push_back(std::move(Callback)); +} + +void MachinePassInstrumentation::addBeforeUnitAnalysisCallback( + BeforeUnitAnalysisCallback Callback) { + if (!Callback) + return; + std::scoped_lock Lock(Mutex); + BeforeUnitAnalysis.push_back(std::move(Callback)); +} + +void MachinePassInstrumentation::addAfterUnitAnalysisCallback(AfterUnitAnalysisCallback Callback) { + if (!Callback) + return; + std::scoped_lock Lock(Mutex); + AfterUnitAnalysis.push_back(std::move(Callback)); +} + +void MachinePassInstrumentation::addUnitAnalysisFailureCallback( + UnitAnalysisFailureCallback Callback) { + if (!Callback) + return; + std::scoped_lock Lock(Mutex); + UnitAnalysisFailure.push_back(std::move(Callback)); +} + +InstrumentationStatistic &MachinePassInstrumentation::statistic(std::string_view Name, + bool IsAnalysis) const { + const std::string Key = std::string(IsAnalysis ? "analysis:" : "pass:") + std::string(Name); + auto [Position, Inserted] = Statistics.try_emplace(Key); + if (Inserted) { + Position->second.Name = std::string(Name); + Position->second.IsAnalysis = IsAnalysis; + } + return Position->second; +} + +bool MachinePassInstrumentation::bufferFunctionEvent( + const MachineFunction &Function, std::function Replay) const { + if (ActiveBuffer == nullptr) + return false; + + std::shared_ptr Snapshot; + auto Cloned = cloneMachineFunction( + Function, *ActiveBuffer->Target, + MachineFunctionCloneOptions{.NewStableID = Function.stableID(), .NewName = std::nullopt}); + if (Cloned) { + Snapshot = std::shared_ptr(std::move(Cloned->ClonedFunction)); + } else { + Snapshot = + std::shared_ptr(&Function, [](const MachineFunction *) noexcept {}); + } + ActiveBuffer->Events.emplace_back( + [Snapshot = std::move(Snapshot), Replay = std::move(Replay)]() { Replay(*Snapshot); }); + return true; +} + +void MachinePassInstrumentation::beginBuffering(BufferedEvents &Buffer, + const TargetDescription &Target) const noexcept { + Buffer.Target = &Target; + Buffer.Events.clear(); + ActiveBuffer = &Buffer; +} + +void MachinePassInstrumentation::endBuffering() const noexcept { + ActiveBuffer = nullptr; +} + +void MachinePassInstrumentation::replayBufferedEvents(BufferedEvents &Buffer) const { + for (const std::function &Event : Buffer.Events) + Event(); + Buffer.Events.clear(); + Buffer.Target = nullptr; +} + +void MachinePassInstrumentation::before(std::string_view Name, + const MachineFunction &Function) const { + if (bufferFunctionEvent(Function, [this, Name = std::string(Name)](const MachineFunction &Input) { + before(Name, Input); + })) { + return; + } + std::vector Callbacks; + std::vector Printers; + { + std::scoped_lock Lock(Mutex); + Callbacks = Before; + Printers = IRPrint; + } + for (const BeforeCallback &Callback : Callbacks) + Callback(Name, Function); + for (const IRPrintCallback &Printer : Printers) + Printer(InstrumentationPhase::Before, Name, Function); +} + +void MachinePassInstrumentation::after(std::string_view Name, const MachineFunction &Function, + const MachinePassResult &Result, + std::uint64_t Nanoseconds) const { + if (bufferFunctionEvent(Function, [this, Name = std::string(Name), Result, + Nanoseconds](const MachineFunction &Input) { + after(Name, Input, Result, Nanoseconds); + })) { + return; + } + std::vector Callbacks; + std::vector Printers; + { + std::scoped_lock Lock(Mutex); + InstrumentationStatistic &Record = statistic(Name, false); + ++Record.Invocations; + Record.Changes += Result.Changed ? 1U : 0U; + Record.TotalNanoseconds += Nanoseconds; + Callbacks = After; + Printers = IRPrint; + } + for (const AfterCallback &Callback : Callbacks) + Callback(Name, Function, Result); + for (const IRPrintCallback &Printer : Printers) + Printer(InstrumentationPhase::After, Name, Function); +} + +void MachinePassInstrumentation::failure(std::string_view Name, const MachineFunction &Function, + const Error &ErrorValue, std::uint64_t Nanoseconds) const { + if (bufferFunctionEvent(Function, [this, Name = std::string(Name), ErrorValue, + Nanoseconds](const MachineFunction &Input) { + failure(Name, Input, ErrorValue, Nanoseconds); + })) { + return; + } + std::vector Callbacks; + { + std::scoped_lock Lock(Mutex); + InstrumentationStatistic &Record = statistic(Name, false); + ++Record.Invocations; + ++Record.Failures; + Record.TotalNanoseconds += Nanoseconds; + Callbacks = Failure; + } + for (const FailureCallback &Callback : Callbacks) + Callback(Name, Function, ErrorValue); +} + +void MachinePassInstrumentation::beforeAnalysis(std::string_view Name, + const MachineFunction &Function) const { + if (bufferFunctionEvent(Function, [this, Name = std::string(Name)](const MachineFunction &Input) { + beforeAnalysis(Name, Input); + })) { + return; + } + std::vector Callbacks; + { + std::scoped_lock Lock(Mutex); + Callbacks = BeforeAnalysis; + } + for (const BeforeAnalysisCallback &Callback : Callbacks) + Callback(Name, Function); +} + +void MachinePassInstrumentation::afterAnalysis(std::string_view Name, + const MachineFunction &Function, bool CacheHit, + std::uint64_t Nanoseconds) const { + if (bufferFunctionEvent(Function, [this, Name = std::string(Name), CacheHit, + Nanoseconds](const MachineFunction &Input) { + afterAnalysis(Name, Input, CacheHit, Nanoseconds); + })) { + return; + } + std::vector Callbacks; + { + std::scoped_lock Lock(Mutex); + InstrumentationStatistic &Record = statistic(Name, true); + ++Record.Invocations; + Record.CacheHits += CacheHit ? 1U : 0U; + Record.TotalNanoseconds += Nanoseconds; + Callbacks = AfterAnalysis; + } + for (const AfterAnalysisCallback &Callback : Callbacks) + Callback(Name, Function, CacheHit, Nanoseconds); +} + +void MachinePassInstrumentation::analysisFailure(std::string_view Name, + const MachineFunction &Function, + const Error &ErrorValue, + std::uint64_t Nanoseconds) const { + if (bufferFunctionEvent(Function, [this, Name = std::string(Name), ErrorValue, + Nanoseconds](const MachineFunction &Input) { + analysisFailure(Name, Input, ErrorValue, Nanoseconds); + })) { + return; + } + std::vector Callbacks; + { + std::scoped_lock Lock(Mutex); + InstrumentationStatistic &Record = statistic(Name, true); + ++Record.Invocations; + ++Record.Failures; + Record.TotalNanoseconds += Nanoseconds; + Callbacks = AnalysisFailure; + } + for (const AnalysisFailureCallback &Callback : Callbacks) + Callback(Name, Function, ErrorValue); +} + +void MachinePassInstrumentation::change(std::string_view Name, const MachineFunction &Function, + MachinePassChanges Changes, bool FingerprintChanged) const { + if (bufferFunctionEvent(Function, [this, Name = std::string(Name), Changes, + FingerprintChanged](const MachineFunction &Input) { + change(Name, Input, Changes, FingerprintChanged); + })) { + return; + } + std::vector Callbacks; + { + std::scoped_lock Lock(Mutex); + Callbacks = Change; + } + for (const ChangeCallback &Callback : Callbacks) + Callback(Name, Function, Changes, FingerprintChanged); +} + +Expected MachinePassInstrumentation::requestAction(std::string_view Pass, + std::string_view Rule, + const MachineFunction &Function, + MachineInstrStableID Instruction, + std::uint64_t Cost) { + MachineActionID Action{ + .Pass = std::string(Pass), + .Rule = std::string(Rule), + .Function = Function.stableID(), + .Instruction = Instruction, + }; + if (Action.Pass.empty() || Action.Rule.empty() || Action.Function != Function.stableID() || + Cost == 0) { + return makeUnexpected(ErrorCode::InvalidArgument, "machine action identity is invalid"); + } + std::scoped_lock ActionLock(ActionMutex); + ActionFilter CurrentFilter; + { + std::scoped_lock Lock(Mutex); + CurrentFilter = Filter; + } + if (CurrentFilter && !CurrentFilter(Action, Cost)) { + std::scoped_lock Lock(Mutex); + ActionEvents.push_back({Action, Cost, false}); + return false; + } + + std::scoped_lock Lock(Mutex); + if (!PerFunctionFuel) { + ActionEvents.push_back({Action, Cost, true}); + return true; + } + std::uint64_t &Consumed = ConsumedFuel[Function.stableID().value()]; + if (Consumed > *PerFunctionFuel || Cost > *PerFunctionFuel - Consumed) { + ActionEvents.push_back({Action, Cost, false}); + return false; + } + Consumed += Cost; + ActionEvents.push_back({Action, Cost, true}); + return true; +} + +Expected MachinePassInstrumentation::requestAction(std::string_view Pass, + std::string_view Rule, + const MachineFunction &Function, + std::nullptr_t, std::uint64_t Cost) { + return requestAction(Pass, Rule, Function, MachineInstrStableID{}, Cost); +} + +void MachinePassInstrumentation::beforeUnit(std::string_view Name, + const CompilationUnit &Unit) const { + std::vector Callbacks; + { + std::scoped_lock Lock(Mutex); + Callbacks = BeforeUnit; + } + for (const BeforeUnitCallback &Callback : Callbacks) + Callback(Name, Unit); +} + +void MachinePassInstrumentation::afterUnit(std::string_view Name, const CompilationUnit &Unit, + const CompilationUnitPassResult &Result, + std::uint64_t Nanoseconds) const { + std::vector Callbacks; + { + std::scoped_lock Lock(Mutex); + InstrumentationStatistic &Record = statistic("unit:" + std::string(Name), false); + ++Record.Invocations; + Record.Changes += Result.Changed ? 1U : 0U; + Record.TotalNanoseconds += Nanoseconds; + Callbacks = AfterUnit; + } + for (const AfterUnitCallback &Callback : Callbacks) + Callback(Name, Unit, Result); +} + +void MachinePassInstrumentation::unitFailure(std::string_view Name, const CompilationUnit &Unit, + const Error &ErrorValue, + std::uint64_t Nanoseconds) const { + std::vector Callbacks; + { + std::scoped_lock Lock(Mutex); + InstrumentationStatistic &Record = statistic("unit:" + std::string(Name), false); + ++Record.Invocations; + ++Record.Failures; + Record.TotalNanoseconds += Nanoseconds; + Callbacks = UnitFailure; + } + for (const UnitFailureCallback &Callback : Callbacks) + Callback(Name, Unit, ErrorValue); +} + +void MachinePassInstrumentation::beforeAnalysis(std::string_view Name, + const CompilationUnit &Unit) const { + std::vector Callbacks; + { + std::scoped_lock Lock(Mutex); + Callbacks = BeforeUnitAnalysis; + } + for (const BeforeUnitAnalysisCallback &Callback : Callbacks) + Callback(Name, Unit); +} + +void MachinePassInstrumentation::afterAnalysis(std::string_view Name, const CompilationUnit &Unit, + bool CacheHit, std::uint64_t Nanoseconds) const { + std::vector Callbacks; + { + std::scoped_lock Lock(Mutex); + InstrumentationStatistic &Record = statistic("unit:" + std::string(Name), true); + ++Record.Invocations; + Record.CacheHits += CacheHit ? 1U : 0U; + Record.TotalNanoseconds += Nanoseconds; + Callbacks = AfterUnitAnalysis; + } + for (const AfterUnitAnalysisCallback &Callback : Callbacks) + Callback(Name, Unit, CacheHit, Nanoseconds); +} + +void MachinePassInstrumentation::analysisFailure(std::string_view Name, const CompilationUnit &Unit, + const Error &ErrorValue, + std::uint64_t Nanoseconds) const { + std::vector Callbacks; + { + std::scoped_lock Lock(Mutex); + InstrumentationStatistic &Record = statistic("unit:" + std::string(Name), true); + ++Record.Invocations; + ++Record.Failures; + Record.TotalNanoseconds += Nanoseconds; + Callbacks = UnitAnalysisFailure; + } + for (const UnitAnalysisFailureCallback &Callback : Callbacks) + Callback(Name, Unit, ErrorValue); +} + +std::vector MachinePassInstrumentation::statistics() const { + std::vector Result; + { + std::scoped_lock Lock(Mutex); + Result.reserve(Statistics.size()); + for (const auto &[Key, Record] : Statistics) { + (void)Key; + Result.push_back(Record); + } + } + std::ranges::sort( + Result, [](const InstrumentationStatistic &Left, const InstrumentationStatistic &Right) { + if (Left.IsAnalysis != Right.IsAnalysis) + return Left.IsAnalysis < Right.IsAnalysis; + return Left.Name < Right.Name; + }); + return Result; +} + +std::vector MachinePassInstrumentation::actionEvents() const { + std::vector Result; + { + std::scoped_lock Lock(Mutex); + Result = ActionEvents; + } + std::ranges::sort(Result, [](const MachineActionEvent &Left, const MachineActionEvent &Right) { + if (Left.ID.Function.value() != Right.ID.Function.value()) + return Left.ID.Function.value() < Right.ID.Function.value(); + if (Left.ID.Instruction.value() != Right.ID.Instruction.value()) + return Left.ID.Instruction.value() < Right.ID.Instruction.value(); + if (Left.ID.Pass != Right.ID.Pass) + return Left.ID.Pass < Right.ID.Pass; + if (Left.ID.Rule != Right.ID.Rule) + return Left.ID.Rule < Right.ID.Rule; + if (Left.Cost != Right.Cost) + return Left.Cost < Right.Cost; + return Left.Accepted < Right.Accepted; + }); + return Result; +} + +Expected +PassManagerCallbacks::validate( + const MachineFunctionPass &Pass) { + const MachinePassContract &Contract = Pass.contract(); + if (Contract.Name.empty()) + return makeUnexpected(ErrorCode::InvalidArgument, "machine pass must have a non-empty name"); + if (Contract.Sets.intersects(Contract.Clears)) { + return makeUnexpected(ErrorCode::InvalidArgument, + "machine pass cannot set and clear the same property"); + } + if (hasDuplicateAnalysisIDs(Contract.RequiredAnalyses)) { + return makeUnexpected(ErrorCode::InvalidArgument, + "machine pass required analyses must be non-null and unique"); + } + return validateParameters(Contract.Parameters); +} + +Expected +PassManagerCallbacks::run( + const PassList &Passes, const MachinePassManagerOptions &Options, MachineFunction &Function, + const TargetDescription &Target, MachineFunctionAnalysisManager &Analyses, + MachinePassInstrumentation *Instrumentation) { + Analyses.setInstrumentation(Instrumentation); + for (const std::unique_ptr &Pass : Passes) { + const MachinePassContract &Contract = Pass->contract(); + const std::string_view Name = Contract.Name; + + if (const MachineFunctionProperties Missing = + Contract.Requires.missingFrom(Function.properties()); + !Missing.empty()) { + Error Failure(ErrorCode::VerificationError, + "pass '" + std::string(Name) + "' requires properties: " + Missing.toString()); + if (Instrumentation != nullptr) + Instrumentation->failure(Name, Function, Failure); + Analyses.setInstrumentation(nullptr); + return std::unexpected(std::move(Failure)); + } + + if (Options.VerifyBefore) { + auto Verification = MachineVerifier::verify(Function, Target); + if (!Verification) { + Error Failure = prefixedError(Verification.error(), "pass '" + std::string(Name) + + "' received invalid MachineIR: "); + if (Instrumentation != nullptr) + Instrumentation->failure(Name, Function, Failure); + Analyses.setInstrumentation(nullptr); + return std::unexpected(std::move(Failure)); + } + } + + for (const AnalysisID Required : Contract.RequiredAnalyses) { + auto Result = Analyses.getResultByID(Required, Function, Target); + if (!Result) { + Error Failure = + prefixedError(Result.error(), "pass '" + std::string(Name) + + "' could not materialize a required analysis: "); + if (Instrumentation != nullptr) + Instrumentation->failure(Name, Function, Failure); + Analyses.setInstrumentation(nullptr); + return std::unexpected(std::move(Failure)); + } + } + + const std::uint64_t FingerprintBefore = + Options.DetectUnreportedChanges ? machineFunctionFingerprint(Function) : 0; + if (Instrumentation != nullptr) + Instrumentation->before(Name, Function); + const Clock::time_point Start = Clock::now(); + Analyses.setActivePass(std::string(Name)); + auto PassResult = Pass->run(Function, Target, Analyses); + Analyses.setActivePass({}); + const std::uint64_t Duration = elapsedNanoseconds(Start); + if (!PassResult) { + Error Failure = + prefixedError(PassResult.error(), "pass '" + std::string(Name) + "' failed: "); + if (Instrumentation != nullptr) + Instrumentation->failure(Name, Function, Failure, Duration); + Analyses.clear(Function); + Analyses.setInstrumentation(nullptr); + return std::unexpected(std::move(Failure)); + } + + if (PassResult->Changed != !PassResult->Changes.empty()) { + Error Failure(ErrorCode::VerificationError, + "pass '" + std::string(Name) + + "' reported inconsistent changed state and modification categories"); + if (Instrumentation != nullptr) + Instrumentation->failure(Name, Function, Failure, Duration); + Analyses.clear(Function); + Analyses.setInstrumentation(nullptr); + return std::unexpected(std::move(Failure)); + } + if (!Contract.DeclaredChanges.contains(PassResult->Changes)) { + Error Failure(ErrorCode::VerificationError, + "pass '" + std::string(Name) + + "' reported a modification category absent from its registration"); + if (Instrumentation != nullptr) + Instrumentation->failure(Name, Function, Failure, Duration); + Analyses.clear(Function); + Analyses.setInstrumentation(nullptr); + return std::unexpected(std::move(Failure)); + } + + bool FingerprintChanged = PassResult->Changed; + if (Options.DetectUnreportedChanges) { + FingerprintChanged = FingerprintBefore != machineFunctionFingerprint(Function); + if (FingerprintChanged && !PassResult->Changed) { + Error Failure(ErrorCode::VerificationError, + "pass '" + std::string(Name) + + "' changed MachineIR without reporting a modification"); + if (Instrumentation != nullptr) + Instrumentation->failure(Name, Function, Failure, Duration); + Analyses.clear(Function); + Analyses.setInstrumentation(nullptr); + return std::unexpected(std::move(Failure)); + } + } + if (Instrumentation != nullptr) + Instrumentation->change(Name, Function, PassResult->Changes, FingerprintChanged); + + auto Transition = + Function.properties().applyTransition(Contract.Requires, Contract.Sets, Contract.Clears); + if (!Transition) { + Error Failure = + prefixedError(Transition.error(), "pass '" + std::string(Name) + + "' produced an invalid property transition: "); + if (Instrumentation != nullptr) + Instrumentation->failure(Name, Function, Failure, Duration); + Analyses.clear(Function); + Analyses.setInstrumentation(nullptr); + return std::unexpected(std::move(Failure)); + } + Analyses.invalidate(Function, PassResult->Preserved, PassResult->Changes); + + if (Options.VerifyEach) { + MachineVerifierOptions VerifyOptions; + VerifyOptions.Stage = Contract.VerificationStage; + auto Verification = MachineVerifier::verify(Function, Target, VerifyOptions); + if (!Verification) { + Error Failure = prefixedError(Verification.error(), + "pass '" + std::string(Name) + "' left invalid MachineIR: "); + if (Instrumentation != nullptr) + Instrumentation->failure(Name, Function, Failure, Duration); + Analyses.clear(Function); + Analyses.setInstrumentation(nullptr); + return std::unexpected(std::move(Failure)); + } + } + if (Instrumentation != nullptr) + Instrumentation->after(Name, Function, *PassResult, Duration); + } + Analyses.setInstrumentation(nullptr); + return {}; +} + +Expected +PassManagerCallbacks::runFunctions( + const PassList &Passes, const MachinePassManagerOptions &Options, CompilationUnit &Unit, + const TargetDescription &Target, const MachineFunctionAnalysisManager &AnalysisPrototype, + std::size_t ThreadCount, MachinePassInstrumentation *Instrumentation) { + if (ThreadCount == 0) + return makeUnexpected(ErrorCode::InvalidArgument, "machine pass thread count must be nonzero"); + auto UnitVerification = verifyCompilationUnit(Unit, Target); + if (!UnitVerification) + return std::unexpected(UnitVerification.error()); + const std::size_t FunctionCount = Unit.functionCount(); + if (FunctionCount == 0) + return {}; + const std::size_t WorkerCount = std::min(ThreadCount, FunctionCount); + if (WorkerCount > 1) { + for (const std::unique_ptr &Pass : Passes) { + if (Pass->contract().ThreadSafety != PassThreadSafety::ThreadSafe) { + return makeUnexpected(ErrorCode::InvalidArgument, + "parallel machine pipeline contains a pass not marked thread-safe"); + } + auto AnalysisSafety = + AnalysisPrototype.validateParallelRequirements(Pass->contract().RequiredAnalyses); + if (!AnalysisSafety) + return std::unexpected(AnalysisSafety.error()); + } + } + std::vector> Managers; + Managers.reserve(FunctionCount); + for (std::size_t Index = 0; Index < FunctionCount; ++Index) { + auto Manager = AnalysisPrototype.forkEmpty(); + if (!Manager) + return std::unexpected(Manager.error()); + Managers.push_back(std::move(*Manager)); + } + + std::vector> Failures(FunctionCount); + std::vector EventBuffers(FunctionCount); + std::atomic NextFunction = 0; + const auto Worker = [&]() { + while (true) { + const std::size_t Index = NextFunction.fetch_add(1, std::memory_order_relaxed); + if (Index >= FunctionCount) + return; + MachineFunction *Function = Unit.functionAt(Index); + if (Function == nullptr) { + Failures[Index] = Error(ErrorCode::InternalError, + "compilation unit contains a null function during parallel run"); + continue; + } + if (Instrumentation != nullptr) + Instrumentation->beginBuffering(EventBuffers[Index], Target); + auto Result = PassManagerCallbacks::run(Passes, Options, *Function, Target, *Managers[Index], + Instrumentation); + if (Instrumentation != nullptr) + Instrumentation->endBuffering(); + if (!Result) + Failures[Index] = Result.error(); + } + }; + + std::vector Workers; + Workers.reserve(WorkerCount); + for (std::size_t Index = 0; Index < WorkerCount; ++Index) + Workers.emplace_back(Worker); + for (std::thread &WorkerThread : Workers) + WorkerThread.join(); + + for (std::size_t Index = 0; Index < FunctionCount; ++Index) { + if (Instrumentation != nullptr) + Instrumentation->replayBufferedEvents(EventBuffers[Index]); + const auto &Failure = Failures[Index]; + if (Failure) { + return std::unexpected(prefixedError( + *Failure, "function '" + std::string(Unit.functionAt(Index)->name()) + "' failed: ")); + } + } + return {}; +} + +Expected +PassManagerCallbacks::validate(const CompilationUnitPass &Pass) { + const CompilationUnitPassContract &Contract = Pass.contract(); + if (Contract.Name.empty()) { + return makeUnexpected(ErrorCode::InvalidArgument, + "compilation-unit pass must have a non-empty name"); + } + if (hasDuplicateAnalysisIDs(Contract.RequiredAnalyses)) { + return makeUnexpected(ErrorCode::InvalidArgument, + "compilation-unit pass required analyses must be non-null and unique"); + } + auto Parameters = validateParameters(Contract.Parameters); + if (!Parameters) + return std::unexpected(Parameters.error()); + return {}; +} + +Expected +PassManagerCallbacks::run( + const PassList &Passes, const CompilationUnitPassManagerOptions &Options, CompilationUnit &Unit, + const TargetDescription &Target, CompilationUnitAnalysisManager &UnitAnalyses, + MachineFunctionAnalysisManager &FunctionAnalyses, MachinePassInstrumentation *Instrumentation) { + UnitAnalyses.setInstrumentation(Instrumentation); + FunctionAnalyses.setInstrumentation(Instrumentation); + for (const std::unique_ptr &Pass : Passes) { + const CompilationUnitPassContract &Contract = Pass->contract(); + const std::string_view Name = Contract.Name; + + if (Options.VerifyBefore) { + auto Verification = verifyCompilationUnit(Unit, Target); + if (!Verification) { + Error Failure = + prefixedError(Verification.error(), "compilation-unit pass '" + std::string(Name) + + "' received invalid MachineIR: "); + if (Instrumentation != nullptr) + Instrumentation->unitFailure(Name, Unit, Failure); + UnitAnalyses.setInstrumentation(nullptr); + FunctionAnalyses.setInstrumentation(nullptr); + return std::unexpected(std::move(Failure)); + } + } + + for (const AnalysisID Required : Contract.RequiredAnalyses) { + auto Result = UnitAnalyses.getResultByID(Required, Unit, Target); + if (!Result) { + Error Failure = + prefixedError(Result.error(), "compilation-unit pass '" + std::string(Name) + + "' could not materialize a required analysis: "); + if (Instrumentation != nullptr) + Instrumentation->unitFailure(Name, Unit, Failure); + UnitAnalyses.setInstrumentation(nullptr); + FunctionAnalyses.setInstrumentation(nullptr); + return std::unexpected(std::move(Failure)); + } + } + + if (Instrumentation != nullptr) + Instrumentation->beforeUnit(Name, Unit); + const Clock::time_point Start = Clock::now(); + auto Result = Pass->run(Unit, Target, UnitAnalyses, FunctionAnalyses); + const std::uint64_t Duration = elapsedNanoseconds(Start); + if (!Result) { + Error Failure = prefixedError(Result.error(), + "compilation-unit pass '" + std::string(Name) + "' failed: "); + if (Instrumentation != nullptr) + Instrumentation->unitFailure(Name, Unit, Failure, Duration); + UnitAnalyses.clearAll(); + FunctionAnalyses.clearAll(); + UnitAnalyses.setInstrumentation(nullptr); + FunctionAnalyses.setInstrumentation(nullptr); + return std::unexpected(std::move(Failure)); + } + if (Result->Changed != !Result->Changes.empty() || + !Contract.DeclaredChanges.contains(Result->Changes)) { + Error Failure(ErrorCode::VerificationError, + "compilation-unit pass '" + std::string(Name) + + "' reported inconsistent or undeclared modifications"); + if (Instrumentation != nullptr) + Instrumentation->unitFailure(Name, Unit, Failure, Duration); + UnitAnalyses.clearAll(); + FunctionAnalyses.clearAll(); + UnitAnalyses.setInstrumentation(nullptr); + FunctionAnalyses.setInstrumentation(nullptr); + return std::unexpected(std::move(Failure)); + } + + UnitAnalyses.invalidate(Unit, Result->PreservedUnitAnalyses, Result->Changes); + for (std::size_t Index = 0; Index < Unit.functionCount(); ++Index) { + MachineFunction *Function = Unit.functionAt(Index); + if (Function != nullptr) { + FunctionAnalyses.invalidate(*Function, Result->PreservedFunctionAnalyses, Result->Changes); + } + } + if (Options.VerifyEach) { + auto Verification = verifyCompilationUnit(Unit, Target); + if (!Verification) { + Error Failure = + prefixedError(Verification.error(), "compilation-unit pass '" + std::string(Name) + + "' left invalid MachineIR: "); + if (Instrumentation != nullptr) + Instrumentation->unitFailure(Name, Unit, Failure, Duration); + UnitAnalyses.clearAll(); + FunctionAnalyses.clearAll(); + UnitAnalyses.setInstrumentation(nullptr); + FunctionAnalyses.setInstrumentation(nullptr); + return std::unexpected(std::move(Failure)); + } + } + if (Instrumentation != nullptr) + Instrumentation->afterUnit(Name, Unit, *Result, Duration); + } + UnitAnalyses.setInstrumentation(nullptr); + FunctionAnalyses.setInstrumentation(nullptr); + return {}; +} + +} // namespace rcc diff --git a/backend/lib/CodeGen/MachinePseudoExpansion.cpp b/backend/lib/CodeGen/MachinePseudoExpansion.cpp index b5afe8e..663b148 100644 --- a/backend/lib/CodeGen/MachinePseudoExpansion.cpp +++ b/backend/lib/CodeGen/MachinePseudoExpansion.cpp @@ -355,7 +355,8 @@ expandImplementation(MachineFunction &Function, const TargetDescription &Target, [[nodiscard]] Expected runPreparationTransaction(MachineFunction &Function, const TargetDescription &Target, - const TargetPseudoExpansionInfo &Info, MachineAnalysisManager &Analyses) { + const TargetPseudoExpansionInfo &Info, + MachineFunctionAnalysisManager &Analyses) { auto Trial = cloneMachineFunction( Function, Target, MachineFunctionCloneOptions{.NewStableID = Function.stableID(), .NewName = std::nullopt}); @@ -380,7 +381,8 @@ runPreparationTransaction(MachineFunction &Function, const TargetDescription &Ta [[nodiscard]] Expected runExpansionTransaction(MachineFunction &Function, const TargetDescription &Target, const TargetPseudoExpansionInfo &Info, MachinePseudoExpansionPhase Phase, - const TargetInstrInfo *BranchInfo, MachineAnalysisManager &Analyses) { + const TargetInstrInfo *BranchInfo, + MachineFunctionAnalysisManager &Analyses) { auto Trial = cloneMachineFunction( Function, Target, MachineFunctionCloneOptions{.NewStableID = Function.stableID(), .NewName = std::nullopt}); @@ -409,9 +411,9 @@ const MachinePassContract &PreparePostRAPseudosPass::contract() const noexcept { return preparationContract(); } -Expected PreparePostRAPseudosPass::run(MachineFunction &Function, - const TargetDescription &Target, - MachineAnalysisManager &Analyses) { +Expected +PreparePostRAPseudosPass::run(MachineFunction &Function, const TargetDescription &Target, + MachineFunctionAnalysisManager &Analyses) { if (!Function.properties().containsAll(contract().Requires)) return makeUnexpected(ErrorCode::VerificationError, "post-RA pseudo preparation requires selected MachineIR"); @@ -422,9 +424,9 @@ const MachinePassContract &PrePEITargetPseudoExpansionPass::contract() const noe return phaseContract(MachinePseudoExpansionPhase::PrePEI); } -Expected PrePEITargetPseudoExpansionPass::run(MachineFunction &Function, - const TargetDescription &Target, - MachineAnalysisManager &Analyses) { +Expected +PrePEITargetPseudoExpansionPass::run(MachineFunction &Function, const TargetDescription &Target, + MachineFunctionAnalysisManager &Analyses) { if (!Function.properties().containsAll(contract().Requires)) return makeUnexpected(ErrorCode::VerificationError, "pre-PEI pseudo expansion requires allocated tracked-liveness MIR"); @@ -438,7 +440,7 @@ const MachinePassContract &ExpandPostRAPseudosPass::contract() const noexcept { Expected ExpandPostRAPseudosPass::run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses) { + MachineFunctionAnalysisManager &Analyses) { if (!Function.properties().containsAll(contract().Requires)) return makeUnexpected(ErrorCode::VerificationError, "post-RA pseudo expansion requires finalized frame and liveness"); @@ -450,9 +452,9 @@ const MachinePassContract &TargetLatePseudoExpansionPass::contract() const noexc return phaseContract(MachinePseudoExpansionPhase::TargetLate); } -Expected TargetLatePseudoExpansionPass::run(MachineFunction &Function, - const TargetDescription &Target, - MachineAnalysisManager &Analyses) { +Expected +TargetLatePseudoExpansionPass::run(MachineFunction &Function, const TargetDescription &Target, + MachineFunctionAnalysisManager &Analyses) { if (!Function.properties().containsAll(contract().Requires)) return makeUnexpected(ErrorCode::VerificationError, "target-late pseudo expansion requires finalized allocated MIR"); diff --git a/backend/lib/CodeGen/MachineScheduler.cpp b/backend/lib/CodeGen/MachineScheduler.cpp index e589675..82f0c91 100644 --- a/backend/lib/CodeGen/MachineScheduler.cpp +++ b/backend/lib/CodeGen/MachineScheduler.cpp @@ -37,10 +37,11 @@ namespace { MachineFunctionProperty::TiedOpsRewritten}, .Sets = {}, .Clears = {}, - .RequiredAnalyses = {MachineAnalysisManager::id()}, + .RequiredAnalyses = {MachineFunctionAnalysisManager::id()}, .VerificationStage = PipelineStage::TiedOpsRewritten, }; - Value.RequiredAnalyses.push_back(MachineAnalysisManager::id()); + Value.RequiredAnalyses.push_back( + MachineFunctionAnalysisManager::id()); Value.ThreadSafety = PassThreadSafety::ThreadSafe; Value.DeclaredChanges = {MachinePassChange::Instructions, MachinePassChange::Operands}; return Value; @@ -395,7 +396,7 @@ const MachinePassContract &MachineSchedulerPass::contract() const noexcept { Expected MachineSchedulerPass::run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses) { + MachineFunctionAnalysisManager &Analyses) { if (!Function.properties().containsAll(contract().Requires)) { return makeUnexpected(ErrorCode::VerificationError, "pre-RA machine scheduler requires selected, SSA-exited MachineIR"); @@ -407,7 +408,7 @@ Expected MachineSchedulerPass::run(MachineFunction &Function, return std::unexpected( prefixedError(Trial.error(), "machine scheduler transaction setup failed: ")); } - MachineAnalysisManager TrialAnalyses; + MachineFunctionAnalysisManager TrialAnalyses; auto TrialLiveness = TrialAnalyses.getResult(*Trial->ClonedFunction, Target); if (!TrialLiveness) diff --git a/backend/lib/CodeGen/MachineShrinkWrapping.cpp b/backend/lib/CodeGen/MachineShrinkWrapping.cpp index aee3323..7c7bc3a 100644 --- a/backend/lib/CodeGen/MachineShrinkWrapping.cpp +++ b/backend/lib/CodeGen/MachineShrinkWrapping.cpp @@ -32,8 +32,8 @@ namespace { MachineFunctionProperty::TracksLiveness}, .Sets = {}, .Clears = {}, - .RequiredAnalyses = {MachineAnalysisManager::id(), - MachineAnalysisManager::id()}, + .RequiredAnalyses = {MachineFunctionAnalysisManager::id(), + MachineFunctionAnalysisManager::id()}, .VerificationStage = PipelineStage::RegisterAllocated, }; Value.ThreadSafety = PassThreadSafety::ThreadSafe; @@ -66,9 +66,9 @@ const MachinePassContract &MachineShrinkWrappingPass::contract() const noexcept return shrinkWrappingContract(); } -Expected MachineShrinkWrappingPass::run(MachineFunction &Function, - const TargetDescription &Target, - MachineAnalysisManager &Analyses) { +Expected +MachineShrinkWrappingPass::run(MachineFunction &Function, const TargetDescription &Target, + MachineFunctionAnalysisManager &Analyses) { if (!Function.properties().containsAll(contract().Requires)) { return makeUnexpected(ErrorCode::VerificationError, "shrink wrapping requires allocated tracked-liveness MachineIR"); diff --git a/backend/lib/CodeGen/MachineSink.cpp b/backend/lib/CodeGen/MachineSink.cpp index 21b17f8..176b75a 100644 --- a/backend/lib/CodeGen/MachineSink.cpp +++ b/backend/lib/CodeGen/MachineSink.cpp @@ -34,8 +34,8 @@ namespace { .Requires = {MachineFunctionProperty::IsSSA, MachineFunctionProperty::Selected}, .Sets = {}, .Clears = {}, - .RequiredAnalyses = {MachineAnalysisManager::id(), - MachineAnalysisManager::id()}, + .RequiredAnalyses = {MachineFunctionAnalysisManager::id(), + MachineFunctionAnalysisManager::id()}, .VerificationStage = PipelineStage::Selected, }; Value.ThreadSafety = PassThreadSafety::ThreadSafe; @@ -50,8 +50,8 @@ namespace { MachineFunctionProperty::TracksLiveness}, .Sets = {}, .Clears = {}, - .RequiredAnalyses = {MachineAnalysisManager::id(), - MachineAnalysisManager::id()}, + .RequiredAnalyses = {MachineFunctionAnalysisManager::id(), + MachineFunctionAnalysisManager::id()}, .VerificationStage = PipelineStage::RegisterAllocated, }; Value.ThreadSafety = PassThreadSafety::ThreadSafe; @@ -354,7 +354,7 @@ const MachinePassContract &MachineSinkPass::contract() const noexcept { Expected MachineSinkPass::run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses) { + MachineFunctionAnalysisManager &Analyses) { if (!Function.properties().containsAll(contract().Requires)) { return makeUnexpected( ErrorCode::VerificationError, @@ -368,7 +368,7 @@ Expected MachineSinkPass::run(MachineFunction &Function, if (!Trial) { return std::unexpected(prefixedError(Trial.error(), "machine sink transaction setup failed: ")); } - MachineAnalysisManager TrialAnalyses; + MachineFunctionAnalysisManager TrialAnalyses; auto TrialResult = runImplementation(*Trial->ClonedFunction, Target, TrialAnalyses); if (!TrialResult) return std::unexpected(TrialResult.error()); @@ -381,9 +381,9 @@ Expected MachineSinkPass::run(MachineFunction &Function, return Result; } -Expected MachineSinkPass::runImplementation(MachineFunction &Function, - const TargetDescription &Target, - MachineAnalysisManager &Analyses) { +Expected +MachineSinkPass::runImplementation(MachineFunction &Function, const TargetDescription &Target, + MachineFunctionAnalysisManager &Analyses) { auto Dominators = Analyses.getResult(Function, Target); if (!Dominators) return std::unexpected(Dominators.error()); diff --git a/backend/lib/CodeGen/MachineStackSlotColoring.cpp b/backend/lib/CodeGen/MachineStackSlotColoring.cpp index e60a7a2..005872b 100644 --- a/backend/lib/CodeGen/MachineStackSlotColoring.cpp +++ b/backend/lib/CodeGen/MachineStackSlotColoring.cpp @@ -228,7 +228,7 @@ const MachinePassContract &MachineStackSlotColoringPass::contract() const noexce Expected MachineStackSlotColoringPass::run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &) { + MachineFunctionAnalysisManager &) { if (!Function.properties().containsAll(contract().Requires)) { return makeUnexpected(ErrorCode::VerificationError, "stack-slot coloring requires allocated PHI-free MachineIR"); diff --git a/backend/lib/CodeGen/MachineTailDuplication.cpp b/backend/lib/CodeGen/MachineTailDuplication.cpp index 5abd473..8be1eb5 100644 --- a/backend/lib/CodeGen/MachineTailDuplication.cpp +++ b/backend/lib/CodeGen/MachineTailDuplication.cpp @@ -248,7 +248,7 @@ const MachinePassContract &MachineTailDuplicationPass::contract() const noexcept Expected MachineTailDuplicationPass::run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &) { + MachineFunctionAnalysisManager &) { if (!Function.properties().containsAll(contract().Requires)) { return makeUnexpected(ErrorCode::VerificationError, "tail duplication requires finalized allocated tracked-liveness MIR"); diff --git a/backend/lib/CodeGen/MachineTailMerge.cpp b/backend/lib/CodeGen/MachineTailMerge.cpp index c4d6de9..dc07950 100644 --- a/backend/lib/CodeGen/MachineTailMerge.cpp +++ b/backend/lib/CodeGen/MachineTailMerge.cpp @@ -298,7 +298,7 @@ const MachinePassContract &MachineTailMergePass::contract() const noexcept { Expected MachineTailMergePass::run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &) { + MachineFunctionAnalysisManager &) { if (!Function.properties().containsAll(contract().Requires)) { return makeUnexpected(ErrorCode::VerificationError, "tail merge requires finalized allocated tracked-liveness MIR"); diff --git a/backend/lib/CodeGen/PHIElimination.cpp b/backend/lib/CodeGen/PHIElimination.cpp index 75472f2..6de449f 100644 --- a/backend/lib/CodeGen/PHIElimination.cpp +++ b/backend/lib/CodeGen/PHIElimination.cpp @@ -490,7 +490,7 @@ const MachinePassContract &PHIEliminationPass::contract() const noexcept { Expected PHIEliminationPass::run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses) { + MachineFunctionAnalysisManager &Analyses) { auto Required = requireProperties(Function, contract()); if (!Required) return std::unexpected(Required.error()); diff --git a/backend/lib/CodeGen/PostRAScheduler.cpp b/backend/lib/CodeGen/PostRAScheduler.cpp index f7d6181..b5f7ae9 100644 --- a/backend/lib/CodeGen/PostRAScheduler.cpp +++ b/backend/lib/CodeGen/PostRAScheduler.cpp @@ -37,10 +37,11 @@ namespace { MachineFunctionProperty::TracksLiveness}, .Sets = {}, .Clears = {}, - .RequiredAnalyses = {MachineAnalysisManager::id()}, + .RequiredAnalyses = {MachineFunctionAnalysisManager::id()}, .VerificationStage = PipelineStage::RegisterAllocated, }; - Value.RequiredAnalyses.push_back(MachineAnalysisManager::id()); + Value.RequiredAnalyses.push_back( + MachineFunctionAnalysisManager::id()); Value.ThreadSafety = PassThreadSafety::ThreadSafe; Value.DeclaredChanges = {MachinePassChange::Instructions, MachinePassChange::Operands}; return Value; @@ -61,7 +62,7 @@ const MachinePassContract &PostRASchedulerPass::contract() const noexcept { Expected PostRASchedulerPass::run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses) { + MachineFunctionAnalysisManager &Analyses) { if (!Function.properties().containsAll(contract().Requires)) { return makeUnexpected(ErrorCode::VerificationError, "post-RA scheduler requires allocated tracked-liveness MachineIR"); @@ -73,7 +74,7 @@ Expected PostRASchedulerPass::run(MachineFunction &Function, return std::unexpected( prefixedError(Trial.error(), "post-RA scheduler transaction setup failed: ")); } - MachineAnalysisManager TrialAnalyses; + MachineFunctionAnalysisManager TrialAnalyses; auto TrialLiveness = TrialAnalyses.getResult(*Trial->ClonedFunction, Target); if (!TrialLiveness) diff --git a/backend/lib/CodeGen/PrologueEpilogueInsertion.cpp b/backend/lib/CodeGen/PrologueEpilogueInsertion.cpp index 47b74f6..c935d6a 100644 --- a/backend/lib/CodeGen/PrologueEpilogueInsertion.cpp +++ b/backend/lib/CodeGen/PrologueEpilogueInsertion.cpp @@ -49,7 +49,7 @@ const MachinePassContract &PrologueEpilogueInsertionPass::contract() const noexc Expected PrologueEpilogueInsertionPass::run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &) { + MachineFunctionAnalysisManager &) { if (Info == nullptr) return makeUnexpected(ErrorCode::InvalidArgument, "PrologueEpilogueInsertion requires target frame lowering"); diff --git a/backend/lib/CodeGen/RegAllocBase.h b/backend/lib/CodeGen/RegAllocBase.h index 318a82d..4ef0bb7 100644 --- a/backend/lib/CodeGen/RegAllocBase.h +++ b/backend/lib/CodeGen/RegAllocBase.h @@ -27,8 +27,9 @@ public: protected: RegAllocBase(MachineFunction &Function, const TargetDescription &Target, - const TargetRegisterAllocationInfo &TargetInfo, MachineAnalysisManager &Analyses, - RegisterAllocationOptions Options, MachineActionReplay *Actions = nullptr) noexcept + const TargetRegisterAllocationInfo &TargetInfo, + MachineFunctionAnalysisManager &Analyses, RegisterAllocationOptions Options, + MachineActionReplay *Actions = nullptr) noexcept : Function(Function), Target(Target), TargetInfo(TargetInfo), Analyses(Analyses), Options(Options), Actions(Actions) {} @@ -38,7 +39,7 @@ protected: MachineFunction &Function; const TargetDescription &Target; const TargetRegisterAllocationInfo &TargetInfo; - MachineAnalysisManager &Analyses; + MachineFunctionAnalysisManager &Analyses; RegisterAllocationOptions Options; MachineActionReplay *Actions = nullptr; }; diff --git a/backend/lib/CodeGen/RegAllocBasic.cpp b/backend/lib/CodeGen/RegAllocBasic.cpp index 9d14d15..7f730ca 100644 --- a/backend/lib/CodeGen/RegAllocBasic.cpp +++ b/backend/lib/CodeGen/RegAllocBasic.cpp @@ -18,7 +18,7 @@ class BasicAllocatorEngine final : public RegAllocBase { public: BasicAllocatorEngine(MachineFunction &Function, const TargetDescription &Target, const TargetRegisterAllocationInfo &TargetInfo, - MachineAnalysisManager &Analyses, RegisterAllocationOptions Options) + MachineFunctionAnalysisManager &Analyses, RegisterAllocationOptions Options) : RegAllocBase(Function, Target, TargetInfo, Analyses, Options) {} private: @@ -80,7 +80,7 @@ private: MachineFunctionProperty::TracksLiveness}, .Sets = {MachineFunctionProperty::NoVRegs}, .Clears = {}, - .RequiredAnalyses = {MachineAnalysisManager::id()}, + .RequiredAnalyses = {MachineFunctionAnalysisManager::id()}, .VerificationStage = PipelineStage::RegisterAllocated, }; Value.ThreadSafety = PassThreadSafety::ThreadSafe; @@ -97,7 +97,7 @@ const MachinePassContract &BasicAllocatorPass::contract() const noexcept { Expected BasicAllocatorPass::run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses) { + MachineFunctionAnalysisManager &Analyses) { if (Info == nullptr) return makeUnexpected(ErrorCode::InvalidArgument, "BasicAllocator requires target behavior"); auto Required = regalloc_detail::requireAllocationProperties(Function, contract()); @@ -112,7 +112,7 @@ Expected BasicAllocatorPass::run(MachineFunction &Function, regalloc_detail::reserveFunctionRegisters(*Trial->ClonedFunction, FunctionReserved); if (!TrialReserved) return std::unexpected(TrialReserved.error()); - MachineAnalysisManager TrialAnalyses; + MachineFunctionAnalysisManager TrialAnalyses; auto Registered = registerStage11MachineAnalyses(TrialAnalyses); if (!Registered) return std::unexpected(Registered.error()); diff --git a/backend/lib/CodeGen/RegAllocBasic.h b/backend/lib/CodeGen/RegAllocBasic.h index 8a68f5f..f88c977 100644 --- a/backend/lib/CodeGen/RegAllocBasic.h +++ b/backend/lib/CodeGen/RegAllocBasic.h @@ -19,7 +19,7 @@ public: [[nodiscard]] const MachinePassContract &contract() const noexcept override; [[nodiscard]] Expected run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses) override; + MachineFunctionAnalysisManager &Analyses) override; private: const TargetRegisterAllocationInfo *Info; diff --git a/backend/lib/CodeGen/RegAllocFast.cpp b/backend/lib/CodeGen/RegAllocFast.cpp index 1399f10..73c3e1a 100644 --- a/backend/lib/CodeGen/RegAllocFast.cpp +++ b/backend/lib/CodeGen/RegAllocFast.cpp @@ -557,7 +557,7 @@ const MachinePassContract &FastAllocatorPass::contract() const noexcept { MachineFunctionProperty::TracksLiveness}, .Sets = {MachineFunctionProperty::NoVRegs}, .Clears = {}, - .RequiredAnalyses = {MachineAnalysisManager::id()}, + .RequiredAnalyses = {MachineFunctionAnalysisManager::id()}, .VerificationStage = PipelineStage::RegisterAllocated, }; Value.ThreadSafety = PassThreadSafety::ThreadSafe; @@ -568,7 +568,7 @@ const MachinePassContract &FastAllocatorPass::contract() const noexcept { Expected FastAllocatorPass::run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses) { + MachineFunctionAnalysisManager &Analyses) { if (Info == nullptr) return makeUnexpected(ErrorCode::InvalidArgument, "FastAllocator requires target behavior"); auto Required = regalloc_detail::requireAllocationProperties(Function, contract()); @@ -583,7 +583,7 @@ Expected FastAllocatorPass::run(MachineFunction &Function, regalloc_detail::reserveFunctionRegisters(*Trial->ClonedFunction, FunctionReserved); if (!TrialReserved) return std::unexpected(TrialReserved.error()); - MachineAnalysisManager TrialAnalyses; + MachineFunctionAnalysisManager TrialAnalyses; auto Registered = registerStage11MachineAnalyses(TrialAnalyses); if (!Registered) return std::unexpected(Registered.error()); diff --git a/backend/lib/CodeGen/RegAllocPBQP.cpp b/backend/lib/CodeGen/RegAllocPBQP.cpp index 3b0e684..6706cd5 100644 --- a/backend/lib/CodeGen/RegAllocPBQP.cpp +++ b/backend/lib/CodeGen/RegAllocPBQP.cpp @@ -86,7 +86,7 @@ class PBQPAllocatorEngine final : public RegAllocBase { public: PBQPAllocatorEngine(MachineFunction &Function, const TargetDescription &Target, const TargetRegisterAllocationInfo &TargetInfo, - MachineAnalysisManager &Analyses, RegisterAllocationOptions Options, + MachineFunctionAnalysisManager &Analyses, RegisterAllocationOptions Options, MachineActionReplay *Actions) : RegAllocBase(Function, Target, TargetInfo, Analyses, Options, Actions) {} @@ -277,7 +277,7 @@ private: MachineFunctionProperty::TracksLiveness}, .Sets = {MachineFunctionProperty::NoVRegs}, .Clears = {}, - .RequiredAnalyses = {MachineAnalysisManager::id()}, + .RequiredAnalyses = {MachineFunctionAnalysisManager::id()}, .VerificationStage = PipelineStage::RegisterAllocated, }; Value.ThreadSafety = PassThreadSafety::ThreadSafe; @@ -294,7 +294,7 @@ const MachinePassContract &PBQPAllocatorPass::contract() const noexcept { Expected PBQPAllocatorPass::run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses) { + MachineFunctionAnalysisManager &Analyses) { if (Info == nullptr) return makeUnexpected(ErrorCode::InvalidArgument, "PBQPAllocator requires target behavior"); auto Required = regalloc_detail::requireAllocationProperties(Function, contract()); @@ -309,7 +309,7 @@ Expected PBQPAllocatorPass::run(MachineFunction &Function, regalloc_detail::reserveFunctionRegisters(*Trial->ClonedFunction, FunctionReserved); if (!TrialReserved) return std::unexpected(TrialReserved.error()); - MachineAnalysisManager TrialAnalyses; + MachineFunctionAnalysisManager TrialAnalyses; auto Registered = registerStage11MachineAnalyses(TrialAnalyses); if (!Registered) return std::unexpected(Registered.error()); diff --git a/backend/lib/CodeGen/SlotIndexes.cpp b/backend/lib/CodeGen/SlotIndexes.cpp index 57e35b5..4fe753a 100644 --- a/backend/lib/CodeGen/SlotIndexes.cpp +++ b/backend/lib/CodeGen/SlotIndexes.cpp @@ -143,12 +143,12 @@ Expected SlotIndexesAnalysis::Result::renumber(MachineFunction &Function) bool SlotIndexesAnalysis::Result::invalidate(const MachineFunction &, const PreservedAnalyses &Preserved) const noexcept { - return !Preserved.preserves(MachineAnalysisManager::id()); + return !Preserved.preserves(MachineFunctionAnalysisManager::id()); } Expected SlotIndexesAnalysis::run(MachineFunction &Function, const TargetDescription &, - MachineAnalysisManager &) { + MachineFunctionAnalysisManager &) { Result ResultValue; auto Numbered = ResultValue.renumber(Function); if (!Numbered) diff --git a/backend/lib/CodeGen/TwoAddressInstructionPass.cpp b/backend/lib/CodeGen/TwoAddressInstructionPass.cpp index be4db82..b6f2a25 100644 --- a/backend/lib/CodeGen/TwoAddressInstructionPass.cpp +++ b/backend/lib/CodeGen/TwoAddressInstructionPass.cpp @@ -459,9 +459,9 @@ const MachinePassContract &TwoAddressInstructionPass::contract() const noexcept return Contract; } -Expected TwoAddressInstructionPass::run(MachineFunction &Function, - const TargetDescription &Target, - MachineAnalysisManager &Analyses) { +Expected +TwoAddressInstructionPass::run(MachineFunction &Function, const TargetDescription &Target, + MachineFunctionAnalysisManager &Analyses) { auto Required = requireProperties(Function, contract()); if (!Required) return std::unexpected(Required.error()); diff --git a/backend/lib/CodeGen/VirtRegMap.cpp b/backend/lib/CodeGen/VirtRegMap.cpp index a55a486..4f3ae45 100644 --- a/backend/lib/CodeGen/VirtRegMap.cpp +++ b/backend/lib/CodeGen/VirtRegMap.cpp @@ -169,7 +169,7 @@ Expected rewriteVirtualRegisters(MachineFunction &Function, const TargetDe if (!MappingVerification) return std::unexpected(MappingVerification.error()); - MachineAnalysisManager ValidationAnalyses; + MachineFunctionAnalysisManager ValidationAnalyses; auto Registered = registerStage11MachineAnalyses(ValidationAnalyses); if (!Registered) return std::unexpected(Registered.error()); @@ -282,7 +282,7 @@ const MachinePassContract &VirtualRegisterRewritePass::contract() const noexcept Expected VirtualRegisterRewritePass::run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &) { + MachineFunctionAnalysisManager &) { if (Mapping == nullptr) return makeUnexpected(ErrorCode::InvalidArgument, "VirtualRegisterRewrite requires a VirtRegMap"); diff --git a/backend/lib/Target/RISCV/RISCVPipeline.cpp b/backend/lib/Target/RISCV/RISCVPipeline.cpp index c5601ef..60f798c 100644 --- a/backend/lib/Target/RISCV/RISCVPipeline.cpp +++ b/backend/lib/Target/RISCV/RISCVPipeline.cpp @@ -27,11 +27,12 @@ namespace rcc::riscv { namespace { template -[[nodiscard]] Expected addPass(MachinePassManager &Pipeline, ArgumentT &&...Arguments) { +[[nodiscard]] Expected addPass(MachineFunctionPassManager &Pipeline, + ArgumentT &&...Arguments) { return Pipeline.addPass(std::make_unique(std::forward(Arguments)...)); } -[[nodiscard]] Expected addInitialPipeline(MachinePassManager &Pipeline, +[[nodiscard]] Expected addInitialPipeline(MachineFunctionPassManager &Pipeline, const RISCVSubtarget &Subtarget) { auto Added = addPass(Pipeline, machineCombinerInfo(), MachineCombinerStage::PreLegalizer); @@ -46,7 +47,7 @@ template return addPass(Pipeline, Subtarget.getInstructionSelector()); } -[[nodiscard]] Expected addSSAExitPipeline(MachinePassManager &Pipeline) { +[[nodiscard]] Expected addSSAExitPipeline(MachineFunctionPassManager &Pipeline) { auto Added = addSelectedSSAOptimizationPipeline(Pipeline, optimizationPipelineInfo()); if (!Added) return std::unexpected(Added.error()); @@ -56,14 +57,14 @@ template return addPass(Pipeline, instrInfo()); } -[[nodiscard]] Expected addRegisterAllocationPipeline(MachinePassManager &Pipeline) { +[[nodiscard]] Expected addRegisterAllocationPipeline(MachineFunctionPassManager &Pipeline) { auto Added = addPreRegisterAllocationOptimizationPipeline(Pipeline, optimizationPipelineInfo()); if (!Added) return std::unexpected(Added.error()); return addPass(Pipeline, registerAllocationInfo()); } -[[nodiscard]] Expected addCompleteRegistry(MachinePassManager &Pipeline, +[[nodiscard]] Expected addCompleteRegistry(MachineFunctionPassManager &Pipeline, const RISCVSubtarget &Subtarget) { auto Added = addInitialPipeline(Pipeline, Subtarget); if (!Added) @@ -79,7 +80,8 @@ template } // namespace -Expected addCanonicalPipeline(MachinePassManager &Pipeline, const MachineFunction &Function, +Expected addCanonicalPipeline(MachineFunctionPassManager &Pipeline, + const MachineFunction &Function, const RISCVSubtarget &Subtarget) { if (!Function.properties().has(MachineFunctionProperty::Legalized)) { auto Added = addPass(Pipeline, machineCombinerInfo(), @@ -132,11 +134,11 @@ Expected> createCanonicalPipelinePass(std::string_view Name, const RISCVSubtarget &Subtarget) { if (Name.empty()) return makeUnexpected(ErrorCode::InvalidArgument, "pipeline pass name cannot be empty"); - MachinePassManager Registry; + MachineFunctionPassManager Registry; auto Added = addCompleteRegistry(Registry, Subtarget); if (!Added) return std::unexpected(Added.error()); - MachinePassManager::PassList Passes = std::move(Registry).takePasses(); + MachineFunctionPassManager::PassList Passes = std::move(Registry).takePasses(); auto Position = std::ranges::find_if(Passes, [Name](const auto &Pass) { return Pass != nullptr && Pass->contract().Name == Name; }); @@ -149,11 +151,11 @@ createCanonicalPipelinePass(std::string_view Name, const RISCVSubtarget &Subtarg Expected> canonicalPipelinePassNames(const MachineFunction &Function, const RISCVSubtarget &Subtarget) { - MachinePassManager Pipeline; + MachineFunctionPassManager Pipeline; auto Added = addCanonicalPipeline(Pipeline, Function, Subtarget); if (!Added) return std::unexpected(Added.error()); - MachinePassManager::PassList Passes = std::move(Pipeline).takePasses(); + MachineFunctionPassManager::PassList Passes = std::move(Pipeline).takePasses(); std::vector Result; Result.reserve(Passes.size()); for (const std::unique_ptr &Pass : Passes) { diff --git a/backend/lib/Tooling/PipelineDriver.cpp b/backend/lib/Tooling/PipelineDriver.cpp index 495842a..d7a7d16 100644 --- a/backend/lib/Tooling/PipelineDriver.cpp +++ b/backend/lib/Tooling/PipelineDriver.cpp @@ -79,10 +79,10 @@ struct FunctionRunResult final { return std::nullopt; } -[[nodiscard]] Expected +[[nodiscard]] Expected createPasses(const MachineFunction &Function, const BackendInvocation &Invocation, const riscv::RISCVSubtarget &Subtarget, MachinePassManagerOptions Options) { - MachinePassManager Pipeline(Options); + MachineFunctionPassManager Pipeline(Options); if (Invocation.PassPipeline.size() == 1 && Invocation.PassPipeline.front() == "default") { auto Added = riscv::addCanonicalPipeline(Pipeline, Function, Subtarget); if (!Added) @@ -212,7 +212,7 @@ runFunction(MachineFunction &Function, mir::MIRDocument &Document, const TargetD auto Passes = createPasses(Function, Invocation, Subtarget, ManagerOptions); if (!Passes) return std::unexpected(Passes.error()); - MachineAnalysisManager Analyses; + MachineFunctionAnalysisManager Analyses; auto Registered = registerMachineOptimizationAnalyses(Analyses); if (!Registered) return std::unexpected(Registered.error()); @@ -257,7 +257,7 @@ runFunction(MachineFunction &Function, mir::MIRDocument &Document, const TargetD return std::unexpected(Captured.error()); } - MachinePassManager SinglePass(ManagerOptions); + MachineFunctionPassManager SinglePass(ManagerOptions); auto Added = SinglePass.addPass(std::move(Pass)); if (!Added) return std::unexpected(Added.error()); diff --git a/backend/unittests/CodeGen/CMakeLists.txt b/backend/unittests/CodeGen/CMakeLists.txt index 0715def..ac6ab36 100644 --- a/backend/unittests/CodeGen/CMakeLists.txt +++ b/backend/unittests/CodeGen/CMakeLists.txt @@ -27,7 +27,9 @@ set( MachineMetadataTest.cpp MachineOperandTest.cpp MachineOptimizationTest.cpp - MachinePassTest.cpp + PassManagerTest.cpp + PassInstrumentationTest.cpp + MachinePassManagerTest.cpp MachineSchedulingTest.cpp PBQPTest.cpp RegisterAllocationTest.cpp @@ -343,14 +345,35 @@ add_test( COMMAND RCCBackendCodeGenMachineOperandTests ) -add_executable(RCCBackendCodeGenMachinePassTests MachinePassTest.cpp) -rcc_backend_configure_target(RCCBackendCodeGenMachinePassTests) +add_executable(RCCBackendCodeGenPassManagerTests PassManagerTest.cpp) +rcc_backend_configure_target(RCCBackendCodeGenPassManagerTests) target_link_libraries( - RCCBackendCodeGenMachinePassTests + RCCBackendCodeGenPassManagerTests PRIVATE RCCBackend::CodeGen RCCBackend::TestTarget ) +add_test(NAME RCCBackend.CodeGen.PassManager COMMAND RCCBackendCodeGenPassManagerTests) -add_test(NAME RCCBackend.CodeGen.MachinePass COMMAND RCCBackendCodeGenMachinePassTests) +add_executable(RCCBackendCodeGenPassInstrumentationTests PassInstrumentationTest.cpp) +rcc_backend_configure_target(RCCBackendCodeGenPassInstrumentationTests) +target_link_libraries( + RCCBackendCodeGenPassInstrumentationTests + PRIVATE RCCBackend::CodeGen RCCBackend::TestTarget +) +add_test( + NAME RCCBackend.CodeGen.PassInstrumentation + COMMAND RCCBackendCodeGenPassInstrumentationTests +) + +add_executable(RCCBackendCodeGenMachinePassManagerTests MachinePassManagerTest.cpp) +rcc_backend_configure_target(RCCBackendCodeGenMachinePassManagerTests) +target_link_libraries( + RCCBackendCodeGenMachinePassManagerTests + PRIVATE RCCBackend::CodeGen RCCBackend::TestTarget +) +add_test( + NAME RCCBackend.CodeGen.MachinePassManager + COMMAND RCCBackendCodeGenMachinePassManagerTests +) add_subdirectory(GlobalISel) @@ -495,7 +518,9 @@ rcc_backend_register_format_files( "${CMAKE_CURRENT_SOURCE_DIR}/MachineMetadataTest.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/MachineOperandTest.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/MachineOptimizationTest.cpp" - "${CMAKE_CURRENT_SOURCE_DIR}/MachinePassTest.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/PassManagerTest.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/PassInstrumentationTest.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/MachinePassManagerTest.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/MachineSchedulingTest.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/PBQPTest.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/RegisterAllocationTest.cpp" @@ -544,7 +569,9 @@ rcc_backend_register_tidy_files( "${CMAKE_CURRENT_SOURCE_DIR}/MachineMetadataTest.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/MachineOperandTest.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/MachineOptimizationTest.cpp" - "${CMAKE_CURRENT_SOURCE_DIR}/MachinePassTest.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/PassManagerTest.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/PassInstrumentationTest.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/MachinePassManagerTest.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/MachineSchedulingTest.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/PBQPTest.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/RegisterAllocationTest.cpp" diff --git a/backend/unittests/CodeGen/GlobalISel/InstructionSelectTest.cpp b/backend/unittests/CodeGen/GlobalISel/InstructionSelectTest.cpp index e98f121..30c2b89 100644 --- a/backend/unittests/CodeGen/GlobalISel/InstructionSelectTest.cpp +++ b/backend/unittests/CodeGen/GlobalISel/InstructionSelectTest.cpp @@ -120,7 +120,7 @@ void testPipeline(TestContext &Context) { Fixture.Function->properties() = {rcc::MachineFunctionProperty::IsSSA, rcc::MachineFunctionProperty::TracksLiveness}; const rcc::riscv::RISCVSubtarget Subtarget(rcc::riscv::RISCVSubtargetFeatures::rv64gc()); - rcc::MachinePassManager Pipeline; + rcc::MachineFunctionPassManager Pipeline; Context.expect( Pipeline.addPass(std::make_unique(Subtarget.getLegalizerInfo())).has_value(), "legalizer must be accepted by the pass manager"); @@ -131,7 +131,7 @@ void testPipeline(TestContext &Context) { Pipeline.addPass(std::make_unique(Subtarget.getInstructionSelector())) .has_value(), "instruction selector must be accepted by the pass manager"); - rcc::MachineAnalysisManager Analyses; + rcc::MachineFunctionAnalysisManager Analyses; auto Run = Pipeline.run(*Fixture.Function, *Target, Analyses); Context.expect(Run.has_value(), "RV64GC generic pipeline must complete"); Context.expect(Fixture.Function->properties().has(rcc::MachineFunctionProperty::Selected), @@ -167,7 +167,7 @@ void testInstructionSelectionTransaction(TestContext &Context) { rcc::MachineFunctionProperty::RegBankSelected}; MutatingFailingSelector Selector; rcc::InstructionSelect Pass(Selector); - rcc::MachineAnalysisManager Analyses; + rcc::MachineFunctionAnalysisManager Analyses; auto Run = Pass.run(*Fixture.Function, *Target, Analyses); Context.expect(!Run && Run.error().code() == rcc::ErrorCode::Unsupported, "a renderer failure must be reported before publication"); @@ -203,7 +203,7 @@ void testInstructionSelectionOrder(TestContext &Context) { const rcc::riscv::RISCVSubtarget Subtarget(rcc::riscv::RISCVSubtargetFeatures::rv64gc()); RecordingSelector Selector(*Subtarget.getInstructionSelector()); rcc::InstructionSelect Pass(Selector); - rcc::MachineAnalysisManager Analyses; + rcc::MachineFunctionAnalysisManager Analyses; auto Run = Pass.run(*Fixture.Function, *Target, Analyses); Context.expect(Run.has_value(), "recorded instruction selection must complete"); std::ranges::reverse(LayoutIDs); @@ -233,7 +233,7 @@ void testInstructionSelectionWorklist(TestContext &Context) { rcc::MachineFunctionProperty::RegBankSelected}; TwoStepSelector Selector; rcc::InstructionSelect Pass(Selector); - rcc::MachineAnalysisManager Analyses; + rcc::MachineFunctionAnalysisManager Analyses; auto Run = Pass.run(*Fixture.Function, *Target, Analyses); Context.expect(Run.has_value(), "a progressing multi-step selection must complete"); Context.expect(Selector.selections() == 4, @@ -326,7 +326,7 @@ void testExtendedRV64GCPipeline(TestContext &Context) { Fixture.Function->properties() = {rcc::MachineFunctionProperty::IsSSA, rcc::MachineFunctionProperty::TracksLiveness}; const rcc::riscv::RISCVSubtarget Subtarget(rcc::riscv::RISCVSubtargetFeatures::rv64gc()); - rcc::MachinePassManager Pipeline; + rcc::MachineFunctionPassManager Pipeline; if (!Pipeline.addPass(std::make_unique(Subtarget.getLegalizerInfo())) || !Pipeline.addPass(std::make_unique(Subtarget.getRegBankInfo())) || !Pipeline.addPass( @@ -334,7 +334,7 @@ void testExtendedRV64GCPipeline(TestContext &Context) { Context.expect(false, "extended RV64GC pipeline construction must succeed"); return; } - rcc::MachineAnalysisManager Analyses; + rcc::MachineFunctionAnalysisManager Analyses; auto Run = Pipeline.run(*Fixture.Function, *Target, Analyses); Context.expect(Run.has_value(), "extended RV64GC pipeline must complete"); Context.expect(Run && Fixture.Function->properties().has(rcc::MachineFunctionProperty::Selected), diff --git a/backend/unittests/CodeGen/GlobalISel/LegalizerTest.cpp b/backend/unittests/CodeGen/GlobalISel/LegalizerTest.cpp index 9cb8a67..b191a3f 100644 --- a/backend/unittests/CodeGen/GlobalISel/LegalizerTest.cpp +++ b/backend/unittests/CodeGen/GlobalISel/LegalizerTest.cpp @@ -73,7 +73,7 @@ void testNullAndMissingContracts(TestContext &Context) { return; rcc::Legalizer NullPass(nullptr); - rcc::MachineAnalysisManager Analyses; + rcc::MachineFunctionAnalysisManager Analyses; auto NullResult = NullPass.run(*Fixture.Function, *Target, Analyses); Context.expect(!NullResult && NullResult.error().code() == rcc::ErrorCode::InvalidArgument, "a null legalizer interface must be rejected"); @@ -117,12 +117,12 @@ void testUnsupportedRollback(TestContext &Context) { Unsupported.Function->properties() = {rcc::MachineFunctionProperty::IsSSA, rcc::MachineFunctionProperty::TracksLiveness}; const rcc::riscv::RISCVSubtarget Subtarget(rcc::riscv::RISCVSubtargetFeatures::rv64gc()); - rcc::MachinePassManager OnlyLegalizer; + rcc::MachineFunctionPassManager OnlyLegalizer; Context.expect( OnlyLegalizer.addPass(std::make_unique(Subtarget.getLegalizerInfo())) .has_value(), "standalone legalizer must be accepted"); - rcc::MachineAnalysisManager UnsupportedAnalyses; + rcc::MachineFunctionAnalysisManager UnsupportedAnalyses; auto Failure = OnlyLegalizer.run(*Unsupported.Function, *Target, UnsupportedAnalyses); Context.expect(!Failure && Failure.error().code() == rcc::ErrorCode::Unsupported, "unsupported generic instructions must produce a target diagnostic"); @@ -152,7 +152,7 @@ void testLegalizerCycleDiagnostic(TestContext &Context) { rcc::MachineFunctionProperty::TracksLiveness}; TogglingLegalizer Legalizer; rcc::Legalizer StablePass(Legalizer); - rcc::MachineAnalysisManager Analyses; + rcc::MachineFunctionAnalysisManager Analyses; auto ResultRun = StablePass.run(*Fixture.Function, *Target, Analyses); Context.expect(!ResultRun && ResultRun.error().code() == rcc::ErrorCode::InternalError, "repeated legalization states must report InternalError"); @@ -188,7 +188,7 @@ void testLegalizerRevisitsInvalidatedInstructions(TestContext &Context) { rcc::MachineFunctionProperty::TracksLiveness}; BackwardInvalidatingLegalizer Legalizer; rcc::Legalizer Pass(Legalizer); - rcc::MachineAnalysisManager Analyses; + rcc::MachineFunctionAnalysisManager Analyses; auto Run = Pass.run(*Fixture.Function, *Target, Analyses); const rcc::Opcode LegalOpcode = rcc::Opcode::fromValue(static_cast(rcc::riscv::InstructionOpcode::ADD)); diff --git a/backend/unittests/CodeGen/GlobalISel/RegBankSelectTest.cpp b/backend/unittests/CodeGen/GlobalISel/RegBankSelectTest.cpp index d4925eb..833435f 100644 --- a/backend/unittests/CodeGen/GlobalISel/RegBankSelectTest.cpp +++ b/backend/unittests/CodeGen/GlobalISel/RegBankSelectTest.cpp @@ -33,7 +33,7 @@ void testBankConflict(TestContext &Context) { Fixture.Function->properties() = {rcc::MachineFunctionProperty::Legalized}; const rcc::riscv::RISCVSubtarget Subtarget(rcc::riscv::RISCVSubtargetFeatures::rv64gc()); rcc::RegBankSelect Pass(Subtarget.getRegBankInfo()); - rcc::MachineAnalysisManager Analyses; + rcc::MachineFunctionAnalysisManager Analyses; auto Result = Pass.run(*Fixture.Function, *Target, Analyses); Context.expect(!Result && Result.error().code() == rcc::ErrorCode::VerificationError, "bank selection must reject a conflicting pre-existing bank"); @@ -66,7 +66,7 @@ void testBankClassOnlyChange(TestContext &Context) { Fixture.Function->properties() = {rcc::MachineFunctionProperty::Legalized}; const rcc::riscv::RISCVSubtarget Subtarget(rcc::riscv::RISCVSubtargetFeatures::rv64gc()); rcc::RegBankSelect Pass(Subtarget.getRegBankInfo()); - rcc::MachineAnalysisManager Analyses; + rcc::MachineFunctionAnalysisManager Analyses; auto Result = Pass.run(*Fixture.Function, *Target, Analyses); Context.expect(Result.has_value() && Result->Changed && Result->Changes.has(rcc::MachinePassChange::Registers), diff --git a/backend/unittests/CodeGen/LiveIntervalTest.cpp b/backend/unittests/CodeGen/LiveIntervalTest.cpp index 7e48b05..34ebd76 100644 --- a/backend/unittests/CodeGen/LiveIntervalTest.cpp +++ b/backend/unittests/CodeGen/LiveIntervalTest.cpp @@ -74,7 +74,7 @@ void testLaneSubrangesAndEarlyClobber(TestContext &Context, const rcc::TargetDes return; } - rcc::MachineAnalysisManager Analyses; + rcc::MachineFunctionAnalysisManager Analyses; auto Registered = rcc::registerStage11MachineAnalyses(Analyses); auto Intervals = Registered ? Analyses.getResult(*Fixture->Function, Target) diff --git a/backend/unittests/CodeGen/LiveIntervalsTest.cpp b/backend/unittests/CodeGen/LiveIntervalsTest.cpp index 5c127a2..a080e4d 100644 --- a/backend/unittests/CodeGen/LiveIntervalsTest.cpp +++ b/backend/unittests/CodeGen/LiveIntervalsTest.cpp @@ -64,7 +64,7 @@ void testCFGAndValueNumbers(TestContext &Context, const rcc::TargetDescription & return; } - rcc::MachineAnalysisManager Analyses; + rcc::MachineFunctionAnalysisManager Analyses; auto Registered = rcc::registerStage11MachineAnalyses(Analyses); auto Variables = Registered ? Analyses.getResult(Function, Target) : rcc::Expected{ @@ -133,7 +133,7 @@ void testPhysicalUnitsAndRegMasks(TestContext &Context, const rcc::TargetDescrip Context.expect(false, "physical-alias instructions must be built"); return; } - rcc::MachineAnalysisManager AliasAnalyses; + rcc::MachineFunctionAnalysisManager AliasAnalyses; auto AliasRegistered = rcc::registerStage11MachineAnalyses(AliasAnalyses); auto AliasIntervals = AliasRegistered @@ -167,7 +167,7 @@ void testPhysicalUnitsAndRegMasks(TestContext &Context, const rcc::TargetDescrip Context.expect(false, "RegMask instructions must be built"); return; } - rcc::MachineAnalysisManager MaskAnalyses; + rcc::MachineFunctionAnalysisManager MaskAnalyses; auto MaskRegistered = rcc::registerStage11MachineAnalyses(MaskAnalyses); auto MaskIntervals = MaskRegistered @@ -237,7 +237,7 @@ void testRISCVLiveness(TestContext &Context) { Context.expect(false, "RV64GC ADDI instructions must be built"); return; } - rcc::MachineAnalysisManager Analyses; + rcc::MachineFunctionAnalysisManager Analyses; auto Registered = rcc::registerStage11MachineAnalyses(Analyses); auto Intervals = Registered ? Analyses.getResult(*Fixture->Function, *Target) diff --git a/backend/unittests/CodeGen/LivePhysRegsTest.cpp b/backend/unittests/CodeGen/LivePhysRegsTest.cpp index ee579be..6eea796 100644 --- a/backend/unittests/CodeGen/LivePhysRegsTest.cpp +++ b/backend/unittests/CodeGen/LivePhysRegsTest.cpp @@ -24,7 +24,7 @@ void testPostRALivenessRepair(TestContext &Context, const rcc::TargetDescription return; } - rcc::MachineAnalysisManager Analyses; + rcc::MachineFunctionAnalysisManager Analyses; auto Registered = rcc::registerStage11MachineAnalyses(Analyses); auto Liveness = Registered ? Analyses.getResult(*Fixture->Function, Target) diff --git a/backend/unittests/CodeGen/LiveRegMatrixTest.cpp b/backend/unittests/CodeGen/LiveRegMatrixTest.cpp index 21c0778..423da50 100644 --- a/backend/unittests/CodeGen/LiveRegMatrixTest.cpp +++ b/backend/unittests/CodeGen/LiveRegMatrixTest.cpp @@ -26,7 +26,7 @@ void testLaneAndAssignment(TestContext &Context, const TargetDescription &Target !buildUse(*Fixture->Function, Target, *Fixture->Block, *Low, TestSubReg::Low32)) return; - MachineAnalysisManager Analyses; + MachineFunctionAnalysisManager Analyses; if (!registerStage11MachineAnalyses(Analyses)) return; auto Intervals = Analyses.getResult(*Fixture->Function, Target); @@ -55,7 +55,7 @@ void testFixedAndMaskInterference(TestContext &Context, const TargetDescription !buildUse(*Fixture->Function, Target, *Fixture->Block, *Value)) return; - MachineAnalysisManager Analyses; + MachineFunctionAnalysisManager Analyses; if (!registerStage11MachineAnalyses(Analyses)) return; auto Intervals = Analyses.getResult(*Fixture->Function, Target); diff --git a/backend/unittests/CodeGen/LiveVariablesTest.cpp b/backend/unittests/CodeGen/LiveVariablesTest.cpp index 577ecde..1cc4e91 100644 --- a/backend/unittests/CodeGen/LiveVariablesTest.cpp +++ b/backend/unittests/CodeGen/LiveVariablesTest.cpp @@ -36,9 +36,9 @@ void testLivenessRebuildAndVerifier(TestContext &Context, const rcc::TargetDescr Context.expect(StaleLiveIn.has_value(), "stale live-in setup must succeed"); setRebuildProperties(Function); - rcc::MachinePassManager Pipeline; + rcc::MachineFunctionPassManager Pipeline; auto Added = Pipeline.addPass(std::make_unique()); - rcc::MachineAnalysisManager Analyses; + rcc::MachineFunctionAnalysisManager Analyses; auto Run = Added ? Pipeline.run(Function, Target, Analyses) : rcc::Expected{std::unexpected(Added.error())}; if (!Run) @@ -169,8 +169,9 @@ class DummyAnalysis final { public: struct Result final {}; - [[nodiscard]] static rcc::Expected - run(rcc::MachineFunction &, const rcc::TargetDescription &, rcc::MachineAnalysisManager &) { + [[nodiscard]] static rcc::Expected run(rcc::MachineFunction &, + const rcc::TargetDescription &, + rcc::MachineFunctionAnalysisManager &) { return Result{}; } }; @@ -192,7 +193,7 @@ void testAnalysisRegistrationAndInvalidation(TestContext &Context, return; } - rcc::MachineAnalysisManager Analyses; + rcc::MachineFunctionAnalysisManager Analyses; auto FirstRegistration = rcc::registerStage11MachineAnalyses(Analyses); auto SecondRegistration = rcc::registerStage11MachineAnalyses(Analyses); auto Intervals = FirstRegistration @@ -211,7 +212,7 @@ void testAnalysisRegistrationAndInvalidation(TestContext &Context, Context.expect( Analyses.cachedResultCount(*Fixture->Function) == 1 && Analyses.hasCached(*Fixture->Function, - rcc::MachineAnalysisManager::id()), + rcc::MachineFunctionAnalysisManager::id()), "operand changes must retain SlotIndexes while invalidating liveness dependents"); auto Recomputed = Analyses.getResult(*Fixture->Function, Target); Context.expect(Recomputed && Analyses.cachedResultCount(*Fixture->Function) == 3, @@ -221,18 +222,21 @@ void testAnalysisRegistrationAndInvalidation(TestContext &Context, Context.expect( Analyses.cachedResultCount(*Fixture->Function) == 1 && Analyses.hasCached(*Fixture->Function, - rcc::MachineAnalysisManager::id()), + rcc::MachineFunctionAnalysisManager::id()), "layout changes must invalidate SlotIndexes and LiveIntervals only"); - rcc::MachineAnalysisManager Atomic; + rcc::MachineFunctionAnalysisManager Atomic; rcc::MachineAnalysisRegistration DummyRegistration; DummyRegistration.Name = "SlotIndexes"; auto Dummy = Atomic.registerAnalysis(std::move(DummyRegistration)); auto Rejected = rcc::registerStage11MachineAnalyses(Atomic); Context.expect( - Dummy && !Rejected && Atomic.isRegistered(rcc::MachineAnalysisManager::id()) && - !Atomic.isRegistered(rcc::MachineAnalysisManager::id()) && - !Atomic.isRegistered(rcc::MachineAnalysisManager::id()), + Dummy && !Rejected && + Atomic.isRegistered(rcc::MachineFunctionAnalysisManager::id()) && + !Atomic.isRegistered( + rcc::MachineFunctionAnalysisManager::id()) && + !Atomic.isRegistered( + rcc::MachineFunctionAnalysisManager::id()), "failed standard-analysis registration must leave the manager unchanged"); } diff --git a/backend/unittests/CodeGen/MachineAnalysesTest.cpp b/backend/unittests/CodeGen/MachineAnalysesTest.cpp index 1c9f255..997d031 100644 --- a/backend/unittests/CodeGen/MachineAnalysesTest.cpp +++ b/backend/unittests/CodeGen/MachineAnalysesTest.cpp @@ -86,7 +86,7 @@ void testCFGAnalyses(TestContext &Context, const rcc::TargetDescription &Target) Updater.addSuccessor(**Body, **Header, rcc::BranchProbability::one()), "reducible loop CFG construction must succeed"); - rcc::MachineAnalysisManager Analyses; + rcc::MachineFunctionAnalysisManager Analyses; Context.expect(rcc::registerStage8MachineAnalyses(Analyses).has_value(), "standard Stage 8 analyses must register atomically"); auto Dominators = Analyses.getResult(**Function, Target); @@ -129,7 +129,7 @@ void testCFGAnalyses(TestContext &Context, const rcc::TargetDescription &Target) Context.expect( Analyses.cachedResultCount(**Function) == 1 && Analyses.hasCached(**Function, - rcc::MachineAnalysisManager::id()), + rcc::MachineFunctionAnalysisManager::id()), "CFG changes must invalidate CFG dependents and memory dependence but preserve aliasing"); auto RefreshedDominators = @@ -167,7 +167,7 @@ void testIrreducibleCFG(TestContext &Context, const rcc::TargetDescription &Targ Updater.addSuccessor(**Right, **Exit, *Half), "irreducible CFG construction must succeed"); - rcc::MachineAnalysisManager Analyses; + rcc::MachineFunctionAnalysisManager Analyses; auto Registered = rcc::registerStage8MachineAnalyses(Analyses); auto Loops = Registered @@ -317,7 +317,7 @@ void testMemoryDependence(TestContext &Context, const rcc::TargetDescription &Ta !VolatileStoreInstruction || !VolatileLoadInstruction || !OtherBlockLoadInstruction) return; - rcc::MachineAnalysisManager Analyses; + rcc::MachineFunctionAnalysisManager Analyses; auto Registered = rcc::registerStage8MachineAnalyses(Analyses); auto Dependencies = Registered ? Analyses.getResult(**Function, Target) @@ -352,14 +352,15 @@ void testMemoryDependence(TestContext &Context, const rcc::TargetDescription &Ta class ConflictingAnalysis final { public: struct Result final {}; - [[nodiscard]] static rcc::Expected - run(rcc::MachineFunction &, const rcc::TargetDescription &, rcc::MachineAnalysisManager &) { + [[nodiscard]] static rcc::Expected run(rcc::MachineFunction &, + const rcc::TargetDescription &, + rcc::MachineFunctionAnalysisManager &) { return Result{}; } }; void testAtomicStandardRegistration(TestContext &Context) { - rcc::MachineAnalysisManager Analyses; + rcc::MachineFunctionAnalysisManager Analyses; Context.expect(Analyses .registerAnalysis({ .Name = "MachineLoopInfo", @@ -367,10 +368,11 @@ void testAtomicStandardRegistration(TestContext &Context) { }) .has_value(), "analysis-name conflict setup must succeed"); - Context.expect(!rcc::registerStage8MachineAnalyses(Analyses) && - !Analyses.isRegistered( - rcc::MachineAnalysisManager::id()), - "failed standard-analysis registration must not publish a partial set"); + Context.expect( + !rcc::registerStage8MachineAnalyses(Analyses) && + !Analyses.isRegistered( + rcc::MachineFunctionAnalysisManager::id()), + "failed standard-analysis registration must not publish a partial set"); } void testCFGUpdaterPHIs(TestContext &Context, const rcc::TargetDescription &Target) { diff --git a/backend/unittests/CodeGen/MachineOptimizationTest.cpp b/backend/unittests/CodeGen/MachineOptimizationTest.cpp index d246e39..bb2c0e1 100644 --- a/backend/unittests/CodeGen/MachineOptimizationTest.cpp +++ b/backend/unittests/CodeGen/MachineOptimizationTest.cpp @@ -321,7 +321,7 @@ void testDCEFixedPointAndDebugUses(TestContext &Context, const rcc::TargetDescri } const std::size_t Before = Fixture.Entry->instructionCount(); - rcc::MachineAnalysisManager Analyses; + rcc::MachineFunctionAnalysisManager Analyses; rcc::MachineDCEPass Pass; auto Result = Pass.run(*Fixture.Function, Target, Analyses); if (!Result) @@ -369,7 +369,7 @@ void testMachineCombinerIdentityRules(TestContext &Context, const rcc::TargetDes return; (void)buildStore(Context, Builder, Consumer, X2, *Memory); - rcc::MachineAnalysisManager Analyses; + rcc::MachineFunctionAnalysisManager Analyses; rcc::MachineCombinerPass Pass(rcc::riscv::machineCombinerInfo(), rcc::MachineCombinerStage::SelectedSSA); auto Result = Pass.run(*Fixture.Function, Target, Analyses); @@ -404,7 +404,7 @@ void testPostRAMachineCombinerIdentity(TestContext &Context, const rcc::TargetDe rcc::Register::fromPhysical(X10), 0); if (FrameIdentity != nullptr) FrameIdentity->setFlags({rcc::MachineInstrFlag::FrameDestroy}); - rcc::MachineAnalysisManager Analyses; + rcc::MachineFunctionAnalysisManager Analyses; rcc::MachineCombinerPass Pass(rcc::riscv::machineCombinerInfo(), rcc::MachineCombinerStage::PostRegisterAllocation); auto Result = Pass.run(*Fixture.Function, Target, Analyses); @@ -450,7 +450,7 @@ void testCSERegisterAndMemoryRules(TestContext &Context, const rcc::TargetDescri rcc::MachineInstr *InvariantTwo = buildLoad(Context, Builder, InvariantLoadTwo, Seed, *InvariantMemory); - rcc::MachineAnalysisManager Analyses; + rcc::MachineFunctionAnalysisManager Analyses; rcc::MachineCSEPass Pass; auto Result = Pass.run(*Fixture.Function, Target, Analyses); if (!Result) @@ -490,7 +490,7 @@ void testCSEBudgetPreservesLegalMIR(TestContext &Context, const rcc::TargetDescr (void)buildADDI(Context, Builder, First, Seed, 2); rcc::MachineInstr *SecondInstruction = buildADDI(Context, Builder, Second, Seed, 2); - rcc::MachineAnalysisManager Analyses; + rcc::MachineFunctionAnalysisManager Analyses; rcc::MachineCSEPass Pass({.MaximumComparisons = 0}); auto Result = Pass.run(*Fixture.Function, Target, Analyses); if (!Result) @@ -545,7 +545,7 @@ void testLICMHoistsOnlyInvariantInstructions(TestContext &Context, rcc::MachineInstr *Load = Memory == nullptr ? nullptr : buildLoad(Context, Builder, MutableLoad, Seed, *Memory); - rcc::MachineAnalysisManager Analyses; + rcc::MachineFunctionAnalysisManager Analyses; rcc::MachineLICMPass Pass; auto Result = Pass.run(*Fixture.Function, Target, Analyses); if (!Result) @@ -597,7 +597,7 @@ void testMachineSinkUsesColdUniqueSuccessor(TestContext &Context, const rcc::Register Consumer = makeGPR(Context, *Fixture.Function); rcc::MachineInstr *Use = buildADD(Context, Builder, Consumer, SunkValue, Seed); - rcc::MachineAnalysisManager Analyses; + rcc::MachineFunctionAnalysisManager Analyses; rcc::MachineSinkPass Pass; auto Result = Pass.run(*Fixture.Function, Target, Analyses); if (!Result) @@ -664,7 +664,7 @@ void testPostRACodeMotion(TestContext &Context, const rcc::TargetDescription &Ta setPostRAProperties(*LICMFixture.Function); Context.expect(rcc::rebuildMachineLiveness(*LICMFixture.Function, Target).has_value(), "post-RA LICM fixture liveness must be built"); - rcc::MachineAnalysisManager LICMAnalyses; + rcc::MachineFunctionAnalysisManager LICMAnalyses; rcc::MachineLICMPass PostRALICM(rcc::MachineCodeMotionStage::PostRegisterAllocation); auto LICMResult = PostRALICM.run(*LICMFixture.Function, Target, LICMAnalyses); Context.expect(LICMResult && LICMResult->Changed && Hoisted->parent() == LICMFixture.Entry && @@ -703,7 +703,7 @@ void testPostRACodeMotion(TestContext &Context, const rcc::TargetDescription &Ta setPostRAProperties(*SinkFixture.Function); Context.expect(rcc::rebuildMachineLiveness(*SinkFixture.Function, Target).has_value(), "post-RA sink fixture liveness must be built"); - rcc::MachineAnalysisManager SinkAnalyses; + rcc::MachineFunctionAnalysisManager SinkAnalyses; rcc::MachineSinkPass PostRASink(rcc::MachineCodeMotionStage::PostRegisterAllocation); auto SinkResult = PostRASink.run(*SinkFixture.Function, Target, SinkAnalyses); Context.expect(SinkResult && SinkResult->Changed && Sunk->parent() == *Cold && @@ -742,7 +742,7 @@ void testMemoryFoldingContract(TestContext &Context, const rcc::TargetDescriptio if (!Folded.Function || Folded.Entry == nullptr) return; TestMemoryFoldingInfo GoodInfo; - rcc::MachineAnalysisManager Analyses; + rcc::MachineFunctionAnalysisManager Analyses; rcc::MachineMemoryFoldingPass Pass(GoodInfo); auto Result = Pass.run(*Folded.Function, Target, Analyses); if (!Result) diff --git a/backend/unittests/CodeGen/MachinePassManagerTest.cpp b/backend/unittests/CodeGen/MachinePassManagerTest.cpp new file mode 100644 index 0000000..6e6c44d --- /dev/null +++ b/backend/unittests/CodeGen/MachinePassManagerTest.cpp @@ -0,0 +1,426 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "rcc/CodeGen/MachinePassManager.h" + +#include "Target/TestTarget.h" +#include "rcc/CodeGen/CompilationUnit.h" +#include "rcc/CodeGen/GenericOpcodes.h" +#include "rcc/CodeGen/MachineFunction.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace { + +class TestContext final { +public: + void expect(bool Condition, std::string_view Message) { + if (Condition) + return; + std::cerr << Message << '\n'; + ++Failures; + } + + [[nodiscard]] int result() const noexcept { + return Failures == 0 ? 0 : 1; + } + +private: + int Failures = 0; +}; + +[[nodiscard]] rcc::Expected createTarget() { + std::vector Descriptors; + std::vector Predicates; + auto Appended = rcc::appendGenericInstructionInfo(Descriptors, Predicates); + if (!Appended) + return std::unexpected(Appended.error()); + auto Instructions = rcc::InstructionSet::create(std::move(Descriptors), std::move(Predicates)); + if (!Instructions) + return std::unexpected(Instructions.error()); + return rcc::test::createTestTargetDescription(std::move(*Instructions)); +} + +class BlockCountAnalysis final { +public: + struct Result final { + std::size_t Count = 0; + }; + + [[nodiscard]] static constexpr std::string_view name() noexcept { + return "BlockCount"; + } + + [[nodiscard]] static rcc::Expected run(rcc::MachineFunction &Function, + const rcc::TargetDescription &, + rcc::MachineFunctionAnalysisManager &) { + return Result{Function.blockCount()}; + } +}; + +class NonThreadSafeAnalysis final { +public: + struct Result final {}; + + [[nodiscard]] static constexpr std::string_view name() noexcept { + return "NonThreadSafe"; + } + + [[nodiscard]] static rcc::Expected run(rcc::MachineFunction &, + const rcc::TargetDescription &, + rcc::MachineFunctionAnalysisManager &) { + return Result{}; + } +}; + +class RequiredAnalysisPass final : public rcc::MachineFunctionPass { +public: + [[nodiscard]] const rcc::MachinePassContract &contract() const noexcept override { + static const rcc::MachinePassContract Contract{ + .Name = "RequiredAnalysis", + .Requires = {}, + .Sets = {}, + .Clears = {}, + .RequiredAnalyses = {rcc::MachineFunctionAnalysisManager::id()}, + .VerificationStage = std::nullopt, + }; + return Contract; + } + + [[nodiscard]] rcc::Expected + run(rcc::MachineFunction &Function, const rcc::TargetDescription &Target, + rcc::MachineFunctionAnalysisManager &Analyses) override { + auto Blocks = Analyses.getResult(Function, Target); + if (!Blocks) + return std::unexpected(Blocks.error()); + rcc::MachinePassResult Result; + Result.Preserved = rcc::PreservedAnalyses::all(); + return Result; + } +}; + +class UnreportedChangePass final : public rcc::MachineFunctionPass { +public: + [[nodiscard]] const rcc::MachinePassContract &contract() const noexcept override { + static const rcc::MachinePassContract Contract{ + .Name = "UnreportedChange", + .Requires = {}, + .Sets = {}, + .Clears = {}, + .RequiredAnalyses = {}, + .VerificationStage = std::nullopt, + }; + return Contract; + } + + [[nodiscard]] rcc::Expected + run(rcc::MachineFunction &Function, const rcc::TargetDescription &, + rcc::MachineFunctionAnalysisManager &) override { + auto Block = Function.createBasicBlock(); + if (!Block) + return std::unexpected(Block.error()); + auto Appended = Function.appendBlock(**Block); + if (!Appended) + return std::unexpected(Appended.error()); + return rcc::MachinePassResult{}; + } +}; + +class MutatingFailurePass final : public rcc::MachineFunctionPass { +public: + [[nodiscard]] const rcc::MachinePassContract &contract() const noexcept override { + static const rcc::MachinePassContract Contract{ + .Name = "MutatingFailure", + .Requires = {}, + .Sets = {}, + .Clears = {}, + .RequiredAnalyses = {rcc::MachineFunctionAnalysisManager::id()}, + .VerificationStage = std::nullopt, + }; + return Contract; + } + + [[nodiscard]] rcc::Expected + run(rcc::MachineFunction &Function, const rcc::TargetDescription &, + rcc::MachineFunctionAnalysisManager &) override { + auto Block = Function.createBasicBlock(); + if (!Block) + return std::unexpected(Block.error()); + auto Appended = Function.appendBlock(**Block); + if (!Appended) + return std::unexpected(Appended.error()); + return rcc::makeUnexpected(rcc::ErrorCode::VerificationError, + "intentional mutating pass failure"); + } +}; + +class ParallelCountingPass final : public rcc::MachineFunctionPass { +public: + explicit ParallelCountingPass(std::atomic &Count) : Count(&Count) {} + + [[nodiscard]] const rcc::MachinePassContract &contract() const noexcept override { + static const rcc::MachinePassContract Contract = [] { + rcc::MachinePassContract Value{ + .Name = "ParallelCounting", + .Requires = {}, + .Sets = {}, + .Clears = {}, + .RequiredAnalyses = {}, + .VerificationStage = std::nullopt, + }; + Value.ThreadSafety = rcc::PassThreadSafety::ThreadSafe; + return Value; + }(); + return Contract; + } + + [[nodiscard]] rcc::Expected + run(rcc::MachineFunction &, const rcc::TargetDescription &, + rcc::MachineFunctionAnalysisManager &) override { + Count->fetch_add(1, std::memory_order_relaxed); + return rcc::MachinePassResult{}; + } + +private: + std::atomic *Count; +}; + +class RequiresNonThreadSafeAnalysisPass final : public rcc::MachineFunctionPass { +public: + [[nodiscard]] const rcc::MachinePassContract &contract() const noexcept override { + static const rcc::MachinePassContract Contract = [] { + rcc::MachinePassContract Value{ + .Name = "RequiresNonThreadSafe", + .Requires = {}, + .Sets = {}, + .Clears = {}, + .RequiredAnalyses = + { + rcc::MachineFunctionAnalysisManager::id(), + }, + .VerificationStage = std::nullopt, + }; + Value.ThreadSafety = rcc::PassThreadSafety::ThreadSafe; + return Value; + }(); + return Contract; + } + + [[nodiscard]] rcc::Expected + run(rcc::MachineFunction &, const rcc::TargetDescription &, + rcc::MachineFunctionAnalysisManager &) override { + return rcc::MachinePassResult{}; + } +}; + +class UnitFunctionCountAnalysis final { +public: + struct Result final { + std::size_t Count = 0; + }; + [[nodiscard]] static constexpr std::string_view name() noexcept { + return "UnitFunctionCount"; + } + [[nodiscard]] static rcc::Expected run(rcc::CompilationUnit &Unit, + const rcc::TargetDescription &, + rcc::CompilationUnitAnalysisManager &) { + return Result{Unit.functionCount()}; + } +}; + +class ObserveUnitPass final : public rcc::CompilationUnitPass { +public: + [[nodiscard]] const rcc::CompilationUnitPassContract &contract() const noexcept override { + static const rcc::CompilationUnitPassContract Contract{ + .Name = "ObserveUnit", + .RequiredAnalyses = {rcc::CompilationUnitAnalysisManager::id()}, + .Parameters = {}, + .DeclaredChanges = {}, + }; + return Contract; + } + + [[nodiscard]] rcc::Expected + run(rcc::CompilationUnit &Unit, const rcc::TargetDescription &Target, + rcc::CompilationUnitAnalysisManager &Analyses, + rcc::MachineFunctionAnalysisManager &) override { + auto Count = Analyses.getResult(Unit, Target); + if (!Count) + return std::unexpected(Count.error()); + if ((*Count)->Count != Unit.functionCount()) { + return rcc::makeUnexpected(rcc::ErrorCode::VerificationError, + "unit analysis returned a stale function count"); + } + return rcc::CompilationUnitPassResult{}; + } +}; + +class MutatingUnitFailurePass final : public rcc::CompilationUnitPass { +public: + [[nodiscard]] const rcc::CompilationUnitPassContract &contract() const noexcept override { + static const rcc::CompilationUnitPassContract Contract{ + .Name = "MutatingUnitFailure", + .RequiredAnalyses = {rcc::CompilationUnitAnalysisManager::id()}, + .Parameters = {}, + .DeclaredChanges = {rcc::MachinePassChange::BlockLayout}, + }; + return Contract; + } + + [[nodiscard]] rcc::Expected + run(rcc::CompilationUnit &Unit, const rcc::TargetDescription &, + rcc::CompilationUnitAnalysisManager &, rcc::MachineFunctionAnalysisManager &) override { + auto Created = Unit.createMachineFunction("added-before-failure"); + if (!Created) + return std::unexpected(Created.error()); + return rcc::makeUnexpected(rcc::ErrorCode::VerificationError, + "intentional compilation-unit pass failure"); + } +}; + +void testMachinePassManager(TestContext &Context, const rcc::TargetDescription &Target) { + auto Function = rcc::MachineFunction::create("pass", rcc::MachineFunctionStableID::fromValue(2)); + Context.expect(Function.has_value(), "pass function creation must succeed"); + if (!Function) + return; + + rcc::MachineFunctionAnalysisManager Analyses; + Context.expect(Analyses + .registerAnalysis({ + .Name = "BlockCount", + .Dependencies = {}, + .InvalidatedBy = rcc::MachinePassChanges::all(), + .ThreadSafety = rcc::PassThreadSafety::ThreadSafe, + }) + .has_value(), + "pass analysis registration must succeed"); + + rcc::MachineFunctionPassManager Pipeline; + Context.expect(Pipeline.addPass(std::make_unique()).has_value(), + "a valid pass must be accepted"); + auto Run = Pipeline.run(**Function, Target, Analyses); + Context.expect(Run.has_value(), "a pass with a materialized required analysis must run"); + + auto ChangedFunction = + rcc::MachineFunction::create("unreported", rcc::MachineFunctionStableID::fromValue(3)); + rcc::MachineFunctionAnalysisManager EmptyAnalyses; + rcc::MachineFunctionPassManager Detecting( + {.VerifyBefore = true, .VerifyEach = true, .DetectUnreportedChanges = true}); + Context.expect(ChangedFunction && + Detecting.addPass(std::make_unique()).has_value() && + !Detecting.run(**ChangedFunction, Target, EmptyAnalyses), + "change detection must reject an unreported MachineIR mutation"); + + auto FailedFunction = + rcc::MachineFunction::create("failed", rcc::MachineFunctionStableID::fromValue(4)); + rcc::MachineFunctionAnalysisManager FailureAnalyses; + Context.expect(FailedFunction && FailureAnalyses + .registerAnalysis({ + .Name = "BlockCount", + .Dependencies = {}, + .InvalidatedBy = rcc::MachinePassChanges::all(), + }) + .has_value(), + "mutating failure analysis fixtures must be valid"); + rcc::MachineFunctionPassManager FailingPipeline; + Context.expect( + FailedFunction && + FailingPipeline.addPass(std::make_unique()).has_value() && + !FailingPipeline.run(**FailedFunction, Target, FailureAnalyses) && + !FailureAnalyses.hasCached(**FailedFunction, + rcc::MachineFunctionAnalysisManager::id()), + "a pass that mutates and fails must not leave stale function analyses cached"); +} + +void testCompilationUnitAndParallelism(TestContext &Context, const rcc::TargetDescription &Target) { + rcc::CompilationUnit Unit; + for (std::size_t Index = 0; Index < 8; ++Index) { + auto Function = Unit.createMachineFunction("f" + std::to_string(Index)); + Context.expect(Function.has_value(), "parallel test function creation must succeed"); + } + + std::atomic Runs = 0; + rcc::MachineFunctionPassManager Parallel; + Context.expect(Parallel.addPass(std::make_unique(Runs)).has_value(), + "thread-safe pass registration must succeed"); + rcc::MachineFunctionAnalysisManager Prototype; + auto ParallelRun = Parallel.runFunctions(Unit, Target, Prototype, std::size_t{4}); + Context.expect(ParallelRun.has_value() && Runs == Unit.functionCount(), + "parallel function execution must visit every function exactly once"); + + rcc::MachineFunctionAnalysisManager UnsafePrototype; + Context.expect(UnsafePrototype + .registerAnalysis({ + .Name = "NonThreadSafe", + .Dependencies = {}, + .InvalidatedBy = rcc::MachinePassChanges::all(), + .ThreadSafety = rcc::PassThreadSafety::NotThreadSafe, + }) + .has_value(), + "non-thread-safe analysis registration must be explicit"); + rcc::MachineFunctionPassManager UnsafeParallel; + Context.expect( + UnsafeParallel.addPass(std::make_unique()).has_value() && + !UnsafeParallel.runFunctions(Unit, Target, UnsafePrototype, std::size_t{4}), + "parallel pipelines must reject a required analysis not marked thread-safe"); + + rcc::CompilationUnitAnalysisManager UnitAnalyses; + Context.expect(UnitAnalyses + .registerAnalysis({ + .Name = "UnitFunctionCount", + .Dependencies = {}, + .InvalidatedBy = rcc::MachinePassChanges::all(), + }) + .has_value(), + "compilation-unit analysis registration must succeed"); + rcc::MachineFunctionAnalysisManager FunctionAnalyses; + rcc::CompilationUnitPassManager UnitPipeline; + Context.expect(UnitPipeline.addPass(std::make_unique()).has_value(), + "compilation-unit pass registration must succeed"); + Context.expect(UnitPipeline.run(Unit, Target, UnitAnalyses, FunctionAnalyses).has_value(), + "compilation-unit pass and analysis must run through their own manager"); + + rcc::MachineFunction *FirstFunction = Unit.functionAt(0); + Context.expect( + FirstFunction != nullptr && + FunctionAnalyses + .registerAnalysis({ + .Name = "BlockCount", + .Dependencies = {}, + .InvalidatedBy = rcc::MachinePassChanges::all(), + }) + .has_value() && + FunctionAnalyses.getResult(*FirstFunction, Target).has_value(), + "compilation-unit failure cache fixtures must materialize"); + rcc::CompilationUnitPassManager FailingUnitPipeline; + Context.expect( + FirstFunction != nullptr && + FailingUnitPipeline.addPass(std::make_unique()).has_value() && + !FailingUnitPipeline.run(Unit, Target, UnitAnalyses, FunctionAnalyses) && + !UnitAnalyses.hasCached( + Unit, rcc::CompilationUnitAnalysisManager::id()) && + !FunctionAnalyses.hasCached( + *FirstFunction, rcc::MachineFunctionAnalysisManager::id()), + "a mutating compilation-unit failure must clear unit and function analysis caches"); +} + +} // namespace + +int main() { + TestContext Context; + auto Target = createTarget(); + Context.expect(Target.has_value(), "machine pass tests require a valid target description"); + if (!Target) + return Context.result(); + + testMachinePassManager(Context, *Target); + testCompilationUnitAndParallelism(Context, *Target); + return Context.result(); +} diff --git a/backend/unittests/CodeGen/MachinePassTest.cpp b/backend/unittests/CodeGen/MachinePassTest.cpp deleted file mode 100644 index fb125a4..0000000 --- a/backend/unittests/CodeGen/MachinePassTest.cpp +++ /dev/null @@ -1,918 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later - -#include "rcc/CodeGen/MachinePass.h" - -#include "Target/TestTarget.h" -#include "rcc/CodeGen/CompilationUnit.h" -#include "rcc/CodeGen/GenericOpcodes.h" -#include "rcc/CodeGen/MachineFunction.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace { - -class TestContext final { -public: - void expect(bool Condition, std::string_view Message) { - if (Condition) - return; - std::cerr << Message << '\n'; - ++Failures; - } - - [[nodiscard]] int result() const noexcept { - return Failures == 0 ? 0 : 1; - } - -private: - int Failures = 0; -}; - -[[nodiscard]] rcc::Expected createTarget() { - std::vector Descriptors; - std::vector Predicates; - auto Appended = rcc::appendGenericInstructionInfo(Descriptors, Predicates); - if (!Appended) - return std::unexpected(Appended.error()); - auto Instructions = rcc::InstructionSet::create(std::move(Descriptors), std::move(Predicates)); - if (!Instructions) - return std::unexpected(Instructions.error()); - return rcc::test::createTestTargetDescription(std::move(*Instructions)); -} - -class BlockCountAnalysis final { -public: - struct Result final { - std::size_t Count = 0; - }; - - [[nodiscard]] static constexpr std::string_view name() noexcept { - return "BlockCount"; - } - - [[nodiscard]] static rcc::Expected run(rcc::MachineFunction &Function, - const rcc::TargetDescription &, - rcc::MachineAnalysisManager &) { - ++Runs; - return Result{Function.blockCount()}; - } - - static inline std::atomic Runs = 0; -}; - -class DependentAnalysis final { -public: - struct Result final { - std::size_t Count = 0; - }; - - [[nodiscard]] static constexpr std::string_view name() noexcept { - return "Dependent"; - } - - [[nodiscard]] static rcc::Expected run(rcc::MachineFunction &Function, - const rcc::TargetDescription &Target, - rcc::MachineAnalysisManager &Analyses) { - auto Blocks = Analyses.getResult(Function, Target); - if (!Blocks) - return std::unexpected(Blocks.error()); - return Result{(*Blocks)->Count}; - } -}; - -class NonThreadSafeAnalysis final { -public: - struct Result final {}; - - [[nodiscard]] static constexpr std::string_view name() noexcept { - return "NonThreadSafe"; - } - - [[nodiscard]] static rcc::Expected - run(rcc::MachineFunction &, const rcc::TargetDescription &, rcc::MachineAnalysisManager &) { - return Result{}; - } -}; - -class FailingAnalysis final { -public: - struct Result final {}; - - [[nodiscard]] static constexpr std::string_view name() noexcept { - return "Failing"; - } - - [[nodiscard]] static rcc::Expected - run(rcc::MachineFunction &, const rcc::TargetDescription &, rcc::MachineAnalysisManager &) { - return rcc::makeUnexpected(rcc::ErrorCode::VerificationError, - "intentional machine analysis failure"); - } -}; - -class StickyAnalysis final { -public: - struct Result final { - [[nodiscard]] bool invalidate(const rcc::MachineFunction &, - const rcc::PreservedAnalyses &) noexcept { - return false; - } - }; - - [[nodiscard]] static constexpr std::string_view name() noexcept { - return "Sticky"; - } - [[nodiscard]] static rcc::Expected - run(rcc::MachineFunction &, const rcc::TargetDescription &, rcc::MachineAnalysisManager &) { - return Result{}; - } -}; - -class ExpiringAnalysis final { -public: - struct Result final { - [[nodiscard]] bool invalidate(const rcc::MachineFunction &, - const rcc::PreservedAnalyses &) noexcept { - return true; - } - }; - - [[nodiscard]] static constexpr std::string_view name() noexcept { - return "Expiring"; - } - [[nodiscard]] static rcc::Expected - run(rcc::MachineFunction &, const rcc::TargetDescription &, rcc::MachineAnalysisManager &) { - return Result{}; - } -}; - -class CycleA final { -public: - struct Result final {}; - [[nodiscard]] static constexpr std::string_view name() noexcept { - return "CycleA"; - } - [[nodiscard]] static rcc::Expected - run(rcc::MachineFunction &, const rcc::TargetDescription &, rcc::MachineAnalysisManager &) { - return Result{}; - } -}; - -class CycleB final { -public: - struct Result final {}; - [[nodiscard]] static constexpr std::string_view name() noexcept { - return "CycleB"; - } - [[nodiscard]] static rcc::Expected - run(rcc::MachineFunction &, const rcc::TargetDescription &, rcc::MachineAnalysisManager &) { - return Result{}; - } -}; - -class RequiredAnalysisPass final : public rcc::MachineFunctionPass { -public: - [[nodiscard]] const rcc::MachinePassContract &contract() const noexcept override { - static const rcc::MachinePassContract Contract{ - .Name = "RequiredAnalysis", - .Requires = {}, - .Sets = {}, - .Clears = {}, - .RequiredAnalyses = {rcc::MachineAnalysisManager::id()}, - .VerificationStage = std::nullopt, - }; - return Contract; - } - - [[nodiscard]] rcc::Expected - run(rcc::MachineFunction &Function, const rcc::TargetDescription &Target, - rcc::MachineAnalysisManager &Analyses) override { - auto Dependent = Analyses.getResult(Function, Target); - if (!Dependent) - return std::unexpected(Dependent.error()); - auto FirstAction = Analyses.requestAction("first", Function); - auto SecondAction = Analyses.requestAction("second", Function); - if (!FirstAction || !SecondAction || !*FirstAction || *SecondAction) { - return rcc::makeUnexpected(rcc::ErrorCode::VerificationError, - "per-function action fuel was not enforced"); - } - rcc::MachinePassResult Result; - Result.Preserved = rcc::PreservedAnalyses::all(); - return Result; - } -}; - -class UnreportedChangePass final : public rcc::MachineFunctionPass { -public: - [[nodiscard]] const rcc::MachinePassContract &contract() const noexcept override { - static const rcc::MachinePassContract Contract{ - .Name = "UnreportedChange", - .Requires = {}, - .Sets = {}, - .Clears = {}, - .RequiredAnalyses = {}, - .VerificationStage = std::nullopt, - }; - return Contract; - } - - [[nodiscard]] rcc::Expected run(rcc::MachineFunction &Function, - const rcc::TargetDescription &, - rcc::MachineAnalysisManager &) override { - auto Block = Function.createBasicBlock(); - if (!Block) - return std::unexpected(Block.error()); - auto Appended = Function.appendBlock(**Block); - if (!Appended) - return std::unexpected(Appended.error()); - return rcc::MachinePassResult{}; - } -}; - -class RequiresFailingAnalysisPass final : public rcc::MachineFunctionPass { -public: - [[nodiscard]] const rcc::MachinePassContract &contract() const noexcept override { - static const rcc::MachinePassContract Contract{ - .Name = "RequiresFailingAnalysis", - .Requires = {}, - .Sets = {}, - .Clears = {}, - .RequiredAnalyses = {rcc::MachineAnalysisManager::id()}, - .VerificationStage = std::nullopt, - }; - return Contract; - } - - [[nodiscard]] rcc::Expected run(rcc::MachineFunction &, - const rcc::TargetDescription &, - rcc::MachineAnalysisManager &) override { - return rcc::MachinePassResult{}; - } -}; - -class MutatingFailurePass final : public rcc::MachineFunctionPass { -public: - [[nodiscard]] const rcc::MachinePassContract &contract() const noexcept override { - static const rcc::MachinePassContract Contract{ - .Name = "MutatingFailure", - .Requires = {}, - .Sets = {}, - .Clears = {}, - .RequiredAnalyses = {rcc::MachineAnalysisManager::id()}, - .VerificationStage = std::nullopt, - }; - return Contract; - } - - [[nodiscard]] rcc::Expected run(rcc::MachineFunction &Function, - const rcc::TargetDescription &, - rcc::MachineAnalysisManager &) override { - auto Block = Function.createBasicBlock(); - if (!Block) - return std::unexpected(Block.error()); - auto Appended = Function.appendBlock(**Block); - if (!Appended) - return std::unexpected(Appended.error()); - return rcc::makeUnexpected(rcc::ErrorCode::VerificationError, - "intentional mutating pass failure"); - } -}; - -class ParallelCountingPass final : public rcc::MachineFunctionPass { -public: - explicit ParallelCountingPass(std::atomic &Count) : Count(&Count) {} - - [[nodiscard]] const rcc::MachinePassContract &contract() const noexcept override { - static const rcc::MachinePassContract Contract = [] { - rcc::MachinePassContract Value{ - .Name = "ParallelCounting", - .Requires = {}, - .Sets = {}, - .Clears = {}, - .RequiredAnalyses = {}, - .VerificationStage = std::nullopt, - }; - Value.ThreadSafety = rcc::PassThreadSafety::ThreadSafe; - return Value; - }(); - return Contract; - } - - [[nodiscard]] rcc::Expected run(rcc::MachineFunction &, - const rcc::TargetDescription &, - rcc::MachineAnalysisManager &) override { - Count->fetch_add(1, std::memory_order_relaxed); - return rcc::MachinePassResult{}; - } - -private: - std::atomic *Count; -}; - -class InstrumentedParallelPass final : public rcc::MachineFunctionPass { -public: - InstrumentedParallelPass(std::atomic &Runs, std::atomic &Active, - std::atomic &MaximumActive) - : Runs(&Runs), Active(&Active), MaximumActive(&MaximumActive) {} - - [[nodiscard]] const rcc::MachinePassContract &contract() const noexcept override { - static const rcc::MachinePassContract Contract = [] { - rcc::MachinePassContract Value{ - .Name = "InstrumentedParallel", - .Requires = {}, - .Sets = {}, - .Clears = {}, - .RequiredAnalyses = {}, - .VerificationStage = std::nullopt, - }; - Value.ThreadSafety = rcc::PassThreadSafety::ThreadSafe; - Value.DeclaredChanges = {rcc::MachinePassChange::BlockLayout}; - return Value; - }(); - return Contract; - } - - [[nodiscard]] rcc::Expected run(rcc::MachineFunction &Function, - const rcc::TargetDescription &, - rcc::MachineAnalysisManager &) override { - const std::uint32_t Current = Active->fetch_add(1, std::memory_order_acq_rel) + 1U; - std::uint32_t Maximum = MaximumActive->load(std::memory_order_relaxed); - while (Maximum < Current && - !MaximumActive->compare_exchange_weak(Maximum, Current, std::memory_order_relaxed)) { - } - std::this_thread::sleep_for(std::chrono::milliseconds(2)); - auto Block = Function.createBasicBlock(); - if (!Block) { - Active->fetch_sub(1, std::memory_order_acq_rel); - return std::unexpected(Block.error()); - } - auto Appended = Function.appendBlock(**Block); - Active->fetch_sub(1, std::memory_order_acq_rel); - if (!Appended) - return std::unexpected(Appended.error()); - Runs->fetch_add(1, std::memory_order_relaxed); - rcc::MachinePassResult Result; - Result.Changed = true; - Result.Changes.add(rcc::MachinePassChange::BlockLayout); - return Result; - } - -private: - std::atomic *Runs; - std::atomic *Active; - std::atomic *MaximumActive; -}; - -class RequiresNonThreadSafeAnalysisPass final : public rcc::MachineFunctionPass { -public: - [[nodiscard]] const rcc::MachinePassContract &contract() const noexcept override { - static const rcc::MachinePassContract Contract = [] { - rcc::MachinePassContract Value{ - .Name = "RequiresNonThreadSafe", - .Requires = {}, - .Sets = {}, - .Clears = {}, - .RequiredAnalyses = - { - rcc::MachineAnalysisManager::id(), - }, - .VerificationStage = std::nullopt, - }; - Value.ThreadSafety = rcc::PassThreadSafety::ThreadSafe; - return Value; - }(); - return Contract; - } - - [[nodiscard]] rcc::Expected run(rcc::MachineFunction &, - const rcc::TargetDescription &, - rcc::MachineAnalysisManager &) override { - return rcc::MachinePassResult{}; - } -}; - -class UnitFunctionCountAnalysis final { -public: - struct Result final { - std::size_t Count = 0; - }; - [[nodiscard]] static constexpr std::string_view name() noexcept { - return "UnitFunctionCount"; - } - [[nodiscard]] static rcc::Expected run(rcc::CompilationUnit &Unit, - const rcc::TargetDescription &, - rcc::CompilationUnitAnalysisManager &) { - return Result{Unit.functionCount()}; - } -}; - -class FailingUnitAnalysis final { -public: - struct Result final {}; - - [[nodiscard]] static constexpr std::string_view name() noexcept { - return "FailingUnit"; - } - - [[nodiscard]] static rcc::Expected run(rcc::CompilationUnit &, - const rcc::TargetDescription &, - rcc::CompilationUnitAnalysisManager &) { - return rcc::makeUnexpected(rcc::ErrorCode::VerificationError, - "intentional compilation-unit analysis failure"); - } -}; - -class RequiresFailingUnitAnalysisPass final : public rcc::CompilationUnitPass { -public: - [[nodiscard]] const rcc::CompilationUnitPassContract &contract() const noexcept override { - static const rcc::CompilationUnitPassContract Contract{ - .Name = "RequiresFailingUnitAnalysis", - .RequiredAnalyses = - { - rcc::CompilationUnitAnalysisManager::id(), - }, - .Parameters = {}, - .DeclaredChanges = {}, - }; - return Contract; - } - - [[nodiscard]] rcc::Expected - run(rcc::CompilationUnit &, const rcc::TargetDescription &, rcc::CompilationUnitAnalysisManager &, - rcc::MachineAnalysisManager &) override { - return rcc::CompilationUnitPassResult{}; - } -}; - -class ObserveUnitPass final : public rcc::CompilationUnitPass { -public: - [[nodiscard]] const rcc::CompilationUnitPassContract &contract() const noexcept override { - static const rcc::CompilationUnitPassContract Contract{ - .Name = "ObserveUnit", - .RequiredAnalyses = {rcc::CompilationUnitAnalysisManager::id()}, - .Parameters = {}, - .DeclaredChanges = {}, - }; - return Contract; - } - - [[nodiscard]] rcc::Expected - run(rcc::CompilationUnit &Unit, const rcc::TargetDescription &Target, - rcc::CompilationUnitAnalysisManager &Analyses, rcc::MachineAnalysisManager &) override { - auto Count = Analyses.getResult(Unit, Target); - if (!Count) - return std::unexpected(Count.error()); - if ((*Count)->Count != Unit.functionCount()) { - return rcc::makeUnexpected(rcc::ErrorCode::VerificationError, - "unit analysis returned a stale function count"); - } - return rcc::CompilationUnitPassResult{}; - } -}; - -class MutatingUnitFailurePass final : public rcc::CompilationUnitPass { -public: - [[nodiscard]] const rcc::CompilationUnitPassContract &contract() const noexcept override { - static const rcc::CompilationUnitPassContract Contract{ - .Name = "MutatingUnitFailure", - .RequiredAnalyses = {rcc::CompilationUnitAnalysisManager::id()}, - .Parameters = {}, - .DeclaredChanges = {rcc::MachinePassChange::BlockLayout}, - }; - return Contract; - } - - [[nodiscard]] rcc::Expected - run(rcc::CompilationUnit &Unit, const rcc::TargetDescription &, - rcc::CompilationUnitAnalysisManager &, rcc::MachineAnalysisManager &) override { - auto Created = Unit.createMachineFunction("added-before-failure"); - if (!Created) - return std::unexpected(Created.error()); - return rcc::makeUnexpected(rcc::ErrorCode::VerificationError, - "intentional compilation-unit pass failure"); - } -}; - -void testAnalysisInfrastructure(TestContext &Context, const rcc::TargetDescription &Target) { - auto Function = - rcc::MachineFunction::create("analysis", rcc::MachineFunctionStableID::fromValue(1)); - Context.expect(Function.has_value(), "analysis function creation must succeed"); - if (!Function) - return; - - rcc::MachineAnalysisManager Analyses; - Context.expect(Analyses - .registerAnalysis({ - .Name = "BlockCount", - .Dependencies = {}, - .InvalidatedBy = {rcc::MachinePassChange::CFG}, - }) - .has_value(), - "base analysis registration must succeed"); - Context.expect(Analyses - .registerAnalysis({ - .Name = "Dependent", - .Dependencies = {rcc::MachineAnalysisManager::id()}, - .InvalidatedBy = {rcc::MachinePassChange::Operands}, - }) - .has_value(), - "dependent analysis registration must succeed"); - - BlockCountAnalysis::Runs = 0; - auto First = Analyses.getResult(**Function, Target); - auto Second = Analyses.getResult(**Function, Target); - Context.expect(First && Second && *First == *Second && BlockCountAnalysis::Runs == 1, - "analysis dependencies must materialize once and then use the cache"); - - Analyses.invalidate(**Function, rcc::PreservedAnalyses::none(), - {rcc::MachinePassChange::Registers}); - Context.expect(Analyses.cachedResultCount(**Function) == 2, - "unrelated changes must preserve cached analyses precisely"); - Analyses.invalidate(**Function, rcc::PreservedAnalyses::none(), {rcc::MachinePassChange::CFG}); - Context.expect(Analyses.cachedResultCount(**Function) == 0, - "invalidating a dependency must invalidate its dependent analysis"); - - rcc::MachineAnalysisManager Cyclic; - Context.expect(Cyclic - .registerAnalysis({ - .Name = "CycleA", - .Dependencies = {rcc::MachineAnalysisManager::id()}, - }) - .has_value() && - Cyclic - .registerAnalysis({ - .Name = "CycleB", - .Dependencies = {rcc::MachineAnalysisManager::id()}, - }) - .has_value(), - "cyclic analysis registrations must be accepted until requested"); - Context.expect(!Cyclic.getResult(**Function, Target), - "analysis dependency cycles must produce a structured error"); - - rcc::MachineAnalysisManager CustomInvalidation; - Context.expect(CustomInvalidation - .registerAnalysis({ - .Name = "Sticky", - .Dependencies = {}, - .InvalidatedBy = {rcc::MachinePassChange::CFG}, - }) - .has_value() && - CustomInvalidation - .registerAnalysis({ - .Name = "Expiring", - .Dependencies = {}, - .InvalidatedBy = {rcc::MachinePassChange::CFG}, - }) - .has_value() && - CustomInvalidation.getResult(**Function, Target) && - CustomInvalidation.getResult(**Function, Target), - "custom invalidation analyses must materialize"); - CustomInvalidation.invalidate(**Function, rcc::PreservedAnalyses::none(), - {rcc::MachinePassChange::CFG}); - Context.expect( - CustomInvalidation.hasCached(**Function, rcc::MachineAnalysisManager::id()) && - !CustomInvalidation.hasCached(**Function, - rcc::MachineAnalysisManager::id()), - "analysis invalidate() must return false to preserve and true to invalidate"); -} - -void testPassAndInstrumentation(TestContext &Context, const rcc::TargetDescription &Target) { - auto Function = rcc::MachineFunction::create("pass", rcc::MachineFunctionStableID::fromValue(2)); - Context.expect(Function.has_value(), "pass function creation must succeed"); - if (!Function) - return; - - rcc::MachineAnalysisManager Analyses; - Context.expect( - Analyses - .registerAnalysis({ - .Name = "BlockCount", - .Dependencies = {}, - .InvalidatedBy = rcc::MachinePassChanges::all(), - .ThreadSafety = rcc::PassThreadSafety::ThreadSafe, - }) - .has_value() && - Analyses - .registerAnalysis({ - .Name = "Dependent", - .Dependencies = {rcc::MachineAnalysisManager::id()}, - }) - .has_value(), - "pass analysis registrations must succeed"); - - rcc::MachinePassInstrumentation Instrumentation; - Instrumentation.setPerFunctionFuel(1); - std::uint32_t BeforePass = 0; - std::uint32_t AfterPass = 0; - std::uint32_t BeforeAnalysis = 0; - std::uint32_t AfterAnalysis = 0; - std::uint32_t AnalysisCacheHits = 0; - std::uint32_t Printed = 0; - std::uint32_t ChangeEvents = 0; - std::uint32_t FailureEvents = 0; - Instrumentation.addBeforeCallback( - [&BeforePass](std::string_view, const rcc::MachineFunction &) { ++BeforePass; }); - Instrumentation.addAfterCallback([&AfterPass](std::string_view, const rcc::MachineFunction &, - const rcc::MachinePassResult &) { ++AfterPass; }); - Instrumentation.addBeforeAnalysisCallback( - [&BeforeAnalysis](std::string_view, const rcc::MachineFunction &) { ++BeforeAnalysis; }); - Instrumentation.addAfterAnalysisCallback( - [&AfterAnalysis, &AnalysisCacheHits](std::string_view, const rcc::MachineFunction &, - bool CacheHit, std::uint64_t) { - ++AfterAnalysis; - AnalysisCacheHits += CacheHit ? 1U : 0U; - }); - Instrumentation.addIRPrintCallback([&Printed](rcc::InstrumentationPhase, std::string_view, - const rcc::MachineFunction &) { ++Printed; }); - Instrumentation.addChangeCallback([&ChangeEvents](std::string_view, const rcc::MachineFunction &, - rcc::MachinePassChanges Changes, - bool FingerprintChanged) { - if (Changes.empty() && !FingerprintChanged) - ++ChangeEvents; - }); - Instrumentation.addFailureCallback([&FailureEvents](std::string_view, - const rcc::MachineFunction &, - const rcc::Error &) { ++FailureEvents; }); - - rcc::MachinePassManager Pipeline; - Context.expect(Pipeline.addPass(std::make_unique()).has_value(), - "a valid pass must be accepted"); - auto Run = Pipeline.run(**Function, Target, Analyses, &Instrumentation); - Context.expect(Run.has_value(), "a pass with a materialized required analysis must run"); - Context.expect(BeforePass == 1 && AfterPass == 1 && BeforeAnalysis == 2 && AfterAnalysis == 4 && - AnalysisCacheHits == 2 && Printed == 2 && ChangeEvents == 1, - "pass, analysis, cache-hit, IR-print, and change callbacks must all run"); - const auto Statistics = Instrumentation.statistics(); - Context.expect(Statistics.size() == 3, - "instrumentation must collect one pass and two analysis statistics"); - - auto ChangedFunction = - rcc::MachineFunction::create("unreported", rcc::MachineFunctionStableID::fromValue(3)); - rcc::MachineAnalysisManager EmptyAnalyses; - rcc::MachinePassManager Detecting( - {.VerifyBefore = true, .VerifyEach = true, .DetectUnreportedChanges = true}); - Context.expect(ChangedFunction && - Detecting.addPass(std::make_unique()).has_value() && - !Detecting.run(**ChangedFunction, Target, EmptyAnalyses, &Instrumentation) && - FailureEvents == 1, - "change detection must reject an unreported MachineIR mutation"); - - auto FailedFunction = - rcc::MachineFunction::create("failed", rcc::MachineFunctionStableID::fromValue(4)); - rcc::MachineAnalysisManager FailureAnalyses; - Context.expect(FailedFunction && FailureAnalyses - .registerAnalysis({ - .Name = "BlockCount", - .Dependencies = {}, - .InvalidatedBy = rcc::MachinePassChanges::all(), - }) - .has_value(), - "mutating failure analysis fixtures must be valid"); - rcc::MachinePassManager FailingPipeline; - Context.expect(FailedFunction && - FailingPipeline.addPass(std::make_unique()).has_value() && - !FailingPipeline.run(**FailedFunction, Target, FailureAnalyses) && - !FailureAnalyses.hasCached( - **FailedFunction, rcc::MachineAnalysisManager::id()), - "a pass that mutates and fails must not leave stale function analyses cached"); - - rcc::MachineAnalysisManager FailingAnalyses; - Context.expect(FailingAnalyses - .registerAnalysis({ - .Name = "Failing", - .Dependencies = {}, - }) - .has_value(), - "failing analysis registration must succeed"); - rcc::MachinePassInstrumentation FailureInstrumentation; - std::uint32_t BeforeFailingAnalysis = 0; - std::uint32_t FailingAnalysisEvents = 0; - std::uint32_t RequiredAnalysisPassFailures = 0; - FailureInstrumentation.addBeforeAnalysisCallback( - [&BeforeFailingAnalysis](std::string_view, const rcc::MachineFunction &) { - ++BeforeFailingAnalysis; - }); - FailureInstrumentation.addAnalysisFailureCallback( - [&FailingAnalysisEvents](std::string_view, const rcc::MachineFunction &, const rcc::Error &) { - ++FailingAnalysisEvents; - }); - FailureInstrumentation.addFailureCallback( - [&RequiredAnalysisPassFailures](std::string_view, const rcc::MachineFunction &, - const rcc::Error &) { ++RequiredAnalysisPassFailures; }); - rcc::MachinePassManager RequiredAnalysisFailurePipeline; - Context.expect( - RequiredAnalysisFailurePipeline.addPass(std::make_unique()) - .has_value() && - !RequiredAnalysisFailurePipeline.run(**Function, Target, FailingAnalyses, - &FailureInstrumentation) && - BeforeFailingAnalysis == 1 && FailingAnalysisEvents == 1 && - RequiredAnalysisPassFailures == 1, - "analysis and pass failure instrumentation must report required-analysis failures"); -} - -void testCompilationUnitAndParallelism(TestContext &Context, const rcc::TargetDescription &Target) { - rcc::CompilationUnit Unit; - for (std::size_t Index = 0; Index < 8; ++Index) { - auto Function = Unit.createMachineFunction("f" + std::to_string(Index)); - Context.expect(Function.has_value(), "parallel test function creation must succeed"); - } - - std::atomic Runs = 0; - rcc::MachinePassManager Parallel; - Context.expect(Parallel.addPass(std::make_unique(Runs)).has_value(), - "thread-safe pass registration must succeed"); - rcc::MachineAnalysisManager Prototype; - auto ParallelRun = Parallel.runFunctions(Unit, Target, Prototype, 4); - Context.expect(ParallelRun.has_value() && Runs == Unit.functionCount(), - "parallel function execution must visit every function exactly once"); - - std::atomic DuplicateRuns = 0; - rcc::MachinePassManager Repeated; - Context.expect( - Repeated.addPass(std::make_unique(DuplicateRuns)).has_value() && - Repeated.addPass(std::make_unique(DuplicateRuns)).has_value() && - Repeated.runFunctions(Unit, Target, Prototype, 4).has_value() && - DuplicateRuns == Unit.functionCount() * 2, - "a pipeline must allow the same named pass to run more than once"); - - rcc::MachinePassInstrumentation Instrumentation; - std::vector ObservedFunctions; - std::vector BeforeBlockCounts; - std::vector AfterBlockCounts; - Instrumentation.addBeforeCallback([&ObservedFunctions, &BeforeBlockCounts]( - std::string_view, const rcc::MachineFunction &Function) { - ObservedFunctions.emplace_back(Function.name()); - BeforeBlockCounts.push_back(Function.blockCount()); - }); - Instrumentation.addAfterCallback([&AfterBlockCounts](std::string_view, - const rcc::MachineFunction &Function, - const rcc::MachinePassResult &) { - AfterBlockCounts.push_back(Function.blockCount()); - }); - std::atomic InstrumentedRuns = 0; - std::atomic ActiveRuns = 0; - std::atomic MaximumActiveRuns = 0; - rcc::MachinePassManager Instrumented; - Context.expect( - Instrumented - .addPass(std::make_unique(InstrumentedRuns, ActiveRuns, - MaximumActiveRuns)) - .has_value() && - Instrumented.runFunctions(Unit, Target, Prototype, 4, &Instrumentation).has_value() && - InstrumentedRuns == Unit.functionCount() && MaximumActiveRuns > 1, - "instrumented function pipelines must execute concurrently with a parallel request"); - bool StableCallbackOrder = ObservedFunctions.size() == Unit.functionCount(); - for (std::size_t Index = 0; StableCallbackOrder && Index < ObservedFunctions.size(); ++Index) - StableCallbackOrder = ObservedFunctions[Index] == "f" + std::to_string(Index); - Context.expect(StableCallbackOrder, - "instrumentation callbacks must commit in stable compilation-unit order"); - Context.expect( - BeforeBlockCounts.size() == Unit.functionCount() && - AfterBlockCounts.size() == Unit.functionCount() && - std::ranges::all_of(BeforeBlockCounts, [](std::size_t Count) { return Count == 0; }) && - std::ranges::all_of(AfterBlockCounts, [](std::size_t Count) { return Count == 1; }), - "buffered instrumentation must retain distinct before/after IR snapshots"); - - rcc::MachineAnalysisManager UnsafePrototype; - Context.expect(UnsafePrototype - .registerAnalysis({ - .Name = "NonThreadSafe", - .Dependencies = {}, - .InvalidatedBy = rcc::MachinePassChanges::all(), - .ThreadSafety = rcc::PassThreadSafety::NotThreadSafe, - }) - .has_value(), - "non-thread-safe analysis registration must be explicit"); - rcc::MachinePassManager UnsafeParallel; - Context.expect( - UnsafeParallel.addPass(std::make_unique()).has_value() && - !UnsafeParallel.runFunctions(Unit, Target, UnsafePrototype, 4), - "parallel pipelines must reject a required analysis not marked thread-safe"); - - rcc::CompilationUnitAnalysisManager UnitAnalyses; - Context.expect(UnitAnalyses - .registerAnalysis({ - .Name = "UnitFunctionCount", - .Dependencies = {}, - .InvalidatedBy = rcc::MachinePassChanges::all(), - }) - .has_value(), - "compilation-unit analysis registration must succeed"); - rcc::MachineAnalysisManager FunctionAnalyses; - rcc::CompilationUnitPassManager UnitPipeline; - Context.expect(UnitPipeline.addPass(std::make_unique()).has_value(), - "compilation-unit pass registration must succeed"); - rcc::MachinePassInstrumentation UnitInstrumentation; - std::uint32_t BeforeUnit = 0; - std::uint32_t AfterUnit = 0; - std::uint32_t BeforeUnitAnalysis = 0; - std::uint32_t AfterUnitAnalysis = 0; - std::uint32_t UnitAnalysisCacheHits = 0; - UnitInstrumentation.addBeforeUnitCallback( - [&BeforeUnit](std::string_view, const rcc::CompilationUnit &) { ++BeforeUnit; }); - UnitInstrumentation.addAfterUnitCallback( - [&AfterUnit](std::string_view, const rcc::CompilationUnit &, - const rcc::CompilationUnitPassResult &) { ++AfterUnit; }); - UnitInstrumentation.addBeforeUnitAnalysisCallback( - [&BeforeUnitAnalysis](std::string_view, const rcc::CompilationUnit &) { - ++BeforeUnitAnalysis; - }); - UnitInstrumentation.addAfterUnitAnalysisCallback( - [&AfterUnitAnalysis, &UnitAnalysisCacheHits](std::string_view, const rcc::CompilationUnit &, - bool CacheHit, std::uint64_t) { - ++AfterUnitAnalysis; - UnitAnalysisCacheHits += CacheHit ? 1U : 0U; - }); - Context.expect( - UnitPipeline.run(Unit, Target, UnitAnalyses, FunctionAnalyses, &UnitInstrumentation) - .has_value(), - "compilation-unit pass and analysis must run through their own manager"); - Context.expect(BeforeUnit == 1 && AfterUnit == 1 && BeforeUnitAnalysis == 1 && - AfterUnitAnalysis == 2 && UnitAnalysisCacheHits == 1, - "compilation-unit instrumentation must report pass and analysis cache events"); - - rcc::CompilationUnitAnalysisManager FailingUnitAnalyses; - Context.expect(FailingUnitAnalyses - .registerAnalysis({ - .Name = "FailingUnit", - .Dependencies = {}, - }) - .has_value(), - "failing compilation-unit analysis registration must succeed"); - rcc::CompilationUnitPassManager FailingUnitAnalysisPipeline; - Context.expect( - FailingUnitAnalysisPipeline.addPass(std::make_unique()) - .has_value(), - "a pass requiring a failing unit analysis must register"); - rcc::MachinePassInstrumentation FailingUnitInstrumentation; - std::uint32_t BeforeFailingUnitAnalysis = 0; - std::uint32_t FailingUnitAnalysisEvents = 0; - std::uint32_t RequiredUnitAnalysisPassFailures = 0; - FailingUnitInstrumentation.addBeforeUnitAnalysisCallback( - [&BeforeFailingUnitAnalysis](std::string_view, const rcc::CompilationUnit &) { - ++BeforeFailingUnitAnalysis; - }); - FailingUnitInstrumentation.addUnitAnalysisFailureCallback( - [&FailingUnitAnalysisEvents](std::string_view, const rcc::CompilationUnit &, - const rcc::Error &) { ++FailingUnitAnalysisEvents; }); - FailingUnitInstrumentation.addUnitFailureCallback( - [&RequiredUnitAnalysisPassFailures](std::string_view, const rcc::CompilationUnit &, - const rcc::Error &) { - ++RequiredUnitAnalysisPassFailures; - }); - Context.expect( - !FailingUnitAnalysisPipeline.run(Unit, Target, FailingUnitAnalyses, FunctionAnalyses, - &FailingUnitInstrumentation) && - BeforeFailingUnitAnalysis == 1 && FailingUnitAnalysisEvents == 1 && - RequiredUnitAnalysisPassFailures == 1, - "unit analysis and pass failure instrumentation must report required-analysis failures"); - - rcc::MachineFunction *FirstFunction = Unit.functionAt(0); - Context.expect( - FirstFunction != nullptr && - FunctionAnalyses - .registerAnalysis({ - .Name = "BlockCount", - .Dependencies = {}, - .InvalidatedBy = rcc::MachinePassChanges::all(), - }) - .has_value() && - FunctionAnalyses.getResult(*FirstFunction, Target).has_value(), - "compilation-unit failure cache fixtures must materialize"); - rcc::CompilationUnitPassManager FailingUnitPipeline; - Context.expect( - FirstFunction != nullptr && - FailingUnitPipeline.addPass(std::make_unique()).has_value() && - !FailingUnitPipeline.run(Unit, Target, UnitAnalyses, FunctionAnalyses) && - !UnitAnalyses.hasCached( - Unit, rcc::CompilationUnitAnalysisManager::id()) && - !FunctionAnalyses.hasCached(*FirstFunction, - rcc::MachineAnalysisManager::id()), - "a mutating compilation-unit failure must clear unit and function analysis caches"); -} - -} // namespace - -int main() { - TestContext Context; - auto Target = createTarget(); - Context.expect(Target.has_value(), "machine pass tests require a valid target description"); - if (!Target) - return Context.result(); - - testAnalysisInfrastructure(Context, *Target); - testPassAndInstrumentation(Context, *Target); - testCompilationUnitAndParallelism(Context, *Target); - return Context.result(); -} diff --git a/backend/unittests/CodeGen/MachineSchedulingTest.cpp b/backend/unittests/CodeGen/MachineSchedulingTest.cpp index bcd4100..5162fb8 100644 --- a/backend/unittests/CodeGen/MachineSchedulingTest.cpp +++ b/backend/unittests/CodeGen/MachineSchedulingTest.cpp @@ -386,7 +386,7 @@ void testTargetSchedulingHooks(TestContext &Context, const rcc::TargetDescriptio Context.expect(false, "target scheduling preference model must be created"); return; } - rcc::MachineAnalysisManager Analyses; + rcc::MachineFunctionAnalysisManager Analyses; rcc::MachineSchedulerPass PreferencePass( *PreferenceModel, {.MaximumRegionSize = 8, .EnableBidirectionalScheduling = false}); auto Preferred = PreferencePass.run(*Fixture.Function, Target, Analyses); @@ -408,7 +408,7 @@ void testTargetSchedulingHooks(TestContext &Context, const rcc::TargetDescriptio rcc::MachineInstr *BoundaryFirst = buildADDI(Context, BoundaryBuilder, makeGPR(Context, *BoundaryFixture.Function), X0, 1); (void)buildADDI(Context, BoundaryBuilder, makeGPR(Context, *BoundaryFixture.Function), X0, 2); - rcc::MachineAnalysisManager BoundaryAnalyses; + rcc::MachineFunctionAnalysisManager BoundaryAnalyses; rcc::MachineSchedulerPass BoundaryPass( *BoundaryModel, {.MaximumRegionSize = 8, .EnableBidirectionalScheduling = false}); auto BoundaryResult = BoundaryPass.run(*BoundaryFixture.Function, Target, BoundaryAnalyses); @@ -455,7 +455,7 @@ void testPreRAScheduler(TestContext &Context, const rcc::TargetDescription &Targ buildSchedulingChain(Context, Fixture, Target, false, Short, Long); Context.expect(Fixture.Block->firstInstruction() == Short, "pre-RA fixture must begin in intentionally suboptimal order"); - rcc::MachineAnalysisManager Analyses; + rcc::MachineFunctionAnalysisManager Analyses; rcc::MachineSchedulerPass Pass(rcc::riscv::schedulingModel(), {.MaximumRegionSize = 64, .EnableBidirectionalScheduling = false}); auto Result = Pass.run(*Fixture.Function, Target, Analyses); @@ -482,7 +482,7 @@ void testPostRASchedulerAndLivenessRepair(TestContext &Context, if (!Rebuilt) return; - rcc::MachineAnalysisManager Analyses; + rcc::MachineFunctionAnalysisManager Analyses; rcc::PostRASchedulerPass Pass(rcc::riscv::schedulingModel(), {.MaximumRegionSize = 64, .EnableBidirectionalScheduling = false}); auto Result = Pass.run(*Fixture.Function, Target, Analyses); diff --git a/backend/unittests/CodeGen/PHIEliminationTest.cpp b/backend/unittests/CodeGen/PHIEliminationTest.cpp index 00668e4..9bc9a57 100644 --- a/backend/unittests/CodeGen/PHIEliminationTest.cpp +++ b/backend/unittests/CodeGen/PHIEliminationTest.cpp @@ -4,7 +4,7 @@ #include "SSAExitTestSupport.h" #include "rcc/CodeGen/MachineCFGUpdater.h" -#include "rcc/CodeGen/MachinePass.h" +#include "rcc/CodeGen/MachinePassManager.h" #include "rcc/CodeGen/MachineVerifier.h" #include @@ -62,11 +62,11 @@ buildPhi(rcc::MachineFunction &Function, const rcc::TargetDescription &Target, [[nodiscard]] rcc::Expected runPHIElimination(rcc::MachineFunction &Function, const rcc::TargetDescription &Target, const rcc::TargetInstrInfo &Info) { - rcc::MachinePassManager Pipeline; + rcc::MachineFunctionPassManager Pipeline; auto Added = Pipeline.addPass(std::make_unique(Info)); if (!Added) return std::unexpected(Added.error()); - rcc::MachineAnalysisManager Analyses; + rcc::MachineFunctionAnalysisManager Analyses; return Pipeline.run(Function, Target, Analyses); } @@ -391,7 +391,7 @@ void testUndefAndFailureAtomicity(TestContext &Context, const rcc::TargetDescrip const std::size_t RegistersBefore = Atomic.Function->registerInfo().virtualRegisters().size(); const std::uint64_t PropertiesBefore = Atomic.Function->properties().rawValue(); TestInstrInfo RejectingInfo(true); - rcc::MachineAnalysisManager Analyses; + rcc::MachineFunctionAnalysisManager Analyses; rcc::PHIEliminationPass FailingPass(RejectingInfo); auto Failed = FailingPass.run(*Atomic.Function, Target, Analyses); Context.expect(!Failed && Failed.error().code() == rcc::ErrorCode::Unsupported, diff --git a/backend/unittests/CodeGen/PassInstrumentationTest.cpp b/backend/unittests/CodeGen/PassInstrumentationTest.cpp new file mode 100644 index 0000000..97ce445 --- /dev/null +++ b/backend/unittests/CodeGen/PassInstrumentationTest.cpp @@ -0,0 +1,173 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "Target/TestTarget.h" +#include "rcc/CodeGen/GenericOpcodes.h" +#include "rcc/CodeGen/MachineFunction.h" +#include "rcc/CodeGen/MachinePassManager.h" + +#include +#include +#include +#include +#include +#include +#include + +namespace { + +class TestContext final { +public: + void expect(bool Condition, std::string_view Message) { + if (Condition) + return; + std::cerr << Message << '\n'; + ++Failures; + } + + [[nodiscard]] int result() const noexcept { + return Failures == 0 ? 0 : 1; + } + +private: + int Failures = 0; +}; + +[[nodiscard]] rcc::Expected createTarget() { + std::vector Descriptors; + std::vector Predicates; + auto Appended = rcc::appendGenericInstructionInfo(Descriptors, Predicates); + if (!Appended) + return std::unexpected(Appended.error()); + auto Instructions = rcc::InstructionSet::create(std::move(Descriptors), std::move(Predicates)); + if (!Instructions) + return std::unexpected(Instructions.error()); + return rcc::test::createTestTargetDescription(std::move(*Instructions)); +} + +class BlockCountAnalysis final { +public: + struct Result final { + std::size_t Count = 0; + }; + + [[nodiscard]] static constexpr std::string_view name() noexcept { + return "BlockCount"; + } + + [[nodiscard]] static rcc::Expected run(rcc::MachineFunction &Function, + const rcc::TargetDescription &, + rcc::MachineFunctionAnalysisManager &) { + return Result{Function.blockCount()}; + } +}; + +class InstrumentedPass final : public rcc::MachineFunctionPass { +public: + [[nodiscard]] const rcc::MachinePassContract &contract() const noexcept override { + static const rcc::MachinePassContract Contract{ + .Name = "Instrumented", + .Requires = {}, + .Sets = {}, + .Clears = {}, + .RequiredAnalyses = + { + rcc::MachineFunctionAnalysisManager::id(), + }, + .VerificationStage = std::nullopt, + }; + return Contract; + } + + [[nodiscard]] rcc::Expected + run(rcc::MachineFunction &Function, const rcc::TargetDescription &Target, + rcc::MachineFunctionAnalysisManager &Analyses) override { + auto First = Analyses.getResult(Function, Target); + auto Second = Analyses.getResult(Function, Target); + auto FirstAction = Analyses.requestAction("first", Function); + auto SecondAction = Analyses.requestAction("second", Function); + if (!First || !Second || !FirstAction || !SecondAction || !*FirstAction || *SecondAction) + return rcc::makeUnexpected(rcc::ErrorCode::VerificationError, + "instrumentation action policy was not enforced"); + rcc::MachinePassResult Result; + Result.Preserved = rcc::PreservedAnalyses::all(); + return Result; + } +}; + +void testInstrumentation(TestContext &Context, const rcc::TargetDescription &Target) { + auto Function = + rcc::MachineFunction::create("instrumentation", rcc::MachineFunctionStableID::fromValue(1)); + Context.expect(Function.has_value(), "instrumentation function creation must succeed"); + if (!Function) + return; + + rcc::MachineFunctionAnalysisManager Analyses; + Context.expect(Analyses + .registerAnalysis({ + .Name = "BlockCount", + .Dependencies = {}, + .InvalidatedBy = rcc::MachinePassChanges::all(), + .ThreadSafety = rcc::PassThreadSafety::ThreadSafe, + }) + .has_value(), + "instrumentation analysis registration must succeed"); + + rcc::MachinePassInstrumentation Instrumentation; + Instrumentation.setPerFunctionFuel(1); + std::uint32_t BeforePass = 0; + std::uint32_t AfterPass = 0; + std::uint32_t BeforeAnalysis = 0; + std::uint32_t AfterAnalysis = 0; + std::uint32_t CacheHits = 0; + std::uint32_t Printed = 0; + std::uint32_t Changes = 0; + Instrumentation.addBeforeCallback( + [&BeforePass](std::string_view, const rcc::MachineFunction &) { ++BeforePass; }); + Instrumentation.addAfterCallback([&AfterPass](std::string_view, const rcc::MachineFunction &, + const rcc::MachinePassResult &) { ++AfterPass; }); + Instrumentation.addBeforeAnalysisCallback( + [&BeforeAnalysis](std::string_view, const rcc::MachineFunction &) { ++BeforeAnalysis; }); + Instrumentation.addAfterAnalysisCallback( + [&AfterAnalysis, &CacheHits](std::string_view, const rcc::MachineFunction &, bool CacheHit, + std::uint64_t) { + ++AfterAnalysis; + CacheHits += CacheHit ? 1U : 0U; + }); + Instrumentation.addIRPrintCallback([&Printed](rcc::InstrumentationPhase, std::string_view, + const rcc::MachineFunction &) { ++Printed; }); + Instrumentation.addChangeCallback([&Changes](std::string_view, const rcc::MachineFunction &, + rcc::MachinePassChanges ReportedChanges, + bool FingerprintChanged) { + if (ReportedChanges.empty() && !FingerprintChanged) + ++Changes; + }); + + rcc::MachineFunctionPassManager Pipeline; + Context.expect(Pipeline.addPass(std::make_unique()).has_value() && + Pipeline.run(**Function, Target, Analyses, &Instrumentation).has_value(), + "instrumented pass must run"); + Context.expect(BeforePass == 1 && AfterPass == 1 && BeforeAnalysis == 1 && AfterAnalysis == 3 && + CacheHits == 2 && Printed == 2 && Changes == 1, + "all pass and analysis instrumentation points must run"); + + const auto Events = Instrumentation.actionEvents(); + Context.expect(Events.size() == 2 && Events[0].Accepted && !Events[1].Accepted, + "action instrumentation must record accepted and rejected decisions"); + const auto Statistics = Instrumentation.statistics(); + Context.expect(Statistics.size() == 2, + "instrumentation must collect one pass and one analysis statistic"); +} + +} // namespace + +int main() { + TestContext Context; + auto Target = createTarget(); + Context.expect(Target.has_value(), + "pass instrumentation tests require a valid target description"); + if (!Target) + return Context.result(); + + testInstrumentation(Context, *Target); + return Context.result(); +} diff --git a/backend/unittests/CodeGen/PassManagerTest.cpp b/backend/unittests/CodeGen/PassManagerTest.cpp new file mode 100644 index 0000000..56c30f3 --- /dev/null +++ b/backend/unittests/CodeGen/PassManagerTest.cpp @@ -0,0 +1,260 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "Target/TestTarget.h" +#include "rcc/CodeGen/GenericOpcodes.h" +#include "rcc/CodeGen/MachineFunction.h" +#include "rcc/CodeGen/MachineFunctionAnalysisManager.h" + +#include +#include +#include +#include +#include +#include +#include + +namespace { + +class TestContext final { +public: + void expect(bool Condition, std::string_view Message) { + if (Condition) + return; + std::cerr << Message << '\n'; + ++Failures; + } + + [[nodiscard]] int result() const noexcept { + return Failures == 0 ? 0 : 1; + } + +private: + int Failures = 0; +}; + +[[nodiscard]] rcc::Expected createTarget() { + std::vector Descriptors; + std::vector Predicates; + auto Appended = rcc::appendGenericInstructionInfo(Descriptors, Predicates); + if (!Appended) + return std::unexpected(Appended.error()); + auto Instructions = rcc::InstructionSet::create(std::move(Descriptors), std::move(Predicates)); + if (!Instructions) + return std::unexpected(Instructions.error()); + return rcc::test::createTestTargetDescription(std::move(*Instructions)); +} + +class BlockCountAnalysis final { +public: + struct Result final { + std::size_t Count = 0; + }; + + [[nodiscard]] static constexpr std::string_view name() noexcept { + return "BlockCount"; + } + + [[nodiscard]] static rcc::Expected run(rcc::MachineFunction &Function, + const rcc::TargetDescription &, + rcc::MachineFunctionAnalysisManager &) { + ++Runs; + return Result{Function.blockCount()}; + } + + static inline std::atomic Runs = 0; +}; + +class DependentAnalysis final { +public: + struct Result final { + std::size_t Count = 0; + }; + + [[nodiscard]] static constexpr std::string_view name() noexcept { + return "Dependent"; + } + + [[nodiscard]] static rcc::Expected run(rcc::MachineFunction &Function, + const rcc::TargetDescription &Target, + rcc::MachineFunctionAnalysisManager &Analyses) { + auto Blocks = Analyses.getResult(Function, Target); + if (!Blocks) + return std::unexpected(Blocks.error()); + return Result{(*Blocks)->Count}; + } +}; + +class StickyAnalysis final { +public: + struct Result final { + [[nodiscard]] bool invalidate(const rcc::MachineFunction &, + const rcc::PreservedAnalyses &) noexcept { + return false; + } + }; + + [[nodiscard]] static constexpr std::string_view name() noexcept { + return "Sticky"; + } + + [[nodiscard]] static rcc::Expected run(rcc::MachineFunction &, + const rcc::TargetDescription &, + rcc::MachineFunctionAnalysisManager &) { + return Result{}; + } +}; + +class ExpiringAnalysis final { +public: + struct Result final { + [[nodiscard]] bool invalidate(const rcc::MachineFunction &, + const rcc::PreservedAnalyses &) noexcept { + return true; + } + }; + + [[nodiscard]] static constexpr std::string_view name() noexcept { + return "Expiring"; + } + + [[nodiscard]] static rcc::Expected run(rcc::MachineFunction &, + const rcc::TargetDescription &, + rcc::MachineFunctionAnalysisManager &) { + return Result{}; + } +}; + +class CycleA final { +public: + struct Result final {}; + + [[nodiscard]] static constexpr std::string_view name() noexcept { + return "CycleA"; + } + + [[nodiscard]] static rcc::Expected run(rcc::MachineFunction &, + const rcc::TargetDescription &, + rcc::MachineFunctionAnalysisManager &) { + return Result{}; + } +}; + +class CycleB final { +public: + struct Result final {}; + + [[nodiscard]] static constexpr std::string_view name() noexcept { + return "CycleB"; + } + + [[nodiscard]] static rcc::Expected run(rcc::MachineFunction &, + const rcc::TargetDescription &, + rcc::MachineFunctionAnalysisManager &) { + return Result{}; + } +}; + +void testAnalysisManager(TestContext &Context, const rcc::TargetDescription &Target) { + auto Function = + rcc::MachineFunction::create("analysis", rcc::MachineFunctionStableID::fromValue(1)); + Context.expect(Function.has_value(), "analysis function creation must succeed"); + if (!Function) + return; + + rcc::MachineFunctionAnalysisManager Analyses; + Context.expect(Analyses + .registerAnalysis({ + .Name = "BlockCount", + .Dependencies = {}, + .InvalidatedBy = {rcc::MachinePassChange::CFG}, + }) + .has_value(), + "base analysis registration must succeed"); + Context.expect(Analyses + .registerAnalysis({ + .Name = "Dependent", + .Dependencies = + { + rcc::MachineFunctionAnalysisManager::id(), + }, + .InvalidatedBy = {rcc::MachinePassChange::Operands}, + }) + .has_value(), + "dependent analysis registration must succeed"); + + BlockCountAnalysis::Runs = 0; + auto First = Analyses.getResult(**Function, Target); + auto Second = Analyses.getResult(**Function, Target); + Context.expect(First && Second && *First == *Second && BlockCountAnalysis::Runs == 1, + "analysis dependencies must materialize once and then use the cache"); + + Analyses.invalidate(**Function, rcc::PreservedAnalyses::none(), + {rcc::MachinePassChange::Registers}); + Context.expect(Analyses.cachedResultCount(**Function) == 2, + "unrelated changes must preserve cached analyses precisely"); + Analyses.invalidate(**Function, rcc::PreservedAnalyses::none(), {rcc::MachinePassChange::CFG}); + Context.expect(Analyses.cachedResultCount(**Function) == 0, + "invalidating a dependency must invalidate its dependent analysis"); + + rcc::MachineFunctionAnalysisManager Cyclic; + Context.expect( + Cyclic.registerAnalysis({ + .Name = "CycleA", + .Dependencies = + { + rcc::MachineFunctionAnalysisManager::id(), + }, + }) + .has_value() && + Cyclic + .registerAnalysis({ + .Name = "CycleB", + .Dependencies = + { + rcc::MachineFunctionAnalysisManager::id(), + }, + }) + .has_value(), + "cyclic analysis registrations must be accepted until requested"); + Context.expect(!Cyclic.getResult(**Function, Target), + "analysis dependency cycles must produce a structured error"); + + rcc::MachineFunctionAnalysisManager CustomInvalidation; + Context.expect(CustomInvalidation + .registerAnalysis({ + .Name = "Sticky", + .Dependencies = {}, + .InvalidatedBy = {rcc::MachinePassChange::CFG}, + }) + .has_value() && + CustomInvalidation + .registerAnalysis({ + .Name = "Expiring", + .Dependencies = {}, + .InvalidatedBy = {rcc::MachinePassChange::CFG}, + }) + .has_value() && + CustomInvalidation.getResult(**Function, Target) && + CustomInvalidation.getResult(**Function, Target), + "custom invalidation analyses must materialize"); + CustomInvalidation.invalidate(**Function, rcc::PreservedAnalyses::none(), + {rcc::MachinePassChange::CFG}); + Context.expect(CustomInvalidation.hasCached( + **Function, rcc::MachineFunctionAnalysisManager::id()) && + !CustomInvalidation.hasCached( + **Function, rcc::MachineFunctionAnalysisManager::id()), + "analysis invalidate() must return false to preserve and true to invalidate"); +} + +} // namespace + +int main() { + TestContext Context; + auto Target = createTarget(); + Context.expect(Target.has_value(), "pass manager tests require a valid target description"); + if (!Target) + return Context.result(); + + testAnalysisManager(Context, *Target); + return Context.result(); +} diff --git a/backend/unittests/CodeGen/RegisterAllocationTest.cpp b/backend/unittests/CodeGen/RegisterAllocationTest.cpp index 1a7c5c7..7dd0dd0 100644 --- a/backend/unittests/CodeGen/RegisterAllocationTest.cpp +++ b/backend/unittests/CodeGen/RegisterAllocationTest.cpp @@ -14,7 +14,7 @@ #include "rcc/CodeGen/MachineInstr.h" #include "rcc/CodeGen/MachineMemOperand.h" #include "rcc/CodeGen/MachineOperand.h" -#include "rcc/CodeGen/MachinePass.h" +#include "rcc/CodeGen/MachinePassManager.h" #include "rcc/CodeGen/MachineRegisterInfo.h" #include "rcc/CodeGen/RegAllocCommon.h" #include "rcc/CodeGen/RegAllocFast.h" @@ -496,7 +496,7 @@ enum class AllocatorKind : std::uint8_t { const rcc::TargetRegisterAllocationInfo &Info, AllocatorKind Kind, rcc::RegisterAllocationOptions Options = {}) { - rcc::MachineAnalysisManager Analyses; + rcc::MachineFunctionAnalysisManager Analyses; auto Registered = rcc::registerStage11MachineAnalyses(Analyses); if (!Registered) return std::unexpected(Registered.error()); @@ -512,7 +512,7 @@ enum class AllocatorKind : std::uint8_t { Pass = std::make_unique(Info, Options); break; } - rcc::MachinePassManager Pipeline; + rcc::MachineFunctionPassManager Pipeline; auto Added = Pipeline.addPass(std::move(Pass)); if (!Added) return std::unexpected(Added.error()); @@ -603,7 +603,7 @@ void testLiveRegMatrix(TestContext &Context, const rcc::TargetDescription &Targe } if (!rcc::rebuildMachineLiveness(*LaneFixture->Function, Target)) return; - rcc::MachineAnalysisManager LaneAnalyses; + rcc::MachineFunctionAnalysisManager LaneAnalyses; if (!rcc::registerStage11MachineAnalyses(LaneAnalyses)) return; auto LaneIntervals = @@ -632,7 +632,7 @@ void testLiveRegMatrix(TestContext &Context, const rcc::TargetDescription &Targe } if (!rcc::rebuildMachineLiveness(*FixedFixture->Function, Target)) return; - rcc::MachineAnalysisManager FixedAnalyses; + rcc::MachineFunctionAnalysisManager FixedAnalyses; if (!rcc::registerStage11MachineAnalyses(FixedAnalyses)) return; auto FixedIntervals = @@ -664,7 +664,7 @@ void testLiveRegMatrix(TestContext &Context, const rcc::TargetDescription &Targe !rcc::rebuildMachineLiveness(*FixedLaneFixture->Function, Target)) { return; } - rcc::MachineAnalysisManager FixedLaneAnalyses; + rcc::MachineFunctionAnalysisManager FixedLaneAnalyses; if (!rcc::registerStage11MachineAnalyses(FixedLaneAnalyses)) return; auto FixedLaneIntervals = @@ -694,7 +694,7 @@ void testSharedUnitLaneMatrix(TestContext &Context, const rcc::TargetDescription !rcc::rebuildMachineLiveness(*Fixture->Function, Target)) { return; } - rcc::MachineAnalysisManager Analyses; + rcc::MachineFunctionAnalysisManager Analyses; if (!rcc::registerStage11MachineAnalyses(Analyses)) return; auto Intervals = Analyses.getResult(*Fixture->Function, Target); diff --git a/backend/unittests/CodeGen/RegisterAllocationTestSupport.h b/backend/unittests/CodeGen/RegisterAllocationTestSupport.h index 49c9e8a..d93b14e 100644 --- a/backend/unittests/CodeGen/RegisterAllocationTestSupport.h +++ b/backend/unittests/CodeGen/RegisterAllocationTestSupport.h @@ -436,7 +436,7 @@ public: const TargetRegisterAllocationInfo &Info, AllocatorKind Kind, RegisterAllocationOptions Options = {}) { - MachineAnalysisManager Analyses; + MachineFunctionAnalysisManager Analyses; auto Registered = registerStage11MachineAnalyses(Analyses); if (!Registered) return std::unexpected(Registered.error()); @@ -452,7 +452,7 @@ public: Pass = std::make_unique(Info, Options); break; } - MachinePassManager Pipeline; + MachineFunctionPassManager Pipeline; auto Added = Pipeline.addPass(std::move(Pass)); if (!Added) return std::unexpected(Added.error()); diff --git a/backend/unittests/CodeGen/SlotIndexesTest.cpp b/backend/unittests/CodeGen/SlotIndexesTest.cpp index d34ff84..9d3f54b 100644 --- a/backend/unittests/CodeGen/SlotIndexesTest.cpp +++ b/backend/unittests/CodeGen/SlotIndexesTest.cpp @@ -25,7 +25,7 @@ void testSlotIndexes(TestContext &Context, const rcc::TargetDescription &Target) return; } - rcc::MachineAnalysisManager Analyses; + rcc::MachineFunctionAnalysisManager Analyses; auto Registered = rcc::registerStage11MachineAnalyses(Analyses); auto Indexes = Registered diff --git a/backend/unittests/CodeGen/TwoAddressInstructionPassTest.cpp b/backend/unittests/CodeGen/TwoAddressInstructionPassTest.cpp index 6853a36..e3ad4eb 100644 --- a/backend/unittests/CodeGen/TwoAddressInstructionPassTest.cpp +++ b/backend/unittests/CodeGen/TwoAddressInstructionPassTest.cpp @@ -3,7 +3,7 @@ #include "rcc/CodeGen/TwoAddressInstructionPass.h" #include "SSAExitTestSupport.h" -#include "rcc/CodeGen/MachinePass.h" +#include "rcc/CodeGen/MachinePassManager.h" #include "rcc/CodeGen/MachineVerifier.h" #include @@ -130,11 +130,11 @@ void testTwoAddressAndSubregisterPseudos(TestContext &Context, const rcc::Target if (!InitialLiveness) return; Function.properties().set(rcc::MachineFunctionProperty::NoPHIs); - rcc::MachinePassManager Pipeline; + rcc::MachineFunctionPassManager Pipeline; Context.expect( Pipeline.addPass(std::make_unique(Info)).has_value(), "two-address pass must be registered"); - rcc::MachineAnalysisManager Analyses; + rcc::MachineFunctionAnalysisManager Analyses; auto Run = Pipeline.run(Function, Target, Analyses); Context.expect(Run.has_value(), "two-address rewrite must succeed"); if (!Run) @@ -238,7 +238,7 @@ void testTwoAddressAndSubregisterPseudos(TestContext &Context, const rcc::Target const std::uint64_t AtomicPropertiesBefore = AtomicFixture.Function->properties().rawValue(); TestInstrInfo RejectingInfo(true); - rcc::MachineAnalysisManager AtomicAnalyses; + rcc::MachineFunctionAnalysisManager AtomicAnalyses; rcc::TwoAddressInstructionPass FailingPass(RejectingInfo); auto Failed = FailingPass.run(*AtomicFixture.Function, Target, AtomicAnalyses); Context.expect(!Failed && Failed.error().code() == rcc::ErrorCode::Unsupported, diff --git a/backend/unittests/Target/RISCVFrameLoweringTest.cpp b/backend/unittests/Target/RISCVFrameLoweringTest.cpp index 285e962..23f1b49 100644 --- a/backend/unittests/Target/RISCVFrameLoweringTest.cpp +++ b/backend/unittests/Target/RISCVFrameLoweringTest.cpp @@ -12,7 +12,7 @@ #include "rcc/CodeGen/MachineInstr.h" #include "rcc/CodeGen/MachineMemOperand.h" #include "rcc/CodeGen/MachineOperand.h" -#include "rcc/CodeGen/MachinePass.h" +#include "rcc/CodeGen/MachinePassManager.h" #include "rcc/CodeGen/PrologueEpilogueInsertion.h" #include "rcc/CodeGen/RegisterMask.h" #include "rcc/CodeGen/TargetDescription.h" @@ -216,12 +216,12 @@ void setFramePassProperties(rcc::MachineFunction &Function) { runFrameLoweringWith(rcc::MachineFunction &Function, const rcc::TargetDescription &Target, const rcc::TargetFrameLowering &FrameLowering) { setFramePassProperties(Function); - rcc::MachinePassManager Pipeline; + rcc::MachineFunctionPassManager Pipeline; auto Added = Pipeline.addPass(std::make_unique(FrameLowering)); if (!Added) return std::unexpected(Added.error()); - rcc::MachineAnalysisManager Analyses; + rcc::MachineFunctionAnalysisManager Analyses; return Pipeline.run(Function, Target, Analyses); } diff --git a/backend/unittests/Target/RISCVLateCodeGenTest.cpp b/backend/unittests/Target/RISCVLateCodeGenTest.cpp index 702f058..868d18f 100644 --- a/backend/unittests/Target/RISCVLateCodeGenTest.cpp +++ b/backend/unittests/Target/RISCVLateCodeGenTest.cpp @@ -18,7 +18,7 @@ #include "rcc/CodeGen/MachineMemoryFolding.h" #include "rcc/CodeGen/MachineOperand.h" #include "rcc/CodeGen/MachineOptimizationPipeline.h" -#include "rcc/CodeGen/MachinePass.h" +#include "rcc/CodeGen/MachinePassManager.h" #include "rcc/CodeGen/MachinePseudoExpansion.h" #include "rcc/CodeGen/MachineShrinkWrapping.h" #include "rcc/CodeGen/MachineStackSlotColoring.h" @@ -376,7 +376,7 @@ void testBlockPlacement(TestContext &Context, const rcc::TargetDescription &Targ CFG.addSuccessor(*Entry, *Hot, *HotProbability).has_value(), "placement CFG construction must succeed"); setSelectedProperties(*Function); - rcc::MachineAnalysisManager Analyses; + rcc::MachineFunctionAnalysisManager Analyses; rcc::MachineBlockPlacementPass Pass; auto Result = Pass.run(*Function, Target, Analyses); if (!Result) @@ -410,7 +410,7 @@ void testFallthroughNormalization(TestContext &Context, const rcc::TargetDescrip setPostRAProperties(*Function); auto Liveness = rcc::rebuildMachineLiveness(*Function, Target); Context.expect(Liveness.has_value(), "fallthrough fixture liveness must be rebuilt"); - rcc::MachineAnalysisManager Analyses; + rcc::MachineFunctionAnalysisManager Analyses; rcc::MachineFallthroughPass Pass(rcc::riscv::instrInfo()); auto Result = Pass.run(*Function, Target, Analyses); if (!Result) @@ -445,7 +445,7 @@ void testFallthroughMaterialization(TestContext &Context, const rcc::TargetDescr setPostRAProperties(*Function); Context.expect(rcc::rebuildMachineLiveness(*Function, Target).has_value(), "materialized fallthrough liveness must be rebuilt"); - rcc::MachineAnalysisManager Analyses; + rcc::MachineFunctionAnalysisManager Analyses; rcc::MachineFallthroughPass Pass(rcc::riscv::instrInfo()); auto Result = Pass.run(*Function, Target, Analyses); if (!Result) @@ -486,7 +486,7 @@ void testBranchOptimization(TestContext &Context, const rcc::TargetDescription & return; } setSelectedProperties(*Function); - rcc::MachineAnalysisManager Analyses; + rcc::MachineFunctionAnalysisManager Analyses; rcc::MachineBranchOptimizationPass Pass(rcc::riscv::instrInfo()); auto Result = Pass.run(*Function, Target, Analyses); if (!Result) @@ -522,7 +522,7 @@ void testBranchOptimization(TestContext &Context, const rcc::TargetDescription & return; } setSelectedProperties(*ConstantFunction); - rcc::MachineAnalysisManager ConstantAnalyses; + rcc::MachineFunctionAnalysisManager ConstantAnalyses; auto ConstantResult = Pass.run(*ConstantFunction, Target, ConstantAnalyses); if (!ConstantResult) std::cerr << "constant branch folding failure: " << ConstantResult.error().message() << '\n'; @@ -566,7 +566,7 @@ void testTailDuplication(TestContext &Context, const rcc::TargetDescription &Tar return; } setRelaxationProperties(Context, *Function, Target); - rcc::MachineAnalysisManager Analyses; + rcc::MachineFunctionAnalysisManager Analyses; rcc::MachineTailDuplicationPass Pass(rcc::riscv::instrInfo()); Tail->attributes().set(rcc::MachineBasicBlockAttribute::MachineBlockAddressTaken); auto Protected = Pass.run(*Function, Target, Analyses); @@ -617,7 +617,7 @@ void testTailMerge(TestContext &Context, const rcc::TargetDescription &Target) { return; } setRelaxationProperties(Context, *Function, Target); - rcc::MachineAnalysisManager Analyses; + rcc::MachineFunctionAnalysisManager Analyses; rcc::MachineTailMergePass Pass(rcc::riscv::instrInfo()); Second->attributes().set(rcc::MachineBasicBlockAttribute::MachineBlockAddressTaken); auto Protected = Pass.run(*Function, Target, Analyses); @@ -662,7 +662,7 @@ void testCopyPropagation(TestContext &Context, const rcc::TargetDescription &Tar if (Add == nullptr) return; setSelectedProperties(*Function); - rcc::MachineAnalysisManager Analyses; + rcc::MachineFunctionAnalysisManager Analyses; rcc::MachineCopyPropagationPass PreRA(rcc::riscv::instrInfo(), rcc::MachineCopyPropagationStage::PreRegisterAllocation); auto PreResult = PreRA.run(*Function, Target, Analyses); @@ -702,7 +702,7 @@ void testCopyPropagation(TestContext &Context, const rcc::TargetDescription &Tar setPostRAProperties(*PostFunction); Context.expect(rcc::rebuildMachineLiveness(*PostFunction, Target).has_value(), "post-RA COPY propagation liveness must be rebuilt"); - rcc::MachineAnalysisManager PostAnalyses; + rcc::MachineFunctionAnalysisManager PostAnalyses; rcc::MachineCopyPropagationPass PostRA(rcc::riscv::instrInfo(), rcc::MachineCopyPropagationStage::PostRegisterAllocation); auto PostResult = PostRA.run(*PostFunction, Target, PostAnalyses); @@ -752,7 +752,7 @@ void testStackSlotColoring(TestContext &Context, const rcc::TargetDescription &T setPostRAProperties(*Function); Context.expect(rcc::rebuildMachineLiveness(*Function, Target).has_value(), "stack-slot coloring liveness must be rebuilt"); - rcc::MachineAnalysisManager Analyses; + rcc::MachineFunctionAnalysisManager Analyses; rcc::MachineStackSlotColoringPass Pass; auto Result = Pass.run(*Function, Target, Analyses); if (!Result) @@ -836,7 +836,7 @@ void testRISCVMemoryFoldingBoundary(TestContext &Context, const rcc::TargetDescr return; setSelectedProperties(*Function); Function->properties().set(rcc::MachineFunctionProperty::IsSSA); - rcc::MachineAnalysisManager Analyses; + rcc::MachineFunctionAnalysisManager Analyses; rcc::MachineMemoryFoldingPass Pass(rcc::riscv::memoryFoldingInfo()); auto Result = Pass.run(*Function, Target, Analyses); if (!Result) @@ -894,7 +894,7 @@ void testShrinkWrappedFrameRegion(TestContext &Context, const rcc::TargetDescrip setPostRAProperties(*Function); Context.expect(rcc::rebuildMachineLiveness(*Function, Target).has_value(), "shrink-wrapping fixture liveness must be rebuilt"); - rcc::MachineAnalysisManager Analyses; + rcc::MachineFunctionAnalysisManager Analyses; rcc::MachineShrinkWrappingPass Shrink{rcc::riscv::frameLowering()}; auto Shrunk = Shrink.run(*Function, Target, Analyses); Context.expect(Shrunk && Shrunk->Changed && @@ -906,7 +906,7 @@ void testShrinkWrappedFrameRegion(TestContext &Context, const rcc::TargetDescrip if (!Shrunk) return; - rcc::MachinePassManager FramePipeline; + rcc::MachineFunctionPassManager FramePipeline; Context.expect(FramePipeline .addPass(std::make_unique( rcc::riscv::frameLowering())) @@ -975,7 +975,7 @@ void testCompressedAndConditionalRelaxation(TestContext &Context, if (Conditional == nullptr) return; setRelaxationProperties(Context, *Function, Target); - rcc::MachineAnalysisManager Analyses; + rcc::MachineFunctionAnalysisManager Analyses; rcc::MachineBranchRelaxationPass Pass(rcc::riscv::instrInfo()); auto Result = Pass.run(*Function, Target, Analyses); if (!Result) @@ -1108,7 +1108,7 @@ void testPseudoPreparation(TestContext &Context, const rcc::TargetDescription &T if (!Copy) return; setSelectedProperties(*Function); - rcc::MachineAnalysisManager Analyses; + rcc::MachineFunctionAnalysisManager Analyses; rcc::PreparePostRAPseudosPass Pass(rcc::riscv::pseudoExpansionInfo()); auto Result = Pass.run(*Function, Target, Analyses); Context.expect(Result && Result->Changed && (*Copy)->operandAt(0)->targetFlags() == 16 && @@ -1170,7 +1170,7 @@ void testPostRAPseudoExpansionAndFinalization(TestContext &Context, setRelaxationProperties(Context, *Function, Target); Function->properties().clear(rcc::MachineFunctionProperty::NoExecutablePseudos); - rcc::MachineAnalysisManager Analyses; + rcc::MachineFunctionAnalysisManager Analyses; rcc::ExpandPostRAPseudosPass Expansion(rcc::riscv::pseudoExpansionInfo()); auto Expanded = Expansion.run(*Function, Target, Analyses); if (!Expanded) @@ -1196,7 +1196,7 @@ void testPostRAPseudoExpansionAndFinalization(TestContext &Context, if (!Expanded) return; - rcc::MachinePassManager Pipeline; + rcc::MachineFunctionPassManager Pipeline; Context.expect(Pipeline.addPass(std::make_unique()) && Pipeline.addPass(std::make_unique( rcc::riscv::instrInfo())), @@ -1213,8 +1213,8 @@ void testCanonicalOptimizationPipelines(TestContext &Context, const rcc::TargetDescription &Target) { const rcc::MachineOptimizationPipelineTargetInfo TargetInfo = rcc::riscv::optimizationPipelineInfo(); - rcc::MachinePassManager SelectedPipeline; - rcc::MachinePassManager PreRAPipeline; + rcc::MachineFunctionPassManager SelectedPipeline; + rcc::MachineFunctionPassManager PreRAPipeline; Context.expect(rcc::addSelectedSSAOptimizationPipeline(SelectedPipeline, TargetInfo) && SelectedPipeline.size() == 6, "canonical selected-SSA optimization pipeline must register completely"); @@ -1259,13 +1259,13 @@ void testCanonicalOptimizationPipelines(TestContext &Context, return; } - rcc::MachinePassManager Pipeline; + rcc::MachineFunctionPassManager Pipeline; auto Added = rcc::addPostRegisterAllocationPipeline(Pipeline, TargetInfo); Context.expect(Added && Pipeline.size() == 20, "canonical post-RA pipeline must register every required pass"); if (!Added) return; - rcc::MachineAnalysisManager Analyses; + rcc::MachineFunctionAnalysisManager Analyses; auto Registered = rcc::registerMachineOptimizationAnalyses(Analyses); Context.expect(Registered.has_value(), "canonical optimization analyses must register completely"); @@ -1325,7 +1325,7 @@ void testTargetLateExpansionRejectsSizeGrowth(TestContext &Context) { GrowingLatePseudoInfo ExpansionInfo; FixedSizeInstrInfo InstrInfo; rcc::TargetLatePseudoExpansionPass Pass(ExpansionInfo, InstrInfo); - rcc::MachineAnalysisManager Analyses; + rcc::MachineFunctionAnalysisManager Analyses; auto Result = Pass.run(*Function, *Target, Analyses); Context.expect(!Result && Result.error().code() == rcc::ErrorCode::PseudoExpansionFailed && (*Pseudo)->parent() == Block && Block->firstInstruction() == *Pseudo && @@ -1373,7 +1373,7 @@ void testTargetLateExpansionRejectsCompensatedGrowth(TestContext &Context) { GrowingLatePseudoInfo ExpansionInfo; FixedSizeInstrInfo InstrInfo; rcc::TargetLatePseudoExpansionPass Pass(ExpansionInfo, InstrInfo); - rcc::MachineAnalysisManager Analyses; + rcc::MachineFunctionAnalysisManager Analyses; auto Result = Pass.run(*Function, *Target, Analyses); Context.expect( !Result && Result.error().code() == rcc::ErrorCode::PseudoExpansionFailed && @@ -1403,7 +1403,7 @@ void testFinalEncodabilityRejectsInvalidInstruction(TestContext &Context, return; } setRelaxationProperties(Context, *ImmediateFunction, Target); - rcc::MachineAnalysisManager Analyses; + rcc::MachineFunctionAnalysisManager Analyses; rcc::FinalEncodabilityVerifierPass Verifier(rcc::riscv::instrInfo()); auto ImmediateResult = Verifier.run(*ImmediateFunction, Target, Analyses); Context.expect(!ImmediateResult && diff --git a/backend/unittests/Target/RISCVRegisterAllocationTest.cpp b/backend/unittests/Target/RISCVRegisterAllocationTest.cpp index 0e60e63..acd4b3a 100644 --- a/backend/unittests/Target/RISCVRegisterAllocationTest.cpp +++ b/backend/unittests/Target/RISCVRegisterAllocationTest.cpp @@ -11,7 +11,7 @@ #include "rcc/CodeGen/MachineInstr.h" #include "rcc/CodeGen/MachineMemOperand.h" #include "rcc/CodeGen/MachineOperand.h" -#include "rcc/CodeGen/MachinePass.h" +#include "rcc/CodeGen/MachinePassManager.h" #include "rcc/CodeGen/MachineRegisterInfo.h" #include "rcc/CodeGen/RegAllocCommon.h" #include "rcc/CodeGen/RegAllocFast.h" @@ -168,7 +168,7 @@ enum class AllocatorKind : std::uint8_t { const rcc::TargetDescription &Target, AllocatorKind Kind, rcc::RegisterAllocationOptions Options = {}) { - rcc::MachineAnalysisManager Analyses; + rcc::MachineFunctionAnalysisManager Analyses; auto Registered = rcc::registerStage11MachineAnalyses(Analyses); if (!Registered) return std::unexpected(Registered.error()); @@ -184,7 +184,7 @@ enum class AllocatorKind : std::uint8_t { Pass = std::make_unique(rcc::riscv::registerAllocationInfo(), Options); break; } - rcc::MachinePassManager Pipeline; + rcc::MachineFunctionPassManager Pipeline; auto Added = Pipeline.addPass(std::move(Pass)); if (!Added) return std::unexpected(Added.error()); diff --git a/backend/unittests/Target/RISCVSSAExitTest.cpp b/backend/unittests/Target/RISCVSSAExitTest.cpp index ab30572..ec98bd1 100644 --- a/backend/unittests/Target/RISCVSSAExitTest.cpp +++ b/backend/unittests/Target/RISCVSSAExitTest.cpp @@ -10,7 +10,7 @@ #include "rcc/CodeGen/MachineIRBuilder.h" #include "rcc/CodeGen/MachineInstr.h" #include "rcc/CodeGen/MachineOperand.h" -#include "rcc/CodeGen/MachinePass.h" +#include "rcc/CodeGen/MachinePassManager.h" #include "rcc/CodeGen/MachineVerifier.h" #include "rcc/CodeGen/PHIElimination.h" #include "rcc/Target/RISCV/RISCVTarget.h" @@ -352,12 +352,12 @@ void testRV64GCCriticalEdge(TestContext &Context, const rcc::TargetDescription & if (!InitialLiveness) return; - rcc::MachinePassManager Pipeline; + rcc::MachineFunctionPassManager Pipeline; Context.expect( Pipeline.addPass(std::make_unique(rcc::riscv::instrInfo())) .has_value(), "RV64GC PHI-elimination pass must be registered"); - rcc::MachineAnalysisManager Analyses; + rcc::MachineFunctionAnalysisManager Analyses; auto Run = Pipeline.run(**Function, Target, Analyses); Context.expect(Run.has_value(), "RV64GC critical-edge PHI elimination must succeed"); if (!Run) -- cgit v1.2.3