https://github.com/ianayl updated 
https://github.com/llvm/llvm-project/pull/227468

>From 0fbf5c511392b91022eb85c2334ff950c07e1808 Mon Sep 17 00:00:00 2001
From: "Li, Ian" <[email protected]>
Date: Mon, 28 Sep 2026 17:35:39 -0700
Subject: [PATCH 1/6] WIP addition of IGCA to OffloadArch

---
 clang/include/clang/Basic/OffloadArch.h       | 14 ++++-
 clang/lib/Basic/OffloadArch.cpp               | 19 ++++++
 clang/unittests/Basic/OffloadArchTest.cpp     |  2 +
 .../llvm/TargetParser/IntelGPUTargetParser.h  | 57 ++++++++++++++++++
 .../lib/TargetParser/IntelGPUTargetParser.cpp | 60 +++++++++++++++++++
 5 files changed, 151 insertions(+), 1 deletion(-)

diff --git a/clang/include/clang/Basic/OffloadArch.h 
b/clang/include/clang/Basic/OffloadArch.h
index a0e5e72db220bb..4aaeb8981b73a3 100644
--- a/clang/include/clang/Basic/OffloadArch.h
+++ b/clang/include/clang/Basic/OffloadArch.h
@@ -22,6 +22,9 @@ enum GPUKind : uint8_t;
 namespace AMDGPU {
 enum GPUKind : uint8_t;
 }
+namespace IntelGPU {
+struct IGCATarget;
+}
 } // namespace llvm
 
 namespace clang {
@@ -39,6 +42,7 @@ class OffloadArch {
     AMDGCNSPIRV, // The 'amdgcnspirv' pseudo target.
     IntelCPU,    // Kind is an IntelArch.
     IntelGPU,    // Kind is an IntelArch.
+    IntelIGCA,   // Kind is an Intel IGCA Target
     Generic,     // The 'generic' processor model.
   };
 
@@ -64,6 +68,7 @@ class OffloadArch {
   static OffloadArch getAMDGPU(llvm::AMDGPU::GPUKind K) {
     return {TargetArch::AMDGPU, static_cast<uint32_t>(K)};
   }
+  static OffloadArch getIntelIGCA(llvm::IntelGPU::IGCATarget T);
   static constexpr OffloadArch getIntel(TargetArch V, IntelArch A) {
     return {V, static_cast<uint32_t>(A)};
   }
@@ -85,18 +90,23 @@ class OffloadArch {
   bool isAMDGCNSPIRV() const { return V == TargetArch::AMDGCNSPIRV; }
   bool isIntelCPU() const { return V == TargetArch::IntelCPU; }
   bool isIntelGPU() const { return V == TargetArch::IntelGPU; }
+  // TODO: Decide whether IntelIGCA counts as Intel here. clang-sycl-linker
+  // uses isIntel() to decide on AOT compilation, and runAOTCompile would then
+  // need an IntelIGCA dispatch.
   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; }
+  bool isIntelIGCA() const { return V == TargetArch::IntelIGCA; }
 
-  // Only valid when isNVPTX() / isAMDGPU() respectively.
+  // Only valid when isNVPTX() / isAMDGPU() / isIntelIGCA() 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);
   }
+  llvm::IntelGPU::IGCATarget igcaTarget() const;
 
   bool operator==(const OffloadArch &Other) const {
     return V == Other.V && Kind == Other.Kind;
@@ -106,6 +116,8 @@ class OffloadArch {
   bool operator<(const OffloadArch &Other) const {
     return std::tie(V, Kind) < std::tie(Other.V, Other.Kind);
   }
+  // TODO test cases for whether or not IntelIGCA functions properly for these
+  // comparisons
 };
 
 const char *OffloadArchToString(OffloadArch A);
diff --git a/clang/lib/Basic/OffloadArch.cpp b/clang/lib/Basic/OffloadArch.cpp
index f8c811f552f387..93de61a3ebd876 100644
--- a/clang/lib/Basic/OffloadArch.cpp
+++ b/clang/lib/Basic/OffloadArch.cpp
@@ -11,6 +11,7 @@
 #include "llvm/ADT/StringRef.h"
 #include "llvm/TargetParser/AMDGPUTargetParser.h"
 #include "llvm/TargetParser/NVPTXTargetParser.h"
+#include "llvm/TargetParser/IntelGPUTargetParser.h"
 #include "llvm/TargetParser/Triple.h"
 
 namespace clang {
@@ -23,6 +24,14 @@ OffloadArch OffloadArch::HIPDefault() {
   return getAMDGPU(llvm::AMDGPU::parseArchAMDGCN("gfx906"));
 }
 
+OffloadArch OffloadArch::getIntelIGCA(llvm::IntelGPU::IGCATarget T) {
+  return {TargetArch::IntelIGCA, T.pack()};
+}
+
+llvm::IntelGPU::IGCATarget OffloadArch::igcaTarget() const {
+  return llvm::IntelGPU::IGCATarget::unpack(Kind);
+}
+
 const char *OffloadArchToString(OffloadArch A) {
   switch (A.targetArch()) {
   case OffloadArch::TargetArch::Unused:
@@ -39,6 +48,8 @@ const char *OffloadArchToString(OffloadArch A) {
     return "graniterapids";
   case OffloadArch::TargetArch::IntelGPU:
     return "bmg_g21";
+  case OffloadArch::TargetArch::IntelIGCA:
+    return llvm::IntelGPU::getIGCATargetName(A.igcaTarget()).data();
   case OffloadArch::TargetArch::Generic:
     return "generic";
   }
@@ -54,6 +65,8 @@ const char *OffloadArchToVirtualArchString(OffloadArch A) {
     return "compute_amdgcn";
   case OffloadArch::TargetArch::Unknown:
     return "unknown";
+  case OffloadArch::TargetArch::IntelIGCA:
+    return llvm::IntelGPU::getIGCATargetName(A.igcaTarget()).data();
   case OffloadArch::TargetArch::Unused:
   case OffloadArch::TargetArch::IntelCPU:
   case OffloadArch::TargetArch::IntelGPU:
@@ -85,9 +98,12 @@ OffloadArch StringToOffloadArch(llvm::StringRef S) {
     return OffloadArch::getNVPTX(NV);
   if (llvm::AMDGPU::GPUKind AK = llvm::AMDGPU::parseArchAMDGCN(S))
     return OffloadArch::getAMDGPU(AK);
+  if (llvm::IntelGPU::IGCATarget IT = llvm::IntelGPU::parseIGCATarget(S))
+    return OffloadArch::getIntelIGCA(IT);
   return OffloadArch::getUnknown();
 }
 
+// TODO: Append the IGCA target names once the IGCA target table exists.
 void fillValidOffloadArchList(llvm::SmallVectorImpl<llvm::StringRef> &Values) {
 #define NVPTX_GPU(NAME, KIND, VIRTUAL, SM_ID, MIN_VER, MAX_VER, SUFFIX)        
\
   Values.push_back(NAME);
@@ -95,6 +111,7 @@ void 
fillValidOffloadArchList(llvm::SmallVectorImpl<llvm::StringRef> &Values) {
   llvm::AMDGPU::fillValidArchListAMDGCN(Values, llvm::Triple::NoSubArch);
 }
 
+// TODO: Confirm IntelIGCA needs no subarch mapping; these only cover AMDGPU.
 OffloadArch getSubArchOffloadArch(llvm::Triple::SubArchType SubArch) {
   llvm::AMDGPU::GPUKind AK = llvm::AMDGPU::getGPUKindFromSubArch(SubArch);
   if (AK == llvm::AMDGPU::GK_NONE)
@@ -126,6 +143,8 @@ llvm::Triple OffloadArchToTriple(const llvm::Triple 
&DefaultToolchainTriple,
     return llvm::Triple(llvm::Triple::amdgpu, llvm::Triple::NoSubArch,
                         llvm::Triple::AMD, llvm::Triple::AMDHSA);
 
+  // TODO: Handle IntelIGCA, which currently gets an empty triple, so
+  // --offload-arch=igca_* cannot pick an offload toolchain.
   return {};
 }
 
diff --git a/clang/unittests/Basic/OffloadArchTest.cpp 
b/clang/unittests/Basic/OffloadArchTest.cpp
index 013ed75fbd57eb..f46ec566c7f037 100644
--- a/clang/unittests/Basic/OffloadArchTest.cpp
+++ b/clang/unittests/Basic/OffloadArchTest.cpp
@@ -54,6 +54,8 @@ TEST(OffloadArchTest, Unknown) {
 }
 
 // Names must round-trip through parse -> string.
+// TODO: Add IGCA targets (e.g. "igca_20ca"), plus IntelIGCA classification and
+// ==/< ordering tests.
 TEST(OffloadArchTest, RoundTrip) {
   for (const char *Name :
        {"sm_52", "sm_90a", "gfx906", "gfx1201", "gfx12-generic", "amdgcnspirv",
diff --git a/llvm/include/llvm/TargetParser/IntelGPUTargetParser.h 
b/llvm/include/llvm/TargetParser/IntelGPUTargetParser.h
index 4ae635e97167ba..b344e99070b485 100644
--- a/llvm/include/llvm/TargetParser/IntelGPUTargetParser.h
+++ b/llvm/include/llvm/TargetParser/IntelGPUTargetParser.h
@@ -34,6 +34,48 @@ enum GPUKind : uint8_t {
 #include "llvm/TargetParser/IntelGPUTargetParser.def"
 };
 
+// TODO Do I want the IGCA_ prefix here?
+enum class IGCAFeatureSet : uint8_t {
+  IGCA_CORE = 0,
+  IGCA_COMPUTE,
+  IGCA_RENDER
+};
+
+// TODO these need to be tested:
+struct IGCATarget {
+  uint16_t Target = 0;
+  IGCAFeatureSet FeatureSet = IGCAFeatureSet::IGCA_CORE;
+  bool IsExactFeatureSet = false;
+
+  /// Return true if the IGCATarget is a valid, properly initialized target.
+  bool isValid() const { return Target != 0; }
+  explicit operator bool() const { return isValid(); }
+
+  bool isCore() const { return FeatureSet == IGCAFeatureSet::IGCA_CORE; }
+  bool isExact() const { return IsExactFeatureSet; }
+  bool isCompute() const { return FeatureSet == IGCAFeatureSet::IGCA_COMPUTE; }
+  bool isRender() const { return FeatureSet == IGCAFeatureSet::IGCA_RENDER; }
+  bool isComputeExact() const { return isCompute() && isExact(); };
+  bool isRenderExact() const { return isRender() && isExact(); };
+
+  /// Pack an IGCATarget into an uint32_t.
+  ///
+  /// We encode as [31:16] Target, [2:1] FeatureSet, [0] IsExactFeatureSet.
+  /// [15:3] is left as reserved.
+  uint32_t pack() const;
+
+  /// Obtain an IGCATarget from a packed uint32_t.
+  static IGCATarget unpack(uint32_t V);
+
+  friend bool operator==(IGCATarget A, IGCATarget B) {
+    // TODO is this bad?
+    return A.pack() == B.pack();
+  }
+
+  /// Return an invalid IGCA Target that returns false on 
IGCATarget::isValid().
+  static IGCATarget invalid() { return IGCATarget{}; }
+};
+
 /// \return the device name that \p GPUIPVersion identifies, as reported by the
 /// driver, e.g. "xe-pvc". If the table lists no such device, return an empty
 /// string. Only the major and minor versions are looked at, so every revision
@@ -44,6 +86,21 @@ LLVM_ABI StringRef getArchName(uint32_t GPUIPVersion);
 /// \return the numeric name of \p GPUIPVersion, e.g. "xe_35.11.0".
 LLVM_ABI std::string getNumericArchName(uint32_t GPUIPVersion);
 
+/// Parse an IGCA Target.
+IGCATarget parseIGCATarget(StringRef TargetStr);
+
+/// Return the IGCA string for a given IGCA Target, i.e. "igca_60ca". Returns
+/// empty string if Target is not a valid target.
+std::string getIGCATargetName(IGCATarget Target);
+// TODO to carry stringref's, I need to create that IGCA Target table
+// If that IGCA Target table gets really verbose, we should just use the
+// strings from that table and use StringRef here instead of std::string.
+// TODO DO STRINGREF'S
+
+// TODO
+// - get igcatarget
+// - translate other targets?
+
 } // namespace IntelGPU
 } // namespace llvm
 
diff --git a/llvm/lib/TargetParser/IntelGPUTargetParser.cpp 
b/llvm/lib/TargetParser/IntelGPUTargetParser.cpp
index 4b4d162ffbfff7..67721b5fda0fda 100644
--- a/llvm/lib/TargetParser/IntelGPUTargetParser.cpp
+++ b/llvm/lib/TargetParser/IntelGPUTargetParser.cpp
@@ -63,3 +63,63 @@ std::string llvm::IntelGPU::getNumericArchName(uint32_t 
GPUIPVersion) {
   return ("xe_" + Twine(Major) + "." + Twine(Minor) + "." + Twine(Revision))
       .str();
 }
+
+IGCATarget llvm::IntelGPU::parseIGCATarget(StringRef MaybeTarget) {
+  if (!MaybeTarget.consume_front("igca_"))
+    return IGCATarget::invalid();
+
+  uint16_t Target;
+  if (MaybeTarget.consumeInteger(10, Target))
+    return IGCATarget::invalid();
+  // TODO check that Target contains a valid target level
+  
+  IGCAFeatureSet FS = IGCAFeatureSet::IGCA_CORE;
+  if (MaybeTarget.consume_front("c"))
+    FS = IGCAFeatureSet::IGCA_COMPUTE;
+  else if (MaybeTarget.consume_front("r"))
+    FS = IGCAFeatureSet::IGCA_RENDER;
+  bool IsExactFS = MaybeTarget.consume_front("a");
+  if (!MaybeTarget.empty())
+    return IGCATarget::invalid();
+
+  return { Target, FS, IsExactFS };
+}
+
+static constexpr uint32_t IGCATargetShift     = 16;
+static constexpr uint32_t IGCAFeatureSetShift = 1;
+static constexpr uint32_t IGCAIsExactFSShift  = 0;
+static constexpr uint32_t IGCAFeatureSetMask  = 0x03;
+static constexpr uint32_t IGCAIsExactFSMask   = 0x1;
+
+// An IGCA Target is packed as follows:
+//
+//    31              16 15           3 2           1 0         0 
+//   +------------------+--------------+-------------+-----------+
+//   |      Target      |   Reserved   | Feature set | Is Exact? |
+//   +------------------+--------------+-------------+-----------+
+//          16 bits         13 bits        2 bits        1 bit
+//
+uint32_t llvm::IntelGPU::IGCATarget::pack() const {
+  // TODO add debug mode asserts here
+  return uint32_t(Target) << IGCATargetShift |
+        (uint32_t(FeatureSet) & IGCAFeatureSetMask) << IGCAFeatureSetShift |
+        (uint32_t(IsExactFeatureSet) & IGCAIsExactFSMask)
+            << IGCAIsExactFSShift;
+}
+
+IGCATarget llvm::IntelGPU::IGCATarget::unpack(uint32_t V) {
+  return {
+    uint16_t(V >> IGCATargetShift),
+    IGCAFeatureSet((V >> IGCAFeatureSetShift) & IGCAFeatureSetMask),
+    bool((V >> IGCAIsExactFSShift) & IGCAIsExactFSMask)
+  };
+}
+
+std::string llvm::IntelGPU::getIGCATargetName(IGCATarget T) {
+  if (!T)
+    return "";
+
+  StringRef FS = T.isCompute() ? "c" : T.isRender() ? "r" : "";
+  StringRef Exact = T.isExact() ? "a" : "";
+  return ("igca_" + Twine(T.Target) + FS + Exact).str();
+}

>From e77b8e687eb00e98d09df7a145b397a195155161 Mon Sep 17 00:00:00 2001
From: "Li, Ian" <[email protected]>
Date: Tue, 29 Sep 2026 12:22:01 -0700
Subject: [PATCH 2/6] Properly define IGCA targets in targetparser.def, and
 collapse IGCATarget struct to wrap around uint32_t packed representation
 instead

---
 clang/include/clang/Basic/OffloadArch.h       |   2 +-
 clang/lib/Basic/OffloadArch.cpp               |   2 +-
 .../TargetParser/IntelGPUTargetParser.def     |  27 ++++-
 .../llvm/TargetParser/IntelGPUTargetParser.h  | 103 ++++++++++--------
 .../lib/TargetParser/IntelGPUTargetParser.cpp |  80 +++++++-------
 .../TargetParser/IntelGPUTargetParserTest.cpp |  89 +++++++++++++++
 6 files changed, 219 insertions(+), 84 deletions(-)

diff --git a/clang/include/clang/Basic/OffloadArch.h 
b/clang/include/clang/Basic/OffloadArch.h
index 4aaeb8981b73a3..a030192746c0d8 100644
--- a/clang/include/clang/Basic/OffloadArch.h
+++ b/clang/include/clang/Basic/OffloadArch.h
@@ -23,7 +23,7 @@ namespace AMDGPU {
 enum GPUKind : uint8_t;
 }
 namespace IntelGPU {
-struct IGCATarget;
+class IGCATarget;
 }
 } // namespace llvm
 
diff --git a/clang/lib/Basic/OffloadArch.cpp b/clang/lib/Basic/OffloadArch.cpp
index 93de61a3ebd876..6e06bbb433ada5 100644
--- a/clang/lib/Basic/OffloadArch.cpp
+++ b/clang/lib/Basic/OffloadArch.cpp
@@ -103,12 +103,12 @@ OffloadArch StringToOffloadArch(llvm::StringRef S) {
   return OffloadArch::getUnknown();
 }
 
-// TODO: Append the IGCA target names once the IGCA target table exists.
 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::IntelGPU::fillValidIGCATargetList(Values);
 }
 
 // TODO: Confirm IntelIGCA needs no subarch mapping; these only cover AMDGPU.
diff --git a/llvm/include/llvm/TargetParser/IntelGPUTargetParser.def 
b/llvm/include/llvm/TargetParser/IntelGPUTargetParser.def
index bd3b0a4634e066..9d3876ca9c78b5 100644
--- a/llvm/include/llvm/TargetParser/IntelGPUTargetParser.def
+++ b/llvm/include/llvm/TargetParser/IntelGPUTargetParser.def
@@ -17,7 +17,8 @@
 //                         GK_<KIND>.
 //     MAJOR             - Major component of the device's GPU IP version.
 //     MINOR             - Minor component of the device's GPU IP version.
-//     IGCA_TARGET       - Numeric IGCA target.
+//     IGCA_TARGET       - Numeric IGCA target: Targets should also be defined
+//                         in the INTEL_IGCA_TARGET table.
 //     IGCA_FEATURE_SETS - Token naming the IGCA feature sets the device
 //                         implements: Core (none), Compute ("c"),
 //                         Render ("r"), ComputeExact ("ca") or
@@ -37,6 +38,15 @@
 // Several devices can share a major and a minor version. The rows are ordered
 // so that the name to print for such a group comes first.
 //
+// This file also includes a list of valid IGCA targets, which can be used to
+// compile binaries with support different GPU architectures and feature sets:
+//
+//   INTEL_IGCA_TARGET(TARGET)
+//     TARGET            - Numeric IGCA target level, e.g. 60. corresponds to
+//                         "igca_60". A defined IGCA target means feature sets,
+//                         i.e. "igca_<TARGET>c", or "igca_<Target>ra" are also
+//                         accepted.
+//
 
//===----------------------------------------------------------------------===//
 
 #ifndef INTEL_GPU
@@ -92,5 +102,20 @@ INTEL_GPU_COMPAT("xe-bmg", XE_BMG, 40, Render)
 INTEL_GPU_COMPAT("xe-mtl", XE_MTL, 30, Render)
 INTEL_GPU_COMPAT("xe-dg2", XE_DG2, 15, RenderExact)
 
+// IGCA target levels. Only targets defined here are valid.
+#ifndef INTEL_IGCA_TARGET
+#define INTEL_IGCA_TARGET(TARGET)
+#endif
+
+INTEL_IGCA_TARGET(10)
+INTEL_IGCA_TARGET(15)
+INTEL_IGCA_TARGET(20)
+INTEL_IGCA_TARGET(30)
+INTEL_IGCA_TARGET(35)
+INTEL_IGCA_TARGET(40)
+INTEL_IGCA_TARGET(50)
+INTEL_IGCA_TARGET(60)
+
 #undef INTEL_GPU
 #undef INTEL_GPU_COMPAT
+#undef INTEL_IGCA_TARGET
diff --git a/llvm/include/llvm/TargetParser/IntelGPUTargetParser.h 
b/llvm/include/llvm/TargetParser/IntelGPUTargetParser.h
index b344e99070b485..4931937be3af40 100644
--- a/llvm/include/llvm/TargetParser/IntelGPUTargetParser.h
+++ b/llvm/include/llvm/TargetParser/IntelGPUTargetParser.h
@@ -22,6 +22,8 @@
 #include <string>
 
 namespace llvm {
+template <typename T> class SmallVectorImpl;
+
 namespace IntelGPU {
 
 /// Intel GPU architecture names, covering both physical devices and the
@@ -34,46 +36,62 @@ enum GPUKind : uint8_t {
 #include "llvm/TargetParser/IntelGPUTargetParser.def"
 };
 
-// TODO Do I want the IGCA_ prefix here?
-enum class IGCAFeatureSet : uint8_t {
+enum IGCAFeatureSet : uint8_t {
   IGCA_CORE = 0,
   IGCA_COMPUTE,
   IGCA_RENDER
 };
 
-// TODO these need to be tested:
-struct IGCATarget {
-  uint16_t Target = 0;
-  IGCAFeatureSet FeatureSet = IGCAFeatureSet::IGCA_CORE;
-  bool IsExactFeatureSet = false;
-
-  /// Return true if the IGCATarget is a valid, properly initialized target.
-  bool isValid() const { return Target != 0; }
+/// Wrapper around an IGCA target's uint32_t representation, packed using the
+/// following format:
+///
+///    31              16 15           3 2           1 0         0
+///   +------------------+--------------+-------------+-----------+
+///   |      Target      |   Reserved   | Feature set | Is Exact? |
+///   +------------------+--------------+-------------+-----------+
+///          16 bits         13 bits        2 bits        1 bit
+///
+/// Target == 0 denotes an invalid IGCA Target.
+class IGCATarget {
+  uint32_t V = 0;
+  constexpr explicit IGCATarget(uint32_t V) : V(V) {}
+
+public:
+  static constexpr uint32_t TargetShift = 16;
+  static constexpr uint32_t FeatureSetShift = 1;
+  static constexpr uint32_t IsExactShift = 0;
+  static constexpr uint32_t FeatureSetMask = 0x3;
+  static constexpr uint32_t IsExactMask = 0x1;
+
+  constexpr IGCATarget(uint16_t Target, IGCAFeatureSet FeatureSet, bool 
IsExact)
+      : V(uint32_t(Target) << TargetShift |
+          (uint32_t(FeatureSet) & FeatureSetMask) << FeatureSetShift |
+          (uint32_t(IsExact) & IsExactMask) << IsExactShift) {}
+
+  /// \return an invalid IGCATarget.
+  static constexpr IGCATarget invalid() { return IGCATarget(0); }
+
+  /// \return the packed uint32_t representation of the IGCA target.
+  constexpr uint32_t pack() const { return V; }
+  /// Wrap a packed uint32_t IGCA target with an IGCATarget class.
+  static constexpr IGCATarget unpack(uint32_t V) { return IGCATarget(V); }
+
+  uint16_t getTarget() const { return uint16_t(V >> TargetShift); }
+  IGCAFeatureSet getFeatureSet() const {
+    return IGCAFeatureSet((V >> FeatureSetShift) & FeatureSetMask);
+  }
+  bool isExact() const { return (V >> IsExactShift) & IsExactMask; }
+  bool isValid() const { return getTarget() != 0; }
   explicit operator bool() const { return isValid(); }
 
-  bool isCore() const { return FeatureSet == IGCAFeatureSet::IGCA_CORE; }
-  bool isExact() const { return IsExactFeatureSet; }
-  bool isCompute() const { return FeatureSet == IGCAFeatureSet::IGCA_COMPUTE; }
-  bool isRender() const { return FeatureSet == IGCAFeatureSet::IGCA_RENDER; }
-  bool isComputeExact() const { return isCompute() && isExact(); };
-  bool isRenderExact() const { return isRender() && isExact(); };
-
-  /// Pack an IGCATarget into an uint32_t.
-  ///
-  /// We encode as [31:16] Target, [2:1] FeatureSet, [0] IsExactFeatureSet.
-  /// [15:3] is left as reserved.
-  uint32_t pack() const;
-
-  /// Obtain an IGCATarget from a packed uint32_t.
-  static IGCATarget unpack(uint32_t V);
-
-  friend bool operator==(IGCATarget A, IGCATarget B) {
-    // TODO is this bad?
-    return A.pack() == B.pack();
-  }
+  bool isCore() const { return getFeatureSet() == IGCA_CORE; }
+  bool isCompute() const { return getFeatureSet() == IGCA_COMPUTE; }
+  bool isRender() const { return getFeatureSet() == IGCA_RENDER; }
+  bool isComputeExact() const { return isCompute() && isExact(); }
+  bool isRenderExact() const { return isRender() && isExact(); }
 
-  /// Return an invalid IGCA Target that returns false on 
IGCATarget::isValid().
-  static IGCATarget invalid() { return IGCATarget{}; }
+  friend bool operator==(IGCATarget A, IGCATarget B) { return A.V == B.V; }
+  friend bool operator!=(IGCATarget A, IGCATarget B) { return A.V != B.V; }
 };
 
 /// \return the device name that \p GPUIPVersion identifies, as reported by the
@@ -86,20 +104,17 @@ LLVM_ABI StringRef getArchName(uint32_t GPUIPVersion);
 /// \return the numeric name of \p GPUIPVersion, e.g. "xe_35.11.0".
 LLVM_ABI std::string getNumericArchName(uint32_t GPUIPVersion);
 
-/// Parse an IGCA Target.
-IGCATarget parseIGCATarget(StringRef TargetStr);
+/// Parse an IGCA target string, such as "igca_60ca". \return an invalid
+/// IGCATarget if \p TargetStr is not a known target in 
+/// IntelGPUTargetParser.def
+LLVM_ABI IGCATarget parseIGCATarget(StringRef TargetStr);
 
-/// Return the IGCA string for a given IGCA Target, i.e. "igca_60ca". Returns
-/// empty string if Target is not a valid target.
-std::string getIGCATargetName(IGCATarget Target);
-// TODO to carry stringref's, I need to create that IGCA Target table
-// If that IGCA Target table gets really verbose, we should just use the
-// strings from that table and use StringRef here instead of std::string.
-// TODO DO STRINGREF'S
+/// \return the \p Target as a string, i.e. "igca_60ca". \return an empty 
string
+/// if \p Target is invalid or not a known target in IntelGPUTargetParser.def.
+LLVM_ABI StringRef getIGCATargetName(IGCATarget Target);
 
-// TODO
-// - get igcatarget
-// - translate other targets?
+/// Append every legal IGCA target spelling to \p Values.
+LLVM_ABI void fillValidIGCATargetList(SmallVectorImpl<StringRef> &Values);
 
 } // namespace IntelGPU
 } // namespace llvm
diff --git a/llvm/lib/TargetParser/IntelGPUTargetParser.cpp 
b/llvm/lib/TargetParser/IntelGPUTargetParser.cpp
index 67721b5fda0fda..7b861b71e4c6a6 100644
--- a/llvm/lib/TargetParser/IntelGPUTargetParser.cpp
+++ b/llvm/lib/TargetParser/IntelGPUTargetParser.cpp
@@ -64,62 +64,68 @@ std::string llvm::IntelGPU::getNumericArchName(uint32_t 
GPUIPVersion) {
       .str();
 }
 
+/// Check that Level is a known IGCA Target in IntelGPUTargetParser.def.
+bool isKnownIGCATargetLevel(uint16_t Level) {
+  switch (Level) {
+#define INTEL_IGCA_TARGET(TARGET) case TARGET:
+#include "llvm/TargetParser/IntelGPUTargetParser.def"
+    return true;
+  default:
+    return false;
+  }
+}
+
 IGCATarget llvm::IntelGPU::parseIGCATarget(StringRef MaybeTarget) {
   if (!MaybeTarget.consume_front("igca_"))
     return IGCATarget::invalid();
 
   uint16_t Target;
-  if (MaybeTarget.consumeInteger(10, Target))
+  if (MaybeTarget.consumeInteger(10, Target) || 
!isKnownIGCATargetLevel(Target))
     return IGCATarget::invalid();
-  // TODO check that Target contains a valid target level
   
   IGCAFeatureSet FS = IGCAFeatureSet::IGCA_CORE;
   if (MaybeTarget.consume_front("c"))
     FS = IGCAFeatureSet::IGCA_COMPUTE;
   else if (MaybeTarget.consume_front("r"))
     FS = IGCAFeatureSet::IGCA_RENDER;
-  bool IsExactFS = MaybeTarget.consume_front("a");
+  // Exact form needs to either be compute or render:
+  bool IsExactFS = (
+      FS != IGCAFeatureSet::IGCA_CORE && MaybeTarget.consume_front("a")
+  );
   if (!MaybeTarget.empty())
     return IGCATarget::invalid();
 
   return { Target, FS, IsExactFS };
 }
 
-static constexpr uint32_t IGCATargetShift     = 16;
-static constexpr uint32_t IGCAFeatureSetShift = 1;
-static constexpr uint32_t IGCAIsExactFSShift  = 0;
-static constexpr uint32_t IGCAFeatureSetMask  = 0x03;
-static constexpr uint32_t IGCAIsExactFSMask   = 0x1;
-
-// An IGCA Target is packed as follows:
-//
-//    31              16 15           3 2           1 0         0 
-//   +------------------+--------------+-------------+-----------+
-//   |      Target      |   Reserved   | Feature set | Is Exact? |
-//   +------------------+--------------+-------------+-----------+
-//          16 bits         13 bits        2 bits        1 bit
-//
-uint32_t llvm::IntelGPU::IGCATarget::pack() const {
-  // TODO add debug mode asserts here
-  return uint32_t(Target) << IGCATargetShift |
-        (uint32_t(FeatureSet) & IGCAFeatureSetMask) << IGCAFeatureSetShift |
-        (uint32_t(IsExactFeatureSet) & IGCAIsExactFSMask)
-            << IGCAIsExactFSShift;
-}
-
-IGCATarget llvm::IntelGPU::IGCATarget::unpack(uint32_t V) {
-  return {
-    uint16_t(V >> IGCATargetShift),
-    IGCAFeatureSet((V >> IGCAFeatureSetShift) & IGCAFeatureSetMask),
-    bool((V >> IGCAIsExactFSShift) & IGCAIsExactFSMask)
-  };
+StringRef llvm::IntelGPU::getIGCATargetName(IGCATarget T) {
+  switch (T.pack()) {
+#define INTEL_IGCA_TARGET(TARGET)                                              
\
+  case IGCATarget(TARGET, IGCAFeatureSet::IGCA_CORE, false).pack():            
\
+    return "igca_" #TARGET;                                                    
\
+  case IGCATarget(TARGET, IGCAFeatureSet::IGCA_COMPUTE, false).pack():         
\
+    return "igca_" #TARGET "c";                                                
\
+  case IGCATarget(TARGET, IGCAFeatureSet::IGCA_COMPUTE, true).pack():          
\
+    return "igca_" #TARGET "ca";                                               
\
+  case IGCATarget(TARGET, IGCAFeatureSet::IGCA_RENDER, false).pack():          
\
+    return "igca_" #TARGET "r";                                                
\
+  case IGCATarget(TARGET, IGCAFeatureSet::IGCA_RENDER, true).pack():           
\
+    return "igca_" #TARGET "ra";
+#include "llvm/TargetParser/IntelGPUTargetParser.def"
+  default:
+    return "";
+  }
 }
 
-std::string llvm::IntelGPU::getIGCATargetName(IGCATarget T) {
-  if (!T)
-    return "";
+#define INTEL_IGCA_TARGET_FEATURESETS(TARGET)                                  
\
+  "igca_" #TARGET, "igca_" #TARGET "c", "igca_" #TARGET "ca",                  
\
+      "igca_" #TARGET "r", "igca_" #TARGET "ra"
 
-  StringRef FS = T.isCompute() ? "c" : T.isRender() ? "r" : "";
-  StringRef Exact = T.isExact() ? "a" : "";
-  return ("igca_" + Twine(T.Target) + FS + Exact).str();
+void llvm::IntelGPU::fillValidIGCATargetList(
+    SmallVectorImpl<StringRef> &Values) {
+#define INTEL_IGCA_TARGET(TARGET)                                              
\
+  Values.append({INTEL_IGCA_TARGET_FEATURESETS(TARGET)});
+#include "llvm/TargetParser/IntelGPUTargetParser.def"
 }
+
+#undef INTEL_IGCA_TARGET_FEATURESETS
diff --git a/llvm/unittests/TargetParser/IntelGPUTargetParserTest.cpp 
b/llvm/unittests/TargetParser/IntelGPUTargetParserTest.cpp
index ab8d456769d0da..93a31558e7e03e 100644
--- a/llvm/unittests/TargetParser/IntelGPUTargetParserTest.cpp
+++ b/llvm/unittests/TargetParser/IntelGPUTargetParserTest.cpp
@@ -78,4 +78,93 @@ TEST(IntelGPUTargetParserTest, NumericArchName) {
       "xe_12.60.7");
 }
 
+TEST(IntelGPUTargetParserTest, IGCATargetBehavior) {
+  IntelGPU::IGCATarget T(60, IntelGPU::IGCA_COMPUTE, true);
+  EXPECT_TRUE(T.isValid());
+  EXPECT_EQ(T.getTarget(), 60);
+  EXPECT_EQ(T.getFeatureSet(), IntelGPU::IGCA_COMPUTE);
+  EXPECT_TRUE(T.isExact());
+  EXPECT_TRUE(T.isComputeExact());
+  EXPECT_FALSE(T.isRender());
+  EXPECT_EQ(IntelGPU::IGCATarget::unpack(T.pack()), T);
+  EXPECT_NE(T, IntelGPU::IGCATarget(60, IntelGPU::IGCA_COMPUTE, false));
+  // Invalid behavior:
+  EXPECT_FALSE(IntelGPU::IGCATarget::invalid());
+  EXPECT_EQ(IntelGPU::IGCATarget::invalid().pack(), 0u);
+}
+
+TEST(IntelGPUTargetParserTest, ParseIGCATarget) {
+  using IntelGPU::IGCATarget;
+  EXPECT_EQ(IntelGPU::parseIGCATarget("igca_10"),
+            IGCATarget(10, IntelGPU::IGCA_CORE, false));
+  EXPECT_EQ(IntelGPU::parseIGCATarget("igca_20c"),
+            IGCATarget(20, IntelGPU::IGCA_COMPUTE, false));
+  EXPECT_EQ(IntelGPU::parseIGCATarget("igca_20ca"),
+            IGCATarget(20, IntelGPU::IGCA_COMPUTE, true));
+  EXPECT_EQ(IntelGPU::parseIGCATarget("igca_15r"),
+            IGCATarget(15, IntelGPU::IGCA_RENDER, false));
+  EXPECT_EQ(IntelGPU::parseIGCATarget("igca_15ra"),
+            IGCATarget(15, IntelGPU::IGCA_RENDER, true));
+  // Only levels in the table are valid targets.
+  EXPECT_FALSE(IntelGPU::parseIGCATarget("igca_42"));
+  EXPECT_FALSE(IntelGPU::parseIGCATarget("igca_0"));
+  // Cannot have exact without naming feature set:
+  EXPECT_FALSE(IntelGPU::parseIGCATarget("igca_10a"));
+  // Malformed spellings:
+  EXPECT_FALSE(IntelGPU::parseIGCATarget("igca_"));
+  EXPECT_FALSE(IntelGPU::parseIGCATarget("igca_10x"));
+  EXPECT_FALSE(IntelGPU::parseIGCATarget("igca_10cr"));
+  EXPECT_FALSE(IntelGPU::parseIGCATarget("igca_10caa"));
+  EXPECT_FALSE(IntelGPU::parseIGCATarget("igca10"));
+  EXPECT_FALSE(IntelGPU::parseIGCATarget("IGCA_10"));
+  EXPECT_FALSE(IntelGPU::parseIGCATarget(""));
+}
+
+TEST(IntelGPUTargetParserTest, IGCATargetName) {
+  using IntelGPU::IGCATarget;
+  EXPECT_EQ(IntelGPU::getIGCATargetName(
+                IGCATarget(60, IntelGPU::IGCA_CORE, false)),
+            "igca_60");
+  EXPECT_EQ(IntelGPU::getIGCATargetName(
+                IGCATarget(60, IntelGPU::IGCA_COMPUTE, true)),
+            "igca_60ca");
+  EXPECT_EQ(IntelGPU::getIGCATargetName(
+                IGCATarget(15, IntelGPU::IGCA_RENDER, false)),
+            "igca_15r");
+  EXPECT_EQ(IntelGPU::getIGCATargetName(IGCATarget::invalid()), "");
+  // A level that is not in the table has no spelling, and neither does an
+  // exact core target.
+  EXPECT_EQ(IntelGPU::getIGCATargetName(
+                IGCATarget(11, IntelGPU::IGCA_CORE, false)),
+            "");
+  EXPECT_EQ(IntelGPU::getIGCATargetName(
+                IGCATarget(10, IntelGPU::IGCA_CORE, true)),
+            "");
+}
+
+TEST(IntelGPUTargetParserTest, EveryIGCASpellingRoundTrips) {
+  SmallVector<StringRef> Names;
+  IntelGPU::fillValidIGCATargetList(Names);
+  EXPECT_FALSE(Names.empty());
+  for (StringRef Name : Names) {
+    IntelGPU::IGCATarget T = IntelGPU::parseIGCATarget(Name);
+    EXPECT_TRUE(T.isValid()) << Name;
+    EXPECT_EQ(IntelGPU::getIGCATargetName(T), Name);
+  }
+}
+
+TEST(IntelGPUTargetParserTest, EveryDeviceHasValidIGCATargetLevel) {
+  // Every device's defined IGCA target should have a corresponding entry in
+  // INTEL_IGCA_TARGET:
+#define INTEL_IGCA_TARGET_CHECK(NAME, IGCA_TARGET)                             
\
+  EXPECT_TRUE(IntelGPU::parseIGCATarget("igca_" #IGCA_TARGET).isValid())       
\
+      << NAME;
+#define INTEL_GPU(NAME, KIND, MAJOR, MINOR, IGCA_TARGET, IGCA_FEATURE_SETS)    
\
+  INTEL_IGCA_TARGET_CHECK(NAME, IGCA_TARGET)
+#define INTEL_GPU_COMPAT(NAME, KIND, IGCA_TARGET, IGCA_FEATURE_SETS)           
\
+  INTEL_IGCA_TARGET_CHECK(NAME, IGCA_TARGET)
+#include "llvm/TargetParser/IntelGPUTargetParser.def"
+#undef INTEL_IGCA_TARGET_CHECK
+}
+
 } // namespace

>From 7fdfd295d0523c9e612a4dc4579f79ffa527fa60 Mon Sep 17 00:00:00 2001
From: "Li, Ian" <[email protected]>
Date: Tue, 29 Sep 2026 13:23:23 -0700
Subject: [PATCH 3/6] fix nvptx test... I'm not so sure about the change...

---
 .../test/Misc/target-invalid-cpu-note/nvptx.c | 40 +++++++++++++++++++
 1 file changed, 40 insertions(+)

diff --git a/clang/test/Misc/target-invalid-cpu-note/nvptx.c 
b/clang/test/Misc/target-invalid-cpu-note/nvptx.c
index 20dbd8dc6aa3b6..528348dfba595c 100644
--- a/clang/test/Misc/target-invalid-cpu-note/nvptx.c
+++ b/clang/test/Misc/target-invalid-cpu-note/nvptx.c
@@ -128,4 +128,44 @@
 // CHECK-SAME: {{^}}, polaris11
 // CHECK-SAME: {{^}}, tongapro
 // CHECK-SAME: {{^}}, stoney
+// CHECK-SAME: {{^}}, igca_10
+// CHECK-SAME: {{^}}, igca_10c
+// CHECK-SAME: {{^}}, igca_10ca
+// CHECK-SAME: {{^}}, igca_10r
+// CHECK-SAME: {{^}}, igca_10ra
+// CHECK-SAME: {{^}}, igca_15
+// CHECK-SAME: {{^}}, igca_15c
+// CHECK-SAME: {{^}}, igca_15ca
+// CHECK-SAME: {{^}}, igca_15r
+// CHECK-SAME: {{^}}, igca_15ra
+// CHECK-SAME: {{^}}, igca_20
+// CHECK-SAME: {{^}}, igca_20c
+// CHECK-SAME: {{^}}, igca_20ca
+// CHECK-SAME: {{^}}, igca_20r
+// CHECK-SAME: {{^}}, igca_20ra
+// CHECK-SAME: {{^}}, igca_30
+// CHECK-SAME: {{^}}, igca_30c
+// CHECK-SAME: {{^}}, igca_30ca
+// CHECK-SAME: {{^}}, igca_30r
+// CHECK-SAME: {{^}}, igca_30ra
+// CHECK-SAME: {{^}}, igca_35
+// CHECK-SAME: {{^}}, igca_35c
+// CHECK-SAME: {{^}}, igca_35ca
+// CHECK-SAME: {{^}}, igca_35r
+// CHECK-SAME: {{^}}, igca_35ra
+// CHECK-SAME: {{^}}, igca_40
+// CHECK-SAME: {{^}}, igca_40c
+// CHECK-SAME: {{^}}, igca_40ca
+// CHECK-SAME: {{^}}, igca_40r
+// CHECK-SAME: {{^}}, igca_40ra
+// CHECK-SAME: {{^}}, igca_50
+// CHECK-SAME: {{^}}, igca_50c
+// CHECK-SAME: {{^}}, igca_50ca
+// CHECK-SAME: {{^}}, igca_50r
+// CHECK-SAME: {{^}}, igca_50ra
+// CHECK-SAME: {{^}}, igca_60
+// CHECK-SAME: {{^}}, igca_60c
+// CHECK-SAME: {{^}}, igca_60ca
+// CHECK-SAME: {{^}}, igca_60r
+// CHECK-SAME: {{^}}, igca_60ra
 // CHECK-SAME: {{$}}

>From 5949a6914849eca4d58411a190714e810e1c1c08 Mon Sep 17 00:00:00 2001
From: "Li, Ian" <[email protected]>
Date: Tue, 29 Sep 2026 13:24:24 -0700
Subject: [PATCH 4/6] clang-format

---
 clang/lib/Basic/OffloadArch.cpp               |  2 +-
 .../llvm/TargetParser/IntelGPUTargetParser.h  |  8 ++---
 .../lib/TargetParser/IntelGPUTargetParser.cpp |  9 +++---
 .../TargetParser/IntelGPUTargetParserTest.cpp | 30 +++++++++----------
 4 files changed, 22 insertions(+), 27 deletions(-)

diff --git a/clang/lib/Basic/OffloadArch.cpp b/clang/lib/Basic/OffloadArch.cpp
index 6e06bbb433ada5..c22aa528265fdb 100644
--- a/clang/lib/Basic/OffloadArch.cpp
+++ b/clang/lib/Basic/OffloadArch.cpp
@@ -10,8 +10,8 @@
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/TargetParser/AMDGPUTargetParser.h"
-#include "llvm/TargetParser/NVPTXTargetParser.h"
 #include "llvm/TargetParser/IntelGPUTargetParser.h"
+#include "llvm/TargetParser/NVPTXTargetParser.h"
 #include "llvm/TargetParser/Triple.h"
 
 namespace clang {
diff --git a/llvm/include/llvm/TargetParser/IntelGPUTargetParser.h 
b/llvm/include/llvm/TargetParser/IntelGPUTargetParser.h
index 4931937be3af40..339becdd102225 100644
--- a/llvm/include/llvm/TargetParser/IntelGPUTargetParser.h
+++ b/llvm/include/llvm/TargetParser/IntelGPUTargetParser.h
@@ -36,11 +36,7 @@ enum GPUKind : uint8_t {
 #include "llvm/TargetParser/IntelGPUTargetParser.def"
 };
 
-enum IGCAFeatureSet : uint8_t {
-  IGCA_CORE = 0,
-  IGCA_COMPUTE,
-  IGCA_RENDER
-};
+enum IGCAFeatureSet : uint8_t { IGCA_CORE = 0, IGCA_COMPUTE, IGCA_RENDER };
 
 /// Wrapper around an IGCA target's uint32_t representation, packed using the
 /// following format:
@@ -105,7 +101,7 @@ LLVM_ABI StringRef getArchName(uint32_t GPUIPVersion);
 LLVM_ABI std::string getNumericArchName(uint32_t GPUIPVersion);
 
 /// Parse an IGCA target string, such as "igca_60ca". \return an invalid
-/// IGCATarget if \p TargetStr is not a known target in 
+/// IGCATarget if \p TargetStr is not a known target in
 /// IntelGPUTargetParser.def
 LLVM_ABI IGCATarget parseIGCATarget(StringRef TargetStr);
 
diff --git a/llvm/lib/TargetParser/IntelGPUTargetParser.cpp 
b/llvm/lib/TargetParser/IntelGPUTargetParser.cpp
index 7b861b71e4c6a6..0e1163dff9aec8 100644
--- a/llvm/lib/TargetParser/IntelGPUTargetParser.cpp
+++ b/llvm/lib/TargetParser/IntelGPUTargetParser.cpp
@@ -82,20 +82,19 @@ IGCATarget llvm::IntelGPU::parseIGCATarget(StringRef 
MaybeTarget) {
   uint16_t Target;
   if (MaybeTarget.consumeInteger(10, Target) || 
!isKnownIGCATargetLevel(Target))
     return IGCATarget::invalid();
-  
+
   IGCAFeatureSet FS = IGCAFeatureSet::IGCA_CORE;
   if (MaybeTarget.consume_front("c"))
     FS = IGCAFeatureSet::IGCA_COMPUTE;
   else if (MaybeTarget.consume_front("r"))
     FS = IGCAFeatureSet::IGCA_RENDER;
   // Exact form needs to either be compute or render:
-  bool IsExactFS = (
-      FS != IGCAFeatureSet::IGCA_CORE && MaybeTarget.consume_front("a")
-  );
+  bool IsExactFS =
+      (FS != IGCAFeatureSet::IGCA_CORE && MaybeTarget.consume_front("a"));
   if (!MaybeTarget.empty())
     return IGCATarget::invalid();
 
-  return { Target, FS, IsExactFS };
+  return {Target, FS, IsExactFS};
 }
 
 StringRef llvm::IntelGPU::getIGCATargetName(IGCATarget T) {
diff --git a/llvm/unittests/TargetParser/IntelGPUTargetParserTest.cpp 
b/llvm/unittests/TargetParser/IntelGPUTargetParserTest.cpp
index 93a31558e7e03e..f1c55912305ece 100644
--- a/llvm/unittests/TargetParser/IntelGPUTargetParserTest.cpp
+++ b/llvm/unittests/TargetParser/IntelGPUTargetParserTest.cpp
@@ -122,24 +122,24 @@ TEST(IntelGPUTargetParserTest, ParseIGCATarget) {
 
 TEST(IntelGPUTargetParserTest, IGCATargetName) {
   using IntelGPU::IGCATarget;
-  EXPECT_EQ(IntelGPU::getIGCATargetName(
-                IGCATarget(60, IntelGPU::IGCA_CORE, false)),
-            "igca_60");
-  EXPECT_EQ(IntelGPU::getIGCATargetName(
-                IGCATarget(60, IntelGPU::IGCA_COMPUTE, true)),
-            "igca_60ca");
-  EXPECT_EQ(IntelGPU::getIGCATargetName(
-                IGCATarget(15, IntelGPU::IGCA_RENDER, false)),
-            "igca_15r");
+  EXPECT_EQ(
+      IntelGPU::getIGCATargetName(IGCATarget(60, IntelGPU::IGCA_CORE, false)),
+      "igca_60");
+  EXPECT_EQ(
+      IntelGPU::getIGCATargetName(IGCATarget(60, IntelGPU::IGCA_COMPUTE, 
true)),
+      "igca_60ca");
+  EXPECT_EQ(
+      IntelGPU::getIGCATargetName(IGCATarget(15, IntelGPU::IGCA_RENDER, 
false)),
+      "igca_15r");
   EXPECT_EQ(IntelGPU::getIGCATargetName(IGCATarget::invalid()), "");
   // A level that is not in the table has no spelling, and neither does an
   // exact core target.
-  EXPECT_EQ(IntelGPU::getIGCATargetName(
-                IGCATarget(11, IntelGPU::IGCA_CORE, false)),
-            "");
-  EXPECT_EQ(IntelGPU::getIGCATargetName(
-                IGCATarget(10, IntelGPU::IGCA_CORE, true)),
-            "");
+  EXPECT_EQ(
+      IntelGPU::getIGCATargetName(IGCATarget(11, IntelGPU::IGCA_CORE, false)),
+      "");
+  EXPECT_EQ(
+      IntelGPU::getIGCATargetName(IGCATarget(10, IntelGPU::IGCA_CORE, true)),
+      "");
 }
 
 TEST(IntelGPUTargetParserTest, EveryIGCASpellingRoundTrips) {

>From adf084bb47a080760de2e687707d64dfa7ad7acb Mon Sep 17 00:00:00 2001
From: "Li, Ian" <[email protected]>
Date: Thu, 1 Oct 2026 15:58:22 -0700
Subject: [PATCH 5/6] Enforce that only certain IGCA target feature sets can
 exist, simplify code and logic

---
 .../test/Misc/target-invalid-cpu-note/nvptx.c |  20 ---
 .../TargetParser/IntelGPUTargetParser.def     |  53 +++++--
 .../llvm/TargetParser/IntelGPUTargetParser.h  |  62 +++++---
 .../lib/TargetParser/IntelGPUTargetParser.cpp |  63 ++------
 .../TargetParser/IntelGPUTargetParserTest.cpp | 139 +++++++++++++-----
 5 files changed, 199 insertions(+), 138 deletions(-)

diff --git a/clang/test/Misc/target-invalid-cpu-note/nvptx.c 
b/clang/test/Misc/target-invalid-cpu-note/nvptx.c
index 528348dfba595c..b8f1bd806ef6af 100644
--- a/clang/test/Misc/target-invalid-cpu-note/nvptx.c
+++ b/clang/test/Misc/target-invalid-cpu-note/nvptx.c
@@ -129,43 +129,23 @@
 // CHECK-SAME: {{^}}, tongapro
 // CHECK-SAME: {{^}}, stoney
 // CHECK-SAME: {{^}}, igca_10
-// CHECK-SAME: {{^}}, igca_10c
-// CHECK-SAME: {{^}}, igca_10ca
 // CHECK-SAME: {{^}}, igca_10r
-// CHECK-SAME: {{^}}, igca_10ra
 // CHECK-SAME: {{^}}, igca_15
-// CHECK-SAME: {{^}}, igca_15c
-// CHECK-SAME: {{^}}, igca_15ca
 // CHECK-SAME: {{^}}, igca_15r
 // CHECK-SAME: {{^}}, igca_15ra
 // CHECK-SAME: {{^}}, igca_20
 // CHECK-SAME: {{^}}, igca_20c
 // CHECK-SAME: {{^}}, igca_20ca
-// CHECK-SAME: {{^}}, igca_20r
-// CHECK-SAME: {{^}}, igca_20ra
 // CHECK-SAME: {{^}}, igca_30
-// CHECK-SAME: {{^}}, igca_30c
-// CHECK-SAME: {{^}}, igca_30ca
 // CHECK-SAME: {{^}}, igca_30r
-// CHECK-SAME: {{^}}, igca_30ra
 // CHECK-SAME: {{^}}, igca_35
-// CHECK-SAME: {{^}}, igca_35c
-// CHECK-SAME: {{^}}, igca_35ca
 // CHECK-SAME: {{^}}, igca_35r
 // CHECK-SAME: {{^}}, igca_35ra
 // CHECK-SAME: {{^}}, igca_40
-// CHECK-SAME: {{^}}, igca_40c
-// CHECK-SAME: {{^}}, igca_40ca
 // CHECK-SAME: {{^}}, igca_40r
-// CHECK-SAME: {{^}}, igca_40ra
 // CHECK-SAME: {{^}}, igca_50
-// CHECK-SAME: {{^}}, igca_50c
-// CHECK-SAME: {{^}}, igca_50ca
 // CHECK-SAME: {{^}}, igca_50r
-// CHECK-SAME: {{^}}, igca_50ra
 // CHECK-SAME: {{^}}, igca_60
 // CHECK-SAME: {{^}}, igca_60c
-// CHECK-SAME: {{^}}, igca_60ca
 // CHECK-SAME: {{^}}, igca_60r
-// CHECK-SAME: {{^}}, igca_60ra
 // CHECK-SAME: {{$}}
diff --git a/llvm/include/llvm/TargetParser/IntelGPUTargetParser.def 
b/llvm/include/llvm/TargetParser/IntelGPUTargetParser.def
index 9d3876ca9c78b5..362b004f737106 100644
--- a/llvm/include/llvm/TargetParser/IntelGPUTargetParser.def
+++ b/llvm/include/llvm/TargetParser/IntelGPUTargetParser.def
@@ -41,11 +41,15 @@
 // This file also includes a list of valid IGCA targets, which can be used to
 // compile binaries with support different GPU architectures and feature sets:
 //
-//   INTEL_IGCA_TARGET(TARGET)
-//     TARGET            - Numeric IGCA target level, e.g. 60. corresponds to
-//                         "igca_60". A defined IGCA target means feature sets,
-//                         i.e. "igca_<TARGET>c", or "igca_<Target>ra" are also
-//                         accepted.
+//   INTEL_IGCA_TARGET(NAME, TARGET, FEATURE_SET)
+//     One row per valid IGCA target spelling. Only the combinations listed
+//     are valid.
+//     NAME              - Name of the IGCA target, e.g. "igca_15ra". Name must
+//                         agree with the other columns.
+//     TARGET            - Numeric IGCA target level, e.g. 60.
+//     FEATURE_SET       - Feature set of the current target, i.e. "Compute" 
for
+//                         "c" suffix, "Render" for "r", "ComputeExact" for
+//                         "ca", "Core" for "", etc.
 //
 
//===----------------------------------------------------------------------===//
 
@@ -102,19 +106,38 @@ INTEL_GPU_COMPAT("xe-bmg", XE_BMG, 40, Render)
 INTEL_GPU_COMPAT("xe-mtl", XE_MTL, 30, Render)
 INTEL_GPU_COMPAT("xe-dg2", XE_DG2, 15, RenderExact)
 
-// IGCA target levels. Only targets defined here are valid.
+// IGCA targets. Only targets listed here are valid.
 #ifndef INTEL_IGCA_TARGET
-#define INTEL_IGCA_TARGET(TARGET)
+#define INTEL_IGCA_TARGET(NAME, TARGET, FEATURE_SET)
 #endif
 
-INTEL_IGCA_TARGET(10)
-INTEL_IGCA_TARGET(15)
-INTEL_IGCA_TARGET(20)
-INTEL_IGCA_TARGET(30)
-INTEL_IGCA_TARGET(35)
-INTEL_IGCA_TARGET(40)
-INTEL_IGCA_TARGET(50)
-INTEL_IGCA_TARGET(60)
+INTEL_IGCA_TARGET("igca_10",   10, Core)
+INTEL_IGCA_TARGET("igca_10r",  10, Render)
+
+INTEL_IGCA_TARGET("igca_15",   15, Core)
+INTEL_IGCA_TARGET("igca_15r",  15, Render)
+INTEL_IGCA_TARGET("igca_15ra", 15, RenderExact)
+
+INTEL_IGCA_TARGET("igca_20",   20, Core)
+INTEL_IGCA_TARGET("igca_20c",  20, Compute)
+INTEL_IGCA_TARGET("igca_20ca", 20, ComputeExact)
+
+INTEL_IGCA_TARGET("igca_30",   30, Core)
+INTEL_IGCA_TARGET("igca_30r",  30, Render)
+
+INTEL_IGCA_TARGET("igca_35",   35, Core)
+INTEL_IGCA_TARGET("igca_35r",  35, Render)
+INTEL_IGCA_TARGET("igca_35ra", 35, RenderExact)
+
+INTEL_IGCA_TARGET("igca_40",   40, Core)
+INTEL_IGCA_TARGET("igca_40r",  40, Render)
+
+INTEL_IGCA_TARGET("igca_50",   50, Core)
+INTEL_IGCA_TARGET("igca_50r",  50, Render)
+
+INTEL_IGCA_TARGET("igca_60",   60, Core)
+INTEL_IGCA_TARGET("igca_60c",  60, Compute)
+INTEL_IGCA_TARGET("igca_60r",  60, Render)
 
 #undef INTEL_GPU
 #undef INTEL_GPU_COMPAT
diff --git a/llvm/include/llvm/TargetParser/IntelGPUTargetParser.h 
b/llvm/include/llvm/TargetParser/IntelGPUTargetParser.h
index 339becdd102225..7d8e1cf1ab4f8b 100644
--- a/llvm/include/llvm/TargetParser/IntelGPUTargetParser.h
+++ b/llvm/include/llvm/TargetParser/IntelGPUTargetParser.h
@@ -16,6 +16,7 @@
 #ifndef LLVM_TARGETPARSER_INTELGPUTARGETPARSER_H
 #define LLVM_TARGETPARSER_INTELGPUTARGETPARSER_H
 
+#include "llvm/ADT/STLForwardCompat.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/Compiler.h"
 #include <cstdint>
@@ -36,7 +37,16 @@ enum GPUKind : uint8_t {
 #include "llvm/TargetParser/IntelGPUTargetParser.def"
 };
 
-enum IGCAFeatureSet : uint8_t { IGCA_CORE = 0, IGCA_COMPUTE, IGCA_RENDER };
+/// Represents an IGCA feature set, including whether or not it is exact. The
+/// values are bitfields where the last bit represents exact. See IGCA Target
+/// representation below for more info.
+enum class IGCAFeatureSet : uint8_t {
+  Core = 0b000,
+  Compute = 0b010,
+  ComputeExact = 0b011,
+  Render = 0b100,
+  RenderExact = 0b101,
+};
 
 /// Wrapper around an IGCA target's uint32_t representation, packed using the
 /// following format:
@@ -54,15 +64,12 @@ class IGCATarget {
 
 public:
   static constexpr uint32_t TargetShift = 16;
-  static constexpr uint32_t FeatureSetShift = 1;
-  static constexpr uint32_t IsExactShift = 0;
-  static constexpr uint32_t FeatureSetMask = 0x3;
+  static constexpr uint32_t FeatureSetMask = 0x7;
   static constexpr uint32_t IsExactMask = 0x1;
 
-  constexpr IGCATarget(uint16_t Target, IGCAFeatureSet FeatureSet, bool 
IsExact)
+  constexpr IGCATarget(uint16_t Target, IGCAFeatureSet FeatureSet)
       : V(uint32_t(Target) << TargetShift |
-          (uint32_t(FeatureSet) & FeatureSetMask) << FeatureSetShift |
-          (uint32_t(IsExact) & IsExactMask) << IsExactShift) {}
+          (llvm::to_underlying(FeatureSet) & FeatureSetMask)) {}
 
   /// \return an invalid IGCATarget.
   static constexpr IGCATarget invalid() { return IGCATarget(0); }
@@ -73,18 +80,39 @@ class IGCATarget {
   static constexpr IGCATarget unpack(uint32_t V) { return IGCATarget(V); }
 
   uint16_t getTarget() const { return uint16_t(V >> TargetShift); }
+  /// \return the feature set, including whether it is exact.
+  ///
+  /// To check if a target has a feature set regardless of exactness, use
+  /// hasCompute() or hasRender() instead of raw comparison between
+  /// IGCAFeatureSet enums.
   IGCAFeatureSet getFeatureSet() const {
-    return IGCAFeatureSet((V >> FeatureSetShift) & FeatureSetMask);
+    return IGCAFeatureSet(V & FeatureSetMask);
   }
-  bool isExact() const { return (V >> IsExactShift) & IsExactMask; }
+  bool isExact() const { return V & IsExactMask; }
   bool isValid() const { return getTarget() != 0; }
   explicit operator bool() const { return isValid(); }
 
-  bool isCore() const { return getFeatureSet() == IGCA_CORE; }
-  bool isCompute() const { return getFeatureSet() == IGCA_COMPUTE; }
-  bool isRender() const { return getFeatureSet() == IGCA_RENDER; }
-  bool isComputeExact() const { return isCompute() && isExact(); }
-  bool isRenderExact() const { return isRender() && isExact(); }
+  bool isCore() const { return getFeatureSet() == IGCAFeatureSet::Core; }
+  /// \return true if the target has a non-exact Compute feature set.
+  bool isCompute() const { return getFeatureSet() == IGCAFeatureSet::Compute; }
+  /// \return true if the target has a non-exact Render feature set.
+  bool isRender() const { return getFeatureSet() == IGCAFeatureSet::Render; }
+  bool isComputeExact() const {
+    return getFeatureSet() == IGCAFeatureSet::ComputeExact;
+  }
+  bool isRenderExact() const {
+    return getFeatureSet() == IGCAFeatureSet::RenderExact;
+  }
+  /// \return true if target has either Compute or ComputeExact feature set.
+  bool hasCompute() const {
+    return (llvm::to_underlying(getFeatureSet()) & ~IsExactMask) ==
+           llvm::to_underlying(IGCAFeatureSet::Compute);
+  }
+  /// \return true if target has either Render or RenderExact feature set.
+  bool hasRender() const {
+    return (llvm::to_underlying(getFeatureSet()) & ~IsExactMask) ==
+           llvm::to_underlying(IGCAFeatureSet::Render);
+  }
 
   friend bool operator==(IGCATarget A, IGCATarget B) { return A.V == B.V; }
   friend bool operator!=(IGCATarget A, IGCATarget B) { return A.V != B.V; }
@@ -100,16 +128,16 @@ LLVM_ABI StringRef getArchName(uint32_t GPUIPVersion);
 /// \return the numeric name of \p GPUIPVersion, e.g. "xe_35.11.0".
 LLVM_ABI std::string getNumericArchName(uint32_t GPUIPVersion);
 
-/// Parse an IGCA target string, such as "igca_60ca". \return an invalid
+/// Parse an IGCA target string, such as "igca_20ca". \return an invalid
 /// IGCATarget if \p TargetStr is not a known target in
 /// IntelGPUTargetParser.def
 LLVM_ABI IGCATarget parseIGCATarget(StringRef TargetStr);
 
-/// \return the \p Target as a string, i.e. "igca_60ca". \return an empty 
string
+/// \return the \p Target as a string, i.e. "igca_20ca". \return an empty 
string
 /// if \p Target is invalid or not a known target in IntelGPUTargetParser.def.
 LLVM_ABI StringRef getIGCATargetName(IGCATarget Target);
 
-/// Append every legal IGCA target spelling to \p Values.
+/// Append every valid IGCA target spelling to \p Values.
 LLVM_ABI void fillValidIGCATargetList(SmallVectorImpl<StringRef> &Values);
 
 } // namespace IntelGPU
diff --git a/llvm/lib/TargetParser/IntelGPUTargetParser.cpp 
b/llvm/lib/TargetParser/IntelGPUTargetParser.cpp
index 0e1163dff9aec8..20335d30dc392b 100644
--- a/llvm/lib/TargetParser/IntelGPUTargetParser.cpp
+++ b/llvm/lib/TargetParser/IntelGPUTargetParser.cpp
@@ -11,6 +11,7 @@
 
//===----------------------------------------------------------------------===//
 
 #include "llvm/TargetParser/IntelGPUTargetParser.h"
+#include "llvm/ADT/StringSwitch.h"
 #include "llvm/ADT/Twine.h"
 #include <cassert>
 
@@ -64,67 +65,31 @@ std::string llvm::IntelGPU::getNumericArchName(uint32_t 
GPUIPVersion) {
       .str();
 }
 
-/// Check that Level is a known IGCA Target in IntelGPUTargetParser.def.
-bool isKnownIGCATargetLevel(uint16_t Level) {
-  switch (Level) {
-#define INTEL_IGCA_TARGET(TARGET) case TARGET:
-#include "llvm/TargetParser/IntelGPUTargetParser.def"
-    return true;
-  default:
-    return false;
-  }
-}
-
 IGCATarget llvm::IntelGPU::parseIGCATarget(StringRef MaybeTarget) {
-  if (!MaybeTarget.consume_front("igca_"))
-    return IGCATarget::invalid();
-
-  uint16_t Target;
-  if (MaybeTarget.consumeInteger(10, Target) || 
!isKnownIGCATargetLevel(Target))
-    return IGCATarget::invalid();
-
-  IGCAFeatureSet FS = IGCAFeatureSet::IGCA_CORE;
-  if (MaybeTarget.consume_front("c"))
-    FS = IGCAFeatureSet::IGCA_COMPUTE;
-  else if (MaybeTarget.consume_front("r"))
-    FS = IGCAFeatureSet::IGCA_RENDER;
-  // Exact form needs to either be compute or render:
-  bool IsExactFS =
-      (FS != IGCAFeatureSet::IGCA_CORE && MaybeTarget.consume_front("a"));
-  if (!MaybeTarget.empty())
-    return IGCATarget::invalid();
-
-  return {Target, FS, IsExactFS};
+  return StringSwitch<IGCATarget>(MaybeTarget)
+#define INTEL_IGCA_TARGET(NAME, TARGET, FEATURE_SET)                           
\
+  .Case(NAME, IGCATarget(TARGET, IGCAFeatureSet::FEATURE_SET))
+#include "llvm/TargetParser/IntelGPUTargetParser.def"
+      .Default(IGCATarget::invalid());
 }
 
 StringRef llvm::IntelGPU::getIGCATargetName(IGCATarget T) {
   switch (T.pack()) {
-#define INTEL_IGCA_TARGET(TARGET)                                              
\
-  case IGCATarget(TARGET, IGCAFeatureSet::IGCA_CORE, false).pack():            
\
-    return "igca_" #TARGET;                                                    
\
-  case IGCATarget(TARGET, IGCAFeatureSet::IGCA_COMPUTE, false).pack():         
\
-    return "igca_" #TARGET "c";                                                
\
-  case IGCATarget(TARGET, IGCAFeatureSet::IGCA_COMPUTE, true).pack():          
\
-    return "igca_" #TARGET "ca";                                               
\
-  case IGCATarget(TARGET, IGCAFeatureSet::IGCA_RENDER, false).pack():          
\
-    return "igca_" #TARGET "r";                                                
\
-  case IGCATarget(TARGET, IGCAFeatureSet::IGCA_RENDER, true).pack():           
\
-    return "igca_" #TARGET "ra";
+#define INTEL_IGCA_TARGET(NAME, TARGET, FEATURE_SET)                           
\
+  case IGCATarget(TARGET, IGCAFeatureSet::FEATURE_SET).pack():                 
\
+    return NAME;
 #include "llvm/TargetParser/IntelGPUTargetParser.def"
   default:
     return "";
   }
 }
 
-#define INTEL_IGCA_TARGET_FEATURESETS(TARGET)                                  
\
-  "igca_" #TARGET, "igca_" #TARGET "c", "igca_" #TARGET "ca",                  
\
-      "igca_" #TARGET "r", "igca_" #TARGET "ra"
-
+// TODO: Ensure -fsycl --offload-arch provides a list of valid IGCA
+// architectures, similar to how compiling for an nvptx triple returns a list
+// of valid GPU architectures. The user trying to input an invalid IGCA target
+// without being told what IGCA targets actually exist might get confusing.
 void llvm::IntelGPU::fillValidIGCATargetList(
     SmallVectorImpl<StringRef> &Values) {
-#define INTEL_IGCA_TARGET(TARGET)                                              
\
-  Values.append({INTEL_IGCA_TARGET_FEATURESETS(TARGET)});
+#define INTEL_IGCA_TARGET(NAME, TARGET, FEATURE_SET) Values.push_back(NAME);
 #include "llvm/TargetParser/IntelGPUTargetParser.def"
 }
-
-#undef INTEL_IGCA_TARGET_FEATURESETS
diff --git a/llvm/unittests/TargetParser/IntelGPUTargetParserTest.cpp 
b/llvm/unittests/TargetParser/IntelGPUTargetParserTest.cpp
index f1c55912305ece..b9685a61c4271d 100644
--- a/llvm/unittests/TargetParser/IntelGPUTargetParserTest.cpp
+++ b/llvm/unittests/TargetParser/IntelGPUTargetParserTest.cpp
@@ -79,33 +79,68 @@ TEST(IntelGPUTargetParserTest, NumericArchName) {
 }
 
 TEST(IntelGPUTargetParserTest, IGCATargetBehavior) {
-  IntelGPU::IGCATarget T(60, IntelGPU::IGCA_COMPUTE, true);
-  EXPECT_TRUE(T.isValid());
-  EXPECT_EQ(T.getTarget(), 60);
-  EXPECT_EQ(T.getFeatureSet(), IntelGPU::IGCA_COMPUTE);
-  EXPECT_TRUE(T.isExact());
-  EXPECT_TRUE(T.isComputeExact());
-  EXPECT_FALSE(T.isRender());
-  EXPECT_EQ(IntelGPU::IGCATarget::unpack(T.pack()), T);
-  EXPECT_NE(T, IntelGPU::IGCATarget(60, IntelGPU::IGCA_COMPUTE, false));
+  using IntelGPU::IGCAFeatureSet;
+  using IntelGPU::IGCATarget;
+  IGCATarget C{60, IGCAFeatureSet::ComputeExact};
+  EXPECT_TRUE(C.isValid());
+  EXPECT_EQ(C.getTarget(), 60);
+  EXPECT_EQ(C.getFeatureSet(), IGCAFeatureSet::ComputeExact);
+  EXPECT_TRUE(C.isExact());
+  // An exact feature set is still of its class:
+  EXPECT_TRUE(C.hasCompute());
+  EXPECT_TRUE(C.isComputeExact());
+  EXPECT_FALSE(C.isCore());
+  EXPECT_FALSE(C.isCompute());
+  EXPECT_FALSE(C.isRender());
+  EXPECT_FALSE(C.hasRender());
+  EXPECT_FALSE(C.isRenderExact());
+  EXPECT_EQ(IGCATarget::unpack(C.pack()), C);
+  EXPECT_NE(C, IGCATarget(60, IGCAFeatureSet::Compute));
+  // A feature set that is not exact:
+  IGCATarget R{60, IGCAFeatureSet::Render};
+  EXPECT_TRUE(R.isRender());
+  EXPECT_FALSE(R.isRenderExact());
+  EXPECT_FALSE(R.isExact());
+  EXPECT_FALSE(R.isCompute());
+  EXPECT_TRUE(R.hasRender());
+  EXPECT_FALSE(R.hasCompute());
+  EXPECT_EQ(IGCATarget::unpack(R.pack()), R);
+  IGCATarget Core{60, IGCAFeatureSet::Core};
+  EXPECT_TRUE(Core.isCore());
   // Invalid behavior:
-  EXPECT_FALSE(IntelGPU::IGCATarget::invalid());
-  EXPECT_EQ(IntelGPU::IGCATarget::invalid().pack(), 0u);
+  EXPECT_FALSE(IGCATarget::invalid());
+  EXPECT_EQ(IGCATarget::invalid().pack(), 0u);
 }
 
 TEST(IntelGPUTargetParserTest, ParseIGCATarget) {
+  using IntelGPU::IGCAFeatureSet;
   using IntelGPU::IGCATarget;
   EXPECT_EQ(IntelGPU::parseIGCATarget("igca_10"),
-            IGCATarget(10, IntelGPU::IGCA_CORE, false));
+            IGCATarget(10, IGCAFeatureSet::Core));
   EXPECT_EQ(IntelGPU::parseIGCATarget("igca_20c"),
-            IGCATarget(20, IntelGPU::IGCA_COMPUTE, false));
+            IGCATarget(20, IGCAFeatureSet::Compute));
   EXPECT_EQ(IntelGPU::parseIGCATarget("igca_20ca"),
-            IGCATarget(20, IntelGPU::IGCA_COMPUTE, true));
+            IGCATarget(20, IGCAFeatureSet::ComputeExact));
   EXPECT_EQ(IntelGPU::parseIGCATarget("igca_15r"),
-            IGCATarget(15, IntelGPU::IGCA_RENDER, false));
+            IGCATarget(15, IGCAFeatureSet::Render));
   EXPECT_EQ(IntelGPU::parseIGCATarget("igca_15ra"),
-            IGCATarget(15, IntelGPU::IGCA_RENDER, true));
-  // Only levels in the table are valid targets.
+            IGCATarget(15, IGCAFeatureSet::RenderExact));
+  EXPECT_EQ(IntelGPU::parseIGCATarget("igca_35ra"),
+            IGCATarget(35, IGCAFeatureSet::RenderExact));
+  EXPECT_EQ(IntelGPU::parseIGCATarget("igca_60c"),
+            IGCATarget(60, IGCAFeatureSet::Compute));
+  EXPECT_EQ(IntelGPU::parseIGCATarget("igca_60r"),
+            IGCATarget(60, IGCAFeatureSet::Render));
+  // Not all target levels support all feature sets:
+  EXPECT_FALSE(IntelGPU::parseIGCATarget("igca_10c"));
+  EXPECT_FALSE(IntelGPU::parseIGCATarget("igca_20r"));
+  EXPECT_FALSE(IntelGPU::parseIGCATarget("igca_20ra"));
+  // Only some target levels have an exact feature set:
+  EXPECT_FALSE(IntelGPU::parseIGCATarget("igca_10ra"));
+  EXPECT_FALSE(IntelGPU::parseIGCATarget("igca_30ra"));
+  EXPECT_FALSE(IntelGPU::parseIGCATarget("igca_60ca"));
+  EXPECT_FALSE(IntelGPU::parseIGCATarget("igca_60ra"));
+  // Only target levels in the table are valid targets:
   EXPECT_FALSE(IntelGPU::parseIGCATarget("igca_42"));
   EXPECT_FALSE(IntelGPU::parseIGCATarget("igca_0"));
   // Cannot have exact without naming feature set:
@@ -121,25 +156,25 @@ TEST(IntelGPUTargetParserTest, ParseIGCATarget) {
 }
 
 TEST(IntelGPUTargetParserTest, IGCATargetName) {
+  using IntelGPU::IGCAFeatureSet;
   using IntelGPU::IGCATarget;
+  EXPECT_EQ(IntelGPU::getIGCATargetName(IGCATarget(60, IGCAFeatureSet::Core)),
+            "igca_60");
   EXPECT_EQ(
-      IntelGPU::getIGCATargetName(IGCATarget(60, IntelGPU::IGCA_CORE, false)),
-      "igca_60");
-  EXPECT_EQ(
-      IntelGPU::getIGCATargetName(IGCATarget(60, IntelGPU::IGCA_COMPUTE, 
true)),
-      "igca_60ca");
-  EXPECT_EQ(
-      IntelGPU::getIGCATargetName(IGCATarget(15, IntelGPU::IGCA_RENDER, 
false)),
-      "igca_15r");
+      IntelGPU::getIGCATargetName(IGCATarget(20, 
IGCAFeatureSet::ComputeExact)),
+      "igca_20ca");
+  EXPECT_EQ(IntelGPU::getIGCATargetName(IGCATarget(15, 
IGCAFeatureSet::Render)),
+            "igca_15r");
+  // A target that does not exist / is not valid should produce "" to signify
+  // invalid target.
   EXPECT_EQ(IntelGPU::getIGCATargetName(IGCATarget::invalid()), "");
-  // A level that is not in the table has no spelling, and neither does an
-  // exact core target.
+  EXPECT_EQ(IntelGPU::getIGCATargetName(IGCATarget(11, IGCAFeatureSet::Core)),
+            "");
   EXPECT_EQ(
-      IntelGPU::getIGCATargetName(IGCATarget(11, IntelGPU::IGCA_CORE, false)),
+      IntelGPU::getIGCATargetName(IGCATarget(60, 
IGCAFeatureSet::ComputeExact)),
       "");
   EXPECT_EQ(
-      IntelGPU::getIGCATargetName(IGCATarget(10, IntelGPU::IGCA_CORE, true)),
-      "");
+      IntelGPU::getIGCATargetName(IGCATarget(10, IGCAFeatureSet::Compute)), 
"");
 }
 
 TEST(IntelGPUTargetParserTest, EveryIGCASpellingRoundTrips) {
@@ -153,16 +188,46 @@ TEST(IntelGPUTargetParserTest, 
EveryIGCASpellingRoundTrips) {
   }
 }
 
-TEST(IntelGPUTargetParserTest, EveryDeviceHasValidIGCATargetLevel) {
-  // Every device's defined IGCA target should have a corresponding entry in
-  // INTEL_IGCA_TARGET:
-#define INTEL_IGCA_TARGET_CHECK(NAME, IGCA_TARGET)                             
\
-  EXPECT_TRUE(IntelGPU::parseIGCATarget("igca_" #IGCA_TARGET).isValid())       
\
+// Spell an IGCA target from its fields, independently of the NAME column.
+std::string expectedIGCASpelling(uint16_t Target,
+                                 IntelGPU::IGCAFeatureSet FeatureSet) {
+  std::string Name = "igca_" + std::to_string(Target);
+  switch (FeatureSet) {
+  case IntelGPU::IGCAFeatureSet::Core:
+    return Name;
+  case IntelGPU::IGCAFeatureSet::Compute:
+    return Name + "c";
+  case IntelGPU::IGCAFeatureSet::ComputeExact:
+    return Name + "ca";
+  case IntelGPU::IGCAFeatureSet::Render:
+    return Name + "r";
+  case IntelGPU::IGCAFeatureSet::RenderExact:
+    return Name + "ra";
+  }
+  return "";
+}
+
+TEST(IntelGPUTargetParserTest, IGCASpellingsMatchFields) {
+  // Every INTEL_IGCA_TARGET's NAME must agree with information in the rest of
+  // its row.
+#define INTEL_IGCA_TARGET(NAME, TARGET, FEATURE_SET)                           
\
+  EXPECT_EQ(NAME, expectedIGCASpelling(                                        
\
+                      TARGET, IntelGPU::IGCAFeatureSet::FEATURE_SET));
+#include "llvm/TargetParser/IntelGPUTargetParser.def"
+}
+
+TEST(IntelGPUTargetParserTest, EveryDeviceHasValidIGCATarget) {
+  // Every device's IGCA target and feature sets should have a corresponding
+  // entry in INTEL_IGCA_TARGET:
+#define INTEL_IGCA_TARGET_CHECK(NAME, IGCA_TARGET, IGCA_FEATURE_SETS)          
\
+  EXPECT_NE(IntelGPU::getIGCATargetName(IntelGPU::IGCATarget(                  
\
+                IGCA_TARGET, IntelGPU::IGCAFeatureSet::IGCA_FEATURE_SETS)),    
\
+            "")                                                                
\
       << NAME;
 #define INTEL_GPU(NAME, KIND, MAJOR, MINOR, IGCA_TARGET, IGCA_FEATURE_SETS)    
\
-  INTEL_IGCA_TARGET_CHECK(NAME, IGCA_TARGET)
+  INTEL_IGCA_TARGET_CHECK(NAME, IGCA_TARGET, IGCA_FEATURE_SETS)
 #define INTEL_GPU_COMPAT(NAME, KIND, IGCA_TARGET, IGCA_FEATURE_SETS)           
\
-  INTEL_IGCA_TARGET_CHECK(NAME, IGCA_TARGET)
+  INTEL_IGCA_TARGET_CHECK(NAME, IGCA_TARGET, IGCA_FEATURE_SETS)
 #include "llvm/TargetParser/IntelGPUTargetParser.def"
 #undef INTEL_IGCA_TARGET_CHECK
 }

>From 7420a14b004047c5bd2f5050f20da2f19e7d13c8 Mon Sep 17 00:00:00 2001
From: "Li, Ian" <[email protected]>
Date: Thu, 8 Oct 2026 13:44:59 -0700
Subject: [PATCH 6/6] fillValidOffloadArchList is a bit misleading isnt it haha

---
 clang/lib/Basic/OffloadArch.cpp               |  1 -
 .../test/Misc/target-invalid-cpu-note/nvptx.c | 20 -------------------
 2 files changed, 21 deletions(-)

diff --git a/clang/lib/Basic/OffloadArch.cpp b/clang/lib/Basic/OffloadArch.cpp
index c22aa528265fdb..2127b12b30875c 100644
--- a/clang/lib/Basic/OffloadArch.cpp
+++ b/clang/lib/Basic/OffloadArch.cpp
@@ -108,7 +108,6 @@ void 
fillValidOffloadArchList(llvm::SmallVectorImpl<llvm::StringRef> &Values) {
   Values.push_back(NAME);
 #include "llvm/TargetParser/NVPTXTargetParser.def"
   llvm::AMDGPU::fillValidArchListAMDGCN(Values, llvm::Triple::NoSubArch);
-  llvm::IntelGPU::fillValidIGCATargetList(Values);
 }
 
 // TODO: Confirm IntelIGCA needs no subarch mapping; these only cover AMDGPU.
diff --git a/clang/test/Misc/target-invalid-cpu-note/nvptx.c 
b/clang/test/Misc/target-invalid-cpu-note/nvptx.c
index b8f1bd806ef6af..20dbd8dc6aa3b6 100644
--- a/clang/test/Misc/target-invalid-cpu-note/nvptx.c
+++ b/clang/test/Misc/target-invalid-cpu-note/nvptx.c
@@ -128,24 +128,4 @@
 // CHECK-SAME: {{^}}, polaris11
 // CHECK-SAME: {{^}}, tongapro
 // CHECK-SAME: {{^}}, stoney
-// CHECK-SAME: {{^}}, igca_10
-// CHECK-SAME: {{^}}, igca_10r
-// CHECK-SAME: {{^}}, igca_15
-// CHECK-SAME: {{^}}, igca_15r
-// CHECK-SAME: {{^}}, igca_15ra
-// CHECK-SAME: {{^}}, igca_20
-// CHECK-SAME: {{^}}, igca_20c
-// CHECK-SAME: {{^}}, igca_20ca
-// CHECK-SAME: {{^}}, igca_30
-// CHECK-SAME: {{^}}, igca_30r
-// CHECK-SAME: {{^}}, igca_35
-// CHECK-SAME: {{^}}, igca_35r
-// CHECK-SAME: {{^}}, igca_35ra
-// CHECK-SAME: {{^}}, igca_40
-// CHECK-SAME: {{^}}, igca_40r
-// CHECK-SAME: {{^}}, igca_50
-// CHECK-SAME: {{^}}, igca_50r
-// CHECK-SAME: {{^}}, igca_60
-// CHECK-SAME: {{^}}, igca_60c
-// CHECK-SAME: {{^}}, igca_60r
 // CHECK-SAME: {{$}}

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to