diff options
Diffstat (limited to 'llvm/test/Transforms/UnifyLoopExits')
| -rw-r--r-- | llvm/test/Transforms/UnifyLoopExits/basic.ll | 131 | ||||
| -rw-r--r-- | llvm/test/Transforms/UnifyLoopExits/integer_guards.ll | 410 | ||||
| -rw-r--r-- | llvm/test/Transforms/UnifyLoopExits/nested.ll | 142 | ||||
| -rw-r--r-- | llvm/test/Transforms/UnifyLoopExits/restore-ssa.ll | 236 | ||||
| -rw-r--r-- | llvm/test/Transforms/UnifyLoopExits/undef-phis.ll | 68 | 
5 files changed, 984 insertions, 3 deletions
| diff --git a/llvm/test/Transforms/UnifyLoopExits/basic.ll b/llvm/test/Transforms/UnifyLoopExits/basic.ll index ccd15d4..d04d142 100644 --- a/llvm/test/Transforms/UnifyLoopExits/basic.ll +++ b/llvm/test/Transforms/UnifyLoopExits/basic.ll @@ -18,12 +18,12 @@ define void @loop_1(i1 %PredEntry, i1 %PredB, i1 %PredC, i1 %PredD) {  ; CHECK:       F:  ; CHECK-NEXT:    br label [[EXIT]]  ; CHECK:       G: -; CHECK-NEXT:    br label [[F:%.*]] +; CHECK-NEXT:    br label [[Y:%.*]]  ; CHECK:       exit:  ; CHECK-NEXT:    ret void  ; CHECK:       loop.exit.guard: -; CHECK-NEXT:    [[GUARD_E:%.*]] = phi i1 [ true, [[B]] ], [ false, [[C]] ], [ false, [[D]] ] -; CHECK-NEXT:    br i1 [[GUARD_E]], label [[E:%.*]], label [[F]] +; CHECK-NEXT:    [[GUARD_X:%.*]] = phi i1 [ true, [[B]] ], [ false, [[C]] ], [ false, [[D]] ] +; CHECK-NEXT:    br i1 [[GUARD_X]], label [[X:%.*]], label [[Y]]  ;  entry:    br i1 %PredEntry, label %A, label %G @@ -53,6 +53,67 @@ exit:    ret void  } +define void @loop_1_callbr(i1 %PredEntry, i1 %PredB, i1 %PredC, i1 %PredD) { +; CHECK-LABEL: @loop_1_callbr( +; CHECK-NEXT:  entry: +; CHECK-NEXT:    br i1 [[PREDENTRY:%.*]], label [[A:%.*]], label [[G:%.*]] +; CHECK:       A: +; CHECK-NEXT:    br label [[B:%.*]] +; CHECK:       B: +; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PREDB:%.*]]) +; CHECK-NEXT:            to label [[C:%.*]] [label %B.target.E] +; CHECK:       C: +; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PREDC:%.*]]) +; CHECK-NEXT:            to label [[D:%.*]] [label %C.target.F] +; CHECK:       D: +; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PREDD:%.*]]) +; CHECK-NEXT:            to label [[A]] [label %D.target.F] +; CHECK:       E: +; CHECK-NEXT:    br label [[EXIT:%.*]] +; CHECK:       F: +; CHECK-NEXT:    br label [[EXIT]] +; CHECK:       G: +; CHECK-NEXT:    br label [[Y:%.*]] +; CHECK:       exit: +; CHECK-NEXT:    ret void +; CHECK:       B.target.E: +; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD:%.*]] +; CHECK:       C.target.F: +; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD]] +; CHECK:       D.target.F: +; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD]] +; CHECK:       loop.exit.guard: +; CHECK-NEXT:    [[GUARD_X:%.*]] = phi i1 [ true, [[B_TARGET_E:%.*]] ], [ false, [[C_TARGET_F:%.*]] ], [ false, [[D_TARGET_F:%.*]] ] +; CHECK-NEXT:    br i1 [[GUARD_X]], label [[X:%.*]], label [[Y]] +; +entry: +  br i1 %PredEntry, label %A, label %G + +A: +  br label %B + +B: +  callbr void asm "", "r,!i"(i1 %PredB) to label %C [label %E] + +C: +  callbr void asm "", "r,!i"(i1 %PredC) to label %D [label %F] + +D: +  callbr void asm "", "r,!i"(i1 %PredD) to label %A [label %F] + +E: +  br label %exit + +F: +  br label %exit + +G: +  br label %F + +exit: +  ret void +} +  define void @loop_2(i1 %PredA, i1 %PredB, i1 %PredC) {  ; CHECK-LABEL: @loop_2(  ; CHECK-NEXT:  entry: @@ -107,3 +168,67 @@ Z:  exit:    ret void  } + +define void @loop_2_callbr(i1 %PredA, i1 %PredB, i1 %PredC) { +; CHECK-LABEL: @loop_2_callbr( +; CHECK-NEXT:  entry: +; CHECK-NEXT:    br label [[A:%.*]] +; CHECK:       A: +; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PREDA:%.*]]) +; CHECK-NEXT:            to label [[B:%.*]] [label %A.target.X] +; CHECK:       B: +; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PREDB:%.*]]) +; CHECK-NEXT:            to label [[C:%.*]] [label %B.target.Y] +; CHECK:       C: +; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PREDC:%.*]]) +; CHECK-NEXT:            to label [[D:%.*]] [label %C.target.Z] +; CHECK:       D: +; CHECK-NEXT:    br label [[A]] +; CHECK:       X: +; CHECK-NEXT:    br label [[EXIT:%.*]] +; CHECK:       Y: +; CHECK-NEXT:    br label [[EXIT]] +; CHECK:       Z: +; CHECK-NEXT:    br label [[EXIT]] +; CHECK:       exit: +; CHECK-NEXT:    ret void +; CHECK:       A.target.X: +; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD:%.*]] +; CHECK:       B.target.Y: +; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD]] +; CHECK:       C.target.Z: +; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD]] +; CHECK:       loop.exit.guard: +; CHECK-NEXT:    [[GUARD_X:%.*]] = phi i1 [ true, [[A_TARGET_X:%.*]] ], [ false, [[B_TARGET_Y:%.*]] ], [ false, [[C_TARGET_Z:%.*]] ] +; CHECK-NEXT:    [[GUARD_Y:%.*]] = phi i1 [ false, [[A_TARGET_X]] ], [ true, [[B_TARGET_Y]] ], [ false, [[C_TARGET_Z]] ] +; CHECK-NEXT:    br i1 [[GUARD_X]], label [[X:%.*]], label [[LOOP_EXIT_GUARD1:%.*]] +; CHECK:       loop.exit.guard1: +; CHECK-NEXT:    br i1 [[GUARD_Y]], label [[Y:%.*]], label [[Z:%.*]] +; +entry: +  br label %A + +A: +  callbr void asm "", "r,!i"(i1 %PredA) to label %B [label %X] + +B: +  callbr void asm "", "r,!i"(i1 %PredB) to label %C [label %Y] + +C: +  callbr void asm "", "r,!i"(i1 %PredC) to label %D [label %Z] + +D: +  br label %A + +X: +  br label %exit + +Y: +  br label %exit + +Z: +  br label %exit + +exit: +  ret void +} diff --git a/llvm/test/Transforms/UnifyLoopExits/integer_guards.ll b/llvm/test/Transforms/UnifyLoopExits/integer_guards.ll index f55639f..be982d5 100644 --- a/llvm/test/Transforms/UnifyLoopExits/integer_guards.ll +++ b/llvm/test/Transforms/UnifyLoopExits/integer_guards.ll @@ -71,6 +71,85 @@ E:    ret void  } +define void @loop_two_exits_callbr(i1 %PredEntry, i1 %PredA) { +; CHECK-LABEL: @loop_two_exits_callbr( +; CHECK-NEXT:  entry: +; CHECK-NEXT:    br i1 [[PREDENTRY:%.*]], label [[A:%.*]], label [[E:%.*]] +; CHECK:       A: +; CHECK-NEXT:    [[INC1:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC2:%.*]], [[C:%.*]] ] +; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PREDA:%.*]]) +; CHECK-NEXT:            to label [[A_TARGET_B:%.*]] [label %C] +; CHECK:       B: +; CHECK-NEXT:    tail call fastcc void @check(i32 1) #[[ATTR0]] +; CHECK-NEXT:    br label [[D:%.*]] +; CHECK:       C: +; CHECK-NEXT:    [[INC2]] = add i32 [[INC1]], 1 +; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[INC2]], 10 +; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[CMP]]) +; CHECK-NEXT:            to label [[A]] [label %C.target.E] +; CHECK:       D: +; CHECK-NEXT:    unreachable +; CHECK:       E: +; CHECK-NEXT:    ret void +; CHECK:       A.target.B: +; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD:%.*]] +; CHECK:       C.target.E: +; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD]] +; CHECK:       loop.exit.guard: +; CHECK-NEXT:    [[MERGED_BB_IDX:%.*]] = phi i32 [ 0, [[A_TARGET_B]] ], [ 1, [[C_TARGET_E:%.*]] ] +; CHECK-NEXT:    [[B_PREDICATE:%.*]] = icmp eq i32 [[MERGED_BB_IDX]], 0 +; CHECK-NEXT:    br i1 [[B_PREDICATE]], label [[B:%.*]], label [[E]] +; +; BOOLEAN-LABEL: @loop_two_exits_callbr( +; BOOLEAN-NEXT:  entry: +; BOOLEAN-NEXT:    br i1 [[PREDENTRY:%.*]], label [[A:%.*]], label [[E:%.*]] +; BOOLEAN:       A: +; BOOLEAN-NEXT:    [[INC1:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC2:%.*]], [[C:%.*]] ] +; BOOLEAN-NEXT:    callbr void asm "", "r,!i"(i1 [[PREDA:%.*]]) +; BOOLEAN-NEXT:            to label [[A_TARGET_B:%.*]] [label %C] +; BOOLEAN:       B: +; BOOLEAN-NEXT:    tail call fastcc void @check(i32 1) #[[ATTR0]] +; BOOLEAN-NEXT:    br label [[D:%.*]] +; BOOLEAN:       C: +; BOOLEAN-NEXT:    [[INC2]] = add i32 [[INC1]], 1 +; BOOLEAN-NEXT:    [[CMP:%.*]] = icmp ult i32 [[INC2]], 10 +; BOOLEAN-NEXT:    callbr void asm "", "r,!i"(i1 [[CMP]]) +; BOOLEAN-NEXT:            to label [[A]] [label %C.target.E] +; BOOLEAN:       D: +; BOOLEAN-NEXT:    unreachable +; BOOLEAN:       E: +; BOOLEAN-NEXT:    ret void +; BOOLEAN:       A.target.B: +; BOOLEAN-NEXT:    br label [[LOOP_EXIT_GUARD:%.*]] +; BOOLEAN:       C.target.E: +; BOOLEAN-NEXT:    br label [[LOOP_EXIT_GUARD]] +; BOOLEAN:       loop.exit.guard: +; BOOLEAN-NEXT:    [[GUARD_B:%.*]] = phi i1 [ true, [[A_TARGET_B]] ], [ false, [[C_TARGET_E:%.*]] ] +; BOOLEAN-NEXT:    br i1 [[GUARD_B]], label [[B:%.*]], label [[E]] +; +entry: +  br i1 %PredEntry, label %A, label %E + +A: +  %inc1 = phi i32 [ 0, %entry ], [ %inc2, %C ] +  callbr void asm "", "r,!i"(i1 %PredA) to label %B [label %C] + +B: +  tail call fastcc void @check(i32 1) #0 +  br label %D + +C: +  %inc2 = add i32 %inc1, 1 +  %cmp = icmp ult i32 %inc2, 10 +  callbr void asm "","r,!i"(i1 %cmp) to label %A [label %E] + +D: +  unreachable + +E: +  ret void +} +  ; The loop exit blocks appear in an inner loop.  define void @inner_loop(i1 %PredEntry, i1 %PredA, i1 %PredB) { @@ -196,6 +275,164 @@ I:    ret void  } +define void @inner_loop_callbr(i1 %PredEntry, i1 %PredA, i1 %PredB) { +; CHECK-LABEL: @inner_loop_callbr( +; CHECK-NEXT:  entry: +; CHECK-NEXT:    br i1 [[PREDENTRY:%.*]], label [[A:%.*]], label [[I:%.*]] +; CHECK:       A: +; CHECK-NEXT:    [[OUTER1:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[OUTER2:%.*]], [[G:%.*]] ] +; CHECK-NEXT:    br label [[B:%.*]] +; CHECK:       B: +; CHECK-NEXT:    [[INNER1:%.*]] = phi i32 [ 0, [[A]] ], [ [[INNER2:%.*]], [[F:%.*]] ] +; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PREDA:%.*]]) +; CHECK-NEXT:            to label [[D:%.*]] [label %B.target.B.target.C] +; CHECK:       C: +; CHECK-NEXT:    tail call fastcc void @check(i32 1) #[[ATTR0]] +; CHECK-NEXT:    br label [[H:%.*]] +; CHECK:       D: +; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PREDB:%.*]]) +; CHECK-NEXT:            to label [[D_TARGET_D_TARGET_E:%.*]] [label %F] +; CHECK:       E: +; CHECK-NEXT:    tail call fastcc void @check(i32 2) #[[ATTR0]] +; CHECK-NEXT:    br label [[H]] +; CHECK:       F: +; CHECK-NEXT:    [[INNER2]] = add i32 [[INNER1]], 1 +; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult i32 [[INNER2]], 20 +; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[CMP1]]) +; CHECK-NEXT:            to label [[B]] [label %F.target.G] +; CHECK:       G: +; CHECK-NEXT:    [[OUTER2]] = add i32 [[OUTER1]], 1 +; CHECK-NEXT:    [[CMP2:%.*]] = icmp ult i32 [[OUTER2]], 10 +; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[CMP2]]) +; CHECK-NEXT:            to label [[A]] [label %G.target.I] +; CHECK:       H: +; CHECK-NEXT:    unreachable +; CHECK:       I: +; CHECK-NEXT:    ret void +; CHECK:       B.target.C: +; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD:%.*]] +; CHECK:       D.target.E: +; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD]] +; CHECK:       G.target.I: +; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD]] +; CHECK:       loop.exit.guard: +; CHECK-NEXT:    [[MERGED_BB_IDX:%.*]] = phi i32 [ 0, [[B_TARGET_C:%.*]] ], [ 1, [[D_TARGET_E:%.*]] ], [ 2, [[G_TARGET_I:%.*]] ] +; CHECK-NEXT:    [[C_PREDICATE:%.*]] = icmp eq i32 [[MERGED_BB_IDX]], 0 +; CHECK-NEXT:    br i1 [[C_PREDICATE]], label [[C:%.*]], label [[LOOP_EXIT_GUARD1:%.*]] +; CHECK:       loop.exit.guard1: +; CHECK-NEXT:    [[E_PREDICATE:%.*]] = icmp eq i32 [[MERGED_BB_IDX]], 1 +; CHECK-NEXT:    br i1 [[E_PREDICATE]], label [[E:%.*]], label [[I]] +; CHECK:       B.target.B.target.C: +; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD2:%.*]] +; CHECK:       D.target.D.target.E: +; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD2]] +; CHECK:       F.target.G: +; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD2]] +; CHECK:       loop.exit.guard2: +; CHECK-NEXT:    [[MERGED_BB_IDX4:%.*]] = phi i32 [ 0, [[B_TARGET_B_TARGET_C:%.*]] ], [ 1, [[D_TARGET_D_TARGET_E]] ], [ 2, [[F_TARGET_G:%.*]] ] +; CHECK-NEXT:    [[B_TARGET_C_PREDICATE:%.*]] = icmp eq i32 [[MERGED_BB_IDX4]], 0 +; CHECK-NEXT:    br i1 [[B_TARGET_C_PREDICATE]], label [[B_TARGET_C]], label [[LOOP_EXIT_GUARD3:%.*]] +; CHECK:       loop.exit.guard3: +; CHECK-NEXT:    [[D_TARGET_E_PREDICATE:%.*]] = icmp eq i32 [[MERGED_BB_IDX4]], 1 +; CHECK-NEXT:    br i1 [[D_TARGET_E_PREDICATE]], label [[D_TARGET_E]], label [[G]] +; +; BOOLEAN-LABEL: @inner_loop_callbr( +; BOOLEAN-NEXT:  entry: +; BOOLEAN-NEXT:    br i1 [[PREDENTRY:%.*]], label [[A:%.*]], label [[I:%.*]] +; BOOLEAN:       A: +; BOOLEAN-NEXT:    [[OUTER1:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[OUTER2:%.*]], [[G:%.*]] ] +; BOOLEAN-NEXT:    br label [[B:%.*]] +; BOOLEAN:       B: +; BOOLEAN-NEXT:    [[INNER1:%.*]] = phi i32 [ 0, [[A]] ], [ [[INNER2:%.*]], [[F:%.*]] ] +; BOOLEAN-NEXT:    callbr void asm "", "r,!i"(i1 [[PREDA:%.*]]) +; BOOLEAN-NEXT:            to label [[D:%.*]] [label %B.target.B.target.C] +; BOOLEAN:       C: +; BOOLEAN-NEXT:    tail call fastcc void @check(i32 1) #[[ATTR0]] +; BOOLEAN-NEXT:    br label [[H:%.*]] +; BOOLEAN:       D: +; BOOLEAN-NEXT:    callbr void asm "", "r,!i"(i1 [[PREDB:%.*]]) +; BOOLEAN-NEXT:            to label [[D_TARGET_D_TARGET_E:%.*]] [label %F] +; BOOLEAN:       E: +; BOOLEAN-NEXT:    tail call fastcc void @check(i32 2) #[[ATTR0]] +; BOOLEAN-NEXT:    br label [[H]] +; BOOLEAN:       F: +; BOOLEAN-NEXT:    [[INNER2]] = add i32 [[INNER1]], 1 +; BOOLEAN-NEXT:    [[CMP1:%.*]] = icmp ult i32 [[INNER2]], 20 +; BOOLEAN-NEXT:    callbr void asm "", "r,!i"(i1 [[CMP1]]) +; BOOLEAN-NEXT:            to label [[B]] [label %F.target.G] +; BOOLEAN:       G: +; BOOLEAN-NEXT:    [[OUTER2]] = add i32 [[OUTER1]], 1 +; BOOLEAN-NEXT:    [[CMP2:%.*]] = icmp ult i32 [[OUTER2]], 10 +; BOOLEAN-NEXT:    callbr void asm "", "r,!i"(i1 [[CMP2]]) +; BOOLEAN-NEXT:            to label [[A]] [label %G.target.I] +; BOOLEAN:       H: +; BOOLEAN-NEXT:    unreachable +; BOOLEAN:       I: +; BOOLEAN-NEXT:    ret void +; BOOLEAN:       B.target.C: +; BOOLEAN-NEXT:    br label [[LOOP_EXIT_GUARD:%.*]] +; BOOLEAN:       D.target.E: +; BOOLEAN-NEXT:    br label [[LOOP_EXIT_GUARD]] +; BOOLEAN:       G.target.I: +; BOOLEAN-NEXT:    br label [[LOOP_EXIT_GUARD]] +; BOOLEAN:       loop.exit.guard: +; BOOLEAN-NEXT:    [[GUARD_C:%.*]] = phi i1 [ true, [[B_TARGET_C:%.*]] ], [ false, [[D_TARGET_E:%.*]] ], [ false, [[G_TARGET_I:%.*]] ] +; BOOLEAN-NEXT:    [[GUARD_E:%.*]] = phi i1 [ false, [[B_TARGET_C]] ], [ true, [[D_TARGET_E]] ], [ false, [[G_TARGET_I]] ] +; BOOLEAN-NEXT:    br i1 [[GUARD_C]], label [[C:%.*]], label [[LOOP_EXIT_GUARD1:%.*]] +; BOOLEAN:       loop.exit.guard1: +; BOOLEAN-NEXT:    br i1 [[GUARD_E]], label [[E:%.*]], label [[I]] +; BOOLEAN:       B.target.B.target.C: +; BOOLEAN-NEXT:    br label [[LOOP_EXIT_GUARD2:%.*]] +; BOOLEAN:       D.target.D.target.E: +; BOOLEAN-NEXT:    br label [[LOOP_EXIT_GUARD2]] +; BOOLEAN:       F.target.G: +; BOOLEAN-NEXT:    br label [[LOOP_EXIT_GUARD2]] +; BOOLEAN:       loop.exit.guard2: +; BOOLEAN-NEXT:    [[GUARD_B_TARGET_C:%.*]] = phi i1 [ true, [[B_TARGET_B_TARGET_C:%.*]] ], [ false, [[D_TARGET_D_TARGET_E]] ], [ false, [[F_TARGET_G:%.*]] ] +; BOOLEAN-NEXT:    [[GUARD_D_TARGET_E:%.*]] = phi i1 [ false, [[B_TARGET_B_TARGET_C]] ], [ true, [[D_TARGET_D_TARGET_E]] ], [ false, [[F_TARGET_G]] ] +; BOOLEAN-NEXT:    br i1 [[GUARD_B_TARGET_C]], label [[B_TARGET_C]], label [[LOOP_EXIT_GUARD3:%.*]] +; BOOLEAN:       loop.exit.guard3: +; BOOLEAN-NEXT:    br i1 [[GUARD_D_TARGET_E]], label [[D_TARGET_E]], label [[G]] +; +entry: +  br i1 %PredEntry, label %A, label %I + +A: +  %outer1 = phi i32 [ 0, %entry ], [ %outer2, %G ] +  br label %B + +B: +  %inner1 = phi i32 [ 0, %A ], [ %inner2, %F ] +  callbr void asm "", "r,!i"(i1 %PredA) to label %D [label %C] + +C: +  tail call fastcc void @check(i32 1) #0 +  br label %H + +D: +  callbr void asm "", "r,!i"(i1 %PredB) to label %E [label %F] + +E: +  tail call fastcc void @check(i32 2) #0 +  br label %H + +F: +  %inner2 = add i32 %inner1, 1 +  %cmp1 = icmp ult i32 %inner2, 20 +  callbr void asm "", "r,!i"(i1 %cmp1) to label %B [label %G] + +G: +  %outer2 = add i32 %outer1, 1 +  %cmp2 = icmp ult i32 %outer2, 10 +  callbr void asm "", "r,!i"(i1 %cmp2) to label %A [label %I] + +H: +  unreachable + +I: +  ret void +} +  ; A loop with more exit blocks.  define void @loop_five_exits(i1 %PredEntry, i1 %PredA, i1 %PredB, i1 %PredC, i1 %PredD) { @@ -341,6 +578,179 @@ L:    ret void  } +define void @loop_five_exits_callbr(i1 %PredEntry, i1 %PredA, i1 %PredB, i1 %PredC, i1 %PredD) { +; CHECK-LABEL: @loop_five_exits_callbr( +; CHECK-NEXT:  entry: +; CHECK-NEXT:    br i1 [[PREDENTRY:%.*]], label [[A:%.*]], label [[L:%.*]] +; CHECK:       A: +; CHECK-NEXT:    [[INC1:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC2:%.*]], [[I:%.*]] ] +; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PREDA:%.*]]) +; CHECK-NEXT:            to label [[A_TARGET_B:%.*]] [label %C] +; CHECK:       B: +; CHECK-NEXT:    tail call fastcc void @check(i32 1) #[[ATTR0]] +; CHECK-NEXT:    br label [[J:%.*]] +; CHECK:       C: +; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PREDB:%.*]]) +; CHECK-NEXT:            to label [[C_TARGET_D:%.*]] [label %E] +; CHECK:       D: +; CHECK-NEXT:    tail call fastcc void @check(i32 2) #[[ATTR0]] +; CHECK-NEXT:    br label [[J]] +; CHECK:       E: +; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PREDC:%.*]]) +; CHECK-NEXT:            to label [[E_TARGET_F:%.*]] [label %G] +; CHECK:       F: +; CHECK-NEXT:    tail call fastcc void @check(i32 3) #[[ATTR0]] +; CHECK-NEXT:    br label [[K:%.*]] +; CHECK:       G: +; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PREDD:%.*]]) +; CHECK-NEXT:            to label [[G_TARGET_H:%.*]] [label %I] +; CHECK:       H: +; CHECK-NEXT:    tail call fastcc void @check(i32 4) #[[ATTR0]] +; CHECK-NEXT:    br label [[K]] +; CHECK:       I: +; CHECK-NEXT:    [[INC2]] = add i32 [[INC1]], 1 +; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[INC2]], 10 +; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[CMP]]) +; CHECK-NEXT:            to label [[A]] [label %I.target.L] +; CHECK:       J: +; CHECK-NEXT:    br label [[L]] +; CHECK:       K: +; CHECK-NEXT:    br label [[L]] +; CHECK:       L: +; CHECK-NEXT:    ret void +; CHECK:       A.target.B: +; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD:%.*]] +; CHECK:       C.target.D: +; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD]] +; CHECK:       E.target.F: +; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD]] +; CHECK:       G.target.H: +; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD]] +; CHECK:       I.target.L: +; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD]] +; CHECK:       loop.exit.guard: +; CHECK-NEXT:    [[MERGED_BB_IDX:%.*]] = phi i32 [ 0, [[A_TARGET_B]] ], [ 1, [[C_TARGET_D]] ], [ 2, [[E_TARGET_F]] ], [ 3, [[G_TARGET_H]] ], [ 4, [[I_TARGET_L:%.*]] ] +; CHECK-NEXT:    [[B_PREDICATE:%.*]] = icmp eq i32 [[MERGED_BB_IDX]], 0 +; CHECK-NEXT:    br i1 [[B_PREDICATE]], label [[B:%.*]], label [[LOOP_EXIT_GUARD1:%.*]] +; CHECK:       loop.exit.guard1: +; CHECK-NEXT:    [[D_PREDICATE:%.*]] = icmp eq i32 [[MERGED_BB_IDX]], 1 +; CHECK-NEXT:    br i1 [[D_PREDICATE]], label [[D:%.*]], label [[LOOP_EXIT_GUARD2:%.*]] +; CHECK:       loop.exit.guard2: +; CHECK-NEXT:    [[F_PREDICATE:%.*]] = icmp eq i32 [[MERGED_BB_IDX]], 2 +; CHECK-NEXT:    br i1 [[F_PREDICATE]], label [[F:%.*]], label [[LOOP_EXIT_GUARD3:%.*]] +; CHECK:       loop.exit.guard3: +; CHECK-NEXT:    [[H_PREDICATE:%.*]] = icmp eq i32 [[MERGED_BB_IDX]], 3 +; CHECK-NEXT:    br i1 [[H_PREDICATE]], label [[H:%.*]], label [[L]] +; +; BOOLEAN-LABEL: @loop_five_exits_callbr( +; BOOLEAN-NEXT:  entry: +; BOOLEAN-NEXT:    br i1 [[PREDENTRY:%.*]], label [[A:%.*]], label [[L:%.*]] +; BOOLEAN:       A: +; BOOLEAN-NEXT:    [[INC1:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC2:%.*]], [[I:%.*]] ] +; BOOLEAN-NEXT:    callbr void asm "", "r,!i"(i1 [[PREDA:%.*]]) +; BOOLEAN-NEXT:            to label [[A_TARGET_B:%.*]] [label %C] +; BOOLEAN:       B: +; BOOLEAN-NEXT:    tail call fastcc void @check(i32 1) #[[ATTR0]] +; BOOLEAN-NEXT:    br label [[J:%.*]] +; BOOLEAN:       C: +; BOOLEAN-NEXT:    callbr void asm "", "r,!i"(i1 [[PREDB:%.*]]) +; BOOLEAN-NEXT:            to label [[C_TARGET_D:%.*]] [label %E] +; BOOLEAN:       D: +; BOOLEAN-NEXT:    tail call fastcc void @check(i32 2) #[[ATTR0]] +; BOOLEAN-NEXT:    br label [[J]] +; BOOLEAN:       E: +; BOOLEAN-NEXT:    callbr void asm "", "r,!i"(i1 [[PREDC:%.*]]) +; BOOLEAN-NEXT:            to label [[E_TARGET_F:%.*]] [label %G] +; BOOLEAN:       F: +; BOOLEAN-NEXT:    tail call fastcc void @check(i32 3) #[[ATTR0]] +; BOOLEAN-NEXT:    br label [[K:%.*]] +; BOOLEAN:       G: +; BOOLEAN-NEXT:    callbr void asm "", "r,!i"(i1 [[PREDD:%.*]]) +; BOOLEAN-NEXT:            to label [[G_TARGET_H:%.*]] [label %I] +; BOOLEAN:       H: +; BOOLEAN-NEXT:    tail call fastcc void @check(i32 4) #[[ATTR0]] +; BOOLEAN-NEXT:    br label [[K]] +; BOOLEAN:       I: +; BOOLEAN-NEXT:    [[INC2]] = add i32 [[INC1]], 1 +; BOOLEAN-NEXT:    [[CMP:%.*]] = icmp ult i32 [[INC2]], 10 +; BOOLEAN-NEXT:    callbr void asm "", "r,!i"(i1 [[CMP]]) +; BOOLEAN-NEXT:            to label [[A]] [label %I.target.L] +; BOOLEAN:       J: +; BOOLEAN-NEXT:    br label [[L]] +; BOOLEAN:       K: +; BOOLEAN-NEXT:    br label [[L]] +; BOOLEAN:       L: +; BOOLEAN-NEXT:    ret void +; BOOLEAN:       A.target.B: +; BOOLEAN-NEXT:    br label [[LOOP_EXIT_GUARD:%.*]] +; BOOLEAN:       C.target.D: +; BOOLEAN-NEXT:    br label [[LOOP_EXIT_GUARD]] +; BOOLEAN:       E.target.F: +; BOOLEAN-NEXT:    br label [[LOOP_EXIT_GUARD]] +; BOOLEAN:       G.target.H: +; BOOLEAN-NEXT:    br label [[LOOP_EXIT_GUARD]] +; BOOLEAN:       I.target.L: +; BOOLEAN-NEXT:    br label [[LOOP_EXIT_GUARD]] +; BOOLEAN:       loop.exit.guard: +; BOOLEAN-NEXT:    [[GUARD_B:%.*]] = phi i1 [ true, [[A_TARGET_B]] ], [ false, [[C_TARGET_D]] ], [ false, [[E_TARGET_F]] ], [ false, [[G_TARGET_H]] ], [ false, [[I_TARGET_L:%.*]] ] +; BOOLEAN-NEXT:    [[GUARD_D:%.*]] = phi i1 [ false, [[A_TARGET_B]] ], [ true, [[C_TARGET_D]] ], [ false, [[E_TARGET_F]] ], [ false, [[G_TARGET_H]] ], [ false, [[I_TARGET_L]] ] +; BOOLEAN-NEXT:    [[GUARD_F:%.*]] = phi i1 [ false, [[A_TARGET_B]] ], [ false, [[C_TARGET_D]] ], [ true, [[E_TARGET_F]] ], [ false, [[G_TARGET_H]] ], [ false, [[I_TARGET_L]] ] +; BOOLEAN-NEXT:    [[GUARD_H:%.*]] = phi i1 [ false, [[A_TARGET_B]] ], [ false, [[C_TARGET_D]] ], [ false, [[E_TARGET_F]] ], [ true, [[G_TARGET_H]] ], [ false, [[I_TARGET_L]] ] +; BOOLEAN-NEXT:    br i1 [[GUARD_B]], label [[B:%.*]], label [[LOOP_EXIT_GUARD1:%.*]] +; BOOLEAN:       loop.exit.guard1: +; BOOLEAN-NEXT:    br i1 [[GUARD_D]], label [[D:%.*]], label [[LOOP_EXIT_GUARD2:%.*]] +; BOOLEAN:       loop.exit.guard2: +; BOOLEAN-NEXT:    br i1 [[GUARD_F]], label [[F:%.*]], label [[LOOP_EXIT_GUARD3:%.*]] +; BOOLEAN:       loop.exit.guard3: +; BOOLEAN-NEXT:    br i1 [[GUARD_H]], label [[H:%.*]], label [[L]] +; +entry: +  br i1 %PredEntry, label %A, label %L + +A: +  %inc1 = phi i32 [ 0, %entry ], [ %inc2, %I ] +  callbr void asm "", "r,!i"(i1 %PredA) to label %B [label %C] + +B: +  tail call fastcc void @check(i32 1) #0 +  br label %J + +C: +  callbr void asm "", "r,!i"(i1 %PredB) to label %D [label %E] + +D: +  tail call fastcc void @check(i32 2) #0 +  br label %J + +E: +  callbr void asm "", "r,!i"(i1 %PredC) to label %F [label %G] + +F: +  tail call fastcc void @check(i32 3) #0 +  br label %K + +G: +  callbr void asm "", "r,!i"(i1 %PredD) to label %H [label %I] + +H: +  tail call fastcc void @check(i32 4) #0 +  br label %K + +I: +  %inc2 = add i32 %inc1, 1 +  %cmp = icmp ult i32 %inc2, 10 +  callbr void asm "", "r,!i"(i1 %cmp) to label %A [label %L] + +J: +  br label %L + +K: +  br label %L + +L: +  ret void +} +  declare void @check(i32 noundef %i) #0 diff --git a/llvm/test/Transforms/UnifyLoopExits/nested.ll b/llvm/test/Transforms/UnifyLoopExits/nested.ll index 8fae2c4..2ec576a 100644 --- a/llvm/test/Transforms/UnifyLoopExits/nested.ll +++ b/llvm/test/Transforms/UnifyLoopExits/nested.ll @@ -78,3 +78,145 @@ exit:    %exit.phi = phi i32 [%A4.phi, %A5], [%Z, %C]    ret void  } + +define void @nested_callbr(i1 %PredB3, i1 %PredB4, i1 %PredA4, i1 %PredA3, i32 %X, i32 %Y, i32 %Z) { +; CHECK-LABEL: @nested_callbr( +; CHECK-NEXT:  entry: +; CHECK-NEXT:    br label [[A1:%.*]] +; CHECK:       A1: +; CHECK-NEXT:    br label [[B1:%.*]] +; CHECK:       B1: +; CHECK-NEXT:    br label [[B2:%.*]] +; CHECK:       B2: +; CHECK-NEXT:    [[X_INC:%.*]] = add i32 [[X:%.*]], 1 +; CHECK-NEXT:    br label [[B3:%.*]] +; CHECK:       B3: +; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PREDB3:%.*]]) +; CHECK-NEXT:            to label [[B4:%.*]] [label %B3.target.A3] +; CHECK:       B4: +; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PREDB4:%.*]]) +; CHECK-NEXT:            to label [[B1]] [label %B4.target.A2] +; CHECK:       A2: +; CHECK-NEXT:    br label [[A4:%.*]] +; CHECK:       A3: +; CHECK-NEXT:    br label [[A4]] +; CHECK:       A4: +; CHECK-NEXT:    [[A4_PHI:%.*]] = phi i32 [ [[Y:%.*]], [[A3:%.*]] ], [ [[X_INC_MOVED:%.*]], [[A2:%.*]] ] +; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PREDA4:%.*]]) +; CHECK-NEXT:            to label [[A4_TARGET_C:%.*]] [label %A5] +; CHECK:       A5: +; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PREDA3:%.*]]) +; CHECK-NEXT:            to label [[A5_TARGET_EXIT:%.*]] [label %A1] +; CHECK:       C: +; CHECK-NEXT:    br label [[EXIT:%.*]] +; CHECK:       exit: +; CHECK-NEXT:    [[EXIT_PHI:%.*]] = phi i32 [ [[Z:%.*]], [[C:%.*]] ], [ [[EXIT_PHI_MOVED:%.*]], [[LOOP_EXIT_GUARD:%.*]] ] +; CHECK-NEXT:    ret void +; CHECK:       A4.target.C: +; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD]] +; CHECK:       A5.target.exit: +; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD]] +; CHECK:       loop.exit.guard: +; CHECK-NEXT:    [[EXIT_PHI_MOVED]] = phi i32 [ poison, [[A4_TARGET_C]] ], [ [[A4_PHI]], [[A5_TARGET_EXIT]] ] +; CHECK-NEXT:    [[GUARD_C:%.*]] = phi i1 [ true, [[A4_TARGET_C]] ], [ false, [[A5_TARGET_EXIT]] ] +; CHECK-NEXT:    br i1 [[GUARD_C]], label [[C]], label [[EXIT]] +; CHECK:       B3.target.A3: +; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD1:%.*]] +; CHECK:       B4.target.A2: +; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD1]] +; CHECK:       loop.exit.guard1: +; CHECK-NEXT:    [[X_INC_MOVED]] = phi i32 [ [[X_INC]], [[B3_TARGET_A3:%.*]] ], [ [[X_INC]], [[B4_TARGET_A2:%.*]] ] +; CHECK-NEXT:    [[GUARD_A3:%.*]] = phi i1 [ true, [[B3_TARGET_A3]] ], [ false, [[B4_TARGET_A2]] ] +; CHECK-NEXT:    br i1 [[GUARD_A3]], label [[A3]], label [[A2]] +; +entry: +  br label %A1 + +A1: +  br label %B1 + +B1: +  br label %B2 + +B2: +  %X.inc = add i32 %X, 1 +  br label %B3 + +B3: +  callbr void asm "", "r,!i"(i1 %PredB3) to label %B4 [label %A3] + +B4: +  callbr void asm "", "r,!i"(i1 %PredB4) to label %B1 [label %A2] + +A2: +  br label %A4 + +A3: +  br label %A4 + +A4: +  %A4.phi = phi i32 [%Y, %A3], [%X.inc, %A2] +  callbr void asm "", "r,!i"(i1 %PredA4) to label %C [label %A5] + +A5: +  callbr void asm "", "r,!i"(i1 %PredA3) to label %exit [label %A1] + +C: +  br label %exit + +exit: +  %exit.phi = phi i32 [%A4.phi, %A5], [%Z, %C] +  ret void +} + +; Here, the newly created target loop that connects b to r1 needs to be part of +; the parent loop (the outer loop b participates in). Otherwise, it will be +; regarded as an additional loop entry point to this outer loop. +define void @nested_callbr_multiple_exits() { +; CHECK-LABEL: @nested_callbr_multiple_exits( +; CHECK-NEXT:    br label [[A:%.*]] +; CHECK:       a: +; CHECK-NEXT:    callbr void asm "", ""() +; CHECK-NEXT:            to label [[B:%.*]] [] +; CHECK:       b: +; CHECK-NEXT:    callbr void asm "", "!i"() +; CHECK-NEXT:            to label [[C:%.*]] [label %b.target.b.target.r1] +; CHECK:       c: +; CHECK-NEXT:    callbr void asm "", "!i"() +; CHECK-NEXT:            to label [[C_TARGET_E:%.*]] [label %b] +; CHECK:       e: +; CHECK-NEXT:    callbr void asm "", "!i"() +; CHECK-NEXT:            to label [[A]] [label %e.target.r2] +; CHECK:       r1: +; CHECK-NEXT:    ret void +; CHECK:       r2: +; CHECK-NEXT:    ret void +; CHECK:       b.target.r1: +; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD:%.*]] +; CHECK:       e.target.r2: +; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD]] +; CHECK:       loop.exit.guard: +; CHECK-NEXT:    [[GUARD_R1:%.*]] = phi i1 [ true, [[B_TARGET_R1:%.*]] ], [ false, [[E_TARGET_R2:%.*]] ] +; CHECK-NEXT:    br i1 [[GUARD_R1]], label [[R1:%.*]], label [[R2:%.*]] +; CHECK:       b.target.b.target.r1: +; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD1:%.*]] +; CHECK:       c.target.e: +; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD1]] +; CHECK:       loop.exit.guard1: +; CHECK-NEXT:    [[GUARD_B_TARGET_R1:%.*]] = phi i1 [ true, [[B_TARGET_B_TARGET_R1:%.*]] ], [ false, [[C_TARGET_E]] ] +; CHECK-NEXT:    br i1 [[GUARD_B_TARGET_R1]], label [[B_TARGET_R1]], label [[E:%.*]] +; +  br label %a +a: +  callbr void asm "", ""() to label %b [] +b: +  callbr void asm "", "!i"() to label %c [label %r1] +c: +  callbr void asm "", "!i"() to label %e [label %b] +e: +  callbr void asm "", "!i"() to label %a [label %r2] +r1: +  ret void +r2: +  ret void +} diff --git a/llvm/test/Transforms/UnifyLoopExits/restore-ssa.ll b/llvm/test/Transforms/UnifyLoopExits/restore-ssa.ll index 3e68df3..ffe8026 100644 --- a/llvm/test/Transforms/UnifyLoopExits/restore-ssa.ll +++ b/llvm/test/Transforms/UnifyLoopExits/restore-ssa.ll @@ -57,6 +57,60 @@ return:    ret i32 %phi  } +define i32 @exiting-used-in-exit_callbr(ptr %arg1, ptr %arg2) local_unnamed_addr align 2 { +; CHECK-LABEL: @exiting-used-in-exit_callbr( +; CHECK-NEXT:  entry: +; CHECK-NEXT:    callbr void asm "", ""() +; CHECK-NEXT:            to label [[A:%.*]] [] +; CHECK:       A: +; CHECK-NEXT:    [[MYTMP42:%.*]] = load i32, ptr [[ARG1:%.*]], align 4 +; CHECK-NEXT:    [[CMP1:%.*]] = icmp slt i32 [[MYTMP42]], 0 +; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[CMP1]]) +; CHECK-NEXT:            to label [[B:%.*]] [label %A.target.return] +; CHECK:       B: +; CHECK-NEXT:    [[MYTMP41:%.*]] = load i32, ptr [[ARG2:%.*]], align 4 +; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[MYTMP41]], 0 +; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[CMP]]) +; CHECK-NEXT:            to label [[A]] [label %B.target.C] +; CHECK:       C: +; CHECK-NEXT:    [[INC:%.*]] = add i32 [[MYTMP41_MOVED:%.*]], 1 +; CHECK-NEXT:    callbr void asm "", ""() +; CHECK-NEXT:            to label [[RETURN:%.*]] [] +; CHECK:       return: +; CHECK-NEXT:    [[PHI:%.*]] = phi i32 [ [[INC]], [[C:%.*]] ], [ [[PHI_MOVED:%.*]], [[LOOP_EXIT_GUARD:%.*]] ] +; CHECK-NEXT:    ret i32 [[PHI]] +; CHECK:       A.target.return: +; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD]] +; CHECK:       B.target.C: +; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD]] +; CHECK:       loop.exit.guard: +; CHECK-NEXT:    [[MYTMP41_MOVED]] = phi i32 [ poison, [[A_TARGET_RETURN:%.*]] ], [ [[MYTMP41]], [[B_TARGET_C:%.*]] ] +; CHECK-NEXT:    [[PHI_MOVED]] = phi i32 [ [[MYTMP42]], [[A_TARGET_RETURN]] ], [ poison, [[B_TARGET_C]] ] +; CHECK-NEXT:    [[GUARD_RETURN:%.*]] = phi i1 [ true, [[A_TARGET_RETURN]] ], [ false, [[B_TARGET_C]] ] +; CHECK-NEXT:    br i1 [[GUARD_RETURN]], label [[RETURN]], label [[C]] +; +entry: +  callbr void asm "", ""() to label %A [] + +A: +  %mytmp42 = load i32, ptr %arg1, align 4 +  %cmp1 = icmp slt i32 %mytmp42, 0 +  callbr void asm "", "r,!i"(i1 %cmp1) to label %B [label %return] + +B: +  %mytmp41 = load i32, ptr %arg2, align 4 +  %cmp = icmp slt i32 %mytmp41, 0 +  callbr void asm "", "r,!i"(i1 %cmp) to label %A [label %C] + +C: +  %inc = add i32 %mytmp41, 1 +  callbr void asm "", ""() to label %return [] + +return: +  %phi = phi i32 [ %inc, %C ], [ %mytmp42, %A ] +  ret i32 %phi +} +  ; Loop consists of A, B and C:  ; - A is the header  ; - A and C are exiting blocks @@ -112,6 +166,63 @@ return:    ret i32 0  } +define i32 @internal-used-in-exit_callbr(ptr %arg1, ptr %arg2) local_unnamed_addr align 2 { +; CHECK-LABEL: @internal-used-in-exit_callbr( +; CHECK-NEXT:  entry: +; CHECK-NEXT:    [[MYTMP42:%.*]] = load i32, ptr [[ARG1:%.*]], align 4 +; CHECK-NEXT:    callbr void asm "", ""() +; CHECK-NEXT:            to label [[A:%.*]] [] +; CHECK:       A: +; CHECK-NEXT:    [[CMP1:%.*]] = icmp slt i32 [[MYTMP42]], 0 +; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[CMP1]]) +; CHECK-NEXT:            to label [[B:%.*]] [label %A.target.return] +; CHECK:       B: +; CHECK-NEXT:    [[MYTMP41:%.*]] = load i32, ptr [[ARG2:%.*]], align 4 +; CHECK-NEXT:    callbr void asm "", ""() +; CHECK-NEXT:            to label [[C:%.*]] [] +; CHECK:       C: +; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[MYTMP42]], 0 +; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[CMP]]) +; CHECK-NEXT:            to label [[A]] [label %C.target.D] +; CHECK:       D: +; CHECK-NEXT:    [[INC:%.*]] = add i32 [[MYTMP41_MOVED:%.*]], 1 +; CHECK-NEXT:    callbr void asm "", ""() +; CHECK-NEXT:            to label [[RETURN:%.*]] [] +; CHECK:       return: +; CHECK-NEXT:    ret i32 0 +; CHECK:       A.target.return: +; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD:%.*]] +; CHECK:       C.target.D: +; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD]] +; CHECK:       loop.exit.guard: +; CHECK-NEXT:    [[MYTMP41_MOVED]] = phi i32 [ poison, [[A_TARGET_RETURN:%.*]] ], [ [[MYTMP41]], [[C_TARGET_D:%.*]] ] +; CHECK-NEXT:    [[GUARD_RETURN:%.*]] = phi i1 [ true, [[A_TARGET_RETURN]] ], [ false, [[C_TARGET_D]] ] +; CHECK-NEXT:    br i1 [[GUARD_RETURN]], label [[RETURN]], label [[D:%.*]] +; +entry: +  %mytmp42 = load i32, ptr %arg1, align 4 +  callbr void asm "", ""() to label %A [] + +A: +  %cmp1 = icmp slt i32 %mytmp42, 0 +  callbr void asm "", "r,!i"(i1 %cmp1) to label %B [label %return] + +B: +  %mytmp41 = load i32, ptr %arg2, align 4 +  callbr void asm "", ""() to label %C [] + +C: +  %cmp = icmp slt i32 %mytmp42, 0 +  callbr void asm "", "r,!i"(i1 %cmp) to label %A [label %D] + +D: +  %inc = add i32 %mytmp41, 1 +  callbr void asm "", ""() to label %return [] + +return: +  ret i32 0 +} +  ; Loop consists of A, B and C:  ; - A is the header  ; - A and C are exiting blocks @@ -172,6 +283,68 @@ return:    ret i32 %phi  } +define i32 @mixed-use-in-exit_callbr(ptr %arg1, ptr %arg2) local_unnamed_addr align 2 { +; CHECK-LABEL: @mixed-use-in-exit_callbr( +; CHECK-NEXT:  entry: +; CHECK-NEXT:    [[MYTMP42:%.*]] = load i32, ptr [[ARG1:%.*]], align 4 +; CHECK-NEXT:    [[CMP2:%.*]] = icmp slt i32 [[MYTMP42]], 0 +; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[CMP2]]) +; CHECK-NEXT:            to label [[A:%.*]] [label %return] +; CHECK:       A: +; CHECK-NEXT:    [[MYTMP43:%.*]] = add i32 [[MYTMP42]], 1 +; CHECK-NEXT:    [[CMP1:%.*]] = icmp slt i32 [[MYTMP42]], 0 +; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[CMP1]]) +; CHECK-NEXT:            to label [[B:%.*]] [label %A.target.return] +; CHECK:       B: +; CHECK-NEXT:    [[MYTMP41:%.*]] = load i32, ptr [[ARG2:%.*]], align 4 +; CHECK-NEXT:    callbr void asm "", ""() +; CHECK-NEXT:            to label [[C:%.*]] [] +; CHECK:       C: +; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[MYTMP42]], 0 +; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[CMP]]) +; CHECK-NEXT:            to label [[A]] [label %C.target.D] +; CHECK:       D: +; CHECK-NEXT:    callbr void asm "", ""() +; CHECK-NEXT:            to label [[RETURN:%.*]] [] +; CHECK:       return: +; CHECK-NEXT:    [[PHI:%.*]] = phi i32 [ [[MYTMP41_MOVED:%.*]], [[D:%.*]] ], [ [[MYTMP42]], [[ENTRY:%.*]] ], [ [[PHI_MOVED:%.*]], [[LOOP_EXIT_GUARD:%.*]] ] +; CHECK-NEXT:    ret i32 [[PHI]] +; CHECK:       A.target.return: +; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD]] +; CHECK:       C.target.D: +; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD]] +; CHECK:       loop.exit.guard: +; CHECK-NEXT:    [[MYTMP41_MOVED]] = phi i32 [ poison, [[A_TARGET_RETURN:%.*]] ], [ [[MYTMP41]], [[C_TARGET_D:%.*]] ] +; CHECK-NEXT:    [[PHI_MOVED]] = phi i32 [ [[MYTMP43]], [[A_TARGET_RETURN]] ], [ poison, [[C_TARGET_D]] ] +; CHECK-NEXT:    [[GUARD_RETURN:%.*]] = phi i1 [ true, [[A_TARGET_RETURN]] ], [ false, [[C_TARGET_D]] ] +; CHECK-NEXT:    br i1 [[GUARD_RETURN]], label [[RETURN]], label [[D]] +; +entry: +  %mytmp42 = load i32, ptr %arg1, align 4 +  %cmp2 = icmp slt i32 %mytmp42, 0 +  callbr void asm "", "r,!i"(i1 %cmp2) to label %A [label %return] + +A: +  %mytmp43 = add i32 %mytmp42, 1 +  %cmp1 = icmp slt i32 %mytmp42, 0 +  callbr void asm "", "r,!i"(i1 %cmp1) to label %B [label %return] + +B: +  %mytmp41 = load i32, ptr %arg2, align 4 +  callbr void asm "", ""() to label %C [] + +C: +  %cmp = icmp slt i32 %mytmp42, 0 +  callbr void asm "", "r,!i"(i1 %cmp) to label %A [label %D] + +D: +  callbr void asm "", ""() to label %return [] + +return: +  %phi = phi i32 [ %mytmp41, %D ], [ %mytmp43, %A ], [%mytmp42, %entry] +  ret i32 %phi +} +  ; Loop consists of A, B and C:  ; - A is the header  ; - A and C are exiting blocks @@ -236,3 +409,66 @@ return:    %phi = phi i32 [ %mytmp41, %D ], [ %mytmp42, %E ]    ret i32 %phi  } + +define i32 @phi-via-external-block_callbr(ptr %arg1, ptr %arg2) local_unnamed_addr align 2 { +; CHECK-LABEL: @phi-via-external-block_callbr( +; CHECK-NEXT:  entry: +; CHECK-NEXT:    [[MYTMP42:%.*]] = load i32, ptr [[ARG1:%.*]], align 4 +; CHECK-NEXT:    callbr void asm "", ""() +; CHECK-NEXT:            to label [[A:%.*]] [] +; CHECK:       A: +; CHECK-NEXT:    [[CMP1:%.*]] = icmp slt i32 [[MYTMP42]], 0 +; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[CMP1]]) +; CHECK-NEXT:            to label [[B:%.*]] [label %A.target.E] +; CHECK:       B: +; CHECK-NEXT:    [[MYTMP41:%.*]] = load i32, ptr [[ARG2:%.*]], align 4 +; CHECK-NEXT:    callbr void asm "", ""() +; CHECK-NEXT:            to label [[C:%.*]] [] +; CHECK:       C: +; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[MYTMP42]], 0 +; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[CMP]]) +; CHECK-NEXT:            to label [[A]] [label %C.target.D] +; CHECK:       D: +; CHECK-NEXT:    callbr void asm "", ""() +; CHECK-NEXT:            to label [[RETURN:%.*]] [] +; CHECK:       E: +; CHECK-NEXT:    callbr void asm "", ""() +; CHECK-NEXT:            to label [[RETURN]] [] +; CHECK:       return: +; CHECK-NEXT:    [[PHI:%.*]] = phi i32 [ [[MYTMP41_MOVED:%.*]], [[D:%.*]] ], [ [[MYTMP42]], [[E:%.*]] ] +; CHECK-NEXT:    ret i32 [[PHI]] +; CHECK:       A.target.E: +; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD:%.*]] +; CHECK:       C.target.D: +; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD]] +; CHECK:       loop.exit.guard: +; CHECK-NEXT:    [[MYTMP41_MOVED]] = phi i32 [ poison, [[A_TARGET_E:%.*]] ], [ [[MYTMP41]], [[C_TARGET_D:%.*]] ] +; CHECK-NEXT:    [[GUARD_E:%.*]] = phi i1 [ true, [[A_TARGET_E]] ], [ false, [[C_TARGET_D]] ] +; CHECK-NEXT:    br i1 [[GUARD_E]], label [[E]], label [[D]] +; +entry: +  %mytmp42 = load i32, ptr %arg1, align 4 +  callbr void asm "", ""() to label %A [] + +A: +  %cmp1 = icmp slt i32 %mytmp42, 0 +  callbr void asm "", "r,!i"(i1 %cmp1) to label %B [label %E] + +B: +  %mytmp41 = load i32, ptr %arg2, align 4 +  callbr void asm "", ""() to label %C [] + +C: +  %cmp = icmp slt i32 %mytmp42, 0 +  callbr void asm "", "r,!i"(i1 %cmp) to label %A [label %D] + +D: +  callbr void asm "", ""() to label %return [] + +E: +  callbr void asm "", ""() to label %return [] + +return: +  %phi = phi i32 [ %mytmp41, %D ], [ %mytmp42, %E ] +  ret i32 %phi +} diff --git a/llvm/test/Transforms/UnifyLoopExits/undef-phis.ll b/llvm/test/Transforms/UnifyLoopExits/undef-phis.ll index 05f50fc..e65e254 100644 --- a/llvm/test/Transforms/UnifyLoopExits/undef-phis.ll +++ b/llvm/test/Transforms/UnifyLoopExits/undef-phis.ll @@ -56,3 +56,71 @@ mbb5291:                                           ; preds = %mbb4321    store volatile [2 x i32] %i5293, ptr addrspace(5) null, align 4    ret void  } + +define fastcc void @undef_phi_callbr(i64 %i5247, i1 %i4530, i1 %i4936.not) { +; CHECK-LABEL: define fastcc void @undef_phi_callbr( +; CHECK-SAME: i64 [[I5247:%.*]], i1 [[I4530:%.*]], i1 [[I4936_NOT:%.*]]) { +; CHECK-NEXT:  [[MBB:.*:]] +; CHECK-NEXT:    callbr void asm "", ""() +; CHECK-NEXT:            to label %[[MBB3932:.*]] [] +; CHECK:       [[MBB3932]]: +; CHECK-NEXT:    callbr void asm "", ""() +; CHECK-NEXT:            to label %[[MBB4454:.*]] [] +; CHECK:       [[MBB4321:.*]]: +; CHECK-NEXT:    [[TMP0:%.*]] = trunc i64 [[I5247]] to i32 +; CHECK-NEXT:    [[I5290:%.*]] = icmp eq i32 [[TMP0]], 0 +; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[I5290]]) +; CHECK-NEXT:            to label %[[MBB3932]] [label %mbb4321.target.mbb5291] +; CHECK:       [[MBB4454]]: +; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[I4530]]) +; CHECK-NEXT:            to label %[[MBB4535:.*]] [label %mbb4454.target.mbb4454.target.mbb4531] +; CHECK:       [[MBB4531:.*]]: +; CHECK-NEXT:    ret void +; CHECK:       [[MBB4535]]: +; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[I4936_NOT]]) +; CHECK-NEXT:            to label %[[MBB4535_TARGET_MBB4321:.*]] [label %mbb4454] +; CHECK:       [[MBB5291:.*]]: +; CHECK-NEXT:    [[I5293:%.*]] = insertvalue [2 x i32] zeroinitializer, i32 [[DOTMOVED:%.*]], 1 +; CHECK-NEXT:    store volatile [2 x i32] [[I5293]], ptr addrspace(5) null, align 4 +; CHECK-NEXT:    ret void +; CHECK:       [[MBB4454_TARGET_MBB4531:.*]]: +; CHECK-NEXT:    br label %[[LOOP_EXIT_GUARD:.*]] +; CHECK:       [[MBB4321_TARGET_MBB5291:.*]]: +; CHECK-NEXT:    br label %[[LOOP_EXIT_GUARD]] +; CHECK:       [[LOOP_EXIT_GUARD]]: +; CHECK-NEXT:    [[DOTMOVED]] = phi i32 [ poison, %[[MBB4454_TARGET_MBB4531]] ], [ [[TMP0]], %[[MBB4321_TARGET_MBB5291]] ] +; CHECK-NEXT:    [[GUARD_MBB4531:%.*]] = phi i1 [ true, %[[MBB4454_TARGET_MBB4531]] ], [ false, %[[MBB4321_TARGET_MBB5291]] ] +; CHECK-NEXT:    br i1 [[GUARD_MBB4531]], label %[[MBB4531]], label %[[MBB5291]] +; CHECK:       [[MBB4454_TARGET_MBB4454_TARGET_MBB4531:.*]]: +; CHECK-NEXT:    br label %[[LOOP_EXIT_GUARD1:.*]] +; CHECK:       [[MBB4535_TARGET_MBB4321]]: +; CHECK-NEXT:    br label %[[LOOP_EXIT_GUARD1]] +; CHECK:       [[LOOP_EXIT_GUARD1]]: +; CHECK-NEXT:    [[GUARD_MBB4454_TARGET_MBB4531:%.*]] = phi i1 [ true, %[[MBB4454_TARGET_MBB4454_TARGET_MBB4531]] ], [ false, %[[MBB4535_TARGET_MBB4321]] ] +; CHECK-NEXT:    br i1 [[GUARD_MBB4454_TARGET_MBB4531]], label %[[MBB4454_TARGET_MBB4531]], label %[[MBB4321]] +; +mbb: +  callbr void asm "", ""() to label %mbb3932 [] + +mbb3932:                                           ; preds = %mbb4321, %mbb +  callbr void asm "", ""() to label %mbb4454 [] + +mbb4321:                                           ; preds = %mbb4535 +  %0 = trunc i64 %i5247 to i32 +  %i5290 = icmp eq i32 %0, 0 +  callbr void asm "", "r,!i"(i1 %i5290) to label %mbb3932 [label %mbb5291] + +mbb4454:                                           ; preds = %mbb4535, %mbb3932 +  callbr void asm "", "r,!i"(i1 %i4530) to label %mbb4535 [label %mbb4531] + +mbb4531:                                           ; preds = %mbb4454 +  ret void + +mbb4535:                                           ; preds = %mbb4454 +  callbr void asm "", "r,!i"(i1 %i4936.not) to label %mbb4321 [label %mbb4454] + +mbb5291:                                           ; preds = %mbb4321 +  %i5293 = insertvalue [2 x i32] zeroinitializer, i32 %0, 1 +  store volatile [2 x i32] %i5293, ptr addrspace(5) null, align 4 +  ret void +} | 
