//===- 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 // //===----------------------------------------------------------------------===// // Test that the various MachineFunction pass managers, adaptors, analyses, and // analysis managers work. //===----------------------------------------------------------------------===// #include "llvm/IR/PassManager.h" #include "llvm/Analysis/CGSCCPassManager.h" #include "llvm/Analysis/LoopAnalysisManager.h" #include "llvm/AsmParser/Parser.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineModuleInfo.h" #include "llvm/CodeGen/MachinePassManager.h" #include "llvm/IR/Analysis.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/MC/TargetRegistry.h" #include "llvm/Passes/PassBuilder.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Target/TargetMachine.h" #include "llvm/TargetParser/Host.h" #include "llvm/TargetParser/Triple.h" #include "gtest/gtest.h" using namespace llvm; namespace { class TestFunctionAnalysis : public AnalysisInfoMixin { public: struct Result { Result(int Count) : InstructionCount(Count) {} int InstructionCount; }; /// The number of instructions in the Function. Result run(Function &F, FunctionAnalysisManager &AM) { return Result(F.getInstructionCount()); } private: friend AnalysisInfoMixin; static AnalysisKey Key; }; AnalysisKey TestFunctionAnalysis::Key; class TestMachineFunctionAnalysis : public AnalysisInfoMixin { public: struct Result { Result(int Count) : InstructionCount(Count) {} int InstructionCount; }; Result run(MachineFunction &MF, MachineFunctionAnalysisManager &AM) { FunctionAnalysisManager &FAM = AM.getResult(MF) .getManager(); TestFunctionAnalysis::Result &FAR = FAM.getResult(MF.getFunction()); return FAR.InstructionCount; } private: friend AnalysisInfoMixin; static AnalysisKey Key; }; AnalysisKey TestMachineFunctionAnalysis::Key; struct TestMachineFunctionPass : public PassInfoMixin { TestMachineFunctionPass(int &Count, std::vector &Counts) : Count(Count), Counts(Counts) {} PreservedAnalyses run(MachineFunction &MF, MachineFunctionAnalysisManager &MFAM) { FunctionAnalysisManager &FAM = MFAM.getResult(MF) .getManager(); TestFunctionAnalysis::Result &FAR = FAM.getResult(MF.getFunction()); Count += FAR.InstructionCount; TestMachineFunctionAnalysis::Result &MFAR = MFAM.getResult(MF); Count += MFAR.InstructionCount; Counts.push_back(Count); return PreservedAnalyses::none(); } int &Count; std::vector &Counts; }; struct TestMachineModulePass : public PassInfoMixin { TestMachineModulePass(int &Count, std::vector &Counts) : Count(Count), Counts(Counts) {} PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM) { MachineModuleInfo &MMI = MAM.getResult(M).getMMI(); FunctionAnalysisManager &FAM = MAM.getResult(M).getManager(); MachineFunctionAnalysisManager &MFAM = MAM.getResult(M) .getManager(); for (Function &F : M) { MachineFunction &MF = MMI.getOrCreateMachineFunction(F); Count += FAM.getResult(F).InstructionCount; Count += MFAM.getResult(MF).InstructionCount; } Counts.push_back(Count); return PreservedAnalyses::all(); } int &Count; std::vector &Counts; }; struct ReportWarningPass : public PassInfoMixin { PreservedAnalyses run(MachineFunction &MF, MachineFunctionAnalysisManager &MFAM) { auto &Ctx = MF.getContext(); Ctx.reportWarning(SMLoc(), "Test warning message."); return PreservedAnalyses::all(); } }; 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; std::unique_ptr TM; 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")) { // MachineModuleAnalysis needs a TargetMachine instance. llvm::InitializeAllTargets(); std::string TripleName = Triple::normalize(sys::getDefaultTargetTriple()); std::string Error; const Target *TheTarget = TargetRegistry::lookupTarget(TripleName, Error); if (!TheTarget) return; TargetOptions Options; TM.reset(TheTarget->createTargetMachine(TripleName, "", "", Options, std::nullopt)); } }; TEST_F(PassManagerTest, Basic) { if (!TM) GTEST_SKIP(); M->setDataLayout(TM->createDataLayout()); MachineModuleInfo MMI(TM.get()); MachineFunctionAnalysisManager MFAM; LoopAnalysisManager LAM; FunctionAnalysisManager FAM; CGSCCAnalysisManager CGAM; ModuleAnalysisManager MAM; PassBuilder PB(TM.get()); PB.registerModuleAnalyses(MAM); PB.registerCGSCCAnalyses(CGAM); PB.registerFunctionAnalyses(FAM); PB.registerLoopAnalyses(LAM); PB.registerMachineFunctionAnalyses(MFAM); PB.crossRegisterProxies(LAM, FAM, CGAM, MAM, &MFAM); FAM.registerPass([&] { return TestFunctionAnalysis(); }); MAM.registerPass([&] { return MachineModuleAnalysis(MMI); }); MFAM.registerPass([&] { return TestMachineFunctionAnalysis(); }); int Count = 0; std::vector Counts; ModulePassManager MPM; FunctionPassManager FPM; MachineFunctionPassManager MFPM; MPM.addPass(TestMachineModulePass(Count, Counts)); FPM.addPass(createFunctionToMachineFunctionPassAdaptor( TestMachineFunctionPass(Count, Counts))); MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); MPM.addPass(TestMachineModulePass(Count, Counts)); MFPM.addPass(TestMachineFunctionPass(Count, Counts)); FPM = FunctionPassManager(); FPM.addPass(createFunctionToMachineFunctionPassAdaptor(std::move(MFPM))); MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); testing::internal::CaptureStderr(); MPM.run(*M, MAM); std::string Output = testing::internal::GetCapturedStderr(); EXPECT_EQ((std::vector{10, 16, 18, 20, 30, 36, 38, 40}), Counts); EXPECT_EQ(40, Count); } TEST_F(PassManagerTest, DiagnosticHandler) { if (!TM) GTEST_SKIP(); M->setDataLayout(TM->createDataLayout()); MachineModuleInfo MMI(TM.get()); LoopAnalysisManager LAM; MachineFunctionAnalysisManager MFAM; FunctionAnalysisManager FAM; CGSCCAnalysisManager CGAM; ModuleAnalysisManager MAM; PassBuilder PB(TM.get()); PB.registerModuleAnalyses(MAM); PB.registerCGSCCAnalyses(CGAM); PB.registerFunctionAnalyses(FAM); PB.registerLoopAnalyses(LAM); PB.registerMachineFunctionAnalyses(MFAM); PB.crossRegisterProxies(LAM, FAM, CGAM, MAM, &MFAM); MAM.registerPass([&] { return MachineModuleAnalysis(MMI); }); ModulePassManager MPM; FunctionPassManager FPM; MachineFunctionPassManager MFPM; MPM.addPass(RequireAnalysisPass()); MFPM.addPass(ReportWarningPass()); FPM.addPass(createFunctionToMachineFunctionPassAdaptor(std::move(MFPM))); MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); testing::internal::CaptureStderr(); MPM.run(*M, MAM); std::string Output = testing::internal::GetCapturedStderr(); EXPECT_TRUE(Output.find("warning: :0: Test warning message.") != std::string::npos); } } // namespace