diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2020-07-26 19:36:28 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2020-07-26 19:36:28 +0000 |
commit | cfca06d7963fa0909f90483b42a6d7d194d01e08 (patch) | |
tree | 209fb2a2d68f8f277793fc8df46c753d31bc853b /llvm/lib/Analysis/CGSCCPassManager.cpp | |
parent | 706b4fc47bbc608932d3b491ae19a3b9cde9497b (diff) |
Notes
Diffstat (limited to 'llvm/lib/Analysis/CGSCCPassManager.cpp')
-rw-r--r-- | llvm/lib/Analysis/CGSCCPassManager.cpp | 169 |
1 files changed, 112 insertions, 57 deletions
diff --git a/llvm/lib/Analysis/CGSCCPassManager.cpp b/llvm/lib/Analysis/CGSCCPassManager.cpp index a0b3f83cca6a6..fd3166f8cd0cd 100644 --- a/llvm/lib/Analysis/CGSCCPassManager.cpp +++ b/llvm/lib/Analysis/CGSCCPassManager.cpp @@ -15,14 +15,15 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/iterator_range.h" #include "llvm/Analysis/LazyCallGraph.h" -#include "llvm/IR/CallSite.h" #include "llvm/IR/Constant.h" #include "llvm/IR/InstIterator.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/PassManager.h" +#include "llvm/IR/PassManagerImpl.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Support/TimeProfiler.h" #include <algorithm> #include <cassert> #include <iterator> @@ -67,16 +68,24 @@ PassManager<LazyCallGraph::SCC, CGSCCAnalysisManager, LazyCallGraph &, // a pointer that we can update. LazyCallGraph::SCC *C = &InitialC; - for (auto &Pass : Passes) { - if (DebugLogging) - dbgs() << "Running pass: " << Pass->name() << " on " << *C << "\n"; + // Get Function analysis manager from its proxy. + FunctionAnalysisManager &FAM = + AM.getCachedResult<FunctionAnalysisManagerCGSCCProxy>(*C)->getManager(); + for (auto &Pass : Passes) { // Check the PassInstrumentation's BeforePass callbacks before running the // pass, skip its execution completely if asked to (callback returns false). if (!PI.runBeforePass(*Pass, *C)) continue; - PreservedAnalyses PassPA = Pass->run(*C, AM, G, UR); + if (DebugLogging) + dbgs() << "Running pass: " << Pass->name() << " on " << *C << "\n"; + + PreservedAnalyses PassPA; + { + TimeTraceScope TimeScope(Pass->name()); + PassPA = Pass->run(*C, AM, G, UR); + } if (UR.InvalidatedSCCs.count(C)) PI.runAfterPassInvalidated<LazyCallGraph::SCC>(*Pass); @@ -85,6 +94,12 @@ PassManager<LazyCallGraph::SCC, CGSCCAnalysisManager, LazyCallGraph &, // 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<FunctionAnalysisManagerCGSCCProxy>(*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. @@ -218,23 +233,22 @@ FunctionAnalysisManagerCGSCCProxy::Result 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<ModuleAnalysisManagerCGSCCProxy>(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<ModuleAnalysisManagerCGSCCProxy>(C, CG); Module &M = *C.begin()->getFunction().getParent(); - auto *FAMProxy = MAM.getCachedResult<FunctionAnalysisManagerModuleProxy>(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<FunctionAnalysisManagerModuleProxy>(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( @@ -244,8 +258,8 @@ bool FunctionAnalysisManagerCGSCCProxy::Result::invalidate( 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. @@ -257,7 +271,7 @@ bool FunctionAnalysisManagerCGSCCProxy::Result::invalidate( for (LazyCallGraph::Node &N : C) FAM->clear(N.getFunction(), N.getFunction().getName()); - return true; + return false; } // Directly check if the relevant set is preserved. @@ -306,9 +320,10 @@ bool FunctionAnalysisManagerCGSCCProxy::Result::invalidate( } // 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 @@ -320,10 +335,9 @@ bool FunctionAnalysisManagerCGSCCProxy::Result::invalidate( /// 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<FunctionAnalysisManagerCGSCCProxy>(C, G).getManager(); + CGSCCAnalysisManager &AM, + FunctionAnalysisManager &FAM) { + AM.getResult<FunctionAnalysisManagerCGSCCProxy>(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. @@ -387,8 +401,10 @@ incorporateNewSCCRange(const SCCRangeT &NewSCCRange, LazyCallGraph &G, // 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<FunctionAnalysisManagerCGSCCProxy>(*OldC) != nullptr; + FunctionAnalysisManager *FAM = nullptr; + if (auto *FAMProxy = + AM.getCachedResult<FunctionAnalysisManagerCGSCCProxy>(*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. @@ -402,8 +418,8 @@ incorporateNewSCCRange(const SCCRangeT &NewSCCRange, LazyCallGraph &G, 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()))) { @@ -413,8 +429,8 @@ incorporateNewSCCRange(const SCCRangeT &NewSCCRange, LazyCallGraph &G, 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. @@ -423,9 +439,10 @@ incorporateNewSCCRange(const SCCRangeT &NewSCCRange, LazyCallGraph &G, return C; } -LazyCallGraph::SCC &llvm::updateCGAndAnalysisManagerForFunctionPass( +static LazyCallGraph::SCC &updateCGAndAnalysisManagerForPass( LazyCallGraph &G, LazyCallGraph::SCC &InitialC, LazyCallGraph::Node &N, - CGSCCAnalysisManager &AM, CGSCCUpdateResult &UR) { + CGSCCAnalysisManager &AM, CGSCCUpdateResult &UR, + FunctionAnalysisManager &FAM, bool FunctionPass) { using Node = LazyCallGraph::Node; using Edge = LazyCallGraph::Edge; using SCC = LazyCallGraph::SCC; @@ -443,28 +460,28 @@ LazyCallGraph::SCC &llvm::updateCGAndAnalysisManagerForFunctionPass( SmallPtrSet<Node *, 16> RetainedEdges; SmallSetVector<Node *, 4> PromotedRefTargets; SmallSetVector<Node *, 4> DemotedCallTargets; + SmallSetVector<Node *, 4> NewCallEdges; + SmallSetVector<Node *, 4> NewRefEdges; // First walk the function and handle all called functions. We do this first // because if there is a single call edge, whether there are ref edges is // irrelevant. for (Instruction &I : instructions(F)) - if (auto CS = CallSite(&I)) - if (Function *Callee = CS.getCalledFunction()) + if (auto *CB = dyn_cast<CallBase>(&I)) + if (Function *Callee = CB->getCalledFunction()) if (Visited.insert(Callee).second && !Callee->isDeclaration()) { Node &CalleeN = *G.lookup(*Callee); Edge *E = N->lookup(CalleeN); - // FIXME: We should really handle adding new calls. While it will - // make downstream usage more complex, there is no fundamental - // limitation and it will allow passes within the CGSCC to be a bit - // more flexible in what transforms they can do. Until then, we - // verify that new calls haven't been introduced. - assert(E && "No function transformations should introduce *new* " - "call edges! Any new calls should be modeled as " - "promoted existing ref edges!"); + assert((E || !FunctionPass) && + "No function transformations should introduce *new* " + "call edges! Any new calls should be modeled as " + "promoted existing ref edges!"); bool Inserted = RetainedEdges.insert(&CalleeN).second; (void)Inserted; assert(Inserted && "We should never visit a function twice."); - if (!E->isCall()) + if (!E) + NewCallEdges.insert(&CalleeN); + else if (!E->isCall()) PromotedRefTargets.insert(&CalleeN); } @@ -478,19 +495,42 @@ LazyCallGraph::SCC &llvm::updateCGAndAnalysisManagerForFunctionPass( auto VisitRef = [&](Function &Referee) { Node &RefereeN = *G.lookup(Referee); Edge *E = N->lookup(RefereeN); - // FIXME: Similarly to new calls, we also currently preclude - // introducing new references. See above for details. - assert(E && "No function transformations should introduce *new* ref " - "edges! Any new ref edges would require IPO which " - "function passes aren't allowed to do!"); + assert((E || !FunctionPass) && + "No function transformations should introduce *new* ref " + "edges! Any new ref edges would require IPO which " + "function passes aren't allowed to do!"); bool Inserted = RetainedEdges.insert(&RefereeN).second; (void)Inserted; assert(Inserted && "We should never visit a function twice."); - if (E->isCall()) + if (!E) + NewRefEdges.insert(&RefereeN); + else if (E->isCall()) DemotedCallTargets.insert(&RefereeN); }; LazyCallGraph::visitReferences(Worklist, Visited, VisitRef); + // Handle new ref edges. + for (Node *RefTarget : NewRefEdges) { + SCC &TargetC = *G.lookupSCC(*RefTarget); + RefSCC &TargetRC = TargetC.getOuterRefSCC(); + (void)TargetRC; + // TODO: This only allows trivial edges to be added for now. + assert((RC == &TargetRC || + RC->isAncestorOf(TargetRC)) && "New ref edge is not trivial!"); + RC->insertTrivialRefEdge(N, *RefTarget); + } + + // Handle new call edges. + for (Node *CallTarget : NewCallEdges) { + SCC &TargetC = *G.lookupSCC(*CallTarget); + RefSCC &TargetRC = TargetC.getOuterRefSCC(); + (void)TargetRC; + // TODO: This only allows trivial edges to be added for now. + assert((RC == &TargetRC || + RC->isAncestorOf(TargetRC)) && "New call edge is not trivial!"); + RC->insertTrivialCallEdge(N, *CallTarget); + } + // Include synthetic reference edges to known, defined lib functions. for (auto *F : G.getLibFunctions()) // While the list of lib functions doesn't have repeats, don't re-visit @@ -658,7 +698,7 @@ LazyCallGraph::SCC &llvm::updateCGAndAnalysisManagerForFunctionPass( // 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<FunctionAnalysisManagerCGSCCProxy>(*C, G); + AM.getResult<FunctionAnalysisManagerCGSCCProxy>(*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 @@ -707,3 +747,18 @@ LazyCallGraph::SCC &llvm::updateCGAndAnalysisManagerForFunctionPass( return *C; } + +LazyCallGraph::SCC &llvm::updateCGAndAnalysisManagerForFunctionPass( + LazyCallGraph &G, LazyCallGraph::SCC &InitialC, LazyCallGraph::Node &N, + 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, + FunctionAnalysisManager &FAM) { + return updateCGAndAnalysisManagerForPass(G, InitialC, N, AM, UR, FAM, + /* FunctionPass */ false); +} |