]> granicus.if.org Git - llvm/commitdiff
[PM] Improve the debugging and logging facilities of the CGSCC bits of
authorChandler Carruth <chandlerc@gmail.com>
Mon, 27 Jun 2016 23:26:08 +0000 (23:26 +0000)
committerChandler Carruth <chandlerc@gmail.com>
Mon, 27 Jun 2016 23:26:08 +0000 (23:26 +0000)
the new pass manager.

This adds operator<< overloads for the various bits of the
LazyCallGraph, dump methods for use from the debugger, and debug logging
using them to the CGSCC pass manager.

Having this was essential for debugging the call graph update patch, and
I've extracted what I could from that patch here to minimize the delta.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@273961 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/Analysis/CGSCCPassManager.h
include/llvm/Analysis/LazyCallGraph.h
lib/Analysis/LazyCallGraph.cpp
lib/Passes/PassBuilder.cpp
test/Other/new-pass-manager.ll

index 989305ebb272b871cc5f38d9c6d6bdc6423b466c..3263ecec4e2659abe196137d3b908066375ada48 100644 (file)
@@ -67,19 +67,20 @@ template <typename CGSCCPassT>
 class ModuleToPostOrderCGSCCPassAdaptor
     : public PassInfoMixin<ModuleToPostOrderCGSCCPassAdaptor<CGSCCPassT>> {
 public:
-  explicit ModuleToPostOrderCGSCCPassAdaptor(CGSCCPassT Pass)
-      : Pass(std::move(Pass)) {}
+  explicit ModuleToPostOrderCGSCCPassAdaptor(CGSCCPassT Pass, bool DebugLogging = false)
+      : Pass(std::move(Pass)), DebugLogging(DebugLogging) {}
   // We have to explicitly define all the special member functions because MSVC
   // refuses to generate them.
   ModuleToPostOrderCGSCCPassAdaptor(
       const ModuleToPostOrderCGSCCPassAdaptor &Arg)
-      : Pass(Arg.Pass) {}
+      : Pass(Arg.Pass), DebugLogging(Arg.DebugLogging) {}
   ModuleToPostOrderCGSCCPassAdaptor(ModuleToPostOrderCGSCCPassAdaptor &&Arg)
-      : Pass(std::move(Arg.Pass)) {}
+      : Pass(std::move(Arg.Pass)), DebugLogging(Arg.DebugLogging) {}
   friend void swap(ModuleToPostOrderCGSCCPassAdaptor &LHS,
                    ModuleToPostOrderCGSCCPassAdaptor &RHS) {
     using std::swap;
     swap(LHS.Pass, RHS.Pass);
+    swap(LHS.DebugLogging, RHS.DebugLogging);
   }
   ModuleToPostOrderCGSCCPassAdaptor &
   operator=(ModuleToPostOrderCGSCCPassAdaptor RHS) {
@@ -97,8 +98,11 @@ public:
     LazyCallGraph &CG = AM.getResult<LazyCallGraphAnalysis>(M);
 
     PreservedAnalyses PA = PreservedAnalyses::all();
-    for (LazyCallGraph::RefSCC &OuterC : CG.postorder_ref_sccs())
-      for (LazyCallGraph::SCC &C : OuterC) {
+    for (LazyCallGraph::RefSCC &RC : CG.postorder_ref_sccs()) {
+      if (DebugLogging)
+        dbgs() << "Running an SCC pass across the RefSCC: " << RC << "\n";
+
+      for (LazyCallGraph::SCC &C : RC) {
         PreservedAnalyses PassPA = Pass.run(C, CGAM);
 
         // We know that the CGSCC pass couldn't have invalidated any other
@@ -115,6 +119,7 @@ public:
         // analyses will eventually occur when the module pass completes.
         PA.intersect(std::move(PassPA));
       }
+    }
 
     // By definition we preserve the proxy. This precludes *any* invalidation
     // of CGSCC analyses by the proxy, but that's OK because we've taken
@@ -126,14 +131,15 @@ public:
 
 private:
   CGSCCPassT Pass;
+  bool DebugLogging;
 };
 
 /// \brief A function to deduce a function pass type and wrap it in the
 /// templated adaptor.
 template <typename CGSCCPassT>
 ModuleToPostOrderCGSCCPassAdaptor<CGSCCPassT>
-createModuleToPostOrderCGSCCPassAdaptor(CGSCCPassT Pass) {
-  return ModuleToPostOrderCGSCCPassAdaptor<CGSCCPassT>(std::move(Pass));
+createModuleToPostOrderCGSCCPassAdaptor(CGSCCPassT Pass, bool DebugLogging = false) {
+  return ModuleToPostOrderCGSCCPassAdaptor<CGSCCPassT>(std::move(Pass), DebugLogging);
 }
 
 extern template class InnerAnalysisManagerProxy<FunctionAnalysisManager,
@@ -159,18 +165,19 @@ template <typename FunctionPassT>
 class CGSCCToFunctionPassAdaptor
     : public PassInfoMixin<CGSCCToFunctionPassAdaptor<FunctionPassT>> {
 public:
-  explicit CGSCCToFunctionPassAdaptor(FunctionPassT Pass)
-      : Pass(std::move(Pass)) {}
+  explicit CGSCCToFunctionPassAdaptor(FunctionPassT Pass, bool DebugLogging = false)
+      : Pass(std::move(Pass)), DebugLogging(DebugLogging) {}
   // We have to explicitly define all the special member functions because MSVC
   // refuses to generate them.
   CGSCCToFunctionPassAdaptor(const CGSCCToFunctionPassAdaptor &Arg)
-      : Pass(Arg.Pass) {}
+      : Pass(Arg.Pass), DebugLogging(Arg.DebugLogging) {}
   CGSCCToFunctionPassAdaptor(CGSCCToFunctionPassAdaptor &&Arg)
-      : Pass(std::move(Arg.Pass)) {}
+      : Pass(std::move(Arg.Pass)), DebugLogging(Arg.DebugLogging) {}
   friend void swap(CGSCCToFunctionPassAdaptor &LHS,
                    CGSCCToFunctionPassAdaptor &RHS) {
     using std::swap;
     swap(LHS.Pass, RHS.Pass);
+    swap(LHS.DebugLogging, RHS.DebugLogging);
   }
   CGSCCToFunctionPassAdaptor &operator=(CGSCCToFunctionPassAdaptor RHS) {
     swap(*this, RHS);
@@ -183,6 +190,9 @@ public:
     FunctionAnalysisManager &FAM =
         AM.getResult<FunctionAnalysisManagerCGSCCProxy>(C).getManager();
 
+    if (DebugLogging)
+      dbgs() << "Running function passes across an SCC: " << C << "\n";
+
     PreservedAnalyses PA = PreservedAnalyses::all();
     for (LazyCallGraph::Node &N : C) {
       PreservedAnalyses PassPA = Pass.run(N.getFunction(), FAM);
@@ -211,14 +221,16 @@ public:
 
 private:
   FunctionPassT Pass;
+  bool DebugLogging;
 };
 
 /// \brief A function to deduce a function pass type and wrap it in the
 /// templated adaptor.
 template <typename FunctionPassT>
 CGSCCToFunctionPassAdaptor<FunctionPassT>
-createCGSCCToFunctionPassAdaptor(FunctionPassT Pass) {
-  return CGSCCToFunctionPassAdaptor<FunctionPassT>(std::move(Pass));
+createCGSCCToFunctionPassAdaptor(FunctionPassT Pass, bool DebugLogging = false) {
+  return CGSCCToFunctionPassAdaptor<FunctionPassT>(std::move(Pass),
+                                                   DebugLogging);
 }
 }
 
index 340ca491574955caf910eabb9e720b877defa622..47cb3101ba3e8f5b08c605ea830196aeb87884d6 100644 (file)
@@ -48,6 +48,7 @@
 #include "llvm/IR/Module.h"
 #include "llvm/IR/PassManager.h"
 #include "llvm/Support/Allocator.h"
+#include "llvm/Support/raw_ostream.h"
 #include <iterator>
 #include <utility>
 
@@ -222,6 +223,12 @@ public:
     /// Internal helper to remove the edge to the given function.
     void removeEdgeInternal(Function &ChildF);
 
+    /// Print the name of this node's function.
+    friend raw_ostream &operator<<(raw_ostream &OS, const Node &N);
+
+    /// Dump the name of this node's function to stderr.
+    void dump() const;
+
   public:
     LazyCallGraph &getGraph() const { return *G; }
 
@@ -353,6 +360,15 @@ public:
       Nodes.clear();
     }
 
+    /// Print a short descrtiption useful for debugging or logging.
+    ///
+    /// We print the function names in the SCC wrapped in '()'s and skipping
+    /// the middle functions if there are a large number.
+    friend raw_ostream &operator<<(raw_ostream &OS, const SCC &C);
+
+    /// Dump a short description of this SCC to stderr.
+    void dump() const;
+
 #ifndef NDEBUG
     /// Verify invariants about the SCC.
     ///
@@ -373,25 +389,15 @@ public:
 
     RefSCC &getOuterRefSCC() const { return *OuterRefSCC; }
 
-    /// Short name useful for debugging or logging.
+    /// Provide a short name by printing this SCC to a std::string.
     ///
-    /// We use the name of the first function in the SCC to name the SCC for
-    /// the purposes of debugging and logging.
+    /// This copes with the fact that we don't have a name per-se for an SCC
+    /// while still making the use of this in debugging and logging useful.
     std::string getName() const {
       std::string Name;
-      int i = 0;
-      for (Node &N : *this) {
-        if (i > 0)
-          Name += ", ";
-        // Elide the inner elements if there are too many.
-        if (i > 8) {
-          Name += "..., ";
-          Name += Nodes.back()->getFunction().getName().str();
-          break;
-        }
-        Name += N.getFunction().getName().str();
-        ++i;
-      }
+      raw_string_ostream OS(Name);
+      OS << *this;
+      OS.flush();
       return Name;
     }
   };
@@ -426,6 +432,15 @@ public:
     /// formRefSCCFast on the graph itself.
     RefSCC(LazyCallGraph &G);
 
+    /// Print a short description useful for debugging or logging.
+    ///
+    /// We print the SCCs wrapped in '[]'s and skipping the middle SCCs if
+    /// there are a large number.
+    friend raw_ostream &operator<<(raw_ostream &OS, const RefSCC &RC);
+
+    /// Dump a short description of this RefSCC to stderr.
+    void dump() const;
+
 #ifndef NDEBUG
     /// Verify invariants about the RefSCC and all its SCCs.
     ///
@@ -477,12 +492,16 @@ public:
     /// Test if this RefSCC is a descendant of \a C.
     bool isDescendantOf(const RefSCC &C) const;
 
-    /// Short name useful for debugging or logging.
+    /// Provide a short name by printing this SCC to a std::string.
     ///
-    /// We use the name of the first function in the SCC to name the SCC for
-    /// the purposes of debugging and logging.
-    StringRef getName() const {
-      return begin()->begin()->getFunction().getName();
+    /// This copes with the fact that we don't have a name per-se for an SCC
+    /// while still making the use of this in debugging and logging useful.
+    std::string getName() const {
+      std::string Name;
+      raw_string_ostream OS(Name);
+      OS << *this;
+      OS.flush();
+      return Name;
     }
 
     ///@{
index a153333e79a8e4ddc5436a8f2032a4a7abb471b7..2d34a243f476fc39ae6fcf321d5e6ee3e4076768 100644 (file)
@@ -120,6 +120,14 @@ void LazyCallGraph::Node::removeEdgeInternal(Function &Target) {
   EdgeIndexMap.erase(IndexMapI);
 }
 
+raw_ostream &llvm::operator<<(raw_ostream &OS, const LazyCallGraph::Node &N) {
+  return OS << N.F.getName();
+}
+
+void LazyCallGraph::Node::dump() const {
+  dbgs() << *this << '\n';
+}
+
 LazyCallGraph::LazyCallGraph(Module &M) : NextDFSNumber(0) {
   DEBUG(dbgs() << "Building CG for module: " << M.getModuleIdentifier()
                << "\n");
@@ -173,6 +181,28 @@ LazyCallGraph &LazyCallGraph::operator=(LazyCallGraph &&G) {
   return *this;
 }
 
+raw_ostream &llvm::operator<<(raw_ostream &OS, const LazyCallGraph::SCC &C) {
+  OS << '(';
+  int i = 0;
+  for (LazyCallGraph::Node &N : C) {
+    if (i > 0)
+      OS << ", ";
+    // Elide the inner elements if there are too many.
+    if (i > 8) {
+      OS << "..., " << *C.Nodes.back();
+      break;
+    }
+    OS << N;
+    ++i;
+  }
+  OS << ')';
+  return OS;
+}
+
+void LazyCallGraph::SCC::dump() const {
+  dbgs() << *this << '\n';
+}
+
 #ifndef NDEBUG
 void LazyCallGraph::SCC::verify() {
   assert(OuterRefSCC && "Can't have a null RefSCC!");
@@ -194,6 +224,29 @@ void LazyCallGraph::SCC::verify() {
 
 LazyCallGraph::RefSCC::RefSCC(LazyCallGraph &G) : G(&G) {}
 
+raw_ostream &llvm::operator<<(raw_ostream &OS,
+                              const LazyCallGraph::RefSCC &RC) {
+  OS << '[';
+  int i = 0;
+  for (LazyCallGraph::SCC &C : RC) {
+    if (i > 0)
+      OS << ", ";
+    // Elide the inner elements if there are too many.
+    if (i > 4) {
+      OS << "..., " << *RC.SCCs.back();
+      break;
+    }
+    OS << C;
+    ++i;
+  }
+  OS << ']';
+  return OS;
+}
+
+void LazyCallGraph::RefSCC::dump() const {
+  dbgs() << *this << '\n';
+}
+
 #ifndef NDEBUG
 void LazyCallGraph::RefSCC::verify() {
   assert(G && "Can't have a null graph!");
index 362bd13d03d3a713c6072fef4f4910e56dc5b05f..5f6174550222ba07f35b4df8d5d2889778e52f68 100644 (file)
@@ -561,7 +561,8 @@ bool PassBuilder::parseCGSCCPassPipeline(CGSCCPassManager &CGPM,
       PipelineText = PipelineText.substr(1);
 
       // Add the nested pass manager with the appropriate adaptor.
-      CGPM.addPass(createCGSCCToFunctionPassAdaptor(std::move(NestedFPM)));
+      CGPM.addPass(
+          createCGSCCToFunctionPassAdaptor(std::move(NestedFPM), DebugLogging));
     } else {
       // Otherwise try to parse a pass name.
       size_t End = PipelineText.find_first_of(",)");
@@ -627,8 +628,8 @@ bool PassBuilder::parseModulePassPipeline(ModulePassManager &MPM,
       PipelineText = PipelineText.substr(1);
 
       // Add the nested pass manager with the appropriate adaptor.
-      MPM.addPass(
-          createModuleToPostOrderCGSCCPassAdaptor(std::move(NestedCGPM)));
+      MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(NestedCGPM),
+                                                          DebugLogging));
     } else if (PipelineText.startswith("function(")) {
       FunctionPassManager NestedFPM(DebugLogging);
 
@@ -689,7 +690,7 @@ bool PassBuilder::parsePassPipeline(ModulePassManager &MPM,
                                 DebugLogging) ||
         !PipelineText.empty())
       return false;
-    MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM)));
+    MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM), DebugLogging));
     return true;
   }
 
index 1ffd422c6a239e7809bf815183be32e2b33116a1..cbb45928429ef26e7c6cfabe759a7c770cbde403 100644 (file)
@@ -22,6 +22,7 @@
 ; CHECK-CGSCC-PASS-NEXT: Running pass: ModuleToPostOrderCGSCCPassAdaptor
 ; CHECK-CGSCC-PASS-NEXT: Running analysis: InnerAnalysisManagerProxy<{{.*}}>
 ; CHECK-CGSCC-PASS-NEXT: Running analysis: LazyCallGraphAnalysis
+; CHECK-CGSCC-PASS-NEXT: Running an SCC pass across the RefSCC: [(foo)]
 ; CHECK-CGSCC-PASS-NEXT: Starting llvm::LazyCallGraph::SCC pass manager run
 ; CHECK-CGSCC-PASS-NEXT: Running pass: NoOpCGSCCPass
 ; CHECK-CGSCC-PASS-NEXT: Finished llvm::LazyCallGraph::SCC pass manager run