diff --git a/test/Transforms/LICM/2003-08-04-TrappingInstHoist.ll b/test/Transforms/LICM/2003-08-04-TrappingInstHoist.ll index a00eb8c7a63..821c8a3fd5b 100644 --- a/test/Transforms/LICM/2003-08-04-TrappingInstHoist.ll +++ b/test/Transforms/LICM/2003-08-04-TrappingInstHoist.ll @@ -1,21 +1,25 @@ -; This testcase tests for a problem where LICM hoists -; potentially trapping instructions when they are not guaranteed to execute. -; -; RUN: llvm-as < %s | opt -licm | llvm-dis | %prcontext "IfUnEqual" 2 | grep div +; RUN: llvm-as < %s | opt -licm | llvm-dis | FileCheck %s @X = global i32 0 ; [#uses=1] declare void @foo() -define i32 @test(i1 %c) { +; This testcase tests for a problem where LICM hoists +; potentially trapping instructions when they are not guaranteed to execute. +define i32 @test1(i1 %c) { +; CHECK: @test1 %A = load i32* @X ; [#uses=2] br label %Loop Loop: ; preds = %LoopTail, %0 call void @foo( ) br i1 %c, label %LoopTail, label %IfUnEqual + IfUnEqual: ; preds = %Loop +; CHECK: IfUnEqual: +; CHECK-NEXT: sdiv i32 4, %A %B1 = sdiv i32 4, %A ; [#uses=1] br label %LoopTail + LoopTail: ; preds = %IfUnEqual, %Loop %B = phi i32 [ 0, %Loop ], [ %B1, %IfUnEqual ] ; [#uses=1] br i1 %c, label %Loop, label %Out @@ -24,3 +28,23 @@ Out: ; preds = %LoopTail ret i32 %C } + +declare void @foo2(i32) + + +;; It is ok and desirable to hoist this potentially trapping instruction. +define i32 @test2(i1 %c) { +; CHECK: @test2 +; CHECK-NEXT: load i32* @X +; CHECK-NEXT: %B = sdiv i32 4, %A + %A = load i32* @X ; [#uses=2] + br label %Loop +Loop: + ;; Should have hoisted this div! + %B = sdiv i32 4, %A ; [#uses=2] + call void @foo2( i32 %B ) + br i1 %c, label %Loop, label %Out +Out: ; preds = %Loop + %C = sub i32 %A, %B ; [#uses=1] + ret i32 %C +} diff --git a/test/Transforms/LICM/2003-08-04-TrappingInstOkHoist.ll b/test/Transforms/LICM/2003-08-04-TrappingInstOkHoist.ll deleted file mode 100644 index 59cc0d66207..00000000000 --- a/test/Transforms/LICM/2003-08-04-TrappingInstOkHoist.ll +++ /dev/null @@ -1,21 +0,0 @@ -; This testcase tests to make sure a trapping instruction is hoisted when -; it is guaranteed to execute. -; -; RUN: llvm-as < %s | opt -licm | llvm-dis | %prcontext "test" 2 | grep div - -@X = global i32 0 ; [#uses=1] - -declare void @foo(i32) - -define i32 @test(i1 %c) { - %A = load i32* @X ; [#uses=2] - br label %Loop -Loop: ; preds = %Loop, %0 - ;; Should have hoisted this div! - %B = sdiv i32 4, %A ; [#uses=2] - call void @foo( i32 %B ) - br i1 %c, label %Loop, label %Out -Out: ; preds = %Loop - %C = sub i32 %A, %B ; [#uses=1] - ret i32 %C -} diff --git a/test/Transforms/LICM/call_sink_const_function.ll b/test/Transforms/LICM/call_sink_const_function.ll deleted file mode 100644 index f187e27335b..00000000000 --- a/test/Transforms/LICM/call_sink_const_function.ll +++ /dev/null @@ -1,17 +0,0 @@ -; RUN: llvm-as < %s | opt -basicaa -licm | llvm-dis | %prcontext sin 1 | grep Out: - -declare double @sin(double) readnone - -declare void @foo() - -define double @test(double %X) { - br label %Loop - -Loop: ; preds = %Loop, %0 - call void @foo( ) - %A = call double @sin( double %X ) readnone ; [#uses=1] - br i1 true, label %Loop, label %Out - -Out: ; preds = %Loop - ret double %A -} diff --git a/test/Transforms/LICM/call_sink_pure_function.ll b/test/Transforms/LICM/call_sink_pure_function.ll deleted file mode 100644 index c0457a17fc4..00000000000 --- a/test/Transforms/LICM/call_sink_pure_function.ll +++ /dev/null @@ -1,16 +0,0 @@ -; RUN: llvm-as < %s | opt -basicaa -licm | llvm-dis | %prcontext strlen 1 | grep Out: - -declare i32 @strlen(i8*) readonly - -declare void @foo() - -define i32 @test(i8* %P) { - br label %Loop - -Loop: ; preds = %Loop, %0 - %A = call i32 @strlen( i8* %P ) readonly ; [#uses=1] - br i1 false, label %Loop, label %Out - -Out: ; preds = %Loop - ret i32 %A -} diff --git a/test/Transforms/LICM/sink_critical_edge.ll b/test/Transforms/LICM/sink_critical_edge.ll deleted file mode 100644 index 6998ab1580c..00000000000 --- a/test/Transforms/LICM/sink_critical_edge.ll +++ /dev/null @@ -1,16 +0,0 @@ -; This testcase checks to make sure the sinker does not cause problems with -; critical edges. - -; RUN: llvm-as < %s | opt -licm | llvm-dis | %prcontext add 1 | grep Exit - -define void @test() { -Entry: - br i1 false, label %Loop, label %Exit -Loop: ; preds = %Loop, %Entry - %X = add i32 0, 1 ; [#uses=1] - br i1 false, label %Loop, label %Exit -Exit: ; preds = %Loop, %Entry - %Y = phi i32 [ 0, %Entry ], [ %X, %Loop ] ; [#uses=0] - ret void -} - diff --git a/test/Transforms/LICM/sink_inst.ll b/test/Transforms/LICM/sink_inst.ll deleted file mode 100644 index e634c753f36..00000000000 --- a/test/Transforms/LICM/sink_inst.ll +++ /dev/null @@ -1,20 +0,0 @@ -; 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. -; -; RUN: llvm-as < %s | opt -licm | llvm-dis | %prcontext mul 1 | grep Out: - -define i32 @test(i32 %N) { -Entry: - br label %Loop -Loop: ; preds = %Loop, %Entry - %N_addr.0.pn = phi i32 [ %dec, %Loop ], [ %N, %Entry ] ; [#uses=3] - %tmp.6 = mul i32 %N, %N_addr.0.pn ; [#uses=1] - %tmp.7 = sub i32 %tmp.6, %N ; [#uses=1] - %dec = add i32 %N_addr.0.pn, -1 ; [#uses=1] - %tmp.1 = icmp ne i32 %N_addr.0.pn, 1 ; [#uses=1] - br i1 %tmp.1, label %Loop, label %Out -Out: ; preds = %Loop - ret i32 %tmp.7 -} - diff --git a/test/Transforms/LICM/sink_load.ll b/test/Transforms/LICM/sink_load.ll deleted file mode 100644 index 87334840e05..00000000000 --- a/test/Transforms/LICM/sink_load.ll +++ /dev/null @@ -1,21 +0,0 @@ -; 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! -; -; RUN: llvm-as < %s | opt -licm | llvm-dis | %prcontext load 1 | grep Out: - -@X = global i32 5 ; [#uses=1] - -define i32 @test(i32 %N) { -Entry: - br label %Loop -Loop: ; preds = %Loop, %Entry - %N_addr.0.pn = phi i32 [ %dec, %Loop ], [ %N, %Entry ] ; [#uses=2] - %tmp.6 = load i32* @X ; [#uses=1] - %dec = add i32 %N_addr.0.pn, -1 ; [#uses=1] - %tmp.1 = icmp ne i32 %N_addr.0.pn, 1 ; [#uses=1] - br i1 %tmp.1, label %Loop, label %Out -Out: ; preds = %Loop - ret i32 %tmp.6 -} - diff --git a/test/Transforms/LICM/sink_multiple.ll b/test/Transforms/LICM/sink_multiple.ll deleted file mode 100644 index c9341704738..00000000000 --- a/test/Transforms/LICM/sink_multiple.ll +++ /dev/null @@ -1,21 +0,0 @@ -; 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. - -; RUN: llvm-as < %s | opt -licm | llvm-dis | \ -; RUN: %prcontext getelementptr 1 | grep Out: - - %Ty = type { i32, i32 } -@X = external global %Ty ; <%Ty*> [#uses=1] - -define i32 @test() { - br label %Loop -Loop: ; preds = %Loop, %0 - %dead = getelementptr %Ty* @X, i64 0, i32 0 ; [#uses=1] - %sunk2 = load i32* %dead ; [#uses=1] - br i1 false, label %Loop, label %Out -Out: ; preds = %Loop - ret i32 %sunk2 -} - diff --git a/test/Transforms/LICM/sink_multiple_exits.ll b/test/Transforms/LICM/sink_multiple_exits.ll deleted file mode 100644 index 2882fa4b0af..00000000000 --- a/test/Transforms/LICM/sink_multiple_exits.ll +++ /dev/null @@ -1,24 +0,0 @@ -; This testcase ensures that we can sink instructions from loops with -; multiple exits. -; -; RUN: llvm-as < %s | opt -licm | llvm-dis | \ -; RUN: %prcontext mul 1 | grep {Out\[12\]:} - -define i32 @test(i32 %N, i1 %C) { -Entry: - br label %Loop -Loop: ; preds = %ContLoop, %Entry - %N_addr.0.pn = phi i32 [ %dec, %ContLoop ], [ %N, %Entry ] ; [#uses=3] - %tmp.6 = mul i32 %N, %N_addr.0.pn ; [#uses=1] - %tmp.7 = sub i32 %tmp.6, %N ; [#uses=2] - %dec = add i32 %N_addr.0.pn, -1 ; [#uses=1] - br i1 %C, label %ContLoop, label %Out1 -ContLoop: ; preds = %Loop - %tmp.1 = icmp ne i32 %N_addr.0.pn, 1 ; [#uses=1] - br i1 %tmp.1, label %Loop, label %Out2 -Out1: ; preds = %Loop - ret i32 %tmp.7 -Out2: ; preds = %ContLoop - ret i32 %tmp.7 -} - diff --git a/test/Transforms/LICM/sink_only_some_exits.ll b/test/Transforms/LICM/sink_only_some_exits.ll deleted file mode 100644 index 42cfece56c9..00000000000 --- a/test/Transforms/LICM/sink_only_some_exits.ll +++ /dev/null @@ -1,23 +0,0 @@ -; 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. -; -; RUN: llvm-as < %s | opt -licm | llvm-dis | \ -; RUN: %prcontext add 1 | grep exit2: - -define i32 @test(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 ; [#uses=2] - store i32 %X, i32* %Q - %V = add i32 %X, 1 ; [#uses=1] - br i1 %C2, label %Loop, label %exit2 -exit1: ; preds = %Loop - ret i32 0 -exit2: ; preds = %Cont - ret i32 %V -} - diff --git a/test/Transforms/LICM/sink_phi_node_use.ll b/test/Transforms/LICM/sink_phi_node_use.ll deleted file mode 100644 index 6e558bb1e49..00000000000 --- a/test/Transforms/LICM/sink_phi_node_use.ll +++ /dev/null @@ -1,21 +0,0 @@ -; RUN: llvm-as < %s | opt -licm | llvm-dis | %prcontext add 1 | grep preheader.loopexit: - -define void @test() { -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 ; [#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 ] ; [#uses=0] - ret void -return.i: ; preds = %no_exit.1.i - ret void -} - diff --git a/test/Transforms/LICM/sink_trapping_inst.ll b/test/Transforms/LICM/sink_trapping_inst.ll deleted file mode 100644 index 8e79039efe4..00000000000 --- a/test/Transforms/LICM/sink_trapping_inst.ll +++ /dev/null @@ -1,18 +0,0 @@ -; Potentially trapping instructions may be sunk as long as they are guaranteed -; to be executed. -; -; RUN: llvm-as < %s | opt -licm | llvm-dis | %prcontext div 1 | grep Out: - -define i32 @test(i32 %N) { -Entry: - br label %Loop -Loop: ; preds = %Loop, %Entry - %N_addr.0.pn = phi i32 [ %dec, %Loop ], [ %N, %Entry ] ; [#uses=3] - %tmp.6 = sdiv i32 %N, %N_addr.0.pn ; [#uses=1] - %dec = add i32 %N_addr.0.pn, -1 ; [#uses=1] - %tmp.1 = icmp ne i32 %N_addr.0.pn, 0 ; [#uses=1] - br i1 %tmp.1, label %Loop, label %Out -Out: ; preds = %Loop - ret i32 %tmp.6 -} - diff --git a/test/Transforms/LICM/sinking.ll b/test/Transforms/LICM/sinking.ll new file mode 100644 index 00000000000..cf182771053 --- /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 ; [#uses=1] + %tmp.7 = sub i32 %tmp.6, %N ; [#uses=1] + %dec = add i32 %N_addr.0.pn, -1 ; [#uses=1] + %tmp.1 = icmp ne i32 %N_addr.0.pn, 1 ; [#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 ; [#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 ; [#uses=1] + %dec = add i32 %N_addr.0.pn, -1 ; [#uses=1] + %tmp.1 = icmp ne i32 %N_addr.0.pn, 1 ; [#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 ; [#uses=2] + %dec = add i32 %N_addr.0.pn, -1 ; [#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 ; [#uses=2] + store i32 %X, i32* %Q + %V = add i32 %X, 1 ; [#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 ; [#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 ] ; [#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 ] ; [#uses=3] + %tmp.6 = sdiv i32 %N, %N_addr.0.pn ; [#uses=1] + %dec = add i32 %N_addr.0.pn, -1 ; [#uses=1] + %tmp.1 = icmp ne i32 %N_addr.0.pn, 0 ; [#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 +} +