summaryrefslogtreecommitdiffstats
path: root/llvm/test/Transforms/LICM/sinking.ll
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/test/Transforms/LICM/sinking.ll')
-rw-r--r--llvm/test/Transforms/LICM/sinking.ll284
1 files changed, 283 insertions, 1 deletions
diff --git a/llvm/test/Transforms/LICM/sinking.ll b/llvm/test/Transforms/LICM/sinking.ll
index 6e9e8d4b7b6..b28eea0bc2a 100644
--- a/llvm/test/Transforms/LICM/sinking.ll
+++ b/llvm/test/Transforms/LICM/sinking.ll
@@ -392,6 +392,288 @@ lab60:
indirectbr i8* undef, [label %lab21, label %lab19]
}
-declare void @f(i32*)
+; Check if LICM can sink a sinkable instruction the exit blocks through
+; a non-trivially replacable PHI node.
+;
+; CHECK-LABEL: @test14
+; CHECK-LABEL: Loop:
+; CHECK-NOT: mul
+; CHECK-NOT: sub
+;
+; CHECK-LABEL: Out12.split.loop.exit:
+; CHECK: %[[LCSSAPHI:.*]] = phi i32 [ %N_addr.0.pn, %ContLoop ]
+; CHECK: %[[MUL:.*]] = mul i32 %N, %[[LCSSAPHI]]
+; CHECK: br label %Out12
+;
+; CHECK-LABEL: Out12.split.loop.exit1:
+; CHECK: %[[LCSSAPHI2:.*]] = phi i32 [ %N_addr.0.pn, %Loop ]
+; CHECK: %[[MUL2:.*]] = mul i32 %N, %[[LCSSAPHI2]]
+; CHECK: %[[SUB:.*]] = sub i32 %[[MUL2]], %N
+; CHECK: br label %Out12
+;
+; CHECK-LABEL: Out12:
+; CHECK: phi i32 [ %[[MUL]], %Out12.split.loop.exit ], [ %[[SUB]], %Out12.split.loop.exit1 ]
+define i32 @test14(i32 %N, i32 %N2, i1 %C) {
+Entry:
+ br label %Loop
+Loop:
+ %N_addr.0.pn = phi i32 [ %dec, %ContLoop ], [ %N, %Entry ]
+ %sink.mul = mul i32 %N, %N_addr.0.pn
+ %sink.sub = sub i32 %sink.mul, %N
+ %dec = add i32 %N_addr.0.pn, -1
+ br i1 %C, label %ContLoop, label %Out12
+ContLoop:
+ %tmp.1 = icmp ne i32 %N_addr.0.pn, 1
+ br i1 %tmp.1, label %Loop, label %Out12
+Out12:
+ %tmp = phi i32 [%sink.mul, %ContLoop], [%sink.sub, %Loop]
+ ret i32 %tmp
+}
+
+; In this test, splitting predecessors is not really required because the
+; operations of sinkable instructions (sub and mul) are same. In this case, we
+; can sink the same sinkable operations and modify the PHI to pass the operands
+; to the shared operations. As of now, we split predecessors of non-trivially
+; replicalbe PHIs by default in LICM because all incoming edges of a
+; non-trivially replacable PHI in LCSSA is critical.
+;
+; CHECK-LABEL: @test15
+; CHECK-LABEL: Loop:
+; CHECK-NOT: mul
+; CHECK-NOT: sub
+;
+; CHECK-LABEL: Out12.split.loop.exit:
+; CHECK: %[[LCSSAPHI:.*]] = phi i32 [ %N_addr.0.pn, %ContLoop ]
+; CHECK: %[[MUL:.*]] = mul i32 %N, %[[LCSSAPHI]]
+; CHECK: %[[SUB:.*]] = sub i32 %[[MUL]], %N2
+; CHECK: br label %Out12
+;
+; CHECK-LABEL: Out12.split.loop.exit1:
+; CHECK: %[[LCSSAPHI2:.*]] = phi i32 [ %N_addr.0.pn, %Loop ]
+; CHECK: %[[MUL2:.*]] = mul i32 %N, %[[LCSSAPHI2]]
+; CHECK: %[[SUB2:.*]] = sub i32 %[[MUL2]], %N
+; CHECK: br label %Out12
+;
+; CHECK-LABEL: Out12:
+; CHECK: phi i32 [ %[[SUB]], %Out12.split.loop.exit ], [ %[[SUB2]], %Out12.split.loop.exit1 ]
+define i32 @test15(i32 %N, i32 %N2, i1 %C) {
+Entry:
+ br label %Loop
+Loop:
+ %N_addr.0.pn = phi i32 [ %dec, %ContLoop ], [ %N, %Entry ]
+ %sink.mul = mul i32 %N, %N_addr.0.pn
+ %sink.sub = sub i32 %sink.mul, %N
+ %sink.sub2 = sub i32 %sink.mul, %N2
+ %dec = add i32 %N_addr.0.pn, -1
+ br i1 %C, label %ContLoop, label %Out12
+ContLoop:
+ %tmp.1 = icmp ne i32 %N_addr.0.pn, 1
+ br i1 %tmp.1, label %Loop, label %Out12
+Out12:
+ %tmp = phi i32 [%sink.sub2, %ContLoop], [%sink.sub, %Loop]
+ ret i32 %tmp
+}
+
+; Sink through a non-trivially replacable PHI node which use the same sinkable
+; instruction multiple times.
+;
+; CHECK-LABEL: @test16
+; CHECK-LABEL: Loop:
+; CHECK-NOT: mul
+;
+; CHECK-LABEL: Out.split.loop.exit:
+; CHECK: %[[PHI:.*]] = phi i32 [ %l2, %ContLoop ]
+; CHECK: br label %Out
+;
+; CHECK-LABEL: Out.split.loop.exit1:
+; CHECK: %[[SINKABLE:.*]] = mul i32 %l2.lcssa, %t.le
+; CHECK: br label %Out
+;
+; CHECK-LABEL: Out:
+; CHECK: %idx = phi i32 [ %[[PHI]], %Out.split.loop.exit ], [ %[[SINKABLE]], %Out.split.loop.exit1 ]
+define i32 @test16(i1 %c, i8** %P, i32* %P2, i64 %V) {
+entry:
+ br label %loop.ph
+loop.ph:
+ br label %Loop
+Loop:
+ %iv = phi i64 [ 0, %loop.ph ], [ %next, %ContLoop ]
+ %l2 = call i32 @getv()
+ %t = trunc i64 %iv to i32
+ %sinkable = mul i32 %l2, %t
+ switch i32 %l2, label %ContLoop [
+ i32 32, label %Out
+ i32 46, label %Out
+ i32 95, label %Out
+ ]
+ContLoop:
+ %next = add nuw i64 %iv, 1
+ %c1 = call i1 @getc()
+ br i1 %c1, label %Loop, label %Out
+Out:
+ %idx = phi i32 [ %l2, %ContLoop ], [ %sinkable, %Loop ], [ %sinkable, %Loop ], [ %sinkable, %Loop ]
+ ret i32 %idx
+}
+
+; Sink a sinkable instruction through multiple non-trivially replacable PHIs in
+; differect exit blocks.
+;
+; CHECK-LABEL: @test17
+; CHECK-LABEL: Loop:
+; CHECK-NOT: mul
+;
+; CHECK-LABEL:OutA.split.loop.exit{{.*}}:
+; CHECK: %[[OP1:.*]] = phi i32 [ %N_addr.0.pn, %ContLoop1 ]
+; CHECK: %[[SINKABLE:.*]] = mul i32 %N, %[[OP1]]
+; CHECK: br label %OutA
+;
+; CHECK-LABEL:OutA:
+; CHECK: phi i32{{.*}}[ %[[SINKABLE]], %OutA.split.loop.exit{{.*}} ]
+;
+; CHECK-LABEL:OutB.split.loop.exit{{.*}}:
+; CHECK: %[[OP2:.*]] = phi i32 [ %N_addr.0.pn, %ContLoop2 ]
+; CHECK: %[[SINKABLE2:.*]] = mul i32 %N, %[[OP2]]
+; CHECK: br label %OutB
+;
+; CHECK-LABEL:OutB:
+; CHECK: phi i32 {{.*}}[ %[[SINKABLE2]], %OutB.split.loop.exit{{.*}} ]
+define i32 @test17(i32 %N, i32 %N2) {
+Entry:
+ br label %Loop
+Loop:
+ %N_addr.0.pn = phi i32 [ %dec, %ContLoop3 ], [ %N, %Entry ]
+ %sink.mul = mul i32 %N, %N_addr.0.pn
+ %c0 = call i1 @getc()
+ br i1 %c0 , label %ContLoop1, label %OutA
+ContLoop1:
+ %c1 = call i1 @getc()
+ br i1 %c1, label %ContLoop2, label %OutA
+
+ContLoop2:
+ %c2 = call i1 @getc()
+ br i1 %c2, label %ContLoop3, label %OutB
+ContLoop3:
+ %c3 = call i1 @getc()
+ %dec = add i32 %N_addr.0.pn, -1
+ br i1 %c3, label %Loop, label %OutB
+OutA:
+ %tmp1 = phi i32 [%sink.mul, %ContLoop1], [%N2, %Loop]
+ br label %Out12
+OutB:
+ %tmp2 = phi i32 [%sink.mul, %ContLoop2], [%dec, %ContLoop3]
+ br label %Out12
+Out12:
+ %tmp = phi i32 [%tmp1, %OutA], [%tmp2, %OutB]
+ ret i32 %tmp
+}
+
+
+; Sink a sinkable instruction through both trivially and non-trivially replacable PHIs.
+;
+; CHECK-LABEL: @test18
+; CHECK-LABEL: Loop:
+; CHECK-NOT: mul
+; CHECK-NOT: sub
+;
+; CHECK-LABEL:Out12.split.loop.exit:
+; CHECK: %[[OP:.*]] = phi i32 [ %iv, %ContLoop ]
+; CHECK: %[[DEC:.*]] = phi i32 [ %dec, %ContLoop ]
+; CHECK: %[[SINKMUL:.*]] = mul i32 %N, %[[OP]]
+; CHECK: %[[SINKSUB:.*]] = sub i32 %[[SINKMUL]], %N2
+; CHECK: br label %Out12
+;
+; CHECK-LABEL:Out12.split.loop.exit1:
+; CHECK: %[[OP2:.*]] = phi i32 [ %iv, %Loop ]
+; CHECK: %[[SINKMUL2:.*]] = mul i32 %N, %[[OP2]]
+; CHECK: %[[SINKSUB2:.*]] = sub i32 %[[SINKMUL2]], %N2
+; CHECK: br label %Out12
+;
+; CHECK-LABEL:Out12:
+; CHECK: %tmp1 = phi i32 [ %[[SINKSUB]], %Out12.split.loop.exit ], [ %[[SINKSUB2]], %Out12.split.loop.exit1 ]
+; CHECK: %tmp2 = phi i32 [ %[[DEC]], %Out12.split.loop.exit ], [ %[[SINKSUB2]], %Out12.split.loop.exit1 ]
+; CHECK: %add = add i32 %tmp1, %tmp2
+define i32 @test18(i32 %N, i32 %N2) {
+Entry:
+ br label %Loop
+Loop:
+ %iv = phi i32 [ %dec, %ContLoop ], [ %N, %Entry ]
+ %sink.mul = mul i32 %N, %iv
+ %sink.sub = sub i32 %sink.mul, %N2
+ %c0 = call i1 @getc()
+ br i1 %c0, label %ContLoop, label %Out12
+ContLoop:
+ %dec = add i32 %iv, -1
+ %c1 = call i1 @getc()
+ br i1 %c1, label %Loop, label %Out12
+Out12:
+ %tmp1 = phi i32 [%sink.sub, %ContLoop], [%sink.sub, %Loop]
+ %tmp2 = phi i32 [%dec, %ContLoop], [%sink.sub, %Loop]
+ %add = add i32 %tmp1, %tmp2
+ ret i32 %add
+}
+
+; Do not sink an instruction through a non-trivially replacable PHI, to avoid
+; assert while splitting predecessors, if the terminator of predecessor is an
+; indirectbr.
+; CHECK-LABEL: @test19
+; CHECK-LABEL: L0:
+; CHECK: %sinkable = mul
+; CHECK: %sinkable2 = add
+
+define i32 @test19(i1 %cond, i1 %cond2, i8* %address, i32 %v1) nounwind {
+entry:
+ br label %L0
+L0:
+ %indirect.goto.dest = select i1 %cond, i8* blockaddress(@test19, %exit), i8* %address
+ %v2 = call i32 @getv()
+ %sinkable = mul i32 %v1, %v2
+ %sinkable2 = add i32 %v1, %v2
+ indirectbr i8* %indirect.goto.dest, [label %L1, label %exit]
+
+L1:
+ %indirect.goto.dest2 = select i1 %cond2, i8* blockaddress(@test19, %exit), i8* %address
+ indirectbr i8* %indirect.goto.dest2, [label %L0, label %exit]
+
+exit:
+ %r = phi i32 [%sinkable, %L0], [%sinkable2, %L1]
+ ret i32 %r
+}
+
+; Do not sink through a non-trivially replacable PHI if splitting predecessors
+; not allowed in SplitBlockPredecessors().
+;
+; CHECK-LABEL: @test20
+; CHECK-LABEL: while.cond
+; CHECK: %sinkable = mul
+; CHECK: %sinkable2 = add
+define void @test20(i32* %s, i1 %b, i32 %v1, i32 %v2) personality i32 (...)* @__CxxFrameHandler3 {
+entry:
+ br label %while.cond
+while.cond:
+ %v = call i32 @getv()
+ %sinkable = mul i32 %v, %v2
+ %sinkable2 = add i32 %v, %v2
+ br i1 %b, label %try.cont, label %while.body
+while.body:
+ invoke void @may_throw()
+ to label %while.body2 unwind label %catch.dispatch
+while.body2:
+ invoke void @may_throw2()
+ to label %while.cond unwind label %catch.dispatch
+catch.dispatch:
+ %.lcssa1 = phi i32 [ %sinkable, %while.body ], [ %sinkable2, %while.body2 ]
+ %cp = cleanuppad within none []
+ store i32 %.lcssa1, i32* %s
+ cleanupret from %cp unwind to caller
+try.cont:
+ ret void
+}
+
+declare void @may_throw()
+declare void @may_throw2()
+declare i32 @__CxxFrameHandler3(...)
+declare i32 @getv()
+declare i1 @getc()
+declare void @f(i32*)
declare void @g()
OpenPOWER on IntegriCloud