[llvm] [SCEV] Add non-poison/non-zero checks on denominators (PR #117152)

Yingwei Zheng via llvm-commits llvm-commits at lists.llvm.org
Thu Nov 21 05:41:28 PST 2024


https://github.com/dtcxzyw updated https://github.com/llvm/llvm-project/pull/117152

>From 8aecde3e8d931073e1ab2c94cd04bf9084f24cfe Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Thu, 21 Nov 2024 20:16:58 +0800
Subject: [PATCH 1/3] [SCEV] Add pre-commit tests. NFC.

---
 .../test/Analysis/ScalarEvolution/pr117133.ll | 53 +++++++++++++++++++
 .../Transforms/IndVarSimplify/pr117133.ll     | 45 ++++++++++++++++
 2 files changed, 98 insertions(+)
 create mode 100644 llvm/test/Analysis/ScalarEvolution/pr117133.ll
 create mode 100644 llvm/test/Transforms/IndVarSimplify/pr117133.ll

diff --git a/llvm/test/Analysis/ScalarEvolution/pr117133.ll b/llvm/test/Analysis/ScalarEvolution/pr117133.ll
new file mode 100644
index 00000000000000..ab8c952b0e5c84
--- /dev/null
+++ b/llvm/test/Analysis/ScalarEvolution/pr117133.ll
@@ -0,0 +1,53 @@
+; NOTE: Assertions have been autogenerated by utils/update_analyze_test_checks.py UTC_ARGS: --version 5
+; RUN: opt -S -disable-output "-passes=print<scalar-evolution>" < %s 2>&1 | FileCheck %s
+
+define i32 @widget() {
+; CHECK-LABEL: 'widget'
+; CHECK-NEXT:  Classifying expressions for: @widget
+; CHECK-NEXT:    %phi = phi i32 [ 0, %b ], [ %udiv6, %b5 ]
+; CHECK-NEXT:    --> ({0,+,1}<nuw><nsw><%b1> /u 0) U: empty-set S: empty-set Exits: <<Unknown>> LoopDispositions: { %b1: Computable }
+; CHECK-NEXT:    %phi2 = phi i32 [ 1, %b ], [ %add, %b5 ]
+; CHECK-NEXT:    --> {1,+,1}<nuw><nsw><%b1> U: [1,2) S: [1,2) Exits: <<Unknown>> LoopDispositions: { %b1: Computable }
+; CHECK-NEXT:    %udiv = udiv i32 10, %phi2
+; CHECK-NEXT:    --> (10 /u {1,+,1}<nuw><nsw><%b1>) U: [10,11) S: [10,11) Exits: <<Unknown>> LoopDispositions: { %b1: Computable }
+; CHECK-NEXT:    %urem = urem i32 %udiv, 10
+; CHECK-NEXT:    --> ((-10 * ((10 /u {1,+,1}<nuw><nsw><%b1>) /u 10))<nuw><nsw> + (10 /u {1,+,1}<nuw><nsw><%b1>)) U: [0,1) S: [0,1) Exits: <<Unknown>> LoopDispositions: { %b1: Computable }
+; CHECK-NEXT:    %udiv6 = udiv i32 %phi2, 0
+; CHECK-NEXT:    --> ({1,+,1}<nuw><nsw><%b1> /u 0) U: empty-set S: empty-set Exits: <<Unknown>> LoopDispositions: { %b1: Computable }
+; CHECK-NEXT:    %add = add i32 %phi2, 1
+; CHECK-NEXT:    --> {2,+,1}<nuw><nsw><%b1> U: [2,3) S: [2,3) Exits: <<Unknown>> LoopDispositions: { %b1: Computable }
+; CHECK-NEXT:  Determining loop execution counts for: @widget
+; CHECK-NEXT:  Loop %b1: <multiple exits> Unpredictable backedge-taken count.
+; CHECK-NEXT:    exit count for b1: ***COULDNOTCOMPUTE***
+; CHECK-NEXT:    exit count for b3: i32 0
+; CHECK-NEXT:  Loop %b1: constant max backedge-taken count is i32 0
+; CHECK-NEXT:  Loop %b1: symbolic max backedge-taken count is i32 0
+; CHECK-NEXT:    symbolic max exit count for b1: ***COULDNOTCOMPUTE***
+; CHECK-NEXT:    symbolic max exit count for b3: i32 0
+;
+b:
+  br label %b1
+
+b1:                                              ; preds = %b5, %b
+  %phi = phi i32 [ 0, %b ], [ %udiv6, %b5 ]
+  %phi2 = phi i32 [ 1, %b ], [ %add, %b5 ]
+  %icmp = icmp eq i32 %phi, 0
+  br i1 %icmp, label %b3, label %b8
+
+b3:                                              ; preds = %b1
+  %udiv = udiv i32 10, %phi2
+  %urem = urem i32 %udiv, 10
+  %icmp4 = icmp eq i32 %urem, 0
+  br i1 %icmp4, label %b7, label %b5
+
+b5:                                              ; preds = %b3
+  %udiv6 = udiv i32 %phi2, 0
+  %add = add i32 %phi2, 1
+  br label %b1
+
+b7:                                              ; preds = %b3
+  ret i32 5
+
+b8:                                              ; preds = %b1
+  ret i32 7
+}
diff --git a/llvm/test/Transforms/IndVarSimplify/pr117133.ll b/llvm/test/Transforms/IndVarSimplify/pr117133.ll
new file mode 100644
index 00000000000000..bb9f1cf4d82cdf
--- /dev/null
+++ b/llvm/test/Transforms/IndVarSimplify/pr117133.ll
@@ -0,0 +1,45 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; RUN: opt -S -passes=indvars < %s | FileCheck %s
+
+
+define i32 @widget() {
+; CHECK-LABEL: define i32 @widget() {
+; CHECK-NEXT:  [[B:.*:]]
+; CHECK-NEXT:    br label %[[B1:.*]]
+; CHECK:       [[B1]]:
+; CHECK-NEXT:    br i1 false, label %[[B3:.*]], label %[[B8:.*]]
+; CHECK:       [[B3]]:
+; CHECK-NEXT:    br i1 true, label %[[B7:.*]], label %[[B5:.*]]
+; CHECK:       [[B5]]:
+; CHECK-NEXT:    br label %[[B1]]
+; CHECK:       [[B7]]:
+; CHECK-NEXT:    ret i32 5
+; CHECK:       [[B8]]:
+; CHECK-NEXT:    ret i32 7
+;
+b:
+  br label %b1
+
+b1:
+  %phi = phi i32 [ 0, %b ], [ %udiv6, %b5 ]
+  %phi2 = phi i32 [ 1, %b ], [ %add, %b5 ]
+  %icmp = icmp eq i32 %phi, 0
+  br i1 %icmp, label %b3, label %b8
+
+b3:
+  %udiv = udiv i32 10, %phi2
+  %urem = urem i32 %udiv, 10
+  %icmp4 = icmp eq i32 %urem, 0
+  br i1 %icmp4, label %b7, label %b5
+
+b5:
+  %udiv6 = udiv i32 %phi2, 0
+  %add = add i32 %phi2, 1
+  br label %b1
+
+b7:
+  ret i32 5
+
+b8:
+  ret i32 7
+}

>From 69157f7ba0fcc5bf0587a72f2582321ffbf52525 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Thu, 21 Nov 2024 20:29:29 +0800
Subject: [PATCH 2/3] [SCEV] Add non-poison/non-zero checks on denominators

---
 llvm/lib/Analysis/ScalarEvolution.cpp                    | 9 +++++++--
 llvm/test/Analysis/ScalarEvolution/fold.ll               | 2 +-
 llvm/test/Analysis/ScalarEvolution/pr117133.ll           | 2 +-
 .../Analysis/ScalarEvolution/udiv-of-x-xsmaxone-fold.ll  | 4 ++--
 llvm/test/Transforms/IndVarSimplify/pr117133.ll          | 2 +-
 5 files changed, 12 insertions(+), 7 deletions(-)

diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp
index 376f260846bbaa..4d0fcfef78f1c2 100644
--- a/llvm/lib/Analysis/ScalarEvolution.cpp
+++ b/llvm/lib/Analysis/ScalarEvolution.cpp
@@ -3422,9 +3422,14 @@ const SCEV *ScalarEvolution::getUDivExpr(const SCEV *LHS,
   if (const SCEV *S = UniqueSCEVs.FindNodeOrInsertPos(ID, IP))
     return S;
 
+  // If the denominator is zero, the udiv will trap.
+  auto IsValidDenominator = [&] {
+    return isGuaranteedNotToBePoison(RHS) && isKnownNonZero(RHS);
+  };
+
   // 0 udiv Y == 0
   if (const SCEVConstant *LHSC = dyn_cast<SCEVConstant>(LHS))
-    if (LHSC->getValue()->isZero())
+    if (LHSC->getValue()->isZero() && IsValidDenominator())
       return LHS;
 
   if (const SCEVConstant *RHSC = dyn_cast<SCEVConstant>(RHS)) {
@@ -3560,7 +3565,7 @@ const SCEV *ScalarEvolution::getUDivExpr(const SCEV *LHS,
         if (MME && MME->getNumOperands() == 2 &&
             isa<SCEVConstant>(MME->getOperand(0)) &&
             cast<SCEVConstant>(MME->getOperand(0))->getAPInt() == -NegC &&
-            MME->getOperand(1) == RHS)
+            MME->getOperand(1) == RHS && IsValidDenominator())
           return getZero(LHS->getType());
       }
     }
diff --git a/llvm/test/Analysis/ScalarEvolution/fold.ll b/llvm/test/Analysis/ScalarEvolution/fold.ll
index 670523ca1bb5b9..5fde3b18da9fe9 100644
--- a/llvm/test/Analysis/ScalarEvolution/fold.ll
+++ b/llvm/test/Analysis/ScalarEvolution/fold.ll
@@ -214,7 +214,7 @@ define i64 @test10(i64 %a, i64 %b) {
   ret i64 %t2
 }
 
-define i64 @test11(i64 %a) {
+define i64 @test11(i64 noundef range(i64 1, 0) %a) {
 ; CHECK-LABEL: 'test11'
 ; CHECK-NEXT:  Classifying expressions for: @test11
 ; CHECK-NEXT:    %t0 = udiv i64 0, %a
diff --git a/llvm/test/Analysis/ScalarEvolution/pr117133.ll b/llvm/test/Analysis/ScalarEvolution/pr117133.ll
index ab8c952b0e5c84..75f15055ce3d94 100644
--- a/llvm/test/Analysis/ScalarEvolution/pr117133.ll
+++ b/llvm/test/Analysis/ScalarEvolution/pr117133.ll
@@ -5,7 +5,7 @@ define i32 @widget() {
 ; CHECK-LABEL: 'widget'
 ; CHECK-NEXT:  Classifying expressions for: @widget
 ; CHECK-NEXT:    %phi = phi i32 [ 0, %b ], [ %udiv6, %b5 ]
-; CHECK-NEXT:    --> ({0,+,1}<nuw><nsw><%b1> /u 0) U: empty-set S: empty-set Exits: <<Unknown>> LoopDispositions: { %b1: Computable }
+; CHECK-NEXT:    --> %phi U: [0,1) S: [0,1) Exits: <<Unknown>> LoopDispositions: { %b1: Variant }
 ; CHECK-NEXT:    %phi2 = phi i32 [ 1, %b ], [ %add, %b5 ]
 ; CHECK-NEXT:    --> {1,+,1}<nuw><nsw><%b1> U: [1,2) S: [1,2) Exits: <<Unknown>> LoopDispositions: { %b1: Computable }
 ; CHECK-NEXT:    %udiv = udiv i32 10, %phi2
diff --git a/llvm/test/Analysis/ScalarEvolution/udiv-of-x-xsmaxone-fold.ll b/llvm/test/Analysis/ScalarEvolution/udiv-of-x-xsmaxone-fold.ll
index 9405c0f726ac7f..5694a505ccb316 100644
--- a/llvm/test/Analysis/ScalarEvolution/udiv-of-x-xsmaxone-fold.ll
+++ b/llvm/test/Analysis/ScalarEvolution/udiv-of-x-xsmaxone-fold.ll
@@ -1,7 +1,7 @@
 ; NOTE: Assertions have been autogenerated by utils/update_analyze_test_checks.py
 ; RUN: opt -disable-output -passes="print<scalar-evolution>" < %s 2>&1 | FileCheck %s
 
-define i32 @test_expr_with_constant_1(i32 %x) {
+define i32 @test_expr_with_constant_1(i32 noundef range(i32 1, 0) %x) {
 ; CHECK-LABEL: 'test_expr_with_constant_1'
 ; CHECK-NEXT:  Classifying expressions for: @test_expr_with_constant_1
 ; CHECK-NEXT:    %smax = tail call i32 @llvm.smax.i32(i32 %x, i32 1)
@@ -20,7 +20,7 @@ entry:
 }
 
 ; Non-1 constant: (-2 + (2 smax %x)) /u %x
-define i32 @test_expr_with_constant_2(i32 %x) {
+define i32 @test_expr_with_constant_2(i32 noundef range(i32 1, 0) %x) {
 ; CHECK-LABEL: 'test_expr_with_constant_2'
 ; CHECK-NEXT:  Classifying expressions for: @test_expr_with_constant_2
 ; CHECK-NEXT:    %smax = tail call i32 @llvm.smax.i32(i32 %x, i32 2)
diff --git a/llvm/test/Transforms/IndVarSimplify/pr117133.ll b/llvm/test/Transforms/IndVarSimplify/pr117133.ll
index bb9f1cf4d82cdf..31545ecba94cdb 100644
--- a/llvm/test/Transforms/IndVarSimplify/pr117133.ll
+++ b/llvm/test/Transforms/IndVarSimplify/pr117133.ll
@@ -7,7 +7,7 @@ define i32 @widget() {
 ; CHECK-NEXT:  [[B:.*:]]
 ; CHECK-NEXT:    br label %[[B1:.*]]
 ; CHECK:       [[B1]]:
-; CHECK-NEXT:    br i1 false, label %[[B3:.*]], label %[[B8:.*]]
+; CHECK-NEXT:    br i1 true, label %[[B3:.*]], label %[[B8:.*]]
 ; CHECK:       [[B3]]:
 ; CHECK-NEXT:    br i1 true, label %[[B7:.*]], label %[[B5:.*]]
 ; CHECK:       [[B5]]:

>From db15881427934a412f1e41b3ed0517558ca64a99 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Thu, 21 Nov 2024 21:41:05 +0800
Subject: [PATCH 3/3] [SCEV] Address review comments. NFC.

---
 llvm/include/llvm/Analysis/ScalarEvolution.h |  6 ++++++
 llvm/lib/Analysis/ScalarEvolution.cpp        | 12 +++---------
 2 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/llvm/include/llvm/Analysis/ScalarEvolution.h b/llvm/include/llvm/Analysis/ScalarEvolution.h
index 885c5985f9d23a..6ee1549b3a305e 100644
--- a/llvm/include/llvm/Analysis/ScalarEvolution.h
+++ b/llvm/include/llvm/Analysis/ScalarEvolution.h
@@ -1039,6 +1039,12 @@ class ScalarEvolution {
   /// Test if the given expression is known to be non-zero.
   bool isKnownNonZero(const SCEV *S);
 
+  /// If the denominator is zero or poison, the udiv will trap.
+  /// Test if the given expression is neither poison nor zero.
+  bool isValidDenominator(const SCEV *S) {
+    return isKnownNonZero(S) && isGuaranteedNotToBePoison(S);
+  }
+
   /// 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.
   bool isKnownToBeAPowerOfTwo(const SCEV *S, bool OrZero = false,
diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp
index 4d0fcfef78f1c2..9af617c65edd9f 100644
--- a/llvm/lib/Analysis/ScalarEvolution.cpp
+++ b/llvm/lib/Analysis/ScalarEvolution.cpp
@@ -3422,14 +3422,9 @@ const SCEV *ScalarEvolution::getUDivExpr(const SCEV *LHS,
   if (const SCEV *S = UniqueSCEVs.FindNodeOrInsertPos(ID, IP))
     return S;
 
-  // If the denominator is zero, the udiv will trap.
-  auto IsValidDenominator = [&] {
-    return isGuaranteedNotToBePoison(RHS) && isKnownNonZero(RHS);
-  };
-
   // 0 udiv Y == 0
   if (const SCEVConstant *LHSC = dyn_cast<SCEVConstant>(LHS))
-    if (LHSC->getValue()->isZero() && IsValidDenominator())
+    if (LHSC->getValue()->isZero() && isValidDenominator(RHS))
       return LHS;
 
   if (const SCEVConstant *RHSC = dyn_cast<SCEVConstant>(RHS)) {
@@ -3565,7 +3560,7 @@ const SCEV *ScalarEvolution::getUDivExpr(const SCEV *LHS,
         if (MME && MME->getNumOperands() == 2 &&
             isa<SCEVConstant>(MME->getOperand(0)) &&
             cast<SCEVConstant>(MME->getOperand(0))->getAPInt() == -NegC &&
-            MME->getOperand(1) == RHS && IsValidDenominator())
+            MME->getOperand(1) == RHS && isValidDenominator(RHS))
           return getZero(LHS->getType());
       }
     }
@@ -4316,8 +4311,7 @@ ScalarEvolution::getSequentialMinMaxExpr(SCEVTypes Kind,
       auto *UDiv = dyn_cast<SCEVUDivExpr>(S);
       // The UDiv may be UB if the divisor is poison or zero. Unless the divisor
       // is a non-zero constant, we have to assume the UDiv may be UB.
-      return UDiv && (!isKnownNonZero(UDiv->getOperand(1)) ||
-                      !isGuaranteedNotToBePoison(UDiv->getOperand(1)));
+      return UDiv && !isValidDenominator(UDiv->getOperand(1));
     });
 
     if (MayBeUB)



More information about the llvm-commits mailing list