Introduction
SME2 and its later versions add to SME. The ZA array register stays. Three new ideas run through this page.
Multi-vector groups. Many instructions take two or four Z registers as
one operand, written { z0.s, z1.s } or { z0.s - z3.s }. Most
also address ZA as an array of vectors rather than as tiles, for example
za.s[w8, 0, vgx2]:
w8is a vector select register, W8 to W11, and the next number is an offset added to it;vgx2orvgx4says the operand is two or four groups of ZA vectors, taken from separate halves or quarters of the array;- a single-vector group is one vector of ZA; a range such as
0x0:0x1or0x0:0x3marks a double-vector or quad-vector group, used by the widening instructions.
Predicate-as-counter registers. P8 to P15 can hold a predicate in
counter form, written pn8 to pn15. A counter does not hold one
bit per element. The lowest set bit of bits 3 to 0 gives the element size, the bits above
it give a count of elements, and bit 15 inverts the result. If bits 3 to 0 are all 0, no
element is active. A counter can govern several vectors at once.
The ZT0 register. ZT0 is a 512-bit table register. luti2
and luti4 read it, using packed 2-bit or 4-bit indexes from a Z register. It
is tied to ZA: turning ZA on with smstart sets ZT0 to zero, and turning it
off leaves ZT0 unknown.
Instructions that read or write ZA need ZA enabled and streaming mode. Most of the
instructions that use only Z registers need streaming mode. ldr,
str and zero on ZT0 do not need streaming mode. None of the
instructions on this page changes the NZCV flags.
Some names cover several generations of the architecture. Instructions on 8-bit floating-point values take their formats and scale from FPMR, the floating-point mode register.
The instructions
Adding and subtracting with ZA
These instructions have no predicate.
| Mnemonic | Syntax | What it does | Flags |
|---|---|---|---|
add | add za.s[w8, 0, vgx2], { z0.s, z1.s }, z0.sadd za.s[w8, 0, vgx2], { z0.s, z1.s }add { z0.h, z1.h }, { z0.h, z1.h }, z0.h | Adds integer elements. The ZA forms write the sum of two Z operands to ZA, or add a Z group into ZA. The third form adds one vector into two or four Z registers. | – |
sub | sub za.s[w8, 0, vgx2], { z0.s, z1.s }, z0.ssub za.s[w8, 0, vgx2], { z0.s, z1.s } | The same as the ZA forms of add, for subtraction. | – |
fadd, fsub | fadd za.s[w8, 0, vgx2], { z0.s, z1.s } | Adds a group of floating-point vectors to ZA, or subtracts it from ZA. | – |
bfadd, bfsub | bfadd za.h[w8, 0, vgx2], { z0.h, z1.h } | The same, for BFloat16 values. | – |
fmla, fmls | fmla za.s[w8, 0, vgx2], { z0.s, z1.s }, z0.s | Multiplies floating-point elements of Z registers, and adds the products to ZA or subtracts them, with no intermediate rounding. The second operand can be one vector, an indexed element or a group. | – |
bfmla, bfmls | bfmla za.h[w8, 0, vgx2], { z0.h, z1.h }, z0.h | The same, for BFloat16 values. | – |
Widening multiply and accumulate to ZA
Each product goes to a wider element of ZA, in a double-vector or quad-vector group.
| Mnemonic | Syntax | What it does | Flags |
|---|---|---|---|
bfmlal, bfmlsl | bfmlal za.s[w8, 0x0:0x1, vgx2], { z0.h, z1.h }, z0.h | Multiplies BFloat16 elements after widening to single precision. Adds to ZA (bfmlal) or subtracts (bfmlsl). | – |
fmlal | fmlal za.s[w8, 0x0:0x1, vgx2], { z0.h, z1.h }, z0.h | Multiplies half-precision elements and adds to single-precision ZA elements, with no intermediate rounding. There is also an 8-bit form that adds to half-precision ZA elements, scaled from FPMR. | – |
fmlsl | fmlsl za.s[w8, 0x0:0x1, vgx2], { z0.h, z1.h }, z0.h | Multiplies half-precision elements and subtracts from single-precision ZA elements. | – |
fmlall | fmlall za.s[w8, 0x0:0x3, vgx2], { z0.b, z1.b }, z0.b | Multiplies 8-bit floating-point elements and adds to single-precision ZA elements in quad-vector groups, scaled from FPMR. | – |
smlal, smlsl, umlal, umlsl | smlal za.s[w8, 0x0:0x1, vgx2], { z0.h, z1.h }, z0.h | Multiplies signed (s) or unsigned (u) 16-bit integers. Adds the 32-bit products to ZA (mlal) or subtracts them (mlsl). | – |
smlall, smlsll, umlall, umlsll | smlall za.s[w8, 0x0:0x3, vgx2], { z0.b, z1.b }, z0.b | Multiplies 8-bit or 16-bit integers. Adds the 32-bit or 64-bit products to quad-vector groups, or subtracts them. | – |
sumlall | sumlall za.s[w8, 0x0:0x3, vgx2], { z0.b, z1.b }, z0.b | Multiplies signed 8-bit elements of the first source by unsigned 8-bit elements of the second, and adds the 32-bit products to ZA. | – |
usmlall | usmlall za.s[w8, 0x0:0x3, vgx2], { z0.b, z1.b }, z0.b | Multiplies unsigned 8-bit elements of the first source by signed 8-bit elements of the second, and adds the 32-bit products to ZA. | – |
Dot products to ZA
A dot product adds together the products of two or four small elements. The total is added to a wider element of ZA.
| Mnemonic | Syntax | What it does | Flags |
|---|---|---|---|
bfdot | bfdot za.s[w8, 0, vgx2], { z0.h, z1.h }, z0.h | Dot product of BFloat16 pairs, added to single-precision elements. | – |
fdot | fdot za.s[w8, 0, vgx2], { z0.h, z1.h }, z0.h | Dot product of half-precision pairs, added to single-precision elements. Other forms take 8-bit floating-point values, in pairs to half precision or in groups of four to single precision, scaled from FPMR. | – |
sdot, udot | sdot za.s[w8, 0, vgx2], { z0.b, z1.b }, z0.b | Dot product of signed or unsigned integers: 16-bit pairs to 32 bits, or groups of four 8-bit or 16-bit values to 32 or 64 bits. | – |
sudot | sudot za.s[w8, 0, vgx2], { z0.b, z1.b }, z0.b | Dot product of groups of four: signed 8-bit values in the first source, unsigned 8-bit values in the second, added to 32-bit elements. | – |
usdot | usdot za.s[w8, 0, vgx2], { z0.b, z1.b }, z0.b | The same, with unsigned values in the first source and signed values in the second. | – |
Vertical dot products to ZA
In a vertical dot product, the elements that are multiplied together come from the same element position in different registers of the first source group. The second source is an indexed element, chosen within each 128-bit segment.
| Mnemonic | Syntax | What it does | Flags |
|---|---|---|---|
bfvdot | bfvdot za.s[w8, 0, vgx2], { z0.h, z1.h }, z0.h[0] | Vertical dot product of BFloat16 pairs, added to single-precision elements. | – |
fvdot | fvdot za.s[w8, 0, vgx2], { z0.h, z1.h }, z0.h[0] | Vertical dot product of half-precision pairs, added to single-precision elements. Another form takes 8-bit floating-point values and adds to half-precision elements, scaled from FPMR. | – |
fvdotb, fvdott | fvdotb za.s[w8, 0, vgx4], { z0.b, z1.b }, z0.b[0] | Vertical dot product of 8-bit floating-point values, added to single-precision elements of four ZA groups, scaled from FPMR. fvdotb uses the lower-numbered pair of the indexed group, and fvdott uses the higher-numbered pair. | – |
svdot, uvdot | svdot za.s[w8, 0, vgx2], { z0.h, z1.h }, z0.h[0] | Vertical dot product of signed or unsigned integers, added to wider elements: 16-bit pairs to 32 bits, or groups of four. | – |
suvdot | suvdot za.s[w8, 0, vgx4], { z0.b - z3.b }, z0.b[0] | Vertical dot product of four signed 8-bit values in the first source and four unsigned 8-bit values in the indexed second source, added to 32-bit elements. | – |
usvdot | usvdot za.s[w8, 0, vgx4], { z0.b - z3.b }, z0.b[0] | The same, with unsigned values in the first source and signed values in the second. | – |
Outer products to a ZA tile
These add to the forms on the SME page. They are predicated by two P registers, as there.
| Mnemonic | Syntax | What it does | Flags |
|---|---|---|---|
smopa, smops | smopa za0.s, p0/m, p0/m, z0.h, z0.h | Two-way sum of outer products of signed 16-bit integers, added to or subtracted from a 32-bit tile. An inactive source element counts as 0. | – |
umopa, umops | umopa za0.s, p0/m, p0/m, z0.h, z0.h | The same, for unsigned 16-bit integers. | – |
fmopa, fmops | fmopa za0.h, p0/m, p0/m, z0.h, z0.h | Outer product of half-precision elements, accumulated in a 16-bit tile. If either source element is inactive, the tile element stays unchanged. fmopa also has 8-bit forms, widening to half or single precision and scaled from FPMR. | – |
bfmopa, bfmops | bfmopa za0.h, p0/m, p0/m, z0.h, z0.h | Outer product of BFloat16 elements, accumulated in a 16-bit tile. If either source element is inactive, the tile element stays unchanged. | – |
Quarter-tile outer products
Each of these makes four independent outer products. Each outer product covers a
quarter of the destination tile and comes from the half-vectors of the source
registers. They take one or two Z registers per source and have no predicate. The
a forms accumulate and the s forms subtract.
| Mnemonic | Syntax | What it does | Flags |
|---|---|---|---|
fmop4a, fmop4s | fmop4a za0.s, z0.s, z16.s | Floating-point outer products for half, single and double precision. Half-precision sums of outer products to a single-precision tile are another form. fmop4a also has 8-bit forms to half or single precision, scaled from FPMR. | – |
bfmop4a, bfmop4s | bfmop4a za0.s, z0.h, z16.h | BFloat16 outer products to a 16-bit tile, or sums of outer products to a single-precision tile. | – |
smop4a, smop4s, umop4a, umop4s | smop4a za0.d, z0.h, z16.h | Sums of outer products of signed (s) or unsigned (u) integers: 16-bit two-way to a 32-bit tile, or four-way 8-bit to 32-bit and 16-bit to 64-bit. | – |
sumop4a, sumop4s | sumop4a za0.d, z0.h, z16.h | Sums of outer products with signed values in the first source and unsigned values in the second. | – |
usmop4a, usmop4s | usmop4a za0.d, z0.h, z16.h | The same, with unsigned values in the first source and signed values in the second. | – |
Sparse outer products
Each of these takes two dense first-source vectors and a compressed second source. An indexed control vector register selects which first-source elements are used; a control bit of 0 drops an element. They have no predicate.
| Mnemonic | Syntax | What it does | Flags |
|---|---|---|---|
ftmopa | ftmopa za0.s, { z0.s, z1.s }, z0.s, z20[0] | Floating-point sparse outer product, accumulated in the tile. Widening forms take half-precision or 8-bit values. | – |
bftmopa | bftmopa za0.s, { z0.h, z1.h }, z0.h, z20[0] | BFloat16 sparse outer product, with non-widening and single-precision widening forms. | – |
stmopa, utmopa | stmopa za0.s, { z0.b, z1.b }, z0.b, z20[0] | Sparse sum of outer products of signed or unsigned integers, 8-bit or 16-bit, accumulated in a 32-bit tile. | – |
sutmopa | sutmopa za0.s, { z0.b, z1.b }, z0.b, z20[0] | Sparse sum of outer products of signed 8-bit first-source values and unsigned 8-bit second-source values. | – |
ustmopa | ustmopa za0.s, { z0.b, z1.b }, z0.b, z20[0] | The same, unsigned by signed. | – |
Multi-vector arithmetic on Z registers
These write two or four Z registers. The second source is either one vector or a group of the same size. They have no predicate.
| Mnemonic | Syntax | What it does | Flags |
|---|---|---|---|
smax, smin, umax, umin | smax { z0.b, z1.b }, { z0.b, z1.b }, z0.b | Signed or unsigned maximum and minimum of each element pair. | – |
sclamp, uclamp | sclamp { z0.b, z1.b }, z0.b, z0.b | Clamps each destination element between the matching elements of the two sources, the first being the minimum and the second the maximum. | – |
fmax, fmin, fmaxnm, fminnm | fmax { z0.h, z1.h }, { z0.h, z1.h }, z0.h | Floating-point maximum and minimum. The nm forms return the number when one operand is a quiet NaN and the other is numeric. The handling of NaNs and zeros in fmax and fmin depends on FPCR.AH. | – |
bfmax, bfmin, bfmaxnm, bfminnm | bfmax { z0.h, z1.h }, { z0.h, z1.h }, z0.h | The same, for BFloat16 values. | – |
famax, famin | famax { z0.h, z1.h }, { z0.h, z1.h }, { z0.h, z1.h } | Maximum or minimum of the absolute values of the element pair. The second operand is always a group. | – |
fclamp, bfclamp | fclamp { z0.h, z1.h }, z0.h, z0.h | Clamps each destination element between the matching elements of the two sources, using the minimum number and maximum number operations. | – |
fmul, bfmul | fmul { z0.h, z1.h }, { z0.h, z1.h }, { z0.h, z1.h } | Multiplies floating-point or BFloat16 elements. | – |
fscale, bfscale | fscale { z0.h, z1.h }, { z0.h, z1.h }, z0.h | Multiplies each element of the first source by 2 to the power of the signed integer in the matching element of the second source. | – |
sqdmulh | sqdmulh { z0.b, z1.b }, { z0.b, z1.b }, z0.b | Multiplies signed elements, doubles the result, and keeps the most significant half. The result is saturated. | – |
srshl, urshl | srshl { z0.b, z1.b }, { z0.b, z1.b }, z0.b | Shifts signed or unsigned elements by the amount in the second source, with rounding. A positive amount shifts left and a negative amount shifts right. | – |
Floating-point conversions on Z registers
| Mnemonic | Syntax | What it does | Flags |
|---|---|---|---|
fcvt | fcvt z0.h, { z0.s, z1.s }fcvt { z0.s, z1.s }, z0.h | Converts between precisions: two single-precision vectors to one half-precision vector, or one half-precision vector to two single-precision vectors. Forms that end in 8-bit values are scaled from FPMR. | – |
fcvtn | fcvtn z0.h, { z0.s, z1.s } | Narrows two single-precision vectors to one half-precision vector, with the results interleaved. Another form narrows four vectors to 8-bit values. | – |
fcvtl | fcvtl { z0.s, z1.s }, z0.h | Converts one half-precision vector to two single-precision vectors, with the results deinterleaved. | – |
bfcvt, bfcvtn | bfcvt z0.h, { z0.s, z1.s } | Converts two single-precision vectors to one BFloat16 vector. bfcvtn interleaves the results. bfcvt also has a form from BFloat16 to 8-bit floating point, scaled from FPMR. | – |
f1cvt, f2cvt | f1cvt { z0.h, z1.h }, z0.b | Converts each 8-bit floating-point element to half precision, scaling down. The 1 form uses FPMR.LSCALE and FPMR.F8S1, and the 2 form uses FPMR.LSCALE2 and FPMR.F8S2. | – |
f1cvtl, f2cvtl | f1cvtl { z0.h, z1.h }, z0.b | The same, with the results deinterleaved into the two destination vectors. | – |
bf1cvt, bf2cvt | bf1cvt { z0.h, z1.h }, z0.b | Converts each 8-bit floating-point element to BFloat16, scaling down, with the same FPMR fields as f1cvt and f2cvt. | – |
bf1cvtl, bf2cvtl | bf1cvtl { z0.h, z1.h }, z0.b | The same, with the results deinterleaved. | – |
fcvtzs, fcvtzu | fcvtzs { z0.s, z1.s }, { z0.s, z1.s } | Converts single-precision elements to signed or unsigned 32-bit integers, rounding toward zero. | – |
scvtf, ucvtf | scvtf { z0.s, z1.s }, { z0.s, z1.s } | Converts signed or unsigned 32-bit integers to single precision. | – |
frinta, frintm, frintn, frintp | frinta { z0.s, z1.s }, { z0.s, z1.s } | Rounds single-precision elements to integral values: frinta to nearest with ties away from zero, frintm toward minus infinity, frintn to nearest with ties to even, frintp toward plus infinity. | – |
Saturating narrowing
These turn two or four source vectors into one vector of narrower elements. The
n forms interleave the results. Results saturate to the destination
range.
| Mnemonic | Syntax | What it does | Flags |
|---|---|---|---|
sqcvt, sqcvtn | sqcvt z0.h, { z0.s, z1.s }sqcvtn z0.b, { z0.s - z3.s } | Saturates signed integers to half or quarter their width. | – |
uqcvt, uqcvtn | uqcvt z0.h, { z0.s, z1.s }uqcvtn z0.b, { z0.s - z3.s } | The same, for unsigned integers. | – |
sqcvtu, sqcvtun | sqcvtu z0.h, { z0.s, z1.s }sqcvtun z0.b, { z0.s - z3.s } | Saturates signed integers to unsigned values of half or quarter the width. | – |
sqrshr, sqrshrn | sqrshr z0.h, { z0.s, z1.s }, #0x10sqrshrn z0.b, { z0.s - z3.s }, #0x20 | Shifts signed integers right by the immediate with rounding, then saturates to narrower signed elements. | – |
sqrshru, sqrshrun | sqrshru z0.h, { z0.s, z1.s }, #0x10sqrshrun z0.b, { z0.s - z3.s }, #0x20 | The same, saturating to narrower unsigned elements. | – |
uqrshr, uqrshrn | uqrshr z0.h, { z0.s, z1.s }, #0x10uqrshrn z0.b, { z0.s - z3.s }, #0x20 | Shifts unsigned integers right by the immediate with rounding, then saturates to narrower unsigned elements. | – |
Selecting and rearranging Z registers
| Mnemonic | Syntax | What it does | Flags |
|---|---|---|---|
sel | sel { z0.b, z1.b }, pn8, { z0.b, z1.b }, { z0.b, z1.b } | Takes consecutive elements from the first source group where the counter predicate is true, and from the second group elsewhere. | – |
sunpk, uunpk | sunpk { z0.h, z1.h }, z0.bsunpk { z0.h - z3.h }, { z0.b, z1.b } | Unpacks elements of one or two source vectors to double width, into two or four destination vectors. sunpk sign-extends and uunpk zero-extends. | – |
uzp | uzp { z0.b, z1.b }, z0.b, z0.b | Concatenates every second element of the two sources into two destinations. A four-register form takes every fourth element. Forms with 128-bit elements exist too. | – |
zip | zip { z0.b, z1.b }, z0.b, z0.bzip { z0.b - z3.b }, { z0.b - z3.b } | Interleaves elements of the two or four sources into two or four destinations. Forms with 128-bit elements exist too. | – |
Loads and stores of multiple vectors
These use a predicate-as-counter register. They transfer two or four vectors, either
consecutive registers or strided registers such as { z0.b, z8.b }. The
consecutive forms also exist in SVE2.1. The strided forms are SME2 only.
| Mnemonic | Syntax | What it does | Flags |
|---|---|---|---|
ld1b, ld1h, ld1w, ld1d | ld1b { z0.b, z1.b }, pn8/z, [x0, x0]ld1d { z0.d, z1.d }, pn8/z, [x0, x0, lsl #3] | Loads bytes, halfwords, words or doublewords to the elements of the vectors, with a register or immediate offset. Inactive elements are set to zero. | – |
ldnt1b, ldnt1h, ldnt1w, ldnt1d | ldnt1b { z0.b, z1.b }, pn8/z, [x0, x0] | Non-temporal loads: the same, with a hint that the data is unlikely to be used again soon. | – |
st1b, st1h, st1w, st1d | st1b { z0.b, z1.b }, pn8, [x0, x0] | Stores the elements of the vectors. Inactive elements are not written. | – |
stnt1b, stnt1h, stnt1w, stnt1d | stnt1b { z0.b, z1.b }, pn8, [x0, x0] | Non-temporal stores: the same, with a hint that the data is unlikely to be used again soon. | – |
ldr, str | ldr zt0, [x0]str zt0, [x0] | Loads or stores the 64 bytes of ZT0 at the address in the base register. Access is by bytes, with no endian conversion. Streaming mode is not needed. | – |
Moving, table lookups and clearing
| Mnemonic | Syntax | What it does | Flags |
|---|---|---|---|
mov | mov za0h.b[w12, 0x0:0x1], { z0.b, z1.b }mov { z0.b, z1.b }, za0h.b[w12, 0x0:0x1]mov za.d[w8, 0, vgx2], { z0.d, z1.d } | Copies two or four Z registers to ZA tile slices or ZA vector groups, or the other way round. This is an alias of mova. It has no predicate in these forms. | – |
movaz | movaz z0.b, za0h.b[w12, 0]movaz { z0.b, z1.b }, za0h.b[w12, 0x0:0x1] | Copies ZA slices or vector groups to Z registers, then sets those slices or groups to zero. | – |
movt | movt x0, zt0[0]movt zt0[0], x0movt zt0, z0 | Copies 8 bytes between ZT0 and a general-purpose register, at a byte offset. These two forms are UNDEFINED outside Debug state. The third form copies a Z register into ZT0 at a vector-length offset; at offset 0 it also writes zeroes to the rest of ZT0. | – |
luti2, luti4 | luti2 z0.b, zt0, z0[0]luti2 { z0.b, z8.b }, zt0, z0[0]luti4 { z0.b - z3.b }, zt0, { z0, z1 } | Copies elements from ZT0 to one, two or four destination vectors, using packed 2-bit or 4-bit indexes from a segment of the index register. The index operand selects the segment. | – |
zero | zero { zt0 }zero za.d[w8, 0, vgx2] | Sets all of ZT0 to zero, or sets one, two or four ZA vector groups to zero. Zeroing ZT0 does not need streaming mode. | – |
Links
Reference
- Arm A64 Instruction Set Architecture – Arm’s description of each A64 instruction
- Arm Architecture Reference Manual for A-profile – the full architecture specification