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 +} |
