342 lines · plain
1; RUN: opt -aa-pipeline=basic-aa -passes='cgscc(function-attrs,function(simplifycfg))' -S < %s | FileCheck %s2 3declare void @readnone() nofree nosync readnone4declare void @unknown()5declare void @reference_function_pointer(ptr) nofree nosync readnone6 7; The @test1_* set of functions checks that when we mutate functions with8; simplifycfg to delete call edges and this ends up splitting both the SCCs9; and the RefSCCs that those functions are in, we re-run the CGSCC passes to10; observe the refined call graph structure.11 12; CHECK: define void @test1_a() {13define void @test1_a() {14 call void @test1_b1()15 call void @test1_b2()16 call void @test1_b3()17 call void @test1_b4()18 ret void19}20 21; CHECK: define void @test1_b1() #0 {22define void @test1_b1() {23 call void @readnone()24 ret void25}26 27; CHECK: define void @test1_b2() #0 {28define void @test1_b2() {29 call void @readnone()30 br i1 false, label %dead, label %exit31 32dead:33 call void @test1_a()34 br label %exit35 36exit:37 ret void38}39 40; CHECK: define void @test1_b3() {41define void @test1_b3() {42 call void @unknown()43 br i1 false, label %dead, label %exit44 45dead:46 call void @test1_a()47 br label %exit48 49exit:50 ret void51}52 53; CHECK: define void @test1_b4() #0 {54define void @test1_b4() {55 call void @readnone()56 br i1 false, label %dead, label %exit57 58dead:59 call void @test1_a()60 br label %exit61 62exit:63 ret void64}65 66 67; The @test2_* set of functions provide similar checks to @test1_* but only68; splitting the SCCs while leaving the RefSCC intact. This is accomplished by69; having dummy ref edges to the root function.70 71; CHECK: define void @test2_a() {72define void @test2_a() {73 call void @test2_b1()74 call void @test2_b2()75 call void @test2_b3()76 call void @test2_b4()77 ret void78}79 80; CHECK: define void @test2_b1() #0 {81define void @test2_b1() {82 call void @readnone()83 ret void84}85 86; CHECK: define void @test2_b2() #0 {87define void @test2_b2() {88 call void @reference_function_pointer(ptr @test2_a)89 br i1 false, label %dead, label %exit90 91dead:92 call void @test2_a()93 br label %exit94 95exit:96 ret void97}98 99; CHECK: define void @test2_b3() {100define void @test2_b3() {101 call void @reference_function_pointer(ptr @test2_a)102 call void @unknown()103 br i1 false, label %dead, label %exit104 105dead:106 call void @test2_a()107 br label %exit108 109exit:110 ret void111}112 113; CHECK: define void @test2_b4() #0 {114define void @test2_b4() {115 call void @reference_function_pointer(ptr @test2_a)116 br i1 false, label %dead, label %exit117 118dead:119 call void @test2_a()120 br label %exit121 122exit:123 ret void124}125 126 127; The @test3_* set of functions are the same challenge as @test1_* but with128; multiple layers that have to be traversed in the correct order instead of129; a single node.130 131; CHECK: define void @test3_a() {132define void @test3_a() {133 call void @test3_b11()134 call void @test3_b21()135 call void @test3_b31()136 call void @test3_b41()137 ret void138}139 140; CHECK: define void @test3_b11() #0 {141define void @test3_b11() {142 call void @test3_b12()143 ret void144}145 146; CHECK: define void @test3_b12() #0 {147define void @test3_b12() {148 call void @test3_b13()149 ret void150}151 152; CHECK: define void @test3_b13() #0 {153define void @test3_b13() {154 call void @readnone()155 ret void156}157 158; CHECK: define void @test3_b21() #0 {159define void @test3_b21() {160 call void @test3_b22()161 ret void162}163 164; CHECK: define void @test3_b22() #0 {165define void @test3_b22() {166 call void @test3_b23()167 ret void168}169 170; CHECK: define void @test3_b23() #0 {171define void @test3_b23() {172 call void @readnone()173 br i1 false, label %dead, label %exit174 175dead:176 call void @test3_a()177 br label %exit178 179exit:180 ret void181}182 183; CHECK: define void @test3_b31() {184define void @test3_b31() {185 call void @test3_b32()186 ret void187}188 189; CHECK: define void @test3_b32() {190define void @test3_b32() {191 call void @test3_b33()192 ret void193}194 195; CHECK: define void @test3_b33() {196define void @test3_b33() {197 call void @unknown()198 br i1 false, label %dead, label %exit199 200dead:201 call void @test3_a()202 br label %exit203 204exit:205 ret void206}207 208; CHECK: define void @test3_b41() #0 {209define void @test3_b41() {210 call void @test3_b42()211 ret void212}213 214; CHECK: define void @test3_b42() #0 {215define void @test3_b42() {216 call void @test3_b43()217 ret void218}219 220; CHECK: define void @test3_b43() #0 {221define void @test3_b43() {222 call void @readnone()223 br i1 false, label %dead, label %exit224 225dead:226 call void @test3_a()227 br label %exit228 229exit:230 ret void231}232 233 234; The @test4_* functions exercise the same core challenge as the @test2_*235; functions, but again include long chains instead of single nodes and ensure236; we traverse the chains in the correct order.237 238; CHECK: define void @test4_a() {239define void @test4_a() {240 call void @test4_b11()241 call void @test4_b21()242 call void @test4_b31()243 call void @test4_b41()244 ret void245}246 247; CHECK: define void @test4_b11() #0 {248define void @test4_b11() {249 call void @test4_b12()250 ret void251}252 253; CHECK: define void @test4_b12() #0 {254define void @test4_b12() {255 call void @test4_b13()256 ret void257}258 259; CHECK: define void @test4_b13() #0 {260define void @test4_b13() {261 call void @readnone()262 ret void263}264 265; CHECK: define void @test4_b21() #0 {266define void @test4_b21() {267 call void @test4_b22()268 ret void269}270 271; CHECK: define void @test4_b22() #0 {272define void @test4_b22() {273 call void @test4_b23()274 ret void275}276 277; CHECK: define void @test4_b23() #0 {278define void @test4_b23() {279 call void @reference_function_pointer(ptr @test4_a)280 br i1 false, label %dead, label %exit281 282dead:283 call void @test4_a()284 br label %exit285 286exit:287 ret void288}289 290; CHECK: define void @test4_b31() {291define void @test4_b31() {292 call void @test4_b32()293 ret void294}295 296; CHECK: define void @test4_b32() {297define void @test4_b32() {298 call void @test4_b33()299 ret void300}301 302; CHECK: define void @test4_b33() {303define void @test4_b33() {304 call void @reference_function_pointer(ptr @test4_a)305 call void @unknown()306 br i1 false, label %dead, label %exit307 308dead:309 call void @test4_a()310 br label %exit311 312exit:313 ret void314}315 316; CHECK: define void @test4_b41() #0 {317define void @test4_b41() {318 call void @test4_b42()319 ret void320}321 322; CHECK: define void @test4_b42() #0 {323define void @test4_b42() {324 call void @test4_b43()325 ret void326}327 328; CHECK: define void @test4_b43() #0 {329define void @test4_b43() {330 call void @reference_function_pointer(ptr @test4_a)331 br i1 false, label %dead, label %exit332 333dead:334 call void @test4_a()335 br label %exit336 337exit:338 ret void339}340 341; CHECK: attributes #0 = { nofree nosync memory(none) }342