Make it possible to have multiple input languages for a single tool.

llvm-svn: 51742
This commit is contained in:
Mikhail Glushenkov 2008-05-30 06:18:16 +00:00
parent 73d708b82c
commit 1f7a028929
4 changed files with 93 additions and 41 deletions

View File

@ -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<Edge>(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<Edge>(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<typename EdgeIter>
static std::string getEdgeSourceLabel(const Node* N, EdgeIter I) {
if (N->ToolPtr)
if (N->ToolPtr) {
return N->ToolPtr->OutputLanguage();
}
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
return I->ToolPtr->InputLanguage();
ret += *B;
}
return ret;
}
}
};

View File

@ -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;

View File

@ -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",

View File

@ -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 <algorithm>
@ -53,17 +54,22 @@ const char * SinkOptionName = "AutoGeneratedSinkOption";
//===----------------------------------------------------------------------===//
/// Helper functions
const std::string& InitPtrToString(const Init* ptr) {
const StringInit& val = dynamic_cast<const StringInit&>(*ptr);
return val.getValue();
}
int InitPtrToInt(const Init* ptr) {
const IntInit& val = dynamic_cast<const IntInit&>(*ptr);
return val.getValue();
}
const DagInit& InitPtrToDagInitRef(const Init* ptr) {
const std::string& InitPtrToString(const Init* ptr) {
const StringInit& val = dynamic_cast<const StringInit&>(*ptr);
return val.getValue();
}
const ListInit& InitPtrToList(const Init* ptr) {
const ListInit& val = dynamic_cast<const ListInit&>(*ptr);
return val;
}
const DagInit& InitPtrToDag(const Init* ptr) {
const DagInit& val = dynamic_cast<const DagInit&>(*ptr);
return val;
}
@ -308,7 +314,7 @@ namespace ToolFlags {
struct ToolProperties : public RefCountedBase<ToolProperties> {
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<std::string>& ToolToInLang,
StringMap<StringSet<> >& ToolToInLang,
StringMap<std::string>& 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<std::string> ToolToInLang;
StringMap<StringSet<> > ToolToInLang;
StringMap<std::string> ToolToOutLang;
FillInToolToLang(TPList, ToolToInLang, ToolToOutLang);
ListInit* edges = CompilationGraph->getValueAsListInit("edges");
StringMap<std::string>::iterator IAE = ToolToInLang.end();
StringMap<std::string>::iterator IBE = ToolToOutLang.end();
StringMap<std::string>::iterator IAE = ToolToOutLang.end();
StringMap<StringSet<> >::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<std::string>::iterator IA = ToolToOutLang.find(A->getName());
StringMap<std::string>::iterator IB = ToolToInLang.find(B->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" && 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) {