[clang] [llvm] [TargetParser][Clang] Parse Intel GPU architecture names (PR #229247)
Srividya Sundaram via cfe-commits
cfe-commits at lists.llvm.org
Mon Oct 12 18:12:07 PDT 2026
https://github.com/srividya-sundaram updated https://github.com/llvm/llvm-project/pull/229247
>From 4e07d042e43ba094a8f05c838631d32c24853e84 Mon Sep 17 00:00:00 2001
From: srividya sundaram <srividya.sundaram at intel.com>
Date: Sat, 12 Sep 2026 19:09:30 -0700
Subject: [PATCH 1/3] [TargetParser][Clang] Parse Intel GPU architecture names
Add support for Intel GPU names in --offload-arch.
#222072 added the mapping from a detected GPU version to its name. This PR adds the reverse mapping needed when a user specifies a name through --offload-arch.
Previously, clang recognized only the hardcoded name bmg_g21.
The shared Intel GPU list now recognizes names such as xe-pvc, xe-dg2, bmg_g21, and xe_12.60.7. Names for the same GPU IP are treated as aliases, so SYCL creates one device job and matches all spellings consistently. clang-sycl-linker uses the canonical name for the image and the name expected by ocloc.
User-visible changes:
- A device is printed and labelled by its canonical name, e.g. bmg_g21 becomes xe-bmg-g21.
- Every listed Intel GPU name is compiled ahead of time with ocloc, as bmg_g21 already was.
- Products on the same GPU IP become aliases, so 13 GPUKind enumerators are removed, e.g. GK_XE_ARL_U is now GK_XE_MTL_U.
- An Intel name is no longer accepted as an NVPTX CPU; -target-cpu bmg_g21 was accepted before.
- An Intel name with a target-ID suffix, e.g. xe-pvc:foo, is not turned into a device.
Canonicalization is limited to SYCL, the only offload kind that compiles for Intel GPUs today.
Selecting the SPIR-V target from an Intel GPU name and diagnosing unknown names are handled separately in follow-up PRs.
Assisted-by: Claude Opus 5.5
---
clang/include/clang/Basic/OffloadArch.h | 26 ++--
clang/lib/Basic/OffloadArch.cpp | 12 +-
clang/lib/Basic/Targets/NVPTX.h | 11 +-
clang/lib/Driver/Driver.cpp | 22 ++-
clang/lib/Driver/ToolChain.cpp | 4 +
clang/lib/Driver/ToolChains/Clang.cpp | 8 +-
clang/test/Driver/sycl-offload-jit.cpp | 61 ++++++++-
.../test/Misc/target-invalid-cpu-note/nvptx.c | 4 +
.../OffloadTools/clang-sycl-linker/basic.ll | 13 +-
.../clang-sycl-linker/ClangSYCLLinker.cpp | 15 ++-
clang/unittests/Basic/OffloadArchTest.cpp | 23 +++-
.../TargetParser/IntelGPUTargetParser.def | 59 +++++---
.../llvm/TargetParser/IntelGPUTargetParser.h | 41 +++++-
.../lib/TargetParser/IntelGPUTargetParser.cpp | 127 +++++++++++++++++-
.../TargetParser/IntelGPUTargetParserTest.cpp | 104 ++++++++++++++
15 files changed, 473 insertions(+), 57 deletions(-)
diff --git a/clang/include/clang/Basic/OffloadArch.h b/clang/include/clang/Basic/OffloadArch.h
index a0e5e72db220b..95a17952d4a2a 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 {
+enum GPUKind : uint8_t;
+}
} // namespace llvm
namespace clang {
@@ -37,17 +40,11 @@ class OffloadArch {
NVPTX, // Kind is an llvm::NVPTX::GPUKind.
AMDGPU, // Kind is an llvm::AMDGPU::GPUKind.
AMDGCNSPIRV, // The 'amdgcnspirv' pseudo target.
- IntelCPU, // Kind is an IntelArch.
- IntelGPU, // Kind is an IntelArch.
+ IntelCPU, // The 'graniterapids' processor; Kind is unused.
+ IntelGPU, // Kind is an llvm::IntelGPU::GPUKind.
Generic, // The 'generic' processor model.
};
- // Intel architectures, which have no TargetParser list yet.
- enum class IntelArch : uint32_t {
- GRANITERAPIDS,
- BMG_G21,
- };
-
private:
// Interpreted according to V; unused for the tagless TargetArch values.
uint32_t Kind = 0;
@@ -64,8 +61,13 @@ class OffloadArch {
static OffloadArch getAMDGPU(llvm::AMDGPU::GPUKind K) {
return {TargetArch::AMDGPU, static_cast<uint32_t>(K)};
}
- static constexpr OffloadArch getIntel(TargetArch V, IntelArch A) {
- return {V, static_cast<uint32_t>(A)};
+ /// An Intel GPU, named by its entry in the TargetParser device list.
+ static OffloadArch getIntelGPU(llvm::IntelGPU::GPUKind K) {
+ return {TargetArch::IntelGPU, static_cast<uint32_t>(K)};
+ }
+ /// Intel CPU offload, which has a single target, so no kind is needed.
+ static constexpr OffloadArch getIntelCPU() {
+ return {TargetArch::IntelCPU, 0};
}
static constexpr OffloadArch getUnused() { return {TargetArch::Unused, 0}; }
static constexpr OffloadArch getUnknown() { return {TargetArch::Unknown, 0}; }
@@ -97,6 +99,10 @@ class OffloadArch {
llvm::AMDGPU::GPUKind amdgpuKind() const {
return static_cast<llvm::AMDGPU::GPUKind>(Kind);
}
+ /// Which Intel GPU this is; only meaningful when isIntelGPU().
+ llvm::IntelGPU::GPUKind intelGPUKind() const {
+ return static_cast<llvm::IntelGPU::GPUKind>(Kind);
+ }
bool operator==(const OffloadArch &Other) const {
return V == Other.V && Kind == Other.Kind;
diff --git a/clang/lib/Basic/OffloadArch.cpp b/clang/lib/Basic/OffloadArch.cpp
index f8c811f552f38..adc94b35ce025 100644
--- a/clang/lib/Basic/OffloadArch.cpp
+++ b/clang/lib/Basic/OffloadArch.cpp
@@ -10,6 +10,7 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/TargetParser/AMDGPUTargetParser.h"
+#include "llvm/TargetParser/IntelGPUTargetParser.h"
#include "llvm/TargetParser/NVPTXTargetParser.h"
#include "llvm/TargetParser/Triple.h"
@@ -38,7 +39,7 @@ const char *OffloadArchToString(OffloadArch A) {
case OffloadArch::TargetArch::IntelCPU:
return "graniterapids";
case OffloadArch::TargetArch::IntelGPU:
- return "bmg_g21";
+ return llvm::IntelGPU::getArchName(A.intelGPUKind()).data();
case OffloadArch::TargetArch::Generic:
return "generic";
}
@@ -73,18 +74,17 @@ OffloadArch StringToOffloadArch(llvm::StringRef S) {
return OffloadArch::getAMDGCNSPIRV();
if (S == "generic")
return OffloadArch::getGeneric();
+ // Intel CPU offload has a single processor and no TargetParser list.
if (S == "graniterapids")
- return OffloadArch::getIntel(OffloadArch::TargetArch::IntelCPU,
- OffloadArch::IntelArch::GRANITERAPIDS);
- if (S == "bmg_g21")
- return OffloadArch::getIntel(OffloadArch::TargetArch::IntelGPU,
- OffloadArch::IntelArch::BMG_G21);
+ return OffloadArch::getIntelCPU();
// Otherwise defer to the vendor TargetParser GPU lists.
if (llvm::NVPTX::GPUKind NV = llvm::NVPTX::parseArch(S))
return OffloadArch::getNVPTX(NV);
if (llvm::AMDGPU::GPUKind AK = llvm::AMDGPU::parseArchAMDGCN(S))
return OffloadArch::getAMDGPU(AK);
+ if (llvm::IntelGPU::GPUKind IK = llvm::IntelGPU::parseArch(S))
+ return OffloadArch::getIntelGPU(IK);
return OffloadArch::getUnknown();
}
diff --git a/clang/lib/Basic/Targets/NVPTX.h b/clang/lib/Basic/Targets/NVPTX.h
index b6d2bfd320103..45ba8322cf5fc 100644
--- a/clang/lib/Basic/Targets/NVPTX.h
+++ b/clang/lib/Basic/Targets/NVPTX.h
@@ -135,8 +135,13 @@ class LLVM_LIBRARY_VISIBILITY NVPTXTargetInfo : public TargetInfo {
return TargetInfo::CharPtrBuiltinVaList;
}
+ // StringToOffloadArch recognizes architectures from all vendors. Accept only
+ // the ones NVPTX accepted before, so Sema does not accept an Intel GPU name
+ // as an NVPTX CPU.
bool isValidCPUName(StringRef Name) const override {
- return !StringToOffloadArch(Name).isUnknown();
+ OffloadArch Arch = StringToOffloadArch(Name);
+ return Arch.isNVPTX() || Arch.isAMDGPU() || Arch.isAMDGCNSPIRV() ||
+ Arch.isGeneric() || Arch.isUnused();
}
void fillValidCPUList(SmallVectorImpl<StringRef> &Values) const override {
@@ -144,8 +149,10 @@ class LLVM_LIBRARY_VISIBILITY NVPTXTargetInfo : public TargetInfo {
}
bool setCPU(StringRef Name) override {
+ if (!isValidCPUName(Name))
+ return false;
GPU = StringToOffloadArch(Name);
- return !GPU.isUnknown();
+ return true;
}
void setSupportedOpenCLOpts() override {
diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp
index 57beab92011a9..bbcf88d823776 100644
--- a/clang/lib/Driver/Driver.cpp
+++ b/clang/lib/Driver/Driver.cpp
@@ -3899,15 +3899,20 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
}
/// Returns the canonical name for the offloading architecture when using a HIP
-/// or CUDA architecture.
+/// or CUDA architecture, or an Intel GPU for SYCL.
static StringRef getCanonicalArchString(Compilation &C,
const llvm::opt::DerivedArgList &Args,
StringRef ArchStr,
- const llvm::Triple &Triple) {
+ const llvm::Triple &Triple,
+ Action::OffloadKind Kind) {
// Lookup the CUDA / HIP architecture string. Only report an error if we were
// expecting the triple to be only NVPTX / AMDGPU.
OffloadArch Arch =
StringToOffloadArch(getProcessorFromTargetID(Triple, ArchStr));
+ // An Intel name takes no target features, so it must parse in full; otherwise
+ // "xe-pvc:garbage" would silently become "xe-pvc".
+ if (Arch.isIntel() && ArchStr.contains(':'))
+ Arch = OffloadArch::getUnknown();
if (Triple.isNVPTX() && (Arch.isUnknown() || !Arch.isNVPTX())) {
C.getDriver().Diag(clang::diag::err_drv_offload_bad_gpu_arch)
<< "CUDA" << ArchStr;
@@ -3930,7 +3935,10 @@ static StringRef getCanonicalArchString(Compilation &C,
}
}
- if (Arch.isNVPTX())
+ // A SYCL Intel GPU has several accepted spellings, e.g. an alias or a numeric
+ // name, so canonicalize it for the same reason as an NVPTX one: two spellings
+ // of one device must be one architecture.
+ if (Arch.isNVPTX() || (Kind == Action::OFK_SYCL && Arch.isIntelGPU()))
return Args.MakeArgStringRef(OffloadArchToString(Arch));
if (Arch.isAMDGPU() || Arch.isAMDGCNSPIRV()) {
@@ -3991,7 +3999,7 @@ Driver::getOffloadArchs(Compilation &C, const llvm::opt::DerivedArgList &Args,
for (auto ArchStr : *GPUsOrErr) {
StringRef CanonicalStr = getCanonicalArchString(
- C, Args, Args.MakeArgString(ArchStr), TC.getTriple());
+ C, Args, Args.MakeArgString(ArchStr), TC.getTriple(), Kind);
if (!CanonicalStr.empty())
Archs.insert(CanonicalStr);
else
@@ -3999,7 +4007,7 @@ Driver::getOffloadArchs(Compilation &C, const llvm::opt::DerivedArgList &Args,
}
} else {
StringRef CanonicalStr =
- getCanonicalArchString(C, Args, Arch, TC.getTriple());
+ getCanonicalArchString(C, Args, Arch, TC.getTriple(), Kind);
if (!CanonicalStr.empty())
Archs.insert(CanonicalStr);
else
@@ -4012,7 +4020,7 @@ Driver::getOffloadArchs(Compilation &C, const llvm::opt::DerivedArgList &Args,
Archs.clear();
} else {
StringRef ArchStr =
- getCanonicalArchString(C, Args, Arch, TC.getTriple());
+ getCanonicalArchString(C, Args, Arch, TC.getTriple(), Kind);
Archs.erase(ArchStr);
}
}
@@ -4068,7 +4076,7 @@ Driver::getOffloadArchs(Compilation &C, const llvm::opt::DerivedArgList &Args,
? ""
: OffloadArchToString(TripleOffloadArch);
StringRef CanonicalStr =
- getCanonicalArchString(C, Args, ArchStr, TC.getTriple());
+ getCanonicalArchString(C, Args, ArchStr, TC.getTriple(), Kind);
if (!CanonicalStr.empty())
Archs.insert(CanonicalStr);
}
diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp
index 255a9c9602b54..d7928cd10ea24 100644
--- a/clang/lib/Driver/ToolChain.cpp
+++ b/clang/lib/Driver/ToolChain.cpp
@@ -2189,7 +2189,11 @@ llvm::opt::DerivedArgList *ToolChain::TranslateXarchArgs(
Skip = IsDevice;
} else if (A->getOption().matches(options::OPT_Xarch__)) {
StringRef Val = A->getValue();
+ // A SYCL Intel GPU has several spellings, so -Xarch_ may name it by
+ // another.
NeedTrans = Val == getArchName() || (BA && Val == BA.ArchName) ||
+ (OFK == Action::OFK_SYCL && BA && BA.Arch.isIntelGPU() &&
+ StringToOffloadArch(Val) == BA.Arch) ||
isXArchCompatibleTripleArch(Triple, Val);
Skip = !NeedTrans;
}
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 2325e7cc552ef..7071ee6b3bebe 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -9864,8 +9864,14 @@ void LinkerWrapper::ConstructJob(Compilation &C, const JobAction &JA,
// If the user explicitly requested it via `--offload-arch` we should
// extract it from any static libraries if present.
- for (StringRef Arg : ToolChainArgs.getAllArgValues(OPT_offload_arch_EQ))
+ // A SYCL Intel GPU is requested by its canonical name, the one its device
+ // images are labeled with, whichever spelling the user wrote.
+ for (StringRef Arg : ToolChainArgs.getAllArgValues(OPT_offload_arch_EQ)) {
+ OffloadArch ID = StringToOffloadArch(Arg);
+ if (Kind == Action::OFK_SYCL && ID.isIntelGPU())
+ Arg = OffloadArchToString(ID);
CmdArgs.emplace_back(Args.MakeArgString("--should-extract=" + Arg));
+ }
// If this is OpenMP the device linker will need `-lompdevice`.
if (Kind == Action::OFK_OpenMP && !Args.hasArg(OPT_no_offloadlib) &&
diff --git a/clang/test/Driver/sycl-offload-jit.cpp b/clang/test/Driver/sycl-offload-jit.cpp
index 82733ccd2bc6f..cb4283db51d25 100644
--- a/clang/test/Driver/sycl-offload-jit.cpp
+++ b/clang/test/Driver/sycl-offload-jit.cpp
@@ -90,11 +90,68 @@
// RUN: %clang -ccc-print-phases --target=x86_64-unknown-linux-gnu -fsycl -fno-gpu-rdc \
// RUN: --offload-targets=spirv64-unknown-unknown --offload-arch=generic --offload-arch=bmg_g21 \
// RUN: -c %s 2>&1 | FileCheck -check-prefixes=CHK-PHASES-NORDC-ARCHS %s
-// CHK-PHASES-NORDC-ARCHS: 7: offload, "device-sycl (spirv64-unknown-unknown:bmg_g21)" {6}, ir
-// CHK-PHASES-NORDC-ARCHS: 12: offload, "device-sycl (spirv64-unknown-unknown:generic)" {11}, ir
+// CHK-PHASES-NORDC-ARCHS: 7: offload, "device-sycl (spirv64-unknown-unknown:generic)" {6}, ir
+// CHK-PHASES-NORDC-ARCHS: 12: offload, "device-sycl (spirv64-unknown-unknown:xe-bmg-g21)" {11}, ir
// CHK-PHASES-NORDC-ARCHS-NEXT: 13: llvm-offload-binary, {7, 12}, image, (device-sycl)
// CHK-PHASES-NORDC-ARCHS-NEXT: 14: clang-linker-wrapper, {13}, sycl-fatbin, (device-sycl)
+/// Every spelling of an Intel GPU names one architecture, spelled canonically,
+/// so several spellings of one device build it once.
+// RUN: %clang -ccc-print-phases --target=x86_64-unknown-linux-gnu -fsycl \
+// RUN: --offload-targets=spirv64-unknown-unknown --offload-arch=bmg_g21 \
+// RUN: --offload-arch=xe-bmg-g21 --offload-arch=xe_20.1.0 -c %s 2>&1 \
+// RUN: | FileCheck -check-prefixes=CHK-INTEL-SPELLINGS %s
+// CHK-INTEL-SPELLINGS-NOT: offload, "device-sycl
+// CHK-INTEL-SPELLINGS: offload, "device-sycl (spirv64-unknown-unknown:xe-bmg-g21)"
+// CHK-INTEL-SPELLINGS-NOT: offload, "device-sycl
+
+/// Products built on one GPU IP version are one architecture too.
+// RUN: %clang -ccc-print-phases --target=x86_64-unknown-linux-gnu -fsycl \
+// RUN: --offload-targets=spirv64-unknown-unknown --offload-arch=xe-arl-u \
+// RUN: --offload-arch=xe-mtl-u --offload-arch=xe_12.70 -c %s 2>&1 \
+// RUN: | FileCheck -check-prefixes=CHK-INTEL-SAME-IP %s
+// CHK-INTEL-SAME-IP-NOT: offload, "device-sycl
+// CHK-INTEL-SAME-IP: offload, "device-sycl (spirv64-unknown-unknown:xe-mtl-u)"
+// CHK-INTEL-SAME-IP-NOT: offload, "device-sycl
+
+/// Removing any spelling of a device removes the device.
+// RUN: %clang -ccc-print-phases --target=x86_64-unknown-linux-gnu -fsycl \
+// RUN: --offload-targets=spirv64-unknown-unknown --offload-arch=xe-bmg-g21 \
+// RUN: --offload-arch=generic --no-offload-arch=bmg_g21 -c %s 2>&1 \
+// RUN: | FileCheck -check-prefixes=CHK-INTEL-NO-ARCH %s
+// RUN: %clang -ccc-print-phases --target=x86_64-unknown-linux-gnu -fsycl \
+// RUN: --offload-targets=spirv64-unknown-unknown --offload-arch=bmg_g21 \
+// RUN: --offload-arch=generic --no-offload-arch=xe_20.1.0 -c %s 2>&1 \
+// RUN: | FileCheck -check-prefixes=CHK-INTEL-NO-ARCH %s
+// CHK-INTEL-NO-ARCH-NOT: bmg
+// CHK-INTEL-NO-ARCH: offload, "device-sycl (spirv64-unknown-unknown:generic)"
+// CHK-INTEL-NO-ARCH-NOT: bmg
+
+/// An Intel GPU name takes no target-ID features, so a suffix is not dropped to
+/// turn the name into a device.
+// RUN: %clang -ccc-print-phases --target=x86_64-unknown-linux-gnu -fsycl \
+// RUN: --offload-targets=spirv64-unknown-unknown --offload-arch=xe-pvc:foo -c %s 2>&1 \
+// RUN: | FileCheck -check-prefixes=CHK-INTEL-SUFFIX %s
+// CHK-INTEL-SUFFIX: offload, "device-sycl (spirv64-unknown-unknown:xe-pvc:foo)"
+
+/// -Xarch_ may name an Intel GPU by any of its spellings.
+// RUN: %clang -### --target=x86_64-unknown-linux-gnu -fsycl \
+// RUN: --offload-targets=spirv64-unknown-unknown --offload-arch=bmg_g21 \
+// RUN: -Xarch_bmg_g21 -DBMG -Xarch_xe-pvc -DPVC -c %s 2>&1 \
+// RUN: | FileCheck -check-prefixes=CHK-INTEL-XARCH %s
+// CHK-INTEL-XARCH: "-fsycl-is-device"
+// CHK-INTEL-XARCH-SAME: "-D" "BMG"
+// CHK-INTEL-XARCH-NOT: "PVC"
+
+/// A static library's device code is requested by the canonical name.
+// RUN: %clang -### --target=x86_64-unknown-linux-gnu -fsycl \
+// RUN: --offload-targets=spirv64-unknown-unknown --offload-arch=bmg_g21 %s 2>&1 \
+// RUN: | FileCheck -check-prefixes=CHK-INTEL-EXTRACT %s
+// RUN: %clang -### --target=x86_64-unknown-linux-gnu -fsycl \
+// RUN: --offload-targets=spirv64-unknown-unknown --offload-arch=xe_20.1.0 %s 2>&1 \
+// RUN: | FileCheck -check-prefixes=CHK-INTEL-EXTRACT %s
+// CHK-INTEL-EXTRACT: clang-linker-wrapper{{.*}}"--should-extract=xe-bmg-g21"
+
/// Multiple device triples are not supported today in non-RDC mode.
// RUN: not %clang -### --target=x86_64-unknown-linux-gnu -fsycl -fno-gpu-rdc \
// RUN: --offload-targets=spirv64-unknown-unknown,spirv32-unknown-unknown -c %s 2>&1 \
diff --git a/clang/test/Misc/target-invalid-cpu-note/nvptx.c b/clang/test/Misc/target-invalid-cpu-note/nvptx.c
index 20dbd8dc6aa3b..b2a38b6b26825 100644
--- a/clang/test/Misc/target-invalid-cpu-note/nvptx.c
+++ b/clang/test/Misc/target-invalid-cpu-note/nvptx.c
@@ -2,6 +2,10 @@
// previous check finished matching (specifically, caret is not treated as
// matching a start of line when used like this in FileCheck).
+// An Intel GPU name is an offload architecture but never an NVPTX CPU.
+// RUN: not %clang_cc1 -triple nvptx64-nvidia-cuda -target-cpu xe-pvc -fsyntax-only %s 2>&1 | FileCheck %s --check-prefix=INTEL
+// INTEL: error: unknown target CPU 'xe-pvc'
+
// RUN: not %clang_cc1 -triple nvptx--- -target-cpu not-a-cpu -fsyntax-only %s 2>&1 | FileCheck %s --implicit-check-not={{[a-zA-Z0-9]}}
// CHECK: error: unknown target CPU 'not-a-cpu'
// CHECK-NEXT: note: valid target CPU values are:
diff --git a/clang/test/OffloadTools/clang-sycl-linker/basic.ll b/clang/test/OffloadTools/clang-sycl-linker/basic.ll
index 0ba81f61005a4..0376e7bf88338 100644
--- a/clang/test/OffloadTools/clang-sycl-linker/basic.ll
+++ b/clang/test/OffloadTools/clang-sycl-linker/basic.ll
@@ -115,9 +115,20 @@
; AOT-INTEL-GPU: link: inputs: {{.*}}.bc, {{.*}}.bc output: [[LLVMLINKOUT:.*]].bc
; AOT-INTEL-GPU-NEXT: LLVM backend: input: [[LLVMLINKOUT]].bc, output: [[SPVSTEM:.*]].spv
; AOT-INTEL-GPU-NEXT: "{{.*}}ocloc{{.*}}" {{.*}}-device bmg_g21 -a -b {{.*}}-output [[SPVSTEM]].out -file [[SPVSTEM]].spv
-; AOT-INTEL-GPU-NEXT: sycl-bundle: image kind: o, triple: spirv64, arch: bmg_g21
+; AOT-INTEL-GPU-NEXT: sycl-bundle: image kind: o, triple: spirv64, arch: xe-bmg-g21
; AOT-INTEL-GPU-NOT: {{.+}}
;
+; Test that every accepted spelling of an Intel GPU reaches ocloc as ocloc's own.
+; RUN: clang-sycl-linker --dry-run -v --module-split-mode=link_unit -arch=xe-bmg-g21 %t/input1.bc -o %t/aot-gpu.out 2>&1 \
+; RUN: | FileCheck %s --check-prefix=AOT-INTEL-NAME
+; RUN: clang-sycl-linker --dry-run -v --module-split-mode=link_unit -arch=xe_20.1.0 %t/input1.bc -o %t/aot-gpu.out 2>&1 \
+; RUN: | FileCheck %s --check-prefix=AOT-INTEL-NAME
+; AOT-INTEL-NAME: "{{.*}}ocloc{{.*}}" {{.*}}-device bmg_g21 {{.*}}-output
+; AOT-INTEL-NAME: sycl-bundle: image kind: o, triple: spirv64, arch: xe-bmg-g21
+; RUN: clang-sycl-linker --dry-run -v --module-split-mode=link_unit -arch=xe-pvc %t/input1.bc -o %t/aot-gpu.out 2>&1 \
+; RUN: | FileCheck %s --check-prefix=AOT-INTEL-PVC
+; AOT-INTEL-PVC: "{{.*}}ocloc{{.*}}" {{.*}}-device pvc {{.*}}-output
+
; Test that all --ocloc-options are passed to ocloc, even if they contain spaces or quotes.
; RUN: clang-sycl-linker --dry-run -v --module-split-mode=link_unit -arch=bmg_g21 %t/input1.bc -o %t/aot-gpu.out 2>&1 \
; RUN: --ocloc-options="-a -b" --ocloc-options=-c --ocloc-options="d" --ocloc-options='"-e -f"' \
diff --git a/clang/tools/clang-sycl-linker/ClangSYCLLinker.cpp b/clang/tools/clang-sycl-linker/ClangSYCLLinker.cpp
index 60ab7dc4e2a7d..01463c15aa0db 100644
--- a/clang/tools/clang-sycl-linker/ClangSYCLLinker.cpp
+++ b/clang/tools/clang-sycl-linker/ClangSYCLLinker.cpp
@@ -716,8 +716,15 @@ static Error runAOTCompileIntelGPU(StringRef InputFile, StringRef OutputFile,
StringRef Arch(Args.getLastArgValue(OPT_arch_EQ));
assert(!Arch.empty() && "Arch must be specified for AOT compilation");
+ // ocloc spells a device without the "xe-" prefix and with "_" between words,
+ // e.g. "bmg_g21" for "xe-bmg-g21", so translate any accepted spelling.
+ StringRef Canonical = OffloadArchToString(StringToOffloadArch(Arch));
+ [[maybe_unused]] bool HasPrefix = Canonical.consume_front("xe-");
+ assert(HasPrefix && "Intel GPU name without the xe- prefix");
+ std::string Device = Canonical.str();
+ llvm::replace(Device, '-', '_');
CmdArgs.push_back("-device");
- CmdArgs.push_back(Arch);
+ CmdArgs.push_back(Device);
// getAllArgValues returns a temporary vector; retain it so the StringRefs
// remain valid through the executeCommands call below.
@@ -1045,8 +1052,12 @@ static Error runSYCLLink(ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs,
TheImage.TheOffloadKind = OFK_SYCL;
TheImage.StringData["triple"] =
Args.MakeArgString(Result.TargetTriple.str());
+ // Label an Intel GPU image with its canonical name, whichever spelling was
+ // given, so that one device's images always carry one arch.
+ StringRef Arch = Args.getLastArgValue(OPT_arch_EQ);
+ OffloadArch OA = StringToOffloadArch(Arch);
TheImage.StringData["arch"] =
- Args.MakeArgString(Args.getLastArgValue(OPT_arch_EQ));
+ OA.isIntelGPU() ? OffloadArchToString(OA) : Args.MakeArgString(Arch);
TheImage.StringData["symbols"] = SI.Symbols;
TheImage.Image = std::move(*FileOrErr);
Images.emplace_back(std::move(TheImage));
diff --git a/clang/unittests/Basic/OffloadArchTest.cpp b/clang/unittests/Basic/OffloadArchTest.cpp
index 013ed75fbd57e..980a88aba6114 100644
--- a/clang/unittests/Basic/OffloadArchTest.cpp
+++ b/clang/unittests/Basic/OffloadArchTest.cpp
@@ -36,10 +36,12 @@ TEST(OffloadArchTest, TargetArchClassification) {
EXPECT_TRUE(IntelCPU.isIntelCPU());
EXPECT_FALSE(IntelCPU.isIntelGPU());
- OffloadArch IntelGPU = parse("bmg_g21");
+ OffloadArch IntelGPU = parse("xe-bmg-g21");
EXPECT_TRUE(IntelGPU.isIntel());
EXPECT_FALSE(IntelGPU.isIntelCPU());
EXPECT_TRUE(IntelGPU.isIntelGPU());
+ EXPECT_TRUE(parse("xe-dg2").isIntelGPU());
+ EXPECT_TRUE(parse("xe_12.60.7").isIntelGPU());
OffloadArch Generic = parse("generic");
EXPECT_FALSE(Generic.isNVPTX());
@@ -57,13 +59,30 @@ TEST(OffloadArchTest, Unknown) {
TEST(OffloadArchTest, RoundTrip) {
for (const char *Name :
{"sm_52", "sm_90a", "gfx906", "gfx1201", "gfx12-generic", "amdgcnspirv",
- "graniterapids", "bmg_g21", "generic"}) {
+ "graniterapids", "xe-bmg-g21", "xe-pvc", "xe-dg2", "generic"}) {
OffloadArch A = parse(Name);
EXPECT_FALSE(A.isUnknown()) << Name;
EXPECT_STREQ(OffloadArchToString(A), Name);
}
}
+// A spelling that is not the architecture name still denotes the device, and
+// canonicalizes to that name rather than round-tripping to itself.
+TEST(OffloadArchTest, IntelGPUAliases) {
+ // An alias, here the spelling accepted before the Intel GPU list existed.
+ EXPECT_EQ(parse("bmg_g21"), parse("xe-bmg-g21"));
+ // A numeric name, whose revision takes no part in the lookup.
+ EXPECT_EQ(parse("xe_12.60.0"), parse("xe-pvc"));
+ EXPECT_EQ(parse("xe_12.60.7"), parse("xe-pvc"));
+ EXPECT_EQ(parse("xe_12.60"), parse("xe-pvc"));
+ EXPECT_STREQ(OffloadArchToString(parse("bmg_g21")), "xe-bmg-g21");
+ EXPECT_STREQ(OffloadArchToString(parse("xe_12.60.7")), "xe-pvc");
+
+ // A well-formed numeric name for a device this build does not know is as
+ // unknown as any other unknown name.
+ EXPECT_TRUE(parse("xe_99.99.0").isUnknown());
+}
+
TEST(OffloadArchTest, Defaults) {
EXPECT_STREQ(OffloadArchToString(OffloadArch::CudaDefault()), "sm_52");
EXPECT_STREQ(OffloadArchToString(OffloadArch::HIPDefault()), "gfx906");
diff --git a/llvm/include/llvm/TargetParser/IntelGPUTargetParser.def b/llvm/include/llvm/TargetParser/IntelGPUTargetParser.def
index bd3b0a4634e06..c8faba2a11e1b 100644
--- a/llvm/include/llvm/TargetParser/IntelGPUTargetParser.def
+++ b/llvm/include/llvm/TargetParser/IntelGPUTargetParser.def
@@ -21,7 +21,9 @@
// IGCA_FEATURE_SETS - Token naming the IGCA feature sets the device
// implements: Core (none), Compute ("c"),
// Render ("r"), ComputeExact ("ca") or
-// RenderExact ("ra").
+// RenderExact ("ra"). It is a token rather than the
+// suffix itself so that a typo is a build error;
+// getIGCAName maps it onto the spelling.
//
// INTEL_GPU_COMPAT(NAME, KIND, IGCA_TARGET, IGCA_FEATURE_SETS)
// A compatibility name that covers several minor versions, e.g. "xe-dg2",
@@ -30,12 +32,28 @@
// offload-arch utility never prints one, but they are legal --offload-arch
// values. The columns mean the same as above.
//
+// INTEL_GPU_ALIAS(NAME, KIND)
+// A further name for a device that already has a row: "bmg_g21", which
+// --offload-arch accepted before the list existed, or another product
+// built on the same GPU IP version, e.g. "xe-arl-u" for "xe-mtl-u". Code
+// for one GPU IP version is the same whichever product runs it, so these
+// are one architecture. An alias declares no kind of its own and is never
+// printed, so a device keeps one canonical name; it only widens what
+// --offload-arch accepts.
+//
// A device is keyed by its major and minor version alone. The revision
// component of the GPU IP version is deliberately left out of the key, so that
// every revision of a device shares one name and one IGCA target.
//
-// 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.
+// Products that share a major and a minor version form one INTEL_GPU row, named
+// after the product the offload-arch utility prints; the other products are
+// aliases. The exception is "xe-pvc-sdv": it has the same major and minor
+// version as "xe-pvc", but the AOT compiler generates different code for it, so
+// it gets its own row.
+//
+// Devices without a published name are left out on purpose; offload-arch names
+// them by GPU IP version, as "xe_*.*.*". A device gets a row only once it has
+// an official name.
//
//===----------------------------------------------------------------------===//
@@ -46,10 +64,7 @@
INTEL_GPU("xe-cri", XE_CRI, 35, 11, 60, Compute)
INTEL_GPU("xe-nvl-p", XE_NVL_P, 35, 10, 60, Render)
INTEL_GPU("xe-nvl-u", XE_NVL_U, 30, 5, 60, Render)
-INTEL_GPU("xe-nvl-h", XE_NVL_H, 30, 5, 60, Render)
INTEL_GPU("xe-nvl-s", XE_NVL_S, 30, 4, 60, Render)
-INTEL_GPU("xe-nvl-hx", XE_NVL_HX, 30, 4, 60, Render)
-INTEL_GPU("xe-nvl-ul", XE_NVL_UL, 30, 4, 60, Render)
INTEL_GPU("xe-wcl", XE_WCL, 30, 3, 50, Render)
INTEL_GPU("xe-ptl-u", XE_PTL_U, 30, 1, 50, Render)
INTEL_GPU("xe-ptl-h", XE_PTL_H, 30, 0, 50, Render)
@@ -59,28 +74,18 @@ INTEL_GPU("xe-bmg-g21", XE_BMG_G21, 20, 1, 40, Render)
INTEL_GPU("xe-arl-h", XE_ARL_H, 12, 74, 35, Render)
INTEL_GPU("xe-mtl-h", XE_MTL_H, 12, 71, 30, Render)
INTEL_GPU("xe-mtl-u", XE_MTL_U, 12, 70, 30, Render)
-INTEL_GPU("xe-arl-u", XE_ARL_U, 12, 70, 30, Render)
-INTEL_GPU("xe-arl-s", XE_ARL_S, 12, 70, 30, Render)
INTEL_GPU("xe-pvc-vg", XE_PVC_VG, 12, 61, 20, ComputeExact)
INTEL_GPU("xe-pvc", XE_PVC, 12, 60, 20, ComputeExact)
INTEL_GPU("xe-pvc-sdv", XE_PVC_SDV, 12, 60, 20, ComputeExact)
INTEL_GPU("xe-acm-g12", XE_ACM_G12, 12, 57, 15, RenderExact)
-INTEL_GPU("xe-dg2-g12", XE_DG2_G12, 12, 57, 15, RenderExact)
INTEL_GPU("xe-acm-g11", XE_ACM_G11, 12, 56, 15, RenderExact)
-INTEL_GPU("xe-dg2-g11", XE_DG2_G11, 12, 56, 15, RenderExact)
-INTEL_GPU("xe-ats-m75", XE_ATS_M75, 12, 56, 15, RenderExact)
INTEL_GPU("xe-acm-g10", XE_ACM_G10, 12, 55, 15, RenderExact)
-INTEL_GPU("xe-dg2-g10", XE_DG2_G10, 12, 55, 15, RenderExact)
-INTEL_GPU("xe-ats-m150", XE_ATS_M150, 12, 55, 15, RenderExact)
INTEL_GPU("xe-dg1", XE_DG1, 12, 10, 10, Render)
INTEL_GPU("xe-adl-n", XE_ADL_N, 12, 4, 10, Render)
INTEL_GPU("xe-adl-p", XE_ADL_P, 12, 3, 10, Render)
-INTEL_GPU("xe-rpl-p", XE_RPL_P, 12, 3, 10, Render)
INTEL_GPU("xe-adl-s", XE_ADL_S, 12, 2, 10, Render)
-INTEL_GPU("xe-rpl-s", XE_RPL_S, 12, 2, 10, Render)
INTEL_GPU("xe-rkl", XE_RKL, 12, 1, 10, Render)
INTEL_GPU("xe-tgllp", XE_TGLLP, 12, 0, 10, Render)
-INTEL_GPU("xe-tgl", XE_TGL, 12, 0, 10, Render)
// Compatibility names, which cover a group of platforms
#ifndef INTEL_GPU_COMPAT
@@ -92,5 +97,27 @@ 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)
+// Aliases, which are further names of a device named above
+#ifndef INTEL_GPU_ALIAS
+#define INTEL_GPU_ALIAS(NAME, KIND)
+#endif
+
+// Accepted before this list existed; to be removed in favor of "xe-bmg-g21".
+INTEL_GPU_ALIAS("bmg_g21", XE_BMG_G21)
+INTEL_GPU_ALIAS("xe-nvl-h", XE_NVL_U)
+INTEL_GPU_ALIAS("xe-nvl-hx", XE_NVL_S)
+INTEL_GPU_ALIAS("xe-nvl-ul", XE_NVL_S)
+INTEL_GPU_ALIAS("xe-arl-u", XE_MTL_U)
+INTEL_GPU_ALIAS("xe-arl-s", XE_MTL_U)
+INTEL_GPU_ALIAS("xe-dg2-g12", XE_ACM_G12)
+INTEL_GPU_ALIAS("xe-dg2-g11", XE_ACM_G11)
+INTEL_GPU_ALIAS("xe-ats-m75", XE_ACM_G11)
+INTEL_GPU_ALIAS("xe-dg2-g10", XE_ACM_G10)
+INTEL_GPU_ALIAS("xe-ats-m150", XE_ACM_G10)
+INTEL_GPU_ALIAS("xe-rpl-p", XE_ADL_P)
+INTEL_GPU_ALIAS("xe-rpl-s", XE_ADL_S)
+INTEL_GPU_ALIAS("xe-tgl", XE_TGLLP)
+
#undef INTEL_GPU
#undef INTEL_GPU_COMPAT
+#undef INTEL_GPU_ALIAS
diff --git a/llvm/include/llvm/TargetParser/IntelGPUTargetParser.h b/llvm/include/llvm/TargetParser/IntelGPUTargetParser.h
index 4ae635e97167b..8713de9579b48 100644
--- a/llvm/include/llvm/TargetParser/IntelGPUTargetParser.h
+++ b/llvm/include/llvm/TargetParser/IntelGPUTargetParser.h
@@ -6,10 +6,8 @@
//
//===----------------------------------------------------------------------===//
//
-// This file provides access to the Intel GPU list in IntelGPUTargetParser.def.
-// Only what is needed to name the device a driver reports is declared here; the
-// table itself carries more, and a consumer that needs the rest either declares
-// it here as well or expands the table directly.
+// This file names the Intel GPU a driver reports, and finds the Intel GPU a
+// user names.
//
//===----------------------------------------------------------------------===//
@@ -22,10 +20,15 @@
#include <string>
namespace llvm {
+template <typename T> class SmallVectorImpl;
+
namespace IntelGPU {
/// Intel GPU architecture names, covering both physical devices and the
/// compatibility names that stand for a whole product line.
+///
+/// The underlying type is fixed because clang/Basic/OffloadArch.h forward
+/// declares this enumeration; the two declarations have to agree.
enum GPUKind : uint8_t {
GK_NONE = 0,
#define INTEL_GPU(NAME, KIND, MAJOR, MINOR, IGCA_TARGET, IGCA_FEATURE_SETS) \
@@ -44,6 +47,36 @@ 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);
+/// \return the human-friendly name of \p Kind, e.g. "xe-pvc", or an empty
+/// string for GK_NONE.
+LLVM_ABI StringRef getArchName(GPUKind Kind);
+
+/// \return the device \p Name denotes, or GK_NONE for a name this build does
+/// not know.
+///
+/// Every spelling the user may write is accepted: a human-friendly name such as
+/// "xe-pvc", a compatibility name such as "xe-dg2", an alias such as "bmg_g21",
+/// and a numeric name such as "xe_12.60.7". Only the human-friendly name is
+/// reported back for a device, so a spelling that is not one canonicalizes to
+/// the one that is. The revision of a numeric name takes no part in the lookup,
+/// just as it takes none in getArchName, so "xe_12.60.0" and "xe_12.60.7" name
+/// the same device; the revision may also be omitted. A numeric name for a
+/// device that is not in the table yields GK_NONE like any other unknown name.
+LLVM_ABI GPUKind parseArch(StringRef Name);
+
+/// \return the IGCA target name to compile \p Kind for, e.g. "xe-pvc" ->
+/// "igca_20ca", or an empty string for GK_NONE. This is the spelling
+/// -target-cpu is invoked with.
+///
+/// The name is the numeric IGCA target followed by the suffix of the feature
+/// sets: igca_60 is the core features, igca_60c adds the compute features, and
+/// igca_60ca is exact, meaning that only a device at that target will do.
+LLVM_ABI StringRef getIGCAName(GPUKind Kind);
+
+/// Append every architecture name this build accepts, for diagnostics that
+/// offer the user an alternative to a name that did not parse.
+LLVM_ABI void fillValidArchList(SmallVectorImpl<StringRef> &Values);
+
} // namespace IntelGPU
} // namespace llvm
diff --git a/llvm/lib/TargetParser/IntelGPUTargetParser.cpp b/llvm/lib/TargetParser/IntelGPUTargetParser.cpp
index 4b4d162ffbfff..044daddc868f1 100644
--- a/llvm/lib/TargetParser/IntelGPUTargetParser.cpp
+++ b/llvm/lib/TargetParser/IntelGPUTargetParser.cpp
@@ -11,8 +11,12 @@
//===----------------------------------------------------------------------===//
#include "llvm/TargetParser/IntelGPUTargetParser.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Twine.h"
+#include "llvm/Support/ErrorHandling.h"
#include <cassert>
+#include <tuple>
using namespace llvm;
using namespace IntelGPU;
@@ -28,7 +32,7 @@ using namespace IntelGPU;
// The reserved bits carry no information.
static constexpr uint32_t GPUIPMajorShift = 22;
static constexpr uint32_t GPUIPMinorShift = 14;
-[[maybe_unused]] static constexpr uint32_t GPUIPMajorMask = 0x3ff;
+static constexpr uint32_t GPUIPMajorMask = 0x3ff;
static constexpr uint32_t GPUIPMinorMask = 0xff;
static constexpr uint32_t GPUIPRevisionMask = 0x3f;
@@ -47,13 +51,20 @@ static constexpr uint32_t packDevice(uint32_t Major, uint32_t Minor) {
return (Major << GPUIPMajorShift) | (Minor << GPUIPMinorShift);
}
-StringRef llvm::IntelGPU::getArchName(uint32_t GPUIPVersion) {
+// The device that \p GPUIPVersion identifies, or GK_NONE if the table lists
+// none. Only INTEL_GPU rows are expanded, so a compatibility name can never
+// match.
+static GPUKind getKindForVersion(uint32_t GPUIPVersion) {
const uint32_t Device = GPUIPVersion & GPUIPDeviceMask;
#define INTEL_GPU(NAME, KIND, MAJOR, MINOR, IGCA_TARGET, IGCA_FEATURE_SETS) \
if (Device == packDevice(MAJOR, MINOR)) \
- return NAME;
+ return GK_##KIND;
#include "llvm/TargetParser/IntelGPUTargetParser.def"
- return "";
+ return GK_NONE;
+}
+
+StringRef llvm::IntelGPU::getArchName(uint32_t GPUIPVersion) {
+ return getArchName(getKindForVersion(GPUIPVersion));
}
std::string llvm::IntelGPU::getNumericArchName(uint32_t GPUIPVersion) {
@@ -63,3 +74,111 @@ std::string llvm::IntelGPU::getNumericArchName(uint32_t GPUIPVersion) {
return ("xe_" + Twine(Major) + "." + Twine(Minor) + "." + Twine(Revision))
.str();
}
+
+StringRef llvm::IntelGPU::getArchName(GPUKind Kind) {
+ switch (Kind) {
+ case GK_NONE:
+ return "";
+#define INTEL_GPU(NAME, KIND, MAJOR, MINOR, IGCA_TARGET, IGCA_FEATURE_SETS) \
+ case GK_##KIND: \
+ return NAME;
+#define INTEL_GPU_COMPAT(NAME, KIND, IGCA_TARGET, IGCA_FEATURE_SETS) \
+ case GK_##KIND: \
+ return NAME;
+#include "llvm/TargetParser/IntelGPUTargetParser.def"
+ }
+ llvm_unreachable("invalid Intel GPU GPUKind");
+}
+
+// Read a numeric architecture name, e.g. "xe_12.60.7", into the GPU IP version
+// it spells. The revision may be omitted, since it takes no part in a lookup
+// either way. Anything else is not a numeric name, which is not the same as
+// naming no device: a caller distinguishes the two by whether this succeeds.
+static bool parseNumericArchName(StringRef Name, uint32_t &GPUIPVersion) {
+ if (!Name.consume_front("xe_"))
+ return false;
+
+ StringRef MajorStr, MinorStr, RevisionStr;
+ std::tie(MajorStr, Name) = Name.split('.');
+ // The revision may be omitted, but a separator with no revision after it is
+ // malformed rather than an omitted revision.
+ const bool HasRevision = Name.contains('.');
+ std::tie(MinorStr, RevisionStr) = Name.split('.');
+ uint32_t Major, Minor, Revision = 0;
+ if (MajorStr.getAsInteger(10, Major) || MinorStr.getAsInteger(10, Minor))
+ return false;
+ if (HasRevision && RevisionStr.getAsInteger(10, Revision))
+ return false;
+
+ // A field too wide for the GPU IP version it spells describes no GPU that
+ // could ever report it, so this is not a numeric name rather than one naming
+ // no device.
+ if (Major > GPUIPMajorMask || Minor > GPUIPMinorMask ||
+ Revision > GPUIPRevisionMask)
+ return false;
+ GPUIPVersion = packDevice(Major, Minor) | Revision;
+ return true;
+}
+
+GPUKind llvm::IntelGPU::parseArch(StringRef Name) {
+ GPUKind Kind = StringSwitch<GPUKind>(Name)
+#define INTEL_GPU(NAME, KIND, MAJOR, MINOR, IGCA_TARGET, IGCA_FEATURE_SETS) \
+ .Case(NAME, GK_##KIND)
+#define INTEL_GPU_COMPAT(NAME, KIND, IGCA_TARGET, IGCA_FEATURE_SETS) \
+ .Case(NAME, GK_##KIND)
+#define INTEL_GPU_ALIAS(NAME, KIND) .Case(NAME, GK_##KIND)
+#include "llvm/TargetParser/IntelGPUTargetParser.def"
+ .Default(GK_NONE);
+ if (Kind != GK_NONE)
+ return Kind;
+
+ // A device with no human-friendly name is spelled numerically, so the same
+ // lookup the driver does for a reported GPU IP version has to be reachable by
+ // name.
+ uint32_t GPUIPVersion;
+ if (parseNumericArchName(Name, GPUIPVersion))
+ return getKindForVersion(GPUIPVersion);
+ return GK_NONE;
+}
+
+// The suffix each IGCA_FEATURE_SETS token contributes to a target name.
+#define IGCA_FEATURE_SETS_Core ""
+#define IGCA_FEATURE_SETS_Compute "c"
+#define IGCA_FEATURE_SETS_Render "r"
+#define IGCA_FEATURE_SETS_ComputeExact "ca"
+#define IGCA_FEATURE_SETS_RenderExact "ra"
+
+StringRef llvm::IntelGPU::getIGCAName(GPUKind Kind) {
+ // Unlike the NVPTX virtual architecture name, this is not a column of its
+ // own: the target and the feature sets already spell it, and a column would
+ // let the three disagree.
+ switch (Kind) {
+ case GK_NONE:
+ return "";
+#define INTEL_GPU(NAME, KIND, MAJOR, MINOR, IGCA_TARGET, IGCA_FEATURE_SETS) \
+ case GK_##KIND: \
+ return "igca_" #IGCA_TARGET IGCA_FEATURE_SETS_##IGCA_FEATURE_SETS;
+#define INTEL_GPU_COMPAT(NAME, KIND, IGCA_TARGET, IGCA_FEATURE_SETS) \
+ case GK_##KIND: \
+ return "igca_" #IGCA_TARGET IGCA_FEATURE_SETS_##IGCA_FEATURE_SETS;
+#include "llvm/TargetParser/IntelGPUTargetParser.def"
+ }
+ llvm_unreachable("invalid Intel GPU GPUKind");
+}
+
+#undef IGCA_FEATURE_SETS_Core
+#undef IGCA_FEATURE_SETS_Compute
+#undef IGCA_FEATURE_SETS_Render
+#undef IGCA_FEATURE_SETS_ComputeExact
+#undef IGCA_FEATURE_SETS_RenderExact
+
+void llvm::IntelGPU::fillValidArchList(SmallVectorImpl<StringRef> &Values) {
+ // An alias is a name the user may write, so it belongs here even though it is
+ // never the name reported for a device.
+#define INTEL_GPU(NAME, KIND, MAJOR, MINOR, IGCA_TARGET, IGCA_FEATURE_SETS) \
+ Values.push_back(NAME);
+#define INTEL_GPU_COMPAT(NAME, KIND, IGCA_TARGET, IGCA_FEATURE_SETS) \
+ Values.push_back(NAME);
+#define INTEL_GPU_ALIAS(NAME, KIND) Values.push_back(NAME);
+#include "llvm/TargetParser/IntelGPUTargetParser.def"
+}
diff --git a/llvm/unittests/TargetParser/IntelGPUTargetParserTest.cpp b/llvm/unittests/TargetParser/IntelGPUTargetParserTest.cpp
index ab8d456769d0d..147a3e3b4485c 100644
--- a/llvm/unittests/TargetParser/IntelGPUTargetParserTest.cpp
+++ b/llvm/unittests/TargetParser/IntelGPUTargetParserTest.cpp
@@ -7,6 +7,8 @@
//===----------------------------------------------------------------------===//
#include "llvm/TargetParser/IntelGPUTargetParser.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallVector.h"
#include "gtest/gtest.h"
#include <cassert>
@@ -78,4 +80,106 @@ TEST(IntelGPUTargetParserTest, NumericArchName) {
"xe_12.60.7");
}
+TEST(IntelGPUTargetParserTest, KindArchNames) {
+ EXPECT_EQ(IntelGPU::getArchName(IntelGPU::GK_XE_PVC), "xe-pvc");
+ EXPECT_EQ(IntelGPU::getArchName(IntelGPU::GK_XE_DG2), "xe-dg2");
+ EXPECT_EQ(IntelGPU::getArchName(IntelGPU::GK_NONE), "");
+}
+
+TEST(IntelGPUTargetParserTest, ParseArch) {
+ // A human-friendly name, a compatibility name, and an alias.
+ EXPECT_EQ(IntelGPU::parseArch("xe-pvc"), IntelGPU::GK_XE_PVC);
+ EXPECT_EQ(IntelGPU::parseArch("xe-dg2"), IntelGPU::GK_XE_DG2);
+ EXPECT_EQ(IntelGPU::parseArch("bmg_g21"), IntelGPU::GK_XE_BMG_G21);
+ // Products built on one GPU IP version are one device, named after the one
+ // the offload-arch utility prints.
+ EXPECT_EQ(IntelGPU::parseArch("xe-arl-u"), IntelGPU::GK_XE_MTL_U);
+ EXPECT_EQ(IntelGPU::parseArch("xe-ats-m150"), IntelGPU::GK_XE_ACM_G10);
+ EXPECT_EQ(IntelGPU::parseArch("xe_12.70"), IntelGPU::GK_XE_MTL_U);
+ // Except PVC-SDV, which the AOT compiler builds for its own stepping.
+ EXPECT_EQ(IntelGPU::parseArch("xe-pvc-sdv"), IntelGPU::GK_XE_PVC_SDV);
+
+ // A numeric name names the same device the driver would have reported.
+ EXPECT_EQ(IntelGPU::parseArch("xe_12.60.0"), IntelGPU::GK_XE_PVC);
+ // The revision takes no part in the lookup, and may be left out.
+ EXPECT_EQ(IntelGPU::parseArch("xe_12.60.7"), IntelGPU::GK_XE_PVC);
+ EXPECT_EQ(IntelGPU::parseArch("xe_12.60"), IntelGPU::GK_XE_PVC);
+ // A numeric name for a device this build does not know names no device.
+ EXPECT_EQ(IntelGPU::parseArch("xe_40.11.0"), IntelGPU::GK_NONE);
+
+ // Neither an empty name nor a malformed one names a device.
+ EXPECT_EQ(IntelGPU::parseArch(""), IntelGPU::GK_NONE);
+ EXPECT_EQ(IntelGPU::parseArch("pvc"), IntelGPU::GK_NONE);
+ EXPECT_EQ(IntelGPU::parseArch("xe_"), IntelGPU::GK_NONE);
+ EXPECT_EQ(IntelGPU::parseArch("xe_12"), IntelGPU::GK_NONE);
+ EXPECT_EQ(IntelGPU::parseArch("xe_12.pvc"), IntelGPU::GK_NONE);
+ EXPECT_EQ(IntelGPU::parseArch("xe_12.60.7.1"), IntelGPU::GK_NONE);
+ // A trailing separator is not an omitted revision.
+ EXPECT_EQ(IntelGPU::parseArch("xe_12.60."), IntelGPU::GK_NONE);
+ EXPECT_EQ(IntelGPU::parseArch("xe_12."), IntelGPU::GK_NONE);
+
+ // A field wider than the GPU IP version field it spells describes no GPU
+ // that could ever report it, so it names no device however well the rest of
+ // the name matches a row. The major version holds 10 bits, the minor 8, the
+ // revision 6.
+ EXPECT_EQ(IntelGPU::parseArch("xe_12.60.63"), IntelGPU::GK_XE_PVC);
+ EXPECT_EQ(IntelGPU::parseArch("xe_12.60.64"), IntelGPU::GK_NONE);
+ EXPECT_EQ(IntelGPU::parseArch("xe_12.256"), IntelGPU::GK_NONE);
+ EXPECT_EQ(IntelGPU::parseArch("xe_1024.60"), IntelGPU::GK_NONE);
+ // The widest values that fit name no row either.
+ EXPECT_EQ(IntelGPU::parseArch("xe_12.255"), IntelGPU::GK_NONE);
+ EXPECT_EQ(IntelGPU::parseArch("xe_1023.60"), IntelGPU::GK_NONE);
+ // Truncated to its field, each of these would name xe-pvc.
+ EXPECT_EQ(IntelGPU::parseArch("xe_12.316"), IntelGPU::GK_NONE);
+ EXPECT_EQ(IntelGPU::parseArch("xe_1036.60"), IntelGPU::GK_NONE);
+ // Wider than the whole version, so the integer itself does not fit.
+ EXPECT_EQ(IntelGPU::parseArch("xe_12.60.99999999999"), IntelGPU::GK_NONE);
+}
+
+TEST(IntelGPUTargetParserTest, EveryNameParses) {
+ // Every name the table declares has to be an --offload-arch value, and has to
+ // name the row it came from.
+#define INTEL_GPU(NAME, KIND, MAJOR, MINOR, IGCA_TARGET, IGCA_FEATURE_SETS) \
+ EXPECT_EQ(IntelGPU::parseArch(NAME), IntelGPU::GK_##KIND) << NAME;
+#define INTEL_GPU_COMPAT(NAME, KIND, IGCA_TARGET, IGCA_FEATURE_SETS) \
+ EXPECT_EQ(IntelGPU::parseArch(NAME), IntelGPU::GK_##KIND) << NAME;
+#define INTEL_GPU_ALIAS(NAME, KIND) \
+ EXPECT_EQ(IntelGPU::parseArch(NAME), IntelGPU::GK_##KIND) << NAME;
+#include "llvm/TargetParser/IntelGPUTargetParser.def"
+}
+
+TEST(IntelGPUTargetParserTest, AliasesAreNeverReported) {
+ // An alias declares no kind of its own, so the name reported for a device is
+ // the row's own name. A device with two spellings would otherwise depend on
+ // which one the table happened to reach first.
+#define INTEL_GPU_ALIAS(NAME, KIND) \
+ EXPECT_NE(IntelGPU::getArchName(IntelGPU::GK_##KIND), NAME) << NAME;
+#include "llvm/TargetParser/IntelGPUTargetParser.def"
+}
+
+TEST(IntelGPUTargetParserTest, IGCANames) {
+ // One of each suffix, since the target and the feature sets are pasted
+ // together.
+ EXPECT_EQ(IntelGPU::getIGCAName(IntelGPU::GK_XE_CRI), "igca_60c");
+ EXPECT_EQ(IntelGPU::getIGCAName(IntelGPU::GK_XE_NVL_P), "igca_60r");
+ EXPECT_EQ(IntelGPU::getIGCAName(IntelGPU::GK_XE_PVC), "igca_20ca");
+ EXPECT_EQ(IntelGPU::getIGCAName(IntelGPU::GK_XE_DG2), "igca_15ra");
+ EXPECT_EQ(IntelGPU::getIGCAName(IntelGPU::GK_NONE), "");
+}
+
+TEST(IntelGPUTargetParserTest, ValidArchList) {
+ SmallVector<StringRef> Values;
+ IntelGPU::fillValidArchList(Values);
+
+ EXPECT_FALSE(Values.empty());
+ EXPECT_NE(llvm::find(Values, "xe-pvc"), Values.end());
+ // A compatibility name and an alias are as valid as any other name.
+ EXPECT_NE(llvm::find(Values, "xe-dg2"), Values.end());
+ EXPECT_NE(llvm::find(Values, "bmg_g21"), Values.end());
+ // The list is offered to a user whose name did not parse, so every entry has
+ // to be a name that would have.
+ for (StringRef Value : Values)
+ EXPECT_NE(IntelGPU::parseArch(Value), IntelGPU::GK_NONE) << Value;
+}
+
} // namespace
>From c206cbf625c43d1aaeeef86eec221790838019bb Mon Sep 17 00:00:00 2001
From: srividya sundaram <srividya.sundaram at intel.com>
Date: Mon, 12 Oct 2026 15:10:29 -0700
Subject: [PATCH 2/3] [TargetParser] Simplify Intel GPU parser comments
Address review comments: say which typo the IGCA_FEATURE_SETS token catches,
note that xe-pvc and xe-pvc-sdv are the only rows sharing a version, and
shorten the parseArch comment.
Assisted-by: Claude Opus 5.5
---
.../llvm/TargetParser/IntelGPUTargetParser.def | 5 ++---
.../llvm/TargetParser/IntelGPUTargetParser.h | 16 ++++++----------
2 files changed, 8 insertions(+), 13 deletions(-)
diff --git a/llvm/include/llvm/TargetParser/IntelGPUTargetParser.def b/llvm/include/llvm/TargetParser/IntelGPUTargetParser.def
index c8faba2a11e1b..566045539c723 100644
--- a/llvm/include/llvm/TargetParser/IntelGPUTargetParser.def
+++ b/llvm/include/llvm/TargetParser/IntelGPUTargetParser.def
@@ -21,9 +21,8 @@
// IGCA_FEATURE_SETS - Token naming the IGCA feature sets the device
// implements: Core (none), Compute ("c"),
// Render ("r"), ComputeExact ("ca") or
-// RenderExact ("ra"). It is a token rather than the
-// suffix itself so that a typo is a build error;
-// getIGCAName maps it onto the spelling.
+// RenderExact ("ra"). It is a token, so a misspelled
+// one such as Compte fails to build.
//
// INTEL_GPU_COMPAT(NAME, KIND, IGCA_TARGET, IGCA_FEATURE_SETS)
// A compatibility name that covers several minor versions, e.g. "xe-dg2",
diff --git a/llvm/include/llvm/TargetParser/IntelGPUTargetParser.h b/llvm/include/llvm/TargetParser/IntelGPUTargetParser.h
index 8713de9579b48..1131ccf52e64c 100644
--- a/llvm/include/llvm/TargetParser/IntelGPUTargetParser.h
+++ b/llvm/include/llvm/TargetParser/IntelGPUTargetParser.h
@@ -40,8 +40,8 @@ enum GPUKind : uint8_t {
/// \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
-/// of a device resolves to the same name.
-/// If several rows match, the first one in IntelGPUTargetParser.def wins.
+/// of a device resolves to the same name. Only xe-pvc and xe-pvc-sdv share a
+/// version; xe-pvc is returned.
LLVM_ABI StringRef getArchName(uint32_t GPUIPVersion);
/// \return the numeric name of \p GPUIPVersion, e.g. "xe_35.11.0".
@@ -54,14 +54,10 @@ LLVM_ABI StringRef getArchName(GPUKind Kind);
/// \return the device \p Name denotes, or GK_NONE for a name this build does
/// not know.
///
-/// Every spelling the user may write is accepted: a human-friendly name such as
-/// "xe-pvc", a compatibility name such as "xe-dg2", an alias such as "bmg_g21",
-/// and a numeric name such as "xe_12.60.7". Only the human-friendly name is
-/// reported back for a device, so a spelling that is not one canonicalizes to
-/// the one that is. The revision of a numeric name takes no part in the lookup,
-/// just as it takes none in getArchName, so "xe_12.60.0" and "xe_12.60.7" name
-/// the same device; the revision may also be omitted. A numeric name for a
-/// device that is not in the table yields GK_NONE like any other unknown name.
+/// \p Name may be a human-friendly name ("xe-pvc"), a compatibility name
+/// ("xe-dg2"), an alias ("bmg_g21") or a numeric name ("xe_12.60.7"). The
+/// revision of a numeric name is ignored and may be omitted, so "xe_12.60",
+/// "xe_12.60.0" and "xe_12.60.7" all denote the same device.
LLVM_ABI GPUKind parseArch(StringRef Name);
/// \return the IGCA target name to compile \p Kind for, e.g. "xe-pvc" ->
>From 4f6c6b294342e5c61552439b4716082477bceb58 Mon Sep 17 00:00:00 2001
From: srividya sundaram <srividya.sundaram at intel.com>
Date: Mon, 12 Oct 2026 18:07:42 -0700
Subject: [PATCH 3/3] [TargetParser][Clang] Address review: one name per Intel
GPU
- Drop aliases: each Intel GPU has one name, plus its numeric name.
bmg_g21 is no longer accepted; use xe-bmg-g21.
- Remove getIGCAName and fillValidArchList until they have a user.
- Canonicalize Intel GPU names for every offload language, not just SYCL.
- Keep clang-sycl-linker's image label as given; the driver passes the
canonical name.
- Leave the NVPTX CPU check to a separate change.
- Move the Intel GPU driver tests to sycl-intel-gpu-arch.cpp.
Assisted-by: Claude Opus 5.5
---
clang/docs/ClangSYCLLinker.md | 2 +-
clang/docs/ReleaseNotes.md | 4 ++
clang/lib/Basic/Targets/NVPTX.h | 11 +---
clang/lib/Driver/Driver.cpp | 25 ++++----
clang/lib/Driver/ToolChain.cpp | 11 ++--
clang/lib/Driver/ToolChains/Clang.cpp | 5 +-
clang/test/Driver/sycl-intel-gpu-arch.cpp | 55 +++++++++++++++++
clang/test/Driver/sycl-offload-jit.cpp | 61 +------------------
.../test/Misc/target-invalid-cpu-note/nvptx.c | 4 --
.../OffloadTools/clang-sycl-linker/basic.ll | 9 ++-
.../clang-sycl-linker/ClangSYCLLinker.cpp | 8 +--
clang/unittests/Basic/OffloadArchTest.cpp | 12 ++--
.../TargetParser/IntelGPUTargetParser.def | 43 ++-----------
.../llvm/TargetParser/IntelGPUTargetParser.h | 26 ++------
.../lib/TargetParser/IntelGPUTargetParser.cpp | 46 +-------------
.../TargetParser/IntelGPUTargetParserTest.cpp | 49 ++-------------
16 files changed, 110 insertions(+), 261 deletions(-)
create mode 100644 clang/test/Driver/sycl-intel-gpu-arch.cpp
diff --git a/clang/docs/ClangSYCLLinker.md b/clang/docs/ClangSYCLLinker.md
index b4f5e751b03bb..c527afa8b41f6 100644
--- a/clang/docs/ClangSYCLLinker.md
+++ b/clang/docs/ClangSYCLLinker.md
@@ -105,7 +105,7 @@ linked device images that are ready to be wrapped and linked with host code to
generate the final executable.
```console
-clang-sycl-linker --triple spirv64 --arch bmg_g21 input.bc
+clang-sycl-linker --triple spirv64 --arch xe-bmg-g21 input.bc
```
### Linking with Device Libraries
diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 4465396bd6042..8fbca2642b617 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -1171,6 +1171,10 @@ The `alpha.cplusplus.UseAfterLifetimeEnd` checker was renamed to `alpha.core.Use
### SYCL Support
+- `--offload-arch` accepts the Intel GPU names from
+ `llvm/TargetParser/IntelGPUTargetParser.def`, e.g. `xe-pvc`, and their numeric
+ names, e.g. `xe_12.60.7`. `bmg_g21` is no longer accepted; use `xe-bmg-g21`.
+
#### Improvements
## Additional Information
diff --git a/clang/lib/Basic/Targets/NVPTX.h b/clang/lib/Basic/Targets/NVPTX.h
index 45ba8322cf5fc..b6d2bfd320103 100644
--- a/clang/lib/Basic/Targets/NVPTX.h
+++ b/clang/lib/Basic/Targets/NVPTX.h
@@ -135,13 +135,8 @@ class LLVM_LIBRARY_VISIBILITY NVPTXTargetInfo : public TargetInfo {
return TargetInfo::CharPtrBuiltinVaList;
}
- // StringToOffloadArch recognizes architectures from all vendors. Accept only
- // the ones NVPTX accepted before, so Sema does not accept an Intel GPU name
- // as an NVPTX CPU.
bool isValidCPUName(StringRef Name) const override {
- OffloadArch Arch = StringToOffloadArch(Name);
- return Arch.isNVPTX() || Arch.isAMDGPU() || Arch.isAMDGCNSPIRV() ||
- Arch.isGeneric() || Arch.isUnused();
+ return !StringToOffloadArch(Name).isUnknown();
}
void fillValidCPUList(SmallVectorImpl<StringRef> &Values) const override {
@@ -149,10 +144,8 @@ class LLVM_LIBRARY_VISIBILITY NVPTXTargetInfo : public TargetInfo {
}
bool setCPU(StringRef Name) override {
- if (!isValidCPUName(Name))
- return false;
GPU = StringToOffloadArch(Name);
- return true;
+ return !GPU.isUnknown();
}
void setSupportedOpenCLOpts() override {
diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp
index bbcf88d823776..d48d5339f1934 100644
--- a/clang/lib/Driver/Driver.cpp
+++ b/clang/lib/Driver/Driver.cpp
@@ -3898,19 +3898,17 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
Args.ClaimAllArgs(options::OPT_cl_ignored_Group);
}
-/// Returns the canonical name for the offloading architecture when using a HIP
-/// or CUDA architecture, or an Intel GPU for SYCL.
+/// Returns the canonical name for the offloading architecture when using a HIP,
+/// CUDA or Intel GPU architecture.
static StringRef getCanonicalArchString(Compilation &C,
const llvm::opt::DerivedArgList &Args,
StringRef ArchStr,
- const llvm::Triple &Triple,
- Action::OffloadKind Kind) {
+ const llvm::Triple &Triple) {
// Lookup the CUDA / HIP architecture string. Only report an error if we were
// expecting the triple to be only NVPTX / AMDGPU.
OffloadArch Arch =
StringToOffloadArch(getProcessorFromTargetID(Triple, ArchStr));
- // An Intel name takes no target features, so it must parse in full; otherwise
- // "xe-pvc:garbage" would silently become "xe-pvc".
+ // An Intel name takes no target features, so "xe-pvc:foo" is not "xe-pvc".
if (Arch.isIntel() && ArchStr.contains(':'))
Arch = OffloadArch::getUnknown();
if (Triple.isNVPTX() && (Arch.isUnknown() || !Arch.isNVPTX())) {
@@ -3935,10 +3933,9 @@ static StringRef getCanonicalArchString(Compilation &C,
}
}
- // A SYCL Intel GPU has several accepted spellings, e.g. an alias or a numeric
- // name, so canonicalize it for the same reason as an NVPTX one: two spellings
- // of one device must be one architecture.
- if (Arch.isNVPTX() || (Kind == Action::OFK_SYCL && Arch.isIntelGPU()))
+ // Several spellings of one device must be one architecture, e.g. "xe-pvc" and
+ // "xe_12.60.7".
+ if (Arch.isNVPTX() || Arch.isIntelGPU())
return Args.MakeArgStringRef(OffloadArchToString(Arch));
if (Arch.isAMDGPU() || Arch.isAMDGCNSPIRV()) {
@@ -3999,7 +3996,7 @@ Driver::getOffloadArchs(Compilation &C, const llvm::opt::DerivedArgList &Args,
for (auto ArchStr : *GPUsOrErr) {
StringRef CanonicalStr = getCanonicalArchString(
- C, Args, Args.MakeArgString(ArchStr), TC.getTriple(), Kind);
+ C, Args, Args.MakeArgString(ArchStr), TC.getTriple());
if (!CanonicalStr.empty())
Archs.insert(CanonicalStr);
else
@@ -4007,7 +4004,7 @@ Driver::getOffloadArchs(Compilation &C, const llvm::opt::DerivedArgList &Args,
}
} else {
StringRef CanonicalStr =
- getCanonicalArchString(C, Args, Arch, TC.getTriple(), Kind);
+ getCanonicalArchString(C, Args, Arch, TC.getTriple());
if (!CanonicalStr.empty())
Archs.insert(CanonicalStr);
else
@@ -4020,7 +4017,7 @@ Driver::getOffloadArchs(Compilation &C, const llvm::opt::DerivedArgList &Args,
Archs.clear();
} else {
StringRef ArchStr =
- getCanonicalArchString(C, Args, Arch, TC.getTriple(), Kind);
+ getCanonicalArchString(C, Args, Arch, TC.getTriple());
Archs.erase(ArchStr);
}
}
@@ -4076,7 +4073,7 @@ Driver::getOffloadArchs(Compilation &C, const llvm::opt::DerivedArgList &Args,
? ""
: OffloadArchToString(TripleOffloadArch);
StringRef CanonicalStr =
- getCanonicalArchString(C, Args, ArchStr, TC.getTriple(), Kind);
+ getCanonicalArchString(C, Args, ArchStr, TC.getTriple());
if (!CanonicalStr.empty())
Archs.insert(CanonicalStr);
}
diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp
index d7928cd10ea24..ae6087a155211 100644
--- a/clang/lib/Driver/ToolChain.cpp
+++ b/clang/lib/Driver/ToolChain.cpp
@@ -2189,12 +2189,11 @@ llvm::opt::DerivedArgList *ToolChain::TranslateXarchArgs(
Skip = IsDevice;
} else if (A->getOption().matches(options::OPT_Xarch__)) {
StringRef Val = A->getValue();
- // A SYCL Intel GPU has several spellings, so -Xarch_ may name it by
- // another.
- NeedTrans = Val == getArchName() || (BA && Val == BA.ArchName) ||
- (OFK == Action::OFK_SYCL && BA && BA.Arch.isIntelGPU() &&
- StringToOffloadArch(Val) == BA.Arch) ||
- isXArchCompatibleTripleArch(Triple, Val);
+ // An Intel GPU has several spellings, so -Xarch_ may name it by another.
+ NeedTrans =
+ Val == getArchName() || (BA && Val == BA.ArchName) ||
+ (BA && BA.Arch.isIntelGPU() && StringToOffloadArch(Val) == BA.Arch) ||
+ isXArchCompatibleTripleArch(Triple, Val);
Skip = !NeedTrans;
}
if (NeedTrans || Skip)
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 7071ee6b3bebe..7258a86f84282 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -9864,11 +9864,10 @@ void LinkerWrapper::ConstructJob(Compilation &C, const JobAction &JA,
// If the user explicitly requested it via `--offload-arch` we should
// extract it from any static libraries if present.
- // A SYCL Intel GPU is requested by its canonical name, the one its device
- // images are labeled with, whichever spelling the user wrote.
+ // Request an Intel GPU by the canonical name its images are labeled with.
for (StringRef Arg : ToolChainArgs.getAllArgValues(OPT_offload_arch_EQ)) {
OffloadArch ID = StringToOffloadArch(Arg);
- if (Kind == Action::OFK_SYCL && ID.isIntelGPU())
+ if (ID.isIntelGPU())
Arg = OffloadArchToString(ID);
CmdArgs.emplace_back(Args.MakeArgString("--should-extract=" + Arg));
}
diff --git a/clang/test/Driver/sycl-intel-gpu-arch.cpp b/clang/test/Driver/sycl-intel-gpu-arch.cpp
new file mode 100644
index 0000000000000..9818d18647ce8
--- /dev/null
+++ b/clang/test/Driver/sycl-intel-gpu-arch.cpp
@@ -0,0 +1,55 @@
+/// Tests for Intel GPU names in --offload-arch.
+
+/// A device name and its numeric name are one architecture, spelled with the
+/// device name.
+// RUN: %clang -ccc-print-phases --target=x86_64-unknown-linux-gnu -fsycl \
+// RUN: --offload-targets=spirv64-unknown-unknown --offload-arch=xe-bmg-g21 \
+// RUN: --offload-arch=xe_20.1.0 -c %s 2>&1 \
+// RUN: | FileCheck -check-prefixes=CHK-SPELLINGS %s
+// CHK-SPELLINGS-NOT: offload, "device-sycl
+// CHK-SPELLINGS: offload, "device-sycl (spirv64-unknown-unknown:xe-bmg-g21)"
+// CHK-SPELLINGS-NOT: offload, "device-sycl
+
+/// Removing either spelling removes the device.
+// RUN: %clang -ccc-print-phases --target=x86_64-unknown-linux-gnu -fsycl \
+// RUN: --offload-targets=spirv64-unknown-unknown --offload-arch=xe-bmg-g21 \
+// RUN: --offload-arch=generic --no-offload-arch=xe_20.1.0 -c %s 2>&1 \
+// RUN: | FileCheck -check-prefixes=CHK-NO-ARCH %s
+// RUN: %clang -ccc-print-phases --target=x86_64-unknown-linux-gnu -fsycl \
+// RUN: --offload-targets=spirv64-unknown-unknown --offload-arch=xe_20.1.0 \
+// RUN: --offload-arch=generic --no-offload-arch=xe-bmg-g21 -c %s 2>&1 \
+// RUN: | FileCheck -check-prefixes=CHK-NO-ARCH %s
+// CHK-NO-ARCH-NOT: bmg
+// CHK-NO-ARCH: offload, "device-sycl (spirv64-unknown-unknown:generic)"
+// CHK-NO-ARCH-NOT: bmg
+
+/// An Intel GPU name takes no target-ID features, so a suffix is not dropped to
+/// turn the name into a device.
+// RUN: %clang -ccc-print-phases --target=x86_64-unknown-linux-gnu -fsycl \
+// RUN: --offload-targets=spirv64-unknown-unknown --offload-arch=xe-pvc:foo -c %s 2>&1 \
+// RUN: | FileCheck -check-prefixes=CHK-SUFFIX %s
+// CHK-SUFFIX: offload, "device-sycl (spirv64-unknown-unknown:xe-pvc:foo)"
+
+/// -Xarch_ may name an Intel GPU by either spelling.
+// RUN: %clang -### --target=x86_64-unknown-linux-gnu -fsycl \
+// RUN: --offload-targets=spirv64-unknown-unknown --offload-arch=xe_20.1.0 \
+// RUN: -Xarch_xe-bmg-g21 -DBMG -Xarch_xe-pvc -DPVC -c %s 2>&1 \
+// RUN: | FileCheck -check-prefixes=CHK-XARCH %s
+// CHK-XARCH: "-fsycl-is-device"
+// CHK-XARCH-SAME: "-D" "BMG"
+// CHK-XARCH-NOT: "PVC"
+
+/// A static library's device code is requested by the device name.
+// RUN: %clang -### --target=x86_64-unknown-linux-gnu -fsycl \
+// RUN: --offload-targets=spirv64-unknown-unknown --offload-arch=xe_20.1.0 %s 2>&1 \
+// RUN: | FileCheck -check-prefixes=CHK-EXTRACT %s
+// CHK-EXTRACT: clang-linker-wrapper{{.*}}"--should-extract=xe-bmg-g21"
+
+/// The same holds for any offload language, e.g. OpenMP.
+// RUN: %clang -ccc-print-phases --target=x86_64-unknown-linux-gnu -fopenmp=libomp \
+// RUN: --offload-targets=spirv64-intel --offload-arch=xe-bmg-g21 \
+// RUN: --offload-arch=xe_20.1.0 -c %s 2>&1 \
+// RUN: | FileCheck -check-prefixes=CHK-OPENMP %s
+// CHK-OPENMP-NOT: offload, "device-openmp
+// CHK-OPENMP: offload, "device-openmp (spirv64-intel:xe-bmg-g21)"
+// CHK-OPENMP-NOT: offload, "device-openmp
diff --git a/clang/test/Driver/sycl-offload-jit.cpp b/clang/test/Driver/sycl-offload-jit.cpp
index cb4283db51d25..82733ccd2bc6f 100644
--- a/clang/test/Driver/sycl-offload-jit.cpp
+++ b/clang/test/Driver/sycl-offload-jit.cpp
@@ -90,68 +90,11 @@
// RUN: %clang -ccc-print-phases --target=x86_64-unknown-linux-gnu -fsycl -fno-gpu-rdc \
// RUN: --offload-targets=spirv64-unknown-unknown --offload-arch=generic --offload-arch=bmg_g21 \
// RUN: -c %s 2>&1 | FileCheck -check-prefixes=CHK-PHASES-NORDC-ARCHS %s
-// CHK-PHASES-NORDC-ARCHS: 7: offload, "device-sycl (spirv64-unknown-unknown:generic)" {6}, ir
-// CHK-PHASES-NORDC-ARCHS: 12: offload, "device-sycl (spirv64-unknown-unknown:xe-bmg-g21)" {11}, ir
+// CHK-PHASES-NORDC-ARCHS: 7: offload, "device-sycl (spirv64-unknown-unknown:bmg_g21)" {6}, ir
+// CHK-PHASES-NORDC-ARCHS: 12: offload, "device-sycl (spirv64-unknown-unknown:generic)" {11}, ir
// CHK-PHASES-NORDC-ARCHS-NEXT: 13: llvm-offload-binary, {7, 12}, image, (device-sycl)
// CHK-PHASES-NORDC-ARCHS-NEXT: 14: clang-linker-wrapper, {13}, sycl-fatbin, (device-sycl)
-/// Every spelling of an Intel GPU names one architecture, spelled canonically,
-/// so several spellings of one device build it once.
-// RUN: %clang -ccc-print-phases --target=x86_64-unknown-linux-gnu -fsycl \
-// RUN: --offload-targets=spirv64-unknown-unknown --offload-arch=bmg_g21 \
-// RUN: --offload-arch=xe-bmg-g21 --offload-arch=xe_20.1.0 -c %s 2>&1 \
-// RUN: | FileCheck -check-prefixes=CHK-INTEL-SPELLINGS %s
-// CHK-INTEL-SPELLINGS-NOT: offload, "device-sycl
-// CHK-INTEL-SPELLINGS: offload, "device-sycl (spirv64-unknown-unknown:xe-bmg-g21)"
-// CHK-INTEL-SPELLINGS-NOT: offload, "device-sycl
-
-/// Products built on one GPU IP version are one architecture too.
-// RUN: %clang -ccc-print-phases --target=x86_64-unknown-linux-gnu -fsycl \
-// RUN: --offload-targets=spirv64-unknown-unknown --offload-arch=xe-arl-u \
-// RUN: --offload-arch=xe-mtl-u --offload-arch=xe_12.70 -c %s 2>&1 \
-// RUN: | FileCheck -check-prefixes=CHK-INTEL-SAME-IP %s
-// CHK-INTEL-SAME-IP-NOT: offload, "device-sycl
-// CHK-INTEL-SAME-IP: offload, "device-sycl (spirv64-unknown-unknown:xe-mtl-u)"
-// CHK-INTEL-SAME-IP-NOT: offload, "device-sycl
-
-/// Removing any spelling of a device removes the device.
-// RUN: %clang -ccc-print-phases --target=x86_64-unknown-linux-gnu -fsycl \
-// RUN: --offload-targets=spirv64-unknown-unknown --offload-arch=xe-bmg-g21 \
-// RUN: --offload-arch=generic --no-offload-arch=bmg_g21 -c %s 2>&1 \
-// RUN: | FileCheck -check-prefixes=CHK-INTEL-NO-ARCH %s
-// RUN: %clang -ccc-print-phases --target=x86_64-unknown-linux-gnu -fsycl \
-// RUN: --offload-targets=spirv64-unknown-unknown --offload-arch=bmg_g21 \
-// RUN: --offload-arch=generic --no-offload-arch=xe_20.1.0 -c %s 2>&1 \
-// RUN: | FileCheck -check-prefixes=CHK-INTEL-NO-ARCH %s
-// CHK-INTEL-NO-ARCH-NOT: bmg
-// CHK-INTEL-NO-ARCH: offload, "device-sycl (spirv64-unknown-unknown:generic)"
-// CHK-INTEL-NO-ARCH-NOT: bmg
-
-/// An Intel GPU name takes no target-ID features, so a suffix is not dropped to
-/// turn the name into a device.
-// RUN: %clang -ccc-print-phases --target=x86_64-unknown-linux-gnu -fsycl \
-// RUN: --offload-targets=spirv64-unknown-unknown --offload-arch=xe-pvc:foo -c %s 2>&1 \
-// RUN: | FileCheck -check-prefixes=CHK-INTEL-SUFFIX %s
-// CHK-INTEL-SUFFIX: offload, "device-sycl (spirv64-unknown-unknown:xe-pvc:foo)"
-
-/// -Xarch_ may name an Intel GPU by any of its spellings.
-// RUN: %clang -### --target=x86_64-unknown-linux-gnu -fsycl \
-// RUN: --offload-targets=spirv64-unknown-unknown --offload-arch=bmg_g21 \
-// RUN: -Xarch_bmg_g21 -DBMG -Xarch_xe-pvc -DPVC -c %s 2>&1 \
-// RUN: | FileCheck -check-prefixes=CHK-INTEL-XARCH %s
-// CHK-INTEL-XARCH: "-fsycl-is-device"
-// CHK-INTEL-XARCH-SAME: "-D" "BMG"
-// CHK-INTEL-XARCH-NOT: "PVC"
-
-/// A static library's device code is requested by the canonical name.
-// RUN: %clang -### --target=x86_64-unknown-linux-gnu -fsycl \
-// RUN: --offload-targets=spirv64-unknown-unknown --offload-arch=bmg_g21 %s 2>&1 \
-// RUN: | FileCheck -check-prefixes=CHK-INTEL-EXTRACT %s
-// RUN: %clang -### --target=x86_64-unknown-linux-gnu -fsycl \
-// RUN: --offload-targets=spirv64-unknown-unknown --offload-arch=xe_20.1.0 %s 2>&1 \
-// RUN: | FileCheck -check-prefixes=CHK-INTEL-EXTRACT %s
-// CHK-INTEL-EXTRACT: clang-linker-wrapper{{.*}}"--should-extract=xe-bmg-g21"
-
/// Multiple device triples are not supported today in non-RDC mode.
// RUN: not %clang -### --target=x86_64-unknown-linux-gnu -fsycl -fno-gpu-rdc \
// RUN: --offload-targets=spirv64-unknown-unknown,spirv32-unknown-unknown -c %s 2>&1 \
diff --git a/clang/test/Misc/target-invalid-cpu-note/nvptx.c b/clang/test/Misc/target-invalid-cpu-note/nvptx.c
index b2a38b6b26825..20dbd8dc6aa3b 100644
--- a/clang/test/Misc/target-invalid-cpu-note/nvptx.c
+++ b/clang/test/Misc/target-invalid-cpu-note/nvptx.c
@@ -2,10 +2,6 @@
// previous check finished matching (specifically, caret is not treated as
// matching a start of line when used like this in FileCheck).
-// An Intel GPU name is an offload architecture but never an NVPTX CPU.
-// RUN: not %clang_cc1 -triple nvptx64-nvidia-cuda -target-cpu xe-pvc -fsyntax-only %s 2>&1 | FileCheck %s --check-prefix=INTEL
-// INTEL: error: unknown target CPU 'xe-pvc'
-
// RUN: not %clang_cc1 -triple nvptx--- -target-cpu not-a-cpu -fsyntax-only %s 2>&1 | FileCheck %s --implicit-check-not={{[a-zA-Z0-9]}}
// CHECK: error: unknown target CPU 'not-a-cpu'
// CHECK-NEXT: note: valid target CPU values are:
diff --git a/clang/test/OffloadTools/clang-sycl-linker/basic.ll b/clang/test/OffloadTools/clang-sycl-linker/basic.ll
index 0376e7bf88338..23c17f3bb07f4 100644
--- a/clang/test/OffloadTools/clang-sycl-linker/basic.ll
+++ b/clang/test/OffloadTools/clang-sycl-linker/basic.ll
@@ -109,7 +109,7 @@
;
; Test AOT compilation for an Intel GPU.
; Test that IMG_Object image kind is set for AOT compilation (Intel GPU).
-; RUN: clang-sycl-linker --dry-run -v --module-split-mode=link_unit -arch=bmg_g21 %t/input1.bc %t/input2.bc -o %t/aot-gpu.out 2>&1 \
+; RUN: clang-sycl-linker --dry-run -v --module-split-mode=link_unit -arch=xe-bmg-g21 %t/input1.bc %t/input2.bc -o %t/aot-gpu.out 2>&1 \
; RUN: --ocloc-options="-a -b" \
; RUN: | FileCheck %s --check-prefix=AOT-INTEL-GPU
; AOT-INTEL-GPU: link: inputs: {{.*}}.bc, {{.*}}.bc output: [[LLVMLINKOUT:.*]].bc
@@ -118,19 +118,18 @@
; AOT-INTEL-GPU-NEXT: sycl-bundle: image kind: o, triple: spirv64, arch: xe-bmg-g21
; AOT-INTEL-GPU-NOT: {{.+}}
;
-; Test that every accepted spelling of an Intel GPU reaches ocloc as ocloc's own.
+; Test that an Intel GPU name, or its numeric name, reaches ocloc as ocloc's own.
; RUN: clang-sycl-linker --dry-run -v --module-split-mode=link_unit -arch=xe-bmg-g21 %t/input1.bc -o %t/aot-gpu.out 2>&1 \
; RUN: | FileCheck %s --check-prefix=AOT-INTEL-NAME
; RUN: clang-sycl-linker --dry-run -v --module-split-mode=link_unit -arch=xe_20.1.0 %t/input1.bc -o %t/aot-gpu.out 2>&1 \
; RUN: | FileCheck %s --check-prefix=AOT-INTEL-NAME
; AOT-INTEL-NAME: "{{.*}}ocloc{{.*}}" {{.*}}-device bmg_g21 {{.*}}-output
-; AOT-INTEL-NAME: sycl-bundle: image kind: o, triple: spirv64, arch: xe-bmg-g21
; RUN: clang-sycl-linker --dry-run -v --module-split-mode=link_unit -arch=xe-pvc %t/input1.bc -o %t/aot-gpu.out 2>&1 \
; RUN: | FileCheck %s --check-prefix=AOT-INTEL-PVC
; AOT-INTEL-PVC: "{{.*}}ocloc{{.*}}" {{.*}}-device pvc {{.*}}-output
; Test that all --ocloc-options are passed to ocloc, even if they contain spaces or quotes.
-; RUN: clang-sycl-linker --dry-run -v --module-split-mode=link_unit -arch=bmg_g21 %t/input1.bc -o %t/aot-gpu.out 2>&1 \
+; RUN: clang-sycl-linker --dry-run -v --module-split-mode=link_unit -arch=xe-bmg-g21 %t/input1.bc -o %t/aot-gpu.out 2>&1 \
; RUN: --ocloc-options="-a -b" --ocloc-options=-c --ocloc-options="d" --ocloc-options='"-e -f"' \
; RUN: | FileCheck %s --check-prefix=AOT-INTEL-OCLOC-OPTIONS
; AOT-INTEL-OCLOC-OPTIONS: "{{.*}}ocloc{{.*}}" {{.*}}-device bmg_g21 -a -b -c d "-e -f"
@@ -151,7 +150,7 @@
; current directory (with a unique suffix to avoid collisions between
; concurrent invocations sharing an output basename).
; RUN: rm -rf %t/outdir && mkdir -p %t/outdir
-; RUN: clang-sycl-linker --dry-run -v --module-split-mode=link_unit -arch=bmg_g21 %t/input1.bc -o %t/outdir/nested.out 2>&1 \
+; RUN: clang-sycl-linker --dry-run -v --module-split-mode=link_unit -arch=xe-bmg-g21 %t/input1.bc -o %t/outdir/nested.out 2>&1 \
; RUN: | FileCheck %s --check-prefix=AOT-STEM-BASENAME
; AOT-STEM-BASENAME: LLVM backend: input: {{.*}}.bc, output: [[SPVSTEM:nested.*]].spv
; AOT-STEM-BASENAME-NEXT: "{{.*}}ocloc{{.*}}" {{.*}}-output [[SPVSTEM]].out -file [[SPVSTEM]].spv
diff --git a/clang/tools/clang-sycl-linker/ClangSYCLLinker.cpp b/clang/tools/clang-sycl-linker/ClangSYCLLinker.cpp
index 01463c15aa0db..50f1d55450cfd 100644
--- a/clang/tools/clang-sycl-linker/ClangSYCLLinker.cpp
+++ b/clang/tools/clang-sycl-linker/ClangSYCLLinker.cpp
@@ -717,7 +717,7 @@ static Error runAOTCompileIntelGPU(StringRef InputFile, StringRef OutputFile,
StringRef Arch(Args.getLastArgValue(OPT_arch_EQ));
assert(!Arch.empty() && "Arch must be specified for AOT compilation");
// ocloc spells a device without the "xe-" prefix and with "_" between words,
- // e.g. "bmg_g21" for "xe-bmg-g21", so translate any accepted spelling.
+ // e.g. "bmg_g21" for "xe-bmg-g21".
StringRef Canonical = OffloadArchToString(StringToOffloadArch(Arch));
[[maybe_unused]] bool HasPrefix = Canonical.consume_front("xe-");
assert(HasPrefix && "Intel GPU name without the xe- prefix");
@@ -1052,12 +1052,8 @@ static Error runSYCLLink(ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs,
TheImage.TheOffloadKind = OFK_SYCL;
TheImage.StringData["triple"] =
Args.MakeArgString(Result.TargetTriple.str());
- // Label an Intel GPU image with its canonical name, whichever spelling was
- // given, so that one device's images always carry one arch.
- StringRef Arch = Args.getLastArgValue(OPT_arch_EQ);
- OffloadArch OA = StringToOffloadArch(Arch);
TheImage.StringData["arch"] =
- OA.isIntelGPU() ? OffloadArchToString(OA) : Args.MakeArgString(Arch);
+ Args.MakeArgString(Args.getLastArgValue(OPT_arch_EQ));
TheImage.StringData["symbols"] = SI.Symbols;
TheImage.Image = std::move(*FileOrErr);
Images.emplace_back(std::move(TheImage));
diff --git a/clang/unittests/Basic/OffloadArchTest.cpp b/clang/unittests/Basic/OffloadArchTest.cpp
index 980a88aba6114..ac87d8395eb26 100644
--- a/clang/unittests/Basic/OffloadArchTest.cpp
+++ b/clang/unittests/Basic/OffloadArchTest.cpp
@@ -66,21 +66,19 @@ TEST(OffloadArchTest, RoundTrip) {
}
}
-// A spelling that is not the architecture name still denotes the device, and
-// canonicalizes to that name rather than round-tripping to itself.
-TEST(OffloadArchTest, IntelGPUAliases) {
- // An alias, here the spelling accepted before the Intel GPU list existed.
- EXPECT_EQ(parse("bmg_g21"), parse("xe-bmg-g21"));
- // A numeric name, whose revision takes no part in the lookup.
+// A numeric name denotes the device, and canonicalizes to the device name.
+TEST(OffloadArchTest, IntelGPUNumericNames) {
+ // The revision takes no part in the lookup.
EXPECT_EQ(parse("xe_12.60.0"), parse("xe-pvc"));
EXPECT_EQ(parse("xe_12.60.7"), parse("xe-pvc"));
EXPECT_EQ(parse("xe_12.60"), parse("xe-pvc"));
- EXPECT_STREQ(OffloadArchToString(parse("bmg_g21")), "xe-bmg-g21");
EXPECT_STREQ(OffloadArchToString(parse("xe_12.60.7")), "xe-pvc");
// A well-formed numeric name for a device this build does not know is as
// unknown as any other unknown name.
EXPECT_TRUE(parse("xe_99.99.0").isUnknown());
+ // So is the spelling clang accepted before the Intel GPU list existed.
+ EXPECT_TRUE(parse("bmg_g21").isUnknown());
}
TEST(OffloadArchTest, Defaults) {
diff --git a/llvm/include/llvm/TargetParser/IntelGPUTargetParser.def b/llvm/include/llvm/TargetParser/IntelGPUTargetParser.def
index 566045539c723..d722d999444b6 100644
--- a/llvm/include/llvm/TargetParser/IntelGPUTargetParser.def
+++ b/llvm/include/llvm/TargetParser/IntelGPUTargetParser.def
@@ -21,8 +21,7 @@
// IGCA_FEATURE_SETS - Token naming the IGCA feature sets the device
// implements: Core (none), Compute ("c"),
// Render ("r"), ComputeExact ("ca") or
-// RenderExact ("ra"). It is a token, so a misspelled
-// one such as Compte fails to build.
+// RenderExact ("ra").
//
// INTEL_GPU_COMPAT(NAME, KIND, IGCA_TARGET, IGCA_FEATURE_SETS)
// A compatibility name that covers several minor versions, e.g. "xe-dg2",
@@ -31,24 +30,14 @@
// offload-arch utility never prints one, but they are legal --offload-arch
// values. The columns mean the same as above.
//
-// INTEL_GPU_ALIAS(NAME, KIND)
-// A further name for a device that already has a row: "bmg_g21", which
-// --offload-arch accepted before the list existed, or another product
-// built on the same GPU IP version, e.g. "xe-arl-u" for "xe-mtl-u". Code
-// for one GPU IP version is the same whichever product runs it, so these
-// are one architecture. An alias declares no kind of its own and is never
-// printed, so a device keeps one canonical name; it only widens what
-// --offload-arch accepts.
-//
// A device is keyed by its major and minor version alone. The revision
// component of the GPU IP version is deliberately left out of the key, so that
// every revision of a device shares one name and one IGCA target.
//
-// Products that share a major and a minor version form one INTEL_GPU row, named
-// after the product the offload-arch utility prints; the other products are
-// aliases. The exception is "xe-pvc-sdv": it has the same major and minor
-// version as "xe-pvc", but the AOT compiler generates different code for it, so
-// it gets its own row.
+// Products that share a major and a minor version have one row, named after
+// the product the offload-arch utility prints. The exception is "xe-pvc-sdv":
+// it has the same major and minor version as "xe-pvc", but the AOT compiler
+// generates different code for it, so it gets its own row.
//
// Devices without a published name are left out on purpose; offload-arch names
// them by GPU IP version, as "xe_*.*.*". A device gets a row only once it has
@@ -96,27 +85,5 @@ 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)
-// Aliases, which are further names of a device named above
-#ifndef INTEL_GPU_ALIAS
-#define INTEL_GPU_ALIAS(NAME, KIND)
-#endif
-
-// Accepted before this list existed; to be removed in favor of "xe-bmg-g21".
-INTEL_GPU_ALIAS("bmg_g21", XE_BMG_G21)
-INTEL_GPU_ALIAS("xe-nvl-h", XE_NVL_U)
-INTEL_GPU_ALIAS("xe-nvl-hx", XE_NVL_S)
-INTEL_GPU_ALIAS("xe-nvl-ul", XE_NVL_S)
-INTEL_GPU_ALIAS("xe-arl-u", XE_MTL_U)
-INTEL_GPU_ALIAS("xe-arl-s", XE_MTL_U)
-INTEL_GPU_ALIAS("xe-dg2-g12", XE_ACM_G12)
-INTEL_GPU_ALIAS("xe-dg2-g11", XE_ACM_G11)
-INTEL_GPU_ALIAS("xe-ats-m75", XE_ACM_G11)
-INTEL_GPU_ALIAS("xe-dg2-g10", XE_ACM_G10)
-INTEL_GPU_ALIAS("xe-ats-m150", XE_ACM_G10)
-INTEL_GPU_ALIAS("xe-rpl-p", XE_ADL_P)
-INTEL_GPU_ALIAS("xe-rpl-s", XE_ADL_S)
-INTEL_GPU_ALIAS("xe-tgl", XE_TGLLP)
-
#undef INTEL_GPU
#undef INTEL_GPU_COMPAT
-#undef INTEL_GPU_ALIAS
diff --git a/llvm/include/llvm/TargetParser/IntelGPUTargetParser.h b/llvm/include/llvm/TargetParser/IntelGPUTargetParser.h
index 1131ccf52e64c..940a6b36f6c84 100644
--- a/llvm/include/llvm/TargetParser/IntelGPUTargetParser.h
+++ b/llvm/include/llvm/TargetParser/IntelGPUTargetParser.h
@@ -20,7 +20,6 @@
#include <string>
namespace llvm {
-template <typename T> class SmallVectorImpl;
namespace IntelGPU {
@@ -44,35 +43,22 @@ enum GPUKind : uint8_t {
/// version; xe-pvc is returned.
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);
-
/// \return the human-friendly name of \p Kind, e.g. "xe-pvc", or an empty
/// string for GK_NONE.
LLVM_ABI StringRef getArchName(GPUKind Kind);
+/// \return the numeric name of \p GPUIPVersion, e.g. "xe_35.11.0".
+LLVM_ABI std::string getNumericArchName(uint32_t GPUIPVersion);
+
/// \return the device \p Name denotes, or GK_NONE for a name this build does
/// not know.
///
/// \p Name may be a human-friendly name ("xe-pvc"), a compatibility name
-/// ("xe-dg2"), an alias ("bmg_g21") or a numeric name ("xe_12.60.7"). The
-/// revision of a numeric name is ignored and may be omitted, so "xe_12.60",
-/// "xe_12.60.0" and "xe_12.60.7" all denote the same device.
+/// ("xe-dg2") or a numeric name ("xe_12.60.7"). The revision of a numeric name
+/// is ignored and may be omitted, so "xe_12.60", "xe_12.60.0" and "xe_12.60.7"
+/// all denote the same device.
LLVM_ABI GPUKind parseArch(StringRef Name);
-/// \return the IGCA target name to compile \p Kind for, e.g. "xe-pvc" ->
-/// "igca_20ca", or an empty string for GK_NONE. This is the spelling
-/// -target-cpu is invoked with.
-///
-/// The name is the numeric IGCA target followed by the suffix of the feature
-/// sets: igca_60 is the core features, igca_60c adds the compute features, and
-/// igca_60ca is exact, meaning that only a device at that target will do.
-LLVM_ABI StringRef getIGCAName(GPUKind Kind);
-
-/// Append every architecture name this build accepts, for diagnostics that
-/// offer the user an alternative to a name that did not parse.
-LLVM_ABI void fillValidArchList(SmallVectorImpl<StringRef> &Values);
-
} // namespace IntelGPU
} // namespace llvm
diff --git a/llvm/lib/TargetParser/IntelGPUTargetParser.cpp b/llvm/lib/TargetParser/IntelGPUTargetParser.cpp
index 044daddc868f1..2f29fa2f28216 100644
--- a/llvm/lib/TargetParser/IntelGPUTargetParser.cpp
+++ b/llvm/lib/TargetParser/IntelGPUTargetParser.cpp
@@ -11,7 +11,6 @@
//===----------------------------------------------------------------------===//
#include "llvm/TargetParser/IntelGPUTargetParser.h"
-#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/ErrorHandling.h"
@@ -87,7 +86,7 @@ StringRef llvm::IntelGPU::getArchName(GPUKind Kind) {
return NAME;
#include "llvm/TargetParser/IntelGPUTargetParser.def"
}
- llvm_unreachable("invalid Intel GPU GPUKind");
+ llvm_unreachable("invalid Intel GPU kind");
}
// Read a numeric architecture name, e.g. "xe_12.60.7", into the GPU IP version
@@ -126,7 +125,6 @@ GPUKind llvm::IntelGPU::parseArch(StringRef Name) {
.Case(NAME, GK_##KIND)
#define INTEL_GPU_COMPAT(NAME, KIND, IGCA_TARGET, IGCA_FEATURE_SETS) \
.Case(NAME, GK_##KIND)
-#define INTEL_GPU_ALIAS(NAME, KIND) .Case(NAME, GK_##KIND)
#include "llvm/TargetParser/IntelGPUTargetParser.def"
.Default(GK_NONE);
if (Kind != GK_NONE)
@@ -140,45 +138,3 @@ GPUKind llvm::IntelGPU::parseArch(StringRef Name) {
return getKindForVersion(GPUIPVersion);
return GK_NONE;
}
-
-// The suffix each IGCA_FEATURE_SETS token contributes to a target name.
-#define IGCA_FEATURE_SETS_Core ""
-#define IGCA_FEATURE_SETS_Compute "c"
-#define IGCA_FEATURE_SETS_Render "r"
-#define IGCA_FEATURE_SETS_ComputeExact "ca"
-#define IGCA_FEATURE_SETS_RenderExact "ra"
-
-StringRef llvm::IntelGPU::getIGCAName(GPUKind Kind) {
- // Unlike the NVPTX virtual architecture name, this is not a column of its
- // own: the target and the feature sets already spell it, and a column would
- // let the three disagree.
- switch (Kind) {
- case GK_NONE:
- return "";
-#define INTEL_GPU(NAME, KIND, MAJOR, MINOR, IGCA_TARGET, IGCA_FEATURE_SETS) \
- case GK_##KIND: \
- return "igca_" #IGCA_TARGET IGCA_FEATURE_SETS_##IGCA_FEATURE_SETS;
-#define INTEL_GPU_COMPAT(NAME, KIND, IGCA_TARGET, IGCA_FEATURE_SETS) \
- case GK_##KIND: \
- return "igca_" #IGCA_TARGET IGCA_FEATURE_SETS_##IGCA_FEATURE_SETS;
-#include "llvm/TargetParser/IntelGPUTargetParser.def"
- }
- llvm_unreachable("invalid Intel GPU GPUKind");
-}
-
-#undef IGCA_FEATURE_SETS_Core
-#undef IGCA_FEATURE_SETS_Compute
-#undef IGCA_FEATURE_SETS_Render
-#undef IGCA_FEATURE_SETS_ComputeExact
-#undef IGCA_FEATURE_SETS_RenderExact
-
-void llvm::IntelGPU::fillValidArchList(SmallVectorImpl<StringRef> &Values) {
- // An alias is a name the user may write, so it belongs here even though it is
- // never the name reported for a device.
-#define INTEL_GPU(NAME, KIND, MAJOR, MINOR, IGCA_TARGET, IGCA_FEATURE_SETS) \
- Values.push_back(NAME);
-#define INTEL_GPU_COMPAT(NAME, KIND, IGCA_TARGET, IGCA_FEATURE_SETS) \
- Values.push_back(NAME);
-#define INTEL_GPU_ALIAS(NAME, KIND) Values.push_back(NAME);
-#include "llvm/TargetParser/IntelGPUTargetParser.def"
-}
diff --git a/llvm/unittests/TargetParser/IntelGPUTargetParserTest.cpp b/llvm/unittests/TargetParser/IntelGPUTargetParserTest.cpp
index 147a3e3b4485c..e04e93dc69e7a 100644
--- a/llvm/unittests/TargetParser/IntelGPUTargetParserTest.cpp
+++ b/llvm/unittests/TargetParser/IntelGPUTargetParserTest.cpp
@@ -7,8 +7,6 @@
//===----------------------------------------------------------------------===//
#include "llvm/TargetParser/IntelGPUTargetParser.h"
-#include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/SmallVector.h"
#include "gtest/gtest.h"
#include <cassert>
@@ -87,14 +85,13 @@ TEST(IntelGPUTargetParserTest, KindArchNames) {
}
TEST(IntelGPUTargetParserTest, ParseArch) {
- // A human-friendly name, a compatibility name, and an alias.
+ // A human-friendly name and a compatibility name.
EXPECT_EQ(IntelGPU::parseArch("xe-pvc"), IntelGPU::GK_XE_PVC);
EXPECT_EQ(IntelGPU::parseArch("xe-dg2"), IntelGPU::GK_XE_DG2);
- EXPECT_EQ(IntelGPU::parseArch("bmg_g21"), IntelGPU::GK_XE_BMG_G21);
- // Products built on one GPU IP version are one device, named after the one
- // the offload-arch utility prints.
- EXPECT_EQ(IntelGPU::parseArch("xe-arl-u"), IntelGPU::GK_XE_MTL_U);
- EXPECT_EQ(IntelGPU::parseArch("xe-ats-m150"), IntelGPU::GK_XE_ACM_G10);
+ // Each device has one name; another product on its GPU IP version is named
+ // by its numeric name instead.
+ EXPECT_EQ(IntelGPU::parseArch("bmg_g21"), IntelGPU::GK_NONE);
+ EXPECT_EQ(IntelGPU::parseArch("xe-arl-u"), IntelGPU::GK_NONE);
EXPECT_EQ(IntelGPU::parseArch("xe_12.70"), IntelGPU::GK_XE_MTL_U);
// Except PVC-SDV, which the AOT compiler builds for its own stepping.
EXPECT_EQ(IntelGPU::parseArch("xe-pvc-sdv"), IntelGPU::GK_XE_PVC_SDV);
@@ -143,43 +140,7 @@ TEST(IntelGPUTargetParserTest, EveryNameParses) {
EXPECT_EQ(IntelGPU::parseArch(NAME), IntelGPU::GK_##KIND) << NAME;
#define INTEL_GPU_COMPAT(NAME, KIND, IGCA_TARGET, IGCA_FEATURE_SETS) \
EXPECT_EQ(IntelGPU::parseArch(NAME), IntelGPU::GK_##KIND) << NAME;
-#define INTEL_GPU_ALIAS(NAME, KIND) \
- EXPECT_EQ(IntelGPU::parseArch(NAME), IntelGPU::GK_##KIND) << NAME;
#include "llvm/TargetParser/IntelGPUTargetParser.def"
}
-TEST(IntelGPUTargetParserTest, AliasesAreNeverReported) {
- // An alias declares no kind of its own, so the name reported for a device is
- // the row's own name. A device with two spellings would otherwise depend on
- // which one the table happened to reach first.
-#define INTEL_GPU_ALIAS(NAME, KIND) \
- EXPECT_NE(IntelGPU::getArchName(IntelGPU::GK_##KIND), NAME) << NAME;
-#include "llvm/TargetParser/IntelGPUTargetParser.def"
-}
-
-TEST(IntelGPUTargetParserTest, IGCANames) {
- // One of each suffix, since the target and the feature sets are pasted
- // together.
- EXPECT_EQ(IntelGPU::getIGCAName(IntelGPU::GK_XE_CRI), "igca_60c");
- EXPECT_EQ(IntelGPU::getIGCAName(IntelGPU::GK_XE_NVL_P), "igca_60r");
- EXPECT_EQ(IntelGPU::getIGCAName(IntelGPU::GK_XE_PVC), "igca_20ca");
- EXPECT_EQ(IntelGPU::getIGCAName(IntelGPU::GK_XE_DG2), "igca_15ra");
- EXPECT_EQ(IntelGPU::getIGCAName(IntelGPU::GK_NONE), "");
-}
-
-TEST(IntelGPUTargetParserTest, ValidArchList) {
- SmallVector<StringRef> Values;
- IntelGPU::fillValidArchList(Values);
-
- EXPECT_FALSE(Values.empty());
- EXPECT_NE(llvm::find(Values, "xe-pvc"), Values.end());
- // A compatibility name and an alias are as valid as any other name.
- EXPECT_NE(llvm::find(Values, "xe-dg2"), Values.end());
- EXPECT_NE(llvm::find(Values, "bmg_g21"), Values.end());
- // The list is offered to a user whose name did not parse, so every entry has
- // to be a name that would have.
- for (StringRef Value : Values)
- EXPECT_NE(IntelGPU::parseArch(Value), IntelGPU::GK_NONE) << Value;
-}
-
} // namespace
More information about the cfe-commits
mailing list