Conversation
An object compiled with '-fsycl -fno-sycl-rdc -c' could not be linked
into a program by anything but the SYCL-aware driver, even though
non-RDC means the device code of a translation unit is final at compile
time. Linking such an object with a plain host linker produced a binary
that aborted at the first kernel launch:
$ clang++ -fsycl -fno-gpu-rdc -fPIE -c test.cpp -o test.o
$ g++ test.o $(pkg-config --libs sycl-dpcpp-7) -o test.gcc
$ ./test.gcc
Assertion `It != m_DeviceKernelInfoMap.end()' failed.
Two things were in the way.
First, the compile-time device link was gated on Triple::isSPIRAOT(),
so for the default JIT 'spir64' target '-fno-sycl-rdc -c' had no effect
at all: the object carried plain device IR in a '__CLANG_OFFLOAD_BUNDLE__'
section and needed the final link to finish the device pipeline. Gate it
on SYCL::hasFinalDeviceImage() instead, which accepts every SPIR-V
target. NVPTX, AMDGCN and NativeCPU still need the device link to run
as part of the host link, so they keep the old behaviour.
Second, even for AOT the finalized image was hidden in an offload bundle
section. Bundles are created 'readonly,exclude' (SHF_EXCLUDE), which is
exactly what makes a host linker drop them, so no device image was
registered and the kernel info map stayed empty. Merge the wrapped
device object into the host object with a partial link ('<linker> -r')
instead of bundling it, via a new PartialLinkJobAction and a matching
tools::PartialLink. The result is an ordinary relocatable object whose
'__sycl_register_lib' constructor registers the image on its own, so any
host linker will do. MSVC provides no '-r', so Windows keeps bundling.
The wrapper names the section holding the image data after the offload
bundle convention, so with the image now living in the host object the
bundler would mistake such an object for a fat one. Require SHF_EXCLUDE
in ObjectFileHandler::IsOffloadSection to tell the two apart.
Link-time handling of the '_image' suffixed bundle target name is kept -
Windows objects and objects from older compilers still use it - and the
list of architecture names it looks for is now shared with the driver
through SYCL::getFinalDeviceImageArchNames().
Finally, replace the two asserts in ProgramManager::getDeviceKernelInfo()
with a sycl::exception: a kernel missing from the map means no device
image provided it, which is a build problem to be reported rather than
an internal invariant to abort on (and 'It->second' on end() is undefined
behaviour in an NDEBUG build).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This commit is entirely authored by Claude. I provide it as a draft PR in the hope it can be used as a fix or will help to narrow the root cause of the issue. It requires a review from compiler team expert. See #23097
An object compiled with
-fsycl -fno-sycl-rdc -ccould not be linked into a program by anything but the SYCL-aware driver, even though non-RDC means the device code of a translation unit is final at compile time. Linking such an object with a plain host linker produced a binary that aborted at the first kernel launch:Two things were in the way.
First, the compile-time device link was gated on
Triple::isSPIRAOT(), so for the default JITspir64target-fno-sycl-rdc -chad no effect at all: the object carried plain device IR in a__CLANG_OFFLOAD_BUNDLE__section and needed the final link to finish the device pipeline. Gate it onSYCL::hasFinalDeviceImage()instead, which accepts every SPIR-V target. NVPTX, AMDGCN and NativeCPU still need the device link to run as part of the host link, so they keep the old behaviour.Second, even for AOT the finalized image was hidden in an offload bundle section. Bundles are created
readonly,exclude(SHF_EXCLUDE), which is exactly what makes a host linker drop them, so no device image was registered and the kernel info map stayed empty. Merge the wrapped device object into the host object with a partial link (<linker> -r) instead of bundling it, via a new PartialLinkJobAction and a matchingtools::PartialLink. The result is an ordinary relocatable object whose__sycl_register_libconstructor registers the image on its own, so any host linker will do. MSVC provides no-r, so Windows keeps bundling.The wrapper names the section holding the image data after the offload bundle convention, so with the image now living in the host object the bundler would mistake such an object for a fat one. Require SHF_EXCLUDE in ObjectFileHandler::IsOffloadSection to tell the two apart.
Link-time handling of the
_imagesuffixed bundle target name is kept - Windows objects and objects from older compilers still use it - and the list of architecture names it looks for is now shared with the driver throughSYCL::getFinalDeviceImageArchNames().Finally, replace the two asserts in
ProgramManager::getDeviceKernelInfo()with a sycl::exception: a kernel missing from the map means no device image provided it, which is a build problem to be reported rather than an internal invariant to abort on (andIt->secondon end() is undefined behavior in an NDEBUG build).Co-Authored-By: Claude Opus 5 noreply@anthropic.com
CC: @tahonermann, @YuriPlyakhin, @srividya-sundaram