Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 82 additions & 0 deletions clang/include/clang/Basic/IntelGPUArch.def
Original file line number Diff line number Diff line change
@@ -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
28 changes: 24 additions & 4 deletions clang/include/clang/Basic/OffloadArch.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#define LLVM_CLANG_BASIC_OFFLOADARCH_H

#include "llvm/ADT/StringRef.h"
#include <cassert>
#include <cstdint>
#include <tuple>

Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -127,6 +132,9 @@ class OffloadArch {
static constexpr OffloadArch getIntel(TargetArch V, IntelArch A) {
return {V, static_cast<uint32_t>(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}; }
Expand All @@ -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; }
Expand All @@ -155,8 +166,17 @@ class OffloadArch {
llvm::AMDGPU::GPUKind amdgpuKind() const {
return static_cast<llvm::AMDGPU::GPUKind>(Kind);
}
// Only valid when isIntelCPU() / isIntelGPU().
IntelArch intelKind() const { return static_cast<IntelArch>(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<IntelArch>(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;
Expand Down
91 changes: 91 additions & 0 deletions clang/lib/Basic/OffloadArch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "llvm/TargetParser/AMDGPUTargetParser.h"
#include "llvm/TargetParser/NVPTXTargetParser.h"
#include "llvm/TargetParser/Triple.h"
#include <iterator>

namespace clang {

Expand Down Expand Up @@ -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: <name>'.
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)
Expand Down Expand Up @@ -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";
}
Expand All @@ -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 "";
}
Expand All @@ -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))
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Driver/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
15 changes: 15 additions & 0 deletions clang/test/Driver/Inputs/offload-arch/offload_arch_only_intel
Original file line number Diff line number Diff line change
@@ -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
48 changes: 48 additions & 0 deletions clang/test/Driver/sycl-offload-arch-intel-gpu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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]]
32 changes: 32 additions & 0 deletions clang/test/Driver/sycl-offload-arch-native.cpp
Original file line number Diff line number Diff line change
@@ -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
Loading
Loading