diff --git a/llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp b/llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp --- a/llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp +++ b/llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp @@ -598,6 +598,17 @@ auto *ParentBB = SI.getParent(); + auto ArePhisLoopInvAndNotUnreachable = [&](BasicBlock *BBToCheck) { + bool isLoopExitAndPhisInvariant = + !L.contains(BBToCheck) && + areLoopExitPHIsLoopInvariant(L, *ParentBB, *BBToCheck); + auto *TI = BBToCheck->getTerminator(); + bool isUnreachable = isa(TI); + bool isNotEmptyUnreachable = + !isUnreachable || (isUnreachable && (&*BBToCheck->begin() != TI)); + return isLoopExitAndPhisInvariant && isNotEmptyUnreachable; + }; + SmallVector ExitCaseIndices; for (auto Case : SI.cases()) { auto *SuccBB = Case.getCaseSuccessor(); @@ -608,9 +619,7 @@ BasicBlock *DefaultExitBB = nullptr; SwitchInstProfUpdateWrapper::CaseWeightOpt DefaultCaseWeight = SwitchInstProfUpdateWrapper::getSuccessorWeight(SI, 0); - if (!L.contains(SI.getDefaultDest()) && - areLoopExitPHIsLoopInvariant(L, *ParentBB, *SI.getDefaultDest()) && - !isa(SI.getDefaultDest()->getTerminator())) { + if (ArePhisLoopInvAndNotUnreachable(SI.getDefaultDest())) { DefaultExitBB = SI.getDefaultDest(); } else if (ExitCaseIndices.empty()) return false; diff --git a/llvm/test/Transforms/SimpleLoopUnswitch/trivial-unswitch.ll b/llvm/test/Transforms/SimpleLoopUnswitch/trivial-unswitch.ll --- a/llvm/test/Transforms/SimpleLoopUnswitch/trivial-unswitch.ll +++ b/llvm/test/Transforms/SimpleLoopUnswitch/trivial-unswitch.ll @@ -1243,3 +1243,52 @@ ; CHECK: loopexit: ; CHECK-NEXT: ret } + +declare void @f() +declare void @g() +define void @test_unswitch_switch_with_nonempty_unreachable() { +; CHECK-LABEL: @test_unswitch_switch_with_nonempty_unreachable() +entry: + br label %loop + +loop: + %cleanup.dest.slot.0 = select i1 undef, i32 5, i32 undef + br label %for.cond + +for.cond: + switch i32 %cleanup.dest.slot.0, label %NonEmptyUnreachableBlock [ + i32 0, label %for.cond + i32 1, label %NonEmptyUnreachableBlock + i32 2, label %loop.loopexit + ] + +loop.loopexit: + unreachable + +NonEmptyUnreachableBlock: + call void @f() + call void @g() + unreachable + +; CHECK:loop: +; CHECK-NEXT: %cleanup.dest.slot.0 = select i1 undef, i32 5, i32 undef +; CHECK-NEXT: switch i32 %cleanup.dest.slot.0, label %NonEmptyUnreachableBlock [ +; CHECK-NEXT: i32 1, label %NonEmptyUnreachableBlock +; CHECK-NEXT: i32 2, label %loop.loopexit +; CHECK-NEXT: i32 0, label %loop.split +; CHECK-NEXT: ] + +; CHECK:loop.split: +; CHECK-NEXT: br label %for.cond + +; CHECK:for.cond: +; CHECK-NEXT: br label %for.cond + +; CHECK:loop.loopexit: +; CHECK-NEXT: unreachable + +; CHECK:NonEmptyUnreachableBlock: +; CHECK-NEXT: call void @f() +; CHECK-NEXT: call void @g() +; CHECK-NEXT: unreachable +}