diff --git a/llvm/lib/Transforms/Utils/CloneFunction.cpp b/llvm/lib/Transforms/Utils/CloneFunction.cpp --- a/llvm/lib/Transforms/Utils/CloneFunction.cpp +++ b/llvm/lib/Transforms/Utils/CloneFunction.cpp @@ -694,38 +694,39 @@ VMap[OrigV] = I; } + // Simplify conditional branches and switches with a constant operand. We try + // to prune these out when cloning, but if the simplification required + // looking through PHI nodes, those are only available after forming the full + // basic block. That may leave some here, and we still want to prune the dead + // code as early as possible. + Function::iterator Begin = cast(VMap[StartingBB])->getIterator(); + for (BasicBlock &BB : make_range(Begin, NewFunc->end())) + ConstantFoldTerminator(&BB); + + // Some blocks may have become unreachable as a result. Find and delete them. + { + SmallPtrSet ReachableBlocks; + SmallVector Worklist; + Worklist.push_back(&*Begin); + while (!Worklist.empty()) { + BasicBlock *BB = Worklist.pop_back_val(); + if (ReachableBlocks.insert(BB).second) + append_range(Worklist, successors(BB)); + } + + SmallVector UnreachableBlocks; + for (BasicBlock &BB : make_range(Begin, NewFunc->end())) + if (!ReachableBlocks.contains(&BB)) + UnreachableBlocks.push_back(&BB); + DeleteDeadBlocks(UnreachableBlocks); + } + // Now that the inlined function body has been fully constructed, go through // and zap unconditional fall-through branches. This happens all the time when // specializing code: code specialization turns conditional branches into // uncond branches, and this code folds them. - Function::iterator Begin = cast(VMap[StartingBB])->getIterator(); Function::iterator I = Begin; while (I != NewFunc->end()) { - // We need to simplify conditional branches and switches with a constant - // operand. We try to prune these out when cloning, but if the - // simplification required looking through PHI nodes, those are only - // available after forming the full basic block. That may leave some here, - // and we still want to prune the dead code as early as possible. - // - // Do the folding before we check if the block is dead since we want code - // like - // bb: - // br i1 undef, label %bb, label %bb - // to be simplified to - // bb: - // br label %bb - // before we call I->getSinglePredecessor(). - ConstantFoldTerminator(&*I); - - // Check if this block has become dead during inlining or other - // simplifications. Note that the first block will appear dead, as it has - // not yet been wired up properly. - if (I != Begin && (pred_empty(&*I) || I->getSinglePredecessor() == &*I)) { - BasicBlock *DeadBB = &*I++; - DeleteDeadBlock(DeadBB); - continue; - } - BranchInst *BI = dyn_cast(I->getTerminator()); if (!BI || BI->isConditional()) { ++I; diff --git a/llvm/test/Transforms/Inline/pr53206.ll b/llvm/test/Transforms/Inline/pr53206.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/Inline/pr53206.ll @@ -0,0 +1,51 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt -S -inline < %s | FileCheck %s + +; Check that the exception handling code is fully pruned, and does not +; leave behind invalid IR. + +define internal void @foo() personality i32 (...)* undef { +entry: + br i1 false, label %join, label %split + +split: + br label %join + +join: + %phi = phi i64 [ 1, %split ], [ 0, %entry ] + %cmp = icmp ugt i64 1, %phi + br i1 %cmp, label %invoke1, label %exit + +invoke1: + invoke void undef() + to label %exit unwind label %cleanup1 + +cleanup1: + %pad1 = cleanuppad within none [] + br label %cleanup1.cont + +cleanup1.cont: + br i1 undef, label %cleanupret, label %invoke2 + +invoke2: + invoke void undef() [ "funclet"(token %pad1) ] + to label %cleanup1.cont unwind label %cleanup2 + +cleanup2: + %pad2 = cleanuppad within %pad1 [] + unreachable + +cleanupret: + unreachable + +exit: + ret void +} + +define void @test() personality i32 (...)* undef { +; CHECK-LABEL: @test( +; CHECK-NEXT: ret void +; + call void @foo() + ret void +}