mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-12-12 22:17:47 +00:00
[SimplifyCFG] avoid crashing after simplifying a switch (PR42737)
Later code in TryToSimplifyUncondBranchFromEmptyBlock() assumes that we have cleaned up unreachable blocks, but that was not happening with this switch transform. llvm-svn: 367037
This commit is contained in:
parent
c6f2828c49
commit
ee79dbb0c4
@ -4276,6 +4276,17 @@ static bool CasesAreContiguous(SmallVectorImpl<ConstantInt *> &Cases) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static void createUnreachableSwitchDefault(SwitchInst *Switch) {
|
||||
LLVM_DEBUG(dbgs() << "SimplifyCFG: switch default is dead.\n");
|
||||
BasicBlock *NewDefaultBlock =
|
||||
SplitBlockPredecessors(Switch->getDefaultDest(), Switch->getParent(), "");
|
||||
Switch->setDefaultDest(&*NewDefaultBlock);
|
||||
SplitBlock(&*NewDefaultBlock, &NewDefaultBlock->front());
|
||||
auto *NewTerminator = NewDefaultBlock->getTerminator();
|
||||
new UnreachableInst(Switch->getContext(), NewTerminator);
|
||||
EraseTerminatorAndDCECond(NewTerminator);
|
||||
}
|
||||
|
||||
/// Turn a switch with two reachable destinations into an integer range
|
||||
/// comparison and branch.
|
||||
static bool TurnSwitchRangeIntoICmp(SwitchInst *SI, IRBuilder<> &Builder) {
|
||||
@ -4384,6 +4395,11 @@ static bool TurnSwitchRangeIntoICmp(SwitchInst *SI, IRBuilder<> &Builder) {
|
||||
cast<PHINode>(BBI)->removeIncomingValue(SI->getParent());
|
||||
}
|
||||
|
||||
// Clean up the default block - it may have phis or other instructions before
|
||||
// the unreachable terminator.
|
||||
if (!HasDefault)
|
||||
createUnreachableSwitchDefault(SI);
|
||||
|
||||
// Drop the switch.
|
||||
SI->eraseFromParent();
|
||||
|
||||
@ -4428,14 +4444,7 @@ static bool eliminateDeadSwitchCases(SwitchInst *SI, AssumptionCache *AC,
|
||||
if (HasDefault && DeadCases.empty() &&
|
||||
NumUnknownBits < 64 /* avoid overflow */ &&
|
||||
SI->getNumCases() == (1ULL << NumUnknownBits)) {
|
||||
LLVM_DEBUG(dbgs() << "SimplifyCFG: switch default is dead.\n");
|
||||
BasicBlock *NewDefault =
|
||||
SplitBlockPredecessors(SI->getDefaultDest(), SI->getParent(), "");
|
||||
SI->setDefaultDest(&*NewDefault);
|
||||
SplitBlock(&*NewDefault, &NewDefault->front());
|
||||
auto *OldTI = NewDefault->getTerminator();
|
||||
new UnreachableInst(SI->getContext(), OldTI);
|
||||
EraseTerminatorAndDCECond(OldTI);
|
||||
createUnreachableSwitchDefault(SI);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -100,3 +100,41 @@ b:
|
||||
%1 = call i32 @f(i32 1)
|
||||
ret i32 %1
|
||||
}
|
||||
|
||||
; This would crash because we did not clean up the
|
||||
; default block of the switch before removing the switch.
|
||||
|
||||
define void @PR42737(i32* %a, i1 %c) {
|
||||
; CHECK-LABEL: @PR42737(
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: [[TMP0:%.*]] = xor i1 [[C:%.*]], true
|
||||
; CHECK-NEXT: call void @llvm.assume(i1 [[TMP0]])
|
||||
; CHECK-NEXT: unreachable
|
||||
;
|
||||
entry:
|
||||
br i1 %c, label %switch, label %else
|
||||
|
||||
else:
|
||||
store i32 2, i32* %a
|
||||
br label %switch
|
||||
|
||||
switch:
|
||||
%cleanup.dest1 = phi i32 [ 0, %else ], [ 3, %entry ]
|
||||
switch i32 %cleanup.dest1, label %unreach1 [
|
||||
i32 0, label %cleanup1
|
||||
i32 3, label %cleanup2
|
||||
]
|
||||
|
||||
cleanup1:
|
||||
br label %unreach2
|
||||
|
||||
cleanup2:
|
||||
br label %unreach2
|
||||
|
||||
unreach1:
|
||||
%phi2 = phi i32 [ %cleanup.dest1, %switch ]
|
||||
unreachable
|
||||
|
||||
unreach2:
|
||||
unreachable
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user