1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals
2 ; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT
3 ; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC
5 ; Test for multiple potential values
8 ; bool iszero(int c) { return c == 0; }
9 ; bool potential_test1(bool c) { return iszero(c ? 1 : -1); }
11 define internal i1 @iszero1(i32 %c) {
12 ; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
13 ; CGSCC-LABEL: define {{[^@]+}}@iszero1
14 ; CGSCC-SAME: () #[[ATTR0:[0-9]+]] {
15 ; CGSCC-NEXT: ret i1 false
17 %cmp = icmp eq i32 %c, 0
21 define i1 @potential_test1(i1 %c) {
22 ; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
23 ; TUNIT-LABEL: define {{[^@]+}}@potential_test1
24 ; TUNIT-SAME: (i1 [[C:%.*]]) #[[ATTR0:[0-9]+]] {
25 ; TUNIT-NEXT: ret i1 false
27 ; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
28 ; CGSCC-LABEL: define {{[^@]+}}@potential_test1
29 ; CGSCC-SAME: (i1 [[C:%.*]]) #[[ATTR1:[0-9]+]] {
30 ; CGSCC-NEXT: [[RET:%.*]] = call noundef i1 @iszero1() #[[ATTR2:[0-9]+]]
31 ; CGSCC-NEXT: ret i1 [[RET]]
33 %arg = select i1 %c, i32 -1, i32 1
34 %ret = call i1 @iszero1(i32 %arg)
41 ; potential values of argument of iszero are {1,-1}
42 ; potential value of returned value of iszero is 0
44 ; int call_with_two_values(int x) { return iszero(x) + iszero(-x); }
45 ; int potential_test2(int x) { return call_with_two_values(1) + call_with_two_values(-1); }
47 define internal i32 @iszero2(i32 %c) {
48 ; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
49 ; CGSCC-LABEL: define {{[^@]+}}@iszero2
50 ; CGSCC-SAME: (i32 [[C:%.*]]) #[[ATTR0]] {
51 ; CGSCC-NEXT: [[CMP:%.*]] = icmp eq i32 [[C]], 0
52 ; CGSCC-NEXT: [[RET:%.*]] = zext i1 [[CMP]] to i32
53 ; CGSCC-NEXT: ret i32 [[RET]]
55 %cmp = icmp eq i32 %c, 0
56 %ret = zext i1 %cmp to i32
60 define internal i32 @call_with_two_values(i32 %c) {
61 ; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
62 ; CGSCC-LABEL: define {{[^@]+}}@call_with_two_values
63 ; CGSCC-SAME: (i32 noundef [[C:%.*]]) #[[ATTR1]] {
64 ; CGSCC-NEXT: [[CSRET1:%.*]] = call i32 @iszero2(i32 noundef [[C]]) #[[ATTR2]]
65 ; CGSCC-NEXT: [[MINUSC:%.*]] = sub i32 0, [[C]]
66 ; CGSCC-NEXT: [[CSRET2:%.*]] = call i32 @iszero2(i32 noundef [[MINUSC]]) #[[ATTR2]]
67 ; CGSCC-NEXT: [[RET:%.*]] = add i32 [[CSRET1]], [[CSRET2]]
68 ; CGSCC-NEXT: ret i32 [[RET]]
70 %csret1 = call i32 @iszero2(i32 %c)
71 %minusc = sub i32 0, %c
72 %csret2 = call i32 @iszero2(i32 %minusc)
73 %ret = add i32 %csret1, %csret2
77 define i32 @potential_test2(i1 %c) {
78 ; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
79 ; TUNIT-LABEL: define {{[^@]+}}@potential_test2
80 ; TUNIT-SAME: (i1 [[C:%.*]]) #[[ATTR0]] {
81 ; TUNIT-NEXT: ret i32 0
83 ; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
84 ; CGSCC-LABEL: define {{[^@]+}}@potential_test2
85 ; CGSCC-SAME: (i1 [[C:%.*]]) #[[ATTR1]] {
86 ; CGSCC-NEXT: [[CSRET1:%.*]] = call i32 @call_with_two_values(i32 noundef 1) #[[ATTR2]]
87 ; CGSCC-NEXT: [[CSRET2:%.*]] = call i32 @call_with_two_values(i32 noundef -1) #[[ATTR2]]
88 ; CGSCC-NEXT: [[RET:%.*]] = add i32 [[CSRET1]], [[CSRET2]]
89 ; CGSCC-NEXT: ret i32 [[RET]]
91 %csret1 = call i32 @call_with_two_values(i32 1)
92 %csret2 = call i32 @call_with_two_values(i32 -1)
93 %ret = add i32 %csret1, %csret2
100 ; potential values of returned value of f are {0,1}
101 ; potential values of argument of g are {0,1}
102 ; potential value of returned value of g is 1
103 ; then returned value of g can be simplified
105 ; int zero_or_one(int c) { return c < 2; }
106 ; int potential_test3() { return zero_or_one(iszero(0))+zero_or_one(iszero(1)); }
108 define internal i32 @iszero3(i32 %c) {
109 ; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
110 ; CGSCC-LABEL: define {{[^@]+}}@iszero3
111 ; CGSCC-SAME: (i32 noundef [[C:%.*]]) #[[ATTR0]] {
112 ; CGSCC-NEXT: [[CMP:%.*]] = icmp eq i32 [[C]], 0
113 ; CGSCC-NEXT: [[RET:%.*]] = zext i1 [[CMP]] to i32
114 ; CGSCC-NEXT: ret i32 [[RET]]
116 %cmp = icmp eq i32 %c, 0
117 %ret = zext i1 %cmp to i32
121 define internal i32 @less_than_two(i32 %c) {
122 ; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
123 ; CGSCC-LABEL: define {{[^@]+}}@less_than_two
124 ; CGSCC-SAME: (i32 noundef [[C:%.*]]) #[[ATTR0]] {
125 ; CGSCC-NEXT: [[CMP:%.*]] = icmp slt i32 [[C]], 2
126 ; CGSCC-NEXT: [[RET:%.*]] = zext i1 [[CMP]] to i32
127 ; CGSCC-NEXT: ret i32 [[RET]]
129 %cmp = icmp slt i32 %c, 2
130 %ret = zext i1 %cmp to i32
134 define i32 @potential_test3() {
135 ; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
136 ; TUNIT-LABEL: define {{[^@]+}}@potential_test3
137 ; TUNIT-SAME: () #[[ATTR0]] {
138 ; TUNIT-NEXT: ret i32 2
140 ; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
141 ; CGSCC-LABEL: define {{[^@]+}}@potential_test3
142 ; CGSCC-SAME: () #[[ATTR1]] {
143 ; CGSCC-NEXT: [[CMP1:%.*]] = call i32 @iszero3(i32 noundef 0) #[[ATTR2]]
144 ; CGSCC-NEXT: [[TRUE1:%.*]] = call i32 @less_than_two(i32 noundef [[CMP1]]) #[[ATTR2]]
145 ; CGSCC-NEXT: [[CMP2:%.*]] = call i32 @iszero3(i32 noundef 1) #[[ATTR2]]
146 ; CGSCC-NEXT: [[TRUE2:%.*]] = call i32 @less_than_two(i32 noundef [[CMP2]]) #[[ATTR2]]
147 ; CGSCC-NEXT: [[RET:%.*]] = add i32 [[TRUE1]], [[TRUE2]]
148 ; CGSCC-NEXT: ret i32 [[RET]]
150 %cmp1 = call i32 @iszero3(i32 0)
151 %true1 = call i32 @less_than_two(i32 %cmp1)
152 %cmp2 = call i32 @iszero3(i32 1)
153 %true2 = call i32 @less_than_two(i32 %cmp2)
154 %ret = add i32 %true1, %true2
162 ; int potential_test4(int c) { return return1or3(c) == 2; }
163 ; int potential_test5(int c) { return return1or3(c) == return2or4(c); }
166 ; int potential_test6(int c) { return return1or3(c) == 3; }
167 ; int potential_test7(int c) { return return1or3(c) == return3or4(c); }
169 define i32 @potential_test4(i32 %c) {
170 ; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
171 ; TUNIT-LABEL: define {{[^@]+}}@potential_test4
172 ; TUNIT-SAME: (i32 [[C:%.*]]) #[[ATTR0]] {
173 ; TUNIT-NEXT: ret i32 0
175 ; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
176 ; CGSCC-LABEL: define {{[^@]+}}@potential_test4
177 ; CGSCC-SAME: (i32 [[C:%.*]]) #[[ATTR1]] {
178 ; CGSCC-NEXT: [[CSRET:%.*]] = call i32 @return1or3(i32 [[C]]) #[[ATTR2]]
179 ; CGSCC-NEXT: [[FALSE:%.*]] = icmp eq i32 [[CSRET]], 2
180 ; CGSCC-NEXT: [[RET:%.*]] = zext i1 [[FALSE]] to i32
181 ; CGSCC-NEXT: ret i32 [[RET]]
183 %csret = call i32 @return1or3(i32 %c)
184 %false = icmp eq i32 %csret, 2
185 %ret = zext i1 %false to i32
189 define i32 @potential_test5(i32 %c) {
190 ; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
191 ; TUNIT-LABEL: define {{[^@]+}}@potential_test5
192 ; TUNIT-SAME: (i32 [[C:%.*]]) #[[ATTR0]] {
193 ; TUNIT-NEXT: ret i32 0
195 ; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
196 ; CGSCC-LABEL: define {{[^@]+}}@potential_test5
197 ; CGSCC-SAME: (i32 [[C:%.*]]) #[[ATTR1]] {
198 ; CGSCC-NEXT: [[CSRET1:%.*]] = call i32 @return1or3(i32 [[C]]) #[[ATTR2]]
199 ; CGSCC-NEXT: [[CSRET2:%.*]] = call i32 @return2or4(i32 [[C]]) #[[ATTR2]]
200 ; CGSCC-NEXT: [[FALSE:%.*]] = icmp eq i32 [[CSRET1]], [[CSRET2]]
201 ; CGSCC-NEXT: [[RET:%.*]] = zext i1 [[FALSE]] to i32
202 ; CGSCC-NEXT: ret i32 [[RET]]
204 %csret1 = call i32 @return1or3(i32 %c)
205 %csret2 = call i32 @return2or4(i32 %c)
206 %false = icmp eq i32 %csret1, %csret2
207 %ret = zext i1 %false to i32
211 define i1 @potential_test6(i32 %c) {
212 ; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
213 ; TUNIT-LABEL: define {{[^@]+}}@potential_test6
214 ; TUNIT-SAME: (i32 [[C:%.*]]) #[[ATTR0]] {
215 ; TUNIT-NEXT: [[CSRET1:%.*]] = call i32 @return1or3(i32 [[C]]) #[[ATTR1:[0-9]+]]
216 ; TUNIT-NEXT: [[RET:%.*]] = icmp eq i32 [[CSRET1]], 3
217 ; TUNIT-NEXT: ret i1 [[RET]]
219 ; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
220 ; CGSCC-LABEL: define {{[^@]+}}@potential_test6
221 ; CGSCC-SAME: (i32 [[C:%.*]]) #[[ATTR1]] {
222 ; CGSCC-NEXT: [[CSRET1:%.*]] = call i32 @return1or3(i32 [[C]]) #[[ATTR2]]
223 ; CGSCC-NEXT: [[RET:%.*]] = icmp eq i32 [[CSRET1]], 3
224 ; CGSCC-NEXT: ret i1 [[RET]]
226 %csret1 = call i32 @return1or3(i32 %c)
227 %ret = icmp eq i32 %csret1, 3
231 define i1 @potential_test7(i32 %c) {
232 ; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
233 ; TUNIT-LABEL: define {{[^@]+}}@potential_test7
234 ; TUNIT-SAME: (i32 [[C:%.*]]) #[[ATTR0]] {
235 ; TUNIT-NEXT: [[CSRET1:%.*]] = call i32 @return1or3(i32 [[C]]) #[[ATTR1]]
236 ; TUNIT-NEXT: [[CSRET2:%.*]] = call i32 @return3or4(i32 [[C]]) #[[ATTR1]]
237 ; TUNIT-NEXT: [[RET:%.*]] = icmp eq i32 [[CSRET1]], [[CSRET2]]
238 ; TUNIT-NEXT: ret i1 [[RET]]
240 ; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
241 ; CGSCC-LABEL: define {{[^@]+}}@potential_test7
242 ; CGSCC-SAME: (i32 [[C:%.*]]) #[[ATTR1]] {
243 ; CGSCC-NEXT: [[CSRET1:%.*]] = call i32 @return1or3(i32 [[C]]) #[[ATTR2]]
244 ; CGSCC-NEXT: [[CSRET2:%.*]] = call i32 @return3or4(i32 [[C]]) #[[ATTR2]]
245 ; CGSCC-NEXT: [[RET:%.*]] = icmp eq i32 [[CSRET1]], [[CSRET2]]
246 ; CGSCC-NEXT: ret i1 [[RET]]
248 %csret1 = call i32 @return1or3(i32 %c)
249 %csret2 = call i32 @return3or4(i32 %c)
250 %ret = icmp eq i32 %csret1, %csret2
254 define internal i32 @return1or3(i32 %c) {
255 ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
256 ; CHECK-LABEL: define {{[^@]+}}@return1or3
257 ; CHECK-SAME: (i32 [[C:%.*]]) #[[ATTR0:[0-9]+]] {
258 ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[C]], 0
259 ; CHECK-NEXT: [[RET:%.*]] = select i1 [[CMP]], i32 1, i32 3
260 ; CHECK-NEXT: ret i32 [[RET]]
262 %cmp = icmp eq i32 %c, 0
263 %ret = select i1 %cmp, i32 1, i32 3
267 define internal i32 @return2or4(i32 %c) {
268 ; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
269 ; CGSCC-LABEL: define {{[^@]+}}@return2or4
270 ; CGSCC-SAME: (i32 [[C:%.*]]) #[[ATTR0]] {
271 ; CGSCC-NEXT: [[CMP:%.*]] = icmp eq i32 [[C]], 0
272 ; CGSCC-NEXT: [[RET:%.*]] = select i1 [[CMP]], i32 2, i32 4
273 ; CGSCC-NEXT: ret i32 [[RET]]
275 %cmp = icmp eq i32 %c, 0
276 %ret = select i1 %cmp, i32 2, i32 4
280 define internal i32 @return3or4(i32 %c) {
281 ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
282 ; CHECK-LABEL: define {{[^@]+}}@return3or4
283 ; CHECK-SAME: (i32 [[C:%.*]]) #[[ATTR0]] {
284 ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[C]], 0
285 ; CHECK-NEXT: [[RET:%.*]] = select i1 [[CMP]], i32 3, i32 4
286 ; CHECK-NEXT: ret i32 [[RET]]
288 %cmp = icmp eq i32 %c, 0
289 %ret = select i1 %cmp, i32 3, i32 4
295 ; propagate argument to callsite argument
297 define internal i1 @cmp_with_four(i32 %c) {
298 ; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
299 ; CGSCC-LABEL: define {{[^@]+}}@cmp_with_four
300 ; CGSCC-SAME: (i32 [[C:%.*]]) #[[ATTR0]] {
301 ; CGSCC-NEXT: [[CMP:%.*]] = icmp eq i32 [[C]], 4
302 ; CGSCC-NEXT: ret i1 [[CMP]]
304 %cmp = icmp eq i32 %c, 4
308 define internal i1 @wrapper(i32 %c) {
309 ; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
310 ; CGSCC-LABEL: define {{[^@]+}}@wrapper
311 ; CGSCC-SAME: (i32 noundef [[C:%.*]]) #[[ATTR1]] {
312 ; CGSCC-NEXT: [[RET:%.*]] = call i1 @cmp_with_four(i32 noundef [[C]]) #[[ATTR2]]
313 ; CGSCC-NEXT: ret i1 [[RET]]
315 %ret = call i1 @cmp_with_four(i32 %c)
319 define i1 @potential_test8() {
320 ; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
321 ; TUNIT-LABEL: define {{[^@]+}}@potential_test8
322 ; TUNIT-SAME: () #[[ATTR0]] {
323 ; TUNIT-NEXT: ret i1 false
325 ; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
326 ; CGSCC-LABEL: define {{[^@]+}}@potential_test8
327 ; CGSCC-SAME: () #[[ATTR1]] {
328 ; CGSCC-NEXT: [[RES1:%.*]] = call i1 @wrapper(i32 noundef 1) #[[ATTR2]]
329 ; CGSCC-NEXT: [[RES3:%.*]] = call i1 @wrapper(i32 noundef 3) #[[ATTR2]]
330 ; CGSCC-NEXT: [[RES5:%.*]] = call i1 @wrapper(i32 noundef 5) #[[ATTR2]]
331 ; CGSCC-NEXT: [[RES13:%.*]] = or i1 [[RES1]], [[RES3]]
332 ; CGSCC-NEXT: [[RES135:%.*]] = or i1 [[RES13]], [[RES5]]
333 ; CGSCC-NEXT: ret i1 [[RES135]]
335 %res1 = call i1 @wrapper(i32 1)
336 %res3 = call i1 @wrapper(i32 3)
337 %res5 = call i1 @wrapper(i32 5)
338 %res13 = or i1 %res1, %res3
339 %res135 = or i1 %res13, %res5
343 define i1 @potential_test9() {
344 ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
345 ; CHECK-LABEL: define {{[^@]+}}@potential_test9
346 ; CHECK-SAME: () #[[ATTR0]] {
348 ; CHECK-NEXT: br label [[COND:%.*]]
350 ; CHECK-NEXT: [[I_0:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[I_1:%.*]], [[INC:%.*]] ]
351 ; CHECK-NEXT: [[C_0:%.*]] = phi i32 [ 1, [[ENTRY]] ], [ [[C_1:%.*]], [[INC]] ]
352 ; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[I_0]], 10
353 ; CHECK-NEXT: br i1 [[CMP]], label [[BODY:%.*]], label [[END:%.*]]
355 ; CHECK-NEXT: [[C_1]] = mul i32 [[C_0]], -1
356 ; CHECK-NEXT: br label [[INC]]
358 ; CHECK-NEXT: [[I_1]] = add i32 [[I_0]], 1
359 ; CHECK-NEXT: br label [[COND]]
361 ; CHECK-NEXT: ret i1 false
366 %i.0 = phi i32 [0, %entry], [%i.1, %inc]
367 %c.0 = phi i32 [1, %entry], [%c.1, %inc]
368 %cmp = icmp slt i32 %i.0, 10
369 br i1 %cmp, label %body, label %end
371 %c.1 = mul i32 %c.0, -1
374 %i.1 = add i32 %i.0, 1
377 %ret = icmp eq i32 %c.0, 0
382 ; potential returned values of @may_return_undef is {1, -1}
383 ; and returned value of @potential_test10 can be simplified to 0(false)
385 define internal i32 @may_return_undef(i32 %c) {
386 ; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
387 ; CGSCC-LABEL: define {{[^@]+}}@may_return_undef
388 ; CGSCC-SAME: (i32 noundef [[C:%.*]]) #[[ATTR0]] {
389 ; CGSCC-NEXT: switch i32 [[C]], label [[OTHERWISE:%.*]] [
390 ; CGSCC-NEXT: i32 1, label [[A:%.*]]
391 ; CGSCC-NEXT: i32 -1, label [[B:%.*]]
394 ; CGSCC-NEXT: ret i32 1
396 ; CGSCC-NEXT: ret i32 -1
398 ; CGSCC-NEXT: ret i32 undef
400 switch i32 %c, label %otherwise [i32 1, label %a
410 define i1 @potential_test10(i32 %c) {
411 ; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
412 ; TUNIT-LABEL: define {{[^@]+}}@potential_test10
413 ; TUNIT-SAME: (i32 [[C:%.*]]) #[[ATTR0]] {
414 ; TUNIT-NEXT: ret i1 false
416 ; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
417 ; CGSCC-LABEL: define {{[^@]+}}@potential_test10
418 ; CGSCC-SAME: (i32 noundef [[C:%.*]]) #[[ATTR1]] {
419 ; CGSCC-NEXT: [[RET:%.*]] = call i32 @may_return_undef(i32 noundef [[C]]) #[[ATTR2]]
420 ; CGSCC-NEXT: [[CMP:%.*]] = icmp eq i32 [[RET]], 0
421 ; CGSCC-NEXT: ret i1 [[CMP]]
423 %ret = call i32 @may_return_undef(i32 %c)
424 %cmp = icmp eq i32 %ret, 0
428 define i32 @optimize_undef_1(i1 %c) {
429 ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
430 ; CHECK-LABEL: define {{[^@]+}}@optimize_undef_1
431 ; CHECK-SAME: (i1 noundef [[C:%.*]]) #[[ATTR0]] {
432 ; CHECK-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
434 ; CHECK-NEXT: ret i32 0
436 ; CHECK-NEXT: [[UNDEF:%.*]] = add i32 undef, 1
437 ; CHECK-NEXT: ret i32 [[UNDEF]]
439 br i1 %c, label %t, label %f
443 %undef = add i32 undef, 1
447 define i32 @optimize_undef_2(i1 %c) {
448 ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
449 ; CHECK-LABEL: define {{[^@]+}}@optimize_undef_2
450 ; CHECK-SAME: (i1 noundef [[C:%.*]]) #[[ATTR0]] {
451 ; CHECK-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
453 ; CHECK-NEXT: ret i32 0
455 ; CHECK-NEXT: [[UNDEF:%.*]] = sub i32 undef, 1
456 ; CHECK-NEXT: ret i32 [[UNDEF]]
458 br i1 %c, label %t, label %f
462 %undef = sub i32 undef, 1
466 define i32 @optimize_undef_3(i1 %c) {
467 ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
468 ; CHECK-LABEL: define {{[^@]+}}@optimize_undef_3
469 ; CHECK-SAME: (i1 noundef [[C:%.*]]) #[[ATTR0]] {
470 ; CHECK-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
472 ; CHECK-NEXT: ret i32 0
474 ; CHECK-NEXT: ret i32 0
476 br i1 %c, label %t, label %f
480 %undef = icmp eq i32 undef, 0
481 %undef2 = zext i1 %undef to i32
486 ; FIXME: returned value can be simplified to 0
487 define i32 @potential_test11(i1 %c) {
488 ; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
489 ; TUNIT-LABEL: define {{[^@]+}}@potential_test11
490 ; TUNIT-SAME: (i1 [[C:%.*]]) #[[ATTR0]] {
491 ; TUNIT-NEXT: [[ZERO1:%.*]] = call i32 @optimize_undef_1(i1 noundef [[C]]) #[[ATTR1]]
492 ; TUNIT-NEXT: [[ZERO2:%.*]] = call i32 @optimize_undef_2(i1 noundef [[C]]) #[[ATTR1]]
493 ; TUNIT-NEXT: [[ACC1:%.*]] = add i32 [[ZERO1]], [[ZERO2]]
494 ; TUNIT-NEXT: [[ACC2:%.*]] = add i32 [[ACC1]], 0
495 ; TUNIT-NEXT: ret i32 [[ACC2]]
497 ; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
498 ; CGSCC-LABEL: define {{[^@]+}}@potential_test11
499 ; CGSCC-SAME: (i1 noundef [[C:%.*]]) #[[ATTR1]] {
500 ; CGSCC-NEXT: [[ZERO1:%.*]] = call i32 @optimize_undef_1(i1 noundef [[C]]) #[[ATTR2]]
501 ; CGSCC-NEXT: [[ZERO2:%.*]] = call i32 @optimize_undef_2(i1 noundef [[C]]) #[[ATTR2]]
502 ; CGSCC-NEXT: [[ZERO3:%.*]] = call i32 @optimize_undef_3(i1 noundef [[C]]) #[[ATTR2]]
503 ; CGSCC-NEXT: [[ACC1:%.*]] = add i32 [[ZERO1]], [[ZERO2]]
504 ; CGSCC-NEXT: [[ACC2:%.*]] = add i32 [[ACC1]], [[ZERO3]]
505 ; CGSCC-NEXT: ret i32 [[ACC2]]
507 %zero1 = call i32 @optimize_undef_1(i1 %c)
508 %zero2 = call i32 @optimize_undef_2(i1 %c)
509 %zero3 = call i32 @optimize_undef_3(i1 %c)
510 %acc1 = add i32 %zero1, %zero2
511 %acc2 = add i32 %acc1, %zero3
515 define i32 @optimize_poison_1(i1 %c) {
516 ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
517 ; CHECK-LABEL: define {{[^@]+}}@optimize_poison_1
518 ; CHECK-SAME: (i1 noundef [[C:%.*]]) #[[ATTR0]] {
519 ; CHECK-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
521 ; CHECK-NEXT: ret i32 0
523 ; CHECK-NEXT: ret i32 0
525 br i1 %c, label %t, label %f
529 %poison = sub nuw i32 0, 1
533 ; returned value can be simplified to 0
534 define i32 @potential_test12(i1 %c) {
535 ; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
536 ; TUNIT-LABEL: define {{[^@]+}}@potential_test12
537 ; TUNIT-SAME: (i1 [[C:%.*]]) #[[ATTR0]] {
538 ; TUNIT-NEXT: ret i32 0
540 ; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
541 ; CGSCC-LABEL: define {{[^@]+}}@potential_test12
542 ; CGSCC-SAME: (i1 noundef [[C:%.*]]) #[[ATTR1]] {
543 ; CGSCC-NEXT: [[ZERO:%.*]] = call noundef i32 @optimize_poison_1(i1 noundef [[C]]) #[[ATTR2]]
544 ; CGSCC-NEXT: ret i32 [[ZERO]]
546 %zero = call i32 @optimize_poison_1(i1 %c)
551 ; Do not simplify %ret in the callee to `%c`.
552 ; The potential value of %c is {0, 1} (undef is merged).
553 ; However, we should not simplify `and i32 %c, 3` to `%c`
555 define internal i32 @potential_test13_callee(i32 %c) {
556 ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
557 ; CHECK-LABEL: define {{[^@]+}}@potential_test13_callee
558 ; CHECK-SAME: (i32 [[C:%.*]]) #[[ATTR0]] {
559 ; CHECK-NEXT: [[RET:%.*]] = and i32 [[C]], 3
560 ; CHECK-NEXT: ret i32 [[RET]]
566 define i32 @potential_test13_caller1() {
567 ; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
568 ; TUNIT-LABEL: define {{[^@]+}}@potential_test13_caller1
569 ; TUNIT-SAME: () #[[ATTR0]] {
570 ; TUNIT-NEXT: [[RET:%.*]] = call i32 @potential_test13_callee(i32 noundef 0) #[[ATTR1]]
571 ; TUNIT-NEXT: ret i32 [[RET]]
573 ; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
574 ; CGSCC-LABEL: define {{[^@]+}}@potential_test13_caller1
575 ; CGSCC-SAME: () #[[ATTR1]] {
576 ; CGSCC-NEXT: [[RET:%.*]] = call noundef i32 @potential_test13_callee(i32 noundef 0) #[[ATTR2]]
577 ; CGSCC-NEXT: ret i32 [[RET]]
579 %ret = call i32 @potential_test13_callee(i32 0)
583 define i32 @potential_test13_caller2() {
584 ; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
585 ; TUNIT-LABEL: define {{[^@]+}}@potential_test13_caller2
586 ; TUNIT-SAME: () #[[ATTR0]] {
587 ; TUNIT-NEXT: [[RET:%.*]] = call i32 @potential_test13_callee(i32 noundef 1) #[[ATTR1]]
588 ; TUNIT-NEXT: ret i32 [[RET]]
590 ; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
591 ; CGSCC-LABEL: define {{[^@]+}}@potential_test13_caller2
592 ; CGSCC-SAME: () #[[ATTR1]] {
593 ; CGSCC-NEXT: [[RET:%.*]] = call noundef i32 @potential_test13_callee(i32 noundef 1) #[[ATTR2]]
594 ; CGSCC-NEXT: ret i32 [[RET]]
596 %ret = call i32 @potential_test13_callee(i32 1)
600 define i32 @potential_test13_caller3() {
601 ; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
602 ; TUNIT-LABEL: define {{[^@]+}}@potential_test13_caller3
603 ; TUNIT-SAME: () #[[ATTR0]] {
604 ; TUNIT-NEXT: [[RET:%.*]] = call i32 @potential_test13_callee(i32 undef) #[[ATTR1]]
605 ; TUNIT-NEXT: ret i32 [[RET]]
607 ; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
608 ; CGSCC-LABEL: define {{[^@]+}}@potential_test13_caller3
609 ; CGSCC-SAME: () #[[ATTR1]] {
610 ; CGSCC-NEXT: [[RET:%.*]] = call noundef i32 @potential_test13_callee(i32 undef) #[[ATTR2]]
611 ; CGSCC-NEXT: ret i32 [[RET]]
613 %ret = call i32 @potential_test13_callee(i32 undef)
617 define i1 @potential_test14(i1 %c0, i1 %c1, i1 %c2, i1 %c3) {
618 ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
619 ; CHECK-LABEL: define {{[^@]+}}@potential_test14
620 ; CHECK-SAME: (i1 [[C0:%.*]], i1 [[C1:%.*]], i1 [[C2:%.*]], i1 [[C3:%.*]]) #[[ATTR0]] {
621 ; CHECK-NEXT: [[X0:%.*]] = select i1 [[C0]], i32 0, i32 1
622 ; CHECK-NEXT: [[X1:%.*]] = select i1 [[C1]], i32 [[X0]], i32 undef
623 ; CHECK-NEXT: [[Y2:%.*]] = select i1 [[C2]], i32 0, i32 7
624 ; CHECK-NEXT: [[Z3:%.*]] = select i1 [[C3]], i32 [[X1]], i32 [[Y2]]
625 ; CHECK-NEXT: [[RET:%.*]] = icmp slt i32 [[Z3]], 7
626 ; CHECK-NEXT: ret i1 [[RET]]
628 %x0 = select i1 %c0, i32 0, i32 1
629 %x1 = select i1 %c1, i32 %x0, i32 undef
630 %y2 = select i1 %c2, i32 0, i32 7
631 %z3 = select i1 %c3, i32 %x1, i32 %y2
632 %ret = icmp slt i32 %z3, 7
636 define i1 @potential_test15(i1 %c0, i1 %c1) {
637 ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
638 ; CHECK-LABEL: define {{[^@]+}}@potential_test15
639 ; CHECK-SAME: (i1 [[C0:%.*]], i1 [[C1:%.*]]) #[[ATTR0]] {
640 ; CHECK-NEXT: ret i1 false
642 %x0 = select i1 %c0, i32 0, i32 1
643 %x1 = select i1 %c1, i32 %x0, i32 undef
644 %ret = icmp eq i32 %x1, 7
648 define i1 @potential_test16(i1 %c0, i1 %c1) {
649 ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
650 ; CHECK-LABEL: define {{[^@]+}}@potential_test16
651 ; CHECK-SAME: (i1 [[C0:%.*]], i1 [[C1:%.*]]) #[[ATTR0]] {
652 ; CHECK-NEXT: ret i1 false
654 %x0 = select i1 %c0, i32 0, i32 undef
655 %x1 = select i1 %c1, i32 %x0, i32 1
656 %ret = icmp eq i32 %x1, 7
661 ; TUNIT: attributes #[[ATTR0]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
662 ; TUNIT: attributes #[[ATTR1]] = { nofree nosync nounwind willreturn memory(none) }
664 ; CGSCC: attributes #[[ATTR0]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
665 ; CGSCC: attributes #[[ATTR1]] = { mustprogress nofree nosync nounwind willreturn memory(none) }
666 ; CGSCC: attributes #[[ATTR2]] = { nofree nosync willreturn }