Skip to content

Commit 4f7dc1b

Browse files
authored
[InstCombine] Fold (add (add A, 1), (sext (icmp ne A, 0))) to call umax(A, 1) (#122491)
Transform (add (add A, 1), (sext (icmp ne A, 0))) into call umax(A, 1). Fixes #121853. Alive2: https://alive2.llvm.org/ce/z/TweTan
1 parent 0d352b2 commit 4f7dc1b

File tree

2 files changed

+148
-0
lines changed

2 files changed

+148
-0
lines changed

llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1775,6 +1775,15 @@ Instruction *InstCombinerImpl::visitAdd(BinaryOperator &I) {
17751775
}
17761776
}
17771777

1778+
// (add (add A, 1), (sext (icmp ne A, 0))) => call umax(A, 1)
1779+
if (match(LHS, m_Add(m_Value(A), m_One())) &&
1780+
match(RHS, m_OneUse(m_SExt(m_OneUse(m_SpecificICmp(
1781+
ICmpInst::ICMP_NE, m_Specific(A), m_ZeroInt())))))) {
1782+
Value *OneConst = ConstantInt::get(A->getType(), 1);
1783+
Value *UMax = Builder.CreateBinaryIntrinsic(Intrinsic::umax, A, OneConst);
1784+
return replaceInstUsesWith(I, UMax);
1785+
}
1786+
17781787
if (Instruction *Ashr = foldAddToAshr(I))
17791788
return Ashr;
17801789

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
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+
; The pattern:
5+
; add(add A, 1), (sext(icmp ne A, 0))
6+
; is transformed into:
7+
; umax(A, 1)
8+
9+
define i32 @add_sext_icmp(i32 %A) {
10+
; CHECK-LABEL: define i32 @add_sext_icmp(
11+
; CHECK-SAME: i32 [[A:%.*]]) {
12+
; CHECK-NEXT: [[ADD2:%.*]] = call i32 @llvm.umax.i32(i32 [[A]], i32 1)
13+
; CHECK-NEXT: ret i32 [[ADD2]]
14+
;
15+
%add1 = add i32 %A, 1
16+
%icmp = icmp ne i32 %A, 0
17+
%sext = sext i1 %icmp to i32
18+
%add2 = add i32 %add1, %sext
19+
ret i32 %add2
20+
}
21+
22+
define i32 @add_sext_icmp_commutative(i32 %A) {
23+
; CHECK-LABEL: define i32 @add_sext_icmp_commutative(
24+
; CHECK-SAME: i32 [[A:%.*]]) {
25+
; CHECK-NEXT: [[ADD2:%.*]] = call i32 @llvm.umax.i32(i32 [[A]], i32 1)
26+
; CHECK-NEXT: ret i32 [[ADD2]]
27+
;
28+
%add1 = add i32 %A, 1
29+
%icmp = icmp ne i32 %A, 0
30+
%sext = sext i1 %icmp to i32
31+
%add2 = add i32 %sext, %add1
32+
ret i32 %add2
33+
}
34+
35+
; Negative test
36+
37+
define i32 @add_sext_icmp_negative_constant(i32 %A) {
38+
; CHECK-LABEL: define i32 @add_sext_icmp_negative_constant(
39+
; CHECK-SAME: i32 [[A:%.*]]) {
40+
; CHECK-NEXT: [[ADD1:%.*]] = add i32 [[A]], 2
41+
; CHECK-NEXT: [[ICMP:%.*]] = icmp ne i32 [[A]], 0
42+
; CHECK-NEXT: [[SEXT:%.*]] = sext i1 [[ICMP]] to i32
43+
; CHECK-NEXT: [[ADD2:%.*]] = add i32 [[ADD1]], [[SEXT]]
44+
; CHECK-NEXT: ret i32 [[ADD2]]
45+
;
46+
%add1 = add i32 %A, 2
47+
%icmp = icmp ne i32 %A, 0
48+
%sext = sext i1 %icmp to i32
49+
%add2 = add i32 %add1, %sext
50+
ret i32 %add2
51+
}
52+
53+
define i32 @add_sext_icmp_negative_pred(i32 %A) {
54+
; CHECK-LABEL: define i32 @add_sext_icmp_negative_pred(
55+
; CHECK-SAME: i32 [[A:%.*]]) {
56+
; CHECK-NEXT: [[ADD1:%.*]] = add i32 [[A]], 1
57+
; CHECK-NEXT: [[ICMP:%.*]] = icmp eq i32 [[A]], 0
58+
; CHECK-NEXT: [[SEXT:%.*]] = sext i1 [[ICMP]] to i32
59+
; CHECK-NEXT: [[ADD2:%.*]] = add i32 [[ADD1]], [[SEXT]]
60+
; CHECK-NEXT: ret i32 [[ADD2]]
61+
;
62+
%add1 = add i32 %A, 1
63+
%icmp = icmp eq i32 %A, 0
64+
%sext = sext i1 %icmp to i32
65+
%add2 = add i32 %add1, %sext
66+
ret i32 %add2
67+
}
68+
69+
; multi-use test
70+
71+
define i32 @add_sext_icmp_multi_use_add2(i32 %A) {
72+
; CHECK-LABEL: define i32 @add_sext_icmp_multi_use_add2(
73+
; CHECK-SAME: i32 [[A:%.*]]) {
74+
; CHECK-NEXT: [[ADD2:%.*]] = call i32 @llvm.umax.i32(i32 [[A]], i32 1)
75+
; CHECK-NEXT: call void @use(i32 [[ADD2]])
76+
; CHECK-NEXT: ret i32 [[ADD2]]
77+
;
78+
%add1 = add i32 %A, 1
79+
%icmp = icmp ne i32 %A, 0
80+
%sext = sext i1 %icmp to i32
81+
%add2 = add i32 %add1, %sext
82+
call void @use(i32 %add2)
83+
ret i32 %add2
84+
}
85+
86+
define i32 @add_sext_icmp_multi_use_sext(i32 %A) {
87+
; CHECK-LABEL: define i32 @add_sext_icmp_multi_use_sext(
88+
; CHECK-SAME: i32 [[A:%.*]]) {
89+
; CHECK-NEXT: [[ADD1:%.*]] = add i32 [[A]], 1
90+
; CHECK-NEXT: [[ICMP:%.*]] = icmp ne i32 [[A]], 0
91+
; CHECK-NEXT: [[SEXT:%.*]] = sext i1 [[ICMP]] to i32
92+
; CHECK-NEXT: call void @use(i32 [[SEXT]])
93+
; CHECK-NEXT: [[ADD2:%.*]] = add i32 [[ADD1]], [[SEXT]]
94+
; CHECK-NEXT: ret i32 [[ADD2]]
95+
;
96+
%add1 = add i32 %A, 1
97+
%icmp = icmp ne i32 %A, 0
98+
%sext = sext i1 %icmp to i32
99+
call void @use(i32 %sext)
100+
%add2 = add i32 %add1, %sext
101+
ret i32 %add2
102+
}
103+
104+
define i32 @add_sext_icmp_multi_use_icmp(i32 %A) {
105+
; CHECK-LABEL: define i32 @add_sext_icmp_multi_use_icmp(
106+
; CHECK-SAME: i32 [[A:%.*]]) {
107+
; CHECK-NEXT: [[ADD1:%.*]] = add i32 [[A]], 1
108+
; CHECK-NEXT: [[ICMP:%.*]] = icmp ne i32 [[A]], 0
109+
; CHECK-NEXT: call void @use(i1 [[ICMP]])
110+
; CHECK-NEXT: [[SEXT:%.*]] = sext i1 [[ICMP]] to i32
111+
; CHECK-NEXT: [[ADD2:%.*]] = add i32 [[ADD1]], [[SEXT]]
112+
; CHECK-NEXT: ret i32 [[ADD2]]
113+
;
114+
%add1 = add i32 %A, 1
115+
%icmp = icmp ne i32 %A, 0
116+
call void @use(i1 %icmp)
117+
%sext = sext i1 %icmp to i32
118+
%add2 = add i32 %add1, %sext
119+
ret i32 %add2
120+
}
121+
122+
define i32 @add_sext_icmp_multi_use_add1(i32 %A) {
123+
; CHECK-LABEL: define i32 @add_sext_icmp_multi_use_add1(
124+
; CHECK-SAME: i32 [[A:%.*]]) {
125+
; CHECK-NEXT: [[ADD1:%.*]] = add i32 [[A]], 1
126+
; CHECK-NEXT: call void @use(i32 [[ADD1]])
127+
; CHECK-NEXT: [[ADD2:%.*]] = call i32 @llvm.umax.i32(i32 [[A]], i32 1)
128+
; CHECK-NEXT: ret i32 [[ADD2]]
129+
;
130+
%add1 = add i32 %A, 1
131+
call void @use(i32 %add1)
132+
%icmp = icmp ne i32 %A, 0
133+
%sext = sext i1 %icmp to i32
134+
%add2 = add i32 %add1, %sext
135+
ret i32 %add2
136+
}
137+
138+
declare void @use(i32)
139+

0 commit comments

Comments
 (0)