• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes
2; RUN: opt -attributor -enable-new-pm=0 -attributor-manifest-internal  -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=3 -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=3 -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
6
7target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
8
9; Test cases specifically designed for the "nofree" function attribute.
10; We use FIXME's to indicate problems and missing attributes.
11
12; Free functions
13declare void @free(i8* nocapture) local_unnamed_addr #1
14declare noalias i8* @realloc(i8* nocapture, i64) local_unnamed_addr #0
15declare void @_ZdaPv(i8*) local_unnamed_addr #2
16
17
18; TEST 1 (positive case)
19define void @only_return() #0 {
20; IS__TUNIT____: Function Attrs: nofree noinline nosync nounwind readnone uwtable willreturn
21; IS__TUNIT____-LABEL: define {{[^@]+}}@only_return
22; IS__TUNIT____-SAME: () [[ATTR3:#.*]] {
23; IS__TUNIT____-NEXT:    ret void
24;
25; IS__CGSCC____: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable willreturn
26; IS__CGSCC____-LABEL: define {{[^@]+}}@only_return
27; IS__CGSCC____-SAME: () [[ATTR3:#.*]] {
28; IS__CGSCC____-NEXT:    ret void
29;
30  ret void
31}
32
33
34; TEST 2 (negative case)
35; Only free
36; void only_free(char* p) {
37;    free(p);
38; }
39
40define void @only_free(i8* nocapture %0) local_unnamed_addr #0 {
41; CHECK: Function Attrs: noinline nounwind uwtable
42; CHECK-LABEL: define {{[^@]+}}@only_free
43; CHECK-SAME: (i8* nocapture [[TMP0:%.*]]) local_unnamed_addr [[ATTR1:#.*]] {
44; CHECK-NEXT:    tail call void @free(i8* nocapture [[TMP0]]) [[ATTR0:#.*]]
45; CHECK-NEXT:    ret void
46;
47  tail call void @free(i8* %0) #1
48  ret void
49}
50
51
52; TEST 3 (negative case)
53; Free occurs in same scc.
54; void free_in_scc1(char*p){
55;    free_in_scc2(p);
56; }
57; void free_in_scc2(char*p){
58;    free_in_scc1(p);
59;    free(p);
60; }
61
62
63define void @free_in_scc1(i8* nocapture %0) local_unnamed_addr #0 {
64; CHECK: Function Attrs: noinline nounwind uwtable
65; CHECK-LABEL: define {{[^@]+}}@free_in_scc1
66; CHECK-SAME: (i8* nocapture [[TMP0:%.*]]) local_unnamed_addr [[ATTR1]] {
67; CHECK-NEXT:    tail call void @free_in_scc2(i8* nocapture [[TMP0]]) [[ATTR0]]
68; CHECK-NEXT:    ret void
69;
70  tail call void @free_in_scc2(i8* %0) #1
71  ret void
72}
73
74
75define void @free_in_scc2(i8* nocapture %0) local_unnamed_addr #0 {
76; CHECK: Function Attrs: noinline nounwind uwtable
77; CHECK-LABEL: define {{[^@]+}}@free_in_scc2
78; CHECK-SAME: (i8* nocapture [[TMP0:%.*]]) local_unnamed_addr [[ATTR1]] {
79; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8* [[TMP0]], null
80; CHECK-NEXT:    br i1 [[CMP]], label [[REC:%.*]], label [[CALL:%.*]]
81; CHECK:       call:
82; CHECK-NEXT:    tail call void @free(i8* nocapture [[TMP0]]) [[ATTR0]]
83; CHECK-NEXT:    br label [[END:%.*]]
84; CHECK:       rec:
85; CHECK-NEXT:    tail call void @free_in_scc1(i8* nocapture [[TMP0]]) [[ATTR0]]
86; CHECK-NEXT:    br label [[END]]
87; CHECK:       end:
88; CHECK-NEXT:    ret void
89;
90  %cmp = icmp eq i8* %0, null
91  br i1 %cmp, label %rec, label %call
92call:
93  tail call void @free(i8* %0) #1
94  br label %end
95rec:
96  tail call void @free_in_scc1(i8* %0)
97  br label %end
98end:
99  ret void
100}
101
102
103; TEST 4 (positive case)
104; Free doesn't occur.
105; void mutual_recursion1(){
106;    mutual_recursion2();
107; }
108; void mutual_recursion2(){
109;     mutual_recursion1();
110; }
111
112
113define void @mutual_recursion1() #0 {
114; NOT_CGSCC_NPM: Function Attrs: nofree noinline noreturn nosync nounwind readnone uwtable willreturn
115; NOT_CGSCC_NPM-LABEL: define {{[^@]+}}@mutual_recursion1
116; NOT_CGSCC_NPM-SAME: () [[ATTR4:#.*]] {
117; NOT_CGSCC_NPM-NEXT:    unreachable
118;
119; IS__CGSCC_NPM: Function Attrs: nofree noinline norecurse noreturn nosync nounwind readnone uwtable willreturn
120; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@mutual_recursion1
121; IS__CGSCC_NPM-SAME: () [[ATTR4:#.*]] {
122; IS__CGSCC_NPM-NEXT:    unreachable
123;
124  call void @mutual_recursion2()
125  ret void
126}
127
128define void @mutual_recursion2() #0 {
129; NOT_CGSCC_NPM: Function Attrs: nofree noinline noreturn nosync nounwind readnone uwtable willreturn
130; NOT_CGSCC_NPM-LABEL: define {{[^@]+}}@mutual_recursion2
131; NOT_CGSCC_NPM-SAME: () [[ATTR4]] {
132; NOT_CGSCC_NPM-NEXT:    unreachable
133;
134; IS__CGSCC_NPM: Function Attrs: nofree noinline norecurse noreturn nosync nounwind readnone uwtable willreturn
135; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@mutual_recursion2
136; IS__CGSCC_NPM-SAME: () [[ATTR4]] {
137; IS__CGSCC_NPM-NEXT:    unreachable
138;
139  call void @mutual_recursion1()
140  ret void
141}
142
143
144; TEST 5
145; C++ delete operation (negative case)
146; void delete_op (char p[]){
147;     delete [] p;
148; }
149
150define void @_Z9delete_opPc(i8* %0) local_unnamed_addr #0 {
151; CHECK: Function Attrs: noinline nounwind uwtable
152; CHECK-LABEL: define {{[^@]+}}@_Z9delete_opPc
153; CHECK-SAME: (i8* [[TMP0:%.*]]) local_unnamed_addr [[ATTR1]] {
154; CHECK-NEXT:    [[TMP2:%.*]] = icmp eq i8* [[TMP0]], null
155; CHECK-NEXT:    br i1 [[TMP2]], label [[TMP4:%.*]], label [[TMP3:%.*]]
156; CHECK:       3:
157; CHECK-NEXT:    tail call void @_ZdaPv(i8* nonnull [[TMP0]]) [[ATTR2:#.*]]
158; CHECK-NEXT:    br label [[TMP4]]
159; CHECK:       4:
160; CHECK-NEXT:    ret void
161;
162  %2 = icmp eq i8* %0, null
163  br i1 %2, label %4, label %3
164
165; <label>:3:                                      ; preds = %1
166  tail call void @_ZdaPv(i8* nonnull %0) #2
167  br label %4
168
169; <label>:4:                                      ; preds = %3, %1
170  ret void
171}
172
173
174; TEST 6 (negative case)
175; Call realloc
176define noalias i8* @call_realloc(i8* nocapture %0, i64 %1) local_unnamed_addr #0 {
177; CHECK: Function Attrs: noinline nounwind uwtable
178; CHECK-LABEL: define {{[^@]+}}@call_realloc
179; CHECK-SAME: (i8* nocapture [[TMP0:%.*]], i64 [[TMP1:%.*]]) local_unnamed_addr [[ATTR1]] {
180; CHECK-NEXT:    [[RET:%.*]] = tail call i8* @realloc(i8* nocapture [[TMP0]], i64 [[TMP1]]) [[ATTR2]]
181; CHECK-NEXT:    ret i8* [[RET]]
182;
183  %ret = tail call i8* @realloc(i8* %0, i64 %1) #2
184  ret i8* %ret
185}
186
187
188; TEST 7 (positive case)
189; Call function declaration with "nofree"
190
191
192; CHECK: Function Attrs:  nofree noinline nounwind readnone uwtable
193; CHECK-NEXT: declare void @nofree_function()
194declare void @nofree_function() nofree readnone #0
195
196define void @call_nofree_function() #0 {
197; IS__TUNIT____: Function Attrs: nofree noinline nosync nounwind readnone uwtable willreturn
198; IS__TUNIT____-LABEL: define {{[^@]+}}@call_nofree_function
199; IS__TUNIT____-SAME: () [[ATTR3]] {
200; IS__TUNIT____-NEXT:    ret void
201;
202; IS__CGSCC____: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable willreturn
203; IS__CGSCC____-LABEL: define {{[^@]+}}@call_nofree_function
204; IS__CGSCC____-SAME: () [[ATTR3]] {
205; IS__CGSCC____-NEXT:    ret void
206;
207  tail call void @nofree_function()
208  ret void
209}
210
211; TEST 8 (negative case)
212; Call function declaration without "nofree"
213
214
215; CHECK: Function Attrs: noinline nounwind uwtable
216; CHECK-NEXT: declare void @maybe_free()
217declare void @maybe_free() #0
218
219
220define void @call_maybe_free() #0 {
221; CHECK: Function Attrs: noinline nounwind uwtable
222; CHECK-LABEL: define {{[^@]+}}@call_maybe_free
223; CHECK-SAME: () [[ATTR1]] {
224; CHECK-NEXT:    tail call void @maybe_free() [[ATTR0]]
225; CHECK-NEXT:    ret void
226;
227  tail call void @maybe_free()
228  ret void
229}
230
231
232; TEST 9 (negative case)
233; Call both of above functions
234
235define void @call_both() #0 {
236; CHECK: Function Attrs: noinline nounwind uwtable
237; CHECK-LABEL: define {{[^@]+}}@call_both
238; CHECK-SAME: () [[ATTR1]] {
239; CHECK-NEXT:    tail call void @maybe_free() [[ATTR0]]
240; CHECK-NEXT:    ret void
241;
242  tail call void @maybe_free()
243  tail call void @nofree_function()
244  ret void
245}
246
247
248; TEST 10 (positive case)
249; Call intrinsic function
250; CHECK: Function Attrs: nofree nosync nounwind readnone speculatable willreturn
251; CHECK-NEXT: declare float @llvm.floor.f32(float)
252declare float @llvm.floor.f32(float)
253
254define void @call_floor(float %a) #0 {
255; IS__TUNIT____: Function Attrs: nofree noinline nosync nounwind readnone uwtable willreturn
256; IS__TUNIT____-LABEL: define {{[^@]+}}@call_floor
257; IS__TUNIT____-SAME: (float [[A:%.*]]) [[ATTR3]] {
258; IS__TUNIT____-NEXT:    ret void
259;
260; IS__CGSCC____: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable willreturn
261; IS__CGSCC____-LABEL: define {{[^@]+}}@call_floor
262; IS__CGSCC____-SAME: (float [[A:%.*]]) [[ATTR3]] {
263; IS__CGSCC____-NEXT:    ret void
264;
265  tail call float @llvm.floor.f32(float %a)
266  ret void
267}
268
269define float @call_floor2(float %a) #0 {
270; IS__TUNIT____: Function Attrs: nofree noinline nosync nounwind readnone uwtable willreturn
271; IS__TUNIT____-LABEL: define {{[^@]+}}@call_floor2
272; IS__TUNIT____-SAME: (float [[A:%.*]]) [[ATTR3]] {
273; IS__TUNIT____-NEXT:    [[C:%.*]] = tail call float @llvm.floor.f32(float [[A]]) [[ATTR11:#.*]]
274; IS__TUNIT____-NEXT:    ret float [[C]]
275;
276; IS__CGSCC____: Function Attrs: nofree noinline nosync nounwind readnone uwtable willreturn
277; IS__CGSCC____-LABEL: define {{[^@]+}}@call_floor2
278; IS__CGSCC____-SAME: (float [[A:%.*]]) [[ATTR7:#.*]] {
279; IS__CGSCC____-NEXT:    [[C:%.*]] = tail call float @llvm.floor.f32(float [[A]]) [[ATTR12:#.*]]
280; IS__CGSCC____-NEXT:    ret float [[C]]
281;
282  %c = tail call float @llvm.floor.f32(float %a)
283  ret float %c
284}
285
286; TEST 11 (positive case)
287; Check propagation.
288
289define void @f1() #0 {
290; IS__TUNIT____: Function Attrs: nofree noinline nosync nounwind readnone uwtable willreturn
291; IS__TUNIT____-LABEL: define {{[^@]+}}@f1
292; IS__TUNIT____-SAME: () [[ATTR3]] {
293; IS__TUNIT____-NEXT:    ret void
294;
295; IS__CGSCC____: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable willreturn
296; IS__CGSCC____-LABEL: define {{[^@]+}}@f1
297; IS__CGSCC____-SAME: () [[ATTR3]] {
298; IS__CGSCC____-NEXT:    ret void
299;
300  tail call void @nofree_function()
301  ret void
302}
303
304define void @f2() #0 {
305; IS__TUNIT____: Function Attrs: nofree noinline nosync nounwind readnone uwtable willreturn
306; IS__TUNIT____-LABEL: define {{[^@]+}}@f2
307; IS__TUNIT____-SAME: () [[ATTR3]] {
308; IS__TUNIT____-NEXT:    ret void
309;
310; IS__CGSCC____: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable willreturn
311; IS__CGSCC____-LABEL: define {{[^@]+}}@f2
312; IS__CGSCC____-SAME: () [[ATTR3]] {
313; IS__CGSCC____-NEXT:    ret void
314;
315  tail call void @f1()
316  ret void
317}
318
319; TEST 12 NoFree argument - positive.
320define double @test12(double* nocapture readonly %a) {
321; CHECK: Function Attrs: nofree nounwind
322; CHECK-LABEL: define {{[^@]+}}@test12
323; CHECK-SAME: (double* nocapture nofree nonnull readonly align 8 dereferenceable(8) [[A:%.*]]) [[ATTR8:#.*]] {
324; CHECK-NEXT:  entry:
325; CHECK-NEXT:    [[TMP0:%.*]] = load double, double* [[A]], align 8
326; CHECK-NEXT:    [[CALL:%.*]] = tail call double @cos(double [[TMP0]]) [[ATTR2]]
327; CHECK-NEXT:    ret double [[CALL]]
328;
329entry:
330  %0 = load double, double* %a, align 8
331  %call = tail call double @cos(double %0) #2
332  ret double %call
333}
334
335declare double @cos(double) nobuiltin nounwind nofree
336
337; FIXME: %a should be nofree.
338; TEST 13 NoFree argument - positive.
339define noalias i32* @test13(i64* nocapture readonly %a) {
340; CHECK: Function Attrs: nounwind
341; CHECK-LABEL: define {{[^@]+}}@test13
342; CHECK-SAME: (i64* nocapture nonnull readonly align 8 dereferenceable(8) [[A:%.*]]) [[ATTR0]] {
343; CHECK-NEXT:  entry:
344; CHECK-NEXT:    [[TMP0:%.*]] = load i64, i64* [[A]], align 8
345; CHECK-NEXT:    [[CALL:%.*]] = tail call noalias i8* @malloc(i64 [[TMP0]]) [[ATTR2]]
346; CHECK-NEXT:    [[TMP1:%.*]] = bitcast i8* [[CALL]] to i32*
347; CHECK-NEXT:    ret i32* [[TMP1]]
348;
349entry:
350  %0 = load i64, i64* %a, align 8
351  %call = tail call noalias i8* @malloc(i64 %0) #2
352  %1 = bitcast i8* %call to i32*
353  ret i32* %1
354}
355
356define void @test14(i8* nocapture %0, i8* nocapture %1) {
357; CHECK: Function Attrs: nounwind
358; CHECK-LABEL: define {{[^@]+}}@test14
359; CHECK-SAME: (i8* nocapture [[TMP0:%.*]], i8* nocapture nofree readnone [[TMP1:%.*]]) [[ATTR0]] {
360; CHECK-NEXT:    tail call void @free(i8* nocapture [[TMP0]]) [[ATTR0]]
361; CHECK-NEXT:    ret void
362;
363  tail call void @free(i8* %0) #1
364  ret void
365}
366
367; UTC_ARGS: --enable
368
369define void @nonnull_assume_pos(i8* %arg1, i8* %arg2, i8* %arg3, i8* %arg4) {
370; ATTRIBUTOR-LABEL: define {{[^@]+}}@nonnull_assume_pos
371; ATTRIBUTOR-SAME: (i8* nofree [[ARG1:%.*]], i8* [[ARG2:%.*]], i8* nofree [[ARG3:%.*]], i8* [[ARG4:%.*]])
372; ATTRIBUTOR-NEXT:    call void @llvm.assume(i1 true) #11 [ "nofree"(i8* [[ARG1]]), "nofree"(i8* [[ARG3]]) ]
373; ATTRIBUTOR-NEXT:    call void @unknown(i8* nofree [[ARG1]], i8* [[ARG2]], i8* nofree [[ARG3]], i8* [[ARG4]])
374; ATTRIBUTOR-NEXT:    ret void
375;
376; IS__TUNIT____-LABEL: define {{[^@]+}}@nonnull_assume_pos
377; IS__TUNIT____-SAME: (i8* nofree [[ARG1:%.*]], i8* [[ARG2:%.*]], i8* nofree [[ARG3:%.*]], i8* [[ARG4:%.*]]) {
378; IS__TUNIT____-NEXT:    call void @llvm.assume(i1 noundef true) [[ATTR11]] [ "nofree"(i8* [[ARG1]]), "nofree"(i8* [[ARG3]]) ]
379; IS__TUNIT____-NEXT:    call void @unknown(i8* nofree [[ARG1]], i8* [[ARG2]], i8* nofree [[ARG3]], i8* [[ARG4]])
380; IS__TUNIT____-NEXT:    ret void
381;
382; IS__CGSCC____-LABEL: define {{[^@]+}}@nonnull_assume_pos
383; IS__CGSCC____-SAME: (i8* nofree [[ARG1:%.*]], i8* [[ARG2:%.*]], i8* nofree [[ARG3:%.*]], i8* [[ARG4:%.*]]) {
384; IS__CGSCC____-NEXT:    call void @llvm.assume(i1 noundef true) [[ATTR12]] [ "nofree"(i8* [[ARG1]]), "nofree"(i8* [[ARG3]]) ]
385; IS__CGSCC____-NEXT:    call void @unknown(i8* nofree [[ARG1]], i8* [[ARG2]], i8* nofree [[ARG3]], i8* [[ARG4]])
386; IS__CGSCC____-NEXT:    ret void
387;
388  call void @llvm.assume(i1 true) ["nofree"(i8* %arg1), "nofree"(i8* %arg3)]
389  call void @unknown(i8* %arg1, i8* %arg2, i8* %arg3, i8* %arg4)
390  ret void
391}
392define void @nonnull_assume_neg(i8* %arg1, i8* %arg2, i8* %arg3, i8* %arg4) {
393; ATTRIBUTOR-LABEL: define {{[^@]+}}@nonnull_assume_neg
394; ATTRIBUTOR-SAME: (i8* [[ARG1:%.*]], i8* [[ARG2:%.*]], i8* [[ARG3:%.*]], i8* [[ARG4:%.*]])
395; ATTRIBUTOR-NEXT:    call void @unknown(i8* [[ARG1]], i8* [[ARG2]], i8* [[ARG3]], i8* [[ARG4]])
396; ATTRIBUTOR-NEXT:    call void @llvm.assume(i1 true) [ "nofree"(i8* [[ARG1]]), "nofree"(i8* [[ARG3]]) ]
397; ATTRIBUTOR-NEXT:    ret void
398;
399; CHECK-LABEL: define {{[^@]+}}@nonnull_assume_neg
400; CHECK-SAME: (i8* [[ARG1:%.*]], i8* [[ARG2:%.*]], i8* [[ARG3:%.*]], i8* [[ARG4:%.*]]) {
401; CHECK-NEXT:    call void @unknown(i8* [[ARG1]], i8* [[ARG2]], i8* [[ARG3]], i8* [[ARG4]])
402; CHECK-NEXT:    call void @llvm.assume(i1 noundef true) [ "nofree"(i8* [[ARG1]]), "nofree"(i8* [[ARG3]]) ]
403; CHECK-NEXT:    ret void
404;
405  call void @unknown(i8* %arg1, i8* %arg2, i8* %arg3, i8* %arg4)
406  call void @llvm.assume(i1 true) ["nofree"(i8* %arg1), "nofree"(i8* %arg3)]
407  ret void
408}
409define void @nonnull_assume_call(i8* %arg1, i8* %arg2, i8* %arg3, i8* %arg4) {
410; ATTRIBUTOR-LABEL: define {{[^@]+}}@nonnull_assume_call
411; ATTRIBUTOR-SAME: (i8* [[ARG1:%.*]], i8* [[ARG2:%.*]], i8* [[ARG3:%.*]], i8* [[ARG4:%.*]])
412; ATTRIBUTOR-NEXT:    call void @unknown(i8* [[ARG1]], i8* [[ARG2]], i8* [[ARG3]], i8* [[ARG4]])
413; ATTRIBUTOR-NEXT:    call void @use_i8_ptr(i8* noalias readnone [[ARG1]])
414; ATTRIBUTOR-NEXT:    call void @use_i8_ptr(i8* noalias readnone [[ARG2]])
415; ATTRIBUTOR-NEXT:    call void @llvm.assume(i1 true) [ "nofree"(i8* [[ARG1]]), "nofree"(i8* [[ARG3]]) ]
416; ATTRIBUTOR-NEXT:    call void @use_i8_ptr(i8* noalias nofree readnone [[ARG3]])
417; ATTRIBUTOR-NEXT:    call void @use_i8_ptr(i8* noalias readnone [[ARG4]])
418; ATTRIBUTOR-NEXT:    call void @use_i8_ptr_ret(i8* noalias nofree readnone [[ARG1]])
419; ATTRIBUTOR-NEXT:    call void @use_i8_ptr_ret(i8* noalias readnone [[ARG2]])
420; ATTRIBUTOR-NEXT:    call void @llvm.assume(i1 true) [ "nofree"(i8* [[ARG1]]), "nofree"(i8* [[ARG4]]) ]
421; ATTRIBUTOR-NEXT:    call void @use_i8_ptr_ret(i8* noalias nofree readnone [[ARG3]])
422; ATTRIBUTOR-NEXT:    call void @use_i8_ptr_ret(i8* noalias nofree readnone [[ARG4]])
423; ATTRIBUTOR-NEXT:    ret void
424;
425; CHECK-LABEL: define {{[^@]+}}@nonnull_assume_call
426; CHECK-SAME: (i8* [[ARG1:%.*]], i8* [[ARG2:%.*]], i8* [[ARG3:%.*]], i8* [[ARG4:%.*]]) {
427; CHECK-NEXT:    call void @unknown(i8* [[ARG1]], i8* [[ARG2]], i8* [[ARG3]], i8* [[ARG4]])
428; CHECK-NEXT:    call void @use_i8_ptr(i8* noalias nocapture readnone [[ARG1]]) [[ATTR0]]
429; CHECK-NEXT:    call void @use_i8_ptr(i8* noalias nocapture readnone [[ARG2]]) [[ATTR0]]
430; CHECK-NEXT:    call void @llvm.assume(i1 noundef true) [ "nofree"(i8* [[ARG1]]), "nofree"(i8* [[ARG3]]) ]
431; CHECK-NEXT:    call void @use_i8_ptr(i8* noalias nocapture nofree readnone [[ARG3]]) [[ATTR0]]
432; CHECK-NEXT:    call void @use_i8_ptr(i8* noalias nocapture readnone [[ARG4]]) [[ATTR0]]
433; CHECK-NEXT:    call void @use_i8_ptr_ret(i8* noalias nocapture nofree readnone [[ARG1]]) [[ATTR0]]
434; CHECK-NEXT:    call void @use_i8_ptr_ret(i8* noalias nocapture readnone [[ARG2]]) [[ATTR0]]
435; CHECK-NEXT:    call void @llvm.assume(i1 noundef true) [ "nofree"(i8* [[ARG1]]), "nofree"(i8* [[ARG4]]) ]
436; CHECK-NEXT:    call void @use_i8_ptr_ret(i8* noalias nocapture nofree readnone [[ARG3]]) [[ATTR0]]
437; CHECK-NEXT:    call void @use_i8_ptr_ret(i8* noalias nocapture nofree readnone [[ARG4]]) [[ATTR0]]
438; CHECK-NEXT:    ret void
439;
440  call void @unknown(i8* %arg1, i8* %arg2, i8* %arg3, i8* %arg4)
441  call void @use_i8_ptr(i8* %arg1)
442  call void @use_i8_ptr(i8* %arg2)
443  call void @llvm.assume(i1 true) ["nofree"(i8* %arg1), "nofree"(i8* %arg3)]
444  call void @use_i8_ptr(i8* %arg3)
445  call void @use_i8_ptr(i8* %arg4)
446  call void @use_i8_ptr_ret(i8* %arg1)
447  call void @use_i8_ptr_ret(i8* %arg2)
448  call void @llvm.assume(i1 true) ["nofree"(i8* %arg1), "nofree"(i8* %arg4)]
449  call void @use_i8_ptr_ret(i8* %arg3)
450  call void @use_i8_ptr_ret(i8* %arg4)
451  ret void
452}
453declare void @llvm.assume(i1)
454declare void @unknown(i8*, i8*, i8*, i8*)
455declare void @use_i8_ptr(i8* nocapture readnone) nounwind
456declare void @use_i8_ptr_ret(i8* nocapture readnone) nounwind willreturn
457
458declare noalias i8* @malloc(i64)
459
460attributes #0 = { nounwind uwtable noinline }
461attributes #1 = { nounwind }
462attributes #2 = { nobuiltin nounwind }
463