[llvm] [ValueTracking] a - b == NonZero -> a != b (PR #159792)

Yingwei Zheng via llvm-commits llvm-commits at lists.llvm.org
Fri Sep 19 22:52:01 PDT 2025


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

>From 45d08242891cad9f9698a602efe6226d5632002f Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Fri, 19 Sep 2025 22:29:14 +0800
Subject: [PATCH 1/3] [ValueTracking] Add pre-commit tests. NFC.

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

diff --git a/llvm/test/Transforms/InstCombine/icmp.ll b/llvm/test/Transforms/InstCombine/icmp.ll
index 0faa7da482ef2..47fe755ad723d 100644
--- a/llvm/test/Transforms/InstCombine/icmp.ll
+++ b/llvm/test/Transforms/InstCombine/icmp.ll
@@ -6054,3 +6054,193 @@ define i1 @icmp_samesign_logical_or(i32 %In) {
   %V = select i1 %c1, i1 true, i1 %c2
   ret i1 %V
 }
+
+define i1 @non_zero_ptrdiff_implies_icmp_eq(ptr %p0, ptr %p1) {
+; CHECK-LABEL: define i1 @non_zero_ptrdiff_implies_icmp_eq(
+; CHECK-SAME: ptr [[P0:%.*]], ptr [[P1:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[I0:%.*]] = ptrtoint ptr [[P0]] to i64
+; CHECK-NEXT:    [[I1:%.*]] = ptrtoint ptr [[P1]] to i64
+; CHECK-NEXT:    [[DIFF:%.*]] = sub i64 [[I0]], [[I1]]
+; CHECK-NEXT:    [[COND:%.*]] = icmp eq i64 [[DIFF]], 12
+; CHECK-NEXT:    call void @llvm.assume(i1 [[COND]])
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq ptr [[P0]], [[P1]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+entry:
+  %i0 = ptrtoint ptr %p0 to i64
+  %i1 = ptrtoint ptr %p1 to i64
+  %diff = sub i64 %i0, %i1
+  %cond = icmp eq i64 %diff, 12
+  call void @llvm.assume(i1 %cond)
+  %cmp = icmp eq ptr %p0, %p1
+  ret i1 %cmp
+}
+
+define i1 @non_zero_ptrdiff_implies_icmp_eq_commuted(ptr %p0, ptr %p1) {
+; CHECK-LABEL: define i1 @non_zero_ptrdiff_implies_icmp_eq_commuted(
+; CHECK-SAME: ptr [[P0:%.*]], ptr [[P1:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[I0:%.*]] = ptrtoint ptr [[P0]] to i64
+; CHECK-NEXT:    [[I1:%.*]] = ptrtoint ptr [[P1]] to i64
+; CHECK-NEXT:    [[DIFF:%.*]] = sub i64 [[I0]], [[I1]]
+; CHECK-NEXT:    [[COND:%.*]] = icmp eq i64 [[DIFF]], 12
+; CHECK-NEXT:    call void @llvm.assume(i1 [[COND]])
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq ptr [[P1]], [[P0]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+entry:
+  %i0 = ptrtoint ptr %p0 to i64
+  %i1 = ptrtoint ptr %p1 to i64
+  %diff = sub i64 %i0, %i1
+  %cond = icmp eq i64 %diff, 12
+  call void @llvm.assume(i1 %cond)
+  %cmp = icmp eq ptr %p1, %p0
+  ret i1 %cmp
+}
+
+define i1 @non_zero_ptrdiff_implies_icmp_ne(ptr %p0, ptr %p1) {
+; CHECK-LABEL: define i1 @non_zero_ptrdiff_implies_icmp_ne(
+; CHECK-SAME: ptr [[P0:%.*]], ptr [[P1:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[I0:%.*]] = ptrtoint ptr [[P0]] to i64
+; CHECK-NEXT:    [[I1:%.*]] = ptrtoint ptr [[P1]] to i64
+; CHECK-NEXT:    [[DIFF:%.*]] = sub i64 [[I0]], [[I1]]
+; CHECK-NEXT:    [[COND:%.*]] = icmp eq i64 [[DIFF]], 12
+; CHECK-NEXT:    call void @llvm.assume(i1 [[COND]])
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne ptr [[P0]], [[P1]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+entry:
+  %i0 = ptrtoint ptr %p0 to i64
+  %i1 = ptrtoint ptr %p1 to i64
+  %diff = sub i64 %i0, %i1
+  %cond = icmp eq i64 %diff, 12
+  call void @llvm.assume(i1 %cond)
+  %cmp = icmp ne ptr %p0, %p1
+  ret i1 %cmp
+}
+
+define i1 @non_zero_truncated_ptrdiff_implies_icmp_ne(ptr %p0, ptr %p1) {
+; CHECK-LABEL: define i1 @non_zero_truncated_ptrdiff_implies_icmp_ne(
+; CHECK-SAME: ptr [[P0:%.*]], ptr [[P1:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[TMP0:%.*]] = ptrtoint ptr [[P0]] to i64
+; CHECK-NEXT:    [[I0:%.*]] = trunc i64 [[TMP0]] to i8
+; CHECK-NEXT:    [[TMP1:%.*]] = ptrtoint ptr [[P1]] to i64
+; CHECK-NEXT:    [[I1:%.*]] = trunc i64 [[TMP1]] to i8
+; CHECK-NEXT:    [[DIFF:%.*]] = sub i8 [[I0]], [[I1]]
+; CHECK-NEXT:    [[COND:%.*]] = icmp eq i8 [[DIFF]], 12
+; CHECK-NEXT:    call void @llvm.assume(i1 [[COND]])
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne ptr [[P0]], [[P1]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+entry:
+  %i0 = ptrtoint ptr %p0 to i8
+  %i1 = ptrtoint ptr %p1 to i8
+  %diff = sub i8 %i0, %i1
+  %cond = icmp eq i8 %diff, 12
+  call void @llvm.assume(i1 %cond)
+  %cmp = icmp ne ptr %p0, %p1
+  ret i1 %cmp
+}
+
+define i1 @non_zero_diff_implies_icmp_eq(i8 %p0, i8 %p1) {
+; CHECK-LABEL: define i1 @non_zero_diff_implies_icmp_eq(
+; CHECK-SAME: i8 [[P0:%.*]], i8 [[P1:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[DIFF:%.*]] = sub i8 [[P0]], [[P1]]
+; CHECK-NEXT:    [[COND:%.*]] = icmp eq i8 [[DIFF]], 12
+; CHECK-NEXT:    call void @llvm.assume(i1 [[COND]])
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 [[P0]], [[P1]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+entry:
+  %diff = sub i8 %p0, %p1
+  %cond = icmp eq i8 %diff, 12
+  call void @llvm.assume(i1 %cond)
+  %cmp = icmp eq i8 %p0, %p1
+  ret i1 %cmp
+}
+
+define i1 @non_zero_diff_implies_icmp_eq_commuted(i8 %p0, i8 %p1) {
+; CHECK-LABEL: define i1 @non_zero_diff_implies_icmp_eq_commuted(
+; CHECK-SAME: i8 [[P0:%.*]], i8 [[P1:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[DIFF:%.*]] = sub i8 [[P0]], [[P1]]
+; CHECK-NEXT:    [[COND:%.*]] = icmp eq i8 [[DIFF]], 12
+; CHECK-NEXT:    call void @llvm.assume(i1 [[COND]])
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 [[P1]], [[P0]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+entry:
+  %diff = sub i8 %p0, %p1
+  %cond = icmp eq i8 %diff, 12
+  call void @llvm.assume(i1 %cond)
+  %cmp = icmp eq i8 %p1, %p0
+  ret i1 %cmp
+}
+
+; Negative tests
+
+define i1 @unknown_ptrdiff_implies_icmp_eq1(ptr %p0, ptr %p1) {
+; CHECK-LABEL: define i1 @unknown_ptrdiff_implies_icmp_eq1(
+; CHECK-SAME: ptr [[P0:%.*]], ptr [[P1:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[I0:%.*]] = ptrtoint ptr [[P0]] to i64
+; CHECK-NEXT:    [[I1:%.*]] = ptrtoint ptr [[P1]] to i64
+; CHECK-NEXT:    [[DIFF:%.*]] = sub i64 [[I0]], [[I1]]
+; CHECK-NEXT:    [[COND:%.*]] = icmp ne i64 [[DIFF]], 12
+; CHECK-NEXT:    call void @llvm.assume(i1 [[COND]])
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq ptr [[P0]], [[P1]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+entry:
+  %i0 = ptrtoint ptr %p0 to i64
+  %i1 = ptrtoint ptr %p1 to i64
+  %diff = sub i64 %i0, %i1
+  %cond = icmp ne i64 %diff, 12
+  call void @llvm.assume(i1 %cond)
+  %cmp = icmp eq ptr %p0, %p1
+  ret i1 %cmp
+}
+
+define i1 @unknown_ptrdiff_implies_icmp_eq2(ptr %p0, ptr %p1, i64 %x) {
+; CHECK-LABEL: define i1 @unknown_ptrdiff_implies_icmp_eq2(
+; CHECK-SAME: ptr [[P0:%.*]], ptr [[P1:%.*]], i64 [[X:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[I0:%.*]] = ptrtoint ptr [[P0]] to i64
+; CHECK-NEXT:    [[I1:%.*]] = ptrtoint ptr [[P1]] to i64
+; CHECK-NEXT:    [[DIFF:%.*]] = sub i64 [[I0]], [[I1]]
+; CHECK-NEXT:    [[COND:%.*]] = icmp eq i64 [[DIFF]], [[X]]
+; CHECK-NEXT:    call void @llvm.assume(i1 [[COND]])
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq ptr [[P0]], [[P1]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+entry:
+  %i0 = ptrtoint ptr %p0 to i64
+  %i1 = ptrtoint ptr %p1 to i64
+  %diff = sub i64 %i0, %i1
+  %cond = icmp eq i64 %diff, %x
+  call void @llvm.assume(i1 %cond)
+  %cmp = icmp eq ptr %p0, %p1
+  ret i1 %cmp
+}
+
+define i1 @non_zero_diff_implies_icmp_ult(i8 %p0, i8 %p1) {
+; CHECK-LABEL: define i1 @non_zero_diff_implies_icmp_ult(
+; CHECK-SAME: i8 [[P0:%.*]], i8 [[P1:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[DIFF:%.*]] = sub i8 [[P0]], [[P1]]
+; CHECK-NEXT:    [[COND:%.*]] = icmp eq i8 [[DIFF]], 12
+; CHECK-NEXT:    call void @llvm.assume(i1 [[COND]])
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i8 [[P0]], [[P1]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+entry:
+  %diff = sub i8 %p0, %p1
+  %cond = icmp eq i8 %diff, 12
+  call void @llvm.assume(i1 %cond)
+  %cmp = icmp ult i8 %p0, %p1
+  ret i1 %cmp
+}

>From e2bbe018184279ca159b7b2bf84b7183d99ba480 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Fri, 19 Sep 2025 22:46:32 +0800
Subject: [PATCH 2/3] [ValueTracking] a - b == NonZero -> a != b

---
 llvm/lib/Analysis/ValueTracking.cpp      | 22 +++++++++++++++++++++-
 llvm/test/Transforms/InstCombine/icmp.ll | 16 ++++++----------
 2 files changed, 27 insertions(+), 11 deletions(-)

diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index bb0db2d31971d..48167e3777447 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -9425,6 +9425,21 @@ isImpliedCondICmps(CmpPredicate LPred, const Value *L0, const Value *L1,
       return true;
   }
 
+  // a - b == NonZero -> a != b
+  // ptrtoint(a) - ptrtoint(b) == NonZero -> a != b
+  const APInt *RHSC;
+  Value *A, *B;
+  if (LPred == ICmpInst::ICMP_EQ && ICmpInst::isEquality(RPred) &&
+      match(L1, m_APInt(RHSC)) && !RHSC->isZero() &&
+      match(L0, m_Sub(m_Value(A), m_Value(B))) &&
+      ((A == R0 && B == R1) || (A == R1 && B == R0) ||
+       (match(A, m_PtrToInt(m_Specific(R0))) &&
+        match(B, m_PtrToInt(m_Specific(R1)))) ||
+       (match(A, m_PtrToInt(m_Specific(R1))) &&
+        match(B, m_PtrToInt(m_Specific(R0)))))) {
+    return RPred.dropSameSign() == ICmpInst::ICMP_NE;
+  }
+
   // L0 = R0 = L1 + R1, L0 >=u L1 implies R0 >=u R1, L0 <u L1 implies R0 <u R1
   if (L0 == R0 &&
       (LPred == ICmpInst::ICMP_ULT || LPred == ICmpInst::ICMP_UGE) &&
@@ -10180,15 +10195,20 @@ void llvm::findValuesAffectedByCondition(
           AddAffected(B);
         if (HasRHSC) {
           Value *Y;
-          // (X & C) or (X | C).
           // (X << C) or (X >>_s C) or (X >>_u C).
           if (match(A, m_Shift(m_Value(X), m_ConstantInt())))
             AddAffected(X);
+          // (X & C) or (X | C).
           else if (match(A, m_And(m_Value(X), m_Value(Y))) ||
                    match(A, m_Or(m_Value(X), m_Value(Y)))) {
             AddAffected(X);
             AddAffected(Y);
           }
+          // X - Y
+          else if (match(A, m_Sub(m_Value(X), m_Value(Y)))) {
+            AddAffected(X);
+            AddAffected(Y);
+          }
         }
       } else {
         AddCmpOperands(A, B);
diff --git a/llvm/test/Transforms/InstCombine/icmp.ll b/llvm/test/Transforms/InstCombine/icmp.ll
index 47fe755ad723d..696208b903798 100644
--- a/llvm/test/Transforms/InstCombine/icmp.ll
+++ b/llvm/test/Transforms/InstCombine/icmp.ll
@@ -6064,8 +6064,7 @@ define i1 @non_zero_ptrdiff_implies_icmp_eq(ptr %p0, ptr %p1) {
 ; CHECK-NEXT:    [[DIFF:%.*]] = sub i64 [[I0]], [[I1]]
 ; CHECK-NEXT:    [[COND:%.*]] = icmp eq i64 [[DIFF]], 12
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[COND]])
-; CHECK-NEXT:    [[CMP:%.*]] = icmp eq ptr [[P0]], [[P1]]
-; CHECK-NEXT:    ret i1 [[CMP]]
+; CHECK-NEXT:    ret i1 false
 ;
 entry:
   %i0 = ptrtoint ptr %p0 to i64
@@ -6086,8 +6085,7 @@ define i1 @non_zero_ptrdiff_implies_icmp_eq_commuted(ptr %p0, ptr %p1) {
 ; CHECK-NEXT:    [[DIFF:%.*]] = sub i64 [[I0]], [[I1]]
 ; CHECK-NEXT:    [[COND:%.*]] = icmp eq i64 [[DIFF]], 12
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[COND]])
-; CHECK-NEXT:    [[CMP:%.*]] = icmp eq ptr [[P1]], [[P0]]
-; CHECK-NEXT:    ret i1 [[CMP]]
+; CHECK-NEXT:    ret i1 false
 ;
 entry:
   %i0 = ptrtoint ptr %p0 to i64
@@ -6108,8 +6106,7 @@ define i1 @non_zero_ptrdiff_implies_icmp_ne(ptr %p0, ptr %p1) {
 ; CHECK-NEXT:    [[DIFF:%.*]] = sub i64 [[I0]], [[I1]]
 ; CHECK-NEXT:    [[COND:%.*]] = icmp eq i64 [[DIFF]], 12
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[COND]])
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ne ptr [[P0]], [[P1]]
-; CHECK-NEXT:    ret i1 [[CMP]]
+; CHECK-NEXT:    ret i1 true
 ;
 entry:
   %i0 = ptrtoint ptr %p0 to i64
@@ -6121,6 +6118,7 @@ entry:
   ret i1 %cmp
 }
 
+; TODO: Handle this case if it is shown in real code.
 define i1 @non_zero_truncated_ptrdiff_implies_icmp_ne(ptr %p0, ptr %p1) {
 ; CHECK-LABEL: define i1 @non_zero_truncated_ptrdiff_implies_icmp_ne(
 ; CHECK-SAME: ptr [[P0:%.*]], ptr [[P1:%.*]]) {
@@ -6152,8 +6150,7 @@ define i1 @non_zero_diff_implies_icmp_eq(i8 %p0, i8 %p1) {
 ; CHECK-NEXT:    [[DIFF:%.*]] = sub i8 [[P0]], [[P1]]
 ; CHECK-NEXT:    [[COND:%.*]] = icmp eq i8 [[DIFF]], 12
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[COND]])
-; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 [[P0]], [[P1]]
-; CHECK-NEXT:    ret i1 [[CMP]]
+; CHECK-NEXT:    ret i1 false
 ;
 entry:
   %diff = sub i8 %p0, %p1
@@ -6170,8 +6167,7 @@ define i1 @non_zero_diff_implies_icmp_eq_commuted(i8 %p0, i8 %p1) {
 ; CHECK-NEXT:    [[DIFF:%.*]] = sub i8 [[P0]], [[P1]]
 ; CHECK-NEXT:    [[COND:%.*]] = icmp eq i8 [[DIFF]], 12
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[COND]])
-; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 [[P1]], [[P0]]
-; CHECK-NEXT:    ret i1 [[CMP]]
+; CHECK-NEXT:    ret i1 false
 ;
 entry:
   %diff = sub i8 %p0, %p1

>From eb18e43d54c17c8ac9015dddee2650274f24e568 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Sat, 20 Sep 2025 13:51:42 +0800
Subject: [PATCH 3/3] [ValueTracking] Rename RHSC to L1C. NFC.

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

diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 48167e3777447..6128e1284b0fa 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -9427,10 +9427,10 @@ isImpliedCondICmps(CmpPredicate LPred, const Value *L0, const Value *L1,
 
   // a - b == NonZero -> a != b
   // ptrtoint(a) - ptrtoint(b) == NonZero -> a != b
-  const APInt *RHSC;
+  const APInt *L1C;
   Value *A, *B;
   if (LPred == ICmpInst::ICMP_EQ && ICmpInst::isEquality(RPred) &&
-      match(L1, m_APInt(RHSC)) && !RHSC->isZero() &&
+      match(L1, m_APInt(L1C)) && !L1C->isZero() &&
       match(L0, m_Sub(m_Value(A), m_Value(B))) &&
       ((A == R0 && B == R1) || (A == R1 && B == R0) ||
        (match(A, m_PtrToInt(m_Specific(R0))) &&



More information about the llvm-commits mailing list