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 | BinInteger
DecimalInteger ::=  ["+" | "-"] ("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
bit

A bit is a boolean value that can be 0 or 1.

int

The int type represents a simple 64-bit integer value, such as 5 or -42.

string

The string type represents an ordered sequence of characters of arbitrary length.

code

The keyword code is an alias for string which may be used to indicate string values that are code.

bits<n>

The bits type 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.

dag

This 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 dag object, 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;

ClassID

Specifying 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 list type; for example, to constrain the elements of the list to a common base class (e.g., a list<Register> can only contain definitions derived from the Register class). The ClassID must 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         ::=  SimpleValue ValueSuffix*
                  | Value "#" [Value]
ValueSuffix   ::=  RangeList
                  | "[" SliceElements "]"
                  | "." TokIdentifier
RangeList     ::=  "{" RangePiece ("," RangePiece)* "}"
RangePiece    ::=  TokInteger
                  | TokInteger "..." TokInteger
                  | TokInteger "-" TokInteger
                  | TokInteger TokInteger
SliceElements ::=  (SliceElement ",")* SliceElement ","?
SliceElement  ::=  Value
                  | Value "..." Value
                  | Value "-" Value
                  | Value TokInteger

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
                 | SimpleValue9
SimpleValue1 ::=  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 of Bar in:

    class Foo <int Bar> {
      int Baz = Bar;
    }
    
  • The implicit template argument NAME in a class or multiclass definition (see NAME).

  • A field local to a class, such as the use of Bar in:

    class Foo {
      int Bar = 5;
      int Baz = Bar;
    }
    
  • The name of a record definition, such as the use of Bar in the definition of Foo:

    def Bar : SomeClass {
      int X = 5;
    }
    
    def Foo {
      SomeClass Baz = Bar;
    }
    
  • A field local to a record definition, such as the use of Bar in:

    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 of Bar in:

    multiclass Foo <int Bar> {
      def : SomeClass<Bar>;
    }
    
  • A variable defined with the defvar or defset statements.

  • The iteration variable of a foreach, such as the use of i in:

    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.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] RecordBody
TemplateArgList ::=  "<" TemplateArgDecl ("," TemplateArgDecl)* ">"
TemplateArgDecl ::=  Type TokIdentifier ["=" 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).

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            ::=  ParentClassList Body
ParentClassList       ::=  [":" ParentClassListNE]
ParentClassListNE     ::=  ClassRef ("," ClassRef)*
ClassRef              ::=  (ClassID | MultiClassID) ["<" [ArgValueList] ">"]
ArgValueList          ::=  PostionalArgValueList [","] NamedArgValueList
PostionalArgValueList ::=  [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. For Foo<a0, a1>, a0 will be assigned to the first argument and a1 will be assigned to the second argument.

  • Named argument (name=value). The value is assigned to the argument with the specified name. For Foo<a=a0, b=a1>, a0 will be assigned to the argument with name a and a1 will be assigned to the argument with name b.

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 !listconcat

  • string / code: uses !strconcat

  • dag: 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] RecordBody
NameValue ::=  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" Statement
LetList ::=  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        ::=  TokIdentifier
MultiClassStatement ::=  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