1 ; Test for a subtle bug when computing analyses during inlining and mutating
2 ; the SCC structure. Without care, this can fail to invalidate analyses.
4 ; RUN: opt < %s -aa-pipeline= -passes='cgscc(inline,function(verify<domtree>))' -debug-pass-manager -inline-deferral -S 2>&1 | FileCheck %s
6 ; First we check that the passes run in the way we expect. Otherwise this test
7 ; may stop testing anything.
9 ; CHECK: Running pass: InlinerPass on (test1_f, test1_g, test1_h)
10 ; CHECK: Running analysis: DominatorTreeAnalysis on test1_f
11 ; CHECK: Invalidating analysis: DominatorTreeAnalysis on test1_f
12 ; CHECK: Invalidating analysis: LoopAnalysis on test1_f
13 ; CHECK: Invalidating analysis: BranchProbabilityAnalysis on test1_f
14 ; CHECK: Invalidating analysis: BlockFrequencyAnalysis on test1_f
15 ; CHECK: Running analysis: DominatorTreeAnalysis on test1_g
16 ; CHECK: Invalidating analysis: DominatorTreeAnalysis on test1_g
17 ; CHECK: Invalidating analysis: LoopAnalysis on test1_g
18 ; CHECK: Invalidating analysis: BranchProbabilityAnalysis on test1_g
19 ; CHECK: Invalidating analysis: BlockFrequencyAnalysis on test1_g
20 ; CHECK: Invalidating analysis: DominatorTreeAnalysis on test1_h
21 ; CHECK: Invalidating analysis: LoopAnalysis on test1_h
22 ; CHECK: Invalidating analysis: BranchProbabilityAnalysis on test1_h
23 ; CHECK: Invalidating analysis: BlockFrequencyAnalysis on test1_h
24 ; CHECK-NOT: Invalidating analysis:
25 ; CHECK: Running pass: DominatorTreeVerifierPass on test1_g
26 ; CHECK-NEXT: Running analysis: DominatorTreeAnalysis on test1_g
27 ; CHECK-NOT: Invalidating analysis:
28 ; CHECK: Running pass: DominatorTreeVerifierPass on test1_h
29 ; CHECK-NEXT: Running analysis: DominatorTreeAnalysis on test1_h
30 ; CHECK-NOT: Invalidating analysis:
31 ; CHECK: Running pass: DominatorTreeVerifierPass on test1_f
33 ; An external function used to control branches.
35 ; CHECK-LABEL: declare i1 @flag()
37 ; The utility function with interesting control flow that gets inlined below to
38 ; perturb the dominator tree.
39 define internal void @callee() {
42 %flag = call i1 @flag()
43 br i1 %flag, label %then, label %else
46 store volatile i8 42, ptr %ptr
50 store volatile i8 -42, ptr %ptr
57 ; The 'test1_' prefixed functions work to carefully test that incrementally
58 ; reducing an SCC in the inliner cannot accidentially leave stale function
59 ; analysis results due to failing to invalidate them for all the functions.
61 ; We visit this function first in the inliner, and while we inline callee
62 ; perturbing the CFG, we don't inline anything else and the SCC structure
64 define void @test1_f() {
65 ; CHECK-LABEL: define void @test1_f()
67 ; We force this edge to survive inlining.
68 call void @test1_g() noinline
69 ; CHECK: call void @test1_g()
71 ; Pull interesting CFG into this function.
73 ; CHECK-NOT: call void @callee()
79 ; We visit this function second and here we inline the edge to 'test1_f'
80 ; separating it into its own SCC. The current SCC is now just 'test1_g' and
82 define void @test1_g() {
83 ; CHECK-LABEL: define void @test1_g()
85 ; This edge gets inlined away.
87 ; CHECK-NOT: call void @test1_f()
88 ; CHECK: call void @test1_g()
90 ; We force this edge to survive inlining.
91 call void @test1_h() noinline
92 ; CHECK: call void @test1_h()
94 ; Pull interesting CFG into this function.
96 ; CHECK-NOT: call void @callee()
102 ; The inliner visits this last function. It can't actually break any cycles
103 ; here, but because we visit this function we compute fresh analyses for it.
104 ; These analyses are then invalidated when we inline callee disrupting the
105 ; CFG, and it is important that they be freed.
106 define void @test1_h() {
107 ; CHECK-LABEL: define void @test1_h()
110 ; CHECK: call void @test1_g()
112 ; Pull interesting CFG into this function.
114 ; CHECK-NOT: call void @callee()
120 ; The 'test2_' prefixed code works to carefully trigger forming an SCC with
121 ; a dominator tree for one of the functions but not the other and without even
122 ; a function analysis manager proxy for the SCC that things get merged into.
123 ; Without proper handling when updating the call graph this will find a stale
126 @test2_global = external global i32, align 4
128 define void @test2_hoge(ptr %arg) {
129 ; CHECK-LABEL: define void @test2_hoge(
131 %tmp2 = call zeroext i1 %arg(ptr @test2_global)
132 ; CHECK: call zeroext i1 %arg(
136 %tmp5 = call zeroext i1 %arg(ptr @test2_global)
137 ; CHECK: call zeroext i1 %arg(
138 br i1 %tmp5, label %bb3, label %bb6
144 define zeroext i1 @test2_widget(ptr %arg) {
145 ; CHECK-LABEL: define zeroext i1 @test2_widget(
147 %tmp1 = alloca i8, align 1
148 %tmp2 = alloca i32, align 4
149 call void @test2_quux()
152 ; CHECK: call zeroext i1 @test2_widget(ptr @test2_global)
153 ; CHECK-NEXT: br label %[[NEW_BB:.*]]
156 ; CHECK-NEXT: call zeroext i1 @test2_widget(ptr @test2_global)
160 call void @test2_hoge.1(ptr %arg)
161 ; CHECK-NEXT: call void @test2_hoge.1(
163 %tmp4 = call zeroext i1 @test2_barney(ptr %tmp2)
164 %tmp5 = zext i1 %tmp4 to i32
165 store i32 %tmp5, ptr %tmp2, align 4
166 %tmp6 = call zeroext i1 @test2_barney(ptr null)
167 call void @test2_ham(ptr %tmp1)
168 ; CHECK: call void @test2_ham(
170 call void @test2_quux()
173 ; CHECK: call zeroext i1 @test2_widget(ptr @test2_global)
174 ; CHECK-NEXT: br label %[[NEW_BB:.*]]
177 ; CHECK-NEXT: call zeroext i1 @test2_widget(ptr @test2_global)
181 ; CHECK-NEXT: ret i1 true
184 define internal void @test2_quux() {
185 ; CHECK-NOT: @test2_quux
187 call void @test2_hoge(ptr @test2_widget)
191 declare void @test2_hoge.1(ptr)
193 declare zeroext i1 @test2_barney(ptr)
195 declare void @test2_ham(ptr)