Skip to content

Commit 4fc1e7d

Browse files
authored
[InstSimplify] Fold (a != 0) ? abs(a) : 0 (#70305)
Solves #70204
1 parent 7391ad3 commit 4fc1e7d

File tree

2 files changed

+357
-2
lines changed

2 files changed

+357
-2
lines changed

llvm/lib/Analysis/InstructionSimplify.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4436,8 +4436,15 @@ static Value *simplifyWithOpReplaced(Value *V, Value *Op, Value *RepOp,
44364436
// TODO: This may be unsound, because it only catches some forms of
44374437
// refinement.
44384438
if (!AllowRefinement) {
4439-
if (canCreatePoison(cast<Operator>(I), !DropFlags))
4440-
return nullptr;
4439+
if (canCreatePoison(cast<Operator>(I), !DropFlags)) {
4440+
// abs cannot create poison if the value is known to never be int_min.
4441+
if (auto *II = dyn_cast<IntrinsicInst>(I);
4442+
II && II->getIntrinsicID() == Intrinsic::abs) {
4443+
if (!ConstOps[0]->isNotMinSignedValue())
4444+
return nullptr;
4445+
} else
4446+
return nullptr;
4447+
}
44414448
Constant *Res = ConstantFoldInstOperands(I, ConstOps, Q.DL, Q.TLI);
44424449
if (DropFlags && Res && I->hasPoisonGeneratingFlagsOrMetadata())
44434450
DropFlags->push_back(I);
Lines changed: 348 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,348 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2+
; RUN: opt -S -passes=instsimplify < %s | FileCheck %s
3+
4+
declare <4 x i16> @llvm.abs.v4i16(<4 x i16>, i1 immarg)
5+
declare i32 @llvm.abs.i32(i32, i1 immarg)
6+
declare i64 @llvm.abs.i64(i64, i1 immarg)
7+
8+
; check (a == 0) ? 0 : abs(a)
9+
10+
define i32 @select_i32_eq0_abs_f(i32 %a) {
11+
; CHECK-LABEL: @select_i32_eq0_abs_f(
12+
; CHECK-NEXT: entry:
13+
; CHECK-NEXT: [[ABS:%.*]] = tail call i32 @llvm.abs.i32(i32 [[A:%.*]], i1 false)
14+
; CHECK-NEXT: ret i32 [[ABS]]
15+
;
16+
entry:
17+
%cond = icmp eq i32 %a, 0
18+
%abs = tail call i32 @llvm.abs.i32(i32 %a, i1 false)
19+
%res = select i1 %cond, i32 0, i32 %abs
20+
ret i32 %res
21+
}
22+
23+
define i32 @select_i32_eq0_abs_t(i32 %a) {
24+
; CHECK-LABEL: @select_i32_eq0_abs_t(
25+
; CHECK-NEXT: entry:
26+
; CHECK-NEXT: [[ABS:%.*]] = tail call i32 @llvm.abs.i32(i32 [[A:%.*]], i1 true)
27+
; CHECK-NEXT: ret i32 [[ABS]]
28+
;
29+
entry:
30+
%cond = icmp eq i32 %a, 0
31+
%abs = tail call i32 @llvm.abs.i32(i32 %a, i1 true)
32+
%res = select i1 %cond, i32 0, i32 %abs
33+
ret i32 %res
34+
}
35+
36+
; check (a == int_min) ? int_min : abs(a)
37+
38+
define i32 @select_i32_eqINTMIN_abs_f(i32 %a) {
39+
; CHECK-LABEL: @select_i32_eqINTMIN_abs_f(
40+
; CHECK-NEXT: entry:
41+
; CHECK-NEXT: [[ABS:%.*]] = tail call i32 @llvm.abs.i32(i32 [[A:%.*]], i1 false)
42+
; CHECK-NEXT: ret i32 [[ABS]]
43+
;
44+
entry:
45+
%cond = icmp eq i32 %a, -2147483648
46+
%abs = tail call i32 @llvm.abs.i32(i32 %a, i1 false)
47+
%res = select i1 %cond, i32 -2147483648, i32 %abs
48+
ret i32 %res
49+
}
50+
51+
; should not transform
52+
define i32 @select_i32_eqINTMIN_abs_t(i32 %a) {
53+
; CHECK-LABEL: @select_i32_eqINTMIN_abs_t(
54+
; CHECK-NEXT: entry:
55+
; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[A:%.*]], -2147483648
56+
; CHECK-NEXT: [[ABS:%.*]] = tail call i32 @llvm.abs.i32(i32 [[A]], i1 true)
57+
; CHECK-NEXT: [[RES:%.*]] = select i1 [[COND]], i32 -2147483648, i32 [[ABS]]
58+
; CHECK-NEXT: ret i32 [[RES]]
59+
;
60+
entry:
61+
%cond = icmp eq i32 %a, -2147483648
62+
%abs = tail call i32 @llvm.abs.i32(i32 %a, i1 true)
63+
%res = select i1 %cond, i32 -2147483648, i32 %abs
64+
ret i32 %res
65+
}
66+
67+
; check random values, like (a == -255) ? 255 : abs(a)
68+
define i32 @select_i32_eqneg255_abs_f(i32 %a) {
69+
; CHECK-LABEL: @select_i32_eqneg255_abs_f(
70+
; CHECK-NEXT: entry:
71+
; CHECK-NEXT: [[ABS:%.*]] = tail call i32 @llvm.abs.i32(i32 [[A:%.*]], i1 false)
72+
; CHECK-NEXT: ret i32 [[ABS]]
73+
;
74+
entry:
75+
%cond = icmp eq i32 %a, -255
76+
%abs = tail call i32 @llvm.abs.i32(i32 %a, i1 false)
77+
%res = select i1 %cond, i32 255, i32 %abs
78+
ret i32 %res
79+
}
80+
81+
define i32 @select_i32_eqneg255_abs_t(i32 %a) {
82+
; CHECK-LABEL: @select_i32_eqneg255_abs_t(
83+
; CHECK-NEXT: entry:
84+
; CHECK-NEXT: [[ABS:%.*]] = tail call i32 @llvm.abs.i32(i32 [[A:%.*]], i1 true)
85+
; CHECK-NEXT: ret i32 [[ABS]]
86+
;
87+
entry:
88+
%cond = icmp eq i32 %a, -255
89+
%abs = tail call i32 @llvm.abs.i32(i32 %a, i1 true)
90+
%res = select i1 %cond, i32 255, i32 %abs
91+
ret i32 %res
92+
}
93+
94+
define i32 @select_i32_eq65555_abs_f(i32 %a) {
95+
; CHECK-LABEL: @select_i32_eq65555_abs_f(
96+
; CHECK-NEXT: entry:
97+
; CHECK-NEXT: [[ABS:%.*]] = tail call i32 @llvm.abs.i32(i32 [[A:%.*]], i1 false)
98+
; CHECK-NEXT: ret i32 [[ABS]]
99+
;
100+
entry:
101+
%cond = icmp eq i32 %a, 65555
102+
%abs = tail call i32 @llvm.abs.i32(i32 %a, i1 false)
103+
%res = select i1 %cond, i32 65555, i32 %abs
104+
ret i32 %res
105+
}
106+
107+
define i32 @select_i32_eq65555_abs_t(i32 %a) {
108+
; CHECK-LABEL: @select_i32_eq65555_abs_t(
109+
; CHECK-NEXT: entry:
110+
; CHECK-NEXT: [[ABS:%.*]] = tail call i32 @llvm.abs.i32(i32 [[A:%.*]], i1 true)
111+
; CHECK-NEXT: ret i32 [[ABS]]
112+
;
113+
entry:
114+
%cond = icmp eq i32 %a, 65555
115+
%abs = tail call i32 @llvm.abs.i32(i32 %a, i1 true)
116+
%res = select i1 %cond, i32 65555, i32 %abs
117+
ret i32 %res
118+
}
119+
120+
121+
; check random values, but the transform doesn't make sense, e.g.
122+
; (a == 255) ? -255 : abs(a)
123+
define i32 @bad_select_i32_eq255_abs_f(i32 %a) {
124+
; CHECK-LABEL: @bad_select_i32_eq255_abs_f(
125+
; CHECK-NEXT: entry:
126+
; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[A:%.*]], 255
127+
; CHECK-NEXT: [[ABS:%.*]] = tail call i32 @llvm.abs.i32(i32 [[A]], i1 false)
128+
; CHECK-NEXT: [[RES:%.*]] = select i1 [[COND]], i32 -255, i32 [[ABS]]
129+
; CHECK-NEXT: ret i32 [[RES]]
130+
;
131+
entry:
132+
%cond = icmp eq i32 %a, 255
133+
%abs = tail call i32 @llvm.abs.i32(i32 %a, i1 false)
134+
%res = select i1 %cond, i32 -255, i32 %abs
135+
ret i32 %res
136+
}
137+
138+
define i32 @bad_select_i32_eq255_abs_t(i32 %a) {
139+
; CHECK-LABEL: @bad_select_i32_eq255_abs_t(
140+
; CHECK-NEXT: entry:
141+
; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[A:%.*]], 255
142+
; CHECK-NEXT: [[ABS:%.*]] = tail call i32 @llvm.abs.i32(i32 [[A]], i1 true)
143+
; CHECK-NEXT: [[RES:%.*]] = select i1 [[COND]], i32 -255, i32 [[ABS]]
144+
; CHECK-NEXT: ret i32 [[RES]]
145+
;
146+
entry:
147+
%cond = icmp eq i32 %a, 255
148+
%abs = tail call i32 @llvm.abs.i32(i32 %a, i1 true)
149+
%res = select i1 %cond, i32 -255, i32 %abs
150+
ret i32 %res
151+
}
152+
153+
define i32 @bad_select_i32_eq65555_abs_f(i32 %a) {
154+
; CHECK-LABEL: @bad_select_i32_eq65555_abs_f(
155+
; CHECK-NEXT: entry:
156+
; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[A:%.*]], -65555
157+
; CHECK-NEXT: [[ABS:%.*]] = tail call i32 @llvm.abs.i32(i32 [[A]], i1 false)
158+
; CHECK-NEXT: [[RES:%.*]] = select i1 [[COND]], i32 65554, i32 [[ABS]]
159+
; CHECK-NEXT: ret i32 [[RES]]
160+
;
161+
entry:
162+
%cond = icmp eq i32 %a, -65555
163+
%abs = tail call i32 @llvm.abs.i32(i32 %a, i1 false)
164+
%res = select i1 %cond, i32 65554, i32 %abs
165+
ret i32 %res
166+
}
167+
168+
define i32 @bad_select_i32_eq65555_abs_t(i32 %a) {
169+
; CHECK-LABEL: @bad_select_i32_eq65555_abs_t(
170+
; CHECK-NEXT: entry:
171+
; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[A:%.*]], -65555
172+
; CHECK-NEXT: [[ABS:%.*]] = tail call i32 @llvm.abs.i32(i32 [[A]], i1 true)
173+
; CHECK-NEXT: [[RES:%.*]] = select i1 [[COND]], i32 65554, i32 [[ABS]]
174+
; CHECK-NEXT: ret i32 [[RES]]
175+
;
176+
entry:
177+
%cond = icmp eq i32 %a, -65555
178+
%abs = tail call i32 @llvm.abs.i32(i32 %a, i1 true)
179+
%res = select i1 %cond, i32 65554, i32 %abs
180+
ret i32 %res
181+
}
182+
183+
define i32 @select_i32_ne0_abs_f(i32 %a) {
184+
; CHECK-LABEL: @select_i32_ne0_abs_f(
185+
; CHECK-NEXT: entry:
186+
; CHECK-NEXT: [[ABS:%.*]] = tail call i32 @llvm.abs.i32(i32 [[A:%.*]], i1 false)
187+
; CHECK-NEXT: ret i32 [[ABS]]
188+
;
189+
entry:
190+
%cond = icmp ne i32 %a, 0
191+
%abs = tail call i32 @llvm.abs.i32(i32 %a, i1 false)
192+
%res = select i1 %cond, i32 %abs, i32 0
193+
ret i32 %res
194+
}
195+
196+
define i32 @select_i32_ne0_abs_t(i32 %a) {
197+
; CHECK-LABEL: @select_i32_ne0_abs_t(
198+
; CHECK-NEXT: entry:
199+
; CHECK-NEXT: [[ABS:%.*]] = tail call i32 @llvm.abs.i32(i32 [[A:%.*]], i1 true)
200+
; CHECK-NEXT: ret i32 [[ABS]]
201+
;
202+
entry:
203+
%cond = icmp ne i32 %a, 0
204+
%abs = tail call i32 @llvm.abs.i32(i32 %a, i1 true)
205+
%res = select i1 %cond, i32 %abs, i32 0
206+
ret i32 %res
207+
}
208+
209+
define i64 @select_i64_eq0_abs_t(i64 %a) {
210+
; CHECK-LABEL: @select_i64_eq0_abs_t(
211+
; CHECK-NEXT: entry:
212+
; CHECK-NEXT: [[ABS:%.*]] = tail call i64 @llvm.abs.i64(i64 [[A:%.*]], i1 true)
213+
; CHECK-NEXT: ret i64 [[ABS]]
214+
;
215+
entry:
216+
%cond = icmp eq i64 %a, 0
217+
%abs = tail call i64 @llvm.abs.i64(i64 %a, i1 true)
218+
%res = select i1 %cond, i64 0, i64 %abs
219+
ret i64 %res
220+
}
221+
222+
define i64 @select_i64_ne0_abs_t(i64 %a) {
223+
; CHECK-LABEL: @select_i64_ne0_abs_t(
224+
; CHECK-NEXT: entry:
225+
; CHECK-NEXT: [[ABS:%.*]] = tail call i64 @llvm.abs.i64(i64 [[A:%.*]], i1 true)
226+
; CHECK-NEXT: ret i64 [[ABS]]
227+
;
228+
entry:
229+
%cond = icmp ne i64 %a, 0
230+
%abs = tail call i64 @llvm.abs.i64(i64 %a, i1 true)
231+
%res = select i1 %cond, i64 %abs, i64 0
232+
ret i64 %res
233+
}
234+
235+
; TODO: Handle vector cases?
236+
define <4 x i16> @select_v4i16_eq0_abs_t(<4 x i16> %a) {
237+
; CHECK-LABEL: @select_v4i16_eq0_abs_t(
238+
; CHECK-NEXT: entry:
239+
; CHECK-NEXT: [[COND:%.*]] = icmp eq <4 x i16> [[A:%.*]], zeroinitializer
240+
; CHECK-NEXT: [[ABS:%.*]] = tail call <4 x i16> @llvm.abs.v4i16(<4 x i16> [[A]], i1 true)
241+
; CHECK-NEXT: [[RES:%.*]] = select <4 x i1> [[COND]], <4 x i16> zeroinitializer, <4 x i16> [[ABS]]
242+
; CHECK-NEXT: ret <4 x i16> [[RES]]
243+
;
244+
entry:
245+
%cond = icmp eq <4 x i16> %a, <i16 0, i16 0, i16 0, i16 0>
246+
%abs = tail call <4 x i16> @llvm.abs.v4i16(<4 x i16> %a, i1 true)
247+
%res = select <4 x i1> %cond, <4 x i16> <i16 0, i16 0, i16 0, i16 0>, <4 x i16> %abs
248+
ret <4 x i16> %res
249+
}
250+
251+
define <4 x i16> @select_v4i16_ne0_abs_t(<4 x i16> %a) {
252+
; CHECK-LABEL: @select_v4i16_ne0_abs_t(
253+
; CHECK-NEXT: entry:
254+
; CHECK-NEXT: [[COND:%.*]] = icmp ne <4 x i16> [[A:%.*]], zeroinitializer
255+
; CHECK-NEXT: [[ABS:%.*]] = tail call <4 x i16> @llvm.abs.v4i16(<4 x i16> [[A]], i1 true)
256+
; CHECK-NEXT: [[RES:%.*]] = select <4 x i1> [[COND]], <4 x i16> [[ABS]], <4 x i16> zeroinitializer
257+
; CHECK-NEXT: ret <4 x i16> [[RES]]
258+
;
259+
entry:
260+
%cond = icmp ne <4 x i16> %a, <i16 0, i16 0, i16 0, i16 0>
261+
%abs = tail call <4 x i16> @llvm.abs.v4i16(<4 x i16> %a, i1 true)
262+
%res = select <4 x i1> %cond, <4 x i16> %abs, <4 x i16> <i16 0, i16 0, i16 0, i16 0>
263+
ret <4 x i16> %res
264+
}
265+
266+
define <4 x i16> @select_v4i16_ne0_abs_t_with_undef(<4 x i16> %a) {
267+
; CHECK-LABEL: @select_v4i16_ne0_abs_t_with_undef(
268+
; CHECK-NEXT: entry:
269+
; CHECK-NEXT: [[COND:%.*]] = icmp ne <4 x i16> [[A:%.*]], zeroinitializer
270+
; CHECK-NEXT: [[ABS:%.*]] = tail call <4 x i16> @llvm.abs.v4i16(<4 x i16> [[A]], i1 true)
271+
; CHECK-NEXT: [[RES:%.*]] = select <4 x i1> [[COND]], <4 x i16> [[ABS]], <4 x i16> <i16 undef, i16 0, i16 0, i16 0>
272+
; CHECK-NEXT: ret <4 x i16> [[RES]]
273+
;
274+
entry:
275+
%cond = icmp ne <4 x i16> %a, <i16 0, i16 0, i16 0, i16 0>
276+
%abs = tail call <4 x i16> @llvm.abs.v4i16(<4 x i16> %a, i1 true)
277+
%res = select <4 x i1> %cond, <4 x i16> %abs, <4 x i16> <i16 undef, i16 0, i16 0, i16 0>
278+
ret <4 x i16> %res
279+
}
280+
281+
define i32 @bad_select_i32_ne0_abs(i32 %a) {
282+
; CHECK-LABEL: @bad_select_i32_ne0_abs(
283+
; CHECK-NEXT: entry:
284+
; CHECK-NEXT: ret i32 0
285+
;
286+
entry:
287+
%cond = icmp ne i32 %a, 0
288+
%abs = tail call i32 @llvm.abs.i32(i32 %a, i1 false)
289+
%res = select i1 %cond, i32 0, i32 %abs
290+
ret i32 %res
291+
}
292+
293+
define i32 @bad_select_i32_eq0_abs(i32 %a) {
294+
; CHECK-LABEL: @bad_select_i32_eq0_abs(
295+
; CHECK-NEXT: entry:
296+
; CHECK-NEXT: ret i32 0
297+
;
298+
entry:
299+
%cond = icmp eq i32 %a, 0
300+
%abs = tail call i32 @llvm.abs.i32(i32 %a, i1 false)
301+
%res = select i1 %cond, i32 %abs, i32 0
302+
ret i32 %res
303+
}
304+
305+
define <4 x i16> @badsplat1_select_v4i16_ne0_abs(<4 x i16> %a) {
306+
; CHECK-LABEL: @badsplat1_select_v4i16_ne0_abs(
307+
; CHECK-NEXT: entry:
308+
; CHECK-NEXT: [[COND:%.*]] = icmp ne <4 x i16> [[A:%.*]], <i16 0, i16 1, i16 0, i16 0>
309+
; CHECK-NEXT: [[ABS:%.*]] = tail call <4 x i16> @llvm.abs.v4i16(<4 x i16> [[A]], i1 true)
310+
; CHECK-NEXT: [[RES:%.*]] = select <4 x i1> [[COND]], <4 x i16> [[ABS]], <4 x i16> <i16 0, i16 1, i16 0, i16 0>
311+
; CHECK-NEXT: ret <4 x i16> [[RES]]
312+
;
313+
entry:
314+
%cond = icmp ne <4 x i16> %a, <i16 0, i16 1, i16 0, i16 0>
315+
%abs = tail call <4 x i16> @llvm.abs.v4i16(<4 x i16> %a, i1 true)
316+
%res = select <4 x i1> %cond, <4 x i16> %abs, <4 x i16> <i16 0, i16 1, i16 0, i16 0>
317+
ret <4 x i16> %res
318+
}
319+
320+
define <4 x i16> @badsplat2_select_v4i16_ne0_abs(<4 x i16> %a) {
321+
; CHECK-LABEL: @badsplat2_select_v4i16_ne0_abs(
322+
; CHECK-NEXT: entry:
323+
; CHECK-NEXT: [[COND:%.*]] = icmp ne <4 x i16> [[A:%.*]], <i16 0, i16 undef, i16 0, i16 0>
324+
; CHECK-NEXT: [[ABS:%.*]] = tail call <4 x i16> @llvm.abs.v4i16(<4 x i16> [[A]], i1 true)
325+
; CHECK-NEXT: [[RES:%.*]] = select <4 x i1> [[COND]], <4 x i16> [[ABS]], <4 x i16> <i16 0, i16 1, i16 0, i16 0>
326+
; CHECK-NEXT: ret <4 x i16> [[RES]]
327+
;
328+
entry:
329+
%cond = icmp ne <4 x i16> %a, <i16 0, i16 undef, i16 0, i16 0>
330+
%abs = tail call <4 x i16> @llvm.abs.v4i16(<4 x i16> %a, i1 true)
331+
%res = select <4 x i1> %cond, <4 x i16> %abs, <4 x i16> <i16 0, i16 1, i16 0, i16 0>
332+
ret <4 x i16> %res
333+
}
334+
335+
define <4 x i16> @badsplat3_select_v4i16_ne0_abs(<4 x i16> %a) {
336+
; CHECK-LABEL: @badsplat3_select_v4i16_ne0_abs(
337+
; CHECK-NEXT: entry:
338+
; CHECK-NEXT: [[COND:%.*]] = icmp ne <4 x i16> [[A:%.*]], zeroinitializer
339+
; CHECK-NEXT: [[ABS:%.*]] = tail call <4 x i16> @llvm.abs.v4i16(<4 x i16> [[A]], i1 true)
340+
; CHECK-NEXT: [[RES:%.*]] = select <4 x i1> [[COND]], <4 x i16> [[ABS]], <4 x i16> <i16 0, i16 1, i16 0, i16 0>
341+
; CHECK-NEXT: ret <4 x i16> [[RES]]
342+
;
343+
entry:
344+
%cond = icmp ne <4 x i16> %a, <i16 0, i16 0, i16 0, i16 0>
345+
%abs = tail call <4 x i16> @llvm.abs.v4i16(<4 x i16> %a, i1 true)
346+
%res = select <4 x i1> %cond, <4 x i16> %abs, <4 x i16> <i16 0, i16 1, i16 0, i16 0>
347+
ret <4 x i16> %res
348+
}

0 commit comments

Comments
 (0)