brintos

brintos / llvm-project-archived public Read only

0
0
Text · 40.6 KiB · a648716 Raw
1075 lines · cpp
1//===- llvm/unittest/IR/PassManager.cpp - PassManager tests ---------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "llvm/IR/PassManager.h"10#include "llvm/Analysis/AssumptionCache.h"11#include "llvm/Analysis/TargetTransformInfo.h"12#include "llvm/AsmParser/Parser.h"13#include "llvm/IR/Dominators.h"14#include "llvm/IR/Function.h"15#include "llvm/IR/LLVMContext.h"16#include "llvm/IR/Module.h"17#include "llvm/IR/PassManagerImpl.h"18#include "llvm/Passes/StandardInstrumentations.h"19#include "llvm/Support/SourceMgr.h"20#include "llvm/Transforms/Scalar/SimplifyCFG.h"21#include "gtest/gtest.h"22 23using namespace llvm;24 25namespace {26 27class TestFunctionAnalysis : public AnalysisInfoMixin<TestFunctionAnalysis> {28public:29  struct Result {30    Result(int Count) : InstructionCount(Count) {}31    int InstructionCount;32    bool invalidate(Function &, const PreservedAnalyses &PA,33                    FunctionAnalysisManager::Invalidator &) {34      // Check whether the analysis or all analyses on functions have been35      // preserved.36      auto PAC = PA.getChecker<TestFunctionAnalysis>();37      return !(PAC.preserved() || PAC.preservedSet<AllAnalysesOn<Function>>());38    }39  };40 41  TestFunctionAnalysis(int &Runs) : Runs(Runs) {}42 43  /// Run the analysis pass over the function and return a result.44  Result run(Function &F, FunctionAnalysisManager &AM) {45    ++Runs;46    int Count = 0;47    for (Function::iterator BBI = F.begin(), BBE = F.end(); BBI != BBE; ++BBI)48      for (BasicBlock::iterator II = BBI->begin(), IE = BBI->end(); II != IE;49           ++II)50        ++Count;51    return Result(Count);52  }53 54private:55  friend AnalysisInfoMixin<TestFunctionAnalysis>;56  static AnalysisKey Key;57 58  int &Runs;59};60 61AnalysisKey TestFunctionAnalysis::Key;62 63class TestModuleAnalysis : public AnalysisInfoMixin<TestModuleAnalysis> {64public:65  struct Result {66    Result(int Count) : FunctionCount(Count) {}67    int FunctionCount;68    bool invalidate(Module &, const PreservedAnalyses &PA,69                    ModuleAnalysisManager::Invalidator &) {70      // Check whether the analysis or all analyses on modules have been71      // preserved.72      auto PAC = PA.getChecker<TestModuleAnalysis>();73      return !(PAC.preserved() || PAC.preservedSet<AllAnalysesOn<Module>>());74    }75  };76 77  TestModuleAnalysis(int &Runs) : Runs(Runs) {}78 79  Result run(Module &M, ModuleAnalysisManager &AM) {80    ++Runs;81    int Count = 0;82    for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I)83      ++Count;84    return Result(Count);85  }86 87private:88  friend AnalysisInfoMixin<TestModuleAnalysis>;89  static AnalysisKey Key;90 91  int &Runs;92};93 94AnalysisKey TestModuleAnalysis::Key;95 96struct TestModulePass : PassInfoMixin<TestModulePass> {97  TestModulePass(int &RunCount) : RunCount(RunCount) {}98 99  PreservedAnalyses run(Module &M, ModuleAnalysisManager &) {100    ++RunCount;101    return PreservedAnalyses::none();102  }103 104  int &RunCount;105};106 107struct TestPreservingModulePass : PassInfoMixin<TestPreservingModulePass> {108  PreservedAnalyses run(Module &M, ModuleAnalysisManager &) {109    return PreservedAnalyses::all();110  }111};112 113struct TestFunctionPass : PassInfoMixin<TestFunctionPass> {114  TestFunctionPass(int &RunCount, int &AnalyzedInstrCount,115                   int &AnalyzedFunctionCount, ModuleAnalysisManager &MAM,116                   bool OnlyUseCachedResults = false)117      : RunCount(RunCount), AnalyzedInstrCount(AnalyzedInstrCount),118        AnalyzedFunctionCount(AnalyzedFunctionCount), MAM(MAM),119        OnlyUseCachedResults(OnlyUseCachedResults) {}120 121  PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM) {122    ++RunCount;123 124    // Getting a cached result that isn't stateless through the proxy will125    // trigger an assert:126    // auto &ModuleProxy = AM.getResult<ModuleAnalysisManagerFunctionProxy>(F);127    // Use MAM, for the purposes of this unittest.128    if (TestModuleAnalysis::Result *TMA =129            MAM.getCachedResult<TestModuleAnalysis>(*F.getParent())) {130      AnalyzedFunctionCount += TMA->FunctionCount;131    }132 133    if (OnlyUseCachedResults) {134      // Hack to force the use of the cached interface.135      if (TestFunctionAnalysis::Result *AR =136              AM.getCachedResult<TestFunctionAnalysis>(F))137        AnalyzedInstrCount += AR->InstructionCount;138    } else {139      // Typical path just runs the analysis as needed.140      TestFunctionAnalysis::Result &AR = AM.getResult<TestFunctionAnalysis>(F);141      AnalyzedInstrCount += AR.InstructionCount;142    }143 144    return PreservedAnalyses::all();145  }146 147  int &RunCount;148  int &AnalyzedInstrCount;149  int &AnalyzedFunctionCount;150  ModuleAnalysisManager &MAM;151  bool OnlyUseCachedResults;152};153 154// A test function pass that invalidates all function analyses for a function155// with a specific name.156struct TestInvalidationFunctionPass157    : PassInfoMixin<TestInvalidationFunctionPass> {158  TestInvalidationFunctionPass(StringRef FunctionName) : Name(FunctionName) {}159 160  PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM) {161    return F.getName() == Name ? PreservedAnalyses::none()162                               : PreservedAnalyses::all();163  }164 165  StringRef Name;166};167 168std::unique_ptr<Module> parseIR(LLVMContext &Context, const char *IR) {169  SMDiagnostic Err;170  return parseAssemblyString(IR, Err, Context);171}172 173class PassManagerTest : public ::testing::Test {174protected:175  LLVMContext Context;176  std::unique_ptr<Module> M;177 178public:179  PassManagerTest()180      : M(parseIR(Context, "define void @f() {\n"181                           "entry:\n"182                           "  call void @g()\n"183                           "  call void @h()\n"184                           "  ret void\n"185                           "}\n"186                           "define void @g() {\n"187                           "  ret void\n"188                           "}\n"189                           "define void @h() {\n"190                           "  ret void\n"191                           "}\n")) {}192};193 194TEST(PreservedAnalysesTest, Basic) {195  PreservedAnalyses PA1 = PreservedAnalyses();196  {197    auto PAC = PA1.getChecker<TestFunctionAnalysis>();198    EXPECT_FALSE(PAC.preserved());199    EXPECT_FALSE(PAC.preservedSet<AllAnalysesOn<Function>>());200  }201  {202    auto PAC = PA1.getChecker<TestModuleAnalysis>();203    EXPECT_FALSE(PAC.preserved());204    EXPECT_FALSE(PAC.preservedSet<AllAnalysesOn<Module>>());205  }206  auto PA2 = PreservedAnalyses::none();207  {208    auto PAC = PA2.getChecker<TestFunctionAnalysis>();209    EXPECT_FALSE(PAC.preserved());210    EXPECT_FALSE(PAC.preservedSet<AllAnalysesOn<Function>>());211  }212  auto PA3 = PreservedAnalyses::all();213  {214    auto PAC = PA3.getChecker<TestFunctionAnalysis>();215    EXPECT_TRUE(PAC.preserved());216    EXPECT_TRUE(PAC.preservedSet<AllAnalysesOn<Function>>());217  }218  PreservedAnalyses PA4 = PA1;219  {220    auto PAC = PA4.getChecker<TestFunctionAnalysis>();221    EXPECT_FALSE(PAC.preserved());222    EXPECT_FALSE(PAC.preservedSet<AllAnalysesOn<Function>>());223  }224  PA4 = PA3;225  {226    auto PAC = PA4.getChecker<TestFunctionAnalysis>();227    EXPECT_TRUE(PAC.preserved());228    EXPECT_TRUE(PAC.preservedSet<AllAnalysesOn<Function>>());229  }230  PA4 = std::move(PA2);231  {232    auto PAC = PA4.getChecker<TestFunctionAnalysis>();233    EXPECT_FALSE(PAC.preserved());234    EXPECT_FALSE(PAC.preservedSet<AllAnalysesOn<Function>>());235  }236  auto PA5 = PreservedAnalyses::allInSet<AllAnalysesOn<Function>>();237  {238    auto PAC = PA5.getChecker<TestFunctionAnalysis>();239    EXPECT_FALSE(PAC.preserved());240    EXPECT_TRUE(PAC.preservedSet<AllAnalysesOn<Function>>());241    EXPECT_FALSE(PAC.preservedSet<AllAnalysesOn<Module>>());242  }243}244 245TEST(PreservedAnalysesTest, Preserve) {246  auto PA = PreservedAnalyses::none();247  PA.preserve<TestFunctionAnalysis>();248  EXPECT_TRUE(PA.getChecker<TestFunctionAnalysis>().preserved());249  EXPECT_FALSE(PA.getChecker<TestModuleAnalysis>().preserved());250  PA.preserve<TestModuleAnalysis>();251  EXPECT_TRUE(PA.getChecker<TestFunctionAnalysis>().preserved());252  EXPECT_TRUE(PA.getChecker<TestModuleAnalysis>().preserved());253 254  // Redundant calls are fine.255  PA.preserve<TestFunctionAnalysis>();256  EXPECT_TRUE(PA.getChecker<TestFunctionAnalysis>().preserved());257  EXPECT_TRUE(PA.getChecker<TestModuleAnalysis>().preserved());258}259 260TEST(PreservedAnalysesTest, PreserveSets) {261  auto PA = PreservedAnalyses::none();262  PA.preserveSet<AllAnalysesOn<Function>>();263  EXPECT_TRUE(PA.getChecker<TestFunctionAnalysis>()264                  .preservedSet<AllAnalysesOn<Function>>());265  EXPECT_FALSE(PA.getChecker<TestModuleAnalysis>()266                   .preservedSet<AllAnalysesOn<Module>>());267  PA.preserveSet<AllAnalysesOn<Module>>();268  EXPECT_TRUE(PA.getChecker<TestFunctionAnalysis>()269                  .preservedSet<AllAnalysesOn<Function>>());270  EXPECT_TRUE(PA.getChecker<TestModuleAnalysis>()271                  .preservedSet<AllAnalysesOn<Module>>());272 273  // Mixing is fine.274  PA.preserve<TestFunctionAnalysis>();275  EXPECT_TRUE(PA.getChecker<TestFunctionAnalysis>()276                  .preservedSet<AllAnalysesOn<Function>>());277  EXPECT_TRUE(PA.getChecker<TestModuleAnalysis>()278                  .preservedSet<AllAnalysesOn<Module>>());279 280  // Redundant calls are fine.281  PA.preserveSet<AllAnalysesOn<Module>>();282  EXPECT_TRUE(PA.getChecker<TestFunctionAnalysis>()283                  .preservedSet<AllAnalysesOn<Function>>());284  EXPECT_TRUE(PA.getChecker<TestModuleAnalysis>()285                  .preservedSet<AllAnalysesOn<Module>>());286}287 288TEST(PreservedAnalysisTest, Intersect) {289  // Setup the initial sets.290  auto PA1 = PreservedAnalyses::none();291  PA1.preserve<TestFunctionAnalysis>();292  PA1.preserveSet<AllAnalysesOn<Module>>();293  auto PA2 = PreservedAnalyses::none();294  PA2.preserve<TestFunctionAnalysis>();295  PA2.preserveSet<AllAnalysesOn<Function>>();296  PA2.preserve<TestModuleAnalysis>();297  PA2.preserveSet<AllAnalysesOn<Module>>();298  auto PA3 = PreservedAnalyses::none();299  PA3.preserve<TestModuleAnalysis>();300  PA3.preserveSet<AllAnalysesOn<Function>>();301 302  // Self intersection is a no-op.303  auto Intersected = PA1;304  Intersected.intersect(PA1);305  EXPECT_TRUE(Intersected.getChecker<TestFunctionAnalysis>().preserved());306  EXPECT_FALSE(Intersected.getChecker<TestFunctionAnalysis>()307                   .preservedSet<AllAnalysesOn<Function>>());308  EXPECT_FALSE(Intersected.getChecker<TestModuleAnalysis>().preserved());309  EXPECT_TRUE(Intersected.getChecker<TestModuleAnalysis>()310                  .preservedSet<AllAnalysesOn<Module>>());311 312  // Intersecting with all is a no-op.313  Intersected.intersect(PreservedAnalyses::all());314  EXPECT_TRUE(Intersected.getChecker<TestFunctionAnalysis>().preserved());315  EXPECT_FALSE(Intersected.getChecker<TestFunctionAnalysis>()316                   .preservedSet<AllAnalysesOn<Function>>());317  EXPECT_FALSE(Intersected.getChecker<TestModuleAnalysis>().preserved());318  EXPECT_TRUE(Intersected.getChecker<TestModuleAnalysis>()319                  .preservedSet<AllAnalysesOn<Module>>());320 321  // Intersecting a narrow set with a more broad set is the narrow set.322  Intersected.intersect(PA2);323  EXPECT_TRUE(Intersected.getChecker<TestFunctionAnalysis>().preserved());324  EXPECT_FALSE(Intersected.getChecker<TestFunctionAnalysis>()325                   .preservedSet<AllAnalysesOn<Function>>());326  EXPECT_FALSE(Intersected.getChecker<TestModuleAnalysis>().preserved());327  EXPECT_TRUE(Intersected.getChecker<TestModuleAnalysis>()328                  .preservedSet<AllAnalysesOn<Module>>());329 330  // Intersecting a broad set with a more narrow set is the narrow set.331  Intersected = PA2;332  Intersected.intersect(PA1);333  EXPECT_TRUE(Intersected.getChecker<TestFunctionAnalysis>().preserved());334  EXPECT_FALSE(Intersected.getChecker<TestFunctionAnalysis>()335                   .preservedSet<AllAnalysesOn<Function>>());336  EXPECT_FALSE(Intersected.getChecker<TestModuleAnalysis>().preserved());337  EXPECT_TRUE(Intersected.getChecker<TestModuleAnalysis>()338                  .preservedSet<AllAnalysesOn<Module>>());339 340  // Intersecting with empty clears.341  Intersected.intersect(PreservedAnalyses::none());342  EXPECT_FALSE(Intersected.getChecker<TestFunctionAnalysis>().preserved());343  EXPECT_FALSE(Intersected.getChecker<TestFunctionAnalysis>()344                   .preservedSet<AllAnalysesOn<Function>>());345  EXPECT_FALSE(Intersected.getChecker<TestModuleAnalysis>().preserved());346  EXPECT_FALSE(Intersected.getChecker<TestModuleAnalysis>()347                   .preservedSet<AllAnalysesOn<Module>>());348 349  // Intersecting non-overlapping clears.350  Intersected = PA1;351  Intersected.intersect(PA3);352  EXPECT_FALSE(Intersected.getChecker<TestFunctionAnalysis>().preserved());353  EXPECT_FALSE(Intersected.getChecker<TestFunctionAnalysis>()354                   .preservedSet<AllAnalysesOn<Function>>());355  EXPECT_FALSE(Intersected.getChecker<TestModuleAnalysis>().preserved());356  EXPECT_FALSE(Intersected.getChecker<TestModuleAnalysis>()357                   .preservedSet<AllAnalysesOn<Module>>());358 359  // Intersecting with moves works in when there is storage on both sides.360  Intersected = PA1;361  auto Tmp = PA2;362  Intersected.intersect(std::move(Tmp));363  EXPECT_TRUE(Intersected.getChecker<TestFunctionAnalysis>().preserved());364  EXPECT_FALSE(Intersected.getChecker<TestFunctionAnalysis>()365                   .preservedSet<AllAnalysesOn<Function>>());366  EXPECT_FALSE(Intersected.getChecker<TestModuleAnalysis>().preserved());367  EXPECT_TRUE(Intersected.getChecker<TestModuleAnalysis>()368                  .preservedSet<AllAnalysesOn<Module>>());369 370  // Intersecting with move works for incoming all and existing all.371  auto Tmp2 = PreservedAnalyses::all();372  Intersected.intersect(std::move(Tmp2));373  EXPECT_TRUE(Intersected.getChecker<TestFunctionAnalysis>().preserved());374  EXPECT_FALSE(Intersected.getChecker<TestFunctionAnalysis>()375                   .preservedSet<AllAnalysesOn<Function>>());376  EXPECT_FALSE(Intersected.getChecker<TestModuleAnalysis>().preserved());377  EXPECT_TRUE(Intersected.getChecker<TestModuleAnalysis>()378                  .preservedSet<AllAnalysesOn<Module>>());379  Intersected = PreservedAnalyses::all();380  auto Tmp3 = PA1;381  Intersected.intersect(std::move(Tmp3));382  EXPECT_TRUE(Intersected.getChecker<TestFunctionAnalysis>().preserved());383  EXPECT_FALSE(Intersected.getChecker<TestFunctionAnalysis>()384                   .preservedSet<AllAnalysesOn<Function>>());385  EXPECT_FALSE(Intersected.getChecker<TestModuleAnalysis>().preserved());386  EXPECT_TRUE(Intersected.getChecker<TestModuleAnalysis>()387                  .preservedSet<AllAnalysesOn<Module>>());388}389 390TEST(PreservedAnalysisTest, Abandon) {391  auto PA = PreservedAnalyses::none();392 393  // We can abandon things after they are preserved.394  PA.preserve<TestFunctionAnalysis>();395  PA.abandon<TestFunctionAnalysis>();396  EXPECT_FALSE(PA.getChecker<TestFunctionAnalysis>().preserved());397 398  // Repeated is fine, and abandoning if they were never preserved is fine.399  PA.abandon<TestFunctionAnalysis>();400  EXPECT_FALSE(PA.getChecker<TestFunctionAnalysis>().preserved());401  PA.abandon<TestModuleAnalysis>();402  EXPECT_FALSE(PA.getChecker<TestModuleAnalysis>().preserved());403 404  // Even if the sets are preserved, the abandoned analyses' checker won't405  // return true for those sets.406  PA.preserveSet<AllAnalysesOn<Function>>();407  PA.preserveSet<AllAnalysesOn<Module>>();408  EXPECT_FALSE(PA.getChecker<TestFunctionAnalysis>()409                   .preservedSet<AllAnalysesOn<Function>>());410  EXPECT_FALSE(PA.getChecker<TestModuleAnalysis>()411                   .preservedSet<AllAnalysesOn<Module>>());412 413  // But an arbitrary (opaque) analysis will still observe the sets as414  // preserved. This also checks that we can use an explicit ID rather than415  // a type.416  AnalysisKey FakeKey, *FakeID = &FakeKey;417  EXPECT_TRUE(PA.getChecker(FakeID).preservedSet<AllAnalysesOn<Function>>());418  EXPECT_TRUE(PA.getChecker(FakeID).preservedSet<AllAnalysesOn<Module>>());419}420 421TEST_F(PassManagerTest, Basic) {422  FunctionAnalysisManager FAM;423  int FunctionAnalysisRuns = 0;424  FAM.registerPass([&] { return TestFunctionAnalysis(FunctionAnalysisRuns); });425 426  ModuleAnalysisManager MAM;427  int ModuleAnalysisRuns = 0;428  MAM.registerPass([&] { return TestModuleAnalysis(ModuleAnalysisRuns); });429  MAM.registerPass([&] { return FunctionAnalysisManagerModuleProxy(FAM); });430  FAM.registerPass([&] { return ModuleAnalysisManagerFunctionProxy(MAM); });431 432  MAM.registerPass([&] { return PassInstrumentationAnalysis(); });433  FAM.registerPass([&] { return PassInstrumentationAnalysis(); });434 435  ModulePassManager MPM;436 437  // Count the runs over a Function.438  int FunctionPassRunCount1 = 0;439  int AnalyzedInstrCount1 = 0;440  int AnalyzedFunctionCount1 = 0;441  {442    // Pointless scoped copy to test move assignment.443    ModulePassManager NestedMPM;444    FunctionPassManager FPM;445    {446      // Pointless scope to test move assignment.447      FunctionPassManager NestedFPM;448      NestedFPM.addPass(TestFunctionPass(FunctionPassRunCount1,449                                         AnalyzedInstrCount1,450                                         AnalyzedFunctionCount1, MAM));451      FPM = std::move(NestedFPM);452    }453    NestedMPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));454    MPM = std::move(NestedMPM);455  }456 457  // Count the runs over a module.458  int ModulePassRunCount = 0;459  MPM.addPass(TestModulePass(ModulePassRunCount));460 461  // Count the runs over a Function in a separate manager.462  int FunctionPassRunCount2 = 0;463  int AnalyzedInstrCount2 = 0;464  int AnalyzedFunctionCount2 = 0;465  {466    FunctionPassManager FPM;467    FPM.addPass(TestFunctionPass(FunctionPassRunCount2, AnalyzedInstrCount2,468                                 AnalyzedFunctionCount2, MAM));469    MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));470  }471 472  // A third function pass manager but with only preserving intervening passes473  // and with a function pass that invalidates exactly one analysis.474  MPM.addPass(TestPreservingModulePass());475  int FunctionPassRunCount3 = 0;476  int AnalyzedInstrCount3 = 0;477  int AnalyzedFunctionCount3 = 0;478  {479    FunctionPassManager FPM;480    FPM.addPass(TestFunctionPass(FunctionPassRunCount3, AnalyzedInstrCount3,481                                 AnalyzedFunctionCount3, MAM));482    FPM.addPass(TestInvalidationFunctionPass("f"));483    MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));484  }485 486  // A fourth function pass manager but with only preserving intervening487  // passes but triggering the module analysis.488  MPM.addPass(RequireAnalysisPass<TestModuleAnalysis, Module>());489  int FunctionPassRunCount4 = 0;490  int AnalyzedInstrCount4 = 0;491  int AnalyzedFunctionCount4 = 0;492  {493    FunctionPassManager FPM;494    FPM.addPass(TestFunctionPass(FunctionPassRunCount4, AnalyzedInstrCount4,495                                 AnalyzedFunctionCount4, MAM));496    MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));497  }498 499  // A fifth function pass manager which invalidates one function first but500  // uses only cached results.501  int FunctionPassRunCount5 = 0;502  int AnalyzedInstrCount5 = 0;503  int AnalyzedFunctionCount5 = 0;504  {505    FunctionPassManager FPM;506    FPM.addPass(TestInvalidationFunctionPass("f"));507    FPM.addPass(TestFunctionPass(FunctionPassRunCount5, AnalyzedInstrCount5,508                                 AnalyzedFunctionCount5, MAM,509                                 /*OnlyUseCachedResults=*/true));510    MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));511  }512 513  MPM.run(*M, MAM);514 515  // Validate module pass counters.516  EXPECT_EQ(1, ModulePassRunCount);517 518  // Validate all function pass counter sets are the same.519  EXPECT_EQ(3, FunctionPassRunCount1);520  EXPECT_EQ(5, AnalyzedInstrCount1);521  EXPECT_EQ(0, AnalyzedFunctionCount1);522  EXPECT_EQ(3, FunctionPassRunCount2);523  EXPECT_EQ(5, AnalyzedInstrCount2);524  EXPECT_EQ(0, AnalyzedFunctionCount2);525  EXPECT_EQ(3, FunctionPassRunCount3);526  EXPECT_EQ(5, AnalyzedInstrCount3);527  EXPECT_EQ(0, AnalyzedFunctionCount3);528  EXPECT_EQ(3, FunctionPassRunCount4);529  EXPECT_EQ(5, AnalyzedInstrCount4);530  EXPECT_EQ(9, AnalyzedFunctionCount4);531  EXPECT_EQ(3, FunctionPassRunCount5);532  EXPECT_EQ(2, AnalyzedInstrCount5); // Only 'g' and 'h' were cached.533  EXPECT_EQ(9, AnalyzedFunctionCount5);534 535  // Validate the analysis counters:536  //   first run over 3 functions, then module pass invalidates537  //   second run over 3 functions, nothing invalidates538  //   third run over 0 functions, but 1 function invalidated539  //   fourth run over 1 function540  //   fifth run invalidates 1 function first, but runs over 0 functions541  EXPECT_EQ(7, FunctionAnalysisRuns);542 543  EXPECT_EQ(1, ModuleAnalysisRuns);544}545 546// A customized pass manager that passes extra arguments through the547// infrastructure.548typedef AnalysisManager<Function, int> CustomizedAnalysisManager;549typedef PassManager<Function, CustomizedAnalysisManager, int, int &>550    CustomizedPassManager;551 552class CustomizedAnalysis : public AnalysisInfoMixin<CustomizedAnalysis> {553public:554  struct Result {555    Result(int I) : I(I) {}556    int I;557  };558 559  Result run(Function &F, CustomizedAnalysisManager &AM, int I) {560    return Result(I);561  }562 563private:564  friend AnalysisInfoMixin<CustomizedAnalysis>;565  static AnalysisKey Key;566};567 568AnalysisKey CustomizedAnalysis::Key;569 570struct CustomizedPass : PassInfoMixin<CustomizedPass> {571  std::function<void(CustomizedAnalysis::Result &, int &)> Callback;572 573  template <typename CallbackT>574  CustomizedPass(CallbackT Callback) : Callback(Callback) {}575 576  PreservedAnalyses run(Function &F, CustomizedAnalysisManager &AM, int I,577                        int &O) {578    Callback(AM.getResult<CustomizedAnalysis>(F, I), O);579    return PreservedAnalyses::none();580  }581};582 583TEST_F(PassManagerTest, CustomizedPassManagerArgs) {584  CustomizedAnalysisManager AM;585  AM.registerPass([&] { return CustomizedAnalysis(); });586  PassInstrumentationCallbacks PIC;587  AM.registerPass([&] { return PassInstrumentationAnalysis(&PIC); });588 589  CustomizedPassManager PM;590 591  // Add an instance of the customized pass that just accumulates the input592  // after it is round-tripped through the analysis.593  int Result = 0;594  PM.addPass(595      CustomizedPass([](CustomizedAnalysis::Result &R, int &O) { O += R.I; }));596 597  // Run this over every function with the input of 42.598  for (Function &F : *M)599    PM.run(F, AM, 42, Result);600 601  // And ensure that we accumulated the correct result.602  EXPECT_EQ(42 * (int)M->size(), Result);603}604 605/// A test analysis pass which caches in its result another analysis pass and606/// uses it to serve queries. This requires the result to invalidate itself607/// when its dependency is invalidated.608struct TestIndirectFunctionAnalysis609    : public AnalysisInfoMixin<TestIndirectFunctionAnalysis> {610  struct Result {611    Result(TestFunctionAnalysis::Result &FDep, TestModuleAnalysis::Result &MDep)612        : FDep(FDep), MDep(MDep) {}613    TestFunctionAnalysis::Result &FDep;614    TestModuleAnalysis::Result &MDep;615 616    bool invalidate(Function &F, const PreservedAnalyses &PA,617                    FunctionAnalysisManager::Invalidator &Inv) {618      auto PAC = PA.getChecker<TestIndirectFunctionAnalysis>();619      return !(PAC.preserved() ||620               PAC.preservedSet<AllAnalysesOn<Function>>()) ||621             Inv.invalidate<TestFunctionAnalysis>(F, PA);622    }623  };624 625  TestIndirectFunctionAnalysis(int &Runs, ModuleAnalysisManager &MAM)626      : Runs(Runs), MAM(MAM) {}627 628  /// Run the analysis pass over the function and return a result.629  Result run(Function &F, FunctionAnalysisManager &AM) {630    ++Runs;631    auto &FDep = AM.getResult<TestFunctionAnalysis>(F);632    auto &MAMProxy = AM.getResult<ModuleAnalysisManagerFunctionProxy>(F);633    // For the test, we insist that the module analysis starts off in the634    // cache. Getting a cached result that isn't stateless trigger an assert.635    // Use MAM, for the purposes of this unittest.636    auto &MDep = *MAM.getCachedResult<TestModuleAnalysis>(*F.getParent());637    // And register the dependency as module analysis dependencies have to be638    // pre-registered on the proxy.639    MAMProxy.registerOuterAnalysisInvalidation<TestModuleAnalysis,640                                               TestIndirectFunctionAnalysis>();641    return Result(FDep, MDep);642  }643 644private:645  friend AnalysisInfoMixin<TestIndirectFunctionAnalysis>;646  static AnalysisKey Key;647 648  int &Runs;649  ModuleAnalysisManager &MAM;650};651 652AnalysisKey TestIndirectFunctionAnalysis::Key;653 654/// A test analysis pass which chaches in its result the result from the above655/// indirect analysis pass.656///657/// This allows us to ensure that whenever an analysis pass is invalidated due658/// to dependencies (especially dependencies across IR units that trigger659/// asynchronous invalidation) we correctly detect that this may in turn cause660/// other analysis to be invalidated.661struct TestDoublyIndirectFunctionAnalysis662    : public AnalysisInfoMixin<TestDoublyIndirectFunctionAnalysis> {663  struct Result {664    Result(TestIndirectFunctionAnalysis::Result &IDep) : IDep(IDep) {}665    TestIndirectFunctionAnalysis::Result &IDep;666 667    bool invalidate(Function &F, const PreservedAnalyses &PA,668                    FunctionAnalysisManager::Invalidator &Inv) {669      auto PAC = PA.getChecker<TestDoublyIndirectFunctionAnalysis>();670      return !(PAC.preserved() ||671               PAC.preservedSet<AllAnalysesOn<Function>>()) ||672             Inv.invalidate<TestIndirectFunctionAnalysis>(F, PA);673    }674  };675 676  TestDoublyIndirectFunctionAnalysis(int &Runs) : Runs(Runs) {}677 678  /// Run the analysis pass over the function and return a result.679  Result run(Function &F, FunctionAnalysisManager &AM) {680    ++Runs;681    auto &IDep = AM.getResult<TestIndirectFunctionAnalysis>(F);682    return Result(IDep);683  }684 685private:686  friend AnalysisInfoMixin<TestDoublyIndirectFunctionAnalysis>;687  static AnalysisKey Key;688 689  int &Runs;690};691 692AnalysisKey TestDoublyIndirectFunctionAnalysis::Key;693 694struct LambdaPass : public PassInfoMixin<LambdaPass> {695  using FuncT = std::function<PreservedAnalyses(Function &, FunctionAnalysisManager &)>;696 697  LambdaPass(FuncT Func) : Func(std::move(Func)) {}698 699  PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM) {700    return Func(F, AM);701  }702 703  FuncT Func;704};705 706TEST_F(PassManagerTest, IndirectAnalysisInvalidation) {707  FunctionAnalysisManager FAM;708  ModuleAnalysisManager MAM;709  int FunctionAnalysisRuns = 0, ModuleAnalysisRuns = 0,710      IndirectAnalysisRuns = 0, DoublyIndirectAnalysisRuns = 0;711  FAM.registerPass([&] { return TestFunctionAnalysis(FunctionAnalysisRuns); });712  FAM.registerPass(713      [&] { return TestIndirectFunctionAnalysis(IndirectAnalysisRuns, MAM); });714  FAM.registerPass([&] {715    return TestDoublyIndirectFunctionAnalysis(DoublyIndirectAnalysisRuns);716  });717 718  MAM.registerPass([&] { return TestModuleAnalysis(ModuleAnalysisRuns); });719  MAM.registerPass([&] { return FunctionAnalysisManagerModuleProxy(FAM); });720  FAM.registerPass([&] { return ModuleAnalysisManagerFunctionProxy(MAM); });721 722  PassInstrumentationCallbacks PIC;723  MAM.registerPass([&] { return PassInstrumentationAnalysis(&PIC); });724  FAM.registerPass([&] { return PassInstrumentationAnalysis(&PIC); });725 726  int InstrCount = 0, FunctionCount = 0;727  ModulePassManager MPM;728  FunctionPassManager FPM;729  // First just use the analysis to get the instruction count, and preserve730  // everything.731  FPM.addPass(LambdaPass([&](Function &F, FunctionAnalysisManager &AM) {732    auto &DoublyIndirectResult =733        AM.getResult<TestDoublyIndirectFunctionAnalysis>(F);734    auto &IndirectResult = DoublyIndirectResult.IDep;735    InstrCount += IndirectResult.FDep.InstructionCount;736    FunctionCount += IndirectResult.MDep.FunctionCount;737    return PreservedAnalyses::all();738  }));739  // Next, invalidate740  //   - both analyses for "f",741  //   - just the underlying (indirect) analysis for "g", and742  //   - just the direct analysis for "h".743  FPM.addPass(LambdaPass([&](Function &F, FunctionAnalysisManager &AM) {744    auto &DoublyIndirectResult =745        AM.getResult<TestDoublyIndirectFunctionAnalysis>(F);746    auto &IndirectResult = DoublyIndirectResult.IDep;747    InstrCount += IndirectResult.FDep.InstructionCount;748    FunctionCount += IndirectResult.MDep.FunctionCount;749    auto PA = PreservedAnalyses::none();750    if (F.getName() == "g")751      PA.preserve<TestFunctionAnalysis>();752    else if (F.getName() == "h")753      PA.preserve<TestIndirectFunctionAnalysis>();754    return PA;755  }));756  // Finally, use the analysis again on each function, forcing re-computation757  // for all of them.758  FPM.addPass(LambdaPass([&](Function &F, FunctionAnalysisManager &AM) {759    auto &DoublyIndirectResult =760        AM.getResult<TestDoublyIndirectFunctionAnalysis>(F);761    auto &IndirectResult = DoublyIndirectResult.IDep;762    InstrCount += IndirectResult.FDep.InstructionCount;763    FunctionCount += IndirectResult.MDep.FunctionCount;764    return PreservedAnalyses::all();765  }));766 767  // Create a second function pass manager. This will cause the module-level768  // invalidation to occur, which will force yet another invalidation of the769  // indirect function-level analysis as the module analysis it depends on gets770  // invalidated.771  FunctionPassManager FPM2;772  FPM2.addPass(LambdaPass([&](Function &F, FunctionAnalysisManager &AM) {773    auto &DoublyIndirectResult =774        AM.getResult<TestDoublyIndirectFunctionAnalysis>(F);775    auto &IndirectResult = DoublyIndirectResult.IDep;776    InstrCount += IndirectResult.FDep.InstructionCount;777    FunctionCount += IndirectResult.MDep.FunctionCount;778    return PreservedAnalyses::all();779  }));780 781  // Add a requires pass to populate the module analysis and then our function782  // pass pipeline.783  MPM.addPass(RequireAnalysisPass<TestModuleAnalysis, Module>());784  MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));785  // Now require the module analysis again (it will have been invalidated once)786  // and then use it again from a function pass manager.787  MPM.addPass(RequireAnalysisPass<TestModuleAnalysis, Module>());788  MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM2)));789  MPM.run(*M, MAM);790 791  // There are generally two possible runs for each of the three functions. But792  // for one function, we only invalidate the indirect analysis so the base one793  // only gets run five times.794  EXPECT_EQ(5, FunctionAnalysisRuns);795  // The module analysis pass should be run twice here.796  EXPECT_EQ(2, ModuleAnalysisRuns);797  // The indirect analysis is invalidated for each function (either directly or798  // indirectly) and run twice for each.799  EXPECT_EQ(9, IndirectAnalysisRuns);800  EXPECT_EQ(9, DoublyIndirectAnalysisRuns);801 802  // There are five instructions in the module and we add the count four803  // times.804  EXPECT_EQ(5 * 4, InstrCount);805 806  // There are three functions and we count them four times for each of the807  // three functions.808  EXPECT_EQ(3 * 4 * 3, FunctionCount);809}810 811// Run SimplifyCFGPass that makes CFG changes and reports PreservedAnalyses812// without CFGAnalyses. So the CFGChecker does not complain.813TEST_F(PassManagerTest, FunctionPassCFGChecker) {814  LLVMContext Context;815  // SimplifyCFG changes this function to816  // define void @foo {next: ret void}817  auto M = parseIR(Context, "define void @foo() {\n"818                            "  br label %next\n"819                            "next:\n"820                            "  br label %exit\n"821                            "exit:\n"822                            "  ret void\n"823                            "}\n");824 825  auto *F = M->getFunction("foo");826  FunctionAnalysisManager FAM;827  ModuleAnalysisManager MAM;828  FunctionPassManager FPM;829  PassInstrumentationCallbacks PIC;830  StandardInstrumentations SI(M->getContext(), /*DebugLogging*/ true);831  SI.registerCallbacks(PIC, &MAM);832  MAM.registerPass([&] { return PassInstrumentationAnalysis(&PIC); });833  MAM.registerPass([&] { return FunctionAnalysisManagerModuleProxy(FAM); });834  FAM.registerPass([&] { return PassInstrumentationAnalysis(&PIC); });835  FAM.registerPass([&] { return DominatorTreeAnalysis(); });836  FAM.registerPass([&] { return AssumptionAnalysis(); });837  FAM.registerPass([&] { return TargetIRAnalysis(); });838 839  FPM.addPass(SimplifyCFGPass());840  FPM.run(*F, FAM);841}842 843// FunctionPass that manually invalidates analyses and always returns844// PreservedAnalyses::all().845struct TestSimplifyCFGInvalidatingAnalysisPass846    : PassInfoMixin<TestSimplifyCFGInvalidatingAnalysisPass> {847  PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM) {848    // Run SimplifyCFG and if it changes CFG then invalidate the CFG analysis.849    // This allows to return PreserveAnalysis::all().850    PreservedAnalyses PA = CFGSimplifier.run(F, FAM);851    FAM.invalidate(F, PA);852    return PreservedAnalyses::all();853  }854 855  SimplifyCFGPass CFGSimplifier;856};857 858// Run TestSimplifyCFGInvalidatingAnalysisPass which changes CFG by running859// SimplifyCFGPass then manually invalidates analyses and always returns860// PreservedAnalyses::all(). CFGChecker does not complain because it resets861// its saved CFG snapshot when the analyses are invalidated manually.862TEST_F(PassManagerTest, FunctionPassCFGCheckerInvalidateAnalysis) {863  LLVMContext Context;864  // SimplifyCFG changes this function to865  // define void @foo {next: ret void}866  auto M = parseIR(Context, "define void @foo() {\n"867                            "  br label %next\n"868                            "next:\n"869                            "  br label %exit\n"870                            "exit:\n"871                            "  ret void\n"872                            "}\n");873 874  auto *F = M->getFunction("foo");875  FunctionAnalysisManager FAM;876  ModuleAnalysisManager MAM;877  FunctionPassManager FPM;878  PassInstrumentationCallbacks PIC;879  StandardInstrumentations SI(M->getContext(), /*DebugLogging*/ true);880  SI.registerCallbacks(PIC, &MAM);881  MAM.registerPass([&] { return FunctionAnalysisManagerModuleProxy(FAM); });882  MAM.registerPass([&] { return PassInstrumentationAnalysis(&PIC); });883  FAM.registerPass([&] { return PassInstrumentationAnalysis(&PIC); });884  FAM.registerPass([&] { return DominatorTreeAnalysis(); });885  FAM.registerPass([&] { return AssumptionAnalysis(); });886  FAM.registerPass([&] { return TargetIRAnalysis(); });887 888  FPM.addPass(TestSimplifyCFGInvalidatingAnalysisPass());889  FPM.run(*F, FAM);890}891 892// Wrap a FunctionPassManager running SimplifyCFG pass with another893// FunctionPassManager.894struct TestSimplifyCFGWrapperPass : PassInfoMixin<TestSimplifyCFGWrapperPass> {895  TestSimplifyCFGWrapperPass(FunctionPassManager &InnerPM) : InnerPM(InnerPM) {}896 897  PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM) {898    // Here we simulate exactly what FunctionPassManager::run() does but899    // instead of running all passes from InnerPM.Passes we run them in bulk900    // by calling InnerPM.run().901    PreservedAnalyses PA = PreservedAnalyses::all();902    PassInstrumentation PI = FAM.getResult<PassInstrumentationAnalysis>(F);903 904    if (!PI.runBeforePass<Function>(InnerPM, F))905      return PreservedAnalyses::all();906 907    PreservedAnalyses PassPA = InnerPM.run(F, FAM);908    PI.runAfterPass(InnerPM, F, PassPA);909    FAM.invalidate(F, PassPA);910    PA.intersect(PassPA);911    PA.preserveSet<AllAnalysesOn<Function>>();912    return PA;913  }914 915  FunctionPassManager &InnerPM;916};917 918// Run TestSimplifyCFGWrapperPass which simulates behavior of919// FunctionPassManager::run() except that it runs all passes at once by calling920// an inner pass manager's passes with PassManager::run(). This is how one pass921// manager is expected to wrap another pass manager.922// SimplifyCFGPass, which is called by the inner pass manager, changes the CFG.923// The CFGChecker's AfterPassCallback, run right after SimplifyCFGPass, does not924// complain because CFGAnalyses is not in the PreservedAnalises set returned by925// SimplifyCFGPass. Then the CFG analysis is invalidated by the analysis manager926// according to the PreservedAnalises set. Further calls to CFGChecker's927// AfterPassCallback see that all analyses for the current function are928// preserved but there is no CFG snapshot available (i.e.929// AM.getCachedResult<PreservedCFGCheckerAnalysis>(F) returns nullptr).930TEST_F(PassManagerTest, FunctionPassCFGCheckerWrapped) {931  LLVMContext Context;932  // SimplifyCFG changes this function to933  // define void @foo {next: ret void}934  auto M = parseIR(Context, "define void @foo() {\n"935                            "  br label %next\n"936                            "next:\n"937                            "  br label %exit\n"938                            "exit:\n"939                            "  ret void\n"940                            "}\n");941 942  auto *F = M->getFunction("foo");943  FunctionAnalysisManager FAM;944  ModuleAnalysisManager MAM;945  FunctionPassManager FPM;946  PassInstrumentationCallbacks PIC;947  StandardInstrumentations SI(M->getContext(), /*DebugLogging*/ true);948  SI.registerCallbacks(PIC, &MAM);949  MAM.registerPass([&] { return FunctionAnalysisManagerModuleProxy(FAM); });950  MAM.registerPass([&] { return PassInstrumentationAnalysis(&PIC); });951  FAM.registerPass([&] { return PassInstrumentationAnalysis(&PIC); });952  FAM.registerPass([&] { return DominatorTreeAnalysis(); });953  FAM.registerPass([&] { return AssumptionAnalysis(); });954  FAM.registerPass([&] { return TargetIRAnalysis(); });955 956  FunctionPassManager InnerFPM;957  InnerFPM.addPass(SimplifyCFGPass());958 959  FPM.addPass(TestSimplifyCFGWrapperPass(InnerFPM));960  FPM.run(*F, FAM);961}962 963#ifdef EXPENSIVE_CHECKS964 965struct WrongFunctionPass : PassInfoMixin<WrongFunctionPass> {966  PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM) {967    F.getEntryBlock().begin()->eraseFromParent();968    return PreservedAnalyses::all();969  }970  static StringRef name() { return "WrongFunctionPass"; }971};972 973TEST_F(PassManagerTest, FunctionPassMissedFunctionAnalysisInvalidation) {974  LLVMContext Context;975  auto M = parseIR(Context, "define void @foo() {\n"976                            "  %a = add i32 0, 0\n"977                            "  ret void\n"978                            "}\n");979 980  FunctionAnalysisManager FAM;981  ModuleAnalysisManager MAM;982  PassInstrumentationCallbacks PIC;983  StandardInstrumentations SI(M->getContext(), /*DebugLogging*/ false);984  SI.registerCallbacks(PIC, &MAM);985  MAM.registerPass([&] { return FunctionAnalysisManagerModuleProxy(FAM); });986  MAM.registerPass([&] { return PassInstrumentationAnalysis(&PIC); });987  FAM.registerPass([&] { return PassInstrumentationAnalysis(&PIC); });988  FAM.registerPass([&] { return ModuleAnalysisManagerFunctionProxy(MAM); });989 990  FunctionPassManager FPM;991  FPM.addPass(WrongFunctionPass());992 993  auto *F = M->getFunction("foo");994  EXPECT_DEATH(FPM.run(*F, FAM), "Function @foo changed by WrongFunctionPass without invalidating analyses");995}996 997struct WrongModulePass : PassInfoMixin<WrongModulePass> {998  PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM) {999    for (Function &F : M)1000      F.getEntryBlock().begin()->eraseFromParent();1001 1002    PreservedAnalyses PA;1003    PA.preserveSet<AllAnalysesOn<Function>>();1004    PA.preserve<FunctionAnalysisManagerModuleProxy>();1005    return PA;1006  }1007  static StringRef name() { return "WrongModulePass"; }1008};1009 1010TEST_F(PassManagerTest, ModulePassMissedFunctionAnalysisInvalidation) {1011  LLVMContext Context;1012  auto M = parseIR(Context, "define void @foo() {\n"1013                            "  %a = add i32 0, 0\n"1014                            "  ret void\n"1015                            "}\n");1016 1017  FunctionAnalysisManager FAM;1018  ModuleAnalysisManager MAM;1019  PassInstrumentationCallbacks PIC;1020  StandardInstrumentations SI(M->getContext(), /*DebugLogging*/ false);1021  SI.registerCallbacks(PIC, &MAM);1022  MAM.registerPass([&] { return FunctionAnalysisManagerModuleProxy(FAM); });1023  MAM.registerPass([&] { return PassInstrumentationAnalysis(&PIC); });1024  FAM.registerPass([&] { return PassInstrumentationAnalysis(&PIC); });1025  FAM.registerPass([&] { return ModuleAnalysisManagerFunctionProxy(MAM); });1026 1027  ModulePassManager MPM;1028  MPM.addPass(WrongModulePass());1029 1030  EXPECT_DEATH(1031      MPM.run(*M, MAM),1032      "Function @foo changed by WrongModulePass without invalidating analyses");1033}1034 1035struct WrongModulePass2 : PassInfoMixin<WrongModulePass2> {1036  PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM) {1037    for (Function &F : M)1038      F.getEntryBlock().begin()->eraseFromParent();1039 1040    PreservedAnalyses PA;1041    PA.preserveSet<AllAnalysesOn<Module>>();1042    PA.abandon<FunctionAnalysisManagerModuleProxy>();1043    return PA;1044  }1045  static StringRef name() { return "WrongModulePass2"; }1046};1047 1048TEST_F(PassManagerTest, ModulePassMissedModuleAnalysisInvalidation) {1049  LLVMContext Context;1050  auto M = parseIR(Context, "define void @foo() {\n"1051                            "  %a = add i32 0, 0\n"1052                            "  ret void\n"1053                            "}\n");1054 1055  FunctionAnalysisManager FAM;1056  ModuleAnalysisManager MAM;1057  PassInstrumentationCallbacks PIC;1058  StandardInstrumentations SI(M->getContext(), /*DebugLogging*/ false);1059  SI.registerCallbacks(PIC, &MAM);1060  MAM.registerPass([&] { return FunctionAnalysisManagerModuleProxy(FAM); });1061  MAM.registerPass([&] { return PassInstrumentationAnalysis(&PIC); });1062  FAM.registerPass([&] { return PassInstrumentationAnalysis(&PIC); });1063  FAM.registerPass([&] { return ModuleAnalysisManagerFunctionProxy(MAM); });1064 1065  ModulePassManager MPM;1066  MPM.addPass(WrongModulePass2());1067 1068  EXPECT_DEATH(1069      MPM.run(*M, MAM),1070      "Module changed by WrongModulePass2 without invalidating analyses");1071}1072 1073#endif1074}1075