diff --git a/llvm/include/llvm/IR/Constant.h b/llvm/include/llvm/IR/Constant.h --- a/llvm/include/llvm/IR/Constant.h +++ b/llvm/include/llvm/IR/Constant.h @@ -204,6 +204,12 @@ /// Constant::removeDeadConstantUsers, but doesn't remove dead constants. bool hasOneLiveUse() const; + /// Return true if the constant has no live uses. + /// + /// This returns the same result as calling Value::use_empty after + /// Constant::removeDeadConstantUsers, but doesn't remove dead constants. + bool hasZeroLiveUses() const; + const Constant *stripPointerCasts() const { return cast(Value::stripPointerCasts()); } @@ -244,6 +250,8 @@ /// Determine what potential relocations may be needed by this constant. PossibleRelocationsTy getRelocationInfo() const; + + bool hasNLiveUses(unsigned N) const; }; } // end namespace llvm diff --git a/llvm/lib/Analysis/LazyCallGraph.cpp b/llvm/lib/Analysis/LazyCallGraph.cpp --- a/llvm/lib/Analysis/LazyCallGraph.cpp +++ b/llvm/lib/Analysis/LazyCallGraph.cpp @@ -1503,7 +1503,7 @@ void LazyCallGraph::removeDeadFunction(Function &F) { // FIXME: This is unnecessarily restrictive. We should be able to remove // functions which recursively call themselves. - assert(F.use_empty() && + assert(F.hasZeroLiveUses() && "This routine should only be called on trivially dead functions!"); // We shouldn't remove library functions as they are never really dead while diff --git a/llvm/lib/IR/Constants.cpp b/llvm/lib/IR/Constants.cpp --- a/llvm/lib/IR/Constants.cpp +++ b/llvm/lib/IR/Constants.cpp @@ -779,18 +779,22 @@ } } -bool Constant::hasOneLiveUse() const { +bool Constant::hasOneLiveUse() const { return hasNLiveUses(1); } + +bool Constant::hasZeroLiveUses() const { return hasNLiveUses(0); } + +bool Constant::hasNLiveUses(unsigned N) const { unsigned NumUses = 0; - for (const Use &use : uses()) { - const Constant *User = dyn_cast(use.getUser()); + for (const Use &U : uses()) { + const Constant *User = dyn_cast(U.getUser()); if (!User || !constantIsDead(User, /* RemoveDeadUsers= */ false)) { ++NumUses; - if (NumUses > 1) + if (NumUses > N) return false; } } - return NumUses == 1; + return NumUses == N; } Constant *Constant::replaceUndefsWith(Constant *C, Constant *Replacement) { diff --git a/llvm/lib/Transforms/IPO/Inliner.cpp b/llvm/lib/Transforms/IPO/Inliner.cpp --- a/llvm/lib/Transforms/IPO/Inliner.cpp +++ b/llvm/lib/Transforms/IPO/Inliner.cpp @@ -940,24 +940,20 @@ // which may reduce the number of callers of other functions to one, // changing inline cost thresholds. bool CalleeWasDeleted = false; - if (Callee.hasLocalLinkage()) { - // To check this we also need to nuke any dead constant uses (perhaps - // made dead by this operation on other functions). - Callee.removeDeadConstantUsers(); - if (Callee.use_empty() && !CG.isLibFunction(Callee)) { - Calls->erase_if([&](const std::pair &Call) { - return Call.first->getCaller() == &Callee; - }); - // Clear the body and queue the function itself for deletion when we - // finish inlining and call graph updates. - // Note that after this point, it is an error to do anything other - // than use the callee's address or delete it. - Callee.dropAllReferences(); - assert(!is_contained(DeadFunctions, &Callee) && - "Cannot put cause a function to become dead twice!"); - DeadFunctions.push_back(&Callee); - CalleeWasDeleted = true; - } + if (Callee.hasLocalLinkage() && Callee.hasZeroLiveUses() && + !CG.isLibFunction(Callee)) { + Calls->erase_if([&](const std::pair &Call) { + return Call.first->getCaller() == &Callee; + }); + // Clear the body and queue the function itself for deletion when we + // finish inlining and call graph updates. + // Note that after this point, it is an error to do anything other + // than use the callee's address or delete it. + Callee.dropAllReferences(); + assert(!is_contained(DeadFunctions, &Callee) && + "Cannot put cause a function to become dead twice!"); + DeadFunctions.push_back(&Callee); + CalleeWasDeleted = true; } if (CalleeWasDeleted) Advice->recordInliningWithCalleeDeleted();