1 ; The CGSCC pass manager includes an SCC iteration utility that tracks indirect 2 ; calls that are turned into direct calls (devirtualization) and re-visits the 3 ; SCC to expose those calls to the SCC-based IPO passes. We trigger 4 ; devirtualization here with GVN which forwards a store through a load and to 5 ; an indirect call. 6 ; 7 ; RUN: opt -aa-pipeline=basic-aa -passes='cgscc(function-attrs,function(gvn,instcombine))' -S < %s | FileCheck %s --check-prefix=CHECK --check-prefix=BEFORE 8 ; RUN: opt -aa-pipeline=basic-aa -passes='cgscc(devirt<1>(function-attrs,function(gvn,instcombine)))' -S < %s | FileCheck %s --check-prefix=CHECK --check-prefix=AFTER --check-prefix=AFTER1 9 ; RUN: opt -aa-pipeline=basic-aa -passes='cgscc(devirt<2>(function-attrs,function(gvn,instcombine)))' -S < %s | FileCheck %s --check-prefix=CHECK --check-prefix=AFTER --check-prefix=AFTER2 10 ; 11 ; We also verify that the real O2 pipeline catches these cases. 12 ; RUN: opt -aa-pipeline=basic-aa -passes='default<O2>' -S < %s | FileCheck %s --check-prefix=CHECK --check-prefix=AFTER --check-prefix=AFTER2 13 14 declare void @readnone() readnone 15 ; CHECK: Function Attrs: readnone 16 ; CHECK-NEXT: declare void @readnone() 17 18 declare void @unknown() 19 ; CHECK-NOT: Function Attrs 20 ; CHECK-LABEL: declare void @unknown(){{ *$}} 21 22 ; The @test1 function checks that when we refine an indirect call to a direct 23 ; call we revisit the SCC passes to reflect the more precise information. This 24 ; is the basic functionality. 25 26 define void @test1() { 27 ; BEFORE-NOT: Function Attrs 28 ; AFTER: Function Attrs: readnone 29 ; CHECK-LABEL: define void @test1() 30 entry: 31 %fptr = alloca void ()* 32 store void ()* @readnone, void ()** %fptr 33 %f = load void ()*, void ()** %fptr 34 call void %f() 35 ret void 36 } 37 38 ; The @test2_* functions check that when we need multiple (in this case 2) 39 ; repetitions to compute some state that is incrementally exposed with each 40 ; one, the limit on repetitions is enforced. So we make progress with 41 ; one repetition but not as much as with three. 42 ; 43 ; This is somewhat awkward to test because we have to contrive to have a state 44 ; repetition triggered and observed with very few passes. The technique here 45 ; is to have one indirect call that can only be resolved when the entire SCC is 46 ; deduced as readonly, and mark that indirect call at the call site as readonly 47 ; to make that possible. This forces us to first deduce readonly, then 48 ; devirtualize again, and then deduce readnone. 49 50 declare void @readnone_with_arg(void ()**) readnone 51 ; CHECK: Function Attrs: readnone 52 ; CHECK-LABEL: declare void @readnone_with_arg(void ()**) 53 54 define void @test2_a(void ()** %ignore) { 55 ; BEFORE-NOT: Function Attrs 56 ; AFTER1: Function Attrs: readonly 57 ; AFTER2: Function Attrs: readnone 58 ; BEFORE: define void @test2_a(void ()** %ignore) 59 ; AFTER: define void @test2_a(void ()** readnone %ignore) 60 entry: 61 %f1ptr = alloca void (void ()**)* 62 store void (void ()**)* @readnone_with_arg, void (void ()**)** %f1ptr 63 %f1 = load void (void ()**)*, void (void ()**)** %f1ptr 64 ; This indirect call is the first to be resolved, allowing us to deduce 65 ; readonly but not (yet) readnone. 66 call void %f1(void ()** %ignore) 67 ; CHECK: call void @readnone_with_arg(void ()** %ignore) 68 69 ; Bogus call to test2_b to make this a cycle. 70 call void @test2_b() 71 72 ret void 73 } 74 75 define void @test2_b() { 76 ; BEFORE-NOT: Function Attrs 77 ; AFTER1: Function Attrs: readonly 78 ; AFTER2: Function Attrs: readnone 79 ; CHECK-LABEL: define void @test2_b() 80 entry: 81 %f2ptr = alloca void ()* 82 store void ()* @readnone, void ()** %f2ptr 83 ; Call the other function here to prevent forwarding until the SCC has had 84 ; function attrs deduced. 85 call void @test2_a(void ()** %f2ptr) 86 87 %f2 = load void ()*, void ()** %f2ptr 88 ; This is the second indirect call to be resolved, and can only be resolved 89 ; after we deduce 'readonly' for the rest of the SCC. Once it is 90 ; devirtualized, we can deduce readnone for the SCC. 91 call void %f2() readonly 92 ; BEFORE: call void %f2() 93 ; AFTER: call void @readnone() 94 95 ret void 96 } 97 98 declare i8* @memcpy(i8*, i8*, i64) 99 ; CHECK-LABEL: declare i8* @memcpy( 100 101 ; The @test3 function checks that when we refine an indirect call to an 102 ; intrinsic we still revisit the SCC pass. This also covers cases where the 103 ; value handle itself doesn't persist due to the nature of how instcombine 104 ; creates the memcpy intrinsic call, and we rely on the count of indirect calls 105 ; decreasing and the count of direct calls increasing. 106 ; Adding 'noinline' attribute to force attributes for improved matching. 107 define void @test3(i8* %src, i8* %dest, i64 %size) noinline { 108 ; CHECK: Function Attrs 109 ; CHECK-NOT: read 110 ; CHECK-SAME: noinline 111 ; BEFORE-LABEL: define void @test3(i8* %src, i8* %dest, i64 %size) 112 ; AFTER-LABEL: define void @test3(i8* nocapture readonly %src, i8* nocapture %dest, i64 %size) 113 %fptr = alloca i8* (i8*, i8*, i64)* 114 store i8* (i8*, i8*, i64)* @memcpy, i8* (i8*, i8*, i64)** %fptr 115 %f = load i8* (i8*, i8*, i64)*, i8* (i8*, i8*, i64)** %fptr 116 call i8* %f(i8* %dest, i8* %src, i64 %size) 117 ; CHECK: call void @llvm.memcpy 118 ret void 119 } 120 121 ; A boring function that just keeps our declarations around. 122 define void @keep(i8** %sink) { 123 ; CHECK-NOT: Function Attrs 124 ; CHECK-LABEL: define void @keep( 125 entry: 126 store volatile i8* bitcast (void ()* @readnone to i8*), i8** %sink 127 store volatile i8* bitcast (void ()* @unknown to i8*), i8** %sink 128 store volatile i8* bitcast (i8* (i8*, i8*, i64)* @memcpy to i8*), i8** %sink 129 call void @unknown() 130 ret void 131 } 132