summaryrefslogtreecommitdiffstats
path: root/llvm/test/Transforms/Inline/cgscc-incremental-invalidate.ll
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/test/Transforms/Inline/cgscc-incremental-invalidate.ll')
-rw-r--r--llvm/test/Transforms/Inline/cgscc-incremental-invalidate.ll111
1 files changed, 111 insertions, 0 deletions
diff --git a/llvm/test/Transforms/Inline/cgscc-incremental-invalidate.ll b/llvm/test/Transforms/Inline/cgscc-incremental-invalidate.ll
new file mode 100644
index 00000000000..7c6d0fc04ce
--- /dev/null
+++ b/llvm/test/Transforms/Inline/cgscc-incremental-invalidate.ll
@@ -0,0 +1,111 @@
+; Test for a subtle bug when computing analyses during inlining and mutating
+; the SCC structure. Without care, this can fail to invalidate analyses.
+;
+; RUN: opt < %s -passes='cgscc(inline,function(verify<domtree>))' -debug-pass-manager -S 2>&1 | FileCheck %s
+
+; First we check that the passes run in the way we expect. Otherwise this test
+; may stop testing anything.
+;
+; CHECK-LABEL: Starting llvm::Module pass manager run.
+; CHECK: Running pass: InlinerPass on (test1_h, test1_g, test1_f)
+; CHECK: Running analysis: FunctionAnalysisManagerCGSCCProxy on (test1_h, test1_g, test1_f)
+; CHECK: Running analysis: DominatorTreeAnalysis on test1_f
+; CHECK: Running analysis: DominatorTreeAnalysis on test1_g
+; CHECK: Invalidating all non-preserved analyses for: (test1_h, test1_g, test1_f)
+; CHECK: Invalidating all non-preserved analyses for: test1_h
+; CHECK-NOT: Invalidating anaylsis:
+; CHECK: Invalidating all non-preserved analyses for: test1_g
+; CHECK: Invalidating analysis: DominatorTreeAnalysis on test1_g
+; CHECK: Invalidating all non-preserved analyses for: test1_f
+; CHECK: Invalidating analysis: DominatorTreeAnalysis on test1_f
+; CHECK: Running analysis: DominatorTreeAnalysis on test1_h
+; CHECK: Invalidating all non-preserved analyses for: (test1_h, test1_g)
+; CHECK: Invalidating all non-preserved analyses for: test1_h
+; CHECK: Invalidating analysis: DominatorTreeAnalysis on test1_h
+
+; 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() {
+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 work to carefully test that incrementally
+; reducing an SCC in the inliner cannot accidentially leave stale function
+; analysis results due to failing to invalidate them for all the functions.
+
+; We visit this function first in the inliner, and while we inline callee
+; perturbing the CFG, we don't inline anything else and the SCC structure
+; remains in tact.
+define void @test1_f() {
+; CHECK-LABEL: define void @test1_f()
+entry:
+ ; We force this edge to survive inlining.
+ call void @test1_g() noinline
+; CHECK: call void @test1_g()
+
+ ; Pull interesting CFG into this function.
+ call void @callee()
+; CHECK-NOT: call void @callee()
+
+ ret void
+; CHECK: ret void
+}
+
+; Next we visit this function and here we inline the edge to 'test1_f'
+; separating it into its own SCC. The current SCC is now just 'test1_g' and
+; 'test1_h'.
+define void @test1_g() {
+; CHECK-LABEL: define void @test1_g()
+entry:
+ ; This edge gets inlined away.
+ call void @test1_f()
+; CHECK-NOT: call void @test1_f()
+; CHECK: call void @test1_g()
+
+ ; We force this edge to survive inlining.
+ call void @test1_h() noinline
+; CHECK: call void @test1_h()
+
+ ; Pull interesting CFG into this function.
+ call void @callee()
+; CHECK-NOT: call void @callee()
+
+ ret void
+; CHECK: ret void
+}
+
+; Finally the inliner visits this last function. It can't actually break any
+; cycles here, but because we visit this function we compute fresh analyses for
+; it. These analyses are then invalidated when we inline callee disrupting the
+; CFG, and it is important that they be freed.
+define void @test1_h() {
+; CHECK-LABEL: define void @test1_h()
+entry:
+ call void @test1_g()
+; CHECK: call void @test1_g()
+
+ ; Pull interesting CFG into this function.
+ call void @callee()
+; CHECK-NOT: call void @callee()
+
+ ret void
+; CHECK: ret void
+}
OpenPOWER on IntegriCloud