blob: 7c6d0fc04ce32df0a91582ed55ddfb89d4e23c38 [file] [log] [blame]
Chandler Carruthb698d592017-01-22 10:34:01 +00001; Test for a subtle bug when computing analyses during inlining and mutating
2; the SCC structure. Without care, this can fail to invalidate analyses.
3;
4; RUN: opt < %s -passes='cgscc(inline,function(verify<domtree>))' -debug-pass-manager -S 2>&1 | FileCheck %s
5
6; First we check that the passes run in the way we expect. Otherwise this test
7; may stop testing anything.
8;
9; CHECK-LABEL: Starting llvm::Module pass manager run.
10; CHECK: Running pass: InlinerPass on (test1_h, test1_g, test1_f)
11; CHECK: Running analysis: FunctionAnalysisManagerCGSCCProxy on (test1_h, test1_g, test1_f)
12; CHECK: Running analysis: DominatorTreeAnalysis on test1_f
13; CHECK: Running analysis: DominatorTreeAnalysis on test1_g
14; CHECK: Invalidating all non-preserved analyses for: (test1_h, test1_g, test1_f)
15; CHECK: Invalidating all non-preserved analyses for: test1_h
16; CHECK-NOT: Invalidating anaylsis:
17; CHECK: Invalidating all non-preserved analyses for: test1_g
18; CHECK: Invalidating analysis: DominatorTreeAnalysis on test1_g
19; CHECK: Invalidating all non-preserved analyses for: test1_f
20; CHECK: Invalidating analysis: DominatorTreeAnalysis on test1_f
21; CHECK: Running analysis: DominatorTreeAnalysis on test1_h
22; CHECK: Invalidating all non-preserved analyses for: (test1_h, test1_g)
23; CHECK: Invalidating all non-preserved analyses for: test1_h
24; CHECK: Invalidating analysis: DominatorTreeAnalysis on test1_h
25
26; An external function used to control branches.
27declare i1 @flag()
28; CHECK-LABEL: declare i1 @flag()
29
30; The utility function with interesting control flow that gets inlined below to
31; perturb the dominator tree.
32define internal void @callee() {
33entry:
34 %ptr = alloca i8
35 %flag = call i1 @flag()
36 br i1 %flag, label %then, label %else
37
38then:
39 store volatile i8 42, i8* %ptr
40 br label %return
41
42else:
43 store volatile i8 -42, i8* %ptr
44 br label %return
45
46return:
47 ret void
48}
49
50; The 'test1_' prefixed functions work to carefully test that incrementally
51; reducing an SCC in the inliner cannot accidentially leave stale function
52; analysis results due to failing to invalidate them for all the functions.
53
54; We visit this function first in the inliner, and while we inline callee
55; perturbing the CFG, we don't inline anything else and the SCC structure
56; remains in tact.
57define void @test1_f() {
58; CHECK-LABEL: define void @test1_f()
59entry:
60 ; We force this edge to survive inlining.
61 call void @test1_g() noinline
62; CHECK: call void @test1_g()
63
64 ; Pull interesting CFG into this function.
65 call void @callee()
66; CHECK-NOT: call void @callee()
67
68 ret void
69; CHECK: ret void
70}
71
72; Next we visit this function and here we inline the edge to 'test1_f'
73; separating it into its own SCC. The current SCC is now just 'test1_g' and
74; 'test1_h'.
75define void @test1_g() {
76; CHECK-LABEL: define void @test1_g()
77entry:
78 ; This edge gets inlined away.
79 call void @test1_f()
80; CHECK-NOT: call void @test1_f()
81; CHECK: call void @test1_g()
82
83 ; We force this edge to survive inlining.
84 call void @test1_h() noinline
85; CHECK: call void @test1_h()
86
87 ; Pull interesting CFG into this function.
88 call void @callee()
89; CHECK-NOT: call void @callee()
90
91 ret void
92; CHECK: ret void
93}
94
95; Finally the inliner visits this last function. It can't actually break any
96; cycles here, but because we visit this function we compute fresh analyses for
97; it. These analyses are then invalidated when we inline callee disrupting the
98; CFG, and it is important that they be freed.
99define void @test1_h() {
100; CHECK-LABEL: define void @test1_h()
101entry:
102 call void @test1_g()
103; CHECK: call void @test1_g()
104
105 ; Pull interesting CFG into this function.
106 call void @callee()
107; CHECK-NOT: call void @callee()
108
109 ret void
110; CHECK: ret void
111}