summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Analysis
diff options
context:
space:
mode:
authorChandler Carruth <chandlerc@gmail.com>2017-01-11 06:23:21 +0000
committerChandler Carruth <chandlerc@gmail.com>2017-01-11 06:23:21 +0000
commit410eaeb0640042279627ebe92696601cbbabce69 (patch)
treef74bac02e0e8555e536654445040d57e2d06b0dc /llvm/lib/Analysis
parent7af39837a9b097eefc66b49c047c057f32072818 (diff)
downloadbcm5719-llvm-410eaeb0640042279627ebe92696601cbbabce69.tar.gz
bcm5719-llvm-410eaeb0640042279627ebe92696601cbbabce69.zip
[PM] Rewrite the loop pass manager to use a worklist and augmented run
arguments much like the CGSCC pass manager. This is a major redesign following the pattern establish for the CGSCC layer to support updates to the set of loops during the traversal of the loop nest and to support invalidation of analyses. An additional significant burden in the loop PM is that so many passes require access to a large number of function analyses. Manually ensuring these are cached, available, and preserved has been a long-standing burden in LLVM even with the help of the automatic scheduling in the old pass manager. And it made the new pass manager extremely unweildy. With this design, we can package the common analyses up while in a function pass and make them immediately available to all the loop passes. While in some cases this is unnecessary, I think the simplicity afforded is worth it. This does not (yet) address loop simplified form or LCSSA form, but those are the next things on my radar and I have a clear plan for them. While the patch is very large, most of it is either mechanically updating loop passes to the new API or the new testing for the loop PM. The code for it is reasonably compact. I have not yet updated all of the loop passes to correctly leverage the update mechanisms demonstrated in the unittests. I'll do that in follow-up patches along with improved FileCheck tests for those passes that ensure things work in more realistic scenarios. In many cases, there isn't much we can do with these until the loop simplified form and LCSSA form are in place. Differential Revision: https://reviews.llvm.org/D28292 llvm-svn: 291651
Diffstat (limited to 'llvm/lib/Analysis')
-rw-r--r--llvm/lib/Analysis/IVUsers.cpp18
-rw-r--r--llvm/lib/Analysis/LoopAccessAnalysis.cpp29
-rw-r--r--llvm/lib/Analysis/LoopInfo.cpp7
-rw-r--r--llvm/lib/Analysis/LoopPass.cpp10
-rw-r--r--llvm/lib/Analysis/LoopPassManager.cpp188
5 files changed, 198 insertions, 54 deletions
diff --git a/llvm/lib/Analysis/IVUsers.cpp b/llvm/lib/Analysis/IVUsers.cpp
index 76e2561b9da..eb3782c3631 100644
--- a/llvm/lib/Analysis/IVUsers.cpp
+++ b/llvm/lib/Analysis/IVUsers.cpp
@@ -36,19 +36,15 @@ using namespace llvm;
AnalysisKey IVUsersAnalysis::Key;
-IVUsers IVUsersAnalysis::run(Loop &L, LoopAnalysisManager &AM) {
- const auto &FAM =
- AM.getResult<FunctionAnalysisManagerLoopProxy>(L).getManager();
- Function *F = L.getHeader()->getParent();
-
- return IVUsers(&L, FAM.getCachedResult<AssumptionAnalysis>(*F),
- FAM.getCachedResult<LoopAnalysis>(*F),
- FAM.getCachedResult<DominatorTreeAnalysis>(*F),
- FAM.getCachedResult<ScalarEvolutionAnalysis>(*F));
+IVUsers IVUsersAnalysis::run(Loop &L, LoopAnalysisManager &AM,
+ LoopStandardAnalysisResults &AR) {
+ return IVUsers(&L, &AR.AC, &AR.LI, &AR.DT, &AR.SE);
}
-PreservedAnalyses IVUsersPrinterPass::run(Loop &L, LoopAnalysisManager &AM) {
- AM.getResult<IVUsersAnalysis>(L).print(OS);
+PreservedAnalyses IVUsersPrinterPass::run(Loop &L, LoopAnalysisManager &AM,
+ LoopStandardAnalysisResults &AR,
+ LPMUpdater &U) {
+ AM.getResult<IVUsersAnalysis>(L, AR).print(OS);
return PreservedAnalyses::all();
}
diff --git a/llvm/lib/Analysis/LoopAccessAnalysis.cpp b/llvm/lib/Analysis/LoopAccessAnalysis.cpp
index 2f3dca3d23f..0de75ec2d17 100644
--- a/llvm/lib/Analysis/LoopAccessAnalysis.cpp
+++ b/llvm/lib/Analysis/LoopAccessAnalysis.cpp
@@ -2120,31 +2120,16 @@ INITIALIZE_PASS_END(LoopAccessLegacyAnalysis, LAA_NAME, laa_name, false, true)
AnalysisKey LoopAccessAnalysis::Key;
-LoopAccessInfo LoopAccessAnalysis::run(Loop &L, LoopAnalysisManager &AM) {
- const FunctionAnalysisManager &FAM =
- AM.getResult<FunctionAnalysisManagerLoopProxy>(L).getManager();
- Function &F = *L.getHeader()->getParent();
- auto *SE = FAM.getCachedResult<ScalarEvolutionAnalysis>(F);
- auto *TLI = FAM.getCachedResult<TargetLibraryAnalysis>(F);
- auto *AA = FAM.getCachedResult<AAManager>(F);
- auto *DT = FAM.getCachedResult<DominatorTreeAnalysis>(F);
- auto *LI = FAM.getCachedResult<LoopAnalysis>(F);
- if (!SE)
- report_fatal_error(
- "ScalarEvolution must have been cached at a higher level");
- if (!AA)
- report_fatal_error("AliasAnalysis must have been cached at a higher level");
- if (!DT)
- report_fatal_error("DominatorTree must have been cached at a higher level");
- if (!LI)
- report_fatal_error("LoopInfo must have been cached at a higher level");
- return LoopAccessInfo(&L, SE, TLI, AA, DT, LI);
+LoopAccessInfo LoopAccessAnalysis::run(Loop &L, LoopAnalysisManager &AM,
+ LoopStandardAnalysisResults &AR) {
+ return LoopAccessInfo(&L, &AR.SE, &AR.TLI, &AR.AA, &AR.DT, &AR.LI);
}
-PreservedAnalyses LoopAccessInfoPrinterPass::run(Loop &L,
- LoopAnalysisManager &AM) {
+PreservedAnalyses
+LoopAccessInfoPrinterPass::run(Loop &L, LoopAnalysisManager &AM,
+ LoopStandardAnalysisResults &AR, LPMUpdater &) {
Function &F = *L.getHeader()->getParent();
- auto &LAI = AM.getResult<LoopAccessAnalysis>(L);
+ auto &LAI = AM.getResult<LoopAccessAnalysis>(L, AR);
OS << "Loop access info in function '" << F.getName() << "':\n";
OS.indent(2) << L.getHeader()->getName() << ":\n";
LAI.print(OS, 4);
diff --git a/llvm/lib/Analysis/LoopInfo.cpp b/llvm/lib/Analysis/LoopInfo.cpp
index 3d85ef6988a..f449ce94d57 100644
--- a/llvm/lib/Analysis/LoopInfo.cpp
+++ b/llvm/lib/Analysis/LoopInfo.cpp
@@ -689,18 +689,13 @@ PreservedAnalyses LoopPrinterPass::run(Function &F,
return PreservedAnalyses::all();
}
-PrintLoopPass::PrintLoopPass() : OS(dbgs()) {}
-PrintLoopPass::PrintLoopPass(raw_ostream &OS, const std::string &Banner)
- : OS(OS), Banner(Banner) {}
-
-PreservedAnalyses PrintLoopPass::run(Loop &L, AnalysisManager<Loop> &) {
+void llvm::printLoop(Loop &L, raw_ostream &OS, const std::string &Banner) {
OS << Banner;
for (auto *Block : L.blocks())
if (Block)
Block->print(OS);
else
OS << "Printing <null> block";
- return PreservedAnalyses::all();
}
//===----------------------------------------------------------------------===//
diff --git a/llvm/lib/Analysis/LoopPass.cpp b/llvm/lib/Analysis/LoopPass.cpp
index b5b8040984d..2686334045b 100644
--- a/llvm/lib/Analysis/LoopPass.cpp
+++ b/llvm/lib/Analysis/LoopPass.cpp
@@ -32,13 +32,14 @@ namespace {
/// PrintLoopPass - Print a Function corresponding to a Loop.
///
class PrintLoopPassWrapper : public LoopPass {
- PrintLoopPass P;
+ raw_ostream &OS;
+ std::string Banner;
public:
static char ID;
- PrintLoopPassWrapper() : LoopPass(ID) {}
+ PrintLoopPassWrapper() : LoopPass(ID), OS(dbgs()) {}
PrintLoopPassWrapper(raw_ostream &OS, const std::string &Banner)
- : LoopPass(ID), P(OS, Banner) {}
+ : LoopPass(ID), OS(OS), Banner(Banner) {}
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.setPreservesAll();
@@ -49,8 +50,7 @@ public:
[](BasicBlock *BB) { return BB; });
if (BBI != L->blocks().end() &&
isFunctionInPrintList((*BBI)->getParent()->getName())) {
- LoopAnalysisManager DummyLAM;
- P.run(*L, DummyLAM);
+ printLoop(*L, OS, Banner);
}
return false;
}
diff --git a/llvm/lib/Analysis/LoopPassManager.cpp b/llvm/lib/Analysis/LoopPassManager.cpp
index 044e5d55daf..75b5db55e54 100644
--- a/llvm/lib/Analysis/LoopPassManager.cpp
+++ b/llvm/lib/Analysis/LoopPassManager.cpp
@@ -20,34 +20,191 @@ using namespace llvm;
// Explicit template instantiations and specialization defininitions for core
// template typedefs.
namespace llvm {
-template class PassManager<Loop>;
-template class AnalysisManager<Loop>;
+template class AllAnalysesOn<Loop>;
+template class AnalysisManager<Loop, LoopStandardAnalysisResults &>;
+template class PassManager<Loop, LoopAnalysisManager,
+ LoopStandardAnalysisResults &, LPMUpdater &>;
template class InnerAnalysisManagerProxy<LoopAnalysisManager, Function>;
-template class OuterAnalysisManagerProxy<FunctionAnalysisManager, Loop>;
+template class OuterAnalysisManagerProxy<FunctionAnalysisManager, Loop,
+ LoopStandardAnalysisResults &>;
+/// Explicitly specialize the pass manager's run method to handle loop nest
+/// structure updates.
template <>
+PreservedAnalyses
+PassManager<Loop, LoopAnalysisManager, LoopStandardAnalysisResults &,
+ LPMUpdater &>::run(Loop &L, LoopAnalysisManager &AM,
+ LoopStandardAnalysisResults &AR, LPMUpdater &U) {
+ PreservedAnalyses PA = PreservedAnalyses::all();
+
+ if (DebugLogging)
+ dbgs() << "Starting Loop pass manager run.\n";
+
+ for (auto &Pass : Passes) {
+ if (DebugLogging)
+ dbgs() << "Running pass: " << Pass->name() << " on " << L;
+
+ PreservedAnalyses PassPA = Pass->run(L, AM, AR, U);
+
+ // If the loop was deleted, abort the run and return to the outer walk.
+ if (U.skipCurrentLoop()) {
+ PA.intersect(std::move(PassPA));
+ break;
+ }
+
+ // Update the analysis manager as each pass runs and potentially
+ // invalidates analyses.
+ AM.invalidate(L, PassPA);
+
+ // Finally, we intersect the final preserved analyses to compute the
+ // aggregate preserved set for this pass manager.
+ PA.intersect(std::move(PassPA));
+
+ // FIXME: Historically, the pass managers all called the LLVM context's
+ // yield function here. We don't have a generic way to acquire the
+ // context and it isn't yet clear what the right pattern is for yielding
+ // in the new pass manager so it is currently omitted.
+ // ...getContext().yield();
+ }
+
+ // Invalidation for the current loop should be handled above, and other loop
+ // analysis results shouldn't be impacted by runs over this loop. Therefore,
+ // the remaining analysis results in the AnalysisManager are preserved. We
+ // mark this with a set so that we don't need to inspect each one
+ // individually.
+ // FIXME: This isn't correct! This loop and all nested loops' analyses should
+ // be preserved, but unrolling should invalidate the parent loop's analyses.
+ PA.preserveSet<AllAnalysesOn<Loop>>();
+
+ if (DebugLogging)
+ dbgs() << "Finished Loop pass manager run.\n";
+
+ return PA;
+}
+
bool LoopAnalysisManagerFunctionProxy::Result::invalidate(
Function &F, const PreservedAnalyses &PA,
FunctionAnalysisManager::Invalidator &Inv) {
- // If this proxy isn't marked as preserved, the set of Function objects in
- // the module may have changed. We therefore can't call
- // InnerAM->invalidate(), because any pointers to Functions it has may be
- // stale.
+ // First compute the sequence of IR units covered by this proxy. We will want
+ // to visit this in postorder, but because this is a tree structure we can do
+ // this by building a preorder sequence and walking it in reverse.
+ SmallVector<Loop *, 4> PreOrderLoops, PreOrderWorklist;
+ // Note that we want to walk the roots in reverse order because we will end
+ // up reversing the preorder sequence. However, it happens that the loop nest
+ // roots are in reverse order within the LoopInfo object. So we just walk
+ // forward here.
+ // FIXME: If we change the order of LoopInfo we will want to add a reverse
+ // here.
+ for (Loop *RootL : *LI) {
+ assert(PreOrderWorklist.empty() &&
+ "Must start with an empty preorder walk worklist.");
+ PreOrderWorklist.push_back(RootL);
+ do {
+ Loop *L = PreOrderWorklist.pop_back_val();
+ PreOrderWorklist.append(L->begin(), L->end());
+ PreOrderLoops.push_back(L);
+ } while (!PreOrderWorklist.empty());
+ }
+
+ // If this proxy or the loop info is going to be invalidated, we also need
+ // to clear all the keys coming from that analysis. We also completely blow
+ // away the loop analyses if any of the standard analyses provided by the
+ // loop pass manager go away so that loop analyses can freely use these
+ // without worrying about declaring dependencies on them etc.
+ // FIXME: It isn't clear if this is the right tradeoff. We could instead make
+ // loop analyses declare any dependencies on these and use the more general
+ // invalidation logic below to act on that.
auto PAC = PA.getChecker<LoopAnalysisManagerFunctionProxy>();
- if (!PAC.preserved() && !PAC.preservedSet<AllAnalysesOn<Loop>>())
- InnerAM->clear();
+ if (!(PAC.preserved() || PAC.preservedSet<AllAnalysesOn<Function>>()) ||
+ Inv.invalidate<AAManager>(F, PA) ||
+ Inv.invalidate<AssumptionAnalysis>(F, PA) ||
+ Inv.invalidate<DominatorTreeAnalysis>(F, PA) ||
+ Inv.invalidate<LoopAnalysis>(F, PA) ||
+ Inv.invalidate<ScalarEvolutionAnalysis>(F, PA)) {
+ // Note that the LoopInfo may be stale at this point, however the loop
+ // objects themselves remain the only viable keys that could be in the
+ // analysis manager's cache. So we just walk the keys and forcibly clear
+ // those results. Note that the order doesn't matter here as this will just
+ // directly destroy the results without calling methods on them.
+ for (Loop *L : PreOrderLoops)
+ InnerAM->clear(*L);
+
+ // We also need to null out the inner AM so that when the object gets
+ // destroyed as invalid we don't try to clear the inner AM again. At that
+ // point we won't be able to reliably walk the loops for this function and
+ // only clear results associated with those loops the way we do here.
+ // FIXME: Making InnerAM null at this point isn't very nice. Most analyses
+ // try to remain valid during invalidation. Maybe we should add an
+ // `IsClean` flag?
+ InnerAM = nullptr;
+
+ // Now return true to indicate this *is* invalid and a fresh proxy result
+ // needs to be built. This is especially important given the null InnerAM.
+ return true;
+ }
+
+ // Directly check if the relevant set is preserved so we can short circuit
+ // invalidating loops.
+ bool AreLoopAnalysesPreserved =
+ PA.allAnalysesInSetPreserved<AllAnalysesOn<Loop>>();
+
+ // Since we have a valid LoopInfo we can actually leave the cached results in
+ // the analysis manager associated with the Loop keys, but we need to
+ // propagate any necessary invalidation logic into them. We'd like to
+ // invalidate things in roughly the same order as they were put into the
+ // cache and so we walk the preorder list in reverse to form a valid
+ // postorder.
+ for (Loop *L : reverse(PreOrderLoops)) {
+ Optional<PreservedAnalyses> InnerPA;
+
+ // Check to see whether the preserved set needs to be adjusted based on
+ // function-level analysis invalidation triggering deferred invalidation
+ // for this loop.
+ if (auto *OuterProxy =
+ InnerAM->getCachedResult<FunctionAnalysisManagerLoopProxy>(*L))
+ for (const auto &OuterInvalidationPair :
+ OuterProxy->getOuterInvalidations()) {
+ AnalysisKey *OuterAnalysisID = OuterInvalidationPair.first;
+ const auto &InnerAnalysisIDs = OuterInvalidationPair.second;
+ if (Inv.invalidate(OuterAnalysisID, F, PA)) {
+ if (!InnerPA)
+ InnerPA = PA;
+ for (AnalysisKey *InnerAnalysisID : InnerAnalysisIDs)
+ InnerPA->abandon(InnerAnalysisID);
+ }
+ }
+
+ // Check if we needed a custom PA set. If so we'll need to run the inner
+ // invalidation.
+ if (InnerPA) {
+ InnerAM->invalidate(*L, *InnerPA);
+ continue;
+ }
- // FIXME: Proper suppor for invalidation isn't yet implemented for the LPM.
+ // Otherwise we only need to do invalidation if the original PA set didn't
+ // preserve all Loop analyses.
+ if (!AreLoopAnalysesPreserved)
+ InnerAM->invalidate(*L, PA);
+ }
// Return false to indicate that this result is still a valid proxy.
return false;
}
+
+template <>
+LoopAnalysisManagerFunctionProxy::Result
+LoopAnalysisManagerFunctionProxy::run(Function &F,
+ FunctionAnalysisManager &AM) {
+ return Result(*InnerAM, AM.getResult<LoopAnalysis>(F));
+}
}
PreservedAnalyses llvm::getLoopPassPreservedAnalyses() {
PreservedAnalyses PA;
+ PA.preserve<AssumptionAnalysis>();
PA.preserve<DominatorTreeAnalysis>();
PA.preserve<LoopAnalysis>();
+ PA.preserve<LoopAnalysisManagerFunctionProxy>();
PA.preserve<ScalarEvolutionAnalysis>();
// TODO: What we really want to do here is preserve an AA category, but that
// concept doesn't exist yet.
@@ -57,3 +214,14 @@ PreservedAnalyses llvm::getLoopPassPreservedAnalyses() {
PA.preserve<SCEVAA>();
return PA;
}
+
+PrintLoopPass::PrintLoopPass() : OS(dbgs()) {}
+PrintLoopPass::PrintLoopPass(raw_ostream &OS, const std::string &Banner)
+ : OS(OS), Banner(Banner) {}
+
+PreservedAnalyses PrintLoopPass::run(Loop &L, LoopAnalysisManager &,
+ LoopStandardAnalysisResults &,
+ LPMUpdater &) {
+ printLoop(L, OS, Banner);
+ return PreservedAnalyses::all();
+}
OpenPOWER on IntegriCloud