brintos

brintos / llvm-project-archived public Read only

0
0
Text · 6.1 KiB · bc31bca Raw
199 lines · plain
1; Test for a subtle bug when computing analyses during inlining and mutating2; 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 %s5 6; First we check that the passes run in the way we expect. Otherwise this test7; may stop testing anything.8;9; CHECK: Running pass: InlinerPass on (test1_f, test1_g, test1_h)10; CHECK: Running analysis: DominatorTreeAnalysis on test1_f11; CHECK: Invalidating analysis: DominatorTreeAnalysis on test1_f12; CHECK: Invalidating analysis: LoopAnalysis on test1_f13; CHECK: Invalidating analysis: BranchProbabilityAnalysis on test1_f14; CHECK: Invalidating analysis: BlockFrequencyAnalysis on test1_f15; CHECK: Invalidating analysis: EphemeralValuesAnalysis on test1_f16; CHECK: Running analysis: DominatorTreeAnalysis on test1_g17; CHECK: Invalidating analysis: DominatorTreeAnalysis on test1_g18; CHECK: Invalidating analysis: LoopAnalysis on test1_g19; CHECK: Invalidating analysis: BranchProbabilityAnalysis on test1_g20; CHECK: Invalidating analysis: BlockFrequencyAnalysis on test1_g21; CHECK: Invalidating analysis: EphemeralValuesAnalysis on test1_g22; CHECK: Invalidating analysis: DominatorTreeAnalysis on test1_h23; CHECK: Invalidating analysis: LoopAnalysis on test1_h24; CHECK: Invalidating analysis: BranchProbabilityAnalysis on test1_h25; CHECK: Invalidating analysis: BlockFrequencyAnalysis on test1_h26; CHECK: Invalidating analysis: EphemeralValuesAnalysis on test1_h27; CHECK-NOT: Invalidating analysis:28; CHECK: Running pass: DominatorTreeVerifierPass on test1_g29; CHECK-NEXT: Running analysis: DominatorTreeAnalysis on test1_g30; CHECK-NOT: Invalidating analysis:31; CHECK: Running pass: DominatorTreeVerifierPass on test1_h32; CHECK-NEXT: Running analysis: DominatorTreeAnalysis on test1_h33; CHECK-NOT: Invalidating analysis:34; CHECK: Running pass: DominatorTreeVerifierPass on test1_f35 36; An external function used to control branches.37declare i1 @flag()38; CHECK-LABEL: declare i1 @flag()39 40; The utility function with interesting control flow that gets inlined below to41; perturb the dominator tree.42define internal void @callee() {43entry:44  %ptr = alloca i845  %flag = call i1 @flag()46  br i1 %flag, label %then, label %else47 48then:49  store volatile i8 42, ptr %ptr50  br label %return51 52else:53  store volatile i8 -42, ptr %ptr54  br label %return55 56return:57  ret void58}59 60; The 'test1_' prefixed functions work to carefully test that incrementally61; reducing an SCC in the inliner cannot accidentially leave stale function62; analysis results due to failing to invalidate them for all the functions.63 64; We visit this function first in the inliner, and while we inline callee65; perturbing the CFG, we don't inline anything else and the SCC structure66; remains in tact.67define void @test1_f() {68; CHECK-LABEL: define void @test1_f()69entry:70  ; We force this edge to survive inlining.71  call void @test1_g() noinline72; CHECK: call void @test1_g()73 74  ; Pull interesting CFG into this function.75  call void @callee()76; CHECK-NOT: call void @callee()77 78  ret void79; CHECK: ret void80}81 82; We visit this function second and here we inline the edge to 'test1_f'83; separating it into its own SCC. The current SCC is now just 'test1_g' and84; 'test1_h'.85define void @test1_g() {86; CHECK-LABEL: define void @test1_g()87entry:88  ; This edge gets inlined away.89  call void @test1_f()90; CHECK-NOT: call void @test1_f()91; CHECK: call void @test1_g()92 93  ; We force this edge to survive inlining.94  call void @test1_h() noinline95; CHECK: call void @test1_h()96 97  ; Pull interesting CFG into this function.98  call void @callee()99; CHECK-NOT: call void @callee()100 101  ret void102; CHECK: ret void103}104 105; The inliner visits this last function. It can't actually break any cycles106; here, but because we visit this function we compute fresh analyses for it.107; These analyses are then invalidated when we inline callee disrupting the108; CFG, and it is important that they be freed.109define void @test1_h() {110; CHECK-LABEL: define void @test1_h()111entry:112  call void @test1_g()113; CHECK: call void @test1_g()114 115  ; Pull interesting CFG into this function.116  call void @callee()117; CHECK-NOT: call void @callee()118 119  ret void120; CHECK: ret void121}122 123; The 'test2_' prefixed code works to carefully trigger forming an SCC with124; a dominator tree for one of the functions but not the other and without even125; a function analysis manager proxy for the SCC that things get merged into.126; Without proper handling when updating the call graph this will find a stale127; dominator tree.128 129@test2_global = external global i32, align 4130 131define void @test2_hoge(ptr %arg) {132; CHECK-LABEL: define void @test2_hoge(133bb:134  %tmp2 = call zeroext i1 %arg(ptr @test2_global)135; CHECK: call zeroext i1 %arg(136  br label %bb3137 138bb3:139  %tmp5 = call zeroext i1 %arg(ptr @test2_global)140; CHECK: call zeroext i1 %arg(141  br i1 %tmp5, label %bb3, label %bb6142 143bb6:144  ret void145}146 147define zeroext i1 @test2_widget(ptr %arg) {148; CHECK-LABEL: define zeroext i1 @test2_widget(149bb:150  %tmp1 = alloca i8, align 1151  %tmp2 = alloca i32, align 4152  call void @test2_quux()153; CHECK-NOT:     call154;155; CHECK:         call zeroext i1 @test2_widget(ptr @test2_global)156; CHECK-NEXT:    br label %[[NEW_BB:.*]]157;158; CHECK:       [[NEW_BB]]:159; CHECK-NEXT:    call zeroext i1 @test2_widget(ptr @test2_global)160;161; CHECK:       {{.*}}:162 163  call void @test2_hoge.1(ptr %arg)164; CHECK-NEXT:    call void @test2_hoge.1(165 166  %tmp4 = call zeroext i1 @test2_barney(ptr %tmp2)167  %tmp5 = zext i1 %tmp4 to i32168  store i32 %tmp5, ptr %tmp2, align 4169  %tmp6 = call zeroext i1 @test2_barney(ptr null)170  call void @test2_ham(ptr %tmp1)171; CHECK:         call void @test2_ham(172 173  call void @test2_quux()174; CHECK-NOT:     call175;176; CHECK:         call zeroext i1 @test2_widget(ptr @test2_global)177; CHECK-NEXT:    br label %[[NEW_BB:.*]]178;179; CHECK:       [[NEW_BB]]:180; CHECK-NEXT:    call zeroext i1 @test2_widget(ptr @test2_global)181;182; CHECK:       {{.*}}:183  ret i1 true184; CHECK-NEXT:    ret i1 true185}186 187define internal void @test2_quux() {188; CHECK-NOT: @test2_quux189bb:190  call void @test2_hoge(ptr @test2_widget)191  ret void192}193 194declare void @test2_hoge.1(ptr)195 196declare zeroext i1 @test2_barney(ptr)197 198declare void @test2_ham(ptr)199