mirror of
https://github.com/RPCS3/llvm.git
synced 2025-01-09 21:50:50 +00:00
[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:
parent
d40aee4db0
commit
980c01094a
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user