https://github.com/srividya-sundaram updated 
https://github.com/llvm/llvm-project/pull/229248

>From 4e07d042e43ba094a8f05c838631d32c24853e84 Mon Sep 17 00:00:00 2001
From: srividya sundaram <[email protected]>
Date: Sat, 12 Sep 2026 19:09:30 -0700
Subject: [PATCH 1/6] [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 3f32c4853a511540a559f42d3556ffef24b73f8d Mon Sep 17 00:00:00 2001
From: srividya sundaram <[email protected]>
Date: Mon, 5 Oct 2026 14:29:55 -0700
Subject: [PATCH 2/6] [Clang][SYCL] Infer the SPIR-V target from an Intel
 offload architecture

Select the SPIR-V target from an Intel offload architecture in --offload-arch.

Previously, clang++ -fsycl --offload-arch=xe-pvc failed with "invalid or 
unsupported offload target" unless --offload-targets was also given, although 
the name alone says which target to use. For CUDA and HIP, an NVIDIA or AMD 
name already selects the target.

For SYCL, an Intel GPU name, an Intel CPU name (graniterapids) or generic now 
selects SPIR-V of the host's width, the same target SYCL uses when no 
architecture is given. generic previously had no inferred target. With 
-foffload-via-llvm the target gets the LLVM environment, as it does for CUDA 
and HIP. OpenMP, CUDA and HIP still reject an Intel name.

Assisted-by: Claude Opus 5.5
---
 clang/lib/Driver/Driver.cpp            | 20 +++++++++++--
 clang/test/Driver/sycl-offload-jit.cpp | 40 ++++++++++++++++++++++++++
 2 files changed, 57 insertions(+), 3 deletions(-)

diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp
index bbcf88d823776..8d4eb664c4808 100644
--- a/clang/lib/Driver/Driver.cpp
+++ b/clang/lib/Driver/Driver.cpp
@@ -967,21 +967,29 @@ using TripleSet = std::multiset<llvm::Triple>;
 // requested offloading kind and architectures.
 static TripleSet inferOffloadToolchains(Compilation &C,
                                         Action::OffloadKind Kind) {
+  // A SYCL Intel GPU has several accepted spellings, so key it by its 
canonical
+  // name, or --no-offload-arch with another spelling would not remove it.
+  auto canonicalize = [Kind](StringRef Arch) {
+    OffloadArch ID = StringToOffloadArch(Arch);
+    return Kind == Action::OFK_SYCL && ID.isIntelGPU()
+               ? std::string(OffloadArchToString(ID))
+               : Arch.str();
+  };
   std::set<std::string> Archs;
   for (Arg *A : C.getInputArgs()) {
     for (StringRef Arch : A->getValues()) {
       if (A->getOption().matches(options::OPT_offload_arch_EQ)) {
         if (Arch == "native") {
           for (StringRef Str : getSystemOffloadArchs(C, Kind))
-            Archs.insert(Str.str());
+            Archs.insert(canonicalize(Str));
         } else {
-          Archs.insert(Arch.str());
+          Archs.insert(canonicalize(Arch));
         }
       } else if (A->getOption().matches(options::OPT_no_offload_arch_EQ)) {
         if (Arch == "all")
           Archs.clear();
         else
-          Archs.erase(Arch.str());
+          Archs.erase(canonicalize(Arch));
       }
     }
   }
@@ -1023,6 +1031,12 @@ static TripleSet inferOffloadToolchains(Compilation &C,
 
     llvm::Triple Triple =
         OffloadArchToTriple(C.getDefaultToolChain().getTriple(), ID);
+    // A SYCL Intel device, or a generic one, is SPIR-V of the host's width, 
the
+    // same target SYCL picks when no architecture is given.
+    if (Kind == Action::OFK_SYCL && (ID.isIntel() || ID.isGeneric()))
+      Triple = llvm::Triple(C.getDefaultToolChain().getTriple().isArch64Bit()
+                                ? llvm::Triple::spirv64
+                                : llvm::Triple::spirv32);
     if (UsesLLVMOffloading)
       Triple.setEnvironment(llvm::Triple::LLVM);
 
diff --git a/clang/test/Driver/sycl-offload-jit.cpp 
b/clang/test/Driver/sycl-offload-jit.cpp
index cb4283db51d25..81adeb0941240 100644
--- a/clang/test/Driver/sycl-offload-jit.cpp
+++ b/clang/test/Driver/sycl-offload-jit.cpp
@@ -134,6 +134,46 @@
 // RUN:   | FileCheck -check-prefixes=CHK-INTEL-SUFFIX %s
 // CHK-INTEL-SUFFIX: offload, "device-sycl 
(spirv64-unknown-unknown:xe-pvc:foo)"
 
+/// Without --offload-targets, an Intel device or "generic" picks SPIR-V of the
+/// host's width, and removing any spelling still removes the device.
+// RUN: %clang -ccc-print-phases --target=x86_64-unknown-linux-gnu -fsycl \
+// RUN:   --offload-arch=xe-pvc --offload-arch=bmg_g21 
--offload-arch=graniterapids \
+// RUN:   --offload-arch=generic -c %s 2>&1 \
+// RUN:   | FileCheck -check-prefixes=CHK-INTEL-NO-TARGETS %s
+// CHK-INTEL-NO-TARGETS-DAG: offload, "device-sycl 
(spirv64-unknown-unknown:generic)"
+// CHK-INTEL-NO-TARGETS-DAG: offload, "device-sycl 
(spirv64-unknown-unknown:graniterapids)"
+// CHK-INTEL-NO-TARGETS-DAG: offload, "device-sycl 
(spirv64-unknown-unknown:xe-bmg-g21)"
+// CHK-INTEL-NO-TARGETS-DAG: offload, "device-sycl 
(spirv64-unknown-unknown:xe-pvc)"
+// RUN: %clang -ccc-print-phases --target=i386-unknown-linux-gnu -fsycl \
+// RUN:   --offload-arch=xe-pvc -c %s 2>&1 \
+// RUN:   | FileCheck -check-prefixes=CHK-INTEL-NO-TARGETS-32 %s
+// CHK-INTEL-NO-TARGETS-32: offload, "device-sycl 
(spirv32-unknown-unknown:xe-pvc)"
+// RUN: %clang -ccc-print-phases --target=x86_64-unknown-linux-gnu -fsycl \
+// RUN:   --offload-arch=xe-pvc --offload-arch=xe_12.60.7 -c %s 2>&1 \
+// RUN:   | FileCheck -check-prefixes=CHK-INTEL-NO-TARGETS-ONE %s
+// CHK-INTEL-NO-TARGETS-ONE-NOT: offload, "device-sycl
+// CHK-INTEL-NO-TARGETS-ONE: offload, "device-sycl 
(spirv64-unknown-unknown:xe-pvc)"
+// CHK-INTEL-NO-TARGETS-ONE-NOT: offload, "device-sycl
+// RUN: %clang -ccc-print-phases --target=x86_64-unknown-linux-gnu -fsycl \
+// RUN:   --offload-arch=bmg_g21 --offload-arch=xe-pvc 
--no-offload-arch=xe-bmg-g21 \
+// RUN:   -c %s 2>&1 | FileCheck -check-prefixes=CHK-INTEL-NO-TARGETS-NO-ARCH 
%s
+// CHK-INTEL-NO-TARGETS-NO-ARCH-NOT: bmg
+// CHK-INTEL-NO-TARGETS-NO-ARCH: offload, "device-sycl 
(spirv64-unknown-unknown:xe-pvc)"
+// CHK-INTEL-NO-TARGETS-NO-ARCH-NOT: bmg
+
+/// As for CUDA and HIP, -foffload-via-llvm gives the inferred target the LLVM
+/// environment.
+// RUN: %clang -### --target=x86_64-unknown-linux-gnu -fsycl 
-foffload-via-llvm \
+// RUN:   --offload-arch=xe-pvc -c %s 2>&1 \
+// RUN:   | FileCheck -check-prefixes=CHK-INTEL-VIA-LLVM %s
+// CHK-INTEL-VIA-LLVM: "-cc1" "-triple" "spirv64-unknown-unknown-llvm"
+
+/// Only SYCL infers a target from an Intel name.
+// RUN: not %clang -### --target=x86_64-unknown-linux-gnu -x cuda -nocudainc \
+// RUN:   -nocudalib --offload-arch=xe-pvc -c %s 2>&1 \
+// RUN:   | FileCheck -check-prefixes=CHK-INTEL-CUDA %s
+// CHK-INTEL-CUDA: error: unsupported CUDA gpu architecture: xe-pvc
+
 /// -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 \

>From 578085074dc4e1c97a5006d8a1b124247c47e41e Mon Sep 17 00:00:00 2001
From: srividya sundaram <[email protected]>
Date: Wed, 7 Oct 2026 15:33:55 -0700
Subject: [PATCH 3/6] [Clang][SYCL] Skip NVIDIA GPUs in --offload-arch=native
 for SYCL

SYCL cannot target NVIDIA GPUs, so on a machine with both an Intel and an
NVIDIA GPU, -fsycl --offload-arch=native created an NVIDIA device job that
hit an assertion. Skip NVIDIA GPUs for SYCL, add a release note for the
inferred SPIR-V target, and shorten a comment.

Assisted-by: Claude Opus 5.5
---
 clang/docs/ReleaseNotes.md                        |  4 ++++
 clang/lib/Driver/Driver.cpp                       |  8 +++++---
 .../Inputs/offload-arch/offload_arch_sm_70_xe_pvc |  4 ++++
 clang/test/Driver/sycl-system-arch.cpp            | 15 +++++++++++++++
 4 files changed, 28 insertions(+), 3 deletions(-)
 create mode 100755 
clang/test/Driver/Inputs/offload-arch/offload_arch_sm_70_xe_pvc
 create mode 100644 clang/test/Driver/sycl-system-arch.cpp

diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 4465396bd6042..74c043f471124 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -1173,6 +1173,10 @@ The `alpha.cplusplus.UseAfterLifetimeEnd` checker was 
renamed to `alpha.core.Use
 
 #### Improvements
 
+- `-fsycl --offload-arch=<Intel GPU>`, e.g. `xe-pvc`, now selects the SPIR-V
+  target without `--offload-targets`. `--offload-arch=native` skips NVIDIA 
GPUs,
+  which SYCL cannot target.
+
 ## Additional Information
 
 A wide variety of additional information is available on the [Clang web
diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp
index 8d4eb664c4808..daf028f801c62 100644
--- a/clang/lib/Driver/Driver.cpp
+++ b/clang/lib/Driver/Driver.cpp
@@ -953,7 +953,9 @@ getSystemOffloadArchs(Compilation &C, Action::OffloadKind 
Kind) {
     }
 
     for (StringRef Arch : llvm::split((*StdoutOrErr)->getBuffer(), "\n"))
-      if (!Arch.empty())
+      // SYCL cannot target NVIDIA GPUs, so skip them.
+      if (!Arch.empty() &&
+          !(Kind == Action::OFK_SYCL && StringToOffloadArch(Arch).isNVPTX()))
         GPUArchs.push_back(Arch.str());
   } else {
     C.getDriver().Diag(diag::err_drv_command_failure) << "offload-arch";
@@ -1031,8 +1033,8 @@ static TripleSet inferOffloadToolchains(Compilation &C,
 
     llvm::Triple Triple =
         OffloadArchToTriple(C.getDefaultToolChain().getTriple(), ID);
-    // A SYCL Intel device, or a generic one, is SPIR-V of the host's width, 
the
-    // same target SYCL picks when no architecture is given.
+    // For SYCL, an Intel name or "generic" means SPIR-V of the host's width,
+    // the target SYCL already uses when no architecture is given.
     if (Kind == Action::OFK_SYCL && (ID.isIntel() || ID.isGeneric()))
       Triple = llvm::Triple(C.getDefaultToolChain().getTriple().isArch64Bit()
                                 ? llvm::Triple::spirv64
diff --git a/clang/test/Driver/Inputs/offload-arch/offload_arch_sm_70_xe_pvc 
b/clang/test/Driver/Inputs/offload-arch/offload_arch_sm_70_xe_pvc
new file mode 100755
index 0000000000000..299c133dbb552
--- /dev/null
+++ b/clang/test/Driver/Inputs/offload-arch/offload_arch_sm_70_xe_pvc
@@ -0,0 +1,4 @@
+#!/bin/sh
+echo "sm_70"
+echo "xe_12.60.7"
+exit 0
diff --git a/clang/test/Driver/sycl-system-arch.cpp 
b/clang/test/Driver/sycl-system-arch.cpp
new file mode 100644
index 0000000000000..b67acebbccf29
--- /dev/null
+++ b/clang/test/Driver/sycl-system-arch.cpp
@@ -0,0 +1,15 @@
+// Needs chmod
+// UNSUPPORTED: system-windows
+// XFAIL: target={{.*}}-zos{{.*}}
+
+// RUN: mkdir -p %t
+// RUN: cp %S/Inputs/offload-arch/offload_arch_sm_70_xe_pvc %t/
+// RUN: chmod +x %t/offload_arch_sm_70_xe_pvc
+
+/// SYCL cannot target NVIDIA GPUs, so --offload-arch=native skips them.
+// RUN: %clang -ccc-print-phases --target=x86_64-unknown-linux-gnu -fsycl \
+// RUN:   --offload-arch=native 
--offload-arch-tool=%t/offload_arch_sm_70_xe_pvc \
+// RUN:   -c %s 2>&1 | FileCheck %s
+// CHECK-NOT: sm_70
+// CHECK: offload, "device-sycl (spirv64-unknown-unknown:xe-pvc)"
+// CHECK-NOT: sm_70

>From c206cbf625c43d1aaeeef86eec221790838019bb Mon Sep 17 00:00:00 2001
From: srividya sundaram <[email protected]>
Date: Mon, 12 Oct 2026 15:10:29 -0700
Subject: [PATCH 4/6] [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 <[email protected]>
Date: Mon, 12 Oct 2026 18:07:42 -0700
Subject: [PATCH 5/6] [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

>From 3c04b745b46cb8663e29a975891b053947bd0939 Mon Sep 17 00:00:00 2001
From: srividya sundaram <[email protected]>
Date: Mon, 12 Oct 2026 18:09:07 -0700
Subject: [PATCH 6/6] [Clang] Canonicalize an inferred Intel GPU name for every
 offload language

Follow the base change: key an Intel GPU by its canonical name whatever the
offload kind, not only for SYCL.

Assisted-by: Claude Opus 5.5
---
 clang/lib/Driver/Driver.cpp | 10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp
index 426b34e2b3ce9..42561acc10679 100644
--- a/clang/lib/Driver/Driver.cpp
+++ b/clang/lib/Driver/Driver.cpp
@@ -969,13 +969,11 @@ using TripleSet = std::multiset<llvm::Triple>;
 // requested offloading kind and architectures.
 static TripleSet inferOffloadToolchains(Compilation &C,
                                         Action::OffloadKind Kind) {
-  // A SYCL Intel GPU has several accepted spellings, so key it by its 
canonical
-  // name, or --no-offload-arch with another spelling would not remove it.
-  auto canonicalize = [Kind](StringRef Arch) {
+  // An Intel GPU has several spellings, so key it by its canonical name, or
+  // --no-offload-arch with another spelling would not remove it.
+  auto canonicalize = [](StringRef Arch) {
     OffloadArch ID = StringToOffloadArch(Arch);
-    return Kind == Action::OFK_SYCL && ID.isIntelGPU()
-               ? std::string(OffloadArchToString(ID))
-               : Arch.str();
+    return ID.isIntelGPU() ? std::string(OffloadArchToString(ID)) : Arch.str();
   };
   std::set<std::string> Archs;
   for (Arg *A : C.getInputArgs()) {

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

Reply via email to