[polly] 68a9cd3 - [Polly] Detect preconditions of cached user assumption translations (#226204)

via llvm-commits llvm-commits at lists.llvm.org
Fri Sep 25 05:06:15 PDT 2026


Author: Timur Baidusenov
Date: 2026-09-25T14:06:08+02:00
New Revision: 68a9cd31fd277f9f6b8a8ab95e18d00a786e7c12

URL: https://github.com/llvm/llvm-project/commit/68a9cd31fd277f9f6b8a8ab95e18d00a786e7c12
DIFF: https://github.com/llvm/llvm-project/commit/68a9cd31fd277f9f6b8a8ab95e18d00a786e7c12.diff

LOG: [Polly] Detect preconditions of cached user assumption translations (#226204)

`addUserAssumptions` detected preconditions of a user assumption by
checking whether building its condition recorded new assumptions, but
`SCEVAffinator` caches translated expressions, so a precondition shared
with an earlier assumption (e.g. the same truncation) was missed and the
assumption went into the context, removing the runtime check it relied
on. For example, with `__builtin_assume((signed char)n >= 0)` and
`__builtin_assume((signed char)n < 10)`, the `n >= 128` check was
dropped, although `n = 261` satisfies both assumptions. Instead, check
the invalid domain of each assumption, which is also cached, and if it
is non-empty, add the assumption to the defined behavior context as in
#189350.

Assisted-by: Claude (Anthropic)

Added: 
    polly/test/ScopInfo/user-assumption-cached-precondition.ll

Modified: 
    polly/lib/Analysis/ScopBuilder.cpp

Removed: 
    


################################################################################
diff  --git a/polly/lib/Analysis/ScopBuilder.cpp b/polly/lib/Analysis/ScopBuilder.cpp
index 5f8c6dc8ccd38..7a52ee3481817 100644
--- a/polly/lib/Analysis/ScopBuilder.cpp
+++ b/polly/lib/Analysis/ScopBuilder.cpp
@@ -1441,17 +1441,31 @@ void ScopBuilder::addUserAssumptions(
       NewParams.insert(Param);
     }
 
-    size_t NumAssumptions = RecordedAssumptions.size();
     SmallVector<isl_set *, 2> ConditionSets;
     auto *TI = InScop ? CI->getParent()->getTerminator() : nullptr;
     BasicBlock *BB = InScop ? CI->getParent() : R.getEntry();
     auto *Dom = InScop ? isl_set_copy(scop->getDomainConditions(BB).get())
                        : isl_set_copy(scop->getContext().get());
     assert(Dom && "Cannot propagate a nullptr.");
-    bool Valid = buildConditionSets(BB, Val, TI, L, Dom, InvalidDomainMap,
-                                    ConditionSets);
+
+    // Collect the invalid domain of this assumption on its own to determine
+    // whether its translation depends on preconditions (such as a truncation
+    // not overflowing). Checking for newly recorded assumptions is not
+    // sufficient: SCEVAffinator caches translated expressions, so a
+    // precondition shared with an earlier assumption is only recorded once.
+    isl::set BBInvalidDomain = InvalidDomainMap[BB];
+    assert(!BBInvalidDomain.is_null() && "Cannot propagate a nullptr.");
+    DenseMap<BasicBlock *, isl::set> AssumptionInvalidDomainMap;
+    AssumptionInvalidDomainMap[BB] =
+        isl::set::empty(BBInvalidDomain.get_space());
+    bool Valid = buildConditionSets(BB, Val, TI, L, Dom,
+                                    AssumptionInvalidDomainMap, ConditionSets);
     isl_set_free(Dom);
 
+    isl::set AssumptionInvalidDomain = AssumptionInvalidDomainMap[BB];
+    bool HasPreconditions = !AssumptionInvalidDomain.is_empty();
+    InvalidDomainMap[BB] = BBInvalidDomain.unite(AssumptionInvalidDomain);
+
     if (!Valid)
       continue;
 
@@ -1487,7 +1501,7 @@ void ScopBuilder::addUserAssumptions(
     // correctness of AssumptionCtx. Using DefinedBehaviorContext which does not
     // gist the other contexts.
     // TODO: Use recordAssumption() for adding context/assumptions
-    if (NumAssumptions == RecordedAssumptions.size()) {
+    if (!HasPreconditions) {
       isl::set newContext =
           scop->getContext().intersect(isl::manage(AssumptionCtx));
       scop->setContext(newContext);

diff  --git a/polly/test/ScopInfo/user-assumption-cached-precondition.ll b/polly/test/ScopInfo/user-assumption-cached-precondition.ll
new file mode 100644
index 0000000000000..43c1e444c641b
--- /dev/null
+++ b/polly/test/ScopInfo/user-assumption-cached-precondition.ll
@@ -0,0 +1,63 @@
+; RUN: opt %loadNPMPolly '-passes=polly-custom<scops>' -polly-print-scops -disable-output < %s 2>&1 | FileCheck %s
+; RUN: opt %loadNPMPolly '-passes=polly-custom<ast>' -polly-print-ast -disable-output < %s 2>&1 | FileCheck %s --check-prefix=AST
+;
+; Both user assumptions are derived from (trunc i64 %n to i8), which is only
+; modeled correctly if the truncation does not overflow. SCEVAffinator caches
+; the translation of the truncation, so the precondition is recorded only for
+; the first assumption. The second assumption must nevertheless not be added
+; to the context: this would remove the 'n >= 128' runtime check from the
+; invalid context and the 'n <= 9' condition from the domain of Stmt_then.
+; For n = 261, both assumptions hold but Stmt_then must not be executed.
+;
+; void f(int *A, long n) {
+;   __builtin_assume((signed char)n >= 0);
+;   __builtin_assume((signed char)n < 10);
+;   for (long i = 0; i < 4; i++)
+;     if (n < 10)
+;       A[i] = 1;
+; }
+
+; CHECK:      Context:
+; CHECK-NEXT:   [n] -> {  : -9223372036854775808 <= n <= 9223372036854775807 }
+; CHECK:      Invalid Context:
+; CHECK-NEXT:   [n] -> {  : n <= -129 or n >= 128 }
+; CHECK:      Defined Behavior Context:
+; CHECK-NEXT:   [n] -> {  : 0 <= n <= 9 }
+; CHECK:      Domain :=
+; CHECK-NEXT:   [n] -> { Stmt_then[i0] : n <= 9 and 0 <= i0 <= 3 };
+
+; AST:      if (1 && 0 == (n <= -129 || n >= 128))
+; AST-EMPTY:
+; AST-NEXT:     if (n <= 9)
+; AST-NEXT:       for (int c0 = 0; c0 <= 3; c0 += 1)
+; AST-NEXT:         Stmt_then(c0);
+
+define void @f(ptr %A, i64 %n) {
+entry:
+  %t = trunc i64 %n to i8
+  %c1 = icmp sge i8 %t, 0
+  call void @llvm.assume(i1 %c1)
+  %c2 = icmp slt i8 %t, 10
+  call void @llvm.assume(i1 %c2)
+  br label %for
+
+for:
+  %i = phi i64 [ 0, %entry ], [ %i.next, %latch ]
+  %small = icmp slt i64 %n, 10
+  br i1 %small, label %then, label %latch
+
+then:
+  %gep = getelementptr inbounds i32, ptr %A, i64 %i
+  store i32 1, ptr %gep
+  br label %latch
+
+latch:
+  %i.next = add nuw nsw i64 %i, 1
+  %cmp = icmp slt i64 %i.next, 4
+  br i1 %cmp, label %for, label %exit
+
+exit:
+  ret void
+}
+
+declare void @llvm.assume(i1)


        


More information about the llvm-commits mailing list