[clang] 6bef34a - [TargetParser] Add a list of Intel GPUs, and use it in offload-arch (#222072)

via cfe-commits cfe-commits at lists.llvm.org
Thu Sep 24 08:55:26 PDT 2026


Author: Nikita Kornev
Date: 2026-09-24T08:55:19-07:00
New Revision: 6bef34a7ebbef9b11654aef83c8fbc1b0dc16860

URL: https://github.com/llvm/llvm-project/commit/6bef34a7ebbef9b11654aef83c8fbc1b0dc16860
DIFF: https://github.com/llvm/llvm-project/commit/6bef34a7ebbef9b11654aef83c8fbc1b0dc16860.diff

LOG: [TargetParser] Add a list of Intel GPUs, and use it in offload-arch (#222072)

Currently offload-arch prints Intel GPU identifiers like "Intel(R) Data
Center GPU Max 1100" which are not legal values for clang's
--offload-arch option.

Print an architecture name instead, e.g. "xe-pvc". The driver reports a
GPU IP version, the GMDID, for every device. Add a table that maps a
GMDID to a name, and look the device up in it. A device that is missing
from the table is printed by its numeric version, e.g. "xe_35.11.0". A
device whose driver does not report a GMDID is skipped.

The table goes in llvm/TargetParser, next to the other GPU lists,
because other tools need it too. Some of them are LLVM libraries, which
cannot include a clang header.

Every row of IntelGPUTargetParser.def holds a name that --offload-arch
accepts, the major and minor components of the GMDID that the device
reports, and the IGCA (Intel Graphics Compute Architecture) target and
feature sets that the name maps to. The revision component is left out,
so every revision of a device gets the same name. A few names, such as
xe-dg2, cover a whole product line. No device reports a GMDID for those,
so offload-arch never prints them.

The header declares only the functions that offload-arch needs. More
will follow when something needs them.

---------

Co-authored-by: Claude Opus 5 <noreply at anthropic.com>

Added: 
    llvm/include/llvm/TargetParser/IntelGPUTargetParser.def
    llvm/include/llvm/TargetParser/IntelGPUTargetParser.h
    llvm/lib/TargetParser/IntelGPUTargetParser.cpp
    llvm/unittests/TargetParser/IntelGPUTargetParserTest.cpp

Modified: 
    clang/tools/offload-arch/CMakeLists.txt
    clang/tools/offload-arch/LevelZeroArch.cpp
    clang/unittests/offload-arch/CMakeLists.txt
    clang/unittests/offload-arch/OffloadArchTest.cpp
    llvm/include/module.modulemap
    llvm/lib/TargetParser/CMakeLists.txt
    llvm/unittests/TargetParser/CMakeLists.txt

Removed: 
    


################################################################################
diff  --git a/clang/tools/offload-arch/CMakeLists.txt b/clang/tools/offload-arch/CMakeLists.txt
index f7d7012cf7272..8e37e3d2ae5db 100644
--- a/clang/tools/offload-arch/CMakeLists.txt
+++ b/clang/tools/offload-arch/CMakeLists.txt
@@ -1,4 +1,4 @@
-set(LLVM_LINK_COMPONENTS Support)
+set(LLVM_LINK_COMPONENTS Support TargetParser)
 
 add_clang_tool(offload-arch OffloadArch.cpp NVPTXArch.cpp AMDGPUArchByKFD.cpp
                AMDGPUArchByHIP.cpp LevelZeroArch.cpp)

diff  --git a/clang/tools/offload-arch/LevelZeroArch.cpp b/clang/tools/offload-arch/LevelZeroArch.cpp
index 47d80aa813085..6720618d2a7d8 100644
--- a/clang/tools/offload-arch/LevelZeroArch.cpp
+++ b/clang/tools/offload-arch/LevelZeroArch.cpp
@@ -14,7 +14,9 @@
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/DynamicLibrary.h"
 #include "llvm/Support/Error.h"
+#include "llvm/TargetParser/IntelGPUTargetParser.h"
 #include <cstdio>
+#include <string>
 
 #define ZE_MAX_DEVICE_NAME 256
 #define ZE_MAX_DEVICE_UUID_SIZE 16
@@ -30,6 +32,7 @@ enum ze_result_t {
 enum ze_structure_type_t {
   ZE_STRUCTURE_TYPE_INIT_DRIVER_TYPE_DESC = 0x00020021,
   ZE_STRUCTURE_TYPE_DEVICE_PROPERTIES = 0x3,
+  ZE_STRUCTURE_TYPE_DEVICE_IP_VERSION_EXT = 0x1000f,
   ZE_STRUCTURE_TYPE_FORCE_UINT32 = 0x7fffffff
 };
 
@@ -72,6 +75,13 @@ struct ze_device_properties_t {
   char name[ZE_MAX_DEVICE_NAME];
 };
 
+// Chained onto ze_device_properties_t::pNext to request the device IP version.
+struct ze_device_ip_version_ext_t {
+  ze_structure_type_t stype;
+  const void *pNext;
+  uint32_t ipVersion;
+};
+
 ze_result_t zeInitDrivers(uint32_t *pCount, ze_driver_handle_t *phDrivers,
                           ze_init_driver_type_desc_t *desc);
 ze_result_t zeDeviceGet(ze_driver_handle_t hDriver, uint32_t *pCount,
@@ -148,6 +158,14 @@ static bool loadLevelZero() {
     }                                                                          \
   } while (0)
 
+// Translate a GPU IP version into an architecture name that is a legal
+// --offload-arch parameter. A device that has no name in the table is named
+// after its version.
+std::string getIntelGPUArchName(uint32_t IPVersion) {
+  StringRef Name = IntelGPU::getArchName(IPVersion);
+  return Name.empty() ? IntelGPU::getNumericArchName(IPVersion) : Name.str();
+}
+
 int printGPUsByLevelZero() {
   if (!loadLevelZero())
     return 1;
@@ -173,11 +191,27 @@ int printGPUsByLevelZero() {
     CALL_ZE_AND_CHECK(zeDeviceGet, Driver, &DeviceCount, Devices.data());
 
     for (auto Device : Devices) {
+      ze_device_ip_version_ext_t IPVersion = {};
+      IPVersion.stype = ZE_STRUCTURE_TYPE_DEVICE_IP_VERSION_EXT;
+      IPVersion.pNext = nullptr;
+
       ze_device_properties_t DeviceProperties = {};
       DeviceProperties.stype = ZE_STRUCTURE_TYPE_DEVICE_PROPERTIES;
-      DeviceProperties.pNext = nullptr;
+      DeviceProperties.pNext = &IPVersion;
       CALL_ZE_AND_CHECK(zeDeviceGetProperties, Device, &DeviceProperties);
-      llvm::outs() << DeviceProperties.name << '\n';
+
+      if (IPVersion.ipVersion == 0) {
+        if (Verbose)
+          llvm::errs()
+              << "warning: skipping device '" << DeviceProperties.name
+              << "': the device does not support Device IP Version Extension\n";
+        continue;
+      }
+
+      if (Verbose)
+        llvm::errs() << "Found device '" << DeviceProperties.name << "'\n";
+
+      llvm::outs() << getIntelGPUArchName(IPVersion.ipVersion) << '\n';
     }
   }
 

diff  --git a/clang/unittests/offload-arch/CMakeLists.txt b/clang/unittests/offload-arch/CMakeLists.txt
index 8d9cbf5c60205..523b5f33ed6b3 100644
--- a/clang/unittests/offload-arch/CMakeLists.txt
+++ b/clang/unittests/offload-arch/CMakeLists.txt
@@ -1,6 +1,7 @@
 set(OffloadArchTestSources
   OffloadArchTest.cpp
   ${CMAKE_CURRENT_SOURCE_DIR}/../../tools/offload-arch/AMDGPUArchByKFD.cpp
+  ${CMAKE_CURRENT_SOURCE_DIR}/../../tools/offload-arch/LevelZeroArch.cpp
   )
 
 if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
@@ -16,4 +17,5 @@ add_distinct_clang_unittest(OffloadArchTests
     LLVMTestingSupport
   LLVM_COMPONENTS
     Support
+    TargetParser
   )

diff  --git a/clang/unittests/offload-arch/OffloadArchTest.cpp b/clang/unittests/offload-arch/OffloadArchTest.cpp
index c380b8c7f1287..2d4a35c85729d 100644
--- a/clang/unittests/offload-arch/OffloadArchTest.cpp
+++ b/clang/unittests/offload-arch/OffloadArchTest.cpp
@@ -16,6 +16,7 @@
 #include "llvm/Testing/Support/SupportHelpers.h"
 #include "gtest/gtest.h"
 #include <algorithm>
+#include <cassert>
 #include <cstdlib>
 #include <optional>
 #include <string>
@@ -29,6 +30,9 @@ llvm::SmallVector<std::string, 8> getCandidateBinPaths(llvm::StringRef ExeDir);
 // Defined in AMDGPUArchByKFD.cpp (non-static, compiled into this test).
 int printGPUsByKFD(llvm::StringRef NodePath);
 
+// Defined in LevelZeroArch.cpp.
+std::string getIntelGPUArchName(uint32_t IPVersion);
+
 using namespace llvm;
 
 cl::opt<bool> Verbose("offload-arch-test-verbose", cl::Hidden, cl::init(false));
@@ -303,3 +307,52 @@ TEST(KFDTopology, GFX1250NonA0IsPrintedPlain) {
   EXPECT_EQ(printGPUsByKFDCapturingStdout(Dir.path(), Output), 0);
   EXPECT_EQ(Output, "gfx1250\n");
 }
+
+// --- getIntelGPUArchName ---
+
+namespace {
+// Build a GPU IP version the way the Level Zero driver reports it. A component
+// too wide for its field would corrupt the fields above it and quietly test
+// something other than what it spells out.
+constexpr uint32_t gpuIPVersion(uint32_t Major, uint32_t Minor,
+                                uint32_t Revision) {
+  assert((Major & ~0x3ffu) == 0 && "major version too wide");
+  assert((Minor & ~0xffu) == 0 && "minor version too wide");
+  assert((Revision & ~0x3fu) == 0 && "revision too wide");
+  return (Major << 22) | (Minor << 14) | Revision;
+}
+} // namespace
+
+TEST(IntelGPUArchName, KnownArchitecturesGetAFriendlyName) {
+  EXPECT_EQ(getIntelGPUArchName(gpuIPVersion(12, 60, 7)), "xe-pvc");
+  EXPECT_EQ(getIntelGPUArchName(gpuIPVersion(20, 1, 4)), "xe-bmg-g21");
+  EXPECT_EQ(getIntelGPUArchName(gpuIPVersion(35, 10, 0)), "xe-nvl-p");
+  EXPECT_EQ(getIntelGPUArchName(gpuIPVersion(12, 0, 0)), "xe-tgllp");
+}
+
+// When several devices share a major and a minor version, the first one listed
+// in IntelGPUTargetParser.def names the whole group.
+TEST(IntelGPUArchName, FirstNameOfAGroupWins) {
+  EXPECT_EQ(getIntelGPUArchName(gpuIPVersion(30, 5, 0)), "xe-nvl-u");
+  EXPECT_EQ(getIntelGPUArchName(gpuIPVersion(12, 55, 0)), "xe-acm-g10");
+}
+
+// Devices with the same major and minor versions but 
diff erent revisions are
+// the same device.
+TEST(IntelGPUArchName, RevisionDoesNotAffectTheName) {
+  EXPECT_EQ(getIntelGPUArchName(gpuIPVersion(12, 60, 0)), "xe-pvc");
+  EXPECT_EQ(getIntelGPUArchName(gpuIPVersion(12, 60, 63)), "xe-pvc");
+}
+
+// An architecture that is not in the table still has to be named, so that a
+// newer device is usable with a compiler that predates it.
+TEST(IntelGPUArchName, UnknownArchitecturesGetANumericName) {
+  EXPECT_EQ(getIntelGPUArchName(gpuIPVersion(40, 11, 0)), "xe_40.11.0");
+  EXPECT_EQ(getIntelGPUArchName(gpuIPVersion(12, 99, 3)), "xe_12.99.3");
+}
+
+// Pre-Xe devices report a GPU IP version too, but they have no human-friendly
+// identifier.
+TEST(IntelGPUArchName, LegacyArchitecture) {
+  EXPECT_EQ(getIntelGPUArchName(gpuIPVersion(9, 0, 9)), "xe_9.0.9");
+}

diff  --git a/llvm/include/llvm/TargetParser/IntelGPUTargetParser.def b/llvm/include/llvm/TargetParser/IntelGPUTargetParser.def
new file mode 100644
index 0000000000000..bd3b0a4634e06
--- /dev/null
+++ b/llvm/include/llvm/TargetParser/IntelGPUTargetParser.def
@@ -0,0 +1,96 @@
+//===--- IntelGPUTargetParser.def - Intel GPU target data ------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is the single source of truth for the Intel GPU list. Each row
+// describes one architecture name that --offload-arch accepts, along with the
+// IGCA (Intel Graphics Compute Architecture) target and feature sets that the
+// name maps to. Adding a device is a single row here.
+//
+//   INTEL_GPU(NAME, KIND, MAJOR, MINOR, IGCA_TARGET, IGCA_FEATURE_SETS)
+//     NAME              - Human-friendly device name, e.g. "xe-cri".
+//     KIND              - GPUKind enumerator suffix; the enumerator is
+//                         GK_<KIND>.
+//     MAJOR             - Major component of the device's GPU IP version.
+//     MINOR             - Minor component of the device's GPU IP version.
+//     IGCA_TARGET       - Numeric IGCA target.
+//     IGCA_FEATURE_SETS - Token naming the IGCA feature sets the device
+//                         implements: Core (none), Compute ("c"),
+//                         Render ("r"), ComputeExact ("ca") or
+//                         RenderExact ("ra").
+//
+//   INTEL_GPU_COMPAT(NAME, KIND, IGCA_TARGET, IGCA_FEATURE_SETS)
+//     A compatibility name that covers several minor versions, e.g. "xe-dg2",
+//     which covers every xe-dg2-* and xe-acm-* platform. These names have no
+//     GPU IP version of their own, so no device reports one and the
+//     offload-arch utility never prints one, but they are legal --offload-arch
+//     values. The columns mean the same as above.
+//
+// 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.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef INTEL_GPU
+#define INTEL_GPU(NAME, KIND, MAJOR, MINOR, IGCA_TARGET, IGCA_FEATURE_SETS)
+#endif
+
+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)
+INTEL_GPU("xe-lnl-m",    XE_LNL_M,    20, 4,   40, Render)
+INTEL_GPU("xe-bmg-g31",  XE_BMG_G31,  20, 2,   40, Render)
+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
+#define INTEL_GPU_COMPAT(NAME, KIND, IGCA_TARGET, IGCA_FEATURE_SETS)
+#endif
+
+INTEL_GPU_COMPAT("xe-ptl", XE_PTL, 50, Render)
+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)
+
+#undef INTEL_GPU
+#undef INTEL_GPU_COMPAT

diff  --git a/llvm/include/llvm/TargetParser/IntelGPUTargetParser.h b/llvm/include/llvm/TargetParser/IntelGPUTargetParser.h
new file mode 100644
index 0000000000000..4ae635e97167b
--- /dev/null
+++ b/llvm/include/llvm/TargetParser/IntelGPUTargetParser.h
@@ -0,0 +1,50 @@
+//===-- IntelGPUTargetParser.h - Parser for Intel GPU targets ---*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// 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.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TARGETPARSER_INTELGPUTARGETPARSER_H
+#define LLVM_TARGETPARSER_INTELGPUTARGETPARSER_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Compiler.h"
+#include <cstdint>
+#include <string>
+
+namespace llvm {
+namespace IntelGPU {
+
+/// Intel GPU architecture names, covering both physical devices and the
+/// compatibility names that stand for a whole product line.
+enum GPUKind : uint8_t {
+  GK_NONE = 0,
+#define INTEL_GPU(NAME, KIND, MAJOR, MINOR, IGCA_TARGET, IGCA_FEATURE_SETS)    \
+  GK_##KIND,
+#define INTEL_GPU_COMPAT(NAME, KIND, IGCA_TARGET, IGCA_FEATURE_SETS) GK_##KIND,
+#include "llvm/TargetParser/IntelGPUTargetParser.def"
+};
+
+/// \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.
+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);
+
+} // namespace IntelGPU
+} // namespace llvm
+
+#endif // LLVM_TARGETPARSER_INTELGPUTARGETPARSER_H

diff  --git a/llvm/include/module.modulemap b/llvm/include/module.modulemap
index 69836bf2e3158..03cab392cb619 100644
--- a/llvm/include/module.modulemap
+++ b/llvm/include/module.modulemap
@@ -438,6 +438,7 @@ module LLVM_Utils {
     // These are intended for textual inclusion.
     textual header "llvm/TargetParser/ARMTargetParser.def"
     textual header "llvm/TargetParser/CSKYTargetParser.def"
+    textual header "llvm/TargetParser/IntelGPUTargetParser.def"
     textual header "llvm/TargetParser/X86TargetParser.def"
     textual header "llvm/TargetParser/LoongArchTargetParser.def"
     textual header "llvm/TargetParser/NVPTXTargetParser.def"

diff  --git a/llvm/lib/TargetParser/CMakeLists.txt b/llvm/lib/TargetParser/CMakeLists.txt
index cb45571583d23..27d6511ec0849 100644
--- a/llvm/lib/TargetParser/CMakeLists.txt
+++ b/llvm/lib/TargetParser/CMakeLists.txt
@@ -21,6 +21,7 @@ add_llvm_component_library(LLVMTargetParser
   AVRTargetParser.cpp
   CSKYTargetParser.cpp
   Host.cpp
+  IntelGPUTargetParser.cpp
   LoongArchTargetParser.cpp
   NVPTXTargetParser.cpp
   PPCTargetParser.cpp

diff  --git a/llvm/lib/TargetParser/IntelGPUTargetParser.cpp b/llvm/lib/TargetParser/IntelGPUTargetParser.cpp
new file mode 100644
index 0000000000000..e680279cdf87c
--- /dev/null
+++ b/llvm/lib/TargetParser/IntelGPUTargetParser.cpp
@@ -0,0 +1,65 @@
+//===-- IntelGPUTargetParser - Parser for Intel GPU targets ---------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements a target parser for the Intel GPU list.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/TargetParser/IntelGPUTargetParser.h"
+#include "llvm/ADT/Twine.h"
+#include <cassert>
+
+using namespace llvm;
+using namespace IntelGPU;
+
+// A GPU IP version packs four fields, from the most significant bit down:
+//
+//    31           22 21      14 13       6 5        0
+//   +---------------+----------+----------+----------+
+//   |     major     |   minor  | reserved | revision |
+//   +---------------+----------+----------+----------+
+//        10 bits      8 bits     8 bits     6 bits
+//
+// The reserved bits carry no information.
+static constexpr uint32_t GPUIPMajorShift = 22;
+static constexpr uint32_t GPUIPMinorShift = 14;
+static constexpr uint32_t GPUIPMajorMask = 0x3ff;
+static constexpr uint32_t GPUIPMinorMask = 0xff;
+static constexpr uint32_t GPUIPRevisionMask = 0x3f;
+
+// The bits that identify a device: the major and the minor version. Neither the
+// revision nor the reserved bits take part in the lookup, because every
+// revision of a device is one device as far as the compiler is concerned.
+static constexpr uint32_t GPUIPDeviceMask = ~0u << GPUIPMinorShift;
+
+// Pack a major and a minor version the way a GPU IP version does, so that a
+// row of the table can be compared against a reported version as it is. A value
+// too wide for its field would silently corrupt the fields above it, which
+// would mean a typo in IntelGPUTargetParser.def going unnoticed.
+static constexpr uint32_t packDevice(uint32_t Major, uint32_t Minor) {
+  assert((Major & ~GPUIPMajorMask) == 0 && "major version too wide");
+  assert((Minor & ~GPUIPMinorMask) == 0 && "minor version too wide");
+  return (Major << GPUIPMajorShift) | (Minor << GPUIPMinorShift);
+}
+
+StringRef llvm::IntelGPU::getArchName(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;
+#include "llvm/TargetParser/IntelGPUTargetParser.def"
+  return "";
+}
+
+std::string llvm::IntelGPU::getNumericArchName(uint32_t GPUIPVersion) {
+  const uint32_t Major = GPUIPVersion >> GPUIPMajorShift;
+  const uint32_t Minor = (GPUIPVersion >> GPUIPMinorShift) & GPUIPMinorMask;
+  const uint32_t Revision = GPUIPVersion & GPUIPRevisionMask;
+  return ("xe_" + Twine(Major) + "." + Twine(Minor) + "." + Twine(Revision))
+      .str();
+}

diff  --git a/llvm/unittests/TargetParser/CMakeLists.txt b/llvm/unittests/TargetParser/CMakeLists.txt
index 9ef532603517b..65b2ff085a299 100644
--- a/llvm/unittests/TargetParser/CMakeLists.txt
+++ b/llvm/unittests/TargetParser/CMakeLists.txt
@@ -7,6 +7,7 @@ add_llvm_unittest(TargetParserTests
   AtomicScopeTest.cpp
   CSKYTargetParserTest.cpp
   Host.cpp
+  IntelGPUTargetParserTest.cpp
   NVPTXTargetParserTest.cpp
   RISCVISAInfoTest.cpp
   RISCVTargetParserTest.cpp

diff  --git a/llvm/unittests/TargetParser/IntelGPUTargetParserTest.cpp b/llvm/unittests/TargetParser/IntelGPUTargetParserTest.cpp
new file mode 100644
index 0000000000000..ab8d456769d0d
--- /dev/null
+++ b/llvm/unittests/TargetParser/IntelGPUTargetParserTest.cpp
@@ -0,0 +1,81 @@
+//===-- IntelGPUTargetParserTest.cpp - Intel GPU Target Parser Test -------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/TargetParser/IntelGPUTargetParser.h"
+#include "gtest/gtest.h"
+#include <cassert>
+
+using namespace llvm;
+
+namespace {
+
+// Build a GPU IP version the way the Level Zero driver reports it. A component
+// too wide for its field would corrupt the fields above it and quietly test
+// something other than what it spells out.
+constexpr uint32_t gpuIPVersion(uint32_t Major, uint32_t Minor,
+                                uint32_t Revision) {
+  assert((Major & ~0x3ffu) == 0 && "major version too wide");
+  assert((Minor & ~0xffu) == 0 && "minor version too wide");
+  assert((Revision & ~0x3fu) == 0 && "revision too wide");
+  return (Major << 22) | (Minor << 14) | Revision;
+}
+
+// The bits between the minor version and the revision, which no component uses.
+constexpr uint32_t GPUIPReservedBits = 0x3fc0;
+
+TEST(IntelGPUTargetParserTest, ArchNames) {
+  EXPECT_EQ(IntelGPU::getArchName(gpuIPVersion(12, 60, 7)), "xe-pvc");
+  EXPECT_EQ(IntelGPU::getArchName(gpuIPVersion(35, 11, 0)), "xe-cri");
+  EXPECT_EQ(IntelGPU::getArchName(gpuIPVersion(12, 55, 3)), "xe-acm-g10");
+  // The revision is not part of the key: every revision of a device is that
+  // same device.
+  EXPECT_EQ(IntelGPU::getArchName(gpuIPVersion(12, 60, 0)), "xe-pvc");
+  EXPECT_EQ(IntelGPU::getArchName(gpuIPVersion(12, 60, 63)), "xe-pvc");
+  // Neither are the reserved bits, whatever a driver reports in them.
+  EXPECT_EQ(IntelGPU::getArchName(gpuIPVersion(12, 60, 7) | GPUIPReservedBits),
+            "xe-pvc");
+  // When several devices share a major and a minor version, the first row of
+  // the group names the whole group.
+  EXPECT_EQ(IntelGPU::getArchName(gpuIPVersion(30, 5, 0)), "xe-nvl-u");
+  // A device that is not in the table has no name at all.
+  EXPECT_EQ(IntelGPU::getArchName(gpuIPVersion(40, 11, 0)), "");
+  EXPECT_EQ(IntelGPU::getArchName(gpuIPVersion(9, 0, 9)), "");
+}
+
+TEST(IntelGPUTargetParserTest, EveryDeviceIsNamed) {
+  // A row that no GPU IP version can reach would make the offload-arch utility
+  // print an empty architecture for a device the table does list, so every
+  // physical device must resolve to some name. It need not be the name of the
+  // row itself: a row that shares its major and minor version with an earlier
+  // one is named after that earlier row. Compatibility names have no version of
+  // their own and so cannot be looked up, which is why INTEL_GPU_COMPAT is left
+  // alone.
+#define INTEL_GPU(NAME, KIND, MAJOR, MINOR, IGCA_TARGET, IGCA_FEATURE_SETS)    \
+  EXPECT_FALSE(IntelGPU::getArchName(gpuIPVersion(MAJOR, MINOR, 0)).empty())   \
+      << NAME;
+#include "llvm/TargetParser/IntelGPUTargetParser.def"
+}
+
+TEST(IntelGPUTargetParserTest, NumericArchName) {
+  EXPECT_EQ(IntelGPU::getNumericArchName(gpuIPVersion(35, 11, 0)),
+            "xe_35.11.0");
+  EXPECT_EQ(IntelGPU::getNumericArchName(gpuIPVersion(12, 99, 3)),
+            "xe_12.99.3");
+  // Pre-Xe devices report a version too, and none of them are in the table.
+  EXPECT_EQ(IntelGPU::getNumericArchName(gpuIPVersion(9, 0, 9)), "xe_9.0.9");
+  // The revision occupies the low 6 bits and the minor version the 8 above it,
+  // so neither can bleed into the major version.
+  EXPECT_EQ(IntelGPU::getNumericArchName(gpuIPVersion(12, 0xff, 0x3f)),
+            "xe_12.255.63");
+  // The reserved bits belong to no component, so they are not spelled out.
+  EXPECT_EQ(
+      IntelGPU::getNumericArchName(gpuIPVersion(12, 60, 7) | GPUIPReservedBits),
+      "xe_12.60.7");
+}
+
+} // namespace


        


More information about the cfe-commits mailing list