[llvm] [ValueTracking] Recognize non-negative results of NSW additions (PR #219132)

via llvm-commits llvm-commits at lists.llvm.org
Thu Aug 27 00:28:06 PDT 2026


https://github.com/VachanVY updated https://github.com/llvm/llvm-project/pull/219132

>From 12405d79b47306f5820c9bba58da1a541e0dc04e Mon Sep 17 00:00:00 2001
From: Vachan V Y <vachanvy05 at gmail.com>
Date: Thu, 27 Aug 2026 12:41:09 +0530
Subject: [PATCH 1/3] [ValueTracking] Pre-commit tests. NFC

---
 llvm/test/Transforms/InstCombine/div.ll | 68 +++++++++++++++++++++++++
 1 file changed, 68 insertions(+)

diff --git a/llvm/test/Transforms/InstCombine/div.ll b/llvm/test/Transforms/InstCombine/div.ll
index 2adf6036d4bcf..3df78779fc8ed 100644
--- a/llvm/test/Transforms/InstCombine/div.ll
+++ b/llvm/test/Transforms/InstCombine/div.ll
@@ -2033,6 +2033,74 @@ define <2 x i32> @sdiv_select_one_false_poison_vec(<2 x i32> %a, i1 %b) {
   ret <2 x i32> %div
 }
 
+define i32 @sdiv_add_nonneg_guard(i32 %x, i32 %y) {
+; CHECK-LABEL: @sdiv_add_nonneg_guard(
+; CHECK-NEXT:    entry:
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[OR]], -1
+; CHECK-NEXT:    br i1 [[CMP]], label %[[CONT:.*]], label %[[UNREACHABLE:.*]]
+; CHECK:       [[CONT]]:
+; CHECK-NEXT:    [[ADD:%.*]] = add nsw i32 [[Y]], [[X]]
+; CHECK-NEXT:    [[DIV:%.*]] = sdiv i32 [[ADD]], 2
+; CHECK-NEXT:    ret i32 [[DIV]]
+;
+entry:
+  %c0 = icmp slt i32 %x, 0
+  %c1 = icmp slt i32 %y, 0
+  %or = or i1 %c0, %c1
+  br i1 %or, label %unreachable, label %cont
+
+unreachable:
+  unreachable
+
+cont:
+  %add = add nsw i32 %x, %y
+  %div = sdiv i32 %add, 2
+  ret i32 %div
+}
+
+define i32 @sdiv_add3_nonneg_guard(i32 %x, i32 %y, i32 %z) {
+; CHECK-LABEL: @sdiv_add3_nonneg_guard(
+; CHECK:         [[ADD0:%.*]] = add nsw i32 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT:    [[ADD1:%.*]] = add nsw i32 [[ADD0]], [[Z:%.*]]
+; CHECK-NEXT:    [[DIV:%.*]] = sdiv i32 [[ADD1]], 2
+; CHECK-NEXT:    ret i32 [[DIV]]
+;
+entry:
+  %or0 = or i32 %x, %y
+  %or1 = or i32 %or0, %z
+  %cmp = icmp sge i32 %or1, 0
+  br i1 %cmp, label %cont, label %unreachable
+
+unreachable:
+  unreachable
+
+cont:
+  %add0 = add nsw i32 %x, %y
+  %add1 = add nsw i32 %add0, %z
+  %div = sdiv i32 %add1, 2
+  ret i32 %div
+}
+
+define i32 @sdiv_add_or_may_be_negative(i32 %x, i32 %y) {
+; CHECK-LABEL: @sdiv_add_or_may_be_negative(
+; CHECK:         [[DIV:%.*]] = sdiv i32 {{%.*}}, 2
+; CHECK-NEXT:    ret i32 [[DIV]]
+;
+entry:
+  %or = or i32 %x, %y
+  %cmp = icmp sgt i32 %or, -2
+  br i1 %cmp, label %cont, label %unreachable
+
+unreachable:
+  unreachable
+
+cont:
+  %add = add nsw i32 %x, %y
+  %div = sdiv i32 %add, 2
+  ret i32 %div
+}
+
 !0 = !{!"function_entry_count", i64 1000}
 ;.
 ; CHECK: [[META0:![0-9]+]] = !{!"function_entry_count", i64 1000}

>From d2f8b25e9d0a44f761f56e4ea9a3a7e1a7ddce7d Mon Sep 17 00:00:00 2001
From: Vachan V Y <vachanvy05 at gmail.com>
Date: Thu, 27 Aug 2026 12:41:40 +0530
Subject: [PATCH 2/3] [ValueTracking] Optimization + check diff; fix #212382

---
 llvm/lib/Analysis/ValueTracking.cpp     | 37 +++++++++++++++++++++++++
 llvm/test/Transforms/InstCombine/div.ll | 10 +++----
 2 files changed, 42 insertions(+), 5 deletions(-)

diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index efc14f9a639da..4c96aeaee82f7 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -887,6 +887,31 @@ static bool isKnownNonZeroFromAssume(const Value *V, const SimplifyQuery &Q) {
   return false;
 }
 
+static bool visitOrTree(Value *Root,
+                        function_ref<bool(Value *)> VisitOperand) {
+  SmallVector<Value *, 4> Worklist = {Root};
+  SmallPtrSet<Value *, 4> Visited = {Root};
+  while (!Worklist.empty()) {
+    Value *X, *Y;
+    if (!match(Worklist.pop_back_val(), m_Or(m_Value(X), m_Value(Y))))
+      continue;
+
+    for (Value *Op : {X, Y}) {
+      if (!Visited.insert(Op).second)
+        continue;
+      if (VisitOperand(Op))
+        return true;
+      Worklist.push_back(Op);
+    }
+  }
+  return false;
+}
+
+static bool isValueInOrTree(const Value *V, Value *Root) {
+  return V == Root ||
+         visitOrTree(Root, [V](Value *Op) { return V == Op; });
+}
+
 static void computeKnownBitsFromCmp(const Value *V, CmpInst::Predicate Pred,
                                     Value *LHS, Value *RHS, KnownBits &Known,
                                     const SimplifyQuery &Q) {
@@ -989,6 +1014,10 @@ static void computeKnownBitsFromCmp(const Value *V, CmpInst::Predicate Pred,
             (*C - (Pred == ICmpInst::ICMP_ULT)).countLeadingZeros());
       }
     }
+    if (((Pred == ICmpInst::ICMP_SGT && C->isAllOnes()) ||
+         (Pred == ICmpInst::ICMP_SGE && C->isZero())) &&
+        isValueInOrTree(V, LHS))
+      Known.makeNonNegative();
   } break;
   }
 }
@@ -10723,6 +10752,14 @@ void llvm::findValuesAffectedByCondition(
             // X nuw- Y u> C -> X u> C
             if (match(A, m_NUWSub(m_Value(X), m_Value())))
               AddAffected(X);
+          } else if ((Pred == ICmpInst::ICMP_SGT && match(B, m_AllOnes())) ||
+                     (Pred == ICmpInst::ICMP_SGE && match(B, m_Zero()))) {
+            // (or X, Y) sgt -1 or (or X, Y) sge 0 implies that all values in
+            // the or tree are non-negative.
+            visitOrTree(A, [&AddAffected](Value *V) {
+              AddAffected(V);
+              return false;
+            });
           }
         }
 
diff --git a/llvm/test/Transforms/InstCombine/div.ll b/llvm/test/Transforms/InstCombine/div.ll
index 3df78779fc8ed..245b50eec5669 100644
--- a/llvm/test/Transforms/InstCombine/div.ll
+++ b/llvm/test/Transforms/InstCombine/div.ll
@@ -2040,8 +2040,8 @@ define i32 @sdiv_add_nonneg_guard(i32 %x, i32 %y) {
 ; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[OR]], -1
 ; CHECK-NEXT:    br i1 [[CMP]], label %[[CONT:.*]], label %[[UNREACHABLE:.*]]
 ; CHECK:       [[CONT]]:
-; CHECK-NEXT:    [[ADD:%.*]] = add nsw i32 [[Y]], [[X]]
-; CHECK-NEXT:    [[DIV:%.*]] = sdiv i32 [[ADD]], 2
+; CHECK-NEXT:    [[ADD:%.*]] = add nuw nsw i32 [[Y]], [[X]]
+; CHECK-NEXT:    [[DIV:%.*]] = lshr i32 [[ADD]], 1
 ; CHECK-NEXT:    ret i32 [[DIV]]
 ;
 entry:
@@ -2061,9 +2061,9 @@ cont:
 
 define i32 @sdiv_add3_nonneg_guard(i32 %x, i32 %y, i32 %z) {
 ; CHECK-LABEL: @sdiv_add3_nonneg_guard(
-; CHECK:         [[ADD0:%.*]] = add nsw i32 [[Y:%.*]], [[X:%.*]]
-; CHECK-NEXT:    [[ADD1:%.*]] = add nsw i32 [[ADD0]], [[Z:%.*]]
-; CHECK-NEXT:    [[DIV:%.*]] = sdiv i32 [[ADD1]], 2
+; CHECK:         [[ADD0:%.*]] = add nuw nsw i32 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT:    [[ADD1:%.*]] = add nuw nsw i32 [[ADD0]], [[Z:%.*]]
+; CHECK-NEXT:    [[DIV:%.*]] = lshr i32 [[ADD1]], 1
 ; CHECK-NEXT:    ret i32 [[DIV]]
 ;
 entry:

>From 9cff7476f501973743403e9c4106bceacc4cc303 Mon Sep 17 00:00:00 2001
From: Vachan V Y <vachanvy05 at gmail.com>
Date: Thu, 27 Aug 2026 12:57:41 +0530
Subject: [PATCH 3/3] [ValueTracking] format

---
 llvm/lib/Analysis/ValueTracking.cpp | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index f60f590d40523..236872b8a8352 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -889,8 +889,7 @@ static bool isKnownNonZeroFromAssume(const Value *V, const SimplifyQuery &Q) {
   return false;
 }
 
-static bool visitOrTree(Value *Root,
-                        function_ref<bool(Value *)> VisitOperand) {
+static bool visitOrTree(Value *Root, function_ref<bool(Value *)> VisitOperand) {
   SmallVector<Value *, 4> Worklist = {Root};
   SmallPtrSet<Value *, 4> Visited = {Root};
   while (!Worklist.empty()) {
@@ -910,8 +909,7 @@ static bool visitOrTree(Value *Root,
 }
 
 static bool isValueInOrTree(const Value *V, Value *Root) {
-  return V == Root ||
-         visitOrTree(Root, [V](Value *Op) { return V == Op; });
+  return V == Root || visitOrTree(Root, [V](Value *Op) { return V == Op; });
 }
 
 static void computeKnownBitsFromCmp(const Value *V, CmpInst::Predicate Pred,



More information about the llvm-commits mailing list