summaryrefslogtreecommitdiff
path: root/llvm/lib/Analysis/CGSCCPassManager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Analysis/CGSCCPassManager.cpp')
-rw-r--r--llvm/lib/Analysis/CGSCCPassManager.cpp169
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);
+}