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