Skip to content

Commit f2734aa

Browse files
authored
[InstCombine] fold icmp with add/sub instructions having the same operands (#143241)
Closes #143211.
1 parent 7c25db3 commit f2734aa

File tree

2 files changed

+135
-0
lines changed

2 files changed

+135
-0
lines changed

llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7728,6 +7728,30 @@ Instruction *InstCombinerImpl::visitICmpInst(ICmpInst &I) {
77287728
}
77297729
}
77307730

7731+
// icmp slt (sub nsw x, y), (add nsw x, y) --> icmp sgt y, 0
7732+
// icmp ult (sub nuw x, y), (add nuw x, y) --> icmp ugt y, 0
7733+
// icmp eq (sub nsw/nuw x, y), (add nsw/nuw x, y) --> icmp eq y, 0
7734+
{
7735+
Value *A, *B;
7736+
CmpPredicate CmpPred;
7737+
if (match(&I, m_c_ICmp(CmpPred, m_Sub(m_Value(A), m_Value(B)),
7738+
m_c_Add(m_Deferred(A), m_Deferred(B))))) {
7739+
auto *I0 = cast<OverflowingBinaryOperator>(Op0);
7740+
auto *I1 = cast<OverflowingBinaryOperator>(Op1);
7741+
bool I0NUW = I0->hasNoUnsignedWrap();
7742+
bool I1NUW = I1->hasNoUnsignedWrap();
7743+
bool I0NSW = I0->hasNoSignedWrap();
7744+
bool I1NSW = I1->hasNoSignedWrap();
7745+
if ((ICmpInst::isUnsigned(Pred) && I0NUW && I1NUW) ||
7746+
(ICmpInst::isSigned(Pred) && I0NSW && I1NSW) ||
7747+
(ICmpInst::isEquality(Pred) &&
7748+
((I0NUW || I0NSW) && (I1NUW || I1NSW)))) {
7749+
return new ICmpInst(CmpPredicate::getSwapped(CmpPred), B,
7750+
ConstantInt::get(Op0->getType(), 0));
7751+
}
7752+
}
7753+
}
7754+
77317755
// Try to optimize equality comparisons against alloca-based pointers.
77327756
if (Op0->getType()->isPointerTy() && I.isEquality()) {
77337757
assert(Op1->getType()->isPointerTy() &&
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
2+
; RUN: opt < %s -passes=instcombine -S | FileCheck %s
3+
4+
define i1 @test-same-operands-sub-add-nsw-icmp-sgt(i8 %a, i8 %b) {
5+
; CHECK-LABEL: define i1 @test-same-operands-sub-add-nsw-icmp-sgt(
6+
; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]]) {
7+
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[B]], 0
8+
; CHECK-NEXT: ret i1 [[CMP]]
9+
;
10+
%sub = sub nsw i8 %a, %b
11+
%add = add nsw i8 %a, %b
12+
%cmp = icmp sgt i8 %sub, %add
13+
ret i1 %cmp
14+
}
15+
16+
define i1 @test-same-operands-sub-add-nsw-icmp-slt(i8 %a, i8 %b) {
17+
; CHECK-LABEL: define i1 @test-same-operands-sub-add-nsw-icmp-slt(
18+
; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]]) {
19+
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[B]], 0
20+
; CHECK-NEXT: ret i1 [[CMP]]
21+
;
22+
%sub = sub nsw i8 %a, %b
23+
%add = add nsw i8 %a, %b
24+
%cmp = icmp slt i8 %sub, %add
25+
ret i1 %cmp
26+
}
27+
28+
define i1 @test-same-operands-sub-add-nsw-icmp-sle(i8 %a, i8 %b) {
29+
; CHECK-LABEL: define i1 @test-same-operands-sub-add-nsw-icmp-sle(
30+
; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]]) {
31+
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[B]], -1
32+
; CHECK-NEXT: ret i1 [[CMP]]
33+
;
34+
%sub = sub nsw i8 %a, %b
35+
%add = add nsw i8 %a, %b
36+
%cmp = icmp sle i8 %sub, %add
37+
ret i1 %cmp
38+
}
39+
40+
define i1 @test-same-operands-sub-add-nsw-nuw-icmp-eq(i8 %a, i8 %b) {
41+
; CHECK-LABEL: define i1 @test-same-operands-sub-add-nsw-nuw-icmp-eq(
42+
; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]]) {
43+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[B]], 0
44+
; CHECK-NEXT: ret i1 [[CMP]]
45+
;
46+
%sub = sub nsw i8 %a, %b
47+
%add = add nuw i8 %a, %b
48+
%cmp = icmp eq i8 %sub, %add
49+
ret i1 %cmp
50+
}
51+
52+
define i1 @test-same-operands-sub-add-nsw-icmp-eq(i8 %a, i8 %b) {
53+
; CHECK-LABEL: define i1 @test-same-operands-sub-add-nsw-icmp-eq(
54+
; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]]) {
55+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[B]], 0
56+
; CHECK-NEXT: ret i1 [[CMP]]
57+
;
58+
%sub = sub nsw i8 %a, %b
59+
%add = add nsw i8 %a, %b
60+
%cmp = icmp eq i8 %sub, %add
61+
ret i1 %cmp
62+
}
63+
64+
define i1 @test-add-sub-nsw-icmp-sgt(i8 %a, i8 %b) {
65+
; CHECK-LABEL: define i1 @test-add-sub-nsw-icmp-sgt(
66+
; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]]) {
67+
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[B]], 0
68+
; CHECK-NEXT: ret i1 [[CMP]]
69+
;
70+
%sub = sub nsw i8 %a, %b
71+
%add = add nsw i8 %a, %b
72+
%cmp = icmp sgt i8 %add, %sub
73+
ret i1 %cmp
74+
}
75+
76+
define i1 @test-add-sub-nuw-icmp-uge(i8 %a, i8 %b) {
77+
; CHECK-LABEL: define i1 @test-add-sub-nuw-icmp-uge(
78+
; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]]) {
79+
; CHECK-NEXT: ret i1 true
80+
;
81+
%sub = sub nuw i8 %a, %b
82+
%add = add nuw i8 %a, %b
83+
%cmp = icmp uge i8 %add, %sub
84+
ret i1 %cmp
85+
}
86+
87+
; Check not folded
88+
define i1 @test-add-sub-nuw-icmp-sge(i8 %a, i8 %b) {
89+
; CHECK-LABEL: define i1 @test-add-sub-nuw-icmp-sge(
90+
; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]]) {
91+
; CHECK-NEXT: [[SUB:%.*]] = sub nuw i8 [[A]], [[B]]
92+
; CHECK-NEXT: [[ADD:%.*]] = add nuw i8 [[A]], [[B]]
93+
; CHECK-NEXT: [[CMP:%.*]] = icmp sge i8 [[ADD]], [[SUB]]
94+
; CHECK-NEXT: ret i1 [[CMP]]
95+
;
96+
%sub = sub nuw i8 %a, %b
97+
%add = add nuw i8 %a, %b
98+
%cmp = icmp sge i8 %add, %sub
99+
ret i1 %cmp
100+
}
101+
102+
define i1 @test-add-swap-sub-nuw-icmp-uge(i8 %a, i8 %b) {
103+
; CHECK-LABEL: define i1 @test-add-swap-sub-nuw-icmp-uge(
104+
; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]]) {
105+
; CHECK-NEXT: ret i1 true
106+
;
107+
%sub = sub nuw i8 %a, %b
108+
%add = add nuw i8 %b, %a
109+
%cmp = icmp uge i8 %add, %sub
110+
ret i1 %cmp
111+
}

0 commit comments

Comments
 (0)