list<dag> properties = l;
}
-// Special Tool instance - the root node of the compilation graph.
-
-def root : Tool<[]>;
-
// Possible Tool properties
def in_language;
// Compilation graph
-class EdgeBase<Tool t1, Tool t2, dag d> {
- Tool a = t1;
- Tool b = t2;
+class EdgeBase<string t1, string t2, dag d> {
+ string a = t1;
+ string b = t2;
dag weight = d;
}
-class Edge<Tool t1, Tool t2> : EdgeBase<t1, t2, (empty)>;
+class Edge<string t1, string t2> : EdgeBase<t1, t2, (empty)>;
// Edge and SimpleEdge are synonyms.
-class SimpleEdge<Tool t1, Tool t2> : EdgeBase<t1, t2, (empty)>;
+class SimpleEdge<string t1, string t2> : EdgeBase<t1, t2, (empty)>;
// Optionally enabled edge.
-class OptionalEdge<Tool t1, Tool t2, dag props> : EdgeBase<t1, t2, props>;
+class OptionalEdge<string t1, string t2, dag props> : EdgeBase<t1, t2, props>;
class CompilationGraph<list<EdgeBase> lst> {
list<EdgeBase> edges = lst;
include "llvm/CompilerDriver/Common.td"
// And optionally:
// include "llvm/CompilerDriver/Tools.td"
- // which contains tool definitions.
+ // which contains some useful tool definitions.
Internally, LLVMC stores information about possible source
transformations in form of a graph. Nodes in this graph represent
``plugins/Base/Base.td`` for an example) is just a list of edges::
def CompilationGraph : CompilationGraph<[
- Edge<root, llvm_gcc_c>,
- Edge<root, llvm_gcc_assembler>,
+ Edge<"root", "llvm_gcc_c">,
+ Edge<"root", "llvm_gcc_assembler">,
...
- Edge<llvm_gcc_c, llc>,
- Edge<llvm_gcc_cpp, llc>,
+ Edge<"llvm_gcc_c", "llc">,
+ Edge<"llvm_gcc_cpp", "llc">,
...
- OptionalEdge<llvm_gcc_c, opt, [(switch_on "opt")]>,
- OptionalEdge<llvm_gcc_cpp, opt, [(switch_on "opt")]>,
+ OptionalEdge<"llvm_gcc_c", "opt", [(switch_on "opt")]>,
+ OptionalEdge<"llvm_gcc_cpp", "opt", [(switch_on "opt")]>,
...
- OptionalEdge<llvm_gcc_assembler, llvm_gcc_cpp_linker,
+ OptionalEdge<"llvm_gcc_assembler", "llvm_gcc_cpp_linker",
(case (input_languages_contain "c++"), (inc_weight),
(or (parameter_equals "linker", "g++"),
(parameter_equals "linker", "c++")), (inc_weight))>,
As you can see, the edges can be either default or optional, where
optional edges are differentiated by an additional ``case`` expression
-used to calculate the weight of this edge.
+used to calculate the weight of this edge. Notice also that we refer
+to tools via their names (as strings). This allows us to add edges to
+an existing compilation graph without having to include all tool
+definitions that it uses.
The default edges are assigned a weight of 1, and optional edges get a
weight of 0 + 2*N where N is the number of tests that evaluated to
def LanguageMap : LanguageMap<[LangToSuffixes<"c", ["c"]>]>;
// Compilation graph
- def CompilationGraph : CompilationGraph<[Edge<root, gcc>]>;
+ def CompilationGraph : CompilationGraph<[Edge<"root", "gcc">]>;
As you can see, this file consists of three parts: tool descriptions,
language map, and the compilation graph definition.
// Toolchains
def CompilationGraph : CompilationGraph<[
- Edge<root, llvm_gcc_c>,
- Edge<root, llvm_gcc_assembler>,
- Edge<root, llvm_gcc_cpp>,
- Edge<root, llvm_gcc_m>,
- Edge<root, llvm_gcc_mxx>,
- Edge<root, llvm_as>,
-
- Edge<llvm_gcc_c, llc>,
- Edge<llvm_gcc_cpp, llc>,
- Edge<llvm_gcc_m, llc>,
- Edge<llvm_gcc_mxx, llc>,
- Edge<llvm_as, llc>,
-
- OptionalEdge<llvm_gcc_c, opt, (case (switch_on "opt"), (inc_weight))>,
- OptionalEdge<llvm_gcc_cpp, opt, (case (switch_on "opt"), (inc_weight))>,
- OptionalEdge<llvm_gcc_m, opt, (case (switch_on "opt"), (inc_weight))>,
- OptionalEdge<llvm_gcc_mxx, opt, (case (switch_on "opt"), (inc_weight))>,
- OptionalEdge<llvm_as, opt, (case (switch_on "opt"), (inc_weight))>,
- Edge<opt, llc>,
-
- Edge<llc, llvm_gcc_assembler>,
- Edge<llvm_gcc_assembler, llvm_gcc_linker>,
- OptionalEdge<llvm_gcc_assembler, llvm_gcc_cpp_linker,
+ Edge<"root", "llvm_gcc_c">,
+ Edge<"root", "llvm_gcc_assembler">,
+ Edge<"root", "llvm_gcc_cpp">,
+ Edge<"root", "llvm_gcc_m">,
+ Edge<"root", "llvm_gcc_mxx">,
+ Edge<"root", "llvm_as">,
+
+ Edge<"llvm_gcc_c", "llc">,
+ Edge<"llvm_gcc_cpp", "llc">,
+ Edge<"llvm_gcc_m", "llc">,
+ Edge<"llvm_gcc_mxx", "llc">,
+ Edge<"llvm_as", "llc">,
+
+ OptionalEdge<"llvm_gcc_c", "opt", (case (switch_on "opt"), (inc_weight))>,
+ OptionalEdge<"llvm_gcc_cpp", "opt", (case (switch_on "opt"), (inc_weight))>,
+ OptionalEdge<"llvm_gcc_m", "opt", (case (switch_on "opt"), (inc_weight))>,
+ OptionalEdge<"llvm_gcc_mxx", "opt", (case (switch_on "opt"), (inc_weight))>,
+ OptionalEdge<"llvm_as", "opt", (case (switch_on "opt"), (inc_weight))>,
+ Edge<"opt", "llc">,
+
+ Edge<"llc", "llvm_gcc_assembler">,
+ Edge<"llvm_gcc_assembler", "llvm_gcc_linker">,
+ OptionalEdge<"llvm_gcc_assembler", "llvm_gcc_cpp_linker",
(case
(or (input_languages_contain "c++"),
- (input_languages_contain "objective-c++")),
+ (input_languages_contain "objective-c++")),
(inc_weight),
(or (parameter_equals "linker", "g++"),
(parameter_equals "linker", "c++")), (inc_weight))>,
- Edge<root, llvm_gcc_linker>,
- OptionalEdge<root, llvm_gcc_cpp_linker,
+ Edge<"root", "llvm_gcc_linker">,
+ OptionalEdge<"root", "llvm_gcc_cpp_linker",
(case
(or (input_languages_contain "c++"),
- (input_languages_contain "objective-c++")),
+ (input_languages_contain "objective-c++")),
(inc_weight),
(or (parameter_equals "linker", "g++"),
(parameter_equals "linker", "c++")), (inc_weight))>
// Compilation graph
def CompilationGraph : CompilationGraph<[
- Edge<root, clang_c>,
- Edge<root, clang_cpp>,
- Edge<root, clang_objective_c>,
- Edge<clang_c, llvm_ld>,
- Edge<clang_cpp, llvm_ld>,
- Edge<clang_objective_c, llvm_ld>
+ Edge<"root", "clang_c">,
+ Edge<"root", "clang_cpp">,
+ Edge<"root", "clang_objective_c">,
+ Edge<"clang_c", "llvm_ld">,
+ Edge<"clang_cpp", "llvm_ld">,
+ Edge<"clang_objective_c", "llvm_ld">
]>;
def LanguageMap : LanguageMap<[LangToSuffixes<"c", ["c"]>]>;
-def CompilationGraph : CompilationGraph<[Edge<root, gcc>]>;
+def CompilationGraph : CompilationGraph<[Edge<"root", "gcc">]>;
}
-/// CollectPropertiesFromOptionList - Gather information about
-/// *global* option properties from the OptionList.
-void CollectPropertiesFromOptionList (RecordVector::const_iterator B,
- RecordVector::const_iterator E,
- GlobalOptionDescriptions& OptDescs)
+/// CollectPropertiesFromOptionLists - Gather information about
+/// *global* option properties from all OptionLists.
+void CollectPropertiesFromOptionLists (RecordVector::const_iterator B,
+ RecordVector::const_iterator E,
+ GlobalOptionDescriptions& OptDescs)
{
// Iterate over a properties list of every Tool definition
for (;B!=E;++B) {
const GlobalOptionDescription& Val = B->second;
if (!nonSuperfluousOptions.count(Val.Name)
&& Val.Type != OptionType::Alias)
- cerr << "Warning: option '-" << Val.Name << "' has no effect! "
+ llvm::cerr << "Warning: option '-" << Val.Name << "' has no effect! "
"Probable cause: this option is specified only in the OptionList.\n";
}
}
/// EmitPopulateLanguageMap - Emit the PopulateLanguageMap() function.
void EmitPopulateLanguageMap (const RecordKeeper& Records, std::ostream& O)
{
+ // Generate code
+ O << "namespace {\n\n";
+ O << "void PopulateLanguageMapLocal(LanguageMap& langMap) {\n";
+
// Get the relevant field out of RecordKeeper
Record* LangMapRecord = Records.getDef("LanguageMap");
- if (!LangMapRecord)
- throw std::string("Language map definition not found!");
- ListInit* LangsToSuffixesList = LangMapRecord->getValueAsListInit("map");
- if (!LangsToSuffixesList)
- throw std::string("Error in the language map definition!");
+ // It is allowed for a plugin to have no language map.
+ if (LangMapRecord) {
- // Generate code
- O << "namespace {\n\n";
- O << "void PopulateLanguageMapLocal(LanguageMap& langMap) {\n";
+ ListInit* LangsToSuffixesList = LangMapRecord->getValueAsListInit("map");
+ if (!LangsToSuffixesList)
+ throw std::string("Error in the language map definition!");
- for (unsigned i = 0; i < LangsToSuffixesList->size(); ++i) {
- Record* LangToSuffixes = LangsToSuffixesList->getElementAsRecord(i);
+ for (unsigned i = 0; i < LangsToSuffixesList->size(); ++i) {
+ Record* LangToSuffixes = LangsToSuffixesList->getElementAsRecord(i);
- const std::string& Lang = LangToSuffixes->getValueAsString("lang");
- const ListInit* Suffixes = LangToSuffixes->getValueAsListInit("suffixes");
+ const std::string& Lang = LangToSuffixes->getValueAsString("lang");
+ const ListInit* Suffixes = LangToSuffixes->getValueAsListInit("suffixes");
- for (unsigned i = 0; i < Suffixes->size(); ++i)
- O << Indent1 << "langMap[\""
- << InitPtrToString(Suffixes->getElement(i))
- << "\"] = \"" << Lang << "\";\n";
+ for (unsigned i = 0; i < Suffixes->size(); ++i)
+ O << Indent1 << "langMap[\""
+ << InitPtrToString(Suffixes->getElement(i))
+ << "\"] = \"" << Lang << "\";\n";
+ }
}
O << "}\n\n}\n\n";
}
/// TypecheckGraph - Check that names for output and input languages
-/// on all edges do match.
-// TOFIX: It would be nice if this function also checked for cycles
-// and multiple default edges in the graph (better error
-// reporting). Unfortunately, it is awkward to do right now because
-// our intermediate representation is not sufficiently
-// sophisticated. Algorithms like these require a real graph instead of
-// an AST.
+/// on all edges do match. This doesn't do much when the information
+/// about the whole graph is not available (i.e. when compiling most
+/// plugins).
+// TODO: add a --check-graph switch to llvmc2. It would also make it
+// possible to detect cycles and multiple default edges.
void TypecheckGraph (Record* CompilationGraph,
const ToolPropertiesList& TPList) {
StringMap<StringSet<> > ToolToInLang;
for (unsigned i = 0; i < edges->size(); ++i) {
Record* Edge = edges->getElementAsRecord(i);
- Record* A = Edge->getValueAsDef("a");
- Record* B = Edge->getValueAsDef("b");
- StringMap<std::string>::iterator IA = ToolToOutLang.find(A->getName());
- StringMap<StringSet<> >::iterator IB = ToolToInLang.find(B->getName());
- if (IA == IAE)
- throw A->getName() + ": no such tool!";
- if (IB == IBE)
- throw B->getName() + ": no such tool!";
- if (A->getName() != "root" && IB->second.count(IA->second) == 0)
- throw "Edge " + A->getName() + "->" + B->getName()
- + ": output->input language mismatch";
- if (B->getName() == "root")
+ const std::string& A = Edge->getValueAsString("a");
+ const std::string& B = Edge->getValueAsString("b");
+ StringMap<std::string>::iterator IA = ToolToOutLang.find(A);
+ StringMap<StringSet<> >::iterator IB = ToolToInLang.find(B);
+
+ if (A != "root") {
+ if (IA != IAE && IB != IBE && IB->second.count(IA->second) == 0)
+ throw "Edge " + A + "->" + B
+ + ": output->input language mismatch";
+ }
+
+ if (B == "root")
throw std::string("Edges back to the root are not allowed!");
}
}
for (unsigned i = 0; i < edges->size(); ++i) {
Record* Edge = edges->getElementAsRecord(i);
- Record* B = Edge->getValueAsDef("b");
+ const std::string& B = Edge->getValueAsString("b");
DagInit* Weight = Edge->getValueAsDag("weight");
if (isDagEmpty(Weight))
continue;
- EmitEdgeClass(i, B->getName(), Weight, OptDescs, O);
+ EmitEdgeClass(i, B, Weight, OptDescs, O);
}
}
for (unsigned i = 0; i < edges->size(); ++i) {
Record* Edge = edges->getElementAsRecord(i);
- Record* A = Edge->getValueAsDef("a");
- Record* B = Edge->getValueAsDef("b");
+ const std::string& A = Edge->getValueAsString("a");
+ const std::string& B = Edge->getValueAsString("b");
- if (A->getName() != "root")
- ToolsInGraph.insert(A->getName());
- if (B->getName() != "root")
- ToolsInGraph.insert(B->getName());
+ if (A != "root")
+ ToolsInGraph.insert(A);
+ ToolsInGraph.insert(B);
}
for (llvm::StringSet<>::iterator B = ToolsInGraph.begin(),
for (unsigned i = 0; i < edges->size(); ++i) {
Record* Edge = edges->getElementAsRecord(i);
- Record* A = Edge->getValueAsDef("a");
- Record* B = Edge->getValueAsDef("b");
+ const std::string& A = Edge->getValueAsString("a");
+ const std::string& B = Edge->getValueAsString("b");
DagInit* Weight = Edge->getValueAsDag("weight");
- O << Indent1 << "G.insertEdge(\"" << A->getName() << "\", ";
+ O << Indent1 << "G.insertEdge(\"" << A << "\", ";
if (isDagEmpty(Weight))
- O << "new SimpleEdge(\"" << B->getName() << "\")";
+ O << "new SimpleEdge(\"" << B << "\")";
else
O << "new Edge" << i << "()";
EmitIncludes(O);
// Get a list of all defined Tools.
+
RecordVector Tools = Records.getAllDerivedDefinitions("Tool");
if (Tools.empty())
throw std::string("No tool definitions found!");
CollectToolProperties(Tools.begin(), Tools.end(), tool_props, opt_descs);
RecordVector OptionLists = Records.getAllDerivedDefinitions("OptionList");
- CollectPropertiesFromOptionList(OptionLists.begin(), OptionLists.end(),
- opt_descs);
+ CollectPropertiesFromOptionLists(OptionLists.begin(), OptionLists.end(),
+ opt_descs);
// Check that there are no options without side effects (specified
// only in the OptionList).
E = tool_props.end(); B!=E; ++B)
EmitToolClassDefinition(*(*B), opt_descs, O);
+ // TOTHINK: Nothing actually prevents us from having multiple
+ // compilation graphs in a single plugin; OTOH, I do not see how
+ // that could be useful.
Record* CompilationGraphRecord = Records.getDef("CompilationGraph");
if (!CompilationGraphRecord)
throw std::string("Compilation graph description not found!");