diff options
author | Simon Tatham <simon.tatham@arm.com> | 2020-01-14 09:10:18 +0000 |
---|---|---|
committer | Simon Tatham <simon.tatham@arm.com> | 2020-01-14 10:19:53 +0000 |
commit | 3388b0f59dcc7813278c753f96b66229f290cc59 (patch) | |
tree | d64f8dcbead51b2deb74e75afe7f86b4516bb5e5 /llvm/docs/TableGen | |
parent | 45924eb4671692b3fa9fd52fe39c81ec0647a848 (diff) | |
download | bcm5719-llvm-3388b0f59dcc7813278c753f96b66229f290cc59.tar.gz bcm5719-llvm-3388b0f59dcc7813278c753f96b66229f290cc59.zip |
[TableGen] Introduce a `defvar` statement.
Summary:
This allows you to define a global or local variable to an arbitrary
value, and refer to it in subsequent definitions.
The main use I anticipate for this is if you have to compute some
difficult function of the parameters of a multiclass, and then use it
many times. For example:
multiclass Foo<int i, string s> {
defvar op = !cast<BaseClass>("whatnot_" # s # "_" # i);
def myRecord {
dag a = (op this, (op that, the other), (op x, y, z));
int b = op.subfield;
}
def myOtherRecord<"template params including", op>;
}
There are a couple of ways to do this already, but they're not really
satisfactory. You can replace `defvar x = y` with a loop over a
singleton list, `foreach x = [y] in { ... }` - but that's unintuitive
to someone who hasn't seen that workaround idiom before, and requires
an extra pair of braces that you often didn't really want. Or you can
define a nested pair of multiclasses, with the inner one taking `x` as
a template parameter, and the outer one instantiating it just once
with the desired value of `x` computed from its other parameters - but
that makes it awkward to sequentially compute each value based on the
previous ones. I think `defvar` makes things considerably easier.
You can also use `defvar` at the top level, where it inserts globals
into the same map used by `defset`. That allows you to define global
constants without having to make a dummy record for them to live in:
defvar MAX_BUFSIZE = 512;
// previously:
// def Dummy { int MAX_BUFSIZE = 512; }
// and then refer to Dummy.MAX_BUFSIZE everywhere
Reviewers: nhaehnle, hfinkel
Reviewed By: hfinkel
Subscribers: hiraditya, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D71407
Diffstat (limited to 'llvm/docs/TableGen')
-rw-r--r-- | llvm/docs/TableGen/LangRef.rst | 41 |
1 files changed, 36 insertions, 5 deletions
diff --git a/llvm/docs/TableGen/LangRef.rst b/llvm/docs/TableGen/LangRef.rst index 8f8b3613db5..7cbe6d99643 100644 --- a/llvm/docs/TableGen/LangRef.rst +++ b/llvm/docs/TableGen/LangRef.rst @@ -124,8 +124,8 @@ TableGen's top-level production consists of "objects". .. productionlist:: TableGenFile: `Object`* - Object: `Class` | `Def` | `Defm` | `Defset` | `Let` | `MultiClass` | - `Foreach` + Object: `Class` | `Def` | `Defm` | `Defset` | `Defvar` | `Let` | + `MultiClass` | `Foreach` ``class``\es ------------ @@ -262,7 +262,7 @@ of: foreach i = 0-5 in def Foo#i; -* a variable defined by ``defset`` +* a variable defined by ``defset`` or ``defvar`` * the implicit template argument ``NAME`` in a ``class`` or ``multiclass`` @@ -348,6 +348,7 @@ It is after parsing the base class list that the "let stack" is applied. BodyList: BodyItem* BodyItem: `Declaration` ";" :| "let" `TokIdentifier` [ "{" `RangeList` "}" ] "=" `Value` ";" + :| `Defvar` The ``let`` form allows overriding the value of an inherited field. @@ -359,8 +360,8 @@ The ``let`` form allows overriding the value of an inherited field. Defines a record whose name is given by the optional :token:`Value`. The value is parsed in a special mode where global identifiers (records and variables -defined by ``defset``) are not recognized, and all unrecognized identifiers -are interpreted as strings. +defined by ``defset``, and variables defined at global scope by ``defvar``) are +not recognized, and all unrecognized identifiers are interpreted as strings. If no name is given, the record is anonymous. The final name of anonymous records is undefined, but globally unique. @@ -420,6 +421,36 @@ The given type must be ``list<A>``, where ``A`` is some class. It is an error to define a record (via ``def`` or ``defm``) inside the braces which doesn't derive from ``A``. +``defvar`` +---------- +.. productionlist:: + Defvar: "defvar" `TokIdentifier` "=" `Value` ";" + +The identifier on the left of the ``=`` is defined to be a global or local +variable, whose value is given by the expression on the right of the ``=``. The +type of the variable is automatically inferred. + +A ``defvar`` statement at the top level of the file defines a global variable, +in the same scope used by ``defset``. If a ``defvar`` statement appears inside +any other construction, including classes, multiclasses and ``foreach`` +statements, then the variable is scoped to the inside of that construction +only. + +In contexts where the ``defvar`` statement will be encountered multiple times, +the definition is re-evaluated for each instance. For example, a ``defvar`` +inside a ``foreach`` can construct a value based on the iteration variable, +which will be different every time round the loop; a ``defvar`` inside a +templated class or multiclass can have a definition depending on the template +parameters. + +Variables local to a ``foreach`` go out of scope at the end of each loop +iteration, so their previous value is not accessible in the next iteration. (It +won't work to ``defvar i=!add(i,1)`` each time you go round the loop.) + +In general, ``defvar`` variables are immutable once they are defined. It is an +error to define the same variable name twice in the same scope (but legal to +shadow the first definition temporarily in an inner scope). + ``foreach`` ----------- |