diff options
author | Chandler Carruth <chandlerc@gmail.com> | 2018-06-20 18:57:07 +0000 |
---|---|---|
committer | Chandler Carruth <chandlerc@gmail.com> | 2018-06-20 18:57:07 +0000 |
commit | 4da3331d3d77aaf0adb2ab3325405a72bdad1a5a (patch) | |
tree | 98d91a2df7d17d329b9d0d849084750d654b0794 /llvm/test/Transforms/SimpleLoopUnswitch | |
parent | 7170b5ae743b9f9c52776aad34e22b3fed85c1b4 (diff) | |
download | bcm5719-llvm-4da3331d3d77aaf0adb2ab3325405a72bdad1a5a.tar.gz bcm5719-llvm-4da3331d3d77aaf0adb2ab3325405a72bdad1a5a.zip |
[PM/LoopUnswitch] Support partial trivial unswitching.
The idea of partial unswitching is to take a *part* of a branch's
condition that is loop invariant and just unswitching that part. This
primarily makes sense with i1 conditions of branches as opposed to
switches. When dealing with i1 conditions, we can easily extract loop
invariant inputs to a a branch and unswitch them to test them entirely
outside the loop.
As part of this, we now create much more significant cruft in the loop
body, so this relies on adding cleanup passes to the loop pipeline and
revisiting unswitched loops to do that cleanup before continuing to
process them.
This already appears to be more powerful at unswitching than the old
loop unswitch pass, and so I'd appreciate pretty careful review in case
I'm just missing some correctness checks. The `LIV-loop-condition` test
case is not unswitched by the old unswitch pass, but is with this pass.
Thanks to Sanjoy and Fedor for the review!
Differential Revision: https://reviews.llvm.org/D46706
llvm-svn: 335156
Diffstat (limited to 'llvm/test/Transforms/SimpleLoopUnswitch')
-rw-r--r-- | llvm/test/Transforms/SimpleLoopUnswitch/LIV-loop-condtion.ll | 16 | ||||
-rw-r--r-- | llvm/test/Transforms/SimpleLoopUnswitch/trivial-unswitch.ll | 176 |
2 files changed, 188 insertions, 4 deletions
diff --git a/llvm/test/Transforms/SimpleLoopUnswitch/LIV-loop-condtion.ll b/llvm/test/Transforms/SimpleLoopUnswitch/LIV-loop-condtion.ll index cbee0fef14b..03c23da6c96 100644 --- a/llvm/test/Transforms/SimpleLoopUnswitch/LIV-loop-condtion.ll +++ b/llvm/test/Transforms/SimpleLoopUnswitch/LIV-loop-condtion.ll @@ -4,17 +4,25 @@ ; itself is an LIV loop condition (not partial LIV which could occur in and/or). define i32 @test(i1 %cond1, i32 %var1) { +; CHECK-LABEL: define i32 @test( entry: br label %loop_begin +; CHECK-NEXT: entry: +; CHECK-NEXT: br i1 %cond1, label %entry.split, label %loop_exit.split +; +; CHECK: entry.split: +; CHECK-NEXT: br label %loop_begin loop_begin: %var3 = phi i32 [%var1, %entry], [%var2, %do_something] %cond2 = icmp eq i32 %var3, 10 %cond.and = and i1 %cond1, %cond2 - -; %cond.and only has %cond1 as LIV so no unswitch should happen. -; CHECK: br i1 %cond.and, label %do_something, label %loop_exit - br i1 %cond.and, label %do_something, label %loop_exit + br i1 %cond.and, label %do_something, label %loop_exit +; CHECK: loop_begin: +; CHECK-NEXT: %[[VAR3:.*]] = phi i32 +; CHECK-NEXT: %[[COND2:.*]] = icmp eq i32 %[[VAR3]], 10 +; CHECK-NEXT: %[[COND_AND:.*]] = and i1 true, %[[COND2]] +; CHECK-NEXT: br i1 %[[COND_AND]], label %do_something, label %loop_exit do_something: %var2 = add i32 %var3, 1 diff --git a/llvm/test/Transforms/SimpleLoopUnswitch/trivial-unswitch.ll b/llvm/test/Transforms/SimpleLoopUnswitch/trivial-unswitch.ll index a97e3f81a8e..572d2b6cf83 100644 --- a/llvm/test/Transforms/SimpleLoopUnswitch/trivial-unswitch.ll +++ b/llvm/test/Transforms/SimpleLoopUnswitch/trivial-unswitch.ll @@ -443,3 +443,179 @@ cleanup: ; CHECK: cleanup: ; CHECK-NEXT: ret void } + +define i32 @test_partial_condition_unswitch_and(i32* %var, i1 %cond1, i1 %cond2) { +; CHECK-LABEL: @test_partial_condition_unswitch_and( +entry: + br label %loop_begin +; CHECK-NEXT: entry: +; CHECK-NEXT: br i1 %cond1, label %entry.split, label %loop_exit.split +; +; CHECK: entry.split: +; CHECK-NEXT: br i1 %cond2, label %entry.split.split, label %loop_exit +; +; CHECK: entry.split.split: +; CHECK-NEXT: br label %loop_begin + +loop_begin: + br i1 %cond1, label %continue, label %loop_exit +; CHECK: loop_begin: +; CHECK-NEXT: br label %continue + +continue: + %var_val = load i32, i32* %var + %var_cond = trunc i32 %var_val to i1 + %cond_and = and i1 %var_cond, %cond2 + br i1 %cond_and, label %do_something, label %loop_exit +; CHECK: continue: +; CHECK-NEXT: %[[VAR:.*]] = load i32 +; CHECK-NEXT: %[[VAR_COND:.*]] = trunc i32 %[[VAR]] to i1 +; CHECK-NEXT: %[[COND_AND:.*]] = and i1 %[[VAR_COND]], true +; CHECK-NEXT: br i1 %[[COND_AND]], label %do_something, label %loop_exit + +do_something: + call void @some_func() noreturn nounwind + br label %loop_begin +; CHECK: do_something: +; CHECK-NEXT: call +; CHECK-NEXT: br label %loop_begin + +loop_exit: + ret i32 0 +; CHECK: loop_exit: +; CHECK-NEXT: br label %loop_exit.split +; +; CHECK: loop_exit.split: +; CHECK-NEXT: ret +} + +define i32 @test_partial_condition_unswitch_or(i32* %var, i1 %cond1, i1 %cond2, i1 %cond3, i1 %cond4, i1 %cond5, i1 %cond6) { +; CHECK-LABEL: @test_partial_condition_unswitch_or( +entry: + br label %loop_begin +; CHECK-NEXT: entry: +; CHECK-NEXT: %[[INV_OR1:.*]] = or i1 %cond4, %cond2 +; CHECK-NEXT: %[[INV_OR2:.*]] = or i1 %[[INV_OR1]], %cond3 +; CHECK-NEXT: %[[INV_OR3:.*]] = or i1 %[[INV_OR2]], %cond1 +; CHECK-NEXT: br i1 %[[INV_OR3]], label %loop_exit.split, label %entry.split +; +; CHECK: entry.split: +; CHECK-NEXT: br label %loop_begin + +loop_begin: + %var_val = load i32, i32* %var + %var_cond = trunc i32 %var_val to i1 + %cond_or1 = or i1 %var_cond, %cond1 + %cond_or2 = or i1 %cond2, %cond3 + %cond_or3 = or i1 %cond_or1, %cond_or2 + %cond_xor1 = xor i1 %cond5, %var_cond + %cond_and1 = and i1 %cond6, %var_cond + %cond_or4 = or i1 %cond_xor1, %cond_and1 + %cond_or5 = or i1 %cond_or3, %cond_or4 + %cond_or6 = or i1 %cond_or5, %cond4 + br i1 %cond_or6, label %loop_exit, label %do_something +; CHECK: loop_begin: +; CHECK-NEXT: %[[VAR:.*]] = load i32 +; CHECK-NEXT: %[[VAR_COND:.*]] = trunc i32 %[[VAR]] to i1 +; CHECK-NEXT: %[[COND_OR1:.*]] = or i1 %[[VAR_COND]], false +; CHECK-NEXT: %[[COND_OR2:.*]] = or i1 false, false +; CHECK-NEXT: %[[COND_OR3:.*]] = or i1 %[[COND_OR1]], %[[COND_OR2]] +; CHECK-NEXT: %[[COND_XOR:.*]] = xor i1 %cond5, %[[VAR_COND]] +; CHECK-NEXT: %[[COND_AND:.*]] = and i1 %cond6, %[[VAR_COND]] +; CHECK-NEXT: %[[COND_OR4:.*]] = or i1 %[[COND_XOR]], %[[COND_AND]] +; CHECK-NEXT: %[[COND_OR5:.*]] = or i1 %[[COND_OR3]], %[[COND_OR4]] +; CHECK-NEXT: %[[COND_OR6:.*]] = or i1 %[[COND_OR5]], false +; CHECK-NEXT: br i1 %[[COND_OR6]], label %loop_exit, label %do_something + +do_something: + call void @some_func() noreturn nounwind + br label %loop_begin +; CHECK: do_something: +; CHECK-NEXT: call +; CHECK-NEXT: br label %loop_begin + +loop_exit: + ret i32 0 +; CHECK: loop_exit.split: +; CHECK-NEXT: ret +} + +define i32 @test_partial_condition_unswitch_with_lcssa_phi1(i32* %var, i1 %cond, i32 %x) { +; CHECK-LABEL: @test_partial_condition_unswitch_with_lcssa_phi1( +entry: + br label %loop_begin +; CHECK-NEXT: entry: +; CHECK-NEXT: br i1 %cond, label %entry.split, label %loop_exit.split +; +; CHECK: entry.split: +; CHECK-NEXT: br label %loop_begin + +loop_begin: + %var_val = load i32, i32* %var + %var_cond = trunc i32 %var_val to i1 + %cond_and = and i1 %var_cond, %cond + br i1 %cond_and, label %do_something, label %loop_exit +; CHECK: loop_begin: +; CHECK-NEXT: %[[VAR:.*]] = load i32 +; CHECK-NEXT: %[[VAR_COND:.*]] = trunc i32 %[[VAR]] to i1 +; CHECK-NEXT: %[[COND_AND:.*]] = and i1 %[[VAR_COND]], true +; CHECK-NEXT: br i1 %[[COND_AND]], label %do_something, label %loop_exit + +do_something: + call void @some_func() noreturn nounwind + br label %loop_begin +; CHECK: do_something: +; CHECK-NEXT: call +; CHECK-NEXT: br label %loop_begin + +loop_exit: + %x.lcssa = phi i32 [ %x, %loop_begin ] + ret i32 %x.lcssa +; CHECK: loop_exit: +; CHECK-NEXT: %[[LCSSA:.*]] = phi i32 [ %x, %loop_begin ] +; CHECK-NEXT: br label %loop_exit.split +; +; CHECK: loop_exit.split: +; CHECK-NEXT: %[[LCSSA_SPLIT:.*]] = phi i32 [ %x, %entry ], [ %[[LCSSA]], %loop_exit ] +; CHECK-NEXT: ret i32 %[[LCSSA_SPLIT]] +} + +define i32 @test_partial_condition_unswitch_with_lcssa_phi2(i32* %var, i1 %cond, i32 %x, i32 %y) { +; CHECK-LABEL: @test_partial_condition_unswitch_with_lcssa_phi2( +entry: + br label %loop_begin +; CHECK-NEXT: entry: +; CHECK-NEXT: br i1 %cond, label %entry.split, label %loop_exit.split +; +; CHECK: entry.split: +; CHECK-NEXT: br label %loop_begin + +loop_begin: + %var_val = load i32, i32* %var + %var_cond = trunc i32 %var_val to i1 + %cond_and = and i1 %var_cond, %cond + br i1 %cond_and, label %do_something, label %loop_exit +; CHECK: loop_begin: +; CHECK-NEXT: %[[VAR:.*]] = load i32 +; CHECK-NEXT: %[[VAR_COND:.*]] = trunc i32 %[[VAR]] to i1 +; CHECK-NEXT: %[[COND_AND:.*]] = and i1 %[[VAR_COND]], true +; CHECK-NEXT: br i1 %[[COND_AND]], label %do_something, label %loop_exit + +do_something: + call void @some_func() noreturn nounwind + br i1 %var_cond, label %loop_begin, label %loop_exit +; CHECK: do_something: +; CHECK-NEXT: call +; CHECK-NEXT: br i1 %[[VAR_COND]], label %loop_begin, label %loop_exit + +loop_exit: + %xy.lcssa = phi i32 [ %x, %loop_begin ], [ %y, %do_something ] + ret i32 %xy.lcssa +; CHECK: loop_exit: +; CHECK-NEXT: %[[LCSSA:.*]] = phi i32 [ %x, %loop_begin ], [ %y, %do_something ] +; CHECK-NEXT: br label %loop_exit.split +; +; CHECK: loop_exit.split: +; CHECK-NEXT: %[[LCSSA_SPLIT:.*]] = phi i32 [ %x, %entry ], [ %[[LCSSA]], %loop_exit ] +; CHECK-NEXT: ret i32 %[[LCSSA_SPLIT]] +} |