Skip to content

Commit 70be072

Browse files
committed
[SYCL] Implement compile and link for source-based kernel bundles
Implements a new `compile` variant for source-based `kernel_bundle` and the corresponding linking functionality. Signed-off-by: Larsen, Steffen <[email protected]>
1 parent f4a3cb9 commit 70be072

File tree

18 files changed

+1636
-341
lines changed

18 files changed

+1636
-341
lines changed

llvm/include/llvm/SYCLPostLink/ModuleSplitter.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,11 @@ std::unique_ptr<ModuleSplitterBase>
300300
getDeviceCodeSplitter(ModuleDesc &&MD, IRSplitMode Mode, bool IROutputOnly,
301301
bool EmitOnlyKernelsAsEntryPoints);
302302

303+
std::unique_ptr<ModuleSplitterBase>
304+
getDeviceCodeSplitter(ModuleDesc &&MD, IRSplitMode Mode, bool IROutputOnly,
305+
bool EmitOnlyKernelsAsEntryPoints,
306+
bool OverwriteAllowDeviceImageDependencies);
307+
303308
#ifndef NDEBUG
304309
void dumpEntryPoints(const EntryPointSet &C, const char *Msg = "", int Tab = 0);
305310
void dumpEntryPoints(const Module &M, bool OnlyKernelsAreEntryPoints = false,

llvm/lib/SYCLPostLink/ModuleSplitter.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1153,8 +1153,19 @@ std::string FunctionsCategorizer::computeCategoryFor(Function *F) const {
11531153
std::unique_ptr<ModuleSplitterBase>
11541154
getDeviceCodeSplitter(ModuleDesc &&MD, IRSplitMode Mode, bool IROutputOnly,
11551155
bool EmitOnlyKernelsAsEntryPoints) {
1156+
return getDeviceCodeSplitter(std::move(MD), Mode, IROutputOnly,
1157+
EmitOnlyKernelsAsEntryPoints,
1158+
AllowDeviceImageDependencies);
1159+
}
1160+
1161+
std::unique_ptr<ModuleSplitterBase>
1162+
getDeviceCodeSplitter(ModuleDesc &&MD, IRSplitMode Mode, bool IROutputOnly,
1163+
bool EmitOnlyKernelsAsEntryPoints,
1164+
bool OverwriteAllowDeviceImageDependencies) {
11561165
FunctionsCategorizer Categorizer;
11571166

1167+
AllowDeviceImageDependencies = OverwriteAllowDeviceImageDependencies;
1168+
11581169
EntryPointsGroupScope Scope =
11591170
selectDeviceCodeGroupScope(MD.getModule(), Mode, IROutputOnly);
11601171

sycl-jit/jit-compiler/lib/rtc/DeviceCompilation.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -648,10 +648,16 @@ jit_compiler::performPostLink(std::unique_ptr<llvm::Module> Module,
648648

649649
const auto SplitMode = getDeviceCodeSplitMode(UserArgList);
650650

651+
const bool AllowDeviceImageDependencies = UserArgList.hasFlag(
652+
options::OPT_fsycl_allow_device_image_dependencies,
653+
options::OPT_fno_sycl_allow_device_image_dependencies, false);
654+
651655
// TODO: EmitOnlyKernelsAsEntryPoints is controlled by
652656
// `shouldEmitOnlyKernelsAsEntryPoints` in
653657
// `clang/lib/Driver/ToolChains/Clang.cpp`.
654-
const bool EmitOnlyKernelsAsEntryPoints = true;
658+
// If we allow device image dependencies, we should definitely not only emit
659+
// kernels as entry points.
660+
const bool EmitOnlyKernelsAsEntryPoints = !AllowDeviceImageDependencies;
655661

656662
// TODO: The optlevel passed to `sycl-post-link` is determined by
657663
// `getSYCLPostLinkOptimizationLevel` in
@@ -684,7 +690,8 @@ jit_compiler::performPostLink(std::unique_ptr<llvm::Module> Module,
684690

685691
std::unique_ptr<ModuleSplitterBase> Splitter = getDeviceCodeSplitter(
686692
ModuleDesc{std::move(Module)}, SplitMode,
687-
/*IROutputOnly=*/false, EmitOnlyKernelsAsEntryPoints);
693+
/*IROutputOnly=*/false, EmitOnlyKernelsAsEntryPoints,
694+
AllowDeviceImageDependencies);
688695
assert(Splitter->hasMoreSplits());
689696

690697
if (auto Err = Splitter->verifyNoCrossModuleDeviceGlobalUsage()) {

sycl/doc/extensions/experimental/sycl_ext_oneapi_kernel_compiler.asciidoc

Lines changed: 78 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -271,8 +271,8 @@ kernel_bundle<bundle_state::executable> build(
271271

272272
_Constraints:_ Available only when `PropertyListT` is an instance of
273273
`sycl::ext::oneapi::experimental::properties` which contains no properties
274-
other than those listed below in the section "New properties for the `build`
275-
function".
274+
other than those listed below in the section "New properties for the `build` and
275+
`compile` functions".
276276

277277
_Effects (1):_ The source code from `sourceBundle` is translated into one or more
278278
device images of state `bundle_state::executable`, and a new kernel bundle is
@@ -317,6 +317,80 @@ source code used to create the kernel bundle being printed to the terminal.
317317
In situations where this is undesirable, developers must ensure that the
318318
exception is caught and handled appropriately.
319319
_{endnote}_]
320+
321+
a|
322+
[frame=all,grid=none]
323+
!====
324+
a!
325+
[source]
326+
----
327+
namespace sycl::ext::oneapi::experimental {
328+
329+
template<typename PropertyListT = empty_properties_t> (1)
330+
kernel_bundle<bundle_state::object> compile(
331+
const kernel_bundle<bundle_state::ext_oneapi_source>& source,
332+
const std::vector<device>& devs, PropertyListT props={})
333+
334+
template<typename PropertyListT = empty_properties_t> (2)
335+
kernel_bundle<bundle_state::executable> build(
336+
const kernel_bundle<bundle_state::ext_oneapi_source>& sourceBundle,
337+
PropertyListT props = {})
338+
339+
} // namespace sycl::ext::oneapi::experimental
340+
----
341+
!====
342+
343+
344+
_Constraints:_ Available only when `PropertyListT` is an instance of
345+
`sycl::ext::oneapi::experimental::properties` which contains no properties
346+
other than those listed below in the section "New properties for the `build` and
347+
`compile` functions".
348+
349+
_Effects (1):_ The source code from `sourceBundle` is translated into one or
350+
more device images of state `bundle_state::object`, and a new kernel bundle is
351+
created to contain these device images.
352+
The new bundle represents all of the kernels in `sourceBundle` that are
353+
compatible with at least one of the devices in `devs`.
354+
Any remaining kernels (those that are not compatible with any of the devices in
355+
`devs`) are not represented in the new kernel bundle.
356+
357+
The new bundle has the same associated context as `sourceBundle`, and the new
358+
bundle's set of associated devices is `devs` (with duplicate devices removed).
359+
360+
_Effects (2)_: Equivalent to
361+
`compile(sourceBundle, sourceBundle.get_devices(), props)`.
362+
363+
_Returns:_ The newly created kernel bundle, which has `object` state.
364+
365+
_Throws:_
366+
367+
* An `exception` with the `errc::invalid` error code if `source` was not created
368+
with `source_language::sycl` or was the result of `sycl::join` taking one or
369+
more `kernel_bundle` objects not created with `source_language::sycl`.
370+
371+
* An `exception` with the `errc::invalid` error code if any of the devices in
372+
`devs` is not contained by the context associated with `sourceBundle`.
373+
374+
* An `exception` with the `errc::invalid` error code if any of the devices in
375+
`devs` does not support compilation of kernels in the source language of
376+
`sourceBundle`.
377+
378+
* An `exception` with the `errc::invalid` error code if `props` contains an
379+
`options` property that specifies an invalid option.
380+
381+
* An `exception` with the `errc::build` error code if the compilation operation
382+
fails. In this case, the exception `what` string provides a full build log,
383+
including descriptions of any errors, warning messages, and other
384+
diagnostics.
385+
This string is intended for human consumption, and the format may not be
386+
stable across implementations of this extension.
387+
388+
[_Note:_ An uncaught `errc::build` exception may result in some or all of the
389+
source code used to create the kernel bundle being printed to the terminal.
390+
In situations where this is undesirable, developers must ensure that the
391+
exception is caught and handled appropriately.
392+
_{endnote}_]
393+
320394
|====
321395

322396
=== New properties for the `create_kernel_bundle_from_source` function
@@ -384,10 +458,10 @@ _Throws (3):_
384458
entry with `name` in this property.
385459
|====
386460

387-
=== New properties for the `build` function
461+
=== New properties for the `build` and `compile` functions
388462

389463
This extension adds the following properties, which can be used in conjunction
390-
with the `build` function that is defined above:
464+
with the `build` and `compile` function that is defined above:
391465

392466
|====
393467
a|

sycl/include/sycl/kernel_bundle.hpp

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1183,6 +1183,36 @@ build_from_source(kernel_bundle<bundle_state::ext_oneapi_source> &SourceKB,
11831183
}
11841184
return build_from_source(SourceKB, Devices, Options, nullptr, KernelNames);
11851185
}
1186+
1187+
__SYCL_EXPORT kernel_bundle<bundle_state::object> compile_from_source(
1188+
kernel_bundle<bundle_state::ext_oneapi_source> &SourceKB,
1189+
const std::vector<device> &Devices,
1190+
const std::vector<sycl::detail::string_view> &CompileOptions,
1191+
sycl::detail::string *LogPtr,
1192+
const std::vector<sycl::detail::string_view> &RegisteredKernelNames);
1193+
1194+
inline kernel_bundle<bundle_state::object>
1195+
compile_from_source(kernel_bundle<bundle_state::ext_oneapi_source> &SourceKB,
1196+
const std::vector<device> &Devices,
1197+
const std::vector<std::string> &CompileOptions,
1198+
std::string *LogPtr,
1199+
const std::vector<std::string> &RegisteredKernelNames) {
1200+
std::vector<sycl::detail::string_view> Options;
1201+
for (const std::string &opt : CompileOptions)
1202+
Options.push_back(sycl::detail::string_view{opt});
1203+
1204+
std::vector<sycl::detail::string_view> KernelNames;
1205+
for (const std::string &name : RegisteredKernelNames)
1206+
KernelNames.push_back(sycl::detail::string_view{name});
1207+
1208+
sycl::detail::string Log;
1209+
auto result = compile_from_source(SourceKB, Devices, Options,
1210+
LogPtr ? &Log : nullptr, KernelNames);
1211+
if (LogPtr)
1212+
*LogPtr = Log.c_str();
1213+
return result;
1214+
}
1215+
11861216
} // namespace detail
11871217

11881218
/////////////////////////
@@ -1220,6 +1250,39 @@ kernel_bundle<bundle_state::ext_oneapi_source> create_kernel_bundle_from_source(
12201250
}
12211251
#endif
12221252

1253+
/////////////////////////
1254+
// syclex::compile(source_kb) => obj_kb
1255+
/////////////////////////
1256+
1257+
template <typename PropertyListT = empty_properties_t,
1258+
typename = std::enable_if_t<detail::all_are_properties_of_v<
1259+
detail::build_source_bundle_props, PropertyListT>>>
1260+
kernel_bundle<bundle_state::object>
1261+
compile(kernel_bundle<bundle_state::ext_oneapi_source> &SourceKB,
1262+
const std::vector<device> &Devices, PropertyListT props = {}) {
1263+
std::vector<std::string> CompileOptionsVec;
1264+
std::string *LogPtr = nullptr;
1265+
std::vector<std::string> RegisteredKernelNamesVec;
1266+
if constexpr (props.template has_property<build_options>())
1267+
CompileOptionsVec = props.template get_property<build_options>().opts;
1268+
if constexpr (props.template has_property<save_log>())
1269+
LogPtr = props.template get_property<save_log>().log;
1270+
if constexpr (props.template has_property<registered_names>())
1271+
RegisteredKernelNamesVec =
1272+
props.template get_property<registered_names>().names;
1273+
return detail::compile_from_source(SourceKB, Devices, CompileOptionsVec,
1274+
LogPtr, RegisteredKernelNamesVec);
1275+
}
1276+
1277+
template <typename PropertyListT = empty_properties_t,
1278+
typename = std::enable_if_t<detail::all_are_properties_of_v<
1279+
detail::build_source_bundle_props, PropertyListT>>>
1280+
kernel_bundle<bundle_state::object>
1281+
compile(kernel_bundle<bundle_state::ext_oneapi_source> &SourceKB,
1282+
PropertyListT props = {}) {
1283+
return compile<PropertyListT>(SourceKB, SourceKB.get_devices(), props);
1284+
}
1285+
12231286
/////////////////////////
12241287
// syclex::build(source_kb) => exe_kb
12251288
/////////////////////////

0 commit comments

Comments
 (0)