summaryrefslogtreecommitdiffstats
path: root/llvm/test/Transforms/SimpleLoopUnswitch
diff options
context:
space:
mode:
authorFedor Sergeev <fedor.sergeev@azul.com>2018-11-07 20:05:11 +0000
committerFedor Sergeev <fedor.sergeev@azul.com>2018-11-07 20:05:11 +0000
commitf9a02a7006f27c14a8ac69d380649fbddfb72538 (patch)
treed31ae6fcc843b5a997efb78e82d08c199cb259e8 /llvm/test/Transforms/SimpleLoopUnswitch
parentdf5b09b8ce2e6ceafbb861afba356c39b8fb5ea0 (diff)
downloadbcm5719-llvm-f9a02a7006f27c14a8ac69d380649fbddfb72538.tar.gz
bcm5719-llvm-f9a02a7006f27c14a8ac69d380649fbddfb72538.zip
[SimpleLoopUnswitch] partial unswitch needs to be careful when replacing invariants with constants
When partial unswitch operates on multiple conditions at once, .e.g: if (Cond1 || Cond2 || NonInv) ... it should infer (and replace) values for individual conditions only on one side of unswitch and not another. More precisely only these derivations hold true: (Cond1 || Cond2) == false => Cond1 == Cond2 == false (Cond1 && Cond2) == true => Cond1 == Cond2 == true By the way we organize unswitching it means only replacing on "continue" blocks and never on "unswitched" ones. Since trivial unswitch does not have "unswitched" blocks it does not have this problem. Fixes PR 39568. Reviewers: chandlerc, asbirlea Differential Revision: https://reviews.llvm.org/D54211 llvm-svn: 346350
Diffstat (limited to 'llvm/test/Transforms/SimpleLoopUnswitch')
-rw-r--r--llvm/test/Transforms/SimpleLoopUnswitch/nontrivial-unswitch.ll109
1 files changed, 98 insertions, 11 deletions
diff --git a/llvm/test/Transforms/SimpleLoopUnswitch/nontrivial-unswitch.ll b/llvm/test/Transforms/SimpleLoopUnswitch/nontrivial-unswitch.ll
index fc8cd5be25c..367d6fe28e9 100644
--- a/llvm/test/Transforms/SimpleLoopUnswitch/nontrivial-unswitch.ll
+++ b/llvm/test/Transforms/SimpleLoopUnswitch/nontrivial-unswitch.ll
@@ -2796,10 +2796,10 @@ loop_begin:
; CHECK: loop_begin.us:
; CHECK-NEXT: %[[V1_US:.*]] = load i1, i1* %ptr1
; CHECK-NEXT: %[[V2_US:.*]] = load i1, i1* %ptr2
-; CHECK-NEXT: %[[AND1_US:.*]] = and i1 %[[V1_US]], false
+; CHECK-NEXT: %[[AND1_US:.*]] = and i1 %[[V1_US]], %cond1
; CHECK-NEXT: %[[OR1_US:.*]] = or i1 %[[V2_US]], %cond2
; CHECK-NEXT: %[[AND2_US:.*]] = and i1 %[[AND1_US]], %[[OR1_US]]
-; CHECK-NEXT: %[[AND3_US:.*]] = and i1 %[[AND2_US]], false
+; CHECK-NEXT: %[[AND3_US:.*]] = and i1 %[[AND2_US]], %cond3
; CHECK-NEXT: br label %loop_b.us
;
; CHECK: loop_b.us:
@@ -2857,12 +2857,99 @@ loop_exit:
; CHECK-NEXT: ret
}
-; Non-trivial unswitching of a switch.
-define i32 @test27(i1* %ptr, i32 %cond) {
+; Non-trivial partial loop unswitching of multiple invariant inputs to an `or`
+; chain. Basically an inverted version of corresponding `and` test (test26).
+define i32 @test27(i1* %ptr1, i1* %ptr2, i1* %ptr3, i1 %cond1, i1 %cond2, i1 %cond3) {
; CHECK-LABEL: @test27(
entry:
br label %loop_begin
; CHECK-NEXT: entry:
+; CHECK-NEXT: %[[INV_OR:.*]] = or i1 %cond3, %cond1
+; CHECK-NEXT: br i1 %[[INV_OR]], label %entry.split.us, label %entry.split
+
+loop_begin:
+ %v1 = load i1, i1* %ptr1
+ %v2 = load i1, i1* %ptr2
+ %cond_or1 = or i1 %v1, %cond1
+ %cond_and1 = and i1 %v2, %cond2
+ %cond_or2 = or i1 %cond_or1, %cond_and1
+ %cond_or3 = or i1 %cond_or2, %cond3
+ br i1 %cond_or3, label %loop_b, label %loop_a
+; The 'loop_b' unswitched loop.
+;
+; CHECK: entry.split.us:
+; CHECK-NEXT: br label %loop_begin.us
+;
+; CHECK: loop_begin.us:
+; CHECK-NEXT: %[[V1_US:.*]] = load i1, i1* %ptr1
+; CHECK-NEXT: %[[V2_US:.*]] = load i1, i1* %ptr2
+; CHECK-NEXT: %[[OR1_US:.*]] = or i1 %[[V1_US]], %cond1
+; CHECK-NEXT: %[[AND1_US:.*]] = and i1 %[[V2_US]], %cond2
+; CHECK-NEXT: %[[OR2_US:.*]] = or i1 %[[OR1_US]], %[[AND1_US]]
+; CHECK-NEXT: %[[OR3_US:.*]] = or i1 %[[OR2_US]], %cond3
+; CHECK-NEXT: br label %loop_b.us
+;
+; CHECK: loop_b.us:
+; CHECK-NEXT: call i32 @b()
+; CHECK-NEXT: br label %latch.us
+;
+; CHECK: latch.us:
+; CHECK-NEXT: %[[V3_US:.*]] = load i1, i1* %ptr3
+; CHECK-NEXT: br i1 %[[V3_US]], label %loop_begin.us, label %loop_exit.split.us
+;
+; CHECK: loop_exit.split.us:
+; CHECK-NEXT: br label %loop_exit
+
+; The original loop.
+;
+; CHECK: entry.split:
+; CHECK-NEXT: br label %loop_begin
+;
+; CHECK: loop_begin:
+; CHECK-NEXT: %[[V1:.*]] = load i1, i1* %ptr1
+; CHECK-NEXT: %[[V2:.*]] = load i1, i1* %ptr2
+; CHECK-NEXT: %[[OR1:.*]] = or i1 %[[V1]], false
+; CHECK-NEXT: %[[AND1:.*]] = and i1 %[[V2]], %cond2
+; CHECK-NEXT: %[[OR2:.*]] = or i1 %[[OR1]], %[[AND1]]
+; CHECK-NEXT: %[[OR3:.*]] = or i1 %[[OR2]], false
+; CHECK-NEXT: br i1 %[[OR3]], label %loop_b, label %loop_a
+
+loop_a:
+ call i32 @a()
+ br label %latch
+; CHECK: loop_a:
+; CHECK-NEXT: call i32 @a()
+; CHECK-NEXT: br label %latch
+
+loop_b:
+ call i32 @b()
+ br label %latch
+; CHECK: loop_b:
+; CHECK-NEXT: call i32 @b()
+; CHECK-NEXT: br label %latch
+
+latch:
+ %v3 = load i1, i1* %ptr3
+ br i1 %v3, label %loop_begin, label %loop_exit
+; CHECK: latch:
+; CHECK-NEXT: %[[V3:.*]] = load i1, i1* %ptr3
+; CHECK-NEXT: br i1 %[[V3]], label %loop_begin, label %loop_exit.split
+
+loop_exit:
+ ret i32 0
+; CHECK: loop_exit.split:
+; CHECK-NEXT: br label %loop_exit
+;
+; CHECK: loop_exit:
+; CHECK-NEXT: ret
+}
+
+; Non-trivial unswitching of a switch.
+define i32 @test28(i1* %ptr, i32 %cond) {
+; CHECK-LABEL: @test28(
+entry:
+ br label %loop_begin
+; CHECK-NEXT: entry:
; CHECK-NEXT: switch i32 %cond, label %[[ENTRY_SPLIT_LATCH:.*]] [
; CHECK-NEXT: i32 0, label %[[ENTRY_SPLIT_A:.*]]
; CHECK-NEXT: i32 1, label %[[ENTRY_SPLIT_B:.*]]
@@ -2970,8 +3057,8 @@ loop_exit:
; can introduce multiple edges to successors. These need lots of special case
; handling as they get collapsed in many cases (domtree, the unswitch itself)
; but not in all cases (the PHI node operands).
-define i32 @test28(i32 %arg) {
-; CHECK-LABEL: @test28(
+define i32 @test29(i32 %arg) {
+; CHECK-LABEL: @test29(
entry:
br label %header
; CHECK-NEXT: entry:
@@ -3149,12 +3236,12 @@ exit:
; CHECK-NEXT: ret i32 %[[EXIT_PHI2]]
}
-; Similar to @test28 but designed to have one of the duplicate edges be
+; Similar to @test29 but designed to have one of the duplicate edges be
; a loop exit edge as those can in some cases be special. Among other things,
; this includes an LCSSA phi with multiple entries despite being a dedicated
; exit block.
-define i32 @test29(i32 %arg) {
-; CHECK-LABEL: define i32 @test29(
+define i32 @test30(i32 %arg) {
+; CHECK-LABEL: define i32 @test30(
entry:
br label %header
; CHECK-NEXT: entry:
@@ -3946,8 +4033,8 @@ exit:
; viable for unswitching the inner-most loop. This lets us check that the
; unswitching doesn't end up cycling infinitely even when the cycle is
; indirect and due to revisiting a loop after cloning.
-define void @test30(i32 %arg) {
-; CHECK-LABEL: define void @test30(
+define void @test31(i32 %arg) {
+; CHECK-LABEL: define void @test31(
entry:
br label %outer.header
; CHECK-NEXT: entry:
OpenPOWER on IntegriCloud