Re-land [openmp] Fix warnings when building on Windows with latest MSVC or Clang...
[llvm-project.git] / llvm / test / Transforms / Attributor / nocapture-2.ll
blob1e5e9da19909f6431cd73b8dfe9bf1a11a7437c0
1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-attributes --check-globals --version 2
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 cases specifically designed for the "no-capture" argument attribute.
6 ; We use FIXME's to indicate problems and missing attributes.
8 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
9 declare ptr @unknown()
11 ; TEST comparison against NULL
13 ; int is_null_return(int *p) {
14 ;   return p == 0;
15 ; }
17 ; no-capture is missing on %p because it is not dereferenceable
18 define i32 @is_null_return(ptr %p) #0 {
19 ; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable
20 ; CHECK-LABEL: define i32 @is_null_return
21 ; CHECK-SAME: (ptr nofree readnone [[P:%.*]]) #[[ATTR0:[0-9]+]] {
22 ; CHECK-NEXT:  entry:
23 ; CHECK-NEXT:    [[CMP:%.*]] = icmp eq ptr [[P]], null
24 ; CHECK-NEXT:    [[CONV:%.*]] = zext i1 [[CMP]] to i32
25 ; CHECK-NEXT:    ret i32 [[CONV]]
27 entry:
28   %cmp = icmp eq ptr %p, null
29   %conv = zext i1 %cmp to i32
30   ret i32 %conv
33 ; TEST comparison against NULL in control flow
35 ; int is_null_control(int *p) {
36 ;   if (p == 0)
37 ;     return 1;
38 ;   if (0 == p)
39 ;     return 1;
40 ;   return 0;
41 ; }
43 ; no-capture is missing on %p because it is not dereferenceable
44 define i32 @is_null_control(ptr %p) #0 {
45 ; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable
46 ; CHECK-LABEL: define i32 @is_null_control
47 ; CHECK-SAME: (ptr nofree [[P:%.*]]) #[[ATTR0]] {
48 ; CHECK-NEXT:  entry:
49 ; CHECK-NEXT:    [[RETVAL:%.*]] = alloca i32, align 4
50 ; CHECK-NEXT:    [[CMP:%.*]] = icmp eq ptr [[P]], null
51 ; CHECK-NEXT:    br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
52 ; CHECK:       if.then:
53 ; CHECK-NEXT:    store i32 1, ptr [[RETVAL]], align 4
54 ; CHECK-NEXT:    br label [[RETURN:%.*]]
55 ; CHECK:       if.end:
56 ; CHECK-NEXT:    br label [[IF_END3:%.*]]
57 ; CHECK:       if.then2:
58 ; CHECK-NEXT:    unreachable
59 ; CHECK:       if.end3:
60 ; CHECK-NEXT:    store i32 0, ptr [[RETVAL]], align 4
61 ; CHECK-NEXT:    br label [[RETURN]]
62 ; CHECK:       return:
63 ; CHECK-NEXT:    [[TMP0:%.*]] = load i32, ptr [[RETVAL]], align 4
64 ; CHECK-NEXT:    ret i32 [[TMP0]]
66 entry:
67   %retval = alloca i32, align 4
68   %cmp = icmp eq ptr %p, null
69   br i1 %cmp, label %if.then, label %if.end
71 if.then:                                          ; preds = %entry
72   store i32 1, ptr %retval, align 4
73   br label %return
75 if.end:                                           ; preds = %entry
76   %cmp1 = icmp eq ptr null, %p
77   br i1 %cmp1, label %if.then2, label %if.end3
79 if.then2:                                         ; preds = %if.end
80   store i32 1, ptr %retval, align 4
81   br label %return
83 if.end3:                                          ; preds = %if.end
84   store i32 0, ptr %retval, align 4
85   br label %return
87 return:                                           ; preds = %if.end3, %if.then2, %if.then
88   %0 = load i32, ptr %retval, align 4
89   ret i32 %0
92 ; TEST singleton SCC
94 ; double *srec0(double *a) {
95 ;   srec0(a);
96 ;   return 0;
97 ; }
99 define ptr @srec0(ptr %a) #0 {
100 ; CHECK: Function Attrs: mustprogress nofree noinline nosync nounwind willreturn memory(none) uwtable
101 ; CHECK-LABEL: define noalias noundef align 4294967296 ptr @srec0
102 ; CHECK-SAME: (ptr nocapture nofree readnone [[A:%.*]]) #[[ATTR1:[0-9]+]] {
103 ; CHECK-NEXT:  entry:
104 ; CHECK-NEXT:    ret ptr null
106 entry:
107   %call = call ptr @srec0(ptr %a)
108   ret ptr null
111 ; TEST singleton SCC with lots of nested recursive calls
113 ; int* srec16(int* a) {
114 ;   return srec16(srec16(srec16(srec16(
115 ;          srec16(srec16(srec16(srec16(
116 ;          srec16(srec16(srec16(srec16(
117 ;          srec16(srec16(srec16(srec16(
118 ;                        a
119 ;          ))))))))))))))));
120 ; }
122 ; Other arguments are possible here due to the no-return behavior.
124 define ptr @srec16(ptr %a) #0 {
125 ; CHECK: Function Attrs: mustprogress nofree noinline nosync nounwind willreturn memory(none) uwtable
126 ; CHECK-LABEL: define noalias nonnull align 4294967296 dereferenceable(4294967295) ptr @srec16
127 ; CHECK-SAME: (ptr nocapture nofree readnone [[A:%.*]]) #[[ATTR1]] {
128 ; CHECK-NEXT:  entry:
129 ; CHECK-NEXT:    ret ptr undef
131 entry:
132   %call = call ptr @srec16(ptr %a)
133   %call1 = call ptr @srec16(ptr %call)
134   %call2 = call ptr @srec16(ptr %call1)
135   %call3 = call ptr @srec16(ptr %call2)
136   %call4 = call ptr @srec16(ptr %call3)
137   %call5 = call ptr @srec16(ptr %call4)
138   %call6 = call ptr @srec16(ptr %call5)
139   %call7 = call ptr @srec16(ptr %call6)
140   %call8 = call ptr @srec16(ptr %call7)
141   %call9 = call ptr @srec16(ptr %call8)
142   %call10 = call ptr @srec16(ptr %call9)
143   %call11 = call ptr @srec16(ptr %call10)
144   %call12 = call ptr @srec16(ptr %call11)
145   %call13 = call ptr @srec16(ptr %call12)
146   %call14 = call ptr @srec16(ptr %call13)
147   %call15 = call ptr @srec16(ptr %call14)
148   ret ptr %call15
151 ; TEST SCC with various calls, casts, and comparisons agains NULL
153 ; float *scc_A(int *a) {
154 ;   return (float*)(a ? (int*)scc_A((int*)scc_B((double*)scc_C((short*)a))) : a);
155 ; }
157 ; long *scc_B(double *a) {
158 ;   return (long*)(a ? scc_C((short*)scc_B((double*)scc_A((int*)a))) : a);
159 ; }
161 ; void *scc_C(short *a) {
162 ;   return scc_A((int*)(scc_A(a) ? scc_B((double*)a) : scc_C(a)));
163 ; }
164 define ptr @scc_A(ptr dereferenceable_or_null(4) %a) {
165 ; CHECK: Function Attrs: nofree nosync nounwind memory(none)
166 ; CHECK-LABEL: define noundef dereferenceable_or_null(4) ptr @scc_A
167 ; CHECK-SAME: (ptr nofree noundef readnone returned dereferenceable_or_null(4) "no-capture-maybe-returned" [[A:%.*]]) #[[ATTR2:[0-9]+]] {
168 ; CHECK-NEXT:  entry:
169 ; CHECK-NEXT:    [[TOBOOL:%.*]] = icmp ne ptr [[A]], null
170 ; CHECK-NEXT:    br i1 [[TOBOOL]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
171 ; CHECK:       cond.true:
172 ; CHECK-NEXT:    [[CALL:%.*]] = call dereferenceable_or_null(4) ptr @scc_C(ptr noalias nofree noundef nonnull readnone dereferenceable(4) "no-capture-maybe-returned" [[A]]) #[[ATTR2]]
173 ; CHECK-NEXT:    [[CALL1:%.*]] = call dereferenceable_or_null(8) ptr @scc_B(ptr noalias nofree noundef readnone dereferenceable_or_null(8) "no-capture-maybe-returned" [[A]]) #[[ATTR2]]
174 ; CHECK-NEXT:    [[CALL2:%.*]] = call ptr @scc_A(ptr noalias nofree noundef readnone dereferenceable_or_null(8) "no-capture-maybe-returned" [[A]]) #[[ATTR2]]
175 ; CHECK-NEXT:    br label [[COND_END:%.*]]
176 ; CHECK:       cond.false:
177 ; CHECK-NEXT:    br label [[COND_END]]
178 ; CHECK:       cond.end:
179 ; CHECK-NEXT:    [[COND:%.*]] = phi ptr [ [[A]], [[COND_TRUE]] ], [ [[A]], [[COND_FALSE]] ]
180 ; CHECK-NEXT:    ret ptr [[A]]
182 entry:
183   %tobool = icmp ne ptr %a, null
184   br i1 %tobool, label %cond.true, label %cond.false
186 cond.true:                                        ; preds = %entry
187   %call = call ptr @scc_C(ptr %a)
188   %call1 = call ptr @scc_B(ptr %call)
189   %call2 = call ptr @scc_A(ptr %call1)
190   br label %cond.end
192 cond.false:                                       ; preds = %entry
193   br label %cond.end
195 cond.end:                                         ; preds = %cond.false, %cond.true
196   %cond = phi ptr [ %call2, %cond.true ], [ %a, %cond.false ]
197   ret ptr %cond
200 ; FIXME: the call1 below to scc_B should return dereferenceable_or_null(8) (as the callee does). Something prevented that deduction and needs to be investigated.
201 define ptr @scc_B(ptr dereferenceable_or_null(8) %a) {
202 ; CHECK: Function Attrs: nofree nosync nounwind memory(none)
203 ; CHECK-LABEL: define noundef dereferenceable_or_null(8) ptr @scc_B
204 ; CHECK-SAME: (ptr nofree noundef readnone returned dereferenceable_or_null(8) "no-capture-maybe-returned" [[A:%.*]]) #[[ATTR2]] {
205 ; CHECK-NEXT:  entry:
206 ; CHECK-NEXT:    [[TOBOOL:%.*]] = icmp ne ptr [[A]], null
207 ; CHECK-NEXT:    br i1 [[TOBOOL]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
208 ; CHECK:       cond.true:
209 ; CHECK-NEXT:    [[CALL:%.*]] = call dereferenceable_or_null(4) ptr @scc_A(ptr noalias nofree noundef nonnull readnone dereferenceable(8) "no-capture-maybe-returned" [[A]]) #[[ATTR2]]
210 ; CHECK-NEXT:    [[CALL1:%.*]] = call dereferenceable_or_null(8) ptr @scc_B(ptr noalias nofree noundef readnone dereferenceable_or_null(8) "no-capture-maybe-returned" [[A]]) #[[ATTR2]]
211 ; CHECK-NEXT:    [[CALL2:%.*]] = call ptr @scc_C(ptr noalias nofree noundef readnone dereferenceable_or_null(8) "no-capture-maybe-returned" [[A]]) #[[ATTR2]]
212 ; CHECK-NEXT:    br label [[COND_END:%.*]]
213 ; CHECK:       cond.false:
214 ; CHECK-NEXT:    br label [[COND_END]]
215 ; CHECK:       cond.end:
216 ; CHECK-NEXT:    [[COND:%.*]] = phi ptr [ [[A]], [[COND_TRUE]] ], [ [[A]], [[COND_FALSE]] ]
217 ; CHECK-NEXT:    ret ptr [[A]]
219 entry:
220   %tobool = icmp ne ptr %a, null
221   br i1 %tobool, label %cond.true, label %cond.false
223 cond.true:                                        ; preds = %entry
224   %call = call ptr @scc_A(ptr %a)
225   %call1 = call ptr @scc_B(ptr %call)
226   %call2 = call ptr @scc_C(ptr %call1)
227   br label %cond.end
229 cond.false:                                       ; preds = %entry
230   br label %cond.end
232 cond.end:                                         ; preds = %cond.false, %cond.true
233   %cond = phi ptr [ %call2, %cond.true ], [ %a, %cond.false ]
234   ret ptr %cond
237 define ptr @scc_C(ptr dereferenceable_or_null(2) %a) {
238 ; CHECK: Function Attrs: nofree nosync nounwind memory(none)
239 ; CHECK-LABEL: define noundef dereferenceable_or_null(4) ptr @scc_C
240 ; CHECK-SAME: (ptr nofree noundef readnone returned dereferenceable_or_null(4) "no-capture-maybe-returned" [[A:%.*]]) #[[ATTR2]] {
241 ; CHECK-NEXT:  entry:
242 ; CHECK-NEXT:    [[CALL:%.*]] = call dereferenceable_or_null(4) ptr @scc_A(ptr noalias nofree noundef readnone dereferenceable_or_null(4) "no-capture-maybe-returned" [[A]]) #[[ATTR2]]
243 ; CHECK-NEXT:    [[TOBOOL:%.*]] = icmp ne ptr [[A]], null
244 ; CHECK-NEXT:    br i1 [[TOBOOL]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
245 ; CHECK:       cond.true:
246 ; CHECK-NEXT:    [[CALL1:%.*]] = call ptr @scc_B(ptr noalias nofree noundef readnone dereferenceable_or_null(8) "no-capture-maybe-returned" [[A]]) #[[ATTR2]]
247 ; CHECK-NEXT:    br label [[COND_END:%.*]]
248 ; CHECK:       cond.false:
249 ; CHECK-NEXT:    [[CALL2:%.*]] = call ptr @scc_C(ptr noalias nofree noundef readnone dereferenceable_or_null(4) "no-capture-maybe-returned" [[A]]) #[[ATTR2]]
250 ; CHECK-NEXT:    br label [[COND_END]]
251 ; CHECK:       cond.end:
252 ; CHECK-NEXT:    [[COND:%.*]] = phi ptr [ [[A]], [[COND_TRUE]] ], [ [[A]], [[COND_FALSE]] ]
253 ; CHECK-NEXT:    [[CALL3:%.*]] = call ptr @scc_A(ptr noalias nofree noundef readnone dereferenceable_or_null(4) "no-capture-maybe-returned" [[A]]) #[[ATTR2]]
254 ; CHECK-NEXT:    ret ptr [[A]]
256 entry:
257   %call = call ptr @scc_A(ptr %a)
258   %tobool = icmp ne ptr %call, null
259   br i1 %tobool, label %cond.true, label %cond.false
261 cond.true:                                        ; preds = %entry
262   %call1 = call ptr @scc_B(ptr %a)
263   br label %cond.end
265 cond.false:                                       ; preds = %entry
266   %call2 = call ptr @scc_C(ptr %a)
267   br label %cond.end
269 cond.end:                                         ; preds = %cond.false, %cond.true
270   %cond = phi ptr [ %call1, %cond.true ], [ %call2, %cond.false ]
271   %call3 = call ptr @scc_A(ptr %cond)
272   ret ptr %call3
276 ; TEST call to external function, marked no-capture
278 ; void external_no_capture(int /* no-capture */ *p);
279 ; void test_external_no_capture(int *p) {
280 ;   external_no_capture(p);
281 ; }
283 declare void @external_no_capture(ptr nocapture)
285 define void @test_external_no_capture(ptr %p) #0 {
286 ; CHECK: Function Attrs: noinline nounwind uwtable
287 ; CHECK-LABEL: define void @test_external_no_capture
288 ; CHECK-SAME: (ptr nocapture [[P:%.*]]) #[[ATTR3:[0-9]+]] {
289 ; CHECK-NEXT:  entry:
290 ; CHECK-NEXT:    call void @external_no_capture(ptr nocapture [[P]])
291 ; CHECK-NEXT:    ret void
293 entry:
294   call void @external_no_capture(ptr %p)
295   ret void
298 ; TEST call to external var-args function, marked no-capture
300 ; void test_var_arg_call(char *p, int a) {
301 ;   printf(p, a);
302 ; }
304 define void @test_var_arg_call(ptr %p, i32 %a) #0 {
305 ; CHECK: Function Attrs: noinline nounwind uwtable
306 ; CHECK-LABEL: define void @test_var_arg_call
307 ; CHECK-SAME: (ptr nocapture [[P:%.*]], i32 [[A:%.*]]) #[[ATTR3]] {
308 ; CHECK-NEXT:  entry:
309 ; CHECK-NEXT:    [[CALL:%.*]] = call i32 (ptr, ...) @printf(ptr nocapture [[P]], i32 [[A]])
310 ; CHECK-NEXT:    ret void
312 entry:
313   %call = call i32 (ptr, ...) @printf(ptr %p, i32 %a)
314   ret void
317 declare i32 @printf(ptr nocapture, ...)
320 ; TEST "captured" only through return
322 ; long *not_captured_but_returned_0(long *a) {
323 ;   *a1 = 0;
324 ;   return a;
325 ; }
327 ; There should *not* be a no-capture attribute on %a
328 define ptr @not_captured_but_returned_0(ptr %a) #0 {
329 ; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(argmem: write) uwtable
330 ; CHECK-LABEL: define noundef nonnull align 8 dereferenceable(8) ptr @not_captured_but_returned_0
331 ; CHECK-SAME: (ptr nofree noundef nonnull returned writeonly align 8 dereferenceable(8) "no-capture-maybe-returned" [[A:%.*]]) #[[ATTR4:[0-9]+]] {
332 ; CHECK-NEXT:  entry:
333 ; CHECK-NEXT:    store i64 0, ptr [[A]], align 8
334 ; CHECK-NEXT:    ret ptr [[A]]
336 entry:
337   store i64 0, ptr %a, align 8
338   ret ptr %a
341 ; TEST "captured" only through return
343 ; long *not_captured_but_returned_1(long *a) {
344 ;   *(a+1) = 1;
345 ;   return a + 1;
346 ; }
348 ; There should *not* be a no-capture attribute on %a
349 define ptr @not_captured_but_returned_1(ptr %a) #0 {
350 ; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(argmem: write) uwtable
351 ; CHECK-LABEL: define noundef nonnull align 8 dereferenceable(8) ptr @not_captured_but_returned_1
352 ; CHECK-SAME: (ptr nofree nonnull writeonly align 8 dereferenceable(16) "no-capture-maybe-returned" [[A:%.*]]) #[[ATTR4]] {
353 ; CHECK-NEXT:  entry:
354 ; CHECK-NEXT:    [[ADD_PTR:%.*]] = getelementptr inbounds i64, ptr [[A]], i64 1
355 ; CHECK-NEXT:    store i64 1, ptr [[ADD_PTR]], align 8
356 ; CHECK-NEXT:    ret ptr [[ADD_PTR]]
358 entry:
359   %add.ptr = getelementptr inbounds i64, ptr %a, i64 1
360   store i64 1, ptr %add.ptr, align 8
361   ret ptr %add.ptr
364 ; TEST calls to "captured" only through return functions
366 ; void test_not_captured_but_returned_calls(long *a) {
367 ;   not_captured_but_returned_0(a);
368 ;   not_captured_but_returned_1(a);
369 ; }
371 define void @test_not_captured_but_returned_calls(ptr %a) #0 {
372 ; TUNIT: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(argmem: write) uwtable
373 ; TUNIT-LABEL: define void @test_not_captured_but_returned_calls
374 ; TUNIT-SAME: (ptr nocapture nofree writeonly align 8 [[A:%.*]]) #[[ATTR4]] {
375 ; TUNIT-NEXT:  entry:
376 ; TUNIT-NEXT:    [[CALL:%.*]] = call ptr @not_captured_but_returned_0(ptr nofree noundef writeonly align 8 "no-capture-maybe-returned" [[A]]) #[[ATTR12:[0-9]+]]
377 ; TUNIT-NEXT:    [[CALL1:%.*]] = call ptr @not_captured_but_returned_1(ptr nofree writeonly align 8 "no-capture-maybe-returned" [[A]]) #[[ATTR12]]
378 ; TUNIT-NEXT:    ret void
380 ; CGSCC: Function Attrs: mustprogress nofree noinline nosync nounwind willreturn memory(argmem: write) uwtable
381 ; CGSCC-LABEL: define void @test_not_captured_but_returned_calls
382 ; CGSCC-SAME: (ptr nofree noundef nonnull writeonly align 8 dereferenceable(16) [[A:%.*]]) #[[ATTR5:[0-9]+]] {
383 ; CGSCC-NEXT:  entry:
384 ; CGSCC-NEXT:    [[CALL:%.*]] = call ptr @not_captured_but_returned_0(ptr nofree noundef nonnull writeonly align 8 dereferenceable(16) [[A]]) #[[ATTR14:[0-9]+]]
385 ; CGSCC-NEXT:    [[CALL1:%.*]] = call ptr @not_captured_but_returned_1(ptr nofree noundef nonnull writeonly align 8 dereferenceable(16) [[A]]) #[[ATTR14]]
386 ; CGSCC-NEXT:    ret void
388 entry:
389   %call = call ptr @not_captured_but_returned_0(ptr %a)
390   %call1 = call ptr @not_captured_but_returned_1(ptr %a)
391   ret void
394 ; TEST "captured" only through transitive return
396 ; long* negative_test_not_captured_but_returned_call_0a(long *a) {
397 ;   return not_captured_but_returned_0(a);
398 ; }
400 ; There should *not* be a no-capture attribute on %a
401 define ptr @negative_test_not_captured_but_returned_call_0a(ptr %a) #0 {
402 ; TUNIT: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(argmem: write) uwtable
403 ; TUNIT-LABEL: define align 8 ptr @negative_test_not_captured_but_returned_call_0a
404 ; TUNIT-SAME: (ptr nofree returned writeonly align 8 "no-capture-maybe-returned" [[A:%.*]]) #[[ATTR4]] {
405 ; TUNIT-NEXT:  entry:
406 ; TUNIT-NEXT:    [[CALL:%.*]] = call ptr @not_captured_but_returned_0(ptr nofree noundef writeonly align 8 "no-capture-maybe-returned" [[A]]) #[[ATTR12]]
407 ; TUNIT-NEXT:    ret ptr [[A]]
409 ; CGSCC: Function Attrs: mustprogress nofree noinline nosync nounwind willreturn memory(argmem: write) uwtable
410 ; CGSCC-LABEL: define noundef nonnull align 8 dereferenceable(8) ptr @negative_test_not_captured_but_returned_call_0a
411 ; CGSCC-SAME: (ptr nofree noundef nonnull writeonly align 8 dereferenceable(8) [[A:%.*]]) #[[ATTR5]] {
412 ; CGSCC-NEXT:  entry:
413 ; CGSCC-NEXT:    [[CALL:%.*]] = call noundef nonnull align 8 dereferenceable(8) ptr @not_captured_but_returned_0(ptr nofree noundef nonnull writeonly align 8 dereferenceable(8) [[A]]) #[[ATTR14]]
414 ; CGSCC-NEXT:    ret ptr [[CALL]]
416 entry:
417   %call = call ptr @not_captured_but_returned_0(ptr %a)
418   ret ptr %call
421 ; TEST captured through write
423 ; void negative_test_not_captured_but_returned_call_0b(long *a) {
424 ;   *a = (long)not_captured_but_returned_0(a);
425 ; }
427 ; There should *not* be a no-capture attribute on %a
428 define void @negative_test_not_captured_but_returned_call_0b(ptr %a) #0 {
429 ; TUNIT: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(argmem: write) uwtable
430 ; TUNIT-LABEL: define void @negative_test_not_captured_but_returned_call_0b
431 ; TUNIT-SAME: (ptr nofree writeonly align 8 [[A:%.*]]) #[[ATTR4]] {
432 ; TUNIT-NEXT:  entry:
433 ; TUNIT-NEXT:    [[CALL:%.*]] = call ptr @not_captured_but_returned_0(ptr nofree noundef writeonly align 8 "no-capture-maybe-returned" [[A]]) #[[ATTR12]]
434 ; TUNIT-NEXT:    [[TMP0:%.*]] = ptrtoint ptr [[A]] to i64
435 ; TUNIT-NEXT:    store i64 [[TMP0]], ptr [[A]], align 8
436 ; TUNIT-NEXT:    ret void
438 ; CGSCC: Function Attrs: mustprogress nofree noinline nosync nounwind willreturn memory(argmem: write) uwtable
439 ; CGSCC-LABEL: define void @negative_test_not_captured_but_returned_call_0b
440 ; CGSCC-SAME: (ptr nofree noundef nonnull writeonly align 8 dereferenceable(8) [[A:%.*]]) #[[ATTR5]] {
441 ; CGSCC-NEXT:  entry:
442 ; CGSCC-NEXT:    [[CALL:%.*]] = call ptr @not_captured_but_returned_0(ptr nofree noundef nonnull writeonly align 8 dereferenceable(8) [[A]]) #[[ATTR14]]
443 ; CGSCC-NEXT:    [[TMP0:%.*]] = ptrtoint ptr [[CALL]] to i64
444 ; CGSCC-NEXT:    store i64 [[TMP0]], ptr [[A]], align 8
445 ; CGSCC-NEXT:    ret void
447 entry:
448   %call = call ptr @not_captured_but_returned_0(ptr %a)
449   %0 = ptrtoint ptr %call to i64
450   store i64 %0, ptr %a, align 8
451   ret void
454 ; TEST "captured" only through transitive return
456 ; long* negative_test_not_captured_but_returned_call_1a(long *a) {
457 ;   return not_captured_but_returned_1(a);
458 ; }
460 ; There should *not* be a no-capture attribute on %a
461 define ptr @negative_test_not_captured_but_returned_call_1a(ptr %a) #0 {
462 ; TUNIT: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(argmem: write) uwtable
463 ; TUNIT-LABEL: define noundef nonnull align 8 dereferenceable(8) ptr @negative_test_not_captured_but_returned_call_1a
464 ; TUNIT-SAME: (ptr nofree writeonly align 8 "no-capture-maybe-returned" [[A:%.*]]) #[[ATTR4]] {
465 ; TUNIT-NEXT:  entry:
466 ; TUNIT-NEXT:    [[CALL:%.*]] = call noundef nonnull align 8 dereferenceable(8) ptr @not_captured_but_returned_1(ptr nofree writeonly align 8 "no-capture-maybe-returned" [[A]]) #[[ATTR12]]
467 ; TUNIT-NEXT:    ret ptr [[CALL]]
469 ; CGSCC: Function Attrs: mustprogress nofree noinline nosync nounwind willreturn memory(argmem: write) uwtable
470 ; CGSCC-LABEL: define noundef nonnull align 8 dereferenceable(8) ptr @negative_test_not_captured_but_returned_call_1a
471 ; CGSCC-SAME: (ptr nofree noundef nonnull writeonly align 8 dereferenceable(16) [[A:%.*]]) #[[ATTR5]] {
472 ; CGSCC-NEXT:  entry:
473 ; CGSCC-NEXT:    [[CALL:%.*]] = call noundef nonnull align 8 dereferenceable(8) ptr @not_captured_but_returned_1(ptr nofree noundef nonnull writeonly align 8 dereferenceable(16) [[A]]) #[[ATTR14]]
474 ; CGSCC-NEXT:    ret ptr [[CALL]]
476 entry:
477   %call = call ptr @not_captured_but_returned_1(ptr %a)
478   ret ptr %call
481 ; TEST captured through write
483 ; void negative_test_not_captured_but_returned_call_1b(long *a) {
484 ;   *a = (long)not_captured_but_returned_1(a);
485 ; }
487 ; There should *not* be a no-capture attribute on %a
488 define void @negative_test_not_captured_but_returned_call_1b(ptr %a) #0 {
489 ; TUNIT: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(write) uwtable
490 ; TUNIT-LABEL: define void @negative_test_not_captured_but_returned_call_1b
491 ; TUNIT-SAME: (ptr nofree writeonly align 8 [[A:%.*]]) #[[ATTR5:[0-9]+]] {
492 ; TUNIT-NEXT:  entry:
493 ; TUNIT-NEXT:    [[CALL:%.*]] = call align 8 ptr @not_captured_but_returned_1(ptr nofree writeonly align 8 "no-capture-maybe-returned" [[A]]) #[[ATTR12]]
494 ; TUNIT-NEXT:    [[TMP0:%.*]] = ptrtoint ptr [[CALL]] to i64
495 ; TUNIT-NEXT:    store i64 [[TMP0]], ptr [[CALL]], align 8
496 ; TUNIT-NEXT:    ret void
498 ; CGSCC: Function Attrs: mustprogress nofree noinline nosync nounwind willreturn memory(write) uwtable
499 ; CGSCC-LABEL: define void @negative_test_not_captured_but_returned_call_1b
500 ; CGSCC-SAME: (ptr nofree noundef nonnull writeonly align 8 dereferenceable(16) [[A:%.*]]) #[[ATTR6:[0-9]+]] {
501 ; CGSCC-NEXT:  entry:
502 ; CGSCC-NEXT:    [[CALL:%.*]] = call align 8 ptr @not_captured_but_returned_1(ptr nofree noundef nonnull writeonly align 8 dereferenceable(16) [[A]]) #[[ATTR14]]
503 ; CGSCC-NEXT:    [[TMP0:%.*]] = ptrtoint ptr [[CALL]] to i64
504 ; CGSCC-NEXT:    store i64 [[TMP0]], ptr [[CALL]], align 8
505 ; CGSCC-NEXT:    ret void
507 entry:
508   %call = call ptr @not_captured_but_returned_1(ptr %a)
509   %0 = ptrtoint ptr %call to i64
510   store i64 %0, ptr %call, align 8
511   ret void
514 ; TEST return argument or unknown call result
516 ; int* ret_arg_or_unknown(int* b) {
517 ;   if (b == 0)
518 ;     return b;
519 ;   return unknown();
520 ; }
522 ; Verify we do *not* assume b is returned or not captured.
525 define ptr @ret_arg_or_unknown(ptr %b) #0 {
526 ; CHECK: Function Attrs: noinline nounwind uwtable
527 ; CHECK-LABEL: define ptr @ret_arg_or_unknown
528 ; CHECK-SAME: (ptr [[B:%.*]]) #[[ATTR3]] {
529 ; CHECK-NEXT:  entry:
530 ; CHECK-NEXT:    [[CMP:%.*]] = icmp eq ptr [[B]], null
531 ; CHECK-NEXT:    br i1 [[CMP]], label [[RET_ARG:%.*]], label [[RET_UNKNOWN:%.*]]
532 ; CHECK:       ret_arg:
533 ; CHECK-NEXT:    ret ptr [[B]]
534 ; CHECK:       ret_unknown:
535 ; CHECK-NEXT:    [[CALL:%.*]] = call ptr @unknown()
536 ; CHECK-NEXT:    ret ptr [[CALL]]
538 entry:
539   %cmp = icmp eq ptr %b, null
540   br i1 %cmp, label %ret_arg, label %ret_unknown
542 ret_arg:
543   ret ptr %b
545 ret_unknown:
546   %call = call ptr @unknown()
547   ret ptr %call
550 define ptr @ret_arg_or_unknown_through_phi(ptr %b) #0 {
551 ; CHECK: Function Attrs: noinline nounwind uwtable
552 ; CHECK-LABEL: define ptr @ret_arg_or_unknown_through_phi
553 ; CHECK-SAME: (ptr [[B:%.*]]) #[[ATTR3]] {
554 ; CHECK-NEXT:  entry:
555 ; CHECK-NEXT:    [[CMP:%.*]] = icmp eq ptr [[B]], null
556 ; CHECK-NEXT:    br i1 [[CMP]], label [[RET_ARG:%.*]], label [[RET_UNKNOWN:%.*]]
557 ; CHECK:       ret_arg:
558 ; CHECK-NEXT:    br label [[R:%.*]]
559 ; CHECK:       ret_unknown:
560 ; CHECK-NEXT:    [[CALL:%.*]] = call ptr @unknown()
561 ; CHECK-NEXT:    br label [[R]]
562 ; CHECK:       r:
563 ; CHECK-NEXT:    [[PHI:%.*]] = phi ptr [ [[B]], [[RET_ARG]] ], [ [[CALL]], [[RET_UNKNOWN]] ]
564 ; CHECK-NEXT:    ret ptr [[PHI]]
566 entry:
567   %cmp = icmp eq ptr %b, null
568   br i1 %cmp, label %ret_arg, label %ret_unknown
570 ret_arg:
571   br label %r
573 ret_unknown:
574   %call = call ptr @unknown()
575   br label %r
578   %phi = phi ptr [ %b, %ret_arg ], [ %call, %ret_unknown ]
579   ret ptr %phi
583 ; TEST not captured by readonly external function
585 declare ptr @readonly_unknown(ptr, ptr) readonly
587 define void @not_captured_by_readonly_call(ptr %b) #0 {
588 ; TUNIT: Function Attrs: noinline nosync nounwind memory(read) uwtable
589 ; TUNIT-LABEL: define void @not_captured_by_readonly_call
590 ; TUNIT-SAME: (ptr nocapture readonly [[B:%.*]]) #[[ATTR7:[0-9]+]] {
591 ; TUNIT-NEXT:  entry:
592 ; TUNIT-NEXT:    [[CALL:%.*]] = call ptr @readonly_unknown(ptr readonly [[B]], ptr readonly [[B]]) #[[ATTR13:[0-9]+]]
593 ; TUNIT-NEXT:    ret void
595 ; CGSCC: Function Attrs: noinline nosync nounwind memory(read) uwtable
596 ; CGSCC-LABEL: define void @not_captured_by_readonly_call
597 ; CGSCC-SAME: (ptr nocapture readonly [[B:%.*]]) #[[ATTR8:[0-9]+]] {
598 ; CGSCC-NEXT:  entry:
599 ; CGSCC-NEXT:    [[CALL:%.*]] = call ptr @readonly_unknown(ptr readonly [[B]], ptr readonly [[B]]) #[[ATTR15:[0-9]+]]
600 ; CGSCC-NEXT:    ret void
602 entry:
603   %call = call ptr @readonly_unknown(ptr %b, ptr %b)
604   ret void
608 ; TEST not captured by readonly external function if return chain is known
610 ; Make sure the returned flag on %r is strong enough to justify nocapture on %b but **not** on %r.
612 define ptr @not_captured_by_readonly_call_not_returned_either1(ptr %b, ptr returned %r) {
613 ; TUNIT: Function Attrs: nosync nounwind memory(read)
614 ; TUNIT-LABEL: define ptr @not_captured_by_readonly_call_not_returned_either1
615 ; TUNIT-SAME: (ptr nocapture readonly [[B:%.*]], ptr readonly returned [[R:%.*]]) #[[ATTR8:[0-9]+]] {
616 ; TUNIT-NEXT:  entry:
617 ; TUNIT-NEXT:    [[CALL:%.*]] = call ptr @readonly_unknown(ptr readonly [[B]], ptr readonly [[R]]) #[[ATTR8]]
618 ; TUNIT-NEXT:    ret ptr [[CALL]]
620 ; CGSCC: Function Attrs: nosync nounwind memory(read)
621 ; CGSCC-LABEL: define ptr @not_captured_by_readonly_call_not_returned_either1
622 ; CGSCC-SAME: (ptr nocapture readonly [[B:%.*]], ptr readonly returned [[R:%.*]]) #[[ATTR9:[0-9]+]] {
623 ; CGSCC-NEXT:  entry:
624 ; CGSCC-NEXT:    [[CALL:%.*]] = call ptr @readonly_unknown(ptr readonly [[B]], ptr readonly [[R]]) #[[ATTR9]]
625 ; CGSCC-NEXT:    ret ptr [[CALL]]
627 entry:
628   %call = call ptr @readonly_unknown(ptr %b, ptr %r) nounwind
629   ret ptr %call
632 declare ptr @readonly_unknown_r1a(ptr, ptr returned) readonly
633 define ptr @not_captured_by_readonly_call_not_returned_either2(ptr %b, ptr %r) {
634 ; TUNIT: Function Attrs: nosync nounwind memory(read)
635 ; TUNIT-LABEL: define ptr @not_captured_by_readonly_call_not_returned_either2
636 ; TUNIT-SAME: (ptr readonly [[B:%.*]], ptr readonly [[R:%.*]]) #[[ATTR8]] {
637 ; TUNIT-NEXT:  entry:
638 ; TUNIT-NEXT:    [[CALL:%.*]] = call ptr @readonly_unknown_r1a(ptr readonly [[B]], ptr readonly [[R]]) #[[ATTR8]]
639 ; TUNIT-NEXT:    ret ptr [[CALL]]
641 ; CGSCC: Function Attrs: nosync nounwind memory(read)
642 ; CGSCC-LABEL: define ptr @not_captured_by_readonly_call_not_returned_either2
643 ; CGSCC-SAME: (ptr readonly [[B:%.*]], ptr readonly [[R:%.*]]) #[[ATTR9]] {
644 ; CGSCC-NEXT:  entry:
645 ; CGSCC-NEXT:    [[CALL:%.*]] = call ptr @readonly_unknown_r1a(ptr readonly [[B]], ptr readonly [[R]]) #[[ATTR9]]
646 ; CGSCC-NEXT:    ret ptr [[CALL]]
648 entry:
649   %call = call ptr @readonly_unknown_r1a(ptr %b, ptr %r) nounwind
650   ret ptr %call
653 declare ptr @readonly_unknown_r1b(ptr, ptr returned) readonly nounwind
654 define ptr @not_captured_by_readonly_call_not_returned_either3(ptr %b, ptr %r) {
655 ; TUNIT: Function Attrs: nosync nounwind memory(read)
656 ; TUNIT-LABEL: define ptr @not_captured_by_readonly_call_not_returned_either3
657 ; TUNIT-SAME: (ptr nocapture readonly [[B:%.*]], ptr readonly [[R:%.*]]) #[[ATTR8]] {
658 ; TUNIT-NEXT:  entry:
659 ; TUNIT-NEXT:    [[CALL:%.*]] = call ptr @readonly_unknown_r1b(ptr nocapture readonly [[B]], ptr readonly [[R]]) #[[ATTR8]]
660 ; TUNIT-NEXT:    ret ptr [[CALL]]
662 ; CGSCC: Function Attrs: nosync nounwind memory(read)
663 ; CGSCC-LABEL: define ptr @not_captured_by_readonly_call_not_returned_either3
664 ; CGSCC-SAME: (ptr nocapture readonly [[B:%.*]], ptr readonly [[R:%.*]]) #[[ATTR9]] {
665 ; CGSCC-NEXT:  entry:
666 ; CGSCC-NEXT:    [[CALL:%.*]] = call ptr @readonly_unknown_r1b(ptr nocapture readonly [[B]], ptr readonly [[R]]) #[[ATTR9]]
667 ; CGSCC-NEXT:    ret ptr [[CALL]]
669 entry:
670   %call = call ptr @readonly_unknown_r1b(ptr %b, ptr %r)
671   ret ptr %call
674 define ptr @not_captured_by_readonly_call_not_returned_either4(ptr %b, ptr %r) nounwind {
675 ; TUNIT: Function Attrs: nosync nounwind memory(read)
676 ; TUNIT-LABEL: define ptr @not_captured_by_readonly_call_not_returned_either4
677 ; TUNIT-SAME: (ptr readonly [[B:%.*]], ptr readonly [[R:%.*]]) #[[ATTR8]] {
678 ; TUNIT-NEXT:  entry:
679 ; TUNIT-NEXT:    [[CALL:%.*]] = call ptr @readonly_unknown_r1a(ptr readonly [[B]], ptr readonly [[R]]) #[[ATTR13]]
680 ; TUNIT-NEXT:    ret ptr [[CALL]]
682 ; CGSCC: Function Attrs: nosync nounwind memory(read)
683 ; CGSCC-LABEL: define ptr @not_captured_by_readonly_call_not_returned_either4
684 ; CGSCC-SAME: (ptr readonly [[B:%.*]], ptr readonly [[R:%.*]]) #[[ATTR9]] {
685 ; CGSCC-NEXT:  entry:
686 ; CGSCC-NEXT:    [[CALL:%.*]] = call ptr @readonly_unknown_r1a(ptr readonly [[B]], ptr readonly [[R]]) #[[ATTR15]]
687 ; CGSCC-NEXT:    ret ptr [[CALL]]
689 entry:
690   %call = call ptr @readonly_unknown_r1a(ptr %b, ptr %r)
691   ret ptr %call
695 declare ptr @unknown_i32p(ptr)
696 define void @nocapture_is_not_subsumed_1(ptr nocapture %b) {
697 ; CHECK-LABEL: define void @nocapture_is_not_subsumed_1
698 ; CHECK-SAME: (ptr nocapture [[B:%.*]]) {
699 ; CHECK-NEXT:  entry:
700 ; CHECK-NEXT:    [[CALL:%.*]] = call ptr @unknown_i32p(ptr [[B]])
701 ; CHECK-NEXT:    store i32 0, ptr [[CALL]], align 4
702 ; CHECK-NEXT:    ret void
704 entry:
705   %call = call ptr @unknown_i32p(ptr %b)
706   store i32 0, ptr %call
707   ret void
710 declare ptr @readonly_i32p(ptr) readonly
711 define void @nocapture_is_not_subsumed_2(ptr nocapture %b) {
712 ; TUNIT: Function Attrs: nosync
713 ; TUNIT-LABEL: define void @nocapture_is_not_subsumed_2
714 ; TUNIT-SAME: (ptr nocapture [[B:%.*]]) #[[ATTR10:[0-9]+]] {
715 ; TUNIT-NEXT:  entry:
716 ; TUNIT-NEXT:    [[CALL:%.*]] = call ptr @readonly_i32p(ptr readonly [[B]]) #[[ATTR13]]
717 ; TUNIT-NEXT:    store i32 0, ptr [[CALL]], align 4
718 ; TUNIT-NEXT:    ret void
720 ; CGSCC: Function Attrs: nosync
721 ; CGSCC-LABEL: define void @nocapture_is_not_subsumed_2
722 ; CGSCC-SAME: (ptr nocapture [[B:%.*]]) #[[ATTR11:[0-9]+]] {
723 ; CGSCC-NEXT:  entry:
724 ; CGSCC-NEXT:    [[CALL:%.*]] = call ptr @readonly_i32p(ptr readonly [[B]]) #[[ATTR15]]
725 ; CGSCC-NEXT:    store i32 0, ptr [[CALL]], align 4
726 ; CGSCC-NEXT:    ret void
728 entry:
729   %call = call ptr @readonly_i32p(ptr %b)
730   store i32 0, ptr %call
731   ret void
734 ; Make sure %p is not not marked nocapture (Bug #64613).
735 ; Version a failed with the lightweight attributor, b with the full one.
736 define ptr @b64613_a(ptr noundef %p) {
737 ; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
738 ; TUNIT-LABEL: define noundef ptr @b64613_a
739 ; TUNIT-SAME: (ptr nofree noundef readnone returned "no-capture-maybe-returned" [[P:%.*]]) #[[ATTR11:[0-9]+]] {
740 ; TUNIT-NEXT:    [[P_ADDR:%.*]] = alloca ptr, align 1
741 ; TUNIT-NEXT:    store ptr [[P]], ptr [[P_ADDR]], align 1
742 ; TUNIT-NEXT:    ret ptr [[P]]
744 ; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
745 ; CGSCC-LABEL: define noundef ptr @b64613_a
746 ; CGSCC-SAME: (ptr nofree noundef readnone returned "no-capture-maybe-returned" [[P:%.*]]) #[[ATTR12:[0-9]+]] {
747 ; CGSCC-NEXT:    [[P_ADDR:%.*]] = alloca ptr, align 1
748 ; CGSCC-NEXT:    store ptr [[P]], ptr [[P_ADDR]], align 1
749 ; CGSCC-NEXT:    ret ptr [[P]]
751   %p.addr = alloca ptr, align 1
752   store ptr %p, ptr %p.addr, align 1
753   %r = load ptr, ptr %p.addr, align 1
754   ret ptr %r
756 define ptr @b64613_b(ptr noundef %p, i32 %i) {
757 ; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
758 ; TUNIT-LABEL: define ptr @b64613_b
759 ; TUNIT-SAME: (ptr nofree noundef [[P:%.*]], i32 [[I:%.*]]) #[[ATTR11]] {
760 ; TUNIT-NEXT:    [[P_ADDR:%.*]] = alloca <2 x ptr>, align 1
761 ; TUNIT-NEXT:    [[G:%.*]] = getelementptr i8, ptr [[P_ADDR]], i32 [[I]]
762 ; TUNIT-NEXT:    store ptr [[P]], ptr [[G]], align 1
763 ; TUNIT-NEXT:    [[R:%.*]] = load ptr, ptr [[P_ADDR]], align 1
764 ; TUNIT-NEXT:    ret ptr [[R]]
766 ; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
767 ; CGSCC-LABEL: define ptr @b64613_b
768 ; CGSCC-SAME: (ptr nofree noundef [[P:%.*]], i32 [[I:%.*]]) #[[ATTR12]] {
769 ; CGSCC-NEXT:    [[P_ADDR:%.*]] = alloca <2 x ptr>, align 1
770 ; CGSCC-NEXT:    [[G:%.*]] = getelementptr i8, ptr [[P_ADDR]], i32 [[I]]
771 ; CGSCC-NEXT:    store ptr [[P]], ptr [[G]], align 1
772 ; CGSCC-NEXT:    [[R:%.*]] = load ptr, ptr [[P_ADDR]], align 1
773 ; CGSCC-NEXT:    ret ptr [[R]]
775   %p.addr = alloca <2 x ptr>, align 1
776   %g = getelementptr i8, ptr %p.addr, i32 %i
777   store ptr %p, ptr %g, align 1
778   %r = load ptr, ptr %p.addr, align 1
779   ret ptr %r
781 define void @b64613_positive(ptr noundef %p, i32 %i) {
782 ; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
783 ; TUNIT-LABEL: define void @b64613_positive
784 ; TUNIT-SAME: (ptr nocapture nofree noundef [[P:%.*]], i32 [[I:%.*]]) #[[ATTR11]] {
785 ; TUNIT-NEXT:    [[P_ADDR:%.*]] = alloca <2 x ptr>, align 1
786 ; TUNIT-NEXT:    [[G:%.*]] = getelementptr i8, ptr [[P_ADDR]], i32 [[I]]
787 ; TUNIT-NEXT:    store ptr [[P]], ptr [[G]], align 1
788 ; TUNIT-NEXT:    ret void
790 ; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
791 ; CGSCC-LABEL: define void @b64613_positive
792 ; CGSCC-SAME: (ptr nocapture nofree noundef [[P:%.*]], i32 [[I:%.*]]) #[[ATTR13:[0-9]+]] {
793 ; CGSCC-NEXT:    [[P_ADDR:%.*]] = alloca <2 x ptr>, align 1
794 ; CGSCC-NEXT:    [[G:%.*]] = getelementptr i8, ptr [[P_ADDR]], i32 [[I]]
795 ; CGSCC-NEXT:    store ptr [[P]], ptr [[G]], align 1
796 ; CGSCC-NEXT:    ret void
798   %p.addr = alloca <2 x ptr>, align 1
799   %g = getelementptr i8, ptr %p.addr, i32 %i
800   store ptr %p, ptr %g, align 1
801   %r = load ptr, ptr %p.addr, align 1
802   %q = call ptr @b64613_b(ptr %r, i32 %i)
803   ret void
806 attributes #0 = { noinline nounwind uwtable }
808 ; TUNIT: attributes #[[ATTR0]] = { mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable }
809 ; TUNIT: attributes #[[ATTR1]] = { mustprogress nofree noinline nosync nounwind willreturn memory(none) uwtable }
810 ; TUNIT: attributes #[[ATTR2]] = { nofree nosync nounwind memory(none) }
811 ; TUNIT: attributes #[[ATTR3]] = { noinline nounwind uwtable }
812 ; TUNIT: attributes #[[ATTR4]] = { mustprogress nofree noinline norecurse nosync nounwind willreturn memory(argmem: write) uwtable }
813 ; TUNIT: attributes #[[ATTR5]] = { mustprogress nofree noinline norecurse nosync nounwind willreturn memory(write) uwtable }
814 ; TUNIT: attributes #[[ATTR6:[0-9]+]] = { memory(read) }
815 ; TUNIT: attributes #[[ATTR7]] = { noinline nosync nounwind memory(read) uwtable }
816 ; TUNIT: attributes #[[ATTR8]] = { nosync nounwind memory(read) }
817 ; TUNIT: attributes #[[ATTR9:[0-9]+]] = { nounwind memory(read) }
818 ; TUNIT: attributes #[[ATTR10]] = { nosync }
819 ; TUNIT: attributes #[[ATTR11]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
820 ; TUNIT: attributes #[[ATTR12]] = { nofree nosync nounwind willreturn memory(write) }
821 ; TUNIT: attributes #[[ATTR13]] = { nosync memory(read) }
823 ; CGSCC: attributes #[[ATTR0]] = { mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable }
824 ; CGSCC: attributes #[[ATTR1]] = { mustprogress nofree noinline nosync nounwind willreturn memory(none) uwtable }
825 ; CGSCC: attributes #[[ATTR2]] = { nofree nosync nounwind memory(none) }
826 ; CGSCC: attributes #[[ATTR3]] = { noinline nounwind uwtable }
827 ; CGSCC: attributes #[[ATTR4]] = { mustprogress nofree noinline norecurse nosync nounwind willreturn memory(argmem: write) uwtable }
828 ; CGSCC: attributes #[[ATTR5]] = { mustprogress nofree noinline nosync nounwind willreturn memory(argmem: write) uwtable }
829 ; CGSCC: attributes #[[ATTR6]] = { mustprogress nofree noinline nosync nounwind willreturn memory(write) uwtable }
830 ; CGSCC: attributes #[[ATTR7:[0-9]+]] = { memory(read) }
831 ; CGSCC: attributes #[[ATTR8]] = { noinline nosync nounwind memory(read) uwtable }
832 ; CGSCC: attributes #[[ATTR9]] = { nosync nounwind memory(read) }
833 ; CGSCC: attributes #[[ATTR10:[0-9]+]] = { nounwind memory(read) }
834 ; CGSCC: attributes #[[ATTR11]] = { nosync }
835 ; CGSCC: attributes #[[ATTR12]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
836 ; CGSCC: attributes #[[ATTR13]] = { mustprogress nofree nosync nounwind willreturn memory(none) }
837 ; CGSCC: attributes #[[ATTR14]] = { nofree nounwind willreturn memory(write) }
838 ; CGSCC: attributes #[[ATTR15]] = { nosync memory(read) }