[clang] [llvm] [clang-sycl-linker] Add per-translation-unit device code split mode (PR #196435)
maksimsab wrote: I don't have a right to give LGTM here but the PR looks good to me. Note/idea: Alexey did mention in the past that `-dry-run` mode is designated for printing external commands which is not the case for `sycl-module-split` and `LLVM Backend`. Clang Driver has a capability for printing pipeline separately from printing external commands. We could reuse such approach/idea. Not in this PR but in the future. https://github.com/llvm/llvm-project/pull/196435 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [clang-sycl-linker] Add per-translation-unit device code split mode (PR #196435)
@@ -468,84 +468,118 @@ static Error runAOTCompile(StringRef InputFile,
StringRef OutputFile,
return createStringError(inconvertibleErrorCode(), "Unsupported arch");
}
+static constexpr char AttrSYCLModuleId[] = "sycl-module-id";
+
/// SYCL device code module split mode.
enum class IRSplitMode {
+ SPLIT_PER_TU, // one module per translation unit
SPLIT_PER_KERNEL, // one module per kernel
SPLIT_NONE// no splitting
};
-/// Parses the value of \p -module-split-mode.
+/// Parses the value of \p --module-split-mode.
static std::optional convertStringToSplitMode(StringRef S) {
return StringSwitch>(S)
+ .Case("source", IRSplitMode::SPLIT_PER_TU)
.Case("kernel", IRSplitMode::SPLIT_PER_KERNEL)
.Case("none", IRSplitMode::SPLIT_NONE)
.Default(std::nullopt);
}
+static StringRef splitModeToString(IRSplitMode Mode) {
+ switch (Mode) {
+ case IRSplitMode::SPLIT_PER_TU:
+return "source";
+ case IRSplitMode::SPLIT_PER_KERNEL:
+return "kernel";
+ case IRSplitMode::SPLIT_NONE:
+return "none";
+ }
+ llvm_unreachable("bad split mode");
+}
+
/// Result of splitting a device module: the bitcode file path and the
/// serialized symbol table for each device image.
struct SplitModule {
SmallString<256> ModuleFilePath;
SmallString<0> Symbols;
};
-static bool isEntryPoint(const Function &F) {
- return !F.isDeclaration() && F.hasKernelCallingConv();
+static bool isEntryPoint(const Function &F, bool EmitOnlyKernelsAsEntryPoints)
{
+ if (F.isDeclaration())
+return false;
+ if (F.hasKernelCallingConv())
+return true;
+ if (EmitOnlyKernelsAsEntryPoints)
+return false;
+ // sycl_external functions carry the "sycl-module-id" attribute.
+ // This branch is not reachable while EmitOnlyKernelsAsEntryPoints is
+ // hardcoded to true (see TODO in runSYCLLink).
+ return F.hasFnAttribute(AttrSYCLModuleId);
}
-/// Collect kernel names from \p M and serialize them into a symbol table.
-static SmallString<0> collectSymbols(const Module &M) {
- SmallVector KernelNames;
+/// Collect entry point names from \p M and serialize them into a symbol table.
+static SmallString<0> collectEntryPoints(const Module &M,
+ bool EmitOnlyKernelsAsEntryPoints) {
+ SmallVector Names;
for (const Function &F : M)
-if (isEntryPoint(F))
- KernelNames.push_back(F.getName());
+if (isEntryPoint(F, EmitOnlyKernelsAsEntryPoints))
+ Names.push_back(F.getName());
SmallString<0> SymbolData;
- llvm::offloading::sycl::writeSymbolTable(KernelNames, SymbolData);
+ llvm::offloading::sycl::writeSymbolTable(Names, SymbolData);
return SymbolData;
}
-/// Splits the fully linked device \p M into one bitcode file per device image
-/// according to \p Mode and returns the list of split images with their symbol
-/// tables.
-///
-/// For SPLIT_NONE, \p LinkedBitcodeFile is returned as-is.
-/// For SPLIT_PER_KERNEL, the module is split into parts such that each part
-/// contains exactly one kernel entry point and its transitive dependencies;
-/// each part is written to a fresh temporary bitcode file.
-static Expected>
-splitDeviceCode(std::unique_ptr M, StringRef LinkedBitcodeFile,
-IRSplitMode Mode, const ArgList &Args) {
- SmallVector SplitModules;
+/// Functor passed to splitModuleTransitiveFromEntryPoints. For each input \p
F,
+/// returns a numeric group ID (if \p F is an entry point) determining which
+/// device image it lands in, or std::nullopt (for non-entry-points).
+/// SPLIT_PER_KERNEL \p Mode gives each kernel its own ID;
+/// SPLIT_PER_TU \p Mode groups kernels by their "sycl-module-id" attribute
+/// value.
+class EntryPointCategorizer {
+public:
+ EntryPointCategorizer(IRSplitMode Mode, bool EmitOnlyKernelsAsEntryPoints)
+ : Mode(Mode), OnlyKernelsAreEntryPoints(EmitOnlyKernelsAsEntryPoints) {}
- if (Mode == IRSplitMode::SPLIT_NONE) {
-SplitModules.push_back(
-{SmallString<256>(LinkedBitcodeFile), collectSymbols(*M)});
-return SplitModules;
- }
+ std::optional operator()(const Function &F) {
+if (!isEntryPoint(F, OnlyKernelsAreEntryPoints))
+ return std::nullopt;
- assert(Mode == IRSplitMode::SPLIT_PER_KERNEL);
+std::string Key;
+switch (Mode) {
+case IRSplitMode::SPLIT_PER_KERNEL:
+ Key = F.getName().str();
+ break;
+case IRSplitMode::SPLIT_PER_TU:
+ Key = F.getFnAttribute(AttrSYCLModuleId).getValueAsString().str();
+ break;
+case IRSplitMode::SPLIT_NONE:
+ llvm_unreachable("categorizer should not be used for SPLIT_NONE");
bader wrote:
```suggestion
llvm_unreachable("categorizer cannot be used for SPLIT_NONE");
```
llvm_unreachable message _**should**_ be stronger than "should not". Please,
use "cannot" instead of "should not".
Categorizer doesn't support `SPLIT_NONE`.
https://github.com/llvm/llvm-project/pull/196435
[clang] [llvm] [clang-sycl-linker] Add per-translation-unit device code split mode (PR #196435)
@@ -3,13 +3,11 @@
// REQUIRES: spirv-registered-target
//
// Test the dry run of a simple case to link two input files.
-// Also verifies the default split mode ("none").
// RUN: %clangxx -emit-llvm -c -target spirv64 %s -o %t_1.bc
bader wrote:
Shouldn't we check the default "split mode"?
https://github.com/llvm/llvm-project/pull/196435
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [clang-sycl-linker] Add per-translation-unit device code split mode (PR #196435)
@@ -468,84 +468,119 @@ static Error runAOTCompile(StringRef InputFile,
StringRef OutputFile,
return createStringError(inconvertibleErrorCode(), "Unsupported arch");
}
+static constexpr char AttrSYCLModuleId[] = "sycl-module-id";
+
/// SYCL device code module split mode.
enum class IRSplitMode {
+ SPLIT_PER_TU, // one module per translation unit
SPLIT_PER_KERNEL, // one module per kernel
SPLIT_NONE// no splitting
};
-/// Parses the value of \p -module-split-mode.
+/// Parses the value of \p --module-split-mode.
static std::optional convertStringToSplitMode(StringRef S) {
return StringSwitch>(S)
+ .Case("source", IRSplitMode::SPLIT_PER_TU)
.Case("kernel", IRSplitMode::SPLIT_PER_KERNEL)
.Case("none", IRSplitMode::SPLIT_NONE)
.Default(std::nullopt);
}
+static StringRef splitModeToString(IRSplitMode Mode) {
+ switch (Mode) {
+ case IRSplitMode::SPLIT_PER_TU:
+return "source";
+ case IRSplitMode::SPLIT_PER_KERNEL:
+return "kernel";
+ case IRSplitMode::SPLIT_NONE:
+return "none";
+ }
+ llvm_unreachable("bad split mode");
+}
+
/// Result of splitting a device module: the bitcode file path and the
/// serialized symbol table for each device image.
struct SplitModule {
SmallString<256> ModuleFilePath;
SmallString<0> Symbols;
};
-static bool isEntryPoint(const Function &F) {
- return !F.isDeclaration() && F.hasKernelCallingConv();
+static bool isEntryPoint(const Function &F, bool EmitOnlyKernelsAsEntryPoints)
{
+ if (F.isDeclaration())
+return false;
+ if (F.hasKernelCallingConv())
+return true;
+ if (EmitOnlyKernelsAsEntryPoints)
+return false;
+ // sycl_external functions carry the "sycl-module-id" attribute.
+ // This branch is not reachable while EmitOnlyKernelsAsEntryPoints is
+ // hardcoded to true (see TODO in runSYCLLink).
+ return F.hasFnAttribute(AttrSYCLModuleId);
}
-/// Collect kernel names from \p M and serialize them into a symbol table.
-static SmallString<0> collectSymbols(const Module &M) {
- SmallVector KernelNames;
+/// Collect entry point names from \p M and serialize them into a symbol table.
+static SmallString<0> collectSymbols(const Module &M,
bader wrote:
```suggestion
static SmallString<0> collectEntryPoints(const Module &M,
```
The comment clearly states that the function collects only entry points rather
than all symbols.
https://github.com/llvm/llvm-project/pull/196435
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [clang-sycl-linker] Add per-translation-unit device code split mode (PR #196435)
@@ -75,11 +70,12 @@
// RUN: | FileCheck %s --check-prefix=NOTARGET
// NOTARGET: Target triple must be specified
//
-// Test the split mode ("none"): no extra splits are produced.
-// RUN: clang-sycl-linker --dry-run -v -triple=spirv64
--module-split-mode=none %t_1.bc %t_2.bc -o %t-split-none.out 2>&1 \
+// Test the split mode ("none"): kernels from different TUs are not split into
+// separate images.
bader wrote:
A few test improvement suggestions.
If the intention to separate all tests for "split mode", I suggest we create a
separate file for it (e.g.
`clang/test/Driver/clang-sycl-linker-split-mode.cpp`).
I would drop the "-test" suffix from the test name:
"`clang/test/Driver/clang-sycl-linker-test.cpp`" ->
"`clang/test/Driver/clang-sycl-linker.cpp`". It doesn't seem to be useful.
Finally, consider moving clang-sycl-linker tests from the Driver to Tooling
directory. There tests can be written in LLVM, so you can convert Input *.ll
files into tests (i.e. no need to create a separate *.cpp file for LIT
commands).
https://github.com/llvm/llvm-project/pull/196435
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [clang-sycl-linker] Add per-translation-unit device code split mode (PR #196435)
@@ -57,6 +57,9 @@ def opencl_aot_options_EQ : Joined<["--", "-"], "opencl-aot-options=">, def module_split_mode_EQ : Joined<["--", "-"], "module-split-mode=">, Flags<[LinkerOnlyOption]>, MetaVarName<"">, - HelpText<"SYCL device code module split mode. Valid values: 'none' (default) " - "emits a single device image; 'kernel' emits one device image per " - "kernel function.">; + HelpText<"SYCL device code module split mode. Valid values: " + "'source' (default) emits one device image per translation unit that contains " + "at least one kernel; translation units containing only sycl_external " + "functions do not produce a device image, this behavior may change in the future; " bader wrote: > translation units containing only sycl_external functions do not produce a > device image, this behavior may change in the future What does it mean? I suggest we drop this part. ```suggestion "at least one entry point" ``` https://github.com/llvm/llvm-project/pull/196435 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [clang-sycl-linker] Add per-translation-unit device code split mode (PR #196435)
@@ -560,17 +595,38 @@ splitDeviceCode(std::unique_ptr M, StringRef
LinkedBitcodeFile,
WriteBitcodeToFile(*Part, OS);
SplitModules.push_back(
-{SmallString<256>(*BitcodeFileOrErr), collectSymbols(*Part)});
+{SmallString<256>(*BitcodeFileOrErr),
+ collectSymbols(*Part, EmitOnlyKernelsAsEntryPoints)});
return Error::success();
};
if (Error Err = splitModuleTransitiveFromEntryPoints(
- std::move(M), EntryPointCategorizer, SplitCallback))
+ std::move(M), Categorizer, SplitCallback))
return Err;
+ if (Verbose || DryRun) {
+SmallVector SplitFiles;
+for (const SplitModule &SI : SplitModules)
+ SplitFiles.push_back(SI.ModuleFilePath);
+errs() << formatv("sycl-module-split: input: {0}, output: {1}, mode:
{2}\n",
+ LinkedBitcodeFile, llvm::join(SplitFiles, ", "),
+ splitModeToString(Mode));
+ }
+
return SplitModules;
}
+/// Returns true if module splitting can be skipped: either \p Mode is
+/// SPLIT_NONE, or \p M contains no entry points (nothing to split from).
+static bool checkModuleSplitCanBeSkipped(IRSplitMode Mode, const Module &M,
+ bool EmitOnlyKernelsAsEntryPoints) {
+ if (Mode == IRSplitMode::SPLIT_NONE)
+return true;
+ return !llvm::any_of(M.functions(), [&](const Function &F) {
bader wrote:
```suggestion
return llvm::none_of(M.functions(), [&](const Function &F) {
```
https://github.com/llvm/llvm-project/pull/196435
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [clang-sycl-linker] Add per-translation-unit device code split mode (PR #196435)
@@ -468,84 +468,119 @@ static Error runAOTCompile(StringRef InputFile,
StringRef OutputFile,
return createStringError(inconvertibleErrorCode(), "Unsupported arch");
}
+static constexpr char AttrSYCLModuleId[] = "sycl-module-id";
+
/// SYCL device code module split mode.
enum class IRSplitMode {
+ SPLIT_PER_TU, // one module per translation unit
SPLIT_PER_KERNEL, // one module per kernel
SPLIT_NONE// no splitting
};
-/// Parses the value of \p -module-split-mode.
+/// Parses the value of \p --module-split-mode.
static std::optional convertStringToSplitMode(StringRef S) {
return StringSwitch>(S)
+ .Case("source", IRSplitMode::SPLIT_PER_TU)
.Case("kernel", IRSplitMode::SPLIT_PER_KERNEL)
.Case("none", IRSplitMode::SPLIT_NONE)
.Default(std::nullopt);
}
+static StringRef splitModeToString(IRSplitMode Mode) {
+ switch (Mode) {
+ case IRSplitMode::SPLIT_PER_TU:
+return "source";
+ case IRSplitMode::SPLIT_PER_KERNEL:
+return "kernel";
+ case IRSplitMode::SPLIT_NONE:
+return "none";
+ }
+ llvm_unreachable("bad split mode");
+}
+
/// Result of splitting a device module: the bitcode file path and the
/// serialized symbol table for each device image.
struct SplitModule {
SmallString<256> ModuleFilePath;
SmallString<0> Symbols;
};
-static bool isEntryPoint(const Function &F) {
- return !F.isDeclaration() && F.hasKernelCallingConv();
+static bool isEntryPoint(const Function &F, bool EmitOnlyKernelsAsEntryPoints)
{
+ if (F.isDeclaration())
+return false;
+ if (F.hasKernelCallingConv())
+return true;
+ if (EmitOnlyKernelsAsEntryPoints)
+return false;
+ // sycl_external functions carry the "sycl-module-id" attribute.
+ // This branch is not reachable while EmitOnlyKernelsAsEntryPoints is
+ // hardcoded to true (see TODO in runSYCLLink).
+ return F.hasFnAttribute(AttrSYCLModuleId);
}
-/// Collect kernel names from \p M and serialize them into a symbol table.
-static SmallString<0> collectSymbols(const Module &M) {
- SmallVector KernelNames;
+/// Collect entry point names from \p M and serialize them into a symbol table.
+static SmallString<0> collectSymbols(const Module &M,
+ bool EmitOnlyKernelsAsEntryPoints) {
+ SmallVector Names;
for (const Function &F : M)
-if (isEntryPoint(F))
- KernelNames.push_back(F.getName());
+if (isEntryPoint(F, EmitOnlyKernelsAsEntryPoints))
+ Names.push_back(F.getName());
SmallString<0> SymbolData;
- llvm::offloading::sycl::writeSymbolTable(KernelNames, SymbolData);
+ llvm::offloading::sycl::writeSymbolTable(Names, SymbolData);
return SymbolData;
}
-/// Splits the fully linked device \p M into one bitcode file per device image
-/// according to \p Mode and returns the list of split images with their symbol
-/// tables.
-///
-/// For SPLIT_NONE, \p LinkedBitcodeFile is returned as-is.
-/// For SPLIT_PER_KERNEL, the module is split into parts such that each part
-/// contains exactly one kernel entry point and its transitive dependencies;
-/// each part is written to a fresh temporary bitcode file.
-static Expected>
-splitDeviceCode(std::unique_ptr M, StringRef LinkedBitcodeFile,
-IRSplitMode Mode, const ArgList &Args) {
- SmallVector SplitModules;
+/// Functor passed to splitModuleTransitiveFromEntryPoints. For each input \p
F,
+/// returns a numeric group ID (if \p F is an entry point) determining which
+/// device image it lands in, or std::nullopt (for non-entry-points).
+/// SPLIT_PER_KERNEL \p Mode gives each kernel its own ID;
+/// SPLIT_PER_TU \p Mode groups kernels by their "sycl-module-id" attribute
+/// value.
+class EntryPointCategorizer {
+public:
+ EntryPointCategorizer(IRSplitMode Mode, bool EmitOnlyKernelsAsEntryPoints)
+ : Mode(Mode), OnlyKernelsAreEntryPoints(EmitOnlyKernelsAsEntryPoints) {}
- if (Mode == IRSplitMode::SPLIT_NONE) {
-SplitModules.push_back(
-{SmallString<256>(LinkedBitcodeFile), collectSymbols(*M)});
-return SplitModules;
- }
+ std::optional operator()(const Function &F) {
+if (!isEntryPoint(F, OnlyKernelsAreEntryPoints))
+ return std::nullopt;
- assert(Mode == IRSplitMode::SPLIT_PER_KERNEL);
+std::string Key;
+switch (Mode) {
+case IRSplitMode::SPLIT_PER_KERNEL:
+ Key = F.getName().str();
+ break;
+case IRSplitMode::SPLIT_PER_TU:
+ Key = F.getFnAttribute(AttrSYCLModuleId).getValueAsString().str();
+ break;
+case IRSplitMode::SPLIT_NONE:
+ llvm_unreachable("categorizer not used for SPLIT_NONE");
+}
- // splitModuleTransitiveFromEntryPoints asserts that at least one entry point
- // was categorized. If the linked module contains no kernel definitions at
- // all, there is nothing to split; fall back to shipping the linked module
- // as a single image.
- bool HasKernel = llvm::any_of(M->functions(), isEntryPoint);
- if (!HasKernel) {
-SplitModule
[clang] [llvm] [clang-sycl-linker] Add per-translation-unit device code split mode (PR #196435)
@@ -468,84 +468,119 @@ static Error runAOTCompile(StringRef InputFile,
StringRef OutputFile,
return createStringError(inconvertibleErrorCode(), "Unsupported arch");
}
+static constexpr char AttrSYCLModuleId[] = "sycl-module-id";
+
/// SYCL device code module split mode.
enum class IRSplitMode {
+ SPLIT_PER_TU, // one module per translation unit
SPLIT_PER_KERNEL, // one module per kernel
SPLIT_NONE// no splitting
};
-/// Parses the value of \p -module-split-mode.
+/// Parses the value of \p --module-split-mode.
static std::optional convertStringToSplitMode(StringRef S) {
return StringSwitch>(S)
+ .Case("source", IRSplitMode::SPLIT_PER_TU)
.Case("kernel", IRSplitMode::SPLIT_PER_KERNEL)
.Case("none", IRSplitMode::SPLIT_NONE)
.Default(std::nullopt);
}
+static StringRef splitModeToString(IRSplitMode Mode) {
+ switch (Mode) {
+ case IRSplitMode::SPLIT_PER_TU:
+return "source";
+ case IRSplitMode::SPLIT_PER_KERNEL:
+return "kernel";
+ case IRSplitMode::SPLIT_NONE:
+return "none";
+ }
+ llvm_unreachable("bad split mode");
+}
+
/// Result of splitting a device module: the bitcode file path and the
/// serialized symbol table for each device image.
struct SplitModule {
SmallString<256> ModuleFilePath;
SmallString<0> Symbols;
};
-static bool isEntryPoint(const Function &F) {
- return !F.isDeclaration() && F.hasKernelCallingConv();
+static bool isEntryPoint(const Function &F, bool EmitOnlyKernelsAsEntryPoints)
{
+ if (F.isDeclaration())
+return false;
+ if (F.hasKernelCallingConv())
+return true;
+ if (EmitOnlyKernelsAsEntryPoints)
+return false;
+ // sycl_external functions carry the "sycl-module-id" attribute.
+ // This branch is not reachable while EmitOnlyKernelsAsEntryPoints is
+ // hardcoded to true (see TODO in runSYCLLink).
+ return F.hasFnAttribute(AttrSYCLModuleId);
}
-/// Collect kernel names from \p M and serialize them into a symbol table.
-static SmallString<0> collectSymbols(const Module &M) {
- SmallVector KernelNames;
+/// Collect entry point names from \p M and serialize them into a symbol table.
+static SmallString<0> collectSymbols(const Module &M,
+ bool EmitOnlyKernelsAsEntryPoints) {
+ SmallVector Names;
for (const Function &F : M)
-if (isEntryPoint(F))
- KernelNames.push_back(F.getName());
+if (isEntryPoint(F, EmitOnlyKernelsAsEntryPoints))
+ Names.push_back(F.getName());
SmallString<0> SymbolData;
- llvm::offloading::sycl::writeSymbolTable(KernelNames, SymbolData);
+ llvm::offloading::sycl::writeSymbolTable(Names, SymbolData);
return SymbolData;
}
-/// Splits the fully linked device \p M into one bitcode file per device image
-/// according to \p Mode and returns the list of split images with their symbol
-/// tables.
-///
-/// For SPLIT_NONE, \p LinkedBitcodeFile is returned as-is.
-/// For SPLIT_PER_KERNEL, the module is split into parts such that each part
-/// contains exactly one kernel entry point and its transitive dependencies;
-/// each part is written to a fresh temporary bitcode file.
-static Expected>
-splitDeviceCode(std::unique_ptr M, StringRef LinkedBitcodeFile,
-IRSplitMode Mode, const ArgList &Args) {
- SmallVector SplitModules;
+/// Functor passed to splitModuleTransitiveFromEntryPoints. For each input \p
F,
+/// returns a numeric group ID (if \p F is an entry point) determining which
+/// device image it lands in, or std::nullopt (for non-entry-points).
+/// SPLIT_PER_KERNEL \p Mode gives each kernel its own ID;
+/// SPLIT_PER_TU \p Mode groups kernels by their "sycl-module-id" attribute
+/// value.
+class EntryPointCategorizer {
+public:
+ EntryPointCategorizer(IRSplitMode Mode, bool EmitOnlyKernelsAsEntryPoints)
+ : Mode(Mode), OnlyKernelsAreEntryPoints(EmitOnlyKernelsAsEntryPoints) {}
- if (Mode == IRSplitMode::SPLIT_NONE) {
-SplitModules.push_back(
-{SmallString<256>(LinkedBitcodeFile), collectSymbols(*M)});
-return SplitModules;
- }
+ std::optional operator()(const Function &F) {
+if (!isEntryPoint(F, OnlyKernelsAreEntryPoints))
+ return std::nullopt;
- assert(Mode == IRSplitMode::SPLIT_PER_KERNEL);
+std::string Key;
+switch (Mode) {
+case IRSplitMode::SPLIT_PER_KERNEL:
+ Key = F.getName().str();
+ break;
+case IRSplitMode::SPLIT_PER_TU:
+ Key = F.getFnAttribute(AttrSYCLModuleId).getValueAsString().str();
+ break;
+case IRSplitMode::SPLIT_NONE:
+ llvm_unreachable("categorizer not used for SPLIT_NONE");
bader wrote:
What does the message mean? I think if we get here categorize **is** used for
`SPLIT_NONE` mode.
Should it say, "categorizer doesn't support SPLIT_NONE" or "categorizer can't
be used for SPLIT_NONE"?
https://github.com/llvm/llvm-project/pull/196435
___
cfe-commits mailing list
cfe-commits@lis
[clang] [llvm] [clang-sycl-linker] Add per-translation-unit device code split mode (PR #196435)
@@ -0,0 +1,25 @@ +target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-n8:16:32:64-G1" +target triple = "spirv64" bader wrote: Please, combine these two inputs into one. It would be more efficient to validate. We should be able to verify `--module-split-mode=source` with a single tool invocation. https://github.com/llvm/llvm-project/pull/196435 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [clang-sycl-linker] Add per-translation-unit device code split mode (PR #196435)
@@ -57,6 +57,11 @@ def opencl_aot_options_EQ : Joined<["--", "-"], "opencl-aot-options=">, def module_split_mode_EQ : Joined<["--", "-"], "module-split-mode=">, Flags<[LinkerOnlyOption]>, MetaVarName<"">, - HelpText<"SYCL device code module split mode. Valid values: 'none' (default) " - "emits a single device image; 'kernel' emits one device image per " - "kernel function.">; + HelpText<"SYCL device code module split mode. Valid values: " + "'source' (default) emits one device image per translation unit " + "that contains at least one kernel (grouped by the 'sycl-module-id' " + "attribute); translation units containing only sycl_external " YuriPlyakhin wrote: 39f9343ac0df15b2789075f192c58925cc5d4879 https://github.com/llvm/llvm-project/pull/196435 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [clang-sycl-linker] Add per-translation-unit device code split mode (PR #196435)
https://github.com/YuriPlyakhin updated
https://github.com/llvm/llvm-project/pull/196435
>From de5f17e5602c93d3aa6814078ee216dcf3687ece Mon Sep 17 00:00:00 2001
From: "Plyakhin, Yury"
Date: Wed, 6 May 2026 18:32:36 +0200
Subject: [PATCH 1/2] [clang-sycl-linker] Add per-translation-unit device code
split mode
Adds `source` split mode to `clang-sycl-linker`, driven by the
`sycl-module-id` function attribute emitted by the SYCL frontend.
`source` is the default mode and groups kernels by the value of their
`sycl-module-id` attribute, emitting one device image per translation
unit. If the linked module contains no kernels, no device image is
emitted. `none` disables splitting and emits a single device image.
`kernel` emits one device image per kernel function.
The `EntryPointCategorizer` in `ClangSYCLLinker.cpp` is refactored into a
class (instead of a stateful lambda) to support both per-kernel and per-TU
modes cleanly.
`llvm-split`'s `-split-by-category=module-id` is renamed to
`-split-by-category=attribute` and the previously hardcoded `"module-id"`
attribute name is replaced by a required `--category-attribute=` CLI
option. This decouples the tool from any specific attribute name. All
`SplitByCategory` tests are updated accordingly.
Co-Authored-By: Claude
---
clang/test/Driver/Inputs/SYCL/external-fn.ll | 19 +++
clang/test/Driver/Inputs/SYCL/two-modules.ll | 25
clang/test/Driver/clang-sycl-linker-test.cpp | 32 -
.../clang-sycl-linker/ClangSYCLLinker.cpp | 131 --
clang/tools/clang-sycl-linker/SYCLLinkOpts.td | 11 +-
.../complex-indirect-call-chain1.ll | 2 +-
.../complex-indirect-call-chain2.ll | 2 +-
.../SplitByCategory/module-split-func-ptr.ll | 2 +-
.../SplitByCategory/split-by-source.ll| 2 +-
.../split-with-kernel-declarations.ll | 2 +-
llvm/tools/llvm-split/llvm-split.cpp | 47 ---
11 files changed, 205 insertions(+), 70 deletions(-)
create mode 100644 clang/test/Driver/Inputs/SYCL/external-fn.ll
create mode 100644 clang/test/Driver/Inputs/SYCL/two-modules.ll
diff --git a/clang/test/Driver/Inputs/SYCL/external-fn.ll
b/clang/test/Driver/Inputs/SYCL/external-fn.ll
new file mode 100644
index 0..b6ec0de46bdad
--- /dev/null
+++ b/clang/test/Driver/Inputs/SYCL/external-fn.ll
@@ -0,0 +1,19 @@
+target datalayout =
"e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-n8:16:32:64-G1"
+target triple = "spirv64"
+
+; A kernel from TU1 and a sycl_external function from TU2.
+
+define spir_func i32 @ext_fn(i32 %a) #1 {
+entry:
+ %r = add nsw i32 %a, 2
+ ret i32 %r
+}
+
+define spir_kernel void @k(ptr addrspace(1) %out) #0 {
+entry:
+ store i32 42, ptr addrspace(1) %out, align 4
+ ret void
+}
+
+attributes #0 = { "sycl-module-id"="TU1.cpp" }
+attributes #1 = { "sycl-module-id"="TU2.cpp" }
diff --git a/clang/test/Driver/Inputs/SYCL/two-modules.ll
b/clang/test/Driver/Inputs/SYCL/two-modules.ll
new file mode 100644
index 0..d63f0e6f38726
--- /dev/null
+++ b/clang/test/Driver/Inputs/SYCL/two-modules.ll
@@ -0,0 +1,25 @@
+target datalayout =
"e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-n8:16:32:64-G1"
+target triple = "spirv64"
+
+define spir_func i32 @helper(i32 %a) {
+entry:
+ %r = add nsw i32 %a, 1
+ ret i32 %r
+}
+
+define spir_kernel void @kernel_a(ptr addrspace(1) %out, i32 %a) #0 {
+entry:
+ %r = call spir_func i32 @helper(i32 %a)
+ store i32 %r, ptr addrspace(1) %out, align 4
+ ret void
+}
+
+define spir_kernel void @kernel_b(ptr addrspace(1) %out, i32 %a) #1 {
+entry:
+ %r = call spir_func i32 @helper(i32 %a)
+ store i32 %r, ptr addrspace(1) %out, align 4
+ ret void
+}
+
+attributes #0 = { "sycl-module-id"="TU1.cpp" }
+attributes #1 = { "sycl-module-id"="TU2.cpp" }
diff --git a/clang/test/Driver/clang-sycl-linker-test.cpp
b/clang/test/Driver/clang-sycl-linker-test.cpp
index cd99d4d47b1e1..69596252efdf0 100644
--- a/clang/test/Driver/clang-sycl-linker-test.cpp
+++ b/clang/test/Driver/clang-sycl-linker-test.cpp
@@ -3,13 +3,14 @@
// REQUIRES: spirv-registered-target
//
// Test the dry run of a simple case to link two input files.
-// Also verifies the default split mode ("none").
+// The input has no SYCL kernels, so the default split mode ('source') produces
+// a single device image via the no-entry-point fallback.
// RUN: %clangxx -emit-llvm -c -target spirv64 %s -o %t_1.bc
// RUN: %clangxx -emit-llvm -c -target spirv64 %s -o %t_2.bc
// RUN: clang-sycl-linker --dry-run -v -triple=spirv64 %t_1.bc %t_2.bc -o
%t-spirv.out 2>&1 \
// RUN: | FileCheck %s --check-prefix=SIMPLE-FO
// SIMPLE-FO: sycl-device-link: inputs: {{.*}}.bc, {{.*}}.bc libfiles:
output: [[LLVMLINKOUT:.*]].bc
-// SIMPLE-FO-NEXT: sycl-module-split: input: [[LLVMLINKOUT]].bc, output:
[[LLVMLINKOUT]].bc, mode: none
+// SIMPLE-FO-NEXT: sycl-module-split: input: [[LLVMLINKOUT]].bc, output:
[[LLVMLINKOUT]].bc,
[clang] [llvm] [clang-sycl-linker] Add per-translation-unit device code split mode (PR #196435)
@@ -468,84 +468,129 @@ static Error runAOTCompile(StringRef InputFile,
StringRef OutputFile,
return createStringError(inconvertibleErrorCode(), "Unsupported arch");
}
+static constexpr char AttrSYCLModuleId[] = "sycl-module-id";
+
/// SYCL device code module split mode.
enum class IRSplitMode {
+ SPLIT_PER_TU, // one module per translation unit
SPLIT_PER_KERNEL, // one module per kernel
SPLIT_NONE// no splitting
};
-/// Parses the value of \p -module-split-mode.
+/// Parses the value of \p --module-split-mode.
static std::optional convertStringToSplitMode(StringRef S) {
return StringSwitch>(S)
+ .Case("source", IRSplitMode::SPLIT_PER_TU)
.Case("kernel", IRSplitMode::SPLIT_PER_KERNEL)
.Case("none", IRSplitMode::SPLIT_NONE)
.Default(std::nullopt);
}
+static StringRef splitModeToString(IRSplitMode Mode) {
+ switch (Mode) {
+ case IRSplitMode::SPLIT_PER_TU:
+return "source";
+ case IRSplitMode::SPLIT_PER_KERNEL:
+return "kernel";
+ case IRSplitMode::SPLIT_NONE:
+return "none";
+ }
+ llvm_unreachable("bad split mode");
+}
+
/// Result of splitting a device module: the bitcode file path and the
/// serialized symbol table for each device image.
struct SplitModule {
SmallString<256> ModuleFilePath;
SmallString<0> Symbols;
};
-static bool isEntryPoint(const Function &F) {
- return !F.isDeclaration() && F.hasKernelCallingConv();
+static bool isEntryPoint(const Function &F, bool EmitOnlyKernelsAsEntryPoints)
{
+ if (F.isDeclaration())
+return false;
+ if (F.hasKernelCallingConv())
+return true;
+ if (EmitOnlyKernelsAsEntryPoints)
+return false;
+ // sycl_external functions carry the "sycl-module-id" attribute.
+ return F.hasFnAttribute(AttrSYCLModuleId);
}
-/// Collect kernel names from \p M and serialize them into a symbol table.
-static SmallString<0> collectSymbols(const Module &M) {
- SmallVector KernelNames;
+/// Collect entry point names from \p M and serialize them into a symbol table.
+static SmallString<0> collectSymbols(const Module &M,
+ bool EmitOnlyKernelsAsEntryPoints) {
+ SmallVector Names;
for (const Function &F : M)
-if (isEntryPoint(F))
- KernelNames.push_back(F.getName());
+if (isEntryPoint(F, EmitOnlyKernelsAsEntryPoints))
+ Names.push_back(F.getName());
SmallString<0> SymbolData;
- llvm::offloading::sycl::writeSymbolTable(KernelNames, SymbolData);
+ llvm::offloading::sycl::writeSymbolTable(Names, SymbolData);
return SymbolData;
}
+class EntryPointCategorizer {
+public:
+ EntryPointCategorizer(IRSplitMode Mode, bool EmitOnlyKernelsAsEntryPoints)
+ : Mode(Mode), OnlyKernelsAreEntryPoints(EmitOnlyKernelsAsEntryPoints) {}
+
+ std::optional operator()(const Function &F) {
YuriPlyakhin wrote:
39f9343ac0df15b2789075f192c58925cc5d4879
https://github.com/llvm/llvm-project/pull/196435
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [clang-sycl-linker] Add per-translation-unit device code split mode (PR #196435)
https://github.com/YuriPlyakhin edited https://github.com/llvm/llvm-project/pull/196435 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [clang-sycl-linker] Add per-translation-unit device code split mode (PR #196435)
https://github.com/YuriPlyakhin updated
https://github.com/llvm/llvm-project/pull/196435
>From de5f17e5602c93d3aa6814078ee216dcf3687ece Mon Sep 17 00:00:00 2001
From: "Plyakhin, Yury"
Date: Wed, 6 May 2026 18:32:36 +0200
Subject: [PATCH 1/2] [clang-sycl-linker] Add per-translation-unit device code
split mode
Adds `source` split mode to `clang-sycl-linker`, driven by the
`sycl-module-id` function attribute emitted by the SYCL frontend.
`source` is the default mode and groups kernels by the value of their
`sycl-module-id` attribute, emitting one device image per translation
unit. If the linked module contains no kernels, no device image is
emitted. `none` disables splitting and emits a single device image.
`kernel` emits one device image per kernel function.
The `EntryPointCategorizer` in `ClangSYCLLinker.cpp` is refactored into a
class (instead of a stateful lambda) to support both per-kernel and per-TU
modes cleanly.
`llvm-split`'s `-split-by-category=module-id` is renamed to
`-split-by-category=attribute` and the previously hardcoded `"module-id"`
attribute name is replaced by a required `--category-attribute=` CLI
option. This decouples the tool from any specific attribute name. All
`SplitByCategory` tests are updated accordingly.
Co-Authored-By: Claude
---
clang/test/Driver/Inputs/SYCL/external-fn.ll | 19 +++
clang/test/Driver/Inputs/SYCL/two-modules.ll | 25
clang/test/Driver/clang-sycl-linker-test.cpp | 32 -
.../clang-sycl-linker/ClangSYCLLinker.cpp | 131 --
clang/tools/clang-sycl-linker/SYCLLinkOpts.td | 11 +-
.../complex-indirect-call-chain1.ll | 2 +-
.../complex-indirect-call-chain2.ll | 2 +-
.../SplitByCategory/module-split-func-ptr.ll | 2 +-
.../SplitByCategory/split-by-source.ll| 2 +-
.../split-with-kernel-declarations.ll | 2 +-
llvm/tools/llvm-split/llvm-split.cpp | 47 ---
11 files changed, 205 insertions(+), 70 deletions(-)
create mode 100644 clang/test/Driver/Inputs/SYCL/external-fn.ll
create mode 100644 clang/test/Driver/Inputs/SYCL/two-modules.ll
diff --git a/clang/test/Driver/Inputs/SYCL/external-fn.ll
b/clang/test/Driver/Inputs/SYCL/external-fn.ll
new file mode 100644
index 0..b6ec0de46bdad
--- /dev/null
+++ b/clang/test/Driver/Inputs/SYCL/external-fn.ll
@@ -0,0 +1,19 @@
+target datalayout =
"e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-n8:16:32:64-G1"
+target triple = "spirv64"
+
+; A kernel from TU1 and a sycl_external function from TU2.
+
+define spir_func i32 @ext_fn(i32 %a) #1 {
+entry:
+ %r = add nsw i32 %a, 2
+ ret i32 %r
+}
+
+define spir_kernel void @k(ptr addrspace(1) %out) #0 {
+entry:
+ store i32 42, ptr addrspace(1) %out, align 4
+ ret void
+}
+
+attributes #0 = { "sycl-module-id"="TU1.cpp" }
+attributes #1 = { "sycl-module-id"="TU2.cpp" }
diff --git a/clang/test/Driver/Inputs/SYCL/two-modules.ll
b/clang/test/Driver/Inputs/SYCL/two-modules.ll
new file mode 100644
index 0..d63f0e6f38726
--- /dev/null
+++ b/clang/test/Driver/Inputs/SYCL/two-modules.ll
@@ -0,0 +1,25 @@
+target datalayout =
"e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-n8:16:32:64-G1"
+target triple = "spirv64"
+
+define spir_func i32 @helper(i32 %a) {
+entry:
+ %r = add nsw i32 %a, 1
+ ret i32 %r
+}
+
+define spir_kernel void @kernel_a(ptr addrspace(1) %out, i32 %a) #0 {
+entry:
+ %r = call spir_func i32 @helper(i32 %a)
+ store i32 %r, ptr addrspace(1) %out, align 4
+ ret void
+}
+
+define spir_kernel void @kernel_b(ptr addrspace(1) %out, i32 %a) #1 {
+entry:
+ %r = call spir_func i32 @helper(i32 %a)
+ store i32 %r, ptr addrspace(1) %out, align 4
+ ret void
+}
+
+attributes #0 = { "sycl-module-id"="TU1.cpp" }
+attributes #1 = { "sycl-module-id"="TU2.cpp" }
diff --git a/clang/test/Driver/clang-sycl-linker-test.cpp
b/clang/test/Driver/clang-sycl-linker-test.cpp
index cd99d4d47b1e1..69596252efdf0 100644
--- a/clang/test/Driver/clang-sycl-linker-test.cpp
+++ b/clang/test/Driver/clang-sycl-linker-test.cpp
@@ -3,13 +3,14 @@
// REQUIRES: spirv-registered-target
//
// Test the dry run of a simple case to link two input files.
-// Also verifies the default split mode ("none").
+// The input has no SYCL kernels, so the default split mode ('source') produces
+// a single device image via the no-entry-point fallback.
// RUN: %clangxx -emit-llvm -c -target spirv64 %s -o %t_1.bc
// RUN: %clangxx -emit-llvm -c -target spirv64 %s -o %t_2.bc
// RUN: clang-sycl-linker --dry-run -v -triple=spirv64 %t_1.bc %t_2.bc -o
%t-spirv.out 2>&1 \
// RUN: | FileCheck %s --check-prefix=SIMPLE-FO
// SIMPLE-FO: sycl-device-link: inputs: {{.*}}.bc, {{.*}}.bc libfiles:
output: [[LLVMLINKOUT:.*]].bc
-// SIMPLE-FO-NEXT: sycl-module-split: input: [[LLVMLINKOUT]].bc, output:
[[LLVMLINKOUT]].bc, mode: none
+// SIMPLE-FO-NEXT: sycl-module-split: input: [[LLVMLINKOUT]].bc, output:
[[LLVMLINKOUT]].bc,
[clang] [llvm] [clang-sycl-linker] Add per-translation-unit device code split mode (PR #196435)
@@ -468,84 +468,129 @@ static Error runAOTCompile(StringRef InputFile,
StringRef OutputFile,
return createStringError(inconvertibleErrorCode(), "Unsupported arch");
}
+static constexpr char AttrSYCLModuleId[] = "sycl-module-id";
+
/// SYCL device code module split mode.
enum class IRSplitMode {
+ SPLIT_PER_TU, // one module per translation unit
SPLIT_PER_KERNEL, // one module per kernel
SPLIT_NONE// no splitting
};
-/// Parses the value of \p -module-split-mode.
+/// Parses the value of \p --module-split-mode.
static std::optional convertStringToSplitMode(StringRef S) {
return StringSwitch>(S)
+ .Case("source", IRSplitMode::SPLIT_PER_TU)
.Case("kernel", IRSplitMode::SPLIT_PER_KERNEL)
.Case("none", IRSplitMode::SPLIT_NONE)
.Default(std::nullopt);
}
+static StringRef splitModeToString(IRSplitMode Mode) {
+ switch (Mode) {
+ case IRSplitMode::SPLIT_PER_TU:
+return "source";
+ case IRSplitMode::SPLIT_PER_KERNEL:
+return "kernel";
+ case IRSplitMode::SPLIT_NONE:
+return "none";
+ }
+ llvm_unreachable("bad split mode");
+}
+
/// Result of splitting a device module: the bitcode file path and the
/// serialized symbol table for each device image.
struct SplitModule {
SmallString<256> ModuleFilePath;
SmallString<0> Symbols;
};
-static bool isEntryPoint(const Function &F) {
- return !F.isDeclaration() && F.hasKernelCallingConv();
+static bool isEntryPoint(const Function &F, bool EmitOnlyKernelsAsEntryPoints)
{
+ if (F.isDeclaration())
+return false;
+ if (F.hasKernelCallingConv())
+return true;
+ if (EmitOnlyKernelsAsEntryPoints)
YuriPlyakhin wrote:
only one branch. I added comment: 39f9343ac0df15b2789075f192c58925cc5d4879
https://github.com/llvm/llvm-project/pull/196435
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [clang-sycl-linker] Add per-translation-unit device code split mode (PR #196435)
YuriPlyakhin wrote:
> nit:
>
> ```c++
> return createStringError(inconvertibleErrorCode(), "error message");
> ```
>
> can be shortened to
>
> ```c++
> return createStringError("error message");
> ```
I see this in several places, none of which is touched by this PR, I'll address
this as an [NFC] refactoring in a new PR to not pollute this one.
https://github.com/llvm/llvm-project/pull/196435
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [clang-sycl-linker] Add per-translation-unit device code split mode (PR #196435)
@@ -468,84 +468,129 @@ static Error runAOTCompile(StringRef InputFile,
StringRef OutputFile,
return createStringError(inconvertibleErrorCode(), "Unsupported arch");
}
+static constexpr char AttrSYCLModuleId[] = "sycl-module-id";
+
/// SYCL device code module split mode.
enum class IRSplitMode {
+ SPLIT_PER_TU, // one module per translation unit
SPLIT_PER_KERNEL, // one module per kernel
SPLIT_NONE// no splitting
};
-/// Parses the value of \p -module-split-mode.
+/// Parses the value of \p --module-split-mode.
static std::optional convertStringToSplitMode(StringRef S) {
return StringSwitch>(S)
+ .Case("source", IRSplitMode::SPLIT_PER_TU)
.Case("kernel", IRSplitMode::SPLIT_PER_KERNEL)
.Case("none", IRSplitMode::SPLIT_NONE)
.Default(std::nullopt);
}
+static StringRef splitModeToString(IRSplitMode Mode) {
+ switch (Mode) {
+ case IRSplitMode::SPLIT_PER_TU:
+return "source";
+ case IRSplitMode::SPLIT_PER_KERNEL:
+return "kernel";
+ case IRSplitMode::SPLIT_NONE:
+return "none";
+ }
+ llvm_unreachable("bad split mode");
+}
+
/// Result of splitting a device module: the bitcode file path and the
/// serialized symbol table for each device image.
struct SplitModule {
SmallString<256> ModuleFilePath;
SmallString<0> Symbols;
};
-static bool isEntryPoint(const Function &F) {
- return !F.isDeclaration() && F.hasKernelCallingConv();
+static bool isEntryPoint(const Function &F, bool EmitOnlyKernelsAsEntryPoints)
{
+ if (F.isDeclaration())
+return false;
+ if (F.hasKernelCallingConv())
+return true;
+ if (EmitOnlyKernelsAsEntryPoints)
+return false;
+ // sycl_external functions carry the "sycl-module-id" attribute.
+ return F.hasFnAttribute(AttrSYCLModuleId);
}
-/// Collect kernel names from \p M and serialize them into a symbol table.
-static SmallString<0> collectSymbols(const Module &M) {
- SmallVector KernelNames;
+/// Collect entry point names from \p M and serialize them into a symbol table.
+static SmallString<0> collectSymbols(const Module &M,
+ bool EmitOnlyKernelsAsEntryPoints) {
+ SmallVector Names;
for (const Function &F : M)
-if (isEntryPoint(F))
- KernelNames.push_back(F.getName());
+if (isEntryPoint(F, EmitOnlyKernelsAsEntryPoints))
+ Names.push_back(F.getName());
SmallString<0> SymbolData;
- llvm::offloading::sycl::writeSymbolTable(KernelNames, SymbolData);
+ llvm::offloading::sycl::writeSymbolTable(Names, SymbolData);
return SymbolData;
}
+class EntryPointCategorizer {
+public:
+ EntryPointCategorizer(IRSplitMode Mode, bool EmitOnlyKernelsAsEntryPoints)
+ : Mode(Mode), OnlyKernelsAreEntryPoints(EmitOnlyKernelsAsEntryPoints) {}
+
+ std::optional operator()(const Function &F) {
+if (!isEntryPoint(F, OnlyKernelsAreEntryPoints))
+ return std::nullopt;
+
+std::string Key;
+switch (Mode) {
+case IRSplitMode::SPLIT_PER_KERNEL:
+ Key = F.getName().str();
+ break;
+case IRSplitMode::SPLIT_PER_TU:
+ Key = F.getFnAttribute(AttrSYCLModuleId).getValueAsString().str();
+ break;
+case IRSplitMode::SPLIT_NONE:
+ llvm_unreachable("categorizer not used for SPLIT_NONE");
+}
+
+auto [It, Inserted] =
+StrToId.try_emplace(std::move(Key), static_cast(StrToId.size()));
+return It->second;
+ }
+
+private:
+ IRSplitMode Mode;
+ bool OnlyKernelsAreEntryPoints;
+ llvm::StringMap StrToId;
+};
+
/// Splits the fully linked device \p M into one bitcode file per device image
/// according to \p Mode and returns the list of split images with their symbol
/// tables.
///
/// For SPLIT_NONE, \p LinkedBitcodeFile is returned as-is.
YuriPlyakhin wrote:
39f9343ac0df15b2789075f192c58925cc5d4879
https://github.com/llvm/llvm-project/pull/196435
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [clang-sycl-linker] Add per-translation-unit device code split mode (PR #196435)
@@ -468,84 +468,129 @@ static Error runAOTCompile(StringRef InputFile,
StringRef OutputFile,
return createStringError(inconvertibleErrorCode(), "Unsupported arch");
}
+static constexpr char AttrSYCLModuleId[] = "sycl-module-id";
+
/// SYCL device code module split mode.
enum class IRSplitMode {
+ SPLIT_PER_TU, // one module per translation unit
SPLIT_PER_KERNEL, // one module per kernel
SPLIT_NONE// no splitting
};
-/// Parses the value of \p -module-split-mode.
+/// Parses the value of \p --module-split-mode.
static std::optional convertStringToSplitMode(StringRef S) {
return StringSwitch>(S)
+ .Case("source", IRSplitMode::SPLIT_PER_TU)
.Case("kernel", IRSplitMode::SPLIT_PER_KERNEL)
.Case("none", IRSplitMode::SPLIT_NONE)
.Default(std::nullopt);
}
+static StringRef splitModeToString(IRSplitMode Mode) {
+ switch (Mode) {
+ case IRSplitMode::SPLIT_PER_TU:
+return "source";
+ case IRSplitMode::SPLIT_PER_KERNEL:
+return "kernel";
+ case IRSplitMode::SPLIT_NONE:
+return "none";
+ }
+ llvm_unreachable("bad split mode");
+}
+
/// Result of splitting a device module: the bitcode file path and the
/// serialized symbol table for each device image.
struct SplitModule {
SmallString<256> ModuleFilePath;
SmallString<0> Symbols;
};
-static bool isEntryPoint(const Function &F) {
- return !F.isDeclaration() && F.hasKernelCallingConv();
+static bool isEntryPoint(const Function &F, bool EmitOnlyKernelsAsEntryPoints)
{
+ if (F.isDeclaration())
+return false;
+ if (F.hasKernelCallingConv())
+return true;
+ if (EmitOnlyKernelsAsEntryPoints)
maksimsab wrote:
Is this tested?
https://github.com/llvm/llvm-project/pull/196435
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [clang-sycl-linker] Add per-translation-unit device code split mode (PR #196435)
maksimsab wrote:
nit:
```cpp
return createStringError(inconvertibleErrorCode(), "error message");
```
can be shortened to
```cpp
return createStringError("error message");
```
https://github.com/llvm/llvm-project/pull/196435
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
