Index: include/llvm/IR/BasicBlock.h =================================================================== --- include/llvm/IR/BasicBlock.h +++ include/llvm/IR/BasicBlock.h @@ -386,6 +386,10 @@ /// direct branches, switches, etc. to it. bool hasAddressTaken() const { return getSubclassDataFromValue() != 0; } + /// Return true if the basic block address is taken and used in a meaningful + /// way, i.e. non-dead way. + bool hasAddressTakenAndUsed(); + /// Update all phi nodes in this basic block's successors to refer to basic /// block \p New instead of to it. void replaceSuccessorsPhiUsesWith(BasicBlock *New); Index: lib/Analysis/InlineCost.cpp =================================================================== --- lib/Analysis/InlineCost.cpp +++ lib/Analysis/InlineCost.cpp @@ -1808,7 +1808,7 @@ // see an indirect branch that ends up being dead code at a particular call // site. If the blockaddress escapes the function, e.g., via a global // variable, inlining may lead to an invalid cross-function reference. - if (BB->hasAddressTaken()) + if (BB->hasAddressTakenAndUsed()) return false; // Analyze the cost of this block. If we blow through the threshold, this Index: lib/IR/BasicBlock.cpp =================================================================== --- lib/IR/BasicBlock.cpp +++ lib/IR/BasicBlock.cpp @@ -436,6 +436,17 @@ return New; } +bool BasicBlock::hasAddressTakenAndUsed() { + if (!hasAddressTaken()) + return false; + + // If the block has its address taken, but not used in a meaningful way. + // then this shouldn't keep the block alive or prevent function inlining, etc. + BlockAddress *BA = BlockAddress::get(this); + BA->removeDeadConstantUsers(); + return !BA->use_empty(); +} + void BasicBlock::replaceSuccessorsPhiUsesWith(BasicBlock *New) { TerminatorInst *TI = getTerminator(); if (!TI) Index: lib/Transforms/Scalar/JumpThreading.cpp =================================================================== --- lib/Transforms/Scalar/JumpThreading.cpp +++ lib/Transforms/Scalar/JumpThreading.cpp @@ -960,16 +960,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) { @@ -986,7 +976,7 @@ if (BasicBlock *SinglePred = BB->getSinglePredecessor()) { const TerminatorInst *TI = SinglePred->getTerminator(); if (!TI->isExceptional() && TI->getNumSuccessors() == 1 && - SinglePred != BB && !hasAddressTakenAndUsed(BB)) { + SinglePred != BB && !BB->hasAddressTakenAndUsed()) { // If SinglePred was a loop header, BB becomes one. if (LoopHeaders.erase(SinglePred)) LoopHeaders.insert(BB); Index: test/Transforms/Inline/blockaddress.ll =================================================================== --- test/Transforms/Inline/blockaddress.ll +++ test/Transforms/Inline/blockaddress.ll @@ -1,5 +1,7 @@ ; RUN: opt -inline -S < %s | FileCheck %s +; RUN: opt -dce -inline -S < %s | FileCheck %s --check-prefixes=CHECK-DCE-INLINE ; RUN: opt -passes='cgscc(inline)' -S < %s | FileCheck %s +; RUN: opt -passes='function(dce),cgscc(inline)' -S < %s | FileCheck %s --check-prefixes=CHECK-DCE-INLINE ; PR10162 ; Make sure doit is not inlined since the blockaddress is taken @@ -49,3 +51,23 @@ } @run.bb = global [1 x i8*] zeroinitializer + +define i32 @g() { +entry: + %dead = extractvalue [1 x i8*] [ i8* blockaddress(@g, %L0) ], 0 + br label %L0 +L0: + ret i32 0 +} + +; Make sure we can inline @g into @run_g as once %dead in @g is deleted +; the blockaddress on %L0 in @g becomes dead. +; +; CHECK-DCE-INLINE-LABEL: define void @run_g( +; CHECK-DCE-INLINE-NOT: call +; CHECK-DCE-INLINE: ret void +define void @run_g() { +entry: + call i32 @g() + ret void +}