[llvm] [InstCombine] KnownBits::isNonNegative should recognize `b - a` after `a <= b` (PR #145105)

Ross Kirsling via llvm-commits llvm-commits at lists.llvm.org
Mon Jun 23 12:54:53 PDT 2025


https://github.com/rkirsling updated https://github.com/llvm/llvm-project/pull/145105

>From e6612fe4290bd154e981569b92565f551ce21a21 Mon Sep 17 00:00:00 2001
From: Ross Kirsling <ross.kirsling at sony.com>
Date: Fri, 20 Jun 2025 11:46:11 -0700
Subject: [PATCH 1/8] Add test case.

---
 .../sub-after-sle-is-non-negative.ll          | 53 +++++++++++++++++++
 1 file changed, 53 insertions(+)
 create mode 100644 llvm/test/Transforms/InstCombine/sub-after-sle-is-non-negative.ll

diff --git a/llvm/test/Transforms/InstCombine/sub-after-sle-is-non-negative.ll b/llvm/test/Transforms/InstCombine/sub-after-sle-is-non-negative.ll
new file mode 100644
index 0000000000000..b4427b72ff8a5
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/sub-after-sle-is-non-negative.ll
@@ -0,0 +1,53 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; RUN: opt < %s -passes=instcombine -S | FileCheck %s
+define void @test_as_arg(i8 %a, i8 %b) {
+; CHECK-LABEL: define void @test_as_arg(
+; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]]) {
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i8 [[A]], [[B]]
+; CHECK-NEXT:    br i1 [[CMP]], label %[[COND_END:.*]], label %[[COND_FALSE:.*]]
+; CHECK:       [[COND_FALSE]]:
+; CHECK-NEXT:    [[SUB:%.*]] = sub nsw i8 [[B]], [[A]]
+; CHECK-NEXT:    [[CONV:%.*]] = sext i8 [[SUB]] to i16
+; CHECK-NEXT:    call void @subroutine(i16 [[CONV]])
+; CHECK-NEXT:    br label %[[COND_END]]
+; CHECK:       [[COND_END]]:
+; CHECK-NEXT:    ret void
+;
+  %cmp = icmp sgt i8 %a, %b
+  br i1 %cmp, label %cond.end, label %cond.false
+
+cond.false:
+  %sub = sub nsw i8 %b, %a
+  %conv = sext i8 %sub to i16
+  call void @subroutine(i16 %conv)
+  br label %cond.end
+
+cond.end:
+  ret void
+}
+
+declare void @subroutine(i16)
+
+define i16 @test_as_retval(i8 %a, i8 %b) {
+; CHECK-LABEL: define i16 @test_as_retval(
+; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]]) {
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i8 [[A]], [[B]]
+; CHECK-NEXT:    br i1 [[CMP]], label %[[COND_TRUE:.*]], label %[[COND_FALSE:.*]]
+; CHECK:       [[COND_TRUE]]:
+; CHECK-NEXT:    ret i16 0
+; CHECK:       [[COND_FALSE]]:
+; CHECK-NEXT:    [[SUB:%.*]] = sub nsw i8 [[B]], [[A]]
+; CHECK-NEXT:    [[CONV:%.*]] = sext i8 [[SUB]] to i16
+; CHECK-NEXT:    ret i16 [[CONV]]
+;
+  %cmp = icmp sgt i8 %a, %b
+  br i1 %cmp, label %cond.true, label %cond.false
+
+cond.true:
+  ret i16 0
+
+cond.false:
+  %sub = sub nsw i8 %b, %a
+  %conv = sext i8 %sub to i16
+  ret i16 %conv
+}

>From d80031d1c511b91b86f9333a6a32c24c52b7ad32 Mon Sep 17 00:00:00 2001
From: Ross Kirsling <ross.kirsling at sony.com>
Date: Fri, 20 Jun 2025 11:46:58 -0700
Subject: [PATCH 2/8] Address issue.

---
 llvm/lib/Analysis/ValueTracking.cpp                   | 11 ++++++++++-
 .../InstCombine/sub-after-sle-is-non-negative.ll      |  4 ++--
 2 files changed, 12 insertions(+), 3 deletions(-)

diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 73320b556f825..be9843503298f 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -278,7 +278,16 @@ static bool isKnownNonZero(const Value *V, const APInt &DemandedElts,
 
 bool llvm::isKnownNonNegative(const Value *V, const SimplifyQuery &SQ,
                               unsigned Depth) {
-  return computeKnownBits(V, SQ, Depth).isNonNegative();
+  if (computeKnownBits(V, SQ, Depth).isNonNegative())
+    return true;
+
+  Value *X, *Y;
+  if (match(V, m_NSWSub(m_Value(X), m_Value(Y))))
+    if (std::optional<bool> result =
+            isImpliedByDomCondition(ICmpInst::ICMP_SLE, Y, X, SQ.CxtI, SQ.DL))
+      return *result;
+
+  return false;
 }
 
 bool llvm::isKnownPositive(const Value *V, const SimplifyQuery &SQ,
diff --git a/llvm/test/Transforms/InstCombine/sub-after-sle-is-non-negative.ll b/llvm/test/Transforms/InstCombine/sub-after-sle-is-non-negative.ll
index b4427b72ff8a5..279a6de4125ed 100644
--- a/llvm/test/Transforms/InstCombine/sub-after-sle-is-non-negative.ll
+++ b/llvm/test/Transforms/InstCombine/sub-after-sle-is-non-negative.ll
@@ -7,7 +7,7 @@ define void @test_as_arg(i8 %a, i8 %b) {
 ; CHECK-NEXT:    br i1 [[CMP]], label %[[COND_END:.*]], label %[[COND_FALSE:.*]]
 ; CHECK:       [[COND_FALSE]]:
 ; CHECK-NEXT:    [[SUB:%.*]] = sub nsw i8 [[B]], [[A]]
-; CHECK-NEXT:    [[CONV:%.*]] = sext i8 [[SUB]] to i16
+; CHECK-NEXT:    [[CONV:%.*]] = zext nneg i8 [[SUB]] to i16
 ; CHECK-NEXT:    call void @subroutine(i16 [[CONV]])
 ; CHECK-NEXT:    br label %[[COND_END]]
 ; CHECK:       [[COND_END]]:
@@ -37,7 +37,7 @@ define i16 @test_as_retval(i8 %a, i8 %b) {
 ; CHECK-NEXT:    ret i16 0
 ; CHECK:       [[COND_FALSE]]:
 ; CHECK-NEXT:    [[SUB:%.*]] = sub nsw i8 [[B]], [[A]]
-; CHECK-NEXT:    [[CONV:%.*]] = sext i8 [[SUB]] to i16
+; CHECK-NEXT:    [[CONV:%.*]] = zext nneg i8 [[SUB]] to i16
 ; CHECK-NEXT:    ret i16 [[CONV]]
 ;
   %cmp = icmp sgt i8 %a, %b

>From 905381cae7795093d3a31af58ba7eb155b814f71 Mon Sep 17 00:00:00 2001
From: Ross Kirsling <ross.kirsling at sony.com>
Date: Fri, 20 Jun 2025 21:53:59 -0700
Subject: [PATCH 3/8] rebuild linux


>From 823ede1bea906881208f8e94994d1ff1fec59f53 Mon Sep 17 00:00:00 2001
From: Ross Kirsling <ross.kirsling at sony.com>
Date: Sun, 22 Jun 2025 18:13:18 -0700
Subject: [PATCH 4/8] Add negative tests.

---
 .../sub-after-sle-is-non-negative.ll          | 54 ++++++++++++++++++-
 1 file changed, 52 insertions(+), 2 deletions(-)

diff --git a/llvm/test/Transforms/InstCombine/sub-after-sle-is-non-negative.ll b/llvm/test/Transforms/InstCombine/sub-after-sle-is-non-negative.ll
index 279a6de4125ed..a282236850135 100644
--- a/llvm/test/Transforms/InstCombine/sub-after-sle-is-non-negative.ll
+++ b/llvm/test/Transforms/InstCombine/sub-after-sle-is-non-negative.ll
@@ -1,5 +1,7 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
 ; RUN: opt < %s -passes=instcombine -S | FileCheck %s
+declare void @subroutine(i16)
+
 define void @test_as_arg(i8 %a, i8 %b) {
 ; CHECK-LABEL: define void @test_as_arg(
 ; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]]) {
@@ -26,8 +28,6 @@ cond.end:
   ret void
 }
 
-declare void @subroutine(i16)
-
 define i16 @test_as_retval(i8 %a, i8 %b) {
 ; CHECK-LABEL: define i16 @test_as_retval(
 ; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]]) {
@@ -51,3 +51,53 @@ cond.false:
   %conv = sext i8 %sub to i16
   ret i16 %conv
 }
+
+define void @test_as_arg_neg(i8 %a, i8 %b) {
+; CHECK-LABEL: define void @test_as_arg_neg(
+; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]]) {
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 [[A]], [[B]]
+; CHECK-NEXT:    br i1 [[CMP]], label %[[COND_END:.*]], label %[[COND_FALSE:.*]]
+; CHECK:       [[COND_FALSE]]:
+; CHECK-NEXT:    [[SUB:%.*]] = sub nsw i8 [[B]], [[A]]
+; CHECK-NEXT:    [[CONV:%.*]] = sext i8 [[SUB]] to i16
+; CHECK-NEXT:    call void @subroutine(i16 [[CONV]])
+; CHECK-NEXT:    br label %[[COND_END]]
+; CHECK:       [[COND_END]]:
+; CHECK-NEXT:    ret void
+;
+  %cmp = icmp slt i8 %a, %b
+  br i1 %cmp, label %cond.end, label %cond.false
+
+cond.false:
+  %sub = sub nsw i8 %b, %a
+  %conv = sext i8 %sub to i16
+  call void @subroutine(i16 %conv)
+  br label %cond.end
+
+cond.end:
+  ret void
+}
+
+define i16 @test_as_retval_neg(i8 %a, i8 %b) {
+; CHECK-LABEL: define i16 @test_as_retval_neg(
+; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]]) {
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 [[A]], [[B]]
+; CHECK-NEXT:    br i1 [[CMP]], label %[[COND_TRUE:.*]], label %[[COND_FALSE:.*]]
+; CHECK:       [[COND_TRUE]]:
+; CHECK-NEXT:    ret i16 0
+; CHECK:       [[COND_FALSE]]:
+; CHECK-NEXT:    [[SUB:%.*]] = sub nsw i8 [[B]], [[A]]
+; CHECK-NEXT:    [[CONV:%.*]] = sext i8 [[SUB]] to i16
+; CHECK-NEXT:    ret i16 [[CONV]]
+;
+  %cmp = icmp slt i8 %a, %b
+  br i1 %cmp, label %cond.true, label %cond.false
+
+cond.true:
+  ret i16 0
+
+cond.false:
+  %sub = sub nsw i8 %b, %a
+  %conv = sext i8 %sub to i16
+  ret i16 %conv
+}

>From b4e86030c10c90550e39e48226fc6e87d59f7550 Mon Sep 17 00:00:00 2001
From: Ross Kirsling <ross.kirsling at sony.com>
Date: Sun, 22 Jun 2025 18:20:32 -0700
Subject: [PATCH 5/8] Move logic into computeKnownBits.

---
 llvm/lib/Analysis/ValueTracking.cpp | 17 +++++++----------
 1 file changed, 7 insertions(+), 10 deletions(-)

diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index be9843503298f..bf017ded68b52 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -278,16 +278,7 @@ static bool isKnownNonZero(const Value *V, const APInt &DemandedElts,
 
 bool llvm::isKnownNonNegative(const Value *V, const SimplifyQuery &SQ,
                               unsigned Depth) {
-  if (computeKnownBits(V, SQ, Depth).isNonNegative())
-    return true;
-
-  Value *X, *Y;
-  if (match(V, m_NSWSub(m_Value(X), m_Value(Y))))
-    if (std::optional<bool> result =
-            isImpliedByDomCondition(ICmpInst::ICMP_SLE, Y, X, SQ.CxtI, SQ.DL))
-      return *result;
-
-  return false;
+  return computeKnownBits(V, SQ, Depth).isNonNegative();
 }
 
 bool llvm::isKnownPositive(const Value *V, const SimplifyQuery &SQ,
@@ -371,6 +362,12 @@ static void computeKnownBitsAddSub(bool Add, const Value *Op0, const Value *Op1,
 
   computeKnownBits(Op0, DemandedElts, Known2, Q, Depth + 1);
   KnownOut = KnownBits::computeForAddSub(Add, NSW, NUW, Known2, KnownOut);
+
+  if (!Add && NSW)
+    if (std::optional<bool> result =
+            isImpliedByDomCondition(ICmpInst::ICMP_SLE, Op1, Op0, Q.CxtI, Q.DL);
+        *result)
+      KnownOut.makeNonNegative();
 }
 
 static void computeKnownBitsMul(const Value *Op0, const Value *Op1, bool NSW,

>From 68cb10e5d3b44bf74f7e7da189e95465654443c1 Mon Sep 17 00:00:00 2001
From: Ross Kirsling <ross.kirsling at sony.com>
Date: Sun, 22 Jun 2025 22:15:45 -0700
Subject: [PATCH 6/8] Address feedback

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

diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 5a20169cdc2d9..7cedcad6af862 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -363,11 +363,10 @@ static void computeKnownBitsAddSub(bool Add, const Value *Op0, const Value *Op1,
   computeKnownBits(Op0, DemandedElts, Known2, Q, Depth + 1);
   KnownOut = KnownBits::computeForAddSub(Add, NSW, NUW, Known2, KnownOut);
 
-  if (!Add && NSW)
-    if (std::optional<bool> result =
-            isImpliedByDomCondition(ICmpInst::ICMP_SLE, Op1, Op0, Q.CxtI, Q.DL);
-        *result)
-      KnownOut.makeNonNegative();
+  if (!Add && NSW &&
+      isImpliedByDomCondition(ICmpInst::ICMP_SLE, Op1, Op0, Q.CxtI, Q.DL)
+          .value_or(false))
+    KnownOut.makeNonNegative();
 }
 
 static void computeKnownBitsMul(const Value *Op0, const Value *Op1, bool NSW,

>From 1ecadd1f920f09b566c3e3c80cf0cfa3cb8ae5ee Mon Sep 17 00:00:00 2001
From: Ross Kirsling <ross.kirsling at sony.com>
Date: Mon, 23 Jun 2025 10:45:19 -0700
Subject: [PATCH 7/8] Address nikic's feedback.

---
 llvm/lib/Analysis/ValueTracking.cpp           |  2 +-
 .../sub-after-sle-is-non-negative.ll          | 58 +++++++++++++++++--
 2 files changed, 55 insertions(+), 5 deletions(-)

diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 7cedcad6af862..b226eaf310f3b 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -363,7 +363,7 @@ static void computeKnownBitsAddSub(bool Add, const Value *Op0, const Value *Op1,
   computeKnownBits(Op0, DemandedElts, Known2, Q, Depth + 1);
   KnownOut = KnownBits::computeForAddSub(Add, NSW, NUW, Known2, KnownOut);
 
-  if (!Add && NSW &&
+  if (!Add && NSW && !KnownOut.isNonNegative() &&
       isImpliedByDomCondition(ICmpInst::ICMP_SLE, Op1, Op0, Q.CxtI, Q.DL)
           .value_or(false))
     KnownOut.makeNonNegative();
diff --git a/llvm/test/Transforms/InstCombine/sub-after-sle-is-non-negative.ll b/llvm/test/Transforms/InstCombine/sub-after-sle-is-non-negative.ll
index a282236850135..8395895b1af65 100644
--- a/llvm/test/Transforms/InstCombine/sub-after-sle-is-non-negative.ll
+++ b/llvm/test/Transforms/InstCombine/sub-after-sle-is-non-negative.ll
@@ -52,8 +52,8 @@ cond.false:
   ret i16 %conv
 }
 
-define void @test_as_arg_neg(i8 %a, i8 %b) {
-; CHECK-LABEL: define void @test_as_arg_neg(
+define void @test_as_arg_wrong_icmp(i8 %a, i8 %b) {
+; CHECK-LABEL: define void @test_as_arg_wrong_icmp(
 ; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]]) {
 ; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 [[A]], [[B]]
 ; CHECK-NEXT:    br i1 [[CMP]], label %[[COND_END:.*]], label %[[COND_FALSE:.*]]
@@ -78,8 +78,34 @@ cond.end:
   ret void
 }
 
-define i16 @test_as_retval_neg(i8 %a, i8 %b) {
-; CHECK-LABEL: define i16 @test_as_retval_neg(
+define void @test_as_arg_missing_nsw(i8 %a, i8 %b) {
+; CHECK-LABEL: define void @test_as_arg_missing_nsw(
+; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]]) {
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i8 [[A]], [[B]]
+; CHECK-NEXT:    br i1 [[CMP]], label %[[COND_END:.*]], label %[[COND_FALSE:.*]]
+; CHECK:       [[COND_FALSE]]:
+; CHECK-NEXT:    [[SUB:%.*]] = sub i8 [[B]], [[A]]
+; CHECK-NEXT:    [[CONV:%.*]] = sext i8 [[SUB]] to i16
+; CHECK-NEXT:    call void @subroutine(i16 [[CONV]])
+; CHECK-NEXT:    br label %[[COND_END]]
+; CHECK:       [[COND_END]]:
+; CHECK-NEXT:    ret void
+;
+  %cmp = icmp sgt i8 %a, %b
+  br i1 %cmp, label %cond.end, label %cond.false
+
+cond.false:
+  %sub = sub i8 %b, %a
+  %conv = sext i8 %sub to i16
+  call void @subroutine(i16 %conv)
+  br label %cond.end
+
+cond.end:
+  ret void
+}
+
+define i16 @test_as_retval_wrong_icmp(i8 %a, i8 %b) {
+; CHECK-LABEL: define i16 @test_as_retval_wrong_icmp(
 ; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]]) {
 ; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 [[A]], [[B]]
 ; CHECK-NEXT:    br i1 [[CMP]], label %[[COND_TRUE:.*]], label %[[COND_FALSE:.*]]
@@ -101,3 +127,27 @@ cond.false:
   %conv = sext i8 %sub to i16
   ret i16 %conv
 }
+
+define i16 @test_as_retval_missing_nsw(i8 %a, i8 %b) {
+; CHECK-LABEL: define i16 @test_as_retval_missing_nsw(
+; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]]) {
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i8 [[A]], [[B]]
+; CHECK-NEXT:    br i1 [[CMP]], label %[[COND_TRUE:.*]], label %[[COND_FALSE:.*]]
+; CHECK:       [[COND_TRUE]]:
+; CHECK-NEXT:    ret i16 0
+; CHECK:       [[COND_FALSE]]:
+; CHECK-NEXT:    [[SUB:%.*]] = sub i8 [[B]], [[A]]
+; CHECK-NEXT:    [[CONV:%.*]] = sext i8 [[SUB]] to i16
+; CHECK-NEXT:    ret i16 [[CONV]]
+;
+  %cmp = icmp sgt i8 %a, %b
+  br i1 %cmp, label %cond.true, label %cond.false
+
+cond.true:
+  ret i16 0
+
+cond.false:
+  %sub = sub i8 %b, %a
+  %conv = sext i8 %sub to i16
+  ret i16 %conv
+}

>From 90d0f801d4ba52b0610cb86970949ed6681731cb Mon Sep 17 00:00:00 2001
From: Ross Kirsling <ross.kirsling at sony.com>
Date: Mon, 23 Jun 2025 12:54:38 -0700
Subject: [PATCH 8/8] rebuild linux




More information about the llvm-commits mailing list