From 1f7a0289297732f420a6261a9ae42a215c52bbc0 Mon Sep 17 00:00:00 2001 From: Mikhail Glushenkov Date: Fri, 30 May 2008 06:18:16 +0000 Subject: [PATCH] Make it possible to have multiple input languages for a single tool. llvm-svn: 51742 --- llvm/tools/llvmc2/CompilationGraph.cpp | 33 +++++-- llvm/tools/llvmc2/Tool.h | 2 +- llvm/tools/llvmc2/examples/Clang.td | 6 +- .../TableGen/LLVMCConfigurationEmitter.cpp | 93 +++++++++++++------ 4 files changed, 93 insertions(+), 41 deletions(-) diff --git a/llvm/tools/llvmc2/CompilationGraph.cpp b/llvm/tools/llvmc2/CompilationGraph.cpp index bf34b333d6d6..92f3104c018a 100644 --- a/llvm/tools/llvmc2/CompilationGraph.cpp +++ b/llvm/tools/llvmc2/CompilationGraph.cpp @@ -115,16 +115,18 @@ void CompilationGraph::insertNode(Tool* V) { } } -void CompilationGraph::insertEdge(const std::string& A, Edge* E) { - Node& B = getNode(E->ToolName()); +void CompilationGraph::insertEdge(const std::string& A, Edge* Edg) { + Node& B = getNode(Edg->ToolName()); if (A == "root") { - const std::string& InputLanguage = B.ToolPtr->InputLanguage(); - ToolsMap[InputLanguage].push_back(IntrusiveRefCntPtr(E)); - NodesMap["root"].AddEdge(E); + const StrVector& InputLanguages = B.ToolPtr->InputLanguages(); + for (StrVector::const_iterator B = InputLanguages.begin(), + E = InputLanguages.end(); B != E; ++B) + ToolsMap[*B].push_back(IntrusiveRefCntPtr(Edg)); + NodesMap["root"].AddEdge(Edg); } else { Node& N = getNode(A); - N.AddEdge(E); + N.AddEdge(Edg); } // Increase the inward edge counter. B.IncrInEdges(); @@ -381,10 +383,23 @@ namespace llvm { template static std::string getEdgeSourceLabel(const Node* N, EdgeIter I) { - if (N->ToolPtr) + if (N->ToolPtr) { return N->ToolPtr->OutputLanguage(); - else - return I->ToolPtr->InputLanguage(); + } + else { + const StrVector& InputLanguages = I->ToolPtr->InputLanguages(); + std::string ret; + + for (StrVector::const_iterator B = InputLanguages.begin(), + E = InputLanguages.end(); B != E; ++B) { + if (llvm::next(B) != E) + ret += *B + ", "; + else + ret += *B; + } + + return ret; + } } }; diff --git a/llvm/tools/llvmc2/Tool.h b/llvm/tools/llvmc2/Tool.h index 294c6fb9b3b9..ec9d1546ffd8 100644 --- a/llvm/tools/llvmc2/Tool.h +++ b/llvm/tools/llvmc2/Tool.h @@ -43,7 +43,7 @@ namespace llvmc { const InputLanguagesSet& InLangs) const = 0; virtual const char* Name() const = 0; - virtual const char* InputLanguage() const = 0; + virtual StrVector InputLanguages() const = 0; virtual const char* OutputLanguage() const = 0; virtual const char* OutputSuffix() const = 0; diff --git a/llvm/tools/llvmc2/examples/Clang.td b/llvm/tools/llvmc2/examples/Clang.td index 45ee63891c8a..c06737238b3b 100644 --- a/llvm/tools/llvmc2/examples/Clang.td +++ b/llvm/tools/llvmc2/examples/Clang.td @@ -4,12 +4,8 @@ include "Common.td" -// TOFIX: It should be possible to use a string list in the 'in_language' -// tool property. There should be also an 'in_language' test in the -// 'case' construct. - def clang : Tool< -[(in_language "c"), +[(in_language ["c", "c++", "objective-c"]), (out_language "llvm-bitcode"), (output_suffix "bc"), (cmd_line (case (switch_on "E"), "clang -E $INFILE -o $OUTFILE", diff --git a/llvm/utils/TableGen/LLVMCConfigurationEmitter.cpp b/llvm/utils/TableGen/LLVMCConfigurationEmitter.cpp index d3ad22c34a61..68548d62b7c8 100644 --- a/llvm/utils/TableGen/LLVMCConfigurationEmitter.cpp +++ b/llvm/utils/TableGen/LLVMCConfigurationEmitter.cpp @@ -18,6 +18,7 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringSet.h" #include "llvm/Support/Streams.h" #include @@ -53,17 +54,22 @@ const char * SinkOptionName = "AutoGeneratedSinkOption"; //===----------------------------------------------------------------------===// /// Helper functions -const std::string& InitPtrToString(const Init* ptr) { - const StringInit& val = dynamic_cast(*ptr); - return val.getValue(); -} - int InitPtrToInt(const Init* ptr) { const IntInit& val = dynamic_cast(*ptr); return val.getValue(); } -const DagInit& InitPtrToDagInitRef(const Init* ptr) { +const std::string& InitPtrToString(const Init* ptr) { + const StringInit& val = dynamic_cast(*ptr); + return val.getValue(); +} + +const ListInit& InitPtrToList(const Init* ptr) { + const ListInit& val = dynamic_cast(*ptr); + return val; +} + +const DagInit& InitPtrToDag(const Init* ptr) { const DagInit& val = dynamic_cast(*ptr); return val; } @@ -308,7 +314,7 @@ namespace ToolFlags { struct ToolProperties : public RefCountedBase { std::string Name; Init* CmdLine; - std::string InLanguage; + StrVector InLanguage; std::string OutLanguage; std::string OutputSuffix; unsigned Flags; @@ -412,7 +418,7 @@ public: /// operator() - Gets called for every tool property; Just forwards /// to the corresponding property handler. void operator() (Init* i) { - const DagInit& d = InitPtrToDagInitRef(i); + const DagInit& d = InitPtrToDag(i); const std::string& property_name = d.getOperator()->getAsString(); PropertyHandlerMap::iterator method = propertyHandlers_.find(property_name); @@ -439,7 +445,29 @@ private: void onInLanguage (const DagInit* d) { checkNumberOfArguments(d, 1); - toolProps_.InLanguage = InitPtrToString(d->getArg(0)); + Init* arg = d->getArg(0); + + // Find out the argument's type. + if (typeid(*arg) == typeid(StringInit)) { + // It's a string. + toolProps_.InLanguage.push_back(InitPtrToString(arg)); + } + else { + // It's a list. + const ListInit& lst = InitPtrToList(arg); + StrVector& out = toolProps_.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)); + } + + // Remove duplicates. + std::sort(out.begin(), out.end()); + StrVector::iterator newE = std::unique(out.begin(), out.end()); + out.erase(newE, out.end()); + } } void onJoin (const DagInit* d) { @@ -573,7 +601,7 @@ private: for (unsigned B = 1, E = d->getNumArgs(); B!=E; ++B) { const DagInit& option_property - = InitPtrToDagInitRef(d->getArg(B)); + = InitPtrToDag(d->getArg(B)); const std::string& option_property_name = option_property.getOperator()->getAsString(); OptionPropertyHandlerMap::iterator method @@ -691,7 +719,7 @@ void EmitLogicalOperationTest(const DagInit& d, const char* LogicOp, std::ostream& O) { O << '('; for (unsigned j = 0, NumArgs = d.getNumArgs(); j < NumArgs; ++j) { - const DagInit& InnerTest = InitPtrToDagInitRef(d.getArg(j)); + const DagInit& InnerTest = InitPtrToDag(d.getArg(j)); EmitCaseTest(InnerTest, IndentLevel, OptDescs, O); if (j != NumArgs - 1) O << ")\n" << IndentLevel << Indent1 << ' ' << LogicOp << " ("; @@ -736,7 +764,7 @@ void EmitCaseConstructHandler(const DagInit* d, const char* IndentLevel, + d->getAsString(); for (unsigned i = 0; i != numArgs; ++i) { - const DagInit& Test = InitPtrToDagInitRef(d->getArg(i)); + const DagInit& Test = InitPtrToDag(d->getArg(i)); // Emit the test. if (Test.getOperator()->getAsString() == "default") { @@ -996,7 +1024,7 @@ void EmitGenerateActionMethod (const ToolProperties& P, if (typeid(*P.CmdLine) == typeid(StringInit)) EmitCmdLineVecFill(P.CmdLine, P.Name, Version, Indent2, O); else - EmitCaseConstructHandler(&InitPtrToDagInitRef(P.CmdLine), Indent2, + EmitCaseConstructHandler(&InitPtrToDag(P.CmdLine), Indent2, EmitCmdLineVecFillCallback(Version, P.Name), true, OptDescs, O); @@ -1061,8 +1089,15 @@ void EmitIsLastMethod (const ToolProperties& P, std::ostream& O) { /// EmitInOutLanguageMethods - Emit the [Input,Output]Language() /// methods for a given Tool class. void EmitInOutLanguageMethods (const ToolProperties& P, std::ostream& O) { - O << Indent1 << "const char* InputLanguage() const {\n" - << Indent2 << "return \"" << P.InLanguage << "\";\n" + O << Indent1 << "StrVector InputLanguages() const {\n" + << Indent2 << "StrVector ret;\n"; + + for (StrVector::const_iterator B = P.InLanguage.begin(), + E = P.InLanguage.end(); B != E; ++B) { + O << Indent2 << "ret.push_back(\"" << *B << "\");\n"; + } + + O << Indent2 << "return ret;\n" << Indent1 << "}\n\n"; O << Indent1 << "const char* OutputLanguage() const {\n" @@ -1207,41 +1242,47 @@ void EmitPopulateLanguageMap (const RecordKeeper& Records, std::ostream& O) /// FillInToolToLang - Fills in two tables that map tool names to /// (input, output) languages. Used by the typechecker. void FillInToolToLang (const ToolPropertiesList& TPList, - StringMap& ToolToInLang, + StringMap >& ToolToInLang, StringMap& ToolToOutLang) { for (ToolPropertiesList::const_iterator B = TPList.begin(), E = TPList.end(); B != E; ++B) { const ToolProperties& P = *(*B); - ToolToInLang[P.Name] = P.InLanguage; + for (StrVector::const_iterator B = P.InLanguage.begin(), + E = P.InLanguage.end(); B != E; ++B) + ToolToInLang[P.Name].insert(*B); ToolToOutLang[P.Name] = P.OutLanguage; } } /// TypecheckGraph - Check that names for output and input languages /// on all edges do match. -// TOFIX: check for cycles. -// TOFIX: check for multiple default edges. +// 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 +// sofisticated. Algorithms like these should be run on a real graph +// instead of AST. void TypecheckGraph (Record* CompilationGraph, const ToolPropertiesList& TPList) { - StringMap ToolToInLang; + StringMap > ToolToInLang; StringMap ToolToOutLang; FillInToolToLang(TPList, ToolToInLang, ToolToOutLang); ListInit* edges = CompilationGraph->getValueAsListInit("edges"); - StringMap::iterator IAE = ToolToInLang.end(); - StringMap::iterator IBE = ToolToOutLang.end(); + StringMap::iterator IAE = ToolToOutLang.end(); + StringMap >::iterator IBE = ToolToInLang.end(); for (unsigned i = 0; i < edges->size(); ++i) { Record* Edge = edges->getElementAsRecord(i); Record* A = Edge->getValueAsDef("a"); Record* B = Edge->getValueAsDef("b"); StringMap::iterator IA = ToolToOutLang.find(A->getName()); - StringMap::iterator IB = ToolToInLang.find(B->getName()); + StringMap >::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" && IA->second != IB->second) + if (A->getName() != "root" && IB->second.count(IA->second) == 0) throw "Edge " + A->getName() + "->" + B->getName() + ": output->input language mismatch"; if (B->getName() == "root") @@ -1253,7 +1294,7 @@ void TypecheckGraph (Record* CompilationGraph, /// by EmitEdgeClass(). void IncDecWeight (const Init* i, const char* IndentLevel, std::ostream& O) { - const DagInit& d = InitPtrToDagInitRef(i); + const DagInit& d = InitPtrToDag(i); const std::string& OpName = d.getOperator()->getAsString(); if (OpName == "inc_weight") @@ -1389,7 +1430,7 @@ void FillInHookNames(const ToolPropertiesList& TPList, } else { // This is a 'case' construct. - const DagInit& d = InitPtrToDagInitRef(P.CmdLine); + const DagInit& d = InitPtrToDag(P.CmdLine); bool even = false; for (DagInit::const_arg_iterator B = d.arg_begin(), E = d.arg_end(); B != E; ++B) {