1; RUN: opt -function-attrs --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