[runtimeunroll] Support multiple exits to latch exit w/epilogue loop

This patch extends the runtime unrolling infrastructure to support unrolling a loop with multiple exiting blocks branching to the same exit block used by the latch. It intentionally does not include a cost model change to enable this functionality unless appropriate force flags are used.

I decided to restrict this to the epilogue case. Given the changes ended up being pretty generic, we may be able to unblock the prolog case too, but I want to do that in a separate change to reduce the amount of code we all have to understand at one time.

Differential Revision: https://reviews.llvm.org/D107381
This commit is contained in:
Philip Reames 2021-08-17 17:50:58 -07:00
parent b26e1efc42
commit 94d0914292
2 changed files with 775 additions and 113 deletions

View File

@ -215,7 +215,10 @@ static void ConnectEpilog(Loop *L, Value *ModVal, BasicBlock *NewExit,
// PN = PHI [I, Latch]
// ...
// Exit:
// EpilogPN = PHI [PN, EpilogPreHeader]
// EpilogPN = PHI [PN, EpilogPreHeader], [X, Exit2], [Y, Exit2.epil]
//
// Exits from non-latch blocks point to the original exit block and the
// epilogue edges have already been added.
//
// There is EpilogPreHeader incoming block instead of NewExit as
// NewExit was spilt 1 more time to get EpilogPreHeader.
@ -441,9 +444,8 @@ static bool canSafelyUnrollMultiExitLoop(Loop *L, BasicBlock *LatchExit,
return false;
// TODO: Support multiple exiting blocks jumping to the `LatchExit` when
// UnrollRuntimeMultiExit is true. This will need updating the logic in
// connectEpilog/connectProlog.
if (!LatchExit->getSinglePredecessor()) {
// using a prolog loop.
if (!UseEpilogRemainder && !LatchExit->getSinglePredecessor()) {
LLVM_DEBUG(
dbgs() << "Bailout for multi-exit handling when latch exit has >1 "
"predecessor.\n");
@ -477,6 +479,11 @@ static bool canProfitablyUnrollMultiExitLoop(
if (UnrollRuntimeMultiExit.getNumOccurrences())
return UnrollRuntimeMultiExit;
// TODO: We used to bail out for correctness (now fixed). Under what
// circumstances is this case profitable to allow?
if (!LatchExit->getSinglePredecessor())
return false;
// The main pain point with multi-exit loop unrolling is that once unrolled,
// we will not be able to merge all blocks into a straight line code.
// There are branches within the unrolled loop that go to the OtherExits.
@ -740,8 +747,7 @@ bool llvm::UnrollRuntimeLoopRemainder(
NewPreHeader = SplitBlock(PreHeader, PreHeader->getTerminator(), DT, LI);
NewPreHeader->setName(PreHeader->getName() + ".new");
// Split LatchExit to create phi nodes from branch above.
SmallVector<BasicBlock*, 4> Preds(predecessors(LatchExit));
NewExit = SplitBlockPredecessors(LatchExit, Preds, ".unr-lcssa", DT, LI,
NewExit = SplitBlockPredecessors(LatchExit, {Latch}, ".unr-lcssa", DT, LI,
nullptr, PreserveLCSSA);
// NewExit gets its DebugLoc from LatchExit, which is not part of the
// original Loop.
@ -856,6 +862,14 @@ bool llvm::UnrollRuntimeLoopRemainder(
// node.
for (unsigned i = 0; i < oldNumOperands; i++){
auto *PredBB =PN.getIncomingBlock(i);
if (PredBB == Latch)
// The latch exit is handled seperately, see connectX
continue;
if (!L->contains(PredBB))
// Even if we had dedicated exits, the code above inserted an
// extra branch which can reach the latch exit.
continue;
auto *V = PN.getIncomingValue(i);
if (Instruction *I = dyn_cast<Instruction>(V))
if (L->contains(I))