[clang] 3c3a18e - clang: Store vendor GPU kinds in OffloadArch instead of re-listing GPUs (#213362)

via cfe-commits cfe-commits at lists.llvm.org
Fri Jul 31 23:14:10 PDT 2026


Author: Matt Arsenault
Date: 2026-08-01T06:14:04Z
New Revision: 3c3a18e239fcb79ad780cc95ac7554046876da2a

URL: https://github.com/llvm/llvm-project/commit/3c3a18e239fcb79ad780cc95ac7554046876da2a
DIFF: https://github.com/llvm/llvm-project/commit/3c3a18e239fcb79ad780cc95ac7554046876da2a.diff

LOG: clang: Store vendor GPU kinds in OffloadArch instead of re-listing GPUs (#213362)

OffloadArch was a flat enum that hand-duplicated every AMDGPU and NVPTX
target, plus a few edge cases. This was yet another place that needed
updating every time a new target is added, which should now be avoided.
Replace with a tagged union-like scheme.

Co-authored-by: Claude (Claude-Opus-4.8) <noreply at anthropic.com>

Added: 
    

Modified: 
    clang/include/clang/Basic/OffloadArch.h
    clang/include/clang/Driver/CudaInstallationDetector.h
    clang/lib/Basic/Cuda.cpp
    clang/lib/Basic/OffloadArch.cpp
    clang/lib/Basic/Targets/NVPTX.cpp
    clang/lib/Basic/Targets/NVPTX.h
    clang/lib/Driver/Driver.cpp
    clang/lib/Driver/OffloadBundler.cpp
    clang/lib/Driver/ToolChains/Cuda.cpp
    clang/lib/Sema/SemaDeclAttr.cpp
    clang/test/Misc/target-invalid-cpu-note/nvptx.c
    clang/unittests/Basic/OffloadArchTest.cpp
    llvm/include/llvm/TargetParser/AMDGPUTargetParser.h
    llvm/include/llvm/TargetParser/NVPTXTargetParser.h

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Basic/OffloadArch.h b/clang/include/clang/Basic/OffloadArch.h
index 552f1b0316ccf..069352ea37f89 100644
--- a/clang/include/clang/Basic/OffloadArch.h
+++ b/clang/include/clang/Basic/OffloadArch.h
@@ -10,161 +10,121 @@
 #define LLVM_CLANG_BASIC_OFFLOADARCH_H
 
 #include "llvm/ADT/StringRef.h"
+#include <cstdint>
 #include <tuple>
 
 namespace llvm {
 class Triple;
+template <typename T> class SmallVectorImpl;
+namespace NVPTX {
+enum GPUKind : uint8_t;
+}
+namespace AMDGPU {
+enum GPUKind : uint8_t;
+}
 } // namespace llvm
 
 namespace clang {
 
-enum class OffloadArch {
-  Unused,
-  Unknown,
-  // TODO: Deprecate and remove GPU architectures older than sm_52.
-  SM_20,
-  SM_21,
-  SM_30,
-  // This has a name conflict with sys/mac.h on AIX, rename it as a workaround.
-  SM_32_,
-  SM_35,
-  SM_37,
-  SM_50,
-  SM_52,
-  SM_53,
-  SM_60,
-  SM_61,
-  SM_62,
-  SM_70,
-  SM_72,
-  SM_75,
-  SM_80,
-  SM_86,
-  SM_87,
-  SM_88,
-  SM_89,
-  SM_90,
-  SM_90a,
-  SM_100,
-  SM_100a,
-  SM_100f,
-  SM_101,
-  SM_101a,
-  SM_101f,
-  SM_103,
-  SM_103a,
-  SM_103f,
-  SM_110,
-  SM_110a,
-  SM_110f,
-  SM_120,
-  SM_120a,
-  SM_120f,
-  SM_121,
-  SM_121a,
-  SM_121f,
-  GFX600,
-  GFX601,
-  GFX602,
-  GFX700,
-  GFX701,
-  GFX702,
-  GFX703,
-  GFX704,
-  GFX705,
-  GFX801,
-  GFX802,
-  GFX803,
-  GFX805,
-  GFX810,
-  GFX9_GENERIC,
-  GFX900,
-  GFX902,
-  GFX904,
-  GFX906,
-  GFX908,
-  GFX909,
-  GFX90a,
-  GFX90c,
-  GFX9_4_GENERIC,
-  GFX942,
-  GFX950,
-  GFX10_1_GENERIC,
-  GFX1010,
-  GFX1011,
-  GFX1012,
-  GFX1013,
-  GFX10_3_GENERIC,
-  GFX1030,
-  GFX1031,
-  GFX1032,
-  GFX1033,
-  GFX1034,
-  GFX1035,
-  GFX1036,
-  GFX11_GENERIC,
-  GFX1100,
-  GFX1101,
-  GFX1102,
-  GFX1103,
-  GFX1150,
-  GFX1151,
-  GFX1152,
-  GFX1153,
-  GFX1154,
-  GFX11_7_GENERIC,
-  GFX1170,
-  GFX1171,
-  GFX1172,
-  GFX12_GENERIC,
-  GFX1200,
-  GFX1201,
-  GFX12_5_GENERIC,
-  GFX1250,
-  GFX1251,
-  GFX13_GENERIC,
-  GFX1310,
-  AMDGCNSPIRV,
-  Generic, // A processor model named 'generic' if the target backend defines a
-           // public one.
-  // Intel CPUs
-  GRANITERAPIDS,
-  // Intel GPUs
-  BMG_G21,
-  LAST = BMG_G21,
-
-  CudaDefault = OffloadArch::SM_52,
-  HIPDefault = OffloadArch::GFX906,
-};
-
-static inline bool IsNVIDIAOffloadArch(OffloadArch A) {
-  return A >= OffloadArch::SM_20 && A < OffloadArch::GFX600;
-}
-
-static inline bool IsAMDOffloadArch(OffloadArch A) {
-  // Generic processor model is for testing only.
-  return A >= OffloadArch::GFX600 && A < OffloadArch::Generic;
-}
+/// A processor an offloading action can target. This is a tagged handle pairing
+/// a TargetArch with the matching TargetParser GPU kind; it does not enumerate
+/// individual GPUs, so new targets are added in the TargetParser data alone.
+class OffloadArch {
+public:
+  enum class TargetArch : uint8_t {
+    Unused,   // Default-constructed; no architecture bound.
+    Unknown,  // A name that matched no known architecture.
+    NVPTX,    // Kind is an llvm::NVPTX::GPUKind.
+    AMDGPU,   // Kind is an llvm::AMDGPU::GPUKind.
+    SPIRV,    // The 'amdgcnspirv' pseudo target.
+    IntelCPU, // Kind is an IntelArch.
+    IntelGPU, // Kind is an IntelArch.
+    Generic,  // The 'generic' processor model.
+  };
+
+  // Intel architectures, which have no TargetParser list yet.
+  enum class IntelArch : uint32_t {
+    GRANITERAPIDS,
+    BMG_G21,
+  };
+
+private:
+  // Interpreted according to V; unused for the tagless TargetArch values.
+  uint32_t Kind = 0;
+  TargetArch V = TargetArch::Unused;
+
+  constexpr OffloadArch(TargetArch V, uint32_t Kind) : Kind(Kind), V(V) {}
+
+public:
+  constexpr OffloadArch() = default;
+
+  static OffloadArch getNVPTX(llvm::NVPTX::GPUKind K) {
+    return {TargetArch::NVPTX, static_cast<uint32_t>(K)};
+  }
+  static OffloadArch getAMDGPU(llvm::AMDGPU::GPUKind K) {
+    return {TargetArch::AMDGPU, static_cast<uint32_t>(K)};
+  }
+  static constexpr OffloadArch getIntel(TargetArch V, IntelArch A) {
+    return {V, static_cast<uint32_t>(A)};
+  }
+  static constexpr OffloadArch getUnused() { return {TargetArch::Unused, 0}; }
+  static constexpr OffloadArch getUnknown() { return {TargetArch::Unknown, 0}; }
+  static constexpr OffloadArch getSPIRV() { return {TargetArch::SPIRV, 0}; }
+  static constexpr OffloadArch getGeneric() { return {TargetArch::Generic, 0}; }
+
+  /// Default architectures used when the user does not specify one.
+  static OffloadArch CudaDefault();
+  static OffloadArch HIPDefault();
+
+  TargetArch targetArch() const { return V; }
+
+  bool isNVPTX() const { return V == TargetArch::NVPTX; }
+  bool isAMDGPU() const { return V == TargetArch::AMDGPU; }
+  bool isSPIRV() const { return V == TargetArch::SPIRV; }
+  bool isIntelCPU() const { return V == TargetArch::IntelCPU; }
+  bool isIntelGPU() const { return V == TargetArch::IntelGPU; }
+  bool isIntel() const { return isIntelCPU() || isIntelGPU(); }
+  bool isGeneric() const { return V == TargetArch::Generic; }
+  bool isUnused() const { return V == TargetArch::Unused; }
+  bool isUnknown() const { return V == TargetArch::Unknown; }
+
+  // Only valid when isNVPTX() / isAMDGPU() respectively.
+  llvm::NVPTX::GPUKind nvptxKind() const {
+    return static_cast<llvm::NVPTX::GPUKind>(Kind);
+  }
+  llvm::AMDGPU::GPUKind amdgpuKind() const {
+    return static_cast<llvm::AMDGPU::GPUKind>(Kind);
+  }
 
-static inline bool IsIntelCPUOffloadArch(OffloadArch Arch) {
-  return Arch >= OffloadArch::GRANITERAPIDS && Arch < OffloadArch::BMG_G21;
-}
+  bool operator==(const OffloadArch &Other) const {
+    return V == Other.V && Kind == Other.Kind;
+  }
+  bool operator!=(const OffloadArch &Other) const { return !(*this == Other); }
 
-static inline bool IsIntelGPUOffloadArch(OffloadArch Arch) {
-  return Arch >= OffloadArch::BMG_G21 && Arch <= OffloadArch::LAST;
-}
+  bool operator<(const OffloadArch &Other) const {
+    return std::tie(V, Kind) < std::tie(Other.V, Other.Kind);
+  }
+};
 
-static inline bool IsIntelOffloadArch(OffloadArch Arch) {
-  return IsIntelCPUOffloadArch(Arch) || IsIntelGPUOffloadArch(Arch);
+inline bool IsNVIDIAOffloadArch(OffloadArch A) { return A.isNVPTX(); }
+inline bool IsAMDOffloadArch(OffloadArch A) {
+  // amdgcnspirv is compiled through the AMDGPU toolchain.
+  return A.isAMDGPU() || A.isSPIRV();
 }
+inline bool IsIntelCPUOffloadArch(OffloadArch A) { return A.isIntelCPU(); }
+inline bool IsIntelGPUOffloadArch(OffloadArch A) { return A.isIntelGPU(); }
+inline bool IsIntelOffloadArch(OffloadArch A) { return A.isIntel(); }
 
 const char *OffloadArchToString(OffloadArch A);
 const char *OffloadArchToVirtualArchString(OffloadArch A);
 
-// Convert a string to an OffloadArch enum value. Returns
-// OffloadArch::Unknown if the string is not recognized.
+// Convert a string to an OffloadArch. Returns an Unknown OffloadArch if the
+// string is not recognized.
 OffloadArch StringToOffloadArch(llvm::StringRef S);
 
+/// Append the canonical names of all NVIDIA and AMDGPU GPUs.
+void fillValidOffloadArchList(llvm::SmallVectorImpl<llvm::StringRef> &Values);
+
 llvm::Triple OffloadArchToTriple(const llvm::Triple &DefaultToolchainTriple,
                                  OffloadArch ID);
 
@@ -173,19 +133,19 @@ llvm::Triple OffloadArchToTriple(const llvm::Triple &DefaultToolchainTriple,
 struct BoundArch {
   llvm::StringRef ArchName;
 
-  /// The parsed offload architecture enum.
-  /// Will be OffloadArch::Unknown if ArchName not recognized.
-  OffloadArch Arch = OffloadArch::Unused;
+  /// The parsed offload architecture.
+  /// Will be an Unknown OffloadArch if ArchName is not recognized.
+  OffloadArch Arch = OffloadArch::getUnused();
 
   BoundArch() = default;
   explicit BoundArch(llvm::StringRef Name)
-      : ArchName(Name),
-        Arch(Name.empty() ? OffloadArch::Unknown : StringToOffloadArch(Name)) {}
+      : ArchName(Name), Arch(Name.empty() ? OffloadArch::getUnknown()
+                                          : StringToOffloadArch(Name)) {}
 
   BoundArch(llvm::StringRef Name, OffloadArch A) : ArchName(Name), Arch(A) {}
 
   bool empty() const { return ArchName.empty(); }
-  explicit operator bool() const { return Arch != OffloadArch::Unused; }
+  explicit operator bool() const { return !Arch.isUnused(); }
 
   bool operator==(const BoundArch &Other) const {
     return Arch == Other.Arch && ArchName == Other.ArchName;

diff  --git a/clang/include/clang/Driver/CudaInstallationDetector.h b/clang/include/clang/Driver/CudaInstallationDetector.h
index 0fecbfe069ca4..98abec7d924bb 100644
--- a/clang/include/clang/Driver/CudaInstallationDetector.h
+++ b/clang/include/clang/Driver/CudaInstallationDetector.h
@@ -11,6 +11,7 @@
 
 #include "clang/Basic/Cuda.h"
 #include "clang/Driver/Driver.h"
+#include "llvm/TargetParser/NVPTXTargetParser.h"
 #include <bitset>
 
 namespace clang {
@@ -28,9 +29,9 @@ class CudaInstallationDetector {
   std::string IncludePath;
   llvm::StringMap<std::string> LibDeviceMap;
 
-  // CUDA architectures for which we have raised an error in
-  // CheckCudaVersionSupportsArch.
-  mutable std::bitset<(int)OffloadArch::LAST> ArchsWithBadVersion;
+  // NVIDIA architectures (indexed by GPUKind) for which we have raised an error
+  // in CheckCudaVersionSupportsArch.
+  mutable std::bitset<llvm::NVPTX::GK_LAST + 1> ArchsWithBadVersion;
 
 public:
   CudaInstallationDetector(const Driver &D, const llvm::Triple &HostTriple,

diff  --git a/clang/lib/Basic/Cuda.cpp b/clang/lib/Basic/Cuda.cpp
index b61d890e23dfe..06c02bd541df3 100644
--- a/clang/lib/Basic/Cuda.cpp
+++ b/clang/lib/Basic/Cuda.cpp
@@ -4,6 +4,7 @@
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/VersionTuple.h"
 #include "llvm/TargetParser/NVPTXTargetParser.h"
+#include <cassert>
 
 namespace clang {
 
@@ -78,16 +79,16 @@ CudaVersion ToCudaVersion(llvm::VersionTuple Version) {
 }
 
 CudaVersion MinVersionForOffloadArch(OffloadArch A) {
-  if (A == OffloadArch::Unknown)
+  if (A.isUnknown())
     return CudaVersion::UNKNOWN;
 
   // AMD GPUs do not depend on CUDA versions.
   if (IsAMDOffloadArch(A))
     return CudaVersion::CUDA_70;
 
-  switch (A) {
+  switch (A.nvptxKind()) {
 #define NVPTX_GPU(NAME, KIND, VIRTUAL, SM_ID, MIN_VER, MAX_VER, SUFFIX)        \
-  case OffloadArch::KIND:                                                      \
+  case llvm::NVPTX::GK_##KIND:                                                 \
     return CudaVersion::MIN_VER;
 #include "llvm/TargetParser/NVPTXTargetParser.def"
   default:
@@ -100,11 +101,12 @@ CudaVersion MaxVersionForOffloadArch(OffloadArch A) {
   if (IsAMDOffloadArch(A))
     return CudaVersion::NEW;
 
-  switch (A) {
-  case OffloadArch::Unknown:
+  if (!A.isNVPTX())
     return CudaVersion::UNKNOWN;
+
+  switch (A.nvptxKind()) {
 #define NVPTX_GPU(NAME, KIND, VIRTUAL, SM_ID, MIN_VER, MAX_VER, SUFFIX)        \
-  case OffloadArch::KIND:                                                      \
+  case llvm::NVPTX::GK_##KIND:                                                 \
     return CudaVersion::MAX_VER;
 #include "llvm/TargetParser/NVPTXTargetParser.def"
   default:
@@ -127,33 +129,15 @@ bool CudaFeatureEnabled(CudaVersion Version, CudaFeature Feature) {
 }
 
 unsigned CudaArchToID(OffloadArch Arch) {
-  switch (Arch) {
-#define NVPTX_GPU(NAME, KIND, VIRTUAL, SM_ID, MIN_VER, MAX_VER, SUFFIX)        \
-  case OffloadArch::KIND:                                                      \
-    return SM_ID;
-#include "llvm/TargetParser/NVPTXTargetParser.def"
-  default:
-    break;
-  }
-  llvm_unreachable("invalid NVIDIA GPU architecture");
-}
-
-static llvm::NVPTX::GPUKind OffloadArchToNVPTXKind(OffloadArch Arch) {
-  switch (Arch) {
-#define NVPTX_GPU(NAME, KIND, VIRTUAL, SM_ID, MIN_VER, MAX_VER, SUFFIX)        \
-  case OffloadArch::KIND:                                                      \
-    return llvm::NVPTX::GK_##KIND;
-#include "llvm/TargetParser/NVPTXTargetParser.def"
-  default:
-    return llvm::NVPTX::GK_NONE;
-  }
+  assert(Arch.isNVPTX() && "invalid NVIDIA GPU architecture");
+  return llvm::NVPTX::getSmVersion(Arch.nvptxKind());
 }
 
 bool IsNVIDIAAcceleratedOffloadArch(OffloadArch Arch) {
-  return llvm::NVPTX::isAcceleratedArch(OffloadArchToNVPTXKind(Arch));
+  return Arch.isNVPTX() && llvm::NVPTX::isAcceleratedArch(Arch.nvptxKind());
 }
 
 bool IsNVIDIAFamilySpecificOffloadArch(OffloadArch Arch) {
-  return llvm::NVPTX::isFamilySpecificArch(OffloadArchToNVPTXKind(Arch));
+  return Arch.isNVPTX() && llvm::NVPTX::isFamilySpecificArch(Arch.nvptxKind());
 }
 } // namespace clang

diff  --git a/clang/lib/Basic/OffloadArch.cpp b/clang/lib/Basic/OffloadArch.cpp
index 5d12f257f3680..55a0564cff89d 100644
--- a/clang/lib/Basic/OffloadArch.cpp
+++ b/clang/lib/Basic/OffloadArch.cpp
@@ -7,164 +7,101 @@
 //===----------------------------------------------------------------------===//
 #include "clang/Basic/OffloadArch.h"
 
-#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringRef.h"
+#include "llvm/TargetParser/AMDGPUTargetParser.h"
+#include "llvm/TargetParser/NVPTXTargetParser.h"
 #include "llvm/TargetParser/Triple.h"
 
 namespace clang {
 
-namespace {
-struct OffloadArchToStringMap {
-  OffloadArch Arch;
-  const char *ArchName;
-  const char *VirtualArchName;
-};
-} // namespace
+OffloadArch OffloadArch::CudaDefault() {
+  return getNVPTX(llvm::NVPTX::parseArch("sm_52"));
+}
 
-#define SM(sm) {OffloadArch::SM_##sm, "sm_" #sm, "compute_" #sm}
-#define GFX(gpu) {OffloadArch::GFX##gpu, "gfx" #gpu, "compute_amdgcn"}
-static const OffloadArchToStringMap ArchNames[] = {
-    // clang-format off
-    {OffloadArch::Unused, "", ""},
-    SM(20), {OffloadArch::SM_21, "sm_21", "compute_20"}, // Fermi
-    SM(30), {OffloadArch::SM_32_, "sm_32", "compute_32"}, SM(35), SM(37),  // Kepler
-    SM(50), SM(52), SM(53),          // Maxwell
-    SM(60), SM(61), SM(62),          // Pascal
-    SM(70), SM(72),                  // Volta
-    SM(75),                          // Turing
-    SM(80), SM(86),                  // Ampere
-    SM(87),                          // Jetson/Drive AGX Orin
-    SM(88),                          // Ampere
-    SM(89),                          // Ada Lovelace
-    SM(90),                          // Hopper
-    SM(90a),                         // Hopper
-    SM(100),                         // Blackwell
-    SM(100a),                        // Blackwell
-    SM(100f),                        // Blackwell
-    SM(101),                         // Blackwell
-    SM(101a),                        // Blackwell
-    SM(101f),                        // Blackwell
-    SM(103),                         // Blackwell
-    SM(103a),                        // Blackwell
-    SM(103f),                        // Blackwell
-    SM(110),                         // Blackwell
-    SM(110a),                        // Blackwell
-    SM(110f),                        // Blackwell
-    SM(120),                         // Blackwell
-    SM(120a),                        // Blackwell
-    SM(120f),                        // Blackwell
-    SM(121),                         // Blackwell
-    SM(121a),                        // Blackwell
-    SM(121f),                        // Blackwell
-    GFX(600),  // gfx600
-    GFX(601),  // gfx601
-    GFX(602),  // gfx602
-    GFX(700),  // gfx700
-    GFX(701),  // gfx701
-    GFX(702),  // gfx702
-    GFX(703),  // gfx703
-    GFX(704),  // gfx704
-    GFX(705),  // gfx705
-    GFX(801),  // gfx801
-    GFX(802),  // gfx802
-    GFX(803),  // gfx803
-    GFX(805),  // gfx805
-    GFX(810),  // gfx810
-    {OffloadArch::GFX9_GENERIC, "gfx9-generic", "compute_amdgcn"},
-    GFX(900),  // gfx900
-    GFX(902),  // gfx902
-    GFX(904),  // gfx903
-    GFX(906),  // gfx906
-    GFX(908),  // gfx908
-    GFX(909),  // gfx909
-    GFX(90a),  // gfx90a
-    GFX(90c),  // gfx90c
-    {OffloadArch::GFX9_4_GENERIC, "gfx9-4-generic", "compute_amdgcn"},
-    GFX(942),  // gfx942
-    GFX(950),  // gfx950
-    {OffloadArch::GFX10_1_GENERIC, "gfx10-1-generic", "compute_amdgcn"},
-    GFX(1010), // gfx1010
-    GFX(1011), // gfx1011
-    GFX(1012), // gfx1012
-    GFX(1013), // gfx1013
-    {OffloadArch::GFX10_3_GENERIC, "gfx10-3-generic", "compute_amdgcn"},
-    GFX(1030), // gfx1030
-    GFX(1031), // gfx1031
-    GFX(1032), // gfx1032
-    GFX(1033), // gfx1033
-    GFX(1034), // gfx1034
-    GFX(1035), // gfx1035
-    GFX(1036), // gfx1036
-    {OffloadArch::GFX11_GENERIC, "gfx11-generic", "compute_amdgcn"},
-    GFX(1100), // gfx1100
-    GFX(1101), // gfx1101
-    GFX(1102), // gfx1102
-    GFX(1103), // gfx1103
-    GFX(1150), // gfx1150
-    GFX(1151), // gfx1151
-    GFX(1152), // gfx1152
-    GFX(1153), // gfx1153
-    GFX(1154), // gfx1154
-    {OffloadArch::GFX11_7_GENERIC, "gfx11-7-generic", "compute_amdgcn"},
-    GFX(1170), // gfx1170
-    GFX(1171), // gfx1171
-    GFX(1172), // gfx1172
-    {OffloadArch::GFX12_GENERIC, "gfx12-generic", "compute_amdgcn"},
-    GFX(1200), // gfx1200
-    GFX(1201), // gfx1201
-    {OffloadArch::GFX12_5_GENERIC, "gfx12-5-generic", "compute_amdgcn"},
-    GFX(1250), // gfx1250
-    GFX(1251), // gfx1251
-    {OffloadArch::GFX13_GENERIC, "gfx13-generic", "compute_amdgcn"},
-    GFX(1310), // gfx1310
-    {OffloadArch::AMDGCNSPIRV, "amdgcnspirv", "compute_amdgcn"},
-    // Intel CPUs
-    {OffloadArch::GRANITERAPIDS, "graniterapids", ""},
-    // Intel GPUS
-    {OffloadArch::BMG_G21, "bmg_g21", ""},
-    {OffloadArch::Generic, "generic", ""},
-    // clang-format on
-};
-#undef SM
-#undef GFX
+OffloadArch OffloadArch::HIPDefault() {
+  return getAMDGPU(llvm::AMDGPU::parseArchAMDGCN("gfx906"));
+}
 
 const char *OffloadArchToString(OffloadArch A) {
-  auto Result =
-      llvm::find_if(ArchNames, [A](const OffloadArchToStringMap &Map) {
-        return A == Map.Arch;
-      });
-  if (Result == std::end(ArchNames))
+  switch (A.targetArch()) {
+  case OffloadArch::TargetArch::Unused:
+    return "";
+  case OffloadArch::TargetArch::Unknown:
     return "unknown";
-  return Result->ArchName;
+  case OffloadArch::TargetArch::NVPTX:
+    return llvm::NVPTX::getArchName(A.nvptxKind()).data();
+  case OffloadArch::TargetArch::AMDGPU:
+    return llvm::AMDGPU::getArchNameAMDGCN(A.amdgpuKind()).data();
+  case OffloadArch::TargetArch::SPIRV:
+    return "amdgcnspirv";
+  case OffloadArch::TargetArch::IntelCPU:
+    return "graniterapids";
+  case OffloadArch::TargetArch::IntelGPU:
+    return "bmg_g21";
+  case OffloadArch::TargetArch::Generic:
+    return "generic";
+  }
+  return "unknown";
 }
 
 const char *OffloadArchToVirtualArchString(OffloadArch A) {
-  auto Result =
-      llvm::find_if(ArchNames, [A](const OffloadArchToStringMap &Map) {
-        return A == Map.Arch;
-      });
-  if (Result == std::end(ArchNames))
+  switch (A.targetArch()) {
+  case OffloadArch::TargetArch::NVPTX:
+    return llvm::NVPTX::getVirtualArch(A.nvptxKind()).data();
+  case OffloadArch::TargetArch::AMDGPU:
+  case OffloadArch::TargetArch::SPIRV:
+    return "compute_amdgcn";
+  case OffloadArch::TargetArch::Unknown:
     return "unknown";
-  return Result->VirtualArchName;
+  case OffloadArch::TargetArch::Unused:
+  case OffloadArch::TargetArch::IntelCPU:
+  case OffloadArch::TargetArch::IntelGPU:
+  case OffloadArch::TargetArch::Generic:
+    return "";
+  }
+  return "unknown";
 }
 
 OffloadArch StringToOffloadArch(llvm::StringRef S) {
-  auto Result =
-      llvm::find_if(ArchNames, [S](const OffloadArchToStringMap &Map) {
-        return S == Map.ArchName;
-      });
-  if (Result == std::end(ArchNames))
-    return OffloadArch::Unknown;
-  return Result->Arch;
+  // The empty string denotes the "unused" architecture.
+  if (S.empty())
+    return OffloadArch::getUnused();
+
+  // Non-GPU-table pseudo/sentinel architectures.
+  if (S == "amdgcnspirv")
+    return OffloadArch::getSPIRV();
+  if (S == "generic")
+    return OffloadArch::getGeneric();
+  if (S == "graniterapids")
+    return OffloadArch::getIntel(OffloadArch::TargetArch::IntelCPU,
+                                 OffloadArch::IntelArch::GRANITERAPIDS);
+  if (S == "bmg_g21")
+    return OffloadArch::getIntel(OffloadArch::TargetArch::IntelGPU,
+                                 OffloadArch::IntelArch::BMG_G21);
+
+  // Otherwise defer to the vendor TargetParser GPU lists.
+  if (llvm::NVPTX::GPUKind NV = llvm::NVPTX::parseArch(S))
+    return OffloadArch::getNVPTX(NV);
+  if (llvm::AMDGPU::GPUKind AK = llvm::AMDGPU::parseArchAMDGCN(S))
+    return OffloadArch::getAMDGPU(AK);
+  return OffloadArch::getUnknown();
+}
+
+void fillValidOffloadArchList(llvm::SmallVectorImpl<llvm::StringRef> &Values) {
+#define NVPTX_GPU(NAME, KIND, VIRTUAL, SM_ID, MIN_VER, MAX_VER, SUFFIX)        \
+  Values.push_back(NAME);
+#include "llvm/TargetParser/NVPTXTargetParser.def"
+  llvm::AMDGPU::fillValidArchListAMDGCN(Values, llvm::Triple::NoSubArch);
 }
 
 llvm::Triple OffloadArchToTriple(const llvm::Triple &DefaultToolchainTriple,
                                  OffloadArch ID) {
-  if (ID == OffloadArch::AMDGCNSPIRV)
+  if (ID.isSPIRV())
     return llvm::Triple(llvm::Triple::spirv64, llvm::Triple::NoSubArch,
                         llvm::Triple::AMD, llvm::Triple::AMDHSA);
 
-  if (IsNVIDIAOffloadArch(ID)) {
+  if (ID.isNVPTX()) {
     llvm::Triple::ArchType Arch = DefaultToolchainTriple.isArch64Bit()
                                       ? llvm::Triple::nvptx64
                                       : llvm::Triple::nvptx;
@@ -172,7 +109,7 @@ llvm::Triple OffloadArchToTriple(const llvm::Triple &DefaultToolchainTriple,
                         llvm::Triple::CUDA);
   }
 
-  if (IsAMDOffloadArch(ID))
+  if (ID.isAMDGPU())
     return llvm::Triple("amdgcn-amd-amdhsa");
 
   return {};

diff  --git a/clang/lib/Basic/Targets/NVPTX.cpp b/clang/lib/Basic/Targets/NVPTX.cpp
index 2e1d9abac8320..d2fed6a2f9787 100644
--- a/clang/lib/Basic/Targets/NVPTX.cpp
+++ b/clang/lib/Basic/Targets/NVPTX.cpp
@@ -64,7 +64,7 @@ NVPTXTargetInfo::NVPTXTargetInfo(const llvm::Triple &Triple,
   // Define available target features
   // These must be defined in sorted order!
   NoAsmVariants = true;
-  GPU = OffloadArch::Unused;
+  GPU = OffloadArch::getUnused();
 
   // PTX supports f16 as a fundamental type.
   HasFastHalfType = true;

diff  --git a/clang/lib/Basic/Targets/NVPTX.h b/clang/lib/Basic/Targets/NVPTX.h
index 72941fd65fda8..996b1a9730606 100644
--- a/clang/lib/Basic/Targets/NVPTX.h
+++ b/clang/lib/Basic/Targets/NVPTX.h
@@ -72,7 +72,7 @@ class LLVM_LIBRARY_VISIBILITY NVPTXTargetInfo : public TargetInfo {
   initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags,
                  StringRef CPU,
                  const std::vector<std::string> &FeaturesVec) const override {
-    if (GPU != OffloadArch::Unused)
+    if (!GPU.isUnused())
       Features[OffloadArchToString(GPU)] = true;
     // Only add PTX feature if explicitly requested. Otherwise, let the backend
     // use the minimum required PTX version for the target SM.
@@ -131,18 +131,16 @@ class LLVM_LIBRARY_VISIBILITY NVPTXTargetInfo : public TargetInfo {
   }
 
   bool isValidCPUName(StringRef Name) const override {
-    return StringToOffloadArch(Name) != OffloadArch::Unknown;
+    return !StringToOffloadArch(Name).isUnknown();
   }
 
   void fillValidCPUList(SmallVectorImpl<StringRef> &Values) const override {
-    for (int i = static_cast<int>(OffloadArch::SM_20);
-         i < static_cast<int>(OffloadArch::Generic); ++i)
-      Values.emplace_back(OffloadArchToString(static_cast<OffloadArch>(i)));
+    fillValidOffloadArchList(Values);
   }
 
   bool setCPU(StringRef Name) override {
     GPU = StringToOffloadArch(Name);
-    return GPU != OffloadArch::Unknown;
+    return !GPU.isUnknown();
   }
 
   void setSupportedOpenCLOpts() override {

diff  --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp
index 38795f7c2ae7a..5bd46db170d96 100644
--- a/clang/lib/Driver/Driver.cpp
+++ b/clang/lib/Driver/Driver.cpp
@@ -961,7 +961,7 @@ static TripleSet inferOffloadToolchains(Compilation &C,
   TripleSet Triples;
   for (llvm::StringRef Arch : Archs) {
     OffloadArch ID = StringToOffloadArch(Arch);
-    if (ID == OffloadArch::Unknown)
+    if (ID.isUnknown())
       ID = StringToOffloadArch(
           getProcessorFromTargetID(llvm::Triple("amdgcn-amd-amdhsa"), Arch));
 
@@ -975,13 +975,12 @@ static TripleSet inferOffloadToolchains(Compilation &C,
           << "CUDA" << Arch;
       return {};
     }
-    if (Kind == Action::OFK_OpenMP &&
-        (ID == OffloadArch::Unknown || ID == OffloadArch::Unused)) {
+    if (Kind == Action::OFK_OpenMP && (ID.isUnknown() || ID.isUnused())) {
       C.getDriver().Diag(clang::diag::err_drv_failed_to_deduce_target_from_arch)
           << Arch;
       return {};
     }
-    if (ID == OffloadArch::Unknown || ID == OffloadArch::Unused) {
+    if (ID.isUnknown() || ID.isUnused()) {
       C.getDriver().Diag(clang::diag::err_drv_offload_bad_gpu_arch)
           << "offload" << Arch;
       return {};
@@ -3466,7 +3465,7 @@ class OffloadingActionBuilder final {
     bool Relocatable = false;
 
     /// Default GPU architecture if there's no one specified.
-    OffloadArch DefaultOffloadArch = OffloadArch::Unknown;
+    OffloadArch DefaultOffloadArch = OffloadArch::getUnknown();
 
     /// Compilation unit ID specified by option '-fuse-cuid=' or'-cuid='.
     const CUIDOptions &CUIDOpts;
@@ -3644,7 +3643,7 @@ class OffloadingActionBuilder final {
     CudaActionBuilder(Compilation &C, DerivedArgList &Args,
                       const InputList &Inputs)
         : CudaActionBuilderBase(C, Args, Inputs, Action::OFK_Cuda) {
-      DefaultOffloadArch = OffloadArch::CudaDefault;
+      DefaultOffloadArch = OffloadArch::CudaDefault();
     }
 
     ActionBuilderReturnCode
@@ -3769,7 +3768,7 @@ class OffloadingActionBuilder final {
                      const InputList &Inputs)
         : CudaActionBuilderBase(C, Args, Inputs, Action::OFK_HIP) {
 
-      DefaultOffloadArch = OffloadArch::HIPDefault;
+      DefaultOffloadArch = OffloadArch::HIPDefault();
 
       if (Args.hasArg(options::OPT_fhip_emit_relocatable,
                       options::OPT_fno_hip_emit_relocatable)) {
@@ -4882,13 +4881,12 @@ static StringRef getCanonicalArchString(Compilation &C,
   // expecting the triple to be only NVPTX / AMDGPU.
   OffloadArch Arch =
       StringToOffloadArch(getProcessorFromTargetID(Triple, ArchStr));
-  if (Triple.isNVPTX() &&
-      (Arch == OffloadArch::Unknown || !IsNVIDIAOffloadArch(Arch))) {
+  if (Triple.isNVPTX() && (Arch.isUnknown() || !IsNVIDIAOffloadArch(Arch))) {
     C.getDriver().Diag(clang::diag::err_drv_offload_bad_gpu_arch)
         << "CUDA" << ArchStr;
     return StringRef();
   } else if (Triple.isAMDGPU() &&
-             (Arch == OffloadArch::Unknown || !IsAMDOffloadArch(Arch))) {
+             (Arch.isUnknown() || !IsAMDOffloadArch(Arch))) {
     C.getDriver().Diag(clang::diag::err_drv_offload_bad_gpu_arch)
         << "HIP" << ArchStr;
     return StringRef();
@@ -4992,12 +4990,12 @@ Driver::getOffloadArchs(Compilation &C, const llvm::opt::DerivedArgList &Args,
   if (Archs.empty()) {
     if (Kind == Action::OFK_Cuda) {
       Archs.insert(OffloadArchToString(TC.getTriple().isSPIRV()
-                                           ? OffloadArch::Unused
-                                           : OffloadArch::CudaDefault));
+                                           ? OffloadArch::getUnused()
+                                           : OffloadArch::CudaDefault()));
     } else if (Kind == Action::OFK_HIP) {
       Archs.insert(OffloadArchToString(TC.getTriple().isSPIRV()
-                                           ? OffloadArch::Generic
-                                           : OffloadArch::HIPDefault));
+                                           ? OffloadArch::getGeneric()
+                                           : OffloadArch::HIPDefault()));
     } else if (Kind == Action::OFK_SYCL) {
       Archs.insert(StringRef());
     } else if (Kind == Action::OFK_OpenMP) {

diff  --git a/clang/lib/Driver/OffloadBundler.cpp b/clang/lib/Driver/OffloadBundler.cpp
index 8e4d44071ef55..b397ee4c5b075 100644
--- a/clang/lib/Driver/OffloadBundler.cpp
+++ b/clang/lib/Driver/OffloadBundler.cpp
@@ -83,8 +83,7 @@ OffloadTargetInfo::OffloadTargetInfo(const StringRef Target,
   StringRef TargetIdWithFeature =
       Components.size() == 6 ? Components.back() : "";
   StringRef TargetId = TargetIdWithFeature.split(':').first;
-  if (!TargetId.empty() &&
-      clang::StringToOffloadArch(TargetId) != clang::OffloadArch::Unknown)
+  if (!TargetId.empty() && !clang::StringToOffloadArch(TargetId).isUnknown())
     this->TargetID = TargetIdWithFeature;
   else
     this->TargetID = "";

diff  --git a/clang/lib/Driver/ToolChains/Cuda.cpp b/clang/lib/Driver/ToolChains/Cuda.cpp
index b7e257b2c0207..93e335ca8bb82 100644
--- a/clang/lib/Driver/ToolChains/Cuda.cpp
+++ b/clang/lib/Driver/ToolChains/Cuda.cpp
@@ -235,14 +235,12 @@ CudaInstallationDetector::CudaInstallationDetector(
       // CUDA-9+ uses single libdevice file for all GPU variants.
       std::string FilePath = LibDevicePath + "/libdevice.10.bc";
       if (FS.exists(FilePath)) {
-        for (int Arch = (int)OffloadArch::SM_30, E = (int)OffloadArch::LAST;
-             Arch < E; ++Arch) {
-          OffloadArch OA = static_cast<OffloadArch>(Arch);
-          if (!IsNVIDIAOffloadArch(OA))
-            continue;
-          std::string OffloadArchName(OffloadArchToString(OA));
-          LibDeviceMap[OffloadArchName] = FilePath;
-        }
+        // CUDA-9+ uses a single libdevice file for every NVIDIA GPU variant
+        // (sm_30 and newer).
+#define NVPTX_GPU(NAME, KIND, VIRTUAL, SM_ID, MIN_VER, MAX_VER, SUFFIX)        \
+  if ((SM_ID) >= 300)                                                          \
+    LibDeviceMap[NAME] = FilePath;
+#include "llvm/TargetParser/NVPTXTargetParser.def"
       }
     } else {
       std::error_code EC;
@@ -326,14 +324,15 @@ void CudaInstallationDetector::AddCudaIncludeArgs(
 
 void CudaInstallationDetector::CheckCudaVersionSupportsArch(
     OffloadArch Arch) const {
-  if (Arch == OffloadArch::Unknown || Version == CudaVersion::UNKNOWN ||
-      ArchsWithBadVersion[(int)Arch])
+  // Only NVIDIA architectures depend on the CUDA toolkit version.
+  if (!Arch.isNVPTX() || Version == CudaVersion::UNKNOWN ||
+      ArchsWithBadVersion[Arch.nvptxKind()])
     return;
 
   auto MinVersion = MinVersionForOffloadArch(Arch);
   auto MaxVersion = MaxVersionForOffloadArch(Arch);
   if (Version < MinVersion || Version > MaxVersion) {
-    ArchsWithBadVersion[(int)Arch] = true;
+    ArchsWithBadVersion[Arch.nvptxKind()] = true;
     D.Diag(diag::err_drv_cuda_version_unsupported)
         << OffloadArchToString(Arch) << CudaVersionToString(MinVersion)
         << CudaVersionToString(MaxVersion) << InstallPath
@@ -414,7 +413,7 @@ void NVPTX::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
   }
 
   // Obtain architecture from the action.
-  assert(GPUArch.Arch != OffloadArch::Unknown &&
+  assert(!GPUArch.Arch.isUnknown() &&
          "Device action expected to have an architecture.");
 
   // Check that our installation's ptxas supports gpu_arch.
@@ -778,7 +777,7 @@ NVPTXToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args,
 
   if (!DAL->hasArg(options::OPT_march_EQ) && OffloadKind != Action::OFK_None) {
     DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_march_EQ),
-                      OffloadArchToString(OffloadArch::CudaDefault));
+                      OffloadArchToString(OffloadArch::CudaDefault()));
   } else if (DAL->getLastArgValue(options::OPT_march_EQ) == "generic" &&
              OffloadKind == Action::OFK_None) {
     DAL->eraseArg(options::OPT_march_EQ);

diff  --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 492b125587344..690821a8e9ef9 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -72,6 +72,7 @@
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/MathExtras.h"
 #include "llvm/Support/raw_ostream.h"
+#include "llvm/TargetParser/NVPTXTargetParser.h"
 #include "llvm/TargetParser/Triple.h"
 #include <optional>
 
@@ -6129,8 +6130,8 @@ Sema::CreateLaunchBoundsAttr(const AttributeCommonInfo &CI, Expr *MaxThreads,
     // launch bounds attribute within ompx_attribute to support other archs.
     if (!IgnoreArch) {
       // '.maxclusterrank' ptx directive requires .target sm_90 or higher.
-      auto SM = getOffloadArch(Context.getTargetInfo());
-      if (SM == OffloadArch::Unknown || SM < OffloadArch::SM_90) {
+      OffloadArch SM = getOffloadArch(Context.getTargetInfo());
+      if (SM.isUnknown() || llvm::NVPTX::getSmVersion(SM.nvptxKind()) < 900) {
         Diag(MaxBlocks->getBeginLoc(), diag::warn_cuda_maxclusterrank_sm_90)
             << OffloadArchToString(SM) << CI << MaxBlocks->getSourceRange();
         // Ignore it by setting MaxBlocks to null;
@@ -6244,7 +6245,8 @@ void Sema::addNoClusterAttr(Decl *D, const AttributeCommonInfo &CI) {
 static void handleClusterDimsAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
   const TargetInfo &TTI = S.Context.getTargetInfo();
   OffloadArch Arch = StringToOffloadArch(TTI.getTargetOpts().CPU);
-  if ((TTI.getTriple().isNVPTX() && Arch < clang::OffloadArch::SM_90) ||
+  if ((TTI.getTriple().isNVPTX() &&
+       llvm::NVPTX::getSmVersion(Arch.nvptxKind()) < 900) ||
       (TTI.getTriple().isAMDGPU() &&
        !TTI.hasFeatureEnabled(TTI.getTargetOpts().FeatureMap, "clusters"))) {
     S.Diag(AL.getLoc(), diag::err_cluster_attr_not_supported) << AL;
@@ -6263,7 +6265,8 @@ static void handleClusterDimsAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
 static void handleNoClusterAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
   const TargetInfo &TTI = S.Context.getTargetInfo();
   OffloadArch Arch = StringToOffloadArch(TTI.getTargetOpts().CPU);
-  if ((TTI.getTriple().isNVPTX() && Arch < clang::OffloadArch::SM_90) ||
+  if ((TTI.getTriple().isNVPTX() &&
+       llvm::NVPTX::getSmVersion(Arch.nvptxKind()) < 900) ||
       (TTI.getTriple().isAMDGPU() &&
        !TTI.hasFeatureEnabled(TTI.getTargetOpts().FeatureMap, "clusters"))) {
     S.Diag(AL.getLoc(), diag::err_cluster_attr_not_supported) << AL;

diff  --git a/clang/test/Misc/target-invalid-cpu-note/nvptx.c b/clang/test/Misc/target-invalid-cpu-note/nvptx.c
index decbdfd44d6eb..922a2eb1d8c3a 100644
--- a/clang/test/Misc/target-invalid-cpu-note/nvptx.c
+++ b/clang/test/Misc/target-invalid-cpu-note/nvptx.c
@@ -59,7 +59,6 @@
 // CHECK-SAME: {{^}}, gfx803
 // CHECK-SAME: {{^}}, gfx805
 // CHECK-SAME: {{^}}, gfx810
-// CHECK-SAME: {{^}}, gfx9-generic
 // CHECK-SAME: {{^}}, gfx900
 // CHECK-SAME: {{^}}, gfx902
 // CHECK-SAME: {{^}}, gfx904
@@ -68,15 +67,12 @@
 // CHECK-SAME: {{^}}, gfx909
 // CHECK-SAME: {{^}}, gfx90a
 // CHECK-SAME: {{^}}, gfx90c
-// CHECK-SAME: {{^}}, gfx9-4-generic
 // CHECK-SAME: {{^}}, gfx942
 // CHECK-SAME: {{^}}, gfx950
-// CHECK-SAME: {{^}}, gfx10-1-generic
 // CHECK-SAME: {{^}}, gfx1010
 // CHECK-SAME: {{^}}, gfx1011
 // CHECK-SAME: {{^}}, gfx1012
 // CHECK-SAME: {{^}}, gfx1013
-// CHECK-SAME: {{^}}, gfx10-3-generic
 // CHECK-SAME: {{^}}, gfx1030
 // CHECK-SAME: {{^}}, gfx1031
 // CHECK-SAME: {{^}}, gfx1032
@@ -84,7 +80,6 @@
 // CHECK-SAME: {{^}}, gfx1034
 // CHECK-SAME: {{^}}, gfx1035
 // CHECK-SAME: {{^}}, gfx1036
-// CHECK-SAME: {{^}}, gfx11-generic
 // CHECK-SAME: {{^}}, gfx1100
 // CHECK-SAME: {{^}}, gfx1101
 // CHECK-SAME: {{^}}, gfx1102
@@ -94,17 +89,39 @@
 // CHECK-SAME: {{^}}, gfx1152
 // CHECK-SAME: {{^}}, gfx1153
 // CHECK-SAME: {{^}}, gfx1154
-// CHECK-SAME: {{^}}, gfx11-7-generic
 // CHECK-SAME: {{^}}, gfx1170
 // CHECK-SAME: {{^}}, gfx1171
 // CHECK-SAME: {{^}}, gfx1172
-// CHECK-SAME: {{^}}, gfx12-generic
 // CHECK-SAME: {{^}}, gfx1200
 // CHECK-SAME: {{^}}, gfx1201
-// CHECK-SAME: {{^}}, gfx12-5-generic
 // CHECK-SAME: {{^}}, gfx1250
 // CHECK-SAME: {{^}}, gfx1251
-// CHECK-SAME: {{^}}, gfx13-generic
 // CHECK-SAME: {{^}}, gfx1310
-// CHECK-SAME: {{^}}, amdgcnspirv
+// CHECK-SAME: {{^}}, gfx9-generic
+// CHECK-SAME: {{^}}, gfx9-4-generic
+// CHECK-SAME: {{^}}, gfx10-1-generic
+// CHECK-SAME: {{^}}, gfx10-3-generic
+// CHECK-SAME: {{^}}, gfx11-generic
+// CHECK-SAME: {{^}}, gfx11-7-generic
+// CHECK-SAME: {{^}}, gfx12-generic
+// CHECK-SAME: {{^}}, gfx12-5-generic
+// CHECK-SAME: {{^}}, gfx13-generic
+// CHECK-SAME: {{^}}, tahiti
+// CHECK-SAME: {{^}}, pitcairn
+// CHECK-SAME: {{^}}, verde
+// CHECK-SAME: {{^}}, hainan
+// CHECK-SAME: {{^}}, oland
+// CHECK-SAME: {{^}}, kaveri
+// CHECK-SAME: {{^}}, hawaii
+// CHECK-SAME: {{^}}, kabini
+// CHECK-SAME: {{^}}, mullins
+// CHECK-SAME: {{^}}, bonaire
+// CHECK-SAME: {{^}}, carrizo
+// CHECK-SAME: {{^}}, iceland
+// CHECK-SAME: {{^}}, tonga
+// CHECK-SAME: {{^}}, fiji
+// CHECK-SAME: {{^}}, polaris10
+// CHECK-SAME: {{^}}, polaris11
+// CHECK-SAME: {{^}}, tongapro
+// CHECK-SAME: {{^}}, stoney
 // CHECK-SAME: {{$}}

diff  --git a/clang/unittests/Basic/OffloadArchTest.cpp b/clang/unittests/Basic/OffloadArchTest.cpp
index c19ad0043d774..36dd958f0d896 100644
--- a/clang/unittests/Basic/OffloadArchTest.cpp
+++ b/clang/unittests/Basic/OffloadArchTest.cpp
@@ -11,26 +11,49 @@
 
 using namespace clang;
 
-TEST(OffloadArchTest, basic) {
-  EXPECT_TRUE(IsNVIDIAOffloadArch(OffloadArch::SM_20));
-  EXPECT_TRUE(IsNVIDIAOffloadArch(OffloadArch::SM_120a));
-  EXPECT_FALSE(IsNVIDIAOffloadArch(OffloadArch::GFX600));
-
-  EXPECT_FALSE(IsAMDOffloadArch(OffloadArch::SM_120a));
-  EXPECT_TRUE(IsAMDOffloadArch(OffloadArch::GFX600));
-  EXPECT_TRUE(IsAMDOffloadArch(OffloadArch::GFX1201));
-  EXPECT_TRUE(IsAMDOffloadArch(OffloadArch::GFX12_GENERIC));
-  EXPECT_TRUE(IsAMDOffloadArch(OffloadArch::AMDGCNSPIRV));
-  EXPECT_FALSE(IsAMDOffloadArch(OffloadArch::GRANITERAPIDS));
-
-  EXPECT_TRUE(IsIntelOffloadArch(OffloadArch::GRANITERAPIDS));
-  EXPECT_TRUE(IsIntelCPUOffloadArch(OffloadArch::GRANITERAPIDS));
-  EXPECT_FALSE(IsIntelGPUOffloadArch(OffloadArch::GRANITERAPIDS));
-  EXPECT_TRUE(IsIntelOffloadArch(OffloadArch::BMG_G21));
-  EXPECT_FALSE(IsIntelCPUOffloadArch(OffloadArch::BMG_G21));
-  EXPECT_TRUE(IsIntelGPUOffloadArch(OffloadArch::BMG_G21));
-
-  EXPECT_FALSE(IsNVIDIAOffloadArch(OffloadArch::Generic));
-  EXPECT_FALSE(IsAMDOffloadArch(OffloadArch::Generic));
-  EXPECT_FALSE(IsIntelOffloadArch(OffloadArch::Generic));
+static OffloadArch parse(llvm::StringRef S) { return StringToOffloadArch(S); }
+
+TEST(OffloadArchTest, VendorClassification) {
+  EXPECT_TRUE(IsNVIDIAOffloadArch(parse("sm_20")));
+  EXPECT_TRUE(IsNVIDIAOffloadArch(parse("sm_120a")));
+  EXPECT_FALSE(IsNVIDIAOffloadArch(parse("gfx600")));
+
+  EXPECT_FALSE(IsAMDOffloadArch(parse("sm_120a")));
+  EXPECT_TRUE(IsAMDOffloadArch(parse("gfx600")));
+  EXPECT_TRUE(IsAMDOffloadArch(parse("gfx1201")));
+  EXPECT_TRUE(IsAMDOffloadArch(parse("gfx12-generic")));
+  EXPECT_TRUE(IsAMDOffloadArch(parse("amdgcnspirv")));
+  EXPECT_FALSE(IsAMDOffloadArch(parse("graniterapids")));
+
+  EXPECT_TRUE(IsIntelOffloadArch(parse("graniterapids")));
+  EXPECT_TRUE(IsIntelCPUOffloadArch(parse("graniterapids")));
+  EXPECT_FALSE(IsIntelGPUOffloadArch(parse("graniterapids")));
+  EXPECT_TRUE(IsIntelOffloadArch(parse("bmg_g21")));
+  EXPECT_FALSE(IsIntelCPUOffloadArch(parse("bmg_g21")));
+  EXPECT_TRUE(IsIntelGPUOffloadArch(parse("bmg_g21")));
+
+  EXPECT_FALSE(IsNVIDIAOffloadArch(parse("generic")));
+  EXPECT_FALSE(IsAMDOffloadArch(parse("generic")));
+  EXPECT_FALSE(IsIntelOffloadArch(parse("generic")));
+}
+
+TEST(OffloadArchTest, Unknown) {
+  EXPECT_TRUE(parse("not-a-real-arch").isUnknown());
+  EXPECT_TRUE(parse("").isUnused());
+}
+
+// Names must round-trip through parse -> string.
+TEST(OffloadArchTest, RoundTrip) {
+  for (const char *Name :
+       {"sm_52", "sm_90a", "gfx906", "gfx1201", "gfx12-generic", "amdgcnspirv",
+        "graniterapids", "bmg_g21", "generic"}) {
+    OffloadArch A = parse(Name);
+    EXPECT_FALSE(A.isUnknown()) << Name;
+    EXPECT_STREQ(OffloadArchToString(A), Name);
+  }
+}
+
+TEST(OffloadArchTest, Defaults) {
+  EXPECT_STREQ(OffloadArchToString(OffloadArch::CudaDefault()), "sm_52");
+  EXPECT_STREQ(OffloadArchToString(OffloadArch::HIPDefault()), "gfx906");
 }

diff  --git a/llvm/include/llvm/TargetParser/AMDGPUTargetParser.h b/llvm/include/llvm/TargetParser/AMDGPUTargetParser.h
index fd0072c89be23..c2e394d82292f 100644
--- a/llvm/include/llvm/TargetParser/AMDGPUTargetParser.h
+++ b/llvm/include/llvm/TargetParser/AMDGPUTargetParser.h
@@ -31,7 +31,7 @@ class Triple;
 namespace AMDGPU {
 
 /// GPU kinds supported by the AMDGPU target.
-enum GPUKind : uint32_t {
+enum GPUKind : uint8_t {
   // Not specified processor.
   GK_NONE = 0,
 

diff  --git a/llvm/include/llvm/TargetParser/NVPTXTargetParser.h b/llvm/include/llvm/TargetParser/NVPTXTargetParser.h
index a49130b99ba76..446f5c47aeaf3 100644
--- a/llvm/include/llvm/TargetParser/NVPTXTargetParser.h
+++ b/llvm/include/llvm/TargetParser/NVPTXTargetParser.h
@@ -17,11 +17,15 @@ namespace llvm {
 namespace NVPTX {
 
 /// GPU kinds supported by the NVPTX target.
-enum GPUKind : uint32_t {
+enum GPUKind : uint8_t {
   GK_NONE = 0,
 #define NVPTX_GPU(NAME, KIND, VIRTUAL, SM_ID, MIN_VER, MAX_VER, SUFFIX)        \
   GK_##KIND,
 #include "llvm/TargetParser/NVPTXTargetParser.def"
+
+  // Alias for the last GPUKind. Keep in sync with the final .def row.
+  // FIXME: Should be generated once the GPU list moves to TableGen.
+  GK_LAST = GK_SM_121f,
 };
 
 /// Suffix class of an NVPTX architecture name. Enumerator spellings match the


        


More information about the cfe-commits mailing list