From ee79dbb0c4ddbdd7e01f05c868b67695a56b4153 Mon Sep 17 00:00:00 2001 From: Sanjay Patel Date: Thu, 25 Jul 2019 17:01:12 +0000 Subject: [PATCH] [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 --- lib/Transforms/Utils/SimplifyCFG.cpp | 25 ++++++++---- .../SimplifyCFG/switch-range-to-icmp.ll | 38 +++++++++++++++++++ 2 files changed, 55 insertions(+), 8 deletions(-) diff --git a/lib/Transforms/Utils/SimplifyCFG.cpp b/lib/Transforms/Utils/SimplifyCFG.cpp index 11651d040dc..f5bcdc74a08 100644 --- a/lib/Transforms/Utils/SimplifyCFG.cpp +++ b/lib/Transforms/Utils/SimplifyCFG.cpp @@ -4276,6 +4276,17 @@ static bool CasesAreContiguous(SmallVectorImpl &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(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; } diff --git a/test/Transforms/SimplifyCFG/switch-range-to-icmp.ll b/test/Transforms/SimplifyCFG/switch-range-to-icmp.ll index c0f6a43fda3..d99e84b6b94 100644 --- a/test/Transforms/SimplifyCFG/switch-range-to-icmp.ll +++ b/test/Transforms/SimplifyCFG/switch-range-to-icmp.ll @@ -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 +}