1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals
2 ; RUN: opt -attributor -enable-new-pm=0 -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=11 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
3 ; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=11 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
4 ; RUN: opt -attributor-cgscc -enable-new-pm=0 -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
5 ; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
7 ; Test cases specifically designed for the "no-capture" argument attribute.
8 ; We use FIXME's to indicate problems and missing attributes.
10 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
11 declare i32* @unknown()
13 ; TEST comparison against NULL
15 ; int is_null_return(int *p) {
19 ; no-capture is missing on %p because it is not dereferenceable
20 define i32 @is_null_return(i32* %p) #0 {
21 ; IS__TUNIT____: Function Attrs: nofree noinline nosync nounwind readnone uwtable willreturn
22 ; IS__TUNIT____-LABEL: define {{[^@]+}}@is_null_return
23 ; IS__TUNIT____-SAME: (i32* nofree readnone [[P:%.*]]) #[[ATTR0:[0-9]+]] {
24 ; IS__TUNIT____-NEXT: entry:
25 ; IS__TUNIT____-NEXT: [[CMP:%.*]] = icmp eq i32* [[P]], null
26 ; IS__TUNIT____-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32
27 ; IS__TUNIT____-NEXT: ret i32 [[CONV]]
29 ; IS__CGSCC____: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable willreturn
30 ; IS__CGSCC____-LABEL: define {{[^@]+}}@is_null_return
31 ; IS__CGSCC____-SAME: (i32* nofree readnone [[P:%.*]]) #[[ATTR0:[0-9]+]] {
32 ; IS__CGSCC____-NEXT: entry:
33 ; IS__CGSCC____-NEXT: [[CMP:%.*]] = icmp eq i32* [[P]], null
34 ; IS__CGSCC____-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32
35 ; IS__CGSCC____-NEXT: ret i32 [[CONV]]
38 %cmp = icmp eq i32* %p, null
39 %conv = zext i1 %cmp to i32
43 ; TEST comparison against NULL in control flow
45 ; int is_null_control(int *p) {
53 ; no-capture is missing on %p because it is not dereferenceable
54 define i32 @is_null_control(i32* %p) #0 {
55 ; IS__TUNIT____: Function Attrs: nofree noinline nosync nounwind readnone uwtable willreturn
56 ; IS__TUNIT____-LABEL: define {{[^@]+}}@is_null_control
57 ; IS__TUNIT____-SAME: (i32* nofree [[P:%.*]]) #[[ATTR0]] {
58 ; IS__TUNIT____-NEXT: entry:
59 ; IS__TUNIT____-NEXT: [[RETVAL:%.*]] = alloca i32, align 4
60 ; IS__TUNIT____-NEXT: [[CMP:%.*]] = icmp eq i32* [[P]], null
61 ; IS__TUNIT____-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
62 ; IS__TUNIT____: if.then:
63 ; IS__TUNIT____-NEXT: store i32 1, i32* [[RETVAL]], align 4
64 ; IS__TUNIT____-NEXT: br label [[RETURN:%.*]]
65 ; IS__TUNIT____: if.end:
66 ; IS__TUNIT____-NEXT: [[CMP1:%.*]] = icmp eq i32* null, [[P]]
67 ; IS__TUNIT____-NEXT: br i1 [[CMP1]], label [[IF_THEN2:%.*]], label [[IF_END3:%.*]]
68 ; IS__TUNIT____: if.then2:
69 ; IS__TUNIT____-NEXT: store i32 1, i32* [[RETVAL]], align 4
70 ; IS__TUNIT____-NEXT: br label [[RETURN]]
71 ; IS__TUNIT____: if.end3:
72 ; IS__TUNIT____-NEXT: store i32 0, i32* [[RETVAL]], align 4
73 ; IS__TUNIT____-NEXT: br label [[RETURN]]
74 ; IS__TUNIT____: return:
75 ; IS__TUNIT____-NEXT: [[TMP0:%.*]] = load i32, i32* [[RETVAL]], align 4
76 ; IS__TUNIT____-NEXT: ret i32 [[TMP0]]
78 ; IS__CGSCC____: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable willreturn
79 ; IS__CGSCC____-LABEL: define {{[^@]+}}@is_null_control
80 ; IS__CGSCC____-SAME: (i32* nofree [[P:%.*]]) #[[ATTR0]] {
81 ; IS__CGSCC____-NEXT: entry:
82 ; IS__CGSCC____-NEXT: [[RETVAL:%.*]] = alloca i32, align 4
83 ; IS__CGSCC____-NEXT: [[CMP:%.*]] = icmp eq i32* [[P]], null
84 ; IS__CGSCC____-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
85 ; IS__CGSCC____: if.then:
86 ; IS__CGSCC____-NEXT: store i32 1, i32* [[RETVAL]], align 4
87 ; IS__CGSCC____-NEXT: br label [[RETURN:%.*]]
88 ; IS__CGSCC____: if.end:
89 ; IS__CGSCC____-NEXT: [[CMP1:%.*]] = icmp eq i32* null, [[P]]
90 ; IS__CGSCC____-NEXT: br i1 [[CMP1]], label [[IF_THEN2:%.*]], label [[IF_END3:%.*]]
91 ; IS__CGSCC____: if.then2:
92 ; IS__CGSCC____-NEXT: store i32 1, i32* [[RETVAL]], align 4
93 ; IS__CGSCC____-NEXT: br label [[RETURN]]
94 ; IS__CGSCC____: if.end3:
95 ; IS__CGSCC____-NEXT: store i32 0, i32* [[RETVAL]], align 4
96 ; IS__CGSCC____-NEXT: br label [[RETURN]]
97 ; IS__CGSCC____: return:
98 ; IS__CGSCC____-NEXT: [[TMP0:%.*]] = load i32, i32* [[RETVAL]], align 4
99 ; IS__CGSCC____-NEXT: ret i32 [[TMP0]]
102 %retval = alloca i32, align 4
103 %cmp = icmp eq i32* %p, null
104 br i1 %cmp, label %if.then, label %if.end
106 if.then: ; preds = %entry
107 store i32 1, i32* %retval, align 4
110 if.end: ; preds = %entry
111 %cmp1 = icmp eq i32* null, %p
112 br i1 %cmp1, label %if.then2, label %if.end3
114 if.then2: ; preds = %if.end
115 store i32 1, i32* %retval, align 4
118 if.end3: ; preds = %if.end
119 store i32 0, i32* %retval, align 4
122 return: ; preds = %if.end3, %if.then2, %if.then
123 %0 = load i32, i32* %retval, align 4
129 ; double *srec0(double *a) {
134 define double* @srec0(double* %a) #0 {
135 ; IS__TUNIT____: Function Attrs: nofree noinline noreturn nosync nounwind readnone uwtable willreturn
136 ; IS__TUNIT____-LABEL: define {{[^@]+}}@srec0
137 ; IS__TUNIT____-SAME: (double* nocapture nofree readnone [[A:%.*]]) #[[ATTR1:[0-9]+]] {
138 ; IS__TUNIT____-NEXT: entry:
139 ; IS__TUNIT____-NEXT: unreachable
141 ; IS__CGSCC____: Function Attrs: nofree noinline norecurse noreturn nosync nounwind readnone uwtable willreturn
142 ; IS__CGSCC____-LABEL: define {{[^@]+}}@srec0
143 ; IS__CGSCC____-SAME: (double* nocapture nofree readnone [[A:%.*]]) #[[ATTR1:[0-9]+]] {
144 ; IS__CGSCC____-NEXT: entry:
145 ; IS__CGSCC____-NEXT: unreachable
148 %call = call double* @srec0(double* %a)
152 ; TEST singleton SCC with lots of nested recursive calls
154 ; int* srec16(int* a) {
155 ; return srec16(srec16(srec16(srec16(
156 ; srec16(srec16(srec16(srec16(
157 ; srec16(srec16(srec16(srec16(
158 ; srec16(srec16(srec16(srec16(
163 ; Other arguments are possible here due to the no-return behavior.
165 define i32* @srec16(i32* %a) #0 {
166 ; IS__TUNIT____: Function Attrs: nofree noinline noreturn nosync nounwind readnone uwtable willreturn
167 ; IS__TUNIT____-LABEL: define {{[^@]+}}@srec16
168 ; IS__TUNIT____-SAME: (i32* nocapture nofree readnone [[A:%.*]]) #[[ATTR1]] {
169 ; IS__TUNIT____-NEXT: entry:
170 ; IS__TUNIT____-NEXT: unreachable
172 ; IS__CGSCC____: Function Attrs: nofree noinline norecurse noreturn nosync nounwind readnone uwtable willreturn
173 ; IS__CGSCC____-LABEL: define {{[^@]+}}@srec16
174 ; IS__CGSCC____-SAME: (i32* nocapture nofree readnone [[A:%.*]]) #[[ATTR1]] {
175 ; IS__CGSCC____-NEXT: entry:
176 ; IS__CGSCC____-NEXT: unreachable
179 %call = call i32* @srec16(i32* %a)
180 %call1 = call i32* @srec16(i32* %call)
181 %call2 = call i32* @srec16(i32* %call1)
182 %call3 = call i32* @srec16(i32* %call2)
183 %call4 = call i32* @srec16(i32* %call3)
184 %call5 = call i32* @srec16(i32* %call4)
185 %call6 = call i32* @srec16(i32* %call5)
186 %call7 = call i32* @srec16(i32* %call6)
187 %call8 = call i32* @srec16(i32* %call7)
188 %call9 = call i32* @srec16(i32* %call8)
189 %call10 = call i32* @srec16(i32* %call9)
190 %call11 = call i32* @srec16(i32* %call10)
191 %call12 = call i32* @srec16(i32* %call11)
192 %call13 = call i32* @srec16(i32* %call12)
193 %call14 = call i32* @srec16(i32* %call13)
194 %call15 = call i32* @srec16(i32* %call14)
198 ; TEST SCC with various calls, casts, and comparisons agains NULL
200 ; float *scc_A(int *a) {
201 ; return (float*)(a ? (int*)scc_A((int*)scc_B((double*)scc_C((short*)a))) : a);
204 ; long *scc_B(double *a) {
205 ; return (long*)(a ? scc_C((short*)scc_B((double*)scc_A((int*)a))) : a);
208 ; void *scc_C(short *a) {
209 ; return scc_A((int*)(scc_A(a) ? scc_B((double*)a) : scc_C(a)));
211 define float* @scc_A(i32* dereferenceable_or_null(4) %a) {
212 ; CHECK: Function Attrs: nofree nosync nounwind readnone
213 ; CHECK-LABEL: define {{[^@]+}}@scc_A
214 ; CHECK-SAME: (i32* nofree readnone dereferenceable_or_null(4) "no-capture-maybe-returned" [[A:%.*]]) #[[ATTR2:[0-9]+]] {
216 ; CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i32* [[A]], null
217 ; CHECK-NEXT: br i1 [[TOBOOL]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
219 ; CHECK-NEXT: [[TMP0:%.*]] = bitcast i32* [[A]] to i16*
220 ; CHECK-NEXT: [[CALL:%.*]] = call dereferenceable_or_null(4) i8* @scc_C(i16* noalias nofree readnone dereferenceable_or_null(4) "no-capture-maybe-returned" [[TMP0]]) #[[ATTR2]]
221 ; CHECK-NEXT: [[TMP1:%.*]] = bitcast i8* [[CALL]] to double*
222 ; CHECK-NEXT: [[CALL1:%.*]] = call dereferenceable_or_null(4) i64* @scc_B(double* noalias nofree readnone dereferenceable_or_null(8) "no-capture-maybe-returned" [[TMP1]]) #[[ATTR2]]
223 ; CHECK-NEXT: [[TMP2:%.*]] = bitcast i64* [[CALL1]] to i32*
224 ; CHECK-NEXT: [[CALL2:%.*]] = call dereferenceable_or_null(4) float* @scc_A(i32* noalias nofree readnone dereferenceable_or_null(4) "no-capture-maybe-returned" [[TMP2]]) #[[ATTR2]]
225 ; CHECK-NEXT: [[TMP3:%.*]] = bitcast float* [[CALL2]] to i32*
226 ; CHECK-NEXT: br label [[COND_END:%.*]]
228 ; CHECK-NEXT: br label [[COND_END]]
230 ; CHECK-NEXT: [[COND:%.*]] = phi i32* [ [[TMP3]], [[COND_TRUE]] ], [ [[A]], [[COND_FALSE]] ]
231 ; CHECK-NEXT: [[TMP4:%.*]] = bitcast i32* [[COND]] to float*
232 ; CHECK-NEXT: ret float* [[TMP4]]
235 %tobool = icmp ne i32* %a, null
236 br i1 %tobool, label %cond.true, label %cond.false
238 cond.true: ; preds = %entry
239 %0 = bitcast i32* %a to i16*
240 %call = call i8* @scc_C(i16* %0)
241 %1 = bitcast i8* %call to double*
242 %call1 = call i64* @scc_B(double* %1)
243 %2 = bitcast i64* %call1 to i32*
244 %call2 = call float* @scc_A(i32* %2)
245 %3 = bitcast float* %call2 to i32*
248 cond.false: ; preds = %entry
251 cond.end: ; preds = %cond.false, %cond.true
252 %cond = phi i32* [ %3, %cond.true ], [ %a, %cond.false ]
253 %4 = bitcast i32* %cond to float*
257 ; 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.
258 define i64* @scc_B(double* dereferenceable_or_null(8) %a) {
259 ; CHECK: Function Attrs: nofree nosync nounwind readnone
260 ; CHECK-LABEL: define {{[^@]+}}@scc_B
261 ; CHECK-SAME: (double* nofree readnone dereferenceable_or_null(8) "no-capture-maybe-returned" [[A:%.*]]) #[[ATTR2]] {
263 ; CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne double* [[A]], null
264 ; CHECK-NEXT: br i1 [[TOBOOL]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
266 ; CHECK-NEXT: [[TMP0:%.*]] = bitcast double* [[A]] to i32*
267 ; CHECK-NEXT: [[CALL:%.*]] = call dereferenceable_or_null(4) float* @scc_A(i32* noalias nofree readnone dereferenceable_or_null(8) "no-capture-maybe-returned" [[TMP0]]) #[[ATTR2]]
268 ; CHECK-NEXT: [[TMP1:%.*]] = bitcast float* [[CALL]] to double*
269 ; CHECK-NEXT: [[CALL1:%.*]] = call dereferenceable_or_null(4) i64* @scc_B(double* noalias nofree readnone dereferenceable_or_null(8) "no-capture-maybe-returned" [[TMP1]]) #[[ATTR2]]
270 ; CHECK-NEXT: [[TMP2:%.*]] = bitcast i64* [[CALL1]] to i16*
271 ; CHECK-NEXT: [[CALL2:%.*]] = call dereferenceable_or_null(4) i8* @scc_C(i16* noalias nofree readnone dereferenceable_or_null(4) "no-capture-maybe-returned" [[TMP2]]) #[[ATTR2]]
272 ; CHECK-NEXT: br label [[COND_END:%.*]]
274 ; CHECK-NEXT: [[TMP3:%.*]] = bitcast double* [[A]] to i8*
275 ; CHECK-NEXT: br label [[COND_END]]
277 ; CHECK-NEXT: [[COND:%.*]] = phi i8* [ [[CALL2]], [[COND_TRUE]] ], [ [[TMP3]], [[COND_FALSE]] ]
278 ; CHECK-NEXT: [[TMP4:%.*]] = bitcast i8* [[COND]] to i64*
279 ; CHECK-NEXT: ret i64* [[TMP4]]
282 %tobool = icmp ne double* %a, null
283 br i1 %tobool, label %cond.true, label %cond.false
285 cond.true: ; preds = %entry
286 %0 = bitcast double* %a to i32*
287 %call = call float* @scc_A(i32* %0)
288 %1 = bitcast float* %call to double*
289 %call1 = call i64* @scc_B(double* %1)
290 %2 = bitcast i64* %call1 to i16*
291 %call2 = call i8* @scc_C(i16* %2)
294 cond.false: ; preds = %entry
295 %3 = bitcast double* %a to i8*
298 cond.end: ; preds = %cond.false, %cond.true
299 %cond = phi i8* [ %call2, %cond.true ], [ %3, %cond.false ]
300 %4 = bitcast i8* %cond to i64*
304 define i8* @scc_C(i16* dereferenceable_or_null(2) %a) {
305 ; CHECK: Function Attrs: nofree nosync nounwind readnone
306 ; CHECK-LABEL: define {{[^@]+}}@scc_C
307 ; CHECK-SAME: (i16* nofree readnone dereferenceable_or_null(4) "no-capture-maybe-returned" [[A:%.*]]) #[[ATTR2]] {
309 ; CHECK-NEXT: [[BC:%.*]] = bitcast i16* [[A]] to i32*
310 ; CHECK-NEXT: [[CALL:%.*]] = call dereferenceable_or_null(4) float* @scc_A(i32* noalias nofree readnone dereferenceable_or_null(4) "no-capture-maybe-returned" [[BC]]) #[[ATTR2]]
311 ; CHECK-NEXT: [[BC2:%.*]] = bitcast float* [[CALL]] to i8*
312 ; CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i8* [[BC2]], null
313 ; CHECK-NEXT: br i1 [[TOBOOL]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
315 ; CHECK-NEXT: [[TMP0:%.*]] = bitcast i16* [[A]] to double*
316 ; CHECK-NEXT: [[CALL1:%.*]] = call dereferenceable_or_null(4) i64* @scc_B(double* noalias nofree readnone dereferenceable_or_null(8) "no-capture-maybe-returned" [[TMP0]]) #[[ATTR2]]
317 ; CHECK-NEXT: [[TMP1:%.*]] = bitcast i64* [[CALL1]] to i8*
318 ; CHECK-NEXT: br label [[COND_END:%.*]]
320 ; CHECK-NEXT: [[CALL2:%.*]] = call dereferenceable_or_null(4) i8* @scc_C(i16* noalias nofree readnone dereferenceable_or_null(4) "no-capture-maybe-returned" [[A]]) #[[ATTR2]]
321 ; CHECK-NEXT: br label [[COND_END]]
323 ; CHECK-NEXT: [[COND:%.*]] = phi i8* [ [[TMP1]], [[COND_TRUE]] ], [ [[CALL2]], [[COND_FALSE]] ]
324 ; CHECK-NEXT: [[TMP2:%.*]] = bitcast i8* [[COND]] to i32*
325 ; CHECK-NEXT: [[CALL3:%.*]] = call dereferenceable_or_null(4) float* @scc_A(i32* noalias nofree readnone dereferenceable_or_null(4) "no-capture-maybe-returned" [[TMP2]]) #[[ATTR2]]
326 ; CHECK-NEXT: [[TMP3:%.*]] = bitcast float* [[CALL3]] to i8*
327 ; CHECK-NEXT: ret i8* [[TMP3]]
330 %bc = bitcast i16* %a to i32*
331 %call = call float* @scc_A(i32* %bc)
332 %bc2 = bitcast float* %call to i8*
333 %tobool = icmp ne i8* %bc2, null
334 br i1 %tobool, label %cond.true, label %cond.false
336 cond.true: ; preds = %entry
337 %0 = bitcast i16* %a to double*
338 %call1 = call i64* @scc_B(double* %0)
339 %1 = bitcast i64* %call1 to i8*
342 cond.false: ; preds = %entry
343 %call2 = call i8* @scc_C(i16* %a)
346 cond.end: ; preds = %cond.false, %cond.true
347 %cond = phi i8* [ %1, %cond.true ], [ %call2, %cond.false ]
348 %2 = bitcast i8* %cond to i32*
349 %call3 = call float* @scc_A(i32* %2)
350 %3 = bitcast float* %call3 to i8*
355 ; TEST call to external function, marked no-capture
357 ; void external_no_capture(int /* no-capture */ *p);
358 ; void test_external_no_capture(int *p) {
359 ; external_no_capture(p);
362 declare void @external_no_capture(i32* nocapture)
364 define void @test_external_no_capture(i32* %p) #0 {
365 ; CHECK: Function Attrs: noinline nounwind uwtable
366 ; CHECK-LABEL: define {{[^@]+}}@test_external_no_capture
367 ; CHECK-SAME: (i32* nocapture [[P:%.*]]) #[[ATTR3:[0-9]+]] {
369 ; CHECK-NEXT: call void @external_no_capture(i32* nocapture [[P]])
370 ; CHECK-NEXT: ret void
373 call void @external_no_capture(i32* %p)
377 ; TEST call to external var-args function, marked no-capture
379 ; void test_var_arg_call(char *p, int a) {
383 define void @test_var_arg_call(i8* %p, i32 %a) #0 {
384 ; CHECK: Function Attrs: noinline nounwind uwtable
385 ; CHECK-LABEL: define {{[^@]+}}@test_var_arg_call
386 ; CHECK-SAME: (i8* nocapture [[P:%.*]], i32 [[A:%.*]]) #[[ATTR3]] {
388 ; CHECK-NEXT: [[CALL:%.*]] = call i32 (i8*, ...) @printf(i8* nocapture [[P]], i32 [[A]])
389 ; CHECK-NEXT: ret void
392 %call = call i32 (i8*, ...) @printf(i8* %p, i32 %a)
396 declare i32 @printf(i8* nocapture, ...)
399 ; TEST "captured" only through return
401 ; long *not_captured_but_returned_0(long *a) {
406 ; There should *not* be a no-capture attribute on %a
407 define i64* @not_captured_but_returned_0(i64* %a) #0 {
408 ; IS__TUNIT____: Function Attrs: argmemonly nofree noinline nosync nounwind uwtable willreturn writeonly
409 ; IS__TUNIT____-LABEL: define {{[^@]+}}@not_captured_but_returned_0
410 ; IS__TUNIT____-SAME: (i64* nofree noundef nonnull returned writeonly align 8 dereferenceable(8) "no-capture-maybe-returned" [[A:%.*]]) #[[ATTR4:[0-9]+]] {
411 ; IS__TUNIT____-NEXT: entry:
412 ; IS__TUNIT____-NEXT: store i64 0, i64* [[A]], align 8
413 ; IS__TUNIT____-NEXT: ret i64* [[A]]
415 ; IS__CGSCC____: Function Attrs: argmemonly nofree noinline norecurse nosync nounwind uwtable willreturn writeonly
416 ; IS__CGSCC____-LABEL: define {{[^@]+}}@not_captured_but_returned_0
417 ; IS__CGSCC____-SAME: (i64* nofree noundef nonnull returned writeonly align 8 dereferenceable(8) "no-capture-maybe-returned" [[A:%.*]]) #[[ATTR4:[0-9]+]] {
418 ; IS__CGSCC____-NEXT: entry:
419 ; IS__CGSCC____-NEXT: store i64 0, i64* [[A]], align 8
420 ; IS__CGSCC____-NEXT: ret i64* [[A]]
423 store i64 0, i64* %a, align 8
427 ; TEST "captured" only through return
429 ; long *not_captured_but_returned_1(long *a) {
434 ; There should *not* be a no-capture attribute on %a
435 define i64* @not_captured_but_returned_1(i64* %a) #0 {
436 ; IS__TUNIT____: Function Attrs: argmemonly nofree noinline nosync nounwind uwtable willreturn writeonly
437 ; IS__TUNIT____-LABEL: define {{[^@]+}}@not_captured_but_returned_1
438 ; IS__TUNIT____-SAME: (i64* nofree nonnull writeonly align 8 dereferenceable(16) "no-capture-maybe-returned" [[A:%.*]]) #[[ATTR4]] {
439 ; IS__TUNIT____-NEXT: entry:
440 ; IS__TUNIT____-NEXT: [[ADD_PTR:%.*]] = getelementptr inbounds i64, i64* [[A]], i64 1
441 ; IS__TUNIT____-NEXT: store i64 1, i64* [[ADD_PTR]], align 8
442 ; IS__TUNIT____-NEXT: ret i64* [[ADD_PTR]]
444 ; IS__CGSCC____: Function Attrs: argmemonly nofree noinline norecurse nosync nounwind uwtable willreturn writeonly
445 ; IS__CGSCC____-LABEL: define {{[^@]+}}@not_captured_but_returned_1
446 ; IS__CGSCC____-SAME: (i64* nofree nonnull writeonly align 8 dereferenceable(16) "no-capture-maybe-returned" [[A:%.*]]) #[[ATTR4]] {
447 ; IS__CGSCC____-NEXT: entry:
448 ; IS__CGSCC____-NEXT: [[ADD_PTR:%.*]] = getelementptr inbounds i64, i64* [[A]], i64 1
449 ; IS__CGSCC____-NEXT: store i64 1, i64* [[ADD_PTR]], align 8
450 ; IS__CGSCC____-NEXT: ret i64* [[ADD_PTR]]
453 %add.ptr = getelementptr inbounds i64, i64* %a, i64 1
454 store i64 1, i64* %add.ptr, align 8
458 ; TEST calls to "captured" only through return functions
460 ; void test_not_captured_but_returned_calls(long *a) {
461 ; not_captured_but_returned_0(a);
462 ; not_captured_but_returned_1(a);
465 define void @test_not_captured_but_returned_calls(i64* %a) #0 {
466 ; IS__TUNIT____: Function Attrs: argmemonly nofree noinline nosync nounwind uwtable willreturn writeonly
467 ; IS__TUNIT____-LABEL: define {{[^@]+}}@test_not_captured_but_returned_calls
468 ; IS__TUNIT____-SAME: (i64* nocapture nofree writeonly align 8 [[A:%.*]]) #[[ATTR4]] {
469 ; IS__TUNIT____-NEXT: entry:
470 ; IS__TUNIT____-NEXT: [[CALL:%.*]] = call i64* @not_captured_but_returned_0(i64* nofree writeonly align 8 "no-capture-maybe-returned" [[A]]) #[[ATTR9:[0-9]+]]
471 ; IS__TUNIT____-NEXT: [[CALL1:%.*]] = call i64* @not_captured_but_returned_1(i64* nofree writeonly align 8 "no-capture-maybe-returned" [[A]]) #[[ATTR9]]
472 ; IS__TUNIT____-NEXT: ret void
474 ; IS__CGSCC____: Function Attrs: argmemonly nofree noinline norecurse nosync nounwind uwtable willreturn writeonly
475 ; IS__CGSCC____-LABEL: define {{[^@]+}}@test_not_captured_but_returned_calls
476 ; IS__CGSCC____-SAME: (i64* nocapture nofree noundef nonnull writeonly align 8 dereferenceable(16) [[A:%.*]]) #[[ATTR4]] {
477 ; IS__CGSCC____-NEXT: entry:
478 ; IS__CGSCC____-NEXT: [[CALL:%.*]] = call i64* @not_captured_but_returned_0(i64* nofree noundef nonnull writeonly align 8 dereferenceable(16) "no-capture-maybe-returned" [[A]]) #[[ATTR9:[0-9]+]]
479 ; IS__CGSCC____-NEXT: [[CALL1:%.*]] = call i64* @not_captured_but_returned_1(i64* nofree noundef nonnull writeonly align 8 dereferenceable(16) "no-capture-maybe-returned" [[A]]) #[[ATTR9]]
480 ; IS__CGSCC____-NEXT: ret void
483 %call = call i64* @not_captured_but_returned_0(i64* %a)
484 %call1 = call i64* @not_captured_but_returned_1(i64* %a)
488 ; TEST "captured" only through transitive return
490 ; long* negative_test_not_captured_but_returned_call_0a(long *a) {
491 ; return not_captured_but_returned_0(a);
494 ; There should *not* be a no-capture attribute on %a
495 define i64* @negative_test_not_captured_but_returned_call_0a(i64* %a) #0 {
496 ; IS__TUNIT____: Function Attrs: argmemonly nofree noinline nosync nounwind uwtable willreturn writeonly
497 ; IS__TUNIT____-LABEL: define {{[^@]+}}@negative_test_not_captured_but_returned_call_0a
498 ; IS__TUNIT____-SAME: (i64* nofree returned writeonly align 8 "no-capture-maybe-returned" [[A:%.*]]) #[[ATTR4]] {
499 ; IS__TUNIT____-NEXT: entry:
500 ; IS__TUNIT____-NEXT: [[CALL:%.*]] = call i64* @not_captured_but_returned_0(i64* nofree writeonly align 8 "no-capture-maybe-returned" [[A]]) #[[ATTR9]]
501 ; IS__TUNIT____-NEXT: ret i64* [[A]]
503 ; IS__CGSCC____: Function Attrs: argmemonly nofree noinline norecurse nosync nounwind uwtable willreturn writeonly
504 ; IS__CGSCC____-LABEL: define {{[^@]+}}@negative_test_not_captured_but_returned_call_0a
505 ; IS__CGSCC____-SAME: (i64* nofree noundef nonnull returned writeonly align 8 dereferenceable(8) "no-capture-maybe-returned" [[A:%.*]]) #[[ATTR4]] {
506 ; IS__CGSCC____-NEXT: entry:
507 ; IS__CGSCC____-NEXT: [[CALL:%.*]] = call i64* @not_captured_but_returned_0(i64* nofree noundef nonnull writeonly align 8 dereferenceable(8) "no-capture-maybe-returned" [[A]]) #[[ATTR9]]
508 ; IS__CGSCC____-NEXT: ret i64* [[A]]
511 %call = call i64* @not_captured_but_returned_0(i64* %a)
515 ; TEST captured through write
517 ; void negative_test_not_captured_but_returned_call_0b(long *a) {
518 ; *a = (long)not_captured_but_returned_0(a);
521 ; There should *not* be a no-capture attribute on %a
522 define void @negative_test_not_captured_but_returned_call_0b(i64* %a) #0 {
523 ; IS__TUNIT____: Function Attrs: argmemonly nofree noinline nosync nounwind uwtable willreturn writeonly
524 ; IS__TUNIT____-LABEL: define {{[^@]+}}@negative_test_not_captured_but_returned_call_0b
525 ; IS__TUNIT____-SAME: (i64* nofree writeonly align 8 [[A:%.*]]) #[[ATTR4]] {
526 ; IS__TUNIT____-NEXT: entry:
527 ; IS__TUNIT____-NEXT: [[CALL:%.*]] = call i64* @not_captured_but_returned_0(i64* nofree writeonly align 8 "no-capture-maybe-returned" [[A]]) #[[ATTR9]]
528 ; IS__TUNIT____-NEXT: [[TMP0:%.*]] = ptrtoint i64* [[A]] to i64
529 ; IS__TUNIT____-NEXT: store i64 [[TMP0]], i64* [[A]], align 8
530 ; IS__TUNIT____-NEXT: ret void
532 ; IS__CGSCC____: Function Attrs: argmemonly nofree noinline norecurse nosync nounwind uwtable willreturn writeonly
533 ; IS__CGSCC____-LABEL: define {{[^@]+}}@negative_test_not_captured_but_returned_call_0b
534 ; IS__CGSCC____-SAME: (i64* nofree noundef nonnull writeonly align 8 dereferenceable(8) [[A:%.*]]) #[[ATTR4]] {
535 ; IS__CGSCC____-NEXT: entry:
536 ; IS__CGSCC____-NEXT: [[CALL:%.*]] = call i64* @not_captured_but_returned_0(i64* nofree noundef nonnull writeonly align 8 dereferenceable(8) "no-capture-maybe-returned" [[A]]) #[[ATTR9]]
537 ; IS__CGSCC____-NEXT: [[TMP0:%.*]] = ptrtoint i64* [[A]] to i64
538 ; IS__CGSCC____-NEXT: store i64 [[TMP0]], i64* [[A]], align 8
539 ; IS__CGSCC____-NEXT: ret void
542 %call = call i64* @not_captured_but_returned_0(i64* %a)
543 %0 = ptrtoint i64* %call to i64
544 store i64 %0, i64* %a, align 8
548 ; TEST "captured" only through transitive return
550 ; long* negative_test_not_captured_but_returned_call_1a(long *a) {
551 ; return not_captured_but_returned_1(a);
554 ; There should *not* be a no-capture attribute on %a
555 define i64* @negative_test_not_captured_but_returned_call_1a(i64* %a) #0 {
556 ; IS__TUNIT____: Function Attrs: argmemonly nofree noinline nosync nounwind uwtable willreturn writeonly
557 ; IS__TUNIT____-LABEL: define {{[^@]+}}@negative_test_not_captured_but_returned_call_1a
558 ; IS__TUNIT____-SAME: (i64* nofree writeonly align 8 "no-capture-maybe-returned" [[A:%.*]]) #[[ATTR4]] {
559 ; IS__TUNIT____-NEXT: entry:
560 ; IS__TUNIT____-NEXT: [[CALL:%.*]] = call noundef nonnull align 8 dereferenceable(8) i64* @not_captured_but_returned_1(i64* nofree writeonly align 8 "no-capture-maybe-returned" [[A]]) #[[ATTR9]]
561 ; IS__TUNIT____-NEXT: ret i64* [[CALL]]
563 ; IS__CGSCC____: Function Attrs: argmemonly nofree noinline norecurse nosync nounwind uwtable willreturn writeonly
564 ; IS__CGSCC____-LABEL: define {{[^@]+}}@negative_test_not_captured_but_returned_call_1a
565 ; IS__CGSCC____-SAME: (i64* nofree noundef nonnull writeonly align 8 dereferenceable(16) "no-capture-maybe-returned" [[A:%.*]]) #[[ATTR4]] {
566 ; IS__CGSCC____-NEXT: entry:
567 ; IS__CGSCC____-NEXT: [[CALL:%.*]] = call noundef nonnull align 8 dereferenceable(8) i64* @not_captured_but_returned_1(i64* nofree noundef nonnull writeonly align 8 dereferenceable(16) "no-capture-maybe-returned" [[A]]) #[[ATTR9]]
568 ; IS__CGSCC____-NEXT: ret i64* [[CALL]]
571 %call = call i64* @not_captured_but_returned_1(i64* %a)
575 ; TEST captured through write
577 ; void negative_test_not_captured_but_returned_call_1b(long *a) {
578 ; *a = (long)not_captured_but_returned_1(a);
581 ; There should *not* be a no-capture attribute on %a
582 define void @negative_test_not_captured_but_returned_call_1b(i64* %a) #0 {
583 ; IS__TUNIT____: Function Attrs: nofree noinline nosync nounwind uwtable willreturn writeonly
584 ; IS__TUNIT____-LABEL: define {{[^@]+}}@negative_test_not_captured_but_returned_call_1b
585 ; IS__TUNIT____-SAME: (i64* nofree writeonly align 8 [[A:%.*]]) #[[ATTR5:[0-9]+]] {
586 ; IS__TUNIT____-NEXT: entry:
587 ; IS__TUNIT____-NEXT: [[CALL:%.*]] = call align 8 i64* @not_captured_but_returned_1(i64* nofree writeonly align 8 "no-capture-maybe-returned" [[A]]) #[[ATTR9]]
588 ; IS__TUNIT____-NEXT: [[TMP0:%.*]] = ptrtoint i64* [[CALL]] to i64
589 ; IS__TUNIT____-NEXT: store i64 [[TMP0]], i64* [[CALL]], align 8
590 ; IS__TUNIT____-NEXT: ret void
592 ; IS__CGSCC____: Function Attrs: nofree noinline norecurse nosync nounwind uwtable willreturn writeonly
593 ; IS__CGSCC____-LABEL: define {{[^@]+}}@negative_test_not_captured_but_returned_call_1b
594 ; IS__CGSCC____-SAME: (i64* nofree noundef nonnull writeonly align 8 dereferenceable(16) [[A:%.*]]) #[[ATTR5:[0-9]+]] {
595 ; IS__CGSCC____-NEXT: entry:
596 ; IS__CGSCC____-NEXT: [[CALL:%.*]] = call align 8 i64* @not_captured_but_returned_1(i64* nofree noundef nonnull writeonly align 8 dereferenceable(16) "no-capture-maybe-returned" [[A]]) #[[ATTR9]]
597 ; IS__CGSCC____-NEXT: [[TMP0:%.*]] = ptrtoint i64* [[CALL]] to i64
598 ; IS__CGSCC____-NEXT: store i64 [[TMP0]], i64* [[CALL]], align 8
599 ; IS__CGSCC____-NEXT: ret void
602 %call = call i64* @not_captured_but_returned_1(i64* %a)
603 %0 = ptrtoint i64* %call to i64
604 store i64 %0, i64* %call, align 8
608 ; TEST return argument or unknown call result
610 ; int* ret_arg_or_unknown(int* b) {
616 ; Verify we do *not* assume b is returned or not captured.
619 define i32* @ret_arg_or_unknown(i32* %b) #0 {
620 ; CHECK: Function Attrs: noinline nounwind uwtable
621 ; CHECK-LABEL: define {{[^@]+}}@ret_arg_or_unknown
622 ; CHECK-SAME: (i32* [[B:%.*]]) #[[ATTR3]] {
624 ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32* [[B]], null
625 ; CHECK-NEXT: br i1 [[CMP]], label [[RET_ARG:%.*]], label [[RET_UNKNOWN:%.*]]
627 ; CHECK-NEXT: ret i32* [[B]]
628 ; CHECK: ret_unknown:
629 ; CHECK-NEXT: [[CALL:%.*]] = call i32* @unknown()
630 ; CHECK-NEXT: ret i32* [[CALL]]
633 %cmp = icmp eq i32* %b, null
634 br i1 %cmp, label %ret_arg, label %ret_unknown
640 %call = call i32* @unknown()
644 define i32* @ret_arg_or_unknown_through_phi(i32* %b) #0 {
645 ; CHECK: Function Attrs: noinline nounwind uwtable
646 ; CHECK-LABEL: define {{[^@]+}}@ret_arg_or_unknown_through_phi
647 ; CHECK-SAME: (i32* [[B:%.*]]) #[[ATTR3]] {
649 ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32* [[B]], null
650 ; CHECK-NEXT: br i1 [[CMP]], label [[RET_ARG:%.*]], label [[RET_UNKNOWN:%.*]]
652 ; CHECK-NEXT: br label [[R:%.*]]
653 ; CHECK: ret_unknown:
654 ; CHECK-NEXT: [[CALL:%.*]] = call i32* @unknown()
655 ; CHECK-NEXT: br label [[R]]
657 ; CHECK-NEXT: [[PHI:%.*]] = phi i32* [ [[B]], [[RET_ARG]] ], [ [[CALL]], [[RET_UNKNOWN]] ]
658 ; CHECK-NEXT: ret i32* [[PHI]]
661 %cmp = icmp eq i32* %b, null
662 br i1 %cmp, label %ret_arg, label %ret_unknown
668 %call = call i32* @unknown()
672 %phi = phi i32* [ %b, %ret_arg ], [ %call, %ret_unknown ]
677 ; TEST not captured by readonly external function
679 declare i32* @readonly_unknown(i32*, i32*) readonly
681 define void @not_captured_by_readonly_call(i32* %b) #0 {
682 ; CHECK: Function Attrs: noinline nounwind readonly uwtable
683 ; CHECK-LABEL: define {{[^@]+}}@not_captured_by_readonly_call
684 ; CHECK-SAME: (i32* nocapture readonly [[B:%.*]]) #[[ATTR7:[0-9]+]] {
686 ; CHECK-NEXT: [[CALL:%.*]] = call i32* @readonly_unknown(i32* readonly [[B]], i32* readonly [[B]]) #[[ATTR6:[0-9]+]]
687 ; CHECK-NEXT: ret void
690 %call = call i32* @readonly_unknown(i32* %b, i32* %b)
695 ; TEST not captured by readonly external function if return chain is known
697 ; Make sure the returned flag on %r is strong enough to justify nocapture on %b but **not** on %r.
699 define i32* @not_captured_by_readonly_call_not_returned_either1(i32* %b, i32* returned %r) {
700 ; CHECK: Function Attrs: nounwind readonly
701 ; CHECK-LABEL: define {{[^@]+}}@not_captured_by_readonly_call_not_returned_either1
702 ; CHECK-SAME: (i32* nocapture readonly [[B:%.*]], i32* readonly returned [[R:%.*]]) #[[ATTR8:[0-9]+]] {
704 ; CHECK-NEXT: [[CALL:%.*]] = call i32* @readonly_unknown(i32* readonly [[B]], i32* readonly [[R]]) #[[ATTR8]]
705 ; CHECK-NEXT: ret i32* [[R]]
708 %call = call i32* @readonly_unknown(i32* %b, i32* %r) nounwind
712 declare i32* @readonly_unknown_r1a(i32*, i32* returned) readonly
713 define i32* @not_captured_by_readonly_call_not_returned_either2(i32* %b, i32* %r) {
714 ; CHECK: Function Attrs: nounwind readonly
715 ; CHECK-LABEL: define {{[^@]+}}@not_captured_by_readonly_call_not_returned_either2
716 ; CHECK-SAME: (i32* nocapture readonly [[B:%.*]], i32* readonly returned [[R:%.*]]) #[[ATTR8]] {
718 ; CHECK-NEXT: [[CALL:%.*]] = call i32* @readonly_unknown_r1a(i32* readonly [[B]], i32* readonly [[R]]) #[[ATTR8]]
719 ; CHECK-NEXT: ret i32* [[R]]
722 %call = call i32* @readonly_unknown_r1a(i32* %b, i32* %r) nounwind
726 declare i32* @readonly_unknown_r1b(i32*, i32* returned) readonly nounwind
727 define i32* @not_captured_by_readonly_call_not_returned_either3(i32* %b, i32* %r) {
728 ; CHECK: Function Attrs: nounwind readonly
729 ; CHECK-LABEL: define {{[^@]+}}@not_captured_by_readonly_call_not_returned_either3
730 ; CHECK-SAME: (i32* nocapture readonly [[B:%.*]], i32* readonly returned [[R:%.*]]) #[[ATTR8]] {
732 ; CHECK-NEXT: [[CALL:%.*]] = call i32* @readonly_unknown_r1b(i32* nocapture readonly [[B]], i32* readonly [[R]]) #[[ATTR8]]
733 ; CHECK-NEXT: ret i32* [[R]]
736 %call = call i32* @readonly_unknown_r1b(i32* %b, i32* %r)
740 define i32* @not_captured_by_readonly_call_not_returned_either4(i32* %b, i32* %r) nounwind {
741 ; CHECK: Function Attrs: nounwind readonly
742 ; CHECK-LABEL: define {{[^@]+}}@not_captured_by_readonly_call_not_returned_either4
743 ; CHECK-SAME: (i32* nocapture readonly [[B:%.*]], i32* readonly returned [[R:%.*]]) #[[ATTR8]] {
745 ; CHECK-NEXT: [[CALL:%.*]] = call i32* @readonly_unknown_r1a(i32* readonly [[B]], i32* readonly [[R]]) #[[ATTR6]]
746 ; CHECK-NEXT: ret i32* [[R]]
749 %call = call i32* @readonly_unknown_r1a(i32* %b, i32* %r)
754 declare i32* @unknown_i32p(i32*)
755 define void @nocapture_is_not_subsumed_1(i32* nocapture %b) {
756 ; CHECK-LABEL: define {{[^@]+}}@nocapture_is_not_subsumed_1
757 ; CHECK-SAME: (i32* nocapture [[B:%.*]]) {
759 ; CHECK-NEXT: [[CALL:%.*]] = call i32* @unknown_i32p(i32* [[B]])
760 ; CHECK-NEXT: store i32 0, i32* [[CALL]], align 4
761 ; CHECK-NEXT: ret void
764 %call = call i32* @unknown_i32p(i32* %b)
765 store i32 0, i32* %call
769 declare i32* @readonly_i32p(i32*) readonly
770 define void @nocapture_is_not_subsumed_2(i32* nocapture %b) {
771 ; CHECK-LABEL: define {{[^@]+}}@nocapture_is_not_subsumed_2
772 ; CHECK-SAME: (i32* nocapture [[B:%.*]]) {
774 ; CHECK-NEXT: [[CALL:%.*]] = call i32* @readonly_i32p(i32* readonly [[B]]) #[[ATTR6]]
775 ; CHECK-NEXT: store i32 0, i32* [[CALL]], align 4
776 ; CHECK-NEXT: ret void
779 %call = call i32* @readonly_i32p(i32* %b)
780 store i32 0, i32* %call
784 attributes #0 = { noinline nounwind uwtable }
786 ; IS__TUNIT____: attributes #[[ATTR0]] = { nofree noinline nosync nounwind readnone uwtable willreturn }
787 ; IS__TUNIT____: attributes #[[ATTR1]] = { nofree noinline noreturn nosync nounwind readnone uwtable willreturn }
788 ; IS__TUNIT____: attributes #[[ATTR2]] = { nofree nosync nounwind readnone }
789 ; IS__TUNIT____: attributes #[[ATTR3]] = { noinline nounwind uwtable }
790 ; IS__TUNIT____: attributes #[[ATTR4]] = { argmemonly nofree noinline nosync nounwind uwtable willreturn writeonly }
791 ; IS__TUNIT____: attributes #[[ATTR5]] = { nofree noinline nosync nounwind uwtable willreturn writeonly }
792 ; IS__TUNIT____: attributes #[[ATTR6]] = { readonly }
793 ; IS__TUNIT____: attributes #[[ATTR7]] = { noinline nounwind readonly uwtable }
794 ; IS__TUNIT____: attributes #[[ATTR8]] = { nounwind readonly }
795 ; IS__TUNIT____: attributes #[[ATTR9]] = { nofree nosync nounwind willreturn writeonly }
797 ; IS__CGSCC____: attributes #[[ATTR0]] = { nofree noinline norecurse nosync nounwind readnone uwtable willreturn }
798 ; IS__CGSCC____: attributes #[[ATTR1]] = { nofree noinline norecurse noreturn nosync nounwind readnone uwtable willreturn }
799 ; IS__CGSCC____: attributes #[[ATTR2]] = { nofree nosync nounwind readnone }
800 ; IS__CGSCC____: attributes #[[ATTR3]] = { noinline nounwind uwtable }
801 ; IS__CGSCC____: attributes #[[ATTR4]] = { argmemonly nofree noinline norecurse nosync nounwind uwtable willreturn writeonly }
802 ; IS__CGSCC____: attributes #[[ATTR5]] = { nofree noinline norecurse nosync nounwind uwtable willreturn writeonly }
803 ; IS__CGSCC____: attributes #[[ATTR6]] = { readonly }
804 ; IS__CGSCC____: attributes #[[ATTR7]] = { noinline nounwind readonly uwtable }
805 ; IS__CGSCC____: attributes #[[ATTR8]] = { nounwind readonly }
806 ; IS__CGSCC____: attributes #[[ATTR9]] = { nounwind willreturn writeonly }