diff --git a/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp b/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp index 91e245e5e8f54..cad0b4c12b54e 100644 --- a/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp +++ b/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp @@ -58,94 +58,37 @@ static cl::opt MaxDeoptOrUnreachableSuccessorCheckDepth( "is followed by a block that either has a terminating " "deoptimizing call or is terminated with an unreachable")); -/// Zap all the instructions in the block and replace them with an unreachable -/// instruction and notify the basic block's successors that one of their -/// predecessors is going away. -static void -emptyAndDetachBlock(BasicBlock *BB, - SmallVectorImpl *Updates, - bool KeepOneInputPHIs) { - // Loop through all of our successors and make sure they know that one - // of their predecessors is going away. - SmallPtrSet UniqueSuccessors; - for (BasicBlock *Succ : successors(BB)) { - Succ->removePredecessor(BB, KeepOneInputPHIs); - if (Updates && UniqueSuccessors.insert(Succ).second) - Updates->push_back({DominatorTree::Delete, BB, Succ}); - } - - // Zap all the instructions in the block. - while (!BB->empty()) { - Instruction &I = BB->back(); - // If this instruction is used, replace uses with an arbitrary value. - // Because control flow can't get here, we don't care what we replace the - // value with. Note that since this block is unreachable, and all values - // contained within it must dominate their uses, that all uses will - // eventually be removed (they are themselves dead). - if (!I.use_empty()) - I.replaceAllUsesWith(PoisonValue::get(I.getType())); - BB->back().eraseFromParent(); - } - new UnreachableInst(BB->getContext(), BB); - assert(BB->size() == 1 && isa(BB->getTerminator()) && - "The successor list of BB isn't empty before " - "applying corresponding DTU updates."); -} - -void llvm::detachDeadBlocks(ArrayRef BBs, - SmallVectorImpl *Updates, - bool KeepOneInputPHIs) { +void llvm::detachDeadBlocks( + ArrayRef BBs, + SmallVectorImpl *Updates, + bool KeepOneInputPHIs) { for (auto *BB : BBs) { - auto NonFirstPhiIt = BB->getFirstNonPHIIt(); - if (NonFirstPhiIt != BB->end()) { - Instruction &I = *NonFirstPhiIt; - // Exception handling funclets need to be explicitly addressed. - // These funclets must begin with cleanuppad or catchpad and end with - // cleanupred or catchret. The return instructions can be in different - // basic blocks than the pad instruction. If we would only delete the - // first block, the we would have possible cleanupret and catchret - // instructions with poison arguments, which wouldn't be valid. - if (isa(I)) { - for (User *User : make_early_inc_range(I.users())) { - Instruction *ReturnInstr = dyn_cast(User); - // If we have a cleanupret or catchret block, replace it with just an - // unreachable. The other alternative, that may use a catchpad is a - // catchswitch. That does not need special handling for now. - if (isa(ReturnInstr) || - isa(ReturnInstr)) { - BasicBlock *ReturnInstrBB = ReturnInstr->getParent(); - // This catchret or catchpad basic block is detached now. Let the - // successors know it. - // This basic block also may have some predecessors too. For - // example the following LLVM-IR is valid: - // - // [cleanuppad_block] - // | - // [regular_block] - // | - // [cleanupret_block] - // - // The IR after the cleanup will look like this: - // - // [cleanuppad_block] - // | - // [regular_block] - // | - // [unreachable] - // - // So regular_block will lead to an unreachable block, which is also - // valid. There is no need to replace regular_block with unreachable - // in this context now. - // On the other hand, the cleanupret/catchret block's successors - // need to know about the deletion of their predecessors. - emptyAndDetachBlock(ReturnInstrBB, Updates, KeepOneInputPHIs); - } - } - } + // Loop through all of our successors and make sure they know that one + // of their predecessors is going away. + SmallPtrSet UniqueSuccessors; + for (BasicBlock *Succ : successors(BB)) { + Succ->removePredecessor(BB, KeepOneInputPHIs); + if (Updates && UniqueSuccessors.insert(Succ).second) + Updates->push_back({DominatorTree::Delete, BB, Succ}); } - // Detaching and emptying the current basic block. - emptyAndDetachBlock(BB, Updates, KeepOneInputPHIs); + // Zap all the instructions in the block. + while (!BB->empty()) { + Instruction &I = BB->back(); + // If this instruction is used, replace uses with an arbitrary value. + // Because control flow can't get here, we don't care what we replace the + // value with. Note that since this block is unreachable, and all values + // contained within it must dominate their uses, that all uses will + // eventually be removed (they are themselves dead). + if (!I.use_empty()) + I.replaceAllUsesWith(PoisonValue::get(I.getType())); + BB->back().eraseFromParent(); + } + new UnreachableInst(BB->getContext(), BB); + assert(BB->size() == 1 && + isa(BB->getTerminator()) && + "The successor list of BB isn't empty before " + "applying corresponding DTU updates."); } } diff --git a/llvm/test/Transforms/SimplifyCFG/unreachable-multi-basic-block-funclet.ll b/llvm/test/Transforms/SimplifyCFG/unreachable-multi-basic-block-funclet.ll deleted file mode 100644 index 0f0fc78ec7add..0000000000000 --- a/llvm/test/Transforms/SimplifyCFG/unreachable-multi-basic-block-funclet.ll +++ /dev/null @@ -1,236 +0,0 @@ -; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 -; RUN: opt -passes=simplifycfg -S < %s | FileCheck %s - -; cleanuppad/cleanupret - -define void @unreachable_cleanuppad_linear(i64 %shapes.1) personality ptr null { -; CHECK-LABEL: define void @unreachable_cleanuppad_linear( -; CHECK-SAME: i64 [[SHAPES_1:%.*]]) personality ptr null { -; CHECK-NEXT: [[START:.*:]] -; CHECK-NEXT: [[_7:%.*]] = icmp ult i64 0, [[SHAPES_1]] -; CHECK-NEXT: ret void -; -start: - %_7 = icmp ult i64 0, %shapes.1 - ret void - -funclet: - %cleanuppad = cleanuppad within none [] - br label %funclet_end - -funclet_end: - cleanupret from %cleanuppad unwind to caller -} - -define void @unreachable_cleanuppad_linear_middle_block(i64 %shapes.1) personality ptr null { -; CHECK-LABEL: define void @unreachable_cleanuppad_linear_middle_block( -; CHECK-SAME: i64 [[SHAPES_1:%.*]]) personality ptr null { -; CHECK-NEXT: [[START:.*:]] -; CHECK-NEXT: [[_7:%.*]] = icmp ult i64 0, [[SHAPES_1]] -; CHECK-NEXT: ret void -; -start: - %_7 = icmp ult i64 0, %shapes.1 - ret void - -funclet: - %cleanuppad = cleanuppad within none [] - br label %middle_block - -middle_block: - %tmp1 = add i64 %shapes.1, 42 - br label %funclet_end - -funclet_end: - cleanupret from %cleanuppad unwind to caller -} - -define void @unreachable_cleanuppad_multiple_predecessors(i64 %shapes.1) personality ptr null { -; CHECK-LABEL: define void @unreachable_cleanuppad_multiple_predecessors( -; CHECK-SAME: i64 [[SHAPES_1:%.*]]) personality ptr null { -; CHECK-NEXT: [[START:.*:]] -; CHECK-NEXT: [[_7:%.*]] = icmp ult i64 0, [[SHAPES_1]] -; CHECK-NEXT: ret void -; -start: - %_7 = icmp ult i64 0, %shapes.1 - ret void - -funclet: - %cleanuppad = cleanuppad within none [] - switch i64 %shapes.1, label %otherwise [ i64 0, label %one - i64 1, label %two - i64 42, label %three ] -one: - br label %funclet_end - -two: - br label %funclet_end - -three: - br label %funclet_end - -otherwise: - br label %funclet_end - -funclet_end: - cleanupret from %cleanuppad unwind to caller -} - -; catchpad/catchret - -define void @unreachable_catchpad_linear(i64 %shapes.1) personality ptr null { -; CHECK-LABEL: define void @unreachable_catchpad_linear( -; CHECK-SAME: i64 [[SHAPES_1:%.*]]) personality ptr null { -; CHECK-NEXT: [[START:.*:]] -; CHECK-NEXT: [[_7:%.*]] = icmp ult i64 0, [[SHAPES_1]] -; CHECK-NEXT: ret void -; -start: - %_7 = icmp ult i64 0, %shapes.1 - ret void - -dispatch: - %cs = catchswitch within none [label %funclet] unwind to caller - -funclet: - %cleanuppad = catchpad within %cs [] - br label %funclet_end - - -funclet_end: - catchret from %cleanuppad to label %unreachable - -unreachable: - unreachable -} - -define void @unreachable_catchpad_multiple_predecessors(i64 %shapes.1) personality ptr null { -; CHECK-LABEL: define void @unreachable_catchpad_multiple_predecessors( -; CHECK-SAME: i64 [[SHAPES_1:%.*]]) personality ptr null { -; CHECK-NEXT: [[START:.*:]] -; CHECK-NEXT: [[_7:%.*]] = icmp ult i64 0, [[SHAPES_1]] -; CHECK-NEXT: ret void -; -start: - %_7 = icmp ult i64 0, %shapes.1 - ret void - -dispatch: - %cs = catchswitch within none [label %funclet] unwind to caller - -funclet: - %cleanuppad = catchpad within %cs [] - switch i64 %shapes.1, label %otherwise [ i64 0, label %one - i64 1, label %two - i64 42, label %three ] -one: - br label %funclet_end - -two: - br label %funclet_end - -three: - br label %funclet_end - -otherwise: - br label %funclet_end - -funclet_end: - catchret from %cleanuppad to label %unreachable - -unreachable: - unreachable -} - -; Issue reproducer - -define void @gh148052(i64 %shapes.1) personality ptr null { -; CHECK-LABEL: define void @gh148052( -; CHECK-SAME: i64 [[SHAPES_1:%.*]]) personality ptr null { -; CHECK-NEXT: [[START:.*:]] -; CHECK-NEXT: [[_7:%.*]] = icmp ult i64 0, [[SHAPES_1]] -; CHECK-NEXT: call void @llvm.assume(i1 [[_7]]) -; CHECK-NEXT: ret void -; -start: - %_7 = icmp ult i64 0, %shapes.1 - br i1 %_7, label %bb1, label %panic - -bb1: - %_11 = icmp ult i64 0, %shapes.1 - br i1 %_11, label %bb3, label %panic1 - -panic: - unreachable - -bb3: - ret void - -panic1: - invoke void @func(i64 0, i64 0, ptr null) - to label %unreachable unwind label %funclet_bb14 - -funclet_bb14: - %cleanuppad = cleanuppad within none [] - br label %bb13 - -unreachable: - unreachable - -bb10: - cleanupret from %cleanuppad5 unwind to caller - -funclet_bb10: - %cleanuppad5 = cleanuppad within none [] - br label %bb10 - -bb13: - cleanupret from %cleanuppad unwind label %funclet_bb10 -} - -%struct.foo = type { ptr, %struct.eggs, ptr } -%struct.eggs = type { ptr, ptr, ptr } - -declare x86_thiscallcc ptr @quux(ptr, ptr, i32) - -define x86_thiscallcc ptr @baz(ptr %arg, ptr %arg1, ptr %arg2, i1 %arg3, ptr %arg4) personality ptr null { -; CHECK-LABEL: define x86_thiscallcc ptr @baz( -; CHECK-SAME: ptr [[ARG:%.*]], ptr [[ARG1:%.*]], ptr [[ARG2:%.*]], i1 [[ARG3:%.*]], ptr [[ARG4:%.*]]) personality ptr null { -; CHECK-NEXT: [[BB:.*:]] -; CHECK-NEXT: [[ALLOCA:%.*]] = alloca [2 x %struct.foo], align 4 -; CHECK-NEXT: [[INVOKE:%.*]] = call x86_thiscallcc ptr @quux(ptr null, ptr null, i32 0) #[[ATTR1:[0-9]+]] -; CHECK-NEXT: unreachable -; -bb: - %alloca = alloca [2 x %struct.foo], align 4 - %invoke = invoke x86_thiscallcc ptr @quux(ptr null, ptr null, i32 0) - to label %bb5 unwind label %bb10 - -bb5: ; preds = %bb - %getelementptr = getelementptr i8, ptr %arg, i32 20 - %call = call x86_thiscallcc ptr null(ptr null, ptr null, i32 0) - br label %bb6 - -bb6: ; preds = %bb10, %bb5 - %phi = phi ptr [ null, %bb10 ], [ null, %bb5 ] - ret ptr %phi - -bb7: ; No predecessors! - %cleanuppad = cleanuppad within none [] - %getelementptr8 = getelementptr i8, ptr %arg2, i32 -20 - %icmp = icmp eq ptr %arg, null - br label %bb9 - -bb9: ; preds = %bb7 - cleanupret from %cleanuppad unwind label %bb10 - -bb10: ; preds = %bb9, %bb - %phi11 = phi ptr [ %arg, %bb9 ], [ null, %bb ] - %cleanuppad12 = cleanuppad within none [] - %getelementptr13 = getelementptr i8, ptr %phi11, i32 -20 - store i32 0, ptr %phi11, align 4 - br label %bb6 -} - -declare void @func(i64, i64, ptr)