https://github.com/YuriPlyakhin updated https://github.com/llvm/llvm-project/pull/206870
>From 9d6a2b8e6bc7fdaada513ebb8e278f6c5746afad Mon Sep 17 00:00:00 2001 From: "Plyakhin, Yury" <[email protected]> Date: Wed, 1 Jul 2026 02:37:42 +0200 Subject: [PATCH 1/3] [clang][SYCL] Add -fsycl-device-code-split option Add the -fsycl-device-code-split= driver option to control how SYCL device code is split into separate device images. Supported values: - per_kernel: one device image per SYCL kernel - per_source: one device image per translation unit - off: no device code split The bare -fsycl-device-code-split flag is an alias for -fsycl-device-code-split=per_source, which is also the default. Co-Authored-By: Claude --- clang/docs/ReleaseNotes.md | 5 +++++ clang/include/clang/Options/Options.td | 9 +++++++++ clang/lib/Driver/ToolChains/Clang.cpp | 20 ++++++++++++++++++++ clang/test/Driver/sycl-offload-jit.cpp | 26 ++++++++++++++++++++++++++ 4 files changed, 60 insertions(+) diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md index cde904ebaac1e..dae7c6c7c8bc2 100644 --- a/clang/docs/ReleaseNotes.md +++ b/clang/docs/ReleaseNotes.md @@ -1136,6 +1136,11 @@ latest release, please see the [Clang Web Site](https://clang.llvm.org) or the - Fixed `-nolibsycl` being silently ignored on Linux: the SYCL runtime library was unconditionally added to the link line even when the flag was passed. +- Added the `-fsycl-device-code-split=` option to control SYCL device code + splitting. Supported values are `per_kernel` (one device image per kernel), + `per_source` (one device image per translation unit), and `off` (no split). + The bare `-fsycl-device-code-split` flag is an alias for + `-fsycl-device-code-split=per_source`, which is also the default. #### Improvements diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td index 9f1f4a5a682ee..6cca1857ea073 100644 --- a/clang/include/clang/Options/Options.td +++ b/clang/include/clang/Options/Options.td @@ -7572,6 +7572,15 @@ def fsycl_host_only : Flag<["-"], "fsycl-host-only">, def sycl_link : Flag<["--"], "sycl-link">, Flags<[HelpHidden]>, HelpText<"Perform link through clang-sycl-linker via the target " "offloading toolchain.">; +def fsycl_device_code_split_EQ : Joined<["-"], "fsycl-device-code-split=">, + HelpText<"Perform SYCL device code split: per_kernel (device code module is " + "created for each SYCL kernel) | per_source (device code module is " + "created for each source (translation unit)) | off (no device code " + "split). Default is 'per_source'.">, + Values<"per_kernel,per_source,off">; +def fsycl_device_code_split : Flag<["-"], "fsycl-device-code-split">, + Alias<fsycl_device_code_split_EQ>, AliasArgs<["per_source"]>, + HelpText<"Perform SYCL device code split in the 'per_source' mode.">; } // let Group = sycl_Group // OS-specific options diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index e4b62590ef811..4eaabdc9dc3b6 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -9876,6 +9876,26 @@ void LinkerWrapper::ConstructJob(Compilation &C, const JobAction &JA, LinkerArgs.emplace_back("--create-library"); } + // Translate the SYCL device code split mode into the corresponding + // clang-sycl-linker `--module-split-mode` value. + if (Kind == Action::OFK_SYCL) { + if (Arg *A = ToolChainArgs.getLastArg(OPT_fsycl_device_code_split_EQ)) { + StringRef Mode = A->getValue(); + StringRef SplitMode = + llvm::StringSwitch<StringRef>(Mode) + .Case("per_kernel", "kernel") + .Case("per_source", "source") + .Case("off", "none") + .Default(""); + if (SplitMode.empty()) + C.getDriver().Diag(clang::diag::err_drv_invalid_value) + << A->getSpelling() << Mode; + else + LinkerArgs.emplace_back( + Args.MakeArgString("--module-split-mode=" + SplitMode)); + } + } + // Forward all of these to the appropriate toolchain. for (StringRef Arg : CompilerArgs) CmdArgs.push_back(Args.MakeArgString( diff --git a/clang/test/Driver/sycl-offload-jit.cpp b/clang/test/Driver/sycl-offload-jit.cpp index fe329f79e03f4..bccdb4652addd 100644 --- a/clang/test/Driver/sycl-offload-jit.cpp +++ b/clang/test/Driver/sycl-offload-jit.cpp @@ -54,6 +54,32 @@ // CHECK-NO-SPIRVLINK-FLAGS-NOT: --device-linker=spirv64-unknown-unknown=--allow-partial-linkage // CHECK-NO-SPIRVLINK-FLAGS-NOT: --device-linker=spirv64-unknown-unknown=--create-library +/// Check -fsycl-device-code-split= is translated to the corresponding +/// clang-sycl-linker --module-split-mode= value. +// RUN: %clang -### --target=x86_64-unknown-linux-gnu -fsycl -fsycl-device-code-split=per_kernel %s 2>&1 \ +// RUN: | FileCheck -check-prefix=CHK-SPLIT-KERNEL %s +// CHK-SPLIT-KERNEL: clang-linker-wrapper{{.*}}"--device-linker=spirv64-unknown-unknown=--module-split-mode=kernel" +// RUN: %clang -### --target=x86_64-unknown-linux-gnu -fsycl -fsycl-device-code-split=per_source %s 2>&1 \ +// RUN: | FileCheck -check-prefix=CHK-SPLIT-SOURCE %s +// CHK-SPLIT-SOURCE: clang-linker-wrapper{{.*}}"--device-linker=spirv64-unknown-unknown=--module-split-mode=source" +// RUN: %clang -### --target=x86_64-unknown-linux-gnu -fsycl -fsycl-device-code-split=off %s 2>&1 \ +// RUN: | FileCheck -check-prefix=CHK-SPLIT-OFF %s +// CHK-SPLIT-OFF: clang-linker-wrapper{{.*}}"--device-linker=spirv64-unknown-unknown=--module-split-mode=none" + +/// Check the bare -fsycl-device-code-split flag aliases to 'per_source'. +// RUN: %clang -### --target=x86_64-unknown-linux-gnu -fsycl -fsycl-device-code-split %s 2>&1 \ +// RUN: | FileCheck -check-prefix=CHK-SPLIT-SOURCE %s + +/// Check that without -fsycl-device-code-split, no --module-split-mode= is passed. +// RUN: %clang -### --target=x86_64-unknown-linux-gnu -fsycl %s 2>&1 \ +// RUN: | FileCheck -check-prefix=CHK-NO-SPLIT %s +// CHK-NO-SPLIT-NOT: --module-split-mode= + +/// Check an invalid -fsycl-device-code-split= value is diagnosed. +// RUN: not %clang -### --target=x86_64-unknown-linux-gnu -fsycl -fsycl-device-code-split=bogus %s 2>&1 \ +// RUN: | FileCheck -check-prefix=CHK-SPLIT-INVALID %s +// CHK-SPLIT-INVALID: error: invalid value 'bogus' in '-fsycl-device-code-split=' + /// Check for option incompatibility with -fsycl // RUN: not %clang -### -fsycl -ffreestanding %s 2>&1 \ // RUN: | FileCheck -check-prefix=CHK-INCOMPATIBILITY %s -DINCOMPATOPT=-ffreestanding >From 46f5fe65fda97e524716d3ac2965da00bc9c9d57 Mon Sep 17 00:00:00 2001 From: "Plyakhin, Yury" <[email protected]> Date: Wed, 1 Jul 2026 04:23:10 +0200 Subject: [PATCH 2/3] format --- clang/lib/Driver/ToolChains/Clang.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 4eaabdc9dc3b6..0aedcef6f9930 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -9881,12 +9881,11 @@ void LinkerWrapper::ConstructJob(Compilation &C, const JobAction &JA, if (Kind == Action::OFK_SYCL) { if (Arg *A = ToolChainArgs.getLastArg(OPT_fsycl_device_code_split_EQ)) { StringRef Mode = A->getValue(); - StringRef SplitMode = - llvm::StringSwitch<StringRef>(Mode) - .Case("per_kernel", "kernel") - .Case("per_source", "source") - .Case("off", "none") - .Default(""); + StringRef SplitMode = llvm::StringSwitch<StringRef>(Mode) + .Case("per_kernel", "kernel") + .Case("per_source", "source") + .Case("off", "none") + .Default(""); if (SplitMode.empty()) C.getDriver().Diag(clang::diag::err_drv_invalid_value) << A->getSpelling() << Mode; >From 9ab27ffea0cf9523638a5a8bbb13bf245737d2f2 Mon Sep 17 00:00:00 2001 From: "Plyakhin, Yury" <[email protected]> Date: Wed, 1 Jul 2026 19:23:40 +0200 Subject: [PATCH 3/3] renaming per feedback --- clang/docs/ReleaseNotes.md | 12 ++++++---- clang/include/clang/Options/Options.td | 20 +++++++++------- clang/lib/Driver/ToolChains/Clang.cpp | 13 ++++++---- clang/test/Driver/sycl-offload-jit.cpp | 33 ++++++++++++++++---------- 4 files changed, 47 insertions(+), 31 deletions(-) diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md index 441805559fb5f..7cb9556716b91 100644 --- a/clang/docs/ReleaseNotes.md +++ b/clang/docs/ReleaseNotes.md @@ -1137,11 +1137,13 @@ latest release, please see the [Clang Web Site](https://clang.llvm.org) or the - Fixed `-nolibsycl` being silently ignored on Linux: the SYCL runtime library was unconditionally added to the link line even when the flag was passed. -- Added the `-fsycl-device-code-split=` option to control SYCL device code - splitting. Supported values are `per_kernel` (one device image per kernel), - `per_source` (one device image per translation unit), and `off` (no split). - The bare `-fsycl-device-code-split` flag is an alias for - `-fsycl-device-code-split=per_source`, which is also the default. +- Added the `-fsycl-device-image-split=` option to select the granularity at + which SYCL device code is grouped into device images. Supported values are + `per_kernel` (one device image per kernel), `per_translation_unit` / `per_tu` + (one device image per translation unit), and `per_link_unit` / `per_lu` (one + device image per linking unit). The bare `-fsycl-device-image-split` flag is + an alias for `-fsycl-device-image-split=per_translation_unit`, which is also + the default. - Clang now is capable of diagnosing reference kernel parameters which are not allowed by SYCL 2020 spec. diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td index 6cca1857ea073..723159b216bd7 100644 --- a/clang/include/clang/Options/Options.td +++ b/clang/include/clang/Options/Options.td @@ -7572,15 +7572,17 @@ def fsycl_host_only : Flag<["-"], "fsycl-host-only">, def sycl_link : Flag<["--"], "sycl-link">, Flags<[HelpHidden]>, HelpText<"Perform link through clang-sycl-linker via the target " "offloading toolchain.">; -def fsycl_device_code_split_EQ : Joined<["-"], "fsycl-device-code-split=">, - HelpText<"Perform SYCL device code split: per_kernel (device code module is " - "created for each SYCL kernel) | per_source (device code module is " - "created for each source (translation unit)) | off (no device code " - "split). Default is 'per_source'.">, - Values<"per_kernel,per_source,off">; -def fsycl_device_code_split : Flag<["-"], "fsycl-device-code-split">, - Alias<fsycl_device_code_split_EQ>, AliasArgs<["per_source"]>, - HelpText<"Perform SYCL device code split in the 'per_source' mode.">; +def fsycl_device_image_split_EQ : Joined<["-"], "fsycl-device-image-split=">, + HelpText<"Select the granularity at which SYCL device code is grouped into " + "device images: per_kernel (one device image per kernel) | " + "per_translation_unit / per_tu (one device image per translation " + "unit) | per_link_unit / per_lu (one device image per linking unit)." + "Default is 'per_translation_unit'.">, + Values<"per_kernel,per_translation_unit,per_tu,per_link_unit,per_lu">; +def fsycl_device_image_split : Flag<["-"], "fsycl-device-image-split">, + Alias<fsycl_device_image_split_EQ>, AliasArgs<["per_translation_unit"]>, + HelpText<"Group SYCL device code into device images at 'per_translation_unit' " + "granularity.">; } // let Group = sycl_Group // OS-specific options diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index ab42f3eeebe80..9d920a263f65d 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -9877,15 +9877,18 @@ void LinkerWrapper::ConstructJob(Compilation &C, const JobAction &JA, LinkerArgs.emplace_back("--create-library"); } - // Translate the SYCL device code split mode into the corresponding - // clang-sycl-linker `--module-split-mode` value. + // Translate the SYCL device image split granularity into the + // corresponding clang-sycl-linker `--module-split-mode` value. if (Kind == Action::OFK_SYCL) { - if (Arg *A = ToolChainArgs.getLastArg(OPT_fsycl_device_code_split_EQ)) { + if (Arg *A = + ToolChainArgs.getLastArg(OPT_fsycl_device_image_split_EQ)) { StringRef Mode = A->getValue(); StringRef SplitMode = llvm::StringSwitch<StringRef>(Mode) .Case("per_kernel", "kernel") - .Case("per_source", "source") - .Case("off", "none") + .Case("per_translation_unit", "source") + .Case("per_tu", "source") + .Case("per_link_unit", "none") + .Case("per_lu", "none") .Default(""); if (SplitMode.empty()) C.getDriver().Diag(clang::diag::err_drv_invalid_value) diff --git a/clang/test/Driver/sycl-offload-jit.cpp b/clang/test/Driver/sycl-offload-jit.cpp index bccdb4652addd..f156858ce81fe 100644 --- a/clang/test/Driver/sycl-offload-jit.cpp +++ b/clang/test/Driver/sycl-offload-jit.cpp @@ -54,31 +54,40 @@ // CHECK-NO-SPIRVLINK-FLAGS-NOT: --device-linker=spirv64-unknown-unknown=--allow-partial-linkage // CHECK-NO-SPIRVLINK-FLAGS-NOT: --device-linker=spirv64-unknown-unknown=--create-library -/// Check -fsycl-device-code-split= is translated to the corresponding +/// Check -fsycl-device-image-split= is translated to the corresponding /// clang-sycl-linker --module-split-mode= value. -// RUN: %clang -### --target=x86_64-unknown-linux-gnu -fsycl -fsycl-device-code-split=per_kernel %s 2>&1 \ +// RUN: %clang -### --target=x86_64-unknown-linux-gnu -fsycl -fsycl-device-image-split=per_kernel %s 2>&1 \ // RUN: | FileCheck -check-prefix=CHK-SPLIT-KERNEL %s // CHK-SPLIT-KERNEL: clang-linker-wrapper{{.*}}"--device-linker=spirv64-unknown-unknown=--module-split-mode=kernel" -// RUN: %clang -### --target=x86_64-unknown-linux-gnu -fsycl -fsycl-device-code-split=per_source %s 2>&1 \ +// RUN: %clang -### --target=x86_64-unknown-linux-gnu -fsycl -fsycl-device-image-split=per_translation_unit %s 2>&1 \ +// RUN: | FileCheck -check-prefix=CHK-SPLIT-SOURCE %s +// RUN: %clang -### --target=x86_64-unknown-linux-gnu -fsycl -fsycl-device-image-split=per_tu %s 2>&1 \ // RUN: | FileCheck -check-prefix=CHK-SPLIT-SOURCE %s // CHK-SPLIT-SOURCE: clang-linker-wrapper{{.*}}"--device-linker=spirv64-unknown-unknown=--module-split-mode=source" -// RUN: %clang -### --target=x86_64-unknown-linux-gnu -fsycl -fsycl-device-code-split=off %s 2>&1 \ -// RUN: | FileCheck -check-prefix=CHK-SPLIT-OFF %s -// CHK-SPLIT-OFF: clang-linker-wrapper{{.*}}"--device-linker=spirv64-unknown-unknown=--module-split-mode=none" +// RUN: %clang -### --target=x86_64-unknown-linux-gnu -fsycl -fsycl-device-image-split=per_link_unit %s 2>&1 \ +// RUN: | FileCheck -check-prefix=CHK-SPLIT-NONE %s +// RUN: %clang -### --target=x86_64-unknown-linux-gnu -fsycl -fsycl-device-image-split=per_lu %s 2>&1 \ +// RUN: | FileCheck -check-prefix=CHK-SPLIT-NONE %s +// CHK-SPLIT-NONE: clang-linker-wrapper{{.*}}"--device-linker=spirv64-unknown-unknown=--module-split-mode=none" -/// Check the bare -fsycl-device-code-split flag aliases to 'per_source'. -// RUN: %clang -### --target=x86_64-unknown-linux-gnu -fsycl -fsycl-device-code-split %s 2>&1 \ +/// Check the bare -fsycl-device-image-split flag aliases to 'per_translation_unit'. +// RUN: %clang -### --target=x86_64-unknown-linux-gnu -fsycl -fsycl-device-image-split %s 2>&1 \ // RUN: | FileCheck -check-prefix=CHK-SPLIT-SOURCE %s -/// Check that without -fsycl-device-code-split, no --module-split-mode= is passed. +/// Check that without -fsycl-device-image-split, no --module-split-mode= is passed. // RUN: %clang -### --target=x86_64-unknown-linux-gnu -fsycl %s 2>&1 \ // RUN: | FileCheck -check-prefix=CHK-NO-SPLIT %s // CHK-NO-SPLIT-NOT: --module-split-mode= -/// Check an invalid -fsycl-device-code-split= value is diagnosed. -// RUN: not %clang -### --target=x86_64-unknown-linux-gnu -fsycl -fsycl-device-code-split=bogus %s 2>&1 \ +/// Check an invalid -fsycl-device-image-split= value is diagnosed. +// RUN: not %clang -### --target=x86_64-unknown-linux-gnu -fsycl -fsycl-device-image-split=bogus %s 2>&1 \ // RUN: | FileCheck -check-prefix=CHK-SPLIT-INVALID %s -// CHK-SPLIT-INVALID: error: invalid value 'bogus' in '-fsycl-device-code-split=' +// CHK-SPLIT-INVALID: error: invalid value 'bogus' in '-fsycl-device-image-split=' + +/// Check -fsycl-device-image-split is unused when not linking (e.g. -c). +// RUN: %clang -### -c --target=x86_64-unknown-linux-gnu -fsycl -fsycl-device-image-split=per_kernel %s 2>&1 \ +// RUN: | FileCheck -check-prefix=CHK-SPLIT-UNUSED %s +// CHK-SPLIT-UNUSED: warning: argument unused during compilation: '-fsycl-device-image-split=per_kernel' /// Check for option incompatibility with -fsycl // RUN: not %clang -### -fsycl -ffreestanding %s 2>&1 \ _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
