1; RUN: opt < %s -aa-pipeline=basic-aa -passes='cgscc(function-attrs,inline)' -S | FileCheck %s 2; This test runs the inliner and the function attribute deduction. It ensures 3; that when the inliner mutates the call graph it correctly updates the CGSCC 4; iteration so that we can compute refined function attributes. In this way it 5; is leveraging function attribute computation to observe correct call graph 6; updates. 7 8; Boring unknown external function call. 9; CHECK: declare void @unknown() 10declare void @unknown() 11 12; Sanity check: this should get annotated as readnone. 13; CHECK: Function Attrs: nounwind readnone 14; CHECK-NEXT: declare void @readnone() 15declare void @readnone() readnone nounwind 16 17; The 'test1_' prefixed functions are designed to trigger forming a new direct 18; call in the inlined body of the function. After that, we form a new SCC and 19; using that can deduce precise function attrs. 20 21; This function should no longer exist. 22; CHECK-NOT: @test1_f() 23define internal void @test1_f(void()* %p) { 24entry: 25 call void %p() 26 ret void 27} 28 29; This function should have had 'readnone' deduced for its SCC. 30; CHECK: Function Attrs: noinline nounwind readnone 31; CHECK-NEXT: define void @test1_g() 32define void @test1_g() noinline { 33entry: 34 call void @test1_f(void()* @test1_h) 35 ret void 36} 37 38; This function should have had 'readnone' deduced for its SCC. 39; CHECK: Function Attrs: noinline nounwind readnone 40; CHECK-NEXT: define void @test1_h() 41define void @test1_h() noinline { 42entry: 43 call void @test1_g() 44 call void @readnone() 45 ret void 46} 47 48 49; The 'test2_' prefixed functions are designed to trigger forming a new direct 50; call due to RAUW-ing the returned value of a called function into the caller. 51; This too should form a new SCC which can then be reasoned about to compute 52; precise function attrs. 53 54; This function should no longer exist. 55; CHECK-NOT: @test2_f() 56define internal void()* @test2_f() { 57entry: 58 ret void()* @test2_h 59} 60 61; This function should have had 'readnone' deduced for its SCC. 62; CHECK: Function Attrs: noinline nounwind readnone 63; CHECK-NEXT: define void @test2_g() 64define void @test2_g() noinline { 65entry: 66 %p = call void()* @test2_f() 67 call void %p() 68 ret void 69} 70 71; This function should have had 'readnone' deduced for its SCC. 72; CHECK: Function Attrs: noinline nounwind readnone 73; CHECK-NEXT: define void @test2_h() 74define void @test2_h() noinline { 75entry: 76 call void @test2_g() 77 call void @readnone() 78 ret void 79} 80 81 82; The 'test3_' prefixed functions are designed to inline in a way that causes 83; call sites to become trivially dead during the middle of inlining callsites of 84; a single function to make sure that the inliner does not get confused by this 85; pattern. 86 87; CHECK-NOT: @test3_maybe_unknown( 88define internal void @test3_maybe_unknown(i1 %b) { 89entry: 90 br i1 %b, label %then, label %exit 91 92then: 93 call void @unknown() 94 br label %exit 95 96exit: 97 ret void 98} 99 100; CHECK-NOT: @test3_f( 101define internal i1 @test3_f() { 102entry: 103 ret i1 false 104} 105 106; CHECK-NOT: @test3_g( 107define internal i1 @test3_g(i1 %b) { 108entry: 109 br i1 %b, label %then1, label %if2 110 111then1: 112 call void @test3_maybe_unknown(i1 true) 113 br label %if2 114 115if2: 116 %f = call i1 @test3_f() 117 br i1 %f, label %then2, label %exit 118 119then2: 120 call void @test3_maybe_unknown(i1 true) 121 br label %exit 122 123exit: 124 ret i1 false 125} 126 127; FIXME: Currently the inliner doesn't successfully mark this as readnone 128; because while it simplifies trivially dead CFGs when inlining callees it 129; doesn't simplify the caller's trivially dead CFG and so we end with a dead 130; block calling @unknown. 131; CHECK-NOT: Function Attrs: readnone 132; CHECK: define void @test3_h() 133define void @test3_h() { 134entry: 135 %g = call i1 @test3_g(i1 false) 136 br i1 %g, label %then, label %exit 137 138then: 139 call void @test3_maybe_unknown(i1 true) 140 br label %exit 141 142exit: 143 call void @test3_maybe_unknown(i1 false) 144 ret void 145} 146 147 148; The 'test4_' prefixed functions are designed to trigger forming a new direct 149; call in the inlined body of the function similar to 'test1_'. However, after 150; that we continue to inline another edge of the graph forcing us to do a more 151; interesting call graph update for the new call edge. Eventually, we still 152; form a new SCC and should use that can deduce precise function attrs. 153 154; This function should have had 'readnone' deduced for its SCC. 155; CHECK: Function Attrs: noinline nounwind readnone 156; CHECK-NEXT: define void @test4_f1() 157define void @test4_f1() noinline { 158entry: 159 call void @test4_h() 160 ret void 161} 162 163; CHECK-NOT: @test4_f2 164define internal void @test4_f2() { 165entry: 166 call void @test4_f1() 167 ret void 168} 169 170; CHECK-NOT: @test4_g 171define internal void @test4_g(void()* %p) { 172entry: 173 call void %p() 174 ret void 175} 176 177; This function should have had 'readnone' deduced for its SCC. 178; CHECK: Function Attrs: noinline nounwind readnone 179; CHECK-NEXT: define void @test4_h() 180define void @test4_h() noinline { 181entry: 182 call void @test4_g(void()* @test4_f2) 183 ret void 184} 185