[llvm] r336419 - CallGraphSCCPass: iterate over all functions.

Tim Northover via llvm-commits llvm-commits at lists.llvm.org
Fri Jul 6 01:04:47 PDT 2018


Author: tnorthover
Date: Fri Jul  6 01:04:47 2018
New Revision: 336419

URL: http://llvm.org/viewvc/llvm-project?rev=336419&view=rev
Log:
CallGraphSCCPass: iterate over all functions.

Previously we only iterated over functions reachable from the set of
external functions in the module. But since some of the passes under
this (notably the always-inliner and coroutine lowerer) are required for
correctness, they need to run over everything.

This just adds an extra layer of iteration over the CallGraph to keep
track of which functions we've already visited and get the next batch of
SCCs.

Should fix PR38029.

Modified:
    llvm/trunk/include/llvm/ADT/SCCIterator.h
    llvm/trunk/lib/Analysis/CallGraphSCCPass.cpp
    llvm/trunk/test/Transforms/Inline/always-inline.ll

Modified: llvm/trunk/include/llvm/ADT/SCCIterator.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ADT/SCCIterator.h?rev=336419&r1=336418&r2=336419&view=diff
==============================================================================
--- llvm/trunk/include/llvm/ADT/SCCIterator.h (original)
+++ llvm/trunk/include/llvm/ADT/SCCIterator.h Fri Jul  6 01:04:47 2018
@@ -90,6 +90,7 @@ class scc_iterator : public iterator_fac
   /// Compute the next SCC using the DFS traversal.
   void GetNextSCC();
 
+public:
   scc_iterator(NodeRef entryN) : visitNum(0) {
     DFSVisitOne(entryN);
     GetNextSCC();
@@ -98,12 +99,6 @@ class scc_iterator : public iterator_fac
   /// End is when the DFS stack is empty.
   scc_iterator() = default;
 
-public:
-  static scc_iterator begin(const GraphT &G) {
-    return scc_iterator(GT::getEntryNode(G));
-  }
-  static scc_iterator end(const GraphT &) { return scc_iterator(); }
-
   /// Direct loop termination test which is more efficient than
   /// comparison with \c end().
   bool isAtEnd() const {
@@ -222,16 +217,25 @@ bool scc_iterator<GraphT, GT>::hasLoop()
     return false;
   }
 
-/// Construct the begin iterator for a deduced graph type T.
+/// Construct the begin iterator for a deduced graph type T, starting from its
+/// entry node.
 template <class T> scc_iterator<T> scc_begin(const T &G) {
-  return scc_iterator<T>::begin(G);
+  return scc_iterator<T>(GraphTraits<T>::getEntryNode(G));
 }
 
-/// Construct the end iterator for a deduced graph type T.
+/// Construct the begin iterator for a graph type T, starting from the specified
+/// node.
+template <class T, class U = GraphTraits<T>>
+scc_iterator<T, U> scc_begin(typename U::NodeRef N) {
+  return scc_iterator<T>(N);
+}
+
+  /// Construct the end iterator for a deduced graph type T.
 template <class T> scc_iterator<T> scc_end(const T &G) {
-  return scc_iterator<T>::end(G);
+  return scc_iterator<T>();
 }
 
+
 } // end namespace llvm
 
 #endif // LLVM_ADT_SCCITERATOR_H

Modified: llvm/trunk/lib/Analysis/CallGraphSCCPass.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/CallGraphSCCPass.cpp?rev=336419&r1=336418&r2=336419&view=diff
==============================================================================
--- llvm/trunk/lib/Analysis/CallGraphSCCPass.cpp (original)
+++ llvm/trunk/lib/Analysis/CallGraphSCCPass.cpp Fri Jul  6 01:04:47 2018
@@ -17,6 +17,7 @@
 
 #include "llvm/Analysis/CallGraphSCCPass.h"
 #include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseSet.h"
 #include "llvm/ADT/SCCIterator.h"
 #include "llvm/ADT/Statistic.h"
 #include "llvm/Analysis/CallGraph.h"
@@ -63,6 +64,10 @@ public:
   /// whether any of the passes modifies the module, and if so, return true.
   bool runOnModule(Module &M) override;
 
+  /// Execute all of the passes scheduled for execution on a given SCC. Return
+  /// true if any passes modify the module.
+  bool runOnSCC(CallGraphSCC &SCC, CallGraph &CG);
+
   using ModulePass::doInitialization;
   using ModulePass::doFinalization;
 
@@ -448,51 +453,78 @@ bool CGPassManager::RunAllPassesOnSCC(Ca
 bool CGPassManager::runOnModule(Module &M) {
   CallGraph &CG = getAnalysis<CallGraphWrapperPass>().getCallGraph();
   bool Changed = doInitialization(CG);
-  
-  // Walk the callgraph in bottom-up SCC order.
-  scc_iterator<CallGraph*> CGI = scc_begin(&CG);
 
-  CallGraphSCC CurSCC(CG, &CGI);
-  while (!CGI.isAtEnd()) {
-    // Copy the current SCC and increment past it so that the pass can hack
-    // on the SCC if it wants to without invalidating our iterator.
-    const std::vector<CallGraphNode *> &NodeVec = *CGI;
-    CurSCC.initialize(NodeVec);
-    ++CGI;
-
-    // At the top level, we run all the passes in this pass manager on the
-    // functions in this SCC.  However, we support iterative compilation in the
-    // case where a function pass devirtualizes a call to a function.  For
-    // example, it is very common for a function pass (often GVN or instcombine)
-    // to eliminate the addressing that feeds into a call.  With that improved
-    // information, we would like the call to be an inline candidate, infer
-    // mod-ref information etc.
-    //
-    // Because of this, we allow iteration up to a specified iteration count.
-    // This only happens in the case of a devirtualized call, so we only burn
-    // compile time in the case that we're making progress.  We also have a hard
-    // iteration count limit in case there is crazy code.
-    unsigned Iteration = 0;
-    bool DevirtualizedCall = false;
-    do {
-      LLVM_DEBUG(if (Iteration) dbgs()
-                 << "  SCCPASSMGR: Re-visiting SCC, iteration #" << Iteration
-                 << '\n');
-      DevirtualizedCall = false;
-      Changed |= RunAllPassesOnSCC(CurSCC, CG, DevirtualizedCall);
-    } while (Iteration++ < MaxIterations && DevirtualizedCall);
-    
-    if (DevirtualizedCall)
-      LLVM_DEBUG(dbgs() << "  CGSCCPASSMGR: Stopped iteration after "
-                        << Iteration
-                        << " times, due to -max-cg-scc-iterations\n");
+  DenseSet<const Function *> Visited;
 
-    MaxSCCIterations.updateMax(Iteration);
+  CallGraph::iterator INext;
+  for (auto I = CG.begin(), E = CG.end(); I != E;) {
+    // Walk the callgraph in bottom-up SCC order.
+    auto CGI = scc_begin<CallGraph *>(I->second.get());
+
+    CallGraphSCC CurSCC(CG, &CGI);
+    while (!CGI.isAtEnd()) {
+      const std::vector<CallGraphNode *> &NodeVec = *CGI;
+
+      // Record that we've seen this set of functions so we don't run the pass
+      // twice.
+      for (auto *Elt : NodeVec)
+        Visited.insert(Elt->getFunction());
+
+      // Copy the current SCC and increment past it so that the pass can hack
+      // on the SCC if it wants to without invalidating our iterator.
+      CurSCC.initialize(NodeVec);
+      ++CGI;
+
+      // If we've got all functions reachable from our chosen initial node,
+      // calculate the next node we need to search from now before parts of the
+      // graph are invalidated.
+      if (CGI.isAtEnd()) {
+        do
+          ++I;
+        while (I != E && Visited.count(I->first));
+      }
+
+      Changed |= runOnSCC(CurSCC, CG);
+    }
   }
+
   Changed |= doFinalization(CG);
   return Changed;
 }
 
+bool CGPassManager::runOnSCC(CallGraphSCC &CurSCC, CallGraph &CG) {
+  bool Changed = false;
+
+  // At the top level, we run all the passes in this pass manager on the
+  // functions in this SCC.  However, we support iterative compilation in the
+  // case where a function pass devirtualizes a call to a function.  For
+  // example, it is very common for a function pass (often GVN or instcombine)
+  // to eliminate the addressing that feeds into a call.  With that improved
+  // information, we would like the call to be an inline candidate, infer
+  // mod-ref information etc.
+  //
+  // Because of this, we allow iteration up to a specified iteration count.
+  // This only happens in the case of a devirtualized call, so we only burn
+  // compile time in the case that we're making progress.  We also have a hard
+  // iteration count limit in case there is crazy code.
+  unsigned Iteration = 0;
+  bool DevirtualizedCall = false;
+  do {
+    LLVM_DEBUG(if (Iteration) dbgs()
+               << "  SCCPASSMGR: Re-visiting SCC, iteration #" << Iteration
+               << '\n');
+    DevirtualizedCall = false;
+    Changed |= RunAllPassesOnSCC(CurSCC, CG, DevirtualizedCall);
+  } while (Iteration++ < MaxIterations && DevirtualizedCall);
+
+  if (DevirtualizedCall)
+    LLVM_DEBUG(dbgs() << "  CGSCCPASSMGR: Stopped iteration after " << Iteration
+                      << " times, due to -max-cg-scc-iterations\n");
+
+  MaxSCCIterations.updateMax(Iteration);
+  return Changed;
+}
+
 /// Initialize CG
 bool CGPassManager::doInitialization(CallGraph &CG) {
   bool Changed = false;

Modified: llvm/trunk/test/Transforms/Inline/always-inline.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/Inline/always-inline.ll?rev=336419&r1=336418&r2=336419&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/Inline/always-inline.ll (original)
+++ llvm/trunk/test/Transforms/Inline/always-inline.ll Fri Jul  6 01:04:47 2018
@@ -316,3 +316,10 @@ define void @outer14() {
   call void @inner14()
   ret void
 }
+
+define internal i32 @outer15() {
+; CHECK-LABEL: @outer15
+; CHECK: ret i32 1
+  %res = call i32 @inner1()
+  ret i32 %res
+}




More information about the llvm-commits mailing list