Skip to content

Commit 8773c9b

Browse files
authored
[InstCombine] Extend foldICmpBinOp to add-like or. (llvm#71396)
InstCombine canonicalizes `add` to `or` when possible, but this makes some optimizations applicable to `add` to be missed because they don't realize that the `or` is equivalent to `add`. In this patch we generalize `foldICmpBinOp` to handle such cases.
1 parent cf4dd91 commit 8773c9b

File tree

2 files changed

+126
-53
lines changed

2 files changed

+126
-53
lines changed

llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp

Lines changed: 33 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -4624,27 +4624,35 @@ Instruction *InstCombinerImpl::foldICmpBinOp(ICmpInst &I,
46244624
}
46254625

46264626
bool NoOp0WrapProblem = false, NoOp1WrapProblem = false;
4627-
if (BO0 && isa<OverflowingBinaryOperator>(BO0))
4628-
NoOp0WrapProblem =
4629-
ICmpInst::isEquality(Pred) ||
4630-
(CmpInst::isUnsigned(Pred) && BO0->hasNoUnsignedWrap()) ||
4631-
(CmpInst::isSigned(Pred) && BO0->hasNoSignedWrap());
4632-
if (BO1 && isa<OverflowingBinaryOperator>(BO1))
4633-
NoOp1WrapProblem =
4634-
ICmpInst::isEquality(Pred) ||
4635-
(CmpInst::isUnsigned(Pred) && BO1->hasNoUnsignedWrap()) ||
4636-
(CmpInst::isSigned(Pred) && BO1->hasNoSignedWrap());
4637-
4627+
bool Op0HasNUW = false, Op1HasNUW = false;
4628+
bool Op0HasNSW = false, Op1HasNSW = false;
46384629
// Analyze the case when either Op0 or Op1 is an add instruction.
46394630
// Op0 = A + B (or A and B are null); Op1 = C + D (or C and D are null).
4631+
auto hasNoWrapProblem = [](const BinaryOperator &BO, CmpInst::Predicate Pred,
4632+
bool &HasNSW, bool &HasNUW) -> bool {
4633+
if (isa<OverflowingBinaryOperator>(BO)) {
4634+
HasNUW = BO.hasNoUnsignedWrap();
4635+
HasNSW = BO.hasNoSignedWrap();
4636+
return ICmpInst::isEquality(Pred) ||
4637+
(CmpInst::isUnsigned(Pred) && HasNUW) ||
4638+
(CmpInst::isSigned(Pred) && HasNSW);
4639+
} else if (BO.getOpcode() == Instruction::Or) {
4640+
HasNUW = true;
4641+
HasNSW = true;
4642+
return true;
4643+
} else {
4644+
return false;
4645+
}
4646+
};
46404647
Value *A = nullptr, *B = nullptr, *C = nullptr, *D = nullptr;
4641-
if (BO0 && BO0->getOpcode() == Instruction::Add) {
4642-
A = BO0->getOperand(0);
4643-
B = BO0->getOperand(1);
4648+
4649+
if (BO0) {
4650+
match(BO0, m_AddLike(m_Value(A), m_Value(B)));
4651+
NoOp0WrapProblem = hasNoWrapProblem(*BO0, Pred, Op0HasNSW, Op0HasNUW);
46444652
}
4645-
if (BO1 && BO1->getOpcode() == Instruction::Add) {
4646-
C = BO1->getOperand(0);
4647-
D = BO1->getOperand(1);
4653+
if (BO1) {
4654+
match(BO1, m_AddLike(m_Value(C), m_Value(D)));
4655+
NoOp1WrapProblem = hasNoWrapProblem(*BO1, Pred, Op1HasNSW, Op1HasNUW);
46484656
}
46494657

46504658
// icmp (A+B), A -> icmp B, 0 for equalities or if there is no overflow.
@@ -4764,17 +4772,15 @@ Instruction *InstCombinerImpl::foldICmpBinOp(ICmpInst &I,
47644772
APInt AP2Abs = AP2->abs();
47654773
if (AP1Abs.uge(AP2Abs)) {
47664774
APInt Diff = *AP1 - *AP2;
4767-
bool HasNUW = BO0->hasNoUnsignedWrap() && Diff.ule(*AP1);
4768-
bool HasNSW = BO0->hasNoSignedWrap();
47694775
Constant *C3 = Constant::getIntegerValue(BO0->getType(), Diff);
4770-
Value *NewAdd = Builder.CreateAdd(A, C3, "", HasNUW, HasNSW);
4776+
Value *NewAdd = Builder.CreateAdd(
4777+
A, C3, "", Op0HasNUW && Diff.ule(*AP1), Op0HasNSW);
47714778
return new ICmpInst(Pred, NewAdd, C);
47724779
} else {
47734780
APInt Diff = *AP2 - *AP1;
4774-
bool HasNUW = BO1->hasNoUnsignedWrap() && Diff.ule(*AP2);
4775-
bool HasNSW = BO1->hasNoSignedWrap();
47764781
Constant *C3 = Constant::getIntegerValue(BO0->getType(), Diff);
4777-
Value *NewAdd = Builder.CreateAdd(C, C3, "", HasNUW, HasNSW);
4782+
Value *NewAdd = Builder.CreateAdd(
4783+
C, C3, "", Op1HasNUW && Diff.ule(*AP1), Op1HasNSW);
47784784
return new ICmpInst(Pred, A, NewAdd);
47794785
}
47804786
}
@@ -4868,16 +4874,14 @@ Instruction *InstCombinerImpl::foldICmpBinOp(ICmpInst &I,
48684874
isKnownNonZero(Z, Q.DL, /*Depth=*/0, Q.AC, Q.CxtI, Q.DT);
48694875
// if Z != 0 and nsw(X * Z) and nsw(Y * Z)
48704876
// X * Z eq/ne Y * Z -> X eq/ne Y
4871-
if (NonZero && BO0 && BO1 && BO0->hasNoSignedWrap() &&
4872-
BO1->hasNoSignedWrap())
4877+
if (NonZero && BO0 && BO1 && Op0HasNSW && Op1HasNSW)
48734878
return new ICmpInst(Pred, X, Y);
48744879
} else
48754880
NonZero = isKnownNonZero(Z, Q.DL, /*Depth=*/0, Q.AC, Q.CxtI, Q.DT);
48764881

48774882
// If Z != 0 and nuw(X * Z) and nuw(Y * Z)
48784883
// X * Z u{lt/le/gt/ge}/eq/ne Y * Z -> X u{lt/le/gt/ge}/eq/ne Y
4879-
if (NonZero && BO0 && BO1 && BO0->hasNoUnsignedWrap() &&
4880-
BO1->hasNoUnsignedWrap())
4884+
if (NonZero && BO0 && BO1 && Op0HasNUW && Op1HasNUW)
48814885
return new ICmpInst(Pred, X, Y);
48824886
}
48834887
}
@@ -4976,8 +4980,8 @@ Instruction *InstCombinerImpl::foldICmpBinOp(ICmpInst &I,
49764980
return new ICmpInst(Pred, BO0->getOperand(0), BO1->getOperand(0));
49774981

49784982
case Instruction::Shl: {
4979-
bool NUW = BO0->hasNoUnsignedWrap() && BO1->hasNoUnsignedWrap();
4980-
bool NSW = BO0->hasNoSignedWrap() && BO1->hasNoSignedWrap();
4983+
bool NUW = Op0HasNUW && Op1HasNUW;
4984+
bool NSW = Op0HasNSW && Op1HasNSW;
49814985
if (!NUW && !NSW)
49824986
break;
49834987
if (!NSW && I.isSigned())

llvm/test/Transforms/InstCombine/icmp.ll

Lines changed: 93 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3862,10 +3862,9 @@ define <8 x i1> @bitreverse_vec_ne(<8 x i16> %x, <8 x i16> %y) {
38623862
define i1 @knownbits1(i8 %a, i8 %b) {
38633863
; CHECK-LABEL: @knownbits1(
38643864
; CHECK-NEXT: [[A1:%.*]] = and i8 [[A:%.*]], 1
3865-
; CHECK-NEXT: [[A2:%.*]] = or disjoint i8 [[A1]], 4
38663865
; CHECK-NEXT: [[B1:%.*]] = and i8 [[B:%.*]], 2
3867-
; CHECK-NEXT: [[B2:%.*]] = or disjoint i8 [[B1]], 5
3868-
; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[A2]], [[B2]]
3866+
; CHECK-NEXT: [[TMP1:%.*]] = or disjoint i8 [[B1]], 1
3867+
; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[A1]], [[TMP1]]
38693868
; CHECK-NEXT: ret i1 [[C]]
38703869
;
38713870
%a1 = and i8 %a, 5
@@ -3879,10 +3878,9 @@ define i1 @knownbits1(i8 %a, i8 %b) {
38793878
define i1 @knownbits2(i8 %a, i8 %b) {
38803879
; CHECK-LABEL: @knownbits2(
38813880
; CHECK-NEXT: [[A1:%.*]] = and i8 [[A:%.*]], 1
3882-
; CHECK-NEXT: [[A2:%.*]] = or disjoint i8 [[A1]], 4
38833881
; CHECK-NEXT: [[B1:%.*]] = and i8 [[B:%.*]], 2
3884-
; CHECK-NEXT: [[B2:%.*]] = or disjoint i8 [[B1]], 5
3885-
; CHECK-NEXT: [[C:%.*]] = icmp ne i8 [[A2]], [[B2]]
3882+
; CHECK-NEXT: [[TMP1:%.*]] = or disjoint i8 [[B1]], 1
3883+
; CHECK-NEXT: [[C:%.*]] = icmp ne i8 [[A1]], [[TMP1]]
38863884
; CHECK-NEXT: ret i1 [[C]]
38873885
;
38883886
%a1 = and i8 %a, 5
@@ -3896,10 +3894,9 @@ define i1 @knownbits2(i8 %a, i8 %b) {
38963894
define i1 @knownbits3(i8 %a, i8 %b) {
38973895
; CHECK-LABEL: @knownbits3(
38983896
; CHECK-NEXT: [[A1:%.*]] = and i8 [[A:%.*]], 1
3899-
; CHECK-NEXT: [[A2:%.*]] = or disjoint i8 [[A1]], 4
39003897
; CHECK-NEXT: [[B1:%.*]] = and i8 [[B:%.*]], 2
3901-
; CHECK-NEXT: [[B2:%.*]] = or disjoint i8 [[B1]], 5
3902-
; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[B2]], [[A2]]
3898+
; CHECK-NEXT: [[TMP1:%.*]] = or disjoint i8 [[B1]], 1
3899+
; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[TMP1]], [[A1]]
39033900
; CHECK-NEXT: ret i1 [[C]]
39043901
;
39053902
%a1 = and i8 %a, 5
@@ -3913,10 +3910,9 @@ define i1 @knownbits3(i8 %a, i8 %b) {
39133910
define <2 x i1> @knownbits4(<2 x i8> %a, <2 x i8> %b) {
39143911
; CHECK-LABEL: @knownbits4(
39153912
; CHECK-NEXT: [[A1:%.*]] = and <2 x i8> [[A:%.*]], <i8 1, i8 1>
3916-
; CHECK-NEXT: [[A2:%.*]] = or disjoint <2 x i8> [[A1]], <i8 4, i8 4>
39173913
; CHECK-NEXT: [[B1:%.*]] = and <2 x i8> [[B:%.*]], <i8 2, i8 2>
3918-
; CHECK-NEXT: [[B2:%.*]] = or disjoint <2 x i8> [[B1]], <i8 5, i8 5>
3919-
; CHECK-NEXT: [[C:%.*]] = icmp ne <2 x i8> [[B2]], [[A2]]
3914+
; CHECK-NEXT: [[TMP1:%.*]] = or disjoint <2 x i8> [[B1]], <i8 1, i8 1>
3915+
; CHECK-NEXT: [[C:%.*]] = icmp ne <2 x i8> [[TMP1]], [[A1]]
39203916
; CHECK-NEXT: ret <2 x i1> [[C]]
39213917
;
39223918
%a1 = and <2 x i8> %a, <i8 5, i8 5>
@@ -3932,10 +3928,9 @@ define <2 x i1> @knownbits4(<2 x i8> %a, <2 x i8> %b) {
39323928
define i1 @knownbits5(i8 %a, i8 %b) {
39333929
; CHECK-LABEL: @knownbits5(
39343930
; CHECK-NEXT: [[A1:%.*]] = and i8 [[A:%.*]], -127
3935-
; CHECK-NEXT: [[A2:%.*]] = or disjoint i8 [[A1]], 4
39363931
; CHECK-NEXT: [[B1:%.*]] = and i8 [[B:%.*]], 2
3937-
; CHECK-NEXT: [[B2:%.*]] = or disjoint i8 [[B1]], 5
3938-
; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[A2]], [[B2]]
3932+
; CHECK-NEXT: [[TMP1:%.*]] = or disjoint i8 [[B1]], 1
3933+
; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[A1]], [[TMP1]]
39393934
; CHECK-NEXT: ret i1 [[C]]
39403935
;
39413936
%a1 = and i8 %a, 133
@@ -3949,10 +3944,9 @@ define i1 @knownbits5(i8 %a, i8 %b) {
39493944
define i1 @knownbits6(i8 %a, i8 %b) {
39503945
; CHECK-LABEL: @knownbits6(
39513946
; CHECK-NEXT: [[A1:%.*]] = and i8 [[A:%.*]], -127
3952-
; CHECK-NEXT: [[A2:%.*]] = or disjoint i8 [[A1]], 4
39533947
; CHECK-NEXT: [[B1:%.*]] = and i8 [[B:%.*]], 2
3954-
; CHECK-NEXT: [[B2:%.*]] = or disjoint i8 [[B1]], 5
3955-
; CHECK-NEXT: [[C:%.*]] = icmp ne i8 [[A2]], [[B2]]
3948+
; CHECK-NEXT: [[TMP1:%.*]] = or disjoint i8 [[B1]], 1
3949+
; CHECK-NEXT: [[C:%.*]] = icmp ne i8 [[A1]], [[TMP1]]
39563950
; CHECK-NEXT: ret i1 [[C]]
39573951
;
39583952
%a1 = and i8 %a, 133
@@ -3966,10 +3960,9 @@ define i1 @knownbits6(i8 %a, i8 %b) {
39663960
define <2 x i1> @knownbits7(<2 x i8> %a, <2 x i8> %b) {
39673961
; CHECK-LABEL: @knownbits7(
39683962
; CHECK-NEXT: [[A1:%.*]] = and <2 x i8> [[A:%.*]], <i8 -127, i8 -127>
3969-
; CHECK-NEXT: [[A2:%.*]] = or disjoint <2 x i8> [[A1]], <i8 4, i8 4>
39703963
; CHECK-NEXT: [[B1:%.*]] = and <2 x i8> [[B:%.*]], <i8 2, i8 2>
3971-
; CHECK-NEXT: [[B2:%.*]] = or disjoint <2 x i8> [[B1]], <i8 5, i8 5>
3972-
; CHECK-NEXT: [[C:%.*]] = icmp eq <2 x i8> [[B2]], [[A2]]
3964+
; CHECK-NEXT: [[TMP1:%.*]] = or disjoint <2 x i8> [[B1]], <i8 1, i8 1>
3965+
; CHECK-NEXT: [[C:%.*]] = icmp eq <2 x i8> [[TMP1]], [[A1]]
39733966
; CHECK-NEXT: ret <2 x i1> [[C]]
39743967
;
39753968
%a1 = and <2 x i8> %a, <i8 133, i8 133>
@@ -3983,10 +3976,9 @@ define <2 x i1> @knownbits7(<2 x i8> %a, <2 x i8> %b) {
39833976
define i1 @knownbits8(i8 %a, i8 %b) {
39843977
; CHECK-LABEL: @knownbits8(
39853978
; CHECK-NEXT: [[A1:%.*]] = and i8 [[A:%.*]], -127
3986-
; CHECK-NEXT: [[A2:%.*]] = or disjoint i8 [[A1]], 4
39873979
; CHECK-NEXT: [[B1:%.*]] = and i8 [[B:%.*]], 2
3988-
; CHECK-NEXT: [[B2:%.*]] = or disjoint i8 [[B1]], 5
3989-
; CHECK-NEXT: [[C:%.*]] = icmp ne i8 [[B2]], [[A2]]
3980+
; CHECK-NEXT: [[TMP1:%.*]] = or disjoint i8 [[B1]], 1
3981+
; CHECK-NEXT: [[C:%.*]] = icmp ne i8 [[TMP1]], [[A1]]
39903982
; CHECK-NEXT: ret i1 [[C]]
39913983
;
39923984
%a1 = and i8 %a, 133
@@ -4912,3 +4904,80 @@ define i1 @or_positive_sgt_zero_multi_use(i8 %a) {
49124904
%cmp = icmp sgt i8 %b, 0
49134905
ret i1 %cmp
49144906
}
4907+
4908+
4909+
define i1 @disjoint_or_sgt_1(i8 %a, i8 %b) {
4910+
; CHECK-LABEL: @disjoint_or_sgt_1(
4911+
; CHECK-NEXT: [[B1:%.*]] = add nsw i8 [[B:%.*]], 2
4912+
; CHECK-NEXT: [[ICMP_:%.*]] = icmp sle i8 [[B1]], [[A:%.*]]
4913+
; CHECK-NEXT: ret i1 [[ICMP_]]
4914+
;
4915+
%a1 = or disjoint i8 %a, 1
4916+
%b1 = add nsw i8 %b, 2
4917+
%icmp_ = icmp sgt i8 %a1, %b1
4918+
ret i1 %icmp_
4919+
}
4920+
4921+
define i1 @disjoint_or_sgt_2(i8 %a, i8 %b) {
4922+
; CHECK-LABEL: @disjoint_or_sgt_2(
4923+
; CHECK-NEXT: [[A1:%.*]] = or disjoint i8 [[A:%.*]], 2
4924+
; CHECK-NEXT: [[B1:%.*]] = add i8 [[B:%.*]], 1
4925+
; CHECK-NEXT: [[ICMP_:%.*]] = icmp sgt i8 [[A1]], [[B1]]
4926+
; CHECK-NEXT: ret i1 [[ICMP_]]
4927+
;
4928+
%a1 = or disjoint i8 %a, 2
4929+
%b1 = add i8 %b, 1
4930+
%icmp_ = icmp sgt i8 %a1, %b1
4931+
ret i1 %icmp_
4932+
}
4933+
4934+
define i1 @disjoint_or_sgt_3(i8 %a, i8 %b) {
4935+
; CHECK-LABEL: @disjoint_or_sgt_3(
4936+
; CHECK-NEXT: [[A1:%.*]] = or disjoint i8 [[A:%.*]], 2
4937+
; CHECK-NEXT: [[B1:%.*]] = add nuw i8 [[B:%.*]], 1
4938+
; CHECK-NEXT: [[ICMP_:%.*]] = icmp sgt i8 [[A1]], [[B1]]
4939+
; CHECK-NEXT: ret i1 [[ICMP_]]
4940+
;
4941+
%a1 = or disjoint i8 %a, 2
4942+
%b1 = add nuw i8 %b, 1
4943+
%icmp_ = icmp sgt i8 %a1, %b1
4944+
ret i1 %icmp_
4945+
}
4946+
4947+
define i1 @disjoint_or_ugt_1(i8 %a, i8 %b) {
4948+
; CHECK-LABEL: @disjoint_or_ugt_1(
4949+
; CHECK-NEXT: [[B1:%.*]] = add nsw i8 [[B:%.*]], 2
4950+
; CHECK-NEXT: [[ICMP_:%.*]] = icmp ule i8 [[B1]], [[A:%.*]]
4951+
; CHECK-NEXT: ret i1 [[ICMP_]]
4952+
;
4953+
%a1 = or disjoint i8 %a, 1
4954+
%b1 = add nsw i8 %b, 2
4955+
%icmp_ = icmp ugt i8 %a1, %b1
4956+
ret i1 %icmp_
4957+
}
4958+
4959+
define i1 @disjoint_or_ugt_2(i8 %a, i8 %b) {
4960+
; CHECK-LABEL: @disjoint_or_ugt_2(
4961+
; CHECK-NEXT: [[A1:%.*]] = or disjoint i8 [[A:%.*]], 2
4962+
; CHECK-NEXT: [[B1:%.*]] = add i8 [[B:%.*]], 1
4963+
; CHECK-NEXT: [[ICMP_:%.*]] = icmp ugt i8 [[A1]], [[B1]]
4964+
; CHECK-NEXT: ret i1 [[ICMP_]]
4965+
;
4966+
%a1 = or disjoint i8 %a, 2
4967+
%b1 = add i8 %b, 1
4968+
%icmp_ = icmp ugt i8 %a1, %b1
4969+
ret i1 %icmp_
4970+
}
4971+
4972+
define i1 @disjoint_or_ugt_3(i8 %a, i8 %b) {
4973+
; CHECK-LABEL: @disjoint_or_ugt_3(
4974+
; CHECK-NEXT: [[A1:%.*]] = or disjoint i8 [[A:%.*]], 2
4975+
; CHECK-NEXT: [[B1:%.*]] = add nuw i8 [[B:%.*]], 1
4976+
; CHECK-NEXT: [[ICMP_:%.*]] = icmp ugt i8 [[A1]], [[B1]]
4977+
; CHECK-NEXT: ret i1 [[ICMP_]]
4978+
;
4979+
%a1 = or disjoint i8 %a, 2
4980+
%b1 = add nuw i8 %b, 1
4981+
%icmp_ = icmp ugt i8 %a1, %b1
4982+
ret i1 %icmp_
4983+
}

0 commit comments

Comments
 (0)