diff --git a/llvm/include/llvm/CodeGen/PassManager.h b/llvm/include/llvm/CodeGen/PassManager.h new file mode 100644 --- /dev/null +++ b/llvm/include/llvm/CodeGen/PassManager.h @@ -0,0 +1,114 @@ +//===- PassManager.h --- Pass management for CodeGen ------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Interface for the pass manager functionality used for CodeGen. The CodeGen +// pipeline consists of only machine function passes. There is no container +// relationship between IR module/function and machine function in terms of pass +// manager organization. So there is no need for adaptor classes (for example +// ModuleToMachineFunctionAdaptor). Since invalidation could only happen among +// machine function passes, there is no proxy classes to handle cross-IR-unit +// invalidation. IR analysis results are provided for machine function passes by +// their respective analysis managers such as ModuleAnalysisManager and +// FunctionAnalysisManager. +// +// doInitilization/doFinalization are available like they do in legacy pass +// manager. This is mostly for AsmPrinter. Their uses in other passes could be +// converted easily to use either constructor or lazy initialization in `run` +// method. +// +// TODO: Add PassInstrumentation function. +// TODO: Add a path in CodeGen to experiment with this interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CODEGEN_PASS_MANAGER_H +#define LLVM_CODEGEN_PASS_MANAGER_H + +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/IR/PassManager.h" + +namespace llvm { +extern template class AnalysisManager; + +/// Machine function passes use this by default. +using MachineFunctionAnalysisManager = AnalysisManager; + +/// Expose IR analysis results to machine function pass. +class MachineFunctionIRAnalysisManager : public MachineFunctionAnalysisManager { + // Add LoopAnalysisManager or CGSCCAnalysisManager in the future if needed. + FunctionAnalysisManager *FAM; + ModuleAnalysisManager *MAM; + +public: + MachineFunctionIRAnalysisManager(bool DebugLogging = false, + FunctionAnalysisManager *FAM = nullptr, + ModuleAnalysisManager *MAM = nullptr) + : MachineFunctionAnalysisManager(DebugLogging), FAM(FAM), MAM(MAM) {} + MachineFunctionIRAnalysisManager(MachineFunctionIRAnalysisManager &&) = + default; + MachineFunctionIRAnalysisManager & + operator=(MachineFunctionIRAnalysisManager &&) = default; + + template typename PassT::Result &getResult(const Module &M) { + assert(MAM); + return MAM->getResult(const_cast(M)); + } + template + typename PassT::Result &getResult(const Function &F) { + assert(FAM); + return FAM->getResult(const_cast(F)); + } +}; + +extern template class PassManager; + +class MachineFunctionPassManager : public PassManager { +public: + MachineFunctionPassManager(bool DebugLogging = false) + : PassManager(DebugLogging) {} + MachineFunctionPassManager(MachineFunctionPassManager &&) = default; + MachineFunctionPassManager & + operator=(MachineFunctionPassManager &&) = default; + + /// Entry point for codegen. + void run(const Module &M, MachineFunctionIRAnalysisManager &MFAM); + + template < + typename PassT, + bool HasDoInitialization = + detail::PassHasDoInitializationMethod::value, + bool HasDoFinalizatio = + detail::PassHasDoFinalizationMethod::value> + void addPass(PassT Pass) { + using PassModelT = + detail::PassModel; + + PassManager::addPass(Pass); + + if (HasDoInitialization) { + auto *P = reinterpret_cast(Passes.back().get()); + InitializationFuncs.push_back( + [=](const Module &M) { P->Pass.doInitialization(M); }); + } + + if (HasDoFinalizatio) { + auto *P = reinterpret_cast(Passes.back().get()); + FinalizationFuncs.push_back( + [=](const Module &M) { P->Pass.doFinalization(M); }); + } + } + +private: + std::vector> InitializationFuncs; + std::vector> FinalizationFuncs; +}; + +} // end namespace llvm + +#endif // LLVM_CODEGEN_PASS_MANAGER_H diff --git a/llvm/include/llvm/IR/PassManager.h b/llvm/include/llvm/IR/PassManager.h --- a/llvm/include/llvm/IR/PassManager.h +++ b/llvm/include/llvm/IR/PassManager.h @@ -554,12 +554,13 @@ Passes.emplace_back(new PassModelT(std::move(Pass))); } -private: +protected: using PassConceptT = detail::PassConcept; std::vector> Passes; +private: /// Flag indicating whether we should do debug logging. bool DebugLogging; }; diff --git a/llvm/include/llvm/IR/PassManagerInternal.h b/llvm/include/llvm/IR/PassManagerInternal.h --- a/llvm/include/llvm/IR/PassManagerInternal.h +++ b/llvm/include/llvm/IR/PassManagerInternal.h @@ -301,6 +301,32 @@ PassT Pass; }; +// SFINAE for doInitialization. +template class PassHasDoInitializationMethod { + using EnabledType = char; + using DisabledType = char[2]; + + template + static EnabledType &check(decltype(&T::doInitialization)); + template static DisabledType &check(...); + +public: + enum { value = sizeof(check(0)) == sizeof(EnabledType) }; +}; + +// SFINAE for doFinalization. +template class PassHasDoFinalizationMethod { + using EnabledType = char; + using DisabledType = char[2]; + + template + static EnabledType &check(decltype(&T::doFinalization)); + template static DisabledType &check(...); + +public: + enum { value = sizeof(check(0)) == sizeof(EnabledType) }; +}; + } // end namespace detail } // end namespace llvm diff --git a/llvm/lib/CodeGen/CMakeLists.txt b/llvm/lib/CodeGen/CMakeLists.txt --- a/llvm/lib/CodeGen/CMakeLists.txt +++ b/llvm/lib/CodeGen/CMakeLists.txt @@ -106,6 +106,7 @@ NonRelocatableStringpool.cpp OptimizePHIs.cpp ParallelCG.cpp + PassManager.cpp PeepholeOptimizer.cpp PHIElimination.cpp PHIEliminationUtils.cpp diff --git a/llvm/lib/CodeGen/PassManager.cpp b/llvm/lib/CodeGen/PassManager.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/CodeGen/PassManager.cpp @@ -0,0 +1,48 @@ +//===---------- PassManager.cpp -------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file contains the pass management machinery for machine functions. +// +//===----------------------------------------------------------------------===// + +#include "llvm/CodeGen/PassManager.h" +#include "llvm/CodeGen/MachineModuleInfo.h" + +using namespace llvm; + +namespace llvm { +template class AllAnalysesOn; +template class AnalysisManager; +template class PassManager; + +void MachineFunctionPassManager::run(const Module &M, + MachineFunctionIRAnalysisManager &MFAM) { + MachineModuleInfo &MMI = MFAM.getResult(M); + + for (auto F : InitializationFuncs) + F(M); + + PreservedAnalyses PA = PreservedAnalyses::all(); + for (auto &P : Passes) { + for (const Function &F : M) { + // Do not codegen any 'available_externally' functions at all, they have + // definitions outside the translation unit. + if (F.hasAvailableExternallyLinkage()) + continue; + + MachineFunction &MF = MMI.getOrCreateMachineFunction(F); + PreservedAnalyses PassPA = P->run(MF, MFAM); + MFAM.invalidate(MF, PassPA); + } + } + + for (auto F : FinalizationFuncs) + F(M); +} + +} // namespace llvm diff --git a/llvm/unittests/CodeGen/CMakeLists.txt b/llvm/unittests/CodeGen/CMakeLists.txt --- a/llvm/unittests/CodeGen/CMakeLists.txt +++ b/llvm/unittests/CodeGen/CMakeLists.txt @@ -7,6 +7,7 @@ Core MC MIRParser + Passes SelectionDAG Support Target @@ -19,6 +20,7 @@ MachineInstrBundleIteratorTest.cpp MachineInstrTest.cpp MachineOperandTest.cpp + PassManagerTest.cpp ScalableVectorMVTsTest.cpp TypeTraitsTest.cpp TargetOptionsTest.cpp diff --git a/llvm/unittests/CodeGen/PassManagerTest.cpp b/llvm/unittests/CodeGen/PassManagerTest.cpp new file mode 100644 --- /dev/null +++ b/llvm/unittests/CodeGen/PassManagerTest.cpp @@ -0,0 +1,190 @@ +//===- llvm/unittest/CodeGen/PassManager.cpp - PassManager tests ----------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/Analysis/CGSCCPassManager.h" +#include "llvm/Analysis/LoopAnalysisManager.h" +#include "llvm/AsmParser/Parser.h" +#include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/CodeGen/PassManager.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Module.h" +#include "llvm/Passes/PassBuilder.h" +#include "llvm/Support/SourceMgr.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Target/TargetMachine.h" +#include "gtest/gtest.h" + +using namespace llvm; + +namespace { + +class TestFunctionAnalysis : public AnalysisInfoMixin { +public: + struct Result { + Result(int Count) : InstructionCount(Count) {} + int InstructionCount; + }; + + /// Run the analysis pass over the function and return a result. + Result run(Function &F, FunctionAnalysisManager &AM) { + int Count = 0; + for (Function::iterator BBI = F.begin(), BBE = F.end(); BBI != BBE; ++BBI) + for (BasicBlock::iterator II = BBI->begin(), IE = BBI->end(); II != IE; + ++II) + ++Count; + return Result(Count); + } + +private: + friend AnalysisInfoMixin; + static AnalysisKey Key; +}; + +AnalysisKey TestFunctionAnalysis::Key; + +class TestMachineFunctionAnalysis + : public AnalysisInfoMixin { +public: + struct Result { + Result(int Count) : InstructionCount(Count) {} + int InstructionCount; + }; + + /// Run the analysis pass over the machine function and return a result. + Result run(MachineFunction &MF, MachineFunctionAnalysisManager &AM) { + return Result(MF.getInstructionCount()); + } + +private: + friend AnalysisInfoMixin; + static AnalysisKey Key; +}; + +AnalysisKey TestMachineFunctionAnalysis::Key; + +struct TestMachineFunctionPass : PassInfoMixin { + TestMachineFunctionPass(int &Count, int &BeforeInitialization, + int &BeforeFinalization) + : Count(Count), BeforeInitialization(BeforeInitialization), + BeforeFinalization(BeforeFinalization) {} + + void doInitialization(const Module &M) { BeforeInitialization = Count; } + void doFinalization(const Module &M) { BeforeFinalization = Count; } + + PreservedAnalyses run(MachineFunction &MF, + MachineFunctionAnalysisManager &AM) { + auto &IRAM = static_cast(AM); + + // Query function analysis result. + TestFunctionAnalysis::Result &FAR = + IRAM.getResult(MF.getFunction()); + // + 5 + Count += FAR.InstructionCount; + + // Query module analysis result. + MachineModuleInfo &MMI = + IRAM.getResult(*MF.getFunction().getParent()); + // + 3 + Count += (MMI.getModule() == MF.getFunction().getParent()); + + // Query machine function analysis result. + TestMachineFunctionAnalysis::Result &MFAR = + AM.getResult(MF); + // + 0 + Count += MFAR.InstructionCount; + + return PreservedAnalyses::none(); + } + + int &Count; + int &BeforeInitialization; + int &BeforeFinalization; +}; + +std::unique_ptr parseIR(LLVMContext &Context, const char *IR) { + SMDiagnostic Err; + return parseAssemblyString(IR, Err, Context); +} + +class PassManagerTest : public ::testing::Test { +protected: + LLVMContext Context; + std::unique_ptr M; + +public: + PassManagerTest() + : M(parseIR(Context, "define void @f() {\n" + "entry:\n" + " call void @g()\n" + " call void @h()\n" + " ret void\n" + "}\n" + "define void @g() {\n" + " ret void\n" + "}\n" + "define void @h() {\n" + " ret void\n" + "}\n")) {} +}; + +TEST_F(PassManagerTest, Basic) { + // Create LLVMTargetMachine to initilize MachineModuleAnalysis. + std::string Error; + const Target *T = + TargetRegistry::lookupTarget("x86_64-unknown-linux", Error); + assert(T); + + TargetOptions Options; + std::unique_ptr TM( + T->createTargetMachine("x86_64-unknown-linux", "", "", Options, None, + None, CodeGenOpt::Aggressive)); + LLVMTargetMachine *LLVMTM = static_cast(TM.get()); + M->setDataLayout(TM->createDataLayout()); + + LoopAnalysisManager LAM(/*DebugLogging*/ true); + FunctionAnalysisManager FAM(/*DebugLogging*/ true); + CGSCCAnalysisManager CGAM(/*DebugLogging*/ true); + ModuleAnalysisManager MAM(/*DebugLogging*/ true); + MAM.registerPass([&] { return PassInstrumentationAnalysis(); }); + MAM.registerPass([&] { return MachineModuleAnalysis(LLVMTM); }); + FAM.registerPass([&] { return PassInstrumentationAnalysis(); }); + FAM.registerPass([&] { return TestFunctionAnalysis(); }); + PassBuilder PB; + PB.crossRegisterProxies(LAM, FAM, CGAM, MAM); + + MachineFunctionIRAnalysisManager MFAM; + { + // Test move assignment. + MachineFunctionIRAnalysisManager NestedMFAM(/*DebugLogging*/ true, &FAM, + &MAM); + NestedMFAM.registerPass([&] { return PassInstrumentationAnalysis(); }); + NestedMFAM.registerPass([&] { return TestMachineFunctionAnalysis(); }); + MFAM = std::move(NestedMFAM); + } + + int Count = 0; + int BeforeInitialization; + int BeforeFinalization; + + MachineFunctionPassManager MFPM; + { + // Test move assignment. + MachineFunctionPassManager NestedMFPM(/*DebugLogging*/ true); + NestedMFPM.addPass(TestMachineFunctionPass(Count, BeforeInitialization, + BeforeFinalization)); + MFPM = std::move(NestedMFPM); + } + + MFPM.run(*M, MFAM); + + EXPECT_EQ(8, Count); + EXPECT_EQ(0, BeforeInitialization); + EXPECT_EQ(8, BeforeFinalization); +} + +}