summaryrefslogtreecommitdiffstats
path: root/test/Transforms/LICM/sinking.ll
diff options
context:
space:
mode:
authorrdivacky <rdivacky@FreeBSD.org>2009-10-14 17:57:32 +0000
committerrdivacky <rdivacky@FreeBSD.org>2009-10-14 17:57:32 +0000
commitcd749a9c07f1de2fb8affde90537efa4bc3e7c54 (patch)
treeb21f6de4e08b89bb7931806bab798fc2a5e3a686 /test/Transforms/LICM/sinking.ll
parent72621d11de5b873f1695f391eb95f0b336c3d2d4 (diff)
downloadFreeBSD-src-cd749a9c07f1de2fb8affde90537efa4bc3e7c54.zip
FreeBSD-src-cd749a9c07f1de2fb8affde90537efa4bc3e7c54.tar.gz
Update llvm to r84119.
Diffstat (limited to 'test/Transforms/LICM/sinking.ll')
-rw-r--r--test/Transforms/LICM/sinking.ll235
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..11112eb
--- /dev/null
+++ b/test/Transforms/LICM/sinking.ll
@@ -0,0 +1,235 @@
+; RUN: opt < %s -basicaa -licm -S | 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
+}
+
OpenPOWER on IntegriCloud