Preprocessor reference#
The preprocessor allows simple compile-time specialization of the tensor language. Identifiers starting with a ‘$’ are compile-time variables. A variable can be either a constant, a type, or an attribute, and can be used in the language wherever one of the former is expected. Definitions of variables can either appear in global scope or in a region. If a variable is given in a region, its scope is limited to the region and its subregions.
Example: Assume we want a fixed-size memref and we want to specialize the size of the memref at compile-time as well as the element type, then we could write
$element_ty = f32
$chunk_size = 64
%x = subview %X[0:$chunk_size] : memref<$element_ty x $chunk_size>
; ... or ...
$chunk_ty = memref<$element_ty x $chunk_size>
%x = subview %X[0:$chunk_size] : $chunk_ty
Moreover, a simple calculator is available. The operands must be integers and the expression is given in reverse Polish notation. For example to calculate \(c = \text{ceil}(a/b) = 1 + \lfloor(a-1) / b\rfloor\) at compile-time we write
$c = !calc($a 1 - b / 1 +)
Note
The preprocessor is only implemented in the parser and is considered a syntax extension to the core language. Compile time definitions are resolved at parse time and are not represented in the AST. Therefore, compile-time variables are not present in the Builder C-API or Builder C++-API, and they are lost when dumping the IR, too.
Identifier#
The following ABNF grammer extends the Tensor language reference.
Compile-time variables are prefixed with the ‘$’.
def-identifier = "$" identifier
Compile-time variables may be used in place of any boolean constant, integer constant, floating constant, type, or attribute.
Definition#
A compile-time variable must be assigned only once within a scope and the scope’s sub-scopes. Assignments are written as following:
def-assign = def-identifier "=" def-rhs
The def-assign non-terminal may appear in global scope as well as region scope, following or preceding a function or instruction. Assignment must precede the use of a compile-time variable.
Definition types#
Compile-time variables can be constant:
def-rhs = boolean-constant / floating-constant / integer-constant
The array, or dictionary, or string attributes can be defined, but boolean and integer attribute cannot be defined to not confuse those with constants.
def-rhs =/ array-attribute
def-rhs =/ dictionary-attribute
def-rhs =/ string-attribute
Lastly, definitions can be types or alias another definition.
def-rhs =/ data-type
def-rhs =/ def-identifier
Calculator#
The right-hand side of a definition can stem from a calculation given reverse Polish notation
def-rhs =/ "!calc" "(" rpn-expr ")"
rpn-expr = int-or-def /
rpn-expr rpn-expr "^" /
rpn-expr rpn-expr "-" /
rpn-expr rpn-expr "+" /
rpn-expr rpn-expr "*" /
rpn-expr rpn-expr "/" /
rpn-expr rpn-expr "%" /
rpn-expr rpn-expr "min" /
rpn-expr rpn-expr "max"
int-or-def = integer-constant / def-identifier
The operators are summarized in the following table:
Operator |
Description |
|---|---|
|
Power |
|
Subtraction |
|
Addition |
|
Multiplication |
|
Integer division |
|
Remainder |
|
Minimum |
|
Maximum |