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

Reply via email to