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. 5 ; 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 8 ; 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 12 13 declare void @readnone() readnone 14 declare void @unknown() 15 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. 19 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 29 } 30 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 37 } 38 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 48 } 49 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 56 } 57 58 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. 62 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 70 } 71 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 80 } 81 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 92 } 93 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 104 } 105 106 ; CHECK: attributes #0 = { readnone } 107