summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorChandler Carruth <chandlerc@gmail.com>2016-12-28 10:34:50 +0000
committerChandler Carruth <chandlerc@gmail.com>2016-12-28 10:34:50 +0000
commit6fbb41e40ac1662c07eb7baad727a8066da56f91 (patch)
tree7b32720a4c8442679bc14547512884299cfd1411 /test
parentb3ccb4ea783bfbc1df5e40ec729ff37a4b304d54 (diff)
[PM] Teach the CGSCC's CG update utility to more carefully invalidate
analyses when we're about to break apart an SCC. We can't wait until after breaking apart the SCC to invalidate things: 1) Which SCC do we then invalidate? All of them? 2) Even if we invalidate all of them, a newly created SCC may not have a proxy that will convey the invalidation to functions! Previously we only invalidated one of the SCCs and too late. This led to stale analyses remaining in the cache. And because the caching strategy actually works, they would get used and chaos would ensue. Doing invalidation early is somewhat pessimizing though if we *know* that the SCC structure won't change. So it turns out that the design to make the mutation API force the caller to know the *kind* of mutation in advance was indeed 100% correct and we didn't do enough of it. So this change also splits two cases of switching a call edge to a ref edge into two separate APIs so that callers can clearly test for this and take the easy path without invalidating when appropriate. This is particularly important in this case as we expect most inlines to be between functions in separate SCCs and so the common case is that we don't have to so aggressively invalidate analyses. The LCG API change in turn needed some basic cleanups and better testing in its unittest. No interesting functionality changed there other than more coverage of the returned sequence of SCCs. While this seems like an obvious improvement over the current state, I'd like to revisit the core concept of invalidating within the CG-update layer at all. I'm wondering if we would be better served forcing the callers to handle the invalidation beforehand in the cases that they can handle it. An interesting example is when we want to teach the inliner to *update and preserve* analyses. But we can cross that bridge when we get there. With this patch, the new pass manager an build all of the LLVM test suite at -O3 and everything passes. =D I haven't bootstrapped yet and I'm sure there are still plenty of bugs, but this gives a nice baseline so I'm going to increasingly focus on fleshing out the missing functionality, especially the bits that are just turned off right now in order to let us establish this baseline. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@290664 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'test')
-rw-r--r--test/Transforms/Inline/cgscc-invalidate.ll104
1 files changed, 104 insertions, 0 deletions
diff --git a/test/Transforms/Inline/cgscc-invalidate.ll b/test/Transforms/Inline/cgscc-invalidate.ll
new file mode 100644
index 00000000000..60315cda771
--- /dev/null
+++ b/test/Transforms/Inline/cgscc-invalidate.ll
@@ -0,0 +1,104 @@
+; This test tries to ensure that the inliner successfully invalidates function
+; analyses after inlining into the function body.
+;
+; The strategy for these tests is to compute domtree over all the functions,
+; then run the inliner, and then verify the domtree. Then we can arrange the
+; inline to disturb the domtree (easy) and detect any stale cached entries in
+; the verifier. We do the initial computation both *inside* the CGSCC walk and
+; in a pre-step to make sure both work.
+;
+; RUN: opt < %s -passes='function(require<domtree>),cgscc(inline,function(verify<domtree>))' -S | FileCheck %s
+; RUN: opt < %s -passes='cgscc(function(require<domtree>),inline,function(verify<domtree>))' -S | FileCheck %s
+
+; An external function used to control branches.
+declare i1 @flag()
+; CHECK-LABEL: declare i1 @flag()
+
+; The utility function with interesting control flow that gets inlined below to
+; perturb the dominator tree.
+define internal void @callee() {
+; CHECK-LABEL: @callee
+entry:
+ %ptr = alloca i8
+ %flag = call i1 @flag()
+ br i1 %flag, label %then, label %else
+
+then:
+ store volatile i8 42, i8* %ptr
+ br label %return
+
+else:
+ store volatile i8 -42, i8* %ptr
+ br label %return
+
+return:
+ ret void
+}
+
+
+; The 'test1_' prefixed functions test the basic scenario of inlining
+; destroying dominator tree.
+
+define void @test1_caller() {
+; CHECK-LABEL: define void @test1_caller()
+entry:
+ call void @callee()
+; CHECK-NOT: @callee
+ ret void
+; CHECK: ret void
+}
+
+
+; The 'test2_' prefixed functions test the scenario of not inlining preserving
+; dominators.
+
+define void @test2_caller() {
+; CHECK-LABEL: define void @test2_caller()
+entry:
+ call void @callee() noinline
+; CHECK: call void @callee
+ ret void
+; CHECK: ret void
+}
+
+
+; The 'test3_' prefixed functions test the scenario of not inlining preserving
+; dominators after splitting an SCC into two smaller SCCs.
+
+; The first function gets visited first and we end up inlining everything we
+; can into this routine. That splits test3_g into a separate SCC that is enqued
+; for later processing.
+define void @test3_f() {
+; CHECK-LABEL: define void @test3_f()
+entry:
+ ; Create the first edge in the SCC cycle.
+ call void @test3_g()
+; CHECK-NOT: @test3_g()
+; CHECK: call void @test3_f()
+
+ ; Pull interesting CFG into this function.
+ call void @callee()
+; CHECK-NOT: call void @callee()
+
+ ret void
+; CHECK: ret void
+}
+
+; This function ends up split into a separate SCC, which can cause its analyses
+; to become stale if the splitting doesn't properly invalidate things. Also, as
+; a consequence of being split out, test3_f is too large to inline by the time
+; we get here.
+define void @test3_g() {
+; CHECK-LABEL: define void @test3_g()
+entry:
+ ; Create the second edge in the SCC cycle.
+ call void @test3_f()
+; CHECK: call void @test3_f()
+
+ ; Pull interesting CFG into this function.
+ call void @callee()
+; CHECK-NOT: call void @callee()
+
+ ret void
+; CHECK: ret void
+}