[clang] [llvm] AMDGPU: Eliminate old macro driven processor name parsing (PR #212608)

Matt Arsenault via cfe-commits cfe-commits at lists.llvm.org
Wed Jul 29 23:51:56 PDT 2026


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

>From 88554dceb0e1df633f2af1e7395c93211faef821 Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Mon, 27 Jul 2026 22:35:25 +0200
Subject: [PATCH] AMDGPU: Eliminate old macro driven processor name parsing

Previously the generated inc file had a series of macros for use
with StringSwitch; now just directly scan the generated name table.

Co-authored-by: Claude (Claude-Opus-4.8)
---
 .../Misc/target-invalid-cpu-note/amdgcn.c     |  36 +--
 .../test/Misc/target-invalid-cpu-note/r600.c  |  20 +-
 .../llvm/TargetParser/AMDGPUTargetParser.h    |   4 +-
 llvm/lib/TargetParser/AMDGPUTargetParser.cpp  | 115 +++++---
 .../TableGen/Basic/AMDGPUTargetDefEmitter.cpp | 256 +++++++++++-------
 5 files changed, 254 insertions(+), 177 deletions(-)

diff --git a/clang/test/Misc/target-invalid-cpu-note/amdgcn.c b/clang/test/Misc/target-invalid-cpu-note/amdgcn.c
index c898accc6db5f..3e641a3944397 100644
--- a/clang/test/Misc/target-invalid-cpu-note/amdgcn.c
+++ b/clang/test/Misc/target-invalid-cpu-note/amdgcn.c
@@ -6,37 +6,19 @@
 // CHECK: error: unknown target CPU 'not-a-cpu'
 // CHECK-NEXT: note: valid target CPU values are:
 // CHECK-SAME: {{^}} gfx600
-// CHECK-SAME: {{^}}, tahiti
 // CHECK-SAME: {{^}}, gfx601
-// CHECK-SAME: {{^}}, pitcairn
-// CHECK-SAME: {{^}}, verde
 // CHECK-SAME: {{^}}, gfx602
-// CHECK-SAME: {{^}}, hainan
-// CHECK-SAME: {{^}}, oland
 // CHECK-SAME: {{^}}, gfx700
-// CHECK-SAME: {{^}}, kaveri
 // CHECK-SAME: {{^}}, gfx701
-// CHECK-SAME: {{^}}, hawaii
 // CHECK-SAME: {{^}}, gfx702
 // CHECK-SAME: {{^}}, gfx703
-// CHECK-SAME: {{^}}, kabini
-// CHECK-SAME: {{^}}, mullins
 // CHECK-SAME: {{^}}, gfx704
-// CHECK-SAME: {{^}}, bonaire
 // CHECK-SAME: {{^}}, gfx705
 // CHECK-SAME: {{^}}, gfx801
-// CHECK-SAME: {{^}}, carrizo
 // CHECK-SAME: {{^}}, gfx802
-// CHECK-SAME: {{^}}, iceland
-// CHECK-SAME: {{^}}, tonga
 // CHECK-SAME: {{^}}, gfx803
-// CHECK-SAME: {{^}}, fiji
-// CHECK-SAME: {{^}}, polaris10
-// CHECK-SAME: {{^}}, polaris11
 // CHECK-SAME: {{^}}, gfx805
-// CHECK-SAME: {{^}}, tongapro
 // CHECK-SAME: {{^}}, gfx810
-// CHECK-SAME: {{^}}, stoney
 // CHECK-SAME: {{^}}, gfx900
 // CHECK-SAME: {{^}}, gfx902
 // CHECK-SAME: {{^}}, gfx904
@@ -84,6 +66,24 @@
 // CHECK-SAME: {{^}}, gfx12-generic
 // CHECK-SAME: {{^}}, gfx12-5-generic
 // CHECK-SAME: {{^}}, gfx13-generic
+// CHECK-SAME: {{^}}, tahiti
+// CHECK-SAME: {{^}}, pitcairn
+// CHECK-SAME: {{^}}, verde
+// CHECK-SAME: {{^}}, hainan
+// CHECK-SAME: {{^}}, oland
+// CHECK-SAME: {{^}}, kaveri
+// CHECK-SAME: {{^}}, hawaii
+// CHECK-SAME: {{^}}, kabini
+// CHECK-SAME: {{^}}, mullins
+// CHECK-SAME: {{^}}, bonaire
+// CHECK-SAME: {{^}}, carrizo
+// CHECK-SAME: {{^}}, iceland
+// CHECK-SAME: {{^}}, tonga
+// CHECK-SAME: {{^}}, fiji
+// CHECK-SAME: {{^}}, polaris10
+// CHECK-SAME: {{^}}, polaris11
+// CHECK-SAME: {{^}}, tongapro
+// CHECK-SAME: {{^}}, stoney
 // CHECK-SAME: {{$}}
 
 // The pseudo targets "generic"/"generic-hsa" may not be used.
diff --git a/clang/test/Misc/target-invalid-cpu-note/r600.c b/clang/test/Misc/target-invalid-cpu-note/r600.c
index 1481d41745ea9..bc0d27e832442 100644
--- a/clang/test/Misc/target-invalid-cpu-note/r600.c
+++ b/clang/test/Misc/target-invalid-cpu-note/r600.c
@@ -6,29 +6,29 @@
 // CHECK: error: unknown target CPU 'not-a-cpu'
 // CHECK-NEXT: note: valid target CPU values are:
 // CHECK-SAME: {{^}} r600
-// CHECK-SAME: {{^}}, rv630
-// CHECK-SAME: {{^}}, rv635
 // CHECK-SAME: {{^}}, r630
-// CHECK-SAME: {{^}}, rs780
 // CHECK-SAME: {{^}}, rs880
-// CHECK-SAME: {{^}}, rv610
-// CHECK-SAME: {{^}}, rv620
 // CHECK-SAME: {{^}}, rv670
 // CHECK-SAME: {{^}}, rv710
 // CHECK-SAME: {{^}}, rv730
-// CHECK-SAME: {{^}}, rv740
 // CHECK-SAME: {{^}}, rv770
 // CHECK-SAME: {{^}}, cedar
-// CHECK-SAME: {{^}}, palm
 // CHECK-SAME: {{^}}, cypress
-// CHECK-SAME: {{^}}, hemlock
 // CHECK-SAME: {{^}}, juniper
 // CHECK-SAME: {{^}}, redwood
 // CHECK-SAME: {{^}}, sumo
-// CHECK-SAME: {{^}}, sumo2
 // CHECK-SAME: {{^}}, barts
 // CHECK-SAME: {{^}}, caicos
-// CHECK-SAME: {{^}}, aruba
 // CHECK-SAME: {{^}}, cayman
 // CHECK-SAME: {{^}}, turks
+// CHECK-SAME: {{^}}, rv630
+// CHECK-SAME: {{^}}, rv635
+// CHECK-SAME: {{^}}, rs780
+// CHECK-SAME: {{^}}, rv610
+// CHECK-SAME: {{^}}, rv620
+// CHECK-SAME: {{^}}, rv740
+// CHECK-SAME: {{^}}, palm
+// CHECK-SAME: {{^}}, hemlock
+// CHECK-SAME: {{^}}, sumo2
+// CHECK-SAME: {{^}}, aruba
 // CHECK-SAME: {{$}}
diff --git a/llvm/include/llvm/TargetParser/AMDGPUTargetParser.h b/llvm/include/llvm/TargetParser/AMDGPUTargetParser.h
index c83528b76c7f9..8f8decdb373ce 100644
--- a/llvm/include/llvm/TargetParser/AMDGPUTargetParser.h
+++ b/llvm/include/llvm/TargetParser/AMDGPUTargetParser.h
@@ -35,10 +35,10 @@ enum GPUKind : uint32_t {
   // Not specified processor.
   GK_NONE = 0,
 
-#define R600_GPU(NAME, ENUM, FEATURES) ENUM,
+#define GET_R600_GPU_ENUM
 #include "llvm/TargetParser/R600TargetParserDef.inc"
 
-#define AMDGPU_GPU(NAME, ENUM) ENUM,
+#define GET_AMDGPU_GPU_ENUM
 #include "llvm/TargetParser/AMDGPUTargetParserDef.inc"
 };
 
diff --git a/llvm/lib/TargetParser/AMDGPUTargetParser.cpp b/llvm/lib/TargetParser/AMDGPUTargetParser.cpp
index 72b474cff7cc1..f866a092d6697 100644
--- a/llvm/lib/TargetParser/AMDGPUTargetParser.cpp
+++ b/llvm/lib/TargetParser/AMDGPUTargetParser.cpp
@@ -13,10 +13,8 @@
 #include "llvm/TargetParser/AMDGPUTargetParser.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/StringSwitch.h"
 #include "llvm/ADT/StringTable.h"
 #include "llvm/ADT/Twine.h"
-#include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/raw_ostream.h"
 #include "llvm/TargetParser/Triple.h"
 #include <array>
@@ -28,6 +26,12 @@ namespace {
 constexpr unsigned NumAMDGPUSubArches =
     Triple::LastAMDGPUSubArch - Triple::FirstAMDGPUSubArch + 1;
 
+// A legacy GPU name (e.g. "tahiti") mapped to the GPUKind it aliases.
+struct GPUNameAlias {
+  StringTable::Offset AltName;
+  GPUKind Kind;
+};
+
 // Per-GPU data for the AMDGCN GPUKinds, from the generated table below.
 struct GPUInfo {
   StringTable::Offset Name;
@@ -37,15 +41,28 @@ struct GPUInfo {
   StringTable::Offset FamilyName;
 };
 
+// Per-GPU data for the R600 GPUKinds.
+struct R600Info {
+  StringTable::Offset Name;
+  R600FeatureKind ArchFeatures;
+};
+
 #define GET_AMDGPU_NAME_TABLE
 #define GET_AMDGPU_GPU_TABLE
+#define GET_AMDGPU_GPU_ALIAS_TABLE
 #define GET_AMDGPU_MAJOR_SUBARCH
 #define GET_AMDGPU_SUBARCH_NAME
 #include "llvm/TargetParser/AMDGPUTargetParserDef.inc"
 
-// The string table shared by every generated table that stores GPU-name-derived
-// strings as offsets.
+#define GET_R600_NAME_TABLE
+#define GET_R600_GPU_TABLE
+#define GET_R600_GPU_ALIAS_TABLE
+#include "llvm/TargetParser/R600TargetParserDef.inc"
+
+// The string tables holding GPU-name-derived strings as offsets. R600 and
+// AMDGPU come from separate generated headers, each with its own pool.
 constexpr StringTable AMDGPUNameStrTab = AMDGPUNameTable;
+constexpr StringTable R600NameStrTab = R600NameTable;
 
 // Look up the GPUInfo row for an AMDGCN GPUKind, or nullptr for GK_NONE / a
 // non-AMDGCN (R600) kind.
@@ -58,6 +75,34 @@ const GPUInfo *getAMDGPUInfo(GPUKind AK) {
   return &AMDGPUGPUTable[Idx];
 }
 
+// Look up the R600Info row for an R600 GPUKind, or nullptr for a non-R600 kind.
+const R600Info *getR600Info(GPUKind AK) {
+  if (AK < R600FirstGPUKind)
+    return nullptr;
+  unsigned Idx = AK - R600FirstGPUKind;
+  if (Idx >= std::size(R600GPUTable))
+    return nullptr;
+  return &R600GPUTable[Idx];
+}
+
+// Scan a name -> GPUKind table (canonical names, then aliases) for \p CPU.
+template <typename InfoT, size_t N, size_t M>
+GPUKind parseArchImpl(StringRef CPU, const InfoT (&Table)[N], GPUKind FirstKind,
+                      const StringTable &StrTab,
+                      const GPUNameAlias (&Aliases)[M]) {
+  for (unsigned I = 0; I != N; ++I) {
+    if (CPU == StrTab[Table[I].Name])
+      return static_cast<GPUKind>(FirstKind + I);
+  }
+
+  for (const GPUNameAlias &A : Aliases) {
+    if (CPU == StrTab[A.AltName])
+      return A.Kind;
+  }
+
+  return GK_NONE;
+}
+
 // Reverse map: SubArch -> GPUKind, indexed by (SubArch - FirstAMDGPUSubArch).
 // Subarches with no GPU (incl. the NoSubArch pseudo targets) map to GK_NONE.
 constexpr std::array<GPUKind, NumAMDGPUSubArches> AMDGPUSubArchToGPUKind = [] {
@@ -220,30 +265,18 @@ StringRef llvm::AMDGPU::getArchNameFromSubArch(Triple::SubArchType SubArch) {
 }
 
 StringRef llvm::AMDGPU::getArchNameR600(GPUKind AK) {
-  switch (AK) {
-#define R600_GPU(NAME, ENUM, FEATURES)                                         \
-  case ENUM:                                                                   \
-    return NAME;
-#include "llvm/TargetParser/R600TargetParserDef.inc"
-  default:
-    return "";
-  }
+  const R600Info *Info = getR600Info(AK);
+  return Info ? R600NameStrTab[Info->Name] : "";
 }
 
 AMDGPU::GPUKind llvm::AMDGPU::parseArchAMDGCN(StringRef CPU) {
-  return StringSwitch<AMDGPU::GPUKind>(CPU)
-#define AMDGPU_GPU(NAME, ENUM) .Case(NAME, ENUM)
-#define AMDGPU_GPU_ALIAS(NAME, ENUM) .Case(NAME, ENUM)
-#include "llvm/TargetParser/AMDGPUTargetParserDef.inc"
-      .Default(AMDGPU::GPUKind::GK_NONE);
+  return parseArchImpl(CPU, AMDGPUGPUTable, AMDGPUFirstGPUKind,
+                       AMDGPUNameStrTab, AMDGPUGPUAliases);
 }
 
 AMDGPU::GPUKind llvm::AMDGPU::parseArchR600(StringRef CPU) {
-  return StringSwitch<AMDGPU::GPUKind>(CPU)
-#define R600_GPU(NAME, ENUM, FEATURES) .Case(NAME, ENUM)
-#define R600_GPU_ALIAS(NAME, ENUM) .Case(NAME, ENUM)
-#include "llvm/TargetParser/R600TargetParserDef.inc"
-      .Default(AMDGPU::GPUKind::GK_NONE);
+  return parseArchImpl(CPU, R600GPUTable, R600FirstGPUKind, R600NameStrTab,
+                       R600GPUAliases);
 }
 
 unsigned AMDGPU::getArchAttrAMDGCN(GPUKind AK) {
@@ -256,36 +289,32 @@ unsigned AMDGPU::getArchAttrAMDGCN(Triple::SubArchType SubArch) {
 }
 
 R600FeatureKind AMDGPU::getArchAttrR600(GPUKind AK) {
-  switch (AK) {
-#define R600_GPU(NAME, ENUM, FEATURES)                                         \
-  case ENUM:                                                                   \
-    return FEATURES;
-#include "llvm/TargetParser/R600TargetParserDef.inc"
-  default:
-    return R600_FEATURE_NONE;
-  }
+  const R600Info *Info = getR600Info(AK);
+  return Info ? Info->ArchFeatures : R600_FEATURE_NONE;
 }
 
 void AMDGPU::fillValidArchListAMDGCN(SmallVectorImpl<StringRef> &Values,
                                      Triple::SubArchType SubArch) {
   // XXX: Should this only report unique canonical names?
   // An alias shares its GPU's GPUKind, so it is filtered alongside it.
-#define AMDGPU_GPU(NAME, ENUM)                                                 \
-  if (getSubArch(ENUM) != Triple::NoSubArch &&                                 \
-      isCPUValidForSubArch(SubArch, ENUM))                                     \
-    Values.push_back(NAME);
-#define AMDGPU_GPU_ALIAS(NAME, ENUM)                                           \
-  if (isCPUValidForSubArch(SubArch, ENUM))                                     \
-    Values.push_back(NAME);
-#include "llvm/TargetParser/AMDGPUTargetParserDef.inc"
+  for (unsigned I = 0; I != std::size(AMDGPUGPUTable); ++I) {
+    GPUKind Kind = static_cast<GPUKind>(AMDGPUFirstGPUKind + I);
+    if (AMDGPUGPUTable[I].SubArch != Triple::NoSubArch &&
+        isCPUValidForSubArch(SubArch, Kind))
+      Values.push_back(AMDGPUNameStrTab[AMDGPUGPUTable[I].Name]);
+  }
+
+  for (const GPUNameAlias &A : AMDGPUGPUAliases) {
+    if (isCPUValidForSubArch(SubArch, A.Kind))
+      Values.push_back(AMDGPUNameStrTab[A.AltName]);
+  }
 }
 
 void AMDGPU::fillValidArchListR600(SmallVectorImpl<StringRef> &Values) {
-  Values.append({
-#define R600_GPU(NAME, ENUM, FEATURES) NAME,
-#define R600_GPU_ALIAS(NAME, ENUM) NAME,
-#include "llvm/TargetParser/R600TargetParserDef.inc"
-  });
+  for (const R600Info &Info : R600GPUTable)
+    Values.push_back(R600NameStrTab[Info.Name]);
+  for (const GPUNameAlias &A : R600GPUAliases)
+    Values.push_back(R600NameStrTab[A.AltName]);
 }
 
 AMDGPU::IsaVersion AMDGPU::getIsaVersion(StringRef GPU) {
diff --git a/llvm/utils/TableGen/Basic/AMDGPUTargetDefEmitter.cpp b/llvm/utils/TableGen/Basic/AMDGPUTargetDefEmitter.cpp
index 4a675bd8f8339..5588a74719428 100644
--- a/llvm/utils/TableGen/Basic/AMDGPUTargetDefEmitter.cpp
+++ b/llvm/utils/TableGen/Basic/AMDGPUTargetDefEmitter.cpp
@@ -179,121 +179,155 @@ static void validate(ArrayRef<GPUEntry> Entries) {
   }
 }
 
-static void emitR600(raw_ostream &OS, const RecordKeeper &RK) {
+// The canonical R600 GPU records, in GPUKind-enum / TableGen definition order.
+static std::vector<const Record *>
+collectR600Canonicals(const RecordKeeper &RK) {
+  std::vector<GPUEntry> Entries = collectGPUs(RK, /*WantR600=*/true);
+  std::vector<const Record *> Canon;
+  Canon.reserve(Entries.size());
+
+  for (const GPUEntry &E : Entries) {
+    if (!E.IsAlias)
+      Canon.push_back(E.Rec);
+  }
+
+  return Canon;
+}
+
+// Emit the R600 GPUKind enumerators (canonical GPUs only; aliases share a
+// canonical's kind). Guarded by GET_R600_GPU_ENUM.
+static void emitR600Enum(raw_ostream &OS, const RecordKeeper &RK) {
+  std::vector<const Record *> Canon = collectR600Canonicals(RK);
+  if (Canon.empty())
+    return;
+  OS << "#ifdef GET_R600_GPU_ENUM\n"
+        "#undef GET_R600_GPU_ENUM\n";
+  for (const Record *R : Canon) {
+    OS << "  ";
+    emitGPUKindEnum(OS, R->getValueAsString("Name"));
+    OS << ",\n";
+  }
+  OS << "#endif // GET_R600_GPU_ENUM\n\n";
+}
+
+// Emit the R600Info table indexed by (GPUKind - R600FirstGPUKind). Names are
+// offsets into the shared \p Names table. Guarded by GET_R600_GPU_TABLE.
+static void emitR600Table(raw_ostream &OS, const RecordKeeper &RK,
+                          StringToOffsetTable &Names) {
+  std::vector<const Record *> Canon = collectR600Canonicals(RK);
+  if (Canon.empty())
+    return;
+
+  OS << "#ifdef GET_R600_GPU_TABLE\n"
+        "#undef GET_R600_GPU_TABLE\n";
+  OS << "static constexpr GPUKind R600FirstGPUKind = ";
+  emitGPUKindEnum(OS, Canon.front()->getValueAsString("Name"));
+  OS << ";\n"
+        "static constexpr R600Info R600GPUTable[] = {\n";
+  for (const Record *R : Canon) {
+    OS << "  {" << Names.GetOrAddStringOffset(R->getValueAsString("Name"))
+       << ", ";
+    emitFeatureExpr(OS, R, "R600_FEATURE_NONE");
+    OS << "},\n";
+  }
+  OS << "};\n"
+        "#endif // GET_R600_GPU_TABLE\n\n";
+}
+
+// Emit the R600 name -> GPUKind alias table. Guarded by
+// GET_R600_GPU_ALIAS_TABLE; names are offsets into \p Names.
+static void emitR600Aliases(raw_ostream &OS, const RecordKeeper &RK,
+                            StringToOffsetTable &Names) {
   std::vector<GPUEntry> Entries = collectGPUs(RK, /*WantR600=*/true);
   validate(Entries);
   if (Entries.empty())
     return;
 
-  OS << "#ifndef R600_GPU\n"
-        "#define R600_GPU(NAME, ENUM, FEATURES)\n"
-        "#endif\n\n"
-        "#ifndef R600_GPU_ALIAS\n"
-        "#define R600_GPU_ALIAS(NAME, ENUM)\n"
-        "#endif\n\n";
-
+  OS << "#ifdef GET_R600_GPU_ALIAS_TABLE\n"
+        "#undef GET_R600_GPU_ALIAS_TABLE\n"
+        "static constexpr GPUNameAlias R600GPUAliases[] = {\n";
   for (const GPUEntry &E : Entries) {
-    StringRef Name = E.Rec->getValueAsString("Name");
-    if (E.IsAlias) {
-      OS << "R600_GPU_ALIAS(\"" << Name << "\", ";
-      emitGPUKindEnum(OS, E.Rec->getValueAsString("Alias"));
-      OS << ")\n";
+    if (!E.IsAlias)
       continue;
-    }
-    OS << "R600_GPU(\"" << Name << "\", ";
-    emitGPUKindEnum(OS, Name);
-    OS << ", ";
-    emitFeatureExpr(OS, E.Rec, "R600_FEATURE_NONE");
-    OS << ")\n";
+    OS << "  {" << Names.GetOrAddStringOffset(E.Rec->getValueAsString("Name"))
+       << ", ";
+    emitGPUKindEnum(OS, E.Rec->getValueAsString("Alias"));
+    OS << "},\n";
   }
-
-  OS << "\n#undef R600_GPU\n"
-        "#undef R600_GPU_ALIAS\n";
+  OS << "};\n"
+        "#endif // GET_R600_GPU_ALIAS_TABLE\n\n";
 }
 
-// Return \p Entries with the generic-family entries moved after the non-generic
-// ones, each group keeping definition order. The GPUKind enum and GPUInfo table
-// are positional and rely on the generics forming a contiguous block at the
-// end, so both are emitted in this order.
-static std::vector<GPUEntry>
-orderGenericsLast(ArrayRef<GPUEntry> Entries,
-                  const StringMap<const Record *> &Canonicals) {
-  std::vector<GPUEntry> Ordered;
-  Ordered.reserve(Entries.size());
+// Canonical AMDGPU GPUs in GPUKind-enum order: non-generic targets first, then
+// the "gfxN-generic" targets. The enum and the GPUInfo table share this order.
+static std::vector<const Record *>
+collectAMDGPUCanonicals(const RecordKeeper &RK) {
+  std::vector<GPUEntry> Entries = collectGPUs(RK, /*WantR600=*/false);
+  std::vector<const Record *> Canon;
+  Canon.reserve(Entries.size());
 
   for (const GPUEntry &E : Entries) {
-    if (!E.isGeneric(Canonicals))
-      Ordered.push_back(E);
+    if (!E.IsAlias && !isGenericTarget(E.Rec))
+      Canon.push_back(E.Rec);
   }
 
   for (const GPUEntry &E : Entries) {
-    if (E.isGeneric(Canonicals))
-      Ordered.push_back(E);
+    if (!E.IsAlias && isGenericTarget(E.Rec))
+      Canon.push_back(E.Rec);
   }
 
-  return Ordered;
+  return Canon;
 }
 
-static void emitAMDGPUEntry(raw_ostream &OS, const GPUEntry &E) {
-  StringRef Name = E.Rec->getValueAsString("Name");
-  if (E.IsAlias) {
-    OS << "AMDGPU_GPU_ALIAS(\"" << Name << "\", ";
-    emitGPUKindEnum(OS, E.Rec->getValueAsString("Alias"));
-    OS << ")\n";
-  } else {
-    OS << "AMDGPU_GPU(\"" << Name << "\", ";
-    emitGPUKindEnum(OS, Name);
-    OS << ")\n";
+// Emit the AMDGPU GPUKind enumerators (canonical GPUs only; aliases share a
+// canonical's kind). Guarded by GET_AMDGPU_GPU_ENUM.
+static void emitAMDGPUEnum(raw_ostream &OS, const RecordKeeper &RK) {
+  std::vector<const Record *> Canon = collectAMDGPUCanonicals(RK);
+  if (Canon.empty())
+    return;
+  OS << "#ifdef GET_AMDGPU_GPU_ENUM\n"
+        "#undef GET_AMDGPU_GPU_ENUM\n";
+  for (const Record *R : Canon) {
+    OS << "  ";
+    emitGPUKindEnum(OS, R->getValueAsString("Name"));
+    OS << ",\n";
   }
+  OS << "#endif // GET_AMDGPU_GPU_ENUM\n\n";
 }
 
-static void emitAMDGPU(raw_ostream &OS, const RecordKeeper &RK) {
+// Emit the name -> GPUKind alias table (legacy names such as "tahiti" ->
+// gfx600). Guarded by GET_AMDGPU_GPU_ALIAS_TABLE; names are offsets into \p
+// Names.
+static void emitAMDGPUAliases(raw_ostream &OS, const RecordKeeper &RK,
+                              StringToOffsetTable &Names) {
   std::vector<GPUEntry> Entries = collectGPUs(RK, /*WantR600=*/false);
   validate(Entries);
   if (Entries.empty())
     return;
 
-  StringMap<const Record *> Canonicals;
+  OS << "#ifdef GET_AMDGPU_GPU_ALIAS_TABLE\n"
+        "#undef GET_AMDGPU_GPU_ALIAS_TABLE\n"
+        "static constexpr GPUNameAlias AMDGPUGPUAliases[] = {\n";
   for (const GPUEntry &E : Entries) {
     if (!E.IsAlias)
-      Canonicals[E.Rec->getValueAsString("Name")] = E.Rec;
+      continue;
+    OS << "  {" << Names.GetOrAddStringOffset(E.Rec->getValueAsString("Name"))
+       << ", ";
+    emitGPUKindEnum(OS, E.Rec->getValueAsString("Alias"));
+    OS << "},\n";
   }
-
-  OS << "#ifndef AMDGPU_GPU\n"
-        "#define AMDGPU_GPU(NAME, ENUM)\n"
-        "#endif\n\n"
-        "#ifndef AMDGPU_GPU_ALIAS\n"
-        "#define AMDGPU_GPU_ALIAS(NAME, ENUM)\n"
-        "#endif\n\n";
-
-  for (const GPUEntry &E : orderGenericsLast(Entries, Canonicals))
-    emitAMDGPUEntry(OS, E);
-
-  OS << "\n#undef AMDGPU_GPU\n"
-        "#undef AMDGPU_GPU_ALIAS\n";
+  OS << "};\n"
+        "#endif // GET_AMDGPU_GPU_ALIAS_TABLE\n\n";
 }
 
 /// Emit a GPUInfo table indexed by (GPUKind - AMDGPUFirstGPUKind). Name and
 /// family strings are stored as offsets into the shared \p Names table.
 static void emitAMDGPUTable(raw_ostream &OS, const RecordKeeper &RK,
                             StringToOffsetTable &Names) {
-  std::vector<GPUEntry> Entries = collectGPUs(RK, /*WantR600=*/false);
-  if (Entries.empty())
+  std::vector<const Record *> Canon = collectAMDGPUCanonicals(RK);
+  if (Canon.empty())
     return;
 
-  StringMap<const Record *> Canonicals;
-  for (const GPUEntry &E : Entries) {
-    if (!E.IsAlias)
-      Canonicals[E.Rec->getValueAsString("Name")] = E.Rec;
-  }
-
-  // Canonicals only; aliases share a canonical's GPUKind row.
-  std::vector<const Record *> Canon;
-  for (const GPUEntry &E : orderGenericsLast(Entries, Canonicals)) {
-    if (!E.IsAlias)
-      Canon.push_back(E.Rec);
-  }
-
   OS << "#ifdef GET_AMDGPU_GPU_TABLE\n"
         "#undef GET_AMDGPU_GPU_TABLE\n";
   OS << "static constexpr GPUKind AMDGPUFirstGPUKind = ";
@@ -314,11 +348,10 @@ 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
+// Emit the subarch -> major-family-subarch overrides for getMajorSubArch (a
+// subarch not listed here is its own major). Each member GPU maps to its
+// family's major, sourced from a "gfxN-generic" target's CoveredGPUs, or from
+// 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 =
@@ -408,30 +441,45 @@ static void emitAMDGPUSubArchNames(raw_ostream &OS, const RecordKeeper &RK,
 
 static void emitAMDGPUTargetDef(const RecordKeeper &RK, raw_ostream &OS) {
   OS << "// Autogenerated by AMDGPUTargetDefEmitter.cpp\n\n";
-  // R600 processors are Processor records; AMDGPU processors are
-  // ProcessorModel records. R600.td and AMDGPU.td are separate top-level files
-  // (neither includes the other), so exactly one family is present in a given
-  // run; the other section emits nothing.
-  emitR600(OS, RK);
-  emitAMDGPU(OS, RK);
+  // R600.td and AMDGPU.td are separate top-level files, so a run sees exactly
+  // one family; the other family's sections emit nothing.
+  emitR600Enum(OS, RK);
+  emitAMDGPUEnum(OS, RK);
   emitAMDGPUMajorSubArch(OS, RK);
 
-  // The GPUInfo and SubArchName tables both reference GPU-name strings; pool
-  // them into a single string table. Buffer the two tables first so every
-  // referenced string is interned, then emit the shared table def (guarded so
-  // consumers pull it in once) ahead of the buffered tables.
-  StringToOffsetTable Names;
-  std::string GPUTable, SubArchNames;
-  raw_string_ostream GPUTableOS(GPUTable), SubArchNamesOS(SubArchNames);
-  emitAMDGPUTable(GPUTableOS, RK, Names);
-  emitAMDGPUSubArchNames(SubArchNamesOS, RK, Names);
-
-  OS << "#ifdef GET_AMDGPU_NAME_TABLE\n"
-        "#undef GET_AMDGPU_NAME_TABLE\n";
-  Names.EmitStringTableDef(OS, "AMDGPUNameTable");
-  OS << "#endif // GET_AMDGPU_NAME_TABLE\n\n";
-
-  OS << GPUTable << SubArchNames;
+  // Each family gets its own string pool with a distinct guard/symbol so the
+  // two generated headers stay independent when a consumer includes both.
+  // Buffer the tables first to intern their strings, then emit the pool ahead.
+  {
+    StringToOffsetTable Names;
+    std::string Tables;
+    raw_string_ostream TablesOS(Tables);
+    emitR600Table(TablesOS, RK, Names);
+    emitR600Aliases(TablesOS, RK, Names);
+    if (!Tables.empty()) {
+      OS << "#ifdef GET_R600_NAME_TABLE\n"
+            "#undef GET_R600_NAME_TABLE\n";
+      Names.EmitStringTableDef(OS, "R600NameTable");
+      OS << "#endif // GET_R600_NAME_TABLE\n\n";
+      OS << Tables;
+    }
+  }
+
+  {
+    StringToOffsetTable Names;
+    std::string Tables;
+    raw_string_ostream TablesOS(Tables);
+    emitAMDGPUTable(TablesOS, RK, Names);
+    emitAMDGPUAliases(TablesOS, RK, Names);
+    emitAMDGPUSubArchNames(TablesOS, RK, Names);
+    if (!Tables.empty()) {
+      OS << "#ifdef GET_AMDGPU_NAME_TABLE\n"
+            "#undef GET_AMDGPU_NAME_TABLE\n";
+      Names.EmitStringTableDef(OS, "AMDGPUNameTable");
+      OS << "#endif // GET_AMDGPU_NAME_TABLE\n\n";
+      OS << Tables;
+    }
+  }
 }
 
 static TableGen::Emitter::Opt X("gen-amdgpu-target-def", emitAMDGPUTargetDef,



More information about the cfe-commits mailing list