Update prebuilt Clang to r416183b from Android.
https://android.googlesource.com/platform/prebuilts/clang/host/
linux-x86/+/06a71ddac05c22edb2d10b590e1769b3f8619bef
clang 12.0.5 (based on r416183b) from build 7284624.
Change-Id: I277a316abcf47307562d8b748b84870f31a72866
Signed-off-by: Olivier Deprez <olivier.deprez@arm.com>
diff --git a/linux-x64/clang/include/llvm/Analysis/CGSCCPassManager.h b/linux-x64/clang/include/llvm/Analysis/CGSCCPassManager.h
index 8af5fb8..985424a 100644
--- a/linux-x64/clang/include/llvm/Analysis/CGSCCPassManager.h
+++ b/linux-x64/clang/include/llvm/Analysis/CGSCCPassManager.h
@@ -88,13 +88,14 @@
#ifndef LLVM_ANALYSIS_CGSCCPASSMANAGER_H
#define LLVM_ANALYSIS_CGSCCPASSMANAGER_H
+#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/PriorityWorklist.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Analysis/LazyCallGraph.h"
-#include "llvm/IR/CallSite.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/InstIterator.h"
#include "llvm/IR/PassManager.h"
@@ -314,6 +315,16 @@
/// for a better technique.
SmallDenseSet<std::pair<LazyCallGraph::Node *, LazyCallGraph::SCC *>, 4>
&InlinedInternalEdges;
+
+ /// Weak VHs to keep track of indirect calls for the purposes of detecting
+ /// devirtualization.
+ ///
+ /// This is a map to avoid having duplicate entries. If a Value is
+ /// deallocated, its corresponding WeakTrackingVH will be nulled out. When
+ /// checking if a Value is in the map or not, also check if the corresponding
+ /// WeakTrackingVH is null to avoid issues with a new Value sharing the same
+ /// address as a deallocated one.
+ SmallMapVector<Value *, WeakTrackingVH, 16> IndirectVHs;
};
/// The core module pass which does a post-order walk of the SCCs and
@@ -325,18 +336,15 @@
/// \c CGSCCAnalysisManagerModuleProxy analysis prior to running the CGSCC
/// pass over the module to enable a \c FunctionAnalysisManager to be used
/// within this run safely.
-template <typename CGSCCPassT>
class ModuleToPostOrderCGSCCPassAdaptor
- : public PassInfoMixin<ModuleToPostOrderCGSCCPassAdaptor<CGSCCPassT>> {
+ : public PassInfoMixin<ModuleToPostOrderCGSCCPassAdaptor> {
public:
- explicit ModuleToPostOrderCGSCCPassAdaptor(CGSCCPassT Pass)
- : Pass(std::move(Pass)) {}
+ using PassConceptT =
+ detail::PassConcept<LazyCallGraph::SCC, CGSCCAnalysisManager,
+ LazyCallGraph &, CGSCCUpdateResult &>;
- // We have to explicitly define all the special member functions because MSVC
- // refuses to generate them.
- ModuleToPostOrderCGSCCPassAdaptor(
- const ModuleToPostOrderCGSCCPassAdaptor &Arg)
- : Pass(Arg.Pass) {}
+ explicit ModuleToPostOrderCGSCCPassAdaptor(std::unique_ptr<PassConceptT> Pass)
+ : Pass(std::move(Pass)) {}
ModuleToPostOrderCGSCCPassAdaptor(ModuleToPostOrderCGSCCPassAdaptor &&Arg)
: Pass(std::move(Arg.Pass)) {}
@@ -355,16 +363,22 @@
/// Runs the CGSCC pass across every SCC in the module.
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM);
+ static bool isRequired() { return true; }
+
private:
- CGSCCPassT Pass;
+ std::unique_ptr<PassConceptT> Pass;
};
/// A function to deduce a function pass type and wrap it in the
/// templated adaptor.
template <typename CGSCCPassT>
-ModuleToPostOrderCGSCCPassAdaptor<CGSCCPassT>
+ModuleToPostOrderCGSCCPassAdaptor
createModuleToPostOrderCGSCCPassAdaptor(CGSCCPassT Pass) {
- return ModuleToPostOrderCGSCCPassAdaptor<CGSCCPassT>(std::move(Pass));
+ using PassModelT = detail::PassModel<LazyCallGraph::SCC, CGSCCPassT,
+ PreservedAnalyses, CGSCCAnalysisManager,
+ LazyCallGraph &, CGSCCUpdateResult &>;
+ return ModuleToPostOrderCGSCCPassAdaptor(
+ std::make_unique<PassModelT>(std::move(Pass)));
}
/// A proxy from a \c FunctionAnalysisManager to an \c SCC.
@@ -380,10 +394,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 +434,19 @@
/// 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.
+///
+/// CGSCC passes can only mutate the call graph in specific ways. This
+/// routine provides a helper that updates the call graph in those ways
+/// including returning whether any changes were made and populating a CG
+/// update result struct for the overall CGSCC walk.
+LazyCallGraph::SCC &updateCGAndAnalysisManagerForCGSCCPass(
+ LazyCallGraph &G, LazyCallGraph::SCC &C, LazyCallGraph::Node &N,
+ CGSCCAnalysisManager &AM, CGSCCUpdateResult &UR,
+ FunctionAnalysisManager &FAM);
/// Adaptor that maps from a SCC to its functions.
///
@@ -425,17 +456,13 @@
/// \c FunctionAnalysisManagerCGSCCProxy analysis prior to running the function
/// pass over the SCC to enable a \c FunctionAnalysisManager to be used
/// within this run safely.
-template <typename FunctionPassT>
class CGSCCToFunctionPassAdaptor
- : public PassInfoMixin<CGSCCToFunctionPassAdaptor<FunctionPassT>> {
+ : public PassInfoMixin<CGSCCToFunctionPassAdaptor> {
public:
- explicit CGSCCToFunctionPassAdaptor(FunctionPassT Pass)
- : Pass(std::move(Pass)) {}
+ using PassConceptT = detail::PassConcept<Function, FunctionAnalysisManager>;
- // We have to explicitly define all the special member functions because MSVC
- // refuses to generate them.
- CGSCCToFunctionPassAdaptor(const CGSCCToFunctionPassAdaptor &Arg)
- : Pass(Arg.Pass) {}
+ explicit CGSCCToFunctionPassAdaptor(std::unique_ptr<PassConceptT> Pass)
+ : Pass(std::move(Pass)) {}
CGSCCToFunctionPassAdaptor(CGSCCToFunctionPassAdaptor &&Arg)
: Pass(std::move(Arg.Pass)) {}
@@ -452,86 +479,24 @@
/// Runs the function pass across every function in the module.
PreservedAnalyses run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM,
- LazyCallGraph &CG, CGSCCUpdateResult &UR) {
- // Setup the function analysis manager from its proxy.
- FunctionAnalysisManager &FAM =
- AM.getResult<FunctionAnalysisManagerCGSCCProxy>(C, CG).getManager();
+ LazyCallGraph &CG, CGSCCUpdateResult &UR);
- SmallVector<LazyCallGraph::Node *, 4> Nodes;
- for (LazyCallGraph::Node &N : C)
- Nodes.push_back(&N);
-
- // The SCC may get split while we are optimizing functions due to deleting
- // edges. If this happens, the current SCC can shift, so keep track of
- // a pointer we can overwrite.
- LazyCallGraph::SCC *CurrentC = &C;
-
- LLVM_DEBUG(dbgs() << "Running function passes across an SCC: " << C
- << "\n");
-
- PreservedAnalyses PA = PreservedAnalyses::all();
- for (LazyCallGraph::Node *N : Nodes) {
- // Skip nodes from other SCCs. These may have been split out during
- // processing. We'll eventually visit those SCCs and pick up the nodes
- // there.
- if (CG.lookupSCC(*N) != CurrentC)
- continue;
-
- Function &F = N->getFunction();
-
- PassInstrumentation PI = FAM.getResult<PassInstrumentationAnalysis>(F);
- if (!PI.runBeforePass<Function>(Pass, F))
- continue;
-
- PreservedAnalyses PassPA = Pass.run(F, FAM);
-
- PI.runAfterPass<Function>(Pass, F);
-
- // We know that the function pass couldn't have invalidated any other
- // function's analyses (that's the contract of a function pass), so
- // directly handle the function analysis manager's invalidation here.
- FAM.invalidate(F, PassPA);
-
- // Then intersect the preserved set so that invalidation of module
- // analyses will eventually occur when the module pass completes.
- PA.intersect(std::move(PassPA));
-
- // If the call graph hasn't been preserved, update it based on this
- // function pass. This may also update the current SCC to point to
- // a smaller, more refined SCC.
- auto PAC = PA.getChecker<LazyCallGraphAnalysis>();
- if (!PAC.preserved() && !PAC.preservedSet<AllAnalysesOn<Module>>()) {
- CurrentC = &updateCGAndAnalysisManagerForFunctionPass(CG, *CurrentC, *N,
- AM, UR);
- assert(
- CG.lookupSCC(*N) == CurrentC &&
- "Current SCC not updated to the SCC containing the current node!");
- }
- }
-
- // By definition we preserve the proxy. And we preserve all analyses on
- // Functions. This precludes *any* invalidation of function analyses by the
- // proxy, but that's OK because we've taken care to invalidate analyses in
- // the function analysis manager incrementally above.
- PA.preserveSet<AllAnalysesOn<Function>>();
- PA.preserve<FunctionAnalysisManagerCGSCCProxy>();
-
- // We've also ensured that we updated the call graph along the way.
- PA.preserve<LazyCallGraphAnalysis>();
-
- return PA;
- }
+ static bool isRequired() { return true; }
private:
- FunctionPassT Pass;
+ std::unique_ptr<PassConceptT> Pass;
};
/// A function to deduce a function pass type and wrap it in the
/// templated adaptor.
template <typename FunctionPassT>
-CGSCCToFunctionPassAdaptor<FunctionPassT>
+CGSCCToFunctionPassAdaptor
createCGSCCToFunctionPassAdaptor(FunctionPassT Pass) {
- return CGSCCToFunctionPassAdaptor<FunctionPassT>(std::move(Pass));
+ using PassModelT =
+ detail::PassModel<Function, FunctionPassT, PreservedAnalyses,
+ FunctionAnalysisManager>;
+ return CGSCCToFunctionPassAdaptor(
+ std::make_unique<PassModelT>(std::move(Pass)));
}
/// A helper that repeats an SCC pass each time an indirect call is refined to
@@ -548,379 +513,36 @@
/// This repetition has the potential to be very large however, as each one
/// might refine a single call site. As a consequence, in practice we use an
/// upper bound on the number of repetitions to limit things.
-template <typename PassT>
-class DevirtSCCRepeatedPass
- : public PassInfoMixin<DevirtSCCRepeatedPass<PassT>> {
+class DevirtSCCRepeatedPass : public PassInfoMixin<DevirtSCCRepeatedPass> {
public:
- explicit DevirtSCCRepeatedPass(PassT Pass, int MaxIterations)
+ using PassConceptT =
+ detail::PassConcept<LazyCallGraph::SCC, CGSCCAnalysisManager,
+ LazyCallGraph &, CGSCCUpdateResult &>;
+
+ explicit DevirtSCCRepeatedPass(std::unique_ptr<PassConceptT> Pass,
+ int MaxIterations)
: Pass(std::move(Pass)), MaxIterations(MaxIterations) {}
/// Runs the wrapped pass up to \c MaxIterations on the SCC, iterating
/// whenever an indirect call is refined.
PreservedAnalyses run(LazyCallGraph::SCC &InitialC, CGSCCAnalysisManager &AM,
- LazyCallGraph &CG, CGSCCUpdateResult &UR) {
- PreservedAnalyses PA = PreservedAnalyses::all();
- PassInstrumentation PI =
- AM.getResult<PassInstrumentationAnalysis>(InitialC, CG);
-
- // The SCC may be refined while we are running passes over it, so set up
- // a pointer that we can update.
- LazyCallGraph::SCC *C = &InitialC;
-
- // Collect value handles for all of the indirect call sites.
- SmallVector<WeakTrackingVH, 8> CallHandles;
-
- // Struct to track the counts of direct and indirect calls in each function
- // of the SCC.
- struct CallCount {
- int Direct;
- int Indirect;
- };
-
- // Put value handles on all of the indirect calls and return the number of
- // direct calls for each function in the SCC.
- auto ScanSCC = [](LazyCallGraph::SCC &C,
- SmallVectorImpl<WeakTrackingVH> &CallHandles) {
- assert(CallHandles.empty() && "Must start with a clear set of handles.");
-
- SmallVector<CallCount, 4> CallCounts;
- for (LazyCallGraph::Node &N : C) {
- CallCounts.push_back({0, 0});
- CallCount &Count = CallCounts.back();
- for (Instruction &I : instructions(N.getFunction()))
- if (auto CS = CallSite(&I)) {
- if (CS.getCalledFunction()) {
- ++Count.Direct;
- } else {
- ++Count.Indirect;
- CallHandles.push_back(WeakTrackingVH(&I));
- }
- }
- }
-
- return CallCounts;
- };
-
- // Populate the initial call handles and get the initial call counts.
- auto CallCounts = ScanSCC(*C, CallHandles);
-
- for (int Iteration = 0;; ++Iteration) {
-
- if (!PI.runBeforePass<LazyCallGraph::SCC>(Pass, *C))
- continue;
-
- PreservedAnalyses PassPA = Pass.run(*C, AM, CG, UR);
-
- if (UR.InvalidatedSCCs.count(C))
- PI.runAfterPassInvalidated<LazyCallGraph::SCC>(Pass);
- else
- PI.runAfterPass<LazyCallGraph::SCC>(Pass, *C);
-
- // If the SCC structure has changed, bail immediately and let the outer
- // CGSCC layer handle any iteration to reflect the refined structure.
- if (UR.UpdatedC && UR.UpdatedC != C) {
- PA.intersect(std::move(PassPA));
- break;
- }
-
- // Check that we didn't miss any update scenario.
- assert(!UR.InvalidatedSCCs.count(C) && "Processing an invalid SCC!");
- assert(C->begin() != C->end() && "Cannot have an empty SCC!");
- assert((int)CallCounts.size() == C->size() &&
- "Cannot have changed the size of the SCC!");
-
- // Check whether any of the handles were devirtualized.
- auto IsDevirtualizedHandle = [&](WeakTrackingVH &CallH) {
- if (!CallH)
- return false;
- auto CS = CallSite(CallH);
- if (!CS)
- return false;
-
- // If the call is still indirect, leave it alone.
- Function *F = CS.getCalledFunction();
- if (!F)
- return false;
-
- LLVM_DEBUG(dbgs() << "Found devirutalized call from "
- << CS.getParent()->getParent()->getName() << " to "
- << F->getName() << "\n");
-
- // We now have a direct call where previously we had an indirect call,
- // so iterate to process this devirtualization site.
- return true;
- };
- bool Devirt = llvm::any_of(CallHandles, IsDevirtualizedHandle);
-
- // Rescan to build up a new set of handles and count how many direct
- // calls remain. If we decide to iterate, this also sets up the input to
- // the next iteration.
- CallHandles.clear();
- auto NewCallCounts = ScanSCC(*C, CallHandles);
-
- // If we haven't found an explicit devirtualization already see if we
- // have decreased the number of indirect calls and increased the number
- // of direct calls for any function in the SCC. This can be fooled by all
- // manner of transformations such as DCE and other things, but seems to
- // work well in practice.
- if (!Devirt)
- for (int i = 0, Size = C->size(); i < Size; ++i)
- if (CallCounts[i].Indirect > NewCallCounts[i].Indirect &&
- CallCounts[i].Direct < NewCallCounts[i].Direct) {
- Devirt = true;
- break;
- }
-
- if (!Devirt) {
- PA.intersect(std::move(PassPA));
- break;
- }
-
- // Otherwise, if we've already hit our max, we're done.
- if (Iteration >= MaxIterations) {
- LLVM_DEBUG(
- dbgs() << "Found another devirtualization after hitting the max "
- "number of repetitions ("
- << MaxIterations << ") on SCC: " << *C << "\n");
- PA.intersect(std::move(PassPA));
- break;
- }
-
- LLVM_DEBUG(
- dbgs()
- << "Repeating an SCC pass after finding a devirtualization in: " << *C
- << "\n");
-
- // Move over the new call counts in preparation for iterating.
- CallCounts = std::move(NewCallCounts);
-
- // 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));
- }
-
- // Note that we don't add any preserved entries here unlike a more normal
- // "pass manager" because we only handle invalidation *between* iterations,
- // not after the last iteration.
- return PA;
- }
+ LazyCallGraph &CG, CGSCCUpdateResult &UR);
private:
- PassT Pass;
+ std::unique_ptr<PassConceptT> Pass;
int MaxIterations;
};
/// A function to deduce a function pass type and wrap it in the
/// templated adaptor.
-template <typename PassT>
-DevirtSCCRepeatedPass<PassT> createDevirtSCCRepeatedPass(PassT Pass,
- int MaxIterations) {
- return DevirtSCCRepeatedPass<PassT>(std::move(Pass), MaxIterations);
-}
-
-// Out-of-line implementation details for templates below this point.
-
template <typename CGSCCPassT>
-PreservedAnalyses
-ModuleToPostOrderCGSCCPassAdaptor<CGSCCPassT>::run(Module &M,
- ModuleAnalysisManager &AM) {
- // Setup the CGSCC analysis manager from its proxy.
- CGSCCAnalysisManager &CGAM =
- AM.getResult<CGSCCAnalysisManagerModuleProxy>(M).getManager();
-
- // Get the call graph for this module.
- LazyCallGraph &CG = AM.getResult<LazyCallGraphAnalysis>(M);
-
- // We keep worklists to allow us to push more work onto the pass manager as
- // the passes are run.
- SmallPriorityWorklist<LazyCallGraph::RefSCC *, 1> RCWorklist;
- SmallPriorityWorklist<LazyCallGraph::SCC *, 1> CWorklist;
-
- // Keep sets for invalidated SCCs and RefSCCs that should be skipped when
- // iterating off the worklists.
- SmallPtrSet<LazyCallGraph::RefSCC *, 4> InvalidRefSCCSet;
- SmallPtrSet<LazyCallGraph::SCC *, 4> InvalidSCCSet;
-
- SmallDenseSet<std::pair<LazyCallGraph::Node *, LazyCallGraph::SCC *>, 4>
- InlinedInternalEdges;
-
- CGSCCUpdateResult UR = {
- RCWorklist, CWorklist, InvalidRefSCCSet, InvalidSCCSet,
- nullptr, nullptr, PreservedAnalyses::all(), InlinedInternalEdges};
-
- // Request PassInstrumentation from analysis manager, will use it to run
- // instrumenting callbacks for the passes later.
- PassInstrumentation PI = AM.getResult<PassInstrumentationAnalysis>(M);
-
- PreservedAnalyses PA = PreservedAnalyses::all();
- CG.buildRefSCCs();
- for (auto RCI = CG.postorder_ref_scc_begin(),
- RCE = CG.postorder_ref_scc_end();
- RCI != RCE;) {
- assert(RCWorklist.empty() &&
- "Should always start with an empty RefSCC worklist");
- // The postorder_ref_sccs range we are walking is lazily constructed, so
- // we only push the first one onto the worklist. The worklist allows us
- // to capture *new* RefSCCs created during transformations.
- //
- // We really want to form RefSCCs lazily because that makes them cheaper
- // to update as the program is simplified and allows us to have greater
- // cache locality as forming a RefSCC touches all the parts of all the
- // functions within that RefSCC.
- //
- // We also eagerly increment the iterator to the next position because
- // the CGSCC passes below may delete the current RefSCC.
- RCWorklist.insert(&*RCI++);
-
- do {
- LazyCallGraph::RefSCC *RC = RCWorklist.pop_back_val();
- if (InvalidRefSCCSet.count(RC)) {
- LLVM_DEBUG(dbgs() << "Skipping an invalid RefSCC...\n");
- continue;
- }
-
- assert(CWorklist.empty() &&
- "Should always start with an empty SCC worklist");
-
- LLVM_DEBUG(dbgs() << "Running an SCC pass across the RefSCC: " << *RC
- << "\n");
-
- // Push the initial SCCs in reverse post-order as we'll pop off the
- // back and so see this in post-order.
- for (LazyCallGraph::SCC &C : llvm::reverse(*RC))
- CWorklist.insert(&C);
-
- do {
- LazyCallGraph::SCC *C = CWorklist.pop_back_val();
- // Due to call graph mutations, we may have invalid SCCs or SCCs from
- // other RefSCCs in the worklist. The invalid ones are dead and the
- // other RefSCCs should be queued above, so we just need to skip both
- // scenarios here.
- if (InvalidSCCSet.count(C)) {
- LLVM_DEBUG(dbgs() << "Skipping an invalid SCC...\n");
- continue;
- }
- if (&C->getOuterRefSCC() != RC) {
- LLVM_DEBUG(dbgs() << "Skipping an SCC that is now part of some other "
- "RefSCC...\n");
- 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<FunctionAnalysisManagerCGSCCProxy>(*C, CG);
-
- // Each time we visit a new SCC pulled off the worklist,
- // a transformation of a child SCC may have also modified this parent
- // and invalidated analyses. So we invalidate using the update record's
- // cross-SCC preserved set. This preserved set is intersected by any
- // CGSCC pass that handles invalidation (primarily pass managers) prior
- // to marking its SCC as preserved. That lets us track everything that
- // might need invalidation across SCCs without excessive invalidations
- // on a single SCC.
- //
- // This essentially allows SCC passes to freely invalidate analyses
- // of any ancestor SCC. If this becomes detrimental to successfully
- // caching analyses, we could force each SCC pass to manually
- // invalidate the analyses for any SCCs other than themselves which
- // are mutated. However, that seems to lose the robustness of the
- // pass-manager driven invalidation scheme.
- //
- // FIXME: This is redundant in one case -- the top of the worklist may
- // *also* be the same SCC we just ran over (and invalidated for). In
- // that case, we'll end up doing a redundant invalidation here as
- // a consequence.
- CGAM.invalidate(*C, UR.CrossSCCPA);
-
- do {
- // Check that we didn't miss any update scenario.
- assert(!InvalidSCCSet.count(C) && "Processing an invalid SCC!");
- assert(C->begin() != C->end() && "Cannot have an empty SCC!");
- assert(&C->getOuterRefSCC() == RC &&
- "Processing an SCC in a different RefSCC!");
-
- UR.UpdatedRC = nullptr;
- UR.UpdatedC = nullptr;
-
- // Check the PassInstrumentation's BeforePass callbacks before
- // running the pass, skip its execution completely if asked to
- // (callback returns false).
- if (!PI.runBeforePass<LazyCallGraph::SCC>(Pass, *C))
- continue;
-
- PreservedAnalyses PassPA = Pass.run(*C, CGAM, CG, UR);
-
- if (UR.InvalidatedSCCs.count(C))
- PI.runAfterPassInvalidated<LazyCallGraph::SCC>(Pass);
- else
- PI.runAfterPass<LazyCallGraph::SCC>(Pass, *C);
-
- // Update the SCC and RefSCC if necessary.
- C = UR.UpdatedC ? UR.UpdatedC : C;
- RC = UR.UpdatedRC ? UR.UpdatedRC : RC;
-
- // 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)) {
- LLVM_DEBUG(dbgs() << "Skipping invalidated root or island SCC!\n");
- break;
- }
- // Check that we didn't miss any update scenario.
- assert(C->begin() != C->end() && "Cannot have an empty SCC!");
-
- // We handle invalidating the CGSCC analysis manager's information
- // for the (potentially updated) SCC here. Note that any other SCCs
- // whose structure has changed should have been invalidated by
- // whatever was updating the call graph. This SCC gets invalidated
- // late as it contains the nodes that were actively being
- // processed.
- CGAM.invalidate(*C, PassPA);
-
- // Then intersect the preserved set so that invalidation of module
- // analyses will eventually occur when the module pass completes.
- // Also intersect with the cross-SCC preserved set to capture any
- // cross-SCC invalidation.
- UR.CrossSCCPA.intersect(PassPA);
- PA.intersect(std::move(PassPA));
-
- // The pass may have restructured the call graph and refined the
- // current SCC and/or RefSCC. We need to update our current SCC and
- // RefSCC pointers to follow these. Also, when the current SCC is
- // refined, re-run the SCC pass over the newly refined SCC in order
- // to observe the most precise SCC model available. This inherently
- // cannot cycle excessively as it only happens when we split SCCs
- // apart, at most converging on a DAG of single nodes.
- // FIXME: If we ever start having RefSCC passes, we'll want to
- // iterate there too.
- if (UR.UpdatedC)
- LLVM_DEBUG(dbgs()
- << "Re-running SCC passes after a refinement of the "
- "current SCC: "
- << *UR.UpdatedC << "\n");
-
- // Note that both `C` and `RC` may at this point refer to deleted,
- // invalid SCC and RefSCCs respectively. But we will short circuit
- // the processing when we check them in the loop above.
- } while (UR.UpdatedC);
- } while (!CWorklist.empty());
-
- // We only need to keep internal inlined edge information within
- // a RefSCC, clear it to save on space and let the next time we visit
- // any of these functions have a fresh start.
- InlinedInternalEdges.clear();
- } while (!RCWorklist.empty());
- }
-
- // By definition we preserve the call garph, all SCC analyses, and the
- // analysis proxies by handling them above and in any nested pass managers.
- PA.preserveSet<AllAnalysesOn<LazyCallGraph::SCC>>();
- PA.preserve<LazyCallGraphAnalysis>();
- PA.preserve<CGSCCAnalysisManagerModuleProxy>();
- PA.preserve<FunctionAnalysisManagerModuleProxy>();
- return PA;
+DevirtSCCRepeatedPass createDevirtSCCRepeatedPass(CGSCCPassT Pass,
+ int MaxIterations) {
+ using PassModelT = detail::PassModel<LazyCallGraph::SCC, CGSCCPassT,
+ PreservedAnalyses, CGSCCAnalysisManager,
+ LazyCallGraph &, CGSCCUpdateResult &>;
+ return DevirtSCCRepeatedPass(std::make_unique<PassModelT>(std::move(Pass)),
+ MaxIterations);
}
// Clear out the debug logging macro.