llvm.org GIT mirror llvm / 0d08db0
Convert internal representation to use DAG. This gives us more flexibility and enables future improvements. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@50724 91177308-0d34-0410-b5e6-96231b3b80d8 Mikhail Glushenkov 11 years ago
7 changed file(s) with 408 addition(s) and 83 deletion(s). Raw diff Collapse all Expand all
1313 class Tool l> {
1414 list properties = l;
1515 }
16
17 // Special Tool instance - root of all toolchains
18
19 def root : Tool<[]>;
1620
1721 // Possible Tool properties
1822
5155 list map = lst;
5256 }
5357
54 // Toolchain classes
58 // Compilation graph
5559
56 class ToolChain lst> {
57 list tools = lst;
60 class Edge {
61 Tool a = t1;
62 Tool b = t2;
5863 }
5964
60 class ToolChains lst> {
61 list chains = lst;
65 class CompilationGraph lst> {
66 list edges = lst;
6267 }
1313 #include "CompilationGraph.h"
1414
1515 #include "llvm/Support/CommandLine.h"
16 #include "llvm/ADT/STLExtras.h"
16 #include "llvm/Support/DOTGraphTraits.h"
17 #include "llvm/Support/GraphWriter.h"
1718
1819 #include
1920
2021 using namespace llvm;
22 using namespace llvmcc;
2123
2224 extern cl::list InputFilenames;
2325 extern cl::opt OutputFilename;
2426
25 int llvmcc::CompilationGraph::Build (const sys::Path& tempDir) const {
26 sys::Path In(InputFilenames.at(0)), Out;
27 CompilationGraph::CompilationGraph() {
28 NodesMap["root"] = Node(this);
29 }
2730
28 // Find out which language corresponds to the suffix of the first input file
29 LanguageMap::const_iterator Lang = ExtsToLangs.find(In.getSuffix());
31 Node& CompilationGraph::getNode(const std::string& ToolName) {
32 nodes_map_type::iterator I = NodesMap.find(ToolName);
33 if (I == NodesMap.end())
34 throw std::runtime_error("Node " + ToolName + " is not in graph");
35 return I->second;
36 }
37
38 const Node& CompilationGraph::getNode(const std::string& ToolName) const {
39 nodes_map_type::const_iterator I = NodesMap.find(ToolName);
40 if (I == NodesMap.end())
41 throw std::runtime_error("Node " + ToolName + " is not in graph!");
42 return I->second;
43 }
44
45 const std::string& CompilationGraph::getLanguage(const sys::Path& File) const {
46 LanguageMap::const_iterator Lang = ExtsToLangs.find(File.getSuffix());
3047 if (Lang == ExtsToLangs.end())
31 throw std::runtime_error("Unknown suffix!");
48 throw std::runtime_error("Unknown suffix: " + File.getSuffix() + '!');
49 return Lang->second;
50 }
3251
33 // Find the toolchain corresponding to this language
34 ToolChainMap::const_iterator ToolsIt = ToolChains.find(Lang->second);
35 if (ToolsIt == ToolChains.end())
36 throw std::runtime_error("Unknown language!");
37 ToolChain Tools = ToolsIt->second;
52 const CompilationGraph::tools_vector_type&
53 CompilationGraph::getToolsVector(const std::string& LangName) const
54 {
55 tools_map_type::const_iterator I = ToolsMap.find(LangName);
56 if (I == ToolsMap.end())
57 throw std::runtime_error("No tools corresponding to " + LangName
58 + " found!");
59 return I->second;
60 }
3861
62 void CompilationGraph::insertVertex(const IntrusiveRefCntPtr V) {
63 if (!NodesMap.count(V->Name())) {
64 Node N;
65 N.OwningGraph = this;
66 N.ToolPtr = V;
67 NodesMap[V->Name()] = N;
68 }
69 }
70
71 void CompilationGraph::insertEdge(const std::string& A,
72 const std::string& B) {
73 // TOTHINK: check this at compile-time?
74 if (B == "root")
75 throw std::runtime_error("Edges back to the root are not allowed!"
76 "Compilation graph should be acyclic!");
77
78 if (A == "root") {
79 const Node& N = getNode(B);
80 const std::string& InputLanguage = N.ToolPtr->InputLanguage();
81 ToolsMap[InputLanguage].push_back(B);
82
83 // Needed to support iteration via GraphTraits.
84 NodesMap["root"].Children.push_back(B);
85 }
86 else {
87 Node& NA = getNode(A);
88 // Check that there is a node at B.
89 getNode(B);
90 NA.Children.push_back(B);
91 }
92 }
93
94 // TOFIX: extend, add an ability to choose between different
95 // toolchains, support more interesting graph topologies.
96 int CompilationGraph::Build (const sys::Path& tempDir) const {
3997 PathVector JoinList;
98 const Tool* JoinTool = 0;
99 sys::Path In, Out;
40100
101 // For each input file
41102 for (cl::list::const_iterator B = InputFilenames.begin(),
42103 E = InputFilenames.end(); B != E; ++B) {
43104 In = sys::Path(*B);
44105
45 // Pass input file through the toolchain
46 for (ToolChain::const_iterator B = Tools.begin(), E = Tools.end();
47 B != E; ++B) {
106 // Get to the head of the toolchain.
107 const tools_vector_type& TV = getToolsVector(getLanguage(In));
108 if(TV.empty())
109 throw std::runtime_error("Tool names vector is empty!");
110 const Node* N = &getNode(*TV.begin());
48111
49 const Tool* CurTool = B->getPtr();
112 // Pass it through the chain until we bump into a Join node or a
113 // node that says that it is the last.
114 bool Last = false;
115 while(!Last) {
116 const Tool* CurTool = N->ToolPtr.getPtr();
50117
51 // Is this the last step in the chain?
52 if (llvm::next(B) == E || CurTool->IsLast()) {
118 if(CurTool->IsJoin()) {
53119 JoinList.push_back(In);
120 JoinTool = CurTool;
54121 break;
122 }
123
124 // Is this the last tool?
125 if (N->Children.empty() || CurTool->IsLast()) {
126 Out.appendComponent(In.getBasename());
127 Out.appendSuffix(CurTool->OutputSuffix());
128 Last = true;
55129 }
56130 else {
57131 Out = tempDir;
64138 if (CurTool->GenerateAction(In, Out).Execute() != 0)
65139 throw std::runtime_error("Tool returned error code!");
66140
141 N = &getNode(*N->Children.begin());
67142 In = Out; Out.clear();
68143 }
69144 }
70145
71 // Pass .o files to linker
72 const Tool* JoinNode = (--Tools.end())->getPtr();
146 if(JoinTool) {
147 // If the final output name is empty, set it to "a.out"
148 if (!OutputFilename.empty()) {
149 Out = sys::Path(OutputFilename);
150 }
151 else {
152 Out = sys::Path("a");
153 Out.appendSuffix(JoinTool->OutputSuffix());
154 }
73155
74 // If the final output name is empty, set it to "a.out"
75 if (!OutputFilename.empty()) {
76 Out = sys::Path(OutputFilename);
156 if (JoinTool->GenerateAction(JoinList, Out).Execute() != 0)
157 throw std::runtime_error("Tool returned error code!");
77158 }
78 else {
79 Out = sys::Path("a");
80 Out.appendSuffix(JoinNode->OutputSuffix());
81 }
82
83 if (JoinNode->GenerateAction(JoinList, Out).Execute() != 0)
84 throw std::runtime_error("Tool returned error code!");
85159
86160 return 0;
87161 }
162
163 namespace llvm {
164 template <>
165 struct DOTGraphTraits
166 : public DefaultDOTGraphTraits
167 {
168
169 template
170 static std::string getNodeLabel(const Node* N, const GraphType&) {
171 if (N->ToolPtr)
172 return N->ToolPtr->Name();
173 else
174 return "root";
175 }
176
177 };
178 }
179
180 void CompilationGraph::writeGraph() {
181 std::ofstream O("CompilationGraph.dot");
182
183 if(O.good()) {
184 llvm::WriteGraph(this, "CompilationGraph");
185 O.close();
186 }
187 else {
188 throw std::runtime_error("");
189 }
190 }
191
192 void CompilationGraph::viewGraph() {
193 llvm::ViewGraph(this, "CompilationGraph");
194 }
1616 #include "AutoGenerated.h"
1717 #include "Tool.h"
1818
19 #include "llvm/ADT/GraphTraits.h"
20 #include "llvm/ADT/iterator"
21 #include "llvm/ADT/SmallVector.h"
1922 #include "llvm/ADT/StringMap.h"
2023 #include "llvm/System/Path.h"
2124
25 #include
26
2227 namespace llvmcc {
2328
24 typedef std::vector > ToolChain;
25 typedef llvm::StringMap ToolChainMap;
26
27 struct CompilationGraph {
28 ToolChainMap ToolChains;
29 class CompilationGraph;
30
31 struct Node {
32 typedef llvm::SmallVector sequence_type;
33
34 Node() {}
35 Node(CompilationGraph* G) : OwningGraph(G) {}
36 Node(CompilationGraph* G, Tool* T) : OwningGraph(G), ToolPtr(T) {}
37
38 // Needed to implement NodeChildIterator/GraphTraits
39 CompilationGraph* OwningGraph;
40 // The corresponding Tool.
41 llvm::IntrusiveRefCntPtr ToolPtr;
42 // Links to children.
43 sequence_type Children;
44 };
45
46 // This can be generalised to something like value_iterator for maps
47 class NodesIterator : public llvm::StringMap::iterator {
48 typedef llvm::StringMap::iterator super;
49 typedef NodesIterator ThisType;
50 typedef Node* pointer;
51 typedef Node& reference;
52
53 public:
54 NodesIterator(super I) : super(I) {}
55
56 inline reference operator*() const {
57 return super::operator->()->second;
58 }
59 inline pointer operator->() const {
60 return &super::operator->()->second;
61 }
62 };
63
64 class CompilationGraph {
65 typedef llvm::StringMap nodes_map_type;
66 typedef llvm::SmallVector tools_vector_type;
67 typedef llvm::StringMap tools_map_type;
68
69 // Map from file extensions to language names.
2970 LanguageMap ExtsToLangs;
30
71 // Map from language names to lists of tool names.
72 tools_map_type ToolsMap;
73 // Map from tool names to Tool objects.
74 nodes_map_type NodesMap;
75
76 public:
77
78 CompilationGraph();
79
80 // insertVertex - insert a new node into the graph.
81 void insertVertex(const llvm::IntrusiveRefCntPtr T);
82
83 // insertEdge - Insert a new edge into the graph. This function
84 // assumes that both A and B have been already inserted.
85 void insertEdge(const std::string& A, const std::string& B);
86
87 // Build - Build the target(s) from the set of the input
88 // files. Command-line options are passed implicitly as global
89 // variables.
3190 int Build(llvm::sys::Path const& tempDir) const;
91
92 /// viewGraph - This function is meant for use from the debugger.
93 /// You can just say 'call G->viewGraph()' and a ghostview window
94 /// should pop up from the program, displaying the compilation
95 /// graph. This depends on there being a 'dot' and 'gv' program
96 /// in your path.
97 void viewGraph();
98
99 /// Write a CompilationGraph.dot file.
100 void writeGraph();
101
102 // GraphTraits support
103
104 typedef NodesIterator nodes_iterator;
105
106 nodes_iterator nodes_begin() {
107 return NodesIterator(NodesMap.begin());
108 }
109
110 nodes_iterator nodes_end() {
111 return NodesIterator(NodesMap.end());
112 }
113
114 // Return a reference to the node correponding to the given tool
115 // name. Throws std::runtime_error in case of error.
116 Node& getNode(const std::string& ToolName);
117 const Node& getNode(const std::string& ToolName) const;
118
119 // Auto-generated function.
120 friend void PopulateCompilationGraph(CompilationGraph&);
121
122 private:
123 // Helper function - find out which language corresponds to the
124 // suffix of this file
125 const std::string& getLanguage(const llvm::sys::Path& File) const;
126
127 // Return a reference to the tool names list correponding to the
128 // given language name. Throws std::runtime_error in case of
129 // error.
130 const tools_vector_type& getToolsVector(const std::string& LangName) const;
131 };
132
133 // Auxiliary class needed to implement GraphTraits support.
134 class NodeChildIterator : public bidirectional_iterator {
135 typedef NodeChildIterator ThisType;
136 typedef Node::sequence_type::iterator iterator;
137
138 CompilationGraph* OwningGraph;
139 iterator KeyIter;
140 public:
141 typedef Node* pointer;
142 typedef Node& reference;
143
144 NodeChildIterator(Node* N, iterator I) :
145 OwningGraph(N->OwningGraph), KeyIter(I) {}
146
147 const ThisType& operator=(const ThisType& I) {
148 assert(OwningGraph == I.OwningGraph);
149 KeyIter = I.KeyIter;
150 return *this;
151 }
152
153 inline bool operator==(const ThisType& I) const
154 { return KeyIter == I.KeyIter; }
155 inline bool operator!=(const ThisType& I) const
156 { return KeyIter != I.KeyIter; }
157
158 inline pointer operator*() const {
159 return &OwningGraph->getNode(*KeyIter);
160 }
161 inline pointer operator->() const {
162 return &OwningGraph->getNode(*KeyIter);
163 }
164
165 ThisType& operator++() { ++KeyIter; return *this; } // Preincrement
166 ThisType operator++(int) { // Postincrement
167 ThisType tmp = *this;
168 ++*this;
169 return tmp;
170 }
171
172 inline ThisType& operator--() { --KeyIter; return *this; } // Predecrement
173 inline ThisType operator--(int) { // Postdecrement
174 ThisType tmp = *this;
175 --*this;
176 return tmp;
177 }
178
32179 };
33180 }
34181
182 namespace llvm {
183 template <>
184 struct GraphTraits {
185 typedef llvmcc::CompilationGraph GraphType;
186 typedef llvmcc::Node NodeType;
187 typedef llvmcc::NodeChildIterator ChildIteratorType;
188
189 static NodeType* getEntryNode(GraphType* G) {
190 return &G->getNode("root");
191 }
192
193 static ChildIteratorType child_begin(NodeType* N) {
194 return ChildIteratorType(N, N->Children.begin());
195 }
196 static ChildIteratorType child_end(NodeType* N) {
197 return ChildIteratorType(N, N->Children.end());
198 }
199
200 typedef GraphType::nodes_iterator nodes_iterator;
201 static nodes_iterator nodes_begin(GraphType *G) {
202 return G->nodes_begin();
203 }
204 static nodes_iterator nodes_end(GraphType *G) {
205 return G->nodes_end();
206 }
207 };
208
209 }
210
35211 #endif // LLVM_TOOLS_LLVMC2_COMPILATION_GRAPH_H
66 //
77 //===----------------------------------------------------------------------===//
88 //
9 // This file contains toolchain descriptions used by llvmcc.
9 // This file contains compilation graph description used by llvmcc.
1010 //
1111 //===----------------------------------------------------------------------===//
1212
1515
1616 // Toolchains
1717
18 def ToolChains : ToolChains<[
19 ToolChain<[llvm_gcc_c, llc, llvm_gcc_assembler, llvm_gcc_linker]>,
20 ToolChain<[llvm_gcc_cpp, llc, llvm_gcc_assembler, llvm_gcc_linker]>,
21 ToolChain<[llvm_as, llc, llvm_gcc_assembler, llvm_gcc_linker]>,
22 ToolChain<[llvm_gcc_assembler, llvm_gcc_linker]>
18 def CompilationGraph : CompilationGraph<[
19 Edge,
20 Edge,
21 Edge,
22 Edge,
23 Edge,
24 Edge,
25 Edge,
26 Edge,
27 Edge
2328 ]>;
66 //
77 //===----------------------------------------------------------------------===//
88 //
9 // This file contains toolchain descriptions used by llvmcc.
9 // This file contains compilation graph description used by llvmcc.
1010 //
1111 //===----------------------------------------------------------------------===//
1212
1515
1616 // Toolchains
1717
18 def ToolChains : ToolChains<[
19 ToolChain<[llvm_gcc_c, opt, llc, llvm_gcc_assembler, llvm_gcc_linker]>,
20 ToolChain<[llvm_gcc_cpp, opt, llc, llvm_gcc_assembler, llvm_gcc_linker]>,
21 ToolChain<[llvm_as, opt, llc, llvm_gcc_assembler, llvm_gcc_linker]>,
22 ToolChain<[llvm_gcc_assembler, llvm_gcc_linker]>
18 def CompilationGraph : CompilationGraph<[
19 Edge,
20 Edge,
21 Edge,
22 Edge,
23 Edge,
24 Edge,
25 Edge,
26 Edge,
27 Edge,
28 Edge
2329 ]>;
2727 namespace sys = llvm::sys;
2828 using namespace llvmcc;
2929
30 // Built-in command-line options.
3031 // External linkage here is intentional.
31 cl::list InputFilenames(cl::Positional,
32 cl::desc(""), cl::OneOrMore);
32
33 cl::list InputFilenames(cl::Positional, cl::desc(""),
34 cl::OneOrMore);
3335 cl::opt OutputFilename("o", cl::desc("Output file name"),
3436 cl::value_desc("file"));
35 cl::opt VerboseMode("v", cl::desc("Enable verbose mode"));
36
37 cl::opt VerboseMode("v",
38 cl::desc("Enable verbose mode"));
39 cl::opt WriteGraph("write-graph",
40 cl::desc("Write CompilationGraph.dot file"),
41 cl::Hidden);
42 cl::opt ViewGraph("view-graph",
43 cl::desc("Show compilation graph in GhostView"),
44 cl::Hidden);
3745
3846 namespace {
3947 int BuildTargets(const CompilationGraph& graph) {
6068 cl::ParseCommandLineOptions(argc, argv,
6169 "LLVM Compiler Driver(Work In Progress)");
6270 PopulateCompilationGraph(graph);
71
72 if(WriteGraph)
73 graph.writeGraph();
74 if(ViewGraph)
75 graph.viewGraph();
76
6377 return BuildTargets(graph);
6478 }
6579 catch(const std::exception& ex) {
379379 checkNumberOfArguments(d, 1);
380380 SplitString(InitPtrToString(d->getArg(0)), toolProps_.CmdLine);
381381 if (toolProps_.CmdLine.empty())
382 throw std::string("Tool " + toolProps_.Name + " has empty command line!");
382 throw "Tool " + toolProps_.Name + " has empty command line!";
383383 }
384384
385385 void onInLanguage (DagInit* d) {
652652 << Indent2 << "std::vector vec;\n";
653653
654654 // Parse CmdLine tool property
655 if(P.CmdLine.empty())
656 throw "Tool " + P.Name + " has empty command line!";
657
655658 StrVector::const_iterator I = P.CmdLine.begin();
656659 ++I;
657660 for (StrVector::const_iterator E = P.CmdLine.end(); I != E; ++I) {
765768
766769 // Emit a Tool class definition
767770 void EmitToolClassDefinition (const ToolProperties& P, std::ostream& O) {
771
772 if(P.Name == "root")
773 return;
774
768775 // Header
769776 O << "class " << P.Name << " : public Tool {\n"
770777 << "public:\n";
850857 std::ostream& O)
851858 {
852859 // Get the relevant field out of RecordKeeper
853 Record* ToolChains = Records.getDef("ToolChains");
854 if (!ToolChains)
855 throw std::string("No ToolChains specification found!");
856 ListInit* chains = ToolChains->getValueAsListInit("chains");
857 if (!chains)
858 throw std::string("Error in toolchain list definition!");
860 Record* CompilationGraph = Records.getDef("CompilationGraph");
861 if (!CompilationGraph)
862 throw std::string("No CompilationGraph specification found!");
863 ListInit* edges = CompilationGraph->getValueAsListInit("edges");
864 if (!edges)
865 throw std::string("Error in compilation graph definition!");
859866
860867 // Generate code
861868 O << "void llvmcc::PopulateCompilationGraph(CompilationGraph& G) {\n"
862 << Indent1 << "PopulateLanguageMap(G.ExtsToLangs);\n"
863 << Indent1 << "std::vector > vec;\n\n";
864
865 for (unsigned i = 0; i < chains->size(); ++i) {
866 Record* ToolChain = chains->getElementAsRecord(i);
867 ListInit* Tools = ToolChain->getValueAsListInit("tools");
868
869 // Get name of the first tool in the list
870 const std::string& firstTool =
871 dynamic_cast(**Tools->begin()).getDef()->getName();
872
873 for (ListInit::iterator B = Tools->begin(),
874 E = Tools->end(); B != E; ++B) {
875 Record* val = dynamic_cast(**B).getDef();
876 O << Indent1 << "vec.push_back(IntrusiveRefCntPtr(new "
877 << val->getName() << "()));\n";
878 }
879 O << Indent1 << "G.ToolChains[\"" << ToolToLang[firstTool]
880 << "\"] = vec;\n";
881 O << Indent1 << "vec.clear();\n\n";
869 << Indent1 << "PopulateLanguageMap(G.ExtsToLangs);\n\n";
870
871 // Insert vertices
872
873 RecordVector Tools = Records.getAllDerivedDefinitions("Tool");
874 if (Tools.empty())
875 throw std::string("No tool definitions found!");
876
877 for (RecordVector::iterator B = Tools.begin(), E = Tools.end(); B != E; ++B) {
878 const std::string& Name = (*B)->getName();
879 if(Name != "root")
880 O << Indent1 << "G.insertVertex(IntrusiveRefCntPtr(new "
881 << Name << "()));\n";
882 }
883
884 O << '\n';
885
886 // Insert edges
887
888 for (unsigned i = 0; i < edges->size(); ++i) {
889 Record* Edge = edges->getElementAsRecord(i);
890 Record* A = Edge->getValueAsDef("a");
891 Record* B = Edge->getValueAsDef("b");
892 O << Indent1 << "G.insertEdge(\"" << A->getName() << "\", \""
893 << B->getName() << "\");\n";
882894 }
883895
884896 O << "}\n\n";