AMD CDNA3汇编指令说明

在AMD CDNA架构中,s_waitcnt指令用于确保特定类型的指令(如内存操作或数据共享操作)完成后再继续执行后续指令。以下是vmcntlgkmcnt后数字的具体含义及用户汇编代码中的用法分析:

1. 计数器的定义

AMD CDNA架构通过三个计数器管理指令依赖性:

  • vmcnt(Vector Memory Count):追踪未完成的向量内存操作(如global_loadbuffer_store等)。
  • lgkmcnt(LDS/GDS/Constant/Message Count):追踪未完成的LDS/GDS指令、标量内存操作(如S_LOAD)和消息指令(如S_SENDMSG)。
  • expcnt(Export Count):追踪未完成的VGPR导出指令(如GDS操作)。

2. 参数含义

  • s_waitcnt vmcnt(N):等待向量内存操作完成,直到未完成操作数 ≤ N。
  • s_waitcnt lgkmcnt(M):等待LDS/GDS/标量内存/消息操作完成,直到未完成操作数 ≤ M。

例如:

  • s_waitcnt vmcnt(0):等待所有向量内存操作完成。
  • s_waitcnt lgkmcnt(4):允许最多有4个LDS/GDS/标量内存/消息操作未完成。

3. 用户代码分析

汇编指令序列

global_load_dwordx4 v[12:15], v[12:13], off nt  ; 向量内存加载(vmcnt++)
ds_read_b128 v[16:19], v10                       ; LDS读取(lgkmcnt++, 每条ds_read递增1次)
ds_read_b128 v[20:23], v6
ds_read2_b32 v[28:29], v11 offset1:1
ds_read_b128 v[24:27], v24
ds_read2_b32 v[30:31], v11 offset0:2 offset1:3

s_waitcnt vmcnt(0) lgkmcnt(4)  ; 等待所有向量内存操作完成,且未完成的LDS操作 ≤4
s_waitcnt lgkmcnt(3)           ; 等待未完成的LDS操作 ≤3
s_waitcnt lgkmcnt(2)           ; 等待未完成的LDS操作 ≤2
s_waitcnt lgkmcnt(1)           ; 等待未完成的LDS操作 ≤1
s_waitcnt lgkmcnt(0)           ; 等待所有LDS操作完成

具体行为

  1. 初始状态:

    • 执行5条ds_read指令后,lgkmcnt初始值为5。
    • global_load_dwordx4指令会增加vmcnt至1。
  2. s_waitcnt vmcnt(0)

    • 等待向量内存操作完成(即vmcnt降为0)。
    • 此时global_load_dwordx4的数据已可用。
  3. s_waitcnt lgkmcnt(4)

    • 等待最多4个LDS操作未完成。假设此时已有一个LDS操作完成(lgkmcnt=4),继续执行后续指令。
  4. 后续lgkmcnt递减:

    • 通过逐步降低允许的未完成操作数(4→3→2→1→0),确保LDS数据按需逐批就绪,避免数据竞争。

4. 关键规则

  • LDS操作的单次计数:每条ds_read指令(无论读取多少DWord)仅递增lgkmcnt一次。
  • 标量内存操作的特殊规则:例如S_LOAD_DWORDX4会递增lgkmcnt 4次(因加载4 DWord),但用户代码中未涉及。
  • 顺序性:同类指令(如多个LDS读取)按序完成,但不同类指令(如LDS和标量内存)可能乱序完成。

 

在AMD CDNA架构中,ds_read_b128指令的作用和计数器行为可以通过以下关键点解释:

5. LDS操作与向量内存操作的区别

  • LDS(Local Data Share):是工作组内共享的低延迟本地内存,用于线程间通信。其操作(如ds_read/ds_write)属于共享内存访问,而非全局内存或设备内存访问。
  • 向量内存操作:指针对全局内存(Global Memory)或设备内存的访问(如global_loadbuffer_load等)。这些操作需要经过内存控制器和缓存层次结构,延迟较高。

6. 计数器分类

AMD CDNA架构通过三个计数器管理指令依赖性:

  • vmcnt(Vector Memory Count):仅追踪全局内存操作(如global_loadbuffer_store等)。
  • lgkmcnt(LDS/GDS/Constant/Message Count):追踪LDS操作、GDS操作、标量内存操作(如S_LOAD)和消息指令(如S_SENDMSG)。

7. ds_read_b128的归类

  • ds_read_b128指令从LDS读取128位数据到VGPR中,属于LDS操作,因此仅递增lgkmcnt,而不影响vmcnt
  • global_load等全局内存指令:需要与设备内存交互,会递增vmcnt

8. 为何vmcnt不增加?

  • 内存层级差异:LDS是片上共享内存,访问延迟极低,由专门的硬件单元管理,不经过全局内存控制器。
  • 计数器设计分离:AMD将LDS操作与全局内存操作分开管理,以避免不同内存层次的依赖混淆,简化同步逻辑。

9. 验证依据

文档中明确说明:

  1. LDS操作归类(Chapter 11):
    • LDS访问由lgkmcnt管理,用于同步工作组内数据共享。
    • 向量内存操作由vmcnt管理,用于全局内存访问。
  2. 计数器定义(Chapter 3.1):
    • vmcnt仅针对全局内存的读写和原子操作。
    • lgkmcnt覆盖LDS、GDS、标量内存和消息操作。

 

10. 汇编指令解释

1. global_load_dwordx4 v[20:23], v[20:21], off nt

  • 功能:从全局内存异步加载4个Dword(16字节)到VGPR v20-v23
  • 参数:
    • v[20:23]:目标VGPR范围。
    • v[20:21]:地址VGPR对(低32位在v20,高32位在v21)。
    • off:无偏移。
    • nt:Non-Temporal提示(绕过缓存)。
  • 计数器:vmcnt 增加1(全局内存操作)。

2. ds_read_b128 v[20:23], v6

  • 功能:从LDS地址v6异步加载128位(16字节)到VGPR v20-v23
  • 参数:
    • v[20:23]:目标VGPR。
    • v6:LDS地址源VGPR。
  • 计数器:lgkmcnt 增加1(LDS操作)。

3. ds_read2_b32 v[28:29], v11 offset1:1

  • 功能:从LDS基地址v11的两个偏移位置读取两个32位数据。
    • 第一个Dword:地址v11(偏移0)。
    • 第二个Dword:地址v11 + 4(偏移1,步长为4字节)。
  • 参数:
    • offset1:1:第二个Dword的偏移量。
  • 计数器:lgkmcnt 增加1(每个ds_read操作递增一次)。

4. ds_read2_b32 v[30:31], v11 offset0:2 offset1:3

  • 功能:从LDS基地址v11的两个偏移位置读取两个32位数据。
    • 第一个Dword:地址v11 + 8(偏移2,步长为4字节)。
    • 第二个Dword:地址v11 + 12(偏移3)。
  • 参数:
    • offset0:2:第一个Dword的偏移量。
    • offset1:3:第二个Dword的偏移量。
  • 计数器:lgkmcnt 增加1。

5. ds_read_b128 v[24:27], v18 offset:1024

  • 功能:从LDS地址v18 + 1024异步加载128位(16字节)到VGPR v24-v27
  • 参数:
    • offset:1024:LDS地址的固定偏移。
  • 计数器:lgkmcnt 增加1。

6. scratch_store_dwordx4 off, v[24:27], s23

  • 功能:将VGPR v24-v27中的4个Dword存储到Scratch内存地址s23 + off
  • 参数:
    • s23:Scratch内存基地址的标量寄存器。
    • off:无附加偏移。
  • 计数器:vmcnt 增加1(Scratch操作属于FLAT格式,视为向量内存操作)。

7. scratch_store_dwordx2 off, v[28:29], s23 offset:32

  • 功能:将VGPR v28-v29中的2个Dword存储到Scratch内存地址s23 + 32
  • 参数:
    • offset:32:相对于基地址的附加偏移。
  • 计数器:vmcnt 增加1。

8. scratch_load_dword v6, off, s23

  • 功能:从Scratch内存地址s23加载1个Dword到VGPR v6
  • 参数:
    • off:无偏移。
  • 计数器:vmcnt 增加1。

9. scratch_load_dword v19, off, s23 offset:4

  • 功能:从Scratch内存地址s23 + 4加载1个Dword到VGPR v19
  • 参数:
    • offset:4:附加偏移量。
  • 计数器:vmcnt 增加1。

11. 问题1:scratch_store_dwordx4scratch_load_dword是否影响vmcnt

结论:

  • 是,Scratch操作属于向量内存操作(FLAT格式),会递增vmcnt计数器。
  • 依据(文档Chapter 4.4):

    VM_CNT(Vector Memory Count):追踪所有向量内存操作(包括MUBUF、MTBUF和FLAT格式)。 FLAT格式包含Scratch操作(如scratch_loadscratch_store),因此会递增vmcnt

 

12. 问题2:scratch_store_dwordx2 off, v[28:29], s23 offset:32,这条指令中地址偏移32的单位是byte还是dwordx2?请从指令集文档中找到依据?

根据AMD CDNA架构文档中Scratch指令的地址偏移规则(见第12.15.2节"Scratch Instructions"),以下是对scratch_store_dwordx2 off, v[28:29], s23 offset:32指令偏移量单位的分析:

结论

指令中的偏移量 offset:32 的单位为字节(Byte),而非Dwordx2。

依据

  1. 指令语义定义:

    • Scratch指令(如scratch_store)的地址计算规则与 FLAT内存操作 一致(见第10章)。文档明确说明:

      FLAT格式的地址偏移(offset)以字节为单位(Chapter 10.3.1: "Addressing")。

  2. 对齐规则:

    • 若以Dword为单位,偏移量为32时实际地址偏移为 32×4=128字节,这与常见的内存对齐要求(如64字节对齐)冲突。文档无此类特殊对齐规则的描述。
  3. 同类指令验证:

    • scratch_load_dword等同类指令的偏移量单位均为字节。

 

13. 问题3:global_load_dwordx4 v[20:23], v[20:21], off nt,这条指令的偏移是off,如果有偏移的话,单位也是byte么?请从指令集文档中找到依据

根据AMD CDNA架构文档中MUBUF指令的地址偏移规则(见Chapter 9.1.5 "Buffer Addressing"),以下是关键分析:

结论

global_load_dwordx4指令的偏移量参数 off 的单位为字节(Byte)。

依据

  1. MUBUF指令的地址计算定义:

    • MUBUF(内存缓冲指令)的地址计算公式为: Base Address + SGPR_address + offset 其中 offset 是符号扩展的12位立即数(范围为 -2048 至 +2047 字节)。文档明确指出:

      For MUBUF instructions, the offset is a 12-bit signed byte offset.

  2. 对齐规则:

    • 在第9.1.7节"Alignment"中,强调地址必须按数据尺寸对齐(例如:dwordx4需对齐到16字节),但偏移量本身仍以字节为单位。这与字节粒度寻址一致。
  3. 同类指令验证:

    • FLAT/Scratch指令(如scratch_store_dwordx2)的偏移量明确以字节为单位(见Chapter 10),MUBUF遵循相同设计原则。

总结

global_load_dwordx4off 参数是 12位有符号字节偏移,范围 -2048 至 +2047 字节。这是AMD CDNA架构的统一内存寻址设计。

 

14. 问题4:vmcnt(Vector Memory Count,lgkmcnt(LDS/GDS/Constant/Message Count),expcnt(Export Count)这3个计数器支持的最大值分别是多少?

根据AMD CDNA架构文档中状态寄存器的定义,三个计数器的最大支持值如下:

计数器最大值

  1. vmcnt(Vector Memory Count)

    • 位数:6位
    • 最大值:26−1=63261=63
    • 功能:追踪未完成的全局向量内存操作(如global_loadbuffer_store等)。
  2. lgkmcnt(LDS/GDS/Constant/Message Count)

    • 位数:4位
    • 最大值:24−1=15241=15
    • 功能:追踪未完成的LDS操作、GDS操作、标量内存读取(如S_LOAD)和消息指令(如S_SENDMSG)。
  3. expcnt(Export Count)

    • 位数:3位
    • 最大值:23−1=7231=7
    • 功能:追踪未完成的导出操作(如GDS指令)。

依据(文档第3.1节)

在状态寄存器概述中明确标注了三个计数器的大小:

CounterBit WidthMax Value
VMCNT 6 63
LGKMCNT 4 15
EXPCNT 3 7

总结

  • 使用S_WAITCNT指令时,需确保参数不超过最大值:
    s_waitcnt vmcnt(63) lgkmcnt(15) expcnt(7)
  • 超过最大值会导致未定义行为。

 

 

 

 

 

END

 

posted @ 2025-05-24 20:39  洗盏更酌  Views(135)  Comments(0)    收藏  举报