[LoopDeletion] Update exits correctly when multiple duplicate edges from an exiting block

Summary:
Currently, we incorrectly update exit blocks of loops when there are multiple
edges from a single exiting block to the exit block. This can happen when we
have switches as the terminator of the exiting blocks.
The fix here is to correctly update the phi nodes in the exit block, and remove
all incoming values *except* for one which is from the preheader.

Note: Currently, this error can manifest only while deleting non-executed loops. However, it
is possible to trigger this error in invariant loops, once we enhance the logic
around the exit conditions for the loop check.

Reviewers: chandlerc, dberlin, sanjoy, efriedma

Reviewed by: efriedma

Subscribers: mzolotukhin, llvm-commits

Differential Revision: https://reviews.llvm.org/D34516

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@306048 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Anna Thomas 2017-06-22 20:20:56 +00:00
parent d40aee4db0
commit 980c01094a
2 changed files with 97 additions and 9 deletions

View File

@ -227,6 +227,8 @@ static void deleteDeadLoop(Loop *L, DominatorTree &DT, ScalarEvolution &SE,
auto *ExitBlock = L->getUniqueExitBlock();
assert(ExitBlock && "Should have a unique exit block!");
assert(L->hasDedicatedExits() && "Loop should have dedicated exits!");
// Connect the preheader directly to the exit block.
// Even when the loop is never executed, we cannot remove the edge from the
// source block to the exit block. Consider the case where the unexecuted loop
@ -236,20 +238,30 @@ static void deleteDeadLoop(Loop *L, DominatorTree &DT, ScalarEvolution &SE,
// non-loop, it will be deleted in a future iteration of loop deletion pass.
Preheader->getTerminator()->replaceUsesOfWith(L->getHeader(), ExitBlock);
SmallVector<BasicBlock *, 4> ExitingBlocks;
L->getExitingBlocks(ExitingBlocks);
// Rewrite phis in the exit block to get their inputs from the Preheader
// instead of the exiting block.
BasicBlock *ExitingBlock = ExitingBlocks[0];
BasicBlock::iterator BI = ExitBlock->begin();
while (PHINode *P = dyn_cast<PHINode>(BI)) {
int j = P->getBasicBlockIndex(ExitingBlock);
assert(j >= 0 && "Can't find exiting block in exit block's phi node!");
// Set the zero'th element of Phi to be from the preheader and remove all
// other incoming values. Given the loop has dedicated exits, all other
// incoming values must be from the exiting blocks.
int PredIndex = 0;
if (LoopIsNeverExecuted)
P->setIncomingValue(j, UndefValue::get(P->getType()));
P->setIncomingBlock(j, Preheader);
for (unsigned i = 1; i < ExitingBlocks.size(); ++i)
P->removeIncomingValue(ExitingBlocks[i]);
P->setIncomingValue(PredIndex, UndefValue::get(P->getType()));
P->setIncomingBlock(PredIndex, Preheader);
// Removes all incoming values from all other exiting blocks (including
// duplicate values from an exiting block).
// Nuke all entries except the zero'th entry which is the preheader entry.
// NOTE! We need to remove Incoming Values in the reverse order as done
// below, to keep the indices valid for deletion (removeIncomingValues
// updates getNumIncomingValues and shifts all values down into the operand
// being deleted).
for (unsigned i = 0, e = P->getNumIncomingValues() - 1; i != e; ++i)
P->removeIncomingValue(e-i, false);
assert((P->getNumIncomingValues() == 1 &&
P->getIncomingBlock(PredIndex) == Preheader) &&
"Should have exactly one value and that's from the preheader!");
++BI;
}

View File

@ -334,3 +334,79 @@ exit:
ret void
}
; 2 edges from a single exiting block to the exit block.
define i64 @test12(i64 %n){
;CHECK-LABEL: @test12
; CHECK-NOT: L1:
; CHECK-NOT: L1Latch:
; CHECK-LABEL: L1.preheader:
; CHECK-NEXT: br label %exit
; CHECK-LABEL: exit:
; CHECK-NEXT: %y.phi = phi i64 [ undef, %L1.preheader ]
; CHECK-NEXT: ret i64 %y.phi
entry:
br i1 true, label %exit1, label %L1
exit1:
ret i64 42
L1: ; preds = %L1Latch, %entry
%y.next = phi i64 [ 0, %entry ], [ %y.add, %L1Latch ]
br i1 true, label %L1Latch, label %exit
L1Latch: ; preds = %L1
%y = phi i64 [ %y.next, %L1 ]
%y.add = add i64 %y, %n
%cond2 = icmp eq i64 %y.add, 42
switch i64 %n, label %L1 [
i64 10, label %exit
i64 20, label %exit
]
exit: ; preds = %L1Latch, %L1Latch
%y.phi = phi i64 [ 10, %L1Latch ], [ 10, %L1Latch ], [ %y.next, %L1]
ret i64 %y.phi
}
; multiple edges to exit block from the same exiting blocks
define i64 @test13(i64 %n) {
; CHECK-LABEL: @test13
; CHECK-NOT: L1:
; CHECK-NOT: L1Latch:
; CHECK-LABEL: L1.preheader:
; CHECK-NEXT: br label %exit
; CHECK-LABEL: exit:
; CHECK-NEXT: %y.phi = phi i64 [ undef, %L1.preheader ]
; CHECK-NEXT: ret i64 %y.phi
entry:
br i1 true, label %exit1, label %L1
exit1:
ret i64 42
L1: ; preds = %L1Latch, %entry
%y.next = phi i64 [ 0, %entry ], [ %y.add, %L1Latch ]
br i1 true, label %L1Block, label %exit
L1Block: ; preds = %L1
%y = phi i64 [ %y.next, %L1 ]
%y.add = add i64 %y, %n
%cond2 = icmp eq i64 %y.add, 42
switch i64 %n, label %L1Latch [
i64 10, label %exit
i64 20, label %exit
]
L1Latch:
switch i64 %n, label %L1 [
i64 30, label %exit
i64 40, label %exit
]
exit: ; preds = %L1Block, %L1, %L1Latch
%y.phi = phi i64 [ 10, %L1Block ], [ 10, %L1Block ], [ %y.next, %L1 ], [ 30, %L1Latch ], [ 30, %L1Latch ]
ret i64 %y.phi
}