| //===- LLVMCConfigurationEmitter.cpp - Generate LLVMCC config -------------===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open |
| // Source License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This tablegen backend is responsible for emitting LLVMCC configuration code. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "LLVMCCConfigurationEmitter.h" |
| #include "Record.h" |
| |
| #include "llvm/ADT/IntrusiveRefCntPtr.h" |
| #include "llvm/ADT/SmallVector.h" |
| #include "llvm/ADT/StringExtras.h" |
| #include "llvm/ADT/StringMap.h" |
| #include "llvm/Support/Streams.h" |
| |
| #include <algorithm> |
| #include <cassert> |
| #include <functional> |
| #include <string> |
| |
| using namespace llvm; |
| |
| namespace { |
| |
| //===----------------------------------------------------------------------===// |
| /// Typedefs |
| |
| typedef std::vector<Record*> RecordVector; |
| typedef std::vector<std::string> StrVector; |
| |
| //===----------------------------------------------------------------------===// |
| /// Constants |
| |
| // Indentation strings |
| const char * Indent1 = " "; |
| const char * Indent2 = " "; |
| const char * Indent3 = " "; |
| const char * Indent4 = " "; |
| |
| // Default help string |
| const char * DefaultHelpString = "NO HELP MESSAGE PROVIDED"; |
| |
| // Name for the "sink" option |
| const char * SinkOptionName = "AutoGeneratedSinkOption"; |
| |
| //===----------------------------------------------------------------------===// |
| /// Helper functions |
| |
| std::string InitPtrToString(Init* ptr) { |
| StringInit& val = dynamic_cast<StringInit&>(*ptr); |
| return val.getValue(); |
| } |
| |
| //===----------------------------------------------------------------------===// |
| /// Back-end specific code |
| |
| // A command-line option can have one of the following types: |
| // |
| // Switch - a simple switch w/o arguments, e.g. -O2 |
| // |
| // Parameter - an option that takes one(and only one) argument, e.g. -o file, |
| // --output=file |
| // |
| // ParameterList - same as Parameter, but more than one occurence |
| // of the option is allowed, e.g. -lm -lpthread |
| // |
| // Prefix - argument is everything after the prefix, |
| // e.g. -Wa,-foo,-bar, -DNAME=VALUE |
| // |
| // PrefixList - same as Prefix, but more than one option occurence is |
| // allowed |
| |
| namespace OptionType { |
| enum OptionType { Switch, Parameter, ParameterList, Prefix, PrefixList}; |
| } |
| |
| bool IsListOptionType (OptionType::OptionType t) { |
| return (t == OptionType::ParameterList || t == OptionType::PrefixList); |
| } |
| |
| // Code duplication here is necessary because one option can affect |
| // several tools and those tools may have different actions associated |
| // with this option. GlobalOptionDescriptions are used to generate |
| // the option registration code, while ToolOptionDescriptions are used |
| // to generate tool-specific code. |
| |
| // Base class for option descriptions |
| |
| struct OptionDescription { |
| OptionType::OptionType Type; |
| std::string Name; |
| |
| OptionDescription(OptionType::OptionType t = OptionType::Switch, |
| const std::string& n = "") |
| : Type(t), Name(n) |
| {} |
| |
| const char* GenTypeDeclaration() const { |
| switch (Type) { |
| case OptionType::PrefixList: |
| case OptionType::ParameterList: |
| return "cl::list<std::string>"; |
| case OptionType::Switch: |
| return "cl::opt<bool>"; |
| case OptionType::Parameter: |
| case OptionType::Prefix: |
| default: |
| return "cl::opt<std::string>"; |
| } |
| } |
| |
| std::string GenVariableName() const { |
| switch (Type) { |
| case OptionType::Switch: |
| return "AutoGeneratedSwitch" + Name; |
| case OptionType::Prefix: |
| return "AutoGeneratedPrefix" + Name; |
| case OptionType::PrefixList: |
| return "AutoGeneratedPrefixList" + Name; |
| case OptionType::Parameter: |
| return "AutoGeneratedParameter" + Name; |
| case OptionType::ParameterList: |
| default: |
| return "AutoGeneratedParameterList" + Name; |
| } |
| } |
| |
| }; |
| |
| // Global option description |
| |
| namespace GlobalOptionDescriptionFlags { |
| enum GlobalOptionDescriptionFlags { Required = 0x1 }; |
| } |
| |
| struct GlobalOptionDescription : public OptionDescription { |
| std::string Help; |
| unsigned Flags; |
| |
| // StringMap can only store DefaultConstructible objects |
| GlobalOptionDescription() : OptionDescription(), Flags(0) |
| {} |
| |
| GlobalOptionDescription (OptionType::OptionType t, const std::string& n) |
| : OptionDescription(t, n), Help(DefaultHelpString), Flags(0) |
| {} |
| |
| bool isRequired() const { |
| return Flags & GlobalOptionDescriptionFlags::Required; |
| } |
| void setRequired() { |
| Flags |= GlobalOptionDescriptionFlags::Required; |
| } |
| |
| // Merge two option descriptions |
| void Merge (const GlobalOptionDescription& other) |
| { |
| if (other.Type != Type) |
| throw "Conflicting definitions for the option " + Name + "!"; |
| |
| if (Help.empty() && !other.Help.empty()) |
| Help = other.Help; |
| else if (!Help.empty() && !other.Help.empty()) |
| cerr << "Warning: more than one help string defined for option " |
| + Name + "\n"; |
| |
| Flags |= other.Flags; |
| } |
| }; |
| |
| // A GlobalOptionDescription array |
| // + some flags affecting generation of option declarations |
| struct GlobalOptionDescriptions { |
| typedef StringMap<GlobalOptionDescription> container_type; |
| typedef container_type::const_iterator const_iterator; |
| |
| // A list of GlobalOptionDescriptions |
| container_type Descriptions; |
| // Should the emitter generate a "cl::sink" option? |
| bool HasSink; |
| |
| // Support for STL-style iteration |
| const_iterator begin() const { return Descriptions.begin(); } |
| const_iterator end() const { return Descriptions.end(); } |
| }; |
| |
| |
| // Tool-local option description |
| |
| // Properties without arguments are implemented as flags |
| namespace ToolOptionDescriptionFlags { |
| enum ToolOptionDescriptionFlags { StopCompilation = 0x1, |
| Forward = 0x2, UnpackValues = 0x4}; |
| } |
| namespace OptionPropertyType { |
| enum OptionPropertyType { AppendCmd }; |
| } |
| |
| typedef std::pair<OptionPropertyType::OptionPropertyType, std::string> |
| OptionProperty; |
| typedef SmallVector<OptionProperty, 4> OptionPropertyList; |
| |
| struct ToolOptionDescription : public OptionDescription { |
| unsigned Flags; |
| OptionPropertyList Props; |
| |
| // StringMap can only store DefaultConstructible objects |
| ToolOptionDescription() : OptionDescription(), Flags(0) {} |
| |
| ToolOptionDescription (OptionType::OptionType t, const std::string& n) |
| : OptionDescription(t, n) |
| {} |
| |
| // Various boolean properties |
| bool isStopCompilation() const { |
| return Flags & ToolOptionDescriptionFlags::StopCompilation; |
| } |
| void setStopCompilation() { |
| Flags |= ToolOptionDescriptionFlags::StopCompilation; |
| } |
| |
| bool isForward() const { |
| return Flags & ToolOptionDescriptionFlags::Forward; |
| } |
| void setForward() { |
| Flags |= ToolOptionDescriptionFlags::Forward; |
| } |
| |
| bool isUnpackValues() const { |
| return Flags & ToolOptionDescriptionFlags::UnpackValues; |
| } |
| void setUnpackValues() { |
| Flags |= ToolOptionDescriptionFlags::UnpackValues; |
| } |
| |
| void AddProperty (OptionPropertyType::OptionPropertyType t, |
| const std::string& val) |
| { |
| Props.push_back(std::make_pair(t, val)); |
| } |
| }; |
| |
| typedef StringMap<ToolOptionDescription> ToolOptionDescriptions; |
| |
| // Tool information record |
| |
| namespace ToolFlags { |
| enum ToolFlags { Join = 0x1, Sink = 0x2 }; |
| } |
| |
| struct ToolProperties : public RefCountedBase<ToolProperties> { |
| std::string Name; |
| StrVector CmdLine; |
| std::string InLanguage; |
| std::string OutLanguage; |
| std::string OutputSuffix; |
| unsigned Flags; |
| ToolOptionDescriptions OptDescs; |
| |
| // Various boolean properties |
| void setSink() { Flags |= ToolFlags::Sink; } |
| bool isSink() const { return Flags & ToolFlags::Sink; } |
| void setJoin() { Flags |= ToolFlags::Join; } |
| bool isJoin() const { return Flags & ToolFlags::Join; } |
| |
| // Default ctor here is needed because StringMap can only store |
| // DefaultConstructible objects |
| ToolProperties() {} |
| ToolProperties (const std::string& n) : Name(n) {} |
| }; |
| |
| |
| // A list of Tool information records |
| // IntrusiveRefCntPtrs are used because StringMap has no copy constructor |
| // (and we want to avoid copying ToolProperties anyway) |
| typedef std::vector<IntrusiveRefCntPtr<ToolProperties> > ToolPropertiesList; |
| |
| |
| // Function object for iterating over a list of tool property records |
| class CollectProperties { |
| private: |
| |
| /// Implementation details |
| |
| // "Property handler" - a function that extracts information |
| // about a given tool property from its DAG representation |
| typedef void (CollectProperties::*PropertyHandler)(DagInit*); |
| |
| // Map from property names -> property handlers |
| typedef StringMap<PropertyHandler> PropertyHandlerMap; |
| |
| // "Option property handler" - a function that extracts information |
| // about a given option property from its DAG representation |
| typedef void (CollectProperties::* |
| OptionPropertyHandler)(DagInit*, GlobalOptionDescription &); |
| |
| // Map from option property names -> option property handlers |
| typedef StringMap<OptionPropertyHandler> OptionPropertyHandlerMap; |
| |
| // Static maps from strings to CollectProperties methods("handlers") |
| static PropertyHandlerMap propertyHandlers_; |
| static OptionPropertyHandlerMap optionPropertyHandlers_; |
| static bool staticMembersInitialized_; |
| |
| |
| /// This is where the information is stored |
| |
| // Current Tool properties |
| ToolProperties& toolProps_; |
| // OptionDescriptions table(used to register options globally) |
| GlobalOptionDescriptions& optDescs_; |
| |
| public: |
| |
| explicit CollectProperties (ToolProperties& p, GlobalOptionDescriptions& d) |
| : toolProps_(p), optDescs_(d) |
| { |
| if (!staticMembersInitialized_) { |
| // Init tool property handlers |
| propertyHandlers_["cmd_line"] = &CollectProperties::onCmdLine; |
| propertyHandlers_["in_language"] = &CollectProperties::onInLanguage; |
| propertyHandlers_["join"] = &CollectProperties::onJoin; |
| propertyHandlers_["out_language"] = &CollectProperties::onOutLanguage; |
| propertyHandlers_["output_suffix"] = &CollectProperties::onOutputSuffix; |
| propertyHandlers_["parameter_option"] |
| = &CollectProperties::onParameter; |
| propertyHandlers_["parameter_list_option"] = |
| &CollectProperties::onParameterList; |
| propertyHandlers_["prefix_option"] = &CollectProperties::onPrefix; |
| propertyHandlers_["prefix_list_option"] = |
| &CollectProperties::onPrefixList; |
| propertyHandlers_["sink"] = &CollectProperties::onSink; |
| propertyHandlers_["switch_option"] = &CollectProperties::onSwitch; |
| |
| // Init option property handlers |
| optionPropertyHandlers_["append_cmd"] = &CollectProperties::onAppendCmd; |
| optionPropertyHandlers_["forward"] = &CollectProperties::onForward; |
| optionPropertyHandlers_["help"] = &CollectProperties::onHelp; |
| optionPropertyHandlers_["required"] = &CollectProperties::onRequired; |
| optionPropertyHandlers_["stop_compilation"] = |
| &CollectProperties::onStopCompilation; |
| optionPropertyHandlers_["unpack_values"] = |
| &CollectProperties::onUnpackValues; |
| |
| staticMembersInitialized_ = true; |
| } |
| } |
| |
| // Gets called for every tool property; |
| // Just forwards to the corresponding property handler. |
| void operator() (Init* i) { |
| DagInit& d = dynamic_cast<DagInit&>(*i); |
| std::string property_name = d.getOperator()->getAsString(); |
| PropertyHandlerMap::iterator method |
| = propertyHandlers_.find(property_name); |
| |
| if (method != propertyHandlers_.end()) { |
| PropertyHandler h = method->second; |
| (this->*h)(&d); |
| } |
| else { |
| throw "Unknown tool property: " + property_name + "!"; |
| } |
| } |
| |
| private: |
| |
| /// Property handlers -- |
| /// Functions that extract information about tool properties from |
| /// DAG representation. |
| |
| void onCmdLine (DagInit* d) { |
| checkNumberOfArguments(d, 1); |
| SplitString(InitPtrToString(d->getArg(0)), toolProps_.CmdLine); |
| if (toolProps_.CmdLine.empty()) |
| throw std::string("Tool " + toolProps_.Name + " has empty command line!"); |
| } |
| |
| void onInLanguage (DagInit* d) { |
| checkNumberOfArguments(d, 1); |
| toolProps_.InLanguage = InitPtrToString(d->getArg(0)); |
| } |
| |
| void onJoin (DagInit* d) { |
| checkNumberOfArguments(d, 0); |
| toolProps_.setJoin(); |
| } |
| |
| void onOutLanguage (DagInit* d) { |
| checkNumberOfArguments(d, 1); |
| toolProps_.OutLanguage = InitPtrToString(d->getArg(0)); |
| } |
| |
| void onOutputSuffix (DagInit* d) { |
| checkNumberOfArguments(d, 1); |
| toolProps_.OutputSuffix = InitPtrToString(d->getArg(0)); |
| } |
| |
| void onSink (DagInit* d) { |
| checkNumberOfArguments(d, 0); |
| optDescs_.HasSink = true; |
| toolProps_.setSink(); |
| } |
| |
| void onSwitch (DagInit* d) { addOption(d, OptionType::Switch); } |
| void onParameter (DagInit* d) { addOption(d, OptionType::Parameter); } |
| void onParameterList (DagInit* d) { addOption(d, OptionType::ParameterList); } |
| void onPrefix (DagInit* d) { addOption(d, OptionType::Prefix); } |
| void onPrefixList (DagInit* d) { addOption(d, OptionType::PrefixList); } |
| |
| /// Option property handlers -- |
| /// Methods that handle properties that are common for all types of |
| /// options (like append_cmd, stop_compilation) |
| |
| void onAppendCmd (DagInit* d, GlobalOptionDescription& o) { |
| checkNumberOfArguments(d, 1); |
| std::string const& cmd = InitPtrToString(d->getArg(0)); |
| |
| toolProps_.OptDescs[o.Name].AddProperty(OptionPropertyType::AppendCmd, cmd); |
| } |
| |
| void onForward (DagInit* d, GlobalOptionDescription& o) { |
| checkNumberOfArguments(d, 0); |
| toolProps_.OptDescs[o.Name].setForward(); |
| } |
| |
| void onHelp (DagInit* d, GlobalOptionDescription& o) { |
| checkNumberOfArguments(d, 1); |
| const std::string& help_message = InitPtrToString(d->getArg(0)); |
| |
| o.Help = help_message; |
| } |
| |
| void onRequired (DagInit* d, GlobalOptionDescription& o) { |
| checkNumberOfArguments(d, 0); |
| o.setRequired(); |
| } |
| |
| void onStopCompilation (DagInit* d, GlobalOptionDescription& o) { |
| checkNumberOfArguments(d, 0); |
| if (o.Type != OptionType::Switch) |
| throw std::string("Only options of type Switch can stop compilation!"); |
| toolProps_.OptDescs[o.Name].setStopCompilation(); |
| } |
| |
| void onUnpackValues (DagInit* d, GlobalOptionDescription& o) { |
| checkNumberOfArguments(d, 0); |
| toolProps_.OptDescs[o.Name].setUnpackValues(); |
| } |
| |
| /// Helper functions |
| |
| // Add an option of type t |
| void addOption (DagInit* d, OptionType::OptionType t) { |
| checkNumberOfArguments(d, 2); |
| const std::string& name = InitPtrToString(d->getArg(0)); |
| |
| GlobalOptionDescription o(t, name); |
| toolProps_.OptDescs[name].Type = t; |
| toolProps_.OptDescs[name].Name = name; |
| processOptionProperties(d, o); |
| insertDescription(o); |
| } |
| |
| // Ensure that the number of args in d is <= min_arguments, |
| // throw exception otherwise |
| void checkNumberOfArguments (DagInit* d, unsigned min_arguments) { |
| if (d->getNumArgs() < min_arguments) |
| throw "Property " + d->getOperator()->getAsString() |
| + " has too few arguments!"; |
| } |
| |
| // Insert new GlobalOptionDescription into GlobalOptionDescriptions list |
| void insertDescription (const GlobalOptionDescription& o) |
| { |
| if (optDescs_.Descriptions.count(o.Name)) { |
| GlobalOptionDescription& D = optDescs_.Descriptions[o.Name]; |
| D.Merge(o); |
| } |
| else { |
| optDescs_.Descriptions[o.Name] = o; |
| } |
| } |
| |
| // Go through the list of option properties and call a corresponding |
| // handler for each. |
| // |
| // Parameters: |
| // name - option name |
| // d - option property list |
| void processOptionProperties (DagInit* d, GlobalOptionDescription& o) { |
| // First argument is option name |
| checkNumberOfArguments(d, 2); |
| |
| for (unsigned B = 1, E = d->getNumArgs(); B!=E; ++B) { |
| DagInit& option_property |
| = dynamic_cast<DagInit&>(*d->getArg(B)); |
| const std::string& option_property_name |
| = option_property.getOperator()->getAsString(); |
| OptionPropertyHandlerMap::iterator method |
| = optionPropertyHandlers_.find(option_property_name); |
| |
| if (method != optionPropertyHandlers_.end()) { |
| OptionPropertyHandler h = method->second; |
| (this->*h)(&option_property, o); |
| } |
| else { |
| throw "Unknown option property: " + option_property_name + "!"; |
| } |
| } |
| } |
| }; |
| |
| // Static members of CollectProperties |
| CollectProperties::PropertyHandlerMap |
| CollectProperties::propertyHandlers_; |
| |
| CollectProperties::OptionPropertyHandlerMap |
| CollectProperties::optionPropertyHandlers_; |
| |
| bool CollectProperties::staticMembersInitialized_ = false; |
| |
| |
| // Gather information from the parsed TableGen data |
| // (Basically a wrapper for CollectProperties) |
| void CollectToolProperties (RecordVector::const_iterator B, |
| RecordVector::const_iterator E, |
| ToolPropertiesList& TPList, |
| GlobalOptionDescriptions& OptDescs) |
| { |
| // Iterate over a properties list of every Tool definition |
| for (;B!=E;++B) { |
| RecordVector::value_type T = *B; |
| ListInit* PropList = T->getValueAsListInit("properties"); |
| if (!PropList) |
| throw std::string("Tool has no property list!"); |
| |
| IntrusiveRefCntPtr<ToolProperties> |
| ToolProps(new ToolProperties(T->getName())); |
| |
| std::for_each(PropList->begin(), PropList->end(), |
| CollectProperties(*ToolProps, OptDescs)); |
| TPList.push_back(ToolProps); |
| } |
| } |
| |
| // Used by EmitGenerateActionMethod |
| void EmitOptionPropertyHandlingCode (const ToolProperties& P, |
| const ToolOptionDescription& D, |
| std::ostream& O) |
| { |
| // if clause |
| O << Indent2 << "if ("; |
| if (D.Type == OptionType::Switch) |
| O << D.GenVariableName(); |
| else |
| O << '!' << D.GenVariableName() << ".empty()"; |
| |
| O <<") {\n"; |
| |
| // Handle option properties that take an argument |
| for (OptionPropertyList::const_iterator B = D.Props.begin(), |
| E = D.Props.end(); B!=E; ++B) { |
| const OptionProperty& val = *B; |
| |
| switch (val.first) { |
| // (append_cmd cmd) property |
| case OptionPropertyType::AppendCmd: |
| O << Indent3 << "vec.push_back(\"" << val.second << "\");\n"; |
| break; |
| // Other properties with argument |
| default: |
| break; |
| } |
| } |
| |
| // Handle flags |
| |
| // (forward) property |
| if (D.isForward()) { |
| switch (D.Type) { |
| case OptionType::Switch: |
| O << Indent3 << "vec.push_back(\"-" << D.Name << "\");\n"; |
| break; |
| case OptionType::Parameter: |
| O << Indent3 << "vec.push_back(\"-" << D.Name << "\");\n"; |
| O << Indent3 << "vec.push_back(" << D.GenVariableName() << ");\n"; |
| break; |
| case OptionType::Prefix: |
| O << Indent3 << "vec.push_back(\"-" << D.Name << "\" + " |
| << D.GenVariableName() << ");\n"; |
| break; |
| case OptionType::PrefixList: |
| O << Indent3 << "for (" << D.GenTypeDeclaration() |
| << "::iterator B = " << D.GenVariableName() << ".begin(),\n" |
| << Indent3 << "E = " << D.GenVariableName() << ".end(); B != E; ++B)\n" |
| << Indent4 << "vec.push_back(\"-" << D.Name << "\" + " |
| << "*B);\n"; |
| break; |
| case OptionType::ParameterList: |
| O << Indent3 << "for (" << D.GenTypeDeclaration() |
| << "::iterator B = " << D.GenVariableName() << ".begin(),\n" |
| << Indent3 << "E = " << D.GenVariableName() |
| << ".end() ; B != E; ++B) {\n" |
| << Indent4 << "vec.push_back(\"-" << D.Name << "\");\n" |
| << Indent4 << "vec.push_back(*B);\n" |
| << Indent3 << "}\n"; |
| break; |
| } |
| } |
| |
| // (unpack_values) property |
| if (D.isUnpackValues()) { |
| if (IsListOptionType(D.Type)) { |
| O << Indent3 << "for (" << D.GenTypeDeclaration() |
| << "::iterator B = " << D.GenVariableName() << ".begin(),\n" |
| << Indent3 << "E = " << D.GenVariableName() |
| << ".end(); B != E; ++B)\n" |
| << Indent4 << "UnpackValues(*B, vec);\n"; |
| } |
| else if (D.Type == OptionType::Prefix || D.Type == OptionType::Parameter){ |
| O << Indent3 << "UnpackValues(" |
| << D.GenVariableName() << ", vec);\n"; |
| } |
| else { |
| // TOFIX: move this to the type-checking phase |
| throw std::string("Switches can't have unpack_values property!"); |
| } |
| } |
| |
| // close if clause |
| O << Indent2 << "}\n"; |
| } |
| |
| // Emite one of two versions of GenerateAction method |
| void EmitGenerateActionMethod (const ToolProperties& P, int V, std::ostream& O) |
| { |
| assert(V==1 || V==2); |
| if (V==1) |
| O << Indent1 << "Action GenerateAction(const PathVector& inFiles,\n"; |
| else |
| O << Indent1 << "Action GenerateAction(const sys::Path& inFile,\n"; |
| |
| O << Indent2 << "const sys::Path& outFile) const\n" |
| << Indent1 << "{\n" |
| << Indent2 << "std::vector<std::string> vec;\n"; |
| |
| // Parse CmdLine tool property |
| StrVector::const_iterator I = P.CmdLine.begin(); |
| ++I; |
| for (StrVector::const_iterator E = P.CmdLine.end(); I != E; ++I) { |
| const std::string& cmd = *I; |
| O << Indent2; |
| if (cmd == "$INFILE") { |
| if (V==1) |
| O << "for (PathVector::const_iterator B = inFiles.begin()" |
| << ", E = inFiles.end();\n" |
| << Indent2 << "B != E; ++B)\n" |
| << Indent3 << "vec.push_back(B->toString());\n"; |
| else |
| O << "vec.push_back(inFile.toString());\n"; |
| } |
| else if (cmd == "$OUTFILE") { |
| O << "vec.push_back(outFile.toString());\n"; |
| } |
| else { |
| O << "vec.push_back(\"" << cmd << "\");\n"; |
| } |
| } |
| |
| // For every understood option, emit handling code |
| for (ToolOptionDescriptions::const_iterator B = P.OptDescs.begin(), |
| E = P.OptDescs.end(); B != E; ++B) { |
| const ToolOptionDescription& val = B->second; |
| EmitOptionPropertyHandlingCode(P, val, O); |
| } |
| |
| // Handle Sink property |
| if (P.isSink()) { |
| O << Indent2 << "if (!" << SinkOptionName << ".empty()) {\n" |
| << Indent3 << "vec.insert(vec.end(), " |
| << SinkOptionName << ".begin(), " << SinkOptionName << ".end());\n" |
| << Indent2 << "}\n"; |
| } |
| |
| O << Indent2 << "return Action(\"" << P.CmdLine.at(0) << "\", vec);\n" |
| << Indent1 << "}\n\n"; |
| } |
| |
| // Emit GenerateAction methods for Tool classes |
| void EmitGenerateActionMethods (const ToolProperties& P, std::ostream& O) { |
| |
| if (!P.isJoin()) |
| O << Indent1 << "Action GenerateAction(const PathVector& inFiles,\n" |
| << Indent2 << "const llvm::sys::Path& outFile) const\n" |
| << Indent1 << "{\n" |
| << Indent2 << "throw std::runtime_error(\"" << P.Name |
| << " is not a Join tool!\");\n" |
| << Indent1 << "}\n\n"; |
| else |
| EmitGenerateActionMethod(P, 1, O); |
| |
| EmitGenerateActionMethod(P, 2, O); |
| } |
| |
| // Emit IsLast() method for Tool classes |
| void EmitIsLastMethod (const ToolProperties& P, std::ostream& O) { |
| O << Indent1 << "bool IsLast() const {\n" |
| << Indent2 << "bool last = false;\n"; |
| |
| for (ToolOptionDescriptions::const_iterator B = P.OptDescs.begin(), |
| E = P.OptDescs.end(); B != E; ++B) { |
| const ToolOptionDescription& val = B->second; |
| |
| if (val.isStopCompilation()) |
| O << Indent2 |
| << "if (" << val.GenVariableName() |
| << ")\n" << Indent3 << "last = true;\n"; |
| } |
| |
| O << Indent2 << "return last;\n" |
| << Indent1 << "}\n\n"; |
| } |
| |
| // Emit static [Input,Output]Language() methods for Tool classes |
| void EmitInOutLanguageMethods (const ToolProperties& P, std::ostream& O) { |
| O << Indent1 << "std::string InputLanguage() const {\n" |
| << Indent2 << "return \"" << P.InLanguage << "\";\n" |
| << Indent1 << "}\n\n"; |
| |
| O << Indent1 << "std::string OutputLanguage() const {\n" |
| << Indent2 << "return \"" << P.OutLanguage << "\";\n" |
| << Indent1 << "}\n\n"; |
| } |
| |
| // Emit static [Input,Output]Language() methods for Tool classes |
| void EmitOutputSuffixMethod (const ToolProperties& P, std::ostream& O) { |
| O << Indent1 << "std::string OutputSuffix() const {\n" |
| << Indent2 << "return \"" << P.OutputSuffix << "\";\n" |
| << Indent1 << "}\n\n"; |
| } |
| |
| // Emit static Name() method for Tool classes |
| void EmitNameMethod (const ToolProperties& P, std::ostream& O) { |
| O << Indent1 << "std::string Name() const {\n" |
| << Indent2 << "return \"" << P.Name << "\";\n" |
| << Indent1 << "}\n\n"; |
| } |
| |
| // Emit static Name() method for Tool classes |
| void EmitIsJoinMethod (const ToolProperties& P, std::ostream& O) { |
| O << Indent1 << "bool IsJoin() const {\n"; |
| if (P.isJoin()) |
| O << Indent2 << "return true;\n"; |
| else |
| O << Indent2 << "return false;\n"; |
| O << Indent1 << "}\n\n"; |
| } |
| |
| // Emit a Tool class definition |
| void EmitToolClassDefinition (const ToolProperties& P, std::ostream& O) { |
| // Header |
| O << "class " << P.Name << " : public Tool {\n" |
| << "public:\n"; |
| |
| EmitNameMethod(P, O); |
| EmitInOutLanguageMethods(P, O); |
| EmitOutputSuffixMethod(P, O); |
| EmitIsJoinMethod(P, O); |
| EmitGenerateActionMethods(P, O); |
| EmitIsLastMethod(P, O); |
| |
| // Close class definition |
| O << "};\n\n"; |
| } |
| |
| // Iterate over a list of option descriptions and emit registration code |
| void EmitOptionDescriptions (const GlobalOptionDescriptions& descs, |
| std::ostream& O) |
| { |
| // Emit static cl::Option variables |
| for (GlobalOptionDescriptions::const_iterator B = descs.begin(), |
| E = descs.end(); B!=E; ++B) { |
| const GlobalOptionDescription& val = B->second; |
| |
| O << val.GenTypeDeclaration() << ' ' |
| << val.GenVariableName() |
| << "(\"" << val.Name << '\"'; |
| |
| if (val.Type == OptionType::Prefix || val.Type == OptionType::PrefixList) |
| O << ", cl::Prefix"; |
| |
| if (val.isRequired()) { |
| switch (val.Type) { |
| case OptionType::PrefixList: |
| case OptionType::ParameterList: |
| O << ", cl::OneOrMore"; |
| break; |
| default: |
| O << ", cl::Required"; |
| } |
| } |
| |
| O << ", cl::desc(\"" << val.Help << "\"));\n"; |
| } |
| |
| if (descs.HasSink) |
| O << "cl::list<std::string> " << SinkOptionName << "(cl::Sink);\n"; |
| |
| O << '\n'; |
| } |
| |
| void EmitPopulateLanguageMap (const RecordKeeper& Records, std::ostream& O) |
| { |
| // Get the relevant field out of RecordKeeper |
| Record* LangMapRecord = Records.getDef("LanguageMap"); |
| if (!LangMapRecord) |
| throw std::string("Language map definition not found!"); |
| |
| ListInit* LangsToSuffixesList = LangMapRecord->getValueAsListInit("map"); |
| if (!LangsToSuffixesList) |
| throw std::string("Error in the language map definition!"); |
| |
| // Generate code |
| O << "void llvmcc::PopulateLanguageMap(LanguageMap& language_map) {\n"; |
| |
| for (unsigned i = 0; i < LangsToSuffixesList->size(); ++i) { |
| Record* LangToSuffixes = LangsToSuffixesList->getElementAsRecord(i); |
| |
| const std::string& Lang = LangToSuffixes->getValueAsString("lang"); |
| const ListInit* Suffixes = LangToSuffixes->getValueAsListInit("suffixes"); |
| |
| for (unsigned i = 0; i < Suffixes->size(); ++i) |
| O << Indent1 << "language_map[\"" |
| << InitPtrToString(Suffixes->getElement(i)) |
| << "\"] = \"" << Lang << "\";\n"; |
| } |
| |
| O << "}\n\n"; |
| } |
| |
| void EmitPopulateCompilationGraph (const RecordKeeper& Records, |
| StringMap<std::string>& ToolToLang, |
| std::ostream& O) |
| { |
| // Get the relevant field out of RecordKeeper |
| Record* ToolChains = Records.getDef("ToolChains"); |
| if (!ToolChains) |
| throw std::string("No ToolChains specification found!"); |
| ListInit* chains = ToolChains->getValueAsListInit("chains"); |
| if (!chains) |
| throw std::string("Error in toolchain list definition!"); |
| |
| // Generate code |
| O << "void llvmcc::PopulateCompilationGraph(CompilationGraph& G) {\n" |
| << Indent1 << "PopulateLanguageMap(G.ExtsToLangs);\n" |
| << Indent1 << "std::vector<IntrusiveRefCntPtr<Tool> > vec;\n\n"; |
| |
| for (unsigned i = 0; i < chains->size(); ++i) { |
| Record* ToolChain = chains->getElementAsRecord(i); |
| ListInit* Tools = ToolChain->getValueAsListInit("tools"); |
| |
| // Get name of the first tool in the list |
| const std::string& firstTool = |
| dynamic_cast<DefInit&>(**Tools->begin()).getDef()->getName(); |
| |
| for (ListInit::iterator B = Tools->begin(), |
| E = Tools->end(); B != E; ++B) { |
| Record* val = dynamic_cast<DefInit&>(**B).getDef(); |
| O << Indent1 << "vec.push_back(IntrusiveRefCntPtr<Tool>(new " |
| << val->getName() << "()));\n"; |
| } |
| O << Indent1 << "G.ToolChains[\"" << ToolToLang[firstTool] |
| << "\"] = vec;\n"; |
| O << Indent1 << "vec.clear();\n\n"; |
| } |
| |
| O << "}\n\n"; |
| } |
| |
| void FillInToolToLang (const ToolPropertiesList& T, |
| StringMap<std::string>& M) { |
| for (ToolPropertiesList::const_iterator B = T.begin(), E = T.end(); |
| B != E; ++B) { |
| const ToolProperties& P = *(*B); |
| M[P.Name] = P.InLanguage; |
| } |
| } |
| |
| // End of anonymous namespace |
| } |
| |
| // Back-end entry point |
| void LLVMCCConfigurationEmitter::run (std::ostream &O) { |
| // Emit file header |
| EmitSourceFileHeader("LLVMCC Configuration Library", O); |
| |
| // Get a list of all defined Tools |
| RecordVector Tools = Records.getAllDerivedDefinitions("Tool"); |
| if (Tools.empty()) |
| throw std::string("No tool definitions found!"); |
| |
| // Gather information from the Tool descriptions |
| ToolPropertiesList tool_props; |
| GlobalOptionDescriptions opt_descs; |
| CollectToolProperties(Tools.begin(), Tools.end(), tool_props, opt_descs); |
| |
| // Emit global option registration code |
| EmitOptionDescriptions(opt_descs, O); |
| |
| // Emit PopulateLanguageMap function |
| // (a language map maps from file extensions to language names) |
| EmitPopulateLanguageMap(Records, O); |
| |
| // Emit Tool classes |
| for (ToolPropertiesList::const_iterator B = tool_props.begin(), |
| E = tool_props.end(); B!=E; ++B) |
| EmitToolClassDefinition(*(*B), O); |
| |
| // Fill in table that maps tool names to languages |
| StringMap<std::string> ToolToLang; |
| FillInToolToLang(tool_props, ToolToLang); |
| |
| // Emit PopulateCompilationGraph function |
| EmitPopulateCompilationGraph(Records, ToolToLang, O); |
| |
| // EOF |
| } |