summaryrefslogtreecommitdiff
path: root/utils
diff options
context:
space:
mode:
authorAnton Korobeynikov <asl@math.spbu.ru>2008-03-23 08:57:20 +0000
committerAnton Korobeynikov <asl@math.spbu.ru>2008-03-23 08:57:20 +0000
commitac67b7ea8fcd530995d7aefd2ad0f04543789855 (patch)
treeed9601b834e843e454707c7b07595ce91e27acbd /utils
parentd59c517a8309faac030d98b37459ca18a204da5a (diff)
downloadllvm-ac67b7ea8fcd530995d7aefd2ad0f04543789855.tar.gz
llvm-ac67b7ea8fcd530995d7aefd2ad0f04543789855.tar.bz2
llvm-ac67b7ea8fcd530995d7aefd2ad0f04543789855.tar.xz
Add first proof-of-concept universal compiler driver framework based
on ideas mentioned in PR686. Written by Mikhail Glushenkov and contributed by Codedgers, Inc. Old llvmc will be removed soon after new one will have all its properties. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@48699 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'utils')
-rw-r--r--utils/TableGen/LLVMCCConfigurationEmitter.cpp935
-rw-r--r--utils/TableGen/LLVMCCConfigurationEmitter.h30
-rw-r--r--utils/TableGen/TableGen.cpp9
3 files changed, 973 insertions, 1 deletions
diff --git a/utils/TableGen/LLVMCCConfigurationEmitter.cpp b/utils/TableGen/LLVMCCConfigurationEmitter.cpp
new file mode 100644
index 0000000000..9431fe1784
--- /dev/null
+++ b/utils/TableGen/LLVMCCConfigurationEmitter.cpp
@@ -0,0 +1,935 @@
+//===- 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() {}
+
+ 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
+}
diff --git a/utils/TableGen/LLVMCCConfigurationEmitter.h b/utils/TableGen/LLVMCCConfigurationEmitter.h
new file mode 100644
index 0000000000..849f054013
--- /dev/null
+++ b/utils/TableGen/LLVMCCConfigurationEmitter.h
@@ -0,0 +1,30 @@
+//===- 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.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVMCCCONF_EMITTER_H
+#define LLVMCCCONF_EMITTER_H
+
+#include "TableGenBackend.h"
+
+namespace llvm {
+ class LLVMCCConfigurationEmitter : public TableGenBackend {
+ RecordKeeper &Records;
+ public:
+ explicit LLVMCCConfigurationEmitter(RecordKeeper &R) : Records(R) {}
+
+ // run - Output the asmwriter, returning true on failure.
+ void run(std::ostream &o);
+ };
+}
+
+#endif //LLVMCCCONF_EMITTER_H
diff --git a/utils/TableGen/TableGen.cpp b/utils/TableGen/TableGen.cpp
index b174ff8903..7f8987d5e6 100644
--- a/utils/TableGen/TableGen.cpp
+++ b/utils/TableGen/TableGen.cpp
@@ -31,6 +31,7 @@
#include "DAGISelEmitter.h"
#include "SubtargetEmitter.h"
#include "IntrinsicEmitter.h"
+#include "LLVMCCConfigurationEmitter.h"
#include <algorithm>
#include <cstdio>
#include <fstream>
@@ -41,11 +42,12 @@ enum ActionType {
PrintRecords,
GenEmitter,
GenRegisterEnums, GenRegister, GenRegisterHeader,
- GenInstrEnums, GenInstrs, GenAsmWriter,
+ GenInstrEnums, GenInstrs, GenAsmWriter,
GenCallingConv,
GenDAGISel,
GenSubtarget,
GenIntrinsic,
+ GenLLVMCCConf,
PrintEnums
};
@@ -76,6 +78,8 @@ namespace {
"Generate subtarget enumerations"),
clEnumValN(GenIntrinsic, "gen-intrinsic",
"Generate intrinsic information"),
+ clEnumValN(GenLLVMCCConf, "gen-llvmcc",
+ "Generate LLVMCC configuration library"),
clEnumValN(PrintEnums, "print-enums",
"Print enum values for a class"),
clEnumValEnd));
@@ -180,6 +184,9 @@ int main(int argc, char **argv) {
case GenIntrinsic:
IntrinsicEmitter(Records).run(*Out);
break;
+ case GenLLVMCCConf:
+ LLVMCCConfigurationEmitter(Records).run(*Out);
+ break;
case PrintEnums:
{
std::vector<Record*> Recs = Records.getAllDerivedDefinitions(Class);