1 ; Make sure that even without some external devirtualization iteration tool,
2 ; the CGSCC pass manager correctly observes and re-visits SCCs that change
3 ; structure due to devirtualization. We trigger devirtualization here with GVN
4 ; which forwards a store through a load and to an indirect call.
6 ; RUN: opt -aa-pipeline=basic-aa -passes='cgscc(function-attrs)' -S < %s | FileCheck %s --check-prefix=BEFORE
7 ; RUN: opt -aa-pipeline=basic-aa -passes='cgscc(function-attrs,function(gvn))' -S < %s | FileCheck %s --check-prefix=AFTER
9 ; Also check that adding an extra CGSCC pass after the function update but
10 ; 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=AFTER
13 declare void @readnone() readnone
14 declare void @unknown()
16 ; The @test1_* checks that if we refine an indirect call to a direct call and
17 ; in the process change the very structure of the call graph we also revisit
18 ; that component of the graph and do so in an up-to-date fashion.
20 ; BEFORE: define void @test1_a1() {
21 ; AFTER: define void @test1_a1() {
22 define void @test1_a1() {
23 %fptr = alloca void()*
24 store void()* @test1_b2, void()** %fptr
25 store void()* @test1_b1, void()** %fptr
26 %f = load void()*, void()** %fptr
31 ; BEFORE: define void @test1_b1() {
32 ; AFTER: define void @test1_b1() {
33 define void @test1_b1() {
39 ; BEFORE: define void @test1_a2() {
40 ; AFTER: define void @test1_a2() #0 {
41 define void @test1_a2() {
42 %fptr = alloca void()*
43 store void()* @test1_b1, void()** %fptr
44 store void()* @test1_b2, void()** %fptr
45 %f = load void()*, void()** %fptr
50 ; BEFORE: define void @test1_b2() {
51 ; AFTER: define void @test1_b2() #0 {
52 define void @test1_b2() {
59 ; The @test2_* set of functions exercise a case where running function passes
60 ; introduces a new post-order relationship that was not present originally and
61 ; makes sure we walk across the SCCs in that order.
63 ; CHECK: define void @test2_a() {
64 define void @test2_a() {
72 ; CHECK: define void @test2_b1() #0 {
73 define void @test2_b1() {
74 %fptr = alloca void()*
75 store void()* @test2_a, void()** %fptr
76 store void()* @readnone, void()** %fptr
77 %f = load void()*, void()** %fptr
82 ; CHECK: define void @test2_b2() #0 {
83 define void @test2_b2() {
84 %fptr = alloca void()*
85 store void()* @test2_a, void()** %fptr
86 store void()* @test2_b2, void()** %fptr
87 store void()* @test2_b3, void()** %fptr
88 store void()* @test2_b1, void()** %fptr
89 %f = load void()*, void()** %fptr
94 ; CHECK: define void @test2_b3() #0 {
95 define void @test2_b3() {
96 %fptr = alloca void()*
97 store void()* @test2_a, void()** %fptr
98 store void()* @test2_b2, void()** %fptr
99 store void()* @test2_b3, void()** %fptr
100 store void()* @test2_b1, void()** %fptr
101 %f = load void()*, void()** %fptr
106 ; CHECK: attributes #0 = { readnone }