Skip to content

[SYCL][NewOffloadModel] Support -fno-sycl-rdc at compile step (-c) - #22833

Open
srividya-sundaram wants to merge 41 commits into
intel:syclfrom
srividya-sundaram:sycl-no-rdc-compile-step
Open

[SYCL][NewOffloadModel] Support -fno-sycl-rdc at compile step (-c)#22833
srividya-sundaram wants to merge 41 commits into
intel:syclfrom
srividya-sundaram:sycl-no-rdc-compile-step

Conversation

@srividya-sundaram

@srividya-sundaram srividya-sundaram commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Summary

This PR adds support for -fno-sycl-rdc -c in the new offload model by finalizing each TU's device code at compile time via clang-linker-wrapper --sycl-device-link --no-sycl-rdc, then embedding the result into the host object via a new -fsycl-include-target-binary CC1 option. The approach mirrors how CUDA/HIP handle no-RDC with -fcuda-include-gpubinary.

Depends on #22832.

maksimsab and others added 6 commits July 30, 2026 13:44
Fix --no-offload-old-driver typo to --no-offload-new-driver in the
old offload model usage example. Add a note that compile-step support
for -fno-sycl-rdc (matching the old model's -c usage pattern) will
be implemented in a follow-up patch via clang-linker-wrapper
--sycl-device-link --no-sycl-rdc per translation unit.
Adds support for specifying -fno-sycl-rdc at the compile step in the new
offload model, matching the old offload model's usage pattern. Previously,
-fno-sycl-rdc was only meaningful at the link step in the new model.

Design (mirrors CUDA/HIP -fno-gpu-rdc per-TU finalize model):
- BuildOffloadingActions: when -fno-sycl-rdc is passed at compile time,
  insert a per-TU LinkerWrapperJobAction (OffloadPackager +
  clang-linker-wrapper --sycl-device-link --no-sycl-rdc) to finalize the
  TU's device code immediately, producing a self-contained device image.
- Clang::ConstructJob: route the finalized image to the new
  -fsycl-include-target-binary CC1 option instead of -fembed-offload-object,
  so the host CodeGen embeds and registers the image at compile time rather
  than deferring it to link time.
- CodeGenModule::Release: when -fsycl-include-target-binary is set on the
  host cc1, read the device image file and call wrapSYCLBinaries to embed
  the binary and emit __sycl_register_lib/__sycl_unregister_lib ctors into
  the host module. The final clang-linker-wrapper invocation then finds no
  SYCL device input and performs a plain host link.
- Downstream uses clang-linker-wrapper --sycl-device-link instead of the
  upstream's clang-sycl-linker, as all Intel SYCL pipeline logic resides in
  clang-linker-wrapper.

New files/options:
- -fsycl-include-target-binary <file>: new CC1 option (analog of
  -fcuda-include-gpubinary) marshalled into CodeGenOpts.SYCLTargetBinaryFileName
- clang/test/Driver/sycl-no-rdc-compile-step.cpp: driver tests verifying
  per-TU pipeline shape, RDC default regression, and link-step regression.

Implements compile-step support tracked in CMPLRLLVM-51875.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

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.

Pull request overview

Adds compile-step (-c) support for -fno-sycl-rdc in the new SYCL offload model by finalizing each TU’s device image during compilation (via a per-TU clang-linker-wrapper --sycl-device-link --no-sycl-rdc) and embedding/registering the finalized image into the host object using a new cc1 option.

Changes:

  • Teach the driver to insert a per-TU LinkerWrapperJobAction for SYCL NoRDC compilation and route its output to the host compile.
  • Introduce -fsycl-include-target-binary and plumb it through driver → CodeGen to embed/register the finalized SYCL image at compile time.
  • Add/update driver + e2e tests and update design documentation around NoRDC usage patterns.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
sycl/test-e2e/AOT/early_aot.cpp Adjust RUN lines for old/new model flag placement; adds explanatory note.
sycl/doc/design/OffloadDesign.md Document NoRDC behavior and usage scenarios for old/new offload models.
sycl/doc/design/NonRelocatableDeviceCode.md Clarify document scope (old offload model NoRDC design).
clang/test/Driver/sycl-no-rdc-new-driver.cpp New driver test for -fno-sycl-rdc propagation and pipeline shape.
clang/test/Driver/sycl-no-rdc-compile-step.cpp New driver test covering compile-step NoRDC finalization + cc1 plumbing.
clang/lib/Driver/ToolChains/Clang.cpp Pass finalized SYCL image to host cc1; propagate NoRDC to linker wrapper and add per-TU device-link mode logic.
clang/lib/Driver/Driver.cpp Insert per-TU linker-wrapper finalizer action for SYCL NoRDC during compilation.
clang/lib/CodeGen/CodeGenModule.cpp Read finalized SYCL image and call wrapSYCLBinaries to embed/register at compile time.
clang/include/clang/Options/Options.td Add new -fsycl-include-target-binary option (marshalled to CodeGenOpts).
clang/include/clang/Basic/CodeGenOptions.h Add SYCLTargetBinaryFileName storage for the new cc1 option.

Comment thread clang/lib/CodeGen/CodeGenModule.cpp Outdated
Comment thread clang/lib/Driver/ToolChains/Clang.cpp Outdated
Comment thread clang/lib/CodeGen/CodeGenModule.cpp Outdated
Comment thread sycl/doc/design/OffloadDesign.md Outdated
Comment thread sycl/test-e2e/AOT/early_aot.cpp Outdated

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.

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated no new comments.

@srividya-sundaram

Copy link
Copy Markdown
Contributor Author

SYCL Pre commit failure is unrelated to the changes in this PR.

@srividya-sundaram

Copy link
Copy Markdown
Contributor Author

Please note that this PR is a follow-up to #22832 and currently includes its changes as a base. Once #22832 lands, this branch will be rebased on top of it so the diff only shows the compile-step additions.

@srividya-sundaram
srividya-sundaram marked this pull request as ready for review July 31, 2026 18:59
@srividya-sundaram
srividya-sundaram requested review from a team as code owners July 31, 2026 18:59
Comment thread clang/include/clang/Options/Options.td Outdated
Comment thread clang/lib/CodeGen/CodeGenModule.cpp Outdated
Comment thread clang/lib/CodeGen/CodeGenModule.cpp Outdated
Comment thread clang/lib/Driver/ToolChains/Clang.cpp Outdated
Comment thread clang/lib/Driver/ToolChains/Clang.cpp Outdated
Comment thread clang/test/Driver/sycl-no-rdc-compile-step.cpp Outdated
Comment thread sycl/doc/design/OffloadDesign.md Outdated
Comment thread sycl/doc/design/OffloadDesign.md
Comment thread sycl/test-e2e/AOT/early_aot.cpp Outdated
Comment thread sycl/test-e2e/AOT/early_aot.cpp Outdated
sarnex pushed a commit that referenced this pull request Jul 31, 2026
…Offload Model (#22832)

## Summary

This patch adds `-fno-sycl-rdc` support to the new SYCL offload model in
the Clang driver. It is based on the work by @maksimsab in #21973, with
review fixes applied.

### What this patch does

By default (`-fsycl-rdc`), all device code across translation units is
linked together into one module at link time before post-link
processing. With `-fno-sycl-rdc`, each object file's device code is
processed independently — skipping the `llvm-link` step — which can
significantly reduce peak memory and compile time.

**Changes:**
- `clang/lib/Driver/ToolChains/Clang.cpp`: In
`LinkerWrapper::ConstructJob`, propagate `--no-sycl-rdc` to
`clang-linker-wrapper` when `-fno-sycl-rdc` is passed at link time.
- `sycl/doc/design/OffloadDesign.md`: Document NoRDC mode for the new
offload model.
- `sycl/doc/design/NonRelocatableDeviceCode.md`: Add a note clarifying
that document covers the old offload model only.
- `sycl/test-e2e/AOT/early_aot.cpp`: Un-XFAIL the test for the new
offload model; adjust RUN lines to pass `-fno-sycl-rdc` at the correct
step per model.
- `clang/test/Driver/sycl-no-rdc-new-driver.cpp`: New driver test
verifying `--no-sycl-rdc` is propagated to `clang-linker-wrapper`
correctly.

### Key behavioral difference from the old offload model

| Model | Where to pass `-fno-sycl-rdc` |
|---|---|
| Old (`--no-offload-new-driver`) | At each **compile** step (`-c`) |
| New (`--offload-new-driver`) | At the **link** step |

This inversion exists because in the new model all SYCL offload
processing (post-link, AOT, wrapping) lives in `clang-linker-wrapper` at
link time.

### Follow-up work

Supporting `-fno-sycl-rdc -c` in the new model (matching the old model's
compile-step ergonomics) will be addressed in a follow-up patch. The
plan is to invoke `clang-linker-wrapper --sycl-device-link
--no-sycl-rdc` per translation unit at compile time, embedding the
finalized device image directly into the host object.

Supporting -fno-sycl-rdc -c in the new model (matching old model
compile-step ergonomics) is addressed in #22833.

Fixes: CMPLRLLVM-51875

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Sabianin, Maksim <maksim.sabianin@intel.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Comment thread clang/test/Driver/sycl-no-rdc-compile-step.cpp Outdated
srividya-sundaram and others added 5 commits July 31, 2026 16:36
Move embedSYCLNoRDCBinary out of CodeGenModule::Release() into a free
function in CGSYCLRuntime.cpp to keep SYCL-specific logic out of common
code. CodeGenModule::Release() retains a single call site.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Comment thread clang/lib/CodeGen/CGSYCLRuntime.cpp Outdated

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

SYCL RT changes LGTM

Comment thread clang/lib/CodeGen/CodeGenModule.cpp Outdated

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

I'm not yet convinced that the diagnostic workaround is needed. Please see the inline comment.

Comment thread clang/lib/CodeGen/CGSYCLRuntime.cpp Outdated
Comment thread clang/lib/CodeGen/CodeGenModule.cpp Outdated
Comment thread sycl/doc/design/OffloadDesign.md Outdated
Comment thread sycl/doc/design/OffloadDesign.md Outdated
…fix embedSYCLNoRDCBinary ordering, update OffloadDesign.md wording
…rupted module after no-RDC bitcode link failure

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.

Pull request overview

Copilot reviewed 22 out of 22 changed files in this pull request and generated 1 comment.

Suppressed comments (1)

sycl/test-e2e/AOT/early_aot.cpp:8

  • The "Old offload model" RUN lines don’t explicitly force the old model (e.g. via --no-offload-new-driver). In configurations where the new offload model is enabled by default, these commands would exercise the new model instead, reducing coverage and making the section header misleading.
// Old offload model: -fno-sycl-rdc at compile step only.
// RUN: %clangxx -fsycl -fsycl-targets=spir64_gen -Xsycl-target-backend=spir64_gen %gpu_aot_target_opts -fno-sycl-rdc -c -DADD_CPP %s -o %t_add.o
// RUN: %clangxx -fsycl -fsycl-targets=spir64_gen -Xsycl-target-backend=spir64_gen %gpu_aot_target_opts -fno-sycl-rdc -c -DSUB_CPP %s -o %t_sub.o
// RUN: %clangxx -fsycl -DMAIN_CPP %s %t_add.o %t_sub.o -o %t.out

Comment thread clang/lib/Driver/ToolChains/Clang.cpp
srividya-sundaram and others added 2 commits August 20, 2026 11:26

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.

Pull request overview

Copilot reviewed 21 out of 21 changed files in this pull request and generated 3 comments.

Suppressed comments (3)

clang/include/clang/Options/Options.td:1931

  • The PR description specifies a new -fsycl-include-target-binary CC1 option, but this change defines only -foffload-include-binary (and aliases the CUDA spelling to it). As written, the promised SYCL option is not available; either implement the described spelling or update the PR contract and all documentation/tests consistently.
def foffload_include_binary : Separate<["-"], "foffload-include-binary">,
  Visibility<[CC1Option]>,
  HelpText<"Incorporate offloading device-side binary into host object file.">,
  MarshallingInfoString<CodeGenOpts<"OffloadBinaryToEmbedFile">>;

clang/lib/Driver/Driver.cpp:8390

  • The !isa<LinkJobAction> condition also selects preprocessing and syntax-only host actions, even though this finalizer is intended for compile steps that produce a host object/IR. For -fsycl -fno-sycl-rdc -E without -o (the special preprocessing branch above only handles an explicit output), this adds an image linker-wrapper to a preprocessing-only pipeline whose device actions have no linkable image. Restrict this branch to host actions with a real compilable output and leave preprocessing/syntax-only handling on their existing paths.
  } else if (C.isOffloadingHostKind(Action::OFK_SYCL) &&
             tools::SYCL::shouldDoPerObjectFileLinking(C) &&
             !isa<LinkJobAction>(HostAction)) {

clang/lib/Driver/ToolChains/Clang.cpp:12165

  • getFinalPhase describes the whole driver invocation, not this nested per-TU action. For a compile-and-link command such as clang++ --offload-new-driver -fsycl -fno-sycl-rdc a.cpp -o a.out, the action graph still creates this OFK_SYCL finalizer (as the new pipeline check demonstrates), but the final phase is Link, so both flags are suppressed. The wrapper then takes the normal runWrapperAndCompile path and returns an object, while the host cc1 is given -foffload-include-binary and tries to parse that file as wrapper bitcode. Forward the flags based on the per-TU action rather than the global final phase, and update the link-step test to cover this distinction.
      if (C.getDriver().getFinalPhase(C.getArgs()) != phases::Link &&
          JA.isDeviceOffloading(Action::OFK_SYCL)) {

Comment thread clang/lib/CodeGen/ModuleLinker.cpp Outdated
Comment thread clang/lib/Driver/ToolChains/Clang.cpp
Comment thread clang/tools/clang-linker-wrapper/ClangLinkerWrapper.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.

Thank you for working with me through the link module control flow changes this week @srividya-sundaram! This looks much cleaner to me now.

I added a couple of comments to note minor fixes.

Just something I want to note to be aware of. With these changes, the no-rdc SYCL device image (if specified) will be linked in everywhere loadLinkModules() is called (which currently includes CodeGenAction::CreateASTConsumer(), CodeGenAction::loadModule(), and CIRGenAction::BeginSourceFileAction()). I think that is a good thing, but it isn't how the modules returned from getBitcodeModuleList() (a list populated by, I think, -mlink-bitcode-file) are handled, so there might be some subtle reason to do things differently. I don't recommend making a change unless/until there is a demonstrable reason to do so.

It looks like there might be some interactions with -flto=thin that might warrant some additional tests. In CodeGenAction::loadModule(), if CI.getCodeGenOpts().ThinLTOIndexFile.empty() is false, the loadLinkModules() call won't be reached. I don't know if that is a good thing or otherwise.

Comment thread clang/lib/CodeGen/ModuleLinker.cpp
Comment thread clang/lib/CodeGen/ModuleLinker.cpp
Comment thread clang/lib/CodeGen/ModuleLinker.cpp Outdated
@srividya-sundaram

Copy link
Copy Markdown
Contributor Author

Thank you for the helpful offline discussions, @tahonermann!

Just something I want to note to be aware of. With these changes, the no-rdc SYCL device image (if specified) will be linked in everywhere loadLinkModules() is called (which currently includes CodeGenAction::CreateASTConsumer(), CodeGenAction::loadModule(), and CIRGenAction::BeginSourceFileAction()). I think that is a good thing, but it isn't how the modules returned from getBitcodeModuleList() (a list populated by, I think, -mlink-bitcode-file) are handled, so there might be some subtle reason to do things differently. I don't recommend making a change unless/until there is a demonstrable reason to do so.

It appears that loadModule is called only when the input is IR
In the normal SYCL no-RDC compile flow the input is C++ , so loadModule never gets called.
So this is probably not relevant/an issue with our SYCL no-rdc-flow

@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, @srividya-sundaram, the updates look great!

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

Labels

new-offload-model Enables testing with NewOffloadModel.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants