[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