First draft of the OptionPreprocessor.

More to follow...

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@84352 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Mikhail Glushenkov 2009-10-17 20:09:29 +00:00
parent 5a1a53e450
commit 0a22fb6664
6 changed files with 232 additions and 52 deletions

View File

@ -68,6 +68,8 @@ def not_empty;
def default;
def single_input_file;
def multiple_input_files;
def any_switch_on;
def any_not_empty;
// Possible actions.
@ -76,7 +78,9 @@ def forward;
def forward_as;
def stop_compilation;
def unpack_values;
def warning;
def error;
def unset_option;
// Increase/decrease the edge weight.
def inc_weight;
@ -90,11 +94,16 @@ class PluginPriority<int p> {
int priority = p;
}
// Option list - used to specify aliases and sometimes help strings.
// Option list - a single place to specify options.
class OptionList<list<dag> l> {
list<dag> options = l;
}
// Option preprocessor - actions taken during plugin loading.
class OptionPreprocessor<dag d> {
dag preprocessor = d;
}
// Map from suffixes to language names
class LangToSuffixes<string str, list<string> lst> {

View File

@ -29,6 +29,11 @@ namespace llvmc {
/// first.
virtual int Priority() const { return 0; }
/// PreprocessOptions - The auto-generated function that performs various
/// consistency checks on options (like ensuring that -O2 and -O3 are not
/// used together).
virtual void PreprocessOptions() const = 0;
/// PopulateLanguageMap - The auto-generated function that fills in
/// the language map (map from file extensions to language names).
virtual void PopulateLanguageMap(LanguageMap&) const = 0;
@ -60,13 +65,10 @@ namespace llvmc {
PluginLoader();
~PluginLoader();
/// PopulateLanguageMap - Fills in the language map by calling
/// PopulateLanguageMap methods of all plugins.
void PopulateLanguageMap(LanguageMap& langMap);
/// PopulateCompilationGraph - Populates the compilation graph by
/// calling PopulateCompilationGraph methods of all plugins.
void PopulateCompilationGraph(CompilationGraph& tools);
/// RunInitialization - Calls PreprocessOptions, PopulateLanguageMap and
/// PopulateCompilationGraph methods of all plugins. This populates the
/// global language map and the compilation graph.
void RunInitialization(LanguageMap& langMap, CompilationGraph& graph) const;
private:
// noncopyable

View File

@ -95,8 +95,7 @@ int Main(int argc, char** argv) {
(argc, argv, "LLVM Compiler Driver (Work In Progress)", true);
PluginLoader Plugins;
Plugins.PopulateLanguageMap(langMap);
Plugins.PopulateCompilationGraph(graph);
Plugins.RunInitialization(langMap, graph);
if (CheckGraph) {
int ret = graph.Check();

View File

@ -62,18 +62,17 @@ namespace llvmc {
pluginListInitialized = false;
}
void PluginLoader::PopulateLanguageMap(LanguageMap& langMap) {
void PluginLoader::RunInitialization(LanguageMap& langMap,
CompilationGraph& graph) const
{
llvm::sys::SmartScopedLock<true> Lock(*PluginMutex);
for (PluginList::iterator B = Plugins.begin(), E = Plugins.end();
B != E; ++B)
(*B)->PopulateLanguageMap(langMap);
}
void PluginLoader::PopulateCompilationGraph(CompilationGraph& graph) {
llvm::sys::SmartScopedLock<true> Lock(*PluginMutex);
for (PluginList::iterator B = Plugins.begin(), E = Plugins.end();
B != E; ++B)
(*B)->PopulateCompilationGraph(graph);
B != E; ++B) {
const BasePlugin* BP = *B;
BP->PreprocessOptions();
BP->PopulateLanguageMap(langMap);
BP->PopulateCompilationGraph(graph);
}
}
}

View File

@ -65,6 +65,18 @@ def OptList : OptionList<[
(help "Pass options to opt"))
]>;
// Option preprocessor.
def Preprocess : OptionPreprocessor<
(case (and (switch_on "O3"), (any_switch_on ["O0", "O1", "O2"])),
(unset_option ["O0", "O1", "O2"]),
(and (switch_on "O2"), (any_switch_on ["O0", "O1"])),
(unset_option ["O0", "O1"]),
(and (switch_on "O1"), (switch_on "O0")),
(unset_option "O0"))
>;
// Tools
class llvm_gcc_based <string cmd_prefix, string in_lang, string E_ext> : Tool<

View File

@ -351,6 +351,9 @@ class OptionDescriptions {
public:
/// FindOption - exception-throwing wrapper for find().
const OptionDescription& FindOption(const std::string& OptName) const;
/// FindSwitch - wrapper for FindOption that throws in case the option is not
/// a switch.
const OptionDescription& FindSwitch(const std::string& OptName) const;
/// insertDescription - Insert new OptionDescription into
/// OptionDescriptions list
@ -372,6 +375,15 @@ OptionDescriptions::FindOption(const std::string& OptName) const
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;
}
void OptionDescriptions::InsertDescription (const OptionDescription& o)
{
container_type::iterator I = Descriptions.find(o.Name);
@ -996,32 +1008,31 @@ bool EmitCaseTest0Args(const std::string& TestName, raw_ostream& O) {
return false;
}
/// EmitCaseTest1Arg - Helper function used by EmitCaseConstructHandler().
bool EmitCaseTest1Arg(const std::string& TestName,
const DagInit& d,
const OptionDescriptions& OptDescs,
raw_ostream& O) {
checkNumberOfArguments(&d, 1);
/// EmitCaseTest1ArgStr - Helper function used by EmitCaseTest1Arg();
bool EmitCaseTest1ArgStr(const std::string& TestName,
const DagInit& d,
const OptionDescriptions& OptDescs,
raw_ostream& O) {
const std::string& OptName = InitPtrToString(d.getArg(0));
if (TestName == "switch_on") {
const OptionDescription& OptDesc = OptDescs.FindOption(OptName);
if (!OptDesc.isSwitch())
throw OptName + ": incorrect option type - should be a switch!";
const OptionDescription& OptDesc = OptDescs.FindSwitch(OptName);
O << OptDesc.GenVariableName();
return true;
} else if (TestName == "input_languages_contain") {
}
else if (TestName == "input_languages_contain") {
O << "InLangs.count(\"" << OptName << "\") != 0";
return true;
} else if (TestName == "in_language") {
}
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) == \"" << OptName << '\"';
return true;
} else if (TestName == "not_empty" || TestName == "empty") {
}
else if (TestName == "not_empty" || TestName == "empty") {
const char* Test = (TestName == "empty") ? "" : "!";
if (OptName == "o") {
@ -1041,6 +1052,47 @@ bool EmitCaseTest1Arg(const std::string& TestName,
return false;
}
/// EmitCaseTest1ArgList - Helper function used by EmitCaseTest1Arg();
bool EmitCaseTest1ArgList(const std::string& TestName,
const DagInit& d,
const OptionDescriptions& OptDescs,
raw_ostream& O) {
const ListInit& L = *static_cast<ListInit*>(d.getArg(0));
if (TestName == "any_switch_on") {
bool isFirst = true;
for (ListInit::const_iterator B = L.begin(), E = L.end(); B != E; ++B) {
const std::string& OptName = InitPtrToString(*B);
const OptionDescription& OptDesc = OptDescs.FindSwitch(OptName);
if (isFirst)
isFirst = false;
else
O << " || ";
O << OptDesc.GenVariableName();
}
return true;
}
// TODO: implement any_not_empty, any_empty, switch_on [..], empty [..]
return false;
}
/// EmitCaseTest1Arg - Helper function used by EmitCaseConstructHandler();
bool EmitCaseTest1Arg(const std::string& TestName,
const DagInit& d,
const OptionDescriptions& OptDescs,
raw_ostream& O) {
checkNumberOfArguments(&d, 1);
if (typeid(*d.getArg(0)) == typeid(ListInit))
return EmitCaseTest1ArgList(TestName, d, OptDescs, O);
else
return EmitCaseTest1ArgStr(TestName, d, OptDescs, O);
}
/// EmitCaseTest2Args - Helper function used by EmitCaseConstructHandler().
bool EmitCaseTest2Args(const std::string& TestName,
const DagInit& d,
@ -1130,10 +1182,14 @@ void EmitCaseTest(const DagInit& d, unsigned IndentLevel,
throw TestName + ": unknown edge property!";
}
// Emit code that handles the 'case' construct.
// Takes a function object that should emit code for every case clause.
// Callback's type is
// void F(Init* Statement, unsigned IndentLevel, raw_ostream& O).
/// EmitCaseConstructHandler - Emit code that handles the 'case'
/// construct. Takes a function object that should emit code for every case
/// clause.
/// Callback's type is void F(Init* Statement, unsigned IndentLevel,
/// raw_ostream& O).
/// EmitElseIf parameter controls the type of condition that is emitted ('if
/// (..) {...} else if (...) {} ... else {...}' vs. 'if (..) {...} if(...)
/// {...} ...').
template <typename F>
void EmitCaseConstructHandler(const Init* Dag, unsigned IndentLevel,
F Callback, bool EmitElseIf,
@ -1876,10 +1932,108 @@ void EmitOptionDefinitions (const OptionDescriptions& descs,
O << '\n';
}
/// EmitPopulateLanguageMap - Emit the PopulateLanguageMap() function.
/// PreprocessOptionsCallback - Helper function passed to
/// EmitCaseConstructHandler() by EmitPreprocessOptions().
class PreprocessOptionsCallback {
const OptionDescriptions& OptDescs_;
void onUnsetOption(Init* i, unsigned IndentLevel, raw_ostream& O) {
const std::string& OptName = InitPtrToString(i);
const OptionDescription& OptDesc = OptDescs_.FindOption(OptName);
const OptionType::OptionType OptType = OptDesc.Type;
if (OptType == OptionType::Switch) {
O.indent(IndentLevel) << OptDesc.GenVariableName() << " = false;\n";
}
else if (OptType == OptionType::Parameter
|| OptType == OptionType::Prefix) {
O.indent(IndentLevel) << OptDesc.GenVariableName() << " = \"\";\n";
}
else {
throw std::string("'unset_option' can only be applied to "
"switches or parameter/prefix options.");
}
}
void processDag(const Init* I, unsigned IndentLevel, raw_ostream& O)
{
const DagInit& d = InitPtrToDag(I);
const std::string& OpName = d.getOperator()->getAsString();
// TOFIX: there is some duplication between this function and
// EmitActionHandler.
if (OpName == "warning") {
checkNumberOfArguments(&d, 1);
O.indent(IndentLevel) << "llvm::errs() << \""
<< InitPtrToString(d.getArg(0)) << "\";\n";
}
else if (OpName == "error") {
checkNumberOfArguments(&d, 1);
O.indent(IndentLevel) << "throw std::runtime_error(\""
<< InitPtrToString(d.getArg(0))
<< "\");\n";
}
else if (OpName == "unset_option") {
checkNumberOfArguments(&d, 1);
Init* I = d.getArg(0);
if (typeid(*I) == typeid(ListInit)) {
const ListInit& DagList = *static_cast<const ListInit*>(I);
for (ListInit::const_iterator B = DagList.begin(), E = DagList.end();
B != E; ++B)
this->onUnsetOption(*B, IndentLevel, O);
}
else {
this->onUnsetOption(I, IndentLevel, O);
}
}
else {
throw "Unknown operator in the option preprocessor: '" + OpName + "'!"
"\nOnly 'warning', 'error' and 'unset_option' are allowed.";
}
}
public:
// TODO: Remove duplication.
void operator()(const Init* I, unsigned IndentLevel, raw_ostream& O) {
if (typeid(*I) == typeid(ListInit)) {
const ListInit& DagList = *static_cast<const ListInit*>(I);
for (ListInit::const_iterator B = DagList.begin(), E = DagList.end();
B != E; ++B)
this->processDag(*B, IndentLevel, O);
}
else {
this->processDag(I, IndentLevel, O);
}
}
PreprocessOptionsCallback(const OptionDescriptions& OptDescs)
: OptDescs_(OptDescs)
{}
};
/// EmitPreprocessOptions - Emit the PreprocessOptionsLocal() function.
void EmitPreprocessOptions (const RecordKeeper& Records,
const OptionDescriptions& OptDecs, raw_ostream& O)
{
O << "void PreprocessOptionsLocal() {\n";
const RecordVector& OptionPreprocessors =
Records.getAllDerivedDefinitions("OptionPreprocessor");
for (RecordVector::const_iterator B = OptionPreprocessors.begin(),
E = OptionPreprocessors.end(); B!=E; ++B) {
DagInit* Case = (*B)->getValueAsDag("preprocessor");
EmitCaseConstructHandler(Case, Indent1, PreprocessOptionsCallback(OptDecs),
false, OptDecs, O);
}
O << "}\n\n";
}
/// EmitPopulateLanguageMap - Emit the PopulateLanguageMapLocal() function.
void EmitPopulateLanguageMap (const RecordKeeper& Records, raw_ostream& O)
{
// Generate code
O << "void PopulateLanguageMapLocal(LanguageMap& langMap) {\n";
// Get the relevant field out of RecordKeeper
@ -1922,17 +2076,16 @@ void IncDecWeight (const Init* i, unsigned IndentLevel,
O.indent(IndentLevel) << "ret -= ";
}
else if (OpName == "error") {
O.indent(IndentLevel)
<< "throw std::runtime_error(\"" <<
(d.getNumArgs() >= 1 ? InitPtrToString(d.getArg(0))
: "Unknown error!")
<< "\");\n";
checkNumberOfArguments(&d, 1);
O.indent(IndentLevel) << "throw std::runtime_error(\""
<< InitPtrToString(d.getArg(0))
<< "\");\n";
return;
}
else
throw "Unknown operator in edge properties list: " + OpName + '!' +
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";
@ -1981,7 +2134,7 @@ void EmitEdgeClasses (const RecordVector& EdgeVector,
}
}
/// EmitPopulateCompilationGraph - Emit the PopulateCompilationGraph()
/// EmitPopulateCompilationGraph - Emit the PopulateCompilationGraphLocal()
/// function.
void EmitPopulateCompilationGraph (const RecordVector& EdgeVector,
const ToolDescriptions& ToolDescs,
@ -2110,6 +2263,8 @@ void EmitRegisterPlugin(int Priority, raw_ostream& O) {
O << "struct Plugin : public llvmc::BasePlugin {\n\n";
O.indent(Indent1) << "int Priority() const { return "
<< Priority << "; }\n\n";
O.indent(Indent1) << "void PreprocessOptions() const\n";
O.indent(Indent1) << "{ PreprocessOptionsLocal(); }\n\n";
O.indent(Indent1) << "void PopulateLanguageMap(LanguageMap& langMap) const\n";
O.indent(Indent1) << "{ PopulateLanguageMapLocal(langMap); }\n\n";
O.indent(Indent1)
@ -2129,7 +2284,8 @@ void EmitIncludes(raw_ostream& O) {
<< "#include \"llvm/CompilerDriver/Tool.h\"\n\n"
<< "#include \"llvm/ADT/StringExtras.h\"\n"
<< "#include \"llvm/Support/CommandLine.h\"\n\n"
<< "#include \"llvm/Support/CommandLine.h\"\n"
<< "#include \"llvm/Support/raw_ostream.h\"\n\n"
<< "#include <cstdlib>\n"
<< "#include <stdexcept>\n\n"
@ -2229,8 +2385,11 @@ void EmitPluginCode(const PluginData& Data, raw_ostream& O) {
O << "namespace {\n\n";
// Emit PopulateLanguageMap() function
// (a language map maps from file extensions to language names).
// Emit PreprocessOptionsLocal() function.
EmitPreprocessOptions(Records, Data.OptDescs, O);
// Emit PopulateLanguageMapLocal() function
// (language map maps from file extensions to language names).
EmitPopulateLanguageMap(Records, O);
// Emit Tool classes.
@ -2241,7 +2400,7 @@ void EmitPluginCode(const PluginData& Data, raw_ostream& O) {
// Emit Edge# classes.
EmitEdgeClasses(Data.Edges, Data.OptDescs, O);
// Emit PopulateCompilationGraph() function.
// Emit PopulateCompilationGraphLocal() function.
EmitPopulateCompilationGraph(Data.Edges, Data.ToolDescs, O);
// Emit code for plugin registration.