[llvm] 0f6f15a - [SCEVExpander] Don't expand a UDiv with a possibly-poison divisor (#202378)

via llvm-commits llvm-commits at lists.llvm.org
Tue Jun 9 03:07:43 PDT 2026


Author: lijinpei-amd
Date: 2026-06-09T10:07:39Z
New Revision: 0f6f15a59f3f774a7f055f9754fe97c088390c4e

URL: https://github.com/llvm/llvm-project/commit/0f6f15a59f3f774a7f055f9754fe97c088390c4e
DIFF: https://github.com/llvm/llvm-project/commit/0f6f15a59f3f774a7f055f9754fe97c088390c4e.diff

LOG: [SCEVExpander] Don't expand a UDiv with a possibly-poison divisor (#202378)

SCEVExpander::isSafeToExpand only check divisor isKnownNonZero, which
ignore the possibility of poison. For the following divisor:
```
%ct = call i32 @llvm.cttz.i32(i32 %x, i1 true)
%divisor = add i32 %ct, 1
...
%rem = urem i32 1, %divisor
```
The urem may be hoisted unsafely.

Fix by also check divisor isGuaranteedNotToBePoison.

Fixes https://github.com/llvm/llvm-project/issues/202028

Added: 
    llvm/test/Transforms/IndVarSimplify/exit-value-safe-udiv.ll

Modified: 
    llvm/include/llvm/Analysis/ScalarEvolution.h
    llvm/lib/Transforms/Utils/ScalarEvolutionExpander.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/Analysis/ScalarEvolution.h b/llvm/include/llvm/Analysis/ScalarEvolution.h
index 15b891b5b4da9..50af763614a31 100644
--- a/llvm/include/llvm/Analysis/ScalarEvolution.h
+++ b/llvm/include/llvm/Analysis/ScalarEvolution.h
@@ -1235,6 +1235,9 @@ class ScalarEvolution {
   /// Test if the given expression is known to be non-zero.
   LLVM_ABI bool isKnownNonZero(const SCEV *S);
 
+  /// Returns true if \p Op is guaranteed to not be poison.
+  LLVM_ABI static bool isGuaranteedNotToBePoison(const SCEV *Op);
+
   /// Test if the given expression is known to be a power of 2.  OrNegative
   /// allows matching negative power of 2s, and OrZero allows matching 0.
   LLVM_ABI bool isKnownToBeAPowerOfTwo(const SCEV *S, bool OrZero = false,
@@ -2427,9 +2430,6 @@ class ScalarEvolution {
   /// Returns true if \p Op is guaranteed not to cause immediate UB.
   bool isGuaranteedNotToCauseUB(const SCEV *Op);
 
-  /// Returns true if \p Op is guaranteed to not be poison.
-  static bool isGuaranteedNotToBePoison(const SCEV *Op);
-
   /// Return true if the SCEV corresponding to \p I is never poison.  Proving
   /// this is more complex than proving that just \p I is never poison, since
   /// SCEV commons expressions across control flow, and you can have cases

diff  --git a/llvm/lib/Transforms/Utils/ScalarEvolutionExpander.cpp b/llvm/lib/Transforms/Utils/ScalarEvolutionExpander.cpp
index d747c7fb2d162..b2e45c3340b9f 100644
--- a/llvm/lib/Transforms/Utils/ScalarEvolutionExpander.cpp
+++ b/llvm/lib/Transforms/Utils/ScalarEvolutionExpander.cpp
@@ -2449,7 +2449,8 @@ struct SCEVFindUnsafe {
 
   bool follow(const SCEV *S) {
     if (const SCEVUDivExpr *D = dyn_cast<SCEVUDivExpr>(S)) {
-      if (!SE.isKnownNonZero(D->getRHS())) {
+      if (!SE.isKnownNonZero(D->getRHS()) ||
+          !SE.isGuaranteedNotToBePoison(D->getRHS())) {
         IsUnsafe = true;
         return false;
       }

diff  --git a/llvm/test/Transforms/IndVarSimplify/exit-value-safe-udiv.ll b/llvm/test/Transforms/IndVarSimplify/exit-value-safe-udiv.ll
new file mode 100644
index 0000000000000..f6250bb7051b5
--- /dev/null
+++ b/llvm/test/Transforms/IndVarSimplify/exit-value-safe-udiv.ll
@@ -0,0 +1,42 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -S -passes=indvars -replexitval=always < %s | FileCheck %s
+
+; Reduced from https://github.com/llvm/llvm-project/issues/202028.
+
+declare i32 @llvm.cttz.i32(i32, i1)
+
+define i32 @speculated_exit_value_udiv(i32 %x, i1 %guard, i1 %backedge) {
+; CHECK-LABEL: @speculated_exit_value_udiv(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CT:%.*]] = call i32 @llvm.cttz.i32(i32 [[X:%.*]], i1 true)
+; CHECK-NEXT:    [[D:%.*]] = add i32 [[CT]], 1
+; CHECK-NEXT:    br label [[LOOP:%.*]]
+; CHECK:       loop:
+; CHECK-NEXT:    br i1 [[GUARD:%.*]], label [[EXIT_EARLY:%.*]], label [[BODY:%.*]]
+; CHECK:       body:
+; CHECK-NEXT:    [[REM:%.*]] = urem i32 1, [[D]]
+; CHECK-NEXT:    br i1 [[BACKEDGE:%.*]], label [[LOOP]], label [[EXIT_LATE:%.*]]
+; CHECK:       exit.early:
+; CHECK-NEXT:    ret i32 0
+; CHECK:       exit.late:
+; CHECK-NEXT:    [[REM_LCSSA:%.*]] = phi i32 [ [[REM]], [[BODY]] ]
+; CHECK-NEXT:    ret i32 [[REM_LCSSA]]
+;
+entry:
+  %ct = call i32 @llvm.cttz.i32(i32 %x, i1 true)
+  %d = add i32 %ct, 1
+  br label %loop
+
+loop:
+  br i1 %guard, label %exit.early, label %body
+
+body:
+  %rem = urem i32 1, %d
+  br i1 %backedge, label %loop, label %exit.late
+
+exit.early:
+  ret i32 0
+
+exit.late:
+  ret i32 %rem
+}


        


More information about the llvm-commits mailing list