4. Data Movement and Conversion#

4.1. addrcast#

Convert between specific and generic address spaces.

Notes:

The representation of generic address values is implementation-defined. However, casting an address from a specific address space to the generic address space and then casting it back to the original address space is guaranteed to preserve the value. Pointer arithmetic on the generic address behaves the same as on the original specific address, as long as the result stays in bounds.

Note

Casting a generic address in the .const address space must use addrcast.global.generic.

Warning

Behavior is undefined if the address space of src0 does not match the .from qualifier.

.reg .32b %paddr;
.reg .64b %gaddr;
.private .align 4 @A[8];

// convert generic address to private
addrcast.private.generic  %paddr, %gaddr;
// convert private address to generic
addrcast.generic.private  %gaddr, %paddr;
// convert private variable address to generic
addrcast.generic.private  %gaddr, @A;

4.2. addrof#

Compute the non-generic address of a source variable.

Semantics:

dst = &src0

Examples:

.import .function void @foo();
.reg .32b %dst;
.reg .64b %dst64;
.private @A[10];
.global @B[4];

// get 32-bit address of private variable
addrof.32b  %dst, @A;
// get 64-bit address of global variable
addrof.64b  %dst64, @B;
// get 64-bit address of function
addrof.64b  %dst64, @foo;

4.3. extract.dynamic#

Extract an element from a vector register using a dynamic index.

Semantics:

dst = src0[index]

Notes:

Warning

Behavior is undefined if the index is out of bounds for src0.

Examples:

.reg .v4.32b %src0;
.reg .32b %dst, %index;

// extract single element from %src0 at %index
extract.dynamic.v4.32b  %dst, %src0, %index;

4.4. extract#

Extract elements from a vector register.

Semantics:

for (i = 0; i < element_count(dst); i++) {
  dst[i] = src0[index + i]
}

Notes:

It is illegal to specify swizzle for dst or src0.

Examples:

.reg .v4.32b %src0;
.reg .32b %dst;
.reg .v2.32b %dstVec;

// extract single element from %src0 at index 1
extract.1.32b  %dst, %src0;
// extract 2 elements from %src0 at index 2
extract.2.v2.32b  %dstVec, %src0;

4.5. f2i#

Convert a floating-point value to an integer.

Semantics:

rnd = round(src0, .rndmode)
dst = type_convert(rnd, .to)

Notes:

If the resulting value (post-rounding) exceeds the range that can be represented by the integer type, the conversion result is clamped to the largest/smallest representable value. The conversion rules are summarized below, where Imax is the largest representable value by the integer type while Imin is the smallest representable value by the same type.

Floating-point to integer conversion (Signed)#

src0

dst

Floating-point Exception

qNaN

0

Invalid Operation

sNaN

0

Invalid Operation

+inf

Imax

Invalid Operation

f > Imax

Imax

Invalid Operation

Imin <= f <= Imax

in-range, representable signed integer i

Inexact if rounding changes f

f < Imin

Imin

Invalid Operation

-inf

Imin

Invalid Operation


Floating-point to integer conversion (Unsigned)#

src0

dst

Floating-point Exception

qNaN

0

Invalid Operation

sNaN

0

Invalid Operation

+inf

Imax

Invalid Operation

f > Imax

Imax

Invalid Operation

0 <= f <= Imax

in-range, representable unsigned integer i

Inexact if rounding changes f

-0

0

None

-1 < f < 0

0

Inexact if rounded result is zero

Invalid Operation if result is -1

-fmax <= f <= -1

0

Invalid Operation

-inf

0

Invalid Operation

Examples:

.reg .32b %dst, %src0;

// convert single-precision to signed 32bit integer
f2i.s32.f  %dst, %src0;
// convert single-precision to unsigned 32-bit integer with round-up rounding
f2i.u32.f.ru  %dst, %src0;

4.6. fext#

Extend a floating-point value to higher precision.

Semantics:

default#
dst = type_convert(src0, .to)

Notes:

Rules for extending special floating-point values#

Source Floating Point Value (hf, bf, f)

Destination Floating Point Result (f, df)

-inf

-inf

-finite

-finite

-denorm

-finite

-0

-0

+0

+0

+denorm

+finite

+finite

+finite

+inf

+inf

NaN

NaN

Examples:

.reg .32b %dst;
.reg .16b %src0;

// convert half-precision float to single-precision float
fext.f.hf  %dst, %src0;

4.7. frnd#

Round a floating-point number to the nearest integer.

Semantics:

dst = round(src0, .rndmode)

Examples:

.reg .32b %dst, %src0;

// round-to-even of single-precision element
frnd.re.f  %dst, %src0;

4.8. ftrunc#

Truncate a floating-point value to lower precision.

Semantics:

default#
dst = truncate(src0, .to)

Notes:

Enabling saturation via .dsat qualifier clamps the final result to between the min/max float values representable by .to type. When .dsat is not specified:

  • if source > maximum value of destination type, destination is set to +infinity

  • if source < minimum value of destination type, destination is set to -infinity

Rules for truncating special floating-point values#

Source Floating Point Value (f, df)

Destination Floating Point Result (hf, bf, f)

-inf

-inf

-finite

-finite/-denorm/-0

-denorm

-0

-0

-0

+0

+0

+denorm

+0

+finite

+finite/+denorm/+0

+inf

+inf

NaN

NaN

Examples:

.reg .32b %src0;
.reg .16b %dst;

// convert single-precision float to half-precision float
ftrunc.hf.f  %dst, %src0;
// convert single-precision float to half-precision float with rounding
ftrunc.hf.f.ru  %dst, %src0;

4.9. ftrunc2#

Truncate and pack two floating-point values into a packed vector.

Semantics:

.to == .hfx2#
ftrunc.hf.f dst[15:0], src0
ftrunc.hf.f dst[31:16], src1
.to == .bfx2#
ftrunc.bf.f dst[15:0], src0
ftrunc.bf.f dst[31:16], src1

Notes:

Enabling saturation via .dsat qualifier clamps the final result to between the min/max float values representable by .to type. When .dsat is not specified:

  • if source > maximum value of destination type, destination is set to +infinity

  • if source < minimum value of destination type, destination is set to -infinity

Examples:

.reg .32b %dst, %src0, %src1;

// truncate and pack 2 single-precision elements (dst must be .v2.16b)
.reg .v2.16b %dst_packed;
ftrunc2.hfx2  %dst_packed, %src0, %src1;

4.10. i2f#

Convert an integer to a floating-point value.

Semantics:

dst = type_convert(src0, .to)

Notes:

Enabling saturation via .dsat qualifier clamps the final result to between the min/max float values representable by .to type. When .dsat is not specified:

  • if source > maximum value of destination type, destination is set to +infinity

  • if source < minimum value of destination type, destination is set to -infinity

Examples:

.reg .16b %dst16, %src16;
.reg .32b %dst32, %src32;
.reg .64b %dst64, %src64;

// convert unsigned short to half-precision floating-point with implicit .re rounding
i2f.hf.u16  %dst16, %src16;
// convert signed short to single-precision floating-point with explicit rounding
i2f.f.s16.rd  %dst32, %src16;
// convert signed int to double-precision floating-point with explicit rounding and saturation
i2f.df.s32.rz.dsat  %dst64, %src32;

4.11. insert.dynamic#

Insert an element into a vector using a dynamic index.

Semantics:

dst[index] = src0

Notes:

Warning

Behavior is undefined if the index is out of bounds for dst.

Examples:

.reg .v4.32b %dst;
.reg .32b %src0, %index;

// insert single element at %index
insert.dynamic.v4.32b  %dst, %src0, %index;

4.12. insert#

Insert elements into a vector.

Semantics:

for (i = 0; i < element_count(src); i++) {
  dst[index + i] = src[i]
}

Notes:

It is illegal to specify swizzle for dst or src0.

Examples:

.reg .v4.32b %dst;
.reg .32b %src0;
.reg .v2.32b %srcVec;

// insert single element from %src0 at index 1
insert.1.32b  %dst, %src0;
// insert 2 elements from %srcVec at index 2
insert.2.v2.32b  %dst, %srcVec;

4.13. isaddr#

Check if a generic address belongs to a specific address space.

Semantics:

if get_address_space(src0) == .addrspace
   dst = ~0
else
   dst = 0

Examples:

.reg .32b %dst, %src0;
.reg .64b %gen;

// convert private address %src0 to generic address %gen
addrcast.generic.private %gen, %src0;
isaddr.private   %dst, %gen; // %r = ~0
isaddr.shared    %dst, %gen; // %r = 0

4.14. mov#

Move data between registers.

Semantics:

// return the start/end bit for reg.swizzle
getSwizzleBits(reg, swizzle) {
   w = bitwidth(reg)
   switch (swizzle) {
     case .x:     return {0, w - 1}
     case .y:     return {w, 2 * w - 1}
     case .z:     return {2 * w, 3 * w - 1}
     case .w:     return {3 * w, 4 * w - 1}
     case .xy:    return {0, 2 * w - 1}
     case .zw:    return {2 * w, 4 * w - 1}
     case .xyzw:  return {0, 4 * w - 1}
   }
}
dst is scalar, src0 is scalar#
dst = src0
dst is vector, src0 is scalar#
[D_S, D_E] = getSwizzleBits(dst, dst_swizzle)
dst[D_S, D_E] = src0
dst is scalar, src0 is vector#
[S_S, S_E] = getSwizzleBits(src, src_swizzle)
dst = src0[S_S, S_E]
dst is vector, src0 is vector#
[S_S, S_E] = getSwizzleBits(src, src_swizzle)
[D_S, D_E] = getSwizzleBits(dst, dst_swizzle)
dst[D_S, D_E] = src0[S_S, S_E]

Notes:

Number of bits being copied is specified by .type, and must match the bitwidth of a scalar variable and that of a vector variable after swizzle.

Examples:

.reg .32b %dst, %src0;
.reg .v2.32b %dstVec, %src0Vec;

// scalar to scalar move
mov.32b  %dst, %src0;
// scalar to vector move
mov.32b  %dstVec.x, %src0;
// vector to scalar move
mov.32b  %dst, %src0Vec.y;
// vector to vector move
mov.64b  %dstVec.xy, %src0Vec.xy;

4.15. pf2i#

Convert packed floats to packed integers.

Semantics:

dst[15:0] = type_convert(src0[15:0], element_type(.to))
dst[31:16] = type_convert(src0[31:16], element_type(.to))

Notes:

Each element independently converted following the rules specified in f2i instruction.

src0 holds a packed floating-point value (.hfx2 or .bfx2) and dst holds a packed integer value (.u16x2 or .s16x2). Both operands must be declared as .v2.16b registers (see packed types).

Examples:

.reg .v2.16b %dst_packed, %src_packed;

// conversion using .v2.16b register declarations
pf2i.s16x2.hfx2  %dst_packed, %src_packed;

4.16. sext#

Sign-extend an integer to a larger type.

Semantics:

dst = sign_extend(src0)

Examples:

.reg .32b %dst;
.reg .16b %src0;

// sign-extend 16-bit element
sext.32b.16b  %dst, %src0;

4.17. trunc#

Truncate an integer to a smaller type.

Semantics:

dst = truncate(src0, .to)

Examples:

.reg .32b %src0;
.reg .16b %dst;

// truncate 32-bit element
trunc.16b.32b  %dst, %src0;

4.18. zext#

Zero-extend an integer to a larger type.

Semantics:

dst = zero_extend(src0)

Examples:

.reg .32b %dst;
.reg .16b %src0;

// zero-extend 16-bit element
zext.32b.16b  %dst, %src0;