diff --git a/clang/test/CodeGen/thinlto-distributed-newpm.ll b/clang/test/CodeGen/thinlto-distributed-newpm.ll --- a/clang/test/CodeGen/thinlto-distributed-newpm.ll +++ b/clang/test/CodeGen/thinlto-distributed-newpm.ll @@ -85,10 +85,7 @@ ; CHECK-O: Running pass: PostOrderFunctionAttrsPass on (main) ; CHECK-O: Invalidating all non-preserved analyses for: (main) ; CHECK-O: Clearing all analysis results for: main -; CHECK-O: Invalidating analysis: FunctionAnalysisManagerCGSCCProxy on (main) ; CHECK-O3: Running pass: ArgumentPromotionPass on (main) -; CHECK-O2: Running pass: CGSCCToFunctionPassAdaptor<{{.*}}PassManager{{.*}}> -; CHECK-O: Running analysis: FunctionAnalysisManagerCGSCCProxy on (main) ; CHECK-O3: Running analysis: TargetIRAnalysis on main ; CHECK-O: Running analysis: PassInstrumentationAnalysis on main ; CHECK-O3: Running pass: CGSCCToFunctionPassAdaptor<{{.*}}PassManager{{.*}}> 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 @@ -1185,8 +1185,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/Analysis/CGSCCPassManager.h b/llvm/include/llvm/Analysis/CGSCCPassManager.h --- a/llvm/include/llvm/Analysis/CGSCCPassManager.h +++ b/llvm/include/llvm/Analysis/CGSCCPassManager.h @@ -380,10 +380,15 @@ public: class Result { public: + explicit Result() : FAM(nullptr) {} explicit Result(FunctionAnalysisManager &FAM) : FAM(&FAM) {} + void updateFAM(FunctionAnalysisManager &FAM) { this->FAM = &FAM; } /// Accessor for the analysis manager. - FunctionAnalysisManager &getManager() { return *FAM; } + FunctionAnalysisManager &getManager() { + assert(FAM); + return *FAM; + } bool invalidate(LazyCallGraph::SCC &C, const PreservedAnalyses &PA, CGSCCAnalysisManager::Invalidator &Inv); @@ -415,7 +420,8 @@ /// update result struct for the overall CGSCC walk. LazyCallGraph::SCC &updateCGAndAnalysisManagerForFunctionPass( LazyCallGraph &G, LazyCallGraph::SCC &C, LazyCallGraph::Node &N, - CGSCCAnalysisManager &AM, CGSCCUpdateResult &UR); + CGSCCAnalysisManager &AM, CGSCCUpdateResult &UR, + FunctionAnalysisManager &FAM); /// Helper to update the call graph after running a CGSCC pass. /// @@ -425,7 +431,8 @@ /// update result struct for the overall CGSCC walk. LazyCallGraph::SCC &updateCGAndAnalysisManagerForCGSCCPass( LazyCallGraph &G, LazyCallGraph::SCC &C, LazyCallGraph::Node &N, - CGSCCAnalysisManager &AM, CGSCCUpdateResult &UR); + CGSCCAnalysisManager &AM, CGSCCUpdateResult &UR, + FunctionAnalysisManager &FAM); /// Adaptor that maps from a SCC to its functions. /// @@ -516,7 +523,7 @@ auto PAC = PA.getChecker(); if (!PAC.preserved() && !PAC.preservedSet>()) { CurrentC = &updateCGAndAnalysisManagerForFunctionPass(CG, *CurrentC, *N, - AM, UR); + AM, UR, FAM); assert( CG.lookupSCC(*N) == CurrentC && "Current SCC not updated to the SCC containing the current node!"); @@ -719,6 +726,7 @@ // Update the analysis manager with each run and intersect the total set // of preserved analyses so we're ready to iterate. AM.invalidate(*C, PassPA); + PA.intersect(std::move(PassPA)); } @@ -754,6 +762,10 @@ // Get the call graph for this module. LazyCallGraph &CG = AM.getResult(M); + // Get Function analysis manager from its proxy. + FunctionAnalysisManager &FAM = + AM.getCachedResult(M)->getManager(); + // We keep worklists to allow us to push more work onto the pass manager as // the passes are run. SmallPriorityWorklist RCWorklist; @@ -829,11 +841,12 @@ continue; } - // Ensure we can proxy analysis updates from from the CGSCC analysis - // manager into the Function analysis manager by getting a proxy here. - // FIXME: This seems like a bit of a hack. We should find a cleaner - // or more costructive way to ensure this happens. - (void)CGAM.getResult(*C, CG); + // Ensure we can proxy analysis updates from the CGSCC analysis manager + // into the the Function analysis manager by getting a proxy here. + // This also needs to update the FunctionAnalysisManager, as this may be + // the first time we see this SCC. + CGAM.getResult(*C, CG).updateFAM( + FAM); // Each time we visit a new SCC pulled off the worklist, // a transformation of a child SCC may have also modified this parent @@ -888,6 +901,13 @@ C = UR.UpdatedC ? UR.UpdatedC : C; RC = UR.UpdatedRC ? UR.UpdatedRC : RC; + if (UR.UpdatedC) { + // If we're updating the SCC, also update the FAM inside the proxy's + // result. + CGAM.getResult(*C, CG).updateFAM( + FAM); + } + // If the CGSCC pass wasn't able to provide a valid updated SCC, // the current SCC may simply need to be skipped if invalid. if (UR.InvalidatedSCCs.count(C)) { 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 @@ -799,6 +799,16 @@ return &static_cast(ResultConcept)->Result; } + /// Verify that the given Result cannot be invalidated, assert otherwise. + template + void verifyNotInvalidated(IRUnitT &IR, typename PassT::Result *Result) const { + PreservedAnalyses PA = PreservedAnalyses::none(); + SmallDenseMap IsResultInvalidated; + Invalidator Inv(IsResultInvalidated, AnalysisResults); + assert(!Result->invalidate(IR, PA, Inv) && + "Cached result cannot be invalidated"); + } + /// Register an analysis pass with the manager. /// /// The parameter is a callable whose result is an analysis pass. This allows @@ -1064,7 +1074,24 @@ 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); + if (Res) + OuterAM->template verifyNotInvalidated(IR, Res); + 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( diff --git a/llvm/include/llvm/Transforms/Utils/CallGraphUpdater.h b/llvm/include/llvm/Transforms/Utils/CallGraphUpdater.h --- a/llvm/include/llvm/Transforms/Utils/CallGraphUpdater.h +++ b/llvm/include/llvm/Transforms/Utils/CallGraphUpdater.h @@ -49,6 +49,7 @@ LazyCallGraph::SCC *SCC = nullptr; CGSCCAnalysisManager *AM = nullptr; CGSCCUpdateResult *UR = nullptr; + FunctionAnalysisManager *FAM = nullptr; ///} public: @@ -68,6 +69,8 @@ this->SCC = &SCC; this->AM = &AM; this->UR = &UR; + FAM = + &AM.getResult(SCC, LCG).getManager(); } ///} 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 @@ -68,6 +68,10 @@ // a pointer that we can update. LazyCallGraph::SCC *C = &InitialC; + // Get Function analysis manager from its proxy. + FunctionAnalysisManager &FAM = + AM.getCachedResult(*C)->getManager(); + for (auto &Pass : Passes) { if (DebugLogging) dbgs() << "Running pass: " << Pass->name() << " on " << *C << "\n"; @@ -90,6 +94,12 @@ // Update the SCC if necessary. C = UR.UpdatedC ? UR.UpdatedC : C; + if (UR.UpdatedC) { + // If C is updated, also create a proxy and update FAM inside the result. + auto *ResultFAMCP = + &AM.getResult(*C, G); + ResultFAMCP->updateFAM(FAM); + } // If the CGSCC pass wasn't able to provide a valid updated SCC, the // current SCC may simply need to be skipped if invalid. @@ -223,23 +233,22 @@ FunctionAnalysisManagerCGSCCProxy::run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, LazyCallGraph &CG) { - // Collect the FunctionAnalysisManager from the Module layer and use that to - // build the proxy result. - // - // This allows us to rely on the FunctionAnalysisMangaerModuleProxy to - // invalidate the function analyses. - auto &MAM = AM.getResult(C, CG).getManager(); + // Note: unconditionally getting checking that the proxy exists may get it at + // this point. There are cases when this is being run unnecessarily, but + // it is cheap and having the assertion in place is more valuable. + auto &MAMProxy = AM.getResult(C, CG); Module &M = *C.begin()->getFunction().getParent(); - auto *FAMProxy = MAM.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."); - - // Note that we special-case invalidation handling of this proxy in the CGSCC - // analysis manager's Module proxy. This avoids the need to do anything - // special here to recompute all of this if ever the FAM's module proxy goes - // away. - return Result(FAMProxy->getManager()); + bool ProxyExists = + MAMProxy.cachedResultExists(M); + assert(ProxyExists && + "The CGSCC pass manager requires that the FAM module proxy is run " + "on the module prior to entering the CGSCC walk"); + (void)ProxyExists; + + // We just return an empty result. The caller will use the updateFAM interface + // to correctly register the relevant FunctionAnalysisManager based on the + // context in which this proxy is run. + return Result(); } bool FunctionAnalysisManagerCGSCCProxy::Result::invalidate( @@ -249,8 +258,8 @@ if (PA.areAllPreserved()) return false; // This is still a valid proxy. - // If this proxy isn't marked as preserved, then even if the result remains - // valid, the key itself may no longer be valid, so we clear everything. + // All updates to preserve valid results are done below, so we don't need to + // invalidate this proxy. // // Note that in order to preserve this proxy, a module pass must ensure that // the FAM has been completely updated to handle the deletion of functions. @@ -262,7 +271,7 @@ for (LazyCallGraph::Node &N : C) FAM->clear(N.getFunction(), N.getFunction().getName()); - return true; + return false; } // Directly check if the relevant set is preserved. @@ -311,9 +320,10 @@ } // end namespace llvm -/// When a new SCC is created for the graph and there might be function -/// analysis results cached for the functions now in that SCC two forms of -/// updates are required. +/// When a new SCC is created for the graph we first update the +/// FunctionAnalysisManager in the Proxy's result. +/// As there might be function analysis results cached for the functions now in +/// that SCC, two forms of updates are required. /// /// First, a proxy from the SCC to the FunctionAnalysisManager needs to be /// created so that any subsequent invalidation events to the SCC are @@ -325,10 +335,9 @@ /// function analyses so that they don't retain stale handles. static void updateNewSCCFunctionAnalyses(LazyCallGraph::SCC &C, LazyCallGraph &G, - CGSCCAnalysisManager &AM) { - // Get the relevant function analysis manager. - auto &FAM = - AM.getResult(C, G).getManager(); + CGSCCAnalysisManager &AM, + FunctionAnalysisManager &FAM) { + AM.getResult(C, G).updateFAM(FAM); // Now walk the functions in this SCC and invalidate any function analysis // results that might have outer dependencies on an SCC analysis. @@ -392,8 +401,10 @@ // If we had a cached FAM proxy originally, we will want to create more of // them for each SCC that was split off. - bool NeedFAMProxy = - AM.getCachedResult(*OldC) != nullptr; + FunctionAnalysisManager *FAM = nullptr; + if (auto *FAMProxy = + AM.getCachedResult(*OldC)) + FAM = &FAMProxy->getManager(); // We need to propagate an invalidation call to all but the newly current SCC // because the outer pass manager won't do that for us after splitting them. @@ -407,8 +418,8 @@ AM.invalidate(*OldC, PA); // Ensure the now-current SCC's function analyses are updated. - if (NeedFAMProxy) - updateNewSCCFunctionAnalyses(*C, G, AM); + if (FAM) + updateNewSCCFunctionAnalyses(*C, G, AM, *FAM); for (SCC &NewC : llvm::reverse(make_range(std::next(NewSCCRange.begin()), NewSCCRange.end()))) { @@ -418,8 +429,8 @@ LLVM_DEBUG(dbgs() << "Enqueuing a newly formed SCC:" << NewC << "\n"); // Ensure new SCCs' function analyses are updated. - if (NeedFAMProxy) - updateNewSCCFunctionAnalyses(NewC, G, AM); + if (FAM) + updateNewSCCFunctionAnalyses(NewC, G, AM, *FAM); // Also propagate a normal invalidation to the new SCC as only the current // will get one from the pass manager infrastructure. @@ -430,7 +441,8 @@ static LazyCallGraph::SCC &updateCGAndAnalysisManagerForPass( LazyCallGraph &G, LazyCallGraph::SCC &InitialC, LazyCallGraph::Node &N, - CGSCCAnalysisManager &AM, CGSCCUpdateResult &UR, bool FunctionPass) { + CGSCCAnalysisManager &AM, CGSCCUpdateResult &UR, + FunctionAnalysisManager &FAM, bool FunctionPass) { using Node = LazyCallGraph::Node; using Edge = LazyCallGraph::Edge; using SCC = LazyCallGraph::SCC; @@ -686,7 +698,7 @@ // analysis manager, we need to create a proxy in the new current SCC as // the invalidated SCCs had their functions moved. if (HasFunctionAnalysisProxy) - AM.getResult(*C, G); + AM.getResult(*C, G).updateFAM(FAM); // Any analyses cached for this SCC are no longer precise as the shape // has changed by introducing this cycle. However, we have taken care to @@ -738,13 +750,15 @@ LazyCallGraph::SCC &llvm::updateCGAndAnalysisManagerForFunctionPass( LazyCallGraph &G, LazyCallGraph::SCC &InitialC, LazyCallGraph::Node &N, - CGSCCAnalysisManager &AM, CGSCCUpdateResult &UR) { - return updateCGAndAnalysisManagerForPass(G, InitialC, N, AM, UR, + CGSCCAnalysisManager &AM, CGSCCUpdateResult &UR, + FunctionAnalysisManager &FAM) { + return updateCGAndAnalysisManagerForPass(G, InitialC, N, AM, UR, FAM, /* FunctionPass */ true); } LazyCallGraph::SCC &llvm::updateCGAndAnalysisManagerForCGSCCPass( LazyCallGraph &G, LazyCallGraph::SCC &InitialC, LazyCallGraph::Node &N, - CGSCCAnalysisManager &AM, CGSCCUpdateResult &UR) { - return updateCGAndAnalysisManagerForPass(G, InitialC, N, AM, UR, + CGSCCAnalysisManager &AM, CGSCCUpdateResult &UR, + FunctionAnalysisManager &FAM) { + return updateCGAndAnalysisManagerForPass(G, InitialC, N, AM, UR, FAM, /* FunctionPass */ false); } diff --git a/llvm/lib/Transforms/Coroutines/CoroSplit.cpp b/llvm/lib/Transforms/Coroutines/CoroSplit.cpp --- a/llvm/lib/Transforms/Coroutines/CoroSplit.cpp +++ b/llvm/lib/Transforms/Coroutines/CoroSplit.cpp @@ -1470,7 +1470,8 @@ static void updateCallGraphAfterCoroutineSplit( LazyCallGraph::Node &N, const coro::Shape &Shape, const SmallVectorImpl &Clones, LazyCallGraph::SCC &C, - LazyCallGraph &CG, CGSCCAnalysisManager &AM, CGSCCUpdateResult &UR) { + LazyCallGraph &CG, CGSCCAnalysisManager &AM, CGSCCUpdateResult &UR, + FunctionAnalysisManager &FAM) { if (!Shape.CoroBegin) return; @@ -1501,7 +1502,7 @@ // update of its own. Function passes run by the adaptor are not permitted to // add new edges of any kind to the graph, and the new edges inserted by this // pass would be misattributed to that unrelated function pass. - updateCGAndAnalysisManagerForCGSCCPass(CG, C, N, AM, UR); + updateCGAndAnalysisManagerForCGSCCPass(CG, C, N, AM, UR, FAM); } // When we see the coroutine the first time, we insert an indirect call to a @@ -1647,6 +1648,9 @@ // non-zero number of nodes, so we assume that here and grab the first // node's function's module. Module &M = *C.begin()->getFunction().getParent(); + auto &FAM = + AM.getResult(C, CG).getManager(); + if (!declaresCoroSplitIntrinsics(M)) return PreservedAnalyses::all(); @@ -1695,7 +1699,7 @@ SmallVector Clones; const coro::Shape Shape = splitCoroutine(F, Clones); - updateCallGraphAfterCoroutineSplit(*N, Shape, Clones, C, CG, AM, UR); + updateCallGraphAfterCoroutineSplit(*N, Shape, Clones, C, CG, AM, UR, FAM); } if (PrepareFn) 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 @@ -667,13 +667,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) { @@ -779,16 +779,6 @@ LLVM_DEBUG(dbgs() << "Inlining calls in: " << F.getName() << "\n"); - // Get a FunctionAnalysisManager via a proxy for this particular node. We - // do this each time we visit a node as the SCC may have changed and as - // we're going to mutate this particular function we want to make sure the - // proxy is in place to forward any invalidation events. We can use the - // manager we get here for looking up results for functions other than this - // node however because those functions aren't going to be mutated by this - // pass. - FunctionAnalysisManager &FAM = - AM.getResult(*C, CG).getManager(); - // Get the remarks emission analysis for the caller. auto &ORE = FAM.getResult(F); @@ -968,8 +958,13 @@ // essentially do all of the same things as a function pass and we can // re-use the exact same logic for updating the call graph to reflect the // change. + + // Inside the update, we also update the FunctionAnalysisManager in the + // proxy for this particular SCC. We do this as the SCC may have changed and + // as we're going to mutate this particular function we want to make sure + // the proxy is in place to forward any invalidation events. LazyCallGraph::SCC *OldC = C; - C = &updateCGAndAnalysisManagerForFunctionPass(CG, *C, N, AM, UR); + C = &updateCGAndAnalysisManagerForFunctionPass(CG, *C, N, AM, UR, FAM); LLVM_DEBUG(dbgs() << "Updated inlining SCC: " << *C << "\n"); RC = &C->getOuterRefSCC(); @@ -1015,8 +1010,6 @@ // Get the necessary information out of the call graph and nuke the // function there. Also, cclear out any cached analyses. auto &DeadC = *CG.lookupSCC(*CG.lookup(*DeadF)); - FunctionAnalysisManager &FAM = - AM.getResult(DeadC, CG).getManager(); FAM.clear(*DeadF, DeadF->getName()); AM.clear(DeadC, DeadC.getName()); auto &DeadRC = DeadC.getOuterRefSCC(); 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 @@ -3723,10 +3723,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 @@ -1170,9 +1170,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 @@ -2093,8 +2093,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 @@ -979,8 +979,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 @@ -696,8 +696,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 @@ -1409,10 +1409,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/Utils/CallGraphUpdater.cpp b/llvm/lib/Transforms/Utils/CallGraphUpdater.cpp --- a/llvm/lib/Transforms/Utils/CallGraphUpdater.cpp +++ b/llvm/lib/Transforms/Utils/CallGraphUpdater.cpp @@ -92,7 +92,7 @@ } else if (LCG) { LazyCallGraph::Node &N = LCG->get(Fn); LazyCallGraph::SCC *C = LCG->lookupSCC(N); - updateCGAndAnalysisManagerForCGSCCPass(*LCG, *C, N, *AM, *UR); + updateCGAndAnalysisManagerForCGSCCPass(*LCG, *C, N, *AM, *UR, *FAM); } } 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 @@ -8072,10 +8072,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()); LoopVectorizeResult Result = runImpl(F, SE, LI, TTI, DT, BFI, &TLI, DB, AA, AC, GetLAA, ORE, PSI); if (!Result.MadeAnyChange) 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 @@ -304,15 +304,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) { @@ -376,19 +389,16 @@ // 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()); - - if (TMA) - ++CountFoundModuleAnalysis1; - - return PreservedAnalyses::all(); - })); + CGPM1.addPass(LambdaSCCPass([&](LazyCallGraph::SCC &C, + CGSCCAnalysisManager &AM, LazyCallGraph &CG, + CGSCCUpdateResult &UR) { + const auto &MAMProxy = AM.getResult(C, CG); + if (MAMProxy.cachedResultExists( + *C.begin()->getFunction().getParent())) + ++CountFoundModuleAnalysis1; + + return PreservedAnalyses::all(); + })); MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM1))); // The second CGSCC run checks that the module analysis got preserved the @@ -398,12 +408,10 @@ CGPM2.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()); - - if (TMA) + const auto &MAMProxy = + AM.getResult(C, CG); + if (MAMProxy.cachedResultExists( + *C.begin()->getFunction().getParent())) ++CountFoundModuleAnalysis2; // Only fail to preserve analyses on one SCC and make sure that gets @@ -417,19 +425,16 @@ // 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()); - - if (TMA) - ++CountFoundModuleAnalysis3; + CGPM3.addPass(LambdaSCCPass([&](LazyCallGraph::SCC &C, + CGSCCAnalysisManager &AM, LazyCallGraph &CG, + CGSCCUpdateResult &UR) { + const auto &MAMProxy = AM.getResult(C, CG); + if (MAMProxy.cachedResultExists( + *C.begin()->getFunction().getParent())) + ++CountFoundModuleAnalysis3; - return PreservedAnalyses::none(); - })); + return PreservedAnalyses::none(); + })); MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM3))); MPM.run(*M, MAM); @@ -456,17 +461,14 @@ // 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); + if (!MAMProxy.cachedResultExists(*F.getParent())) + 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))); @@ -477,20 +479,17 @@ // 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); + if (!MAMProxy.cachedResultExists(*F.getParent())) + 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))); @@ -501,17 +500,14 @@ // 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); + if (MAMProxy.cachedResultExists(*F.getParent())) + 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))); @@ -880,7 +876,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, @@ -889,9 +886,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 @@ -907,6 +906,7 @@ static AnalysisKey Key; int &Runs; + ModuleAnalysisManager &MAM; }; AnalysisKey TestIndirectSCCAnalysis::Key; @@ -974,7 +974,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) { @@ -982,21 +984,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 @@ -1012,6 +1016,8 @@ static AnalysisKey Key; int &Runs; + ModuleAnalysisManager &MAM; + CGSCCAnalysisManager &CGAM; }; AnalysisKey TestIndirectFunctionAnalysis::Key; @@ -1024,7 +1030,7 @@ DoublyIndirectSCCAnalysisRuns = 0; CGAM.registerPass([&] { return TestSCCAnalysis(SCCAnalysisRuns); }); CGAM.registerPass( - [&] { return TestIndirectSCCAnalysis(IndirectSCCAnalysisRuns); }); + [&] { return TestIndirectSCCAnalysis(IndirectSCCAnalysisRuns, MAM); }); CGAM.registerPass([&] { return TestDoublyIndirectSCCAnalysis(DoublyIndirectSCCAnalysisRuns); }); @@ -1032,7 +1038,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); @@ -1142,7 +1149,7 @@ DoublyIndirectSCCAnalysisRuns = 0; CGAM.registerPass([&] { return TestSCCAnalysis(SCCAnalysisRuns); }); CGAM.registerPass( - [&] { return TestIndirectSCCAnalysis(IndirectSCCAnalysisRuns); }); + [&] { return TestIndirectSCCAnalysis(IndirectSCCAnalysisRuns, MAM); }); CGAM.registerPass([&] { return TestDoublyIndirectSCCAnalysis(DoublyIndirectSCCAnalysisRuns); }); @@ -1150,7 +1157,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); @@ -1199,7 +1207,7 @@ // Now update the call graph. auto &NewC = - updateCGAndAnalysisManagerForFunctionPass(CG, C, H2N, AM, UR); + updateCGAndAnalysisManagerForFunctionPass(CG, C, H2N, AM, UR, FAM); assert(&NewC != &C && "Should get a new SCC due to update!"); (void)&NewC; @@ -1245,7 +1253,7 @@ // Now update the call graph. auto &NewC = - updateCGAndAnalysisManagerForFunctionPass(CG, C, H2N, AM, UR); + updateCGAndAnalysisManagerForFunctionPass(CG, C, H2N, AM, UR, FAM); assert(&NewC != &C && "Should get a new SCC due to update!"); (void)&NewC; @@ -1337,6 +1345,8 @@ if (C.getName() != "(h3, h1, h2)") return; + auto &FAM = + AM.getResult(C, CG).getManager(); Function *FnX = M->getFunction("x"); Function *FnH1 = M->getFunction("h1"); Function *FnH2 = M->getFunction("h2"); @@ -1355,7 +1365,7 @@ auto &H2N = *llvm::find_if( C, [](LazyCallGraph::Node &N) { return N.getName() == "h2"; }); ASSERT_NO_FATAL_FAILURE( - updateCGAndAnalysisManagerForCGSCCPass(CG, C, H2N, AM, UR)); + updateCGAndAnalysisManagerForCGSCCPass(CG, C, H2N, AM, UR, FAM)); })); ModulePassManager MPM(/*DebugLogging*/ true); @@ -1372,6 +1382,8 @@ if (C.getName() != "(h3, h1, h2)") return; + auto &FAM = + AM.getResult(C, CG).getManager(); Function *FnX = M->getFunction("x"); Function *FnH1 = M->getFunction("h1"); Function *FnH2 = M->getFunction("h2"); @@ -1389,8 +1401,9 @@ auto &H2N = *llvm::find_if( C, [](LazyCallGraph::Node &N) { return N.getName() == "h2"; }); - ASSERT_DEATH(updateCGAndAnalysisManagerForFunctionPass(CG, C, H2N, AM, UR), - "Any new calls should be modeled as"); + ASSERT_DEATH( + updateCGAndAnalysisManagerForFunctionPass(CG, C, H2N, AM, UR, FAM), + "Any new calls should be modeled as"); })); ModulePassManager MPM(/*DebugLogging*/ true); @@ -1406,6 +1419,8 @@ if (C.getName() != "(f)") return; + auto &FAM = + AM.getResult(C, CG).getManager(); Function *FnF = M->getFunction("f"); Function *FnH2 = M->getFunction("h2"); ASSERT_NE(FnF, nullptr); @@ -1418,7 +1433,7 @@ auto &FN = *llvm::find_if( C, [](LazyCallGraph::Node &N) { return N.getName() == "f"; }); ASSERT_NO_FATAL_FAILURE( - updateCGAndAnalysisManagerForCGSCCPass(CG, C, FN, AM, UR)); + updateCGAndAnalysisManagerForCGSCCPass(CG, C, FN, AM, UR, FAM)); })); ModulePassManager MPM(/*DebugLogging*/ true); @@ -1435,6 +1450,8 @@ if (C.getName() != "(f)") return; + auto &FAM = + AM.getResult(C, CG).getManager(); Function *FnF = M->getFunction("f"); Function *FnH2 = M->getFunction("h2"); ASSERT_NE(FnF, nullptr); @@ -1446,8 +1463,9 @@ auto &FN = *llvm::find_if( C, [](LazyCallGraph::Node &N) { return N.getName() == "f"; }); - ASSERT_DEATH(updateCGAndAnalysisManagerForFunctionPass(CG, C, FN, AM, UR), - "Any new calls should be modeled as"); + ASSERT_DEATH( + updateCGAndAnalysisManagerForFunctionPass(CG, C, FN, AM, UR, FAM), + "Any new calls should be modeled as"); })); ModulePassManager MPM(/*DebugLogging*/ true); @@ -1463,6 +1481,8 @@ if (C.getName() != "(f)") return; + auto &FAM = + AM.getResult(C, CG).getManager(); Function *FnF = M->getFunction("f"); Function *FnewF = Function::Create(FnF->getFunctionType(), FnF->getLinkage(), "newF", *M); @@ -1483,7 +1503,7 @@ C, [](LazyCallGraph::Node &N) { return N.getName() == "f"; }); ASSERT_NO_FATAL_FAILURE( - updateCGAndAnalysisManagerForCGSCCPass(CG, C, FN, AM, UR)); + updateCGAndAnalysisManagerForCGSCCPass(CG, C, FN, AM, UR, FAM)); })); ModulePassManager MPM(/*DebugLogging*/ true); @@ -1500,6 +1520,8 @@ if (C.getName() != "(f)") return; + auto &FAM = + AM.getResult(C, CG).getManager(); Function *FnF = M->getFunction("f"); Function *FnewF = Function::Create(FnF->getFunctionType(), FnF->getLinkage(), "newF", *M); @@ -1519,8 +1541,9 @@ auto &FN = *llvm::find_if( C, [](LazyCallGraph::Node &N) { return N.getName() == "f"; }); - ASSERT_DEATH(updateCGAndAnalysisManagerForFunctionPass(CG, C, FN, AM, UR), - "Any new calls should be modeled as"); + ASSERT_DEATH( + updateCGAndAnalysisManagerForFunctionPass(CG, C, FN, AM, UR, FAM), + "Any new calls should be modeled as"); })); ModulePassManager MPM(/*DebugLogging*/ true); @@ -1701,6 +1724,9 @@ CGPM.addPass(LambdaSCCPassNoPreserve( [&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, LazyCallGraph &CG, CGSCCUpdateResult &UR) { + auto &FAM = + AM.getResult(C, CG).getManager(); + for (auto &N : C) { auto &F = N.getFunction(); if (F.getName() != "f") @@ -1728,7 +1754,7 @@ "f.ref", &*F.begin()->begin()); ASSERT_NO_FATAL_FAILURE( - updateCGAndAnalysisManagerForCGSCCPass(CG, C, N, AM, UR)) + updateCGAndAnalysisManagerForCGSCCPass(CG, C, N, AM, UR, FAM)) << "Updating the call graph with a demoted, self-referential " "call edge 'f -> f', and a newly inserted ref edge 'f -> g', " "caused a fatal failure"; 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 @@ -107,20 +107,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. @@ -139,6 +142,7 @@ int &RunCount; int &AnalyzedInstrCount; int &AnalyzedFunctionCount; + ModuleAnalysisManager &MAM; bool OnlyUseCachedResults; }; @@ -436,8 +440,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))); @@ -455,7 +460,7 @@ { FunctionPassManager FPM(/*DebugLogging*/ true); FPM.addPass(TestFunctionPass(FunctionPassRunCount2, AnalyzedInstrCount2, - AnalyzedFunctionCount2)); + AnalyzedFunctionCount2, MAM)); MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); } @@ -468,7 +473,7 @@ { FunctionPassManager FPM(/*DebugLogging*/ true); FPM.addPass(TestFunctionPass(FunctionPassRunCount3, AnalyzedInstrCount3, - AnalyzedFunctionCount3)); + AnalyzedFunctionCount3, MAM)); FPM.addPass(TestInvalidationFunctionPass("f")); MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); } @@ -482,7 +487,7 @@ { FunctionPassManager FPM; FPM.addPass(TestFunctionPass(FunctionPassRunCount4, AnalyzedInstrCount4, - AnalyzedFunctionCount4)); + AnalyzedFunctionCount4, MAM)); MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); } @@ -495,7 +500,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))); } @@ -612,21 +617,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); } @@ -635,6 +641,7 @@ static AnalysisKey Key; int &Runs; + ModuleAnalysisManager &MAM; }; AnalysisKey TestIndirectFunctionAnalysis::Key; @@ -693,16 +700,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();