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/include | |
| parent | a2f8d7c5e22b510965327383410bd576f7cf28e7 (diff) | |
| download | rcc-project-236082a0fe4dcd0362c5c74923a93e3db6a01291.tar.gz rcc-project-236082a0fe4dcd0362c5c74923a93e3db6a01291.tar.xz | |
[CodeGen] Align pass manager ownership
Diffstat (limited to 'backend/include')
42 files changed, 1142 insertions, 826 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" |
