Chandler Carruth | b698d59 | 2017-01-22 10:34:01 +0000 | [diff] [blame] | 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. |
| 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. |
Chandler Carruth | 20e588e | 2017-03-09 11:35:40 +0000 | [diff] [blame] | 10 | ; CHECK: Running pass: InlinerPass on (test1_f, test1_g, test1_h) |
| 11 | ; CHECK: Running analysis: FunctionAnalysisManagerCGSCCProxy on (test1_f, test1_g, test1_h) |
Chandler Carruth | b698d59 | 2017-01-22 10:34:01 +0000 | [diff] [blame] | 12 | ; CHECK: Running analysis: DominatorTreeAnalysis on test1_f |
| 13 | ; CHECK: Running analysis: DominatorTreeAnalysis on test1_g |
Chandler Carruth | bd9c290 | 2017-07-09 03:59:31 +0000 | [diff] [blame] | 14 | ; CHECK: Invalidating all non-preserved analyses for: (test1_f) |
Chandler Carruth | b698d59 | 2017-01-22 10:34:01 +0000 | [diff] [blame] | 15 | ; CHECK: Invalidating all non-preserved analyses for: test1_f |
| 16 | ; CHECK: Invalidating analysis: DominatorTreeAnalysis on test1_f |
Chandler Carruth | bd9c290 | 2017-07-09 03:59:31 +0000 | [diff] [blame] | 17 | ; CHECK: Invalidating analysis: LoopAnalysis on test1_f |
| 18 | ; CHECK: Invalidating analysis: BranchProbabilityAnalysis on test1_f |
| 19 | ; CHECK: Invalidating analysis: BlockFrequencyAnalysis on test1_f |
| 20 | ; CHECK: Invalidating all non-preserved analyses for: (test1_g, test1_h) |
Chandler Carruth | 20e588e | 2017-03-09 11:35:40 +0000 | [diff] [blame] | 21 | ; CHECK: Invalidating all non-preserved analyses for: test1_g |
| 22 | ; CHECK: Invalidating analysis: DominatorTreeAnalysis on test1_g |
Chandler Carruth | bd9c290 | 2017-07-09 03:59:31 +0000 | [diff] [blame] | 23 | ; CHECK: Invalidating analysis: LoopAnalysis on test1_g |
| 24 | ; CHECK: Invalidating analysis: BranchProbabilityAnalysis on test1_g |
| 25 | ; CHECK: Invalidating analysis: BlockFrequencyAnalysis on test1_g |
Chandler Carruth | b698d59 | 2017-01-22 10:34:01 +0000 | [diff] [blame] | 26 | ; CHECK: Invalidating all non-preserved analyses for: test1_h |
| 27 | ; CHECK: Invalidating analysis: DominatorTreeAnalysis on test1_h |
Chandler Carruth | bd9c290 | 2017-07-09 03:59:31 +0000 | [diff] [blame] | 28 | ; CHECK: Invalidating analysis: LoopAnalysis on test1_h |
| 29 | ; CHECK: Invalidating analysis: BranchProbabilityAnalysis on test1_h |
| 30 | ; CHECK: Invalidating analysis: BlockFrequencyAnalysis on test1_h |
| 31 | ; CHECK-NOT: Invalidating analysis: |
| 32 | ; CHECK: Starting llvm::Function pass manager run. |
| 33 | ; CHECK-NEXT: Running pass: DominatorTreeVerifierPass on test1_g |
| 34 | ; CHECK-NEXT: Running analysis: DominatorTreeAnalysis on test1_g |
| 35 | ; CHECK-NEXT: Finished llvm::Function pass manager run. |
| 36 | ; CHECK-NEXT: Starting llvm::Function pass manager run. |
| 37 | ; CHECK-NEXT: Running pass: DominatorTreeVerifierPass on test1_h |
| 38 | ; CHECK-NEXT: Running analysis: DominatorTreeAnalysis on test1_h |
| 39 | ; CHECK-NEXT: Finished llvm::Function pass manager run. |
| 40 | ; CHECK-NOT: Invalidating analysis: |
| 41 | ; CHECK: Running pass: DominatorTreeVerifierPass on test1_f |
| 42 | ; CHECK-NEXT: Running analysis: DominatorTreeAnalysis on test1_f |
Chandler Carruth | b698d59 | 2017-01-22 10:34:01 +0000 | [diff] [blame] | 43 | |
| 44 | ; An external function used to control branches. |
| 45 | declare i1 @flag() |
| 46 | ; CHECK-LABEL: declare i1 @flag() |
| 47 | |
| 48 | ; The utility function with interesting control flow that gets inlined below to |
| 49 | ; perturb the dominator tree. |
| 50 | define internal void @callee() { |
| 51 | entry: |
| 52 | %ptr = alloca i8 |
| 53 | %flag = call i1 @flag() |
| 54 | br i1 %flag, label %then, label %else |
| 55 | |
| 56 | then: |
| 57 | store volatile i8 42, i8* %ptr |
| 58 | br label %return |
| 59 | |
| 60 | else: |
| 61 | store volatile i8 -42, i8* %ptr |
| 62 | br label %return |
| 63 | |
| 64 | return: |
| 65 | ret void |
| 66 | } |
| 67 | |
| 68 | ; The 'test1_' prefixed functions work to carefully test that incrementally |
| 69 | ; reducing an SCC in the inliner cannot accidentially leave stale function |
| 70 | ; analysis results due to failing to invalidate them for all the functions. |
| 71 | |
Chandler Carruth | 20e588e | 2017-03-09 11:35:40 +0000 | [diff] [blame] | 72 | ; The inliner visits this last function. It can't actually break any cycles |
| 73 | ; here, but because we visit this function we compute fresh analyses for it. |
| 74 | ; These analyses are then invalidated when we inline callee disrupting the |
| 75 | ; CFG, and it is important that they be freed. |
| 76 | define void @test1_h() { |
| 77 | ; CHECK-LABEL: define void @test1_h() |
Chandler Carruth | b698d59 | 2017-01-22 10:34:01 +0000 | [diff] [blame] | 78 | entry: |
Chandler Carruth | 20e588e | 2017-03-09 11:35:40 +0000 | [diff] [blame] | 79 | call void @test1_g() |
Chandler Carruth | b698d59 | 2017-01-22 10:34:01 +0000 | [diff] [blame] | 80 | ; CHECK: call void @test1_g() |
| 81 | |
| 82 | ; Pull interesting CFG into this function. |
| 83 | call void @callee() |
| 84 | ; CHECK-NOT: call void @callee() |
| 85 | |
| 86 | ret void |
| 87 | ; CHECK: ret void |
| 88 | } |
| 89 | |
Chandler Carruth | 20e588e | 2017-03-09 11:35:40 +0000 | [diff] [blame] | 90 | ; We visit this function second and here we inline the edge to 'test1_f' |
Chandler Carruth | b698d59 | 2017-01-22 10:34:01 +0000 | [diff] [blame] | 91 | ; separating it into its own SCC. The current SCC is now just 'test1_g' and |
| 92 | ; 'test1_h'. |
| 93 | define void @test1_g() { |
| 94 | ; CHECK-LABEL: define void @test1_g() |
| 95 | entry: |
| 96 | ; This edge gets inlined away. |
| 97 | call void @test1_f() |
| 98 | ; CHECK-NOT: call void @test1_f() |
| 99 | ; CHECK: call void @test1_g() |
| 100 | |
| 101 | ; We force this edge to survive inlining. |
| 102 | call void @test1_h() noinline |
| 103 | ; CHECK: call void @test1_h() |
| 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 | } |
| 112 | |
Chandler Carruth | 20e588e | 2017-03-09 11:35:40 +0000 | [diff] [blame] | 113 | ; We visit this function first in the inliner, and while we inline callee |
| 114 | ; perturbing the CFG, we don't inline anything else and the SCC structure |
| 115 | ; remains in tact. |
| 116 | define void @test1_f() { |
| 117 | ; CHECK-LABEL: define void @test1_f() |
Chandler Carruth | b698d59 | 2017-01-22 10:34:01 +0000 | [diff] [blame] | 118 | entry: |
Chandler Carruth | 20e588e | 2017-03-09 11:35:40 +0000 | [diff] [blame] | 119 | ; We force this edge to survive inlining. |
| 120 | call void @test1_g() noinline |
Chandler Carruth | b698d59 | 2017-01-22 10:34:01 +0000 | [diff] [blame] | 121 | ; CHECK: call void @test1_g() |
| 122 | |
| 123 | ; Pull interesting CFG into this function. |
| 124 | call void @callee() |
| 125 | ; CHECK-NOT: call void @callee() |
| 126 | |
| 127 | ret void |
| 128 | ; CHECK: ret void |
| 129 | } |
Chandler Carruth | c213c67 | 2017-07-09 13:45:11 +0000 | [diff] [blame] | 130 | |
| 131 | ; The 'test2_' prefixed code works to carefully trigger forming an SCC with |
| 132 | ; a dominator tree for one of the functions but not the other and without even |
| 133 | ; a function analysis manager proxy for the SCC that things get merged into. |
| 134 | ; Without proper handling when updating the call graph this will find a stale |
| 135 | ; dominator tree. |
| 136 | |
| 137 | @test2_global = external global i32, align 4 |
| 138 | |
| 139 | define void @test2_hoge(i1 (i32*)* %arg) { |
| 140 | ; CHECK-LABEL: define void @test2_hoge( |
| 141 | bb: |
| 142 | %tmp2 = call zeroext i1 %arg(i32* @test2_global) |
| 143 | ; CHECK: call zeroext i1 %arg( |
| 144 | br label %bb3 |
| 145 | |
| 146 | bb3: |
| 147 | %tmp5 = call zeroext i1 %arg(i32* @test2_global) |
| 148 | ; CHECK: call zeroext i1 %arg( |
| 149 | br i1 %tmp5, label %bb3, label %bb6 |
| 150 | |
| 151 | bb6: |
| 152 | ret void |
| 153 | } |
| 154 | |
| 155 | define zeroext i1 @test2_widget(i32* %arg) { |
| 156 | ; CHECK-LABEL: define zeroext i1 @test2_widget( |
| 157 | bb: |
| 158 | %tmp1 = alloca i8, align 1 |
| 159 | %tmp2 = alloca i32, align 4 |
| 160 | call void @test2_quux() |
| 161 | ; CHECK-NOT: call |
| 162 | ; |
| 163 | ; CHECK: call zeroext i1 @test2_widget(i32* @test2_global) |
| 164 | ; CHECK-NEXT: br label %[[NEW_BB:.*]] |
| 165 | ; |
| 166 | ; CHECK: [[NEW_BB]]: |
| 167 | ; CHECK-NEXT: call zeroext i1 @test2_widget(i32* @test2_global) |
| 168 | ; |
| 169 | ; CHECK: {{.*}}: |
| 170 | |
| 171 | call void @test2_hoge.1(i32* %arg) |
| 172 | ; CHECK-NEXT: call void @test2_hoge.1( |
| 173 | |
| 174 | %tmp4 = call zeroext i1 @test2_barney(i32* %tmp2) |
| 175 | %tmp5 = zext i1 %tmp4 to i32 |
| 176 | store i32 %tmp5, i32* %tmp2, align 4 |
| 177 | %tmp6 = call zeroext i1 @test2_barney(i32* null) |
| 178 | call void @test2_ham(i8* %tmp1) |
| 179 | ; CHECK: call void @test2_ham( |
| 180 | |
| 181 | call void @test2_quux() |
| 182 | ; CHECK-NOT: call |
| 183 | ; |
| 184 | ; CHECK: call zeroext i1 @test2_widget(i32* @test2_global) |
| 185 | ; CHECK-NEXT: br label %[[NEW_BB:.*]] |
| 186 | ; |
| 187 | ; CHECK: [[NEW_BB]]: |
| 188 | ; CHECK-NEXT: call zeroext i1 @test2_widget(i32* @test2_global) |
| 189 | ; |
| 190 | ; CHECK: {{.*}}: |
| 191 | ret i1 true |
| 192 | ; CHECK-NEXT: ret i1 true |
| 193 | } |
| 194 | |
| 195 | define internal void @test2_quux() { |
| 196 | ; CHECK-NOT: @test2_quux |
| 197 | bb: |
| 198 | call void @test2_hoge(i1 (i32*)* @test2_widget) |
| 199 | ret void |
| 200 | } |
| 201 | |
| 202 | declare void @test2_hoge.1(i32*) |
| 203 | |
| 204 | declare zeroext i1 @test2_barney(i32*) |
| 205 | |
| 206 | declare void @test2_ham(i8*) |