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

>From 4e07d042e43ba094a8f05c838631d32c24853e84 Mon Sep 17 00:00:00 2001
From: srividya sundaram <[email protected]>
Date: Sat, 12 Sep 2026 19:09:30 -0700
Subject: [PATCH 1/3] [TargetParser][Clang] Parse Intel GPU architecture names

Add support for Intel GPU names in --offload-arch.

#222072 added the mapping from a detected GPU version to its name. This PR adds 
the reverse mapping needed when a user specifies a name through --offload-arch.
Previously, clang recognized only the hardcoded name bmg_g21.

The shared Intel GPU list now recognizes names such as xe-pvc, xe-dg2, bmg_g21, 
and xe_12.60.7. Names for the same GPU IP are treated as aliases, so SYCL 
creates one device job and matches all spellings consistently. 
clang-sycl-linker uses the canonical name for the image and the name expected 
by ocloc.

User-visible changes:
- A device is printed and labelled by its canonical name, e.g. bmg_g21 becomes 
xe-bmg-g21.
- Every listed Intel GPU name is compiled ahead of time with ocloc, as bmg_g21 
already was.
- Products on the same GPU IP become aliases, so 13 GPUKind enumerators are 
removed, e.g. GK_XE_ARL_U is now GK_XE_MTL_U.
- An Intel name is no longer accepted as an NVPTX CPU; -target-cpu bmg_g21 was 
accepted before.
- An Intel name with a target-ID suffix, e.g. xe-pvc:foo, is not turned into a 
device.

Canonicalization is limited to SYCL, the only offload kind that compiles for 
Intel GPUs today.

Selecting the SPIR-V target from an Intel GPU name and diagnosing unknown names 
are handled separately in follow-up PRs.

Assisted-by: Claude Opus 5.5
---
 clang/include/clang/Basic/OffloadArch.h       |  26 ++--
 clang/lib/Basic/OffloadArch.cpp               |  12 +-
 clang/lib/Basic/Targets/NVPTX.h               |  11 +-
 clang/lib/Driver/Driver.cpp                   |  22 ++-
 clang/lib/Driver/ToolChain.cpp                |   4 +
 clang/lib/Driver/ToolChains/Clang.cpp         |   8 +-
 clang/test/Driver/sycl-offload-jit.cpp        |  61 ++++++++-
 .../test/Misc/target-invalid-cpu-note/nvptx.c |   4 +
 .../OffloadTools/clang-sycl-linker/basic.ll   |  13 +-
 .../clang-sycl-linker/ClangSYCLLinker.cpp     |  15 ++-
 clang/unittests/Basic/OffloadArchTest.cpp     |  23 +++-
 .../TargetParser/IntelGPUTargetParser.def     |  59 +++++---
 .../llvm/TargetParser/IntelGPUTargetParser.h  |  41 +++++-
 .../lib/TargetParser/IntelGPUTargetParser.cpp | 127 +++++++++++++++++-
 .../TargetParser/IntelGPUTargetParserTest.cpp | 104 ++++++++++++++
 15 files changed, 473 insertions(+), 57 deletions(-)

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

>From c206cbf625c43d1aaeeef86eec221790838019bb Mon Sep 17 00:00:00 2001
From: srividya sundaram <[email protected]>
Date: Mon, 12 Oct 2026 15:10:29 -0700
Subject: [PATCH 2/3] [TargetParser] Simplify Intel GPU parser comments

Address review comments: say which typo the IGCA_FEATURE_SETS token catches,
note that xe-pvc and xe-pvc-sdv are the only rows sharing a version, and
shorten the parseArch comment.

Assisted-by: Claude Opus 5.5
---
 .../llvm/TargetParser/IntelGPUTargetParser.def   |  5 ++---
 .../llvm/TargetParser/IntelGPUTargetParser.h     | 16 ++++++----------
 2 files changed, 8 insertions(+), 13 deletions(-)

diff --git a/llvm/include/llvm/TargetParser/IntelGPUTargetParser.def 
b/llvm/include/llvm/TargetParser/IntelGPUTargetParser.def
index c8faba2a11e1b..566045539c723 100644
--- a/llvm/include/llvm/TargetParser/IntelGPUTargetParser.def
+++ b/llvm/include/llvm/TargetParser/IntelGPUTargetParser.def
@@ -21,9 +21,8 @@
 //     IGCA_FEATURE_SETS - Token naming the IGCA feature sets the device
 //                         implements: Core (none), Compute ("c"),
 //                         Render ("r"), ComputeExact ("ca") or
-//                         RenderExact ("ra"). It is a token rather than the
-//                         suffix itself so that a typo is a build error;
-//                         getIGCAName maps it onto the spelling.
+//                         RenderExact ("ra"). It is a token, so a misspelled
+//                         one such as Compte fails to build.
 //
 //   INTEL_GPU_COMPAT(NAME, KIND, IGCA_TARGET, IGCA_FEATURE_SETS)
 //     A compatibility name that covers several minor versions, e.g. "xe-dg2",
diff --git a/llvm/include/llvm/TargetParser/IntelGPUTargetParser.h 
b/llvm/include/llvm/TargetParser/IntelGPUTargetParser.h
index 8713de9579b48..1131ccf52e64c 100644
--- a/llvm/include/llvm/TargetParser/IntelGPUTargetParser.h
+++ b/llvm/include/llvm/TargetParser/IntelGPUTargetParser.h
@@ -40,8 +40,8 @@ enum GPUKind : uint8_t {
 /// \return the device name that \p GPUIPVersion identifies, as reported by the
 /// driver, e.g. "xe-pvc". If the table lists no such device, return an empty
 /// string. Only the major and minor versions are looked at, so every revision
-/// of a device resolves to the same name.
-/// If several rows match, the first one in IntelGPUTargetParser.def wins.
+/// of a device resolves to the same name. Only xe-pvc and xe-pvc-sdv share a
+/// version; xe-pvc is returned.
 LLVM_ABI StringRef getArchName(uint32_t GPUIPVersion);
 
 /// \return the numeric name of \p GPUIPVersion, e.g. "xe_35.11.0".
@@ -54,14 +54,10 @@ LLVM_ABI StringRef getArchName(GPUKind Kind);
 /// \return the device \p Name denotes, or GK_NONE for a name this build does
 /// not know.
 ///
-/// Every spelling the user may write is accepted: a human-friendly name such 
as
-/// "xe-pvc", a compatibility name such as "xe-dg2", an alias such as 
"bmg_g21",
-/// and a numeric name such as "xe_12.60.7". Only the human-friendly name is
-/// reported back for a device, so a spelling that is not one canonicalizes to
-/// the one that is. The revision of a numeric name takes no part in the 
lookup,
-/// just as it takes none in getArchName, so "xe_12.60.0" and "xe_12.60.7" name
-/// the same device; the revision may also be omitted. A numeric name for a
-/// device that is not in the table yields GK_NONE like any other unknown name.
+/// \p Name may be a human-friendly name ("xe-pvc"), a compatibility name
+/// ("xe-dg2"), an alias ("bmg_g21") or a numeric name ("xe_12.60.7"). The
+/// revision of a numeric name is ignored and may be omitted, so "xe_12.60",
+/// "xe_12.60.0" and "xe_12.60.7" all denote the same device.
 LLVM_ABI GPUKind parseArch(StringRef Name);
 
 /// \return the IGCA target name to compile \p Kind for, e.g. "xe-pvc" ->

>From 4f6c6b294342e5c61552439b4716082477bceb58 Mon Sep 17 00:00:00 2001
From: srividya sundaram <[email protected]>
Date: Mon, 12 Oct 2026 18:07:42 -0700
Subject: [PATCH 3/3] [TargetParser][Clang] Address review: one name per Intel
 GPU

- Drop aliases: each Intel GPU has one name, plus its numeric name.
  bmg_g21 is no longer accepted; use xe-bmg-g21.
- Remove getIGCAName and fillValidArchList until they have a user.
- Canonicalize Intel GPU names for every offload language, not just SYCL.
- Keep clang-sycl-linker's image label as given; the driver passes the
  canonical name.
- Leave the NVPTX CPU check to a separate change.
- Move the Intel GPU driver tests to sycl-intel-gpu-arch.cpp.

Assisted-by: Claude Opus 5.5
---
 clang/docs/ClangSYCLLinker.md                 |  2 +-
 clang/docs/ReleaseNotes.md                    |  4 ++
 clang/lib/Basic/Targets/NVPTX.h               | 11 +---
 clang/lib/Driver/Driver.cpp                   | 25 ++++----
 clang/lib/Driver/ToolChain.cpp                | 11 ++--
 clang/lib/Driver/ToolChains/Clang.cpp         |  5 +-
 clang/test/Driver/sycl-intel-gpu-arch.cpp     | 55 +++++++++++++++++
 clang/test/Driver/sycl-offload-jit.cpp        | 61 +------------------
 .../test/Misc/target-invalid-cpu-note/nvptx.c |  4 --
 .../OffloadTools/clang-sycl-linker/basic.ll   |  9 ++-
 .../clang-sycl-linker/ClangSYCLLinker.cpp     |  8 +--
 clang/unittests/Basic/OffloadArchTest.cpp     | 12 ++--
 .../TargetParser/IntelGPUTargetParser.def     | 43 ++-----------
 .../llvm/TargetParser/IntelGPUTargetParser.h  | 26 ++------
 .../lib/TargetParser/IntelGPUTargetParser.cpp | 46 +-------------
 .../TargetParser/IntelGPUTargetParserTest.cpp | 49 ++-------------
 16 files changed, 110 insertions(+), 261 deletions(-)
 create mode 100644 clang/test/Driver/sycl-intel-gpu-arch.cpp

diff --git a/clang/docs/ClangSYCLLinker.md b/clang/docs/ClangSYCLLinker.md
index b4f5e751b03bb..c527afa8b41f6 100644
--- a/clang/docs/ClangSYCLLinker.md
+++ b/clang/docs/ClangSYCLLinker.md
@@ -105,7 +105,7 @@ linked device images that are ready to be wrapped and 
linked with host code to
 generate the final executable.
 
 ```console
-clang-sycl-linker --triple spirv64 --arch bmg_g21 input.bc
+clang-sycl-linker --triple spirv64 --arch xe-bmg-g21 input.bc
 ```
 
 ### Linking with Device Libraries
diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 4465396bd6042..8fbca2642b617 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -1171,6 +1171,10 @@ The `alpha.cplusplus.UseAfterLifetimeEnd` checker was 
renamed to `alpha.core.Use
 
 ### SYCL Support
 
+- `--offload-arch` accepts the Intel GPU names from
+  `llvm/TargetParser/IntelGPUTargetParser.def`, e.g. `xe-pvc`, and their 
numeric
+  names, e.g. `xe_12.60.7`. `bmg_g21` is no longer accepted; use `xe-bmg-g21`.
+
 #### Improvements
 
 ## Additional Information
diff --git a/clang/lib/Basic/Targets/NVPTX.h b/clang/lib/Basic/Targets/NVPTX.h
index 45ba8322cf5fc..b6d2bfd320103 100644
--- a/clang/lib/Basic/Targets/NVPTX.h
+++ b/clang/lib/Basic/Targets/NVPTX.h
@@ -135,13 +135,8 @@ class LLVM_LIBRARY_VISIBILITY NVPTXTargetInfo : public 
TargetInfo {
     return TargetInfo::CharPtrBuiltinVaList;
   }
 
-  // StringToOffloadArch recognizes architectures from all vendors. Accept only
-  // the ones NVPTX accepted before, so Sema does not accept an Intel GPU name
-  // as an NVPTX CPU.
   bool isValidCPUName(StringRef Name) const override {
-    OffloadArch Arch = StringToOffloadArch(Name);
-    return Arch.isNVPTX() || Arch.isAMDGPU() || Arch.isAMDGCNSPIRV() ||
-           Arch.isGeneric() || Arch.isUnused();
+    return !StringToOffloadArch(Name).isUnknown();
   }
 
   void fillValidCPUList(SmallVectorImpl<StringRef> &Values) const override {
@@ -149,10 +144,8 @@ class LLVM_LIBRARY_VISIBILITY NVPTXTargetInfo : public 
TargetInfo {
   }
 
   bool setCPU(StringRef Name) override {
-    if (!isValidCPUName(Name))
-      return false;
     GPU = StringToOffloadArch(Name);
-    return true;
+    return !GPU.isUnknown();
   }
 
   void setSupportedOpenCLOpts() override {
diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp
index bbcf88d823776..d48d5339f1934 100644
--- a/clang/lib/Driver/Driver.cpp
+++ b/clang/lib/Driver/Driver.cpp
@@ -3898,19 +3898,17 @@ void Driver::BuildActions(Compilation &C, 
DerivedArgList &Args,
   Args.ClaimAllArgs(options::OPT_cl_ignored_Group);
 }
 
-/// Returns the canonical name for the offloading architecture when using a HIP
-/// or CUDA architecture, or an Intel GPU for SYCL.
+/// Returns the canonical name for the offloading architecture when using a 
HIP,
+/// CUDA or Intel GPU architecture.
 static StringRef getCanonicalArchString(Compilation &C,
                                         const llvm::opt::DerivedArgList &Args,
                                         StringRef ArchStr,
-                                        const llvm::Triple &Triple,
-                                        Action::OffloadKind Kind) {
+                                        const llvm::Triple &Triple) {
   // Lookup the CUDA / HIP architecture string. Only report an error if we were
   // expecting the triple to be only NVPTX / AMDGPU.
   OffloadArch Arch =
       StringToOffloadArch(getProcessorFromTargetID(Triple, ArchStr));
-  // An Intel name takes no target features, so it must parse in full; 
otherwise
-  // "xe-pvc:garbage" would silently become "xe-pvc".
+  // An Intel name takes no target features, so "xe-pvc:foo" is not "xe-pvc".
   if (Arch.isIntel() && ArchStr.contains(':'))
     Arch = OffloadArch::getUnknown();
   if (Triple.isNVPTX() && (Arch.isUnknown() || !Arch.isNVPTX())) {
@@ -3935,10 +3933,9 @@ static StringRef getCanonicalArchString(Compilation &C,
     }
   }
 
-  // A SYCL Intel GPU has several accepted spellings, e.g. an alias or a 
numeric
-  // name, so canonicalize it for the same reason as an NVPTX one: two 
spellings
-  // of one device must be one architecture.
-  if (Arch.isNVPTX() || (Kind == Action::OFK_SYCL && Arch.isIntelGPU()))
+  // Several spellings of one device must be one architecture, e.g. "xe-pvc" 
and
+  // "xe_12.60.7".
+  if (Arch.isNVPTX() || Arch.isIntelGPU())
     return Args.MakeArgStringRef(OffloadArchToString(Arch));
 
   if (Arch.isAMDGPU() || Arch.isAMDGCNSPIRV()) {
@@ -3999,7 +3996,7 @@ Driver::getOffloadArchs(Compilation &C, const 
llvm::opt::DerivedArgList &Args,
 
           for (auto ArchStr : *GPUsOrErr) {
             StringRef CanonicalStr = getCanonicalArchString(
-                C, Args, Args.MakeArgString(ArchStr), TC.getTriple(), Kind);
+                C, Args, Args.MakeArgString(ArchStr), TC.getTriple());
             if (!CanonicalStr.empty())
               Archs.insert(CanonicalStr);
             else
@@ -4007,7 +4004,7 @@ Driver::getOffloadArchs(Compilation &C, const 
llvm::opt::DerivedArgList &Args,
           }
         } else {
           StringRef CanonicalStr =
-              getCanonicalArchString(C, Args, Arch, TC.getTriple(), Kind);
+              getCanonicalArchString(C, Args, Arch, TC.getTriple());
           if (!CanonicalStr.empty())
             Archs.insert(CanonicalStr);
           else
@@ -4020,7 +4017,7 @@ Driver::getOffloadArchs(Compilation &C, const 
llvm::opt::DerivedArgList &Args,
           Archs.clear();
         } else {
           StringRef ArchStr =
-              getCanonicalArchString(C, Args, Arch, TC.getTriple(), Kind);
+              getCanonicalArchString(C, Args, Arch, TC.getTriple());
           Archs.erase(ArchStr);
         }
       }
@@ -4076,7 +4073,7 @@ Driver::getOffloadArchs(Compilation &C, const 
llvm::opt::DerivedArgList &Args,
                                   ? ""
                                   : OffloadArchToString(TripleOffloadArch);
     StringRef CanonicalStr =
-        getCanonicalArchString(C, Args, ArchStr, TC.getTriple(), Kind);
+        getCanonicalArchString(C, Args, ArchStr, TC.getTriple());
     if (!CanonicalStr.empty())
       Archs.insert(CanonicalStr);
   }
diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp
index d7928cd10ea24..ae6087a155211 100644
--- a/clang/lib/Driver/ToolChain.cpp
+++ b/clang/lib/Driver/ToolChain.cpp
@@ -2189,12 +2189,11 @@ llvm::opt::DerivedArgList 
*ToolChain::TranslateXarchArgs(
       Skip = IsDevice;
     } else if (A->getOption().matches(options::OPT_Xarch__)) {
       StringRef Val = A->getValue();
-      // A SYCL Intel GPU has several spellings, so -Xarch_ may name it by
-      // another.
-      NeedTrans = Val == getArchName() || (BA && Val == BA.ArchName) ||
-                  (OFK == Action::OFK_SYCL && BA && BA.Arch.isIntelGPU() &&
-                   StringToOffloadArch(Val) == BA.Arch) ||
-                  isXArchCompatibleTripleArch(Triple, Val);
+      // An Intel GPU has several spellings, so -Xarch_ may name it by another.
+      NeedTrans =
+          Val == getArchName() || (BA && Val == BA.ArchName) ||
+          (BA && BA.Arch.isIntelGPU() && StringToOffloadArch(Val) == BA.Arch) 
||
+          isXArchCompatibleTripleArch(Triple, Val);
       Skip = !NeedTrans;
     }
     if (NeedTrans || Skip)
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp 
b/clang/lib/Driver/ToolChains/Clang.cpp
index 7071ee6b3bebe..7258a86f84282 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -9864,11 +9864,10 @@ void LinkerWrapper::ConstructJob(Compilation &C, const 
JobAction &JA,
 
       // If the user explicitly requested it via `--offload-arch` we should
       // extract it from any static libraries if present.
-      // A SYCL Intel GPU is requested by its canonical name, the one its 
device
-      // images are labeled with, whichever spelling the user wrote.
+      // Request an Intel GPU by the canonical name its images are labeled 
with.
       for (StringRef Arg : ToolChainArgs.getAllArgValues(OPT_offload_arch_EQ)) 
{
         OffloadArch ID = StringToOffloadArch(Arg);
-        if (Kind == Action::OFK_SYCL && ID.isIntelGPU())
+        if (ID.isIntelGPU())
           Arg = OffloadArchToString(ID);
         CmdArgs.emplace_back(Args.MakeArgString("--should-extract=" + Arg));
       }
diff --git a/clang/test/Driver/sycl-intel-gpu-arch.cpp 
b/clang/test/Driver/sycl-intel-gpu-arch.cpp
new file mode 100644
index 0000000000000..9818d18647ce8
--- /dev/null
+++ b/clang/test/Driver/sycl-intel-gpu-arch.cpp
@@ -0,0 +1,55 @@
+/// Tests for Intel GPU names in --offload-arch.
+
+/// A device name and its numeric name are one architecture, spelled with the
+/// device name.
+// RUN: %clang -ccc-print-phases --target=x86_64-unknown-linux-gnu -fsycl \
+// RUN:   --offload-targets=spirv64-unknown-unknown --offload-arch=xe-bmg-g21 \
+// RUN:   --offload-arch=xe_20.1.0 -c %s 2>&1 \
+// RUN:   | FileCheck -check-prefixes=CHK-SPELLINGS %s
+// CHK-SPELLINGS-NOT: offload, "device-sycl
+// CHK-SPELLINGS: offload, "device-sycl (spirv64-unknown-unknown:xe-bmg-g21)"
+// CHK-SPELLINGS-NOT: offload, "device-sycl
+
+/// Removing either spelling removes the device.
+// RUN: %clang -ccc-print-phases --target=x86_64-unknown-linux-gnu -fsycl \
+// RUN:   --offload-targets=spirv64-unknown-unknown --offload-arch=xe-bmg-g21 \
+// RUN:   --offload-arch=generic --no-offload-arch=xe_20.1.0 -c %s 2>&1 \
+// RUN:   | FileCheck -check-prefixes=CHK-NO-ARCH %s
+// RUN: %clang -ccc-print-phases --target=x86_64-unknown-linux-gnu -fsycl \
+// RUN:   --offload-targets=spirv64-unknown-unknown --offload-arch=xe_20.1.0 \
+// RUN:   --offload-arch=generic --no-offload-arch=xe-bmg-g21 -c %s 2>&1 \
+// RUN:   | FileCheck -check-prefixes=CHK-NO-ARCH %s
+// CHK-NO-ARCH-NOT: bmg
+// CHK-NO-ARCH: offload, "device-sycl (spirv64-unknown-unknown:generic)"
+// CHK-NO-ARCH-NOT: bmg
+
+/// An Intel GPU name takes no target-ID features, so a suffix is not dropped 
to
+/// turn the name into a device.
+// RUN: %clang -ccc-print-phases --target=x86_64-unknown-linux-gnu -fsycl \
+// RUN:   --offload-targets=spirv64-unknown-unknown --offload-arch=xe-pvc:foo 
-c %s 2>&1 \
+// RUN:   | FileCheck -check-prefixes=CHK-SUFFIX %s
+// CHK-SUFFIX: offload, "device-sycl (spirv64-unknown-unknown:xe-pvc:foo)"
+
+/// -Xarch_ may name an Intel GPU by either spelling.
+// RUN: %clang -### --target=x86_64-unknown-linux-gnu -fsycl \
+// RUN:   --offload-targets=spirv64-unknown-unknown --offload-arch=xe_20.1.0 \
+// RUN:   -Xarch_xe-bmg-g21 -DBMG -Xarch_xe-pvc -DPVC -c %s 2>&1 \
+// RUN:   | FileCheck -check-prefixes=CHK-XARCH %s
+// CHK-XARCH: "-fsycl-is-device"
+// CHK-XARCH-SAME: "-D" "BMG"
+// CHK-XARCH-NOT: "PVC"
+
+/// A static library's device code is requested by the device name.
+// RUN: %clang -### --target=x86_64-unknown-linux-gnu -fsycl \
+// RUN:   --offload-targets=spirv64-unknown-unknown --offload-arch=xe_20.1.0 
%s 2>&1 \
+// RUN:   | FileCheck -check-prefixes=CHK-EXTRACT %s
+// CHK-EXTRACT: clang-linker-wrapper{{.*}}"--should-extract=xe-bmg-g21"
+
+/// The same holds for any offload language, e.g. OpenMP.
+// RUN: %clang -ccc-print-phases --target=x86_64-unknown-linux-gnu 
-fopenmp=libomp \
+// RUN:   --offload-targets=spirv64-intel --offload-arch=xe-bmg-g21 \
+// RUN:   --offload-arch=xe_20.1.0 -c %s 2>&1 \
+// RUN:   | FileCheck -check-prefixes=CHK-OPENMP %s
+// CHK-OPENMP-NOT: offload, "device-openmp
+// CHK-OPENMP: offload, "device-openmp (spirv64-intel:xe-bmg-g21)"
+// CHK-OPENMP-NOT: offload, "device-openmp
diff --git a/clang/test/Driver/sycl-offload-jit.cpp 
b/clang/test/Driver/sycl-offload-jit.cpp
index cb4283db51d25..82733ccd2bc6f 100644
--- a/clang/test/Driver/sycl-offload-jit.cpp
+++ b/clang/test/Driver/sycl-offload-jit.cpp
@@ -90,68 +90,11 @@
 // RUN: %clang -ccc-print-phases --target=x86_64-unknown-linux-gnu -fsycl 
-fno-gpu-rdc \
 // RUN:   --offload-targets=spirv64-unknown-unknown --offload-arch=generic 
--offload-arch=bmg_g21 \
 // RUN:   -c %s 2>&1 | FileCheck -check-prefixes=CHK-PHASES-NORDC-ARCHS %s
-// CHK-PHASES-NORDC-ARCHS: 7: offload, "device-sycl 
(spirv64-unknown-unknown:generic)" {6}, ir
-// CHK-PHASES-NORDC-ARCHS: 12: offload, "device-sycl 
(spirv64-unknown-unknown:xe-bmg-g21)" {11}, ir
+// CHK-PHASES-NORDC-ARCHS: 7: offload, "device-sycl 
(spirv64-unknown-unknown:bmg_g21)" {6}, ir
+// CHK-PHASES-NORDC-ARCHS: 12: offload, "device-sycl 
(spirv64-unknown-unknown:generic)" {11}, ir
 // CHK-PHASES-NORDC-ARCHS-NEXT: 13: llvm-offload-binary, {7, 12}, image, 
(device-sycl)
 // CHK-PHASES-NORDC-ARCHS-NEXT: 14: clang-linker-wrapper, {13}, sycl-fatbin, 
(device-sycl)
 
-/// Every spelling of an Intel GPU names one architecture, spelled canonically,
-/// so several spellings of one device build it once.
-// RUN: %clang -ccc-print-phases --target=x86_64-unknown-linux-gnu -fsycl \
-// RUN:   --offload-targets=spirv64-unknown-unknown --offload-arch=bmg_g21 \
-// RUN:   --offload-arch=xe-bmg-g21 --offload-arch=xe_20.1.0 -c %s 2>&1 \
-// RUN:   | FileCheck -check-prefixes=CHK-INTEL-SPELLINGS %s
-// CHK-INTEL-SPELLINGS-NOT: offload, "device-sycl
-// CHK-INTEL-SPELLINGS: offload, "device-sycl 
(spirv64-unknown-unknown:xe-bmg-g21)"
-// CHK-INTEL-SPELLINGS-NOT: offload, "device-sycl
-
-/// Products built on one GPU IP version are one architecture too.
-// RUN: %clang -ccc-print-phases --target=x86_64-unknown-linux-gnu -fsycl \
-// RUN:   --offload-targets=spirv64-unknown-unknown --offload-arch=xe-arl-u \
-// RUN:   --offload-arch=xe-mtl-u --offload-arch=xe_12.70 -c %s 2>&1 \
-// RUN:   | FileCheck -check-prefixes=CHK-INTEL-SAME-IP %s
-// CHK-INTEL-SAME-IP-NOT: offload, "device-sycl
-// CHK-INTEL-SAME-IP: offload, "device-sycl (spirv64-unknown-unknown:xe-mtl-u)"
-// CHK-INTEL-SAME-IP-NOT: offload, "device-sycl
-
-/// Removing any spelling of a device removes the device.
-// RUN: %clang -ccc-print-phases --target=x86_64-unknown-linux-gnu -fsycl \
-// RUN:   --offload-targets=spirv64-unknown-unknown --offload-arch=xe-bmg-g21 \
-// RUN:   --offload-arch=generic --no-offload-arch=bmg_g21 -c %s 2>&1 \
-// RUN:   | FileCheck -check-prefixes=CHK-INTEL-NO-ARCH %s
-// RUN: %clang -ccc-print-phases --target=x86_64-unknown-linux-gnu -fsycl \
-// RUN:   --offload-targets=spirv64-unknown-unknown --offload-arch=bmg_g21 \
-// RUN:   --offload-arch=generic --no-offload-arch=xe_20.1.0 -c %s 2>&1 \
-// RUN:   | FileCheck -check-prefixes=CHK-INTEL-NO-ARCH %s
-// CHK-INTEL-NO-ARCH-NOT: bmg
-// CHK-INTEL-NO-ARCH: offload, "device-sycl (spirv64-unknown-unknown:generic)"
-// CHK-INTEL-NO-ARCH-NOT: bmg
-
-/// An Intel GPU name takes no target-ID features, so a suffix is not dropped 
to
-/// turn the name into a device.
-// RUN: %clang -ccc-print-phases --target=x86_64-unknown-linux-gnu -fsycl \
-// RUN:   --offload-targets=spirv64-unknown-unknown --offload-arch=xe-pvc:foo 
-c %s 2>&1 \
-// RUN:   | FileCheck -check-prefixes=CHK-INTEL-SUFFIX %s
-// CHK-INTEL-SUFFIX: offload, "device-sycl 
(spirv64-unknown-unknown:xe-pvc:foo)"
-
-/// -Xarch_ may name an Intel GPU by any of its spellings.
-// RUN: %clang -### --target=x86_64-unknown-linux-gnu -fsycl \
-// RUN:   --offload-targets=spirv64-unknown-unknown --offload-arch=bmg_g21 \
-// RUN:   -Xarch_bmg_g21 -DBMG -Xarch_xe-pvc -DPVC -c %s 2>&1 \
-// RUN:   | FileCheck -check-prefixes=CHK-INTEL-XARCH %s
-// CHK-INTEL-XARCH: "-fsycl-is-device"
-// CHK-INTEL-XARCH-SAME: "-D" "BMG"
-// CHK-INTEL-XARCH-NOT: "PVC"
-
-/// A static library's device code is requested by the canonical name.
-// RUN: %clang -### --target=x86_64-unknown-linux-gnu -fsycl \
-// RUN:   --offload-targets=spirv64-unknown-unknown --offload-arch=bmg_g21 %s 
2>&1 \
-// RUN:   | FileCheck -check-prefixes=CHK-INTEL-EXTRACT %s
-// RUN: %clang -### --target=x86_64-unknown-linux-gnu -fsycl \
-// RUN:   --offload-targets=spirv64-unknown-unknown --offload-arch=xe_20.1.0 
%s 2>&1 \
-// RUN:   | FileCheck -check-prefixes=CHK-INTEL-EXTRACT %s
-// CHK-INTEL-EXTRACT: clang-linker-wrapper{{.*}}"--should-extract=xe-bmg-g21"
-
 /// Multiple device triples are not supported today in non-RDC mode.
 // RUN: not %clang -### --target=x86_64-unknown-linux-gnu -fsycl -fno-gpu-rdc \
 // RUN:   --offload-targets=spirv64-unknown-unknown,spirv32-unknown-unknown -c 
%s 2>&1 \
diff --git a/clang/test/Misc/target-invalid-cpu-note/nvptx.c 
b/clang/test/Misc/target-invalid-cpu-note/nvptx.c
index b2a38b6b26825..20dbd8dc6aa3b 100644
--- a/clang/test/Misc/target-invalid-cpu-note/nvptx.c
+++ b/clang/test/Misc/target-invalid-cpu-note/nvptx.c
@@ -2,10 +2,6 @@
 // previous check finished matching (specifically, caret is not treated as
 // matching a start of line when used like this in FileCheck).
 
-// An Intel GPU name is an offload architecture but never an NVPTX CPU.
-// RUN: not %clang_cc1 -triple nvptx64-nvidia-cuda -target-cpu xe-pvc 
-fsyntax-only %s 2>&1 | FileCheck %s --check-prefix=INTEL
-// INTEL: error: unknown target CPU 'xe-pvc'
-
 // RUN: not %clang_cc1 -triple nvptx--- -target-cpu not-a-cpu -fsyntax-only %s 
2>&1 | FileCheck %s --implicit-check-not={{[a-zA-Z0-9]}}
 // CHECK: error: unknown target CPU 'not-a-cpu'
 // CHECK-NEXT: note: valid target CPU values are:
diff --git a/clang/test/OffloadTools/clang-sycl-linker/basic.ll 
b/clang/test/OffloadTools/clang-sycl-linker/basic.ll
index 0376e7bf88338..23c17f3bb07f4 100644
--- a/clang/test/OffloadTools/clang-sycl-linker/basic.ll
+++ b/clang/test/OffloadTools/clang-sycl-linker/basic.ll
@@ -109,7 +109,7 @@
 ;
 ; Test AOT compilation for an Intel GPU.
 ; Test that IMG_Object image kind is set for AOT compilation (Intel GPU).
-; RUN: clang-sycl-linker --dry-run -v --module-split-mode=link_unit 
-arch=bmg_g21 %t/input1.bc %t/input2.bc -o %t/aot-gpu.out 2>&1 \
+; RUN: clang-sycl-linker --dry-run -v --module-split-mode=link_unit 
-arch=xe-bmg-g21 %t/input1.bc %t/input2.bc -o %t/aot-gpu.out 2>&1 \
 ; RUN:     --ocloc-options="-a -b" \
 ; RUN:   | FileCheck %s --check-prefix=AOT-INTEL-GPU
 ; AOT-INTEL-GPU:      link: inputs: {{.*}}.bc, {{.*}}.bc output: 
[[LLVMLINKOUT:.*]].bc
@@ -118,19 +118,18 @@
 ; AOT-INTEL-GPU-NEXT: sycl-bundle: image kind: o, triple: spirv64, arch: 
xe-bmg-g21
 ; AOT-INTEL-GPU-NOT:  {{.+}}
 ;
-; Test that every accepted spelling of an Intel GPU reaches ocloc as ocloc's 
own.
+; Test that an Intel GPU name, or its numeric name, reaches ocloc as ocloc's 
own.
 ; RUN: clang-sycl-linker --dry-run -v --module-split-mode=link_unit 
-arch=xe-bmg-g21 %t/input1.bc -o %t/aot-gpu.out 2>&1 \
 ; RUN:   | FileCheck %s --check-prefix=AOT-INTEL-NAME
 ; RUN: clang-sycl-linker --dry-run -v --module-split-mode=link_unit 
-arch=xe_20.1.0 %t/input1.bc -o %t/aot-gpu.out 2>&1 \
 ; RUN:   | FileCheck %s --check-prefix=AOT-INTEL-NAME
 ; AOT-INTEL-NAME: "{{.*}}ocloc{{.*}}" {{.*}}-device bmg_g21 {{.*}}-output
-; AOT-INTEL-NAME: sycl-bundle: image kind: o, triple: spirv64, arch: xe-bmg-g21
 ; RUN: clang-sycl-linker --dry-run -v --module-split-mode=link_unit 
-arch=xe-pvc %t/input1.bc -o %t/aot-gpu.out 2>&1 \
 ; RUN:   | FileCheck %s --check-prefix=AOT-INTEL-PVC
 ; AOT-INTEL-PVC: "{{.*}}ocloc{{.*}}" {{.*}}-device pvc {{.*}}-output
 
 ; Test that all --ocloc-options are passed to ocloc, even if they contain 
spaces or quotes.
-; RUN: clang-sycl-linker --dry-run -v --module-split-mode=link_unit 
-arch=bmg_g21 %t/input1.bc -o %t/aot-gpu.out 2>&1 \
+; RUN: clang-sycl-linker --dry-run -v --module-split-mode=link_unit 
-arch=xe-bmg-g21 %t/input1.bc -o %t/aot-gpu.out 2>&1 \
 ; RUN:     --ocloc-options="-a -b" --ocloc-options=-c --ocloc-options="d" 
--ocloc-options='"-e -f"' \
 ; RUN:   | FileCheck %s --check-prefix=AOT-INTEL-OCLOC-OPTIONS
 ; AOT-INTEL-OCLOC-OPTIONS: "{{.*}}ocloc{{.*}}" {{.*}}-device bmg_g21 -a -b -c 
d "-e -f"
@@ -151,7 +150,7 @@
 ; current directory (with a unique suffix to avoid collisions between
 ; concurrent invocations sharing an output basename).
 ; RUN: rm -rf %t/outdir && mkdir -p %t/outdir
-; RUN: clang-sycl-linker --dry-run -v --module-split-mode=link_unit 
-arch=bmg_g21 %t/input1.bc -o %t/outdir/nested.out 2>&1 \
+; RUN: clang-sycl-linker --dry-run -v --module-split-mode=link_unit 
-arch=xe-bmg-g21 %t/input1.bc -o %t/outdir/nested.out 2>&1 \
 ; RUN:   | FileCheck %s --check-prefix=AOT-STEM-BASENAME
 ; AOT-STEM-BASENAME:      LLVM backend: input: {{.*}}.bc, output: 
[[SPVSTEM:nested.*]].spv
 ; AOT-STEM-BASENAME-NEXT: "{{.*}}ocloc{{.*}}" {{.*}}-output [[SPVSTEM]].out 
-file [[SPVSTEM]].spv
diff --git a/clang/tools/clang-sycl-linker/ClangSYCLLinker.cpp 
b/clang/tools/clang-sycl-linker/ClangSYCLLinker.cpp
index 01463c15aa0db..50f1d55450cfd 100644
--- a/clang/tools/clang-sycl-linker/ClangSYCLLinker.cpp
+++ b/clang/tools/clang-sycl-linker/ClangSYCLLinker.cpp
@@ -717,7 +717,7 @@ static Error runAOTCompileIntelGPU(StringRef InputFile, 
StringRef OutputFile,
   StringRef Arch(Args.getLastArgValue(OPT_arch_EQ));
   assert(!Arch.empty() && "Arch must be specified for AOT compilation");
   // ocloc spells a device without the "xe-" prefix and with "_" between words,
-  // e.g. "bmg_g21" for "xe-bmg-g21", so translate any accepted spelling.
+  // e.g. "bmg_g21" for "xe-bmg-g21".
   StringRef Canonical = OffloadArchToString(StringToOffloadArch(Arch));
   [[maybe_unused]] bool HasPrefix = Canonical.consume_front("xe-");
   assert(HasPrefix && "Intel GPU name without the xe- prefix");
@@ -1052,12 +1052,8 @@ static Error 
runSYCLLink(ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs,
     TheImage.TheOffloadKind = OFK_SYCL;
     TheImage.StringData["triple"] =
         Args.MakeArgString(Result.TargetTriple.str());
-    // Label an Intel GPU image with its canonical name, whichever spelling was
-    // given, so that one device's images always carry one arch.
-    StringRef Arch = Args.getLastArgValue(OPT_arch_EQ);
-    OffloadArch OA = StringToOffloadArch(Arch);
     TheImage.StringData["arch"] =
-        OA.isIntelGPU() ? OffloadArchToString(OA) : Args.MakeArgString(Arch);
+        Args.MakeArgString(Args.getLastArgValue(OPT_arch_EQ));
     TheImage.StringData["symbols"] = SI.Symbols;
     TheImage.Image = std::move(*FileOrErr);
     Images.emplace_back(std::move(TheImage));
diff --git a/clang/unittests/Basic/OffloadArchTest.cpp 
b/clang/unittests/Basic/OffloadArchTest.cpp
index 980a88aba6114..ac87d8395eb26 100644
--- a/clang/unittests/Basic/OffloadArchTest.cpp
+++ b/clang/unittests/Basic/OffloadArchTest.cpp
@@ -66,21 +66,19 @@ TEST(OffloadArchTest, RoundTrip) {
   }
 }
 
-// A spelling that is not the architecture name still denotes the device, and
-// canonicalizes to that name rather than round-tripping to itself.
-TEST(OffloadArchTest, IntelGPUAliases) {
-  // An alias, here the spelling accepted before the Intel GPU list existed.
-  EXPECT_EQ(parse("bmg_g21"), parse("xe-bmg-g21"));
-  // A numeric name, whose revision takes no part in the lookup.
+// A numeric name denotes the device, and canonicalizes to the device name.
+TEST(OffloadArchTest, IntelGPUNumericNames) {
+  // The revision takes no part in the lookup.
   EXPECT_EQ(parse("xe_12.60.0"), parse("xe-pvc"));
   EXPECT_EQ(parse("xe_12.60.7"), parse("xe-pvc"));
   EXPECT_EQ(parse("xe_12.60"), parse("xe-pvc"));
-  EXPECT_STREQ(OffloadArchToString(parse("bmg_g21")), "xe-bmg-g21");
   EXPECT_STREQ(OffloadArchToString(parse("xe_12.60.7")), "xe-pvc");
 
   // A well-formed numeric name for a device this build does not know is as
   // unknown as any other unknown name.
   EXPECT_TRUE(parse("xe_99.99.0").isUnknown());
+  // So is the spelling clang accepted before the Intel GPU list existed.
+  EXPECT_TRUE(parse("bmg_g21").isUnknown());
 }
 
 TEST(OffloadArchTest, Defaults) {
diff --git a/llvm/include/llvm/TargetParser/IntelGPUTargetParser.def 
b/llvm/include/llvm/TargetParser/IntelGPUTargetParser.def
index 566045539c723..d722d999444b6 100644
--- a/llvm/include/llvm/TargetParser/IntelGPUTargetParser.def
+++ b/llvm/include/llvm/TargetParser/IntelGPUTargetParser.def
@@ -21,8 +21,7 @@
 //     IGCA_FEATURE_SETS - Token naming the IGCA feature sets the device
 //                         implements: Core (none), Compute ("c"),
 //                         Render ("r"), ComputeExact ("ca") or
-//                         RenderExact ("ra"). It is a token, so a misspelled
-//                         one such as Compte fails to build.
+//                         RenderExact ("ra").
 //
 //   INTEL_GPU_COMPAT(NAME, KIND, IGCA_TARGET, IGCA_FEATURE_SETS)
 //     A compatibility name that covers several minor versions, e.g. "xe-dg2",
@@ -31,24 +30,14 @@
 //     offload-arch utility never prints one, but they are legal --offload-arch
 //     values. The columns mean the same as above.
 //
-//   INTEL_GPU_ALIAS(NAME, KIND)
-//     A further name for a device that already has a row: "bmg_g21", which
-//     --offload-arch accepted before the list existed, or another product
-//     built on the same GPU IP version, e.g. "xe-arl-u" for "xe-mtl-u". Code
-//     for one GPU IP version is the same whichever product runs it, so these
-//     are one architecture. An alias declares no kind of its own and is never
-//     printed, so a device keeps one canonical name; it only widens what
-//     --offload-arch accepts.
-//
 // A device is keyed by its major and minor version alone. The revision
 // component of the GPU IP version is deliberately left out of the key, so that
 // every revision of a device shares one name and one IGCA target.
 //
-// Products that share a major and a minor version form one INTEL_GPU row, 
named
-// after the product the offload-arch utility prints; the other products are
-// aliases. The exception is "xe-pvc-sdv": it has the same major and minor
-// version as "xe-pvc", but the AOT compiler generates different code for it, 
so
-// it gets its own row.
+// Products that share a major and a minor version have one row, named after
+// the product the offload-arch utility prints. The exception is "xe-pvc-sdv":
+// it has the same major and minor version as "xe-pvc", but the AOT compiler
+// generates different code for it, so it gets its own row.
 //
 // Devices without a published name are left out on purpose; offload-arch names
 // them by GPU IP version, as "xe_*.*.*". A device gets a row only once it has
@@ -96,27 +85,5 @@ INTEL_GPU_COMPAT("xe-bmg", XE_BMG, 40, Render)
 INTEL_GPU_COMPAT("xe-mtl", XE_MTL, 30, Render)
 INTEL_GPU_COMPAT("xe-dg2", XE_DG2, 15, RenderExact)
 
-// Aliases, which are further names of a device named above
-#ifndef INTEL_GPU_ALIAS
-#define INTEL_GPU_ALIAS(NAME, KIND)
-#endif
-
-// Accepted before this list existed; to be removed in favor of "xe-bmg-g21".
-INTEL_GPU_ALIAS("bmg_g21",     XE_BMG_G21)
-INTEL_GPU_ALIAS("xe-nvl-h",    XE_NVL_U)
-INTEL_GPU_ALIAS("xe-nvl-hx",   XE_NVL_S)
-INTEL_GPU_ALIAS("xe-nvl-ul",   XE_NVL_S)
-INTEL_GPU_ALIAS("xe-arl-u",    XE_MTL_U)
-INTEL_GPU_ALIAS("xe-arl-s",    XE_MTL_U)
-INTEL_GPU_ALIAS("xe-dg2-g12",  XE_ACM_G12)
-INTEL_GPU_ALIAS("xe-dg2-g11",  XE_ACM_G11)
-INTEL_GPU_ALIAS("xe-ats-m75",  XE_ACM_G11)
-INTEL_GPU_ALIAS("xe-dg2-g10",  XE_ACM_G10)
-INTEL_GPU_ALIAS("xe-ats-m150", XE_ACM_G10)
-INTEL_GPU_ALIAS("xe-rpl-p",    XE_ADL_P)
-INTEL_GPU_ALIAS("xe-rpl-s",    XE_ADL_S)
-INTEL_GPU_ALIAS("xe-tgl",      XE_TGLLP)
-
 #undef INTEL_GPU
 #undef INTEL_GPU_COMPAT
-#undef INTEL_GPU_ALIAS
diff --git a/llvm/include/llvm/TargetParser/IntelGPUTargetParser.h 
b/llvm/include/llvm/TargetParser/IntelGPUTargetParser.h
index 1131ccf52e64c..940a6b36f6c84 100644
--- a/llvm/include/llvm/TargetParser/IntelGPUTargetParser.h
+++ b/llvm/include/llvm/TargetParser/IntelGPUTargetParser.h
@@ -20,7 +20,6 @@
 #include <string>
 
 namespace llvm {
-template <typename T> class SmallVectorImpl;
 
 namespace IntelGPU {
 
@@ -44,35 +43,22 @@ enum GPUKind : uint8_t {
 /// version; xe-pvc is returned.
 LLVM_ABI StringRef getArchName(uint32_t GPUIPVersion);
 
-/// \return the numeric name of \p GPUIPVersion, e.g. "xe_35.11.0".
-LLVM_ABI std::string getNumericArchName(uint32_t GPUIPVersion);
-
 /// \return the human-friendly name of \p Kind, e.g. "xe-pvc", or an empty
 /// string for GK_NONE.
 LLVM_ABI StringRef getArchName(GPUKind Kind);
 
+/// \return the numeric name of \p GPUIPVersion, e.g. "xe_35.11.0".
+LLVM_ABI std::string getNumericArchName(uint32_t GPUIPVersion);
+
 /// \return the device \p Name denotes, or GK_NONE for a name this build does
 /// not know.
 ///
 /// \p Name may be a human-friendly name ("xe-pvc"), a compatibility name
-/// ("xe-dg2"), an alias ("bmg_g21") or a numeric name ("xe_12.60.7"). The
-/// revision of a numeric name is ignored and may be omitted, so "xe_12.60",
-/// "xe_12.60.0" and "xe_12.60.7" all denote the same device.
+/// ("xe-dg2") or a numeric name ("xe_12.60.7"). The revision of a numeric name
+/// is ignored and may be omitted, so "xe_12.60", "xe_12.60.0" and "xe_12.60.7"
+/// all denote the same device.
 LLVM_ABI GPUKind parseArch(StringRef Name);
 
-/// \return the IGCA target name to compile \p Kind for, e.g. "xe-pvc" ->
-/// "igca_20ca", or an empty string for GK_NONE. This is the spelling
-/// -target-cpu is invoked with.
-///
-/// The name is the numeric IGCA target followed by the suffix of the feature
-/// sets: igca_60 is the core features, igca_60c adds the compute features, and
-/// igca_60ca is exact, meaning that only a device at that target will do.
-LLVM_ABI StringRef getIGCAName(GPUKind Kind);
-
-/// Append every architecture name this build accepts, for diagnostics that
-/// offer the user an alternative to a name that did not parse.
-LLVM_ABI void fillValidArchList(SmallVectorImpl<StringRef> &Values);
-
 } // namespace IntelGPU
 } // namespace llvm
 
diff --git a/llvm/lib/TargetParser/IntelGPUTargetParser.cpp 
b/llvm/lib/TargetParser/IntelGPUTargetParser.cpp
index 044daddc868f1..2f29fa2f28216 100644
--- a/llvm/lib/TargetParser/IntelGPUTargetParser.cpp
+++ b/llvm/lib/TargetParser/IntelGPUTargetParser.cpp
@@ -11,7 +11,6 @@
 
//===----------------------------------------------------------------------===//
 
 #include "llvm/TargetParser/IntelGPUTargetParser.h"
-#include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringSwitch.h"
 #include "llvm/ADT/Twine.h"
 #include "llvm/Support/ErrorHandling.h"
@@ -87,7 +86,7 @@ StringRef llvm::IntelGPU::getArchName(GPUKind Kind) {
     return NAME;
 #include "llvm/TargetParser/IntelGPUTargetParser.def"
   }
-  llvm_unreachable("invalid Intel GPU GPUKind");
+  llvm_unreachable("invalid Intel GPU kind");
 }
 
 // Read a numeric architecture name, e.g. "xe_12.60.7", into the GPU IP version
@@ -126,7 +125,6 @@ GPUKind llvm::IntelGPU::parseArch(StringRef Name) {
   .Case(NAME, GK_##KIND)
 #define INTEL_GPU_COMPAT(NAME, KIND, IGCA_TARGET, IGCA_FEATURE_SETS)           
\
   .Case(NAME, GK_##KIND)
-#define INTEL_GPU_ALIAS(NAME, KIND) .Case(NAME, GK_##KIND)
 #include "llvm/TargetParser/IntelGPUTargetParser.def"
                      .Default(GK_NONE);
   if (Kind != GK_NONE)
@@ -140,45 +138,3 @@ GPUKind llvm::IntelGPU::parseArch(StringRef Name) {
     return getKindForVersion(GPUIPVersion);
   return GK_NONE;
 }
-
-// The suffix each IGCA_FEATURE_SETS token contributes to a target name.
-#define IGCA_FEATURE_SETS_Core ""
-#define IGCA_FEATURE_SETS_Compute "c"
-#define IGCA_FEATURE_SETS_Render "r"
-#define IGCA_FEATURE_SETS_ComputeExact "ca"
-#define IGCA_FEATURE_SETS_RenderExact "ra"
-
-StringRef llvm::IntelGPU::getIGCAName(GPUKind Kind) {
-  // Unlike the NVPTX virtual architecture name, this is not a column of its
-  // own: the target and the feature sets already spell it, and a column would
-  // let the three disagree.
-  switch (Kind) {
-  case GK_NONE:
-    return "";
-#define INTEL_GPU(NAME, KIND, MAJOR, MINOR, IGCA_TARGET, IGCA_FEATURE_SETS)    
\
-  case GK_##KIND:                                                              
\
-    return "igca_" #IGCA_TARGET IGCA_FEATURE_SETS_##IGCA_FEATURE_SETS;
-#define INTEL_GPU_COMPAT(NAME, KIND, IGCA_TARGET, IGCA_FEATURE_SETS)           
\
-  case GK_##KIND:                                                              
\
-    return "igca_" #IGCA_TARGET IGCA_FEATURE_SETS_##IGCA_FEATURE_SETS;
-#include "llvm/TargetParser/IntelGPUTargetParser.def"
-  }
-  llvm_unreachable("invalid Intel GPU GPUKind");
-}
-
-#undef IGCA_FEATURE_SETS_Core
-#undef IGCA_FEATURE_SETS_Compute
-#undef IGCA_FEATURE_SETS_Render
-#undef IGCA_FEATURE_SETS_ComputeExact
-#undef IGCA_FEATURE_SETS_RenderExact
-
-void llvm::IntelGPU::fillValidArchList(SmallVectorImpl<StringRef> &Values) {
-  // An alias is a name the user may write, so it belongs here even though it 
is
-  // never the name reported for a device.
-#define INTEL_GPU(NAME, KIND, MAJOR, MINOR, IGCA_TARGET, IGCA_FEATURE_SETS)    
\
-  Values.push_back(NAME);
-#define INTEL_GPU_COMPAT(NAME, KIND, IGCA_TARGET, IGCA_FEATURE_SETS)           
\
-  Values.push_back(NAME);
-#define INTEL_GPU_ALIAS(NAME, KIND) Values.push_back(NAME);
-#include "llvm/TargetParser/IntelGPUTargetParser.def"
-}
diff --git a/llvm/unittests/TargetParser/IntelGPUTargetParserTest.cpp 
b/llvm/unittests/TargetParser/IntelGPUTargetParserTest.cpp
index 147a3e3b4485c..e04e93dc69e7a 100644
--- a/llvm/unittests/TargetParser/IntelGPUTargetParserTest.cpp
+++ b/llvm/unittests/TargetParser/IntelGPUTargetParserTest.cpp
@@ -7,8 +7,6 @@
 
//===----------------------------------------------------------------------===//
 
 #include "llvm/TargetParser/IntelGPUTargetParser.h"
-#include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/SmallVector.h"
 #include "gtest/gtest.h"
 #include <cassert>
 
@@ -87,14 +85,13 @@ TEST(IntelGPUTargetParserTest, KindArchNames) {
 }
 
 TEST(IntelGPUTargetParserTest, ParseArch) {
-  // A human-friendly name, a compatibility name, and an alias.
+  // A human-friendly name and a compatibility name.
   EXPECT_EQ(IntelGPU::parseArch("xe-pvc"), IntelGPU::GK_XE_PVC);
   EXPECT_EQ(IntelGPU::parseArch("xe-dg2"), IntelGPU::GK_XE_DG2);
-  EXPECT_EQ(IntelGPU::parseArch("bmg_g21"), IntelGPU::GK_XE_BMG_G21);
-  // Products built on one GPU IP version are one device, named after the one
-  // the offload-arch utility prints.
-  EXPECT_EQ(IntelGPU::parseArch("xe-arl-u"), IntelGPU::GK_XE_MTL_U);
-  EXPECT_EQ(IntelGPU::parseArch("xe-ats-m150"), IntelGPU::GK_XE_ACM_G10);
+  // Each device has one name; another product on its GPU IP version is named
+  // by its numeric name instead.
+  EXPECT_EQ(IntelGPU::parseArch("bmg_g21"), IntelGPU::GK_NONE);
+  EXPECT_EQ(IntelGPU::parseArch("xe-arl-u"), IntelGPU::GK_NONE);
   EXPECT_EQ(IntelGPU::parseArch("xe_12.70"), IntelGPU::GK_XE_MTL_U);
   // Except PVC-SDV, which the AOT compiler builds for its own stepping.
   EXPECT_EQ(IntelGPU::parseArch("xe-pvc-sdv"), IntelGPU::GK_XE_PVC_SDV);
@@ -143,43 +140,7 @@ TEST(IntelGPUTargetParserTest, EveryNameParses) {
   EXPECT_EQ(IntelGPU::parseArch(NAME), IntelGPU::GK_##KIND) << NAME;
 #define INTEL_GPU_COMPAT(NAME, KIND, IGCA_TARGET, IGCA_FEATURE_SETS)           
\
   EXPECT_EQ(IntelGPU::parseArch(NAME), IntelGPU::GK_##KIND) << NAME;
-#define INTEL_GPU_ALIAS(NAME, KIND)                                            
\
-  EXPECT_EQ(IntelGPU::parseArch(NAME), IntelGPU::GK_##KIND) << NAME;
 #include "llvm/TargetParser/IntelGPUTargetParser.def"
 }
 
-TEST(IntelGPUTargetParserTest, AliasesAreNeverReported) {
-  // An alias declares no kind of its own, so the name reported for a device is
-  // the row's own name. A device with two spellings would otherwise depend on
-  // which one the table happened to reach first.
-#define INTEL_GPU_ALIAS(NAME, KIND)                                            
\
-  EXPECT_NE(IntelGPU::getArchName(IntelGPU::GK_##KIND), NAME) << NAME;
-#include "llvm/TargetParser/IntelGPUTargetParser.def"
-}
-
-TEST(IntelGPUTargetParserTest, IGCANames) {
-  // One of each suffix, since the target and the feature sets are pasted
-  // together.
-  EXPECT_EQ(IntelGPU::getIGCAName(IntelGPU::GK_XE_CRI), "igca_60c");
-  EXPECT_EQ(IntelGPU::getIGCAName(IntelGPU::GK_XE_NVL_P), "igca_60r");
-  EXPECT_EQ(IntelGPU::getIGCAName(IntelGPU::GK_XE_PVC), "igca_20ca");
-  EXPECT_EQ(IntelGPU::getIGCAName(IntelGPU::GK_XE_DG2), "igca_15ra");
-  EXPECT_EQ(IntelGPU::getIGCAName(IntelGPU::GK_NONE), "");
-}
-
-TEST(IntelGPUTargetParserTest, ValidArchList) {
-  SmallVector<StringRef> Values;
-  IntelGPU::fillValidArchList(Values);
-
-  EXPECT_FALSE(Values.empty());
-  EXPECT_NE(llvm::find(Values, "xe-pvc"), Values.end());
-  // A compatibility name and an alias are as valid as any other name.
-  EXPECT_NE(llvm::find(Values, "xe-dg2"), Values.end());
-  EXPECT_NE(llvm::find(Values, "bmg_g21"), Values.end());
-  // The list is offered to a user whose name did not parse, so every entry has
-  // to be a name that would have.
-  for (StringRef Value : Values)
-    EXPECT_NE(IntelGPU::parseArch(Value), IntelGPU::GK_NONE) << Value;
-}
-
 } // namespace

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

Reply via email to