[llvm-branch-commits] [polly] release/22.x: [Polly][ScopInfo] Lazy Scop instantiation (#179535) (PR #181992)
Cullen Rhodes via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Mon Feb 23 00:32:05 PST 2026
https://github.com/c-rhodes updated https://github.com/llvm/llvm-project/pull/181992
>From ebe6b3c774cd1864d6eb0216614a56c4a145f3df Mon Sep 17 00:00:00 2001
From: Michael Kruse <llvm-project at meinersbur.de>
Date: Mon, 16 Feb 2026 23:28:51 +0100
Subject: [PATCH] [Polly][ScopInfo] Lazy Scop instantiation (#179535)
The old NPM was using ScopInfo pass introduced in
https://reviews.llvm.org/D20962, which in contrast to the LPM was using
ScopInfoRegionPass. ScopInfo was instantiating all Scop objects
immediately. After codegenning, all Scop objects need to be recomputed
anyway, making this approach wastful. The PhaseManager inherited this
behaviour from the NPM, leading to some concerns.
Replace the instantiate-all behavior of ScopInfo with an on-demand
instantiation. SCoPs now must be iterated using ScopDetection instead
using ScopInfo, but only some unsed legacy NPM passes (now removed) were
doing that anyway.
(cherry picked from commit d5607ad55c5e56383d33e6ec0f582a687d75dedb)
---
polly/include/polly/ScopInfo.h | 48 ++-----------------
polly/lib/Analysis/ScopInfo.cpp | 85 ++++++++-------------------------
polly/lib/Pass/PhaseManager.cpp | 22 ++++-----
3 files changed, 35 insertions(+), 120 deletions(-)
diff --git a/polly/include/polly/ScopInfo.h b/polly/include/polly/ScopInfo.h
index e426f283ddf9d..d0a1ab6d6e7da 100644
--- a/polly/include/polly/ScopInfo.h
+++ b/polly/include/polly/ScopInfo.h
@@ -2670,17 +2670,10 @@ class Scop final {
raw_ostream &operator<<(raw_ostream &OS, const Scop &scop);
class ScopInfo {
-public:
- using RegionToScopMapTy = MapVector<Region *, std::unique_ptr<Scop>>;
- using reverse_iterator = RegionToScopMapTy::reverse_iterator;
- using const_reverse_iterator = RegionToScopMapTy::const_reverse_iterator;
- using iterator = RegionToScopMapTy::iterator;
- using const_iterator = RegionToScopMapTy::const_iterator;
-
private:
/// A map of Region to its Scop object containing
/// Polly IR of static control part.
- RegionToScopMapTy RegionToScopMap;
+ llvm::SmallDenseMap<const Region *, std::unique_ptr<Scop>> RegionToScopMap;
const DataLayout &DL;
ScopDetection &SD;
ScalarEvolution &SE;
@@ -2701,47 +2694,12 @@ class ScopInfo {
/// the scop object. If the given region is a subregion, return a
/// nullptr. Top level region containing the entry block of a function
/// is not considered in the scop creation.
- Scop *getScop(Region *R) const {
- auto MapIt = RegionToScopMap.find(R);
- if (MapIt != RegionToScopMap.end())
- return MapIt->second.get();
- return nullptr;
- }
+ Scop *getScop(const Region *R);
/// Recompute the Scop-Information for a function.
///
/// This invalidates any iterators.
- void recompute();
-
- /// Handle invalidation explicitly
- bool invalidate(Function &F, const PreservedAnalyses &PA,
- FunctionAnalysisManager::Invalidator &Inv);
-
- iterator begin() { return RegionToScopMap.begin(); }
- iterator end() { return RegionToScopMap.end(); }
- const_iterator begin() const { return RegionToScopMap.begin(); }
- const_iterator end() const { return RegionToScopMap.end(); }
- reverse_iterator rbegin() { return RegionToScopMap.rbegin(); }
- reverse_iterator rend() { return RegionToScopMap.rend(); }
- const_reverse_iterator rbegin() const { return RegionToScopMap.rbegin(); }
- const_reverse_iterator rend() const { return RegionToScopMap.rend(); }
- bool empty() const { return RegionToScopMap.empty(); }
-};
-
-struct ScopInfoAnalysis : AnalysisInfoMixin<ScopInfoAnalysis> {
- static AnalysisKey Key;
-
- using Result = ScopInfo;
-
- Result run(Function &, FunctionAnalysisManager &);
-};
-
-struct ScopInfoPrinterPass final : PassInfoMixin<ScopInfoPrinterPass> {
- ScopInfoPrinterPass(raw_ostream &OS) : Stream(OS) {}
-
- PreservedAnalyses run(Function &, FunctionAnalysisManager &);
-
- raw_ostream &Stream;
+ void invalidate();
};
} // end namespace polly
diff --git a/polly/lib/Analysis/ScopInfo.cpp b/polly/lib/Analysis/ScopInfo.cpp
index bf993a27dd17d..d3aaa7840ae80 100644
--- a/polly/lib/Analysis/ScopInfo.cpp
+++ b/polly/lib/Analysis/ScopInfo.cpp
@@ -2579,73 +2579,30 @@ void updateLoopCountStatistic(ScopDetection::LoopStats Stats,
ScopInfo::ScopInfo(const DataLayout &DL, ScopDetection &SD, ScalarEvolution &SE,
LoopInfo &LI, AliasAnalysis &AA, DominatorTree &DT,
AssumptionCache &AC, OptimizationRemarkEmitter &ORE)
- : DL(DL), SD(SD), SE(SE), LI(LI), AA(AA), DT(DT), AC(AC), ORE(ORE) {
- recompute();
-}
+ : DL(DL), SD(SD), SE(SE), LI(LI), AA(AA), DT(DT), AC(AC), ORE(ORE) {}
-void ScopInfo::recompute() {
- RegionToScopMap.clear();
- /// Create polyhedral description of scops for all the valid regions of a
- /// function.
- for (auto &It : SD) {
- Region *R = const_cast<Region *>(It);
- if (!SD.isMaxRegionInScop(*R))
- continue;
+Scop *ScopInfo::getScop(const Region *R) {
+ auto &&[It, Inserted] = RegionToScopMap.try_emplace(R);
+ if (Inserted && SD.isMaxRegionInScop(*R)) {
+ ScopBuilder SB(const_cast<Region *>(R), AC, AA, DL, DT, LI, SD, SE, ORE);
+ It->second = SB.getScop();
+ Scop *S = It->second.get();
- ScopBuilder SB(R, AC, AA, DL, DT, LI, SD, SE, ORE);
- std::unique_ptr<Scop> S = SB.getScop();
- if (!S)
- continue;
#if !defined(NDEBUG) || defined(LLVM_ENABLE_STATS)
- ScopDetection::LoopStats Stats =
- ScopDetection::countBeneficialLoops(&S->getRegion(), SE, LI, 0);
- updateLoopCountStatistic(Stats, S->getStatistics());
+ if (S) {
+ ScopDetection::LoopStats Stats =
+ ScopDetection::countBeneficialLoops(&S->getRegion(), SE, LI, 0);
+ updateLoopCountStatistic(Stats, S->getStatistics());
+ }
#endif
- bool Inserted = RegionToScopMap.insert({R, std::move(S)}).second;
- assert(Inserted && "Building Scop for the same region twice!");
- (void)Inserted;
- }
-}
-
-bool ScopInfo::invalidate(Function &F, const PreservedAnalyses &PA,
- FunctionAnalysisManager::Invalidator &Inv) {
- // Check whether the analysis, all analyses on functions have been preserved
- // or anything we're holding references to is being invalidated
- auto PAC = PA.getChecker<ScopInfoAnalysis>();
- return !(PAC.preserved() || PAC.preservedSet<AllAnalysesOn<Function>>()) ||
- Inv.invalidate<ScopAnalysis>(F, PA) ||
- Inv.invalidate<ScalarEvolutionAnalysis>(F, PA) ||
- Inv.invalidate<LoopAnalysis>(F, PA) ||
- Inv.invalidate<AAManager>(F, PA) ||
- Inv.invalidate<DominatorTreeAnalysis>(F, PA) ||
- Inv.invalidate<AssumptionAnalysis>(F, PA);
-}
-
-AnalysisKey ScopInfoAnalysis::Key;
-
-ScopInfoAnalysis::Result ScopInfoAnalysis::run(Function &F,
- FunctionAnalysisManager &FAM) {
- auto &SD = FAM.getResult<ScopAnalysis>(F);
- auto &SE = FAM.getResult<ScalarEvolutionAnalysis>(F);
- auto &LI = FAM.getResult<LoopAnalysis>(F);
- auto &AA = FAM.getResult<AAManager>(F);
- auto &DT = FAM.getResult<DominatorTreeAnalysis>(F);
- auto &AC = FAM.getResult<AssumptionAnalysis>(F);
- auto &DL = F.getParent()->getDataLayout();
- auto &ORE = FAM.getResult<OptimizationRemarkEmitterAnalysis>(F);
- return {DL, SD, SE, LI, AA, DT, AC, ORE};
-}
-
-PreservedAnalyses ScopInfoPrinterPass::run(Function &F,
- FunctionAnalysisManager &FAM) {
- auto &SI = FAM.getResult<ScopInfoAnalysis>(F);
- // Since the legacy PM processes Scops in bottom up, we print them in reverse
- // order here to keep the output persistent
- for (auto &It : reverse(SI)) {
- if (It.second)
- It.second->print(Stream, PollyPrintInstructions);
- else
- Stream << "Invalid Scop!\n";
+
+ return S;
}
- return PreservedAnalyses::all();
+
+ return It->second.get();
+}
+
+void ScopInfo::invalidate() {
+ // Recompute all SCoPs on-demand
+ RegionToScopMap.clear();
}
diff --git a/polly/lib/Pass/PhaseManager.cpp b/polly/lib/Pass/PhaseManager.cpp
index 330dfe8b1ef1e..e65f812eb94b0 100644
--- a/polly/lib/Pass/PhaseManager.cpp
+++ b/polly/lib/Pass/PhaseManager.cpp
@@ -152,18 +152,18 @@ class PhaseManager {
}
}
- SmallPriorityWorklist<Region *, 4> Worklist;
- for (auto &[R, S] : Info)
- if (S)
- Worklist.insert(R);
+ SmallPriorityWorklist<const Region *, 4> Worklist;
+ for (const Region *R : SD)
+ Worklist.insert(R);
TargetTransformInfo &TTI = FAM.getResult<TargetIRAnalysis>(F);
while (!Worklist.empty()) {
- Region *R = Worklist.pop_back_val();
+ const Region *R = Worklist.pop_back_val();
Scop *S = Info.getScop(R);
if (!S) {
- // This can happen if codegenning of a previous SCoP made this region
- // not-a-SCoP anymore.
+ // This can happen if the region is not maximal, is not determined a
+ // valid SCoP by ScopBuilder, or codegenning of a previous SCoP made
+ // this region not-a-SCoP anymore.
POLLY_DEBUG(dbgs() << "SCoP in Region '" << *R << "' disappeared");
continue;
}
@@ -249,10 +249,10 @@ class PhaseManager {
if (ModifiedByCodeGen) {
ModifiedIR = true;
- // For all regions, create new polly::Scop objects because the old ones
- // refere to invalidated LLVM-IR.
- // FIXME: Adds all SCoPs again to statistics
- Info.recompute();
+ // Discard old polly::Scop objects because they may refer to invalidated
+ // LLVM-IR instructions and SCEV expressions. ScopInfo will recreate
+ // them on demand.
+ Info.invalidate();
}
}
More information about the llvm-branch-commits
mailing list