#include <string>
#include <typeinfo>
+
using namespace llvm;
namespace {
/// Typedefs
typedef std::vector<Record*> RecordVector;
+typedef std::vector<const DagInit*> DagVector;
typedef std::vector<std::string> StrVector;
//===----------------------------------------------------------------------===//
const char * const DefaultHelpString = "NO HELP MESSAGE PROVIDED";
// Name for the "sink" option.
-const char * const SinkOptionName = "AutoGeneratedSinkOption";
+const char * const SinkOptionName = "SinkOption";
//===----------------------------------------------------------------------===//
/// Helper functions
return val.getValue();
}
+bool InitPtrToBool(const Init* ptr) {
+ bool ret = false;
+ const DefInit& val = dynamic_cast<const DefInit&>(*ptr);
+ const std::string& str = val.getAsString();
+
+ if (str == "true") {
+ ret = true;
+ }
+ else if (str == "false") {
+ ret = false;
+ }
+ else {
+ throw "Incorrect boolean value: '" + str +
+ "': must be either 'true' or 'false'";
+ }
+
+ return ret;
+}
+
const std::string& InitPtrToString(const Init* ptr) {
const StringInit& val = dynamic_cast<const StringInit&>(*ptr);
return val.getValue();
/// CheckBooleanConstant - Check that the provided value is a boolean constant.
void CheckBooleanConstant(const Init* I) {
- const DefInit& val = dynamic_cast<const DefInit&>(*I);
- const std::string& str = val.getAsString();
-
- if (str != "true" && str != "false") {
- throw "Incorrect boolean value: '" + str +
- "': must be either 'true' or 'false'";
- }
+ InitPtrToBool(I);
}
// CheckNumberOfArguments - Ensure that the number of args in d is
throw GetOperatorName(d) + ": too few arguments!";
}
-// IsDagEmpty - is this DAG marked with an empty marker?
-bool IsDagEmpty (const DagInit& d) {
- return GetOperatorName(d) == "empty_dag_marker";
-}
-
// EscapeVariableName - Escape commas and other symbols not allowed
// in the C++ variable names. Makes it possible to use options named
// like "Wa," (useful for prefix options).
throw ErrorString;
}
-// apply is needed because C++'s syntax doesn't let us construct a function
-// object and call it in the same statement.
-template<typename F, typename T0>
-void apply(F Fun, T0& Arg0) {
- return Fun(Arg0);
-}
-
-template<typename F, typename T0, typename T1>
-void apply(F Fun, T0& Arg0, T1& Arg1) {
- return Fun(Arg0, Arg1);
-}
-
//===----------------------------------------------------------------------===//
/// Back-end specific code
namespace OptionDescriptionFlags {
enum OptionDescriptionFlags { Required = 0x1, Hidden = 0x2,
- ReallyHidden = 0x4, Extern = 0x8,
- OneOrMore = 0x10, Optional = 0x20,
- CommaSeparated = 0x40, ForwardNotSplit = 0x80,
- ZeroOrMore = 0x100 };
+ ReallyHidden = 0x4, OneOrMore = 0x8,
+ Optional = 0x10, CommaSeparated = 0x20,
+ ForwardNotSplit = 0x40, ZeroOrMore = 0x80 };
}
/// OptionDescription - Represents data contained in a single
/// GenVariableName - Returns the variable name used in the
/// generated C++ code.
- std::string GenVariableName() const;
+ std::string GenVariableName() const
+ { return "autogenerated::" + GenOptionType() + EscapeVariableName(Name); }
+
+ /// GenPlainVariableName - Returns the variable name without the namespace
+ /// prefix.
+ std::string GenPlainVariableName() const
+ { return GenOptionType() + EscapeVariableName(Name); }
/// Merge - Merge two option descriptions.
void Merge (const OptionDescription& other);
bool isCommaSeparated() const;
void setCommaSeparated();
- bool isExtern() const;
- void setExtern();
-
bool isForwardNotSplit() const;
void setForwardNotSplit();
bool isList() const
{ return OptionType::IsList(this->Type); }
+ bool isParameterList() const
+ { return (OptionType::IsList(this->Type)
+ && !OptionType::IsSwitchList(this->Type)); }
+
+private:
+
+ // GenOptionType - Helper function used by GenVariableName().
+ std::string GenOptionType() const;
};
void OptionDescription::CheckConsistency() const {
Flags |= OptionDescriptionFlags::ForwardNotSplit;
}
-bool OptionDescription::isExtern() const {
- return Flags & OptionDescriptionFlags::Extern;
-}
-void OptionDescription::setExtern() {
- Flags |= OptionDescriptionFlags::Extern;
-}
-
bool OptionDescription::isRequired() const {
return Flags & OptionDescriptionFlags::Required;
}
}
}
-std::string OptionDescription::GenVariableName() const {
- const std::string& EscapedName = EscapeVariableName(Name);
+std::string OptionDescription::GenOptionType() const {
switch (Type) {
case OptionType::Alias:
- return "AutoGeneratedAlias_" + EscapedName;
+ return "Alias_";
case OptionType::PrefixList:
case OptionType::ParameterList:
- return "AutoGeneratedList_" + EscapedName;
+ return "List_";
case OptionType::Switch:
- return "AutoGeneratedSwitch_" + EscapedName;
+ return "Switch_";
case OptionType::SwitchList:
- return "AutoGeneratedSwitchList_" + EscapedName;
+ return "SwitchList_";
case OptionType::Prefix:
case OptionType::Parameter:
default:
- return "AutoGeneratedParameter_" + EscapedName;
+ return "Parameter_";
}
}
// wrong type.
const OptionDescription& FindSwitch(const std::string& OptName) const;
const OptionDescription& FindParameter(const std::string& OptName) const;
- const OptionDescription& FindList(const std::string& OptName) const;
+ const OptionDescription& FindParameterList(const std::string& OptName) const;
const OptionDescription&
FindListOrParameter(const std::string& OptName) const;
+ const OptionDescription&
+ FindParameterListOrParameter(const std::string& OptName) const;
/// insertDescription - Insert new OptionDescription into
/// OptionDescriptions list
}
const OptionDescription&
-OptionDescriptions::FindList(const std::string& OptName) const {
+OptionDescriptions::FindParameterList(const std::string& OptName) const {
const OptionDescription& OptDesc = this->FindOption(OptName);
- if (!OptDesc.isList())
- throw OptName + ": incorrect option type - should be a list!";
+ if (!OptDesc.isList() || OptDesc.isSwitchList())
+ throw OptName + ": incorrect option type - should be a parameter list!";
return OptDesc;
}
return OptDesc;
}
+const OptionDescription&
+OptionDescriptions::FindParameterListOrParameter
+(const std::string& OptName) const {
+ const OptionDescription& OptDesc = this->FindOption(OptName);
+ if ((!OptDesc.isList() && !OptDesc.isParameter()) || OptDesc.isSwitchList())
+ throw OptName
+ + ": incorrect option type - should be a parameter list or parameter!";
+ return OptDesc;
+}
+
void OptionDescriptions::InsertDescription (const OptionDescription& o) {
container_type::iterator I = Descriptions.find(o.Name);
if (I != Descriptions.end()) {
((Obj)->*(h))(Dag, IndentLevel, O);
}
-
template <typename H>
typename HandlerTable<H>::HandlerMap HandlerTable<H>::Handlers_;
: optDesc_(OD)
{
if (!staticMembersInitialized_) {
- AddHandler("extern", &CollectOptionProperties::onExtern);
AddHandler("help", &CollectOptionProperties::onHelp);
AddHandler("hidden", &CollectOptionProperties::onHidden);
AddHandler("init", &CollectOptionProperties::onInit);
/// Option property handlers --
/// Methods that handle option properties such as (help) or (hidden).
- void onExtern (const DagInit& d) {
- CheckNumberOfArguments(d, 0);
- optDesc_.setExtern();
- }
-
void onHelp (const DagInit& d) {
CheckNumberOfArguments(d, 1);
optDesc_.Help = EscapeQuotes(InitPtrToString(d.getArg(0)));
void onCommaSeparated (const DagInit& d) {
CheckNumberOfArguments(d, 0);
- if (!optDesc_.isList())
- throw "'comma_separated' is valid only on list options!";
+ if (!optDesc_.isParameterList())
+ throw "'comma_separated' is valid only on parameter list options!";
optDesc_.setCommaSeparated();
}
if (val < 2)
throw "Error in the 'multi_val' property: "
"the value must be greater than 1!";
- if (!optDesc_.isList())
+ if (!optDesc_.isParameterList())
throw "The multi_val property is valid only on list options!";
optDesc_.MultiVal = val;
}
OptionDescription OD(Type, Name);
- if (!OD.isExtern())
- CheckNumberOfArguments(d, 2);
+ CheckNumberOfArguments(d, 2);
+ // Alias option store the aliased option name in the 'Help' field and do not
+ // have any properties.
if (OD.isAlias()) {
- // Aliases store the aliased option name in the 'Help' field.
OD.Help = InitPtrToString(d.getArg(1));
}
- else if (!OD.isExtern()) {
+ else {
processOptionProperties(d, OD);
}
+
+ // Switch options are ZeroOrMore by default.
+ if (OD.isSwitch()) {
+ if (!(OD.isOptional() || OD.isOneOrMore() || OD.isRequired()))
+ OD.setZeroOrMore();
+ }
+
OptDescs_.InsertDescription(OD);
}
/// CollectOptionDescriptions - Collects option properties from all
/// OptionLists.
-void CollectOptionDescriptions (RecordVector::const_iterator B,
- RecordVector::const_iterator E,
+void CollectOptionDescriptions (const RecordVector& V,
OptionDescriptions& OptDescs)
{
// For every OptionList:
- for (; B!=E; ++B) {
- RecordVector::value_type T = *B;
+ for (RecordVector::const_iterator B = V.begin(), E = V.end(); B!=E; ++B)
+ {
// Throws an exception if the value does not exist.
- ListInit* PropList = T->getValueAsListInit("options");
+ ListInit* PropList = (*B)->getValueAsListInit("options");
- // For every option description in this list:
- // collect the information and
+ // For every option description in this list: invoke AddOption.
std::for_each(PropList->begin(), PropList->end(), AddOption(OptDescs));
}
}
StrVector InLanguage;
std::string InFileOption;
std::string OutFileOption;
- std::string OutLanguage;
+ StrVector OutLanguage;
std::string OutputSuffix;
unsigned Flags;
const Init* OnEmpty;
// Default ctor here is needed because StringMap can only store
// DefaultConstructible objects
- ToolDescription ()
- : CmdLine(0), Actions(0), OutFileOption("-o"),
- Flags(0), OnEmpty(0)
- {}
- ToolDescription (const std::string& n)
+ ToolDescription (const std::string &n = "")
: Name(n), CmdLine(0), Actions(0), OutFileOption("-o"),
Flags(0), OnEmpty(0)
{}
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));
+ // Copy strings to the output vector.
+ for (unsigned i = 0, NumArgs = d.getNumArgs(); i < NumArgs; ++i) {
+ OutVec.push_back(InitPtrToString(d.getArg(i)));
}
- 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));
- }
+ // Remove duplicates.
+ std::sort(OutVec.begin(), OutVec.end());
+ StrVector::iterator newE = std::unique(OutVec.begin(), OutVec.end());
+ OutVec.erase(newE, OutVec.end());
+ }
- // Remove duplicates.
- std::sort(out.begin(), out.end());
- StrVector::iterator newE = std::unique(out.begin(), out.end());
- out.erase(newE, out.end());
- }
+
+ void onInLanguage (const DagInit& d) {
+ this->onInOutLanguage(d, toolDesc_.InLanguage);
}
void onJoin (const DagInit& d) {
- CheckNumberOfArguments(d, 0);
- toolDesc_.setJoin();
+ bool isReallyJoin = false;
+
+ if (d.getNumArgs() == 0) {
+ isReallyJoin = true;
+ }
+ else {
+ Init* I = d.getArg(0);
+ isReallyJoin = InitPtrToBool(I);
+ }
+
+ // Is this *really* a join tool? We allow (join false) for generating two
+ // tool descriptions from a single generic one.
+ // TOFIX: come up with a cleaner solution.
+ if (isReallyJoin) {
+ 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) {
/// CollectToolDescriptions - Gather information about tool properties
/// from the parsed TableGen data (basically a wrapper for the
/// CollectToolProperties function object).
-void CollectToolDescriptions (RecordVector::const_iterator B,
- RecordVector::const_iterator E,
+void CollectToolDescriptions (const RecordVector& Tools,
ToolDescriptions& ToolDescs)
{
// Iterate over a properties list of every Tool definition
- for (;B!=E;++B) {
+ for (RecordVector::const_iterator B = Tools.begin(),
+ E = Tools.end(); B!=E; ++B) {
const Record* T = *B;
// Throws an exception if the value does not exist.
ListInit* PropList = T->getValueAsListInit("properties");
/// FillInEdgeVector - Merge all compilation graph definitions into
/// one single edge list.
-void FillInEdgeVector(RecordVector::const_iterator B,
- RecordVector::const_iterator E, RecordVector& Out) {
- for (; B != E; ++B) {
- const ListInit* edges = (*B)->getValueAsListInit("edges");
+void FillInEdgeVector(const RecordVector& CompilationGraphs,
+ DagVector& Out) {
+ for (RecordVector::const_iterator B = CompilationGraphs.begin(),
+ E = CompilationGraphs.end(); B != E; ++B) {
+ const ListInit* Edges = (*B)->getValueAsListInit("edges");
- for (unsigned i = 0; i < edges->size(); ++i)
- Out.push_back(edges->getElementAsRecord(i));
- }
-}
-
-/// CalculatePriority - Calculate the priority of this plugin.
-int CalculatePriority(RecordVector::const_iterator B,
- RecordVector::const_iterator E) {
- int priority = 0;
-
- if (B != E) {
- priority = static_cast<int>((*B)->getValueAsInt("priority"));
-
- if (++B != E)
- throw "More than one 'PluginPriority' instance found: "
- "most probably an error!";
+ for (ListInit::const_iterator B = Edges->begin(),
+ E = Edges->end(); B != E; ++B) {
+ Out.push_back(&InitPtrToDag(*B));
+ }
}
-
- return priority;
}
/// NotInGraph - Helper function object for FilterNotInGraph.
/// FilterNotInGraph - Filter out from ToolDescs all Tools not
/// mentioned in the compilation graph definition.
-void FilterNotInGraph (const RecordVector& EdgeVector,
+void FilterNotInGraph (const DagVector& EdgeVector,
ToolDescriptions& ToolDescs) {
// List all tools mentioned in the graph.
llvm::StringSet<> ToolsInGraph;
- for (RecordVector::const_iterator B = EdgeVector.begin(),
+ for (DagVector::const_iterator B = EdgeVector.begin(),
E = EdgeVector.end(); B != E; ++B) {
- const Record* Edge = *B;
- const std::string& NodeA = Edge->getValueAsString("a");
- const std::string& NodeB = Edge->getValueAsString("b");
+ const DagInit* Edge = *B;
+ const std::string& NodeA = InitPtrToString(Edge->getArg(0));
+ const std::string& NodeB = InitPtrToString(Edge->getArg(1));
if (NodeA != "root")
ToolsInGraph.insert(NodeA);
}
/// 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. This doesn't do much when the information
-/// about the whole graph is not available (i.e. when compiling most
-/// plugins).
-void TypecheckGraph (const RecordVector& EdgeVector,
+/// 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 (RecordVector::const_iterator B = EdgeVector.begin(),
+ for (DagVector::const_iterator B = EdgeVector.begin(),
E = EdgeVector.end(); B != E; ++B) {
- const Record* Edge = *B;
- const std::string& NodeA = Edge->getValueAsString("a");
- const std::string& NodeB = Edge->getValueAsString("b");
- StringMap<std::string>::iterator IA = ToolToOutLang.find(NodeA);
+ const DagInit* Edge = *B;
+ const std::string& NodeA = InitPtrToString(Edge->getArg(0));
+ const std::string& NodeB = InitPtrToString(Edge->getArg(1));
+ 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!";
}
}
if (ActionName == "forward" || ActionName == "forward_as" ||
ActionName == "forward_value" ||
ActionName == "forward_transformed_value" ||
- ActionName == "switch_on" || ActionName == "any_switch_on" ||
- ActionName == "parameter_equals" ||
- ActionName == "element_in_list" || ActionName == "not_empty" ||
- ActionName == "empty") {
+ ActionName == "parameter_equals" || ActionName == "element_in_list") {
CheckNumberOfArguments(Stmt, 1);
Init* Arg = Stmt.getArg(0);
- if (typeid(*Arg) == typeid(StringInit)) {
- const std::string& Name = InitPtrToString(Arg);
- OptionNames_.insert(Name);
- }
- else {
- // It's a list.
- const ListInit& List = InitPtrToList(Arg);
- for (ListInit::const_iterator B = List.begin(), E = List.end();
- B != E; ++B) {
- const std::string& Name = InitPtrToString(*B);
- OptionNames_.insert(Name);
- }
+ if (typeid(*Arg) == typeid(StringInit))
+ OptionNames_.insert(InitPtrToString(Arg));
+ }
+ else if (ActionName == "any_switch_on" || ActionName == "switch_on" ||
+ ActionName == "any_not_empty" || ActionName == "any_empty" ||
+ ActionName == "not_empty" || ActionName == "empty") {
+ for (unsigned i = 0, NumArgs = Stmt.getNumArgs(); i < NumArgs; ++i) {
+ Init* Arg = Stmt.getArg(i);
+ if (typeid(*Arg) == typeid(StringInit))
+ OptionNames_.insert(InitPtrToString(Arg));
}
}
else if (ActionName == "and" || ActionName == "or" || ActionName == "not") {
{}
void operator()(const Init* Statement) {
+ // Statement is either a dag, or a list of dags.
if (typeid(*Statement) == typeid(ListInit)) {
const ListInit& DagList = *static_cast<const ListInit*>(Statement);
for (ListInit::const_iterator B = DagList.begin(), E = DagList.end();
}
};
+/// IsOptionalEdge - Validate that the 'optional_edge' has proper structure.
+bool IsOptionalEdge (const DagInit& Edg) {
+ return (GetOperatorName(Edg) == "optional_edge") && (Edg.getNumArgs() > 2);
+}
+
/// CheckForSuperfluousOptions - Check that there are no side
/// effect-free options (specified only in the OptionList). Otherwise,
/// output a warning.
-void CheckForSuperfluousOptions (const RecordVector& Edges,
+void CheckForSuperfluousOptions (const DagVector& EdgeVector,
const ToolDescriptions& ToolDescs,
const OptionDescriptions& OptDescs) {
llvm::StringSet<> nonSuperfluousOptions;
// Add all options mentioned in the 'case' clauses of the
// OptionalEdges of the compilation graph to the set of
// non-superfluous options.
- for (RecordVector::const_iterator B = Edges.begin(), E = Edges.end();
- B != E; ++B) {
- const Record* Edge = *B;
- DagInit& Weight = *Edge->getValueAsDag("weight");
-
- if (!IsDagEmpty(Weight))
+ for (DagVector::const_iterator B = EdgeVector.begin(),
+ E = EdgeVector.end(); B != E; ++B) {
+ const DagInit& Edge = **B;
+ if (IsOptionalEdge(Edge)) {
+ const DagInit& Weight = InitPtrToDag(Edge.getArg(2));
WalkCase(&Weight, ExtractOptionNames(nonSuperfluousOptions), Id());
+ }
}
// Check that all options in OptDescs belong to the set of
return false;
}
-/// EmitListTest - Helper function used by EmitCaseTest1ArgList().
+/// EmitMultipleArgumentTest - Helper function used by
+/// EmitCaseTestMultipleArgs()
template <typename F>
-void EmitListTest(const ListInit& L, const char* LogicOp,
- F Callback, raw_ostream& O)
+void EmitMultipleArgumentTest(const DagInit& D, const char* LogicOp,
+ F Callback, raw_ostream& O)
{
- // This is a lot like EmitLogicalOperationTest, but works on ListInits instead
- // of Dags...
- bool isFirst = true;
- for (ListInit::const_iterator B = L.begin(), E = L.end(); B != E; ++B) {
- if (isFirst)
- isFirst = false;
- else
- O << ' ' << LogicOp << ' ';
- Callback(InitPtrToString(*B), O);
+ for (unsigned i = 0, NumArgs = D.getNumArgs(); i < NumArgs; ++i) {
+ if (i != 0)
+ O << ' ' << LogicOp << ' ';
+ Callback(InitPtrToString(D.getArg(i)), O);
}
}
-// Callbacks for use with EmitListTest.
+// Callbacks for use with EmitMultipleArgumentTest
class EmitSwitchOn {
const OptionDescriptions& OptDescs_;
};
-/// EmitCaseTest1ArgList - Helper function used by EmitCaseTest1Arg();
-bool EmitCaseTest1ArgList(const std::string& TestName,
- const DagInit& d,
- const OptionDescriptions& OptDescs,
- raw_ostream& O) {
- const ListInit& L = InitPtrToList(d.getArg(0));
-
+/// EmitCaseTestMultipleArgs - Helper function used by EmitCaseTest1Arg()
+bool EmitCaseTestMultipleArgs (const std::string& TestName,
+ const DagInit& d,
+ const OptionDescriptions& OptDescs,
+ raw_ostream& O) {
if (TestName == "any_switch_on") {
- EmitListTest(L, "||", EmitSwitchOn(OptDescs), O);
+ EmitMultipleArgumentTest(d, "||", EmitSwitchOn(OptDescs), O);
return true;
}
else if (TestName == "switch_on") {
- EmitListTest(L, "&&", EmitSwitchOn(OptDescs), O);
+ EmitMultipleArgumentTest(d, "&&", EmitSwitchOn(OptDescs), O);
return true;
}
else if (TestName == "any_not_empty") {
- EmitListTest(L, "||", EmitEmptyTest(true, OptDescs), O);
+ EmitMultipleArgumentTest(d, "||", EmitEmptyTest(true, OptDescs), O);
return true;
}
else if (TestName == "any_empty") {
- EmitListTest(L, "||", EmitEmptyTest(false, OptDescs), O);
+ EmitMultipleArgumentTest(d, "||", EmitEmptyTest(false, OptDescs), O);
return true;
}
else if (TestName == "not_empty") {
- EmitListTest(L, "&&", EmitEmptyTest(true, OptDescs), O);
+ EmitMultipleArgumentTest(d, "&&", EmitEmptyTest(true, OptDescs), O);
return true;
}
else if (TestName == "empty") {
- EmitListTest(L, "&&", EmitEmptyTest(false, OptDescs), O);
+ EmitMultipleArgumentTest(d, "&&", EmitEmptyTest(false, OptDescs), O);
return true;
}
return false;
}
-/// EmitCaseTest1ArgStr - Helper function used by EmitCaseTest1Arg();
-bool EmitCaseTest1ArgStr(const std::string& TestName,
- const DagInit& d,
- const OptionDescriptions& OptDescs,
- raw_ostream& O) {
- const std::string& OptName = InitPtrToString(d.getArg(0));
+/// EmitCaseTest1Arg - Helper function used by EmitCaseTest1OrMoreArgs()
+bool EmitCaseTest1Arg (const std::string& TestName,
+ const DagInit& d,
+ const OptionDescriptions& OptDescs,
+ raw_ostream& O) {
+ const std::string& Arg = InitPtrToString(d.getArg(0));
- if (TestName == "switch_on") {
- apply(EmitSwitchOn(OptDescs), OptName, O);
- return true;
- }
- else if (TestName == "input_languages_contain") {
- O << "InLangs.count(\"" << OptName << "\") != 0";
+ if (TestName == "input_languages_contain") {
+ O << "InLangs.count(\"" << Arg << "\") != 0";
return true;
}
else if (TestName == "in_language") {
// tools can process several files in different languages simultaneously.
// TODO: make this work with Edge::Weight (if possible).
- O << "LangMap.GetLanguage(inFile) == \"" << OptName << '\"';
- return true;
- }
- else if (TestName == "not_empty" || TestName == "empty") {
- bool EmitNegate = (TestName == "not_empty");
- apply(EmitEmptyTest(EmitNegate, OptDescs), OptName, O);
+ O << "LangMap.GetLanguage(inFile) == \"" << Arg << '\"';
return true;
}
return false;
}
-/// EmitCaseTest1Arg - Helper function used by EmitCaseConstructHandler();
-bool EmitCaseTest1Arg(const std::string& TestName,
- const DagInit& d,
- const OptionDescriptions& OptDescs,
- raw_ostream& O) {
+/// EmitCaseTest1OrMoreArgs - Helper function used by
+/// EmitCaseConstructHandler()
+bool EmitCaseTest1OrMoreArgs(const std::string& TestName,
+ const DagInit& d,
+ const OptionDescriptions& OptDescs,
+ raw_ostream& O) {
CheckNumberOfArguments(d, 1);
- if (typeid(*d.getArg(0)) == typeid(ListInit))
- return EmitCaseTest1ArgList(TestName, d, OptDescs, O);
- else
- return EmitCaseTest1ArgStr(TestName, d, OptDescs, O);
+ return EmitCaseTest1Arg(TestName, d, OptDescs, O) ||
+ EmitCaseTestMultipleArgs(TestName, d, OptDescs, O);
}
/// EmitCaseTest2Args - Helper function used by EmitCaseConstructHandler().
return true;
}
else if (TestName == "element_in_list") {
- const OptionDescription& OptDesc = OptDescs.FindList(OptName);
+ const OptionDescription& OptDesc = OptDescs.FindParameterList(OptName);
const std::string& VarName = OptDesc.GenVariableName();
O << "std::find(" << VarName << ".begin(),\n";
O.indent(IndentLevel + Indent1)
const OptionDescriptions& OptDescs,
raw_ostream& O) {
O << '(';
- for (unsigned j = 0, NumArgs = d.getNumArgs(); j < NumArgs; ++j) {
- const DagInit& InnerTest = InitPtrToDag(d.getArg(j));
+ for (unsigned i = 0, NumArgs = d.getNumArgs(); i < NumArgs; ++i) {
+ const DagInit& InnerTest = InitPtrToDag(d.getArg(i));
EmitCaseTest(InnerTest, IndentLevel, OptDescs, O);
- if (j != NumArgs - 1) {
+ if (i != NumArgs - 1) {
O << ")\n";
O.indent(IndentLevel + Indent1) << ' ' << LogicOp << " (";
}
EmitLogicalNot(d, IndentLevel, OptDescs, O);
else if (EmitCaseTest0Args(TestName, O))
return;
- else if (EmitCaseTest1Arg(TestName, d, OptDescs, O))
+ else if (EmitCaseTest1OrMoreArgs(TestName, d, OptDescs, O))
return;
else if (EmitCaseTest2Args(TestName, d, IndentLevel, OptDescs, O))
return;
{}
void operator() (const Init* Statement, unsigned IndentLevel) {
+ // Is this a nested 'case'?
+ bool IsCase = dynamic_cast<const DagInit*>(Statement) &&
+ GetOperatorName(static_cast<const DagInit&>(*Statement)) == "case";
- // Ignore nested 'case' DAG.
- if (!(dynamic_cast<const DagInit*>(Statement) &&
- GetOperatorName(static_cast<const DagInit&>(*Statement)) == "case")) {
+ // If so, ignore it, it is handled by our caller, WalkCase.
+ if (!IsCase) {
if (typeid(*Statement) == typeid(ListInit)) {
const ListInit& DagList = *static_cast<const ListInit*>(Statement);
for (ListInit::const_iterator B = DagList.begin(), E = DagList.end();
}
+/// EmitForEachListElementCycleHeader - Emit common code for iterating through
+/// all elements of a list. Helper function used by
+/// EmitForwardOptionPropertyHandlingCode.
+void EmitForEachListElementCycleHeader (const OptionDescription& D,
+ unsigned IndentLevel,
+ raw_ostream& O) {
+ unsigned IndentLevel1 = IndentLevel + Indent1;
+
+ O.indent(IndentLevel)
+ << "for (" << D.GenTypeDeclaration()
+ << "::iterator B = " << D.GenVariableName() << ".begin(),\n";
+ O.indent(IndentLevel)
+ << "E = " << D.GenVariableName() << ".end(); B != E;) {\n";
+ O.indent(IndentLevel1) << "unsigned pos = " << D.GenVariableName()
+ << ".getPosition(B - " << D.GenVariableName()
+ << ".begin());\n";
+}
+
/// EmitForwardOptionPropertyHandlingCode - Helper function used to
/// implement EmitActionHandler. Emits code for
/// handling the (forward) and (forward_as) option properties.
<< D.GenVariableName() << "));\n";
break;
case OptionType::PrefixList:
- // TODO: remove duplication across PrefixList / ParameterList / SwitchList
- // branches
- O.indent(IndentLevel)
- << "for (" << D.GenTypeDeclaration()
- << "::iterator B = " << D.GenVariableName() << ".begin(),\n";
- O.indent(IndentLevel)
- << "E = " << D.GenVariableName() << ".end(); B != E;) {\n";
- O.indent(IndentLevel1) << "unsigned pos = " << D.GenVariableName()
- << ".getPosition(B - " << D.GenVariableName()
- << ".begin());\n";
+ EmitForEachListElementCycleHeader(D, IndentLevel, O);
O.indent(IndentLevel1) << "vec.push_back(std::make_pair(pos, \""
<< Name << "\" + " << "*B));\n";
O.indent(IndentLevel1) << "++B;\n";
O.indent(IndentLevel) << "}\n";
break;
case OptionType::ParameterList:
- O.indent(IndentLevel)
- << "for (" << D.GenTypeDeclaration() << "::iterator B = "
- << D.GenVariableName() << ".begin(),\n";
- O.indent(IndentLevel) << "E = " << D.GenVariableName()
- << ".end() ; B != E;) {\n";
- O.indent(IndentLevel1) << "unsigned pos = " << D.GenVariableName()
- << ".getPosition(B - " << D.GenVariableName()
- << ".begin());\n";
+ EmitForEachListElementCycleHeader(D, IndentLevel, O);
O.indent(IndentLevel1) << "vec.push_back(std::make_pair(pos, \""
<< Name << "\"));\n";
O.indent(IndentLevel) << "}\n";
break;
case OptionType::SwitchList:
- O.indent(IndentLevel)
- << "for (" << D.GenTypeDeclaration() << "::iterator B = "
- << D.GenVariableName() << ".begin(),\n";
- O.indent(IndentLevel) << "E = " << D.GenVariableName()
- << ".end() ; B != E;) {\n";
- O.indent(IndentLevel1) << "unsigned pos = " << D.GenVariableName()
- << ".getPosition(B - " << D.GenVariableName()
- << ".begin());\n";
+ EmitForEachListElementCycleHeader(D, IndentLevel, O);
O.indent(IndentLevel1) << "vec.push_back(std::make_pair(pos, \""
<< Name << "\"));\n";
O.indent(IndentLevel1) << "++B;\n";
unsigned IndentLevel, raw_ostream& O) const
{
O.indent(IndentLevel)
- << "throw std::runtime_error(\"" <<
- (d.getNumArgs() >= 1 ? InitPtrToString(d.getArg(0))
- : "Unknown error!")
+ << "PrintError(\""
+ << (d.getNumArgs() >= 1 ? InitPtrToString(d.getArg(0)) : "Unknown error!")
<< "\");\n";
+ O.indent(IndentLevel) << "return 1;\n";
}
void onWarningDag(const DagInit& d,
/// EmitActionHandlersCallback - Emit code that handles actions. Used by
/// EmitGenerateActionMethod() as an argument to EmitCaseConstructHandler().
-
class EmitActionHandlersCallback;
typedef void (EmitActionHandlersCallback::* EmitActionHandlersCallbackHandler)
{
CheckNumberOfArguments(Dag, 1);
const std::string& Name = InitPtrToString(Dag.getArg(0));
- const OptionDescription& D = OptDescs.FindListOrParameter(Name);
+ const OptionDescription& D = OptDescs.FindParameterListOrParameter(Name);
if (D.isSwitchList()) {
throw std::runtime_error
CheckNumberOfArguments(Dag, 2);
const std::string& Name = InitPtrToString(Dag.getArg(0));
const std::string& Hook = InitPtrToString(Dag.getArg(1));
- const OptionDescription& D = OptDescs.FindListOrParameter(Name);
+ const OptionDescription& D = OptDescs.FindParameterListOrParameter(Name);
O.indent(IndentLevel) << "vec.push_back(std::make_pair("
<< D.GenVariableName() << ".getPosition("
};
void EmitGenerateActionMethodHeader(const ToolDescription& D,
- bool IsJoin, raw_ostream& O)
+ bool IsJoin, bool Naked,
+ raw_ostream& O)
{
+ O.indent(Indent1) << "int GenerateAction(Action& Out,\n";
+
if (IsJoin)
- O.indent(Indent1) << "Action GenerateAction(const PathVector& inFiles,\n";
+ O.indent(Indent2) << "const PathVector& inFiles,\n";
else
- O.indent(Indent1) << "Action GenerateAction(const sys::Path& inFile,\n";
+ O.indent(Indent2) << "const sys::Path& inFile,\n";
- O.indent(Indent2) << "bool HasChildren,\n";
+ O.indent(Indent2) << "const bool HasChildren,\n";
O.indent(Indent2) << "const llvm::sys::Path& TempDir,\n";
O.indent(Indent2) << "const InputLanguagesSet& InLangs,\n";
O.indent(Indent2) << "const LanguageMap& LangMap) const\n";
O.indent(Indent1) << "{\n";
- O.indent(Indent2) << "std::string cmd;\n";
- O.indent(Indent2) << "std::string out_file;\n";
- O.indent(Indent2) << "std::vector<std::pair<unsigned, std::string> > vec;\n";
- O.indent(Indent2) << "bool stop_compilation = !HasChildren;\n";
- O.indent(Indent2) << "bool no_out_file = false;\n";
- O.indent(Indent2) << "const char* output_suffix = \""
- << D.OutputSuffix << "\";\n";
+
+ if (!Naked) {
+ O.indent(Indent2) << "std::string cmd;\n";
+ O.indent(Indent2) << "std::string out_file;\n";
+ O.indent(Indent2)
+ << "std::vector<std::pair<unsigned, std::string> > vec;\n";
+ O.indent(Indent2) << "bool stop_compilation = !HasChildren;\n";
+ O.indent(Indent2) << "bool no_out_file = false;\n";
+ O.indent(Indent2) << "std::string output_suffix(\""
+ << D.OutputSuffix << "\");\n";
+ }
}
// EmitGenerateActionMethod - Emit either a normal or a "join" version of the
const OptionDescriptions& OptDescs,
bool IsJoin, raw_ostream& O) {
- EmitGenerateActionMethodHeader(D, IsJoin, O);
+ EmitGenerateActionMethodHeader(D, IsJoin, /* Naked = */ false, O);
if (!D.CmdLine)
throw "Tool " + D.Name + " has no cmd_line property!";
O.indent(Indent3) << "out_file = this->OutFilename("
<< (IsJoin ? "sys::Path(),\n" : "inFile,\n");
- O.indent(Indent4) << "TempDir, stop_compilation, output_suffix).str();\n\n";
+ O.indent(Indent4) <<
+ "TempDir, stop_compilation, output_suffix.c_str()).str();\n\n";
O.indent(Indent3) << "vec.push_back(std::make_pair(65536, out_file));\n";
O.indent(Indent2) << "}\n\n";
// Handle the Sink property.
+ std::string SinkOption("autogenerated::");
+ SinkOption += SinkOptionName;
if (D.isSink()) {
- O.indent(Indent2) << "if (!" << SinkOptionName << ".empty()) {\n";
+ O.indent(Indent2) << "if (!" << SinkOption << ".empty()) {\n";
O.indent(Indent3) << "for (cl::list<std::string>::iterator B = "
- << SinkOptionName << ".begin(), E = " << SinkOptionName
+ << SinkOption << ".begin(), E = " << SinkOption
<< ".end(); B != E; ++B)\n";
- O.indent(Indent4) << "vec.push_back(std::make_pair(" << SinkOptionName
- << ".getPosition(B - " << SinkOptionName
+ O.indent(Indent4) << "vec.push_back(std::make_pair(" << SinkOption
+ << ".getPosition(B - " << SinkOption
<< ".begin()), *B));\n";
O.indent(Indent2) << "}\n";
}
- O.indent(Indent2) << "return Action(cmd, this->SortArgs(vec), "
+ O.indent(Indent2) << "Out.Construct(cmd, this->SortArgs(vec), "
<< "stop_compilation, out_file);\n";
+ O.indent(Indent2) << "return 0;\n";
O.indent(Indent1) << "}\n\n";
}
const OptionDescriptions& OptDescs,
raw_ostream& O) {
if (!ToolDesc.isJoin()) {
- O.indent(Indent1) << "Action GenerateAction(const PathVector& inFiles,\n";
- O.indent(Indent2) << "bool HasChildren,\n";
- O.indent(Indent2) << "const llvm::sys::Path& TempDir,\n";
- O.indent(Indent2) << "const InputLanguagesSet& InLangs,\n";
- O.indent(Indent2) << "const LanguageMap& LangMap) const\n";
- O.indent(Indent1) << "{\n";
- O.indent(Indent2) << "throw std::runtime_error(\"" << ToolDesc.Name
+ EmitGenerateActionMethodHeader(ToolDesc, /* IsJoin = */ true,
+ /* Naked = */ true, O);
+ O.indent(Indent2) << "PrintError(\"" << ToolDesc.Name
<< " is not a Join tool!\");\n";
+ O.indent(Indent2) << "return -1;\n";
O.indent(Indent1) << "}\n\n";
}
else {
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";
}
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.
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);
/// EmitOptionDefinitions - Iterate over a list of option descriptions
/// and emit registration code.
void EmitOptionDefinitions (const OptionDescriptions& descs,
- bool HasSink, bool HasExterns,
- raw_ostream& O)
+ bool HasSink, raw_ostream& O)
{
std::vector<OptionDescription> Aliases;
continue;
}
- if (val.isExtern())
- O << "extern ";
-
O << val.GenTypeDeclaration() << ' '
- << val.GenVariableName();
-
- if (val.isExtern()) {
- O << ";\n";
- continue;
- }
+ << val.GenPlainVariableName();
O << "(\"" << val.Name << "\"\n";
const OptionDescription& val = *B;
O << val.GenTypeDeclaration() << ' '
- << val.GenVariableName()
+ << val.GenPlainVariableName()
<< "(\"" << val.Name << '\"';
const OptionDescription& D = descs.FindOption(val.Help);
// Emit the sink option.
if (HasSink)
- O << (HasExterns ? "extern cl" : "cl")
- << "::list<std::string> " << SinkOptionName
- << (HasExterns ? ";\n" : "(cl::Sink);\n");
+ O << "cl::list<std::string> " << SinkOptionName << "(cl::Sink);\n";
O << '\n';
}
const OptionDescriptions& OptDescs_;
- void onListOrDag(const DagInit& d, HandlerImpl h,
- unsigned IndentLevel, raw_ostream& O) const
+ void onEachArgument(const DagInit& d, HandlerImpl h,
+ unsigned IndentLevel, raw_ostream& O) const
{
CheckNumberOfArguments(d, 1);
- const Init* I = d.getArg(0);
- // If I is a list, apply h to each element.
- if (typeid(*I) == typeid(ListInit)) {
- const ListInit& L = *static_cast<const ListInit*>(I);
- for (ListInit::const_iterator B = L.begin(), E = L.end(); B != E; ++B)
- ((this)->*(h))(*B, IndentLevel, O);
- }
- // Otherwise, apply h to I.
- else {
- ((this)->*(h))(I, IndentLevel, O);
+ for (unsigned i = 0, NumArgs = d.getNumArgs(); i < NumArgs; ++i) {
+ ((this)->*(h))(d.getArg(i), IndentLevel, O);
}
}
void onUnsetOption(const DagInit& d,
unsigned IndentLevel, raw_ostream& O) const
{
- this->onListOrDag(d, &EmitPreprocessOptionsCallback::onUnsetOptionImpl,
- IndentLevel, O);
+ this->onEachArgument(d, &EmitPreprocessOptionsCallback::onUnsetOptionImpl,
+ IndentLevel, O);
}
- void onSetOptionImpl(const DagInit& d,
+ void onSetOptionImpl(const DagInit& D,
unsigned IndentLevel, raw_ostream& O) const {
- CheckNumberOfArguments(d, 2);
- const std::string& OptName = InitPtrToString(d.getArg(0));
- const Init* Value = d.getArg(1);
+ CheckNumberOfArguments(D, 2);
+
+ const std::string& OptName = InitPtrToString(D.getArg(0));
const OptionDescription& OptDesc = OptDescs_.FindOption(OptName);
+ const Init* Value = D.getArg(1);
if (OptDesc.isList()) {
const ListInit& List = InitPtrToList(Value);
O.indent(IndentLevel) << OptDesc.GenVariableName() << ".clear();\n";
for (ListInit::const_iterator B = List.begin(), E = List.end();
B != E; ++B) {
- O.indent(IndentLevel) << OptDesc.GenVariableName() << ".push_back(\""
- << InitPtrToString(*B) << "\");\n";
+ const Init* CurElem = *B;
+ if (OptDesc.isSwitchList())
+ CheckBooleanConstant(CurElem);
+
+ O.indent(IndentLevel)
+ << OptDesc.GenVariableName() << ".push_back(\""
+ << (OptDesc.isSwitchList() ? CurElem->getAsString()
+ : InitPtrToString(CurElem))
+ << "\");\n";
}
}
else if (OptDesc.isSwitch()) {
<< " = \"" << Str << "\";\n";
}
else {
- throw "Can't apply 'set_option' to alias option -" + OptName + " !";
+ throw "Can't apply 'set_option' to alias option '" + OptName + "'!";
}
}
{
CheckNumberOfArguments(d, 1);
- // Two arguments: (set_option "parameter", VALUE), where VALUE can be a
- // boolean, a string or a string list.
- if (d.getNumArgs() > 1)
- this->onSetOptionImpl(d, IndentLevel, O);
- // One argument: (set_option "switch")
- // or (set_option ["switch1", "switch2", ...])
- else
- this->onListOrDag(d, &EmitPreprocessOptionsCallback::onSetSwitch,
- IndentLevel, O);
+ // 2-argument form: (set_option "A", true), (set_option "B", "C"),
+ // (set_option "D", ["E", "F"])
+ if (d.getNumArgs() == 2) {
+ const OptionDescription& OptDesc =
+ OptDescs_.FindOption(InitPtrToString(d.getArg(0)));
+ const Init* Opt2 = d.getArg(1);
+
+ if (!OptDesc.isSwitch() || typeid(*Opt2) != typeid(StringInit)) {
+ this->onSetOptionImpl(d, IndentLevel, O);
+ return;
+ }
+ }
+
+ // Multiple argument form: (set_option "A"), (set_option "B", "C", "D")
+ this->onEachArgument(d, &EmitPreprocessOptionsCallback::onSetSwitch,
+ IndentLevel, O);
}
public:
};
-/// EmitPreprocessOptions - Emit the PreprocessOptionsLocal() function.
+/// EmitPreprocessOptions - Emit the PreprocessOptions() function.
void EmitPreprocessOptions (const RecordKeeper& Records,
const OptionDescriptions& OptDecs, raw_ostream& O)
{
- O << "void PreprocessOptionsLocal() {\n";
+ O << "int PreprocessOptions () {\n";
const RecordVector& OptionPreprocessors =
Records.getAllDerivedDefinitions("OptionPreprocessor");
false, OptDecs, O);
}
+ O << '\n';
+ O.indent(Indent1) << "return 0;\n";
O << "}\n\n";
}
-/// EmitPopulateLanguageMap - Emit the PopulateLanguageMapLocal() function.
-void EmitPopulateLanguageMap (const RecordKeeper& Records, raw_ostream& O)
+class DoEmitPopulateLanguageMap;
+typedef void (DoEmitPopulateLanguageMap::* DoEmitPopulateLanguageMapHandler)
+(const DagInit& D);
+
+class DoEmitPopulateLanguageMap
+: public HandlerTable<DoEmitPopulateLanguageMapHandler>
{
- O << "void PopulateLanguageMapLocal(LanguageMap& langMap) {\n";
+private:
+ raw_ostream& O_;
+
+public:
+
+ explicit DoEmitPopulateLanguageMap (raw_ostream& O) : O_(O) {
+ if (!staticMembersInitialized_) {
+ AddHandler("lang_to_suffixes",
+ &DoEmitPopulateLanguageMap::onLangToSuffixes);
- // Get the relevant field out of RecordKeeper
- const Record* LangMapRecord = Records.getDef("LanguageMap");
+ staticMembersInitialized_ = true;
+ }
+ }
- // It is allowed for a plugin to have no language map.
- if (LangMapRecord) {
+ void operator() (Init* I) {
+ InvokeDagInitHandler(this, I);
+ }
- ListInit* LangsToSuffixesList = LangMapRecord->getValueAsListInit("map");
- if (!LangsToSuffixesList)
- throw "Error in the language map definition!";
+private:
- for (unsigned i = 0; i < LangsToSuffixesList->size(); ++i) {
- const Record* LangToSuffixes = LangsToSuffixesList->getElementAsRecord(i);
+ void onLangToSuffixes (const DagInit& d) {
+ CheckNumberOfArguments(d, 2);
- const std::string& Lang = LangToSuffixes->getValueAsString("lang");
- const ListInit* Suffixes = LangToSuffixes->getValueAsListInit("suffixes");
+ const std::string& Lang = InitPtrToString(d.getArg(0));
+ Init* Suffixes = d.getArg(1);
- for (unsigned i = 0; i < Suffixes->size(); ++i)
- O.indent(Indent1) << "langMap[\""
- << InitPtrToString(Suffixes->getElement(i))
- << "\"] = \"" << Lang << "\";\n";
+ // Second argument to lang_to_suffixes is either a single string...
+ if (typeid(*Suffixes) == typeid(StringInit)) {
+ O_.indent(Indent1) << "langMap[\"" << InitPtrToString(Suffixes)
+ << "\"] = \"" << Lang << "\";\n";
+ }
+ // ...or a list of strings.
+ else {
+ const ListInit& Lst = InitPtrToList(Suffixes);
+ assert(Lst.size() != 0);
+ for (ListInit::const_iterator B = Lst.begin(), E = Lst.end();
+ B != E; ++B) {
+ O_.indent(Indent1) << "langMap[\"" << InitPtrToString(*B)
+ << "\"] = \"" << Lang << "\";\n";
+ }
}
}
+};
+
+/// EmitPopulateLanguageMap - Emit the PopulateLanguageMap() function.
+void EmitPopulateLanguageMap (const RecordKeeper& Records, raw_ostream& O)
+{
+ O << "int PopulateLanguageMap (LanguageMap& langMap) {\n";
+
+ // For each LanguageMap:
+ const RecordVector& LangMaps =
+ Records.getAllDerivedDefinitions("LanguageMap");
+
+ // Call DoEmitPopulateLanguageMap.
+ for (RecordVector::const_iterator B = LangMaps.begin(),
+ E = LangMaps.end(); B!=E; ++B) {
+ ListInit* LangMap = (*B)->getValueAsListInit("map");
+ std::for_each(LangMap->begin(), LangMap->end(),
+ DoEmitPopulateLanguageMap(O));
+ }
+
+ O << '\n';
+ O.indent(Indent1) << "return 0;\n";
O << "}\n\n";
}
-/// IncDecWeight - Helper function passed to EmitCaseConstructHandler()
-/// by EmitEdgeClass().
-void IncDecWeight (const Init* i, unsigned IndentLevel,
- raw_ostream& O) {
+/// EmitEdgePropertyHandlerCallback - Emits code that handles edge
+/// properties. Helper function passed to EmitCaseConstructHandler() by
+/// EmitEdgeClass().
+void EmitEdgePropertyHandlerCallback (const Init* i, unsigned IndentLevel,
+ raw_ostream& O) {
const DagInit& d = InitPtrToDag(i);
const std::string& OpName = GetOperatorName(d);
if (OpName == "inc_weight") {
O.indent(IndentLevel) << "ret += ";
}
- else if (OpName == "dec_weight") {
- O.indent(IndentLevel) << "ret -= ";
- }
else if (OpName == "error") {
CheckNumberOfArguments(d, 1);
- O.indent(IndentLevel) << "throw std::runtime_error(\""
+ O.indent(IndentLevel) << "PrintError(\""
<< InitPtrToString(d.getArg(0))
<< "\");\n";
+ O.indent(IndentLevel) << "return -1;\n";
return;
}
else {
/// EmitEdgeClass - Emit a single Edge# class.
void EmitEdgeClass (unsigned N, const std::string& Target,
- DagInit* Case, const OptionDescriptions& OptDescs,
+ const DagInit& Case, const OptionDescriptions& OptDescs,
raw_ostream& O) {
// Class constructor.
// Function Weight().
O.indent(Indent1)
- << "unsigned Weight(const InputLanguagesSet& InLangs) const {\n";
+ << "int Weight(const InputLanguagesSet& InLangs) const {\n";
O.indent(Indent2) << "unsigned ret = 0;\n";
// Handle the 'case' construct.
- EmitCaseConstructHandler(Case, Indent2, IncDecWeight, false, OptDescs, O);
+ EmitCaseConstructHandler(&Case, Indent2, EmitEdgePropertyHandlerCallback,
+ false, OptDescs, O);
O.indent(Indent2) << "return ret;\n";
O.indent(Indent1) << "}\n\n};\n\n";
}
/// EmitEdgeClasses - Emit Edge* classes that represent graph edges.
-void EmitEdgeClasses (const RecordVector& EdgeVector,
+void EmitEdgeClasses (const DagVector& EdgeVector,
const OptionDescriptions& OptDescs,
raw_ostream& O) {
int i = 0;
- for (RecordVector::const_iterator B = EdgeVector.begin(),
+ for (DagVector::const_iterator B = EdgeVector.begin(),
E = EdgeVector.end(); B != E; ++B) {
- const Record* Edge = *B;
- const std::string& NodeB = Edge->getValueAsString("b");
- DagInit& Weight = *Edge->getValueAsDag("weight");
+ const DagInit& Edge = **B;
+ const std::string& Name = GetOperatorName(Edge);
+
+ if (Name == "optional_edge") {
+ assert(IsOptionalEdge(Edge));
+ const std::string& NodeB = InitPtrToString(Edge.getArg(1));
+
+ const DagInit& Weight = InitPtrToDag(Edge.getArg(2));
+ EmitEdgeClass(i, NodeB, Weight, OptDescs, O);
+ }
+ else if (Name != "edge") {
+ throw "Unknown edge class: '" + Name + "'!";
+ }
- if (!IsDagEmpty(Weight))
- EmitEdgeClass(i, NodeB, &Weight, OptDescs, O);
++i;
}
}
-/// EmitPopulateCompilationGraph - Emit the PopulateCompilationGraphLocal()
-/// function.
-void EmitPopulateCompilationGraph (const RecordVector& EdgeVector,
+/// EmitPopulateCompilationGraph - Emit the PopulateCompilationGraph() function.
+void EmitPopulateCompilationGraph (const DagVector& EdgeVector,
const ToolDescriptions& ToolDescs,
raw_ostream& O)
{
- O << "void PopulateCompilationGraphLocal(CompilationGraph& G) {\n";
+ O << "int PopulateCompilationGraph (CompilationGraph& G) {\n";
for (ToolDescriptions::const_iterator B = ToolDescs.begin(),
E = ToolDescs.end(); B != E; ++B)
// Insert edges.
int i = 0;
- for (RecordVector::const_iterator B = EdgeVector.begin(),
+ for (DagVector::const_iterator B = EdgeVector.begin(),
E = EdgeVector.end(); B != E; ++B) {
- const Record* Edge = *B;
- const std::string& NodeA = Edge->getValueAsString("a");
- const std::string& NodeB = Edge->getValueAsString("b");
- DagInit& Weight = *Edge->getValueAsDag("weight");
+ const DagInit& Edge = **B;
+ const std::string& NodeA = InitPtrToString(Edge.getArg(0));
+ const std::string& NodeB = InitPtrToString(Edge.getArg(1));
- O.indent(Indent1) << "G.insertEdge(\"" << NodeA << "\", ";
+ O.indent(Indent1) << "if (int ret = G.insertEdge(\"" << NodeA << "\", ";
- if (IsDagEmpty(Weight))
- O << "new SimpleEdge(\"" << NodeB << "\")";
- else
+ if (IsOptionalEdge(Edge))
O << "new Edge" << i << "()";
+ else
+ O << "new SimpleEdge(\"" << NodeB << "\")";
+
+ O << "))\n";
+ O.indent(Indent2) << "return ret;\n";
- O << ");\n";
++i;
}
+ O << '\n';
+ O.indent(Indent1) << "return 0;\n";
O << "}\n\n";
}
CheckNumberOfArguments(Dag, 2);
const std::string& OptName = InitPtrToString(Dag.getArg(0));
const std::string& HookName = InitPtrToString(Dag.getArg(1));
- const OptionDescription& D = OptDescs_.FindOption(OptName);
+ const OptionDescription& D =
+ OptDescs_.FindParameterListOrParameter(OptName);
HookNames_[HookName] = HookInfo(D.isList() ? HookInfo::ListHook
: HookInfo::ArgHook);
return;
}
- // We're invoked on a command line.
+ // We're invoked on a command line string.
this->onCmdLine(InitPtrToString(Arg));
}
- void operator()(const DagInit* Test, unsigned, bool) {
- this->operator()(Test);
- }
void operator()(const Init* Statement, unsigned) {
this->operator()(Statement);
}
if (HookNames.empty())
return;
- O << "namespace hooks {\n";
for (HookInfoMap::const_iterator B = HookNames.begin(),
E = HookNames.end(); B != E; ++B) {
const char* HookName = B->first();
O <<");\n";
}
- O << "}\n\n";
-}
-
-/// EmitRegisterPlugin - Emit code to register this plugin.
-void EmitRegisterPlugin(int Priority, raw_ostream& O) {
- O << "struct Plugin : public llvmc::BasePlugin {\n\n";
- O.indent(Indent1) << "int Priority() const { return "
- << Priority << "; }\n\n";
- O.indent(Indent1) << "void PreprocessOptions() const\n";
- O.indent(Indent1) << "{ PreprocessOptionsLocal(); }\n\n";
- O.indent(Indent1) << "void PopulateLanguageMap(LanguageMap& langMap) const\n";
- O.indent(Indent1) << "{ PopulateLanguageMapLocal(langMap); }\n\n";
- O.indent(Indent1)
- << "void PopulateCompilationGraph(CompilationGraph& graph) const\n";
- O.indent(Indent1) << "{ PopulateCompilationGraphLocal(graph); }\n"
- << "};\n\n"
- << "static llvmc::RegisterPlugin<Plugin> RP;\n\n";
}
/// EmitIncludes - Emit necessary #include directives and some
void EmitIncludes(raw_ostream& O) {
O << "#include \"llvm/CompilerDriver/BuiltinOptions.h\"\n"
<< "#include \"llvm/CompilerDriver/CompilationGraph.h\"\n"
- << "#include \"llvm/CompilerDriver/ForceLinkageMacros.h\"\n"
- << "#include \"llvm/CompilerDriver/Plugin.h\"\n"
+ << "#include \"llvm/CompilerDriver/Error.h\"\n"
<< "#include \"llvm/CompilerDriver/Tool.h\"\n\n"
<< "#include \"llvm/Support/CommandLine.h\"\n"
<< "using namespace llvm;\n"
<< "using namespace llvmc;\n\n"
- << "extern cl::opt<std::string> OutputFilename;\n\n"
-
<< "inline const char* checkCString(const char* s)\n"
<< "{ return s == NULL ? \"\" : s; }\n\n";
}
-/// PluginData - Holds all information about a plugin.
-struct PluginData {
+/// DriverData - Holds all information about the driver.
+struct DriverData {
OptionDescriptions OptDescs;
- bool HasSink;
- bool HasExterns;
ToolDescriptions ToolDescs;
- RecordVector Edges;
- int Priority;
+ DagVector Edges;
+ bool HasSink;
};
/// HasSink - Go through the list of tool descriptions and check if
return false;
}
-/// HasExterns - Go through the list of option descriptions and check
-/// if there are any external options.
-bool HasExterns(const OptionDescriptions& OptDescs) {
- for (OptionDescriptions::const_iterator B = OptDescs.begin(),
- E = OptDescs.end(); B != E; ++B)
- if (B->second.isExtern())
- return true;
-
- return false;
-}
-
-/// CollectPluginData - Collect tool and option properties,
-/// compilation graph edges and plugin priority from the parse tree.
-void CollectPluginData (const RecordKeeper& Records, PluginData& Data) {
+/// CollectDriverData - Collect compilation graph edges, tool properties and
+/// option properties from the parse tree.
+void CollectDriverData (const RecordKeeper& Records, DriverData& Data) {
// Collect option properties.
const RecordVector& OptionLists =
Records.getAllDerivedDefinitions("OptionList");
- CollectOptionDescriptions(OptionLists.begin(), OptionLists.end(),
- Data.OptDescs);
+ CollectOptionDescriptions(OptionLists, Data.OptDescs);
// Collect tool properties.
const RecordVector& Tools = Records.getAllDerivedDefinitions("Tool");
- CollectToolDescriptions(Tools.begin(), Tools.end(), Data.ToolDescs);
+ CollectToolDescriptions(Tools, Data.ToolDescs);
Data.HasSink = HasSink(Data.ToolDescs);
- Data.HasExterns = HasExterns(Data.OptDescs);
// Collect compilation graph edges.
const RecordVector& CompilationGraphs =
Records.getAllDerivedDefinitions("CompilationGraph");
- FillInEdgeVector(CompilationGraphs.begin(), CompilationGraphs.end(),
- Data.Edges);
-
- // Calculate the priority of this plugin.
- const RecordVector& Priorities =
- Records.getAllDerivedDefinitions("PluginPriority");
- Data.Priority = CalculatePriority(Priorities.begin(), Priorities.end());
+ FillInEdgeVector(CompilationGraphs, Data.Edges);
}
-/// CheckPluginData - Perform some sanity checks on the collected data.
-void CheckPluginData(PluginData& Data) {
+/// CheckDriverData - Perform some sanity checks on the collected data.
+void CheckDriverData(DriverData& Data) {
// Filter out all tools not mentioned in the compilation graph.
FilterNotInGraph(Data.Edges, Data.ToolDescs);
// Typecheck the compilation graph.
+ // TODO: use a genuine graph representation instead of a vector and check for
+ // multiple edges.
TypecheckGraph(Data.Edges, Data.ToolDescs);
// Check that there are no options without side effects (specified
CheckForSuperfluousOptions(Data.Edges, Data.ToolDescs, Data.OptDescs);
}
-void EmitPluginCode(const PluginData& Data, raw_ostream& O) {
+void EmitDriverCode(const DriverData& Data,
+ raw_ostream& O, RecordKeeper &Records) {
// Emit file header.
EmitIncludes(O);
// Emit global option registration code.
- EmitOptionDefinitions(Data.OptDescs, Data.HasSink, Data.HasExterns, O);
+ O << "namespace llvmc {\n"
+ << "namespace autogenerated {\n\n";
+ EmitOptionDefinitions(Data.OptDescs, Data.HasSink, O);
+ O << "} // End namespace autogenerated.\n"
+ << "} // End namespace llvmc.\n\n";
// Emit hook declarations.
+ O << "namespace hooks {\n";
EmitHookDeclarations(Data.ToolDescs, Data.OptDescs, O);
+ O << "} // End namespace hooks.\n\n";
O << "namespace {\n\n";
-
- // Emit PreprocessOptionsLocal() function.
- EmitPreprocessOptions(Records, Data.OptDescs, O);
-
- // Emit PopulateLanguageMapLocal() function
- // (language map maps from file extensions to language names).
- EmitPopulateLanguageMap(Records, O);
+ O << "using namespace llvmc::autogenerated;\n\n";
// Emit Tool classes.
for (ToolDescriptions::const_iterator B = Data.ToolDescs.begin(),
// Emit Edge# classes.
EmitEdgeClasses(Data.Edges, Data.OptDescs, O);
- // Emit PopulateCompilationGraphLocal() function.
- EmitPopulateCompilationGraph(Data.Edges, Data.ToolDescs, O);
-
- // Emit code for plugin registration.
- EmitRegisterPlugin(Data.Priority, O);
-
O << "} // End anonymous namespace.\n\n";
- // Force linkage magic.
O << "namespace llvmc {\n";
- O << "LLVMC_FORCE_LINKAGE_DECL(LLVMC_PLUGIN_NAME) {}\n";
- O << "}\n";
+ O << "namespace autogenerated {\n\n";
+
+ // Emit PreprocessOptions() function.
+ EmitPreprocessOptions(Records, Data.OptDescs, O);
+
+ // Emit PopulateLanguageMap() function
+ // (language map maps from file extensions to language names).
+ EmitPopulateLanguageMap(Records, O);
+
+ // Emit PopulateCompilationGraph() function.
+ EmitPopulateCompilationGraph(Data.Edges, Data.ToolDescs, O);
+
+ O << "} // End namespace autogenerated.\n";
+ O << "} // End namespace llvmc.\n\n";
// EOF
}
/// run - The back-end entry point.
void LLVMCConfigurationEmitter::run (raw_ostream &O) {
try {
- PluginData Data;
+ DriverData Data;
- CollectPluginData(Records, Data);
- CheckPluginData(Data);
+ CollectDriverData(Records, Data);
+ CheckDriverData(Data);
- this->EmitSourceFileHeader("LLVMC Configuration Library", O);
- EmitPluginCode(Data, O);
+ this->EmitSourceFileHeader("llvmc-based driver: auto-generated code", O);
+ EmitDriverCode(Data, O, Records);
} catch (std::exception& Error) {
throw Error.what() + std::string(" - usually this means a syntax error.");