[polly] 59d7709 - Bound ISL operations during DeLICM scalar collapsing (#203073)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Jul 16 03:12:40 PDT 2026
Author: Shikhar Jain
Date: 2026-07-16T15:42:35+05:30
New Revision: 59d7709ee9352df286bfb9b7a3b97c38deae5495
URL: https://github.com/llvm/llvm-project/commit/59d7709ee9352df286bfb9b7a3b97c38deae5495
DIFF: https://github.com/llvm/llvm-project/commit/59d7709ee9352df286bfb9b7a3b97c38deae5495.diff
LOG: Bound ISL operations during DeLICM scalar collapsing (#203073)
The IslMaxOperationsGuard in DeLICM previously covered only the zone
analysis performed in computeZone(). The subsequent greedyCollapse() ->
collapseScalarsToStore() path calls computeScalarReachingOverwrite(),
which performs an unbounded ISL lexmin().
Share a single[already present], dormant IslMaxOperationsGuard across
both regions and arm it narrowly around each operation intensive
computation via IslQuotaScope, so the same operations budget covers both
computeZone() and the scalar collapsing. When the quota is exceeded
during scalar collapsing, bail out cleanly: increment DeLICMOutOfQuota
and emit an "OutOfQuota" analysis remark.
Fixes: https://github.com/llvm/llvm-project/issues/202045
Added:
polly/test/DeLICM/outofquota-greedycollapse.ll
Modified:
polly/lib/Transform/DeLICM.cpp
Removed:
################################################################################
diff --git a/polly/lib/Transform/DeLICM.cpp b/polly/lib/Transform/DeLICM.cpp
index 4deace112f5b4..ffc3c14e9b14b 100644
--- a/polly/lib/Transform/DeLICM.cpp
+++ b/polly/lib/Transform/DeLICM.cpp
@@ -40,7 +40,7 @@ cl::opt<int>
DelicmMaxOps("polly-delicm-max-ops",
cl::desc("Maximum number of isl operations to invest for "
"lifetime analysis; 0=no limit"),
- cl::init(1000000), cl::cat(PollyCategory));
+ cl::init(1500000), cl::cat(PollyCategory));
cl::opt<bool> DelicmOverapproximateWrites(
"polly-delicm-overapproximate-writes",
@@ -545,6 +545,13 @@ class DeLICMImpl final : public ZoneAlgorithm {
/// The number of PHIs mapped to some array element.
int NumberOfMappedPHIScalars = 0;
+ /// Shared ISL operations budget guarding the expensive zone analysis
+ /// (computeZone) and the scalar-to-store collapsing (greedyCollapse). It is
+ /// constructed dormant (AutoEnter=false) and armed narrowly around each
+ /// dangerous region via IslQuotaScope, so the same budget covers both
+ /// regions without ever nesting two armed scopes.
+ IslMaxOperationsGuard MaxOpGuard;
+
/// Determine whether two knowledges are conflicting with each other.
///
/// @see Knowledge::isConflicting
@@ -1024,9 +1031,35 @@ class DeLICMImpl final : public ZoneAlgorithm {
auto TargetAccRel = getAccessRelationFor(TargetStoreMA);
// { Zone[] -> DomTarget[] }
- // For each point in time, find the next target store instance.
- auto Target =
- computeScalarReachingOverwrite(Schedule, TargetDom, false, true);
+ // For each point in time, find the next target store instance. This can be
+ // expensive for SCoPs with many modular/quasi-affine constraints, so bound
+ // it with the shared ISL operations budget.
+ isl::map Target;
+ {
+ IslQuotaScope MaxOpScope = MaxOpGuard.enter();
+ Target = computeScalarReachingOverwrite(Schedule, TargetDom, false, true);
+
+ if (MaxOpScope.hasQuotaExceeded()) {
+ DeLICMOutOfQuota++;
+ assert(
+ isl_ctx_last_error(IslCtx.get()) == isl_error_quota &&
+ "The only reason that these things have not been computed should "
+ "be if the max-operations limit hit");
+ POLLY_DEBUG(
+ dbgs() << "collapseScalarsToStore exceeded max_operations\n");
+ DebugLoc Begin, End;
+ getDebugLocations(getBBPairForRegion(&S->getRegion()), Begin, End);
+ OptimizationRemarkAnalysis R(DEBUG_TYPE, "OutOfQuota", Begin,
+ S->getEntry());
+ R << "maximal number of operations exceeded during "
+ "collapseScalarsToStore";
+ S->getFunction().getContext().diagnose(R);
+ return false;
+ }
+
+ if (Target.is_null())
+ return false;
+ }
// { Zone[] -> Element[] }
// Use the target store's write location as a suggestion to map scalars to.
@@ -1187,7 +1220,9 @@ class DeLICMImpl final : public ZoneAlgorithm {
}
public:
- DeLICMImpl(Scop *S, LoopInfo *LI) : ZoneAlgorithm("polly-delicm", S, LI) {}
+ DeLICMImpl(Scop *S, LoopInfo *LI)
+ : ZoneAlgorithm("polly-delicm", S, LI),
+ MaxOpGuard(IslCtx.get(), DelicmMaxOps, /*AutoEnter=*/false) {}
/// Calculate the lifetime (definition to last use) of every array element.
///
@@ -1200,7 +1235,7 @@ class DeLICMImpl final : public ZoneAlgorithm {
isl::union_map EltKnown, EltWritten;
{
- IslMaxOperationsGuard MaxOpGuard(IslCtx.get(), DelicmMaxOps);
+ IslQuotaScope MaxOpScope = MaxOpGuard.enter();
computeCommon();
@@ -1239,6 +1274,7 @@ class DeLICMImpl final : public ZoneAlgorithm {
/// the first processed element claims it.
void greedyCollapse() {
bool Modified = false;
+ bool MaxOpQuotaExceeded = false;
for (auto &Stmt : *S) {
for (auto *MA : Stmt) {
@@ -1334,7 +1370,13 @@ class DeLICMImpl final : public ZoneAlgorithm {
POLLY_DEBUG(dbgs() << "Analyzing target access " << MA << "\n");
if (collapseScalarsToStore(MA))
Modified = true;
+ else if (MaxOpGuard.hasQuotaExceeded()) {
+ MaxOpQuotaExceeded = true;
+ break;
+ }
}
+ if (MaxOpQuotaExceeded)
+ break;
}
if (Modified)
diff --git a/polly/test/DeLICM/outofquota-greedycollapse.ll b/polly/test/DeLICM/outofquota-greedycollapse.ll
new file mode 100644
index 0000000000000..42e608fae3f36
--- /dev/null
+++ b/polly/test/DeLICM/outofquota-greedycollapse.ll
@@ -0,0 +1,70 @@
+; RUN: opt %loadNPMPolly '-passes=polly-custom<delicm>' -polly-process-unprofitable -pass-remarks-analysis=polly-delicm -disable-output < %s 2>&1 | FileCheck %s
+
+; This test exercises the ISL operations guard in the DeLICM phase when
+; collapsing scalars to a store. The structure of the SCoP below has a few
+; important characteristics:
+; a) A large loop iteration space.
+; b) A long if-else ladder such that, of the two branches exiting each
+; conditional block, one is always a predecessor of a common basic block.
+; c) The domain of the common BB is the union of all domains reaching it,
+; which forces certain ISL operations to handle a high-dimensional,
+; extremely large search space.
+; Thus it is necessary to bound these operations and bail out instead of
+; hanging indefinitely.
+; With the shared IslMaxOperationsGuard[budget defined by -polly-delicm-max-ops]
+; now armed during collapseScalarsToStore() as well, the analysis aborts
+; once the operations budget is exhausted, emitting an "OutOfQuota" remark
+; and leaving the SCoP unmodified.
+
+; CHECK: maximal number of operations exceeded during collapseScalarsToStore
+
+define void @ham(ptr %arg) {
+bb:
+ br label %bb1
+
+bb1: ; preds = %bb19, %bb
+ %phi = phi i64 [ 1, %bb ], [ %add, %bb19 ]
+ %trunc = trunc i64 %phi to i32
+ %and = and i32 %trunc, 1
+ %icmp = icmp eq i32 %and, 0
+ br i1 %icmp, label %bb4, label %bb2
+
+bb2: ; preds = %bb16, %bb13, %bb10, %bb7, %bb4, %bb1
+ %phi3 = phi i8 [ 1, %bb1 ], [ 0, %bb4 ], [ 1, %bb13 ], [ 0, %bb16 ], [ 0, %bb10 ], [ 1, %bb7 ]
+ %getelementptr = getelementptr i8, ptr %arg, i64 %phi
+ store i8 %phi3, ptr %getelementptr, align 1
+ br label %bb19
+
+bb4: ; preds = %bb1
+ %and5 = and i64 %phi, 254
+ %icmp6 = icmp eq i64 %and5, 0
+ br i1 %icmp6, label %bb7, label %bb2
+
+bb7: ; preds = %bb4
+ %and8 = and i32 %trunc, 256
+ %icmp9 = icmp eq i32 %and8, 0
+ br i1 %icmp9, label %bb10, label %bb2
+
+bb10: ; preds = %bb7
+ %and11 = and i64 %phi, 3584
+ %icmp12 = icmp eq i64 %and11, 0
+ br i1 %icmp12, label %bb13, label %bb2
+
+bb13: ; preds = %bb10
+ %and14 = and i32 %trunc, 8192
+ %icmp15 = icmp eq i32 %and14, 0
+ br i1 %icmp15, label %bb16, label %bb2
+
+bb16: ; preds = %bb13
+ %and17 = and i64 %phi, 49152
+ %icmp18 = icmp eq i64 %and17, 0
+ br i1 %icmp18, label %bb19, label %bb2
+
+bb19: ; preds = %bb16, %bb2
+ %add = add i64 %phi, 1
+ %icmp20 = icmp eq i64 %add, 65536
+ br i1 %icmp20, label %bb21, label %bb1
+
+bb21: ; preds = %bb19
+ ret void
+}
More information about the llvm-commits
mailing list