1; RUN: opt -functionattrs --disable-nofree-inference=false -S < %s | FileCheck %s --check-prefix=FNATTR
2
3target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
4
5; Test cases specifically designed for the "nofree" function attribute.
6; We use FIXME's to indicate problems and missing attributes.
7
8; Free functions
9declare void @free(i8* nocapture) local_unnamed_addr #1
10declare noalias i8* @realloc(i8* nocapture, i64) local_unnamed_addr #0
11declare void @_ZdaPv(i8*) local_unnamed_addr #2
12
13
14; TEST 1 (positive case)
15; FNATTR: Function Attrs: noinline norecurse nounwind readnone uwtable
16; FNATTR-NEXT: define void @only_return()
17define void @only_return() #0 {
18    ret void
19}
20
21
22; TEST 2 (negative case)
23; Only free
24; void only_free(char* p) {
25;    free(p);
26; }
27
28; FNATTR: Function Attrs: noinline nounwind uwtable
29; FNATTR-NEXT: define void @only_free(i8* nocapture %0) local_unnamed_addr
30define void @only_free(i8* nocapture %0) local_unnamed_addr #0 {
31    tail call void @free(i8* %0) #1
32    ret void
33}
34
35
36; TEST 3 (negative case)
37; Free occurs in same scc.
38; void free_in_scc1(char*p){
39;    free_in_scc2(p);
40; }
41; void free_in_scc2(char*p){
42;    free_in_scc1(p);
43;    free(p);
44; }
45
46
47; FNATTR: Function Attrs: noinline nounwind uwtable
48; FNATTR-NEXT: define void @free_in_scc1(i8* nocapture %0) local_unnamed_addr
49define void @free_in_scc1(i8* nocapture %0) local_unnamed_addr #0 {
50  tail call void @free_in_scc2(i8* %0) #1
51  ret void
52}
53
54
55; FNATTR: Function Attrs: noinline nounwind uwtable
56; FNATTR-NEXT: define void @free_in_scc2(i8* nocapture %0) local_unnamed_addr
57define void @free_in_scc2(i8* nocapture %0) local_unnamed_addr #0 {
58  %cmp = icmp eq i8* %0, null
59  br i1 %cmp, label %rec, label %call
60call:
61  tail call void @free(i8* %0) #1
62  br label %end
63rec:
64  tail call void @free_in_scc1(i8* %0)
65  br label %end
66end:
67  ret void
68}
69
70
71; TEST 4 (positive case)
72; Free doesn't occur.
73; void mutual_recursion1(){
74;    mutual_recursion2();
75; }
76; void mutual_recursion2(){
77;     mutual_recursion1();
78; }
79
80
81; FNATTR: Function Attrs: noinline nounwind readnone uwtable
82; FNATTR-NEXT: define void @mutual_recursion1()
83define void @mutual_recursion1() #0 {
84  call void @mutual_recursion2()
85  ret void
86}
87
88; FNATTR: Function Attrs: noinline nounwind readnone uwtable
89; FNATTR-NEXT: define void @mutual_recursion2()
90define void @mutual_recursion2() #0 {
91  call void @mutual_recursion1()
92  ret void
93}
94
95
96; TEST 5
97; C++ delete operation (negative case)
98; void delete_op (char p[]){
99;     delete [] p;
100; }
101
102; FNATTR: Function Attrs: noinline nounwind uwtable
103; FNATTR-NEXT: define void @_Z9delete_opPc(i8* %0) local_unnamed_addr
104define void @_Z9delete_opPc(i8* %0) local_unnamed_addr #0 {
105  %2 = icmp eq i8* %0, null
106  br i1 %2, label %4, label %3
107
108; <label>:3:                                      ; preds = %1
109  tail call void @_ZdaPv(i8* nonnull %0) #2
110  br label %4
111
112; <label>:4:                                      ; preds = %3, %1
113  ret void
114}
115
116
117; TEST 6 (negative case)
118; Call realloc
119; FNATTR: Function Attrs: noinline nounwind uwtable
120; FNATTR-NEXT: define noalias i8* @call_realloc(i8* nocapture %0, i64 %1) local_unnamed_addr
121define noalias i8* @call_realloc(i8* nocapture %0, i64 %1) local_unnamed_addr #0 {
122    %ret = tail call i8* @realloc(i8* %0, i64 %1) #2
123    ret i8* %ret
124}
125
126
127; TEST 7 (positive case)
128; Call function declaration with "nofree"
129
130
131; FNATTR: Function Attrs: nofree noinline nounwind readnone uwtable
132; FNATTR-NEXT: declare void @nofree_function()
133declare void @nofree_function() nofree readnone #0
134
135; FNATTR: Function Attrs: noinline nounwind readnone uwtable
136; FNATTR-NEXT: define void @call_nofree_function()
137define void @call_nofree_function() #0 {
138    tail call void @nofree_function()
139    ret void
140}
141
142; TEST 8 (negative case)
143; Call function declaration without "nofree"
144
145
146declare void @maybe_free() #0
147
148
149; FNATTR: Function Attrs: noinline nounwind uwtable
150; FNATTR: define void @call_maybe_free()
151define void @call_maybe_free() #0 {
152    tail call void @maybe_free()
153    ret void
154}
155
156
157; TEST 9 (negative case)
158; Call both of above functions
159
160; FNATTR: Function Attrs: noinline nounwind uwtable
161; FNATTR-NEXT: define void @call_both()
162define void @call_both() #0 {
163    tail call void @maybe_free()
164    tail call void @nofree_function()
165    ret void
166}
167
168
169; TEST 10 (positive case)
170; Call intrinsic function
171; FNATTRS: Function Attrs: noinline readnone speculatable
172; FNATTRS-NEXT: declare float @llvm.floor.f32(float %0)
173declare float @llvm.floor.f32(float)
174
175; FNATTRS: Function Attrs: noinline nounwind uwtable
176; FNATTRS-NEXT: define void @call_floor(float %a)
177; FIXME: missing nofree
178
179define void @call_floor(float %a) #0 {
180    tail call float @llvm.floor.f32(float %a)
181    ret void
182}
183
184; TEST 11 (positive case)
185; Check propagation.
186
187; FNATTRS: Function Attrs: noinline nounwind uwtable
188; FNATTRS-NEXT: define void @f1()
189define void @f1() #0 {
190    tail call void @nofree_function()
191    ret void
192}
193
194; FNATTRS: Function Attrs: noinline nounwind uwtable
195; FNATTRS-NEXT: define void @f2()
196define void @f2() #0 {
197    tail call void @f1()
198    ret void
199}
200
201
202declare noalias i8* @malloc(i64)
203
204attributes #0 = { nounwind uwtable noinline }
205attributes #1 = { nounwind }
206attributes #2 = { nobuiltin nounwind }
207