#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/Support/Streams.h"
-
#include <algorithm>
#include <cassert>
#include <functional>
#include <stdexcept>
#include <string>
-
+#include <typeinfo>
using namespace llvm;
namespace {
std::string EscapeVariableName(const std::string& Var) const {
std::string ret;
for (unsigned i = 0; i != Var.size(); ++i) {
- if (Var[i] == ',') {
+ char cur_char = Var[i];
+ if (cur_char == ',') {
+ ret += "_comma_";
+ }
+ else if (cur_char == '+') {
+ ret += "_plus_";
+ }
+ else if (cur_char == ',') {
ret += "_comma_";
}
else {
- ret.push_back(Var[i]);
+ ret.push_back(cur_char);
}
}
return ret;
/// HasSink - Should the emitter generate a "cl::sink" option?
bool HasSink;
+ /// FindOption - exception-throwing wrapper for find().
const GlobalOptionDescription& FindOption(const std::string& OptName) const {
const_iterator I = Descriptions.find(OptName);
if (I != Descriptions.end())
throw OptName + ": no such option!";
}
- // Insert new GlobalOptionDescription into GlobalOptionDescriptions list
+ /// insertDescription - Insert new GlobalOptionDescription into
+ /// GlobalOptionDescriptions list
void insertDescription (const GlobalOptionDescription& o)
{
container_type::iterator I = Descriptions.find(o.Name);
Forward = 0x2, UnpackValues = 0x4};
}
namespace OptionPropertyType {
- enum OptionPropertyType { AppendCmd, OutputSuffix };
+ enum OptionPropertyType { AppendCmd, ForwardAs, OutputSuffix };
}
typedef std::pair<OptionPropertyType::OptionPropertyType, std::string>
// Default ctor here is needed because StringMap can only store
// DefaultConstructible objects
- ToolProperties() : Flags(0) {}
- ToolProperties (const std::string& n) : Name(n), Flags(0) {}
+ ToolProperties() : CmdLine(0), Flags(0) {}
+ ToolProperties (const std::string& n) : Name(n), CmdLine(0), Flags(0) {}
};
&CollectOptionProperties::onAppendCmd;
optionPropertyHandlers_["forward"] =
&CollectOptionProperties::onForward;
+ optionPropertyHandlers_["forward_as"] =
+ &CollectOptionProperties::onForwardAs;
optionPropertyHandlers_["help"] =
&CollectOptionProperties::onHelp;
optionPropertyHandlers_["output_suffix"] =
toolProps_->OptDescs[optDesc_.Name].setForward();
}
+ void onForwardAs (const DagInit* d) {
+ checkNumberOfArguments(d, 1);
+ checkToolProps(d);
+ const std::string& cmd = InitPtrToString(d->getArg(0));
+
+ toolProps_->OptDescs[optDesc_.Name].
+ AddProperty(OptionPropertyType::ForwardAs, cmd);
+ }
+
void onHelp (const DagInit* d) {
checkNumberOfArguments(d, 1);
const std::string& help_message = InitPtrToString(d->getArg(0));
GlobalOptionDescriptions& OptDescs)
{
// Iterate over a properties list of every Tool definition
-
for (;B!=E;++B) {
RecordVector::value_type T = *B;
// Throws an exception if the value does not exist.
}
}
+/// CheckForSuperfluousOptions - Check that there are no side
+/// effect-free options (specified only in the OptionList). Otherwise,
+/// output a warning.
+void CheckForSuperfluousOptions (const ToolPropertiesList& TPList,
+ const GlobalOptionDescriptions& OptDescs) {
+ llvm::StringSet<> nonSuperfluousOptions;
+
+ // Add all options mentioned in the TPList to the set of
+ // non-superfluous options.
+ for (ToolPropertiesList::const_iterator B = TPList.begin(),
+ E = TPList.end(); B != E; ++B) {
+ const ToolProperties& TP = *(*B);
+ for (ToolOptionDescriptions::const_iterator B = TP.OptDescs.begin(),
+ E = TP.OptDescs.end(); B != E; ++B) {
+ nonSuperfluousOptions.insert(B->first());
+ }
+ }
+
+ // Check that all options in OptDescs belong to the set of
+ // non-superfluous options.
+ for (GlobalOptionDescriptions::const_iterator B = OptDescs.begin(),
+ E = OptDescs.end(); B != E; ++B) {
+ const GlobalOptionDescription& Val = B->second;
+ if (!nonSuperfluousOptions.count(Val.Name)
+ && Val.Type != OptionType::Alias)
+ cerr << "Warning: option '-" << Val.Name << "' has no effect! "
+ "Probable cause: this option is specified only in the OptionList.\n";
+ }
+}
+
/// EmitCaseTest1Arg - Helper function used by
/// EmitCaseConstructHandler.
bool EmitCaseTest1Arg(const std::string& TestName,
O << "InLangs.count(\"" << OptName << "\") != 0";
return true;
} else if (TestName == "in_language") {
- // Works only for cmd_line!
- O << "GetLanguage(inFile) == \"" << OptName << '\"';
+ // 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) == \"" << OptName << '\"';
return true;
} else if (TestName == "not_empty") {
if (OptName == "o") {
// void F(Init* Statement, const char* IndentLevel, std::ostream& O).
template <typename F>
void EmitCaseConstructHandler(const DagInit* d, const char* IndentLevel,
- const F& Callback, bool EmitElseIf,
+ F Callback, bool EmitElseIf,
const GlobalOptionDescriptions& OptDescs,
std::ostream& O) {
assert(d->getOperator()->getAsString() == "case");
/// EmitForwardOptionPropertyHandlingCode - Helper function used to
/// implement EmitOptionPropertyHandlingCode(). Emits code for
-/// handling the (forward) option property.
+/// handling the (forward) and (forward_as) option properties.
void EmitForwardOptionPropertyHandlingCode (const ToolOptionDescription& D,
+ const std::string& NewName,
std::ostream& O) {
+ const std::string& Name = NewName.empty()
+ ? ("-" + D.Name)
+ : NewName;
+
switch (D.Type) {
case OptionType::Switch:
- O << Indent3 << "vec.push_back(\"-" << D.Name << "\");\n";
+ O << Indent3 << "vec.push_back(\"" << Name << "\");\n";
break;
case OptionType::Parameter:
- O << Indent3 << "vec.push_back(\"-" << D.Name << "\");\n";
+ O << Indent3 << "vec.push_back(\"" << Name << "\");\n";
O << Indent3 << "vec.push_back(" << D.GenVariableName() << ");\n";
break;
case OptionType::Prefix:
- O << Indent3 << "vec.push_back(\"-" << D.Name << "\" + "
+ O << Indent3 << "vec.push_back(\"" << 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 << "\" + "
+ << Indent4 << "vec.push_back(\"" << Name << "\" + "
<< "*B);\n";
break;
case OptionType::ParameterList:
<< "::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(\"" << Name << "\");\n"
<< Indent4 << "vec.push_back(*B);\n"
<< Indent3 << "}\n";
break;
for (OptionPropertyList::const_iterator B = D.Props.begin(),
E = D.Props.end(); B != E; ++B) {
const OptionProperty& OptProp = *B;
- if (OptProp.first == OptionPropertyType::AppendCmd)
+ if (OptProp.first == OptionPropertyType::AppendCmd
+ || OptProp.first == OptionPropertyType::ForwardAs)
ret = true;
}
if (D.isForward() || D.isUnpackValues())
case OptionPropertyType::AppendCmd:
O << Indent3 << "vec.push_back(\"" << val.second << "\");\n";
break;
+ // (forward_as) property
+ case OptionPropertyType::ForwardAs:
+ EmitForwardOptionPropertyHandlingCode(D, val.second, O);
+ break;
// Other properties with argument
default:
break;
// (forward) property
if (D.isForward())
- EmitForwardOptionPropertyHandlingCode(D, O);
+ EmitForwardOptionPropertyHandlingCode(D, "", O);
// (unpack_values) property
if (D.isUnpackValues()) {
O << Indent1 << "Action GenerateAction(const sys::Path& inFile,\n";
O << Indent2 << "const sys::Path& outFile,\n"
- << Indent2 << "const InputLanguagesSet& InLangs) const\n"
+ << Indent2 << "const InputLanguagesSet& InLangs,\n"
+ << Indent2 << "const LanguageMap& LangMap) const\n"
<< Indent1 << "{\n"
<< Indent2 << "const char* cmd;\n"
<< Indent2 << "std::vector<std::string> vec;\n";
if (!P.isJoin())
O << Indent1 << "Action GenerateAction(const PathVector& inFiles,\n"
<< Indent2 << "const llvm::sys::Path& outFile,\n"
- << Indent2 << "const InputLanguagesSet& InLangs) const\n"
+ << Indent2 << "const InputLanguagesSet& InLangs,\n"
+ << Indent2 << "const LanguageMap& LangMap) const\n"
<< Indent1 << "{\n"
<< Indent2 << "throw std::runtime_error(\"" << P.Name
<< " is not a Join tool!\");\n"
throw std::string("Error in the language map definition!");
// Generate code
- O << "void llvmc::PopulateLanguageMap() {\n";
+ O << "namespace {\n\n";
+ O << "void PopulateLanguageMapLocal(LanguageMap& langMap) {\n";
for (unsigned i = 0; i < LangsToSuffixesList->size(); ++i) {
Record* LangToSuffixes = LangsToSuffixesList->getElementAsRecord(i);
const ListInit* Suffixes = LangToSuffixes->getValueAsListInit("suffixes");
for (unsigned i = 0; i < Suffixes->size(); ++i)
- O << Indent1 << "GlobalLanguageMap[\""
+ O << Indent1 << "langMap[\""
<< InitPtrToString(Suffixes->getElement(i))
<< "\"] = \"" << Lang << "\";\n";
}
- O << "}\n\n";
+ O << "}\n\n}\n\n";
}
/// FillInToolToLang - Fills in two tables that map tool names to
// and multiple default edges in the graph (better error
// reporting). Unfortunately, it is awkward to do right now because
// our intermediate representation is not sufficiently
-// sofisticated. Algorithms like these should be run on a real graph
-// instead of AST.
+// sophisticated. Algorithms like these require a real graph instead of
+// an AST.
void TypecheckGraph (Record* CompilationGraph,
const ToolPropertiesList& TPList) {
StringMap<StringSet<> > ToolToInLang;
ListInit* edges = CompilationGraph->getValueAsListInit("edges");
// Generate code
- O << "void llvmc::PopulateCompilationGraph(CompilationGraph& G) {\n"
- << Indent1 << "PopulateLanguageMap();\n\n";
+ O << "namespace {\n\n";
+ O << "void PopulateCompilationGraphLocal(CompilationGraph& G) {\n";
// Insert vertices
O << ");\n";
}
- O << "}\n\n";
+ O << "}\n\n}\n\n";
}
/// ExtractHookNames - Extract the hook names from all instances of
O << "}\n\n";
}
+/// EmitRegisterPlugin - Emit code to register this plugin.
+void EmitRegisterPlugin(std::ostream& O) {
+ O << "namespace {\n\n"
+ << "struct Plugin : public llvmc::BasePlugin {\n"
+ << Indent1 << "void PopulateLanguageMap(LanguageMap& langMap) const\n"
+ << Indent1 << "{ PopulateLanguageMapLocal(langMap); }\n\n"
+ << Indent1
+ << "void PopulateCompilationGraph(CompilationGraph& graph) const\n"
+ << Indent1 << "{ PopulateCompilationGraphLocal(graph); }\n"
+ << "};\n\n"
+
+ << "static llvmc::RegisterPlugin<Plugin> RP;\n\n}\n\n";
+}
+
+/// EmitInclude - Emit necessary #include directives.
+void EmitIncludes(std::ostream& O) {
+ O << "#include \"llvm/CompilerDriver/CompilationGraph.h\"\n"
+ << "#include \"llvm/CompilerDriver/Plugin.h\"\n"
+ << "#include \"llvm/CompilerDriver/Tool.h\"\n\n"
+
+ << "#include \"llvm/ADT/StringExtras.h\"\n"
+ << "#include \"llvm/Support/CommandLine.h\"\n\n"
+
+ << "#include <cstdlib>\n"
+ << "#include <stdexcept>\n\n"
+
+ << "using namespace llvm;\n"
+ << "using namespace llvmc;\n\n"
+
+ << "extern cl::opt<std::string> OutputFilename;\n\n";
+}
+
// End of anonymous namespace
}
// Emit file header.
EmitSourceFileHeader("LLVMC Configuration Library", O);
+ EmitIncludes(O);
// Get a list of all defined Tools.
RecordVector Tools = Records.getAllDerivedDefinitions("Tool");
CollectPropertiesFromOptionList(OptionLists.begin(), OptionLists.end(),
opt_descs);
+ // Check that there are no options without side effects (specified
+ // only in the OptionList).
+ CheckForSuperfluousOptions(tool_props, opt_descs);
+
// Emit global option registration code.
EmitOptionDescriptions(opt_descs, O);
// Emit PopulateCompilationGraph() function.
EmitPopulateCompilationGraph(CompilationGraphRecord, O);
+ // Emit code for plugin registration.
+ EmitRegisterPlugin(O);
+
// EOF
} catch (std::exception& Error) {
throw Error.what() + std::string(" - usually this means a syntax error.");