185 lines · plain
1; RUN: opt < %s -aa-pipeline=basic-aa -passes='cgscc(function-attrs,inline)' -S | FileCheck %s2; This test runs the inliner and the function attribute deduction. It ensures3; that when the inliner mutates the call graph it correctly updates the CGSCC4; iteration so that we can compute refined function attributes. In this way it5; is leveraging function attribute computation to observe correct call graph6; updates.7 8; Boring unknown external function call.9; CHECK: declare void @unknown()10declare void @unknown()11 12; Basic correctness check: this should get annotated as memory(none).13; CHECK: Function Attrs: nounwind memory(none)14; CHECK-NEXT: declare void @readnone()15declare void @readnone() readnone nounwind16 17; The 'test1_' prefixed functions are designed to trigger forming a new direct18; call in the inlined body of the function. After that, we form a new SCC and19; 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(ptr %p) {24entry:25 call void %p()26 ret void27}28 29; This function should have had 'memory(none)' deduced for its SCC.30; CHECK: Function Attrs: nofree noinline nosync nounwind memory(none)31; CHECK-NEXT: define void @test1_g()32define void @test1_g() noinline {33entry:34 call void @test1_f(ptr @test1_h)35 ret void36}37 38; This function should have had 'memory(none)' deduced for its SCC.39; CHECK: Function Attrs: nofree noinline nosync nounwind memory(none)40; CHECK-NEXT: define void @test1_h()41define void @test1_h() noinline {42entry:43 call void @test1_g()44 call void @readnone()45 ret void46}47 48 49; The 'test2_' prefixed functions are designed to trigger forming a new direct50; 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 compute52; precise function attrs.53 54; This function should no longer exist.55; CHECK-NOT: @test2_f()56define internal ptr @test2_f() {57entry:58 ret ptr @test2_h59}60 61; This function should have had 'memory(none)' deduced for its SCC.62; CHECK: Function Attrs: nofree noinline nosync nounwind memory(none)63; CHECK-NEXT: define void @test2_g()64define void @test2_g() noinline {65entry:66 %p = call ptr @test2_f()67 call void %p()68 ret void69}70 71; This function should have had 'memory(none)' deduced for its SCC.72; CHECK: Function Attrs: nofree noinline nosync nounwind memory(none)73; CHECK-NEXT: define void @test2_h()74define void @test2_h() noinline {75entry:76 call void @test2_g()77 call void @readnone()78 ret void79}80 81 82; The 'test3_' prefixed functions are designed to inline in a way that causes83; call sites to become trivially dead during the middle of inlining callsites of84; a single function to make sure that the inliner does not get confused by this85; pattern.86 87; CHECK-NOT: @test3_maybe_unknown(88define internal void @test3_maybe_unknown(i1 %b) {89entry:90 br i1 %b, label %then, label %exit91 92then:93 call void @unknown()94 br label %exit95 96exit:97 ret void98}99 100; CHECK-NOT: @test3_f(101define internal i1 @test3_f() {102entry:103 ret i1 false104}105 106; CHECK-NOT: @test3_g(107define internal i1 @test3_g(i1 %b) {108entry:109 br i1 %b, label %then1, label %if2110 111then1:112 call void @test3_maybe_unknown(i1 true)113 br label %if2114 115if2:116 %f = call i1 @test3_f()117 br i1 %f, label %then2, label %exit118 119then2:120 call void @test3_maybe_unknown(i1 true)121 br label %exit122 123exit:124 ret i1 false125}126 127; FIXME: Currently the inliner doesn't successfully mark this as readnone128; because while it simplifies trivially dead CFGs when inlining callees it129; doesn't simplify the caller's trivially dead CFG and so we end with a dead130; block calling @unknown.131; CHECK-NOT: Function Attrs: readnone132; 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 %exit137 138then:139 call void @test3_maybe_unknown(i1 true)140 br label %exit141 142exit:143 call void @test3_maybe_unknown(i1 false)144 ret void145}146 147 148; The 'test4_' prefixed functions are designed to trigger forming a new direct149; call in the inlined body of the function similar to 'test1_'. However, after150; that we continue to inline another edge of the graph forcing us to do a more151; interesting call graph update for the new call edge. Eventually, we still152; form a new SCC and should use that can deduce precise function attrs.153 154; This function should have had 'memory(none)' deduced for its SCC.155; CHECK: Function Attrs: nofree noinline nosync nounwind memory(none)156; CHECK-NEXT: define void @test4_f1()157define void @test4_f1() noinline {158entry:159 call void @test4_h()160 ret void161}162 163; CHECK-NOT: @test4_f2164define internal void @test4_f2() {165entry:166 call void @test4_f1()167 ret void168}169 170; CHECK-NOT: @test4_g171define internal void @test4_g(ptr %p) {172entry:173 call void %p()174 ret void175}176 177; This function should have had 'memory(none)' deduced for its SCC.178; CHECK: Function Attrs: nofree noinline nosync nounwind memory(none)179; CHECK-NEXT: define void @test4_h()180define void @test4_h() noinline {181entry:182 call void @test4_g(ptr @test4_f2)183 ret void184}185