Author: Florian Hahn Date: 2022-05-11T14:45:05-07:00 New Revision: 60c8e02c9d12b38c00e5f870d883c5ac293a5371
URL: https://github.com/llvm/llvm-project/commit/60c8e02c9d12b38c00e5f870d883c5ac293a5371 DIFF: https://github.com/llvm/llvm-project/commit/60c8e02c9d12b38c00e5f870d883c5ac293a5371.diff LOG: [IPSCCP] Support unfeasible default dests for switch. At the moment, unfeasible default destinations are not handled properly in removeNonFeasibleEdges. So far, only unfeasible cases are removed, but later code expects unreachable blocks to have no predecessors. This is causing the crash reported in PR49573. If the default destination is unfeasible it won't be executed. Create a new unreachable block on demand and use that as default destination. Note that at the moment this only is relevant for cases where resolvedUndefsIn marks the first case as executable. Regular switch handling has a FIXME/TODO to support determining whether the default case is feasible or not. Fixes #48917. Differential Revision: https://reviews.llvm.org/D113497 (cherry picked from commit 857c612d899f271402470d4026d2e3be1dce53a4) Added: Modified: llvm/lib/Transforms/Scalar/SCCP.cpp llvm/test/Transforms/SCCP/switch-constantfold-crash.ll Removed: ################################################################################ diff --git a/llvm/lib/Transforms/Scalar/SCCP.cpp b/llvm/lib/Transforms/Scalar/SCCP.cpp index c34da51e6dc17..fa1cfc84e4fda 100644 --- a/llvm/lib/Transforms/Scalar/SCCP.cpp +++ b/llvm/lib/Transforms/Scalar/SCCP.cpp @@ -342,7 +342,8 @@ static void findReturnsToZap(Function &F, } static bool removeNonFeasibleEdges(const SCCPSolver &Solver, BasicBlock *BB, - DomTreeUpdater &DTU) { + DomTreeUpdater &DTU, + BasicBlock *&NewUnreachableBB) { SmallPtrSet<BasicBlock *, 8> FeasibleSuccessors; bool HasNonFeasibleEdges = false; for (BasicBlock *Succ : successors(BB)) { @@ -385,6 +386,23 @@ static bool removeNonFeasibleEdges(const SCCPSolver &Solver, BasicBlock *BB, } else if (FeasibleSuccessors.size() > 1) { SwitchInstProfUpdateWrapper SI(*cast<SwitchInst>(TI)); SmallVector<DominatorTree::UpdateType, 8> Updates; + + // If the default destination is unfeasible it will never be taken. Replace + // it with a new block with a single Unreachable instruction. + BasicBlock *DefaultDest = SI->getDefaultDest(); + if (!FeasibleSuccessors.contains(DefaultDest)) { + if (!NewUnreachableBB) { + NewUnreachableBB = + BasicBlock::Create(DefaultDest->getContext(), "default.unreachable", + DefaultDest->getParent(), DefaultDest); + new UnreachableInst(DefaultDest->getContext(), NewUnreachableBB); + } + + SI->setDefaultDest(NewUnreachableBB); + Updates.push_back({DominatorTree::Delete, BB, DefaultDest}); + Updates.push_back({DominatorTree::Insert, BB, NewUnreachableBB}); + } + for (auto CI = SI->case_begin(); CI != SI->case_end();) { if (FeasibleSuccessors.contains(CI->getCaseSuccessor())) { ++CI; @@ -532,8 +550,9 @@ bool llvm::runIPSCCP( NumInstRemoved += changeToUnreachable(F.front().getFirstNonPHI(), /*PreserveLCSSA=*/false, &DTU); + BasicBlock *NewUnreachableBB = nullptr; for (BasicBlock &BB : F) - MadeChanges |= removeNonFeasibleEdges(Solver, &BB, DTU); + MadeChanges |= removeNonFeasibleEdges(Solver, &BB, DTU, NewUnreachableBB); for (BasicBlock *DeadBB : BlocksToErase) DTU.deleteBB(DeadBB); diff --git a/llvm/test/Transforms/SCCP/switch-constantfold-crash.ll b/llvm/test/Transforms/SCCP/switch-constantfold-crash.ll index eb727fc54c03d..4aa1679310542 100644 --- a/llvm/test/Transforms/SCCP/switch-constantfold-crash.ll +++ b/llvm/test/Transforms/SCCP/switch-constantfold-crash.ll @@ -1,8 +1,9 @@ -; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt -passes=ipsccp < %s -S | FileCheck %s +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature +; RUN: opt -passes=ipsccp < %s -S | FileCheck --check-prefixes=CHECK,ONCE %s +; RUN: opt -passes='ipsccp,ipsccp' < %s -S | FileCheck --check-prefixes=CHECK,TWICE %s define void @barney() { -; CHECK-LABEL: @barney( +; CHECK-LABEL: define {{[^@]+}}@barney() { ; CHECK-NEXT: bb: ; CHECK-NEXT: br label [[BB9:%.*]] ; CHECK: bb6: @@ -26,7 +27,7 @@ bb9: ; preds = %bb } define void @blam() { -; CHECK-LABEL: @blam( +; CHECK-LABEL: define {{[^@]+}}@blam() { ; CHECK-NEXT: bb: ; CHECK-NEXT: br label [[BB16:%.*]] ; CHECK: bb16: @@ -59,7 +60,7 @@ bb38: ; preds = %bb16 define void @hoge() { -; CHECK-LABEL: @hoge( +; CHECK-LABEL: define {{[^@]+}}@hoge() { ; CHECK-NEXT: bb: ; CHECK-NEXT: br label [[BB2:%.*]] ; CHECK: bb2: @@ -89,3 +90,142 @@ bb3: ; preds = %bb2 bb4: ; preds = %bb2, %bb2, %bb2 unreachable } + +; Test case from PR49573. %default.bb is unfeasible. Make sure it gets replaced +; by an unreachable block. +define void @pr49573_main() { +; ONCE-LABEL: define {{[^@]+}}@pr49573_main() { +; ONCE-NEXT: entry: +; ONCE-NEXT: [[TGT:%.*]] = call i16 @pr49573_fn() +; ONCE-NEXT: switch i16 2, label [[DEFAULT_UNREACHABLE:%.*]] [ +; ONCE-NEXT: i16 0, label [[CASE_0:%.*]] +; ONCE-NEXT: i16 2, label [[CASE_2:%.*]] +; ONCE-NEXT: ] +; ONCE: case.0: +; ONCE-NEXT: unreachable +; ONCE: default.unreachable: +; ONCE-NEXT: unreachable +; ONCE: case.2: +; ONCE-NEXT: br label [[NEXT:%.*]] +; ONCE: next: +; ONCE-NEXT: [[TGT_2:%.*]] = call i16 @pr49573_fn_2() +; ONCE-NEXT: switch i16 2, label [[DEFAULT_UNREACHABLE]] [ +; ONCE-NEXT: i16 0, label [[CASE_0]] +; ONCE-NEXT: i16 2, label [[CASE_2]] +; ONCE-NEXT: ] +; +; TWICE-LABEL: define {{[^@]+}}@pr49573_main() { +; TWICE-NEXT: entry: +; TWICE-NEXT: [[TGT:%.*]] = call i16 @pr49573_fn() +; TWICE-NEXT: br label [[CASE_2:%.*]] +; TWICE: case.2: +; TWICE-NEXT: br label [[NEXT:%.*]] +; TWICE: next: +; TWICE-NEXT: [[TGT_2:%.*]] = call i16 @pr49573_fn_2() +; TWICE-NEXT: br label [[CASE_2]] +; +entry: + %tgt = call i16 @pr49573_fn() + switch i16 %tgt, label %default.bb [ + i16 0, label %case.0 + i16 1, label %case.1 + i16 2, label %case.2 + ] + +case.0: + unreachable + +default.bb: + ret void + +case.1: + ret void + +case.2: + br label %next + +next: + %tgt.2 = call i16 @pr49573_fn_2() + switch i16 %tgt.2, label %default.bb [ + i16 0, label %case.0 + i16 2, label %case.2 + ] +} + +; Make sure a new unreachable BB is created. +define void @pr49573_main_2() { +; ONCE-LABEL: define {{[^@]+}}@pr49573_main_2() { +; ONCE-NEXT: entry: +; ONCE-NEXT: [[TGT:%.*]] = call i16 @pr49573_fn() +; ONCE-NEXT: switch i16 2, label [[DEFAULT_UNREACHABLE:%.*]] [ +; ONCE-NEXT: i16 0, label [[CASE_0:%.*]] +; ONCE-NEXT: i16 2, label [[CASE_2:%.*]] +; ONCE-NEXT: ] +; ONCE: case.0: +; ONCE-NEXT: unreachable +; ONCE: default.unreachable: +; ONCE-NEXT: unreachable +; ONCE: case.2: +; ONCE-NEXT: ret void +; +; TWICE-LABEL: define {{[^@]+}}@pr49573_main_2() { +; TWICE-NEXT: entry: +; TWICE-NEXT: [[TGT:%.*]] = call i16 @pr49573_fn() +; TWICE-NEXT: br label [[CASE_2:%.*]] +; TWICE: case.2: +; TWICE-NEXT: ret void +; +entry: + %tgt = call i16 @pr49573_fn() + switch i16 %tgt, label %default.bb [ + i16 0, label %case.0 + i16 1, label %case.1 + i16 2, label %case.2 + ] + +case.0: + unreachable + +default.bb: + ret void + +case.1: + ret void + +case.2: + ret void +} + +define internal i16 @pr49573_fn() { +; CHECK-LABEL: define {{[^@]+}}@pr49573_fn() { +; CHECK-NEXT: entry: +; CHECK-NEXT: br label [[ELSE:%.*]] +; CHECK: else: +; CHECK-NEXT: ret i16 undef +; +entry: + br i1 undef, label %then, label %else + +then: + ret i16 0 + +else: + ret i16 2 +} + +define internal i16 @pr49573_fn_2() { +; CHECK-LABEL: define {{[^@]+}}@pr49573_fn_2() { +; CHECK-NEXT: entry: +; CHECK-NEXT: br label [[ELSE:%.*]] +; CHECK: else: +; CHECK-NEXT: ret i16 undef +; +entry: + br i1 undef, label %then, label %else + +then: + ret i16 0 + +else: + ret i16 2 +} _______________________________________________ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits