[clang] 8069359 - AMDGPU: Handle more TargetParser queries in tablegen (#212357)

via cfe-commits cfe-commits at lists.llvm.org
Wed Jul 29 21:58:26 PDT 2026


Author: Matt Arsenault
Date: 2026-07-30T06:58:20+02:00
New Revision: 806935948ba3532ba559d614f97cc7688d9cb2ee

URL: https://github.com/llvm/llvm-project/commit/806935948ba3532ba559d614f97cc7688d9cb2ee
DIFF: https://github.com/llvm/llvm-project/commit/806935948ba3532ba559d614f97cc7688d9cb2ee.diff

LOG: AMDGPU: Handle more TargetParser queries in tablegen (#212357)

Previously we had various enum switches. Start generated tables
indexed by enums. Avoid some special cases by defining the dummy
"generic" and "generic-hsa" targets as real processors.

Co-authored-by: Claude (Claude-Opus-4.8)

Added: 
    

Modified: 
    clang/lib/Basic/Targets/AMDGPU.cpp
    clang/lib/Basic/Targets/AMDGPU.h
    clang/test/Driver/amdgpu-mcpu.cl
    clang/test/Misc/target-invalid-cpu-note/amdgcn.c
    llvm/include/llvm/TargetParser/AMDGPUTargetParser.h
    llvm/lib/Target/AMDGPU/AMDGPUTargetParser.td
    llvm/lib/Target/AMDGPU/GCNProcessors.td
    llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUTargetStreamer.cpp
    llvm/lib/TargetParser/AMDGPUTargetParser.cpp
    llvm/test/CodeGen/AMDGPU/hsa-default-device.ll
    llvm/test/TableGen/AMDGPUTargetDefErrors.td
    llvm/unittests/TargetParser/TargetParserTest.cpp
    llvm/utils/TableGen/Basic/AMDGPUTargetDefEmitter.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/Basic/Targets/AMDGPU.cpp b/clang/lib/Basic/Targets/AMDGPU.cpp
index 370ef52a9bdb0..1d74fcc3428b4 100644
--- a/clang/lib/Basic/Targets/AMDGPU.cpp
+++ b/clang/lib/Basic/Targets/AMDGPU.cpp
@@ -291,12 +291,9 @@ void AMDGPUTargetInfo::getTargetDefines(const LangOptions &Opts,
       (getTriple().isAMDGCN() ? getArchNameAMDGCN(GPUKind)
                               : getArchNameR600(GPUKind));
 
-  // Sanitize the name of generic targets.
+  // Sanitize the name of generic targets, the only names containing '-'.
   // e.g. gfx10-1-generic -> gfx10_1_generic
-  if (GPUKind >= llvm::AMDGPU::GK_AMDGPU_GENERIC_FIRST &&
-      GPUKind <= llvm::AMDGPU::GK_AMDGPU_GENERIC_LAST) {
-    llvm::replace(CanonName, '-', '_');
-  }
+  llvm::replace(CanonName, '-', '_');
 
   Builder.defineMacro(Twine("__") + Twine(CanonName) + Twine("__"));
   // Emit macros for gfx family e.g. gfx906 -> __GFX9__, gfx1030 -> __GFX10___

diff  --git a/clang/lib/Basic/Targets/AMDGPU.h b/clang/lib/Basic/Targets/AMDGPU.h
index 85cc1cd21619c..f8933ebee8ffd 100644
--- a/clang/lib/Basic/Targets/AMDGPU.h
+++ b/clang/lib/Basic/Targets/AMDGPU.h
@@ -267,8 +267,11 @@ class LLVM_LIBRARY_VISIBILITY AMDGPUTargetInfo final : public TargetInfo {
   }
 
   bool isValidCPUName(StringRef Name) const override {
-    if (getTriple().isAMDGCN())
-      return llvm::AMDGPU::isCPUValidForSubArch(getTriple().getSubArch(), Name);
+    if (getTriple().isAMDGCN()) {
+      return llvm::AMDGPU::isCPUValidForSubArch(getTriple().getSubArch(),
+                                                Name) &&
+             !llvm::AMDGPU::isPseudoTarget(Name);
+    }
     return llvm::AMDGPU::parseArchR600(Name) != llvm::AMDGPU::GK_NONE;
   }
 
@@ -278,9 +281,9 @@ class LLVM_LIBRARY_VISIBILITY AMDGPUTargetInfo final : public TargetInfo {
     if (getTriple().isAMDGCN()) {
       GPUKind = llvm::AMDGPU::parseArchAMDGCN(Name);
       GPUFeatures = llvm::AMDGPU::getArchAttrAMDGCN(GPUKind);
-      // Reject a CPU whose subarch is incompatible with the triple's subarch.
       return llvm::AMDGPU::isCPUValidForSubArch(getTriple().getSubArch(),
-                                                GPUKind);
+                                                GPUKind) &&
+             !llvm::AMDGPU::isPseudoTarget(GPUKind);
     }
     GPUKind = llvm::AMDGPU::parseArchR600(Name);
     GPUFeatures = llvm::AMDGPU::getArchAttrR600(GPUKind);

diff  --git a/clang/test/Driver/amdgpu-mcpu.cl b/clang/test/Driver/amdgpu-mcpu.cl
index 931e08fcd9f01..32dc3e6fe4205 100644
--- a/clang/test/Driver/amdgpu-mcpu.cl
+++ b/clang/test/Driver/amdgpu-mcpu.cl
@@ -133,6 +133,12 @@
 // RUN: %clang -### -target amdgcn -mcpu=gfx12-5-generic %s 2>&1 | FileCheck --check-prefix=GFX12_5_GENERIC %s
 // RUN: %clang -### -target amdgcn -mcpu=gfx13-generic %s 2>&1 | FileCheck --check-prefix=GFX13_GENERIC %s
 
+// The pseudo targets "generic"/"generic-hsa" may not be used.
+// RUN: not %clang -target amdgcn -mcpu=generic -nogpulib -c %s 2>&1 | FileCheck --check-prefix=PSEUDO-GENERIC %s
+// RUN: not %clang -target amdgcn-amd-amdhsa -mcpu=generic -nogpulib -c %s 2>&1 | FileCheck --check-prefix=PSEUDO-GENERIC %s
+// RUN: not %clang -target amdgcn -mcpu=generic-hsa -nogpulib -c %s 2>&1 | FileCheck --check-prefix=PSEUDO-GENERIC-HSA %s
+// RUN: not %clang -target amdgcn-amd-amdhsa -mcpu=generic-hsa -nogpulib -c %s 2>&1 | FileCheck --check-prefix=PSEUDO-GENERIC-HSA %s
+
 // GCNDEFAULT-NOT: -target-cpu
 // GFX600:    "-target-cpu" "gfx600"
 // GFX601:    "-target-cpu" "gfx601"
@@ -196,3 +202,6 @@
 // GFX12_GENERIC:     "-target-cpu" "gfx12-generic"
 // GFX12_5_GENERIC:   "-target-cpu" "gfx12-5-generic"
 // GFX13_GENERIC:     "-target-cpu" "gfx13-generic"
+
+// PSEUDO-GENERIC:     error: unknown target CPU 'generic'
+// PSEUDO-GENERIC-HSA: error: unknown target CPU 'generic-hsa'

diff  --git a/clang/test/Misc/target-invalid-cpu-note/amdgcn.c b/clang/test/Misc/target-invalid-cpu-note/amdgcn.c
index 1b05f5f8a4c58..c898accc6db5f 100644
--- a/clang/test/Misc/target-invalid-cpu-note/amdgcn.c
+++ b/clang/test/Misc/target-invalid-cpu-note/amdgcn.c
@@ -86,6 +86,20 @@
 // CHECK-SAME: {{^}}, gfx13-generic
 // CHECK-SAME: {{$}}
 
+// The pseudo targets "generic"/"generic-hsa" may not be used.
+// RUN: not %clang_cc1 -triple amdgcn--- -target-cpu generic -fsyntax-only %s 2>&1 | FileCheck --check-prefix=GENERIC %s
+// RUN: not %clang_cc1 -triple amdgcn-amd-amdhsa -target-cpu generic -fsyntax-only %s 2>&1 | FileCheck --check-prefix=GENERIC %s
+// GENERIC: error: unknown target CPU 'generic'
+// GENERIC-NEXT: note: valid target CPU values are:
+// GENERIC-NOT: {{[ ,]}}generic{{[,$]}}
+// GENERIC-NOT: generic-hsa
+
+// RUN: not %clang_cc1 -triple amdgcn--- -target-cpu generic-hsa -fsyntax-only %s 2>&1 | FileCheck --check-prefix=GENERIC-HSA %s
+// RUN: not %clang_cc1 -triple amdgcn-amd-amdhsa -target-cpu generic-hsa -fsyntax-only %s 2>&1 | FileCheck --check-prefix=GENERIC-HSA %s
+// GENERIC-HSA: error: unknown target CPU 'generic-hsa'
+// GENERIC-HSA-NEXT: note: valid target CPU values are:
+// GENERIC-HSA-NOT: generic-hsa
+
 // When the triple carries a major-family subarch, only the GPUs in that family
 // are valid (a CPU from another family is rejected).
 // RUN: not %clang_cc1 -triple amdgpu9--- -target-cpu gfx1030 -fsyntax-only %s 2>&1 | FileCheck --check-prefix=GFX9 %s

diff  --git a/llvm/include/llvm/TargetParser/AMDGPUTargetParser.h b/llvm/include/llvm/TargetParser/AMDGPUTargetParser.h
index c13b85f3bfc2e..c83528b76c7f9 100644
--- a/llvm/include/llvm/TargetParser/AMDGPUTargetParser.h
+++ b/llvm/include/llvm/TargetParser/AMDGPUTargetParser.h
@@ -37,11 +37,9 @@ enum GPUKind : uint32_t {
 
 #define R600_GPU(NAME, ENUM, FEATURES) ENUM,
 #include "llvm/TargetParser/R600TargetParserDef.inc"
-#define AMDGPU_GPU(NAME, ENUM, SUBARCH, ISAVERSION, FEATURES) ENUM,
-#include "llvm/TargetParser/AMDGPUTargetParserDef.inc"
 
-  GK_AMDGPU_GENERIC_FIRST = GK_GFX9_GENERIC,
-  GK_AMDGPU_GENERIC_LAST = GK_GFX13_GENERIC,
+#define AMDGPU_GPU(NAME, ENUM) ENUM,
+#include "llvm/TargetParser/AMDGPUTargetParserDef.inc"
 };
 
 /// Instruction set architecture version.
@@ -120,6 +118,16 @@ LLVM_ABI bool isCPUValidForSubArch(Triple::SubArchType SubArch, GPUKind AK);
 /// is parsed via parseArchAMDGCN. An unrecognized name is never valid.
 LLVM_ABI bool isCPUValidForSubArch(Triple::SubArchType SubArch, StringRef CPU);
 
+/// Return true if \p AK is a pseudo target (e.g. "generic"/"generic-hsa"): a
+/// recognized AMDGCN GPU that represents no concrete hardware and has no
+/// subarch of its own. Such targets are resolved by the backend as a default
+/// device but are not valid as an explicit -mcpu.
+LLVM_ABI bool isPseudoTarget(GPUKind AK);
+
+/// Convenience overload of isPseudoTarget taking a GPU name \p CPU, which is
+/// parsed via parseArchAMDGCN.
+LLVM_ABI bool isPseudoTarget(StringRef CPU);
+
 /// Returns the effective triple appropriate to use when linking \p B into \p A
 /// by merging the subarches in case of inexact match.
 ///

diff  --git a/llvm/lib/Target/AMDGPU/AMDGPUTargetParser.td b/llvm/lib/Target/AMDGPU/AMDGPUTargetParser.td
index d03493d924b13..e53f65cd5f60d 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUTargetParser.td
+++ b/llvm/lib/Target/AMDGPU/AMDGPUTargetParser.td
@@ -43,6 +43,10 @@ class AMDGPUGPUInfo<list<int> isa = []> {
   // should be used for a "gfxN-generic" targets only, and empty for
   // individual GPUs.
   list<Processor> CoveredGPUs = [];
+
+  // A pseudo target ("generic"/"generic-hsa") that represents no
+  // hardware.
+  bit IsPseudoTarget = false;
 }
 
 // An R600 processor that is also a canonical TargetParser GPU.

diff  --git a/llvm/lib/Target/AMDGPU/GCNProcessors.td b/llvm/lib/Target/AMDGPU/GCNProcessors.td
index 7008931c424a0..d6d8a8a4e070e 100644
--- a/llvm/lib/Target/AMDGPU/GCNProcessors.td
+++ b/llvm/lib/Target/AMDGPU/GCNProcessors.td
@@ -19,11 +19,14 @@ defvar ArchFeaturesW32Wgp = [FEATURE_FAST_FMA_F32, FEATURE_FAST_DENORMAL_F32,
 
 // The code produced for "generic" is only useful for tests and cannot
 // be expected to execute on any target.
-def : ProcessorModel<"generic", NoSchedModel, []>;
+def : AMDGPUProcessorModel<"generic", NoSchedModel, [], [6, 0, 0]> {
+  let IsPseudoTarget = true;
+}
 
-def : ProcessorModel<"generic-hsa", NoSchedModel,
-  [FeatureFlatAddressSpace]
->;
+def : AMDGPUProcessorModel<"generic-hsa", NoSchedModel,
+  [FeatureFlatAddressSpace], [7, 0, 0]> {
+  let IsPseudoTarget = true;
+}
 
 //===------------------------------------------------------------===//
 // GCN GFX6 (Southern Islands (SI)).

diff  --git a/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUTargetStreamer.cpp b/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUTargetStreamer.cpp
index ea752e44b7fad..463387f064ef0 100644
--- a/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUTargetStreamer.cpp
+++ b/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUTargetStreamer.cpp
@@ -239,6 +239,8 @@ unsigned AMDGPUTargetStreamer::getElfMach(StringRef GPU) {
   case GK_GFX12_GENERIC:    return ELF::EF_AMDGPU_MACH_AMDGCN_GFX12_GENERIC;
   case GK_GFX12_5_GENERIC:  return ELF::EF_AMDGPU_MACH_AMDGCN_GFX12_5_GENERIC;
   case GK_GFX13_GENERIC:    return ELF::EF_AMDGPU_MACH_AMDGCN_GFX13_GENERIC;
+  case GK_GENERIC:
+  case GK_GENERIC_HSA:
   case GK_NONE:    return ELF::EF_AMDGPU_MACH_NONE;
   }
   // clang-format on

diff  --git a/llvm/lib/TargetParser/AMDGPUTargetParser.cpp b/llvm/lib/TargetParser/AMDGPUTargetParser.cpp
index de6ed11f2d242..fa95e4005bb22 100644
--- a/llvm/lib/TargetParser/AMDGPUTargetParser.cpp
+++ b/llvm/lib/TargetParser/AMDGPUTargetParser.cpp
@@ -18,43 +18,69 @@
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/raw_ostream.h"
 #include "llvm/TargetParser/Triple.h"
+#include <array>
 
 using namespace llvm;
 using namespace AMDGPU;
 
-StringRef llvm::AMDGPU::getArchFamilyNameAMDGCN(GPUKind AK) {
-  StringRef ArchName = getArchNameAMDGCN(AK);
-  assert((AK >= GK_AMDGPU_GENERIC_FIRST && AK <= GK_AMDGPU_GENERIC_LAST) ==
-             ArchName.ends_with("-generic") &&
-         "Generic AMDGCN arch not classified correctly!");
-  if (AK >= GK_AMDGPU_GENERIC_FIRST && AK <= GK_AMDGPU_GENERIC_LAST) {
-    // Return the part before the first '-', e.g. "gfx9-4-generic" -> "gfx9".
-    return ArchName.take_front(ArchName.find('-'));
+namespace {
+// Per-GPU data for the AMDGCN GPUKinds, from the generated table below.
+struct GPUInfo {
+  StringRef Name;
+  Triple::SubArchType SubArch;
+  unsigned ArchFeatures;
+  IsaVersion Version;
+  StringRef FamilyName;
+};
+
+#define GET_AMDGPU_GPU_TABLE
+#include "llvm/TargetParser/AMDGPUTargetParserDef.inc"
+
+// Look up the GPUInfo row for an AMDGCN GPUKind, or nullptr for GK_NONE / a
+// non-AMDGCN (R600) kind.
+const GPUInfo *getAMDGPUInfo(GPUKind AK) {
+  if (AK < AMDGPUFirstGPUKind)
+    return nullptr;
+  unsigned Idx = AK - AMDGPUFirstGPUKind;
+  if (Idx >= std::size(AMDGPUGPUTable))
+    return nullptr;
+  return &AMDGPUGPUTable[Idx];
+}
+
+// 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{};
+
+  for (unsigned I = 0; I < std::size(AMDGPUGPUTable); ++I) {
+    Triple::SubArchType SubArch = AMDGPUGPUTable[I].SubArch;
+    if (SubArch != Triple::NoSubArch) {
+      Map[SubArch - Triple::FirstAMDGPUSubArch] =
+          static_cast<GPUKind>(AMDGPUFirstGPUKind + I);
+    }
   }
-  return ArchName.empty() ? "" : ArchName.drop_back(2);
+  return Map;
+}();
+} // namespace
+
+StringRef llvm::AMDGPU::getArchFamilyNameAMDGCN(GPUKind AK) {
+  const GPUInfo *Info = getAMDGPUInfo(AK);
+  return Info ? Info->FamilyName : "";
 }
 
 Triple::SubArchType llvm::AMDGPU::getSubArch(GPUKind AK) {
-  switch (AK) {
-#define AMDGPU_GPU(NAME, ENUM, SUBARCH, ISAVERSION, FEATURES)                  \
-  case ENUM:                                                                   \
-    return SUBARCH;
-#include "llvm/TargetParser/AMDGPUTargetParserDef.inc"
-  default:
-    return Triple::SubArchType::NoSubArch;
-  }
+  const GPUInfo *Info = getAMDGPUInfo(AK);
+  return Info ? Info->SubArch : Triple::SubArchType::NoSubArch;
 }
 
 AMDGPU::GPUKind
 llvm::AMDGPU::getGPUKindFromSubArch(Triple::SubArchType SubArch) {
-  switch (SubArch) {
-#define AMDGPU_GPU(NAME, ENUM, SUBARCH, ISAVERSION, FEATURES)                  \
-  case SUBARCH:                                                                \
-    return ENUM;
-#include "llvm/TargetParser/AMDGPUTargetParserDef.inc"
-  default:
+  if (SubArch < Triple::FirstAMDGPUSubArch ||
+      SubArch > Triple::LastAMDGPUSubArch)
     return GK_NONE;
-  }
+  return AMDGPUSubArchToGPUKind[SubArch - Triple::FirstAMDGPUSubArch];
 }
 
 static const Triple::SubArchType
@@ -139,13 +165,28 @@ bool AMDGPU::isCPUValidForSubArch(Triple::SubArchType SubArch, GPUKind AK) {
   // A legacy triple without a subarch accepts any known GPU.
   if (SubArch == Triple::NoSubArch)
     return true;
-  return isSubArchCompatible(getSubArch(AK), SubArch);
+
+  // Reject the dummy "generic" targets
+  Triple::SubArchType GPUSubArch = getSubArch(AK);
+  if (GPUSubArch == Triple::NoSubArch)
+    return false;
+
+  return isSubArchCompatible(GPUSubArch, SubArch);
 }
 
 bool AMDGPU::isCPUValidForSubArch(Triple::SubArchType SubArch, StringRef CPU) {
   return isCPUValidForSubArch(SubArch, parseArchAMDGCN(CPU));
 }
 
+bool AMDGPU::isPseudoTarget(GPUKind AK) {
+  const GPUInfo *Info = getAMDGPUInfo(AK);
+  return Info && Info->SubArch == Triple::NoSubArch;
+}
+
+bool AMDGPU::isPseudoTarget(StringRef CPU) {
+  return isPseudoTarget(parseArchAMDGCN(CPU));
+}
+
 bool AMDGPU::isSubArchCompatible(const Triple &A, const Triple &B) {
   // Tolerate subarch mismatch if one entry is none. This is a hack for bitcode
   // libraries.
@@ -185,14 +226,8 @@ std::string AMDGPU::mergeSubArch(const Triple &A, const Triple &B) {
 }
 
 StringRef llvm::AMDGPU::getArchNameAMDGCN(GPUKind AK) {
-  switch (AK) {
-#define AMDGPU_GPU(NAME, ENUM, SUBARCH, ISAVERSION, FEATURES)                  \
-  case ENUM:                                                                   \
-    return NAME;
-#include "llvm/TargetParser/AMDGPUTargetParserDef.inc"
-  default:
-    return "";
-  }
+  const GPUInfo *Info = getAMDGPUInfo(AK);
+  return Info ? Info->Name : "";
 }
 
 // Canonical GPU name for each AMDGPU subarch, indexed by SubArch -
@@ -253,11 +288,9 @@ StringRef llvm::AMDGPU::getArchNameR600(GPUKind AK) {
 
 AMDGPU::GPUKind llvm::AMDGPU::parseArchAMDGCN(StringRef CPU) {
   return StringSwitch<AMDGPU::GPUKind>(CPU)
-#define AMDGPU_GPU(NAME, ENUM, SUBARCH, ISAVERSION, FEATURES) .Case(NAME, ENUM)
+#define AMDGPU_GPU(NAME, ENUM) .Case(NAME, ENUM)
 #define AMDGPU_GPU_ALIAS(NAME, ENUM) .Case(NAME, ENUM)
 #include "llvm/TargetParser/AMDGPUTargetParserDef.inc"
-      .Case("generic", AMDGPU::GPUKind::GK_GFX600)
-      .Case("generic-hsa", AMDGPU::GPUKind::GK_GFX700)
       .Default(AMDGPU::GPUKind::GK_NONE);
 }
 
@@ -270,25 +303,12 @@ AMDGPU::GPUKind llvm::AMDGPU::parseArchR600(StringRef CPU) {
 }
 
 unsigned AMDGPU::getArchAttrAMDGCN(GPUKind AK) {
-  switch (AK) {
-#define AMDGPU_GPU(NAME, ENUM, SUBARCH, ISAVERSION, FEATURES)                  \
-  case ENUM:                                                                   \
-    return FEATURES;
-#include "llvm/TargetParser/AMDGPUTargetParserDef.inc"
-  default:
-    return FEATURE_NONE;
-  }
+  const GPUInfo *Info = getAMDGPUInfo(AK);
+  return Info ? Info->ArchFeatures : FEATURE_NONE;
 }
 
 unsigned AMDGPU::getArchAttrAMDGCN(Triple::SubArchType SubArch) {
-  switch (SubArch) {
-#define AMDGPU_GPU(NAME, ENUM, SUBARCH, ISAVERSION, FEATURES)                  \
-  case SUBARCH:                                                                \
-    return FEATURES;
-#include "llvm/TargetParser/AMDGPUTargetParserDef.inc"
-  default:
-    return FEATURE_NONE;
-  }
+  return getArchAttrAMDGCN(getGPUKindFromSubArch(SubArch));
 }
 
 R600FeatureKind AMDGPU::getArchAttrR600(GPUKind AK) {
@@ -306,8 +326,9 @@ 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, SUBARCH, ISAVERSION, FEATURES)                  \
-  if (isCPUValidForSubArch(SubArch, ENUM))                                     \
+#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))                                     \
@@ -324,38 +345,13 @@ void AMDGPU::fillValidArchListR600(SmallVectorImpl<StringRef> &Values) {
 }
 
 AMDGPU::IsaVersion AMDGPU::getIsaVersion(StringRef GPU) {
-  AMDGPU::GPUKind AK = parseArchAMDGCN(GPU);
-  if (AK == AMDGPU::GPUKind::GK_NONE) {
-    if (GPU == "generic-hsa")
-      return {7, 0, 0};
-    if (GPU == "generic")
-      return {6, 0, 0};
-    return {0, 0, 0};
-  }
-
-  switch (AK) {
-#define MAKE_ISAVERSION(A, B, C) {A, B, C}
-#define AMDGPU_GPU(NAME, ENUM, SUBARCH, ISAVERSION, FEATURES)                  \
-  case ENUM:                                                                   \
-    return MAKE_ISAVERSION ISAVERSION;
-#include "llvm/TargetParser/AMDGPUTargetParserDef.inc"
-#undef MAKE_ISAVERSION
-  default:
-    return {0, 0, 0};
-  }
+  const GPUInfo *Info = getAMDGPUInfo(parseArchAMDGCN(GPU));
+  return Info ? Info->Version : IsaVersion{0, 0, 0};
 }
 
 AMDGPU::IsaVersion AMDGPU::getIsaVersion(Triple::SubArchType SubArch) {
-  switch (SubArch) {
-#define MAKE_ISAVERSION(A, B, C) {A, B, C}
-#define AMDGPU_GPU(NAME, ENUM, SUBARCH, ISAVERSION, FEATURES)                  \
-  case SUBARCH:                                                                \
-    return MAKE_ISAVERSION ISAVERSION;
-#include "llvm/TargetParser/AMDGPUTargetParserDef.inc"
-#undef MAKE_ISAVERSION
-  default:
-    return {0, 0, 0};
-  }
+  const GPUInfo *Info = getAMDGPUInfo(getGPUKindFromSubArch(SubArch));
+  return Info ? Info->Version : IsaVersion{0, 0, 0};
 }
 
 unsigned AMDGPU::getTotalNumSGPRs(GPUKind AK) {

diff  --git a/llvm/test/CodeGen/AMDGPU/hsa-default-device.ll b/llvm/test/CodeGen/AMDGPU/hsa-default-device.ll
index e10010d256a30..0a6959519722d 100644
--- a/llvm/test/CodeGen/AMDGPU/hsa-default-device.ll
+++ b/llvm/test/CodeGen/AMDGPU/hsa-default-device.ll
@@ -3,7 +3,7 @@
 ; Make sure that with an HSA triple, we don't default to an
 ; unsupported device.
 
-; CHECK: .amdgcn_target "amdgcn-unknown-amdhsa-unknown-gfx700"
+; CHECK: .amdgcn_target "amdgcn-unknown-amdhsa-unknown-generic-hsa"
 define amdgpu_kernel void @test_kernel(ptr addrspace(1) %out0, ptr addrspace(1) %out1) nounwind {
   store float 0.0, ptr addrspace(1) %out0
   ret void

diff  --git a/llvm/test/TableGen/AMDGPUTargetDefErrors.td b/llvm/test/TableGen/AMDGPUTargetDefErrors.td
index 7697f37b955a6..cd9111a50743e 100644
--- a/llvm/test/TableGen/AMDGPUTargetDefErrors.td
+++ b/llvm/test/TableGen/AMDGPUTargetDefErrors.td
@@ -18,6 +18,7 @@ class AMDGPUGPUInfo<list<int> isa = []> {
   list<AMDGPUArchFeature> ArchFeatures = [];
   list<int> IsaVersion = isa;
   list<Processor> CoveredGPUs = [];
+  bit IsPseudoTarget = false;
 }
 
 def : ProcessorModel<"gfx900", NoSchedModel, []>, AMDGPUGPUInfo<[9, 0, 0]>;
@@ -33,6 +34,7 @@ class AMDGPUGPUInfo<list<int> isa = []> {
   list<AMDGPUArchFeature> ArchFeatures = [];
   list<int> IsaVersion = isa;
   list<Processor> CoveredGPUs = [];
+  bit IsPseudoTarget = false;
 }
 
 def DupA : ProcessorModel<"gfx900", NoSchedModel, []>, AMDGPUGPUInfo<[9, 0, 0]>;
@@ -48,6 +50,7 @@ class AMDGPUGPUInfo<list<int> isa = []> {
   list<AMDGPUArchFeature> ArchFeatures = [];
   list<int> IsaVersion = isa;
   list<Processor> CoveredGPUs = [];
+  bit IsPseudoTarget = false;
 }
 
 def : ProcessorModel<"gfx900", NoSchedModel, []>, AMDGPUGPUInfo<[9, 0, 0]>;
@@ -63,6 +66,7 @@ class AMDGPUGPUInfo<list<int> isa = []> {
   list<AMDGPUArchFeature> ArchFeatures = [];
   list<int> IsaVersion = isa;
   list<Processor> CoveredGPUs = [];
+  bit IsPseudoTarget = false;
 }
 // A malformed IsaVersion is reported (not asserted), so this stays a clean
 // diagnostic in release builds.

diff  --git a/llvm/unittests/TargetParser/TargetParserTest.cpp b/llvm/unittests/TargetParser/TargetParserTest.cpp
index 827c5aafac857..e28392fc25195 100644
--- a/llvm/unittests/TargetParser/TargetParserTest.cpp
+++ b/llvm/unittests/TargetParser/TargetParserTest.cpp
@@ -2659,6 +2659,27 @@ TEST(TargetParserTest, testAMDGPUisCPUValidForSubArch) {
   EXPECT_FALSE(
       AMDGPU::isCPUValidForSubArch(Triple::NoSubArch, AMDGPU::GK_NONE));
   EXPECT_FALSE(AMDGPU::isCPUValidForSubArch(Triple::NoSubArch, ""));
+
+  // The pseudo targets "generic"/"generic-hsa" represent no hardware and have
+  // no subarch of their own. They are not valid for an explicit subarch (their
+  // NoSubArch must not act as a wildcard). A legacy NoSubArch triple still
+  // accepts them, matching the wildcard behavior for any known GPU (the backend
+  // resolves "generic-hsa" as the default device for a bare amdhsa triple).
+  EXPECT_FALSE(AMDGPU::isCPUValidForSubArch(Triple::AMDGPUSubArch900,
+                                            AMDGPU::GK_GENERIC));
+  EXPECT_FALSE(
+      AMDGPU::isCPUValidForSubArch(Triple::AMDGPUSubArch900, "generic"));
+  EXPECT_TRUE(
+      AMDGPU::isCPUValidForSubArch(Triple::NoSubArch, AMDGPU::GK_GENERIC));
+  EXPECT_TRUE(AMDGPU::isCPUValidForSubArch(Triple::NoSubArch, "generic"));
+
+  EXPECT_FALSE(AMDGPU::isCPUValidForSubArch(Triple::AMDGPUSubArch900,
+                                            AMDGPU::GK_GENERIC_HSA));
+  EXPECT_FALSE(
+      AMDGPU::isCPUValidForSubArch(Triple::AMDGPUSubArch900, "generic-hsa"));
+  EXPECT_TRUE(
+      AMDGPU::isCPUValidForSubArch(Triple::NoSubArch, AMDGPU::GK_GENERIC_HSA));
+  EXPECT_TRUE(AMDGPU::isCPUValidForSubArch(Triple::NoSubArch, "generic-hsa"));
 }
 
 TEST(TargetParserTest, testAMDGPUparseArchR600) {

diff  --git a/llvm/utils/TableGen/Basic/AMDGPUTargetDefEmitter.cpp b/llvm/utils/TableGen/Basic/AMDGPUTargetDefEmitter.cpp
index 66d9d3b66350c..a4468de6d0968 100644
--- a/llvm/utils/TableGen/Basic/AMDGPUTargetDefEmitter.cpp
+++ b/llvm/utils/TableGen/Basic/AMDGPUTargetDefEmitter.cpp
@@ -29,11 +29,14 @@ static void emitGPUKindEnum(raw_ostream &OS, StringRef Name) {
     OS << ((C == '-') ? '_' : toUpper(C));
 }
 
-// Derive the Triple::SubArchType from an AMDGPU processor name, e.g. "gfx90a"
-// -> Triple::AMDGPUSubArch90A. A generic target uses its family's major
-// subarch, e.g. "gfx9-generic" -> Triple::AMDGPUSubArch9.
-static void emitSubArch(raw_ostream &OS, StringRef Name) {
-  StringRef Suffix = Name;
+/// 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");
   Suffix.consume_front("gfx");
   Suffix.consume_back("-generic");
 
@@ -42,8 +45,24 @@ static void emitSubArch(raw_ostream &OS, StringRef Name) {
     OS << ((C == '-') ? '_' : toUpper(C));
 }
 
-// Emit the ISA version tuple "(major, minor, stepping)".
-static void emitIsaVersion(raw_ostream &OS, const Record *Rec) {
+/// 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"))
+    return Name.take_front(Name.find('-'));
+  return Name.drop_back(2);
+}
+
+// Emit the ISA version tuple as "major, minor, stepping" wrapped in \p Open and
+// \p Close (parens for the AMDGPU_GPU macro's ISAVERSION argument, braces for a
+// struct initializer).
+static void emitIsaVersion(raw_ostream &OS, const Record *Rec, char Open,
+                           char Close) {
   std::vector<int64_t> V = Rec->getValueAsListOfInts("IsaVersion");
   if (V.size() != 3) {
     PrintFatalError(Rec->getLoc(),
@@ -52,7 +71,14 @@ static void emitIsaVersion(raw_ostream &OS, const Record *Rec) {
                         "IsaVersion");
   }
 
-  OS << '(' << V[0] << ", " << V[1] << ", " << V[2] << ')';
+  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.
@@ -61,14 +87,12 @@ struct GPUEntry {
   const Record *Rec;
   bool IsAlias;
 
-  // An entry is generic if it is (or aliases) a "gfxN-generic" family target,
-  // i.e. a canonical that covers a set of concrete GPUs (non-empty
-  // CoveredGPUs).
-  // \p Canonicals maps canonical GPU names to their records.
+  // Whether this entry is (or aliases) a generic family target. \p Canonicals
+  // maps canonical GPU names to their records.
   bool isGeneric(const StringMap<const Record *> &Canonicals) const {
     const Record *Canon =
         IsAlias ? Canonicals.lookup(Rec->getValueAsString("Alias")) : Rec;
-    return Canon && !Canon->getValueAsListOfDefs("CoveredGPUs").empty();
+    return Canon && isGenericTarget(Canon);
   }
 };
 } // namespace
@@ -163,19 +187,42 @@ static void emitR600(raw_ostream &OS, const RecordKeeper &RK) {
       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, "R600_FEATURE_NONE");
-      OS << ")\n";
+      continue;
     }
+    OS << "R600_GPU(\"" << Name << "\", ";
+    emitGPUKindEnum(OS, Name);
+    OS << ", ";
+    emitFeatureExpr(OS, E.Rec, "R600_FEATURE_NONE");
+    OS << ")\n";
   }
 
   OS << "\n#undef R600_GPU\n"
         "#undef R600_GPU_ALIAS\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());
+
+  for (const GPUEntry &E : Entries) {
+    if (!E.isGeneric(Canonicals))
+      Ordered.push_back(E);
+  }
+
+  for (const GPUEntry &E : Entries) {
+    if (E.isGeneric(Canonicals))
+      Ordered.push_back(E);
+  }
+
+  return Ordered;
+}
+
 static void emitAMDGPUEntry(raw_ostream &OS, const GPUEntry &E) {
   StringRef Name = E.Rec->getValueAsString("Name");
   if (E.IsAlias) {
@@ -185,12 +232,6 @@ static void emitAMDGPUEntry(raw_ostream &OS, const GPUEntry &E) {
   } else {
     OS << "AMDGPU_GPU(\"" << Name << "\", ";
     emitGPUKindEnum(OS, Name);
-    OS << ", ";
-    emitSubArch(OS, Name);
-    OS << ", ";
-    emitIsaVersion(OS, E.Rec);
-    OS << ", ";
-    emitFeatureExpr(OS, E.Rec, "FEATURE_NONE");
     OS << ")\n";
   }
 }
@@ -208,28 +249,56 @@ static void emitAMDGPU(raw_ostream &OS, const RecordKeeper &RK) {
   }
 
   OS << "#ifndef AMDGPU_GPU\n"
-        "#define AMDGPU_GPU(NAME, ENUM, SUBARCH, ISAVERSION, FEATURES)\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";
 
-  // The GPUKind enum is positional and code relies on the generic targets
-  // being a contiguous block at the end (GK_AMDGPU_GENERIC_FIRST/LAST), so emit
-  // all non-generic entries first, then the generics, each group preserving
-  // TableGen definition order.
+  for (const GPUEntry &E : orderGenericsLast(Entries, Canonicals))
+    emitAMDGPUEntry(OS, E);
+
+  OS << "\n#undef AMDGPU_GPU\n"
+        "#undef AMDGPU_GPU_ALIAS\n";
+}
+
+/// Emit a GPUInfo table indexed by (GPUKind - AMDGPUFirstGPUKind).
+static void emitAMDGPUTable(raw_ostream &OS, const RecordKeeper &RK) {
+  std::vector<GPUEntry> Entries = collectGPUs(RK, /*WantR600=*/false);
+  if (Entries.empty())
+    return;
+
+  StringMap<const Record *> Canonicals;
   for (const GPUEntry &E : Entries) {
-    if (!E.isGeneric(Canonicals))
-      emitAMDGPUEntry(OS, E);
+    if (!E.IsAlias)
+      Canonicals[E.Rec->getValueAsString("Name")] = E.Rec;
   }
 
-  for (const GPUEntry &E : Entries) {
-    if (E.isGeneric(Canonicals))
-      emitAMDGPUEntry(OS, E);
+  // 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 << "\n#undef AMDGPU_GPU\n"
-        "#undef AMDGPU_GPU_ALIAS\n";
+  OS << "#ifdef GET_AMDGPU_GPU_TABLE\n"
+        "#undef GET_AMDGPU_GPU_TABLE\n";
+  OS << "static constexpr GPUKind AMDGPUFirstGPUKind = ";
+  emitGPUKindEnum(OS, Canon.front()->getValueAsString("Name"));
+  OS << ";\n"
+        "static constexpr GPUInfo AMDGPUGPUTable[] = {\n";
+  for (const Record *R : Canon) {
+    StringRef Name = R->getValueAsString("Name");
+    OS << "  {\"" << Name << "\", ";
+    emitSubArch(OS, R);
+    OS << ", ";
+    emitFeatureExpr(OS, R, "FEATURE_NONE");
+    OS << ", ";
+    emitIsaVersion(OS, R, '{', '}');
+    OS << ", \"" << getArchFamily(R) << "\"},\n";
+  }
+  OS << "};\n"
+        "#endif // GET_AMDGPU_GPU_TABLE\n\n";
 }
 
 static void emitAMDGPUTargetDef(const RecordKeeper &RK, raw_ostream &OS) {
@@ -240,6 +309,7 @@ static void emitAMDGPUTargetDef(const RecordKeeper &RK, raw_ostream &OS) {
   // run; the other section emits nothing.
   emitR600(OS, RK);
   emitAMDGPU(OS, RK);
+  emitAMDGPUTable(OS, RK);
 }
 
 static TableGen::Emitter::Opt X("gen-amdgpu-target-def", emitAMDGPUTargetDef,


        


More information about the cfe-commits mailing list