diff options
Diffstat (limited to 'gnu/llvm/unittests/IR/PassManagerTest.cpp')
| -rw-r--r-- | gnu/llvm/unittests/IR/PassManagerTest.cpp | 784 |
1 files changed, 0 insertions, 784 deletions
diff --git a/gnu/llvm/unittests/IR/PassManagerTest.cpp b/gnu/llvm/unittests/IR/PassManagerTest.cpp deleted file mode 100644 index 13b87f1022e..00000000000 --- a/gnu/llvm/unittests/IR/PassManagerTest.cpp +++ /dev/null @@ -1,784 +0,0 @@ -//===- 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/IR/PassManager.h" -#include "llvm/AsmParser/Parser.h" -#include "llvm/IR/Function.h" -#include "llvm/IR/LLVMContext.h" -#include "llvm/IR/Module.h" -#include "llvm/Support/SourceMgr.h" -#include "gtest/gtest.h" - -using namespace llvm; - -namespace { - -class TestFunctionAnalysis : public AnalysisInfoMixin<TestFunctionAnalysis> { -public: - struct Result { - Result(int Count) : InstructionCount(Count) {} - int InstructionCount; - }; - - TestFunctionAnalysis(int &Runs) : Runs(Runs) {} - - /// 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: - friend AnalysisInfoMixin<TestFunctionAnalysis>; - static AnalysisKey Key; - - int &Runs; -}; - -AnalysisKey TestFunctionAnalysis::Key; - -class TestModuleAnalysis : public AnalysisInfoMixin<TestModuleAnalysis> { -public: - struct Result { - Result(int Count) : FunctionCount(Count) {} - int FunctionCount; - }; - - 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: - friend AnalysisInfoMixin<TestModuleAnalysis>; - static AnalysisKey Key; - - int &Runs; -}; - -AnalysisKey TestModuleAnalysis::Key; - -struct TestModulePass : PassInfoMixin<TestModulePass> { - TestModulePass(int &RunCount) : RunCount(RunCount) {} - - PreservedAnalyses run(Module &M, ModuleAnalysisManager &) { - ++RunCount; - return PreservedAnalyses::none(); - } - - int &RunCount; -}; - -struct TestPreservingModulePass : PassInfoMixin<TestPreservingModulePass> { - PreservedAnalyses run(Module &M, ModuleAnalysisManager &) { - return PreservedAnalyses::all(); - } -}; - -struct TestFunctionPass : PassInfoMixin<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<ModuleAnalysisManagerFunctionProxy>(F).getManager(); - if (TestModuleAnalysis::Result *TMA = - MAM.getCachedResult<TestModuleAnalysis>(*F.getParent())) - AnalyzedFunctionCount += TMA->FunctionCount; - - if (OnlyUseCachedResults) { - // Hack to force the use of the cached interface. - if (TestFunctionAnalysis::Result *AR = - AM.getCachedResult<TestFunctionAnalysis>(F)) - AnalyzedInstrCount += AR->InstructionCount; - } else { - // Typical path just runs the analysis as needed. - TestFunctionAnalysis::Result &AR = AM.getResult<TestFunctionAnalysis>(F); - AnalyzedInstrCount += AR.InstructionCount; - } - - return PreservedAnalyses::all(); - } - - 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 - : PassInfoMixin<TestInvalidationFunctionPass> { - TestInvalidationFunctionPass(StringRef FunctionName) : Name(FunctionName) {} - - PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM) { - return F.getName() == Name ? PreservedAnalyses::none() - : PreservedAnalyses::all(); - } - - StringRef Name; -}; - -std::unique_ptr<Module> parseIR(LLVMContext &Context, const char *IR) { - SMDiagnostic Err; - return parseAssemblyString(IR, Err, Context); -} - -class PassManagerTest : public ::testing::Test { -protected: - LLVMContext Context; - std::unique_ptr<Module> M; - -public: - PassManagerTest() - : M(parseIR(Context, "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(PreservedAnalysesTest, Basic) { - PreservedAnalyses PA1 = PreservedAnalyses(); - { - auto PAC = PA1.getChecker<TestFunctionAnalysis>(); - EXPECT_FALSE(PAC.preserved()); - EXPECT_FALSE(PAC.preservedSet<AllAnalysesOn<Function>>()); - } - { - auto PAC = PA1.getChecker<TestModuleAnalysis>(); - EXPECT_FALSE(PAC.preserved()); - EXPECT_FALSE(PAC.preservedSet<AllAnalysesOn<Module>>()); - } - auto PA2 = PreservedAnalyses::none(); - { - auto PAC = PA2.getChecker<TestFunctionAnalysis>(); - EXPECT_FALSE(PAC.preserved()); - EXPECT_FALSE(PAC.preservedSet<AllAnalysesOn<Function>>()); - } - auto PA3 = PreservedAnalyses::all(); - { - auto PAC = PA3.getChecker<TestFunctionAnalysis>(); - EXPECT_TRUE(PAC.preserved()); - EXPECT_TRUE(PAC.preservedSet<AllAnalysesOn<Function>>()); - } - PreservedAnalyses PA4 = PA1; - { - auto PAC = PA4.getChecker<TestFunctionAnalysis>(); - EXPECT_FALSE(PAC.preserved()); - EXPECT_FALSE(PAC.preservedSet<AllAnalysesOn<Function>>()); - } - PA4 = PA3; - { - auto PAC = PA4.getChecker<TestFunctionAnalysis>(); - EXPECT_TRUE(PAC.preserved()); - EXPECT_TRUE(PAC.preservedSet<AllAnalysesOn<Function>>()); - } - PA4 = std::move(PA2); - { - auto PAC = PA4.getChecker<TestFunctionAnalysis>(); - EXPECT_FALSE(PAC.preserved()); - EXPECT_FALSE(PAC.preservedSet<AllAnalysesOn<Function>>()); - } - auto PA5 = PreservedAnalyses::allInSet<AllAnalysesOn<Function>>(); - { - auto PAC = PA5.getChecker<TestFunctionAnalysis>(); - EXPECT_FALSE(PAC.preserved()); - EXPECT_TRUE(PAC.preservedSet<AllAnalysesOn<Function>>()); - EXPECT_FALSE(PAC.preservedSet<AllAnalysesOn<Module>>()); - } -} - -TEST(PreservedAnalysesTest, Preserve) { - auto PA = PreservedAnalyses::none(); - PA.preserve<TestFunctionAnalysis>(); - EXPECT_TRUE(PA.getChecker<TestFunctionAnalysis>().preserved()); - EXPECT_FALSE(PA.getChecker<TestModuleAnalysis>().preserved()); - PA.preserve<TestModuleAnalysis>(); - EXPECT_TRUE(PA.getChecker<TestFunctionAnalysis>().preserved()); - EXPECT_TRUE(PA.getChecker<TestModuleAnalysis>().preserved()); - - // Redundant calls are fine. - PA.preserve<TestFunctionAnalysis>(); - EXPECT_TRUE(PA.getChecker<TestFunctionAnalysis>().preserved()); - EXPECT_TRUE(PA.getChecker<TestModuleAnalysis>().preserved()); -} - -TEST(PreservedAnalysesTest, PreserveSets) { - auto PA = PreservedAnalyses::none(); - PA.preserveSet<AllAnalysesOn<Function>>(); - EXPECT_TRUE(PA.getChecker<TestFunctionAnalysis>() - .preservedSet<AllAnalysesOn<Function>>()); - EXPECT_FALSE(PA.getChecker<TestModuleAnalysis>() - .preservedSet<AllAnalysesOn<Module>>()); - PA.preserveSet<AllAnalysesOn<Module>>(); - EXPECT_TRUE(PA.getChecker<TestFunctionAnalysis>() - .preservedSet<AllAnalysesOn<Function>>()); - EXPECT_TRUE(PA.getChecker<TestModuleAnalysis>() - .preservedSet<AllAnalysesOn<Module>>()); - - // Mixing is fine. - PA.preserve<TestFunctionAnalysis>(); - EXPECT_TRUE(PA.getChecker<TestFunctionAnalysis>() - .preservedSet<AllAnalysesOn<Function>>()); - EXPECT_TRUE(PA.getChecker<TestModuleAnalysis>() - .preservedSet<AllAnalysesOn<Module>>()); - - // Redundant calls are fine. - PA.preserveSet<AllAnalysesOn<Module>>(); - EXPECT_TRUE(PA.getChecker<TestFunctionAnalysis>() - .preservedSet<AllAnalysesOn<Function>>()); - EXPECT_TRUE(PA.getChecker<TestModuleAnalysis>() - .preservedSet<AllAnalysesOn<Module>>()); -} - -TEST(PreservedAnalysisTest, Intersect) { - // Setup the initial sets. - auto PA1 = PreservedAnalyses::none(); - PA1.preserve<TestFunctionAnalysis>(); - PA1.preserveSet<AllAnalysesOn<Module>>(); - auto PA2 = PreservedAnalyses::none(); - PA2.preserve<TestFunctionAnalysis>(); - PA2.preserveSet<AllAnalysesOn<Function>>(); - PA2.preserve<TestModuleAnalysis>(); - PA2.preserveSet<AllAnalysesOn<Module>>(); - auto PA3 = PreservedAnalyses::none(); - PA3.preserve<TestModuleAnalysis>(); - PA3.preserveSet<AllAnalysesOn<Function>>(); - - // Self intersection is a no-op. - auto Intersected = PA1; - Intersected.intersect(PA1); - EXPECT_TRUE(Intersected.getChecker<TestFunctionAnalysis>().preserved()); - EXPECT_FALSE(Intersected.getChecker<TestFunctionAnalysis>() - .preservedSet<AllAnalysesOn<Function>>()); - EXPECT_FALSE(Intersected.getChecker<TestModuleAnalysis>().preserved()); - EXPECT_TRUE(Intersected.getChecker<TestModuleAnalysis>() - .preservedSet<AllAnalysesOn<Module>>()); - - // Intersecting with all is a no-op. - Intersected.intersect(PreservedAnalyses::all()); - EXPECT_TRUE(Intersected.getChecker<TestFunctionAnalysis>().preserved()); - EXPECT_FALSE(Intersected.getChecker<TestFunctionAnalysis>() - .preservedSet<AllAnalysesOn<Function>>()); - EXPECT_FALSE(Intersected.getChecker<TestModuleAnalysis>().preserved()); - EXPECT_TRUE(Intersected.getChecker<TestModuleAnalysis>() - .preservedSet<AllAnalysesOn<Module>>()); - - // Intersecting a narrow set with a more broad set is the narrow set. - Intersected.intersect(PA2); - EXPECT_TRUE(Intersected.getChecker<TestFunctionAnalysis>().preserved()); - EXPECT_FALSE(Intersected.getChecker<TestFunctionAnalysis>() - .preservedSet<AllAnalysesOn<Function>>()); - EXPECT_FALSE(Intersected.getChecker<TestModuleAnalysis>().preserved()); - EXPECT_TRUE(Intersected.getChecker<TestModuleAnalysis>() - .preservedSet<AllAnalysesOn<Module>>()); - - // Intersecting a broad set with a more narrow set is the narrow set. - Intersected = PA2; - Intersected.intersect(PA1); - EXPECT_TRUE(Intersected.getChecker<TestFunctionAnalysis>().preserved()); - EXPECT_FALSE(Intersected.getChecker<TestFunctionAnalysis>() - .preservedSet<AllAnalysesOn<Function>>()); - EXPECT_FALSE(Intersected.getChecker<TestModuleAnalysis>().preserved()); - EXPECT_TRUE(Intersected.getChecker<TestModuleAnalysis>() - .preservedSet<AllAnalysesOn<Module>>()); - - // Intersecting with empty clears. - Intersected.intersect(PreservedAnalyses::none()); - EXPECT_FALSE(Intersected.getChecker<TestFunctionAnalysis>().preserved()); - EXPECT_FALSE(Intersected.getChecker<TestFunctionAnalysis>() - .preservedSet<AllAnalysesOn<Function>>()); - EXPECT_FALSE(Intersected.getChecker<TestModuleAnalysis>().preserved()); - EXPECT_FALSE(Intersected.getChecker<TestModuleAnalysis>() - .preservedSet<AllAnalysesOn<Module>>()); - - // Intersecting non-overlapping clears. - Intersected = PA1; - Intersected.intersect(PA3); - EXPECT_FALSE(Intersected.getChecker<TestFunctionAnalysis>().preserved()); - EXPECT_FALSE(Intersected.getChecker<TestFunctionAnalysis>() - .preservedSet<AllAnalysesOn<Function>>()); - EXPECT_FALSE(Intersected.getChecker<TestModuleAnalysis>().preserved()); - EXPECT_FALSE(Intersected.getChecker<TestModuleAnalysis>() - .preservedSet<AllAnalysesOn<Module>>()); - - // Intersecting with moves works in when there is storage on both sides. - Intersected = PA1; - auto Tmp = PA2; - Intersected.intersect(std::move(Tmp)); - EXPECT_TRUE(Intersected.getChecker<TestFunctionAnalysis>().preserved()); - EXPECT_FALSE(Intersected.getChecker<TestFunctionAnalysis>() - .preservedSet<AllAnalysesOn<Function>>()); - EXPECT_FALSE(Intersected.getChecker<TestModuleAnalysis>().preserved()); - EXPECT_TRUE(Intersected.getChecker<TestModuleAnalysis>() - .preservedSet<AllAnalysesOn<Module>>()); - - // Intersecting with move works for incoming all and existing all. - auto Tmp2 = PreservedAnalyses::all(); - Intersected.intersect(std::move(Tmp2)); - EXPECT_TRUE(Intersected.getChecker<TestFunctionAnalysis>().preserved()); - EXPECT_FALSE(Intersected.getChecker<TestFunctionAnalysis>() - .preservedSet<AllAnalysesOn<Function>>()); - EXPECT_FALSE(Intersected.getChecker<TestModuleAnalysis>().preserved()); - EXPECT_TRUE(Intersected.getChecker<TestModuleAnalysis>() - .preservedSet<AllAnalysesOn<Module>>()); - Intersected = PreservedAnalyses::all(); - auto Tmp3 = PA1; - Intersected.intersect(std::move(Tmp3)); - EXPECT_TRUE(Intersected.getChecker<TestFunctionAnalysis>().preserved()); - EXPECT_FALSE(Intersected.getChecker<TestFunctionAnalysis>() - .preservedSet<AllAnalysesOn<Function>>()); - EXPECT_FALSE(Intersected.getChecker<TestModuleAnalysis>().preserved()); - EXPECT_TRUE(Intersected.getChecker<TestModuleAnalysis>() - .preservedSet<AllAnalysesOn<Module>>()); -} - -TEST(PreservedAnalysisTest, Abandon) { - auto PA = PreservedAnalyses::none(); - - // We can abandon things after they are preserved. - PA.preserve<TestFunctionAnalysis>(); - PA.abandon<TestFunctionAnalysis>(); - EXPECT_FALSE(PA.getChecker<TestFunctionAnalysis>().preserved()); - - // Repeated is fine, and abandoning if they were never preserved is fine. - PA.abandon<TestFunctionAnalysis>(); - EXPECT_FALSE(PA.getChecker<TestFunctionAnalysis>().preserved()); - PA.abandon<TestModuleAnalysis>(); - EXPECT_FALSE(PA.getChecker<TestModuleAnalysis>().preserved()); - - // Even if the sets are preserved, the abandoned analyses' checker won't - // return true for those sets. - PA.preserveSet<AllAnalysesOn<Function>>(); - PA.preserveSet<AllAnalysesOn<Module>>(); - EXPECT_FALSE(PA.getChecker<TestFunctionAnalysis>() - .preservedSet<AllAnalysesOn<Function>>()); - EXPECT_FALSE(PA.getChecker<TestModuleAnalysis>() - .preservedSet<AllAnalysesOn<Module>>()); - - // But an arbitrary (opaque) analysis will still observe the sets as - // preserved. This also checks that we can use an explicit ID rather than - // a type. - AnalysisKey FakeKey, *FakeID = &FakeKey; - EXPECT_TRUE(PA.getChecker(FakeID).preservedSet<AllAnalysesOn<Function>>()); - EXPECT_TRUE(PA.getChecker(FakeID).preservedSet<AllAnalysesOn<Module>>()); -} - -TEST_F(PassManagerTest, Basic) { - FunctionAnalysisManager FAM(/*DebugLogging*/ true); - int FunctionAnalysisRuns = 0; - FAM.registerPass([&] { return TestFunctionAnalysis(FunctionAnalysisRuns); }); - - ModuleAnalysisManager MAM(/*DebugLogging*/ true); - int ModuleAnalysisRuns = 0; - MAM.registerPass([&] { return TestModuleAnalysis(ModuleAnalysisRuns); }); - MAM.registerPass([&] { return FunctionAnalysisManagerModuleProxy(FAM); }); - FAM.registerPass([&] { return ModuleAnalysisManagerFunctionProxy(MAM); }); - - MAM.registerPass([&] { return PassInstrumentationAnalysis(); }); - FAM.registerPass([&] { return PassInstrumentationAnalysis(); }); - - 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(/*DebugLogging*/ true); - FunctionPassManager FPM; - { - // Pointless scope to test move assignment. - FunctionPassManager NestedFPM(/*DebugLogging*/ true); - 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(/*DebugLogging*/ true); - 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(/*DebugLogging*/ true); - FPM.addPass(TestFunctionPass(FunctionPassRunCount3, AnalyzedInstrCount3, - AnalyzedFunctionCount3)); - FPM.addPass(TestInvalidationFunctionPass("f")); - MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); - } - - // A fourth function pass manager but with only preserving intervening - // passes but triggering the module analysis. - MPM.addPass(RequireAnalysisPass<TestModuleAnalysis, Module>()); - 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 which invalidates one function first but - // uses only cached results. - int FunctionPassRunCount5 = 0; - int AnalyzedInstrCount5 = 0; - int AnalyzedFunctionCount5 = 0; - { - FunctionPassManager FPM(/*DebugLogging*/ true); - FPM.addPass(TestInvalidationFunctionPass("f")); - FPM.addPass(TestFunctionPass(FunctionPassRunCount5, AnalyzedInstrCount5, - AnalyzedFunctionCount5, - /*OnlyUseCachedResults=*/true)); - MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); - } - - MPM.run(*M, 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(9, AnalyzedFunctionCount4); - EXPECT_EQ(3, FunctionPassRunCount5); - EXPECT_EQ(2, AnalyzedInstrCount5); // Only 'g' and 'h' were cached. - EXPECT_EQ(9, 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 - // fifth run invalidates 1 function first, but runs over 0 functions - EXPECT_EQ(7, FunctionAnalysisRuns); - - EXPECT_EQ(1, ModuleAnalysisRuns); -} - -// A customized pass manager that passes extra arguments through the -// infrastructure. -typedef AnalysisManager<Function, int> CustomizedAnalysisManager; -typedef PassManager<Function, CustomizedAnalysisManager, int, int &> - CustomizedPassManager; - -class CustomizedAnalysis : public AnalysisInfoMixin<CustomizedAnalysis> { -public: - struct Result { - Result(int I) : I(I) {} - int I; - }; - - Result run(Function &F, CustomizedAnalysisManager &AM, int I) { - return Result(I); - } - -private: - friend AnalysisInfoMixin<CustomizedAnalysis>; - static AnalysisKey Key; -}; - -AnalysisKey CustomizedAnalysis::Key; - -struct CustomizedPass : PassInfoMixin<CustomizedPass> { - std::function<void(CustomizedAnalysis::Result &, int &)> Callback; - - template <typename CallbackT> - CustomizedPass(CallbackT Callback) : Callback(Callback) {} - - PreservedAnalyses run(Function &F, CustomizedAnalysisManager &AM, int I, - int &O) { - Callback(AM.getResult<CustomizedAnalysis>(F, I), O); - return PreservedAnalyses::none(); - } -}; - -TEST_F(PassManagerTest, CustomizedPassManagerArgs) { - CustomizedAnalysisManager AM; - AM.registerPass([&] { return CustomizedAnalysis(); }); - PassInstrumentationCallbacks PIC; - AM.registerPass([&] { return PassInstrumentationAnalysis(&PIC); }); - - CustomizedPassManager PM; - - // Add an instance of the customized pass that just accumulates the input - // after it is round-tripped through the analysis. - int Result = 0; - PM.addPass( - CustomizedPass([](CustomizedAnalysis::Result &R, int &O) { O += R.I; })); - - // Run this over every function with the input of 42. - for (Function &F : *M) - PM.run(F, AM, 42, Result); - - // And ensure that we accumulated the correct result. - EXPECT_EQ(42 * (int)M->size(), Result); -} - -/// A test analysis pass which caches in its result another analysis pass and -/// uses it to serve queries. This requires the result to invalidate itself -/// when its dependency is invalidated. -struct TestIndirectFunctionAnalysis - : public AnalysisInfoMixin<TestIndirectFunctionAnalysis> { - struct Result { - Result(TestFunctionAnalysis::Result &FDep, TestModuleAnalysis::Result &MDep) - : FDep(FDep), MDep(MDep) {} - TestFunctionAnalysis::Result &FDep; - TestModuleAnalysis::Result &MDep; - - bool invalidate(Function &F, const PreservedAnalyses &PA, - FunctionAnalysisManager::Invalidator &Inv) { - auto PAC = PA.getChecker<TestIndirectFunctionAnalysis>(); - return !(PAC.preserved() || - PAC.preservedSet<AllAnalysesOn<Function>>()) || - Inv.invalidate<TestFunctionAnalysis>(F, PA); - } - }; - - TestIndirectFunctionAnalysis(int &Runs) : Runs(Runs) {} - - /// Run the analysis pass over the function and return a result. - Result run(Function &F, FunctionAnalysisManager &AM) { - ++Runs; - auto &FDep = AM.getResult<TestFunctionAnalysis>(F); - auto &Proxy = AM.getResult<ModuleAnalysisManagerFunctionProxy>(F); - const ModuleAnalysisManager &MAM = Proxy.getManager(); - // For the test, we insist that the module analysis starts off in the - // cache. - auto &MDep = *MAM.getCachedResult<TestModuleAnalysis>(*F.getParent()); - // And register the dependency as module analysis dependencies have to be - // pre-registered on the proxy. - Proxy.registerOuterAnalysisInvalidation<TestModuleAnalysis, - TestIndirectFunctionAnalysis>(); - return Result(FDep, MDep); - } - -private: - friend AnalysisInfoMixin<TestIndirectFunctionAnalysis>; - static AnalysisKey Key; - - int &Runs; -}; - -AnalysisKey TestIndirectFunctionAnalysis::Key; - -/// A test analysis pass which chaches in its result the result from the above -/// indirect analysis pass. -/// -/// This allows us to ensure that whenever an analysis pass is invalidated due -/// to dependencies (especially dependencies across IR units that trigger -/// asynchronous invalidation) we correctly detect that this may in turn cause -/// other analysis to be invalidated. -struct TestDoublyIndirectFunctionAnalysis - : public AnalysisInfoMixin<TestDoublyIndirectFunctionAnalysis> { - struct Result { - Result(TestIndirectFunctionAnalysis::Result &IDep) : IDep(IDep) {} - TestIndirectFunctionAnalysis::Result &IDep; - - bool invalidate(Function &F, const PreservedAnalyses &PA, - FunctionAnalysisManager::Invalidator &Inv) { - auto PAC = PA.getChecker<TestDoublyIndirectFunctionAnalysis>(); - return !(PAC.preserved() || - PAC.preservedSet<AllAnalysesOn<Function>>()) || - Inv.invalidate<TestIndirectFunctionAnalysis>(F, PA); - } - }; - - TestDoublyIndirectFunctionAnalysis(int &Runs) : Runs(Runs) {} - - /// Run the analysis pass over the function and return a result. - Result run(Function &F, FunctionAnalysisManager &AM) { - ++Runs; - auto &IDep = AM.getResult<TestIndirectFunctionAnalysis>(F); - return Result(IDep); - } - -private: - friend AnalysisInfoMixin<TestDoublyIndirectFunctionAnalysis>; - static AnalysisKey Key; - - int &Runs; -}; - -AnalysisKey TestDoublyIndirectFunctionAnalysis::Key; - -struct LambdaPass : public PassInfoMixin<LambdaPass> { - using FuncT = std::function<PreservedAnalyses(Function &, FunctionAnalysisManager &)>; - - LambdaPass(FuncT Func) : Func(std::move(Func)) {} - - PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM) { - return Func(F, AM); - } - - FuncT Func; -}; - -TEST_F(PassManagerTest, IndirectAnalysisInvalidation) { - FunctionAnalysisManager FAM(/*DebugLogging*/ true); - int FunctionAnalysisRuns = 0, ModuleAnalysisRuns = 0, - IndirectAnalysisRuns = 0, DoublyIndirectAnalysisRuns = 0; - FAM.registerPass([&] { return TestFunctionAnalysis(FunctionAnalysisRuns); }); - FAM.registerPass( - [&] { return TestIndirectFunctionAnalysis(IndirectAnalysisRuns); }); - FAM.registerPass([&] { - return TestDoublyIndirectFunctionAnalysis(DoublyIndirectAnalysisRuns); - }); - - ModuleAnalysisManager MAM(/*DebugLogging*/ true); - MAM.registerPass([&] { return TestModuleAnalysis(ModuleAnalysisRuns); }); - MAM.registerPass([&] { return FunctionAnalysisManagerModuleProxy(FAM); }); - FAM.registerPass([&] { return ModuleAnalysisManagerFunctionProxy(MAM); }); - - PassInstrumentationCallbacks PIC; - MAM.registerPass([&] { return PassInstrumentationAnalysis(&PIC); }); - FAM.registerPass([&] { return PassInstrumentationAnalysis(&PIC); }); - - int InstrCount = 0, FunctionCount = 0; - ModulePassManager MPM(/*DebugLogging*/ true); - FunctionPassManager FPM(/*DebugLogging*/ true); - // First just use the analysis to get the instruction count, and preserve - // everything. - FPM.addPass(LambdaPass([&](Function &F, FunctionAnalysisManager &AM) { - auto &DoublyIndirectResult = - AM.getResult<TestDoublyIndirectFunctionAnalysis>(F); - auto &IndirectResult = DoublyIndirectResult.IDep; - InstrCount += IndirectResult.FDep.InstructionCount; - FunctionCount += IndirectResult.MDep.FunctionCount; - return PreservedAnalyses::all(); - })); - // Next, invalidate - // - both analyses for "f", - // - just the underlying (indirect) analysis for "g", and - // - just the direct analysis for "h". - FPM.addPass(LambdaPass([&](Function &F, FunctionAnalysisManager &AM) { - auto &DoublyIndirectResult = - AM.getResult<TestDoublyIndirectFunctionAnalysis>(F); - auto &IndirectResult = DoublyIndirectResult.IDep; - InstrCount += IndirectResult.FDep.InstructionCount; - FunctionCount += IndirectResult.MDep.FunctionCount; - auto PA = PreservedAnalyses::none(); - if (F.getName() == "g") - PA.preserve<TestFunctionAnalysis>(); - else if (F.getName() == "h") - PA.preserve<TestIndirectFunctionAnalysis>(); - return PA; - })); - // Finally, use the analysis again on each function, forcing re-computation - // for all of them. - FPM.addPass(LambdaPass([&](Function &F, FunctionAnalysisManager &AM) { - auto &DoublyIndirectResult = - AM.getResult<TestDoublyIndirectFunctionAnalysis>(F); - auto &IndirectResult = DoublyIndirectResult.IDep; - InstrCount += IndirectResult.FDep.InstructionCount; - FunctionCount += IndirectResult.MDep.FunctionCount; - return PreservedAnalyses::all(); - })); - - // Create a second function pass manager. This will cause the module-level - // invalidation to occur, which will force yet another invalidation of the - // indirect function-level analysis as the module analysis it depends on gets - // invalidated. - FunctionPassManager FPM2(/*DebugLogging*/ true); - FPM2.addPass(LambdaPass([&](Function &F, FunctionAnalysisManager &AM) { - auto &DoublyIndirectResult = - AM.getResult<TestDoublyIndirectFunctionAnalysis>(F); - auto &IndirectResult = DoublyIndirectResult.IDep; - InstrCount += IndirectResult.FDep.InstructionCount; - FunctionCount += IndirectResult.MDep.FunctionCount; - return PreservedAnalyses::all(); - })); - - // Add a requires pass to populate the module analysis and then our function - // pass pipeline. - MPM.addPass(RequireAnalysisPass<TestModuleAnalysis, Module>()); - MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); - // Now require the module analysis again (it will have been invalidated once) - // and then use it again from a function pass manager. - MPM.addPass(RequireAnalysisPass<TestModuleAnalysis, Module>()); - MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM2))); - MPM.run(*M, MAM); - - // There are generally two possible runs for each of the three functions. But - // for one function, we only invalidate the indirect analysis so the base one - // only gets run five times. - EXPECT_EQ(5, FunctionAnalysisRuns); - // The module analysis pass should be run twice here. - EXPECT_EQ(2, ModuleAnalysisRuns); - // The indirect analysis is invalidated for each function (either directly or - // indirectly) and run twice for each. - EXPECT_EQ(9, IndirectAnalysisRuns); - EXPECT_EQ(9, DoublyIndirectAnalysisRuns); - - // There are five instructions in the module and we add the count four - // times. - EXPECT_EQ(5 * 4, InstrCount); - - // There are three functions and we count them four times for each of the - // three functions. - EXPECT_EQ(3 * 4 * 3, FunctionCount); -} -} |
