//===- llvm/unittest/IR/PassManager.cpp - PassManager tests ---------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "llvm/AsmParser/Parser.h" #include "llvm/IR/Function.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/IR/PassManager.h" #include "llvm/Support/SourceMgr.h" #include "gtest/gtest.h" using namespace llvm; namespace { class TestFunctionAnalysis { public: struct Result { Result(int Count) : InstructionCount(Count) {} int InstructionCount; }; /// \brief Returns an opaque, unique ID for this pass type. static void *ID() { return (void *)&PassID; } TestFunctionAnalysis(int &Runs) : Runs(Runs) {} /// \brief Run the analysis pass over the function and return a result. Result run(Function *F, FunctionAnalysisManager *AM) { ++Runs; 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: /// \brief Private static data to provide unique ID. static char PassID; int &Runs; }; char TestFunctionAnalysis::PassID; class TestModuleAnalysis { public: struct Result { Result(int Count) : FunctionCount(Count) {} int FunctionCount; }; static void *ID() { return (void *)&PassID; } TestModuleAnalysis(int &Runs) : Runs(Runs) {} Result run(Module *M, ModuleAnalysisManager *AM) { ++Runs; int Count = 0; for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I) ++Count; return Result(Count); } private: static char PassID; int &Runs; }; char TestModuleAnalysis::PassID; struct TestModulePass { TestModulePass(int &RunCount) : RunCount(RunCount) {} PreservedAnalyses run(Module *M) { ++RunCount; return PreservedAnalyses::none(); } static StringRef name() { return "TestModulePass"; } int &RunCount; }; struct TestPreservingModulePass { PreservedAnalyses run(Module *M) { return PreservedAnalyses::all(); } static StringRef name() { return "TestPreservingModulePass"; } }; struct TestMinPreservingModulePass { PreservedAnalyses run(Module *M, ModuleAnalysisManager *AM) { PreservedAnalyses PA; // Force running an analysis. (void)AM->getResult(M); PA.preserve(); return PA; } static StringRef name() { return "TestMinPreservingModulePass"; } }; struct TestFunctionPass { TestFunctionPass(int &RunCount, int &AnalyzedInstrCount, int &AnalyzedFunctionCount, bool OnlyUseCachedResults = false) : RunCount(RunCount), AnalyzedInstrCount(AnalyzedInstrCount), AnalyzedFunctionCount(AnalyzedFunctionCount), OnlyUseCachedResults(OnlyUseCachedResults) {} PreservedAnalyses run(Function *F, FunctionAnalysisManager *AM) { ++RunCount; const ModuleAnalysisManager &MAM = AM->getResult(F).getManager(); if (TestModuleAnalysis::Result *TMA = MAM.getCachedResult(F->getParent())) AnalyzedFunctionCount += TMA->FunctionCount; if (OnlyUseCachedResults) { // Hack to force the use of the cached interface. if (TestFunctionAnalysis::Result *AR = AM->getCachedResult(F)) AnalyzedInstrCount += AR->InstructionCount; } else { // Typical path just runs the analysis as needed. TestFunctionAnalysis::Result &AR = AM->getResult(F); AnalyzedInstrCount += AR.InstructionCount; } return PreservedAnalyses::all(); } static StringRef name() { return "TestFunctionPass"; } int &RunCount; int &AnalyzedInstrCount; int &AnalyzedFunctionCount; bool OnlyUseCachedResults; }; // A test function pass that invalidates all function analyses for a function // with a specific name. struct TestInvalidationFunctionPass { TestInvalidationFunctionPass(StringRef FunctionName) : Name(FunctionName) {} PreservedAnalyses run(Function *F) { return F->getName() == Name ? PreservedAnalyses::none() : PreservedAnalyses::all(); } static StringRef name() { return "TestInvalidationFunctionPass"; } StringRef Name; }; Module *parseIR(const char *IR) { LLVMContext &C = getGlobalContext(); SMDiagnostic Err; return ParseAssemblyString(IR, nullptr, Err, C); } class PassManagerTest : public ::testing::Test { protected: std::unique_ptr M; public: PassManagerTest() : M(parseIR("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, BasicPreservedAnalyses) { PreservedAnalyses PA1 = PreservedAnalyses(); EXPECT_FALSE(PA1.preserved()); EXPECT_FALSE(PA1.preserved()); PreservedAnalyses PA2 = PreservedAnalyses::none(); EXPECT_FALSE(PA2.preserved()); EXPECT_FALSE(PA2.preserved()); PreservedAnalyses PA3 = PreservedAnalyses::all(); EXPECT_TRUE(PA3.preserved()); EXPECT_TRUE(PA3.preserved()); PreservedAnalyses PA4 = PA1; EXPECT_FALSE(PA4.preserved()); EXPECT_FALSE(PA4.preserved()); PA4 = PA3; EXPECT_TRUE(PA4.preserved()); EXPECT_TRUE(PA4.preserved()); PA4 = std::move(PA2); EXPECT_FALSE(PA4.preserved()); EXPECT_FALSE(PA4.preserved()); PA4.preserve(); EXPECT_TRUE(PA4.preserved()); EXPECT_FALSE(PA4.preserved()); PA1.preserve(); EXPECT_FALSE(PA1.preserved()); EXPECT_TRUE(PA1.preserved()); PA1.preserve(); EXPECT_TRUE(PA1.preserved()); EXPECT_TRUE(PA1.preserved()); PA1.intersect(PA4); EXPECT_TRUE(PA1.preserved()); EXPECT_FALSE(PA1.preserved()); } TEST_F(PassManagerTest, Basic) { FunctionAnalysisManager FAM; int FunctionAnalysisRuns = 0; FAM.registerPass(TestFunctionAnalysis(FunctionAnalysisRuns)); ModuleAnalysisManager MAM; int ModuleAnalysisRuns = 0; MAM.registerPass(TestModuleAnalysis(ModuleAnalysisRuns)); MAM.registerPass(FunctionAnalysisManagerModuleProxy(FAM)); FAM.registerPass(ModuleAnalysisManagerFunctionProxy(MAM)); ModulePassManager MPM; // Count the runs over a Function. int FunctionPassRunCount1 = 0; int AnalyzedInstrCount1 = 0; int AnalyzedFunctionCount1 = 0; { // Pointless scoped copy to test move assignment. ModulePassManager NestedMPM; FunctionPassManager FPM; { // Pointless scope to test move assignment. FunctionPassManager NestedFPM; NestedFPM.addPass(TestFunctionPass(FunctionPassRunCount1, AnalyzedInstrCount1, AnalyzedFunctionCount1)); FPM = std::move(NestedFPM); } NestedMPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); MPM = std::move(NestedMPM); } // Count the runs over a module. int ModulePassRunCount = 0; MPM.addPass(TestModulePass(ModulePassRunCount)); // Count the runs over a Function in a separate manager. int FunctionPassRunCount2 = 0; int AnalyzedInstrCount2 = 0; int AnalyzedFunctionCount2 = 0; { FunctionPassManager FPM; FPM.addPass(TestFunctionPass(FunctionPassRunCount2, AnalyzedInstrCount2, AnalyzedFunctionCount2)); MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); } // A third function pass manager but with only preserving intervening passes // and with a function pass that invalidates exactly one analysis. MPM.addPass(TestPreservingModulePass()); int FunctionPassRunCount3 = 0; int AnalyzedInstrCount3 = 0; int AnalyzedFunctionCount3 = 0; { FunctionPassManager FPM; FPM.addPass(TestFunctionPass(FunctionPassRunCount3, AnalyzedInstrCount3, AnalyzedFunctionCount3)); FPM.addPass(TestInvalidationFunctionPass("f")); MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); } // A fourth function pass manager but with a minimal intervening passes. MPM.addPass(TestMinPreservingModulePass()); int FunctionPassRunCount4 = 0; int AnalyzedInstrCount4 = 0; int AnalyzedFunctionCount4 = 0; { FunctionPassManager FPM; FPM.addPass(TestFunctionPass(FunctionPassRunCount4, AnalyzedInstrCount4, AnalyzedFunctionCount4)); MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); } // A fifth function pass manager but which uses only cached results. int FunctionPassRunCount5 = 0; int AnalyzedInstrCount5 = 0; int AnalyzedFunctionCount5 = 0; { FunctionPassManager FPM; FPM.addPass(TestInvalidationFunctionPass("f")); FPM.addPass(TestFunctionPass(FunctionPassRunCount5, AnalyzedInstrCount5, AnalyzedFunctionCount5, /*OnlyUseCachedResults=*/true)); MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); } MPM.run(M.get(), &MAM); // Validate module pass counters. EXPECT_EQ(1, ModulePassRunCount); // Validate all function pass counter sets are the same. EXPECT_EQ(3, FunctionPassRunCount1); EXPECT_EQ(5, AnalyzedInstrCount1); EXPECT_EQ(0, AnalyzedFunctionCount1); EXPECT_EQ(3, FunctionPassRunCount2); EXPECT_EQ(5, AnalyzedInstrCount2); EXPECT_EQ(0, AnalyzedFunctionCount2); EXPECT_EQ(3, FunctionPassRunCount3); EXPECT_EQ(5, AnalyzedInstrCount3); EXPECT_EQ(0, AnalyzedFunctionCount3); EXPECT_EQ(3, FunctionPassRunCount4); EXPECT_EQ(5, AnalyzedInstrCount4); EXPECT_EQ(0, AnalyzedFunctionCount4); EXPECT_EQ(3, FunctionPassRunCount5); EXPECT_EQ(2, AnalyzedInstrCount5); // Only 'g' and 'h' were cached. EXPECT_EQ(0, AnalyzedFunctionCount5); // Validate the analysis counters: // first run over 3 functions, then module pass invalidates // second run over 3 functions, nothing invalidates // third run over 0 functions, but 1 function invalidated // fourth run over 1 function EXPECT_EQ(7, FunctionAnalysisRuns); EXPECT_EQ(1, ModuleAnalysisRuns); } }