llvm-6502/utils/TableGen/LLVMCConfigurationEmitter.cpp
David Greene d4a9066c93 [AVX] Make Inits Foldable
Manage Inits in a FoldingSet.  This provides several benefits:

- Memory for Inits is properly managed

- Duplicate Inits are folded into Flyweights, saving memory

- It enforces const-correctness, protecting against certain classes
  of bugs

The above benefits allow Inits to be used in more contexts, which in
turn provides more dynamism to TableGen.  This enhanced capability
will be used by the AVX code generator to a fold common patterns
together.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@134907 91177308-0d34-0410-b5e6-96231b3b80d8
2011-07-11 18:25:51 +00:00

3135 lines
95 KiB
C++

//===- LLVMCConfigurationEmitter.cpp - Generate LLVMC config ----*- C++ -*-===//
//
// 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 LLVMC configuration code.
//
//===----------------------------------------------------------------------===//
#include "LLVMCConfigurationEmitter.h"
#include "Record.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringSet.h"
#include <algorithm>
#include <cassert>
#include <functional>
#include <stdexcept>
#include <string>
#include <typeinfo>
using namespace llvm;
namespace {
//===----------------------------------------------------------------------===//
/// Typedefs
typedef std::vector<Record*> RecordVector;
typedef std::vector<const DagInit*> DagVector;
typedef std::vector<std::string> StrVector;
//===----------------------------------------------------------------------===//
/// Constants
// Indentation.
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.
const char * const DefaultHelpString = "NO HELP MESSAGE PROVIDED";
// Name for the "sink" option.
const char * const SinkOptionName = "SinkOption";
//===----------------------------------------------------------------------===//
/// Helper functions
/// Id - An 'identity' function object.
struct Id {
template<typename T0>
void operator()(const T0&) const {
}
template<typename T0, typename T1>
void operator()(const T0&, const T1&) const {
}
template<typename T0, typename T1, typename T2>
void operator()(const T0&, const T1&, const T2&) const {
}
};
int InitPtrToInt(const Init* ptr) {
const IntInit& val = dynamic_cast<const IntInit&>(*ptr);
return val.getValue();
}
bool InitPtrToBool(const Init* ptr) {
bool ret = false;
const DefInit& val = dynamic_cast<const DefInit&>(*ptr);
const std::string& str = val.getAsString();
if (str == "true") {
ret = true;
}
else if (str == "false") {
ret = false;
}
else {
throw "Incorrect boolean value: '" + str +
"': must be either 'true' or 'false'";
}
return ret;
}
const std::string& InitPtrToString(const Init* ptr) {
const StringInit& val = dynamic_cast<const StringInit&>(*ptr);
return val.getValue();
}
const ListInit& InitPtrToList(const Init* ptr) {
const ListInit& val = dynamic_cast<const ListInit&>(*ptr);
return val;
}
const DagInit& InitPtrToDag(const Init* ptr) {
const DagInit& val = dynamic_cast<const DagInit&>(*ptr);
return val;
}
const std::string GetOperatorName(const DagInit& D) {
return D.getOperator()->getAsString();
}
/// CheckBooleanConstant - Check that the provided value is a boolean constant.
void CheckBooleanConstant(const Init* I) {
InitPtrToBool(I);
}
// 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.getNumArgs() < minArgs)
throw GetOperatorName(d) + ": too few arguments!";
}
// 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 ret;
for (unsigned i = 0; i != Var.size(); ++i) {
char cur_char = Var[i];
if (cur_char == ',') {
ret += "_comma_";
}
else if (cur_char == '+') {
ret += "_plus_";
}
else if (cur_char == '-') {
ret += "_dash_";
}
else {
ret.push_back(cur_char);
}
}
return ret;
}
/// 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;
}
return false;
}
template <class I, class S>
void CheckedIncrement(I& P, I E, S ErrorString) {
++P;
if (P == E)
throw ErrorString;
}
//===----------------------------------------------------------------------===//
/// Back-end specific code
/// OptionType - One of six different option types. See the
/// documentation for detailed description of differences.
namespace OptionType {
enum OptionType { Alias, Switch, SwitchList,
Parameter, ParameterList, Prefix, PrefixList };
bool IsAlias(OptionType t) {
return (t == Alias);
}
bool IsList (OptionType t) {
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);
}
}
OptionType::OptionType stringToOptionType(const std::string& T) {
if (T == "alias_option")
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")
return OptionType::ParameterList;
else if (T == "prefix_option")
return OptionType::Prefix;
else if (T == "prefix_list_option")
return OptionType::PrefixList;
else
throw "Unknown option type: " + T + '!';
}
namespace OptionDescriptionFlags {
enum OptionDescriptionFlags { Required = 0x1, Hidden = 0x2,
ReallyHidden = 0x4, OneOrMore = 0x8,
Optional = 0x10, CommaSeparated = 0x20,
ForwardNotSplit = 0x40, ZeroOrMore = 0x80 };
}
/// OptionDescription - Represents data contained in a single
/// OptionList entry.
struct OptionDescription {
OptionType::OptionType Type;
std::string Name;
unsigned Flags;
std::string Help;
unsigned MultiVal;
const Init* InitVal;
OptionDescription(OptionType::OptionType t = OptionType::Switch,
const std::string& n = "",
const std::string& h = DefaultHelpString)
: Type(t), Name(n), Flags(0x0), Help(h), MultiVal(1), InitVal(0)
{}
/// GenTypeDeclaration - Returns the C++ variable type of this
/// option.
const char* GenTypeDeclaration() const;
/// GenVariableName - Returns the variable name used in the
/// generated C++ code.
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;
bool isMultiVal() const;
bool isCommaSeparated() const;
void setCommaSeparated();
bool isForwardNotSplit() const;
void setForwardNotSplit();
bool isRequired() const;
void setRequired();
bool isOneOrMore() const;
void setOneOrMore();
bool isZeroOrMore() const;
void setZeroOrMore();
bool isOptional() const;
void setOptional();
bool isHidden() const;
void setHidden();
bool isReallyHidden() const;
void setReallyHidden();
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)
throw "Conflicting definitions for the option " + Name + "!";
if (Help == other.Help || Help == DefaultHelpString)
Help = other.Help;
else if (other.Help != DefaultHelpString) {
llvm::errs() << "Warning: several different help strings"
" defined for option " + Name + "\n";
}
Flags |= other.Flags;
}
bool OptionDescription::isAlias() const {
return OptionType::IsAlias(this->Type);
}
bool OptionDescription::isMultiVal() const {
return MultiVal > 1;
}
bool OptionDescription::isCommaSeparated() const {
return Flags & OptionDescriptionFlags::CommaSeparated;
}
void OptionDescription::setCommaSeparated() {
Flags |= OptionDescriptionFlags::CommaSeparated;
}
bool OptionDescription::isForwardNotSplit() const {
return Flags & OptionDescriptionFlags::ForwardNotSplit;
}
void OptionDescription::setForwardNotSplit() {
Flags |= OptionDescriptionFlags::ForwardNotSplit;
}
bool OptionDescription::isRequired() const {
return Flags & OptionDescriptionFlags::Required;
}
void OptionDescription::setRequired() {
Flags |= OptionDescriptionFlags::Required;
}
bool OptionDescription::isOneOrMore() const {
return Flags & OptionDescriptionFlags::OneOrMore;
}
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;
}
void OptionDescription::setOptional() {
Flags |= OptionDescriptionFlags::Optional;
}
bool OptionDescription::isHidden() const {
return Flags & OptionDescriptionFlags::Hidden;
}
void OptionDescription::setHidden() {
Flags |= OptionDescriptionFlags::Hidden;
}
bool OptionDescription::isReallyHidden() const {
return Flags & OptionDescriptionFlags::ReallyHidden;
}
void OptionDescription::setReallyHidden() {
Flags |= OptionDescriptionFlags::ReallyHidden;
}
const char* OptionDescription::GenTypeDeclaration() const {
switch (Type) {
case OptionType::Alias:
return "cl::alias";
case OptionType::PrefixList:
case OptionType::ParameterList:
return "cl::list<std::string>";
case OptionType::Switch:
return "cl::opt<bool>";
case OptionType::SwitchList:
return "cl::list<bool>";
case OptionType::Parameter:
case OptionType::Prefix:
default:
return "cl::opt<std::string>";
}
}
std::string OptionDescription::GenOptionType() const {
switch (Type) {
case OptionType::Alias:
return "Alias_";
case OptionType::PrefixList:
case OptionType::ParameterList:
return "List_";
case OptionType::Switch:
return "Switch_";
case OptionType::SwitchList:
return "SwitchList_";
case OptionType::Prefix:
case OptionType::Parameter:
default:
return "Parameter_";
}
}
/// OptionDescriptions - An OptionDescription array plus some helper
/// functions.
class OptionDescriptions {
typedef StringMap<OptionDescription> container_type;
/// Descriptions - A list of OptionDescriptions.
container_type Descriptions;
public:
/// FindOption - exception-throwing wrapper for find().
const OptionDescription& FindOption(const std::string& OptName) const;
// Wrappers for FindOption that throw an exception in case the option has a
// wrong type.
const OptionDescription& FindSwitch(const std::string& OptName) const;
const OptionDescription& FindParameter(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
void InsertDescription (const OptionDescription& o);
// Support for STL-style iteration
typedef container_type::const_iterator const_iterator;
const_iterator begin() const { return Descriptions.begin(); }
const_iterator end() const { return Descriptions.end(); }
};
const OptionDescription&
OptionDescriptions::FindOption(const std::string& OptName) const {
const_iterator I = Descriptions.find(OptName);
if (I != Descriptions.end())
return I->second;
else
throw OptName + ": no such option!";
}
const OptionDescription&
OptionDescriptions::FindSwitch(const std::string& OptName) const {
const OptionDescription& OptDesc = this->FindOption(OptName);
if (!OptDesc.isSwitch())
throw OptName + ": incorrect option type - should be a switch!";
return OptDesc;
}
const OptionDescription&
OptionDescriptions::FindParameterList(const std::string& OptName) const {
const OptionDescription& OptDesc = this->FindOption(OptName);
if (!OptDesc.isList() || OptDesc.isSwitchList())
throw OptName + ": incorrect option type - should be a parameter list!";
return OptDesc;
}
const OptionDescription&
OptionDescriptions::FindParameter(const std::string& OptName) const {
const OptionDescription& OptDesc = this->FindOption(OptName);
if (!OptDesc.isParameter())
throw OptName + ": incorrect option type - should be a parameter!";
return OptDesc;
}
const OptionDescription&
OptionDescriptions::FindListOrParameter(const std::string& OptName) const {
const OptionDescription& OptDesc = this->FindOption(OptName);
if (!OptDesc.isList() && !OptDesc.isParameter())
throw OptName
+ ": incorrect option type - should be a list or parameter!";
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()) {
OptionDescription& D = I->second;
D.Merge(o);
}
else {
Descriptions[o.Name] = o;
}
}
/// HandlerTable - A base class for function objects implemented as
/// 'tables of handlers'.
template <typename Handler>
class HandlerTable {
protected:
// Implementation details.
/// HandlerMap - A map from property names to property handlers
typedef StringMap<Handler> HandlerMap;
static HandlerMap Handlers_;
static bool staticMembersInitialized_;
public:
Handler GetHandler (const std::string& HandlerName) const {
typename HandlerMap::iterator method = Handlers_.find(HandlerName);
if (method != Handlers_.end()) {
Handler h = method->second;
return h;
}
else {
throw "No handler found for property " + HandlerName + "!";
}
}
void AddHandler(const char* Property, Handler H) {
Handlers_[Property] = H;
}
};
template <class Handler, class FunctionObject>
Handler GetHandler(FunctionObject* Obj, const DagInit& Dag) {
const std::string& HandlerName = GetOperatorName(Dag);
return Obj->GetHandler(HandlerName);
}
template <class FunctionObject>
void InvokeDagInitHandler(FunctionObject* Obj, const Init* I) {
typedef void (FunctionObject::*Handler) (const DagInit&);
const DagInit& Dag = InitPtrToDag(I);
Handler h = GetHandler<Handler>(Obj, Dag);
((Obj)->*(h))(Dag);
}
template <class FunctionObject>
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& Dag = InitPtrToDag(I);
Handler h = GetHandler<Handler>(Obj, Dag);
((Obj)->*(h))(Dag, IndentLevel, O);
}
template <typename H>
typename HandlerTable<H>::HandlerMap HandlerTable<H>::Handlers_;
template <typename H>
bool HandlerTable<H>::staticMembersInitialized_ = false;
/// CollectOptionProperties - Function object for iterating over an
/// option property list.
class CollectOptionProperties;
typedef void (CollectOptionProperties::* CollectOptionPropertiesHandler)
(const DagInit&);
class CollectOptionProperties
: public HandlerTable<CollectOptionPropertiesHandler>
{
private:
/// optDescs_ - OptionDescriptions table. This is where the
/// information is stored.
OptionDescription& optDesc_;
public:
explicit CollectOptionProperties(OptionDescription& OD)
: optDesc_(OD)
{
if (!staticMembersInitialized_) {
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;
}
}
/// operator() - Just forwards to the corresponding property
/// handler.
void operator() (const Init* I) {
InvokeDagInitHandler(this, I);
}
private:
/// Option property handlers --
/// Methods that handle option properties such as (help) or (hidden).
void onHelp (const DagInit& d) {
CheckNumberOfArguments(d, 1);
optDesc_.Help = EscapeQuotes(InitPtrToString(d.getArg(0)));
}
void onHidden (const DagInit& d) {
CheckNumberOfArguments(d, 0);
optDesc_.setHidden();
}
void onReallyHidden (const DagInit& d) {
CheckNumberOfArguments(d, 0);
optDesc_.setReallyHidden();
}
void onCommaSeparated (const DagInit& d) {
CheckNumberOfArguments(d, 0);
if (!optDesc_.isParameterList())
throw "'comma_separated' is valid only on parameter list options!";
optDesc_.setCommaSeparated();
}
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);
const Init* i = d.getArg(0);
const std::string& str = i->getAsString();
bool correct = optDesc_.isParameter() && dynamic_cast<const StringInit*>(i);
correct |= (optDesc_.isSwitch() && (str == "true" || str == "false"));
if (!correct)
throw "Incorrect usage of the 'init' option property!";
optDesc_.InitVal = i;
}
void onOneOrMore (const DagInit& d) {
CheckNumberOfArguments(d, 0);
optDesc_.setOneOrMore();
optDesc_.CheckConsistency();
}
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 has no effect.\n";
optDesc_.setOptional();
optDesc_.CheckConsistency();
}
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 (!optDesc_.isParameterList())
throw "The multi_val property is valid only on list options!";
optDesc_.MultiVal = val;
}
};
/// AddOption - A function object that is applied to every option
/// description. Used by CollectOptionDescriptions.
class AddOption {
private:
OptionDescriptions& OptDescs_;
public:
explicit AddOption(OptionDescriptions& OD) : OptDescs_(OD)
{}
void operator()(const Init* i) {
const DagInit& d = InitPtrToDag(i);
CheckNumberOfArguments(d, 1);
const OptionType::OptionType Type =
stringToOptionType(GetOperatorName(d));
const std::string& Name = InitPtrToString(d.getArg(0));
OptionDescription OD(Type, Name);
CheckNumberOfArguments(d, 2);
// Alias option store the aliased option name in the 'Help' field and do not
// have any properties.
if (OD.isAlias()) {
OD.Help = InitPtrToString(d.getArg(1));
}
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();
// Skip the first argument: it's always the option name.
++B;
std::for_each(B, d.arg_end(), CollectOptionProperties(o));
}
};
/// CollectOptionDescriptions - Collects option properties from all
/// OptionLists.
void CollectOptionDescriptions (const RecordVector& V,
OptionDescriptions& OptDescs)
{
// For every OptionList:
for (RecordVector::const_iterator B = V.begin(), E = V.end(); B!=E; ++B)
{
// Throws an exception if the value does not exist.
const ListInit* PropList = (*B)->getValueAsListInit("options");
// For every option description in this list: invoke AddOption.
std::for_each(PropList->begin(), PropList->end(), AddOption(OptDescs));
}
}
// Tool information record
namespace ToolFlags {
enum ToolFlags { Join = 0x1, Sink = 0x2 };
}
struct ToolDescription : public RefCountedBase<ToolDescription> {
std::string Name;
const Init* CmdLine;
const Init* Actions;
StrVector InLanguage;
std::string InFileOption;
std::string OutFileOption;
StrVector OutLanguage;
std::string OutputSuffix;
unsigned Flags;
const Init* OnEmpty;
// 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
ToolDescription (const std::string &n = "")
: Name(n), CmdLine(0), Actions(0), OutFileOption("-o"),
Flags(0), OnEmpty(0)
{}
};
/// ToolDescriptions - A list of Tool information records.
typedef std::vector<IntrusiveRefCntPtr<ToolDescription> > ToolDescriptions;
/// CollectToolProperties - Function object for iterating over a list of
/// tool property records.
class CollectToolProperties;
typedef void (CollectToolProperties::* CollectToolPropertiesHandler)
(const DagInit&);
class CollectToolProperties : public HandlerTable<CollectToolPropertiesHandler>
{
private:
/// toolDesc_ - Properties of the current Tool. This is where the
/// information is stored.
ToolDescription& toolDesc_;
public:
explicit CollectToolProperties (ToolDescription& d)
: toolDesc_(d)
{
if (!staticMembersInitialized_) {
AddHandler("actions", &CollectToolProperties::onActions);
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() (const Init* I) {
InvokeDagInitHandler(this, I);
}
private:
/// Property handlers --
/// Functions that extract information about tool properties from
/// DAG representation.
void onActions (const DagInit& d) {
CheckNumberOfArguments(d, 1);
const Init* Case = d.getArg(0);
if (typeid(*Case) != typeid(DagInit) ||
GetOperatorName(static_cast<const DagInit&>(*Case)) != "case")
throw "The argument to (actions) should be a 'case' construct!";
toolDesc_.Actions = Case;
}
void onCommand (const DagInit& d) {
CheckNumberOfArguments(d, 1);
toolDesc_.CmdLine = d.getArg(0);
}
/// onInOutLanguage - Common implementation of on{In,Out}Language().
void onInOutLanguage (const DagInit& d, StrVector& OutVec) {
CheckNumberOfArguments(d, 1);
// Copy strings to the output vector.
for (unsigned i = 0, NumArgs = d.getNumArgs(); i < NumArgs; ++i) {
OutVec.push_back(InitPtrToString(d.getArg(i)));
}
// Remove duplicates.
std::sort(OutVec.begin(), OutVec.end());
StrVector::iterator newE = std::unique(OutVec.begin(), OutVec.end());
OutVec.erase(newE, OutVec.end());
}
void onInLanguage (const DagInit& d) {
this->onInOutLanguage(d, toolDesc_.InLanguage);
}
void onJoin (const DagInit& d) {
bool isReallyJoin = false;
if (d.getNumArgs() == 0) {
isReallyJoin = true;
}
else {
const Init* I = d.getArg(0);
isReallyJoin = InitPtrToBool(I);
}
// Is this *really* a join tool? We allow (join false) for generating two
// tool descriptions from a single generic one.
// TOFIX: come up with a cleaner solution.
if (isReallyJoin) {
toolDesc_.setJoin();
}
}
void onOutLanguage (const DagInit& d) {
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 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 (const RecordVector& Tools,
ToolDescriptions& ToolDescs)
{
// Iterate over a properties list of every Tool definition
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.
const ListInit* PropList = T->getValueAsListInit("properties");
IntrusiveRefCntPtr<ToolDescription>
ToolDesc(new ToolDescription(T->getName()));
std::for_each(PropList->begin(), PropList->end(),
CollectToolProperties(*ToolDesc));
ToolDescs.push_back(ToolDesc);
}
}
/// FillInEdgeVector - Merge all compilation graph definitions into
/// one single edge list.
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));
}
}
}
/// NotInGraph - Helper function object for FilterNotInGraph.
struct NotInGraph {
private:
const llvm::StringSet<>& ToolsInGraph_;
public:
NotInGraph(const llvm::StringSet<>& ToolsInGraph)
: ToolsInGraph_(ToolsInGraph)
{}
bool operator()(const IntrusiveRefCntPtr<ToolDescription>& x) {
return (ToolsInGraph_.count(x->Name) == 0);
}
};
/// FilterNotInGraph - Filter out from ToolDescs all Tools not
/// mentioned in the compilation graph definition.
void FilterNotInGraph (const DagVector& EdgeVector,
ToolDescriptions& ToolDescs) {
// List all tools mentioned in the graph.
llvm::StringSet<> ToolsInGraph;
for (DagVector::const_iterator B = EdgeVector.begin(),
E = EdgeVector.end(); B != E; ++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);
ToolsInGraph.insert(NodeB);
}
// Filter ToolPropertiesList.
ToolDescriptions::iterator new_end =
std::remove_if(ToolDescs.begin(), ToolDescs.end(),
NotInGraph(ToolsInGraph));
ToolDescs.erase(new_end, ToolDescs.end());
}
/// FillInToolToLang - Fills in two tables that map tool names to
/// input & output language names. Helper function used by TypecheckGraph().
void FillInToolToLang (const ToolDescriptions& ToolDescs,
StringMap<StringSet<> >& ToolToInLang,
StringMap<StringSet<> >& ToolToOutLang) {
for (ToolDescriptions::const_iterator B = ToolDescs.begin(),
E = ToolDescs.end(); B != E; ++B) {
const ToolDescription& D = *(*B);
for (StrVector::const_iterator B = D.InLanguage.begin(),
E = D.InLanguage.end(); B != E; ++B)
ToolToInLang[D.Name].insert(*B);
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.
void TypecheckGraph (const DagVector& EdgeVector,
const ToolDescriptions& ToolDescs) {
StringMap<StringSet<> > ToolToInLang;
StringMap<StringSet<> > ToolToOutLang;
FillInToolToLang(ToolDescs, ToolToInLang, ToolToOutLang);
for (DagVector::const_iterator B = EdgeVector.begin(),
E = EdgeVector.end(); B != E; ++B) {
const DagInit* Edge = *B;
const std::string& NodeA = InitPtrToString(Edge->getArg(0));
const std::string& NodeB = InitPtrToString(Edge->getArg(1));
StringMap<StringSet<> >::iterator IA = ToolToOutLang.find(NodeA);
StringMap<StringSet<> >::iterator IB = ToolToInLang.find(NodeB);
if (NodeB == "root")
throw "Edges back to the root are not allowed!";
if (NodeA != "root") {
if (IA == 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";
}
}
}
}
/// WalkCase - Walks the 'case' expression DAG and invokes
/// TestCallback on every test, and StatementCallback on every
/// statement. Handles 'case' nesting, but not the 'and' and 'or'
/// combinators (that is, they are passed directly to TestCallback).
/// TestCallback must have type 'void TestCallback(const DagInit*, unsigned
/// IndentLevel, bool FirstTest)'.
/// StatementCallback must have type 'void StatementCallback(const Init*,
/// unsigned IndentLevel)'.
template <typename F1, typename F2>
void WalkCase(const Init* Case, F1 TestCallback, F2 StatementCallback,
unsigned IndentLevel = 0)
{
const DagInit& d = InitPtrToDag(Case);
// Error checks.
if (GetOperatorName(d) != "case")
throw "WalkCase should be invoked only on 'case' expressions!";
if (d.getNumArgs() < 2)
throw "There should be at least one clause in the 'case' expression:\n"
+ d.getAsString();
// Main loop.
bool even = false;
const unsigned numArgs = d.getNumArgs();
unsigned i = 1;
for (DagInit::const_arg_iterator B = d.arg_begin(), E = d.arg_end();
B != E; ++B) {
const Init* arg = *B;
if (!even)
{
// Handle test.
const DagInit& Test = InitPtrToDag(arg);
if (GetOperatorName(Test) == "default" && (i+1 != numArgs))
throw "The 'default' clause should be the last in the "
"'case' construct!";
if (i == numArgs)
throw "Case construct handler: no corresponding action "
"found for the test " + Test.getAsString() + '!';
TestCallback(Test, IndentLevel, (i == 1));
}
else
{
if (dynamic_cast<const DagInit*>(arg)
&& GetOperatorName(static_cast<const DagInit&>(*arg)) == "case") {
// Nested 'case'.
WalkCase(arg, TestCallback, StatementCallback, IndentLevel + Indent1);
}
// Handle statement.
StatementCallback(arg, IndentLevel);
}
++i;
even = !even;
}
}
/// ExtractOptionNames - A helper function object used by
/// CheckForSuperfluousOptions() to walk the 'case' DAG.
class ExtractOptionNames {
llvm::StringSet<>& OptionNames_;
void processDag(const Init* Statement) {
const DagInit& Stmt = InitPtrToDag(Statement);
const std::string& ActionName = GetOperatorName(Stmt);
if (ActionName == "forward" || ActionName == "forward_as" ||
ActionName == "forward_value" ||
ActionName == "forward_transformed_value" ||
ActionName == "parameter_equals" || ActionName == "element_in_list") {
CheckNumberOfArguments(Stmt, 1);
const 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) {
const 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));
}
}
}
public:
ExtractOptionNames(llvm::StringSet<>& OptionNames) : OptionNames_(OptionNames)
{}
void operator()(const Init* Statement) {
// Statement is either a dag, or a list of dags.
if (typeid(*Statement) == typeid(ListInit)) {
const ListInit& DagList = *static_cast<const ListInit*>(Statement);
for (ListInit::const_iterator B = DagList.begin(), E = DagList.end();
B != E; ++B)
this->processDag(*B);
}
else {
this->processDag(Statement);
}
}
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 DagVector& EdgeVector,
const ToolDescriptions& ToolDescs,
const OptionDescriptions& OptDescs) {
llvm::StringSet<> nonSuperfluousOptions;
// Add all options mentioned in the ToolDesc.Actions to the set of
// non-superfluous options.
for (ToolDescriptions::const_iterator B = ToolDescs.begin(),
E = ToolDescs.end(); B != E; ++B) {
const ToolDescription& TD = *(*B);
ExtractOptionNames Callback(nonSuperfluousOptions);
if (TD.Actions)
WalkCase(TD.Actions, Callback, Callback);
}
// Add all options mentioned in the 'case' clauses of the
// OptionalEdges of the compilation graph to the set of
// non-superfluous options.
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
// non-superfluous options.
for (OptionDescriptions::const_iterator B = OptDescs.begin(),
E = OptDescs.end(); B != E; ++B) {
const OptionDescription& Val = B->second;
if (!nonSuperfluousOptions.count(Val.Name)
&& Val.Type != OptionType::Alias)
llvm::errs() << "Warning: option '-" << Val.Name << "' has no effect! "
"Probable cause: this option is specified only in the OptionList.\n";
}
}
/// EmitCaseTest0Args - Helper function used by EmitCaseConstructHandler().
bool EmitCaseTest0Args(const std::string& TestName, raw_ostream& O) {
if (TestName == "single_input_file") {
O << "InputFilenames.size() == 1";
return true;
}
else if (TestName == "multiple_input_files") {
O << "InputFilenames.size() > 1";
return true;
}
return false;
}
/// EmitMultipleArgumentTest - Helper function used by
/// EmitCaseTestMultipleArgs()
template <typename F>
void EmitMultipleArgumentTest(const DagInit& D, const char* LogicOp,
F Callback, raw_ostream& 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 EmitMultipleArgumentTest
class EmitSwitchOn {
const OptionDescriptions& OptDescs_;
public:
EmitSwitchOn(const OptionDescriptions& OptDescs) : OptDescs_(OptDescs)
{}
void operator()(const std::string& OptName, raw_ostream& O) const {
const OptionDescription& OptDesc = OptDescs_.FindSwitch(OptName);
O << OptDesc.GenVariableName();
}
};
class EmitEmptyTest {
bool EmitNegate_;
const OptionDescriptions& OptDescs_;
public:
EmitEmptyTest(bool EmitNegate, const OptionDescriptions& OptDescs)
: EmitNegate_(EmitNegate), OptDescs_(OptDescs)
{}
void operator()(const std::string& OptName, raw_ostream& O) const {
const char* Neg = (EmitNegate_ ? "!" : "");
if (OptName == "o") {
O << Neg << "OutputFilename.empty()";
}
else if (OptName == "save-temps") {
O << Neg << "(SaveTemps == SaveTempsEnum::Unset)";
}
else {
const OptionDescription& OptDesc = OptDescs_.FindListOrParameter(OptName);
O << Neg << OptDesc.GenVariableName() << ".empty()";
}
}
};
/// 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") {
EmitMultipleArgumentTest(d, "||", EmitSwitchOn(OptDescs), O);
return true;
}
else if (TestName == "switch_on") {
EmitMultipleArgumentTest(d, "&&", EmitSwitchOn(OptDescs), O);
return true;
}
else if (TestName == "any_not_empty") {
EmitMultipleArgumentTest(d, "||", EmitEmptyTest(true, OptDescs), O);
return true;
}
else if (TestName == "any_empty") {
EmitMultipleArgumentTest(d, "||", EmitEmptyTest(false, OptDescs), O);
return true;
}
else if (TestName == "not_empty") {
EmitMultipleArgumentTest(d, "&&", EmitEmptyTest(true, OptDescs), O);
return true;
}
else if (TestName == "empty") {
EmitMultipleArgumentTest(d, "&&", EmitEmptyTest(false, OptDescs), O);
return true;
}
return false;
}
/// 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 == "input_languages_contain") {
O << "InLangs.count(\"" << Arg << "\") != 0";
return true;
}
else if (TestName == "in_language") {
// This works only for single-argument Tool::GenerateAction. Join
// tools can process several files in different languages simultaneously.
// TODO: make this work with Edge::Weight (if possible).
O << "LangMap.GetLanguage(inFile) == \"" << Arg << '\"';
return true;
}
return false;
}
/// 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().
bool EmitCaseTest2Args(const std::string& TestName,
const DagInit& d,
unsigned IndentLevel,
const OptionDescriptions& OptDescs,
raw_ostream& O) {
CheckNumberOfArguments(d, 2);
const std::string& OptName = InitPtrToString(d.getArg(0));
const std::string& OptArg = InitPtrToString(d.getArg(1));
if (TestName == "parameter_equals") {
const OptionDescription& OptDesc = OptDescs.FindParameter(OptName);
O << OptDesc.GenVariableName() << " == \"" << OptArg << "\"";
return true;
}
else if (TestName == "element_in_list") {
const OptionDescription& OptDesc = OptDescs.FindParameterList(OptName);
const std::string& VarName = OptDesc.GenVariableName();
O << "std::find(" << VarName << ".begin(),\n";
O.indent(IndentLevel + Indent1)
<< VarName << ".end(), \""
<< OptArg << "\") != " << VarName << ".end()";
return true;
}
return false;
}
// Forward declaration.
// EmitLogicalOperationTest and EmitCaseTest are mutually recursive.
void EmitCaseTest(const DagInit& d, unsigned IndentLevel,
const OptionDescriptions& OptDescs,
raw_ostream& O);
/// EmitLogicalOperationTest - Helper function used by
/// EmitCaseConstructHandler.
void EmitLogicalOperationTest(const DagInit& d, const char* LogicOp,
unsigned IndentLevel,
const OptionDescriptions& OptDescs,
raw_ostream& O) {
O << '(';
for (unsigned i = 0, NumArgs = d.getNumArgs(); i < NumArgs; ++i) {
const DagInit& InnerTest = InitPtrToDag(d.getArg(i));
EmitCaseTest(InnerTest, IndentLevel, OptDescs, O);
if (i != NumArgs - 1) {
O << ")\n";
O.indent(IndentLevel + Indent1) << ' ' << LogicOp << " (";
}
else {
O << ')';
}
}
}
void EmitLogicalNot(const DagInit& d, unsigned IndentLevel,
const OptionDescriptions& OptDescs, raw_ostream& O)
{
CheckNumberOfArguments(d, 1);
const DagInit& InnerTest = InitPtrToDag(d.getArg(0));
O << "! (";
EmitCaseTest(InnerTest, IndentLevel, OptDescs, O);
O << ")";
}
/// EmitCaseTest - Helper function used by EmitCaseConstructHandler.
void EmitCaseTest(const DagInit& d, unsigned IndentLevel,
const OptionDescriptions& OptDescs,
raw_ostream& O) {
const std::string& TestName = GetOperatorName(d);
if (TestName == "and")
EmitLogicalOperationTest(d, "&&", IndentLevel, OptDescs, O);
else if (TestName == "or")
EmitLogicalOperationTest(d, "||", IndentLevel, OptDescs, O);
else if (TestName == "not")
EmitLogicalNot(d, IndentLevel, OptDescs, O);
else if (EmitCaseTest0Args(TestName, O))
return;
else if (EmitCaseTest1OrMoreArgs(TestName, d, OptDescs, O))
return;
else if (EmitCaseTest2Args(TestName, d, IndentLevel, OptDescs, O))
return;
else
throw "Unknown test '" + TestName + "' used in the 'case' construct!";
}
/// EmitCaseTestCallback - Callback used by EmitCaseConstructHandler.
class EmitCaseTestCallback {
bool EmitElseIf_;
const OptionDescriptions& OptDescs_;
raw_ostream& O_;
public:
EmitCaseTestCallback(bool EmitElseIf,
const OptionDescriptions& OptDescs, raw_ostream& O)
: EmitElseIf_(EmitElseIf), OptDescs_(OptDescs), O_(O)
{}
void operator()(const DagInit& Test, unsigned IndentLevel, bool FirstTest)
{
if (GetOperatorName(Test) == "default") {
O_.indent(IndentLevel) << "else {\n";
}
else {
O_.indent(IndentLevel)
<< ((!FirstTest && EmitElseIf_) ? "else if (" : "if (");
EmitCaseTest(Test, IndentLevel, OptDescs_, O_);
O_ << ") {\n";
}
}
};
/// EmitCaseStatementCallback - Callback used by EmitCaseConstructHandler.
template <typename F>
class EmitCaseStatementCallback {
F Callback_;
raw_ostream& O_;
public:
EmitCaseStatementCallback(F Callback, raw_ostream& O)
: Callback_(Callback), O_(O)
{}
void operator() (const Init* Statement, unsigned IndentLevel) {
// Is this a nested 'case'?
bool IsCase = dynamic_cast<const DagInit*>(Statement) &&
GetOperatorName(static_cast<const DagInit&>(*Statement)) == "case";
// If so, ignore it, it is handled by our caller, WalkCase.
if (!IsCase) {
if (typeid(*Statement) == typeid(ListInit)) {
const ListInit& DagList = *static_cast<const ListInit*>(Statement);
for (ListInit::const_iterator B = DagList.begin(), E = DagList.end();
B != E; ++B)
Callback_(*B, (IndentLevel + Indent1), O_);
}
else {
Callback_(Statement, (IndentLevel + Indent1), O_);
}
}
O_.indent(IndentLevel) << "}\n";
}
};
/// 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(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(..) {..}
/// .. else {..}').
template <typename F>
void EmitCaseConstructHandler(const Init* Case, unsigned IndentLevel,
F Callback, bool EmitElseIf,
const OptionDescriptions& OptDescs,
raw_ostream& O) {
WalkCase(Case, EmitCaseTestCallback(EmitElseIf, OptDescs, O),
EmitCaseStatementCallback<F>(Callback, O), IndentLevel);
}
/// 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) {
const char* Delimiters = " \t\n\v\f\r";
enum TokenizerState
{ Normal, SpecialCommand, InsideSpecialCommand, InsideQuotationMarks }
cur_st = Normal;
if (CmdLine.empty())
return;
Out.push_back("");
std::string::size_type B = CmdLine.find_first_not_of(Delimiters),
E = CmdLine.size();
for (; B != E; ++B) {
char cur_ch = CmdLine[B];
switch (cur_st) {
case Normal:
if (cur_ch == '$') {
cur_st = SpecialCommand;
break;
}
if (OneOf(Delimiters, cur_ch)) {
// Skip whitespace
B = CmdLine.find_first_not_of(Delimiters, B);
if (B == std::string::npos) {
B = E-1;
continue;
}
--B;
Out.push_back("");
continue;
}
break;
case SpecialCommand:
if (OneOf(Delimiters, cur_ch)) {
cur_st = Normal;
Out.push_back("");
continue;
}
if (cur_ch == '(') {
Out.push_back("");
cur_st = InsideSpecialCommand;
continue;
}
break;
case InsideSpecialCommand:
if (OneOf(Delimiters, cur_ch)) {
continue;
}
if (cur_ch == '\'') {
cur_st = InsideQuotationMarks;
Out.push_back("");
continue;
}
if (cur_ch == ')') {
cur_st = Normal;
Out.push_back("");
}
if (cur_ch == ',') {
continue;
}
break;
case InsideQuotationMarks:
if (cur_ch == '\'') {
cur_st = InsideSpecialCommand;
continue;
}
break;
}
Out.back().push_back(cur_ch);
}
}
/// SubstituteCall - Given "$CALL(HookName, [Arg1 [, Arg2 [...]]])", output
/// "hooks::HookName([Arg1 [, Arg2 [, ...]]])". Helper function used by
/// SubstituteSpecialCommands().
StrVector::const_iterator
SubstituteCall (StrVector::const_iterator Pos,
StrVector::const_iterator End,
bool IsJoin, raw_ostream& O)
{
const char* errorMessage = "Syntax error in $CALL invocation!";
CheckedIncrement(Pos, End, errorMessage);
const std::string& CmdName = *Pos;
if (CmdName == ")")
throw "$CALL invocation: empty argument list!";
O << "hooks::";
O << CmdName << "(";
bool firstIteration = true;
while (true) {
CheckedIncrement(Pos, End, errorMessage);
const std::string& Arg = *Pos;
assert(Arg.size() != 0);
if (Arg[0] == ')')
break;
if (firstIteration)
firstIteration = false;
else
O << ", ";
if (Arg == "$INFILE") {
if (IsJoin)
throw "$CALL(Hook, $INFILE) can't be used with a Join tool!";
else
O << "inFile.c_str()";
}
else {
O << '"' << Arg << '"';
}
}
O << ')';
return Pos;
}
/// SubstituteEnv - Given '$ENV(VAR_NAME)', output 'getenv("VAR_NAME")'. Helper
/// function used by SubstituteSpecialCommands().
StrVector::const_iterator
SubstituteEnv (StrVector::const_iterator Pos,
StrVector::const_iterator End, raw_ostream& O)
{
const char* errorMessage = "Syntax error in $ENV invocation!";
CheckedIncrement(Pos, End, errorMessage);
const std::string& EnvName = *Pos;
if (EnvName == ")")
throw "$ENV invocation: empty argument list!";
O << "checkCString(std::getenv(\"";
O << EnvName;
O << "\"))";
CheckedIncrement(Pos, End, errorMessage);
return Pos;
}
/// SubstituteSpecialCommands - Given an invocation of $CALL or $ENV, output
/// handler code. Helper function used by EmitCmdLineVecFill().
StrVector::const_iterator
SubstituteSpecialCommands (StrVector::const_iterator Pos,
StrVector::const_iterator End,
bool IsJoin, raw_ostream& O)
{
const std::string& cmd = *Pos;
// Perform substitution.
if (cmd == "$CALL") {
Pos = SubstituteCall(Pos, End, IsJoin, O);
}
else if (cmd == "$ENV") {
Pos = SubstituteEnv(Pos, End, O);
}
else {
throw "Unknown special command: " + cmd;
}
// Handle '$CMD(ARG)/additional/text'.
const std::string& Leftover = *Pos;
assert(Leftover.at(0) == ')');
if (Leftover.size() != 1)
O << " + std::string(\"" << (Leftover.c_str() + 1) << "\")";
return Pos;
}
/// EmitCmdLineVecFill - Emit code that fills in the command line
/// vector. Helper function used by EmitGenerateActionMethod().
void EmitCmdLineVecFill(const Init* CmdLine, const std::string& ToolName,
bool IsJoin, unsigned IndentLevel,
raw_ostream& O) {
StrVector StrVec;
TokenizeCmdLine(InitPtrToString(CmdLine), StrVec);
if (StrVec.empty())
throw "Tool '" + ToolName + "' has empty command line!";
StrVector::const_iterator B = StrVec.begin(), E = StrVec.end();
// Emit the command itself.
assert(!StrVec[0].empty());
O.indent(IndentLevel) << "cmd = ";
if (StrVec[0][0] == '$') {
B = SubstituteSpecialCommands(B, E, IsJoin, O);
++B;
}
else {
O << '"' << StrVec[0] << '"';
++B;
}
O << ";\n";
// Go through the command arguments.
assert(B <= E);
for (; B != E; ++B) {
const std::string& cmd = *B;
assert(!cmd.empty());
O.indent(IndentLevel);
if (cmd.at(0) == '$') {
O << "vec.push_back(std::make_pair(0, ";
B = SubstituteSpecialCommands(B, E, IsJoin, O);
O << "));\n";
}
else {
O << "vec.push_back(std::make_pair(0, \"" << cmd << "\"));\n";
}
}
}
/// EmitForEachListElementCycleHeader - Emit common code for iterating through
/// all elements of a list. Helper function used by
/// EmitForwardOptionPropertyHandlingCode.
void EmitForEachListElementCycleHeader (const OptionDescription& D,
unsigned IndentLevel,
raw_ostream& O) {
unsigned IndentLevel1 = IndentLevel + Indent1;
O.indent(IndentLevel)
<< "for (" << D.GenTypeDeclaration()
<< "::iterator B = " << D.GenVariableName() << ".begin(),\n";
O.indent(IndentLevel)
<< "E = " << D.GenVariableName() << ".end(); B != E;) {\n";
O.indent(IndentLevel1) << "unsigned pos = " << D.GenVariableName()
<< ".getPosition(B - " << D.GenVariableName()
<< ".begin());\n";
}
/// EmitForwardOptionPropertyHandlingCode - Helper function used to
/// implement EmitActionHandler. Emits code for
/// handling the (forward) and (forward_as) option properties.
void EmitForwardOptionPropertyHandlingCode (const OptionDescription& D,
unsigned IndentLevel,
const std::string& NewName,
raw_ostream& O) {
const std::string& Name = NewName.empty()
? ("-" + D.Name)
: NewName;
unsigned IndentLevel1 = IndentLevel + Indent1;
switch (D.Type) {
case OptionType::Switch:
O.indent(IndentLevel)
<< "vec.push_back(std::make_pair(" << D.GenVariableName()
<< ".getPosition(), \"" << Name << "\"));\n";
break;
case OptionType::Parameter:
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(std::make_pair("
<< D.GenVariableName() << ".getPosition(), \""
<< Name << "\" + "
<< D.GenVariableName() << "));\n";
break;
case OptionType::PrefixList:
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(std::make_pair(pos, *B));\n";
O.indent(IndentLevel1) << "++B;\n";
}
O.indent(IndentLevel) << "}\n";
break;
case OptionType::ParameterList:
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(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:
default:
throw "Aliases are not allowed in tool option descriptions!";
}
}
/// ActionHandlingCallbackBase - Base class of EmitActionHandlersCallback and
/// EmitPreprocessOptionsCallback.
struct ActionHandlingCallbackBase
{
void onErrorDag(const DagInit& d,
unsigned IndentLevel, raw_ostream& O) const
{
O.indent(IndentLevel)
<< "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);
O.indent(IndentLevel) << "llvm::errs() << \""
<< InitPtrToString(d.getArg(0)) << "\";\n";
}
};
/// 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,
public HandlerTable<EmitActionHandlersCallbackHandler>
{
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,
const char* BlockOpen, const char* BlockClose,
unsigned IndentLevel, raw_ostream& O) const
{
StrVector Out;
TokenizeCmdLine(Str, Out);
for (StrVector::const_iterator B = Out.begin(), E = Out.end();
B != E; ++B) {
const std::string& cmd = *B;
O.indent(IndentLevel) << BlockOpen;
if (cmd.at(0) == '$')
B = SubstituteSpecialCommands(B, E, /* IsJoin = */ true, O);
else
O << '"' << cmd << '"';
O << BlockClose;
}
}
void onAppendCmd (const DagInit& Dag,
unsigned IndentLevel, raw_ostream& O) const
{
CheckNumberOfArguments(Dag, 1);
this->EmitHookInvocation(InitPtrToString(Dag.getArg(0)),
"vec.push_back(std::make_pair(65536, ", "));\n",
IndentLevel, O);
}
void onForward (const DagInit& Dag,
unsigned IndentLevel, raw_ostream& O) const
{
CheckNumberOfArguments(Dag, 1);
const std::string& Name = InitPtrToString(Dag.getArg(0));
EmitForwardOptionPropertyHandlingCode(OptDescs.FindOption(Name),
IndentLevel, "", O);
}
void onForwardAs (const DagInit& Dag,
unsigned IndentLevel, raw_ostream& O) const
{
CheckNumberOfArguments(Dag, 2);
const std::string& Name = InitPtrToString(Dag.getArg(0));
const std::string& NewName = InitPtrToString(Dag.getArg(1));
EmitForwardOptionPropertyHandlingCode(OptDescs.FindOption(Name),
IndentLevel, NewName, O);
}
void onForwardValue (const DagInit& Dag,
unsigned IndentLevel, raw_ostream& O) const
{
CheckNumberOfArguments(Dag, 1);
const std::string& Name = InitPtrToString(Dag.getArg(0));
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(std::make_pair("
<< D.GenVariableName() << ".getPosition(), "
<< D.GenVariableName() << "));\n";
}
else {
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);
const std::string& Name = InitPtrToString(Dag.getArg(0));
const std::string& Hook = InitPtrToString(Dag.getArg(1));
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";
}
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);
this->EmitHookInvocation(InitPtrToString(Dag.getArg(0)),
"output_suffix = ", ";\n", IndentLevel, O);
}
void onStopCompilation (const DagInit& Dag,
unsigned IndentLevel, raw_ostream& O) const
{
O.indent(IndentLevel) << "stop_compilation = true;\n";
}
void onUnpackValues (const DagInit& Dag,
unsigned IndentLevel, raw_ostream& O) const
{
throw "'unpack_values' is deprecated. "
"Use 'comma_separated' + 'forward_value' instead!";
}
public:
explicit EmitActionHandlersCallback(const OptionDescriptions& OD)
: OptDescs(OD)
{
if (!staticMembersInitialized_) {
AddHandler("error", &EmitActionHandlersCallback::onErrorDag);
AddHandler("warning", &EmitActionHandlersCallback::onWarningDag);
AddHandler("append_cmd", &EmitActionHandlersCallback::onAppendCmd);
AddHandler("forward", &EmitActionHandlersCallback::onForward);
AddHandler("forward_as", &EmitActionHandlersCallback::onForwardAs);
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* I,
unsigned IndentLevel, raw_ostream& O) const
{
InvokeDagInitHandler(this, I, IndentLevel, O);
}
};
void EmitGenerateActionMethodHeader(const ToolDescription& D,
bool IsJoin, bool Naked,
raw_ostream& O)
{
O.indent(Indent1) << "int GenerateAction(Action& Out,\n";
if (IsJoin)
O.indent(Indent2) << "const PathVector& inFiles,\n";
else
O.indent(Indent2) << "const sys::Path& inFile,\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";
if (!Naked) {
O.indent(Indent2) << "std::string cmd;\n";
O.indent(Indent2) << "std::string out_file;\n";
O.indent(Indent2)
<< "std::vector<std::pair<unsigned, std::string> > vec;\n";
O.indent(Indent2) << "bool stop_compilation = !HasChildren;\n";
O.indent(Indent2) << "bool no_out_file = false;\n";
O.indent(Indent2) << "std::string output_suffix(\""
<< D.OutputSuffix << "\");\n";
}
}
// EmitGenerateActionMethod - Emit either a normal or a "join" version of the
// Tool::GenerateAction() method.
void EmitGenerateActionMethod (const ToolDescription& D,
const OptionDescriptions& OptDescs,
bool IsJoin, raw_ostream& O) {
EmitGenerateActionMethodHeader(D, IsJoin, /* Naked = */ false, O);
if (!D.CmdLine)
throw "Tool " + D.Name + " has no cmd_line property!";
// Process the 'command' property.
O << '\n';
EmitCmdLineVecFill(D.CmdLine, D.Name, IsJoin, Indent2, O);
O << '\n';
// Process the 'actions' list of this tool.
if (D.Actions)
EmitCaseConstructHandler(D.Actions, Indent2,
EmitActionHandlersCallback(OptDescs),
false, OptDescs, O);
O << '\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 (!" << SinkOption << ".empty()) {\n";
O.indent(Indent3) << "for (cl::list<std::string>::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) << "Out.Construct(cmd, this->SortArgs(vec), "
<< "stop_compilation, out_file);\n";
O.indent(Indent2) << "return 0;\n";
O.indent(Indent1) << "}\n\n";
}
/// EmitGenerateActionMethods - Emit two GenerateAction() methods for
/// a given Tool class.
void EmitGenerateActionMethods (const ToolDescription& ToolDesc,
const OptionDescriptions& OptDescs,
raw_ostream& O) {
if (!ToolDesc.isJoin()) {
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 {
EmitGenerateActionMethod(ToolDesc, OptDescs, true, O);
}
EmitGenerateActionMethod(ToolDesc, OptDescs, false, O);
}
/// EmitInOutLanguageMethods - Emit the [Input,Output]Language()
/// methods for a given Tool class.
void EmitInOutLanguageMethods (const ToolDescription& D, raw_ostream& O) {
O.indent(Indent1) << "const char** InputLanguages() const {\n";
O.indent(Indent2) << "return InputLanguages_;\n";
O.indent(Indent1) << "}\n\n";
O.indent(Indent1) << "const char** OutputLanguages() const {\n";
O.indent(Indent2) << "return OutputLanguages_;\n";
O.indent(Indent1) << "}\n\n";
}
/// EmitNameMethod - Emit the Name() method for a given Tool class.
void EmitNameMethod (const ToolDescription& D, raw_ostream& O) {
O.indent(Indent1) << "const char* Name() const {\n";
O.indent(Indent2) << "return \"" << D.Name << "\";\n";
O.indent(Indent1) << "}\n\n";
}
/// EmitIsJoinMethod - Emit the IsJoin() method for a given Tool
/// class.
void EmitIsJoinMethod (const ToolDescription& D, raw_ostream& O) {
O.indent(Indent1) << "bool IsJoin() const {\n";
if (D.isJoin())
O.indent(Indent2) << "return true;\n";
else
O.indent(Indent2) << "return false;\n";
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!";
EmitStrArray(D.Name, "InputLanguages_", D.InLanguage, O);
EmitStrArray(D.Name, "OutputLanguages_", D.OutLanguage, O);
O << '\n';
}
/// EmitToolClassDefinition - Emit a Tool class definition.
void EmitToolClassDefinition (const ToolDescription& D,
const OptionDescriptions& OptDescs,
raw_ostream& O) {
if (D.Name == "root")
return;
// Header
O << "class " << D.Name << " : public ";
if (D.isJoin())
O << "JoinTool";
else
O << "Tool";
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
O << "};\n";
EmitStaticMemberDefinitions(D, O);
}
/// EmitOptionDefinitions - Iterate over a list of option descriptions
/// and emit registration code.
void EmitOptionDefinitions (const OptionDescriptions& descs,
bool HasSink, raw_ostream& O)
{
std::vector<OptionDescription> Aliases;
// Emit static cl::Option variables.
for (OptionDescriptions::const_iterator B = descs.begin(),
E = descs.end(); B!=E; ++B) {
const OptionDescription& val = B->second;
if (val.Type == OptionType::Alias) {
Aliases.push_back(val);
continue;
}
O << val.GenTypeDeclaration() << ' '
<< val.GenPlainVariableName();
O << "(\"" << val.Name << "\"\n";
if (val.Type == OptionType::Prefix || val.Type == OptionType::PrefixList)
O << ", cl::Prefix";
if (val.isRequired()) {
if (val.isList() && !val.isMultiVal())
O << ", cl::OneOrMore";
else
O << ", cl::Required";
}
if (val.isOptional())
O << ", cl::Optional";
if (val.isOneOrMore())
O << ", cl::OneOrMore";
if (val.isZeroOrMore())
O << ", cl::ZeroOrMore";
if (val.isReallyHidden())
O << ", cl::ReallyHidden";
else if (val.isHidden())
O << ", cl::Hidden";
if (val.isCommaSeparated())
O << ", cl::CommaSeparated";
if (val.MultiVal > 1)
O << ", cl::multi_val(" << val.MultiVal << ')';
if (val.InitVal) {
const std::string& str = val.InitVal->getAsString();
O << ", cl::init(" << str << ')';
}
if (!val.Help.empty())
O << ", cl::desc(\"" << val.Help << "\")";
O << ");\n\n";
}
// Emit the aliases (they should go after all the 'proper' options).
for (std::vector<OptionDescription>::const_iterator
B = Aliases.begin(), E = Aliases.end(); B != E; ++B) {
const OptionDescription& val = *B;
O << val.GenTypeDeclaration() << ' '
<< val.GenPlainVariableName()
<< "(\"" << val.Name << '\"';
const OptionDescription& D = descs.FindOption(val.Help);
O << ", cl::aliasopt(" << D.GenVariableName() << ")";
O << ", cl::desc(\"" << "An alias for -" + val.Help << "\"));\n";
}
// Emit the sink option.
if (HasSink)
O << "cl::list<std::string> " << SinkOptionName << "(cl::Sink);\n";
O << '\n';
}
/// EmitPreprocessOptionsCallback - Helper function passed to
/// EmitCaseConstructHandler() by EmitPreprocessOptions().
class EmitPreprocessOptionsCallback;
typedef void
(EmitPreprocessOptionsCallback::* EmitPreprocessOptionsCallbackHandler)
(const DagInit&, unsigned, raw_ostream&) const;
class EmitPreprocessOptionsCallback :
public ActionHandlingCallbackBase,
public HandlerTable<EmitPreprocessOptionsCallbackHandler>
{
typedef EmitPreprocessOptionsCallbackHandler Handler;
typedef void
(EmitPreprocessOptionsCallback::* HandlerImpl)
(const Init*, unsigned, raw_ostream&) const;
const OptionDescriptions& OptDescs_;
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()) {
O.indent(IndentLevel) << OptDesc.GenVariableName() << " = false;\n";
}
else if (OptDesc.isParameter()) {
O.indent(IndentLevel) << OptDesc.GenVariableName() << " = \"\";\n";
}
else if (OptDesc.isList()) {
O.indent(IndentLevel) << OptDesc.GenVariableName() << ".clear();\n";
}
else {
throw "Can't apply 'unset_option' to alias option '" + OptName + "'!";
}
}
void onUnsetOption(const DagInit& d,
unsigned IndentLevel, raw_ostream& O) const
{
this->onEachArgument(d, &EmitPreprocessOptionsCallback::onUnsetOptionImpl,
IndentLevel, O);
}
void onSetOptionImpl(const DagInit& D,
unsigned IndentLevel, raw_ostream& O) const {
CheckNumberOfArguments(D, 2);
const std::string& OptName = InitPtrToString(D.getArg(0));
const OptionDescription& OptDesc = OptDescs_.FindOption(OptName);
const Init* Value = D.getArg(1);
if (OptDesc.isList()) {
const ListInit& List = InitPtrToList(Value);
O.indent(IndentLevel) << OptDesc.GenVariableName() << ".clear();\n";
for (ListInit::const_iterator B = List.begin(), E = List.end();
B != E; ++B) {
const Init* CurElem = *B;
if (OptDesc.isSwitchList())
CheckBooleanConstant(CurElem);
O.indent(IndentLevel)
<< OptDesc.GenVariableName() << ".push_back(\""
<< (OptDesc.isSwitchList() ? CurElem->getAsString()
: InitPtrToString(CurElem))
<< "\");\n";
}
}
else if (OptDesc.isSwitch()) {
CheckBooleanConstant(Value);
O.indent(IndentLevel) << OptDesc.GenVariableName()
<< " = " << Value->getAsString() << ";\n";
}
else if (OptDesc.isParameter()) {
const std::string& Str = InitPtrToString(Value);
O.indent(IndentLevel) << OptDesc.GenVariableName()
<< " = \"" << Str << "\";\n";
}
else {
throw "Can't apply 'set_option' to alias option '" + OptName + "'!";
}
}
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;
}
}
// 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 PreprocessOptions() function.
void EmitPreprocessOptions (const RecordKeeper& Records,
const OptionDescriptions& OptDecs, raw_ostream& O)
{
O << "int PreprocessOptions () {\n";
const RecordVector& OptionPreprocessors =
Records.getAllDerivedDefinitions("OptionPreprocessor");
for (RecordVector::const_iterator B = OptionPreprocessors.begin(),
E = OptionPreprocessors.end(); B!=E; ++B) {
const DagInit* Case = (*B)->getValueAsDag("preprocessor");
EmitCaseConstructHandler(Case, Indent1,
EmitPreprocessOptionsCallback(OptDecs),
false, OptDecs, O);
}
O << '\n';
O.indent(Indent1) << "return 0;\n";
O << "}\n\n";
}
class DoEmitPopulateLanguageMap;
typedef void (DoEmitPopulateLanguageMap::* DoEmitPopulateLanguageMapHandler)
(const DagInit& D);
class DoEmitPopulateLanguageMap
: public HandlerTable<DoEmitPopulateLanguageMapHandler>
{
private:
raw_ostream& O_;
public:
explicit DoEmitPopulateLanguageMap (raw_ostream& O) : O_(O) {
if (!staticMembersInitialized_) {
AddHandler("lang_to_suffixes",
&DoEmitPopulateLanguageMap::onLangToSuffixes);
staticMembersInitialized_ = true;
}
}
void operator() (const Init* I) {
InvokeDagInitHandler(this, I);
}
private:
void onLangToSuffixes (const DagInit& d) {
CheckNumberOfArguments(d, 2);
const std::string& Lang = InitPtrToString(d.getArg(0));
const 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) {
const 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";
}
/// 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 == "error") {
CheckNumberOfArguments(d, 1);
O.indent(IndentLevel) << "PrintError(\""
<< InitPtrToString(d.getArg(0))
<< "\");\n";
O.indent(IndentLevel) << "return -1;\n";
return;
}
else {
throw "Unknown operator in edge properties list: '" + OpName + "'!"
"\nOnly 'inc_weight', 'dec_weight' and 'error' are allowed.";
}
if (d.getNumArgs() > 0)
O << InitPtrToInt(d.getArg(0)) << ";\n";
else
O << "2;\n";
}
/// EmitEdgeClass - Emit a single Edge# class.
void EmitEdgeClass (unsigned N, const std::string& Target,
const DagInit& Case, const OptionDescriptions& OptDescs,
raw_ostream& O) {
// Class constructor.
O << "class Edge" << N << ": public Edge {\n"
<< "public:\n";
O.indent(Indent1) << "Edge" << N << "() : Edge(\"" << Target
<< "\") {}\n\n";
// Function Weight().
O.indent(Indent1)
<< "int Weight(const InputLanguagesSet& InLangs) const {\n";
O.indent(Indent2) << "unsigned ret = 0;\n";
// Handle the 'case' construct.
EmitCaseConstructHandler(&Case, Indent2, EmitEdgePropertyHandlerCallback,
false, OptDescs, O);
O.indent(Indent2) << "return ret;\n";
O.indent(Indent1) << "}\n\n};\n\n";
}
/// EmitEdgeClasses - Emit Edge* classes that represent graph edges.
void EmitEdgeClasses (const DagVector& EdgeVector,
const OptionDescriptions& OptDescs,
raw_ostream& O) {
int i = 0;
for (DagVector::const_iterator B = EdgeVector.begin(),
E = EdgeVector.end(); B != E; ++B) {
const DagInit& Edge = **B;
const std::string& Name = GetOperatorName(Edge);
if (Name == "optional_edge") {
assert(IsOptionalEdge(Edge));
const std::string& NodeB = InitPtrToString(Edge.getArg(1));
const DagInit& Weight = InitPtrToDag(Edge.getArg(2));
EmitEdgeClass(i, NodeB, Weight, OptDescs, O);
}
else if (Name != "edge") {
throw "Unknown edge class: '" + Name + "'!";
}
++i;
}
}
/// EmitPopulateCompilationGraph - Emit the PopulateCompilationGraph() function.
void EmitPopulateCompilationGraph (const DagVector& EdgeVector,
const ToolDescriptions& ToolDescs,
raw_ostream& O)
{
O << "int PopulateCompilationGraph (CompilationGraph& G) {\n";
for (ToolDescriptions::const_iterator B = ToolDescs.begin(),
E = ToolDescs.end(); B != E; ++B)
O.indent(Indent1) << "G.insertNode(new " << (*B)->Name << "());\n";
O << '\n';
// Insert edges.
int i = 0;
for (DagVector::const_iterator B = EdgeVector.begin(),
E = EdgeVector.end(); B != E; ++B) {
const DagInit& Edge = **B;
const std::string& NodeA = InitPtrToString(Edge.getArg(0));
const std::string& NodeB = InitPtrToString(Edge.getArg(1));
O.indent(Indent1) << "if (int ret = G.insertEdge(\"" << NodeA << "\", ";
if (IsOptionalEdge(Edge))
O << "new Edge" << i << "()";
else
O << "new SimpleEdge(\"" << NodeB << "\")";
O << "))\n";
O.indent(Indent2) << "return ret;\n";
++i;
}
O << '\n';
O.indent(Indent1) << "return 0;\n";
O << "}\n\n";
}
/// HookInfo - Information about the hook type and number of arguments.
struct HookInfo {
// A hook can either have a single parameter of type std::vector<std::string>,
// or NumArgs parameters of type const char*.
enum HookType { ListHook, ArgHook };
HookType Type;
unsigned NumArgs;
HookInfo() : Type(ArgHook), NumArgs(1)
{}
HookInfo(HookType T) : Type(T), NumArgs(1)
{}
HookInfo(unsigned N) : Type(ArgHook), NumArgs(N)
{}
};
typedef llvm::StringMap<HookInfo> HookInfoMap;
/// ExtractHookNames - Extract the hook names from all instances of
/// $CALL(HookName) in the provided command line string/action. Helper
/// function used by FillInHookNames().
class ExtractHookNames {
HookInfoMap& HookNames_;
const OptionDescriptions& OptDescs_;
public:
ExtractHookNames(HookInfoMap& HookNames, const OptionDescriptions& OptDescs)
: HookNames_(HookNames), OptDescs_(OptDescs)
{}
void onAction (const DagInit& Dag) {
const std::string& Name = GetOperatorName(Dag);
if (Name == "forward_transformed_value") {
CheckNumberOfArguments(Dag, 2);
const std::string& OptName = InitPtrToString(Dag.getArg(0));
const std::string& HookName = InitPtrToString(Dag.getArg(1));
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);
this->onCmdLine(InitPtrToString(Dag.getArg(0)));
}
}
void onCmdLine(const std::string& Cmd) {
StrVector cmds;
TokenizeCmdLine(Cmd, cmds);
for (StrVector::const_iterator B = cmds.begin(), E = cmds.end();
B != E; ++B) {
const std::string& cmd = *B;
if (cmd == "$CALL") {
unsigned NumArgs = 0;
CheckedIncrement(B, E, "Syntax error in $CALL invocation!");
const std::string& HookName = *B;
if (HookName.at(0) == ')')
throw "$CALL invoked with no arguments!";
while (++B != E && B->at(0) != ')') {
++NumArgs;
}
HookInfoMap::const_iterator H = HookNames_.find(HookName);
if (H != HookNames_.end() && H->second.NumArgs != NumArgs &&
H->second.Type != HookInfo::ArgHook)
throw "Overloading of hooks is not allowed. Overloaded hook: "
+ HookName;
else
HookNames_[HookName] = HookInfo(NumArgs);
}
}
}
void operator()(const Init* Arg) {
// We're invoked on an action (either a dag or a dag list).
if (typeid(*Arg) == typeid(DagInit)) {
const DagInit& Dag = InitPtrToDag(Arg);
this->onAction(Dag);
return;
}
else if (typeid(*Arg) == typeid(ListInit)) {
const ListInit& List = InitPtrToList(Arg);
for (ListInit::const_iterator B = List.begin(), E = List.end(); B != E;
++B) {
const DagInit& Dag = InitPtrToDag(*B);
this->onAction(Dag);
}
return;
}
// We're invoked on a command line string.
this->onCmdLine(InitPtrToString(Arg));
}
void operator()(const Init* Statement, unsigned) {
this->operator()(Statement);
}
};
/// FillInHookNames - Actually extract the hook names from all command
/// line strings. Helper function used by EmitHookDeclarations().
void FillInHookNames(const ToolDescriptions& ToolDescs,
const OptionDescriptions& OptDescs,
HookInfoMap& HookNames)
{
// For all tool descriptions:
for (ToolDescriptions::const_iterator B = ToolDescs.begin(),
E = ToolDescs.end(); B != E; ++B) {
const ToolDescription& D = *(*B);
// Look for 'forward_transformed_value' in 'actions'.
if (D.Actions)
WalkCase(D.Actions, Id(), ExtractHookNames(HookNames, OptDescs));
// Look for hook invocations in 'cmd_line'.
if (!D.CmdLine)
continue;
if (dynamic_cast<const StringInit*>(D.CmdLine))
// This is a string.
ExtractHookNames(HookNames, OptDescs).operator()(D.CmdLine);
else
// This is a 'case' construct.
WalkCase(D.CmdLine, Id(), ExtractHookNames(HookNames, OptDescs));
}
}
/// EmitHookDeclarations - Parse CmdLine fields of all the tool
/// property records and emit hook function declaration for each
/// instance of $CALL(HookName).
void EmitHookDeclarations(const ToolDescriptions& ToolDescs,
const OptionDescriptions& OptDescs, raw_ostream& O) {
HookInfoMap HookNames;
FillInHookNames(ToolDescs, OptDescs, HookNames);
if (HookNames.empty())
return;
for (HookInfoMap::const_iterator B = HookNames.begin(),
E = HookNames.end(); B != E; ++B) {
const char* HookName = B->first();
const HookInfo& Info = B->second;
O.indent(Indent1) << "std::string " << HookName << "(";
if (Info.Type == HookInfo::ArgHook) {
for (unsigned i = 0, j = Info.NumArgs; i < j; ++i) {
O << "const char* Arg" << i << (i+1 == j ? "" : ", ");
}
}
else {
O << "const std::vector<std::string>& Arg";
}
O <<");\n";
}
}
/// EmitIncludes - Emit necessary #include directives and some
/// additional declarations.
void EmitIncludes(raw_ostream& O) {
O << "#include \"llvm/CompilerDriver/BuiltinOptions.h\"\n"
<< "#include \"llvm/CompilerDriver/CompilationGraph.h\"\n"
<< "#include \"llvm/CompilerDriver/Error.h\"\n"
<< "#include \"llvm/CompilerDriver/Tool.h\"\n\n"
<< "#include \"llvm/Support/CommandLine.h\"\n"
<< "#include \"llvm/Support/raw_ostream.h\"\n\n"
<< "#include <algorithm>\n"
<< "#include <cstdlib>\n"
<< "#include <iterator>\n"
<< "#include <stdexcept>\n\n"
<< "using namespace llvm;\n"
<< "using namespace llvmc;\n\n"
<< "inline const char* checkCString(const char* s)\n"
<< "{ return s == NULL ? \"\" : s; }\n\n";
}
/// DriverData - Holds all information about the driver.
struct DriverData {
OptionDescriptions OptDescs;
ToolDescriptions ToolDescs;
DagVector Edges;
bool HasSink;
};
/// HasSink - Go through the list of tool descriptions and check if
/// there are any with the 'sink' property set.
bool HasSink(const ToolDescriptions& ToolDescs) {
for (ToolDescriptions::const_iterator B = ToolDescs.begin(),
E = ToolDescs.end(); B != E; ++B)
if ((*B)->isSink())
return true;
return false;
}
/// 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, Data.OptDescs);
// Collect tool properties.
const RecordVector& Tools = Records.getAllDerivedDefinitions("Tool");
CollectToolDescriptions(Tools, Data.ToolDescs);
Data.HasSink = HasSink(Data.ToolDescs);
// Collect compilation graph edges.
const RecordVector& CompilationGraphs =
Records.getAllDerivedDefinitions("CompilationGraph");
FillInEdgeVector(CompilationGraphs, Data.Edges);
}
/// CheckDriverData - Perform some sanity checks on the collected data.
void CheckDriverData(DriverData& Data) {
// Filter out all tools not mentioned in the compilation graph.
FilterNotInGraph(Data.Edges, Data.ToolDescs);
// Typecheck the compilation graph.
// TODO: use a genuine graph representation instead of a vector and check for
// multiple edges.
TypecheckGraph(Data.Edges, Data.ToolDescs);
// Check that there are no options without side effects (specified
// only in the OptionList).
CheckForSuperfluousOptions(Data.Edges, Data.ToolDescs, Data.OptDescs);
}
void EmitDriverCode(const DriverData& Data,
raw_ostream& O, RecordKeeper &Records) {
// Emit file header.
EmitIncludes(O);
// Emit global option registration code.
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";
O << "using namespace llvmc::autogenerated;\n\n";
// Emit Tool classes.
for (ToolDescriptions::const_iterator B = Data.ToolDescs.begin(),
E = Data.ToolDescs.end(); B!=E; ++B)
EmitToolClassDefinition(*(*B), Data.OptDescs, O);
// Emit Edge# classes.
EmitEdgeClasses(Data.Edges, Data.OptDescs, O);
O << "} // End anonymous namespace.\n\n";
O << "namespace llvmc {\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
}
// End of anonymous namespace
}
/// run - The back-end entry point.
void LLVMCConfigurationEmitter::run (raw_ostream &O) {
try {
DriverData Data;
CollectDriverData(Records, Data);
CheckDriverData(Data);
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.");
}
}