[llvm] AMDGPU: Add -gen-amdgpu-target-def TableGen backend (PR #212318)

Matt Arsenault via llvm-commits llvm-commits at lists.llvm.org
Mon Jul 27 14:51:04 PDT 2026


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

>From ab3d1b8820b377ab56a666d5831508a2fec5ff46 Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Sun, 26 Jul 2026 22:26:01 +0200
Subject: [PATCH] AMDGPU: Add -gen-amdgpu-target-def TableGen backend

Currently subtarget information is duplicated between a def file and
the backend. There are also increasingly unwieldy mapping tables
for subarches. Work towards unifying these, starting with r600. This
mirrors aarch64 and riscv's existing custom targetparser backends (i.e.,
the prompt was copy what riscv does).

Co-authored-by: Claude (Claude-Opus-4.8)
---
 llvm/include/llvm/TargetParser/CMakeLists.txt |   3 +
 llvm/lib/Target/AMDGPU/AMDGPUFeatures.td      |   2 +
 llvm/lib/Target/AMDGPU/AMDGPUTargetParser.td  |  31 ++++
 llvm/lib/Target/AMDGPU/R600Processors.td      |  61 +++++---
 llvm/lib/TargetParser/AMDGPUTargetParser.cpp  |   8 +-
 llvm/test/TableGen/AMDGPUTargetDefErrors.td   |  42 ++++++
 .../TargetParser/TargetParserTest.cpp         |  64 +++++++++
 .../TableGen/Basic/AMDGPUTargetDefEmitter.cpp | 134 ++++++++++++++++++
 llvm/utils/TableGen/Basic/CMakeLists.txt      |   1 +
 9 files changed, 321 insertions(+), 25 deletions(-)
 create mode 100644 llvm/lib/Target/AMDGPU/AMDGPUTargetParser.td
 create mode 100644 llvm/test/TableGen/AMDGPUTargetDefErrors.td
 create mode 100644 llvm/utils/TableGen/Basic/AMDGPUTargetDefEmitter.cpp

diff --git a/llvm/include/llvm/TargetParser/CMakeLists.txt b/llvm/include/llvm/TargetParser/CMakeLists.txt
index 329317653c672..62e9da1447f68 100644
--- a/llvm/include/llvm/TargetParser/CMakeLists.txt
+++ b/llvm/include/llvm/TargetParser/CMakeLists.txt
@@ -10,5 +10,8 @@ tablegen(LLVM RISCVTargetParserDef.inc -gen-riscv-target-def EXTRA_INCLUDES ${PR
 set(LLVM_TARGET_DEFINITIONS ${PROJECT_SOURCE_DIR}/lib/Target/PowerPC/PPC.td)
 tablegen(LLVM PPCGenTargetFeatures.inc -gen-target-features EXTRA_INCLUDES ${PROJECT_SOURCE_DIR}/lib/Target/PowerPC)
 
+set(LLVM_TARGET_DEFINITIONS ${PROJECT_SOURCE_DIR}/lib/Target/AMDGPU/R600.td)
+tablegen(LLVM R600TargetParserDef.inc -gen-amdgpu-target-def EXTRA_INCLUDES ${PROJECT_SOURCE_DIR}/lib/Target/AMDGPU)
+
 # This covers all of the tablegen calls above.
 add_public_tablegen_target(target_parser_gen)
diff --git a/llvm/lib/Target/AMDGPU/AMDGPUFeatures.td b/llvm/lib/Target/AMDGPU/AMDGPUFeatures.td
index 594e2ad0e3e03..2c105c3804e35 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUFeatures.td
+++ b/llvm/lib/Target/AMDGPU/AMDGPUFeatures.td
@@ -6,6 +6,8 @@
 //
 //===----------------------------------------------------------------------===//
 
+include "AMDGPUTargetParser.td"
+
 def FeatureFP64 : SubtargetFeature<"fp64",
   "HasFP64",
   "true",
diff --git a/llvm/lib/Target/AMDGPU/AMDGPUTargetParser.td b/llvm/lib/Target/AMDGPU/AMDGPUTargetParser.td
new file mode 100644
index 0000000000000..ffa3869e7151e
--- /dev/null
+++ b/llvm/lib/Target/AMDGPU/AMDGPUTargetParser.td
@@ -0,0 +1,31 @@
+//===-- AMDGPUTargetParser.td - TargetParser metadata ------*- tablegen -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// TargetParser metadata attached to processor records for the
+// -gen-amdgpu-target-def backend.
+//
+//===----------------------------------------------------------------------===//
+
+// FIXME: These duplicate real SubtargetFeatures and should be unified
+// (e.g. FEATURE_XNACK mirrors FeatureXNACK).
+class AMDGPUArchFeature<string spelling> {
+  string Spelling = spelling;
+}
+
+// R600-only.
+def FEATURE_FMA : AMDGPUArchFeature<"FEATURE_FMA">;
+
+// Marks a Processor/ProcessorModel record as a canonical TargetParser GPU.
+class AMDGPUGPUInfo {
+  list<AMDGPUArchFeature> ArchFeatures = [];
+}
+
+// An R600 processor that is also a canonical TargetParser GPU.
+class R600ProcessorModel<string n, ProcessorItineraries pi,
+                         list<SubtargetFeature> f>
+    : Processor<n, pi, f>, AMDGPUGPUInfo;
diff --git a/llvm/lib/Target/AMDGPU/R600Processors.td b/llvm/lib/Target/AMDGPU/R600Processors.td
index dc21eb9ed011d..c893f4a11c952 100644
--- a/llvm/lib/Target/AMDGPU/R600Processors.td
+++ b/llvm/lib/Target/AMDGPU/R600Processors.td
@@ -68,24 +68,31 @@ def FeatureNorthernIslands : R600SubtargetFeatureGeneration<"NORTHERN_ISLANDS",
    FeatureAddressableLocalMemorySize32768, FeatureMadMacF32Insts]
 >;
 
-
 //===----------------------------------------------------------------------===//
 // Radeon HD 2000/3000 Series (R600).
 //===----------------------------------------------------------------------===//
 
-def : Processor<"r600", R600_VLIW5_Itin,
+def : R600ProcessorModel<"r600", R600_VLIW5_Itin,
   [FeatureR600, FeatureWavefrontSize64, FeatureVertexCache]
 >;
 
-def : Processor<"r630", R600_VLIW5_Itin,
+def : ProcessorAlias<"rv630", "r600">;
+def : ProcessorAlias<"rv635", "r600">;
+
+def : R600ProcessorModel<"r630", R600_VLIW5_Itin,
   [FeatureR600, FeatureWavefrontSize32, FeatureVertexCache]
 >;
 
-def : Processor<"rs880", R600_VLIW5_Itin,
+def : ProcessorAlias<"rs780", "rs880">;
+
+def : R600ProcessorModel<"rs880", R600_VLIW5_Itin,
   [FeatureR600, FeatureWavefrontSize16]
 >;
 
-def : Processor<"rv670", R600_VLIW5_Itin,
+def : ProcessorAlias<"rv610", "rs880">;
+def : ProcessorAlias<"rv620", "rs880">;
+
+def : R600ProcessorModel<"rv670", R600_VLIW5_Itin,
   [FeatureR600, FeatureWavefrontSize64, FeatureVertexCache]
 >;
 
@@ -93,15 +100,17 @@ def : Processor<"rv670", R600_VLIW5_Itin,
 // Radeon HD 4000 Series (R700).
 //===----------------------------------------------------------------------===//
 
-def : Processor<"rv710", R600_VLIW5_Itin,
+def : R600ProcessorModel<"rv710", R600_VLIW5_Itin,
   [FeatureR700, FeatureWavefrontSize32, FeatureVertexCache]
 >;
 
-def : Processor<"rv730", R600_VLIW5_Itin,
+def : R600ProcessorModel<"rv730", R600_VLIW5_Itin,
   [FeatureR700, FeatureWavefrontSize32, FeatureVertexCache]
 >;
 
-def : Processor<"rv770", R600_VLIW5_Itin,
+def : ProcessorAlias<"rv740", "rv770">;
+
+def : R600ProcessorModel<"rv770", R600_VLIW5_Itin,
   [FeatureR700, FeatureWavefrontSize64, FeatureVertexCache]
 >;
 
@@ -109,44 +118,54 @@ def : Processor<"rv770", R600_VLIW5_Itin,
 // Radeon HD 5000 Series (Evergreen).
 //===----------------------------------------------------------------------===//
 
-def : Processor<"cedar", R600_VLIW5_Itin,
+def : R600ProcessorModel<"cedar", R600_VLIW5_Itin,
   [FeatureEvergreen, FeatureWavefrontSize32, FeatureVertexCache,
    FeatureCFALUBug]
 >;
 
-def : Processor<"cypress", R600_VLIW5_Itin,
-  [FeatureEvergreen, FeatureWavefrontSize64, FeatureVertexCache, FeatureFMA]
->;
+def : ProcessorAlias<"palm", "cedar">;
 
-def : Processor<"juniper", R600_VLIW5_Itin,
+def : R600ProcessorModel<"cypress", R600_VLIW5_Itin,
+  [FeatureEvergreen, FeatureWavefrontSize64, FeatureVertexCache, FeatureFMA]> {
+  let ArchFeatures = [FEATURE_FMA];
+}
+
+def : ProcessorAlias<"hemlock", "cypress">;
+
+def : R600ProcessorModel<"juniper", R600_VLIW5_Itin,
   [FeatureEvergreen, FeatureWavefrontSize64, FeatureVertexCache]
 >;
 
-def : Processor<"redwood", R600_VLIW5_Itin,
+def : R600ProcessorModel<"redwood", R600_VLIW5_Itin,
   [FeatureEvergreen, FeatureWavefrontSize64, FeatureVertexCache,
    FeatureCFALUBug]
 >;
 
-def : Processor<"sumo", R600_VLIW5_Itin,
+def : R600ProcessorModel<"sumo", R600_VLIW5_Itin,
   [FeatureEvergreen, FeatureWavefrontSize64, FeatureCFALUBug]
 >;
 
+def : ProcessorAlias<"sumo2", "sumo">;
+
 //===----------------------------------------------------------------------===//
 // Radeon HD 6000 Series (Northern Islands).
 //===----------------------------------------------------------------------===//
 
-def : Processor<"barts", R600_VLIW5_Itin,
+def : R600ProcessorModel<"barts", R600_VLIW5_Itin,
   [FeatureNorthernIslands, FeatureVertexCache, FeatureCFALUBug]
 >;
 
-def : Processor<"caicos", R600_VLIW5_Itin,
+def : R600ProcessorModel<"caicos", R600_VLIW5_Itin,
   [FeatureNorthernIslands, FeatureCFALUBug]
 >;
 
-def : Processor<"cayman", R600_VLIW4_Itin,
-  [FeatureNorthernIslands, FeatureCaymanISA, FeatureFMA]
->;
+def : ProcessorAlias<"aruba", "cayman">;
+
+def : R600ProcessorModel<"cayman", R600_VLIW4_Itin,
+  [FeatureNorthernIslands, FeatureCaymanISA, FeatureFMA]> {
+  let ArchFeatures = [FEATURE_FMA];
+}
 
-def : Processor<"turks", R600_VLIW5_Itin,
+def : R600ProcessorModel<"turks", R600_VLIW5_Itin,
   [FeatureNorthernIslands, FeatureVertexCache, FeatureCFALUBug]
 >;
diff --git a/llvm/lib/TargetParser/AMDGPUTargetParser.cpp b/llvm/lib/TargetParser/AMDGPUTargetParser.cpp
index 51e4b6f0e6e59..dbc3b59a0861b 100644
--- a/llvm/lib/TargetParser/AMDGPUTargetParser.cpp
+++ b/llvm/lib/TargetParser/AMDGPUTargetParser.cpp
@@ -245,7 +245,7 @@ StringRef llvm::AMDGPU::getArchNameR600(GPUKind AK) {
 #define R600_GPU(NAME, ENUM, FEATURES)                                         \
   case ENUM:                                                                   \
     return NAME;
-#include "llvm/TargetParser/AMDGPUTargetParser.def"
+#include "llvm/TargetParser/R600TargetParserDef.inc"
   default:
     return "";
   }
@@ -265,7 +265,7 @@ 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/AMDGPUTargetParser.def"
+#include "llvm/TargetParser/R600TargetParserDef.inc"
       .Default(AMDGPU::GPUKind::GK_NONE);
 }
 
@@ -296,7 +296,7 @@ unsigned AMDGPU::getArchAttrR600(GPUKind AK) {
 #define R600_GPU(NAME, ENUM, FEATURES)                                         \
   case ENUM:                                                                   \
     return FEATURES;
-#include "llvm/TargetParser/AMDGPUTargetParser.def"
+#include "llvm/TargetParser/R600TargetParserDef.inc"
   default:
     return FEATURE_NONE;
   }
@@ -319,7 +319,7 @@ 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/AMDGPUTargetParser.def"
+#include "llvm/TargetParser/R600TargetParserDef.inc"
   });
 }
 
diff --git a/llvm/test/TableGen/AMDGPUTargetDefErrors.td b/llvm/test/TableGen/AMDGPUTargetDefErrors.td
new file mode 100644
index 0000000000000..922ca47353d58
--- /dev/null
+++ b/llvm/test/TableGen/AMDGPUTargetDefErrors.td
@@ -0,0 +1,42 @@
+// RUN: rm -rf %t && split-file %s %t
+// RUN: not llvm-tblgen -gen-amdgpu-target-def -I %p/../../include %t/bad-alias.td 2>&1 \
+// RUN:   | FileCheck %t/bad-alias.td -DFILE=%t/bad-alias.td --implicit-check-not="error:"
+// RUN: not llvm-tblgen -gen-amdgpu-target-def -I %p/../../include %t/dup-processor.td 2>&1 \
+// RUN:   | FileCheck %t/dup-processor.td -DFILE=%t/dup-processor.td --implicit-check-not="error:"
+// RUN: not llvm-tblgen -gen-amdgpu-target-def -I %p/../../include %t/alias-shadows-processor.td 2>&1 \
+// RUN:   | FileCheck %t/alias-shadows-processor.td -DFILE=%t/alias-shadows-processor.td --implicit-check-not="error:"
+
+// Verify the validation performed by the -gen-amdgpu-target-def backend.
+
+//--- bad-alias.td
+include "llvm/Target/Target.td"
+def MyTarget : Target;
+class AMDGPUArchFeature<string spelling> { string Spelling = spelling; }
+class AMDGPUGPUInfo { list<AMDGPUArchFeature> ArchFeatures = []; }
+
+def : ProcessorModel<"gfx900", NoSchedModel, []>, AMDGPUGPUInfo;
+// An alias must resolve to a canonical AMDGPU GPU.
+// CHECK: [[FILE]]:[[#@LINE+1]]:1: error: ProcessorAlias 'foo' aliases 'gfx-missing' which is not a canonical AMDGPU GPU
+def : ProcessorAlias<"foo", "gfx-missing">;
+
+//--- dup-processor.td
+include "llvm/Target/Target.td"
+def MyTarget : Target;
+class AMDGPUArchFeature<string spelling> { string Spelling = spelling; }
+class AMDGPUGPUInfo { list<AMDGPUArchFeature> ArchFeatures = []; }
+
+def DupA : ProcessorModel<"gfx900", NoSchedModel, []>, AMDGPUGPUInfo;
+// A canonical GPU name must be unique.
+// CHECK: [[FILE]]:[[#@LINE+1]]:5: error: duplicate AMDGPU processor name 'gfx900'
+def DupB : ProcessorModel<"gfx900", NoSchedModel, []>, AMDGPUGPUInfo;
+
+//--- alias-shadows-processor.td
+include "llvm/Target/Target.td"
+def MyTarget : Target;
+class AMDGPUArchFeature<string spelling> { string Spelling = spelling; }
+class AMDGPUGPUInfo { list<AMDGPUArchFeature> ArchFeatures = []; }
+
+def : ProcessorModel<"gfx900", NoSchedModel, []>, AMDGPUGPUInfo;
+// An alias name must not collide with a canonical GPU name.
+// CHECK: [[FILE]]:[[#@LINE+1]]:1: error: duplicate AMDGPU processor name 'gfx900'
+def : ProcessorAlias<"gfx900", "gfx900">;
diff --git a/llvm/unittests/TargetParser/TargetParserTest.cpp b/llvm/unittests/TargetParser/TargetParserTest.cpp
index d2d89f11734ef..54325fcc20141 100644
--- a/llvm/unittests/TargetParser/TargetParserTest.cpp
+++ b/llvm/unittests/TargetParser/TargetParserTest.cpp
@@ -2661,6 +2661,70 @@ TEST(TargetParserTest, testAMDGPUisCPUValidForSubArch) {
   EXPECT_FALSE(AMDGPU::isCPUValidForSubArch(Triple::NoSubArch, ""));
 }
 
+TEST(TargetParserTest, testAMDGPUparseArchR600) {
+  // Canonical R600 GPU names map to their own GPUKind and round-trip through
+  // getArchNameR600.
+  struct CanonicalGPU {
+    StringRef Name;
+    AMDGPU::GPUKind Kind;
+    unsigned Features;
+  };
+  static const CanonicalGPU Canonicals[] = {
+      {"r600", AMDGPU::GK_R600, AMDGPU::FEATURE_NONE},
+      {"r630", AMDGPU::GK_R630, AMDGPU::FEATURE_NONE},
+      {"rs880", AMDGPU::GK_RS880, AMDGPU::FEATURE_NONE},
+      {"rv670", AMDGPU::GK_RV670, AMDGPU::FEATURE_NONE},
+      {"rv710", AMDGPU::GK_RV710, AMDGPU::FEATURE_NONE},
+      {"rv730", AMDGPU::GK_RV730, AMDGPU::FEATURE_NONE},
+      {"rv770", AMDGPU::GK_RV770, AMDGPU::FEATURE_NONE},
+      {"cedar", AMDGPU::GK_CEDAR, AMDGPU::FEATURE_NONE},
+      {"cypress", AMDGPU::GK_CYPRESS, AMDGPU::FEATURE_FMA},
+      {"juniper", AMDGPU::GK_JUNIPER, AMDGPU::FEATURE_NONE},
+      {"redwood", AMDGPU::GK_REDWOOD, AMDGPU::FEATURE_NONE},
+      {"sumo", AMDGPU::GK_SUMO, AMDGPU::FEATURE_NONE},
+      {"barts", AMDGPU::GK_BARTS, AMDGPU::FEATURE_NONE},
+      {"caicos", AMDGPU::GK_CAICOS, AMDGPU::FEATURE_NONE},
+      {"cayman", AMDGPU::GK_CAYMAN, AMDGPU::FEATURE_FMA},
+      {"turks", AMDGPU::GK_TURKS, AMDGPU::FEATURE_NONE},
+  };
+  for (const CanonicalGPU &G : Canonicals) {
+    EXPECT_EQ(AMDGPU::parseArchR600(G.Name), G.Kind) << G.Name;
+    EXPECT_EQ(AMDGPU::getArchNameR600(G.Kind), G.Name) << G.Name;
+    EXPECT_EQ(AMDGPU::getArchAttrR600(G.Kind), G.Features) << G.Name;
+  }
+
+  // Aliases resolve to the canonical GPUKind but are not returned by
+  // getArchNameR600.
+  struct AliasGPU {
+    StringRef Alias;
+    AMDGPU::GPUKind Kind;
+  };
+  static const AliasGPU Aliases[] = {
+      {"rv630", AMDGPU::GK_R600},  {"rv635", AMDGPU::GK_R600},
+      {"rs780", AMDGPU::GK_RS880}, {"rv610", AMDGPU::GK_RS880},
+      {"rv620", AMDGPU::GK_RS880}, {"rv740", AMDGPU::GK_RV770},
+      {"palm", AMDGPU::GK_CEDAR},  {"hemlock", AMDGPU::GK_CYPRESS},
+      {"sumo2", AMDGPU::GK_SUMO},  {"aruba", AMDGPU::GK_CAYMAN},
+  };
+  for (const AliasGPU &A : Aliases) {
+    EXPECT_EQ(AMDGPU::parseArchR600(A.Alias), A.Kind) << A.Alias;
+    EXPECT_NE(AMDGPU::getArchNameR600(A.Kind), A.Alias) << A.Alias;
+  }
+
+  // Unknown and AMDGCN names do not parse as R600 GPUs.
+  EXPECT_EQ(AMDGPU::parseArchR600(""), AMDGPU::GK_NONE);
+  EXPECT_EQ(AMDGPU::parseArchR600("not-a-cpu"), AMDGPU::GK_NONE);
+  EXPECT_EQ(AMDGPU::parseArchR600("gfx900"), AMDGPU::GK_NONE);
+
+  // All canonical and alias names appear in the valid-arch list.
+  SmallVector<StringRef, 0> Values;
+  AMDGPU::fillValidArchListR600(Values);
+  for (const CanonicalGPU &G : Canonicals)
+    EXPECT_TRUE(llvm::is_contained(Values, G.Name)) << G.Name;
+  for (const AliasGPU &A : Aliases)
+    EXPECT_TRUE(llvm::is_contained(Values, A.Alias)) << A.Alias;
+}
+
 TEST(TargetParserTest, testAMDGPUfillValidArchListAMDGCN) {
   SmallVector<StringRef, 0> All;
   AMDGPU::fillValidArchListAMDGCN(All, Triple::NoSubArch);
diff --git a/llvm/utils/TableGen/Basic/AMDGPUTargetDefEmitter.cpp b/llvm/utils/TableGen/Basic/AMDGPUTargetDefEmitter.cpp
new file mode 100644
index 0000000000000..e8a013227411a
--- /dev/null
+++ b/llvm/utils/TableGen/Basic/AMDGPUTargetDefEmitter.cpp
@@ -0,0 +1,134 @@
+//===- AMDGPUTargetDefEmitter.cpp - Generate lists of AMDGPU GPUs ---------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This tablegen backend emits the AMDGPU GPU tables used by
+// AMDGPUTargetParser.cpp.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/TableGen/Error.h"
+#include "llvm/TableGen/Record.h"
+#include "llvm/TableGen/TableGenBackend.h"
+#include <vector>
+
+using namespace llvm;
+
+// Derive the GPUKind enum from a processor name, e.g. "gfx90a" -> "GK_GFX90A".
+static void emitGPUKindEnum(raw_ostream &OS, StringRef Name) {
+  OS << "GK_";
+  for (char C : Name)
+    OS << ((C == '-') ? '_' : toUpper(C));
+}
+
+// A canonical GPU or a ProcessorAlias.
+namespace {
+struct GPUEntry {
+  const Record *Rec;
+  bool IsAlias;
+};
+} // namespace
+
+// Emit the ArchFeature spellings joined with '|', or FEATURE_NONE when empty.
+static void emitFeatureExpr(raw_ostream &OS, const Record *Rec) {
+  ListSeparator LS("|");
+  bool Any = false;
+  for (const Record *F : Rec->getValueAsListOfDefs("ArchFeatures")) {
+    OS << LS << F->getValueAsString("Spelling");
+    Any = true;
+  }
+
+  if (!Any)
+    OS << "FEATURE_NONE";
+}
+
+// Collect canonical GPUs and their aliases, in TableGen definition order.
+static std::vector<GPUEntry> collectGPUs(const RecordKeeper &RK) {
+  ArrayRef<const Record *> GPUs = RK.getAllDerivedDefinitions("AMDGPUGPUInfo");
+  std::vector<GPUEntry> Entries;
+  Entries.reserve(GPUs.size());
+  for (const Record *Rec : GPUs)
+    Entries.push_back({Rec, /*IsAlias=*/false});
+
+  for (const Record *Rec :
+       RK.getAllDerivedDefinitionsIfDefined("ProcessorAlias"))
+    Entries.push_back({Rec, /*IsAlias=*/true});
+
+  sort(Entries, [](const GPUEntry &A, const GPUEntry &B) {
+    return A.Rec->getID() < B.Rec->getID();
+  });
+
+  return Entries;
+}
+
+// Check that every alias resolves to a canonical GPU and no name repeats.
+static void validate(ArrayRef<GPUEntry> Entries) {
+  StringMap<const Record *> Canonicals;
+  for (const GPUEntry &E : Entries)
+    if (!E.IsAlias)
+      Canonicals[E.Rec->getValueAsString("Name")] = E.Rec;
+
+  StringMap<const Record *> Seen;
+  for (const GPUEntry &E : Entries) {
+    StringRef Name = E.Rec->getValueAsString("Name");
+    if (!Seen.insert({Name, E.Rec}).second) {
+      PrintFatalError(E.Rec->getLoc(),
+                      "duplicate AMDGPU processor name '" + Name + "'");
+    }
+
+    if (E.IsAlias) {
+      StringRef Alias = E.Rec->getValueAsString("Alias");
+      if (!Canonicals.count(Alias)) {
+        PrintFatalError(E.Rec->getLoc(),
+                        "ProcessorAlias '" + Name + "' aliases '" + Alias +
+                            "' which is not a canonical AMDGPU GPU");
+      }
+    }
+  }
+}
+
+static void emitR600(raw_ostream &OS, const RecordKeeper &RK) {
+  std::vector<GPUEntry> Entries = collectGPUs(RK);
+  validate(Entries);
+
+  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";
+
+  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";
+    } else {
+      OS << "R600_GPU(\"" << Name << "\", ";
+      emitGPUKindEnum(OS, Name);
+      OS << ", ";
+      emitFeatureExpr(OS, E.Rec);
+      OS << ")\n";
+    }
+  }
+
+  OS << "\n#undef R600_GPU\n"
+        "#undef R600_GPU_ALIAS\n";
+}
+
+static void emitAMDGPUTargetDef(const RecordKeeper &RK, raw_ostream &OS) {
+  OS << "// Autogenerated by AMDGPUTargetDefEmitter.cpp\n\n";
+  emitR600(OS, RK);
+}
+
+static TableGen::Emitter::Opt X("gen-amdgpu-target-def", emitAMDGPUTargetDef,
+                                "Generate the list of AMDGPU GPUs");
diff --git a/llvm/utils/TableGen/Basic/CMakeLists.txt b/llvm/utils/TableGen/Basic/CMakeLists.txt
index f21437026b85c..fb2510e8bcc39 100644
--- a/llvm/utils/TableGen/Basic/CMakeLists.txt
+++ b/llvm/utils/TableGen/Basic/CMakeLists.txt
@@ -9,6 +9,7 @@ set(LLVM_LINK_COMPONENTS
   )
 
 add_llvm_library(LLVMTableGenBasic OBJECT EXCLUDE_FROM_ALL DISABLE_LLVM_LINK_LLVM_DYLIB
+  AMDGPUTargetDefEmitter.cpp
   ARMTargetDefEmitter.cpp
   Attributes.cpp
   CodeGenIntrinsics.cpp



More information about the llvm-commits mailing list