[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