107 lines · plain
1; Make sure that even without some external devirtualization iteration tool,2; the CGSCC pass manager correctly observes and re-visits SCCs that change3; structure due to devirtualization. We trigger devirtualization here with GVN4; which forwards a store through a load and to an indirect call.5;6; RUN: opt -aa-pipeline=basic-aa -passes='cgscc(function-attrs)' -S < %s | FileCheck %s --check-prefix=BEFORE7; RUN: opt -aa-pipeline=basic-aa -passes='cgscc(function-attrs,function(gvn))' -S < %s | FileCheck %s --check-prefix=AFTER8;9; Also check that adding an extra CGSCC pass after the function update but10; without requiring the outer manager to iterate doesn't break any invariant.11; RUN: opt -aa-pipeline=basic-aa -passes='cgscc(function-attrs,function(gvn),function-attrs)' -S < %s | FileCheck %s --check-prefix=AFTER12 13declare void @readnone() nofree nosync readnone14declare void @unknown()15 16; The @test1_* checks that if we refine an indirect call to a direct call and17; in the process change the very structure of the call graph we also revisit18; that component of the graph and do so in an up-to-date fashion.19 20; BEFORE: define void @test1_a1() {21; AFTER: define void @test1_a1() {22define void @test1_a1() {23 %fptr = alloca ptr24 store ptr @test1_b2, ptr %fptr25 store ptr @test1_b1, ptr %fptr26 %f = load ptr, ptr %fptr27 call void %f()28 ret void29}30 31; BEFORE: define void @test1_b1() {32; AFTER: define void @test1_b1() {33define void @test1_b1() {34 call void @unknown()35 call void @test1_a1()36 ret void37}38 39; BEFORE: define void @test1_a2() {40; AFTER: define void @test1_a2() #0 {41define void @test1_a2() {42 %fptr = alloca ptr43 store ptr @test1_b1, ptr %fptr44 store ptr @test1_b2, ptr %fptr45 %f = load ptr, ptr %fptr46 call void %f()47 ret void48}49 50; BEFORE: define void @test1_b2() {51; AFTER: define void @test1_b2() #0 {52define void @test1_b2() {53 call void @readnone()54 call void @test1_a2()55 ret void56}57 58 59; The @test2_* set of functions exercise a case where running function passes60; introduces a new post-order relationship that was not present originally and61; makes sure we walk across the SCCs in that order.62 63; CHECK: define void @test2_a() {64define void @test2_a() {65 call void @test2_b1()66 call void @test2_b2()67 call void @test2_b3()68 call void @unknown()69 ret void70}71 72; CHECK: define void @test2_b1() #0 {73define void @test2_b1() {74 %fptr = alloca ptr75 store ptr @test2_a, ptr %fptr76 store ptr @readnone, ptr %fptr77 %f = load ptr, ptr %fptr78 call void %f()79 ret void80}81 82; CHECK: define void @test2_b2() #0 {83define void @test2_b2() {84 %fptr = alloca ptr85 store ptr @test2_a, ptr %fptr86 store ptr @test2_b2, ptr %fptr87 store ptr @test2_b3, ptr %fptr88 store ptr @test2_b1, ptr %fptr89 %f = load ptr, ptr %fptr90 call void %f()91 ret void92}93 94; CHECK: define void @test2_b3() #0 {95define void @test2_b3() {96 %fptr = alloca ptr97 store ptr @test2_a, ptr %fptr98 store ptr @test2_b2, ptr %fptr99 store ptr @test2_b3, ptr %fptr100 store ptr @test2_b1, ptr %fptr101 %f = load ptr, ptr %fptr102 call void %f()103 ret void104}105 106; CHECK: attributes #0 = { nofree nosync readnone }107