[llvm-branch-commits] [llvm] AMDGPU: TableGen subarch to major subarch table (PR #212605)

Matt Arsenault via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Wed Jul 29 11:59:34 PDT 2026


https://github.com/arsenm updated https://github.com/llvm/llvm-project/pull/212605

>From 6c2f22c2d358f7237a47c031f1f420ab2c30633c Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Mon, 27 Jul 2026 07:54:09 +0200
Subject: [PATCH] AMDGPU: TableGen subarch to major subarch table

Replace the hand-written AMDGPUMajorFamilies array with a
generated lookup table. Adds a special case for the major
arches missing a concrete generic target definition (we probably
should just define those to avoid this).

Co-authored-by: Claude (Claude-Opus-4.8)
---
 llvm/lib/Target/AMDGPU/AMDGPUTargetParser.td  |   8 ++
 llvm/lib/Target/AMDGPU/GCNProcessors.td       |   6 +
 llvm/lib/TargetParser/AMDGPUTargetParser.cpp  |  74 ++++--------
 .../TableGen/Basic/AMDGPUTargetDefEmitter.cpp | 106 ++++++++++++++----
 4 files changed, 119 insertions(+), 75 deletions(-)

diff --git a/llvm/lib/Target/AMDGPU/AMDGPUTargetParser.td b/llvm/lib/Target/AMDGPU/AMDGPUTargetParser.td
index e53f65cd5f60d..e6ea319017436 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUTargetParser.td
+++ b/llvm/lib/Target/AMDGPU/AMDGPUTargetParser.td
@@ -59,3 +59,11 @@ class R600ProcessorModel<string n, ProcessorItineraries pi,
 class AMDGPUProcessorModel<string n, SchedMachineModel m,
                            list<SubtargetFeature> f, list<int> isa>
     : ProcessorModel<n, m, f>, AMDGPUGPUInfo<isa>;
+
+// A major-subarch family that has no "gfxN-generic" target of its own
+// (gfx6, gfx7, gfx8). \p major is the bare subarch suffix (e.g. "6");
+// \p members are the GPUs mapped to Triple::AMDGPUSubArch<major>
+class AMDGPUFamily<string major, list<Processor> members> {
+  string MajorSubArch = major;
+  list<Processor> Members = members;
+}
diff --git a/llvm/lib/Target/AMDGPU/GCNProcessors.td b/llvm/lib/Target/AMDGPU/GCNProcessors.td
index d6d8a8a4e070e..47dc1f182c7b4 100644
--- a/llvm/lib/Target/AMDGPU/GCNProcessors.td
+++ b/llvm/lib/Target/AMDGPU/GCNProcessors.td
@@ -398,3 +398,9 @@ def GFX13_GENERIC : AMDGPUProcessorModel<"gfx13-generic", GFX12SpeedModel,
   let ArchFeatures = ArchFeaturesW32Wgp;
   let CoveredGPUs = [GFX1310];
 }
+
+// The gfx6/gfx7/gfx8 families have no "gfxN-generic" target, so their major
+// subarch (AMDGPUSubArch6/7/8) is declared here for getMajorSubArch.
+def : AMDGPUFamily<"6", [GFX600, GFX601, GFX602]>;
+def : AMDGPUFamily<"7", [GFX700, GFX701, GFX702, GFX703, GFX704, GFX705]>;
+def : AMDGPUFamily<"8", [GFX801, GFX802, GFX803, GFX805]>;
diff --git a/llvm/lib/TargetParser/AMDGPUTargetParser.cpp b/llvm/lib/TargetParser/AMDGPUTargetParser.cpp
index fa95e4005bb22..a555c94ee6c91 100644
--- a/llvm/lib/TargetParser/AMDGPUTargetParser.cpp
+++ b/llvm/lib/TargetParser/AMDGPUTargetParser.cpp
@@ -24,6 +24,9 @@ using namespace llvm;
 using namespace AMDGPU;
 
 namespace {
+constexpr unsigned NumAMDGPUSubArches =
+    Triple::LastAMDGPUSubArch - Triple::FirstAMDGPUSubArch + 1;
+
 // Per-GPU data for the AMDGCN GPUKinds, from the generated table below.
 struct GPUInfo {
   StringRef Name;
@@ -34,6 +37,7 @@ struct GPUInfo {
 };
 
 #define GET_AMDGPU_GPU_TABLE
+#define GET_AMDGPU_MAJOR_SUBARCH
 #include "llvm/TargetParser/AMDGPUTargetParserDef.inc"
 
 // Look up the GPUInfo row for an AMDGCN GPUKind, or nullptr for GK_NONE / a
@@ -49,8 +53,6 @@ const GPUInfo *getAMDGPUInfo(GPUKind AK) {
 
 // Reverse map: SubArch -> GPUKind, indexed by (SubArch - FirstAMDGPUSubArch).
 // Subarches with no GPU (incl. the NoSubArch pseudo targets) map to GK_NONE.
-constexpr unsigned NumAMDGPUSubArches =
-    Triple::LastAMDGPUSubArch - Triple::FirstAMDGPUSubArch + 1;
 constexpr std::array<GPUKind, NumAMDGPUSubArches> AMDGPUSubArchToGPUKind = [] {
   std::array<GPUKind, NumAMDGPUSubArches> Map{};
 
@@ -63,6 +65,21 @@ constexpr std::array<GPUKind, NumAMDGPUSubArches> AMDGPUSubArchToGPUKind = [] {
   }
   return Map;
 }();
+
+/// SubArch -> major-family, indexed by (SubArch - FirstAMDGPUSubArch).
+constexpr std::array<Triple::SubArchType, NumAMDGPUSubArches>
+    AMDGPUMajorFamilies = [] {
+      std::array<Triple::SubArchType, NumAMDGPUSubArches> Map{};
+
+      for (unsigned I = 0; I < NumAMDGPUSubArches; ++I) {
+        Map[I] =
+            static_cast<Triple::SubArchType>(Triple::FirstAMDGPUSubArch + I);
+      }
+
+      for (const AMDGPUMajorSubArchEntry &Entry : AMDGPUMajorSubArch)
+        Map[Entry.SubArch - Triple::FirstAMDGPUSubArch] = Entry.Major;
+      return Map;
+    }();
 } // namespace
 
 StringRef llvm::AMDGPU::getArchFamilyNameAMDGCN(GPUKind AK) {
@@ -83,59 +100,6 @@ llvm::AMDGPU::getGPUKindFromSubArch(Triple::SubArchType SubArch) {
   return AMDGPUSubArchToGPUKind[SubArch - Triple::FirstAMDGPUSubArch];
 }
 
-static const Triple::SubArchType
-    AMDGPUMajorFamilies[Triple::LastAMDGPUSubArch - Triple::FirstAMDGPUSubArch +
-                        1] = {
-        Triple::AMDGPUSubArch6,    Triple::AMDGPUSubArch6,
-        Triple::AMDGPUSubArch6,    Triple::AMDGPUSubArch6,
-
-        Triple::AMDGPUSubArch7,    Triple::AMDGPUSubArch7,
-        Triple::AMDGPUSubArch7,    Triple::AMDGPUSubArch7,
-        Triple::AMDGPUSubArch7,    Triple::AMDGPUSubArch7,
-        Triple::AMDGPUSubArch7,
-
-        Triple::AMDGPUSubArch8,    Triple::AMDGPUSubArch8,
-        Triple::AMDGPUSubArch8,    Triple::AMDGPUSubArch8,
-        Triple::AMDGPUSubArch8,
-
-        Triple::AMDGPUSubArch810,
-
-        Triple::AMDGPUSubArch9,    Triple::AMDGPUSubArch9,
-        Triple::AMDGPUSubArch9,    Triple::AMDGPUSubArch9,
-        Triple::AMDGPUSubArch9,    Triple::AMDGPUSubArch9,
-        Triple::AMDGPUSubArch9,
-
-        Triple::AMDGPUSubArch908,  Triple::AMDGPUSubArch90A,
-
-        Triple::AMDGPUSubArch9_4,  Triple::AMDGPUSubArch9_4,
-        Triple::AMDGPUSubArch9_4,
-
-        Triple::AMDGPUSubArch10_1, Triple::AMDGPUSubArch10_1,
-        Triple::AMDGPUSubArch10_1, Triple::AMDGPUSubArch10_1,
-        Triple::AMDGPUSubArch10_1,
-
-        Triple::AMDGPUSubArch10_3, Triple::AMDGPUSubArch10_3,
-        Triple::AMDGPUSubArch10_3, Triple::AMDGPUSubArch10_3,
-        Triple::AMDGPUSubArch10_3, Triple::AMDGPUSubArch10_3,
-        Triple::AMDGPUSubArch10_3, Triple::AMDGPUSubArch10_3,
-
-        Triple::AMDGPUSubArch11,   Triple::AMDGPUSubArch11,
-        Triple::AMDGPUSubArch11,   Triple::AMDGPUSubArch11,
-        Triple::AMDGPUSubArch11,   Triple::AMDGPUSubArch11,
-        Triple::AMDGPUSubArch11,   Triple::AMDGPUSubArch11,
-        Triple::AMDGPUSubArch11,   Triple::AMDGPUSubArch11,
-
-        Triple::AMDGPUSubArch11_7, Triple::AMDGPUSubArch11_7,
-        Triple::AMDGPUSubArch11_7, Triple::AMDGPUSubArch11_7,
-
-        Triple::AMDGPUSubArch12,   Triple::AMDGPUSubArch12,
-        Triple::AMDGPUSubArch12,
-
-        Triple::AMDGPUSubArch12_5, Triple::AMDGPUSubArch12_5,
-        Triple::AMDGPUSubArch12_5,
-
-        Triple::AMDGPUSubArch13,   Triple::AMDGPUSubArch13};
-
 Triple::SubArchType AMDGPU::getMajorSubArch(Triple::SubArchType X) {
   if (X < Triple::FirstAMDGPUSubArch || X > Triple::LastAMDGPUSubArch)
     return Triple::NoSubArch;
diff --git a/llvm/utils/TableGen/Basic/AMDGPUTargetDefEmitter.cpp b/llvm/utils/TableGen/Basic/AMDGPUTargetDefEmitter.cpp
index a4468de6d0968..ece842771f32c 100644
--- a/llvm/utils/TableGen/Basic/AMDGPUTargetDefEmitter.cpp
+++ b/llvm/utils/TableGen/Basic/AMDGPUTargetDefEmitter.cpp
@@ -18,6 +18,8 @@
 #include "llvm/TableGen/Error.h"
 #include "llvm/TableGen/Record.h"
 #include "llvm/TableGen/TableGenBackend.h"
+#include <string>
+#include <utility>
 #include <vector>
 
 using namespace llvm;
@@ -29,14 +31,11 @@ static void emitGPUKindEnum(raw_ostream &OS, StringRef Name) {
     OS << ((C == '-') ? '_' : toUpper(C));
 }
 
-/// Derive the Triple::SubArchType for a canonical GPU record.
-static void emitSubArch(raw_ostream &OS, const Record *Rec) {
-  if (Rec->getValueAsBit("IsPseudoTarget")) {
-    OS << "Triple::NoSubArch";
-    return;
-  }
-
-  StringRef Suffix = Rec->getValueAsString("Name");
+// Derive the Triple::SubArchType from a "gfx..." GPU name, e.g. "gfx90a" ->
+// Triple::AMDGPUSubArch90A, "gfx9-generic" -> Triple::AMDGPUSubArch9 (the
+// family major). The name must be a real hardware GPU (not a pseudo target).
+static void emitSubArchForName(raw_ostream &OS, StringRef Name) {
+  StringRef Suffix = Name;
   Suffix.consume_front("gfx");
   Suffix.consume_back("-generic");
 
@@ -45,15 +44,33 @@ static void emitSubArch(raw_ostream &OS, const Record *Rec) {
     OS << ((C == '-') ? '_' : toUpper(C));
 }
 
-/// The gfx family for a canonical GPU record: the "-generic" family prefix
-/// (e.g.  "gfx9-4-generic" -> "gfx9"), or the name with its last two chars
-/// dropped for a concrete GPU (e.g. "gfx90a" -> "gfx9", "gfx1030" ->
-/// "gfx10"). Empty for a pseudo target.
+// Derive the Triple::SubArchType for a canonical GPU record. A pseudo target
+// represents no hardware and maps to Triple::NoSubArch; otherwise the subarch
+// is derived from the name.
+static void emitSubArch(raw_ostream &OS, const Record *Rec) {
+  if (Rec->getValueAsBit("IsPseudoTarget")) {
+    OS << "Triple::NoSubArch";
+    return;
+  }
+  emitSubArchForName(OS, Rec->getValueAsString("Name"));
+}
+
+// A canonical GPU record is a "gfxN-generic" family target if it covers a set
+// of concrete GPUs (via CoveredGPUs) rather than being a single piece of
+// hardware.
+static bool isGenericTarget(const Record *Rec) {
+  return !Rec->getValueAsListOfDefs("CoveredGPUs").empty();
+}
+
+// The gfx family for a canonical GPU record: the "-generic" family prefix (e.g.
+// "gfx9-4-generic" -> "gfx9"), or the name with its last two chars dropped for
+// a concrete GPU (e.g. "gfx90a" -> "gfx9", "gfx1030" -> "gfx10"). Empty for a
+// pseudo target.
 static StringRef getArchFamily(const Record *Rec) {
   if (Rec->getValueAsBit("IsPseudoTarget"))
     return "";
   StringRef Name = Rec->getValueAsString("Name");
-  if (Name.ends_with("-generic"))
+  if (isGenericTarget(Rec))
     return Name.take_front(Name.find('-'));
   return Name.drop_back(2);
 }
@@ -74,13 +91,6 @@ static void emitIsaVersion(raw_ostream &OS, const Record *Rec, char Open,
   OS << Open << V[0] << ", " << V[1] << ", " << V[2] << Close;
 }
 
-// A canonical GPU record is a "gfxN-generic" family target if it covers a set
-// of concrete GPUs (via CoveredGPUs) rather than being a single piece of
-// hardware.
-static bool isGenericTarget(const Record *Rec) {
-  return !Rec->getValueAsListOfDefs("CoveredGPUs").empty();
-}
-
 // A canonical GPU or a ProcessorAlias.
 namespace {
 struct GPUEntry {
@@ -301,6 +311,61 @@ static void emitAMDGPUTable(raw_ostream &OS, const RecordKeeper &RK) {
         "#endif // GET_AMDGPU_GPU_TABLE\n\n";
 }
 
+// Emit the subarch -> major-family-subarch overrides; a subarch not listed here
+// is its own major subarch. Each entry maps a member GPU's own subarch to its
+// family's major subarch, from one of two sources: a "gfxN-generic" target,
+// whose subarch is the major for every GPU it lists in CoveredGPUs, or an
+// AMDGPUFamily's MajorSubArch for the gfx6/gfx7/gfx8 families that have no
+// generic target.
+static void emitAMDGPUMajorSubArch(raw_ostream &OS, const RecordKeeper &RK) {
+  ArrayRef<const Record *> GPUs =
+      RK.getAllDerivedDefinitionsIfDefined("AMDGPUGPUInfo");
+  ArrayRef<const Record *> Families =
+      RK.getAllDerivedDefinitionsIfDefined("AMDGPUFamily");
+
+  // The overrides come from generic targets' CoveredGPUs and AMDGPUFamily
+  // members. std::array makes the R600 case (zero entries) well-formed.
+  size_t NumEntries = 0;
+  for (const Record *G : GPUs)
+    NumEntries += G->getValueAsListOfDefs("CoveredGPUs").size();
+  for (const Record *F : Families)
+    NumEntries += F->getValueAsListOfDefs("Members").size();
+
+  OS << "#ifdef GET_AMDGPU_MAJOR_SUBARCH\n"
+        "#undef GET_AMDGPU_MAJOR_SUBARCH\n"
+        "struct AMDGPUMajorSubArchEntry {\n"
+        "  Triple::SubArchType SubArch;\n"
+        "  Triple::SubArchType Major;\n"
+        "};\n"
+        "static constexpr std::array<AMDGPUMajorSubArchEntry, "
+     << NumEntries << "> AMDGPUMajorSubArch = {{\n";
+
+  // A "gfxN-generic" target's subarch is the major for every GPU it covers.
+  for (const Record *G : GPUs) {
+    for (const Record *Member : G->getValueAsListOfDefs("CoveredGPUs")) {
+      OS << "  {";
+      emitSubArchForName(OS, Member->getValueAsString("Name"));
+      OS << ", ";
+      emitSubArch(OS, G);
+      OS << "},\n";
+    }
+  }
+
+  // The gfx6/gfx7/gfx8 families have no generic target, so their major comes
+  // from AMDGPUFamily::MajorSubArch.
+  for (const Record *F : Families) {
+    StringRef Major = F->getValueAsString("MajorSubArch");
+    for (const Record *Member : F->getValueAsListOfDefs("Members")) {
+      OS << "  {";
+      emitSubArchForName(OS, Member->getValueAsString("Name"));
+      OS << ", Triple::AMDGPUSubArch" << Major << "},\n";
+    }
+  }
+
+  OS << "}};\n"
+        "#endif // GET_AMDGPU_MAJOR_SUBARCH\n\n";
+}
+
 static void emitAMDGPUTargetDef(const RecordKeeper &RK, raw_ostream &OS) {
   OS << "// Autogenerated by AMDGPUTargetDefEmitter.cpp\n\n";
   // R600 processors are Processor records; AMDGPU processors are
@@ -310,6 +375,7 @@ static void emitAMDGPUTargetDef(const RecordKeeper &RK, raw_ostream &OS) {
   emitR600(OS, RK);
   emitAMDGPU(OS, RK);
   emitAMDGPUTable(OS, RK);
+  emitAMDGPUMajorSubArch(OS, RK);
 }
 
 static TableGen::Emitter::Opt X("gen-amdgpu-target-def", emitAMDGPUTargetDef,



More information about the llvm-branch-commits mailing list