diff --git a/llvm/include/llvm/IR/BasicBlock.h b/llvm/include/llvm/IR/BasicBlock.h --- a/llvm/include/llvm/IR/BasicBlock.h +++ b/llvm/include/llvm/IR/BasicBlock.h @@ -449,6 +449,15 @@ return getBasicBlockBits().BlockAddressRefCount != 0; } + /// Returns true if there are any uses of this basic block other than + /// direct branches, switches, etc. to it. Note that this will first try to + /// drop zombie BlockAddress'es that aren't used by anything. + bool hasAddressTakenAndUsed(); + + /// Dpes this block has it's address taken, and there are not other uses of + /// the block, and the block consists of a single "unreachable" instruction? + bool isZombieAddressTakenBlock(); + /// Update all phi nodes in this basic block to refer to basic block \p New /// instead of basic block \p Old. void replacePhiUsesWith(BasicBlock *Old, BasicBlock *New); diff --git a/llvm/lib/IR/BasicBlock.cpp b/llvm/lib/IR/BasicBlock.cpp --- a/llvm/lib/IR/BasicBlock.cpp +++ b/llvm/lib/IR/BasicBlock.cpp @@ -443,6 +443,29 @@ return New; } +bool BasicBlock::hasAddressTakenAndUsed() { + if (!const_cast(this)->hasAddressTaken()) + return false; + + if (getParent()) { + // If the block has its address taken, it may be a tree of dead constants + // hanging off of it. These shouldn't keep the block alive. + BlockAddress *BA = BlockAddress::get(this); + BA->removeDeadConstantUsers(); + return !BA->use_empty(); + } + + return any_of(users(), [](const User *U) { return isa(U); }); +} + +bool BasicBlock::isZombieAddressTakenBlock() { + if (!hasAddressTakenAndUsed()) + return false; + + return sizeWithoutDebug() == 1 && hasOneUse() && + isa(getTerminator()); +} + void BasicBlock::replacePhiUsesWith(BasicBlock *Old, BasicBlock *New) { // N.B. This might not be a complete BasicBlock, so don't assume // that it ends with a non-phi instruction. diff --git a/llvm/lib/Transforms/Scalar/JumpThreading.cpp b/llvm/lib/Transforms/Scalar/JumpThreading.cpp --- a/llvm/lib/Transforms/Scalar/JumpThreading.cpp +++ b/llvm/lib/Transforms/Scalar/JumpThreading.cpp @@ -443,7 +443,7 @@ if (&BB == &F.getEntryBlock() || DTU->isBBPendingDeletion(&BB)) continue; - if (pred_empty(&BB)) { + if (pred_empty(&BB) && !BB.isZombieAddressTakenBlock()) { // When processBlock makes BB unreachable it doesn't bother to fix up // the instructions in it. We must remove BB to prevent invalid IR. LLVM_DEBUG(dbgs() << " JT: Deleting dead block '" << BB.getName() @@ -1016,16 +1016,6 @@ return MinSucc; } -static bool hasAddressTakenAndUsed(BasicBlock *BB) { - if (!BB->hasAddressTaken()) return false; - - // If the block has its address taken, it may be a tree of dead constants - // hanging off of it. These shouldn't keep the block alive. - BlockAddress *BA = BlockAddress::get(BB); - BA->removeDeadConstantUsers(); - return !BA->use_empty(); -} - /// processBlock - If there are any predecessors whose control can be threaded /// through to a successor, transform them now. bool JumpThreadingPass::processBlock(BasicBlock *BB) { @@ -1981,7 +1971,7 @@ const Instruction *TI = SinglePred->getTerminator(); if (TI->isExceptionalTerminator() || TI->getNumSuccessors() != 1 || - SinglePred == BB || hasAddressTakenAndUsed(BB)) + SinglePred == BB || BB->hasAddressTakenAndUsed()) return false; // If SinglePred was a loop header, BB becomes one. diff --git a/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp b/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp --- a/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp +++ b/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp @@ -108,11 +108,15 @@ if (DTU) DTU->applyUpdates(Updates); - for (BasicBlock *BB : BBs) + for (BasicBlock *BB : BBs) { + // We can't *actually* delete blocks that have their address taken... + if (BB->isZombieAddressTakenBlock()) + continue; if (DTU) DTU->deleteBB(BB); else BB->eraseFromParent(); + } } bool llvm::EliminateUnreachableBlocks(Function &F, DomTreeUpdater *DTU, diff --git a/llvm/lib/Transforms/Utils/Local.cpp b/llvm/lib/Transforms/Utils/Local.cpp --- a/llvm/lib/Transforms/Utils/Local.cpp +++ b/llvm/lib/Transforms/Utils/Local.cpp @@ -2415,6 +2415,8 @@ // Skip already-deleted blocks if (DTU && DTU->isBBPendingDeletion(&BB)) continue; + if (BB.isZombieAddressTakenBlock()) + continue; BlocksToRemove.insert(&BB); } diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp --- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp +++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp @@ -4831,7 +4831,8 @@ DTU->applyUpdates(Updates); // If this block is now dead, remove it. - if (pred_empty(BB) && BB != &BB->getParent()->getEntryBlock()) { + if (pred_empty(BB) && BB != &BB->getParent()->getEntryBlock() && + !BB->isZombieAddressTakenBlock()) { DeleteDeadBlock(BB, DTU); return true; } @@ -6713,7 +6714,8 @@ // Remove basic blocks that have no predecessors (except the entry block)... // or that just have themself as a predecessor. These are unreachable. - if ((pred_empty(BB) && BB != &BB->getParent()->getEntryBlock()) || + if ((pred_empty(BB) && BB != &BB->getParent()->getEntryBlock() && + !BB->isZombieAddressTakenBlock()) || BB->getSinglePredecessor() == BB) { LLVM_DEBUG(dbgs() << "Removing BB: \n" << *BB); DeleteDeadBlock(BB, DTU); diff --git a/llvm/test/CodeGen/RISCV/codemodel-lowering.ll b/llvm/test/CodeGen/RISCV/codemodel-lowering.ll --- a/llvm/test/CodeGen/RISCV/codemodel-lowering.ll +++ b/llvm/test/CodeGen/RISCV/codemodel-lowering.ll @@ -33,18 +33,23 @@ ; RV32I-SMALL-LABEL: lower_blockaddress: ; RV32I-SMALL: # %bb.0: ; RV32I-SMALL-NEXT: lui a0, %hi(addr) -; RV32I-SMALL-NEXT: addi a1, zero, 1 +; RV32I-SMALL-NEXT: lui a1, %hi(.Ltmp0) +; RV32I-SMALL-NEXT: addi a1, a1, %lo(.Ltmp0) ; RV32I-SMALL-NEXT: sw a1, %lo(addr)(a0) ; RV32I-SMALL-NEXT: ret +; RV32I-SMALL-NEXT: .Ltmp0: # Address of block that was removed by CodeGen ; ; RV32I-MEDIUM-LABEL: lower_blockaddress: ; RV32I-MEDIUM: # %bb.0: ; RV32I-MEDIUM-NEXT: .LBB1_1: # Label of block must be emitted ; RV32I-MEDIUM-NEXT: auipc a0, %pcrel_hi(addr) ; RV32I-MEDIUM-NEXT: addi a0, a0, %pcrel_lo(.LBB1_1) -; RV32I-MEDIUM-NEXT: addi a1, zero, 1 +; RV32I-MEDIUM-NEXT: .LBB1_2: # Label of block must be emitted +; RV32I-MEDIUM-NEXT: auipc a1, %pcrel_hi(.Ltmp0) +; RV32I-MEDIUM-NEXT: addi a1, a1, %pcrel_lo(.LBB1_2) ; RV32I-MEDIUM-NEXT: sw a1, 0(a0) ; RV32I-MEDIUM-NEXT: ret +; RV32I-MEDIUM-NEXT: .Ltmp0: # Address of block that was removed by CodeGen store volatile i8* blockaddress(@lower_blockaddress, %block), i8** @addr ret void @@ -58,15 +63,15 @@ ; RV32I-SMALL-LABEL: lower_blockaddress_displ: ; RV32I-SMALL: # %bb.0: # %entry ; RV32I-SMALL-NEXT: addi sp, sp, -16 -; RV32I-SMALL-NEXT: lui a1, %hi(.Ltmp0) -; RV32I-SMALL-NEXT: addi a1, a1, %lo(.Ltmp0) +; RV32I-SMALL-NEXT: lui a1, %hi(.Ltmp1) +; RV32I-SMALL-NEXT: addi a1, a1, %lo(.Ltmp1) ; RV32I-SMALL-NEXT: addi a2, zero, 101 ; RV32I-SMALL-NEXT: sw a1, 8(sp) ; RV32I-SMALL-NEXT: blt a0, a2, .LBB2_3 ; RV32I-SMALL-NEXT: # %bb.1: # %if.then ; RV32I-SMALL-NEXT: lw a0, 8(sp) ; RV32I-SMALL-NEXT: jr a0 -; RV32I-SMALL-NEXT: .Ltmp0: # Block address taken +; RV32I-SMALL-NEXT: .Ltmp1: # Block address taken ; RV32I-SMALL-NEXT: .LBB2_2: # %return ; RV32I-SMALL-NEXT: addi a0, zero, 4 ; RV32I-SMALL-NEXT: addi sp, sp, 16 @@ -81,7 +86,7 @@ ; RV32I-MEDIUM-NEXT: addi sp, sp, -16 ; RV32I-MEDIUM-NEXT: .LBB2_4: # %entry ; RV32I-MEDIUM-NEXT: # Label of block must be emitted -; RV32I-MEDIUM-NEXT: auipc a1, %pcrel_hi(.Ltmp0) +; RV32I-MEDIUM-NEXT: auipc a1, %pcrel_hi(.Ltmp1) ; RV32I-MEDIUM-NEXT: addi a1, a1, %pcrel_lo(.LBB2_4) ; RV32I-MEDIUM-NEXT: addi a2, zero, 101 ; RV32I-MEDIUM-NEXT: sw a1, 8(sp) @@ -89,7 +94,7 @@ ; RV32I-MEDIUM-NEXT: # %bb.1: # %if.then ; RV32I-MEDIUM-NEXT: lw a0, 8(sp) ; RV32I-MEDIUM-NEXT: jr a0 -; RV32I-MEDIUM-NEXT: .Ltmp0: # Block address taken +; RV32I-MEDIUM-NEXT: .Ltmp1: # Block address taken ; RV32I-MEDIUM-NEXT: .LBB2_2: # %return ; RV32I-MEDIUM-NEXT: addi a0, zero, 4 ; RV32I-MEDIUM-NEXT: addi sp, sp, 16