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, _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
