1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-23 19:23:23 +01:00
llvm-mirror/test/Transforms/Inline/cgscc-update.ll
Fedor Sergeev 012a27a068 [PM][FunctionAttrs] add NoUnwind attribute inference to PostOrderFunctionAttrs pass
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
2018-03-23 21:46:16 +00:00

185 lines
4.8 KiB
LLVM

; RUN: opt < %s -aa-pipeline=basic-aa -passes='cgscc(function-attrs,inline)' -S | FileCheck %s
; This test runs the inliner and the function attribute deduction. It ensures
; that when the inliner mutates the call graph it correctly updates the CGSCC
; iteration so that we can compute refined function attributes. In this way it
; is leveraging function attribute computation to observe correct call graph
; updates.
; Boring unknown external function call.
; CHECK: declare void @unknown()
declare void @unknown()
; Sanity check: this should get annotated as readnone.
; CHECK: Function Attrs: nounwind readnone
; CHECK-NEXT: declare void @readnone()
declare void @readnone() readnone nounwind
; The 'test1_' prefixed functions are designed to trigger forming a new direct
; call in the inlined body of the function. After that, we form a new SCC and
; using that can deduce precise function attrs.
; This function should no longer exist.
; CHECK-NOT: @test1_f()
define internal void @test1_f(void()* %p) {
entry:
call void %p()
ret void
}
; This function should have had 'readnone' deduced for its SCC.
; CHECK: Function Attrs: noinline nounwind readnone
; CHECK-NEXT: define void @test1_g()
define void @test1_g() noinline {
entry:
call void @test1_f(void()* @test1_h)
ret void
}
; This function should have had 'readnone' deduced for its SCC.
; CHECK: Function Attrs: noinline nounwind readnone
; CHECK-NEXT: define void @test1_h()
define void @test1_h() noinline {
entry:
call void @test1_g()
call void @readnone()
ret void
}
; The 'test2_' prefixed functions are designed to trigger forming a new direct
; call due to RAUW-ing the returned value of a called function into the caller.
; This too should form a new SCC which can then be reasoned about to compute
; precise function attrs.
; This function should no longer exist.
; CHECK-NOT: @test2_f()
define internal void()* @test2_f() {
entry:
ret void()* @test2_h
}
; This function should have had 'readnone' deduced for its SCC.
; CHECK: Function Attrs: noinline nounwind readnone
; CHECK-NEXT: define void @test2_g()
define void @test2_g() noinline {
entry:
%p = call void()* @test2_f()
call void %p()
ret void
}
; This function should have had 'readnone' deduced for its SCC.
; CHECK: Function Attrs: noinline nounwind readnone
; CHECK-NEXT: define void @test2_h()
define void @test2_h() noinline {
entry:
call void @test2_g()
call void @readnone()
ret void
}
; The 'test3_' prefixed functions are designed to inline in a way that causes
; call sites to become trivially dead during the middle of inlining callsites of
; a single function to make sure that the inliner does not get confused by this
; pattern.
; CHECK-NOT: @test3_maybe_unknown(
define internal void @test3_maybe_unknown(i1 %b) {
entry:
br i1 %b, label %then, label %exit
then:
call void @unknown()
br label %exit
exit:
ret void
}
; CHECK-NOT: @test3_f(
define internal i1 @test3_f() {
entry:
ret i1 false
}
; CHECK-NOT: @test3_g(
define internal i1 @test3_g(i1 %b) {
entry:
br i1 %b, label %then1, label %if2
then1:
call void @test3_maybe_unknown(i1 true)
br label %if2
if2:
%f = call i1 @test3_f()
br i1 %f, label %then2, label %exit
then2:
call void @test3_maybe_unknown(i1 true)
br label %exit
exit:
ret i1 false
}
; FIXME: Currently the inliner doesn't successfully mark this as readnone
; because while it simplifies trivially dead CFGs when inlining callees it
; doesn't simplify the caller's trivially dead CFG and so we end with a dead
; block calling @unknown.
; CHECK-NOT: Function Attrs: readnone
; CHECK: define void @test3_h()
define void @test3_h() {
entry:
%g = call i1 @test3_g(i1 false)
br i1 %g, label %then, label %exit
then:
call void @test3_maybe_unknown(i1 true)
br label %exit
exit:
call void @test3_maybe_unknown(i1 false)
ret void
}
; The 'test4_' prefixed functions are designed to trigger forming a new direct
; call in the inlined body of the function similar to 'test1_'. However, after
; that we continue to inline another edge of the graph forcing us to do a more
; interesting call graph update for the new call edge. Eventually, we still
; form a new SCC and should use that can deduce precise function attrs.
; This function should have had 'readnone' deduced for its SCC.
; CHECK: Function Attrs: noinline nounwind readnone
; CHECK-NEXT: define void @test4_f1()
define void @test4_f1() noinline {
entry:
call void @test4_h()
ret void
}
; CHECK-NOT: @test4_f2
define internal void @test4_f2() {
entry:
call void @test4_f1()
ret void
}
; CHECK-NOT: @test4_g
define internal void @test4_g(void()* %p) {
entry:
call void %p()
ret void
}
; This function should have had 'readnone' deduced for its SCC.
; CHECK: Function Attrs: noinline nounwind readnone
; CHECK-NEXT: define void @test4_h()
define void @test4_h() noinline {
entry:
call void @test4_g(void()* @test4_f2)
ret void
}