Home | History | Annotate | Download | only in Analysis
      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