mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-13 04:30:23 +00:00
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:
parent
5a1a53e450
commit
0a22fb6664
@ -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> {
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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<
|
||||
|
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user