Files
clang-p2996/llvm/test/Transforms/FunctionAttrs/nofree-attributor.ll
Johannes Doerfert 3ab9e8b818 [Attributor][Fix] Initialize the cache prior to using it
Summary:
There were segfaults as we modified and iterated the instruction maps in
the cache at the same time. This was happening because we created new
instructions while we populated the cache. This fix changes the order
in which we perform these actions. First, the caches for the whole
module are created, then we start to create abstract attributes.

I don't have a unit test but the LLVM test suite exposes this problem.

Reviewers: uenoku, sstefan1

Subscribers: hiraditya, bollu, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D67232

llvm-svn: 372105
2019-09-17 10:52:41 +00:00

247 lines
7.4 KiB
LLVM

; RUN: opt -functionattrs --disable-nofree-inference=false -S < %s | FileCheck %s --check-prefix=FNATTR
; RUN: opt -attributor --attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=4 -S < %s | FileCheck %s --check-prefix=ATTRIBUTOR
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)
; FNATTR: Function Attrs: noinline norecurse nounwind readnone uwtable
; FNATTR-NEXT: define void @only_return()
; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind uwtable
; ATTRIBUTOR-NEXT: define void @only_return()
define void @only_return() #0 {
ret void
}
; TEST 2 (negative case)
; Only free
; void only_free(char* p) {
; free(p);
; }
; FNATTR: Function Attrs: noinline nounwind uwtable
; FNATTR-NEXT: define void @only_free(i8* nocapture %0) local_unnamed_addr
; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable
; ATTRIBUTOR-NOT: nofree
; ATTRIBUTOR-NEXT: define void @only_free(i8* nocapture %0) local_unnamed_addr #1
define void @only_free(i8* nocapture %0) local_unnamed_addr #0 {
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);
; }
; FNATTR: Function Attrs: noinline nounwind uwtable
; FNATTR-NEXT: define void @free_in_scc1(i8* nocapture %0) local_unnamed_addr
; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable
; ATTRIBUTOR-NOT: nofree
; ATTRIBUTOR-NEXT :define void @free_in_scc1(i8* nocapture %0) local_unnamed_addr
define void @free_in_scc1(i8* nocapture %0) local_unnamed_addr #0 {
tail call void @free_in_scc2(i8* %0) #1
ret void
}
; FNATTR: Function Attrs: noinline nounwind uwtable
; FNATTR-NEXT: define void @free_in_scc2(i8* nocapture %0) local_unnamed_addr
; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable
; ATTRIBUTOR-NOT: nofree
; ATTRIBUTOR: define void @free_in_scc2(i8* nocapture %0) local_unnamed_addr
define void @free_in_scc2(i8* nocapture %0) local_unnamed_addr #0 {
%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();
; }
; FNATTR: Function Attrs: noinline nounwind readnone uwtable
; FNATTR-NEXT: define void @mutual_recursion1()
; ATTRIBUTOR: Function Attrs: nofree noinline noreturn nosync nounwind uwtable
; ATTRIBUTOR-NEXT: define void @mutual_recursion1()
define void @mutual_recursion1() #0 {
call void @mutual_recursion2()
ret void
}
; FNATTR: Function Attrs: noinline nounwind readnone uwtable
; FNATTR-NEXT: define void @mutual_recursion2()
; ATTRIBUTOR: Function Attrs: nofree noinline noreturn nosync nounwind uwtable
; ATTRIBUTOR-NEXT: define void @mutual_recursion2()
define void @mutual_recursion2() #0 {
call void @mutual_recursion1()
ret void
}
; TEST 5
; C++ delete operation (negative case)
; void delete_op (char p[]){
; delete [] p;
; }
; FNATTR: Function Attrs: noinline nounwind uwtable
; FNATTR-NEXT: define void @_Z9delete_opPc(i8* %0) local_unnamed_addr
; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable
; ATTRIBUTOR-NOT: nofree
; ATTRIBUTOR-NEXT: define void @_Z9delete_opPc(i8* %0) local_unnamed_addr #1
define void @_Z9delete_opPc(i8* %0) local_unnamed_addr #0 {
%2 = icmp eq i8* %0, null
br i1 %2, label %4, label %3
; <label>:3: ; preds = %1
tail call void @_ZdaPv(i8* nonnull %0) #2
br label %4
; <label>:4: ; preds = %3, %1
ret void
}
; TEST 6 (negative case)
; Call realloc
; FNATTR: Function Attrs: noinline nounwind uwtable
; FNATTR-NEXT: define noalias i8* @call_realloc(i8* nocapture %0, i64 %1) local_unnamed_addr
; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable
; ATTRIBUTOR-NOT: nofree
; ATTRIBUTOR-NEXT: define noalias i8* @call_realloc(i8* nocapture %0, i64 %1) local_unnamed_addr
define noalias i8* @call_realloc(i8* nocapture %0, i64 %1) local_unnamed_addr #0 {
%ret = tail call i8* @realloc(i8* %0, i64 %1) #2
ret i8* %ret
}
; TEST 7 (positive case)
; Call function declaration with "nofree"
; FNATTR: Function Attrs: nofree noinline nounwind readnone uwtable
; FNATTR-NEXT: declare void @nofree_function()
; ATTRIBUTOR: Function Attrs: nofree noinline nounwind readnone uwtable
; ATTRIBUTOR-NEXT: declare void @nofree_function()
declare void @nofree_function() nofree readnone #0
; FNATTR: Function Attrs: noinline nounwind readnone uwtable
; FNATTR-NEXT: define void @call_nofree_function()
; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind uwtable
; ATTRIBUTOR-NEXT: define void @call_nofree_function()
define void @call_nofree_function() #0 {
tail call void @nofree_function()
ret void
}
; TEST 8 (negative case)
; Call function declaration without "nofree"
; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable
; ATTRIBUTOR-NEXT: declare void @maybe_free()
declare void @maybe_free() #0
; FNATTR: Function Attrs: noinline nounwind uwtable
; FNATTR: define void @call_maybe_free()
; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable
; ATTRIBUTOR-NOT: nofree
; ATTRIBUTOR-NEXT: define void @call_maybe_free()
define void @call_maybe_free() #0 {
tail call void @maybe_free()
ret void
}
; TEST 9 (negative case)
; Call both of above functions
; FNATTR: Function Attrs: noinline nounwind uwtable
; FNATTR-NEXT: define void @call_both()
; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable
; ATTRIBUTOR-NOT: nofree
; ATTRIBUTOR-NEXT: define void @call_both()
define void @call_both() #0 {
tail call void @maybe_free()
tail call void @nofree_function()
ret void
}
; TEST 10 (positive case)
; Call intrinsic function
; FNATTRS: Function Attrs: noinline readnone speculatable
; FNATTRS-NEXT: declare float @llvm.floor.f32(float %0)
; ATTRIBUTOR: Function Attrs: nounwind readnone speculatable
; ATTRIBUTOR-NEXT: declare float @llvm.floor.f32(float)
declare float @llvm.floor.f32(float)
; FNATTRS: Function Attrs: noinline nounwind uwtable
; FNATTRS-NEXT: define void @call_floor(float %a)
; FIXME: missing nofree
; ATTRIBUTOR: Function Attrs: noinline nosync nounwind uwtable
; ATTRIBUTOR-NEXT: define void @call_floor(float %a)
define void @call_floor(float %a) #0 {
tail call float @llvm.floor.f32(float %a)
ret void
}
; TEST 11 (positive case)
; Check propagation.
; FNATTRS: Function Attrs: noinline nounwind uwtable
; FNATTRS-NEXT: define void @f1()
; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind uwtable
; ATTRIBUTOR-NEXT: define void @f1()
define void @f1() #0 {
tail call void @nofree_function()
ret void
}
; FNATTRS: Function Attrs: noinline nounwind uwtable
; FNATTRS-NEXT: define void @f2()
; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind uwtable
; ATTRIBUTOR-NEXT: define void @f2()
define void @f2() #0 {
tail call void @f1()
ret void
}
attributes #0 = { nounwind uwtable noinline }
attributes #1 = { nounwind }
attributes #2 = { nobuiltin nounwind }