9.1. Format and Semantics of Instruction Descriptions#
This section describes each PTX instruction. In addition to the name and the format of the
instruction, the semantics are described, followed by some examples that attempt to show several
possible instantiations of the instruction.
PTX instructions generally have from zero to four operands, plus an optional guard predicate
appearing after an @ symbol to the left of the opcode:
@popcode;
@popcodea;
@popcoded,a;
@popcoded,a,b;
@popcoded,a,b,c;
For instructions that create a result value, the d operand is the destination operand, while
a, b, and c are source operands.
The setp instruction writes two destination registers. We use a | symbol to separate
multiple destination registers.
setp.lt.s32 p|q, a, b; // p = (a < b); q = !(a < b);
For some instructions the destination operand is optional. A bit bucket operand denoted with an
underscore (_) may be used in place of a destination register.
In PTX, predicate registers are virtual and have .pred as the type specifier. So, predicate
registers can be declared as
.reg .pred p, q, r;
All instructions have an optional guard predicate which controls conditional execution of the
instruction. The syntax to specify conditional execution is to prefix an instruction with @{!}p,
where p is a predicate variable, optionally negated. Instructions without a guard predicate are
executed unconditionally.
Predicates are most commonly set as the result of a comparison performed by the setp
instruction.
As an example, consider the high-level code
if (i < n)
j = j + 1;
This can be written in PTX as
setp.lt.s32 p, i, n; // p = (i < n)
@p add.s32 j, j, 1; // if i < n, add 1 to j
To get a conditional branch or conditional function call, use a predicate to control the execution
of the branch or call instructions. To implement the above example as a true conditional branch, the
following PTX instruction sequence might be used:
setp.lt.s32 p, i, n; // compare i to n
@!p bra L1; // if False, branch over
add.s32 j, j, 1;
L1: ...
The signed integer comparisons are the traditional eq (equal), ne (not-equal), lt
(less-than), le (less-than-or-equal), gt (greater-than), and ge
(greater-than-or-equal). The unsigned comparisons are eq, ne, lo (lower), ls
(lower-or-same), hi (higher), and hs (higher-or-same). The bit-size comparisons are eq
and ne; ordering comparisons are not defined for bit-size types.
Table 22
shows the operators for signed integer, unsigned integer, and bit-size types.
Table 22 Operators for Signed Integer, Unsigned Integer, and Bit-Size Types
The ordered floating-point comparisons are eq, ne, lt, le, gt, and ge. If
either operand is NaN, the result is
False. Table 23 lists the floating-point
comparison operators.
Table 23 Floating-Point Comparison Operators
Meaning
Floating-Point Operator
a==b&&!isNaN(a)&&!isNaN(b)
eq
a!=b&&!isNaN(a)&&!isNaN(b)
ne
a<b&&!isNaN(a)&&!isNaN(b)
lt
a<=b&&!isNaN(a)&&!isNaN(b)
le
a>b&&!isNaN(a)&&!isNaN(b)
gt
a>=b&&!isNaN(a)&&!isNaN(b)
ge
To aid comparison operations in the presence of NaN values, unordered floating-point comparisons
are provided: equ, neu, ltu, leu, gtu, and geu. If both operands are numeric
values (not NaN), then the comparison has the same result as its ordered counterpart. If either
operand is NaN, then the result of the comparison is True.
Table 24 lists the floating-point
comparison operators accepting NaN values.
Table 24 Floating-Point Comparison Operators Accepting NaN
Meaning
Floating-Point Operator
a==b||isNaN(a)||isNaN(b)
equ
a!=b||isNaN(a)||isNaN(b)
neu
a<b||isNaN(a)||isNaN(b)
ltu
a<=b||isNaN(a)||isNaN(b)
leu
a>b||isNaN(a)||isNaN(b)
gtu
a>=b||isNaN(a)||isNaN(b)
geu
To test for NaN values, two operators num (numeric) and nan (isNaN) are
provided. num returns True if both operands are numeric values (not NaN), and nan
returns True if either operand is
NaN. Table 25 lists the
floating-point comparison operators testing for NaN values.
Table 25 Floating-Point Comparison Operators Testing for NaN
Predicate values may be computed and manipulated using the following instructions: and, or,
xor, not, and mov.
There is no direct conversion between predicates and integer values, and no direct way to load or
store predicate register values. However, setp can be used to generate a predicate from an
integer, and the predicate-based select (selp) instruction can be used to generate an integer
value based on the value of a predicate; for example:
selp.u32 %r1,1,0,%p; // convert predicate to 32-bit value
9.4. Type Information for Instructions and Operands#
Typed instructions must have a type-size modifier. For example, the add instruction requires
type and size information to properly perform the addition operation (signed, unsigned, float,
different sizes), and this information must be specified as a suffix to the opcode.
Example
.reg .u16 d, a, b;
add.u16 d, a, b; // perform a 16-bit unsigned add
Some instructions require multiple type-size modifiers, most notably the data conversion instruction
cvt. It requires separate type-size modifiers for the result and source, and these are placed in
the same order as the operands. For example:
.reg .u16 a;
.reg .f32 d;
cvt.f32.u16 d, a; // convert 16-bit unsigned to 32-bit float
In general, an operand’s type must agree with the corresponding instruction-type modifier. The rules
for operand and instruction type conformance are as follows:
Bit-size types agree with any type of the same size.
Signed and unsigned integer types agree provided they have the same size, and integer operands are
silently cast to the instruction type if needed. For example, an unsigned integer operand used in
a signed integer instruction will be treated as a signed integer by the instruction.
Floating-point types agree only if they have the same size; i.e., they must match exactly.
Some operands have their type and size defined independently from the instruction type-size. For
example, the shift amount operand for left and right shift instructions always has type .u32,
while the remaining operands have their type and size determined by the instruction type.
Example
// 64-bit arithmetic right shift; shift amount 'b' is .u32
shr.s64 d,a,b;
For convenience, ld, st, and cvt instructions permit source and destination data
operands to be wider than the instruction-type size, so that narrow values may be loaded, stored,
and converted using regular-width registers. For example, 8-bit or 16-bit values may be held
directly in 32-bit or 64-bit registers when being loaded, stored, or converted to other types and
sizes. The operand type checking rules are relaxed for bit-size and integer (signed and unsigned)
instruction types; floating-point instruction types still require that the operand type-size matches
exactly, unless the operand is of bit-size type.
When a source operand has a size that exceeds the instruction-type size, the source data is
truncated (chopped) to the appropriate number of bits specified by the instruction type-size.
Table 27
summarizes the relaxed type-checking rules for source operands. Note that some combinations may
still be invalid for a particular instruction; for example, the cvt instruction does not support
.bX instruction types, so those rows are invalid for cvt.
Table 27 Relaxed Type-checking Rules for Source Operands
Source Operand Type
b8
b16
b32
b64
b128
s8
s16
s32
s64
u8
u16
u32
u64
f16
f32
f64
Instruction Type
b8
–
chop
chop
chop
chop
–
chop
chop
chop
–
chop
chop
chop
chop
chop
chop
b16
inv
–
chop
chop
chop
inv
–
chop
chop
inv
–
chop
chop
–
chop
chop
b32
inv
inv
–
chop
chop
inv
inv
–
chop
inv
inv
–
chop
inv
–
chop
b64
inv
inv
inv
–
chop
inv
inv
inv
–
inv
inv
inv
–
inv
inv
–
b128
inv
inv
inv
inv
–
inv
inv
inv
inv
inv
inv
inv
inv
inv
inv
inv
s8
–
chop
chop
chop
chop
–
chop
chop
chop
–
chop
chop
chop
inv
inv
inv
s16
inv
–
chop
chop
chop
inv
–
chop
chop
inv
–
chop
chop
inv
inv
inv
s32
inv
inv
–
chop
chop
inv
inv
–
chop
inv
inv
–
chop
inv
inv
inv
s64
inv
inv
inv
–
chop
inv
inv
inv
–
inv
inv
inv
–
inv
inv
inv
u8
–
chop
chop
chop
chop
–
chop
chop
chop
–
chop
chop
chop
inv
inv
inv
u16
inv
–
chop
chop
chop
inv
–
chop
chop
inv
–
chop
chop
inv
inv
inv
u32
inv
inv
–
chop
chop
inv
inv
–
chop
inv
inv
–
chop
inv
inv
inv
u64
inv
inv
inv
–
chop
inv
inv
inv
–
inv
inv
inv
–
inv
inv
inv
f16
inv
–
chop
chop
chop
inv
inv
inv
inv
inv
inv
inv
inv
–
inv
inv
f32
inv
inv
–
chop
chop
inv
inv
inv
inv
inv
inv
inv
inv
inv
–
inv
f64
inv
inv
inv
–
chop
inv
inv
inv
inv
inv
inv
inv
inv
inv
inv
–
Notes
chop = keep only low bits that fit; “–” = allowed, but no conversion needed;
inv = invalid, parse error.
Source register size must be of equal or greater size than the instruction-type size.
Bit-size source registers may be used with any appropriately-sized instruction type. The data are
truncated (“chopped”) to the instruction-type size and interpreted according to the instruction
type.
Integer source registers may be used with any appropriately-sized bit-size or integer instruction
type. The data are truncated to the instruction-type size and interpreted according to the
instruction type.
Floating-point source registers can only be used with bit-size or floating-point instruction types.
When used with a narrower bit-size instruction type, the data are truncated. When used with a
floating-point instruction type, the size must match exactly.
When a destination operand has a size that exceeds the instruction-type size, the destination data
is zero- or sign-extended to the size of the destination register. If the corresponding instruction
type is signed integer, the data is sign-extended; otherwise, the data is zero-extended.
Table 28
summarizes the relaxed type-checking rules for destination operands.
Table 28 Relaxed Type-checking Rules for Destination Operands
Destination Operand Type
b8
b16
b32
b64
b128
s8
s16
s32
s64
u8
u16
u32
u64
f16
f32
f64
Instruction Type
b8
–
zext
zext
zext
zext
–
zext
zext
zext
–
zext
zext
zext
zext
zext
zext
b16
inv
–
zext
zext
zext
inv
–
zext
zext
inv
–
zext
zext
–
zext
zext
b32
inv
inv
–
zext
zext
inv
inv
–
zext
inv
inv
–
zext
inv
–
zext
b64
inv
inv
inv
–
zext
inv
inv
inv
–
inv
inv
inv
–
inv
inv
–
b128
inv
inv
inv
inv
–
inv
inv
inv
inv
inv
inv
inv
inv
inv
inv
inv
s8
–
sext
sext
sext
sext
–
sext
sext
sext
–
sext
sext
sext
inv
inv
inv
s16
inv
–
sext
sext
sext
inv
–
sext
sext
inv
–
sext
sext
inv
inv
inv
s32
inv
inv
–
sext
sext
inv
inv
–
sext
inv
inv
–
sext
inv
inv
inv
s64
inv
inv
inv
–
sext
inv
inv
inv
–
inv
inv
inv
–
inv
inv
inv
u8
–
zext
zext
zext
zext
–
zext
zext
zext
–
zext
zext
zext
inv
inv
inv
u16
inv
–
zext
zext
zext
inv
–
zext
zext
inv
–
zext
zext
inv
inv
inv
u32
inv
inv
–
zext
zext
inv
inv
–
zext
inv
inv
–
zext
inv
inv
inv
u64
inv
inv
inv
–
zext
inv
inv
inv
–
inv
inv
inv
–
inv
inv
inv
f16
inv
–
zext
zext
zext
inv
inv
inv
inv
inv
inv
inv
inv
–
inv
inv
f32
inv
inv
–
zext
zext
inv
inv
inv
inv
inv
inv
inv
inv
inv
–
inv
f64
inv
inv
inv
–
zext
inv
inv
inv
inv
inv
inv
inv
inv
inv
inv
–
Notes
sext = sign-extend; zext = zero-extend; “–” = allowed, but no conversion needed;
inv = invalid, parse error.
Destination register size must be of equal or greater size than the instruction-type size.
Bit-size destination registers may be used with any appropriately-sized instruction type. The data
are sign-extended to the destination register width for signed integer instruction types, and are
zero-extended to the destination register width otherwise.
Integer destination registers may be used with any appropriately-sized bit-size or integer
instruction type. The data are sign-extended to the destination register width for signed integer
instruction types, and are zero-extended to the destination register width for bit-size and
unsigned integer instruction types.
Floating-point destination registers can only be used with bit-size or floating-point instruction
types. When used with a narrower bit-size instruction type, the data are zero-extended. When used
with a floating-point instruction type, the size must match exactly.
Threads in a CTA execute together, at least in appearance, until they come to a conditional control
construct such as a conditional branch, conditional function call, or conditional return. If threads
execute down different control flow paths, the threads are called divergent. If all of the threads
act in unison and follow a single control flow path, the threads are called uniform. Both
situations occur often in programs.
A CTA with divergent threads may have lower performance than a CTA with uniformly executing threads,
so it is important to have divergent threads re-converge as soon as possible. All control constructs
are assumed to be divergent points unless the control-flow instruction is marked as uniform, using
the .uni suffix. For divergent control flow, the optimizing code generator automatically
determines points of re-convergence. Therefore, a compiler or code author targeting PTX can ignore
the issue of divergent threads, but has the opportunity to improve performance by marking branch
points as uniform when the compiler or author can guarantee that the branch point is non-divergent.
The goal of the semantic description of an instruction is to describe the results in all cases in as
simple language as possible. The semantics are described using C, until C is not expressive enough.
A PTX program may execute on a GPU with either a 16-bit or a 32-bit data path. When executing on a
32-bit data path, 16-bit registers in PTX are mapped to 32-bit physical registers, and 16-bit
computations are promoted to 32-bit computations. This can lead to computational differences
between code run on a 16-bit machine versus the same code run on a 32-bit machine, since the
promoted computation may have bits in the high-order half-word of registers that are not present in
16-bit physical registers. These extra precision bits can become visible at the application level,
for example, by a right-shift instruction.
At the PTX language level, one solution would be to define semantics for 16-bit code that is
consistent with execution on a 16-bit data path. This approach introduces a performance penalty for
16-bit code executing on a 32-bit data path, since the translated code would require many additional
masking instructions to suppress extra precision bits in the high-order half-word of 32-bit
registers.
Rather than introduce a performance penalty for 16-bit code running on 32-bit GPUs, the semantics of
16-bit instructions in PTX is machine-specific. A compiler or programmer may choose to enforce
portable, machine-independent 16-bit semantics by adding explicit conversions to 16-bit values at
appropriate points in the program to guarantee portability of the code. However, for many
performance-critical applications, this is not desirable, and for many applications the difference
in execution is preferable to limiting performance.
Performs addition and writes the resulting value into a destination register.
For .u16x2, .s16x2 instruction types, forms input vectors by half word values from source
operands. Half-word operands are then added in parallel to produce .u16x2, .s16x2 result in
destination.
For .u8x4, .s8x4 instruction types, forms input vectors by quarter word values from source
operands. Quarter-word operands are then added in parallel to produce .u8x4, .s8x4 result
in destination.
Operands d, a and b have the same type as the instruction type. For instruction types
.u16x2, .s16x2, .u8x4, .s8x4, operands d, a and b have type .b32.
Semantics
if (type == u16x2 || type == s16x2) {
iA[0] = a[0:15];
iA[1] = a[16:31];
iB[0] = b[0:15];
iB[1] = b[16:31];
for (i = 0; i < 2; i++) {
d[i] = iA[i] + iB[i];
}
} else if (type == u8x4 || type == s8x4) {
iA[0] = a[0:7];
iA[1] = a[8:15];
iA[2] = a[16:23];
iA[3] = a[24:31];
iB[0] = b[0:7];
iB[1] = b[8:15];
iB[2] = b[16:23];
iB[3] = b[24:31];
for (i = 0; i < 4; i++) {
d[i] = iA[i] + iB[i];
}
} else {
d = a + b;
}
Performs subtraction and writes the resulting value into a destination register.
For .u8x4, .s8x4 instruction types, forms input vectors by quarter word values from source
operands. Quarter-word operands are then subtracted in parallel to produce .u8x4, .s8x4 result
in destination.
For instruction types .u8x4, .s8x4 operands d, a and b have type .b32.
Semantics
if (type == u8x4 || type == s8x4) {
iA[0] = a[0:7];
iA[1] = a[8:15];
iA[2] = a[16:23];
iA[3] = a[24:31];
iB[0] = b[0:7];
iB[1] = b[8:15];
iB[2] = b[16:23];
iB[3] = b[24:31];
for (i = 0; i < 4; i++) {
d[i] = iA[i] - iB[i];
}
} else {
d = a - b;
}
Multiplies two values, optionally extracts the high or low half of the intermediate result, and adds
a third value. Writes the result into a destination register.
Semantics
t = a * b;
n = bitwidth of type;
d = t + c; // for .wide
d = t<2n-1..n> + c; // for .hi variant
d = t<n-1..0> + c; // for .lo variant
Multiply two 24-bit integer values and add a third value.
Syntax
mad24.mode.type d, a, b, c;
mad24.hi.sat.s32 d, a, b, c;
.mode = { .hi, .lo };
.type = { .u32, .s32 };
Description
Compute the product of two 24-bit integer values held in 32-bit source registers, and add a third,
32-bit value to either the high or low 32-bits of the 48-bit result. Return either the high or low
32-bits of the 48-bit result.
Semantics
t = a * b;
d = t<47..16> + c; // for .hi variant
d = t<31..0> + c; // for .lo variant
Examples
mad24.lo.s32 d,a,b,c; // low 32-bits of 24x24-bit signed multiply.
For .s8x4 instruction types, forms input vectors by quarter word values
from source operands. Quarter-word operands are then negated in parallel to
produce .s8x4 result in destination.
Operands d and a have the same type as the instruction type.
For instruction type .s8x4, operands d and a have type .b32.
Semantics
if (type == s8x4) {
iA[0] = a[0:7];
iA[1] = a[8:15];
iA[2] = a[16:23];
iA[3] = a[24:31];
for (i = 0; i < 4; i++) {
d[i] = -iA[i];
}
} else {
d = -a;
}
For .u16x2, .s16x2 instruction types, forms input vectors by half word values from source
operands. Half-word operands are then processed in parallel to produce .u16x2, .s16x2 result
in destination.
For .u8x4, .s8x4 instruction types, input vectors are formed with quarter-word values from
source operands. Quarter-word operands are then processed in parallel to store .u8x4, .s8x4
result in destination.
Operands d, a and b have the same type as the instruction type. For instruction types
.u16x2, .s16x2, .u8x4, .s8x4, operands d, a and b have type .b32.
Semantics
if (type == u16x2 || type == s16x2) {
iA[0] = a[0:15];
iA[1] = a[16:31];
iB[0] = b[0:15];
iB[1] = b[16:31];
for (i = 0; i < 2; i++) {
d[i] = (iA[i] < iB[i]) ? iA[i] : iB[i];
}
} else if (type == u8x4 || type == s8x4) {
iA[0] = a[0:7];
iA[1] = a[8:15];
iA[2] = a[16:23];
iA[3] = a[24:31];
iB[0] = b[0:7];
iB[1] = b[8:15];
iB[2] = b[16:23];
iB[3] = b[24:31];
for (i = 0; i < 4; i++) {
d[i] = (iA[i] < iB[i]) ? iA[i] : iB[i];
}
} else {
d = (a < b) ? a : b; // Integer (signed and unsigned)
}
For .u16x2, .s16x2 instruction types, forms input vectors by half word values from source
operands. Half-word operands are then processed in parallel to produce .u16x2, .s16x2 result
in destination.
For .u8x4, .s8x4 instruction types, input vectors are formed with quarter-word values from
source operands. Quarter-word operands are then processed in parallel to store .u8x4, .s8x4
result in destination.
Operands d, a and b have the same type as the instruction type. For instruction types
.u16x2, .s16x2, .u8x4, .s8x4, operands d, a and b have type .b32.
Semantics
if (type == u16x2 || type == s16x2) {
iA[0] = a[0:15];
iA[1] = a[16:31];
iB[0] = b[0:15];
iB[1] = b[16:31];
for (i = 0; i < 2; i++) {
d[i] = (iA[i] > iB[i]) ? iA[i] : iB[i];
}
} else if (type == u8x4 || type == s8x4) {
iA[0] = a[0:7];
iA[1] = a[8:15];
iA[2] = a[16:23];
iA[3] = a[24:31];
iB[0] = b[0:7];
iB[1] = b[8:15];
iB[2] = b[16:23];
iB[3] = b[24:31];
for (i = 0; i < 4; i++) {
d[i] = (iA[i] > iB[i]) ? iA[i] : iB[i];
}
} else {
d = (a > b) ? a : b; // Integer (signed and unsigned)
}
Examples
max.u32 d,a,b;
max.s32 q,q,0;
max.relu.s16x2 t,t,u;
max.u8x4 p, q, r;
Count the number of one bits in a and place the resulting population count in 32-bit
destination register d. Operand a has the instruction type and destination d has type
.u32.
Semantics
.u32 d = 0;
while (a != 0) {
if (a & 0x1) d++;
a = a >> 1;
}
Count the number of leading zeros in a starting with the most-significant bit and place the
result in 32-bit destination register d. Operand a has the instruction type, and destination
d has type .u32. For .b32 type, the number of leading zeros is between 0 and 32,
inclusively. For .b64 type, the number of leading zeros is between 0 and 64, inclusively.
Semantics
.u32 d = 0;
if (.type == .b32) { max = 32; mask = 0x80000000; }
else { max = 64; mask = 0x8000000000000000; }
while (d < max && (a&mask == 0) ) {
d++;
a = a << 1;
}
Find the bit position of the most significant non-sign bit in a and place the result in
d. Operand a has the instruction type, and destination d has type .u32. For unsigned
integers, bfind returns the bit position of the most significant 1. For signed integers,
bfind returns the bit position of the most significant 0 for negative inputs and the most
significant 1 for non-negative inputs.
If .shiftamt is specified, bfind returns the shift amount needed to left-shift the found bit
into the most-significant bit position.
bfind returns 0xffffffff if no non-sign bit is found.
Semantics
msb = (.type==.u32 || .type==.s32) ? 31 : 63;
// negate negative signed inputs
if ( (.type==.s32 || .type==.s64) && (a & (1<<msb)) ) {
a = ~a;
}
.u32 d = 0xffffffff;
for (.s32 i=msb; i>=0; i--) {
if (a & (1<<i)) { d = i; break; }
}
if (.shiftamt && d != 0xffffffff) { d = msb - d; }
Examples
bfind.u32 d, a;
bfind.shiftamt.s64 cnt, X; // cnt is .u32
Given a 32-bit value mask and an integer value base (between 0 and 31), find the n-th (given
by offset) set bit in mask from the base bit, and store the bit position in d. If not
found, store 0xffffffff in d.
Operand mask has a 32-bit type. Operand base has .b32, .u32 or .s32
type. Operand offset has .s32 type. Destination d has type .b32.
Operand base must be <= 31, otherwise behavior is undefined.
Semantics
d = 0xffffffff;
if (offset == 0) {
if (mask[base] == 1) {
d = base;
}
} else {
pos = base;
count = |offset| - 1;
inc = (offset > 0) ? 1 : -1;
while ((pos >= 0) && (pos < 32)) { if (mask[pos] == 1) { if (count == 0) { d = pos; break; } else { count = count - 1; } } pos = pos + inc;}
plaintext
}
Examples
fns.b32 d, 0xaaaaaaaa, 3, 1; // d = 3
fns.b32 d, 0xaaaaaaaa, 3, -1; // d = 3
fns.b32 d, 0xaaaaaaaa, 2, 1; // d = 3
fns.b32 d, 0xaaaaaaaa, 2, -1; // d = 1
Extract bit field from a and place the zero or sign-extended result in d. Source b gives
the bit field starting bit position, and source c gives the bit field length in bits.
Operands a and d have the same type as the instruction type. Operands b and c are
type .u32, but are restricted to the 8-bit value range 0..255.
The sign bit of the extracted field is defined as:
.u32, .u64:
zero
.s32, .s64:
msb of input a if the extracted field extends beyond the msb of a msb of extracted
field, otherwise
If the bit field length is zero, the result is zero.
The destination d is padded with the sign bit of the extracted field. If the start position is
beyond the msb of the input, the destination d is filled with the replicated sign bit of the
extracted field.
Semantics
msb = (.type==.u32 || .type==.s32) ? 31 : 63;
pos = b & 0xff; // pos restricted to 0..255 range
len = c & 0xff; // len restricted to 0..255 range
Align and insert a bit field from a into b, and place the result in f. Source c
gives the starting bit position for the insertion, and source d gives the bit field length in
bits.
Operands a, b, and f have the same type as the instruction type. Operands c and
d are type .u32, but are restricted to the 8-bit value range 0..255.
If the bit field length is zero, the result is b.
If the start position is beyond the msb of the input, the result is b.
Semantics
msb = (.type==.b32) ? 31 : 63;
pos = c & 0xff; // pos restricted to 0..255 range
len = d & 0xff; // len restricted to 0..255 range
f = b;
for (i=0; i<len && pos+i<=msb; i++) {
f[pos+i] = a[i];
}
Sign-extends or zero-extends an N-bit value from operand a where N is specified in operand
b. The resulting value is stored in the destination operand d.
For the .s32 instruction type, the value in a is treated as an N-bit signed value and the
most significant bit of this N-bit value is replicated up to bit 31. For the .u32 instruction
type, the value in a is treated as an N-bit unsigned number and is zero-extended to 32
bits. Operand b is an unsigned 32-bit value.
If the value of N is 0, then the result of szext is 0. If the value of N is 32 or higher, then
the result of szext depends upon the value of the .mode qualifier as follows:
If .mode is .clamp, then the result is the same as the source operand a.
If .mode is .wrap, then the result is computed using the wrapped value of N.
Generates a 32-bit mask starting from the bit position specified in operand a, and of the width
specified in operand b. The generated bitmask is stored in the destination operand d.
The resulting bitmask is 0 in the following cases:
When the value of a is 32 or higher and .mode is .clamp.
When either the specified value of b or the wrapped value of b (when .mode is
specified as .wrap) is 0.
Semantics
a1 = a & 0x1f;
mask0 = (~0) << a1;
b1 = b & 0x1f;
sum = a1 + b1;
mask1 = (~0) << sum;
Four-way byte dot product which is accumulated in 32-bit result.
Operand a and b are 32-bit inputs which hold 4 byte inputs in packed form for dot product.
Operand c has type .u32 if both .atype and .btype are .u32 else operand c
has type .s32.
Semantics
d = c;
// Extract 4 bytes from a 32bit input and sign or zero extend
// based on input type.
Va = extractAndSignOrZeroExt_4(a, .atype);
Vb = extractAndSignOrZeroExt_4(b, .btype);
Instructions add.cc, addc, sub.cc, subc, mad.cc and madc reference an
implicitly specified condition code register (CC) having a single carry flag bit (CC.CF)
holding carry-in/carry-out or borrow-in/borrow-out. These instructions support extended-precision
integer addition, subtraction, and multiplication. No other instructions access the condition code,
and there is no support for setting, clearing, or testing the condition code. The condition code
register is not preserved across calls and is mainly intended for use in straight-line code
sequences for computing extended-precision integer addition, subtraction, and multiplication.
The extended-precision arithmetic instructions are:
Multiply two values, extract high or low half of result, and add a third value with carry-out.
Syntax
mad{.hi,.lo}.cc.type d, a, b, c;
.type = { .u32, .s32, .u64, .s64 };
Description
Multiplies two values, extracts either the high or low part of the result, and adds a third
value. Writes the result to the destination register and the carry-out from the addition into the
condition code register.
Semantics
t = a * b;
d = t<63..32> + c; // for .hi variant
d = t<31..0> + c; // for .lo variant
Multiply two values, extract high or low half of result, and add a third value with carry-in and
optional carry-out.
Syntax
madc{.hi,.lo}{.cc}.type d, a, b, c;
.type = { .u32, .s32, .u64, .s64 };
Description
Multiplies two values, extracts either the high or low part of the result, and adds a third value
along with carry-in. Writes the result to the destination register and optionally writes the
carry-out from the addition into the condition code register.
Semantics
t = a * b;
d = t<63..32> + c + CC.CF; // for .hi variant
d = t<31..0> + c + CC.CF; // for .lo variant
if .cc specified, carry-out from addition is written to CC.CF
Examples
// extended-precision multiply: [r3,r2,r1,r0] = [r5,r4] * [r7,r6]
mul.lo.u32 r0,r4,r6; // r0=(r4*r6).[31:0], no carry-out
mul.hi.u32 r1,r4,r6; // r1=(r4*r6).[63:32], no carry-out
mad.lo.cc.u32 r1,r5,r6,r1; // r1+=(r5*r6).[31:0], may carry-out
madc.hi.u32 r2,r5,r6,0; // r2 =(r5*r6).[63:32]+carry-in,
// no carry-out
mad.lo.cc.u32 r1,r4,r7,r1; // r1+=(r4*r7).[31:0], may carry-out
madc.hi.cc.u32 r2,r4,r7,r2; // r2+=(r4*r7).[63:32]+carry-in,
// may carry-out
addc.u32 r3,0,0; // r3 = carry-in, no carry-out
mad.lo.cc.u32 r2,r5,r7,r2; // r2+=(r5*r7).[31:0], may carry-out
madc.hi.u32 r3,r5,r7,r3; // r3+=(r5*r7).[63:32]+carry-in
Floating-point instructions operate on .f32 and .f64 register operands and constant
immediate values. The floating-point instructions are:
testp
copysign
add
sub
mul
fma
mad
div
abs
neg
min
max
rcp
sqrt
rsqrt
sin
cos
lg2
ex2
tanh
Instructions that support rounding modifiers are IEEE-754 compliant. Double-precision instructions
support subnormal inputs and results. Single-precision instructions support subnormal inputs and
results by default for sm_20 and subsequent targets, and flush subnormal inputs and results to
sign-preserving zero for sm_1x targets. The optional .ftz modifier on single-precision
instructions provides backward compatibility with sm_1x targets by flushing subnormal inputs and
results to sign-preserving zero regardless of the target architecture.
Single-precision add, sub, mul, and mad support saturation of results to the range
[0.0, 1.0], with NaNs being flushed to positive zero. NaN payloads are supported for
double-precision instructions (except for rcp.approx.ftz.f64 and rsqrt.approx.ftz.f64, which
maps input NaNs to a canonical NaN). Single-precision instructions return an unspecified
NaN. Note that future implementations may support NaN payloads for single-precision
instructions, so PTX programs should not rely on the specific single-precision NaNs being
generated.
Table 29 summarizes
floating-point instructions in PTX.
Table 29 Summary of Floating-Point Instructions
Instruction
.rn
.rz
.rm
.rp
.ftz
.sat
Notes
{add,sub,mul}.rnd.f32
x
x
x
x
x
x
If no rounding modifier is specified,
default is .rn and instructions may
be folded into a multiply-add.
{add,sub,mul}.rnd.f64
x
x
x
x
n/a
n/a
If no rounding modifier is specified,
default is .rn and instructions may
be folded into a multiply-add.
add{.rnd}{.ftz}{.sat}.f32 d, a, b;
add{.rnd}{.ftz}.f32x2 d, a, b;
add{.rnd}.f64 d, a, b;
.rnd = { .rn, .rz, .rm, .rp };
Description
Performs addition and writes the resulting value into a destination register.
For .f32x2 instruction type, forms input vectors of single precision (.f32) values from
source operands. Single precision (.f32) operands are then added in parallel to produce
.f32x2 result in destination.
For .f32x2 instruction type, operands d, a and b have .b64 type.
Semantics
if (type == f32 || type == f64) {
d = a + b;
} else if (type == f32x2) {
fA[0] = a[0:31];
fA[1] = a[32:63];
fB[0] = b[0:31];
fB[1] = b[32:63];
for (i = 0; i < 2; i++) {
d[i] = fA[i] + fB[i];
}
}
Examples
@p add.rz.ftz.f32 f1,f2,f3;
add.rp.ftz.f32x2 d, a, b;
sub{.rnd}{.ftz}{.sat}.f32 d, a, b;
sub{.rnd}{.ftz}.f32x2 d, a, b;
sub{.rnd}.f64 d, a, b;
.rnd = { .rn, .rz, .rm, .rp };
Description
Performs subtraction and writes the resulting value into a destination register.
For .f32x2 instruction type, forms input vectors of single precision (.f32) values
from source operands. Single precision (.f32) operands are then subtracted in parallel
to produce .f32x2 result in destination.
For .f32x2 instruction type, operands d, a and b have .b64 type.
Semantics
if (type == f32 || type == f64) {
d = a - b;
} else if (type == f32x2) {
fA[0] = a[0:31];
fA[1] = a[32:63];
fB[0] = b[0:31];
fB[1] = b[32:63];
for (i = 0; i < 2; i++) {
d[i] = fA[i] - fB[i];
}
}
mul{.rnd}{.ftz}{.sat}.f32 d, a, b;
mul{.rnd}{.ftz}.f32x2 d, a, b;
mul{.rnd}.f64 d, a, b;
.rnd = { .rn, .rz, .rm, .rp };
Description
Compute the product of two values.
For .f32x2 instruction type, forms input vectors of single precision (.f32) values
from source operands. Single precision (.f32) operands are then multiplied in parallel
to produce .f32x2 result in destination.
For .f32x2 instruction type, operands d, a and b have .b64 type.
Semantics
if (type == f32 || type == f64) {
d = a * b;
} else if (type == f32x2) {
fA[0] = a[0:31];
fA[1] = a[32:63];
fB[0] = b[0:31];
fB[1] = b[32:63];
for (i = 0; i < 2; i++) {
d[i] = fA[i] * fB[i];
}
}
Examples
mul.ftz.f32 circumf,radius,pi // a single-precision multiply
fma.rnd{.ftz}{.sat}.f32 d, a, b, c;
fma.rnd{.ftz}.f32x2 d, a, b, c;
fma.rnd.f64 d, a, b, c;
.rnd = { .rn, .rz, .rm, .rp };
Description
Performs a fused multiply-add with no loss of precision in the intermediate product and addition.
For .f32x2 instruction type, forms input vectors of single precision (.f32) values from
source operands. Single precision (.f32) operands are then operated in parallel to produce
.f32x2 result in destination.
For .f32x2 instruction type, operands d, a, b and c have .b64 type.
Semantics
if (type == f32 || type == f64) {
d = a * b + c;
} else if (type == f32x2) {
fA[0] = a[0:31];
fA[1] = a[32:63];
fB[0] = b[0:31];
fB[1] = b[32:63];
fC[0] = c[0:31];
fC[1] = c[32:63];
for (i = 0; i < 2; i++) {
d[i] = fA[i] * fB[i] + fC[i];
}
}
div.approx{.ftz}.f32 d, a, b; // fast, approximate divide
div.full{.ftz}.f32 d, a, b; // full-range approximate divide
div.rnd{.ftz}.f32 d, a, b; // IEEE 754 compliant rounding
div.rnd.f64 d, a, b; // IEEE 754 compliant rounding
.rnd = { .rn, .rz, .rm, .rp };
Description
Divides a by b, stores result in d.
Semantics
d = a / b;
Fast, approximate single-precision divides:
div.approx.f32 implements a fast approximation to divide, computed as d=a*(1/b). For
|b| in [2-126, 2126], the maximum ulp error is 2. For 2126 <
|b| < 2128, if a is infinity, div.approx.f32 returns NaN, otherwise it
returns a sign-preserving zero.
div.full.f32 implements a relatively fast, full-range approximation that scales operands to
achieve better accuracy, but is not fully IEEE 754 compliant and does not support rounding
modifiers. The maximum ulp error is 2 across the full range of inputs.
Divide with IEEE 754 compliant rounding:
Rounding modifiers (no default):
.rn
mantissa LSB rounds to nearest even
.rz
mantissa LSB rounds towards zero
.rm
mantissa LSB rounds towards negative infinity
.rp
mantissa LSB rounds towards positive infinity
Subnormal numbers:
sm_20+
By default, subnormal numbers are supported.
div.ftz.f32 flushes subnormal inputs and results to sign-preserving zero.
sm_1x
div.f64 supports subnormal numbers.
div.f32 flushes subnormal inputs and results to sign-preserving zero.
Examples
div.approx.ftz.f32 diam,circum,3.14159;
div.full.ftz.f32 x, y, z;
div.rn.f64 xd, yd, zd;
min{.ftz}{.NaN}{.xorsign.abs}.f32 d, a, b;
min{.ftz}{.NaN}{.abs}.f32 d, a, b, c;
min.f64 d, a, b;
Description
Store the minimum of a, b and optionally c in d.
If .NaN modifier is specified, then the result is canonical NaN if any of the inputs is
NaN.
If .abs modifier is specified, the magnitude of destination operand d is the minimum of
absolute values of both input arguments.
If .xorsign modifier is specified, the sign bit of destination d is equal to the XOR of the
sign bits of both inputs a and b. The .xorsign qualifier cannot be specified for three
inputs operation.
Qualifier .xorsign requires qualifier .abs to be specified. In such cases, .xorsign
considers the sign bit of both inputs before applying .abs operation.
If the result of min is NaN then the .xorsign and .abs modifiers will be ignored.
Semantics
def min_num (z, x, y) {
if (isNaN(x) && isNaN(y))
z = NaN;
else if (isNaN(x))
z = y;
else if (isNaN(y))
z = x;
else
// note: -0.0 < +0.0 here
z = (x < y) ? x : y;
return z;
}
def min_nan (z, x, y) {
if (isNaN(x) || isNaN(y))
z = NaN;
else
// note: -0.0 < +0.0 here
z = (x < y) ? x : y;
return z;
}
def two_inputs_min (z, x, y) {
if (.NaN)
z = min_nan(z, x, y);
else
z = min_num(z, x, y);
return z;
}
if (.xorsign && !isPresent(c)) {
xorsign = getSignBit(a) ^ getSignBit(b);
}
if (.abs) {
a = |a|;
b = |b|;
if (isPresent(c)) {
c = |c|;
}
}
d = two_inputs_min(d, a, b)
if (isPresent(c)) {
d = two_inputs_min(d, d, c)
}
if (.xorsign && !isPresent(c) && !isNaN(d)) {
setSignBit(d, xorsign);
}
Examples
@p min.ftz.f32 z,z,x;
min.f64 a,b,c;
// fp32 min with .NaN
min.NaN.f32 f0,f1,f2;
// fp32 min with .xorsign.abs
min.xorsign.abs.f32 Rd, Ra, Rb;
max{.ftz}{.NaN}{.xorsign.abs}.f32 d, a, b;
max{.ftz}{.NaN}{.abs}.f32 d, a, b, c;
max.f64 d, a, b;
Description
Store the maximum of a, b and optionally c in d.
If .NaN modifier is specified, the result is canonical NaN if any of the inputs is
NaN.
If .abs modifier is specified, the magnitude of destination operand d is the maximum of
absolute values of the input arguments.
If .xorsign modifier is specified, the sign bit of destination d is equal to the XOR of the
sign bits of the inputs: a and b. The .xorsign qualifier cannot be specified for three
inputs operation.
Qualifier .xorsign requires qualifier .abs to be specified. In such cases, .xorsign
considers the sign bit of both inputs before applying .abs operation.
If the result of max is NaN then the .xorsign and .abs modifiers will be ignored.
Semantics
def max_num (z, x, y) {
if (isNaN(x) && isNaN(y))
z = NaN;
else if (isNaN(x))
z = y;
else if (isNaN(y))
z = x;
else
// note: +0.0 > -0.0 here
z = (x > y) ? x : y;
return z;
}
def max_nan (z, x, y) {
if (isNaN(x) || isNaN(y))
z = NaN;
else
// note: +0.0 > -0.0 here
z = (x > y) ? x : y;
return z;
}
def two_inputs_max (z, x, y) {
if (.NaN)
z = max_nan(z, x, y);
else
z = max_num(z, x, y);
return z;
}
if (.xorsign && !isPresent(c)) {
xorsign = getSignBit(a) ^ getSignBit(b);
}
if (.abs) {
a = |a|;
b = |b|;
if (isPresent(c)) {
c = |c|;
}
}
d = two_inputs_max (d, a, b)
if (isPresent(c)) {
d = two_inputs_max (d, d, c)
}
if (.xorsign && !isPresent(c) !isNaN(d)) {
setSignBit(d, xorsign);
}
Examples
max.ftz.f32 f0,f1,f2;
max.f64 a,b,c;
// fp32 max with .NaN
max.NaN.f32 f0,f1,f2;
// fp32 max with .xorsign.abs
max.xorsign.abs.f32 Rd, Ra, Rb;
9.7.3.17. Floating Point Instructions: rsqrt.approx.ftz.f64#
rsqrt.approx.ftz.f64
Compute an approximation of the square root reciprocal of a value.
Syntax
rsqrt.approx.ftz.f64 d, a;
Description
Compute a double-precision (.f64) approximation of the square root reciprocal of a value. The
least significant 32 bits of the double-precision (.f64) destination d are all zeros.
Semantics
tmp = a[63:32]; // upper word of a, 1.11.20 format
d[63:32] = 1.0 / sqrt(tmp);
d[31:0] = 0x00000000;
Half precision floating-point instructions operate on .f16 and .f16x2 register operands. The
half precision floating-point instructions are:
add
sub
mul
fma
neg
abs
min
max
tanh
ex2
Half-precision add, sub, mul, and fma support saturation of results to the range
[0.0, 1.0], with NaNs being flushed to positive zero. Half-precision instructions return an
unspecified NaN.
9.7.4.1. Half Precision Floating Point Instructions: add#
add
Add two values.
Syntax
add{.rnd}{.ftz}{.sat}.f16 d, a, b;
add{.rnd}{.ftz}{.sat}.f16x2 d, a, b;
add{.rnd}.bf16 d, a, b;
add{.rnd}.bf16x2 d, a, b;
.rnd = { .rn };
Description
Performs addition and writes the resulting value into a destination register.
For .f16x2 and .bf16x2 instruction type, forms input vectors by half word values from source
operands. Half-word operands are then added in parallel to produce .f16x2 or .bf16x2 result
in destination.
For .f16 instruction type, operands d, a and b have .f16 or .b16 type. For
.f16x2 instruction type, operands d, a and b have .b32 type. For .bf16
instruction type, operands d, a, b have .b16 type. For .bf16x2 instruction type,
operands d, a, b have .b32 type.
Semantics
if (type == f16 || type == bf16) {
d = a + b;
} else if (type == f16x2 || type == bf16x2) {
fA[0] = a[0:15];
fA[1] = a[16:31];
fB[0] = b[0:15];
fB[1] = b[16:31];
for (i = 0; i < 2; i++) {
d[i] = fA[i] + fB[i];
}
}
// SIMD bf16 addition
cvt.rn.bf16x2.f32 p4, f4, f5; // Convert two f32 into packed bf16x2
cvt.rn.bf16x2.f32 p5, f6, f7; // Convert two f32 into packed bf16x2
add.bf16x2 p6, p4, p5; // SIMD bf16x2 addition
// SIMD fp16 addition
ld.global.b32 f0, [addr]; // load 32 bit which hold packed f16x2
ld.global.b32 f1, [addr + 4]; // load 32 bit which hold packed f16x2
add.f16x2 f2, f0, f1; // SIMD f16x2 addition
ld.global.b32 f3, [addr + 8]; // load 32 bit which hold packed bf16x2
ld.global.b32 f4, [addr + 12]; // load 32 bit which hold packed bf16x2
add.bf16x2 f5, f3, f4; // SIMD bf16x2 addition
9.7.4.2. Half Precision Floating Point Instructions: sub#
sub
Subtract two values.
Syntax
sub{.rnd}{.ftz}{.sat}.f16 d, a, b;
sub{.rnd}{.ftz}{.sat}.f16x2 d, a, b;
sub{.rnd}.bf16 d, a, b;
sub{.rnd}.bf16x2 d, a, b;
.rnd = { .rn };
Description
Performs subtraction and writes the resulting value into a destination register.
For .f16x2 and .bf16x2 instruction type, forms input vectors by half word values from source
operands. Half-word operands are then subtracted in parallel to produce .f16x2 or .bf16x2
result in destination.
For .f16 instruction type, operands d, a and b have .f16 or .b16 type. For
.f16x2 instruction type, operands d, a and b have .b32 type. For .bf16
instruction type, operands d, a, b have .b16 type. For .bf16x2 instruction type,
operands d, a, b have .b32 type.
Semantics
if (type == f16 || type == bf16) {
d = a - b;
} else if (type == f16x2 || type == bf16x2) {
fA[0] = a[0:15];
fA[1] = a[16:31];
fB[0] = b[0:15];
fB[1] = b[16:31];
for (i = 0; i < 2; i++) {
d[i] = fA[i] - fB[i];
}
}
// SIMD bf16 subtraction
cvt.rn.bf16x2.f32 p4, f4, f5; // Convert two f32 into packed bf16x2
cvt.rn.bf16x2.f32 p5, f6, f7; // Convert two f32 into packed bf16x2
sub.bf16x2 p6, p4, p5; // SIMD bf16x2 subtraction
// SIMD fp16 subtraction
ld.global.b32 f0, [addr]; // load 32 bit which hold packed f16x2
ld.global.b32 f1, [addr + 4]; // load 32 bit which hold packed f16x2
sub.f16x2 f2, f0, f1; // SIMD f16x2 subtraction
// SIMD bf16 subtraction
ld.global.b32 f3, [addr + 8]; // load 32 bit which hold packed bf16x2
ld.global.b32 f4, [addr + 12]; // load 32 bit which hold packed bf16x2
sub.bf16x2 f5, f3, f4; // SIMD bf16x2 subtraction
9.7.4.3. Half Precision Floating Point Instructions: mul#
mul
Multiply two values.
Syntax
mul{.rnd}{.ftz}{.sat}.f16 d, a, b;
mul{.rnd}{.ftz}{.sat}.f16x2 d, a, b;
mul{.rnd}.bf16 d, a, b;
mul{.rnd}.bf16x2 d, a, b;
.rnd = { .rn };
Description
Performs multiplication and writes the resulting value into a destination register.
For .f16x2 and .bf16x2 instruction type, forms input vectors by half word values from source
operands. Half-word operands are then multiplied in parallel to produce .f16x2 or .bf16x2
result in destination.
For .f16 instruction type, operands d, a and b have .f16 or .b16 type. For
.f16x2 instruction type, operands d, a and b have .b32 type. For .bf16
instruction type, operands d, a, b have .b16 type. For .bf16x2 instruction type,
operands d, a, b have .b32 type.
Semantics
if (type == f16 || type == bf16) {
d = a * b;
} else if (type == f16x2 || type == bf16x2) {
fA[0] = a[0:15];
fA[1] = a[16:31];
fB[0] = b[0:15];
fB[1] = b[16:31];
for (i = 0; i < 2; i++) {
d[i] = fA[i] * fB[i];
}
}
// SIMD bf16 multiplication
cvt.rn.bf16x2.f32 p4, f4, f5; // Convert two f32 into packed bf16x2
cvt.rn.bf16x2.f32 p5, f6, f7; // Convert two f32 into packed bf16x2
mul.bf16x2 p6, p4, p5; // SIMD bf16x2 multiplication
// SIMD fp16 multiplication
ld.global.b32 f0, [addr]; // load 32 bit which hold packed f16x2
ld.global.b32 f1, [addr + 4]; // load 32 bit which hold packed f16x2
mul.f16x2 f2, f0, f1; // SIMD f16x2 multiplication
// SIMD bf16 multiplication
ld.global.b32 f3, [addr + 8]; // load 32 bit which hold packed bf16x2
ld.global.b32 f4, [addr + 12]; // load 32 bit which hold packed bf16x2
mul.bf16x2 f5, f3, f4; // SIMD bf16x2 multiplication
9.7.4.4. Half Precision Floating Point Instructions: fma#
fma
Fused multiply-add
Syntax
fma.rnd{.ftz}{.sat}.f16 d, a, b, c;
fma.rnd{.ftz}{.sat}.f16x2 d, a, b, c;
fma.rnd{.ftz}.relu.f16 d, a, b, c;
fma.rnd{.ftz}.relu.f16x2 d, a, b, c;
fma.rnd{.relu}.bf16 d, a, b, c;
fma.rnd{.relu}.bf16x2 d, a, b, c;
fma.rnd.oob.{relu}.type d, a, b, c;
.rnd = { .rn };
Description
Performs a fused multiply-add with no loss of precision in the intermediate product and addition.
For .f16x2 and .bf16x2 instruction type, forms input vectors by half word values from source
operands. Half-word operands are then operated in parallel to produce .f16x2 or .bf16x2
result in destination.
For .f16 instruction type, operands d, a, b and c have .f16 or .b16
type. For .f16x2 instruction type, operands d, a, b and c have .b32
type. For .bf16 instruction type, operands d, a, b and c have .b16 type. For
.bf16x2 instruction type, operands d, a, b and c have .b32 type.
Semantics
if (type == f16 || type == bf16) {
d = a * b + c;
} else if (type == f16x2 || type == bf16x2) {
fA[0] = a[0:15];
fA[1] = a[16:31];
fB[0] = b[0:15];
fB[1] = b[16:31];
fC[0] = c[0:15];
fC[1] = c[16:31];
for (i = 0; i < 2; i++) {
d[i] = fA[i] * fB[i] + fC[i];
}
}
For .f16x2 and .bf16x2 instruction type, forms input vector by extracting half word values
from the source operand. Half-word operands are then negated in parallel to produce .f16x2 or
.bf16x2 result in destination.
For .f16 instruction type, operands d and a have .f16 or .b16 type. For
.f16x2 instruction type, operands d and a have .b32 type. For .bf16 instruction
type, operands d and a have .b16 type. For .bf16x2 instruction type, operands d
and a have .b32 type.
Semantics
if (type == f16 || type == bf16) {
d = -a;
} else if (type == f16x2 || type == bf16x2) {
fA[0] = a[0:15];
fA[1] = a[16:31];
for (i = 0; i < 2; i++) {
d[i] = -fA[i];
}
}
Take absolute value of a and store the result in d.
For .f16x2 and .bf16x2 instruction type, forms input vector by extracting half word values
from the source operand. Absolute values of half-word operands are then computed in parallel to
produce .f16x2 or .bf16x2 result in destination.
For .f16 instruction type, operands d and a have .f16 or .b16 type. For
.f16x2 instruction type, operands d and a have .f16x2 or .b32 type. For
.bf16 instruction type, operands d and a have .b16 type. For .bf16x2 instruction
type, operands d and a have .b32 type.
Semantics
if (type == f16 || type == bf16) {
d = |a|;
} else if (type == f16x2 || type == bf16x2) {
fA[0] = a[0:15];
fA[1] = a[16:31];
for (i = 0; i < 2; i++) {
d[i] = |fA[i]|;
}
}
9.7.4.7. Half Precision Floating Point Instructions: min#
min
Find the minimum of two values.
Syntax
min{.ftz}{.NaN}{.xorsign.abs}.f16 d, a, b;
min{.ftz}{.NaN}{.xorsign.abs}.f16x2 d, a, b;
min{.NaN}{.xorsign.abs}.bf16 d, a, b;
min{.NaN}{.xorsign.abs}.bf16x2 d, a, b;
Description
Store the minimum of a and b in d.
For .f16x2 and .bf16x2 instruction types, input vectors are formed with half-word values
from source operands. Half-word operands are then processed in parallel to store .f16x2 or
.bf16x2 result in destination.
For .f16 instruction type, operands d and a have .f16 or .b16 type. For
.f16x2 instruction type, operands d and a have .f16x2 or .b32 type. For
.bf16 instruction type, operands d and a have .b16 type. For .bf16x2 instruction
type, operands d and a have .b32 type.
If .NaN modifier is specified, then the result is canonical NaN if either of the inputs is
NaN.
If .abs modifier is specified, the magnitude of destination operand d is the minimum of
absolute values of both the input arguments.
If .xorsign modifier is specified, the sign bit of destination d is equal to the XOR of the
sign bits of both the inputs.
Modifiers .abs and .xorsign must be specified together and .xorsign considers the sign
bit of both inputs before applying .abs operation.
If the result of min is NaN then the .xorsign and .abs modifiers will be ignored.
Semantics
if (type == f16 || type == bf16) {
if (.xorsign) {
xorsign = getSignBit(a) ^ getSignBit(b);
if (.abs) {
a = |a|;
b = |b|;
}
}
if (isNaN(a) && isNaN(b)) d = NaN;
if (.NaN && (isNaN(a) || isNaN(b))) d = NaN;
else if (isNaN(a)) d = b;
else if (isNaN(b)) d = a;
else d = (a < b) ? a : b;
if (.xorsign && !isNaN(d)) {
setSignBit(d, xorsign);
}
} else if (type == f16x2 || type == bf16x2) {
fA[0] = a[0:15];
fA[1] = a[16:31];
fB[0] = b[0:15];
fB[1] = b[16:31];
for (i = 0; i < 2; i++) {
if (.xorsign) {
xorsign = getSignBit(fA[i]) ^ getSignBit(fB[i]);
if (.abs) {
fA[i] = |fA[i]|;
fB[i] = |fB[i]|;
}
}
if (isNaN(fA[i]) && isNaN(fB[i])) d[i] = NaN;
if (.NaN && (isNaN(fA[i]) || isNaN(fB[i]))) d[i] = NaN;
else if (isNaN(fA[i])) d[i] = fB[i];
else if (isNaN(fB[i])) d[i] = fA[i];
else d[i] = (fA[i] < fB[i]) ? fA[i] : fB[i];
if (.xorsign && !isNaN(d[i])) {
setSignBit(d[i], xorsign);
}
}
}
Examples
min.ftz.f16 h0,h1,h2;
min.f16x2 b0,b1,b2;
// SIMD fp16 min with .NaN
min.NaN.f16x2 b0,b1,b2;
min.bf16 h0, h1, h2;
// SIMD bf16 min with NaN
min.NaN.bf16x2 b0, b1, b2;
// scalar bf16 min with xorsign.abs
min.xorsign.abs.bf16 Rd, Ra, Rb
9.7.4.8. Half Precision Floating Point Instructions: max#
max
Find the maximum of two values.
Syntax
max{.ftz}{.NaN}{.xorsign.abs}.f16 d, a, b;
max{.ftz}{.NaN}{.xorsign.abs}.f16x2 d, a, b;
max{.NaN}{.xorsign.abs}.bf16 d, a, b;
max{.NaN}{.xorsign.abs}.bf16x2 d, a, b;
Description
Store the maximum of a and b in d.
For .f16x2 and .bf16x2 instruction types, input vectors are formed with half-word values
from source operands. Half-word operands are then processed in parallel to store .f16x2 or
.bf16x2 result in destination.
For .f16 instruction type, operands d and a have .f16 or .b16 type. For
.f16x2 instruction type, operands d and a have .f16x2 or .b32 type. For
.bf16 instruction type, operands d and a have .b16 type. For .bf16x2 instruction
type, operands d and a have .b32 type.
If .NaN modifier is specified, the result is canonical NaN if either of the inputs is
NaN.
If .abs modifier is specified, the magnitude of destination operand d is the maximum of
absolute values of both the input arguments.
If .xorsign modifier is specified, the sign bit of destination d is equal to the XOR of the
sign bits of both the inputs.
Modifiers .abs and .xorsign must be specified together and .xorsign considers the sign
bit of both inputs before applying .abs operation.
If the result of max is NaN then the .xorsign and .abs modifiers will be ignored.
Semantics
if (type == f16 || type == bf16) {
if (.xorsign) {
xorsign = getSignBit(a) ^ getSignBit(b);
if (.abs) {
a = |a|;
b = |b|;
}
}
if (isNaN(a) && isNaN(b)) d = NaN;
if (.NaN && (isNaN(a) || isNaN(b))) d = NaN;
else if (isNaN(a)) d = b;
else if (isNaN(b)) d = a;
else d = (a > b) ? a : b;
if (.xorsign && !isNaN(d)) {
setSignBit(d, xorsign);
}
} else if (type == f16x2 || type == bf16x2) {
fA[0] = a[0:15];
fA[1] = a[16:31];
fB[0] = b[0:15];
fB[1] = b[16:31];
for (i = 0; i < 2; i++) {
if (.xorsign) {
xorsign = getSignBit(fA[i]) ^ getSignBit(fB[i]);
if (.abs) {
fA[i] = |fA[i]|;
fB[i] = |fB[i]|;
}
}
if (isNaN(fA[i]) && isNaN(fB[i])) d[i] = NaN;
if (.NaN && (isNaN(fA[i]) || isNaN(fB[i]))) d[i] = NaN;
else if (isNaN(fA[i])) d[i] = fB[i];
else if (isNaN(fB[i])) d[i] = fA[i];
else d[i] = (fA[i] > fB[i]) ? fA[i] : fB[i];
if (.xorsign && !isNaN(fA[i])) {
setSignBit(d[i], xorsign);
}
}
}
Examples
max.ftz.f16 h0,h1,h2;
max.f16x2 b0,b1,b2;
// SIMD fp16 max with NaN
max.NaN.f16x2 b0,b1,b2;
// scalar f16 max with xorsign.abs
max.xorsign.abs.f16 Rd, Ra, Rb;
max.bf16 h0, h1, h2;
// scalar bf16 max and NaN
max.NaN.bf16x2 b0, b1, b2;
// SIMD bf16 max with xorsign.abs
max.xorsign.abs.bf16x2 Rd, Ra, Rb;
9.7.4.9. Half Precision Floating Point Instructions: tanh#
tanh
Find the hyperbolic tangent of a value (in radians)
Syntax
tanh.approx.type d, a;
.type = {.f16, .f16x2, .bf16, .bf16x2}
Description
Take hyperbolic tangent value of a.
The type of operands d and a are as specified by .type.
For .f16x2 or .bf16x2 instruction type, each of the half-word operands are operated in
parallel and the results are packed appropriately into a .f16x2 or .bf16x2.
For .f16 instruction type, operands d and a have .f16 or .b16 type.
For .f16x2 instruction type, operands d and a have .f16x2 or .b32 type.
For .bf16 instruction type, operands d and a have .b16 type.
For .bf16x2 instruction type, operands d and a have .b32 type.
The type of operands d and a are as specified by .type.
For .f16x2 or .bf16x2 instruction type, each of the half-word operands are operated in
parallel and the results are packed appropriately into a .f16x2 or .bf16x2.
For .f16 instruction type, operands d and a have .f16 or .b16 type.
For .f16x2 instruction type, operands d and a have .f16x2 or .b32 type.
For .bf16 instruction type, operands d and a have .b16 type.
For .bf16x2 instruction type, operands d and a have .b32 type.
Mixed precision floating-point instructions operate on data with varied floating point precision.
Before executing the specified operation, operands with different precision needs to be converted
such that all the instruction operands can be represented with a consistent floating-point precision.
The register variable to be used for holding a particular operand depends upon the combination of
the instruction types. Refer Fundamental Types and
Alternate Floating-Point Data Formats for more details
around exact register operand to be used for a given data type.
The mixed precision floating point instructions are:
add
sub
fma
mul
Mixed precision add, sub, fma support saturation of results to the range [0.0, 1.0],
with NaN being flushed to positive zero.
9.7.5.1. Mixed Precision Floating Point Instructions: add#
add
Add 2 values.
Syntax
add{.rnd}{.sat}.cdtype.atype d, a, c;
add{.rnd}.dtype2.atype2.ctype2 d, a, c;
add.rz.ftz.dtype3.atype3.ctype2 d, a, c;
add.rz.dtype4.atype3.ctype2 d, a, c;
9.7.5.2. Mixed Precision Floating Point Instructions: sub#
sub
Subtract one value from another.
Syntax
sub{.rnd}{.sat}.cdtype.atype d, a, c;
sub{.rnd}.dtype2.atype2.ctype2 d, a, c;
sub.rz.ftz.dtype3.atype3.ctype2 d, a, c;
sub.rz.dtype4.atype3.ctype2 d, a, c;
Converts input operands a, b and c to .cdtype/.dtype type. The converted values
are then used to perform fused multiply-add operation with no loss of precision in the intermediate
product and addition. The resulting value is stored in the destination operand d.
Alternate floating-point instructions operate on FP8, FP6, FP4 data types. The register variable
to be used for such instruction varies depending upon the data type. Refer
Packed Floating Point Data Types for details on the supported data types and their
register representations.
The alternate floating-point instructions are:
add
sub
mul
fma
9.7.6.1. Alternate Floating Point Instructions: add#
Performs addition and writes the resulting value into a destination register.
First forms input vectors by extracting four values of the specified type from packed source
operands. These extracted input vectors are then added in parallel with an infinite precision.
The resulting values are then rounded to the destination type using the rounding mode
specified by .rnd.
Operands d and c must be of type .b32. When .atype is .e2m1x4, operand
a must be of type .b16; otherwise operand a must be of type .b32.
// f8x4 addition
mov.b32 ra, {ba0, ba1, ba2, ba3}; // pack four f8 as f8x4
mov.b32 rc, {bc0, bc1, bc2, bc3}; // pack four f8 as f8x4
add.rn.e5m2x4.e4m3x4.satfinite rd, ra, rc; // SIMD addition
// f4x4 and f8x4 addition
.reg .b16 ra16;
mov.b16 ra16, {ba0, ba1}; // pack four f4 as f4x4 in b16 operand
mov.b32 rc, {bc0, bc1, bc2, bc3}; // pack four f8 as f8x4
add.rn.e4m3x4.e2m1x4 rd, ra16, rc; // SIMD addition
// f4x4 (padded) and f8x4 addition
mov.b32 ra, {ba0, ba1, ba2, ba3}; // pack four f4 as f4x4 in b32. Each f4 resides within lower half of a byte
mov.b32 rc, {bc0, bc1, bc2, bc3}; // pack four f8 as f8x4
add.rn.e4m3x4.e2m1p4x4 rd, ra, rc;
9.7.6.2. Alternate Floating Point Instructions: sub#
Performs subtraction and writes the resulting value into a destination register.
First forms input vectors by extracting four values of the specified type from packed source
operands. These extracted input vectors are then subtracted in parallel with an infinite
precision. The resulting value is then rounded to the destination type using the rounding
mode specified by .rnd.
Operands d and c must be of type .b32. When .atype is .e2m1x4, operand
a must be of type .b16; otherwise operand a must be of type .b32.
Performs multiplication and writes the resulting value into a destination register.
First forms input vectors by extracting four values of the specified type from packed source
operands. These extracted input vectors are then multiplied in parallel with an infinite
precision. The resulting values are then rounded to the destination type using the rounding
mode specified by .rnd.
Operand d must be of type .b32. When .atype is .e2m1x4, operand a must
be of type .b16; otherwise operand a must be of type .b32. Similarly, if
.ctype is .e2m1x4, operand c must be of type .b16; otherwise it must be of
type .b32.
Performs a fused multiply-add with no loss of precision in the intermediate product and
addition.
First forms input vectors by extracting four values of the specified type from packed
source operands. These extracted input vectors are then operated in parallel with an infinite
precision. The resulting values are then rounded to the destination type using the rounding
mode specified by .rnd.
Operands d and c must be of type .b32. When .atype is .e2m1x4, operand
a must be of type .b16; otherwise operand a must be of type .b32. Similarly,
if .btype is .e2m1x4, operand b must be of type .b16; otherwise it must be of
type .b32.
for (i = 0; i < 4; i++) {
d[i] = iA[i] * iB[i] + iC[i];
}
Examples
.reg .b32 rd, ra, rb, rc;
// multiply ue8m0x4 with f4x4 and add f8x4
mov.b32 ra, {ba0, ba1, ba2, ba3}; // pack four ue8m0
mov.b32 rb, {bb0, bb1, ba2, ba3}; // pack four f4 as f4x4 in b32 operand. Each f4 resides within lower half of a byte.
mov.b32 rc, {ba0, ba1, ba2, ba3}; // pack four f8 as f8x4
fma.rn.e5m2x4.ue8m0x4.e2m1p4x4.satfinite rd, ra, rb, rc;
// multiply f6x4 with f4x4 and add f8x4
mov.b32 ra, {ba0, ba1, ba2, ba3}; // pack four f6 as f6x4
.reg .b16 rb16;
mov.b16 rb16, {bb0, bb1}; // pack four f4 as f4x4 in .b16 operand
mov.b32 rc, {ba0, ba1, ba2, ba3}; // pack four f8 as f8x4
fma.rn.e4m3x4.e3m2x4.e2m1x4.satfinite rd, ra, rb16, rc; // SIMD fused-multiply-add
// multiply ue8m0x4 with f8x4 and add f8x4
mov.b32 ra, {ba0, ba1, ba2, ba3}; // pack four ue8m0 values
mov.b32 rb, {bb0, bb1, bb2, bb3}; // pack four f8 as f8x4
mov.b32 rc, {ba0, ba1, ba2, ba3}; // pack four f8 as f8x4
fma.rn.e4m3x4.ue8m0x4.e5m2x4 rd, ra, rb, rc; // SIMD fused-multiply-add
As with single-precision floating-point instructions, the set, setp, and slct
instructions support subnormal numbers for sm_20 and higher targets and flush single-precision
subnormal inputs to sign-preserving zero for sm_1x targets. The optional .ftz modifier
provides backward compatibility with sm_1x targets by flushing subnormal inputs and results to
sign-preserving zero regardless of the target architecture.
9.7.7.1. Comparison and Selection Instructions: set#
set
Compare two numeric values with a relational operator, and optionally combine this result with a
predicate value by applying a Boolean operator.
Syntax
set.CmpOp{.ftz}.dtype.stype d, a, b;
set.CmpOp.BoolOp{.ftz}.dtype.stype d, a, b, {!}c;
Compares two numeric values and optionally combines the result with another predicate value by
applying a Boolean operator. If this result is True, 1.0f is written for floating-point
destination types, and 0xffffffff is written for integer destination types. Otherwise,
0x00000000 is written.
For .u16x2, .s16x2 instruction types, forms input vectors by half word values
from source operands. Half-word operands are then compared in parallel. If the result
is True, 0xffff is written to the destination register at a bit-position
corresponding to input half word values. Otherwise, 0x0000 is written. In this
case, all operands must be of type .b32.
For .u8x4, .s8x4 instruction types, forms input vectors by quarter word values
from source operands. Quarter-word operands are then compared in parallel. If the
result is True, 0xff is written to the destination register at a bit-position
corresponding to input quarter word values. Otherwise, 0x00 is written. In this
case, all operands must be of type .b32.
Operand d has type .dtype; operands a and b have type .stype; operand c has
type .pred.
Semantics
if (type == u16x2 || type == s16x2) {
iA[0] = a[0:15];
iA[1] = a[16:31];
iB[0] = b[0:15];
iB[1] = b[16:31];
for (i = 0; i < 2; i++) {
d[i] = (iA[i] CmpOp iB[i]) ? 0xffff : 0x0000;
}
} else if (type == u8x4 || type == s8x4) {
iA[0] = a[0:7];
iA[1] = a[8:15];
iA[2] = a[16:23];
iA[3] = a[24:31];
iB[0] = b[0:7];
iB[1] = b[8:15];
iB[2] = b[16:23];
iB[3] = b[24:31];
for (i = 0; i < 4; i++) {
d[i] = (iA[i] CmpOp iB[i]) ? 0xff : 0x00;
}
} else {
t = (a CmpOp b) ? 1 : 0;
if (isFloat(dtype))
d = BoolOp(t, c) ? 1.0f : 0x00000000;
else
d = BoolOp(t, c) ? 0xffffffff : 0x00000000;
}
Compares two values and combines the result with another predicate value by applying a Boolean
operator. This result is written to the first destination operand. A related value computed using
the complement of the compare result is written to the second destination operand.
Applies to all numeric types. Operands a and b have type .type; operands p, q,
and c have type .pred. The sink symbol ‘_’ may be used in place of any one of the
destination operands.
Semantics
t = (a CmpOp b) ? 1 : 0;
p = BoolOp(t, c);
q = BoolOp(!t, c);
Examples
setp.lt.and.s32 p|q,a,b,r;
@q setp.eq.u32 p,i,n;
9.7.7.3. Comparison and Selection Instructions: selp#
selp
Select between source operands, based on the value of the predicate source operand.
Conditional selection. If c >= 0, a is stored in d, otherwise b is stored in
d. Operands d, a, and b are treated as a bitsize type of the same width as the first
instruction type; operand c must match the second instruction type (.s32 or .f32). The
selected input is copied to the output without modification.
Semantics
d = (c >= 0) ? a : b;
Examples
slct.u32.s32 x, y, z, val;
slct.ftz.u64.f32 A, B, C, fval;
Compares two values and combines the result with another predicate value by applying a Boolean
operator. This result is written to the destination operand.
Operand c, p and q has type .pred.
For instruction type .f16, operands a and b have type .b16 or .f16.
For instruction type .f16x2, operands a and b have type .b32.
For instruction type .bf16, operands a and b have type .b16.
For instruction type .bf16x2, operands a and b have type .b32.
Semantics
if (type == .f16 || type == .bf16) {
t = (a CmpOp b) ? 1 : 0;
p = BoolOp(t, c);
} else if (type == .f16x2 || type == .bf16x2) {
fA[0] = a[0:15];
fA[1] = a[16:31];
fB[0] = b[0:15];
fB[1] = b[16:31];
t[0] = (fA[0] CmpOp fB[0]) ? 1 : 0;
t[1] = (fA[1] CmpOp fB[1]) ? 1 : 0;
p = BoolOp(t[0], c);
q = BoolOp(t[1], c);
}
The logic and shift instructions are fundamentally untyped, performing bit-wise operations on
operands of any type, provided the operands are of the same size. This permits bit-wise operations
on floating point values without having to define a union to access the bits. Instructions and,
or, xor, and not also operate on predicates.
lop3.b32 d, a, b, c, immLut;
lop3.BoolOp.b32 d|p, a, b, c, immLut, q;
.BoolOp = { .or , .and };
Description
Compute bitwise logical operation on inputs a, b, c and store the result in destination
d.
Optionally, .BoolOp can be specified to compute the predicate result p by performing a
Boolean operation on the destination operand d with the predicate q in the following manner:
p = (d != 0) BoolOp q;
The sink symbol ‘_’ may be used in place of the destination operand d when .BoolOp qualifier
is specified.
The logical operation is defined by a look-up table which, for 3 inputs, can be represented as an
8-bit value specified by operand immLut as described below. immLut is an integer constant
that can take values from 0 to 255, thereby allowing up to 256 distinct logical operations on inputs
a, b, c.
For a logical operation F(a,b,c) the value of immLut can be computed by applying the same
operation to three predefined constant values as follows:
ta = 0xF0;
tb = 0xCC;
tc = 0xAA;
immLut = F(ta, tb, tc);
Examples:
If F = (a & b & c);
immLut = 0xF0 & 0xCC & 0xAA = 0x80
If F = (a | b | c);
immLut = 0xF0 | 0xCC | 0xAA = 0xFE
If F = (a & b & ~c);
immLut = 0xF0 & 0xCC & (~0xAA) = 0x40
If F = ((a & b | c) ^ a);
immLut = (0xF0 & 0xCC | 0xAA) ^ 0xF0 = 0x1A
The following table illustrates computation of immLut for various logical operations:
ta
tb
tc
Oper 0 (False)
Oper 1 (ta & tb & tc)
Oper 2 (ta & tb & ~tc)
…
Oper 254 (ta | tb | tc)
Oper 255 (True)
0
0
0
0
0
0
…
0
1
0
0
1
0
0
0
1
1
0
1
0
0
0
0
1
1
0
1
1
0
0
0
1
1
1
0
0
0
0
0
1
1
1
0
1
0
0
0
1
1
1
1
0
0
0
1
1
1
1
1
1
0
1
0
1
1
immLut
0x0
0x80
0x40
…
0xFE
0xFF
Semantics
F = GetFunctionFromTable(immLut); // returns the function corresponding to immLut value
d = F(a, b, c);
if (BoolOp specified) {
p = (d != 0) BoolOp q;
}
Examples
lop3.b32 d, a, b, c, 0x40;
lop3.or.b32 d|p, a, b, c, 0x3f, q;
lop3.and.b32 _|p, a, b, c, 0x3f, q;
shf.l.mode.b32 d, a, b, c; // left shift
shf.r.mode.b32 d, a, b, c; // right shift
.mode = { .clamp, .wrap };
Description
Shift the 64-bit value formed by concatenating operands a and b left or right by the amount
specified by the unsigned 32-bit value in c. Operand b holds bits 63:32 and operand a
holds bits 31:0 of the 64-bit source value. The source is shifted left or right by the clamped
or wrapped value in c. For shf.l, the most-significant 32-bits of the result are written
into d; for shf.r, the least-significant 32-bits of the result are written into d.
Semantics
u32 n = (.mode == .clamp) ? min(c, 32) : c & 0x1f;
switch (shf.dir) { // shift concatenation of [b, a]
case shf.l: // extract 32 msbs
u32 d = (b << n) | (a >> (32-n));
case shf.r: // extract 32 lsbs
u32 d = (b << (32-n)) | (a >> n);
}
Example
shf.l.clamp.b32 r3,r1,r0,16;
// 128-bit left shift; n < 32
// [r7,r6,r5,r4] = [r3,r2,r1,r0] << n
shf.l.clamp.b32 r7,r2,r3,n;
shf.l.clamp.b32 r6,r1,r2,n;
shf.l.clamp.b32 r5,r0,r1,n;
shl.b32 r4,r0,n;
// 128-bit right shift, arithmetic; n < 32
// [r7,r6,r5,r4] = [r3,r2,r1,r0] >> n
shf.r.clamp.b32 r4,r0,r1,n;
shf.r.clamp.b32 r5,r1,r2,n;
shf.r.clamp.b32 r6,r2,r3,n;
shr.s32 r7,r3,n; // result is sign-extended
shf.r.clamp.b32 r1,r0,r0,n; // rotate right by n; n < 32
shf.l.clamp.b32 r1,r0,r0,n; // rotate left by n; n < 32
// extract 32-bits from [r1,r0] starting at position n < 32
shf.r.clamp.b32 r0,r0,r1,n;
Shift a right by the amount specified by unsigned 32-bit value in b. Signed shifts fill with
the sign bit, unsigned and untyped shifts fill with 0.
Semantics
d = a >> b;
Example
shr.u16 c,a,2;
shr.s32 i,i,1;
shr.b16 k,i,j;
9.7.10. Data Movement and Conversion Instructions#
These instructions copy data from place to place, and from state space to state space, possibly
converting it from one format to another. mov, ld, ldu, and st operate on both
scalar and vector types. The isspacep instruction is provided to query whether a generic address
falls within a particular state space window. The cvta instruction converts addresses between
generic and const, global, local, or shared state spaces.
Instructions ld, st, suld, and sust support optional cache operations.
The Data Movement and Conversion Instructions are:
PTX ISA version 2.0 introduced optional cache operators on load and store instructions. The cache
operators require a target architecture of sm_20 or higher.
Cache operators on load or store instructions are treated as performance hints only. The use of a
cache operator on an ld or st instruction does not change the memory consistency behavior of
the program.
For sm_20 and higher, the cache operators have the following definitions and behavior.
Table 30 Cache Operators for Memory Load Instructions
Operator
Meaning
.ca
Cache at all levels, likely to be accessed again.
The default load instruction cache operation is ld.ca, which allocates cache lines in all
levels (L1 and L2) with normal eviction policy. Global data is coherent at the L2 level, but
multiple L1 caches are not coherent for global data. If one thread stores to global memory
via one L1 cache, and a second thread loads that address via a second L1 cache with ld.ca,
the second thread may get stale L1 cache data, rather than the data stored by the first thread.
The driver must invalidate global L1 cache lines between dependent grids of parallel threads.
Stores by the first grid program are then correctly fetched by the second grid program issuing
default ld.ca loads cached in L1.
.cg
Cache at global level (cache in L2 and below, not L1).
Use ld.cg to cache loads only globally, bypassing the L1 cache, and cache only in the L2
cache.
.cs
Cache streaming, likely to be accessed once.
The ld.cs load cached streaming operation allocates global lines with evict-first policy in
L1 and L2 to limit cache pollution by temporary streaming data that may be accessed once or
twice. When ld.cs is applied to a Local window address, it performs the ld.lu
operation.
.lu
Last use.
The compiler/programmer may use ld.lu when restoring spilled registers and popping function
stack frames to avoid needless write-backs of lines that will not be used again. The ld.lu
instruction performs a load cached streaming operation (ld.cs) on global addresses.
.cv
Don’t cache and fetch again (consider cached system memory lines stale, fetch again).
The ld.cv load operation applied to a global System Memory address invalidates (discards) a
matching L2 line and re-fetches the line on each new load.
Table 31 Cache Operators for Memory Store Instructions
Operator
Meaning
.wb
Cache write-back all coherent levels.
The default store instruction cache operation is st.wb, which writes back cache lines of
coherent cache levels with normal eviction policy.
If one thread stores to global memory, bypassing its L1 cache, and a second thread in a
different SM later loads from that address via a different L1 cache with ld.ca, the second
thread may get a hit on stale L1 cache data, rather than get the data from L2 or memory stored
by the first thread.
The driver must invalidate global L1 cache lines between dependent grids of thread arrays.
Stores by the first grid program are then correctly missed in L1 and fetched by the second grid
program issuing default ld.ca loads.
.cg
Cache at global level (cache in L2 and below, not L1).
Use st.cg to cache global store data only globally, bypassing the L1 cache, and cache only
in the L2 cache.
.cs
Cache streaming, likely to be accessed once.
The st.cs store cached-streaming operation allocates cache lines with evict-first policy to
limit cache pollution by streaming output data.
.wt
Cache write-through (to system memory).
The st.wt store write-through operation applied to a global System Memory address writes
through the L2 cache.
PTX ISA version 7.4 adds optional cache eviction priority hints on load and store
instructions. Cache eviction priority requires target architecture sm_70 or higher.
Cache eviction priority on load or store instructions is treated as a performance hint. It is
supported for .global state space and generic addresses where the address points to .global
state space.
Table 32 Cache Eviction Priority Hints for Memory Load and Store Instructions
Cache Eviction Priority
Meaning
evict_normal
Cache data with normal eviction priority. This is the default eviction priority.
evict_first
Data cached with this priority will be first in the eviction priority order and
will likely be evicted when cache eviction is required. This priority is suitable
for streaming data.
evict_last
Data cached with this priority will be last in the eviction priority order and will
likely be evicted only after other data with evict_normal or evict_first
eviction priority is already evicted. This priority is suitable for data that
should remain persistent in cache.
evict_unchanged
Do not change eviction priority order as part of this operation.
no_allocate
Do not allocate data to cache. This priority is suitable for streaming data.
9.7.10.3. Data Movement and Conversion Instructions: mov#
mov
Set a register variable with the value of a register variable or an immediate value. Take the
non-generic address of a variable in global, local, or shared state space.
Syntax
mov.type d, a;
mov.type d, sreg;
mov.type d, avar; // get address of variable
mov.type d, avar+imm; // get address of variable with offset
mov.u32 d, fname; // get address of device function
mov.u64 d, fname; // get address of device function
mov.u32 d, kernel; // get address of entry function
mov.u64 d, kernel; // get address of entry function
Operand a may be a register, special register, variable with optional offset in an addressable
memory space, or function name.
For variables declared in .const, .global, .local, and .shared state spaces, mov
places the non-generic address of the variable (i.e., the address of the variable in its state
space) into the destination register. The generic address of a variable in const, global,
local, or shared state space may be generated by first taking the address within the state
space with mov and then converting it to a generic address using the cvta instruction;
alternately, the generic address of a variable declared in const, global, local, or
shared state space may be taken directly using the cvta instruction.
Note that if the address of a device function parameter is moved to a register, the parameter will
be copied onto the stack and the address will be in the local state space.
Semantics
d = a;
d = sreg;
d = &avar; // address is non-generic; i.e., within the variable's declared state space
d = &avar+imm;
Examples
mov.f32 d,a;
mov.u16 u,v;
mov.f32 k,0.1;
mov.u32 ptr, A; // move address of A into ptr
mov.u32 ptr, A[5]; // move address of A[5] into ptr
mov.u32 ptr, A+20; // move address with offset into ptr
mov.u32 addr, myFunc; // get address of device function 'myFunc'
mov.u64 kptr, main; // get address of entry function 'main'
9.7.10.4. Data Movement and Conversion Instructions: mov#
mov
Move vector-to-scalar (pack) or scalar-to-vector (unpack).
Syntax
mov.type d, a;
.type = { .b16, .b32, .b64, .b128 };
Description
Write scalar register d with the packed value of vector register a, or write vector register
d with the unpacked values from scalar register a.
When destination operand d is a vector register, the sink symbol '_' may be used for one or
more elements provided that at least one element is a scalar register.
For bit-size types, mov may be used to pack vector elements into a scalar register or unpack
sub-fields of a scalar register into a vector. Both the overall size of the vector and the size of
the scalar must match the size of the instruction type.
Semantics
// pack two 8-bit elements into .b16
d = a.x | (a.y << 8)
// pack four 8-bit elements into .b32
d = a.x | (a.y << 8) | (a.z << 16) | (a.w << 24)
// pack two 16-bit elements into .b32
d = a.x | (a.y << 16)
// pack four 16-bit elements into .b64
d = a.x | (a.y << 16) | (a.z << 32) | (a.w << 48)
// pack two 32-bit elements into .b64
d = a.x | (a.y << 32)
// pack four 32-bit elements into .b128
d = a.x | (a.y << 32) | (a.z << 64) | (a.w << 96)
// pack two 64-bit elements into .b128
d = a.x | (a.y << 64)
// unpack 8-bit elements from .b16
{ d.x, d.y } = { a[0..7], a[8..15] }
// unpack 8-bit elements from .b32
{ d.x, d.y, d.z, d.w }
{ a[0..7], a[8..15], a[16..23], a[24..31] }
// unpack 16-bit elements from .b32
{ d.x, d.y } = { a[0..15], a[16..31] }
// unpack 16-bit elements from .b64
{ d.x, d.y, d.z, d.w } =
{ a[0..15], a[16..31], a[32..47], a[48..63] }
// unpack 32-bit elements from .b64
{ d.x, d.y } = { a[0..31], a[32..63] }
// unpack 32-bit elements from .b128
{ d.x, d.y, d.z, d.w } =
{ a[0..31], a[32..63], a[64..95], a[96..127] }
// unpack 64-bit elements from .b128
{ d.x, d.y } = { a[0..63], a[64..127] }
Examples
mov.b32 %r1,{a,b}; // a,b have type .u16
mov.b64 {lo,hi}, %x; // %x is a double; lo,hi are .u32
mov.b32 %r1,{x,y,z,w}; // x,y,z,w have type .b8
mov.b32 {r,g,b,a},%r1; // r,g,b,a have type .u8
mov.b64 {%r1, _}, %x; // %x is.b64, %r1 is .b32
mov.b128 {%b1, %b2}, %y; // %y is.b128, %b1 and % b2 are .b64
mov.b128 %y, {%b1, %b2}; // %y is.b128, %b1 and % b2 are .b64
9.7.10.5. Data Movement and Conversion Instructions: shfl (deprecated)#
shfl (deprecated)
Register data shuffle within threads of a warp.
Syntax
shfl.mode.b32 d[|p], a, b, c;
.mode = { .up, .down, .bfly, .idx };
Description
Exchange register data between threads of a warp.
Each thread in the currently executing warp will compute a source lane index j based on input
operands b and c and the mode. If the computed source lane index j is in range, the
thread will copy the input operand a from lane j into its own destination register d;
otherwise, the thread will simply copy its own input a to destination d. The optional
destination predicate p is set to True if the computed source lane is in range, and
otherwise set to False.
Note that an out of range value of b may still result in a valid computed source lane index
j. In this case, a data transfer occurs and the destination predicate p is True.
Note that results are undefined in divergent control flow within a warp, if an active thread sources
a register from an inactive thread.
Operand b specifies a source lane or source lane offset, depending on the mode.
Operand c contains two packed values specifying a mask for logically splitting warps into
sub-segments and an upper bound for clamping the source lane index.
Semantics
lane[4:0] = [Thread].laneid; // position of thread in warp
bval[4:0] = b[4:0]; // source lane or lane offset (0..31)
cval[4:0] = c[4:0]; // clamp value
mask[4:0] = c[12:8];
// get value of source register a if thread is active and
// guard predicate true, else unpredictable
if (isActive(Thread) && isGuardPredicateTrue(Thread)) {
SourceA[lane] = a;
} else {
// Value of SourceA[lane] is unpredictable for
// inactive/predicated-off threads in warp
}
maxLane = (lane[4:0] & mask[4:0]) | (cval[4:0] & ~mask[4:0]);
minLane = (lane[4:0] & mask[4:0]);
switch (.mode) {
case .up: j = lane - bval; pval = (j >= maxLane); break;
case .down: j = lane + bval; pval = (j <= maxLane); break;
case .bfly: j = lane ^ bval; pval = (j <= maxLane); break;
case .idx: j = minLane | (bval[4:0] & ~mask[4:0]);
pval = (j <= maxLane); break;
}
if (!pval) j = lane; // copy from own lane
d = SourceA[j]; // copy input a from lane j
if (dest predicate selected)
p = pval;
// Warp-level INCLUSIVE PLUS REVERSE-SCAN://// Assumes input in following registers:// - Rx = sequence value for this thread//shfl.down.b32 Ry|p, Rx, 0x1, 0x1f;
// BUTTERFLY REDUCTION://// Assumes input in following registers:// - Rx = sequence value for this thread//shfl.bfly.b32 Ry, Rx, 0x10, 0x1f; // no predicate destadd.f32 Rx, Ry, Rx;shfl.bfly.b32 Ry, Rx, 0x8, 0x1f;add.f32 Rx, Ry, Rx;shfl.bfly.b32 Ry, Rx, 0x4, 0x1f;add.f32 Rx, Ry, Rx;shfl.bfly.b32 Ry, Rx, 0x2, 0x1f;add.f32 Rx, Ry, Rx;shfl.bfly.b32 Ry, Rx, 0x1, 0x1f;add.f32 Rx, Ry, Rx;//// All threads now hold sum in Rx
plaintext
9.7.10.6. Data Movement and Conversion Instructions: shfl.sync#
shfl.sync
Register data shuffle within threads of a warp.
Syntax
shfl.sync.mode.b32 d[|p], a, b, c, membermask;
.mode = { .up, .down, .bfly, .idx };
Description
Exchange register data between threads of a warp.
shfl.sync will cause executing thread to wait until all non-exited threads corresponding to
membermask have executed shfl.sync with the same qualifiers and same membermask value
before resuming execution.
Operand membermask specifies a 32-bit integer which is a mask indicating threads participating
in barrier where the bit position corresponds to thread’s laneid.
shfl.sync exchanges register data between threads in membermask.
Each thread in the currently executing warp will compute a source lane index j based on input
operands b and c and the mode. If the computed source lane index j is in range, the
thread will copy the input operand a from lane j into its own destination register d;
otherwise, the thread will simply copy its own input a to destination d. The optional
destination predicate p is set to True if the computed source lane is in range, and
otherwise set to False.
Note that an out of range value of b may still result in a valid computed source lane index
j. In this case, a data transfer occurs and the destination predicate p is True.
Note that results are undefined if a thread sources a register from an inactive thread or a thread
that is not in membermask.
Operand b specifies a source lane or source lane offset, depending on the mode.
Operand c contains two packed values specifying a mask for logically splitting warps into
sub-segments and an upper bound for clamping the source lane index.
The behavior of shfl.sync is undefined if the executing thread is not in the membermask.
Note
For .target sm_6x or below, all threads in membermask must execute the same shfl.sync
instruction in convergence, and only threads belonging to some membermask can be active when
the shfl.sync instruction is executed. Otherwise, the behavior is undefined.
Semantics
// wait for all threads in membermask to arrive
wait_for_specified_threads(membermask);
lane[4:0] = [Thread].laneid; // position of thread in warp
bval[4:0] = b[4:0]; // source lane or lane offset (0..31)
cval[4:0] = c[4:0]; // clamp value
segmask[4:0] = c[12:8];
// get value of source register a if thread is active and
// guard predicate true, else unpredictable
if (isActive(Thread) && isGuardPredicateTrue(Thread)) {
SourceA[lane] = a;
} else {
// Value of SourceA[lane] is unpredictable for
// inactive/predicated-off threads in warp
}
maxLane = (lane[4:0] & segmask[4:0]) | (cval[4:0] & ~segmask[4:0]);
minLane = (lane[4:0] & segmask[4:0]);
switch (.mode) {
case .up: j = lane - bval; pval = (j >= maxLane); break;
case .down: j = lane + bval; pval = (j <= maxLane); break;
case .bfly: j = lane ^ bval; pval = (j <= maxLane); break;
case .idx: j = minLane | (bval[4:0] & ~segmask[4:0]);
pval = (j <= maxLane); break;
}
if (!pval) j = lane; // copy from own lane
d = SourceA[j]; // copy input a from lane j
if (dest predicate selected)
p = pval;
Examples
shfl.sync.up.b32 Ry|p, Rx, 0x1, 0x0, 0xffffffff;
9.7.10.7. Data Movement and Conversion Instructions: prmt#
prmt
Permute bytes from register pair.
Syntax
prmt.b32{.mode} d, a, b, c;
.mode = { .f4e, .b4e, .rc8, .ecl, .ecr, .rc16 };
Description
Pick four arbitrary bytes from two 32-bit registers, and reassemble them into a 32-bit destination
register.
In the generic form (no mode specified), the permute control consists of four 4-bit selection
values. The bytes in the two source registers are numbered from 0 to 7: {b,a}={{b7,b6,b5,b4},{b3,b2,b1,b0}}. For each byte in the target register, a 4-bit selection value is defined.
The 3 lsbs of the selection value specify which of the 8 source bytes should be moved into the
target position. The msb defines if the byte value should be copied, or if the sign (msb of the
byte) should be replicated over all 8 bits of the target position (sign extend of the byte value);
msb=0 means copy the literal value; msb=1 means replicate the sign. Note that the sign
extension is only performed as part of generic form.
Thus, the four 4-bit values fully specify an arbitrary byte permute, as a 16b permute code.
default mode
d.b3
source select
d.b2
source select
d.b1
source select
d.b0
source select
index
c[15:12]
c[11:8]
c[7:4]
c[3:0]
The more specialized form of the permute control uses the two lsb’s of operand c (which is
typically an address pointer) to control the byte extraction.
Load register variable d from the location specified by the source address operand a in
specified state space. If no state space is given, perform the load using Generic Addressing.
If no sub-qualifier is specified with .shared state space, then ::cta is assumed by default.
Supported addressing modes for operand a and alignment requirements are described in
Addresses as Operands
If no sub-qualifier is specified with .param state space, then:
::func is assumed when access is inside a device function.
::entry is assumed when accessing kernel function parameters from entry function. Otherwise, when
accessing device function parameters or any other .param variables from entry function ::func
is assumed by default.
For ld.param::entry instruction, operand a must be a kernel parameter address, otherwise behavior
is undefined. For ld.param::func instruction, operand a must be a device function parameter address,
otherwise behavior is undefined.
The .relaxed and .acquire qualifiers indicate memory synchronization as described in the
Memory Consistency Model. The .scope qualifier
indicates the set of threads with which an ld.relaxed or ld.acquire instruction can directly
synchronize1. The .weak qualifier indicates a memory instruction with no synchronization.
The effects of this instruction become visible to other threads only when synchronization is established
by other means.
The optional qualifier .proxy::readonly may be used to indicate that the memory operation is
performed using the readonly proxy. When this qualifier is specified, the memory location referred
to by source operand a is treated as read-only during the lifetime of the kernel.
The proxy::readonly qualifier may only be used with global state space or with generic addressing
where the address points to global or const state space.
If the generic address does not fall within the address window of the global or const memory,
then the behavior is undefined.
The semantic details of .mmio qualifier are described in the Memory Consistency Model.
Only .sys thread scope is valid for ld.mmio operation.
The .weak, .volatile, .relaxed and .acquire qualifiers are mutually exclusive. When
none of these is specified, the .weak qualifier is assumed by default.
.relaxed and .acquire:
May be used with .global, .shared spaces, or with generic addressing where the address
points to .global or .shared space.
Cache operations are not allowed.
.volatile:
May be used with .global, .shared, .local spaces, or with generic addressing where
the address points to .global, .shared, or .local space.
Cache operations are not allowed.
.mmio:
May be used only with .global space or with generic addressing where the address points to
.global space.
State space is .global or with generic addressing where address points to .global state space
The .v4 (.vec) qualifier with type .b64 or .s64 or .u64 or .f64 is supported if:
State space is .global or with generic addressing where address points to .global state space
Qualifiers .level1::eviction_priority and .level2::eviction_priority specify the eviction policy
for L1 and L2 cache respectively which may be applied during memory access.
Qualifier .level2::eviction_priority is supported if:
.vec is .v8 and .type is .b32 or .s32 or .u32 or .f32
AND Operand d is vector of 8 registers with type specified with .type
OR .vec is .v4 and .type is .b64 or .s64 or .u64 or .f64
AND Operand d is vector of 4 registers with type specified with .type
Optionally, sink symbol ‘_’ can be used in vector expression d when:
.vec is .v8 and .type is .b32 or .s32 or .u32 or .f32 OR
.vec is .v4 and .type is .b64 or .s64 or .u64 or .f64
which indicates that data from corresponding memory location is not read.
The .level::prefetch_size qualifier is a hint to fetch additional data of the specified size
into the respective cache level.The sub-qualifier prefetch_size can be set to either of 64B,
128B, 256B thereby allowing the prefetch size to be 64 Bytes, 128 Bytes or 256 Bytes
respectively.
The qualifier .level::prefetch_size may only be used with .global state space and with
generic addressing where the address points to .global state space. If the generic address does
not fall within the address window of the global memory, then the prefetching behavior is undefined.
The .level::prefetch_size qualifier is treated as a performance hint only.
When the optional argument cache_policy is specified, the qualifier .level::cache_hint is
required. The 64-bit operand cache_policy specifies the cache eviction policy that may be used
during the memory access.
The qualifiers .unified and .level::cache_hint are only supported for .global state
space and for generic addressing where the address points to the .global state space.
cache_policy is a hint to the cache subsystem and may not always be respected. It is treated as
a performance hint only, and does not change the memory consistency behavior of the program.
1 This synchronization is further extended to other threads through the transitive nature of
causality order, as described in the memory consistency model.
Semantics
d = a; // named variable a
d = *(&a+immOff) // variable-plus-offset
d = *a; // register
d = *(a+immOff); // register-plus-offset
d = *(immAddr); // immediate address
Load register variable d from the location specified by the source address operand a in the
global state space, and optionally cache in non-coherent read-only cache.
Note
On some architectures, the texture cache is larger, has higher bandwidth, and longer latency than
the global memory cache. For applications with sufficient parallelism to cover the longer
latency, ld.global.nc should offer better performance than ld.global on such
architectures.
The address operand a shall contain a global address.
Supported addressing modes for operand a and alignment requirements are
described in Addresses as Operands.
The .v8 (.vec) qualifier is supported if:
.type is .b32, .s32, .u32, or .f32 AND
State space is .global or with generic addressing where address points to .global state space
The .v4 (.vec) qualifier with type .b64 or .s64 or .u64 or .f64 is supported if:
State space is .global or with generic addressing where address points to .global state space
Qualifiers .level1::eviction_priority and .level2::eviction_priority specify the eviction policy
for L1 and L2 cache respectively which may be applied during memory access.
Qualifier .level2::eviction_priority is supported if:
.vec is .v8 and .type is .b32 or .s32 or .u32 or .f32
AND Operand d is vector of 8 registers with type specified with .type
OR .vec is .v4 and .type is .b64 or .s64 or .u64 or .f64
AND Operand d is vector of 4 registers with type specified with .type
Optionally, sink symbol ‘_’ can be used in vector expression d when:
.vec is .v8 and .type is .b32 or .s32 or .u32 or .f32 OR
.vec is .v4 and .type is .b64 or .s64 or .u64 or .f64
which indicates that data from corresponding memory location is not read.
The .level::prefetch_size qualifier is a hint to fetch additional data of the specified size
into the respective cache level.The sub-qualifier prefetch_size can be set to either of 64B,
128B, 256B thereby allowing the prefetch size to be 64 Bytes, 128 Bytes or 256 Bytes
respectively.
The .level::prefetch_size qualifier is treated as a performance hint only.
When the optional argument cache_policy is specified, the qualifier .level::cache_hint is
required. The 64-bit operand cache_policy specifies the cache eviction policy that may be used
during the memory access.
cache_policy is a hint to the cache subsystem and may not always be respected. It is treated as
a performance hint only, and does not change the memory consistency behavior of the program.
Semantics
d = a; // named variable a
d = *(&a+immOff) // variable-plus-offset
d = *a; // register
d = *(a+immOff); // register-plus-offset
d = *(immAddr); // immediate address
Load read-only data into register variable d from the location specified by the source address
operand a in the global state space, where the address is guaranteed to be the same across all
threads in the warp. If no state space is given, perform the load using Generic Addressing.
Supported addressing modes for operand a and alignment requirements are described in
Addresses as Operands.
Semantics
d = a; // named variable a
d = *(&a+immOff) // variable-plus-offset
d = *a; // register
d = *(a+immOff); // register-plus-offset
d = *(immAddr); // immediate address
Store the value of operand b in the location specified by the destination address
operand a in specified state space. If no state space is given, perform the store using
Generic Addressing. Stores to const memory are illegal.
If no sub-qualifier is specified with .shared state space, then ::cta is assumed by default.
Supported addressing modes for operand a and alignment requirements are described in
Addresses as Operands.
If .param is specified without any sub-qualifiers then it defaults to .param::func.
The qualifiers .relaxed and .release indicate memory synchronization as described in the
Memory Consistency Model. The .scope qualifier
indicates the set of threads with which an st.relaxed or st.release instruction can directly
synchronize1. The .weak qualifier indicates a memory instruction with no synchronization.
The effects of this instruction become visible to other threads only when synchronization is established
by other means.
The semantic details of .mmio qualifier are described in the Memory Consistency Model.
Only .sys thread scope is valid for st.mmio operation.
The .weak, .volatile, .relaxed and .release qualifiers are mutually exclusive. When
none of these is specified, the .weak qualifier is assumed by default.
.relaxed and .release:
May be used with .global, .shared spaces or with generic addressing where the address points
to .global or .shared space.
Cache operations are not allowed.
.volatile:
May be used with .global, .shared, .local spaces or with generic addressing where the
address points to .global, .shared, or .local space.
Cache operations are not allowed.
.mmio:
May be used only with .global space or with generic addressing where the address points to
.global space.
The .v8 (.vec) qualifier is supported if:
.type is .b32, .s32, .u32, or .f32 AND
State space is .global or with generic addressing where address points to .global state space
The .v4 (.vec) qualifier with type .b64 or .s64 or .u64 or .f64 is supported if:
State space is .global or with generic addressing where address points to .global state space
Qualifiers .level1::eviction_priority and .level2::eviction_priority specify the eviction policy
for L1 and L2 cache respectively which may be applied during memory access.
Qualifier .level2::eviction_priority is supported if:
.vec is .v8 and .type is .b32 or .s32 or .u32 or .f32
AND Operand d is vector of 8 registers with type specified with .type
OR .vec is .v4 and .type is .b64 or .s64 or .u64 or .f64
AND Operand d is vector of 4 registers with type specified with .type
Optionally, sink symbol ‘_’ can be used in vector expression b when:
.vec is .v8 and .type is .b32 or .s32 or .u32 or .f32 OR
.vec is .v4 and .type is .b64 or .s64 or .u64 or .f64
which indicates that no data is being written at the corresponding destination address.
When the optional argument cache_policy is specified, the qualifier .level::cache_hint is
required. The 64-bit operand cache_policy specifies the cache eviction policy that may be used
during the memory access.
The qualifier .level::cache_hint is only supported for .global state space and for generic
addressing where the address points to the .global state space.
cache_policy is a hint to the cache subsystem and may not always be respected. It is treated as
a performance hint only, and does not change the memory consistency behavior of the program.
1 This synchronization is further extended to other threads through the transitive nature of
causality order, as described in the memory consistency model.
Semantics
d = a; // named variable d
*(&a+immOffset) = b; // variable-plus-offset
*a = b; // register
*(a+immOffset) = b; // register-plus-offset
*(immAddr) = b; // immediate address
st.async is a non-blocking instruction which initiates an asynchronous store operation that
stores the value specified by source operand b to the destination memory location
specified by operand a.
st.async is performed in the generic proxy.
Operands
a is a destination address, and must be either a register, or of the form register+immOff,
as described in Addresses as Operands.
b is a source value, of the type indicated by qualifier .type.
.completion_mechanism specifies the mechanism for observing the completion of the
asynchronous operation.
When .completion_mechanism is .mbarrier::complete_tx::bytes: upon completion of the
asynchronous operation, a
complete-tx
operation will be performed on the mbarrier object specified by the operand mbar, with
completeCount argument equal to the amount of data stored in bytes.
This instruction accesses its mbarrier operand using generic-proxy.
.type specifies the type of the source operand b.
Conditions
When .sem is .weak:
This is a weak store to shared memory, which signals its completion through an mbarrier object.
The store operation is treated as a weak memory operation.
Requires:
The shared memory addresses of destination operand a and the mbarrier objectmbar belong
to the same CTA within the same cluster as the executing thread.
The number of CTAs within the cluster is strictly greater than one; %cluster_nctarank>1 is true.
Otherwise, the behavior is undefined.
.mmio must not be specified.
If .ss is specified, it must be .shared::cluster.
If .ss is not specified, generic addressing is used for operands a and mbar.
If the generic addresses specified do not fall within the address window of
.shared::cluster state space, the behavior is undefined.
.completion_mechanism must be specified and must be .mbarrier::complete_tx::bytes.
When .sem is .release:
This is a release store to global memory.
The store operation is a strong memory operation with .release semantics at the
scope specified by .scope.
If .mmio is specified, .scope must be .sys.
If .ss is specified, it must be .global.
If .ss is not specified, generic addressing is used for operand a.
If the generic address specified does not fall within the address window of .global
state space, the behavior is undefined.
For .vec qualifier:
.v2 is supported with .b32, .b64, .s32, .s64, .u32, .u64,
.f32 and .f64 types.
.v4 qualifier is supported with .b32, .s32, .u32 and .f32 types.
multimem.st.async is a non-blocking instruction which initiates an asynchronous store
operation that stores the value specified by source operand b to the memory locations
residing on each GPU’s memory referred to by the destination multimem address operand a.
Address operand a must be a multimem address. Otherwise, the behavior is undefined.
Operands
a is a destination address, and must be either a register, or of the form
register+immOff, as described in Addresses as Operands.
b is a source value, of the type indicated by qualifier .type.
Qualifiers
The mandatory .sem modifier specifies the memory ordering semantics as described in the
Memory Consistency Model.
The mandatory .scope modifier specifies the set of threads with which this instruction
can directly synchronize. The store operation here is a strong memory operation with
.release semantics at the scope specified by .scope.
.ss specifies the state space of the destination operand a. If .ss is specified,
it must be .global. If .ss is not specified, Generic Addressing is used for operand
a. If the generic address specified does not fall within the address window of .global
state space, the behavior is undefined.
.type specifies the type of the source operand b.
Examples
// Release store to multimem address, GPU scope, explicit .global state space.
multimem.st.async.release.gpu.global.u32 [mm_addr], src_u32;
// Release store, system scope, generic addressing for multimem operand.
multimem.st.async.release.sys.f64 [mm_addr], src_f64;
9.7.10.14. Data Movement and Conversion Instructions: st.bulk#
st.bulk
Initializes a region of memory as specified by state space.
Syntax
st.bulk{.weak}{.shared::cta} [a], size, initval; // initval must be zero
Description
st.bulk instruction initializes a region of shared memory starting from the location specified
by destination address operand a.
The 32-bit or 64-bit integer operand size specifies the amount of memory to be initialized in terms of
number of bytes. size must be a multiple of 8. If the value is not a multiple of 8, then the
behavior is undefined. The maximum value of size operand can be 16777216.
The integer constant operand initval specifies the initialization value for the memory
locations. The only numeric value allowed for operand initval is 0.
If no state space is specified then Generic Addressing is used. If the
address specified by a does not fall within the address window of .shared state space then
the behavior is undefined.
The optional qualifier .weak specify the memory synchronizing effect of the st.bulk
instruction as described in the Memory Consistency Model.
Examples
st.bulk.weak.shared::cta [dst], n, 0;
st.bulk [gdst], 4096, 0;
9.7.10.15. Data Movement and Conversion Instructions: multimem.ld_reduce , multimem.st , multimem.red#
The multimem.* operations operate on multimem addresses and accesses all of the multiple memory
locations which the multimem address points to.
Multimem addresses can be accessed only by multimem.* operations. Accessing a multimem address
with ld, st or any other memory operations results in undefined behavior.
Refer to CUDA programming guide for creation and management of the multimem addresses.
multimem.ld_reduce, multimem.st, multimem.red
Perform memory operations on the multimem address.
Instruction multimem.ld_reduce performs the following operations:
load operation on the multimem address a, which involves loading of data from all of the
multiple memory locations pointed to by the multimem address a,
reduction operation specified by .op on the multiple data loaded from the multimem address
a.
The result of the reduction operation in returned in register d.
Instruction multimem.st performs a store operation of the input operand b to all the memory
locations pointed to by the multimem address a.
Instruction multimem.red performs a reduction operation on all the memory locations pointed to
by the multimem address a, with operand b.
Instruction multimem.ld_reduce performs reduction on the values loaded from all the memory
locations that the multimem address points to. In contrast, the multimem.red perform reduction
on all the memory locations that the multimem address points to.
Address operand a must be a multimem address. Otherwise, the behavior is undefined. Supported
addressing modes for operand a and alignment requirements are described in
Addresses as Operands.
If no state space is specified then Generic Addressing is
used. If the address specified by a does not fall within the address window of .global state
space then the behavior is undefined.
For floating-point type multi- operations, the size of the specified type along with .vec must
equal either 32-bits or 64-bits or 128-bits. No other combinations of .vec and type are
allowed. Type .f64 cannot be used with .vec qualifier.
The following table describes the valid usage of .vec and base floating-point type:
For multimem.ld_reduce, the default precision of the intermediate accumulation is same as the
specified type.
Optionally, .acc_prec qualifier can be specified to change the precision of intermediate
accumulation as follows:
.type
.acc::prec
Changes precision to
.f16, .f16x2,
.bf16, .bf16x2
.acc::f32
.f32
.e5m2, .e4m3,
.e5m2x2, .e4m3x2,
.e4m3x4, .e5m2x4
.acc::f16
.f16
Optional qualifiers .ldsem, .stsem and .redsem specify the memory synchronizing effect
of the multimem.ld_reduce, multimem.st and multimem.red respectively, as described in
Memory Consistency Model. If explicit semantics qualifiers
are not specified, then multimem.ld_reduce and multimem.st default to .weak and
multimem.red defaults to .relaxed.
The optional .scope qualifier specifies the set of threads that can directly observe the memory
synchronizing effect of this operation, as described in
Memory Consistency Model. If the .scope qualifier is not specified for
multimem.red then .sys scope is assumed by default.
9.7.10.16. Data Movement and Conversion Instructions: prefetch , prefetchu#
prefetch, prefetchu
Prefetch line containing a generic address at a specified level of memory hierarchy, in specified
state space.
Syntax
prefetch{.space}.level [a]; // prefetch to data cache
prefetch{.global}.level::prefetch_size.valid_addr [a]; // prefetch to L1 data cache
prefetch.global.level::eviction_priority [a]; // prefetch to data cache
prefetchu.L1 [a]; // prefetch to uniform cache
prefetch{.tensormap_space}.tensormap [a]; // prefetch the tensormap
The prefetch instruction brings the cache line containing the specified address in global or
local memory state space into the specified cache level.
The optional qualifier .L1::32B can be specified to represent a valid prefetch of at least
32 byte. If specified, the instruction must satisfy the following conditions:
Qualifier .valid_addr must be specified; The .valid_addr qualifier requires at-least
1B-wide memory location referred to by address a to be valid for this access.
Otherwise, the behavior is undefined.
Qualifier .space if specified, must be set to .global. If the address is not specified,
generic addressing is used and the generic address must fall within the global state-space.
If the .tensormap qualifier is specified then the prefetch instruction brings the cache line
containing the specified address in the .const or .param memory state space for subsequent
use by the cp.async.bulk.tensor instruction.
Optionally, the eviction priority to be applied on the prefetched cache line can be specified by the
modifier .level::eviction_priority.
Supported addressing modes for operand a and alignment requirements are described in
Addresses as Operands
The prefetchu instruction brings the cache line containing the specified generic address into
the specified uniform cache level.
A prefetch to a shared memory location performs no operation.
A prefetch into the uniform cache requires a generic address, and no operation occurs if the
address maps to a const, local, or shared memory location.
The applypriority instruction applies the cache eviction priority specified by the
.level::eviction_priority qualifier to the address range [a..a+size) in the specified cache
level.
If no state space is specified then Generic Addressing is
used. If the specified address does not fall within the address window of .global state space
then the behavior is undefined.
The operand size is an integer constant that specifies the amount of data, in bytes, in the
specified cache level on which the priority is to be applied. The only supported value for the
size operand is 128.
Supported addressing modes for operand a are described in Addresses as Operands.
a must be aligned to 128 bytes.
Examples
applypriority.global.L2::evict_normal [ptr], 128;
9.7.10.18. Data Movement and Conversion Instructions: applypriority.async.bulk#
applypriority.async.bulk
Apply the cache eviction priority to the specified address in the specified cache level.
The applypriority.async.bulk instruction applies the cache eviction priority specified by
the .level::eviction_priority qualifier to the address range [a..a+size) in the specified
cache level.
If no state space is specified then Generic Addressing is
used. If the specified address does not fall within the address window of .global state space
then the behavior is undefined.
The operand size is a 32 bit integer that specifies the amount of data, in bytes, in the
specified cache level on which the priority is to be applied. The value of the size operand
needs to be a multiple of 16.
Supported addressing modes for operand a are described in Addresses as Operands.
a must be aligned to 128 bytes.
The qualifier .bulk_group specifies that the applypriority.async.bulk variant uses
bulk async-group based completion mechanism.
The applypriority.async.bulk instruction is treated as a weak memory operation in the
Memory Consistency Model.
The applypriority.async.bulk.tensor instruction applies the cache eviction priority to
the tensor. Qualifier .level::eviction_priority specifies the priority and the cache level.
If no state space is specified then Generic Addressing is
used. If the specified address does not fall within the address window of .global state space
then the behavior is undefined.
Various tensor attributes such as the base address and size of the tensor are specified in the
Tensor-map.
The optional qualifiers .override::global_address and .override_attribute supports value
override functionality for various tensor properties present in the tensorMap object. For more
details refer Overriding tensor property value.
The qualifier .bulk_group specifies that the applypriority.async.bulk.tensor variant uses
bulk async-group based completion mechanism.
The applypriority.async.bulk.tensor instruction is treated as a weak memory operation in the
Memory Consistency Model.
9.7.10.20. Data Movement and Conversion Instructions: discard#
discard
Discard the data at the specified address range and cache level.
Syntax
discard{.global}.level [a], size;
.level = { .L2 };
Description
Semantically, this behaves like a weak write of an unstable indeterminate value:
reads of memory locations with unstable indeterminate values may return different
bit patterns each time until the memory is overwritten.
This operation hints to the implementation that data in the specified cache .level
can be destructively discarded without writing it back to memory.
The operand size is an integer constant that specifies the length in bytes of the
address range [a,a+size) to write unstable indeterminate values into.
The only supported value for the size operand is 128.
If no state space is specified then Generic Addressing is used.
If the specified address does not fall within the address window of .global state space
then the behavior is undefined.
Supported addressing modes for address operand a are described in Addresses as Operands.
a must be aligned to 128 bytes.
Examples
discard.global.L2 [ptr], 128;
ld.weak.u32 r0, [ptr];
ld.weak.u32 r1, [ptr];
// The values in r0 and r1 may differ!
9.7.10.21. Data Movement and Conversion Instructions: createpolicy#
createpolicy
Create a cache eviction policy for the specified cache level.
The createpolicy instruction creates a cache eviction policy for the specified cache level in an
opaque 64-bit register specified by the destination operand cache_policy. The cache eviction
policy specifies how cache eviction priorities are applied to global memory addresses used in memory
operations with .level::cache_hint qualifier.
There are two types of cache eviction policies:
Range-based policy
The cache eviction policy created using createpolicy.range specifies the cache eviction
behaviors for the following three address ranges:
[a..a+(primary-size-1)] referred to as primary range.
[a+primary-size..a+(total-size-1)] referred to as trailing secondary range.
[a-(total-size-primary-size)..(a-1)] referred to as preceding secondary range.
The cache eviction policy created using createpolicy.range.fabric specifies the cache
eviction behaviors for the following three address ranges within a fabric handle:
[aOff..aOff+(primary-size-1)] referred to as primary range.
[aOff+primary-size..aOff+(total-size-1)] referred to as trailing secondary range.
[aOff-(total-size-primary-size)..(aOff-1)] referred to as preceding secondary range.
When a range-based cache eviction policy is used in a memory operation with
.level::cache_hint qualifier, the eviction priorities are applied as follows:
If the memory address falls in the primary range, the eviction priority specified by
.level::primary_priority is applied.
If the memory address falls in either of the secondary ranges, the eviction priority specified by
.level::secondary_priority is applied.
If the memory address does not fall in any of the above ranges, then the applied eviction
priority is unspecified.
The 32-bit operand primary-size specifies the size, in bytes, of the primary range. The
32-bit operand total-size specifies the combined size, in bytes, of the address range
including primary and secondary ranges. The value of primary-size must be less than or equal
to the value of total-size. Maximum allowed value of total-size is 4GB.
If .level::secondary_priority is not specified, then it defaults to .L2::evict_unchanged.
If no state space is specified then Generic Addressing is
used. If the specified address does not fall within the address window of .global state space
then the behavior is undefined.
Fraction-based policy
A memory operation with .level::cache_hint qualifier can use the fraction-based cache
eviction policy to request the cache eviction priority specified by .level::primary_priority to
be applied to a fraction of cache accesses specified by the 32-bit floating point operand
fraction. The remainder of the cache accesses get the eviction priority specified by
.level::secondary_priority. This implies that in a memory operation that uses a fraction-based
cache policy, the memory access has a probability specified by the operand fraction of
getting the cache eviction priority specified by .level::primary_priority.
The valid range of values for the operand fraction is (0.0,..,1.0]. If the operand
fraction is not specified, it defaults to 1.0.
If .level::secondary_priority is not specified, then it defaults to .L2::evict_unchanged.
The access property created using the CUDA APIs can be converted into cache eviction policy by the
instruction createpolicy.cvt. The source operand access-property is a 64-bit opaque
register. Refer to CUDA programming guide for more details.
Write predicate register p with 1 if generic address a falls within the specified state
space window and with 0 otherwise. Destination p has type .pred; the source address
operand must be of type .u32 or .u64.
isspacep.param{::entry} returns 1 if the generic address falls within the window of
Kernel Function Parameters, otherwise returns 0. If .param
is specified without any sub-qualifiers then it defaults to .param::entry.
isspacep.global returns 1 for Kernel Function Parameters
as .param window is contained within the .global
window.
If no sub-qualifier is specified with .shared state space, then ::cta is assumed by default.
Note
ispacep.shared::cluster will return 1 for every shared memory address that is accessible to
the threads in the cluster, whereas ispacep.shared::cta will return 1 only if the address is
of a variable declared in the executing CTA.
9.7.10.23. Data Movement and Conversion Instructions: cvta#
cvta
Convert address from .const,
Kernel Function Parameters (.param), .global, .local, or .shared
state space to generic, or vice-versa. Take the generic address of a variable declared in
.const, Kernel Function Parameters (.param),
.global, .local, or .shared state space.
Syntax
// convert const, global, local, or shared address to generic address
cvta.space.size p, a; // source address in register a
cvta.space.size p, var; // get generic address of var
cvta.space.size p, var+imm; // generic address of var+offset
// convert generic address to const, global, local, or shared address
cvta.to.space.size p, a;
Convert a const, Kernel Function Parameters
(.param), global, local, or shared address to a generic address, or vice-versa. The
source and destination addresses must be the same size. Use cvt.u32.u64 or cvt.u64.u32 to
truncate or zero-extend addresses.
For variables declared in .const,
Kernel Function Parameters (.param), .global, .local, or .shared
state space, the generic address of the variable may be taken using cvta. The source is either a
register or a variable defined in const,
Kernel Function Parameters (.param), global, local, or shared memory
with an optional offset.
When converting a generic address into a const,
Kernel Function Parameters (.param), global, local, or shared
address, the resulting address is undefined in cases where the generic address does not fall within
the address window of the specified state space. A program may use isspacep to guard against
such incorrect behavior.
For cvta with .shared state space, the address must belong to the space specified by
::cta or ::cluster sub-qualifier, otherwise the behavior is undefined. If no sub-qualifier
is specified with .shared state space, then ::cta is assumed by default.
If .param is specified without any sub-qualifiers then it defaults to .param::entry. For
.param{::entry} state space, operand a must be a kernel parameter address, otherwise
behavior is undefined.
For .f16x2 and .bf16x2 instruction type, two inputs a and b of .f32 type are
converted into .f16 or .bf16 type and the converted values are packed in the destination
register d, such that the value converted from input a is stored in the upper half of d
and the value converted from input b is stored in the lower half of d
For .f16x2 instruction type, destination operand d has .f16x2 or .b32 type. For
.bf16 instruction type, operand d has .b16 type. For .bf16x2 instruction type,
operand d has .b32 type. For .tf32 instruction type, operand d has .b32 type.
When converting to .e4m3x2/.e5m2x2/.ue5m3x2 data formats, the destination operand d has .b16
type. When converting two .f32 inputs to .e4m3x2/.e5m2x2/.ue5m3x2, each input is converted to the
specified format, and the converted values are packed in the destination operand d such that the
value converted from input a is stored in the upper 8 bits of d and the value converted from
input b is stored in the lower 8 bits of d. When converting an .f16x2/.bf16x2 input to
.e4m3x2/ .e5m2x2/.ue5m3x2, each .f16/.bf16 input from operand a is converted to the specified
format. The converted values are packed in the destination operand d such that the value
converted from the upper 16 bits of input a is stored in the upper 8 bits of d and the value
converted from the lower 16 bits of input a is stored in the lower 8 bits of d.
When converting from .e4m3x2/.e5m2x2/.ue5m3x2 to .f16x2/.bf16x2, source operand a has .b16
type. Each 8-bit input value in operand a is converted to .f16/.bf16 type. The converted values
are packed in the destination operand d such that the value converted from the upper 8 bits of
a is stored in the upper 16 bits of d and the value converted from the lower 8 bits of a
is stored in the lower 16 bits of d.
For .bf16x2 destination type optional scale-factor operand of type .b16 can be specified along with
.scaled::n2::ue8m0 qualifier. Operand scale-factor stores two packed scaling factors of type .ue8m0.
Inputs are converted to destination type and then multiplied by scale-factor. The scaling factor of upper
8 bits of a is stored in the upper 8 bits of operand scale-factor and the scaling factor of lower 8 bits
of a is stored in the lower 8 bits of operand scale-factor. If not specified explicitly, value of
scale-factor will be assumed to be 0x7f7f, that is, assumed as value 1 for both input scale factors.
When converting to .e2m1x2 data formats, the destination operand d has .b8 type.
When converting two .f32 inputs to .e2m1x2, each input is converted to the specified format,
and the converted values are packed in the destination operand d such that the value converted
from input a is stored in the upper 4 bits of d and the value converted from input b is
stored in the lower 4 bits of d. When converting an .f16x2/.bf16x2 input to
.e2m1x2, each .f16/.bf16 input from operand a is converted to the specified format.
The converted values are packed in d so that the value from the upper 16 bits of a is stored
in the upper 4 bits of d, and the value from the lower 16 bits of a is stored in the lower 4
bits of d.
When converting from .e2m1x2 to .f16x2/.bf16x2, source operand a has .b8 type. Each 4-bit
input value in operand a is converted to .f16/.bf16 type. The converted values are packed in the
destination operand d such that the value converted from the upper 4 bits of a is stored in
the upper 16 bits of d and the value converted from the lower 4 bits of a is stored in the
lower 16 bits of d.
For .bf16x2 destination type optional scale-factor operand of type .b16 can be specified along with
.scaled::n2::ue8m0 qualifier. Operand scale-factor stores two packed scaling factors of type .ue8m0.
Inputs are converted to destination type and then multiplied by scale-factor. The scaling factor of upper
4 bits of a is stored in the upper 8 bits of operand scale-factor and the scaling factor of lower 4 bits
of a is stored in the lower 8 bits of operand scale-factor. If not specified explicitly, value of
scale-factor will be assumed to be 0x7f7f, that is, assumed as value 1 for both input scale factors.
When converting to .e2m1x4 data format, the destination operand d has .b16 type. When
converting four .f32 inputs to .e2m1x4, each input is converted to the specified format,
and the converted values are packed in the destination operand d such that the value converted
from inputs a, b, e, f are stored in each 4 bits starting from upper bits of d.
When converting to .e2m3x2/.e3m2x2 data formats, the destination operand d has .b16
type. When converting two .f32 inputs to .e2m3x2/.e3m2x2, each input is converted to the
specified format, and the converted values are packed in the destination operand d such that the
value converted from input a is stored in the upper 8 bits of d with 2 MSB bits padded with
zeros and the value converted from input b is stored in the lower 8 bits of d with 2 MSB bits
padded with zeros. When converting an .f16x2/.bf16x2 input to .e2m3x2/.e3m2x2, each
.f16/.bf16 input from operand a is converted to the specified format. The converted
values are packed in the destination operand d so that the value from the upper 16 bits of input
a is stored in the upper 8 bits of d with 2 MSB bits padded with zeros, and the value from
the lower 16 bits of input a is stored in the lower 8 bits of d with 2 MSB bits padded with
zeros.
When converting from .e2m3x2/.e3m2x2 to .f16x2/.bf16x2, source operand a has .b16 type.
Each 8-bit input value with 2 MSB bits 0 in operand a is converted to .f16/.bf16 type. The converted
values are packed in the destination operand d such that the value converted from the upper 8 bits
of a is stored in the upper 16 bits of d and the value converted from the lower 8 bits of a
is stored in the lower 16 bits of d.
For .bf16x2 destination type optional scale-factor operand of type .b16 can be specified along with
.scaled::n2::ue8m0 qualifier. Operand scale-factor stores two packed scaling factors of type .ue8m0.
Inputs are converted to destination type and then multiplied by scale-factor. The scaling factor of upper
8 bits of a is stored in the upper 8 bits of operand scale-factor and the scaling factor of lower 8 bits
of a is stored in the lower 8 bits of operand scale-factor. If not specified explicitly, value of
scale-factor will be assumed to be 0x7f7f, that is, assumed as value 1 for both input scale factors.
When converting to .e5m2x4/.e4m3x4/.e3m2x4/.e2m3x4 data format, the destination
operand d has .b32 type. When converting four .f32 inputs to
.e5m2x4/.e4m3x4/.e3m2x4/.e2m3x4, each input is converted to the specified format,
and the converted values are packed in the destination operand d such that the value converted
from inputs a, b, e, f are stored in each 8 bits starting from upper bits of d.
For .e3m2x4/.e2m3x4, each 8-bit output will have 2 MSB bits padded with zeros.
When converting to .ue8m0x2 data formats, the destination operand d has .b16 type. When
converting two .f32 or two packed .bf16 inputs to .ue8m0x2, each input is converted to the
specified format, and the converted values are packed in the destination operand d such that the
value converted from input a is stored in the upper 8 bits of d and the value converted from
input b is stored in the lower 8 bits of d.
When converting from .ue8m0x2/.ue5m3x2 to .bf16x2, source operand a has .b16 type. Each 8-bit
input value in operand a is converted to .bf16 type. The converted values are packed in the
destination operand d such that the value converted from the upper 8 bits of a is stored in
the upper 16 bits of d and the value converted from the lower 8 bits of a is stored in the
lower 16 bits of d.
When converting to .s2f6x2 data formats, the destination operand d has .b16 type. When
converting two .f32 inputs to .s2f6x2, each input is converted to the .s2f6 value, and
the converted values are packed in the destination operand d such that the value converted from
input a is stored in the upper 8 bits of d and the value converted from input b is
stored in the lower 8 bits of d. When converting from .bf16x2, each input packed in operand
a is converted to .s2f6 value and converted values are packed in the destination operand
d such that value converted from upper 8 bits of input a is stored in upper 8 bits of
operand d and the value converted from lower 8 bits of input a is stored in lower 8 bits of
operand d. Optional operand scale-factor has type .b16 and stores two packed scaling
factors of type .ue8m0. For down conversion, inputs are divided by scale-factor and then
conversion is performed. The scaling factor of input a/.bf16 input from upper 16 bits of a
is stored in the upper 8 bits of operand scale-factor and the scaling factor of input b/.bf16
input from lower 16 bits of a is stored in the lower 8 bits of operand scale-factor.
If not specified explicitly, value of scale-factor will be assumed to be 0x7f7f,
that is, assumed as value 1 for both input scale factors.
When converting from .s2f6x2 to .bf16x2, source operand a has .b16 type. Each 8-bit
input value in operand a is converted to .bf16 type. The converted values are packed in the
destination operand d such that the value converted from the upper 8 bits of a is stored in
the upper 16 bits of d and the value converted from the lower 8 bits of a is stored in the
lower 16 bits of d. Optional operand scale-factor has type .b16 and stores two packed
scaling factors of type .ue8m0. For up-conversion, inputs are converted to destination type and
then multiplied by scale-factor. The scaling factor of .s2f6 input from upper 8 bits of a
is stored in the upper 8 bits of operand scale-factor and the scaling factor of .s2f6 input
from lower 8 bits of a is stored in the lower 8 bits of operand scale-factor.
If not specified explicitly, value of scale-factor will be assumed to
be 0x7f7f, that is, assumed as value 1 for both input scale factors.
Optional qualifiers .scaled::n1::ue8m0 or .scaled::n2::ue8m0 can be used to specify
that the instruction uses scale-factor with 1 scale value or 2 packed scale values of ue8m0 type.
Operand scale-factor must be used with either of the qualifiers .scaled::n1::ue8m0
or .scaled::n2::ue8m0.
Operand scale-factor:
has type .b16 when used with qualifier .scaled::n2::ue8m0 qualifier.
Default value of scale-factor is 0x7f7f in this case if not specified explicitly.
has type .b8 when used with qualifier .scaled::n1::ue8m0 qualifier.
Default value of scale-factor is 0x7f in this case if not specified explicitly.
rbits is a .b32 type register operand used for providing random bits for .rs rounding mode.
When converting to .f16x2, two 16-bit values are provided from rbits where 13 LSBs from
upper 16-bits are used as random bits for operand a with 3 MSBs are 0 and 13 LSBs from lower
16-bits are used as random bits for operand b with 3 MSBs are 0.
When converting to .bf16x2, two 16-bit values are provided from rbits where upper 16-bits
are used as random bits for operand a and lower 16-bits are used as random bits for operand b.
When converting to .e4m3x4/.e5m2x4/.e2m3x4/.e3m2x4, two 16-bit values are provided
from rbits where lower 16-bits are used for operands e, f and upper 16 bits are used
for operands a, b.
When converting to .e2m1x4, two 16-bit values are provided from rbits where lower 8-bits
from both 16-bits half of rbits are used for operands e, f and upper 8-bits from both
16-bits half of rbits are used for operands a, b.
Rounding modifier is mandatory in all of the following cases:
float-to-float conversions, when destination type is smaller than source type
.satfinite modifier is only supported for conversions involving the following types:
.e4m3x2, .e5m2x2, .e2m1x2, .e2m3x2, .e3m2x2, .e4m3x4, .e5m2x4,
.e2m1x4, .e2m3x4, .e3m2x4, .s2f6x2 destination types.
.satfinite modifier is mandatory for such conversions.
.f16, .bf16, .f16x2, .bf16x2, .tf32, .ue8m0x2, .ue5m3x2 as destination types.
The .pzo qualifier is only supported for float-to-float conversions where the destination type is
strictly smaller than the source type. When this qualifier is specified, it enforces the generation of positive
zeros only in the output. In other words, if the result of the conversion produces -0.0, it will be
forced to +0.0.
Note that the .pzo qualifier applies only to the results of the data format conversion. In other words,
.pzo qualifier has no impact on other additional operands such as rbits.
Semantics
if (/* inst type is .f16x2 or .bf16x2 */) {
d[31:16] = convert(a);
d[15:0] = convert(b);
} else if (/* inst destination type is .e5m2x2 or .e4m3x2 or .ue8m0x2 or .ue5m3x2 */) {
if (/* inst source type is .f32 */) {
d[15:8] = convert(a / scale-factor[7:0]); // scale-factor if present
d[7:0] = convert(b / scale-factor[7:0]); // scale-factor if present
} else {
d[15:8] = convert(a[31:16] / scale-factor[7:0]); // scale-factor if present
d[7:0] = convert(a[15:0] / scale-factor[7:0]); // scale-factor if present
}
} else if (/* inst destination type is .s2f6x2 */) {
if (/* inst source type is .f32 */) {
d[15:8] = convert(a / scale-factor[15:8]);
d[7:0] = convert(b / scale-factor[7:0]);
} else {
d[15:8] = convert(a[15:8] / scale-factor[15:8]);
d[7:0] = convert(a[7:0] / scale-factor[7:0]);
}
} else if (/* inst source type is .s2f6x2 */) {
d[31:16] = convert(a[15:8]) * scale-factor[15:8];
d[15:0] = convert(a[7:0]) * scale-factor[7:0];
} else if (/* inst destination type is .e2m1x2 */) {
if (/* inst source type is .f32 */) {
d[7:4] = convert(a / scale-factor[7:0]); // scale-factor if present
d[3:0] = convert(b / scale-factor[7:0]); // scale-factor if present
} else {
d[7:4] = convert(a[31:16] / scale-factor[7:0]); // scale-factor if present
d[3:0] = convert(a[15:0] / scale-factor[7:0]); // scale-factor if present
}
} else if (/* inst destination type is .e2m3x2 or .e3m2x2 */) {
if (/* inst source type is .f32 */) {
d[15:14] = 0;
d[13:8] = convert(a / scale-factor[7:0]); // scale-factor if present
d[7:6] = 0;
d[5:0] = convert(b / scale-factor[7:0]); // scale-factor if present
} else {
d[15:14] = 0;
d[13:8] = convert(a[31:16] / scale-factor[7:0]); // scale-factor if present
d[7:6] = 0;
d[5:0] = convert(a[15:0] / scale-factor[7:0]); // scale-factor if present
}
} else if (/* inst destination type is .e2m1x4 */) {
d[15:12] = convert(a);
d[11:8] = convert(b);
d[7:4] = convert(e);
d[3:0] = convert(f);
} else if (/* inst destination type is .e4m3x4 or .e5m2x4 */) {
d[31:24] = convert(a);
d[23:16] = convert(b);
d[15:8] = convert(e);
d[7:0] = convert(f);
} else if (/* inst destination type is .e2m3x4 or .e3m2x4 */) {
d[31:30] = 0;
d[29:24] = convert(a);
d[23:22] = 0;
d[21:16] = convert(b);
d[15:14] = 0;
d[13:8] = convert(e);
d[7:6] = 0;
d[5:0] = convert(f);
} else if (/* inst source type is .e4m3x2 or .e5m2x2 or .e3m2x2 or .e2m3x2 or .ue5m3x2 */) {
d[31:16] = convert(a[15:8]) * scale-factor[15:8]; // scale-factor if present for .bf16x2 dest type
d[15:0] = convert(a[7:0]) * scale-factor[7:0]; // scale-factor if present for .bf16x2 dest type
} else if (/* inst source type is .e2m1x2 */) {
d[31:16] = convert(a[7:4]) * scale-factor[15:8]; // scale-factor if present for .bf16x2 dest type
d[15:0] = convert(a[3:0]) * scale-factor[7:0]; // scale-factor if present for .bf16x2 dest type
} else {
d = convert(a);
}
// Random bits rbits semantics for .rs rounding:
Destination type .f16:
Refer Figure 39 for random bits layout details.
Figure 39 Random bits layout for .rs rounding with .f16 destination type
Destination type .bf16:
Refer Figure 40 for random bits layout details.
Figure 40 Random bits layout for .rs rounding with .bf16 destination type
Destination type .e2m1x4:
Refer Figure 41 for random bits layout details.
Figure 41 Random bits layout for .rs rounding with .e2m1x4 destination type
Destination type .e5m2x4, .e4m3x4, .e3m2x4, .e2m3x4:
Refer Figure 42 for random bits layout details.
Figure 42 Random bits layout for .rs rounding with .e5m2x4/.e4m3x4/.e3m2x4/.e2m3x4 destination type
Examples
cvt.f32.s32 f,i;
cvt.s32.f64 j,r; // float-to-int saturates by default
cvt.rni.f32.f32 x,y; // round to nearest int, result is fp
cvt.f32.f32 x,y; // note .ftz behavior for sm_1x targets
cvt.rn.relu.f16.f32 b, f; // result is saturated with .relu saturation mode
cvt.rz.f16x2.f32 b1, f, f1; // convert two fp32 values to packed fp16 outputs
cvt.rn.relu.satfinite.f16x2.f32 b1, f, f1; // convert two fp32 values to packed fp16 outputs with .relu saturation on each output
cvt.rn.bf16.f32 b, f; // convert fp32 to bf16
cvt.rz.relu.satfinite.bf16.f3 2 b, f; // convert fp32 to bf16 with .relu and .satfinite saturation
cvt.rz.satfinite.bf16x2.f32 b1, f, f1; // convert two fp32 values to packed bf16 outputs
cvt.rn.relu.bf16x2.f32 b1, f, f1; // convert two fp32 values to packed bf16 outputs with .relu saturation on each output
cvt.rna.satfinite.tf32.f32 b1, f; // convert fp32 to tf32 format
cvt.rn.relu.tf32.f32 d, a; // convert fp32 to tf32 format
cvt.f64.bf16.rp f, b; // convert bf16 to f64 format
cvt.bf16.f16.rz b, f // convert f16 to bf16 format
cvt.bf16.u64.rz b, u // convert u64 to bf16 format
cvt.s8.bf16.rpi s, b // convert bf16 to s8 format
cvt.bf16.bf16.rpi b1, b2 // convert bf16 to corresponding int represented in bf16 format
cvt.rn.satfinite.e4m3x2.f32 d, a, b; // convert a, b to .e4m3 and pack as .e4m3x2 output
cvt.rn.relu.satfinite.e5m2x2.f16x2 d, a; // unpack a and convert the values to .e5m2 outputs with .relu
// saturation on each output and pack as .e5m2x2
cvt.rn.f16x2.e4m3x2 d, a; // unpack a, convert two .e4m3 values to packed f16x2 output
cvt.rn.satfinite.tf32.f32 d, a; // convert fp32 to tf32 format
cvt.rn.relu.f16x2.e2m1x2 d, a; // unpack a, convert two .e2m1 values to packed f16x2 output
cvt.rn.satfinite.e2m3x2.f32 d, a, b; // convert a, b to .e2m3 and pack as .e2m3x2 output
cvt.rn.relu.f16x2.e3m2x2 d, a; // unpack a, convert two .e3m2 values to packed f16x2 output
cvt.rs.f16x2.f32 d, a, b, rbits; // convert 2 fp32 values to packed fp16 with applying .rs rounding
cvt.rs.satfinite.e2m1x4.f32 d, {a, b, e, f}, rbits; // convert 4 fp32 values to packed 4 e2m1 values with applying .rs rounding
cvt.rn.satfinite.relu.e2m1x2.f16x2 d, a; // unpack a and convert to two .e2m1 values
cvt.rn.satfinite.e2m3x2.bf16x2 d, a; // unpack a and convert to two .e2m3 values
// Convert 2 f32 values to s2f6 after applying scale factor for dividing the value
cvt.rn.satfinite.scaled::n2::ue8m0.s2f6x2.f32 d, a, b, scale-factor;
cvt.rz.satfinite.e2m3x2.f32 d, a, b; // convert a, b to .e2m3 and pack as .e2m3x2 with round towards zero mode
cvt.rn.bf16.f32.pzo b, f; // convert fp32 to bf16 with positive zero’s only
cvt.rn.relu.satfinite.f16x2.f32.pzo b1, f, f1; // convert two fp32 values to packed fp16 outputs with .relu saturation on each output and produce positive zero’s only
Convert two 32-bit integers a and b into specified type and pack the results into d.
Destination d is an unsigned 32-bit integer. Source operands a and b are integers of
type .abType and the source operand c is an integer of type .cType.
The inputs a and b are converted to values of type specified by .convertType with
saturation and the results after conversion are packed into lower bits of d.
If operand c is specified then remaining bits of d are copied from lower bits of c.
Semantics
ta = a < MIN(convertType) ? MIN(convertType) : a;
ta = a > MAX(convertType) ? MAX(convertType) : a;
tb = b < MIN(convertType) ? MIN(convertType) : b;
tb = b > MAX(convertType) ? MAX(convertType) : b;
size = sizeInBits(convertType);
td = tb ;
for (i = size; i <= 2 * size - 1; i++) {
td[i] = ta[i - size];
}
if (isU16(convertType) || isS16(convertType)) {
d = td;
} else {
for (i = 0; i < 2 * size; i++) {
d[i] = td[i];
}
for (i = 2 * size; i <= 31; i++) {
d[i] = c[i - 2 * size];
}
}
.sat modifier limits the converted values to MIN(convertType).. MAX(convertedType) (no
overflow) if the corresponding inputs are not in the range of datatype specified as
.convertType.
Get address in the CTA specified by operand b which corresponds to the address specified by
operand a.
Instruction type .type indicates the type of the destination operand d and the source
operand a.
When space is .shared::cluster, source a is either a shared memory variable or a register
containing a valid shared memory address and register d contains a shared memory address. When
the optional qualifier .space is not specified, both a and d are registers containing
generic addresses pointing to shared memory.
b is a 32-bit integer operand representing the rank of the target CTA.
Destination register d will hold an address in CTA b corresponding to operand a.
Write the destination register d with the rank of the CTA which contains the address specified
in operand a.
Instruction type .type indicates the type of source operand a.
When space is .shared::cluster, source a is either a shared memory variable or a register
containing a valid shared memory address. When the optional qualifier .space is not specified,
a is a register containing a generic addresses pointing to shared memory. Destination d is
always a 32-bit register which holds the rank of the CTA.
9.7.10.28. Data Movement and Conversion Instructions: Asynchronous copy#
An asynchronous copy operation performs the underlying operation asynchronously in the background,
thus allowing the issuing threads to perform subsequent tasks.
An asynchronous copy operation can be a bulk operation that operates on a large amount of data, or
a non-bulk operation that operates on smaller sized data. The amount of data handled by a bulk
asynchronous operation must be a multiple of 16 bytes.
An asynchronous copy operation typically includes the following sequence:
Optionally, reading from the tensormap.
Reading data from the source location(s).
Writing data to the destination location(s).
Writes being made visible to the executing thread or other threads.
9.7.10.28.1. Completion Mechanisms for Asynchronous Copy Operations#
A thread must explicitly wait for the completion of an asynchronous copy operation in order to
access the result of the operation. Once an asynchronous copy operation is initiated, modifying the
source memory location or tensor descriptor or reading from the destination memory location before
the asynchronous operation completes, exhibits undefined behavior.
This section describes two asynchronous copy operation completion mechanisms supported in PTX:
Async-group mechanism and mbarrier-based mechanism.
Asynchronous operations may be tracked by either of the completion mechanisms or both mechanisms.
The tracking mechanism is instruction/instruction-variant specific.
When using the async-group completion mechanism, the issuing thread specifies a group of
asynchronous operations, called async-group, using a commit operation and tracks the completion
of this group using a wait operation. The thread issuing the asynchronous operation must create
separate async-groups for bulk and non-bulk asynchronous operations.
A commit operation creates a per-thread async-group containing all prior asynchronous operations
tracked by async-group completion and initiated by the executing thread but none of the asynchronous
operations following the commit operation. A committed asynchronous operation belongs to a single
async-group.
When an async-group completes, all the asynchronous operations belonging to that group are
complete and the executing thread that initiated the asynchronous operations can read the result of
the asynchronous operations. All async-groups committed by an executing thread always complete in
the order in which they were committed. There is no ordering between asynchronous operations within
an async-group.
A typical pattern of using async-group as the completion mechanism is as follows:
Initiate the asynchronous operations.
Group the asynchronous operations into an async-group using a commit operation.
Wait for the completion of the async-group using the wait operation.
Once the async-group completes, access the results of all asynchronous operations in that
async-group.
A thread can track the completion of one or more asynchronous operations using the current phase of
an mbarrier object. When the current phase of the mbarrier object is complete, it implies that
all asynchronous operations tracked by this phase are complete, and all threads participating in
that mbarrier object can access the result of the asynchronous operations.
The mbarrier object to be used for tracking the completion of an asynchronous operation can be
either specified along with the asynchronous operation as part of its syntax, or as a separate
operation. For bulk asynchronous operations and fabric operations, the mbarrier object must be specified in the
asynchronous operation, whereas for non-bulk operations, it can be specified after the asynchronous
operation.
A typical pattern of using mbarrier-based completion mechanism is as follows:
Initiate the asynchronous operations.
Set up an mbarrier object to track the asynchronous operations in its current phase, either as
part of the asynchronous operation or as a separate operation.
Wait for the mbarrier object to complete its current phase using mbarrier.test_wait or
mbarrier.try_wait.
Once the mbarrier.test_wait or mbarrier.try_wait operation returns True, access the
results of the asynchronous operations tracked by the mbarrier object.
9.7.10.28.1.3. Report Mechanisms for Asynchronous Copy Operations#
Asynchronous copy operations with copy-direction from .global to .shared::cta or
.shared::cluster support reporting data validity through an mbarrier object.
When the qualifier .report_mechanism is specified, the copy operation inspects the data
being copied and signals a report-on
operation on the mbarrier if the data matches the pattern as specified in the qualifier.
To avoid data inspection, the report mechanism must be set to .mbarrier::report::disabled.
When the report mechanism is unspecified, it defaults to .mbarrier::report::disabled.
The granularity of the data inspection is also specified as part of the qualifier.
Note that when the .report_mechanism is specified for data inspection, the associated
mbarrier operand must have been initialized with the layout .layout::v1, otherwise the
behavior is undefined. For more details on mbarrier layout, refer
Layouts of the mbarrier object.
Table 33 Report mechanisms for asynchronous copy operations
Report mechanism
.mbarrier::report::validity
Elmemt
format
Matching
bit pattern
Granularity of the
source data that is
written into
Details of data
inspection
Result of inspection
::disabled
N/A
N/A
N/A
No inspection
N/A
::per_16bytes
::80000000
FP32
-0
16 bytes of 4 FP32
elements
A sampled element
from the aligned 16
byte chunk of the
source global memory
is matched with the
Matching bit-pattern
If the pattern matches,
issues a report-on
operation on the
mbarrier to update the
payload report to a
non-zero value. In
particular, the report
predicate is modified
to non-zero value;
whereas report value
is altered in an
idempotent way
(atomically OR’ed with
0)
::8000
FP16
16 bytes of 8 FP16
elements
::80
FP8
16 bytes of 16 FP8
elements
::8
FP4
16 bytes of 32 FP4
elements
::per_element
::ff
8bit/
4bit
NaN / 0xF
1 byte
Each element
is matched with the
Matching bit-pattern
The cp{.reduce}.async.bulk operations are performed in the asynchronous proxy (or async
proxy).
Accessing the same memory location across multiple proxies needs a cross-proxy fence. For the
async proxy, fence.proxy.async should be used to synchronize memory between generic
proxy and the async proxy.
The completion of a cp{.reduce}.async.bulk operation is followed by an implicit generic-async
proxy fence. So the result of the asynchronous operation is made visible to the generic proxy as
soon as its completion is observed. Async-group OR mbarrier-based completion mechanism must
be used to wait for the completion of the cp{.reduce}.async.bulk instructions.
9.7.10.28.3. Data Movement and Conversion Instructions: Non-bulk copy#
9.7.10.28.3.1. Data Movement and Conversion Instructions: cp.async#
cp.async
Initiates an asynchronous copy operation from one state space to another.
cp.async is a non-blocking instruction which initiates an asynchronous copy operation of data
from the location specified by source address operand src to the location specified by
destination address operand dst. Operand src specifies a location
in the global state space and dst specifies a location in the shared state space.
Operand cp-size is an integer constant which specifies the size of data in bytes to be copied to
the destination dst. cp-size can only be 4, 8 and 16.
Instruction cp.async allows optionally specifying a 32-bit integer operand src-size. Operand
src-size represents the size of the data in bytes to be copied from src to dst and must
be less than cp-size. In such case, remaining bytes in destination dst are filled with
zeros. Specifying src-size larger than cp-size results in undefined behavior.
The optional and non-immediate predicate argument ignore-src specifies whether the data from the
source location src should be ignored completely. If the source data is ignored then zeros will
be copied to destination dst. If the argument ignore-src is not specified then it defaults
to False.
Supported alignment requirements and addressing modes for operand src and dst are described
in Addresses as Operands.
The mandatory .async qualifier indicates that the cp instruction will initiate the memory
copy operation asynchronously and control will return to the executing thread before the copy
operation is complete. The executing thread can then use
async-group based completion mechanism
or the mbarrier based completion mechanism
to wait for completion of the asynchronous copy operation.
No other synchronization mechanism guarantees the completion of the asynchronous
copy operations.
There is no ordering guarantee between two cp.async operations if they are not explicitly
synchronized using cp.async.wait_all or cp.async.wait_group or mbarrier instructions.
As described in Cache Operators, the .cg qualifier indicates
caching of data only at global level cache L2 and not at L1 whereas .ca qualifier indicates
caching of data at all levels including L1 cache. Cache operator are treated as performance hints
only.
cp.async is treated as a weak memory operation performed in the generic proxy in the
Memory Consistency Model.
The .level::prefetch_size qualifier is a hint to fetch additional data of the specified size
into the respective cache level.The sub-qualifier prefetch_size can be set to either of 64B,
128B, 256B thereby allowing the prefetch size to be 64 Bytes, 128 Bytes or 256 Bytes
respectively.
The qualifier .level::prefetch_size may only be used with .global state space and with
generic addressing where the address points to .global state space. If the generic address does
not fall within the address window of the global memory, then the prefetching behavior is undefined.
The .level::prefetch_size qualifier is treated as a performance hint only.
When the optional argument cache_policy is specified, the qualifier .level::cache_hint is
required. The 64-bit operand cache_policy specifies the cache eviction policy that may be used
during the memory access.
The qualifier .level::cache_hint is only supported for .global state space and for generic
addressing where the address points to the .global state space.
cache_policy is a hint to the cache subsystem and may not always be respected. It is treated as
a performance hint only, and does not change the memory consistency behavior of the program.
9.7.10.28.3.2. Data Movement and Conversion Instructions: cp.async.commit_group#
cp.async.commit_group
Commits all prior initiated but uncommitted cp.async instructions into a cp.async-group.
Syntax
cp.async.commit_group ;
Description
cp.async.commit_group instruction creates a new cp.async-group per thread and batches all
prior cp.async instructions initiated by the executing thread but not committed to any
cp.async-group into the new cp.async-group. If there are no uncommitted cp.async
instructions then cp.async.commit_group results in an empty cp.async-group.
An executing thread can wait for the completion of all cp.async operations in a cp.async-group
using cp.async.wait_group.
There is no memory ordering guarantee provided between any two cp.async operations within the
same cp.async-group. So two or more cp.async operations within a cp.async-group copying data
to the same location results in undefined behavior.
Examples
// Example 1:
cp.async.ca.shared.global [shrd], [gbl], 4;
cp.async.commit_group ; // Marks the end of a cp.async group
// Example 2:
cp.async.ca.shared.global [shrd1], [gbl1], 8;
cp.async.ca.shared.global [shrd1+8], [gbl1+8], 8;
cp.async.commit_group ; // Marks the end of cp.async group 1
cp.async.ca.shared.global [shrd2], [gbl2], 16;
cp.async.cg.shared.global [shrd2+16], [gbl2+16], 16;
cp.async.commit_group ; // Marks the end of cp.async group 2
9.7.10.28.3.3. Data Movement and Conversion Instructions: cp.async.wait_group / cp.async.wait_all#
cp.async.wait_group, cp.async.wait_all
Wait for completion of prior asynchronous copy operations.
Syntax
cp.async.wait_group N;
cp.async.wait_all ;
Description
cp.async.wait_group instruction will cause executing thread to wait till only N or fewer of
the most recent cp.async-groups are pending and all the prior cp.async-groups committed by
the executing threads are complete. For example, when N is 0, the executing thread waits on all
the prior cp.async-groups to complete. Operand N is an integer constant.
cp.async.wait_all is equivalent to :
cp.async.commit_group;
cp.async.wait_group 0;
An empty cp.async-group is considered to be trivially complete.
Writes performed by cp.async operations are made visible to the executing thread only after:
The completion of cp.async.wait_all or
The completion of cp.async.wait_group on the cp.async-group in which the cp.async
belongs to or
There is no ordering between two cp.async operations that are not synchronized with
cp.async.wait_all or cp.async.wait_group or mbarrier objects.
cp.async.wait_group and cp.async.wait_all does not provide any ordering and visibility
guarantees for any other memory operation apart from cp.async.
Examples
// Example of .wait_all:
cp.async.ca.shared.global [shrd1], [gbl1], 4;
cp.async.cg.shared.global [shrd2], [gbl2], 16;
cp.async.wait_all; // waits for all prior cp.async to complete
// Example of .wait_group :
cp.async.ca.shared.global [shrd3], [gbl3], 8;
cp.async.commit_group; // End of group 1
cp.async.cg.shared.global [shrd4], [gbl4], 16;
cp.async.commit_group; // End of group 2
cp.async.cg.shared.global [shrd5], [gbl5], 16;
cp.async.commit_group; // End of group 3
cp.async.wait_group 1; // waits for group 1 and group 2 to complete
9.7.10.28.4. Data Movement and Conversion Instructions: Bulk copy#
9.7.10.28.4.1. Data Movement and Conversion Instructions: cp.async.bulk#
cp.async.bulk
Initiates an asynchronous copy operation from one state space to another.
cp.async.bulk is a non-blocking instruction which initiates an asynchronous bulk-copy operation
from the location specified by source address operand srcMem to the location specified by
destination address operand dstMem.
The direction of bulk-copy is from the state space specified by the .src modifier to the state
space specified by the .dst modifiers.
The 32-bit operand size specifies the amount of memory to be copied, in terms of number of
bytes. size must be a multiple of 16. If the value is not a multiple of 16, then the behavior is
undefined. The memory range [dstMem,dstMem+size-1] must not overflow the destination memory
space and the memory range [srcMem,srcMem+size-1] must not overflow the source memory
space. Otherwise, the behavior is undefined. The addresses dstMem and srcMem must be aligned
to 16 bytes.
The optional qualifier .ignore_oob specifies that up to 15 bytes at the beginning or ending of
[srcMem..srcMem+size) may be out-of-bounds of a global memory allocation, and the value of the
corresponding bytes in destination shared memory [dstMem..dstMem+size) is indeterminate.
The 32-bit operands ignoreBytesLeft and ignoreBytesRight are used to specify the bytes from
beginning and ending of the copy-chunk specified by size that may go out of bounds. The only valid
values for ignoreBytesLeft and ignoreBytesRight are [0..15], and any other value may
result in undefined behavior. The srcMem and dstMem addresses must be aligned to 16 bytes,
and the size operand must be a multiple of 16 even with .ignore_oob qualifier. The qualifier
.ignore_oob is only available for the global to .shared::cta copy direction.
In presence of .ignore_oob, the qualifier .report_mechanism, if specified, must be set to
.mbarrier::report::disabled.
When the destination of the copy is .shared::cta the destination address has to be in the shared
memory of the executing CTA within the cluster, otherwise the behavior is undefined.
When the source of the copy is .shared::cta and the destination is .shared::cluster, the
destination has to be in the shared memory of a different CTA within the cluster.
The modifier .completion_mechanism specifies the completion mechanism that is supported on the
instruction variant. The completion mechanisms that are supported for different variants are
summarized in the following table:
.completion-mechanism
.dst
.src
Completion mechanism
.mbarrier::...
.shared::cta
.global
mbarrier based
.shared::cluster
.global
.shared::cluster
.shared::cta
.bulk_group
.global
.shared::cta
Bulk async-group
based
The modifier .mbarrier::complete_tx::bytes specifies that the cp.async.bulk variant uses
mbarrier based completion mechanism. The complete-tx
operation, with completeCount argument equal to amount of data copied in bytes, will be
performed on the mbarrier object specified by the operand mbar.
This instruction accesses its mbarrier operand using generic-proxy.
The modifier .bulk_group specifies that the cp.async.bulk variant uses bulk async-group
based completion mechanism.
The optional qualifier .multicast::cluster allows copying of data from global memory to shared
memory of multiple CTAs in the cluster. Operand ctaMask specifies the destination CTAs in the
cluster such that each bit position in the 16-bit or otherwise 32-bit ctaMask operand corresponds
to the %cluster_ctarank of the destination CTA. The additional sub-qualifier ::16b or ::32b can be
specified to correspond to the width of the ctaMask argument. By default, ctaMask is assumed
to be of 16-bit width. The source data is multicast to the same CTA-relative offset as dstMem
in the shared memory of each destination CTA. The mbarrier signal is also multicast to the same
CTA-relative offset as mbar in the shared memory of the destination CTA.
When the optional argument cache_policy is specified, the qualifier .level::cache_hint is
required. The 64-bit operand cache_policy specifies the cache eviction policy that may be used
during the memory access.
cache_policy is a hint to the cache subsystem and may not always be respected. It is treated as
a performance hint only, and does not change the memory consistency behavior of the program. The
qualifier .level::cache_hint is only supported when at least one of the .src or .dst
statespaces is .global state space.
When the optional qualifier .cp_mask is specified, the argument byteMask is required.
The i-th bit in the 16-bit wide byteMask operand specifies whether the i-th byte of each 16-byte
wide chunk of source data is copied to the destination. If the bit is set, the byte is copied.
The optional .sem modifier specifies the memory ordering semantics as described in the
Memory Consistency Model.
When .sem is not specified, it defaults to .weak.
When .sem is .weak, the data copy operation accesses memory with weak memory operations.
When .sem is .relaxed, the data copy accesses memory with naturally-aligned strong memory operations
with element-wise atomic size specified by .type and thread scope specified by .scope.
// Validity check using 0x8000 pattern on every 16B
cp.async.bulk.shared::cluster.global.mbarrier::complete_tx::bytes.mbarrier::report::validity::per_16bytes::8000
[dstMem], [srcMem], size, [mbar];
// .global -> .shared::cta with .relaxed scope and .b128 type
cp.async.bulk.relaxed.shared::cta.global.mbarrier::complete_tx::bytes.b128 [dstMem], [srcMem], size, [mbar];
cp.reduce.async.bulk is a non-blocking instruction which initiates an asynchronous reduction
operation on an array of memory locations specified by the destination address operand dstMem
with the source array whose location is specified by the source address operand srcMem. The size
of the source and the destination array must be the same and is specified by the operand size.
Each data element in the destination array is reduced inline with the corresponding data element in
the source array with the reduction operation specified by the modifier .redOp. The type of each
data element in the source and the destination array is specified by the modifier .type.
The source address operand srcMem is located in the state space specified by .src and the
destination address operand dstMem is located in the state specified by the .dst.
The 32-bit operand size specifies the amount of memory to be copied from the source location and
used in the reduction operation, in terms of number of bytes. size must be a multiple of 16. If
the value is not a multiple of 16, then the behavior is undefined. The memory range [dstMem,dstMem+size-1] must not overflow the destination memory space and the memory range [srcMem,srcMem+size-1] must not overflow the source memory space. Otherwise, the behavior is
undefined. The addresses dstMem and srcMem must be aligned to 16 bytes.
The operations supported by .redOp are classified as follows:
The bit-size operations are .and, .or, and .xor.
The integer operations are .add, .inc, .dec, .min, and .max. The .inc and
.dec operations return a result in the range [0..x] where x is the value at the source
state space.
The floating point operation .add rounds to the nearest even.
The cp.reduce.async.bulk.add.f16 and cp.reduce.async.bulk.add.bf16 operations require
.noftz qualifier. It preserves input and result subnormals, and does not flush them to zero.
The default behavior for cp.reduce.async.bulk.add.f32 is equivalent to specifying optional
.noftz qualifier which preserves input and result subnormals, and does not flush them to zero.
The following table describes the valid combinations of .redOp and element type:
.dst
.redOp
Element type
.shared::cluster
.add
.u32, .s32, .u64
.min, .max
.u32, .s32
.inc, .dec
.u32
.and, .or, .xor
.b32
.global
.add
.u32, .s32, .u64, .f32, .f64, .f16, .bf16
.min, .max
.u32, .s32, .u64, .s64, .f16, .bf16
.inc, .dec
.u32
.and, .or, .xor
.b32, .b64
The modifier .completion_mechanism specifies the completion mechanism that is supported on the
instruction variant. The completion mechanisms that are supported for different variants are
summarized in the following table:
.completion-mechanism
.dst
.src
Completion mechanism
.mbarrier::...
.shared::cluster
.global
mbarrier based
.shared::cluster
.shared::cta
.bulk_group
.global
.shared::cta
Bulk async-group
based
The modifier .mbarrier::complete_tx::bytes specifies that the cp.reduce.async.bulk variant
uses mbarrier based completion mechanism. The complete-tx
operation, with completeCount argument equal to amount of data copied in bytes, will be
performed on the mbarrier object specified by the operand mbar.
This instruction accesses its mbarrier operand using generic-proxy.
The modifier .bulk_group specifies that the cp.reduce.async.bulk variant uses bulk
async-group based completion mechanism.
When the optional argument cache_policy is specified, the qualifier .level::cache_hint is
required. The 64-bit operand cache_policy specifies the cache eviction policy that may be used
during the memory access.
cache_policy is a hint to the cache subsystem and may not always be respected. It is treated as
a performance hint only, and does not change the memory consistency behavior of the program. The
qualifier .level::cache_hint is only supported when at least one of the .src or .dst
statespaces is .global state space.
The optional .sem.scope qualifier specifies the memory ordering semantics of each individual
element-wise reduction in dstMem performed by this operation as described in the
Memory Consistency Model. These are element-wise atomic at the specified scope.
Source location accesses are .weak, that is, not atomic.
When .sem.scope is not specified, it defaults to .relaxed.sys.
The load operations from srcMem in cp.reduce.async.bulk are treated as weak
memory operation and the complete-tx
operation on the mbarrier has .release semantics at the .cluster scope as described in the
Memory Consistency Model. The memory operations are performed in the async proxy.
cp.async.bulk.prefetch is a non-blocking instruction which may initiate an asynchronous prefetch
of data from the location specified by source address operand srcMem, in .src statespace, to
the L2 cache.
The 32-bit operand size specifies the amount of memory to be prefetched in terms of number of
bytes. size must be a multiple of 16. If the value is not a multiple of 16, then the behavior is
undefined. The address srcMem must be aligned to 16 bytes.
When the optional argument cache_policy is specified, the qualifier .level::cache_hint is
required. The 64-bit operand cache_policy specifies the cache eviction policy that may be used
during the memory access.
cache_policy is a hint to the cache subsystem and may not always be respected. It is treated as
a performance hint only, and does not change the memory consistency behavior of the program.
Instruction multimem.cp.async.bulk initiates an asynchronous bulk-copy operation from source
address range [srcMem,srcMem+size) to memory locations residing on each GPU’s memory referred
to by the destination multimem address range [dstMem,dstMem+size). The direction of
bulk-copy is from the state space specified by the .src modifier to the state space specified
by the .dst modifiers.
The 32-bit operand size specifies the amount of memory to be copied, in terms of number of
bytes. Operand size must be a multiple of 16. The memory range [dstMem,dstMem+size)
must not overflow the destination multimem memory space. The memory range [srcMem,srcMem+size)
must not overflow the source memory space. The addresses dstMem and srcMem must be aligned
to 16 bytes. If any of these pre-conditions is not met, the behavior is undefined.
The modifier .completion_mechanism specifies the completion mechanism that is supported by the
instruction. The modifier .bulk_group specifies that the multimem.cp.async.bulk instruction
uses bulk async-group based completion mechanism.
When the optional modifier .cp_mask is specified, the argument byteMask is required. The
i-th bit in the 16-bit wide byteMask operand specifies whether the i-th byte of each 16-byte
wide chunk of source data is copied to the destination. If the bit is set, the byte is copied.
The optional .sem qualifier specifies the memory ordering semantics as described in the
Memory Consistency Model.
When .sem is not specified, it defaults to .weak.
When .sem is .weak, the data copy operation accesses memory with weak memory operations.
When .sem is .relaxed, the data copy accesses memory with naturally-aligned strong memory
operations with element-wise atomic size specified by .type and thread scope specified by .scope.
Instruction multimem.cp.reduce.async.bulk initiates an element-wise asynchronous reduction
operation with elements from source memory address range [srcMem,srcMem+size) to memory
locations residing on each GPU’s memory referred to by the multimem destination address range
[dstMem,dstMem+size).
Each data element in the destination array is reduced inline with the corresponding data element in
the source array with the reduction operation specified by the modifier .redOp. The type of each
data element in the source and the destination array is specified by the modifier .type.
The source address operand srcMem is in the state space specified by .src and the
destination address operand dstMem is in the state specified by the .dst.
The 32-bit operand size specifies the amount of memory to be copied from the source location
and used in the reduction operation, in terms of number of bytes. Operand size must be a
multiple of 16. The memory range [dstMem,dstMem+size) must not overflow the destination
multimem memory space. The memory range [srcMem,srcMem+size) must not overflow the source
memory space. The addresses dstMem and srcMem must be aligned to 16 bytes. If any of these
preconditions is not met, the behavior is undefined.
The operations supported by .redOp are classified as follows:
The bit-size operations are .and, .or, and .xor.
The integer operations are .add, .inc, .dec, .min, and .max. The .inc and
.dec operations return a result in the range [0..x] where x is the value at the source
state space.
The floating point operation .add rounds to the nearest even, preserve input and result
subnormals, and does not flush them to zero.
The multimem.cp.reduce.async.bulk.add.f16 and multimem.cp.reduce.async.bulk.add.bf16
operations require .noftz qualifier. It preserves input and result subnormals, and does
not flush them to zero.
The default behavior for multimem.cp.reduce.async.bulk.add.f32 is equivalent to specifying
optional .noftz qualifier which preserves input and result subnormals, and does not flush
them to zero.
The following table describes the valid combinations of .redOp and element type:
.redOp
element type
.add
.u32, .s32, .u64, .f32, .f64,
.f16, .bf16
.min,
.max
.u32, .s32, .u64, .s64, .f16,
.bf16
.inc,
.dec
.u32
.and,
.or,
.xor
.b32, .b64
The modifier .completion_mechanism specifies the completion mechanism that is supported by the
instruction. The modifier .bulk_group specifies that the multimem.cp.reduce.async.bulk uses
bulk async-group based completion mechanism.
The optional .sem.scope qualifier specifies the memory ordering semantics of each individual
element-wise reduction in dstMem performed by this operation as described in the
Memory Consistency Model. These are element-wise atomic at the specified scope.
Source location accesses are .weak, that is, not atomic.
When .sem.scope is not specified, it defaults to .relaxed.sys.
The load operations from srcMem in multimem.cp.reduce.async.bulk
are treated as weak memory operations as described in the Memory Consistency Model.
9.7.10.28.5. Data Movement and Conversion Instructions: Tensor copy#
9.7.10.28.5.1. Restriction on Tensor Copy instructions#
Following are the restrictions on the types .b4x16, .b4x16_p64, .b6x16_p32 and
.b6p2x16:
cp.reduce.async.bulk doesn’t support the types .b4x16, .b4x16_p64, .b6x16_p32
and .b6p2x16.
cp.async.bulk.tensor with the direction .global.shared::cta doesn’t support the
type .b4x16_p64.
cp.async.bulk.tensor with the direction .shared::cluster.global doesn’t support
the sub-byte types on sm_120a.
OOB-NaN fill mode doesn’t support the types .b4x16, .b4x16_p64, .b6x16_p32
and .b6p2x16.
Box-Size[0] must be exactly:
For b6x16_p32 and .b6p2x16:
128B for .shared::cluster.global and .shared::cta.global directions on sm_107f.
64B or 128B for .global.shared::cta direction on sm_107f.
96B on sm_100f.
64B for b4x16_p64.
Tensor-Size[0] must be a multiple of:
For b6x16_p32 and .b6p2x16:
128B for .shared::cluster.global and .shared::cta.global directions on sm_107f.
64B or 128B for .global.shared::cta direction on sm_107f.
96B on sm_100f.
64B for b4x16_p64.
For .b4x16_p64, .b6x16_p32 and .b6p2x16, the first coordinate in the tensorCoords
argument vector must be a multiple of 128.
For .b4x16_p64, .b6x16_p32 and .b6p2x16, the global memory address must be 32B aligned.
Additionally, tensor stride in every dimension must be 32B aligned.
For .b6x16_p32 and .b6p2x16:
On sm_107f, for .shared::cluster.global and .shared::cta.global directions,
the global memory address must be 32B aligned. Additionally, tensor stride in every dimension must be 32B aligned.
On sm_100f, the global memory address must be 32B aligned. Additionally, tensor stride in every dimension
must be 32B aligned.
For .b6x16_p32 and .b6p2x16:
On sm_107f, for .global.shared::cta direction, the global memory address must be 16B aligned.
Additionally, tensor stride in every dimension must be 16B aligned on.
On sm_100f, the global memory address must be 32B aligned. Additionally, tensor stride in every
dimension must be 32B aligned.
.b4x16_p64 supports the following swizzling modes:
None.
128B (With all potential swizzle atomicity values except: 32B with 8B flip)
.b6x16_p32 and .b6p2x16 supports the following swizzling modes:
None.
64-Byte with 16B atomic swizzling on sm_107f.
128-Byte with 16B, 32B and 64B atomic swizzling on sm_107f
128-Byte (With all potential swizzle atomicity values except: 32B with 8B flip) on sm_100f
.b6x16_p32 and .b6p2x16 doesn’t support the following swizzling modes:
32-Byte with 16B atomic swizzling
128-Byte with 32B atomic swizzling with 8B flip
Following are the restrictions on the 96B swizzle mode:
The .swizzle_atomicity must be 16B.
The .interleave_layout must not be set.
Box-Size[0] must be less than or equal to 96B.
The type must not be among following: .b4x16_p64, .b6x16_p32 and .b6p2x16.
The .load_mode must not be set to .im2col::w::128.
Following are the restrictions on the 128-byte swizzle mode having 32-byte atomicity with 8-byte flip as sub-mode:
The copy direction must be .shared::cluster.global or otherwise .shared::cta.global.
The .load_mode must not be set to .im2col::w, .im2col::w::128.
Following are the restrictions on the .global.shared::cta direction:
Starting co-ordinates for Bounding Box (tensorCoords) must be non-negative with
the following exception:
For sm_107f, starting co-ordinates for Bounding Box (tensorCoords) can be
negative for .tile::scatter4 mode.
The bounding box along the D, W and H dimensions must stay within the tensor boundaries.
This implies:
Bounding-Box Lower-Corner must be non-negative.
Bounding-Box Upper-Corner must be non-positive.
Following are the restrictions for sm_120a:
cp.async.bulk.tensor with the direction .shared::cluster.global doesn’t support:
the sub-byte types
the qualifier .swizzle_atomicity
Following are the restrictions for sm_103a while using type .b6p2x16 on
cp.async.bulk.tensor with the direction .global.shared::cta:
Box-Size[0] must be exactly either of 48B or 96B.
The global memory address must be 16B aligned.
Tensor Stride in every dimension must be 16B aligned.
The first coordinate in the tensorCoords argument vector must be a multiple of 64.
Tensor-Size[0] must be a multiple of 48B.
The following swizzle modes are supported:
None.
128B (With all potential swizzle atomicity values except: 32B with 8B flip)
PTX instructions operating on tensor data require an opaque tensor-map object. The
tensor-map specifies various properties associated with the tensor.
Certain PTX instructions, when qualified with .override::* qualifier, ignore a specific
property from the tensor-map; instead, the explicit instruction operand’s value is used
for that property. The following subsection describes semantics around overriding
various properties from the tensor-map object.
The optional qualifier .override::global_address allows overriding of the tensor base
address. When .override::global_address is specified, the global memory address present
in the opaque tensorMap object is ignored and instead the address specified by the
explicit 64-bit operand gAddrToOverride is used. The gAddrToOverride address must be
16B aligned; otherwise, a runtime error is raised.
Additionally, the memory address range [gAddrToOverride, gAddrToOverride + 128 KiB)
must be allocated and accessible during execution; otherwise, the behavior is undefined.
The optional qualifier .override_attribute allows overriding of tensor attributes.
The only attributes that are allowed to be overridden are global dimension (global_dim) and global
stride (global_stride). When the qualifier
.override_attribute is specified, attribute values from the tensorMap object are
ignored and values specified via the additional operand attributeOverrideInfo are used.
The following conditions must be satisfied for valid usage of
.override_attribute qualifier:
As part of tensor attributes override, the tensor base address override must also naturally follow.
In other words, while using .override_attribute qualifier, it is mandatory to also specify
.override::global_address qualifier.
The tensor data access mode must be tile. i.e. The qualifier .load_mode if specified must
be set to .tile.
If specified, the optional .multicast qualifier must be .multicast::cluster::32b.
Tensor start coordinates as specified by the operand tensorCoords must be zero,
otherwise the behavior is undefined.
The .override_attribute qualifier can take the following two values:
.override::global_dim and .override::global_dim_stride.
For .1d tensors, since stride is absent, only .override::global_dim is valid.
For tensors with dimensionality of at least 2, both dimension and stride must be overridden
together, so only .override::global_dim_stride is valid.
The form of the attributeOverrideInfo operand depends on the value used for the
.override_attribute qualifier and is summarized in the
Table 34.
When .override::global_dim is used, the operand tensorSizeToOverride specifies the new
value for dimension. In this case, the operand tensorSizeToOverride is a brace-enclosed
vector expression comprising singleton 8-bit or otherwise 16-bit register.
Note that, when .b16 register is specified, 8-bit value must be wrapped inside lower half
of the register operand. When .override::global_dim_stride is specified the operand
tensorSizeToOverride must be a vector expression with number of 8-bit or otherwise 16-bit
register elements exactly matching to the tensor dimensionality as specified by the qualifier .dim.
Note that, when vector comprising .b16 register is specified, 8-bit value must be wrapped
inside lower half of each of the register operand. In this case, additional operands
tensorLowerStrideToOverride and tensorUpperStrideToOverride specify the new values to be
used for tensor lower stride and tensor upper stride respectively. The tensorLowerStrideToOverride
is a brace-enclosed vector expression comprising of 32-bit registers. The vector size for
tensorLowerStrideToOverride must be one less than the tensor dimensionality as given by .dim.
The tensorUpperStrideToOverride operand must be single .b16 register holding at most four
4-bit tensor upper stride values. The total number of 4-bit tensor upper stride values packed within
the tensorUpperStrideToOverride operand must be one less than the tensor dimensionality given by
.dim otherwise the behavior is undefined. Any unused bits from tensorUpperStrideToOverride can
be populated with zero. As an example, when .dim is set to .4d, lower 12-bits from
tensorUpperStrideToOverride operand specify tensor upper stride values whereas upper 4-bits can
be set to zero.
Table 35 Operand type and size requirements for each component of attributeOverrideInfo
Component of attributeOverrideInfo
Nature of the operand
tensorSizeToOverride
Vector expression comprising .dim
many elements of type .b8 or .b16.
For .b16 register, the value must
reside within the lower 8-bits of operand.
tensorLowerStrideToOverride
Vector expression of size .dim-1
where each element is of type .b32.
tensorUpperStrideToOverride
Single .b16 packed register storing
.dim-1 values. Each value is of type
.b4. Unused bits must be set to 0.
For each tensor dimension, the values specified for tensorLowerStrideToOverride and
tensorUpperStrideToOverride are operated as shown in the below equation to compute the
effective global stride (global_stride) value to be used instead of the one already present
in the tensorMap object.
cp.async.bulk.tensor is a non-blocking instruction which initiates an asynchronous copy
operation of tensor data from the location in .src state space to the location in the .dst
state space.
The operand dstMem specifies the location in the .dst state space into which the tensor data
has to be copied and srcMem specifies the location in the .src state space from which the
tensor data has to be copied.
When .dst is specified as .shared::cta, the address dstMem must be in the shared memory
of the executing CTA within the cluster, otherwise the behavior is undefined. When .dst is
.shared::cta, the mbarrier object mbar must also reside in the shared memory of the
executing CTA, otherwise behavior is undefined. If the mbarrier object mbar resides in the
shared memory of a different CTA within the cluster (a remote barrier), .dst must be
specified as .shared::cluster, otherwise behavior is undefined.
When .dst is specified as .shared::cluster, the address dstMem can be in the shared memory
of any of the CTAs within the current cluster.
The operand tensorMap is the generic address of the opaque tensor-map object which resides
in .param space or .const space or .global space. The operand tensorMap specifies
the properties of the tensor copy operation, as described in Tensor-map.
The tensorMap is accessed in tensormap proxy. Refer to the CUDA programming guide for creating
the tensor-map objects on the host side.
The dimension of the tensor data is specified by the .dim modifier.
The vector operand tensorCoords specifies the starting coordinates in the tensor data in the
global memory from or to which the copy operation has to be performed. The individual tensor
coordinates in tensorCoords are of type .s32. The format of vector argument tensorCoords
is dependent on .load_mode specified and is as follows:
.load_mode
tensorCoords
Semantics
.tile::scatter4
{col_idx, row_idx0, row_idx1, row_idx2, row_idx3}
Fixed length vector of size 5.
The five elements together specify the start
co-ordinates of the four rows.
.tile::gather4
Rest all
{d0, .., dn}
for n = .dim
Vector of n elements where n = .dim.
The elements indicate the offset in each of the
dimension.
The modifier .completion_mechanism specifies the completion mechanism that is supported on the
instruction variant. The completion mechanisms that are supported for different variants are
summarized in the following table:
.completion-mechanism
.dst
.src
Completion mechanism
Needed for completion of
entire Async operation
optionally can be used for the completion of
reading of the tensormap object
.mbarrier::...
.shared::cta
.global
mbarrier based
Bulk async-group based
.shared::cluster
.global
.bulk_group
.global
.shared::cta
Bulk async-group
based
The modifier .mbarrier::complete_tx::bytes specifies that the cp.async.bulk.tensor variant
uses mbarrier based completion mechanism. Upon the completion of the asynchronous copy operation, the
complete-tx
operation, with completeCount argument equal to amount of data copied in bytes, will be
performed on the mbarrier object specified by the operand mbar.
This instruction accesses its mbarrier operand using generic-proxy.
When the mbarrier object mbar resides in the shared memory of a different CTA within the
cluster (a remote barrier), .dst must be specified as .shared::cluster; using
.shared::cta as .dst in this case will not signal the remote barrier and results in
undefined behavior.
The modifier .cta_group can only be specified with the mbarrier based completion mechanism. The
modifier .cta_group is used to signal either the odd numbered CTA or the even numbered CTA among
the CTA-Pair. When .cta_group::1 is specified, the mbarrier object mbar
that is specified must be in the shared memory of the same CTA as the shared memory destination dstMem.
When .cta_group::2 is specified, the mbarrier object mbar can be in shared memory of either the
same CTA as the shared memory destination dstMem or in its peer-CTA. If
.cta_group is not specified, then it defaults to .cta_group::1.
The modifier .bulk_group specifies that the cp.async.bulk.tensor variant uses bulk
async-group based completion mechanism.
The qualifier .load_mode specifies how the data in the source location is copied into the
destination location. If .load_mode is not specified, it defaults to .tile.
In .tile mode, the multi-dimensional layout of the source tensor is preserved at the destination.
In .tile::gather4 mode, four rows in 2-dimensional source tensor are combined to form a single 2-dimensional
destination tensor. In .tile::scatter4 mode, single 2-dimensional source tensor is divided into four rows
in 2-dimensional destination tensor. Details of .tile::scatter4/.tile::gather4 modes are described
in .tile::scatter4 and .tile::gather4 modes.
In .im2col, .im2col::*, .im2col_no_offs and .im2col_no_offs::w modes, some dimensions of the
source tensors are unrolled in a single dimensional column at the destination.
Details of various im2col modes are described
in im2col mode. In each of these modes, the tensor has to be at least 3-dimensional. The vector
operand im2colInfo can be specified only when .load_mode is .im2col or .im2col::w or
.im2col::w::128. The format of the vector argument im2colInfo is dependent on the exact im2col mode
and is as follows:
Exact im2col mode
im2colInfo argument
Semantics
.im2col
{ i2cOffW , i2cOffH , i2cOffD }
for .dim = .5d
A vector of im2col offsets whose vector size is two
less than number of dimensions .dim.
.im2col::w
{ wHalo, wOffset }
A vector of 2 arguments containing
wHalo and
wOffset
arguments.
.im2col::w::128
.im2col_no_offs
im2colInfo is not applicable.
im2colInfo is not applicable.
.im2col_no_offs::w
im2colInfo is not applicable.
im2colInfo is not applicable. wHalo and
wOffset values default to 0.
Argument wHalo is a 16bit unsigned integer whose valid set of values differs on the load-mode and is as follows:
- Im2col::w mode : valid range is [0, 512).
- Im2col::w::128 mode : valid range is [0, 32).
Argument wOffset is a 16bit unsigned integer whose valid range of values is [0, 32).
The optional qualifier .multicast::cluster allows copying of data from global memory to shared
memory of multiple CTAs in the cluster. Operand ctaMask specifies the destination CTAs in the
cluster such that each bit position in the 16-bit or otherwise 32-bit ctaMask operand corresponds
to the %cluster_ctarank of the destination CTA. The additional sub-qualifier ::16b or ::32b can be
specified to correspond to the width of the ctaMask argument. By default, ctaMask is assumed
to be of 16-bit width. The source data is multicast to the same offset as dstMem in the shared
memory of each destination CTA. When .cta_group is specified as:
.cta_group::1 : The mbarrier signal is multicast to the same shared memory offset
as mbar in the destination CTA.
.cta_group::2 : The mbarrier signal is multicast either to all the odd-numbered CTAs or
even-numbered CTAs for each possible CTA-Pair within a cluster. In particular,
for each destination CTA specified in the ctaMask, the mbarrier signal is sent either to the
destination CTA or its peer-CTA based on the %cluster_ctarank parity of the shared memory where
the mbarrier object mbar resides.
The optional modifiers .override::global_address and .override_attribute support value
override functionality for various tensor properties present in the tensorMap object. For more
details refer to the Overriding tensor property value
section.
When the optional argument cache_policy is specified, the qualifier .level::cache_hint is
required. The 64-bit operand cache_policy specifies the cache eviction policy that may be used
during the memory access.
cache_policy is a hint to the cache subsystem and may not always be respected. It is treated as
a performance hint only, and does not change the memory consistency behavior of the program.
The copy operation in cp.async.bulk.tensor is treated as a weak memory operation and the
complete-tx
operation on the mbarrier has .release semantics at the .cluster scope as described in the
Memory Consistency Model.
// Validity check using 0x8 pattern on every 16B
cp.async.bulk.tensor.1d.shared::cluster.global.mbarrier::complete_tx::bytes.mbarrier::report::validity::per_16bytes::8 [sMem], [tensorDesc, {u}], [mbar];
// Validity check using 0xff pattern on per element
cp.async.bulk.tensor.2d.shared::cluster.global.tile::gather4.mbarrier::complete_tx::bytes.mbarrier::report::validity::per_element::ff
[sMem], [tensorDesc, {u, v, w, x, y}], [mbar];
9.7.10.28.5.4. Data Movement and Conversion Instructions: cp.reduce.async.bulk.tensor#
cp.reduce.async.bulk.tensor
Initiates an asynchronous reduction operation on the tensor data.
cp.reduce.async.bulk.tensor is a non-blocking instruction which initiates an asynchronous
reduction operation of tensor data in the .dst state space with tensor data in the .src
state space.
The operand srcMem specifies the location of the tensor data in the .src state space using
which the reduction operation has to be performed.
The operand tensorMap is the generic address of the opaque tensor-map object which resides
in .param space or .const space or .global space. The operand tensorMap specifies
the properties of the tensor copy operation, as described in Tensor-map.
The tensorMap is accessed in tensormap proxy. Refer to the CUDA programming guide for creating
the tensor-map objects on the host side.
Each element of the tensor data in the .dst state space is reduced inline with the corresponding
element from the tensor data in the .src state space. The modifier .redOp specifies the
reduction operation used for the inline reduction. The type of each tensor data element in the
source and the destination tensor is specified in Tensor-map.
The dimension of the tensor is specified by the .dim modifier.
The vector operand tensorCoords specifies the starting coordinates of the tensor data in the
global memory on which the reduce operation is to be performed. The number of tensor coordinates in
the vector argument tensorCoords should be equal to the dimension specified by the modifier
.dim. The individual tensor coordinates are of the type .s32.
The following table describes the valid combinations of .redOp and element type:
.redOp
Element type
.add
.u32, .s32, .u64, .f32, .f16, .bf16
.min, .max
.u32, .s32, .u64, .s64, .f16, .bf16
.inc, .dec
.u32
.and, .or, .xor
.b32, .b64
The modifier .completion_mechanism specifies the completion mechanism that is supported on the
instruction variant. Value .bulk_group of the modifier .completion_mechanism specifies that
cp.reduce.async.bulk.tensor instruction uses bulk async-group based completion mechanism.
The qualifier .load_mode specifies how the data in the source location is copied into the
destination location. If .load_mode is not specified, it defaults to .tile. In .tile
mode, the multi-dimensional layout of the source tensor is preserved at the destination. In
.im2col_no_offs and .im2col_no_offs::w modes, some dimensions of the source tensors are
unrolled in a single dimensional column at the destination. Details of the im2col mode are
described in im2col mode. In .im2col mode, the tensor has to be at least
3-dimensional.
The optional qualifiers .override::global_address and .override_attribute support value
override functionality for various tensor properties present in the tensorMap object. For more
details refer to the Overriding tensor property value
section.
When the optional argument cache_policy is specified, the qualifier .level::cache_hint is
required. The 64-bit operand cache_policy specifies the cache eviction policy that may be used
during the memory access.
cache_policy is a hint to the cache subsystem and may not always be respected. It is treated as
a performance hint only, and does not change the memory consistency behavior of the program. The
qualifier .level::cache_hint is only supported when at least one of the .src or .dst
statespaces is .global state space.
Each reduction operation performed by cp.reduce.async.bulk.tensor has individually
.relaxed.gpu memory ordering semantics and are element-wise atomic.
The load operations in cp.reduce.async.bulk.tensor
are treated as weak memory operations and the complete-tx
operation on the mbarrier has .release semantics at the .cluster scope as described in the
Memory Consistency Model.
cp.async.bulk.prefetch.tensor is a non-blocking instruction which may initiate an asynchronous
prefetch of tensor data from the location in .src statespace to the L2 cache.
The operand tensorMap is the generic address of the opaque tensor-map object which resides
in .param space or .const space or .global space. The operand tensorMap specifies
the properties of the tensor copy operation, as described in Tensor-map.
The tensorMap is accessed in tensormap proxy. Refer to the CUDA programming guide for creating
the tensor-map objects on the host side.
The dimension of the tensor data is specified by the .dim modifier.
The vector operand tensorCoords specifies the starting coordinates in the tensor data in the
global memory from which the copy operation has to be performed. The individual tensor
coordinates in tensorCoords are of type .s32. The format of vector argument tensorCoords
is dependent on .load_mode specified and is as follows:
.load_mode
tensorCoords
Semantics
.tile::gather4
{col_idx, row_idx0, row_idx1, row_idx2, row_idx3}
Fixed length vector of size 5.
The five elements together specify the start
co-ordinates of the four rows.
Rest all
{d0, .., dn}
for n = .dim
Vector of n elements where n = .dim.
The elements indicate the offset in each of the
dimension.
The qualifier .load_mode specifies how the data in the source location is copied into the
destination location. If .load_mode is not specified, it defaults to .tile.
In .tile mode, the multi-dimensional layout of the source tensor is preserved at the destination.
In .tile::gather4 mode, four rows in the 2-dimensional source tensor are fetched to L2 cache.
Details of .tile::gather4 modes are described
in .tile::scatter4 and .tile::gather4 modes.
In .im2col and .im2col::* modes, some dimensions of the source tensors are unrolled in a single
dimensional column at the destination. Details of the im2col and .im2col::* modes are described in
im2col mode and im2col::w, im2col_no_offs::w and im2col::w::128 modes
respectively. In .im2col and .im2col::* modes, the tensor has to be at least 3-dimensional. The vector
operand im2colInfo can be specified only when .load_mode is .im2col or .im2col::w or
.im2col::w::128. The format of the vector argument im2colInfo is dependent on the exact im2col mode
and is as follows:
Exact im2col mode
im2colInfo argument
Semantics
.im2col
{ i2cOffW , i2cOffH , i2cOffD }
for .dim = .5d
A vector of im2col offsets whose vector size is two
less than number of dimensions .dim.
.im2col::w
{ wHalo, wOffset }
A vector of 2 arguments containing
wHalo and
wOffset
arguments.
.im2col::w::128
The optional qualifiers .override::global_address and .override_attribute support value
override functionality for various tensor properties present in the tensorMap object. For more
details refer to the Overriding tensor property value
section.
When the optional argument cache_policy is specified, the qualifier .level::cache_hint is
required. The 64-bit operand cache_policy specifies the cache eviction policy that may be used
during the memory access.
cache_policy is a hint to the cache subsystem and may not always be respected. It is treated as
a performance hint only, and does not change the memory consistency behavior of the program.
Qualifier .level::eviction_priority specifies the eviction priority to be applied
for the prefetched cache line.
cp.async.bulk.prefetch.tensor is treated as a weak memory operation in the
Memory Consistency Model.
9.7.10.28.6. Data Movement and Conversion Instructions: Bulk and Tensor copy completion instructions#
9.7.10.28.6.1. Data Movement and Conversion Instructions: cp.async.bulk.commit_group#
cp.async.bulk.commit_group
Commits all prior initiated but uncommitted cp.async.bulk instructions into a
cp.async.bulk-group.
Syntax
cp.async.bulk.commit_group;
Description
cp.async.bulk.commit_group instruction creates a new per-thread bulk async-group and batches
all prior cp{.reduce}.async.bulk{.prefetch}{.tensor}/applypriority.async.bulk{.tensor}
instructions satisfying the following conditions into the new bulk async-group:
The prior cp{.reduce}.async.bulk{.prefetch}{.tensor}/applypriority.async.bulk{.tensor}
instructions use bulk_group based completion mechanism, and
They are initiated by the executing thread but not committed to any bulk async-group.
If there are no uncommitted cp{.reduce}.async.bulk{.prefetch}{.tensor}/applypriority.async.bulk{.tensor}
instructions then cp.async.bulk.commit_group results in an empty bulk async-group.
An executing thread can wait for the completion of all
cp{.reduce}.async.bulk{.prefetch}{.tensor}/applypriority.async.bulk{.tensor}
operations in a bulk async-group using cp.async.bulk.wait_group.
There is no memory ordering guarantee provided between any two
cp{.reduce}.async.bulk{.prefetch}{.tensor}/applypriority.async.bulk{.tensor} operations within
the same bulk async-group.
Examples
cp.async.bulk.commit_group;
9.7.10.28.6.2. Data Movement and Conversion Instructions: cp.async.bulk.wait_group#
cp.async.bulk.wait_group
Wait for completion of bulk async-groups.
Syntax
cp.async.bulk.wait_group{.read} N;
Description
cp.async.bulk.wait_group instruction will cause the executing thread to wait until only N or
fewer of the most recent bulk async-groups are pending and all the prior bulk async-groups
committed by the executing threads are complete. For example, when N is 0, the executing thread
waits on all the prior bulk async-groups to complete. Operand N is an integer constant.
By default, cp.async.bulk.wait_group instruction will cause the executing thread to wait until
completion of all the bulk async operations in the specified bulk async-group. A bulk async
operation includes the following:
Optionally, reading from the tensormap.
Reading from the source locations.
Writing to their respective destination locations.
Writes being made visible to the executing thread.
The optional .read modifier indicates that the waiting has to be done until all the bulk
async operations in the specified bulk async-group have completed:
The tensormap.replace instruction replaces the field, specified by .field qualifier,
of the tensor-map object at the location specified by the address operand addr with a
new value. The new value is specified by the argument new_val.
Qualifier .mode specifies the mode of the tensor-map object
located at the address operand addr.
Instruction type .b1024 indicates the size of the tensor-map
object, which is 1024 bits.
Operand new_val has the type .type. When .field is specified as .global_address
or .global_stride, .type must be .b64. Otherwise, .type must be .b32.
The immediate integer operand ord specifies the ordinal of the field across the rank of the
tensor which needs to be replaced in the tensor-map object. The only valid
values for ord are [0..4].
For field .rank, the operand new_val must be ones less than the desired tensor rank as
this field uses zero-based numbering.
When .field3 is specified, the operand new_val must be an immediate and the
Table 36 shows the mapping of the operand new_val across various fields.
Table 36 Tensormap new_val validity
new_val
.field3
.elemtype
.interleave_layout
.swizzle_mode
.swizzle_atomicity
.fill_mode
0
.u8
No interleave
No swizzling
16B
Zero fill
1
.u16
16B interleave
32B swizzling
32B
OOB-NaN fill
2
.u32
32B interleave
64B swizzling
32B + 8B flip
x
3
.s32
x
128B swizzling
64B
x
4
.u64
x
96B swizzling
x
x
5
.s64
x
x
x
x
6
.f16
x
x
x
x
7
.f32
x
x
x
x
8
.f32.ftz
x
x
x
x
9
.f64
x
x
x
x
10
.bf16
x
x
x
x
11
.tf32
x
x
x
x
12
.tf32.ftz
x
x
x
x
13
.b4x16
x
x
x
x
14
.b4x16_p64
x
x
x
x
15
.b6x16_p32
or
.b6p2x16
x
x
x
x
Note
The values of .elemtype do not correspond to the values of the CUtensorMapDataType enum used in the driver API.
If no state space is specified then Generic Addressing is used.
If the address specified by addr does not fall within the address window of .global
or .shared::cta state space then the behavior is undefined.
tensormap.replace is treated as a weak memory operation, on the entire 1024-bit opaque
tensor-map object, in the Memory Consistency Model.
The spcompress instruction copies elements from a dense vector data to
form the structured sparse compressed vector cdata. The resulting metadata is written to
the vector operand mdata.
The compression factor is specified using qualifier .spfactor. The only allowed value
for .spfactor is .sp::2:4 resulting in 2:4 compression for a dense input vector.
In this case, 2 elements per 4 group of elements from data would be selected and copied
into cdata. The output vector mdata stores the indices for the chosen 2 elements per
group of 4 elements. The criterion for selection of these elements is specified by a field
from sparsity descriptor spdesc.
The qualifier .elemsize specifies the size in bits for each element from the input vector
data. The exact data type for each element is specified by a field from sparsity descriptor
spdesc. The qualifier .idxsize specifies the size of the metadata index for each
selected element. Given the compression factor is 2:4, the .idxsize can only be .b2
or .b4.
The .num qualifier depicts the repeat factor for the operation. The operands data,
cdata, mdata are brace-enclosed vector expression consisting of one or more 32-bit
registers. Any register overlap or otherwise register reuse among vector operands data,
cdata, mdata results in undefined behavior. For the data and cdata operands,
vector size depends on .num qualifier. For the mdata operand, the vector size depends
on the .num, .idxsize, .elemsize qualifier values.
For instance, when .num qualifier is specified as .x1, the operand data must
comprise of 2 .b32 registers while the resulting cdata, mdata are vector operands
with singleton .b32 register each. Similarly, when .num is set to .x64, the input
operand data is a vector of 128 .b32 registers while the resulting cdata comprises
of 64 .b32 registers. The expected vector size for each of the operand can be computed
based on the Table 37.
Note that the total vector size of all operands should not exceed 253. i.e.
vecSize(data)+vecSize(cdata)+vecSize(mdata)<=253.
Table 37 Expected vector size for various operands
Operand
Vector Size
data
2*num
cdata
num
mdata
ceil(num*idxsize/elemsize)
The 32-bit register operand spdesc is the instruction descriptor argument. The
instruction descriptor encodes the exact data type for the input elements in data
operand. It also specifies the operation that needs to be applied to select 2 elements
per group of 4 elements. The Table 38 lists
the exact layout for the descriptor argument spdesc.
Table 38 Instruction descriptor format
Bits
Size
Description
Values
0-1
2
These bits represent the operation that needs
to be used in the selection of 2 elements per
group of 4 elements.
MAX and MIN will select the two elements with
the greatest and smallest values respectively.
Whereas MAXABS and MINABS will select the two
elements with the greatest and smallest
magnitude respectively.
0: MAX, 1: MAXABS, 2: MIN,
3: MINABS
2-4
3
These bits represent the data type of elements
from source operand data. When set to
either 0 or 1, the .elemsize qualifier on
the instruction helps to uniquely identify the
exact type. Inconsistent setting of these bits
with respect to .elemsize qualifier would
result in runtime error.
The spdecompress instruction copies elements from structured sparse compressed vector
cdata to form the dense vector data. The metadata information corresponding to
the structured sparse compressed vector cdata is given by the vector operand mdata.
The decompression factor is derived from the qualifier .spfactor. The qualifier is of
form .sp::num_src:num_target implying instruction decompresses each sequence of
num_src elements so as to form the sequence comprising num_target many elements.
Given decompress operation, it naturally follows that the num_src value must be
strictly numerically smaller than the num_target value.
The spdecompress instruction copies each element out of a sequence of num_src
elements from cdata so as to transform it into a sequence of num_target
elements in the resulting data operand. The target index corresponding to the
each element of num_src sequence is given by mdata operand. If no element
from num_src sequence is copied to a position within a sequence of num_target
elements, then that position is set to zero. Similarly, all empty and unpopulated bits
of the output operand data are set to zero.
The .num qualifier depicts the repeat factor for the operation. The size of target
index per element is specified by .idxsize. The qualifier .elemsize depicts
size of each element belonging to the sequence of num_src and num_target.
The operands mdata, cdata and data are brace-enclosed vector expression
consisting of one or more .b32 registers. Any register overlap or otherwise
register reuse among vector operands mdata, cdata, data results in
undefined behavior. The vector size for each of the operand depends on the qualifier
values. The expected vector size for each of the operand can be computed based on the
Table 39.
Table 39 Expected vector size for various operands
Operand
Vector Size
mdata
ceil(num_src*idxsize*num/32)
cdata
ceil(num_src*elemsize*num/32)
data
ceil(num_target*elemsize*num/32)
The following conditions must be satisfied for a valid spdecompress instruction:
The input span corresponding to single iteration of .num qualifier must fit within
a single .b32 register. i.e. num_src*.elemsize<=32.
The .idxsize should be sufficient to fully index into the sequence of num_target
elements. In other words, if .idxsize is .b2 then num_target must be <=4.
The size of the data operand should be at least 1.
i.e. num_target*.elemsize*.num>=32.
The size of the data operand can be at most 128.
i.e. num_target*.elemsize*.num<=4096.
The total vector size of all operands should not exceed 253.
i.e. vecSize(mdata)+vecSize(cdata)+vecSize(data)<=253.
Figure 44 shows pictorial representation of a simple spdecompress instruction.
Figure 44 Illustration for spdecompress instruction.
Semantics
for N in .num:
for S in num_source:
data[mdata[N][S]] = cdata[N][S];
NVLink failures encountered by pointer-address-based memory operations are fatal to the application.
The CUDA Compute Fabric Transport (CUDA CFT) programming model introduces fabric operations that
report failures directly to the application, enabling them to be resilient over NVLink failures.
How to handle these failures is entirely up to the application and may include aborting or cleanly
tearing the process down, or attempting to recover from transient failures by retrying the operation.
May fail and report a status that identifies success or potential failure of the operation,
enabling applications to react accordingly.
Are asynchronous operations, enabling the operation to make progress in the background.
Perform some CFT Handle resource accesses via the fabric-proxy.
Most fabric operations perform multiple accesses: CFT Handle resource accesses via fabric-proxy,
and multiple pointer-based accesses via often multiple different proxies.
Fabric operation accesses to CFT Handle resources are performed through the fabric-proxy.
Cross-proxy fences between fabric-proxy and generic-proxy are available.
The lifecycle of a handle starts and ends in the host,when the host-side of the CUDA application
detects whether the system supports fabric operations, creates logical endpoints, binds resources
to the logical endpoints, and shares them with other GPUs in the NVLink domain. To enable remote
source accesses the logical endpoint readiness should be queried. The lifecycle of a fabric operation
starts and ends in the device. This section only covers the PTX device-side programming model of
fabric operations; refer to the
Logical Endpoint section of the CUDA Driver API
for the end-to-end programming model of fabric operations spanning host-code and device-code.
The lifecycle of fabric operations includes:
Threads issue one or more fabric operations tracked by an mbarrier.layout::v1.
Each thread submits the fabric operations before the associated mbarrier phase completes.
Threads arrive-on and expect-tx at the mbarrier phase to ensure it advances once
the fabric operations complete.
Threads wait until the mbarrier phase completes.
Threads inspect the predicate report for errors, and handle them.
The status report may contain additional information about the errors.
For any thread to observe completion of fabric operations via an mbarrier object, the issuing
thread is required to submit those operations before the barrier phase tracking these operations
advances. Otherwise, the behavior is undefined.
A single arriveexpect_tx operation can be issued for multiple and different types of fabric
operations tracked by the same barrier.
Submitted fabric operations are guaranteed to eventually complete, and threads may block on the
mbarrier to observe their completion and their report status.
A single operation like fabric.try_put may issue many requests, and each of the requests may
fail for a different reason. The failures are reported on
the mbarrier objects.
Multiple different fabric operations may also be tracked by the same mbarrier object
and fail for different reasons.
The mbarrier.try_wait.phase_type::primary operation that notifies the program of completion
sets the report predicate if there were any errors; the opaque report value may contain more
information. See fabric reporting mechanism for details.
The application can then decide how to handle the errors based on their severity nature.
9.7.11.4. Completion mechanisms of fabric operations#
The completion of fabric operations can be tracked by mbarrier objects of type
layout::v1.
For details refer to
mbarrier based completion mechanism.
Observing completion of a fabric operation provides ordering for all memory accesses and CFT Handle
resource accesses performed by the operation, irrespective of whether any errors were reported or not.
In addition to tracking the completion of the fabric operation, a subset of operation effects,
such as waiting on reads from shared memory, waiting on changes in a counter value, etc.,
can also be tracked independently from the entire completion of the operation.
Fabric operations tracked by mbarrier use the report::fabric reporting mechanism with the
following semantics:
If the operation succeeds, the payload report (contents of the mbarrier object)
is not modified. In other words, report predicate and report value both remain unchanged.
Otherwise, the operation fails, the mbarrier report predicate is set, and the opaque report
value may contain more information, which may be decoded via the
cudaFabricOpErrorStatusGet/Count APIs.
The behavior of a program that combines fabric operations specifying report::fabric with other
operations specifying different reporting mechanism is undefined.
All fabric operations that read data from shared memory support tracking the completion of the
read operation. This enables applications to reuse the shared memory read by these operations
without waiting for the entire operation to complete. This is a partial completion mechanism,
that is, it does not track completion of an entire asynchronous operation.
Note that since fabric.try_get does not read from shared memory - it writes to it - this
completion mechanism does not provide any ordering for try_get operations.
Fabric operations support tracking the completion of the destination data accesses performed by
try_put and try_red using a global memory counter. It enables programs to wait on data
modifications by observing the counter updates. Multiple fabric operations may share the same
counter concurrently. Since concurrent operations are not ordered with respect to each other,
programs must wait on the counter reaching a final value.
This mechanism increments a counter by one for each byte of data accessed. The granularity at
which counter updates occur is unspecified; updates may happen once per byte, once collectively
at the end of the operation, or any granularity in between. The 8B-wide counter must be 256B
aligned, and the counter increment is a system-scope atomic operation.
If counter and data overlap, the behavior is undefined.
If the logical endpoint lacks support for counted completion, the behavior is undefined
(refer to the
Logical Endpoint section of the CUDA Driver API
for details).
This is a partial completion mechanism that programs can use to wait on destination data accesses.
For .multimem fabric operations with counted completion, counters only track accesses at their
destination device.
Asynchronously copies size bytes from fabric handle [srcLeId,srcDataOff] to destination
memory [dst], where srcLeId is a 32-bit unsigned value denoting the logical endpoint
identifier, and srcDataOff is a 64-bit unsigned value denoting the base offset of the
resource to access within the logical endpoint associated with srcLeId.
The logical endpoint associated with srcLeId must be a unicast logical endpoint.
The size operand is 32 bits and specifies the number of bytes to be copied. It must be a
multiple of 16; otherwise, the behavior is undefined. The range [dst,dst+size-1] must be
in bounds of the destination memory space. The range [srcDataOff,srcDataOff+size-1] must
be in bounds of the logical endpoint resources associated with srcLeId.
The source handle offset srcDataOff and destination pointer dst must be 16-byte aligned.
If .dst is .shared::cta, then:
The destination of the copy [dst] and the barrier [bar] must refer to the local CTA’s
shared memory; otherwise, the behavior is undefined.
The completion mechanism must be
.mbarrier::complete_tx::bytes.mbarrier::report::fabric.
The mbarrier object bar must be initialized with .layout::v1 (see
Layouts of the mbarrier object). Qualifier
.mbarrier::complete_tx::bytes specifies that the operation completes by performing a
complete-tx operation
with the total number of bytes copied (size) on mbarrier object at the location specified
by the address operand bar. Refer to
Fabric Reporting Mechanism for the description of
.mbarrier::report::fabric. For any thread to observe completion of fabric operations via an
mbarrier object, the issuing thread is required to submit those operations before the barrier
phase tracking these operations advances.
This instruction reads the data at the location specified by the handle operand through the
fabric-proxy, copies it to the destination .shared::cta memory through the async-proxy, and
updates the mbarrier object in .shared::cta through the generic-proxy.
When the optional argument cache_policy is specified, the qualifier .level::cache_hint
is required. The 64-bit operand cache_policy specifies the cache eviction policy that may be
used during the memory access. cache_policy is a hint to the cache subsystem and may not
always be respected. It is treated as a performance hint only and does not change the memory
consistency behavior of the program.
The completion of this operation may be observed by waiting at the barrier via CTA-scope
operations. Threads must submit fabric operations and wait for their completion before
grid exit; otherwise, the behavior is undefined.
Accesses to a source handle are 128-bit-wide atomic with .relaxed.sys memory-order semantics as
described in the Memory Consistency Model.
Asynchronously copies size bytes from [src] to destination fabric handle
[dstLeId,dstDataOff], where dstLeId is a 32-bit unsigned value denoting the logical
endpoint identifier, and dstDataOff is a 64-bit unsigned value denoting the base offset of
the resource to access within the logical endpoint associated with dstLeId.
The size operand is 32 bits and specifies the number of bytes to be copied. It must be a
multiple of 16; otherwise, the behavior is undefined. The range [src,src+size-1] must
be in bounds of the source memory space. The range [dstDataOff,dstDataOff+size-1] must
be in bounds of the resource at the logical endpoint associated with dstLeId on the current
device.
The source pointer src and the destination handle offset dstDataOff must be 16-byte
aligned.
If the qualifier .multimem is specified, then dstLeId must be associated with a multicast
logical endpoint and the device that issues the operation must be a member of that endpoint. In
the absence of the .multimem qualifier, dstLeId must be associated with a unicast logical
endpoint.
If .src is .shared::cta, then the source of the copy [src] and the barrier [bar]
refer to the local CTA’s shared memory.
The mbarrier object bar must be initialized with .layout::v1 (see
Layouts of the mbarrier object). Qualifier
.mbarrier::complete_tx::16B specifies that the complete-tx operation is performed on bar
with completion count equal to the number of bytes copied divided by 16; that is, the count is
incremented by 1 for every 16 bytes copied. Note that this completion mechanism differs from
fabric.try_get, where the complete-tx operation uses a completion count equal to the number
of bytes copied. For any thread to observe completion of fabric operations via an mbarrier
object, the issuing thread is required to submit those operations before the barrier phase
tracking these operations advances.
If the qualifier .counted::bytes is present (completion_mechanism1 form), then:
dstLeId must be associated with a logical endpoint with counted completion support
(Counted completion mechanism), and
the counter offset dstCounterOff must be 256-byte aligned, and
this operation provides counter-based completion for destination data using a 256-byte-aligned
counter of size 8 bytes specified at [dstLeId,dstCounterOff].
The .counted::bytes qualifier is incompatible with the .cp_mask qualifier.
If .cp_mask is specified, the bytemask operand is required and must contain a 16-bit-wide
mask to select which bytes of each 16-byte chunk are written to the destination.
This instruction accesses the data and the counter at the locations specified by the handle
operands through the fabric-proxy, reads from the source .shared::cta through the
async-proxy, and updates the mbarrier object in .shared::cta through the generic-proxy.
When the optional argument cache_policy is specified, the qualifier .level::cache_hint
is required. The 64-bit operand cache_policy specifies the cache eviction policy that may be
used during the memory access. cache_policy is a hint to the cache subsystem and may not
always be respected. It is treated as a performance hint only and does not change the memory
consistency behavior of the program.
The completion of this operation may be observed by waiting at the barrier via CTA-scope
operations. Threads must submit fabric operations and wait for their completion before
grid exit; otherwise, the behavior is undefined.
This operation has .relaxed.sys memory-order semantics as described in the
Memory Consistency Model.
Asynchronously copies size bytes from [src] to destination fabric handle
[dstLeId,dstDataOff] with element-wise reduction, where dstLeId is a 32-bit unsigned
value denoting the logical endpoint identifier, and dstDataOff is a 64-bit unsigned value
denoting the base offset of the resource to access within the logical endpoint associated with
dstLeId.
The size operand is 32 bits and specifies the number of bytes to be copied. It must be a
multiple of 16; otherwise, the behavior is undefined. The source range [src,src+size-1]
must be in bounds of the source memory space. The destination range
[dstDataOff,dstDataOff+size-1] must be in bounds of the logical endpoint associated with
dstLeId on the current device.
The source pointer src and the destination handle offset dstDataOff must be 16-byte
aligned.
Each data element in the destination array is reduced with the corresponding data element in the
source array using the reduction operation indicated by the .redOp* qualifier. The type of each
data element in the source and destination arrays is specified by the matching .type*
qualifier.
If the qualifier .multimem is specified, then dstLeId must be associated with a multicast
logical endpoint such that the device that issued the operation is a member of the multicast
endpoint. In the absence of the qualifier, dstLeId must be associated with a unicast logical
endpoint.
If .src is .shared::cta, then the source of the copy [src] and the barrier [bar]
refer to the local CTA’s shared memory.
The mbarrier object bar must be initialized with .layout::v1 (see
Layouts of the mbarrier object). Qualifier
.mbarrier::complete_tx::16B specifies that the complete-tx operation is performed on bar
with completion count equal to the number of bytes copied divided by 16; that is, the count is
incremented by 1 for every 16 bytes copied. Note that fabric.try_get uses a different
completion mechanism in which the complete-tx operation uses a completion count equal to the
number of bytes copied. For any thread to observe completion of fabric operations via an
mbarrier object, the issuing thread is required to submit those operations before the barrier
phase tracking these operations advances.
If the qualifier .counted::bytes is present (completion_mechanism1 form), then:
dstLeId must be associated with a logical endpoint with counted completion support
(see Counted completion mechanism for details), and
the counter offset dstCounterOff must be 256-byte aligned,
the range [dstCounterOff,dstCounterOff+7] is in bounds of the logical endpoint
dstLeId on the current device, and must not overlap with
[dstDataOff,dstDataOff+size-1], and
this operation provides counter-based completion for destination data using a 256-byte-aligned
8-byte counter at [dstLeId,dstCounterOff].
This instruction accesses the data and the counter at the locations specified by the handle
operands through the fabric-proxy, reads from the source .shared::cta through the
async-proxy, and updates the mbarrier object in .shared::cta through the generic-proxy.
When the optional argument cache_policy is specified, the qualifier .level::cache_hint
is required. The 64-bit operand cache_policy specifies the cache eviction policy that may be
used during the memory access. cache_policy is a hint to the cache subsystem and may not
always be respected. It is treated as a performance hint only and does not change the memory
consistency behavior of the program.
The completion of this operation may be observed by waiting at the barrier via CTA-scope
operations. Threads must submit fabric operations and wait for their completion before
grid exit; otherwise, the behavior is undefined.
This operation has .relaxed.sys memory-order semantics as described in the
Memory Consistency Model.
Initiates asynchronous loads from multiple resources pointed to by multicast fabric handle
[srcLeId,srcDataOff], of size bytes, and performs element-wise reduction on data across
each of the loads. The result is stored in [dst,dst+size-1]. srcLeId is a 32-bit
unsigned value denoting the logical endpoint identifier, and srcDataOff is a 64-bit unsigned
value denoting the base offset of the resources to access within the multicast logical endpoint
associated with srcLeId.
The size operand is 32 bits and specifies the number of bytes to be copied. It must be a
multiple of 16; otherwise, the behavior is undefined. The destination range [dst,dst+size-1]
must be in bounds of the destination memory space. The source range
[srcDataOff,srcDataOff+size-1] must be in bounds of the logical endpoint associated with
srcLeId on the current device.
The destination pointer dst and the source handle offset srcDataOff must be 16-byte
aligned.
A reduction is performed on the values read from all resources referred to by the multicast
logical endpoint. The .redOp* qualifiers specify the reduction operation. The .type*
qualifiers specify the type of each data element in the source arrays.
The srcLeId operand must be associated with a multicast logical endpoint with pull-reduction
support, and the device that issues the operation must be a member of the multicast endpoint.
If .dst is .shared::cta, then the destination [dst] and the barrier [bar] refer to
the local CTA’s shared memory.
The mbarrier object bar must be initialized with .layout::v1 (see
Layouts of the mbarrier object). Qualifier
.mbarrier::complete_tx::bytes specifies that the complete-tx operation is performed on bar
with completion count equal to the number of bytes copied. For any thread to observe completion of
fabric operations via an mbarrier object, the issuing thread is required to submit those
operations before the barrier phase tracking these operations advances.
This instruction accesses data at the locations specified by the handle operands through the
fabric-proxy, accesses the destination .shared::cta through the async-proxy, and updates the
mbarrier object in .shared::cta through the generic-proxy.
The completion of this operation may be observed by waiting at the barrier via CTA-scope
operations. Threads must submit fabric operations and wait for their completion before
grid exit; otherwise, the behavior is undefined.
This operation has .relaxed.sys memory-order semantics as described in the
Memory Consistency Model.
The .sync qualifier indicates that this instruction causes the issuing thread to wait until
all warp lanes execute this instruction with the same operand values.
Operand imm-membermask is an integer constant and must be 0xFFFFFFFF.
The behavior is undefined if:
while a thread is waiting, a warp lane executes this instruction with different operand values, OR
Submits prior fabric operations issued by the current thread.
Syntax
fabric.submit{.submitop};
.submitop = { .op_restrict::fetching }
Description
Submits prior fabric operations issued by the current thread. For any thread to observe completion
of fabric operations via an mbarrier object, the issuing thread is required to submit those
operations before the barrier phase tracking these operations advances. Otherwise, the behavior is
undefined. See Life of a Fabric Operation.
If .op_restrict::fetching is specified, then only prior fabric.try_get and
fabric.try_pullred operations issued by the current thread are submitted. Otherwise, all prior
fabric operations issued by the current thread are submitted.
This operation has no effect on fabric operations that have already been submitted.
Wait on local shared-memory reads of submitted fabric operations.
Syntax
fabric.wait.sync_restrict::reads;
Description
Fabric-read completion mechanism instruction fabric.wait waits on the local
shared memory (.shared::cta) reads of submitted fabric operations. This enables
overwriting the shared memory read by these operations before they complete.
Asynchronously copies data from the tensor at fabric handle [tensorMapLeId,tensorMapOff]
to destination memory [dstMem], where tensorMapLeId is a 32-bit unsigned value denoting
the logical endpoint identifier, and tensorMapOff is a 64-bit unsigned value denoting the
base offset of the resource to access within the logical endpoint associated with
tensorMapLeId.
The logical endpoint associated with tensorMapLeId must be a unicast logical endpoint.
The range [dstMem,dstMem+size-1] must be in bounds of the destination memory space,
where size is computed using the tensor descriptor tensorMap, and it is the number of
bytes copied from the source fabric handle. It must be a multiple of 16; otherwise, the
behavior is undefined. The source handle offset tensorMapOff and destination pointer
dstMem must be 16-byte aligned.
If .dst is .shared::cta, then:
The destination of the copy [dstMem] and the barrier [mbar] must refer to the local
CTA’s shared memory; otherwise, the behavior is undefined.
The completion mechanism must be
.mbarrier::complete_tx::bytes.mbarrier::report::fabric.
The mbarrier object mbar must be initialized with .layout::v1 (see
Layouts of the mbarrier object). Qualifier
.mbarrier::complete_tx::bytes specifies that the operation completes by performing a
complete-tx operation
with the total number of bytes copied on the mbarrier object at the location specified by
the address operand mbar. Refer to Fabric Reporting Mechanism
for the description of .mbarrier::report::fabric. For any thread to observe completion of
fabric operations via an mbarrier object, the issuing thread is required to submit those
operations before the barrier phase tracking these operations advances.
The operand tensorMap is the generic address of the opaque tensor-map object which resides
in .param space, .const space, or .global space. The operand tensorMap specifies
the properties of the tensor copy operation. The tensorMap is accessed in the tensormap
proxy. Refer to the CUDA programming guide for creating the tensor-map objects on the host
side.
The dimension of the tensor data is specified by the .dim qualifier.
The qualifier .load_mode specifies how the data in the source location is copied into the
destination location.
This instruction reads the data at the location specified by the handle operand through the
fabric-proxy, reads the operand tensorMap through the tensormap-proxy, copies the data to
the destination .shared::cta memory through the async-proxy, and updates the mbarrier
object in .shared::cta through the generic-proxy.
The qualifiers .override::global_address and .override_attribute support value override
functionality for various tensor properties present in the tensorMap object. For more
details refer to the Overriding tensor property value.
When the optional argument cache_policy is specified, the qualifier .level::cache_hint
is required. The 64-bit operand cache_policy specifies the cache eviction policy that may
be used during the memory access. cache_policy is a hint to the cache subsystem and may
not always be respected. It is treated as a performance hint only and does not change the
memory consistency behavior of the program.
The completion of this operation may be observed by waiting at the barrier via CTA-scope
operations. Threads must submit fabric operations and wait for their completion before
grid exit; otherwise, the behavior is undefined.
Accesses to a source handle are 128-bit-wide atomic with .relaxed.sys memory-order semantics
as described in the Memory Consistency Model. Accesses to the destination shared memory are
with weak memory-order semantics.
Asynchronously copies data from source memory [src] to the tensor at fabric handle
[tensorMapLeId,tensorMapOff], where tensorMapLeId is a 32-bit unsigned value denoting
the logical endpoint identifier, and tensorMapOff is a 64-bit unsigned value denoting the
base offset of the resource to access within the logical endpoint associated with
tensorMapLeId.
The sizeBytes operand is 32 bits and specifies the number of bytes to be copied. It must
be a multiple of 16; otherwise, the behavior is undefined. The number of bytes transferred by
the instruction is computed using the tensor descriptor operand tensorMap, and it must
match sizeBytes; otherwise, the behavior is undefined. The range
[src,src+sizeBytes-1] must be in bounds of the source memory space. The source
pointer src and destination handle offset tensorMapOff must be 16-byte aligned.
If the optional .multimem qualifier is specified, then tensorMapLeId must be associated
with a multicast logical endpoint and the device that issues the operation must be a member of
that endpoint. Also, in the case of .multimem, the copy operation is performed on all
member devices of the multicast endpoint. In the absence of the .multimem modifier,
tensorMapLeId must be associated with a unicast logical endpoint.
If .src is .shared::cta, then the source of the copy [src] and the barrier
[mbar] refer to the local CTA’s shared memory.
The mbarrier object mbar must be initialized with .layout::v1 (see
Layouts of the mbarrier object). Qualifier
.mbarrier::complete_tx::16B specifies that the complete-tx operation is performed on
mbar with completion count equal to the number of bytes copied divided by 16; that is,
the count is incremented by 1 for every 16 bytes copied. Note that this completion mechanism
differs from that for fabric.try_get.async.tensor, in which the complete-tx operation is
performed with completion count equal to the number of bytes copied.
For any thread to observe completion of fabric operations via
an mbarrier object, the issuing thread is required to submit those operations before the
barrier phase tracking these operations advances.
If the qualifier .counted::bytes is present, then:
tensorMapLeId must be associated with a logical endpoint with counted completion support
(Counted completion mechanism), and
the counter offset counterOff must be 256-byte aligned, and
the range [counterOff,counterOff+7] is in bounds of the logical endpoint
tensorMapLeId on the current device, and must not overlap with the tensorMap
being accessed, and
this operation provides counter-based completion for destination data using a 256-byte-aligned
counter of size 8 bytes specified at [tensorMapLeId,counterOff].
The operand tensorMap is the generic address of the opaque tensor-map object which resides
in .param space, .const space, or .global space. The operand tensorMap specifies
the properties of the tensor copy operation. The tensorMap is accessed in the tensormap
proxy. Refer to the CUDA programming guide for creating the tensor-map objects on the host
side.
The dimension of the tensor data is specified by the .dim qualifier.
The qualifier .load_mode specifies how the data in the source location is copied to the
destination location.
This instruction accesses the data and the counter at the location specified by the handle
operands through the fabric-proxy, reads the tensorMap through the tensormap-proxy, reads
from the source .shared::cta through the async-proxy, and updates the mbarrier object
in .shared::cta through the generic-proxy.
The qualifiers .override::global_address and .override_attribute support value override
functionality for various tensor properties present in the tensorMap object. For more
details refer to the Overriding tensor property value.
When the optional argument cache_policy is specified, the qualifier .level::cache_hint
is required. The 64-bit operand cache_policy specifies the cache eviction policy that may
be used during the memory access. cache_policy is a hint to the cache subsystem and may
not always be respected. It is treated as a performance hint only and does not change the
memory consistency behavior of the program.
The completion of this operation may be observed by waiting at the barrier via CTA-scope
operations. Threads must submit fabric operations and wait for their completion before
grid exit; otherwise, the behavior is undefined.
This operation has .relaxed.sys memory-order semantics as described in the
Memory Consistency Model. Accesses to the source shared memory are with weak memory-order
semantics.
Asynchronously copies sizeBytes bytes from source memory [src] to the tensor at
fabric handle [tensorMapLeId,tensorMapOff] with element-wise reduction, where
tensorMapLeId is a 32-bit unsigned value denoting the logical endpoint identifier, and
tensorMapOff is a 64-bit unsigned value denoting the base offset of the resource to
access within the logical endpoint associated with tensorMapLeId.
The sizeBytes operand is 32 bits and specifies the number of bytes to be copied. It must
be a multiple of 16; otherwise, the behavior is undefined. The range
[src,src+sizeBytes-1] must be in bounds of the source memory space. The source
pointer src and the destination handle offset tensorMapOff must be 16-byte aligned.
Each data element in the destination array is reduced at the destination with the
corresponding data element in the source array and the reduction operation specified by the
modifier .redOp. The type of each data element in the source and the destination array is
specified by the tensorMap.
If the optional .multimem qualifier is specified, then tensorMapLeId must be associated
with a multicast logical endpoint such that the device that issued the operation is a member
of the multicast endpoint. Also, in the case of .multimem, the reduction operation is
performed on all member devices of the multicast endpoint. In the absence of the .multimem
qualifier, tensorMapLeId must be associated with a unicast logical endpoint.
If .src is .shared::cta, then the source of the copy [src] and the barrier
[mbar] refer to the local CTA’s shared memory.
The mbarrier object mbar must be initialized with .layout::v1 (see
Layouts of the mbarrier object). Qualifier
.mbarrier::complete_tx::16B specifies that the complete-tx operation is performed on
mbar with completion count equal to the number of bytes copied divided by 16; that is,
the count is incremented by 1 for every 16 bytes copied. Note that fabric.try_get uses
a different completion mechanism in which the complete-tx
operation is performed with completion count equal to the number of bytes copied.
For any thread to observe completion of fabric operations via
an mbarrier object, the issuing thread is required to submit those operations before the
barrier phase tracking these operations advances.
If the qualifier .counted::bytes is present, then:
tensorMapLeId must be associated with a logical endpoint with counted completion support
(Counted completion mechanism), and
the counter offset counterOff must be 256-byte aligned, and
the range [counterOff,counterOff+7] is in bounds of the logical endpoint
tensorMapLeId on the current device, and must not overlap with the tensorMap
being accessed, and
this operation provides counter-based completion for destination data using a 256-byte-aligned
counter of size 8 bytes specified at [tensorMapLeId,counterOff].
The operand tensorMap is the generic address of the opaque tensor-map object which resides
in .param space, .const space, or .global space. The operand tensorMap specifies
the properties of the tensor copy operation, as described in Tensor-map. The tensorMap
is accessed in the tensormap proxy. Refer to the CUDA programming guide for creating the
tensor-map objects on the host side.
The dimension of the tensor data is specified by the .dim qualifier.
The qualifier .load_mode specifies how the data in the source location is copied into
the destination location.
The following table describes the valid combinations of .redOp and element type:
.redOp
Element Type
.and, .xor, .or
.b32, .b64
.min, .max
.u32, .s32, .u64, .s64, .f16, .bf16
.add
.u32, .u64, .f16, .bf16, .f32, .f64
This instruction accesses the data and the counter at the location specified by the handle
operands through the fabric-proxy, reads the tensorMap through the tensormap-proxy, reads
from the source .shared::cta through the async-proxy, and updates the mbarrier object
in .shared::cta through the generic-proxy.
The qualifiers .override::global_address and .override_attribute support value override
functionality for various tensor properties present in the tensorMap object. For more
details refer to the Overriding tensor property value.
When the optional argument cache_policy is specified, the qualifier .level::cache_hint
is required. The 64-bit operand cache_policy specifies the cache eviction policy that may
be used during the memory access. cache_policy is a hint to the cache subsystem and may
not always be respected. It is treated as a performance hint only, and does not change the
memory consistency behavior of the program.
The completion of this operation may be observed by waiting at the barrier via CTA-scope
operations. Threads must submit fabric operations and wait for their completion before
grid exit; otherwise, the behavior is undefined.
This operation has .relaxed.sys memory-order semantics as described in the
Memory Consistency Model. Accesses to the source shared memory are with weak memory-order
semantics.
Atomically loads the original value at location [dstLeId,dstDataOff] into destination
shared memory location [smem_dst], performs a reduction operation with the data at shared
memory location [smem_src] and the value in location [dstLeId,dstDataOff], and stores
the result of the specified operation at location [dstLeId,dstDataOff], overwriting
the original value.
For the .cas (compare-and-swap) operation, the lower 16 bytes at the location [smem_src]
is the compare value and the upper 16 bytes at the location [smem_src] is the swap value. The
operation compares the value at location [dstLeId,dstDataOff] with the compare value;
if they are equal, it stores swap value at location [dstLeId,dstDataOff], otherwise it
leaves the value at location [dstLeId,dstDataOff] unchanged.
The operation is performed on 16 bytes. The source range [smem_src,smem_src+15] must be in
bounds of the source memory space. For the .cas operation, the source range
[smem_src,smem_src+31] must be in bounds of the source memory space. The pointers smem_src and
smem_dst must be 16B aligned.
For types .f16x2, .bf16x2, .b32, .f32, and .u32, dstDataOff must be
4B aligned. For types .b64, .f64, and .u64, dstDataOff must be 8B
aligned. For type .b128, dstDataOff must be 16B aligned.
The element-wide input and output of the atomic operation are selected as follows. Let
smemOffset be the distance between dstDataOff and its lower 16B alignment boundary
(dstDataOff&0xF). The input element is read at smem_src+smemOffset, and the output
element is written at smem_dst+smemOffset. This operation writes unspecified values to the
byte ranges [smem_dst,smem_dst+smemOffset) and
[smem_dst+smemOffset+elementWidth,smem_dst+16).
If .src is .shared::cta, then the source of the copy [smem_src] and the barrier
[mbar] refer to the local CTA’s shared memory.
The mbarrier object mbar must be initialized with .layout::v1 (see
Layouts of the mbarrier object). Qualifier
.mbarrier::complete_tx::16B specifies that the complete-tx operation will be performed on
mbar with completion count equal to the number of bytes copied divided by 16; that is,
the count is incremented by 1 for every 16 bytes copied. Note that instructions
fabric.try_get and fabric.try_get.async.tensor use a different completion mechanism
in which the complete-tx operation is performed with completion count equal to the number of
bytes copied. For any thread to observe completion of fabric operations via an mbarrier
object, the issuing thread is required to submit those operations before the barrier phase
tracking these operations advances.
When the optional argument cache_policy is specified, the qualifier .level::cache_hint
is required. The 64-bit operand cache_policy specifies the cache eviction policy that may be
used during the memory access. cache_policy is a hint to the cache subsystem and may not
always be respected. It is treated as a performance hint only and does not change the memory
consistency behavior of the program.
This instruction reads and updates the data at the location specified by the handle operands
through the fabric-proxy, reads and updates the data at the source .shared::cta through
the async-proxy, and it updates the mbarrier object in .shared::cta through the
generic-proxy.
The completion of this operation may be observed by waiting at the barrier via CTA-scope
operations. Threads must submit fabric operations and wait for their completion before
grid exit; otherwise, the behavior is undefined.
This operation has .relaxed.sys memory-order semantics as described in the
Memory Consistency Model. Accesses to the source and destination shared memory are with
weak memory-order semantics.
Semantics
atomic {
[smem_dst] = [dstLeId, dstDataOff]; // copy as the prev value
if (operation == cas) { // smem_src must be 32B aligned
b = lower16Bytes([smem_src]); // smem_src value to be compared
c = upper16Bytes([smem_src]); // swap value
[dstLeId, dstDataOff] = cas([dstLeId, dstDataOff], b, c);
} else {
[dstLeId, dstDataOff] = operation([dstLeId, dstDataOff], [smem_src]);
}
}
For working with textures and samplers, PTX has two modes of operation. In the unified mode,
texture and sampler information is accessed through a single .texref handle. In the independent
mode, texture and sampler information each have their own handle, allowing them to be defined
separately and combined at the site of usage in the program.
The advantage of unified mode is that it allows 256 samplers per kernel (128 for architectures prior
to sm_3x), with the restriction that they correspond 1-to-1 with the 256 possible textures per
kernel (128 for architectures prior to sm_3x). The advantage of independent mode is that
textures and samplers can be mixed and matched, but the number of samplers is greatly restricted to
32 per kernel (16 for architectures prior to sm_3x).
Table 40 summarizes the number of textures, samplers and
surfaces available in different texturing modes.
Table 40 Texture, sampler and surface limits
Texturing mode
Resource
sm_1x, sm_2x
sm_3x+
Unified mode
Textures
128
256
Samplers
128
256
Surfaces
8
16
Independent mode
Textures
128
256
Samplers
16
32
Surfaces
8
16
The texturing mode is selected using .target options texmode_unified and
texmode_independent. A PTX module may declare only one texturing mode. If no texturing mode is
declared, the module is assumed to use unified mode.
Example: calculate an element’s power contribution as element’s power/total number of elements.
A mipmap is a sequence of textures, each of which is a progressively lower resolution
representation of the same image. The height and width of each image, or level of detail (LOD), in
the mipmap is a power of two smaller than the previous level. Mipmaps are used in graphics
applications to improve rendering speed and reduce aliasing artifacts. For example, a
high-resolution mipmap image is used for objects that are close to the user; lower-resolution images
are used as the object appears farther away. Mipmap filtering modes are provided when switching
between two levels of detail (LODs) in order to avoid abrupt changes in visual fidelity.
Example: If the texture has a basic size of 256 by 256 pixels, then the associated mipmap set
may contain a series of eight images, each one-fourth the total area of the previous one: 128x128
pixels, 64x64, 32x32, 16x16, 8x8, 4x4, 2x2, 1x1 (a single pixel). If, for example, a scene is
rendering this texture in a space of 40x40 pixels, then either a scaled up version of the 32x32
(without trilinear interpolation) or an interpolation of the 64x64 and the 32x32 mipmaps (with
trilinear interpolation) would be used.
The total number of LODs in a complete mipmap pyramid is calculated through the following equation:
numLODs = 1 + floor(log2(max(w, h, d)))
The finest LOD is called the base level and is the 0th level. The next (coarser) level is the 1st
level, and so on. The coarsest level is the level of size (1 x 1 x 1). Each successively smaller
mipmap level has half the {width, height, depth} of the previous level, but if this half value is a
fractional value, it’s rounded down to the next largest integer. Essentially, the size of a mipmap
level can be specified as:
max(1, floor(w_b / 2^i)) x
max(1, floor(h_b / 2^i)) x
max(1, floor(d_b / 2^i))
where i is the ith level beyond the 0th level (the base level). And w_b, h_b and d_b are the
width, height and depth of the base level respectively.
PTX support for mipmaps
The PTX tex instruction supports three modes for specifying the LOD: base, level, and
gradient. In base mode, the instruction always picks level 0. In level mode, an additional
argument is provided to specify the LOD to fetch from. In gradmode, two floating-point vector
arguments provide partials (e.g., {ds/dx,dt/dx} and {ds/dy,dt/dy} for a 2d texture),
which the tex instruction uses to compute the LOD.
These instructions provide access to texture memory.
Texture lookup using a texture coordinate vector. The instruction loads data from the texture named
by operand a at coordinates given by operand c into destination d. Operand c is a
scalar or singleton tuple for 1d textures; is a two-element vector for 2d textures; and is a
four-element vector for 3d textures, where the fourth element is ignored. An optional texture
sampler b may be specified. If no sampler is specified, the sampler behavior is a property of
the named texture. The optional destination predicate p is set to True if data from texture
at specified coordinates is resident in memory, False otherwise. When optional destination
predicate p is set to False, data loaded will be all zeros. Memory residency of Texture Data
at specified coordinates is dependent on execution environment setup using Driver API calls, prior
to kernel launch. Refer to Driver API documentation for more details including any
system/implementation specific behavior.
An optional operand e may be specified. Operand e is a vector of .s32 values that
specifies coordinate offset. Offset is applied to coordinates before doing texture lookup. Offset
value is in the range of -8 to +7. Operand e is a singleton tuple for 1d textures; is a two
element vector 2d textures; and is four-element vector for 3d textures, where the fourth element is
ignored.
An optional operand f may be specified for depthtextures. Depth textures are special type
of textures which hold data from the depth buffer. Depth buffer contains depth information of each
pixel. Operand f is .f32 scalar value that specifies depth compare value for depth
textures. Each element fetched from texture is compared against value given in f operand. If
comparison passes, result is 1.0; otherwise result is 0.0. These per-element comparison results are
used for the filtering. When using depth compare operand, the elements in texture coordinate vector
c have .f32 type.
Depth compare operand is not supported for 3d textures.
The instruction returns a two-element vector for destination type .f16x2. For all other
destination types, the instruction returns a four-element vector. Coordinates may be given in either
signed 32-bit integer or 32-bit floating point form.
A texture base address is assumed to be aligned to a 16 byte boundary, and the address given by the
coordinate vector must be naturally aligned to a multiple of the access size. If an address is not
properly aligned, the resulting behavior is undefined; i.e., the access may proceed by silently
masking off low-order address bits to achieve proper rounding, or the instruction may fault.
tex.{a1d,a2d}
Texture array selection, followed by texture lookup. The instruction first selects a texture from
the texture array named by operand a using the index given by the first element of the array
coordinate vector c. The instruction then loads data from the selected texture at coordinates
given by the remaining elements of operand c into destination d. Operand c is a bit-size
type vector or tuple containing an index into the array of textures followed by coordinates within
the selected texture, as follows:
For 1d texture arrays, operand c has type .v2.b32. The first element is interpreted as an
unsigned integer index (.u32) into the texture array, and the second element is interpreted as
a 1d texture coordinate of type .ctype.
For 2d texture arrays, operand c has type .v4.b32. The first element is interpreted as an
unsigned integer index (.u32) into the texture array, and the next two elements are
interpreted as 2d texture coordinates of type .ctype. The fourth element is ignored.
An optional texture sampler b may be specified. If no sampler is specified, the sampler behavior
is a property of the named texture.
An optional operand e may be specified. Operand e is a vector of .s32 values that
specifies coordinate offset. Offset is applied to coordinates before doing texture lookup. Offset
value is in the range of -8 to +7. Operand e is a singleton tuple for 1d texture arrays; and is
a two element vector 2d texture arrays.
An optional operand f may be specified for depth textures arrays. Operand f is .f32
scalar value that specifies depth compare value for depth textures. When using depth compare
operand, the coordinates in texture coordinate vector c have .f32 type.
The instruction returns a two-element vector for destination type .f16x2. For all other
destination types, the instruction returns a four-element vector. The texture array index is a
32-bit unsigned integer, and texture coordinate elements are 32-bit signed integer or floating point
values.
The optional destination predicate p is set to True if data from texture at specified
coordinates is resident in memory, False otherwise. When optional destination predicate p is
set to False, data loaded will be all zeros. Memory residency of Texture Data at specified
coordinates is dependent on execution environment setup using Driver API calls, prior to kernel
launch. Refer to Driver API documentation for more details including any system/implementation
specific behavior.
tex.cube
Cubemap texture lookup. The instruction loads data from the cubemap texture named by operand a
at coordinates given by operand c into destination d. Cubemap textures are special
two-dimensional layered textures consisting of six layers that represent the faces of a cube. All
layers in a cubemap are of the same size and are square (i.e., width equals height).
When accessing a cubemap, the texture coordinate vector c has type .v4.f32, and comprises
three floating-point coordinates (s, t, r) and a fourth padding argument which is
ignored. Coordinates (s, t, r) are projected onto one of the six cube faces. The (s,
t, r) coordinates can be thought of as a direction vector emanating from the center of the
cube. Of the three coordinates (s, t, r), the coordinate of the largest magnitude (the
major axis) selects the cube face. Then, the other two coordinates (the minor axes) are divided by
the absolute value of the major axis to produce a new (s, t) coordinate pair to lookup into
the selected cube face.
An optional texture sampler b may be specified. If no sampler is specified, the sampler behavior
is a property of the named texture.
Offset vector operand e is not supported for cubemap textures.
an optional operand f may be specified for cubemap depth textures. operand f is .f32
scalar value that specifies depth compare value for cubemap depth textures.
The optional destination predicate p is set to True if data from texture at specified
coordinates is resident in memory, False otherwise. When optional destination predicate p is
set to False, data loaded will be all zeros. Memory residency of Texture Data at specified
coordinates is dependent on execution environment setup using Driver API calls, prior to kernel
launch. Refer to Driver API documentation for more details including any system/implementation
specific behavior.
tex.acube
Cubemap array selection, followed by cubemap lookup. The instruction first selects a cubemap texture
from the cubemap array named by operand a using the index given by the first element of the
array coordinate vector c. The instruction then loads data from the selected cubemap texture at
coordinates given by the remaining elements of operand c into destination d.
Cubemap array textures consist of an array of cubemaps, i.e., the total number of layers is a
multiple of six. When accessing a cubemap array texture, the coordinate vector c has type
.v4.b32. The first element is interpreted as an unsigned integer index (.u32) into the
cubemap array, and the remaining three elements are interpreted as floating-point cubemap
coordinates (s, t, r), used to lookup in the selected cubemap as described above.
An optional texture sampler b may be specified. If no sampler is specified, the sampler behavior
is a property of the named texture.
Offset vector operand e is not supported for cubemap texture arrays.
An optional operand f may be specified for cubemap depth texture arrays. Operand f is
.f32 scalar value that specifies depth compare value for cubemap depth textures.
The optional destination predicate p is set to True if data from texture at specified
coordinates is resident in memory, False otherwise. When optional destination predicate p is
set to False, data loaded will be all zeros. Memory residency of Texture Data at specified
coordinates is dependent on execution environment setup using Driver API calls, prior to kernel
launch. Refer to Driver API documentation for more details including any system/implementation
specific behavior.
tex.2dms
Multi-sample texture lookup using a texture coordinate vector. Multi-sample textures consist of
multiple samples per data element. The instruction loads data from the texture named by operand
a from sample number given by first element of the operand c, at coordinates given by
remaining elements of operand c into destination d. When accessing a multi-sample texture,
texture coordinate vector c has type .v4.b32. The first element in operand c is
interpreted as unsigned integer sample number (.u32), and the next two elements are interpreted
as signed integer (.s32) 2d texture coordinates. The fourth element is ignored. An optional
texture sampler b may be specified. If no sampler is specified, the sampler behavior is a
property of the named texture.
An optional operand e may be specified. Operand e is a vector of type .v2.s32 that
specifies coordinate offset. Offset is applied to coordinates before doing texture lookup. Offset
value is in the range of -8 to +7.
Depth compare operand f is not supported for multi-sample textures.
The optional destination predicate p is set to True if data from texture at specified
coordinates is resident in memory, False otherwise. When optional destination predicate p is
set to False, data loaded will be all zeros. Memory residency of Texture Data at specified
coordinates is dependent on execution environment setup using Driver API calls, prior to kernel
launch. Refer to Driver API documentation for more details including any system/implementation
specific behavior.
tex.a2dms
Multi-sample texture array selection, followed by multi-sample texture lookup. The instruction first
selects a multi-sample texture from the multi-sample texture array named by operand a using the
index given by the first element of the array coordinate vector c. The instruction then loads
data from the selected multi-sample texture from sample number given by second element of the
operand c, at coordinates given by remaining elements of operand c into destination
d. When accessing a multi-sample texture array, texture coordinate vector c has type
.v4.b32. The first element in operand c is interpreted as unsigned integer sampler number, the
second element is interpreted as unsigned integer index (.u32) into the multi-sample texture
array and the next two elements are interpreted as signed integer (.s32) 2d texture
coordinates. An optional texture sampler b may be specified. If no sampler is specified, the
sampler behavior is a property of the named texture.
An optional operand e may be specified. Operand e is a vector of type .v2.s32 values
that specifies coordinate offset. Offset is applied to coordinates before doing texture
lookup. Offset value is in the range of -8 to +7.
Depth compare operand f is not supported for multi-sample texture arrays.
The optional destination predicate p is set to True if data from texture at specified
coordinates is resident in memory, False otherwise. When optional destination predicate p is
set to False, data loaded will be all zeros. Memory residency of Texture Data at specified
coordinates is dependent on execution environment setup using Driver API calls, prior to kernel
launch. Refer to Driver API documentation for more details including any system/implementation
specific behavior.
Mipmaps
.base (lod zero)
Pick level 0 (base level). This is the default if no mipmap mode is specified. No additional arguments.
.level (lod explicit)
Requires an additional 32-bit scalar argument, lod, which contains the LOD to fetch from. The
type of lod follows .ctype (either .s32 or .f32). Geometries .2dms and
.a2dms are not supported in this mode.
.grad (lod gradient)
Requires two .f32 vectors, dPdx and dPdy, that specify the partials. The vectors are
singletons for 1d and a1d textures; are two-element vectors for 2d and a2d textures; and are
four-element vectors for 3d, cube and acube textures, where the fourth element is ignored for 3d
and cube geometries. Geometries .2dms and .a2dms are not supported in this mode.
For mipmap texture lookup, an optional operand e may be specified. Operand e is a vector of
.s32 that specifies coordinate offset. Offset is applied to coordinates before doing texture
lookup. Offset value is in the range of -8 to +7. Offset vector operand is not supported for cube
and cubemap geometries.
An optional operand f may be specified for mipmap textures. Operand f is .f32 scalar
value that specifies depth compare value for depth textures. When using depth compare operand, the
coordinates in texture coordinate vector c have .f32 type.
The optional destination predicate p is set to True if data from texture at specified
coordinates is resident in memory, False otherwise. When optional destination predicate p is
set to False, data loaded will be all zeros. Memory residency of Texture Data at specified
coordinates is dependent on execution environment setup using Driver API calls, prior to kernel
launch. Refer to Driver API documentation for more details including any system/implementation
specific behavior.
Depth compare operand is not supported for 3d textures.
Indirect texture access
Beginning with PTX ISA version 3.1, indirect texture access is supported in unified mode for target
architecture sm_20 or higher. In indirect access, operand a is a .u64 register holding
the address of a .texref variable.
Examples
// Example of unified mode texturing
// - f4 is required to pad four-element tuple and is ignored
tex.3d.v4.s32.s32 {r1,r2,r3,r4}, [tex_a,{f1,f2,f3,f4}];
// Example of independent mode texturing
tex.1d.v4.s32.f32 {r1,r2,r3,r4}, [tex_a,smpl_x,{f1}];
// Example of 1D texture array, independent texturing mode
tex.a1d.v4.s32.s32 {r1,r2,r3,r4}, [tex_a,smpl_x,{idx,s1}];
// Example of 2D texture array, unified texturing mode
// - f3 is required to pad four-element tuple and is ignored
tex.a2d.v4.s32.f32 {r1,r2,r3,r4}, [tex_a,{idx,f1,f2,f3}];
// Example of cubemap array, unified textureing mode
tex.acube.v4.f32.f32 {r0,r1,r2,r3}, [tex_cuarray,{idx,f1,f2,f3}];
// Example of multi-sample texture, unified texturing mode
tex.2dms.v4.s32.s32 {r0,r1,r2,r3}, [tex_ms,{sample,r6,r7,r8}];
// Example of multi-sample texture, independent texturing mode
tex.2dms.v4.s32.s32 {r0,r1,r2,r3}, [tex_ms, smpl_x,{sample,r6,r7,r8}];
// Example of multi-sample texture array, unified texturing mode
tex.a2dms.v4.s32.s32 {r0,r1,r2,r3}, [tex_ams,{idx,sample,r6,r7}];
// Example of texture returning .f16 data
tex.1d.v4.f16.f32 {h1,h2,h3,h4}, [tex_a,smpl_x,{f1}];
// Example of texture returning .f16x2 data
tex.1d.v2.f16x2.f32 {h1,h2}, [tex_a,smpl_x,{f1}];
// Example of 3d texture array access with tex.grad,unified texturing mode
tex.grad.3d.v4.f32.f32 {%f4,%f5,%f6,%f7},[tex_3d,{%f0,%f0,%f0,%f0}],
{fl0,fl1,fl2,fl3},{fl0,fl1,fl2,fl3};
// Example of cube texture array access with tex.grad,unified texturing mode
tex.grad.cube.v4.f32.f32{%f4,%f5,%f6,%f7},[tex_cube,{%f0,%f0,%f0,%f0}],
{fl0,fl1,fl2,fl3},{fl0,fl1,fl2,fl3};
// Example of 1d texture lookup with offset, unified texturing mode
tex.1d.v4.s32.f32 {r1,r2,r3,r4}, [tex_a, {f1}], {r5};
// Example of 2d texture array lookup with offset, unified texturing mode
tex.a2d.v4.s32.f32 {r1,r2,r3,r4}, [tex_a,{idx,f1,f2}], {f5,f6};
// Example of 2d mipmap texture lookup with offset, unified texturing mode
tex.level.2d.v4.s32.f32 {r1,r2,r3,r4}, [tex_a,{f1,f2}],
flvl, {r7, r8};
// Example of 2d depth texture lookup with compare, unified texturing mode
tex.1d.v4.f32.f32 {f1,f2,f3,f4}, [tex_a, {f1}], f0;
// Example of depth 2d texture array lookup with offset, compare
tex.a2d.v4.s32.f32 {f0,f1,f2,f3}, [tex_a,{idx,f4,f5}], {r5,r6}, f6;
// Example of destination predicate use
tex.3d.v4.s32.s32 {r1,r2,r3,r4}|p, [tex_a,{f1,f2,f3,f4}];
Texture fetch of the 4-texel bilerp footprint using a texture coordinate vector. The instruction
loads the bilerp footprint from the texture named by operand a at coordinates given by operand
c into vector destination d. The texture component fetched for each texel sample is
specified by .comp. The four texel samples are placed into destination vector d in
counter-clockwise order starting at lower left.
An optional texture sampler b may be specified. If no sampler is specified, the sampler behavior
is a property of the named texture.
The optional destination predicate p is set to True if data from texture at specified
coordinates is resident in memory, False otherwise. When optional destination predicate p is
set to False, data loaded will be all zeros. Memory residency of Texture Data at specified
coordinates is dependent on execution environment setup using Driver API calls, prior to kernel
launch. Refer to Driver API documentation for more details including any system/implementation
specific behavior.
An optional operand f may be specified for depth textures. Depth textures are special type of
textures which hold data from the depth buffer. Depth buffer contains depth information of each
pixel. Operand f is .f32 scalar value that specifies depth compare value for depth
textures. Each element fetched from texture is compared against value given in f operand. If
comparison passes, result is 1.0; otherwise result is 0.0. These per-element comparison results are
used for the filtering.
A texture base address is assumed to be aligned to a 16 byte boundary, and the address given by the
coordinate vector must be naturally aligned to a multiple of the access size. If an address is not
properly aligned, the resulting behavior is undefined; i.e., the access may proceed by silently
masking off low-order address bits to achieve proper rounding, or the instruction may fault.
tld4.2d
For 2D textures, operand c specifies coordinates as a two-element, 32-bit floating-point vector.
An optional operand e may be specified. Operand e is a vector of type .v2.s32 that
specifies coordinate offset. Offset is applied to coordinates before doing texture fetch. Offset
value is in the range of -8 to +7.
tld4.a2d
Texture array selection, followed by tld4 texture fetch of 2d texture. For 2d texture arrays
operand c is a four element, 32-bit vector. The first element in operand c is interpreted as an
unsigned integer index (.u32) into the texture array, and the next two elements are interpreted
as 32-bit floating point coordinates of 2d texture. The fourth element is ignored.
An optional operand e may be specified. Operand e is a vector of type .v2.s32 that
specifies coordinate offset. Offset is applied to coordinates before doing texture fetch. Offset
value is in the range of -8 to +7.
tld4.cube
For cubemap textures, operand c specifies four-element vector which comprises three
floating-point coordinates (s, t, r) and a fourth padding argument which is ignored.
Cubemap textures are special two-dimensional layered textures consisting of six layers that
represent the faces of a cube. All layers in a cubemap are of the same size and are square (i.e.,
width equals height).
Coordinates (s, t, r) are projected onto one of the six cube faces. The (s, t, r) coordinates can be
thought of as a direction vector emanating from the center of the cube. Of the three coordinates (s,
t, r), the coordinate of the largest magnitude (the major axis) selects the cube face. Then, the
other two coordinates (the minor axes) are divided by the absolute value of the major axis to
produce a new (s, t) coordinate pair to lookup into the selected cube face.
Offset vector operand e is not supported for cubemap textures.
tld4.acube
Cubemap array selection, followed by tld4 texture fetch of cubemap texture. The first element in
operand c is interpreted as an unsigned integer index (.u32) into the cubemap texture array,
and the remaining three elements are interpreted as floating-point cubemap coordinates (s, t, r),
used to lookup in the selected cubemap.
Offset vector operand e is not supported for cubemap texture arrays.
Indirect texture access
Beginning with PTX ISA version 3.1, indirect texture access is supported in unified mode for target
architecture sm_20 or higher. In indirect access, operand a is a .u64 register holding
the address of a .texref variable.
Examples
//Example of unified mode texturing
tld4.r.2d.v4.s32.f32 {r1,r2,r3,r4}, [tex_a,{f1,f2}];
// Example of independent mode texturing
tld4.r.2d.v4.u32.f32 {u1,u2,u3,u4}, [tex_a,smpl_x,{f1,f2}];
// Example of unified mode texturing using offset
tld4.r.2d.v4.s32.f32 {r1,r2,r3,r4}, [tex_a,{f1,f2}], {r5, r6};
// Example of unified mode texturing using compare
tld4.r.2d.v4.f32.f32 {f1,f2,f3,f4}, [tex_a,{f5,f6}], f7;
// Example of optional destination predicate
tld4.r.2d.v4.f32.f32 {f1,f2,f3,f4}|p, [tex_a,{f5,f6}], f7;
Query an attribute of a texture or sampler. Operand a is either a .texref or .samplerref variable, or a .u64 register.
Query
Returns
.width
.height
.depth
value in elements
.channel_data_type
Unsigned integer corresponding to source language’s channel data type
enumeration. If the source language combines channel data type and channel
order into a single enumeration type, that value is returned for both
channel_data_type and channel_order queries.
.channel_order
Unsigned integer corresponding to source language’s channel order
enumeration. If the source language combines channel data type and channel
order into a single enumeration type, that value is returned for both
channel_data_type and channel_order queries.
.normalized_coords
1 (True) or 0 (False).
.force_unnormalized_coords
1 (True) or 0 (False). Defined only for .samplerref
variables in independent texture mode. Overrides the normalized_coords
field of a .texref variable used with a .samplerref in a tex
instruction.
.filter_mode
Integer from enum{nearest,linear}
.addr_mode_0
.addr_mode_1
.addr_mode_2
Integer from
enum{wrap,mirror,clamp_ogl,clamp_to_edge,clamp_to_border}
.array_size
For a texture array, number of textures in array, 0 otherwise.
.num_mipmap_levels
For a mipmapped texture, number of levels of details (LOD), 0 otherwise.
.num_samples
For a multi-sample texture, number of samples, 0 otherwise.
Texture attributes are queried by supplying a .texref argument to txq. In unified mode,
sampler attributes are also accessed via a .texref argument, and in independent mode sampler
attributes are accessed via a separate .samplerref argument.
txq.level
txq.level requires an additional 32bit integer argument, lod, which specifies LOD and
queries requested attribute for the specified LOD.
Indirect texture access
Beginning with PTX ISA version 3.1, indirect texture access is supported in unified mode for target
architecture sm_20 or higher. In indirect access, operand a is a .u64 register holding
the address of a .texref variable.
Query whether a register points to an opaque variable of a specified type.
Syntax
istypep.type p, a; // result is .pred
.type = { .texref, .samplerref, .surfref };
Description
Write predicate register p with 1 if register a points to an opaque variable of the
specified type, and with 0 otherwise. Destination p has type .pred; the source address
operand must be of type .u64.
Load from surface memory using a surface coordinate vector. The instruction loads data from the
surface named by operand a at coordinates given by operand b into destination d. Operand
a is a .surfref variable or .u64 register. Operand b is a scalar or singleton tuple
for 1d surfaces; is a two-element vector for 2d surfaces; and is a four-element vector for 3d
surfaces, where the fourth element is ignored. Coordinate elements are of type .s32.
suld.b performs an unformatted load of binary data. The lowest dimension coordinate represents a
byte offset into the surface and is not scaled, and the size of the data transfer matches the size
of destination operand d.
suld.b.{a1d,a2d}
Surface layer selection, followed by a load from the selected surface. The instruction first selects
a surface layer from the surface array named by operand a using the index given by the first
element of the array coordinate vector b. The instruction then loads data from the selected
surface at coordinates given by the remaining elements of operand b into destination
d. Operand a is a .surfref variable or .u64 register. Operand b is a bit-size
type vector or tuple containing an index into the array of surfaces followed by coordinates within
the selected surface, as follows:
For 1d surface arrays, operand b has type .v2.b32. The first element is interpreted as an
unsigned integer index (.u32) into the surface array, and the second element is interpreted as a
1d surface coordinate of type .s32.
For 2d surface arrays, operand b has type .v4.b32. The first element is interpreted as an
unsigned integer index (.u32) into the surface array, and the next two elements are interpreted
as 2d surface coordinates of type .s32. The fourth element is ignored.
A surface base address is assumed to be aligned to a 16 byte boundary, and the address given by the
coordinate vector must be naturally aligned to a multiple of the access size. If an address is not
properly aligned, the resulting behavior is undefined; i.e., the access may proceed by silently
masking off low-order address bits to achieve proper rounding, or the instruction may fault.
The .clamp field specifies how to handle out-of-bounds addresses:
.trap
causes an execution trap on out-of-bounds addresses
.clamp
loads data at the nearest surface location (sized appropriately)
.zero
loads zero for out-of-bounds addresses
Indirect surface access
Beginning with PTX ISA version 3.1, indirect surface access is supported for target architecture
sm_20 or higher. In indirect access, operand a is a .u64 register holding the address of
a .surfref variable.
Store to surface memory using a surface coordinate vector. The instruction stores data from operand
c to the surface named by operand a at coordinates given by operand b. Operand a is
a .surfref variable or .u64 register. Operand b is a scalar or singleton tuple for 1d
surfaces; is a two-element vector for 2d surfaces; and is a four-element vector for 3d surfaces,
where the fourth element is ignored. Coordinate elements are of type .s32.
sust.b performs an unformatted store of binary data. The lowest dimension coordinate represents
a byte offset into the surface and is not scaled. The size of the data transfer matches the size of
source operand c.
sust.p performs a formatted store of a vector of 32-bit data values to a surface sample. The
source vector elements are interpreted left-to-right as R, G, B, and A surface
components. These elements are written to the corresponding surface sample components. Source
elements that do not occur in the surface sample are ignored. Surface sample components that do not
occur in the source vector will be written with an unpredictable value. The lowest dimension
coordinate represents a sample offset rather than a byte offset.
The source data interpretation is based on the surface sample format as follows: If the surface
format contains UNORM, SNORM, or FLOAT data, then .f32 is assumed; if the surface
format contains UINT data, then .u32 is assumed; if the surface format contains SINT
data, then .s32 is assumed. The source data is then converted from this type to the surface
sample format.
sust.b.{a1d,a2d}
Surface layer selection, followed by an unformatted store to the selected surface. The instruction
first selects a surface layer from the surface array named by operand a using the index given by
the first element of the array coordinate vector b. The instruction then stores the data in
operand c to the selected surface at coordinates given by the remaining elements of operand
b. Operand a is a .surfref variable or .u64 register. Operand b is a bit-size type
vector or tuple containing an index into the array of surfaces followed by coordinates within the
selected surface, as follows:
For 1d surface arrays, operand b has type .v2.b32. The first element is interpreted as an
unsigned integer index (.u32) into the surface array, and the second element is interpreted as
a 1d surface coordinate of type .s32.
For 2d surface arrays, operand b has type .v4.b32. The first element is interpreted as an
unsigned integer index (.u32) into the surface array, and the next two elements are
interpreted as 2d surface coordinates of type .s32. The fourth element is ignored.
A surface base address is assumed to be aligned to a 16 byte boundary, and the address given by the
coordinate vector must be naturally aligned to a multiple of the access size. If an address is not
properly aligned, the resulting behavior is undefined; i.e., the access may proceed by silently
masking off low-order address bits to achieve proper rounding, or the instruction may fault.
The .clamp field specifies how to handle out-of-bounds addresses:
.trap
causes an execution trap on out-of-bounds addresses
.clamp
stores data at the nearest surface location (sized appropriately)
.zero
drops stores to out-of-bounds addresses
Indirect surface access
Beginning with PTX ISA version 3.1, indirect surface access is supported for target architecture
sm_20 or higher. In indirect access, operand a is a .u64 register holding the address of
a .surfref variable.
Reduction to surface memory using a surface coordinate vector. The instruction performs a reduction
operation with data from operand c to the surface named by operand a at coordinates given by
operand b. Operand a is a .surfref variable or .u64 register. Operand b is a
scalar or singleton tuple for 1d surfaces; is a two-element vector for 2d surfaces; and is a
four-element vector for 3d surfaces, where the fourth element is ignored. Coordinate elements are of
type .s32.
sured.b performs an unformatted reduction on .u32, .s32, .b32, .u64, or .s64
data. The lowest dimension coordinate represents a byte offset into the surface and is not
scaled. Operation add applies to .u32, .u64, and .s32 types; min and max
apply to .u32, .s32, .u64 and .s64 types; operations and and or apply to
.b32 type.
sured.p performs an unformatted reduction on sample-addressed data. The lowest dimension coordinate
represents a sample offset rather than a byte offset and is scaled by the data-size given by .ctype.
The instruction type .b64 is restricted to min and max operations. For type .b32,
the data is interpreted as .u32 or .s32 based on the surface sample format as follows:
if the surface format contains UINT data, then .u32 is assumed; if the surface format contains
SINT data, then .s32 is assumed. For type .b64, if the surface format contains UINT data,
then .u64 is assumed; if the surface format contains SINT data, then .s64 is assumed.
A surface base address is assumed to be aligned to a 16 byte boundary, and the address given by the
coordinate vector must be naturally aligned to a multiple of the access size. If an address is not
properly aligned, the resulting behavior is undefined; i.e., the access may proceed by silently
masking off low-order address bits to achieve proper rounding, or the instruction may fault.
The .clamp field specifies how to handle out-of-bounds addresses:
.trap
causes an execution trap on out-of-bounds addresses
.clamp
stores data at the nearest surface location (sized appropriately)
.zero
drops stores to out-of-bounds addresses
Indirect surface access
Beginning with PTX ISA version 3.1, indirect surface access is supported for target architecture
sm_20 or higher. In indirect access, operand a is a .u64 register holding the address of
a .surfref variable.
Query an attribute of a surface. Operand a is a .surfref variable or a .u64 register.
Query
Returns
.width
.height
.depth
value in elements
.channel_data_type
Unsigned integer corresponding to source language’s channel data
type enumeration. If the source language combines channel data
type and channel order into a single enumeration type, that value
is returned for both channel_data_type and channel_order
queries.
.channel_order
Unsigned integer corresponding to source language’s channel order
enumeration. If the source language combines channel data type and
channel order into a single enumeration type, that value is
returned for both channel_data_type and channel_order
queries.
.array_size
For a surface array, number of surfaces in array, 0 otherwise.
.memory_layout
1 for surface with linear memory layout; 0 otherwise
Indirect surface access
Beginning with PTX ISA version 3.1, indirect surface access is supported for target architecture
sm_20 or higher. In indirect access, operand a is a .u64 register holding the address of
a .surfref variable.
The curly braces create a group of instructions, used primarily for defining a function body. The
curly braces also provide a mechanism for determining the scope of a variable: any variable declared
within a scope is not available outside the scope.
@p bra{.uni} tgt; // tgt is a label
bra{.uni} tgt; // unconditional branch
Description
Continue execution at the target. Conditional branches are specified by using a guard predicate. The
branch target must be a label.
bra.uni is guaranteed to be non-divergent, i.e. all active threads in a warp that are currently
executing this instruction have identical values for the guard predicate and branch target.
Index into a list of possible destination labels, and continue execution from the chosen
label. Conditional branches are specified by using a guard predicate.
brx.idx.uni guarantees that the branch is non-divergent, i.e. all active threads in a warp that
are currently executing this instruction have identical values for the guard predicate and the
index argument.
The index operand is a .u32 register. The tlist operand must be the label of a
.branchtargets directive. It is accessed as a zero-based sequence using index. Behaviour is
undefined if the value of index is greater than or equal to the length of tlist.
The .branchtargets directive must be defined in the local function scope before it is used. It
must refer to labels within the current function.
Semantics
if (p) {
if (index < length(tlist)) {
pc = tlist[index];
} else {
pc = undefined;
}
}
// direct call to named function, func is a symbol
call{.uni} (ret-param), func, (param-list);
call{.uni} func, (param-list);
call{.uni} func;
// indirect call via pointer, with full list of call targets
call{.uni} (ret-param), fptr, (param-list), flist;
call{.uni} fptr, (param-list), flist;
call{.uni} fptr, flist;
// indirect call via pointer, with no knowledge of call targets
call{.uni} (ret-param), fptr, (param-list), fproto;
call{.uni} fptr, (param-list), fproto;
call{.uni} fptr, fproto;
Description
The call instruction stores the address of the next instruction, so execution can resume at that
point after executing a ret instruction. A call is assumed to be divergent unless the
.uni suffix is present. The .uni suffix indicates that the call is guaranteed to be
non-divergent, i.e. all active threads in a warp that are currently executing this instruction have
identical values for the guard predicate and call target.
For direct calls, the called location func must be a symbolic function name; for indirect calls,
the called location fptr must be an address of a function held in a register. Input arguments
and return values are optional. Arguments may be registers, immediate constants, or variables in
.param space. Arguments are pass-by-value.
Indirect calls require an additional operand, flist or fproto, to communicate the list of
potential call targets or the common function prototype of all call targets,
respectively. In the first case, flist gives a complete list of potential call targets and
the optimizing backend is free to optimize the calling convention. In the second case, where the
complete list of potential call targets may not be known, the common function prototype is given
and the call must obey the ABI’s calling convention.
The flist operand is either the name of an array (call table) initialized to a list of function
names; or a label associated with a .calltargets directive, which declares a list of potential
call targets. In both cases the fptr register holds the address of a function listed in the call
table or .calltargets list, and the call operands are type-checked against the type
signature of the functions indicated by flist.
The fproto operand is the name of a label associated with a .callprototype directive. This
operand is used when a complete list of potential targets is not known. The call operands are
type-checked against the prototype, and code generation will follow the ABI calling convention. If a
function that doesn’t match the prototype is called, the behavior is undefined.
Call tables may be declared at module scope or local scope, in either the constant or global state
space. The .calltargets and .callprototype directives must be declared within a function
body. All functions must be declared prior to being referenced in a call table initializer or
.calltargets directive.
Examples
// examples of direct call
call init; // call function 'init'
call.uni g, (a); // call function 'g' with parameter 'a'
@p call (d), h, (a, b); // return value into register d
// call-via-pointer using jump table
.func (.reg .u32 rv) foo (.reg .u32 a, .reg .u32 b) …
.func (.reg .u32 rv) bar (.reg .u32 a, .reg .u32 b) …
.func (.reg .u32 rv) baz (.reg .u32 a, .reg .u32 b) …
Return execution to caller’s environment. A divergent return suspends threads until all threads are
ready to return to the caller. This allows multiple divergent ret instructions.
A ret is assumed to be divergent unless the .uni suffix is present, indicating that the
return is guaranteed to be non-divergent.
Any values returned from a function should be moved into the return parameter variables prior to
executing the ret instruction.
A return instruction executed in a top-level entry routine will terminate thread execution.
Performs barrier synchronization and communication within a CTA. Each CTA instance has sixteen
barriers numbered 0..15.
barrier{.cta} instructions can be used by the threads within the CTA for synchronization and
communication.
Operands a, b, and d have type .u32; operands p and c are predicates. Source
operand a specifies a logical barrier resource as an immediate constant or register with value
0 through 15. Operand b specifies the number of threads participating in the barrier. If
no thread count is specified, all threads in the CTA participate in the barrier. When specifying a
thread count, the value must be a multiple of the warp size. Note that a non-zero thread count is
required for barrier{.cta}.arrive.
Depending on operand b, either specified number of threads (in multiple of warp size) or all
threads in the CTA participate in barrier{.cta} instruction. The barrier{.cta} instructions
signal the arrival of the executing threads at the named barrier.
barrier{.cta} instruction causes executing thread to wait for all non-exited threads from its
warp and marks warps’ arrival at barrier. In addition to signaling its arrival at the barrier, the
barrier{.cta}.red and barrier{.cta}.sync instructions causes executing thread to wait for
non-exited threads of all other warps participating in the barrier to
arrive. barrier{.cta}.arrive does not cause executing thread to wait for threads of other
participating warps.
When a barrier completes, the waiting threads are restarted without delay, and the barrier is
reinitialized so that it can be immediately reused.
The barrier{.cta}.sync or barrier{.cta}.red or barrier{.cta}.arrive instruction
guarantees that when the barrier completes, prior memory accesses requested by this thread are
performed relative to all threads participating in the barrier. The barrier{.cta}.sync and
barrier{.cta}.red instruction further guarantees that no new memory access is requested by this
thread before the barrier completes.
A memory read (e.g., by ld or atom) has been performed when the value read has been
transmitted from memory and cannot be modified by another thread participating in the barrier. A
memory write (e.g., by st, red or atom) has been performed when the value written has
become visible to other threads participating in the barrier, that is, when the previous value can
no longer be read.
barrier{.cta}.red performs a reduction operation across threads. The c predicate (or its
complement) from all threads in the CTA are combined using the specified reduction operator. Once
the barrier count is reached, the final value is written to the destination register in all threads
waiting at the barrier.
The reduction operations for barrier{.cta}.red are population-count (.popc),
all-threads-True (.and), and any-thread-True (.or). The result of .popc is the number of
threads with a True predicate, while .and and .or indicate if all the threads had a
True predicate or if any of the threads had a True predicate.
Instruction barrier{.cta} has optional .aligned modifier. When specified, it indicates that
all threads in CTA will execute the same barrier{.cta} instruction. In conditionally executed
code, an aligned barrier{.cta} instruction should only be used if it is known that all threads
in CTA evaluate the condition identically, otherwise behavior is undefined.
Different warps may execute different forms of the barrier{.cta} instruction using the same
barrier name and thread count. One example mixes barrier{.cta}.sync and barrier{.cta}.arrive
to implement producer/consumer models. The producer threads execute barrier{.cta}.arrive to
announce their arrival at the barrier and continue execution without delay to produce the next
value, while the consumer threads execute the barrier{.cta}.sync to wait for a resource to be
produced. The roles are then reversed, using a different barrier, where the producer threads execute
a barrier{.cta}.sync to wait for a resource to consumed, while the consumer threads announce
that the resource has been consumed with barrier{.cta}.arrive. Care must be taken to keep a warp
from executing more barrier{.cta} instructions than intended (barrier{.cta}.arrive followed
by any other barrier{.cta} instruction to the same barrier) prior to the reset of the
barrier. barrier{.cta}.red should not be intermixed with barrier{.cta}.sync or
barrier{.cta}.arrive using the same active barrier. Execution in this case is unpredictable.
The optional .cta qualifier simply indicates CTA-level applicability of the barrier and it
doesn’t change the semantics of the instruction.
bar{.cta}.sync is equivalent to barrier{.cta}.sync.aligned. bar{.cta}.arrive is
equivalent to barrier{.cta}.arrive.aligned. bar{.cta}.red is equivalent to
barrier{.cta}.red.aligned.
Note
For .target sm_6x or below,
barrier{.cta} instruction without .aligned modifier is equivalent to .aligned
variant and has the same restrictions as of .aligned variant.
All threads in warp (except for those have exited) must execute barrier{.cta} instruction
in convergence.
Examples
// Use bar.sync to arrive at a pre-computed barrier number and
// wait for all threads in CTA to also arrive:
st.shared [r0],r1; // write my result to shared memory
bar.cta.sync 1; // arrive, wait for others to arrive
ld.shared r2,[r3]; // use shared results from other threads
// Use bar.sync to arrive at a pre-computed barrier number and
// wait for fixed number of cooperating threads to arrive:
#define CNT1 (8*12) // Number of cooperating threads
st.shared [r0],r1; // write my result to shared memorybar.cta.sync 1, CNT1; // arrive, wait for others to arriveld.shared r2,[r3]; // use shared results from other threads
plaintext
// Use bar.red.and to compare results across the entire CTA:
setp.eq.u32 p,r1,r2; // p is True if r1==r2
bar.cta.red.and.pred r3,1,p; // r3=AND(p) forall threads in CTA
// Use bar.red.popc to compute the size of a group of threads
// that have a specific condition True:
setp.eq.u32 p,r1,r2; // p is True if r1==r2
bar.cta.red.popc.u32 r3,1,p; // r3=SUM(p) forall threads in CTA
/* Producer/consumer model. The producer deposits a value in
shared memory, signals that it is complete but does not wait
using bar.arrive, and begins fetching more data from memory.
Once the data returns from memory, the producer must wait
until the consumer signals that it has read the value from
the shared memory location. In the meantime, a consumer
thread waits until the data is stored by the producer, reads
it, and then signals that it is done (without waiting).
*/
// Producer code places produced value in shared memory.
st.shared [r0],r1;
bar.arrive 0,64;
ld.global r1,[r2];
bar.sync 1,64;
…
// Consumer code, reads value from shared memory
bar.sync 0,64;
ld.shared r1,[r0];
bar.arrive 1,64;
…
9.7.15.2. Parallel Synchronization and Communication Instructions: bar.warp.sync#
bar.warp.sync
Barrier synchronization for threads in a warp.
Syntax
bar.warp.sync membermask;
Description
bar.warp.sync will cause executing thread to wait until all threads corresponding to
membermask have executed a bar.warp.sync with the same membermask value before resuming
execution.
Operand membermask specifies a 32-bit integer which is a mask indicating threads participating
in barrier where the bit position corresponds to thread’s laneid.
The behavior of bar.warp.sync is undefined if the executing thread is not in the membermask.
bar.warp.sync also guarantee memory ordering among threads participating in barrier. Thus,
threads within warp that wish to communicate via memory can store to memory, execute
bar.warp.sync, and then safely read values stored by other threads in warp.
Note
For .target sm_6x or below, all threads in membermask must execute the same
bar.warp.sync instruction in convergence, and only threads belonging to some membermask
can be active when the bar.warp.sync instruction is executed. Otherwise, the behavior is
undefined.
Examples
st.shared.u32 [r0],r1; // write my result to shared memory
bar.warp.sync 0xffffffff; // arrive, wait for others to arrive
ld.shared.u32 r2,[r3]; // read results written by other threads
9.7.15.3. Parallel Synchronization and Communication Instructions: barrier.cluster#
Performs barrier synchronization and communication within a cluster.
barrier.cluster instructions can be used by the threads within the cluster for synchronization
and communication.
barrier.cluster.arrive instruction marks warps’ arrival at barrier without causing executing
thread to wait for threads of other participating warps.
barrier.cluster.wait instruction causes the executing thread to wait for all non-exited threads
of the cluster to perform barrier.cluster.arrive.
In addition, barrier.cluster instructions cause the executing thread to wait for all non-exited
threads from its warp.
When all non-exited threads in the cluster have executed barrier.cluster.arrive, the barrier
completes and is automatically reinitialized. After using barrier.cluster.wait to detect completion
of the barrier, a thread may immediately arrive at the barrier once again.
Each thread must arrive at the barrier only once before the barrier completes.
The barrier.cluster.wait instruction guarantees that when it completes the execution, memory
accesses (except asynchronous operations) requested, in program order, prior to the preceding
barrier.cluster.arrive by all threads in the cluster are complete and visible to the executing
thread.
There is no memory ordering and visibility guarantee for memory accesses requested by the executing
thread, in program order, after barrier.cluster.arrive and prior to barrier.cluster.wait.
The optional .relaxed qualifier on barrier.cluster.arrive specifies that there are no memory
ordering and visibility guarantees provided for the memory accesses performed prior to
barrier.cluster.arrive.
The optional .sem and .acquire qualifiers on instructions barrier.cluster.arrive and
barrier.cluster.wait specify the memory synchronization as described in the
Memory Consistency Model. If the optional .sem qualifier is absent for
barrier.cluster.arrive, .release is assumed by default. If the optional .acquire
qualifier is absent for barrier.cluster.wait, .acquire is assumed by default.
The optional .aligned qualifier indicates that all threads in the warp must execute the same
barrier.cluster instruction. In conditionally executed code, an aligned barrier.cluster
instruction should only be used if it is known that all threads in the warp evaluate the condition
identically, otherwise behavior is undefined.
Examples
// use of arrive followed by wait
ld.shared::cluster.u32 r0, [addr];
barrier.cluster.arrive.aligned;
...
barrier.cluster.wait.aligned;
st.shared::cluster.u32 [addr], r1;
// use memory fence prior to arrive for relaxed barrier
@cta0 ld.shared::cluster.u32 r0, [addr];
fence.cluster.acq_rel;
barrier.cluster.arrive.relaxed.aligned;
…
barrier.cluster.wait.aligned;
@cta1 st.shared::cluster.u32 [addr], r1;
9.7.15.4. Parallel Synchronization and Communication Instructions: membar / fence#
The membar instruction guarantees that prior memory accesses requested by this thread (ld,
st, atom and red instructions) are performed at the specified level, before later
memory operations requested by this thread following the membar instruction. The level
qualifier specifies the set of threads that may observe the ordering effect of this operation.
A memory read (e.g., by ld or atom) has been performed when the value read has been
transmitted from memory and cannot be modified by another thread at the indicated level. A memory
write (e.g., by st, red or atom) has been performed when the value written has become
visible to other threads at the specified level, that is, when the previous value can no longer be
read.
The fence instruction establishes an ordering between memory accesses requested by this thread
(ld, st, atom and red instructions) as described in the
Memory Consistency Model. The scope qualifier specifies the set of threads that may
observe the ordering effect of this operation.
fence.acq_rel is a light-weight fence that is sufficient for memory synchronization in most
programs. Instances of fence.acq_rel synchronize when combined with additional memory operations
as described in acquire and release patterns in the Memory Consistency Model.
If the optional .sem qualifier is absent, .acq_rel
is assumed by default.
fence.sc is a slower fence that can restore sequential consistency when used in sufficient
places, at the cost of performance. Instances of fence.sc with sufficient scope always
synchronize by forming a total order per scope, determined at runtime. This total order can be
constrained further by other synchronization in the program.
Qualifiers .op_restrict and .sync_restrict restrict the class of memory operations
for which the fence instruction provides the memory ordering guarantees. When .op_restrict
is .mbarrier_init, the synchronizing effect of the fence only applies to the prior
mbarrier.init operations executed by the same thread on mbarrier objects in .shared::cta
state space. When .sync_restrict is .sync_restrict::shared::cta, .sem must be
.release, and the effect of the fence only applies to operations performed on objects in
.shared::cta state space. Likewise, when .sync_restrict is .sync_restrict::shared::cluster,
.sem must be .acquire, and the effect of the fence only applies to operations performed on
objects in .shared::cluster state space. When either .sync_restrict::shared::cta or
.sync_restrict::shared::cluster is present, the .scope must be specified as .cluster.
When .sync_restrict is .sync_restrict::shared::cluster::read, .sem must be
.release, and the effect of the fence only applies to read operations performed on objects in
.shared::cluster state space. When this synchronization restriction is present, the .scope
must be specified as .cluster.
Caution
fence.proxy.async::generic.release.sync_restrict::shared::cluster::read.cluster is
a non-cumulative fence operation: it does not transitively establish ordering with respect to
Causality Order.
The address operand addr and the operand size together specify the memory range
[addr,addr+size-1] on which the ordering guarantees on the memory accesses across the proxies is to be
provided. The only supported value for the size operand is 128, which must be a constant integer literal.
Generic Addressing is used unconditionally, and the address specified by
the operand addr must fall within the .global state space. Otherwise, the behavior is undefined.
On sm_70 and higher membar is a synonym for fence.sc1, and the membar
levels cta, gl and sys are synonymous with the fence scopes cta, gpu and
sys respectively.
membar.proxy and fence.proxy instructions establish an ordering between memory accesses that
may happen through different proxies.
A uni-directional proxy ordering from the from-proxykind to the to-proxykind establishes
ordering between a prior memory access performed via the from-proxykind and a subsequent memory access
performed via the to-proxykind.
A bi-directional proxy ordering between two proxykinds establishes two uni-directional proxy orderings
: one from the first proxykind to the second proxykind and the other from the second proxykind to the first
proxykind.
The .proxykind qualifier indicates the bi-directional proxy ordering that is established between the memory
accesses done between the generic proxy and the proxy specified by .proxykind.
Bi-directional proxy fences do not directly synchronize with other fences in the sense that
fences with .release or .acquire semantics do. Instead, bi-directional proxy fences
take effect within a single thread and therefore do not have a .scope qualifier. Their
cross-proxy synchronizing effect composes with other forms of synchronization according to
the rules of the Memory Consistency Model.
Value .alias of the .proxykind qualifier refers to memory accesses performed using virtually
aliased addresses to the same memory location. Value .async of the .proxykind qualifier specifies
that the memory ordering is established between the async proxy and the generic proxy. The memory
ordering is limited only to operations performed on objects in the state space specified. If no state space
is specified, then the memory ordering applies on all state spaces.
A .release proxy fence can form a release sequence that synchronizes with an acquire
sequence that contains a .acquire proxy fence. The .to_proxykind and
.from_proxykind qualifiers indicate the uni-directional proxy ordering that is established.
On sm_70 and higher, membar.proxy is a synonym for fence.proxy.
1 The semantics of fence.sc introduced with sm_70 is a superset of the semantics of
membar and the two are compatible; when executing on sm_70 or later architectures,
membar acquires the full semantics of fence.sc.
// Acquire remote barrier state via async proxy.
barrier.cluster.wait.acquire;
fence.proxy.async::generic.acquire.sync_restrict::shared::cluster.cluster;
// Release local barrier state via generic proxy.
mbarrier.init [bar];
fence.mbarrier_init.release.cluster;
barrier.cluster.arrive.relaxed;
// Acquire local shared memory via generic proxy.
mbarrier.try_wait.relaxed.cluster.shared::cta.b64 complete, [addr], parity;
fence.acquire.sync_restrict::shared::cluster.cluster;
// Release local shared memory via generic proxy.
fence.release.sync_restrict::shared::cta.cluster;
mbarrier.arrive.relaxed.cluster.shared::cluster.b64 state, [bar];
Atomically loads the original value at location a into destination register d, performs a
reduction operation with operand b and the value in location a, and stores the result of the
specified operation at location a, overwriting the original value. For the .cas (compare-and-swap)
operation, operand b is the compare value and operand c is the swap value. The operation
compares the value at location a with operand b; if they are equal, it stores operand c
at location a, otherwise it leaves the value at location a unchanged. Operand a specifies a
location in the specified state space. If no state space is given, perform the memory accesses using
Generic Addressing. atom with scalar type may be used only
with .global and .shared spaces and with generic addressing, where the address points to
.global or .shared space. atom with vector type may be used only with .global space
and with generic addressing where the address points to .global space.
For atom with vector type, operands d and b are brace-enclosed vector expressions, size
of which is equal to the size of vector qualifier.
If no sub-qualifier is specified with .shared state space, then ::cta is assumed by default.
The optional .sem qualifier specifies a memory synchronizing effect as described in the
Memory Consistency Model. If the .sem qualifier is absent,
.relaxed is assumed by default.
The optional .scope qualifier specifies the set of threads that can directly observe the memory
synchronizing effect of this operation, as described in the Memory Consistency Model.
If the .scope qualifier is absent, .gpu scope is
assumed by default.
Table 41 shows the valid combinations of types and atomic operations for scalar atom
instructions.
Table 41 Atom Scalar Type Operations
Type
Integer Operations
Floating-Point Operations
Bit Operations
.u32
.add, .inc, .dec,
.min, .max
Not supported
Not supported
.s32
.add, .min, .max
Not supported
Not supported
.u64
.add, .min, .max
Not supported
Not supported
.s64
.min, .max
Not supported
Not supported
.f32
Not supported
.add{.noftz}
Not supported
.f64
Not supported
.add (noftz by default)
Not supported
.f16
Not supported
.add (requires .noftz)
Not supported
.f16x2
Not supported
.add (requires .noftz)
Not supported
.bf16
Not supported
.add (requires .noftz)
Not supported
.bf16x2
Not supported
.add (requires .noftz)
Not supported
.b16
Not supported
Not supported
.cas
.b32
Not supported
Not supported
.and, .or, .xor,
.exch, .cas
.b64
Not supported
Not supported
.and, .or, .xor,
.exch, .cas
.b128
Not supported
Not supported
.exch, .cas
For atom with vector type, the supported combinations of vector qualifier and types, and atomic
operations supported on these combinations are depicted in the following table:
Vector qualifier
Types
.f16/ bf16
.f16x2/ bf16x2
.f32
.v2
.add, .min, .max
(all require .noftz)
.add, .min, .max
(all require .noftz)
.add
.v4
.add, .min, .max
(all require .noftz)
.add, .min, .max
(all require .noftz)
.add
.v8
.add, .min, .max
(all require .noftz)
Not supported
Not Supported
Two atomic operations (atom or red) are performed atomically with respect to each other only
if each operation specifies a scope that includes the other. When this condition is not met, each
operation observes the other operation being performed as if it were split into a read followed by a
dependent write.
atom instruction on packed type or vector type, accesses adjacent scalar elements in memory. In
such cases, the atomicity is guaranteed separately for each of the individual scalar elements; the
entire atom is not guaranteed to be atomic as a single access.
For sm_6x and earlier architectures, atom operations on .shared state space do not
guarantee atomicity with respect to normal store instructions to the same address. It is the
programmer’s responsibility to guarantee correctness of programs that use shared memory atomic
instructions, e.g., by inserting barriers between normal stores and atomic operations to a common
address, or by using atom.exch to store to locations accessed by other atomic operations.
Supported addressing modes for operand a and alignment requirements are described in Addresses as Operands
Operation Descriptions:
Integer operations: .add, .inc, .dec, .min, .max
The .inc and .dec operations return a result in the range [0..b].
.inc and .dec are only supported for .u32 type.
Floating-point operations: .add, .min, .max
The .add operation rounds to nearest even.
The .min and .max operations implement the exact same floating-point instructions as the
non-atomic min and max instructions, but perform them atomically.
The atom.add.f32 operation without .noftz, flushes subnormal inputs and results to
sign-preserving zero on global memory but supports subnormal inputs and results and doesn’t flush
them to zero on shared memory. atom.add.f16, atom.add.f16x2, atom.add.bf16 and
atom.add.bf16x2 operations require the .noftz qualifier; it preserves subnormal inputs
and results, and does not flush them to zero.
atom.add.f16, atom.add.f16x2, atom.add.bf16 and atom.add.bf16x2 operations
require the .noftz qualifier; it preserves subnormal inputs and results, and does not flush
them to zero.
Bit operations: .and, .or, .xor, .cas (compare-and-swap), and .exch
(exchange)
The .cas operation takes three operands: d (destination), [a] (memory address),
b (compare value), and c (swap value). It atomically compares the value at location a
with operand b; if they are equal, it stores operand c at location a and returns the
original value in d. If they are not equal, it leaves the value at location a unchanged
and returns the original value in d.
When the optional argument cache_policy is specified, the qualifier .level::cache_hint is
required. The 64-bit operand cache_policy specifies the cache eviction policy that may be used
during the memory access.
The qualifier .level::cache_hint is only supported for .global state space and for generic
addressing where the address points to the .global state space.
cache_policy is a hint to the cache subsystem and may not always be respected. It is treated as
a performance hint only, and does not change the memory consistency behavior of the program.
Semantics
atomic {
d = *a;
*a = (operation == cas) ? operation(*a, b, c)
: operation(*a, b);
}
where
inc(r, s) = (r >= s) ? 0 : r+1;
dec(r, s) = (r==0 || r > s) ? s : r-1;
exch(r, s) = s;
cas(r,s,t) = (r == s) ? t : r;
Performs a reduction operation with operand b and the value in location a, and stores the
result of the specified operation at location a, overwriting the original value. Operand a
specifies a location in the specified state space. If no state space is given, perform the memory
accesses using Generic Addressing. red with scalar type may
be used only with .global and .shared spaces and with generic addressing, where the address
points to .global or .shared space. red with vector type may be used only with
.global space and with generic addressing where the address points to .global space.
For red with vector type, operand b is brace-enclosed vector expressions, size of which is
equal to the size of vector qualifier.
If no sub-qualifier is specified with .shared state space, then ::cta is assumed by default.
The optional .sem qualifier specifies a memory synchronizing effect as described in the
Memory Consistency Model. If the .sem qualifier is absent,
.relaxed is assumed by default.
The optional .scope qualifier specifies the set of threads that can directly observe the memory
synchronizing effect of this operation, as described in the Memory Consistency Model.
If the .scope qualifier is absent, .gpu scope is
assumed by default.
Table 42 shows the valid combinations of types and reduction operations for scalar red
instructions.
Table 42 Red Scalar Type Operations
Type
Integer Operations
Floating-Point Operations
Bit Operations
.u32
.add, .inc, .dec,
.min, .max
Not supported
Not supported
.s32
.add, .min, .max
Not supported
Not supported
.u64
.add, .min, .max
Not supported
Not supported
.s64
.min, .max
Not supported
Not supported
.f32
Not supported
.add{.noftz}
Not supported
.f64
Not supported
.add (noftz by default)
Not supported
.f16
Not supported
.add (requires .noftz)
Not supported
.f16x2
Not supported
.add (requires .noftz)
Not supported
.bf16
Not supported
.add (requires .noftz)
Not supported
.bf16x2
Not supported
.add (requires .noftz)
Not supported
.b32
Not supported
Not supported
.and, .or, .xor
.b64
Not supported
Not supported
.and, .or, .xor
For red with vector type, the supported combinations of vector qualifier, types and reduction
operations supported on these combinations are depicted in following table:
Vector qualifier
Types
.f16/ bf16
.f16x2/ bf16x2
.f32
.v2
.add, .min, .max
(all require .noftz)
.add, .min, .max
(all require .noftz)
.add
.v4
.add, .min, .max
(all require .noftz)
.add, .min, .max
(all require .noftz)
.add
.v8
.add, .min, .max
(all require .noftz)
Not supported
Not Supported
Two atomic operations (atom or red) are performed atomically with respect to each other only
if each operation specifies a scope that includes the other. When this condition is not met, each
operation observes the other operation being performed as if it were split into a read followed by a
dependent write.
red instruction on packed type or vector type, accesses adjacent scalar elements in memory. In
such case, the atomicity is guaranteed separately for each of the individual scalar elements; the
entire red is not guaranteed to be atomic as a single access.
For sm_6x and earlier architectures, red operations on .shared state space do not
guarantee atomicity with respect to normal store instructions to the same address. It is the
programmer’s responsibility to guarantee correctness of programs that use shared memory reduction
instructions, e.g., by inserting barriers between normal stores and reduction operations to a common
address, or by using atom.exch to store to locations accessed by other reduction operations.
Supported addressing modes for operand a and alignment requirements are described in Addresses as Operands
Operation Descriptions:
Integer operations: .add, .inc, .dec, .min, .max
The .inc and .dec operations return a result in the range [0..b].
.inc and .dec are only supported for .u32 type.
Floating-point operations: .add, .min, .max
The .add operation rounds to nearest even.
The .min and .max operations implement the exact same floating-point instructions as the
non-atomic min and max instructions, but perform them atomically.
The red.add.f32 operation without .noftz, flushes subnormal inputs and results to
sign-preserving zero on global memory but supports subnormal inputs and results and doesn’t flush
them to zero on shared memory. red.add.f16, red.add.f16x2, red.add.bf16 and
red.add.bf16x2 operations require the .noftz qualifier; it preserves subnormal inputs
and results, and does not flush them to zero.
red.add.f16, red.add.f16x2, red.add.bf16 and red.add.bf16x2 operations
require the .noftz qualifier; it preserves subnormal inputs and results, and does not flush
them to zero.
Bit operations: .and, .or, .xor
When the optional argument cache_policy is specified, the qualifier .level::cache_hint is
required. The 64-bit operand cache_policy specifies the cache eviction policy that may be used
during the memory access.
The qualifier .level::cache_hint is only supported for .global state space and for generic
addressing where the address points to the .global state space.
cache_policy is a hint to the cache subsystem and may not always be respected. It is treated as
a performance hint only, and does not change the memory consistency behavior of the program.
Semantics
*a = operation(*a, b);
where
inc(r, s) = (r >= s) ? 0 : r+1;
dec(r, s) = (r==0 || r > s) ? s : r-1;
red.async is a non-blocking instruction which initiates an asynchronous reduction operation
specified by .op, with the operand b and the value at the destination memory location
specified by operand a.
red.async is performed in the generic proxy.
Operands
a is a destination address, and must be either a register, or of the form
register+immOff, as described in Addresses as Operands.
b is a source value, of the type indicated by qualifier .type.
.completion_mechanism specifies the mechanism for observing the
completion of the asynchronous operation.
When .completion_mechanism is .mbarrier::complete_tx::bytes: upon
completion of the asynchronous operation, a
complete-tx
operation will be performed on the mbarrier object specified by the operand mbar,
with completeCount argument equal to the amount of data stored in bytes.
When .completion_mechanism is not specified: the completion of the store
synchronizes with the end of the CTA.
This instruction accesses its mbarrier operand using generic-proxy.
.op specifies the reduction operation.
The .inc and .dec operations return a result in the range [0..b].
.type specifies the type of the source operand b.
Conditions
When .sem is .relaxed:
The reduce operation is a relaxed memory operation.
The complete-tx operation on the mbarrier has .release
semantics at .cluster scope.
The shared-memory addresses of the destination operand a and the
mbarrier operand mbar must meet all of the following conditions:
They belong to the same CTA.
The CTA to which they belong is different from the CTA of the executing thread,
but must be within the same cluster.
Otherwise, the behavior is undefined.
.mmio must not be specified.
If .ss is specified, it must be .shared::cluster.
If .ss is not specified, generic addressing is used for operands a and mbar.
If the generic addresses specified do not fall within the address window of
.shared::cluster state space, the behavior is undefined.
If .completion_mechanism is specified, it must be .mbarrier::complete_tx::bytes.
If .completion_mechanism is not specified, it defaults to .mbarrier::complete_tx::bytes.
When .sem is .release:
The reduce operation is a strong memory operation with .release semantics
at the scope specified by .scope.
If .mmio is specified, .scope must be .sys.
If .ss is specified, it must be .global.
If .ss is not specified, generic addressing is used for operand a.
If the generic address specified does not fall within the address window of
.global state space, the behavior is undefined.
multimem.red.async is a non-blocking instruction which initiates an asynchronous
reduction operation specified by .op, with operand b and the value at memory
locations residing on each GPU’s memory referred to by the destination multimem address
operand a.
Address operand a must be a multimem address. Otherwise, the behavior is undefined.
Operands
a is a destination address, and must be either a register, or of the form
register+immOff, as described in Addresses as Operands.
b is a source value, of the type indicated by qualifier .type.
Qualifiers
The mandatory .sem modifier specifies the memory ordering semantics as
described in the Memory Consistency Model.
The mandatory .scope modifier specifies the set of threads with which this instruction
can directly synchronize. The reduce operation is a strong memory operation with
.release semantics at the scope specified by .scope.
.ss specifies the state space of the destination operand a.
If .ss is specified, it must be .global. If .ss is not specified,
generic addressing is used for operand a. If the generic address specified
does not fall within the address window of .global state space, the behavior
is undefined.
Performs a reduction of the source predicate across all active threads in a warp. The destination
predicate value is the same across all threads in the warp.
The reduction modes are:
.all
True if source predicate is True for all active threads in warp. Negate the source
predicate to compute .none.
.any
True if source predicate is True for some active thread in warp. Negate the source
predicate to compute .not_all.
.uni
True if source predicate has the same value in all active threads in warp. Negating the
source predicate also computes .uni.
In the ballot form, vote.ballot.b32 simply copies the predicate from each thread in a warp
into the corresponding bit position of destination register d, where the bit position
corresponds to the thread’s lane id.
An inactive thread in warp will contribute a 0 for its entry when participating in
vote.ballot.b32.
Release Notes
Note that vote applies to threads in a single warp, not across an entire CTA.
Examples
vote.all.pred p,q;
vote.uni.pred p,q;
vote.ballot.b32 r1,p; // get 'ballot' across warp
9.7.15.10. Parallel Synchronization and Communication Instructions: vote.sync#
vote.sync will cause executing thread to wait until all non-exited threads corresponding to
membermask have executed vote.sync with the same qualifiers and same membermask value
before resuming execution.
Operand membermask specifies a 32-bit integer which is a mask indicating threads participating
in this instruction where the bit position corresponds to thread’s laneid. Operand a is a
predicate register.
In the mode form, vote.sync performs a reduction of the source predicate across all non-exited
threads in membermask. The destination operand d is a predicate register and its value is
the same across all threads in membermask.
The reduction modes are:
.all
True if source predicate is True for all non-exited threads in membermask. Negate the
source predicate to compute .none.
.any
True if source predicate is True for some thread in membermask. Negate the source
predicate to compute .not_all.
.uni
True if source predicate has the same value in all non-exited threads in
membermask. Negating the source predicate also computes .uni.
In the ballot form, the destination operand d is a .b32 register. In this form,
vote.sync.ballot.b32 simply copies the predicate from each thread in membermask into the
corresponding bit position of destination register d, where the bit position corresponds to the
thread’s lane id.
A thread not specified in membermask will contribute a 0 for its entry in
vote.sync.ballot.b32.
The behavior of vote.sync is undefined if the executing thread is not in the membermask.
Note
For .target sm_6x or below, all threads in membermask must execute the same vote.sync
instruction in convergence, and only threads belonging to some membermask can be active when
the vote.sync instruction is executed. Otherwise, the behavior is undefined.
Examples
vote.sync.all.pred p,q,0xffffffff;
vote.sync.ballot.b32 r1,p,0xffffffff; // get 'ballot' across warp
9.7.15.11. Parallel Synchronization and Communication Instructions: match.sync#
match.sync
Broadcast and compare a value across threads in warp.
Syntax
match.any.sync.type d, a, membermask;
match.all.sync.type d[|p], a, membermask;
.type = { .b32, .b64 };
Description
match.sync will cause executing thread to wait until all non-exited threads from membermask
have executed match.sync with the same qualifiers and same membermask value before resuming
execution.
Operand membermask specifies a 32-bit integer which is a mask indicating threads participating
in this instruction where the bit position corresponds to thread’s laneid.
match.sync performs broadcast and compare of operand a across all non-exited threads in
membermask and sets destination d and optional predicate p based on mode.
Operand a has instruction type and d has .b32 type.
Destination d is a 32-bit mask where bit position in mask corresponds to thread’s laneid.
The matching operation modes are:
.all
d is set to mask corresponding to non-exited threads in membermask if all non-exited
threads in membermask have same value of operand a; otherwise d is set
to 0. Optionally predicate p is set to true if all non-exited threads in membermask have
same value of operand a; otherwise p is set to false. The sink symbol ‘_’ may be used in
place of any one of the destination operands.
.any
d is set to mask of non-exited threads in membermask that have same value of operand
a.
The behavior of match.sync is undefined if the executing thread is not in the membermask.
Release Notes
Note that match.sync applies to threads in a single warp, not across an entire CTA.
Examples
match.any.sync.b32 d, a, 0xffffffff;
match.all.sync.b64 d|p, a, mask;
9.7.15.12. Parallel Synchronization and Communication Instructions: activemask#
activemask
Queries the active threads within a warp.
Syntax
activemask.b32 d;
Description
activemask queries predicated-on active threads from the executing warp and sets the destination
d with 32-bit integer mask where bit position in the mask corresponds to the thread’s
laneid.
Destination d is a 32-bit destination register.
An active thread will contribute 1 for its entry in the result and exited or inactive or
predicated-off thread will contribute 0 for its entry in the result.
Examples
activemask.b32 %r1;
9.7.15.13. Parallel Synchronization and Communication Instructions: redux.sync#
redux.sync
Perform reduction operation on the data from each predicated active thread in the thread group.
redux.sync will cause the executing thread to wait until all non-exited threads corresponding to
membermask have executed redux.sync with the same qualifiers and same membermask value
before resuming execution.
Operand membermask specifies a 32-bit integer which is a mask indicating threads participating
in this instruction where the bit position corresponds to thread’s laneid.
redux.sync performs a reduction operation .op of the 32 bit source register src across
all non-exited threads in the membermask. The result of the reduction operation is written to
the 32 bit destination register dst.
Reduction operation can be one of the bitwise operation in .and, .or, .xor or arithmetic
operation in .add, .min , .max.
For the .add operation result is truncated to 32 bits.
For .f32 instruction type, if the input value is 0.0 then +0.0 > -0.0.
If .abs qualifier is specified, then the absolute value of the input is considered for the
reduction operation.
If the .NaN qualifier is specified, then the result of the reduction operation is canonical NaN
if the input to the reduction operation from any participating thread is NaN.
In the absence of .NaN qualifier, only non-NaN values are considered for the reduction operation
and the result will be canonical NaN when all inputs are NaNs.
The behavior of redux.sync is undefined if the executing thread is not in the membermask.
Release Notes
Note that redux.sync applies to threads in a single warp, not across an entire CTA.
9.7.15.14. Parallel Synchronization and Communication Instructions: griddepcontrol#
griddepcontrol
Control execution of dependent grids.
Syntax
griddepcontrol.action;
.action = { .launch_dependents, .wait }
Description
The griddepcontrol instruction allows the dependent grids and prerequisite grids as defined by
the runtime, to control execution in the following way:
.launch_dependents modifier signals that specific dependents the runtime system designated to
react to this instruction can be scheduled as soon as all other CTAs in the grid issue the same
instruction or have completed. The dependent may launch before the completion of the current
grid. There is no guarantee that the dependent will launch before the completion of the current
grid. Repeated invocations of this instruction by threads in the current CTA will have no additional
side effects past that of the first invocation. A release fence preceeding a griddepcontrol.launch_dependents
in program-order synchronizes with the start of a dependent grid if either both grids have the same
memory synchronization domain
and the fence scope is gpu, or if the fence scope is sys.
.wait modifier causes the executing thread to wait until all prerequisite grids in flight have
completed and all the memory operations from the prerequisite grids are performed and made visible
to the current grid.
Note
If the prerequisite grid is using griddepcontrol.launch_dependents, then the dependent grid
must use griddepcontrol.wait to ensure correct functional execution.
9.7.15.15. Parallel Synchronization and Communication Instructions: elect.sync#
elect.sync
Elect a leader thread from a set of threads.
Syntax
elect.sync d|p, membermask;
Description
elect.sync elects one predicated active leader thread from among a set of threads specified by
membermask. laneid of the elected thread is returned in the 32-bit destination operand
d. The sink symbol ‘_’ can be used for destination operand d. The predicate destination
p is set to True for the leader thread, and False for all other threads.
Operand membermask specifies a 32-bit integer indicating the set of threads from which a leader
is to be elected. The behavior is undefined if the executing thread is not in membermask.
Election of a leader thread happens deterministically, i.e. the same leader thread is elected for
the same membermask every time.
The mandatory .sync qualifier indicates that elect causes the executing thread to wait until
all threads in the membermask execute the elect instruction before resuming execution.
Examples
elect.sync %r0|%p0, 0xffffffff;
9.7.15.16. Parallel Synchronization and Communication Instructions: mbarrier#
mbarrier is a barrier created in shared memory that supports :
Synchronizing any subset of threads within a CTA
One-way synchronization of threads across CTAs of a cluster. As noted in
mbarrier support with shared memory, threads can
perform only arrive operations but not *_wait on an mbarrier located in shared::cluster
space.
Waiting for completion of asynchronous memory operations initiated by a thread and making them
visible to other threads.
An mbarrier object is an opaque object in memory which can be initialized and invalidated using :
mbarrier.init
mbarrier.inval
Operations supported on mbarrier objects are :
mbarrier.expect_tx
mbarrier.complete_tx
mbarrier.arrive
mbarrier.arrive_drop
mbarrier.test_wait
mbarrier.try_wait
mbarrier.pending_count
mbarrier.check_layout
cp.async.mbarrier.arrive
Performing any mbarrier operation except mbarrier.init on an uninitialized mbarrier object
results in undefined behavior.
Performing any non-mbarrier or mbarrier.init operations on an initialized mbarrier object
results in undefined behavior.
Unlike bar{.cta}/barrier{.cta} instructions which can access a limited number of barriers
per CTA, mbarrier objects are user defined and are only limited by the total shared memory size
available.
mbarrier operations enable threads to perform useful work after the arrival at the mbarrier and
before waiting for the mbarrier to complete.
9.7.15.16.1. Size and alignment of mbarrier object#
An mbarrier object is an opaque object with the following type and alignment requirements :
An opaque mbarrier object supports two different layouts:
.layout::v0
.layout::v1
The exact layout of the mbarrier object can be specified at the time of creation.
The asynchronous operations that can be tracked by an mbarrier object depend on the layout.
Refer to Contents of the mbarrier object
for more details.
An opaque mbarrier object irrespective of the layout keeps track of the following information :
Current primary and conditional phases of the mbarrier object
Count of pending arrivals for the current phase of the mbarrier object
Count of expected arrivals for the next phase of the mbarrier object
Count of pending asynchronous memory operations (or transactions) tracked by the current phase of
the mbarrier object. This is also referred to as tx-count.
However, an mbarrier object with .layout::v1 additionally keeps track of the following information:
Payload report corresponding to each primary phase
An mbarrier object progresses through a sequence of phases where each phase is defined by threads
performing an expected number of
arrive-on
operations.
The valid range of each of the counts differs based on the mbarrier layout.
Refer Table 43 for more details.
The primary phase of an mbarrier object is the number of times the mbarrier object has been used to
synchronize threads and asynchronous
operations. In each primary phase {0, 1, 2, …}, threads perform in program order :
arrive-on
operations to complete the current primary phase and
test_wait / try_wait operations to check for the completion of the current primary phase.
An mbarrier object is automatically reinitialized upon completion of the current primary phase for
immediate use in the next phase. The current primary phase is incomplete and all prior primary phases
are complete.
For each primary phase of the mbarrier object, at least one test_wait or try_wait operation must be
performed which returns True for waitComplete before an arrive-on operation
in the subsequent primary phase.
The primary phase of an mbarrier object advances upon completion of arrivals, and transaction-count
updates of asynchronous operations tracked by the mbarrier.
The conditional phase advances if the primary phase advances, and no asynchronous operation tracked
by the mbarrier prevents it via a
report-on operation.
Mbarrier objects with .layout::v0 do not support tracking asynchronous operations that could prevent
the conditional phase from advancing via
report-on, resulting
in both phases advancing in unison. That is, either both phase advance, or no phase advances.
Mbarrier objects with .layout::v1 support tracking asynchronous operations that can prevent
the conditional phase from advancing via a
report-on operation.
If the primary phase advances, but the conditional phase does not advance, the payload report is
non-zero and may contain more information. If the conditional phase advances, the payload report is
zero.
An mbarrier object is automatically reinitialized upon completion of the current primary phase for
immediate use in the next phase. Refer
Phase Completion of the mbarrier object
for more details on conditional phase completion.
9.7.15.16.6. Tracking asynchronous operations by the mbarrier object#
Starting with the Hopper architecture (sm_9x), mbarrier object supports a new count, called
tx-count, which is used for tracking the completion of asynchronous memory operations or
transactions. tx-count tracks the number of asynchronous transactions, in units specified by the
asynchronous memory operation, that are outstanding and yet to be complete.
The tx-count of an mbarrier object must be set to the total amount of asynchronous memory
operations, in units as specified by the asynchronous operations, to be tracked by the current
phase. Upon completion of each of the asynchronous operations, the complete-tx
operation will be performed on the mbarrier object and thus progress the mbarrier towards the
completion of the current phase.
The expect-tx operation, with an expectCount argument, increases the tx-count of an
mbarrier object by the value specified by expectCount. This sets the current phase of the
mbarrier object to expect and track the completion of additional asynchronous transactions.
The complete-tx operation, with an completeCount argument, on an mbarrier object consists of the following:
mbarrier signaling
Signals the completion of asynchronous transactions that were tracked by the current phase. As a
result of this, tx-count is decremented by completeCount.
mbarrier potentially completing the current phase
If the current phase has been completed then the mbarrier transitions to the next phase. Refer to
Phase Completion of the mbarrier object
for details on phase completion requirements and phase transition process.
9.7.15.16.7. Tracking successful completion of an operation using the mbarrier object#
An mbarrier object with layout .layout::v1 can track asynchronous operations that prevent the
conditional phase from advancing and provide additional information via the payload report on
completion.
The mbarrier.test_wait and mbarrier.try_wait instructions with .phase_type::primary allow
observing primary phase completion and the payload report. The payload report consists of a
report predicate (reportPredicate) and a report value (reportValue). For the conditional
phase to advance, the entire payload report must be zero.
If the predicate i.e. reportPredicate is zero, the value reportValue is guaranteed to be
zero and therefore the conditional phase has advanced.
The mbarrier.test_wait and mbarrier.try_wait instructions with .phase_type::conditional
allow observing the conditional phase advance which means the payload report was zero.
9.7.15.16.8. Phase Completion of the mbarrier object#
The requirements for completion of the current phase are described below. Upon completion of the
current phase, the phase transitions to the subsequent phase as described below.
Current primary phase completion requirements
An mbarrier object irrespective of the layout completes the current primary phase when all of
the following conditions are met:
The count of the pending arrivals has reached zero.
The tx-count has reached zero.
Current conditional phase completion requirements
An mbarrier object completes the current conditional phase when all of the following
conditions are met:
The count of the pending arrivals has reached zero.
The tx-count has reached zero.
If the layout of the mbarrier is .layout::v1, then the payload report associated with the
primary phase was zero.
Phase transition
When an mbarrier object with .layout::v0 completes the current phase, the following
actions are performed atomically:
The mbarrier object transitions to the next primary and conditional phases.
The pending arrival count is reinitialized to the expected arrival count.
When an mbarrier object with .layout::v1 completes the current phase, the following
actions are performed atomically:
If the payload report associated with the current primary phase of the mbarrier
is zero, then the conditional phase advances.
The mbarrier object transitions to the next primary phase.
The payload report corresponding to the next primary phase is reinitialized to zero.
The pending arrival count is reinitialized to the expected arrival count.
9.7.15.16.9. Arrive-on operation on mbarrier object#
An arrive-on operation, with an optional count argument, on an mbarrier object consists of the
following 2 steps :
mbarrier signalling:
Signals the arrival of the executing thread OR completion of the asynchronous instruction which
signals the arrive-on operation initiated by the executing thread on the mbarrier object. As a
result of this, the pending arrival count is decremented by count. If the count argument is
not specified, then it defaults to 1.
mbarrier potentially completing the current phase:
If the current phase has been completed then the mbarrier transitions to the next phase. Refer to
Phase Completion of the mbarrier object
for details on phase completion requirements and phase transition process.
9.7.15.16.10. Report-on operation on mbarrier object#
The report-on operation on an mbarrier object signals miscellaneous information regarding
asynchronous operation. For example, such a miscellaneous information can be about errors,
warnings encountered; otherwise, it can as well be any extra information conveyed by
asynchronous operation.
The miscellaneous information reported by asynchronous operation via report-onmbarrier operation
would be updated in the payload report.
The following asynchronous operations can potentially issue report-on operation
on an associated mbarrier object:
Fabric operations such as fabric.try_get, fabric.try_put, fabric.try_red,
fabric.try_pullred, fabric.try_get.async.tensor, fabric.try_put.async.tensor,
fabric.try_red.async.tensor. Refer to Fabric Reporting Mechanism for more details.
9.7.15.16.11. mbarrier support with shared memory#
The following table summarizes the support of various mbarrier operations on mbarrier objects
located at different shared memory locations:
mbarrier operations
.shared::cta
.shared::cluster
mbarrier.arrive,
mbarrier.arrive_drop
Supported
Supported, cannot return result
mbarrier.expect_tx
Supported
Supported
mbarrier.complete_tx
Supported
Supported
Other mbarrier operations
Supported
Not supported
9.7.15.16.12. Parallel Synchronization and Communication Instructions: mbarrier.init#
mbarrier.init initializes the mbarrier object at the location specified by the address operand
addr with the unsigned 32-bit integer count.
The .layout qualifier specifies the layout that is used to initialize the mbarrier object.
If not specified explicitly, a .layout::v0 mbarrier is initialized.
Refer Layouts of the mbarrier object for more details.
The valid range of values for the operand count varies depending upon .layout as
specified below:
[1, …, 220 - 1] for mbarrier with .layout::v0
[1, …, 29 - 1] for mbarrier with .layout::v1
The constituents of the mbarrier object are initialized as follows:
The primary and conditional phases are initialized to zero.
The expected arrival and pending arrival counts are initialized to count.
The initial transaction count tx-count is initialized to zero.
For an mbarrier object with .layout::v1, the payload report
corresponding to the primary phase is initialized to zero.
If no state space is specified then Generic Addressing is
used. If the address specified by addr does not fall within the address window of
.shared::cta state space then the behavior is undefined.
The behavior of performing an mbarrier.init operation on a memory location containing a
valid mbarrier object is undefined; invalidate the mbarrier object using mbarrier.inval
first, before repurposing the memory location for any other purpose, including another mbarrier object.
cvta.shared.u64 addr, shMem2;
mbarrier.init.b64 [addr], %r1;
bar.cta.sync 0;
// … other mbarrier operations on addr
mbarrier.init.shared::cta.b64 [shMem], 12;
mbarrier.init.layout::v1.shared::cta.b64 [shMem3], 4;
bar.sync 0;
// … other mbarrier operations on shMem
// … other mbarrier operations on shMem3
9.7.15.16.13. Parallel Synchronization and Communication Instructions: mbarrier.inval#
mbarrier.inval
Invalidates the mbarrier object.
Syntax
mbarrier.inval{.shared{::cta}}.b64 [addr];
Description
mbarrier.inval invalidates the mbarrier object at the location specified by the address
operand addr.
The invalidation is supported for all layouts described in
Layouts of the mbarrier object.
An mbarrier object must be invalidated before using its memory location for any other purpose.
Performing any mbarrier operation except mbarrier.init on a memory location that does not
contain a valid mbarrier object, results in undefined behaviour.
If no state space is specified then Generic Addressing is
used. If the address specified by addr does not fall within the address window of
.shared::cta state space then the behavior is undefined.
A thread executing mbarrier.expect_tx performs an expect-tx
operation on the mbarrier object at the location specified by the address operand addr. The
32-bit unsigned integer operand txCount specifies the expectCount argument to the
expect-tx operation.
If no state space is specified then Generic Addressing is
used. If the address specified by addr does not fall within the address window of
.shared::cta or .shared::cluster state space then the behavior is undefined.
The optional .sem qualifier specifies a memory synchronizing effect as described in the
Memory Consistency Model.
The .relaxed qualifier does not provide any memory ordering semantics and visibility
guarantees.
The optional .scope qualifier indicates the set of threads that directly observe the memory
synchronizing effect of this operation, as described in the Memory Consistency Model.
Qualifiers .sem and .scope must be specified together.
The optional qualifier .multicast::cluster::32b allows performing the
expect-tx
operation on an mbarrier object from shared memory of multiple CTAs in the cluster. The operand
txCount specifies the expectCount argument for the
expect-tx
operation. Operand ctaMask specifies the intended target CTAs in the cluster such that each bit
position in the 32-bit ctaMask operand corresponds to the %cluster_ctarank of a target CTA. For
example, a ctaMask with value 0x1 performs the operation on the CTA with rank 0, whereas a
ctaMask with value 0x3 performs the operation on CTAs with ranks 0 and 1. The
expect-tx
operation is multicast to the same CTA-relative offset as addr in the shared memory of the
target CTA.
A thread executing mbarrier.complete_tx performs a complete-tx
operation on the mbarrier object at the location specified by the address operand addr. The
32-bit unsigned integer operand txCount specifies the completeCount argument to the
complete-tx operation.
mbarrier.complete_tx does not involve any asynchronous memory operations and only simulates the
completion of an asynchronous memory operation and its side effect of signaling to the mbarrier
object.
If no state space is specified then Generic Addressing is
used. If the address specified by addr does not fall within the address window of
.shared::cta or .shared::cluster state space then the behavior is undefined.
The optional .sem qualifier specifies a memory synchronizing effect as described in the
Memory Consistency Model.
The .relaxed qualifier does not provide any memory ordering semantics and visibility
guarantees.
The optional .scope qualifier indicates the set of threads that directly observe the memory
synchronizing effect of this operation, as described in the Memory Consistency Model.
Qualifiers .sem and .scope must be specified together.
The optional qualifier .multicast::cluster::32b allows performing the
complete-tx
operation on the mbarrier object from shared memory of multiple CTAs in the cluster. The operand
txCount specifies the completeCount argument for the
complete-tx
operation. Operand ctaMask specifies the intended target CTAs in the cluster; each bit position in
the 32-bit ctaMask operand corresponds to the %cluster_ctarank of the target CTA. For example, ctaMask
with value 0x1 performs the operation on CTA with rank 0, whereas ctaMask with value
0x3 performs the operation on CTAs with rank 0 and 1. The
complete-tx
operation is multicast to the same CTA-relative offset as addr in the shared memory of each target CTA.
A thread executing mbarrier.arrive performs an arrive-on operation
on the mbarrier object at the location specified by the address operand addr. The 32-bit
unsigned integer operand count specifies the count argument to the arrive-on
operation.
If no state space is specified then Generic Addressing is
used. If the address specified by addr does not fall within the address window of
.shared::cta state space then the behavior is undefined.
The optional qualifier .expect_tx specifies that an expect-tx
operation is performed prior to the arrive-on
operation. The 32-bit unsigned integer operand txCount specifies the expectCount argument to
the expect-tx operation. When both qualifiers .arrive and .expect_tx are specified, then
the count argument of the arrive-on operation is assumed to be 1.
A mbarrier.arrive operation with .noComplete qualifier must not cause the mbarrier to
complete its current phase, otherwise the behavior is undefined.
Note: for sm_8x, when the argument count is specified, the modifier .noComplete is
required.
mbarrier.arrive operation on an mbarrier object located in .shared::cta returns an opaque
64-bit register capturing the phase of the mbarrier object prior to the arrive-on operation in the
destination operand state. Contents of the state operand are implementation
specific. Optionally, sink symbol '_' can be used for the state argument.
mbarrier.arrive operation on an mbarrier object located in .shared::cluster but not in
.shared::cta cannot return a value. Sink symbol ‘_’ is mandatory for the destination operand for
such cases.
The optional .sem qualifier specifies a memory synchronizing effect as described in the
Memory Consistency Model. If the .sem qualifier is absent,
.release is assumed by default.
The .relaxed qualifier does not provide any memory ordering semantics and visibility
guarantees.
The optional .scope qualifier indicates the set of threads that directly observe the memory
synchronizing effect of this operation, as described in the Memory Consistency Model.
If the .scope qualifier is not specified then it
defaults to .cta. In contrast, the .shared::<scope> indicates the state space where the
mbarrier resides.
Qualifiers .sem and .scope must be specified together.
The optional qualifier .multicast::cluster::32b allows performing arrive-on and optionally
expect-tx
operation on an mbarrier object from shared memory of multiple CTAs in the cluster. Operand
ctaMask specifies the intended target CTAs in the cluster; each bit position in the 32-bit
ctaMask operand corresponds to the %cluster_ctarank of the target CTA. For example, ctaMask with
the value 0x1 applies the operation on CTA with rank 0, while a value of 0x3 applies it to
CTAs with ranks 0 and 1. The arrive-on and optionally
expect-tx
operation are multicast to the same CTA-relative offset as addr in the shared memory of each
target CTA.
A thread executing mbarrier.arrive_drop on the mbarrier object at the location specified by
the address operand addr performs the following steps:
Decrements the expected arrival count of the mbarrier object by the value specified by the
32-bit integer operand count. If count operand is not specified, it defaults to 1.
The decrement done in the expected arrivals count of the mbarrier object will be for all the
subsequent phases of the mbarrier object.
If the decrement causes the expected arrivals count to be zero, the behavior is undefined.
If no state space is specified then Generic Addressing is
used. If the address specified by addr does not fall within the address window of
.shared::cta or .shared::cluster state space then the behavior is undefined.
The optional qualifier .expect_tx specifies that an expect-tx
operation is performed prior to the arrive_drop operation, i.e. the decrement of arrival count and
arrive-on
operation. The 32-bit unsigned integer operand txCount specifies the expectCount argument to
the expect-tx operation. When both qualifiers .arrive_drop and .expect_tx are specified, then
the count argument of the arrive-on operation is assumed to be 1.
mbarrier.arrive_drop operation with .release qualifier forms the release pattern as
described in the Memory Consistency Model and synchronizes with the acquire patterns.
The optional .sem qualifier specifies a memory synchronizing effect as described in the
Memory Consistency Model. If the .sem qualifier is absent,
.release is assumed by default. The .relaxed qualifier does not provide any memory
ordering semantics and visibility guarantees.
The optional .scope qualifier indicates the set of threads that an mbarrier.arrive_drop
instruction can directly synchronize. If the .scope qualifier is not specified then it defaults
to .cta. In contrast, the .shared::<scope> indicates the state space where the mbarrier
resides.
A mbarrier.arrive_drop with .noComplete qualifier must not complete the mbarrier,
otherwise the behavior is undefined.
Note: for sm_8x, when the argument count is specified, the modifier .noComplete is
required.
A thread that wants to either exit or opt out of participating in the arrive-on operation can use
mbarrier.arrive_drop to drop itself from the mbarrier.
mbarrier.arrive_drop operation on an mbarrier object located in .shared::cta returns an
opaque 64-bit register capturing the phase of the mbarrier object prior to the arrive-on
operation
in the destination operand state. Contents of the returned state are implementation
specific. Optionally, sink symbol '_' can be used for the state argument.
mbarrier.arrive_drop operation on an mbarrier object located in .shared::cluster but not
in .shared::cta cannot return a value. Sink symbol ‘_’ is mandatory for the destination operand
for such cases.
The optional qualifier .multicast::cluster::32b allows performing
mbarrier.arrive_drop and optionally
expect-tx
operation on an mbarrier object from shared memory of multiple CTAs in the
cluster. The operand ctaMask specifies the intended target CTAs in the cluster
such that each bit in the 32-bit ctaMask corresponds to the %cluster_ctarank of the
target CTA. For example, a ctaMask with value 0x1 performs the operation
on CTA with rank 0, whereas ctaMask with value 0x3 performs the operation
on CTAs with ranks 0 and 1. The mbarrier.arrive_drop and optionally
expect-tx
operation is multicast to the same CTA-relative offset as addr
in the shared memory of the target CTA.
Qualifiers .sem and .scope must be specified together.
Causes an arrive-on operation to be
triggered by the system on the mbarrier object upon the completion of all prior cp.async
operations initiated by the
executing thread. The mbarrier object is at the location specified by the operand addr. The
arrive-on operation is
asynchronous to execution of cp.async.mbarrier.arrive.
When .noinc modifier is not specified, the pending count of the mbarrier object is incremented
by 1 prior to the asynchronous arrive-on operation. This
results in a zero-net change for the pending count from the asynchronous arrive-on operation
during the current phase. The pending count of the mbarrier object after the increment should not
exceed the limit as mentioned in
Contents of the mbarrier object. Otherwise,
the behavior is undefined.
When the .noinc modifier is specified, the increment to the pending count of the mbarrier
object is not performed. Hence the decrement of the pending count done by the asynchronous
arrive-on operation must be
accounted for in the initialization of the mbarrier object.
If no state space is specified then Generic Addressing is
used. If the address specified by addr does not fall within the address window of
.shared::cta state space then the behavior is undefined.
// Example 1: no .noinc
mbarrier.init.shared.b64 [shMem], threadCount;
....
cp.async.ca.shared.global [shard1], [gbl1], 4;
cp.async.cg.shared.global [shard2], [gbl2], 16;
....
// Absence of .noinc accounts for arrive-on from completion of prior cp.async operations.
// So mbarrier.init must only account for arrive-on from mbarrier.arrive.
cp.async.mbarrier.arrive.shared.b64 [shMem];
....
mbarrier.arrive.shared.b64 state, [shMem];
waitLoop:
mbarrier.test_wait.shared.b64 p, [shMem], state;
@!p bra waitLoop;
// Example 2: with .noinc
// Tracks arrive-on from mbarrier.arrive and cp.async.mbarrier.arrive.
// All threads participating in the mbarrier perform cp.async
mov.b32 copyOperationCnt, threadCount;
// 3 arrive-on operations will be triggered per-thread
mul.lo.u32 copyArrivalCnt, copyOperationCnt, 3;
add.u32 totalCount, threadCount, copyArrivalCnt;
mbarrier.init.shared.b64 [shMem], totalCount;
…
cp.async.ca.shared.global [shard1], [gbl1], 4;
cp.async.cg.shared.global [shard2], [gbl2], 16;
…
// Presence of .noinc requires mbarrier initialization to have accounted for arrive-on from cp.async
cp.async.mbarrier.arrive.noinc.shared.b64 [shMem]; // 1st instance
…
cp.async.ca.shared.global [shard3], [gbl3], 4;
cp.async.ca.shared.global [shard4], [gbl4], 16;
cp.async.mbarrier.arrive.noinc.shared::cta.b64 [shMem]; // 2nd instance
…
cp.async.ca.shared.global [shard5], [gbl5], 4;
cp.async.cg.shared.global [shard6], [gbl6], 16;
cp.async.mbarrier.arrive.noinc.shared.b64 [shMem]; // 3rd and last instance
…
mbarrier.arrive.shared.b64 state, [shMem];
waitLoop:
mbarrier.test_wait.shared.b64 p, [shMem], state;
@!p bra waitLoop;
9.7.15.16.19. Parallel Synchronization and Communication Instructions: mbarrier.test_wait / mbarrier.try_wait#
mbarrier.test_wait, mbarrier.try_wait
Checks whether the mbarrier object has completed the phase.
Syntax
// without parity
mbarrier.test_wait{.phase_type::primary}{.sem.scope}{.ss}.b64 waitComplete, [addr], state;
The test_wait and try_wait operations test for the completion of the current or the immediately
preceding phase of an mbarrier object at the location specified by the operand addr.
mbarrier.test_wait is a non-blocking instruction which tests for the completion of the phase.
mbarrier.try_wait is a potentially blocking instruction which tests for the completion of the
phase. If the phase is not complete, the executing thread may be suspended. Suspended thread resumes
execution when the specified phase completes OR before the phase completes following a
system-dependent time limit. The optional 32-bit unsigned integer operand timeHint
specifies the time limit, in nanoseconds, that may be used for the time limit instead of the
system-dependent limit.
mbarrier.test_wait and mbarrier.try_wait test for completion of the phase :
Specified by the 64-bit unsigned integer operand state, which was returned by an
mbarrier.arrive instruction on the same mbarrier object during the current or the
immediately preceding phase. Or
Indicated by the 32-bit unsigned integer operand phaseParity, whose integer parity
denotes either the current phase or the immediately preceding phase of the mbarrier object.
The .parity variant of the instructions test for the completion of the phase indicated by the
integer parity of the operand phaseParity, which denotes either the current phase or the immediately
preceding phase of the mbarrier object. An even phase has integer parity 0 and an odd phase has
integer parity of 1.
Note: the use of the .parity variants of the instructions requires tracking the phase of an
mbarrier object throughout its lifetime.
The test_wait and try_wait operations are valid only for :
the current incomplete phase, for which waitComplete returns False.
the immediately preceding phase, for which waitComplete returns True.
The qualifier .phase_type::* specifies the exact phase to test for completion of an operation.
The semantics around possible combinations are summarized below:
.phase_type::* is unspecified: checks completion of the primary phase.
.phase_type::primary checks completion of the primary phase and sets the reportPredicate
and reportValue. Note that the reportPredicate and reportValue operands are undefined
when waitComplete is False.
For .layout::v0, reportPredicate and reportValue are always zero.
.phase_type::conditional requires .parity qualifier and checks for completion of the
conditional phase, which may complete independently from the primary phase.
For .layout::v0, the primary and conditional phase complete in unison.
Operand reportValue must be of type .b8.
If no state space is specified then Generic Addressing is
used. If the address specified by addr does not fall within the address window of
.shared::cta state space then the behavior is undefined.
When mbarrier.test_wait and mbarrier.try_wait operations with .acquire qualifier
returns True, they form the acquire pattern as described in the
Memory Consistency Model.
The optional .sem qualifier specifies a memory synchronizing effect as described in the
Memory Consistency Model. If the .sem qualifier is absent,
.acquire is assumed by default. The .relaxed qualifier does not provide any memory
ordering semantics and visibility guarantees.
The optional .scope qualifier indicates the set of threads that the mbarrier.test_wait and
mbarrier.try_wait instructions can directly synchronize. If the .scope qualifier is not
specified then it defaults to .cta. In contrast, the .shared::<scope> indicates the state
space where the mbarrier resides.
Qualifiers .sem and .scope must be specified together.
The following ordering of memory operations hold for the executing thread when
mbarrier.test_wait or mbarrier.try_wait having acquire semantics returns True :
All memory accesses (except async operations) requested prior, in program
order, to mbarrier.arrive having release semantics during the completed phase by
the participating threads of the CTA are performed and are visible to the executing thread.
All cp.async operations
requested prior, in program order, to cp.async.mbarrier.arrive during the completed phase by
the participating threads of the CTA are performed and made visible to the executing thread.
All cp.async.bulk asynchronous operations using the same mbarrier object requested prior,
in program order, to mbarrier.arrive having release semantics during the completed
phase by the participating threads of the CTA are performed and made visible to the executing thread.
All memory accesses requested after the mbarrier.test_wait or mbarrier.try_wait, in
program order, are not performed and not visible to memory accesses performed prior to
mbarrier.arrive having release semantics, in program order, by other threads
participating in the mbarrier.
There is no ordering and visibility guarantee for memory accesses requested by the thread after
mbarrier.arrive having release semantics and prior to mbarrier.test_wait,
in program order.
Examples
// Example 1a, thread synchronization with test_wait:
.reg .b64 %r1;
.shared .b64 shMem;
mbarrier.init.shared.b64 [shMem], N; // N threads participating in the mbarrier.
…
mbarrier.arrive.shared.b64 %r1, [shMem]; // N threads executing mbarrier.arrive
// computation not requiring mbarrier synchronization…
// Example 1b, thread synchronization with try_wait :
.reg .b64 %r1;
.shared .b64 shMem;
mbarrier.init.layout::v0.shared.b64 [shMem], N; // N threads participating in the mbarrier.
…
mbarrier.arrive.shared.b64 %r1, [shMem]; // N threads executing mbarrier.arrive
// computation not requiring mbarrier synchronization…
waitLoop:
mbarrier.try_wait.phase_type::primary.relaxed.cluster.shared.b64 complete, [shMem], %r1;
@!complete bra waitLoop;
// Example 2, thread synchronization using phase parity :
.reg .b32 i, parArg;
.reg .b64 %r1;
.shared .b64 shMem;
mov.b32 i, 0;
mbarrier.init.shared.b64 [shMem], N; // N threads participating in the mbarrier.
…
loopStart : // One phase per loop iteration
…
mbarrier.arrive.shared.b64 %r1, [shMem]; // N threads
…
and.b32 parArg, i, 1;
waitLoop:
mbarrier.test_wait.parity.shared.b64 complete, [shMem], parArg;
@!complete nanosleep.u32 20;
@!complete bra waitLoop;
…
add.u32 i, i, 1;
setp.lt.u32 p, i, IterMax;
@p bra loopStart;
// Example 3, Asynchronous copy completion waiting :
9.7.15.16.20. Parallel Synchronization and Communication Instructions: mbarrier.pending_count#
mbarrier.pending_count
Query the pending arrival count from the opaque mbarrier state.
Syntax
mbarrier.pending_count{.layout}.b64 count, state;
.layout = { .layout::v0 }
Description
The pending count can be queried from the opaque mbarrier state using mbarrier.pending_count.
The state operand is a 64-bit register that must be the result of a prior
mbarrier.arrive.noComplete or mbarrier.arrive_drop.noComplete instruction. Otherwise, the
behavior is undefined.
The destination register count is a 32-bit unsigned integer representing the pending count of
the mbarrier object prior to the arrive-on operation from
which the state register was obtained.
The optional qualifier .layout::v0 denotes the layout of the corresponding mbarrier object as
described in the section Layouts of the mbarrier object.
The layout of the opaque mbarrier object can be queried using mbarrier.check_layout.
The address operand addr specifies the memory location of the mbarrier object whose
layout is being inspected. The instruction sets the predicate operand p to True if the
layout of the mbarrier object exactly matches the .layout qualifier. Refer
Layouts of the mbarrier object for
more details.
If no state space is specified then Generic Addressing is used. If the address specified
by addr does not fall within the address window of .shared::cta state space then the
behavior is undefined.
Examples
.reg .pred p;
.shared .b64 shMem;
mbarrier.check_layout.layout::v1.shared::cta.b64 p, [shMem];
@!p bra exit
// … mbarrier operations on shMem
exit: ret;
9.7.15.17. Parallel Synchronization and Communication Instructions: tensormap.cp_fenceproxy#
The tensormap.cp_fenceproxy instructions perform the following operations in order :
Copies data of size specified by the size argument, in bytes, from the location specified
by the address operand src in shared memory to the location specified by the address operand
dst in the global memory, in the generic proxy.
Establishes a uni-directional proxy release pattern on the ordering from the copy operation
to the subsequent access performed in the tensormap proxy on the address dst.
The valid value of immediate operand size is 128.
The operands src and dst specify non-generic addresses in shared::cta and global
state space respectively.
The .scope qualifier specifies the set of threads that can directly observe the proxy
synchronizing effect of this operation, as described in Memory Consistency Model.
The mandatory .sync qualifier indicates that tensormap.cp_fenceproxy causes the executing
thread to wait until all threads in the warp execute the same tensormap.cp_fenceproxy
instruction before resuming execution.
The mandatory .aligned qualifier indicates that all threads in the warp must execute the same
tensormap.cp_fenceproxy instruction. In conditionally executed code, an aligned tensormap.cp_fenceproxy
instruction should only be used if it is known that all threads in the warp evaluate the condition
identically, otherwise behavior is undefined.
Examples
// Example: manipulate a tensor-map object and then consume it in cp.async.bulk.tensor
The clusterlaunchcontrol.try_cancel instruction requests atomically cancelling the launch of
a cluster that has not started running yet. It asynchronously writes an opaque response to shared
memory indicating whether the operation succeeded or failed. The completion of the asynchronous
operation is tracked using the mbarrier completion mechanism at .cluster scope.
This instruction accesses its mbarrier operand using generic-proxy.
On success, the opaque response contains the ctaid of the first CTA of the canceled cluster; no
other successful response from other clusterlaunchcontrol.try_cancel operations from the same
grid will contain that id.
The mandatory .async qualifier indicates that the instruction will initiate the cancellation
operation asynchronously and control will return to the executing thread before the requested
operation is complete.
The .space qualifier is specified, both operands addr and mbar must be in the
.shared::cta state space. Otherwise, generic addressing will be assumed for both. The result
is undefined if any of address operands do not fall within the address window of .shared::cta.
The qualifier .completion_mechanism specifies that upon completion of the asynchronous operation,
complete-tx
operation, with completeCount argument equal to amount of data stored in bytes, will be performed
on the mbarrier object specified by the operand mbar.
The executing thread can then use mbarrier instructions to wait for completion
of the asynchronous operation. No other synchronization mechanisms described in Memory Consistency Model can be used to guarantee the completion of the asynchronous copy operations.
The .multicast::cluster::all qualifier indicates that the response is asynchronously written using
weak async-proxy writes to the corresponding local shared memory addr of each CTA in the requesting
cluster. The completion of the writes to addr of a particular CTA is signaled via a complete-tx operation
to the mbarrier object on the shared memory of that CTA.
The behavior of instruction with .multicast::cluster::all qualifier is undefined if any CTA in the
cluster is exited.
Operand addr specifies the naturally aligned address of the 16-byte wide shared memory location where
the request’s response is written.
The response of clusterlaunchcontrol.try_cancel instruction will be 16-byte opaque value and will be
it available at location specified by operand addr. After loading this response into 16-byte register,
instruction clusterlaunchcontrol.query_cancel can be used to check if request was successful and to
retrieve ctaid of the first CTA of the canceled cluster.
If the executing CTA has already observed the completion of a clusterlaunchcontrol.try_cancel instruction
as failed, then the behavior of issuing a subsequent clusterlaunchcontrol.try_cancel instruction is undefined.
Examples
// Assumption: 1D cluster (cluster_ctaid.y/.z == 1) with 1 thread per CTA.
// Current Cluster to be processed: initially the launched cluster:
mov.b32 xctaid, %ctaid.x;
// Establish full synchronization across all CTAs of the cluster for the first iteration.
// Weaker synchronization may suffice depending on initialization sequence.
barrier.cluster.arrive;
barrier.cluster.wait;
// Iteration loop over all cluster CTAs
processCluster:
mov.u32 %r0, %tid.x;
setp.u32.eq p0, %r0, 0x0;
// Elect a leader thread (thread idx 0) for each CTA to arrive and expect_tx at
// each CTA local shared memory barrier:
mov.u32 %r0, %tid.x;
setp.u32.eq p0, %r0, 0x0;
// All other threads skip to processing the work of the current cluster:
@!p0 bra processCurrentCluster;
// All CTAs in the cluster arrive at their local SMEM barrier and set 16B handle tx count:
mbarrier.arrive.expect_tx.cluster.relaxed.shared::cta.b64 state, [mbar], 16;
// First CTA in Cluster attempts to cancel a not-yet-started cluster:
mov.u32 %r0, %cluster_ctaid.x;
setp.u32.eq p0, %r0, 0x0;
@p0 clusterlaunchcontrol.try_cancel.async.mbarrier::complete_tx::bytes.multicast::cluster::all.b128 [addr], [mbar];
processCurrentCluster:
// …process current cluster (“xctaid”) while cancellation request for next cluster runs asynchronously…
// After processing current cluster, wait on cancellation request response for next cluster via specified mbarrier:
waitLoop:
// .acquire prevents weak handle read (“ld.shared handle, [addr]”) from overtaking this mbarrier.try_wait:
mbarrier.try_wait.cluster.acquire.shared::cta.b64 complete, [mbar], state;
@!complete bra waitLoop;
// Cancellation request has completed.
// Generic-proxy weak read of cancellation request into 16-byte wide register:
ld.shared.b128 handle, [addr];
// Check whether cancellation succeeded:
clusterlaunchcontrol.query_cancel.is_canceled.pred.b128 p, handle;
// If cancellation request failed, we couldn’t cancel any other cluster, so all current cluster CTAs exit.
@!p ret;
// Otherwise, cancellation request succeeded.
// Extract “ctaid” of first cancelled-cluster CTA which we’ll process in next “processCluster” loop iteration:
@p clusterlaunchcontrol.query_cancel.get_first_ctaid.v4.b32.b128 {xctaid, _, _, _}, handle;
// Release current iteration generic-proxy weak read of handle (“ld.shared handle, [addr]”)
// before next iteration async-proxy write to handle (“clusterlaunchcontrol.try_cancel [addr]”)
fence.proxy.async::generic.release.sync_restrict::shared::cta.cluster;
// Arrive and wait at the next iteration cluster barrier with relaxed semantics.
barrier.cluster.arrive.relaxed;
barrier.cluster.wait;
// Acquire prior iteration generic-proxy weak read of handle (“ld.shared handle, [addr]”)
// before current iteration async-proxy write to handle (“clusterlaunchcontrol.try_cancel [addr]”)
fence.proxy.async::generic.acquire.sync_restrict::shared::cluster.cluster;
bra processCluster;
9.7.15.19. Parallel Synchronization and Communication Instructions: clusterlaunchcontrol.query_cancel#
clusterlaunchcontrol.query_cancel
Queries response of clusterlaunchcontrol.try_cancel operation.
Instruction clusterlaunchcontrol.query_cancel can be used to decode opaque response
written by instruction clusterlaunchcontrol.try_cancel.
After loading response from clusterlaunchcontrol.try_cancel instruction into 16-byte
register it can be further queried using clusterlaunchcontrol.query_cancel instruction
as follows:
clusterlaunchcontrol.query_cancel.is_canceled.pred.b128: If the cluster is canceled
successfully, predicate p is set to true; otherwise, it is set to false.
If the request succeeded, the instruction clusterlaunchcontrol.query_cancel.get_first_ctaid
extracts the CTA id of the first CTA in the canceled cluster. By default, the instruction
returns a .v4 vector whose first three elements are the x, y and z coordinate
of first CTA in canceled cluster. The contents of the 4th element are unspecified. The
explicit .get_first_ctaid::x, .get_first_ctaid::y, or .get_first_ctaid::z
qualifiers can be used to extract individual x, y or z coordinates into a 32-bit
register.
If the request fails the behavior of clusterlaunchcontrol.query_cancel.get_first_ctaid
is undefined.
The matrix multiply and accumulate operation has the following form:
D = A * B + C
where D and C are called accumulators and may refer to the same matrix.
PTX provides two ways to perform matrix multiply-and-accumulate computation:
Using wmma instructions:
This warp-level computation is performed collectively by all threads in the warp as follows:
Load matrices A, B and C from memory into registers using the wmma.load operation. When
the operation completes, the destination registers in each thread hold a fragment of the
loaded matrix.
Perform the matrix multiply and accumulate operation using the wmma.mma operation on the
loaded matrices. When the operation completes, the destination registers in each thread hold
a fragment of the result matrix returned by the wmma.mma operation.
Store result Matrix D back to memory using the wmma.store operation. Alternately, result
matrix D can also be used as argument C for a subsequent wmma.mma operation.
The wmma.load and wmma.store instructions implicitly handle the organization of matrix
elements when loading the input matrices from memory for the wmma.mma operation and when
storing the result back to memory.
Using mma instruction:
Similar to wmma, mma also requires computation to be performed collectively by all
threads in the warp however distribution of matrix elements across different threads in warp
needs to be done explicitly before invoking the mma operation. The mma instruction
supports both dense as well as sparse matrix A. The sparse variant can be used when A is a
structured sparse matrix as described in Sparse matrix storage.
The matrix multiply and accumulate operations support a limited set of shapes for the operand
matrices A, B and C. The shapes of all three matrix operands are collectively described by the tuple
MxNxK, where A is an MxK matrix, B is a KxN matrix, while C and D are MxN matrices.
The following matrix shapes are supported for the specified types:
Instruction
Scale
Sparsity
Multiplicand Data-type
Shape
PTX ISA version
wmma
NA
Dense
Floating-point - .f16
.m16n16k16, .m8n32k16,
and .m32n8k16
PTX ISA version 6.0
wmma
Dense
Alternate floating-point format - .bf16
.m16n16k16, .m8n32k16,
and .m32n8k16
PTX ISA version 7.0
wmma
Dense
Alternate floating-point format - .tf32
.m16n16k8
PTX ISA version 7.0
wmma
Dense
Integer - .u8/.s8
.m16n16k16, .m8n32k16,
and .m32n8k16
PTX ISA version 6.3
wmma
Dense
Sub-byte integer - .u4/.s4
.m8n8k32
PTX ISA version 6.3
wmma
Dense
Single-bit - .b1
.m8n8k128
PTX ISA version 6.3
mma
NA
Dense
Floating-point - .f64
.m8n8k4
PTX ISA version 7.0
.m16n8k4, .m16n8k8,
and .m16n8k16
PTX ISA version 7.8
mma
Dense
Floating-point - .f16
.m8n8k4
PTX ISA version 6.4
.m16n8k8
PTX ISA version 6.5
.m16n8k16
PTX ISA version 7.0
mma
Dense
Alternate floating-point format - .bf16
.m16n8k8 and .m16n8k16
PTX ISA version 7.0
mma
Dense
Alternate floating-point format - .tf32
.m16n8k4 and .m16n8k8
PTX ISA version 7.0
mma
Dense
Integer - .u8/.s8
.m8n8k16
PTX ISA version 6.5
.m16n8k16 and .m16n8k32
PTX ISA version 7.0
mma
Dense
Sub-byte integer - .u4/.s4
.m8n8k32
PTX ISA version 6.5
.m16n8k32 and .m16n8k64
PTX ISA version 7.0
mma
Dense
Single-bit - .b1
.m8n8k128, .m16n8k128,
and .m16n8k256
PTX ISA version 7.0
mma
Dense
Alternate floating-point format - .e4m3
/ .e5m2
.m16n8k32
PTX ISA version 8.4
mma
Dense
Alternate floating-point format - .e4m3
/ .e5m2
.m16n8k16
PTX ISA version 8.7
mma
Dense
Alternate floating-point format - .e3m2
/ .e2m3/.e2m1
.m16n8k32
PTX ISA version 8.7
mma
Yes
Dense
Alternate floating-point format - .e4m3
/ .e5m2/.e3m2/.e2m3/.e2m1
X
(Scale)
.ue8m0
.m16n8k32
PTX ISA version 8.7
mma
Dense
Alternate floating-point format - .e2m1
X
(Scale)
.ue8m0/.ue4m3
.m16n8k64
PTX ISA version 8.7
mma
NA
Sparse
Floating-point - .f16
.m16n8k16 and .m16n8k32
PTX ISA version 7.1
mma
Sparse
Alternate floating-point format - .bf16
.m16n8k16 and .m16n8k32
PTX ISA version 7.1
mma
Sparse
Alternate floating-point format - .tf32
.m16n8k8 and .m16n8k16
PTX ISA version 7.1
mma
Sparse
Integer - .u8/.s8
.m16n8k32 and .m16n8k64
PTX ISA version 7.1
mma
Sparse
Sub-byte integer - .u4/.s4
.m16n8k64 and
.m16n8k128
PTX ISA version 7.1
mma
Sparse
Alternate floating-point format - .e4m3
/ .e5m2
.m16n8k64
PTX ISA version 8.4
mma
Sparse
with
ordered
metadata
Floating-point - .f16
.m16n8k16 and .m16n8k32
PTX ISA version 8.5
mma
Sparse
with
ordered
metadata
Alternate floating-point format - .bf16
.m16n8k16 and .m16n8k32
PTX ISA version 8.5
mma
Sparse
with
ordered
metadata
Alternate floating-point format - .tf32
.m16n8k8 and .m16n8k16
PTX ISA version 8.5
mma
Sparse
with
ordered
metadata
Integer - .u8/.s8
.m16n8k32 and .m16n8k64
PTX ISA version 8.5
mma
Sparse
with
ordered
metadata
Sub-byte integer - .u4/.s4
.m16n8k64 and
.m16n8k128
PTX ISA version 8.5
mma
Sparse
with
ordered
metadata
Alternate floating-point format - .e4m3
/ .e5m2
.m16n8k64
PTX ISA version 8.5
mma
Sparse
with
ordered
metadata
Alternate floating-point format - .e3m2
/ .e2m3/.e2m1
.m16n8k64
PTX ISA version 8.7
mma
Yes
Sparse
with
ordered
metadata
Alternate floating-point format - .e4m3
/ .e5m2/.e3m2/.e2m3/.e2m1
X
(Scale)
.ue8m0
.m16n8k64
PTX ISA version 8.7
mma
Sparse
with
ordered
metadata
Alternate floating-point format - .e2m1
X
(Scale)
.ue8m0/.ue4m3
The matrix multiply and accumulate operation is supported separately on integer, floating-point,
sub-byte integer and single bit data-types. All operands must contain the same basic type kind,
i.e., integer or floating-point.
For floating-point matrix multiply and accumulate operation, different matrix operands may have
different precision, as described later.
Data-type
Multiplicands (A or B)
Accumulators (C or D)
Integer
.u8, .s8
.s32
Floating Point
.f16
.f16, .f32
Alternate floating Point
.bf16
.f32
Alternate floating Point
.tf32
.f32
Alternate floating Point
.e4m3 or .e5m2 or
.e3m2 or .e2m3 or
.e2m1
.f16, .f32
Alternate floating Point
with scale
.e4m3 or .e5m2 or
.e3m2 or .e2m3 or
.e2m1 X (Scale)
.ue8m0
The mma instruction with the following .kind qualifier:
.kind::mxf8f6f4
.kind::mxf4
.kind::mxf4nvf4
perform matrix multiplication with block scaling. This operation has the following form:
D=(A*scale_A)*(B*scale_B)+C.
For a scale_A matrix of shape M x SFA_N, each row of matrix A is divided into
SFA_N number of chunks and each chunk of a row is multiplied with the corresponding
element (henceforth referred as SF_A) from the same row of scale_A.
Similarly, for a scale_B matrix of shape SFB_M x N, each column of matrix B is
divided into the SFB_M number of chunks and each chunk of a column is multiplied with
the corresponding element (henceforth referred as SF_B) from the same column of scale_B.
Figure 45 shows an example of mma with block scaling of scale_vec::2X.
Figure 45 mma with block scaling of .scale_vec::2X
The shapes for scale_A and scale_B matrices depend upon the qualifier .scale_vec_size
as shown in Table 44.
Table 44 Shapes for scale matrices depending upon .scale_vec_size qualifier
.scale_vec_size
Shape of scale_A
Shape of scale_B
.scale_vec::1X
M x 1
1 x N
.scale_vec::2X
M x 2
2 x N
.scale_vec::4X
M x 4
4 x N
The valid combination of the exact element types and the .scale_vec_size are listed in
Table 45.
Table 45 Valid combinations of .scale_vec_size and .kind qualifier
.kind::*
Element Data Type
.atype and .btype
Scale Data Type
.stype
.scale_vec_size
.kind::mxf8f6f4
.e4m3, .e5m2.e3m2, .e2m3.e2m1
.ue8m0
.scale_vec::1X
.kind::mxf4
.e2m1
.ue8m0
.scale_vec::2X
.kind::mxf4nvf4
.e2m1
.ue8m0
.scale_vec::2X,
.scale_vec::4X
.e2m1
.ue4m3
.scale_vec::4X
The scale-a-data and scale-b-data argument provides metadata for scale_A and
scale_B matrices respectively. The tuple {byte-id-a,thread-id-a} and
{byte-id-b,thread-id-b} provides the selector information to choose elements
SF_A and SF_B from corresponding metadata arguments scale-a-data and
scale-b-data.
The tuple {byte-id-a,thread-id-a} allows to select the scale matrix element SF_A
from scale-a-data. Similarly, the tuple {byte-id-b,thread-id-b} allows to select
the scale matrix element SF_B from scale-b-data.
The components thread-id-a, thread-id-b decides which threads among the quad
contribute the SF_A and SF_B values. The following listing describes the impact
of thread selector component thread-id-a, thread-id-b:
One thread-pair within the quad determined by thread-id-a, contributes the SF_A
values. The value of 0 selects lower two threads whereas value of 1 selects upper two
threads from the quad. In other words, when thread-id-a set to 0, thread-pair
satisfying: %laneid % 4 == 0 or 1 provides the SF_A. In contrast when
thread-id-a set to 1, thread-pair satisfying: %laneid % 4 == 2 or 3 provides
the SF_A. Refer Figure 46 for more details.
Figure 46 Selection of set of values for SF_A based on thread-id-a
One thread within the quad, determined by thread-id-b, contributes the SF_B
value. In other words, each thread satisfying: %laneid % 4 == thread-id-b
provides the SF_B. Refer Figure 47 for more details.
Figure 47 Selection of set of values for SF_B based on thread-id-b
The arguments byte-id-a, byte-id-b selects which bytes from the scale-a-data,
scale-b-data contribute the SF_A and SF_B values. The following listing describes
implications of .scale_vec_size qualifier on byte selector component byte-id-a,
byte-id-b:
When .scale_vec_size is .scale_vec::1X
One byte each within scale-a-data and scale-b-data determined by byte-id-a,
byte-id-b respectively contributes the SF_A and SF_B values.
When .scale_vec_size is .scale_vec::2X
One byte-pair (two bytes) within scale-a-data and scale-b-data determined by
byte-id-a and byte-id-b contributes the SF_A and SF_B values. The value
of 0 selects lower two bytes whereas value of 2 selects upper two bytes from the
corresponding metadata value.
When .scale_vec_size is .scale_vec::4X
All four bytes within scale-a-data and scale-b-data contribute the values.
Hence, byte-id-a, byte-id-b must be zero.
Figure 48 Selection of set of values for SF_A or SF_B based on byte-id-a or byte-id-b
Table 46 enumerates the valid values for
various selector components. Any other value results in undefined behavior.
Table 46 Valid values for various selector components
.scale_vec_size
Selector Components
byte-id-a
thread-id-a
byte-id-b
thread-id-b
scale_vec::1X
[0, 1, 2, 3]
[0, 1]
[0, 1, 2, 3]
[0, 1, 2, 3]
scale_vec::2X
[0, 2]
[0, 2]
scale_vec::4X
0
0
9.7.16.4. Matrix multiply-accumulate operation using wmma instructions#
This section describes warp level wmma.load,wmma.mma and wmma.store instructions and the
organization of various matrices involved in these instruction.
Each thread in the warp holds a fragment of the matrix. The distribution of fragments loaded by the
threads in a warp is unspecified and is target architecture dependent, and hence the identity of the
fragment within the matrix is also unspecified and is target architecture dependent. The fragment
returned by a wmma operation can be used as an operand for another wmma operation if the
shape, layout and element type of the underlying matrix matches. Since fragment layout is
architecture dependent, using the fragment returned by a wmma operation in one function as an
operand for a wmma operation in a different function may not work as expected if the two
functions are linked together but were compiled for different link-compatible SM architectures. Note
passing wmma fragment to a function having .weak linkage is unsafe since at link time
references to such function may get resolved to a function in different compilation module.
Each fragment is a vector expression whose contents are determined as follows. The identity of
individual matrix elements in the fragment is unspecified.
Integer fragments
Multiplicands (A or B):
Data-type
Shape
Matrix
Fragment
.u8 or .s8
.m16n16k16
A
A vector expression of two .b32 registers, with each
register containing four elements from the matrix.
B
A vector expression of two .b32 registers, with each
register containing four elements from the matrix.
.m8n32k16
A
A vector expression containing a single .b32 register
containing four elements from the matrix.
B
A vector expression of four .b32 registers, with each
register containing four elements from the matrix.
.m32n8k16
A
A vector expression of four .b32 registers, with each
register containing four elements from the matrix.
B
A vector expression containing single .b32 register,
with each containing four elements from the matrix.
Accumulators (C or D):
Data-type
Shape
Fragment
.s32
.m16n16k16
A vector expression of eight .s32 registers.
.m8n32k16
.m32n8k16
Floating point fragments
Data-type
Matrix
Fragment
.f16
A or B
A vector expression of eight .f16x2 registers.
.f16
C or D
A vector expression of four .f16x2 registers.
.f32
A vector expression of eight .f32 registers.
Floating point fragments for .bf16 data format
Multiplicands (A or B):
Data-type
Shape
Matrix
Fragment
.bf16
.m16n16k16
A
A vector expression of four .b32 registers, with each
register containing two elements from the matrix.
B
.m8n32k16
A
A vector expression containing a two .b32 registers,
with containing two elements from the matrix.
B
A vector expression of eight .b32 registers, with
each register containing two elements from the matrix.
.m32n8k16
A
A vector expression of eight .b32 registers, with
each register containing two elements from the matrix.
B
A vector expression containing two .b32 registers,
with each containing two elements from the matrix.
Accumulators (C or D):
Data-type
Matrix
Fragment
.f32
C or D
A vector expression containing eight .f32 registers.
Floating point fragments for .tf32 data format
Multiplicands (A or B):
Data-type
Shape
Matrix
Fragment
.tf32
.m16n16k8
A
A vector expression of four .b32 registers.
B
A vector expression of four .b32 registers.
Accumulators (C or D):
Data-type
Shape
Matrix
Fragment
.f32
.m16n16k8
C or D
A vector expression containing eight .f32 registers.
Double precision floating point fragments
Multiplicands (A or B):
Data-type
Shape
Matrix
Fragment
.f64
.m8n8k4
A or B
A vector expression of single .f64 register.
Accumulators (C or D):
Data-type
Shape
Matrix
Fragment
.f64
.m8n8k4
C or D
A vector expression containing single .f64 register.
Sub-byte integer and single-bit fragments
Multiplicands (A or B):
Data-type
Shape
Fragment
.u4 or .s4
.m8n8k32
A vector expression containing a single .b32 register, containing eight elements from the matrix.
.b1
.m8n8k128
A vector expression containing a single .b32 register, containing 32 elements from the matrix.
Accumulators (C or D):
Data-type
Shape
Fragment
.s32
.m8n8k32
A vector expression of two .s32 registers.
.m8n8k128
A vector expression of two .s32 registers.
Manipulating fragment contents
The contents of a matrix fragment can be manipulated by reading and writing to individual
registers in the fragment, provided the following conditions are satisfied:
All matrix element in the fragment are operated on uniformly across threads, using the same
parameters.
The order of the matrix elements is not changed.
For example, if each register corresponding to a given matrix is multiplied by a uniform constant
value, then the resulting matrix is simply the scaled version of the original matrix.
Note that type conversion between .f16 and .f32 accumulator fragments is not supported in
either direction. The result is undefined even if the order of elements in the fragment remains
unchanged.
Each matrix can be stored in memory with a row-major or column-major layout. In a row-major
format, consecutive elements of each row are stored in contiguous memory locations, and the row is
called the leading dimension of the matrix. In a column-major format, consecutive elements of
each column are stored in contiguous memory locations and the column is called the leading
dimension of the matrix.
Consecutive instances of the leading dimension (rows or columns) need not be stored contiguously
in memory. The wmma.load and wmma.store operations accept an optional argument stride
that specifies the offset from the beginning of each row (or column) to the next, in terms of matrix
elements (and not bytes). For example, the matrix being accessed by a wmma operation may be a
submatrix from a larger matrix stored in memory. This allows the programmer to compose a
multiply-and-accumulate operation on matrices that are larger than the shapes supported by the
wmma operation.
Address Alignment
The starting address of each instance of the leading dimension (row or column) must be aligned
with the size of the corresponding fragment in bytes. Note that the starting address is
determined by the base pointer and the optional stride.
Fragment size in bytes = 32 (eight elements of type .f16x2)
Actual stride in bytes = 2 * s (since stride is specified in terms of .f16
elements, not bytes)
For each row of this matrix to be aligned at fragment size the following must be true:
p is a multiple of 32.
2*s is a multiple of 32.
Default value for stride
The default value of the stride is the size of the leading dimension of the matrix. For
example, for an MxK matrix, the stride is K for a row-major layout and M for a
column-major layout. In particular, the default strides for the supported matrix shapes are as
follows:
Collectively load a matrix across all threads in a warp from the location indicated by address
operand p in the specified state space into destination register r.
If no state space is given, perform the memory accesses using
Generic Addressing. wmma.load operation may be used only with .global and
.shared spaces and with generic addressing, where the address points to .global or
.shared space.
The mutually exclusive qualifiers .a, .b and .c indicate whether matrix A, B or C is
being loaded respectively for the wmma computation.
The destination operand r is a brace-enclosed vector expression that can hold the fragment
returned by the load operation, as described in Matrix Fragments for WMMA.
The .shape qualifier indicates the dimensions of all the matrix arguments involved in the
intended wmma computation.
The .layout qualifier indicates whether the matrix to be loaded is stored in row-major or
column-major format.
stride is an optional 32-bit integer operand that provides an offset in terms of matrix elements
between the start of consecutive instances of the leading dimension (rows or columns). The default
value of stride is described in
Matrix Storage for WMMA and must be specified if the actual value is larger than
the default. For example, if the matrix is a sub-matrix of a larger matrix, then the value of stride
is the leading dimension of the larger matrix. Specifying a value lower than the default value
results in undefined behavior.
The required alignment for address p and stride is described in the
Matrix Storage for WMMA.
The mandatory .sync qualifier indicates that wmma.load causes the executing thread to wait
until all threads in the warp execute the same wmma.load instruction before resuming execution.
The mandatory .aligned qualifier indicates that all threads in the warp must execute the same
wmma.load instruction. In conditionally executed code, a wmma.load instruction should only
be used if it is known that all threads in the warp evaluate the condition identically, otherwise
behavior is undefined.
The behavior of wmma.load is undefined if all threads do not use the same qualifiers and the
same values of p and stride, or if any thread in the warp has exited.
Collectively store a matrix across all threads in a warp at the location indicated by address
operand p in the specified state space from source register r.
If no state space is given, perform the memory accesses using
Generic Addressing. wmma.load operation may be used only with .global and
.shared spaces and with generic addressing, where the address points to .global or
.shared space.
The source operand r is a brace-enclosed vector expression that matches the shape of the
fragment expected by the store operation, as described in Matrix Fragments for WMMA.
The .shape qualifier indicates the dimensions of all the matrix arguments involved in the
intended wmma computation. It must match the .shape qualifier specified on the wmma.mma
instruction that produced the D matrix being stored.
The .layout qualifier indicates whether the matrix to be loaded is stored in row-major or
column-major format.
stride is an optional 32-bit integer operand that provides an offset in terms of matrix elements
between the start of consecutive instances of the leading dimension (rows or columns). The default
value of stride is described in
Matrix Storage for WMMA and must be specified if the actual value is larger than
the default. For example, if the matrix is a sub-matrix of a larger matrix, then the value of stride
is the leading dimension of the larger matrix. Specifying a value lower than the default value
results in undefined behavior.
The required alignment for address p and stride is described in the
Matrix Storage for WMMA.
The mandatory .sync qualifier indicates that wmma.store causes the executing thread to wait
until all threads in the warp execute the same wmma.store instruction before resuming execution.
The mandatory .aligned qualifier indicates that all threads in the warp must execute the same
wmma.store instruction. In conditionally executed code, a wmma.store instruction should only
be used if it is known that all threads in the warp evaluate the condition identically, otherwise
behavior is undefined.
The behavior of wmma.store is undefined if all threads do not use the same qualifiers and the
same values of p and stride, or if any thread in the warp has exited.
Perform a warp-level matrix multiply-and-accumulate computation D=A*B+C using matrices A,
B and C loaded in registers a, b and c respectively, and store the result matrix in
register d. The register arguments a, b, c and d hold unspecified fragments of
the corresponding matrices as described in Matrix Fragments for WMMA
The qualifiers .dtype, .atype, .btype and .ctype indicate the data-type of the
elements in the matrices D, A, B and C respectively.
For wmma.mma without explicit .atype and .btype: .atype and .btype are
implicitly set to .f16.
For integer wmma, .ctype and .dtype must be specified as .s32. Also, the values for
.atype and .btype must be the same, i.e., either both are .s8 or both are .u8.
For sub-byte single-bit wmma, .ctype and .dtype must be specified as .s32. Also, the
values for .atype and .btype must be the same; i.e., either both are .s4, both are
.u4, or both are .b1.
For single-bit wmma, multiplication is replaced by a sequence of logical operations;
specifically, wmma.xor.popc and wmma.and.popc computes the XOR, AND respectively of a
128-bit row of A with a 128-bit column of B, then counts the number of set bits in the result
(popc). This result is added to the corresponding element of C and written into D.
The qualifiers .alayout and .blayout must match the layout specified on the wmma.load
instructions that produce the contents of operands a and b respectively. Similarly, the
qualifiers .atype, .btype and .ctype must match the corresponding qualifiers on the
wmma.load instructions that produce the contents of operands a, b and c
respectively.
The .shape qualifier must match the .shape qualifier used on the wmma.load instructions
that produce the contents of all three input operands a, b and c respectively.
The destination operand d is a brace-enclosed vector expression that matches the .shape of
the fragment computed by the wmma.mma instruction.
Saturation at the output:
The optional qualifier .satfinite indicates that the final values in the destination register
are saturated as follows:
The output is clamped to the minimum or maximum 32-bit signed integer value. Otherwise, if the
accumulation would overflow, the value wraps.
Precision and rounding for .f16 floating point operations:
Element-wise multiplication of matrix A and B is performed with at least single precision. When
.ctype or .dtype is .f32, accumulation of the intermediate values is performed with
at least single precision. When both .ctype and .dtype are specified as .f16, the
accumulation is performed with at least half precision.
The accumulation order, rounding and handling of subnormal inputs is unspecified.
Precision and rounding for .bf16, .tf32 floating point operations:
Element-wise multiplication of matrix A and B is performed with specified precision. Accumulation
of the intermediate values is performed with at least single precision.
The accumulation order, rounding and handling of subnormal inputs is unspecified.
Rounding modifiers on double precision wmma.mma (default is .rn):
.rn
mantissa LSB rounds to nearest even
.rz
mantissa LSB rounds towards zero
.rm
mantissa LSB rounds towards negative infinity
.rp
mantissa LSB rounds towards positive infinity
The mandatory .sync qualifier indicates that wmma.mma causes the executing thread to wait
until all threads in the warp execute the same wmma.mma instruction before resuming execution.
The mandatory .aligned qualifier indicates that all threads in the warp must execute the same
wmma.mma instruction. In conditionally executed code, a wmma.mma instruction should only be
used if it is known that all threads in the warp evaluate the condition identically, otherwise
behavior is undefined.
The behavior of wmma.mma is undefined if all threads in the same warp do not use the same
qualifiers, or if any thread in the warp has exited.
9.7.16.5. Matrix multiply-accumulate operation using mma instruction#
This section describes warp-level mma, ldmatrix, stmatrix, and movmatrix
instructions and the organization of various matrices involved in these instructions.
9.7.16.5.1. Matrix Fragments for mma.m8n8k4 with .f16 floating point type#
A warp executing mma.m8n8k4 with .f16 floating point type will compute 4 MMA operations of shape
.m8n8k4.
Elements of 4 matrices need to be distributed across the threads in a warp. The following table
shows distribution of matrices for MMA operations.
MMA Computation
Threads participating in MMA computation
MMA computation 1
Threads with %laneid 0-3 (low group) and 16-19 (high group)
MMA computation 2
Threads with %laneid 4-7 (low group) and 20-23 (high group)
MMA computation 3
Threads with %laneid 8-11 (low group) and 24-27 (high group)
MMA computation 4
Threads with %laneid 12-15 (low group) and 28-31 (high group)
For each of the individual MMA computation shown above, each of the required thread holds a fragment
of the matrix for performing mma operation as follows:
Multiplicand A:
.atype
Fragment
Elements (low to high)
.f16
A vector expression containing two .f16x2 registers,
with each register containing two .f16 elements from
the matrix A.
a0, a1, a2, a3
The layout of the fragments held by different threads is shown below:
Fragment layout for Row Major matrix A is shown in Figure 49.
Figure 49 MMA .m8n8k4 fragment layout for row-major matrix A with .f16 type
The row and column of a matrix fragment can be computed as:
row=%laneid%4if%laneid<16(%laneid%4)+4otherwise
col=iforaiwherei={0,..,3}
Fragment layout for Column Major matrix A is shown in Figure 50.
The layout of the fragments held by different threads is shown below:
Figure 50 MMA .m8n8k4 fragment layout for column-major matrix A with .f16 type
The row and column of a matrix fragment can be computed as:
.s8 or .u8 or .e4m3 or .e5m2 or .e3m2 or .e2m3 or .e2m1:
.atype
Fragment
Elements (low to high)
.s8 / .u8
A vector expression containing four .b32 registers, with each
register containing four .s8 / .u8 elements from the
matrix A.
a0, a1, .., a14, a15
.e4m3 /
.e5m2 /
.e3m2 /
.e2m3 /
.e2m1
A vector expression containing four .b32 registers, with each
register containing four .e4m3 / .e5m2 / .e3m2 /
.e2m3 / .e2m1 elements from the matrix A.
a0, a1, …, a14, a15
The layout of the fragments held by different threads is shown in Figure 91.
Figure 91 MMA .m16n8k32 fragment layout for matrix A with .u8 / .s8 / .e4m3 / .e5m2 / .e3m2 / .e2m3 / .e2m1 type.
The row and column of a matrix fragment can be computed as:
.s8 or .u8 or .e4m3 or .e5m2 or .e3m2 or .e2m3 or .e2m1:
.btype
Fragment
Elements (low to high)
.s8 / .u8
A vector expression containing two .b32 registers, with each
register containing four .s8 / .u8 elements from the
matrix B.
b0, b1, b2, b3, b4, b5, b6, b7
.e4m3 /
.e5m2 /
.e3m2 /
.e2m3 /
.e2m1
A vector expression containing two .b32 registers, with each
register containing four .e4m3 / .e5m2 / .e3m2 /
.e2m3 / .e2m1 elements from the matrix B.
b0, b1, b2, b3, b4, b5, b6, b7
The layout of the fragments held by different threads is shown in Figure 93 and
Figure 94.
Figure 93 MMA .m16n8k32 fragment layout for rows 0–15 of matrix B with .u8 / .s8 / .e4m3 / .e5m2 / .e3m2 / .e2m3 / .e2m1 type.
Figure 94 MMA .m16n8k32 fragment layout for rows 16–31 of matrix B with .u8 / .s8 / .e4m3 / .e5m2 / .e3m2 / .e2m3 / .e2m1 type.
The row and column of a matrix fragment can be computed as:
mma.sync.aligned.m8n8k4.alayout.blayout.dtype.f16.f16.ctype d, a, b, c;
mma.sync.aligned.m16n8k8.row.col.dtype.f16.f16.ctype d, a, b, c;
mma.sync.aligned.m16n8k16.row.col.dtype.f16.f16.ctype d, a, b, c;
mma.sync.aligned.m16n8k4.row.col.f32.tf32.tf32.f32 d, a, b, c;
mma.sync.aligned.m16n8k8.row.col.f32.atype.btype.f32 d, a, b, c;
mma.sync.aligned.m16n8k16.row.col.f32.bf16.bf16.f32 d, a, b, c;
mma.sync.aligned.shape.row.col.dtype.f8type.f8type.ctype d, a, b, c;
mma.sync.aligned.m16n8k32.row.col.kind.dtype.f8f6f4type.f8f6f4type.ctype d, a, b, c;
Perform a MxNxK matrix multiply and accumulate operation, D=A*B+C, where the A matrix is
MxK, the B matrix is KxN, and the C and D matrices are MxN.
Qualifier .block_scale specifies that the matrices A and B are scaled with scale_A and
scale_B matrices respectively before performing the matrix multiply and accumulate operation
as specified in the section Block Scaling for mma.sync. The data type
corresponding to each of the element within scale_A and Scale_B matrices is specified
by .stype. Qualifier .scale_vec_size specifies the number of columns of scale_A matrix
and number of rows in the matrix scale_B.
The valid combinations of .kind, .stype and .scale_vec_size are described in
Table 45. For mma with .kind::mxf4 when the
qualifier .scale_vec_size is not specified, then it defaults to 2X. In contrast, when
.kind is specified as .kind::mxf8f6f4 then the qualifier .scale_vec_size defaults
to 1X. However, for .kind::mxf4nvf4, it is mandatory to provide valid .scale_vec_size.
A warp executing mma.sync.m8n8k4 instruction computes 4 matrix multiply and accumulate
operations. Rest of the mma.sync operations compute a single matrix multiply and accumulate
operation per warp.
For single-bit mma.sync, multiplication is replaced by a sequence of logical operations;
specifically, mma.xor.popc and mma.and.popc computes the XOR, AND respectively of a k-bit
row of A with a k-bit column of B, then counts the number of set bits in the result (popc). This
result is added to the corresponding element of C and written into D.
Operands a and b represent two multiplicand matrices A and B, while c and d
represent the accumulator and destination matrices, distributed across the threads in warp.
When .block_scale qualifier is specified, operand scale-a-data, scale-b-data represents
the scale matrix metadata corresponding to scale_A and scale_B matrices respectively. The
tuple {byte-id-a,thread-id-a} and {byte-id-b,thread-id-b} represent selectors for matrices
scale_A and scale_B respectively from their corresponding metadata arguments scale-a-data,
scale-b-data. The operands scale-a-data, scale-b-data are of type .b32. The operands
byte-id-a, thread-id-a, byte-id-b, thread-id-b are unsigned 16-bit integer values.
For more details on selector arguments refer Block Scaling for mma.sync section.
The qualifiers .dtype, .atype, .btype and .ctype indicate the data-type of the
elements in the matrices D, A, B and C respectively. The qualifier .stype indicate the data-type
of the elements in the matrices scale_A and scale_B. Specific shapes have type restrictions :
.m8n8k4 : When .ctype is .f32, .dtype must also be .f32.
.m16n8k8 :
.dtype must be the same as .ctype.
.atype must be the same as .btype.
.m16n8k16 and .m16n8k32 :
.dtype must be the same as .ctype.
The qualifiers .alayout and .blayout indicate the row-major or column-major layouts of
matrices A and B respectively.
When .kind is either of .kind::mxf8f6f4 or .kind::f8f6f4, the individual 4-bit and the
6-bit floating point type elements must be packed in an 8-bit container. The matrix element of type
.e2m1 resides in central 4 bits of the 8-bit container with padding in the upper 2 bits and
lower 2 bits of the container. When the matrix element is of type .e3m2 or .e2m3, the
matrix element resides in the lower 6 bits of the 8-bit container with padding in the upper 2 bits
of the container. In contrast, note that when using mma with .kind::mxf4 or
.kind::mxf4nvf4, no explicit padding is necessary even though matrix elements are of type .e2m1.
Precision and rounding :
.f16 floating point operations:
Element-wise multiplication of matrix A and B is performed with at least single
precision. When .ctype or .dtype is .f32, accumulation of the intermediate values
is performed with at least single precision. When both .ctype and .dtype are specified
as .f16, the accumulation is performed with at least half precision.
The accumulation order, rounding and handling of subnormal inputs are unspecified.
.e4m3, .e5m2, .e3m2, .e2m3, .e2m1 floating point operations :
Element-wise multiplication of matrix A and B is performed with specified precision. Accumulation
of the intermediate values is performed with at least single precision.
The accumulation order, rounding, and handling of subnormal inputs are unspecified.
.bf16 and .tf32 floating point operations :
Element-wise multiplication of matrix A and B is performed with specified
precision. Accumulation of the intermediate values is performed with at least single
precision.
The accumulation order, rounding, and handling of subnormal inputs are unspecified.
.f64 floating point operations :
Precision of the element-wise multiplication and addition operation is identical to that of .f64
precision fused multiply-add. Supported rounding modifiers are :
.rn : mantissa LSB rounds to nearest even. This is the default.
.rz : mantissa LSB rounds towards zero.
.rm : mantissa LSB rounds towards negative infinity.
.rp : mantissa LSB rounds towards positive infinity.
Integer operations :
The integer mma operation is performed with .s32 accumulators. The .satfinite
qualifier indicates that on overflow, the accumulated value is limited to the range
MIN_INT32.. MAX_INT32 (where the bounds are defined as the minimum negative signed 32-bit
integer and the maximum positive signed 32-bit integer respectively).
If .satfinite is not specified, the accumulated value is wrapped instead.
The mandatory .sync qualifier indicates that mma instruction causes the executing thread to
wait until all threads in the warp execute the same mma instruction before resuming execution.
The mandatory .aligned qualifier indicates that all threads in the warp must execute the same
mma instruction. In conditionally executed code, a mma instruction should only be used if it
is known that all threads in the warp evaluate the condition identically, otherwise behavior is
undefined.
The behavior of mma instruction is undefined if all threads in the same warp do not use the same
qualifiers, or if any thread in the warp has exited.
Examples of half precision floating point type
// f16 elements in C and D matrix
.reg .f16x2 %Ra<2> %Rb<2> %Rc<4> %Rd<4>
mma.sync.aligned.m8n8k4.row.col.f16.f16.f16.f16
{%Rd0, %Rd1, %Rd2, %Rd3},
{%Ra0, %Ra1},
{%Rb0, %Rb1},
{%Rc0, %Rc1, %Rc2, %Rc3};
// f16 elements in C and f32 elements in D
.reg .f16x2 %Ra<2> %Rb<2> %Rc<4>
.reg .f32 %Rd<8>
mma.sync.aligned.m8n8k4.row.col.f32.f16.f16.f16
{%Rd0, %Rd1, %Rd2, %Rd3, %Rd4, %Rd5, %Rd6, %Rd7},
{%Ra0, %Ra1},
{%Rb0, %Rb1},
{%Rc0, %Rc1, %Rc2, %Rc3};
// f32 elements in C and D
.reg .f16x2 %Ra<2>, %Rb<1>;
.reg .f32 %Rc<4>, %Rd<4>;
mma.sync.aligned.m16n8k8.row.col.f32.f16.f16.f32
{%Rd0, %Rd1, %Rd2, %Rd3},
{%Ra0, %Ra1},
{%Rb0},
{%Rc0, %Rc1, %Rc2, %Rc3};
// s8 elements in A and u8 elements in B
mma.sync.aligned.m8n8k16.row.col.satfinite.s32.s8.u8.s32
{%Rd0, %Rd1},
{%Ra},
{%Rb},
{%Rc0, %Rc1};
// u4 elements in A and B matrix
mma.sync.aligned.m8n8k32.row.col.satfinite.s32.u4.u4.s32
{%Rd0, %Rd1},
{%Ra},
{%Rb},
{%Rc0, %Rc1};
// s8 elements in A and u8 elements in B
.reg .b32 %Ra<2>, %Rb, %Rc<4>, %Rd<4>;
mma.sync.aligned.m16n8k16.row.col.satfinite.s32.s8.u8.s32
{%Rd0, %Rd1, %Rd2, %Rd3},
{%Ra0, %Ra1},
{%Rb},
{%Rc0, %Rc1, %Rc2, %Rc3};
// u4 elements in A and s4 elements in B
.reg .b32 %Ra<2>, %Rb, %Rc<4>, %Rd<4>;
mma.sync.aligned.m16n8k32.row.col.satfinite.s32.u4.s4.s32
{%Rd0, %Rd1, %Rd2, %Rd3},
{%Ra0, %Ra1},
{%Rb},
{%Rc0, %Rc1, %Rc2, %Rc3};
// s8 elements in A and s8 elements in B
.reg .b32 %Ra<4>, %Rb<2>, %Rc<4>, %Rd<4>;
mma.sync.aligned.m16n8k32.row.col.satfinite.s32.s8.s8.s32
{%Rd0, %Rd1, %Rd2, %Rd3},
{%Ra0, %Ra1, %Ra2, %Ra3},
{%Rb0, %Rb1},
{%Rc0, %Rc1, %Rc2, %Rc3};
// u8 elements in A and u8 elements in B
.reg .b32 %Ra<4>, %Rb<2>, %Rc<4>, %Rd<4>;
mma.sync.aligned.m16n8k64.row.col.satfinite.s32.u4.u4.s32
{%Rd0, %Rd1, %Rd2, %Rd3},
{%Ra0, %Ra1, %Ra2, %Ra3},
{%Rb0, %Rb1 },
{%Rc0, %Rc1, %Rc2, %Rc3};
Examples of single bit type
// b1 elements in A and B
.reg .b32 %Ra, %Rb, %Rc<2>, %Rd<2>;
mma.sync.aligned.m8n8k128.row.col.s32.b1.b1.s32.and.popc
{%Rd0, %Rd1},
{%Ra},
{%Rb},
{%Rc0, %Rc1};
// b1 elements in A and B
.reg .b32 %Ra, %Rb, %Rc<2>, %Rd<2>;
mma.sync.aligned.m8n8k128.row.col.s32.b1.b1.s32.xor.popc
{%Rd0, %Rd1},
{%Ra},
{%Rb},
{%Rc0, %Rc1};
Collectively load one or more matrices across all threads in a warp from the location indicated by
the address operand p, from .shared state space into destination register r. If no state
space is provided, generic addressing is used, such that the address in p points into
.shared space. If the generic address doesn’t fall in .shared state space, then the behavior
is undefined. The instruction optionally supports element size expansion during load.
The .shape qualifier indicates the dimensions of the matrices being loaded. Each matrix element
holds 16-bit or 8-bit or 6-bit or 4-bit data.
Following table shows the matrix load case for each .shape.
.shape
Matrix shape
Element size
.m8n8
8x8
16-bit
.m16n16
16x16
8-bit or 6-bit or 4-bit
.m8n16
8x16
6-bit or 4-bit
Following table shows the valid use of 6-bit or 4-bit data load.
.src_fmt
.shape
Source data
Padding
.dst_fmt
.b6x16_p32
.m8n16
16 6-bit elements
32 bits
.b8x16
(16 8-bit
elements)
.m16n16
.b4x16_p64
.m8n16
16 4-bit elements
64 bits
.m16n16
For .b6x16_p32 format source data is 16 unsigned 6-bit elements with 32 bits padding.
For .b4x16_p64 format source data is 16 unsigned 4-bit elements with 64 bits padding.
Following table shows the valid use of 4-bit load expanded to 8-bit.
.ctype
.shape
Source data
.dtype
.s4
.m8n16
Signed 4-bit
elements
.s8
For .s4 type, the source data is a sequence of signed 4-bit elements that are
expanded to signed 8-bit values during load.
The values .x1, .x2 and .x4 for .num indicate one, two or four matrices
respectively. When .shape is .m16n16, only .x1 and .x2 are valid values for .num.
The mandatory .sync qualifier indicates that ldmatrix causes the executing thread to wait
until all threads in the warp execute the same ldmatrix instruction before resuming execution.
The mandatory .aligned qualifier indicates that all threads in the warp must execute the same
ldmatrix instruction. In conditionally executed code, an ldmatrix instruction should only be
used if it is known that all threads in the warp evaluate the condition identically, otherwise the
behavior is undefined.
The behavior of ldmatrix is undefined if all threads do not use the same qualifiers, or if any
thread in the warp has exited.
The destination operand r is a brace-enclosed vector expression consisting of 1, 2, or 4 32-bit
registers as per the value of .num. Each component of the vector expression holds a fragment
from the corresponding matrix.
Consecutive instances of row need not be stored contiguously in memory. The eight addresses required
for each matrix are provided by eight threads, depending upon the value of .num as shown in the
following table. Each address corresponds to the start of a matrix row. Addresses addr0–addr7
correspond to the rows of the first matrix, addresses addr8–addr15 correspond to the rows of the
second matrix, and so on.
.num
Threads 0–7
Threads 8–15
Threads 16–23
Threads 24–31
.x1
addr0–addr7
–
–
–
.x2
addr0–addr7
addr8–addr15
–
–
.x4
addr0–addr7
addr8–addr15
addr16–addr23
addr24–addr31
Note
For .target sm_75 or below, all threads must contain valid addresses. Otherwise, the behavior
is undefined. For .num=.x1 and .num=.x2, addresses contained in lower threads can be
copied to higher threads to achieve the expected behavior.
When reading 8x8 matrices, a group of four consecutive threads loads 16 bytes. The matrix addresses
must be naturally aligned accordingly.
Each thread in a warp loads fragments of a row, with thread 0 receiving the first fragment in its
register r, and so on. A group of four threads loads an entire row of the matrix as shown in
Figure 107.
Figure 107 ldmatrix fragment layout for one 8x8 Matrix with 16-bit elements
When .num = .x2, the elements of the second matrix are loaded in the next destination
register in each thread as per the layout in above table. Similarly, when .num = .x4,
elements of the third and fourth matrices are loaded in the subsequent destination registers in each
thread.
For matrix shape 16x16, two destination registers r0 and r1 of type .b32 must be
specified and in each register four 8-bit elements are loaded. For 4-bit or 6-bit data, 8-bit
element will have 4 bits or 2 bits of padding respectively.
An entire row of the matrix can be loaded by a group of four consecutive and aligned threads.
Each thread in a warp loads 4 consecutive columns across 2 rows as shown in the
Figure 108.
Figure 108 ldmatrix fragment layout for one 16x16 matrix with 8-bit elements
For matrix shape 8x16, one destination register r0 of type .b32 must be specified where four
8-bit elements are loaded in the register. For 4-bit or 6-bit data, 8-bit element will have 4 bits
or 2 bits of padding respectively.
An entire row of the matrix can be loaded by a group of four consecutive and aligned threads.
Each thread in a warp loads 4 consecutive columns as shown in Figure 109.
Figure 109 ldmatrix fragment layout for one 8x16 matrix with 8-bit elements containing 4-bit/6-bit data
Optional qualifier .trans indicates that the matrix is loaded in column-major format. However,
for 16x16 matrices, .trans is mandatory.
// Load one 16x16 matrices of 64-bit elements and transpose them
.reg .b64 addr;
.reg .b32 d<2>;
ldmatrix.sync.aligned.m16n16.x1.trans.shared.b8 {d0, d1}, [addr];
// Load two 16x16 matrices of 64-bit elements and transpose them
.reg .b64 addr;
.reg .b32 d<4>;
ldmatrix.sync.aligned.m16n16.x2.trans.shared::cta.b8 {d0, d1, d2, d3}, [addr];
// Load two 16x16 matrices of 6-bit elements and transpose them
.reg .b64 addr;
.reg .b32 d<4>;
ldmatrix.sync.aligned.m16n16.x2.trans.shared::cta.b8x16.b6x16_p32 {d0, d1, d2, d3}, [addr];
// Load one 8x16 matrix of 4-bit signed elements expanded to 8-bit signed
.reg .b64 addr;
.reg .b32 d;
ldmatrix.sync.aligned.m8n16.x1.shared::cta.s8.s4 {d}, [addr];
9.7.16.5.16. Warp-level matrix store instruction: stmatrix#
stmatrix
Collectively store one or more matrices to shared memory.
Collectively store one or more matrices across all threads in a warp to the location indicated by
the address operand p, in .shared state space. If no state space is provided, generic
addressing is used, such that the address in p points into .shared space. If the generic
address doesn’t fall in .shared state space, then the behavior is undefined.
The .shape qualifier indicates the dimensions of the matrices being loaded. Each matrix element
holds 16-bit or 8-bit data as indicated by the .type qualifier.
.m16n8 shape is valid only for .b8 type.
The values .x1, .x2 and .x4 for .num indicate one, two or four matrices
respectively.
The mandatory .sync qualifier indicates that stmatrix causes the executing thread to wait
until all threads in the warp execute the same stmatrix instruction before resuming execution.
The mandatory .aligned qualifier indicates that all threads in the warp must execute the same
stmatrix instruction. In conditionally executed code, an stmatrix instruction should only be
used if it is known that all threads in the warp evaluate the condition identically, otherwise the
behavior is undefined.
The behavior of stmatrix is undefined if all threads do not use the same qualifiers, or if any
thread in the warp has exited.
The source operand r is a brace-enclosed vector expression consisting of 1, 2, or 4 32-bit
registers as per the value of .num. Each component of the vector expression holds a fragment
from the corresponding matrix.
Consecutive instances of row need not be stored contiguously in memory. The eight addresses required
for each matrix are provided by eight threads, depending upon the value of .num as shown in the
following table. Each address corresponds to the start of a matrix row. Addresses addr0–addr7
correspond to the rows of the first matrix, addresses addr8–addr15 correspond to the rows of the
second matrix, and so on.
.num
Threads 0–7
Threads 8–15
Threads 16–23
Threads 24–31
.x1
addr0–addr7
–
–
–
.x2
addr0–addr7
addr8–addr15
–
–
.x4
addr0–addr7
addr8–addr15
addr16–addr23
addr24–addr31
When storing 8x8 matrices, a group of four consecutive threads stores 16 bytes. The matrix addresses
must be naturally aligned accordingly.
Each thread in a warp stores fragments of a row, with thread 0 storing the first fragment from its
register r, and so on. A group of four threads stores an entire row of the matrix as shown in
Figure 110.
Figure 110 stmatrix fragment layout for one 8x8 matrix with 16-bit elements
When .num = .x2, the elements of the second matrix are stored from the next source register
in each thread as per the layout in above table. Similarly, when .num = .x4, elements of the
third and fourth matrices are stored from the subsequent source registers in each thread.
For 16x8 matrix shape, each of the 32 threads in the warp provides four elements of data per matrix.
Each element in the source operand r is of type .b32 and contains four 8 bit elements e0,
e1, e2, e3 with e0 and e3 containing the LSB and MSB respectively of register r.
Figure 111 stmatrix fragment layout for one 16x8 matrix with 8 bit elements
Optional qualifier .trans indicates that the matrix is stored in column-major format. However,
for 16x8 matrices, .trans is mandatory.
Move a row-major matrix across all threads in a warp, reading elements from source a, and
writing the transposed elements to destination d.
The .shape qualifier indicates the dimensions of the matrix being transposed. Each matrix
element holds 16-bit data as indicated by the .type qualifier.
The mandatory .sync qualifier indicates that movmatrix causes the executing thread to wait
until all threads in the warp execute the same movmatrix instruction before resuming execution.
The mandatory .aligned qualifier indicates that all threads in the warp must execute the same
movmatrix instruction. In conditionally executed code, a movmatrix instruction should only
be used if it is known that all threads in the warp evaluate the condition identically, otherwise
the behavior is undefined.
Operands a and d are 32-bit registers containing fragments of the input matrix and the
resulting matrix respectively. The mandatory qualifier .trans indicates that the resulting
matrix in d is a transpose of the input matrix specified by a.
Each thread in a warp holds a fragment of a row of the input matrix, with thread 0 holding the first
fragment in register a, and so on. A group of four threads holds an entire row of the input
matrix as shown in Figure 112.
Figure 112 movmatrix source matrix fragment layout
Each thread in a warp holds a fragment of a column of the result matrix, with thread 0 holding the
first fragment in register d, and so on. A group of four threads holds an entire column of the
result matrix as shown in Figure 113.
Figure 113 movmatrix result matrix fragment layout
9.7.16.6. Matrix multiply-accumulate operation using mma.sp instruction with sparse matrix A#
This section describes warp-level mma.sp{::ordered_metadata} instruction with sparse matrix A.
This variant of the mma operation can be used when A is a structured sparse matrix with 50%
zeros in each row distributed in a shape-specific granularity. For an MxNxK sparse
mma.sp{::ordered_metadata} operation, the MxK matrix A is packed into MxK/2 elements.
For each K-wide row of matrix A, 50% elements are zeros and the remaining K/2 non-zero elements
are packed in the operand representing matrix A. The mapping of these K/2 elements to the
corresponding K-wide row is provided explicitly as metadata.
Granularity of sparse matrix A is defined as the ratio of the number of non-zero elements in a
sub-chunk of the matrix row to the total number of elements in that sub-chunk where the size of the
sub-chunk is shape-specific. For example, in a 16x16 matrix A, sparsity is expected to be at 2:4
granularity, i.e. each 4-element vector (i.e. a sub-chunk of 4 consecutive elements) of a matrix row
contains 2 zeros. Index of each non-zero element in a sub-chunk is stored in the metadata
operand. Values 0b0000, 0b0101, 0b1010, 0b1111 are invalid values for metadata and
will result in undefined behavior. In a group of four consecutive threads, one or more threads store
the metadata for the whole group depending upon the matrix shape. These threads are specified using
an additional sparsity selector operand.
Figure 114 shows an example of a 16x16 matrix A represented in sparse format and sparsity
selector indicating which thread in a group of four consecutive threads stores the metadata.
Figure 114 Sparse MMA storage example
Granularities for different matrix shapes and data types are described below.
Sparse mma.sp{::ordered_metadata} with half-precision and .bf16 type
For the .m16n8k16 and .m16n8k32mma.sp{::ordered_metadata} operations, matrix A is
structured sparse at a granularity of 2:4. In other words, each chunk of four adjacent elements
in a row of matrix A has two zeros and two non-zero elements. Only the two non-zero elements are
stored in the operand representing matrix A and their positions in the four-wide chunk in matrix
A are indicated by two 2-bit indices in the metadata operand. For mma.sp::ordered_metadata,
0b0100, 0b1000, 0b1001, 0b1100, 0b1101, 0b1110 are the meaningful values
of indices; any other values result in undefined behavior.
Figure 115 Sparse MMA metadata example for .f16/.bf16 type.
The sparsity selector indicates the threads which contribute metadata as listed below:
m16n8k16: One thread within a group of four consecutive threads contributes the metadata for
the entire group. This thread is indicated by a value in {0, 1, 2, 3}.
m16n8k32: A thread-pair within a group of four consecutive threads contributes the sparsity
metadata. Hence, the sparsity selector must be either 0 (threads T0, T1) or 1 (threads T2, T3);
any other value results in undefined behavior.
Sparse mma.sp{::ordered_metadata} with .tf32 type
When matrix A has .tf32 elements, matrix A is structured sparse at a granularity of 1:2. In
other words, each chunk of two adjacent elements in a row of matrix A has one zero and one non-zero
element. Only the non-zero elements are stored in the operand for matrix A and their positions in a
two-wide chunk in matrix A are indicated by the 4-bit index in the metadata. 0b1110 and
0b0100 are the only meaningful index values; any other values result in undefined behavior.
Figure 116 Sparse MMA metadata example for .tf32 type.
The sparsity selector indicates the threads which contribute metadata as listed below:
m16n8k8: One thread within a group of four consecutive threads contributes the metadata for
the entire group. This thread is indicated by a value in {0, 1, 2, 3}.
m16n8k16: A thread-pair within a group of four consecutive threads contributes the sparsity
metadata. Hence, the sparsity selector must be either 0 (threads T0, T1) or 1 (threads T2, T3);
any other value results in undefined behavior.
Sparse mma.sp{::ordered_metadata} with integer type
When matrices A and B have .u8/.s8 elements, matrix A is structured sparse at a granularity
of 2:4. In other words, each chunk of four adjacent elements in a row of matrix A have two zeroes
and two non-zero elements. Only the two non-zero elements are stored in sparse matrix and their
positions in the four-wide chunk are indicated by two 2-bit indices in the metadata. For
mma.sp::ordered_metadata, 0b0100, 0b1000, 0b1001, 0b1100, 0b1101, 0b1110
are the meaningful values of indices; any other values result in undefined behavior.
Figure 117 Sparse MMA metadata example for .u8/.s8 type.
when matrices A and B have .u4/.s4 elements, matrix A is pair-wise structured sparse at a
granularity of 4:8. In other words, each chunk of eight adjacent elements in a row of matrix A has
four zeroes and four non-zero values. Further, the zero and non-zero values are clustered in
sub-chunks of two elements each within the eight-wide chunk. i.e., each two-wide sub-chunk within
the eight-wide chunk must be all zeroes or all non-zeros. Only the four non-zero values are stored
in sparse matrix and the positions of the two two-wide sub-chunks with non-zero values in the
eight-wide chunk of a row of matrix A are indicated by two 2-bit indices in the metadata. For
mma.sp::ordered_metadata, 0b0100, 0b1000, 0b1001, 0b1100, 0b1101, 0b1110
are the meaningful values of indices; any other values result in undefined behavior.
Figure 118 Sparse MMA metadata example for .u4/.s4 type.
The sparsity selector indicates the threads which contribute metadata as listed below:
m16n8k32 with .u8/.s8 type and m16n8k64 with .u4/.s4 type: A thread-pair
within a group of four consecutive threads contributes the sparsity metadata. Hence, the sparsity
selector must be either 0 (threads T0, T1) or 1 (threads T2, T3); any other value results in an
undefined behavior.
m16n8k64 with .u8/.s8 type and m16n8k128 with .u4/.s4 type: All threads
within a group of four consecutive threads contribute the sparsity metadata. Hence, the sparsity
selector in this case must be 0. Any other value of sparsity selector results in an undefined
behavior.
Sparse mma.sp{::ordered_metadata} operating on .e4m3/.e5m2/.e3m2/.e2m3/.e2m1
type with .kind::f8f6f4 or .kind::mxf8f6f4
When matrices A and B have .e4m3/.e5m2/.e3m2/.e2m3/.e2m1 elements, matrix A is
structured sparse at a granularity of 2:4. In other words, each chunk of four adjacent elements in a
row of matrix A have two zeroes and two non-zero elements. Only the two non-zero elements are stored
in sparse matrix and their positions in the four-wide chunk are indicated by two 2-bit indices in the
metadata. 0b0100, 0b1000, 0b1001, 0b1100, 0b1101, 0b1110 are the meaningful
values of indices; any other values result in undefined behavior.
Figure 119 Sparse MMA metadata example for .e4m3/.e5m2/.e3m2/.e2m3/.e2m1 type.
The sparsity selector indicates the threads which contribute metadata as listed below:
m16n8k64: All threads within a group of four consecutive threads contribute the sparsity metadata.
Hence, the sparsity selector in this case must be 0. Any other value of sparsity selector results in
undefined behavior.
Sparse mma.sp::ordered_metadata operating on .e2m1 type with .kind::mxf4 or .kind::mxf4nvf4
When matrices A and B have .e2m1 elements, matrix A is pair-wise structured sparse at a granularity
of 4:8. In other words, each chunk of eight adjacent elements in a row of matrix A has four zeroes and
four non-zero values. Further, the zero and non-zero values are clustered in sub-chunks of two elements
each within the eight-wide chunk. i.e., each two-wide sub-chunk within the eight-wide chunk must be all
zeroes or all non-zeros. Only the four non-zero values are stored in sparse matrix and the positions of
the two two-wide sub-chunks with non-zero values in the eight-wide chunk of a row of matrix A are
indicated by two 2-bit indices in the metadata. 0b0100, 0b1000, 0b1001, 0b1100, 0b1101,
0b1110 are the meaningful values of indices; any other values result in undefined behavior.
Figure 120 Sparse MMA metadata example for .e2m1 type with .kind::mxf4 or .kind::mxf4nvf4
The sparsity selector indicates the threads which contribute metadata as listed below:
m16n8k128: All threads within a group of four consecutive threads contribute the sparsity metadata.
Hence, the sparsity selector in this case must be 0. Any other value of sparsity selector results in
undefined behavior.
9.7.16.6.2. Matrix fragments for multiply-accumulate operation with sparse matrix A#
In this section we describe how the contents of thread registers are associated with fragments of
various matrices and the sparsity metadata. The following conventions are used throughout this
section:
For matrix A, only the layout of a fragment is described in terms of register vector sizes and
their association with the matrix data.
For matrices C and D, since the matrix dimension - data type combination is the same for all
supported shapes, and is already covered in
Matrix multiply-accumulate operation using mma instruction, the pictorial representations
of matrix fragments are not included in this section.
For the metadata operand, pictorial representations of the association between indices of the
elements of matrix A and the contents of the metadata operand are included. Tk:[m..n] present
in cell [x][y..z] indicates that bits m through n (with m being higher) in the
metadata operand of thread with %laneid=k contains the indices of the non-zero elements from
the chunk [x][y]..[x][z] of matrix A.
9.7.16.6.2.1. Matrix Fragments for sparse mma.m16n8k16 with .f16 and .bf16 types#
A warp executing sparse mma.m16n8k16 with .f16 / .bf16 floating point type will compute
an MMA operation of shape .m16n8k16.
Elements of the matrix are distributed across the threads in a warp so each thread of the warp holds
a fragment of the matrix.
Multiplicand A:
.atype
Fragment
Elements
.f16 / .bf16
A vector expression containing two .b32 registers,
with each register containing two non-zero .f16 /
.bf16 elements out of 4 consecutive elements from
matrix A.
Metadata: A .b32 register containing 16 2-bit vectors each storing the index of a non-zero
element of a 4-wide chunk of matrix A as shown in Figure 122.
Figure 122 Sparse MMA .m16n8k16 metadata layout for .f16/.bf16 type.
9.7.16.6.2.2. Matrix Fragments for sparse mma.m16n8k32 with .f16 and .bf16 types#
A warp executing sparse mma.m16n8k32 with .f16 / .bf16 floating point type will compute
an MMA operation of shape .m16n8k32.
Elements of the matrix are distributed across the threads in a warp so each thread of the warp holds
a fragment of the matrix.
Multiplicand A:
.atype
Fragment
Elements
.f16 / .bf16
A vector expression containing four .b32 registers,
with each register containing two non-zero .f16 /
.bf16 elements out of 4 consecutive elements from
matrix A.
Metadata: A .b32 register containing 16 2-bit vectors with each pair of 2-bit vectors storing
the indices of two non-zero element from a 4-wide chunk of matrix A as shown in
Figure 125.
Figure 125 Sparse MMA .m16n8k32 metadata layout for .f16/.bf16 type.
9.7.16.6.2.3. Matrix Fragments for sparse mma.m16n8k16 with .tf32 floating point type#
A warp executing sparse mma.m16n8k16 with .tf32 floating point type will compute an MMA
operation of shape .m16n8k16.
Elements of the matrix are distributed across the threads in a warp so each thread of the warp holds
a fragment of the matrix.
Multiplicand A:
.atype
Fragment
Elements
.tf32
A vector expression containing four .b32 registers, with each
register containing one non-zero .tf32 element out of 2
consecutive elements from matrix A.
Metadata: A .b32 register containing 8 4-bit vectors each storing the index of a non-zero
element of a 2-wide chunk of matrix A as shown in Figure 128.
Figure 128 Sparse MMA .m16n8k16 metadata layout for .tf32 type.
9.7.16.6.2.4. Matrix Fragments for sparse mma.m16n8k8 with .tf32 floating point type#
A warp executing sparse mma.m16n8k8 with .tf32 floating point type will compute an MMA
operation of shape .m16n8k8.
Elements of the matrix are distributed across the threads in a warp so each thread of the warp holds
a fragment of the matrix.
Multiplicand A:
.atype
Fragment
Elements
.tf32
A vector expression containing two .b32 registers, each
containing one non-zero .tf32 element out of 2
consecutive elements from matrix A.
Matrix fragments for multiplicand B and accumulators C and D are the same as in case of
Matrix Fragments for mma.m16n8k8 for .tf32
format.
Metadata: A .b32 register containing 8 4-bit vectors each storing the index of a non-zero
element of a 2-wide chunk of matrix A as shown in Figure 130.
Figure 130 Sparse MMA .m16n8k8 metadata layout for .tf32 type.
9.7.16.6.2.5. Matrix Fragments for sparse mma.m16n8k32 with .u8 / .s8 integer type#
A warp executing sparse mma.m16n8k32 with .u8 / .s8 integer type will compute an MMA
operation of shape .m16n8k32.
Elements of the matrix are distributed across the threads in a warp so each thread of the warp holds
a fragment of the matrix.
Multiplicand A:
.atype
Fragment
Elements
.u8 / .s8
A vector expression containing two .b32 registers, with each
register containing four non-zero .u8 / .s8 elements out
of 8 consecutive elements from matrix A.
Metadata: A .b32 register containing 16 2-bit vectors with each pair of 2-bit vectors storing
the indices of two non-zero elements from a 4-wide chunk of matrix A as shown in
Figure 132.
Figure 132 Sparse MMA .m16n8k32 metadata layout for .u8/.s8 type.
9.7.16.6.2.6. Matrix Fragments for sparse mma.m16n8k64 with .u8 / .s8 / .e4m3 / .e5m2 type#
A warp executing sparse mma.m16n8k64 with .u8 / .s8/ .e4m3/ .e5m2 /
.e3m2 / .e2m3 / .e2m1 type will compute an MMA operation of shape .m16n8k64.
Elements of the matrix are distributed across the threads in a warp so each thread of the warp holds
a fragment of the matrix.
Multiplicand A:
.atype
Fragment
Elements
.u8 / .s8
A vector expression containing four .b32 registers, with each
register containing four non-zero .u8 / .s8 elements out
of 8 consecutive elements from matrix A.
A vector expression containing four .b32 registers, with each
register containing four non-zero .e4m3 / .e5m2 /
.e3m2 / .e2m3 / .e2m1 elements out of 8 consecutive
elements from matrix A.
The layout of the fragments held by different threads is shown in Figure 133
and Figure 134.
Figure 133 Sparse MMA .m16n8k64 fragment layout for columns 0–31 of matrix A with .u8/.s8/.e4m3/.e5m2/.e3m2/.e2m3/.e2m1 type.
Figure 134 Sparse MMA .m16n8k64 fragment layout for columns 32–63 of matrix A with .u8/.s8/.e4m3/.e5m2/.e3m2/.e2m3/.e2m1 type.
Metadata: A .b32 register containing 16 2-bit vectors with each pair of 2-bit vectors storing
the indices of two non-zero elements from a 4-wide chunk of matrix A as shown in
Figure 139 and Figure 140.
Figure 139 Sparse MMA .m16n8k64 metadata layout for columns 0–31 for .u8/.s8/.e4m3/.e5m2/.e3m2/.e2m3/.e2m1 type.
Figure 140 Sparse MMA .m16n8k64 metadata layout for columns 32–63 for .u8/.s8/.e4m3/.e5m2/.e3m2/.e2m3/.e2m1 type.
9.7.16.6.2.7. Matrix Fragments for sparse mma.m16n8k64 with .u4 / .s4 integer type#
A warp executing sparse mma.m16n8k64 with .u4 / .s4 integer type will compute an MMA
operation of shape .m16n8k64.
Elements of the matrix are distributed across the threads in a warp so each thread of the warp holds
a fragment of the matrix.
Multiplicand A:
.atype
Fragment
Elements
.u4 / .s4
A vector expression containing two .b32 registers, with each
register containing eight non-zero .u4 / .s4 elements
out of 16 consecutive elements from matrix A.
Metadata: A .b32 register containing 16 2-bit vectors with each pair of 2-bit vectors storing
the indices of four non-zero elements from a 8-wide chunk of matrix A as shown in
Figure 142.
Figure 142 Sparse MMA .m16n8k64 metadata layout for .u4/.s4 type.
9.7.16.6.2.8. Matrix Fragments for sparse mma.m16n8k128 with .u4 / .s4 integer type#
A warp executing sparse mma.m16n8k128 with .u4 / .s4 / .e2m1 integer type will compute an MMA
operation of shape .m16n8k128.
Elements of the matrix are distributed across the threads in a warp so each thread of the warp holds
a fragment of the matrix.
Multiplicand A:
.atype
Fragment
Elements
.u4 / .s4
A vector expression containing four .b32 registers, with each
register containing eight non-zero .u4 / .s4 elements out
of 16 consecutive elements from matrix A.
A vector expression containing four .b32 registers, with each
register containing eight non-zero .e2m1 elements out
of 16 consecutive elements from matrix A.
The layout of the fragments held by different threads is shown in Figure 143
and Figure 144.
Figure 143 Sparse MMA .m16n8k128 fragment layout for columns 0–63 of matrix A with .u4/.s4/.e2m1 type.
Figure 144 Sparse MMA .m16n8k128 fragment layout for columns 64–127 of matrix A with .u4/.s4/.e2m1 type.
Metadata: A .b32 register containing 16 2-bit vectors with each pair of 2-bit vectors storing
the indices of four non-zero elements from a 8-wide chunk of matrix A as shown in
Figure 149 and Figure 150.
Figure 149 Sparse MMA .m16n8k128 metadata layout for columns 0–63 for .u4/.s4/.e2m1 type.
Figure 150 Sparse MMA .m16n8k128 metadata layout for columns 64–127 for .u4/.s4/.e2m1 type.
Perform matrix multiply-and-accumulate operation with sparse matrix A
Syntax
Half precision floating point type:
mma.spvariant.sync.aligned.m16n8k16.row.col.dtype.f16.f16.ctype d, a, b, c, e, f;
mma.spvariant.sync.aligned.m16n8k32.row.col.dtype.f16.f16.ctype d, a, b, c, e, f;
mma.spvariant.sync.aligned.m16n8k16.row.col.f32.bf16.bf16.f32 d, a, b, c, e, f;
mma.spvariant.sync.aligned.m16n8k32.row.col.f32.bf16.bf16.f32 d, a, b, c, e, f;
mma.spvariant.sync.aligned.m16n8k8.row.col.f32.tf32.tf32.f32 d, a, b, c, e, f;
mma.spvariant.sync.aligned.m16n8k16.row.col.f32.tf32.tf32.f32 d, a, b, c, e, f;
mma.spvariant.sync.aligned.m16n8k64.row.col.f32.f8type.f8type.f32 d, a, b, c, e, f;
mma.sp::ordered_metadata.sync.aligned.m16n8k64.row.col.kind.dtype.f8f6f4type.f8f6f4type.ctype d, a, b, c, e, f;
Perform a MxNxK matrix multiply and accumulate operation, D=A*B+C, where the A matrix is
MxK, the B matrix is KxN, and the C and D matrices are MxN.
A warp executing mma.sp.sync/mma.sp::ordered_metadata.sync instruction compute a single matrix
multiply and accumulate operation.
Qualifier .block_scale specifies that the matrices A and B are scaled with scale_A
and scale_B matrices respectively before performing the matrix multiply and accumulate operation
as specified in the section Block Scaling for mma.sync. The data type corresponding
to each of the element within scale_A and scale_B matrices is specified by .stype.
Qualifier .scale_vec_size specifies the number of columns of scale_A matrix and number of
rows in the matrix scale_B.
The valid combinations of .kind, .stype and .scale_vec_size are described in
Table 45. For mma with .kind::mxf4 when the
qualifier .scale_vec_size is not specified, then it defaults to 2X. In contrast,
when .kind is specified as .kind::mxf8f6f4 then the qualifier .scale_vec_size
defaults to 1X. However, for .kind::mxf4nvf4, it is mandatory to provide valid
.scale_vec_size.
Operands a and b represent two multiplicand matrices A and B, while c and d
represent the accumulator and destination matrices, distributed across the threads in warp. Matrix A
is structured sparse as described in Sparse matrix storage Operands e and f represent sparsity
metadata and sparsity selector respectively. Operand e is a 32-bit integer and operand f is
a 32-bit integer constant with values in the range 0..3.
When .block_scale qualifier is specified, operand scale-a-data, scale-b-data represents
the scale matrix metadata corresponding to scale_A and scale_B matrices respectively.
The tuple {byte-id-a,thread-id-a} and {byte-id-b,thread-id-b} represent selectors for
matrices scale_A and scale_B respectively from their corresponding metadata arguments
scale-a-data, scale-b-data. The operands scale-a-data, scale-b-data are of type
.b32. The operands byte-id-a, thread-id-a, byte-id-b, thread-id-b are unsigned
16-bit integer values. For more details on selector arguments refer
Block Scaling for mma.sync section.
Instruction mma.sp::ordered_metadata requires the indices in the sparsity metadata to be sorted
in an increasing order starting from LSB, otherwise behavior is undefined.
The qualifiers .dtype, .atype, .btype and .ctype indicate the data-type of the
elements in the matrices D, A, B and C respectively. The qualifier .stype indicate the
data-type of the elements in the matrices scale_A and scale_B. In case of shapes
.m16n8k16, .m16n8k32 and .m16n8k64, .dtype must be the same as .ctype.
When .kind is either of .kind::mxf8f6f4 or .kind::f8f6f4, the individual 4-bit and
the 6-bit floating point type elements must be packed in an 8-bit container. The matrix element
of type .e2m1 resides in central 4 bits of the 8-bit container with padding in the upper 2
bits and lower 2 bits of the container. When the matrix element is of type .e3m2 or .e2m3,
the matrix element resides in the lower 6 bits of the 8-bit container with padding in the upper
2 bits of the container. In contrast, note that when using mma with .kind::mxf4 or
.kind::mxf4nvf4, no explicit padding is necessary even though matrix elements are of type
.e2m1.
Precision and rounding :
.f16 floating point operations :
Element-wise multiplication of matrix A and B is performed with at least single
precision. When .ctype or .dtype is .f32, accumulation of the intermediate values
is performed with at least single precision. When both .ctype and .dtype are specified
as .f16, the accumulation is performed with at least half precision.
The accumulation order, rounding and handling of subnormal inputs are unspecified.
.e4m3, .e5m2, .e3m2, .e2m3, .e2m1 floating point operations :
Element-wise multiplication of matrix A and B is performed with specified precision. Accumulation
of the intermediate values is performed with at least single precision.
The accumulation order, rounding, and handling of subnormal inputs are unspecified.
.bf16 and .tf32 floating point operations :
Element-wise multiplication of matrix A and B is performed with specified
precision. Accumulation of the intermediate values is performed with at least single
precision.
The accumulation order, rounding, and handling of subnormal inputs are unspecified.
Integer operations :
The integer mma.sp/mma.sp::ordered_metadata operation is performed with .s32 accumulators.
The .satfinite qualifier indicates that on overflow, the accumulated value is limited to the range
MIN_INT32.. MAX_INT32 (where the bounds are defined as the minimum negative signed 32-bit
integer and the maximum positive signed 32-bit integer respectively).
If .satfinite is not specified, the accumulated value is wrapped instead.
The mandatory .sync qualifier indicates that mma.sp/mma.sp::ordered_metadata instruction causes
the executing thread to wait until all threads in the warp execute the same mma.sp/mma.sp::ordered_metadata
instruction before resuming execution.
The mandatory .aligned qualifier indicates that all threads in the warp must execute the same
mma.sp/mma.sp::ordered_metadata instruction. In conditionally executed code, a mma.sp/mma.sp::ordered_metadata
instruction should only be used if it is known that all threads in the warp evaluate the condition identically,
otherwise behavior is undefined.
The behavior of mma.sp/mma.sp::ordered_metadata instruction is undefined if all threads in the same warp
do not use the same qualifiers, or if any thread in the warp has exited.
Examples of half precision floating point type
// f16 elements in C and D matrix
.reg .f16x2 %Ra<2> %Rb<2> %Rc<2> %Rd<2>
.reg .b32 %Re;
mma.sp.sync.aligned.m16n8k16.row.col.f16.f16.f16.f16
{%Rd0, %Rd1},
{%Ra0, %Ra1},
{%Rb0, %Rb1},
{%Rc0, %Rc1}, %Re, 0x1;
// u8 elements in A and B matrix
mma.sp.sync.aligned.m16n8k32.row.col.satfinite.s32.u8.u8.s32
{%Rd0, %Rd1, %Rd2, %Rd3},
{%Ra0, %Ra1},
{%Rb0, %Rb1},
{%Rc0, %Rc1, %Rc2, %Rc3}, %Re, 0x1;
// s8 elements in A and B matrix
mma.sp.sync.aligned.m16n8k64.row.col.satfinite.s32.s8.s8.s32
{%Rd0, %Rd1, %Rd2, %Rd3},
{%Ra0, %Ra1, %Ra2, %Ra3},
{%Rb0, %Rb1, %Rb2, %Rb3},
{%Rc0, %Rc1, %Rc2, %Rc3}, %Re, 0x0;
// s8 elements in A and B matrix with ordered metadata
mma.sp::ordered_metadata.sync.aligned.m16n8k64.row.col.satfinite.s32.s8.s8.s32
{%Rd0, %Rd1, %Rd2, %Rd3},
{%Ra0, %Ra1, %Ra2, %Ra3},
{%Rb0, %Rb1, %Rb2, %Rb3},
{%Rc0, %Rc1, %Rc2, %Rc3}, %Re, 0x0;
// u4 elements in A and B matrix
mma.sp.sync.aligned.m16n8k64.row.col.s32.s4.s4.s32
{%Rd0, %Rd1, %Rd2, %Rd3},
{%Ra0, %Ra1},
{%Rb0, %Rb1},
{%Rc0, %Rc1, %Rc2, %Rc3}, %Re, 0x1;
// u4 elements in A and B matrix
mma.sp.sync.aligned.m16n8k128.row.col.satfinite.s32.u4.u4.s32
{%Rd0, %Rd1, %Rd2, %Rd3},
{%Ra0, %Ra1, %Ra2, %Ra3},
{%Rb0, %Rb1, %Rb2, %Rb3},
{%Rc0, %Rc1, %Rc2, %Rc3}, %Re, 0x0;
The warpgroup level matrix multiply and accumulate operation has either of the following forms,
where matrix D is called accumulator:
D=A*B+D
D=A*B, where the input from accumulator D is disabled.
The wgmma instructions perform warpgroup level matrix multiply-and-accumulate operation by
having all threads in a warpgroup collectively perform the following actions:
Load matrices A, B and D into registers or into shared memory.
Perform the following fence operations:
wgmma.fence operations to indicate that the register/shared-memory across the warpgroup
have been written into.
fence.proxy.async operation to make the generic proxy operations visible to the async
proxy.
Issue the asynchronous matrix multiply and accumulate operations using the wgmma.mma_async
operation on the input matrices. The wgmma.mma_async operation is performed in the async
proxy.
Create a wgmma-group and commit all the prior outstanding wgmma.mma_async operations into the
group, by using wgmma.commit_group operation.
Wait for the completion of the required wgmma-group.
Once the wgmma-group completes, all the wgmma.mma_async operations have been performed and
completed.
The matrix multiply and accumulate operations support a limited set of shapes for the operand
matrices A, B and D. The shapes of all three matrix operands are collectively described by the tuple
MxNxK, where A is an MxK matrix, B is a KxN matrix, while D is a MxN matrix.
The following matrix shapes are supported for the specified types for the wgmma.mma_async
operation:
The matrix multiply and accumulate operation is supported separately on integer, floating-point,
sub-byte integer and single bit data-types. All operands must contain the same basic type kind,
i.e., integer or floating-point.
For floating-point matrix multiply and accumulate operation, different matrix operands may have
different precision, as described later.
For integer matrix multiply and accumulate operation, both multiplicand matrices (A and B) must have
elements of the same data-type, e.g. both signed integer or both unsigned integer.
The wgmma.mma_async operations are performed in the asynchronous proxy (or async proxy).
Accessing the same memory location across multiple proxies needs a cross-proxy fence. For the async
proxy, fence.proxy.async should be used to synchronize memory between generic proxy and the
async proxy.
The completion of a wgmma.mma_async operation is followed by an implicit generic-async proxy
fence. So the result of the asynchronous operation is made visible to the generic proxy as soon as
its completion is observed. wgmma.commit_group and wgmma.wait_group operations must be used
to wait for the completion of the wgmma.mma_async instructions.
9.7.17.5. Asynchronous Warpgroup Level Matrix Multiply-Accumulate Operation using wgmma.mma_async instruction#
This section describes warpgroup level wgmma.mma_async instruction and the organization of
various matrices involved in this instruction.
9.7.17.5.1. Register Fragments and Shared Memory Matrix Layouts#
The input matrix A of the warpgroup wide MMA operations can be either in registers or in the shared
memory. The input matrix B of the warpgroup wide MMA operations must be in the shared memory. This
section describes the layouts of register fragments and shared memory expected by the warpgroup MMA
instructions.
When the matrices are in shared memory, their starting addresses must be aligned to 16 bytes.
This section describes the organization of various matrices located in register operands of the
wgmma.mma_async instruction.
9.7.17.5.1.1.1. Matrix Fragments for wgmma.mma_async.m64nNk16#
A warpgroup executing wgmma.mma_async.m64nNk16 will compute an MMA operation of shape
.m64nNk16 where N is a valid n dimension as listed in
Matrix Shape.
Elements of the matrix are distributed across the threads in a warpgroup so each thread of the
warpgroup holds a fragment of the matrix.
Multiplicand A in registers:
.atype
Fragment
Elements (low to high)
.f16/.bf16
A vector expression containing four .f16x2 registers, with each
register containing two .f16/ .bf16 elements from matrix A.
a0, a1, a2, a3, a4, a5, a6, a7
The layout of the fragments held by different threads is shown in Figure 151.
Figure 151 WGMMA .m64nNk16 register fragment layout for matrix A.
Accumulator D:
.dtype
Fragment
Elements (low to high)
.f16
A vector expression containing N/4 number of .f16x2
registers, with each register containing two .f16
elements from matrix D.
d0, d1, d2, d3, …, dX, dY, dZ, dW
where
X=N/2-4
Y=N/2-3
Z=N/2-2
W=N/2-1
N=8*iwherei={1,2,...,32}
.f32
A vector expression containing N/2 number of .f32
registers.
The layout of the fragments held by different threads is shown in Figure 152.
Figure 152 WGMMA .m64nNk16 register fragment layout for accumulator matrix D.
9.7.17.5.1.1.2. Matrix Fragments for wgmma.mma_async.m64nNk8#
A warpgroup executing wgmma.mma_async.m64nNk8 will compute an MMA operation of shape
.m64nNk8 where N is a valid n dimension as listed in Matrix Shape.
Elements of the matrix are distributed across the threads in a warpgroup so each thread of the
warpgroup holds a fragment of the matrix.
Multiplicand A in registers:
.atype
Fragment
Elements (low to high)
.tf32
A vector expression containing four .b32 registers containing
four .tf32 elements from matrix A.
a0, a1, a2, a3
The layout of the fragments held by different threads is shown in Figure 153.
Figure 153 WGMMA .m64nNk8 register fragment layout for matrix A.
Accumulator D:
.dtype
Fragment
Elements (low to high)
.f32
A vector expression containing N/2 number of .f32 registers.
d0, d1, d2, d3, …, dX, dY, dZ, dW
where
X=N/2-4
Y=N/2-3
Z=N/2-2
W=N/2-1
N=8*iwherei={1,2,...,32}
The layout of the fragments held by different threads is shown in Figure 154.
Figure 154 WGMMA .m64nNk8 register fragment layout for accumulator matrix D.
9.7.17.5.1.1.3. Matrix Fragments for wgmma.mma_async.m64nNk32#
A warpgroup executing wgmma.mma_async.m64nNk32 will compute an MMA operation of shape
.m64nNk32 where N is a valid n dimension as listed in
Matrix Shape.
Elements of the matrix are distributed across the threads in a warpgroup so each thread of the
warpgroup holds a fragment of the matrix.
Multiplicand A in registers:
.atype
Fragment
Elements (low to high)
.s8/.u8
A vector expression containing four .b32 registers, with each
register containing four .u8/ .s8 elements from matrix A.
a0, a1, a2, a3, … , a14, a15
.e4m3/ .e5m2
A vector expression containing four .b32 registers, with each
register containing four .e4m3/ .e5m2 elements from
matrix A.
The layout of the fragments held by different threads is shown in Figure 155.
Figure 155 WGMMA .m64nNk32 register fragment layout for matrix A.
Accumulator D:
.dtype
Fragment
Elements (low to high)
Miscellaneous Information
.s32
A vector expression containing
N/2 number of .s32
registers.
d0, d1, d2, d3, …, dX, dY, dZ, dW
where
X=N/2-4
Y=N/2-3
Z=N/2-2
W=N/2-1
N depends on .dtype, as
described in the next column.
N=8*iwherei={1,2,3,4}
=16*iwherei={3,4,...,15,16}
.f32
A vector expression containing
N/2 number of .f32
registers.
N=8*iwherei={1,2,...,32}
.f16
A vector expression containing
N/4 number of .f16x2
registers, with each register
containing two .f16
elements from matrix D.
The layout of the fragments held by different threads is shown in Figure 156.
Figure 156 WGMMA .m64nNk32 register fragment layout for accumulator matrix D.
9.7.17.5.1.1.4. Matrix Fragments for wgmma.mma_async.m64nNk256#
A warpgroup executing wgmma.mma_async.m64nNk256 will compute an MMA operation of shape
.m64nNk256 where N is a valid n dimension as listed in
Matrix Shape.
Elements of the matrix are distributed across the threads in a warpgroup so each thread of the
warpgroup holds a fragment of the matrix.
Multiplicand A in registers:
.atype
Fragment
Elements (low to high)
.b1
A vector expression containing four .b32 registers, with each
register containing thirty two .b1 elements from matrix A.
a0, a1, a2, …, a127
The layout of the fragments held by different threads is shown in Figure 157.
Figure 157 WGMMA .m64nNk256 register fragment layout for matrix A.
Accumulator D:
.dtype
Fragment
Elements (low to high)
.s32
A vector expression containing N/2 number of .s32 registers.
d0, d1, d2, d3, …, dX, dY, dZ, dW
where
X=N/2-4
Y=N/2-3
Z=N/2-2
W=N/2-1
N=8*iwherei={1,2,3,4}
=16*iwherei={3,4,...,15,16}
The layout of the fragments held by different threads is shown in Figure 158.
Figure 158 WGMMA .m64nNk256 register fragment layout for accumulator matrix D.
If the argument imm-trans-a / imm-trans-b of the instruction wgmma.mma_async{.sp}
is 0, then K-major is used for matrix A / B respectively. If the value of argument
imm-trans-a is 1 then M-major is used for matrix A. If the value of the argument
imm-trans-b is 1, then N-major is used for matrix B.
In a column-major default BLAS library such as cuBLAS, the matrices A and B with and
without transpose can be classified as either K-Major or M-or-N-Major as shown in the
following table:
Non-Transposed
Transposed
A
K-major
M-major
B
K-major
N-major
To avoid confusion with A, B, row-major, col-major, transpose, and
non-transpose, we will use MN-Major and K-Major throughout this section.
The matrices in the shared memory are made up of one or more “swizzle layout atom”.
The exact layout of these swizzle atoms depends on the swizzling mode, swizzle-atomicity,
and the leading dimension. The layout of the swizzle are shown in
Table 47.
Table 47 Various combinations of swizzling mode, leading dimension and swizzle-atom layout
Swizzling mode
Leading Dimension
/ Major-ness
Swizzle atom layout
(128b element)
128B Swizzling Mode
M/N
8x8
K
8x8
64B Swizzling Mode
M/N
4x8
K
8x4
32B Swizzling Mode
M/N
2x8
K
8x2
None
M/N
1x8
K
8x1
The above shapes are for elements of size 128 bits. For smaller elements sizes, the same
shapes would get multiplied along the leading dimension by a factor of 128/sizeof_bits(Element).
For example, 128B MN major swizzle atom would have a shape of (8*(128/32))x8=32x8 for
tf32 tensor core inputs.
The leading dimension byte offset is defined differently for transposed and non-transposed
matrices. The leading byte offset is defined as follows for matrices whose element types are
normalized to 128-bits:
Major-ness
Definition
K-Major
No-Swizzling: the offset from the first column to the second columns
of the 8x2 tile in the 128-bit element type normalized matrix.
Swizzled layouts: not used, assumed to be 1.
MN-Major
Interleave: offset from the first 8 columns to the next 8 columns.
Swizzled layouts: offset from the first (swizzle-byte-size/16) rows
to the next (swizzle-byte-size/16) rows.
The stride dimension byte offset is defined differently for transposed and non-transposed
matrices. The stride dimension byte offset is defined as follows for matrices whose element
types are normalized to 128-bits:
Major-ness
Definition
K-Major
The offset from the first 8 rows to the next 8 rows.
MN-Major
Interleave: offset from the first row to the next row.
Swizzled layout: offset from the first 8 columns to the next 8
columns
Matrix descriptor specifies the properties of the matrix in shared memory that is a multiplicand in
the matrix multiply and accumulate operation. It is a 64-bit value contained in a register with the
following layout:
Instruction wgmma.mma_async issues a MxNxK matrix multiply and accumulate operation, D=A*B+D, where the A matrix is MxK, the B matrix is KxN, and the D matrix is MxN.
The operation of the form D=A*B is issued when the input predicate argument scale-d is
false.
wgmma.fence instruction must be used to fence the register accesses of wgmma.mma_async
instruction from their prior accesses. Otherwise, the behavior is undefined.
wgmma.commit_group and wgmma.wait_group operations must be used to wait for the completion
of the asynchronous matrix multiply and accumulate operations before the results are accessed.
Register operand d represents the accumulator matrix as well as the destination matrix,
distributed across the participating threads. Register operand a represents the multiplicand
matrix A in register distributed across the participating threads. The 64-bit register operands
a-desc and b-desc are the matrix descriptors which represent the multiplicand matrices A and
B in shared memory respectively. The contents of a matrix descriptor must be same across all the warps
in the warpgroup. The format of the matrix descriptor is described in
Matrix Descriptor Format.
Matrices A and B are stored in row-major and column-major format respectively. For certain floating
point variants, the input matrices A and B can be transposed by specifying the value 1 for the
immediate integer arguments imm-trans-a and imm-trans-b respectively. A value of 0 can be
used to avoid the transpose operation. The valid values of imm-trans-a and imm-trans-b are 0
and 1. The transpose operation is only supported for the wgmma.mma_async variants with .f16/
.bf16 types on matrices accessed from shared memory using matrix descriptors.
For the floating point variants of the wgmma.mma_async operation, each element of the input
matrices A and B can be negated by specifying the value -1 for operands imm-scale-a and
imm-scale-b respectively. A value of 1 can be used to avoid the negate operation. The valid
values of imm-scale-a and imm-scale-b are -1 and 1.
The qualifiers .dtype, .atype and .btype indicate the data type of the elements in
matrices D, A and B respectively. .atype and .btype must be the same for all floating point
wgmma.mma_async variants except for the FP8 floating point variants. The sizes of individual
data elements of matrices A and B in alternate floating point variants of the wgmma.mma_async
operation are as follows:
Matrices A and B have 8-bit data elements when .atype/ .btype is .e4m3/.e5m2.
Matrices A and B have 16-bit data elements when .atype/ .btype is .bf16.
Matrices A and B have 32-bit data elements when .atype/ .btype is .tf32.
Precision and rounding:
Floating point operations:
Element-wise multiplication of matrix A and B is performed with at least single precision. When
.dtype is .f32, accumulation of the intermediate values is performed with at least single
precision. When .dtype is .f16, the accumulation is performed with at least half
precision.
The accumulation order, rounding and handling of subnormal inputs are unspecified.
.bf16 and .tf32 floating point operations:
Element-wise multiplication of matrix A and B is performed with specified
precision. wgmma.mma_async operation involving type .tf32 will truncate lower 13 bits of
the 32-bit input data before multiplication is issued. Accumulation of the intermediate values is
performed with at least single precision.
The accumulation order, rounding, and handling of subnormal inputs are unspecified.
Integer operations:
The integer wgmma.mma_async operation is performed with .s32 accumulators. The
.satfinite qualifier indicates that on overflow, the accumulated value is limited to the
range MIN_INT32.. MAX_INT32 (where the bounds are defined as the minimum negative signed
32-bit integer and the maximum positive signed 32-bit integer respectively).
If .satfinite is not specified, the accumulated value is wrapped instead.
Note
For .atype and .btype as .e4m3 or .e5m2 with .dtype as .f32, current
implementation does accumulation at higher than half precision but lower than single
precision.
The mandatory .sync qualifier indicates that wgmma.mma_async instruction causes the
executing thread to wait until all threads in the warp execute the same wgmma.mma_async
instruction before resuming execution.
The mandatory .aligned qualifier indicates that all threads in the warpgroup must execute the
same wgmma.mma_async instruction. In conditionally executed code, a wgmma.mma_async
instruction should only be used if it is known that all threads in the warpgroup evaluate the
condition identically, otherwise behavior is undefined.
9.7.17.6. Asynchronous Warpgroup Level Multiply-and-Accumulate Operation using wgmma.mma_async.sp instruction#
This section describes warp-level wgmma.mma_async.sp instruction with sparse matrix A. This
variant of the wgmma.mma_async operation can be used when A is a structured sparse matrix with
50% zeros in each row distributed in a shape-specific granularity. For an MxNxK sparse
wgmma.mma_async.sp operation, the MxK matrix A is packed into MxK/2 elements. For each
K-wide row of matrix A, 50% elements are zeros and the remaining K/2 non-zero elements are
packed in the operand representing matrix A. The mapping of these K/2 elements to the
corresponding K-wide row is provided explicitly as metadata.
Granularity of sparse matrix A is defined as the ratio of the number of non-zero elements in a
sub-chunk of the matrix row to the total number of elements in that sub-chunk where the size of the
sub-chunk is shape-specific. For example, in a 64x32 matrix A used in floating point
wgmma.mma_async operations, sparsity is expected to be at 2:4 granularity, i.e. each 4-element
vector (i.e. a sub-chunk of 4 consecutive elements) of a matrix row contains 2 zeros. Index of each
non-zero element in a sub-chunk is stored in the metadata operand. Values 0b0000, 0b0101,
0b1010, 0b1111 are invalid values for metadata and will result in undefined behavior. In a
group of four consecutive threads, one or more threads store the metadata for the whole group
depending upon the matrix shape. These threads are specified using an additional sparsity selector operand.
Matrix A and its corresponding input operand to the sparse wgmma is similar to the diagram shown in
Figure 114, with an appropriate matrix size.
Granularities for different matrix shapes and data types are described below.
Sparse wgmma.mma_async.sp with half-precision and .bf16 type
For .f16 and .bf16 types, for all supported 64xNx32 shapes, matrix A is structured
sparse at a granularity of 2:4. In other words, each chunk of four adjacent elements in a row of
matrix A have two zeroes and two non-zero elements. Only the two non-zero elements are stored in
matrix A and their positions in the four-wide chunk in Matrix A are indicated by two 2-bit indices
in the metadata operand.
Figure 174 Sparse WGMMA metadata example for .f16/.bf16 type.
The sparsity selector indicates a thread-pair within a group of four consecutive threads which
contributes the sparsity metadata. Hence, the sparsity selector must be either 0 (threads T0, T1) or
1 (threads T2, T3); any other value results in undefined behavior.
Sparse wgmma.mma_async.sp with .tf32 type
For .tf32 type, for all supported 64xNx16 shapes, matrix A is structured sparse at a
granularity of 1:2. In other words, each chunk of two adjacent elements in a row of matrix A have
one zero and one non-zero element. Only the non-zero element is stored in operand for matrix A and
the 4-bit index in the metadata indicates the position of the non-zero element in the two-wide
chunk. 0b1110 and 0b0100 are the only meaningful values of the index, the remaining values result in
undefined behavior.
Figure 175 Sparse WGMMA metadata example for .tf32 type.
The sparsity selector indicates a thread-pair within a group of four consecutive threads which
contributes the sparsity metadata. Hence, the sparsity selector must be either 0 (threads T0, T1) or
1 (threads T2, T3); any other value results in undefined behavior.
Sparse wgmma.mma_async.sp with .e4m3 and .e5m2 floating point type
For .e4m3 and .e5m2 types, for all supported 64xNx64 shapes, matrix A is structured
sparse at a granularity of 2:4. In other words, each chunk of four adjacent elements in a row of
matrix A have two zeroes and two non-zero elements. Only the two non-zero elements are stored in
matrix A and their positions in the four-wide chunk in Matrix A are indicated by two 2-bit indices
in the metadata operand.
Figure 176 Sparse WGMMA metadata example for .e4m3/.e5m2 type.
All threads contribute the sparsity metadata and the sparsity selector must be 0; any other value
results in undefined behavior.
Sparse wgmma.mma_async.sp with integer type
For the integer type, for all supported 64xNx64 shapes, matrix A is structured sparse at a
granularity of 2:4. In other words, each chunk of four adjacent elements in a row of matrix A have
two zeroes and two non-zero elements. Only the two non-zero elements are stored in matrix A and two
2-bit indices in the metadata indicate the position of these two non-zero elements in the four-wide
chunk.
Figure 177 Sparse WGMMA metadata example for .u8/.s8 type.
All threads contribute the sparsity metadata and the sparsity selector must be 0; any other value
results in undefined behavior.
9.7.17.6.2. Matrix fragments for warpgroup-level multiply-accumulate operation with sparse matrix A#
In this section we describe how the contents of thread registers are associated with fragments of A
matrix and the sparsity metadata.
Each warp in the warpgroup provides sparsity information for 16 rows of matrix A. The following
table shows the assignment of warps to rows of matrix A:
Warp
Sparsity information for rows of matrix A
%warpid % 4 = 3
48-63
%warpid % 4 = 2
32-47
%warpid % 4 = 1
16-31
%warpid % 4 = 0
0-15
The following conventions are used throughout this section:
For matrix A, only the layout of a fragment is described in terms of register vector sizes and
their association with the matrix data.
For the metadata operand, pictorial representations of the association between indices of the
elements of matrix A and the contents of the metadata operand are included. Tk:[m..n] present
in cell [x][y..z] indicates that bits m through n (with m being higher) in the
metadata operand of thread with %laneid=k contains the indices of the non-zero elements from
the chunk [x][y]..[x][z] of matrix A.
9.7.17.6.2.1. Matrix Fragments for sparse wgmma.mma_async.m64nNk32#
A warpgroup executing sparse wgmma.mma_async.m64nNk32 will compute an MMA operation of shape
.m64nNk32 where N is a valid n dimension as listed in
Matrix Shape.
Elements of the matrix are distributed across the threads in a warpgroup so each thread of the
warpgroup holds a fragment of the matrix.
Metadata operand is a .b32 register containing 16 2-bit vectors each storing the index of a
non-zero element of a 4-wide chunk of matrix A.
Figure 179 shows the mapping of the metadata bits to the elements
of matrix A for a warp. In this figure, variable i represents the value of the sparsity
selector operand.
Figure 179 Sparse WGMMA .m64nNk32 metadata layout for .f16/.bf16 type.
9.7.17.6.2.2. Matrix Fragments for sparse wgmma.mma_async.m64nNk16#
A warpgroup executing sparse wgmma.mma_async.m64nNk16 will compute an MMA operation of shape
.m64nNk16 where N is a valid n dimension as listed in
Matrix Shape.
Elements of the matrix are distributed across the threads in a warpgroup so each thread of the
warpgroup holds a fragment of the matrix.
Metadata operand is a .b32 register containing eight 4-bit vectors each storing the index of a
non-zero element of a 2-wide chunk of matrix A.
Figure 181 shows the mapping of the metadata bits to the elements
of matrix A for a warp. In this figure, variable i represents the value of the sparsity
selector operand.
Figure 181 Sparse WGMMA .m64nNk16 metadata layout for .tf32 type.
9.7.17.6.2.3. Matrix Fragments for sparse wgmma.mma_async.m64nNk64#
A warpgroup executing sparse wgmma.mma_async.m64nNk64 will compute an MMA operation of shape
.m64nNk64 where N is a valid n dimension as listed in
Matrix Shape.
Elements of the matrix are distributed across the threads in a warpgroup so each thread of the
warpgroup holds a fragment of the matrix.
Instruction wgmma.mma_async issues a MxNxK matrix multiply and accumulate operation, D=A*B+D, where the A matrix is MxK, the B matrix is KxN, and the D matrix is MxN.
The matrix A is stored in the packed format Mx(K/2) as described in
Sparse matrix storage.
The operation of the form D=A*B is issued when the input predicate argument scale-d is
false.
wgmma.fence instruction must be used to fence the register accesses of wgmma.mma_async
instruction from their prior accesses. Otherwise, the behavior is undefined.
wgmma.commit_group and wgmma.wait_group operations must be used to wait for the completion
of the asynchronous matrix multiply and accumulate operations before the results are accessed.
Register operand d represents the accumulator matrix as well as the destination matrix,
distributed across the participating threads. Register operand a represents the multiplicand
matrix A in register distributed across the participating threads. The 64-bit register operands
a-desc and b-desc are the matrix descriptors which represent the multiplicand matrices A and
B in shared memory respectively. The contents of a matrix descriptor must be same across all the
warps in the warpgroup. The format of the matrix descriptor is described in
Matrix Descriptor Format. Matrix A is
structured sparse as described in Sparse matrix storage. Operands sp-meta and sp-sel
represent sparsity metadata and sparsity selector respectively. Operand sp-meta is a 32-bit
integer and operand sp-sel is a 32-bit integer constant with values in the range 0..3.
The valid values of sp-meta and sp-sel for each shape is specified in
Sparse matrix storage and are summarized here :
Matrix shape
.atype
Valid values of sp-meta
Valid values of sp-sel
.m64nNk16
.tf32
0b1110 , 0b0100
0 (threads T0, T1) or 1 (threads T2, T3)
.m64nNk32
.f16/
.bf16
0b00, 0b01, 0b10, 0b11
0 (threads T0, T1) or 1 (threads T2, T3)
.m64nNk64
.e4m3 /
.e5m2 /
.s8 /
.u8
0b00, 0b01, 0b10, 0b11
0 (all threads contribute)
Matrices A and B are stored in row-major and column-major format respectively. For certain floating
point variants, the input matrices A and B can be transposed by specifying the value 1 for the
immediate integer arguments imm-trans-a and imm-trans-b respectively. A value of 0 can be
used to avoid the transpose operation. The valid values of imm-trans-a and imm-trans-b are 0
and 1. The transpose operation is only supported for the wgmma.mma_async variants with .f16/
.bf16 types on matrices accessed from shared memory using matrix descriptors.
For the floating point variants of the wgmma.mma_async operation, each element of the input
matrices A and B can be negated by specifying the value -1 for operands imm-scale-a and
imm-scale-b respectively. A value of 1 can be used to avoid the negate operation. The valid
values of imm-scale-a and imm-scale-b are -1 and 1.
The qualifiers .dtype, .atype and .btype indicate the data type of the elements in
matrices D, A and B respectively. .atype and .btype must be the same for all floating point
wgmma.mma_async variants except for the FP8 floating point variants. The sizes of individual
data elements of matrices A and B in alternate floating point variants of the wgmma.mma_async
operation are as follows:
Matrices A and B have 8-bit data elements when .atype/ .btype is .e4m3/.e5m2.
Matrices A and B have 16-bit data elements when .atype/ .btype is .bf16.
Matrices A and B have 32-bit data elements when .atype/ .btype is .tf32.
Precision and rounding:
Floating point operations:
Element-wise multiplication of matrix A and B is performed with at least single precision. When
.dtype is .f32, accumulation of the intermediate values is performed with at least single
precision. When .dtype is .f16, the accumulation is performed with at least half
precision.
The accumulation order, rounding and handling of subnormal inputs are unspecified.
.bf16 and .tf32 floating point operations:
Element-wise multiplication of matrix A and B is performed with specified
precision. wgmma.mma_async operation involving type .tf32 will truncate lower 13 bits of
the 32-bit input data before multiplication is issued. Accumulation of the intermediate values is
performed with at least single precision.
The accumulation order, rounding, and handling of subnormal inputs are unspecified.
Integer operations:
The integer wgmma.mma_async operation is performed with .s32 accumulators. The
.satfinite qualifier indicates that on overflow, the accumulated value is limited to the
range MIN_INT32.. MAX_INT32 (where the bounds are defined as the minimum negative signed
32-bit integer and the maximum positive signed 32-bit integer respectively).
If .satfinite is not specified, the accumulated value is wrapped instead.
The mandatory .sync qualifier indicates that wgmma.mma_async instruction causes the
executing thread to wait until all threads in the warp execute the same wgmma.mma_async
instruction before resuming execution.
The mandatory .aligned qualifier indicates that all threads in the warpgroup must execute the
same wgmma.mma_async instruction. In conditionally executed code, a wgmma.mma_async
instruction should only be used if it is known that all threads in the warpgroup evaluate the
condition identically, otherwise behavior is undefined.
Enforce an ordering of register accesses between wgmma.mma_async and other operations.
Syntax
wgmma.fence.sync.aligned;
Description
wgmma.fence instruction establishes an ordering between prior accesses to any warpgroup
registers and subsequent accesses to the same registers by a wgmma.mma_async instruction. Only
the accumulator register and the input registers containing the fragments of matrix A require this
ordering.
The wgmma.fence instruction must be issued by all warps of the warpgroup at the following
locations:
Before the first wgmma.mma_async operation in a warpgroup.
Between a register access by a thread in the warpgroup and any wgmma.mma_async instruction
that accesses the same registers, either as accumulator or input register containing fragments of
matrix A, except when these are accumulator register accesses across multiple wgmma.mma_async
instructions of the same shape. In the latter case, an ordering guarantee is provided by default.
Otherwise, the behavior is undefined.
An async proxy fence must be used to establish an ordering between prior writes to shared memory
matrices and subsequent reads of the same matrices in a wgmma.mma_async instruction.
The mandatory .sync qualifier indicates that wgmma.fence instruction causes the executing
thread to wait until all threads in the warp execute the same wgmma.fence instruction before
resuming execution.
The mandatory .aligned qualifier indicates that all threads in the warpgroup must execute the
same wgmma.fence instruction. In conditionally executed code, an wgmma.fence instruction
should only be used if it is known that all threads in the warpgroup evaluate the condition
identically, otherwise the behavior is undefined.
Examples
// Example 1, first use example:
wgmma.fence.sync.aligned; // Establishes an ordering w.r.t. prior accesses to the registers s32d<0-3>
wgmma.mma_async.sync.aligned.m64n8k32.s32.u8.u8 {s32d0, s32d1, s32d2, s32d3},
descA, descB, scaleD;
wgmma.commit_group.sync.aligned;
wgmma.wait_group.sync.aligned 0;
// Example 2, use-case with the input value updated in between:
wgmma.fence.sync.aligned;
wgmma.mma_async.sync.aligned.m64n8k32.s32.u8.u8 {s32d0, s32d1, s32d2, s32d3},
descA, descB, scaleD;
…
mov.b32 s32d0, new_val;
wgmma.fence.sync.aligned;
wgmma.mma_async.sync.aligned.m64n8k32.s32.u8.u8 {s32d4, s32d5, s32d6, s32d7},
{s32d0, s32d1, s32d2, s32d3},
descB, scaleD;
wgmma.commit_group.sync.aligned;
wgmma.wait_group.sync.aligned 0;
Commits all prior uncommitted wgmma.mma_async operations into a wgmma-group.
Syntax
wgmma.commit_group.sync.aligned;
Description
wgmma.commit_group instruction creates a new wgmma-group per warpgroup and batches all prior
wgmma.mma_async instructions initiated by the executing warp but not committed to any
wgmma-group into the new wgmma-group. If there are no uncommitted wgmma.mma_async instructions
then wgmma.commit_group results in an empty wgmma-group.
An executing thread can wait for the completion of all wgmma.mma_async operations in a
wgmma-group by using wgmma.wait_group.
The mandatory .sync qualifier indicates that wgmma.commit_group instruction causes the
executing thread to wait until all threads in the warp execute the same wgmma.commit_group
instruction before resuming execution.
The mandatory .aligned qualifier indicates that all threads in the warpgroup must execute the
same wgmma.commit_group instruction. In conditionally executed code, an wgmma.commit_group
instruction should only be used if it is known that all threads in the warpgroup evaluate the
condition identically, otherwise the behavior is undefined.
Signal the completion of a preceding warpgroup operation.
Syntax
wgmma.wait_group.sync.aligned N;
Description
wgmma.wait_group instruction will cause the executing thread to wait until only N or fewer of
the most recent wgmma-groups are pending and all the prior wgmma-groups committed by the executing
threads are complete. For example, when N is 0, the executing thread waits on all the prior
wgmma-groups to complete. Operand N is an integer constant.
Accessing the accumulator register or the input register containing the fragments of matrix A of a
wgmma.mma_async instruction without first performing a wgmma.wait_group instruction that
waits on a wgmma-group including that wgmma.mma_async instruction is undefined behavior.
The mandatory .sync qualifier indicates that wgmma.wait_group instruction causes the
executing thread to wait until all threads in the warp execute the same wgmma.wait_group
instruction before resuming execution.
The mandatory .aligned qualifier indicates that all threads in the warpgroup must execute the
same wgmma.wait_group instruction. In conditionally executed code, an wgmma.wait_group
instruction should only be used if it is known that all threads in the warpgroup evaluate the
condition identically, otherwise the behavior is undefined.
The 5th generation TensorCore has dedicated on-chip memory that is specialized for use by
TensorCore operations. This Tensor Memory is organized as a two-dimensional matrix where
the horizontal rows are called lanes and the vertical columns are called columns.
On architecture sm_100a/sm_100f, the 5th generation TensorCore’s Tensor Memory has a
two-dimensional structure of 512 columns and 128 rows per CTA, with each cell being 32-bits in size.
Restrictions on threads accessing the Tensor Memory via the load and store operations
are specified in Access restrictions.
The allocation and deallocation of Tensor Memory is performed in terms of
columns. The unit of allocation is 32 columns and the number of columns being allocated must be
a power of 2. When a column is allocated, all 128 lanes of the column are allocated.
All of the Tensor Memory that was allocated in a kernel, must be explicitly deallocated
before the kernel exits.
The matrix multiply and accumulate operations support a limited set of shapes for the operand matrices
A, B and D. The shapes of all three matrix operands are collectively described by the tuple
MxNxK where A is MxK matrix, B is a KxN matrix, and D is a MxN matrix.
Table 48 shows matrix shapes that are supported for the specified types for the
tcgen05.mma operation.
Table 48 Various combinations of .kind and shapes
Various Combinations
Shapes Supported
.kind::*
Has .ws
CTA Group
Sparsity
dtype
atype/btype
kind::f16
No .ws
1
Dense
.f16
.f16
64xNxK
128xNxK
N = {8, 16, 24, … 256} steps of 8
K = 16
.f32
.f16, .bf16
Sparse
.f16
.f16
K = 32
.f32
.f16, .bf16
2
Dense
.f16
.f16
128xNxK
256xNxK
N = {16, 32, … 256} steps of 16
K = 16
.f32
.f16, .bf16
Sparse
.f16
.f16
K = 32
.f32
.f16, .bf16
.ws
1
Dense
.f16
.f16
32xNxK
64xNxK
128xNxK
N = {64, 128, 256}
K = 16
.f32
.f16, .bf16
Sparse
.f16
.f16
N = {64, 128}
K = 32
.f32
.f16, .bf16
2
Either
.f16
.f16
Invalid
.f32
.f16, .bf16
.kind::tf32
No .ws
1
Dense
.f32
.tf32
64xNxK
128xNxK
N = {8, 16, 24, … 256} steps of 8
K = 8
Sparse
K = 16
2
Dense
128xNxK
256xNxK
N = {16, 32, … 256} steps of 16
K = 8
Sparse
K = 16
.ws
1
Dense
32xNxK
64xNxK
128xNxK
N = {64, 128, 256}
K = 8
Sparse
N = {64, 128}
K = 16
2
Dense
Invalid
Sparse
.kind::f8f6f4
No .ws
1
Dense
.f32
.f16
.e4m3,
.e5m2,
.e2m3,
.e3m2,
.e2m1
For K = 64, only
.e4m3 and
.e5m2 are
supported.
64xNxK
128xNxK
128xNxK1
N = {8, 16, … 256} steps of 8
OR
N = {16, 32, … 256} steps of 16
K = 32
K1
= 64
Sparse
K = 64 /
128
2
Dense
128xNxK
256xNxK
256xNxK1
N = {16, 32, … 256} steps of 16
K = 32
K1
= 64
Sparse
K = 64 /
128
.ws
1
Dense
32xNxK
64xNxK
128xNxK
N = {64, 128, 256}
K = 32 / 64
Sparse
N = {64, 128}
K = 64 /
128
2
Dense
Invalid
Sparse
.kind::mxf8f6f4
No .ws
1
Dense
.f32
.e4m3,
.e5m2,
.e2m3,
.e3m2,
.e2m1
X
(Scale)
.ue8m0
128xNxK
N = {8, 16, … 256} steps of 8
K = 32 / 64
Sparse
K = 64 /
128
2
Dense
128xNxK
256xNxK
256xNxK1
N = {16, 32, … 256} steps of 16
K = 32,
K1
= 64
Sparse
256xNxK
K = 64 /
128
.ws
1
Dense
Invalid
Sparse
2
Dense
Sparse
.kind::i8
No .ws
1
Dense
.s32
.s8, .u8
64xNxK
128xNxK
N = {8, 16, 24, 32, 48, … 256}
steps of 16 after N > 32
K = 32
Sparse
K = 64
2
Dense
128xNxK
256xNxK
N = {32, 64, … 256} steps of 32
K = 32
Sparse
K = 64
.ws
1
Dense
32xNxK
64xNxK
128xNxK
N = {64, 128, 256}
K = 32
Sparse
N = {64, 128}
K = 64
2
Dense
Invalid
Sparse
.kind::mxf4
No .ws
1
Dense
.f32
.e2m1
X
(Scale)
.ue8m0
128xNxK
N = {8, 16, … 256} steps of 8
K = 64 / 96
Sparse
K = 128 /
192
2
Dense
128xNxK
256xNxK
256xNxK1
N = {16, 32, … 256} steps of 16
K = 64,
K1
= 96 / 128
Sparse
256xNxK
K = 128 /
192
.ws
1 / 2
Either
Invalid
.kind::mxf4nvf4
No .ws
1
Dense
.f32
.e2m1
X
(Scale)
.ue8m0,
.ue4m3,
.ue5m3
128xNxK
N = {8, 16, … 256} steps of 8
K = 64 / 96
Sparse
K = 128 /
192
2
Dense
128xNxK
256xNxK
256xNxK1
N = {16, 32, … 256} steps of 16
K = 64,
K1
= 96 / 128
Sparse
256xNxK
K = 128 /
192
.ws
1 / 2
Either
Invalid
.kind::ti16
No .ws
1
Dense
.s32
.s1z4m11
64xN1 xK
128xN2 xK
N1 = {8, 16, 24, … 256}
steps of 8
N2 = {16, 32, … 256}
steps of 16
K can be specified explicitly if there are multiple values of K supported for a given MMA variant.
Otherwise, if K can be uniquely determined as per the Table 48, then the
instruction descriptor bit corresponding to K must be set to 0.
The data movement shape indicates the dimension of the data to be moved to or from the
Tensor Memory. These shapes are described as a tuple lanexsize where:
lane indicates the number of rows in the Tensor Memory; and
size indicates the amount of data, in units of bits (b), across the columns in the
Tensor Memory.
The following shapes are supported by various tcgen05 operations:
The following shows the layout of the matrix fragments across threads of the warp.
9.7.18.2.3.1.1. Matrix fragments for shape .32x32b#
A tcgen05{.ld,.st}.32x32b instruction has the following data vector register.
Fragment
Elements (low to high)
A vector expression containing .num
number of .b32 registers as
mentioned in the
Table 59.
r0, r1, …
A warp executing tcgen05{.ld,.st}.32x32b will access 32 lanes of the Tensor Memory.
It loads from or stores to each of the lane (32 * .num)-bits of data as shown in
Figure 186.
Figure 186 Matrix Fragment for shape .32x32b
9.7.18.2.3.1.2. Matrix fragments for shape .16x64b#
A tcgen05{.ld,.st}.16x64b instruction has the following data vector register.
Fragment
Elements (low to high)
A vector expression containing .num
number of .b32 registers as
mentioned in the
Table 59.
r0, r1, …
A warp executing tcgen05{.ld,.st}.16x64b will access 16 lanes of the Tensor Memory.
It loads from or stores to each of the lane (64 * .num)-bits of data as shown in
Figure 187.
Figure 187 Matrix Fragment for shape .16x64b
9.7.18.2.3.1.3. Matrix fragments for shape .16x128b#
A tcgen05{.ld,.st}.16x128b instruction has the following data vector register.
Fragment
Elements (low to high)
A vector expression containing .num
number of .b32 registers as
mentioned in the
Table 59.
r0, r1, …
A warp executing tcgen05{.ld,.st}.16x128b will access 16 lanes of the Tensor Memory.
It loads from or stores to each of the lane (128 * .num)-bits of data as shown in
Figure 188.
Figure 188 Matrix Fragment for shape .16x128b
9.7.18.2.3.1.4. Matrix fragments for shape .16x256b#
A tcgen05{.ld,.st}.16x256b instruction has the following data vector register.
Fragment
Elements (low to high)
A vector expression containing .num
number of .b32 registers as
mentioned in the
Table 59.
r0, r1, r2, r3, …
A warp executing tcgen05{.ld,.st}.16x256b will access 16 lanes of the Tensor Memory.
It loads from or stores to each of the lane (256 * .num)-bits of data as shown in
Figure 189.
Figure 189 Matrix Fragment for shape .16x256b
9.7.18.2.3.1.5. Matrix fragments for shape .16x32bx2#
A tcgen05{.ld,.st}.16x32bx2 instruction has the following data vector register.
Fragment
Elements (low to high)
A vector expression containing .num
number of .b32 registers as
mentioned in the
Table 59.
r0, r1, …
A warp executing tcgen05{.ld,.st}.16x32bx2 will access 16 lanes of the Tensor Memory.
It loads from or stores to each of the lane (32 * .num)-bits of data as shown in
Figure 190.
In this mode, the leading dimension stride is specified as a relative byte offset between the
columns as explained in the below table.
The leading dimension stride can either be specified as a relative offset between the columns
or as an absolute byte address of next buffer. The leading dimension stride is defined
differently for transposed and non-transposed matrices. The leading dimension stride is defined
as follows for matrices whose element types are normalized to 128-bits:
Major-ness
Definition
K-Major
No-Swizzling: the stride from the first column to the second column
of the 8x2 tile in the 128-bit element type normalized matrix.
Swizzled layouts: not used, assumed to be 1.
MN-Major
Interleave: stride from the first 8 columns to the next 8 columns.
Swizzled layouts: stride from the first (swizzle-byte-size/16) rows
to the next (swizzle-byte-size/16) rows.
9.7.18.3.1.2. Absolute address mode for K dimension being 48B#
The tcgen05.mma instruction with K-dimension of 48B would overflow the 128B
shared memory boundary if the data is packed contiguously.
In this case, the absolute address mode can be used to break up the data in the
shared memory into two chunks such that both these chunks are laid out within
the aligned 128-byte address boundary.
The leading dimension absolute address can point to the second data chunk in the shared memory.
9.7.18.3.1.2.1. Restrictions on the Leading Dimension Absolute Address Stride#
Following are the restrictions on the absolute address stride mode:
Only 128B swizzle (with 16B atomicity) is supported.
Only K-Major mode is supported. That is, the transpose bits(bits #15 and #16) in
Instruction descriptor must be 0.
The stride dimension byte offset is defined differently for transposed and non-transposed
matrices. The stride dimension byte offset is defined as follows for matrices whose element
types are normalized to 128-bits:
Major-ness
Definition
K-Major
The offset from the first 8 rows to the next 8 rows.
MN-Major
Interleave: offset from the first row to the next row.
Swizzled layout: offset from the first 8 columns to the next 8
columns
The shared memory descriptor describes the properties of multiplicand matrix in shared
memory including its location in the shared memory of the current CTA. It is a 64-bit
value contained in a register with the following layout:
lut::b Matrix B K_Segment start offset in K=128 (48B) block
- 0: 0
- 1: 24
54-60
7
Fixed constant value of 0xb00000000
61-63
3
Specifies the swizzling mode to be used:
0. No swizzling
1. 128-Byte with 32B atomic swizzling
2. 128-Byte swizzling
4. 64-Byte swizzling
6. 32-Byte swizzling
Note: Values 3, 5 and 7 are invalid
where matrix-descriptor-encode(x) = (x & 0x3FFFF) >> 4
The value of base offset is 0 when the repeating pattern of the specified swizzling mode
starts as per shown in Table 50.
When decompress::lut::b qualifier is used, the tcgen05.mma instruction reads 48 bytes of B matrix from
shared memory and stores in the collector buffer. The tcgen05.mma instruction needs only 24 bytes(3 * 64 / 8).
Based on the value of bit 53 in the shared memory descriptor, either the first or second 24 bytes chunk will be used.
Table 50 Starting address of repeating pattern for various swizzling modes
Swizzling mode
Starting address of the repeating pattern
128-Byte swizzle
1024-Byte boundary
64-Byte swizzle
512-Byte boundary
32-Byte swizzle
256-Byte boundary
Otherwise, the base offset must be a non-zero value, computed using the following formula:
baseoffset=(patternstartaddr>>0x7)&0x7
The instruction descriptor describes the shapes, types and other details of all the matrices
and the matrix-multiplication-and-accumulation operation. It is a 32-bit value in registers
and the exact layout is dependent on the MMA-Kind:
Table 51 Instruction descriptor format for .kind::tf32, .kind::f16, .kind::f8f6f4, .kind::i8 and .kind::ti16
Bit 29 for K dimension is valid for architecture sm_107f or higher in the same family.
For .kind::mxf8f6f4:
Bit 26 for Matrix A Scale Factor Layout is valid for sm_107f or higher in the same family.
Bit 31 for K dimension is valid for architecture sm_107f or higher in the same family.
For .kind::mxf4, .kind::mxf4nvf4:
Bit 3 for K dimension is valid for architecture sm_107f or higher in the same family.
Bit 12 for sparsity version must map to v0 for architectures sm_100a, sm_103a,
sm_110a and to v1 for architecture sm_107a, otherwise behavior is undefined.
Bit 26 for Matrix A Scale Factor Layout is valid for sm_107f or higher in the same family.
The zero-column mask descriptor is used to generate a mask that specifies which columns of
B matrix will have zero value for the MMA operation regardless of the values present in
the shared memory. The total size of the generated mask is N-bits.
A 0-bit in the mask specifies that values of the corresponding column in matrix B should
be used for the MMA operation. A 1-bit in the mask specifies 0s must be used for the entire
column for the MMA operation.
The zero-column mask descriptor is a 64-bit value in registers with the following layout:
Table 54 Zero-Column Mask descriptor layout
Bits
Size (bits)
Field Name
Description
0-7
8
Start Count 0 (sc0)
Specifies the LSBs that must be skipped
for sub-mask mask-i
8-15
8
Start Count 1 (sc1)
16-23
8
Start Count 2 (sc2)
24-31
8
Start Count 3 (sc3)
32
1
First Span 0 (fs0)
Specifies the starting value for
sub-mask mask-i
33
1
First Span 1 (fs1)
34
1
First Span 2 (fs2)
35
1
First Span 3 (fs3)
36-38
3
Reserved - Must be 0
39
1
Non-Zero Mask
Value 0 indicates generated mask will have all 0s
Value 1 indicates the mask has to be generated
40-47
8
Skip Span
(Count of consecutive columns where B matrix is used) - 1
48-55
8
Use Span
(Count of consecutive columns where 0s ar used) - 1
56-61
6
Column Shift
Shifts column by specified amount.
Thus allows MMA on non-0 starting column.
Max shift amount = 16 for M=32
Max shift amount = 32 otherwise
The zero-column mask is made up of one or more sub-mask depending on M, as shown in the table:
M
Zero-Column Mask breakup
Sub-masks
First Span used
Start Column used
128
Single sub-mask of size N-bits
mask0
fs0
sc0
64
Two sub-masks, each with size of N/2 bits
mask0, mask1
fs0, fs1
sc0, sc1
32
Four sub-masks, each with size of N/4 bits
mask0, mask1
mask2, mask3
fs0, fs1, fs2,
fs3
sc0, sc1, sc2,
sc3
The following table shows the coverage of the sub-masks across N-dimension:
Sub-mask
M
128
64
32
mask0
Columns [0, N-1]
Columns [0, N/2-1]
Columns [0, N/4-1]
mask1
–
Columns [N/2, N-1]
Columns [N/4, N/2-1]
mask2
–
–
Columns [N/2, (N/4*3)-1]
mask3
–
–
Columns [(N/4*3), N-1]
The following examples shows zero-column mask descriptor and their corresponding mask generated:
Example 1: M = 128
Input zero-column mask descriptor:
Start count
First span
Non-Zero Mask
Skip Span
Use Span
Shift
{0, 0, 0, 0}
{0, 0, 0, 0}
0
4
3
0
Output zero-column mask: 0x0.
As Non-Zero Mask field is 0, the mask is 0x0. All the columns of the matrix B will be used
for the MMA operation.
Example 2: M = 128
Input zero-column mask descriptor:
Start count
First span
Non-Zero Mask
Skip Span
Use Span
Shift
{-, -, -, 0}
{-, -, -, 0}
1
2
3
0
Output mask0: 0b … 111 0000 111 0000 (size = N)
Example 3: M = 64
Input zero-column mask descriptor:
Start count
{.., sc1, sc0}
First span
{.., fs1, fs0}
Non-Zero Mask
Skip Span
Use Span
Shift
{-, -, 0, 0}
{-, -, 0, 1}
1
2
3
0
Output mask0: 0b … 111 0000 111 0000 111
Output masl1: 0b … 0000 111 0000 111 0000
Example 4: M = 32
Input zero-column mask descriptor:
Start count
{sc3, sc2, sc1, sc0}
First span
{fs3, fs2, fs1, fs0}
Non-Zero Mask
Skip Span
Use Span
Shift
{1, 2, 1, 0}
{0, 0, 1, 1}
1
2
3
2
Output mask0: 0b … 0000 111 0000 111
Output mask1: 0b … 0000 111 0000 11
Output mask2: 0b … 111 0000 111 00
Output mask3: 0b … 111 0000 111 000
If N = 128 then B Matrix with columns from 2 to 129 will be used for the MMA operation,
due to the shift of 2.
Each of the tcgen05 operation has different requirements for the number of
threads/warps that needs to issue them.
The following table lists the execution granularity requirements of each of the
tcgen05 operation:
Table 55 Execution granularity requirements for tcgen05 operations
tcgen05 operation
.cta_group
Issue Granularity
.mma,.cp,.shift,.commit
::1
An issue from a single thread in the current
CTA would initiate the base operation.
::2
Issue from a single thread from the
CTA-Pair would initiate
the base operation.
When the current CTA issues the operation, the peer
CTA should be active and should not have exited.
.alloc,.dealloc,.relinquish_alloc_permit
::1
Issue from a single warp in the current CTA
would initiate the allocation management instruction.
::2
Issue from two warps, one in each of the current CTA
and its Peer CTA, in order to
collectively perform the operation, i.e., the first
warp to perform the operation could block until the
the second warp in the Peer CTA
also performs the operation (see examples below).
.ld,.st,.wait::{ld,st}
N/A
Issue from a warp in the current CTA can access only
1/4 of the Tensor Memory of the current CTA. So, a
warpgroup is needed to access the entire Tensor Memory
of the current CTA.
.fence::*
N/A
A thread needs to fence all its accesses to the tensor
memory that it wants to order with other accesses to
the tensor memory from other threads.
The following example shows that:
Before attempting to deallocate Tensor Memory, it suffices to ensure that there are no concurrent
Tensor Memory accesses from the Peer CTA.
Warps can immediately exit after deallocating Tensor Memory; no extra synchronization required.
Table 56 Example of deallocating Tensor Memory before CTA exit.
This example uses a cluster barrier for illustration purposes but in practice other
synchronization mechanisms are often used.
The following example illustrates a scenario in which the program exhibits non-deterministic
behavior due to incorrect synchronization because .dealloc may or may not block:
Table 57 Example of non-determinstic hang due to incorrect synchronization
Any 2 CTAs within the cluster whose %cluster_ctarank differs by the last bit only
is said to form a CTA pair.
Within a CTA pair, the CTA whose last bit in the %cluster_ctarank is:
0 is termed the even numbered CTA within the CTA pair.
1 is termed as the odd numbered CTA within the CTA pair.
Most of the tcgen05 operations can either execute at a single CTA level granularity OR
at a CTA pair level granularity. When a tcgen05 operation is performed at CTA pair
granularity, the Tensor Memory of both the CTAs within the CTA pair are accessed. The set
of threads that need to issue the tcgen05 operation is listed in the
Issue Granularity.
The peer CTA of the odd CTA within the CTA pair is the even CTA in the same pair.
Similarly, the peer CTA of the even CTA within the CTA pair is the odd CTA in the same pair.
9.7.18.6. Memory Consistency Model for 5th generation of TensorCore operations#
Ordering of tcgen05 instructions is described in terms of two key concepts:
The asynchronous tcgen05 operations may execute and complete in a different order than they
were issued. However, some specific pairs of the asynchronous tcgen05 instructions from the same
warp form tcgen05 pipelines, where in the two asynchronous operations are guaranteed to access
certain operands in tensor memory in the same order as the instructions that issued them. The specific
pairings are as follows:
Instructions tcgen05.commit and tcgen05.wait are implicitly pipelined with respect
to previously issued tcgen05.{mma,cp,shift} and tcgen05.{ld,st} instructions
respectively that they track from the same thread.
9.7.18.6.2.1.1. mbarrier based completion mechanism#
Completion of the following instruction’s asynchronous operations is observed
through the mbarrier based waiting mechanism:
tcgen05.mma
tcgen05.cp
tcgen05.shift
tcgen05.commit is used to track the completion of the above asynchronous instructions.
Following are the implicitly pipelined tcgen05 instruction pairing that uses mbarrier
based completion mechanism:
9.7.18.6.2.1.2. tcgen05.wait instruction based completion mechanism#
Completion of the following instruction’s asynchronous operations is observed through
tcgen05.wait based waiting mechanism:
tcgen05.ld
tcgen05.st
tcgen05.wait::ld and tcgen05.wait::st is used to track the completion of the
tcgen05.ld and tcgen05.st asynchronous instructions.
Following are the implicitly pipelined tcgen05 instruction pairing that uses
tcgen05.wait based completion mechanism:
tcgen05.ld -> tcgen05.wait::ld
tcgen05.st -> tcgen05.wait::st
9.7.18.6.3. Specialized Inter-thread Synchronization for tcgen05 instructions#
The tcgen05 instructions support a specialized inter-thread synchronization which are
optimized for tcgen05 family of instructions. The standard memory consistency model
synchronization mechanisms also apply to the tcgen05 family of instructions.
The tcgen05.fence::before_thread_sync and tcgen05.fence::after_thread_sync composes
with execution ordering instructions, like morally strong ld/st/atom instructions,
mbarrier instruction, barrier instructions and so on, to establish an ordering between
the tcgen05 operations across threads. The asynchronous tcgen05 instructions that are
ordered across threads in the same warp also form a tcgen05 pipeline.
An asynchronous tcgen05 operation prior to a tcgen05.fence::before_thread_sync is ordered
before all subsequent tcgen05 and the execution ordering operations.
An asynchronous tcgen05 operation subsequent to a tcgen05.fence::after_thread_sync is
ordered after all the prior tcgen05 and the execution ordering operations.
Using the above rules, the following are the five canonical synchronization patterns:
9.7.18.6.4.1. Pipelined instructions, same thread#
In this pattern, no explicit ordering mechanism is needed and the ordering guarantee is
provided by the pipelined instruction pairing.
Example:
tcgen05.cp (A matrix)
tcgen05.mma.cta_group::N (writes to D)
tcgen05.mma.cta_group::N (reads C, which is written by the previous instruction, using the same shape)
The two instructions will be executed in program order.
9.7.18.6.4.2. Non-pipelined instructions, same thread#
In this pattern, explicit waiting mechanisms are used to wait for the completion of the
asynchronous tcgen05 operations.
Example 1:
tcgen05.st
tcgen05.wait::st
tcgen05.ld
tcgen05.wait::st is used to wait for the completion of the prior asynchronous
instruction tcgen05.st.
For the completion of the asynchronous tcgen05.mma, tcgen05.commit is used.
As tcgen05.ld is an asynchronous operation, the instruction tcgen05.fence::after_thread_sync
is needed.
No explicit tcgen05.fence::before_thread_sync is needed as this is implicitly performed by
tcgen05.commit. The combination of tcgen05.mma and tcgen05.commit forms a
conceptual asynchronous pipeline and establishes execution ordering.
mbarrier.try_wait.relaxed.cluster// loop until successtcgen05.fence::after_thread_synctcgen05.mmabar.warp.sync0xfffffffftcgen05.mma.cta_group::N...,[a]
9.7.18.6.4.4. Non-pipelined instructions, different thread#
In this pattern, the producer threads that issue the asynchronous tcgen05 instructions
must explicitly wait for the instructions’ completion before synchronizing with the consumer threads.
For tcgen05.ld, an intra-thread ordering through true register dependency will be respected
regardless of the presence or absence of other forms of synchronization. This form of register
dependency does not imply any other form of ordering. For example, a register dependency does
not imply that a dependee instruction’s memory accesses will be performed before a dependent
instruction’s memory accesses. To enforce such memory orderings and avoiding anti-dependency
hazards around tcgen05.ld, tcgen05.wait::ld must be used.
The shared memory accesses by tcgen05.mma and tcgen05.cp operations are performed
asynchronously and via the asynchronous proxy (async proxy). These shared memory accesses
are not subject to the pipelining rules above.
Accessing the same memory location across multiple proxies needs a cross-proxy fence.
For the async proxy, fence.proxy.async should be used to synchronize memory between
generic proxy and the async proxy.
9.7.18.7. Tensor Memory Allocation and Management Instructions#
tcgen05.alloc is a blocking instruction which dynamically allocates
the specified number of columns in the Tensor Memory and writes
the address of the allocated Tensor Memory into shared memory
at the location specified by address operand dst. The tcgen05.alloc blocks if the
requested amount of Tensor Memory is not available and unblocks
as soon as the requested amount of Tensor Memory becomes
available for allocation.
tcgen05.dealloc is a potentially blocking instruction which deallocates the Tensor Memory
specified by the Tensor Memory address taddr. The operand
taddr must point to a previous Tensor Memory allocation.
If .cta_group::2 is specified,
issuing warp and peer CTA warp must synchronize Tensor Memory accesses
before attempting to collectively deallocate the Tensor Memory, and
tcgen05.dealloc may block to collectively performs the deallocation with
the other peer CTA’s warp.
All of the Tensor Memory that was allocated using tcgen05.alloc instruction in a kernel,
must be explicitly deallocated using tcgen05.dealloc before the kernel exits.
The unsigned 32-bit operand nCols specify the number of columns to be allocated or
de-allocated. The unit of allocation and de-allocation is 32 columns and all of lanes
per column. The number of columns allocated
should not increase between any two allocations in the execution order within the CTA.
If .exclusive is not specified, the operand nCols must be a power of 2, in the
range [32, 512].
If .exclusive is specified, nCols must be a multiple of 32, in the range [32, 512]
on target sm_100f, or the range [32, 576] on target sm_107f.
Table 58 nCols values for Non-exclusive and Exclusive allocation
Allocation Kind
nCols Minimum
nCols Maximum
nCols Modulus
nCols Popcount
Non-exclusive
32
512
32
= 1 (Power of two)
Exclusive (.exclusive)
sm_100, sm_103, sm_110 -> 512
sm_107 -> 576
(No restriction)
Instruction tcgen05.relinquish_alloc_permit specifies that the CTA of the executing
thread is relinquishing the right to allocate Tensor Memory. So,
it is illegal for a CTA to perform tcgen05.alloc after any of its constituent threads
execute tcgen05.relinquish_alloc_permit.
If no state space is specified then Generic Addressing is used.
If the address specified by dst does not fall within the address window of
.shared::cta state space then the behavior is undefined.
The optional .exclusive qualifier describes an effect on the allocation permit.
When .exclusive is not specified, the allocation is non-exclusive. The instruction uses
the allocation permit, but does not claim ownership of it. Multiple non-exclusive allocations
may exist simultaneously.
When .exclusive is specified, the allocation is exclusive. The instruction claims
ownership of the allocation permit. No other allocation may exist at the same time as an
exclusive allocation. An exclusive allocation typically occupies all Tensor Memory capacity,
but it may occupy less.
Memory must be deallocated with .exclusive if and only if it is allocated with
.exclusive.
Exclusive Allocation:
A tcgen05.alloc.exclusive operation makes an exclusive allocation, taking control of
Tensor Memory and of the allocation permit. This must be the only live allocation, until it is
deallocated with a corresponding tcgen05.dealloc.exclusive operation.
An exclusive allocation operation blocks until there is no other live allocation. Until the
sole live allocation is deallocated, no other CTA may allocate, whether exclusively or
nonexclusively. The sole allocation must be deallocated by a matching
tcgen05.dealloc.exclusive with the same number of columns, at which point the allocation
permit becomes available again.
An exclusive allocation operation may allocate a number of columns that is not a power of 2.
If .cta_group::1 is specified, ownership of the sole allocation is held by a single CTA.
If .cta_group::2 is specified, ownership is held jointly by both peer CTAs.
Qualifier .cta_group specifies the number of CTAs involved in the allocation and
de-allocation operation. When .cta_group::1 is specified, one warp from the CTA must
perform the allocation and de-allocation. When .cta_group::2 is specified, one warp
from each of the peer CTAs must collectively perform the allocation and
de-allocation. Refer to the Issue Granularity section.
When .cta_group::2 is specified, the issuing warp must make sure that peer CTA is launched
and its warps eventually participate in collective operations.
All tcgen05 instructions within a kernel must specify the same value for the .cta_group
qualifier.
The mandatory .sync qualifier indicates that the instruction causes the executing thread
to wait until all threads in the warp execute the same instruction before resuming execution.
The mandatory .aligned qualifier indicates that all threads in the warp must execute the
same instruction. In conditionally executed code, the instruction should only be used if it
is known that all threads in the warp evaluate the condition identically, otherwise behavior
is undefined.
The behavior of the instruction is undefined if all the threads in the warp do not use the
same values of nCols, or if any thread in the warp has exited.
The store operation in tcgen05.alloc is treated as a weak memory operation in the
Memory Consistency Model.
Examples
// Example 1: Non-exclusive allocation and deallocation for 1-CTA
tcgen05.alloc.cta_group::1.sync.aligned.shared::cta.b32 [sMemAddr1], 32;
ld.shared.b32 taddr, [sMemAddr1];
// use taddr …
// more allocations and its usages …
tcgen05.dealloc.cta_group::1.sync.aligned.b32 taddr, 32;
// more deallocations …
tcgen05.relinquish_alloc_permit.cta_group::1.sync.aligned;
// Example 2: Exclusive allocation and deallocation for 2-CTA
// Following instructions are performed by current warp and the warp in the peer-CTA:
tcgen05.alloc.cta_group::2.sync.aligned.shared::cta.b32 [sMemAddr2], 32;
ld.shared.b32 taddr, [sMemAddr2];
// use taddr …
// more allocations and its usages …
tcgen05.dealloc.cta_group::2.sync.aligned.b32 taddr, 32;
// more deallocations …
tcgen05.relinquish_alloc_permit.cta_group::2.sync.aligned;
// Example 3: Exclusive allocation and deallocation for 2-CTA
9.7.18.8. Tensor Memory and Register Load/Store Instructions#
The threads of the CTA can perform the loads and stores to the Tensor Memory
of the CTA and move data between registers and Tensor Memory. The loads and stores of data
can be performed in certain shapes as specified in the
Matrix and Data Movement Shape section.
Not all threads of the CTA can access the entire Tensor Memory via the tcgen05.ld and
tcgen05.st operations.
The Tensor Memory of a CTA is divided into 4 equal chunks such that each warp of a warpgroup
in the CTA can access a chunk of the Tensor Memory. All the columns of the Tensor Memory can
be accessed by all the four warps of a warpgroup. A lane of the Tensor Memory can be accessed
by a single warp in the warpgroup. The following table describes the access restriction.
Instruction tcgen05.ld asynchronously loads data from the Tensor Memory
at the location specified by the 32-bit address operand taddr into the destination
register r, collectively across all threads of the warps.
All the threads in the warp must specify the same value of taddr, which must be the
base address of the collective load operation. Otherwise, the behavior is undefined.
The .shape qualifier and the .num qualifier together determines the total
dimension of the data which is loaded from the Tensor Memory. The .shape
qualifier indicates the base dimension of data to be accessed as described in the
Data Movement Shape. The .num qualifier indicates
the repeat factor on the base dimension resulting in the total dimension of the data that
is accessed.
The shape .16x32bx2 performs two accesses into Tensor Memory of the shape .16x32b.
The base address of the first access is specified by taddr and the base address of the
second access is specified by taddr+immHalfSplitoff, where immHalfSplitoff is an
immediate argument.
The destination operand r is a brace-enclosed vector expression consisting of one
or more 32-bit registers as per the value of .shape and .num. The size of the
vector for various combinations of .num and .shape is shown in
Table 59.
Table 59 Various-combinations of .num and .shape
.num
.shape
.16x32bx2 / .16x64b / .32x32b
.16x128b
.16x256b
.x1
1
2
4
.x2
2
4
8
.x4
4
8
16
.x8
8
16
32
.x16
16
32
64
.x32
32
64
128
.x64
64
128
NA
.x128
128
NA
NA
The qualifier .red specifies that the reduction operation specified by .redOp is
performed on the data that is loaded across columns in each lane. The result of the
reduction operation is written into the corresponding thread’s 32-bit destination register
operand redVal. When .red qualifier is specified, .num modifier must be at least
.x2.
If .abs qualifier is specified, the absolute values of the loaded data are considered for
the reduction operation.
If .NaN qualifier is specified, the result of the reduction operation is canonical NaN if
either of the inputs to the reduction operation is NaN.
When the qualifier .spcompress is specified the instruction performs in-line
spcompress operation while loading the data
from the Tensor Memory. The compression factor is specified by the qualifier .spfactor.
The only allowed value for .spfactor is .sp::2:4 resulting in 2:4 compression for
the data loaded from the Tensor Memory. In this case, half of the data as read from the
Tensor Memory is stored to the vector operand cdata while corresponding metadata
information depicting indices for the chosen elements is stored in the vector operand mdata.
The size of each data element is given by .type and must be .f32. The size for the
resulting metadata index for each data element is given by .idxsize and must always be .b2.
The .rowop along with the optional .abs qualifier together specifies the criterion to
select the two elements per group of four elements. When the qualifier .red is specified
along with the .spcompress qualifier, the same .rowop along with the optional .abs
qualifier also specifies the reduction operator. However, note that in such cases, if .NaN
qualifier is specified, it is applicable only to the reduction part of the operation
(.red portion) and it does not apply to the spcompress
part of the operation.
This is because fundamentally spcompress
operation always preserves the NaN in the output.
The operands mdata, cdata are brace-enclosed vector expression consisting of one or more
.b32 registers. The expected vector size for each of the operand can be computed based on the
Table 60.
Table 60 Expected vector size for various operands
Operand
Vector Size
mdata
ceil(num/32)
cdata
num/2
The optional qualifier .pack::16b can be used to pack two 16-bit elements from adjacent
columns into a single 32-bit element during the load as shown in the section
Packing and Unpacking.
The mandatory .sync qualifier indicates that tcgen05.ld causes the executing thread
to wait until all threads in the warp execute the same tcgen05.ld instruction before
resuming execution.
The mandatory .aligned qualifier indicates that all threads in the warp must execute the
same tcgen05.ld instruction. In conditionally executed code, a tcgen05.ld instruction
should only be used if it is known that all threads in the warp evaluate the condition
identically, otherwise behavior is undefined.
The behavior of tcgen05.ld is undefined if all threads do not use the same values of taddr,
or if any thread in the warp has exited.
Instruction tcgen05.st asynchronously stores data from the source register r into
the Tensor Memory at the location specified by the 32-bit address operand taddr,
collectively across all threads of the warps.
All the threads in the warp must specify the same value of taddr, which must be the base
address of the collective store operation. Otherwise, the behavior is undefined.
The .shape qualifier and the .num qualifier together determines the total dimension
of the data which is stored to the Tensor Memory. The .shape qualifier indicates the base
dimension of data to be accessed as described in the
Data Movement Shape. The .num
qualifier indicates the repeat factor on the base dimension resulting in the total dimension of
the data that is accessed.
The shape .16x32bx2 performs two accesses into Tensor Memory of the shape .16x32b.
The base address of the first access is specified by taddr and the base address of the
second access is specified by taddr+immHalfSplitoff, where immHalfSplitoff is an
immediate argument.
The source operand r is a brace-enclosed vector expression consisting of one or more 32-bit
registers as per the value of .shape and .num. The size of the vector for various
combinations of .num and .shape is shown in Table 61.
Table 61 Various-combinations of .num and .shape
.num
.shape
.16x32bx2 / .16x64b / .32x32b
.16x128b
.16x256b
.x1
1
2
4
.x2
2
4
8
.x4
4
8
16
.x8
8
16
32
.x16
16
32
64
.x32
32
64
128
.x64
64
128
NA
.x128
128
NA
NA
The optional qualifier .unpack::16b can be used to unpack a 32-bit element in the
register into two 16-bit elements and store them in adjacent columns as shown in the
section Packing and Unpacking.
The mandatory .sync qualifier indicates that tcgen05.st causes the executing
thread to wait until all threads in the warp execute the same tcgen05.st instruction
before resuming execution.
The mandatory .aligned qualifier indicates that all threads in the warp must execute
the same tcgen05.st instruction. In conditionally executed code, a tcgen05.st
instruction should only be used if it is known that all threads in the warp evaluate
the condition identically, otherwise behavior is undefined.
The behavior of tcgen05.st is undefined if all threads do not use the same values of
taddr, or if any thread in the warp has exited.
Waits for the completion of all prior asynchronous tcgen05.ld / tcgen05.st instructions.
Syntax
tcgen05.wait_operation.sync.aligned;
.wait_operation = { .wait::ld, .wait::st }
Description
Instruction tcgen05.wait::st causes the executing thread to block until all prior
tcgen05.st operations issued by the executing thread have completed.
Instruction tcgen05.wait::ld causes the executing thread to block until all prior
tcgen05.ld operations issued by the executing thread have completed.
The mandatory .sync qualifier indicates that tcgen05.wait_operation causes the
executing thread to wait until all threads in the warp execute the same tcgen05.wait_operation
instruction before resuming execution.
The mandatory .aligned qualifier indicates that all threads in the warp must execute the
same tcgen05.wait_operation instruction.
Instruction tcgen05.cp initiates an asynchronous copy operation from shared memory to the
location specified by the address operand taddr in the Tensor Memory.
The 64-bit register operand s-desc is the matrix descriptor which represents the source
matrix in the shared memory that needs to be copied. The format of the matrix descriptor is
described in Matrix Descriptors.
The .shape qualifier indicates the dimension of data to be copied as described in the
Data Movement Shape.
Qualifier .cta_group specifies the number of CTAs whose Tensor Memory is
accessed when a single thread of a single CTA executes the tcgen05.cp instruction.
When .cta_group::1 is specified, the data is copied into the Tensor Memory
of the current CTA. A thread executing a tcgen05.cp instruction with .cta_group::2
causes both the current and peer CTA to copy data
from their shared memory to Tensor Memory.
All tcgen05 instructions within a kernel must specify the same value for the .cta_group
qualifier.
When the qualifiers .dst_fmt and .src_fmt are specified, the data is decompressed
from the source format .src_fmt in the shared memory to the destination format
.dst_fmt in Tensor Memory by the copy operation. The details of source
and the destination formats as specified in the section
Optional Decompression.
Some of the .shape qualifiers require certain .multicast qualifiers.
.64x128b requires .warpx2::02_13 or .warpx2::01_23
.32x128b requires .warpx4
When the .multicast qualifier is specified as either .warpx2::02_13 or
.warpx2::01_23 then the data being copied is multicasted into warp pairs and each
warp in the warp pair receive half of the data. Warp pairs are formed as follows:
.warpx2::02_13 : warps 0 and 2 form a pair; warps 1 and 3 form a pair.
.warpx2::01_23 : warps 0 and 1 form a pair; warps 2 and 3 form a pair.
When the .multicast modifier is specified as .warpx4 then the data being
copied is multicasted into all 4 warps.
Asynchronously shift down the rows of the matrix in the Tensor Memory for a warp.
Syntax
tcgen05.shift.cta_group.down [taddr];
.cta_group = { .cta_group::1, .cta_group::2 }
Description
Instruction tcgen05.shift is an asynchronous instruction which initiates the shifting of 32-byte
elements downwards across all the rows, except the last, by one row. The address operand taddr
specifies the base address of the matrix in the Tensor Memory whose rows must
be down shifted.
The lane of the address operand taddr must be aligned to 32.
Qualifier .cta_group specifies the number of CTAs whose Tensor Memory
is touched when a single thread of a single CTA executes the tcgen05.shift instruction.
When .cta_group::1 is specified, the shift operation is performed in the
Tensor Memory of the current CTA. When .cta_group::2 is specified,
the shift operation is performed in the Tensor Memory of both the current and the
peer CTAs.
All tcgen05 instructions within a kernel must specify the same value for the .cta_group
qualifier.
9.7.18.10. TensorCore 5th Generation Matrix Multiply and accumulate Operations#
The 5th generation of TensorCore operations of shape MxNxK perform matrix
multiplication and accumulation of the form:
D=A*B+D
where:
the A matrix has shape MxK, in either Tensor Memory or Shared Memory
the B matrix has shape KxN, in Shared Memory of the current CTA and optionally in peer CTA
the D matrix is of the shape MxN, in Tensor Memory
Optionally an input predicate can be used to disable the input from the accumulator
matrix and the following operation can be performed as
D=A*B
The matrix multiplication and accumulation operations are categorized into various kinds
based on input types and the throughput of the multiplication operation. The following shows the
different kinds of MMA operations that are supported:
f16 : supports f16 and bf16 input types.
tf32 : supports tf32 input types.
f8f6f4 : supports all input combinations of f8, f6 and f4 types.
i8 : supports signed and unsigned 8-bit integer input types.
mxf4nvf4 : supports mxf4 type and a custom NVIDIA floating-point
type for inputs where the type of the vector elements is 4 bits and requires a common
scaling factor to form the complete floating-point type, similar to other mx-types.
Optionally, the 5th generation of TensorCore MMAs support dense and sparse matrix A.
Sparse Matrices describes the details of the sparse matrices.
Some of the MMA-kinds requires scaling of input matrices from memory to form the matrix
A and matrix B before performing the MMA operation.
Block Scaling for tcgen05.mma describes the details of the scaling of matrices.
The following table show the various matrices involved in the MMA operations and the memory in
which they can reside:
Matrix Type
Memory
A
Tensor Memory OR Shared Memory
B
Shared Memory
D
Tensor Memory
SparseMetaData
A-Scale / B-Scale
B Lookup Metadata
Tensor Memory, needs B to
be in Shared Memory
A sequence of MMA instructions may reuse the same A matrix with a sequence of B
matrices or may reuse the same B matrix with a sequence of A matrices.
In these patterns the TensorCore may be able to load the unchanged matrix once and reuse
it through the sequence without multiple reloads. The A or B matrices are loaded
into a TensorCore collector buffer (i.e., special cache).
An MMA instruction has an optional collector qualifier to specify when an A or B
matrix is new to the sequence and should be loaded, unchanged within the sequence
and should be reused, or the last use in the sequence and should be discarded.
The collector qualifier is used to give the TensorCore permission to reuse a previously
loaded A or B matrix; however reuse is opportunistic in that the TensorCore may
reload a matrix even when it has permission to reuse that matrix. Thus, the source
memory of an A or B matrix must not be modified while the MMA instruction using those
matrices has not completed - regardless of collector qualifier permissions.
The 5th generation of TensorCore MMAs can be used for general matrix multiplication OR for
convolution operations. In case of convolutions, the activations can be stored in either
matrix A or matrix B while the weights will be stored in the other matrix.
The matrices A and B can be transposed by specifying the Transpose A Matrix
and Transpose B Matrix bits in the instruction descriptor respectively.
The elements of the matrices A and B can be negated by specifying the Negate
A Matrix and Negate B Matrix bits in the instruction descriptor respectively.
The support for Transpose and Negate operation for various MMA-Kind are shown in
Table 62.
Table 62 Transpose and Negate operation for various MMA-Kind
MMA-Kind
Is Transpose A/B supported
Is Negate A/B supported
.kind::tf32
Yes
Yes
.kind::f16
Yes
Yes
.kind::ti16
Yes
Yes
.kind::f8f6f4
No for matrix B with
decpmpress::lut::b
No for element types
E3M2, E2M3 and
E2M1 for Dense matrix
with K = 64
Yes for all other cases
Yes
.kind::mxf8f6f4
No for matrix B with
decpmpress::lut::b
No for element types
E3M2, E2M3 and
E2M1 for Dense matrix
with K = 64
Yes for all other cases
Yes
.kind::i8
Yes
No
.kind::mxf4
No
Yes
.kind::mxf4nvf4
No
Yes
For .kind::tf32, the transpose operations on matrices A and B are supported
only with 128B swizzling mode with 32B swizzle-atomicity.
For all other MMA-Kinds, the transpose operations on matrices A and B are not supported
on 128B swizzling mode with 32B swizzle-atomicity.
Table 63 shows the valid combinations of N shape with
.cta_group qualifier for 8bit transpose B.
Table 63 Various combinations of N shape with .cta_group qualifier for 8bit transpose B
9.7.18.10.3. Valid Combinations of Type-Size, Major-ness and Swizzling#
Table 65 Valid Combinations of Type-Size, Major-ness and Swizzling
Type-Size
Major-ness
Matrix
Supported Swizzle
4-bit,
6-bit,
8-bit,
16-bit,
32-bit
Row
A
All swizzling modes
Column
B
8-bit
16-bit
Column (transpose)
A
All except 128B
swizzling with 32B
atomicity
Row (transpose)
B
32-bit
Column (transpose)
A
Only 128B swizzling
with 32B atomicity
Row (transpose)
B
9.7.18.10.4. Packing formats of elements in Tensor and Shared memory#
9.7.18.10.4.1. Packing format for matrix D in Tensor Memory#
The sub-word elements of matrix D are expected not to be packed within a 32-bit Tensor Memory word.
For example, if the type of elements of the matrix D is 16 bits then a Tensor Memory word
would contain a single 16-bit element in its lower 16 bits.
The 6-bit and 4-bit floating point types have different packing format requirements for
different MMA kinds in both Tensor memory and Shared memory. The requirements are as follows.
9.7.18.10.4.3. Packing format used for matrix A by .kind::mxf8f6f4 in Tensor Memory#
The supported combination of the container size and the individual floating point type elements supports
are listed in Table 66
Table 66 Valid Combinations of Container size and floating point types
Individual floating point type
element
Container
size
Dense K dimension
(number of elements)
FP4
8-bits
32
FP6
6-bits
64
8-bits
(with 2-bits padding
in each byte)
32
FP8
8-bits
32
The 8-bit or 6-bit containers must be contiguously packed in a 32-bit Tensor
Memory word. For example, if the type of elements of the matrix A is 6 bits and uses 8-bit container
then 4 consecutive A elements should be packed in one 32-bit Tensor Memory word.
4-bit packing format in an 8-bit container as shown in Figure 202
The layouts which utilize only half the datapath lanes, i.e.,
Layout F and
Layout C, must use the same Tensor Memory
lane alignment across matrices A, D and the sparsity metadata matrix.
The following shows the warps that can access the Tensor Memory regions via
tcgen05.ld / tcgen05.st along with the addresses for various Tensor Memory Layouts.
If the bit TransposeAMatrix / TransposeBMatrix in the
Instruction descriptor is 0, then K-major is
used for matrix A / B respectively. If the bit TransposeAMatrix in the
Instruction descriptor is 1 then M-major is
used for matrix A. If the bit TransposeBMatrix in the
Instruction descriptor is 1, then N-major is
used for matrix B.
In a column-major default BLAS library such as cuBLAS, the matrices A and B with and
without transpose can be classified as either K-Major or M-or-N-Major as shown in the
following table:
Non-Transposed
Transposed
A
K-major
M-major
B
K-major
N-major
To avoid confusion with A, B, row-major, col-major, transpose, and
non-transpose, we will use MN-Major and K-Major throughout this section.
The matrices in the shared memory are made up of one or more “swizzle layout atom”.
The exact layout of these swizzle atoms depends on the swizzling mode, swizzle-atomicity,
and the leading dimension. The layout of the swizzle are shown in
Table 67
Table 67 Layout for swizzle atoms
Swizzling mode and
Swizzle-Atomicity
Leading
Dimension
Swizzle atom layout
(128b element)
128B Swizzling with
32B atomicity
M/N
8x4
–
–
128B Swizzling with
16B atomicity
M/N
8x8
K
8x8
64B Swizzling Mode
M/N
4x8
K
8x4
32B Swizzling Mode
M/N
2x8
K
8x2
None
M/N
1x8
K
8x1
The above shapes are for elements of size 128 bits. For smaller element sizes, the same shapes
would get multiplied along the leading dimension by a factor of 128/sizeof_bits(Element).
For example, 128B MN major swizzle atom would have a shape of (8*(128/32))x8 = 32x8 for
tf32 tensor core inputs.
The tcgen05.mma instructions with the following .kind qualifier:
.kind::mxf8f6f4
.kind::mxf4
.kind::mxf4nvf4
perform matrix multiplication with block scaling. This operation has the following form:
(A*scale_A)*(B*scale_B)+D
where scale_A and scale_B are matrices residing in Tensor Memory.
For a scale_A matrix of shape M x SFA_N, each row of matrix A is divided into
SFA_N number of chunks and each chunk of a row is multiplied with the corresponding
element in the SF_A of the same row.
Similarly, for a scale_B matrix of shape SFB_M x N, each column of matrix B is
divided into the SFB_M number of chunks and each chunk of a column is multiplied with
the corresponding element in the SF_B of the same column.
Scale factor for B matrix needs to be duplicated to all 32 lane partitions of tensor memory.
But for the A matrix, the duplication is not necessary if the scales are copied into Tensor Memory
via tcgen05.st on sm_107f architecture.
Figure 236 shows an example of tcgen05.mma with block scaling of
scale_vec::2X.
Figure 236 tcgen05.mma with block scaling of scale_vec::2X
9.7.18.10.7.1. Valid combinations of scale_vectorsize with types and MMA-Kind#
The shape of scale_A and scale_B matrices depend on the .scale_vectorsize as shown in
Table 68.
Table 68 Valid combinations of scale_vectorsize and shapes
.scale_vectorsize
.kind::*
K
Shape of scale_A
Shape of scale_B
.scale_vec::1X
.kind::mxf8f6f4
All supported values of K
M x 1
1 x N
.scale_vec::2X
.kind::mxf4,
.kind::mxf4nvf4
All supported values of K
M x 2
2 x N
.scale_vec::4X
.kind::mxf4nvf4
All supported values of K
M x 4
4 x N
.block16
.kind::mxf4nvf4
K = 96
M x 6
6 x N
K = 128
M x 8
8 x N
All supported values of K
except 96
M x 4
4 x N
.block32
.kind::mxf4,
.kind::mxf4nvf4
K = 96
M x 3
3 x N
K = 128
M x 4
4 x N
All supported values of K
except 96
M x 2
2 x N
.kind::mxf8f6f4
All supported values of K
M x 1
1 x N
The valid combination of the exact element types and the .scale_vectorsize are listed in
Table 69.
Table 69 Valid combinations of scale_vectorsize with types and MMA-Kind
The value of the scale factor AID selects the sub-columns in the Tensor Memory to
form the scale factor A matrix, which is used to scale the matrix A.
The following shows the scale factor matrix layout for various scale vector sizes:
9.7.18.10.7.2.1. Layout of the Scale Factor A Matrix for scale_vec::1X/block32 with K=32/K=64#
There is one scale factor per row of the A matrix with block size as 32 and the scale factor must be provided in
1-byte aligned sub-column of the Tensor Memory. SFA_ID specifies the byte offset in the
Tensor Memory word that must be used for the scale factor matrix.
Figure 237 shows which sub-columns get selected for
different values of SFA_ID.
Figure 237 Layout of scale factor A matrix with scale_vec::1X/block32 with K=32/K=64
For example, if SFA_ID is 0, then all the green columns are selected to form the scale factor
matrix. Similarly, SFA_ID values of 1, 2 and 3 would select the blue, yellow, and red columns,
respectively.
Figure 238 shows the scale factor A matrix layout
with 128 lanes which is supported on sm_107f architecture. Valid values of subp here are [0, 3];
Figure 238 Layout of scale factor A matrix with scale_vec::1X/block32 with K=32/K=64 with 128 lanes
9.7.18.10.7.2.2. Layout of the Scale Factor A Matrix for scale_vec::2X/block32 with K=64/K=128#
There are two scale factors per row of the A matrix with block size as 32 and the scale factor must be provided in
2-byte aligned sub-column of the Tensor Memory. SFA_ID specifies the half word offset in the
Tensor Memory word that must be used for the scale factor matrix.
Figure 239 shows which sub-columns get selected for different
values of SFA_ID.
Figure 239 Layout of scale factor A matrix with scale_vec::2X/block32 with K=64/K=128
For example, if SFA_ID is 0, then all the green columns are selected to form the scale factor
matrix. Similarly, if SFA_ID is 2, then all of the blue columns are selected to form the scale
factor matrix.
Figure 240 shows the scale factor A matrix layout
with 128 lanes which is supported on sm_107f architecture. Valid values of subp here are [0, 3];
Figure 240 Layout of scale factor A matrix with scale_vec::2X/block32 with K=64/K=128 with 128 lanes
9.7.18.10.7.2.3. Layout of the Scale Factor A Matrix for scale_vec::4X/block16 with K=64/K=128#
There are four scale factors per row of the A matrix with block size as 16 and the scale factor must be provided in
4-byte aligned sub-column of the Tensor Memory. The SFA_ID value must be 0 and this specifies
that all of the columns (in green) will be used for the scale factor matrix.
Figure 241 shows which sub-columns get selected for different
values of SFA_ID.
Figure 241 Layout of scale factor A matrix with scale_vec::4X/block16 with K=64/K=128
Figure 242 shows the scale factor A matrix layout
with 128 lanes which is supported on sm_107f architecture. Valid values of subp here are [0, 3];
Figure 242 Layout of scale factor A matrix with scale_vec::4X/block16 with K=64/K=128 with 128 lanes
9.7.18.10.7.2.4. Layout of the Scale Factor A Matrix for block32 with K=96 (Semantically equivalent to scale_vec::3X)#
There are three scale factors per row of the A matrix with block size as 32 and the scale
factor must be provided in 4-byte aligned sub-column of the Tensor Memory. SFA_ID specifies
the byte offset in the Tensor Memory word that must be used for the scale factor matrix.
Figure 243, Figure 244,
Figure 245 and Figure 246
show which sub-columns get selected for different values of SFA_ID.
Figure 243 Layout of scale factor A matrix with block32 with K=96 with SFA_ID=00
Figure 244 Layout of scale factor A matrix with block32 with K=96 with SFA_ID=01
Figure 245 Layout of scale factor A matrix with block32 with K=96 with SFA_ID=10
Figure 246 Layout of scale factor A matrix with block32 with K=96 with SFA_ID=11
For example, if SFA_ID is 0, then all the green columns are selected to form the scale factor
matrix. Similarly, SFA_ID values of 1, 2 and 3 would select the blue, yellow, and red columns,
respectively.
Figure 247, Figure 248,
Figure 249 and Figure 250
show the scale factor A matrix layout
with 128 lanes which is supported on sm_107f architecture. Valid values of subp here are [0, 3];
Figure 247 Layout of scale factor A matrix with block32 with K=96 with 128 lanes SFA_ID=00
Figure 248 Layout of scale factor A matrix with block32 with K=96 with 128 lanes SFA_ID=01
Figure 249 Layout of scale factor A matrix with block32 with K=96 with 128 lanes SFA_ID=10
Figure 250 Layout of scale factor A matrix with block32 with K=96 with 128 lanes SFA_ID=11
9.7.18.10.7.2.5. Layout of the Scale Factor A Matrix for block16 with K=96 (Semantically equivalent to scale_vec::6X)#
There are six scale factors per row of the A matrix with block size as 16 and the scale
factor must be provided in 4-byte aligned sub-column of the Tensor Memory. SFA_ID specifies
the byte offset in the Tensor Memory word that must be used for the scale factor matrix.
Figure 251 and Figure 252
show which sub-columns get selected for different values of SFA_ID.
Figure 251 Layout of scale factor A matrix with block16 with K=96 with SFA_ID=00
Figure 252 Layout of scale factor A matrix with block16 with K=96 with SFA_ID=10
For example, if SFA_ID is 0, then all the green columns are selected to form the scale factor
matrix. Similarly, if SFA_ID is 2, then all of the blue columns are selected to form the scale
factor matrix.
Figure 253 and Figure 254
show the scale factor A matrix layout
with 128 lanes which is supported on sm_107f architecture. Valid values of subp here are [0, 3];
Figure 253 Layout of scale factor A matrix with block16 with K=96 with 128 lanes with SFA_ID=00
Figure 254 Layout of scale factor A matrix with block16 with K=96 with 128 lanes with SFA_ID=10
9.7.18.10.7.2.6. Layout of the Scale Factor A Matrix for block16 with K=128/256 (Semantically equivalent to scale_vec::8X)#
There are eight scale factors per row of the A matrix with block size as 16 and the scale
factor must be provided in 4-byte aligned sub-column of the Tensor Memory. SFA_ID specifies
the byte offset in the Tensor Memory word that must be used for the scale factor matrix and must be 0.
Figure 255 shows which sub-columns get selected.
Figure 255 Layout of scale factor A matrix with block16 with K=128/256
Figure 256
shows the scale factor A matrix layout
with 128 lanes which is supported on sm_107f architecture. Valid values of subp here are [0, 3];
Figure 256 Layout of scale factor A matrix with block16 with K=128/256 with 128 lanes
The value of the scale factor BID selects the sub-columns in the Tensor Memory to
form the scale factor B matrix, which is used to scale the matrix B.
The following shows the scale factor matrix layout for various scale vector sizes:
9.7.18.10.7.3.1. Layout of the Scale Factor B Matrix for scale_vec::1X/block32 with K=32/K=64#
There is one scale factor per row of the B matrix with block size as 32 and the scale factor must be provided in
1-byte aligned sub-column of the Tensor Memory. SFB_ID specifies the byte offset in the
Tensor Memory word that must be used for the scale factor matrix.
Figure 257 shows which sub-columns get selected for
different values of SFB_ID.
Figure 257 Layout of scale factor B matrix with scale_vec::1X/block32 with K=32/K=64
For example, if SFB_ID is 0, then all the green columns are selected to form the scale factor
matrix. Similarly, SFB_ID values of 1, 2 and 3 would select the blue, yellow, and red columns, respectively.
9.7.18.10.7.3.2. Layout of the Scale Factor B Matrix for scale_vec::2X/block32 with K=64/K=128#
There are two scale factors per row of the B matrix with block size as 32 and the scale factor must be provided in
2-byte aligned sub-column of the Tensor Memory. SFB_ID specifies the half word offset in the
Tensor Memory word that must be used for the scale factor matrix.
Figure 258 shows which sub-columns get selected for
different values of SFB_ID.
Figure 258 Layout of scale factor B matrix with scale_vec::2X/block32 with K=64/K=128
For example, if SFB_ID is 0, then all the green columns are selected to form the scale factor
matrix. Similarly, if SFB_ID is 2, then all of the blue columns are selected to form the scale
factor matrix.
9.7.18.10.7.3.3. Layout of the Scale Factor B Matrix for scale_vec::4X/block16 with K=64/K=128#
There are four scale factors per row of the B matrix with block size as 16 and the scale factor must be provided in
4-byte aligned sub-column of the Tensor Memory. The SFB_ID value must be 0 and this specifies
that all of the columns (in green) will be used for the scale factor matrix.
Figure 259 shows which sub-columns get selected for
different values of SFB_ID.
Figure 259 Layout of scale factor B matrix with scale_vec::4X/block16 with K=64/K=128
9.7.18.10.7.3.4. Layout of the Scale Factor B Matrix for block32 with K=96 (Semantically equivalent to scale_vec::3X)#
There are three scale factors per row of the B matrix with block size as 32 and the scale factor
must be provided in 4-byte aligned sub-column of the Tensor Memory. SFB_ID specifies the byte
offset in the Tensor Memory word that must be used for the scale factor matrix.
Figure 264 Layout of scale factor B matrix with block32 with K=96 and N>128 with SFB_ID=00
Figure 265 Layout of scale factor B matrix with block32 with K=96 and N>128 with SFB_ID=01
Figure 266 Layout of scale factor B matrix with block32 with K=96 and N>128 with SFB_ID=10
Figure 267 Layout of scale factor B matrix with block32 with K=96 and N>128 with SFB_ID=10
Figure 268 Layout of scale factor B matrix with block32 with K=96 and N>128 with SFB_ID=11
Figure 269 Layout of scale factor B matrix with block32 with K=96 and N>128 with SFB_ID=11
For example, if SFB_ID is 0, then all the green columns are selected to form the
scale factor matrix. Similarly, SFB_ID values of 1, 2 and 3 would select the blue,
yellow, and red columns, respectively.
9.7.18.10.7.3.5. Layout of the Scale Factor B Matrix for block16 with K=96 (Semantically equivalent to scale_vec::6X)#
There are six scale factors per row of the B matrix with block size as 16 and the scale factor
must be provided in 4-byte aligned sub-column of the Tensor Memory. SFB_ID specifies the byte
offset in the Tensor Memory word that must be used for the scale factor matrix.
For N<=128, Figure 270 and
Figure 271 show which sub-columns
get selected for different values of SFB_ID.
Figure 270 Layout of scale factor B matrix with block16 with K=96 and N<=128 with SFB_ID=00
Figure 271 Layout of scale factor B matrix with block16 with K=96 and N<=128 with SFB_ID=10
Figure 272 Layout of scale factor B matrix with block16 with K=96 and N>128 with SFB_ID=00
Figure 273 Layout of scale factor B matrix with block16 with K=96 and N>128 with SFB_ID=00
Figure 274 Layout of scale factor B matrix with block16 with K=96 and N>128 with SFB_ID=10
Figure 275 Layout of scale factor B matrix with block16 with K=96 and N>128 with SFB_ID=10
For example, if SFB_ID is 0, then all the green columns are selected to form the
scale factor matrix. Similarly, if SFB_ID is 2, then all of the blue columns are
selected to form the scale factor matrix.
9.7.18.10.7.3.6. Layout of the Scale Factor B Matrix for block16 with K=128/256 (Semantically equivalent to scale_vec::8X)#
There are eight scale factors per row of the B matrix with block size as 16 and the scale factor
must be provided in 4-byte aligned sub-column of the Tensor Memory. SFB_ID specifies the byte
offset in the Tensor Memory word that must be used for the scale factor matrix.
For N<=128, Figure 276 shows which sub-columns
get selected for different values of SFB_ID.
Figure 276 Layout of scale factor B matrix with block16 with K=128/256 and N<=128 with SFB_ID=00
For N>128, Figure 277 and
Figure 278
show which sub-columns
get selected for different values of SFB_ID.
Figure 277 Layout of scale factor B matrix with block16 with K=128/256 and N>128 with SFB_ID=00
Figure 278 Layout of scale factor B matrix with block16 with K=128/256 and N>128 with SFB_ID=00
The tcgen05.mma instructions with the following .kind qualifier:
.kind::f8f6f4
.kind::mxf8f6f4
supports decompression of pre-compressed input matrix B.
The values of the matrix B reside in a lookup table in the
Tensor Memory and the input operand in the instruction points to a
compressed matrix which contains the indices into the lookup table.
Figure 279 shows the layout of Lookup
table stored in Tensor Memory.
Figure 279 Layout of Lookup table in Tensor Memory
B matrix of shape NxK is compressed as shown in Figure 280.
Figure 280 B matrix of NxK compressed for 8B LUT
Figure 281 shows how the compressed Matrix B is used in the matrix computation.
Figure 281 Matrix B usage in computation
Figure 282 shows the GMEM and TMEM layouts of the lookup table. The GMEM layout
shows 4 blocks of 128B such that each block contains 8 rows and 2 columns.
This instruction tcgen05.mma.sp can be used when the matrix A is a structured
sparse matrix with 50% zeros in each row distributed as per its sparse granularity.
In a MxNxK sparse tcgen05.mma.sp operation, the matrix A of shape MxK is
stored in a packed form as Mx(K/2) in memory. For each K-wide row of matrix A,
50% of elements are zeros and the remaining K/2 non-zero elements are stored in
memory. The metadata specifies the mapping of the K/2 non-zero elements to the K
elements before performing the MMA operation.
Granularity of sparse matrix A is defined as the ratio of the number of non-zero
elements in a sub-chunk of the matrix row to the total number of elements in that
sub-chunk where the size of the sub-chunk is shape-specific. The following table lists
the granularity of different tcgen05.mma.sp variants:
.kind of tcgen05.mma
Sparse Granularity
Sparsity Version
.kind::tf32
1:2
N/A
.kind::f16
2:4
.kind::ti16
.kind::f8f6f4
.kind::mxf8f6f4
.kind::i8
.kind::mxf4
4:8 (in pairs)
v0
2:4
v1
.kind::mxf4nvf4
4:8 (in pairs)
v0
2:4
v1
9.7.18.10.9.1. Sparse tcgen05.mma.sp with .kind::tf32#
For .kind::tf32, matrix A is structured sparse at a granularity of 1:2.
In other words, each chunk of two adjacent elements in a row of matrix A has one
zero and one non-zero element. Only the non-zero element is stored in memory and the
4-bit index in the metadata indicates the position of the non-zero element in the
two-wide chunk. The only meaningful values of the index are:
0b1110
0b0100
Rest of the values result in undefined behavior.
Figure 283 Sparse tcgen05.mma metadata example for tf32 kind
matrix A is structured sparse at a granularity of 2:4. In other words, each chunk
of four adjacent elements in a row of matrix A has two zero and two non-zero elements.
Only the non-zero elements are stored in memory and the two 2-bit indices in the metadata
indicates the position of the two non-zero elements in the four-wide chunk. The only
meaningful values of the index are:
0b0100
0b1000
0b1100
0b1001
0b1101
0b0110
0b1110
Figure 284 Sparse tcgen05.mma metadata example for f16/f8f6f4/mxf8f6f4 kind
9.7.18.10.9.3. Sparse tcgen05.mma.sp with .kind::mxf4 and .kind::mxf4nvf4#
The sparsity granularity for .kind::mxf4 and .kind::mxf4nvf4 is determined by
the SparsityVersion field (bit 12) of the Instruction descriptor:
SparsityVersionv0 (bit 12 = 0): Applicable to sm_100a, sm_103a, and
sm_110a. Matrix A is pair-wise structured sparse at a granularity of 4:8.
Each chunk of eight adjacent elements in a row has four zeros and four non-zero elements,
clustered in two-element sub-chunks. Only the four non-zero elements are stored in memory
and the two 2-bit indices in the metadata indicate the positions of the two non-zero
two-wide sub-chunks within the eight-wide chunk.
SparsityVersionv1 (bit 12 = 1): Applicable to sm_107a. Matrix A is
structured sparse at a granularity of 2:4. Each chunk of four adjacent elements in
a row has two zeros and two non-zero elements. Only the two non-zero elements are stored
in memory and the two 2-bit indices in the metadata indicate the positions of the two
non-zero elements within the four-wide chunk. The metadata format and valid index values
are the same as for .kind::mxf8f6f4 (see Sparse tcgen05.mma.sp with .kind::f16, .kind::f8f6f4, .kind::mxf8f6f4, .kind::i8, .kind::ti16).
The only meaningful values of the metadata index are:
0b0100
0b1000
0b1100
0b1001
0b1101
0b0110
0b1110
Rest of the values result in undefined behavior.
Note
Bit 12 of the instruction descriptor (SparsityVersion) must be set to v0 for
sm_100a, sm_103a, sm_110a and to v1 for sm_107a. Using the
wrong SparsityVersion results in undefined behavior. See Instruction descriptor
for details.
Figure 285 Sparse tcgen05.mma metadata example for mxf4 kind (SparsityVersion v0, 4:8)
Figure 286 Sparse tcgen05.mma metadata example for mxf4 kind (SparsityVersion v1, 2:4)
The value of the sparsity selector selects the sub-columns in the Tensor Memory
to form the sparsity metadata matrix, which is used with matrix A to form the
multiplicand matrix.
The following shows the sparse metadata matrix layout in Tensor Memory for various MMA variants:
9.7.18.10.9.4.1. Layout of the Sparsity Metadata Matrix for M = 64 for .kind::f16 , .kind::ti16#
Figure 287 shows which sub-columns get
selected for different values of Sparsity Selector.
Figure 287 Sparsity Metadata Layout for M = 64 for .kind::f16
9.7.18.10.9.4.2. Layout of the Sparsity Metadata Matrix for M = 128 / M = 256 for .kind::f16 , .kind::ti16#
Figure 288 shows which sub-columns get
selected for different values of Sparsity Selector.
Figure 288 Sparsity Metadata Layout for M = 128 / M = 256 for .kind::f16
9.7.18.10.9.4.3. Layout of the Sparsity Metadata Matrix for M = 64 for .kind::tf32#
Figure 289 shows which sub-columns get
selected for different values of Sparsity Selector.
Figure 289 Sparsity Metadata Layout for M = 64 for .kind::tf32
9.7.18.10.9.4.4. Layout of the Sparsity Metadata Matrix for M = 128 / M = 256 for .kind::tf32#
Figure 290 shows which sub-columns get
selected for different values of Sparsity Selector.
Figure 290 Sparsity Metadata Layout for M = 128 / M = 256 for .kind::tf32
9.7.18.10.9.4.5. Layout of the Sparsity Metadata Matrix for M = 64 for .kind::f8f6f4 , .kind::mxf8f6f4 , .kind::i8 , .kind::mxf4 , .kind::mxf4nvf4#
The value of the sparsity selector:
must be 0 for .kind::i8 and .kind::f8f6f4
is assumed to be 0 for .kind::mxf8f6f4, .kind::mxf4 and .kind::mxf4nvf4
and all of the columns are selected as
shown in Figure 291
Figure 291 Sparsity Metadata Layout for M = 64 for .kind::f8f6f4, .kind::mxf8f6f4, .kind::i8, .kind::mxf4, .kind::mxf4nvf4
9.7.18.10.9.4.6. Layout of the Sparsity Metadata Matrix for M = 128 / M = 256 for .kind::f8f6f4 , .kind::mxf8f6f4 , .kind::i8 , .kind::mxf4 , .kind::mxf4nvf4#
The value of the sparsity selector:
must be 0 for .kind::i8 and .kind::f8f6f4
is assumed to be 0 for .kind::mxf8f6f4, .kind::mxf4 and .kind::mxf4nvf4
and all of the columns are selected as
shown in Figure 292
Figure 292 Sparsity Metadata Layout for M = 128 / M = 256 for .kind::f8f6f4, .kind::mxf8f6f4, .kind::i8, .kind::mxf4, .kind::mxf4nvf4
The layouts which utilize only half the datapath lanes as specified in
Data Path Layout Organization,
i.e. Layout F and
Layout C, must use the same alignment
across matrices A, D and the sparsity metadata matrix.
9.7.18.10.10. TensorCore 5th Generation of MMA Instructions#
Instruction tcgen05.mma is an asynchronous instruction which initiates an MxNxK matrix
multiply and accumulate operation,
D=A*B+D
where the A matrix is MxK, the B matrix is KxN, and the D matrix is MxN.
The operation of the form
D=A*B
is issued when the input predicate argument enable-input-d is false.
The optional immediate argument scale-input-d can be specified to scale the input
matrix D as follows:
D=A*B+D*(2^-scale-input-d)
The valid range of values for argument scale-input-d is [0, 15]. The argument
scale-input-d is only valid for .kind::tf32 and .kind::f16.
The 32-bit register operand idesc is the instruction descriptor as described
in Instruction descriptor, specifies
the shapes, exact types, sparsity and other details of the input matrices,
output matrix and the matrix multiply and accumulate operation.
The qualifier .cta_group::1 specifies that the matrix multiply and
accumulate operation is performed on the Tensor Memory of the
executing thread’s CTA only. The qualifier .cta_group::2 specifies that the matrix
multiply and accumulate operation is performed on the Tensor Memory
of the executing thread’s CTA and its peer CTA.
All tcgen05 instructions within a kernel must specify the same value for the .cta_group
qualifier.
The instruction tcgen05.mma has single thread semantics, unlike the collective
instructions mma.sync or wgmma.mma_async. So, a single thread issuing the
tcgen05.mma will result in the initiation of the whole matrix multiply and
accumulate operation. Refer to the section Issue Granularity.
The qualifier .kind specifies the general kind of the element types of the multiplicand
matrices. The exact types of the elements of the input and output matrices for each MMA-kind
are specified in the Instruction descriptor.
The address operand d-tmem specifies the address of the destination and the accumulation
matrix D in the Tensor Memory. The address operand a-tmem
specifies the address of the matrix A in the Tensor Memory.
The 64-bit register operand a-desc and b-desc are the matrix descriptors which
represent the matrices A and B in shared memory respectively. The format of the
matrix descriptor is described in Matrix Descriptors.
For instruction with .decompress::lut::b qualifier, B matrix elements are obtained
from look-up-table. The 64 bit register operand b-compressed-desc
is the shared memory descriptor for B matrix and b-decompress-metadata is the two
column aligned address of the lookup table stored in Tensor Memory. Data loaded from shared
memory contains a 3-bit index for each element, which is used to index the lookup table to get
the 8 bit value. Every element in the same 8-column-aligned 8-column slice of the B matrix
shares the same set of 8 possible values to choose from. For example, the lookup table contains
8 unique values for the elements with N coordinates 0-7, another 8 unique values for the elements
with N coordinate 8-15 and so on. When .decompress::lut::b is specified, matrix B doesn’t
support transpose and the only type allowed is E4M3. Layout B (M = 128 + cta_group::2 + Dense A matrix),
Layout C (M = 128 + cta_group::2 + Sparse A matrix) and Layout F (M = 64 + non .ws mode) are not allowed for storing the
lookup tables in Tensor Memory.
The vector operand disable-output-lane specifies the lane(s) in the
Tensor Memory that should be not be updated with the resultant
matrix D. Elements of the vector operand disable-output-lane forms a mask where
each bit corresponds to a lane of the Tensor Memory, with least
significant bit of the first element of the vector (leftmost in syntax) corresponding
to the lane 0 of the Tensor Memory. If a bit in the mask is 1,
then the corresponding lane in the Tensor Memory for the resultant matrix D will not
be updated. The size of the vector is as follows:
.cta_group
Size of the vector disable-output-lane
::1
4
::2
8
Qualifier .block_scale specifies that the matrices A and B are scaled with
scale_A and scale_B matrices respectively before performing the matrix multiply
and accumulate operation as specified in the section Block Scaling for tcgen05.mma.
The address operand scale-A-tmem and scale-B-tmem specify the base address the
matrices scale_A and scale_B respectively in the Tensor Memory.
For qualifier .scale_vectorsize,
If .scale_vec::NX is specified: N specifies the number of columns in scale_A
matrix and number of rows in scale_B matrix.
If .blockN is specified: N specifies the block size for which single scale factor
will be applied. In this form, value of N is same as the K-dimension / (N of .scale_vec::NX).
Aliased .scale_vectorsize variants:
.block16 is aliased with:
.scale_vec::4X when .kind=.kind::mxf4nvf4 and K = 64 or 128
.block32 is aliased with:
.scale_vec::1X when .kind=.kind::mxf8f6f4 for all supported values of K
.scale_vec::2X when .kind=.kind::mxf4 or .kind::mxf4nvf4 and K = 64 or 128
The valid combinations of MMA-kind and .scale_vectorsize are
described in Table 68. For .kind::mxf4 when the qualifier
.scale_vectorsize is not specified, then it defaults to .block32. For .kind::mxf4nvf4,
the qualifier .scale_vectorsize must be explicitly specified.
The qualifier .ashift shifts the rows of the A matrix down by one row, except for
the last row in the Tensor Memory. Qualifier .ashift is only allowed
with M = 128 or M = 256.
The qualifier .collector_a_usage specifies the usage of collector buffer for matrix A.
The qualifier .collector_b_usage specifies the usage of collector buffer for matrix B.
Following collector buffer operations can be specified:
.collector_usage
Semantics
.collector::a::fill,
.collector::b::fill
Specified matrix read from the memory
should be filled in collector buffer.
.collector::a::use,
.collector::b::use
Specified matrix can be read from the
collector buffer. This requires a previous fill to
the collector buffer to be still valid.
.collector::a::lastuse,
.collector::b::lastuse
Specified matrix can be read from the
collector buffer and the contents of the collector
buffer can be discarded. This requires a previous
fill to the collector buffer to be valid till the
collector buffer is read.
.collector::a::discard,
.collector::b::discard
Contents of the collector buffer for the specified
matrix can be discarded.
If no .collector_a_usage qualifier is specified, then it defaults to .collector::a::discard.
If no .collector_b_usage qualifier is specified, then it defaults to .collector::b::discard.
It is illegal to specify either of .collector::a::use or .collector::a::fill along with
.ashift.
For .kind::mxf8f6f4 and .kind::f8f6f4 with dense K=64 and sparse K=128,
matrix A in shared memory can be transposed only for formats E5M2 and E4M3.
Instruction tcgen05.mma.sp is an asynchronous instruction which initiates an
MxNxK matrix multiply and accumulate operation of the form
D=A*B+D
where the A matrix is Mx(K/2), the B matrix is KxN, and the D matrix is MxN.
Sparse Matrices describes the details of the sparsity.
The operation of the form
D=A*B
is issued when the input predicate argument enable-input-d is false.
The optional immediate argument scale-input-d can be specified to scale the
input matrix D as follows:
D=A*B+D*(2^-scale-input-d)
The valid range of values for argument scale-input-d is [0, 15]. The argument
scale-input-d is only valid for .kind::tf32 and .kind::f16.
The 32-bit register operand idesc is the instruction descriptor as described in
Instruction descriptor, specifies the shapes,
exact types, sparsity and other details of the input matrices, output matrix and the
matrix multiply and accumulate operation.
The qualifier .cta_group::1 specifies that the matrix multiply and accumulate
operation is performed on the Tensor Memory of the executing
thread’s CTA only. The qualifier .cta_group::2 specifies that the matrix
multiply and accumulate operation is performed on the Tensor Memory
of the executing thread’s CTA and its peer CTA.
All tcgen05 instructions within a kernel must specify the same value for the .cta_group
qualifier.
The instruction tcgen05.mma.sp has single thread semantics, unlike the collective
instructions mma.sync or wgmma.mma_async. So, a single thread issuing the
tcgen05.mma.sp will result in the initiation of the whole matrix multiply and
accumulate operation. Refer to the section Issue Granularity.
The qualifier .kind specifies the general kind of the element types of the multiplicand
matrices. The exact types of the elements of the input and output matrices for each MMA-kind
are specified in the Instruction descriptor.
The address operand d-tmem specifies the address of the destination and the accumulation
matrix D in the Tensor Memory. The address operand a-tmem
specifies the address of the matrix A in the Tensor Memory. The
64-bit register operand a-desc and b-desc are the matrix descriptors which represent
the matrices A and B in shared memory respectively. The format of the matrix descriptor
is described in Matrix Descriptors.
The vector operand disable-output-lane specifies the lane(s) in the Tensor Memory
that should be not be updated with the resultant matrix D. Elements of the vector operand
disable-output-lane forms a mask where each bit corresponds to a lane of the
Tensor Memory. with least significant bit of the first element of
the vector (leftmost in syntax) corresponding to the lane 0 of the Tensor Memory. If a bit in
the mask is 1, then the corresponding lane in the Tensor Memory for the resultant matrix D
will not be updated. The size of the vector is as follows:
.cta_group
Size of the vector disable-output-lane
::1
4
::2
8
Qualifier .block_scale specifies that the matrices A and B are scaled with
scale_A and scale_B matrices respectively before performing the matrix multiply
and accumulate operation as specified in the section Block Scaling for tcgen05.mma.
The address operand scale-A-tmem and scale-B-tmem specify the base address the
matrices scale_A and scale_B respectively in the Tensor Memory.
For qualifier .scale_vectorsize,
If .scale_vec::NX is specified: N specifies the number of columns in scale_A
matrix and number of rows in scale_B matrix.
If .blockN is specified: N specifies the block size for which single scale factor
will be applied. In this form, value of N is same as the K-dimension / (N of .scale_vec::NX).
Aliased .scale_vectorsize variants:
.block16 is aliased with:
.scale_vec::4X when .kind=.kind::mxf4nvf4 and K = 64 or 128
.block32 is aliased with:
.scale_vec::1X when .kind=.kind::mxf8f6f4 for all supported values of K
.scale_vec::2X when .kind=.kind::mxf4 or .kind::mxf4nvf4 and K = 64 or 128
The valid combinations of MMA-kind and .scale_vectorsize are
described in Table 68. For .kind::mxf4 when the qualifier
.scale_vectorsize is not specified, then it defaults to .block32. For .kind::mxf4nvf4,
the qualifier .scale_vectorsize must be explicitly specified.
The qualifier .ashift shifts the rows of the A matrix down by one row, except for
the last row in the Tensor Memory. Qualifier .ashift is only allowed
with M = 128 or M = 256.
The qualifier .collector_a_usage specifies the usage of collector buffer for matrix A.
The qualifier .collector_b_usage specifies the usage of collector buffer for matrix B.
Following collector buffer operations can be specified:
.collector_usage
Semantics
.collector::a::fill,
.collector::b::fill
Specified matrix read from the memory
should be filled in collector buffer.
.collector::a::use,
.collector::b::use
Specified matrix can be read from the
collector buffer. This requires a previous fill to
the collector buffer to be still valid.
.collector::a::lastuse,
.collector::b::lastuse
Specified matrix can be read from the
collector buffer and the contents of the collector
buffer can be discarded. This requires a previous
fill to the collector buffer to be valid till the
collector buffer is read.
.collector::a::discard,
.collector::b::discard
Contents of the collector buffer for the specified
matrix can be discarded.
If no .collector_a_usage qualifier is specified, then it defaults to .collector::a::discard.
If no .collector_b_usage qualifier is specified, then it defaults to .collector::b::discard.
It is illegal to specify either of .collector::a::use or .collector::a::fill along with
.ashift.
Instruction tcgen05.mma.ws is an asynchronous instruction which initiates an MxNxK
matrix multiply and accumulate operation,
D=A*B+D
where the A matrix is MxK, the B matrix is KxN, and the D matrix is MxN.
The operation of the form
D=A*B
is issued when the input predicate argument enable-input-d is false.
The 32-bit register operand idesc is the instruction descriptor as described in
Instruction descriptor, specifies the shapes, exact
types, sparsity and other details of the input matrices, output matrix and the matrix
multiply and accumulate operation.
The qualifier .cta_group::1 specifies that the matrix multiply and accumulate operation
is performed on the Tensor Memory of the executing thread’s CTA only.
All tcgen05 instructions within a kernel must specify the same value for the .cta_group
qualifier.
The instruction tcgen05.mma.ws has single thread semantics, unlike the collective
instructions mma.sync or wgmma.mma_async. So, a single thread issuing the
tcgen05.mma.ws will result in the initiation of the whole matrix multiply and accumulate
operation. Refer to the section Issue Granularity.
The qualifier .kind specifies the general kind of the element types of the multiplicand
matrices. The exact types of the elements of the input and output matrices for each MMA-kind
are specified in the Instruction descriptor.
The address operand d-tmem specifies the address of the destination and the accumulation
matrix D in the Tensor Memory. The address operand a-tmem
specifies the address of the matrix A in the Tensor Memory. The
64-bit register operand a-desc and b-desc are the matrix descriptors which represent
the matrices A and B in shared memory respectively. The format of the matrix descriptor
is described in Matrix Descriptors.
The optional operand zero-column-mask-desc is a 64-bit register which specifies the
Zero-Column Mask Descriptor. The zero-column
mask descriptor is used to generate a mask that specifies which columns of B matrix
will have zero value for the matrix multiply and accumulate operation regardless of the
values present in the shared memory.
The qualifier .collector_usage specifies the usage of collector buffer for Matrix B.
Following collector buffer operations can be specified:
.collector_usage
Semantics
.collector::bN::fill
Specifies that the B matrix read from the memory
should be filled in collector buffer #N.
.collector::bN::use
Specifies that the B matrix can be read from the
collector buffer #N. This requires a previous fill
to the collector buffer #N to be still valid.
.collector::bN::lastuse
Specifies that the B matrix can be read from the
collector buffer #N after which the contents of the
collector buffer #N can be discarded. This requires
a previous fill to the collector buffer #N to be
valid till the collector buffer #N is read.
.collector::bN::discard
Specifies that the contents of the collector buffer
#N can be discarded.
If no .collector_usage qualifier is specified, then it defaults to .collector::b0::discard.
Instruction tcgen05.mma.ws.sp is an asynchronous instruction which initiates
an MxNxK matrix multiply and accumulate operation,
D=A*B+D
where the A matrix is Mx(K/2), the B matrix is KxN, and the D matrix
is MxN. Sparse Matrices describes the details of the
sparsity.
The operation of the form
D=A*B
is issued when the input predicate argument enable-input-d is false.
The 32-bit register operand idesc is the instruction descriptor as described in
Instruction descriptor, specifies the shapes, exact
types, sparsity and other details of the input matrices, output matrix and the matrix
multiply and accumulate operation.
The qualifier .cta_group::1 specifies that the matrix multiply and accumulate
operation is performed on the Tensor Memory of the executing thread’s CTA only.
All tcgen05 instructions within a kernel must specify the same value for the .cta_group
qualifier.
The instruction tcgen05.mma.ws.sp has single thread semantics, unlike the collective
instructions mma.sync or wgmma.mma_async. So, a single thread issuing the
tcgen05.mma.ws.sp will result in the initiation of the whole matrix multiply and
accumulate operation. Refer to the section Issue Granularity.
The qualifier .kind specifies the general kind of the element types of the multiplicand
matrices. The exact types of the elements of the input and output matrices for each MMA-kind are
specified in the Instruction descriptor.
The address operand d-tmem specifies the address of the destination and the accumulation
matrix D in the Tensor Memory. The address operand a-tmem specifies
the address of the matrix A in the Tensor Memory. The 64-bit register
operand a-desc and b-desc are the matrix descriptors which represent the matrices A
and B in shared memory respectively. The format of the matrix descriptor is described in
Matrix Descriptors.
The optional operand zero-column-mask-desc is a 64-bit register which specifies the
Zero-Column Mask Descriptor. The zero-column
mask descriptor is used to generate a mask that specifies which columns of B matrix
will have zero value for the matrix multiply and accumulate operation regardless of the
values present in the shared memory.
The qualifier .collector_usage specifies the usage of collector buffer for Matrix B.
Following collector buffer operations can be specified:
.collector_usage
Semantics
.collector::bN::fill
Specifies that the B matrix read from the memory
should be filled in collector buffer #N.
.collector::bN::use
Specifies that the B matrix can be read from the
collector buffer #N. This requires a previous fill
to the collector buffer #N to be still valid.
.collector::bN::lastuse
Specifies that the B matrix can be read from the
collector buffer #N after which the contents of the
collector buffer #N can be discarded. This requires
a previous fill to the collector buffer #N to be
valid till the collector buffer #N is read.
.collector::bN::discard
Specifies that the contents of the collector buffer
#N can be discarded.
If no .collector_usage qualifier is specified, then it defaults to .collector::b0::discard.
The instruction tcgen05.fence::before_thread_sync orders all the prior asynchronous
tcgen05 operations with respect to the subsequent tcgen05 and the execution
ordering operations.
The instruction tcgen05.fence::after_thread_sync orders all the subsequent asynchronous
tcgen05 operations with respect to the prior tcgen05 and the execution ordering
operations.
The tcgen05.fence::* instructions compose with execution ordering instructions across
a thread scope and provide ordering between tcgen05 instructions across the same scope.
The tcgen05.fence::before_thread_sync instructions behave as code motion fence for prior
tcgen05 instructions as they cannot be hoisted across. The tcgen05.fence::after_thread_sync
instructions behave as code motion fence for subsequent tcgen05 instructions as they cannot
be hoisted across.
The instruction tcgen05.commit is an asynchronous instruction which makes the mbarrier object,
specified by the address operand mbar, track the completion of all the prior asynchronous
tcgen05 operations, as listed in
mbarrier based completion mechanism,
initiated by the executing thread. Upon the completion of the tracked asynchronous tcgen05
operations, the signal specified by the .completion_mechanism is triggered by the system
on the mbarrier object.
This instruction accesses its mbarrier operand using generic-proxy.
The instruction tcgen05.commit.cta_group::1 tracks for the completion of all prior
asynchronous tcgen05 operations with .cta_group::1 issued by the current thread.
Similarly, the instruction tcgen05.commit.cta_group::2 tracks for the completion of all
prior asynchronous tcgen05 operations with .cta_group::2 issued by the current thread.
All tcgen05 instructions within a kernel must specify the same value for the .cta_group
qualifier.
The qualifier .mbarrier::arrive::one indicates that upon the completion of the prior
asynchronous tcgen05 operation issued by the current thread, an arrive-on operation, with
the count argument of 1, is signaled on the mbarrier object. The scope of the arrive-on operation
is the cluster scope.
The optional qualifier .multicast::cluster allows signaling on the mbarrier objects of multiple
CTAs in the cluster. Operand ctaMask specifies the CTAs in the cluster such that each bit
position in the 16-bit or otherwise 32-bit ctaMask operand corresponds to the %cluster_ctarank
of the destination CTA. The additional sub-qualifier ::16b or ::32b can be specified to correspond
to the width of the ctaMask argument. By default, ctaMask is assumed to be of 16-bit width.
The mbarrier signal is multicast to the same offset as mbar in the shared memory of each
destination CTA.
If no state space is specified then Generic Addressing is used. If the
address specified by mbar does not fall within the address window of .shared::cluster state
space then the behavior is undefined.
The tcgen05.commit operation with .sync_restrict::shared::read::mma::a performs an
arrive-on
operation on the barrier upon completion of read of A matrix from shared memory for all prior
tcgen05.mma operations. This does not signal the overall completion of any prior tcgen05.mma
operations.
Examples
Example 1:
tcgen05.cp.cta_group::1.128x256b [taddr0], sdesc0;
tcgen05.commit.cta_group::1.mbarrier::arrive::one.b64 [mbarObj1];
loop:
mbarrier.try_wait.parity.b64 p, [mbarObj1], 0;
@!p bra loop;
Example 2:
tcgen05.mma.cta_group::2.kind::tf32 [taddr0], adesc, bdesc, idesc, p;
tcgen05.commit.shared::cluster.multicast::cluster::32b.cta_group::2.mbarrier::arrive::one.b64 [mbarObj2];
loop:
mbarrier.try_wait.parity.b64 p, [mbarObj2], 0;
@!p bra loop;
Copies the current value of stack pointer into the destination register d. Pointer returned by
stacksave can be used in a subsequent stackrestore instruction to restore the stack
pointer. If d is modified prior to use in stackrestore instruction, it may corrupt data in
the stack.
Destination operand d has the same type as the instruction type.
Sets the current stack pointer to source register a.
When stackrestore is used with operand a written by a prior stacksave instruction, it
will effectively restore the state of stack as it was before stacksave was executed. Note that
if stackrestore is used with an arbitrary value of a, it may cause corruption of stack
pointer. This implies that the correct use of this feature requires that stackrestore.typea is
used after stacksave.typea without redefining the value of a between them.
Operand a has the same type as the instruction type.
Semantics
stackptr = a;
Examples
.reg .u32 ra;
stacksave.u32 ra;
// Code that may modify stack pointer
...
stackrestore.u32 ra;
The alloca instruction dynamically allocates memory on the stack frame of the current function
and updates the stack pointer accordingly. The returned pointer ptr points to local memory and
can be used in the address operand of ld.local and st.local instructions.
If sufficient memory is unavailable for allocation on the stack, then execution of alloca may
result in stack overflow. In such cases, attempting to access the allocated memory with ptr will
result in undefined program behavior.
The memory allocated by alloca is deallocated in the following ways:
It is automatically deallocated when the function exits.
It can be explicitly deallocated using stacksave and stackrestore instructions:
stacksave can be used to save the value of stack pointer before executing alloca, and
stackrestore can be used after alloca to restore stack pointer to the original value which
was previously saved with stacksave. Note that accessing deallocated memory after executing
stackrestore results in undefined behavior.
size is an unsigned value which specifies the amount of memory in number of bytes to be
allocated on stack. size=0 may not lead to a valid memory allocation.
Both ptr and size have the same type as the instruction type.
immAlign is a 32-bit value which specifies the alignment requirement in number of bytes for the
memory allocated by alloca. It is an integer constant, must be a power of 2 and must not exceed
2^23. immAlign is an optional argument with default value being 8 which is the minimum
guaranteed alignment.
Semantics
alloca.type ptr, size, immAlign:
a = max(immAlign, frame_align); // frame_align is the minimum guaranteed alignment
// Allocate size bytes of stack memory with alignment a and update the stack pointer.
// Since the stack grows down, the updated stack pointer contains a lower address.
stackptr = alloc_stack_mem(size, a);
// Return the new value of stack pointer as ptr. Since ptr is the lowest address of the memory
// allocated by alloca, the memory can be accessed using ptr up to (ptr + size of allocated memory).
stacksave ptr;
Examples
.reg .u32 ra, stackptr, ptr, size;
stacksave.u32 stackptr; // Save the current stack pointer
alloca ptr, size, 8; // Allocate stack memory
st.local.u32 [ptr], ra; // Use the allocated stack memory
stackrestore.u32 stackptr; // Deallocate memory by restoring the stack pointer
All video instructions operate on 32-bit register operands. However, the video instructions may be
classified as either scalar or SIMD based on whether their core operation applies to one or multiple
values.
The source and destination operands are all 32-bit registers. The type of each operand (.u32 or
.s32) is specified in the instruction type; all combinations of dtype, atype, and
btype are valid. Using the atype/btype and asel/bsel specifiers, the input values are
extracted and sign- or zero-extended internally to .s33 values. The primary operation is then
performed to produce an .s34 intermediate result. The sign of the intermediate result depends on
dtype.
The intermediate result is optionally clamped to the range of the destination type (signed or
unsigned), taking into account the subword destination size in the case of optional data merging.
This intermediate result is then optionally combined with the third source operand using a secondary
arithmetic operation or subword data merge, as shown in the following pseudocode. The sign of the
third operand is based on dtype.
Perform scalar arithmetic operation with optional saturate, and optional secondary arithmetic operation or subword data merge.
Semantics
// extract byte/half-word/word and sign- or zero-extend
// based on source operand type
ta = partSelectSignExtend( a, atype, asel );
tb = partSelectSignExtend( b, btype, bsel );
switch ( vop ) {
case vadd: tmp = ta + tb;
case vsub: tmp = ta - tb;
case vabsdiff: tmp = | ta - tb |;
case vmin: tmp = MIN( ta, tb );
case vmax: tmp = MAX( ta, tb );
}
// saturate, taking into account destination type and merge operations
tmp = optSaturate( tmp, sat, isSigned(dtype), dsel );
d = optSecondaryOp( op2, tmp, c ); // optional secondary operation
d = optMerge( dsel, tmp, c ); // optional merge with c operand
Shift a left by unsigned amount in b with optional saturate, and optional secondary
arithmetic operation or subword data merge. Left shift fills with zero.
vshr
Shift a right by unsigned amount in b with optional saturate, and optional secondary
arithmetic operation or subword data merge. Signed shift fills with the sign bit, unsigned shift
fills with zero.
Semantics
// extract byte/half-word/word and sign- or zero-extend
// based on source operand type
ta = partSelectSignExtend( a,atype, asel );
tb = partSelectSignExtend( b, .u32, bsel );
if ( mode == .clamp && tb > 32 ) tb = 32;
if ( mode == .wrap ) tb = tb & 0x1f;
switch ( vop ){
case vshl: tmp = ta << tb;
case vshr: tmp = ta >> tb;
}
// saturate, taking into account destination type and merge operations
tmp = optSaturate( tmp, sat, isSigned(dtype), dsel );
d = optSecondaryOp( op2, tmp, c ); // optional secondary operation
d = optMerge( dsel, tmp, c ); // optional merge with c operand
Calculate (a*b)+c, with optional operand negates, plus one mode, and scaling.
The source operands support optional negation with some restrictions. Although PTX syntax allows
separate negation of the a and b operands, internally this is represented as negation of the
product (a*b). That is, (a*b) is negated if and only if exactly one of a or b is
negated. PTX allows negation of either (a*b) or c.
The plus one mode (.po) computes (a*b)+c+1, which is used in computing averages. Source
operands may not be negated in .po mode.
The intermediate result of (a*b) is unsigned if atype and btype are unsigned and the product
(a*b) is not negated; otherwise, the intermediate result is signed. Input c has the same
sign as the intermediate result.
The final result is unsigned if the intermediate result is unsigned and c is not negated.
Depending on the sign of the a and b operands, and the operand negates, the following
combinations of operands are supported for VMAD:
(u32 * u32) + u32 // intermediate unsigned; final unsigned
-(u32 * u32) + s32 // intermediate signed; final signed
(u32 * u32) - u32 // intermediate unsigned; final signed
(u32 * s32) + s32 // intermediate signed; final signed
-(u32 * s32) + s32 // intermediate signed; final signed
(u32 * s32) - s32 // intermediate signed; final signed
(s32 * u32) + s32 // intermediate signed; final signed
-(s32 * u32) + s32 // intermediate signed; final signed
(s32 * u32) - s32 // intermediate signed; final signed
(s32 * s32) + s32 // intermediate signed; final signed
-(s32 * s32) + s32 // intermediate signed; final signed
(s32 * s32) - s32 // intermediate signed; final signed
The intermediate result is optionally scaled via right-shift; this result is sign-extended if the
final result is signed, and zero-extended otherwise.
The final result is optionally saturated to the appropriate 32-bit range based on the type (signed
or unsigned) of the final result.
Semantics
// extract byte/half-word/word and sign- or zero-extend
// based on source operand type
ta = partSelectSignExtend( a, atype, asel );
tb = partSelectSignExtend( b, btype, bsel );
signedFinal = isSigned(atype) || isSigned(btype) ||
(a.negate ^ b.negate) || c.negate;
tmp[127:0] = ta * tb;
lsb = 0;
if ( .po ) { lsb = 1; } else
if ( a.negate ^ b.negate ) { tmp = ~tmp; lsb = 1; } else
if ( c.negate ) { c = ~c; lsb = 1; }
c128[127:0] = (signedFinal) sext32( c ) : zext ( c );
tmp = tmp + c128 + lsb;
switch( scale ) {
case .shr7: result = (tmp >> 7) & 0xffffffffffffffff;
case .shr15: result = (tmp >> 15) & 0xffffffffffffffff;
}
if ( .sat ) {
if (signedFinal) result = CLAMP(result, S32_MAX, S32_MIN);
else result = CLAMP(result, U32_MAX, U32_MIN);
}
Compare input values using specified comparison, with optional secondary arithmetic operation or
subword data merge.
The intermediate result of the comparison is always unsigned, and therefore destination d and
operand c are also unsigned.
Semantics
// extract byte/half-word/word and sign- or zero-extend
// based on source operand type
ta = partSelectSignExtend( a, atype, asel );
tb = partSelectSignExtend( b, btype, bsel );
tmp = compare( ta, tb, cmp ) ? 1 : 0;
d = optSecondaryOp( op2, tmp, c ); // optional secondary operation
d = optMerge( dsel, tmp, c ); // optional merge with c operand
The SIMD video instructions operate on pairs of 16-bit values and quads of 8-bit values.
The SIMD video instructions are:
vadd2, vadd4
vsub2, vsub4
vavrg2, vavrg4
vabsdiff2, vabsdiff4
vmin2, vmin4
vmax2, vmax4
vset2, vset4
PTX includes SIMD video instructions for operation on pairs of 16-bit values and quads of 8-bit
values. The SIMD video instructions execute the following stages:
Form input vectors by extracting and sign- or zero-extending byte or half-word values from the
source operands, to form pairs of signed 17-bit values.
Perform a SIMD arithmetic operation on the input pairs.
Optionally clamp the result to the appropriate signed or unsigned range, as determinted by the
destination type.
Optionally perform one of the following:
perform a second SIMD merge operation, or
apply a scalar accumulate operation to reduce the intermediate SIMD results to a single
scalar.
The general format of dual half-word SIMD video instructions is as follows:
// 2-way SIMD operation, with second SIMD merge or accumulate
vop2.dtype.atype.btype{.sat}{.add} d{.mask}, a{.asel}, b{.bsel}, c;
The source and destination operands are all 32-bit registers. The type of each operand (.u32 or
.s32) is specified in the instruction type; all combinations of dtype, atype, and
btype are valid. Using the atype/btype and asel/bsel specifiers, the input values are
extracted and sign- or zero-extended internally to .s33 values. The primary operation is then
performed to produce an .s34 intermediate result. The sign of the intermediate result depends on
dtype.
The intermediate result is optionally clamped to the range of the destination type (signed or
unsigned), taking into account the subword destination size in the case of optional data merging.
vop2 = { vadd2, vsub2, vavrg2, vabsdiff2, vmin2, vmax2 };
.dtype = .atype = .btype = { .u32, .s32 };
.mask = { .h0, .h1, .h10 }; // defaults to .h10
.asel = .bsel = { .hxy, where x,y are from { 0, 1, 2, 3 } };
.asel defaults to .h10
.bsel defaults to .h32
Description
Two-way SIMD parallel arithmetic operation with secondary operation.
Elements of each dual half-word source to the operation are selected from any of the four half-words
in the two source operands a and b using the asel and bsel modifiers.
The selected half-words are then operated on in parallel.
The results are optionally clamped to the appropriate range determined by the destination type
(signed or unsigned). Saturation cannot be used with the secondary accumulate operation.
For instructions with a secondary SIMD merge operation:
For half-word positions indicated in mask, the selected half-word results are copied into
destination d. For all other positions, the corresponding half-word from source operand c
is copied to d.
For instructions with a secondary accumulate operation:
For half-word positions indicated in mask, the selected half-word results are added to operand
c, producing a result in d.
Semantics
// extract pairs of half-words and sign- or zero-extend
// based on operand type
Va = extractAndSignExt_2( a, b, .asel, .atype );
Vb = extractAndSignExt_2( a, b, .bsel, .btype );
Vc = extractAndSignExt_2( c );
for (i=0; i<2; i++) {
switch ( vop2 ) {
case vadd2: t[i] = Va[i] + Vb[i];
case vsub2: t[i] = Va[i] - Vb[i];
case vavrg2: if ( ( Va[i] + Vb[i] ) >= 0 ) {
t[i] = ( Va[i] + Vb[i] + 1 ) >> 1;
} else {
t[i] = ( Va[i] + Vb[i] ) >> 1;
}
case vabsdiff2: t[i] = | Va[i] - Vb[i] |;
case vmin2: t[i] = MIN( Va[i], Vb[i] );
case vmax2: t[i] = MAX( Va[i], Vb[i] );
}
if (.sat) {
if ( .dtype == .s32 ) t[i] = CLAMP( t[i], S16_MAX, S16_MIN );
else t[i] = CLAMP( t[i], U16_MAX, U16_MIN );
}
}
// secondary accumulate or SIMD merge
mask = extractMaskBits( .mask );
if (.add) {
d = c;
for (i=0; i<2; i++) { d += mask[i] ? t[i] : 0; }
} else {
d = 0;
for (i=0; i<2; i++) { d |= mask[i] ? t[i] : Vc[i]; }
}
.atype = .btype = { .u32, .s32 };
.cmp = { .eq, .ne, .lt, .le, .gt, .ge };
.mask = { .h0, .h1, .h10 }; // defaults to .h10
.asel = .bsel = { .hxy, where x,y are from { 0, 1, 2, 3 } };
.asel defaults to .h10
.bsel defaults to .h32
Description
Two-way SIMD parallel comparison with secondary operation.
Elements of each dual half-word source to the operation are selected from any of the four half-words
in the two source operands a and b using the asel and bsel modifiers.
The selected half-words are then compared in parallel.
The intermediate result of the comparison is always unsigned, and therefore the half-words of
destination d and operand c are also unsigned.
For instructions with a secondary SIMD merge operation:
For half-word positions indicated in mask, the selected half-word results are copied into
destination d. For all other positions, the corresponding half-word from source operand b
is copied to d.
For instructions with a secondary accumulate operation:
For half-word positions indicated in mask, the selected half-word results are added to operand
c, producing a result in d.
Semantics
// extract pairs of half-words and sign- or zero-extend
// based on operand type
Va = extractAndSignExt_2( a, b, .asel, .atype );
Vb = extractAndSignExt_2( a, b, .bsel, .btype );
Vc = extractAndSignExt_2( c );
for (i=0; i<2; i++) {
t[i] = compare( Va[i], Vb[i], .cmp ) ? 1 : 0;
}
// secondary accumulate or SIMD merge
mask = extractMaskBits( .mask );
if (.add) {
d = c;
for (i=0; i<2; i++) { d += mask[i] ? t[i] : 0; }
} else {
d = 0;
for (i=0; i<2; i++) { d |= mask[i] ? t[i] : Vc[i]; }
}
.dtype = .atype = .btype = { .u32, .s32 };
.mask = { .b0,
.b1, .b10
.b2, .b20, .b21, .b210,
.b3, .b30, .b31, .b310, .b32, .b320, .b321, .b3210 };
defaults to .b3210
.asel = .bsel = .bxyzw, where x,y,z,w are from { 0, …, 7 };
.asel defaults to .b3210
.bsel defaults to .b7654
Description
Four-way SIMD parallel arithmetic operation with secondary operation.
Elements of each quad byte source to the operation are selected from any of the eight bytes in the
two source operands a and b using the asel and bsel modifiers.
The selected bytes are then operated on in parallel.
The results are optionally clamped to the appropriate range determined by the destination type
(signed or unsigned). Saturation cannot be used with the secondary accumulate operation.
For instructions with a secondary SIMD merge operation:
For byte positions indicated in mask, the selected byte results are copied into destination
d. For all other positions, the corresponding byte from source operand c is copied to
d.
For instructions with a secondary accumulate operation:
For byte positions indicated in mask, the selected byte results are added to operand c,
producing a result in d.
Semantics
// extract quads of bytes and sign- or zero-extend
// based on operand type
Va = extractAndSignExt_4( a, b, .asel, .atype );
Vb = extractAndSignExt_4( a, b, .bsel, .btype );
Vc = extractAndSignExt_4( c );
for (i=0; i<4; i++) {
switch ( vop4 ) {
case vadd4: t[i] = Va[i] + Vb[i];
case vsub4: t[i] = Va[i] - Vb[i];
case vavrg4: if ( ( Va[i] + Vb[i] ) >= 0 ) {
t[i] = ( Va[i] + Vb[i] + 1 ) >> 1;
} else {
t[i] = ( Va[i] + Vb[i] ) >> 1;
}
case vabsdiff4: t[i] = | Va[i] - Vb[i] |;
case vmin4: t[i] = MIN( Va[i], Vb[i] );
case vmax4: t[i] = MAX( Va[i], Vb[i] );
}
if (.sat) {
if ( .dtype == .s32 ) t[i] = CLAMP( t[i], S8_MAX, S8_MIN );
else t[i] = CLAMP( t[i], U8_MAX, U8_MIN );
}
}
// secondary accumulate or SIMD merge
mask = extractMaskBits( .mask );
if (.add) {
d = c;
for (i=0; i<4; i++) { d += mask[i] ? t[i] : 0; }
} else {
d = 0;
for (i=0; i<4; i++) { d |= mask[i] ? t[i] : Vc[i]; }
}
Four-way SIMD parallel comparison with secondary operation.
Elements of each quad byte source to the operation are selected from any of the eight bytes in the
two source operands a and b using the asel and bsel modifiers.
The selected bytes are then compared in parallel.
The intermediate result of the comparison is always unsigned, and therefore the bytes of destination
d and operand c are also unsigned.
For instructions with a secondary SIMD merge operation:
For byte positions indicated in mask, the selected byte results are copied into destination
d. For all other positions, the corresponding byte from source operand b is copied to
d.
For instructions with a secondary accumulate operation:
For byte positions indicated in mask, the selected byte results are added to operand c,
producing a result in d.
Semantics
// extract quads of bytes and sign- or zero-extend
// based on operand type
Va = extractAndSignExt_4( a, b, .asel, .atype );
Vb = extractAndSignExt_4( a, b, .bsel, .btype );
Vc = extractAndSignExt_4( c );
for (i=0; i<4; i++) {
t[i] = compare( Va[i], Vb[i], cmp ) ? 1 : 0;
}
// secondary accumulate or SIMD merge
mask = extractMaskBits( .mask );
if (.add) {
d = c;
for (i=0; i<4; i++) { d += mask[i] ? t[i] : 0; }
} else {
d = 0;
for (i=0; i<4; i++) { d |= mask[i] ? t[i] : Vc[i]; }
}
Suspend the thread for an approximate delay given in nanoseconds.
Syntax
nanosleep.u32 t;
Description
Suspends the thread for a sleep duration approximately close to the delay t, specified in
nanoseconds. t may be a register or an immediate value.
The sleep duration is approximated, but guaranteed to be in the interval [0,2*t]. The maximum
sleep duration is 1 millisecond. The implementation may reduce the sleep duration for individual
threads within a warp such that all sleeping threads in the warp wake up together.
pmevent a; // trigger a single performance monitor event
pmevent.mask a; // trigger one or more performance monitor events
Description
Triggers one or more of a fixed number of performance monitor events, with event index or mask
specified by immediate operand a.
pmevent (without modifier .mask) triggers a single performance monitor event indexed by
immediate operand a, in the range 0..15.
pmevent.mask triggers one or more of the performance monitor events. Each bit in the 16-bit
immediate operand a controls an event.
Programmatic performance monitor events may be combined with other hardware events using Boolean
functions to increment one of the four performance counters. The relationship between events and
counters is programmed via API calls from the host.
Hint to change the number of registers owned by the warp.
Syntax
setmaxnreg.action.sync.aligned.u32 imm-reg-count;
.action = { .inc, .dec };
Description
setmaxnreg provides a hint to the system to update the maximum number of per-thread registers
owned by the executing warp to the value specified by the imm-reg-count operand.
Qualifier .dec is used to release extra registers such that the absolute per-thread maximum
register count is reduced from its current value to imm-reg-count. Qualifier .inc is used to
request additional registers such that the absolute per-thread maximum register count is increased
from its current value to imm-reg-count.
A pool of available registers is maintained per-CTA. Register adjustments requested by the
setmaxnreg instructions are handled by supplying extra registers from this pool to the
requesting warp or by releasing extra registers from the requesting warp to this pool, depending
upon the value of the .action qualifier.
The setmaxnreg.inc instruction blocks the execution until enough registers are available in the
CTA’s register pool. After the instruction setmaxnreg.inc obtains new registers from the CTA
pool, the initial contents of the new registers are undefined. The new registers must be initialized
before they are used.
The same setmaxnreg instruction must be executed by all warps in a
warpgroup. After executing a
setmaxnreg instruction, all warps in the warpgroup must synchronize explicitly before
executing subsequent setmaxnreg instructions. If a setmaxnreg instruction is not executed by all
warps in the warpgroup, then the behavior is undefined.
Operand imm-reg-count is an integer constant. The value of imm-reg-count must be in the
range 24 to 256 (both inclusive) and must be a multiple of 8.
Changes to the register file of the warp always happen at the tail-end of the register file.
The setmaxnreg instruction requires that the kernel has been launched with a valid value of
maximum number of per-thread registers specified via the appropriate compilation via the appropriate
compile-time option or the appropriate performance tuning directive. Otherwise, the setmaxnreg
instruction may have no effect.
When qualifier .dec is specified, the maximum number of per-thread registers owned by the warp
prior to the execution of setmaxnreg instruction should be greater than or equal to the
imm-reg-count. Otherwise, the behaviour is undefined.
When qualifier .inc is specified, the maximum number of per-thread registers owned by the warp
prior to the execution of setmaxnreg instruction should be less than or equal to the
imm-reg-count. Otherwise, the behaviour is undefined.
The mandatory .sync qualifier indicates that setmaxnreg instruction causes the executing
thread to wait until all threads in the warp execute the same setmaxnreg instruction before
resuming execution.
The mandatory .aligned qualifier indicates that all threads in the warpgroup must execute the
same setmaxnreg instruction. In conditionally executed code, setmaxnreg instruction should
only be used if it is known that all threads in warpgroup evaluate the condition identically,
otherwise the behavior is undefined.