1 TableGen Programmer’s Reference#
1.1 Introduction#
The purpose of TableGen is to generate complex output files based on
information from source files that are significantly easier to code than the
output files would be, and also easier to maintain and modify over time. The
information is coded in a declarative style involving classes and records,
which are then processed by TableGen. The internalized records are passed on
to various backends, which extract information from a subset of the records
and generate one or more output files. These output files are typically
.inc files for C++, but may be any type of file that the backend
developer needs.
This document describes the LLVM TableGen facility in detail. It is intended
for the programmer who is using TableGen to produce code for a project. If
you are looking for a simple overview, check out the TableGen Overview. The various *-tblgen commands used to invoke TableGen are
described in tblgen Family - Description to C++
Code.
An example of a backend is RegisterInfo, which generates the register
file information for a particular target machine, for use by the LLVM
target-independent code generator. See TableGen Backends
for a description of the LLVM TableGen backends, and TableGen
Backend Developer’s Guide for a guide to writing a new
backend.
Here are a few of the things backends can do.
Generate the register file information for a particular target machine.
Generate the instruction definitions for a target.
Generate the patterns that the code generator uses to match instructions to intermediate representation (IR) nodes.
Generate semantic attribute identifiers for Clang.
Generate abstract syntax tree (AST) declaration node definitions for Clang.
Generate AST statement node definitions for Clang.
1.1.1 Concepts#
TableGen source files contain two primary items: abstract records and concrete records. In this and other TableGen documents, abstract records are called classes. (These classes are different from C++ classes and do not map onto them.) In addition, concrete records are usually just called records, although sometimes the term record refers to both classes and concrete records. The distinction should be clear in context.
Classes and concrete records have a unique name, either chosen by the programmer or generated by TableGen. Associated with that name is a list of fields with values and an optional list of parent classes (sometimes called base or super classes). The fields are the primary data that backends will process. Note that TableGen assigns no meaning to fields; the meanings are entirely up to the backends and the programs that incorporate the output of those backends.
Note
The term “parent class” can refer to a class that is a parent of another class, and also to a class from which a concrete record inherits. This nonstandard use of the term arises because TableGen treats classes and concrete records similarly.
A backend processes some subset of the concrete records built by the
TableGen parser and emits the output files. These files are usually C++
.inc files that are included by the programs that require the data in
those records. However, a backend can produce any type of output files. For
example, it could produce a data file containing messages tagged with
identifiers and substitution parameters. In a complex use case such as the
LLVM code generator, there can be many concrete records and some of them can
have an unexpectedly large number of fields, resulting in large output files.
In order to reduce the complexity of TableGen files, classes are used to abstract out groups of record fields. For example, a few classes may abstract the concept of a machine register file, while other classes may abstract the instruction formats, and still others may abstract the individual instructions. TableGen allows an arbitrary hierarchy of classes, so that the abstract classes for two concepts can share a third superclass that abstracts common “sub-concepts” from the two original concepts.
In order to make classes more useful, a concrete record (or another class)
can request a class as a parent class and pass template arguments to it.
These template arguments can be used in the fields of the parent class to
initialize them in a custom manner. That is, record or class A can
request parent class S with one set of template arguments, while record or class
B can request S with a different set of arguments. Without template
arguments, many more classes would be required, one for each combination of
the template arguments.
Both classes and concrete records can include fields that are uninitialized.
The uninitialized “value” is represented by a question mark (?). Classes
often have uninitialized fields that are expected to be filled in when those
classes are inherited by concrete records. Even so, some fields of concrete
records may remain uninitialized.
TableGen provides multiclasses to collect a group of record definitions in one place. A multiclass is a sort of macro that can be “invoked” to define multiple concrete records all at once. A multiclass can inherit from other multiclasses, which means that the multiclass inherits all the definitions from its parent multiclasses.
Appendix C: Sample Record illustrates a complex record in the Intel X86 target and the simple way in which it is defined.
1.2 Source Files#
TableGen source files are plain ASCII text files. The files can contain
statements, comments, and blank lines (see Lexical Analysis). The standard file
extension for TableGen files is .td.
TableGen files can grow quite large, so there is an include mechanism that allows one file to include the content of another file (see Include Files). This allows large files to be broken up into smaller ones, and also provides a simple library mechanism where multiple source files can include the same library file.
TableGen supports a simple preprocessor that can be used to conditionalize
portions of .td files. See Preprocessing Facilities for more
information.
1.3 Lexical Analysis#
The lexical and syntax notation used here is intended to imitate Python’s notation. In particular, for lexical definitions, the productions operate at the character level and there is no implied whitespace between elements. The syntax definitions operate at the token level, so there is implied whitespace between tokens.
TableGen supports BCPL-style comments (// ...) and nestable C-style
comments (/* ... */).
TableGen also provides simple Preprocessing Facilities.
Formfeed characters may be used freely in files to produce page breaks when the file is printed for review.
The following are the basic punctuation tokens:
- + [ ] { } ( ) < > : ; . ... = ? #
1.3.1 Literals#
Numeric literals take one of the following forms:
TokInteger ::=DecimalInteger|HexInteger|BinIntegerDecimalInteger ::= ["+" | "-"] ("0"..."9")+ HexInteger ::= "0x" ("0"..."9" | "a"..."f" | "A"..."F")+ BinInteger ::= "0b" ("0" | "1")+
Observe that the DecimalInteger token includes the optional +
or - sign, unlike most languages where the sign would be treated as a
unary operator.
TableGen has two kinds of string literals:
TokString ::= '"' (non-'"' characters and escapes) '"'
TokCode ::= "[{" (text not containing "}]") "}]"
A TokCode is nothing more than a multi-line string literal
delimited by [{ and }]. It can break across lines and the
line breaks are retained in the string.
The current implementation accepts the following escape sequences:
\\ \' \" \t \n
1.3.2 Identifiers#
TableGen has name- and identifier-like tokens, which are case-sensitive.
ualpha ::= "a"..."z" | "A"..."Z" | "_"
TokIdentifier ::= ("0"..."9")* ualpha (ualpha | "0"..."9")*
TokVarName ::= "$" ualpha (ualpha | "0"..."9")*
Note that, unlike most languages, TableGen allows TokIdentifier to
begin with an integer. In case of ambiguity, a token is interpreted as a
numeric literal rather than an identifier.
TableGen has the following reserved keywords, which cannot be used as identifiers:
assert bit bits class code
dag def dump else false
foreach defm defset defvar field
if in include int let
list multiclass string then true
Warning
The field reserved word is deprecated, except when used with the
CodeEmitterGen backend where it’s used to distinguish normal record
fields from encoding fields.
1.3.3 Bang operators#
TableGen provides “bang operators” that have a wide variety of uses:
BangOperator ::= one of
!add !and !cast !con !dag
!div !empty !eq !exists !filter
!find !foldl !foreach !ge !getdagarg
!getdagname !getdagop !getdagopname !gt !head
!if !initialized !instances !interleave !isa
!le !listconcat !listflatten !listremove !listsplat
!logtwo !lt !match !mul !ne
!not !or !range !repr !setdagarg
!setdagname !setdagop !setdagopname !shl !size
!sra !srl !strconcat !sub !subst
!substr !tail !tolower !toupper !xor
The !cond operator has a slightly different
syntax compared to other bang operators, so it is defined separately:
CondOperator ::= !cond
See Appendix A: Bang Operators for a description of each bang operator.
1.3.4 Include files#
TableGen has an include mechanism. The content of the included file
lexically replaces the include directive and is then parsed as if it were
originally in the main file.
IncludeDirective ::= "include" TokString
Portions of the main file and included files can be conditionalized using preprocessor directives.
PreprocessorDirective ::= "#define" | "#ifdef" | "#ifndef"
1.4 Types#
The TableGen language is statically typed, using a simple but complete type system. Types are used to check for errors, to perform implicit conversions, and to help interface designers constrain the allowed input. Every value is required to have an associated type.
TableGen supports a mixture of low-level types (e.g., bit) and
high-level types (e.g., dag). This flexibility allows you to describe a
wide range of records conveniently and compactly.
Type ::= "bit" | "int" | "string" | "dag" | "code"
| "bits" "<" TokInteger ">"
| "list" "<" Type ">"
| ClassID
ClassID ::= TokIdentifier
bitA
bitis a boolean value that can be 0 or 1.intThe
inttype represents a simple 64-bit integer value, such as 5 or -42.stringThe
stringtype represents an ordered sequence of characters of arbitrary length.codeThe keyword
codeis an alias forstringwhich may be used to indicate string values that are code.bits<n>The
bitstype is a fixed-sized integer of arbitrary length n that is treated as separate bits. These bits can be accessed individually. A field of this type is useful for representing an instruction operation code, register number, or address mode/register/displacement. The bits of the field can be set individually or as subfields. For example, in an instruction address, the addressing mode, base register number, and displacement can be set separately.list<type>This type represents a list whose elements are of the type specified in angle brackets. The element type is arbitrary; it can even be another list type. List elements are indexed from 0.
dagThis type represents a nestable directed acyclic graph (DAG) of nodes. Each node has an operator and zero or more arguments (or operands). An argument can be another
dagobject, allowing an arbitrary tree of nodes and edges. As an example, DAGs are used to represent code patterns for use by the code generator instruction selection algorithms. See Directed acyclic graphs (DAGs) for more details;ClassIDSpecifying a class name in a type context indicates that the type of the defined value must be a subclass of the specified class. This is useful in conjunction with the
listtype; for example, to constrain the elements of the list to a common base class (e.g., alist<Register>can only contain definitions derived from theRegisterclass). TheClassIDmust name a class that has been previously declared or defined.
1.5 Values and Expressions#
There are many contexts in TableGen statements where a value is required. A common example is in the definition of a record, where each field is specified by a name and an optional value. TableGen allows for a reasonable number of different forms when building up value expressions. These forms allow the TableGen file to be written in a syntax that is natural for the application.
Note that all of the values have rules for converting them from one type to
another. For example, these rules allow you to assign a value like 7
to an entity of type bits<4>.
Value ::=SimpleValueValueSuffix* |Value"#" [Value] ValueSuffix ::=RangeList| "["SliceElements"]" | "."TokIdentifierRangeList ::= "{"RangePiece(","RangePiece)* "}" RangePiece ::=TokInteger|TokInteger"..."TokInteger|TokInteger"-"TokInteger|TokIntegerTokIntegerSliceElements ::= (SliceElement",")*SliceElement","? SliceElement ::=Value|Value"..."Value|Value"-"Value|ValueTokInteger
Warning
The peculiar last form of RangePiece and SliceElement is
due to the fact that the “-” is included in the TokInteger,
hence 1-5 gets lexed as two consecutive tokens, with values 1 and
-5, instead of “1”, “-”, and “5”.
The use of hyphen as the range punctuation is deprecated.
1.5.1 Simple values#
The SimpleValue has a number of forms.
SimpleValue ::=SimpleValue1|SimpleValue2|SimpleValue3|SimpleValue4|SimpleValue5|SimpleValue6|SimpleValue7|SimpleValue8|SimpleValue9SimpleValue1 ::=TokInteger|TokString+ |TokCode
A value can be an integer literal, a string literal, or a code literal. Multiple adjacent string literals are concatenated as in C/C++; the simple value is the concatenation of the strings. Code literals become strings and are then indistinguishable from them.
SimpleValue2 ::= "true" | "false"
The true and false literals are essentially syntactic sugar for the
integer values 1 and 0. They improve the readability of TableGen files when
boolean values are used in field initializations, bit sequences, if
statements, etc. When parsed, these literals are converted to integers.
Note
Although true and false are literal names for 1 and 0, we
recommend as a stylistic rule that you use them for boolean
values only.
SimpleValue3 ::= "?"
A question mark represents an uninitialized value.
SimpleValue4 ::= "{" [ValueList] "}"
ValueList ::= ValueListNE
ValueListNE ::= Value ("," Value)*
This value represents a sequence of bits, which can be used to initialize a
bits<n> field (note the braces). When doing so, the values
must represent a total of n bits.
SimpleValue5 ::= "["ValueList"]" ["<"Type">"]
This value is a list initializer (note the brackets). The values in brackets
are the elements of the list. The optional Type can be used to
indicate a specific element type; otherwise the element type is inferred
from the given values. TableGen can usually infer the type, although
sometimes not when the value is the empty list ([]).
SimpleValue6 ::= "(" DagArg [DagArgList] ")"
DagArgList ::= DagArg ("," DagArg)*
DagArg ::= Value [":" TokVarName] | TokVarName
This represents a DAG initializer (note the parentheses). The first
DagArg is called the “operator” of the DAG and must be a record.
See Directed acyclic graphs (DAGs) for more details.
SimpleValue7 ::= TokIdentifier
The resulting value is the value of the entity named by the identifier. The possible identifiers are described here, but the descriptions will make more sense after reading the remainder of this guide.
A template argument of a
class, such as the use ofBarin:class Foo <int Bar> { int Baz = Bar; }
The implicit template argument
NAMEin aclassormulticlassdefinition (see NAME).A field local to a
class, such as the use ofBarin:class Foo { int Bar = 5; int Baz = Bar; }
The name of a record definition, such as the use of
Barin the definition ofFoo:def Bar : SomeClass { int X = 5; } def Foo { SomeClass Baz = Bar; }
A field local to a record definition, such as the use of
Barin:def Foo { int Bar = 5; int Baz = Bar; }
Fields inherited from the record’s parent classes can be accessed the same way.
A template argument of a
multiclass, such as the use ofBarin:multiclass Foo <int Bar> { def : SomeClass<Bar>; }
A variable defined with the
defvarordefsetstatements.The iteration variable of a
foreach, such as the use ofiin:foreach i = 0...5 in def Foo#i;
SimpleValue8 ::=ClassID"<"ArgValueList">"
This form creates a new anonymous record definition (as would be created by an
unnamed def inheriting from the given class with the given template
arguments; see def) and the value is that record. A field of the record can be
obtained using a suffix; see Suffixed Values.
Invoking a class in this manner can provide a simple subroutine facility. See Using Classes as Subroutines for more information.
SimpleValue9 ::=BangOperator["<"Type">"] "("ValueListNE")" |CondOperator"("CondClause(","CondClause)* ")" CondClause ::=Value":"Value
The bang operators provide functions that are not available with the other
simple values. Except in the case of !cond, a bang operator takes a list
of arguments enclosed in parentheses and performs some function on those
arguments, producing a value for that bang operator. The !cond operator
takes a list of pairs of arguments separated by colons. See Appendix A:
Bang Operators for a description of each bang operator.
The Type is only accepted for certain bang operators, and must not be
code.
1.5.2 Suffixed values#
The SimpleValue values described above can be specified with
certain suffixes. The purpose of a suffix is to obtain a subvalue of the
primary value. Here are the possible suffixes for some primary value.
- value
{17} The final value is bit 17 of the integer value (note the braces).
- value
{8...15} The final value is bits 8–15 of the integer value. The order of the bits can be reversed by specifying
{15...8}.- value
[i] The final value is element i of the list value (note the brackets). In other words, the brackets act as a subscripting operator on the list. This is the case only when a single element is specified.
- value
[i,] The final value is a list that contains a single element i of the list. In short, a list slice with a single element.
- value
[4...7,17,2...3,4] The final value is a new list that is a slice of the list value. The new list contains elements 4, 5, 6, 7, 17, 2, 3, and 4. Elements may be included multiple times and in any order. This is the result only when more than one element is specified.
- value
[i,m...n,j,ls] Each element may be an expression (variables, bang operators). The type of m and n should be int. The type of i, j, and ls should be either int or list<int>.
- value
- value
.field The final value is the value of the specified field in the specified record value.
1.5.3 The paste operator#
The paste operator (#) is the only infix operator available in TableGen
expressions. It allows you to concatenate strings or lists, but has a few
unusual features.
The paste operator can be used when specifying the record name in a
Def or Defm statement, in which case it must construct a
string. If an operand is an undefined name (TokIdentifier) or the
name of a global Defvar or Defset, it is treated as a
verbatim string of characters. The value of a global name is not used.
The paste operator can be used in all other value expressions, in which case it can construct a string or a list. Rather oddly, but consistent with the previous case, if the right-hand-side operand is an undefined name or a global name, it is treated as a verbatim string of characters. The left-hand-side operand is treated normally.
Values can have a trailing paste operator, in which case the left-hand-side operand is concatenated to an empty string.
Appendix B: Paste Operator Examples presents examples of the behavior of the paste operator.
1.6 Statements#
The following statements may appear at the top level of TableGen source files.
TableGenFile ::= (Statement|IncludeDirective|PreprocessorDirective)* Statement ::=Assert|Class|Def|Defm|Defset|Deftype|Defvar|Dump|Foreach|If|Let|MultiClass
The following sections describe each of these top-level statements.
1.6.1 class — define an abstract record class#
A class statement defines an abstract record class from which other
classes and records can inherit.
Class ::= "class"ClassID[TemplateArgList]RecordBodyTemplateArgList ::= "<"TemplateArgDecl(","TemplateArgDecl)* ">" TemplateArgDecl ::=TypeTokIdentifier["="Value]
A class can be parameterized by a list of “template arguments,” whose values can be used in the class’s record body. These template arguments are specified each time the class is inherited by another class or record.
If a template argument is not assigned a default value with =, it is
uninitialized (has the “value” ?) and must be specified in the template
argument list when the class is inherited (required argument). If an
argument is assigned a default value, then it need not be specified in the
argument list (optional argument). In the declaration, all required template
arguments must precede any optional arguments. The template argument default
values are evaluated from left to right.
The RecordBody is defined below. It can include a list of
parent classes from which the current class inherits, along with field
definitions and other statements. When a class C inherits from another
class D, the fields of D are effectively merged into the fields of
C.
A given class can only be defined once. A class statement is
considered to define the class if any of the following are true (the
RecordBody elements are described below).
The
TemplateArgListis present, orThe
ParentClassListin theRecordBodyis present, orThe
Bodyin theRecordBodyis present and not empty.
You can declare an empty class by specifying an empty TemplateArgList
and an empty RecordBody. This can serve as a restricted form of
forward declaration. Note that records derived from a forward-declared
class will inherit no fields from it, because those records are built when
their declarations are parsed, and thus before the class is finally defined.
Every class has an implicit template argument named NAME (uppercase),
which is bound to the name of the Def or Defm inheriting
from the class. If the class is inherited by an anonymous record, the name
is unspecified but globally unique.
See Examples: classes and records for examples.
1.6.1.1 Record Bodies#
Record bodies appear in both class and record definitions. A record body can include a parent class list, which specifies the classes from which the current class or record inherits fields. Such classes are called the parent classes of the class or record. The record body also includes the main body of the definition, which contains the specification of the fields of the class or record.
RecordBody ::=ParentClassListBodyParentClassList ::= [":"ParentClassListNE] ParentClassListNE ::=ClassRef(","ClassRef)* ClassRef ::= (ClassID|MultiClassID) ["<" [ArgValueList] ">"] ArgValueList ::=PostionalArgValueList[","]NamedArgValueListPostionalArgValueList ::= [Value{","Value}*] NamedArgValueList ::= [NameValue"="Value{","NameValue"="Value}*]
A ParentClassList containing a MultiClassID is valid only
in the class list of a defm statement. In that case, the ID must be the
name of a multiclass.
The argument values can be specified in two forms:
Positional argument (
value). The value is assigned to the argument in the corresponding position. ForFoo<a0, a1>,a0will be assigned to the first argument anda1will be assigned to the second argument.Named argument (
name=value). The value is assigned to the argument with the specified name. ForFoo<a=a0, b=a1>,a0will be assigned to the argument with nameaanda1will be assigned to the argument with nameb.
Required arguments can also be specified as a named argument.
Note that the argument can only be specified once regardless of the way (named or positional) to specify and positional arguments should precede named arguments.
Body ::= ";" | "{" BodyItem* "}"
BodyItem ::= Type TokIdentifier ["=" Value] ";"
| "let" [LetMode] TokIdentifier [RangeList] "=" Value ";"
| "defvar" TokIdentifier "=" Value ";"
| Assert
LetMode ::= "append" | "prepend"
Note that append and prepend are context-sensitive keywords: they are
only recognized as modifiers immediately after let. In all other positions,
they remain valid identifiers (e.g., usable as field names).
A field definition in the body specifies a field to be included in the class or record. If no initial value is specified, then the field’s value is uninitialized. The type must be specified; TableGen will not infer it from the value.
The let form is used to reset a field to a new value. This can be done
for fields defined directly in the body or fields inherited from parent
classes. A RangeList can be specified to reset certain bits in a
bit<n> field.
The let append and let prepend forms concatenate a value with the
field’s current value instead of replacing it. For append, the new value
is added after the current value; for prepend, it is added before. The
supported types and concatenation operators are:
list<T>: uses!listconcatstring/code: uses!strconcatdag: uses!con
If the field is currently unset (?), let append and let prepend
simply set the value directly. This is useful for accumulating values across
a class hierarchy:
class Base {
list<int> items = [2, 3];
}
class Middle : Base {
let append items = [4]; // items = [2, 3, 4]
}
def Concrete : Middle {
let prepend items = [1]; // items = [1, 2, 3, 4]
}
A plain let (without append/prepend) always replaces the current
value, which can be used to opt out of accumulated values.
The defvar form defines a variable whose value can be used in other
value expressions within the body. The variable is not a field: it does not
become a field of the class or record being defined. Variables are provided
to hold temporary values while processing the body. See Defvar in a Record
Body for more details.
When class C2 inherits from class C1, it acquires all the field
definitions of C1. As those definitions are merged into class C2, any
template arguments passed to C1 by C2 are substituted into the
definitions. In other words, the abstract record fields defined by C1 are
expanded with the template arguments before being merged into C2.
1.6.2 def — define a concrete record#
A def statement defines a new concrete record.
Def ::= "def" [NameValue]RecordBodyNameValue ::=Value(parsed in a special mode)
The name value is optional. If specified, it is parsed in a special mode
where undefined (unrecognized) identifiers are interpreted as literal
strings. In particular, global identifiers are considered unrecognized.
These include global variables defined by defvar and defset. A
record name can be the null string.
If no name value is given, the record is anonymous. The final name of an anonymous record is unspecified but globally unique.
Special handling occurs if a def appears inside a multiclass
statement. See the multiclass section below for details.
A record can inherit from one or more classes by specifying the
ParentClassList clause at the beginning of its record body. All of
the fields in the parent classes are added to the record. If two or more
parent classes provide the same field, the record ends up with the field value
of the last parent class.
As a special case, the name of a record can be passed as a template argument to that record’s parent classes. For example:
class A <dag d> {
dag the_dag = d;
}
def rec1 : A<(ops rec1)>;
The DAG (ops rec1) is passed as a template argument to class A. Notice
that the DAG includes rec1, the record being defined.
The steps taken to create a new record are somewhat complex. See How records are built.
See Examples: classes and records for examples.
1.6.3 Examples: classes and records#
Here is a simple TableGen file with one class and two record definitions.
class C {
bit V = true;
}
def X : C;
def Y : C {
let V = false;
string Greeting = "Hello!";
}
First, the abstract class C is defined. It has one field named V
that is a bit initialized to true.
Next, two records are defined, derived from class C; that is, with C
as their parent class. Thus they both inherit the V field. Record Y
also defines another string field, Greeting, which is initialized to
"Hello!". In addition, Y overrides the inherited V field,
setting it to false.
A class is useful for isolating the common features of multiple records in one place. A class can initialize common fields to default values, but records inheriting from that class can override the defaults.
TableGen supports the definition of parameterized classes as well as nonparameterized ones. Parameterized classes specify a list of variable declarations, which may optionally have defaults, that are bound when the class is specified as a parent class of another class or record.
class FPFormat <bits<3> val> {
bits<3> Value = val;
}
def NotFP : FPFormat<0>;
def ZeroArgFP : FPFormat<1>;
def OneArgFP : FPFormat<2>;
def OneArgFPRW : FPFormat<3>;
def TwoArgFP : FPFormat<4>;
def CompareFP : FPFormat<5>;
def CondMovFP : FPFormat<6>;
def SpecialFP : FPFormat<7>;
The purpose of the FPFormat class is to act as a sort of enumerated
type. It provides a single field, Value, which holds a 3-bit number. Its
template argument, val, is used to set the Value field. Each of the
eight records is defined with FPFormat as its parent class. The
enumeration value is passed in angle brackets as the template argument. Each
record will inherit the Value field with the appropriate enumeration
value.
Here is a more complex example of classes with template arguments. First, we
define a class similar to the FPFormat class above. It takes a template
argument and uses it to initialize a field named Value. Then we define
four records that inherit the Value field with its four different
integer values.
class ModRefVal <bits<2> val> {
bits<2> Value = val;
}
def None : ModRefVal<0>;
def Mod : ModRefVal<1>;
def Ref : ModRefVal<2>;
def ModRef : ModRefVal<3>;
This is somewhat contrived, but let’s say we would like to examine the two
bits of the Value field independently. We can define a class that
accepts a ModRefVal record as a template argument and splits up its
value into two fields, one bit each. Then we can define records that inherit from
ModRefBits and so acquire two fields from it, one for each bit in the
ModRefVal record passed as the template argument.
class ModRefBits <ModRefVal mrv> {
// Break the value up into its bits, which can provide a nice
// interface to the ModRefVal values.
bit isMod = mrv.Value{0};
bit isRef = mrv.Value{1};
}
// Example uses.
def foo : ModRefBits<Mod>;
def bar : ModRefBits<Ref>;
def snork : ModRefBits<ModRef>;
This illustrates how one class can be defined to reorganize the fields in another class, thus hiding the internal representation of that other class.
Running llvm-tblgen on the example prints the following definitions:
def bar { // Value
bit isMod = 0;
bit isRef = 1;
}
def foo { // Value
bit isMod = 1;
bit isRef = 0;
}
def snork { // Value
bit isMod = 1;
bit isRef = 1;
}
1.6.4 let — override fields in classes or records#
A let statement collects a set of field values (sometimes called
bindings) and applies them to all the classes and records defined by
statements within the scope of the let.
Let ::= "let"LetList"in" "{"Statement* "}" | "let"LetList"in"StatementLetList ::=LetItem(","LetItem)* LetItem ::= [LetMode]TokIdentifier[RangeList] "="Value
The let statement establishes a scope, which is a sequence of statements
in braces or a single statement with no braces. The bindings in the
LetList apply to the statements in that scope.
The field names in the LetList must name fields in classes inherited by
the classes and records defined in the statements. The field values are
applied to the classes and records after the records inherit all the fields from
their parent classes. So the let acts to override inherited field
values. A let cannot override the value of a template argument.
Top-level let statements are often useful when a few fields need to be
overridden in several records. Here are two examples. Note that let
statements can be nested.
let isTerminator = true, isReturn = true, isBarrier = true, hasCtrlDep = true in
def RET : I<0xC3, RawFrm, (outs), (ins), "ret", [(X86retflag 0)]>;
let isCall = true in
// All calls clobber the non-callee saved registers...
let Defs = [EAX, ECX, EDX, FP0, FP1, FP2, FP3, FP4, FP5, FP6, ST0,
MM0, MM1, MM2, MM3, MM4, MM5, MM6, MM7, XMM0, XMM1, XMM2,
XMM3, XMM4, XMM5, XMM6, XMM7, EFLAGS] in {
def CALLpcrel32 : Ii32<0xE8, RawFrm, (outs), (ins i32imm:$dst, variable_ops),
"call\t${dst:call}", []>;
def CALL32r : I<0xFF, MRM2r, (outs), (ins GR32:$dst, variable_ops),
"call\t{*}$dst", [(X86call GR32:$dst)]>;
def CALL32m : I<0xFF, MRM2m, (outs), (ins i32mem:$dst, variable_ops),
"call\t{*}$dst", []>;
}
Note that a top-level let will not override fields defined in the classes or records
themselves.
Top-level let also supports append and prepend modes, which
concatenate the value with the field’s current value instead of replacing it.
See the BodyItem production for the supported types and semantics.
let append traits = [NewTrait] in {
def MyRecord : Base;
}
1.6.5 multiclass — define multiple records#
While classes with template arguments are a good way to factor out commonality
between multiple records, multiclasses allow a convenient method for
defining many records at once. For example, consider a 3-address
instruction architecture whose instructions come in two formats: reg = reg
op reg and reg = reg op imm (e.g., SPARC). We would like to specify in
one place that these two common formats exist, then in a separate place
specify what all the operations are. The multiclass and defm
statements accomplish this goal. You can think of a multiclass as a macro or
template that expands into multiple records.
MultiClass ::= "multiclass"TokIdentifier[TemplateArgList]ParentClassList"{"MultiClassStatement+ "}" MultiClassID ::=TokIdentifierMultiClassStatement ::=Assert|Def|Defm|Defvar|Foreach|If|Let
As with regular classes, the multiclass has a name and can accept template
arguments. A multiclass can inherit from other multiclasses, which causes
the other multiclasses to be expanded and contribute to the record
definitions in the inheriting multiclass. The body of the multiclass
contains a series of statements that define records, using Def and
Defm. In addition, Defvar, Foreach, and
Let statements can be used to factor out even more common elements.
The If and Assert statements can also be used.
Also as with regular classes, the multiclass has the implicit template
argument NAME (see NAME). When a named (non-anonymous) record is
defined in a multiclass and the record’s name does not include a use of the
template argument NAME, such a use is automatically prepended
to the name. That is, the following are equivalent inside a multiclass:
def Foo ...
def NAME # Foo ...
The records defined in a multiclass are created when the multiclass is
“instantiated” or “invoked” by a defm statement outside the multiclass
definition. Each def statement in the multiclass produces a record. As
with top-level def statements, these definitions can inherit from
multiple parent classes.
See Examples: multiclasses and defms for examples.
1.6.6 defm — invoke multiclasses to define multiple records#
Once multiclasses have been defined, you use the defm statement to
“invoke” them and process the multiple record definitions in those
multiclasses. Those record definitions are specified by def
statements in the multiclasses, and indirectly by defm statements.
Defm ::= "defm" [NameValue]ParentClassList";"
The optional NameValue is formed in the same way as the name of a
def. The ParentClassList is a colon followed by a list of at
least one multiclass and any number of regular classes. The multiclasses
must precede the regular classes. Note that the defm does not have a
body.
This statement instantiates all the records defined in all the specified
multiclasses, either directly by def statements or indirectly by
defm statements. These records also receive the fields defined in any
regular classes included in the parent class list. This is useful for adding
a common set of fields to all the records created by the defm.
The name is parsed in the same special mode used by def. If the name is
not included, an unspecified but globally unique name is provided. That is,
the following examples end up with different names:
defm : SomeMultiClass<...>; // A globally unique name.
defm "" : SomeMultiClass<...>; // An empty name.
The defm statement can be used in a multiclass body. When this occurs,
the second variant is equivalent to:
defm NAME : SomeMultiClass<...>;
More generally, when defm occurs in a multiclass and its name does not
include a use of the implicit template argument