176 changes: 176 additions & 0 deletions llvm/test/Transforms/SimpleLoopUnswitch/trivial-unswitch.ll
Original file line number Diff line number Diff line change
Expand Up @@ -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]]
}