LLVM で現在対応が進められている AMD RDNA 5 アーキテクチャ (gfx1310) だが、最近になり Dual Issue VALU/Wave32 に関するプルリクエストが公開された。
Dual Issue VALU は RDNA 3 アーキテクチャ (GFX11) から実装された機能であり、VOPD 系命令 (V_DUAL_*) を最大 2種類を組み合わせて、X側と Y側に同時に発行することができるというものだ。
ただし、対応する命令は限られており、片側 (Y側) だけでしか選択できない命令もある。また Dual Issue には、Wave32 モードでしか正常に動作しない、レジスタバンクの競合を避けるために X側と Y側で別のレジスタバンクを使用する必要がある等、いくつかの条件がある。
内部的には、フル機能の SIMD ユニットと、一部の命令のみをサポートしたサブセットとなる SIMD ユニットを組み合わせていると思われる。
RDNA 5 (gfx1310) では VOPD に V_{MAX,MIN}_I32_e32, V_SUB_U32_e32, V_LSHRREV_B32_e32, V_ASHRREV_I32_e32 といった、整数を入力に取る最大値、最小値を取り出す命令、減算命令、ビットシフト命令が追加された。
一方でビット論理積命令の V_AND_B32 は削除されている。
ここと以降で参照している LLVM のコード中に書いている命令は名前から DUAL を省略し、元となった命令名で表現した疑似命令となっている。
defvar VOPDPseudosCommon = [ "V_FMAC_F32_e32", "V_FMAAK_F32", "V_FMAMK_F32", "V_MUL_F32_e32", "V_ADD_F32_e32", "V_SUB_F32_e32", "V_SUBREV_F32_e32", "V_MUL_LEGACY_F32_e32", "V_MOV_B32_e32", "V_CNDMASK_B32_e32", "V_MAX_F32_e32", "V_MIN_F32_e32", "V_DOT2C_F32_F16_e32", "V_DOT2C_F32_BF16_e32" ]; defvar VOPDYOnlyPseudosCommon = ["V_ADD_U32_e32", "V_LSHLREV_B32_e32"]; defvar VOPDYOnlyPseudosGFX11_12 = ["V_AND_B32_e32"]; defvar VOPDYOnlyPseudosGFX1250 = ["V_MAX_I32_e32", "V_MIN_I32_e32", "V_SUB_U32_e32", "V_LSHRREV_B32_e32", "V_ASHRREV_I32_e32"]; defvar VOPDXPseudosGFX11 = VOPDPseudosCommon; defvar VOPDXPseudosGFX12 = VOPDPseudosCommon; defvar VOPDYPseudosGFX11 = !listconcat(VOPDXPseudosGFX11, VOPDYOnlyPseudosCommon, VOPDYOnlyPseudosGFX11_12); defvar VOPDYPseudosGFX12 = !listconcat(VOPDXPseudosGFX12, VOPDYOnlyPseudosCommon, VOPDYOnlyPseudosGFX11_12); defvar VOPDYPseudosGFX1250 = !listconcat(VOPDXPseudosGFX12, VOPDYOnlyPseudosCommon, VOPDYOnlyPseudosGFX1250); def GFX11GenD : GFXGenD<GFX11Gen, VOPDXPseudosGFX11, VOPDYPseudosGFX11>; def GFX12GenD : GFXGenD<GFX12Not12_50Gen, VOPDXPseudosGFX12, VOPDYPseudosGFX12>; def GFX1250GenD : GFXGenD<GFX1250Gen, VOPDXPseudosGFX12, VOPDYPseudosGFX1250>; def GFX13GenD : GFXGenD<GFX13Gen, VOPDXPseudosGFX12, VOPDYPseudosGFX1250>;
そして重要なのが、RDNA 5 (gfx1310) では Dual Issue 系命令として、新たな命令エンコーディングを採用した VOPD3 が追加された。
VOPD3 には、V_{FMAAK,FMAMK}_F32 命令を除いた VOPD の命令が含まれており、そして V_FMA_F32_e64 命令が追加されている。
V_{FMAAK,FMAMK}_F32 命令と V_FMA_F32 命令の違いは入力にリテラル定数を用いるかどうかであり、V_FMAAK_F32 命令は加算部分の引数に、V_FMAMK_F32 命令は乗算部分の片方の引数にリテラル定数を用いる。
V_FMA_F32 命令は命令エンコーディングの違いから、3つの入力にそれぞれ別のレジスタを指定可能となっている。
FMA 系命令には他に V_FMAC_F32 命令が存在するが、こちらは累算向けで、加算部分に指定したレジスタに演算結果を出力する命令となる。
従来の Dual Issue、VOPD では V_{FMAC,FMAAK,FMAMK}_F32 命令をサポートし、 V_FMA_F32 命令はサポートしていなかった。
そのため、nihui/vkpeak のような GPU ベンチマークツールでは Dual Issue が機能せず、公称ピーク FP32 性能の半分しか性能が出ないケースがあった。
それが RDNA 5 (gfx1310) では X側 Y側の両方に V_FMA_F32 (V_DUAL_FMA_F32) 命令を発行可能となったことで改善される可能性がある。
ただし、これまで半分のピーク性能しか出なかったケースが改善されれば性能が倍になったように見えるのは確かだが、ピーク FP32 性能自体は RDNA 2 から RDNA 3 に世代が進んだ時のようには大きく変わらないことが考えられる。
defvar VOPD3XPseudosExtraGFX13 = ["V_ADD_U32_e32", "V_LSHLREV_B32_e32", "V_FMA_F32_e64", "V_SUB_U32_e32", "V_LSHRREV_B32_e32", "V_ASHRREV_I32_e32"]; defvar VOPD3XPseudosExtraGFX1250 = ["V_FMA_F64_e64", "V_ADD_F64_pseudo_e32", "V_MUL_F64_pseudo_e32", "V_MAX_NUM_F64_e32", "V_MIN_NUM_F64_e32"]; defvar VOPD3XPseudosGFX13 = !listconcat( !filter(x, VOPDXPseudosGFX12, !and(!eq(!find(x, "FMAAK"), -1), !eq(!find(x, "FMAMK"), -1))), VOPD3XPseudosExtraGFX13); defvar VOPD3XPseudosGFX1250 = !listconcat(VOPD3XPseudosGFX13, VOPD3XPseudosExtraGFX1250); defvar VOPD3YPseudosExtra = ["V_BITOP3_B32_e64", "V_FMA_F32_e64"]; defvar VOPD3YPseudosGFX1250 = !listconcat( !filter(x, VOPDYPseudosGFX1250, !and(!eq(!find(x, "FMAAK"), -1), !eq(!find(x, "FMAMK"), -1))), VOPD3YPseudosExtra); def GFX1250GenD3 : GFXGenD<GFX1250Gen, VOPD3XPseudosGFX1250, VOPD3YPseudosGFX1250>; def GFX13GenD3 : GFXGenD<GFX13Gen, VOPD3XPseudosGFX13, VOPD3YPseudosGFX1250>;
また、RDNA 5 (gfx1310) では Dual Issue における制限が一部緩和され、X側と Y側で同じ入力レジスタを指定できるようになっており、これも Dual Issue が使えるケースを増やすのに役立つだろう。
こうした変更を RDNA 3 あるいはそこから世代の進んだ RDNA 4 に実装しなかった理由としては、設計が複雑化し、必要な実装面積も増えるからだと思われる。
サブセットとなる SIMD ユニットがサポートする命令を増やせば、当然必要な回路数は増える。レジスタのデータポートも Dual Issue を活用できるように設計し、増やす必要があるだろう。
使用できるレジスタ数を増やせば、命令長も増える。
RDNA 3/4 では Dual Issue の導入世代として、命令や制限はそれなりにあるが、ハードウェア側の実装コストを抑えつつ、コンパイラ側の対応を確実に進められる選択を取ったのだと思われる。