Skip to content

Commit c0cf491

Browse files
committed
[InstrCombin] fold icmp with add/sub instructions having the same operands
Closes#143211
1 parent ca4dfca commit c0cf491

File tree

2 files changed

+155
-0
lines changed

2 files changed

+155
-0
lines changed

llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp

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

7731+
// In case of a comparison with add/sub instructions having the same operands,
7732+
// check whether cmp operands have same signed no wrap. If so, just compare
7733+
// the sub's second operand and zero.
7734+
// For example:
7735+
// %tmp1 = sub nsw i8 %x, %y
7736+
// %tmp2 = add nsw i8 %x, %y
7737+
// %cmp = icmp sgt i8 %tmp1, %tmp2
7738+
// transform this into:
7739+
// %cmp = icmp slt i32 %y, 0
7740+
// This handles similar cases to transform.
7741+
{
7742+
Value *A, *B;
7743+
auto *I0 = dyn_cast<OverflowingBinaryOperator>(Op0);
7744+
auto *I1 = dyn_cast<OverflowingBinaryOperator>(Op1);
7745+
bool UnsignedCmp = ICmpInst::isUnsigned(Pred);
7746+
bool SignedCmp = ICmpInst::isSigned(Pred);
7747+
bool EqualityCmp = ICmpInst::isEquality(Pred);
7748+
7749+
if (I0 && I1) {
7750+
bool I0NUW = I0->hasNoUnsignedWrap();
7751+
bool I1NUW = I1->hasNoUnsignedWrap();
7752+
bool I0NSW = I0->hasNoSignedWrap();
7753+
bool I1NSW = I1->hasNoSignedWrap();
7754+
bool Swaped = false;
7755+
if ((UnsignedCmp && I0NUW && I1NUW) || (SignedCmp && I0NSW && I1NSW) ||
7756+
(EqualityCmp && I0NUW && I0NSW && I1NUW && I1NSW)) {
7757+
if (I0->getOpcode() == Instruction::Add &&
7758+
I1->getOpcode() == Instruction::Sub) {
7759+
std::swap(I0, I1);
7760+
Swaped = true;
7761+
}
7762+
if (match(I0, m_Sub(m_Value(A), m_Value(B))) &&
7763+
(match(I1, m_Add(m_Specific(A), m_Specific(B))) ||
7764+
match(I1, m_Add(m_Specific(B), m_Specific(A))))) {
7765+
return new ICmpInst(Swaped ? Pred : I.getSwappedPredicate(), B,
7766+
ConstantInt::get(Op0->getType(), 0));
7767+
}
7768+
}
7769+
}
7770+
}
7771+
77317772
// Try to optimize equality comparisons against alloca-based pointers.
77327773
if (Op0->getType()->isPointerTy() && I.isEquality()) {
77337774
assert(Op1->getType()->isPointerTy() &&
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
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 nuw nsw i8 %a, %b
47+
%add = add nuw nsw i8 %a, %b
48+
%cmp = icmp eq i8 %sub, %add
49+
ret i1 %cmp
50+
}
51+
52+
; Check not folded
53+
define i1 @test-same-operands-sub-add-nsw-icmp-eq(i8 %a, i8 %b) {
54+
; CHECK-LABEL: define i1 @test-same-operands-sub-add-nsw-icmp-eq(
55+
; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]]) {
56+
; CHECK-NEXT: [[SUB:%.*]] = sub nsw i8 [[A]], [[B]]
57+
; CHECK-NEXT: [[ADD:%.*]] = add nsw i8 [[A]], [[B]]
58+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[SUB]], [[ADD]]
59+
; CHECK-NEXT: ret i1 [[CMP]]
60+
;
61+
%sub = sub nsw i8 %a, %b
62+
%add = add nsw i8 %a, %b
63+
%cmp = icmp eq i8 %sub, %add
64+
ret i1 %cmp
65+
}
66+
67+
define i1 @test-add-sub-nsw-icmp-sgt(i8 %a, i8 %b) {
68+
; CHECK-LABEL: define i1 @test-add-sub-nsw-icmp-sgt(
69+
; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]]) {
70+
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[B]], 0
71+
; CHECK-NEXT: ret i1 [[CMP]]
72+
;
73+
%sub = sub nsw i8 %a, %b
74+
%add = add nsw i8 %a, %b
75+
%cmp = icmp sgt i8 %add, %sub
76+
ret i1 %cmp
77+
}
78+
79+
define i1 @test-add-sub-nuw-icmp-uge(i8 %a, i8 %b) {
80+
; CHECK-LABEL: define i1 @test-add-sub-nuw-icmp-uge(
81+
; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]]) {
82+
; CHECK-NEXT: ret i1 true
83+
;
84+
%sub = sub nuw i8 %a, %b
85+
%add = add nuw i8 %a, %b
86+
%cmp = icmp uge i8 %add, %sub
87+
ret i1 %cmp
88+
}
89+
90+
; Check not folded
91+
define i1 @test-add-sub-nuw-icmp-sge(i8 %a, i8 %b) {
92+
; CHECK-LABEL: define i1 @test-add-sub-nuw-icmp-sge(
93+
; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]]) {
94+
; CHECK-NEXT: [[SUB:%.*]] = sub nuw i8 [[A]], [[B]]
95+
; CHECK-NEXT: [[ADD:%.*]] = add nuw i8 [[A]], [[B]]
96+
; CHECK-NEXT: [[CMP:%.*]] = icmp sge i8 [[ADD]], [[SUB]]
97+
; CHECK-NEXT: ret i1 [[CMP]]
98+
;
99+
%sub = sub nuw i8 %a, %b
100+
%add = add nuw i8 %a, %b
101+
%cmp = icmp sge i8 %add, %sub
102+
ret i1 %cmp
103+
}
104+
105+
define i1 @test-add-swap-sub-nuw-icmp-uge(i8 %a, i8 %b) {
106+
; CHECK-LABEL: define i1 @test-add-swap-sub-nuw-icmp-uge(
107+
; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]]) {
108+
; CHECK-NEXT: ret i1 true
109+
;
110+
%sub = sub nuw i8 %a, %b
111+
%add = add nuw i8 %b, %a
112+
%cmp = icmp uge i8 %add, %sub
113+
ret i1 %cmp
114+
}

0 commit comments

Comments
 (0)