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 target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
7 declare ptr @geti1Ptr()
9 ; Make sure we do *not* return true.
11 ; CHECK: @[[G1:[a-zA-Z0-9_$"\\.-]+]] = private global ptr undef
12 ; CHECK: @[[G2:[a-zA-Z0-9_$"\\.-]+]] = private global ptr undef
13 ; CHECK: @[[G3:[a-zA-Z0-9_$"\\.-]+]] = private global i1 undef
15 define internal i1 @recursive_inst_comparator(ptr %a, ptr %b) {
16 ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
17 ; CHECK-LABEL: define {{[^@]+}}@recursive_inst_comparator
18 ; CHECK-SAME: (ptr noalias nofree readnone [[A:%.*]], ptr noalias nofree readnone [[B:%.*]]) #[[ATTR0:[0-9]+]] {
19 ; CHECK-NEXT: [[CMP:%.*]] = icmp eq ptr [[A]], [[B]]
20 ; CHECK-NEXT: ret i1 [[CMP]]
22 %cmp = icmp eq ptr %a, %b
26 define internal i1 @recursive_inst_generator(i1 %c, ptr %p) {
27 ; TUNIT-LABEL: define {{[^@]+}}@recursive_inst_generator
28 ; TUNIT-SAME: (i1 [[C:%.*]], ptr nofree [[P:%.*]]) {
29 ; TUNIT-NEXT: [[A:%.*]] = call ptr @geti1Ptr()
30 ; TUNIT-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
32 ; TUNIT-NEXT: [[R1:%.*]] = call i1 @recursive_inst_comparator(ptr noalias nofree readnone [[A]], ptr noalias nofree readnone [[P]]) #[[ATTR7:[0-9]+]]
33 ; TUNIT-NEXT: ret i1 [[R1]]
35 ; TUNIT-NEXT: [[R2:%.*]] = call i1 @recursive_inst_generator(i1 noundef true, ptr nofree [[A]])
36 ; TUNIT-NEXT: ret i1 [[R2]]
38 ; CGSCC-LABEL: define {{[^@]+}}@recursive_inst_generator
39 ; CGSCC-SAME: (i1 [[C:%.*]], ptr nofree [[P:%.*]]) {
40 ; CGSCC-NEXT: [[A:%.*]] = call ptr @geti1Ptr()
41 ; CGSCC-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
43 ; CGSCC-NEXT: [[R1:%.*]] = call i1 @recursive_inst_comparator(ptr noalias nofree readnone [[A]], ptr noalias nofree readnone [[P]])
44 ; CGSCC-NEXT: ret i1 [[R1]]
46 ; CGSCC-NEXT: [[R2:%.*]] = call i1 @recursive_inst_generator(i1 noundef true, ptr nofree [[A]])
47 ; CGSCC-NEXT: ret i1 [[R2]]
49 %a = call ptr @geti1Ptr()
50 br i1 %c, label %t, label %f
52 %r1 = call i1 @recursive_inst_comparator(ptr %a, ptr %p)
55 %r2 = call i1 @recursive_inst_generator(i1 true, ptr %a)
59 ; FIXME: This should *not* return true.
60 define i1 @recursive_inst_generator_caller(i1 %c) {
61 ; TUNIT-LABEL: define {{[^@]+}}@recursive_inst_generator_caller
62 ; TUNIT-SAME: (i1 [[C:%.*]]) {
63 ; TUNIT-NEXT: [[CALL:%.*]] = call i1 @recursive_inst_generator(i1 [[C]], ptr undef)
64 ; TUNIT-NEXT: ret i1 [[CALL]]
66 ; CGSCC-LABEL: define {{[^@]+}}@recursive_inst_generator_caller
67 ; CGSCC-SAME: (i1 [[C:%.*]]) {
68 ; CGSCC-NEXT: [[CALL:%.*]] = call i1 @recursive_inst_generator(i1 [[C]], ptr nofree undef)
69 ; CGSCC-NEXT: ret i1 [[CALL]]
71 %call = call i1 @recursive_inst_generator(i1 %c, ptr undef)
75 ; Make sure we do *not* return true.
76 define internal i1 @recursive_inst_compare(i1 %c, ptr %p) {
77 ; CHECK-LABEL: define {{[^@]+}}@recursive_inst_compare
78 ; CHECK-SAME: (i1 [[C:%.*]], ptr [[P:%.*]]) {
79 ; CHECK-NEXT: [[A:%.*]] = call ptr @geti1Ptr()
80 ; CHECK-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
82 ; CHECK-NEXT: [[CMP:%.*]] = icmp eq ptr [[A]], [[P]]
83 ; CHECK-NEXT: ret i1 [[CMP]]
85 ; CHECK-NEXT: [[CALL:%.*]] = call i1 @recursive_inst_compare(i1 noundef true, ptr [[A]])
86 ; CHECK-NEXT: ret i1 [[CALL]]
88 %a = call ptr @geti1Ptr()
89 br i1 %c, label %t, label %f
91 %cmp = icmp eq ptr %a, %p
94 %call = call i1 @recursive_inst_compare(i1 true, ptr %a)
98 ; FIXME: This should *not* return true.
99 define i1 @recursive_inst_compare_caller(i1 %c) {
100 ; CHECK-LABEL: define {{[^@]+}}@recursive_inst_compare_caller
101 ; CHECK-SAME: (i1 [[C:%.*]]) {
102 ; CHECK-NEXT: [[CALL:%.*]] = call i1 @recursive_inst_compare(i1 [[C]], ptr undef)
103 ; CHECK-NEXT: ret i1 [[CALL]]
105 %call = call i1 @recursive_inst_compare(i1 %c, ptr undef)
109 ; Make sure we do *not* return true.
110 define internal i1 @recursive_alloca_compare(i1 %c, ptr %p) {
111 ; CHECK: Function Attrs: nofree nosync nounwind memory(none)
112 ; CHECK-LABEL: define {{[^@]+}}@recursive_alloca_compare
113 ; CHECK-SAME: (i1 noundef [[C:%.*]], ptr noalias nofree readnone [[P:%.*]]) #[[ATTR1:[0-9]+]] {
114 ; CHECK-NEXT: [[A:%.*]] = alloca i1, align 1
115 ; CHECK-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
117 ; CHECK-NEXT: [[CMP:%.*]] = icmp eq ptr [[A]], [[P]]
118 ; CHECK-NEXT: ret i1 [[CMP]]
120 ; CHECK-NEXT: [[CALL:%.*]] = call i1 @recursive_alloca_compare(i1 noundef true, ptr noalias nofree noundef nonnull readnone dereferenceable(1) [[A]]) #[[ATTR1]]
121 ; CHECK-NEXT: ret i1 [[CALL]]
124 br i1 %c, label %t, label %f
126 %cmp = icmp eq ptr %a, %p
129 %call = call i1 @recursive_alloca_compare(i1 true, ptr %a)
133 ; FIXME: This should *not* return true.
134 define i1 @recursive_alloca_compare_caller(i1 %c) {
135 ; TUNIT: Function Attrs: nofree norecurse nosync nounwind memory(none)
136 ; TUNIT-LABEL: define {{[^@]+}}@recursive_alloca_compare_caller
137 ; TUNIT-SAME: (i1 [[C:%.*]]) #[[ATTR2:[0-9]+]] {
138 ; TUNIT-NEXT: [[CALL:%.*]] = call i1 @recursive_alloca_compare(i1 noundef [[C]], ptr undef) #[[ATTR1]]
139 ; TUNIT-NEXT: ret i1 [[CALL]]
141 ; CGSCC: Function Attrs: nofree nosync nounwind memory(none)
142 ; CGSCC-LABEL: define {{[^@]+}}@recursive_alloca_compare_caller
143 ; CGSCC-SAME: (i1 noundef [[C:%.*]]) #[[ATTR1]] {
144 ; CGSCC-NEXT: [[CALL:%.*]] = call i1 @recursive_alloca_compare(i1 noundef [[C]], ptr nofree undef) #[[ATTR1]]
145 ; CGSCC-NEXT: ret i1 [[CALL]]
147 %call = call i1 @recursive_alloca_compare(i1 %c, ptr undef)
151 ; Make sure we do *not* simplify this to return 0 or 1, return 42 is ok though.
152 define internal i8 @recursive_alloca_load_return(i1 %c, ptr %p, i8 %v) {
153 ; TUNIT: Function Attrs: nofree nosync nounwind memory(argmem: readwrite)
154 ; TUNIT-LABEL: define {{[^@]+}}@recursive_alloca_load_return
155 ; TUNIT-SAME: (i1 noundef [[C:%.*]], ptr noalias nocapture nofree readonly [[P:%.*]], i8 noundef [[V:%.*]]) #[[ATTR3:[0-9]+]] {
156 ; TUNIT-NEXT: [[A:%.*]] = alloca i8, align 1
157 ; TUNIT-NEXT: store i8 [[V]], ptr [[A]], align 1
158 ; TUNIT-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
160 ; TUNIT-NEXT: store i8 0, ptr [[A]], align 1
161 ; TUNIT-NEXT: [[L:%.*]] = load i8, ptr [[P]], align 1
162 ; TUNIT-NEXT: ret i8 [[L]]
164 ; TUNIT-NEXT: [[CALL:%.*]] = call i8 @recursive_alloca_load_return(i1 noundef true, ptr noalias nocapture nofree noundef nonnull readonly dereferenceable(1) [[A]], i8 noundef 1) #[[ATTR4:[0-9]+]]
165 ; TUNIT-NEXT: ret i8 [[CALL]]
167 ; CGSCC: Function Attrs: nofree nosync nounwind memory(argmem: readwrite)
168 ; CGSCC-LABEL: define {{[^@]+}}@recursive_alloca_load_return
169 ; CGSCC-SAME: (i1 noundef [[C:%.*]], ptr noalias nocapture nofree readonly [[P:%.*]], i8 noundef [[V:%.*]]) #[[ATTR2:[0-9]+]] {
170 ; CGSCC-NEXT: [[A:%.*]] = alloca i8, align 1
171 ; CGSCC-NEXT: store i8 [[V]], ptr [[A]], align 1
172 ; CGSCC-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
174 ; CGSCC-NEXT: store i8 0, ptr [[A]], align 1
175 ; CGSCC-NEXT: [[L:%.*]] = load i8, ptr [[P]], align 1
176 ; CGSCC-NEXT: ret i8 [[L]]
178 ; CGSCC-NEXT: [[CALL:%.*]] = call i8 @recursive_alloca_load_return(i1 noundef true, ptr noalias nocapture nofree noundef nonnull readonly dereferenceable(1) [[A]], i8 noundef 1) #[[ATTR3:[0-9]+]]
179 ; CGSCC-NEXT: ret i8 [[CALL]]
183 br i1 %c, label %t, label %f
189 %call = call i8 @recursive_alloca_load_return(i1 true, ptr %a, i8 1)
193 define i8 @recursive_alloca_load_return_caller(i1 %c) {
194 ; TUNIT: Function Attrs: nofree norecurse nosync nounwind memory(none)
195 ; TUNIT-LABEL: define {{[^@]+}}@recursive_alloca_load_return_caller
196 ; TUNIT-SAME: (i1 [[C:%.*]]) #[[ATTR2]] {
197 ; TUNIT-NEXT: [[CALL:%.*]] = call i8 @recursive_alloca_load_return(i1 noundef [[C]], ptr undef, i8 noundef 42) #[[ATTR4]]
198 ; TUNIT-NEXT: ret i8 [[CALL]]
200 ; CGSCC: Function Attrs: nofree nosync nounwind memory(none)
201 ; CGSCC-LABEL: define {{[^@]+}}@recursive_alloca_load_return_caller
202 ; CGSCC-SAME: (i1 noundef [[C:%.*]]) #[[ATTR1]] {
203 ; CGSCC-NEXT: [[CALL:%.*]] = call i8 @recursive_alloca_load_return(i1 noundef [[C]], ptr nofree undef, i8 noundef 42) #[[ATTR5:[0-9]+]]
204 ; CGSCC-NEXT: ret i8 [[CALL]]
206 %call = call i8 @recursive_alloca_load_return(i1 %c, ptr undef, i8 42)
210 @G1 = private global ptr undef
211 @G2 = private global ptr undef
212 @G3 = private global i1 undef
214 ; Make sure we do *not* return true.
215 define internal i1 @recursive_alloca_compare_global1(i1 %c) {
216 ; TUNIT: Function Attrs: nofree nosync nounwind
217 ; TUNIT-LABEL: define {{[^@]+}}@recursive_alloca_compare_global1
218 ; TUNIT-SAME: (i1 noundef [[C:%.*]]) #[[ATTR4]] {
219 ; TUNIT-NEXT: [[A:%.*]] = alloca i1, align 1
220 ; TUNIT-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
222 ; TUNIT-NEXT: [[P:%.*]] = load ptr, ptr @G1, align 8
223 ; TUNIT-NEXT: [[CMP:%.*]] = icmp eq ptr [[A]], [[P]]
224 ; TUNIT-NEXT: ret i1 [[CMP]]
226 ; TUNIT-NEXT: store ptr [[A]], ptr @G1, align 8
227 ; TUNIT-NEXT: [[CALL:%.*]] = call i1 @recursive_alloca_compare_global1(i1 noundef true) #[[ATTR4]]
228 ; TUNIT-NEXT: ret i1 [[CALL]]
230 ; CGSCC: Function Attrs: nofree nosync nounwind
231 ; CGSCC-LABEL: define {{[^@]+}}@recursive_alloca_compare_global1
232 ; CGSCC-SAME: (i1 noundef [[C:%.*]]) #[[ATTR3]] {
233 ; CGSCC-NEXT: [[A:%.*]] = alloca i1, align 1
234 ; CGSCC-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
236 ; CGSCC-NEXT: [[P:%.*]] = load ptr, ptr @G1, align 8
237 ; CGSCC-NEXT: [[CMP:%.*]] = icmp eq ptr [[A]], [[P]]
238 ; CGSCC-NEXT: ret i1 [[CMP]]
240 ; CGSCC-NEXT: store ptr [[A]], ptr @G1, align 8
241 ; CGSCC-NEXT: [[CALL:%.*]] = call i1 @recursive_alloca_compare_global1(i1 noundef true) #[[ATTR3]]
242 ; CGSCC-NEXT: ret i1 [[CALL]]
245 br i1 %c, label %t, label %f
247 %p = load ptr, ptr @G1
248 %cmp = icmp eq ptr %a, %p
251 store ptr %a, ptr @G1
252 %call = call i1 @recursive_alloca_compare_global1(i1 true)
256 ; FIXME: This should *not* return true.
257 define i1 @recursive_alloca_compare_caller_global1(i1 %c) {
258 ; TUNIT: Function Attrs: nofree norecurse nosync nounwind
259 ; TUNIT-LABEL: define {{[^@]+}}@recursive_alloca_compare_caller_global1
260 ; TUNIT-SAME: (i1 [[C:%.*]]) #[[ATTR5:[0-9]+]] {
261 ; TUNIT-NEXT: [[CALL:%.*]] = call i1 @recursive_alloca_compare_global1(i1 noundef [[C]]) #[[ATTR4]]
262 ; TUNIT-NEXT: ret i1 [[CALL]]
264 ; CGSCC: Function Attrs: nofree nosync nounwind
265 ; CGSCC-LABEL: define {{[^@]+}}@recursive_alloca_compare_caller_global1
266 ; CGSCC-SAME: (i1 noundef [[C:%.*]]) #[[ATTR3]] {
267 ; CGSCC-NEXT: [[CALL:%.*]] = call i1 @recursive_alloca_compare_global1(i1 noundef [[C]]) #[[ATTR5]]
268 ; CGSCC-NEXT: ret i1 [[CALL]]
270 %call = call i1 @recursive_alloca_compare_global1(i1 %c)
274 define internal i1 @recursive_alloca_compare_global2(i1 %c) {
275 ; TUNIT: Function Attrs: nofree nosync nounwind
276 ; TUNIT-LABEL: define {{[^@]+}}@recursive_alloca_compare_global2
277 ; TUNIT-SAME: (i1 noundef [[C:%.*]]) #[[ATTR4]] {
278 ; TUNIT-NEXT: [[A:%.*]] = alloca i1, align 1
279 ; TUNIT-NEXT: [[P:%.*]] = load ptr, ptr @G2, align 8
280 ; TUNIT-NEXT: store ptr [[A]], ptr @G2, align 8
281 ; TUNIT-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
283 ; TUNIT-NEXT: [[CMP:%.*]] = icmp eq ptr [[A]], [[P]]
284 ; TUNIT-NEXT: ret i1 [[CMP]]
286 ; TUNIT-NEXT: [[CALL:%.*]] = call i1 @recursive_alloca_compare_global2(i1 noundef true) #[[ATTR4]]
287 ; TUNIT-NEXT: ret i1 [[CALL]]
289 ; CGSCC: Function Attrs: nofree nosync nounwind
290 ; CGSCC-LABEL: define {{[^@]+}}@recursive_alloca_compare_global2
291 ; CGSCC-SAME: (i1 noundef [[C:%.*]]) #[[ATTR3]] {
292 ; CGSCC-NEXT: [[A:%.*]] = alloca i1, align 1
293 ; CGSCC-NEXT: [[P:%.*]] = load ptr, ptr @G2, align 8
294 ; CGSCC-NEXT: store ptr [[A]], ptr @G2, align 8
295 ; CGSCC-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
297 ; CGSCC-NEXT: [[CMP:%.*]] = icmp eq ptr [[A]], [[P]]
298 ; CGSCC-NEXT: ret i1 [[CMP]]
300 ; CGSCC-NEXT: [[CALL:%.*]] = call i1 @recursive_alloca_compare_global2(i1 noundef true) #[[ATTR3]]
301 ; CGSCC-NEXT: ret i1 [[CALL]]
304 %p = load ptr, ptr @G2
305 store ptr %a, ptr @G2
306 br i1 %c, label %t, label %f
308 %cmp = icmp eq ptr %a, %p
311 %call = call i1 @recursive_alloca_compare_global2(i1 true)
315 ; FIXME: This should *not* return true.
316 define i1 @recursive_alloca_compare_caller_global2(i1 %c) {
317 ; TUNIT: Function Attrs: nofree norecurse nosync nounwind
318 ; TUNIT-LABEL: define {{[^@]+}}@recursive_alloca_compare_caller_global2
319 ; TUNIT-SAME: (i1 [[C:%.*]]) #[[ATTR5]] {
320 ; TUNIT-NEXT: [[CALL:%.*]] = call i1 @recursive_alloca_compare_global2(i1 noundef [[C]]) #[[ATTR4]]
321 ; TUNIT-NEXT: ret i1 [[CALL]]
323 ; CGSCC: Function Attrs: nofree nosync nounwind
324 ; CGSCC-LABEL: define {{[^@]+}}@recursive_alloca_compare_caller_global2
325 ; CGSCC-SAME: (i1 noundef [[C:%.*]]) #[[ATTR3]] {
326 ; CGSCC-NEXT: [[CALL:%.*]] = call i1 @recursive_alloca_compare_global2(i1 noundef [[C]]) #[[ATTR5]]
327 ; CGSCC-NEXT: ret i1 [[CALL]]
329 %call = call i1 @recursive_alloca_compare_global2(i1 %c)
332 define internal i1 @recursive_inst_compare_global3(i1 %c) {
334 ; TUNIT: Function Attrs: nofree nosync nounwind
335 ; TUNIT-LABEL: define {{[^@]+}}@recursive_inst_compare_global3
336 ; TUNIT-SAME: (i1 noundef [[C:%.*]]) #[[ATTR4]] {
337 ; TUNIT-NEXT: [[P:%.*]] = load i1, ptr @G3, align 1
338 ; TUNIT-NEXT: store i1 [[C]], ptr @G3, align 1
339 ; TUNIT-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
341 ; TUNIT-NEXT: [[CMP:%.*]] = icmp eq i1 [[C]], [[P]]
342 ; TUNIT-NEXT: ret i1 [[CMP]]
344 ; TUNIT-NEXT: [[CALL:%.*]] = call i1 @recursive_inst_compare_global3(i1 noundef true) #[[ATTR4]]
345 ; TUNIT-NEXT: ret i1 [[CALL]]
347 ; CGSCC: Function Attrs: nofree nosync nounwind
348 ; CGSCC-LABEL: define {{[^@]+}}@recursive_inst_compare_global3
349 ; CGSCC-SAME: (i1 noundef [[C:%.*]]) #[[ATTR3]] {
350 ; CGSCC-NEXT: [[P:%.*]] = load i1, ptr @G3, align 1
351 ; CGSCC-NEXT: store i1 [[C]], ptr @G3, align 1
352 ; CGSCC-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
354 ; CGSCC-NEXT: [[CMP:%.*]] = icmp eq i1 [[C]], [[P]]
355 ; CGSCC-NEXT: ret i1 [[CMP]]
357 ; CGSCC-NEXT: [[CALL:%.*]] = call i1 @recursive_inst_compare_global3(i1 noundef true) #[[ATTR3]]
358 ; CGSCC-NEXT: ret i1 [[CALL]]
360 %p = load i1, ptr @G3
362 br i1 %c, label %t, label %f
364 %cmp = icmp eq i1 %c, %p
367 %call = call i1 @recursive_inst_compare_global3(i1 true)
371 ; FIXME: This should *not* return true.
372 define i1 @recursive_inst_compare_caller_global3(i1 %c) {
373 ; TUNIT: Function Attrs: nofree norecurse nosync nounwind
374 ; TUNIT-LABEL: define {{[^@]+}}@recursive_inst_compare_caller_global3
375 ; TUNIT-SAME: (i1 [[C:%.*]]) #[[ATTR5]] {
376 ; TUNIT-NEXT: [[CALL:%.*]] = call i1 @recursive_inst_compare_global3(i1 noundef [[C]]) #[[ATTR4]]
377 ; TUNIT-NEXT: ret i1 [[CALL]]
379 ; CGSCC: Function Attrs: nofree nosync nounwind
380 ; CGSCC-LABEL: define {{[^@]+}}@recursive_inst_compare_caller_global3
381 ; CGSCC-SAME: (i1 noundef [[C:%.*]]) #[[ATTR3]] {
382 ; CGSCC-NEXT: [[CALL:%.*]] = call i1 @recursive_inst_compare_global3(i1 noundef [[C]]) #[[ATTR5]]
383 ; CGSCC-NEXT: ret i1 [[CALL]]
385 %call = call i1 @recursive_inst_compare_global3(i1 %c)
389 define i32 @non_unique_phi_ops(ptr %ptr) {
390 ; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)
391 ; TUNIT-LABEL: define {{[^@]+}}@non_unique_phi_ops
392 ; TUNIT-SAME: (ptr nocapture nofree readonly [[PTR:%.*]]) #[[ATTR6:[0-9]+]] {
394 ; TUNIT-NEXT: br label [[HEADER:%.*]]
396 ; TUNIT-NEXT: [[I:%.*]] = phi i32 [ [[ADD:%.*]], [[F:%.*]] ], [ 0, [[ENTRY:%.*]] ]
397 ; TUNIT-NEXT: [[P:%.*]] = phi i32 [ [[NON_UNIQUE:%.*]], [[F]] ], [ poison, [[ENTRY]] ]
398 ; TUNIT-NEXT: [[ADD]] = add i32 [[I]], 1
399 ; TUNIT-NEXT: [[G:%.*]] = getelementptr i32, ptr [[PTR]], i32 [[I]]
400 ; TUNIT-NEXT: [[NON_UNIQUE_INPUT:%.*]] = load i32, ptr [[G]], align 4
401 ; TUNIT-NEXT: [[CMP1:%.*]] = icmp eq i32 [[I]], [[NON_UNIQUE_INPUT]]
402 ; TUNIT-NEXT: br i1 [[CMP1]], label [[T:%.*]], label [[F]]
404 ; TUNIT-NEXT: br label [[F]]
406 ; TUNIT-NEXT: [[NON_UNIQUE]] = phi i32 [ [[NON_UNIQUE_INPUT]], [[T]] ], [ [[P]], [[HEADER]] ]
407 ; TUNIT-NEXT: [[CMP2:%.*]] = icmp slt i32 [[I]], 42
408 ; TUNIT-NEXT: br i1 [[CMP2]], label [[HEADER]], label [[END:%.*]]
410 ; TUNIT-NEXT: ret i32 [[P]]
412 ; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)
413 ; CGSCC-LABEL: define {{[^@]+}}@non_unique_phi_ops
414 ; CGSCC-SAME: (ptr nocapture nofree readonly [[PTR:%.*]]) #[[ATTR4:[0-9]+]] {
416 ; CGSCC-NEXT: br label [[HEADER:%.*]]
418 ; CGSCC-NEXT: [[I:%.*]] = phi i32 [ [[ADD:%.*]], [[F:%.*]] ], [ 0, [[ENTRY:%.*]] ]
419 ; CGSCC-NEXT: [[P:%.*]] = phi i32 [ [[NON_UNIQUE:%.*]], [[F]] ], [ poison, [[ENTRY]] ]
420 ; CGSCC-NEXT: [[ADD]] = add i32 [[I]], 1
421 ; CGSCC-NEXT: [[G:%.*]] = getelementptr i32, ptr [[PTR]], i32 [[I]]
422 ; CGSCC-NEXT: [[NON_UNIQUE_INPUT:%.*]] = load i32, ptr [[G]], align 4
423 ; CGSCC-NEXT: [[CMP1:%.*]] = icmp eq i32 [[I]], [[NON_UNIQUE_INPUT]]
424 ; CGSCC-NEXT: br i1 [[CMP1]], label [[T:%.*]], label [[F]]
426 ; CGSCC-NEXT: br label [[F]]
428 ; CGSCC-NEXT: [[NON_UNIQUE]] = phi i32 [ [[NON_UNIQUE_INPUT]], [[T]] ], [ [[P]], [[HEADER]] ]
429 ; CGSCC-NEXT: [[CMP2:%.*]] = icmp slt i32 [[I]], 42
430 ; CGSCC-NEXT: br i1 [[CMP2]], label [[HEADER]], label [[END:%.*]]
432 ; CGSCC-NEXT: ret i32 [[P]]
438 %i = phi i32 [ %add, %f ], [ 0, %entry ]
439 %p = phi i32 [ %non_unique, %f ], [ poison, %entry ]
441 %g = getelementptr i32, ptr %ptr, i32 %i
442 %non_unique_input = load i32, ptr %g, align 4
443 %cmp1 = icmp eq i32 %i, %non_unique_input
444 br i1 %cmp1, label %t, label %f
448 %non_unique = phi i32 [ %non_unique_input, %t ], [ %p, %header ]
449 %cmp2 = icmp slt i32 %i, 42
450 br i1 %cmp2, label %header, label %end
457 ; TUNIT: attributes #[[ATTR0]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
458 ; TUNIT: attributes #[[ATTR1]] = { nofree nosync nounwind memory(none) }
459 ; TUNIT: attributes #[[ATTR2]] = { nofree norecurse nosync nounwind memory(none) }
460 ; TUNIT: attributes #[[ATTR3]] = { nofree nosync nounwind memory(argmem: readwrite) }
461 ; TUNIT: attributes #[[ATTR4]] = { nofree nosync nounwind }
462 ; TUNIT: attributes #[[ATTR5]] = { nofree norecurse nosync nounwind }
463 ; TUNIT: attributes #[[ATTR6]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read) }
464 ; TUNIT: attributes #[[ATTR7]] = { nounwind memory(none) }
466 ; CGSCC: attributes #[[ATTR0]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
467 ; CGSCC: attributes #[[ATTR1]] = { nofree nosync nounwind memory(none) }
468 ; CGSCC: attributes #[[ATTR2]] = { nofree nosync nounwind memory(argmem: readwrite) }
469 ; CGSCC: attributes #[[ATTR3]] = { nofree nosync nounwind }
470 ; CGSCC: attributes #[[ATTR4]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read) }
471 ; CGSCC: attributes #[[ATTR5]] = { nofree nounwind }