[llvm] goldsteinn/icmp add or disjoint or (PR #87937)
via llvm-commits
llvm-commits at lists.llvm.org
Sun Apr 7 12:49:33 PDT 2024
https://github.com/goldsteinn created https://github.com/llvm/llvm-project/pull/87937
- **[InstCombine] Add tests for folding `(icmp eq/ne (add nuw x, y), 0)`; NFC**
- **[InstCombine] Fold `(icmp eq/ne (add nuw x, y), 0)` -> `(icmp eq/ne (or x, y), 0)`**
- **[InstCombine] Use existing `(icmp pred (add x, y), C)` folds with `or disjoint`**
>From 12db1e92d007b888ceaf8d2dc838d762bbec6be7 Mon Sep 17 00:00:00 2001
From: Noah Goldstein <goldstein.w.n at gmail.com>
Date: Sun, 7 Apr 2024 14:40:21 -0500
Subject: [PATCH 1/3] [InstCombine] Add tests for folding `(icmp eq/ne (add nuw
x, y), 0)`; NFC
---
llvm/test/Transforms/InstCombine/icmp-add.ll | 51 ++++++++++++++------
1 file changed, 35 insertions(+), 16 deletions(-)
diff --git a/llvm/test/Transforms/InstCombine/icmp-add.ll b/llvm/test/Transforms/InstCombine/icmp-add.ll
index b99ed20d7d431c..950ad3b7647b6a 100644
--- a/llvm/test/Transforms/InstCombine/icmp-add.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-add.ll
@@ -1802,22 +1802,17 @@ define i1 @test4(i32 %a) {
ret i1 %c
}
-define { i32, i1 } @test4multiuse(i32 %a) {
-; CHECK-LABEL: @test4multiuse(
-; CHECK-NEXT: [[B:%.*]] = add nsw i32 [[A:%.*]], -2147483644
-; CHECK-NEXT: [[C:%.*]] = icmp slt i32 [[A]], 2147483640
-; CHECK-NEXT: [[TMP:%.*]] = insertvalue { i32, i1 } undef, i32 [[B]], 0
-; CHECK-NEXT: [[RES:%.*]] = insertvalue { i32, i1 } [[TMP]], i1 [[C]], 1
-; CHECK-NEXT: ret { i32, i1 } [[RES]]
+define {
+i32, i1 } @test4multiuse(i32 %a) {
;
- %b = add nsw i32 %a, -2147483644
- %c = icmp slt i32 %b, -4
+%b = add nsw i32 %a, -2147483644
+%c = icmp slt i32 %b, -4
- %tmp = insertvalue { i32, i1 } undef, i32 %b, 0
- %res = insertvalue { i32, i1 } %tmp, i1 %c, 1
+%tmp = insertvalue { i32, i1 } undef, i32 %b, 0
+%res = insertvalue { i32, i1 } %tmp, i1 %c, 1
- ret { i32, i1 } %res
+ret { i32, i1 } %res
}
define <2 x i1> @test4vec(<2 x i32> %a) {
@@ -2857,7 +2852,7 @@ define i1 @icmp_add_add_C_comm2(i32 %X, i32 %b) {
; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i32 [[A]], [[TMP1]]
; CHECK-NEXT: ret i1 [[CMP]]
;
- %a = udiv i32 42, %X ; thwart complexity-based canonicalization
+ %a = udiv i32 42, %X ; thwart complexity-based canonicalization
%add1 = add i32 %a, %b
%add2 = add i32 %add1, -1
%cmp = icmp ugt i32 %a, %add2
@@ -2871,7 +2866,7 @@ define i1 @icmp_add_add_C_comm2_pred(i32 %X, i32 %b) {
; CHECK-NEXT: [[CMP:%.*]] = icmp ule i32 [[A]], [[TMP1]]
; CHECK-NEXT: ret i1 [[CMP]]
;
- %a = udiv i32 42, %X ; thwart complexity-based canonicalization
+ %a = udiv i32 42, %X ; thwart complexity-based canonicalization
%add1 = add i32 %a, %b
%add2 = add i32 %add1, -1
%cmp = icmp ule i32 %a, %add2
@@ -2886,7 +2881,7 @@ define i1 @icmp_add_add_C_comm2_wrong_pred(i32 %X, i32 %b) {
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[A]], [[ADD2]]
; CHECK-NEXT: ret i1 [[CMP]]
;
- %a = udiv i32 42, %X ; thwart complexity-based canonicalization
+ %a = udiv i32 42, %X ; thwart complexity-based canonicalization
%add1 = add i32 %a, %b
%add2 = add i32 %add1, -1
%cmp = icmp ult i32 %a, %add2
@@ -2900,7 +2895,7 @@ define i1 @icmp_add_add_C_comm3(i32 %X, i32 %b) {
; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i32 [[A]], [[TMP1]]
; CHECK-NEXT: ret i1 [[CMP]]
;
- %a = udiv i32 42, %X ; thwart complexity-based canonicalization
+ %a = udiv i32 42, %X ; thwart complexity-based canonicalization
%add1 = add i32 %b, %a
%add2 = add i32 %add1, -1
%cmp = icmp ugt i32 %a, %add2
@@ -3003,4 +2998,28 @@ define i1 @icmp_dec_notnonzero(i8 %x) {
ret i1 %c
}
+define i1 @icmp_addnuw_nonzero(i8 %x, i8 %y) {
+; CHECK-LABEL: @icmp_addnuw_nonzero(
+; CHECK-NEXT: [[I:%.*]] = sub i8 0, [[Y:%.*]]
+; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[I]], [[X:%.*]]
+; CHECK-NEXT: ret i1 [[C]]
+;
+ %i = add nuw i8 %x, %y
+ %c = icmp eq i8 %i, 0
+ ret i1 %c
+}
+
+define i1 @icmp_addnuw_nonzero_fail_multiuse(i32 %x, i32 %y) {
+; CHECK-LABEL: @icmp_addnuw_nonzero_fail_multiuse(
+; CHECK-NEXT: [[I:%.*]] = add nuw i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: [[C:%.*]] = icmp eq i32 [[I]], 0
+; CHECK-NEXT: call void @use(i32 [[I]])
+; CHECK-NEXT: ret i1 [[C]]
+;
+ %i = add nuw i32 %x, %y
+ %c = icmp eq i32 %i, 0
+ call void @use(i32 %i)
+ ret i1 %c
+}
+
declare void @llvm.assume(i1)
>From 820b35974fa66374ab63a7fd6414ef91bda23f6e Mon Sep 17 00:00:00 2001
From: Noah Goldstein <goldstein.w.n at gmail.com>
Date: Sun, 7 Apr 2024 14:38:03 -0500
Subject: [PATCH 2/3] [InstCombine] Fold `(icmp eq/ne (add nuw x, y), 0)` ->
`(icmp eq/ne (or x, y), 0)`
`(icmp eq/ne (or x, y), 0)` is probably easier to analyze than `(icmp
eq/ne x, -y)`
Proof: https://alive2.llvm.org/ce/z/2-VTb6
---
.../InstCombine/InstCombineCompares.cpp | 5 +++++
llvm/test/Transforms/InstCombine/icmp-add.ll | 16 ++++++----------
2 files changed, 11 insertions(+), 10 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index db302d7e526844..53aa84d53f3085 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -3453,6 +3453,11 @@ Instruction *InstCombinerImpl::foldICmpBinOpEqualityWithConstant(
if (Value *NegVal = dyn_castNegVal(BOp0))
return new ICmpInst(Pred, NegVal, BOp1);
if (BO->hasOneUse()) {
+ // (add nuw A, B) != 0 -> (or A, B) != 0
+ if (match(BO, m_NUWAdd(m_Value(), m_Value()))) {
+ Value *Or = Builder.CreateOr(BOp0, BOp1);
+ return new ICmpInst(Pred, Or, Constant::getNullValue(BO->getType()));
+ }
Value *Neg = Builder.CreateNeg(BOp1);
Neg->takeName(BO);
return new ICmpInst(Pred, BOp0, Neg);
diff --git a/llvm/test/Transforms/InstCombine/icmp-add.ll b/llvm/test/Transforms/InstCombine/icmp-add.ll
index 950ad3b7647b6a..e71a3af4b5be4f 100644
--- a/llvm/test/Transforms/InstCombine/icmp-add.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-add.ll
@@ -9,10 +9,8 @@ declare void @use(i32)
define i1 @cvt_icmp_0_zext_plus_zext_eq_i16(i16 %arg, i16 %arg1) {
; CHECK-LABEL: @cvt_icmp_0_zext_plus_zext_eq_i16(
; CHECK-NEXT: bb:
-; CHECK-NEXT: [[I:%.*]] = zext i16 [[ARG:%.*]] to i32
-; CHECK-NEXT: [[I2:%.*]] = zext i16 [[ARG1:%.*]] to i32
-; CHECK-NEXT: [[I3:%.*]] = sub nsw i32 0, [[I]]
-; CHECK-NEXT: [[I4:%.*]] = icmp eq i32 [[I2]], [[I3]]
+; CHECK-NEXT: [[TMP0:%.*]] = or i16 [[ARG1:%.*]], [[ARG:%.*]]
+; CHECK-NEXT: [[I4:%.*]] = icmp eq i16 [[TMP0]], 0
; CHECK-NEXT: ret i1 [[I4]]
;
bb:
@@ -27,10 +25,8 @@ bb:
define i1 @cvt_icmp_0_zext_plus_zext_eq_i8(i8 %arg, i8 %arg1) {
; CHECK-LABEL: @cvt_icmp_0_zext_plus_zext_eq_i8(
; CHECK-NEXT: bb:
-; CHECK-NEXT: [[I:%.*]] = zext i8 [[ARG:%.*]] to i32
-; CHECK-NEXT: [[I2:%.*]] = zext i8 [[ARG1:%.*]] to i32
-; CHECK-NEXT: [[I3:%.*]] = sub nsw i32 0, [[I]]
-; CHECK-NEXT: [[I4:%.*]] = icmp eq i32 [[I2]], [[I3]]
+; CHECK-NEXT: [[TMP0:%.*]] = or i8 [[ARG1:%.*]], [[ARG:%.*]]
+; CHECK-NEXT: [[I4:%.*]] = icmp eq i8 [[TMP0]], 0
; CHECK-NEXT: ret i1 [[I4]]
;
bb:
@@ -3000,8 +2996,8 @@ define i1 @icmp_dec_notnonzero(i8 %x) {
define i1 @icmp_addnuw_nonzero(i8 %x, i8 %y) {
; CHECK-LABEL: @icmp_addnuw_nonzero(
-; CHECK-NEXT: [[I:%.*]] = sub i8 0, [[Y:%.*]]
-; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[I]], [[X:%.*]]
+; CHECK-NEXT: [[TMP1:%.*]] = or i8 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[TMP1]], 0
; CHECK-NEXT: ret i1 [[C]]
;
%i = add nuw i8 %x, %y
>From 337903cc5320c9fb80d905def958a4ebe912293d Mon Sep 17 00:00:00 2001
From: Noah Goldstein <goldstein.w.n at gmail.com>
Date: Sun, 7 Apr 2024 14:37:07 -0500
Subject: [PATCH 3/3] [InstCombine] Use existing `(icmp pred (add x, y), C)`
folds with `or disjoint`
No significant changes, just some missed plumbing.
---
.../InstCombine/InstCombineCompares.cpp | 50 ++++++++++---------
.../test/Transforms/InstCombine/known-bits.ll | 3 +-
2 files changed, 28 insertions(+), 25 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index 53aa84d53f3085..f805fc21f97de6 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -2986,10 +2986,10 @@ Instruction *InstCombinerImpl::foldICmpAddConstant(ICmpInst &Cmp,
Value *Op0, *Op1;
Instruction *Ext0, *Ext1;
const CmpInst::Predicate Pred = Cmp.getPredicate();
- if (match(Add,
- m_Add(m_CombineAnd(m_Instruction(Ext0), m_ZExtOrSExt(m_Value(Op0))),
- m_CombineAnd(m_Instruction(Ext1),
- m_ZExtOrSExt(m_Value(Op1))))) &&
+ if (match(Add, m_AddLike(m_CombineAnd(m_Instruction(Ext0),
+ m_ZExtOrSExt(m_Value(Op0))),
+ m_CombineAnd(m_Instruction(Ext1),
+ m_ZExtOrSExt(m_Value(Op1))))) &&
Op0->getType()->isIntOrIntVectorTy(1) &&
Op1->getType()->isIntOrIntVectorTy(1)) {
unsigned BW = C.getBitWidth();
@@ -3021,9 +3021,9 @@ Instruction *InstCombinerImpl::foldICmpAddConstant(ICmpInst &Cmp,
// If the add does not wrap, we can always adjust the compare by subtracting
// the constants. Equality comparisons are handled elsewhere. SGE/SLE/UGE/ULE
// are canonicalized to SGT/SLT/UGT/ULT.
- if ((Add->hasNoSignedWrap() &&
+ if ((match(Add, m_NSWAddLike(m_Value(), m_Value())) &&
(Pred == ICmpInst::ICMP_SGT || Pred == ICmpInst::ICMP_SLT)) ||
- (Add->hasNoUnsignedWrap() &&
+ (match(Add, m_NUWAddLike(m_Value(), m_Value())) &&
(Pred == ICmpInst::ICMP_UGT || Pred == ICmpInst::ICMP_ULT))) {
bool Overflow;
APInt NewC =
@@ -3438,6 +3438,20 @@ Instruction *InstCombinerImpl::foldICmpBinOpEqualityWithConstant(
}
}
break;
+ case Instruction::Or: {
+ const APInt *BOC;
+ if (match(BOp1, m_APInt(BOC)) && BO->hasOneUse() && RHS->isAllOnesValue()) {
+ // Comparing if all bits outside of a constant mask are set?
+ // Replace (X | C) == -1 with (X & ~C) == ~C.
+ // This removes the -1 constant.
+ Constant *NotBOC = ConstantExpr::getNot(cast<Constant>(BOp1));
+ Value *And = Builder.CreateAnd(BOp0, NotBOC);
+ return new ICmpInst(Pred, And, NotBOC);
+ }
+ if (!cast<PossiblyDisjointInst>(BO)->isDisjoint())
+ break;
+ [[fallthrough]];
+ }
case Instruction::Add: {
// (A + C2) == C --> A == (C - C2)
// (A + C2) != C --> A != (C - C2)
@@ -3452,7 +3466,7 @@ Instruction *InstCombinerImpl::foldICmpBinOpEqualityWithConstant(
return new ICmpInst(Pred, BOp0, NegVal);
if (Value *NegVal = dyn_castNegVal(BOp0))
return new ICmpInst(Pred, NegVal, BOp1);
- if (BO->hasOneUse()) {
+ if (BO->hasOneUse() && BO->getOpcode() != Instruction::Or) {
// (add nuw A, B) != 0 -> (or A, B) != 0
if (match(BO, m_NUWAdd(m_Value(), m_Value()))) {
Value *Or = Builder.CreateOr(BOp0, BOp1);
@@ -3477,18 +3491,6 @@ Instruction *InstCombinerImpl::foldICmpBinOpEqualityWithConstant(
}
}
break;
- case Instruction::Or: {
- const APInt *BOC;
- if (match(BOp1, m_APInt(BOC)) && BO->hasOneUse() && RHS->isAllOnesValue()) {
- // Comparing if all bits outside of a constant mask are set?
- // Replace (X | C) == -1 with (X & ~C) == ~C.
- // This removes the -1 constant.
- Constant *NotBOC = ConstantExpr::getNot(cast<Constant>(BOp1));
- Value *And = Builder.CreateAnd(BOp0, NotBOC);
- return new ICmpInst(Pred, And, NotBOC);
- }
- break;
- }
case Instruction::UDiv:
case Instruction::SDiv:
if (BO->isExact()) {
@@ -3761,10 +3763,6 @@ Instruction *InstCombinerImpl::foldICmpBinOpWithConstant(ICmpInst &Cmp,
if (Instruction *I = foldICmpAndConstant(Cmp, BO, C))
return I;
break;
- case Instruction::Or:
- if (Instruction *I = foldICmpOrConstant(Cmp, BO, C))
- return I;
- break;
case Instruction::Mul:
if (Instruction *I = foldICmpMulConstant(Cmp, BO, C))
return I;
@@ -3794,6 +3792,12 @@ Instruction *InstCombinerImpl::foldICmpBinOpWithConstant(ICmpInst &Cmp,
if (Instruction *I = foldICmpSubConstant(Cmp, BO, C))
return I;
break;
+ case Instruction::Or:
+ if (Instruction *I = foldICmpOrConstant(Cmp, BO, C))
+ return I;
+ if (!cast<PossiblyDisjointInst>(BO)->isDisjoint())
+ break;
+ [[fallthrough]];
case Instruction::Add:
if (Instruction *I = foldICmpAddConstant(Cmp, BO, C))
return I;
diff --git a/llvm/test/Transforms/InstCombine/known-bits.ll b/llvm/test/Transforms/InstCombine/known-bits.ll
index 769f7661fc8dc0..ba5619a25a49df 100644
--- a/llvm/test/Transforms/InstCombine/known-bits.ll
+++ b/llvm/test/Transforms/InstCombine/known-bits.ll
@@ -483,8 +483,7 @@ if.else:
define i1 @test_icmp_or_distjoint(i8 %n, i1 %other) {
; CHECK-LABEL: @test_icmp_or_distjoint(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[N_OR:%.*]] = or disjoint i8 [[N:%.*]], 16
-; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i8 [[N_OR]], -111
+; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i8 [[N:%.*]], -127
; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
; CHECK: if.then:
; CHECK-NEXT: ret i1 true
More information about the llvm-commits
mailing list