From 45d08242891cad9f9698a602efe6226d5632002f Mon Sep 17 00:00:00 2001 From: Yingwei Zheng 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 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 >_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 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))) &&