summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/llvm/CompilerDriver/Tool.h2
-rw-r--r--lib/CompilerDriver/CompilationGraph.cpp58
-rw-r--r--test/LLVMC/MultipleOutputLanguages.td27
-rw-r--r--utils/TableGen/LLVMCConfigurationEmitter.cpp96
4 files changed, 124 insertions, 59 deletions
diff --git a/include/llvm/CompilerDriver/Tool.h b/include/llvm/CompilerDriver/Tool.h
index 45ef50d0b5..7316dfdcab 100644
--- a/include/llvm/CompilerDriver/Tool.h
+++ b/include/llvm/CompilerDriver/Tool.h
@@ -58,7 +58,7 @@ namespace llvmc {
virtual const char* Name() const = 0;
virtual const char** InputLanguages() const = 0;
- virtual const char* OutputLanguage() const = 0;
+ virtual const char** OutputLanguages() const = 0;
virtual bool IsJoin() const = 0;
virtual bool WorksOnEmpty() const = 0;
diff --git a/lib/CompilerDriver/CompilationGraph.cpp b/lib/CompilerDriver/CompilationGraph.cpp
index 0aecfa6a9d..87a2c4817a 100644
--- a/lib/CompilerDriver/CompilationGraph.cpp
+++ b/lib/CompilerDriver/CompilationGraph.cpp
@@ -440,13 +440,17 @@ int CompilationGraph::CheckLanguageNames() const {
continue;
}
- const char* OutLang = N1.ToolPtr->OutputLanguage();
+ const char** OutLangs = N1.ToolPtr->OutputLanguages();
const char** InLangs = N2->ToolPtr->InputLanguages();
bool eq = false;
- for (;*InLangs; ++InLangs) {
- if (std::strcmp(OutLang, *InLangs) == 0) {
- eq = true;
- break;
+ const char* OutLang = 0;
+ for (;*OutLangs; ++OutLangs) {
+ OutLang = *OutLangs;
+ for (;*InLangs; ++InLangs) {
+ if (std::strcmp(OutLang, *InLangs) == 0) {
+ eq = true;
+ break;
+ }
}
}
@@ -481,7 +485,7 @@ int CompilationGraph::CheckMultipleDefaultEdges() const {
for (const_nodes_iterator B = this->NodesMap.begin(),
E = this->NodesMap.end(); B != E; ++B) {
const Node& N = B->second;
- int MaxWeight = 0;
+ int MaxWeight = -1024;
// Ignore the root node.
if (!N.ToolPtr)
@@ -573,6 +577,26 @@ int CompilationGraph::Check () {
// Code related to graph visualization.
+namespace {
+
+std::string SquashStrArray (const char** StrArr) {
+ std::string ret;
+
+ for (; *StrArr; ++StrArr) {
+ if (*(StrArr + 1)) {
+ ret += *StrArr;
+ ret += ", ";
+ }
+ else {
+ ret += *StrArr;
+ }
+ }
+
+ return ret;
+}
+
+} // End anonymous namespace.
+
namespace llvm {
template <>
struct DOTGraphTraits<llvmc::CompilationGraph*>
@@ -587,7 +611,8 @@ namespace llvm {
if (N->ToolPtr->IsJoin())
return N->Name() + "\n (join" +
(N->HasChildren() ? ")"
- : std::string(": ") + N->ToolPtr->OutputLanguage() + ')');
+ : std::string(": ") +
+ SquashStrArray(N->ToolPtr->OutputLanguages()) + ')');
else
return N->Name();
else
@@ -597,28 +622,15 @@ namespace llvm {
template<typename EdgeIter>
static std::string getEdgeSourceLabel(const Node* N, EdgeIter I) {
if (N->ToolPtr) {
- return N->ToolPtr->OutputLanguage();
+ return SquashStrArray(N->ToolPtr->OutputLanguages());
}
else {
- const char** InLangs = I->ToolPtr->InputLanguages();
- std::string ret;
-
- for (; *InLangs; ++InLangs) {
- if (*(InLangs + 1)) {
- ret += *InLangs;
- ret += ", ";
- }
- else {
- ret += *InLangs;
- }
- }
-
- return ret;
+ return SquashStrArray(I->ToolPtr->InputLanguages());
}
}
};
-}
+} // End namespace llvm
int CompilationGraph::writeGraph(const std::string& OutputFilename) {
std::string ErrorInfo;
diff --git a/test/LLVMC/MultipleOutputLanguages.td b/test/LLVMC/MultipleOutputLanguages.td
new file mode 100644
index 0000000000..02512c2db7
--- /dev/null
+++ b/test/LLVMC/MultipleOutputLanguages.td
@@ -0,0 +1,27 @@
+// Check that multiple output languages work.
+// RUN: tblgen -I %p/../../include --gen-llvmc %s -o %t
+// RUN: FileCheck -input-file %t %s
+// RUN: %compile_cxx %t
+// XFAIL: vg_leak
+
+include "llvm/CompilerDriver/Common.td"
+
+def dummy_tool : Tool<[
+ (command "dummy_cmd"),
+ (in_language "dummy_lang"),
+ (out_language ["another_dummy_lang", "yet_another_dummy_lang"])
+]>;
+
+def another_dummy_tool : Tool<[
+ (command "another_dummy_cmd"),
+ (in_language ["another_dummy_lang", "some_other_dummy_lang"]),
+ (out_language "executable"),
+ (join)
+]>;
+
+// CHECK: new SimpleEdge("dummy_tool")
+// CHECK: new SimpleEdge("another_dummy_tool")
+def DummyGraph : CompilationGraph<[
+ (edge "root", "dummy_tool"),
+ (edge "dummy_tool", "another_dummy_tool")
+]>;
diff --git a/utils/TableGen/LLVMCConfigurationEmitter.cpp b/utils/TableGen/LLVMCConfigurationEmitter.cpp
index 8b81e14cc2..7ad981f4e4 100644
--- a/utils/TableGen/LLVMCConfigurationEmitter.cpp
+++ b/utils/TableGen/LLVMCConfigurationEmitter.cpp
@@ -833,7 +833,7 @@ struct ToolDescription : public RefCountedBase<ToolDescription> {
StrVector InLanguage;
std::string InFileOption;
std::string OutFileOption;
- std::string OutLanguage;
+ StrVector OutLanguage;
std::string OutputSuffix;
unsigned Flags;
const Init* OnEmpty;
@@ -919,41 +919,43 @@ private:
toolDesc_.CmdLine = d.getArg(0);
}
- void onInLanguage (const DagInit& d) {
+ /// onInOutLanguage - Common implementation of on{In,Out}Language().
+ void onInOutLanguage (const DagInit& d, StrVector& OutVec) {
CheckNumberOfArguments(d, 1);
Init* arg = d.getArg(0);
// Find out the argument's type.
if (typeid(*arg) == typeid(StringInit)) {
// It's a string.
- toolDesc_.InLanguage.push_back(InitPtrToString(arg));
+ OutVec.push_back(InitPtrToString(arg));
}
else {
// It's a list.
const ListInit& lst = InitPtrToList(arg);
- StrVector& out = toolDesc_.InLanguage;
// Copy strings to the output vector.
- for (ListInit::const_iterator B = lst.begin(), E = lst.end();
- B != E; ++B) {
- out.push_back(InitPtrToString(*B));
- }
+ for (ListInit::const_iterator B = lst.begin(), E = lst.end(); B != E; ++B)
+ OutVec.push_back(InitPtrToString(*B));
// Remove duplicates.
- std::sort(out.begin(), out.end());
- StrVector::iterator newE = std::unique(out.begin(), out.end());
- out.erase(newE, out.end());
+ std::sort(OutVec.begin(), OutVec.end());
+ StrVector::iterator newE = std::unique(OutVec.begin(), OutVec.end());
+ OutVec.erase(newE, OutVec.end());
}
}
+
+ void onInLanguage (const DagInit& d) {
+ this->onInOutLanguage(d, toolDesc_.InLanguage);
+ }
+
void onJoin (const DagInit& d) {
CheckNumberOfArguments(d, 0);
toolDesc_.setJoin();
}
void onOutLanguage (const DagInit& d) {
- CheckNumberOfArguments(d, 1);
- toolDesc_.OutLanguage = InitPtrToString(d.getArg(0));
+ this->onInOutLanguage(d, toolDesc_.OutLanguage);
}
void onOutFileOption (const DagInit& d) {
@@ -1062,47 +1064,62 @@ void FilterNotInGraph (const DagVector& EdgeVector,
}
/// FillInToolToLang - Fills in two tables that map tool names to
-/// (input, output) languages. Helper function used by TypecheckGraph().
+/// input & output language names. Helper function used by TypecheckGraph().
void FillInToolToLang (const ToolDescriptions& ToolDescs,
StringMap<StringSet<> >& ToolToInLang,
- StringMap<std::string>& ToolToOutLang) {
+ StringMap<StringSet<> >& ToolToOutLang) {
for (ToolDescriptions::const_iterator B = ToolDescs.begin(),
E = ToolDescs.end(); B != E; ++B) {
const ToolDescription& D = *(*B);
for (StrVector::const_iterator B = D.InLanguage.begin(),
E = D.InLanguage.end(); B != E; ++B)
ToolToInLang[D.Name].insert(*B);
- ToolToOutLang[D.Name] = D.OutLanguage;
+ for (StrVector::const_iterator B = D.OutLanguage.begin(),
+ E = D.OutLanguage.end(); B != E; ++B)
+ ToolToOutLang[D.Name].insert(*B);
}
}
+/// Intersect - Is set intersection non-empty?
+bool Intersect (const StringSet<>& S1, const StringSet<>& S2) {
+ for (StringSet<>::const_iterator B = S1.begin(), E = S1.end(); B != E; ++B) {
+ if (S2.count(B->first()) != 0)
+ return true;
+ }
+ return false;
+}
+
/// TypecheckGraph - Check that names for output and input languages
/// on all edges do match.
void TypecheckGraph (const DagVector& EdgeVector,
const ToolDescriptions& ToolDescs) {
StringMap<StringSet<> > ToolToInLang;
- StringMap<std::string> ToolToOutLang;
+ StringMap<StringSet<> > ToolToOutLang;
FillInToolToLang(ToolDescs, ToolToInLang, ToolToOutLang);
- StringMap<std::string>::iterator IAE = ToolToOutLang.end();
- StringMap<StringSet<> >::iterator IBE = ToolToInLang.end();
for (DagVector::const_iterator B = EdgeVector.begin(),
E = EdgeVector.end(); B != E; ++B) {
const DagInit* Edge = *B;
const std::string& NodeA = InitPtrToString(Edge->getArg(0));
const std::string& NodeB = InitPtrToString(Edge->getArg(1));
- StringMap<std::string>::iterator IA = ToolToOutLang.find(NodeA);
+ StringMap<StringSet<> >::iterator IA = ToolToOutLang.find(NodeA);
StringMap<StringSet<> >::iterator IB = ToolToInLang.find(NodeB);
+ if (NodeB == "root")
+ throw "Edges back to the root are not allowed!";
+
if (NodeA != "root") {
- if (IA != IAE && IB != IBE && IB->second.count(IA->second) == 0)
+ if (IA == ToolToOutLang.end())
+ throw NodeA + ": no output language defined!";
+ if (IB == ToolToInLang.end())
+ throw NodeB + ": no input language defined!";
+
+ if (!Intersect(IA->second, IB->second)) {
throw "Edge " + NodeA + "->" + NodeB
+ ": output->input language mismatch";
+ }
}
-
- if (NodeB == "root")
- throw "Edges back to the root are not allowed!";
}
}
@@ -2250,11 +2267,8 @@ void EmitInOutLanguageMethods (const ToolDescription& D, raw_ostream& O) {
O.indent(Indent2) << "return InputLanguages_;\n";
O.indent(Indent1) << "}\n\n";
- if (D.OutLanguage.empty())
- throw "Tool " + D.Name + " has no 'out_language' property!";
-
- O.indent(Indent1) << "const char* OutputLanguage() const {\n";
- O.indent(Indent2) << "return \"" << D.OutLanguage << "\";\n";
+ O.indent(Indent1) << "const char** OutputLanguages() const {\n";
+ O.indent(Indent2) << "return OutputLanguages_;\n";
O.indent(Indent1) << "}\n\n";
}
@@ -2299,17 +2313,28 @@ void EmitWorksOnEmptyMethod (const ToolDescription& D,
O.indent(Indent1) << "}\n\n";
}
+/// EmitStrArray - Emit definition of a 'const char**' static member
+/// variable. Helper used by EmitStaticMemberDefinitions();
+void EmitStrArray(const std::string& Name, const std::string& VarName,
+ const StrVector& StrVec, raw_ostream& O) {
+ O << "const char* " << Name << "::" << VarName << "[] = {";
+ for (StrVector::const_iterator B = StrVec.begin(), E = StrVec.end();
+ B != E; ++B)
+ O << '\"' << *B << "\", ";
+ O << "0};\n";
+}
+
/// EmitStaticMemberDefinitions - Emit static member definitions for a
/// given Tool class.
void EmitStaticMemberDefinitions(const ToolDescription& D, raw_ostream& O) {
if (D.InLanguage.empty())
throw "Tool " + D.Name + " has no 'in_language' property!";
+ if (D.OutLanguage.empty())
+ throw "Tool " + D.Name + " has no 'out_language' property!";
- O << "const char* " << D.Name << "::InputLanguages_[] = {";
- for (StrVector::const_iterator B = D.InLanguage.begin(),
- E = D.InLanguage.end(); B != E; ++B)
- O << '\"' << *B << "\", ";
- O << "0};\n\n";
+ EmitStrArray(D.Name, "InputLanguages_", D.InLanguage, O);
+ EmitStrArray(D.Name, "OutputLanguages_", D.OutLanguage, O);
+ O << '\n';
}
/// EmitToolClassDefinition - Emit a Tool class definition.
@@ -2327,7 +2352,8 @@ void EmitToolClassDefinition (const ToolDescription& D,
O << "Tool";
O << " {\nprivate:\n";
- O.indent(Indent1) << "static const char* InputLanguages_[];\n\n";
+ O.indent(Indent1) << "static const char* InputLanguages_[];\n";
+ O.indent(Indent1) << "static const char* OutputLanguages_[];\n\n";
O << "public:\n";
EmitNameMethod(D, O);