diff options
Diffstat (limited to 'llvm/test/Transforms/SimpleLoopUnswitch/trivial-unswitch.ll')
-rw-r--r-- | llvm/test/Transforms/SimpleLoopUnswitch/trivial-unswitch.ll | 1245 |
1 files changed, 0 insertions, 1245 deletions
diff --git a/llvm/test/Transforms/SimpleLoopUnswitch/trivial-unswitch.ll b/llvm/test/Transforms/SimpleLoopUnswitch/trivial-unswitch.ll deleted file mode 100644 index 56a9bac8980..00000000000 --- a/llvm/test/Transforms/SimpleLoopUnswitch/trivial-unswitch.ll +++ /dev/null @@ -1,1245 +0,0 @@ -; RUN: opt -passes='loop(unswitch),verify<loops>' -S < %s | FileCheck %s -; RUN: opt -enable-mssa-loop-dependency=true -verify-memoryssa -passes='loop(unswitch),verify<loops>' -S < %s | FileCheck %s - -declare void @some_func() noreturn -declare void @sink(i32) - -declare i1 @cond() -declare i32 @cond.i32() - -; This test contains two trivial unswitch condition in one loop. -; LoopUnswitch pass should be able to unswitch the second one -; after unswitching the first one. -define i32 @test1(i32* %var, i1 %cond1, i1 %cond2) { -; CHECK-LABEL: @test1( -entry: - br label %loop_begin -; CHECK-NEXT: entry: -; CHECK-NEXT: br i1 %{{.*}}, label %entry.split, label %loop_exit.split -; -; CHECK: entry.split: -; CHECK-NEXT: br i1 %{{.*}}, 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 ; first trivial condition -; CHECK: loop_begin: -; CHECK-NEXT: br label %continue - -continue: - %var_val = load i32, i32* %var - br i1 %cond2, label %do_something, label %loop_exit ; second trivial condition -; CHECK: continue: -; CHECK-NEXT: load -; CHECK-NEXT: br 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: -; CHECK-NEXT: br label %loop_exit.split -; -; CHECK: loop_exit.split: -; CHECK-NEXT: ret -} - -; Test for two trivially unswitchable switches. -define i32 @test3(i32* %var, i32 %cond1, i32 %cond2) { -; CHECK-LABEL: @test3( -entry: - br label %loop_begin -; CHECK-NEXT: entry: -; CHECK-NEXT: switch i32 %cond1, label %entry.split [ -; CHECK-NEXT: i32 0, label %loop_exit1 -; CHECK-NEXT: ] -; -; CHECK: entry.split: -; CHECK-NEXT: switch i32 %cond2, label %loop_exit2 [ -; CHECK-NEXT: i32 42, label %loop_exit2 -; CHECK-NEXT: i32 0, label %entry.split.split -; CHECK-NEXT: ] -; -; CHECK: entry.split.split: -; CHECK-NEXT: br label %loop_begin - -loop_begin: - switch i32 %cond1, label %continue [ - i32 0, label %loop_exit1 - ] -; CHECK: loop_begin: -; CHECK-NEXT: br label %continue - -continue: - %var_val = load i32, i32* %var - switch i32 %cond2, label %loop_exit2 [ - i32 0, label %do_something - i32 42, label %loop_exit2 - ] -; CHECK: continue: -; CHECK-NEXT: load -; CHECK-NEXT: br 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_exit1: - ret i32 0 -; CHECK: loop_exit1: -; CHECK-NEXT: ret - -loop_exit2: - ret i32 0 -; CHECK: loop_exit2: -; CHECK-NEXT: ret -; -; We shouldn't have any unreachable blocks here because the unswitched switches -; turn into branches instead. -; CHECK-NOT: unreachable -} - -; Test for a trivially unswitchable switch with multiple exiting cases and -; multiple looping cases. -define i32 @test4(i32* %var, i32 %cond1, i32 %cond2) { -; CHECK-LABEL: @test4( -entry: - br label %loop_begin -; CHECK-NEXT: entry: -; CHECK-NEXT: switch i32 %cond2, label %loop_exit2 [ -; CHECK-NEXT: i32 13, label %loop_exit1 -; CHECK-NEXT: i32 42, label %loop_exit3 -; CHECK-NEXT: i32 0, label %entry.split -; CHECK-NEXT: i32 1, label %entry.split -; CHECK-NEXT: i32 2, label %entry.split -; CHECK-NEXT: ] -; -; CHECK: entry.split: -; CHECK-NEXT: br label %loop_begin - -loop_begin: - %var_val = load i32, i32* %var - switch i32 %cond2, label %loop_exit2 [ - i32 0, label %loop0 - i32 1, label %loop1 - i32 13, label %loop_exit1 - i32 2, label %loop2 - i32 42, label %loop_exit3 - ] -; CHECK: loop_begin: -; CHECK-NEXT: load -; CHECK-NEXT: switch i32 %cond2, label %loop2 [ -; CHECK-NEXT: i32 0, label %loop0 -; CHECK-NEXT: i32 1, label %loop1 -; CHECK-NEXT: ] - -loop0: - call void @some_func() noreturn nounwind - br label %loop_latch -; CHECK: loop0: -; CHECK-NEXT: call -; CHECK-NEXT: br label %loop_latch - -loop1: - call void @some_func() noreturn nounwind - br label %loop_latch -; CHECK: loop1: -; CHECK-NEXT: call -; CHECK-NEXT: br label %loop_latch - -loop2: - call void @some_func() noreturn nounwind - br label %loop_latch -; CHECK: loop2: -; CHECK-NEXT: call -; CHECK-NEXT: br label %loop_latch - -loop_latch: - br label %loop_begin -; CHECK: loop_latch: -; CHECK-NEXT: br label %loop_begin - -loop_exit1: - ret i32 0 -; CHECK: loop_exit1: -; CHECK-NEXT: ret - -loop_exit2: - ret i32 0 -; CHECK: loop_exit2: -; CHECK-NEXT: ret - -loop_exit3: - ret i32 0 -; CHECK: loop_exit3: -; CHECK-NEXT: ret -} - -; This test contains a trivially unswitchable branch with an LCSSA phi node in -; a loop exit block. -define i32 @test5(i1 %cond1, i32 %x, i32 %y) { -; CHECK-LABEL: @test5( -entry: - br label %loop_begin -; CHECK-NEXT: entry: -; CHECK-NEXT: br i1 %{{.*}}, label %entry.split, label %loop_exit -; -; CHECK: entry.split: -; CHECK-NEXT: br label %loop_begin - -loop_begin: - br i1 %cond1, label %latch, label %loop_exit -; CHECK: loop_begin: -; CHECK-NEXT: br label %latch - -latch: - call void @some_func() noreturn nounwind - br label %loop_begin -; CHECK: latch: -; CHECK-NEXT: call -; CHECK-NEXT: br label %loop_begin - -loop_exit: - %result1 = phi i32 [ %x, %loop_begin ] - %result2 = phi i32 [ %y, %loop_begin ] - %result = add i32 %result1, %result2 - ret i32 %result -; CHECK: loop_exit: -; CHECK-NEXT: %[[R1:.*]] = phi i32 [ %x, %entry ] -; CHECK-NEXT: %[[R2:.*]] = phi i32 [ %y, %entry ] -; CHECK-NEXT: %[[R:.*]] = add i32 %[[R1]], %[[R2]] -; CHECK-NEXT: ret i32 %[[R]] -} - -; This test contains a trivially unswitchable branch with a real phi node in LCSSA -; position in a shared exit block where a different path through the loop -; produces a non-invariant input to the PHI node. -define i32 @test6(i32* %var, i1 %cond1, i1 %cond2, i32 %x, i32 %y) { -; CHECK-LABEL: @test6( -entry: - br label %loop_begin -; CHECK-NEXT: entry: -; CHECK-NEXT: br i1 %{{.*}}, label %entry.split, label %loop_exit.split -; -; CHECK: entry.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 - br i1 %cond2, label %latch, label %loop_exit -; CHECK: continue: -; CHECK-NEXT: load -; CHECK-NEXT: br i1 %cond2, label %latch, label %loop_exit - -latch: - call void @some_func() noreturn nounwind - br label %loop_begin -; CHECK: latch: -; CHECK-NEXT: call -; CHECK-NEXT: br label %loop_begin - -loop_exit: - %result1 = phi i32 [ %x, %loop_begin ], [ %var_val, %continue ] - %result2 = phi i32 [ %var_val, %continue ], [ %y, %loop_begin ] - %result = add i32 %result1, %result2 - ret i32 %result -; CHECK: loop_exit: -; CHECK-NEXT: %[[R1:.*]] = phi i32 [ %var_val, %continue ] -; CHECK-NEXT: %[[R2:.*]] = phi i32 [ %var_val, %continue ] -; CHECK-NEXT: br label %loop_exit.split -; -; CHECK: loop_exit.split: -; CHECK-NEXT: %[[R1S:.*]] = phi i32 [ %x, %entry ], [ %[[R1]], %loop_exit ] -; CHECK-NEXT: %[[R2S:.*]] = phi i32 [ %y, %entry ], [ %[[R2]], %loop_exit ] -; CHECK-NEXT: %[[R:.*]] = add i32 %[[R1S]], %[[R2S]] -; CHECK-NEXT: ret i32 %[[R]] -} - -; This test contains a trivially unswitchable switch with an LCSSA phi node in -; a loop exit block. -define i32 @test7(i32 %cond1, i32 %x, i32 %y) { -; CHECK-LABEL: @test7( -entry: - br label %loop_begin -; CHECK-NEXT: entry: -; CHECK-NEXT: switch i32 %cond1, label %entry.split [ -; CHECK-NEXT: i32 0, label %loop_exit -; CHECK-NEXT: i32 1, label %loop_exit -; CHECK-NEXT: ] -; -; CHECK: entry.split: -; CHECK-NEXT: br label %loop_begin - -loop_begin: - switch i32 %cond1, label %latch [ - i32 0, label %loop_exit - i32 1, label %loop_exit - ] -; CHECK: loop_begin: -; CHECK-NEXT: br label %latch - -latch: - call void @some_func() noreturn nounwind - br label %loop_begin -; CHECK: latch: -; CHECK-NEXT: call -; CHECK-NEXT: br label %loop_begin - -loop_exit: - %result1 = phi i32 [ %x, %loop_begin ], [ %x, %loop_begin ] - %result2 = phi i32 [ %y, %loop_begin ], [ %y, %loop_begin ] - %result = add i32 %result1, %result2 - ret i32 %result -; CHECK: loop_exit: -; CHECK-NEXT: %[[R1:.*]] = phi i32 [ %x, %entry ], [ %x, %entry ] -; CHECK-NEXT: %[[R2:.*]] = phi i32 [ %y, %entry ], [ %y, %entry ] -; CHECK-NEXT: %[[R:.*]] = add i32 %[[R1]], %[[R2]] -; CHECK-NEXT: ret i32 %[[R]] -} - -; This test contains a trivially unswitchable switch with a real phi node in -; LCSSA position in a shared exit block where a different path through the loop -; produces a non-invariant input to the PHI node. -define i32 @test8(i32* %var, i32 %cond1, i32 %cond2, i32 %x, i32 %y) { -; CHECK-LABEL: @test8( -entry: - br label %loop_begin -; CHECK-NEXT: entry: -; CHECK-NEXT: switch i32 %cond1, label %entry.split [ -; CHECK-NEXT: i32 0, label %loop_exit.split -; CHECK-NEXT: i32 1, label %loop_exit2 -; CHECK-NEXT: i32 2, label %loop_exit.split -; CHECK-NEXT: ] -; -; CHECK: entry.split: -; CHECK-NEXT: br label %loop_begin - -loop_begin: - switch i32 %cond1, label %continue [ - i32 0, label %loop_exit - i32 1, label %loop_exit2 - i32 2, label %loop_exit - ] -; CHECK: loop_begin: -; CHECK-NEXT: br label %continue - -continue: - %var_val = load i32, i32* %var - switch i32 %cond2, label %latch [ - i32 0, label %loop_exit - ] -; CHECK: continue: -; CHECK-NEXT: load -; CHECK-NEXT: switch i32 %cond2, label %latch [ -; CHECK-NEXT: i32 0, label %loop_exit -; CHECK-NEXT: ] - -latch: - call void @some_func() noreturn nounwind - br label %loop_begin -; CHECK: latch: -; CHECK-NEXT: call -; CHECK-NEXT: br label %loop_begin - -loop_exit: - %result1.1 = phi i32 [ %x, %loop_begin ], [ %x, %loop_begin ], [ %var_val, %continue ] - %result1.2 = phi i32 [ %var_val, %continue ], [ %y, %loop_begin ], [ %y, %loop_begin ] - %result1 = add i32 %result1.1, %result1.2 - ret i32 %result1 -; CHECK: loop_exit: -; CHECK-NEXT: %[[R1:.*]] = phi i32 [ %var_val, %continue ] -; CHECK-NEXT: %[[R2:.*]] = phi i32 [ %var_val, %continue ] -; CHECK-NEXT: br label %loop_exit.split -; -; CHECK: loop_exit.split: -; CHECK-NEXT: %[[R1S:.*]] = phi i32 [ %x, %entry ], [ %x, %entry ], [ %[[R1]], %loop_exit ] -; CHECK-NEXT: %[[R2S:.*]] = phi i32 [ %y, %entry ], [ %y, %entry ], [ %[[R2]], %loop_exit ] -; CHECK-NEXT: %[[R:.*]] = add i32 %[[R1S]], %[[R2S]] -; CHECK-NEXT: ret i32 %[[R]] - -loop_exit2: - %result2.1 = phi i32 [ %x, %loop_begin ] - %result2.2 = phi i32 [ %y, %loop_begin ] - %result2 = add i32 %result2.1, %result2.2 - ret i32 %result2 -; CHECK: loop_exit2: -; CHECK-NEXT: %[[R1:.*]] = phi i32 [ %x, %entry ] -; CHECK-NEXT: %[[R2:.*]] = phi i32 [ %y, %entry ] -; CHECK-NEXT: %[[R:.*]] = add i32 %[[R1]], %[[R2]] -; CHECK-NEXT: ret i32 %[[R]] -} - -; This test, extracted from the LLVM test suite, has an interesting dominator -; tree to update as there are edges to sibling domtree nodes within child -; domtree nodes of the unswitched node. -define void @xgets(i1 %cond1, i1* %cond2.ptr) { -; CHECK-LABEL: @xgets( -entry: - br label %for.cond.preheader -; CHECK: entry: -; CHECK-NEXT: br label %for.cond.preheader - -for.cond.preheader: - br label %for.cond -; CHECK: for.cond.preheader: -; CHECK-NEXT: br i1 %cond1, label %for.cond.preheader.split, label %if.end17.thread.loopexit -; -; CHECK: for.cond.preheader.split: -; CHECK-NEXT: br label %for.cond - -for.cond: - br i1 %cond1, label %land.lhs.true, label %if.end17.thread.loopexit -; CHECK: for.cond: -; CHECK-NEXT: br label %land.lhs.true - -land.lhs.true: - br label %if.then20 -; CHECK: land.lhs.true: -; CHECK-NEXT: br label %if.then20 - -if.then20: - %cond2 = load volatile i1, i1* %cond2.ptr - br i1 %cond2, label %if.then23, label %if.else -; CHECK: if.then20: -; CHECK-NEXT: %[[COND2:.*]] = load volatile i1, i1* %cond2.ptr -; CHECK-NEXT: br i1 %[[COND2]], label %if.then23, label %if.else - -if.else: - br label %for.cond -; CHECK: if.else: -; CHECK-NEXT: br label %for.cond - -if.end17.thread.loopexit: - br label %if.end17.thread -; CHECK: if.end17.thread.loopexit: -; CHECK-NEXT: br label %if.end17.thread - -if.end17.thread: - br label %cleanup -; CHECK: if.end17.thread: -; CHECK-NEXT: br label %cleanup - -if.then23: - br label %cleanup -; CHECK: if.then23: -; CHECK-NEXT: br label %cleanup - -cleanup: - ret void -; 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]] -} - -; Unswitch will not actually change the loop nest from: -; A < B < C -define void @hoist_inner_loop0() { -; CHECK-LABEL: define void @hoist_inner_loop0( -entry: - br label %a.header -; CHECK: entry: -; CHECK-NEXT: br label %a.header - -a.header: - br label %b.header -; CHECK: a.header: -; CHECK-NEXT: br label %b.header - -b.header: - %v1 = call i1 @cond() - br label %c.header -; CHECK: b.header: -; CHECK-NEXT: %v1 = call i1 @cond() -; CHECK-NEXT: br i1 %v1, label %[[B_LATCH_SPLIT:.*]], label %[[B_HEADER_SPLIT:.*]] -; -; CHECK: [[B_HEADER_SPLIT]]: -; CHECK-NEXT: br label %c.header - -c.header: - br i1 %v1, label %b.latch, label %c.latch -; CHECK: c.header: -; CHECK-NEXT: br label %c.latch - -c.latch: - %v2 = call i1 @cond() - br i1 %v2, label %c.header, label %b.latch -; CHECK: c.latch: -; CHECK-NEXT: %v2 = call i1 @cond() -; CHECK-NEXT: br i1 %v2, label %c.header, label %b.latch - -b.latch: - %v3 = call i1 @cond() - br i1 %v3, label %b.header, label %a.latch -; CHECK: b.latch: -; CHECK-NEXT: br label %[[B_LATCH_SPLIT]] -; -; CHECK: [[B_LATCH_SPLIT]]: -; CHECK-NEXT: %v3 = call i1 @cond() -; CHECK-NEXT: br i1 %v3, label %b.header, label %a.latch - -a.latch: - br label %a.header -; CHECK: a.latch: -; CHECK-NEXT: br label %a.header - -exit: - ret void -; CHECK: exit: -; CHECK-NEXT: ret void -} - -; Unswitch will transform the loop nest from: -; A < B < C -; into -; A < (B, C) -define void @hoist_inner_loop1(i32* %ptr) { -; CHECK-LABEL: define void @hoist_inner_loop1( -entry: - br label %a.header -; CHECK: entry: -; CHECK-NEXT: br label %a.header - -a.header: - %x.a = load i32, i32* %ptr - br label %b.header -; CHECK: a.header: -; CHECK-NEXT: %x.a = load i32, i32* %ptr -; CHECK-NEXT: br label %b.header - -b.header: - %x.b = load i32, i32* %ptr - %v1 = call i1 @cond() - br label %c.header -; CHECK: b.header: -; CHECK-NEXT: %x.b = load i32, i32* %ptr -; CHECK-NEXT: %v1 = call i1 @cond() -; CHECK-NEXT: br i1 %v1, label %b.latch, label %[[B_HEADER_SPLIT:.*]] -; -; CHECK: [[B_HEADER_SPLIT]]: -; CHECK-NEXT: %[[X_B_LCSSA:.*]] = phi i32 [ %x.b, %b.header ] -; CHECK-NEXT: br label %c.header - -c.header: - br i1 %v1, label %b.latch, label %c.latch -; CHECK: c.header: -; CHECK-NEXT: br label %c.latch - -c.latch: - ; Use values from other loops to check LCSSA form. - store i32 %x.a, i32* %ptr - store i32 %x.b, i32* %ptr - %v2 = call i1 @cond() - br i1 %v2, label %c.header, label %a.exit.c -; CHECK: c.latch: -; CHECK-NEXT: store i32 %x.a, i32* %ptr -; CHECK-NEXT: store i32 %[[X_B_LCSSA]], i32* %ptr -; CHECK-NEXT: %v2 = call i1 @cond() -; CHECK-NEXT: br i1 %v2, label %c.header, label %a.exit.c - -b.latch: - %v3 = call i1 @cond() - br i1 %v3, label %b.header, label %a.exit.b -; CHECK: b.latch: -; CHECK-NEXT: %v3 = call i1 @cond() -; CHECK-NEXT: br i1 %v3, label %b.header, label %a.exit.b - -a.exit.c: - br label %a.latch -; CHECK: a.exit.c -; CHECK-NEXT: br label %a.latch - -a.exit.b: - br label %a.latch -; CHECK: a.exit.b: -; CHECK-NEXT: br label %a.latch - -a.latch: - br label %a.header -; CHECK: a.latch: -; CHECK-NEXT: br label %a.header - -exit: - ret void -; CHECK: exit: -; CHECK-NEXT: ret void -} - -; Unswitch will transform the loop nest from: -; A < B < C -; into -; (A < B), C -define void @hoist_inner_loop2(i32* %ptr) { -; CHECK-LABEL: define void @hoist_inner_loop2( -entry: - br label %a.header -; CHECK: entry: -; CHECK-NEXT: br label %a.header - -a.header: - %x.a = load i32, i32* %ptr - br label %b.header -; CHECK: a.header: -; CHECK-NEXT: %x.a = load i32, i32* %ptr -; CHECK-NEXT: br label %b.header - -b.header: - %x.b = load i32, i32* %ptr - %v1 = call i1 @cond() - br label %c.header -; CHECK: b.header: -; CHECK-NEXT: %x.b = load i32, i32* %ptr -; CHECK-NEXT: %v1 = call i1 @cond() -; CHECK-NEXT: br i1 %v1, label %b.latch, label %[[B_HEADER_SPLIT:.*]] -; -; CHECK: [[B_HEADER_SPLIT]]: -; CHECK-NEXT: %[[X_A_LCSSA:.*]] = phi i32 [ %x.a, %b.header ] -; CHECK-NEXT: %[[X_B_LCSSA:.*]] = phi i32 [ %x.b, %b.header ] -; CHECK-NEXT: br label %c.header - -c.header: - br i1 %v1, label %b.latch, label %c.latch -; CHECK: c.header: -; CHECK-NEXT: br label %c.latch - -c.latch: - ; Use values from other loops to check LCSSA form. - store i32 %x.a, i32* %ptr - store i32 %x.b, i32* %ptr - %v2 = call i1 @cond() - br i1 %v2, label %c.header, label %exit -; CHECK: c.latch: -; CHECK-NEXT: store i32 %[[X_A_LCSSA]], i32* %ptr -; CHECK-NEXT: store i32 %[[X_B_LCSSA]], i32* %ptr -; CHECK-NEXT: %v2 = call i1 @cond() -; CHECK-NEXT: br i1 %v2, label %c.header, label %exit - -b.latch: - %v3 = call i1 @cond() - br i1 %v3, label %b.header, label %a.latch -; CHECK: b.latch: -; CHECK-NEXT: %v3 = call i1 @cond() -; CHECK-NEXT: br i1 %v3, label %b.header, label %a.latch - -a.latch: - br label %a.header -; CHECK: a.latch: -; CHECK-NEXT: br label %a.header - -exit: - ret void -; CHECK: exit: -; CHECK-NEXT: ret void -} - -; Same as @hoist_inner_loop2 but with a nested loop inside the hoisted loop. -; Unswitch will transform the loop nest from: -; A < B < C < D -; into -; (A < B), (C < D) -define void @hoist_inner_loop3(i32* %ptr) { -; CHECK-LABEL: define void @hoist_inner_loop3( -entry: - br label %a.header -; CHECK: entry: -; CHECK-NEXT: br label %a.header - -a.header: - %x.a = load i32, i32* %ptr - br label %b.header -; CHECK: a.header: -; CHECK-NEXT: %x.a = load i32, i32* %ptr -; CHECK-NEXT: br label %b.header - -b.header: - %x.b = load i32, i32* %ptr - %v1 = call i1 @cond() - br label %c.header -; CHECK: b.header: -; CHECK-NEXT: %x.b = load i32, i32* %ptr -; CHECK-NEXT: %v1 = call i1 @cond() -; CHECK-NEXT: br i1 %v1, label %b.latch, label %[[B_HEADER_SPLIT:.*]] -; -; CHECK: [[B_HEADER_SPLIT]]: -; CHECK-NEXT: %[[X_A_LCSSA:.*]] = phi i32 [ %x.a, %b.header ] -; CHECK-NEXT: %[[X_B_LCSSA:.*]] = phi i32 [ %x.b, %b.header ] -; CHECK-NEXT: br label %c.header - -c.header: - br i1 %v1, label %b.latch, label %c.body -; CHECK: c.header: -; CHECK-NEXT: br label %c.body - -c.body: - %x.c = load i32, i32* %ptr - br label %d.header -; CHECK: c.body: -; CHECK-NEXT: %x.c = load i32, i32* %ptr -; CHECK-NEXT: br label %d.header - -d.header: - ; Use values from other loops to check LCSSA form. - store i32 %x.a, i32* %ptr - store i32 %x.b, i32* %ptr - store i32 %x.c, i32* %ptr - %v2 = call i1 @cond() - br i1 %v2, label %d.header, label %c.latch -; CHECK: d.header: -; CHECK-NEXT: store i32 %[[X_A_LCSSA]], i32* %ptr -; CHECK-NEXT: store i32 %[[X_B_LCSSA]], i32* %ptr -; CHECK-NEXT: store i32 %x.c, i32* %ptr -; CHECK-NEXT: %v2 = call i1 @cond() -; CHECK-NEXT: br i1 %v2, label %d.header, label %c.latch - -c.latch: - %v3 = call i1 @cond() - br i1 %v3, label %c.header, label %exit -; CHECK: c.latch: -; CHECK-NEXT: %v3 = call i1 @cond() -; CHECK-NEXT: br i1 %v3, label %c.header, label %exit - -b.latch: - %v4 = call i1 @cond() - br i1 %v4, label %b.header, label %a.latch -; CHECK: b.latch: -; CHECK-NEXT: %v4 = call i1 @cond() -; CHECK-NEXT: br i1 %v4, label %b.header, label %a.latch - -a.latch: - br label %a.header -; CHECK: a.latch: -; CHECK-NEXT: br label %a.header - -exit: - ret void -; CHECK: exit: -; CHECK-NEXT: ret void -} - -; This test is designed to exercise checking multiple remaining exits from the -; loop being unswitched. -; Unswitch will transform the loop nest from: -; A < B < C < D -; into -; A < B < (C, D) -define void @hoist_inner_loop4() { -; CHECK-LABEL: define void @hoist_inner_loop4( -entry: - br label %a.header -; CHECK: entry: -; CHECK-NEXT: br label %a.header - -a.header: - br label %b.header -; CHECK: a.header: -; CHECK-NEXT: br label %b.header - -b.header: - br label %c.header -; CHECK: b.header: -; CHECK-NEXT: br label %c.header - -c.header: - %v1 = call i1 @cond() - br label %d.header -; CHECK: c.header: -; CHECK-NEXT: %v1 = call i1 @cond() -; CHECK-NEXT: br i1 %v1, label %[[C_HEADER_SPLIT:.*]], label %c.latch -; -; CHECK: [[C_HEADER_SPLIT]]: -; CHECK-NEXT: br label %d.header - -d.header: - br i1 %v1, label %d.exiting1, label %c.latch -; CHECK: d.header: -; CHECK-NEXT: br label %d.exiting1 - -d.exiting1: - %v2 = call i1 @cond() - br i1 %v2, label %d.exiting2, label %a.latch -; CHECK: d.exiting1: -; CHECK-NEXT: %v2 = call i1 @cond() -; CHECK-NEXT: br i1 %v2, label %d.exiting2, label %a.latch - -d.exiting2: - %v3 = call i1 @cond() - br i1 %v3, label %d.exiting3, label %loopexit.d -; CHECK: d.exiting2: -; CHECK-NEXT: %v3 = call i1 @cond() -; CHECK-NEXT: br i1 %v3, label %d.exiting3, label %loopexit.d - -d.exiting3: - %v4 = call i1 @cond() - br i1 %v4, label %d.latch, label %b.latch -; CHECK: d.exiting3: -; CHECK-NEXT: %v4 = call i1 @cond() -; CHECK-NEXT: br i1 %v4, label %d.latch, label %b.latch - -d.latch: - br label %d.header -; CHECK: d.latch: -; CHECK-NEXT: br label %d.header - -c.latch: - %v5 = call i1 @cond() - br i1 %v5, label %c.header, label %loopexit.c -; CHECK: c.latch: -; CHECK-NEXT: %v5 = call i1 @cond() -; CHECK-NEXT: br i1 %v5, label %c.header, label %loopexit.c - -b.latch: - br label %b.header -; CHECK: b.latch: -; CHECK-NEXT: br label %b.header - -a.latch: - br label %a.header -; CHECK: a.latch: -; CHECK-NEXT: br label %a.header - -loopexit.d: - br label %exit -; CHECK: loopexit.d: -; CHECK-NEXT: br label %exit - -loopexit.c: - br label %exit -; CHECK: loopexit.c: -; CHECK-NEXT: br label %exit - -exit: - ret void -; CHECK: exit: -; CHECK-NEXT: ret void -} - -; Unswitch will transform the loop nest from: -; A < B < C < D -; into -; A < ((B < C), D) -define void @hoist_inner_loop5(i32* %ptr) { -; CHECK-LABEL: define void @hoist_inner_loop5( -entry: - br label %a.header -; CHECK: entry: -; CHECK-NEXT: br label %a.header - -a.header: - %x.a = load i32, i32* %ptr - br label %b.header -; CHECK: a.header: -; CHECK-NEXT: %x.a = load i32, i32* %ptr -; CHECK-NEXT: br label %b.header - -b.header: - %x.b = load i32, i32* %ptr - br label %c.header -; CHECK: b.header: -; CHECK-NEXT: %x.b = load i32, i32* %ptr -; CHECK-NEXT: br label %c.header - -c.header: - %x.c = load i32, i32* %ptr - %v1 = call i1 @cond() - br label %d.header -; CHECK: c.header: -; CHECK-NEXT: %x.c = load i32, i32* %ptr -; CHECK-NEXT: %v1 = call i1 @cond() -; CHECK-NEXT: br i1 %v1, label %c.latch, label %[[C_HEADER_SPLIT:.*]] -; -; CHECK: [[C_HEADER_SPLIT]]: -; CHECK-NEXT: %[[X_B_LCSSA:.*]] = phi i32 [ %x.b, %c.header ] -; CHECK-NEXT: %[[X_C_LCSSA:.*]] = phi i32 [ %x.c, %c.header ] -; CHECK-NEXT: br label %d.header - -d.header: - br i1 %v1, label %c.latch, label %d.latch -; CHECK: d.header: -; CHECK-NEXT: br label %d.latch - -d.latch: - ; Use values from other loops to check LCSSA form. - store i32 %x.a, i32* %ptr - store i32 %x.b, i32* %ptr - store i32 %x.c, i32* %ptr - %v2 = call i1 @cond() - br i1 %v2, label %d.header, label %a.latch -; CHECK: d.latch: -; CHECK-NEXT: store i32 %x.a, i32* %ptr -; CHECK-NEXT: store i32 %[[X_B_LCSSA]], i32* %ptr -; CHECK-NEXT: store i32 %[[X_C_LCSSA]], i32* %ptr -; CHECK-NEXT: %v2 = call i1 @cond() -; CHECK-NEXT: br i1 %v2, label %d.header, label %a.latch - -c.latch: - %v3 = call i1 @cond() - br i1 %v3, label %c.header, label %b.latch -; CHECK: c.latch: -; CHECK-NEXT: %v3 = call i1 @cond() -; CHECK-NEXT: br i1 %v3, label %c.header, label %b.latch - -b.latch: - br label %b.header -; CHECK: b.latch: -; CHECK-NEXT: br label %b.header - -a.latch: - br label %a.header -; CHECK: a.latch: -; CHECK-NEXT: br label %a.header - -exit: - ret void -; CHECK: exit: -; CHECK-NEXT: ret void -} - -; Same as `@hoist_inner_loop2` but using a switch. -; Unswitch will transform the loop nest from: -; A < B < C -; into -; (A < B), C -define void @hoist_inner_loop_switch(i32* %ptr) { -; CHECK-LABEL: define void @hoist_inner_loop_switch( -entry: - br label %a.header -; CHECK: entry: -; CHECK-NEXT: br label %a.header - -a.header: - %x.a = load i32, i32* %ptr - br label %b.header -; CHECK: a.header: -; CHECK-NEXT: %x.a = load i32, i32* %ptr -; CHECK-NEXT: br label %b.header - -b.header: - %x.b = load i32, i32* %ptr - %v1 = call i32 @cond.i32() - br label %c.header -; CHECK: b.header: -; CHECK-NEXT: %x.b = load i32, i32* %ptr -; CHECK-NEXT: %v1 = call i32 @cond.i32() -; CHECK-NEXT: switch i32 %v1, label %[[B_HEADER_SPLIT:.*]] [ -; CHECK-NEXT: i32 1, label %b.latch -; CHECK-NEXT: i32 2, label %b.latch -; CHECK-NEXT: i32 3, label %b.latch -; CHECK-NEXT: ] -; -; CHECK: [[B_HEADER_SPLIT]]: -; CHECK-NEXT: %[[X_A_LCSSA:.*]] = phi i32 [ %x.a, %b.header ] -; CHECK-NEXT: %[[X_B_LCSSA:.*]] = phi i32 [ %x.b, %b.header ] -; CHECK-NEXT: br label %c.header - -c.header: - switch i32 %v1, label %c.latch [ - i32 1, label %b.latch - i32 2, label %b.latch - i32 3, label %b.latch - ] -; CHECK: c.header: -; CHECK-NEXT: br label %c.latch - -c.latch: - ; Use values from other loops to check LCSSA form. - store i32 %x.a, i32* %ptr - store i32 %x.b, i32* %ptr - %v2 = call i1 @cond() - br i1 %v2, label %c.header, label %exit -; CHECK: c.latch: -; CHECK-NEXT: store i32 %[[X_A_LCSSA]], i32* %ptr -; CHECK-NEXT: store i32 %[[X_B_LCSSA]], i32* %ptr -; CHECK-NEXT: %v2 = call i1 @cond() -; CHECK-NEXT: br i1 %v2, label %c.header, label %exit - -b.latch: - %v3 = call i1 @cond() - br i1 %v3, label %b.header, label %a.latch -; CHECK: b.latch: -; CHECK-NEXT: %v3 = call i1 @cond() -; CHECK-NEXT: br i1 %v3, label %b.header, label %a.latch - -a.latch: - br label %a.header -; CHECK: a.latch: -; CHECK-NEXT: br label %a.header - -exit: - ret void -; CHECK: exit: -; CHECK-NEXT: ret void -} - -define void @test_unswitch_to_common_succ_with_phis(i32* %var, i32 %cond) { -; CHECK-LABEL: @test_unswitch_to_common_succ_with_phis( -entry: - br label %header -; CHECK-NEXT: entry: -; CHECK-NEXT: switch i32 %cond, label %loopexit1 [ -; CHECK-NEXT: i32 13, label %loopexit2 -; CHECK-NEXT: i32 0, label %entry.split -; CHECK-NEXT: i32 1, label %entry.split -; CHECK-NEXT: ] -; -; CHECK: entry.split: -; CHECK-NEXT: br label %header - -header: - %var_val = load i32, i32* %var - switch i32 %cond, label %loopexit1 [ - i32 0, label %latch - i32 1, label %latch - i32 13, label %loopexit2 - ] -; CHECK: header: -; CHECK-NEXT: load -; CHECK-NEXT: br label %latch - -latch: - ; No-op PHI node to exercise weird PHI update scenarios. - %phi = phi i32 [ %var_val, %header ], [ %var_val, %header ] - call void @sink(i32 %phi) - br label %header -; CHECK: latch: -; CHECK-NEXT: %[[PHI:.*]] = phi i32 [ %var_val, %header ] -; CHECK-NEXT: call void @sink(i32 %[[PHI]]) -; CHECK-NEXT: br label %header - -loopexit1: - ret void -; CHECK: loopexit1: -; CHECK-NEXT: ret - -loopexit2: - ret void -; CHECK: loopexit2: -; CHECK-NEXT: ret -} - -define void @test_unswitch_to_default_common_succ_with_phis(i32* %var, i32 %cond) { -; CHECK-LABEL: @test_unswitch_to_default_common_succ_with_phis( -entry: - br label %header -; CHECK-NEXT: entry: -; CHECK-NEXT: switch i32 %cond, label %entry.split [ -; CHECK-NEXT: i32 13, label %loopexit -; CHECK-NEXT: ] -; -; CHECK: entry.split: -; CHECK-NEXT: br label %header - -header: - %var_val = load i32, i32* %var - switch i32 %cond, label %latch [ - i32 0, label %latch - i32 1, label %latch - i32 13, label %loopexit - ] -; CHECK: header: -; CHECK-NEXT: load -; CHECK-NEXT: br label %latch - -latch: - ; No-op PHI node to exercise weird PHI update scenarios. - %phi = phi i32 [ %var_val, %header ], [ %var_val, %header ], [ %var_val, %header ] - call void @sink(i32 %phi) - br label %header -; CHECK: latch: -; CHECK-NEXT: %[[PHI:.*]] = phi i32 [ %var_val, %header ] -; CHECK-NEXT: call void @sink(i32 %[[PHI]]) -; CHECK-NEXT: br label %header - -loopexit: - ret void -; CHECK: loopexit: -; CHECK-NEXT: ret -} |