X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=utils%2FTableGen%2FLLVMCConfigurationEmitter.cpp;h=c40a39dff729824674db75a5eb1d102c59aee2c6;hb=75f6e89ea9f8fe9cf8c8f9fe6a3322bd6566fdf1;hp=6217f5c1d34a8e85f00186af390a5268c4da4207;hpb=545f96814bd881d57d961aa51465e977f9172b2d;p=oota-llvm.git diff --git a/utils/TableGen/LLVMCConfigurationEmitter.cpp b/utils/TableGen/LLVMCConfigurationEmitter.cpp index 6217f5c1d34..c40a39dff72 100644 --- a/utils/TableGen/LLVMCConfigurationEmitter.cpp +++ b/utils/TableGen/LLVMCConfigurationEmitter.cpp @@ -17,6 +17,7 @@ #include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringSet.h" + #include #include #include @@ -24,31 +25,33 @@ #include #include + using namespace llvm; +namespace { //===----------------------------------------------------------------------===// /// Typedefs typedef std::vector RecordVector; +typedef std::vector DagVector; typedef std::vector StrVector; //===----------------------------------------------------------------------===// /// Constants // Indentation. -static const unsigned TabWidth = 4; -static const unsigned Indent1 = TabWidth*1; -static const unsigned Indent2 = TabWidth*2; -static const unsigned Indent3 = TabWidth*3; +const unsigned TabWidth = 4; +const unsigned Indent1 = TabWidth*1; +const unsigned Indent2 = TabWidth*2; +const unsigned Indent3 = TabWidth*3; +const unsigned Indent4 = TabWidth*4; // Default help string. -static const char * const DefaultHelpString = "NO HELP MESSAGE PROVIDED"; +const char * const DefaultHelpString = "NO HELP MESSAGE PROVIDED"; // Name for the "sink" option. -static const char * const SinkOptionName = "AutoGeneratedSinkOption"; - -namespace { +const char * const SinkOptionName = "SinkOption"; //===----------------------------------------------------------------------===// /// Helper functions @@ -86,33 +89,32 @@ const DagInit& InitPtrToDag(const Init* ptr) { return val; } -const std::string GetOperatorName(const DagInit* D) { - return D->getOperator()->getAsString(); +const std::string GetOperatorName(const DagInit& D) { + return D.getOperator()->getAsString(); } -const std::string GetOperatorName(const DagInit& D) { - return GetOperatorName(&D); +/// CheckBooleanConstant - Check that the provided value is a boolean constant. +void CheckBooleanConstant(const Init* I) { + const DefInit& val = dynamic_cast(*I); + const std::string& str = val.getAsString(); + + if (str != "true" && str != "false") { + throw "Incorrect boolean value: '" + str + + "': must be either 'true' or 'false'"; + } } -// checkNumberOfArguments - Ensure that the number of args in d is +// CheckNumberOfArguments - Ensure that the number of args in d is // greater than or equal to min_arguments, otherwise throw an exception. -void checkNumberOfArguments (const DagInit* d, unsigned minArgs) { - if (!d || d->getNumArgs() < minArgs) +void CheckNumberOfArguments (const DagInit& d, unsigned minArgs) { + if (d.getNumArgs() < minArgs) throw GetOperatorName(d) + ": too few arguments!"; } -void checkNumberOfArguments (const DagInit& d, unsigned minArgs) { - checkNumberOfArguments(&d, minArgs); -} - -// 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). -std::string EscapeVariableName(const std::string& Var) { +std::string EscapeVariableName (const std::string& Var) { std::string ret; for (unsigned i = 0; i != Var.size(); ++i) { char cur_char = Var[i]; @@ -132,8 +134,23 @@ std::string EscapeVariableName(const std::string& Var) { return ret; } -/// oneOf - Does the input string contain this character? -bool oneOf(const char* lst, char c) { +/// EscapeQuotes - Replace '"' with '\"'. +std::string EscapeQuotes (const std::string& Var) { + std::string ret; + for (unsigned i = 0; i != Var.size(); ++i) { + char cur_char = Var[i]; + if (cur_char == '"') { + ret += "\\\""; + } + else { + ret.push_back(cur_char); + } + } + return ret; +} + +/// OneOf - Does the input string contain this character? +bool OneOf(const char* lst, char c) { while (*lst) { if (*lst++ == c) return true; @@ -142,24 +159,12 @@ bool oneOf(const char* lst, char c) { } template -void checkedIncrement(I& P, I E, S ErrorString) { +void CheckedIncrement(I& P, I E, S ErrorString) { ++P; if (P == E) 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 -void apply(F Fun, T0& Arg0) { - return Fun(Arg0); -} - -template -void apply(F Fun, T0& Arg0, T1& Arg1) { - return Fun(Arg0, Arg1); -} - //===----------------------------------------------------------------------===// /// Back-end specific code @@ -168,21 +173,25 @@ void apply(F Fun, T0& Arg0, T1& Arg1) { /// documentation for detailed description of differences. namespace OptionType { - enum OptionType { Alias, Switch, Parameter, ParameterList, - Prefix, PrefixList}; + enum OptionType { Alias, Switch, SwitchList, + Parameter, ParameterList, Prefix, PrefixList }; bool IsAlias(OptionType t) { return (t == Alias); } bool IsList (OptionType t) { - return (t == ParameterList || t == PrefixList); + return (t == SwitchList || t == ParameterList || t == PrefixList); } bool IsSwitch (OptionType t) { return (t == Switch); } + bool IsSwitchList (OptionType t) { + return (t == SwitchList); + } + bool IsParameter (OptionType t) { return (t == Parameter || t == Prefix); } @@ -194,6 +203,8 @@ OptionType::OptionType stringToOptionType(const std::string& T) { return OptionType::Alias; else if (T == "switch_option") return OptionType::Switch; + else if (T == "switch_list_option") + return OptionType::SwitchList; else if (T == "parameter_option") return OptionType::Parameter; else if (T == "parameter_list_option") @@ -208,9 +219,9 @@ OptionType::OptionType stringToOptionType(const std::string& T) { namespace OptionDescriptionFlags { enum OptionDescriptionFlags { Required = 0x1, Hidden = 0x2, - ReallyHidden = 0x4, Extern = 0x8, - OneOrMore = 0x10, Optional = 0x20, - CommaSeparated = 0x40 }; + ReallyHidden = 0x4, OneOrMore = 0x8, + Optional = 0x10, CommaSeparated = 0x20, + ForwardNotSplit = 0x40, ZeroOrMore = 0x80 }; } /// OptionDescription - Represents data contained in a single @@ -235,11 +246,20 @@ struct OptionDescription { /// 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); + /// CheckConsistency - Check that the flags are consistent. + void CheckConsistency() const; + // Misc convenient getters/setters. bool isAlias() const; @@ -249,8 +269,8 @@ struct OptionDescription { bool isCommaSeparated() const; void setCommaSeparated(); - bool isExtern() const; - void setExtern(); + bool isForwardNotSplit() const; + void setForwardNotSplit(); bool isRequired() const; void setRequired(); @@ -258,6 +278,9 @@ struct OptionDescription { bool isOneOrMore() const; void setOneOrMore(); + bool isZeroOrMore() const; + void setZeroOrMore(); + bool isOptional() const; void setOptional(); @@ -270,14 +293,39 @@ struct OptionDescription { bool isSwitch() const { return OptionType::IsSwitch(this->Type); } + bool isSwitchList() const + { return OptionType::IsSwitchList(this->Type); } + bool isParameter() const { return OptionType::IsParameter(this->Type); } 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 { + unsigned i = 0; + + i += this->isRequired(); + i += this->isOptional(); + i += this->isOneOrMore(); + i += this->isZeroOrMore(); + + if (i > 1) { + throw "Only one of (required), (optional), (one_or_more) or " + "(zero_or_more) properties is allowed!"; + } +} + void OptionDescription::Merge (const OptionDescription& other) { if (other.Type != Type) @@ -308,11 +356,11 @@ void OptionDescription::setCommaSeparated() { Flags |= OptionDescriptionFlags::CommaSeparated; } -bool OptionDescription::isExtern() const { - return Flags & OptionDescriptionFlags::Extern; +bool OptionDescription::isForwardNotSplit() const { + return Flags & OptionDescriptionFlags::ForwardNotSplit; } -void OptionDescription::setExtern() { - Flags |= OptionDescriptionFlags::Extern; +void OptionDescription::setForwardNotSplit() { + Flags |= OptionDescriptionFlags::ForwardNotSplit; } bool OptionDescription::isRequired() const { @@ -329,6 +377,13 @@ void OptionDescription::setOneOrMore() { Flags |= OptionDescriptionFlags::OneOrMore; } +bool OptionDescription::isZeroOrMore() const { + return Flags & OptionDescriptionFlags::ZeroOrMore; +} +void OptionDescription::setZeroOrMore() { + Flags |= OptionDescriptionFlags::ZeroOrMore; +} + bool OptionDescription::isOptional() const { return Flags & OptionDescriptionFlags::Optional; } @@ -359,6 +414,8 @@ const char* OptionDescription::GenTypeDeclaration() const { return "cl::list"; case OptionType::Switch: return "cl::opt"; + case OptionType::SwitchList: + return "cl::list"; case OptionType::Parameter: case OptionType::Prefix: default: @@ -366,20 +423,21 @@ const char* OptionDescription::GenTypeDeclaration() const { } } -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 "SwitchList_"; case OptionType::Prefix: case OptionType::Parameter: default: - return "AutoGeneratedParameter_" + EscapedName; + return "Parameter_"; } } @@ -399,9 +457,11 @@ public: // 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 @@ -431,10 +491,10 @@ OptionDescriptions::FindSwitch(const std::string& OptName) const { } 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; } @@ -455,6 +515,16 @@ OptionDescriptions::FindListOrParameter(const std::string& OptName) const { 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()) { @@ -499,15 +569,33 @@ public: }; +template +Handler GetHandler(FunctionObject* Obj, const DagInit& Dag) { + const std::string& HandlerName = GetOperatorName(Dag); + return Obj->GetHandler(HandlerName); +} + +template +void InvokeDagInitHandler(FunctionObject* Obj, Init* I) { + typedef void (FunctionObject::*Handler) (const DagInit&); + + const DagInit& Dag = InitPtrToDag(I); + Handler h = GetHandler(Obj, Dag); + + ((Obj)->*(h))(Dag); +} + template -void InvokeDagInitHandler(FunctionObject* Obj, Init* i) { - typedef void (FunctionObject::*Handler) (const DagInit*); +void InvokeDagInitHandler(const FunctionObject* const Obj, + const Init* I, unsigned IndentLevel, raw_ostream& O) +{ + typedef void (FunctionObject::*Handler) + (const DagInit&, unsigned IndentLevel, raw_ostream& O) const; - const DagInit& property = InitPtrToDag(i); - const std::string& property_name = GetOperatorName(property); - Handler h = Obj->GetHandler(property_name); + const DagInit& Dag = InitPtrToDag(I); + Handler h = GetHandler(Obj, Dag); - ((Obj)->*(h))(&property); + ((Obj)->*(h))(Dag, IndentLevel, O); } template @@ -521,7 +609,7 @@ bool HandlerTable::staticMembersInitialized_ = false; /// option property list. class CollectOptionProperties; typedef void (CollectOptionProperties::* CollectOptionPropertiesHandler) -(const DagInit*); +(const DagInit&); class CollectOptionProperties : public HandlerTable @@ -538,16 +626,18 @@ public: : optDesc_(OD) { if (!staticMembersInitialized_) { - AddHandler("extern", &CollectOptionProperties::onExtern); AddHandler("help", &CollectOptionProperties::onHelp); AddHandler("hidden", &CollectOptionProperties::onHidden); AddHandler("init", &CollectOptionProperties::onInit); AddHandler("multi_val", &CollectOptionProperties::onMultiVal); AddHandler("one_or_more", &CollectOptionProperties::onOneOrMore); + AddHandler("zero_or_more", &CollectOptionProperties::onZeroOrMore); AddHandler("really_hidden", &CollectOptionProperties::onReallyHidden); AddHandler("required", &CollectOptionProperties::onRequired); AddHandler("optional", &CollectOptionProperties::onOptional); AddHandler("comma_separated", &CollectOptionProperties::onCommaSeparated); + AddHandler("forward_not_split", + &CollectOptionProperties::onForwardNotSplit); staticMembersInitialized_ = true; } @@ -555,8 +645,8 @@ public: /// operator() - Just forwards to the corresponding property /// handler. - void operator() (Init* i) { - InvokeDagInitHandler(this, i); + void operator() (Init* I) { + InvokeDagInitHandler(this, I); } private: @@ -564,44 +654,45 @@ private: /// 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 = InitPtrToString(d->getArg(0)); + void onHelp (const DagInit& d) { + CheckNumberOfArguments(d, 1); + optDesc_.Help = EscapeQuotes(InitPtrToString(d.getArg(0))); } - void onHidden (const DagInit* d) { - checkNumberOfArguments(d, 0); + void onHidden (const DagInit& d) { + CheckNumberOfArguments(d, 0); optDesc_.setHidden(); } - void onReallyHidden (const DagInit* d) { - checkNumberOfArguments(d, 0); + void onReallyHidden (const DagInit& d) { + CheckNumberOfArguments(d, 0); optDesc_.setReallyHidden(); } - void onCommaSeparated (const DagInit* d) { - checkNumberOfArguments(d, 0); - if (!optDesc_.isList()) - throw "'comma_separated' is valid only on list options!"; + void onCommaSeparated (const DagInit& d) { + CheckNumberOfArguments(d, 0); + if (!optDesc_.isParameterList()) + throw "'comma_separated' is valid only on parameter list options!"; optDesc_.setCommaSeparated(); } - void onRequired (const DagInit* d) { - checkNumberOfArguments(d, 0); - if (optDesc_.isOneOrMore() || optDesc_.isOptional()) - throw "Only one of (required), (optional) or " - "(one_or_more) properties is allowed!"; + void onForwardNotSplit (const DagInit& d) { + CheckNumberOfArguments(d, 0); + if (!optDesc_.isParameter()) + throw "'forward_not_split' is valid only for parameter options!"; + optDesc_.setForwardNotSplit(); + } + + void onRequired (const DagInit& d) { + CheckNumberOfArguments(d, 0); + optDesc_.setRequired(); + optDesc_.CheckConsistency(); } - void onInit (const DagInit* d) { - checkNumberOfArguments(d, 1); - Init* i = d->getArg(0); + void onInit (const DagInit& d) { + CheckNumberOfArguments(d, 1); + Init* i = d.getArg(0); const std::string& str = i->getAsString(); bool correct = optDesc_.isParameter() && dynamic_cast(i); @@ -613,35 +704,42 @@ private: optDesc_.InitVal = i; } - void onOneOrMore (const DagInit* d) { - checkNumberOfArguments(d, 0); - if (optDesc_.isRequired() || optDesc_.isOptional()) - throw "Only one of (required), (optional) or " - "(one_or_more) properties is allowed!"; - if (!OptionType::IsList(optDesc_.Type)) - llvm::errs() << "Warning: specifying the 'one_or_more' property " - "on a non-list option will have no effect.\n"; + void onOneOrMore (const DagInit& d) { + CheckNumberOfArguments(d, 0); + optDesc_.setOneOrMore(); + optDesc_.CheckConsistency(); } - void onOptional (const DagInit* d) { - checkNumberOfArguments(d, 0); - if (optDesc_.isRequired() || optDesc_.isOneOrMore()) - throw "Only one of (required), (optional) or " - "(one_or_more) properties is allowed!"; - if (!OptionType::IsList(optDesc_.Type)) + void onZeroOrMore (const DagInit& d) { + CheckNumberOfArguments(d, 0); + + if (optDesc_.isList()) + llvm::errs() << "Warning: specifying the 'zero_or_more' property " + "on a list option has no effect.\n"; + + optDesc_.setZeroOrMore(); + optDesc_.CheckConsistency(); + } + + void onOptional (const DagInit& d) { + CheckNumberOfArguments(d, 0); + + if (!optDesc_.isList()) llvm::errs() << "Warning: specifying the 'optional' property" - "on a non-list option will have no effect.\n"; + "on a non-list option has no effect.\n"; + optDesc_.setOptional(); + optDesc_.CheckConsistency(); } - void onMultiVal (const DagInit* d) { - checkNumberOfArguments(d, 1); - int val = InitPtrToInt(d->getArg(0)); + void onMultiVal (const DagInit& d) { + CheckNumberOfArguments(d, 1); + int val = InitPtrToInt(d.getArg(0)); if (val < 2) throw "Error in the 'multi_val' property: " "the value must be greater than 1!"; - if (!OptionType::IsList(optDesc_.Type)) + if (!optDesc_.isParameterList()) throw "The multi_val property is valid only on list options!"; optDesc_.MultiVal = val; } @@ -660,7 +758,7 @@ public: void operator()(const Init* i) { const DagInit& d = InitPtrToDag(i); - checkNumberOfArguments(&d, 1); + CheckNumberOfArguments(d, 1); const OptionType::OptionType Type = stringToOptionType(GetOperatorName(d)); @@ -668,46 +766,51 @@ public: 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()) { - processOptionProperties(&d, OD); + 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); } private: /// processOptionProperties - Go through the list of option /// properties and call a corresponding handler for each. - static void processOptionProperties (const DagInit* d, OptionDescription& o) { - checkNumberOfArguments(d, 2); - DagInit::const_arg_iterator B = d->arg_begin(); + static void processOptionProperties (const DagInit& d, OptionDescription& o) { + CheckNumberOfArguments(d, 2); + DagInit::const_arg_iterator B = d.arg_begin(); // Skip the first argument: it's always the option name. ++B; - std::for_each(B, d->arg_end(), CollectOptionProperties(o)); + std::for_each(B, d.arg_end(), CollectOptionProperties(o)); } }; /// 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)); } } @@ -723,9 +826,12 @@ struct ToolDescription : public RefCountedBase { Init* CmdLine; Init* Actions; StrVector InLanguage; - std::string OutLanguage; + std::string InFileOption; + std::string OutFileOption; + StrVector OutLanguage; std::string OutputSuffix; unsigned Flags; + const Init* OnEmpty; // Various boolean properties void setSink() { Flags |= ToolFlags::Sink; } @@ -735,9 +841,9 @@ struct ToolDescription : public RefCountedBase { // Default ctor here is needed because StringMap can only store // DefaultConstructible objects - ToolDescription() : CmdLine(0), Actions(0), Flags(0) {} - ToolDescription (const std::string& n) - : Name(n), CmdLine(0), Actions(0), Flags(0) + ToolDescription (const std::string &n = "") + : Name(n), CmdLine(0), Actions(0), OutFileOption("-o"), + Flags(0), OnEmpty(0) {} }; @@ -750,7 +856,7 @@ typedef std::vector > ToolDescriptions; class CollectToolProperties; typedef void (CollectToolProperties::* CollectToolPropertiesHandler) -(const DagInit*); +(const DagInit&); class CollectToolProperties : public HandlerTable { @@ -768,19 +874,24 @@ public: if (!staticMembersInitialized_) { AddHandler("actions", &CollectToolProperties::onActions); - AddHandler("cmd_line", &CollectToolProperties::onCmdLine); + AddHandler("command", &CollectToolProperties::onCommand); AddHandler("in_language", &CollectToolProperties::onInLanguage); AddHandler("join", &CollectToolProperties::onJoin); AddHandler("out_language", &CollectToolProperties::onOutLanguage); + + AddHandler("out_file_option", &CollectToolProperties::onOutFileOption); + AddHandler("in_file_option", &CollectToolProperties::onInFileOption); + AddHandler("output_suffix", &CollectToolProperties::onOutputSuffix); AddHandler("sink", &CollectToolProperties::onSink); + AddHandler("works_on_empty", &CollectToolProperties::onWorksOnEmpty); staticMembersInitialized_ = true; } } - void operator() (Init* i) { - InvokeDagInitHandler(this, i); + void operator() (Init* I) { + InvokeDagInitHandler(this, I); } private: @@ -789,78 +900,84 @@ private: /// Functions that extract information about tool properties from /// DAG representation. - void onActions (const DagInit* d) { - checkNumberOfArguments(d, 1); - Init* Case = d->getArg(0); + void onActions (const DagInit& d) { + CheckNumberOfArguments(d, 1); + Init* Case = d.getArg(0); if (typeid(*Case) != typeid(DagInit) || - GetOperatorName(static_cast(Case)) != "case") + GetOperatorName(static_cast(*Case)) != "case") throw "The argument to (actions) should be a 'case' construct!"; toolDesc_.Actions = Case; } - void onCmdLine (const DagInit* d) { - checkNumberOfArguments(d, 1); - toolDesc_.CmdLine = d->getArg(0); + void onCommand (const DagInit& d) { + CheckNumberOfArguments(d, 1); + toolDesc_.CmdLine = d.getArg(0); } - void onInLanguage (const DagInit* d) { - checkNumberOfArguments(d, 1); - Init* arg = d->getArg(0); + /// onInOutLanguage - Common implementation of on{In,Out}Language(). + void onInOutLanguage (const DagInit& d, StrVector& OutVec) { + CheckNumberOfArguments(d, 1); - // 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); + void onJoin (const DagInit& d) { + CheckNumberOfArguments(d, 0); toolDesc_.setJoin(); } - void onOutLanguage (const DagInit* d) { - checkNumberOfArguments(d, 1); - toolDesc_.OutLanguage = InitPtrToString(d->getArg(0)); + void onOutLanguage (const DagInit& d) { + this->onInOutLanguage(d, toolDesc_.OutLanguage); + } + + void onOutFileOption (const DagInit& d) { + CheckNumberOfArguments(d, 1); + toolDesc_.OutFileOption = InitPtrToString(d.getArg(0)); + } + + void onInFileOption (const DagInit& d) { + CheckNumberOfArguments(d, 1); + toolDesc_.InFileOption = InitPtrToString(d.getArg(0)); } - void onOutputSuffix (const DagInit* d) { - checkNumberOfArguments(d, 1); - toolDesc_.OutputSuffix = InitPtrToString(d->getArg(0)); + void onOutputSuffix (const DagInit& d) { + CheckNumberOfArguments(d, 1); + toolDesc_.OutputSuffix = InitPtrToString(d.getArg(0)); } - void onSink (const DagInit* d) { - checkNumberOfArguments(d, 0); + void onSink (const DagInit& d) { + CheckNumberOfArguments(d, 0); toolDesc_.setSink(); } + void onWorksOnEmpty (const DagInit& d) { + toolDesc_.OnEmpty = d.getArg(0); + } + }; /// 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"); @@ -876,30 +993,17 @@ void CollectToolDescriptions (RecordVector::const_iterator B, /// 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"); - - 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((*B)->getValueAsInt("priority")); - - if (++B != E) - throw "More than one 'PluginPriority' instance found: " - "most probably an error!"; +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 (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. @@ -919,18 +1023,18 @@ public: /// 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); @@ -945,49 +1049,62 @@ void FilterNotInGraph (const RecordVector& 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 >& ToolToInLang, - StringMap& ToolToOutLang) { + StringMap >& 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 > ToolToInLang; - StringMap ToolToOutLang; + StringMap > ToolToOutLang; FillInToolToLang(ToolDescs, ToolToInLang, ToolToOutLang); - StringMap::iterator IAE = ToolToOutLang.end(); - StringMap >::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::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 >::iterator IA = ToolToOutLang.find(NodeA); StringMap >::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!"; } } @@ -1033,12 +1150,12 @@ void WalkCase(const Init* Case, F1 TestCallback, F2 StatementCallback, throw "Case construct handler: no corresponding action " "found for the test " + Test.getAsString() + '!'; - TestCallback(&Test, IndentLevel, (i == 1)); + TestCallback(Test, IndentLevel, (i == 1)); } else { if (dynamic_cast(arg) - && GetOperatorName(static_cast(arg)) == "case") { + && GetOperatorName(static_cast(*arg)) == "case") { // Nested 'case'. WalkCase(arg, TestCallback, StatementCallback, IndentLevel + Indent1); } @@ -1063,14 +1180,23 @@ class ExtractOptionNames { if (ActionName == "forward" || ActionName == "forward_as" || ActionName == "forward_value" || ActionName == "forward_transformed_value" || - ActionName == "switch_on" || ActionName == "parameter_equals" || - ActionName == "element_in_list" || ActionName == "not_empty" || - ActionName == "empty") { - checkNumberOfArguments(&Stmt, 1); - const std::string& Name = InitPtrToString(Stmt.getArg(0)); - OptionNames_.insert(Name); - } - else if (ActionName == "and" || ActionName == "or") { + ActionName == "parameter_equals" || ActionName == "element_in_list") { + CheckNumberOfArguments(Stmt, 1); + + Init* Arg = Stmt.getArg(0); + 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") { for (unsigned i = 0, NumArgs = Stmt.getNumArgs(); i < NumArgs; ++i) { this->processDag(Stmt.getArg(i)); } @@ -1082,6 +1208,7 @@ public: {} 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(Statement); for (ListInit::const_iterator B = DagList.begin(), E = DagList.end(); @@ -1093,18 +1220,23 @@ public: } } - void operator()(const DagInit* Test, unsigned, bool) { - this->operator()(Test); + void operator()(const DagInit& Test, unsigned, bool) { + this->operator()(&Test); } void operator()(const Init* Statement, unsigned) { this->operator()(Statement); } }; +/// 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; @@ -1122,13 +1254,13 @@ void CheckForSuperfluousOptions (const RecordVector& Edges, // 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)) - WalkCase(Weight, ExtractOptionNames(nonSuperfluousOptions), Id()); + 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 @@ -1157,24 +1289,20 @@ bool EmitCaseTest0Args(const std::string& TestName, raw_ostream& O) { return false; } -/// EmitListTest - Helper function used by EmitCaseTest1ArgList(). +/// EmitMultipleArgumentTest - Helper function used by +/// EmitCaseTestMultipleArgs() template -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 << " || "; - 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_; @@ -1212,54 +1340,48 @@ public: }; -/// EmitCaseTest1ArgList - Helper function used by EmitCaseTest1Arg(); -bool EmitCaseTest1ArgList(const std::string& TestName, - const DagInit& d, - const OptionDescriptions& OptDescs, - raw_ostream& O) { - const ListInit& L = *static_cast(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") { @@ -1267,28 +1389,22 @@ bool EmitCaseTest1ArgStr(const std::string& TestName, // 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) { - checkNumberOfArguments(&d, 1); - if (typeid(*d.getArg(0)) == typeid(ListInit)) - return EmitCaseTest1ArgList(TestName, d, OptDescs, O); - else - return EmitCaseTest1ArgStr(TestName, d, OptDescs, 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); + return EmitCaseTest1Arg(TestName, d, OptDescs, O) || + EmitCaseTestMultipleArgs(TestName, d, OptDescs, O); } /// EmitCaseTest2Args - Helper function used by EmitCaseConstructHandler(). @@ -1297,7 +1413,7 @@ bool EmitCaseTest2Args(const std::string& TestName, unsigned IndentLevel, const OptionDescriptions& OptDescs, raw_ostream& O) { - checkNumberOfArguments(&d, 2); + CheckNumberOfArguments(d, 2); const std::string& OptName = InitPtrToString(d.getArg(0)); const std::string& OptArg = InitPtrToString(d.getArg(1)); @@ -1307,7 +1423,7 @@ bool EmitCaseTest2Args(const std::string& TestName, 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) @@ -1332,10 +1448,10 @@ void EmitLogicalOperationTest(const DagInit& d, const char* LogicOp, 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 << " ("; } @@ -1348,7 +1464,7 @@ void EmitLogicalOperationTest(const DagInit& d, const char* LogicOp, void EmitLogicalNot(const DagInit& d, unsigned IndentLevel, const OptionDescriptions& OptDescs, raw_ostream& O) { - checkNumberOfArguments(&d, 1); + CheckNumberOfArguments(d, 1); const DagInit& InnerTest = InitPtrToDag(d.getArg(0)); O << "! ("; EmitCaseTest(InnerTest, IndentLevel, OptDescs, O); @@ -1369,12 +1485,12 @@ void EmitCaseTest(const DagInit& d, unsigned IndentLevel, 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; else - throw TestName + ": unknown edge property!"; + throw "Unknown test '" + TestName + "' used in the 'case' construct!"; } @@ -1390,7 +1506,7 @@ public: : EmitElseIf_(EmitElseIf), OptDescs_(OptDescs), O_(O) {} - void operator()(const DagInit* Test, unsigned IndentLevel, bool FirstTest) + void operator()(const DagInit& Test, unsigned IndentLevel, bool FirstTest) { if (GetOperatorName(Test) == "default") { O_.indent(IndentLevel) << "else {\n"; @@ -1398,7 +1514,7 @@ public: else { O_.indent(IndentLevel) << ((!FirstTest && EmitElseIf_) ? "else if (" : "if ("); - EmitCaseTest(*Test, IndentLevel, OptDescs_, O_); + EmitCaseTest(Test, IndentLevel, OptDescs_, O_); O_ << ") {\n"; } } @@ -1416,10 +1532,12 @@ public: {} void operator() (const Init* Statement, unsigned IndentLevel) { + // Is this a nested 'case'? + bool IsCase = dynamic_cast(Statement) && + GetOperatorName(static_cast(*Statement)) == "case"; - // Ignore nested 'case' DAG. - if (!(dynamic_cast(Statement) && - GetOperatorName(static_cast(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(Statement); for (ListInit::const_iterator B = DagList.begin(), E = DagList.end(); @@ -1438,7 +1556,7 @@ public: /// EmitCaseConstructHandler - Emit code that handles the 'case' /// construct. Takes a function object that should emit code for every case /// clause. Implemented on top of WalkCase. -/// Callback's type is void F(Init* Statement, unsigned IndentLevel, +/// Callback's type is void F(const Init* Statement, unsigned IndentLevel, /// raw_ostream& O). /// EmitElseIf parameter controls the type of condition that is emitted ('if /// (..) {..} else if (..) {} .. else {..}' vs. 'if (..) {..} if(..) {..} @@ -1452,10 +1570,10 @@ void EmitCaseConstructHandler(const Init* Case, unsigned IndentLevel, EmitCaseStatementCallback(Callback, O), IndentLevel); } -/// TokenizeCmdline - converts from +/// TokenizeCmdLine - converts from /// "$CALL(HookName, 'Arg1', 'Arg2')/path -arg1 -arg2" to /// ["$CALL(", "HookName", "Arg1", "Arg2", ")/path", "-arg1", "-arg2"]. -void TokenizeCmdline(const std::string& CmdLine, StrVector& Out) { +void TokenizeCmdLine(const std::string& CmdLine, StrVector& Out) { const char* Delimiters = " \t\n\v\f\r"; enum TokenizerState { Normal, SpecialCommand, InsideSpecialCommand, InsideQuotationMarks } @@ -1477,7 +1595,7 @@ void TokenizeCmdline(const std::string& CmdLine, StrVector& Out) { cur_st = SpecialCommand; break; } - if (oneOf(Delimiters, cur_ch)) { + if (OneOf(Delimiters, cur_ch)) { // Skip whitespace B = CmdLine.find_first_not_of(Delimiters, B); if (B == std::string::npos) { @@ -1492,7 +1610,7 @@ void TokenizeCmdline(const std::string& CmdLine, StrVector& Out) { case SpecialCommand: - if (oneOf(Delimiters, cur_ch)) { + if (OneOf(Delimiters, cur_ch)) { cur_st = Normal; Out.push_back(""); continue; @@ -1505,7 +1623,7 @@ void TokenizeCmdline(const std::string& CmdLine, StrVector& Out) { break; case InsideSpecialCommand: - if (oneOf(Delimiters, cur_ch)) { + if (OneOf(Delimiters, cur_ch)) { continue; } if (cur_ch == '\'') { @@ -1544,7 +1662,7 @@ SubstituteCall (StrVector::const_iterator Pos, bool IsJoin, raw_ostream& O) { const char* errorMessage = "Syntax error in $CALL invocation!"; - checkedIncrement(Pos, End, errorMessage); + CheckedIncrement(Pos, End, errorMessage); const std::string& CmdName = *Pos; if (CmdName == ")") @@ -1556,7 +1674,7 @@ SubstituteCall (StrVector::const_iterator Pos, bool firstIteration = true; while (true) { - checkedIncrement(Pos, End, errorMessage); + CheckedIncrement(Pos, End, errorMessage); const std::string& Arg = *Pos; assert(Arg.size() != 0); @@ -1591,7 +1709,7 @@ SubstituteEnv (StrVector::const_iterator Pos, StrVector::const_iterator End, raw_ostream& O) { const char* errorMessage = "Syntax error in $ENV invocation!"; - checkedIncrement(Pos, End, errorMessage); + CheckedIncrement(Pos, End, errorMessage); const std::string& EnvName = *Pos; if (EnvName == ")") @@ -1601,7 +1719,7 @@ SubstituteEnv (StrVector::const_iterator Pos, O << EnvName; O << "\"))"; - checkedIncrement(Pos, End, errorMessage); + CheckedIncrement(Pos, End, errorMessage); return Pos; } @@ -1642,86 +1760,63 @@ void EmitCmdLineVecFill(const Init* CmdLine, const std::string& ToolName, bool IsJoin, unsigned IndentLevel, raw_ostream& O) { StrVector StrVec; - TokenizeCmdline(InitPtrToString(CmdLine), StrVec); + TokenizeCmdLine(InitPtrToString(CmdLine), StrVec); if (StrVec.empty()) throw "Tool '" + ToolName + "' has empty command line!"; - StrVector::const_iterator I = StrVec.begin(), E = StrVec.end(); + StrVector::const_iterator B = StrVec.begin(), E = StrVec.end(); - // If there is a hook invocation on the place of the first command, skip it. + // Emit the command itself. assert(!StrVec[0].empty()); + O.indent(IndentLevel) << "cmd = "; if (StrVec[0][0] == '$') { - while (I != E && (*I)[0] != ')' ) - ++I; - - // Skip the ')' symbol. - ++I; + B = SubstituteSpecialCommands(B, E, IsJoin, O); + ++B; } else { - ++I; + O << '"' << StrVec[0] << '"'; + ++B; } + O << ";\n"; - bool hasINFILE = false; + // Go through the command arguments. + assert(B <= E); + for (; B != E; ++B) { + const std::string& cmd = *B; - for (; I != E; ++I) { - const std::string& cmd = *I; assert(!cmd.empty()); O.indent(IndentLevel); + if (cmd.at(0) == '$') { - if (cmd == "$INFILE") { - hasINFILE = true; - if (IsJoin) { - O << "for (PathVector::const_iterator B = inFiles.begin()" - << ", E = inFiles.end();\n"; - O.indent(IndentLevel) << "B != E; ++B)\n"; - O.indent(IndentLevel + Indent1) << "vec.push_back(B->str());\n"; - } - else { - O << "vec.push_back(inFile.str());\n"; - } - } - else if (cmd == "$OUTFILE") { - O << "vec.push_back(\"\");\n"; - O.indent(IndentLevel) << "out_file_index = vec.size()-1;\n"; - } - else { - O << "vec.push_back("; - I = SubstituteSpecialCommands(I, E, IsJoin, O); - O << ");\n"; - } + O << "vec.push_back(std::make_pair(0, "; + B = SubstituteSpecialCommands(B, E, IsJoin, O); + O << "));\n"; } else { - O << "vec.push_back(\"" << cmd << "\");\n"; + O << "vec.push_back(std::make_pair(0, \"" << cmd << "\"));\n"; } } - if (!hasINFILE) - throw "Tool '" + ToolName + "' doesn't take any input!"; - O.indent(IndentLevel) << "cmd = "; - if (StrVec[0][0] == '$') - SubstituteSpecialCommands(StrVec.begin(), StrVec.end(), IsJoin, O); - else - O << '"' << StrVec[0] << '"'; - O << ";\n"; } -/// EmitCmdLineVecFillCallback - A function object wrapper around -/// EmitCmdLineVecFill(). Used by EmitGenerateActionMethod() as an -/// argument to EmitCaseConstructHandler(). -class EmitCmdLineVecFillCallback { - bool IsJoin; - const std::string& ToolName; - public: - EmitCmdLineVecFillCallback(bool J, const std::string& TN) - : IsJoin(J), ToolName(TN) {} +/// 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; - void operator()(const Init* Statement, unsigned IndentLevel, - raw_ostream& O) const - { - EmitCmdLineVecFill(Statement, ToolName, IsJoin, IndentLevel, O); - } -}; + 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 @@ -1737,45 +1832,61 @@ void EmitForwardOptionPropertyHandlingCode (const OptionDescription& D, switch (D.Type) { case OptionType::Switch: - O.indent(IndentLevel) << "vec.push_back(\"" << Name << "\");\n"; + O.indent(IndentLevel) + << "vec.push_back(std::make_pair(" << D.GenVariableName() + << ".getPosition(), \"" << Name << "\"));\n"; break; case OptionType::Parameter: - O.indent(IndentLevel) << "vec.push_back(\"" << Name << "\");\n"; - O.indent(IndentLevel) << "vec.push_back(" << D.GenVariableName() << ");\n"; + O.indent(IndentLevel) << "vec.push_back(std::make_pair(" + << D.GenVariableName() + <<".getPosition(), \"" << Name; + + if (!D.isForwardNotSplit()) { + O << "\"));\n"; + O.indent(IndentLevel) << "vec.push_back(std::make_pair(" + << D.GenVariableName() << ".getPosition(), " + << D.GenVariableName() << "));\n"; + } + else { + O << "=\" + " << D.GenVariableName() << "));\n"; + } break; case OptionType::Prefix: - O.indent(IndentLevel) << "vec.push_back(\"" << Name << "\" + " - << D.GenVariableName() << ");\n"; + O.indent(IndentLevel) << "vec.push_back(std::make_pair(" + << D.GenVariableName() << ".getPosition(), \"" + << Name << "\" + " + << D.GenVariableName() << "));\n"; break; case OptionType::PrefixList: - 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) << "vec.push_back(\"" << Name << "\" + " << "*B);\n"; + EmitForEachListElementCycleHeader(D, IndentLevel, O); + O.indent(IndentLevel1) << "vec.push_back(std::make_pair(pos, \"" + << Name << "\" + " << "*B));\n"; O.indent(IndentLevel1) << "++B;\n"; for (int i = 1, j = D.MultiVal; i < j; ++i) { - O.indent(IndentLevel1) << "vec.push_back(*B);\n"; + O.indent(IndentLevel1) << "vec.push_back(std::make_pair(pos, *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) << "vec.push_back(\"" << Name << "\");\n"; + EmitForEachListElementCycleHeader(D, IndentLevel, O); + O.indent(IndentLevel1) << "vec.push_back(std::make_pair(pos, \"" + << Name << "\"));\n"; for (int i = 0, j = D.MultiVal; i < j; ++i) { - O.indent(IndentLevel1) << "vec.push_back(*B);\n"; + O.indent(IndentLevel1) << "vec.push_back(std::make_pair(pos, *B));\n"; O.indent(IndentLevel1) << "++B;\n"; } + O.indent(IndentLevel) << "}\n"; + break; + case OptionType::SwitchList: + EmitForEachListElementCycleHeader(D, IndentLevel, O); + O.indent(IndentLevel1) << "vec.push_back(std::make_pair(pos, \"" + << Name << "\"));\n"; + O.indent(IndentLevel1) << "++B;\n"; O.indent(IndentLevel) << "}\n"; break; case OptionType::Alias: @@ -1786,22 +1897,23 @@ void EmitForwardOptionPropertyHandlingCode (const OptionDescription& D, /// ActionHandlingCallbackBase - Base class of EmitActionHandlersCallback and /// EmitPreprocessOptionsCallback. -struct ActionHandlingCallbackBase { +struct ActionHandlingCallbackBase +{ void onErrorDag(const DagInit& d, 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, unsigned IndentLevel, raw_ostream& O) const { - checkNumberOfArguments(&d, 1); + CheckNumberOfArguments(d, 1); O.indent(IndentLevel) << "llvm::errs() << \"" << InitPtrToString(d.getArg(0)) << "\";\n"; } @@ -1811,16 +1923,18 @@ struct ActionHandlingCallbackBase { /// EmitActionHandlersCallback - Emit code that handles actions. Used by /// EmitGenerateActionMethod() as an argument to EmitCaseConstructHandler(). class EmitActionHandlersCallback; + typedef void (EmitActionHandlersCallback::* EmitActionHandlersCallbackHandler) (const DagInit&, unsigned, raw_ostream&) const; -class EmitActionHandlersCallback -: public ActionHandlingCallbackBase, +class EmitActionHandlersCallback : + public ActionHandlingCallbackBase, public HandlerTable { - const OptionDescriptions& OptDescs; typedef EmitActionHandlersCallbackHandler Handler; + const OptionDescriptions& OptDescs; + /// EmitHookInvocation - Common code for hook invocation from actions. Used by /// onAppendCmd and onOutputSuffix. void EmitHookInvocation(const std::string& Str, @@ -1828,7 +1942,7 @@ class EmitActionHandlersCallback unsigned IndentLevel, raw_ostream& O) const { StrVector Out; - TokenizeCmdline(Str, Out); + TokenizeCmdLine(Str, Out); for (StrVector::const_iterator B = Out.begin(), E = Out.end(); B != E; ++B) { @@ -1848,15 +1962,16 @@ class EmitActionHandlersCallback void onAppendCmd (const DagInit& Dag, unsigned IndentLevel, raw_ostream& O) const { - checkNumberOfArguments(&Dag, 1); + CheckNumberOfArguments(Dag, 1); this->EmitHookInvocation(InitPtrToString(Dag.getArg(0)), - "vec.push_back(", ");\n", IndentLevel, O); + "vec.push_back(std::make_pair(65536, ", "));\n", + IndentLevel, O); } void onForward (const DagInit& Dag, unsigned IndentLevel, raw_ostream& O) const { - checkNumberOfArguments(&Dag, 1); + CheckNumberOfArguments(Dag, 1); const std::string& Name = InitPtrToString(Dag.getArg(0)); EmitForwardOptionPropertyHandlingCode(OptDescs.FindOption(Name), IndentLevel, "", O); @@ -1865,7 +1980,7 @@ class EmitActionHandlersCallback void onForwardAs (const DagInit& Dag, unsigned IndentLevel, raw_ostream& O) const { - checkNumberOfArguments(&Dag, 2); + CheckNumberOfArguments(Dag, 2); const std::string& Name = InitPtrToString(Dag.getArg(0)); const std::string& NewName = InitPtrToString(Dag.getArg(1)); EmitForwardOptionPropertyHandlingCode(OptDescs.FindOption(Name), @@ -1875,38 +1990,63 @@ class EmitActionHandlersCallback void onForwardValue (const DagInit& Dag, unsigned IndentLevel, raw_ostream& O) const { - checkNumberOfArguments(&Dag, 1); + 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 + ("forward_value is not allowed with switch_list"); + } if (D.isParameter()) { - O.indent(IndentLevel) << "vec.push_back(" - << D.GenVariableName() << ");\n"; + O.indent(IndentLevel) << "vec.push_back(std::make_pair(" + << D.GenVariableName() << ".getPosition(), " + << D.GenVariableName() << "));\n"; } else { - O.indent(IndentLevel) << "std::copy(" << D.GenVariableName() - << ".begin(), " << D.GenVariableName() - << ".end(), std::back_inserter(vec));\n"; + O.indent(IndentLevel) << "for (" << D.GenTypeDeclaration() + << "::iterator B = " << D.GenVariableName() + << ".begin(), \n"; + O.indent(IndentLevel + Indent1) << " E = " << D.GenVariableName() + << ".end(); B != E; ++B)\n"; + O.indent(IndentLevel) << "{\n"; + O.indent(IndentLevel + Indent1) + << "unsigned pos = " << D.GenVariableName() + << ".getPosition(B - " << D.GenVariableName() + << ".begin());\n"; + O.indent(IndentLevel + Indent1) + << "vec.push_back(std::make_pair(pos, *B));\n"; + O.indent(IndentLevel) << "}\n"; } } void onForwardTransformedValue (const DagInit& Dag, unsigned IndentLevel, raw_ostream& O) const { - checkNumberOfArguments(&Dag, 2); + 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(" + << (D.isList() ? "0" : "") << "), " + << "hooks::" << Hook << "(" << D.GenVariableName() + << (D.isParameter() ? ".c_str()" : "") << ")));\n"; + } - O.indent(IndentLevel) << "vec.push_back(" << "hooks::" - << Hook << "(" << D.GenVariableName() - << (D.isParameter() ? ".c_str()" : "") << "));\n"; + void onNoOutFile (const DagInit& Dag, + unsigned IndentLevel, raw_ostream& O) const + { + CheckNumberOfArguments(Dag, 0); + O.indent(IndentLevel) << "no_out_file = true;\n"; } void onOutputSuffix (const DagInit& Dag, unsigned IndentLevel, raw_ostream& O) const { - checkNumberOfArguments(&Dag, 1); + CheckNumberOfArguments(Dag, 1); this->EmitHookInvocation(InitPtrToString(Dag.getArg(0)), "output_suffix = ", ";\n", IndentLevel, O); } @@ -1939,97 +2079,53 @@ class EmitActionHandlersCallback AddHandler("forward_value", &EmitActionHandlersCallback::onForwardValue); AddHandler("forward_transformed_value", &EmitActionHandlersCallback::onForwardTransformedValue); + AddHandler("no_out_file", + &EmitActionHandlersCallback::onNoOutFile); AddHandler("output_suffix", &EmitActionHandlersCallback::onOutputSuffix); AddHandler("stop_compilation", &EmitActionHandlersCallback::onStopCompilation); AddHandler("unpack_values", &EmitActionHandlersCallback::onUnpackValues); + staticMembersInitialized_ = true; } } - void operator()(const Init* Statement, + void operator()(const Init* I, unsigned IndentLevel, raw_ostream& O) const { - const DagInit& Dag = InitPtrToDag(Statement); - const std::string& ActionName = GetOperatorName(Dag); - Handler h = GetHandler(ActionName); - - ((this)->*(h))(Dag, IndentLevel, O); + InvokeDagInitHandler(this, I, IndentLevel, O); } }; -bool IsOutFileIndexCheckRequiredStr (const Init* CmdLine) { - StrVector StrVec; - TokenizeCmdline(InitPtrToString(CmdLine), StrVec); - - for (StrVector::const_iterator I = StrVec.begin(), E = StrVec.end(); - I != E; ++I) { - if (*I == "$OUTFILE") - return false; - } - - return true; -} - -class IsOutFileIndexCheckRequiredStrCallback { - bool* ret_; - -public: - IsOutFileIndexCheckRequiredStrCallback(bool* ret) : ret_(ret) - {} - - void operator()(const Init* CmdLine) { - // Ignore nested 'case' DAG. - if (typeid(*CmdLine) == typeid(DagInit)) - return; - - if (IsOutFileIndexCheckRequiredStr(CmdLine)) - *ret_ = true; - } - - void operator()(const DagInit* Test, unsigned, bool) { - this->operator()(Test); - } - void operator()(const Init* Statement, unsigned) { - this->operator()(Statement); - } -}; - -bool IsOutFileIndexCheckRequiredCase (Init* CmdLine) { - bool ret = false; - WalkCase(CmdLine, Id(), IsOutFileIndexCheckRequiredStrCallback(&ret)); - return ret; -} - -/// IsOutFileIndexCheckRequired - Should we emit an "out_file_index != -1" check -/// in EmitGenerateActionMethod() ? -bool IsOutFileIndexCheckRequired (Init* CmdLine) { - if (typeid(*CmdLine) == typeid(StringInit)) - return IsOutFileIndexCheckRequiredStr(CmdLine); - else - return IsOutFileIndexCheckRequiredCase(CmdLine); -} - 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::vector vec;\n"; - O.indent(Indent2) << "bool stop_compilation = !HasChildren;\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 > 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 @@ -2038,51 +2134,76 @@ void EmitGenerateActionMethod (const ToolDescription& D, 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!"; - bool IndexCheckRequired = IsOutFileIndexCheckRequired(D.CmdLine); - O.indent(Indent2) << "int out_file_index" - << (IndexCheckRequired ? " = -1" : "") - << ";\n\n"; - - // Process the cmd_line property. - if (typeid(*D.CmdLine) == typeid(StringInit)) - EmitCmdLineVecFill(D.CmdLine, D.Name, IsJoin, Indent2, O); - else - EmitCaseConstructHandler(D.CmdLine, Indent2, - EmitCmdLineVecFillCallback(IsJoin, D.Name), - true, OptDescs, O); + // Process the 'command' property. + O << '\n'; + EmitCmdLineVecFill(D.CmdLine, D.Name, IsJoin, Indent2, O); + O << '\n'; - // For every understood option, emit handling code. + // Process the 'actions' list of this tool. if (D.Actions) EmitCaseConstructHandler(D.Actions, Indent2, EmitActionHandlersCallback(OptDescs), false, OptDescs, O); - O << '\n'; - O.indent(Indent2) - << "std::string out_file = OutFilename(" - << (IsJoin ? "sys::Path(),\n" : "inFile,\n"); - O.indent(Indent3) << "TempDir, stop_compilation, output_suffix).str();\n\n"; - if (IndexCheckRequired) - O.indent(Indent2) << "if (out_file_index != -1)\n"; - O.indent(IndexCheckRequired ? Indent3 : Indent2) - << "vec[out_file_index] = out_file;\n"; + // Input file (s) + if (!D.InFileOption.empty()) { + O.indent(Indent2) + << "vec.push_back(std::make_pair(InputFilenames.getPosition(0), \"" + << D.InFileOption << "\");\n"; + } + + if (IsJoin) { + O.indent(Indent2) + << "for (PathVector::const_iterator B = inFiles.begin(),\n"; + O.indent(Indent3) << "E = inFiles.end(); B != E; ++B)\n"; + O.indent(Indent2) << "{\n"; + O.indent(Indent3) << "vec.push_back(std::make_pair(" + << "InputFilenames.getPosition(B - inFiles.begin()), " + << "B->str()));\n"; + O.indent(Indent2) << "}\n"; + } + else { + O.indent(Indent2) << "vec.push_back(std::make_pair(" + << "InputFilenames.getPosition(0), inFile.str()));\n"; + } + + // Output file + O.indent(Indent2) << "if (!no_out_file) {\n"; + if (!D.OutFileOption.empty()) + O.indent(Indent3) << "vec.push_back(std::make_pair(65536, \"" + << D.OutFileOption << "\"));\n"; + + O.indent(Indent3) << "out_file = this->OutFilename(" + << (IsJoin ? "sys::Path(),\n" : "inFile,\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(Indent3) << "vec.insert(vec.end(), " - << SinkOptionName << ".begin(), " << SinkOptionName - << ".end());\n"; + O.indent(Indent2) << "if (!" << SinkOption << ".empty()) {\n"; + O.indent(Indent3) << "for (cl::list::iterator B = " + << SinkOption << ".begin(), E = " << SinkOption + << ".end(); B != E; ++B)\n"; + 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, vec, stop_compilation, out_file);\n"; + 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"; } @@ -2092,14 +2213,11 @@ void EmitGenerateActionMethods (const ToolDescription& ToolDesc, 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 { @@ -2116,11 +2234,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"; } @@ -2142,17 +2257,51 @@ void EmitIsJoinMethod (const ToolDescription& D, raw_ostream& O) { O.indent(Indent1) << "}\n\n"; } +/// EmitWorksOnEmptyCallback - Callback used by EmitWorksOnEmptyMethod in +/// conjunction with EmitCaseConstructHandler. +void EmitWorksOnEmptyCallback (const Init* Value, + unsigned IndentLevel, raw_ostream& O) { + CheckBooleanConstant(Value); + O.indent(IndentLevel) << "return " << Value->getAsString() << ";\n"; +} + +/// EmitWorksOnEmptyMethod - Emit the WorksOnEmpty() method for a given Tool +/// class. +void EmitWorksOnEmptyMethod (const ToolDescription& D, + const OptionDescriptions& OptDescs, + raw_ostream& O) +{ + O.indent(Indent1) << "bool WorksOnEmpty() const {\n"; + if (D.OnEmpty == 0) + O.indent(Indent2) << "return false;\n"; + else + EmitCaseConstructHandler(D.OnEmpty, Indent2, EmitWorksOnEmptyCallback, + /*EmitElseIf = */ true, OptDescs, O); + 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. @@ -2169,13 +2318,15 @@ void EmitToolClassDefinition (const ToolDescription& D, else O << "Tool"; - O << "{\nprivate:\n"; - O.indent(Indent1) << "static const char* InputLanguages_[];\n\n"; + O << " {\nprivate:\n"; + O.indent(Indent1) << "static const char* InputLanguages_[];\n"; + O.indent(Indent1) << "static const char* OutputLanguages_[];\n\n"; O << "public:\n"; EmitNameMethod(D, O); EmitInOutLanguageMethods(D, O); EmitIsJoinMethod(D, O); + EmitWorksOnEmptyMethod(D, OptDescs, O); EmitGenerateActionMethods(D, OptDescs, O); // Close class definition @@ -2188,8 +2339,7 @@ void EmitToolClassDefinition (const ToolDescription& D, /// 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 Aliases; @@ -2203,16 +2353,8 @@ void EmitOptionDefinitions (const OptionDescriptions& descs, continue; } - if (val.isExtern()) - O << "extern "; - O << val.GenTypeDeclaration() << ' ' - << val.GenVariableName(); - - if (val.isExtern()) { - O << ";\n"; - continue; - } + << val.GenPlainVariableName(); O << "(\"" << val.Name << "\"\n"; @@ -2225,12 +2367,15 @@ void EmitOptionDefinitions (const OptionDescriptions& descs, else O << ", cl::Required"; } - else if (val.isOneOrMore() && val.isList()) { - O << ", cl::OneOrMore"; - } - else if (val.isOptional() && val.isList()) { + + if (val.isOptional()) O << ", cl::Optional"; - } + + if (val.isOneOrMore()) + O << ", cl::OneOrMore"; + + if (val.isZeroOrMore()) + O << ", cl::ZeroOrMore"; if (val.isReallyHidden()) O << ", cl::ReallyHidden"; @@ -2260,7 +2405,7 @@ void EmitOptionDefinitions (const OptionDescriptions& descs, const OptionDescription& val = *B; O << val.GenTypeDeclaration() << ' ' - << val.GenVariableName() + << val.GenPlainVariableName() << "(\"" << val.Name << '\"'; const OptionDescription& D = descs.FindOption(val.Help); @@ -2271,20 +2416,45 @@ void EmitOptionDefinitions (const OptionDescriptions& descs, // Emit the sink option. if (HasSink) - O << (HasExterns ? "extern cl" : "cl") - << "::list " << SinkOptionName - << (HasExterns ? ";\n" : "(cl::Sink);\n"); + O << "cl::list " << SinkOptionName << "(cl::Sink);\n"; O << '\n'; } /// EmitPreprocessOptionsCallback - Helper function passed to /// EmitCaseConstructHandler() by EmitPreprocessOptions(). -class EmitPreprocessOptionsCallback : ActionHandlingCallbackBase { + +class EmitPreprocessOptionsCallback; + +typedef void +(EmitPreprocessOptionsCallback::* EmitPreprocessOptionsCallbackHandler) +(const DagInit&, unsigned, raw_ostream&) const; + +class EmitPreprocessOptionsCallback : + public ActionHandlingCallbackBase, + public HandlerTable +{ + typedef EmitPreprocessOptionsCallbackHandler Handler; + typedef void + (EmitPreprocessOptionsCallback::* HandlerImpl) + (const Init*, unsigned, raw_ostream&) const; + const OptionDescriptions& OptDescs_; - void onUnsetOption(Init* i, unsigned IndentLevel, raw_ostream& O) { - const std::string& OptName = InitPtrToString(i); + void onEachArgument(const DagInit& d, HandlerImpl h, + unsigned IndentLevel, raw_ostream& O) const + { + CheckNumberOfArguments(d, 1); + + for (unsigned i = 0, NumArgs = d.getNumArgs(); i < NumArgs; ++i) { + ((this)->*(h))(d.getArg(i), IndentLevel, O); + } + } + + void onUnsetOptionImpl(const Init* I, + unsigned IndentLevel, raw_ostream& O) const + { + const std::string& OptName = InitPtrToString(I); const OptionDescription& OptDesc = OptDescs_.FindOption(OptName); if (OptDesc.isSwitch()) { @@ -2301,52 +2471,115 @@ class EmitPreprocessOptionsCallback : ActionHandlingCallbackBase { } } - void processDag(const Init* I, unsigned IndentLevel, raw_ostream& O) + void onUnsetOption(const DagInit& d, + unsigned IndentLevel, raw_ostream& O) const { - const DagInit& d = InitPtrToDag(I); - const std::string& OpName = GetOperatorName(d); + this->onEachArgument(d, &EmitPreprocessOptionsCallback::onUnsetOptionImpl, + IndentLevel, O); + } + + void onSetOptionImpl(const DagInit& D, + unsigned IndentLevel, raw_ostream& O) const { + CheckNumberOfArguments(D, 2); - if (OpName == "warning") { - this->onWarningDag(d, IndentLevel, O); + 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) { + 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 (OpName == "error") { - this->onWarningDag(d, IndentLevel, O); + else if (OptDesc.isSwitch()) { + CheckBooleanConstant(Value); + O.indent(IndentLevel) << OptDesc.GenVariableName() + << " = " << Value->getAsString() << ";\n"; } - else if (OpName == "unset_option") { - checkNumberOfArguments(&d, 1); - Init* I = d.getArg(0); - if (typeid(*I) == typeid(ListInit)) { - const ListInit& DagList = *static_cast(I); - for (ListInit::const_iterator B = DagList.begin(), E = DagList.end(); - B != E; ++B) - this->onUnsetOption(*B, IndentLevel, O); - } - else { - this->onUnsetOption(I, IndentLevel, O); - } + else if (OptDesc.isParameter()) { + const std::string& Str = InitPtrToString(Value); + O.indent(IndentLevel) << OptDesc.GenVariableName() + << " = \"" << Str << "\";\n"; } else { - throw "Unknown operator in the option preprocessor: '" + OpName + "'!" - "\nOnly 'warning', 'error' and 'unset_option' are allowed."; + throw "Can't apply 'set_option' to alias option '" + OptName + "'!"; } } -public: + void onSetSwitch(const Init* I, + unsigned IndentLevel, raw_ostream& O) const { + const std::string& OptName = InitPtrToString(I); + const OptionDescription& OptDesc = OptDescs_.FindOption(OptName); + + if (OptDesc.isSwitch()) + O.indent(IndentLevel) << OptDesc.GenVariableName() << " = true;\n"; + else + throw "set_option: -" + OptName + " is not a switch option!"; + } + + void onSetOption(const DagInit& d, + unsigned IndentLevel, raw_ostream& O) const + { + CheckNumberOfArguments(d, 1); + + // 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; + } + } - void operator()(const Init* I, unsigned IndentLevel, raw_ostream& O) { - this->processDag(I, IndentLevel, O); + // Multiple argument form: (set_option "A"), (set_option "B", "C", "D") + this->onEachArgument(d, &EmitPreprocessOptionsCallback::onSetSwitch, + IndentLevel, O); } +public: + EmitPreprocessOptionsCallback(const OptionDescriptions& OptDescs) : OptDescs_(OptDescs) - {} + { + if (!staticMembersInitialized_) { + AddHandler("error", &EmitPreprocessOptionsCallback::onErrorDag); + AddHandler("warning", &EmitPreprocessOptionsCallback::onWarningDag); + AddHandler("unset_option", &EmitPreprocessOptionsCallback::onUnsetOption); + AddHandler("set_option", &EmitPreprocessOptionsCallback::onSetOption); + + staticMembersInitialized_ = true; + } + } + + void operator()(const Init* I, + unsigned IndentLevel, raw_ostream& O) const + { + InvokeDagInitHandler(this, I, IndentLevel, O); + } + }; -/// 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"); @@ -2359,58 +2592,102 @@ void EmitPreprocessOptions (const RecordKeeper& Records, 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 { - O << "void PopulateLanguageMapLocal(LanguageMap& langMap) {\n"; +private: + raw_ostream& O_; + +public: - // Get the relevant field out of RecordKeeper - const Record* LangMapRecord = Records.getDef("LanguageMap"); + explicit DoEmitPopulateLanguageMap (raw_ostream& O) : O_(O) { + if (!staticMembersInitialized_) { + AddHandler("lang_to_suffixes", + &DoEmitPopulateLanguageMap::onLangToSuffixes); - // It is allowed for a plugin to have no language map. - if (LangMapRecord) { + staticMembersInitialized_ = true; + } + } - ListInit* LangsToSuffixesList = LangMapRecord->getValueAsListInit("map"); - if (!LangsToSuffixesList) - throw "Error in the language map definition!"; + void operator() (Init* I) { + InvokeDagInitHandler(this, I); + } - for (unsigned i = 0; i < LangsToSuffixesList->size(); ++i) { - const Record* LangToSuffixes = LangsToSuffixesList->getElementAsRecord(i); +private: - const std::string& Lang = LangToSuffixes->getValueAsString("lang"); - const ListInit* Suffixes = LangToSuffixes->getValueAsListInit("suffixes"); + void onLangToSuffixes (const DagInit& d) { + CheckNumberOfArguments(d, 2); - for (unsigned i = 0; i < Suffixes->size(); ++i) - O.indent(Indent1) << "langMap[\"" - << InitPtrToString(Suffixes->getElement(i)) - << "\"] = \"" << Lang << "\";\n"; + const std::string& Lang = InitPtrToString(d.getArg(0)); + Init* Suffixes = d.getArg(1); + + // 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(\"" + CheckNumberOfArguments(d, 1); + O.indent(IndentLevel) << "PrintError(\"" << InitPtrToString(d.getArg(0)) << "\");\n"; + O.indent(IndentLevel) << "return -1;\n"; return; } else { @@ -2427,7 +2704,7 @@ void IncDecWeight (const Init* i, unsigned IndentLevel, /// 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. @@ -2438,40 +2715,48 @@ void EmitEdgeClass (unsigned N, const std::string& Target, // 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"; + 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)); - if (!isDagEmpty(Weight)) + const DagInit& Weight = InitPtrToDag(Edge.getArg(2)); EmitEdgeClass(i, NodeB, Weight, OptDescs, O); + } + else if (Name != "edge") { + throw "Unknown edge class: '" + Name + "'!"; + } + ++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) @@ -2482,24 +2767,27 @@ void EmitPopulateCompilationGraph (const RecordVector& EdgeVector, // 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"; } @@ -2540,23 +2828,24 @@ public: const std::string& Name = GetOperatorName(Dag); if (Name == "forward_transformed_value") { - checkNumberOfArguments(Dag, 2); + 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); } else if (Name == "append_cmd" || Name == "output_suffix") { - checkNumberOfArguments(Dag, 1); + CheckNumberOfArguments(Dag, 1); this->onCmdLine(InitPtrToString(Dag.getArg(0))); } } void onCmdLine(const std::string& Cmd) { StrVector cmds; - TokenizeCmdline(Cmd, cmds); + TokenizeCmdLine(Cmd, cmds); for (StrVector::const_iterator B = cmds.begin(), E = cmds.end(); B != E; ++B) { @@ -2564,7 +2853,7 @@ public: if (cmd == "$CALL") { unsigned NumArgs = 0; - checkedIncrement(B, E, "Syntax error in $CALL invocation!"); + CheckedIncrement(B, E, "Syntax error in $CALL invocation!"); const std::string& HookName = *B; if (HookName.at(0) == ')') @@ -2604,13 +2893,10 @@ public: 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); } @@ -2654,7 +2940,6 @@ void EmitHookDeclarations(const ToolDescriptions& ToolDescs, 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(); @@ -2673,23 +2958,6 @@ void EmitHookDeclarations(const ToolDescriptions& ToolDescs, 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 RP;\n\n"; } /// EmitIncludes - Emit necessary #include directives and some @@ -2697,8 +2965,7 @@ void EmitRegisterPlugin(int Priority, raw_ostream& O) { 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" @@ -2712,21 +2979,17 @@ void EmitIncludes(raw_ostream& O) { << "using namespace llvm;\n" << "using namespace llvmc;\n\n" - << "extern cl::opt 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 @@ -2740,46 +3003,27 @@ bool HasSink(const ToolDescriptions& ToolDescs) { 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); @@ -2789,27 +3033,27 @@ void CheckPluginData(PluginData& Data) { // Check that there are no options without side effects (specified // only in the OptionList). 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(), @@ -2819,18 +3063,23 @@ void EmitPluginCode(const PluginData& Data, raw_ostream& O) { // 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 } @@ -2842,13 +3091,13 @@ void EmitPluginCode(const PluginData& Data, raw_ostream& O) { /// 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); - 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.");