Summary:
This was motivated by absence of PrunEH functionality in new PM.
It was decided that a proper way to do PruneEH is to add NoUnwind inference
into PostOrderFunctionAttrs and then perform normal SimplifyCFG on top.
This change generalizes attribute handling implemented for (a removal of)
Convergent attribute, by introducing a generic builder-like class
AttributeInferer
It registers all the attribute inference requests, storing per-attribute
predicates into a vector, and then goes through an SCC Node, scanning all
the instructions for not breaking attribute assumptions.
The main idea is that as soon all the instructions from all the functions
of SCC Node conform to attribute assumptions then we are free to infer
the attribute as set for all the functions of SCC Node.
It handles two distinct cases of attributes:
- those that might break due to derefinement of the function code
for these attributes we are allowed to apply inference only if all the
functions are "exact definitions". Example - NoUnwind.
- those that do not care about derefinement
for these attributes we are allowed to apply inference as soon as we see
any function definition. Example - removal of Convergent attribute.
Also in this commit:
* Converted all the FunctionAttrs tests to use FileCheck and added new-PM
invocations to them
* FunctionAttrs/convergent.ll test demonstrates a difference in behavior between
new and old PM implementations. Marked with FIXME.
* PruneEH tests were converted to new-PM as well, using function-attrs+simplify-cfg
combo as intended
* some of "other" tests were updated since function-attrs now infers 'nounwind'
even for old PM pipeline
* -disable-nounwind-inference hidden option added as a possible workaround for a supposedly
rare case when nounwind being inferred by default presents a problem
Reviewers: chandlerc, jlebar
Reviewed By: jlebar
Subscribers: eraman, llvm-commits
Differential Revision: https://reviews.llvm.org/D44415
llvm-svn: 328377
111 lines
3.0 KiB
LLVM
111 lines
3.0 KiB
LLVM
; FIXME: convert CHECK-INDIRECT into CHECK (and remove -check-prefixes) as soon
|
|
; FIXME: as new-pass-manager's handling of indirect_non_convergent_call is fixed
|
|
;
|
|
; RUN: opt -functionattrs -S < %s | FileCheck %s --check-prefixes=CHECK,CHECK-INDIRECT
|
|
; RUN: opt -passes=function-attrs -S < %s | FileCheck %s
|
|
|
|
; CHECK: Function Attrs
|
|
; CHECK-NOT: convergent
|
|
; CHECK-NEXT: define i32 @nonleaf()
|
|
define i32 @nonleaf() convergent {
|
|
%a = call i32 @leaf()
|
|
ret i32 %a
|
|
}
|
|
|
|
; CHECK: Function Attrs
|
|
; CHECK-NOT: convergent
|
|
; CHECK-NEXT: define i32 @leaf()
|
|
define i32 @leaf() convergent {
|
|
ret i32 0
|
|
}
|
|
|
|
; CHECK: Function Attrs
|
|
; CHECK-SAME: convergent
|
|
; CHECK-NEXT: declare i32 @k()
|
|
declare i32 @k() convergent
|
|
|
|
; CHECK: Function Attrs
|
|
; CHECK-SAME: convergent
|
|
; CHECK-NEXT: define i32 @extern()
|
|
define i32 @extern() convergent {
|
|
%a = call i32 @k() convergent
|
|
ret i32 %a
|
|
}
|
|
|
|
; Convergent should not be removed on the function here. Although the call is
|
|
; not explicitly convergent, it picks up the convergent attr from the callee.
|
|
;
|
|
; CHECK: Function Attrs
|
|
; CHECK-SAME: convergent
|
|
; CHECK-NEXT: define i32 @extern_non_convergent_call()
|
|
define i32 @extern_non_convergent_call() convergent {
|
|
%a = call i32 @k()
|
|
ret i32 %a
|
|
}
|
|
|
|
; CHECK: Function Attrs
|
|
; CHECK-SAME: convergent
|
|
; CHECK-NEXT: define i32 @indirect_convergent_call(
|
|
define i32 @indirect_convergent_call(i32 ()* %f) convergent {
|
|
%a = call i32 %f() convergent
|
|
ret i32 %a
|
|
}
|
|
; Give indirect_non_convergent_call the norecurse attribute so we get a
|
|
; "Function Attrs" comment in the output.
|
|
;
|
|
; CHECK: Function Attrs
|
|
; CHECK-INDIRECT-NOT: convergent
|
|
; CHECK-INDIRECT-NEXT: define i32 @indirect_non_convergent_call(
|
|
define i32 @indirect_non_convergent_call(i32 ()* %f) convergent norecurse {
|
|
%a = call i32 %f()
|
|
ret i32 %a
|
|
}
|
|
|
|
; CHECK: Function Attrs
|
|
; CHECK-SAME: convergent
|
|
; CHECK-NEXT: declare void @llvm.nvvm.barrier0()
|
|
declare void @llvm.nvvm.barrier0() convergent
|
|
|
|
; CHECK: Function Attrs
|
|
; CHECK-SAME: convergent
|
|
; CHECK-NEXT: define i32 @intrinsic()
|
|
define i32 @intrinsic() convergent {
|
|
; Implicitly convergent, because the intrinsic is convergent.
|
|
call void @llvm.nvvm.barrier0()
|
|
ret i32 0
|
|
}
|
|
|
|
; CHECK: Function Attrs
|
|
; CHECK-NOT: convergent
|
|
; CHECK-NEXT: define i32 @recursive1()
|
|
define i32 @recursive1() convergent {
|
|
%a = call i32 @recursive2() convergent
|
|
ret i32 %a
|
|
}
|
|
|
|
; CHECK: Function Attrs
|
|
; CHECK-NOT: convergent
|
|
; CHECK-NEXT: define i32 @recursive2()
|
|
define i32 @recursive2() convergent {
|
|
%a = call i32 @recursive1() convergent
|
|
ret i32 %a
|
|
}
|
|
|
|
; CHECK: Function Attrs
|
|
; CHECK-SAME: convergent
|
|
; CHECK-NEXT: define i32 @noopt()
|
|
define i32 @noopt() convergent optnone noinline {
|
|
%a = call i32 @noopt_friend() convergent
|
|
ret i32 0
|
|
}
|
|
|
|
; A function which is mutually-recursive with a convergent, optnone function
|
|
; shouldn't have its convergent attribute stripped.
|
|
; CHECK: Function Attrs
|
|
; CHECK-SAME: convergent
|
|
; CHECK-NEXT: define i32 @noopt_friend()
|
|
define i32 @noopt_friend() convergent {
|
|
%a = call i32 @noopt()
|
|
ret i32 0
|
|
}
|