1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-10-19 02:52:53 +02:00
llvm-mirror/test/Other/cgscc-devirt-iteration.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

132 lines
5.4 KiB
LLVM

; The CGSCC pass manager includes an SCC iteration utility that tracks indirect
; calls that are turned into direct calls (devirtualization) and re-visits the
; SCC to expose those calls to the SCC-based IPO passes. We trigger
; devirtualization here with GVN which forwards a store through a load and to
; an indirect call.
;
; RUN: opt -aa-pipeline=basic-aa -passes='cgscc(function-attrs,function(gvn,instcombine))' -S < %s | FileCheck %s --check-prefix=CHECK --check-prefix=BEFORE
; RUN: opt -aa-pipeline=basic-aa -passes='cgscc(devirt<1>(function-attrs,function(gvn,instcombine)))' -S < %s | FileCheck %s --check-prefix=CHECK --check-prefix=AFTER --check-prefix=AFTER1
; RUN: opt -aa-pipeline=basic-aa -passes='cgscc(devirt<2>(function-attrs,function(gvn,instcombine)))' -S < %s | FileCheck %s --check-prefix=CHECK --check-prefix=AFTER --check-prefix=AFTER2
;
; We also verify that the real O2 pipeline catches these cases.
; RUN: opt -aa-pipeline=basic-aa -passes='default<O2>' -S < %s | FileCheck %s --check-prefix=CHECK --check-prefix=AFTER --check-prefix=AFTER2
declare void @readnone() readnone
; CHECK: Function Attrs: readnone
; CHECK-NEXT: declare void @readnone()
declare void @unknown()
; CHECK-NOT: Function Attrs
; CHECK-LABEL: declare void @unknown(){{ *$}}
; The @test1 function checks that when we refine an indirect call to a direct
; call we revisit the SCC passes to reflect the more precise information. This
; is the basic functionality.
define void @test1() {
; BEFORE-NOT: Function Attrs
; AFTER: Function Attrs: readnone
; CHECK-LABEL: define void @test1()
entry:
%fptr = alloca void ()*
store void ()* @readnone, void ()** %fptr
%f = load void ()*, void ()** %fptr
call void %f()
ret void
}
; The @test2_* functions check that when we need multiple (in this case 2)
; repetitions to compute some state that is incrementally exposed with each
; one, the limit on repetitions is enforced. So we make progress with
; one repetition but not as much as with three.
;
; This is somewhat awkward to test because we have to contrive to have a state
; repetition triggered and observed with very few passes. The technique here
; is to have one indirect call that can only be resolved when the entire SCC is
; deduced as readonly, and mark that indirect call at the call site as readonly
; to make that possible. This forces us to first deduce readonly, then
; devirtualize again, and then deduce readnone.
declare void @readnone_with_arg(void ()**) readnone
; CHECK: Function Attrs: readnone
; CHECK-LABEL: declare void @readnone_with_arg(void ()**)
define void @test2_a(void ()** %ignore) {
; BEFORE-NOT: Function Attrs
; AFTER1: Function Attrs: readonly
; AFTER2: Function Attrs: readnone
; BEFORE: define void @test2_a(void ()** %ignore)
; AFTER: define void @test2_a(void ()** readnone %ignore)
entry:
%f1ptr = alloca void (void ()**)*
store void (void ()**)* @readnone_with_arg, void (void ()**)** %f1ptr
%f1 = load void (void ()**)*, void (void ()**)** %f1ptr
; This indirect call is the first to be resolved, allowing us to deduce
; readonly but not (yet) readnone.
call void %f1(void ()** %ignore)
; CHECK: call void @readnone_with_arg(void ()** %ignore)
; Bogus call to test2_b to make this a cycle.
call void @test2_b()
ret void
}
define void @test2_b() {
; BEFORE-NOT: Function Attrs
; AFTER1: Function Attrs: readonly
; AFTER2: Function Attrs: readnone
; CHECK-LABEL: define void @test2_b()
entry:
%f2ptr = alloca void ()*
store void ()* @readnone, void ()** %f2ptr
; Call the other function here to prevent forwarding until the SCC has had
; function attrs deduced.
call void @test2_a(void ()** %f2ptr)
%f2 = load void ()*, void ()** %f2ptr
; This is the second indirect call to be resolved, and can only be resolved
; after we deduce 'readonly' for the rest of the SCC. Once it is
; devirtualized, we can deduce readnone for the SCC.
call void %f2() readonly
; BEFORE: call void %f2()
; AFTER: call void @readnone()
ret void
}
declare i8* @memcpy(i8*, i8*, i64)
; CHECK-LABEL: declare i8* @memcpy(
; The @test3 function checks that when we refine an indirect call to an
; intrinsic we still revisit the SCC pass. This also covers cases where the
; value handle itself doesn't persist due to the nature of how instcombine
; creates the memcpy intrinsic call, and we rely on the count of indirect calls
; decreasing and the count of direct calls increasing.
; Adding 'noinline' attribute to force attributes for improved matching.
define void @test3(i8* %src, i8* %dest, i64 %size) noinline {
; CHECK: Function Attrs
; CHECK-NOT: read
; CHECK-SAME: noinline
; BEFORE-LABEL: define void @test3(i8* %src, i8* %dest, i64 %size)
; AFTER-LABEL: define void @test3(i8* nocapture readonly %src, i8* nocapture %dest, i64 %size)
%fptr = alloca i8* (i8*, i8*, i64)*
store i8* (i8*, i8*, i64)* @memcpy, i8* (i8*, i8*, i64)** %fptr
%f = load i8* (i8*, i8*, i64)*, i8* (i8*, i8*, i64)** %fptr
call i8* %f(i8* %dest, i8* %src, i64 %size)
; CHECK: call void @llvm.memcpy
ret void
}
; A boring function that just keeps our declarations around.
define void @keep(i8** %sink) {
; CHECK-NOT: Function Attrs
; CHECK-LABEL: define void @keep(
entry:
store volatile i8* bitcast (void ()* @readnone to i8*), i8** %sink
store volatile i8* bitcast (void ()* @unknown to i8*), i8** %sink
store volatile i8* bitcast (i8* (i8*, i8*, i64)* @memcpy to i8*), i8** %sink
call void @unknown()
ret void
}