diff options
author | Chris Lattner <sabre@nondot.org> | 2009-08-30 22:13:26 +0000 |
---|---|---|
committer | Chris Lattner <sabre@nondot.org> | 2009-08-30 22:13:26 +0000 |
commit | 409255e329381fc19815cc18ce9798b41694d6a7 (patch) | |
tree | e063fdec6089af52ab48aa7fc980f74caa29b3d2 /test/Transforms/LICM/sinking.ll | |
parent | 7025264addb5eed5af99ed8e6aaa022f80ef3fa4 (diff) | |
download | external_llvm-409255e329381fc19815cc18ce9798b41694d6a7.zip external_llvm-409255e329381fc19815cc18ce9798b41694d6a7.tar.gz external_llvm-409255e329381fc19815cc18ce9798b41694d6a7.tar.bz2 |
merge all sinking tests into one and convert them to filecheck.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@80522 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'test/Transforms/LICM/sinking.ll')
-rw-r--r-- | test/Transforms/LICM/sinking.ll | 235 |
1 files changed, 235 insertions, 0 deletions
diff --git a/test/Transforms/LICM/sinking.ll b/test/Transforms/LICM/sinking.ll new file mode 100644 index 0000000..cf18277 --- /dev/null +++ b/test/Transforms/LICM/sinking.ll @@ -0,0 +1,235 @@ +; RUN: llvm-as < %s | opt -basicaa -licm | llvm-dis | FileCheck %s + +declare i32 @strlen(i8*) readonly + +declare void @foo() + +; Sink readonly function. +define i32 @test1(i8* %P) { + br label %Loop + +Loop: ; preds = %Loop, %0 + %A = call i32 @strlen( i8* %P ) readonly + br i1 false, label %Loop, label %Out + +Out: ; preds = %Loop + ret i32 %A +; CHECK: @test1 +; CHECK: Out: +; CHECK-NEXT: call i32 @strlen +; CHECK-NEXT: ret i32 %A +} + +declare double @sin(double) readnone + +; Sink readnone function out of loop with unknown memory behavior. +define double @test2(double %X) { + br label %Loop + +Loop: ; preds = %Loop, %0 + call void @foo( ) + %A = call double @sin( double %X ) readnone + br i1 true, label %Loop, label %Out + +Out: ; preds = %Loop + ret double %A +; CHECK: @test2 +; CHECK: Out: +; CHECK-NEXT: call double @sin +; CHECK-NEXT: ret double %A +} + +; This testcase checks to make sure the sinker does not cause problems with +; critical edges. +define void @test3() { +Entry: + br i1 false, label %Loop, label %Exit +Loop: + %X = add i32 0, 1 + br i1 false, label %Loop, label %Exit +Exit: + %Y = phi i32 [ 0, %Entry ], [ %X, %Loop ] + ret void + +; CHECK: @test3 +; CHECK: Exit.loopexit: +; CHECK-NEXT: %X = add i32 0, 1 +; CHECK-NEXT: br label %Exit + +} + +; If the result of an instruction is only used outside of the loop, sink +; the instruction to the exit blocks instead of executing it on every +; iteration of the loop. +; +define i32 @test4(i32 %N) { +Entry: + br label %Loop +Loop: ; preds = %Loop, %Entry + %N_addr.0.pn = phi i32 [ %dec, %Loop ], [ %N, %Entry ] + %tmp.6 = mul i32 %N, %N_addr.0.pn ; <i32> [#uses=1] + %tmp.7 = sub i32 %tmp.6, %N ; <i32> [#uses=1] + %dec = add i32 %N_addr.0.pn, -1 ; <i32> [#uses=1] + %tmp.1 = icmp ne i32 %N_addr.0.pn, 1 ; <i1> [#uses=1] + br i1 %tmp.1, label %Loop, label %Out +Out: ; preds = %Loop + ret i32 %tmp.7 +; CHECK: @test4 +; CHECK: Out: +; CHECK-NEXT: mul i32 %N, %N_addr.0.pn +; CHECK-NEXT: sub i32 %tmp.6, %N +; CHECK-NEXT: ret i32 +} + +; To reduce register pressure, if a load is hoistable out of the loop, and the +; result of the load is only used outside of the loop, sink the load instead of +; hoisting it! +; +@X = global i32 5 ; <i32*> [#uses=1] + +define i32 @test5(i32 %N) { +Entry: + br label %Loop +Loop: ; preds = %Loop, %Entry + %N_addr.0.pn = phi i32 [ %dec, %Loop ], [ %N, %Entry ] + %tmp.6 = load i32* @X ; <i32> [#uses=1] + %dec = add i32 %N_addr.0.pn, -1 ; <i32> [#uses=1] + %tmp.1 = icmp ne i32 %N_addr.0.pn, 1 ; <i1> [#uses=1] + br i1 %tmp.1, label %Loop, label %Out +Out: ; preds = %Loop + ret i32 %tmp.6 +; CHECK: @test5 +; CHECK: Out: +; CHECK-NEXT: %tmp.6 = load i32* @X +; CHECK-NEXT: ret i32 %tmp.6 +} + + + +; The loop sinker was running from the bottom of the loop to the top, causing +; it to miss opportunities to sink instructions that depended on sinking other +; instructions from the loop. Instead they got hoisted, which is better than +; leaving them in the loop, but increases register pressure pointlessly. + + %Ty = type { i32, i32 } +@X2 = external global %Ty + +define i32 @test6() { + br label %Loop +Loop: + %dead = getelementptr %Ty* @X2, i64 0, i32 0 + %sunk2 = load i32* %dead + br i1 false, label %Loop, label %Out +Out: ; preds = %Loop + ret i32 %sunk2 +; CHECK: @test6 +; CHECK: Out: +; CHECK-NEXT: %dead = getelementptr %Ty* @X2, i64 0, i32 0 +; CHECK-NEXT: %sunk2 = load i32* %dead +; CHECK-NEXT: ret i32 %sunk2 +} + + + +; This testcase ensures that we can sink instructions from loops with +; multiple exits. +; +define i32 @test7(i32 %N, i1 %C) { +Entry: + br label %Loop +Loop: ; preds = %ContLoop, %Entry + %N_addr.0.pn = phi i32 [ %dec, %ContLoop ], [ %N, %Entry ] + %tmp.6 = mul i32 %N, %N_addr.0.pn + %tmp.7 = sub i32 %tmp.6, %N ; <i32> [#uses=2] + %dec = add i32 %N_addr.0.pn, -1 ; <i32> [#uses=1] + br i1 %C, label %ContLoop, label %Out1 +ContLoop: + %tmp.1 = icmp ne i32 %N_addr.0.pn, 1 + br i1 %tmp.1, label %Loop, label %Out2 +Out1: ; preds = %Loop + ret i32 %tmp.7 +Out2: ; preds = %ContLoop + ret i32 %tmp.7 +; CHECK: @test7 +; CHECK: Out1: +; CHECK-NEXT: mul i32 %N, %N_addr.0.pn +; CHECK-NEXT: sub i32 %tmp.6, %N +; CHECK-NEXT: ret +; CHECK: Out2: +; CHECK-NEXT: mul i32 %N, %N_addr.0.pn +; CHECK-NEXT: sub i32 %tmp.6 +; CHECK-NEXT: ret +} + + +; This testcase checks to make sure we can sink values which are only live on +; some exits out of the loop, and that we can do so without breaking dominator +; info. +define i32 @test8(i1 %C1, i1 %C2, i32* %P, i32* %Q) { +Entry: + br label %Loop +Loop: ; preds = %Cont, %Entry + br i1 %C1, label %Cont, label %exit1 +Cont: ; preds = %Loop + %X = load i32* %P ; <i32> [#uses=2] + store i32 %X, i32* %Q + %V = add i32 %X, 1 ; <i32> [#uses=1] + br i1 %C2, label %Loop, label %exit2 +exit1: ; preds = %Loop + ret i32 0 +exit2: ; preds = %Cont + ret i32 %V +; CHECK: @test8 +; CHECK: exit1: +; CHECK-NEXT: ret i32 0 +; CHECK: exit2: +; CHECK-NEXT: %V = add i32 %X, 1 +; CHECK-NEXT: ret i32 %V +} + + +define void @test9() { +loopentry.2.i: + br i1 false, label %no_exit.1.i.preheader, label %loopentry.3.i.preheader +no_exit.1.i.preheader: ; preds = %loopentry.2.i + br label %no_exit.1.i +no_exit.1.i: ; preds = %endif.8.i, %no_exit.1.i.preheader + br i1 false, label %return.i, label %endif.8.i +endif.8.i: ; preds = %no_exit.1.i + %inc.1.i = add i32 0, 1 ; <i32> [#uses=1] + br i1 false, label %no_exit.1.i, label %loopentry.3.i.preheader.loopexit +loopentry.3.i.preheader.loopexit: ; preds = %endif.8.i + br label %loopentry.3.i.preheader +loopentry.3.i.preheader: ; preds = %loopentry.3.i.preheader.loopexit, %loopentry.2.i + %arg_num.0.i.ph13000 = phi i32 [ 0, %loopentry.2.i ], [ %inc.1.i, %loopentry.3.i.preheader.loopexit ] ; <i32> [#uses=0] + ret void +return.i: ; preds = %no_exit.1.i + ret void + +; CHECK: @test9 +; CHECK: loopentry.3.i.preheader.loopexit: +; CHECK-NEXT: %inc.1.i = add i32 0, 1 +; CHECK-NEXT: br label %loopentry.3.i.preheader +} + + +; Potentially trapping instructions may be sunk as long as they are guaranteed +; to be executed. +define i32 @test10(i32 %N) { +Entry: + br label %Loop +Loop: ; preds = %Loop, %Entry + %N_addr.0.pn = phi i32 [ %dec, %Loop ], [ %N, %Entry ] ; <i32> [#uses=3] + %tmp.6 = sdiv i32 %N, %N_addr.0.pn ; <i32> [#uses=1] + %dec = add i32 %N_addr.0.pn, -1 ; <i32> [#uses=1] + %tmp.1 = icmp ne i32 %N_addr.0.pn, 0 ; <i1> [#uses=1] + br i1 %tmp.1, label %Loop, label %Out +Out: ; preds = %Loop + ret i32 %tmp.6 + +; CHECK: @test10 +; CHECK: Out: +; CHECK-NEXT: %tmp.6 = sdiv i32 %N, %N_addr.0.pn +; CHECK-NEXT: ret i32 %tmp.6 +} + |