1 ; RUN: opt -functionattrs -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=10 -S < %s | FileCheck %s
3 ; Test cases specifically designed for the "no-capture" argument attribute.
4 ; We use FIXME's to indicate problems and missing attributes.
6 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
8 ; TEST comparison against NULL
10 ; int is_null_return(int *p) {
14 ; FIXME: no-capture missing for %p
15 ; CHECK: define i32 @is_null_return(i32* readnone %p)
16 define i32 @is_null_return(i32* %p) #0 {
18 %cmp = icmp eq i32* %p, null
19 %conv = zext i1 %cmp to i32
23 ; TEST comparison against NULL in control flow
25 ; int is_null_control(int *p) {
33 ; FIXME: no-capture missing for %p
34 ; CHECK: define i32 @is_null_control(i32* readnone %p)
35 define i32 @is_null_control(i32* %p) #0 {
37 %retval = alloca i32, align 4
38 %cmp = icmp eq i32* %p, null
39 br i1 %cmp, label %if.then, label %if.end
41 if.then: ; preds = %entry
42 store i32 1, i32* %retval, align 4
45 if.end: ; preds = %entry
46 %cmp1 = icmp eq i32* null, %p
47 br i1 %cmp1, label %if.then2, label %if.end3
49 if.then2: ; preds = %if.end
50 store i32 1, i32* %retval, align 4
53 if.end3: ; preds = %if.end
54 store i32 0, i32* %retval, align 4
57 return: ; preds = %if.end3, %if.then2, %if.then
58 %0 = load i32, i32* %retval, align 4
64 ; double *srec0(double *a) {
69 ; CHECK: define noalias nonnull align 536870912 dereferenceable(4294967295) double* @srec0(double* nocapture readnone %a)
70 define double* @srec0(double* %a) #0 {
72 %call = call double* @srec0(double* %a)
76 ; TEST singleton SCC with lots of nested recursive calls
78 ; int* srec16(int* a) {
79 ; return srec16(srec16(srec16(srec16(
80 ; srec16(srec16(srec16(srec16(
81 ; srec16(srec16(srec16(srec16(
82 ; srec16(srec16(srec16(srec16(
87 ; Other arguments are possible here due to the no-return behavior.
89 ; CHECK: define noalias nonnull align 536870912 dereferenceable(4294967295) i32* @srec16(i32* nocapture readnone %a)
90 define i32* @srec16(i32* %a) #0 {
92 %call = call i32* @srec16(i32* %a)
94 ; CHECK-NEXT: unreachable
95 %call1 = call i32* @srec16(i32* %call)
96 %call2 = call i32* @srec16(i32* %call1)
97 %call3 = call i32* @srec16(i32* %call2)
98 %call4 = call i32* @srec16(i32* %call3)
99 %call5 = call i32* @srec16(i32* %call4)
100 %call6 = call i32* @srec16(i32* %call5)
101 %call7 = call i32* @srec16(i32* %call6)
102 %call8 = call i32* @srec16(i32* %call7)
103 %call9 = call i32* @srec16(i32* %call8)
104 %call10 = call i32* @srec16(i32* %call9)
105 %call11 = call i32* @srec16(i32* %call10)
106 %call12 = call i32* @srec16(i32* %call11)
107 %call13 = call i32* @srec16(i32* %call12)
108 %call14 = call i32* @srec16(i32* %call13)
109 %call15 = call i32* @srec16(i32* %call14)
113 ; TEST SCC with various calls, casts, and comparisons agains NULL
115 ; CHECK: define dereferenceable_or_null(4) float* @scc_A(i32* readnone returned dereferenceable_or_null(4) "no-capture-maybe-returned" %a)
117 ; CHECK: define dereferenceable_or_null(8) i64* @scc_B(double* readnone returned dereferenceable_or_null(8) "no-capture-maybe-returned" %a)
119 ; CHECK: define dereferenceable_or_null(2) i8* @scc_C(i16* readnone returned dereferenceable_or_null(2) "no-capture-maybe-returned" %a)
121 ; float *scc_A(int *a) {
122 ; return (float*)(a ? (int*)scc_A((int*)scc_B((double*)scc_C((short*)a))) : a);
125 ; long *scc_B(double *a) {
126 ; return (long*)(a ? scc_C((short*)scc_B((double*)scc_A((int*)a))) : a);
129 ; void *scc_C(short *a) {
130 ; return scc_A((int*)(scc_A(a) ? scc_B((double*)a) : scc_C(a)));
132 define float* @scc_A(i32* dereferenceable_or_null(4) %a) {
134 %tobool = icmp ne i32* %a, null
135 br i1 %tobool, label %cond.true, label %cond.false
137 cond.true: ; preds = %entry
138 %0 = bitcast i32* %a to i16*
139 %call = call i8* @scc_C(i16* %0)
140 %1 = bitcast i8* %call to double*
141 %call1 = call i64* @scc_B(double* %1)
142 %2 = bitcast i64* %call1 to i32*
143 %call2 = call float* @scc_A(i32* %2)
144 %3 = bitcast float* %call2 to i32*
147 cond.false: ; preds = %entry
150 cond.end: ; preds = %cond.false, %cond.true
151 %cond = phi i32* [ %3, %cond.true ], [ %a, %cond.false ]
152 %4 = bitcast i32* %cond to float*
156 define i64* @scc_B(double* dereferenceable_or_null(8) %a) {
158 %tobool = icmp ne double* %a, null
159 br i1 %tobool, label %cond.true, label %cond.false
161 cond.true: ; preds = %entry
162 %0 = bitcast double* %a to i32*
163 %call = call float* @scc_A(i32* %0)
164 %1 = bitcast float* %call to double*
165 %call1 = call i64* @scc_B(double* %1)
166 %2 = bitcast i64* %call1 to i16*
167 %call2 = call i8* @scc_C(i16* %2)
170 cond.false: ; preds = %entry
171 %3 = bitcast double* %a to i8*
174 cond.end: ; preds = %cond.false, %cond.true
175 %cond = phi i8* [ %call2, %cond.true ], [ %3, %cond.false ]
176 %4 = bitcast i8* %cond to i64*
180 define i8* @scc_C(i16* dereferenceable_or_null(2) %a) {
182 %bc = bitcast i16* %a to i32*
183 %call = call float* @scc_A(i32* %bc)
184 %bc2 = bitcast float* %call to i8*
185 %tobool = icmp ne i8* %bc2, null
186 br i1 %tobool, label %cond.true, label %cond.false
188 cond.true: ; preds = %entry
189 %0 = bitcast i16* %a to double*
190 %call1 = call i64* @scc_B(double* %0)
191 %1 = bitcast i64* %call1 to i8*
194 cond.false: ; preds = %entry
195 %call2 = call i8* @scc_C(i16* %a)
198 cond.end: ; preds = %cond.false, %cond.true
199 %cond = phi i8* [ %1, %cond.true ], [ %call2, %cond.false ]
200 %2 = bitcast i8* %cond to i32*
201 %call3 = call float* @scc_A(i32* %2)
202 %3 = bitcast float* %call3 to i8*
207 ; TEST call to external function, marked no-capture
209 ; void external_no_capture(int /* no-capture */ *p);
210 ; void test_external_no_capture(int *p) {
211 ; external_no_capture(p);
214 ; CHECK: define void @test_external_no_capture(i32* nocapture %p)
215 declare void @external_no_capture(i32* nocapture)
217 define void @test_external_no_capture(i32* %p) #0 {
219 call void @external_no_capture(i32* %p)
223 ; TEST call to external var-args function, marked no-capture
225 ; void test_var_arg_call(char *p, int a) {
229 ; CHECK: define void @test_var_arg_call(i8* nocapture %p, i32 %a)
230 define void @test_var_arg_call(i8* %p, i32 %a) #0 {
232 %call = call i32 (i8*, ...) @printf(i8* %p, i32 %a)
236 declare i32 @printf(i8* nocapture, ...)
239 ; TEST "captured" only through return
241 ; long *not_captured_but_returned_0(long *a) {
246 ; There should *not* be a no-capture attribute on %a
247 ; CHECK: define nonnull dereferenceable(8) i64* @not_captured_but_returned_0(i64* nonnull returned writeonly dereferenceable(8) "no-capture-maybe-returned" %a)
249 define i64* @not_captured_but_returned_0(i64* %a) #0 {
251 store i64 0, i64* %a, align 8
255 ; TEST "captured" only through return
257 ; long *not_captured_but_returned_1(long *a) {
262 ; There should *not* be a no-capture attribute on %a
263 ; CHECK: define nonnull i64* @not_captured_but_returned_1(i64* writeonly "no-capture-maybe-returned" %a)
264 define i64* @not_captured_but_returned_1(i64* %a) #0 {
266 %add.ptr = getelementptr inbounds i64, i64* %a, i64 1
267 store i64 1, i64* %add.ptr, align 8
271 ; TEST calls to "captured" only through return functions
273 ; void test_not_captured_but_returned_calls(long *a) {
274 ; not_captured_but_returned_0(a);
275 ; not_captured_but_returned_1(a);
278 ; CHECK: define void @test_not_captured_but_returned_calls(i64* nocapture writeonly %a)
279 define void @test_not_captured_but_returned_calls(i64* %a) #0 {
281 %call = call i64* @not_captured_but_returned_0(i64* %a)
282 %call1 = call i64* @not_captured_but_returned_1(i64* %a)
286 ; TEST "captured" only through transitive return
288 ; long* negative_test_not_captured_but_returned_call_0a(long *a) {
289 ; return not_captured_but_returned_0(a);
292 ; There should *not* be a no-capture attribute on %a
293 ; CHECK: define i64* @negative_test_not_captured_but_returned_call_0a(i64* returned writeonly "no-capture-maybe-returned" %a)
294 define i64* @negative_test_not_captured_but_returned_call_0a(i64* %a) #0 {
296 %call = call i64* @not_captured_but_returned_0(i64* %a)
300 ; TEST captured through write
302 ; void negative_test_not_captured_but_returned_call_0b(long *a) {
303 ; *a = (long)not_captured_but_returned_0(a);
306 ; There should *not* be a no-capture attribute on %a
307 ; CHECK: define void @negative_test_not_captured_but_returned_call_0b(i64* writeonly %a)
308 define void @negative_test_not_captured_but_returned_call_0b(i64* %a) #0 {
310 %call = call i64* @not_captured_but_returned_0(i64* %a)
311 %0 = ptrtoint i64* %call to i64
312 store i64 %0, i64* %a, align 8
316 ; TEST "captured" only through transitive return
318 ; long* negative_test_not_captured_but_returned_call_1a(long *a) {
319 ; return not_captured_but_returned_1(a);
322 ; There should *not* be a no-capture attribute on %a
323 ; CHECK: define nonnull i64* @negative_test_not_captured_but_returned_call_1a(i64* writeonly "no-capture-maybe-returned" %a)
324 define i64* @negative_test_not_captured_but_returned_call_1a(i64* %a) #0 {
326 %call = call i64* @not_captured_but_returned_1(i64* %a)
330 ; TEST captured through write
332 ; void negative_test_not_captured_but_returned_call_1b(long *a) {
333 ; *a = (long)not_captured_but_returned_1(a);
336 ; There should *not* be a no-capture attribute on %a
337 ; CHECK: define void @negative_test_not_captured_but_returned_call_1b(i64* writeonly %a)
338 define void @negative_test_not_captured_but_returned_call_1b(i64* %a) #0 {
340 %call = call i64* @not_captured_but_returned_1(i64* %a)
341 %0 = ptrtoint i64* %call to i64
342 store i64 %0, i64* %call, align 8
346 ; TEST return argument or unknown call result
348 ; int* ret_arg_or_unknown(int* b) {
354 ; Verify we do *not* assume b is returned or not captured.
356 ; CHECK: define i32* @ret_arg_or_unknown(i32* readnone %b)
357 ; CHECK: define i32* @ret_arg_or_unknown_through_phi(i32* readnone %b)
359 declare i32* @unknown()
361 define i32* @ret_arg_or_unknown(i32* %b) #0 {
363 %cmp = icmp eq i32* %b, null
364 br i1 %cmp, label %ret_arg, label %ret_unknown
370 %call = call i32* @unknown()
374 define i32* @ret_arg_or_unknown_through_phi(i32* %b) #0 {
376 %cmp = icmp eq i32* %b, null
377 br i1 %cmp, label %ret_arg, label %ret_unknown
383 %call = call i32* @unknown()
387 %phi = phi i32* [ %b, %ret_arg ], [ %call, %ret_unknown ]
392 ; TEST not captured by readonly external function
394 ; CHECK: define void @not_captured_by_readonly_call(i32* nocapture readonly %b)
395 declare i32* @readonly_unknown(i32*, i32*) readonly
397 define void @not_captured_by_readonly_call(i32* %b) #0 {
399 %call = call i32* @readonly_unknown(i32* %b, i32* %b)
404 ; TEST not captured by readonly external function if return chain is known
406 ; Make sure the returned flag on %r is strong enough to justify nocapture on %b but **not** on %r.
408 ; CHECK: define i32* @not_captured_by_readonly_call_not_returned_either1(i32* nocapture readonly %b, i32* readonly returned %r)
410 ; CHECK: define i32* @not_captured_by_readonly_call_not_returned_either2(i32* nocapture readonly %b, i32* readonly returned %r)
411 ; CHECK: define i32* @not_captured_by_readonly_call_not_returned_either3(i32* nocapture readonly %b, i32* readonly returned %r)
413 ; CHECK: define i32* @not_captured_by_readonly_call_not_returned_either4(i32* nocapture readonly %b, i32* readonly returned %r)
414 define i32* @not_captured_by_readonly_call_not_returned_either1(i32* %b, i32* returned %r) {
416 %call = call i32* @readonly_unknown(i32* %b, i32* %r) nounwind
420 declare i32* @readonly_unknown_r1a(i32*, i32* returned) readonly
421 define i32* @not_captured_by_readonly_call_not_returned_either2(i32* %b, i32* %r) {
423 %call = call i32* @readonly_unknown_r1a(i32* %b, i32* %r) nounwind
427 declare i32* @readonly_unknown_r1b(i32*, i32* returned) readonly nounwind
428 define i32* @not_captured_by_readonly_call_not_returned_either3(i32* %b, i32* %r) {
430 %call = call i32* @readonly_unknown_r1b(i32* %b, i32* %r)
434 define i32* @not_captured_by_readonly_call_not_returned_either4(i32* %b, i32* %r) nounwind {
436 %call = call i32* @readonly_unknown_r1a(i32* %b, i32* %r)
440 attributes #0 = { noinline nounwind uwtable }