diff options
| author | Richard-Qin-X <richard.qin.001@gmail.com> | 2026-08-13 05:45:37 +0800 |
|---|---|---|
| committer | Richard-Qin-X <richard.qin.001@gmail.com> | 2026-08-13 05:45:37 +0800 |
| commit | 236082a0fe4dcd0362c5c74923a93e3db6a01291 (patch) | |
| tree | 5d8a329ca526b087b6ce51895b5135997e8e03bd /backend | |
| parent | a2f8d7c5e22b510965327383410bd576f7cf28e7 (diff) | |
| download | rcc-project-236082a0fe4dcd0362c5c74923a93e3db6a01291.tar.gz rcc-project-236082a0fe4dcd0362c5c74923a93e3db6a01291.tar.xz | |
[CodeGen] Align pass manager ownership
Diffstat (limited to 'backend')
108 files changed, 2435 insertions, 2534 deletions
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<MachinePassResult> run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses) override; + MachineFunctionAnalysisManager &Analyses) override; private: [[nodiscard]] Expected<MachinePassResult> 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 <memory> @@ -20,7 +20,7 @@ public: [[nodiscard]] const MachinePassContract &contract() const noexcept override; [[nodiscard]] Expected<MachinePassResult> run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses) override; + MachineFunctionAnalysisManager &Analyses) override; private: [[nodiscard]] Expected<MachinePassResult> 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<MachinePassResult> 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 <cstdint> @@ -64,8 +64,9 @@ public: return "LiveIntervals"; } - [[nodiscard]] static Expected<Result> - run(MachineFunction &Function, const TargetDescription &Target, MachineAnalysisManager &Analyses); + [[nodiscard]] static Expected<Result> 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<Result> - run(MachineFunction &Function, const TargetDescription &Target, MachineAnalysisManager &Analyses); + [[nodiscard]] static Expected<Result> 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<MachinePassResult> run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses) override; + MachineFunctionAnalysisManager &Analyses) override; }; [[nodiscard]] Expected<void> verifyTrackedMachineLiveness(const MachineFunction &Function, const TargetDescription &Target); [[nodiscard]] Expected<bool> rebuildMachineLiveness(MachineFunction &Function, const TargetDescription &Target); -[[nodiscard]] Expected<void> registerStage11MachineAnalyses(MachineAnalysisManager &Analyses); +[[nodiscard]] Expected<void> +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<Result> - run(MachineFunction &Function, const TargetDescription &Target, MachineAnalysisManager &Analyses); + [[nodiscard]] static Expected<Result> run(MachineFunction &Function, + const TargetDescription &Target, + MachineFunctionAnalysisManager &Analyses); }; struct MachineLoop final { @@ -107,8 +108,9 @@ public: return "MachineLoopInfo"; } - [[nodiscard]] static Expected<Result> - run(MachineFunction &Function, const TargetDescription &Target, MachineAnalysisManager &Analyses); + [[nodiscard]] static Expected<Result> run(MachineFunction &Function, + const TargetDescription &Target, + MachineFunctionAnalysisManager &Analyses); }; class MachineBranchProbabilityAnalysis final { @@ -130,8 +132,9 @@ public: return "MachineBranchProbability"; } - [[nodiscard]] static Expected<Result> - run(MachineFunction &Function, const TargetDescription &Target, MachineAnalysisManager &Analyses); + [[nodiscard]] static Expected<Result> run(MachineFunction &Function, + const TargetDescription &Target, + MachineFunctionAnalysisManager &Analyses); }; class MachineBlockFrequencyAnalysis final { @@ -152,8 +155,9 @@ public: return "MachineBlockFrequency"; } - [[nodiscard]] static Expected<Result> - run(MachineFunction &Function, const TargetDescription &Target, MachineAnalysisManager &Analyses); + [[nodiscard]] static Expected<Result> run(MachineFunction &Function, + const TargetDescription &Target, + MachineFunctionAnalysisManager &Analyses); }; enum class MachineAliasResult : std::uint8_t { @@ -175,8 +179,9 @@ public: return "MachineAliasAnalysis"; } - [[nodiscard]] static Expected<Result> - run(MachineFunction &Function, const TargetDescription &Target, MachineAnalysisManager &Analyses); + [[nodiscard]] static Expected<Result> run(MachineFunction &Function, + const TargetDescription &Target, + MachineFunctionAnalysisManager &Analyses); }; enum class MachineMemoryDependencyKind : std::uint8_t { @@ -233,11 +238,13 @@ public: return "MachineMemoryDependence"; } - [[nodiscard]] static Expected<Result> - run(MachineFunction &Function, const TargetDescription &Target, MachineAnalysisManager &Analyses); + [[nodiscard]] static Expected<Result> run(MachineFunction &Function, + const TargetDescription &Target, + MachineFunctionAnalysisManager &Analyses); }; -[[nodiscard]] Expected<void> registerStage8MachineAnalyses(MachineAnalysisManager &Analyses); +[[nodiscard]] Expected<void> +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<MachinePassResult> run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses) override; + MachineFunctionAnalysisManager &Analyses) override; private: - [[nodiscard]] Expected<MachinePassResult> runImplementation(MachineFunction &Function, - const TargetDescription &Target, - MachineAnalysisManager &Analyses, - MachineActionReplay &Actions) const; + [[nodiscard]] Expected<MachinePassResult> + 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 <cstddef> @@ -24,7 +24,7 @@ public: [[nodiscard]] const MachinePassContract &contract() const noexcept override; [[nodiscard]] Expected<MachinePassResult> run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses) override; + MachineFunctionAnalysisManager &Analyses) override; private: [[nodiscard]] Expected<MachinePassResult> 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 <cstddef> @@ -24,7 +24,7 @@ public: [[nodiscard]] const MachinePassContract &contract() const noexcept override; [[nodiscard]] Expected<MachinePassResult> run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses) override; + MachineFunctionAnalysisManager &Analyses) override; private: [[nodiscard]] Expected<MachinePassResult> 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 <cstddef> @@ -20,12 +20,12 @@ public: [[nodiscard]] const MachinePassContract &contract() const noexcept override; [[nodiscard]] Expected<MachinePassResult> run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses) override; + MachineFunctionAnalysisManager &Analyses) override; private: - [[nodiscard]] Expected<MachinePassResult> runImplementation(MachineFunction &Function, - const TargetDescription &Target, - MachineAnalysisManager &Analyses); + [[nodiscard]] Expected<MachinePassResult> + 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 <cstddef> @@ -24,7 +24,7 @@ public: [[nodiscard]] const MachinePassContract &contract() const noexcept override; [[nodiscard]] Expected<MachinePassResult> run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses) override; + MachineFunctionAnalysisManager &Analyses) override; private: [[nodiscard]] Expected<MachinePassResult> 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 <cstddef> #include <cstdint> @@ -30,7 +30,7 @@ public: [[nodiscard]] const MachinePassContract &contract() const noexcept override; [[nodiscard]] Expected<MachinePassResult> run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses) override; + MachineFunctionAnalysisManager &Analyses) override; private: [[nodiscard]] Expected<MachinePassResult> 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<MachinePassResult> run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses) override; + MachineFunctionAnalysisManager &Analyses) override; private: [[nodiscard]] Expected<MachinePassResult> 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<MachinePassResult> 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<MachinePassResult> 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<MachinePassResult> 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 <cstdint> +#include <initializer_list> + +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<MachinePassChange> 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<std::uint32_t>(Change); + } + + [[nodiscard]] constexpr bool has(MachinePassChange Change) const noexcept { + return (Bits & static_cast<std::uint32_t>(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<MachineFunction, MachinePassInstrumentation> 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<bool> requestAction(MachinePassInstrumentation *Instrumentation, + std::string_view Pass, std::string_view Rule, + const MachineFunction &Function, + MachineInstrStableID Instruction, + std::uint64_t Cost); + [[nodiscard]] static Expected<bool> requestAction(MachinePassInstrumentation *Instrumentation, + std::string_view Pass, std::string_view Rule, + const MachineFunction &Function, std::nullptr_t, + std::uint64_t Cost); +}; + +template <> +struct AnalysisManagerInstrumentation<CompilationUnit, MachinePassInstrumentation> 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<MachinePassChanges>; +using CompilationUnitAnalysisRegistration = AnalysisRegistration<MachinePassChanges>; + +using MachineFunctionAnalysisManager = + AnalysisManager<MachineFunction, MachineAnalysisRegistration, MachinePassChanges, + MachinePassInstrumentation>; +using CompilationUnitAnalysisManager = + AnalysisManager<CompilationUnit, CompilationUnitAnalysisRegistration, MachinePassChanges, + MachinePassInstrumentation>; + +[[nodiscard]] Expected<void> +registerStage8MachineAnalyses(MachineFunctionAnalysisManager &Analyses); +[[nodiscard]] Expected<void> +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 <cstddef> #include <cstdint> @@ -29,12 +29,12 @@ public: [[nodiscard]] const MachinePassContract &contract() const noexcept override; [[nodiscard]] Expected<MachinePassResult> run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses) override; + MachineFunctionAnalysisManager &Analyses) override; private: - [[nodiscard]] Expected<MachinePassResult> runImplementation(MachineFunction &Function, - const TargetDescription &Target, - MachineAnalysisManager &Analyses); + [[nodiscard]] Expected<MachinePassResult> + 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 <cstddef> @@ -24,7 +24,7 @@ public: [[nodiscard]] const MachinePassContract &contract() const noexcept override; [[nodiscard]] Expected<MachinePassResult> run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses) override; + MachineFunctionAnalysisManager &Analyses) override; private: [[nodiscard]] Expected<MachinePassResult> 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<void> registerMachineOptimizationAnalyses(MachineAnalysisManager &Analyses); +[[nodiscard]] Expected<void> +registerMachineOptimizationAnalyses(MachineFunctionAnalysisManager &Analyses); [[nodiscard]] Expected<void> -addSelectedSSAOptimizationPipeline(MachinePassManager &Pipeline, +addSelectedSSAOptimizationPipeline(MachineFunctionPassManager &Pipeline, const MachineOptimizationPipelineTargetInfo &TargetInfo); [[nodiscard]] Expected<void> addPreRegisterAllocationOptimizationPipeline( - MachinePassManager &Pipeline, const MachineOptimizationPipelineTargetInfo &TargetInfo); + MachineFunctionPassManager &Pipeline, const MachineOptimizationPipelineTargetInfo &TargetInfo); [[nodiscard]] Expected<void> -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 <concepts> -#include <cstddef> -#include <cstdint> -#include <functional> -#include <initializer_list> -#include <memory> -#include <mutex> -#include <optional> -#include <span> -#include <string> -#include <string_view> -#include <unordered_map> -#include <unordered_set> -#include <utility> -#include <vector> - -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<MachinePassChange> 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<std::uint32_t>(Change); - } - - [[nodiscard]] constexpr bool has(MachinePassChange Change) const noexcept { - return (Bits & static_cast<std::uint32_t>(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 <typename AnalysisT> void preserve() { - preserve(analysisID<AnalysisT>()); - } - - [[nodiscard]] bool preserves(AnalysisID ID) const noexcept { - return PreserveAll || (ID != nullptr && Preserved.contains(ID)); - } - - [[nodiscard]] bool preservesAll() const noexcept { - return PreserveAll; - } - - template <typename AnalysisT> [[nodiscard]] static AnalysisID analysisID() noexcept { - static const std::uint8_t Token = 0; - return &Token; - } - -private: - bool PreserveAll = false; - std::unordered_set<AnalysisID> Preserved; -}; - -enum class PassThreadSafety : std::uint8_t { - NotThreadSafe, - ThreadSafe, -}; - -struct PassParameter final { - std::string Name; - std::string Description; - std::optional<std::string> DefaultValue; - bool Required = false; -}; - -struct MachinePassRegistrationMetadata { - std::vector<PassParameter> Parameters; - PassThreadSafety ThreadSafety = PassThreadSafety::NotThreadSafe; - MachinePassChanges DeclaredChanges = MachinePassChanges::all(); -}; - -struct MachinePassContract final : MachinePassRegistrationMetadata { - std::string Name; - MachineFunctionProperties Requires; - MachineFunctionProperties Sets; - MachineFunctionProperties Clears; - std::vector<AnalysisID> RequiredAnalyses; - std::optional<PipelineStage> VerificationStage; -}; - -struct MachinePassResult final { - bool Changed = false; - MachinePassChanges Changes; - PreservedAnalyses Preserved = PreservedAnalyses::none(); -}; - -struct CompilationUnitPassContract final { - std::string Name; - std::vector<AnalysisID> RequiredAnalyses; - std::vector<PassParameter> 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<AnalysisID> Dependencies; - MachinePassChanges InvalidatedBy = MachinePassChanges::all(); - PassThreadSafety ThreadSafety = PassThreadSafety::NotThreadSafe; -}; - -struct CompilationUnitAnalysisRegistration final { - AnalysisID ID = nullptr; - std::string Name; - std::vector<AnalysisID> 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 <typename AnalysisT> [[nodiscard]] static AnalysisID id() noexcept { - return PreservedAnalyses::analysisID<AnalysisT>(); - } - - template <typename AnalysisT> - [[nodiscard]] Expected<void> registerAnalysis(MachineAnalysisRegistration Registration = {}) { - using ResultT = typename AnalysisT::Result; - if (Registration.ID == nullptr) - Registration.ID = id<AnalysisT>(); - if (Registration.Name.empty()) { - if constexpr (requires { - { AnalysisT::name() } -> std::convertible_to<std::string_view>; - }) { - Registration.Name = std::string(AnalysisT::name()); - } else { - Registration.Name = "unnamed-machine-analysis"; - } - } - - ErasedRunner Runner = [](MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Manager) -> Expected<std::shared_ptr<void>> { - auto Computed = AnalysisT::run(Function, Target, Manager); - if (!Computed) - return std::unexpected(Computed.error()); - return std::shared_ptr<void>(new ResultT(std::move(*Computed)), - [](void *Value) { delete static_cast<ResultT *>(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<bool>; - }) { - return static_cast<ResultT *>(Value)->invalidate(Function, Preserved); - } - return true; - }; - return registerAnalysisImpl(std::move(Registration), std::move(Runner), std::move(Invalidator)); - } - - template <typename AnalysisT> - [[nodiscard]] Expected<typename AnalysisT::Result *> getResult(MachineFunction &Function, - const TargetDescription &Target) { - const AnalysisID Key = id<AnalysisT>(); - if (!isRegistered(Key)) { - auto Registered = registerAnalysis<AnalysisT>(); - if (!Registered) - return std::unexpected(Registered.error()); - } - auto Result = getResultImpl(Key, Function, Target); - if (!Result) - return std::unexpected(Result.error()); - return static_cast<typename AnalysisT::Result *>(*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<std::unique_ptr<MachineAnalysisManager>> forkEmpty() const; - [[nodiscard]] Expected<bool> - requestAction(std::string_view Action, const MachineFunction &Function, std::uint64_t Cost = 1); - [[nodiscard]] Expected<bool> requestAction(std::string_view Rule, const MachineFunction &Function, - MachineInstrStableID Instruction, - std::uint64_t Cost = 1); - -private: - using ErasedRunner = std::function<Expected<std::shared_ptr<void>>( - MachineFunction &, const TargetDescription &, MachineAnalysisManager &)>; - using ErasedInvalidator = - std::function<bool(void *, const MachineFunction &, const PreservedAnalyses &)>; - - struct RegisteredAnalysis final { - MachineAnalysisRegistration Info; - ErasedRunner Runner; - ErasedInvalidator Invalidator; - }; - - struct CacheEntry final { - std::shared_ptr<void> Value; - AnalysisID ID = nullptr; - }; - - [[nodiscard]] Expected<void> registerAnalysisImpl(MachineAnalysisRegistration Registration, - ErasedRunner Runner, - ErasedInvalidator Invalidator); - [[nodiscard]] Expected<void *> getResultImpl(AnalysisID ID, MachineFunction &Function, - const TargetDescription &Target); - [[nodiscard]] Expected<void> materializeDependencies(const RegisteredAnalysis &Registration, - MachineFunction &Function, - const TargetDescription &Target); - [[nodiscard]] Expected<void> - validateParallelRequirements(std::span<const AnalysisID> RequiredAnalyses) const; - void setInstrumentation(MachinePassInstrumentation *NewInstrumentation) noexcept { - Instrumentation = NewInstrumentation; - } - - std::unordered_map<AnalysisID, RegisteredAnalysis> Registry; - std::unordered_map<MachineFunction *, std::unordered_map<AnalysisID, CacheEntry>> Cache; - std::unordered_map<MachineFunction *, std::vector<AnalysisID>> ActiveComputations; - MachinePassInstrumentation *Instrumentation = nullptr; - std::string ActivePass; - - friend class MachinePassManager; - friend class CompilationUnitPassManager; - friend Expected<void> registerStage8MachineAnalyses(MachineAnalysisManager &Analyses); - friend Expected<void> 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 <typename AnalysisT> [[nodiscard]] static AnalysisID id() noexcept { - return PreservedAnalyses::analysisID<AnalysisT>(); - } - - template <typename AnalysisT> - [[nodiscard]] Expected<void> - registerAnalysis(CompilationUnitAnalysisRegistration Registration = {}) { - using ResultT = typename AnalysisT::Result; - if (Registration.ID == nullptr) - Registration.ID = id<AnalysisT>(); - if (Registration.Name.empty()) { - if constexpr (requires { - { AnalysisT::name() } -> std::convertible_to<std::string_view>; - }) { - Registration.Name = std::string(AnalysisT::name()); - } else { - Registration.Name = "unnamed-compilation-unit-analysis"; - } - } - - ErasedRunner Runner = - [](CompilationUnit &Unit, const TargetDescription &Target, - CompilationUnitAnalysisManager &Manager) -> Expected<std::shared_ptr<void>> { - auto Computed = AnalysisT::run(Unit, Target, Manager); - if (!Computed) - return std::unexpected(Computed.error()); - return std::shared_ptr<void>(new ResultT(std::move(*Computed)), - [](void *Value) { delete static_cast<ResultT *>(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<bool>; - }) { - return static_cast<ResultT *>(Value)->invalidate(Unit, Preserved); - } - return true; - }; - return registerAnalysisImpl(std::move(Registration), std::move(Runner), std::move(Invalidator)); - } - - template <typename AnalysisT> - [[nodiscard]] Expected<typename AnalysisT::Result *> getResult(CompilationUnit &Unit, - const TargetDescription &Target) { - const AnalysisID Key = id<AnalysisT>(); - if (!isRegistered(Key)) { - auto Registered = registerAnalysis<AnalysisT>(); - if (!Registered) - return std::unexpected(Registered.error()); - } - auto Result = getResultImpl(Key, Unit, Target); - if (!Result) - return std::unexpected(Result.error()); - return static_cast<typename AnalysisT::Result *>(*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<Expected<std::shared_ptr<void>>( - CompilationUnit &, const TargetDescription &, CompilationUnitAnalysisManager &)>; - using ErasedInvalidator = - std::function<bool(void *, const CompilationUnit &, const PreservedAnalyses &)>; - - struct RegisteredAnalysis final { - CompilationUnitAnalysisRegistration Info; - ErasedRunner Runner; - ErasedInvalidator Invalidator; - }; - - struct CacheEntry final { - std::shared_ptr<void> Value; - AnalysisID ID = nullptr; - }; - - [[nodiscard]] Expected<void> - registerAnalysisImpl(CompilationUnitAnalysisRegistration Registration, ErasedRunner Runner, - ErasedInvalidator Invalidator); - [[nodiscard]] Expected<void *> getResultImpl(AnalysisID ID, CompilationUnit &Unit, - const TargetDescription &Target); - [[nodiscard]] Expected<void> materializeDependencies(const RegisteredAnalysis &Registration, - CompilationUnit &Unit, - const TargetDescription &Target); - void setInstrumentation(MachinePassInstrumentation *NewInstrumentation) noexcept { - Instrumentation = NewInstrumentation; - } - - std::unordered_map<AnalysisID, RegisteredAnalysis> Registry; - std::unordered_map<CompilationUnit *, std::unordered_map<AnalysisID, CacheEntry>> Cache; - std::unordered_map<CompilationUnit *, std::vector<AnalysisID>> 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<MachinePassResult> 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<CompilationUnitPassResult> - 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<MachineInstrStableID, MachineInstrStableID> &SourceToClone) - : Analyses(&Analyses) { - for (const auto &[Source, Clone] : SourceToClone) - RecordingInstructionIDs.try_emplace(Clone, Source); - } - - [[nodiscard]] Expected<bool> request(std::string_view Rule, const MachineFunction &Function, - MachineInstrStableID Instruction = {}, - std::uint64_t Cost = 1); - void beginReplay() noexcept; - [[nodiscard]] Expected<void> 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<MachineInstrStableID, MachineInstrStableID> RecordingInstructionIDs; - std::vector<Decision> Decisions; - std::size_t NextDecision = 0; - bool IsReplaying = false; -}; - -class MachinePassInstrumentation final { -public: - using BeforeCallback = std::function<void(std::string_view, const MachineFunction &)>; - using AfterCallback = - std::function<void(std::string_view, const MachineFunction &, const MachinePassResult &)>; - using FailureCallback = - std::function<void(std::string_view, const MachineFunction &, const Error &)>; - using BeforeAnalysisCallback = std::function<void(std::string_view, const MachineFunction &)>; - using AfterAnalysisCallback = - std::function<void(std::string_view, const MachineFunction &, bool, std::uint64_t)>; - using AnalysisFailureCallback = - std::function<void(std::string_view, const MachineFunction &, const Error &)>; - using IRPrintCallback = - std::function<void(InstrumentationPhase, std::string_view, const MachineFunction &)>; - using ChangeCallback = - std::function<void(std::string_view, const MachineFunction &, MachinePassChanges, bool)>; - using ActionFilter = std::function<bool(const MachineActionID &, std::uint64_t)>; - - using BeforeUnitCallback = std::function<void(std::string_view, const CompilationUnit &)>; - using AfterUnitCallback = std::function<void(std::string_view, const CompilationUnit &, - const CompilationUnitPassResult &)>; - using UnitFailureCallback = - std::function<void(std::string_view, const CompilationUnit &, const Error &)>; - using BeforeUnitAnalysisCallback = std::function<void(std::string_view, const CompilationUnit &)>; - using AfterUnitAnalysisCallback = - std::function<void(std::string_view, const CompilationUnit &, bool, std::uint64_t)>; - using UnitAnalysisFailureCallback = - std::function<void(std::string_view, const CompilationUnit &, const Error &)>; - - 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<std::uint64_t> 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<InstrumentationStatistic> statistics() const; - [[nodiscard]] std::vector<MachineActionEvent> actionEvents() const; - void clearStatistics(); - -private: - struct BufferedEvents final { - const TargetDescription *Target = nullptr; - std::vector<std::function<void()>> Events; - }; - - [[nodiscard]] bool bufferFunctionEvent(const MachineFunction &Function, - std::function<void(const MachineFunction &)> 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<bool> 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<BeforeCallback> Before; - std::vector<AfterCallback> After; - std::vector<FailureCallback> Failure; - std::vector<BeforeAnalysisCallback> BeforeAnalysis; - std::vector<AfterAnalysisCallback> AfterAnalysis; - std::vector<AnalysisFailureCallback> AnalysisFailure; - std::vector<IRPrintCallback> IRPrint; - std::vector<ChangeCallback> Change; - ActionFilter Filter; - std::optional<std::uint64_t> PerFunctionFuel; - std::unordered_map<std::uint64_t, std::uint64_t> ConsumedFuel; - std::vector<MachineActionEvent> ActionEvents; - - std::vector<BeforeUnitCallback> BeforeUnit; - std::vector<AfterUnitCallback> AfterUnit; - std::vector<UnitFailureCallback> UnitFailure; - std::vector<BeforeUnitAnalysisCallback> BeforeUnitAnalysis; - std::vector<AfterUnitAnalysisCallback> AfterUnitAnalysis; - std::vector<UnitAnalysisFailureCallback> UnitAnalysisFailure; - mutable std::unordered_map<std::string, InstrumentationStatistic> 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<std::unique_ptr<MachineFunctionPass>>; - - explicit MachinePassManager(MachinePassManagerOptions Options = {}) : Options(Options) {} - - MachinePassManager(const MachinePassManager &) = delete; - MachinePassManager &operator=(const MachinePassManager &) = delete; - - [[nodiscard]] Expected<void> addPass(std::unique_ptr<MachineFunctionPass> Pass); - [[nodiscard]] Expected<void> run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses, - MachinePassInstrumentation *Instrumentation = nullptr) const; - [[nodiscard]] Expected<void> - 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<void> 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<void> addPass(std::unique_ptr<CompilationUnitPass> Pass); - [[nodiscard]] Expected<void> run(CompilationUnit &Unit, const TargetDescription &Target, - CompilationUnitAnalysisManager &UnitAnalyses, - MachineAnalysisManager &FunctionAnalyses, - MachinePassInstrumentation *Instrumentation = nullptr) const; - -private: - CompilationUnitPassManagerOptions Options; - std::vector<std::unique_ptr<CompilationUnitPass>> 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 <cstddef> +#include <memory> +#include <optional> +#include <string> +#include <vector> + +namespace rcc { + +class CompilationUnit; +class MachineFunction; +class TargetDescription; + +struct MachinePassRegistrationMetadata { + std::vector<PassParameter> Parameters; + PassThreadSafety ThreadSafety = PassThreadSafety::NotThreadSafe; + MachinePassChanges DeclaredChanges = MachinePassChanges::all(); +}; + +struct MachinePassContract final : MachinePassRegistrationMetadata { + std::string Name; + MachineFunctionProperties Requires; + MachineFunctionProperties Sets; + MachineFunctionProperties Clears; + std::vector<AnalysisID> RequiredAnalyses; + std::optional<PipelineStage> VerificationStage; +}; + +struct MachinePassResult final { + bool Changed = false; + MachinePassChanges Changes; + PreservedAnalyses Preserved = PreservedAnalyses::none(); +}; + +struct CompilationUnitPassContract final { + std::string Name; + std::vector<AnalysisID> RequiredAnalyses; + std::vector<PassParameter> 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<MachinePassResult> + 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<CompilationUnitPassResult> + 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<MachineFunction, MachineFunctionPass, MachinePassManagerOptions> final { + using PassList = std::vector<std::unique_ptr<MachineFunctionPass>>; + + [[nodiscard]] static Expected<void> validate(const MachineFunctionPass &Pass); + [[nodiscard]] static Expected<void> + run(const PassList &Passes, const MachinePassManagerOptions &Options, MachineFunction &Function, + const TargetDescription &Target, MachineFunctionAnalysisManager &Analyses, + MachinePassInstrumentation *Instrumentation = nullptr); + [[nodiscard]] static Expected<void> + 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<MachineFunction, MachineFunctionPass, MachinePassManagerOptions>; + +struct CompilationUnitPassManagerOptions final { + bool VerifyBefore = true; + bool VerifyEach = true; +}; + +template <> +struct PassManagerCallbacks<CompilationUnit, CompilationUnitPass, CompilationUnitPassManagerOptions> + final { + using PassList = std::vector<std::unique_ptr<CompilationUnitPass>>; + + [[nodiscard]] static Expected<void> validate(const CompilationUnitPass &Pass); + [[nodiscard]] static Expected<void> run(const PassList &Passes, + const CompilationUnitPassManagerOptions &Options, + CompilationUnit &Unit, const TargetDescription &Target, + CompilationUnitAnalysisManager &UnitAnalyses, + MachineFunctionAnalysisManager &FunctionAnalyses, + MachinePassInstrumentation *Instrumentation = nullptr); +}; + +using CompilationUnitPassManager = + PassManager<CompilationUnit, CompilationUnitPass, CompilationUnitPassManagerOptions>; + +} // 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<MachinePassResult> 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<MachinePassResult> 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<MachinePassResult> 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<MachinePassResult> 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 <cstddef> @@ -25,7 +25,7 @@ public: [[nodiscard]] const MachinePassContract &contract() const noexcept override; [[nodiscard]] Expected<MachinePassResult> 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 <cstddef> @@ -24,7 +24,7 @@ public: [[nodiscard]] const MachinePassContract &contract() const noexcept override; [[nodiscard]] Expected<MachinePassResult> 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<MachinePassResult> run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses) override; + MachineFunctionAnalysisManager &Analyses) override; private: - [[nodiscard]] Expected<MachinePassResult> runImplementation(MachineFunction &Function, - const TargetDescription &Target, - MachineAnalysisManager &Analyses); + [[nodiscard]] Expected<MachinePassResult> + 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 <cstddef> @@ -21,7 +21,7 @@ public: [[nodiscard]] const MachinePassContract &contract() const noexcept override; [[nodiscard]] Expected<MachinePassResult> run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses) override; + MachineFunctionAnalysisManager &Analyses) override; private: [[nodiscard]] Expected<MachinePassResult> 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 <cstddef> @@ -25,7 +25,7 @@ public: [[nodiscard]] const MachinePassContract &contract() const noexcept override; [[nodiscard]] Expected<MachinePassResult> run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses) override; + MachineFunctionAnalysisManager &Analyses) override; private: [[nodiscard]] Expected<MachinePassResult> 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 <cstddef> @@ -24,7 +24,7 @@ public: [[nodiscard]] const MachinePassContract &contract() const noexcept override; [[nodiscard]] Expected<MachinePassResult> run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses) override; + MachineFunctionAnalysisManager &Analyses) override; private: [[nodiscard]] Expected<MachinePassResult> 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<MachinePassResult> run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses) override; + MachineFunctionAnalysisManager &Analyses) override; private: [[nodiscard]] Expected<MachinePassResult> 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<MachinePassResult> 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<MachinePassResult> run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses) override; + MachineFunctionAnalysisManager &Analyses) override; private: [[nodiscard]] Expected<MachinePassResult> 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 <memory> 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<MachinePassResult> 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<MachinePassResult> 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<Result> - run(MachineFunction &Function, const TargetDescription &Target, MachineAnalysisManager &Analyses); + [[nodiscard]] static Expected<Result> 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<MachinePassResult> run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses) override; + MachineFunctionAnalysisManager &Analyses) override; private: [[nodiscard]] Expected<MachinePassResult> 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 <cstdint> @@ -82,7 +82,7 @@ public: [[nodiscard]] const MachinePassContract &contract() const noexcept override; [[nodiscard]] Expected<MachinePassResult> 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 <cstdint> +#include <functional> +#include <mutex> +#include <optional> +#include <string> +#include <string_view> +#include <unordered_map> +#include <vector> + +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<void(std::string_view, const MachineFunction &)>; + using AfterCallback = + std::function<void(std::string_view, const MachineFunction &, const MachinePassResult &)>; + using FailureCallback = + std::function<void(std::string_view, const MachineFunction &, const Error &)>; + using BeforeAnalysisCallback = std::function<void(std::string_view, const MachineFunction &)>; + using AfterAnalysisCallback = + std::function<void(std::string_view, const MachineFunction &, bool, std::uint64_t)>; + using AnalysisFailureCallback = + std::function<void(std::string_view, const MachineFunction &, const Error &)>; + using IRPrintCallback = + std::function<void(InstrumentationPhase, std::string_view, const MachineFunction &)>; + using ChangeCallback = + std::function<void(std::string_view, const MachineFunction &, MachinePassChanges, bool)>; + using ActionFilter = std::function<bool(const MachineActionID &, std::uint64_t)>; + + using BeforeUnitCallback = std::function<void(std::string_view, const CompilationUnit &)>; + using AfterUnitCallback = std::function<void(std::string_view, const CompilationUnit &, + const CompilationUnitPassResult &)>; + using UnitFailureCallback = + std::function<void(std::string_view, const CompilationUnit &, const Error &)>; + using BeforeUnitAnalysisCallback = std::function<void(std::string_view, const CompilationUnit &)>; + using AfterUnitAnalysisCallback = + std::function<void(std::string_view, const CompilationUnit &, bool, std::uint64_t)>; + using UnitAnalysisFailureCallback = + std::function<void(std::string_view, const CompilationUnit &, const Error &)>; + + 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<std::uint64_t> 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<InstrumentationStatistic> statistics() const; + [[nodiscard]] std::vector<MachineActionEvent> actionEvents() const; + + [[nodiscard]] Expected<bool> requestAction(std::string_view Pass, std::string_view Rule, + const MachineFunction &Function, + MachineInstrStableID Instruction, std::uint64_t Cost); + [[nodiscard]] Expected<bool> 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<std::function<void()>> Events; + }; + + [[nodiscard]] bool bufferFunctionEvent(const MachineFunction &Function, + std::function<void(const MachineFunction &)> 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<BeforeCallback> Before; + std::vector<AfterCallback> After; + std::vector<FailureCallback> Failure; + std::vector<BeforeAnalysisCallback> BeforeAnalysis; + std::vector<AfterAnalysisCallback> AfterAnalysis; + std::vector<AnalysisFailureCallback> AnalysisFailure; + std::vector<IRPrintCallback> IRPrint; + std::vector<ChangeCallback> Change; + ActionFilter Filter; + std::optional<std::uint64_t> PerFunctionFuel; + std::unordered_map<std::uint64_t, std::uint64_t> ConsumedFuel; + std::vector<MachineActionEvent> ActionEvents; + + std::vector<BeforeUnitCallback> BeforeUnit; + std::vector<AfterUnitCallback> AfterUnit; + std::vector<UnitFailureCallback> UnitFailure; + std::vector<BeforeUnitAnalysisCallback> BeforeUnitAnalysis; + std::vector<AfterUnitAnalysisCallback> AfterUnitAnalysis; + std::vector<UnitAnalysisFailureCallback> UnitAnalysisFailure; + mutable std::unordered_map<std::string, InstrumentationStatistic> Statistics; + + static thread_local BufferedEvents *ActiveBuffer; + + template <typename, typename> friend struct AnalysisManagerInstrumentation; + template <typename, typename, typename> friend struct PassManagerCallbacks; +}; + +class MachineActionReplay final { +public: + template <typename AnalysisManagerT> + 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 <typename AnalysisManagerT> + MachineActionReplay( + AnalysisManagerT &Analyses, + const std::unordered_map<MachineInstrStableID, MachineInstrStableID> &SourceToClone) + : MachineActionReplay(Analyses) { + for (const auto &[Source, Clone] : SourceToClone) + RecordingInstructionIDs.try_emplace(Clone, Source); + } + + [[nodiscard]] Expected<bool> request(std::string_view Rule, const MachineFunction &Function, + MachineInstrStableID Instruction = {}, + std::uint64_t Cost = 1); + void beginReplay() noexcept; + [[nodiscard]] Expected<void> finishReplay() const; + +private: + struct Decision final { + std::string Rule; + MachineFunctionStableID Function; + MachineInstrStableID Instruction; + std::uint64_t Cost = 0; + bool Accepted = false; + }; + + std::function<Expected<bool>(std::string_view, const MachineFunction &, MachineInstrStableID, + std::uint64_t)> + Request; + std::unordered_map<MachineInstrStableID, MachineInstrStableID> RecordingInstructionIDs; + std::vector<Decision> 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 <algorithm> +#include <chrono> +#include <concepts> +#include <cstddef> +#include <cstdint> +#include <functional> +#include <memory> +#include <optional> +#include <ranges> +#include <set> +#include <span> +#include <string> +#include <string_view> +#include <unordered_map> +#include <unordered_set> +#include <utility> +#include <vector> + +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 <typename AnalysisT> void preserve() { + preserve(analysisID<AnalysisT>()); + } + + [[nodiscard]] bool preserves(AnalysisID ID) const noexcept { + return PreserveAll || (ID != nullptr && Preserved.contains(ID)); + } + + [[nodiscard]] bool preservesAll() const noexcept { + return PreserveAll; + } + + template <typename AnalysisT> [[nodiscard]] static AnalysisID analysisID() noexcept { + static const std::uint8_t Token = 0; + return &Token; + } + +private: + bool PreserveAll = false; + std::unordered_set<AnalysisID> Preserved; +}; + +enum class PassThreadSafety : std::uint8_t { + NotThreadSafe, + ThreadSafe, +}; + +struct PassParameter final { + std::string Name; + std::string Description; + std::optional<std::string> DefaultValue; + bool Required = false; +}; + +template <typename IRUnitT, typename InstrumentationT> 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 <typename InstructionT> + [[nodiscard]] static Expected<bool> requestAction(InstrumentationT *, std::string_view, + std::string_view, const IRUnitT &, InstructionT, + std::uint64_t) { + return true; + } +}; + +template <typename ChangeT> struct AnalysisRegistration final { + AnalysisID ID = nullptr; + std::string Name; + std::vector<AnalysisID> Dependencies; + ChangeT InvalidatedBy = ChangeT::all(); + PassThreadSafety ThreadSafety = PassThreadSafety::NotThreadSafe; +}; + +template <typename IRUnitT, typename PassT, typename OptionsT> struct PassManagerCallbacks; + +template <typename IRUnitT, typename PassT, typename OptionsT> class PassManager { +public: + using PassList = std::vector<std::unique_ptr<PassT>>; + using Callbacks = PassManagerCallbacks<IRUnitT, PassT, OptionsT>; + + 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<void> addPass(std::unique_ptr<PassT> 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 <typename... Args> + [[nodiscard]] Expected<void> run(IRUnitT &Unit, Args &&...Arguments) const { + return Callbacks::run(Passes, Options, Unit, std::forward<Args>(Arguments)...); + } + + template <typename... Args> + [[nodiscard]] Expected<void> runFunctions(Args &&...Arguments) const + requires requires(const PassList &InputPasses, const OptionsT &InputOptions, + Args &&...InputArguments) { + Callbacks::runFunctions(InputPasses, InputOptions, std::forward<Args>(InputArguments)...); + } + { + return Callbacks::runFunctions(Passes, Options, std::forward<Args>(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 <typename IRUnitT, typename RegistrationT, typename ChangeT, typename InstrumentationT> +class AnalysisManager { +public: + using Self = AnalysisManager<IRUnitT, RegistrationT, ChangeT, InstrumentationT>; + + AnalysisManager() = default; + AnalysisManager(const AnalysisManager &) = delete; + AnalysisManager &operator=(const AnalysisManager &) = delete; + AnalysisManager(AnalysisManager &&) = delete; + AnalysisManager &operator=(AnalysisManager &&) = delete; + ~AnalysisManager() = default; + + template <typename AnalysisT> [[nodiscard]] static AnalysisID id() noexcept { + return PreservedAnalyses::analysisID<AnalysisT>(); + } + + template <typename AnalysisT> + [[nodiscard]] Expected<void> registerAnalysis(RegistrationT Registration = {}) { + using ResultT = typename AnalysisT::Result; + if (Registration.ID == nullptr) + Registration.ID = id<AnalysisT>(); + if (Registration.Name.empty()) { + if constexpr (requires { + { AnalysisT::name() } -> std::convertible_to<std::string_view>; + }) + Registration.Name = std::string(AnalysisT::name()); + else + Registration.Name = "unnamed-analysis"; + } + + ErasedRunner Runner = [](IRUnitT &Unit, const TargetDescription &Target, + Self &Manager) -> Expected<std::shared_ptr<void>> { + auto Computed = AnalysisT::run(Unit, Target, Manager); + if (!Computed) + return std::unexpected(Computed.error()); + return std::shared_ptr<void>(new ResultT(std::move(*Computed)), + [](void *Value) { delete static_cast<ResultT *>(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<bool>; + }) + return static_cast<ResultT *>(Value)->invalidate(Unit, Preserved); + return true; + }; + return registerAnalysisImpl(std::move(Registration), std::move(Runner), std::move(Invalidator)); + } + + template <typename AnalysisT> + [[nodiscard]] Expected<typename AnalysisT::Result *> getResult(IRUnitT &Unit, + const TargetDescription &Target) { + const AnalysisID Key = id<AnalysisT>(); + if (!isRegistered(Key)) { + auto Registered = registerAnalysis<AnalysisT>(); + if (!Registered) + return std::unexpected(Registered.error()); + } + auto Result = getResultImpl(Key, Unit, Target); + if (!Result) + return std::unexpected(Result.error()); + return static_cast<typename AnalysisT::Result *>(*Result); + } + + [[nodiscard]] Expected<void *> 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<AnalysisID> 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<IRUnitT *>(&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<IRUnitT *>(&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<std::unique_ptr<Self>> forkEmpty() const { + if (!ActiveComputations.empty()) + return makeUnexpected(ErrorCode::InvalidArgument, + "cannot fork an analysis manager during analysis computation"); + auto Result = std::make_unique<Self>(); + Result->Registry = Registry; + return Result; + } + + [[nodiscard]] Expected<void> 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<void> + validateParallelRequirements(std::span<const AnalysisID> RequiredAnalyses) const { + std::vector<AnalysisID> Worklist(RequiredAnalyses.begin(), RequiredAnalyses.end()); + std::unordered_set<AnalysisID> 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 <typename InstructionT> + [[nodiscard]] Expected<bool> 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<IRUnitT, InstrumentationT>::requestAction( + Instrumentation, ActivePass.empty() ? "unscoped" : ActivePass, Rule, Unit, Instruction, + Cost); + } + + [[nodiscard]] Expected<bool> 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<IRUnitT, InstrumentationT>::requestAction( + Instrumentation, ActivePass.empty() ? "unscoped" : ActivePass, Rule, Unit, nullptr, Cost); + } + + [[nodiscard]] const std::string &activePass() const noexcept { + return ActivePass; + } + +private: + using ErasedRunner = + std::function<Expected<std::shared_ptr<void>>(IRUnitT &, const TargetDescription &, Self &)>; + using ErasedInvalidator = std::function<bool(void *, const IRUnitT &, const PreservedAnalyses &)>; + + struct RegisteredAnalysis final { + RegistrationT Info; + ErasedRunner Runner; + ErasedInvalidator Invalidator; + }; + + struct CacheEntry final { + std::shared_ptr<void> Value; + AnalysisID ID = nullptr; + }; + + [[nodiscard]] static bool hasDuplicateAnalysisIDs(std::span<const AnalysisID> IDs) { + std::unordered_set<AnalysisID> Unique; + for (const AnalysisID ID : IDs) { + if (ID == nullptr || !Unique.insert(ID).second) + return true; + } + return false; + } + + [[nodiscard]] Expected<void> 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<void *> 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<IRUnitT, InstrumentationT>::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<IRUnitT, InstrumentationT>::analysisFailure( + Instrumentation, Registration.Info.Name, Unit, Failure, 0); + return std::unexpected(std::move(Failure)); + } + + if (Instrumentation != nullptr) + AnalysisManagerInstrumentation<IRUnitT, InstrumentationT>::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<IRUnitT, InstrumentationT>::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<IRUnitT, InstrumentationT>::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<IRUnitT, InstrumentationT>::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<IRUnitT, InstrumentationT>::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::nanoseconds>( + std::chrono::steady_clock::now() - Start); + return Elapsed.count() <= 0 ? 0 : static_cast<std::uint64_t>(Elapsed.count()); + } + + std::unordered_map<AnalysisID, RegisteredAnalysis> Registry; + std::unordered_map<IRUnitT *, std::unordered_map<AnalysisID, CacheEntry>> Cache; + std::unordered_map<IRUnitT *, std::vector<AnalysisID>> 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<void> addCanonicalPipeline(MachinePassManager &Pipeline, +[[nodiscard]] Expected<void> addCanonicalPipeline(MachineFunctionPassManager &Pipeline, const MachineFunction &Function, const RISCVSubtarget &Subtarget); [[nodiscard]] Expected<std::unique_ptr<MachineFunctionPass>> 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<MachinePassResult> 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<MachinePassResult> 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<MachinePassResult> 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<void> LiveIntervalsAnalysis::Result::shrinkToUses(Register Reg, bool LiveIntervalsAnalysis::Result::invalidate(const MachineFunction &, const PreservedAnalyses &Preserved) const noexcept { - return !Preserved.preserves(MachineAnalysisManager::id<LiveIntervalsAnalysis>()); + return !Preserved.preserves(MachineFunctionAnalysisManager::id<LiveIntervalsAnalysis>()); } Expected<LiveIntervalsAnalysis::Result> LiveIntervalsAnalysis::run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses) { + MachineFunctionAnalysisManager &Analyses) { auto Indexes = Analyses.getResult<SlotIndexesAnalysis>(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<LiveVariablesAnalysis>()); + return !Preserved.preserves(MachineFunctionAnalysisManager::id<LiveVariablesAnalysis>()); } -Expected<LiveVariablesAnalysis::Result> LiveVariablesAnalysis::run(MachineFunction &Function, - const TargetDescription &Target, - MachineAnalysisManager &) { +Expected<LiveVariablesAnalysis::Result> +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<MachinePassResult> 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<void> verifyTrackedMachineLiveness(const MachineFunction &Function, return {}; } -Expected<void> registerStage11MachineAnalyses(MachineAnalysisManager &Analyses) { +Expected<void> registerStage11MachineAnalyses(MachineFunctionAnalysisManager &Analyses) { const std::array IDs{ - MachineAnalysisManager::id<SlotIndexesAnalysis>(), - MachineAnalysisManager::id<LiveVariablesAnalysis>(), - MachineAnalysisManager::id<LiveIntervalsAnalysis>(), + MachineFunctionAnalysisManager::id<SlotIndexesAnalysis>(), + MachineFunctionAnalysisManager::id<LiveVariablesAnalysis>(), + MachineFunctionAnalysisManager::id<LiveIntervalsAnalysis>(), }; const std::size_t Registered = static_cast<std::size_t>( std::ranges::count_if(IDs, [&Analyses](AnalysisID ID) { return Analyses.isRegistered(ID); })); @@ -994,7 +994,7 @@ Expected<void> registerStage11MachineAnalyses(MachineAnalysisManager &Analyses) auto Candidate = Analyses.forkEmpty(); if (!Candidate) return std::unexpected(Candidate.error()); - MachineAnalysisManager &Staging = **Candidate; + MachineFunctionAnalysisManager &Staging = **Candidate; auto Slots = Staging.registerAnalysis<SlotIndexesAnalysis>({ .Name = "SlotIndexes", .Dependencies = {}, @@ -1015,8 +1015,8 @@ Expected<void> registerStage11MachineAnalyses(MachineAnalysisManager &Analyses) return std::unexpected(Variables.error()); auto Intervals = Staging.registerAnalysis<LiveIntervalsAnalysis>({ .Name = "LiveIntervals", - .Dependencies = {MachineAnalysisManager::id<SlotIndexesAnalysis>(), - MachineAnalysisManager::id<LiveVariablesAnalysis>()}, + .Dependencies = {MachineFunctionAnalysisManager::id<SlotIndexesAnalysis>(), + MachineFunctionAnalysisManager::id<LiveVariablesAnalysis>()}, .InvalidatedBy = {MachinePassChange::Instructions, MachinePassChange::Operands, MachinePassChange::Registers, MachinePassChange::CFG, MachinePassChange::BlockLayout, MachinePassChange::TargetState}, @@ -1024,8 +1024,7 @@ Expected<void> 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::Result> 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::Result> MachineLoopAnalysis::run(MachineFunction &Function, - const TargetDescription &Target, - MachineAnalysisManager &Analyses) { +Expected<MachineLoopAnalysis::Result> +MachineLoopAnalysis::run(MachineFunction &Function, const TargetDescription &Target, + MachineFunctionAnalysisManager &Analyses) { auto Dominators = Analyses.getResult<MachineDominatorTreeAnalysis>(Function, Target); if (!Dominators) return std::unexpected(Dominators.error()); @@ -496,7 +496,7 @@ std::span<const MachineSuccessor> MachineBranchProbabilityAnalysis::Result::succ Expected<MachineBranchProbabilityAnalysis::Result> MachineBranchProbabilityAnalysis::run(MachineFunction &Function, const TargetDescription &, - MachineAnalysisManager &) { + MachineFunctionAnalysisManager &) { Result ResultValue; const std::vector<MachineBasicBlock *> Blocks = linkedBlocks(Function); const auto Order = blockOrder(Blocks); @@ -522,7 +522,7 @@ MachineBlockFrequencyAnalysis::Result::frequency(const MachineBasicBlock &Block) Expected<MachineBlockFrequencyAnalysis::Result> MachineBlockFrequencyAnalysis::run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses) { + MachineFunctionAnalysisManager &Analyses) { auto Dominators = Analyses.getResult<MachineDominatorTreeAnalysis>(Function, Target); auto Loops = Analyses.getResult<MachineLoopAnalysis>(Function, Target); auto Probabilities = Analyses.getResult<MachineBranchProbabilityAnalysis>(Function, Target); @@ -628,8 +628,9 @@ MachineAliasAnalysis::Result::alias(const MachineMemOperand &Left, return Distance >= LowerSize ? MachineAliasResult::NoAlias : MachineAliasResult::PartialAlias; } -Expected<MachineAliasAnalysis::Result> -MachineAliasAnalysis::run(MachineFunction &, const TargetDescription &, MachineAnalysisManager &) { +Expected<MachineAliasAnalysis::Result> MachineAliasAnalysis::run(MachineFunction &, + const TargetDescription &, + MachineFunctionAnalysisManager &) { return Result{}; } @@ -659,7 +660,7 @@ std::span<const MachineMemoryDependency> MachineMemoryDependenceAnalysis::Result Expected<MachineMemoryDependenceAnalysis::Result> MachineMemoryDependenceAnalysis::run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses) { + MachineFunctionAnalysisManager &Analyses) { auto Alias = Analyses.getResult<MachineAliasAnalysis>(Function, Target); if (!Alias) return std::unexpected(Alias.error()); @@ -766,14 +767,14 @@ MachineMemoryDependenceAnalysis::run(MachineFunction &Function, const TargetDesc return ResultValue; } -Expected<void> registerStage8MachineAnalyses(MachineAnalysisManager &Analyses) { +Expected<void> registerStage8MachineAnalyses(MachineFunctionAnalysisManager &Analyses) { const std::array IDs{ - MachineAnalysisManager::id<MachineDominatorTreeAnalysis>(), - MachineAnalysisManager::id<MachineLoopAnalysis>(), - MachineAnalysisManager::id<MachineBranchProbabilityAnalysis>(), - MachineAnalysisManager::id<MachineBlockFrequencyAnalysis>(), - MachineAnalysisManager::id<MachineAliasAnalysis>(), - MachineAnalysisManager::id<MachineMemoryDependenceAnalysis>(), + MachineFunctionAnalysisManager::id<MachineDominatorTreeAnalysis>(), + MachineFunctionAnalysisManager::id<MachineLoopAnalysis>(), + MachineFunctionAnalysisManager::id<MachineBranchProbabilityAnalysis>(), + MachineFunctionAnalysisManager::id<MachineBlockFrequencyAnalysis>(), + MachineFunctionAnalysisManager::id<MachineAliasAnalysis>(), + MachineFunctionAnalysisManager::id<MachineMemoryDependenceAnalysis>(), }; const std::size_t Registered = static_cast<std::size_t>( std::ranges::count_if(IDs, [&Analyses](AnalysisID ID) { return Analyses.isRegistered(ID); })); @@ -787,7 +788,7 @@ Expected<void> registerStage8MachineAnalyses(MachineAnalysisManager &Analyses) { auto Candidate = Analyses.forkEmpty(); if (!Candidate) return std::unexpected(Candidate.error()); - MachineAnalysisManager &Staging = **Candidate; + MachineFunctionAnalysisManager &Staging = **Candidate; auto Dominators = Staging.registerAnalysis<MachineDominatorTreeAnalysis>({ .Name = "MachineDominatorTree", @@ -799,7 +800,7 @@ Expected<void> registerStage8MachineAnalyses(MachineAnalysisManager &Analyses) { return std::unexpected(Dominators.error()); auto Loops = Staging.registerAnalysis<MachineLoopAnalysis>({ .Name = "MachineLoopInfo", - .Dependencies = {MachineAnalysisManager::id<MachineDominatorTreeAnalysis>()}, + .Dependencies = {MachineFunctionAnalysisManager::id<MachineDominatorTreeAnalysis>()}, .InvalidatedBy = {MachinePassChange::CFG, MachinePassChange::BlockLayout}, .ThreadSafety = PassThreadSafety::ThreadSafe, }); @@ -815,9 +816,9 @@ Expected<void> registerStage8MachineAnalyses(MachineAnalysisManager &Analyses) { return std::unexpected(Probabilities.error()); auto Frequencies = Staging.registerAnalysis<MachineBlockFrequencyAnalysis>({ .Name = "MachineBlockFrequency", - .Dependencies = {MachineAnalysisManager::id<MachineDominatorTreeAnalysis>(), - MachineAnalysisManager::id<MachineLoopAnalysis>(), - MachineAnalysisManager::id<MachineBranchProbabilityAnalysis>()}, + .Dependencies = {MachineFunctionAnalysisManager::id<MachineDominatorTreeAnalysis>(), + MachineFunctionAnalysisManager::id<MachineLoopAnalysis>(), + MachineFunctionAnalysisManager::id<MachineBranchProbabilityAnalysis>()}, .InvalidatedBy = {MachinePassChange::CFG, MachinePassChange::BlockLayout}, .ThreadSafety = PassThreadSafety::ThreadSafe, }); @@ -835,7 +836,7 @@ Expected<void> registerStage8MachineAnalyses(MachineAnalysisManager &Analyses) { return std::unexpected(Alias.error()); auto MemoryDependence = Staging.registerAnalysis<MachineMemoryDependenceAnalysis>({ .Name = "MachineMemoryDependence", - .Dependencies = {MachineAnalysisManager::id<MachineAliasAnalysis>()}, + .Dependencies = {MachineFunctionAnalysisManager::id<MachineAliasAnalysis>()}, .InvalidatedBy = {MachinePassChange::Instructions, MachinePassChange::Operands, MachinePassChange::CFG, MachinePassChange::BlockLayout, MachinePassChange::Frame, MachinePassChange::ConstantPool, @@ -844,8 +845,7 @@ Expected<void> 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<MachineDominatorTreeAnalysis>(), - MachineAnalysisManager::id<MachineBranchProbabilityAnalysis>(), - MachineAnalysisManager::id<MachineBlockFrequencyAnalysis>(), - MachineAnalysisManager::id<MachineLoopAnalysis>(), + MachineFunctionAnalysisManager::id<MachineDominatorTreeAnalysis>(), + MachineFunctionAnalysisManager::id<MachineBranchProbabilityAnalysis>(), + MachineFunctionAnalysisManager::id<MachineBlockFrequencyAnalysis>(), + MachineFunctionAnalysisManager::id<MachineLoopAnalysis>(), }, .VerificationStage = PipelineStage::Selected, }; @@ -101,9 +101,9 @@ const MachinePassContract &MachineBlockPlacementPass::contract() const noexcept return placementContract(); } -Expected<MachinePassResult> MachineBlockPlacementPass::run(MachineFunction &Function, - const TargetDescription &Target, - MachineAnalysisManager &Analyses) { +Expected<MachinePassResult> +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<MachinePassResult> 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<MachinePassResult> MachineBlockPlacementPass::run(MachineFunction &Func } Expected<MachinePassResult> 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<MachineBranchProbabilityAnalysis>(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<MachinePassResult> 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<MachinePassResult> MachineBranchRelaxationPass::run(MachineFunction &Function, - const TargetDescription &Target, - MachineAnalysisManager &Analyses) { +Expected<MachinePassResult> +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<MachineDominatorTreeAnalysis>()}, + .RequiredAnalyses = {MachineFunctionAnalysisManager::id<MachineDominatorTreeAnalysis>()}, .VerificationStage = PipelineStage::Selected, }; Value.ThreadSafety = PassThreadSafety::ThreadSafe; @@ -314,7 +314,7 @@ const MachinePassContract &MachineCSEPass::contract() const noexcept { Expected<MachinePassResult> 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<MachinePassResult> 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<MachinePassResult> MachineCSEPass::run(MachineFunction &Function, return Result; } -Expected<MachinePassResult> MachineCSEPass::runImplementation(MachineFunction &Function, - const TargetDescription &Target, - MachineAnalysisManager &Analyses) { +Expected<MachinePassResult> +MachineCSEPass::runImplementation(MachineFunction &Function, const TargetDescription &Target, + MachineFunctionAnalysisManager &Analyses) { auto Dominators = Analyses.getResult<MachineDominatorTreeAnalysis>(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<MachinePassResult> 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<MachinePassResult> MachineCopyPropagationPass::run(MachineFunction &Function, - const TargetDescription &Target, - MachineAnalysisManager &Analyses) { +Expected<MachinePassResult> +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<MachinePassResult> 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<LiveVariablesAnalysis>()}, + .RequiredAnalyses = {MachineFunctionAnalysisManager::id<LiveVariablesAnalysis>()}, .VerificationStage = PipelineStage::RegisterAllocated, }; Value.ThreadSafety = PassThreadSafety::ThreadSafe; @@ -120,7 +120,7 @@ const MachinePassContract &MachineFallthroughPass::contract() const noexcept { Expected<MachinePassResult> 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<MachinePassResult> 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<LiveVariablesAnalysis>(*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<MachinePassResult> 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<MachinePassResult> 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<MachineDominatorTreeAnalysis>(), - MachineAnalysisManager::id<MachineLoopAnalysis>(), - MachineAnalysisManager::id<MachineBlockFrequencyAnalysis>()}, + .RequiredAnalyses = {MachineFunctionAnalysisManager::id<MachineDominatorTreeAnalysis>(), + MachineFunctionAnalysisManager::id<MachineLoopAnalysis>(), + MachineFunctionAnalysisManager::id<MachineBlockFrequencyAnalysis>()}, .VerificationStage = PipelineStage::Selected, }; Value.ThreadSafety = PassThreadSafety::ThreadSafe; @@ -50,9 +50,9 @@ namespace { MachineFunctionProperty::TracksLiveness}, .Sets = {}, .Clears = {}, - .RequiredAnalyses = {MachineAnalysisManager::id<MachineDominatorTreeAnalysis>(), - MachineAnalysisManager::id<MachineLoopAnalysis>(), - MachineAnalysisManager::id<MachineBlockFrequencyAnalysis>()}, + .RequiredAnalyses = {MachineFunctionAnalysisManager::id<MachineDominatorTreeAnalysis>(), + MachineFunctionAnalysisManager::id<MachineLoopAnalysis>(), + MachineFunctionAnalysisManager::id<MachineBlockFrequencyAnalysis>()}, .VerificationStage = PipelineStage::RegisterAllocated, }; Value.ThreadSafety = PassThreadSafety::ThreadSafe; @@ -332,7 +332,7 @@ const MachinePassContract &MachineLICMPass::contract() const noexcept { Expected<MachinePassResult> 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<MachinePassResult> 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<MachinePassResult> MachineLICMPass::run(MachineFunction &Function, return Result; } -Expected<MachinePassResult> MachineLICMPass::runImplementation(MachineFunction &Function, - const TargetDescription &Target, - MachineAnalysisManager &Analyses) { +Expected<MachinePassResult> +MachineLICMPass::runImplementation(MachineFunction &Function, const TargetDescription &Target, + MachineFunctionAnalysisManager &Analyses) { auto Loops = Analyses.getResult<MachineLoopAnalysis>(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<MachinePassResult> 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 <typename Pass, typename... Arguments> -[[nodiscard]] Expected<void> addPass(MachinePassManager &Pipeline, Arguments &&...Values) { +[[nodiscard]] Expected<void> addPass(MachineFunctionPassManager &Pipeline, Arguments &&...Values) { return Pipeline.addPass(std::make_unique<Pass>(std::forward<Arguments>(Values)...)); } } // namespace -Expected<void> registerMachineOptimizationAnalyses(MachineAnalysisManager &Analyses) { +Expected<void> registerMachineOptimizationAnalyses(MachineFunctionAnalysisManager &Analyses) { auto Registered = registerStage8MachineAnalyses(Analyses); if (!Registered) return std::unexpected(Registered.error()); @@ -46,7 +46,7 @@ Expected<void> registerMachineOptimizationAnalyses(MachineAnalysisManager &Analy } Expected<void> -addSelectedSSAOptimizationPipeline(MachinePassManager &Pipeline, +addSelectedSSAOptimizationPipeline(MachineFunctionPassManager &Pipeline, const MachineOptimizationPipelineTargetInfo &TargetInfo) { auto Added = addPass<MachineCombinerPass>(Pipeline, TargetInfo.Combiner, MachineCombinerStage::SelectedSSA); @@ -68,7 +68,7 @@ addSelectedSSAOptimizationPipeline(MachinePassManager &Pipeline, } Expected<void> addPreRegisterAllocationOptimizationPipeline( - MachinePassManager &Pipeline, const MachineOptimizationPipelineTargetInfo &TargetInfo) { + MachineFunctionPassManager &Pipeline, const MachineOptimizationPipelineTargetInfo &TargetInfo) { auto Added = addPass<MachineBranchOptimizationPass>(Pipeline, TargetInfo.InstrInfo); if (!Added) return std::unexpected(Added.error()); @@ -87,7 +87,7 @@ Expected<void> addPreRegisterAllocationOptimizationPipeline( } Expected<void> -addPostRegisterAllocationPipeline(MachinePassManager &Pipeline, +addPostRegisterAllocationPipeline(MachineFunctionPassManager &Pipeline, const MachineOptimizationPipelineTargetInfo &TargetInfo) { auto Added = addPass<MachineStackSlotColoringPass>(Pipeline); if (!Added) diff --git a/backend/lib/CodeGen/MachinePass.cpp b/backend/lib/CodeGen/MachinePassManager.cpp index 0ce6f70..0810965 100644 --- a/backend/lib/CodeGen/MachinePass.cpp +++ b/backend/lib/CodeGen/MachinePassManager.cpp @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-3.0-or-later -#include "rcc/CodeGen/MachinePass.h" +#include "rcc/CodeGen/MachinePassManager.h" #include "rcc/CodeGen/CompilationUnit.h" #include "rcc/CodeGen/MachineBasicBlock.h" @@ -141,6 +141,56 @@ void combineFingerprint(std::uint64_t &State, std::uint64_t Value) noexcept { } // namespace +void AnalysisManagerInstrumentation<MachineFunction, MachinePassInstrumentation>::beforeAnalysis( + MachinePassInstrumentation *Instrumentation, std::string_view Name, + const MachineFunction &Function) { + Instrumentation->beforeAnalysis(Name, Function); +} + +void AnalysisManagerInstrumentation<MachineFunction, MachinePassInstrumentation>::afterAnalysis( + MachinePassInstrumentation *Instrumentation, std::string_view Name, + const MachineFunction &Function, bool CacheHit, std::uint64_t Nanoseconds) { + Instrumentation->afterAnalysis(Name, Function, CacheHit, Nanoseconds); +} + +void AnalysisManagerInstrumentation<MachineFunction, MachinePassInstrumentation>::analysisFailure( + MachinePassInstrumentation *Instrumentation, std::string_view Name, + const MachineFunction &Function, const Error &Failure, std::uint64_t Nanoseconds) { + Instrumentation->analysisFailure(Name, Function, Failure, Nanoseconds); +} + +Expected<bool> +AnalysisManagerInstrumentation<MachineFunction, MachinePassInstrumentation>::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<bool> +AnalysisManagerInstrumentation<MachineFunction, MachinePassInstrumentation>::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<CompilationUnit, MachinePassInstrumentation>::beforeAnalysis( + MachinePassInstrumentation *Instrumentation, std::string_view Name, + const CompilationUnit &Unit) { + Instrumentation->beforeAnalysis(Name, Unit); +} + +void AnalysisManagerInstrumentation<CompilationUnit, MachinePassInstrumentation>::afterAnalysis( + MachinePassInstrumentation *Instrumentation, std::string_view Name, const CompilationUnit &Unit, + bool CacheHit, std::uint64_t Nanoseconds) { + Instrumentation->afterAnalysis(Name, Unit, CacheHit, Nanoseconds); +} + +void AnalysisManagerInstrumentation<CompilationUnit, MachinePassInstrumentation>::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); @@ -160,7 +210,7 @@ Expected<bool> MachineActionReplay::request(std::string_view Rule, const Machine const auto Position = RecordingInstructionIDs.find(Instruction); const MachineInstrStableID CanonicalInstruction = Position == RecordingInstructionIDs.end() ? Instruction : Position->second; - auto Accepted = Analyses->requestAction(Rule, Function, CanonicalInstruction, Cost); + auto Accepted = Request(Rule, Function, CanonicalInstruction, Cost); if (!Accepted) return std::unexpected(Accepted.error()); Decisions.push_back({ @@ -214,452 +264,6 @@ Expected<void> MachineActionReplay::finishReplay() const { return {}; } -Expected<void> -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<MachineFunction *>(&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<MachineFunction *>(&Function)); - return Position == Cache.end() ? 0 : Position->second.size(); -} - -Expected<void> -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<void *> 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<AnalysisID> 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<std::unique_ptr<MachineAnalysisManager>> MachineAnalysisManager::forkEmpty() const { - if (!ActiveComputations.empty()) { - return makeUnexpected(ErrorCode::InvalidArgument, - "cannot fork a machine analysis manager during analysis computation"); - } - auto Result = std::make_unique<MachineAnalysisManager>(); - Result->Registry = Registry; - return Result; -} - -Expected<void> MachineAnalysisManager::validateParallelRequirements( - std::span<const AnalysisID> RequiredAnalyses) const { - std::vector<AnalysisID> Worklist(RequiredAnalyses.begin(), RequiredAnalyses.end()); - std::unordered_set<AnalysisID> 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<bool> MachineAnalysisManager::requestAction(std::string_view Action, - const MachineFunction &Function, - std::uint64_t Cost) { - return requestAction(Action, Function, MachineInstrStableID{}, Cost); -} - -Expected<bool> 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<void> 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<CompilationUnit *>(&Unit)); - if (UnitPosition == Cache.end()) - return false; - const auto AnalysisPosition = UnitPosition->second.find(ID); - return AnalysisPosition != UnitPosition->second.end() && AnalysisPosition->second.Value; -} - -Expected<void> -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<void *> 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<AnalysisID> 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; @@ -966,9 +570,17 @@ void MachinePassInstrumentation::change(std::string_view Name, const MachineFunc Callback(Name, Function, Changes, FingerprintChanged); } -Expected<bool> MachinePassInstrumentation::requestAction(const MachineActionID &Action, +Expected<bool> 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"); @@ -1000,6 +612,13 @@ Expected<bool> MachinePassInstrumentation::requestAction(const MachineActionID & return true; } +Expected<bool> 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<BeforeUnitCallback> Callbacks; @@ -1043,8 +662,8 @@ void MachinePassInstrumentation::unitFailure(std::string_view Name, const Compil Callback(Name, Unit, ErrorValue); } -void MachinePassInstrumentation::beforeUnitAnalysis(std::string_view Name, - const CompilationUnit &Unit) const { +void MachinePassInstrumentation::beforeAnalysis(std::string_view Name, + const CompilationUnit &Unit) const { std::vector<BeforeUnitAnalysisCallback> Callbacks; { std::scoped_lock Lock(Mutex); @@ -1054,9 +673,8 @@ void MachinePassInstrumentation::beforeUnitAnalysis(std::string_view Name, Callback(Name, Unit); } -void MachinePassInstrumentation::afterUnitAnalysis(std::string_view Name, - const CompilationUnit &Unit, bool CacheHit, - std::uint64_t Nanoseconds) const { +void MachinePassInstrumentation::afterAnalysis(std::string_view Name, const CompilationUnit &Unit, + bool CacheHit, std::uint64_t Nanoseconds) const { std::vector<AfterUnitAnalysisCallback> Callbacks; { std::scoped_lock Lock(Mutex); @@ -1070,10 +688,9 @@ void MachinePassInstrumentation::afterUnitAnalysis(std::string_view Name, Callback(Name, Unit, CacheHit, Nanoseconds); } -void MachinePassInstrumentation::unitAnalysisFailure(std::string_view Name, - const CompilationUnit &Unit, - const Error &ErrorValue, - std::uint64_t Nanoseconds) const { +void MachinePassInstrumentation::analysisFailure(std::string_view Name, const CompilationUnit &Unit, + const Error &ErrorValue, + std::uint64_t Nanoseconds) const { std::vector<UnitAnalysisFailureCallback> Callbacks; { std::scoped_lock Lock(Mutex); @@ -1128,14 +745,10 @@ std::vector<MachineActionEvent> MachinePassInstrumentation::actionEvents() const return Result; } -void MachinePassInstrumentation::clearStatistics() { - std::scoped_lock Lock(Mutex); - Statistics.clear(); - ConsumedFuel.clear(); - ActionEvents.clear(); -} - -Expected<void> MachinePassManager::validateContract(const MachinePassContract &Contract) const { +Expected<void> +PassManagerCallbacks<MachineFunction, MachineFunctionPass, MachinePassManagerOptions>::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)) { @@ -1149,20 +762,11 @@ Expected<void> MachinePassManager::validateContract(const MachinePassContract &C return validateParameters(Contract.Parameters); } -Expected<void> MachinePassManager::addPass(std::unique_ptr<MachineFunctionPass> 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<void> MachinePassManager::run(MachineFunction &Function, const TargetDescription &Target, - MachineAnalysisManager &Analyses, - MachinePassInstrumentation *Instrumentation) const { +Expected<void> +PassManagerCallbacks<MachineFunction, MachineFunctionPass, MachinePassManagerOptions>::run( + const PassList &Passes, const MachinePassManagerOptions &Options, MachineFunction &Function, + const TargetDescription &Target, MachineFunctionAnalysisManager &Analyses, + MachinePassInstrumentation *Instrumentation) { Analyses.setInstrumentation(Instrumentation); for (const std::unique_ptr<MachineFunctionPass> &Pass : Passes) { const MachinePassContract &Contract = Pass->contract(); @@ -1192,7 +796,7 @@ Expected<void> MachinePassManager::run(MachineFunction &Function, const TargetDe } for (const AnalysisID Required : Contract.RequiredAnalyses) { - auto Result = Analyses.getResultImpl(Required, Function, Target); + auto Result = Analyses.getResultByID(Required, Function, Target); if (!Result) { Error Failure = prefixedError(Result.error(), "pass '" + std::string(Name) + @@ -1209,9 +813,9 @@ Expected<void> MachinePassManager::run(MachineFunction &Function, const TargetDe if (Instrumentation != nullptr) Instrumentation->before(Name, Function); const Clock::time_point Start = Clock::now(); - Analyses.ActivePass = std::string(Name); + Analyses.setActivePass(std::string(Name)); auto PassResult = Pass->run(Function, Target, Analyses); - Analyses.ActivePass.clear(); + Analyses.setActivePass({}); const std::uint64_t Duration = elapsedNanoseconds(Start); if (!PassResult) { Error Failure = @@ -1296,11 +900,11 @@ Expected<void> MachinePassManager::run(MachineFunction &Function, const TargetDe return {}; } -Expected<void> MachinePassManager::runFunctions(CompilationUnit &Unit, - const TargetDescription &Target, - const MachineAnalysisManager &AnalysisPrototype, - std::size_t ThreadCount, - MachinePassInstrumentation *Instrumentation) const { +Expected<void> +PassManagerCallbacks<MachineFunction, MachineFunctionPass, MachinePassManagerOptions>::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); @@ -1322,7 +926,7 @@ Expected<void> MachinePassManager::runFunctions(CompilationUnit &Unit, return std::unexpected(AnalysisSafety.error()); } } - std::vector<std::unique_ptr<MachineAnalysisManager>> Managers; + std::vector<std::unique_ptr<MachineFunctionAnalysisManager>> Managers; Managers.reserve(FunctionCount); for (std::size_t Index = 0; Index < FunctionCount; ++Index) { auto Manager = AnalysisPrototype.forkEmpty(); @@ -1347,7 +951,8 @@ Expected<void> MachinePassManager::runFunctions(CompilationUnit &Unit, } if (Instrumentation != nullptr) Instrumentation->beginBuffering(EventBuffers[Index], Target); - auto Result = run(*Function, Target, *Managers[Index], Instrumentation); + auto Result = PassManagerCallbacks::run(Passes, Options, *Function, Target, *Managers[Index], + Instrumentation); if (Instrumentation != nullptr) Instrumentation->endBuffering(); if (!Result) @@ -1374,12 +979,10 @@ Expected<void> MachinePassManager::runFunctions(CompilationUnit &Unit, return {}; } -Expected<void> CompilationUnitPassManager::addPass(std::unique_ptr<CompilationUnitPass> Pass) { - if (!Pass) { - return makeUnexpected(ErrorCode::InvalidArgument, - "compilation-unit pass manager cannot add a null pass"); - } - const CompilationUnitPassContract &Contract = Pass->contract(); +Expected<void> +PassManagerCallbacks<CompilationUnit, CompilationUnitPass, + CompilationUnitPassManagerOptions>::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"); @@ -1391,15 +994,14 @@ Expected<void> CompilationUnitPassManager::addPass(std::unique_ptr<CompilationUn auto Parameters = validateParameters(Contract.Parameters); if (!Parameters) return std::unexpected(Parameters.error()); - Passes.push_back(std::move(Pass)); return {}; } -Expected<void> CompilationUnitPassManager::run(CompilationUnit &Unit, - const TargetDescription &Target, - CompilationUnitAnalysisManager &UnitAnalyses, - MachineAnalysisManager &FunctionAnalyses, - MachinePassInstrumentation *Instrumentation) const { +Expected<void> +PassManagerCallbacks<CompilationUnit, CompilationUnitPass, CompilationUnitPassManagerOptions>::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<CompilationUnitPass> &Pass : Passes) { @@ -1421,7 +1023,7 @@ Expected<void> CompilationUnitPassManager::run(CompilationUnit &Unit, } for (const AnalysisID Required : Contract.RequiredAnalyses) { - auto Result = UnitAnalyses.getResultImpl(Required, Unit, Target); + auto Result = UnitAnalyses.getResultByID(Required, Unit, Target); if (!Result) { Error Failure = prefixedError(Result.error(), "compilation-unit pass '" + std::string(Name) + 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<MachinePassResult> 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<MachinePassResult> 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<MachinePassResult> PreparePostRAPseudosPass::run(MachineFunction &Function, - const TargetDescription &Target, - MachineAnalysisManager &Analyses) { +Expected<MachinePassResult> +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<MachinePassResult> PrePEITargetPseudoExpansionPass::run(MachineFunction &Function, - const TargetDescription &Target, - MachineAnalysisManager &Analyses) { +Expected<MachinePassResult> +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<MachinePassResult> 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<MachinePassResult> TargetLatePseudoExpansionPass::run(MachineFunction &Function, - const TargetDescription &Target, - MachineAnalysisManager &Analyses) { +Expected<MachinePassResult> +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<LiveVariablesAnalysis>()}, + .RequiredAnalyses = {MachineFunctionAnalysisManager::id<LiveVariablesAnalysis>()}, .VerificationStage = PipelineStage::TiedOpsRewritten, }; - Value.RequiredAnalyses.push_back(MachineAnalysisManager::id<MachineBlockFrequencyAnalysis>()); + Value.RequiredAnalyses.push_back( + MachineFunctionAnalysisManager::id<MachineBlockFrequencyAnalysis>()); Value.ThreadSafety = PassThreadSafety::ThreadSafe; Value.DeclaredChanges = {MachinePassChange::Instructions, MachinePassChange::Operands}; return Value; @@ -395,7 +396,7 @@ const MachinePassContract &MachineSchedulerPass::contract() const noexcept { Expected<MachinePassResult> 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<MachinePassResult> MachineSchedulerPass::run(MachineFunction &Function, return std::unexpected( prefixedError(Trial.error(), "machine scheduler transaction setup failed: ")); } - MachineAnalysisManager TrialAnalyses; + MachineFunctionAnalysisManager TrialAnalyses; auto TrialLiveness = TrialAnalyses.getResult<LiveVariablesAnalysis>(*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<MachineDominatorTreeAnalysis>(), - MachineAnalysisManager::id<MachineLoopAnalysis>()}, + .RequiredAnalyses = {MachineFunctionAnalysisManager::id<MachineDominatorTreeAnalysis>(), + MachineFunctionAnalysisManager::id<MachineLoopAnalysis>()}, .VerificationStage = PipelineStage::RegisterAllocated, }; Value.ThreadSafety = PassThreadSafety::ThreadSafe; @@ -66,9 +66,9 @@ const MachinePassContract &MachineShrinkWrappingPass::contract() const noexcept return shrinkWrappingContract(); } -Expected<MachinePassResult> MachineShrinkWrappingPass::run(MachineFunction &Function, - const TargetDescription &Target, - MachineAnalysisManager &Analyses) { +Expected<MachinePassResult> +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<MachineDominatorTreeAnalysis>(), - MachineAnalysisManager::id<MachineBlockFrequencyAnalysis>()}, + .RequiredAnalyses = {MachineFunctionAnalysisManager::id<MachineDominatorTreeAnalysis>(), + MachineFunctionAnalysisManager::id<MachineBlockFrequencyAnalysis>()}, .VerificationStage = PipelineStage::Selected, }; Value.ThreadSafety = PassThreadSafety::ThreadSafe; @@ -50,8 +50,8 @@ namespace { MachineFunctionProperty::TracksLiveness}, .Sets = {}, .Clears = {}, - .RequiredAnalyses = {MachineAnalysisManager::id<MachineDominatorTreeAnalysis>(), - MachineAnalysisManager::id<MachineBlockFrequencyAnalysis>()}, + .RequiredAnalyses = {MachineFunctionAnalysisManager::id<MachineDominatorTreeAnalysis>(), + MachineFunctionAnalysisManager::id<MachineBlockFrequencyAnalysis>()}, .VerificationStage = PipelineStage::RegisterAllocated, }; Value.ThreadSafety = PassThreadSafety::ThreadSafe; @@ -354,7 +354,7 @@ const MachinePassContract &MachineSinkPass::contract() const noexcept { Expected<MachinePassResult> 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<MachinePassResult> 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<MachinePassResult> MachineSinkPass::run(MachineFunction &Function, return Result; } -Expected<MachinePassResult> MachineSinkPass::runImplementation(MachineFunction &Function, - const TargetDescription &Target, - MachineAnalysisManager &Analyses) { +Expected<MachinePassResult> +MachineSinkPass::runImplementation(MachineFunction &Function, const TargetDescription &Target, + MachineFunctionAnalysisManager &Analyses) { auto Dominators = Analyses.getResult<MachineDominatorTreeAnalysis>(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<MachinePassResult> 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<MachinePassResult> 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<MachinePassResult> 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<MachinePassResult> 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<LiveVariablesAnalysis>()}, + .RequiredAnalyses = {MachineFunctionAnalysisManager::id<LiveVariablesAnalysis>()}, .VerificationStage = PipelineStage::RegisterAllocated, }; - Value.RequiredAnalyses.push_back(MachineAnalysisManager::id<MachineBlockFrequencyAnalysis>()); + Value.RequiredAnalyses.push_back( + MachineFunctionAnalysisManager::id<MachineBlockFrequencyAnalysis>()); Value.ThreadSafety = PassThreadSafety::ThreadSafe; Value.DeclaredChanges = {MachinePassChange::Instructions, MachinePassChange::Operands}; return Value; @@ -61,7 +62,7 @@ const MachinePassContract &PostRASchedulerPass::contract() const noexcept { Expected<MachinePassResult> 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<MachinePassResult> PostRASchedulerPass::run(MachineFunction &Function, return std::unexpected( prefixedError(Trial.error(), "post-RA scheduler transaction setup failed: ")); } - MachineAnalysisManager TrialAnalyses; + MachineFunctionAnalysisManager TrialAnalyses; auto TrialLiveness = TrialAnalyses.getResult<LiveVariablesAnalysis>(*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<MachinePassResult> 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<LiveIntervalsAnalysis>()}, + .RequiredAnalyses = {MachineFunctionAnalysisManager::id<LiveIntervalsAnalysis>()}, .VerificationStage = PipelineStage::RegisterAllocated, }; Value.ThreadSafety = PassThreadSafety::ThreadSafe; @@ -97,7 +97,7 @@ const MachinePassContract &BasicAllocatorPass::contract() const noexcept { Expected<MachinePassResult> 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<MachinePassResult> 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<MachinePassResult> 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<LiveVariablesAnalysis>()}, + .RequiredAnalyses = {MachineFunctionAnalysisManager::id<LiveVariablesAnalysis>()}, .VerificationStage = PipelineStage::RegisterAllocated, }; Value.ThreadSafety = PassThreadSafety::ThreadSafe; @@ -568,7 +568,7 @@ const MachinePassContract &FastAllocatorPass::contract() const noexcept { Expected<MachinePassResult> 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<MachinePassResult> 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<LiveIntervalsAnalysis>()}, + .RequiredAnalyses = {MachineFunctionAnalysisManager::id<LiveIntervalsAnalysis>()}, .VerificationStage = PipelineStage::RegisterAllocated, }; Value.ThreadSafety = PassThreadSafety::ThreadSafe; @@ -294,7 +294,7 @@ const MachinePassContract &PBQPAllocatorPass::contract() const noexcept { Expected<MachinePassResult> 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<MachinePassResult> 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<void> SlotIndexesAnalysis::Result::renumber(MachineFunction &Function) bool SlotIndexesAnalysis::Result::invalidate(const MachineFunction &, const PreservedAnalyses &Preserved) const noexcept { - return !Preserved.preserves(MachineAnalysisManager::id<SlotIndexesAnalysis>()); + return !Preserved.preserves(MachineFunctionAnalysisManager::id<SlotIndexesAnalysis>()); } Expected<SlotIndexesAnalysis::Result> 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<MachinePassResult> TwoAddressInstructionPass::run(MachineFunction &Function, - const TargetDescription &Target, - MachineAnalysisManager &Analyses) { +Expected<MachinePassResult> +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<bool> 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<MachinePassResult> 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 <typename PassT, typename... ArgumentT> -[[nodiscard]] Expected<void> addPass(MachinePassManager &Pipeline, ArgumentT &&...Arguments) { +[[nodiscard]] Expected<void> addPass(MachineFunctionPassManager &Pipeline, + ArgumentT &&...Arguments) { return Pipeline.addPass(std::make_unique<PassT>(std::forward<ArgumentT>(Arguments)...)); } -[[nodiscard]] Expected<void> addInitialPipeline(MachinePassManager &Pipeline, +[[nodiscard]] Expected<void> addInitialPipeline(MachineFunctionPassManager &Pipeline, const RISCVSubtarget &Subtarget) { auto Added = addPass<MachineCombinerPass>(Pipeline, machineCombinerInfo(), MachineCombinerStage::PreLegalizer); @@ -46,7 +47,7 @@ template <typename PassT, typename... ArgumentT> return addPass<InstructionSelect>(Pipeline, Subtarget.getInstructionSelector()); } -[[nodiscard]] Expected<void> addSSAExitPipeline(MachinePassManager &Pipeline) { +[[nodiscard]] Expected<void> addSSAExitPipeline(MachineFunctionPassManager &Pipeline) { auto Added = addSelectedSSAOptimizationPipeline(Pipeline, optimizationPipelineInfo()); if (!Added) return std::unexpected(Added.error()); @@ -56,14 +57,14 @@ template <typename PassT, typename... ArgumentT> return addPass<TwoAddressInstructionPass>(Pipeline, instrInfo()); } -[[nodiscard]] Expected<void> addRegisterAllocationPipeline(MachinePassManager &Pipeline) { +[[nodiscard]] Expected<void> addRegisterAllocationPipeline(MachineFunctionPassManager &Pipeline) { auto Added = addPreRegisterAllocationOptimizationPipeline(Pipeline, optimizationPipelineInfo()); if (!Added) return std::unexpected(Added.error()); return addPass<PBQPAllocatorPass>(Pipeline, registerAllocationInfo()); } -[[nodiscard]] Expected<void> addCompleteRegistry(MachinePassManager &Pipeline, +[[nodiscard]] Expected<void> addCompleteRegistry(MachineFunctionPassManager &Pipeline, const RISCVSubtarget &Subtarget) { auto Added = addInitialPipeline(Pipeline, Subtarget); if (!Added) @@ -79,7 +80,8 @@ template <typename PassT, typename... ArgumentT> } // namespace -Expected<void> addCanonicalPipeline(MachinePassManager &Pipeline, const MachineFunction &Function, +Expected<void> addCanonicalPipeline(MachineFunctionPassManager &Pipeline, + const MachineFunction &Function, const RISCVSubtarget &Subtarget) { if (!Function.properties().has(MachineFunctionProperty::Legalized)) { auto Added = addPass<MachineCombinerPass>(Pipeline, machineCombinerInfo(), @@ -132,11 +134,11 @@ Expected<std::unique_ptr<MachineFunctionPass>> 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<std::vector<std::string>> 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<std::string> Result; Result.reserve(Passes.size()); for (const std::unique_ptr<MachineFunctionPass> &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<MachinePassManager::PassList> +[[nodiscard]] Expected<MachineFunctionPassManager::PassList> 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<rcc::Legalizer>(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<rcc::InstructionSelect>(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<rcc::Legalizer>(Subtarget.getLegalizerInfo())) || !Pipeline.addPass(std::make_unique<rcc::RegBankSelect>(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<rcc::Legalizer>(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<std::uint32_t>(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<rcc::LiveIntervalsAnalysis>(*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<rcc::LiveVariablesAnalysis>(Function, Target) : rcc::Expected<rcc::LiveVariablesAnalysis::Result *>{ @@ -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<rcc::LiveIntervalsAnalysis>(*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<rcc::LiveVariablesAnalysis>(*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<LiveIntervalsAnalysis>(*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<LiveIntervalsAnalysis>(*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::RebuildMachineLivenessPass>()); - rcc::MachineAnalysisManager Analyses; + rcc::MachineFunctionAnalysisManager Analyses; auto Run = Added ? Pipeline.run(Function, Target, Analyses) : rcc::Expected<void>{std::unexpected(Added.error())}; if (!Run) @@ -169,8 +169,9 @@ class DummyAnalysis final { public: struct Result final {}; - [[nodiscard]] static rcc::Expected<Result> - run(rcc::MachineFunction &, const rcc::TargetDescription &, rcc::MachineAnalysisManager &) { + [[nodiscard]] static rcc::Expected<Result> 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::SlotIndexesAnalysis>()), + rcc::MachineFunctionAnalysisManager::id<rcc::SlotIndexesAnalysis>()), "operand changes must retain SlotIndexes while invalidating liveness dependents"); auto Recomputed = Analyses.getResult<rcc::LiveIntervalsAnalysis>(*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::LiveVariablesAnalysis>()), + rcc::MachineFunctionAnalysisManager::id<rcc::LiveVariablesAnalysis>()), "layout changes must invalidate SlotIndexes and LiveIntervals only"); - rcc::MachineAnalysisManager Atomic; + rcc::MachineFunctionAnalysisManager Atomic; rcc::MachineAnalysisRegistration DummyRegistration; DummyRegistration.Name = "SlotIndexes"; auto Dummy = Atomic.registerAnalysis<DummyAnalysis>(std::move(DummyRegistration)); auto Rejected = rcc::registerStage11MachineAnalyses(Atomic); Context.expect( - Dummy && !Rejected && Atomic.isRegistered(rcc::MachineAnalysisManager::id<DummyAnalysis>()) && - !Atomic.isRegistered(rcc::MachineAnalysisManager::id<rcc::SlotIndexesAnalysis>()) && - !Atomic.isRegistered(rcc::MachineAnalysisManager::id<rcc::LiveVariablesAnalysis>()), + Dummy && !Rejected && + Atomic.isRegistered(rcc::MachineFunctionAnalysisManager::id<DummyAnalysis>()) && + !Atomic.isRegistered( + rcc::MachineFunctionAnalysisManager::id<rcc::SlotIndexesAnalysis>()) && + !Atomic.isRegistered( + rcc::MachineFunctionAnalysisManager::id<rcc::LiveVariablesAnalysis>()), "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<rcc::MachineDominatorTreeAnalysis>(**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::MachineAliasAnalysis>()), + rcc::MachineFunctionAnalysisManager::id<rcc::MachineAliasAnalysis>()), "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<rcc::MachineMemoryDependenceAnalysis>(**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<Result> - run(rcc::MachineFunction &, const rcc::TargetDescription &, rcc::MachineAnalysisManager &) { + [[nodiscard]] static rcc::Expected<Result> run(rcc::MachineFunction &, + const rcc::TargetDescription &, + rcc::MachineFunctionAnalysisManager &) { return Result{}; } }; void testAtomicStandardRegistration(TestContext &Context) { - rcc::MachineAnalysisManager Analyses; + rcc::MachineFunctionAnalysisManager Analyses; Context.expect(Analyses .registerAnalysis<ConflictingAnalysis>({ .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<rcc::MachineDominatorTreeAnalysis>()), - "failed standard-analysis registration must not publish a partial set"); + Context.expect( + !rcc::registerStage8MachineAnalyses(Analyses) && + !Analyses.isRegistered( + rcc::MachineFunctionAnalysisManager::id<rcc::MachineDominatorTreeAnalysis>()), + "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 <atomic> +#include <cstddef> +#include <cstdint> +#include <iostream> +#include <memory> +#include <string> +#include <string_view> +#include <utility> +#include <vector> + +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<rcc::TargetDescription> createTarget() { + std::vector<rcc::InstructionDescriptor> Descriptors; + std::vector<rcc::ImmediatePredicate> 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<Result> 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<Result> 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<BlockCountAnalysis>()}, + .VerificationStage = std::nullopt, + }; + return Contract; + } + + [[nodiscard]] rcc::Expected<rcc::MachinePassResult> + run(rcc::MachineFunction &Function, const rcc::TargetDescription &Target, + rcc::MachineFunctionAnalysisManager &Analyses) override { + auto Blocks = Analyses.getResult<BlockCountAnalysis>(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<rcc::MachinePassResult> + 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<BlockCountAnalysis>()}, + .VerificationStage = std::nullopt, + }; + return Contract; + } + + [[nodiscard]] rcc::Expected<rcc::MachinePassResult> + 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<std::uint32_t> &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<rcc::MachinePassResult> + run(rcc::MachineFunction &, const rcc::TargetDescription &, + rcc::MachineFunctionAnalysisManager &) override { + Count->fetch_add(1, std::memory_order_relaxed); + return rcc::MachinePassResult{}; + } + +private: + std::atomic<std::uint32_t> *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<NonThreadSafeAnalysis>(), + }, + .VerificationStage = std::nullopt, + }; + Value.ThreadSafety = rcc::PassThreadSafety::ThreadSafe; + return Value; + }(); + return Contract; + } + + [[nodiscard]] rcc::Expected<rcc::MachinePassResult> + 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<Result> 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<UnitFunctionCountAnalysis>()}, + .Parameters = {}, + .DeclaredChanges = {}, + }; + return Contract; + } + + [[nodiscard]] rcc::Expected<rcc::CompilationUnitPassResult> + run(rcc::CompilationUnit &Unit, const rcc::TargetDescription &Target, + rcc::CompilationUnitAnalysisManager &Analyses, + rcc::MachineFunctionAnalysisManager &) override { + auto Count = Analyses.getResult<UnitFunctionCountAnalysis>(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<UnitFunctionCountAnalysis>()}, + .Parameters = {}, + .DeclaredChanges = {rcc::MachinePassChange::BlockLayout}, + }; + return Contract; + } + + [[nodiscard]] rcc::Expected<rcc::CompilationUnitPassResult> + 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<BlockCountAnalysis>({ + .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<RequiredAnalysisPass>()).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<UnreportedChangePass>()).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<BlockCountAnalysis>({ + .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<MutatingFailurePass>()).has_value() && + !FailingPipeline.run(**FailedFunction, Target, FailureAnalyses) && + !FailureAnalyses.hasCached(**FailedFunction, + rcc::MachineFunctionAnalysisManager::id<BlockCountAnalysis>()), + "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<std::uint32_t> Runs = 0; + rcc::MachineFunctionPassManager Parallel; + Context.expect(Parallel.addPass(std::make_unique<ParallelCountingPass>(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<NonThreadSafeAnalysis>({ + .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<RequiresNonThreadSafeAnalysisPass>()).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<UnitFunctionCountAnalysis>({ + .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<ObserveUnitPass>()).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<BlockCountAnalysis>({ + .Name = "BlockCount", + .Dependencies = {}, + .InvalidatedBy = rcc::MachinePassChanges::all(), + }) + .has_value() && + FunctionAnalyses.getResult<BlockCountAnalysis>(*FirstFunction, Target).has_value(), + "compilation-unit failure cache fixtures must materialize"); + rcc::CompilationUnitPassManager FailingUnitPipeline; + Context.expect( + FirstFunction != nullptr && + FailingUnitPipeline.addPass(std::make_unique<MutatingUnitFailurePass>()).has_value() && + !FailingUnitPipeline.run(Unit, Target, UnitAnalyses, FunctionAnalyses) && + !UnitAnalyses.hasCached( + Unit, rcc::CompilationUnitAnalysisManager::id<UnitFunctionCountAnalysis>()) && + !FunctionAnalyses.hasCached( + *FirstFunction, rcc::MachineFunctionAnalysisManager::id<BlockCountAnalysis>()), + "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 <algorithm> -#include <atomic> -#include <chrono> -#include <cstddef> -#include <cstdint> -#include <iostream> -#include <memory> -#include <ranges> -#include <string> -#include <string_view> -#include <thread> -#include <utility> -#include <vector> - -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<rcc::TargetDescription> createTarget() { - std::vector<rcc::InstructionDescriptor> Descriptors; - std::vector<rcc::ImmediatePredicate> 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<Result> run(rcc::MachineFunction &Function, - const rcc::TargetDescription &, - rcc::MachineAnalysisManager &) { - ++Runs; - return Result{Function.blockCount()}; - } - - static inline std::atomic<std::uint32_t> 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<Result> run(rcc::MachineFunction &Function, - const rcc::TargetDescription &Target, - rcc::MachineAnalysisManager &Analyses) { - auto Blocks = Analyses.getResult<BlockCountAnalysis>(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<Result> - 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<Result> - 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<Result> - 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<Result> - 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<Result> - 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<Result> - 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<DependentAnalysis>()}, - .VerificationStage = std::nullopt, - }; - return Contract; - } - - [[nodiscard]] rcc::Expected<rcc::MachinePassResult> - run(rcc::MachineFunction &Function, const rcc::TargetDescription &Target, - rcc::MachineAnalysisManager &Analyses) override { - auto Dependent = Analyses.getResult<DependentAnalysis>(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<rcc::MachinePassResult> 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<FailingAnalysis>()}, - .VerificationStage = std::nullopt, - }; - return Contract; - } - - [[nodiscard]] rcc::Expected<rcc::MachinePassResult> 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<BlockCountAnalysis>()}, - .VerificationStage = std::nullopt, - }; - return Contract; - } - - [[nodiscard]] rcc::Expected<rcc::MachinePassResult> 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<std::uint32_t> &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<rcc::MachinePassResult> run(rcc::MachineFunction &, - const rcc::TargetDescription &, - rcc::MachineAnalysisManager &) override { - Count->fetch_add(1, std::memory_order_relaxed); - return rcc::MachinePassResult{}; - } - -private: - std::atomic<std::uint32_t> *Count; -}; - -class InstrumentedParallelPass final : public rcc::MachineFunctionPass { -public: - InstrumentedParallelPass(std::atomic<std::uint32_t> &Runs, std::atomic<std::uint32_t> &Active, - std::atomic<std::uint32_t> &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<rcc::MachinePassResult> 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<std::uint32_t> *Runs; - std::atomic<std::uint32_t> *Active; - std::atomic<std::uint32_t> *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<NonThreadSafeAnalysis>(), - }, - .VerificationStage = std::nullopt, - }; - Value.ThreadSafety = rcc::PassThreadSafety::ThreadSafe; - return Value; - }(); - return Contract; - } - - [[nodiscard]] rcc::Expected<rcc::MachinePassResult> 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<Result> 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<Result> 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<FailingUnitAnalysis>(), - }, - .Parameters = {}, - .DeclaredChanges = {}, - }; - return Contract; - } - - [[nodiscard]] rcc::Expected<rcc::CompilationUnitPassResult> - 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<UnitFunctionCountAnalysis>()}, - .Parameters = {}, - .DeclaredChanges = {}, - }; - return Contract; - } - - [[nodiscard]] rcc::Expected<rcc::CompilationUnitPassResult> - run(rcc::CompilationUnit &Unit, const rcc::TargetDescription &Target, - rcc::CompilationUnitAnalysisManager &Analyses, rcc::MachineAnalysisManager &) override { - auto Count = Analyses.getResult<UnitFunctionCountAnalysis>(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<UnitFunctionCountAnalysis>()}, - .Parameters = {}, - .DeclaredChanges = {rcc::MachinePassChange::BlockLayout}, - }; - return Contract; - } - - [[nodiscard]] rcc::Expected<rcc::CompilationUnitPassResult> - 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<BlockCountAnalysis>({ - .Name = "BlockCount", - .Dependencies = {}, - .InvalidatedBy = {rcc::MachinePassChange::CFG}, - }) - .has_value(), - "base analysis registration must succeed"); - Context.expect(Analyses - .registerAnalysis<DependentAnalysis>({ - .Name = "Dependent", - .Dependencies = {rcc::MachineAnalysisManager::id<BlockCountAnalysis>()}, - .InvalidatedBy = {rcc::MachinePassChange::Operands}, - }) - .has_value(), - "dependent analysis registration must succeed"); - - BlockCountAnalysis::Runs = 0; - auto First = Analyses.getResult<DependentAnalysis>(**Function, Target); - auto Second = Analyses.getResult<DependentAnalysis>(**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<CycleA>({ - .Name = "CycleA", - .Dependencies = {rcc::MachineAnalysisManager::id<CycleB>()}, - }) - .has_value() && - Cyclic - .registerAnalysis<CycleB>({ - .Name = "CycleB", - .Dependencies = {rcc::MachineAnalysisManager::id<CycleA>()}, - }) - .has_value(), - "cyclic analysis registrations must be accepted until requested"); - Context.expect(!Cyclic.getResult<CycleA>(**Function, Target), - "analysis dependency cycles must produce a structured error"); - - rcc::MachineAnalysisManager CustomInvalidation; - Context.expect(CustomInvalidation - .registerAnalysis<StickyAnalysis>({ - .Name = "Sticky", - .Dependencies = {}, - .InvalidatedBy = {rcc::MachinePassChange::CFG}, - }) - .has_value() && - CustomInvalidation - .registerAnalysis<ExpiringAnalysis>({ - .Name = "Expiring", - .Dependencies = {}, - .InvalidatedBy = {rcc::MachinePassChange::CFG}, - }) - .has_value() && - CustomInvalidation.getResult<StickyAnalysis>(**Function, Target) && - CustomInvalidation.getResult<ExpiringAnalysis>(**Function, Target), - "custom invalidation analyses must materialize"); - CustomInvalidation.invalidate(**Function, rcc::PreservedAnalyses::none(), - {rcc::MachinePassChange::CFG}); - Context.expect( - CustomInvalidation.hasCached(**Function, rcc::MachineAnalysisManager::id<StickyAnalysis>()) && - !CustomInvalidation.hasCached(**Function, - rcc::MachineAnalysisManager::id<ExpiringAnalysis>()), - "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<BlockCountAnalysis>({ - .Name = "BlockCount", - .Dependencies = {}, - .InvalidatedBy = rcc::MachinePassChanges::all(), - .ThreadSafety = rcc::PassThreadSafety::ThreadSafe, - }) - .has_value() && - Analyses - .registerAnalysis<DependentAnalysis>({ - .Name = "Dependent", - .Dependencies = {rcc::MachineAnalysisManager::id<BlockCountAnalysis>()}, - }) - .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<RequiredAnalysisPass>()).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<UnreportedChangePass>()).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<BlockCountAnalysis>({ - .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<MutatingFailurePass>()).has_value() && - !FailingPipeline.run(**FailedFunction, Target, FailureAnalyses) && - !FailureAnalyses.hasCached( - **FailedFunction, rcc::MachineAnalysisManager::id<BlockCountAnalysis>()), - "a pass that mutates and fails must not leave stale function analyses cached"); - - rcc::MachineAnalysisManager FailingAnalyses; - Context.expect(FailingAnalyses - .registerAnalysis<FailingAnalysis>({ - .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<RequiresFailingAnalysisPass>()) - .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<std::uint32_t> Runs = 0; - rcc::MachinePassManager Parallel; - Context.expect(Parallel.addPass(std::make_unique<ParallelCountingPass>(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<std::uint32_t> DuplicateRuns = 0; - rcc::MachinePassManager Repeated; - Context.expect( - Repeated.addPass(std::make_unique<ParallelCountingPass>(DuplicateRuns)).has_value() && - Repeated.addPass(std::make_unique<ParallelCountingPass>(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<std::string> ObservedFunctions; - std::vector<std::size_t> BeforeBlockCounts; - std::vector<std::size_t> 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<std::uint32_t> InstrumentedRuns = 0; - std::atomic<std::uint32_t> ActiveRuns = 0; - std::atomic<std::uint32_t> MaximumActiveRuns = 0; - rcc::MachinePassManager Instrumented; - Context.expect( - Instrumented - .addPass(std::make_unique<InstrumentedParallelPass>(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<NonThreadSafeAnalysis>({ - .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<RequiresNonThreadSafeAnalysisPass>()).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<UnitFunctionCountAnalysis>({ - .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<ObserveUnitPass>()).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<FailingUnitAnalysis>({ - .Name = "FailingUnit", - .Dependencies = {}, - }) - .has_value(), - "failing compilation-unit analysis registration must succeed"); - rcc::CompilationUnitPassManager FailingUnitAnalysisPipeline; - Context.expect( - FailingUnitAnalysisPipeline.addPass(std::make_unique<RequiresFailingUnitAnalysisPass>()) - .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<BlockCountAnalysis>({ - .Name = "BlockCount", - .Dependencies = {}, - .InvalidatedBy = rcc::MachinePassChanges::all(), - }) - .has_value() && - FunctionAnalyses.getResult<BlockCountAnalysis>(*FirstFunction, Target).has_value(), - "compilation-unit failure cache fixtures must materialize"); - rcc::CompilationUnitPassManager FailingUnitPipeline; - Context.expect( - FirstFunction != nullptr && - FailingUnitPipeline.addPass(std::make_unique<MutatingUnitFailurePass>()).has_value() && - !FailingUnitPipeline.run(Unit, Target, UnitAnalyses, FunctionAnalyses) && - !UnitAnalyses.hasCached( - Unit, rcc::CompilationUnitAnalysisManager::id<UnitFunctionCountAnalysis>()) && - !FunctionAnalyses.hasCached(*FirstFunction, - rcc::MachineAnalysisManager::id<BlockCountAnalysis>()), - "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 <array> @@ -62,11 +62,11 @@ buildPhi(rcc::MachineFunction &Function, const rcc::TargetDescription &Target, [[nodiscard]] rcc::Expected<void> 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<rcc::PHIEliminationPass>(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 <cstddef> +#include <cstdint> +#include <iostream> +#include <memory> +#include <string_view> +#include <utility> +#include <vector> + +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<rcc::TargetDescription> createTarget() { + std::vector<rcc::InstructionDescriptor> Descriptors; + std::vector<rcc::ImmediatePredicate> 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<Result> 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<BlockCountAnalysis>(), + }, + .VerificationStage = std::nullopt, + }; + return Contract; + } + + [[nodiscard]] rcc::Expected<rcc::MachinePassResult> + run(rcc::MachineFunction &Function, const rcc::TargetDescription &Target, + rcc::MachineFunctionAnalysisManager &Analyses) override { + auto First = Analyses.getResult<BlockCountAnalysis>(Function, Target); + auto Second = Analyses.getResult<BlockCountAnalysis>(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<BlockCountAnalysis>({ + .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<InstrumentedPass>()).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 <atomic> +#include <cstddef> +#include <cstdint> +#include <iostream> +#include <string_view> +#include <utility> +#include <vector> + +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<rcc::TargetDescription> createTarget() { + std::vector<rcc::InstructionDescriptor> Descriptors; + std::vector<rcc::ImmediatePredicate> 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<Result> run(rcc::MachineFunction &Function, + const rcc::TargetDescription &, + rcc::MachineFunctionAnalysisManager &) { + ++Runs; + return Result{Function.blockCount()}; + } + + static inline std::atomic<std::uint32_t> 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<Result> run(rcc::MachineFunction &Function, + const rcc::TargetDescription &Target, + rcc::MachineFunctionAnalysisManager &Analyses) { + auto Blocks = Analyses.getResult<BlockCountAnalysis>(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<Result> 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<Result> 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<Result> 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<Result> 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<BlockCountAnalysis>({ + .Name = "BlockCount", + .Dependencies = {}, + .InvalidatedBy = {rcc::MachinePassChange::CFG}, + }) + .has_value(), + "base analysis registration must succeed"); + Context.expect(Analyses + .registerAnalysis<DependentAnalysis>({ + .Name = "Dependent", + .Dependencies = + { + rcc::MachineFunctionAnalysisManager::id<BlockCountAnalysis>(), + }, + .InvalidatedBy = {rcc::MachinePassChange::Operands}, + }) + .has_value(), + "dependent analysis registration must succeed"); + + BlockCountAnalysis::Runs = 0; + auto First = Analyses.getResult<DependentAnalysis>(**Function, Target); + auto Second = Analyses.getResult<DependentAnalysis>(**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<CycleA>({ + .Name = "CycleA", + .Dependencies = + { + rcc::MachineFunctionAnalysisManager::id<CycleB>(), + }, + }) + .has_value() && + Cyclic + .registerAnalysis<CycleB>({ + .Name = "CycleB", + .Dependencies = + { + rcc::MachineFunctionAnalysisManager::id<CycleA>(), + }, + }) + .has_value(), + "cyclic analysis registrations must be accepted until requested"); + Context.expect(!Cyclic.getResult<CycleA>(**Function, Target), + "analysis dependency cycles must produce a structured error"); + + rcc::MachineFunctionAnalysisManager CustomInvalidation; + Context.expect(CustomInvalidation + .registerAnalysis<StickyAnalysis>({ + .Name = "Sticky", + .Dependencies = {}, + .InvalidatedBy = {rcc::MachinePassChange::CFG}, + }) + .has_value() && + CustomInvalidation + .registerAnalysis<ExpiringAnalysis>({ + .Name = "Expiring", + .Dependencies = {}, + .InvalidatedBy = {rcc::MachinePassChange::CFG}, + }) + .has_value() && + CustomInvalidation.getResult<StickyAnalysis>(**Function, Target) && + CustomInvalidation.getResult<ExpiringAnalysis>(**Function, Target), + "custom invalidation analyses must materialize"); + CustomInvalidation.invalidate(**Function, rcc::PreservedAnalyses::none(), + {rcc::MachinePassChange::CFG}); + Context.expect(CustomInvalidation.hasCached( + **Function, rcc::MachineFunctionAnalysisManager::id<StickyAnalysis>()) && + !CustomInvalidation.hasCached( + **Function, rcc::MachineFunctionAnalysisManager::id<ExpiringAnalysis>()), + "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<rcc::PBQPAllocatorPass>(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<rcc::LiveIntervalsAnalysis>(*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<PBQPAllocatorPass>(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 <array> @@ -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<rcc::TwoAddressInstructionPass>(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<rcc::PrologueEpilogueInsertionPass>(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::PrologueEpilogueInsertionPass>( 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<rcc::FinalizeEmissionPseudosPass>()) && Pipeline.addPass(std::make_unique<rcc::FinalEncodabilityVerifierPass>( 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::PBQPAllocatorPass>(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::PHIEliminationPass>(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) |
