Add inward edge counters to Nodes; Associate JoinLists with JoinTools.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@50738 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/tools/llvmc2/CompilationGraph.cpp b/tools/llvmc2/CompilationGraph.cpp
index c0c849b..2dd8812 100644
--- a/tools/llvmc2/CompilationGraph.cpp
+++ b/tools/llvmc2/CompilationGraph.cpp
@@ -86,7 +86,7 @@
 }
 
 void CompilationGraph::insertNode(Tool* V) {
-  if (!NodesMap.count(V->Name())) {
+  if (NodesMap.count(V->Name()) == 0) {
     Node N;
     N.OwningGraph = this;
     N.ToolPtr = V;
@@ -95,28 +95,27 @@
 }
 
 void CompilationGraph::insertEdge(const std::string& A, Edge* E) {
+  Node& B = getNode(E->ToolName());
   if (A == "root") {
-    const Node& N = getNode(E->ToolName());
-    const std::string& InputLanguage = N.ToolPtr->InputLanguage();
+    const std::string& InputLanguage = B.ToolPtr->InputLanguage();
     ToolsMap[InputLanguage].push_back(E->ToolName());
-
-    // Needed to support iteration via GraphTraits.
     NodesMap["root"].AddEdge(E);
   }
   else {
     Node& N = getNode(A);
     N.AddEdge(E);
   }
+  // Increase the inward edge counter.
+  B.IncrInEdges();
 }
 
 // Pass input file through the chain until we bump into a Join node or
 // a node that says that it is the last.
-const Tool* CompilationGraph::PassThroughGraph (sys::Path& In,
-                                                sys::Path Out,
-                                                const sys::Path& TempDir,
-                                                PathVector& JoinList) const {
+const JoinTool*
+CompilationGraph::PassThroughGraph (sys::Path& In, sys::Path Out,
+                                    const sys::Path& TempDir) const {
   bool Last = false;
-  const Tool* ret = 0;
+  JoinTool* ret = 0;
 
   // Get to the head of the toolchain.
   const tools_vector_type& TV = getToolsVector(getLanguage(In));
@@ -125,11 +124,11 @@
   const Node* N = &getNode(*TV.begin());
 
   while(!Last) {
-    const Tool* CurTool = N->ToolPtr.getPtr();
+    Tool* CurTool = N->ToolPtr.getPtr();
 
     if (CurTool->IsJoin()) {
-      JoinList.push_back(In);
-      ret = CurTool;
+      ret = &dynamic_cast<JoinTool&>(*CurTool);
+      ret->AddToJoinList(In);
       break;
     }
 
@@ -161,11 +160,8 @@
   return ret;
 }
 
-// TOFIX: support more interesting graph topologies. We will need to
-// do topological sorting to process multiple Join nodes correctly.
 int CompilationGraph::Build (const sys::Path& TempDir) const {
-  PathVector JoinList;
-  const Tool* JoinTool = 0;
+  const JoinTool* JT = 0;
   sys::Path In, Out;
 
   // For each input file
@@ -173,25 +169,25 @@
         E = InputFilenames.end(); B != E; ++B) {
     In = sys::Path(*B);
 
-    const Tool* NewJoin = PassThroughGraph(In, Out, TempDir, JoinList);
-    if (JoinTool && NewJoin && JoinTool != NewJoin)
+    const JoinTool* NewJoin = PassThroughGraph(In, Out, TempDir);
+    if (JT && NewJoin && JT != NewJoin)
       throw std::runtime_error("Graphs with multiple Join nodes"
                                "are not yet supported!");
     else if (NewJoin)
-      JoinTool = NewJoin;
+      JT = NewJoin;
   }
 
-  if (JoinTool) {
+  if (JT) {
     // If the final output name is empty, set it to "a.out"
     if (!OutputFilename.empty()) {
       Out = sys::Path(OutputFilename);
     }
     else {
       Out = sys::Path("a");
-      Out.appendSuffix(JoinTool->OutputSuffix());
+      Out.appendSuffix(JT->OutputSuffix());
     }
 
-    if (JoinTool->GenerateAction(JoinList, Out).Execute() != 0)
+    if (JT->GenerateAction(Out).Execute() != 0)
       throw std::runtime_error("Tool returned error code!");
   }
 
diff --git a/tools/llvmc2/CompilationGraph.h b/tools/llvmc2/CompilationGraph.h
index bddd8bd..bf46fa5 100644
--- a/tools/llvmc2/CompilationGraph.h
+++ b/tools/llvmc2/CompilationGraph.h
@@ -55,31 +55,41 @@
     typedef container_type::iterator iterator;
     typedef container_type::const_iterator const_iterator;
 
-    Node() {}
-    Node(CompilationGraph* G) : OwningGraph(G) {}
-    Node(CompilationGraph* G, Tool* T) : OwningGraph(G), ToolPtr(T) {}
+    Node() : OwningGraph(0), InEdges(0) {}
+    Node(CompilationGraph* G) : OwningGraph(G), InEdges(0) {}
+    Node(CompilationGraph* G, Tool* T) :
+      OwningGraph(G), ToolPtr(T), InEdges(0) {}
 
     bool HasChildren() const { return !OutEdges.empty(); }
     const std::string Name() const { return ToolPtr->Name(); }
 
+    // Iteration.
     iterator EdgesBegin() { return OutEdges.begin(); }
     const_iterator EdgesBegin() const { return OutEdges.begin(); }
     iterator EdgesEnd() { return OutEdges.end(); }
     const_iterator EdgesEnd() const { return OutEdges.end(); }
 
-    // Choose one of the edges based on command-line options.
+    // Choose one of the outward edges based on command-line options.
     const Edge* ChooseEdge() const;
 
-    // Takes ownership of the object.
+    // Add an outward edge. Takes ownership of the Edge object.
     void AddEdge(Edge* E)
     { OutEdges.push_back(llvm::IntrusiveRefCntPtr<Edge>(E)); }
 
+    // Inward edge counter. Used by Build() to implement topological
+    // sort.
+    void IncrInEdges() { ++InEdges; }
+    void DecrInEdges() { --InEdges; }
+    bool HasNoInEdges() const { return InEdges == 0; }
+
     // Needed to implement NodeChildIterator/GraphTraits
     CompilationGraph* OwningGraph;
     // The corresponding Tool.
     llvm::IntrusiveRefCntPtr<Tool> ToolPtr;
     // Links to children.
     container_type OutEdges;
+    // Number of parents.
+    unsigned InEdges;
   };
 
   class NodesIterator;
@@ -105,7 +115,7 @@
     void insertNode(Tool* T);
 
     // insertEdge - Insert a new edge into the graph. Takes ownership
-    // of the object.
+    // of the Edge object.
     void insertEdge(const std::string& A, Edge* E);
 
     // Build - Build target(s) from the input file set. Command-line
@@ -143,9 +153,8 @@
     const tools_vector_type& getToolsVector(const std::string& LangName) const;
 
     // Pass the input file through the toolchain.
-    const Tool* PassThroughGraph (llvm::sys::Path& In, llvm::sys::Path Out,
-                                  const llvm::sys::Path& TempDir,
-                                  PathVector& JoinList) const;
+    const JoinTool* PassThroughGraph (llvm::sys::Path& In, llvm::sys::Path Out,
+                                      const llvm::sys::Path& TempDir) const;
 
   };
 
diff --git a/tools/llvmc2/Tool.h b/tools/llvmc2/Tool.h
index 0d907dd..5136468 100644
--- a/tools/llvmc2/Tool.h
+++ b/tools/llvmc2/Tool.h
@@ -28,11 +28,14 @@
 
   class Tool : public llvm::RefCountedBaseVPTR<Tool> {
   public:
-    virtual Action GenerateAction (PathVector const& inFiles,
-                                  llvm::sys::Path const& outFile) const = 0;
 
-    virtual Action GenerateAction (llvm::sys::Path const& inFile,
-                                  llvm::sys::Path const& outFile) const = 0;
+    virtual ~Tool() {}
+
+    virtual Action GenerateAction (const PathVector& inFiles,
+                                   const llvm::sys::Path& outFile) const = 0;
+
+    virtual Action GenerateAction (const llvm::sys::Path& inFile,
+                                   const llvm::sys::Path& outFile) const = 0;
 
     virtual const char* Name() const = 0;
     virtual const char* InputLanguage() const = 0;
@@ -47,9 +50,21 @@
     // TOFIX: find a better name
     static void UnpackValues (std::string const& from,
                               std::vector<std::string>& to);
+  };
 
-    virtual ~Tool()
-    {}
+  // Join tools have an input file list associated with them.
+  class JoinTool : public Tool {
+  public:
+    void AddToJoinList(const llvm::sys::Path& P) { JoinList.push_back(P); }
+    void ClearJoinList() { JoinList.clear(); }
+
+    Action GenerateAction(const llvm::sys::Path& outFile) const
+    { return GenerateAction(JoinList, outFile); }
+    // We shouldn't shadow GenerateAction from the base class.
+    using Tool::GenerateAction;
+
+  private:
+    PathVector JoinList;
   };
 
 }