Arithmetic Types
The arithmetic layer is the set of scalar (Numeric) and SIMD (Vector) values
a kernel computes with: the types themselves, their public operations.
The type tower
Every arithmetic value is either a scalar Numeric or a Vector of a Numeric
element type. A type class is also its constructor: Float32(x) builds (or
casts to) a Float32.
Numeric scalars
Numeric is the base of every scalar that wraps an ir.Value.
Integers —
Int4Int8Int16Int32Int64Int128,Uint8Uint16Uint32Uint64Uint128. Signedness and width are fixed per type.Floats —
Float16BFloat16Float32Float64.Narrow floats —
Float8E5M2Float8E4M3FNFloat8E4M3FNUZFloat8E4M3B11FNUZFloat8E4M3,Float6E2M3FNFloat6E3M2FN,Float8E8M0FNU,Float4E2M1FN. These are storage/transport types, not meant for direct arithmetic, and native support is architecture-restricted.Boolean— thei1type; the result of comparisons and predicates.
Public methods
Common to Numeric and Vector, elementwise for Vector:
Method |
Meaning |
Example |
|---|---|---|
|
construct or cast — the type class is its own constructor. A |
|
Arithmetic — |
result type follows Type interoperability; elementwise with scalar broadcast for |
|
Bitwise/shift — |
integer-only |
|
Comparison — |
result is |
|
|
reinterpret the bits: |
|
|
the scalar type ( |
|
|
the underlying |
|
|
ternary select; a non- |
|
|
value-preserving conversion to another type |
|
Numeric-only methods:
Method |
Meaning |
Example |
|---|---|---|
|
whether the value is compile-time (Python) rather than run-time ( |
|
|
the type’s bit width, and |
|
|
build a |
|
|
the |
|
Vector
Vector is a fixed-length sequence of N elements of a single Numeric
element type. It has value semantics and inherits the scalar operators, applied
elementwise; a scalar operand is auto-broadcast across the lanes.
Type aliases —
Float32x4,BFloat16x8,Int32x4, … name adtype×Nvector type directly (<dtype>x<N>).
Compile-time and run-time values
A Numeric is polymorphic in the value it holds — the type is the same either
way, and is_static() reports which:
a compile-time value — a Python
int/float/bool, known while tracing; ora run-time value — an
ir.Valuefrom an MLIR op, known only at execution.
A Vector is always run-time — it is backed by an MLIR vector value, so it has
no compile-time (folded) form.
Arithmetic preserves the compile-time property
If every operand is compile-time, the result is compile-time — the host folds it
and emits no MLIR (Int32(3) + Int32(4) ⇒ Int32 holding 7). As soon as one
operand is run-time, the result is run-time and an MLIR op is emitted. This
holds uniformly across arithmetic, comparison, bitwise, and shift operators.
Python literals
A bare literal stays plain Python while it only meets other Python values
(2 + 3 is ordinary Python). On contact with a Numeric it takes a DSL type
by value (see Operand normalization) as a compile-time value; on contact
with a Vector it broadcasts to the lanes and the result is run-time. After
this the interoperability rules apply. An explicit Int32(5) is likewise
compile-time until combined with a run-time value.
Using a compile-time value as Python
Because it holds a real Python value, a compile-time Numeric works wherever
Python expects one — int(x), bool(x), indexing, a Python if — so a DSL
constant can still drive host-side control flow. A run-time Numeric raises if
forced to a Python value.
Type interoperability
How a binary operation between two DSL numeric values determines the type its
operands are converted to (the common type) and the type it produces (the
result type). The rules are the same whether operands are scalar (Numeric),
Vector, or a mix of the two; Vector ⊗ Vector additionally broadcasts shapes,
which is independent of type and covered in the layout guides.
Operand normalization
Before the rules below apply, operands are normalized:
Python literals take a DSL type by value: an
intbecomesInt32, orInt64when it falls outside theInt32range; afloatbecomesFloat32; aboolbecomesBoolean.Booleandepends on the operation:In arithmetic (
+ - * / // %) it is converted toInt32and then follows theInt32rules.In comparisons it is compared directly and the result is
Boolean.In bitwise (
& | ^) and shift (<< >>) it staysBooleanand the result isBoolean.
Common type
For two numeric operands (after normalization above; Boolean in arithmetic is
already Int32 here), the common type is:
lhs \ rhs |
Int8 |
Int16 |
Int32 |
Int64 |
Uint32 |
Float16 |
BFloat16 |
Float32 |
Float64 |
|---|---|---|---|---|---|---|---|---|---|
Int8 |
Int8 |
Int16 |
Int32 |
Int64 |
Uint32 |
Float16 |
BFloat16 |
Float32 |
Float64 |
Int16 |
Int16 |
Int16 |
Int32 |
Int64 |
Uint32 |
Float16 |
BFloat16 |
Float32 |
Float64 |
Int32 |
Int32 |
Int32 |
Int32 |
Int64 |
Uint32 |
Float32 |
Float32 |
Float32 |
Float64 |
Int64 |
Int64 |
Int64 |
Int64 |
Int64 |
Int64 |
Float64 |
Float64 |
Float64 |
Float64 |
Uint32 |
Uint32 |
Uint32 |
Uint32 |
Int64 |
Uint32 |
Float32 |
Float32 |
Float32 |
Float64 |
Float16 |
Float16 |
Float16 |
Float32 |
Float64 |
Float32 |
Float16 |
Float32 |
Float32 |
Float64 |
BFloat16 |
BFloat16 |
BFloat16 |
Float32 |
Float64 |
Float32 |
Float32 |
BFloat16 |
Float32 |
Float64 |
Float32 |
Float32 |
Float32 |
Float32 |
Float64 |
Float32 |
Float32 |
Float32 |
Float32 |
Float64 |
Float64 |
Float64 |
Float64 |
Float64 |
Float64 |
Float64 |
Float64 |
Float64 |
Float64 |
Float64 |
The table follows these rules (other integer widths obey the same integer rules):
Same type → itself.
Two integers, same signedness → the wider one (
Int8 + Int8staysInt8; there is no promotion to a machineint).Two integers, mixed signedness → the unsigned type when it is at least as wide as the signed one, otherwise the signed type. So
Int32 + Uint32isUint32, andInt64 + Uint32isInt64.One float, one integer → the float, widened to cover the integer’s width:
Float16 + Int32isFloat32,Float32 + Int64isFloat64, andFloat16 + Int8isFloat16.Two floats → the wider one; at equal width the higher-precision one (
Float64 > Float32 > Float16/BFloat16).Float16andBFloat16are equal width and neither converts to the other without loss, so they combine toFloat32.
Result type
Given the common type C from the table above:
Operation |
Result type |
|---|---|
|
|
|
|
|
|
|
|