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 -aa-pipeline= -passes='cgscc(inline,function(verify<domtree>))' -debug-pass-manager -inline-deferral -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: 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 32 33; An external function used to control branches. 34declare i1 @flag() 35; CHECK-LABEL: declare i1 @flag() 36 37; The utility function with interesting control flow that gets inlined below to 38; perturb the dominator tree. 39define internal void @callee() { 40entry: 41 %ptr = alloca i8 42 %flag = call i1 @flag() 43 br i1 %flag, label %then, label %else 44 45then: 46 store volatile i8 42, ptr %ptr 47 br label %return 48 49else: 50 store volatile i8 -42, ptr %ptr 51 br label %return 52 53return: 54 ret void 55} 56 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. 60 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 63; remains in tact. 64define void @test1_f() { 65; CHECK-LABEL: define void @test1_f() 66entry: 67 ; We force this edge to survive inlining. 68 call void @test1_g() noinline 69; CHECK: call void @test1_g() 70 71 ; Pull interesting CFG into this function. 72 call void @callee() 73; CHECK-NOT: call void @callee() 74 75 ret void 76; CHECK: ret void 77} 78 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 81; 'test1_h'. 82define void @test1_g() { 83; CHECK-LABEL: define void @test1_g() 84entry: 85 ; This edge gets inlined away. 86 call void @test1_f() 87; CHECK-NOT: call void @test1_f() 88; CHECK: call void @test1_g() 89 90 ; We force this edge to survive inlining. 91 call void @test1_h() noinline 92; CHECK: call void @test1_h() 93 94 ; Pull interesting CFG into this function. 95 call void @callee() 96; CHECK-NOT: call void @callee() 97 98 ret void 99; CHECK: ret void 100} 101 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. 106define void @test1_h() { 107; CHECK-LABEL: define void @test1_h() 108entry: 109 call void @test1_g() 110; CHECK: call void @test1_g() 111 112 ; Pull interesting CFG into this function. 113 call void @callee() 114; CHECK-NOT: call void @callee() 115 116 ret void 117; CHECK: ret void 118} 119 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 124; dominator tree. 125 126@test2_global = external global i32, align 4 127 128define void @test2_hoge(ptr %arg) { 129; CHECK-LABEL: define void @test2_hoge( 130bb: 131 %tmp2 = call zeroext i1 %arg(ptr @test2_global) 132; CHECK: call zeroext i1 %arg( 133 br label %bb3 134 135bb3: 136 %tmp5 = call zeroext i1 %arg(ptr @test2_global) 137; CHECK: call zeroext i1 %arg( 138 br i1 %tmp5, label %bb3, label %bb6 139 140bb6: 141 ret void 142} 143 144define zeroext i1 @test2_widget(ptr %arg) { 145; CHECK-LABEL: define zeroext i1 @test2_widget( 146bb: 147 %tmp1 = alloca i8, align 1 148 %tmp2 = alloca i32, align 4 149 call void @test2_quux() 150; CHECK-NOT: call 151; 152; CHECK: call zeroext i1 @test2_widget(ptr @test2_global) 153; CHECK-NEXT: br label %[[NEW_BB:.*]] 154; 155; CHECK: [[NEW_BB]]: 156; CHECK-NEXT: call zeroext i1 @test2_widget(ptr @test2_global) 157; 158; CHECK: {{.*}}: 159 160 call void @test2_hoge.1(ptr %arg) 161; CHECK-NEXT: call void @test2_hoge.1( 162 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( 169 170 call void @test2_quux() 171; CHECK-NOT: call 172; 173; CHECK: call zeroext i1 @test2_widget(ptr @test2_global) 174; CHECK-NEXT: br label %[[NEW_BB:.*]] 175; 176; CHECK: [[NEW_BB]]: 177; CHECK-NEXT: call zeroext i1 @test2_widget(ptr @test2_global) 178; 179; CHECK: {{.*}}: 180 ret i1 true 181; CHECK-NEXT: ret i1 true 182} 183 184define internal void @test2_quux() { 185; CHECK-NOT: @test2_quux 186bb: 187 call void @test2_hoge(ptr @test2_widget) 188 ret void 189} 190 191declare void @test2_hoge.1(ptr) 192 193declare zeroext i1 @test2_barney(ptr) 194 195declare void @test2_ham(ptr) 196