[ThinLTO] Add code comment. NFC
[llvm-complete.git] / test / Other / cgscc-observe-devirt.ll
blob3b35f0edc1206a398b32275f399d930c4fde066b
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
27   call void %f()
28   ret void
31 ; BEFORE: define void @test1_b1() {
32 ; AFTER: define void @test1_b1() {
33 define void @test1_b1() {
34   call void @unknown()
35   call void @test1_a1()
36   ret void
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
46   call void %f()
47   ret void
50 ; BEFORE: define void @test1_b2() {
51 ; AFTER: define void @test1_b2() #0 {
52 define void @test1_b2() {
53   call void @readnone()
54   call void @test1_a2()
55   ret void
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() {
65   call void @test2_b1()
66   call void @test2_b2()
67   call void @test2_b3()
68   call void @unknown()
69   ret void
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
78   call void %f()
79   ret void
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
90   call void %f()
91   ret void
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
102   call void %f()
103   ret void
106 ; CHECK: attributes #0 = { readnone }