diff --git a/llvm/include/llvm/Analysis/AliasAnalysis.h b/llvm/include/llvm/Analysis/AliasAnalysis.h --- a/llvm/include/llvm/Analysis/AliasAnalysis.h +++ b/llvm/include/llvm/Analysis/AliasAnalysis.h @@ -1143,8 +1143,8 @@ static void getModuleAAResultImpl(Function &F, FunctionAnalysisManager &AM, AAResults &AAResults) { auto &MAMProxy = AM.getResult(F); - auto &MAM = MAMProxy.getManager(); - if (auto *R = MAM.template getCachedResult(*F.getParent())) { + if (auto *R = + MAMProxy.template getCachedResult(*F.getParent())) { AAResults.addAAResult(*R); MAMProxy .template registerOuterAnalysisInvalidation(); diff --git a/llvm/include/llvm/IR/PassManager.h b/llvm/include/llvm/IR/PassManager.h --- a/llvm/include/llvm/IR/PassManager.h +++ b/llvm/include/llvm/IR/PassManager.h @@ -62,6 +62,8 @@ namespace llvm { +class FunctionAnalysisManagerCGSCCProxy; + /// A special type used by analysis passes to provide an address that /// identifies that particular analysis pass type. /// @@ -793,7 +795,8 @@ /// /// \returns null if there is no cached result. template - typename PassT::Result *getCachedResult(IRUnitT &IR) const { + typename PassT::Result *getCachedResult(IRUnitT &IR, + bool calledFromProxy = false) const { assert(AnalysisPasses.count(PassT::ID()) && "This analysis pass was not registered prior to being queried"); @@ -805,7 +808,15 @@ detail::AnalysisResultModel; - return &static_cast(ResultConcept)->Result; + auto *RetRes = &static_cast(ResultConcept)->Result; + if (calledFromProxy) { + PreservedAnalyses PA = PreservedAnalyses::none(); + SmallDenseMap IsResultInvalidated; + Invalidator Inv(IsResultInvalidated, AnalysisResults); + assert(!RetRes->invalidate(IR, PA, Inv) && + "Cached result cannot be invalidated"); + } + return RetRes; } /// Register an analysis pass with the manager. @@ -1167,7 +1178,22 @@ public: explicit Result(const AnalysisManagerT &OuterAM) : OuterAM(&OuterAM) {} - const AnalysisManagerT &getManager() const { return *OuterAM; } + /// Get a cached analysis. If the analysis can be invalidated, this will + /// assert. + template + typename PassT::Result *getCachedResult(IRUnitTParam &IR) const { + typename PassT::Result *Res = + OuterAM->template getCachedResult(IR, true); + return Res; + } + + /// Method provided for unit testing, not intended for general use. + template + bool cachedResultExists(IRUnitTParam &IR) const { + typename PassT::Result *Res = + OuterAM->template getCachedResult(IR); + return Res != nullptr; + } /// When invalidation occurs, remove any registered invalidation events. bool invalidate( @@ -1219,6 +1245,8 @@ } private: + const AnalysisManagerT &getInnerManager() const { return *OuterAM; } + friend FunctionAnalysisManagerCGSCCProxy; const AnalysisManagerT *OuterAM; /// A map from an outer analysis ID to the set of this IR-unit's analyses diff --git a/llvm/lib/Analysis/CGSCCPassManager.cpp b/llvm/lib/Analysis/CGSCCPassManager.cpp --- a/llvm/lib/Analysis/CGSCCPassManager.cpp +++ b/llvm/lib/Analysis/CGSCCPassManager.cpp @@ -221,11 +221,13 @@ // Collect the FunctionAnalysisManager from the Module layer and use that to // build the proxy result. // - // This allows us to rely on the FunctionAnalysisMangaerModuleProxy to + // This allows us to rely on the FunctionAnalysisManagerModuleProxy to // invalidate the function analyses. - auto &MAM = AM.getResult(C, CG).getManager(); + auto &MAMProxy = + AM.getResult(C, CG).getInnerManager(); Module &M = *C.begin()->getFunction().getParent(); - auto *FAMProxy = MAM.getCachedResult(M); + auto *FAMProxy = + MAMProxy.getCachedResult(M); assert(FAMProxy && "The CGSCC pass manager requires that the FAM module " "proxy is run on the module prior to entering the CGSCC " "walk."); diff --git a/llvm/lib/Transforms/IPO/Inliner.cpp b/llvm/lib/Transforms/IPO/Inliner.cpp --- a/llvm/lib/Transforms/IPO/Inliner.cpp +++ b/llvm/lib/Transforms/IPO/Inliner.cpp @@ -875,13 +875,13 @@ PreservedAnalyses InlinerPass::run(LazyCallGraph::SCC &InitialC, CGSCCAnalysisManager &AM, LazyCallGraph &CG, CGSCCUpdateResult &UR) { - const ModuleAnalysisManager &MAM = - AM.getResult(InitialC, CG).getManager(); + const auto &MAMProxy = + AM.getResult(InitialC, CG); bool Changed = false; assert(InitialC.size() > 0 && "Cannot handle an empty SCC!"); Module &M = *InitialC.begin()->getFunction().getParent(); - ProfileSummaryInfo *PSI = MAM.getCachedResult(M); + ProfileSummaryInfo *PSI = MAMProxy.getCachedResult(M); if (!ImportedFunctionsStats && InlinerFunctionImportStats != InlinerFunctionImportStatsOpts::No) { diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp --- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp +++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp @@ -3643,10 +3643,9 @@ auto *LI = AM.getCachedResult(F); auto *AA = &AM.getResult(F); - const ModuleAnalysisManager &MAM = - AM.getResult(F).getManager(); + auto &MAMProxy = AM.getResult(F); ProfileSummaryInfo *PSI = - MAM.getCachedResult(*F.getParent()); + MAMProxy.getCachedResult(*F.getParent()); auto *BFI = (PSI && PSI->hasProfileSummary()) ? &AM.getResult(F) : nullptr; diff --git a/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp --- a/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp +++ b/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp @@ -1168,9 +1168,8 @@ PreservedAnalyses AddressSanitizerPass::run(Function &F, AnalysisManager &AM) { auto &MAMProxy = AM.getResult(F); - auto &MAM = MAMProxy.getManager(); Module &M = *F.getParent(); - if (auto *R = MAM.getCachedResult(M)) { + if (auto *R = MAMProxy.getCachedResult(M)) { const TargetLibraryInfo *TLI = &AM.getResult(F); AddressSanitizer Sanitizer(M, R, CompileKernel, Recover, UseAfterScope); if (Sanitizer.instrumentFunction(F, TLI)) diff --git a/llvm/lib/Transforms/Instrumentation/ControlHeightReduction.cpp b/llvm/lib/Transforms/Instrumentation/ControlHeightReduction.cpp --- a/llvm/lib/Transforms/Instrumentation/ControlHeightReduction.cpp +++ b/llvm/lib/Transforms/Instrumentation/ControlHeightReduction.cpp @@ -2101,8 +2101,7 @@ auto &BFI = FAM.getResult(F); auto &DT = FAM.getResult(F); auto &MAMProxy = FAM.getResult(F); - auto &MAM = MAMProxy.getManager(); - auto &PSI = *MAM.getCachedResult(*F.getParent()); + auto &PSI = *MAMProxy.getCachedResult(*F.getParent()); auto &RI = FAM.getResult(F); auto &ORE = FAM.getResult(F); bool Changed = CHR(F, BFI, DT, PSI, RI, ORE).run(); diff --git a/llvm/lib/Transforms/Scalar/ConstantHoisting.cpp b/llvm/lib/Transforms/Scalar/ConstantHoisting.cpp --- a/llvm/lib/Transforms/Scalar/ConstantHoisting.cpp +++ b/llvm/lib/Transforms/Scalar/ConstantHoisting.cpp @@ -975,8 +975,8 @@ auto BFI = ConstHoistWithBlockFrequency ? &AM.getResult(F) : nullptr; - auto &MAM = AM.getResult(F).getManager(); - auto *PSI = MAM.getCachedResult(*F.getParent()); + auto &MAMProxy = AM.getResult(F); + auto *PSI = MAMProxy.getCachedResult(*F.getParent()); if (!runImpl(F, TTI, DT, BFI, F.getEntryBlock(), PSI)) return PreservedAnalyses::all(); diff --git a/llvm/lib/Transforms/Scalar/LoopLoadElimination.cpp b/llvm/lib/Transforms/Scalar/LoopLoadElimination.cpp --- a/llvm/lib/Transforms/Scalar/LoopLoadElimination.cpp +++ b/llvm/lib/Transforms/Scalar/LoopLoadElimination.cpp @@ -697,8 +697,8 @@ auto &TLI = AM.getResult(F); auto &AA = AM.getResult(F); auto &AC = AM.getResult(F); - auto &MAM = AM.getResult(F).getManager(); - auto *PSI = MAM.getCachedResult(*F.getParent()); + auto &MAMProxy = AM.getResult(F); + auto *PSI = MAMProxy.getCachedResult(*F.getParent()); auto *BFI = (PSI && PSI->hasProfileSummary()) ? &AM.getResult(F) : nullptr; MemorySSA *MSSA = EnableMSSALoopDependency diff --git a/llvm/lib/Transforms/Scalar/LoopUnrollPass.cpp b/llvm/lib/Transforms/Scalar/LoopUnrollPass.cpp --- a/llvm/lib/Transforms/Scalar/LoopUnrollPass.cpp +++ b/llvm/lib/Transforms/Scalar/LoopUnrollPass.cpp @@ -1426,10 +1426,9 @@ if (auto *LAMProxy = AM.getCachedResult(F)) LAM = &LAMProxy->getManager(); - const ModuleAnalysisManager &MAM = - AM.getResult(F).getManager(); + auto &MAMProxy = AM.getResult(F); ProfileSummaryInfo *PSI = - MAM.getCachedResult(*F.getParent()); + MAMProxy.getCachedResult(*F.getParent()); auto *BFI = (PSI && PSI->hasProfileSummary()) ? &AM.getResult(F) : nullptr; diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp --- a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp +++ b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp @@ -7982,10 +7982,9 @@ LoopStandardAnalysisResults AR = {AA, AC, DT, LI, SE, TLI, TTI, MSSA}; return LAM.getResult(L, AR); }; - const ModuleAnalysisManager &MAM = - AM.getResult(F).getManager(); + auto &MAMProxy = AM.getResult(F); ProfileSummaryInfo *PSI = - MAM.getCachedResult(*F.getParent()); + MAMProxy.getCachedResult(*F.getParent()); bool Changed = runImpl(F, SE, LI, TTI, DT, BFI, &TLI, DB, AA, AC, GetLAA, ORE, PSI); if (!Changed) diff --git a/llvm/unittests/Analysis/CGSCCPassManagerTest.cpp b/llvm/unittests/Analysis/CGSCCPassManagerTest.cpp --- a/llvm/unittests/Analysis/CGSCCPassManagerTest.cpp +++ b/llvm/unittests/Analysis/CGSCCPassManagerTest.cpp @@ -302,15 +302,28 @@ LazyCallGraph &CG, CGSCCUpdateResult &UR) { ++SCCPassRunCount1; - const ModuleAnalysisManager &MAM = - AM.getResult(C, CG).getManager(); - FunctionAnalysisManager &FAM = - AM.getResult(C, CG).getManager(); + // Note: The proper way to get to a module pass from a CGSCC pass is + // through the ModuleAnalysisManagerCGSCCProxy: + // ``` + // const auto &MAMProxy = + // AM.getResult(C, CG); + // ``` + // However getting a stateful analysis is incorrect usage, and the call + // to getCachedResult below asserts: + // ``` + // if (TestModuleAnalysis::Result *TMA = + // MAMProxy.getCachedResult( + // *C.begin()->getFunction().getParent())) + // AnalyzedModuleFunctionCount1 += TMA->FunctionCount; + // ``` + // For the purposes of this unittest, use the above MAM directly. if (TestModuleAnalysis::Result *TMA = MAM.getCachedResult( *C.begin()->getFunction().getParent())) AnalyzedModuleFunctionCount1 += TMA->FunctionCount; + FunctionAnalysisManager &FAM = + AM.getResult(C, CG).getManager(); TestSCCAnalysis::Result &AR = AM.getResult(C, CG); AnalyzedSCCFunctionCount1 += AR.FunctionCount; for (LazyCallGraph::Node &N : C) { @@ -374,19 +387,18 @@ // required module pass above. CGSCCPassManager CGPM1(/*DebugLogging*/ true); int CountFoundModuleAnalysis1 = 0; - CGPM1.addPass( - LambdaSCCPass([&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, - LazyCallGraph &CG, CGSCCUpdateResult &UR) { - const auto &MAM = - AM.getResult(C, CG).getManager(); - auto *TMA = MAM.getCachedResult( - *C.begin()->getFunction().getParent()); + CGPM1.addPass(LambdaSCCPass([&](LazyCallGraph::SCC &C, + CGSCCAnalysisManager &AM, LazyCallGraph &CG, + CGSCCUpdateResult &UR) { + const auto &MAMProxy = AM.getResult(C, CG); + bool TMA = MAMProxy.cachedResultExists( + *C.begin()->getFunction().getParent()); - if (TMA) - ++CountFoundModuleAnalysis1; + if (TMA) + ++CountFoundModuleAnalysis1; - return PreservedAnalyses::all(); - })); + return PreservedAnalyses::all(); + })); MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM1))); // The second CGSCC run checks that the module analysis got preserved the @@ -396,9 +408,9 @@ CGPM2.addPass( LambdaSCCPass([&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, LazyCallGraph &CG, CGSCCUpdateResult &UR) { - const auto &MAM = - AM.getResult(C, CG).getManager(); - auto *TMA = MAM.getCachedResult( + const auto &MAMProxy = + AM.getResult(C, CG); + bool TMA = MAMProxy.cachedResultExists( *C.begin()->getFunction().getParent()); if (TMA) @@ -415,19 +427,18 @@ // should have been invalidated by the above CGSCC run. CGSCCPassManager CGPM3(/*DebugLogging*/ true); int CountFoundModuleAnalysis3 = 0; - CGPM3.addPass( - LambdaSCCPass([&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, - LazyCallGraph &CG, CGSCCUpdateResult &UR) { - const auto &MAM = - AM.getResult(C, CG).getManager(); - auto *TMA = MAM.getCachedResult( - *C.begin()->getFunction().getParent()); + CGPM3.addPass(LambdaSCCPass([&](LazyCallGraph::SCC &C, + CGSCCAnalysisManager &AM, LazyCallGraph &CG, + CGSCCUpdateResult &UR) { + const auto &MAMProxy = AM.getResult(C, CG); + bool TMA = MAMProxy.cachedResultExists( + *C.begin()->getFunction().getParent()); - if (TMA) - ++CountFoundModuleAnalysis3; + if (TMA) + ++CountFoundModuleAnalysis3; - return PreservedAnalyses::none(); - })); + return PreservedAnalyses::none(); + })); MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM3))); MPM.run(*M, MAM); @@ -454,17 +465,16 @@ // Start true and mark false if we ever failed to find a module analysis // because we expect this to succeed for each SCC. bool FoundModuleAnalysis1 = true; - FPM1.addPass( - LambdaFunctionPass([&](Function &F, FunctionAnalysisManager &AM) { - const auto &MAM = - AM.getResult(F).getManager(); - auto *TMA = MAM.getCachedResult(*F.getParent()); + FPM1.addPass(LambdaFunctionPass([&](Function &F, + FunctionAnalysisManager &AM) { + const auto &MAMProxy = AM.getResult(F); + bool TMA = MAMProxy.cachedResultExists(*F.getParent()); - if (!TMA) - FoundModuleAnalysis1 = false; + if (!TMA) + FoundModuleAnalysis1 = false; - return PreservedAnalyses::all(); - })); + return PreservedAnalyses::all(); + })); CGSCCPassManager CGPM1(/*DebugLogging*/ true); CGPM1.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM1))); MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM1))); @@ -475,20 +485,19 @@ // Again, start true and mark false if we ever failed to find a module analysis // because we expect this to succeed for each SCC. bool FoundModuleAnalysis2 = true; - FPM2.addPass( - LambdaFunctionPass([&](Function &F, FunctionAnalysisManager &AM) { - const auto &MAM = - AM.getResult(F).getManager(); - auto *TMA = MAM.getCachedResult(*F.getParent()); - - if (!TMA) - FoundModuleAnalysis2 = false; - - // Only fail to preserve analyses on one SCC and make sure that gets - // propagated. - return F.getName() == "h2" ? PreservedAnalyses::none() - : PreservedAnalyses::all(); - })); + FPM2.addPass(LambdaFunctionPass([&](Function &F, + FunctionAnalysisManager &AM) { + const auto &MAMProxy = AM.getResult(F); + bool TMA = MAMProxy.cachedResultExists(*F.getParent()); + + if (!TMA) + FoundModuleAnalysis2 = false; + + // Only fail to preserve analyses on one SCC and make sure that gets + // propagated. + return F.getName() == "h2" ? PreservedAnalyses::none() + : PreservedAnalyses::all(); + })); CGSCCPassManager CGPM2(/*DebugLogging*/ true); CGPM2.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM2))); MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM2))); @@ -499,17 +508,16 @@ // Start false and mark true if we ever *succeeded* to find a module // analysis, as we expect this to fail for every function. bool FoundModuleAnalysis3 = false; - FPM3.addPass( - LambdaFunctionPass([&](Function &F, FunctionAnalysisManager &AM) { - const auto &MAM = - AM.getResult(F).getManager(); - auto *TMA = MAM.getCachedResult(*F.getParent()); + FPM3.addPass(LambdaFunctionPass([&](Function &F, + FunctionAnalysisManager &AM) { + const auto &MAMProxy = AM.getResult(F); + bool TMA = MAMProxy.cachedResultExists(*F.getParent()); - if (TMA) - FoundModuleAnalysis3 = true; + if (TMA) + FoundModuleAnalysis3 = true; - return PreservedAnalyses::none(); - })); + return PreservedAnalyses::none(); + })); CGSCCPassManager CGPM3(/*DebugLogging*/ true); CGPM3.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM3))); MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM3))); @@ -878,7 +886,8 @@ } }; - TestIndirectSCCAnalysis(int &Runs) : Runs(Runs) {} + TestIndirectSCCAnalysis(int &Runs, ModuleAnalysisManager &MAM) + : Runs(Runs), MAM(MAM) {} /// Run the analysis pass over the function and return a result. Result run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, @@ -887,9 +896,11 @@ auto &SCCDep = AM.getResult(C, CG); auto &ModuleProxy = AM.getResult(C, CG); - const ModuleAnalysisManager &MAM = ModuleProxy.getManager(); // For the test, we insist that the module analysis starts off in the - // cache. + // cache. Getting a cached result that isn't stateless triggers an assert. + // auto &MDep = *ModuleProxy.getCachedResult( + // *C.begin()->getFunction().getParent()); + // Use MAM, for the purposes of this unittest. auto &MDep = *MAM.getCachedResult( *C.begin()->getFunction().getParent()); // Register the dependency as module analysis dependencies have to be @@ -905,6 +916,7 @@ static AnalysisKey Key; int &Runs; + ModuleAnalysisManager &MAM; }; AnalysisKey TestIndirectSCCAnalysis::Key; @@ -972,7 +984,9 @@ } }; - TestIndirectFunctionAnalysis(int &Runs) : Runs(Runs) {} + TestIndirectFunctionAnalysis(int &Runs, ModuleAnalysisManager &MAM, + CGSCCAnalysisManager &CGAM) + : Runs(Runs), MAM(MAM), CGAM(CGAM) {} /// Run the analysis pass over the function and return a result. Result run(Function &F, FunctionAnalysisManager &AM) { @@ -980,21 +994,23 @@ auto &FDep = AM.getResult(F); auto &ModuleProxy = AM.getResult(F); - const ModuleAnalysisManager &MAM = ModuleProxy.getManager(); // For the test, we insist that the module analysis starts off in the - // cache. + // cache. Getting a cached result that isn't stateless triggers an assert. + // Use MAM, for the purposes of this unittest. auto &MDep = *MAM.getCachedResult(*F.getParent()); // Register the dependency as module analysis dependencies have to be // pre-registered on the proxy. ModuleProxy.registerOuterAnalysisInvalidation< TestModuleAnalysis, TestIndirectFunctionAnalysis>(); - // For thet test we assume this is run inside a CGSCC pass manager. + // For the test we assume this is run inside a CGSCC pass manager. + // Use MAM, for the purposes of this unittest. const LazyCallGraph &CG = *MAM.getCachedResult(*F.getParent()); auto &CGSCCProxy = AM.getResult(F); - const CGSCCAnalysisManager &CGAM = CGSCCProxy.getManager(); // For the test, we insist that the CGSCC analysis starts off in the cache. + // Getting a cached result that isn't stateless triggers an assert. + // Use CGAM, for the purposes of this unittest. auto &SCCDep = *CGAM.getCachedResult(*CG.lookupSCC(*CG.lookup(F))); // Register the dependency as CGSCC analysis dependencies have to be @@ -1010,6 +1026,8 @@ static AnalysisKey Key; int &Runs; + ModuleAnalysisManager &MAM; + CGSCCAnalysisManager &CGAM; }; AnalysisKey TestIndirectFunctionAnalysis::Key; @@ -1022,7 +1040,7 @@ DoublyIndirectSCCAnalysisRuns = 0; CGAM.registerPass([&] { return TestSCCAnalysis(SCCAnalysisRuns); }); CGAM.registerPass( - [&] { return TestIndirectSCCAnalysis(IndirectSCCAnalysisRuns); }); + [&] { return TestIndirectSCCAnalysis(IndirectSCCAnalysisRuns, MAM); }); CGAM.registerPass([&] { return TestDoublyIndirectSCCAnalysis(DoublyIndirectSCCAnalysisRuns); }); @@ -1030,7 +1048,8 @@ int FunctionAnalysisRuns = 0, IndirectFunctionAnalysisRuns = 0; FAM.registerPass([&] { return TestFunctionAnalysis(FunctionAnalysisRuns); }); FAM.registerPass([&] { - return TestIndirectFunctionAnalysis(IndirectFunctionAnalysisRuns); + return TestIndirectFunctionAnalysis(IndirectFunctionAnalysisRuns, MAM, + CGAM); }); ModulePassManager MPM(/*DebugLogging*/ true); @@ -1140,7 +1159,7 @@ DoublyIndirectSCCAnalysisRuns = 0; CGAM.registerPass([&] { return TestSCCAnalysis(SCCAnalysisRuns); }); CGAM.registerPass( - [&] { return TestIndirectSCCAnalysis(IndirectSCCAnalysisRuns); }); + [&] { return TestIndirectSCCAnalysis(IndirectSCCAnalysisRuns, MAM); }); CGAM.registerPass([&] { return TestDoublyIndirectSCCAnalysis(DoublyIndirectSCCAnalysisRuns); }); @@ -1148,7 +1167,8 @@ int FunctionAnalysisRuns = 0, IndirectFunctionAnalysisRuns = 0; FAM.registerPass([&] { return TestFunctionAnalysis(FunctionAnalysisRuns); }); FAM.registerPass([&] { - return TestIndirectFunctionAnalysis(IndirectFunctionAnalysisRuns); + return TestIndirectFunctionAnalysis(IndirectFunctionAnalysisRuns, MAM, + CGAM); }); ModulePassManager MPM(/*DebugLogging*/ true); diff --git a/llvm/unittests/IR/PassManagerTest.cpp b/llvm/unittests/IR/PassManagerTest.cpp --- a/llvm/unittests/IR/PassManagerTest.cpp +++ b/llvm/unittests/IR/PassManagerTest.cpp @@ -106,20 +106,23 @@ struct TestFunctionPass : PassInfoMixin { TestFunctionPass(int &RunCount, int &AnalyzedInstrCount, - int &AnalyzedFunctionCount, + int &AnalyzedFunctionCount, ModuleAnalysisManager &MAM, bool OnlyUseCachedResults = false) : RunCount(RunCount), AnalyzedInstrCount(AnalyzedInstrCount), - AnalyzedFunctionCount(AnalyzedFunctionCount), + AnalyzedFunctionCount(AnalyzedFunctionCount), MAM(MAM), OnlyUseCachedResults(OnlyUseCachedResults) {} PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM) { ++RunCount; - const ModuleAnalysisManager &MAM = - AM.getResult(F).getManager(); + // Getting a cached result that isn't stateless through the proxy will + // trigger an assert: + // auto &ModuleProxy = AM.getResult(F); + // Use MAM, for the purposes of this unittest. if (TestModuleAnalysis::Result *TMA = - MAM.getCachedResult(*F.getParent())) + MAM.getCachedResult(*F.getParent())) { AnalyzedFunctionCount += TMA->FunctionCount; + } if (OnlyUseCachedResults) { // Hack to force the use of the cached interface. @@ -138,6 +141,7 @@ int &RunCount; int &AnalyzedInstrCount; int &AnalyzedFunctionCount; + ModuleAnalysisManager &MAM; bool OnlyUseCachedResults; }; @@ -435,8 +439,9 @@ { // Pointless scope to test move assignment. FunctionPassManager NestedFPM(/*DebugLogging*/ true); - NestedFPM.addPass(TestFunctionPass( - FunctionPassRunCount1, AnalyzedInstrCount1, AnalyzedFunctionCount1)); + NestedFPM.addPass(TestFunctionPass(FunctionPassRunCount1, + AnalyzedInstrCount1, + AnalyzedFunctionCount1, MAM)); FPM = std::move(NestedFPM); } NestedMPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); @@ -454,7 +459,7 @@ { FunctionPassManager FPM(/*DebugLogging*/ true); FPM.addPass(TestFunctionPass(FunctionPassRunCount2, AnalyzedInstrCount2, - AnalyzedFunctionCount2)); + AnalyzedFunctionCount2, MAM)); MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); } @@ -467,7 +472,7 @@ { FunctionPassManager FPM(/*DebugLogging*/ true); FPM.addPass(TestFunctionPass(FunctionPassRunCount3, AnalyzedInstrCount3, - AnalyzedFunctionCount3)); + AnalyzedFunctionCount3, MAM)); FPM.addPass(TestInvalidationFunctionPass("f")); MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); } @@ -481,7 +486,7 @@ { FunctionPassManager FPM; FPM.addPass(TestFunctionPass(FunctionPassRunCount4, AnalyzedInstrCount4, - AnalyzedFunctionCount4)); + AnalyzedFunctionCount4, MAM)); MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); } @@ -494,7 +499,7 @@ FunctionPassManager FPM(/*DebugLogging*/ true); FPM.addPass(TestInvalidationFunctionPass("f")); FPM.addPass(TestFunctionPass(FunctionPassRunCount5, AnalyzedInstrCount5, - AnalyzedFunctionCount5, + AnalyzedFunctionCount5, MAM, /*OnlyUseCachedResults=*/true)); MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); } @@ -611,21 +616,22 @@ } }; - TestIndirectFunctionAnalysis(int &Runs) : Runs(Runs) {} + TestIndirectFunctionAnalysis(int &Runs, ModuleAnalysisManager &MAM) + : Runs(Runs), MAM(MAM) {} /// Run the analysis pass over the function and return a result. Result run(Function &F, FunctionAnalysisManager &AM) { ++Runs; auto &FDep = AM.getResult(F); - auto &Proxy = AM.getResult(F); - const ModuleAnalysisManager &MAM = Proxy.getManager(); + auto &MAMProxy = AM.getResult(F); // For the test, we insist that the module analysis starts off in the - // cache. + // cache. Getting a cached result that isn't stateless trigger an assert. + // Use MAM, for the purposes of this unittest. auto &MDep = *MAM.getCachedResult(*F.getParent()); // And register the dependency as module analysis dependencies have to be // pre-registered on the proxy. - Proxy.registerOuterAnalysisInvalidation(); + MAMProxy.registerOuterAnalysisInvalidation(); return Result(FDep, MDep); } @@ -634,6 +640,7 @@ static AnalysisKey Key; int &Runs; + ModuleAnalysisManager &MAM; }; AnalysisKey TestIndirectFunctionAnalysis::Key; @@ -692,16 +699,16 @@ TEST_F(PassManagerTest, IndirectAnalysisInvalidation) { FunctionAnalysisManager FAM(/*DebugLogging*/ true); + ModuleAnalysisManager MAM(/*DebugLogging*/ true); int FunctionAnalysisRuns = 0, ModuleAnalysisRuns = 0, IndirectAnalysisRuns = 0, DoublyIndirectAnalysisRuns = 0; FAM.registerPass([&] { return TestFunctionAnalysis(FunctionAnalysisRuns); }); FAM.registerPass( - [&] { return TestIndirectFunctionAnalysis(IndirectAnalysisRuns); }); + [&] { return TestIndirectFunctionAnalysis(IndirectAnalysisRuns, MAM); }); FAM.registerPass([&] { return TestDoublyIndirectFunctionAnalysis(DoublyIndirectAnalysisRuns); }); - ModuleAnalysisManager MAM(/*DebugLogging*/ true); MAM.registerPass([&] { return TestModuleAnalysis(ModuleAnalysisRuns); }); MAM.registerPass([&] { return FunctionAnalysisManagerModuleProxy(FAM); }); FAM.registerPass([&] { return ModuleAnalysisManagerFunctionProxy(MAM); }); diff --git a/llvm/unittests/Transforms/Scalar/LoopPassManagerTest.cpp b/llvm/unittests/Transforms/Scalar/LoopPassManagerTest.cpp --- a/llvm/unittests/Transforms/Scalar/LoopPassManagerTest.cpp +++ b/llvm/unittests/Transforms/Scalar/LoopPassManagerTest.cpp @@ -779,9 +779,11 @@ .WillByDefault(Invoke([&](Loop &L, LoopAnalysisManager &AM, LoopStandardAnalysisResults &AR) { auto &FAMP = AM.getResult(L, AR); - auto &FAM = FAMP.getManager(); Function &F = *L.getHeader()->getParent(); - if (FAM.getCachedResult(F)) + // This call will assert when trying to get the actual analysis if the + // FunctionAnalysis can be invalidated. Only check its existence. + // Alternatively, use FAM above, for the purposes of this unittest. + if (FAMP.cachedResultExists(F)) FAMP.registerOuterAnalysisInvalidation(); return MLAHandle.getResult();