|  | ; RUN: opt -passes='loop(simple-loop-unswitch),verify<loops>' -S < %s | FileCheck %s | 
|  | ; RUN: opt -verify-memoryssa -passes='loop-mssa(simple-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(ptr %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, ptr %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(ptr %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, ptr %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(ptr %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, ptr %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(ptr %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, ptr %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(ptr %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, ptr %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, ptr %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, ptr %cond2.ptr | 
|  | br i1 %cond2, label %if.then23, label %if.else | 
|  | ; CHECK:       if.then20: | 
|  | ; CHECK-NEXT:    %[[COND2:.*]] = load volatile i1, ptr %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(ptr %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:    [[FROZEN:%.+]] = freeze i1 %cond2 | 
|  | ; CHECK-NEXT:    br i1 [[FROZEN]], 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, ptr %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_and_select(ptr %var, i1 %cond1, i1 %cond2) { | 
|  | ; CHECK-LABEL: @test_partial_condition_unswitch_and_select( | 
|  | 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:    [[FROZEN:%.+]] = freeze i1 %cond2 | 
|  | ; CHECK-NEXT:    br i1 [[FROZEN]], 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, ptr %var | 
|  | %var_cond = trunc i32 %var_val to i1 | 
|  | %cond_and = select i1 %var_cond, i1 %cond2, i1 false | 
|  | 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:.*]] = select i1 %[[VAR_COND]], i1 true, i1 false | 
|  | ; 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_simple_select(ptr %var, i1 %cond1, i1 %cond2) { | 
|  | ; CHECK-LABEL: @test_partial_condition_unswitch_or_simple_select( | 
|  | 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:    [[FROZEN:%.+]] = freeze i1 %cond2 | 
|  | ; CHECK-NEXT:    br i1 [[FROZEN]], label %loop_exit.split1, label %entry.split.split | 
|  | ; | 
|  | ; 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, ptr %var | 
|  | %var_cond = trunc i32 %var_val to i1 | 
|  | %cond_or = select i1 %var_cond, i1 true, i1 %cond2 | 
|  | br i1 %cond_or, label %loop_exit, label %do_something | 
|  | ; CHECK:       continue: | 
|  | ; CHECK-NEXT:    %[[VAR:.*]] = load i32 | 
|  | ; CHECK-NEXT:    %[[VAR_COND:.*]] = trunc i32 %[[VAR]] to i1 | 
|  | ; CHECK-NEXT:    %[[COND_OR:.*]] = select i1 %[[VAR_COND]], i1 true, i1 false | 
|  | ; CHECK-NEXT:    br i1 %[[COND_OR]], 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: | 
|  | ; CHECK-NEXT:    br label %loop_exit.split1 | 
|  | ; | 
|  | ; CHECK:       loop_exit.split1: | 
|  | ; CHECK-NEXT:    br label %loop_exit.split | 
|  | ; | 
|  | ; CHECK:       loop_exit.split: | 
|  | ; CHECK-NEXT:    ret | 
|  | } | 
|  |  | 
|  | define i32 @test_partial_condition_unswitch_or(ptr %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:    %[[C4_FR:.+]] = freeze i1 %cond4 | 
|  | ; CHECK-NEXT:    %[[C2_FR:.+]] = freeze i1 %cond2 | 
|  | ; CHECK-NEXT:    %[[C3_FR:.+]] = freeze i1 %cond3 | 
|  | ; CHECK-NEXT:    %[[C1_FR:.+]] = freeze i1 %cond1 | 
|  | ; CHECK-NEXT:    %[[INV_OR1:.*]] = or i1 %[[C4_FR]], %[[C2_FR]] | 
|  | ; CHECK-NEXT:    %[[INV_OR2:.*]] = or i1 %[[INV_OR1]], %[[C3_FR]] | 
|  | ; CHECK-NEXT:    %[[INV_OR3:.*]] = or i1 %[[INV_OR2]], %[[C1_FR]] | 
|  | ; 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, ptr %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(ptr %var, i1 %cond, i32 %x) { | 
|  | ; CHECK-LABEL: @test_partial_condition_unswitch_with_lcssa_phi1( | 
|  | entry: | 
|  | br label %loop_begin | 
|  | ; CHECK-NEXT:  entry: | 
|  | ; CHECK-NEXT:    [[FROZEN:%.+]] = freeze i1 %cond | 
|  | ; CHECK-NEXT:    br i1 [[FROZEN]], label %entry.split, label %loop_exit.split | 
|  | ; | 
|  | ; CHECK:       entry.split: | 
|  | ; CHECK-NEXT:    br label %loop_begin | 
|  |  | 
|  | loop_begin: | 
|  | %var_val = load i32, ptr %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(ptr %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:    [[FROZEN:%.+]] = freeze i1 %cond | 
|  | ; CHECK-NEXT:    br i1 [[FROZEN]], label %entry.split, label %loop_exit.split | 
|  | ; | 
|  | ; CHECK:       entry.split: | 
|  | ; CHECK-NEXT:    br label %loop_begin | 
|  |  | 
|  | loop_begin: | 
|  | %var_val = load i32, ptr %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(ptr %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, ptr %ptr | 
|  | br label %b.header | 
|  | ; CHECK:       a.header: | 
|  | ; CHECK-NEXT:    %x.a = load i32, ptr %ptr | 
|  | ; CHECK-NEXT:    br label %b.header | 
|  |  | 
|  | b.header: | 
|  | %x.b = load i32, ptr %ptr | 
|  | %v1 = call i1 @cond() | 
|  | br label %c.header | 
|  | ; CHECK:       b.header: | 
|  | ; CHECK-NEXT:    %x.b = load i32, ptr %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, ptr %ptr | 
|  | store i32 %x.b, ptr %ptr | 
|  | %v2 = call i1 @cond() | 
|  | br i1 %v2, label %c.header, label %a.exit.c | 
|  | ; CHECK:       c.latch: | 
|  | ; CHECK-NEXT:    store i32 %x.a, ptr %ptr | 
|  | ; CHECK-NEXT:    store i32 %[[X_B_LCSSA]], ptr %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(ptr %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, ptr %ptr | 
|  | br label %b.header | 
|  | ; CHECK:       a.header: | 
|  | ; CHECK-NEXT:    %x.a = load i32, ptr %ptr | 
|  | ; CHECK-NEXT:    br label %b.header | 
|  |  | 
|  | b.header: | 
|  | %x.b = load i32, ptr %ptr | 
|  | %v1 = call i1 @cond() | 
|  | br label %c.header | 
|  | ; CHECK:       b.header: | 
|  | ; CHECK-NEXT:    %x.b = load i32, ptr %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, ptr %ptr | 
|  | store i32 %x.b, ptr %ptr | 
|  | %v2 = call i1 @cond() | 
|  | br i1 %v2, label %c.header, label %exit | 
|  | ; CHECK:       c.latch: | 
|  | ; CHECK-NEXT:    store i32 %[[X_A_LCSSA]], ptr %ptr | 
|  | ; CHECK-NEXT:    store i32 %[[X_B_LCSSA]], ptr %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(ptr %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, ptr %ptr | 
|  | br label %b.header | 
|  | ; CHECK:       a.header: | 
|  | ; CHECK-NEXT:    %x.a = load i32, ptr %ptr | 
|  | ; CHECK-NEXT:    br label %b.header | 
|  |  | 
|  | b.header: | 
|  | %x.b = load i32, ptr %ptr | 
|  | %v1 = call i1 @cond() | 
|  | br label %c.header | 
|  | ; CHECK:       b.header: | 
|  | ; CHECK-NEXT:    %x.b = load i32, ptr %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, ptr %ptr | 
|  | br label %d.header | 
|  | ; CHECK:       c.body: | 
|  | ; CHECK-NEXT:    %x.c = load i32, ptr %ptr | 
|  | ; CHECK-NEXT:    br label %d.header | 
|  |  | 
|  | d.header: | 
|  | ; Use values from other loops to check LCSSA form. | 
|  | store i32 %x.a, ptr %ptr | 
|  | store i32 %x.b, ptr %ptr | 
|  | store i32 %x.c, ptr %ptr | 
|  | %v2 = call i1 @cond() | 
|  | br i1 %v2, label %d.header, label %c.latch | 
|  | ; CHECK:       d.header: | 
|  | ; CHECK-NEXT:    store i32 %[[X_A_LCSSA]], ptr %ptr | 
|  | ; CHECK-NEXT:    store i32 %[[X_B_LCSSA]], ptr %ptr | 
|  | ; CHECK-NEXT:    store i32 %x.c, ptr %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(ptr %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, ptr %ptr | 
|  | br label %b.header | 
|  | ; CHECK:       a.header: | 
|  | ; CHECK-NEXT:    %x.a = load i32, ptr %ptr | 
|  | ; CHECK-NEXT:    br label %b.header | 
|  |  | 
|  | b.header: | 
|  | %x.b = load i32, ptr %ptr | 
|  | br label %c.header | 
|  | ; CHECK:       b.header: | 
|  | ; CHECK-NEXT:    %x.b = load i32, ptr %ptr | 
|  | ; CHECK-NEXT:    br label %c.header | 
|  |  | 
|  | c.header: | 
|  | %x.c = load i32, ptr %ptr | 
|  | %v1 = call i1 @cond() | 
|  | br label %d.header | 
|  | ; CHECK:       c.header: | 
|  | ; CHECK-NEXT:    %x.c = load i32, ptr %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, ptr %ptr | 
|  | store i32 %x.b, ptr %ptr | 
|  | store i32 %x.c, ptr %ptr | 
|  | %v2 = call i1 @cond() | 
|  | br i1 %v2, label %d.header, label %a.latch | 
|  | ; CHECK:       d.latch: | 
|  | ; CHECK-NEXT:    store i32 %x.a, ptr %ptr | 
|  | ; CHECK-NEXT:    store i32 %[[X_B_LCSSA]], ptr %ptr | 
|  | ; CHECK-NEXT:    store i32 %[[X_C_LCSSA]], ptr %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(ptr %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, ptr %ptr | 
|  | br label %b.header | 
|  | ; CHECK:       a.header: | 
|  | ; CHECK-NEXT:    %x.a = load i32, ptr %ptr | 
|  | ; CHECK-NEXT:    br label %b.header | 
|  |  | 
|  | b.header: | 
|  | %x.b = load i32, ptr %ptr | 
|  | %v1 = call i32 @cond.i32() | 
|  | br label %c.header | 
|  | ; CHECK:       b.header: | 
|  | ; CHECK-NEXT:    %x.b = load i32, ptr %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, ptr %ptr | 
|  | store i32 %x.b, ptr %ptr | 
|  | %v2 = call i1 @cond() | 
|  | br i1 %v2, label %c.header, label %exit | 
|  | ; CHECK:       c.latch: | 
|  | ; CHECK-NEXT:    store i32 %[[X_A_LCSSA]], ptr %ptr | 
|  | ; CHECK-NEXT:    store i32 %[[X_B_LCSSA]], ptr %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(ptr %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, ptr %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(ptr %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, ptr %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 | 
|  | } | 
|  |  | 
|  | declare void @f() | 
|  | declare void @g() | 
|  | define void @test_unswitch_switch_with_nonempty_unreachable() { | 
|  | ; CHECK-LABEL: @test_unswitch_switch_with_nonempty_unreachable() | 
|  | entry: | 
|  | br label %loop | 
|  |  | 
|  | loop: | 
|  | %cleanup.dest.slot.0 = select i1 undef, i32 5, i32 undef | 
|  | br label %for.cond | 
|  |  | 
|  | for.cond: | 
|  | switch i32 %cleanup.dest.slot.0, label %NonEmptyUnreachableBlock [ | 
|  | i32 0, label %for.cond | 
|  | i32 1, label %NonEmptyUnreachableBlock | 
|  | i32 2, label %loop.loopexit | 
|  | ] | 
|  |  | 
|  | loop.loopexit: | 
|  | unreachable | 
|  |  | 
|  | NonEmptyUnreachableBlock: | 
|  | call void @f() | 
|  | call void @g() | 
|  | unreachable | 
|  |  | 
|  | ; CHECK:loop: | 
|  | ; CHECK-NEXT:  %cleanup.dest.slot.0 = select i1 undef, i32 5, i32 undef | 
|  | ; CHECK-NEXT:  switch i32 %cleanup.dest.slot.0, label %NonEmptyUnreachableBlock [ | 
|  | ; CHECK-NEXT:    i32 1, label %NonEmptyUnreachableBlock | 
|  | ; CHECK-NEXT:    i32 0, label %loop.split | 
|  | ; CHECK-NEXT:    i32 2, label %loop.split | 
|  | ; CHECK-NEXT:  ] | 
|  |  | 
|  | ; CHECK:loop.split: | 
|  | ; CHECK-NEXT:  br label %for.cond | 
|  |  | 
|  | ; CHECK:for.cond: | 
|  | ; CHECK-NEXT:  switch i32 %cleanup.dest.slot.0, label %loop.loopexit [ | 
|  | ; CHECK-NEXT:    i32 0, label %for.cond | 
|  | ; CHECK-NEXT:  ] | 
|  |  | 
|  | ; CHECK:loop.loopexit: | 
|  | ; CHECK-NEXT:  unreachable | 
|  |  | 
|  | ; CHECK:NonEmptyUnreachableBlock: | 
|  | ; CHECK-NEXT:  call void @f() | 
|  | ; CHECK-NEXT:  call void @g() | 
|  | ; CHECK-NEXT:  unreachable | 
|  | } | 
|  |  | 
|  | define void @test_unswitch_switch_with_nonempty_unreachable2() { | 
|  | ; CHECK-LABEL: @test_unswitch_switch_with_nonempty_unreachable2() | 
|  | entry: | 
|  | br label %loop | 
|  |  | 
|  | loop: | 
|  | %cleanup.dest.slot.0 = select i1 undef, i32 5, i32 undef | 
|  | br label %for.cond | 
|  |  | 
|  | for.cond: | 
|  | switch i32 %cleanup.dest.slot.0, label %for.cond [ | 
|  | i32 0, label %for.cond | 
|  | i32 1, label %NonEmptyUnreachableBlock | 
|  | i32 2, label %loop.loopexit | 
|  | ] | 
|  |  | 
|  | loop.loopexit: | 
|  | unreachable | 
|  |  | 
|  | NonEmptyUnreachableBlock: | 
|  | call void @f() | 
|  | call void @g() | 
|  | unreachable | 
|  |  | 
|  | ; CHECK:loop: | 
|  | ; CHECK-NEXT:  %cleanup.dest.slot.0 = select i1 undef, i32 5, i32 undef | 
|  | ; CHECK-NEXT:  switch i32 %cleanup.dest.slot.0, label %loop.split [ | 
|  | ; CHECK-NEXT:    i32 1, label %NonEmptyUnreachableBlock | 
|  | ; CHECK-NEXT:  ] | 
|  |  | 
|  | ; CHECK:loop.split: | 
|  | ; CHECK-NEXT:  br label %for.cond | 
|  |  | 
|  | ; CHECK:for.cond: | 
|  | ; CHECK-NEXT:  switch i32 %cleanup.dest.slot.0, label %for.cond.backedge [ | 
|  | ; CHECK-NEXT:    i32 0, label %for.cond.backedge | 
|  | ; CHECK-NEXT:    i32 2, label %loop.loopexit | 
|  | ; CHECK-NEXT:  ] | 
|  |  | 
|  | ; CHECK:for.cond.backedge: | 
|  | ; CHECK-NEXT:  br label %for.cond | 
|  |  | 
|  | ; CHECK:loop.loopexit: | 
|  | ; CHECK-NEXT:  unreachable | 
|  |  | 
|  | ; CHECK:NonEmptyUnreachableBlock: | 
|  | ; CHECK-NEXT:  call void @f() | 
|  | ; CHECK-NEXT:  call void @g() | 
|  | ; CHECK-NEXT:  unreachable | 
|  | } | 
|  |  | 
|  | ; PR45355 | 
|  | define void @test_unswitch_switch_with_duplicate_edge() { | 
|  | ; CHECK-LABEL: @test_unswitch_switch_with_duplicate_edge() | 
|  | entry: | 
|  | br label %lbl1 | 
|  |  | 
|  | lbl1:                                             ; preds = %entry | 
|  | %cleanup.dest.slot.0 = select i1 undef, i32 5, i32 undef | 
|  | br label %for.cond1 | 
|  |  | 
|  | for.cond1:                                        ; preds = %for.cond1, %lbl1 | 
|  | switch i32 %cleanup.dest.slot.0, label %UnifiedUnreachableBlock [ | 
|  | i32 0, label %for.cond1 | 
|  | i32 5, label %UnifiedUnreachableBlock | 
|  | i32 2, label %lbl1.loopexit | 
|  | ] | 
|  |  | 
|  | UnifiedUnreachableBlock:                          ; preds = %for.cond1, %for.cond1 | 
|  | unreachable | 
|  |  | 
|  | lbl1.loopexit:                                    ; preds = %for.cond1 | 
|  | unreachable | 
|  |  | 
|  | ; CHECK: for.cond1: | 
|  | ; CHECK-NEXT:  switch i32 %cleanup.dest.slot.0, label %UnifiedUnreachableBlock [ | 
|  | ; CHECK-NEXT:    i32 0, label %for.cond1 | 
|  | ; CHECK-NEXT:    i32 5, label %UnifiedUnreachableBlock | 
|  | ; CHECK-NEXT:    i32 2, label %lbl1.loopexit | 
|  | ; CHECK-NEXT:  ] | 
|  | } |