AMDGPU 指令操作数语法

约定

本文档通篇使用以下符号

符号

描述

{0..N}

0 到 N(包括 N)范围内的任何整数值。

<x>

x 的语法和含义在其他地方解释。

操作数

v (32 位)

向量寄存器。有 256 个 32 位向量寄存器。

可以使用一系列向量寄存器来操作超过 32 位的数据。

汇编器当前支持包含 1 到 12 个、16 个和 32 个向量寄存器的元组。

语法

描述

v<N>

单个 32 位向量寄存器。

N 必须是十进制整数

v[<N>]

单个 32 位向量寄存器。

N 可以指定为整数绝对表达式

v[<N>:<K>]

K-N+1)个向量寄存器的序列。

NK 可以指定为整数绝对表达式

[v<N>, v<N+1>, … v<K>]

K-N+1)个向量寄存器的序列。

寄存器索引必须指定为十进制整数

注意:NK 必须满足以下条件

  • 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 个累加器寄存器的元组。

语法

替代语法 (SP3)

描述

a<N>

acc<N>

单个 32 位累加器寄存器。

N 必须是十进制整数

a[<N>]

acc[<N>]

单个 32 位累加器寄存器。

N 可以指定为整数绝对表达式

a[<N>:<K>]

acc[<N>:<K>]

K-N+1)个累加器寄存器的序列。

NK 可以指定为整数绝对表达式

[a<N>, a<N+1>, … a<K>]

[acc<N>, acc<N+1>, … acc<K>]

K-N+1)个累加器寄存器的序列。

寄存器索引必须指定为十进制整数

注意:NK 必须满足以下条件

  • 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 个或更多标量寄存器的序列必须是四字对齐的。

语法

描述

s<N>

单个 32 位标量寄存器。

N 必须是十进制整数

s[<N>]

单个 32 位标量寄存器。

N 可以指定为整数绝对表达式

s[<N>:<K>]

K-N+1)个标量寄存器的序列。

NK 可以指定为整数绝对表达式

[s<N>, s<N+1>, … s<K>]

K-N+1)个标量寄存器的序列。

寄存器索引必须指定为十进制整数

注意:NK 必须满足以下条件

  • 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 寄存器的序列必须是四字对齐的。

语法

描述

ttmp<N>

单个 32 位 ttmp 寄存器。

N 必须是十进制整数

ttmp[<N>]

单个 32 位 ttmp 寄存器。

N 可以指定为整数绝对表达式

ttmp[<N>:<K>]

K-N+1)个 ttmp 寄存器的序列。

NK 可以指定为整数绝对表达式

[ttmp<N>, ttmp<N+1>, … ttmp<K>]

K-N+1)个 ttmp 寄存器的序列。

寄存器索引必须指定为十进制整数

注意:NK 必须满足以下条件

  • 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

8 位整数绝对表达式。该值必须在 0..0xFF 范围内。

uimm32

32 位整数绝对表达式。该值必须在 0..0xFFFFFFFF 范围内。

uimm20

20 位整数绝对表达式

该值必须在 0..0xFFFFF 范围内。

simm21

21 位整数绝对表达式

该值必须在 -0x100000..0x0FFFFF 范围内。

off

特殊实体,指示不使用此操作数的值。

语法

描述

off

指示未使用的操作数。

数字

整数

整数为 64 位宽。它们转换为预期操作数类型,如此处所述。

整数可以以二进制、八进制、十六进制和十进制格式指定

格式

语法

示例

十进制

[-]?[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(程序计数器)的引用。

一元二元运算产生 64 位整数结果。

表达式语法

表达式的语法如下所示

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