Home | History | Annotate | Download | only in IR
      1 //===- llvm/unittest/IR/PassManager.cpp - PassManager tests ---------------===//
      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/AsmParser/Parser.h"
     11 #include "llvm/IR/Function.h"
     12 #include "llvm/IR/LLVMContext.h"
     13 #include "llvm/IR/Module.h"
     14 #include "llvm/IR/PassManager.h"
     15 #include "llvm/Support/SourceMgr.h"
     16 #include "gtest/gtest.h"
     17 
     18 using namespace llvm;
     19 
     20 namespace {
     21 
     22 class TestFunctionAnalysis : public AnalysisInfoMixin<TestFunctionAnalysis> {
     23 public:
     24   struct Result {
     25     Result(int Count) : InstructionCount(Count) {}
     26     int InstructionCount;
     27   };
     28 
     29   TestFunctionAnalysis(int &Runs) : Runs(Runs) {}
     30 
     31   /// \brief Run the analysis pass over the function and return a result.
     32   Result run(Function &F, FunctionAnalysisManager &AM) {
     33     ++Runs;
     34     int Count = 0;
     35     for (Function::iterator BBI = F.begin(), BBE = F.end(); BBI != BBE; ++BBI)
     36       for (BasicBlock::iterator II = BBI->begin(), IE = BBI->end(); II != IE;
     37            ++II)
     38         ++Count;
     39     return Result(Count);
     40   }
     41 
     42 private:
     43   friend AnalysisInfoMixin<TestFunctionAnalysis>;
     44   static char PassID;
     45 
     46   int &Runs;
     47 };
     48 
     49 char TestFunctionAnalysis::PassID;
     50 
     51 class TestModuleAnalysis : public AnalysisInfoMixin<TestModuleAnalysis> {
     52 public:
     53   struct Result {
     54     Result(int Count) : FunctionCount(Count) {}
     55     int FunctionCount;
     56   };
     57 
     58   TestModuleAnalysis(int &Runs) : Runs(Runs) {}
     59 
     60   Result run(Module &M, ModuleAnalysisManager &AM) {
     61     ++Runs;
     62     int Count = 0;
     63     for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I)
     64       ++Count;
     65     return Result(Count);
     66   }
     67 
     68 private:
     69   friend AnalysisInfoMixin<TestModuleAnalysis>;
     70   static char PassID;
     71 
     72   int &Runs;
     73 };
     74 
     75 char TestModuleAnalysis::PassID;
     76 
     77 struct TestModulePass : PassInfoMixin<TestModulePass> {
     78   TestModulePass(int &RunCount) : RunCount(RunCount) {}
     79 
     80   PreservedAnalyses run(Module &M, ModuleAnalysisManager &) {
     81     ++RunCount;
     82     return PreservedAnalyses::none();
     83   }
     84 
     85   int &RunCount;
     86 };
     87 
     88 struct TestPreservingModulePass : PassInfoMixin<TestPreservingModulePass> {
     89   PreservedAnalyses run(Module &M, ModuleAnalysisManager &) {
     90     return PreservedAnalyses::all();
     91   }
     92 };
     93 
     94 struct TestMinPreservingModulePass
     95     : PassInfoMixin<TestMinPreservingModulePass> {
     96   PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM) {
     97     PreservedAnalyses PA;
     98 
     99     // Force running an analysis.
    100     (void)AM.getResult<TestModuleAnalysis>(M);
    101 
    102     PA.preserve<FunctionAnalysisManagerModuleProxy>();
    103     return PA;
    104   }
    105 };
    106 
    107 struct TestFunctionPass : PassInfoMixin<TestFunctionPass> {
    108   TestFunctionPass(int &RunCount, int &AnalyzedInstrCount,
    109                    int &AnalyzedFunctionCount,
    110                    bool OnlyUseCachedResults = false)
    111       : RunCount(RunCount), AnalyzedInstrCount(AnalyzedInstrCount),
    112         AnalyzedFunctionCount(AnalyzedFunctionCount),
    113         OnlyUseCachedResults(OnlyUseCachedResults) {}
    114 
    115   PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM) {
    116     ++RunCount;
    117 
    118     const ModuleAnalysisManager &MAM =
    119         AM.getResult<ModuleAnalysisManagerFunctionProxy>(F).getManager();
    120     if (TestModuleAnalysis::Result *TMA =
    121             MAM.getCachedResult<TestModuleAnalysis>(*F.getParent()))
    122       AnalyzedFunctionCount += TMA->FunctionCount;
    123 
    124     if (OnlyUseCachedResults) {
    125       // Hack to force the use of the cached interface.
    126       if (TestFunctionAnalysis::Result *AR =
    127               AM.getCachedResult<TestFunctionAnalysis>(F))
    128         AnalyzedInstrCount += AR->InstructionCount;
    129     } else {
    130       // Typical path just runs the analysis as needed.
    131       TestFunctionAnalysis::Result &AR = AM.getResult<TestFunctionAnalysis>(F);
    132       AnalyzedInstrCount += AR.InstructionCount;
    133     }
    134 
    135     return PreservedAnalyses::all();
    136   }
    137 
    138   int &RunCount;
    139   int &AnalyzedInstrCount;
    140   int &AnalyzedFunctionCount;
    141   bool OnlyUseCachedResults;
    142 };
    143 
    144 // A test function pass that invalidates all function analyses for a function
    145 // with a specific name.
    146 struct TestInvalidationFunctionPass
    147     : PassInfoMixin<TestInvalidationFunctionPass> {
    148   TestInvalidationFunctionPass(StringRef FunctionName) : Name(FunctionName) {}
    149 
    150   PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM) {
    151     return F.getName() == Name ? PreservedAnalyses::none()
    152                                : PreservedAnalyses::all();
    153   }
    154 
    155   StringRef Name;
    156 };
    157 
    158 std::unique_ptr<Module> parseIR(LLVMContext &Context, const char *IR) {
    159   SMDiagnostic Err;
    160   return parseAssemblyString(IR, Err, Context);
    161 }
    162 
    163 class PassManagerTest : public ::testing::Test {
    164 protected:
    165   LLVMContext Context;
    166   std::unique_ptr<Module> M;
    167 
    168 public:
    169   PassManagerTest()
    170       : M(parseIR(Context, "define void @f() {\n"
    171                            "entry:\n"
    172                            "  call void @g()\n"
    173                            "  call void @h()\n"
    174                            "  ret void\n"
    175                            "}\n"
    176                            "define void @g() {\n"
    177                            "  ret void\n"
    178                            "}\n"
    179                            "define void @h() {\n"
    180                            "  ret void\n"
    181                            "}\n")) {}
    182 };
    183 
    184 TEST_F(PassManagerTest, BasicPreservedAnalyses) {
    185   PreservedAnalyses PA1 = PreservedAnalyses();
    186   EXPECT_FALSE(PA1.preserved<TestFunctionAnalysis>());
    187   EXPECT_FALSE(PA1.preserved<TestModuleAnalysis>());
    188   PreservedAnalyses PA2 = PreservedAnalyses::none();
    189   EXPECT_FALSE(PA2.preserved<TestFunctionAnalysis>());
    190   EXPECT_FALSE(PA2.preserved<TestModuleAnalysis>());
    191   PreservedAnalyses PA3 = PreservedAnalyses::all();
    192   EXPECT_TRUE(PA3.preserved<TestFunctionAnalysis>());
    193   EXPECT_TRUE(PA3.preserved<TestModuleAnalysis>());
    194   PreservedAnalyses PA4 = PA1;
    195   EXPECT_FALSE(PA4.preserved<TestFunctionAnalysis>());
    196   EXPECT_FALSE(PA4.preserved<TestModuleAnalysis>());
    197   PA4 = PA3;
    198   EXPECT_TRUE(PA4.preserved<TestFunctionAnalysis>());
    199   EXPECT_TRUE(PA4.preserved<TestModuleAnalysis>());
    200   PA4 = std::move(PA2);
    201   EXPECT_FALSE(PA4.preserved<TestFunctionAnalysis>());
    202   EXPECT_FALSE(PA4.preserved<TestModuleAnalysis>());
    203   PA4.preserve<TestFunctionAnalysis>();
    204   EXPECT_TRUE(PA4.preserved<TestFunctionAnalysis>());
    205   EXPECT_FALSE(PA4.preserved<TestModuleAnalysis>());
    206   PA1.preserve<TestModuleAnalysis>();
    207   EXPECT_FALSE(PA1.preserved<TestFunctionAnalysis>());
    208   EXPECT_TRUE(PA1.preserved<TestModuleAnalysis>());
    209   PA1.preserve<TestFunctionAnalysis>();
    210   EXPECT_TRUE(PA1.preserved<TestFunctionAnalysis>());
    211   EXPECT_TRUE(PA1.preserved<TestModuleAnalysis>());
    212   PA1.intersect(PA4);
    213   EXPECT_TRUE(PA1.preserved<TestFunctionAnalysis>());
    214   EXPECT_FALSE(PA1.preserved<TestModuleAnalysis>());
    215 }
    216 
    217 TEST_F(PassManagerTest, Basic) {
    218   FunctionAnalysisManager FAM;
    219   int FunctionAnalysisRuns = 0;
    220   FAM.registerPass([&] { return TestFunctionAnalysis(FunctionAnalysisRuns); });
    221 
    222   ModuleAnalysisManager MAM;
    223   int ModuleAnalysisRuns = 0;
    224   MAM.registerPass([&] { return TestModuleAnalysis(ModuleAnalysisRuns); });
    225   MAM.registerPass([&] { return FunctionAnalysisManagerModuleProxy(FAM); });
    226   FAM.registerPass([&] { return ModuleAnalysisManagerFunctionProxy(MAM); });
    227 
    228   ModulePassManager MPM;
    229 
    230   // Count the runs over a Function.
    231   int FunctionPassRunCount1 = 0;
    232   int AnalyzedInstrCount1 = 0;
    233   int AnalyzedFunctionCount1 = 0;
    234   {
    235     // Pointless scoped copy to test move assignment.
    236     ModulePassManager NestedMPM;
    237     FunctionPassManager FPM;
    238     {
    239       // Pointless scope to test move assignment.
    240       FunctionPassManager NestedFPM;
    241       NestedFPM.addPass(TestFunctionPass(
    242           FunctionPassRunCount1, AnalyzedInstrCount1, AnalyzedFunctionCount1));
    243       FPM = std::move(NestedFPM);
    244     }
    245     NestedMPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
    246     MPM = std::move(NestedMPM);
    247   }
    248 
    249   // Count the runs over a module.
    250   int ModulePassRunCount = 0;
    251   MPM.addPass(TestModulePass(ModulePassRunCount));
    252 
    253   // Count the runs over a Function in a separate manager.
    254   int FunctionPassRunCount2 = 0;
    255   int AnalyzedInstrCount2 = 0;
    256   int AnalyzedFunctionCount2 = 0;
    257   {
    258     FunctionPassManager FPM;
    259     FPM.addPass(TestFunctionPass(FunctionPassRunCount2, AnalyzedInstrCount2,
    260                                  AnalyzedFunctionCount2));
    261     MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
    262   }
    263 
    264   // A third function pass manager but with only preserving intervening passes
    265   // and with a function pass that invalidates exactly one analysis.
    266   MPM.addPass(TestPreservingModulePass());
    267   int FunctionPassRunCount3 = 0;
    268   int AnalyzedInstrCount3 = 0;
    269   int AnalyzedFunctionCount3 = 0;
    270   {
    271     FunctionPassManager FPM;
    272     FPM.addPass(TestFunctionPass(FunctionPassRunCount3, AnalyzedInstrCount3,
    273                                  AnalyzedFunctionCount3));
    274     FPM.addPass(TestInvalidationFunctionPass("f"));
    275     MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
    276   }
    277 
    278   // A fourth function pass manager but with a minimal intervening passes.
    279   MPM.addPass(TestMinPreservingModulePass());
    280   int FunctionPassRunCount4 = 0;
    281   int AnalyzedInstrCount4 = 0;
    282   int AnalyzedFunctionCount4 = 0;
    283   {
    284     FunctionPassManager FPM;
    285     FPM.addPass(TestFunctionPass(FunctionPassRunCount4, AnalyzedInstrCount4,
    286                                  AnalyzedFunctionCount4));
    287     MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
    288   }
    289 
    290   // A fifth function pass manager but which uses only cached results.
    291   int FunctionPassRunCount5 = 0;
    292   int AnalyzedInstrCount5 = 0;
    293   int AnalyzedFunctionCount5 = 0;
    294   {
    295     FunctionPassManager FPM;
    296     FPM.addPass(TestInvalidationFunctionPass("f"));
    297     FPM.addPass(TestFunctionPass(FunctionPassRunCount5, AnalyzedInstrCount5,
    298                                  AnalyzedFunctionCount5,
    299                                  /*OnlyUseCachedResults=*/true));
    300     MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
    301   }
    302 
    303   MPM.run(*M, MAM);
    304 
    305   // Validate module pass counters.
    306   EXPECT_EQ(1, ModulePassRunCount);
    307 
    308   // Validate all function pass counter sets are the same.
    309   EXPECT_EQ(3, FunctionPassRunCount1);
    310   EXPECT_EQ(5, AnalyzedInstrCount1);
    311   EXPECT_EQ(0, AnalyzedFunctionCount1);
    312   EXPECT_EQ(3, FunctionPassRunCount2);
    313   EXPECT_EQ(5, AnalyzedInstrCount2);
    314   EXPECT_EQ(0, AnalyzedFunctionCount2);
    315   EXPECT_EQ(3, FunctionPassRunCount3);
    316   EXPECT_EQ(5, AnalyzedInstrCount3);
    317   EXPECT_EQ(0, AnalyzedFunctionCount3);
    318   EXPECT_EQ(3, FunctionPassRunCount4);
    319   EXPECT_EQ(5, AnalyzedInstrCount4);
    320   EXPECT_EQ(0, AnalyzedFunctionCount4);
    321   EXPECT_EQ(3, FunctionPassRunCount5);
    322   EXPECT_EQ(2, AnalyzedInstrCount5); // Only 'g' and 'h' were cached.
    323   EXPECT_EQ(0, AnalyzedFunctionCount5);
    324 
    325   // Validate the analysis counters:
    326   //   first run over 3 functions, then module pass invalidates
    327   //   second run over 3 functions, nothing invalidates
    328   //   third run over 0 functions, but 1 function invalidated
    329   //   fourth run over 1 function
    330   EXPECT_EQ(7, FunctionAnalysisRuns);
    331 
    332   EXPECT_EQ(1, ModuleAnalysisRuns);
    333 }
    334 }
    335