Add a 'set_option' action for use in OptionPreprocessor.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@91594 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Mikhail Glushenkov 2009-12-17 07:49:16 +00:00
parent 24723288a2
commit 994dbe0073
5 changed files with 111 additions and 42 deletions

View File

@ -84,6 +84,7 @@ def stop_compilation;
def unpack_values;
def warning;
def error;
def set_option;
def unset_option;
// Increase/decrease the edge weight.

View File

@ -11,20 +11,30 @@ def OptList : OptionList<[
(switch_option "baz", (help "dummy")),
(parameter_option "foo_p", (help "dummy")),
(parameter_option "bar_p", (help "dummy")),
(parameter_option "baz_p", (help "dummy"))
(parameter_option "baz_p", (help "dummy")),
(parameter_list_option "foo_l", (help "dummy"))
]>;
def Preprocess : OptionPreprocessor<
(case
// CHECK: W1
// CHECK: foo = false;
// CHECK: foo_p = "";
// CHECK: foo_l.clear();
(and (switch_on "foo"), (any_switch_on ["bar", "baz"])),
(warning "W1"),
[(warning "W1"), (unset_option "foo"),
(unset_option "foo_p"), (unset_option "foo_l")],
// CHECK: W2
// CHECK: foo = true;
// CHECK: foo_p = "asdf";
(and (switch_on ["foo", "bar"]), (any_empty ["foo_p", "bar_p"])),
(warning "W2"),
[(warning "W2"), (set_option "foo"), (set_option "foo_p", "asdf")],
// CHECK: W3
// CHECK: foo = true;
// CHECK: bar = true;
// CHECK: baz = true;
(and (empty ["foo_p", "bar_p"]), (any_not_empty ["baz_p"])),
(warning "W3"))
[(warning "W3"), (set_option ["foo", "bar", "baz"])])
>;
// Shut up warnings...
@ -38,7 +48,8 @@ def dummy : Tool<
(switch_on "baz"), (error),
(not_empty "foo_p"), (error),
(not_empty "bar_p"), (error),
(not_empty "baz_p"), (error)))
(not_empty "baz_p"), (error),
(not_empty "foo_l"), (error)))
]>;
def Graph : CompilationGraph<[Edge<"root", "dummy">]>;

View File

@ -656,10 +656,10 @@ For example, without those definitions the following command wouldn't work::
$ llvmc hello.cpp
llvmc: Unknown suffix: cpp
The language map entries should be added only for tools that are
linked with the root node. Since tools are not allowed to have
multiple output languages, for nodes "inside" the graph the input and
output languages should match. This is enforced at compile-time.
The language map entries are needed only for the tools that are linked from the
root node. Since a tool can't have multiple output languages, for inner nodes of
the graph the input and output languages should match. This is enforced at
compile-time.
Option preprocessor
===================
@ -672,24 +672,31 @@ the driver with both of these options enabled.
The ``OptionPreprocessor`` feature is reserved specially for these
occasions. Example (adapted from the built-in Base plugin)::
def Preprocess : OptionPreprocessor<
(case (and (switch_on "O3"), (any_switch_on ["O0", "O1", "O2"])),
[(unset_option ["O0", "O1", "O2"]),
(warning "Multiple -O options specified, defaulted to -O3.")],
(and (switch_on "O2"), (any_switch_on ["O0", "O1"])),
(unset_option ["O0", "O1"]),
(and (switch_on "O1"), (switch_on "O0")),
(unset_option "O0"))
>;
Here, ``OptionPreprocessor`` is used to unset all spurious optimization options
(so that they are not forwarded to the compiler).
def Preprocess : OptionPreprocessor<
(case (not (any_switch_on ["O0", "O1", "O2", "O3"])),
(set_option "O2"),
(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"))
>;
Here, ``OptionPreprocessor`` is used to unset all spurious ``-O`` options so
that they are not forwarded to the compiler. If no optimization options are
specified, ``-O2`` is enabled.
``OptionPreprocessor`` is basically a single big ``case`` expression, which is
evaluated only once right after the plugin is loaded. The only allowed actions
in ``OptionPreprocessor`` are ``error``, ``warning`` and a special action
``unset_option``, which, as the name suggests, unsets a given option. For
convenience, ``unset_option`` also works on lists.
in ``OptionPreprocessor`` are ``error``, ``warning`` and two special actions:
``unset_option`` and ``set_option``. As their names suggest, they can be used to
set or unset a given option. To set a parameter option with ``set_option``, use
the two-argument form: ``(set_option "parameter", "value")``. For convenience,
``set_option`` and ``unset_option`` also work on lists (that is, instead of
``[(unset_option "A"), (unset_option "B")]`` you can use ``(unset_option ["A",
"B"])``).
More advanced topics

View File

@ -91,7 +91,9 @@ def OptList : OptionList<[
// Option preprocessor.
def Preprocess : OptionPreprocessor<
(case (and (switch_on "O3"), (any_switch_on ["O0", "O1", "O2"])),
(case (not (any_switch_on ["O0", "O1", "O2", "O3"])),
(set_option "O2"),
(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"]),

View File

@ -2303,11 +2303,32 @@ class EmitPreprocessOptionsCallback :
public HandlerTable<EmitPreprocessOptionsCallbackHandler>
{
typedef EmitPreprocessOptionsCallbackHandler Handler;
typedef void
(EmitPreprocessOptionsCallback::* HandlerImpl)
(const Init*, unsigned, raw_ostream&) const;
const OptionDescriptions& OptDescs_;
void onUnsetOptionStr(const Init* I,
unsigned IndentLevel, raw_ostream& O) const
void onListOrDag(HandlerImpl h,
const DagInit& d, unsigned IndentLevel, raw_ostream& O) const
{
checkNumberOfArguments(d, 1);
const Init* I = d.getArg(0);
// If I is a list, apply h to each element.
if (typeid(*I) == typeid(ListInit)) {
const ListInit& L = *static_cast<const ListInit*>(I);
for (ListInit::const_iterator B = L.begin(), E = L.end(); B != E; ++B)
((this)->*(h))(*B, IndentLevel, O);
}
// Otherwise, apply h to I.
else {
((this)->*(h))(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);
@ -2326,26 +2347,52 @@ class EmitPreprocessOptionsCallback :
}
}
void onUnsetOptionList(const ListInit& L,
unsigned IndentLevel, raw_ostream& O) const
{
for (ListInit::const_iterator B = L.begin(), E = L.end(); B != E; ++B)
this->onUnsetOptionStr(*B, IndentLevel, O);
}
void onUnsetOption(const DagInit& d,
unsigned IndentLevel, raw_ostream& O) const
{
checkNumberOfArguments(d, 1);
Init* I = d.getArg(0);
this->onListOrDag(&EmitPreprocessOptionsCallback::onUnsetOptionImpl,
d, IndentLevel, O);
}
if (typeid(*I) == typeid(ListInit)) {
const ListInit& L = *static_cast<const ListInit*>(I);
this->onUnsetOptionList(L, IndentLevel, O);
}
else {
this->onUnsetOptionStr(I, IndentLevel, O);
}
void onSetParameter(const DagInit& d,
unsigned IndentLevel, raw_ostream& O) const {
checkNumberOfArguments(d, 2);
const std::string& OptName = InitPtrToString(d.getArg(0));
const std::string& Value = InitPtrToString(d.getArg(1));
const OptionDescription& OptDesc = OptDescs_.FindOption(OptName);
if (OptDesc.isParameter())
O.indent(IndentLevel) << OptDesc.GenVariableName()
<< " = \"" << Value << "\";\n";
else
throw "Two-argument 'set_option' "
"can be only applied to parameter options!";
}
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 "One-argument 'set_option' can be only applied to switch options!";
}
void onSetOption(const DagInit& d,
unsigned IndentLevel, raw_ostream& O) const
{
checkNumberOfArguments(d, 1);
// Two arguments: (set_option "parameter", "value")
if (d.getNumArgs() > 1)
this->onSetParameter(d, IndentLevel, O);
// One argument: (set_option "switch")
// or (set_option ["switch1", "switch2", ...])
else
this->onListOrDag(&EmitPreprocessOptionsCallback::onSetSwitch,
d, IndentLevel, O);
}
public:
@ -2357,6 +2404,7 @@ public:
AddHandler("error", &EmitPreprocessOptionsCallback::onErrorDag);
AddHandler("warning", &EmitPreprocessOptionsCallback::onWarningDag);
AddHandler("unset_option", &EmitPreprocessOptionsCallback::onUnsetOption);
AddHandler("set_option", &EmitPreprocessOptionsCallback::onSetOption);
staticMembersInitialized_ = true;
}