diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp index bb0db2d31971d..6128e1284b0fa 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 *L1C; + Value *A, *B; + if (LPred == ICmpInst::ICMP_EQ && ICmpInst::isEquality(RPred) && + 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))) && + 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 0faa7da482ef2..696208b903798 100644 --- a/llvm/test/Transforms/InstCombine/icmp.ll +++ b/llvm/test/Transforms/InstCombine/icmp.ll @@ -6054,3 +6054,189 @@ 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: ret i1 false +; +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: ret i1 false +; +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: ret i1 true +; +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 +} + +; 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:%.*]]) { +; 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: ret i1 false +; +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: ret i1 false +; +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 +}