diff --git a/clang/include/clang/Basic/IntelGPUArch.def b/clang/include/clang/Basic/IntelGPUArch.def new file mode 100644 index 0000000000000..a7e01afb08ac7 --- /dev/null +++ b/clang/include/clang/Basic/IntelGPUArch.def @@ -0,0 +1,82 @@ +//===--- IntelGPUArch.def - Intel GPU architecture names --------*- 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 lists the human-friendly names of the Intel GPU architectures, +// keyed by the architecture and release components of the GMDID that the +// device reports. The revision component is deliberately not part of the key: +// every stepping of an architecture shares one name. +// +// Several devices can share an architecture and release. The entries are +// ordered so that the name to print for such a group comes first, which lets +// this file be generated from a device list without having to pick a +// representative device. A name that covers more than one release, such as +// xe-dg2 or xe-mtl, has no GMDID of its own and is listed with a sentinel +// architecture and release of zero; consumers that name a device must skip +// those entries. +// +// Every entry also records the IGCA level of the device, the level of the +// Intel Graphics Compiler architecture that the device implements. Devices +// that share an IGCA level are binary compatible with each other. +// +// Together, the names and the IGCA levels listed here are the Intel GPU +// architectures that '--offload-arch' accepts. +// +// The intent is for this table to be generated from the data published by the +// GPU driver, so keep it free of anything a generator cannot produce. +// +//===----------------------------------------------------------------------===// + +#ifndef INTEL_GPU_ARCH +#error "Define INTEL_GPU_ARCH prior to including this file!" +#endif + +// INTEL_GPU_ARCH(ARCHITECTURE, RELEASE, NAME, IGCA) +INTEL_GPU_ARCH(35, 11, "xe-cri", "igca_60c") +INTEL_GPU_ARCH(35, 10, "xe-nvl-p", "igca_60r") +INTEL_GPU_ARCH(30, 5, "xe-nvl-u", "igca_60r") +INTEL_GPU_ARCH(30, 5, "xe-nvl-h", "igca_60r") +INTEL_GPU_ARCH(30, 4, "xe-nvl-s", "igca_60r") +INTEL_GPU_ARCH(30, 4, "xe-nvl-hx", "igca_60r") +INTEL_GPU_ARCH(30, 4, "xe-nvl-ul", "igca_60r") +INTEL_GPU_ARCH(30, 3, "xe-wcl", "igca_50r") +INTEL_GPU_ARCH(30, 1, "xe-ptl-u", "igca_50r") +INTEL_GPU_ARCH(30, 0, "xe-ptl-h", "igca_50r") +INTEL_GPU_ARCH(0, 0, "xe-ptl", "igca_50r") +INTEL_GPU_ARCH(20, 4, "xe-lnl-m", "igca_40r") +INTEL_GPU_ARCH(20, 2, "xe-bmg-g31", "igca_40r") +INTEL_GPU_ARCH(20, 1, "xe-bmg-g21", "igca_40r") +INTEL_GPU_ARCH(0, 0, "xe-bmg", "igca_40r") +INTEL_GPU_ARCH(12, 74, "xe-arl-h", "igca_35r") +INTEL_GPU_ARCH(12, 71, "xe-mtl-h", "igca_30r") +INTEL_GPU_ARCH(12, 70, "xe-mtl-u", "igca_30r") +INTEL_GPU_ARCH(12, 70, "xe-arl-u", "igca_30r") +INTEL_GPU_ARCH(12, 70, "xe-arl-s", "igca_30r") +INTEL_GPU_ARCH(0, 0, "xe-mtl", "igca_30r") +INTEL_GPU_ARCH(12, 61, "xe-pvc-vg", "igca_20ca") +INTEL_GPU_ARCH(12, 60, "xe-pvc", "igca_20ca") +INTEL_GPU_ARCH(12, 60, "xe-pvc-sdv", "igca_20ca") +INTEL_GPU_ARCH(12, 57, "xe-acm-g12", "igca_15ra") +INTEL_GPU_ARCH(12, 57, "xe-dg2-g12", "igca_15ra") +INTEL_GPU_ARCH(12, 56, "xe-acm-g11", "igca_15ra") +INTEL_GPU_ARCH(12, 56, "xe-dg2-g11", "igca_15ra") +INTEL_GPU_ARCH(12, 56, "xe-ats-m75", "igca_15ra") +INTEL_GPU_ARCH(12, 55, "xe-acm-g10", "igca_15ra") +INTEL_GPU_ARCH(12, 55, "xe-dg2-g10", "igca_15ra") +INTEL_GPU_ARCH(12, 55, "xe-ats-m150", "igca_15ra") +INTEL_GPU_ARCH(0, 0, "xe-dg2", "igca_15ra") +INTEL_GPU_ARCH(12, 10, "xe-dg1", "igca_10r") +INTEL_GPU_ARCH(12, 4, "xe-adl-n", "igca_10r") +INTEL_GPU_ARCH(12, 3, "xe-adl-p", "igca_10r") +INTEL_GPU_ARCH(12, 3, "xe-rpl-p", "igca_10r") +INTEL_GPU_ARCH(12, 2, "xe-adl-s", "igca_10r") +INTEL_GPU_ARCH(12, 2, "xe-rpl-s", "igca_10r") +INTEL_GPU_ARCH(12, 1, "xe-rkl", "igca_10r") +INTEL_GPU_ARCH(12, 0, "xe-tgllp", "igca_10r") +INTEL_GPU_ARCH(12, 0, "xe-tgl", "igca_10r") + +#undef INTEL_GPU_ARCH diff --git a/clang/include/clang/Basic/OffloadArch.h b/clang/include/clang/Basic/OffloadArch.h index fe1ebca8f2558..9472592dd8b13 100644 --- a/clang/include/clang/Basic/OffloadArch.h +++ b/clang/include/clang/Basic/OffloadArch.h @@ -10,6 +10,7 @@ #define LLVM_CLANG_BASIC_OFFLOADARCH_H #include "llvm/ADT/StringRef.h" +#include #include #include @@ -40,7 +41,11 @@ class OffloadArch { SPIRV, // The 'amdgcnspirv' pseudo target. IntelCPU, // Kind is an IntelArch. IntelGPU, // Kind is an IntelArch. - Generic, // The 'generic' processor model. + // An Intel GPU named the way the GPU driver names it: by the architecture + // name or by the IGCA level of an entry of IntelGPUArch.def. Kind is + // opaque; use StringToOffloadArch to build one. + IntelXeGPU, + Generic, // The 'generic' processor model. }; // Intel architectures, which have no TargetParser list yet. @@ -127,6 +132,9 @@ class OffloadArch { static constexpr OffloadArch getIntel(TargetArch V, IntelArch A) { return {V, static_cast(A)}; } + // Defined out of line, so that Kind can be checked against the table of + // IntelGPUArch.def entries that gives it its meaning. + static OffloadArch getIntelXeGPU(uint32_t Kind); static constexpr OffloadArch getUnused() { return {TargetArch::Unused, 0}; } static constexpr OffloadArch getUnknown() { return {TargetArch::Unknown, 0}; } static constexpr OffloadArch getSPIRV() { return {TargetArch::SPIRV, 0}; } @@ -142,7 +150,10 @@ class OffloadArch { bool isAMDGPU() const { return V == TargetArch::AMDGPU; } bool isSPIRV() const { return V == TargetArch::SPIRV; } bool isIntelCPU() const { return V == TargetArch::IntelCPU; } - bool isIntelGPU() const { return V == TargetArch::IntelGPU; } + bool isIntelXeGPU() const { return V == TargetArch::IntelXeGPU; } + bool isIntelGPU() const { + return V == TargetArch::IntelGPU || isIntelXeGPU(); + } bool isIntel() const { return isIntelCPU() || isIntelGPU(); } bool isGeneric() const { return V == TargetArch::Generic; } bool isUnused() const { return V == TargetArch::Unused; } @@ -155,8 +166,17 @@ class OffloadArch { llvm::AMDGPU::GPUKind amdgpuKind() const { return static_cast(Kind); } - // Only valid when isIntelCPU() / isIntelGPU(). - IntelArch intelKind() const { return static_cast(Kind); } + // Only valid when isIntelCPU(), or when isIntelGPU() and !isIntelXeGPU(). + IntelArch intelKind() const { + assert((isIntelCPU() || (isIntelGPU() && !isIntelXeGPU())) && + "not an Intel CPU or a non-Xe Intel GPU"); + return static_cast(Kind); + } + // Only valid when isIntelXeGPU(); opaque outside of OffloadArch.cpp. + uint32_t intelXeKind() const { + assert(isIntelXeGPU() && "not an Intel Xe GPU"); + return 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 3784291d9d482..f8338f190db77 100644 --- a/clang/lib/Basic/OffloadArch.cpp +++ b/clang/lib/Basic/OffloadArch.cpp @@ -12,6 +12,7 @@ #include "llvm/TargetParser/AMDGPUTargetParser.h" #include "llvm/TargetParser/NVPTXTargetParser.h" #include "llvm/TargetParser/Triple.h" +#include namespace clang { @@ -101,6 +102,86 @@ static const IntelArchNameMap IntelArchNames[] = { #undef INTEL_CPU #undef INTEL_GPU +namespace { +// The Intel GPU architectures the GPU driver knows about, each with the IGCA +// level it implements. Architectures that share an architecture and a release +// are listed with the one that names the group first; a name that covers more +// than one release has a sentinel architecture and release of zero. +struct IntelGPUArchEntry { + uint32_t Architecture; + uint32_t Release; + const char *Name; + const char *IGCALevel; + + // The entries with a sentinel GMDID name a group of architectures, so the + // numeric form of a name never refers to one of them. + bool namesAGroup() const { return Architecture == 0 && Release == 0; } +}; +} // namespace + +static constexpr IntelGPUArchEntry IntelGPUArchs[] = { +#define INTEL_GPU_ARCH(ARCHITECTURE, RELEASE, NAME, IGCA) \ + {ARCHITECTURE, RELEASE, NAME, IGCA}, +#include "clang/Basic/IntelGPUArch.def" +}; + +static constexpr uint32_t NumIntelGPUArchs = std::size(IntelGPUArchs); + +// An intelXeKind holds the index of the entry it names. Its top bit indicates +// whether the Name or IGCALevel was passed: it is set when the IGCALevel was +// passed. +static constexpr uint32_t IntelGPUIGCALevelFlag = 1u << 31; + +OffloadArch OffloadArch::getIntelXeGPU(uint32_t Kind) { + assert((Kind & ~IntelGPUIGCALevelFlag) < NumIntelGPUArchs && + "Kind does not name an entry of IntelGPUArch.def"); + return {TargetArch::IntelXeGPU, Kind}; +} + +static const IntelGPUArchEntry *lookupIntelGPUArch(OffloadArch A) { + uint32_t Index = A.intelXeKind() & ~IntelGPUIGCALevelFlag; + return Index < NumIntelGPUArchs ? &IntelGPUArchs[Index] : nullptr; +} + +// Parse one of the Intel GPU architecture names listed in IntelGPUArch.def: the +// name of an architecture ("xe-lnl-m"), the IGCA level shared by a group of +// architectures ("igca_40r"), or the numeric form the offload-arch tool prints +// for an architecture that has no name in this build ("xe_20.4.5"). A name that +// is none of these yields an unknown architecture, which the driver reports as +// 'unsupported offload gpu architecture: '. +static OffloadArch parseIntelGPUArch(llvm::StringRef S) { + for (uint32_t Index = 0; Index != NumIntelGPUArchs; ++Index) { + const IntelGPUArchEntry &Entry = IntelGPUArchs[Index]; + if (S == Entry.Name) + return OffloadArch::getIntelXeGPU(Index); + if (S == Entry.IGCALevel) + return OffloadArch::getIntelXeGPU(Index | IntelGPUIGCALevelFlag); + } + + // The numeric form spells out all three components of the GMDID, but only the + // architecture and the release are validated: the revision names a stepping + // of an architecture, and a table keyed by architecture and release cannot + // tell which steppings exist. + if (!S.consume_front("xe_")) + return OffloadArch::getUnknown(); + llvm::StringRef ArchitectureStr, ReleaseStr, RevisionStr; + std::tie(ArchitectureStr, S) = S.split('.'); + std::tie(ReleaseStr, RevisionStr) = S.split('.'); + uint32_t Architecture, Release, Revision; + if (ArchitectureStr.getAsInteger(10, Architecture) || + ReleaseStr.getAsInteger(10, Release) || + RevisionStr.getAsInteger(10, Revision)) + return OffloadArch::getUnknown(); + + for (uint32_t Index = 0; Index != NumIntelGPUArchs; ++Index) { + const IntelGPUArchEntry &Entry = IntelGPUArchs[Index]; + if (!Entry.namesAGroup() && Entry.Architecture == Architecture && + Entry.Release == Release) + return OffloadArch::getIntelXeGPU(Index); + } + return OffloadArch::getUnknown(); +} + static const IntelArchNameMap *lookupIntelArch(OffloadArch::TargetArch V, OffloadArch::IntelArch Arch) { for (const IntelArchNameMap &Entry : IntelArchNames) @@ -134,6 +215,13 @@ const char *OffloadArchToString(OffloadArch A) { lookupIntelArch(A.targetArch(), A.intelKind()); return Entry ? Entry->Name : "unknown"; } + case OffloadArch::TargetArch::IntelXeGPU: { + const IntelGPUArchEntry *Entry = lookupIntelGPUArch(A); + if (!Entry) + return "unknown"; + return A.intelXeKind() & IntelGPUIGCALevelFlag ? Entry->IGCALevel + : Entry->Name; + } case OffloadArch::TargetArch::Generic: return "generic"; } @@ -152,6 +240,7 @@ const char *OffloadArchToVirtualArchString(OffloadArch A) { case OffloadArch::TargetArch::Unused: case OffloadArch::TargetArch::IntelCPU: case OffloadArch::TargetArch::IntelGPU: + case OffloadArch::TargetArch::IntelXeGPU: case OffloadArch::TargetArch::Generic: return ""; } @@ -170,6 +259,8 @@ OffloadArch StringToOffloadArch(llvm::StringRef S) { return OffloadArch::getGeneric(); if (const IntelArchNameMap *Entry = lookupIntelArch(S)) return OffloadArch::getIntel(Entry->V, Entry->Arch); + if (OffloadArch A = parseIntelGPUArch(S); !A.isUnknown()) + return A; // Otherwise defer to the vendor TargetParser GPU lists. if (llvm::NVPTX::GPUKind NV = llvm::NVPTX::parseArch(S)) diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index 6546e611d11e6..5323049f11a21 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -963,6 +963,10 @@ getSystemOffloadArchs(Compilation &C, Action::OffloadKind Kind) { Args.push_back("--only=amdgpu"); else if (Kind == Action::OFK_Cuda) Args.push_back("--only=nvptx"); + else if (Kind == Action::OFK_SYCL) + // SYCL offloading is currently supported for Intel GPU devices only, so + // the devices of the other vendors present in the system are ignored. + Args.push_back("--only=intel"); auto StdoutOrErr = C.getDriver().executeProgram(Args); if (!StdoutOrErr) { diff --git a/clang/test/Driver/Inputs/offload-arch/offload_arch_only_intel b/clang/test/Driver/Inputs/offload-arch/offload_arch_only_intel new file mode 100644 index 0000000000000..b03a604079da4 --- /dev/null +++ b/clang/test/Driver/Inputs/offload-arch/offload_arch_only_intel @@ -0,0 +1,15 @@ +#!/bin/sh +# Mimics the 'offload-arch' utility of a system which has GPUs of several +# vendors installed: the Intel GPU is printed only when the utility is +# restricted to the Intel devices. +case "$*" in +*--only=intel*) + echo "bmg_g21" + ;; +*) + echo "sm_70" + echo "gfx906" + echo "bmg_g21" + ;; +esac +exit 0 diff --git a/clang/test/Driver/sycl-offload-arch-intel-gpu.cpp b/clang/test/Driver/sycl-offload-arch-intel-gpu.cpp index 8c73a02072645..6eb906701db02 100644 --- a/clang/test/Driver/sycl-offload-arch-intel-gpu.cpp +++ b/clang/test/Driver/sycl-offload-arch-intel-gpu.cpp @@ -117,7 +117,55 @@ // RUN: %clangxx -### --offload-new-driver --sysroot=%S/Inputs/SYCL -fsycl --offload-arch=lnl_m %s 2>&1 | \ // RUN: FileCheck %s --check-prefixes=TARGET-TRIPLE-GPU,CLANG-OFFLOAD-PACKAGER-GPU-OPTS -DDEV_STR=lnl_m -DMAC_STR=LNL_M +// The architecture names, the IGCA levels and the numeric names listed in +// clang/include/clang/Basic/IntelGPUArch.def are accepted as well. + +// RUN: %clangxx -### --offload-new-driver --sysroot=%S/Inputs/SYCL -fsycl --offload-arch=xe-lnl-m %s 2>&1 | \ +// RUN: FileCheck %s --check-prefixes=TARGET-TRIPLE-GPU-ONLY,CLANG-OFFLOAD-PACKAGER-GPU-OPTS -DDEV_STR=xe-lnl-m + +// RUN: %clangxx -### --offload-new-driver --sysroot=%S/Inputs/SYCL -fsycl --offload-arch=xe-cri %s 2>&1 | \ +// RUN: FileCheck %s --check-prefixes=TARGET-TRIPLE-GPU-ONLY,CLANG-OFFLOAD-PACKAGER-GPU-OPTS -DDEV_STR=xe-cri + +// A name that covers more than one release is accepted too. +// RUN: %clangxx -### --offload-new-driver --sysroot=%S/Inputs/SYCL -fsycl --offload-arch=xe-dg2 %s 2>&1 | \ +// RUN: FileCheck %s --check-prefixes=TARGET-TRIPLE-GPU-ONLY,CLANG-OFFLOAD-PACKAGER-GPU-OPTS -DDEV_STR=xe-dg2 + +// RUN: %clangxx -### --offload-new-driver --sysroot=%S/Inputs/SYCL -fsycl --offload-arch=igca_40r %s 2>&1 | \ +// RUN: FileCheck %s --check-prefixes=TARGET-TRIPLE-GPU-ONLY,CLANG-OFFLOAD-PACKAGER-GPU-OPTS -DDEV_STR=igca_40r + +// The revision component of a numeric name is not validated, as every stepping +// of an architecture shares one name. +// RUN: %clangxx -### --offload-new-driver --sysroot=%S/Inputs/SYCL -fsycl --offload-arch=xe_20.4.0 %s 2>&1 | \ +// RUN: FileCheck %s --check-prefixes=TARGET-TRIPLE-GPU-ONLY,CLANG-OFFLOAD-PACKAGER-GPU-OPTS -DDEV_STR=xe_20.4.0 + +// RUN: %clangxx -### --offload-new-driver --sysroot=%S/Inputs/SYCL -fsycl --offload-arch=xe_20.4.63 %s 2>&1 | \ +// RUN: FileCheck %s --check-prefixes=TARGET-TRIPLE-GPU-ONLY,CLANG-OFFLOAD-PACKAGER-GPU-OPTS -DDEV_STR=xe_20.4.63 + // TARGET-TRIPLE-GPU: clang{{.*}} "-triple" "spir64_gen-unknown-unknown" // TARGET-TRIPLE-GPU: "-D__SYCL_TARGET_INTEL_GPU_[[MAC_STR]]__" // CLANG-OFFLOAD-PACKAGER-GPU: llvm-offload-binary{{.*}} "--image={{.*}}triple=spir64_gen-unknown-unknown,arch=[[DEV_STR]],kind=sycl" +// TARGET-TRIPLE-GPU-ONLY: clang{{.*}} "-triple" "spir64_gen-unknown-unknown" // CLANG-OFFLOAD-PACKAGER-GPU-OPTS: llvm-offload-binary{{.*}} "--image={{.*}}triple=spir64_gen-unknown-unknown,arch=[[DEV_STR]],kind=sycl{{.*}}" + +// Tests for handling an incorrect architecture. +// +// RUN: not %clangxx -### --offload-new-driver --sysroot=%S/Inputs/SYCL -fsycl --offload-arch=xe-lnl %s 2>&1 | \ +// RUN: FileCheck %s --check-prefix=BAD-ARCH -DBAD_STR=xe-lnl + +// RUN: not %clangxx -### --offload-new-driver --sysroot=%S/Inputs/SYCL -fsycl --offload-arch=igca_99 %s 2>&1 | \ +// RUN: FileCheck %s --check-prefix=BAD-ARCH -DBAD_STR=igca_99 + +// The architecture and the release of a numeric name are validated. +// RUN: not %clangxx -### --offload-new-driver --sysroot=%S/Inputs/SYCL -fsycl --offload-arch=xe_20.99.0 %s 2>&1 | \ +// RUN: FileCheck %s --check-prefix=BAD-ARCH -DBAD_STR=xe_20.99.0 + +// A numeric name spells out all three components of the GMDID. +// RUN: not %clangxx -### --offload-new-driver --sysroot=%S/Inputs/SYCL -fsycl --offload-arch=xe_20.4 %s 2>&1 | \ +// RUN: FileCheck %s --check-prefix=BAD-ARCH -DBAD_STR=xe_20.4 + +// The sentinel GMDID of a name that covers more than one release is not a GMDID +// that a device reports. +// RUN: not %clangxx -### --offload-new-driver --sysroot=%S/Inputs/SYCL -fsycl --offload-arch=xe_0.0.0 %s 2>&1 | \ +// RUN: FileCheck %s --check-prefix=BAD-ARCH -DBAD_STR=xe_0.0.0 + +// BAD-ARCH: error: unsupported offload gpu architecture: [[BAD_STR]] diff --git a/clang/test/Driver/sycl-offload-arch-native.cpp b/clang/test/Driver/sycl-offload-arch-native.cpp new file mode 100644 index 0000000000000..efeeb7973651d --- /dev/null +++ b/clang/test/Driver/sycl-offload-arch-native.cpp @@ -0,0 +1,32 @@ +/// Tests the behavior of using -fsycl --offload-new-driver +// --offload-arch=native. +// +// SYCL offloading is supported for Intel GPU devices only, so the driver is +// expected to restrict the 'offload-arch' utility to the Intel devices. + +// Needs chmod +// UNSUPPORTED: system-windows + +// RUN: mkdir -p %t +// RUN: cp %S/Inputs/offload-arch/offload_arch_only_intel %t/ +// RUN: echo '#!/bin/sh' > %t/offload_arch_empty +// RUN: chmod +x %t/offload_arch_only_intel %t/offload_arch_empty + +// The devices of the other vendors reported by 'offload-arch' are not turned +// into SYCL offloading targets. +// RUN: %clangxx -### --offload-new-driver --sysroot=%S/Inputs/SYCL -fsycl \ +// RUN: --offload-arch=native --offload-arch-tool=%t/offload_arch_only_intel %s 2>&1 | \ +// RUN: FileCheck %s --check-prefix=NATIVE \ +// RUN: --implicit-check-not="nvptx64-nvidia-cuda" \ +// RUN: --implicit-check-not="amdgcn-amd-amdhsa" + +// NATIVE: clang{{.*}} "-triple" "spir64_gen-unknown-unknown" +// NATIVE: "-D__SYCL_TARGET_INTEL_GPU_BMG_G21__" +// NATIVE: llvm-offload-binary{{.*}} "--image={{.*}}triple=spir64_gen-unknown-unknown,arch=bmg_g21,kind=sycl{{.*}}" + +// Case when no device supporting SYCL is detected in the system. +// RUN: not %clangxx -### --offload-new-driver --sysroot=%S/Inputs/SYCL -fsycl \ +// RUN: --offload-arch=native --offload-arch-tool=%t/offload_arch_empty %s 2>&1 | \ +// RUN: FileCheck %s --check-prefix=NO-DEVICE + +// NO-DEVICE: error: cannot determine sycl architecture: No GPU detected in the system diff --git a/clang/tools/offload-arch/IntelGPUArch.def b/clang/tools/offload-arch/IntelGPUArch.def deleted file mode 100644 index 75c64b72e2f4a..0000000000000 --- a/clang/tools/offload-arch/IntelGPUArch.def +++ /dev/null @@ -1,69 +0,0 @@ -//===--- IntelGPUArch.def - Intel GPU architecture names --------*- 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 lists the human-friendly names of the Intel GPU architectures, -// keyed by the architecture and release components of the GMDID that the -// device reports. The revision component is deliberately not part of the key: -// every stepping of an architecture shares one name. -// -// Several devices can share an architecture and release. The entries are -// ordered so that the name to print for such a group comes first, which lets -// this file be generated from a device list without having to pick a -// representative device. Groups that cover more than one release, such as -// xe-dg2 or xe-mtl, have no GMDID of their own and are therefore not listed. -// -// The intent is for this table to be generated from the data published by the -// GPU driver, so keep it free of anything a generator cannot produce. -// -//===----------------------------------------------------------------------===// - -#ifndef INTEL_GPU_ARCH -#error "Define INTEL_GPU_ARCH prior to including this file!" -#endif - -// INTEL_GPU_ARCH(ARCHITECTURE, RELEASE, NAME) -INTEL_GPU_ARCH(35, 11, "xe-cri") -INTEL_GPU_ARCH(35, 10, "xe-nvl-p") -INTEL_GPU_ARCH(30, 5, "xe-nvl-u") -INTEL_GPU_ARCH(30, 5, "xe-nvl-h") -INTEL_GPU_ARCH(30, 4, "xe-nvl-s") -INTEL_GPU_ARCH(30, 4, "xe-nvl-hx") -INTEL_GPU_ARCH(30, 4, "xe-nvl-ul") -INTEL_GPU_ARCH(30, 3, "xe-wcl") -INTEL_GPU_ARCH(30, 1, "xe-ptl-u") -INTEL_GPU_ARCH(30, 0, "xe-ptl-h") -INTEL_GPU_ARCH(20, 4, "xe-lnl-m") -INTEL_GPU_ARCH(20, 2, "xe-bmg-g31") -INTEL_GPU_ARCH(20, 1, "xe-bmg-g21") -INTEL_GPU_ARCH(12, 74, "xe-arl-h") -INTEL_GPU_ARCH(12, 71, "xe-mtl-h") -INTEL_GPU_ARCH(12, 70, "xe-mtl-u") -INTEL_GPU_ARCH(12, 70, "xe-arl-u") -INTEL_GPU_ARCH(12, 70, "xe-arl-s") -INTEL_GPU_ARCH(12, 61, "xe-pvc-vg") -INTEL_GPU_ARCH(12, 60, "xe-pvc") -INTEL_GPU_ARCH(12, 60, "xe-pvc-sdv") -INTEL_GPU_ARCH(12, 57, "xe-acm-g12") -INTEL_GPU_ARCH(12, 57, "xe-dg2-g12") -INTEL_GPU_ARCH(12, 56, "xe-acm-g11") -INTEL_GPU_ARCH(12, 56, "xe-dg2-g11") -INTEL_GPU_ARCH(12, 56, "xe-ats-m75") -INTEL_GPU_ARCH(12, 55, "xe-acm-g10") -INTEL_GPU_ARCH(12, 55, "xe-dg2-g10") -INTEL_GPU_ARCH(12, 55, "xe-ats-m150") -INTEL_GPU_ARCH(12, 10, "xe-dg1") -INTEL_GPU_ARCH(12, 4, "xe-adl-n") -INTEL_GPU_ARCH(12, 3, "xe-adl-p") -INTEL_GPU_ARCH(12, 3, "xe-rpl-p") -INTEL_GPU_ARCH(12, 2, "xe-adl-s") -INTEL_GPU_ARCH(12, 2, "xe-rpl-s") -INTEL_GPU_ARCH(12, 1, "xe-rkl") -INTEL_GPU_ARCH(12, 0, "xe-tgllp") -INTEL_GPU_ARCH(12, 0, "xe-tgl") - -#undef INTEL_GPU_ARCH diff --git a/clang/tools/offload-arch/LevelZeroArch.cpp b/clang/tools/offload-arch/LevelZeroArch.cpp index 7e1b5c3bb6894..de7752b90f59f 100644 --- a/clang/tools/offload-arch/LevelZeroArch.cpp +++ b/clang/tools/offload-arch/LevelZeroArch.cpp @@ -163,15 +163,16 @@ static constexpr uint32_t GMDIDRevisionMask = 0x3f; // Human-friendly names of the known Intel GPU architectures, keyed by the // architecture and release components of the GMDID. Several devices can share // an architecture and a release, in which case the first of them names the -// whole group. +// whole group. Names that cover more than one release have a sentinel GMDID of +// zero, as no single device reports them. static constexpr struct { uint32_t Architecture; uint32_t Release; const char *Name; } IntelGPUArchNames[] = { -#define INTEL_GPU_ARCH(ARCHITECTURE, RELEASE, NAME) \ +#define INTEL_GPU_ARCH(ARCHITECTURE, RELEASE, NAME, IGCA) \ {ARCHITECTURE, RELEASE, NAME}, -#include "IntelGPUArch.def" +#include "clang/Basic/IntelGPUArch.def" }; // Translate a GMDID into an architecture name that is a legal --offload-arch @@ -183,9 +184,13 @@ std::string getIntelGPUArchName(uint32_t IPVersion) { uint32_t Release = (IPVersion >> GMDIDReleaseShift) & GMDIDReleaseMask; uint32_t Revision = IPVersion & GMDIDRevisionMask; - for (const auto &Entry : IntelGPUArchNames) + for (const auto &Entry : IntelGPUArchNames) { + // The entries that name a group of releases have no GMDID to match against. + if (Entry.Architecture == 0 && Entry.Release == 0) + continue; if (Entry.Architecture == Architecture && Entry.Release == Release) return Entry.Name; + } // A device this build has never heard of still has to be named, so that it // can be used with a compiler that predates it. The numeric name spells out diff --git a/clang/unittests/Basic/OffloadArchTest.cpp b/clang/unittests/Basic/OffloadArchTest.cpp index 24f42d668183c..888a98926d14e 100644 --- a/clang/unittests/Basic/OffloadArchTest.cpp +++ b/clang/unittests/Basic/OffloadArchTest.cpp @@ -56,7 +56,8 @@ TEST(OffloadArchTest, Unknown) { TEST(OffloadArchTest, RoundTrip) { for (const char *Name : {"sm_52", "sm_90a", "gfx906", "gfx1201", "gfx12-generic", "amdgcnspirv", - "graniterapids", "bmg_g21", "generic"}) { + "graniterapids", "bmg_g21", "generic", "xe-bmg-g21", "xe-dg2", + "igca_40r"}) { OffloadArch A = parse(Name); EXPECT_FALSE(A.isUnknown()) << Name; EXPECT_STREQ(OffloadArchToString(A), Name); @@ -89,3 +90,52 @@ TEST(OffloadArchTest, IntelGPUFamilyArchParsing) { OffloadArch::getIntel(OffloadArch::TargetArch::IntelGPU, OffloadArch::IntelArch::PTL)); } + +// The names the GPU driver uses, as listed in IntelGPUArch.def: the name of an +// architecture, the IGCA level of a group of architectures, or the numeric form +// of a GMDID. +TEST(OffloadArchTest, IntelGPUArchNames) { + EXPECT_TRUE(parse("xe-lnl-m").isIntelXeGPU()); + EXPECT_TRUE(parse("xe-lnl-m").isIntelGPU()); + EXPECT_TRUE(parse("xe-lnl-m").isIntel()); + EXPECT_TRUE(parse("xe-cri").isIntelXeGPU()); + EXPECT_TRUE(parse("igca_40r").isIntelXeGPU()); + EXPECT_TRUE(parse("xe_20.4.5").isIntelXeGPU()); + + // A name that covers more than one release has no GMDID of its own, but is + // still a name. + EXPECT_TRUE(parse("xe-dg2").isIntelXeGPU()); + + EXPECT_TRUE(parse("xe-lnl").isUnknown()); + EXPECT_TRUE(parse("igca_99").isUnknown()); +} + +// The revision component of a numeric name is not validated: every stepping of +// an architecture shares one name. +TEST(OffloadArchTest, IntelGPUNumericArchNames) { + EXPECT_EQ(parse("xe_20.4.0"), parse("xe-lnl-m")); + EXPECT_EQ(parse("xe_20.4.63"), parse("xe-lnl-m")); + + // Several architectures can share an architecture and a release, in which + // case the first of them names the group. + EXPECT_EQ(parse("xe_12.55.0"), parse("xe-acm-g10")); + + // An architecture and release that no entry has. + EXPECT_TRUE(parse("xe_20.99.0").isUnknown()); + + // The sentinel GMDID of a name that covers more than one release is not a + // GMDID that a device reports. + EXPECT_TRUE(parse("xe_0.0.0").isUnknown()); + + for (const char *Name : {"xe_20.4", "xe_20.4.5.6", "xe_20.4.x", "xe_.4.5", + "xe_-20.4.5", "xe_20.4.-5", "xe_"}) + EXPECT_TRUE(parse(Name).isUnknown()) << Name; +} + +// The IGCA level and the name of an architecture stay apart, as they name +// different sets of devices. +TEST(OffloadArchTest, IntelGPUArchNameAndIGCALevelDiffer) { + EXPECT_NE(parse("igca_40r"), parse("xe-lnl-m")); + EXPECT_STREQ(OffloadArchToString(parse("igca_40r")), "igca_40r"); + EXPECT_STREQ(OffloadArchToString(parse("xe-bmg-g31")), "xe-bmg-g31"); +} diff --git a/clang/unittests/offload-arch/OffloadArchTest.cpp b/clang/unittests/offload-arch/OffloadArchTest.cpp index be6d83d5ed4ff..b16c52eac2db6 100644 --- a/clang/unittests/offload-arch/OffloadArchTest.cpp +++ b/clang/unittests/offload-arch/OffloadArchTest.cpp @@ -158,3 +158,9 @@ TEST(IntelGPUArchName, UnknownArchitecturesGetANumericName) { TEST(IntelGPUArchName, LegacyArchitecture) { EXPECT_EQ(getIntelGPUArchName(gmdid(9, 0, 9)), "xe_9.0.9"); } + +// The entries that name a group of releases carry a sentinel GMDID that no +// device reports, so they never name a device. +TEST(IntelGPUArchName, GroupNamesDoNotNameADevice) { + EXPECT_EQ(getIntelGPUArchName(gmdid(0, 0, 0)), "xe_0.0.0"); +}