[clang] [llvm] [TargetParser][clang] Parse and store Intel IGCA virtual architecture as an OffloadArch (PR #227468)
Ian Li via cfe-commits
cfe-commits at lists.llvm.org
Thu Oct 8 14:57:29 PDT 2026
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" <ian.li at intel.com>
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" <ian.li at intel.com>
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" <ian.li at intel.com>
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" <ian.li at intel.com>
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" <ian.li at intel.com>
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" <ian.li at intel.com>
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: {{$}}
More information about the cfe-commits
mailing list