AMDGPU 後端的用戶指南¶
簡介¶
AMDGPU 後端為 AMD GPU 提供 ISA 程式碼生成,從 R600 系列一直到目前的 GCN 系列。它位於 llvm/lib/Target/AMDGPU
目錄中。
LLVM¶
目標三元組¶
使用 Clang 選項 -target <Architecture>-<Vendor>-<OS>-<Environment>
來指定目標三元組
表 18 AMDGPU 架構¶ 架構
描述
r600
AMD GPU HD2XXX-HD6XXX,用於圖形和運算著色器。
amdgcn
AMD GPU GCN GFX6 及更高版本,用於圖形和運算著色器。
表 19 AMDGPU 供應商¶ 供應商
描述
amd
可用於所有 AMD GPU 用途。
mesa
如果 OS 為
mesa3d
,則可以使用。
表 20 AMDGPU 作業系統¶ OS
描述
<empty>
預設為未知的 OS。
amdhsa
在 HSA [HSA] 相容執行階段(例如
AMD 的 ROCm™ 執行階段 [AMD-ROCm],在 Linux 上使用 rocm-amdhsa 載入器。請參閱AMD ROCm 平台發行說明 [AMD-ROCm-Release-Notes] 以了解支援的硬體和軟體。
AMD 的 PAL 執行階段,在 Windows 上使用 pal-amdhsa 載入器。
amdpal
圖形著色器和運算核心,在 AMD 的 PAL 執行階段上執行,在 Windows 和 Linux Pro 上使用 pal-amdpal 載入器。
mesa3d
圖形著色器和運算核心,在 AMD 的 Mesa 3D 執行階段上執行,在 Linux 上使用 mesa-mesa3d 載入器。
表 21 AMDGPU 環境¶ 環境
描述
<empty>
預設。
處理器¶
使用 Clang 選項 -mcpu=<target-id>
或 --offload-arch=<target-id>
來指定 AMDGPU 處理器,以及可選的目標功能。請參閱目標 ID和目標功能以取得 AMD GPU 目標特定資訊。
每個處理器都支援每個 OS ABI(請參閱AMDGPU 作業系統),但以下例外情況除外
amdhsa
在r600
架構中不受支援(請參閱AMDGPU 架構)。表 22 AMDGPU 處理器¶ 處理器
替代處理器
目標三元組架構
獨立顯示卡/加速處理器
支援的目標功能
目標屬性
OS 支援(請參閱amdgpu-os和對應的執行階段發行說明,以取得目前的資訊和支援程度)
範例產品
Radeon HD 2000/3000 系列 (R600) [AMD-RADEON-HD-2000-3000]
r600
r600
獨立顯示卡
不支援通用位址空間
r630
r600
獨立顯示卡
不支援通用位址空間
rs880
r600
獨立顯示卡
不支援通用位址空間
rv670
r600
獨立顯示卡
不支援通用位址空間
Radeon HD 4000 系列 (R700) [AMD-RADEON-HD-4000]
rv710
r600
獨立顯示卡
不支援通用位址空間
rv730
r600
獨立顯示卡
不支援通用位址空間
rv770
r600
獨立顯示卡
不支援通用位址空間
Radeon HD 5000 系列 (Evergreen) [AMD-RADEON-HD-5000]
cedar
r600
獨立顯示卡
不支援通用位址空間
cypress
r600
獨立顯示卡
不支援通用位址空間
juniper
r600
獨立顯示卡
不支援通用位址空間
redwood
r600
獨立顯示卡
不支援通用位址空間
sumo
r600
獨立顯示卡
不支援通用位址空間
Radeon HD 6000 系列 (Northern Islands) [AMD-RADEON-HD-6000]
barts
r600
獨立顯示卡
不支援通用位址空間
caicos
r600
獨立顯示卡
不支援通用位址空間
cayman
r600
獨立顯示卡
不支援通用位址空間
turks
r600
獨立顯示卡
不支援通用位址空間
GCN GFX6 (Southern Islands (SI)) [AMD-GCN-GFX6]
gfx600
tahiti
amdgcn
獨立顯示卡
不支援通用位址空間
pal-amdpal
gfx601
pitcairn
verde
amdgcn
獨立顯示卡
不支援通用位址空間
pal-amdpal
gfx602
hainan
oland
amdgcn
獨立顯示卡
不支援通用位址空間
pal-amdpal
GCN GFX7 (Sea Islands (CI)) [AMD-GCN-GFX7]
gfx700
kaveri
amdgcn
加速處理器
偏移量 flat scratch
rocm-amdhsa
pal-amdhsa
pal-amdpal
A6-7000
A6 Pro-7050B
A8-7100
A8 Pro-7150B
A10-7300
A10 Pro-7350B
FX-7500
A8-7200P
A10-7400P
FX-7600P
gfx701
hawaii
amdgcn
獨立顯示卡
偏移量 flat scratch
rocm-amdhsa
pal-amdhsa
pal-amdpal
FirePro W8100
FirePro W9100
FirePro S9150
FirePro S9170
gfx702
amdgcn
獨立顯示卡
偏移量 flat scratch
rocm-amdhsa
pal-amdhsa
pal-amdpal
Radeon R9 290
Radeon R9 290x
Radeon R390
Radeon R390x
gfx703
kabini
mullins
amdgcn
加速處理器
偏移量 flat scratch
pal-amdhsa
pal-amdpal
E1-2100
E1-2200
E1-2500
E2-3000
E2-3800
A4-5000
A4-5100
A6-5200
A4 Pro-3340B
gfx704
bonaire
amdgcn
獨立顯示卡
偏移量 flat scratch
pal-amdhsa
pal-amdpal
Radeon HD 7790
Radeon HD 8770
R7 260
R7 260X
gfx705
amdgcn
加速處理器
偏移量 flat scratch
pal-amdhsa
pal-amdpal
待定
GCN GFX8 (Volcanic Islands (VI)) [AMD-GCN-GFX8]
gfx801
carrizo
amdgcn
加速處理器
xnack
偏移量 flat scratch
rocm-amdhsa
pal-amdhsa
pal-amdpal
A6-8500P
Pro A6-8500B
A8-8600P
Pro A8-8600B
FX-8800P
Pro A12-8800B
A10-8700P
Pro A10-8700B
A10-8780P
A10-9600P
A10-9630P
A12-9700P
A12-9730P
FX-9800P
FX-9830P
E2-9010
A6-9210
A9-9410
gfx802
iceland
tonga
amdgcn
獨立顯示卡
偏移量 flat scratch
rocm-amdhsa
pal-amdhsa
pal-amdpal
Radeon R9 285
Radeon R9 380
Radeon R9 385
gfx803
fiji
amdgcn
獨立顯示卡
rocm-amdhsa
pal-amdhsa
pal-amdpal
Radeon R9 Nano
Radeon R9 Fury
Radeon R9 FuryX
Radeon Pro Duo
FirePro S9300x2
Radeon Instinct MI8
polaris10
amdgcn
獨立顯示卡
偏移量 flat scratch
rocm-amdhsa
pal-amdhsa
pal-amdpal
Radeon RX 470
Radeon RX 480
Radeon Instinct MI6
polaris11
amdgcn
獨立顯示卡
偏移量 flat scratch
rocm-amdhsa
pal-amdhsa
pal-amdpal
Radeon RX 460
gfx805
tongapro
amdgcn
獨立顯示卡
偏移量 flat scratch
rocm-amdhsa
pal-amdhsa
pal-amdpal
FirePro S7150
FirePro S7100
FirePro W7100
Mobile FirePro M7170
gfx810
stoney
amdgcn
加速處理器
xnack
偏移量 flat scratch
rocm-amdhsa
pal-amdhsa
pal-amdpal
待定
GCN GFX9 (Vega) [AMD-GCN-GFX900-GFX904-VEGA] [AMD-GCN-GFX906-VEGA7NM] [AMD-GCN-GFX908-CDNA1] [AMD-GCN-GFX90A-CDNA2] [AMD-GCN-GFX942-CDNA3]
gfx900
amdgcn
獨立顯示卡
xnack
絕對 flat scratch
rocm-amdhsa
pal-amdhsa
pal-amdpal
Radeon Vega Frontier Edition
Radeon RX Vega 56
Radeon RX Vega 64
Radeon RX Vega 64 Liquid
Radeon Instinct MI25
gfx902
amdgcn
加速處理器
xnack
絕對 flat scratch
rocm-amdhsa
pal-amdhsa
pal-amdpal
Ryzen 3 2200G
Ryzen 5 2400G
gfx904
amdgcn
獨立顯示卡
xnack
rocm-amdhsa
pal-amdhsa
pal-amdpal
待定
gfx906
amdgcn
獨立顯示卡
sramecc
xnack
絕對 flat scratch
rocm-amdhsa
pal-amdhsa
pal-amdpal
Radeon Instinct MI50
Radeon Instinct MI60
Radeon VII
Radeon Pro VII
gfx908
amdgcn
獨立顯示卡
sramecc
xnack
絕對 flat scratch
rocm-amdhsa
AMD Instinct MI100 Accelerator
gfx909
amdgcn
加速處理器
xnack
絕對 flat scratch
pal-amdpal
待定
gfx90a
amdgcn
獨立顯示卡
sramecc
tgsplit
xnack
kernarg 預先載入(MI210 除外)
絕對 flat scratch
封裝的工作項目 ID
rocm-amdhsa
rocm-amdhsa
rocm-amdhsa
AMD Instinct MI210 Accelerator
AMD Instinct MI250 Accelerator
AMD Instinct MI250X Accelerator
gfx90c
amdgcn
加速處理器
xnack
絕對 flat scratch
pal-amdpal
Ryzen 7 4700G
Ryzen 7 4700GE
Ryzen 5 4600G
Ryzen 5 4600GE
Ryzen 3 4300G
Ryzen 3 4300GE
Ryzen Pro 4000G
Ryzen 7 Pro 4700G
Ryzen 7 Pro 4750GE
Ryzen 5 Pro 4650G
Ryzen 5 Pro 4650GE
Ryzen 3 Pro 4350G
Ryzen 3 Pro 4350GE
gfx942
amdgcn
獨立顯示卡
sramecc
tgsplit
xnack
kernarg 預先載入
架構化的 flat scratch
封裝的工作項目 ID
AMD Instinct MI300X
AMD Instinct MI300A
gfx950
amdgcn
獨立顯示卡
sramecc
tgsplit
xnack
kernarg 預先載入
架構化的 flat scratch
封裝的工作項目 ID
待定
GCN GFX10.1 (RDNA 1) [AMD-GCN-GFX10-RDNA1]
gfx1010
amdgcn
獨立顯示卡
cumode
wavefrontsize64
xnack
絕對 flat scratch
rocm-amdhsa
pal-amdhsa
pal-amdpal
Radeon RX 5700
Radeon RX 5700 XT
Radeon Pro 5600 XT
Radeon Pro 5600M
gfx1011
amdgcn
獨立顯示卡
cumode
wavefrontsize64
xnack
絕對 flat scratch
rocm-amdhsa
pal-amdhsa
pal-amdpal
Radeon Pro V520
gfx1012
amdgcn
獨立顯示卡
cumode
wavefrontsize64
xnack
絕對 flat scratch
rocm-amdhsa
pal-amdhsa
pal-amdpal
Radeon RX 5500
Radeon RX 5500 XT
gfx1013
amdgcn
加速處理器
cumode
wavefrontsize64
xnack
絕對 flat scratch
rocm-amdhsa
pal-amdhsa
pal-amdpal
待定
GCN GFX10.3 (RDNA 2) [AMD-GCN-GFX10-RDNA2]
gfx1030
amdgcn
獨立顯示卡
cumode
wavefrontsize64
絕對 flat scratch
rocm-amdhsa
pal-amdhsa
pal-amdpal
Radeon RX 6800
Radeon RX 6800 XT
Radeon RX 6900 XT
Radeon PRO W6800
Radeon PRO V620
gfx1031
amdgcn
獨立顯示卡
cumode
wavefrontsize64
絕對 flat scratch
rocm-amdhsa
pal-amdhsa
pal-amdpal
Radeon RX 6700 XT
gfx1032
amdgcn
獨立顯示卡
cumode
wavefrontsize64
絕對 flat scratch
rocm-amdhsa
pal-amdhsa
pal-amdpal
待定
gfx1033
amdgcn
加速處理器
cumode
wavefrontsize64
絕對 flat scratch
pal-amdpal
待定
gfx1034
amdgcn
獨立顯示卡
cumode
wavefrontsize64
絕對 flat scratch
pal-amdpal
待定
gfx1035
amdgcn
加速處理器
cumode
wavefrontsize64
絕對 flat scratch
pal-amdpal
待定
gfx1036
amdgcn
加速處理器
cumode
wavefrontsize64
絕對 flat scratch
pal-amdpal
待定
GCN GFX11 (RDNA 3) [AMD-GCN-GFX11-RDNA3]
gfx1100
amdgcn
獨立顯示卡
cumode
wavefrontsize64
架構化的 flat scratch
封裝的工作項目 ID
pal-amdpal
Radeon PRO W7900 Dual Slot
Radeon PRO W7900
Radeon PRO W7800
Radeon RX 7900 XTX
Radeon RX 7900 XT
Radeon RX 7900 GRE
gfx1101
amdgcn
獨立顯示卡
cumode
wavefrontsize64
架構化的 flat scratch
封裝的工作項目 ID
待定
gfx1102
amdgcn
獨立顯示卡
cumode
wavefrontsize64
架構化的 flat scratch
封裝的工作項目 ID
待定
gfx1103
amdgcn
加速處理器
cumode
wavefrontsize64
架構化的 flat scratch
封裝的工作項目 ID
待定
GCN GFX11 (RDNA 3.5) [AMD-GCN-GFX11-RDNA3.5]
gfx1150
amdgcn
加速處理器
cumode
wavefrontsize64
架構化的 flat scratch
封裝的工作項目 ID
待定
gfx1151
amdgcn
加速處理器
cumode
wavefrontsize64
架構化的 flat scratch
封裝的工作項目 ID
待定
gfx1152
amdgcn
加速處理器
cumode
wavefrontsize64
架構化的 flat scratch
封裝的工作項目 ID
待定
gfx1153
amdgcn
加速處理器
cumode
wavefrontsize64
架構化的 flat scratch
封裝的工作項目 ID
待定
gfx1200
amdgcn
獨立顯示卡
cumode
wavefrontsize64
架構化的 flat scratch
封裝的工作項目 ID
待定
gfx1201
amdgcn
獨立顯示卡
cumode
wavefrontsize64
架構化的 flat scratch
封裝的工作項目 ID
待定
通用處理器允許在它支援的任何處理器上執行單一程式碼物件。此類程式碼物件的效能可能不如非通用處理器的程式碼物件。
通用處理器僅在程式碼物件 V6 及更高版本上可用(請參閱ELF 程式碼物件)。
通用處理器程式碼物件已進行版本控制。請參閱通用處理器版本控制以取得有關版本控制如何運作的更多資訊。
表 23 AMDGPU 通用處理器¶ 處理器
目標三元組架構
支援的處理器
支援的目標功能
目標屬性
目標限制
gfx9-generic
amdgcn
gfx900
gfx902
gfx904
gfx906
gfx909
gfx90c
xnack
絕對 flat scratch
v_mad_mix
指令在gfx900
、gfx902
、gfx909
、gfx90c
上不可用
v_fma_mix
指令在gfx904
上不可用sramecc 在
gfx906
上不可用以下指令在
gfx906
上不可用
v_fmac_f32
v_xnor_b32
v_dot4_i32_i8
v_dot8_i32_i4
v_dot2_i32_i16
v_dot2_u32_u16
v_dot4_u32_u8
v_dot8_u32_u4
v_dot2_f32_f16
gfx9-4-generic
amdgcn
gfx942
gfx950
sramecc
tgsplit
xnack
kernarg 預先載入
架構化的 flat scratch
封裝的工作項目 ID
FP8 和 BF8 指令、FP8 和 BF8 轉換指令,以及具有 XF32 格式支援的指令不可用。
gfx10-1-generic
amdgcn
gfx1010
gfx1011
gfx1012
gfx1013
xnack
wavefrontsize64
cumode
絕對 flat scratch
以下指令在
gfx1011
和gfx1012
上不可用
v_dot4_i32_i8
v_dot8_i32_i4
v_dot2_i32_i16
v_dot2_u32_u16
v_dot2c_f32_f16
v_dot4c_i32_i8
v_dot4_u32_u8
v_dot8_u32_u4
v_dot2_f32_f16
BVH 光線追蹤指令在
gfx1013
上不可用
gfx10-3-generic
amdgcn
gfx1030
gfx1031
gfx1032
gfx1033
gfx1034
gfx1035
gfx1036
wavefrontsize64
cumode
絕對 flat scratch
無限制。
gfx11-generic
amdgcn
gfx1100
gfx1101
gfx1102
gfx1103
gfx1150
gfx1151
gfx1152
gfx1153
wavefrontsize64
cumode
架構化的 flat scratch
封裝的工作項目 ID
應用各種程式碼生成悲觀化,以解決此系列中某些目標特有的一些危害。
並非所有 VGPR 都可以在以下情況下使用
gfx1100
gfx1101
gfx1151
SALU 浮點指令在以下情況下不可用
gfx1150
gfx1151
gfx1152
gfx1153
SGPR 不支援在 dpp 指令中作為 src1,適用於
gfx1150
gfx1151
gfx1152
gfx1153
gfx12-generic
amdgcn
gfx1200
gfx1201
wavefrontsize64
cumode
架構化的 flat scratch
封裝的工作項目 ID
無限制。
通用處理器版本控制¶
通用處理器(請參閱AMDGPU 通用處理器)程式碼物件已進行版本控制(請參閱程式碼物件 V6 及更高版本的 AMDGPU ELF 標頭 e_flags),版本介於 1 到 255 之間。非通用程式碼物件的版本始終設定為 0。
對於通用程式碼物件,新增支援的處理器可能需要變更為通用目標產生的程式碼,以便它能夠繼續在先前支援的處理器以及新的處理器上執行。當這種情況發生時,通用程式碼物件版本號會與通用目標更新同時遞增。
通用目標的每個支援處理器都映射到它引入的版本。如果載入的程式碼物件版本大於或等於處理器新增到通用目標的版本,則通用程式碼物件可以在支援的處理器上執行。
目標功能¶
目標功能控制如何生成程式碼以支援某些處理器特定的功能。並非所有處理器都支援所有目標功能。執行階段必須確保用於執行程式碼的裝置所支援的功能與生成程式碼時啟用的功能相符。功能不符可能會導致執行不正確,或效能降低。
每個處理器支援的目標功能列在處理器中。
目標功能由以下 Clang 選項之一精確控制
-mcpu=<target-id>
或 --offload-arch=<target-id>
-mcpu
和--offload-arch
可以將目標功能指定為目標 ID 的可選組件。如果省略,目標功能具有any
值。請參閱目標 ID。
-m[no-]<target-feature>
未由目標 ID 指定的目標功能使用單獨的選項指定。這些目標功能可以具有
on
或off
值。on
通過省略no-
前綴來指定,而off
通過包含no-
前綴來指定。如果未指定,則預設為off
。
例如
-mcpu=gfx908:xnack+
啟用
xnack
功能。-mcpu=gfx908:xnack-
停用
xnack
功能。-mcumode
啟用
cumode
功能。-mno-cumode
停用
cumode
功能。表 24 AMDGPU 目標功能¶ 目標功能
控制的 Clang 選項
描述
名稱
cumode
-m[no-]cumode
控制為核心生成程式碼時使用的 wavefront 執行模式。停用時,使用原生 WGP wavefront 執行模式;啟用時,使用 CU wavefront 執行模式(請參閱記憶體模型)。
sramecc
-mcpu
--offload-arch
如果指定,則生成只能在具有 SRAMECC 相符設定的程序中載入和執行的程式碼。
如果未針對程式碼物件 V2 至 V3 指定,則生成可以在啟用 SRAMECC 的程序中載入和執行的程式碼。
如果未針對程式碼物件 V4 或更高版本指定,則生成可以在具有 SRAMECC 任一設定的程序中載入和執行的程式碼。
tgsplit
-m[no-]tgsplit
啟用/停用生成假設工作群組以 threadgroup 分割模式啟動的程式碼。啟用後,工作群組的 wave 可能會在不同的 CU 中啟動。
wavefrontsize64
-m[no-]wavefrontsize64
控制為核心生成程式碼時使用的 wavefront 大小。停用時,使用原生 wavefront 大小 32;啟用時,使用 wavefront 大小 64。
xnack
-mcpu
--offload-arch
如果指定,則生成只能在具有 XNACK 重播相符設定的程序中載入和執行的程式碼。
如果未針對程式碼物件 V2 至 V3 指定,則生成可以在啟用 XNACK 重播的程序中載入和執行的程式碼。
如果未針對程式碼物件 V4 或更高版本指定,則生成可以在具有 XNACK 重播任一設定的程序中載入和執行的程式碼。
XNACK 重播可用於按需分頁和頁面遷移。如果在裝置中啟用,則如果發生頁面錯誤,除非使用啟用 XNACK 重播生成,或針對程式碼物件 V4 或更高版本生成且未指定 XNACK 重播,否則程式碼可能執行不正確。在未啟用 XNACK 重播的裝置上執行使用啟用 XNACK 重播生成的程式碼,或針對程式碼物件 V4 或更高版本生成且未指定 XNACK 重播的程式碼,將正確執行,但效能可能不如針對停用 XNACK 重播生成的程式碼。
目標 ID¶
AMDGPU 支援目標 ID。請參閱Clang Offload Bundler以取得一般描述。AMDGPU 目標特定資訊為
- 處理器
是在AMDGPU 處理器中指定的 AMDGPU 處理器或替代處理器名稱。非標準形式的目標 ID 允許主要處理器和替代處理器名稱。標準形式的目標 ID 僅允許主要處理器名稱。
- 目標功能
是在AMDGPU 目標功能中指定的目標功能名稱,處理器支援該功能。每個處理器支援的目標功能在AMDGPU 處理器中指定。可以在目標 ID 中指定的那些功能標記為由
-mcpu
和--offload-arch
控制。每個目標功能在目標 ID 中最多只能出現一次。非標準形式的目標 ID 允許以任何順序指定目標功能。標準形式的目標 ID 要求以字母順序指定目標功能。
程式碼物件 V2 至 V3 目標 ID¶
程式碼物件 V2 至 V3 的目標 ID 語法與Clang Offload Bundler中定義的語法相同,但用於.amdgcn_target <target-triple> “-” <target-id>組譯器指令和捆綁條目 ID 時除外。在這些情況下,它具有以下 BNF 語法
<target-id> ::== <processor> ( "+" <target-feature> )*
其中,如果目標功能為Off,則省略,如果為On或Any,則存在。
注意
程式碼物件 V2 至 V3 無法表示 Any,並將其視為與 On 相同。
嵌入捆綁的程式碼物件¶
AMDGPU 支援 HIP 和 OpenMP 語言,這些語言執行程式碼物件嵌入,如Clang Offload Bundler中所述。
注意
用於捆綁條目 ID 的程式碼物件 V2 至 V3 的目標 ID 語法與其他地方使用的語法不同。請參閱程式碼物件 V2 至 V3 目標 ID。
位址空間¶
AMDGPU 架構支援許多記憶體位址空間。位址空間名稱使用 OpenCL 標準名稱,並新增了一些名稱。
AMDGPU 位址空間對應於 LLVM IR 中使用的目標架構特定 LLVM 位址空間編號。
AMDGPU 位址空間在AMDGPU 位址空間中描述。對於 amdgcn
目標,僅支援 64 位元程序位址空間。
表 25 AMDGPU 位址空間¶ 64 位元程序位址空間
位址空間名稱
LLVM IR 位址空間編號
HSA 區段名稱
硬體名稱
位址大小
NULL 值
通用
0
flat
flat
64
0x0000000000000000
全域
1
global
global
64
0x0000000000000000
區域
2
不適用
GDS
32
未針對 AMDHSA 實作
本地
3
group
LDS
32
0xFFFFFFFF
常數
4
constant
與全域相同
64
0x0000000000000000
私有
5
private
scratch
32
0xFFFFFFFF
常數 32 位元
6
待辦事項
0x00000000
緩衝區 Fat 指標
7
不適用
不適用
160
0
緩衝區資源
8
不適用
V#
128
0x00000000000000000000000000000000
緩衝區跨步指標(實驗性)
9
待辦事項
Streamout 暫存器
128
不適用
GS_REGS
- 通用
除非AMDGPU 處理器的目標屬性欄位指定不支援通用位址空間,否則支援通用位址空間。
通用位址空間使用硬體 flat 位址支援兩個固定範圍的虛擬位址(私有和本地 aperture),這些位址位於可定址全域記憶體範圍之外,以將 flat 位址映射到私有或本地位址。這使用 FLAT 指令,這些指令可以採用 flat 位址並存取全域、私有 (scratch) 和群組 (LDS) 記憶體,具體取決於位址是否在其中一個 aperture 範圍內。
對 scratch 進行 Flat 存取需要硬體 aperture 設定以及核心序言中的設定(請參閱Flat Scratch)。對 LDS 進行 Flat 存取需要硬體 aperture 設定和 M0 (GFX7-GFX8) 暫存器設定(請參閱M0)。
若要在私有或群組位址空間位址(稱為區段位址)和 flat 位址之間轉換,可以使用對應 aperture 的基準位址。對於 GFX7-GFX8,這些位址可在HSA AQL 佇列中取得,可以使用佇列指標 SGPR(請參閱初始核心執行狀態)取得其位址。對於 GFX9-GFX11,aperture 基準位址可直接作為內嵌常數暫存器
SRC_SHARED_BASE/LIMIT
和SRC_PRIVATE_BASE/LIMIT
使用。在 64 位元位址模式下,aperture 大小為 2^32 位元組,基準與 2^32 對齊,這使得從 flat 到區段或從區段到 flat 的轉換更容易。全域位址空間位址在用作 flat 位址時具有相同的值,因此不需要轉換。
- 全域和常數
全域和常數位址空間都使用全域虛擬位址,這與 CPU 使用的虛擬位址空間相同。但是,某些虛擬位址可能僅可由 CPU 存取,某些僅可由 GPU 存取,而某些則可由兩者存取。
使用常數位址空間表示資料在核心執行期間不會變更。這允許使用純量讀取指令。由於常數位址空間只能在主機端修改,因此從常數位址空間載入的通用指標可以安全地假定為全域指標,因為只有裝置全域記憶體在主機端可見和管理。向量和純量 L1 快取會在每次核心分派執行之前使揮發性資料失效,以允許常數記憶體在核心分派之間變更值。
- 區域
區域位址空間使用硬體全域資料儲存區 (GDS)。在相同裝置上執行的所有 wavefront,對於任何給定的區域位址都將存取相同的記憶體。然而,由不同裝置上執行的 wavefront 存取相同的區域位址,將存取不同的記憶體。它的效能比全域記憶體更高。它由執行時期配置。資料儲存區 (DS) 指令可用於存取它。
- 本地
區域位址空間使用硬體區域資料儲存區 (LDS),它在硬體建立工作群組的 wavefront 時自動配置,並在工作群組的所有 wavefront 終止時釋放。屬於相同工作群組的所有 wavefront,對於任何給定的區域位址都將存取相同的記憶體。然而,由不同工作群組的 wavefront 存取相同的區域位址,將存取不同的記憶體。它的效能比全域記憶體更高。資料儲存區 (DS) 指令可用於存取它。
- 私有
私有位址空間使用硬體暫存記憶體支援,它在建立 wavefront 時自動配置記憶體,並在 wavefront 終止時釋放記憶體。wavefront 的 lane 對於任何給定的私有位址所存取的記憶體,會與相同或不同 wavefront 的另一個 lane 對於相同私有位址所存取的記憶體不同。
如果核心調度使用暫存記憶體,則硬體會從執行時期為每個 wavefront 配置的後備記憶體池中配置記憶體。wavefront 的 lane 使用 dword (4 位元組) 交錯方式存取此記憶體。從私有位址到後備記憶體位址的映射關係是
wavefront-scratch-base + ((private-address / 4) * wavefront-size * 4) + (wavefront-lane-id * 4) + (private-address % 4)
如果 wavefront 的每個 lane 都存取相同的私有位址,則交錯會導致存取相鄰的 dword,因此需要提取的快取線更少。
wavefront 暫存基底位址由 wavefront 決定的方式有多種(請參閱 初始核心執行狀態)。
可以使用帶有暫存緩衝區描述符和每個 wavefront 暫存偏移的緩衝區指令、暫存指令或平面指令,以交錯方式存取暫存記憶體。除了 GFX9-GFX11 中的平面和暫存指令外,不支援多 dword 存取。
在 wavefront 的其他 lane 中操作堆疊值的程式碼,例如透過將堆疊指標
addrspacecast
轉換為通用指標並取得到達其他 lane 的偏移量,或透過顯式建構暫存緩衝區描述符,當它修改其他 lane 的暫存值時,會觸發未定義的行為。編譯器可能會假設此類修改不會發生。當使用程式碼物件 V5 時,可以使用LIBOMPTARGET_STACK_SIZE
來提供私有區段大小(以位元組為單位),以用於使用動態堆疊的情況。- 常數 32 位元
待辦事項
- 緩衝區 Fat 指標
緩衝區胖指標是一種實驗性的位址空間,目前在後端不支援。它公開了一個非整數指標,未來旨在支援 128 位元緩衝區描述符加上 32 位元緩衝區偏移量的建模(總共封裝一個 160 位元指標),允許使用正常的 LLVM 載入/儲存/原子操作來建模在圖形工作負載中大量使用的緩衝區描述符,目標是後端。
用於建構緩衝區胖指標的緩衝區描述符必須是原始的:步幅必須為 0,“add tid” 標誌必須為 0,swizzle 啟用位元必須關閉,並且範圍必須以位元組為單位測量。(在可能禁用邊界檢查的子目標上,緩衝區胖指標可能會選擇啟用或不啟用它)。gfx942 中引入的快取 swizzle 支援可以使用。
這些指標可以透過從緩衝區資源 (ptr addrspace(8)) 進行 addrspacecast 或使用 llvm.amdgcn.make.buffer.rsrc 直接產生 ptr addrspace(7) 來建立,這會產生初始偏移量為 0 的緩衝區胖指標,並防止位址空間轉換被重寫掉。
- 緩衝區資源
位址空間 8 中的緩衝區資源指標是 AMDGPU IR 中表示緩衝區描述符的較新形式,取代了先前作為 <4 x i32> 的表示形式。它是一個非整數指標,表示 128 位元緩衝區描述符資源 (V#)。
由於一般來說,緩衝區資源支援 LLVM 中不易表示的複雜定址模式(例如對結構化緩衝區的隱式 swizzle 存取),因此對緩衝區資源執行非平凡的位址計算(例如
getelementptr
操作)是非法的。它們可以傳遞給 AMDGPU 緩衝區內建函數,並且可以在i128
之間相互轉換。允許將緩衝區資源轉換為緩衝區胖指標,並新增 0 的偏移量。
緩衝區資源可以使用 llvm.amdgcn.make.buffer.rsrc 內建函數從 64 位元指標(應為通用或全域)建立,該內建函數採用指標(成為資源的基底)、儲存在 V# 的位元 63:48 中的 16 位元步幅(和 swizzle 控制)欄位、32 位元 NumRecords/範圍欄位(位元 95:64)和 32 位元標誌欄位(位元 127:96)。這些欄位的具體解釋因目標架構而異,並在 ISA 描述中詳細說明。
- 緩衝區步幅指標
緩衝區索引指標是一種實驗性的位址空間。它表示一個 128 位元緩衝區描述符和一個 32 位元偏移量,就像緩衝區胖指標一樣。此外,它還包含一個緩衝區索引,允許直接定址結構化元素。這些組件按此順序出現,即描述符首先出現,然後是 32 位元偏移量,然後是 32 位元索引。
緩衝區描述符中的位元必須滿足以下要求:步幅是結構化元素的大小,“add tid” 標誌必須為 0,並且 swizzle 啟用位元必須關閉。
這些指標可以透過從緩衝區資源 (ptr addrspace(8)) 進行 addrspacecast 或使用 llvm.amdgcn.make.buffer.rsrc 直接產生 ptr addrspace(9) 來建立,這會產生初始索引和偏移量值均為 0 的緩衝區步幅指標。這可防止位址空間轉換被重寫掉。
- Streamout 暫存器
GS NGG Streamout 指令使用的專用暫存器。暫存器檔案被建模為不同位址空間中的記憶體,因為它由類似位址的偏移量而不是具名暫存器索引,並且因為暫存器存取會影響 LGKMcnt。這是僅供編譯器使用的內部位址空間。請勿將此位址空間用於 IR 指標。
記憶體範圍¶
本節提供當目標三元組 OS 為 amdhsa
時,AMDGPU 後端記憶體模型支援的 LLVM 記憶體同步範圍(請參閱 記憶體模型 和 目標三元組)。
支援的記憶體模型基於 HSA 記憶體模型 [HSA],而 HSA 記憶體模型又基於具有範圍包含的 HRF-indirect [HRF]。先行發生關係在同步關係上是可傳遞的,與範圍無關,並且同步關係允許記憶體範圍實例是包含性的(請參閱表 AMDHSA LLVM 同步範圍)。
這與 OpenCL [OpenCL] 記憶體模型不同,後者沒有範圍包含,並且要求記憶體範圍完全匹配。但是,對於 OpenCL 來說,這是保守正確的。
表 26 AMDHSA LLVM 同步範圍¶ LLVM 同步範圍
描述
none
預設值:
system
。與其他操作同步,並參與其他操作的修改和 seq_cst 總排序(影像操作除外),適用於所有位址空間(私有或存取私有的通用位址空間除外),前提是其他操作的同步範圍是
system
.
agent
且由同一代理上的執行緒執行。
workgroup
且由同一工作群組中的執行緒執行。
wavefront
且由同一 wavefront 中的執行緒執行。
agent
與其他操作同步,並參與其他操作的修改和 seq_cst 總排序(影像操作除外),適用於所有位址空間(私有或存取私有的通用位址空間除外),前提是其他操作的同步範圍是
system
或agent
且由同一代理上的執行緒執行。
workgroup
且由同一工作群組中的執行緒執行。
wavefront
且由同一 wavefront 中的執行緒執行。
workgroup
與其他操作同步,並參與其他操作的修改和 seq_cst 總排序(影像操作除外),適用於所有位址空間(私有或存取私有的通用位址空間除外),前提是其他操作的同步範圍是
system
、agent
或workgroup
且由同一工作群組中的執行緒執行。
wavefront
且由同一 wavefront 中的執行緒執行。
wavefront
與其他操作同步,並參與其他操作的修改和 seq_cst 總排序(影像操作除外),適用於所有位址空間(私有或存取私有的通用位址空間除外),前提是其他操作的同步範圍是
system
、agent
、workgroup
或wavefront
且由同一 wavefront 中的執行緒執行。
singlethread
僅與在相同執行緒中執行的其他操作(影像操作除外)同步,並參與其他操作的修改和 seq_cst 總排序,適用於所有位址空間(例如,在訊號處理常式中)。
one-as
與
system
相同,但僅與相同位址空間內的其他操作同步。
agent-one-as
與
agent
相同,但僅與相同位址空間內的其他操作同步。
workgroup-one-as
與
workgroup
相同,但僅與相同位址空間內的其他操作同步。
wavefront-one-as
與
wavefront
相同,但僅與相同位址空間內的其他操作同步。
singlethread-one-as
與
singlethread
相同,但僅與相同位址空間內的其他操作同步。
LLVM IR 內建函數¶
AMDGPU 後端實作了以下 LLVM IR 內建函數。
本節尚在建構中 (WIP)。
LLVM 內建函數 |
描述 |
---|---|
llvm.amdgcn.sqrt |
提供對 v_sqrt_f64、v_sqrt_f32 和 v_sqrt_f16 (在支援 half 的目標上) 的直接存取。執行 sqrt 函數。 |
llvm.amdgcn.log |
提供對 v_log_f32 和 v_log_f16 (在支援 half 的目標上) 的直接存取。執行 log2 函數。 |
llvm.amdgcn.exp2 |
提供對 v_exp_f32 和 v_exp_f16 (在支援 half 的目標上) 的直接存取。執行 exp2 函數。 |
針對 half、float 和 double 實作。 |
|
針對 float 和 half(以及 float 或 half 的向量)實作。未針對 double 實作。硬體為 float 提供 1ULP 準確度,為 half 提供 0.51ULP 準確度。Float 指令本機不支援次常態輸入。 |
|
針對 double、float 和 half(以及向量)實作。 |
|
針對 float 和 half(以及向量)實作。 |
|
針對 float 和 half(以及向量)實作。 |
|
針對 float 和 half(以及向量)實作。 |
|
針對 float 和 half(以及 float 或 half 的向量)實作。未針對 double 實作。硬體為 float 提供 1ULP 準確度,為 half 提供 0.51ULP 準確度。Float 指令本機不支援次常態輸入。 |
|
已實作,必須使用 alloca 位址空間。 |
|
已實作,必須使用 alloca 位址空間。 |
|
自然浮點模式類型為 i32。這是透過使用 s_getreg_b32 從 MODE 暫存器中提取相關位元來實作的。前 10 個位元是核心浮點模式。位元 12:18 是例外遮罩。在 gfx9+ 上,位元 23 是 FP16_OVFL。與浮點指令無關的位元欄位為 0。 |
|
AMDGPU 支援兩種可獨立控制的捨入模式,具體取決於浮點類型。一種控制 float,另一種控制 double 和 half 操作。如果兩種模式相同,則傳回標準傳回值之一。如果模式不同,則傳回 12 個擴展值 之一,描述兩種模式。 不支援捨入到最接近值,遠離零的 ties。MODE 暫存器中的原始捨入模式值與 FLT_ROUNDS 值不完全匹配,因此會執行轉換。 |
|
輸入值預期為 ' |
|
傳回 AMDGPU 浮點環境的目前值。這會儲存與目前捨入模式、反常態化模式、已啟用陷阱和浮點例外相關的資訊。格式是 MODE 和 TRAPSTS 暫存器的 64 位元串連。 |
|
將浮點環境設定為指定狀態。 |
|
llvm.amdgcn.readfirstlane |
提供對 v_readfirstlane_b32 的直接存取。傳回輸入運算元中最低活動 lane 的值。目前針對 i16、i32、float、half、bfloat、<2 x i16>、<2 x half>、<2 x bfloat>、i64、double、指標、32 位元向量的倍數實作。 |
llvm.amdgcn.readlane |
提供對 v_readlane_b32 的直接存取。傳回第一個輸入運算元的指定 lane 中的值。第二個運算元指定要從哪個 lane 讀取。目前針對 i16、i32、float、half、bfloat、<2 x i16>、<2 x half>、<2 x bfloat>、i64、double、指標、32 位元向量的倍數實作。 |
llvm.amdgcn.writelane |
提供對 v_writelane_b32 的直接存取。將第一個輸入運算元中的值寫入發散輸出的指定 lane。第二個運算元指定要寫入的 lane。目前針對 i16、i32、float、half、bfloat、<2 x i16>、<2 x half>、<2 x bfloat>、i64、double、指標、32 位元向量的倍數實作。 |
llvm.amdgcn.wave.reduce.umin |
對 wavefront 中每個 lane 提供的無號值執行算術無號最小值縮減。內建函數採用第二個運算元 0 的縮減策略提示:目標預設偏好、1:迭代策略 和 2:DPP。如果目標不支援 DPP 操作(例如 gfx6/7),則將使用預設迭代策略執行縮減。內建函數目前僅針對 i32 實作。 |
llvm.amdgcn.wave.reduce.umax |
對 wavefront 中每個 lane 提供的無號值執行算術無號最大值縮減。內建函數採用第二個運算元 0 的縮減策略提示:目標預設偏好、1:迭代策略 和 2:DPP。如果目標不支援 DPP 操作(例如 gfx6/7),則將使用預設迭代策略執行縮減。內建函數目前僅針對 i32 實作。 |
llvm.amdgcn.permlane16 |
提供對 v_permlane16_b32 的直接存取。在第二個輸入運算元的列(16 個連續 lane)內執行任意收集樣式操作。第三個和第四個輸入必須是純量值。這些值組合為單個 64 位元值,表示用於在每列中 swizzle 的 lane 選擇。目前針對 i16、i32、float、half、bfloat、<2 x i16>、<2 x half>、<2 x bfloat>、i64、double、指標、32 位元向量的倍數實作。 |
llvm.amdgcn.permlanex16 |
提供對 v_permlanex16_b32 的直接存取。在第二個輸入運算元的兩列(每列 16 個連續 lane)之間執行任意收集樣式操作。第三個和第四個輸入必須是純量值。這些值組合為單個 64 位元值,表示用於在每列中 swizzle 的 lane 選擇。目前針對 i16、i32、float、half、bfloat、<2 x i16>、<2 x half>、<2 x bfloat>、i64、double、指標、32 位元向量的倍數實作。 |
llvm.amdgcn.permlane64 |
提供對 v_permlane64_b32 的直接存取。在輸入運算元的 lane 之間執行特定排列,其中 wave64 的高半部分和低半部分交換。在 wave32 模式下不執行任何操作。目前針對 i16、i32、float、half、bfloat、<2 x i16>、<2 x half>、<2 x bfloat>、i64、double、指標、32 位元向量的倍數實作。 |
llvm.amdgcn.udot2 |
在支援此類指令的目標上提供對 v_dot2_u32_u16 的直接存取。這使用兩個 v2i16 運算元執行無號點積,並與第三個 i32 運算元求和。i1 第四個運算元用於鉗制輸出。 |
llvm.amdgcn.udot4 |
在支援此類指令的目標上提供對 v_dot4_u32_u8 的直接存取。這使用兩個 i32 運算元(持有 4 個 8 位元值的向量)執行無號點積,並與第三個 i32 運算元求和。i1 第四個運算元用於鉗制輸出。 |
llvm.amdgcn.udot8 |
在支援此類指令的目標上提供對 v_dot8_u32_u4 的直接存取。這使用兩個 i32 運算元(持有 8 個 4 位元值的向量)執行無號點積,並與第三個 i32 運算元求和。i1 第四個運算元用於鉗制輸出。 |
llvm.amdgcn.sdot2 |
在支援此類指令的目標上提供對 v_dot2_i32_i16 的直接存取。這使用兩個 v2i16 運算元執行有號點積,並與第三個 i32 運算元求和。i1 第四個運算元用於鉗制輸出。在適用的情況下(例如,無鉗制),這會降低為支援它的目標的 v_dot2c_i32_i16。 |
llvm.amdgcn.sdot4 |
在支援此類指令的目標上提供對 v_dot4_i32_i8 的直接存取。這使用兩個 i32 運算元(持有 4 個 8 位元值的向量)執行有號點積,並與第三個 i32 運算元求和。i1 第四個運算元用於鉗制輸出。在適用的情況下(即,無鉗制/運算元修飾符),這會降低為支援它的目標的 v_dot4c_i32_i8。RDNA3 不提供 v_dot4_i32_i8,而是提供 v_dot4_i32_iu8,後者具有用於保存向量運算元符號的運算元。因此,此內建函數會降低為 gfx11 目標的此指令的有號版本。 |
llvm.amdgcn.sdot8 |
在支援此類指令的目標上提供對 v_dot8_u32_u4 的直接存取。這使用兩個 i32 運算元(持有 8 個 4 位元值的向量)執行有號點積,並與第三個 i32 運算元求和。i1 第四個運算元用於鉗制輸出。在適用的情況下(即,無鉗制/運算元修飾符),這會降低為支援它的目標的 v_dot8c_i32_i4。RDNA3 不提供 v_dot8_i32_i4,而是提供 v_dot4_i32_iu4,後者具有用於保存向量運算元符號的運算元。因此,此內建函數會降低為 gfx11 目標的此指令的有號版本。 |
llvm.amdgcn.sudot4 |
在 gfx11 目標上提供對 v_dot4_i32_iu8 的直接存取。這使用兩個 i32 運算元(持有 4 個 8 位元值的向量)執行點積,並與第五個 i32 運算元求和。i1 第六個運算元用於鉗制輸出。向量運算元之前的 i1 決定符號。 |
llvm.amdgcn.sudot8 |
在 gfx11 目標上提供對 v_dot8_i32_iu4 的直接存取。這使用兩個 i32 運算元(持有 8 個 4 位元值的向量)執行點積,並與第五個 i32 運算元求和。i1 第六個運算元用於鉗制輸出。向量運算元之前的 i1 決定符號。 |
llvm.amdgcn.sched.barrier |
控制在指令排程期間可能允許跨越內建函數的指令類型。參數是可用於跨越內建函數排程的指令類型的遮罩。
|
llvm.amdgcn.sched.group.barrier |
建立具有特定屬性的排程群組,以建立自訂排程管線。群組之間的排序由指令排程器強制執行。內建函數適用於內建函數之前的程式碼。內建函數採用三個值來控制排程群組的行為。
遮罩可以包含多個指令類型。設定超出有效遮罩範圍的值是未定義的行為。 組合多個 sched_group_barrier 內建函數可以在指令排程期間啟用特定指令類型的排序。例如,以下程式碼強制執行 1 個 VMEM 讀取、接著 1 個 VALU 指令,再接著 5 個 MFMA 指令的序列。 // 1 VMEM read __builtin_amdgcn_sched_group_barrier(32, 1, 0) // 1 VALU __builtin_amdgcn_sched_group_barrier(2, 1, 0) // 5 MFMA __builtin_amdgcn_sched_group_barrier(8, 5, 0) |
llvm.amdgcn.iglp.opt |
用於指令群組級並行性的實驗性內建函數。內建函數實作預定義的指令排程排序。內建函數適用於周圍的排程區域。內建函數採用一個值來指定策略。編譯器實作了兩種策略。
在排程區域中只能使用一個 iglp_opt 內建函數。iglp_opt 內建函數不能與 sched_barrier 或 sched_group_barrier 組合使用。 iglp_opt 策略實作可能會變更。 |
llvm.amdgcn.atomic.cond.sub.u32 |
在 gfx12 目標上,根據位址空間提供對 flat_atomic_cond_sub_u32、global_atomic_cond_sub_u32 和 ds_cond_sub_u32 的直接存取。僅當記憶體值大於或等於資料值時,才執行減法。 |
llvm.amdgcn.s.getpc |
提供對 s_getpc_b64 指令的存取,但即使在 s_getpc_b64 指令傳回零擴展值的處理器上,傳回值也會從底層 PC 硬體暫存器的寬度進行符號擴展。 |
llvm.amdgcn.ballot |
傳回一個位元欄位(i32 或 i64),其中包含其 i1 引數在所有活動 lane 中的結果,以及在所有非活動 lane 中的零。提供一種將 LLVM IR 中的 i1 轉換為 i32 或 i64 lane 遮罩的方法 - 硬體用於控制 EXEC 暫存器中使用之活動 lane 的位元欄位。例如,ballot(i1 true) 傳回 EXEC 遮罩。 |
llvm.amdgcn.mfma.scale.f32.16x16x128.f8f6f4 |
發射 v_mfma_scale_f32_16x16x128_f8f6f4 以設定縮放因子。最後 4 個運算元對應於縮放輸入。
|
llvm.amdgcn.mfma.scale.f32.32x32x64.f8f6f4 |
發射 v_mfma_scale_f32_32x32x64_f8f6f4 |
llvm.amdgcn.permlane16.swap |
在支援的目標上提供對 v_permlane16_swap_b32 指令的直接存取。交換前 2 個運算元的 lane 之間的值。第一個運算元的奇數列與第二個運算元的偶數列交換(一列為 16 個 lane)。傳回交換暫存器的配對。傳回的第一個元素對應於第一個引數的交換元素。 |
llvm.amdgcn.permlane32.swap |
在支援的目標上提供對 v_permlane32_swap_b32 指令的直接存取。交換前 2 個運算元的 lane 之間的值。第一個運算元的第 2 列和第 3 列與第二個運算元的第 0 列和第 1 列交換(一列為 16 個 lane)。傳回交換暫存器的配對。傳回的第一個元素對應於第一個引數的交換元素。 |
llvm.amdgcn.mov.dpp |
llvm.amdgcn.mov.dpp.`<type>` 內建函數表示 AMDGPU 中的 mov.dpp 操作。此操作已棄用,可以使用 llvm.amdgcn.update.dpp 替換。 |
llvm.amdgcn.update.dpp |
llvm.amdgcn.update.dpp.`<type>` 內建函數表示 AMDGPU 中的 update.dpp 操作。它採用舊值、來源運算元、DPP 控制運算元、列遮罩、bank 遮罩和邊界控制。支援各種資料類型,包括 bf16、f16、f32、f64、i16、i32、i64、p0、p3、p5、v2f16、v2f32、v2i16、v2i32、v2p0、v3i32、v4i32、v8f16。此操作等效於 v_mov_b32 操作序列。在未來使用中,它優先於 llvm.amdgcn.mov.dpp.`<type>`。llvm.amdgcn.update.dpp.<type> <old> <src> <dpp_ctrl> <row_mask> <bank_mask> <bound_ctrl> 應等效於:- v_mov_b32 <dest> <old> - v_mov_b32 <dest> <src> <dpp_ctrl> <row_mask> <bank_mask> <bound_ctrl> |
LLVM IR Metadata¶
AMDGPU 後端實作了以下目標自訂 LLVM IR metadata。
‘amdgpu.last.use
’ Metadata¶
在支援 TH_LOAD_LU 時間性提示的載入指令上設定 TH_LOAD_LU 時間性提示。優先於非時間性提示 (TH_LOAD_NT)。這不帶任何引數。
%val = load i32, ptr %in, align 4, !amdgpu.last.use !{}
‘amdgpu.no.remote.memory
’ Metadata¶
斷言記憶體操作不會存取主機記憶體或遠端連線的對等裝置記憶體中的位元組(位址必須是裝置本機的)。這旨在用於 atomicrmw 和其他原子指令。這是發射某些子目標上某些 系統範圍 原子操作的本機硬體指令所必需的。對於大多數整數原子操作,這是發射本機原子指令的充分限制。
沒有 metadata 的 atomicrmw 將被保守地視為需要在所有情況下保留操作行為。這通常會與 !amdgpu.no.fine.grained.memory 結合使用。
; Indicates the atomic does not access fine-grained memory, or
; remote device memory.
%old0 = atomicrmw sub ptr %ptr0, i32 1 acquire, !amdgpu.no.fine.grained.memory !0, !amdgpu.no.remote.memory !0
; Indicates the atomic does not access peer device memory.
%old2 = atomicrmw sub ptr %ptr2, i32 1 acquire, !amdgpu.no.remote.memory !0
!0 = !{}
‘amdgpu.no.fine.grained.memory
’ Metadata¶
聲明記憶體存取不會存取在細粒度分配記憶體中分配的位元組。這旨在與 atomicrmw 和其他原子指令一起使用。 為了在某些子目標上針對某些 系統範圍 原子操作發出原生硬體指令,這是必需的。 沒有 metadata 的 atomicrmw 將被保守地視為在所有情況下都必須保留操作行為。 這通常會與 !amdgpu.no.remote.memory.access 結合使用。
; Indicates the access does not access fine-grained memory, or
; remote device memory.
%old0 = atomicrmw sub ptr %ptr0, i32 1 acquire, !amdgpu.no.fine.grained.memory !0, !amdgpu.no.remote.memory.access !0
; Indicates the access does not access fine-grained memory
%old2 = atomicrmw sub ptr %ptr2, i32 1 acquire, !amdgpu.no.fine.grained.memory !0
!0 = !{}
‘amdgpu.ignore.denormal.mode
’ Metadata¶
用於 atomicrmw 浮點運算。 表示次常態輸入和結果的處理並不重要,並且可能與預期的浮點模式不一致。 為了在某些目標上針對某些位址空間發出原生原子指令,這是必要的,在這些位址空間中,浮點次常態值會被無條件清除。 這通常與 !amdgpu.no.remote.memory.access 和 !amdgpu.no.fine.grained.memory 結合使用。
%res0 = atomicrmw fadd ptr addrspace(1) %ptr, float %value seq_cst, align 4, !amdgpu.ignore.denormal.mode !0
%res1 = atomicrmw fadd ptr addrspace(1) %ptr, float %value seq_cst, align 4, !amdgpu.ignore.denormal.mode !0, !amdgpu.no.fine.grained.memory !0, !amdgpu.no.remote.memory.access !0
!0 = !{}
LLVM IR 屬性¶
AMDGPU 後端支援下列 LLVM IR 屬性。
表 28 AMDGPU LLVM IR 屬性¶ LLVM 屬性
描述
“amdgpu-flat-work-group-size”=”min,max”
指定在核心程式調度時將指定的最小和最大平面工作群組大小。 由
amdgpu_flat_work_group_size
CLANG 屬性 [CLANG-ATTR] 產生。 IR 隱含的預設值為 1,1024。 Clang 可能會根據語言預設值發出具有更嚴格限制的此屬性。 如果在執行期間的任何時間點,實際的區塊或工作群組大小超過限制,則行為未定義。 例如,即使只有一個活動執行緒,但執行緒本地 ID 超過限制,行為也是未定義的。“amdgpu-implicitarg-num-bytes”=”n”
要添加到核心引數區塊大小以用於隱含引數的核心引數位元組數。 這因作業系統和語言而異(對於 OpenCL,請參閱 針對 AMDHSA OS 附加的 OpenCL 核心隱含引數)。
“amdgpu-num-sgpr”=”n”
指定要使用的 SGPR 數量。 由
amdgpu_num_sgpr
CLANG 屬性 [CLANG-ATTR] 產生。“amdgpu-num-vgpr”=”n”
指定要使用的 VGPR 數量。 由
amdgpu_num_vgpr
CLANG 屬性 [CLANG-ATTR] 產生。“amdgpu-waves-per-eu”=”m,n”
指定每個執行單元的最小和最大波前數量。 由
amdgpu_waves_per_eu
CLANG 屬性 [CLANG-ATTR] 產生。 這是一個最佳化提示,後端可能無法滿足請求。 如果指定的範圍與函數的 “amdgpu-flat-work-group-size” 值不相容,則工作群組大小隱含的佔用率界限優先。“amdgpu-ieee” true/false。
僅限 GFX6-GFX11 指定函數是否期望在進入時設定模式暫存器的 IEEE 欄位。 覆蓋呼叫慣例的預設值。
“amdgpu-dx10-clamp” true/false。
僅限 GFX6-GFX11 指定函數是否期望在進入時設定模式暫存器的 DX10_CLAMP 欄位。 覆蓋呼叫慣例的預設值。
“amdgpu-no-workitem-id-x”
表示函數不依賴 llvm.amdgcn.workitem.id.x 內建函數的值。 如果函數標記了此屬性,或通過標記了此屬性的呼叫站點到達,並且呼叫了該內建函數,則程式的行為是未定義的。 (此處使用全程式未定義行為,例如,預先載入的暫存器集合中缺少所需的工作項目 ID 可能意味著所有其他預先載入的暫存器都比編譯假設的要早。) 後端通常可以在程式碼產生期間推斷出這一點,因此通常前端標記具有此功能的函數沒有任何好處。
“amdgpu-no-workitem-id-y”
與 amdgpu-no-workitem-id-x 相同,但適用於 llvm.amdgcn.workitem.id.y 內建函數。
“amdgpu-no-workitem-id-z”
與 amdgpu-no-workitem-id-x 相同,但適用於 llvm.amdgcn.workitem.id.z 內建函數。
“amdgpu-no-workgroup-id-x”
與 amdgpu-no-workitem-id-x 相同,但適用於 llvm.amdgcn.workgroup.id.x 內建函數。
“amdgpu-no-workgroup-id-y”
與 amdgpu-no-workitem-id-x 相同,但適用於 llvm.amdgcn.workgroup.id.y 內建函數。
“amdgpu-no-workgroup-id-z”
與 amdgpu-no-workitem-id-x 相同,但適用於 llvm.amdgcn.workgroup.id.z 內建函數。
“amdgpu-no-dispatch-ptr”
與 amdgpu-no-workitem-id-x 相同,但適用於 llvm.amdgcn.dispatch.ptr 內建函數。
“amdgpu-no-implicitarg-ptr”
與 amdgpu-no-workitem-id-x 相同,但適用於 llvm.amdgcn.implicitarg.ptr 內建函數。
“amdgpu-no-dispatch-id”
與 amdgpu-no-workitem-id-x 相同,但適用於 llvm.amdgcn.dispatch.id 內建函數。
“amdgpu-no-queue-ptr”
與 amdgpu-no-workitem-id-x 類似,但適用於 llvm.amdgcn.queue.ptr 內建函數。 請注意,與其他 ABI 提示屬性不同,在 intrinsic 呼叫未直接出現在程式中的情況下,可能需要佇列指標。 某些子目標需要佇列指標來處理某些位址空間轉換,以及 llvm.amdgcn.is.shared、llvm.amdgcn.is.private、llvm.trap 和 llvm.debug 內建函數。
“amdgpu-no-hostcall-ptr”
與 amdgpu-no-implicitarg-ptr 類似,但特定於隱含核心引數,該引數保存指向 hostcall 緩衝區的指標。 如果此屬性不存在,則也會移除 amdgpu-no-implicitarg-ptr。
“amdgpu-no-heap-ptr”
與 amdgpu-no-implicitarg-ptr 類似,但特定於隱含核心引數,該引數保存指向符合 malloc/free 裝置函式庫 V1 版本實作要求的已初始化記憶體緩衝區的指標。 如果此屬性不存在,則也會移除 amdgpu-no-implicitarg-ptr。
“amdgpu-no-multigrid-sync-arg”
與 amdgpu-no-implicitarg-ptr 類似,但特定於隱含核心引數,該引數保存多重網格同步指標。 如果此屬性不存在,則也會移除 amdgpu-no-implicitarg-ptr。
“amdgpu-no-default-queue”
與 amdgpu-no-implicitarg-ptr 類似,但特定於隱含核心引數,該引數保存預設佇列指標。 如果此屬性不存在,則也會移除 amdgpu-no-implicitarg-ptr。
“amdgpu-no-completion-action”
與 amdgpu-no-implicitarg-ptr 類似,但特定於隱含核心引數,該引數保存完成動作指標。 如果此屬性不存在,則也會移除 amdgpu-no-implicitarg-ptr。
“amdgpu-lds-size”=”min[,max]”
Min 是在位址零的本地資料儲存區中將分配的最小位元組數。 變數使用絕對符號 metadata 在此框架內分配,主要由 AMDGPULowerModuleLDS 傳遞。 可選的 max 是將分配的最大位元組數。 請注意,min==max 表示無法將更多變數添加到框架中。 這是 LDS 變數如何降低的內部細節,語言前端不應設定此屬性。
“amdgpu-gds-size”
預期在進入時在 GDS 記憶體開始處分配的位元組數。
“amdgpu-git-ptr-high”
AMDPAL OS 類型的全域資訊表位址的硬連線高半部分。 0xffffffff 表示沒有硬連線高半部分,因為目前的硬體只允許 16 位元值。
“amdgpu-32bit-address-high-bits”
對於實際上被截斷的 64 位元位址的 32 位元位址空間(即 addrspace(6))假設的高 32 位元。
“amdgpu-color-export”
如果設定為 1,則表示著色器匯出顏色資訊。 對於 amdgpu_ps 預設為 1,對於其他呼叫慣例預設為 0。 決定當著色器通過終止通道提前終止時,空匯出的必要性和類型。
“amdgpu-depth-export”
如果設定為 1,則表示著色器匯出深度資訊。 決定當著色器通過終止通道提前終止時,空匯出的必要性和類型。 當沒有可用的空匯出目標時,僅深度著色器將匯出到深度通道 (GFX11+)。
“InitialPSInputAddr”
為 amdgpu_ps 著色器設定 spi_ps_input_addr 暫存器的初始值。 由此值啟用的任何位元都將在最終暫存器值中啟用。
“amdgpu-wave-priority-threshold”
調整波前優先順序的 VALU 指令計數閾值。 如果超過,則在著色器函數的開始處暫時提高波前優先順序,直到其最後的 VMEM 指令,以允許較新的波前也發出其 VMEM 指令。
“amdgpu-memory-bound”
由後端內部設定
“amdgpu-wave-limiter”
由後端內部設定
“amdgpu-unroll-threshold”
設定此函數內迴圈展開的基本成本閾值偏好,預設值為 300。 實際閾值可能會因每個迴圈的 metadata 而異,或因啟發式方法而降低。
“amdgpu-max-num-workgroups”=”x,y,z”
指定核心程式調度在 X、Y 和 Z 維度中的最大工作群組數。 每個數字必須 >= 1。 由
amdgpu_max_num_work_groups
CLANG 屬性 [CLANG-ATTR] 產生。 僅當所有三個數字都 >= 1 時,Clang 才會發出此屬性。“amdgpu-hidden-argument”
此屬性在後端內部使用,用於將函數引數標記為隱藏。 隱藏引數由編譯器管理,並且不是使用者提供的顯式引數的一部分。
“amdgpu-agpr-alloc”=”min(,max)”
指示要提供的 AGPR 數量的最小和最大範圍以進行分配。 這些值將四捨五入到下一個分配粒度 (4) 的倍數。 最小值被解釋為函數分配所需的最小 AGPR 數量(即,函數所需暫存器不超過 min)。 如果僅指定一個值,則將其解釋為最小暫存器預算。 最大值將限制分配以使用不超過 max AGPR。
如果滿足這些值會違反其他分配限制,則可能會忽略這些值。
如果通過任何標記有此屬性較高值的函數到達需要超過下限的 AGPR 的函數,則行為未定義。 最小值 0 表示函數不需要任何 AGPR。
這僅與支援 accum_offset (gfx90a+) 的 AGPR 目標相關。
“amdgpu-sgpr-hazard-wait”
如果設定為 0,則停用 SGPR 危害等待插入。 僅用於測試 SGPR 危害等待的效能影響。
“amdgpu-sgpr-hazard-boundary-cull”
在函數呼叫邊界啟用插入 SGPR 危害剔除序列。 剔除序列減少了未來危害等待,但具有效能成本。
“amdgpu-sgpr-hazard-mem-wait-cull”
在記憶體等待之前啟用插入 SGPR 危害剔除序列。 剔除序列減少了未來危害等待,但具有效能成本。 嘗試通過與記憶體存取重疊來攤銷成本。
“amdgpu-sgpr-hazard-mem-wait-cull-threshold”
設定在記憶體等待時插入剔除序列之前必須存在的活動 SGPR 危害的數量。
呼叫慣例¶
AMDGPU 後端支援下列呼叫慣例
表 29 AMDGPU 呼叫慣例¶ 呼叫慣例
描述
ccc
C 呼叫慣例。 預設使用。 有關更多詳細資訊,請參閱 非核心函數。
fastcc
快速呼叫慣例。 與
ccc
大致相同。
coldcc
冷呼叫慣例。 與
ccc
大致相同。
amdgpu_cs
用於 Mesa/AMDPAL 計算著色器。 ..TODO:: 描述。
amdgpu_cs_chain
與
amdgpu_cs
類似,但差異如下所述。具有此呼叫慣例的函數不能直接呼叫。 它們必須通過
llvm.amdgcn.cs.chain
內建函數啟動。如果引數具有
inreg
屬性,則在 SGPR 中傳遞引數,從 s0 開始;否則在 VGPR 中傳遞引數,從 v8 開始。 不允許使用比子目標中可用的 SGPR 或 VGPR 更多的數量。 在使用暫存緩衝區描述符的子目標上(而不是scratch_{load,store}_*
指令),暫存緩衝區描述符在 s[48:51] 中傳遞。 這將 SGPR /inreg
引數限制為相當於 48 個 dword; 不允許使用超過此數量的引數。返回類型必須為 void。 不支援 Varargs、sret、byval、byref、inalloca、preallocated。
純量暫存器以及 v0-v7 中的值不會保留。 從 v8 開始的 VGPR 中的值對於活動通道不會保留,但當使用 WWM 時,必須由被呼叫者為非活動通道保存(一個值得注意的例外是在函數中使用 llvm.amdgcn.init.whole.wave 內建函數時 - 在這種情況下,後端假設進入時沒有非活動通道; 任何需要保留的非活動通道都必須顯式地存在於 IR 中)。
波前暫存在函數邊界處為「空」。 沒有堆疊指標輸入或輸出值,但函數可以自由使用從初始堆疊指標開始的暫存。 允許呼叫
amdgpu_gfx
函數,並且其行為與amdgpu_cs
函數中的行為相同。所有計數器 (
lgkmcnt
、vmcnt
、storecnt
等) 在函數進入時都假定為未知狀態。一個函數可能有多個出口(例如,一個鏈式出口和一個普通的
ret void
,用於波前結束時),但所有llvm.amdgcn.cs.chain
出口都必須在統一控制流程中。
amdgpu_cs_chain_preserve
與
amdgpu_cs_chain
相同,但從 v8 開始的 VGPR 的活動通道會被保留。 不允許呼叫amdgpu_gfx
函數,並且任何對llvm.amdgcn.cs.chain
的呼叫都不能傳遞比呼叫者的 VGPR 函數參數更多的 VGPR 引數。
amdgpu_es
如果幾何圖形正在使用中,則用於幾何著色器之前的 AMDPAL 著色器階段。 因此,如果曲面細分正在使用中,則為域(= 曲面細分評估)著色器,否則為頂點著色器。 ..TODO:: 描述。
amdgpu_gfx
用於 AMD 圖形目標。 具有此呼叫慣例的函數不能用作進入點。 ..TODO:: 描述。
amdgpu_gs
用於 Mesa/AMDPAL 幾何著色器。 ..TODO:: 描述。
amdgpu_hs
用於 Mesa/AMDPAL 外殼著色器(= 曲面細分控制著色器)。 ..TODO:: 描述。
amdgpu_kernel
請參閱 核心函數
amdgpu_ls
如果曲面細分正在使用中,則用於 AMDPAL 頂點著色器。 ..TODO:: 描述。
amdgpu_ps
用於 Mesa/AMDPAL 像素著色器。 ..TODO:: 描述。
amdgpu_vs
用於光柵化之前的 Mesa/AMDPAL 最後一個著色器階段(如果曲面細分和幾何圖形未使用,則為頂點著色器,否則如果需要,則為複製著色器)。 ..TODO:: 描述。
AMDGPU MCExpr¶
作為 AMDGPU MC 層的一部分,AMDGPU 提供了以下目標特定的 MCExpr
。
表 30 AMDGPU MCExpr 類型:¶ MCExpr
運算元
傳回值
max(arg, ...)
1 或更多
可變參數符號運算,傳回其所有引數的最大值。
or(arg, ...)
1 或更多
可變參數符號運算,傳回其所有引數的按位或結果。
函數資源使用量¶
函數的資源使用量取決於其每個被呼叫者的資源使用量。 用於表示資源使用量的表達式通過傳播每個被呼叫者的等效表達式來反映這一點。 這些表達式在編譯為組合語言或物件格式時由編譯器作為符號發出,不應被覆蓋或重新定義。
以下描述了所有發出的函數資源使用量符號
表 31 函數資源使用量:¶ 符號
類型
描述
範例
<function_name>.num_vgpr
整數
<function_name> 使用的 VGPR 數量,自身及其被呼叫者的 VGPR 使用量的最壞情況
.set foo.num_vgpr, max(32, bar.num_vgpr, baz.num_vgpr)
<function_name>.num_agpr
整數
<function_name> 使用的 AGPR 數量,自身及其被呼叫者的 AGPR 使用量的最壞情況
.set foo.num_agpr, max(35, bar.num_agpr)
<function_name>.numbered_sgpr
整數
<function_name> 使用的 SGPR 數量,自身及其被呼叫者的 SGPR 使用量的最壞情況(不包含任何隱含使用的 SGPR)
.set foo.num_sgpr, 21
<function_name>.private_seg_size
整數
<function_name> 所需的總堆疊大小,表達式為本地使用的堆疊大小 + 最壞情況的被呼叫者
.set foo.private_seg_size, 16+max(bar.private_seg_size, baz.private_seg_size)
<function_name>.uses_vcc
布林值
<function_name> 或其任何被呼叫者是否使用 vcc
.set foo.uses_vcc, or(0, bar.uses_vcc)
<function_name>.uses_flat_scratch
布林值
<function_name> 或其任何被呼叫者是否使用平面暫存
.set foo.uses_flat_scratch, 1
<function_name>.has_dyn_sized_stack
布林值
<function_name> 或其任何被呼叫者是否為動態大小
.set foo.has_dyn_sized_stack, 1
<function_name>.has_recursion
布林值
<function_name> 或其任何被呼叫者是否包含遞迴
.set foo.has_recursion, 0
<function_name>.has_indirect_call
布林值
<function_name> 或其任何被呼叫者是否包含間接呼叫
.set foo.has_indirect_call, max(0, bar.has_indirect_call)
此外,還發出了三個符號,描述編譯單元的最壞情況(即最大值)num_vgpr
、num_agpr
和 numbered_sgpr
,這些符號可以被引用並用於上述符號表達式。 這三個符號是 amdgcn.max_num_vgpr
、amdgcn.max_num_agpr
和 amdgcn.max_num_sgpr
。
ELF 程式碼物件¶
AMDGPU 後端產生標準 ELF [ELF] 可重定位程式碼物件,該物件可以由 lld
連結以產生標準 ELF 共享程式碼物件,該物件可以載入並在 AMDGPU 目標上執行。
標頭¶
AMDGPU 後端使用以下 ELF 標頭
表 32 AMDGPU ELF 標頭¶ 欄位
值
e_ident[EI_CLASS]
ELFCLASS64
e_ident[EI_DATA]
ELFDATA2LSB
e_ident[EI_OSABI]
ELFOSABI_NONE
ELFOSABI_AMDGPU_HSA
ELFOSABI_AMDGPU_PAL
ELFOSABI_AMDGPU_MESA3D
e_ident[EI_ABIVERSION]
ELFABIVERSION_AMDGPU_HSA_V2
ELFABIVERSION_AMDGPU_HSA_V3
ELFABIVERSION_AMDGPU_HSA_V4
ELFABIVERSION_AMDGPU_HSA_V5
ELFABIVERSION_AMDGPU_HSA_V6
ELFABIVERSION_AMDGPU_PAL
ELFABIVERSION_AMDGPU_MESA3D
e_type
ET_REL
ET_DYN
e_machine
EM_AMDGPU
e_entry
0
e_flags
請參閱 程式碼物件 V2 的 AMDGPU ELF 標頭 e_flags、 程式碼物件 V3 的 AMDGPU ELF 標頭 e_flags、 程式碼物件 V4 和 V5 的 AMDGPU ELF 標頭 e_flags 和 程式碼物件 V6 及更高版本的 AMDGPU ELF 標頭 e_flags
表 33 AMDGPU ELF 標頭列舉值¶ 名稱
值
EM_AMDGPU
224
ELFOSABI_NONE
0
ELFOSABI_AMDGPU_HSA
64
ELFOSABI_AMDGPU_PAL
65
ELFOSABI_AMDGPU_MESA3D
66
ELFABIVERSION_AMDGPU_HSA_V2
0
ELFABIVERSION_AMDGPU_HSA_V3
1
ELFABIVERSION_AMDGPU_HSA_V4
2
ELFABIVERSION_AMDGPU_HSA_V5
3
ELFABIVERSION_AMDGPU_HSA_V6
4
ELFABIVERSION_AMDGPU_PAL
0
ELFABIVERSION_AMDGPU_MESA3D
0
e_ident[EI_CLASS]
ELF 類別為
ELFCLASS32
用於r600
架構。ELFCLASS64
用於amdgcn
架構,該架構僅支援 64 位元處理程序位址空間應用程式。
e_ident[EI_DATA]
所有 AMDGPU 目標都使用
ELFDATA2LSB
進行小端位元組排序。e_ident[EI_OSABI]
以下 AMDGPU 目標架構特定 OS ABI 之一(請參閱 AMDGPU 作業系統)
ELFOSABI_NONE
用於未知 OS。ELFOSABI_AMDGPU_HSA
用於amdhsa
OS。ELFOSABI_AMDGPU_PAL
用於amdpal
OS。ELFOSABI_AMDGPU_MESA3D
用於mesa3D
OS。
e_ident[EI_ABIVERSION]
程式碼物件符合的 AMDGPU 目標架構特定 OS ABI 的 ABI 版本
ELFABIVERSION_AMDGPU_HSA_V2
用於指定程式碼物件 V2 的 AMD HSA 執行階段 ABI 版本。 此版本的 LLVM 無法再發出。ELFABIVERSION_AMDGPU_HSA_V3
用於指定程式碼物件 V3 的 AMD HSA 執行階段 ABI 版本。 此版本的 LLVM 無法再發出。ELFABIVERSION_AMDGPU_HSA_V4
用於指定程式碼物件 V4 的 AMD HSA 執行階段 ABI 版本。 使用 Clang 選項-mcode-object-version=4
指定。ELFABIVERSION_AMDGPU_HSA_V5
用於指定程式碼物件 V5 的 AMD HSA 執行階段 ABI 版本。 使用 Clang 選項-mcode-object-version=5
指定。 如果未指定,這是預設程式碼物件版本。ELFABIVERSION_AMDGPU_HSA_V6
用於指定程式碼物件 V6 的 AMD HSA 執行階段 ABI 版本。 使用 Clang 選項-mcode-object-version=6
指定。ELFABIVERSION_AMDGPU_PAL
用於指定 AMD PAL 執行階段 ABI 的版本。ELFABIVERSION_AMDGPU_MESA3D
用於指定 AMD MESA 3D 執行階段 ABI 的版本。
e_type
可以是以下值之一
ET_REL
由 AMDGPU 後端編譯器產生的類型,因為它是可重定位程式碼物件。
ET_DYN
由連結器產生的類型,因為它是共享程式碼物件。
AMD HSA 執行階段載入器需要
ET_DYN
程式碼物件。e_machine
值
EM_AMDGPU
用於r600
和amdgcn
架構支援的所有處理器(請參閱 AMDGPU 處理器)。 特定處理器在程式碼物件 V2 的NT_AMD_HSA_ISA_VERSION
註解記錄中指定(請參閱 程式碼物件 V2 註解記錄),在程式碼物件 V3 及更高版本的e_flags
的EF_AMDGPU_MACH
位元欄位中指定(請參閱 程式碼物件 V3 的 AMDGPU ELF 標頭 e_flags、 程式碼物件 V4 和 V5 的 AMDGPU ELF 標頭 e_flags 和 程式碼物件 V6 及更高版本的 AMDGPU ELF 標頭 e_flags)。e_entry
進入點為 0,因為必須選擇個別核心程式的進入點,才能通過 AQL 封包調用它們。
e_flags
AMDGPU 後端使用以下 ELF 標頭旗標
表 34 程式碼物件 V2 的 AMDGPU ELF 標頭 e_flags
¶名稱
值
描述
EF_AMDGPU_FEATURE_XNACK_V2
0x01
指示是否為程式碼物件中包含的所有程式碼啟用了
xnack
目標特性。 如果處理器不支援xnack
目標特性,則必須為 0。 請參閱 目標特性。EF_AMDGPU_FEATURE_TRAP_HANDLER_V2
0x02
指示是否為程式碼物件中包含的所有程式碼啟用了陷阱處理常式。 如果處理器不支援陷阱處理常式,則必須為 0。 請參閱 目標特性。
表 35 程式碼物件 V3 的 AMDGPU ELF 標頭 e_flags
¶名稱
值
描述
EF_AMDGPU_MACH
0x0ff
在 AMDGPU EF_AMDGPU_MACH 值 中定義的
EF_AMDGPU_MACH_xxx
值的 AMDGPU 處理器選擇遮罩。EF_AMDGPU_FEATURE_XNACK_V3
0x100
指示是否為程式碼物件中包含的所有程式碼啟用了
xnack
目標特性。 如果處理器不支援xnack
目標特性,則必須為 0。 請參閱 目標特性。EF_AMDGPU_FEATURE_SRAMECC_V3
0x200
指示是否為程式碼物件中包含的所有程式碼啟用了
sramecc
目標特性。 如果處理器不支援sramecc
目標特性,則必須為 0。 請參閱 目標特性。表 36 程式碼物件 V4 和 V5 的 AMDGPU ELF 標頭 e_flags
¶名稱
值
描述
EF_AMDGPU_MACH
0x0ff
在 AMDGPU EF_AMDGPU_MACH 值 中定義的
EF_AMDGPU_MACH_xxx
值的 AMDGPU 處理器選擇遮罩。EF_AMDGPU_FEATURE_XNACK_V4
0x300
用於
EF_AMDGPU_FEATURE_XNACK_*_V4
值的 XNACK 選擇遮罩。EF_AMDGPU_FEATURE_XNACK_UNSUPPORTED_V4
0x000
不支援 XNACK。
EF_AMDGPU_FEATURE_XNACK_ANY_V4
0x100
XNACK 可以具有任何值。
EF_AMDGPU_FEATURE_XNACK_OFF_V4
0x200
XNACK 已停用。
EF_AMDGPU_FEATURE_XNACK_ON_V4
0x300
XNACK 已啟用。
EF_AMDGPU_FEATURE_SRAMECC_V4
0xc00
用於
EF_AMDGPU_FEATURE_SRAMECC_*_V4
值的 SRAMECC 選擇遮罩。EF_AMDGPU_FEATURE_SRAMECC_UNSUPPORTED_V4
0x000
不支援 SRAMECC。
EF_AMDGPU_FEATURE_SRAMECC_ANY_V4
0x400
SRAMECC 可以具有任何值。
EF_AMDGPU_FEATURE_SRAMECC_OFF_V4
0x800
SRAMECC 已停用。
EF_AMDGPU_FEATURE_SRAMECC_ON_V4
0xc00
SRAMECC 已啟用。
表 37 程式碼物件 V6 及更高版本的 AMDGPU ELF 標頭 e_flags
¶名稱
值
描述
EF_AMDGPU_MACH
0x0ff
在 AMDGPU EF_AMDGPU_MACH 值 中定義的
EF_AMDGPU_MACH_xxx
值的 AMDGPU 處理器選擇遮罩。EF_AMDGPU_FEATURE_XNACK_V4
0x300
用於
EF_AMDGPU_FEATURE_XNACK_*_V4
值的 XNACK 選擇遮罩。EF_AMDGPU_FEATURE_XNACK_UNSUPPORTED_V4
0x000
不支援 XNACK。
EF_AMDGPU_FEATURE_XNACK_ANY_V4
0x100
XNACK 可以具有任何值。
EF_AMDGPU_FEATURE_XNACK_OFF_V4
0x200
XNACK 已停用。
EF_AMDGPU_FEATURE_XNACK_ON_V4
0x300
XNACK 已啟用。
EF_AMDGPU_FEATURE_SRAMECC_V4
0xc00
用於
EF_AMDGPU_FEATURE_SRAMECC_*_V4
值的 SRAMECC 選擇遮罩。EF_AMDGPU_FEATURE_SRAMECC_UNSUPPORTED_V4
0x000
不支援 SRAMECC。
EF_AMDGPU_FEATURE_SRAMECC_ANY_V4
0x400
SRAMECC 可以具有任何值。
EF_AMDGPU_FEATURE_SRAMECC_OFF_V4
0x800
SRAMECC 已停用。
EF_AMDGPU_FEATURE_SRAMECC_ON_V4
0xc00
SRAMECC 已啟用。
EF_AMDGPU_GENERIC_VERSION_V
0xff000000
通用程式碼物件版本選擇遮罩。 這是一個介於 1 和 255 之間的值,儲存在 EFLAGS 的最高有效位元組中。 請參閱 通用處理器版本控制
表 38 AMDGPU EF_AMDGPU_MACH
值¶名稱
值
描述(請參閱 AMDGPU 處理器)
EF_AMDGPU_MACH_NONE
0x000
未指定
EF_AMDGPU_MACH_R600_R600
0x001
r600
EF_AMDGPU_MACH_R600_R630
0x002
r630
EF_AMDGPU_MACH_R600_RS880
0x003
rs880
EF_AMDGPU_MACH_R600_RV670
0x004
rv670
EF_AMDGPU_MACH_R600_RV710
0x005
rv710
EF_AMDGPU_MACH_R600_RV730
0x006
rv730
EF_AMDGPU_MACH_R600_RV770
0x007
rv770
EF_AMDGPU_MACH_R600_CEDAR
0x008
cedar
EF_AMDGPU_MACH_R600_CYPRESS
0x009
cypress
EF_AMDGPU_MACH_R600_JUNIPER
0x00a
juniper
EF_AMDGPU_MACH_R600_REDWOOD
0x00b
redwood
EF_AMDGPU_MACH_R600_SUMO
0x00c
sumo
EF_AMDGPU_MACH_R600_BARTS
0x00d
barts
EF_AMDGPU_MACH_R600_CAICOS
0x00e
caicos
EF_AMDGPU_MACH_R600_CAYMAN
0x00f
cayman
EF_AMDGPU_MACH_R600_TURKS
0x010
turks
保留
0x011 - 0x01f
為
r600
架構處理器保留。EF_AMDGPU_MACH_AMDGCN_GFX600
0x020
gfx600
EF_AMDGPU_MACH_AMDGCN_GFX601
0x021
gfx601
EF_AMDGPU_MACH_AMDGCN_GFX700
0x022
gfx700
EF_AMDGPU_MACH_AMDGCN_GFX701
0x023
gfx701
EF_AMDGPU_MACH_AMDGCN_GFX702
0x024
gfx702
EF_AMDGPU_MACH_AMDGCN_GFX703
0x025
gfx703
EF_AMDGPU_MACH_AMDGCN_GFX704
0x026
gfx704
保留
0x027
保留。
EF_AMDGPU_MACH_AMDGCN_GFX801
0x028
gfx801
EF_AMDGPU_MACH_AMDGCN_GFX802
0x029
gfx802
EF_AMDGPU_MACH_AMDGCN_GFX803
0x02a
gfx803
EF_AMDGPU_MACH_AMDGCN_GFX810
0x02b
gfx810
EF_AMDGPU_MACH_AMDGCN_GFX900
0x02c
gfx900
EF_AMDGPU_MACH_AMDGCN_GFX902
0x02d
gfx902
EF_AMDGPU_MACH_AMDGCN_GFX904
0x02e
gfx904
EF_AMDGPU_MACH_AMDGCN_GFX906
0x02f
gfx906
EF_AMDGPU_MACH_AMDGCN_GFX908
0x030
gfx908
EF_AMDGPU_MACH_AMDGCN_GFX909
0x031
gfx909
EF_AMDGPU_MACH_AMDGCN_GFX90C
0x032
gfx90c
EF_AMDGPU_MACH_AMDGCN_GFX1010
0x033
gfx1010
EF_AMDGPU_MACH_AMDGCN_GFX1011
0x034
gfx1011
EF_AMDGPU_MACH_AMDGCN_GFX1012
0x035
gfx1012
EF_AMDGPU_MACH_AMDGCN_GFX1030
0x036
gfx1030
EF_AMDGPU_MACH_AMDGCN_GFX1031
0x037
gfx1031
EF_AMDGPU_MACH_AMDGCN_GFX1032
0x038
gfx1032
EF_AMDGPU_MACH_AMDGCN_GFX1033
0x039
gfx1033
EF_AMDGPU_MACH_AMDGCN_GFX602
0x03a
gfx602
EF_AMDGPU_MACH_AMDGCN_GFX705
0x03b
gfx705
EF_AMDGPU_MACH_AMDGCN_GFX805
0x03c
gfx805
EF_AMDGPU_MACH_AMDGCN_GFX1035
0x03d
gfx1035
EF_AMDGPU_MACH_AMDGCN_GFX1034
0x03e
gfx1034
EF_AMDGPU_MACH_AMDGCN_GFX90A
0x03f
gfx90a
保留
0x040
保留。
EF_AMDGPU_MACH_AMDGCN_GFX1100
0x041
gfx1100
EF_AMDGPU_MACH_AMDGCN_GFX1013
0x042
gfx1013
EF_AMDGPU_MACH_AMDGCN_GFX1150
0x043
gfx1150
EF_AMDGPU_MACH_AMDGCN_GFX1103
0x044
gfx1103
EF_AMDGPU_MACH_AMDGCN_GFX1036
0x045
gfx1036
EF_AMDGPU_MACH_AMDGCN_GFX1101
0x046
gfx1101
EF_AMDGPU_MACH_AMDGCN_GFX1102
0x047
gfx1102
EF_AMDGPU_MACH_AMDGCN_GFX1200
0x048
gfx1200
保留
0x049
保留。
EF_AMDGPU_MACH_AMDGCN_GFX1151
0x04a
gfx1151
保留
0x04b
保留。
EF_AMDGPU_MACH_AMDGCN_GFX942
0x04c
gfx942
保留
0x04d
保留。
EF_AMDGPU_MACH_AMDGCN_GFX1201
0x04e
gfx1201
EF_AMDGPU_MACH_AMDGCN_GFX950
0x04f
gfx950
保留
0x050
保留。
EF_AMDGPU_MACH_AMDGCN_GFX9_GENERIC
0x051
gfx9-generic
EF_AMDGPU_MACH_AMDGCN_GFX10_1_GENERIC
0x052
gfx10-1-generic
EF_AMDGPU_MACH_AMDGCN_GFX10_3_GENERIC
0x053
gfx10-3-generic
EF_AMDGPU_MACH_AMDGCN_GFX11_GENERIC
0x054
gfx11-generic
EF_AMDGPU_MACH_AMDGCN_GFX1152
0x055
gfx1152
.保留
0x056
保留。
保留
0x057
保留。
EF_AMDGPU_MACH_AMDGCN_GFX1153
0x058
gfx1153
.EF_AMDGPU_MACH_AMDGCN_GFX12_GENERIC
0x059
gfx12-generic
EF_AMDGPU_MACH_AMDGCN_GFX9_4_GENERIC
0x05f
gfx9-4-generic
章節¶
AMDGPU 目標 ELF 程式碼物件具有標準 ELF 章節,其中包括
表 39 AMDGPU ELF 章節¶ 名稱
類型
屬性
.bss
SHT_NOBITS
SHF_ALLOC
+SHF_WRITE
.data
SHT_PROGBITS
SHF_ALLOC
+SHF_WRITE
.debug_
*
SHT_PROGBITS
none
.dynamic
SHT_DYNAMIC
SHF_ALLOC
.dynstr
SHT_PROGBITS
SHF_ALLOC
.dynsym
SHT_PROGBITS
SHF_ALLOC
.got
SHT_PROGBITS
SHF_ALLOC
+SHF_WRITE
.hash
SHT_HASH
SHF_ALLOC
.note
SHT_NOTE
none
.rela
name
SHT_RELA
none
.rela.dyn
SHT_RELA
none
.rodata
SHT_PROGBITS
SHF_ALLOC
.shstrtab
SHT_STRTAB
none
.strtab
SHT_STRTAB
none
.symtab
SHT_SYMTAB
none
.text
SHT_PROGBITS
SHF_ALLOC
+SHF_EXECINSTR
這些章節具有其標準含義(請參閱 [ELF]),並且僅在需要時生成。
.debug
*標準 DWARF 章節。有關 AMDGPU 後端產生的 DWARF 的資訊,請參閱 DWARF 偵錯資訊。
.dynamic
、.dynstr
、.dynsym
、.hash
動態載入器使用的標準章節。
.note
有關 AMDGPU 後端支援的註記記錄,請參閱 註記記錄。
.rela
name、.rela.dyn
對於可重定位的程式碼物件,name 是重定位記錄套用的章節名稱。例如,
.rela.text
是與.text
章節關聯的重定位記錄的章節名稱。對於連結的共享程式碼物件,
.rela.dyn
包含每個可重定位程式碼物件的.rela
name 章節中的所有重定位記錄。有關 AMDGPU 後端支援的重定位記錄,請參閱 重定位記錄。
.text
核心和它們呼叫的函式的可執行機器碼。生成為與位置無關的程式碼。有關 isa 生成中使用的約定,請參閱 程式碼約定。
.amdgpu.kernel.runtime.handle
用於裝置佇列的符號。
註記記錄¶
AMDGPU 後端程式碼物件在 .note
章節中包含 ELF 註記記錄。生成的註記及其語義取決於程式碼物件版本;請參閱 程式碼物件 V2 註記記錄 和 程式碼物件 V3 及更高版本註記記錄。
根據 ELFCLASS32
和 ELFCLASS64
的要求,必須在 name
欄位後生成最少的零位元組填充,以確保 desc
欄位為 4 位元組對齊。此外,必須生成最少的零位元組填充,以確保 desc
欄位大小是 4 位元組的倍數。.note
章節的 sh_addralign
欄位必須至少為 4,以指示至少 8 位元組對齊。
程式碼物件 V2 註記記錄¶
警告
此版本的 LLVM 不再支援程式碼物件 V2 生成。
AMDGPU 後端程式碼物件在為程式碼物件 V2 編譯時,在 .note
章節中使用以下 ELF 註記記錄。
註記記錄供應商欄位為 “AMD”。
可能存在其他註記記錄,但此處未記錄的任何註記記錄均已棄用,不應使用。
表 41 AMDGPU 程式碼物件 V2 ELF 註記記錄列舉值¶ 名稱
值
NT_AMD_HSA_CODE_OBJECT_VERSION
1
NT_AMD_HSA_HSAIL
2
NT_AMD_HSA_ISA_VERSION
3
保留
4-9
NT_AMD_HSA_METADATA
10
NT_AMD_HSA_ISA_NAME
11
NT_AMD_HSA_CODE_OBJECT_VERSION
指定程式碼物件版本號碼。描述欄位具有以下佈局
struct amdgpu_hsa_note_code_object_version_s { uint32_t major_version; uint32_t minor_version; };
major_version
的值小於或等於 2。NT_AMD_HSA_HSAIL
指定 HSAIL Finalizer 使用的 HSAIL 屬性。描述欄位具有以下佈局
struct amdgpu_hsa_note_hsail_s { uint32_t hsail_major_version; uint32_t hsail_minor_version; uint8_t profile; uint8_t machine_model; uint8_t default_float_round; };
NT_AMD_HSA_ISA_VERSION
指定目標 ISA 版本。描述欄位具有以下佈局
struct amdgpu_hsa_note_isa_s { uint16_t vendor_name_size; uint16_t architecture_name_size; uint32_t major; uint32_t minor; uint32_t stepping; char vendor_and_architecture_name[1]; };
vendor_name_size
和architecture_name_size
分別是供應商和架構名稱的長度,包括 NUL 字元。vendor_and_architecture_name
包含供應商的 NUL 終止字串,後跟架構的 NUL 終止字串。HSA 執行階段載入器使用此註記記錄。
程式碼物件 V2 僅支援有限數量的處理器,並且具有目標功能的固定設定。有關處理器清單和對應的目標 ID,請參閱 AMDGPU 程式碼物件 V2 支援的處理器和固定的目標功能設定。在表中,註記記錄 ISA 名稱是供應商名稱、架構名稱、主要、次要和步進的串聯,並以 “:” 分隔。
目標 ID 列顯示 LLVM 編譯器使用的處理器名稱和固定的目標功能。LLVM 編譯器不會生成
NT_AMD_HSA_HSAIL
註記記錄。由 Finalizer 生成的程式碼物件也使用程式碼物件 V2,並且始終生成
NT_AMD_HSA_HSAIL
註記記錄。處理器名稱和sramecc
目標功能如 AMDGPU 程式碼物件 V2 支援的處理器和固定的目標功能設定 中所示,但xnack
目標功能由EF_AMDGPU_FEATURE_XNACK_V2
e_flags
位元指定。NT_AMD_HSA_ISA_NAME
將目標 ISA 名稱指定為非 NUL 終止字串。
HSA 執行階段載入器不使用此註記記錄。
請參閱程式碼物件 V2 對處理器的有限支援和目標功能的固定設定的
NT_AMD_HSA_ISA_VERSION
註記記錄描述。有關從字串到對應目標 ID 的映射,請參閱 AMDGPU 程式碼物件 V2 支援的處理器和固定的目標功能設定。如果支援並啟用
xnack
目標功能,則 LLVM 編譯器產生的字串可能會附加+xnack
。Finlizer 沒有執行附加,而是使用了EF_AMDGPU_FEATURE_XNACK_V2
e_flags
位元。NT_AMD_HSA_METADATA
指定與 HSA [HSA] 相容執行階段(請參閱 AMDGPU 作業系統)上執行的程式碼物件相關聯的可擴展中繼資料。當目標三元組 OS 為
amdhsa
時,這是必需的(請參閱 目標三元組)。有關程式碼物件中繼資料字串的語法,請參閱 程式碼物件 V2 中繼資料。表 42 AMDGPU 程式碼物件 V2 支援的處理器和固定的目標功能設定¶ 註記記錄 ISA 名稱
目標 ID
AMD:AMDGPU:6:0:0
gfx600
AMD:AMDGPU:6:0:1
gfx601
AMD:AMDGPU:6:0:2
gfx602
AMD:AMDGPU:7:0:0
gfx700
AMD:AMDGPU:7:0:1
gfx701
AMD:AMDGPU:7:0:2
gfx702
AMD:AMDGPU:7:0:3
gfx703
AMD:AMDGPU:7:0:4
gfx704
AMD:AMDGPU:7:0:5
gfx705
AMD:AMDGPU:8:0:0
gfx802
AMD:AMDGPU:8:0:1
gfx801:xnack+
AMD:AMDGPU:8:0:2
gfx802
AMD:AMDGPU:8:0:3
gfx803
AMD:AMDGPU:8:0:4
gfx803
AMD:AMDGPU:8:0:5
gfx805
AMD:AMDGPU:8:1:0
gfx810:xnack+
AMD:AMDGPU:9:0:0
gfx900:xnack-
AMD:AMDGPU:9:0:1
gfx900:xnack+
AMD:AMDGPU:9:0:2
gfx902:xnack-
AMD:AMDGPU:9:0:3
gfx902:xnack+
AMD:AMDGPU:9:0:4
gfx904:xnack-
AMD:AMDGPU:9:0:5
gfx904:xnack+
AMD:AMDGPU:9:0:6
gfx906:sramecc-:xnack-
AMD:AMDGPU:9:0:7
gfx906:sramecc-:xnack+
AMD:AMDGPU:9:0:12
gfx90c:xnack-
程式碼物件 V3 及更高版本註記記錄¶
AMDGPU 後端程式碼物件在為程式碼物件 V3 及更高版本編譯時,在 .note
章節中使用以下 ELF 註記記錄。
註記記錄供應商欄位為 “AMDGPU”。
可能存在其他註記記錄,但此處未記錄的任何註記記錄均已棄用,不應使用。
表 44 AMDGPU 程式碼物件 V3 及更高版本 ELF 註記記錄列舉值¶ 名稱
值
保留
0-31
NT_AMDGPU_METADATA
32
NT_AMDGPU_KFD_CORE_STATE
33
NT_AMDGPU_METADATA
指定與 AMDGPU 程式碼物件相關聯的可擴展中繼資料。它在訊息封裝 [MsgPack] 二進位資料格式中編碼為映射。有關為
amdhsa
OS 定義的映射鍵,請參閱 程式碼物件 V3 中繼資料、程式碼物件 V4 中繼資料 和 程式碼物件 V5 中繼資料。
符號¶
符號包括以下內容
表 45 AMDGPU ELF 符號¶ 名稱
類型
章節
描述
連結名稱
STT_OBJECT
.data
.rodata
.bss
全域變數
連結名稱
.kd
STT_OBJECT
.rodata
核心描述符
連結名稱
STT_FUNC
.text
核心進入點
連結名稱
STT_OBJECT
SHN_AMDGPU_LDS
LDS 中的全域變數
- 全域變數
編譯單元使用和定義的全域變數。
如果符號在編譯單元中定義,則根據它是否具有初始化的資料或是否為唯讀,將其分配到適當的章節中。
如果符號是外部的,則其章節為
STN_UNDEF
,並且載入器將使用另一個程式碼物件提供的定義或執行階段明確定義的定義來解析重定位。如果符號駐留在本機/群組記憶體 (LDS) 中,則其章節是特殊的處理器特定章節名稱
SHN_AMDGPU_LDS
,並且st_value
欄位描述對齊要求,就像它對通用符號所做的那樣。- 核心描述符
每個 HSA 核心都有一個關聯的核心描述符。它是用於調用核心的 AQL 派送封包中使用的核心描述符的位址,而不是核心進入點。HSA 核心描述符的佈局在 核心描述符 中定義。
- 核心進入點
每個 HSA 核心也有一個用於其機器碼進入點的符號。
重定位記錄¶
AMDGPU 後端為 AMDHSA 生成 Elf64_Rela
重定位記錄,或為 Mesa/AMDPAL 生成 Elf64_Rel
重定位記錄。支援的可重定位欄位為
word32
這指定一個 32 位元欄位,佔用 4 個位元組,具有任意位元組對齊。這些值使用與 AMDGPU 架構中其他 word 值相同的位元組順序。
word64
這指定一個 64 位元欄位,佔用 8 個位元組,具有任意位元組對齊。這些值使用與 AMDGPU 架構中其他 word 值相同的位元組順序。
以下符號用於指定重定位計算
- A
表示用於計算可重定位欄位值的加數。如果加數欄位小於 64 位元,則將其零擴展為 64 位元,以便在以下計算中使用。(實際上,這僅影響 Mesa/AMDPAL 上的
_HI
重定位類型,其中加數來自 32 位元欄位,但計算結果取決於完整 64 位元位址的高位部分。)- G
表示全域偏移表中的偏移量,重定位項目的符號將在執行期間駐留在該偏移量處。
- GOT
表示全域偏移表的位址。
- P
表示正在重定位的儲存單元的位置(
et_rel
的章節偏移量或et_dyn
的位址)(使用r_offset
計算)。- S
表示索引駐留在重定位項目中的符號的值。不使用此符號的重定位必須指定
STN_UNDEF
的符號索引。- B
表示已載入的可執行檔或共享物件的基底位址,即 ELF 位址與實際載入位址之間的差值。使用此符號的重定位僅在可執行檔或共享物件中有效。
支援以下重定位類型
表 46 AMDGPU ELF 重定位記錄¶ 重定位類型
種類
值
欄位
計算
R_AMDGPU_NONE
0
none
none
R_AMDGPU_ABS32_LO
靜態、動態
1
word32
(S + A) & 0xFFFFFFFF
R_AMDGPU_ABS32_HI
靜態、動態
2
word32
(S + A) >> 32
R_AMDGPU_ABS64
靜態、動態
3
word64
S + A
R_AMDGPU_REL32
靜態
4
word32
S + A - P
R_AMDGPU_REL64
靜態
5
word64
S + A - P
R_AMDGPU_ABS32
靜態、動態
6
word32
S + A
R_AMDGPU_GOTPCREL
靜態
7
word32
G + GOT + A - P
R_AMDGPU_GOTPCREL32_LO
靜態
8
word32
(G + GOT + A - P) & 0xFFFFFFFF
R_AMDGPU_GOTPCREL32_HI
靜態
9
word32
(G + GOT + A - P) >> 32
R_AMDGPU_REL32_LO
靜態
10
word32
(S + A - P) & 0xFFFFFFFF
R_AMDGPU_REL32_HI
靜態
11
word32
(S + A - P) >> 32
保留
12
R_AMDGPU_RELATIVE64
動態
13
word64
B + A
R_AMDGPU_REL16
靜態
14
word16
((S + A - P) - 4) / 4
R_AMDGPU_ABS32_LO
和 R_AMDGPU_ABS32_HI
僅受 mesa3d
OS 支援,該 OS 不支援 R_AMDGPU_ABS64
。
目前沒有 OS 載入器支援 32 位元程式,因此未使用 R_AMDGPU_ABS32
。
已載入程式碼物件路徑統一資源識別碼 (URI)¶
AMDGPU 程式碼物件載入器將載入程式碼物件的 ELF 共享物件的路徑表示為文字統一資源識別碼 (URI)。請注意,程式碼物件是 ELF 共享物件的記憶體中已載入的重定位形式。多個程式碼物件可以從同一個 ELF 共享物件在同一個進程中載入到不同的記憶體位址。
已載入的程式碼物件路徑 URI 語法由以下 BNF 語法定義
code_object_uri ::== file_uri | memory_uri
file_uri ::== "file://" file_path [ range_specifier ]
memory_uri ::== "memory://" process_id range_specifier
range_specifier ::== [ "#" | "?" ] "offset=" number "&" "size=" number
file_path ::== URI_ENCODED_OS_FILE_PATH
process_id ::== DECIMAL_NUMBER
number ::== HEX_NUMBER | DECIMAL_NUMBER | OCTAL_NUMBER
- 數字
是 C 整數文字,其中十六進位值以 “0x” 或 “0X” 為前綴,八進位值以 “0” 為前綴。
- file_path
是以 URI 編碼的 UTF-8 字串指定的檔案路徑。在 URI 編碼中,不在正規表示式
[a-zA-Z0-9/_.~-]
中的每個字元都編碼為兩個大寫十六進位數字,並以 “%” 開頭。路徑中的目錄以 “/” 分隔。- 偏移量
是程式碼物件起點的從 0 開始的位元組偏移量。對於檔案 URI,它是從
file_path
指定的檔案的起點開始的,如果省略則預設為 0。對於記憶體 URI,它是記憶體位址,並且是必需的。- 大小
是程式碼物件中的位元組數。對於檔案 URI,如果省略則預設為檔案的大小。對於記憶體 URI,這是必需的。
- process_id
是擁有記憶體的進程的識別碼。對於 Linux,它是進程 ID (PID) 的 C 無符號整數十進位文字。
例如
file:///dir1/dir2/file1
file:///dir3/dir4/file2#offset=0x2000&size=3000
memory://1234#offset=0x20000&size=3000
DWARF 偵錯資訊¶
警告
本節描述 AMDGPU DWARF [DWARF] 的臨時支援,目前尚未完全實作,並且可能會變更。
AMDGPU 生成 DWARF [DWARF] 偵錯資訊 ELF 章節(請參閱 ELF 程式碼物件),其中包含將程式碼物件可執行程式碼和資料映射到來源語言結構的資訊。工具(例如偵錯器和分析器)可以使用它。它使用 異質偵錯的 DWARF 擴充功能 中定義的功能,這些功能在 DWARF 版本 4 和 DWARF 版本 5 中作為 LLVM 供應商擴充功能提供。
本節定義 AMDGPU 目標架構特定的 DWARF 映射。
暫存器識別碼¶
本節定義 DWARF 運算式(請參閱 DWARF 版本 5 第 2.5 節和 A.2.5.4 DWARF 運算式)和呼叫框架資訊指令(請參閱 DWARF 版本 5 第 6.4 節和 A.6.4 呼叫框架資訊)中使用的 AMDGPU 目標架構暫存器編號。
單個程式碼物件可以包含用於具有不同波前大小的核心的程式碼。向量暫存器和某些純量暫存器基於波前大小。AMDGPU 為每個波前大小定義了不同的 DWARF 暫存器。這簡化了 DWARF 的使用者,以便每個暫存器都具有固定大小,而不是根據波前大小模式而動態變化。同樣,為那些大小根據進程位址大小而變化的暫存器定義了不同的 DWARF 暫存器。這允許使用者將特定的 AMDGPU 處理器視為單一架構,而不管它在執行階段如何配置。編譯器明確指定與其正在生成的程式碼將要執行的模式相符的 DWARF 暫存器。
DWARF 暫存器編碼為數字,這些數字映射到架構暫存器。AMDGPU 的映射在 AMDGPU DWARF 暫存器映射 中定義。所有 AMDGPU 目標都使用相同的映射。
DWARF 暫存器 |
AMDGPU 暫存器 |
位元大小 |
描述 |
---|---|---|---|
0 |
PC_32 |
32 |
在 32 位元進程位址空間中執行時的程式計數器 (PC)。在 CFI 中用於描述呼叫框架的 PC。 |
1 |
EXEC_MASK_32 |
32 |
在波前 32 模式中執行時的執行遮罩暫存器。 |
2-15 |
保留 |
保留用於使用 DWARF 快捷方式高頻存取的暫存器。 |
|
16 |
PC_64 |
64 |
在 64 位元進程位址空間中執行時的程式計數器 (PC)。在 CFI 中用於描述呼叫框架的 PC。 |
17 |
EXEC_MASK_64 |
64 |
在波前 64 模式中執行時的執行遮罩暫存器。 |
18-31 |
保留 |
保留用於使用 DWARF 快捷方式高頻存取的暫存器。 |
|
32-95 |
SGPR0-SGPR63 |
32 |
純量通用暫存器。 |
96-127 |
保留 |
保留用於使用 DWARF 1 位元組 ULEB 頻繁存取的暫存器。 |
|
128 |
STATUS |
32 |
狀態暫存器。 |
129-511 |
保留 |
保留用於未來的純量架構暫存器。 |
|
512 |
VCC_32 |
32 |
在波前 32 模式中執行時的向量條件碼暫存器。 |
513-767 |
保留 |
保留用於在波前 32 模式中執行時的未來向量架構暫存器。 |
|
768 |
VCC_64 |
64 |
在波前 64 模式中執行時的向量條件碼暫存器。 |
769-1023 |
保留 |
保留用於在波前 64 模式中執行時的未來向量架構暫存器。 |
|
1024-1087 |
保留 |
保留用於填充。 |
|
1088-1129 |
SGPR64-SGPR105 |
32 |
純量通用暫存器。 |
1130-1535 |
保留 |
保留用於未來的純量通用暫存器。 |
|
1536-1791 |
VGPR0-VGPR255 |
32*32 |
在波前 32 模式中執行時的向量通用暫存器。 |
1792-2047 |
保留 |
保留用於在波前 32 模式中執行時的未來向量通用暫存器。 |
|
2048-2303 |
AGPR0-AGPR255 |
32*32 |
在波前 32 模式中執行時的向量累加暫存器。 |
2304-2559 |
保留 |
保留用於在波前 32 模式中執行時的未來向量累加暫存器。 |
|
2560-2815 |
VGPR0-VGPR255 |
64*32 |
在波前 64 模式中執行時的向量通用暫存器。 |
2816-3071 |
保留 |
保留用於在波前 64 模式中執行時的未來向量通用暫存器。 |
|
3072-3327 |
AGPR0-AGPR255 |
64*32 |
在波前 64 模式中執行時的向量累加暫存器。 |
3328-3583 |
保留 |
保留用於在波前 64 模式中執行時的未來向量累加暫存器。 |
向量暫存器表示為波前的完整大小。它們組織為連續的 dword(32 位元),每個通道一個,最低有效位元位置的 dword 對應於通道 0,依此類推。涉及 DW_OP_LLVM_offset
和 DW_OP_LLVM_push_lane
運算的 DWARF 位置運算式用於選取與在使用 SIMD 或 SIMT 執行模型實作的語言中執行目前執行緒的通道相對應的向量暫存器的部分。
如果波前大小為 32 個通道,則使用波前 32 模式暫存器定義。如果波前大小為 64 個通道,則使用波前 64 模式暫存器定義。某些 AMDGPU 目標支援在波前 32 和波前 64 模式下執行。將使用與生成的程式碼的波前模式相對應的暫存器定義。
如果程式碼是為了在 32 位元程序位址空間中執行而產生,則會使用 32 位元程序位址空間暫存器定義。如果程式碼是為了在 64 位元程序位址空間中執行而產生,則會使用 64 位元程序位址空間暫存器定義。amdgcn
目標僅支援 64 位元程序位址空間。
記憶體空間識別碼¶
DWARF 記憶體空間代表原始語言記憶體空間。請參閱 DWARF 第 5 版第 2.12 節,該節已由異質除錯的 DWARF 擴充功能章節 A.2.14 記憶體空間 更新。
用於 AMDGPU 的 DWARF 記憶體空間映射定義於 AMDGPU DWARF 記憶體空間映射。
DWARF |
AMDGPU |
|
---|---|---|
記憶體空間名稱 |
值 |
記憶體空間 |
|
0x0000 |
通用 (平面) |
|
0x0001 |
全域 |
|
0x0002 |
全域 |
|
0x0003 |
本地 (群組/LDS) |
|
0x0004 |
私有 (Scratch) |
|
0x8000 |
區域 (GDS) |
使用異質除錯的 DWARF 擴充功能章節 A.2.14 記憶體空間 中定義的 DWARF 記憶體空間值。
此外,DW_ADDR_AMDGPU_region
編碼為供應商擴充功能。這可用於 AMD 擴充功能,以存取硬體 GDS 記憶體,該記憶體是每個裝置配置的暫存記憶體。
對於 AMDGPU,如果沒有 DW_AT_LLVM_memory_space
屬性,則使用 DW_MSPACE_LLVM_none
的預設記憶體空間。
請參閱 位址空間識別碼,以取得有關 DWARF 記憶體空間到 DWARF 位址空間的 AMDGPU 映射資訊,包括位址大小和 NULL 值。
位址空間識別碼¶
DWARF 位址空間對應於目標架構特定的線性可定址記憶體區域。請參閱 DWARF 第 5 版第 2.12 節和異質除錯的 DWARF 擴充功能章節 A.2.13 位址空間。
用於 AMDGPU 的 DWARF 位址空間映射定義於 AMDGPU DWARF 位址空間映射。
DWARF |
AMDGPU |
註解 |
|||
---|---|---|---|---|---|
位址空間名稱 |
值 |
位址 |
位元大小 |
LLVM IR 位址空間 |
|
64 位元程序位址空間 |
32 位元程序位址空間 |
||||
|
0x00 |
64 |
32 |
全域 |
預設位址空間 |
|
0x01 |
64 |
32 |
通用 (平面) |
|
|
0x02 |
32 |
32 |
區域 (GDS) |
|
|
0x03 |
32 |
32 |
本地 (群組/LDS) |
|
保留 |
0x04 |
||||
|
0x05 |
32 |
32 |
私有 (Scratch) |
聚焦 lane |
|
0x06 |
32 |
32 |
私有 (Scratch) |
未調換 (unswizzled) wavefront |
請參閱 位址空間,以取得有關 AMDGPU LLVM IR 位址空間的資訊,包括位址大小和 NULL 值。
DW_ASPACE_LLVM_none
位址空間是在未指定位址空間的 DWARF 運算中使用的預設目標架構位址空間。因此,它必須映射到全域位址空間,以便 DW_OP_addr*
和相關運算可以參考程式碼中的位址。
DW_ASPACE_AMDGPU_generic
位址空間允許位置運算式指定平面位址空間。如果位址對應於本地位址空間中的位址,則它對應於正在執行聚焦執行緒的 wavefront。如果位址對應於私有位址空間中的位址,則對於使用 SIMD 或 SIMT 執行模型實作的語言,它對應於正在執行聚焦執行緒的 lane。
注意
類似 CUDA 的語言(例如 HIP)在語言類型系統中沒有位址空間,但允許在不同位址空間中配置變數,需要在 DWARF 運算式中明確指定 DW_ASPACE_AMDGPU_generic
位址空間,因為預設位址空間是全域位址空間。
DW_ASPACE_AMDGPU_local
位址空間允許位置運算式指定對應於正在執行聚焦執行緒的 wavefront 的本地位址空間。
DW_ASPACE_AMDGPU_private_lane
位址空間允許位置運算式指定對應於正在執行聚焦執行緒的 lane 的私有位址空間,適用於使用 SIMD 或 SIMT 執行模型實作的語言。
DW_ASPACE_AMDGPU_private_wave
位址空間允許位置運算式指定未調換 (unswizzled) 的私有位址空間,該空間對應於正在執行聚焦執行緒的 wavefront。私有記憶體的 wavefront 視圖是 位址空間 中定義的每個 wavefront 的未調換後備記憶體佈局,因此位址 0 對應於 wavefront 後備記憶體的第一個位置(即,位址不會被 wavefront-scratch-base
偏移)。以下公式可用於將 DW_ASPACE_AMDGPU_private_lane
位址轉換為 DW_ASPACE_AMDGPU_private_wave
位址
private-address-wavefront =
((private-address-lane / 4) * wavefront-size * 4) +
(wavefront-lane-id * 4) + (private-address-lane % 4)
如果 DW_ASPACE_AMDGPU_private_lane
位址是 dword 對齊的,並且需要從 lane 0 開始的每個 lane 的 dword 開頭,則這簡化為
private-address-wavefront =
private-address-lane * wavefront-size
編譯器可以使用 DW_ASPACE_AMDGPU_private_wave
位址空間將完整的溢出向量暫存器讀回 CFI 中的完整向量暫存器。框架指標可以是 dword 對齊的私有 lane 位址,可以將其移位以乘以 wavefront 大小,然後用於形成私有 wavefront 位址,該位址提供一組連續 dword 的位置(每個 lane 一個),其中溢出了向量暫存器 dword。編譯器知道 wavefront 大小,因為它產生程式碼。請注意,位址的類型可能必須轉換,因為 DW_ASPACE_AMDGPU_private_lane
位址的大小可能小於 DW_ASPACE_AMDGPU_private_wave
位址的大小。
Lane 識別碼¶
DWARF lane 識別碼指定以 SIMD 或 SIMT 方式執行的硬體的目標架構 lane 位置,以及原始語言將其執行緒映射到這些 lane 上的位置。DWARF lane 識別碼由 DW_OP_LLVM_push_lane
DWARF 運算式運算推送。請參閱 DWARF 第 5 版第 2.5 節,該節已由異質除錯的 DWARF 擴充功能章節 A.2.5.4 DWARF 運算式運算 更新。
對於 AMDGPU,lane 識別碼對應於 wavefront 的硬體 lane ID。它的編號從 0 到 wavefront 大小減 1。
運算式¶
DWARF 運算式用於計算程式值和程式物件的位置。請參閱 DWARF 第 5 版第 2.5 節和 A.2.5.4 DWARF 運算式運算。
DWARF 位置描述描述如何存取儲存空間,包括記憶體和暫存器。在存取 AMDGPU 上的儲存空間時,位元組的順序是最低有效位元組優先,位元在位元組內的順序是最低有效位元優先。
對於 AMDGPU CFI 運算式,DW_OP_LLVM_select_bit_piece
用於描述在執行遮罩下溢出到記憶體的向量暫存器:zero-single 位置描述是向量暫存器,而 one-single 位置描述是溢出的記憶體位置描述。DW_OP_LLVM_form_aspace_address
用於指定記憶體位置描述的位址空間。
在 AMDGPU 運算式中,DW_OP_LLVM_select_bit_piece
由 DW_AT_LLVM_lane_pc
屬性運算式使用,其中發散控制流程由執行遮罩控制。未定義的位置描述與 DW_OP_LLVM_extend
一起用於指示 lane 在進入子程式時未處於活動狀態。請參閱 DW_AT_LLVM_lane_pc 以取得範例。
基礎類型轉換¶
對於 AMDGPU 運算式,DW_OP_convert
可用於在不同位址空間中的 DW_ATE_address
編碼的基礎類型之間進行轉換。
當 位址空間 中描述的所有相關條件都滿足時,轉換會如其中定義的那樣進行,否則會導致評估錯誤。
注意
對於不支援特定位址空間的目標,轉換到或從該位址空間轉換始終是評估錯誤。
對於支援通用位址空間的目標,當通用位址位於全域位址空間中時,定義從 DW_ASPACE_AMDGPU_generic
轉換為 DW_ASPACE_LLVM_none
。轉換不需要更改位址的字面值。
當存在相關硬體支援、任何需要的硬體設定已完成且通用位址位於相應的位址空間中時,定義從 DW_ASPACE_AMDGPU_generic
轉換為 DW_ASPACE_AMDGPU_local
、DW_ASPACE_AMDGPU_private_wave
或 DW_ASPACE_AMDGPU_private_lane
。轉換為 DW_ASPACE_AMDGPU_private_lane
還需要上下文包含活動 lane。
除錯資訊條目屬性¶
本節描述 AMDGPU 如何使用某些除錯資訊條目屬性。請參閱 DWARF 第 5 版第 3.3.5 節和 3.1.1 節中的章節,這些章節已由異質除錯的 DWARF 擴充功能章節 A.3.3.5 低階資訊 和 A.3.1.1 完整和部分編譯單元條目 更新。
DW_AT_LLVM_lane_pc
¶
對於 AMDGPU,DW_AT_LLVM_lane_pc
屬性用於指定 SIMT 執行緒的各個 lane 的程式位置。
如果 lane 是活動 lane,則這將與當前程式位置相同。
如果 lane 處於非活動狀態,但在進入子程式時處於活動狀態,則這是 lane 在子程式中概念性定位的程式位置。
如果 lane 在進入子程式時未處於活動狀態,則這將是未定義的位置。用戶端除錯器可以透過檢查 lane 是否在網格內相關工作群組的範圍內(考慮到部分工作群組)來檢查 lane 是否是有效工作群組的一部分。如果不是,則除錯器可以省略 lane 的任何資訊。否則,除錯器可以重複展開堆疊並檢查呼叫子程式的 DW_AT_LLVM_lane_pc
,直到找到非未定義的位置。從概念上講,lane 僅具有它具有非未定義 DW_AT_LLVM_lane_pc
的呼叫框架。
以下範例說明了 AMDGPU 後端如何為以下子程式虛擬碼的巢狀 IF/THEN/ELSE
結構產生 DWARF 位置列表運算式,目標是每個 wavefront 具有 64 個 lane。
1SUBPROGRAM X
2BEGIN
3 a;
4 IF (c1) THEN
5 b;
6 IF (c2) THEN
7 c;
8 ELSE
9 d;
10 ENDIF
11 e;
12 ELSE
13 f;
14 ENDIF
15 g;
16END
AMDGPU 後端可能會產生以下虛擬 LLVM MIR 來操作執行遮罩 (EXEC
) 以線性化控制流程。評估條件以建立條件評估為 true 的 lane 的遮罩。首先,透過將 EXEC
遮罩設定為當前 EXEC
遮罩與條件遮罩的邏輯 AND
,來執行 THEN
區域。然後,透過否定 EXEC
遮罩和在區域開始時儲存的 EXEC
遮罩的邏輯 AND
,來執行 ELSE
區域。在 IF/THEN/ELSE
區域之後,EXEC
遮罩會還原為區域開始時的值。如下所示。其他方法也是可能的,但基本概念是相同的。
1$lex_start:
2 a;
3 %1 = EXEC
4 %2 = c1
5$lex_1_start:
6 EXEC = %1 & %2
7$if_1_then:
8 b;
9 %3 = EXEC
10 %4 = c2
11$lex_1_1_start:
12 EXEC = %3 & %4
13$lex_1_1_then:
14 c;
15 EXEC = ~EXEC & %3
16$lex_1_1_else:
17 d;
18 EXEC = %3
19$lex_1_1_end:
20 e;
21 EXEC = ~EXEC & %1
22$lex_1_else:
23 f;
24 EXEC = %1
25$lex_1_end:
26 g;
27$lex_end:
為了建立定義 lane 程式位置向量的位置描述的 DWARF 位置列表運算式,可以使用 LLVM MIR DBG_VALUE
虛擬指令來註解線性化的控制流程。這可以透過為 lane PC 定義人為變數來完成。為其建立的 DWARF 位置列表運算式用作子程式的除錯資訊條目上 DW_AT_LLVM_lane_pc
屬性的值。
為每個良好巢狀結構化的控制流程區域定義 DWARF 程序,如果 lane 不活動(即它是發散的),則該程序會提供 lane 的概念性 lane 程式位置。每個區域的 DWARF 運算式運算在概念上繼承了直接封閉區域的值,並根據區域的語義對其進行修改。
對於 IF/THEN/ELSE
區域,發散程式位置位於 THEN
區域的開始處,因為它是首先執行的。對於 ELSE
區域,發散程式位置位於 IF/THEN/ELSE
區域的結尾處,因為 THEN
區域已完成。
lane PC 人為變數在每個區域轉換時都會指派。它使用直接封閉區域的 DWARF 程序來計算每個 lane 的程式位置(假設它們是發散的),然後透過插入 EXEC
遮罩指示為活動狀態的每個 lane 的當前程式位置來修改結果。
透過為每個區域使用單獨的 DWARF 程序,可以重複使用它們來定義任何巢狀區域的值。這減少了 DWARF 運算式運算的總大小。
以下提供了一個使用虛擬 LLVM MIR 的範例。
1$lex_start:
2 DEFINE_DWARF %__uint_64 = DW_TAG_base_type[
3 DW_AT_name = "__uint64";
4 DW_AT_byte_size = 8;
5 DW_AT_encoding = DW_ATE_unsigned;
6 ];
7 DEFINE_DWARF %__active_lane_pc = DW_TAG_dwarf_procedure[
8 DW_AT_name = "__active_lane_pc";
9 DW_AT_location = [
10 DW_OP_regx PC;
11 DW_OP_LLVM_extend 64, 64;
12 DW_OP_regval_type EXEC, %uint_64;
13 DW_OP_LLVM_select_bit_piece 64, 64;
14 ];
15 ];
16 DEFINE_DWARF %__divergent_lane_pc = DW_TAG_dwarf_procedure[
17 DW_AT_name = "__divergent_lane_pc";
18 DW_AT_location = [
19 DW_OP_LLVM_undefined;
20 DW_OP_LLVM_extend 64, 64;
21 ];
22 ];
23 DBG_VALUE $noreg, $noreg, %DW_AT_LLVM_lane_pc, DIExpression[
24 DW_OP_call_ref %__divergent_lane_pc;
25 DW_OP_call_ref %__active_lane_pc;
26 ];
27 a;
28 %1 = EXEC;
29 DBG_VALUE %1, $noreg, %__lex_1_save_exec;
30 %2 = c1;
31$lex_1_start:
32 EXEC = %1 & %2;
33$lex_1_then:
34 DEFINE_DWARF %__divergent_lane_pc_1_then = DW_TAG_dwarf_procedure[
35 DW_AT_name = "__divergent_lane_pc_1_then";
36 DW_AT_location = DIExpression[
37 DW_OP_call_ref %__divergent_lane_pc;
38 DW_OP_addrx &lex_1_start;
39 DW_OP_stack_value;
40 DW_OP_LLVM_extend 64, 64;
41 DW_OP_call_ref %__lex_1_save_exec;
42 DW_OP_deref_type 64, %__uint_64;
43 DW_OP_LLVM_select_bit_piece 64, 64;
44 ];
45 ];
46 DBG_VALUE $noreg, $noreg, %DW_AT_LLVM_lane_pc, DIExpression[
47 DW_OP_call_ref %__divergent_lane_pc_1_then;
48 DW_OP_call_ref %__active_lane_pc;
49 ];
50 b;
51 %3 = EXEC;
52 DBG_VALUE %3, %__lex_1_1_save_exec;
53 %4 = c2;
54$lex_1_1_start:
55 EXEC = %3 & %4;
56$lex_1_1_then:
57 DEFINE_DWARF %__divergent_lane_pc_1_1_then = DW_TAG_dwarf_procedure[
58 DW_AT_name = "__divergent_lane_pc_1_1_then";
59 DW_AT_location = DIExpression[
60 DW_OP_call_ref %__divergent_lane_pc_1_then;
61 DW_OP_addrx &lex_1_1_start;
62 DW_OP_stack_value;
63 DW_OP_LLVM_extend 64, 64;
64 DW_OP_call_ref %__lex_1_1_save_exec;
65 DW_OP_deref_type 64, %__uint_64;
66 DW_OP_LLVM_select_bit_piece 64, 64;
67 ];
68 ];
69 DBG_VALUE $noreg, $noreg, %DW_AT_LLVM_lane_pc, DIExpression[
70 DW_OP_call_ref %__divergent_lane_pc_1_1_then;
71 DW_OP_call_ref %__active_lane_pc;
72 ];
73 c;
74 EXEC = ~EXEC & %3;
75$lex_1_1_else:
76 DEFINE_DWARF %__divergent_lane_pc_1_1_else = DW_TAG_dwarf_procedure[
77 DW_AT_name = "__divergent_lane_pc_1_1_else";
78 DW_AT_location = DIExpression[
79 DW_OP_call_ref %__divergent_lane_pc_1_then;
80 DW_OP_addrx &lex_1_1_end;
81 DW_OP_stack_value;
82 DW_OP_LLVM_extend 64, 64;
83 DW_OP_call_ref %__lex_1_1_save_exec;
84 DW_OP_deref_type 64, %__uint_64;
85 DW_OP_LLVM_select_bit_piece 64, 64;
86 ];
87 ];
88 DBG_VALUE $noreg, $noreg, %DW_AT_LLVM_lane_pc, DIExpression[
89 DW_OP_call_ref %__divergent_lane_pc_1_1_else;
90 DW_OP_call_ref %__active_lane_pc;
91 ];
92 d;
93 EXEC = %3;
94$lex_1_1_end:
95 DBG_VALUE $noreg, $noreg, %DW_AT_LLVM_lane_pc, DIExpression[
96 DW_OP_call_ref %__divergent_lane_pc;
97 DW_OP_call_ref %__active_lane_pc;
98 ];
99 e;
100 EXEC = ~EXEC & %1;
101$lex_1_else:
102 DEFINE_DWARF %__divergent_lane_pc_1_else = DW_TAG_dwarf_procedure[
103 DW_AT_name = "__divergent_lane_pc_1_else";
104 DW_AT_location = DIExpression[
105 DW_OP_call_ref %__divergent_lane_pc;
106 DW_OP_addrx &lex_1_end;
107 DW_OP_stack_value;
108 DW_OP_LLVM_extend 64, 64;
109 DW_OP_call_ref %__lex_1_save_exec;
110 DW_OP_deref_type 64, %__uint_64;
111 DW_OP_LLVM_select_bit_piece 64, 64;
112 ];
113 ];
114 DBG_VALUE $noreg, $noreg, %DW_AT_LLVM_lane_pc, DIExpression[
115 DW_OP_call_ref %__divergent_lane_pc_1_else;
116 DW_OP_call_ref %__active_lane_pc;
117 ];
118 f;
119 EXEC = %1;
120$lex_1_end:
121 DBG_VALUE $noreg, $noreg, %DW_AT_LLVM_lane_pc DIExpression[
122 DW_OP_call_ref %__divergent_lane_pc;
123 DW_OP_call_ref %__active_lane_pc;
124 ];
125 g;
126$lex_end:
DWARF 程序 %__active_lane_pc
用於使用當前程式位置更新處於活動狀態的 lane pc 元素。
為區域條目時儲存的執行遮罩建立人為變數 %__lex_1_save_exec 和 %__lex_1_1_save_exec。使用 DBG_VALUE
虛擬指令,將建立位置列表條目,以描述在任何給定程式位置配置人為變數的位置。編譯器可能會將它們配置到暫存器或將它們溢出到記憶體。
每個區域的 DWARF 程序都使用儲存的執行遮罩人為變數的值,僅更新在進入區域時處於活動狀態的 lane。所有其他 lane 都保留它們上次活動的封閉區域的值。如果它們在進入子程式時未處於活動狀態,則將具有未定義的位置描述。
可以類似地處理其他結構化的控制流程區域。例如,迴圈會將區域的發散程式位置設定在迴圈的結尾。任何活動的 lane 都將在迴圈中,而任何不活動的 lane 都必須已退出迴圈。
IF/THEN/ELSEIF/ELSEIF/...
區域可以視為 IF/THEN/ELSE
區域的巢狀結構來處理。
DWARF 程序可以使用 DW_AT_LLVM_active_lane 中描述的活動 lane 人為變數,而不是實際的 EXEC
遮罩,以便支援整個或四分之一 wavefront 模式。
DW_AT_LLVM_active_lane
¶
子程式除錯資訊條目上的 DW_AT_LLVM_active_lane
屬性用於指定 SIMT 執行緒的概念性活動 lane。
可以修改執行遮罩以實作整個或四分之一 wavefront 模式運算。例如,可能需要暫時啟用所有 lane 以執行整個 wavefront 運算。此類區域將儲存 EXEC
遮罩,更新它以啟用必要的 lane,執行運算,然後從儲存的值還原 EXEC
遮罩。在執行整個 wavefront 區域時,概念性執行遮罩是儲存的值,而不是 EXEC
值。
這可以透過為活動 lane 遮罩定義人為變數來處理。活動 lane 遮罩人為變數對於正常區域將是實際的 EXEC
遮罩,對於暫時更新遮罩的區域將是儲存的執行遮罩。為此人為變數建立的位置列表運算式用於定義 DW_AT_LLVM_active_lane
屬性的值。
DW_AT_LLVM_augmentation
¶
對於 AMDGPU,編譯單元除錯資訊條目的 DW_AT_LLVM_augmentation
屬性具有以下擴充字串值
[amdgpu:v0.0]
“vX.Y” 指定編譯單元的 DWARF 中使用的 AMDGPU 擴充功能的主要版本號 X 和次要版本號 Y。版本號符合 [SEMVER]。
呼叫框架資訊¶
DWARF 呼叫框架資訊 (CFI) 描述消費者如何虛擬展開執行中程序或核心轉儲中的呼叫框架。請參閱 DWARF 第 5 版第 6.4 節和 A.6.4 呼叫框架資訊。
對於 AMDGPU,通用資訊條目 (CIE) 欄位具有以下值
augmentation
字串包含以下以 null 終止的 UTF-8 字串[amd:v0.0]
vX.Y
指定用於此 CIE 或使用它的 FDE 的 AMDGPU 擴充功能的主要版本號 X 和次要版本號 Y。版本號符合 [SEMVER]。address_size
的Global
位址空間定義於 位址空間識別碼。segment_selector_size
為 0,因為 AMDGPU 不使用區段選擇器。code_alignment_factor
為 4 位元組。data_alignment_factor
為 4 位元組。return_address_register
對於 32 位元程序為PC_32
,對於 64 位元程序為PC_64
,定義於 暫存器識別碼。initial_instructions
由於暫存器較少的子程式 X 可以從配置更多暫存器的子程式 Y 呼叫,因此 X 不會變更任何額外的暫存器,因為它無法存取它們。因此,所有欄的預設規則是same value
。
對於 AMDGPU,暫存器編號遵循 暫存器識別碼 中定義的編號。
對於 AMDGPU,指令大小是可變的。消費者可以從返回位址中減去 1,以取得呼叫站點指令中位元組的位址。請參閱 DWARF 第 5 版第 6.4.4 節。
加速存取¶
請參閱 DWARF 第 5 版第 6.1 節。
依名稱查找區段標頭¶
請參閱 DWARF 第 5 版第 6.1.1.4.1 節和 A.6.1.1 依名稱查找。
對於 AMDGPU,依名稱查找區段標頭表
augmentation_string_size
(uword)
設定為
augmentation_string
值的長度,該長度始終為 4 的倍數。
augmentation_string
(UTF-8 字元序列)
包含以下 UTF-8 字串,以 null 填補至 4 位元組的倍數
[amdgpu:v0.0]“vX.Y” 指定此索引的 DWARF 中使用的 AMDGPU 擴充功能的主要版本號 X 和次要版本號 Y。版本號符合 [SEMVER]。
注意
這與 DWARF 第 5 版定義不同,後者要求前 4 個字元為供應商 ID。但這與其他擴充字串一致,並且確實允許多個供應商的貢獻。但是,向後相容性可能更理想。
依位址查找區段標頭¶
請參閱 DWARF 第 5 版第 6.1.2 節。
對於 AMDGPU,依位址查找區段標頭表
address_size
(ubyte)
符合 位址空間識別碼 中定義的
Global
位址空間的位址大小。
segment_selector_size
(ubyte)
AMDGPU 不使用區段選擇器,因此此值為 0。
.debug_aranges
中的條目沒有區段選擇器。
行號資訊¶
請參閱 DWARF 第 5 版第 6.2 節和 A.6.2 行號資訊。
AMDGPU 不使用 isa
狀態機暫存器,並且始終將其設定為 0。指令集必須從 ELF 檔案標頭 e_flags
欄位的 EF_AMDGPU_MACH
位元位置取得(請參閱 ELF 標頭)。請參閱 DWARF 第 5 版第 6.2.2 節。
對於 AMDGPU,行號程式標頭欄位具有以下值(請參閱 DWARF 第 5 版第 6.2.4 節)
address_size
(ubyte)符合 位址空間識別碼 中定義的
Global
位址空間的位址大小。segment_selector_size
(ubyte)AMDGPU 不使用區段選擇器,因此此值為 0。
minimum_instruction_length
(ubyte)對於 GFX9-GFX11,此值為 4。
maximum_operations_per_instruction
(ubyte)對於 GFX9-GFX11,此值為 1。
線上編譯程式(例如,由 OpenCL 語言運行時編譯的程式)的原始碼文字可以嵌入到 DWARF Version 5 行號表 (line table) 中。請參閱 DWARF Version 5 第 6.2.4.1 節,該節已由異質除錯的 DWARF 擴展章節 DW_LNCT_LLVM_source 更新。
用於控制 AMDGPU 中原始碼嵌入的 Clang 選項定義於 AMDGPU Clang 除錯選項 中。
表 50 AMDGPU Clang 除錯選項¶ 除錯旗標 (Debug Flag)
描述
-g[no-]embed-source
啟用/停用在 DWARF 除錯區段中嵌入原始碼文字。適用於原始碼無法寫入磁碟的環境,例如執行線上編譯時。
例如
-gembed-source
啟用嵌入原始碼。
-gno-embed-source
停用嵌入原始碼。
32 位元和 64 位元 DWARF 格式¶
請參閱 DWARF Version 5 第 7.4 節和 A.7.4 32 位元和 64 位元 DWARF 格式。
適用於 AMDGPU
對於
amdgcn
目標架構,僅支援 64 位元處理程序位址空間。生產者可以產生 32 位元或 64 位元 DWARF 格式。LLVM 產生 32 位元 DWARF 格式。
單元標頭 (Unit Headers)¶
對於 AMDGPU,以下值適用於 DWARF Version 5 第 7.5.1.1、7.5.1.2 和 7.5.1.3 節中描述的每個單元標頭。
address_size
(ubyte)符合 位址空間識別碼 中定義的
Global
位址空間的位址大小。
程式碼慣例 (Code Conventions)¶
本節提供每個支援的目標三元組 OS (作業系統) 所使用的程式碼慣例(請參閱 目標三元組)。
AMDHSA¶
本節提供當目標三元組 OS 為 amdhsa
時所使用的程式碼慣例(請參閱 目標三元組)。
程式碼物件元數據 (Code Object Metadata)¶
程式碼物件元數據指定與在 HSA [HSA] 相容的運行時環境上執行的程式碼物件相關聯的可擴展元數據(請參閱 AMDGPU 作業系統)。此元數據的編碼和語意取決於程式碼物件版本;請參閱 程式碼物件 V2 元數據、程式碼物件 V3 元數據、程式碼物件 V4 元數據 和 程式碼物件 V5 元數據。
程式碼物件元數據在註記記錄 (note record) 中指定(請參閱 註記記錄),並且當目標三元組 OS 為 amdhsa
時是必需的(請參閱 目標三元組)。它必須包含支援 HSA 相容運行時環境核心查詢所需的最低限度資訊。例如,dispatch 封包中需要的區段大小。此外,高階語言運行時環境可能需要包含其他資訊。例如,AMD OpenCL 運行時環境會記錄核心引數資訊。
程式碼物件 V2 元數據¶
警告
此版本的 LLVM 不再支援程式碼物件 V2 生成。
程式碼物件 V2 元數據由 NT_AMD_HSA_METADATA
註記記錄指定(請參閱 程式碼物件 V2 註記記錄)。
此元數據指定為 YAML 格式化的字串(請參閱 [YAML] 和 YAML I/O)。
此元數據表示為單個 YAML 文件,其中包含表 AMDHSA 程式碼物件 V2 元數據映射表 和參考表格中定義的映射 (mapping)。
對於布林值,字串值 false
和 true
分別用於 false 和 true。
其他資訊可以添加到映射中。為避免衝突,任何非 AMD 金鑰名稱都應以 “vendor-name.” 為前綴。
表 51 AMDHSA 程式碼物件 V2 元數據映射表¶ 字串金鑰 (String Key)
值類型 (Value Type)
是否必填?
描述
“Version” (版本)
2 個整數的序列 (sequence)
必填
第一個整數是主版本號 (major version)。目前為 1。
第二個整數是次要版本號 (minor version)。目前為 0。
“Printf”
字串序列
每個字串都是關於 printf 函數呼叫的編碼資訊。編碼資訊組織為以冒號 (':') 分隔的欄位 (field)。
ID:N:S[0]:S[1]:...:S[N-1]:FormatString
其中
ID
32 位元整數,作為每個 printf 函數呼叫的唯一 ID
N
32 位元整數,等於 printf 函數呼叫的引數數量減 1
S[i]
(其中 i = 0, 1, … , N-1)32 位元整數,表示 printf 函數呼叫的第 i 個 FormatString 引數的大小(以位元組為單位)
- FormatString (格式字串)
傳遞給 printf 函數呼叫的格式字串。
“Kernels” (核心)
映射序列
必填
程式碼物件中每個核心的映射序列。有關映射的定義,請參閱 AMDHSA 程式碼物件 V2 核心元數據映射表。
表 52 AMDHSA 程式碼物件 V2 核心元數據映射表¶ 字串金鑰 (String Key)
值類型 (Value Type)
是否必填?
描述
“Name” (名稱)
字串
必填
核心的原始碼名稱。
“SymbolName” (符號名稱)
字串
必填
核心描述符 ELF 符號的名稱。
“Language” (語言)
字串
核心的原始碼語言。值包括
“OpenCL C”
“OpenCL C++”
“HCC”
“OpenMP”
“LanguageVersion” (語言版本)
2 個整數的序列 (sequence)
第一個整數是主版本號。
第二個整數是次要版本號。
“Attrs” (屬性)
映射
核心屬性的映射。有關映射定義,請參閱 AMDHSA 程式碼物件 V2 核心屬性元數據映射表。
“Args” (引數)
映射序列
核心引數的映射序列。有關映射定義,請參閱 AMDHSA 程式碼物件 V2 核心引數元數據映射表。
“CodeProps” (程式碼屬性)
映射
與核心程式碼相關的屬性映射。有關映射定義,請參閱 AMDHSA 程式碼物件 V2 核心程式碼屬性元數據映射表。
表 53 AMDHSA 程式碼物件 V2 核心屬性元數據映射表¶ 字串金鑰 (String Key)
值類型 (Value Type)
是否必填?
描述
“ReqdWorkGroupSize” (必要工作群組大小)
3 個整數的序列
如果不是 0, 0, 0,則所有值必須 >=1,且 dispatch 工作群組大小 X、Y、Z 必須對應於指定的值。預設為 0, 0, 0。
對應於 OpenCL
reqd_work_group_size
屬性。“WorkGroupSizeHint” (工作群組大小提示)
3 個整數的序列
dispatch 工作群組大小 X、Y、Z 很可能為指定的值。
對應於 OpenCL
work_group_size_hint
屬性。“VecTypeHint” (向量類型提示)
字串
純量或向量類型的名稱。
對應於 OpenCL
vec_type_hint
屬性。“RuntimeHandle” (運行時環境句柄)
字串
與核心相關聯的外部符號名稱。OpenCL 運行時環境為符號分配全域緩衝區,並將核心的位址儲存到其中,用於裝置端佇列 (device side enqueueing)。僅適用於裝置端佇列核心。
表 54 AMDHSA 程式碼物件 V2 核心引數元數據映射表¶ 字串金鑰 (String Key)
值類型 (Value Type)
是否必填?
描述
“Name” (名稱)
字串
核心引數名稱。
“TypeName” (類型名稱)
字串
核心引數類型名稱。
“Size” (大小)
整數
必填
核心引數大小(以位元組為單位)。
“Align” (對齊)
整數
必填
核心引數對齊方式(以位元組為單位)。必須為 2 的冪次方。
“ValueKind” (值種類)
字串
必填
核心引數種類,指定如何設定對應的引數。值包括
- “ByValue” (傳值)
引數直接複製到 kernarg 中。
- “GlobalBuffer” (全域緩衝區)
傳遞 kernarg 中緩衝區資料的全域位址空間指標。
- “DynamicSharedPointer” (動態共享指標)
傳遞 kernarg 中動態分配 LDS 的群組位址空間指標。
- “Sampler” (取樣器)
傳遞 kernarg 中 S# 的全域位址空間指標。
- “Image” (影像)
傳遞 kernarg 中 T# 的全域位址空間指標。
- “Pipe” (管道)
傳遞 kernarg 中 OpenCL 管道的全域位址空間指標。
- “Queue” (佇列)
傳遞 kernarg 中 OpenCL 裝置佇列佇列的全域位址空間指標。
- “HiddenGlobalOffsetX” (隱藏全域偏移 X)
傳遞 kernarg 中 OpenCL 網格 dispatch 全域偏移的 X 維度。
- “HiddenGlobalOffsetY” (隱藏全域偏移 Y)
傳遞 kernarg 中 OpenCL 網格 dispatch 全域偏移的 Y 維度。
- “HiddenGlobalOffsetZ” (隱藏全域偏移 Z)
傳遞 kernarg 中 OpenCL 網格 dispatch 全域偏移的 Z 維度。
- “HiddenNone” (隱藏無)
核心未使用的引數。需要為其保留空間,但不需要進行設定。
- “HiddenPrintfBuffer” (隱藏 printf 緩衝區)
傳遞 kernarg 中運行時環境 printf 緩衝區的全域位址空間指標。與 “HiddenHostcallBuffer” 互斥。
- “HiddenHostcallBuffer” (隱藏主機呼叫緩衝區)
傳遞 kernarg 中運行時環境 hostcall 緩衝區的全域位址空間指標。與 “HiddenPrintfBuffer” 互斥。
- “HiddenDefaultQueue” (隱藏預設佇列)
傳遞 kernarg 中核心應預設使用的 OpenCL 裝置佇列佇列的全域位址空間指標。
- “HiddenCompletionAction” (隱藏完成動作)
用於幫助將佇列核心連結到祖先樹的全域位址空間指標,以確定父核心何時完成。
- “HiddenMultiGridSyncArg” (隱藏多網格同步引數)
傳遞 kernarg 中多網格同步的全域位址空間指標。
“ValueType” (值類型)
字串
未使用且已棄用。此項不應再發出,但為相容性而接受。
“PointeeAlign” (被指物對齊)
整數
指標類型核心引數的被指物類型對齊方式(以位元組為單位)。必須為 2 的冪次方。僅當 “ValueKind” 為 “DynamicSharedPointer” 時才存在。
“AddrSpaceQual” (位址空間限定詞)
字串
核心引數位址空間限定詞。僅當 “ValueKind” 為 “GlobalBuffer” 或 “DynamicSharedPointer” 時才存在。值為
“Private” (私有)
“Global” (全域)
“Constant” (常數)
“Local” (本地)
“Generic” (通用)
“Region” (區域)
“AccQual” (存取限定詞)
字串
核心引數存取限定詞。僅當 “ValueKind” 為 “Image” 或 “Pipe” 時才存在。值為
“ReadOnly” (唯讀)
“WriteOnly” (僅寫)
“ReadWrite” (讀寫)
“ActualAccQual” (實際存取限定詞)
字串
核心在核心引數上執行的實際記憶體存取。僅當 “ValueKind” 為 “GlobalBuffer”、“Image” 或 “Pipe” 時才存在。這可能比 “AccQual” 指示的更嚴格,以反映核心實際執行的操作。如果不存在,則運行時環境必須假設 “AccQual” 和 “IsConst” 所暗示的內容。值為
“ReadOnly” (唯讀)
“WriteOnly” (僅寫)
“ReadWrite” (讀寫)
“IsConst” (為常數)
布林值
指示核心引數是否為 const 限定。僅當 “ValueKind” 為 “GlobalBuffer” 時才存在。
“IsRestrict” (為 restrict)
布林值
指示核心引數是否為 restrict 限定。僅當 “ValueKind” 為 “GlobalBuffer” 時才存在。
“IsVolatile” (為 volatile)
布林值
指示核心引數是否為 volatile 限定。僅當 “ValueKind” 為 “GlobalBuffer” 時才存在。
“IsPipe” (為管道)
布林值
指示核心引數是否為 pipe 限定。僅當 “ValueKind” 為 “Pipe” 時才存在。
表 55 AMDHSA 程式碼物件 V2 核心程式碼屬性元數據映射表¶ 字串金鑰 (String Key)
值類型 (Value Type)
是否必填?
描述
“KernargSegmentSize” (Kernarg 區段大小)
整數
必填
kernarg 區段的大小(以位元組為單位),該區段保存核心引數的值。
“GroupSegmentFixedSize” (群組區段固定大小)
整數
必填
工作群組所需的群組區段記憶體量(以位元組為單位)。這不包括在 dispatch 核心時可能添加的任何動態分配的群組區段記憶體。
“PrivateSegmentFixedSize” (私有區段固定大小)
整數
必填
工作項目所需的固定私有位址空間記憶體量(以位元組為單位)。如果核心使用動態呼叫堆疊,則必須將呼叫堆疊的額外空間添加到此值。
“KernargSegmentAlign” (Kernarg 區段對齊)
整數
必填
kernarg 區段中引數的最大位元組對齊方式。必須為 2 的冪次方。
“WavefrontSize” (波前大小)
整數
必填
波前大小。必須為 2 的冪次方。
“NumSGPRs” (SGPR 數量)
整數
必填
GFX6-GFX11 的波前使用的純量暫存器數量。這包括 VCC、Flat Scratch (GFX7-GFX10) 和 XNACK (for GFX8-GFX10) 的特殊 SGPR。它不包括啟用陷阱處理常式時新增的 16 個 SGPR。它不會向上捨入到分配粒度。
“NumVGPRs” (VGPR 數量)
整數
必填
GFX6-GFX11 的每個工作項目使用的向量暫存器數量
“MaxFlatWorkGroupSize” (最大平面工作群組大小)
整數
必填
核心支援的最大平面工作群組大小(以工作項目為單位)。必須 >=1,並且如果不是 0, 0, 0,則與 ReqdWorkGroupSize 一致。
“NumSpilledSGPRs” (溢出 SGPR 數量)
整數
從純量暫存器到暫存器分配器建立的溢出位置的儲存次數。
“NumSpilledVGPRs” (溢出 VGPR 數量)
整數
從向量暫存器到暫存器分配器建立的溢出位置的儲存次數。
程式碼物件 V3 元數據¶
警告
此版本的 LLVM 不再支援程式碼物件 V3 的產生。
程式碼物件 V3 及更高版本的元數據由 NT_AMDGPU_METADATA
註記記錄指定(請參閱 程式碼物件 V3 及更高版本的註記記錄)。
此元數據表示為 Message Pack 格式化的二進制資料(請參閱 [MsgPack])。頂層是一個 Message Pack 映射,其中包括表 AMDHSA 程式碼物件 V3 元數據映射表 和參考表格中定義的金鑰。
其他資訊可以添加到映射中。為避免衝突,任何金鑰名稱都應以 “vendor-name.” 為前綴,其中 vendor-name
可以是供應商名稱和產生資訊的特定供應商工具的名稱。當前綴出現在由同一 vendor-name 添加的映射中時,前綴簡稱為 “.”。
表 56 AMDHSA 程式碼物件 V3 元數據映射表¶ 字串金鑰 (String Key)
值類型 (Value Type)
是否必填?
描述
“amdhsa.version” (amdhsa.版本)
2 個整數的序列 (sequence)
必填
第一個整數是主版本號 (major version)。目前為 1。
第二個整數是次要版本號 (minor version)。目前為 0。
“amdhsa.printf” (amdhsa.printf)
字串序列
每個字串都是關於 printf 函數呼叫的編碼資訊。編碼資訊組織為以冒號 (':') 分隔的欄位 (field)。
ID:N:S[0]:S[1]:...:S[N-1]:FormatString
其中
ID
32 位元整數,作為每個 printf 函數呼叫的唯一 ID
N
32 位元整數,等於 printf 函數呼叫的引數數量減 1
S[i]
(其中 i = 0, 1, … , N-1)32 位元整數,表示 printf 函數呼叫的第 i 個 FormatString 引數的大小(以位元組為單位)
- FormatString (格式字串)
傳遞給 printf 函數呼叫的格式字串。
“amdhsa.kernels” (amdhsa.核心)
映射序列
必填
程式碼物件中每個核心的映射序列。有關該映射中包含的金鑰定義,請參閱 AMDHSA 程式碼物件 V3 核心元數據映射表。
表 57 AMDHSA 程式碼物件 V3 核心元數據映射表¶ 字串金鑰 (String Key)
值類型 (Value Type)
是否必填?
描述
“.name” (名稱)
字串
必填
核心的原始碼名稱。
“.symbol” (符號)
字串
必填
核心描述符 ELF 符號的名稱。
“.language” (語言)
字串
核心的原始碼語言。值包括
“OpenCL C”
“OpenCL C++”
“HCC”
“HIP”
“OpenMP”
“Assembler” (組譯器)
“.language_version” (語言版本)
2 個整數的序列 (sequence)
第一個整數是主版本號。
第二個整數是次要版本號。
“.args” (引數)
映射序列
核心引數的映射序列。有關該映射中包含的金鑰定義,請參閱 AMDHSA 程式碼物件 V3 核心引數元數據映射表。
“.reqd_workgroup_size” (必要工作群組大小)
3 個整數的序列
如果不是 0, 0, 0,則所有值必須 >=1,且 dispatch 工作群組大小 X、Y、Z 必須對應於指定的值。預設為 0, 0, 0。
對應於 OpenCL
reqd_work_group_size
屬性。“.workgroup_size_hint” (工作群組大小提示)
3 個整數的序列
dispatch 工作群組大小 X、Y、Z 很可能為指定的值。
對應於 OpenCL
work_group_size_hint
屬性。“.vec_type_hint” (向量類型提示)
字串
純量或向量類型的名稱。
對應於 OpenCL
vec_type_hint
屬性。“.device_enqueue_symbol” (裝置佇列符號)
字串
與核心相關聯的外部符號名稱。OpenCL 運行時環境為符號分配全域緩衝區,並將核心的位址儲存到其中,用於裝置端佇列 (device side enqueueing)。僅適用於裝置端佇列核心。
“.kernarg_segment_size” (Kernarg 區段大小)
整數
必填
kernarg 區段的大小(以位元組為單位),該區段保存核心引數的值。
“.group_segment_fixed_size” (群組區段固定大小)
整數
必填
工作群組所需的群組區段記憶體量(以位元組為單位)。這不包括在 dispatch 核心時可能添加的任何動態分配的群組區段記憶體。
“.private_segment_fixed_size” (私有區段固定大小)
整數
必填
工作項目所需的固定私有位址空間記憶體量(以位元組為單位)。如果核心使用動態呼叫堆疊,則必須將呼叫堆疊的額外空間添加到此值。
“.kernarg_segment_align” (Kernarg 區段對齊)
整數
必填
kernarg 區段中引數的最大位元組對齊方式。必須為 2 的冪次方。
“.wavefront_size” (波前大小)
整數
必填
波前大小。必須為 2 的冪次方。
“.sgpr_count” (SGPR 數量)
整數
必填
GFX6-GFX9 的波前所需的純量暫存器數量。如果明確使用暫存器,或明確使用編號較高的暫存器,則需要暫存器。這包括 VCC、Flat Scratch (GFX7-GFX9) 和 XNACK (for GFX8-GFX9) 的特殊 SGPR。它不包括啟用陷阱處理常式時新增的 16 個 SGPR。它不會向上捨入到分配粒度。
“.vgpr_count” (VGPR 數量)
整數
必填
GFX6-GFX9 的每個工作項目所需的向量暫存器數量。如果明確使用暫存器,或明確使用編號較高的暫存器,則需要暫存器。
“.agpr_count” (AGPR 數量)
整數
必填
GFX90A、GFX908 的每個工作項目所需的累加器暫存器數量。
“.max_flat_workgroup_size” (最大平面工作群組大小)
整數
必填
核心支援的最大平面工作群組大小(以工作項目為單位)。必須 >=1,並且如果不是 0, 0, 0,則與 ReqdWorkGroupSize 一致。
“.sgpr_spill_count” (SGPR 溢出數量)
整數
從純量暫存器到暫存器分配器建立的溢出位置的儲存次數。
“.vgpr_spill_count” (VGPR 溢出數量)
整數
從向量暫存器到暫存器分配器建立的溢出位置的儲存次數。
“.kind” (種類)
字串
核心的種類,具有以下值
- “normal” (一般)
常規核心。
- “init” (初始化)
這些核心必須在載入包含的程式碼物件後調用,並且必須在調用同一程式碼物件中的任何 normal 和 fini 核心之前完成。
- “fini” (結束)
這些核心必須在卸載包含的程式碼物件之前調用,並且在同一程式碼物件中的所有 init 和 normal 核心都已調用並完成後調用。
如果省略,則假定為 “normal”。
“.max_num_work_groups_{x,y,z}” (最大工作群組數量_{x,y,z})
整數
X、Y 和 Z 維度中啟動的最大工作群組數量。每個數字必須 >=1。
表 58 AMDHSA 程式碼物件 V3 核心引數元數據映射表¶ 字串金鑰 (String Key)
值類型 (Value Type)
是否必填?
描述
“.name” (名稱)
字串
核心引數名稱。
“.type_name” (類型名稱)
字串
核心引數類型名稱。
“.size” (大小)
整數
必填
核心引數大小(以位元組為單位)。
“.offset” (偏移)
整數
必填
核心引數偏移(以位元組為單位)。偏移量必須是引數所需對齊方式的倍數。
“.value_kind” (值種類)
字串
必填
核心引數種類,指定如何設定對應的引數。值包括
- “by_value” (傳值)
引數直接複製到 kernarg 中。
- “global_buffer” (全域緩衝區)
傳遞 kernarg 中緩衝區資料的全域位址空間指標。
- “dynamic_shared_pointer” (動態共享指標)
傳遞 kernarg 中動態分配 LDS 的群組位址空間指標。
- “sampler” (取樣器)
傳遞 kernarg 中 S# 的全域位址空間指標。
- “image” (影像)
傳遞 kernarg 中 T# 的全域位址空間指標。
- “pipe” (管道)
傳遞 kernarg 中 OpenCL 管道的全域位址空間指標。
- “queue” (佇列)
傳遞 kernarg 中 OpenCL 裝置佇列佇列的全域位址空間指標。
- “hidden_global_offset_x” (隱藏全域偏移 X)
傳遞 kernarg 中 OpenCL 網格 dispatch 全域偏移的 X 維度。
- “hidden_global_offset_y” (隱藏全域偏移 Y)
傳遞 kernarg 中 OpenCL 網格 dispatch 全域偏移的 Y 維度。
- “hidden_global_offset_z” (隱藏全域偏移 Z)
傳遞 kernarg 中 OpenCL 網格 dispatch 全域偏移的 Z 維度。
- “hidden_none” (隱藏無)
核心未使用的引數。需要為其保留空間,但不需要進行設定。
- “hidden_printf_buffer” (隱藏 printf 緩衝區)
傳遞 kernarg 中運行時環境 printf 緩衝區的全域位址空間指標。在程式碼物件 V5 之前,與 “hidden_hostcall_buffer” 互斥。
- “hidden_hostcall_buffer” (隱藏主機呼叫緩衝區)
傳遞 kernarg 中運行時環境 hostcall 緩衝區的全域位址空間指標。在程式碼物件 V5 之前,與 “hidden_printf_buffer” 互斥。
- “hidden_default_queue” (隱藏預設佇列)
傳遞 kernarg 中核心應預設使用的 OpenCL 裝置佇列佇列的全域位址空間指標。
- “hidden_completion_action” (隱藏完成動作)
用於幫助將佇列核心連結到祖先樹的全域位址空間指標,以確定父核心何時完成。
- “hidden_multigrid_sync_arg” (隱藏多網格同步引數)
傳遞 kernarg 中多網格同步的全域位址空間指標。
“.value_type” (值類型)
字串
未使用且已棄用。此項不應再發出,但為相容性而接受。
“.pointee_align” (被指物對齊)
整數
指標類型核心引數的被指物類型對齊方式(以位元組為單位)。必須為 2 的冪次方。僅當 “.value_kind” 為 “dynamic_shared_pointer” 時才存在。
“.address_space” (位址空間)
字串
核心引數位址空間限定詞。僅當 “.value_kind” 為 “global_buffer” 或 “dynamic_shared_pointer” 時才存在。值為
“private” (私有)
“global” (全域)
“constant” (常數)
“local” (本地)
“generic” (通用)
“region” (區域)
“.access” (存取)
字串
核心引數存取限定詞。僅當 “.value_kind” 為 “image” 或 “pipe” 時才存在。值為
“read_only” (唯讀)
“write_only” (僅寫)
“read_write” (讀寫)
“.actual_access” (實際存取)
字串
核心在核心引數上執行的實際記憶體存取。僅當 “.value_kind” 為 “global_buffer”、“image” 或 “pipe” 時才存在。這可能比 “.access” 指示的更嚴格,以反映核心實際執行的操作。如果不存在,則運行時環境必須假設 “.access” 和 “.is_const” 所暗示的內容。值為
“read_only” (唯讀)
“write_only” (僅寫)
“read_write” (讀寫)
“.is_const” (為常數)
布林值
指示核心引數是否為 const 限定。僅當 “.value_kind” 為 “global_buffer” 時才存在。
“.is_restrict” (為 restrict)
布林值
指示核心引數是否為 restrict 限定。僅當 “.value_kind” 為 “global_buffer” 時才存在。
“.is_volatile” (為 volatile)
布林值
指示核心引數是否為 volatile 限定。僅當 “.value_kind” 為 “global_buffer” 時才存在。
“.is_pipe” (為管道)
布林值
指示核心引數是否為 pipe 限定。僅當 “.value_kind” 為 “pipe” 時才存在。
程式碼物件 V4 元數據¶
- . 警告:
程式碼物件 V4 不是此版本 LLVM 發出的預設程式碼物件版本。
程式碼物件 V4 元數據與 程式碼物件 V3 元數據 相同,但具有表 AMDHSA 程式碼物件 V4 元數據映射表變更 中定義的變更和新增內容。
程式碼物件 V5 元數據¶
程式碼物件 V5 元數據與 程式碼物件 V4 元數據 相同,但具有表 AMDHSA 程式碼物件 V5 元數據映射表變更、表 AMDHSA 程式碼物件 V5 核心元數據映射表新增內容 和表 AMDHSA 程式碼物件 V5 核心引數元數據映射表新增內容和變更 中定義的變更。
表 60 AMDHSA 程式碼物件 V5 元數據映射表變更¶ 字串金鑰 (String Key)
值類型 (Value Type)
是否必填?
描述
“amdhsa.version” (amdhsa.版本)
2 個整數的序列 (sequence)
必填
第一個整數是主版本號 (major version)。目前為 1。
第二個整數是次要版本號。目前為 2。
表 61 AMDHSA 程式碼物件 V5 核心元數據映射表新增內容¶ 字串金鑰 (String Key)
值類型 (Value Type)
是否必填?
描述
“.uses_dynamic_stack” (使用動態堆疊)
布林值
指示產生的機器碼是否使用動態大小的堆疊。
“.workgroup_processor_mode” (工作群組處理器模式)
布林值
(GFX10+) 控制 程式碼物件 V3 核心描述符 中的 ENABLE_WGP_MODE。
表 62 AMDHSA 程式碼物件 V5 核心屬性元數據映射表¶ 字串金鑰 (String Key)
值類型 (Value Type)
是否必填?
描述
“.uniform_work_group_size” (統一工作群組大小)
整數
指示核心是否要求全域大小的每個維度都是工作群組大小的相應維度的倍數。值 1 表示 true,值 0 表示 false。僅當值為 1 時才發出元數據。
表 63 AMDHSA 程式碼物件 V5 核心引數元數據映射表新增內容和變更¶ 字串金鑰 (String Key)
值類型 (Value Type)
是否必填?
描述
“.value_kind” (值種類)
字串
必填
核心引數種類,指定如何設定對應的引數。值包括:與程式碼物件 V3 元數據相同(請參閱 AMDHSA 程式碼物件 V3 核心引數元數據映射表),並具有以下新增內容
- “hidden_block_count_x” (隱藏區塊計數 X)
傳遞 kernarg 中 X 維度的網格 dispatch 工作群組計數。某些語言(例如 OpenCL)支援每個維度中的最後一個工作群組為部分工作群組。此計數僅包括非部分工作群組計數。這與 AQL dispatch 封包中的值不同,後者具有工作項目中的網格大小。
- “hidden_block_count_y” (隱藏區塊計數 Y)
傳遞 kernarg 中 Y 維度的網格 dispatch 工作群組計數。某些語言(例如 OpenCL)支援每個維度中的最後一個工作群組為部分工作群組。此計數僅包括非部分工作群組計數。這與 AQL dispatch 封包中的值不同,後者具有工作項目中的網格大小。如果網格維度為 1,則必須為 1。
- “hidden_block_count_z” (隱藏區塊計數 Z)
傳遞 kernarg 中 Z 維度的網格 dispatch 工作群組計數。某些語言(例如 OpenCL)支援每個維度中的最後一個工作群組為部分工作群組。此計數僅包括非部分工作群組計數。這與 AQL dispatch 封包中的值不同,後者具有工作項目中的網格大小。如果網格維度為 1 或 2,則必須為 1。
- “hidden_group_size_x” (隱藏群組大小 X)
傳遞 kernarg 中 X 維度的網格 dispatch 工作群組大小。此大小僅適用於非部分工作群組。這與 AQL dispatch 封包工作群組大小的值相同。
- “hidden_group_size_y” (隱藏群組大小 Y)
傳遞 kernarg 中 Y 維度的網格 dispatch 工作群組大小。此大小僅適用於非部分工作群組。這與 AQL dispatch 封包工作群組大小的值相同。如果網格維度為 1,則必須為 1。
- “hidden_group_size_z” (隱藏群組大小 Z)
傳遞 kernarg 中 Z 維度的網格 dispatch 工作群組大小。此大小僅適用於非部分工作群組。這與 AQL dispatch 封包工作群組大小的值相同。如果網格維度為 1 或 2,則必須為 1。
- “hidden_remainder_x” (隱藏餘數 X)
如果存在 X 維度的部分工作群組,則為該部分工作群組的網格 dispatch 工作群組大小。如果 X 維度中不存在部分工作群組,則必須為零。
- “hidden_remainder_y” (隱藏餘數 Y)
如果存在 Y 維度的部分工作群組,則為該部分工作群組的網格 dispatch 工作群組大小。如果 Y 維度中不存在部分工作群組,則必須為零。
- “hidden_remainder_z” (隱藏餘數 Z)
如果存在 Z 維度的部分工作群組,則為該部分工作群組的網格 dispatch 工作群組大小。如果 Z 維度中不存在部分工作群組,則必須為零。
- “hidden_grid_dims” (隱藏網格維度)
網格 dispatch 維度。這與 AQL dispatch 封包維度的值相同。必須為介於 1 到 3 之間的值。
- “hidden_heap_v1” (隱藏堆積 v1)
指向已初始化記憶體緩衝區的全域位址空間指標,該緩衝區符合 malloc/free 裝置庫 V1 版本實作的要求。
- “hidden_dynamic_lds_size” (隱藏動態 LDS 大小)
傳遞 kernarg 中動態分配的 LDS 記憶體大小。
- “hidden_private_base” (隱藏私有基底)
平面定址私有光圈基底的高 32 位元。僅供 GFX8 用於允許私有區段和平面位址之間的轉換。請參閱 平面 Scratch。
- “hidden_shared_base” (隱藏共享基底)
平面定址共享光圈基底的高 32 位元。僅供 GFX8 用於允許共享區段和平面位址之間的轉換。請參閱 平面 Scratch。
- “hidden_queue_ptr” (隱藏佇列指標)
指向 ROCm 運行時環境
struct amd_queue_t
結構的全域記憶體位址空間指標,用於關聯的 dispatch AQL 封包的 HSA 佇列。僅在 GFX9 之前的裝置上用於陷阱處理常式 ABI(請參閱 陷阱處理常式 ABI)。
核心 Dispatch¶
HSA 架構佇列語言 (AQL) 定義了一個使用者空間記憶體介面,可用於以代理程式獨立的方式控制核心的 dispatch。代理程式可以使用 HSA 相容的運行時環境為其建立零個或多個 AQL 佇列(請參閱 AMDGPU 作業系統),其中可以放置 AQL 封包(所有封包均為 64 位元組)。有關 AQL 佇列機制和封包佈局,請參閱HSA 平台系統架構規範 [HSA]。
核心代理程式的封包處理器負責偵測和 dispatch 與其關聯的 AQL 佇列中的 HSA 核心。對於 AMD GPU,封包處理器由硬體命令處理器 (CP)、異步 dispatch 控制器 (ADC) 和著色器處理器輸入控制器 (SPI) 實作。
可以使用 HSA 相容的運行時環境來分配 AQL 佇列物件。它使用核心模式驅動程式來初始化 AQL 佇列並向 CP 註冊。
若要 dispatch 核心,請執行以下動作。這可以在 CPU 主機程式中發生,也可以從在 GPU 上執行的 HSA 核心發生。
取得要在其上執行核心的核心代理程式的 AQL 佇列指標。
取得要執行的核心的核心描述符指標(請參閱 核心描述符)。它必須適用於 HSA 相容運行時環境在與 AQL 佇列關聯的核心代理程式上載入的程式碼物件中包含的核心。
使用 HSA 相容運行時環境分配器為具有 kernarg 屬性的記憶體區域分配空間,以用於將執行核心的核心代理程式。它必須至少為 16 位元組對齊。
核心引數值會指派給核心引數記憶體分配。佈局在HSA 程式設計人員語言參考 [HSA] 中定義。對於 AMDGPU,核心執行直接存取核心引數記憶體,方式與存取常數記憶體的方式相同。(請注意,HSA 規範允許實作將核心引數內容複製到核心存取的另一個位置。)
在 AQL 佇列上建立 AQL 核心 dispatch 封包。HSA 相容運行時環境 API 使用 64 位元原子操作在 AQL 佇列中為封包保留空間。必須設定封包,並且最終寫入必須使用原子儲存發佈 (atomic store release) 來設定封包種類,以確保封包內容對核心代理程式可見。AQL 定義了門鈴訊號機制,以通知核心代理程式 AQL 佇列已更新。這些規則以及 AQL 佇列和核心 dispatch 封包的佈局在HSA 系統架構規範 [HSA] 中定義。
核心 dispatch 封包包含有關實際 dispatch 的資訊,例如網格和工作群組大小,以及來自程式碼物件的有關核心的資訊,例如區段大小。可以使用 HSA 相容運行時環境對核心符號的查詢來取得程式碼物件值,這些值記錄在 程式碼物件元數據 中。
CP 執行微指令,並負責偵測和設定 GPU,以執行核心分派的波前。
CP 確保當波前開始執行核心機器碼時,純量通用暫存器 (SGPR) 和向量通用暫存器 (VGPR) 會依照機器碼的要求進行設定。所需的設定定義於核心描述符中。初始暫存器狀態定義於初始核心執行狀態中。
核心機器碼的前言(請參閱核心前言)會先設定必要的機器狀態,然後繼續執行對應於核心的機器碼。
當核心分派完成執行時,如果核心分派封包中指定的完成訊號不為 0,CP 會發出完成訊號。
記憶體空間¶
記憶體空間屬性如下:
表 64 AMDHSA 記憶體空間¶ 記憶體空間名稱
HSA 區段名稱
硬體名稱
位址大小
NULL 值
私有
private
scratch
32
0x00000000
本地
group
LDS
32
0xFFFFFFFF
全域
global
global
64
0x0000000000000000
常數
constant
與全域相同
64
0x0000000000000000
通用
flat
flat
64
0x0000000000000000
區域
不適用
GDS
32
未針對 AMDHSA 實作
全域和常數記憶體空間都使用全域虛擬位址,這與 CPU 使用的虛擬位址空間相同。但是,有些虛擬位址可能僅 CPU 可存取,有些僅 GPU 可存取,有些則兩者皆可存取。
使用常數記憶體空間表示資料在核心執行期間不會變更。這允許使用純量讀取指令。向量和純量 L1 快取會在每次核心分派執行前,使不穩定的資料失效,以允許常數記憶體在核心分派之間變更值。
本機記憶體空間使用硬體本機資料儲存區 (LDS),當硬體建立波前的工作群組時會自動配置,並在工作群組的所有波前終止時釋放。資料儲存區 (DS) 指令可用於存取它。
私有記憶體空間使用硬體暫存記憶體支援。如果核心使用暫存記憶體,則硬體會配置記憶體,該記憶體使用波前通道雙字組(4 位元組)交錯方式存取。從私有位址到實體位址的對應關係為:
wavefront-scratch-base + (private-address * wavefront-size * 4) + (wavefront-lane-id * 4)
波前決定波前暫存基底位址的方式有所不同(請參閱初始核心執行狀態)。此記憶體可以使用緩衝區指令,透過暫存緩衝區描述符和每個波前的暫存偏移量、透過暫存指令或透過平面指令以交錯方式存取。如果波前的每個通道存取相同的私有位址,則交錯會導致存取相鄰的雙字組,因此需要提取較少的快取行。除了 GFX9-GFX11 中的平面和暫存指令外,不支援多字組存取。
通用位址空間使用 GFX7-GFX11 中可用的硬體平面位址支援。這使用兩個固定的虛擬位址範圍(私有和本機孔徑),它們位於可定址全域記憶體範圍之外,以將平面位址對應到私有或本機位址。
FLAT 指令可以採用平面位址,並根據位址是否在其中一個孔徑範圍內,存取全域、私有(暫存)和群組 (LDS) 記憶體。平面存取暫存記憶體需要硬體孔徑設定和核心前言中的設定(請參閱平面暫存記憶體)。平面存取 LDS 需要硬體孔徑設定和 M0 (GFX7-GFX8) 暫存器設定(請參閱M0)。
若要在區段位址和平面位址之間轉換,可以使用孔徑位址的基底位址。對於 GFX7-GFX8,這些位址可在HSA AQL 佇列中找到,其位址可以使用佇列指標 SGPR 取得(請參閱初始核心執行狀態)。對於 GFX9-GFX11,孔徑基底位址可直接作為內嵌常數暫存器 SRC_SHARED_BASE/LIMIT
和 SRC_PRIVATE_BASE/LIMIT
使用。在 64 位元位址模式中,孔徑大小為 2^32 位元組,基底對齊至 2^32,這使得從平面位址轉換為區段位址或從區段位址轉換為平面位址更容易。
影像和取樣器¶
由 HSA 相容執行階段建立的影像和取樣器控制代碼(請參閱AMDGPU 作業系統)分別是硬體 32 位元組 V# 和 48 位元組 S# 物件的 64 位元位址。為了支援 HSA query_sampler
操作,額外使用兩個雙字組來儲存 HSA BRIG 列舉值,用於無法從 S# 表示法中輕易推導出的查詢。
HSA 訊號¶
由 HSA 相容執行階段建立的 HSA 訊號控制代碼(請參閱AMDGPU 作業系統)是在 CPU 和 GPU 皆可存取的記憶體中配置的結構的 64 位元位址。此結構由執行階段定義,並可能在版本之間變更。例如,請參閱[AMD-ROCm-github]。
HSA AQL 佇列¶
HSA AQL 佇列結構由 HSA 相容執行階段定義(請參閱AMDGPU 作業系統),並可能在版本之間變更。例如,請參閱[AMD-ROCm-github]。對於某些處理器,它包含實作某些語言功能所需的欄位,例如平面位址孔徑基底。它還包含 CP 使用的欄位,例如管理暫存記憶體的配置。
核心描述符¶
核心描述符包含 CP 啟動核心執行所需的資訊,包括實作核心的機器碼的進入點位址。
程式碼物件 V3 核心描述符¶
CP 微指令碼要求核心描述符以 64 位元組對齊方式配置。
V3 之前的程式碼物件的 CP 使用的欄位,也與程式碼物件 V3 核心描述符中指定的欄位一致。
表 65 程式碼物件 V3 核心描述符¶ 位元
大小
欄位名稱
描述
31:0
4 位元組
GROUP_SEGMENT_FIXED_SIZE
工作群組所需的固定本機位址空間記憶體量,以位元組為單位。這不包括在核心分派時可能新增的任何動態配置的本機位址空間記憶體。
63:32
4 位元組
PRIVATE_SEGMENT_FIXED_SIZE
工作項目所需的固定私有位址空間記憶體量,以位元組為單位。當無法預測此值時,程式碼物件 v4 和更舊版本會將此值設定為高於最低要求。
95:64
4 位元組
KERNARG_SIZE
AQL 分派封包指向的 kernarg 記憶體大小。kernarg 記憶體用於將引數傳遞給核心。
如果分派封包中的 kernarg 指標為 NULL,則沒有核心引數。
如果分派封包中的 kernarg 指標不為 NULL,且此值為 0,則 kernarg 記憶體大小未指定。
如果分派封包中的 kernarg 指標不為 NULL,且此值不為 0,則此值指定 kernarg 記憶體大小(以位元組為單位)。建議提供一個值,因為 CP 可能會使用它來最佳化使 kernarg 記憶體對核心程式碼可見。
127:96
4 位元組
保留,必須為 0。
191:128
8 位元組
KERNEL_CODE_ENTRY_BYTE_OFFSET
從核心描述符的基底位址到核心的進入點指令的位元組偏移量(可能為負值),該指令必須以 256 位元組對齊。
351:192
20 位元組
保留,必須為 0。
383:352
4 位元組
COMPUTE_PGM_RSRC3
- GFX6-GFX9
保留,必須為 0。
- GFX90A、GFX942
CP 用於設定
COMPUTE_PGM_RSRC3
組態暫存器的運算著色器 (CS) 程式設定。請參閱GFX90A、GFX942 的 compute_pgm_rsrc3。- GFX10-GFX11
CP 用於設定
COMPUTE_PGM_RSRC3
組態暫存器的運算著色器 (CS) 程式設定。請參閱GFX10-GFX11 的 compute_pgm_rsrc3。- GFX12
CP 用於設定
COMPUTE_PGM_RSRC3
組態暫存器的運算著色器 (CS) 程式設定。請參閱GFX12 的 compute_pgm_rsrc3。415:384
4 位元組
COMPUTE_PGM_RSRC1
CP 用於設定
COMPUTE_PGM_RSRC1
組態暫存器的運算著色器 (CS) 程式設定。請參閱GFX6-GFX12 的 compute_pgm_rsrc1。447:416
4 位元組
COMPUTE_PGM_RSRC2
CP 用於設定
COMPUTE_PGM_RSRC2
組態暫存器的運算著色器 (CS) 程式設定。請參閱GFX6-GFX12 的 compute_pgm_rsrc2。458:448
7 位元
請參閱下方的個別位元。
啟用 SGPR 使用者資料暫存器的設定(請參閱初始核心執行狀態)。
請求的 SGPR 使用者資料暫存器總數不得超過 16 個,且必須與
compute_pgm_rsrc2.user_sgpr.user_sgpr_count
中的值相符。超過 16 個的任何請求都會被忽略。>448
1 位元
ENABLE_SGPR_PRIVATE_SEGMENT _BUFFER
如果AMDGPU 處理器的目標屬性欄指定架構平面暫存記憶體,則不支援且必須為 0。
>449
1 位元
ENABLE_SGPR_DISPATCH_PTR
>450
1 位元
ENABLE_SGPR_QUEUE_PTR
>451
1 位元
ENABLE_SGPR_KERNARG_SEGMENT_PTR
>452
1 位元
ENABLE_SGPR_DISPATCH_ID
>453
1 位元
ENABLE_SGPR_FLAT_SCRATCH_INIT
如果AMDGPU 處理器的目標屬性欄指定架構平面暫存記憶體,則不支援且必須為 0。
>454
1 位元
ENABLE_SGPR_PRIVATE_SEGMENT _SIZE
457:455
3 位元
保留,必須為 0。
458
1 位元
ENABLE_WAVEFRONT_SIZE32
- GFX6-GFX9
保留,必須為 0。
- GFX10-GFX11
如果為 0,則以波前大小 64 模式執行。
如果為 1,則以原生波前大小 32 模式執行。
459
1 位元
USES_DYNAMIC_STACK
表示產生的機器碼是否正在使用動態大小的堆疊。這僅在程式碼物件 v5 和更新版本中設定。
463:460
4 位元
保留,必須為 0。
470:464
7 位元
KERNARG_PRELOAD_SPEC_LENGTH
- GFX6-GFX9
保留,必須為 0。
- GFX90A、GFX942
從 kernarg 區段預先載入到使用者 SGPR 中以在核心執行之前使用的雙字組數量。(請參閱預先載入的核心引數)。
479:471
9 位元
KERNARG_PRELOAD_SPEC_OFFSET
- GFX6-GFX9
保留,必須為 0。
- GFX90A、GFX942
kernarg 區段中開始將資料預先載入到使用者 SGPR 的雙字組偏移量。(請參閱預先載入的核心引數)。
511:480
4 位元組
保留,必須為 0。
512
總大小 64 位元組。
表 66 GFX6-GFX12 的 compute_pgm_rsrc1¶ 位元
大小
欄位名稱
描述
5:0
6 位元
GRANULATED_WORKITEM_VGPR_COUNT
每個工作項目使用的向量暫存器區塊數量;粒度是裝置特定的
- GFX6-GFX9
vgprs_used 0..256
max(0, ceil(vgprs_used / 4) - 1)
- GFX90A、GFX942
vgprs_used 0..512
- vgprs_used = align(arch_vgprs, 4)
acc_vgprs
max(0, ceil(vgprs_used / 8) - 1)
- GFX10-GFX12(波前大小 64)
max_vgpr 1..256
max(0, ceil(vgprs_used / 4) - 1)
- GFX10-GFX12(波前大小 32)
max_vgpr 1..256
max(0, ceil(vgprs_used / 8) - 1)
其中 vgprs_used 定義為明確參考的最高 VGPR 編號加一。
CP 用於設定
COMPUTE_PGM_RSRC1.VGPRS
。組譯器會針對選定的處理器,從 .amdhsa_kernel 指令提供給 .amdhsa_next_free_vgpr 巢狀指令的值自動計算此值(請參閱AMDHSA 核心組譯器指令)。
9:6
4 位元
GRANULATED_WAVEFRONT_SGPR_COUNT
波前使用的純量暫存器區塊數量;粒度是裝置特定的
- GFX6-GFX8
sgprs_used 0..112
max(0, ceil(sgprs_used / 8) - 1)
- GFX9
sgprs_used 0..112
2 * max(0, ceil(sgprs_used / 16) - 1)
- GFX10-GFX12
保留,必須為 0。(始終配置 128 個 SGPR。)
其中 sgprs_used 定義為明確參考的最高 SGPR 編號加一,加上目標特定的額外特殊 SGPR 數量,用於 VCC、FLAT_SCRATCH (GFX7+) 和 XNACK_MASK (GFX8+),以及任何其他目標特定的限制。它不包括在啟用陷阱處理常式時新增的 16 個 SGPR。
目標特定的限制和特殊 SGPR 佈局定義在硬體文件中,可在處理器表格中找到。
CP 用於設定
COMPUTE_PGM_RSRC1.SGPRS
。組譯器會針對選定的處理器,從 .amdhsa_kernel 指令提供給 .amdhsa_next_free_sgpr 和 .amdhsa_reserve_* 巢狀指令的值自動計算此值(請參閱AMDHSA 核心組譯器指令)。
11:10
2 位元
PRIORITY
必須為 0。
以指定的優先順序開始執行波前。
CP 負責填寫
COMPUTE_PGM_RSRC1.PRIORITY
。13:12
2 位元
FLOAT_ROUND_MODE_32
波前開始執行時,單精度 (32 位元) 浮點運算的指定捨入模式。
浮點捨入模式值定義於浮點捨入模式列舉值中。
CP 用於設定
COMPUTE_PGM_RSRC1.FLOAT_MODE
。15:14
2 位元
FLOAT_ROUND_MODE_16_64
波前開始執行時,半精度/雙精度(16 位元和 64 位元)浮點運算的指定捨入反常模式。
浮點捨入模式值定義於浮點捨入模式列舉值中。
CP 用於設定
COMPUTE_PGM_RSRC1.FLOAT_MODE
。17:16
2 位元
FLOAT_DENORM_MODE_32
波前開始執行時,單精度 (32 位元) 浮點運算的指定反常模式。
浮點反常模式值定義於浮點反常模式列舉值中。
CP 用於設定
COMPUTE_PGM_RSRC1.FLOAT_MODE
。19:18
2 位元
FLOAT_DENORM_MODE_16_64
波前開始執行時,半精度/雙精度(16 位元和 64 位元)浮點運算的指定反常模式。
浮點反常模式值定義於浮點反常模式列舉值中。
CP 用於設定
COMPUTE_PGM_RSRC1.FLOAT_MODE
。20
1 位元
PRIV
必須為 0。
以特權陷阱處理常式模式開始執行波前。
CP 負責填寫
COMPUTE_PGM_RSRC1.PRIV
。21
1 位元
ENABLE_DX10_CLAMP
WG_RR_EN
- GFX9-GFX11
波前開始執行時,啟用 DX10 鉗位模式。向量 ALU 使用此模式來強制執行 DX10 樣式的 NaN 處理(設定時,將 NaN 鉗位為零,否則讓 NaN 通過)。
CP 用於設定
COMPUTE_PGM_RSRC1.DX10_CLAMP
。- GFX12
如果為 1,則波前以循環配置方式,相對於 SIMD 的其他波前進行排程。否則,波前以最舊的年齡順序排程。
CP 負責填寫
COMPUTE_PGM_RSRC1.WG_RR_EN
。22
1 位元
DEBUG_MODE
必須為 0。
以單步執行模式開始執行波前。
CP 負責填寫
COMPUTE_PGM_RSRC1.DEBUG_MODE
。23
1 位元
ENABLE_IEEE_MODE
DISABLE_PERF
- GFX9-GFX11
波前開始執行時,啟用 IEEE 模式。支援例外旗標收集的浮點運算碼將根據 IEEE 754-2008 標準,靜音並傳播發出訊號的 NaN 輸入。由於發出訊號的 NaN 傳播和靜音,min_dx10 和 max_dx10 變得符合 IEEE 754-2008 標準。
CP 用於設定
COMPUTE_PGM_RSRC1.IEEE_MODE
。- GFX12
保留。必須為 0。
24
1 位元
BULKY
必須為 0。
僅允許一個工作群組在運算單元上執行。
CP 負責填寫
COMPUTE_PGM_RSRC1.BULKY
。25
1 位元
CDBG_USER
必須為 0。
可用於控制偵錯程式碼的旗標。
CP 負責填寫
COMPUTE_PGM_RSRC1.CDBG_USER
。26
1 位元
FP16_OVFL
- GFX6-GFX8
保留,必須為 0。
- GFX9-GFX12
波前開始執行時,具有指定的 fp16 溢位模式。
如果為 0,fp16 溢位會產生 +/-INF 值。
如果為 1,則 +/-INF 輸入值或除以 0 導致的 fp16 溢位會產生 +/-INF,否則會將計算出的溢位鉗位為 +/-MAX_FP16(適當情況下)。
CP 用於設定
COMPUTE_PGM_RSRC1.FP16_OVFL
。28:27
2 位元
保留,必須為 0。
29
1 位元
WGP_MODE
- GFX6-GFX9
保留,必須為 0。
- GFX10-GFX12
如果為 0,則在 CU 波前執行模式中執行工作群組。
如果為 1,則在 WGP 波前執行模式中執行工作群組。
請參閱記憶體模型。
CP 用於設定
COMPUTE_PGM_RSRC1.WGP_MODE
。30
1 位元
MEM_ORDERED
- GFX6-GFX9
保留,必須為 0。
- GFX10-GFX12
控制 s_waitcnt 的 vmcnt 和 vscnt 計數器的行為。
如果為 0,vmcnt 會報告與取樣指令無序的載入完成和原子傳回,而 vscnt 會報告有序的儲存完成和無傳回的原子操作完成。
如果為 1,vmcnt 會報告有序的載入完成、原子傳回和取樣指令,而 vscnt 會報告有序的儲存完成和無傳回的原子操作完成。
CP 用於設定
COMPUTE_PGM_RSRC1.MEM_ORDERED
。31
1 位元
FWD_PROGRESS
- GFX6-GFX9
保留,必須為 0。
- GFX10-GFX12
如果為 0,則使用最舊優先原則執行 SIMD 波前。
如果為 1,則執行 SIMD 波前以確保波前將取得某些進展。
CP 用於設定
COMPUTE_PGM_RSRC1.FWD_PROGRESS
。32
總大小 4 位元組
表 67 GFX6-GFX12 的 compute_pgm_rsrc2¶ 位元
大小
欄位名稱
描述
0
1 位元
ENABLE_PRIVATE_SEGMENT
啟用私有區段的設定。
如果AMDGPU 處理器的目標屬性欄未指定架構平面暫存記憶體,則啟用 SGPR 波前暫存偏移系統暫存器的設定(請參閱初始核心執行狀態)。
如果AMDGPU 處理器的目標屬性欄指定架構平面暫存記憶體,則啟用 FLAT_SCRATCH 暫存器對的設定(請參閱初始核心執行狀態)。
CP 用於設定
COMPUTE_PGM_RSRC2.SCRATCH_EN
。5:1
5 位元
USER_SGPR_COUNT
請求的 SGPR 使用者資料暫存器總數。此數字必須大於或等於已啟用的使用者資料暫存器數量。
CP 用於設定
COMPUTE_PGM_RSRC2.USER_SGPR
。6
1 位元
ENABLE_TRAP_HANDLER
- GFX6-GFX11
必須為 0。
此位元代表
COMPUTE_PGM_RSRC2.TRAP_PRESENT
,如果執行階段已安裝陷阱處理常式,則 CP 會設定此位元。- GFX12
保留,必須為 0。
7
1 位元
ENABLE_SGPR_WORKGROUP_ID_X
啟用 X 維度工作群組 ID 的系統 SGPR 暫存器的設定(請參閱初始核心執行狀態)。
CP 用於設定
COMPUTE_PGM_RSRC2.TGID_X_EN
。8
1 位元
ENABLE_SGPR_WORKGROUP_ID_Y
啟用 Y 維度工作群組 ID 的系統 SGPR 暫存器的設定(請參閱初始核心執行狀態)。
CP 用於設定
COMPUTE_PGM_RSRC2.TGID_Y_EN
。9
1 位元
ENABLE_SGPR_WORKGROUP_ID_Z
啟用 Z 維度工作群組 ID 的系統 SGPR 暫存器的設定(請參閱初始核心執行狀態)。
CP 用於設定
COMPUTE_PGM_RSRC2.TGID_Z_EN
。10
1 位元
ENABLE_SGPR_WORKGROUP_INFO
啟用工作群組資訊的系統 SGPR 暫存器的設定(請參閱初始核心執行狀態)。
CP 用於設定
COMPUTE_PGM_RSRC2.TGID_SIZE_EN
。12:11
2 位元
ENABLE_VGPR_WORKITEM_ID
啟用用於工作項目 ID 的 VGPR 系統暫存器的設定。系統 VGPR 工作項目 ID 列舉值定義了這些值。
CP 用於設定
COMPUTE_PGM_RSRC2.TIDIG_CMP_CNT
。13
1 位元
ENABLE_EXCEPTION_ADDRESS_WATCH
必須為 0。
波前開始執行時,啟用位址監看例外,當 L1 偵測到執行緒存取感興趣的位址時,會產生這些例外。
CP 負責根據執行階段的要求,在
COMPUTE_PGM_RSRC2.EXCP_EN_MSB
中填寫位址監看位元。14
1 位元
ENABLE_EXCEPTION_MEMORY
必須為 0。
波前開始執行時,啟用記憶體違規例外,當從 L1 或 LDS 發生此波前的記憶體違規時(寫入唯讀記憶體、未對齊的原子操作、LDS 位址超出範圍、非法位址等),會產生這些例外。
CP 根據執行階段的要求,在
COMPUTE_PGM_RSRC2.EXCP_EN_MSB
中設定記憶體違規位元。23:15
9 位元
GRANULATED_LDS_SIZE
必須為 0。
CP 使用分派封包中的四捨五入值,而不是此值,因為分派可能包含動態配置的群組區段記憶體。CP 直接寫入
COMPUTE_PGM_RSRC2.LDS_SIZE
。要為每個工作群組配置的群組區段 (LDS) 量。粒度是裝置特定的
- GFX6
roundup(lds-size / (64 * 4))
- GFX7-GFX11
roundup(lds-size / (128 * 4))
- GFX950
roundup(lds-size / (320 * 4))
24
1 位元
ENABLE_EXCEPTION_IEEE_754_FP _INVALID_OPERATION
波前開始執行時,啟用指定的例外。
CP 用於設定
COMPUTE_PGM_RSRC2.EXCP_EN
(從位元 0..6 設定)。IEEE 754 FP 無效運算
25
1 位元
ENABLE_EXCEPTION_FP_DENORMAL _SOURCE
FP 反常,一個或多個輸入運算元是反常數
26
1 位元
ENABLE_EXCEPTION_IEEE_754_FP _DIVISION_BY_ZERO
IEEE 754 FP 除以零
27
1 位元
ENABLE_EXCEPTION_IEEE_754_FP _OVERFLOW
IEEE 754 FP FP 溢位
28
1 位元
ENABLE_EXCEPTION_IEEE_754_FP _UNDERFLOW
IEEE 754 FP 下溢
29
1 位元
ENABLE_EXCEPTION_IEEE_754_FP _INEXACT
IEEE 754 FP 不精確
30
1 位元
ENABLE_EXCEPTION_INT_DIVIDE_BY _ZERO
整數除以零(僅限 rcp_iflag_f32 指令)
31
1 位元
保留
保留,必須為 0。
32
總大小 4 位元組。
表 68 GFX90A、GFX942 的 compute_pgm_rsrc3¶ 位元
大小
欄位名稱
描述
5:0
6 位元
ACCUM_OFFSET
統一暫存器檔案中第一個 AccVGPR 的偏移量。粒度為 4。值為 0-63。0 - accum-offset = 4、1 - accum-offset = 8、…、63 - accum-offset = 256。
15:6
10 位元
保留,必須為 0。
16
1 位元
TG_SPLIT
如果為 0,則工作群組的波在同一個 CU 中啟動。
如果為 1,則工作群組的波可以在不同的 CU 中啟動。這些波不能使用 S_BARRIER 或 LDS。
31:17
15 位元
保留,必須為 0。
32
總大小 4 位元組。
表 69 GFX10-GFX11 的 compute_pgm_rsrc3¶ 位元
大小
欄位名稱
描述
3:0
4 位元
SHARED_VGPR_COUNT
在子向量模式下執行時,共用 VGPR 區塊的數量。對於波前大小 64,值為 0-15,表示 0-120 個 VGPR(粒度為 8),因此 (compute_pgm_rsrc1.vgprs +1)*4 + shared_vgpr_count*8 不超過 256。對於波前大小 32,shared_vgpr_count 必須為 0。
9:4
6 位元
INST_PREF_SIZE
- GFX10
保留,必須為 0。
- GFX11
要預先提取的指令位元組數,從核心的進入點指令開始,在波前開始執行之前。該值為 0..63,粒度為 128 位元組。
10
1 位元
TRAP_ON_START
- GFX10
保留,必須為 0。
- GFX11
必須為 0。
如果為 1,波前會透過陷入陷阱處理常式來開始執行。
CP 負責根據執行階段的要求,在
COMPUTE_PGM_RSRC3.TRAP_ON_START
中填寫啟動時陷入陷阱位元。11
1 位元
TRAP_ON_END
- GFX10
保留,必須為 0。
- GFX11
必須為 0。
如果為 1,波前執行會透過陷入陷阱處理常式來終止。
CP 負責根據執行階段的要求,在
COMPUTE_PGM_RSRC3.TRAP_ON_END
中填寫結束時陷入陷阱位元。30:12
19 位元
保留,必須為 0。
31
1 位元
IMAGE_OP
- GFX10
保留,必須為 0。
- GFX11
如果為 1,則核心執行包含影像指令。如果作為圖形管線的一部分執行,則影像讀取指令將停滯,等待執行任何必要的
WAIT_SYNC
柵欄,以指示較早的管線階段已完成寫入影像。不適用於非圖形管線一部分的運算核心,且必須為 0。
32
總大小 4 位元組。
表 70 GFX12 的 compute_pgm_rsrc3¶ 位元
大小
欄位名稱
描述
3:0
4 位元
保留
保留,必須為 0。
11:4
8 位元
INST_PREF_SIZE
要預先提取的指令位元組數,從核心的進入點指令開始,在波前開始執行之前。該值為 0..255,粒度為 128 位元組。
12
1 位元
保留
保留,必須為 0。
13
1 位元
GLG_EN
如果為 1,則將為此分派啟用群組啟動保證
30:14
17 位元
保留
保留,必須為 0。
31
1 位元
IMAGE_OP
如果為 1,則核心執行包含影像指令。如果作為圖形管線的一部分執行,則影像讀取指令將停滯,等待執行任何必要的
WAIT_SYNC
柵欄,以指示較早的管線階段已完成寫入影像。不適用於非圖形管線一部分的運算核心,且必須為 0。
32
總大小 4 位元組。
表 71 浮點捨入模式列舉值¶ 列舉名稱
值
描述
FLOAT_ROUND_MODE_NEAR_EVEN
0
捨入到最接近的偶數
FLOAT_ROUND_MODE_PLUS_INFINITY
1
朝 +無限大捨入
FLOAT_ROUND_MODE_MINUS_INFINITY
2
朝 -無限大捨入
FLOAT_ROUND_MODE_ZERO
3
朝 0 捨入
表 72 擴充 FLT_ROUNDS 列舉值¶ F32 NEAR_EVEN
F32 PLUS_INFINITY
F32 MINUS_INFINITY
F32 ZERO
F64/F16 NEAR_EVEN
1
11
14
17
F64/F16 PLUS_INFINITY
8
2
15
18
F64/F16 MINUS_INFINITY
9
12
3
19
F64/F16 ZERO
10
13
16
0
表 73 浮點反常模式列舉值¶ 列舉名稱
值
描述
FLOAT_DENORM_MODE_FLUSH_SRC_DST
0
清除來源和目的地反常值
FLOAT_DENORM_MODE_FLUSH_DST
1
清除輸出反常值
FLOAT_DENORM_MODE_FLUSH_SRC
2
清除來源反常值
FLOAT_DENORM_MODE_FLUSH_NONE
3
不清除
反常值清除是尊重符號的。即
"denormal-fp-math"="preserve-sign"
預期的行為。使用"denormal-fp-math"="positive-zero"
時,行為未定義
表 74 系統 VGPR 工作項目 ID 列舉值¶ 列舉名稱
值
描述
SYSTEM_VGPR_WORKITEM_ID_X
0
設定工作項目 X 維度 ID。
SYSTEM_VGPR_WORKITEM_ID_X_Y
1
設定工作項目 X 和 Y 維度 ID。
SYSTEM_VGPR_WORKITEM_ID_X_Y_Z
2
設定工作項目 X、Y 和 Z 維度 ID。
SYSTEM_VGPR_WORKITEM_ID_UNDEFINED
3
未定義。
初始核心執行狀態¶
本節定義封包處理器在每個波前開始執行之前將設定的暫存器狀態。這受到 CP/ADC/SPI 硬體控制器的限制。
SGPR 暫存器的順序已定義,但編譯器可以使用核心描述符中的 enable_sgpr_*
位元欄位來指定實際設定哪些暫存器(請參閱核心描述符)。用於已啟用暫存器的暫存器編號從 SGPR0 開始密集排列:第一個已啟用暫存器是 SGPR0,下一個已啟用暫存器是 SGPR1,依此類推;已停用的暫存器沒有 SGPR 編號。
初始 SGPR 最多包含 16 個使用者 SGPR,這些 SGPR 由 CP 設定,並適用於網格的所有波前。可以使用 enable_sgpr_*
位元欄位指定超過 16 個使用者 SGPR,在這種情況下,僅實際初始化前 16 個。緊隨其後的是系統 SGPR,這些 SGPR 由 ADC/SPI 設定,並且網格分派的每個波前可以具有不同的值。
SGPR 暫存器初始狀態定義於SGPR 暫存器設定順序中。
表 75 SGPR 暫存器設定順序¶ SGPR 順序
名稱 (核心描述符啟用欄位)
SGPR 數量
描述
優先
私有區段緩衝區 (enable_sgpr_private _segment_buffer)
4
請參閱 私有區段緩衝區。
接著
分派指標 (enable_sgpr_dispatch_ptr)
2
實際執行的核心分派之 AQL 分派封包的 64 位元位址。
接著
佇列指標 (enable_sgpr_queue_ptr)
2
分派封包排入佇列之 AQL 佇列的 amd_queue_t 物件的 64 位元位址。
接著
核心參數區段指標 (enable_sgpr_kernarg _segment_ptr)
2
核心參數區段的 64 位元位址。這直接從核心分派封包中的 kernarg_address 複製而來。
讓 CP 載入一次可避免在每個波前開始時都載入。
接著
分派 ID (enable_sgpr_dispatch_id)
2
正在執行的分派封包的 64 位元分派 ID。
接著
平面暫存初始化 (enable_sgpr_flat_scratch _init)
2
請參閱 平面暫存。
接著
私有區段大小 (enable_sgpr_private _segment_size)
1
單一工作項目的記憶體配置的 32 位元組大小。這是核心分派封包「私有區段位元組大小」欄位中的值,由 CP 四捨五入為 DWORD 的倍數。
讓 CP 載入一次可避免在每個波前開始時都載入。
這不適用於 GFX7-GFX8,因為它與平面暫存初始化的第二個 SGPR 值相同。然而,GFX9-GFX11 可能需要它,因為它改變了平面暫存初始化值的意義。
接著
預先載入的核心參數 (kernarg_preload_spec _length)
不適用
請參閱 預先載入的核心參數。
接著
工作群組 ID X (enable_sgpr_workgroup_id _X)
1
波前網格 X 維度的 32 位元工作群組 ID。
接著
工作群組 ID Y (enable_sgpr_workgroup_id _Y)
1
波前網格 Y 維度的 32 位元工作群組 ID。
接著
工作群組 ID Z (enable_sgpr_workgroup_id _Z)
1
波前網格 Z 維度的 32 位元工作群組 ID。
接著
工作群組資訊 (enable_sgpr_workgroup _info)
1
{first_wavefront, 14’b0000, ordered_append_term[10:0], threadgroup_size_in_wavefronts[5:0]}
接著
暫存波前偏移 (enable_sgpr_private _segment_wavefront_offset)
1
VGPR 暫存器的順序已定義,但編譯器可以使用 enable_vgpr* 位元欄位在核心描述符中指定實際設定的暫存器 (請參閱核心描述符)。用於啟用的暫存器的暫存器編號從 VGPR0 開始是密集的:第一個啟用的暫存器是 VGPR0,下一個啟用的暫存器是 VGPR1,依此類推;停用的暫存器沒有 VGPR 編號。
VGPR 初始狀態有不同的方法。
除非 AMDGPU 處理器的「目標屬性」欄另有規定,否則每個工作項目 ID 使用一個單獨的 VGPR 暫存器。此方法的 VGPR 暫存器初始狀態在 適用於未封裝工作項目 ID 方法的 VGPR 暫存器設定順序中定義。
如果 AMDGPU 處理器的「目標屬性」欄指定「封裝工作項目 ID」,則 VGPR0 暫存器的初始值用於所有工作項目 ID。此方法的暫存器佈局在 適用於封裝工作項目 ID 方法的暫存器佈局中定義。
表 76 適用於未封裝工作項目 ID 方法的 VGPR 暫存器設定順序¶ VGPR 順序
名稱 (核心描述符啟用欄位)
VGPR 數量
描述
優先
工作項目 ID X (始終初始化)
1
波前通道工作群組 X 維度的 32 位元工作項目 ID。
接著
工作項目 ID Y (enable_vgpr_workitem_id > 0)
1
波前通道工作群組 Y 維度的 32 位元工作項目 ID。
接著
工作項目 ID Z (enable_vgpr_workitem_id > 1)
1
波前通道工作群組 Z 維度的 32 位元工作項目 ID。
表 77 適用於封裝工作項目 ID 方法的暫存器佈局¶ 位元
大小
欄位名稱
描述
0:9
10 位元
工作項目 ID X
波前通道工作群組 X 維度的工作項目 ID。
始終初始化。
10:19
10 位元
工作項目 ID Y
波前通道工作群組 Y 維度的工作項目 ID。
如果 enable_vgpr_workitem_id > 0 則初始化,否則設定為 0。
20:29
10 位元
工作項目 ID Z
波前通道工作群組 Z 維度的工作項目 ID。
如果 enable_vgpr_workitem_id > 1 則初始化,否則設定為 0。
30:31
2 位元
保留,設定為 0。
暫存器的設定由 GPU CP/ADC/SPI 硬體完成,如下所示
工作群組 ID 之前的 SGPR 由 CP 使用 16 個使用者資料暫存器設定。
工作群組 ID 暫存器 X、Y、Z 由 ADC 設定,ADC 支援任何組合,包括無。
暫存波前偏移由 SPI 以每個波前為基礎設定,這就是為什麼它的值不能包含在每個佇列的平面暫存初始化值中的原因 (請參閱 平面暫存)。
VGPR 由 SPI 設定,SPI 僅支援指定 (X)、(X, Y) 或 (X, Y, Z)。
平面暫存暫存器對初始化在 平面暫存中描述。
全域區段可以使用緩衝區指令 (GFX6,具有 V# 64 位元位址支援)、平面指令 (GFX7-GFX11) 或全域指令 (GFX9-GFX11) 存取。
如果使用緩衝區操作,則編譯器可以產生具有以下屬性的 V#
基底位址為 0
無混洗
ATC:如果存在 IOMMU 則為 1 (例如 APU)
ptr64:1
MTYPE 設定為支援與執行階段相符的記憶體一致性 (例如 APU 的 CC 和 dGPU 的 NC)。
預先載入的核心參數¶
在支援此功能的硬體上,核心參數可以預先載入到使用者 SGPR 中,最多可達到可用的使用者 SGPR 最大數量。預先載入 SGPR 的配置發生在最後一個啟用的非核心參數預先載入使用者 SGPR 之後。(請參閱 初始核心執行狀態)
預先載入的資料是從核心參數區段複製而來,資料量由核心描述符的 kernarg_preload_spec_length 欄位中指定的值決定。然後,此資料會載入到連續的使用者 SGPR 中。接收預先載入的核心參數資料的 SGPR 數量與 kernarg_preload_spec_length 給定的值相對應。預先載入從核心參數區段內的 dword 偏移開始,該偏移由 kernarg_preload_spec_offset 欄位指定。
如果 kernarg_preload_spec_length 為非零值,CP 韌體將在 kernel_code_entry_byte_offset 中附加額外的 256 個位元組。此附加功能有助於將序言納入核心入口點,以處理為核心參數預先載入設計的程式碼在配備不相容韌體的硬體上執行的情況。如果硬體具有相容的韌體,則將跳過核心入口點開始處的 256 個位元組。
使用程式碼物件 V5 及更高版本,通常透過隱含引數指標存取的隱藏核心引數可以預先載入到使用者 SGPR 中。這些引數會新增至核心函數簽章,並標記有屬性 "inreg" 和 "amdgpu-hidden-argument"。(請參閱 AMDGPU LLVM IR 屬性)。
核心序言¶
編譯器在核心序言中執行初始化,具體取決於目標以及核心中堆疊使用情況和呼叫函數等資訊。此初始化的某些部分需要編譯器請求某些使用者和系統 SGPR 透過 核心描述符 出現在 初始核心執行狀態 中。
CFI¶
CFI 傳回位址未定義。
CFI CFA 是使用一個表達式定義的,該表達式評估為位置描述,該位置描述包含
DW_ASPACE_AMDGPU_private_lane
位址空間位址0
的一個記憶體位置描述。
M0¶
- GFX6-GFX8
如果核心可能透過 DS 或平面操作存取 LDS,則 M0 暫存器必須初始化為至少是 LDS 總大小的值。分派封包中提供 LDS 總大小。對於 M0,也可以使用給定目標的 LDS 最大可能值 (GFX6 為 0x7FFF,GFX7-GFX8 為 0xFFFF)。
- GFX9-GFX11
M0 暫存器不用於範圍檢查 LDS 存取,因此不需要在序言中初始化。
堆疊指標¶
如果核心有函數呼叫,則必須透過將 SGPR32 設定為最後一次本地配置之後的位址的未混洗暫存偏移,來設定 非核心函數 中描述的 ABI 堆疊指標。
幀指標¶
如果核心基於 SIFrameLowering
中定義的原因需要幀指標,則使用 SGPR33,並且始終在核心序言中設定為 0
。如果不需要幀指標,則幀指標的所有使用都會替換為立即 0
偏移。
平面暫存¶
初始化平面暫存有不同的方法。
如果 AMDGPU 處理器的「目標屬性」欄指定「不支援通用位址空間」
不支援平面暫存,並且沒有平面暫存暫存器對。
如果 AMDGPU 處理器的「目標屬性」欄指定「偏移平面暫存」
如果核心或其呼叫的任何函數可能使用平面操作來存取暫存記憶體,則序言程式碼必須設定 FLAT_SCRATCH 暫存器對 (FLAT_SCRATCH_LO/FLAT_SCRATCH_HI)。初始化使用平面暫存初始化和暫存波前偏移 SGPR 暫存器 (請參閱 初始核心執行狀態)
平面暫存初始化的低字組是從
SH_HIDDEN_PRIVATE_BASE_VIMID
到 SPI 為執行核心分派的佇列管理的暫存後備記憶體基底的 32 位元組偏移。這與暫存區段緩衝區 V# 基底位址中使用的值相同。CP 從執行階段取得此值。(暫存區段緩衝區基底位址為
SH_HIDDEN_PRIVATE_BASE_VIMID
加上此偏移。)序言必須新增暫存波前偏移的值,以從
SH_HIDDEN_PRIVATE_BASE_VIMID
取得波前的位元組暫存後備記憶體偏移。使用暫存區段緩衝區時,暫存波前偏移也必須用作私有區段位址的偏移。
由於 FLAT_SCRATCH_LO 的單位為 256 個位元組,因此偏移在移入 FLAT_SCRATCH_HI 之前必須右移 8 位。
FLAT_SCRATCH_HI 對應於 GFX7 上的 SGPRn-4 和 GFX8 上的 SGPRn-6 (其中 SGPRn 是分配給波前的編號最高的 SGPR)。FLAT_SCRATCH_HI 乘以 256 (因為它的單位為 256 個位元組) 並新增至
SH_HIDDEN_PRIVATE_BASE_VIMID
,以計算在存取暫存孔徑的平面記憶體指令中每個波前的平面暫存基底。平面暫存初始化的第二個字組是單一工作項目暫存記憶體使用量的 32 位元組大小。
CP 從執行階段取得此值,並且它始終是 DWORD 的倍數。CP 檢查核心分派封包「私有區段位元組大小」欄位中的值是否不大,並在必要時請求執行階段增加佇列的暫存大小。
CP 直接從核心分派封包「私有區段位元組大小」欄位載入,並四捨五入為 DWORD 的倍數。讓 CP 載入一次可避免在每個波前開始時都載入。
核心序言程式碼必須將其移至 FLAT_SCRATCH_LO,即 GFX7 上的 SGPRn-3 和 GFX8 上的 SGPRn-5。FLAT_SCRATCH_LO 用作平面記憶體指令中的平面暫存大小。
如果 AMDGPU 處理器的「目標屬性」欄指定「絕對平面暫存」
如果核心或其呼叫的任何函數可能使用平面操作來存取暫存記憶體,則序言程式碼必須設定 FLAT_SCRATCH 暫存器對 (FLAT_SCRATCH_LO/FLAT_SCRATCH_HI,它們在 SGPRn-4/SGPRn-3 中)。初始化使用平面暫存初始化和暫存波前偏移 SGPR 暫存器 (請參閱 初始核心執行狀態)
平面暫存初始化是 SPI 為執行核心分派的佇列管理的暫存後備記憶體基底的 64 位元位址。
CP 從執行階段取得此值。
核心序言必須新增波的暫存波前偏移的值,並將結果作為 64 位元值移至 FLAT_SCRATCH SGPR 暫存器對,即 SGPRn-6 和 SGPRn-5。它用作平面記憶體指令中的平面暫存基底。
使用暫存區段緩衝區時,暫存波前偏移也必須用作私有區段位址的偏移 (請參閱 私有區段緩衝區)。
如果 AMDGPU 處理器的「目標屬性」欄指定「架構平面暫存」
如果在 適用於 GFX6-GFX12 的 compute_pgm_rsrc2 中啟用了 ENABLE_PRIVATE_SEGMENT,則 FLAT_SCRATCH 暫存器對將初始化為 SPI 為執行核心分派的佇列管理的暫存後備記憶體基底的 64 位元位址,加上波的暫存波前偏移的值,以用作平面記憶體指令中的平面暫存基底。
私有區段緩衝區¶
如果 AMDGPU 處理器的「目標屬性」欄指定「架構平面暫存」,則不支援私有區段緩衝區。而是使用平面 SCRATCH 指令。
否則,私有區段緩衝區 SGPR 暫存器用於初始化 4 個 SGPR,這些 SGPR 用作 V# 以存取暫存。CP 使用執行階段提供的值。它與暫存波前偏移一起用作偏移,以使用區段位址存取私有記憶體空間。請參閱 初始核心執行狀態。
暫存 V# 是一個四對齊的 SGPR,並且始終為核心選擇,如下所示
如果在指令選擇期間已知存在堆疊使用情況,則保留 SGPR0-3 以用作暫存 V#。如果停用最佳化 (-O0)、堆疊物件已存在 (對於本機變數等),或存在任何函數呼叫,則假定存在堆疊使用情況。
否則,將保留從四對齊 SGPR 索引開始的四個高編號 SGPR,用於暫定的暫存 V#。如果確定需要溢出,則將使用這些 SGPR。
如果沒有使用暫定的暫存 V#,則會取消保留它,並且在忽略它的情況下確定暫存器計數。
如果使用了暫定的暫存 V#,則其暫存器編號會移至暫存器分配器分配的最高編號之後的第一個四對齊 SGPR 索引,並且會更新所有使用。暫存器計數包括移位位置中的它們。
在任何一種情況下,如果處理器有 SGPR 分配錯誤,則不會移位或取消保留暫定的分配,以確保暫存器計數更高以解決該錯誤。
注意
這種使用暫定的暫存 V# 並在使用時移位暫存器編號的方法避免了在消除暫定的 V# 時必須第二次執行暫存器分配。這樣更有效率,並且避免了第二次暫存器分配可能執行溢出的問題,這會因為不再有暫存 V# 而失敗。
當發出核心序言程式碼時,已知上述暫存 V# 是否實際使用。如果是,則序言程式碼必須透過將私有區段緩衝區複製到暫存 V# 暫存器,然後將私有區段波前偏移新增至 V# 中的佇列基底位址來設定它。結果是一個 V#,其基底位址指向波前暫存後備記憶體的開頭。
始終請求私有區段緩衝區,但僅在使用時才請求私有區段波前偏移 (請參閱 初始核心執行狀態)。
記憶體模型¶
本節描述 LLVM 記憶體模型到 AMDGPU 機器碼的對應 (請參閱 並行操作的記憶體模型)。
AMDGPU 後端支援 記憶體範圍 中指定的記憶體同步範圍。
用於實作記憶體模型的程式碼序列指定單一執行緒必須執行的指令順序。s_waitcnt
和快取管理指令 (例如 buffer_wbinvl1_vol
) 是相對於同一執行緒執行的其他記憶體指令定義的。這允許它們更早或更晚移動,這允許它們與同一指令的其他實例組合,或提升/沉降出迴圈以提高效能。僅給出與記憶體模型相關的指令;需要額外的 s_waitcnt
指令以確保在暫存器使用之前已定義。這些指令可能能夠與如上所述的記憶體模型 s_waitcnt
指令組合。
AMDGPU 後端支援以下記憶體模型
- HSA 記憶體模型 [HSA]
HSA 記憶體模型對所有位址空間使用單一先行發生關係 (請參閱 位址空間)。
- OpenCL 記憶體模型 [OpenCL]
OpenCL 記憶體模型針對全域和本機位址空間具有單獨的先行發生關係。只有指定全域和本機位址空間的柵欄,以及 seq_cst 指令會加入關係。由於 LLVM
memfence
指令不允許指定位址空間,因此 OpenCL 柵欄必須保守地假定已指定本機和全域位址空間。然而,當沒有存取相應位址空間的中間記憶體指令時,通常可以執行最佳化來消除額外的s_waitcnt
指令。表中的程式碼序列指示 OpenCL 記憶體可以省略的內容。目標三元組環境用於確定來源語言是否為 OpenCL (請參閱 OpenCL)。
對本機記憶體的 ds/flat_load/store/atomic
指令稱為 LDS 操作。
對全域記憶體的 buffer/global/flat_load/store/atomic
指令稱為向量記憶體操作。
私有位址空間使用 buffer_load/store
(使用暫存 V# (GFX6-GFX8)) 或 scratch_load/store
(GFX9-GFX11)。由於只有單一執行緒存取記憶體,因此原子記憶體排序沒有意義,並且所有存取都被視為非原子。
常數位址空間使用 buffer/global_load
指令 (或等效的純量記憶體指令)。由於常數位址空間內容在核心分派執行期間不會變更,因此執行儲存是非法的,並且原子記憶體排序沒有意義,並且所有存取都被視為非原子。
寬於工作群組的記憶體同步範圍對於群組 (LDS) 位址空間沒有意義,並且被視為工作群組。
記憶體模型不支援區域位址空間,該空間被視為非原子。
取得記憶體排序對於儲存原子指令沒有意義,並且被視為非原子。
釋放記憶體排序對於載入原子指令沒有意義,並且被視為非原子。
取得-釋放記憶體排序對於載入或儲存原子指令沒有意義,並且分別被視為取得和釋放。
記憶體順序也新增了表 AMDHSA 記憶體模型單一執行緒最佳化限制 中定義的單一執行緒最佳化限制。
表 78 AMDHSA 記憶體模型單一執行緒最佳化限制¶ LLVM 記憶體
最佳化限制
排序
無序
none
單調
none
取得
如果是載入原子/atomicrmw,則後續的載入/載入原子/儲存/儲存原子/atomicrmw/柵欄指令都不能在取得之前移動。
如果是柵欄,則與載入原子相同,加上沒有在前的相關聯柵欄配對原子可以在柵欄之後移動。
釋放
如果是儲存原子/atomicrmw,則在前的載入/載入原子/儲存/儲存原子/atomicrmw/柵欄指令都不能在釋放之後移動。
如果是柵欄,則與儲存原子相同,加上沒有後續的相關聯柵欄配對原子可以在柵欄之前移動。
取得_釋放
與取得和釋放相同的限制。
seq_cst
如果是載入原子,則與取得相同的限制,加上沒有在前的循序一致載入原子/儲存原子/atomicrmw/柵欄指令可以在 seq_cst 之後移動。
如果是儲存原子,則與釋放相同的限制,加上沒有後續的循序一致載入原子/儲存原子/atomicrmw/柵欄指令可以在 seq_cst 之前移動。
如果是 atomicrmw/柵欄,則與取得_釋放相同的限制。
用於實作記憶體模型的程式碼序列在以下章節中定義
柵欄和位址空間¶
LLVM 柵欄沒有位址空間資訊,因此,柵欄程式碼產生通常需要保守地同步所有位址空間。
在 OpenCL 的情況下,柵欄只需要同步使用者指定的位址空間,這可能會導致額外的不必要等待。例如,預期僅同步本機記憶體的柵欄也必須等待所有全域記憶體操作,這是沒有必要的。
記憶體模型放寬註解 可以用作柵欄的最佳化提示,以解決此問題。AMDGPU 後端識別柵欄上的以下標籤
amdgpu-as:local
- 僅柵欄本機位址空間amdgpu-as:global
- 僅柵欄全域位址空間
注意
作為最佳化提示,這些標籤不能保證在程式碼產生之前存留。最佳化可以自由捨棄標籤,以允許更好的程式碼最佳化,但代價是同步額外的位址空間。
記憶體模型 GFX6-GFX9¶
針對 GFX6-GFX9
每個代理程式有多個著色器陣列 (SA)。
每個 SA 有多個運算單元 (CU)。
每個 CU 有多個執行波前的 SIMD。
單一工作群組的波前在同一個 CU 中執行,但可能由不同的 SIMD 執行。
每個 CU 都有一個單一 LDS 記憶體,由在其上執行的工作群組的波前共用。
CU 的所有 LDS 操作都作為波前寬操作以全域順序執行,並且不涉及快取。完成情況以執行順序報告給波前。
LDS 記憶體有多個請求佇列,這些佇列由 CU 的 SIMD 共用。因此,工作群組的不同波前執行的 LDS 操作可以彼此重新排序,這可能會導致相對於同一工作群組中其他波前的 LDS 操作重新排序向量記憶體操作的可見性。需要
s_waitcnt lgkmcnt(0)
以確保工作群組的波前之間的 LDS 操作和向量記憶體操作之間同步,而不是同一波前執行的操作之間同步。向量記憶體操作作為波前寬操作執行,並且完成情況以執行順序報告給波前。例外情況是,對於 GFX7-GFX9,如果
flat_load/store/atomic
指令存取 LDS 記憶體,則它們可以報告向量記憶體順序外,如果它們存取全域記憶體,則可以報告 LDS 操作順序外。向量記憶體操作存取由 CU 的所有 SIMD 共用的單一向量 L1 快取。因此,單一波前的通道之間的一致性,或同一工作群組中波前之間的一致性不需要特殊操作。需要
buffer_wbinvl1_vol
以確保在不同工作群組中執行的波前之間的一致性,因為它們可能在不同的 CU 上執行。純量記憶體操作存取由一組 CU 上所有波前共用的純量 L1 快取。純量和向量 L1 快取不一致。但是,純量操作以受限的方式使用,因此不會影響記憶體模型。請參閱 記憶體空間。
向量和純量記憶體操作使用由同一代理程式上所有 CU 共用的 L2 快取。
L2 快取具有獨立通道,用於服務不相交的虛擬位址範圍。
每個 CU 每個通道都有一個單獨的請求佇列。因此,代理程式的不同工作群組 (可能在不同的 CU 上執行) 中執行的波前執行的向量和純量記憶體操作可以彼此重新排序。需要
s_waitcnt vmcnt(0)
以確保不同 CU 的向量記憶體操作之間同步。它確保先前的向量記憶體操作已完成,然後再執行後續的向量記憶體或 LDS 操作,因此可用於滿足取得和釋放的要求。L2 快取可以與某些目標上的其他代理程式保持一致性,或者可以設定虛擬位址範圍來繞過它,以確保系統一致性。
純量記憶體操作僅用於存取在核心調度執行期間證明不會變更的記憶體。 這包括常數位址空間和程式作用域 const
變數的全域位址空間。 因此,核心機器碼不必維護純量快取,以確保它與向量快取一致。 純量快取和向量快取在核心調度之間由 CP 使失效,因為常數位址空間資料可能在核心調度執行之間變更。 請參閱 記憶體空間。
一個例外情況是,如果純量寫入用於溢出 SGPR 暫存器。 在這種情況下,AMDGPU 後端確保用於溢出的記憶體位置永遠不會同時被向量記憶體操作存取。 如果使用純量寫入,則在 s_endpgm
之前和函數返回之前插入 s_dcache_wb
,因為這些位置可能被未來使用相同暫存區的波前或在相同位址建立框架的函數呼叫用於向量記憶體指令。 不需要 s_dcache_inv
,因為所有純量寫入在同一個執行緒中都是先寫後讀。
對於核心參數後備記憶體
CP 在每次核心調度開始時使 L1 快取失效。
在 dGPU 上,核心參數後備記憶體分配在主機記憶體中,以 MTYPE UC(非快取)存取,以避免需要使 L2 快取失效。 這也使其被視為非揮發性,因此不會被
*_vol
失效。在 APU 上,核心參數後備記憶體以 MTYPE CC(快取一致性)存取,因此 L2 快取將與 CPU 和其他代理程式保持一致性。
暫存後備記憶體(用於私有位址空間)以 MTYPE NC_NV(非一致性非揮發性)存取。 由於私有位址空間僅由單個執行緒存取,並且始終是先寫後讀,因此永遠不需要使 L1 快取中的這些條目失效。 因此,所有快取失效都以 *_vol
完成,僅使揮發性快取行失效。
用於實作 GFX6-GFX9 記憶體模型的程式碼序列在表 AMDHSA 記憶體模型程式碼序列 GFX6-GFX9 中定義。
表 79 AMDHSA 記憶體模型程式碼序列 GFX6-GFX9¶ LLVM 指令
LLVM 記憶體排序
LLVM 記憶體同步作用域
AMDGPU 位址空間
AMDGPU 機器碼 GFX6-GFX9
非原子
載入
none
none
global
通用
private
constant
!volatile & !nontemporal
buffer/global/flat_load
!volatile & nontemporal
buffer/global/flat_load glc=1 slc=1
volatile
buffer/global/flat_load glc=1
s_waitcnt vmcnt(0)
必須在任何後續的揮發性全域/通用載入/儲存之前發生。
確保對不同位址的揮發性操作不會被硬體重新排序。
載入
none
none
區域
ds_load
儲存
none
none
global
通用
private
constant
!volatile & !nontemporal
buffer/global/flat_store
!volatile & nontemporal
buffer/global/flat_store glc=1 slc=1
volatile
buffer/global/flat_store
s_waitcnt vmcnt(0)
必須在任何後續的揮發性全域/通用載入/儲存之前發生。
確保對不同位址的揮發性操作不會被硬體重新排序。
儲存
none
none
區域
ds_store
無序原子
載入原子
無序
任何
任何
與非原子相同.
儲存原子
無序
任何
任何
與非原子相同.
atomicrmw
無序
任何
任何
與單調原子相同.
單調原子
載入原子
單調
singlethread
wavefront
workgroup
global
區域
通用
buffer/global/ds/flat_load
載入原子
單調
agent
system
global
通用
buffer/global/flat_load glc=1
儲存原子
單調
singlethread
wavefront
workgroup
agent
system
global
通用
buffer/global/flat_store
儲存原子
單調
singlethread
wavefront
workgroup
區域
ds_store
atomicrmw
單調
singlethread
wavefront
workgroup
agent
system
global
通用
buffer/global/flat_atomic
atomicrmw
單調
singlethread
wavefront
workgroup
區域
ds_atomic
取得原子
載入原子
取得
singlethread
wavefront
global
區域
通用
buffer/global/ds/flat_load
載入原子
取得
workgroup
global
buffer/global_load
載入原子
取得
workgroup
區域
通用
ds/flat_load
s_waitcnt lgkmcnt(0)
如果是 OpenCL,則省略。
必須在任何後續的全域/通用載入/載入原子/儲存/儲存原子/atomicrmw 之前發生。
確保任何後續的全域資料讀取都不會早於正在取得的區域載入原子值。
載入原子
取得
agent
system
global
buffer/global_load glc=1
s_waitcnt vmcnt(0)
必須在後續的 buffer_wbinvl1_vol 之前發生。
確保載入在使快取失效之前已完成。
buffer_wbinvl1_vol
必須在任何後續的全域/通用載入/載入原子/atomicrmw 之前發生。
確保後續的載入不會看到過時的全域資料。
載入原子
取得
agent
system
通用
flat_load glc=1
s_waitcnt vmcnt(0) & lgkmcnt(0)
如果是 OpenCL,則省略 lgkmcnt(0)。
必須在後續的 buffer_wbinvl1_vol 之前發生。
確保 flat_load 在使快取失效之前已完成。
buffer_wbinvl1_vol
必須在任何後續的全域/通用載入/載入原子/atomicrmw 之前發生。
確保後續的載入不會看到過時的全域資料。
atomicrmw
取得
singlethread
wavefront
global
區域
通用
buffer/global/ds/flat_atomic
atomicrmw
取得
workgroup
global
buffer/global_atomic
atomicrmw
取得
workgroup
區域
通用
ds/flat_atomic
s_waitcnt lgkmcnt(0)
如果是 OpenCL,則省略。
必須在任何後續的全域/通用載入/載入原子/儲存/儲存原子/atomicrmw 之前發生。
確保任何後續的全域資料讀取都不會早於正在取得的區域 atomicrmw 值。
atomicrmw
取得
agent
system
global
buffer/global_atomic
s_waitcnt vmcnt(0)
必須在後續的 buffer_wbinvl1_vol 之前發生。
確保 atomicrmw 在使快取失效之前已完成。
buffer_wbinvl1_vol
必須在任何後續的全域/通用載入/載入原子/atomicrmw 之前發生。
確保後續的載入不會看到過時的全域資料。
atomicrmw
取得
agent
system
通用
flat_atomic
s_waitcnt vmcnt(0) & lgkmcnt(0)
如果是 OpenCL,則省略 lgkmcnt(0)。
必須在後續的 buffer_wbinvl1_vol 之前發生。
確保 atomicrmw 在使快取失效之前已完成。
buffer_wbinvl1_vol
必須在任何後續的全域/通用載入/載入原子/atomicrmw 之前發生。
確保後續的載入不會看到過時的全域資料。
柵欄
取得
singlethread
wavefront
none
none
柵欄
取得
workgroup
none
s_waitcnt lgkmcnt(0)
如果是 OpenCL 且位址空間不是通用的,則省略。
有關特定位址空間柵欄的更多詳細資訊,請參閱 柵欄和位址空間。
必須在任何先前的區域/通用載入原子/atomicrmw 之後發生,其同步作用域相等或更寬,且記憶體排序強於無序(這稱為柵欄配對原子)。
必須在任何後續的全域/通用載入/載入原子/儲存/儲存原子/atomicrmw 之前發生。
確保任何後續的全域資料讀取都不會早於柵欄配對原子讀取的值。
柵欄
取得
agent
system
none
s_waitcnt lgkmcnt(0) & vmcnt(0)
如果是 OpenCL 且位址空間不是通用的,則省略 lgkmcnt(0)。
有關特定位址空間柵欄的更多詳細資訊,請參閱 柵欄和位址空間。
可以拆分為單獨的 s_waitcnt vmcnt(0) 和 s_waitcnt lgkmcnt(0),以允許根據以下規則獨立移動它們。
s_waitcnt vmcnt(0) 必須在任何先前的全域/通用載入原子/atomicrmw 之後發生,其同步作用域相等或更寬,且記憶體排序強於無序(這稱為柵欄配對原子)。
s_waitcnt lgkmcnt(0) 必須在任何先前的區域/通用載入原子/atomicrmw 之後發生,其同步作用域相等或更寬,且記憶體排序強於無序(這稱為柵欄配對原子)。
必須在後續的 buffer_wbinvl1_vol 之前發生。
確保柵欄配對原子在使快取失效之前已完成。 因此,任何後續讀取的位置都不得早於柵欄配對原子讀取的值。
buffer_wbinvl1_vol
必須在任何後續的全域/通用載入/載入原子/儲存/儲存原子/atomicrmw 之前發生。
確保後續的載入不會看到過時的全域資料。
釋放原子
儲存原子
釋放
singlethread
wavefront
global
區域
通用
buffer/global/ds/flat_store
儲存原子
釋放
workgroup
global
通用
s_waitcnt lgkmcnt(0)
如果是 OpenCL,則省略。
必須在任何先前的區域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
必須在後續的儲存之前發生。
確保對區域的所有記憶體操作在執行正在釋放的儲存之前已完成。
buffer/global/flat_store
儲存原子
釋放
workgroup
區域
ds_store
儲存原子
釋放
agent
system
global
通用
s_waitcnt lgkmcnt(0) & vmcnt(0)
如果是 OpenCL 且位址空間不是通用的,則省略 lgkmcnt(0)。
可以拆分為單獨的 s_waitcnt vmcnt(0) 和 s_waitcnt lgkmcnt(0),以允許根據以下規則獨立移動它們。
s_waitcnt vmcnt(0) 必須在任何先前的全域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
s_waitcnt lgkmcnt(0) 必須在任何先前的區域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
必須在後續的儲存之前發生。
確保對記憶體的所有記憶體操作在執行正在釋放的儲存之前已完成。
buffer/global/flat_store
atomicrmw
釋放
singlethread
wavefront
global
區域
通用
buffer/global/ds/flat_atomic
atomicrmw
釋放
workgroup
global
通用
s_waitcnt lgkmcnt(0)
如果是 OpenCL,則省略。
必須在任何先前的區域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
必須在後續的 atomicrmw 之前發生。
確保對區域的所有記憶體操作在執行正在釋放的 atomicrmw 之前已完成。
buffer/global/flat_atomic
atomicrmw
釋放
workgroup
區域
ds_atomic
atomicrmw
釋放
agent
system
global
通用
s_waitcnt lgkmcnt(0) & vmcnt(0)
如果是 OpenCL,則省略 lgkmcnt(0)。
可以拆分為單獨的 s_waitcnt vmcnt(0) 和 s_waitcnt lgkmcnt(0),以允許根據以下規則獨立移動它們。
s_waitcnt vmcnt(0) 必須在任何先前的全域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
s_waitcnt lgkmcnt(0) 必須在任何先前的區域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
必須在後續的 atomicrmw 之前發生。
確保對全域和區域的所有記憶體操作在執行正在釋放的 atomicrmw 之前已完成。
buffer/global/flat_atomic
柵欄
釋放
singlethread
wavefront
none
none
柵欄
釋放
workgroup
none
s_waitcnt lgkmcnt(0)
如果是 OpenCL 且位址空間不是通用的,則省略。
有關特定位址空間柵欄的更多詳細資訊,請參閱 柵欄和位址空間。
必須在任何先前的區域/通用載入/載入原子/儲存/儲存原子/atomicrmw 之後發生。
必須在任何後續的儲存原子/atomicrmw 之前發生,其同步作用域相等或更寬,且記憶體排序強於無序(這稱為柵欄配對原子)。
確保對區域的所有記憶體操作在執行後續的柵欄配對原子之前已完成。
柵欄
釋放
agent
system
none
s_waitcnt lgkmcnt(0) & vmcnt(0)
如果是 OpenCL 且位址空間不是通用的,則省略 lgkmcnt(0)。
如果是 OpenCL 且位址空間是區域的,則省略 vmcnt(0)。
有關特定位址空間柵欄的更多詳細資訊,請參閱 柵欄和位址空間。
可以拆分為單獨的 s_waitcnt vmcnt(0) 和 s_waitcnt lgkmcnt(0),以允許根據以下規則獨立移動它們。
s_waitcnt vmcnt(0) 必須在任何先前的全域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
s_waitcnt lgkmcnt(0) 必須在任何先前的區域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
必須在任何後續的儲存原子/atomicrmw 之前發生,其同步作用域相等或更寬,且記憶體排序強於無序(這稱為柵欄配對原子)。
確保所有記憶體操作在執行後續的柵欄配對原子之前已完成。
取得-釋放原子
atomicrmw
取得_釋放
singlethread
wavefront
global
區域
通用
buffer/global/ds/flat_atomic
atomicrmw
取得_釋放
workgroup
global
s_waitcnt lgkmcnt(0)
如果是 OpenCL,則省略。
必須在任何先前的區域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
必須在後續的 atomicrmw 之前發生。
確保對區域的所有記憶體操作在執行正在釋放的 atomicrmw 之前已完成。
buffer/global_atomic
atomicrmw
取得_釋放
workgroup
區域
ds_atomic
s_waitcnt lgkmcnt(0)
如果是 OpenCL,則省略。
必須在任何後續的全域/通用載入/載入原子/儲存/儲存原子/atomicrmw 之前發生。
確保任何後續的全域資料讀取都不會早於正在取得的區域載入原子值。
atomicrmw
取得_釋放
workgroup
通用
s_waitcnt lgkmcnt(0)
如果是 OpenCL,則省略。
必須在任何先前的區域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
必須在後續的 atomicrmw 之前發生。
確保對區域的所有記憶體操作在執行正在釋放的 atomicrmw 之前已完成。
flat_atomic
s_waitcnt lgkmcnt(0)
如果是 OpenCL,則省略。
必須在任何後續的全域/通用載入/載入原子/儲存/儲存原子/atomicrmw 之前發生。
確保任何後續的全域資料讀取都不會早於正在取得的區域載入原子值。
atomicrmw
取得_釋放
agent
system
global
s_waitcnt lgkmcnt(0) & vmcnt(0)
如果是 OpenCL,則省略 lgkmcnt(0)。
可以拆分為單獨的 s_waitcnt vmcnt(0) 和 s_waitcnt lgkmcnt(0),以允許根據以下規則獨立移動它們。
s_waitcnt vmcnt(0) 必須在任何先前的全域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
s_waitcnt lgkmcnt(0) 必須在任何先前的區域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
必須在後續的 atomicrmw 之前發生。
確保對全域的所有記憶體操作在執行正在釋放的 atomicrmw 之前已完成。
buffer/global_atomic
s_waitcnt vmcnt(0)
必須在後續的 buffer_wbinvl1_vol 之前發生。
確保 atomicrmw 在使快取失效之前已完成。
buffer_wbinvl1_vol
必須在任何後續的全域/通用載入/載入原子/atomicrmw 之前發生。
確保後續的載入不會看到過時的全域資料。
atomicrmw
取得_釋放
agent
system
通用
s_waitcnt lgkmcnt(0) & vmcnt(0)
如果是 OpenCL,則省略 lgkmcnt(0)。
可以拆分為單獨的 s_waitcnt vmcnt(0) 和 s_waitcnt lgkmcnt(0),以允許根據以下規則獨立移動它們。
s_waitcnt vmcnt(0) 必須在任何先前的全域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
s_waitcnt lgkmcnt(0) 必須在任何先前的區域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
必須在後續的 atomicrmw 之前發生。
確保對全域的所有記憶體操作在執行正在釋放的 atomicrmw 之前已完成。
flat_atomic
s_waitcnt vmcnt(0) & lgkmcnt(0)
如果是 OpenCL,則省略 lgkmcnt(0)。
必須在後續的 buffer_wbinvl1_vol 之前發生。
確保 atomicrmw 在使快取失效之前已完成。
buffer_wbinvl1_vol
必須在任何後續的全域/通用載入/載入原子/atomicrmw 之前發生。
確保後續的載入不會看到過時的全域資料。
柵欄
取得_釋放
singlethread
wavefront
none
none
柵欄
取得_釋放
workgroup
none
s_waitcnt lgkmcnt(0)
如果是 OpenCL 且位址空間不是通用的,則省略。
但是,由於 LLVM 目前在柵欄上沒有位址空間,因此需要保守地始終產生(請參閱先前柵欄的註解)。
必須在任何先前的區域/通用載入/載入原子/儲存/儲存原子/atomicrmw 之後發生。
必須在任何後續的全域/通用載入/載入原子/儲存/儲存原子/atomicrmw 之前發生。
確保對區域的所有記憶體操作在執行任何後續的全域記憶體操作之前已完成。
確保先前的區域/通用載入原子/atomicrmw,其同步作用域相等或更寬,且記憶體排序強於無序(這稱為取得柵欄配對原子),在後續的全域記憶體操作之前已完成。 這滿足取得的要求。
確保所有先前的記憶體操作在後續的區域/通用儲存原子/atomicrmw 之前已完成,其同步作用域相等或更寬,且記憶體排序強於無序(這稱為釋放柵欄配對原子)。 這滿足釋放的要求。
柵欄
取得_釋放
agent
system
none
s_waitcnt lgkmcnt(0) & vmcnt(0)
如果是 OpenCL 且位址空間不是通用的,則省略 lgkmcnt(0)。
有關特定位址空間柵欄的更多詳細資訊,請參閱 柵欄和位址空間。
可以拆分為單獨的 s_waitcnt vmcnt(0) 和 s_waitcnt lgkmcnt(0),以允許根據以下規則獨立移動它們。
s_waitcnt vmcnt(0) 必須在任何先前的全域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
s_waitcnt lgkmcnt(0) 必須在任何先前的區域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
必須在後續的 buffer_wbinvl1_vol 之前發生。
確保先前的全域/區域/通用載入原子/atomicrmw,其同步作用域相等或更寬,且記憶體排序強於無序(這稱為取得柵欄配對原子),在使快取失效之前已完成。 這滿足取得的要求。
確保所有先前的記憶體操作在後續的全域/區域/通用儲存原子/atomicrmw 之前已完成,其同步作用域相等或更寬,且記憶體排序強於無序(這稱為釋放柵欄配對原子)。 這滿足釋放的要求。
buffer_wbinvl1_vol
必須在任何後續的全域/通用載入/載入原子/儲存/儲存原子/atomicrmw 之前發生。
確保後續的載入不會看到過時的全域資料。 這滿足取得的要求。
循序一致性原子
載入原子
seq_cst
singlethread
wavefront
global
區域
通用
與對應的載入原子取得相同,但即使對於 OpenCL 也必須產生所有指令。
載入原子
seq_cst
workgroup
global
通用
s_waitcnt lgkmcnt(0)
必須在先前的區域/通用載入原子/儲存原子/atomicrmw 之後發生,其記憶體排序為 seq_cst,且同步作用域相等或更寬。(請注意,seq_cst 柵欄有自己的 s_waitcnt lgkmcnt(0),因此不需要考慮。)
確保任何先前的循序一致性區域記憶體指令在執行此循序一致性指令之前已完成。 這可以防止重新排序 seq_cst 儲存,然後是 seq_cst 載入。(請注意,seq_cst 比取得/釋放更強,因為釋放的 s_waitcnt 會阻止重新排序載入取得,然後是儲存釋放,但是沒有任何東西阻止儲存釋放,然後是載入取得以無序完成。 s_waitcnt 可以放在 seq_store 之後或 seq_load 之前。 我們選擇載入以使 s_waitcnt 盡可能晚,以便儲存可能已經完成。)
後續指令與對應的載入原子取得相同,但即使對於 OpenCL 也必須產生所有指令。
載入原子
seq_cst
workgroup
區域
與對應的載入原子取得相同,但即使對於 OpenCL 也必須產生所有指令。
載入原子
seq_cst
agent
system
global
通用
s_waitcnt lgkmcnt(0) & vmcnt(0)
可以拆分為單獨的 s_waitcnt vmcnt(0) 和 s_waitcnt lgkmcnt(0),以允許根據以下規則獨立移動它們。
s_waitcnt lgkmcnt(0) 必須在先前的全域/通用載入原子/儲存原子/atomicrmw 之後發生,其記憶體排序為 seq_cst,且同步作用域相等或更寬。(請注意,seq_cst 柵欄有自己的 s_waitcnt lgkmcnt(0),因此不需要考慮。)
s_waitcnt vmcnt(0) 必須在先前的全域/通用載入原子/儲存原子/atomicrmw 之後發生,其記憶體排序為 seq_cst,且同步作用域相等或更寬。(請注意,seq_cst 柵欄有自己的 s_waitcnt vmcnt(0),因此不需要考慮。)
確保任何先前的循序一致性全域記憶體指令在執行此循序一致性指令之前已完成。 這可以防止重新排序 seq_cst 儲存,然後是 seq_cst 載入。(請注意,seq_cst 比取得/釋放更強,因為釋放的 s_waitcnt 會阻止重新排序載入取得,然後是儲存釋放,但是沒有任何東西阻止儲存釋放,然後是載入取得以無序完成。 s_waitcnt 可以放在 seq_store 之後或 seq_load 之前。 我們選擇載入以使 s_waitcnt 盡可能晚,以便儲存可能已經完成。)
後續指令與對應的載入原子取得相同,但即使對於 OpenCL 也必須產生所有指令。
儲存原子
seq_cst
singlethread
wavefront
workgroup
agent
system
global
區域
通用
與對應的儲存原子釋放相同,但即使對於 OpenCL 也必須產生所有指令。
atomicrmw
seq_cst
singlethread
wavefront
workgroup
agent
system
global
區域
通用
與對應的 atomicrmw acq_rel 相同,但即使對於 OpenCL 也必須產生所有指令。
柵欄
seq_cst
singlethread
wavefront
workgroup
agent
system
none
與對應的柵欄 acq_rel 相同,但即使對於 OpenCL 也必須產生所有指令。
記憶體模型 GFX90A¶
對於 GFX90A
每個代理程式有多個著色器陣列 (SA)。
每個 SA 有多個運算單元 (CU)。
每個 CU 有多個執行波前的 SIMD。
單個工作群組的波前在同一個 CU 中執行,但可能由不同的 SIMD 執行。 例外情況是當處於 tgsplit 執行模式時,波前可能由不同 CU 中的不同 SIMD 執行。
每個 CU 都有一個單個 LDS 記憶體,由在其上執行的工作群組的波前共享。 例外情況是當處於 tgsplit 執行模式時,由於同一工作群組的波前可能位於不同的 CU 中,因此不分配 LDS。
CU 的所有 LDS 操作都作為波前寬操作以全域順序執行,並且不涉及快取。完成情況以執行順序報告給波前。
LDS 記憶體有多個請求佇列,這些佇列由 CU 的 SIMD 共用。因此,工作群組的不同波前執行的 LDS 操作可以彼此重新排序,這可能會導致相對於同一工作群組中其他波前的 LDS 操作重新排序向量記憶體操作的可見性。需要
s_waitcnt lgkmcnt(0)
以確保工作群組的波前之間的 LDS 操作和向量記憶體操作之間同步,而不是同一波前執行的操作之間同步。向量記憶體操作作為波前寬操作執行,完成情況以執行順序報告給波前。 例外情況是,如果
flat_load/store/atomic
指令存取 LDS 記憶體,則可以報告向量記憶體順序外,如果存取全域記憶體,則可以報告 LDS 操作順序外。向量記憶體操作存取由 CU 的所有 SIMD 共享的單個向量 L1 快取。 因此
單個波前的通道之間的一致性不需要特殊操作。
同一工作群組中波前之間的一致性不需要特殊操作,因為它們在同一個 CU 上執行。 例外情況是當處於 tgsplit 執行模式時,由於同一工作群組的波前可能位於不同的 CU 中,因此需要
buffer_wbinvl1_vol
,如下一項所述。在不同工作群組中執行的波前之間的一致性需要
buffer_wbinvl1_vol
,因為它們可能在不同的 CU 上執行。
純量記憶體操作存取由一組 CU 上所有波前共用的純量 L1 快取。純量和向量 L1 快取不一致。但是,純量操作以受限的方式使用,因此不會影響記憶體模型。請參閱 記憶體空間。
向量和純量記憶體操作使用由同一代理程式上所有 CU 共用的 L2 快取。
L2 快取具有獨立通道,用於服務不相交的虛擬位址範圍。
每個 CU 都有一個單獨的每個通道的請求佇列。 因此,由不同工作群組(可能在不同 CU 上執行)或同一工作群組(如果在 tgsplit 模式下執行)中的波前執行的向量和純量記憶體操作可以相對於彼此重新排序。 需要
s_waitcnt vmcnt(0)
以確保不同 CU 的向量記憶體操作之間的同步。 它確保先前的向量記憶體操作在執行後續的向量記憶體或 LDS 操作之前已完成,因此可以用於滿足取得和釋放的要求。一個代理程式的 L2 快取可以透過以下方式與其他代理程式保持一致性:對於 L2 本地的記憶體,使用 MTYPE RW(讀寫)或 MTYPE CC(快取一致性)與 PTE C 位元;對於非 L2 本地的記憶體,使用 MTYPE NC(非一致性)與設定 PTE C 位元或 MTYPE UC(非快取)。
由於一致性請求引起的快取探測,任何本地記憶體快取行都將自動被來自與其他 L2 快取關聯的 CU 或來自 CPU 的寫入失效。 一致性請求是由 GPU 存取具有設定 PTE C 位元的頁面、CPU 透過 XGMI 存取以及配置為一致性請求的 PCIe 請求引起的。
來自 CPU 的 XGMI 對本地記憶體的存取可能會在 CPU 上快取。 由於 L2 探測篩選器和設定的 PTE C 位元,來自 GPU 的後續存取將自動使 CPU 快取失效或寫回。
由於同一代理程式上的所有工作群組共享同一個 L2,因此一致性不需要 L2 失效或寫回。
為了確保不同代理程式中工作群組的本地和遠端記憶體寫入的一致性,需要
buffer_wbl2
。 它將寫回 MTYPE RW(用於本地粗粒度記憶體)和 MTYPE NC(用於遠端粗粒度記憶體)的髒 L2 快取行。 請注意,MTYPE CC(用於本地細粒度記憶體)導致寫穿到 DRAM,而 MTYPE UC(用於遠端細粒度記憶體)繞過 L2,因此兩者都不會導致髒 L2 快取行。為了確保不同代理程式中工作群組的本地和遠端記憶體讀取的一致性,需要
buffer_invl2
。 它將使 MTYPE NC(用於遠端粗粒度記憶體)的 L2 快取行失效。 請注意,MTYPE CC(用於本地細粒度記憶體)和 MTYPE RW(用於本地粗粒度記憶體)導致本地讀取被具有 PTE C 位元的遠端寫入失效,因此這些快取行不會失效。 請注意,MTYPE UC(用於遠端細粒度記憶體)繞過 L2,因此永遠不會導致需要失效的 L2 快取行。
從 GPU 到 CPU 記憶體的 PCIe 存取透過使用 MTYPE UC(非快取)保持一致性,MTYPE UC(非快取)繞過 L2。
純量記憶體操作僅用於存取在核心調度執行期間證明不會變更的記憶體。 這包括常數位址空間和程式作用域 const
變數的全域位址空間。 因此,核心機器碼不必維護純量快取,以確保它與向量快取一致。 純量快取和向量快取在核心調度之間由 CP 使失效,因為常數位址空間資料可能在核心調度執行之間變更。 請參閱 記憶體空間。
一個例外情況是,如果純量寫入用於溢出 SGPR 暫存器。 在這種情況下,AMDGPU 後端確保用於溢出的記憶體位置永遠不會同時被向量記憶體操作存取。 如果使用純量寫入,則在 s_endpgm
之前和函數返回之前插入 s_dcache_wb
,因為這些位置可能被未來使用相同暫存區的波前或在相同位址建立框架的函數呼叫用於向量記憶體指令。 不需要 s_dcache_inv
,因為所有純量寫入在同一個執行緒中都是先寫後讀。
對於核心參數後備記憶體
CP 在每次核心調度開始時使 L1 快取失效。
在透過 XGMI 或 PCIe 的 dGPU 上,核心參數後備記憶體分配在主機記憶體中,以 MTYPE UC(非快取)存取,以避免需要使 L2 快取失效。 這也使其被視為非揮發性,因此不會被
*_vol
失效。在 APU 上,核心參數後備記憶體以 MTYPE CC(快取一致性)存取,因此 L2 快取將與 CPU 和其他代理程式保持一致性。
暫存後備記憶體(用於私有位址空間)以 MTYPE NC_NV(非一致性非揮發性)存取。 由於私有位址空間僅由單個執行緒存取,並且始終是先寫後讀,因此永遠不需要使 L1 快取中的這些條目失效。 因此,所有快取失效都以 *_vol
完成,僅使揮發性快取行失效。
用於實作 GFX90A 記憶體模型的程式碼序列在表 AMDHSA 記憶體模型程式碼序列 GFX90A 中定義。
表 80 AMDHSA 記憶體模型程式碼序列 GFX90A¶ LLVM 指令
LLVM 記憶體排序
LLVM 記憶體同步作用域
AMDGPU 位址空間
AMDGPU 機器碼 GFX90A
非原子
載入
none
none
global
通用
private
constant
!volatile & !nontemporal
buffer/global/flat_load
!volatile & nontemporal
buffer/global/flat_load glc=1 slc=1
volatile
buffer/global/flat_load glc=1
s_waitcnt vmcnt(0)
必須在任何後續的揮發性全域/通用載入/儲存之前發生。
確保對不同位址的揮發性操作不會被硬體重新排序。
載入
none
none
區域
ds_load
儲存
none
none
global
通用
private
constant
!volatile & !nontemporal
buffer/global/flat_store
!volatile & nontemporal
buffer/global/flat_store glc=1 slc=1
volatile
buffer/global/flat_store
s_waitcnt vmcnt(0)
必須在任何後續的揮發性全域/通用載入/儲存之前發生。
確保對不同位址的揮發性操作不會被硬體重新排序。
儲存
none
none
區域
ds_store
無序原子
載入原子
無序
任何
任何
與非原子相同.
儲存原子
無序
任何
任何
與非原子相同.
atomicrmw
無序
任何
任何
與單調原子相同.
單調原子
載入原子
單調
singlethread
wavefront
global
通用
buffer/global/flat_load
載入原子
單調
workgroup
global
通用
buffer/global/flat_load glc=1
如果不是 TgSplit 執行模式,則省略 glc=1。
載入原子
單調
singlethread
wavefront
workgroup
區域
如果是 TgSplit 執行模式,則無法使用區域位址空間。
ds_load
載入原子
單調
agent
global
通用
buffer/global/flat_load glc=1
載入原子
單調
system
global
通用
buffer/global/flat_load glc=1
儲存原子
單調
singlethread
wavefront
workgroup
agent
global
通用
buffer/global/flat_store
儲存原子
單調
system
global
通用
buffer/global/flat_store
儲存原子
單調
singlethread
wavefront
workgroup
區域
如果是 TgSplit 執行模式,則無法使用區域位址空間。
ds_store
atomicrmw
單調
singlethread
wavefront
workgroup
agent
global
通用
buffer/global/flat_atomic
atomicrmw
單調
system
global
通用
buffer/global/flat_atomic
atomicrmw
單調
singlethread
wavefront
workgroup
區域
如果是 TgSplit 執行模式,則無法使用區域位址空間。
ds_atomic
取得原子
載入原子
取得
singlethread
wavefront
global
區域
通用
buffer/global/ds/flat_load
載入原子
取得
workgroup
global
buffer/global_load glc=1
如果不是 TgSplit 執行模式,則省略 glc=1。
s_waitcnt vmcnt(0)
如果不是 TgSplit 執行模式,則省略。
必須在後續的 buffer_wbinvl1_vol 之前發生。
buffer_wbinvl1_vol
如果不是 TgSplit 執行模式,則省略。
必須在任何後續的全域/通用載入/載入原子/儲存/儲存原子/atomicrmw 之前發生。
確保後續的載入不會看到過時的資料。
載入原子
取得
workgroup
區域
如果是 TgSplit 執行模式,則無法使用區域位址空間。
ds_load
s_waitcnt lgkmcnt(0)
如果是 OpenCL,則省略。
必須在任何後續的全域/通用載入/載入原子/儲存/儲存原子/atomicrmw 之前發生。
確保任何後續的全域資料讀取都不會早於正在取得的區域載入原子值。
載入原子
取得
workgroup
通用
flat_load glc=1
如果不是 TgSplit 執行模式,則省略 glc=1。
s_waitcnt lgkm/vmcnt(0)
如果不是 TgSplit 執行模式,則使用 lgkmcnt(0),如果是 TgSplit 執行模式,則使用 vmcnt(0)。
如果是 OpenCL,則省略 lgkmcnt(0)。
必須在後續的 buffer_wbinvl1_vol 以及任何後續的全域/通用載入/載入原子/儲存/儲存原子/atomicrmw 之前發生。
確保任何後續的全域資料讀取都不會早於正在取得的區域載入原子值。
buffer_wbinvl1_vol
如果不是 TgSplit 執行模式,則省略。
確保後續的載入不會看到過時的資料。
載入原子
取得
agent
global
buffer/global_load glc=1
s_waitcnt vmcnt(0)
必須在後續的 buffer_wbinvl1_vol 之前發生。
確保載入在使快取失效之前已完成。
buffer_wbinvl1_vol
必須在任何後續的全域/通用載入/載入原子/atomicrmw 之前發生。
確保後續的載入不會看到過時的全域資料。
載入原子
取得
system
global
buffer/global/flat_load glc=1
s_waitcnt vmcnt(0)
必須在後續的 buffer_invl2 和 buffer_wbinvl1_vol 之前發生。
確保載入在使快取失效之前已完成。
buffer_invl2; buffer_wbinvl1_vol
必須在任何後續的全域/通用載入/載入原子/atomicrmw 之前發生。
確保後續的載入不會看到過時的 L1 全域資料,也不會看到過時的 L2 MTYPE NC 全域資料。 由於記憶體探測,MTYPE RW 和 CC 記憶體在 L2 中永遠不會過時。
載入原子
取得
agent
通用
flat_load glc=1
s_waitcnt vmcnt(0) & lgkmcnt(0)
如果是 TgSplit 執行模式,則省略 lgkmcnt(0)。
如果是 OpenCL,則省略 lgkmcnt(0)。
必須在後續的 buffer_wbinvl1_vol 之前發生。
確保 flat_load 在使快取失效之前已完成。
buffer_wbinvl1_vol
必須在任何後續的全域/通用載入/載入原子/atomicrmw 之前發生。
確保後續的載入不會看到過時的全域資料。
載入原子
取得
system
通用
flat_load glc=1
s_waitcnt vmcnt(0) & lgkmcnt(0)
如果是 TgSplit 執行模式,則省略 lgkmcnt(0)。
如果是 OpenCL,則省略 lgkmcnt(0)。
必須在後續的 buffer_invl2 和 buffer_wbinvl1_vol 之前發生。
確保 flat_load 在使快取失效之前已完成。
buffer_invl2; buffer_wbinvl1_vol
必須在任何後續的全域/通用載入/載入原子/atomicrmw 之前發生。
確保後續的載入不會看到過時的 L1 全域資料,也不會看到過時的 L2 MTYPE NC 全域資料。 由於記憶體探測,MTYPE RW 和 CC 記憶體在 L2 中永遠不會過時。
atomicrmw
取得
singlethread
wavefront
global
通用
buffer/global/flat_atomic
atomicrmw
取得
singlethread
wavefront
區域
如果是 TgSplit 執行模式,則無法使用區域位址空間。
ds_atomic
atomicrmw
取得
workgroup
global
buffer/global_atomic
s_waitcnt vmcnt(0)
如果不是 TgSplit 執行模式,則省略。
必須在後續的 buffer_wbinvl1_vol 之前發生。
確保 atomicrmw 在使快取失效之前已完成。
buffer_wbinvl1_vol
如果不是 TgSplit 執行模式,則省略。
必須在任何後續的全域/通用載入/載入原子/atomicrmw 之前發生。
確保後續的載入不會看到過時的全域資料。
atomicrmw
取得
workgroup
區域
如果是 TgSplit 執行模式,則無法使用區域位址空間。
ds_atomic
s_waitcnt lgkmcnt(0)
如果是 OpenCL,則省略。
必須在任何後續的全域/通用載入/載入原子/儲存/儲存原子/atomicrmw 之前發生。
確保任何後續的全域資料讀取都不會早於正在取得的區域 atomicrmw 值。
atomicrmw
取得
workgroup
通用
flat_atomic
s_waitcnt lgkm/vmcnt(0)
如果不是 TgSplit 執行模式,則使用 lgkmcnt(0),如果是 TgSplit 執行模式,則使用 vmcnt(0)。
如果是 OpenCL,則省略 lgkmcnt(0)。
必須在後續的 buffer_wbinvl1_vol 以及任何後續的全域/通用載入/載入原子/儲存/儲存原子/atomicrmw 之前發生。
確保任何後續的全域資料讀取都不會早於正在取得的區域 atomicrmw 值。
buffer_wbinvl1_vol
如果不是 TgSplit 執行模式,則省略。
確保後續的載入不會看到過時的資料。
atomicrmw
取得
agent
global
buffer/global_atomic
s_waitcnt vmcnt(0)
必須在後續的 buffer_wbinvl1_vol 之前發生。
確保 atomicrmw 在使快取失效之前已完成。
buffer_wbinvl1_vol
必須在任何後續的全域/通用載入/載入原子/atomicrmw 之前發生。
確保後續的載入不會看到過時的全域資料。
atomicrmw
取得
system
global
buffer/global_atomic
s_waitcnt vmcnt(0)
必須在後續的 buffer_invl2 和 buffer_wbinvl1_vol 之前發生。
確保 atomicrmw 在使快取失效之前已完成。
buffer_invl2; buffer_wbinvl1_vol
必須在任何後續的全域/通用載入/載入原子/atomicrmw 之前發生。
確保後續的載入不會看到過時的 L1 全域資料,也不會看到過時的 L2 MTYPE NC 全域資料。 由於記憶體探測,MTYPE RW 和 CC 記憶體在 L2 中永遠不會過時。
atomicrmw
取得
agent
通用
flat_atomic
s_waitcnt vmcnt(0) & lgkmcnt(0)
如果是 TgSplit 執行模式,則省略 lgkmcnt(0)。
如果是 OpenCL,則省略 lgkmcnt(0)。
必須在後續的 buffer_wbinvl1_vol 之前發生。
確保 atomicrmw 在使快取失效之前已完成。
buffer_wbinvl1_vol
必須在任何後續的全域/通用載入/載入原子/atomicrmw 之前發生。
確保後續的載入不會看到過時的全域資料。
atomicrmw
取得
system
通用
flat_atomic
s_waitcnt vmcnt(0) & lgkmcnt(0)
如果是 TgSplit 執行模式,則省略 lgkmcnt(0)。
如果是 OpenCL,則省略 lgkmcnt(0)。
必須在後續的 buffer_invl2 和 buffer_wbinvl1_vol 之前發生。
確保 atomicrmw 在使快取失效之前已完成。
buffer_invl2; buffer_wbinvl1_vol
必須在任何後續的全域/通用載入/載入原子/atomicrmw 之前發生。
確保後續的載入不會看到過時的 L1 全域資料,也不會看到過時的 L2 MTYPE NC 全域資料。 由於記憶體探測,MTYPE RW 和 CC 記憶體在 L2 中永遠不會過時。
柵欄
取得
singlethread
wavefront
none
none
柵欄
取得
workgroup
none
s_waitcnt lgkm/vmcnt(0)
如果不是 TgSplit 執行模式,則使用 lgkmcnt(0),如果是 TgSplit 執行模式,則使用 vmcnt(0)。
如果是 OpenCL 且位址空間不是通用的,則省略 lgkmcnt(0)。
如果是 OpenCL 且位址空間是區域的,則省略 vmcnt(0)。
有關特定位址空間柵欄的更多詳細資訊,請參閱 柵欄和位址空間。
s_waitcnt vmcnt(0) 必須在任何先前的全域/通用載入原子/ atomicrmw 之後發生,其同步作用域相等或更寬,且記憶體排序強於無序(這稱為柵欄配對原子)。
s_waitcnt lgkmcnt(0) 必須在任何先前的區域/通用載入原子/atomicrmw 之後發生,其同步作用域相等或更寬,且記憶體排序強於無序(這稱為柵欄配對原子)。
必須在後續的 buffer_wbinvl1_vol 以及任何後續的全域/通用載入/載入原子/儲存/儲存原子/atomicrmw 之前發生。
確保任何後續的全域資料讀取都不會早於柵欄配對原子讀取的值。
buffer_wbinvl1_vol
如果不是 TgSplit 執行模式,則省略。
確保後續的載入不會看到過時的資料。
柵欄
取得
agent
none
s_waitcnt lgkmcnt(0) & vmcnt(0)
如果是 TgSplit 執行模式,則省略 lgkmcnt(0)。
如果是 OpenCL 且位址空間不是通用的,則省略 lgkmcnt(0)。
有關特定位址空間柵欄的更多詳細資訊,請參閱 柵欄和位址空間。
可以拆分為單獨的 s_waitcnt vmcnt(0) 和 s_waitcnt lgkmcnt(0),以允許根據以下規則獨立移動它們。
s_waitcnt vmcnt(0) 必須在任何先前的全域/通用載入原子/atomicrmw 之後發生,其同步作用域相等或更寬,且記憶體排序強於無序(這稱為柵欄配對原子)。
s_waitcnt lgkmcnt(0) 必須在任何先前的區域/通用載入原子/atomicrmw 之後發生,其同步作用域相等或更寬,且記憶體排序強於無序(這稱為柵欄配對原子)。
必須在後續的 buffer_wbinvl1_vol 之前發生。
確保柵欄配對原子在使快取失效之前已完成。 因此,任何後續讀取的位置都不得早於柵欄配對原子讀取的值。
buffer_wbinvl1_vol
必須在任何後續的全域/通用載入/載入原子/儲存/儲存原子/atomicrmw 之前發生。
確保後續的載入不會看到過時的全域資料。
柵欄
取得
system
none
s_waitcnt lgkmcnt(0) & vmcnt(0)
如果是 TgSplit 執行模式,則省略 lgkmcnt(0)。
如果是 OpenCL 且位址空間不是通用的,則省略 lgkmcnt(0)。
有關特定位址空間柵欄的更多詳細資訊,請參閱 柵欄和位址空間。
可以拆分為單獨的 s_waitcnt vmcnt(0) 和 s_waitcnt lgkmcnt(0),以允許根據以下規則獨立移動它們。
s_waitcnt vmcnt(0) 必須在任何先前的全域/通用載入原子/atomicrmw 之後發生,其同步作用域相等或更寬,且記憶體排序強於無序(這稱為柵欄配對原子)。
s_waitcnt lgkmcnt(0) 必須在任何先前的區域/通用載入原子/atomicrmw 之後發生,其同步作用域相等或更寬,且記憶體排序強於無序(這稱為柵欄配對原子)。
必須在後續的 buffer_invl2 和 buffer_wbinvl1_vol 之前發生。
確保柵欄配對原子在使快取失效之前已完成。 因此,任何後續讀取的位置都不得早於柵欄配對原子讀取的值。
buffer_invl2; buffer_wbinvl1_vol
必須在任何後續的全域/通用載入/載入原子/儲存/儲存原子/atomicrmw 之前發生。
確保後續的載入不會看到過時的 L1 全域資料,也不會看到過時的 L2 MTYPE NC 全域資料。 由於記憶體探測,MTYPE RW 和 CC 記憶體在 L2 中永遠不會過時。
釋放原子
儲存原子
釋放
singlethread
wavefront
global
通用
buffer/global/flat_store
儲存原子
釋放
singlethread
wavefront
區域
如果是 TgSplit 執行模式,則無法使用區域位址空間。
ds_store
儲存原子
釋放
workgroup
global
通用
s_waitcnt lgkm/vmcnt(0)
如果不是 TgSplit 執行模式,則使用 lgkmcnt(0),如果是 TgSplit 執行模式,則使用 vmcnt(0)。
如果是 OpenCL,則省略 lgkmcnt(0)。
s_waitcnt vmcnt(0) 必須在任何先前的全域/通用載入/儲存/ 載入原子/儲存原子/ atomicrmw 之後發生。
s_waitcnt lgkmcnt(0) 必須在任何先前的區域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
必須在後續的儲存之前發生。
確保所有記憶體操作在執行正在釋放的儲存之前已完成。
buffer/global/flat_store
儲存原子
釋放
workgroup
區域
如果是 TgSplit 執行模式,則無法使用區域位址空間。
ds_store
儲存原子
釋放
agent
global
通用
s_waitcnt lgkmcnt(0) & vmcnt(0)
如果是 TgSplit 執行模式,則省略 lgkmcnt(0)。
如果是 OpenCL 且位址空間不是通用的,則省略 lgkmcnt(0)。
可以拆分為單獨的 s_waitcnt vmcnt(0) 和 s_waitcnt lgkmcnt(0),以允許根據以下規則獨立移動它們。
s_waitcnt vmcnt(0) 必須在任何先前的全域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
s_waitcnt lgkmcnt(0) 必須在任何先前的區域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
必須在後續的儲存之前發生。
確保對記憶體的所有記憶體操作在執行正在釋放的儲存之前已完成。
buffer/global/flat_store
儲存原子
釋放
system
global
通用
buffer_wbl2
必須在後續的 s_waitcnt 之前發生。
執行 L2 寫回以確保先前的全域/通用儲存/atomicrmw 在系統作用域中可見。
s_waitcnt lgkmcnt(0) & vmcnt(0)
如果是 TgSplit 執行模式,則省略 lgkmcnt(0)。
如果是 OpenCL 且位址空間不是通用的,則省略 lgkmcnt(0)。
可以拆分為單獨的 s_waitcnt vmcnt(0) 和 s_waitcnt lgkmcnt(0),以允許根據以下規則獨立移動它們。
s_waitcnt vmcnt(0) 必須在任何先前的全域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
s_waitcnt lgkmcnt(0) 必須在任何先前的區域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
必須在後續的儲存之前發生。
確保對記憶體的所有記憶體操作和 L2 寫回在執行正在釋放的儲存之前已完成。
buffer/global/flat_store
atomicrmw
釋放
singlethread
wavefront
global
通用
buffer/global/flat_atomic
atomicrmw
釋放
singlethread
wavefront
區域
如果是 TgSplit 執行模式,則無法使用區域位址空間。
ds_atomic
atomicrmw
釋放
workgroup
global
通用
s_waitcnt lgkm/vmcnt(0)
如果不是 TgSplit 執行模式,則使用 lgkmcnt(0),如果是 TgSplit 執行模式,則使用 vmcnt(0)。
如果是 OpenCL,則省略 lgkmcnt(0)。
s_waitcnt vmcnt(0) 必須在任何先前的全域/通用載入/儲存/ 載入原子/儲存原子/ atomicrmw 之後發生。
s_waitcnt lgkmcnt(0) 必須在任何先前的區域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
必須在後續的 atomicrmw 之前發生。
確保所有記憶體操作在執行正在釋放的 atomicrmw 之前已完成。
buffer/global/flat_atomic
atomicrmw
釋放
workgroup
區域
如果是 TgSplit 執行模式,則無法使用區域位址空間。
ds_atomic
atomicrmw
釋放
agent
global
通用
s_waitcnt lgkmcnt(0) & vmcnt(0)
如果是 TgSplit 執行模式,則省略 lgkmcnt(0)。
如果是 OpenCL,則省略 lgkmcnt(0)。
可以拆分為單獨的 s_waitcnt vmcnt(0) 和 s_waitcnt lgkmcnt(0),以允許根據以下規則獨立移動它們。
s_waitcnt vmcnt(0) 必須在任何先前的全域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
s_waitcnt lgkmcnt(0) 必須在任何先前的區域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
必須在後續的 atomicrmw 之前發生。
確保對全域和區域的所有記憶體操作在執行正在釋放的 atomicrmw 之前已完成。
buffer/global/flat_atomic
atomicrmw
釋放
system
global
通用
buffer_wbl2
必須在後續的 s_waitcnt 之前發生。
執行 L2 寫回以確保先前的全域/通用儲存/atomicrmw 在系統作用域中可見。
s_waitcnt lgkmcnt(0) & vmcnt(0)
如果是 TgSplit 執行模式,則省略 lgkmcnt(0)。
如果是 OpenCL,則省略 lgkmcnt(0)。
可以拆分為單獨的 s_waitcnt vmcnt(0) 和 s_waitcnt lgkmcnt(0),以允許根據以下規則獨立移動它們。
s_waitcnt vmcnt(0) 必須在任何先前的全域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
s_waitcnt lgkmcnt(0) 必須在任何先前的區域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
必須在後續的 atomicrmw 之前發生。
確保對記憶體的所有記憶體操作和 L2 寫回在執行正在釋放的儲存之前已完成。
buffer/global/flat_atomic
柵欄
釋放
singlethread
wavefront
none
none
柵欄
釋放
workgroup
none
s_waitcnt lgkm/vmcnt(0)
如果不是 TgSplit 執行模式,則使用 lgkmcnt(0),如果是 TgSplit 執行模式,則使用 vmcnt(0)。
如果是 OpenCL 且位址空間不是通用的,則省略 lgkmcnt(0)。
如果是 OpenCL 且位址空間是區域的,則省略 vmcnt(0)。
有關特定位址空間柵欄的更多詳細資訊,請參閱 柵欄和位址空間。
s_waitcnt vmcnt(0) 必須在任何先前的全域/通用載入/儲存/ 載入原子/儲存原子/ atomicrmw 之後發生。
s_waitcnt lgkmcnt(0) 必須在任何先前的區域/通用載入/載入原子/儲存/儲存原子/atomicrmw 之後發生。
必須在任何後續的儲存原子/atomicrmw 之前發生,其同步作用域相等或更寬,且記憶體排序強於無序(這稱為柵欄配對原子)。
確保所有記憶體操作在執行後續的柵欄配對原子之前已完成。
柵欄
釋放
agent
none
s_waitcnt lgkmcnt(0) & vmcnt(0)
如果是 TgSplit 執行模式,則省略 lgkmcnt(0)。
如果是 OpenCL 且位址空間不是通用的,則省略 lgkmcnt(0)。
如果是 OpenCL 且位址空間是區域的,則省略 vmcnt(0)。
有關特定位址空間柵欄的更多詳細資訊,請參閱 柵欄和位址空間。
可以拆分為單獨的 s_waitcnt vmcnt(0) 和 s_waitcnt lgkmcnt(0),以允許根據以下規則獨立移動它們。
s_waitcnt vmcnt(0) 必須在任何先前的全域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
s_waitcnt lgkmcnt(0) 必須在任何先前的區域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
必須在任何後續的儲存原子/atomicrmw 之前發生,其同步作用域相等或更寬,且記憶體排序強於無序(這稱為柵欄配對原子)。
確保所有記憶體操作在執行後續的柵欄配對原子之前已完成。
柵欄
釋放
system
none
buffer_wbl2
如果是 OpenCL 且位址空間是區域的,則省略。
必須在後續的 s_waitcnt 之前發生。
執行 L2 寫回以確保先前的全域/通用儲存/atomicrmw 在系統作用域中可見。
s_waitcnt lgkmcnt(0) & vmcnt(0)
如果是 TgSplit 執行模式,則省略 lgkmcnt(0)。
如果是 OpenCL 且位址空間不是通用的,則省略 lgkmcnt(0)。
如果是 OpenCL 且位址空間是區域的,則省略 vmcnt(0)。
有關特定位址空間柵欄的更多詳細資訊,請參閱 柵欄和位址空間。
可以拆分為單獨的 s_waitcnt vmcnt(0) 和 s_waitcnt lgkmcnt(0),以允許根據以下規則獨立移動它們。
s_waitcnt vmcnt(0) 必須在任何先前的全域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
s_waitcnt lgkmcnt(0) 必須在任何先前的區域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
必須在任何後續的儲存原子/atomicrmw 之前發生,其同步作用域相等或更寬,且記憶體排序強於無序(這稱為柵欄配對原子)。
確保所有記憶體操作在執行後續的柵欄配對原子之前已完成。
取得-釋放原子
atomicrmw
取得_釋放
singlethread
wavefront
global
通用
buffer/global/flat_atomic
atomicrmw
取得_釋放
singlethread
wavefront
區域
如果是 TgSplit 執行模式,則無法使用區域位址空間。
ds_atomic
atomicrmw
取得_釋放
workgroup
global
s_waitcnt lgkm/vmcnt(0)
如果不是 TgSplit 執行模式,則使用 lgkmcnt(0),如果是 TgSplit 執行模式,則使用 vmcnt(0)。
如果是 OpenCL,則省略 lgkmcnt(0)。
必須在任何先前的區域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
s_waitcnt vmcnt(0) 必須在任何先前的全域/通用載入/儲存/ 載入原子/儲存原子/ atomicrmw 之後發生。
s_waitcnt lgkmcnt(0) 必須在任何先前的區域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
必須在後續的 atomicrmw 之前發生。
確保所有記憶體操作在執行正在釋放的 atomicrmw 之前已完成。
buffer/global_atomic
s_waitcnt vmcnt(0)
如果不是 TgSplit 執行模式,則省略。
必須在後續的 buffer_wbinvl1_vol 之前發生。
確保任何後續的全域資料讀取都不會早於正在取得的 atomicrmw 值。
buffer_wbinvl1_vol
如果不是 TgSplit 執行模式,則省略。
確保後續的載入不會看到過時的資料。
atomicrmw
取得_釋放
workgroup
區域
如果是 TgSplit 執行模式,則無法使用區域位址空間。
ds_atomic
s_waitcnt lgkmcnt(0)
如果是 OpenCL,則省略。
必須在任何後續的全域/通用載入/載入原子/儲存/儲存原子/atomicrmw 之前發生。
確保任何後續的全域資料讀取都不會早於正在取得的區域載入原子值。
atomicrmw
取得_釋放
workgroup
通用
s_waitcnt lgkm/vmcnt(0)
如果不是 TgSplit 執行模式,則使用 lgkmcnt(0),如果是 TgSplit 執行模式,則使用 vmcnt(0)。
如果是 OpenCL,則省略 lgkmcnt(0)。
s_waitcnt vmcnt(0) 必須在任何先前的全域/通用載入/儲存/ 載入原子/儲存原子/ atomicrmw 之後發生。
s_waitcnt lgkmcnt(0) 必須在任何先前的區域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
必須在後續的 atomicrmw 之前發生。
確保所有記憶體操作在執行正在釋放的 atomicrmw 之前已完成。
flat_atomic
s_waitcnt lgkmcnt(0) & vmcnt(0)
如果不是 TgSplit 執行模式,則省略 vmcnt(0)。
如果是 OpenCL,則省略 lgkmcnt(0)。
必須在後續的 buffer_wbinvl1_vol 以及任何後續的全域/通用載入/載入原子/儲存/儲存原子/atomicrmw 之前發生。
確保任何後續的全域資料讀取都不會早於正在取得的區域載入原子值。
buffer_wbinvl1_vol
如果不是 TgSplit 執行模式,則省略。
確保後續的載入不會看到過時的資料。
atomicrmw
取得_釋放
agent
global
s_waitcnt lgkmcnt(0) & vmcnt(0)
如果是 TgSplit 執行模式,則省略 lgkmcnt(0)。
如果是 OpenCL,則省略 lgkmcnt(0)。
可以拆分為單獨的 s_waitcnt vmcnt(0) 和 s_waitcnt lgkmcnt(0),以允許根據以下規則獨立移動它們。
s_waitcnt vmcnt(0) 必須在任何先前的全域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
s_waitcnt lgkmcnt(0) 必須在任何先前的區域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
必須在後續的 atomicrmw 之前發生。
確保對全域的所有記憶體操作在執行正在釋放的 atomicrmw 之前已完成。
buffer/global_atomic
s_waitcnt vmcnt(0)
必須在後續的 buffer_wbinvl1_vol 之前發生。
確保 atomicrmw 在使快取失效之前已完成。
buffer_wbinvl1_vol
必須在任何後續的全域/通用載入/載入原子/atomicrmw 之前發生。
確保後續的載入不會看到過時的全域資料。
atomicrmw
取得_釋放
system
global
buffer_wbl2
必須在後續的 s_waitcnt 之前發生。
執行 L2 寫回以確保先前的全域/通用儲存/atomicrmw 在系統作用域中可見。
s_waitcnt lgkmcnt(0) & vmcnt(0)
如果是 TgSplit 執行模式,則省略 lgkmcnt(0)。
如果是 OpenCL,則省略 lgkmcnt(0)。
可以拆分為單獨的 s_waitcnt vmcnt(0) 和 s_waitcnt lgkmcnt(0),以允許根據以下規則獨立移動它們。
s_waitcnt vmcnt(0) 必須在任何先前的全域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
s_waitcnt lgkmcnt(0) 必須在任何先前的區域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
必須在後續的 atomicrmw 之前發生。
確保對全域的所有記憶體操作和 L2 寫回在執行正在釋放的 atomicrmw 之前已完成。
buffer/global_atomic
s_waitcnt vmcnt(0)
必須在後續的 buffer_invl2 和 buffer_wbinvl1_vol 之前發生。
確保 atomicrmw 在使快取失效之前已完成。
buffer_invl2; buffer_wbinvl1_vol
必須在任何後續的全域/通用載入/載入原子/atomicrmw 之前發生。
確保後續的載入不會看到過時的 L1 全域資料,也不會看到過時的 L2 MTYPE NC 全域資料。 由於記憶體探測,MTYPE RW 和 CC 記憶體在 L2 中永遠不會過時。
atomicrmw
取得_釋放
agent
通用
s_waitcnt lgkmcnt(0) & vmcnt(0)
如果是 TgSplit 執行模式,則省略 lgkmcnt(0)。
如果是 OpenCL,則省略 lgkmcnt(0)。
可以拆分為單獨的 s_waitcnt vmcnt(0) 和 s_waitcnt lgkmcnt(0),以允許根據以下規則獨立移動它們。
s_waitcnt vmcnt(0) 必須在任何先前的全域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
s_waitcnt lgkmcnt(0) 必須在任何先前的區域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
必須在後續的 atomicrmw 之前發生。
確保對全域的所有記憶體操作在執行正在釋放的 atomicrmw 之前已完成。
flat_atomic
s_waitcnt vmcnt(0) & lgkmcnt(0)
如果是 TgSplit 執行模式,則省略 lgkmcnt(0)。
如果是 OpenCL,則省略 lgkmcnt(0)。
必須在後續的 buffer_wbinvl1_vol 之前發生。
確保 atomicrmw 在使快取失效之前已完成。
buffer_wbinvl1_vol
必須在任何後續的全域/通用載入/載入原子/atomicrmw 之前發生。
確保後續的載入不會看到過時的全域資料。
atomicrmw
取得_釋放
system
通用
buffer_wbl2
必須在後續的 s_waitcnt 之前發生。
執行 L2 寫回以確保先前的全域/通用儲存/atomicrmw 在系統作用域中可見。
s_waitcnt lgkmcnt(0) & vmcnt(0)
如果是 TgSplit 執行模式,則省略 lgkmcnt(0)。
如果是 OpenCL,則省略 lgkmcnt(0)。
可以拆分為單獨的 s_waitcnt vmcnt(0) 和 s_waitcnt lgkmcnt(0),以允許根據以下規則獨立移動它們。
s_waitcnt vmcnt(0) 必須在任何先前的全域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
s_waitcnt lgkmcnt(0) 必須在任何先前的區域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
必須在後續的 atomicrmw 之前發生。
確保對全域的所有記憶體操作和 L2 寫回在執行正在釋放的 atomicrmw 之前已完成。
flat_atomic
s_waitcnt vmcnt(0) & lgkmcnt(0)
如果是 TgSplit 執行模式,則省略 lgkmcnt(0)。
如果是 OpenCL,則省略 lgkmcnt(0)。
必須在後續的 buffer_invl2 和 buffer_wbinvl1_vol 之前發生。
確保 atomicrmw 在使快取失效之前已完成。
buffer_invl2; buffer_wbinvl1_vol
必須在任何後續的全域/通用載入/載入原子/atomicrmw 之前發生。
確保後續的載入不會看到過時的 L1 全域資料,也不會看到過時的 L2 MTYPE NC 全域資料。 由於記憶體探測,MTYPE RW 和 CC 記憶體在 L2 中永遠不會過時。
柵欄
取得_釋放
singlethread
wavefront
none
none
柵欄
取得_釋放
workgroup
none
s_waitcnt lgkm/vmcnt(0)
如果不是 TgSplit 執行模式,則使用 lgkmcnt(0),如果是 TgSplit 執行模式,則使用 vmcnt(0)。
如果是 OpenCL 且位址空間不是通用的,則省略 lgkmcnt(0)。
如果是 OpenCL 且位址空間是區域的,則省略 vmcnt(0)。
但是,由於 LLVM 目前在柵欄上沒有位址空間,因此需要保守地始終產生(請參閱先前柵欄的註解)。
s_waitcnt vmcnt(0) 必須在任何先前的全域/通用載入/儲存/ 載入原子/儲存原子/ atomicrmw 之後發生。
s_waitcnt lgkmcnt(0) 必須在任何先前的區域/通用載入/載入原子/儲存/儲存原子/atomicrmw 之後發生。
必須在任何後續的全域/通用載入/載入原子/儲存/儲存原子/atomicrmw 之前發生。
確保所有記憶體操作在執行任何後續的全域記憶體操作之前已完成。
確保先前的區域/通用載入原子/atomicrmw,其同步作用域相等或更寬,且記憶體排序強於無序(這稱為取得柵欄配對原子),在後續的全域記憶體操作之前已完成。 這滿足取得的要求。
確保所有先前的記憶體操作在後續的區域/通用儲存原子/atomicrmw 之前已完成,其同步作用域相等或更寬,且記憶體排序強於無序(這稱為釋放柵欄配對原子)。 這滿足釋放的要求。
必須在後續的 buffer_wbinvl1_vol 之前發生。
確保取得柵欄配對原子在使快取失效之前已完成。 因此,任何後續讀取的位置都不得早於取得柵欄配對原子讀取的值。
buffer_wbinvl1_vol
如果不是 TgSplit 執行模式,則省略。
確保後續的載入不會看到過時的資料。
柵欄
取得_釋放
agent
none
s_waitcnt lgkmcnt(0) & vmcnt(0)
如果是 TgSplit 執行模式,則省略 lgkmcnt(0)。
如果是 OpenCL 且位址空間不是通用的,則省略 lgkmcnt(0)。
有關特定位址空間柵欄的更多詳細資訊,請參閱 柵欄和位址空間。
可以拆分為單獨的 s_waitcnt vmcnt(0) 和 s_waitcnt lgkmcnt(0),以允許根據以下規則獨立移動它們。
s_waitcnt vmcnt(0) 必須在任何先前的全域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
s_waitcnt lgkmcnt(0) 必須在任何先前的區域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
必須在後續的 buffer_wbinvl1_vol 之前發生。
確保先前的全域/區域/通用載入原子/atomicrmw,其同步作用域相等或更寬,且記憶體排序強於無序(這稱為取得柵欄配對原子),在使快取失效之前已完成。 這滿足取得的要求。
確保所有先前的記憶體操作在後續的全域/區域/通用儲存原子/atomicrmw 之前已完成,其同步作用域相等或更寬,且記憶體排序強於無序(這稱為釋放柵欄配對原子)。 這滿足釋放的要求。
buffer_wbinvl1_vol
必須在任何後續的全域/通用載入/載入原子/儲存/儲存原子/atomicrmw 之前發生。
確保後續的載入不會看到過時的全域資料。 這滿足取得的要求。
柵欄
取得_釋放
system
none
buffer_wbl2
如果是 OpenCL 且位址空間是區域的,則省略。
必須在後續的 s_waitcnt 之前發生。
執行 L2 寫回以確保先前的全域/通用儲存/atomicrmw 在系統作用域中可見。
s_waitcnt lgkmcnt(0) & vmcnt(0)
如果是 TgSplit 執行模式,則省略 lgkmcnt(0)。
如果是 OpenCL 且位址空間不是通用的,則省略 lgkmcnt(0)。
有關特定位址空間柵欄的更多詳細資訊,請參閱 柵欄和位址空間。
可以拆分為單獨的 s_waitcnt vmcnt(0) 和 s_waitcnt lgkmcnt(0),以允許根據以下規則獨立移動它們。
s_waitcnt vmcnt(0) 必須在任何先前的全域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
s_waitcnt lgkmcnt(0) 必須在任何先前的區域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
必須在後續的 buffer_invl2 和 buffer_wbinvl1_vol 之前發生。
確保先前的全域/區域/通用載入原子/atomicrmw,其同步作用域相等或更寬,且記憶體排序強於無序(這稱為取得柵欄配對原子),在使快取失效之前已完成。 這滿足取得的要求。
確保所有先前的記憶體操作在後續的全域/區域/通用儲存原子/atomicrmw 之前已完成,其同步作用域相等或更寬,且記憶體排序強於無序(這稱為釋放柵欄配對原子)。 這滿足釋放的要求。
buffer_invl2; buffer_wbinvl1_vol
必須在任何後續的全域/通用載入/載入原子/儲存/儲存原子/atomicrmw 之前發生。
確保後續的載入不會看到過時的 L1 全域資料,也不會看到過時的 L2 MTYPE NC 全域資料。 由於記憶體探測,MTYPE RW 和 CC 記憶體在 L2 中永遠不會過時。
循序一致性原子
載入原子
seq_cst
singlethread
wavefront
global
區域
通用
與對應的載入原子取得相同,但即使對於 OpenCL 也必須產生所有指令。
載入原子
seq_cst
workgroup
global
通用
s_waitcnt lgkm/vmcnt(0)
如果不是 TgSplit 執行模式,則使用 lgkmcnt(0),如果是 TgSplit 執行模式,則使用 vmcnt(0)。
s_waitcnt lgkmcnt(0) 必須在先前的區域/通用載入原子/儲存原子/atomicrmw 之後發生,其記憶體排序為 seq_cst,且同步作用域相等或更寬。(請注意,seq_cst 柵欄有自己的 s_waitcnt lgkmcnt(0),因此不需要考慮。)
s_waitcnt vmcnt(0) 必須在先前的全域/通用載入原子/儲存原子/atomicrmw 之後發生,其記憶體排序為 seq_cst,且同步作用域相等或更寬。(請注意,seq_cst 柵欄有自己的 s_waitcnt vmcnt(0),因此不需要考慮。)
確保任何先前的循序一致性全域/區域記憶體指令在執行此循序一致性指令之前已完成。 這可以防止重新排序 seq_cst 儲存,然後是 seq_cst 載入。(請注意,seq_cst 比取得/釋放更強,因為釋放的 s_waitcnt 會阻止重新排序載入取得,然後是儲存釋放,但是沒有任何東西阻止儲存釋放,然後是載入取得以無序完成。 s_waitcnt 可以放在 seq_store 之後或 seq_load 之前。 我們選擇載入以使 s_waitcnt 盡可能晚,以便儲存可能已經完成。)
後續指令與對應的載入原子取得相同,但即使對於 OpenCL 也必須產生所有指令。
載入原子
seq_cst
workgroup
區域
如果是 TgSplit 執行模式,則無法使用區域位址空間。
與對應的載入原子取得相同,但即使對於 OpenCL 也必須產生所有指令。
載入原子
seq_cst
agent
system
global
通用
s_waitcnt lgkmcnt(0) & vmcnt(0)
如果是 TgSplit 執行模式,則省略 lgkmcnt(0)。
可以拆分為單獨的 s_waitcnt vmcnt(0) 和 s_waitcnt lgkmcnt(0),以允許根據以下規則獨立移動它們。
s_waitcnt lgkmcnt(0) 必須在先前的全域/通用載入原子/儲存原子/atomicrmw 之後發生,其記憶體排序為 seq_cst,且同步作用域相等或更寬。(請注意,seq_cst 柵欄有自己的 s_waitcnt lgkmcnt(0),因此不需要考慮。)
s_waitcnt vmcnt(0) 必須在先前的全域/通用載入原子/儲存原子/atomicrmw 之後發生,其記憶體排序為 seq_cst,且同步作用域相等或更寬。(請注意,seq_cst 柵欄有自己的 s_waitcnt vmcnt(0),因此不需要考慮。)
確保任何先前的循序一致性全域記憶體指令在執行此循序一致性指令之前已完成。 這可以防止重新排序 seq_cst 儲存,然後是 seq_cst 載入。(請注意,seq_cst 比取得/釋放更強,因為釋放的 s_waitcnt 會阻止重新排序載入取得,然後是儲存釋放,但是沒有任何東西阻止儲存釋放,然後是載入取得以無序完成。 s_waitcnt 可以放在 seq_store 之後或 seq_load 之前。 我們選擇載入以使 s_waitcnt 盡可能晚,以便儲存可能已經完成。)
後續指令與對應的載入原子取得相同,但即使對於 OpenCL 也必須產生所有指令。
儲存原子
seq_cst
singlethread
wavefront
workgroup
agent
system
global
區域
通用
與對應的儲存原子釋放相同,但即使對於 OpenCL 也必須產生所有指令。
atomicrmw
seq_cst
singlethread
wavefront
workgroup
agent
system
global
區域
通用
與對應的 atomicrmw acq_rel 相同,但即使對於 OpenCL 也必須產生所有指令。
柵欄
seq_cst
singlethread
wavefront
workgroup
agent
system
none
與對應的柵欄 acq_rel 相同,但即使對於 OpenCL 也必須產生所有指令。
記憶體模型 GFX942¶
對於 GFX942
每個代理程式有多個著色器陣列 (SA)。
每個 SA 有多個運算單元 (CU)。
每個 CU 有多個執行波前的 SIMD。
單個工作群組的波前在同一個 CU 中執行,但可能由不同的 SIMD 執行。 例外情況是當處於 tgsplit 執行模式時,波前可能由不同 CU 中的不同 SIMD 執行。
每個 CU 都有一個單個 LDS 記憶體,由在其上執行的工作群組的波前共享。 例外情況是當處於 tgsplit 執行模式時,由於同一工作群組的波前可能位於不同的 CU 中,因此不分配 LDS。
CU 的所有 LDS 操作都作為波前寬操作以全域順序執行,並且不涉及快取。完成情況以執行順序報告給波前。
LDS 記憶體有多個請求佇列,這些佇列由 CU 的 SIMD 共用。因此,工作群組的不同波前執行的 LDS 操作可以彼此重新排序,這可能會導致相對於同一工作群組中其他波前的 LDS 操作重新排序向量記憶體操作的可見性。需要
s_waitcnt lgkmcnt(0)
以確保工作群組的波前之間的 LDS 操作和向量記憶體操作之間同步,而不是同一波前執行的操作之間同步。向量記憶體操作作為波前寬操作執行,完成情況以執行順序報告給波前。 例外情況是,如果
flat_load/store/atomic
指令存取 LDS 記憶體,則可以報告向量記憶體順序外,如果存取全域記憶體,則可以報告 LDS 操作順序外。向量記憶體操作存取由 CU 的所有 SIMD 共享的單個向量 L1 快取。 因此
單個波前的通道之間的一致性不需要特殊操作。
同一工作群組中波前之間的一致性不需要特殊操作,因為它們在同一個 CU 上執行。 例外情況是當處於 tgsplit 執行模式時,由於同一工作群組的波前可能位於不同的 CU 中,因此需要
buffer_inv sc0
,它將使 L1 快取失效。在不同工作群組中執行的波前之間的一致性需要
buffer_inv sc0
以使 L1 快取失效,因為它們可能在不同的 CU 上執行。原子讀取-修改-寫入指令隱式繞過 L1 快取。 因此,它們不使用 sc0 位元進行一致性,而是使用它來指示指令是否傳回正在更新的原始值。 它們確實使用 sc1 來指示系統或代理程式作用域一致性。
純量記憶體操作存取由一組 CU 上所有波前共用的純量 L1 快取。純量和向量 L1 快取不一致。但是,純量操作以受限的方式使用,因此不會影響記憶體模型。請參閱 記憶體空間。
向量和純量記憶體操作使用 L2 快取。
gfx942 可以配置為多個較小的代理程式,每個代理程式都有一個 L2,由同一代理程式上的所有 CU 共享,或者配置為較少(可能是一個)較大的代理程式,每個代理程式上的 CU 群組各自共享單獨的 L2 快取。
L2 快取具有獨立通道,用於服務不相交的虛擬位址範圍。
每個 CU 都有一個單獨的每個通道的請求佇列,用於其關聯的 L2。 因此,由具有不同 L1 快取和相同 L2 快取的波前執行的向量和純量記憶體操作可以相對於彼此重新排序。
需要
s_waitcnt vmcnt(0)
以確保不同 CU 的向量記憶體操作之間的同步。 它確保先前的向量記憶體操作在執行後續的向量記憶體或 LDS 操作之前已完成,因此可以用於滿足取得和釋放的要求。L2 快取可以透過對 L2 本地的記憶體使用 MTYPE RW(讀寫),以及對非 L2 本地的記憶體使用設定 PTE C 位元的 MTYPE NC(非一致性),與其他 L2 快取保持一致性。
由於 PTE C 位元引起的快取探測,任何本地記憶體快取行都將自動被來自與其他 L2 快取關聯的 CU 或來自 CPU 的寫入失效。
來自 CPU 的 XGMI 對本地記憶體的存取可能會在 CPU 上快取。 由於 L2 探測篩選器,來自 GPU 的後續存取將自動使 CPU 快取失效或寫回。
為了確保同一代理程式中具有不同 L1 快取的 CU 的本地記憶體寫入的一致性,需要
buffer_wbl2
。 如果代理程式配置為具有單個 L2,它將不執行任何操作,如果配置為具有多個 L2 快取,則將寫回髒 L2 快取行。為了確保不同代理程式中 CU 的本地記憶體寫入的一致性,需要
buffer_wbl2 sc1
。 它將寫回髒 L2 快取行。為了確保同一代理程式中具有不同 L1 快取的 CU 的本地記憶體讀取的一致性,需要
buffer_inv sc1
。 如果代理程式配置為具有單個 L2,它將不執行任何操作,如果配置為具有多個 L2 快取,則將使非本地 L2 快取行失效。為了確保不同代理程式中 CU 的本地記憶體讀取的一致性,需要
buffer_inv sc0 sc1
。 如果配置為具有多個 L2 快取,它將使非本地 L2 快取行失效。
從 GPU 到 CPU 的 PCIe 存取可以透過使用 MTYPE UC(非快取)保持一致性,MTYPE UC(非快取)繞過 L2。
純量記憶體操作僅用於存取在核心調度執行期間證明不會變更的記憶體。 這包括常數位址空間和程式作用域 const
變數的全域位址空間。 因此,核心機器碼不必維護純量快取,以確保它與向量快取一致。 純量快取和向量快取在核心調度之間由 CP 使失效,因為常數位址空間資料可能在核心調度執行之間變更。 請參閱 記憶體空間。
一個例外情況是,如果純量寫入用於溢出 SGPR 暫存器。 在這種情況下,AMDGPU 後端確保用於溢出的記憶體位置永遠不會同時被向量記憶體操作存取。 如果使用純量寫入,則在 s_endpgm
之前和函數返回之前插入 s_dcache_wb
,因為這些位置可能被未來使用相同暫存區的波前或在相同位址建立框架的函數呼叫用於向量記憶體指令。 不需要 s_dcache_inv
,因為所有純量寫入在同一個執行緒中都是先寫後讀。
對於核心參數後備記憶體
CP 在每次核心調度開始時使 L1 快取失效。
在透過 XGMI 或 PCIe 的 dGPU 上,核心參數後備記憶體分配在主機記憶體中,以 MTYPE UC(非快取)存取,以避免需要使 L2 快取失效。 這也使其被視為非揮發性,因此不會被
*_vol
失效。在 APU 上,核心參數後備記憶體以 MTYPE CC(快取一致性)存取,因此 L2 快取將與 CPU 和其他代理程式保持一致性。
暫存後備記憶體(用於私有位址空間)以 MTYPE NC_NV(非一致性非揮發性)存取。 由於私有位址空間僅由單個執行緒存取,並且始終是先寫後讀,因此永遠不需要使 L1 快取中的這些條目失效。 因此,所有快取失效都以 *_vol
完成,僅使揮發性快取行失效。
用於實作 GFX942 記憶體模型的程式碼序列在表 AMDHSA 記憶體模型程式碼序列 GFX942 中定義。
表 81 AMDHSA 記憶體模型程式碼序列 GFX942¶ LLVM 指令
LLVM 記憶體排序
LLVM 記憶體同步作用域
AMDGPU 位址空間
AMDGPU 機器碼 GFX942
非原子
載入
none
none
global
通用
private
constant
!volatile & !nontemporal
buffer/global/flat_load
!volatile & nontemporal
buffer/global/flat_load nt=1
volatile
buffer/global/flat_load sc0=1 sc1=1
s_waitcnt vmcnt(0)
必須在任何後續的揮發性全域/通用載入/儲存之前發生。
確保對不同位址的揮發性操作不會被硬體重新排序。
載入
none
none
區域
ds_load
儲存
none
none
global
通用
private
constant
!volatile & !nontemporal
- GFX942
buffer/global/flat_store
!volatile & nontemporal
- GFX942
buffer/global/flat_store nt=1
volatile
buffer/global/flat_store sc0=1 sc1=1
s_waitcnt vmcnt(0)
必須在任何後續的揮發性全域/通用載入/儲存之前發生。
確保對不同位址的揮發性操作不會被硬體重新排序。
儲存
none
none
區域
ds_store
無序原子
載入原子
無序
任何
任何
與非原子相同.
儲存原子
無序
任何
任何
與非原子相同.
atomicrmw
無序
任何
任何
與單調原子相同.
單調原子
載入原子
單調
singlethread
wavefront
global
通用
buffer/global/flat_load
載入原子
單調
workgroup
global
通用
buffer/global/flat_load sc0=1
載入原子
單調
singlethread
wavefront
workgroup
區域
如果是 TgSplit 執行模式,則無法使用區域位址空間。
ds_load
載入原子
單調
agent
global
通用
buffer/global/flat_load sc1=1
載入原子
單調
system
global
通用
buffer/global/flat_load sc0=1 sc1=1
儲存原子
單調
singlethread
wavefront
global
通用
buffer/global/flat_store
儲存原子
單調
workgroup
global
通用
buffer/global/flat_store sc0=1
儲存原子
單調
agent
global
通用
buffer/global/flat_store sc1=1
儲存原子
單調
system
global
通用
buffer/global/flat_store sc0=1 sc1=1
儲存原子
單調
singlethread
wavefront
workgroup
區域
如果是 TgSplit 執行模式,則無法使用區域位址空間。
ds_store
atomicrmw
單調
singlethread
wavefront
workgroup
agent
global
通用
buffer/global/flat_atomic
atomicrmw
單調
system
global
通用
buffer/global/flat_atomic sc1=1
atomicrmw
單調
singlethread
wavefront
workgroup
區域
如果是 TgSplit 執行模式,則無法使用區域位址空間。
ds_atomic
取得原子
載入原子
取得
singlethread
wavefront
global
區域
通用
buffer/global/ds/flat_load
載入原子
取得
workgroup
global
buffer/global_load sc0=1
s_waitcnt vmcnt(0)
如果不是 TgSplit 執行模式,則省略。
必須在後續的 buffer_inv 之前發生。
buffer_inv sc0=1
如果不是 TgSplit 執行模式,則省略。
必須在任何後續的全域/通用載入/載入原子/儲存/儲存原子/atomicrmw 之前發生。
確保後續的載入不會看到過時的資料。
載入原子
取得
workgroup
區域
如果是 TgSplit 執行模式,則無法使用區域位址空間。
ds_load
s_waitcnt lgkmcnt(0)
如果是 OpenCL,則省略。
必須在任何後續的全域/通用載入/載入原子/儲存/儲存原子/atomicrmw 之前發生。
確保任何後續的全域資料讀取都不會早於正在取得的區域載入原子值。
載入原子
取得
workgroup
通用
flat_load sc0=1
s_waitcnt lgkm/vmcnt(0)
如果不是 TgSplit 執行模式,則使用 lgkmcnt(0),如果是 TgSplit 執行模式,則使用 vmcnt(0)。
如果是 OpenCL,則省略 lgkmcnt(0)。
必須在後續的 buffer_inv 以及任何後續的全域/通用載入/載入原子/儲存/儲存原子/atomicrmw 之前發生。
確保任何後續的全域資料讀取都不會早於正在取得的區域載入原子值。
buffer_inv sc0=1
如果不是 TgSplit 執行模式,則省略。
確保後續的載入不會看到過時的資料。
載入原子
取得
agent
global
buffer/global_load sc1=1
s_waitcnt vmcnt(0)
必須在後續的 buffer_inv 之前發生。
確保載入在使快取失效之前已完成。
buffer_inv sc1=1
必須在任何後續的全域/通用載入/載入原子/atomicrmw 之前發生。
確保後續的載入不會看到過時的全域資料。
載入原子
取得
system
global
buffer/global/flat_load sc0=1 sc1=1
s_waitcnt vmcnt(0)
必須在後續的 buffer_inv 之前發生。
確保載入在使快取失效之前已完成。
buffer_inv sc0=1 sc1=1
必須在任何後續的全域/通用載入/載入原子/atomicrmw 之前發生。
確保後續的載入不會看到過時的 MTYPE NC 全域資料。 由於記憶體探測,MTYPE RW 和 CC 記憶體永遠不會過時。
載入原子
取得
agent
通用
flat_load sc1=1
s_waitcnt vmcnt(0) & lgkmcnt(0)
如果是 TgSplit 執行模式,則省略 lgkmcnt(0)。
如果是 OpenCL,則省略 lgkmcnt(0)。
必須在後續的 buffer_inv 之前發生。
確保 flat_load 在使快取失效之前已完成。
buffer_inv sc1=1
必須在任何後續的全域/通用載入/載入原子/atomicrmw 之前發生。
確保後續的載入不會看到過時的全域資料。
載入原子
取得
system
通用
flat_load sc0=1 sc1=1
s_waitcnt vmcnt(0) & lgkmcnt(0)
如果是 TgSplit 執行模式,則省略 lgkmcnt(0)。
如果是 OpenCL,則省略 lgkmcnt(0)。
必須在後續的 buffer_inv 之前發生。
確保 flat_load 在使快取失效之前已完成。
buffer_inv sc0=1 sc1=1
必須在任何後續的全域/通用載入/載入原子/atomicrmw 之前發生。
確保後續的載入不會看到過時的 MTYPE NC 全域資料。 由於記憶體探測,MTYPE RW 和 CC 記憶體永遠不會過時。
atomicrmw
取得
singlethread
wavefront
global
通用
buffer/global/flat_atomic
atomicrmw
取得
singlethread
wavefront
區域
如果是 TgSplit 執行模式,則無法使用區域位址空間。
ds_atomic
atomicrmw
取得
workgroup
global
buffer/global_atomic
s_waitcnt vmcnt(0)
如果不是 TgSplit 執行模式,則省略。
必須在後續的 buffer_inv 之前發生。
確保 atomicrmw 在使快取失效之前已完成。
buffer_inv sc0=1
如果不是 TgSplit 執行模式,則省略。
必須在任何後續的全域/通用載入/載入原子/atomicrmw 之前發生。
確保後續的載入不會看到過時的全域資料。
atomicrmw
取得
workgroup
區域
如果是 TgSplit 執行模式,則無法使用區域位址空間。
ds_atomic
s_waitcnt lgkmcnt(0)
如果是 OpenCL,則省略。
必須在任何後續的全域/通用載入/載入原子/儲存/儲存原子/atomicrmw 之前發生。
確保任何後續的全域資料讀取都不會早於正在取得的區域 atomicrmw 值。
atomicrmw
取得
workgroup
通用
flat_atomic
s_waitcnt lgkm/vmcnt(0)
如果不是 TgSplit 執行模式,則使用 lgkmcnt(0),如果是 TgSplit 執行模式,則使用 vmcnt(0)。
如果是 OpenCL,則省略 lgkmcnt(0)。
必須在後續的 buffer_inv 以及任何後續的全域/通用載入/載入原子/儲存/儲存原子/atomicrmw 之前發生。
確保任何後續的全域資料讀取都不會早於正在取得的區域 atomicrmw 值。
buffer_inv sc0=1
如果不是 TgSplit 執行模式,則省略。
確保後續的載入不會看到過時的資料。
atomicrmw
取得
agent
global
buffer/global_atomic
s_waitcnt vmcnt(0)
必須在後續的 buffer_inv 之前發生。
確保 atomicrmw 在使快取失效之前已完成。
buffer_inv sc1=1
必須在任何後續的全域/通用載入/載入原子/atomicrmw 之前發生。
確保後續的載入不會看到過時的全域資料。
atomicrmw
取得
system
global
buffer/global_atomic sc1=1
s_waitcnt vmcnt(0)
必須在後續的 buffer_inv 之前發生。
確保 atomicrmw 在使快取失效之前已完成。
buffer_inv sc0=1 sc1=1
必須在任何後續的全域/通用載入/載入原子/atomicrmw 之前發生。
確保後續的載入不會看到過時的 MTYPE NC 全域資料。 由於記憶體探測,MTYPE RW 和 CC 記憶體永遠不會過時。
atomicrmw
取得
agent
通用
flat_atomic
s_waitcnt vmcnt(0) & lgkmcnt(0)
如果是 TgSplit 執行模式,則省略 lgkmcnt(0)。
如果是 OpenCL,則省略 lgkmcnt(0)。
必須在後續的 buffer_inv 之前發生。
確保 atomicrmw 在使快取失效之前已完成。
buffer_inv sc1=1
必須在任何後續的全域/通用載入/載入原子/atomicrmw 之前發生。
確保後續的載入不會看到過時的全域資料。
atomicrmw
取得
system
通用
flat_atomic sc1=1
s_waitcnt vmcnt(0) & lgkmcnt(0)
如果是 TgSplit 執行模式,則省略 lgkmcnt(0)。
如果是 OpenCL,則省略 lgkmcnt(0)。
必須在後續的 buffer_inv 之前發生。
確保 atomicrmw 在使快取失效之前已完成。
buffer_inv sc0=1 sc1=1
必須在任何後續的全域/通用載入/載入原子/atomicrmw 之前發生。
確保後續的載入不會看到過時的 MTYPE NC 全域資料。 由於記憶體探測,MTYPE RW 和 CC 記憶體永遠不會過時。
柵欄
取得
singlethread
wavefront
none
none
柵欄
取得
workgroup
none
s_waitcnt lgkm/vmcnt(0)
如果不是 TgSplit 執行模式,則使用 lgkmcnt(0),如果是 TgSplit 執行模式,則使用 vmcnt(0)。
如果是 OpenCL 且位址空間不是通用的,則省略 lgkmcnt(0)。
如果是 OpenCL 且位址空間是區域的,則省略 vmcnt(0)。
有關特定位址空間柵欄的更多詳細資訊,請參閱 柵欄和位址空間。
s_waitcnt vmcnt(0) 必須在任何先前的全域/通用載入原子/ atomicrmw 之後發生,其同步作用域相等或更寬,且記憶體排序強於無序(這稱為柵欄配對原子)。
s_waitcnt lgkmcnt(0) 必須在任何先前的區域/通用載入原子/atomicrmw 之後發生,其同步作用域相等或更寬,且記憶體排序強於無序(這稱為柵欄配對原子)。
必須在後續的 buffer_inv 以及任何後續的全域/通用載入/載入原子/儲存/儲存原子/atomicrmw 之前發生。
確保任何後續的全域資料讀取都不會早於柵欄配對原子讀取的值。
buffer_inv sc0=1
如果不是 TgSplit 執行模式,則省略。
確保後續的載入不會看到過時的資料。
柵欄
取得
agent
none
s_waitcnt lgkmcnt(0) & vmcnt(0)
如果是 TgSplit 執行模式,則省略 lgkmcnt(0)。
如果是 OpenCL 且位址空間不是通用的,則省略 lgkmcnt(0)。
有關特定位址空間柵欄的更多詳細資訊,請參閱 柵欄和位址空間。
可以拆分為單獨的 s_waitcnt vmcnt(0) 和 s_waitcnt lgkmcnt(0),以允許根據以下規則獨立移動它們。
s_waitcnt vmcnt(0) 必須在任何先前的全域/通用載入原子/atomicrmw 之後發生,其同步作用域相等或更寬,且記憶體排序強於無序(這稱為柵欄配對原子)。
s_waitcnt lgkmcnt(0) 必須在任何先前的區域/通用載入原子/atomicrmw 之後發生,其同步作用域相等或更寬,且記憶體排序強於無序(這稱為柵欄配對原子)。
必須在後續的 buffer_inv 之前發生。
確保柵欄配對原子在使快取失效之前已完成。 因此,任何後續讀取的位置都不得早於柵欄配對原子讀取的值。
buffer_inv sc1=1
必須在任何後續的全域/通用載入/載入原子/儲存/儲存原子/atomicrmw 之前發生。
確保後續的載入不會看到過時的全域資料。
柵欄
取得
system
none
s_waitcnt lgkmcnt(0) & vmcnt(0)
如果是 TgSplit 執行模式,則省略 lgkmcnt(0)。
如果是 OpenCL 且位址空間不是通用的,則省略 lgkmcnt(0)。
有關特定位址空間柵欄的更多詳細資訊,請參閱 柵欄和位址空間。
可以拆分為單獨的 s_waitcnt vmcnt(0) 和 s_waitcnt lgkmcnt(0),以允許根據以下規則獨立移動它們。
s_waitcnt vmcnt(0) 必須在任何先前的全域/通用載入原子/atomicrmw 之後發生,其同步作用域相等或更寬,且記憶體排序強於無序(這稱為柵欄配對原子)。
s_waitcnt lgkmcnt(0) 必須在任何先前的區域/通用載入原子/atomicrmw 之後發生,其同步作用域相等或更寬,且記憶體排序強於無序(這稱為柵欄配對原子)。
必須在後續的 buffer_inv 之前發生。
確保柵欄配對原子在使快取失效之前已完成。 因此,任何後續讀取的位置都不得早於柵欄配對原子讀取的值。
buffer_inv sc0=1 sc1=1
必須在任何後續的全域/通用載入/載入原子/儲存/儲存原子/atomicrmw 之前發生。
確保後續的載入不會看到過時的全域資料。
釋放原子
儲存原子
釋放
singlethread
wavefront
global
通用
- GFX942
buffer/global/flat_store
儲存原子
釋放
singlethread
wavefront
區域
如果是 TgSplit 執行模式,則無法使用區域位址空間。
ds_store
儲存原子
釋放
workgroup
global
通用
s_waitcnt lgkm/vmcnt(0)
如果不是 TgSplit 執行模式,則使用 lgkmcnt(0),如果是 TgSplit 執行模式,則使用 vmcnt(0)。
如果是 OpenCL,則省略 lgkmcnt(0)。
s_waitcnt vmcnt(0) 必須在任何先前的全域/通用載入/儲存/ 載入原子/儲存原子/ atomicrmw 之後發生。
s_waitcnt lgkmcnt(0) 必須在任何先前的區域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
必須在後續的儲存之前發生。
確保所有記憶體操作在執行正在釋放的儲存之前已完成。
- GFX942
buffer/global/flat_store sc0=1
儲存原子
釋放
workgroup
區域
如果是 TgSplit 執行模式,則無法使用區域位址空間。
ds_store
儲存原子
釋放
agent
global
通用
buffer_wbl2 sc1=1
必須在後續的 s_waitcnt 之前發生。
執行 L2 寫回以確保先前的全域/通用儲存/atomicrmw 在代理程式作用域中可見。
s_waitcnt lgkmcnt(0) & vmcnt(0)
如果是 TgSplit 執行模式,則省略 lgkmcnt(0)。
如果是 OpenCL 且位址空間不是通用的,則省略 lgkmcnt(0)。
可以拆分為單獨的 s_waitcnt vmcnt(0) 和 s_waitcnt lgkmcnt(0),以允許根據以下規則獨立移動它們。
s_waitcnt vmcnt(0) 必須在任何先前的全域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
s_waitcnt lgkmcnt(0) 必須在任何先前的區域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
必須在後續的儲存之前發生。
確保對記憶體的所有記憶體操作在執行正在釋放的儲存之前已完成。
- GFX942
buffer/global/flat_store sc1=1
儲存原子
釋放
system
global
通用
buffer_wbl2 sc0=1 sc1=1
必須在後續的 s_waitcnt 之前發生。
執行 L2 寫回以確保先前的全域/通用儲存/atomicrmw 在系統作用域中可見。
s_waitcnt lgkmcnt(0) & vmcnt(0)
如果是 TgSplit 執行模式,則省略 lgkmcnt(0)。
如果是 OpenCL 且位址空間不是通用的,則省略 lgkmcnt(0)。
可以拆分為單獨的 s_waitcnt vmcnt(0) 和 s_waitcnt lgkmcnt(0),以允許根據以下規則獨立移動它們。
s_waitcnt vmcnt(0) 必須在任何先前的全域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
s_waitcnt lgkmcnt(0) 必須在任何先前的區域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
必須在後續的儲存之前發生。
確保對記憶體的所有記憶體操作和 L2 寫回在執行正在釋放的儲存之前已完成。
buffer/global/flat_store sc0=1 sc1=1
atomicrmw
釋放
singlethread
wavefront
global
通用
buffer/global/flat_atomic
atomicrmw
釋放
singlethread
wavefront
區域
如果是 TgSplit 執行模式,則無法使用區域位址空間。
ds_atomic
atomicrmw
釋放
workgroup
global
通用
s_waitcnt lgkm/vmcnt(0)
如果不是 TgSplit 執行模式,則使用 lgkmcnt(0),如果是 TgSplit 執行模式,則使用 vmcnt(0)。
如果是 OpenCL,則省略 lgkmcnt(0)。
s_waitcnt vmcnt(0) 必須在任何先前的全域/通用載入/儲存/ 載入原子/儲存原子/ atomicrmw 之後發生。
s_waitcnt lgkmcnt(0) 必須在任何先前的區域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
必須在後續的 atomicrmw 之前發生。
確保所有記憶體操作在執行正在釋放的 atomicrmw 之前已完成。
buffer/global/flat_atomic sc0=1
atomicrmw
釋放
workgroup
區域
如果是 TgSplit 執行模式,則無法使用區域位址空間。
ds_atomic
atomicrmw
釋放
agent
global
通用
buffer_wbl2 sc1=1
必須在後續的 s_waitcnt 之前發生。
執行 L2 寫回以確保先前的全域/通用儲存/atomicrmw 在代理程式作用域中可見。
s_waitcnt lgkmcnt(0) & vmcnt(0)
如果是 TgSplit 執行模式,則省略 lgkmcnt(0)。
如果是 OpenCL,則省略 lgkmcnt(0)。
可以拆分為單獨的 s_waitcnt vmcnt(0) 和 s_waitcnt lgkmcnt(0),以允許根據以下規則獨立移動它們。
s_waitcnt vmcnt(0) 必須在任何先前的全域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
s_waitcnt lgkmcnt(0) 必須在任何先前的區域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
必須在後續的 atomicrmw 之前發生。
確保對全域和區域的所有記憶體操作在執行正在釋放的 atomicrmw 之前已完成。
buffer/global/flat_atomic sc1=1
atomicrmw
釋放
system
global
通用
buffer_wbl2 sc0=1 sc1=1
必須在後續的 s_waitcnt 之前發生。
執行 L2 寫回以確保先前的全域/通用儲存/atomicrmw 在系統作用域中可見。
s_waitcnt lgkmcnt(0) & vmcnt(0)
如果是 TgSplit 執行模式,則省略 lgkmcnt(0)。
如果是 OpenCL,則省略 lgkmcnt(0)。
可以拆分為單獨的 s_waitcnt vmcnt(0) 和 s_waitcnt lgkmcnt(0),以允許根據以下規則獨立移動它們。
s_waitcnt vmcnt(0) 必須在任何先前的全域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
s_waitcnt lgkmcnt(0) 必須在任何先前的區域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
必須在後續的 atomicrmw 之前發生。
確保對記憶體的所有記憶體操作和 L2 寫回在執行正在釋放的儲存之前已完成。
buffer/global/flat_atomic sc0=1 sc1=1
柵欄
釋放
singlethread
wavefront
none
none
柵欄
釋放
workgroup
none
s_waitcnt lgkm/vmcnt(0)
如果不是 TgSplit 執行模式,則使用 lgkmcnt(0),如果是 TgSplit 執行模式,則使用 vmcnt(0)。
如果是 OpenCL 且位址空間不是通用的,則省略 lgkmcnt(0)。
如果是 OpenCL 且位址空間是區域的,則省略 vmcnt(0)。
有關特定位址空間柵欄的更多詳細資訊,請參閱 柵欄和位址空間。
s_waitcnt vmcnt(0) 必須在任何先前的全域/通用載入/儲存/ 載入原子/儲存原子/ atomicrmw 之後發生。
s_waitcnt lgkmcnt(0) 必須在任何先前的區域/通用載入/載入原子/儲存/儲存原子/atomicrmw 之後發生。
必須在任何後續的儲存原子/atomicrmw 之前發生,其同步作用域相等或更寬,且記憶體排序強於無序(這稱為柵欄配對原子)。
確保所有記憶體操作在執行後續的柵欄配對原子之前已完成。
柵欄
釋放
agent
none
buffer_wbl2 sc1=1
如果是 OpenCL 且位址空間是區域的,則省略。
必須在後續的 s_waitcnt 之前發生。
執行 L2 寫回以確保先前的全域/通用儲存/atomicrmw 在代理程式作用域中可見。
s_waitcnt lgkmcnt(0) & vmcnt(0)
如果是 TgSplit 執行模式,則省略 lgkmcnt(0)。
如果是 OpenCL 且位址空間不是通用的,則省略 lgkmcnt(0)。
如果是 OpenCL 且位址空間是區域的,則省略 vmcnt(0)。
有關特定位址空間柵欄的更多詳細資訊,請參閱 柵欄和位址空間。
可以拆分為單獨的 s_waitcnt vmcnt(0) 和 s_waitcnt lgkmcnt(0),以允許根據以下規則獨立移動它們。
s_waitcnt vmcnt(0) 必須在任何先前的全域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
s_waitcnt lgkmcnt(0) 必須在任何先前的區域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
必須在任何後續的儲存原子/atomicrmw 之前發生,其同步作用域相等或更寬,且記憶體排序強於無序(這稱為柵欄配對原子)。
確保所有記憶體操作在執行後續的柵欄配對原子之前已完成。
柵欄
釋放
system
none
buffer_wbl2 sc0=1 sc1=1
必須在後續的 s_waitcnt 之前發生。
執行 L2 寫回以確保先前的全域/通用儲存/atomicrmw 在系統作用域中可見。
s_waitcnt lgkmcnt(0) & vmcnt(0)
如果是 TgSplit 執行模式,則省略 lgkmcnt(0)。
如果是 OpenCL 且位址空間不是通用的,則省略 lgkmcnt(0)。
如果是 OpenCL 且位址空間是區域的,則省略 vmcnt(0)。
有關特定位址空間柵欄的更多詳細資訊,請參閱 柵欄和位址空間。
可以拆分為單獨的 s_waitcnt vmcnt(0) 和 s_waitcnt lgkmcnt(0),以允許根據以下規則獨立移動它們。
s_waitcnt vmcnt(0) 必須在任何先前的全域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
s_waitcnt lgkmcnt(0) 必須在任何先前的區域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
必須在任何後續的儲存原子/atomicrmw 之前發生,其同步作用域相等或更寬,且記憶體排序強於無序(這稱為柵欄配對原子)。
確保所有記憶體操作在執行後續的柵欄配對原子之前已完成。
取得-釋放原子
atomicrmw
取得_釋放
singlethread
wavefront
global
通用
buffer/global/flat_atomic
atomicrmw
取得_釋放
singlethread
wavefront
區域
如果是 TgSplit 執行模式,則無法使用區域位址空間。
ds_atomic
atomicrmw
取得_釋放
workgroup
global
s_waitcnt lgkm/vmcnt(0)
如果不是 TgSplit 執行模式,則使用 lgkmcnt(0),如果是 TgSplit 執行模式,則使用 vmcnt(0)。
如果是 OpenCL,則省略 lgkmcnt(0)。
必須在任何先前的區域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
s_waitcnt vmcnt(0) 必須在任何先前的全域/通用載入/儲存/ 載入原子/儲存原子/ atomicrmw 之後發生。
s_waitcnt lgkmcnt(0) 必須在任何先前的區域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
必須在後續的 atomicrmw 之前發生。
確保所有記憶體操作在執行正在釋放的 atomicrmw 之前已完成。
buffer/global_atomic
s_waitcnt vmcnt(0)
如果不是 TgSplit 執行模式,則省略。
必須在後續的 buffer_inv 之前發生。
確保任何後續的全域資料讀取都不會早於正在取得的 atomicrmw 值。
buffer_inv sc0=1
如果不是 TgSplit 執行模式,則省略。
確保後續的載入不會看到過時的資料。
atomicrmw
取得_釋放
workgroup
區域
如果是 TgSplit 執行模式,則無法使用區域位址空間。
ds_atomic
s_waitcnt lgkmcnt(0)
如果是 OpenCL,則省略。
必須在任何後續的全域/通用載入/載入原子/儲存/儲存原子/atomicrmw 之前發生。
確保任何後續的全域資料讀取都不會早於正在取得的區域載入原子值。
atomicrmw
取得_釋放
workgroup
通用
s_waitcnt lgkm/vmcnt(0)
如果不是 TgSplit 執行模式,則使用 lgkmcnt(0),如果是 TgSplit 執行模式,則使用 vmcnt(0)。
如果是 OpenCL,則省略 lgkmcnt(0)。
s_waitcnt vmcnt(0) 必須在任何先前的全域/通用載入/儲存/ 載入原子/儲存原子/ atomicrmw 之後發生。
s_waitcnt lgkmcnt(0) 必須在任何先前的區域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
必須在後續的 atomicrmw 之前發生。
確保所有記憶體操作在執行正在釋放的 atomicrmw 之前已完成。
flat_atomic
s_waitcnt lgkmcnt(0) & vmcnt(0)
如果不是 TgSplit 執行模式,則省略 vmcnt(0)。
如果是 OpenCL,則省略 lgkmcnt(0)。
必須在後續的 buffer_inv 以及任何後續的全域/通用載入/載入原子/儲存/儲存原子/atomicrmw 之前發生。
確保任何後續的全域資料讀取都不會早於正在取得的區域載入原子值。
buffer_inv sc0=1
如果不是 TgSplit 執行模式,則省略。
確保後續的載入不會看到過時的資料。
atomicrmw
取得_釋放
agent
global
buffer_wbl2 sc1=1
必須在後續的 s_waitcnt 之前發生。
執行 L2 寫回以確保先前的全域/通用儲存/atomicrmw 在代理程式作用域中可見。
s_waitcnt lgkmcnt(0) & vmcnt(0)
如果是 TgSplit 執行模式,則省略 lgkmcnt(0)。
如果是 OpenCL,則省略 lgkmcnt(0)。
可以拆分為單獨的 s_waitcnt vmcnt(0) 和 s_waitcnt lgkmcnt(0),以允許根據以下規則獨立移動它們。
s_waitcnt vmcnt(0) 必須在任何先前的全域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
s_waitcnt lgkmcnt(0) 必須在任何先前的區域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
必須在後續的 atomicrmw 之前發生。
確保對全域的所有記憶體操作在執行正在釋放的 atomicrmw 之前已完成。
buffer/global_atomic
s_waitcnt vmcnt(0)
必須在後續的 buffer_inv 之前發生。
確保 atomicrmw 在使快取失效之前已完成。
buffer_inv sc1=1
必須在任何後續的全域/通用載入/載入原子/atomicrmw 之前發生。
確保後續的載入不會看到過時的全域資料。
atomicrmw
取得_釋放
system
global
buffer_wbl2 sc0=1 sc1=1
必須在後續的 s_waitcnt 之前發生。
執行 L2 寫回以確保先前的全域/通用儲存/atomicrmw 在系統作用域中可見。
s_waitcnt lgkmcnt(0) & vmcnt(0)
如果是 TgSplit 執行模式,則省略 lgkmcnt(0)。
如果是 OpenCL,則省略 lgkmcnt(0)。
可以拆分為單獨的 s_waitcnt vmcnt(0) 和 s_waitcnt lgkmcnt(0),以允許根據以下規則獨立移動它們。
s_waitcnt vmcnt(0) 必須在任何先前的全域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
s_waitcnt lgkmcnt(0) 必須在任何先前的區域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
必須在後續的 atomicrmw 之前發生。
確保對全域的所有記憶體操作和 L2 寫回在執行正在釋放的 atomicrmw 之前已完成。
buffer/global_atomic sc1=1
s_waitcnt vmcnt(0)
必須在後續的 buffer_inv 之前發生。
確保 atomicrmw 在使快取失效之前已完成。
buffer_inv sc0=1 sc1=1
必須在任何後續的全域/通用載入/載入原子/atomicrmw 之前發生。
確保後續的載入不會看到過時的 MTYPE NC 全域資料。 由於記憶體探測,MTYPE RW 和 CC 記憶體永遠不會過時。
atomicrmw
取得_釋放
agent
通用
buffer_wbl2 sc1=1
必須在後續的 s_waitcnt 之前發生。
執行 L2 寫回以確保先前的全域/通用儲存/atomicrmw 在代理程式作用域中可見。
s_waitcnt lgkmcnt(0) & vmcnt(0)
如果是 TgSplit 執行模式,則省略 lgkmcnt(0)。
如果是 OpenCL,則省略 lgkmcnt(0)。
可以拆分為單獨的 s_waitcnt vmcnt(0) 和 s_waitcnt lgkmcnt(0),以允許根據以下規則獨立移動它們。
s_waitcnt vmcnt(0) 必須在任何先前的全域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
s_waitcnt lgkmcnt(0) 必須在任何先前的區域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
必須在後續的 atomicrmw 之前發生。
確保對全域的所有記憶體操作在執行正在釋放的 atomicrmw 之前已完成。
flat_atomic
s_waitcnt vmcnt(0) & lgkmcnt(0)
如果是 TgSplit 執行模式,則省略 lgkmcnt(0)。
如果是 OpenCL,則省略 lgkmcnt(0)。
必須在後續的 buffer_inv 之前發生。
確保 atomicrmw 在使快取失效之前已完成。
buffer_inv sc1=1
必須在任何後續的全域/通用載入/載入原子/atomicrmw 之前發生。
確保後續的載入不會看到過時的全域資料。
atomicrmw
取得_釋放
system
通用
buffer_wbl2 sc0=1 sc1=1
必須在後續的 s_waitcnt 之前發生。
執行 L2 寫回以確保先前的全域/通用儲存/atomicrmw 在系統作用域中可見。
s_waitcnt lgkmcnt(0) & vmcnt(0)
如果是 TgSplit 執行模式,則省略 lgkmcnt(0)。
如果是 OpenCL,則省略 lgkmcnt(0)。
可以拆分為單獨的 s_waitcnt vmcnt(0) 和 s_waitcnt lgkmcnt(0),以允許根據以下規則獨立移動它們。
s_waitcnt vmcnt(0) 必須在任何先前的全域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
s_waitcnt lgkmcnt(0) 必須在任何先前的區域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
必須在後續的 atomicrmw 之前發生。
確保對全域的所有記憶體操作和 L2 寫回在執行正在釋放的 atomicrmw 之前已完成。
flat_atomic sc1=1
s_waitcnt vmcnt(0) & lgkmcnt(0)
如果是 TgSplit 執行模式,則省略 lgkmcnt(0)。
如果是 OpenCL,則省略 lgkmcnt(0)。
必須在後續的 buffer_inv 之前發生。
確保 atomicrmw 在使快取失效之前已完成。
buffer_inv sc0=1 sc1=1
必須在任何後續的全域/通用載入/載入原子/atomicrmw 之前發生。
確保後續的載入不會看到過時的 MTYPE NC 全域資料。 由於記憶體探測,MTYPE RW 和 CC 記憶體永遠不會過時。
柵欄
取得_釋放
singlethread
wavefront
none
none
柵欄
取得_釋放
workgroup
none
s_waitcnt lgkm/vmcnt(0)
如果不是 TgSplit 執行模式,則使用 lgkmcnt(0),如果是 TgSplit 執行模式,則使用 vmcnt(0)。
如果是 OpenCL 且位址空間不是通用的,則省略 lgkmcnt(0)。
如果是 OpenCL 且位址空間是區域的,則省略 vmcnt(0)。
但是,由於 LLVM 目前在柵欄上沒有位址空間,因此需要保守地始終產生(請參閱先前柵欄的註解)。
s_waitcnt vmcnt(0) 必須在任何先前的全域/通用載入/儲存/ 載入原子/儲存原子/ atomicrmw 之後發生。
s_waitcnt lgkmcnt(0) 必須在任何先前的區域/通用載入/載入原子/儲存/儲存原子/atomicrmw 之後發生。
必須在任何後續的全域/通用載入/載入原子/儲存/儲存原子/atomicrmw 之前發生。
確保所有記憶體操作在執行任何後續的全域記憶體操作之前已完成。
確保先前的區域/通用載入原子/atomicrmw,其同步作用域相等或更寬,且記憶體排序強於無序(這稱為取得柵欄配對原子),在後續的全域記憶體操作之前已完成。 這滿足取得的要求。
確保所有先前的記憶體操作在後續的區域/通用儲存原子/atomicrmw 之前已完成,其同步作用域相等或更寬,且記憶體排序強於無序(這稱為釋放柵欄配對原子)。 這滿足釋放的要求。
必須在後續的 buffer_inv 之前發生。
確保取得柵欄配對原子在使快取失效之前已完成。 因此,任何後續讀取的位置都不得早於取得柵欄配對原子讀取的值。
buffer_inv sc0=1
如果不是 TgSplit 執行模式,則省略。
確保後續的載入不會看到過時的資料。
柵欄
取得_釋放
agent
none
buffer_wbl2 sc1=1
如果是 OpenCL 且位址空間是區域的,則省略。
必須在後續的 s_waitcnt 之前發生。
執行 L2 寫回以確保先前的全域/通用儲存/atomicrmw 在代理程式作用域中可見。
s_waitcnt lgkmcnt(0) & vmcnt(0)
如果是 TgSplit 執行模式,則省略 lgkmcnt(0)。
如果是 OpenCL 且位址空間不是通用的,則省略 lgkmcnt(0)。
有關特定位址空間柵欄的更多詳細資訊,請參閱 柵欄和位址空間。
可以拆分為單獨的 s_waitcnt vmcnt(0) 和 s_waitcnt lgkmcnt(0),以允許根據以下規則獨立移動它們。
s_waitcnt vmcnt(0) 必須在任何先前的全域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
s_waitcnt lgkmcnt(0) 必須在任何先前的區域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
必須在後續的 buffer_inv 之前發生。
確保先前的全域/區域/通用載入原子/atomicrmw,其同步作用域相等或更寬,且記憶體排序強於無序(這稱為取得柵欄配對原子),在使快取失效之前已完成。 這滿足取得的要求。
確保所有先前的記憶體操作在後續的全域/區域/通用儲存原子/atomicrmw 之前已完成,其同步作用域相等或更寬,且記憶體排序強於無序(這稱為釋放柵欄配對原子)。 這滿足釋放的要求。
buffer_inv sc1=1
必須在任何後續的全域/通用載入/載入原子/儲存/儲存原子/atomicrmw 之前發生。
確保後續的載入不會看到過時的全域資料。 這滿足取得的要求。
柵欄
取得_釋放
system
none
buffer_wbl2 sc0=1 sc1=1
如果是 OpenCL 且位址空間是區域的,則省略。
必須在後續的 s_waitcnt 之前發生。
執行 L2 寫回以確保先前的全域/通用儲存/atomicrmw 在系統作用域中可見。
s_waitcnt lgkmcnt(0) & vmcnt(0)
如果是 TgSplit 執行模式,則省略 lgkmcnt(0)。
如果是 OpenCL 且位址空間不是通用的,則省略 lgkmcnt(0)。
有關特定位址空間柵欄的更多詳細資訊,請參閱 柵欄和位址空間。
可以拆分為單獨的 s_waitcnt vmcnt(0) 和 s_waitcnt lgkmcnt(0),以允許根據以下規則獨立移動它們。
s_waitcnt vmcnt(0) 必須在任何先前的全域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
s_waitcnt lgkmcnt(0) 必須在任何先前的區域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
必須在後續的 buffer_inv 之前發生。
確保先前的全域/區域/通用載入原子/atomicrmw,其同步作用域相等或更寬,且記憶體排序強於無序(這稱為取得柵欄配對原子),在使快取失效之前已完成。 這滿足取得的要求。
確保所有先前的記憶體操作在後續的全域/區域/通用儲存原子/atomicrmw 之前已完成,其同步作用域相等或更寬,且記憶體排序強於無序(這稱為釋放柵欄配對原子)。 這滿足釋放的要求。
buffer_inv sc0=1 sc1=1
必須在任何後續的全域/通用載入/載入原子/儲存/儲存原子/atomicrmw 之前發生。
確保後續的載入不會看到過時的 MTYPE NC 全域資料。 由於記憶體探測,MTYPE RW 和 CC 記憶體永遠不會過時。
循序一致性原子
載入原子
seq_cst
singlethread
wavefront
global
區域
通用
與對應的載入原子取得相同,但即使對於 OpenCL 也必須產生所有指令。
載入原子
seq_cst
workgroup
global
通用
s_waitcnt lgkm/vmcnt(0)
如果不是 TgSplit 執行模式,則使用 lgkmcnt(0),如果是 TgSplit 執行模式,則使用 vmcnt(0)。
s_waitcnt lgkmcnt(0) 必須在先前的區域/通用載入原子/儲存原子/atomicrmw 之後發生,其記憶體排序為 seq_cst,且同步作用域相等或更寬。(請注意,seq_cst 柵欄有自己的 s_waitcnt lgkmcnt(0),因此不需要考慮。)
s_waitcnt vmcnt(0) 必須在先前的全域/通用載入原子/儲存原子/atomicrmw 之後發生,其記憶體排序為 seq_cst,且同步作用域相等或更寬。(請注意,seq_cst 柵欄有自己的 s_waitcnt vmcnt(0),因此不需要考慮。)
確保任何先前的循序一致性全域/區域記憶體指令在執行此循序一致性指令之前已完成。 這可以防止重新排序 seq_cst 儲存,然後是 seq_cst 載入。(請注意,seq_cst 比取得/釋放更強,因為釋放的 s_waitcnt 會阻止重新排序載入取得,然後是儲存釋放,但是沒有任何東西阻止儲存釋放,然後是載入取得以無序完成。 s_waitcnt 可以放在 seq_store 之後或 seq_load 之前。 我們選擇載入以使 s_waitcnt 盡可能晚,以便儲存可能已經完成。)
後續指令與對應的載入原子取得相同,但即使對於 OpenCL 也必須產生所有指令。
載入原子
seq_cst
workgroup
區域
如果是 TgSplit 執行模式,則無法使用區域位址空間。
與對應的載入原子取得相同,但即使對於 OpenCL 也必須產生所有指令。
載入原子
seq_cst
agent
system
global
通用
s_waitcnt lgkmcnt(0) & vmcnt(0)
如果是 TgSplit 執行模式,則省略 lgkmcnt(0)。
可以拆分為單獨的 s_waitcnt vmcnt(0) 和 s_waitcnt lgkmcnt(0),以允許根據以下規則獨立移動它們。
s_waitcnt lgkmcnt(0) 必須在先前的全域/通用載入原子/儲存原子/atomicrmw 之後發生,其記憶體排序為 seq_cst,且同步作用域相等或更寬。(請注意,seq_cst 柵欄有自己的 s_waitcnt lgkmcnt(0),因此不需要考慮。)
s_waitcnt vmcnt(0) 必須在先前的全域/通用載入原子/儲存原子/atomicrmw 之後發生,其記憶體排序為 seq_cst,且同步作用域相等或更寬。(請注意,seq_cst 柵欄有自己的 s_waitcnt vmcnt(0),因此不需要考慮。)
確保任何先前的循序一致性全域記憶體指令在執行此循序一致性指令之前已完成。 這可以防止重新排序 seq_cst 儲存,然後是 seq_cst 載入。(請注意,seq_cst 比取得/釋放更強,因為釋放的 s_waitcnt 會阻止重新排序載入取得,然後是儲存釋放,但是沒有任何東西阻止儲存釋放,然後是載入取得以無序完成。 s_waitcnt 可以放在 seq_store 之後或 seq_load 之前。 我們選擇載入以使 s_waitcnt 盡可能晚,以便儲存可能已經完成。)
後續指令與對應的載入原子取得相同,但即使對於 OpenCL 也必須產生所有指令。
儲存原子
seq_cst
singlethread
wavefront
workgroup
agent
system
global
區域
通用
與對應的儲存原子釋放相同,但即使對於 OpenCL 也必須產生所有指令。
atomicrmw
seq_cst
singlethread
wavefront
workgroup
agent
system
global
區域
通用
與對應的 atomicrmw acq_rel 相同,但即使對於 OpenCL 也必須產生所有指令。
柵欄
seq_cst
singlethread
wavefront
workgroup
agent
system
none
與對應的柵欄 acq_rel 相同,但即使對於 OpenCL 也必須產生所有指令。
記憶體模型 GFX10-GFX11¶
對於 GFX10-GFX11
每個代理程式有多個著色器陣列 (SA)。
每個 SA 都有多個工作群組處理器 (WGP)。
每個 WGP 都有多個運算單元 (CU)。
每個 CU 有多個執行波前的 SIMD。
單個工作群組的波前在同一個 WGP 中執行。 在 CU 波前執行模式下,波前可能由同一個 CU 中不同的 SIMD 執行。 在 WGP 波前執行模式下,波前可能由同一個 WGP 中不同 CU 中的不同 SIMD 執行。
每個 WGP 都有一個單個 LDS 記憶體,由在其上執行的工作群組的波前共享。
WGP 的所有 LDS 操作都作為全波前寬操作以全域順序執行,並且不涉及快取。 完成情況以執行順序報告給波前。
LDS 記憶體具有由 WGP 的 SIMD 共享的多個請求佇列。 因此,同一工作群組的不同波前執行的 LDS 操作可以相對於彼此重新排序,這可能會導致相對於同一工作群組中其他波前的 LDS 操作重新排序向量記憶體操作的可見性。 需要
s_waitcnt lgkmcnt(0)
以確保工作群組的波前之間 LDS 操作和向量記憶體操作之間的同步,但不包括同一波前執行的操作之間。向量記憶體操作作為波前寬操作執行。 載入/儲存/取樣操作的完成情況以該波前執行的其他載入/儲存/取樣操作的執行順序報告給波前。
向量記憶體操作存取向量 L0 快取。 每個 CU 有一個單個 L0 快取。 CU 的每個 SIMD 存取同一個 L0 快取。 因此,單個波前的通道之間的一致性不需要特殊操作。 但是,在同一工作群組中執行的波前之間的一致性需要
buffer_gl0_inv
,因為它們可能在存取不同 L0 的不同 CU 的 SIMD 上執行。 在不同工作群組中執行的波前之間的一致性也需要buffer_gl0_inv
,因為它們可能在不同的 WGP 上執行。純量記憶體操作存取 WGP 上所有波前共享的純量 L0 快取。 純量快取和向量 L0 快取不一致。 但是,純量操作以受限制的方式使用,因此不會影響記憶體模型。 請參閱 記憶體空間。
向量和純量記憶體 L0 快取使用由同一個 SA 上的所有 WGP 共享的 L1 快取。 因此,單個工作群組的波前之間的一致性不需要特殊操作。 但是,在不同工作群組中執行的波前之間的一致性需要
buffer_gl1_inv
,因為它們可能在存取不同 L1 的不同 SA 上執行。L1 快取具有獨立的象限,用於服務不相交的虛擬位址範圍。
每個 L0 快取都有一個單獨的每個 L1 象限的請求佇列。 因此,由不同波前執行的向量和純量記憶體操作,無論是在同一個還是不同的工作群組中執行(可能在存取不同 L0 的不同 CU 上執行),都可以相對於彼此重新排序。 需要
s_waitcnt vmcnt(0) & vscnt(0)
以確保不同波前的向量記憶體操作之間的同步。 它確保先前的向量記憶體操作在執行後續的向量記憶體或 LDS 操作之前已完成,因此可以用於滿足取得、釋放和循序一致性的要求。L1 快取使用由同一個代理程式上的所有 SA 共享的 L2 快取。
L2 快取具有獨立通道,用於服務不相交的虛擬位址範圍。
單個 SA 的每個 L1 象限存取不同的 L2 通道。 每個 L1 象限都有一個單獨的每個 L2 通道的請求佇列。 因此,由不同工作群組(可能在不同 SA 上執行)中的波前執行的向量和純量記憶體操作可以相對於彼此重新排序。 需要
s_waitcnt vmcnt(0) & vscnt(0)
以確保不同 SA 的向量記憶體操作之間的同步。 它確保先前的向量記憶體操作在執行後續的向量記憶體之前已完成,因此可以用於滿足取得、釋放和循序一致性的要求。L2 快取可以與某些目標上的其他代理程式保持一致性,或者可以設定虛擬位址範圍來繞過它,以確保系統一致性。
在 GFX10.3 和 GFX11 上,GPU 記憶體存在附加的最後一層 (MALL) 快取。 MALL 快取與 GPU 記憶體完全一致,並且對系統一致性沒有影響。 所有代理程式(GPU 和 CPU)都透過 MALL 快取存取 GPU 記憶體。
純量記憶體操作僅用於存取在核心調度執行期間證明不會變更的記憶體。 這包括常數位址空間和程式作用域 const
變數的全域位址空間。 因此,核心機器碼不必維護純量快取,以確保它與向量快取一致。 純量快取和向量快取在核心調度之間由 CP 使失效,因為常數位址空間資料可能在核心調度執行之間變更。 請參閱 記憶體空間。
一個例外情況是,如果純量寫入用於溢出 SGPR 暫存器。 在這種情況下,AMDGPU 後端確保用於溢出的記憶體位置永遠不會同時被向量記憶體操作存取。 如果使用純量寫入,則在 s_endpgm
之前和函數返回之前插入 s_dcache_wb
,因為這些位置可能被未來使用相同暫存區的波前或在相同位址建立框架的函數呼叫用於向量記憶體指令。 不需要 s_dcache_inv
,因為所有純量寫入在同一個執行緒中都是先寫後讀。
對於核心參數後備記憶體
CP 在每次核心調度開始時使 L0 和 L1 快取失效。
在 dGPU 上,核心參數後備記憶體以 MTYPE UC(非快取)存取,以避免需要使 L2 快取失效。
在 APU 上,核心參數後備記憶體以 MTYPE CC(快取一致性)存取,因此 L2 快取將與 CPU 和其他代理程式保持一致性。
暫存後備記憶體(用於私有位址空間)以 MTYPE NC(非一致性)存取。 由於私有位址空間僅由單個執行緒存取,並且始終是先寫後讀,因此永遠不需要使 L0 或 L1 快取中的這些條目失效。
波前以原生模式執行,並以順序報告載入和取樣指令。 在此模式下,vmcnt 按順序報告載入、帶傳回的原子和取樣指令的完成情況,而 vscnt 按順序報告不帶傳回的儲存和原子的完成情況。 請參閱 GFX6-GFX12 的 compute_pgm_rsrc1 中的 MEM_ORDERED
欄位。
波前可以在 WGP 或 CU 波前執行模式下執行
在 WGP 波前執行模式下,工作群組的波前在 WGP 的兩個 CU 的 SIMD 上執行。 因此,工作群組同步需要顯式管理每個 CU L0 快取。 此外,工作群組作用域中對 L1 的存取需要顯式排序,因為來自不同 CU 的存取是無序的。
在 CU wavefront 執行模式中,work-group 的 wavefronts 會在 WGP 單一 CU 的 SIMD 上執行。因此,work-group 的所有全域記憶體存取都會存取相同的 L0,進而確保 L1 存取是有序的,因此不需要針對 work-group 同步進行快取的明確管理。
請參閱 WGP_MODE
欄位,位於 適用於 GFX6-GFX12 的 compute_pgm_rsrc1 和 目標功能。
用於實作 GFX10-GFX11 記憶體模型的程式碼序列定義於表 AMDHSA 記憶體模型程式碼序列 GFX10-GFX11 中。
表 82 AMDHSA 記憶體模型程式碼序列 GFX10-GFX11¶ LLVM 指令
LLVM 記憶體排序
LLVM 記憶體同步作用域
AMDGPU 位址空間
AMDGPU 機器碼 GFX10-GFX11
非原子
載入
none
none
global
通用
private
constant
!volatile & !nontemporal
buffer/global/flat_load
!volatile & nontemporal
buffer/global/flat_load slc=1 dlc=1
若為 GFX10,則省略 dlc=1。
volatile
buffer/global/flat_load glc=1 dlc=1
s_waitcnt vmcnt(0)
必須在任何後續的揮發性全域/通用載入/儲存之前發生。
確保對不同位址的揮發性操作不會被硬體重新排序。
載入
none
none
區域
ds_load
儲存
none
none
global
通用
private
constant
!volatile & !nontemporal
buffer/global/flat_store
!volatile & nontemporal
buffer/global/flat_store glc=1 slc=1 dlc=1
若為 GFX10,則省略 dlc=1。
volatile
buffer/global/flat_store dlc=1
若為 GFX10,則省略 dlc=1。
s_waitcnt vscnt(0)
必須在任何後續的揮發性全域/通用載入/儲存之前發生。
確保對不同位址的揮發性操作不會被硬體重新排序。
儲存
none
none
區域
ds_store
無序原子
載入原子
無序
任何
任何
與非原子相同.
儲存原子
無序
任何
任何
與非原子相同.
atomicrmw
無序
任何
任何
與單調原子相同.
單調原子
載入原子
單調
singlethread
wavefront
global
通用
buffer/global/flat_load
載入原子
單調
workgroup
global
通用
buffer/global/flat_load glc=1
若為 CU wavefront 執行模式,則省略 glc=1。
載入原子
單調
singlethread
wavefront
workgroup
區域
ds_load
載入原子
單調
agent
system
global
通用
buffer/global/flat_load glc=1 dlc=1
若為 GFX11,則省略 dlc=1。
儲存原子
單調
singlethread
wavefront
workgroup
agent
system
global
通用
buffer/global/flat_store
儲存原子
單調
singlethread
wavefront
workgroup
區域
ds_store
atomicrmw
單調
singlethread
wavefront
workgroup
agent
system
global
通用
buffer/global/flat_atomic
atomicrmw
單調
singlethread
wavefront
workgroup
區域
ds_atomic
取得原子
載入原子
取得
singlethread
wavefront
global
區域
通用
buffer/global/ds/flat_load
載入原子
取得
workgroup
global
buffer/global_load glc=1
若為 CU wavefront 執行模式,則省略 glc=1。
s_waitcnt vmcnt(0)
若為 CU wavefront 執行模式,則省略。
必須在後續的 buffer_gl0_inv 之前,以及任何後續的 global/generic load/load atomic/store/store atomic/atomicrmw 之前發生。
buffer_gl0_inv
若為 CU wavefront 執行模式,則省略。
確保後續的載入不會看到過時的資料。
載入原子
取得
workgroup
區域
ds_load
s_waitcnt lgkmcnt(0)
如果是 OpenCL,則省略。
必須在後續的 buffer_gl0_inv 之前,以及任何後續的 global/generic load/load atomic/store/store atomic/atomicrmw 之前發生。
確保任何後續的全域資料讀取都不會早於正在取得的區域載入原子值。
buffer_gl0_inv
若為 CU wavefront 執行模式,則省略。
如果是 OpenCL,則省略。
確保後續的載入不會看到過時的資料。
載入原子
取得
workgroup
通用
flat_load glc=1
若為 CU wavefront 執行模式,則省略 glc=1。
s_waitcnt lgkmcnt(0) & vmcnt(0)
若為 CU wavefront 執行模式,則省略 vmcnt(0)。
如果是 OpenCL,則省略 lgkmcnt(0)。
必須在後續的 buffer_gl0_inv 以及任何後續的 global/generic load/load atomic/store/store atomic/atomicrmw 之前發生。
確保任何後續的全域資料讀取都不會早於正在取得的區域載入原子值。
buffer_gl0_inv
若為 CU wavefront 執行模式,則省略。
確保後續的載入不會看到過時的資料。
載入原子
取得
agent
system
global
buffer/global_load glc=1 dlc=1
若為 GFX11,則省略 dlc=1。
s_waitcnt vmcnt(0)
必須在後續的 buffer_gl*_inv 之前發生。
確保在使快取失效之前,載入已完成。
buffer_gl1_inv; buffer_gl0_inv
必須在任何後續的全域/通用載入/載入原子/atomicrmw 之前發生。
確保後續的載入不會看到過時的全域資料。
載入原子
取得
agent
system
通用
flat_load glc=1 dlc=1
若為 GFX11,則省略 dlc=1。
s_waitcnt vmcnt(0) & lgkmcnt(0)
如果是 OpenCL,則省略 lgkmcnt(0)。
必須在後續的 buffer_gl*_invl 之前發生。
確保 flat_load 在使快取失效之前已完成。
buffer_gl1_inv; buffer_gl0_inv
必須在任何後續的全域/通用載入/載入原子/atomicrmw 之前發生。
確保後續的載入不會看到過時的全域資料。
atomicrmw
取得
singlethread
wavefront
global
區域
通用
buffer/global/ds/flat_atomic
atomicrmw
取得
workgroup
global
buffer/global_atomic
s_waitcnt vm/vscnt(0)
若為 CU wavefront 執行模式,則省略。
若為帶有返回值的 atomic,則使用 vmcnt(0),若為不帶返回值的 atomic,則使用 vscnt(0)。
必須在後續的 buffer_gl0_inv 之前,以及任何後續的 global/generic load/load atomic/store/store atomic/atomicrmw 之前發生。
buffer_gl0_inv
若為 CU wavefront 執行模式,則省略。
確保後續的載入不會看到過時的資料。
atomicrmw
取得
workgroup
區域
ds_atomic
s_waitcnt lgkmcnt(0)
如果是 OpenCL,則省略。
必須在後續的 buffer_gl0_inv 之前發生。
確保任何後續的全域資料讀取都不會早於正在取得的區域 atomicrmw 值。
buffer_gl0_inv
若為 OpenCL,則省略。
確保後續的載入不會看到過時的資料。
atomicrmw
取得
workgroup
通用
flat_atomic
s_waitcnt lgkmcnt(0) & vm/vscnt(0)
若為 CU wavefront 執行模式,則省略 vm/vscnt(0)。
如果是 OpenCL,則省略 lgkmcnt(0)。
若為帶有返回值的 atomic,則使用 vmcnt(0),若為不帶返回值的 atomic,則使用 vscnt(0)。
必須在後續的 buffer_gl0_inv 之前發生。
確保任何後續的全域資料讀取都不會早於正在取得的區域 atomicrmw 值。
buffer_gl0_inv
若為 CU wavefront 執行模式,則省略。
確保後續的載入不會看到過時的資料。
atomicrmw
取得
agent
system
global
buffer/global_atomic
s_waitcnt vm/vscnt(0)
若為帶有返回值的 atomic,則使用 vmcnt(0),若為不帶返回值的 atomic,則使用 vscnt(0)。
必須在後續的 buffer_gl*_inv 之前發生。
確保 atomicrmw 在使快取失效之前已完成。
buffer_gl1_inv; buffer_gl0_inv
必須在任何後續的全域/通用載入/載入原子/atomicrmw 之前發生。
確保後續的載入不會看到過時的全域資料。
atomicrmw
取得
agent
system
通用
flat_atomic
s_waitcnt vm/vscnt(0) & lgkmcnt(0)
如果是 OpenCL,則省略 lgkmcnt(0)。
若為帶有返回值的 atomic,則使用 vmcnt(0),若為不帶返回值的 atomic,則使用 vscnt(0)。
必須在後續的 buffer_gl*_inv 之前發生。
確保 atomicrmw 在使快取失效之前已完成。
buffer_gl1_inv; buffer_gl0_inv
必須在任何後續的全域/通用載入/載入原子/atomicrmw 之前發生。
確保後續的載入不會看到過時的全域資料。
柵欄
取得
singlethread
wavefront
none
none
柵欄
取得
workgroup
none
s_waitcnt lgkmcnt(0) & vmcnt(0) & vscnt(0)
若為 CU wavefront 執行模式,則省略 vmcnt(0) 和 vscnt(0)。
如果是 OpenCL 且位址空間不是通用的,則省略 lgkmcnt(0)。
若為 OpenCL 且位址空間為 local,則省略 vmcnt(0) 和 vscnt(0)。
有關特定位址空間柵欄的更多詳細資訊,請參閱 柵欄和位址空間。
可以拆分為個別的 s_waitcnt vmcnt(0)、s_waitcnt vscnt(0) 和 s_waitcnt lgkmcnt(0),以允許根據以下規則獨立移動它們。
s_waitcnt vmcnt(0) 必須在任何先前的 global/generic load atomic/ atomicrmw-with-return-value 之後發生,其同步範圍相等或更寬,且記憶體排序強於 unordered(這稱為 fence-paired-atomic)。
s_waitcnt vscnt(0) 必須在任何先前的 global/generic atomicrmw-no-return-value 之後發生,其同步範圍相等或更寬,且記憶體排序強於 unordered(這稱為 fence-paired-atomic)。
s_waitcnt lgkmcnt(0) 必須在任何先前的區域/通用載入原子/atomicrmw 之後發生,其同步作用域相等或更寬,且記憶體排序強於無序(這稱為柵欄配對原子)。
必須在後續的 buffer_gl0_inv 之前發生。
確保柵欄配對原子在使快取失效之前已完成。 因此,任何後續讀取的位置都不得早於柵欄配對原子讀取的值。
buffer_gl0_inv
若為 CU wavefront 執行模式,則省略。
確保後續的載入不會看到過時的資料。
柵欄
取得
agent
system
none
s_waitcnt lgkmcnt(0) & vmcnt(0) & vscnt(0)
如果是 OpenCL 且位址空間不是通用的,則省略 lgkmcnt(0)。
若為 OpenCL 且位址空間為 local,則省略 vmcnt(0) 和 vscnt(0)。
有關特定位址空間柵欄的更多詳細資訊,請參閱 柵欄和位址空間。
可以拆分為個別的 s_waitcnt vmcnt(0)、s_waitcnt vscnt(0) 和 s_waitcnt lgkmcnt(0),以允許根據以下規則獨立移動它們。
s_waitcnt vmcnt(0) 必須在任何先前的 global/generic load atomic/ atomicrmw-with-return-value 之後發生,其同步範圍相等或更寬,且記憶體排序強於 unordered(這稱為 fence-paired-atomic)。
s_waitcnt vscnt(0) 必須在任何先前的 global/generic atomicrmw-no-return-value 之後發生,其同步範圍相等或更寬,且記憶體排序強於 unordered(這稱為 fence-paired-atomic)。
s_waitcnt lgkmcnt(0) 必須在任何先前的區域/通用載入原子/atomicrmw 之後發生,其同步作用域相等或更寬,且記憶體排序強於無序(這稱為柵欄配對原子)。
必須在後續的 buffer_gl*_inv 之前發生。
確保 fence-paired atomic 在使快取失效之前已完成。因此,任何後續讀取的位置都不得早於 fence-paired-atomic 讀取的值。
buffer_gl1_inv; buffer_gl0_inv
必須在任何後續的全域/通用載入/載入原子/儲存/儲存原子/atomicrmw 之前發生。
確保後續的載入不會看到過時的全域資料。
釋放原子
儲存原子
釋放
singlethread
wavefront
global
區域
通用
buffer/global/ds/flat_store
儲存原子
釋放
workgroup
global
通用
s_waitcnt lgkmcnt(0) & vmcnt(0) & vscnt(0)
若為 CU wavefront 執行模式,則省略 vmcnt(0) 和 vscnt(0)。
如果是 OpenCL,則省略 lgkmcnt(0)。
可以拆分為個別的 s_waitcnt vmcnt(0)、s_waitcnt vscnt(0) 和 s_waitcnt lgkmcnt(0),以允許根據以下規則獨立移動它們。
s_waitcnt vmcnt(0) 必須在任何先前的 global/generic load/load atomic/ atomicrmw-with-return-value 之後發生。
s_waitcnt vscnt(0) 必須在任何先前的 global/generic store/store atomic/ atomicrmw-no-return-value 之後發生。
s_waitcnt lgkmcnt(0) 必須在任何先前的區域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
必須在後續的儲存之前發生。
確保所有記憶體操作在執行正在釋放的儲存之前已完成。
buffer/global/flat_store
儲存原子
釋放
workgroup
區域
s_waitcnt vmcnt(0) & vscnt(0)
若為 CU wavefront 執行模式,則省略。
如果是 OpenCL,則省略。
可以拆分為個別的 s_waitcnt vmcnt(0) 和 s_waitcnt vscnt(0),以允許根據以下規則獨立移動它們。
s_waitcnt vmcnt(0) 必須在任何先前的 global/generic load/load atomic/ atomicrmw-with-return-value 之後發生。
s_waitcnt vscnt(0) 必須在任何先前的 global/generic store/store atomic/ atomicrmw-no-return-value 之後發生。
必須在後續的儲存之前發生。
確保所有全域記憶體操作在執行正在釋放的 store 之前已完成。
ds_store
儲存原子
釋放
agent
system
global
通用
s_waitcnt lgkmcnt(0) & vmcnt(0) & vscnt(0)
如果是 OpenCL 且位址空間不是通用的,則省略 lgkmcnt(0)。
可以拆分為個別的 s_waitcnt vmcnt(0)、s_waitcnt vscnt(0) 和 s_waitcnt lgkmcnt(0),以允許根據以下規則獨立移動它們。
s_waitcnt vmcnt(0) 必須在任何先前的 global/generic load/load atomic/ atomicrmw-with-return-value 之後發生。
s_waitcnt vscnt(0) 必須在任何先前的 global/generic store/store atomic/ atomicrmw-no-return-value 之後發生。
s_waitcnt lgkmcnt(0) 必須在任何先前的區域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
必須在後續的儲存之前發生。
確保所有記憶體操作在執行正在釋放的儲存之前已完成。
buffer/global/flat_store
atomicrmw
釋放
singlethread
wavefront
global
區域
通用
buffer/global/ds/flat_atomic
atomicrmw
釋放
workgroup
global
通用
s_waitcnt lgkmcnt(0) & vmcnt(0) & vscnt(0)
若為 CU wavefront 執行模式,則省略 vmcnt(0) 和 vscnt(0)。
如果是 OpenCL,則省略 lgkmcnt(0)。
可以拆分為個別的 s_waitcnt vmcnt(0)、s_waitcnt vscnt(0) 和 s_waitcnt lgkmcnt(0),以允許根據以下規則獨立移動它們。
s_waitcnt vmcnt(0) 必須在任何先前的 global/generic load/load atomic/ atomicrmw-with-return-value 之後發生。
s_waitcnt vscnt(0) 必須在任何先前的 global/generic store/store atomic/ atomicrmw-no-return-value 之後發生。
s_waitcnt lgkmcnt(0) 必須在任何先前的區域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
必須在後續的 atomicrmw 之前發生。
確保所有記憶體操作在執行正在釋放的 atomicrmw 之前已完成。
buffer/global/flat_atomic
atomicrmw
釋放
workgroup
區域
s_waitcnt vmcnt(0) & vscnt(0)
若為 CU wavefront 執行模式,則省略。
如果是 OpenCL,則省略。
可以拆分為個別的 s_waitcnt vmcnt(0) 和 s_waitcnt vscnt(0),以允許根據以下規則獨立移動它們。
s_waitcnt vmcnt(0) 必須在任何先前的 global/generic load/load atomic/ atomicrmw-with-return-value 之後發生。
s_waitcnt vscnt(0) 必須在任何先前的 global/generic store/store atomic/ atomicrmw-no-return-value 之後發生。
必須在後續的儲存之前發生。
確保所有全域記憶體操作在執行正在釋放的 store 之前已完成。
ds_atomic
atomicrmw
釋放
agent
system
global
通用
- s_waitcnt lgkmcnt(0) &
vmcnt(0) & vscnt(0)
如果是 OpenCL,則省略 lgkmcnt(0)。
可以拆分為個別的 s_waitcnt vmcnt(0)、s_waitcnt vscnt(0) 和 s_waitcnt lgkmcnt(0),以允許根據以下規則獨立移動它們。
s_waitcnt vmcnt(0) 必須在任何先前的 global/generic load/load atomic/ atomicrmw-with-return-value 之後發生。
s_waitcnt vscnt(0) 必須在任何先前的 global/generic store/store atomic/ atomicrmw-no-return-value 之後發生。
s_waitcnt lgkmcnt(0) 必須在任何先前的區域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
必須在後續的 atomicrmw 之前發生。
確保對全域和區域的所有記憶體操作在執行正在釋放的 atomicrmw 之前已完成。
buffer/global/flat_atomic
柵欄
釋放
singlethread
wavefront
none
none
柵欄
釋放
workgroup
none
s_waitcnt lgkmcnt(0) & vmcnt(0) & vscnt(0)
若為 CU wavefront 執行模式,則省略 vmcnt(0) 和 vscnt(0)。
如果是 OpenCL 且位址空間不是通用的,則省略 lgkmcnt(0)。
若為 OpenCL 且位址空間為 local,則省略 vmcnt(0) 和 vscnt(0)。
有關特定位址空間柵欄的更多詳細資訊,請參閱 柵欄和位址空間。
可以拆分為個別的 s_waitcnt vmcnt(0)、s_waitcnt vscnt(0) 和 s_waitcnt lgkmcnt(0),以允許根據以下規則獨立移動它們。
s_waitcnt vmcnt(0) 必須在任何先前的 global/generic load/load atomic/ atomicrmw-with-return-value 之後發生。
s_waitcnt vscnt(0) 必須在任何先前的 global/generic store/store atomic/ atomicrmw-no-return-value 之後發生。
s_waitcnt lgkmcnt(0) 必須在任何先前的 local/generic load/store/load atomic/store atomic/ atomicrmw 之後發生。
必須在任何後續的儲存原子/atomicrmw 之前發生,其同步作用域相等或更寬,且記憶體排序強於無序(這稱為柵欄配對原子)。
確保所有記憶體操作在執行後續的柵欄配對原子之前已完成。
柵欄
釋放
agent
system
none
s_waitcnt lgkmcnt(0) & vmcnt(0) & vscnt(0)
如果是 OpenCL 且位址空間不是通用的,則省略 lgkmcnt(0)。
若為 OpenCL 且位址空間為 local,則省略 vmcnt(0) 和 vscnt(0)。
有關特定位址空間柵欄的更多詳細資訊,請參閱 柵欄和位址空間。
可以拆分為個別的 s_waitcnt vmcnt(0)、s_waitcnt vscnt(0) 和 s_waitcnt lgkmcnt(0),以允許根據以下規則獨立移動它們。
s_waitcnt vmcnt(0) 必須在任何先前的 global/generic load/load atomic/ atomicrmw-with-return-value 之後發生。
s_waitcnt vscnt(0) 必須在任何先前的 global/generic store/store atomic/ atomicrmw-no-return-value 之後發生。
s_waitcnt lgkmcnt(0) 必須在任何先前的區域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
必須在任何後續的儲存原子/atomicrmw 之前發生,其同步作用域相等或更寬,且記憶體排序強於無序(這稱為柵欄配對原子)。
確保所有記憶體操作在執行後續的柵欄配對原子之前已完成。
取得-釋放原子
atomicrmw
取得_釋放
singlethread
wavefront
global
區域
通用
buffer/global/ds/flat_atomic
atomicrmw
取得_釋放
workgroup
global
s_waitcnt lgkmcnt(0) & vmcnt(0) & vscnt(0)
若為 CU wavefront 執行模式,則省略 vmcnt(0) 和 vscnt(0)。
如果是 OpenCL,則省略 lgkmcnt(0)。
必須在任何先前的區域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
可以拆分為個別的 s_waitcnt vmcnt(0)、s_waitcnt vscnt(0) 和 s_waitcnt lgkmcnt(0),以允許根據以下規則獨立移動它們。
s_waitcnt vmcnt(0) 必須在任何先前的 global/generic load/load atomic/ atomicrmw-with-return-value 之後發生。
s_waitcnt vscnt(0) 必須在任何先前的 global/generic store/store atomic/ atomicrmw-no-return-value 之後發生。
s_waitcnt lgkmcnt(0) 必須在任何先前的區域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
必須在後續的 atomicrmw 之前發生。
確保所有記憶體操作在執行正在釋放的 atomicrmw 之前已完成。
buffer/global_atomic
s_waitcnt vm/vscnt(0)
若為 CU wavefront 執行模式,則省略。
若為帶有返回值的 atomic,則使用 vmcnt(0),若為不帶返回值的 atomic,則使用 vscnt(0)。
必須在後續的 buffer_gl0_inv 之前發生。
確保任何後續的全域資料讀取都不會早於正在取得的 atomicrmw 值。
buffer_gl0_inv
若為 CU wavefront 執行模式,則省略。
確保後續的載入不會看到過時的資料。
atomicrmw
取得_釋放
workgroup
區域
s_waitcnt vmcnt(0) & vscnt(0)
若為 CU wavefront 執行模式,則省略。
如果是 OpenCL,則省略。
可以拆分為個別的 s_waitcnt vmcnt(0) 和 s_waitcnt vscnt(0),以允許根據以下規則獨立移動它們。
s_waitcnt vmcnt(0) 必須在任何先前的 global/generic load/load atomic/ atomicrmw-with-return-value 之後發生。
s_waitcnt vscnt(0) 必須在任何先前的 global/generic store/store atomic/ atomicrmw-no-return-value 之後發生。
必須在後續的儲存之前發生。
確保所有全域記憶體操作在執行正在釋放的 store 之前已完成。
ds_atomic
s_waitcnt lgkmcnt(0)
如果是 OpenCL,則省略。
必須在後續的 buffer_gl0_inv 之前發生。
確保任何後續的全域資料讀取都不會早於正在取得的區域載入原子值。
buffer_gl0_inv
若為 CU wavefront 執行模式,則省略。
若為 OpenCL,則省略。
確保後續的載入不會看到過時的資料。
atomicrmw
取得_釋放
workgroup
通用
s_waitcnt lgkmcnt(0) & vmcnt(0) & vscnt(0)
若為 CU wavefront 執行模式,則省略 vmcnt(0) 和 vscnt(0)。
如果是 OpenCL,則省略 lgkmcnt(0)。
可以拆分為個別的 s_waitcnt vmcnt(0)、s_waitcnt vscnt(0) 和 s_waitcnt lgkmcnt(0),以允許根據以下規則獨立移動它們。
s_waitcnt vmcnt(0) 必須在任何先前的 global/generic load/load atomic/ atomicrmw-with-return-value 之後發生。
s_waitcnt vscnt(0) 必須在任何先前的 global/generic store/store atomic/ atomicrmw-no-return-value 之後發生。
s_waitcnt lgkmcnt(0) 必須在任何先前的區域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
必須在後續的 atomicrmw 之前發生。
確保所有記憶體操作在執行正在釋放的 atomicrmw 之前已完成。
flat_atomic
s_waitcnt lgkmcnt(0) & vmcnt(0) & vscnt(0)
若為 CU wavefront 執行模式,則省略 vmcnt(0) 和 vscnt(0)。
如果是 OpenCL,則省略 lgkmcnt(0)。
必須在後續的 buffer_gl0_inv 之前發生。
確保任何後續讀取的全域資料都不早於正在取得的 load atomic 值。
buffer_gl0_inv
若為 CU wavefront 執行模式,則省略。
確保後續的載入不會看到過時的資料。
atomicrmw
取得_釋放
agent
system
global
s_waitcnt lgkmcnt(0) & vmcnt(0) & vscnt(0)
如果是 OpenCL,則省略 lgkmcnt(0)。
可以拆分為個別的 s_waitcnt vmcnt(0)、s_waitcnt vscnt(0) 和 s_waitcnt lgkmcnt(0),以允許根據以下規則獨立移動它們。
s_waitcnt vmcnt(0) 必須在任何先前的 global/generic load/load atomic/ atomicrmw-with-return-value 之後發生。
s_waitcnt vscnt(0) 必須在任何先前的 global/generic store/store atomic/ atomicrmw-no-return-value 之後發生。
s_waitcnt lgkmcnt(0) 必須在任何先前的區域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
必須在後續的 atomicrmw 之前發生。
確保對全域的所有記憶體操作在執行正在釋放的 atomicrmw 之前已完成。
buffer/global_atomic
s_waitcnt vm/vscnt(0)
若為帶有返回值的 atomic,則使用 vmcnt(0),若為不帶返回值的 atomic,則使用 vscnt(0)。
必須在後續的 buffer_gl*_inv 之前發生。
確保 atomicrmw 在使快取失效之前已完成。
buffer_gl1_inv; buffer_gl0_inv
必須在任何後續的全域/通用載入/載入原子/atomicrmw 之前發生。
確保後續的載入不會看到過時的全域資料。
atomicrmw
取得_釋放
agent
system
通用
s_waitcnt lgkmcnt(0) & vmcnt(0) & vscnt(0)
如果是 OpenCL,則省略 lgkmcnt(0)。
可以拆分為個別的 s_waitcnt vmcnt(0)、s_waitcnt vscnt(0) 和 s_waitcnt lgkmcnt(0),以允許根據以下規則獨立移動它們。
s_waitcnt vmcnt(0) 必須在任何先前的 global/generic load/load atomic atomicrmw-with-return-value 之後發生。
s_waitcnt vscnt(0) 必須在任何先前的 global/generic store/store atomic/ atomicrmw-no-return-value 之後發生。
s_waitcnt lgkmcnt(0) 必須在任何先前的區域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
必須在後續的 atomicrmw 之前發生。
確保所有記憶體操作在執行正在釋放的 atomicrmw 之前已完成。
flat_atomic
s_waitcnt vm/vscnt(0) & lgkmcnt(0)
如果是 OpenCL,則省略 lgkmcnt(0)。
若為帶有返回值的 atomic,則使用 vmcnt(0),若為不帶返回值的 atomic,則使用 vscnt(0)。
必須在後續的 buffer_gl*_inv 之前發生。
確保 atomicrmw 在使快取失效之前已完成。
buffer_gl1_inv; buffer_gl0_inv
必須在任何後續的全域/通用載入/載入原子/atomicrmw 之前發生。
確保後續的載入不會看到過時的全域資料。
柵欄
取得_釋放
singlethread
wavefront
none
none
柵欄
取得_釋放
workgroup
none
s_waitcnt lgkmcnt(0) & vmcnt(0) & vscnt(0)
若為 CU wavefront 執行模式,則省略 vmcnt(0) 和 vscnt(0)。
如果是 OpenCL 且位址空間不是通用的,則省略 lgkmcnt(0)。
若為 OpenCL 且位址空間為 local,則省略 vmcnt(0) 和 vscnt(0)。
但是,由於 LLVM 目前在柵欄上沒有位址空間,因此需要保守地始終產生(請參閱先前柵欄的註解)。
可以拆分為個別的 s_waitcnt vmcnt(0)、s_waitcnt vscnt(0) 和 s_waitcnt lgkmcnt(0),以允許根據以下規則獨立移動它們。
s_waitcnt vmcnt(0) 必須在任何先前的 global/generic load/load atomic/ atomicrmw-with-return-value 之後發生。
s_waitcnt vscnt(0) 必須在任何先前的 global/generic store/store atomic/ atomicrmw-no-return-value 之後發生。
s_waitcnt lgkmcnt(0) 必須在任何先前的 local/generic load/store/load atomic/store atomic/ atomicrmw 之後發生。
必須在任何後續的全域/通用載入/載入原子/儲存/儲存原子/atomicrmw 之前發生。
確保所有記憶體操作在執行任何後續的全域記憶體操作之前已完成。
確保先前的區域/通用載入原子/atomicrmw,其同步作用域相等或更寬,且記憶體排序強於無序(這稱為取得柵欄配對原子),在後續的全域記憶體操作之前已完成。 這滿足取得的要求。
確保所有先前的記憶體操作在後續的區域/通用儲存原子/atomicrmw 之前已完成,其同步作用域相等或更寬,且記憶體排序強於無序(這稱為釋放柵欄配對原子)。 這滿足釋放的要求。
必須在後續的 buffer_gl0_inv 之前發生。
確保取得柵欄配對原子在使快取失效之前已完成。 因此,任何後續讀取的位置都不得早於取得柵欄配對原子讀取的值。
buffer_gl0_inv
若為 CU wavefront 執行模式,則省略。
確保後續的載入不會看到過時的資料。
柵欄
取得_釋放
agent
system
none
s_waitcnt lgkmcnt(0) & vmcnt(0) & vscnt(0)
如果是 OpenCL 且位址空間不是通用的,則省略 lgkmcnt(0)。
若為 OpenCL 且位址空間為 local,則省略 vmcnt(0) 和 vscnt(0)。
有關特定位址空間柵欄的更多詳細資訊,請參閱 柵欄和位址空間。
可以拆分為個別的 s_waitcnt vmcnt(0)、s_waitcnt vscnt(0) 和 s_waitcnt lgkmcnt(0),以允許根據以下規則獨立移動它們。
s_waitcnt vmcnt(0) 必須在任何先前的 global/generic load/load atomic/ atomicrmw-with-return-value 之後發生。
s_waitcnt vscnt(0) 必須在任何先前的 global/generic store/store atomic/ atomicrmw-no-return-value 之後發生。
s_waitcnt lgkmcnt(0) 必須在任何先前的區域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
必須在後續的 buffer_gl*_inv 之前發生。
確保先前的 global/local/generic load atomic/atomicrmw (其同步範圍相等或更寬,且記憶體排序強於 unordered,這稱為 acquire-fence-paired-atomic) 在使快取失效之前已完成。這滿足 acquire 的要求。
確保所有先前的記憶體操作在後續的全域/區域/通用儲存原子/atomicrmw 之前已完成,其同步作用域相等或更寬,且記憶體排序強於無序(這稱為釋放柵欄配對原子)。 這滿足釋放的要求。
buffer_gl1_inv; buffer_gl0_inv
必須在任何後續的全域/通用載入/載入原子/儲存/儲存原子/atomicrmw 之前發生。
確保後續的載入不會看到過時的全域資料。 這滿足取得的要求。
循序一致性原子
載入原子
seq_cst
singlethread
wavefront
global
區域
通用
與對應的載入原子取得相同,但即使對於 OpenCL 也必須產生所有指令。
載入原子
seq_cst
workgroup
global
通用
s_waitcnt lgkmcnt(0) & vmcnt(0) & vscnt(0)
若為 CU wavefront 執行模式,則省略 vmcnt(0) 和 vscnt(0)。
可以拆分為個別的 s_waitcnt vmcnt(0)、s_waitcnt vscnt(0) 和 s_waitcnt lgkmcnt(0),以允許根據以下規則獨立移動它們。
s_waitcnt lgkmcnt(0) 必須在先前的區域/通用載入原子/儲存原子/atomicrmw 之後發生,其記憶體排序為 seq_cst,且同步作用域相等或更寬。(請注意,seq_cst 柵欄有自己的 s_waitcnt lgkmcnt(0),因此不需要考慮。)
s_waitcnt vmcnt(0) 必須在先前的 global/generic load atomic/ atomicrmw-with-return-value 之後發生,其記憶體排序為 seq_cst 且同步範圍相等或更寬。(請注意,seq_cst fences 有自己的 s_waitcnt vmcnt(0),因此無需考慮。)
s_waitcnt vscnt(0) 必須在先前的 global/generic store atomic/ atomicrmw-no-return-value 之後發生,其記憶體排序為 seq_cst 且同步範圍相等或更寬。(請注意,seq_cst fences 有自己的 s_waitcnt vscnt(0),因此無需考慮。)
確保任何先前的循序一致性全域/區域記憶體指令在執行此循序一致性指令之前已完成。 這可以防止重新排序 seq_cst 儲存,然後是 seq_cst 載入。(請注意,seq_cst 比取得/釋放更強,因為釋放的 s_waitcnt 會阻止重新排序載入取得,然後是儲存釋放,但是沒有任何東西阻止儲存釋放,然後是載入取得以無序完成。 s_waitcnt 可以放在 seq_store 之後或 seq_load 之前。 我們選擇載入以使 s_waitcnt 盡可能晚,以便儲存可能已經完成。)
後續指令與對應的載入原子取得相同,但即使對於 OpenCL 也必須產生所有指令。
載入原子
seq_cst
workgroup
區域
s_waitcnt vmcnt(0) & vscnt(0)
若為 CU wavefront 執行模式,則省略。
可以拆分為個別的 s_waitcnt vmcnt(0) 和 s_waitcnt vscnt(0),以允許根據以下規則獨立移動它們。
s_waitcnt vmcnt(0) 必須在先前的 global/generic load atomic/ atomicrmw-with-return-value 之後發生,其記憶體排序為 seq_cst 且同步範圍相等或更寬。(請注意,seq_cst fences 有自己的 s_waitcnt vmcnt(0),因此無需考慮。)
s_waitcnt vscnt(0) 必須在先前的 global/generic store atomic/ atomicrmw-no-return-value 之後發生,其記憶體排序為 seq_cst 且同步範圍相等或更寬。(請注意,seq_cst fences 有自己的 s_waitcnt vscnt(0),因此無需考慮。)
確保任何先前的循序一致性全域記憶體指令在執行此循序一致性指令之前已完成。 這可以防止重新排序 seq_cst 儲存,然後是 seq_cst 載入。(請注意,seq_cst 比取得/釋放更強,因為釋放的 s_waitcnt 會阻止重新排序載入取得,然後是儲存釋放,但是沒有任何東西阻止儲存釋放,然後是載入取得以無序完成。 s_waitcnt 可以放在 seq_store 之後或 seq_load 之前。 我們選擇載入以使 s_waitcnt 盡可能晚,以便儲存可能已經完成。)
後續指令與對應的載入原子取得相同,但即使對於 OpenCL 也必須產生所有指令。
載入原子
seq_cst
agent
system
global
通用
s_waitcnt lgkmcnt(0) & vmcnt(0) & vscnt(0)
可以拆分為個別的 s_waitcnt vmcnt(0)、s_waitcnt vscnt(0) 和 s_waitcnt lgkmcnt(0),以允許根據以下規則獨立移動它們。
s_waitcnt lgkmcnt(0) 必須在先前的 local load atomic/store atomic/atomicrmw 之後發生,其記憶體排序為 seq_cst 且同步範圍相等或更寬。(請注意,seq_cst fences 有自己的 s_waitcnt lgkmcnt(0),因此無需考慮。)
s_waitcnt vmcnt(0) 必須在先前的 global/generic load atomic/ atomicrmw-with-return-value 之後發生,其記憶體排序為 seq_cst 且同步範圍相等或更寬。(請注意,seq_cst fences 有自己的 s_waitcnt vmcnt(0),因此無需考慮。)
s_waitcnt vscnt(0) 必須在先前的 global/generic store atomic/ atomicrmw-no-return-value 之後發生,其記憶體排序為 seq_cst 且同步範圍相等或更寬。(請注意,seq_cst fences 有自己的 s_waitcnt vscnt(0),因此無需考慮。)
確保任何先前的循序一致性全域記憶體指令在執行此循序一致性指令之前已完成。 這可以防止重新排序 seq_cst 儲存,然後是 seq_cst 載入。(請注意,seq_cst 比取得/釋放更強,因為釋放的 s_waitcnt 會阻止重新排序載入取得,然後是儲存釋放,但是沒有任何東西阻止儲存釋放,然後是載入取得以無序完成。 s_waitcnt 可以放在 seq_store 之後或 seq_load 之前。 我們選擇載入以使 s_waitcnt 盡可能晚,以便儲存可能已經完成。)
後續指令與對應的載入原子取得相同,但即使對於 OpenCL 也必須產生所有指令。
儲存原子
seq_cst
singlethread
wavefront
workgroup
agent
system
global
區域
通用
與對應的儲存原子釋放相同,但即使對於 OpenCL 也必須產生所有指令。
atomicrmw
seq_cst
singlethread
wavefront
workgroup
agent
system
global
區域
通用
與對應的 atomicrmw acq_rel 相同,但即使對於 OpenCL 也必須產生所有指令。
柵欄
seq_cst
singlethread
wavefront
workgroup
agent
system
none
與對應的柵欄 acq_rel 相同,但即使對於 OpenCL 也必須產生所有指令。
記憶體模型 GFX12¶
適用於 GFX12
每個代理程式有多個著色器陣列 (SA)。
每個 SA 都有多個工作群組處理器 (WGP)。
每個 WGP 都有多個運算單元 (CU)。
每個 CU 有多個執行波前的 SIMD。
單一 work-group 的 wavefronts 在相同的 WGP 中執行。
在 CU wavefront 執行模式中,wavefronts 可能由相同 CU 中不同的 SIMD 執行。
在 WGP wavefront 執行模式中,wavefronts 可能由相同 WGP 中不同 CU 中不同的 SIMD 執行。
每個 WGP 都有一個單個 LDS 記憶體,由在其上執行的工作群組的波前共享。
WGP 的所有 LDS 操作都作為全波前寬操作以全域順序執行,並且不涉及快取。 完成情況以執行順序報告給波前。
LDS 記憶體具有多個請求佇列,由 WGP 的 SIMD 共用。因此,work-group 不同 wavefronts 執行的 LDS 操作可能會彼此重新排序,這可能會導致向量記憶體操作的可見性相對於相同 work-group 中其他 wavefronts 的 LDS 操作重新排序。需要
s_wait_dscnt 0x0
來確保 work-group wavefronts 之間 LDS 操作和向量記憶體操作之間的同步,但同一 wavefront 執行的操作之間則不需要。向量記憶體操作作為 wavefront 寬度操作執行。向量記憶體操作分為不同類型。向量記憶體操作的完成會在類型內依序報告給 wavefront,但類型之間可能會亂序。向量記憶體操作的類型(及其相關的
s_wait
指令)為LDS:
s_wait_dscnt
載入(global、scratch、flat、buffer 和 image):
s_wait_loadcnt
儲存(global、scratch、flat、buffer 和 image):
s_wait_storecnt
取樣和 Gather4:
s_wait_samplecnt
BVH:
s_wait_bvhcnt
向量和純量記憶體指令包含一個
SCOPE
欄位,其值對應於每個快取層級。SCOPE
決定快取是否可以在本機完成操作,或者是否需要將操作轉發到下一個快取層級。SCOPE
值為SCOPE_CU
:運算單元(注意:不受 CU/WGP 模式影響)SCOPE_SE
:Shader EngineSCOPE_DEV
:裝置/代理SCOPE_SYS
:系統
當具有給定
SCOPE
的記憶體操作到達具有較小SCOPE
值的快取時,它會被轉發到下一級快取。當具有給定
SCOPE
的記憶體操作到達具有大於或等於其自身SCOPE
值的快取時,操作可以繼續進行讀取可以命中快取
寫入可以在此快取中發生,並且交易會從此快取層級確認。
RMW 操作可以在本機完成。
global_inv
、global_wb
和global_wbinv
指令用於使快取失效、寫回和寫回+失效快取。受影響的快取由指令的SCOPE:
控制。global_inv
使 scope 嚴格小於指令的快取失效。失效請求不能與擱置或即將到來的記憶體操作重新排序。global_wb
是一個寫回操作,它還額外確保在較低 scope 層級完成的先前記憶體操作已到達global_wb
的SCOPE:
。對於 gfx120x 中的
SCOPE_SYS
以外的 scope,可以省略global_wb
。
向量記憶體操作存取向量 L0 快取。每個 CU 有一個單一 L0 快取。CU 的每個 SIMD 存取相同的 L0 快取。因此,單一 wavefront 的 lanes 之間的同調性不需要特殊操作。為了實現相同 work-group 中執行的 wavefronts 之間的同調性
在 CU wavefront 執行模式中,不需要特殊操作。
在 WGP wavefront 執行模式中,需要
global_inv scope:SCOPE_SE
,因為 wavefronts 可能在存取不同 L0 的不同 CU 的 SIMD 上執行。
純量記憶體操作存取 WGP 上所有波前共享的純量 L0 快取。 純量快取和向量 L0 快取不一致。 但是,純量操作以受限制的方式使用,因此不會影響記憶體模型。 請參閱 記憶體空間。
向量和純量記憶體 L0 快取使用 L1 buffer,該 buffer 由相同 SA 上的所有 WGP 共用。L1 buffer 作為 SA 內用戶端到 L2 的橋樑。
L1 buffers 具有獨立的象限,以服務不相交的虛擬位址範圍。
每個 L0 快取對於每個 L1 象限都有一個單獨的請求佇列。因此,不同 wavefronts 執行的向量和純量記憶體操作(無論是在相同還是不同的 work-groups 中執行,這些 work-groups 可能在存取不同 L0 的不同 CU 上執行)可能會彼此重新排序。以下部分或全部 wait 指令是確保不同 wavefronts 的向量記憶體操作之間同步所必需的。它確保先前的向量記憶體操作已完成,然後再執行後續的向量記憶體或 LDS 操作,因此可以用於滿足 acquire、release 和循序一致性的要求。
s_wait_loadcnt 0x0
s_wait_samplecnt 0x0
s_wait_bvhcnt 0x0
s_wait_storecnt 0x0
L1 buffers 使用 L2 快取,該快取由相同 agent 上的所有 SA 共用。
L2 快取具有獨立通道,用於服務不相交的虛擬位址範圍。
單一 SA 的每個 L1 象限存取不同的 L2 通道。每個 L1 象限對於每個 L2 通道都有一個單獨的請求佇列。因此,在 agent 的不同 work-groups(可能在不同的 SA 上執行)中執行的 wavefronts 所執行的向量和純量記憶體操作可能會彼此重新排序。以下部分或全部 wait 指令是確保不同 SA 的向量記憶體操作之間同步所必需的。它確保先前的向量記憶體操作已完成,然後再執行後續的向量記憶體,因此可以用於滿足 acquire、release 和循序一致性的要求。
s_wait_loadcnt 0x0
s_wait_samplecnt 0x0
s_wait_bvhcnt 0x0
s_wait_storecnt 0x0
L2 快取可以與其他 agents 保持同調,或者可以設定虛擬位址範圍以繞過它,以確保系統同調性。
GPU 記憶體存在記憶體附加的末級 (MALL) 快取。MALL 快取與 GPU 記憶體完全同調,並且對系統同調性沒有影響。所有 agents(GPU 和 CPU)都透過 MALL 快取存取 GPU 記憶體。
純量記憶體操作僅用於存取在核心調度執行期間證明不會變更的記憶體。 這包括常數位址空間和程式作用域 const
變數的全域位址空間。 因此,核心機器碼不必維護純量快取,以確保它與向量快取一致。 純量快取和向量快取在核心調度之間由 CP 使失效,因為常數位址空間資料可能在核心調度執行之間變更。 請參閱 記憶體空間。
對於核心參數後備記憶體
CP 在每次核心調度開始時使快取失效。
在 dGPU 上,核心參數後備記憶體以 MTYPE UC(非快取)存取,以避免需要使 L2 快取失效。
在 APU 上,核心參數後備記憶體以 MTYPE CC(快取一致性)存取,因此 L2 快取將與 CPU 和其他代理程式保持一致性。
Scratch 後備記憶體(用於私有位址空間)使用 MTYPE NC(非同調)存取。由於私有位址空間僅由單一執行緒存取,並且始終是先寫後讀,因此永遠不需要使 L0 中的這些條目失效。
波前可以在 WGP 或 CU 波前執行模式下執行
在 WGP 波前執行模式下,工作群組的波前在 WGP 的兩個 CU 的 SIMD 上執行。 因此,工作群組同步需要顯式管理每個 CU L0 快取。 此外,工作群組作用域中對 L1 的存取需要顯式排序,因為來自不同 CU 的存取是無序的。
在 CU wavefront 執行模式中,work-group 的 wavefronts 會在 WGP 單一 CU 的 SIMD 上執行。因此,work-group 的所有全域記憶體存取都會存取相同的 L0,進而確保 L1 存取是有序的,因此不需要針對 work-group 同步進行快取的明確管理。
請參閱 WGP_MODE
欄位,位於 適用於 GFX6-GFX12 的 compute_pgm_rsrc1 和 目標功能。
用於實作 GFX12 記憶體模型的程式碼序列定義於表 AMDHSA 記憶體模型程式碼序列 GFX12 中。
LLVM IR syncscope 到 GFX12 指令 scope
運算元的對應定義於 AMDHSA 記憶體模型程式碼序列 GFX12 - 指令 Scope 中。
此表僅在 AMDHSA 記憶體模型程式碼序列 GFX12 中的條目直接引用它時適用,並且僅適用於引用該表的程式碼序列中的指令。
表 83 AMDHSA 記憶體模型程式碼序列 GFX12 - 指令 Scope¶ LLVM syncscope
CU wavefront 執行模式
WGP wavefront 執行模式
none
scope:SCOPE_SYS
scope:SCOPE_SYS
system
scope:SCOPE_SYS
scope:SCOPE_SYS
agent
scope:SCOPE_DEV
scope:SCOPE_DEV
workgroup
none
scope:SCOPE_SE
wavefront
none
none
singlethread
none
none
one-as
scope:SCOPE_SYS
scope:SCOPE_SYS
system-one-as
scope:SCOPE_SYS
scope:SCOPE_SYS
agent-one-as
scope:SCOPE_DEV
scope:SCOPE_DEV
workgroup-one-as
none
scope:SCOPE_SE
wavefront-one-as
none
none
singlethread-one-as
none
none
表 84 AMDHSA 記憶體模型程式碼序列 GFX12¶ LLVM 指令
LLVM 記憶體排序
LLVM 記憶體同步作用域
AMDGPU 位址空間
AMDGPU 機器碼 GFX12
非原子
載入
none
none
global
通用
private
constant
!volatile & !nontemporal
buffer/global/flat_load
!volatile & nontemporal
buffer/global/flat_load
th:TH_LOAD_NT
volatile
buffer/global/flat_load
scope:SCOPE_SYS
s_wait_loadcnt 0x0
必須在任何後續的揮發性全域/通用載入/儲存之前發生。
確保對不同位址的揮發性操作不會被硬體重新排序。
載入
none
none
區域
ds_load
儲存
none
none
global
通用
private
constant
!volatile & !nontemporal
buffer/global/flat_store
!volatile & nontemporal
buffer/global/flat_store
th:TH_STORE_NT
volatile
buffer/global/flat_store
scope:SCOPE_SYS
s_wait_storecnt 0x0
必須在任何後續的揮發性全域/通用載入/儲存之前發生。
確保對不同位址的揮發性操作不會被硬體重新排序。
儲存
none
none
區域
ds_store
無序原子
載入原子
無序
任何
任何
與非原子相同.
儲存原子
無序
任何
任何
與非原子相同.
atomicrmw
無序
任何
任何
與單調原子相同.
單調原子
載入原子
單調
singlethread
wavefront
workgroup
agent
system
global
通用
buffer/global/flat_load
載入原子
單調
singlethread
wavefront
workgroup
區域
ds_load
儲存原子
單調
singlethread
wavefront
workgroup
agent
system
global
通用
buffer/global/flat_store
儲存原子
單調
singlethread
wavefront
workgroup
區域
ds_store
atomicrmw
單調
singlethread
wavefront
workgroup
agent
system
global
通用
buffer/global/flat_atomic
atomicrmw
單調
singlethread
wavefront
workgroup
區域
ds_atomic
取得原子
載入原子
取得
singlethread
wavefront
global
區域
通用
buffer/global/ds/flat_load
載入原子
取得
workgroup
global
buffer/global_load
scope:SCOPE_SE
s_wait_loadcnt 0x0
若為 CU wavefront 執行模式,則省略。
必須在後續的
global_inv
之前,以及任何後續的 global/generic load/load atomic/store/store atomic/atomicrmw 之前發生。
global_inv scope:SCOPE_SE
若為 CU wavefront 執行模式,則省略。
確保後續的載入不會看到過時的資料。
載入原子
取得
workgroup
區域
ds_load
s_wait_dscnt 0x0
如果是 OpenCL,則省略。
必須在後續的
global_inv
之前,以及任何後續的 global/generic load/load atomic/store/store atomic/atomicrmw 之前發生。確保任何後續的全域資料讀取都不會早於正在取得的區域載入原子值。
global_inv scope:SCOPE_SE
若為 OpenCL 或 CU wavefront 執行模式,則省略。
確保後續的載入不會看到過時的資料。
載入原子
取得
workgroup
通用
flat_load
s_wait_loadcnt 0x0
s_wait_dscnt 0x0
CU wavefront 執行模式s_wait_dscnt 0x0
若為 OpenCL,則省略
s_wait_dscnt 0x0
必須在後續的
global_inv
以及任何後續的 global/generic load/load atomic/store/store atomic/atomicrmw 之前發生。確保任何後續的全域資料讀取都不會早於正在取得的區域載入原子值。
global_inv scope:SCOPE_SE
若為 CU wavefront 執行模式,則省略。
確保後續的載入不會看到過時的資料。
載入原子
取得
agent
system
global
buffer/global_load
s_wait_loadcnt 0x0
必須在後續的
global_inv
之前發生。確保在使快取失效之前,載入已完成。
global_inv
必須在任何後續的全域/通用載入/載入原子/atomicrmw 之前發生。
確保後續的載入不會看到過時的全域資料。
載入原子
取得
agent
system
通用
flat_load
s_wait_loadcnt 0x0
s_wait_dscnt 0x0
若為 OpenCL,則省略
s_wait_dscnt 0x0
必須在後續的
global_inv
之前發生。確保 flat_load 在使快取失效之前已完成。
global_inv
必須在任何後續的全域/通用載入/載入原子/atomicrmw 之前發生。
確保後續的載入不會看到過時的全域資料。
atomicrmw
取得
singlethread
wavefront
global
區域
通用
buffer/global/ds/flat_atomic
atomicrmw
取得
workgroup
global
buffer/global_atomic
若為帶有返回值的 atomic,則使用
th:TH_ATOMIC_RETURN
帶有返回值的 Atomics_wait_loadcnt 0x0
不帶返回值的 Atomics_wait_storecnt 0x0
若為 CU wavefront 執行模式,則省略。
必須在後續的
global_inv
之前,以及任何後續的 global/generic load/load atomic/store/store atomic/atomicrmw 之前發生。
global_inv scope:SCOPE_SE
若為 CU wavefront 執行模式,則省略。
確保後續的載入不會看到過時的資料。
atomicrmw
取得
workgroup
區域
ds_atomic
s_wait_dscnt 0x0
如果是 OpenCL,則省略。
必須在後續的
global_inv
之前發生。確保任何後續的全域資料讀取都不會早於正在取得的區域 atomicrmw 值。
global_inv scope:SCOPE_SE
若為 OpenCL,則省略。
若為 CU wavefront 執行模式,則省略。
確保後續的載入不會看到過時的資料。
atomicrmw
取得
workgroup
通用
flat_atomic
若為帶有返回值的 atomic,則使用
th:TH_ATOMIC_RETURN
帶有返回值的 Atomics_wait_loadcnt 0x0
s_wait_dscnt 0x0
不帶返回值的 Atomics_wait_storecnt 0x0
s_wait_dscnt 0x0
若為 CU wavefront 執行模式,則對於不帶返回值的 atomics,省略所有內容,對於帶有返回值的 atomics,僅發出
s_wait_dscnt 0x0
。若為 OpenCL,則省略
s_wait_dscnt 0x0
必須在後續的
global_inv
之前發生。確保任何後續的全域資料讀取都不會早於正在取得的區域 atomicrmw 值。
global_inv scope:SCOPE_SE
若為 CU wavefront 執行模式,則省略。
確保後續的載入不會看到過時的資料。
atomicrmw
取得
agent
system
global
buffer/global_atomic
若為帶有返回值的 atomic,則使用
th:TH_ATOMIC_RETURN
帶有返回值的 Atomics_wait_loadcnt 0x0
不帶返回值的 Atomics_wait_storecnt 0x0
必須在後續的
global_inv
之前發生。確保 atomicrmw 在使快取失效之前已完成。
global_inv
必須在任何後續的全域/通用載入/載入原子/atomicrmw 之前發生。
確保後續的載入不會看到過時的全域資料。
atomicrmw
取得
agent
system
通用
flat_atomic
若為帶有返回值的 atomic,則使用
th:TH_ATOMIC_RETURN
帶有返回值的 Atomics_wait_loadcnt 0x0
s_wait_dscnt 0x0
不帶返回值的 Atomics_wait_storecnt 0x0
s_wait_dscnt 0x0
若為 OpenCL,則省略 dscnt
必須在後續的 global_inv 之前發生
確保 atomicrmw 在使快取失效之前已完成。
global_inv
必須在任何後續的全域/通用載入/載入原子/atomicrmw 之前發生。
確保後續的載入不會看到過時的全域資料。
柵欄
取得
singlethread
wavefront
none
none
柵欄
取得
workgroup
none
s_wait_storecnt 0x0
s_wait_loadcnt 0x0
s_wait_dscnt 0x0
CU wavefront 執行模式s_wait_dscnt 0x0
若為 OpenCL,則省略
s_wait_dscnt 0x0
若為 OpenCL 且位址空間為 local,則省略所有內容。
有關特定位址空間柵欄的更多詳細資訊,請參閱 柵欄和位址空間。
注意:我們不必使用
s_wait_samplecnt 0x0
或s_wait_bvhcnt 0x0
,因為沒有 fence 可以與之配對的 atomic sample 或 BVH 指令。waits 可以根據以下規則獨立移動
s_wait_loadcnt 0x0
必須在任何先前的 global/generic load atomic/ atomicrmw-with-return-value 之後發生,其同步範圍相等或更寬,且記憶體排序強於 unordered(這稱為 fence-paired-atomic)。
s_wait_storecnt 0x0
必須在任何先前的 global/generic atomicrmw-no-return-value 之後發生,其同步範圍相等或更寬,且記憶體排序強於 unordered(這稱為 fence-paired-atomic)。
s_wait_dscnt 0x0
必須在任何先前的 local/generic load atomic/atomicrmw 之後發生,其同步範圍相等或更寬,且記憶體排序強於 unordered(這稱為 fence-paired-atomic)。必須在後續的
global_inv
之前發生。確保柵欄配對原子在使快取失效之前已完成。 因此,任何後續讀取的位置都不得早於柵欄配對原子讀取的值。
global_inv scope:SCOPE_SE
若為 CU wavefront 執行模式,則省略。
確保後續的載入不會看到過時的資料。
柵欄
取得
agent
none
s_wait_storecnt 0x0
s_wait_loadcnt 0x0
s_wait_dscnt 0x0
若為 OpenCL,則省略
s_wait_dscnt 0x0
。若為 OpenCL 且位址空間為 local,則省略所有內容。
有關特定位址空間柵欄的更多詳細資訊,請參閱 柵欄和位址空間。
注意:我們不必使用
s_wait_samplecnt 0x0
或s_wait_bvhcnt 0x0
,因為沒有 fence 可以與之配對的 atomic sample 或 BVH 指令。waits 可以根據以下規則獨立移動
s_wait_loadcnt 0x0
必須在任何先前的 global/generic load atomic/ atomicrmw-with-return-value 之後發生,其同步範圍相等或更寬,且記憶體排序強於 unordered(這稱為 fence-paired-atomic)。
s_wait_storecnt 0x0
必須在任何先前的 global/generic atomicrmw-no-return-value 之後發生,其同步範圍相等或更寬,且記憶體排序強於 unordered(這稱為 fence-paired-atomic)。
s_wait_dscnt 0x0
必須在任何先前的 local/generic load atomic/atomicrmw 之後發生,其同步範圍相等或更寬,且記憶體排序強於 unordered(這稱為 fence-paired-atomic)。必須在後續的
global_inv
之前發生確保 fence-paired atomic 在使快取失效之前已完成。因此,任何後續讀取的位置都不得早於 fence-paired-atomic 讀取的值。
global_inv
確保後續的載入不會看到過時的資料。
釋放原子
儲存原子
釋放
singlethread
wavefront
global
區域
通用
buffer/global/ds/flat_store
儲存原子
釋放
workgroup
global
s_wait_bvhcnt 0x0
s_wait_samplecnt 0x0
s_wait_storecnt 0x0
s_wait_loadcnt 0x0
s_wait_dscnt 0x0
CU wavefront 執行模式s_wait_dscnt 0x0
若為 OpenCL,則省略
s_wait_dscnt 0x0
。waits 可以根據以下規則獨立移動
s_wait_loadcnt 0x0
、s_wait_samplecnt 0x0
和s_wait_bvhcnt 0x0
必須在任何先前的 global/generic load/load atomic/ atomicrmw-with-return-value 之後發生。
s_wait_storecnt 0x0
必須在任何先前的 global/generic store/store atomic/ atomicrmw-no-return-value 之後發生。
s_wait_dscnt 0x0
必須在任何先前的 local/generic load/store/load atomic/store atomic/atomicrmw 之後發生。確保所有記憶體操作在執行正在釋放的儲存之前已完成。
buffer/global/flat_store
儲存原子
釋放
workgroup
區域
s_wait_bvhcnt 0x0
s_wait_samplecnt 0x0
s_wait_storecnt 0x0
s_wait_loadcnt 0x0
s_wait_dscnt 0x0
CU wavefront 執行模式s_wait_dscnt 0x0
如果是 OpenCL,則省略。
waits 可以根據以下規則獨立移動
s_wait_loadcnt 0x0
、s_wait_samplecnt 0x0
和s_wait_bvhcnt 0x0
必須在任何先前的 global/generic load/load atomic/ atomicrmw-with-return-value 之後發生。
s_wait_storecnt 0x0
必須在任何先前的 global/generic store/store atomic/ atomicrmw-no-return-value 之後發生。必須在後續的儲存之前發生。
確保所有全域記憶體操作在執行正在釋放的 store 之前已完成。
ds_store
儲存原子
釋放
agent
system
global
通用
global_wb scope:SCOPE_SYS
若為 agent scope,則省略。
s_wait_bvhcnt 0x0
s_wait_samplecnt 0x0
s_wait_storecnt 0x0
s_wait_loadcnt 0x0
s_wait_dscnt 0x0
若為 OpenCL,則省略
s_wait_dscnt 0x0
。waits 可以根據以下規則獨立移動
s_wait_loadcnt 0x0
、s_wait_samplecnt 0x0
和s_wait_bvhcnt 0x0
必須在任何先前的 global/generic load/load atomic/ atomicrmw-with-return-value 之後發生。
s_wait_storecnt 0x0
必須在global_wb
(如果存在) 之後,或任何先前的 global/generic store/store atomic/ atomicrmw-no-return-value 之後發生。
s_wait_dscnt 0x0
必須在任何先前的 local/generic load/store/load atomic/store atomic/atomicrmw 之後發生。必須在後續的儲存之前發生。
確保所有記憶體操作在執行正在釋放的儲存之前已完成。
buffer/global/flat_store
atomicrmw
釋放
singlethread
wavefront
global
區域
通用
buffer/global/ds/flat_atomic
atomicrmw
釋放
workgroup
global
通用
s_wait_bvhcnt 0x0
s_wait_samplecnt 0x0
s_wait_storecnt 0x0
s_wait_loadcnt 0x0
s_wait_dscnt 0x0
CU wavefront 執行模式s_wait_dscnt 0x0
若為 OpenCL,則省略
s_wait_dscnt 0x0
。若為 OpenCL 且 CU wavefront 執行模式,則省略所有內容。
waits 可以根據以下規則獨立移動
s_wait_loadcnt 0x0
、s_wait_samplecnt 0x0
和s_wait_bvhcnt 0x0
必須在任何先前的 global/generic load/load atomic/ atomicrmw-with-return-value 之後發生。
s_wait_storecnt 0x0
必須在任何先前的 global/generic store/store atomic/ atomicrmw-no-return-value 之後發生。
s_wait_dscnt 0x0
必須在任何先前的 local/generic load/store/load atomic/store atomic/atomicrmw 之後發生。必須在後續的 atomic 之前發生。
確保所有記憶體操作在執行正在釋放的 atomicrmw 之前已完成。
buffer/global/flat_atomic
atomicrmw
釋放
workgroup
區域
s_wait_bvhcnt 0x0
s_wait_samplecnt 0x0
s_wait_storecnt 0x0
s_wait_loadcnt 0x0
s_wait_dscnt 0x0
CU wavefront 執行模式s_wait_dscnt 0x0
若為 OpenCL,則省略所有內容。
waits 可以根據以下規則獨立移動
s_wait_loadcnt 0x0
、s_wait_samplecnt 0x0
和s_wait_bvhcnt 0x0
必須在任何先前的 global/generic load/load atomic/ atomicrmw-with-return-value 之後發生。
s_wait_storecnt 0x0
必須在任何先前的 global/generic store/store atomic/ atomicrmw-no-return-value 之後發生。必須在後續的 atomic 之前發生。
確保所有全域記憶體操作在執行正在釋放的 store 之前已完成。
ds_atomic
atomicrmw
釋放
agent
system
global
通用
global_wb scope:SCOPE_SYS
若為 agent scope,則省略。
s_wait_bvhcnt 0x0
s_wait_samplecnt 0x0
s_wait_storecnt 0x0
s_wait_loadcnt 0x0
s_wait_dscnt 0x0
若為 OpenCL,則省略
s_wait_dscnt 0x0
。waits 可以根據以下規則獨立移動
s_wait_loadcnt 0x0
、s_wait_samplecnt 0x0
和s_wait_bvhcnt 0x0
必須在任何先前的 global/generic load/load atomic/ atomicrmw-with-return-value 之後發生。
s_wait_storecnt 0x0
必須在global_wb
(如果存在) 之後,或任何先前的 global/generic store/store atomic/ atomicrmw-no-return-value 之後發生。
s_wait_dscnt 0x0
必須在任何先前的 local/generic load/store/load atomic/store atomic/atomicrmw 之後發生。必須在後續的 atomic 之前發生。
確保對全域和區域的所有記憶體操作在執行正在釋放的 atomicrmw 之前已完成。
buffer/global/flat_atomic
柵欄
釋放
singlethread
wavefront
none
none
柵欄
釋放
workgroup
none
s_wait_bvhcnt 0x0
s_wait_samplecnt 0x0
s_wait_storecnt 0x0
s_wait_loadcnt 0x0
s_wait_dscnt 0x0
CU wavefront 執行模式s_wait_dscnt 0x0
若為 OpenCL,則省略
s_wait_dscnt 0x0
。若為 OpenCL 且位址空間為 local,則省略所有內容。
有關特定位址空間柵欄的更多詳細資訊,請參閱 柵欄和位址空間。
waits 可以根據以下規則獨立移動
s_wait_loadcnt 0x0
、s_wait_samplecnt 0x0
和s_wait_bvhcnt 0x0
必須在任何先前的 global/generic load/load atomic/ atomicrmw-with-return-value 之後發生。
s_wait_storecnt 0x0
必須在任何先前的 global/generic store/store atomic/ atomicrmw-no-return-value 之後發生。
s_wait_dscnt 0x0
必須在任何先前的 local/generic load/store/load atomic/store atomic/ atomicrmw 之後發生。必須在任何後續的儲存原子/atomicrmw 之前發生,其同步作用域相等或更寬,且記憶體排序強於無序(這稱為柵欄配對原子)。
確保所有記憶體操作在執行後續的柵欄配對原子之前已完成。
柵欄
釋放
agent
system
none
global_wb scope:SCOPE_SYS
若為 agent scope,則省略。
s_wait_bvhcnt 0x0
s_wait_samplecnt 0x0
s_wait_storecnt 0x0
s_wait_loadcnt 0x0
s_wait_dscnt 0x0
OpenCLs_wait_bvhcnt 0x0
s_wait_samplecnt 0x0
s_wait_storecnt 0x0
s_wait_loadcnt 0x0
若為 OpenCl,則省略
s_wait_dscnt 0x0
。若為 OpenCL 且位址空間為 local,則省略所有內容。
有關特定位址空間柵欄的更多詳細資訊,請參閱 柵欄和位址空間。
waits 可以根據以下規則獨立移動
s_wait_loadcnt 0x0
、s_wait_samplecnt 0x0
和s_wait_bvhcnt 0x0
必須在任何先前的 global/generic load/load atomic/ atomicrmw-with-return-value 之後發生。
s_wait_storecnt 0x0
必須在global_wb
(如果存在) 之後,或任何先前的 global/generic store/store atomic/ atomicrmw-no-return-value 之後發生。
s_wait_dscnt 0x0
必須在任何先前的 local/generic load/store/load atomic/store atomic/atomicrmw 之後發生。必須在任何後續的儲存原子/atomicrmw 之前發生,其同步作用域相等或更寬,且記憶體排序強於無序(這稱為柵欄配對原子)。
確保所有記憶體操作在執行後續的柵欄配對原子之前已完成。
取得-釋放原子
atomicrmw
取得_釋放
singlethread
wavefront
global
區域
通用
buffer/global/ds/flat_atomic
atomicrmw
取得_釋放
workgroup
global
s_wait_bvhcnt 0x0
s_wait_samplecnt 0x0
s_wait_storecnt 0x0
s_wait_loadcnt 0x0
s_wait_dscnt 0x0
CU wavefront 執行模式s_wait_dscnt 0x0
若為 OpenCL,則省略
s_wait_dscnt 0x0
。必須在任何先前的區域/通用載入/儲存/載入原子/儲存原子/atomicrmw 之後發生。
waits 可以根據以下規則獨立移動
s_wait_loadcnt 0x0
、s_wait_samplecnt 0x0
和s_wait_bvhcnt 0x0
必須在任何先前的 global/generic load/load atomic/ atomicrmw-with-return-value 之後發生。
s_wait_storecnt 0x0
必須在任何先前的 global/generic store/store atomic/ atomicrmw-no-return-value 之後發生。
s_wait_dscnt 0x0
必須在任何先前的 local/generic load/store/load atomic/store atomic/atomicrmw 之後發生。必須在後續的 atomicrmw 之前發生。
確保所有記憶體操作在執行正在釋放的 atomicrmw 之前已完成。
buffer/global_atomic
若為帶有返回值的 atomic,則使用
th:TH_ATOMIC_RETURN
。
帶有返回值的 Atomics_wait_loadcnt 0x0
不帶返回值的 Atomics_wait_storecnt 0x0
若為 CU wavefront 執行模式,則省略。
必須在後續的
global_inv
之前發生。確保任何後續的全域資料讀取都不會早於正在取得的 atomicrmw 值。
global_inv scope:SCOPE_SE
若為 CU wavefront 執行模式,則省略。
確保後續的載入不會看到過時的資料。
atomicrmw
取得_釋放
workgroup
區域
- 1 |
s_wait_bvhcnt 0x0
s_wait_samplecnt 0x0
s_wait_storecnt 0x0
s_wait_loadcnt 0x0
s_wait_dscnt 0x0
CU wavefront 執行模式s_wait_dscnt 0x0
如果是 OpenCL,則省略。
waits 可以根據以下規則獨立移動
s_wait_loadcnt 0x0
、s_wait_samplecnt 0x0
和s_wait_bvhcnt 0x0
必須在任何先前的 global/generic load/load atomic/ atomicrmw-with-return-value 之後發生。
s_wait_storecnt 0x0
必須在任何先前的 global/generic store/store atomic/ atomicrmw-no-return-value 之後發生。必須在後續的儲存之前發生。
確保所有全域記憶體操作在執行正在釋放的 store 之前已完成。
ds_atomic
s_wait_dscnt 0x0
如果是 OpenCL,則省略。
必須在後續的
global_inv
之前發生。確保任何後續的全域資料讀取都不會早於正在取得的區域載入原子值。
global_inv scope:SCOPE_SE
若為 CU wavefront 執行模式,則省略。
若為 OpenCL,則省略。
確保後續的載入不會看到過時的資料。
atomicrmw
取得_釋放
workgroup
通用
s_wait_bvhcnt 0x0
s_wait_samplecnt 0x0
s_wait_storecnt 0x0
s_wait_loadcnt 0x0
s_wait_dscnt 0x0
CU wavefront 執行模式s_wait_dscnt 0x0
若為 OpenCL,則省略
s_wait_loadcnt 0x0
。waits 可以根據以下規則獨立移動
s_wait_loadcnt 0x0
、s_wait_samplecnt 0x0
和s_wait_bvhcnt 0x0
必須在任何先前的 global/generic load/load atomic/ atomicrmw-with-return-value 之後發生。
s_wait_storecnt 0x0
必須在任何先前的 global/generic store/store atomic/ atomicrmw-no-return-value 之後發生。
s_wait_dscnt 0x0
必須在任何先前的 local/generic load/store/load atomic/store atomic/atomicrmw 之後發生。必須在後續的 atomicrmw 之前發生。
確保所有記憶體操作在執行正在釋放的 atomicrmw 之前已完成。
flat_atomic
若為帶有返回值的 atomic,則使用
th:TH_ATOMIC_RETURN
。
不帶返回值的 Atomics_wait_dscnt 0x0
s_wait_storecnt 0x0
帶有返回值的 Atomics_wait_loadcnt 0x0
s_wait_dscnt 0x0
CU wavefront 執行模式s_wait_dscnt 0x0
若為 OpenCL,則省略
s_wait_dscnt 0x0
必須在後續的
global_inv
之前發生。確保任何後續讀取的全域資料都不早於正在取得的 load atomic 值。
global_inv scope:SCOPE_SE
若為 CU wavefront 執行模式,則省略。
確保後續的載入不會看到過時的資料。
atomicrmw
取得_釋放
agent
system
global
global_wb scope:SCOPE_SYS
若為 agent scope,則省略。
s_wait_bvhcnt 0x0
s_wait_samplecnt 0x0
s_wait_storecnt 0x0
s_wait_loadcnt 0x0
s_wait_dscnt 0x0
若為 OpenCL,則省略
s_wait_dscnt 0x0
waits 可以根據以下規則獨立移動
s_wait_loadcnt 0x0
、s_wait_samplecnt 0x0
和s_wait_bvhcnt 0x0
必須在任何先前的 global/generic load/load atomic/ atomicrmw-with-return-value 之後發生。
s_wait_storecnt 0x0
必須在global_wb
(如果存在) 之後,或任何先前的 global/generic store/store atomic/ atomicrmw-no-return-value 之後發生。
s_wait_dscnt 0x0
必須在任何先前的 local/generic load/store/load atomic/store atomic/atomicrmw 之後發生。必須在後續的 atomicrmw 之前發生。
確保對全域的所有記憶體操作在執行正在釋放的 atomicrmw 之前已完成。
buffer/global_atomic
若為帶有返回值的 atomic,則使用
th:TH_ATOMIC_RETURN
。
帶有返回值的 Atomics_wait_loadcnt 0x0
不帶返回值的 Atomics_wait_storecnt 0x0
必須在後續的
global_inv
之前發生。確保 atomicrmw 在使快取失效之前已完成。
global_inv
必須在任何後續的全域/通用載入/載入原子/atomicrmw 之前發生。
確保後續的載入不會看到過時的全域資料。
atomicrmw
取得_釋放
agent
system
通用
global_wb scope:SCOPE_SYS
若為 agent scope,則省略。
s_wait_bvhcnt 0x0
s_wait_samplecnt 0x0
s_wait_storecnt 0x0
s_wait_loadcnt 0x0
s_wait_dscnt 0x0
若為 OpenCL,則省略
s_wait_dscnt 0x0
waits 可以根據以下規則獨立移動
s_wait_loadcnt 0x0
、s_wait_samplecnt 0x0
和s_wait_bvhcnt 0x0
必須在任何先前的 global/generic load/load atomic atomicrmw-with-return-value 之後發生。
s_wait_storecnt 0x0
必須在global_wb
(如果存在) 之後,或任何先前的 global/generic store/store atomic/ atomicrmw-no-return-value 之後發生。
s_wait_dscnt 0x0
必須在任何先前的 local/generic load/store/load atomic/store atomic/atomicrmw 之後發生。必須在後續的 atomicrmw 之前發生。
確保所有記憶體操作在執行正在釋放的 atomicrmw 之前已完成。
flat_atomic
若為帶有返回值的 atomic,則使用
th:TH_ATOMIC_RETURN
。
帶有返回值的 Atomics_wait_loadcnt 0x0
s_wait_dscnt 0x0
不帶返回值的 Atomics_wait_storecnt 0x0
s_wait_dscnt 0x0
若為 OpenCL,則省略
s_wait_dscnt 0x0
。必須在後續的
global_inv
之前發生。確保 atomicrmw 在使快取失效之前已完成。
global_inv
必須在任何後續的全域/通用載入/載入原子/atomicrmw 之前發生。
確保後續的載入不會看到過時的全域資料。
柵欄
取得_釋放
singlethread
wavefront
none
none
柵欄
取得_釋放
workgroup
none
s_wait_bvhcnt 0x0
s_wait_samplecnt 0x0
s_wait_storecnt 0x0
s_wait_loadcnt 0x0
s_wait_dscnt 0x0
CU wavefront 執行模式s_wait_dscnt 0x0
若為 OpenCL 且位址空間不是 generic,則省略
s_wait_dscnt 0x0
若為 OpenCL 且位址空間為 local,則省略除
s_wait_dscnt 0x0
之外的所有內容。有關特定位址空間柵欄的更多詳細資訊,請參閱 柵欄和位址空間。
waits 可以根據以下規則獨立移動
s_wait_loadcnt 0x0
、s_wait_samplecnt 0x0
和s_wait_bvhcnt 0x0
必須在任何先前的 global/generic load/load atomic/ atomicrmw-with-return-value 之後發生。
s_wait_storecnt 0x0
必須在任何先前的 global/generic store/store atomic/ atomicrmw-no-return-value 之後發生。
s_wait_dscnt 0x0
必須在任何先前的 local/generic load/store/load atomic/store atomic/ atomicrmw 之後發生。必須在任何後續的全域/通用載入/載入原子/儲存/儲存原子/atomicrmw 之前發生。
確保所有記憶體操作在執行任何後續的全域記憶體操作之前已完成。
確保先前的區域/通用載入原子/atomicrmw,其同步作用域相等或更寬,且記憶體排序強於無序(這稱為取得柵欄配對原子),在後續的全域記憶體操作之前已完成。 這滿足取得的要求。
確保所有先前的記憶體操作在後續的區域/通用儲存原子/atomicrmw 之前已完成,其同步作用域相等或更寬,且記憶體排序強於無序(這稱為釋放柵欄配對原子)。 這滿足釋放的要求。
必須在後續的
global_inv
之前發生。確保取得柵欄配對原子在使快取失效之前已完成。 因此,任何後續讀取的位置都不得早於取得柵欄配對原子讀取的值。
global_inv scope:SCOPE_SE
若為 CU wavefront 執行模式,則省略。
確保後續的載入不會看到過時的資料。
柵欄
取得_釋放
agent
system
none
global_wb scope:SCOPE_SYS
若為 agent scope,則省略。
s_wait_bvhcnt 0x0
s_wait_samplecnt 0x0
s_wait_storecnt 0x0
s_wait_loadcnt 0x0
s_wait_dscnt 0x0
若為 OpenCL 且位址空間不是 generic,則省略
s_wait_dscnt 0x0
若為 OpenCL 且位址空間為 local,則省略除
s_wait_dscnt 0x0
之外的所有內容。有關特定位址空間柵欄的更多詳細資訊,請參閱 柵欄和位址空間。
waits 可以根據以下規則獨立移動
s_wait_loadcnt 0x0
、s_wait_samplecnt 0x0
和s_wait_bvhcnt 0x0
必須在任何先前的 global/generic load/load atomic/ atomicrmw-with-return-value 之後發生。
s_wait_storecnt 0x0
必須在global_wb
(如果存在) 之後,或任何先前的 global/generic store/store atomic/ atomicrmw-no-return-value 之後發生。
s_wait_dscnt 0x0
必須在任何先前的 local/generic load/store/load atomic/store atomic/atomicrmw 之後發生。必須在後續的
global_inv
之前發生確保先前的 global/local/generic load atomic/atomicrmw (其同步範圍相等或更寬,且記憶體排序強於 unordered,這稱為 acquire-fence-paired-atomic) 在使快取失效之前已完成。這滿足 acquire 的要求。
確保所有先前的記憶體操作在後續的全域/區域/通用儲存原子/atomicrmw 之前已完成,其同步作用域相等或更寬,且記憶體排序強於無序(這稱為釋放柵欄配對原子)。 這滿足釋放的要求。
global_inv scope:
必須在任何後續的全域/通用載入/載入原子/儲存/儲存原子/atomicrmw 之前發生。
確保後續的載入不會看到過時的全域資料。 這滿足取得的要求。
循序一致性原子
載入原子
seq_cst
singlethread
wavefront
global
區域
通用
與對應的載入原子取得相同,但即使對於 OpenCL 也必須產生所有指令。
載入原子
seq_cst
workgroup
global
通用
s_wait_bvhcnt 0x0
s_wait_samplecnt 0x0
s_wait_storecnt 0x0
s_wait_loadcnt 0x0
s_wait_dscnt 0x0
CU wavefront 執行模式s_wait_dscnt 0x0
若為 OpenCL,則省略
s_wait_dscnt 0x0
waits 可以根據以下規則獨立移動
s_wait_dscnt 0x0
必須在先前的 local/generic load atomic/store atomic/atomicrmw 之後發生,其記憶體排序為 seq_cst 且同步範圍相等或更寬。(請注意,seq_cst fences 有自己的s_wait_dscnt 0x0
,因此無需考慮。)
s_wait_loadcnt 0x0
、s_wait_samplecnt 0x0
和s_wait_bvhcnt 0x0
必須在先前的 global/generic load atomic/ atomicrmw-with-return-value 之後發生,其記憶體排序為 seq_cst 且同步範圍相等或更寬。(請注意,seq_cst fences 有自己的 waits,因此無需考慮。)
s_wait_storecnt 0x0
必須在先前的 global/generic store atomic/ atomicrmw-no-return-value 之後發生,其記憶體排序為 seq_cst 且同步範圍相等或更寬。(請注意,seq_cst fences 有自己的s_wait_storecnt 0x0
,因此無需考慮。)確保任何先前的循序一致性 global/local 記憶體指令在執行此循序一致性指令之前已完成。這可防止重新排序 seq_cst store 後面跟著 seq_cst load。(請注意,seq_cst 比 acquire/release 更強,因為 load acquire 後面跟著 store release 的重新排序受到 release 的
s_wait
s 的阻止,但沒有任何東西阻止 store release 後面跟著 load acquire 從亂序完成。s_wait
s 可以放在 seq_store 之後或 seq_load 之前。我們選擇 load 是為了使s_wait
s 盡可能晚,以便 store 可能已經完成。)
後續指令與對應的載入原子取得相同,但即使對於 OpenCL 也必須產生所有指令。
載入原子
seq_cst
workgroup
區域
s_wait_bvhcnt 0x0
s_wait_samplecnt 0x0
s_wait_storecnt 0x0
s_wait_loadcnt 0x0
s_wait_dscnt 0x0
CU wavefront 執行模式s_wait_dscnt 0x0
若為 OpenCL,則省略所有內容。
waits 可以根據以下規則獨立移動
s_wait_loadcnt 0x0
、s_wait_samplecnt 0x0
和s_wait_bvhcnt 0x0
必須在先前的 global/generic load atomic/ atomicrmw-with-return-value 之後發生,其記憶體排序為 seq_cst 且同步範圍相等或更寬。(請注意,seq_cst fences 有自己的s_wait
s,因此無需考慮。)
s_wait_storecnt 0x0
必須在先前的 global/generic store atomic/ atomicrmw-no-return-value 之後發生,其記憶體排序為 seq_cst 且同步範圍相等或更寬。(請注意,seq_cst fences 有自己的s_wait_storecnt 0x0
,因此無需考慮。)確保任何先前的循序一致性全域記憶體指令在執行此循序一致性指令之前已完成。這可防止重新排序 seq_cst store 後面跟著 seq_cst load。(請注意,seq_cst 比 acquire/release 更強,因為 load acquire 後面跟著 store release 的重新排序受到 release 的
s_wait
s 的阻止,但沒有任何東西阻止 store release 後面跟著 load acquire 從亂序完成。s_waitcnt 可以放在 seq_store 之後或 seq_load 之前。我們選擇 load 是為了使s_wait
s 盡可能晚,以便 store 可能已經完成。)
後續指令與對應的載入原子取得相同,但即使對於 OpenCL 也必須產生所有指令。
載入原子
seq_cst
agent
system
global
通用
s_wait_bvhcnt 0x0
s_wait_samplecnt 0x0
s_wait_storecnt 0x0
s_wait_loadcnt 0x0
s_wait_dscnt 0x0
若為 OpenCL,則省略
s_wait_dscnt 0x0
waits 可以根據以下規則獨立移動
s_wait_dscnt 0x0
必須在先前的 local load atomic/store atomic/atomicrmw 之後發生,其記憶體排序為 seq_cst 且同步範圍相等或更寬。(請注意,seq_cst fences 有自己的s_wait_dscnt 0x0
,因此無需考慮。)
s_wait_loadcnt 0x0
、s_wait_samplecnt 0x0
和s_wait_bvhcnt 0x0
必須在先前的 global/generic load atomic/ atomicrmw-with-return-value 之後發生,其記憶體排序為 seq_cst 且同步範圍相等或更寬。(請注意,seq_cst fences 有自己的s_wait
s,因此無需考慮。)
s_wait_storecnt 0x0
必須在先前的 global/generic store atomic/ atomicrmw-no-return-value 之後發生,其記憶體排序為 seq_cst 且同步範圍相等或更寬。(請注意,seq_cst fences 有自己的s_wait_storecnt 0x0
,因此無需考慮。)確保任何先前的循序一致性全域記憶體指令在執行此循序一致性指令之前已完成。這可防止重新排序 seq_cst store 後面跟著 seq_cst load。(請注意,seq_cst 比 acquire/release 更強,因為 load acquire 後面跟著 store release 的重新排序受到 release 的
s_wait
s 的阻止,但沒有任何東西阻止 store release 後面跟著 load acquire 從亂序完成。s_wait
s 可以放在 seq_store 之後或 seq_load 之前。我們選擇 load 是為了使s_wait
s 盡可能晚,以便 store 可能已經完成。)
後續指令與對應的載入原子取得相同,但即使對於 OpenCL 也必須產生所有指令。
儲存原子
seq_cst
singlethread
wavefront
workgroup
agent
system
global
區域
通用
與對應的儲存原子釋放相同,但即使對於 OpenCL 也必須產生所有指令。
atomicrmw
seq_cst
singlethread
wavefront
workgroup
agent
system
global
區域
通用
與對應的 atomicrmw acq_rel 相同,但即使對於 OpenCL 也必須產生所有指令。
柵欄
seq_cst
singlethread
wavefront
workgroup
agent
system
none
與對應的柵欄 acq_rel 相同,但即使對於 OpenCL 也必須產生所有指令。
Trap Handler ABI¶
對於由 AMDGPU 後端為 HSA [HSA] 相容執行階段產生的程式碼物件(請參閱 AMDGPU 作業系統),執行階段安裝了一個 trap handler,其支援 s_trap
指令。如需用法,請參閱
AMDGPU Trap Handler for AMDHSA OS Code Object V4 及更高版本
表 85 AMDGPU Trap Handler for AMDHSA OS Code Object V2¶ 用法
程式碼序列
Trap Handler 輸入
描述
保留
s_trap 0x00
硬體保留。
debugtrap(arg)
s_trap 0x01
SGPR0-1
:queue_ptr
VGPR0
:arg
保留給 Finalizer HSA
debugtrap
intrinsic(尚未實作)。llvm.trap
s_trap 0x02
SGPR0-1
:queue_ptr
導致 wave 在 trap 指令處的 PC 停止。相關的佇列會發出訊號以將其置於錯誤狀態。當佇列處於錯誤狀態時,在佇列上執行調度的 waves 將會終止。
llvm.debugtrap
s_trap 0x03
none
如果未啟用偵錯器,則行為如同 no-operation。trap handler 會進入並立即返回以繼續執行 wavefront。
如果已啟用偵錯器,則會導致偵錯器報告 debug trap,並且 wavefront 會在指令處的 PC 進入 halt 狀態。偵錯器必須增加 PC 並恢復 wave。
保留
s_trap 0x04
保留。
保留
s_trap 0x05
保留。
保留
s_trap 0x06
保留。
保留
s_trap 0x07
保留。
保留
s_trap 0x08
保留。
保留
s_trap 0xfe
保留。
保留
s_trap 0xff
保留。
表 86 AMDGPU Trap Handler for AMDHSA OS Code Object V3¶ 用法
程式碼序列
Trap Handler 輸入
描述
保留
s_trap 0x00
硬體保留。
偵錯器中斷點
s_trap 0x01
none
保留供偵錯器用於中斷點。導致 wave 在 trap 指令處的 PC 停止。偵錯器負責恢復 wave,包括中斷點覆寫的指令。
llvm.trap
s_trap 0x02
SGPR0-1
:
queue_ptr
導致 wave 在 trap 指令處的 PC 停止。相關的佇列會發出訊號以將其置於錯誤狀態。當佇列處於錯誤狀態時,在佇列上執行調度的 waves 將會終止。
llvm.debugtrap
s_trap 0x03
none
如果未啟用偵錯器,則行為如同 no-operation。trap handler 會進入並立即返回以繼續執行 wavefront。
如果已啟用偵錯器,則會導致偵錯器報告 debug trap,並且 wavefront 會在指令處的 PC 進入 halt 狀態。偵錯器必須增加 PC 並恢復 wave。
保留
s_trap 0x04
保留。
保留
s_trap 0x05
保留。
保留
s_trap 0x06
保留。
保留
s_trap 0x07
保留。
保留
s_trap 0x08
保留。
保留
s_trap 0xfe
保留。
保留
s_trap 0xff
保留。
表 87 AMDGPU Trap Handler for AMDHSA OS Code Object V4 及更高版本¶ 用法
程式碼序列
GFX6-GFX8 輸入
GFX9-GFX11 輸入
描述
保留
s_trap 0x00
硬體保留。
偵錯器中斷點
s_trap 0x01
none
none
保留供偵錯器用於中斷點。導致 wave 在 trap 指令處的 PC 停止。偵錯器負責恢復 wave,包括中斷點覆寫的指令。
llvm.trap
s_trap 0x02
SGPR0-1
:
queue_ptr
none
導致 wave 在 trap 指令處的 PC 停止。相關的佇列會發出訊號以將其置於錯誤狀態。當佇列處於錯誤狀態時,在佇列上執行調度的 waves 將會終止。
llvm.debugtrap
s_trap 0x03
none
none
如果未啟用偵錯器,則行為如同 no-operation。trap handler 會進入並立即返回以繼續執行 wavefront。
如果已啟用偵錯器,則會導致偵錯器報告 debug trap,並且 wavefront 會在指令處的 PC 進入 halt 狀態。偵錯器必須增加 PC 並恢復 wave。
保留
s_trap 0x04
保留。
保留
s_trap 0x05
保留。
保留
s_trap 0x06
保留。
保留
s_trap 0x07
保留。
保留
s_trap 0x08
保留。
保留
s_trap 0xfe
保留。
保留
s_trap 0xff
保留。
呼叫慣例¶
注意
本節目前尚未完成且存在不準確之處。這是 WIP,將在確定資訊後更新。
請參閱 位址空間識別碼 以取得關於 swizzled 位址的資訊。Unswizzled 位址是正常的線性位址。
核心函數¶
本節描述外部核心函數的呼叫慣例 ABI。
請參閱 初始核心執行狀態 以取得核心呼叫慣例。
以下內容不是 AMDGPU 核心呼叫慣例的一部分,但描述了 AMDGPU 如何實作函數呼叫
Clang 決定 kernarg layout 以符合《HSA Programmer’s Language Reference》[HSA]。
所有 structs 都直接傳遞。
Lambda 值以 TBA 方式傳遞。
核心在其序言中執行某些設定,如 核心序言 中所述。
非核心函數¶
本節描述外部核心函數以外的函數的呼叫慣例 ABI。
如果核心具有函數呼叫,則始終會分配 scratch 並將其用於呼叫堆疊,該堆疊使用 swizzled scratch 位址空間從低位址成長到高位址。
在進入函數時
SGPR0-3 包含具有以下屬性的 V#(請參閱 私有區段 Buffer)
指向 wavefront scratch 後備記憶體開頭的基準位址。
以 dword 元素大小和 wavefront size 元素步幅進行 swizzled。
已設定 FLAT_SCRATCH 暫存器對。請參閱 Flat Scratch。
GFX6-GFX8:M0 暫存器設定為 LDS 的大小 (以位元組為單位)。請參閱 M0。
EXEC 暫存器設定為進入函數時活動的 lanes。
MODE 暫存器:TBD
VGPR0-31 和 SGPR4-29 用於傳遞函數輸入引數,如下所述。
SGPR30-31 返回位址 (RA)。函數完成時必須返回的程式碼位址。如果函數為 no return,則值未定義。
SGPR32 用於堆疊指標 (SP)。它是相對於 wavefront scratch 後備記憶體開頭的 unswizzled scratch 偏移。
unswizzled SP 可以與 buffer 指令一起使用,作為具有 SGPR0-3 中 scratch V# 的 unswizzled SGPR 偏移,以 swizzled 方式存取堆疊。
unswizzled SP 值可以透過以下方式轉換為 swizzled SP 值
swizzled SP = unswizzled SP / wavefront size這可以用於取得堆疊物件的私有位址空間位址,並透過新增 flat scratch aperture 基準位址將此位址轉換為 flat 位址。
對於
r600
架構,swizzled SP 值始終為 4 位元組對齊,對於amdgcn
架構,則為 16 位元組對齊。注意
amdgcn
值被選擇為避免 OpenCL 語言的動態堆疊對齊,OpenCL 語言將最大基本類型定義為 16 個位元組。在進入時,swizzled SP 值是在堆疊上傳遞的第一個函數引數的位址。其他堆疊傳遞的引數是從進入 swizzled SP 值開始的正偏移量。
函式可能會使用超出最後一個堆疊傳遞引數的正向偏移量,以用於堆疊配置的區域變數和暫存器溢出槽。如有必要,函式可能會將這些對齊到大於 16 位元組的對齊方式。在這些之後,函式可能會動態分配空間,以用於諸如運行時大小的
alloca
區域分配。如果函式呼叫另一個函式,它會將任何堆疊配置的引數放置在最後一個區域分配之後,並調整 SGPR32 至最後一個區域分配之後的位址。
所有其他暫存器皆未指定。
任何必要的
s_waitcnt
皆已執行,以確保記憶體可供函式使用。在 C ABI 中,結構 (struct) 引數請使用傳參考 (pass-by-reference, byref) 而非傳值 (pass-by-value, byval)。被呼叫者 (Callee) 負責分配堆疊記憶體,並在結構被修改時複製結構的值。請注意,後端 (backend) 仍然支援結構引數的傳值 (byval)。
從函式退出時
VGPR0-31 和 SGPR4-29 用於傳遞函式結果引數,如下所述。任何使用的暫存器都被視為被覆寫 (clobbered) 的暫存器。
以下暫存器會被保留,並具有與進入時相同的值
FLAT_SCRATCH
EXEC
GFX6-GFX8: M0
除了 SGPR4-31 中被覆寫的暫存器之外,所有 SGPR 暫存器。
VGPR40-47
VGPR56-63
VGPR72-79
VGPR88-95
VGPR104-111
VGPR120-127
VGPR136-143
VGPR152-159
VGPR168-175
VGPR184-191
VGPR200-207
VGPR216-223
VGPR232-239
VGPR248-255
注意
除了引數暫存器之外,被覆寫的 VGPR 和被保留的暫存器會以規律的間隔交錯,以便保持相似的比率,且不受已分配 VGPR 數量的影響。
GFX90A: 除了 AGPR0-31 中被覆寫的暫存器之外,所有 AGPR 暫存器。
在呼叫點處非作用中之所有 VGPR 的通道 (Lanes)。
對於 AMDGPU 後端,程序間暫存器分配 (Inter-Procedural Register Allocation, IPRA) 優化可能會將某些被覆寫的 SGPR 和 VGPR 暫存器標記為已保留,如果可以確定被呼叫的函式不會更改它們的值。
PC 會設定為進入時提供的 RA。
MODE 暫存器:待定。
所有其他暫存器皆被覆寫。
任何必要的
s_waitcnt
皆已執行,以確保函式存取的記憶體可供呼叫者 (caller) 使用。
函式輸入引數由來源語言函式明確宣告的形式引數,以及實作使用的隱含輸入引數組成。
來源語言輸入引數為
任何來源語言的隱含
this
或self
引數都首先以指標類型出現。接著是函式的形式引數,依據來源順序由左至右排列。
來源語言結果引數為
函式結果引數。
小於或等於 16 位元組的來源語言輸入或結果結構類型引數,會遞迴地分解為其基本類型欄位,並且每個欄位都像獨立的引數一樣傳遞。對於輸入引數,如果被呼叫的函式要求結構位於記憶體中,例如因為要取得其位址,則函式主體負責分配堆疊位置,並將欄位引數複製到其中。Clang 將此稱為直接結構 (direct struct)。
大於 16 位元組的來源語言輸入結構類型引數,會以傳參考方式傳遞。呼叫者負責分配堆疊位置以建立結構值的副本,並將位址作為輸入引數傳遞。被呼叫的函式負責在存取輸入引數時執行解參考 (dereference)。Clang 將此稱為傳值結構 (by-value struct)。
大於 16 位元組的來源語言結果結構類型引數,會以傳參考方式傳回。呼叫者負責分配堆疊位置以保存結果值,並將位址作為最後一個輸入引數 (在隱含輸入引數之前) 傳遞。在這種情況下,沒有結果引數。被呼叫的函式負責在儲存結果值時執行解參考。Clang 將此稱為結構化返回 (structured return, sret)。
待辦事項:更正 ``sret`` 定義。
Lambda 引數類型被視為具有實作定義欄位集的結構類型。
對於 AMDGPU 後端,除非標記為 inreg
(在這種情況下,它們會在 SGPR 中傳遞),否則所有來源語言引數 (包括分解的結構類型引數) 都會在 VGPR 中傳遞。
AMDGPU 後端從葉節點開始遍歷函式呼叫圖,以確定使用了哪些隱含輸入引數,並傳播到函式的每個呼叫者。已使用的隱含引數會按照以下順序附加到來源語言引數之後的函式引數中
工作項目 ID (Work-Item ID) (1 個 VGPR)
X、Y 和 Z 工作項目 ID 被封裝到具有以下佈局的單個 VGRP 中。僅設定函式實際使用的欄位。其他位元未定義。
這些值來自初始核心執行狀態。請參閱 初始核心執行狀態。
表 88 工作項目隱含引數佈局¶ 位元
大小
欄位名稱
9:0
10 位元
X 工作項目 ID
19:10
10 位元
Y 工作項目 ID
29:20
10 位元
Z 工作項目 ID
31:30
2 位元
未使用
分派指標 (Dispatch Ptr) (2 個 SGPR)
該值來自初始核心執行狀態。請參閱 SGPR 暫存器設定順序。
佇列指標 (Queue Ptr) (2 個 SGPR)
該值來自初始核心執行狀態。請參閱 SGPR 暫存器設定順序。
核心引數區段指標 (Kernarg Segment Ptr) (2 個 SGPR)
該值來自初始核心執行狀態。請參閱 SGPR 暫存器設定順序。
分派 ID (Dispatch ID) (2 個 SGPR)
該值來自初始核心執行狀態。請參閱 SGPR 暫存器設定順序。
工作群組 ID X (Work-Group ID X) (1 個 SGPR)
該值來自初始核心執行狀態。請參閱 SGPR 暫存器設定順序。
工作群組 ID Y (Work-Group ID Y) (1 個 SGPR)
該值來自初始核心執行狀態。請參閱 SGPR 暫存器設定順序。
工作群組 ID Z (Work-Group ID Z) (1 個 SGPR)
該值來自初始核心執行狀態。請參閱 SGPR 暫存器設定順序。
隱含引數指標 (Implicit Argument Ptr) (2 個 SGPR)
該值是透過將偏移量加到核心引數區段指標 (Kernarg Segment Ptr) 來計算,以取得指向第一個核心引數隱含引數的全域位址空間指標。
輸入和結果引數會依以下方式依序分配
注意
以下描述可能存在一些錯誤和遺漏,需要更正。
VGPR 引數會分配給從 VGPR0 開始到 VGPR31 的連續 VGPR。
如果引數數量超過這些暫存器可以容納的數量,則剩餘的引數會依序分配在堆疊上,並位於自然對齊的位址。
SGPR 引數會分配給從 SGPR0 開始到 SGPR29 的連續 SGPR。
如果引數數量超過這些暫存器可以容納的數量,則剩餘的引數會依序分配在堆疊上,並位於自然對齊的位址。
請注意,分解的結構類型引數可能會有部分欄位在暫存器中傳遞,而部分在記憶體中傳遞。
以下內容並非 AMDGPU 函式呼叫慣例的一部分,而是描述 AMDGPU 如何實作函式呼叫
如有必要,SGPR33 會用作框架指標 (Frame Pointer, FP)。與 SP 類似,它是一個未混合 (unswizzled) 的 scratch 位址。只有在使用運行時大小的
alloca
,或基於SIFrameLowering
中定義的原因時,才需要它。支援運行時堆疊對齊。SGPR34 用作基底指標 (Base Pointer, BP),以存取函式中傳入的堆疊引數。只有當函式需要運行時堆疊對齊時,才需要 BP。
不支援在堆疊上分配 SGPR 引數。
目前未產生 CFI。請參閱 A.6.4 呼叫框架資訊。
注意
將會產生 CFI,其將 CFA 定義為未混合 (unswizzled) 位址,該位址相對於最低位址堆疊配置區域變數之未混合私有位址空間中的 wave scratch 基底。
DW_AT_frame_base
將定義為混合 (swizzled) 私有位址空間中的混合位址,方法是將 CFA 除以 wavefront 大小 (因為 CFA 始終至少是 dword 對齊,這與 scratch 混合元素大小相符)。如果未執行動態堆疊對齊,則堆疊配置的引數會作為相對於
DW_AT_frame_base
的負向偏移量存取,而區域變數和暫存器溢出槽會作為相對於DW_AT_frame_base
的正向偏移量存取。函式引數傳遞的實作方式是在進入時將輸入實體暫存器複製到虛擬暫存器。暫存器分配器可以在必要時溢出 (spill)。這些會在呼叫點處複製回實體暫存器。最終結果是,每次函式呼叫都可能在完全不同的位置擁有這些值。IPRA 可以幫助避免混洗 (shuffling) 引數暫存器。
呼叫點的實作方式是在相對於 SP 的正向偏移量處設定引數。然後,在呼叫之前遞增 SP 以考慮已知的框架大小,並在呼叫之後遞減 SP。
注意
CFI 將反映從 SP 計算 CFA 所需的已變更計算。
堆疊框架中使用 4 位元組的溢出槽。分配一個槽作為緊急溢出槽。緩衝區指令用於堆疊存取,而不是
flat_scratch
指令。
AMDPAL¶
本節提供目標三元組 (target triple) OS 為 amdpal
時使用的程式碼慣例 (請參閱 目標三元組)。
程式碼物件元資料 (Code Object Metadata)¶
注意
元資料目前正在開發中,並且可能會進行重大變更。僅支援目前版本。當產生此文件時,版本為 2.6。
程式碼物件元資料由 NT_AMDGPU_METADATA
註記記錄指定 (請參閱 程式碼物件 V3 及更高版本註記記錄)。
元資料表示為 Message Pack 格式化的二進制資料 (請參閱 [MsgPack])。頂層是一個 Message Pack 映射 (map),其中包含表 AMDPAL 程式碼物件元資料映射 和參考表格中定義的鍵 (keys)。
其他資訊可以添加到映射中。為避免衝突,任何金鑰名稱都應以 “vendor-name.” 為前綴,其中 vendor-name
可以是供應商名稱和產生資訊的特定供應商工具的名稱。當前綴出現在由同一 vendor-name 添加的映射中時,前綴簡稱為 “.”。
表 89 AMDPAL 程式碼物件元資料映射¶ 字串金鑰 (String Key)
值類型 (Value Type)
是否必填?
描述
“amdpal.version”
2 個整數的序列 (sequence)
必填
PAL 程式碼物件元資料 (主要、次要) 版本。目前值由 Util::Abi::PipelineMetadata(Major|Minor)Version 定義。
“amdpal.pipelines”
映射序列
必填
每個管線 (pipeline) 的元資料。有關該映射中包含的鍵的定義,請參閱 AMDPAL 程式碼物件管線元資料映射。
表 90 AMDPAL 程式碼物件管線元資料映射¶ 字串金鑰 (String Key)
值類型 (Value Type)
是否必填?
描述
“.name” (名稱)
字串
管線的來源名稱。
“.type”
字串
管線類型,例如 VsPs。值包括
“VsPs”
“Gs”
“Cs”
“Ngg”
“Tess”
“GsTess”
“NggTess”
“.internal_pipeline_hash”
2 個整數的序列 (sequence)
必填
此管線的內部編譯器雜湊值。較低的 64 位元是雜湊的「穩定」部分,用於例如著色器替換查找。較高的 64 位元是雜湊的「唯一」部分,用於例如管線快取查找。該值由實作定義,並且不能在編譯器的不同建置版本之間依賴。
“.shaders”
映射 (map)
每個 API 著色器 (shader) 的元資料。有關該映射中包含的鍵的定義,請參閱 AMDPAL 程式碼物件著色器映射。
“.hardware_stages”
映射 (map)
每個硬體階段 (hardware stage) 的元資料。有關該映射中包含的鍵的定義,請參閱 AMDPAL 程式碼物件硬體階段映射。
“.shader_functions”
映射 (map)
每個著色器函式 (shader function) 的元資料。有關該映射中包含的鍵的定義,請參閱 AMDPAL 程式碼物件著色器函式映射。
“.registers”
映射 (map)
必填
硬體暫存器配置。有關該映射中包含的鍵的定義,請參閱 AMDPAL 程式碼物件暫存器映射。
“.user_data_limit”
整數
此管線存取的使用者資料條目 (user data entries) 數量。
“.spill_threshold”
整數
使用者資料溢出閾值 (user data spill threshold)。0xFFFF 表示 NoUserDataSpilling。
“.uses_viewport_array_index”
布林值
指示管線是否使用視口陣列索引 (viewport array index) 功能。使用此功能的管線可以渲染到所有 16 個視口,而不使用此功能的管線則限制為視口 #0。
“.es_gs_lds_size”
整數
內部用於處理 ES 和 GS 著色器階段之間資料傳遞的 LDS 空間大小 (以位元組為單位)。如果資料是使用晶片外 (off-chip) 緩衝區傳遞的,則此值可以為零。此值應用於程式設計所有標記為 “UserDataMapping::EsGsLdsSize” 的 user-SGPR (通常只有 GS 和 VS HW 階段會有如此標記的 user-SGPR)。
“.nggSubgroupSize”
整數
NGG 著色器的明確最大子群組大小 (subgroup size) (子群組中的最大執行緒數)。
“.num_interpolants”
整數
僅限圖形。PS 插值器 (interpolants) 的數量。
“.mesh_scratch_memory_size”
整數
使用的最大網格著色器 (mesh shader) scratch 記憶體。
“.api”
字串
客戶端圖形 API 的名稱。
“.api_create_info”
二進制 (binary)
圖形 API 著色器建立資訊二進制 blob。如果驅動程式想要能夠在稍後關聯建立期間使用的 API 特定資訊,則可以使用編譯器定義它。
表 91 AMDPAL 程式碼物件著色器映射¶ 字串金鑰 (String Key)
值類型 (Value Type)
描述
“.compute”
“.vertex”
“.hull”
“.domain”
“.geometry”
“.pixel”
映射 (map)
有關該映射中包含的鍵的定義,請參閱 AMDPAL 程式碼物件 API 著色器元資料映射。
表 92 AMDPAL 程式碼物件 API 著色器元資料映射¶ 字串金鑰 (String Key)
值類型 (Value Type)
是否必填?
描述
“.api_shader_hash”
2 個整數的序列 (sequence)
必填
輸入著色器雜湊值,通常從客戶端傳入。該值由實作定義,並且不能在編譯器的不同建置版本之間依賴。
“.hardware_mapping”
字串序列
必填
標記,指示此 API 著色器映射到的 HW 階段。值包括
“.ls”
“.hs”
“.es”
“.gs”
“.vs”
“.ps”
“.cs”
表 93 AMDPAL 程式碼物件硬體階段映射¶ 字串金鑰 (String Key)
值類型 (Value Type)
描述
“.ls”
“.hs”
“.es”
“.gs”
“.vs”
“.ps”
“.cs”
映射 (map)
有關該映射中包含的鍵的定義,請參閱 AMDPAL 程式碼物件硬體階段元資料映射。
表 94 AMDPAL 程式碼物件硬體階段元資料映射¶ 字串金鑰 (String Key)
值類型 (Value Type)
是否必填?
描述
“.entry_point”
字串
指向此管線階段進入點的 ELF 符號。
“.scratch_memory_size”
整數
Scratch 記憶體大小,以位元組為單位。
“.lds_size”
整數
本地資料共享 (Local Data Share) 大小,以位元組為單位。
“.perf_data_buffer_size”
整數
效能資料緩衝區大小,以位元組為單位。
“.vgpr_count” (VGPR 數量)
整數
使用的 VGPR 數量。
“.agpr_count” (AGPR 數量)
整數
使用的 AGPR 數量。
“.sgpr_count” (SGPR 數量)
整數
使用的 SGPR 數量。
“.vgpr_limit”
整數
如果非零,則表示著色器在編譯時使用了指令,指示編譯器將 VGPR 使用量限制為小於或等於指定值 (僅在與 HW 預設值不同時設定)。
“.sgpr_limit”
整數
SGPR 計數上限 (僅在與 HW 預設值不同時設定)。
“.threadgroup_dimensions”
3 個整數的序列
執行緒群組 (Thread-group) X/Y/Z 維度 (僅限計算)。
“.wavefront_size” (波前大小)
整數
Wavefront 大小 (僅在與 HW 預設值不同時設定)。
“.uses_uavs”
布林值
著色器讀取或寫入 UAV。
“.uses_rovs”
布林值
著色器讀取或寫入 ROV。
“.writes_uavs”
布林值
著色器寫入一個或多個 UAV。
“.writes_depth”
布林值
著色器寫出深度值。
“.uses_append_consume”
布林值
著色器使用 append 和/或 consume 操作,無論是記憶體還是 GDS。
“.uses_prim_id”
布林值
著色器使用 PrimID。
表 95 AMDPAL 程式碼物件著色器函式映射¶ 字串金鑰 (String Key)
值類型 (Value Type)
描述
符號名稱
映射 (map)
符號名稱 是著色器函式程式碼進入位址的 ELF 符號名稱。該值是函式的元資料。請參閱 AMDPAL 程式碼物件著色器函式元資料映射。
表 96 AMDPAL 程式碼物件著色器函式元資料映射¶ 字串金鑰 (String Key)
值類型 (Value Type)
描述
“.api_shader_hash”
2 個整數的序列 (sequence)
輸入著色器雜湊值,通常從客戶端傳入。該值由實作定義,並且不能在編譯器的不同建置版本之間依賴。
“.scratch_memory_size”
整數
著色器使用的 scratch 記憶體大小,以位元組為單位。
“.lds_size”
整數
LDS 記憶體大小,以位元組為單位。
“.vgpr_count” (VGPR 數量)
整數
著色器使用的 VGPR 數量。
“.sgpr_count” (SGPR 數量)
整數
著色器使用的 SGPR 數量。
“.stack_frame_size_in_bytes”
整數
著色器使用的堆疊大小量。
“.shader_subtype”
字串
著色器子類型/種類。值包括
“Unknown”
表 97 AMDPAL 程式碼物件暫存器映射¶ 32 位元整數鍵
值類型 (Value Type)
描述
reg offset
32 位元整數
reg offset
是 GRBM 暫存器的 dword 偏移量,位於 GFXIP 暫存器空間中 (即,驅動程式可存取的 GPU 暫存器編號,而非著色器 GPR 暫存器編號)。驅動程式需要在執行此管線時,將每個指定的暫存器程式設計為對應的指定值。通常,reg offsets
是硬體晶片標頭定義的每個暫存器的uint16_t
偏移量。暫存器會設定為提供的值。但是,指定使用者資料暫存器 (例如,COMPUTE_USER_DATA_0) 的reg offset
需要特殊處理。有關更多資訊,請參閱 使用者資料 節。
使用者資料 (User Data)¶
每個硬體階段都有一組 32 位元實體 SPI 使用者資料暫存器 (根據圖形 IP 和階段,可以是 16 個或 32 個),這些暫存器可以從命令緩衝區寫入,然後在透過後續分派或繪圖操作啟動 wave 時載入到 SGPR 中。這是將大多數引數從應用程式/運行時傳遞到硬體著色器的方式。
PAL 透過公開每個管線一組 128 個使用者資料條目來抽象化此功能,客戶端可以使用這些條目將引數從命令緩衝區傳遞到該管線中的一個或多個著色器。ELF 程式碼物件必須指定從虛擬化使用者資料條目到實體使用者資料暫存器的映射,而 PAL 負責實作該映射,包括在需要時將溢出的使用者資料條目溢出到記憶體。
由於使用者資料暫存器是 GRBM 可存取的 SPI 暫存器,因此此映射實際上嵌入在 .registers
元資料條目中。對於大多數暫存器,該映射中的值是一個字面 32 位元值,應由驅動程式寫入到暫存器中。但是,當暫存器是使用者資料暫存器 (任何 USER_DATA 暫存器,例如 SPI_SHADER_USER_DATA_PS_5) 時,該值實際上是一個編碼,告訴驅動程式將使用者資料條目值或幾個驅動程式內部值之一寫入到暫存器中。此編碼在下表中描述
注意
目前,使用者資料暫存器 0 和 1 (例如,SPI_SHADER_USER_DATA_PS_0 和 SPI_SHADER_USER_DATA_PS_1) 已保留。使用者資料暫存器 0 必須始終程式設計為 GlobalTable 的位址,而使用者資料暫存器 1 必須始終程式設計為 PerShaderTable 的位址。
表 98 AMDPAL 使用者資料映射¶ 值
名稱
描述
0..127
使用者資料條目 (User Data Entry)
透過 CmdSetUserData() 指定的 user_data_entry[N] 的 32 位元值
0x10000000
GlobalTable
指向 GPU 記憶體的 32 位元指標,其中包含全域內部表 (應始終指向使用者資料暫存器 0)。
0x10000001
PerShaderTable
指向 GPU 記憶體的 32 位元指標,其中包含每個著色器的內部表。有關更多詳細資訊,請參閱 每個著色器表 (應始終指向使用者資料暫存器 1)。
0x10000002
SpillTable
指向 GPU 記憶體的 32 位元指標,其中包含使用者資料溢出表。有關更多詳細資訊,請參閱 溢出表。
0x10000003
BaseVertex
頂點偏移量 (Vertex offset) (32 位元無號整數)。如果管線未在頂點著色器中參考繪圖索引,則不需要。僅圖形管線的第一階段支援。
0x10000004
BaseInstance
實例偏移量 (Instance offset) (32 位元無號整數)。僅圖形管線的第一階段支援。
0x10000005
DrawIndex
繪圖索引 (Draw index) (32 位元無號整數)。僅圖形管線的第一階段支援。
0x10000006
Workgroup
執行緒群組計數 (Thread group count) (32 位元無號整數)。包含 Compute 分派操作網格維度的緩衝區之 64 位元位址的低半部分。位址的高半部分儲存在下一個循序 user-SGPR 中。僅計算管線支援。
0x1000000A
EsGsLdsSize
指示 PAL 將程式設計此 user-SGPR 以包含用於 ES/GS 偽環形緩衝區的 LDS 空間量,以便在著色器階段之間傳遞資料。
0x1000000B
ViewId
視圖 ID (View id) (32 位元無號整數) 識別圖形管線實例化的視圖。
0x1000000C
StreamOutTable
指向 GPU 記憶體的 32 位元指標,其中包含 stream out 目標 SRD 表。每個管線只能出現一個著色器階段。
0x1000000D
PerShaderPerfData
指向 GPU 記憶體的 32 位元指標,其中包含每個著色器的效能資料緩衝區。
0x1000000F
VertexBufferTable
指向 GPU 記憶體的 32 位元指標,其中包含頂點緩衝區 SRD 表。每個管線只能出現一個著色器階段。
0x10000010
UavExportTable
指向 GPU 記憶體的 32 位元指標,其中包含 UAV 匯出 SRD 表。每個管線只能出現一個著色器階段 (PS)。這些取代顏色目標,並且與著色器使用的任何 UAV 完全分離。這是可選的,僅當使用 UAV 匯出取代顏色目標匯出以優化特定著色器時,才由 PS 使用。
0x10000011
NggCullingData
指向 GPU 記憶體的 64 位元指標,其中包含某些 NGG 管線執行剔除 (culling) 所需的硬體暫存器資料。此值包含提供完整 GPU 位址的兩個連續暫存器中的第一個的位址。
0x10000015
FetchShaderPtr
指向 GPU 記憶體的 64 位元指標,其中包含 fetch shader 副程式。
每個著色器表 (Per-Shader Table)¶
ELF 的 .data
區段中可選緩衝區的 GPU 位址的低 32 位元。位址的高 32 位元與著色器的程式計數器的高 32 位元相符。
緩衝區可以是著色器編譯器所需的任何內容,並允許每個著色器擁有自己的 .data
區段區域。通常,這可以是緩衝區 SRD 的表和緩衝區 SRD 指向的資料,但也可能是平坦位址 (flat-address) 的記憶體區域。其佈局和用法由著色器編譯器定義。
每個著色器在 .data
區段中的表都由符號 _amdgpu_
xs_shdr_intrl_data
參考,其中 xs 對應於資料所屬的硬體著色器階段。例如,計算著色器硬體階段的 _amdgpu_cs_shdr_intrl_data
。
溢出表 (Spill Table)¶
硬體著色器可能需要存取比一個或多個硬體著色器階段的使用者資料暫存器中可用槽更多的使用者資料條目。在這種情況下,PAL 運行時預期必要的使用者資料條目會溢出到 GPU 記憶體,並使用一個使用者資料暫存器指向溢出的使用者資料記憶體。然後,使用者資料條目的值必須表示著色器預期讀取表的 GPU 虛擬位址的低 32 位元的位置。溢出表本身表示 PAL 運行時在 GPU 可存取記憶體中管理的一組 32 位元值,這些值可以間接存取硬體著色器。
未指定的 OS (Unspecified OS)¶
本節提供目標三元組 OS 為空時使用的程式碼慣例 (請參閱 目標三元組)。
陷阱處理常式 ABI (Trap Handler ABI)¶
對於 AMDGPU 後端為非 amdhsa OS 產生的程式碼物件,運行時不會安裝陷阱處理常式。llvm.trap
和 llvm.debugtrap
指令的處理方式如下
表 99 非 AMDHSA OS 的 AMDGPU 陷阱處理常式¶ 用法
程式碼序列
描述
llvm.trap
s_endpgm
導致 wavefront 終止。
llvm.debugtrap
none
由於未安裝陷阱處理常式,因此發出編譯器警告。
核心檔案格式 (Core file format)¶
本節描述支援 AMDGPU 的核心檔案格式。AMDGPU 程式的核心轉儲 (core dumps) 可以分為 2 種:分割或統一核心檔案。
分割佈局由一個主機核心檔案 (host core file) 組成,其中包含重建主機進程映像的資訊;以及一個 AMDGPU 核心檔案,其中包含進程中使用的 AMDGPU agent 的資訊。AMDGPU 核心檔案由以下組成
描述進程的 AMDGPU agent、AMDGPU 佇列和 AMDGPU 運行時狀態的註記 (請參閱 核心檔案註記)。
包含 AMDGPU agent 記憶體映像的載入區段 (load segments) 列表 (請參閱 記憶體區段)。
統一核心檔案是分割佈局的兩個檔案中包含的所有資訊 (所有註記和載入區段) 的聯集。它包含重建跨所有 agent 的進程映像所需的所有資訊。
核心檔案標頭¶
AMDGPU 核心檔案是一種 ELF64
核心檔案。標頭的內容在統一核心檔案佈局和 AMDGPU 核心檔案佈局中有所不同。
分割檔案¶
在分割檔案佈局中,AMDGPU 核心檔案是一個 ELF64
檔案,其標頭配置如AMDGPU 核心檔案標頭中所述
表 100 AMDGPU 核心檔案標頭¶ 欄位
值
e_ident[EI_CLASS]
ELFCLASS64
(0x2
)
e_ident[EI_DATA]
ELFDATA2LSB
(0x1
)
e_ident[EI_OSABI]
ELFOSABI_AMDGPU_HSA
(0x40
)
e_type
ET_CORE``(``0x4
)
e_ident[EI_ABIVERSION]
ELFABIVERSION_AMDGPU_HSA_5
e_machine
EM_AMDGPU
(0xe0
)
統一檔案¶
在統一核心檔案模式下,ELF64
標頭設定為描述主機架構和程序。
核心檔案註記¶
AMDGPU 核心檔案必須在 PT_NOTE
段中包含一個快照註記。當使用分割核心檔案佈局時,此註記位於 AMDGPU 檔案中。
註記記錄供應商欄位為 “AMDGPU
”,記錄類型為 “NT_AMDGPU_KFD_CORE_STATE
”(請參閱程式碼物件 V3 及更高版本的註記記錄)
註記的內容在表AMDGPU 快照註記格式 V1中定義
表 101 AMDGPU 快照註記格式 V1¶ 欄位
類型
大小 (位元組)
位元組對齊
註解
version_major
uint32
4
4
KFD_IOCTL_MAJOR_VERSION
version_minor
uint32
4
4
KFD_IOCTL_MINOR_VERSION
runtime_info_size
uint64
8
8
必須是 8 的倍數
n_agents
uint32
4
8
agent_info_entry_size
uint32
4
4
必須是 8 的倍數
n_queues
uint32
4
8
queue_info_entry_size
uint32
4
4
必須是 8 的倍數
runtime_info
kfd_runtime_info
runtime_info_size
8
agents_info
kfd_dbg_device_info_entry[n_agents]
n_agents * agent_info_entry_size
8
queues_info
kfd_queue_snapshot_entry[n_queues]
n_queues * queue_info_entry_size
8
所有 kfd_*
類型的定義都來自 KFD 儲存庫中的 include/uapi/linux/kfd_ioctl.h
標頭檔。它通常安裝在 /usr/include/linux/kfd_ioctl.h
中。使用的 kfd_ioctl.h
檔案版本必須為 KFD_IOCTL_MAJOR_VERSION
和 KFD_IOCTL_MINOR_VERSION
定義值,以符合註記中的 kfd_version_major
和 kfd_version_major
值。
記憶體段¶
AMDGPU 核心檔案必須在載入段(類型為 PT_LOAD
)中包含 AMDGPU 代理程式記憶體的映像。這些段必須對應於代理程式記憶體的內容透過 ROCr 執行階段對應到主機程序的記憶體區域(請注意,這些記憶體對應通常對於程序本身是不可讀取的)。
當使用分割核心檔案佈局時,這些段必須包含在 AMDGPU 核心檔案中。
原始碼語言¶
OpenCL¶
當語言為 OpenCL 時,會發生以下差異
使用 OpenCL 記憶體模型(請參閱記憶體模型)。
AMDGPU 後端會為 AMDHSA 作業系統將額外的引數附加到核心的顯式引數中(請參閱為 AMDHSA 作業系統附加的 OpenCL 核心隱式引數)。
產生額外的元數據(請參閱程式碼物件元數據)。
表 102 為 AMDHSA 作業系統附加的 OpenCL 核心隱式引數¶ 位置
位元組大小
位元組對齊
描述
1
8
8
OpenCL 全域偏移 X
2
8
8
OpenCL 全域偏移 Y
3
8
8
OpenCL 全域偏移 Z
4
8
8
printf 緩衝區的 OpenCL 位址
5
8
8
enqueue_kernel 使用的虛擬佇列的 OpenCL 位址。
6
8
8
enqueue_kernel 使用的 AqlWrap 結構的 OpenCL 位址。
7
8
8
用於多網格同步的指標引數。
HCC¶
當語言為 HCC 時,會發生以下差異
使用 HSA 記憶體模型(請參閱記憶體模型)。
組譯器¶
AMDGPU 後端具有基於 LLVM-MC 的組譯器,目前正在開發中。它支援 AMDGCN GFX6-GFX11。
本節介紹指令和運算元的一般語法。
指令¶
指令具有以下語法
<
opcode> <
operand0>, <
operand1>,... <
modifier0> <
modifier1>...
運算元和修飾符的順序是固定的。大多數修飾符是可選的,可以省略。
詳細指令語法描述的連結可以在下表中找到。請注意,開發中的功能不包含在此描述中。
架構
核心 ISA
ISA 變體和擴充功能
GCN 2
-
GCN 3, GCN 4
-
GCN 5
CDNA 1
CDNA 2
CDNA 3
RDNA 1
RDNA 2
RDNA 3
有關指令、其語義和支援的運算元組合的更多資訊,請參閱指令集架構手冊[AMD-GCN-GFX6]、[AMD-GCN-GFX7]、[AMD-GCN-GFX8]、[AMD-GCN-GFX900-GFX904-VEGA]、[AMD-GCN-GFX906-VEGA7NM]、[AMD-GCN-GFX908-CDNA1]、[AMD-GCN-GFX90A-CDNA2]、[AMD-GCN-GFX942-CDNA3]、[AMD-GCN-GFX10-RDNA1]、[AMD-GCN-GFX10-RDNA2]、[AMD-GCN-GFX11-RDNA3] 和 [AMD-GCN-GFX11-RDNA3.5]。
運算元¶
運算元的詳細描述可以在此處找到。
修飾符¶
修飾符的詳細描述可以在此處找到。
指令範例¶
DS¶
ds_add_u32 v2, v4 offset:16
ds_write_src2_b64 v2 offset0:4 offset1:8
ds_cmpst_f32 v2, v4, v6
ds_min_rtn_f64 v[8:9], v2, v[4:5]
有關支援指令的完整列表,請參閱 ISA 手冊中的「LDS/GDS 指令」。
FLAT¶
flat_load_dword v1, v[3:4]
flat_store_dwordx3 v[3:4], v[5:7]
flat_atomic_swap v1, v[3:4], v5 glc
flat_atomic_cmpswap v1, v[3:4], v[5:6] glc slc
flat_atomic_fmax_x2 v[1:2], v[3:4], v[5:6] glc
有關支援指令的完整列表,請參閱 ISA 手冊中的「FLAT 指令」。
MUBUF¶
buffer_load_dword v1, off, s[4:7], s1
buffer_store_dwordx4 v[1:4], v2, ttmp[4:7], s1 offen offset:4 glc tfe
buffer_store_format_xy v[1:2], off, s[4:7], s1
buffer_wbinvl1
buffer_atomic_inc v1, v2, s[8:11], s4 idxen offset:4 slc
有關支援指令的完整列表,請參閱 ISA 手冊中的「MUBUF 指令」。
SMRD/SMEM¶
s_load_dword s1, s[2:3], 0xfc
s_load_dwordx8 s[8:15], s[2:3], s4
s_load_dwordx16 s[88:103], s[2:3], s4
s_dcache_inv_vol
s_memtime s[4:5]
有關支援指令的完整列表,請參閱 ISA 手冊中的「純量記憶體操作」。
SOP1¶
s_mov_b32 s1, s2
s_mov_b64 s[0:1], 0x80000000
s_cmov_b32 s1, 200
s_wqm_b64 s[2:3], s[4:5]
s_bcnt0_i32_b64 s1, s[2:3]
s_swappc_b64 s[2:3], s[4:5]
s_cbranch_join s[4:5]
有關支援指令的完整列表,請參閱 ISA 手冊中的「SOP1 指令」。
SOP2¶
s_add_u32 s1, s2, s3
s_and_b64 s[2:3], s[4:5], s[6:7]
s_cselect_b32 s1, s2, s3
s_andn2_b32 s2, s4, s6
s_lshr_b64 s[2:3], s[4:5], s6
s_ashr_i32 s2, s4, s6
s_bfm_b64 s[2:3], s4, s6
s_bfe_i64 s[2:3], s[4:5], s6
s_cbranch_g_fork s[4:5], s[6:7]
有關支援指令的完整列表,請參閱 ISA 手冊中的「SOP2 指令」。
SOPC¶
s_cmp_eq_i32 s1, s2
s_bitcmp1_b32 s1, s2
s_bitcmp0_b64 s[2:3], s4
s_setvskip s3, s5
有關支援指令的完整列表,請參閱 ISA 手冊中的「SOPC 指令」。
SOPP¶
s_barrier
s_nop 2
s_endpgm
s_waitcnt 0 ; Wait for all counters to be 0
s_waitcnt vmcnt(0) & expcnt(0) & lgkmcnt(0) ; Equivalent to above
s_waitcnt vmcnt(1) ; Wait for vmcnt counter to be 1.
s_sethalt 9
s_sleep 10
s_sendmsg 0x1
s_sendmsg sendmsg(MSG_INTERRUPT)
s_trap 1
有關支援指令的完整列表,請參閱 ISA 手冊中的「SOPP 指令」。
除非另有說明,否則 SOPP 指令的運算元幾乎不進行驗證,因此程式設計人員應熟悉可接受值的範圍。
VALU¶
對於向量 ALU 指令運算碼(VOP1、VOP2、VOP3、VOPC、VOP_DPP、VOP_SDWA),組譯器將根據其運算元自動使用最佳編碼。若要強制使用特定編碼,可以將後綴添加到指令的運算碼中
_e32 用於 32 位元 VOP1/VOP2/VOPC
_e64 用於 64 位元 VOP3
_dpp 用於 VOP_DPP
_e64_dpp 用於帶 DPP 的 VOP3
_sdwa 用於 VOP_SDWA
VOP1/VOP2/VOP3/VOPC 範例
v_mov_b32 v1, v2
v_mov_b32_e32 v1, v2
v_nop
v_cvt_f64_i32_e32 v[1:2], v2
v_floor_f32_e32 v1, v2
v_bfrev_b32_e32 v1, v2
v_add_f32_e32 v1, v2, v3
v_mul_i32_i24_e64 v1, v2, 3
v_mul_i32_i24_e32 v1, -3, v3
v_mul_i32_i24_e32 v1, -100, v3
v_addc_u32 v1, s[0:1], v2, v3, s[2:3]
v_max_f16_e32 v1, v2, v3
VOP_DPP 範例
v_mov_b32 v0, v0 quad_perm:[0,2,1,1]
v_sin_f32 v0, v0 row_shl:1 row_mask:0xa bank_mask:0x1 bound_ctrl:0
v_mov_b32 v0, v0 wave_shl:1
v_mov_b32 v0, v0 row_mirror
v_mov_b32 v0, v0 row_bcast:31
v_mov_b32 v0, v0 quad_perm:[1,3,0,1] row_mask:0xa bank_mask:0x1 bound_ctrl:0
v_add_f32 v0, v0, |v0| row_shl:1 row_mask:0xa bank_mask:0x1 bound_ctrl:0
v_max_f16 v1, v2, v3 row_shl:1 row_mask:0xa bank_mask:0x1 bound_ctrl:0
VOP3_DPP 範例(適用於 GFX11+)
v_add_f32_e64_dpp v0, v1, v2 dpp8:[0,1,2,3,4,5,6,7]
v_sqrt_f32_e64_dpp v0, v1 row_shl:1 row_mask:0xa bank_mask:0x1 bound_ctrl:0
v_ldexp_f32 v0, v1, v2 dpp8:[0,1,2,3,4,5,6,7]
VOP_SDWA 範例
v_mov_b32 v1, v2 dst_sel:BYTE_0 dst_unused:UNUSED_PRESERVE src0_sel:DWORD
v_min_u32 v200, v200, v1 dst_sel:WORD_1 dst_unused:UNUSED_PAD src0_sel:BYTE_1 src1_sel:DWORD
v_sin_f32 v0, v0 dst_unused:UNUSED_PAD src0_sel:WORD_1
v_fract_f32 v0, |v0| dst_sel:DWORD dst_unused:UNUSED_PAD src0_sel:WORD_1
v_cmpx_le_u32 vcc, v1, v2 src0_sel:BYTE_2 src1_sel:WORD_0
有關支援指令的完整列表,請參閱「向量 ALU 指令」。
程式碼物件 V2 預定義符號¶
警告
此版本的 LLVM 不再支援程式碼物件 V2 生成。
AMDGPU 組譯器會自動定義和更新某些符號。這些符號不會影響程式碼產生。
.option.machine_version_major¶
設定為正在組譯的目標的 GFX 主要世代編號。例如,當為「GFX9」目標組譯時,這將設定為整數值「9」。可能的 GFX 主要世代編號在處理器中呈現。
.option.machine_version_minor¶
設定為正在組譯的目標的 GFX 次要世代編號。例如,當為「GFX810」目標組譯時,這將設定為整數值「1」。可能的 GFX 次要世代編號在處理器中呈現。
.option.machine_version_stepping¶
設定為正在組譯的目標的 GFX 步進世代編號。例如,當為「GFX704」目標組譯時,這將設定為整數值「4」。可能的 GFX 步進世代編號在處理器中呈現。
.kernel.vgpr_count¶
每次遇到 .amdgpu_hsa_kernel (名稱) 指令時,都會設定為零。在每個指令中,如果此符號的目前值小於或等於該指令中明確引用的最大 VGPR 編號,則符號值會更新為等於該 VGPR 編號加一。
.kernel.sgpr_count¶
每次遇到 .amdgpu_hsa_kernel (名稱) 指令時,都會設定為零。在每個指令中,如果此符號的目前值小於或等於該指令中明確引用的最大 VGPR 編號,則符號值會更新為等於該 SGPR 編號加一。
程式碼物件 V2 指令¶
警告
此版本的 LLVM 不再支援程式碼物件 V2 生成。
AMDGPU ABI 在輸出程式碼物件中定義輔助資料。在組譯原始碼中,可以使用組譯器指令指定它們。
.hsa_code_object_version major, minor¶
major 和 minor 是整數,用於指定組譯器將產生的 HSA 程式碼物件的版本。
.hsa_code_object_isa [major, minor, stepping, vendor, arch]¶
major、minor 和 stepping 都是描述組譯程式的指令集架構 (ISA) 版本的整數。
vendor 和 arch 是帶引號的字串。vendor 應始終等於 “AMD”,而 arch 應始終等於 “AMDGPU”。
預設情況下,組譯器將從傳遞給組譯器的 -mcpu 選項的值中衍生 ISA 版本、vendor 和 arch。
.amdgpu_hsa_kernel (name)¶
此指令指定具有給定名稱的符號是核心進入點(標籤),並且物件應包含 STT_AMDGPU_HSA_KERNEL 類型的對應符號。
.amd_kernel_code_t¶
此指令標記用於指定組譯器將發出的 amd_kernel_code_t 物件的鍵/值對列表的開始。列表必須以 .end_amd_kernel_code_t 指令終止。對於任何未指定的 amd_kernel_code_t 值,將使用預設值。所有鍵的預設值為 0,但以下例外
amd_code_version_major 預設為 1。
amd_kernel_code_version_minor 預設為 2。
amd_machine_kind 預設為 1。
amd_machine_version_major、machine_version_minor 和 amd_machine_version_stepping 是從傳遞給組譯器的 -mcpu 選項的值衍生的。
kernel_code_entry_byte_offset 預設為 256。
wavefront_size 在 GFX10 之前的所有目標預設為 6。對於 GFX10 及更高版本,如果目標功能
wavefrontsize64
已啟用,則預設為 6,否則為 5。請注意,wavefront 大小指定為 2 的冪,因此值 n 表示大小為 2^ n。call_convention 預設為 -1。
kernarg_segment_alignment、group_segment_alignment 和 private_segment_alignment 預設為 4。請注意,對齊方式指定為 2 的冪,因此值 n 表示對齊方式為 2^ n。
如果 GFX90A 及更高版本的目標功能
tgsplit
已啟用,則 enable_tg_split 預設為 1。如果 GFX10 及更高版本的目標功能
cumode
已停用,則 enable_wgp_mode 預設為 1。對於 GFX10 及更高版本,enable_mem_ordered 預設為 1。
.amd_kernel_code_t 指令必須緊接在函數標籤之後和任何指令之前放置。
有關 amd_kernel_code_t 鍵的完整列表,請參閱 AMDGPU ABI 文件、lib/Target/AMDGPU/AmdKernelCodeT.h 中的註解和 test/CodeGen/AMDGPU/hsa.s。
程式碼物件 V2 範例原始碼¶
警告
此版本的 LLVM 不再支援程式碼物件 V2 生成。
以下是一個最小組譯原始碼檔案的範例,定義了一個 HSA 核心
1.hsa_code_object_version 1,0
2.hsa_code_object_isa
3
4.hsatext
5.globl hello_world
6.p2align 8
7.amdgpu_hsa_kernel hello_world
8
9hello_world:
10
11 .amd_kernel_code_t
12 enable_sgpr_kernarg_segment_ptr = 1
13 is_ptr64 = 1
14 compute_pgm_rsrc1_vgprs = 0
15 compute_pgm_rsrc1_sgprs = 0
16 compute_pgm_rsrc2_user_sgpr = 2
17 compute_pgm_rsrc1_wgp_mode = 0
18 compute_pgm_rsrc1_mem_ordered = 0
19 compute_pgm_rsrc1_fwd_progress = 1
20 .end_amd_kernel_code_t
21
22 s_load_dwordx2 s[0:1], s[0:1] 0x0
23 v_mov_b32 v0, 3.14159
24 s_waitcnt lgkmcnt(0)
25 v_mov_b32 v1, s0
26 v_mov_b32 v2, s1
27 flat_store_dword v[1:2], v0
28 s_endpgm
29.Lfunc_end0:
30 .size hello_world, .Lfunc_end0-hello_world
程式碼物件 V3 及更高版本預定義符號¶
AMDGPU 組譯器會自動定義和更新某些符號。這些符號不會影響程式碼產生。
.amdgcn.gfx_generation_number¶
設定為正在組譯的目標的 GFX 主要世代編號。例如,當為「GFX9」目標組譯時,這將設定為整數值「9」。可能的 GFX 主要世代編號在處理器中呈現。
.amdgcn.gfx_generation_minor¶
設定為正在組譯的目標的 GFX 次要世代編號。例如,當為「GFX810」目標組譯時,這將設定為整數值「1」。可能的 GFX 次要世代編號在處理器中呈現。
.amdgcn.gfx_generation_stepping¶
設定為正在組譯的目標的 GFX 步進世代編號。例如,當為「GFX704」目標組譯時,這將設定為整數值「4」。可能的 GFX 步進世代編號在處理器中呈現。
.amdgcn.next_free_vgpr¶
在組譯開始之前設定為零。在每個指令中,如果此符號的目前值小於或等於該指令中明確引用的最大 VGPR 編號,則符號值會更新為等於該 VGPR 編號加一。
可用於設定.amdhsa_next_free_vgpr 指令,請參閱AMDHSA 核心組譯器指令。
可以隨時設定,例如在每個核心開始時手動設定為零。
.amdgcn.next_free_sgpr¶
在組譯開始之前設定為零。在每個指令中,如果此符號的目前值小於或等於該指令中明確引用的最大 SGPR 編號,則符號值會更新為等於該 SGPR 編號加一。
可用於設定.amdhsa_next_free_spgr 指令,請參閱AMDHSA 核心組譯器指令。
可以隨時設定,例如在每個核心開始時手動設定為零。
程式碼物件 V3 及更高版本指令¶
以 .amdgcn
開頭的指令對於所有 amdgcn
架構處理器都有效,並且與作業系統無關。當指定 amdhsa
作業系統時,以 .amdhsa
開頭的指令特定於 amdgcn
架構處理器。請參閱目標三元組和處理器。
.amdgcn_target <target-triple> “-” <target-id>¶
可選指令,用於宣告包含的組譯器原始碼檔案支援的 <target-triple>-<target-id>
。組譯器使用它來驗證命令列選項,例如 -triple
、-mcpu
和 --offload-arch=<target-id>
。允許使用非規範目標 ID。請參閱目標三元組和目標 ID。
注意
用於程式碼物件 V2 到 V3 的此指令的目標 ID 語法與其他地方使用的語法不同。請參閱程式碼物件 V2 到 V3 目標 ID。
.amdhsa_code_object_version <version>¶
可選指令,用於宣告組譯器要產生的程式碼物件版本。如果不存在,將使用預設值。
.amdhsa_kernel <name>¶
在目前區段的目前位置建立正確對齊的 AMDHSA 核心描述符和符號 <name>.kd
。僅當作業系統為 amdhsa
時有效。<name>
必須是標記要執行的第一個指令的符號(標籤),並且不需要預先定義。
標記用於產生核心描述符位元組的指令列表的開始,如核心描述符中所述。此列表中可能出現的指令在AMDHSA 核心組譯器指令中描述。指令可以以任何順序出現,必須對於正在組譯的目標有效,並且不能重複。指令支援核心描述符中它們引用的欄位指定的數值範圍。如果未指定指令,則假定它具有預設值,除非它被標記為「必需」,在這種情況下,省略該指令是錯誤的。此指令列表以 .end_amdhsa_kernel
指令終止。
表 103 AMDHSA 核心組譯器指令¶ 指令
預設值
支援於
描述
.amdhsa_group_segment_fixed_size
0
GFX6-GFX12
控制 程式碼物件 V3 核心描述符中的 GROUP_SEGMENT_FIXED_SIZE。
.amdhsa_private_segment_fixed_size
0
GFX6-GFX12
控制 程式碼物件 V3 核心描述符中的 PRIVATE_SEGMENT_FIXED_SIZE。
.amdhsa_kernarg_size
0
GFX6-GFX12
控制 程式碼物件 V3 核心描述符中的 KERNARG_SIZE。
.amdhsa_user_sgpr_count
0
GFX6-GFX12
控制 COMPUTE_PGM_RSRC2 適用於 GFX6-GFX12 的 compute_pgm_rsrc2 中的 USER_SGPR_COUNT
.amdhsa_user_sgpr_private_segment_buffer
0
GFX6-GFX10 (GFX942 除外)
控制 程式碼物件 V3 核心描述符 中的 ENABLE_SGPR_PRIVATE_SEGMENT_BUFFER。
.amdhsa_user_sgpr_dispatch_ptr
0
GFX6-GFX12
控制 程式碼物件 V3 核心描述符 中的 ENABLE_SGPR_DISPATCH_PTR。
.amdhsa_user_sgpr_queue_ptr
0
GFX6-GFX12
控制 程式碼物件 V3 核心描述符 中的 ENABLE_SGPR_QUEUE_PTR。
.amdhsa_user_sgpr_kernarg_segment_ptr
0
GFX6-GFX12
控制 程式碼物件 V3 核心描述符 中的 ENABLE_SGPR_KERNARG_SEGMENT_PTR。
.amdhsa_user_sgpr_dispatch_id
0
GFX6-GFX12
控制 程式碼物件 V3 核心描述符 中的 ENABLE_SGPR_DISPATCH_ID。
.amdhsa_user_sgpr_flat_scratch_init
0
GFX6-GFX10 (GFX942 除外)
控制 程式碼物件 V3 核心描述符 中的 ENABLE_SGPR_FLAT_SCRATCH_INIT。
.amdhsa_user_sgpr_private_segment_size
0
GFX6-GFX12
控制 程式碼物件 V3 核心描述符 中的 ENABLE_SGPR_PRIVATE_SEGMENT_SIZE。
.amdhsa_wavefront_size32
目標功能特定 (wavefrontsize64)
GFX10-GFX12
控制 程式碼物件 V3 核心描述符 中的 ENABLE_WAVEFRONT_SIZE32。
.amdhsa_uses_dynamic_stack
0
GFX6-GFX12
控制 程式碼物件 V3 核心描述符 中的 USES_DYNAMIC_STACK。
.amdhsa_system_sgpr_private_segment_wavefront_offset
0
GFX6-GFX10 (GFX942 除外)
控制 適用於 GFX6-GFX12 的 compute_pgm_rsrc2 中的 ENABLE_PRIVATE_SEGMENT。
.amdhsa_enable_private_segment
0
GFX942, GFX11-GFX12
控制 適用於 GFX6-GFX12 的 compute_pgm_rsrc2 中的 ENABLE_PRIVATE_SEGMENT。
.amdhsa_system_sgpr_workgroup_id_x
1
GFX6-GFX12
控制 適用於 GFX6-GFX12 的 compute_pgm_rsrc2 中的 ENABLE_SGPR_WORKGROUP_ID_X。
.amdhsa_system_sgpr_workgroup_id_y
0
GFX6-GFX12
控制 適用於 GFX6-GFX12 的 compute_pgm_rsrc2 中的 ENABLE_SGPR_WORKGROUP_ID_Y。
.amdhsa_system_sgpr_workgroup_id_z
0
GFX6-GFX12
控制 適用於 GFX6-GFX12 的 compute_pgm_rsrc2 中的 ENABLE_SGPR_WORKGROUP_ID_Z。
.amdhsa_system_sgpr_workgroup_info
0
GFX6-GFX12
控制 適用於 GFX6-GFX12 的 compute_pgm_rsrc2 中的 ENABLE_SGPR_WORKGROUP_INFO。
.amdhsa_system_vgpr_workitem_id
0
GFX6-GFX12
控制 適用於 GFX6-GFX12 的 compute_pgm_rsrc2 中的 ENABLE_VGPR_WORKITEM_ID。可能的值在系統 VGPR 工作項目 ID 列舉值中定義。
.amdhsa_next_free_vgpr
必填
GFX6-GFX12
明確引用的最大 VGPR 編號,加一。用於計算 適用於 GFX6-GFX12 的 compute_pgm_rsrc1 中的 GRANULATED_WORKITEM_VGPR_COUNT。
.amdhsa_next_free_sgpr
必填
GFX6-GFX12
明確引用的最大 SGPR 編號,加一。用於計算 適用於 GFX6-GFX12 的 compute_pgm_rsrc1 中的 GRANULATED_WAVEFRONT_SGPR_COUNT。
.amdhsa_accum_offset
必填
GFX90A、GFX942
統一暫存器檔案中第一個 AccVGPR 的偏移量。用於計算 適用於 GFX90A、GFX942 的 compute_pgm_rsrc3 中的 ACCUM_OFFSET。
.amdhsa_reserve_vcc
1
GFX6-GFX12
核心是否可以使用特殊的 VCC SGPR。用於計算 適用於 GFX6-GFX12 的 compute_pgm_rsrc1 中的 GRANULATED_WAVEFRONT_SGPR_COUNT。
.amdhsa_reserve_flat_scratch
1
GFX7-GFX10 (GFX942 除外)
核心是否可以使用 flat 指令來存取 scratch 記憶體。用於計算 適用於 GFX6-GFX12 的 compute_pgm_rsrc1 中的 GRANULATED_WAVEFRONT_SGPR_COUNT。
.amdhsa_reserve_xnack_mask
目標功能特定 (xnack)
GFX8-GFX10
核心是否可以觸發 XNACK 重播。用於計算 適用於 GFX6-GFX12 的 compute_pgm_rsrc1 中的 GRANULATED_WAVEFRONT_SGPR_COUNT。
.amdhsa_float_round_mode_32
0
GFX6-GFX12
控制 適用於 GFX6-GFX12 的 compute_pgm_rsrc1 中的 FLOAT_ROUND_MODE_32。可能的值在浮點數捨入模式列舉值中定義。
.amdhsa_float_round_mode_16_64
0
GFX6-GFX12
控制 適用於 GFX6-GFX12 的 compute_pgm_rsrc1 中的 FLOAT_ROUND_MODE_16_64。可能的值在浮點數捨入模式列舉值中定義。
.amdhsa_float_denorm_mode_32
0
GFX6-GFX12
控制 適用於 GFX6-GFX12 的 compute_pgm_rsrc1 中的 FLOAT_DENORM_MODE_32。可能的值在浮點數非正規化模式列舉值中定義。
.amdhsa_float_denorm_mode_16_64
3
GFX6-GFX12
控制 適用於 GFX6-GFX12 的 compute_pgm_rsrc1 中的 FLOAT_DENORM_MODE_16_64。可能的值在浮點數非正規化模式列舉值中定義。
.amdhsa_dx10_clamp
1
GFX6-GFX11
控制 適用於 GFX6-GFX12 的 compute_pgm_rsrc1 中的 ENABLE_DX10_CLAMP。
.amdhsa_ieee_mode
1
GFX6-GFX11
控制 適用於 GFX6-GFX12 的 compute_pgm_rsrc1 中的 ENABLE_IEEE_MODE。
.amdhsa_round_robin_scheduling
0
GFX12
控制 適用於 GFX6-GFX12 的 compute_pgm_rsrc1 中的 ENABLE_WG_RR_EN。
.amdhsa_fp16_overflow
0
GFX9-GFX12
控制 適用於 GFX6-GFX12 的 compute_pgm_rsrc1 中的 FP16_OVFL。
.amdhsa_tg_split
目標功能特定 (tgsplit)
GFX90A, GFX942, GFX11-GFX12
控制 適用於 GFX90A、GFX942 的 compute_pgm_rsrc3 中的 TG_SPLIT。
.amdhsa_workgroup_processor_mode
目標功能特定 (cumode)
GFX10-GFX12
控制 程式碼物件 V3 核心描述符 中的 ENABLE_WGP_MODE。
.amdhsa_memory_ordered
1
GFX10-GFX12
控制 適用於 GFX6-GFX12 的 compute_pgm_rsrc1 中的 MEM_ORDERED。
.amdhsa_forward_progress
0
GFX10-GFX12
控制 適用於 GFX6-GFX12 的 compute_pgm_rsrc1 中的 FWD_PROGRESS。
.amdhsa_shared_vgpr_count
0
GFX10-GFX11
控制 適用於 GFX10-GFX11 的 compute_pgm_rsrc3 中的 SHARED_VGPR_COUNT。
.amdhsa_inst_pref_size
0
GFX11-GFX12
控制 適用於 GFX10-GFX11 的 compute_pgm_rsrc3 或 適用於 GFX12 的 compute_pgm_rsrc3 中的 INST_PREF_SIZE
.amdhsa_exception_fp_ieee_invalid_op
0
GFX6-GFX12
控制
compute_pgm_rsrc2 for GFX6-GFX12
中的ENABLE_EXCEPTION_IEEE_754_FP_INVALID_OPERATION
啟用狀態。
.amdhsa_exception_fp_denorm_src
0
GFX6-GFX12
控制
compute_pgm_rsrc2 for GFX6-GFX12
中的ENABLE_EXCEPTION_FP_DENORMAL_SOURCE
啟用狀態。
.amdhsa_exception_fp_ieee_div_zero
0
GFX6-GFX12
控制
compute_pgm_rsrc2 for GFX6-GFX12
中的ENABLE_EXCEPTION_IEEE_754_FP_DIVISION_BY_ZERO
啟用狀態。
.amdhsa_exception_fp_ieee_overflow
0
GFX6-GFX12
控制
compute_pgm_rsrc2 for GFX6-GFX12
中的ENABLE_EXCEPTION_IEEE_754_FP_OVERFLOW
啟用狀態。
.amdhsa_exception_fp_ieee_underflow
0
GFX6-GFX12
控制
compute_pgm_rsrc2 for GFX6-GFX12
中的ENABLE_EXCEPTION_IEEE_754_FP_UNDERFLOW
啟用狀態。
.amdhsa_exception_fp_ieee_inexact
0
GFX6-GFX12
控制
compute_pgm_rsrc2 for GFX6-GFX12
中的ENABLE_EXCEPTION_IEEE_754_FP_INEXACT
啟用狀態。
.amdhsa_exception_int_div_zero
0
GFX6-GFX12
控制
compute_pgm_rsrc2 for GFX6-GFX12
中的ENABLE_EXCEPTION_INT_DIVIDE_BY_ZERO
啟用狀態。
.amdhsa_user_sgpr_kernarg_preload_length
0
GFX90A、GFX942
控制 Code Object V3 Kernel Descriptor 中的
KERNARG_PRELOAD_SPEC_LENGTH
。
.amdhsa_user_sgpr_kernarg_preload_offset
0
GFX90A、GFX942
控制 Code Object V3 Kernel Descriptor 中的
KERNARG_PRELOAD_SPEC_OFFSET
。
.amdgpu_metadata¶
選用指示詞,宣告 NT_AMDGPU_METADATA
註記記錄的內容(請參閱AMDGPU Code Object V3 及更高版本的 ELF 註記記錄)。
內容必須為 [YAML] 標記格式,並具有與 Code Object V3 Metadata、Code Object V4 Metadata 或 Code Object V5 Metadata 中描述的相同結構和語意。
此指示詞以 .end_amdgpu_metadata
指示詞終止。
Code Object V3 及更高版本範例原始碼¶
以下是一個最小組譯原始碼檔案的範例,定義了一個 HSA 核心
1.amdgcn_target "amdgcn-amd-amdhsa--gfx900+xnack" // optional
2
3.text
4.globl hello_world
5.p2align 8
6.type hello_world,@function
7hello_world:
8 s_load_dwordx2 s[0:1], s[0:1] 0x0
9 v_mov_b32 v0, 3.14159
10 s_waitcnt lgkmcnt(0)
11 v_mov_b32 v1, s0
12 v_mov_b32 v2, s1
13 flat_store_dword v[1:2], v0
14 s_endpgm
15.Lfunc_end0:
16 .size hello_world, .Lfunc_end0-hello_world
17
18.rodata
19.p2align 6
20.amdhsa_kernel hello_world
21 .amdhsa_user_sgpr_kernarg_segment_ptr 1
22 .amdhsa_next_free_vgpr .amdgcn.next_free_vgpr
23 .amdhsa_next_free_sgpr .amdgcn.next_free_sgpr
24.end_amdhsa_kernel
25
26.amdgpu_metadata
27---
28amdhsa.version:
29 - 1
30 - 0
31amdhsa.kernels:
32 - .name: hello_world
33 .symbol: hello_world.kd
34 .kernarg_segment_size: 48
35 .group_segment_fixed_size: 0
36 .private_segment_fixed_size: 0
37 .kernarg_segment_align: 4
38 .wavefront_size: 64
39 .sgpr_count: 2
40 .vgpr_count: 3
41 .max_flat_workgroup_size: 256
42 .args:
43 - .size: 8
44 .offset: 0
45 .value_kind: global_buffer
46 .address_space: global
47 .actual_access: write_only
48//...
49.end_amdgpu_metadata
此核心等同於下列 HIP 程式
1__global__ void hello_world(float *p) {
2 *p = 3.14159f;
3}
如果組譯原始碼檔案包含多個核心及/或函式,則可以使用 .set <symbol>, <expression>
指示詞重設 .amdgcn.next_free_vgpr 和 .amdgcn.next_free_sgpr 符號。例如,在兩個核心的情況下,其中 function1
僅從 kernel1
呼叫,將函式與呼叫它的核心分組,並在兩個連線組件之間重設符號就足夠了
1.amdgcn_target "amdgcn-amd-amdhsa--gfx900+xnack" // optional
2
3// gpr tracking symbols are implicitly set to zero
4
5.text
6.globl kern0
7.p2align 8
8.type kern0,@function
9kern0:
10 // ...
11 s_endpgm
12.Lkern0_end:
13 .size kern0, .Lkern0_end-kern0
14
15.rodata
16.p2align 6
17.amdhsa_kernel kern0
18 // ...
19 .amdhsa_next_free_vgpr .amdgcn.next_free_vgpr
20 .amdhsa_next_free_sgpr .amdgcn.next_free_sgpr
21.end_amdhsa_kernel
22
23// reset symbols to begin tracking usage in func1 and kern1
24.set .amdgcn.next_free_vgpr, 0
25.set .amdgcn.next_free_sgpr, 0
26
27.text
28.hidden func1
29.global func1
30.p2align 2
31.type func1,@function
32func1:
33 // ...
34 s_setpc_b64 s[30:31]
35.Lfunc1_end:
36.size func1, .Lfunc1_end-func1
37
38.globl kern1
39.p2align 8
40.type kern1,@function
41kern1:
42 // ...
43 s_getpc_b64 s[4:5]
44 s_add_u32 s4, s4, func1@rel32@lo+4
45 s_addc_u32 s5, s5, func1@rel32@lo+4
46 s_swappc_b64 s[30:31], s[4:5]
47 // ...
48 s_endpgm
49.Lkern1_end:
50 .size kern1, .Lkern1_end-kern1
51
52.rodata
53.p2align 6
54.amdhsa_kernel kern1
55 // ...
56 .amdhsa_next_free_vgpr .amdgcn.next_free_vgpr
57 .amdhsa_next_free_sgpr .amdgcn.next_free_sgpr
58.end_amdhsa_kernel
這些符號無法識別連線的組件,以便自動追蹤每個核心的使用情況。然而,在某些情況下,仔細組織原始碼檔案中的核心和函式,表示只需極少的額外工作即可準確計算 GPR 使用量。