Skip to content

[SYCL] Avoid runtime registration for empty device pre-link outputs - #23545

Open
vishalshetagar wants to merge 6 commits into
intel:syclfrom
vishalshetagar:fix/23528-sycl-link-empty-images
Open

vishalshetagar wants to merge 6 commits into
intel:syclfrom
vishalshetagar:fix/23528-sycl-link-empty-images

Conversation

@vishalshetagar

@vishalshetagar vishalshetagar commented Oct 19, 2026 •

Copy link
Copy Markdown

-fsycl-link currently introduces SYCL runtime registration references even when its inputs contain no device images or only empty images. This prevents host-only and kernel-free configurations from linking with a host linker unless they also link the SYCL runtime.

Make both offload driver paths produce the required output without references to __sycl_register_lib or __sycl_unregister_lib when there is nothing to register. Both offload wrappers skip registration for empty image sets, and both post-link implementations omit empty modules. The post-link tool returns before writing unused IR, property, or symbol files.

When device pre-linking has no device inputs, a dedicated helper emits an empty object for the host triple while keeping device-triple validation strict in the normal wrapping path. For non-RDC compilation, retain the SYCL image group after post-link filtering and emit a placeholder container only when the combined group is empty, so host compilation still receives its required input. Preserve registration and metadata for nonempty images, mixed image sets, and NativeCPU placeholders.

Add an end-to-end test covering host-only pre-linking, kernel-free SYCL pre-linking, and empty non-RDC compilation with both drivers, followed by host linking and execution without the SYCL runtime. Extend compiler regressions for empty and mixed images, ELF/COFF output, NativeCPU entry tables and registration, and empty post-link output. Give fixtures that require nonempty device images real kernels.

Fixes #23528.

When -fsycl-link has no device images or only empty images, emit the
required output object without references to __sycl_register_lib or
__sycl_unregister_lib. This allows a host linker to link host-only and
kernel-free configurations without the SYCL runtime.

Handle empty images in both offload wrappers, omit empty modules from
post-link image tables, and generate an empty object when the new driver
has no device-link outputs. Preserve registration for nonempty images
and NativeCPU placeholders.

Extend existing regression tests for empty and mixed images, host-only
inputs, and empty modules through both post-link implementations.

Fixes intel#23528
@vishalshetagar
vishalshetagar requested review from a team as code owners October 19, 2026 19:22
Copilot AI balanced review requested due to automatic review settings October 19, 2026 19:22

Copilot AI 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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

An organization owner can choose the repository organization as the billing source for reviews requested by members with a paid Copilot license. Learn about Copilot code review billing.

Give the non-RDC wrapper and linker-wrapper command tests a kernel so
post-link processing retains an image. Empty sources now correctly omit
images and registration, so they cannot exercise image sections or the
missing-ocloc diagnostic.

Disable integration-header inclusion to keep these standalone fixtures
independent of installed SYCL headers and host C++ libraries. Extend the
non-RDC test to check that empty ELF and COFF objects contain no embedded
device image or SYCL registration references.

Reproduced both original failures with the PR's CI-built compiler. The
updated tests pass, along with the surrounding SYCL driver, wrapper, and
post-link tests: 294 passed, 3 expected failures, 15 unsupported, and no
unexpected failures.
@sarnex

sarnex commented Oct 21, 2026

Copy link
Copy Markdown
Contributor

@vishalshetagar Looks like the PR needs to be merged with HEAD since there are merge conflicts, could you take a look? Thanks

…mpty-images

# Conflicts:
#	clang/test/OffloadTools/clang-linker-wrapper/linker-wrapper-sycl.cpp
#	clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
…mpty-images

# Conflicts:
#	clang/test/Driver/sycl-nordc-wrapper-object.cpp
#	clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
Keep the SYCL image group when post-link removes every image. Emit a
container with one empty image only when the combined group is empty,
so the host compilation still has its required input and omits runtime
registration. Mixed target groups retain only their nonempty images.

Extend the existing image test for empty tool/library post-link paths,
ELF and COFF host wrapping, and mixed targets. Give the no-RDC section
fixture a real kernel because its checks require a nonempty image.

Validated with 139 focused lit tests, Linux host linking for both drivers,
12 ELF/COFF wrapper checks, and native Windows linking/execution of eight
executables and eight DLLs plus two nonempty failure controls.
@vishalshetagar

Copy link
Copy Markdown
Author

Thanks @sarnex I’ve merged the latest upstream sycl branch and resolved the conflicts. Retesting caught an empty-image issue with the updated non-RDC flow, which I fixed in the follow-up commit.

All 139 focused regression tests passed, along with Linux and native Windows linking checks. The changes are pushed and the PR description is updated.

@vishalshetagar

vishalshetagar commented Nov 2, 2026 •

Copy link
Copy Markdown
Author

@sarnex Could you please rerun all jobs for the Windows workflow? The latest retry failed downloading sycl_windows_default. The build succeeded on October 23, but the toolchain artifact has a three-day retention period, so the November 2 retry needs a fresh build. Thanks!

@sarnex

sarnex commented Nov 2, 2026

Copy link
Copy Markdown
Contributor

Done, you can ignore the Windows Arc failure, it's not related to this change

@sarnex

sarnex commented Nov 2, 2026

Copy link
Copy Markdown
Contributor

Ping @intel/dpcpp-tools-reviewers @intel/dpcpp-clang-driver-reviewers for review, thanks!

@mdtoguchi mdtoguchi 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.

An end-to-end test would be good (sycl/test-e2e) that covers this scenario.

Also, please clean up the commit message and detail what the full scope of the changes are without all of the testing result information.

const ArgList &Args, bool IsEmbeddedIR = false) {
StringRef Target = Args.getLastArgValue(OPT_triple_EQ);
if (Target.empty())
if (Target.empty() && !SplitModules.empty())

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 relaxes the -triple check. Could the empty case get a small dedicated helper (emit an empty wrapper object for the host triple), so this check stays strict for everyone else?

return SYCLImagesOrErr.takeError();

std::scoped_lock<decltype(ImageMtx)> Guard(ImageMtx);
auto &SYCLImages = Images[OFK_SYCL];

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.

A comment explaining the need for this would be good to have, as it isn't clear that the potential empty Input would be used at L3196

return BinOrErr.takeError();
MemoryBuffer *Bin = *BinOrErr;
HasNonEmptyImage |=
Bin->getBufferSize() != 0 || Triple(Img.Tgt).isNativeCPU();

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.

Is the NativeCPU exception here tested? Would be good to make sure that the empty native_cpu image produces the needed info.

SYCLWrappingOptions Options) {
if (llvm::all_of(Images, [](const SYCLImage &Image) {
return Image.Image->getBufferSize() == 0 &&
Image.Target != "native_cpu";

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.

Maybe use Triple(Image.Target).isNativeCPU() for consistency with clang-offload-wrapper.

}
addTableRow(*Table, CopyTriple);
if (!MD.getModule().global_values().empty() ||
!MD.getModule().getModuleInlineAsm().empty())

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.

We are only adding the as long as we aren't empty, looks like we can exit early if this condition isn't met as opposed to only exiting right before we have already generated the info.

Exercise host-only and kernel-free device pre-linking with both offload
drivers, then link and run the results without the SYCL runtime. Cover
empty non-RDC compilation as well, and disable automatic SYCL library
dependencies in Windows objects.

Emit the empty host wrapper object through a dedicated helper so normal
wrapping retains strict device-triple validation. Explain why the empty
SYCL image group must survive post-link filtering for fatbin-only output.

Use Triple::isNativeCPU consistently when deciding whether an empty image
still needs registration. Check NativeCPU entry tables and registration
with both wrappers for ELF and COFF hosts.

Return before writing unused post-link files for empty modules, and check
that only the empty image table is produced.
@vishalshetagar
vishalshetagar requested a review from a team as a code owner November 3, 2026 01:24
@vishalshetagar

vishalshetagar commented Nov 3, 2026 •

Copy link
Copy Markdown
Author

@mdtoguchi Thanks for the review. Addressed all five inline suggestions in b64f560 and added an E2E test covering host-only and kernel-free pre-linking, plus empty non-RDC compilation, with both drivers. The test links and runs without the SYCL runtime.

I also cleaned up the PR description, which will become the squash commit message, to describe the full scope without the testing results. Could you please take another look?

@vishalshetagar
vishalshetagar force-pushed the fix/23528-sycl-link-empty-images branch from cf7a486 to b64f560 Compare November 3, 2026 02:16

@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.

Thank you for working on this @vishalshetagar!

I don't see anything that looks like it should require review from the CFE team, so I'll go ahead and approve from that perspective. The test coverage looks good to me, but I'm not very familiar with the scenarios to be tested, so that might not mean much.

I don't understand why an exception is needed for native CPU, but I'm not sure how important that is either. Ideally, I would expect the SYCL RT symbol references to be omitted if the TU defines no kernels for native CPU too. But perhaps that is something we can come back to if it is found to be an issue.

@vishalshetagar

Copy link
Copy Markdown
Author

@tahonermann Thanks for the review and approval! NativeCPU can use an empty image payload while representing kernels through a table of host function pointers, so an empty payload alone doesn’t mean there are no kernels to register. The exception preserves registration for that case.

I agree that a NativeCPU TU with no kernels should ideally avoid the runtime references too. The current exception is conservative; we can follow up on distinguishing that case using the kernel entries.

This branch has not been deployed

No deployments
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.

Device pre-link with -fsycl-link of object files that define no kernels generates an object file with unneeded SYCL RT dependencies

5 participants