Skip to content

[SYCL][Driver] Validate the Intel GPU names of '--offload-arch' - #23060

Closed
KornevNikita wants to merge 8 commits into
intel:syclfrom
KornevNikita:offload-arch-validate
Closed

KornevNikita wants to merge 8 commits into
intel:syclfrom
KornevNikita:offload-arch-validate

Conversation

@KornevNikita

Copy link
Copy Markdown
Contributor

Record the IGCA level of every device in IntelGPUArch.def, so that the
table lists both names a device answers to, and add the names that cover
more than one release (xe-dg2, xe-mtl, xe-bmg, xe-ptl) with a sentinel
GMDID of zero. Move the table to clang/include/clang/Basic/ so that the
driver and the offload-arch tool can share it.

The driver now accepts, and validates against that table, the three
forms of a name the GPU driver uses: the name of an architecture
('xe-lnl-m'), the IGCA level shared by a group of architectures
('igca_40r'), and the numeric form the offload-arch tool prints for an
architecture this build has no name for ('xe_20.4.5'). Of the numeric
form only the architecture and the release are validated, as every
stepping of an architecture shares one name. Anything else is rejected
with the existing 'unsupported offload gpu architecture' diagnostic.

Co-Authored-By: Claude Opus 5 noreply@anthropic.com

KornevNikita and others added 5 commits August 28, 2026 14:45
…ames

The output of this utility is expected to be a list of names that are legal
--offload-arch parameters, but for Intel GPUs it printed the name of the
device, e.g. "Intel(R) Data Center GPU Max 1100", which is not one.

Query the GMDID of each device with zeDeviceGetProperties and the device IP
version extension, and translate its architecture and release components into
an architecture name using the table in IntelGPUArch.def, which is meant to be
generated from the data published by the GPU driver.  A device that has no
entry in the table is named after all three components of its GMDID, e.g.
xe_40.11.0, so that a GPU newer than the compiler is still usable.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
(cherry picked from commit a7e6682f197f7603915e5de75bc17683f8be6455)
Record the IGCA level of every device in IntelGPUArch.def, so that the
table lists both names a device answers to, and add the names that cover
more than one release (xe-dg2, xe-mtl, xe-bmg, xe-ptl) with a sentinel
GMDID of zero. Move the table to clang/include/clang/Basic/ so that the
driver and the offload-arch tool can share it.

The driver now accepts, and validates against that table, the three
forms of a name the GPU driver uses: the name of an architecture
('xe-lnl-m'), the IGCA level shared by a group of architectures
('igca_40r'), and the numeric form the offload-arch tool prints for an
architecture this build has no name for ('xe_20.4.5'). Of the numeric
form only the architecture and the release are validated, as every
stepping of an architecture shares one name. Anything else is rejected
with the existing 'unsupported offload gpu architecture' diagnostic.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
# Conflicts:
#	clang/tools/offload-arch/LevelZeroArch.cpp
#	clang/unittests/offload-arch/OffloadArchTest.cpp

@tahonermann tahonermann left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks pretty good. I added some comments regarding asserts and diagnostics.

Comment thread clang/include/clang/Basic/OffloadArch.h Outdated
Comment on lines +168 to +171
// Only valid when isIntelCPU(), or when isIntelGPU() and !isIntelXeGPU().
IntelArch intelKind() const { return static_cast<IntelArch>(Kind); }
// Only valid when isIntelXeGPU(); opaque outside of OffloadArch.cpp.
uint32_t intelXeKind() const { return Kind; }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason not to assert the preconditions?

Suggested change
// Only valid when isIntelCPU(), or when isIntelGPU() and !isIntelXeGPU().
IntelArch intelKind() const { return static_cast<IntelArch>(Kind); }
// Only valid when isIntelXeGPU(); opaque outside of OffloadArch.cpp.
uint32_t intelXeKind() const { return Kind; }
// Only valid when isIntelCPU(), or when isIntelGPU() and !isIntelXeGPU().
IntelArch intelKind() const {
assert(isIntelCPU() || (isIntelGPU() && !isIntelXeGPU()), "Intel CPU or non-Xe GPU required");
return static_cast<IntelArch>(Kind);
}
// Only valid when isIntelXeGPU(); opaque outside of OffloadArch.cpp.
uint32_t intelXeKind() const {
assert(isIntelXeGPU(), "Intel Xe GPU required");
return Kind;
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added asserts d992cfc

Comment thread clang/include/clang/Basic/OffloadArch.h Outdated
Comment on lines +134 to +136
static constexpr OffloadArch getIntelXeGPU(uint32_t Kind) {
return {TargetArch::IntelXeGPU, Kind};
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can it be asserted that Kind matches a Xe GPU?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated the function - d992cfc

Comment thread clang/lib/Basic/OffloadArch.cpp

@tahonermann tahonermann left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @KornevNikita, looks good to me. I added one comment regarding a possible group architecture addition, but I understand if such decisions aren't ours to make.

Comment on lines +40 to +45
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")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These all have a consistent name prefix and map to the same IGCA level. Should there not be a "xe-nvl" group name for these?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIUC not all nvc-* devices share the same device code, e.g. xe-nvl-p is different from the rest of xe-nvl-*.

Actually xe-ptl covers all xe-nvl-u*, xe-nvl-h*, xe-nvl-s, xe-wcl and xe-ptl-* targets (but not xe-nvl-p), see https://github.com/intel/llvm/blob/sycl/sycl/doc/UsersManual.md.

And there are also other group names like xe-dg2 etc.

@KornevNikita

Copy link
Copy Markdown
Contributor Author

@srividya-sundaram could you please take a look?

@tahonermann

Copy link
Copy Markdown
Contributor

@KornevNikita, what is the plan for pushing these changes to upstream. We'll need them there to work on the frontend portions of the IGCA support.

@KornevNikita

Copy link
Copy Markdown
Contributor Author

@intel/dpcpp-clang-driver-reviewers could you take a look please?

@KornevNikita

KornevNikita commented Sep 7, 2026 •

Copy link
Copy Markdown
Contributor Author

@KornevNikita, what is the plan for pushing these changes to upstream. We'll need them there to work on the frontend portions of the IGCA support.

My plan was to keep this work in intel/llvm according to the consensus to increase the chances of this feature getting into 2026.3, and to move it to upstream once the feature is ready.

We'll need them there to work on the frontend portions of the IGCA support.

Do you mean it's needed in the upstream right now?

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")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I notice that group entries with same IGCA level but with ARCHITECTURE and RELEASE set to 0 are ordered last.

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") --> group entry
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") --> group entry

Currently, --offload-arch = igca_40r currently resolves to xe-lnl-m because it happens to be first in the ordered list.

But if the group entry xe-bmg were ever moved to the top of its IGCA group then --offload-arch = igca_40r would resolve to the group entry instead of a real device.

Can we skip IGCA level scanning with !Entry.namesAGroup() for group entries?

@KornevNikita KornevNikita Sep 7, 2026 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just curious - why a specific gpu name is better than a group name?
09b7e7e

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OCLOC would not know for which real device the code should be compiled for. The driver wouldnt have any valid arch value to pass either.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't clock support generic targets like dg2, bmg? For me it seems like xe-bmg should be a valid target?

return static_cast<IntelArch>(Kind);
}
// Only valid when isIntelXeGPU(); opaque outside of OffloadArch.cpp.
uint32_t intelXeKind() const {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
uint32_t intelXeKind() const {
uint32_t intelXeArchIndex() const {

Comment on lines +130 to +132
// 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.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// 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.
// An intelXeKind holds the index of the entry it names.
// Packed as (IntelGPUIGCALevelFlag | index into IntelGPUArchs[]).
// IntelGPUIGCALevelFlag is 0 when a device name (e.g. "xe-lnl-m") is passed,
// and 1 when an IGCA level (e.g. "igca_40r") is passed.


static const IntelGPUArchEntry *lookupIntelGPUArch(OffloadArch A) {
uint32_t Index = A.intelXeKind() & ~IntelGPUIGCALevelFlag;
return Index < NumIntelGPUArchs ? &IntelGPUArchs[Index] : nullptr;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Index should be valid by getIntelXeGPU()'s assert, correct?
Do we need this additional check for Index again here? Wondering if we will ever hit the else part to return nullptr here.


OffloadArch OffloadArch::getIntelXeGPU(uint32_t Kind) {
assert((Kind & ~IntelGPUIGCALevelFlag) < NumIntelGPUArchs &&
"Kind does not name an entry of IntelGPUArch.def");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"Kind does not name an entry of IntelGPUArch.def");
"index does not name an entry of IntelGPUArch.def";

"not an Intel CPU or a non-Xe Intel GPU");
return static_cast<IntelArch>(Kind);
}
// Only valid when isIntelXeGPU(); opaque outside of OffloadArch.cpp.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

opaque outside of OffloadArch.cpp.

Can we make this private since this is used only inside OffloadArch.cpp?

Or it might be better to replace this with:

// Only valid when isIntelXeGPU(). Returns the index into IntelGPUArchs[].
uint32_t intelXeArchIndex() const;
// Only valid when isIntelXeGPU(). Returns true if an IGCA level
// (e.g. "igca_40r") was passed rather than a device name.
bool intelXeIsIGCALevel() const;

// different sets of devices.
TEST(OffloadArchTest, IntelGPUArchNameAndIGCALevelDiffer) {
EXPECT_NE(parse("igca_40r"), parse("xe-lnl-m"));
EXPECT_STREQ(OffloadArchToString(parse("igca_40r")), "igca_40r");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we also include a test like this?

// igca_40r is shared by xe-lnl-m, xe-bmg-g31, xe-bmg-g21, and the group
// xe-bmg. Verify it resolves to the first real device entry, not the group.
EXPECT_EQ(parse("igca_40r"), parse("xe-lnl-m"));

@tahonermann

tahonermann commented Sep 8, 2026 •

Copy link
Copy Markdown
Contributor

@KornevNikita,

We'll need them there to work on the frontend portions of the IGCA support.

Do you mean it's needed in the upstream right now?

Yes. In accordance with our upstream first strategy, our intent is to push all changes upstream when they are ready and when that is possible (in some cases, upstream is missing foundational work that can't be quickly resolved). The goal is to minimize discrepancies with upstream and the overhead of tracking changes that have not yet been pushed upstream.

@KornevNikita

Copy link
Copy Markdown
Contributor Author

@tahonermann we synced with @srividya-sundaram offline. We agreed that I would close this PR and she would handle this task in the upstream.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants