[llvm] 4b802fe - [AMDGPU] Use sparse direct lookup table for VOPD eligibility (#206534)

via llvm-commits llvm-commits at lists.llvm.org
Tue Jun 30 01:23:44 PDT 2026


Author: Igor Wodiany
Date: 2026-06-30T09:23:40+01:00
New Revision: 4b802fed943f420377c80fac82257000c1a11a9e

URL: https://github.com/llvm/llvm-project/commit/4b802fed943f420377c80fac82257000c1a11a9e
DIFF: https://github.com/llvm/llvm-project/commit/4b802fed943f420377c80fac82257000c1a11a9e.diff

LOG: [AMDGPU] Use sparse direct lookup table for VOPD eligibility (#206534)

This replaces a manually generated table with a new TableGen feature
that enables sparse direct lookup. Additional changes are made to put
both X and Y eligibility into a single table.

Assisted-by: Claude Code

Added: 
    

Modified: 
    llvm/lib/Target/AMDGPU/SIInstrInfo.td
    llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.cpp
    llvm/lib/Target/AMDGPU/VOPDInstructions.td

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/AMDGPU/SIInstrInfo.td b/llvm/lib/Target/AMDGPU/SIInstrInfo.td
index 8c30e53e9b4e4..7be067c085b5f 100644
--- a/llvm/lib/Target/AMDGPU/SIInstrInfo.td
+++ b/llvm/lib/Target/AMDGPU/SIInstrInfo.td
@@ -3576,22 +3576,15 @@ def lo16_to_vgpr32 : OutPatFrag<(ops node:$op),
 def hi16_to_vgpr32 : OutPatFrag<(ops node:$op),
   (REG_SEQUENCE VGPR_32, (i16 (IMPLICIT_DEF)), lo16, $op, hi16)>;
 
-// Instructions eligible to be the first (X) instruction in Dual Issue VALU
-// (VOPD) encoding. Consumed by buildVOPDXYLookup() to build a direct lookup
-// table; no helper is generated.
-def VOPDXTable : GenericTable {
-  let FilterClass = "VOPDX";
+// Direct lookup table for VOPDXY eligibility, indexed by the packed
+// (VOPDOp << 5) | (Subtarget << 1) | VOPD3 key.
+def VOPDXYTable : GenericTable {
+  let FilterClass = "VOPDXY";
   let CppTypeName = "VOPDXYInfo";
-  let Fields = ["VOPDOp", "Subtarget", "VOPD3"];
-}
-
-// Instructions eligible to be the second (Y) instruction in Dual Issue VALU
-// (VOPD) encoding. Consumed by buildVOPDXYLookup() to build a direct lookup
-// table; no helper is generated.
-def VOPDYTable : GenericTable {
-  let FilterClass = "VOPDY";
-  let CppTypeName = "VOPDXYInfo";
-  let Fields = ["VOPDOp", "Subtarget", "VOPD3"];
+  let Fields = ["VOPDXYKey", "IsX", "IsY"];
+  let PrimaryKey = ["VOPDXYKey"];
+  let PrimaryKeyName = "getVOPDXYInfo";
+  let DisallowSparseTable = false;
 }
 
 include "SIInstructions.td"

diff  --git a/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.cpp b/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.cpp
index 34779acd2b8d2..588ca588819cc 100644
--- a/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.cpp
+++ b/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.cpp
@@ -420,9 +420,9 @@ struct VOPTrue16Info {
 };
 
 struct VOPDXYInfo {
-  uint16_t VOPDOp;
-  uint16_t Subtarget;
-  bool VOPD3;
+  uint16_t VOPDXYKey;
+  bool IsX;
+  bool IsY;
 };
 
 #define GET_FP4FP8DstByteSelTable_DECL
@@ -465,10 +465,8 @@ struct FP4FP8DstByteSelInfo {
 #define GET_VOPDComponentTable_IMPL
 #define GET_VOPDPairs_DECL
 #define GET_VOPDPairs_IMPL
-#define GET_VOPDXTable_DECL
-#define GET_VOPDXTable_IMPL
-#define GET_VOPDYTable_DECL
-#define GET_VOPDYTable_IMPL
+#define GET_VOPDXYTable_DECL
+#define GET_VOPDXYTable_IMPL
 #define GET_VOPTrue16Table_DECL
 #define GET_VOPTrue16Table_IMPL
 #define GET_True16D16Table_IMPL
@@ -693,28 +691,6 @@ unsigned getVOPDEncodingFamily(const MCSubtargetInfo &ST) {
   llvm_unreachable("Subtarget generation does not support VOPD!");
 }
 
-static constexpr unsigned getVOPDXYKey(unsigned VOPDOp, unsigned Subtarget,
-                                       bool VOPD3) {
-  return (VOPDOp << 5) | (Subtarget << 1) | (VOPD3 ? 1u : 0u);
-}
-
-// TODO: Ideally, the table should be emitted by the TableGen backend, however
-// this is currently not supported, so the direct lookup table is generated
-// manually here.
-constexpr unsigned VOPDXYKeyBits = 11;
-static constexpr std::array<CanBeVOPD, 1 << VOPDXYKeyBits> buildVOPDXYLookup() {
-  std::array<CanBeVOPD, 1 << VOPDXYKeyBits> Table{};
-  for (auto &E : Table)
-    E = {false, false};
-  for (const auto &E : VOPDXTable)
-    Table[getVOPDXYKey(E.VOPDOp, E.Subtarget, E.VOPD3)].X = true;
-  for (const auto &E : VOPDYTable)
-    Table[getVOPDXYKey(E.VOPDOp, E.Subtarget, E.VOPD3)].Y = true;
-  return Table;
-}
-
-constexpr auto VOPDXYLookup = buildVOPDXYLookup();
-
 CanBeVOPD getCanBeVOPD(unsigned Opc, unsigned EncodingFamily, bool VOPD3) {
   bool IsConvertibleToBitOp = VOPD3 ? getBitOp2(Opc) : 0;
   Opc = IsConvertibleToBitOp ? (unsigned)AMDGPU::V_BITOP3_B32_e64 : Opc;
@@ -723,7 +699,12 @@ CanBeVOPD getCanBeVOPD(unsigned Opc, unsigned EncodingFamily, bool VOPD3) {
   const VOPDComponentInfo *Info = getVOPDComponentHelper(Opc);
   if (!Info)
     return {false, false};
-  return VOPDXYLookup[getVOPDXYKey(Info->VOPDOp, EncodingFamily, VOPD3)];
+  unsigned Key =
+      (Info->VOPDOp << 5) | (EncodingFamily << 1) | (VOPD3 ? 1u : 0u);
+  const VOPDXYInfo *XYInfo = getVOPDXYInfo(Key);
+  if (!XYInfo)
+    return {false, false};
+  return {XYInfo->IsX, XYInfo->IsY};
 }
 
 unsigned getVOPDOpcode(unsigned Opc, bool VOPD3) {

diff  --git a/llvm/lib/Target/AMDGPU/VOPDInstructions.td b/llvm/lib/Target/AMDGPU/VOPDInstructions.td
index 6a905d432b5c2..1fadb8999b14b 100644
--- a/llvm/lib/Target/AMDGPU/VOPDInstructions.td
+++ b/llvm/lib/Target/AMDGPU/VOPDInstructions.td
@@ -103,6 +103,7 @@ class GFXGenD<GFXGen Gen, list<string> DXPseudos, list<string> DYPseudos,
   list<string> VOPDXPseudos = DXPseudos;
   list<string> VOPDYPseudos = DYPseudos;
   Predicate SubtargetPredicate = subtargetPred;
+  bit IsVOPD3 = 0;
 }
 
 class VOPD_Base<dag outs, dag ins, string asm, VOP_Pseudo VDX, VOP_Pseudo VDY,
@@ -262,9 +263,13 @@ defvar VOPD3YPseudosGFX1250 = !listconcat(
                                                                      !eq(!find(x, "FMAMK"), -1))),
                                 VOPD3YPseudosExtra);
 
-def GFX1250GenD3 : GFXGenD<GFX1250Gen, VOPD3XPseudosGFX1250, VOPD3YPseudosGFX1250>;
+def GFX1250GenD3 : GFXGenD<GFX1250Gen, VOPD3XPseudosGFX1250, VOPD3YPseudosGFX1250> {
+  let IsVOPD3 = 1;
+}
 
-def GFX13GenD3 : GFXGenD<GFX13Gen, VOPD3XPseudosGFX13, VOPD3YPseudosGFX1250>;
+def GFX13GenD3 : GFXGenD<GFX13Gen, VOPD3XPseudosGFX13, VOPD3YPseudosGFX1250> {
+  let IsVOPD3 = 1;
+}
 
 class getOpcMap<string OPName> {
   defvar BaseName = !substr(OPName,2);
@@ -290,29 +295,26 @@ foreach Gen = [GFX1250GenD3, GFX13GenD3] in {
   }
 }
 
-class VOPDXY<bits<6> Op, int Sub, bit IsVOPD3> {
-  bits<6> VOPDOp = Op;
-  bits<4> Subtarget = Sub;
-  bit VOPD3 = IsVOPD3;
+class VOPDXY<bits<6> Op, bits<4> Sub, bit IsVOPD3, bit X, bit Y> {
+  bits<11> VOPDXYKey = {Op, Sub, IsVOPD3};
+  bit IsX = X;
+  bit IsY = Y;
 }
 
-class VOPDX<bits<6> Op, int Sub, bit IsVOPD3> : VOPDXY<Op, Sub, IsVOPD3>;
-class VOPDY<bits<6> Op, int Sub, bit IsVOPD3> : VOPDXY<Op, Sub, IsVOPD3>;
-
-foreach Gen = [GFX11GenD, GFX1170GenD, GFX12GenD, GFX1250GenD, GFX13GenD] in {
-  foreach p = Gen.VOPDXPseudos in
-    def "VOPDX_" # p # Gen.Suffix :
-        VOPDX<!cast<VOPD_Component>(p).VOPDOp, Gen.Subtarget, 0>;
-  foreach p = Gen.VOPDYPseudos in
-    def "VOPDY_" # p # Gen.Suffix :
-        VOPDY<!cast<VOPD_Component>(p).VOPDOp, Gen.Subtarget, 0>;
-}
-
-foreach Gen = [GFX1250GenD3, GFX13GenD3] in {
-  foreach p = Gen.VOPDXPseudos in
-    def "VOPDX_VOPD3_" # p # Gen.Suffix :
-        VOPDX<!cast<VOPD_Component>(p).VOPDOp, Gen.Subtarget, 1>;
-  foreach p = Gen.VOPDYPseudos in
-    def "VOPDY_VOPD3_" # p # Gen.Suffix :
-        VOPDY<!cast<VOPD_Component>(p).VOPDOp, Gen.Subtarget, 1>;
+foreach Gen = [GFX11GenD, GFX1170GenD, GFX12GenD, GFX1250GenD, GFX13GenD,
+               GFX1250GenD3, GFX13GenD3] in {
+  defvar Prefix = !if(Gen.IsVOPD3, "VOPDXY_VOPD3_", "VOPDXY_");
+  defvar XOnly = !listremove(Gen.VOPDXPseudos, Gen.VOPDYPseudos);
+  defvar YOnly = !listremove(Gen.VOPDYPseudos, Gen.VOPDXPseudos);
+  defvar XAndY = !listremove(Gen.VOPDXPseudos, XOnly);
+
+  foreach p = XOnly in
+    def Prefix # p # Gen.Suffix :
+        VOPDXY<!cast<VOPD_Component>(p).VOPDOp, Gen.Subtarget, Gen.IsVOPD3, 1, 0>;
+  foreach p = YOnly in
+    def Prefix # p # Gen.Suffix :
+        VOPDXY<!cast<VOPD_Component>(p).VOPDOp, Gen.Subtarget, Gen.IsVOPD3, 0, 1>;
+  foreach p = XAndY in
+    def Prefix # p # Gen.Suffix :
+        VOPDXY<!cast<VOPD_Component>(p).VOPDOp, Gen.Subtarget, Gen.IsVOPD3, 1, 1>;
 }


        


More information about the llvm-commits mailing list