xref: /llvm-project/llvm/test/Transforms/Attributor/value-simplify-instances.ll (revision 29441e4f5fa5f5c7709f7cf180815ba97f611297)
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
4
5target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
6
7declare ptr @geti1Ptr()
8
9; Make sure we do *not* return true.
10;.
11; CHECK: @G1 = private global ptr undef
12; CHECK: @G2 = private global ptr undef
13; CHECK: @G3 = private global i1 undef
14;.
15define 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]]
21;
22  %cmp = icmp eq ptr %a, %b
23  ret i1 %cmp
24}
25
26define 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:%.*]]
31; TUNIT:       t:
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]]
34; TUNIT:       f:
35; TUNIT-NEXT:    [[R2:%.*]] = call i1 @recursive_inst_generator(i1 noundef true, ptr nofree [[A]])
36; TUNIT-NEXT:    ret i1 [[R2]]
37;
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:%.*]]
42; CGSCC:       t:
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]]
45; CGSCC:       f:
46; CGSCC-NEXT:    [[R2:%.*]] = call i1 @recursive_inst_generator(i1 noundef true, ptr nofree [[A]])
47; CGSCC-NEXT:    ret i1 [[R2]]
48;
49  %a = call ptr @geti1Ptr()
50  br i1 %c, label %t, label %f
51t:
52  %r1 = call i1 @recursive_inst_comparator(ptr %a, ptr %p)
53  ret i1 %r1
54f:
55  %r2 = call i1 @recursive_inst_generator(i1 true, ptr %a)
56  ret i1 %r2
57}
58
59; FIXME: This should *not* return true.
60define 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]]
65;
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]]
70;
71  %call = call i1 @recursive_inst_generator(i1 %c, ptr undef)
72  ret i1 %call
73}
74
75; Make sure we do *not* return true.
76define 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:%.*]]
81; CHECK:       t:
82; CHECK-NEXT:    [[CMP:%.*]] = icmp eq ptr [[A]], [[P]]
83; CHECK-NEXT:    ret i1 [[CMP]]
84; CHECK:       f:
85; CHECK-NEXT:    [[CALL:%.*]] = call i1 @recursive_inst_compare(i1 noundef true, ptr [[A]])
86; CHECK-NEXT:    ret i1 [[CALL]]
87;
88  %a = call ptr @geti1Ptr()
89  br i1 %c, label %t, label %f
90t:
91  %cmp = icmp eq ptr %a, %p
92  ret i1 %cmp
93f:
94  %call = call i1 @recursive_inst_compare(i1 true, ptr %a)
95  ret i1 %call
96}
97
98; FIXME: This should *not* return true.
99define 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]]
104;
105  %call = call i1 @recursive_inst_compare(i1 %c, ptr undef)
106  ret i1 %call
107}
108
109; Make sure we do *not* return true.
110define 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:%.*]]
116; CHECK:       t:
117; CHECK-NEXT:    [[CMP:%.*]] = icmp eq ptr [[A]], [[P]]
118; CHECK-NEXT:    ret i1 [[CMP]]
119; CHECK:       f:
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]]
122;
123  %a = alloca i1
124  br i1 %c, label %t, label %f
125t:
126  %cmp = icmp eq ptr %a, %p
127  ret i1 %cmp
128f:
129  %call = call i1 @recursive_alloca_compare(i1 true, ptr %a)
130  ret i1 %call
131}
132
133; FIXME: This should *not* return true.
134define 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]]
140;
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]]
146;
147  %call = call i1 @recursive_alloca_compare(i1 %c, ptr undef)
148  ret i1 %call
149}
150
151; Make sure we do *not* simplify this to return 0 or 1, return 42 is ok though.
152define 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 nofree readonly captures(none) [[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:%.*]]
159; TUNIT:       t:
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]]
163; TUNIT:       f:
164; TUNIT-NEXT:    [[CALL:%.*]] = call i8 @recursive_alloca_load_return(i1 noundef true, ptr noalias nofree noundef nonnull readonly captures(none) dereferenceable(1) [[A]], i8 noundef 1) #[[ATTR4:[0-9]+]]
165; TUNIT-NEXT:    ret i8 [[CALL]]
166;
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 nofree readonly captures(none) [[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:%.*]]
173; CGSCC:       t:
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]]
177; CGSCC:       f:
178; CGSCC-NEXT:    [[CALL:%.*]] = call i8 @recursive_alloca_load_return(i1 noundef true, ptr noalias nofree noundef nonnull readonly captures(none) dereferenceable(1) [[A]], i8 noundef 1) #[[ATTR3:[0-9]+]]
179; CGSCC-NEXT:    ret i8 [[CALL]]
180;
181  %a = alloca i8
182  store i8 %v, ptr %a
183  br i1 %c, label %t, label %f
184t:
185  store i8 0, ptr %a
186  %l = load i8, ptr %p
187  ret i8 %l
188f:
189  %call = call i8 @recursive_alloca_load_return(i1 true, ptr %a, i8 1)
190  ret i8 %call
191}
192
193define 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]]
199;
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]]
205;
206  %call = call i8 @recursive_alloca_load_return(i1 %c, ptr undef, i8 42)
207  ret i8 %call
208}
209
210@G1 = private global ptr undef
211@G2 = private global ptr undef
212@G3 = private global i1 undef
213
214; Make sure we do *not* return true.
215define 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:%.*]]
221; TUNIT:       t:
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]]
225; TUNIT:       f:
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]]
229;
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:%.*]]
235; CGSCC:       t:
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]]
239; CGSCC:       f:
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]]
243;
244  %a = alloca i1
245  br i1 %c, label %t, label %f
246t:
247  %p = load ptr, ptr @G1
248  %cmp = icmp eq ptr %a, %p
249  ret i1 %cmp
250f:
251  store ptr %a, ptr @G1
252  %call = call i1 @recursive_alloca_compare_global1(i1 true)
253  ret i1 %call
254}
255
256; FIXME: This should *not* return true.
257define 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]]
263;
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]]
269;
270  %call = call i1 @recursive_alloca_compare_global1(i1 %c)
271  ret i1 %call
272}
273
274define 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:%.*]]
282; TUNIT:       t:
283; TUNIT-NEXT:    [[CMP:%.*]] = icmp eq ptr [[A]], [[P]]
284; TUNIT-NEXT:    ret i1 [[CMP]]
285; TUNIT:       f:
286; TUNIT-NEXT:    [[CALL:%.*]] = call i1 @recursive_alloca_compare_global2(i1 noundef true) #[[ATTR4]]
287; TUNIT-NEXT:    ret i1 [[CALL]]
288;
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:%.*]]
296; CGSCC:       t:
297; CGSCC-NEXT:    [[CMP:%.*]] = icmp eq ptr [[A]], [[P]]
298; CGSCC-NEXT:    ret i1 [[CMP]]
299; CGSCC:       f:
300; CGSCC-NEXT:    [[CALL:%.*]] = call i1 @recursive_alloca_compare_global2(i1 noundef true) #[[ATTR3]]
301; CGSCC-NEXT:    ret i1 [[CALL]]
302;
303  %a = alloca i1
304  %p = load ptr, ptr @G2
305  store ptr %a, ptr @G2
306  br i1 %c, label %t, label %f
307t:
308  %cmp = icmp eq ptr %a, %p
309  ret i1 %cmp
310f:
311  %call = call i1 @recursive_alloca_compare_global2(i1 true)
312  ret i1 %call
313}
314
315; FIXME: This should *not* return true.
316define 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]]
322;
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]]
328;
329  %call = call i1 @recursive_alloca_compare_global2(i1 %c)
330  ret i1 %call
331}
332define internal i1 @recursive_inst_compare_global3(i1 %c) {
333;
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:%.*]]
340; TUNIT:       t:
341; TUNIT-NEXT:    [[CMP:%.*]] = icmp eq i1 [[C]], [[P]]
342; TUNIT-NEXT:    ret i1 [[CMP]]
343; TUNIT:       f:
344; TUNIT-NEXT:    [[CALL:%.*]] = call i1 @recursive_inst_compare_global3(i1 noundef true) #[[ATTR4]]
345; TUNIT-NEXT:    ret i1 [[CALL]]
346;
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:%.*]]
353; CGSCC:       t:
354; CGSCC-NEXT:    [[CMP:%.*]] = icmp eq i1 [[C]], [[P]]
355; CGSCC-NEXT:    ret i1 [[CMP]]
356; CGSCC:       f:
357; CGSCC-NEXT:    [[CALL:%.*]] = call i1 @recursive_inst_compare_global3(i1 noundef true) #[[ATTR3]]
358; CGSCC-NEXT:    ret i1 [[CALL]]
359;
360  %p = load i1, ptr @G3
361  store i1 %c, ptr @G3
362  br i1 %c, label %t, label %f
363t:
364  %cmp = icmp eq i1 %c, %p
365  ret i1 %cmp
366f:
367  %call = call i1 @recursive_inst_compare_global3(i1 true)
368  ret i1 %call
369}
370
371; FIXME: This should *not* return true.
372define 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]]
378;
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]]
384;
385  %call = call i1 @recursive_inst_compare_global3(i1 %c)
386  ret i1 %call
387}
388
389define 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 nofree readonly captures(none) [[PTR:%.*]]) #[[ATTR6:[0-9]+]] {
393; TUNIT-NEXT:  entry:
394; TUNIT-NEXT:    br label [[HEADER:%.*]]
395; TUNIT:       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]]
403; TUNIT:       t:
404; TUNIT-NEXT:    br label [[F]]
405; TUNIT:       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:%.*]]
409; TUNIT:       end:
410; TUNIT-NEXT:    ret i32 [[P]]
411;
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 nofree readonly captures(none) [[PTR:%.*]]) #[[ATTR4:[0-9]+]] {
415; CGSCC-NEXT:  entry:
416; CGSCC-NEXT:    br label [[HEADER:%.*]]
417; CGSCC:       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]]
425; CGSCC:       t:
426; CGSCC-NEXT:    br label [[F]]
427; CGSCC:       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:%.*]]
431; CGSCC:       end:
432; CGSCC-NEXT:    ret i32 [[P]]
433;
434entry:
435  br label %header
436
437header:
438  %i = phi i32 [ %add, %f ], [ 0, %entry ]
439  %p = phi i32 [ %non_unique, %f ], [ poison, %entry ]
440  %add = add i32 %i, 1
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
445t:
446  br label %f
447f:
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
451
452end:
453  ret i32 %p
454}
455
456;.
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) }
465;.
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 }
472;.
473