1 //===- CGSCCPassManagerTest.cpp -------------------------------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "llvm/Analysis/CGSCCPassManager.h" 11 #include "llvm/Analysis/LazyCallGraph.h" 12 #include "llvm/AsmParser/Parser.h" 13 #include "llvm/IR/Function.h" 14 #include "llvm/IR/InstIterator.h" 15 #include "llvm/IR/LLVMContext.h" 16 #include "llvm/IR/Module.h" 17 #include "llvm/IR/PassManager.h" 18 #include "llvm/Support/SourceMgr.h" 19 #include "gtest/gtest.h" 20 21 using namespace llvm; 22 23 namespace { 24 25 class TestModuleAnalysis { 26 public: 27 struct Result { 28 Result(int Count) : FunctionCount(Count) {} 29 int FunctionCount; 30 }; 31 32 static void *ID() { return (void *)&PassID; } 33 static StringRef name() { return "TestModuleAnalysis"; } 34 35 TestModuleAnalysis(int &Runs) : Runs(Runs) {} 36 37 Result run(Module &M, ModuleAnalysisManager &AM) { 38 ++Runs; 39 return Result(M.size()); 40 } 41 42 private: 43 static char PassID; 44 45 int &Runs; 46 }; 47 48 char TestModuleAnalysis::PassID; 49 50 class TestSCCAnalysis { 51 public: 52 struct Result { 53 Result(int Count) : FunctionCount(Count) {} 54 int FunctionCount; 55 }; 56 57 static void *ID() { return (void *)&PassID; } 58 static StringRef name() { return "TestSCCAnalysis"; } 59 60 TestSCCAnalysis(int &Runs) : Runs(Runs) {} 61 62 Result run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM) { 63 ++Runs; 64 return Result(C.size()); 65 } 66 67 private: 68 static char PassID; 69 70 int &Runs; 71 }; 72 73 char TestSCCAnalysis::PassID; 74 75 class TestFunctionAnalysis { 76 public: 77 struct Result { 78 Result(int Count) : InstructionCount(Count) {} 79 int InstructionCount; 80 }; 81 82 static void *ID() { return (void *)&PassID; } 83 static StringRef name() { return "TestFunctionAnalysis"; } 84 85 TestFunctionAnalysis(int &Runs) : Runs(Runs) {} 86 87 Result run(Function &F, FunctionAnalysisManager &AM) { 88 ++Runs; 89 int Count = 0; 90 for (Instruction &I : instructions(F)) { 91 (void)I; 92 ++Count; 93 } 94 return Result(Count); 95 } 96 97 private: 98 static char PassID; 99 100 int &Runs; 101 }; 102 103 char TestFunctionAnalysis::PassID; 104 105 class TestImmutableFunctionAnalysis { 106 public: 107 struct Result { 108 bool invalidate(Function &, const PreservedAnalyses &) { return false; } 109 }; 110 111 static void *ID() { return (void *)&PassID; } 112 static StringRef name() { return "TestImmutableFunctionAnalysis"; } 113 114 TestImmutableFunctionAnalysis(int &Runs) : Runs(Runs) {} 115 116 Result run(Function &F, FunctionAnalysisManager &AM) { 117 ++Runs; 118 return Result(); 119 } 120 121 private: 122 static char PassID; 123 124 int &Runs; 125 }; 126 127 char TestImmutableFunctionAnalysis::PassID; 128 129 struct TestModulePass { 130 TestModulePass(int &RunCount) : RunCount(RunCount) {} 131 132 PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM) { 133 ++RunCount; 134 (void)AM.getResult<TestModuleAnalysis>(M); 135 return PreservedAnalyses::all(); 136 } 137 138 static StringRef name() { return "TestModulePass"; } 139 140 int &RunCount; 141 }; 142 143 struct TestSCCPass { 144 TestSCCPass(int &RunCount, int &AnalyzedInstrCount, 145 int &AnalyzedSCCFunctionCount, int &AnalyzedModuleFunctionCount, 146 bool OnlyUseCachedResults = false) 147 : RunCount(RunCount), AnalyzedInstrCount(AnalyzedInstrCount), 148 AnalyzedSCCFunctionCount(AnalyzedSCCFunctionCount), 149 AnalyzedModuleFunctionCount(AnalyzedModuleFunctionCount), 150 OnlyUseCachedResults(OnlyUseCachedResults) {} 151 152 PreservedAnalyses run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM) { 153 ++RunCount; 154 155 const ModuleAnalysisManager &MAM = 156 AM.getResult<ModuleAnalysisManagerCGSCCProxy>(C).getManager(); 157 FunctionAnalysisManager &FAM = 158 AM.getResult<FunctionAnalysisManagerCGSCCProxy>(C).getManager(); 159 if (TestModuleAnalysis::Result *TMA = 160 MAM.getCachedResult<TestModuleAnalysis>( 161 *C.begin()->getFunction().getParent())) 162 AnalyzedModuleFunctionCount += TMA->FunctionCount; 163 164 if (OnlyUseCachedResults) { 165 // Hack to force the use of the cached interface. 166 if (TestSCCAnalysis::Result *AR = AM.getCachedResult<TestSCCAnalysis>(C)) 167 AnalyzedSCCFunctionCount += AR->FunctionCount; 168 for (LazyCallGraph::Node &N : C) 169 if (TestFunctionAnalysis::Result *FAR = 170 FAM.getCachedResult<TestFunctionAnalysis>(N.getFunction())) 171 AnalyzedInstrCount += FAR->InstructionCount; 172 } else { 173 // Typical path just runs the analysis as needed. 174 TestSCCAnalysis::Result &AR = AM.getResult<TestSCCAnalysis>(C); 175 AnalyzedSCCFunctionCount += AR.FunctionCount; 176 for (LazyCallGraph::Node &N : C) { 177 TestFunctionAnalysis::Result &FAR = 178 FAM.getResult<TestFunctionAnalysis>(N.getFunction()); 179 AnalyzedInstrCount += FAR.InstructionCount; 180 181 // Just ensure we get the immutable results. 182 (void)FAM.getResult<TestImmutableFunctionAnalysis>(N.getFunction()); 183 } 184 } 185 186 return PreservedAnalyses::all(); 187 } 188 189 static StringRef name() { return "TestSCCPass"; } 190 191 int &RunCount; 192 int &AnalyzedInstrCount; 193 int &AnalyzedSCCFunctionCount; 194 int &AnalyzedModuleFunctionCount; 195 bool OnlyUseCachedResults; 196 }; 197 198 struct TestFunctionPass { 199 TestFunctionPass(int &RunCount) : RunCount(RunCount) {} 200 201 PreservedAnalyses run(Function &F, AnalysisManager<Function> &) { 202 ++RunCount; 203 return PreservedAnalyses::none(); 204 } 205 206 static StringRef name() { return "TestFunctionPass"; } 207 208 int &RunCount; 209 }; 210 211 std::unique_ptr<Module> parseIR(const char *IR) { 212 // We just use a static context here. This is never called from multiple 213 // threads so it is harmless no matter how it is implemented. We just need 214 // the context to outlive the module which it does. 215 static LLVMContext C; 216 SMDiagnostic Err; 217 return parseAssemblyString(IR, Err, C); 218 } 219 220 TEST(CGSCCPassManagerTest, Basic) { 221 auto M = parseIR("define void @f() {\n" 222 "entry:\n" 223 " call void @g()\n" 224 " call void @h1()\n" 225 " ret void\n" 226 "}\n" 227 "define void @g() {\n" 228 "entry:\n" 229 " call void @g()\n" 230 " call void @x()\n" 231 " ret void\n" 232 "}\n" 233 "define void @h1() {\n" 234 "entry:\n" 235 " call void @h2()\n" 236 " ret void\n" 237 "}\n" 238 "define void @h2() {\n" 239 "entry:\n" 240 " call void @h3()\n" 241 " call void @x()\n" 242 " ret void\n" 243 "}\n" 244 "define void @h3() {\n" 245 "entry:\n" 246 " call void @h1()\n" 247 " ret void\n" 248 "}\n" 249 "define void @x() {\n" 250 "entry:\n" 251 " ret void\n" 252 "}\n"); 253 FunctionAnalysisManager FAM(/*DebugLogging*/ true); 254 int FunctionAnalysisRuns = 0; 255 FAM.registerPass([&] { return TestFunctionAnalysis(FunctionAnalysisRuns); }); 256 int ImmutableFunctionAnalysisRuns = 0; 257 FAM.registerPass([&] { 258 return TestImmutableFunctionAnalysis(ImmutableFunctionAnalysisRuns); 259 }); 260 261 CGSCCAnalysisManager CGAM(/*DebugLogging*/ true); 262 int SCCAnalysisRuns = 0; 263 CGAM.registerPass([&] { return TestSCCAnalysis(SCCAnalysisRuns); }); 264 265 ModuleAnalysisManager MAM(/*DebugLogging*/ true); 266 int ModuleAnalysisRuns = 0; 267 MAM.registerPass([&] { return LazyCallGraphAnalysis(); }); 268 MAM.registerPass([&] { return TestModuleAnalysis(ModuleAnalysisRuns); }); 269 270 MAM.registerPass([&] { return FunctionAnalysisManagerModuleProxy(FAM); }); 271 MAM.registerPass([&] { return CGSCCAnalysisManagerModuleProxy(CGAM); }); 272 CGAM.registerPass([&] { return FunctionAnalysisManagerCGSCCProxy(FAM); }); 273 CGAM.registerPass([&] { return ModuleAnalysisManagerCGSCCProxy(MAM); }); 274 FAM.registerPass([&] { return CGSCCAnalysisManagerFunctionProxy(CGAM); }); 275 FAM.registerPass([&] { return ModuleAnalysisManagerFunctionProxy(MAM); }); 276 277 ModulePassManager MPM(/*DebugLogging*/ true); 278 int ModulePassRunCount1 = 0; 279 MPM.addPass(TestModulePass(ModulePassRunCount1)); 280 281 CGSCCPassManager CGPM1(/*DebugLogging*/ true); 282 int SCCPassRunCount1 = 0; 283 int AnalyzedInstrCount1 = 0; 284 int AnalyzedSCCFunctionCount1 = 0; 285 int AnalyzedModuleFunctionCount1 = 0; 286 CGPM1.addPass(TestSCCPass(SCCPassRunCount1, AnalyzedInstrCount1, 287 AnalyzedSCCFunctionCount1, 288 AnalyzedModuleFunctionCount1)); 289 290 FunctionPassManager FPM1(/*DebugLogging*/ true); 291 int FunctionPassRunCount1 = 0; 292 FPM1.addPass(TestFunctionPass(FunctionPassRunCount1)); 293 CGPM1.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM1))); 294 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM1))); 295 296 MPM.run(*M, MAM); 297 298 EXPECT_EQ(1, ModulePassRunCount1); 299 300 EXPECT_EQ(1, ModuleAnalysisRuns); 301 EXPECT_EQ(4, SCCAnalysisRuns); 302 EXPECT_EQ(6, FunctionAnalysisRuns); 303 EXPECT_EQ(6, ImmutableFunctionAnalysisRuns); 304 305 EXPECT_EQ(4, SCCPassRunCount1); 306 EXPECT_EQ(14, AnalyzedInstrCount1); 307 EXPECT_EQ(6, AnalyzedSCCFunctionCount1); 308 EXPECT_EQ(4 * 6, AnalyzedModuleFunctionCount1); 309 } 310 311 } 312