AMDGPU 指令操作数语法¶
约定¶
本文档通篇使用以下符号
符号
描述
{0..N}
0 到 N(包括 N)范围内的任何整数值。
<x>
x 的语法和含义在其他地方解释。
操作数¶
v (32 位)¶
向量寄存器。有 256 个 32 位向量寄存器。
可以使用一系列向量寄存器来操作超过 32 位的数据。
汇编器当前支持包含 1 到 12 个、16 个和 32 个向量寄存器的元组。
注意:N 和 K 必须满足以下条件
N <= K。
0 <= N <= 255。
0 <= K <= 255。
K-N+1 必须在 1 到 12 的范围内或等于 16 或 32。
GFX90A 和 GFX942 具有额外的对齐要求:向量寄存器对必须是偶数对齐的(第一个寄存器必须是偶数)。
示例
v255
v[0]
v[0:1]
v[1:1]
v[0:3]
v[2*2]
v[1-1:2-1]
[v252]
[v252,v253,v254,v255]
非顺序地址 (NSA) 语法
GFX10+ image 指令可以为图像地址使用特殊的 NSA(非顺序地址)语法
语法
描述
[Vm, Vn, … Vk]
32 位向量寄存器的序列。每个寄存器可以使用上述定义的语法指定。
与标准语法相反,NSA 序列中的寄存器不需要具有连续的索引。此外,同一寄存器可以在序列中出现多次。
GFX11+ 具有额外的限制:如果地址大小超过 5 个 dword,则从第 5 个元素开始的寄存器必须是连续的。
示例
[v32,v1,v[2]]
[v[32],v[1:1],[v2]]
[v4,v4,v4,v4]
v (16 位)¶
16 位向量寄存器。每个32 位向量寄存器分为两个 16 位低位和高位寄存器,因此有 512 个 16 位向量寄存器。
只有 VOP3、VOP3P 和 VINTERP 指令可以访问所有 512 个寄存器(使用op_sel修饰符)。VOP1、VOP2 和 VOPC 指令目前只能使用下面描述的语法访问 128 个低位 16 位寄存器。
警告
本节尚不完整。汇编器中对 16 位寄存器的支持仍在 WIP 中。
语法
描述
v<N>
单个 16 位向量寄存器(低半部分)。
注意:N 必须满足以下条件
0 <= N <= 127。
示例
v127
a¶
累加器寄存器。有 256 个 32 位累加器寄存器。
可以使用一系列累加器寄存器来操作超过 32 位的数据。
汇编器当前支持包含 1 到 12 个、16 个和 32 个累加器寄存器的元组。
注意:N 和 K 必须满足以下条件
N <= K。
0 <= N <= 255。
0 <= K <= 255。
K-N+1 必须在 1 到 12 的范围内或等于 16 或 32。
GFX90A 和 GFX942 具有额外的对齐要求:累加器寄存器对必须是偶数对齐的(第一个寄存器必须是偶数)。
示例
a255
a[0]
a[0:1]
a[1:1]
a[0:3]
a[2*2]
a[1-1:2-1]
[a252]
[a252,a253,a254,a255]
acc0
acc[1]
[acc250]
[acc2,acc3]
s¶
标量 32 位寄存器。可用标量寄存器的数量取决于 GPU
GPU
标量寄存器的数量
GFX7
104
GFX8
102
GFX9
102
GFX10+
106
可以使用一系列标量寄存器来操作超过 32 位的数据。汇编器当前支持包含 1 到 12 个、16 个和 32 个标量寄存器的元组。
标量寄存器对必须是偶数对齐的(第一个寄存器必须是偶数)。4 个或更多标量寄存器的序列必须是四字对齐的。
注意:N 和 K 必须满足以下条件
N 必须根据序列大小正确对齐。
N <= K。
0 <= N < SMAX,其中 SMAX 是可用标量寄存器的数量。
0 <= K < SMAX,其中 SMAX 是可用标量寄存器的数量。
K-N+1 必须在 1 到 12 的范围内或等于 16 或 32。
示例
s0
s[0]
s[0:1]
s[1:1]
s[0:3]
s[2*2]
s[1-1:2-1]
[s4]
[s4,s5,s6,s7]
无效对齐的标量寄存器示例
s[1:2]
s[2:5]
trap¶
一组陷阱处理程序寄存器
ttmp¶
陷阱处理程序临时标量寄存器,32 位宽。可用 ttmp 寄存器的数量取决于 GPU
GPU
ttmp 寄存器的数量
GFX7
12
GFX8
12
GFX9
16
GFX10+
16
可以使用一系列 ttmp 寄存器来操作超过 32 位的数据。汇编器当前支持包含 1 到 12 个和 16 个 ttmp 寄存器的元组。
ttmp 寄存器对必须是偶数对齐的(第一个寄存器必须是偶数)。4 个或更多 ttmp 寄存器的序列必须是四字对齐的。
注意:N 和 K 必须满足以下条件
N 必须根据序列大小正确对齐。
N <= K。
0 <= N < TMAX,其中 TMAX 是可用 ttmp 寄存器的数量。
0 <= K < TMAX,其中 TMAX 是可用 ttmp 寄存器的数量。
K-N+1 必须在 1 到 12 的范围内或等于 16。
示例
ttmp0
ttmp[0]
ttmp[0:1]
ttmp[1:1]
ttmp[0:3]
ttmp[2*2]
ttmp[1-1:2-1]
[ttmp4]
[ttmp4,ttmp5,ttmp6,ttmp7]
无效对齐的 ttmp 寄存器示例
ttmp[1:2]
ttmp[2:5]
tba¶
陷阱基地址,64 位宽。保存指向当前陷阱处理程序程序的指针。
语法
描述
可用性
tba
64 位陷阱基地址寄存器。
GFX7、GFX8
[tba]
64 位陷阱基地址寄存器(SP3 语法)。
GFX7、GFX8
[tba_lo,tba_hi]
64 位陷阱基地址寄存器(SP3 语法)。
GFX7、GFX8
陷阱基地址的高 32 位和低 32 位可以作为单独的寄存器访问
语法
描述
可用性
tba_lo
陷阱基地址寄存器的低 32 位。
GFX7、GFX8
tba_hi
陷阱基地址寄存器的高 32 位。
GFX7、GFX8
[tba_lo]
陷阱基地址寄存器的低 32 位(SP3 语法)。
GFX7、GFX8
[tba_hi]
陷阱基地址寄存器的高 32 位(SP3 语法)。
GFX7、GFX8
tma¶
陷阱内存地址,64 位宽。
语法
描述
可用性
tma
64 位陷阱内存地址寄存器。
GFX7、GFX8
[tma]
64 位陷阱内存地址寄存器(SP3 语法)。
GFX7、GFX8
[tma_lo,tma_hi]
64 位陷阱内存地址寄存器(SP3 语法)。
GFX7、GFX8
陷阱内存地址的高 32 位和低 32 位可以作为单独的寄存器访问
语法
描述
可用性
tma_lo
陷阱内存地址寄存器的低 32 位。
GFX7、GFX8
tma_hi
陷阱内存地址寄存器的高 32 位。
GFX7、GFX8
[tma_lo]
陷阱内存地址寄存器的低 32 位(SP3 语法)。
GFX7、GFX8
[tma_hi]
陷阱内存地址寄存器的高 32 位(SP3 语法)。
GFX7、GFX8
flat_scratch¶
平面暂存地址,64 位宽。保存暂存内存的基地址。
语法
描述
flat_scratch
64 位平面暂存地址寄存器。
[flat_scratch]
64 位平面暂存地址寄存器(SP3 语法)。
[flat_scratch_lo,flat_scratch_hi]
64 位平面暂存地址寄存器(SP3 语法)。
平面暂存地址的高 32 位和低 32 位可以作为单独的寄存器访问
语法
描述
flat_scratch_lo
平面暂存地址寄存器的低 32 位。
flat_scratch_hi
平面暂存地址寄存器的高 32 位。
[flat_scratch_lo]
平面暂存地址寄存器的低 32 位(SP3 语法)。
[flat_scratch_hi]
平面暂存地址寄存器的高 32 位(SP3 语法)。
xnack_mask¶
Xnack 掩码,64 位宽。保存 64 位掩码,指示哪些线程由于向量内存操作而收到 XNACK。
有关 xnack 功能的可用性,请参阅此表。
语法
描述
xnack_mask
64 位 xnack 掩码寄存器。
[xnack_mask]
64 位 xnack 掩码寄存器(SP3 语法)。
[xnack_mask_lo,xnack_mask_hi]
64 位 xnack 掩码寄存器(SP3 语法)。
xnack 掩码的高 32 位和低 32 位可以作为单独的寄存器访问
语法
描述
xnack_mask_lo
xnack 掩码寄存器的低 32 位。
xnack_mask_hi
xnack 掩码寄存器的高 32 位。
[xnack_mask_lo]
xnack 掩码寄存器的低 32 位(SP3 语法)。
[xnack_mask_hi]
xnack 掩码寄存器的高 32 位(SP3 语法)。
vcc¶
向量条件代码,64 位宽。每个线程一位的位掩码;它保存向量比较操作的结果。
请注意,GFX10+ H/W 在 wave32 模式下不使用 vcc 的高 32 位。
语法
描述
vcc
64 位向量条件代码寄存器。
[vcc]
64 位向量条件代码寄存器(SP3 语法)。
[vcc_lo,vcc_hi]
64 位向量条件代码寄存器(SP3 语法)。
向量条件代码的高 32 位和低 32 位可以作为单独的寄存器访问
语法
描述
vcc_lo
向量条件代码寄存器的低 32 位。
vcc_hi
向量条件代码寄存器的高 32 位。
[vcc_lo]
向量条件代码寄存器的低 32 位(SP3 语法)。
[vcc_hi]
向量条件代码寄存器的高 32 位(SP3 语法)。
m0¶
32 位内存寄存器。它有多种用途,包括寄存器索引和边界检查。
语法
描述
m0
32 位内存寄存器。
[m0]
32 位内存寄存器(SP3 语法)。
exec¶
执行掩码,64 位宽。每个线程一位的位掩码,应用于向量指令,控制哪些线程执行指令,哪些线程忽略指令。
请注意,GFX10+ H/W 在 wave32 模式下不使用 exec 的高 32 位。
语法
描述
exec
64 位执行掩码寄存器。
[exec]
64 位执行掩码寄存器(SP3 语法)。
[exec_lo,exec_hi]
64 位执行掩码寄存器(SP3 语法)。
执行掩码的高 32 位和低 32 位可以作为单独的寄存器访问
语法
描述
exec_lo
执行掩码寄存器的低 32 位。
exec_hi
执行掩码寄存器的高 32 位。
[exec_lo]
执行掩码寄存器的低 32 位(SP3 语法)。
[exec_hi]
执行掩码寄存器的高 32 位(SP3 语法)。
vccz¶
单个位标志,指示vcc全为零。
注意:当 GFX10+ 在 wave32 模式下运行时,此寄存器反映vcc_lo的状态。
execz¶
单个位标志,指示exec全为零。
注意:当 GFX10+ 在 wave32 模式下运行时,此寄存器反映exec_lo的状态。
scc¶
单个位标志,指示标量比较操作的结果。
lds_direct¶
特殊操作数,提供使用m0作为地址从 LDS 内存中获取的 32 位值。
null¶
这是一个特殊的操作数,可以用作源操作数或目标操作数。
当用作目标操作数时,操作结果将被丢弃。
当用作源操作数时,它提供零值。
内联常量¶
内联常量是编码为指令一部分的整数或浮点值。将内联常量与字面量进行比较。
内联常量包括
如果一个数字可以编码为字面量或常量,则汇编器会选择后一种编码,因为它更有效。
iconst¶
只有一小部分整数可以编码为内联常量。它们在下表中列出。其他整数编码为字面量。
值
注意
{0..64}
正整数内联常量。
{-16..-1}
负整数内联常量。
fconst¶
编码为内联常量的浮点数。
只有一小部分浮点数可以编码为内联常量。它们在下表中列出。其他浮点数编码为字面量。
值
注意
可用性
0.0
与整数常量 0 相同。
所有 GPU
0.5
浮点常量 0.5
所有 GPU
1.0
浮点常量 1.0
所有 GPU
2.0
浮点常量 2.0
所有 GPU
4.0
浮点常量 4.0
所有 GPU
-0.5
浮点常量 -0.5
所有 GPU
-1.0
浮点常量 -1.0
所有 GPU
-2.0
浮点常量 -2.0
所有 GPU
-4.0
浮点常量 -4.0
所有 GPU
0.1592
1.0/(2.0*pi)。仅用于 16 位操作数。
GFX8+
0.15915494
1.0/(2.0*pi)。仅用于 16 位和 32 位操作数。
GFX8+
0.15915494309189532
1.0/(2.0*pi)。
GFX8+
警告
浮点内联常量不能与 16 位整数操作数一起使用。汇编器将这些值编码为字面量。
ival¶
编码为内联常量的符号操作数。这些操作数提供对 H/W 寄存器的只读访问。
语法
替代语法 (SP3)
注意
可用性
shared_base
src_shared_base
共享内存区域的基地址。
GFX9+
shared_limit
src_shared_limit
共享内存区域末尾的地址。
GFX9+
private_base
src_private_base
私有内存区域的基地址。
GFX9+
private_limit
src_private_limit
私有内存区域末尾的地址。
GFX9+
pops_exiting_wave_id
src_pops_exiting_wave_id
POPS 的专用计数器。
GFX9、GFX10
literal¶
字面量是一个 64 位值,编码为指令流中单独的 32 位 dword。将字面量与内联常量进行比较。
如果一个数字可以编码为字面量或内联常量,则汇编器会选择后一种编码,因为它更有效。
一条指令只能使用一个字面量,但多个操作数可以引用同一个字面量。
uimm8¶
uimm32¶
uimm20¶
该值必须在 0..0xFFFFF 范围内。
simm21¶
该值必须在 -0x100000..0x0FFFFF 范围内。
off¶
特殊实体,指示不使用此操作数的值。
语法
描述
off
指示未使用的操作数。
数字¶
整数¶
整数可以以二进制、八进制、十六进制和十进制格式指定
格式
语法
示例
十进制
[-]?[1-9][0-9]*
-1234
二进制
[-]?0b[01]+
0b1010
八进制
[-]?0[0-7]+
010
十六进制
[-]?0x[0-9a-fA-F]+
0xff
[-]?[0x]?[0-9][0-9a-fA-F]*[hH]
0ffh
浮点数¶
所有浮点数都作为双精度(64 位宽)处理。它们转换为预期操作数类型,如此处所述。
浮点数可以以十六进制和十进制格式指定
格式
语法
示例
注意
十进制
[-]?[0-9]*[.][0-9]*([eE][+-]?[0-9]*)?
-1.234, 234e2
必须包含十进制分隔符或指数。
十六进制
[-]0x[0-9a-fA-F]*(.[0-9a-fA-F]*)?[pP][+-]?[0-9a-fA-F]+
-0x1afp-10, 0x.1afp10
表达式¶
表达式求值为 64 位整数。请注意,不支持浮点表达式。
表达式有两种类型
绝对表达式¶
绝对表达式的值在程序重定位后不会更改。绝对表达式不得包含未分配和可重定位的值,例如标签。
绝对表达式求值为 64 位整数值,并转换为预期操作数类型,如此处所述。
示例
x = -1
y = x + 10
可重定位表达式¶
可重定位表达式的值取决于程序重定位。
请注意,可重定位表达式的使用仅限于分支目标和 32 位整数操作数。
可重定位表达式求值为 64 位整数值,该值取决于操作数类型和表达式中使用的符号的重定位类型。例如,如果指令引用标签,则此引用求值为从指令后的地址到标签地址的偏移量
label:
v_add_co_u32_e32 v0, vcc, label, v1 // 'label' operand is evaluated to -4
操作数和运算¶
表达式由 64 位整数操作数和运算组成。操作数包括整数和符号。
表达式也可以使用 “.”,它是对当前 PC(程序计数器)的引用。
表达式语法¶
表达式的语法如下所示
expr ::= expr binop expr | primaryexpr ;
primaryexpr ::= '(' expr ')' | symbol | number | '.' | unop primaryexpr ;
binop ::= '&&'
| '||'
| '|'
| '^'
| '&'
| '!'
| '=='
| '!='
| '<>'
| '<'
| '<='
| '>'
| '>='
| '<<'
| '>>'
| '+'
| '-'
| '*'
| '/'
| '%' ;
unop ::= '~'
| '+'
| '-'
| '!' ;
二元运算符¶
下表描述了二元运算符。它们对 64 位整数进行运算并产生 64 位整数。优先级较高的运算符先执行。
运算符
优先级
含义
*
5
*
/
5
/
%
5
%
+
4
+
-
4
-
<<
3
<<
>>
3
>>
==
2
==
!=
2
!=
<>
2
!=
<
2
<
<=
2
<=
>
2
>
>=
2
>=
|
1
|
^
1
^
&
1
&
&&
0
&&
||
0
||
一元运算符¶
下表描述了一元运算符。它们对 64 位整数进行运算并产生 64 位整数。
运算符
含义
!
!
~
~
+
+
-
-
符号¶
符号是命名的 64 位整数值,表示可重定位地址或绝对(不可重定位)数字。
- 符号名称具有以下语法
[a-zA-Z_.][a-zA-Z0-9_$.@]*
下表提供了用于符号定义的几种语法示例。
语法
含义
.globl <S>
声明一个全局符号 S,而不为其赋值。
.set <S>, <E>
将表达式 E 的值分配给符号 S。
<S> = <E>
将表达式 E 的值分配给符号 S。
<S>
声明一个标签 S,并为其分配当前 PC 值。
符号可以在声明或赋值之前使用;未赋值的符号假定为 PC 相对。
有关符号的更多信息,请参见此处。
类型和大小转换¶
本节描述当 64 位整数、浮点数或表达式用于具有不同类型或大小的操作数时会发生什么。
整数值转换¶
指令操作数可以指定为 64 位整数或绝对表达式。这些值使用以下步骤转换为预期操作数类型
1. 验证。汇编器检查输入值是否可以在不丢失精度的情况下截断为所需的截断宽度(见下表)。在以下两种情况下,此操作启用
截断的位全为 0。
截断的位全为 1,并且截断后的值设置了 MSB 位。
在所有其他情况下,汇编器会触发错误。
2. 转换。输入值转换为下表描述的预期类型。根据操作数类型,此转换由汇编器或 AMDGPU H/W(或两者)执行。
预期类型
截断宽度
转换
描述
i16、u16、b16
16
num.u16
截断为 16 位。
i32、u32、b32
32
num.u32
截断为 32 位。
i64
32
{-1,num.i32}
截断为 32 位,然后将结果符号扩展为 64 位。
u64、b64
32
{0,num.u32}
截断为 32 位,然后将结果零扩展为 64 位。
f16
16
num.u16
使用低 16 位作为 f16 值。
f32
32
num.u32
使用低 32 位作为 f32 值。
f64
32
{num.u32,0}
使用数字的低 32 位作为结果的高 32 位;结果的低 32 位清零。
已启用转换的示例
// GFX9
v_add_u16 v0, -1, 0 // src0 = 0xFFFF
v_add_f16 v0, -1, 0 // src0 = 0xFFFF (NaN)
//
v_add_u32 v0, -1, 0 // src0 = 0xFFFFFFFF
v_add_f32 v0, -1, 0 // src0 = 0xFFFFFFFF (NaN)
//
v_add_u16 v0, 0xff00, v0 // src0 = 0xff00
v_add_u16 v0, 0xffffffffffffff00, v0 // src0 = 0xff00
v_add_u16 v0, -256, v0 // src0 = 0xff00
//
s_bfe_i64 s[0:1], 0xffefffff, s3 // src0 = 0xffffffffffefffff
s_bfe_u64 s[0:1], 0xffefffff, s3 // src0 = 0x00000000ffefffff
v_ceil_f64_e32 v[0:1], 0xffefffff // src0 = 0xffefffff00000000 (-1.7976922776554302e308)
//
x = 0xffefffff //
s_bfe_i64 s[0:1], x, s3 // src0 = 0xffffffffffefffff
s_bfe_u64 s[0:1], x, s3 // src0 = 0x00000000ffefffff
v_ceil_f64_e32 v[0:1], x // src0 = 0xffefffff00000000 (-1.7976922776554302e308)
已禁用转换的示例
// GFX9
v_add_u16 v0, 0x1ff00, v0 // truncated bits are not all 0 or 1
v_add_u16 v0, 0xffffffffffff00ff, v0 // truncated bits do not match MSB of the result
浮点数值转换¶
指令操作数可以指定为 64 位浮点数。这些值使用以下步骤转换为预期操作数类型
1. 验证。汇编器检查输入 f64 数字是否可以转换为所需的浮点类型(见下表),而不会发生溢出或下溢。允许精度损失。如果此转换不可能,则汇编器会触发错误。
2. 转换。输入值转换为下表描述的预期类型。根据操作数类型,这由汇编器或 AMDGPU H/W(或两者)执行。
预期类型
所需的 FP 类型
转换
描述
i16、u16、b16
f16
f16(num)
转换为 f16 并使用结果的位作为整数值。该值必须编码为字面量,否则会发生错误。请注意,该值不能编码为内联常量。
i32、u32、b32
f32
f32(num)
转换为 f32 并使用结果的位作为整数值。
i64、u64、b64
-
-
禁用转换。
f16
f16
f16(num)
f16
f32
f32
f32(num)
f32
f64
f64
{num.u32.hi,0}
使用数字的高 32 位作为结果的高 32 位;零填充结果的低 32 位。
请注意,结果可能与原始数字不同。
已启用转换的示例
// GFX9
v_add_f16 v0, 1.0, 0 // src0 = 0x3C00 (1.0)
v_add_u16 v0, 1.0, 0 // src0 = 0x3C00
//
v_add_f32 v0, 1.0, 0 // src0 = 0x3F800000 (1.0)
v_add_u32 v0, 1.0, 0 // src0 = 0x3F800000
// src0 before conversion:
// 1.7976931348623157e308 = 0x7fefffffffffffff
// src0 after conversion:
// 1.7976922776554302e308 = 0x7fefffff00000000
v_ceil_f64 v[0:1], 1.7976931348623157e308
v_add_f16 v1, 65500.0, v2 // ok for f16.
v_add_f32 v1, 65600.0, v2 // ok for f32, but would result in overflow for f16.
已禁用转换的示例
// GFX9
v_add_f16 v1, 65600.0, v2 // overflow
可重定位值转换¶
可重定位表达式可以与 32 位整数操作数和跳转目标一起使用。
当可重定位表达式的值由链接器解析时,会根据需要进行转换,并截断至操作数大小。转换方式取决于重定位类型和操作数类型。
例如,当指令的 32 位操作数引用可重定位表达式 expr 时,此引用会被计算为从指令地址之后到被引用地址的 64 位偏移量,以字节为单位。 然后,该值会被截断为 32 位,并编码为字面值。
expr = .
v_add_co_u32_e32 v0, vcc, expr, v1 // 'expr' operand is evaluated to -4
// and then truncated to 0xFFFFFFFC
再举一个例子,当分支指令引用标签时,此引用会被计算为从指令地址之后到标签地址的偏移量,以双字为单位。 然后,该值会被截断为 16 位。
label:
s_branch label // 'label' operand is evaluated to -1 and truncated to 0xFFFF