Skip to content

[NewOffloadModel] Refactor device compiler and linker option parsing in ClangLinkerWrapper#21055

Merged
sarnex merged 2 commits intointel:syclfrom
YixingZhang007:resolve-kerne-program-test
Mar 3, 2026
Merged

[NewOffloadModel] Refactor device compiler and linker option parsing in ClangLinkerWrapper#21055
sarnex merged 2 commits intointel:syclfrom
YixingZhang007:resolve-kerne-program-test

Conversation

@YixingZhang007
Copy link
Copy Markdown
Contributor

@YixingZhang007 YixingZhang007 commented Jan 14, 2026

This patch refactors the parsing of device compiler and linker options in clang-linker-wrapper.

The specific changes are listed below:

  1. Merged appendSYCLDeviceOptionsAtLinkTime() directly into getLinkerArgs() in ClangLinkerWrapper.cpp, so the ArgList returned by getLinkerArgs() includes both linker_arg_EQ and compiler_arg_EQ options, which are the filtered options of OPT_device_linker_args_EQ and OPT_device_compiler_args_EQ.
  2. OPT_compiler_arg_EQ and OPT_linker_arg_EQ are now storing both the options passed to the backend compiler and the options passed to the Clang command for linking.

With this patch, the SYCL E2E test KernelAndProgram/kernel-bundle-merge-options-env.cpp pass with the new offloading mode.

@YixingZhang007
Copy link
Copy Markdown
Contributor Author

YixingZhang007 commented Feb 10, 2026

I haven’t seen any issues with removing the -linker-arg= and -compiler-arg= options passed to clang-linker-wrapper, and I don’t see any tests that rely on them either. However, please let me know if I’ve missed anything or if you have any other suggestions. Thank you!

Comment thread clang/test/Driver/linker-wrapper.c Outdated
Comment thread clang/tools/clang-linker-wrapper/LinkerWrapperOpts.td
Comment thread clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp Outdated
@YuriPlyakhin
Copy link
Copy Markdown
Contributor

I haven’t seen any issues with removing the -linker-arg= and -compiler-arg= options passed to clang-linker-wrapper, and I don’t see any tests that rely on them either. However, please let me know if I’ve missed anything or if you have any other suggestions. Thank you!

I guess it is because our variant of new offloading model is not using them, but most likely community variant of the code (for other programming models at least) will likely fail, after this change.

@YixingZhang007
Copy link
Copy Markdown
Contributor Author

I don’t think the current CI failure is related to the change in this PR, as our change only affects tests with the new offloading model.

continue;
Arg = Arg.substr(ColonPos + 1);
}
size_t EqPos = Arg.find('=');
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 you add a comment giving an example value of Arg and then explain how we process it? It seems we are looking both for a : and for =. I want to understand the processing we are doing here a bit better

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.

For sure! I’ve added the following comment before the lambda function to explain the --device-compiler and --device-linker arguments passed to the clang-linker-wrapper.

  // The device_linker_args and device_compiler_args options accept values 
  // in the form [<kind>:][<triple>=]<value>. 
  // An example of passing such an option to clang-linker-wrapper is:
  // --device-compiler=spir64_gen-unknown-unknown=opt_val.

// Filter the SYCL device compiler and linker options by target triple and
// offload kind.
const StringRef TripleStr = DAL.getLastArgValue(OPT_triple_EQ);
auto processDeviceArgs = [&](unsigned DeviceOptID, unsigned OptID) {
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 give these arguments some more descriptive names?

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.

Thanks for the suggestion! I have changed it to be

  auto ProcessDeviceArgs =
      [&](unsigned DeviceArgsOptionID, unsigned ForwardedOptionID) {

CompileLinkOptionsOrErr->first,
CompileLinkOptionsOrErr->second);
StringRef DeviceCompilerArgs =
LinkerArgs.getLastArgValue(OPT_compiler_arg_EQ);
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 this part combining the flags from the image with the command line flags from the tool? If so please add a comment

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.

Yes, this is the part for combing the flags from the image with argument passed via option -device-compiler= and -device-linker= to clang-linker-warpper? I have added a comment in the code. Thank you! ;)

// Filter the SYCL device compiler and linker options by target triple and
// offload kind.
const StringRef TripleStr = DAL.getLastArgValue(OPT_triple_EQ);
auto processDeviceArgs = [&](unsigned DeviceOptID, unsigned OptID) {
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.

nit: usually we start lambda names with a capital letter

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.

Thank you for pointing this out! I have made the change.

// offload kind.
const StringRef TripleStr = DAL.getLastArgValue(OPT_triple_EQ);
auto processDeviceArgs = [&](unsigned DeviceOptID, unsigned OptID) {
for (StringRef Arg : Args.getAllArgValues(DeviceOptID)) {
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.

nit: Rename variable Arg to DeviceArgValue or something similar as this is not an Arg*, but the values attached to the --device-compiler or --device-linker

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.

Thank you for the suggestion! I have rename the variable to DeviceArgValue.

for (StringRef Arg : Args.getAllArgValues(DeviceOptID)) {
size_t ColonPos = Arg.find(':');
if (ColonPos != StringRef::npos) {
StringRef Kind = Arg.substr(0, ColonPos);
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.

nit: For better readability consider using drop_front and take_front functions instead of substr functions as appropriate.

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.

I also agree that using drop_front and take_front would be better. I have made the change.

@YixingZhang007
Copy link
Copy Markdown
Contributor Author

YixingZhang007 commented Feb 25, 2026

I don’t think the current CI failure is related to the changes in this patch. The failures seems to be caused by the CI machine itself, and I am seeing similar issues with other PRs as well. Thank you!

Comment on lines +2091 to +2092
auto ProcessDeviceArgs = [&](unsigned DeviceArgsOptionID,
unsigned ForwardedOptionID) {
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
auto ProcessDeviceArgs = [&](unsigned DeviceArgsOptionID,
unsigned ForwardedOptionID) {
auto ProcessDeviceArgs = [&](llvm::opt::OptSpecifier DeviceArgsOptionID,
llvm::opt::OptSpecifier ForwardedOptionID) {

nit - while technically it is an unsigned, using OptSpecifier provides some clarity.

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.

Thank you for the suggestion! I have made the changes :)

Copy link
Copy Markdown
Contributor

@sarnex sarnex left a comment

Choose a reason for hiding this comment

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

looks good just some minor questions

llvm::opt::OptSpecifier ForwardedOptionID) {
for (StringRef DeviceArgValue : Args.getAllArgValues(DeviceArgsOptionID)) {
size_t ColonPos = DeviceArgValue.find(':');
if (ColonPos != StringRef::npos) {
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.

Should we instead change all the != npos checks to be if ( == npos) continue? Or are there valid cases where some of those might not be present?

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.

Thanks for the suggestion! Yes, there could be cases where the argument contains only <kind>:<value>, only <triple>=<value>, or even just <value> (both <kind> and <triple> are optional). If we use continue, it would skip cases where either <kind> or <triple> is not available.

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.

got it, thanks. my third question seems related to this so ill ask a follow-up there

Comment thread clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp Outdated
// If this isn't a recognized triple then it's an `arg=value` option.
if (TT.getArch() != Triple::ArchType::UnknownArch) {
if (TargetTriple != TripleStr)
continue;
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.

In what cases will the driver generate arg=value instead of including the triple?

Copy link
Copy Markdown
Contributor Author

@YixingZhang007 YixingZhang007 Feb 26, 2026

Choose a reason for hiding this comment

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

There is an example found at

// RUN: clang-linker-wrapper --dry-run --host-triple=x86_64-unknown-linux-gnu \
// RUN: --linker-path=/usr/bin/ld --device-linker=foo=bar --device-linker=a \
// RUN: --device-linker=nvptx64-nvidia-cuda=b --device-compiler=foo\
// RUN: %t.o -o a.out 2>&1 | FileCheck %s --check-prefix=LINKER-ARGS

In this example, foo=bar is passed as an argument to -device-linker, and foo is not an triple. I am not sure when this case would happen, and this is the only test found that tests this behavior. This line is added to allow this test case. Also, before this patch, we were also supporting the case of arg=value; removing it may make our code less aligned with the community code. Please feel free to let me know if there is any suggestion on this :) Thank you!

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.

@mdtoguchi Do you think we need to support the above argument style? Or should we just change the test

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.

The argument style can present itself externally - but albeit only with using the internal undocumented -Zlinker-input option. Weird case, but as community supports it we should as well.

Copy link
Copy Markdown
Contributor

@sarnex sarnex left a comment

Choose a reason for hiding this comment

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

thanks!

@YixingZhang007
Copy link
Copy Markdown
Contributor Author

@intel/llvm-gatekeepers I don't think the CI failure is related to the change in this patch. Could you please help merge the PR? Thank you!

@sarnex
Copy link
Copy Markdown
Contributor

sarnex commented Mar 2, 2026

Still needs a review from @intel/dpcpp-clang-driver-reviewers

@sarnex
Copy link
Copy Markdown
Contributor

sarnex commented Mar 2, 2026

@YuriPlyakhin I think you need to remove your 'Requested changes' before we can merge (unless I should force merge)

@YixingZhang007
Copy link
Copy Markdown
Contributor Author

@YuriPlyakhin I think you need to remove your 'Requested changes' before we can merge (unless I should force merge)

@intel/llvm-gatekeepers I have removed the Requested changes as it has been addressed, and I think we should be able to merge this PR now. Thank you!

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.

6 participants