llvm/utils/TableGen/LLVMCCConfigurationEmitter.cpp
Anton Korobeynikov ac67b7ea8f 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
2008-03-23 08:57:20 +00:00

936 lines
29 KiB
C++

//===- 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
}