[Attributor] Liveness for internal functions.

For an internal function, if all its call sites are dead, the body of the function is considered dead.

Reviewers: jdoerfert, uenoku

Subscribers: hiraditya, llvm-commits

Differential Revision: https://reviews.llvm.org/D66155

llvm-svn: 369470
diff --git a/llvm/lib/Transforms/IPO/Attributor.cpp b/llvm/lib/Transforms/IPO/Attributor.cpp
index bbd14d7..16894d8 100644
--- a/llvm/lib/Transforms/IPO/Attributor.cpp
+++ b/llvm/lib/Transforms/IPO/Attributor.cpp
@@ -1570,13 +1570,22 @@
 
   void initialize(Attributor &A) override {
     const Function *F = getAssociatedFunction();
+
+    if (F->hasInternalLinkage())
+      return;
+
     if (!F || !F->hasExactDefinition()) {
       indicatePessimisticFixpoint();
       return;
     }
 
+    exploreFromEntry(A, F);
+  }
+
+  void exploreFromEntry(Attributor &A, const Function *F) {
     ToBeExploredPaths.insert(&(F->getEntryBlock().front()));
     AssumedLiveBlocks.insert(&(F->getEntryBlock()));
+
     for (size_t i = 0; i < ToBeExploredPaths.size(); ++i)
       if (const Instruction *NextNoReturnI =
               findNextNoReturn(A, ToBeExploredPaths[i]))
@@ -1606,7 +1615,12 @@
            "Attempted to manifest an invalid state!");
 
     ChangeStatus HasChanged = ChangeStatus::UNCHANGED;
-    const Function &F = *getAssociatedFunction();
+    Function &F = *getAssociatedFunction();
+
+    if (AssumedLiveBlocks.empty()) {
+      F.replaceAllUsesWith(UndefValue::get(F.getType()));
+      return ChangeStatus::CHANGED;
+    }
 
     // Flag to determine if we can change an invoke to a call assuming the
     // callee is nounwind. This is not possible if the personality of the
@@ -1725,6 +1739,13 @@
 
   /// See AbstractAttribute::trackStatistics()
   void trackStatistics() const override {
+    STATS_DECL(DeadInternalFunction, Function,
+               "Number of internal functions classified as dead (no live callsite)");
+    BUILD_STAT_NAME(DeadInternalFunction, Function) +=
+        (getAssociatedFunction()->hasInternalLinkage() &&
+         AssumedLiveBlocks.empty())
+            ? 1
+            : 0;
     STATS_DECL(DeadBlocks, Function,
                "Number of basic blocks classified as dead");
     BUILD_STAT_NAME(DeadBlocks, Function) +=
@@ -1796,10 +1817,25 @@
 }
 
 ChangeStatus AAIsDeadImpl::updateImpl(Attributor &A) {
+  const Function *F = getAssociatedFunction();
+  ChangeStatus Status = ChangeStatus::UNCHANGED;
+
+  if (F->hasInternalLinkage() && AssumedLiveBlocks.empty()) {
+    auto CallSiteCheck = [&](CallSite) { return false; };
+
+    // All callsites of F are dead.
+    if (A.checkForAllCallSites(CallSiteCheck, *this, true))
+      return ChangeStatus::UNCHANGED;
+
+    // There exists at least one live call site, so we explore the function.
+    Status = ChangeStatus::CHANGED;
+
+    exploreFromEntry(A, F);
+  }
+
   // Temporary collection to iterate over existing noreturn instructions. This
   // will alow easier modification of NoReturnCalls collection
   SmallVector<const Instruction *, 8> NoReturnChanged;
-  ChangeStatus Status = ChangeStatus::UNCHANGED;
 
   for (const Instruction *I : NoReturnCalls)
     NoReturnChanged.push_back(I);
@@ -2249,6 +2285,11 @@
   if (!LivenessAA)
     LivenessAA =
         &getAAFor<AAIsDead>(AA, IRPosition::function(*CtxI->getFunction()));
+
+  // Don't check liveness for AAIsDead.
+  if (&AA == LivenessAA)
+    return false;
+
   if (!LivenessAA->isAssumedDead(CtxI))
     return false;