; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes ; 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 ; 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 ; 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 ; 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 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" ; Test cases specifically designed for the "nofree" function attribute. ; We use FIXME's to indicate problems and missing attributes. ; Free functions declare void @free(i8* nocapture) local_unnamed_addr #1 declare noalias i8* @realloc(i8* nocapture, i64) local_unnamed_addr #0 declare void @_ZdaPv(i8*) local_unnamed_addr #2 ; TEST 1 (positive case) define void @only_return() #0 { ; IS__TUNIT____: Function Attrs: nofree noinline nosync nounwind readnone uwtable willreturn ; IS__TUNIT____-LABEL: define {{[^@]+}}@only_return ; IS__TUNIT____-SAME: () [[ATTR3:#.*]] { ; IS__TUNIT____-NEXT: ret void ; ; IS__CGSCC____: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable willreturn ; IS__CGSCC____-LABEL: define {{[^@]+}}@only_return ; IS__CGSCC____-SAME: () [[ATTR3:#.*]] { ; IS__CGSCC____-NEXT: ret void ; ret void } ; TEST 2 (negative case) ; Only free ; void only_free(char* p) { ; free(p); ; } define void @only_free(i8* nocapture %0) local_unnamed_addr #0 { ; CHECK: Function Attrs: noinline nounwind uwtable ; CHECK-LABEL: define {{[^@]+}}@only_free ; CHECK-SAME: (i8* nocapture [[TMP0:%.*]]) local_unnamed_addr [[ATTR1:#.*]] { ; CHECK-NEXT: tail call void @free(i8* nocapture [[TMP0]]) [[ATTR0:#.*]] ; CHECK-NEXT: ret void ; tail call void @free(i8* %0) #1 ret void } ; TEST 3 (negative case) ; Free occurs in same scc. ; void free_in_scc1(char*p){ ; free_in_scc2(p); ; } ; void free_in_scc2(char*p){ ; free_in_scc1(p); ; free(p); ; } define void @free_in_scc1(i8* nocapture %0) local_unnamed_addr #0 { ; CHECK: Function Attrs: noinline nounwind uwtable ; CHECK-LABEL: define {{[^@]+}}@free_in_scc1 ; CHECK-SAME: (i8* nocapture [[TMP0:%.*]]) local_unnamed_addr [[ATTR1]] { ; CHECK-NEXT: tail call void @free_in_scc2(i8* nocapture [[TMP0]]) [[ATTR0]] ; CHECK-NEXT: ret void ; tail call void @free_in_scc2(i8* %0) #1 ret void } define void @free_in_scc2(i8* nocapture %0) local_unnamed_addr #0 { ; CHECK: Function Attrs: noinline nounwind uwtable ; CHECK-LABEL: define {{[^@]+}}@free_in_scc2 ; CHECK-SAME: (i8* nocapture [[TMP0:%.*]]) local_unnamed_addr [[ATTR1]] { ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8* [[TMP0]], null ; CHECK-NEXT: br i1 [[CMP]], label [[REC:%.*]], label [[CALL:%.*]] ; CHECK: call: ; CHECK-NEXT: tail call void @free(i8* nocapture [[TMP0]]) [[ATTR0]] ; CHECK-NEXT: br label [[END:%.*]] ; CHECK: rec: ; CHECK-NEXT: tail call void @free_in_scc1(i8* nocapture [[TMP0]]) [[ATTR0]] ; CHECK-NEXT: br label [[END]] ; CHECK: end: ; CHECK-NEXT: ret void ; %cmp = icmp eq i8* %0, null br i1 %cmp, label %rec, label %call call: tail call void @free(i8* %0) #1 br label %end rec: tail call void @free_in_scc1(i8* %0) br label %end end: ret void } ; TEST 4 (positive case) ; Free doesn't occur. ; void mutual_recursion1(){ ; mutual_recursion2(); ; } ; void mutual_recursion2(){ ; mutual_recursion1(); ; } define void @mutual_recursion1() #0 { ; NOT_CGSCC_NPM: Function Attrs: nofree noinline noreturn nosync nounwind readnone uwtable willreturn ; NOT_CGSCC_NPM-LABEL: define {{[^@]+}}@mutual_recursion1 ; NOT_CGSCC_NPM-SAME: () [[ATTR4:#.*]] { ; NOT_CGSCC_NPM-NEXT: unreachable ; ; IS__CGSCC_NPM: Function Attrs: nofree noinline norecurse noreturn nosync nounwind readnone uwtable willreturn ; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@mutual_recursion1 ; IS__CGSCC_NPM-SAME: () [[ATTR4:#.*]] { ; IS__CGSCC_NPM-NEXT: unreachable ; call void @mutual_recursion2() ret void } define void @mutual_recursion2() #0 { ; NOT_CGSCC_NPM: Function Attrs: nofree noinline noreturn nosync nounwind readnone uwtable willreturn ; NOT_CGSCC_NPM-LABEL: define {{[^@]+}}@mutual_recursion2 ; NOT_CGSCC_NPM-SAME: () [[ATTR4]] { ; NOT_CGSCC_NPM-NEXT: unreachable ; ; IS__CGSCC_NPM: Function Attrs: nofree noinline norecurse noreturn nosync nounwind readnone uwtable willreturn ; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@mutual_recursion2 ; IS__CGSCC_NPM-SAME: () [[ATTR4]] { ; IS__CGSCC_NPM-NEXT: unreachable ; call void @mutual_recursion1() ret void } ; TEST 5 ; C++ delete operation (negative case) ; void delete_op (char p[]){ ; delete [] p; ; } define void @_Z9delete_opPc(i8* %0) local_unnamed_addr #0 { ; CHECK: Function Attrs: noinline nounwind uwtable ; CHECK-LABEL: define {{[^@]+}}@_Z9delete_opPc ; CHECK-SAME: (i8* [[TMP0:%.*]]) local_unnamed_addr [[ATTR1]] { ; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i8* [[TMP0]], null ; CHECK-NEXT: br i1 [[TMP2]], label [[TMP4:%.*]], label [[TMP3:%.*]] ; CHECK: 3: ; CHECK-NEXT: tail call void @_ZdaPv(i8* nonnull [[TMP0]]) [[ATTR2:#.*]] ; CHECK-NEXT: br label [[TMP4]] ; CHECK: 4: ; CHECK-NEXT: ret void ; %2 = icmp eq i8* %0, null br i1 %2, label %4, label %3 ;