diff --git a/sycl/include/sycl/ext/oneapi/experimental/detail/properties/launch_config.hpp b/sycl/include/sycl/ext/oneapi/experimental/detail/properties/launch_config.hpp new file mode 100644 index 0000000000000..b733c12cf758a --- /dev/null +++ b/sycl/include/sycl/ext/oneapi/experimental/detail/properties/launch_config.hpp @@ -0,0 +1,96 @@ +//==------ launch_config.hpp ------- SYCL kernel launch configuration -----==// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--------------------------------------------------------------------===// + +#pragma once + +#include +#include + +namespace sycl { +inline namespace _V1 { +template class nd_range; +template class range; + +namespace ext::oneapi::experimental { +namespace detail { +struct AllowCTADTag; +// Trait for identifying sycl::range and sycl::nd_range. +template struct is_range_or_nd_range : std::false_type {}; +template +struct is_range_or_nd_range> : std::true_type {}; +template +struct is_range_or_nd_range> : std::true_type {}; + +template +constexpr bool is_range_or_nd_range_v = is_range_or_nd_range::value; + +template struct LaunchConfigAccess; + +// Checks that none of the properties in the property list has compile-time +// effects on the kernel. +template +struct NoPropertyHasCompileTimeKernelEffect : std::false_type {}; +template +struct NoPropertyHasCompileTimeKernelEffect> { + static constexpr bool value = + !(HasCompileTimeEffect::value || ... || false); +}; +} // namespace detail + +// Available only when Range is range or nd_range +template < + typename RangeT, typename PropertiesT = empty_properties_t, + typename = std::enable_if_t< + ext::oneapi::experimental::detail::is_range_or_nd_range_v>> +class launch_config { + static_assert(ext::oneapi::experimental::detail:: + NoPropertyHasCompileTimeKernelEffect::value, + "launch_config does not allow properties with compile-time " + "kernel effects."); + +public: + launch_config(RangeT Range, PropertiesT Properties = {}) + : MRange{Range}, MProperties{Properties} {} + +private: + RangeT MRange; + PropertiesT MProperties; + + const RangeT &getRange() const noexcept { return MRange; } + + const PropertiesT &getProperties() const noexcept { return MProperties; } + + template + friend struct detail::LaunchConfigAccess; +}; + +#ifdef __cpp_deduction_guides +// CTAD work-around to avoid warning from GCC when using default deduction +// guidance. +launch_config(detail::AllowCTADTag) + -> launch_config; +#endif // __cpp_deduction_guides + +namespace detail { +// Helper for accessing the members of launch_config. +template struct LaunchConfigAccess { + LaunchConfigAccess(const launch_config &LaunchConfig) + : MLaunchConfig{LaunchConfig} {} + + const launch_config &MLaunchConfig; + + const LCRangeT &getRange() const noexcept { return MLaunchConfig.getRange(); } + + const LCPropertiesT &getProperties() const noexcept { + return MLaunchConfig.getProperties(); + } +}; +} // namespace detail +} // namespace ext::oneapi::experimental +} // namespace _V1 +} // namespace sycl diff --git a/sycl/include/sycl/ext/oneapi/experimental/enqueue_functions.hpp b/sycl/include/sycl/ext/oneapi/experimental/enqueue_functions.hpp index ffa071f209580..59f48861ee7f7 100644 --- a/sycl/include/sycl/ext/oneapi/experimental/enqueue_functions.hpp +++ b/sycl/include/sycl/ext/oneapi/experimental/enqueue_functions.hpp @@ -12,10 +12,13 @@ #include #include +#include #include +#include #include #include #include +#include #include #include #include @@ -25,78 +28,6 @@ inline namespace _V1 { namespace ext::oneapi::experimental { namespace detail { -// Trait for identifying sycl::range and sycl::nd_range. -template struct is_range_or_nd_range : std::false_type {}; -template -struct is_range_or_nd_range> : std::true_type {}; -template -struct is_range_or_nd_range> : std::true_type {}; - -template -constexpr bool is_range_or_nd_range_v = is_range_or_nd_range::value; - -template struct LaunchConfigAccess; - -// Checks that none of the properties in the property list has compile-time -// effects on the kernel. -template -struct NoPropertyHasCompileTimeKernelEffect : std::false_type {}; -template -struct NoPropertyHasCompileTimeKernelEffect> { - static constexpr bool value = - !(HasCompileTimeEffect::value || ... || false); -}; -} // namespace detail - -// Available only when Range is range or nd_range -template < - typename RangeT, typename PropertiesT = empty_properties_t, - typename = std::enable_if_t< - ext::oneapi::experimental::detail::is_range_or_nd_range_v>> -class launch_config { - static_assert(ext::oneapi::experimental::detail:: - NoPropertyHasCompileTimeKernelEffect::value, - "launch_config does not allow properties with compile-time " - "kernel effects."); - -public: - launch_config(RangeT Range, PropertiesT Properties = {}) - : MRange{Range}, MProperties{Properties} {} - -private: - RangeT MRange; - PropertiesT MProperties; - - const RangeT &getRange() const noexcept { return MRange; } - - const PropertiesT &getProperties() const noexcept { return MProperties; } - - template - friend struct detail::LaunchConfigAccess; -}; - -#ifdef __cpp_deduction_guides -// CTAD work-around to avoid warning from GCC when using default deduction -// guidance. -launch_config(detail::AllowCTADTag) - -> launch_config; -#endif // __cpp_deduction_guides - -namespace detail { -// Helper for accessing the members of launch_config. -template struct LaunchConfigAccess { - LaunchConfigAccess(const launch_config &LaunchConfig) - : MLaunchConfig{LaunchConfig} {} - - const launch_config &MLaunchConfig; - - const LCRangeT &getRange() const noexcept { return MLaunchConfig.getRange(); } - - const LCPropertiesT &getProperties() const noexcept { - return MLaunchConfig.getProperties(); - } -}; - template void submit_impl(const queue &Q, PropertiesT Props, CommandGroupFunc &&CGF, const sycl::detail::code_location &CodeLoc) { @@ -357,6 +288,75 @@ void nd_launch(queue Q, launch_config, Properties> Config, }); } +// Free function kernel enqueue functions +template +void single_task(queue Q, kernel_function_s KernelFunc, ArgsT &&...Args) { + (void)KernelFunc; + submit(Q, [&](handler &CGH) { + single_task(CGH, KernelFunc, std::forward(Args)...); + }); +} + +template +void single_task(handler &CGH, kernel_function_s KernelFunc, + ArgsT &&...Args) { + (void)KernelFunc; + queue Q = CGH.getQueue(); + sycl::kernel_bundle Bndl = + get_kernel_bundle(Q.get_context()); + sycl::kernel Krn = Bndl.template ext_oneapi_get_kernel(); + CGH.set_args(std::forward(Args)...); + CGH.single_task(Krn); +} + +template +void nd_launch(queue Q, nd_range Range, + kernel_function_s KernelFunc, ArgsT &&...Args) { + (void)KernelFunc; + submit(Q, [&](handler &CGH) { + nd_launch(CGH, Range, KernelFunc, std::forward(Args)...); + }); +} + +template +void nd_launch(handler &CGH, nd_range Range, + kernel_function_s KernelFunc, ArgsT &&...Args) { + (void)KernelFunc; + queue Q = CGH.getQueue(); + sycl::kernel_bundle Bndl = + get_kernel_bundle(Q.get_context()); + sycl::kernel Krn = Bndl.template ext_oneapi_get_kernel(); + + CGH.set_args(std::forward(Args)...); + CGH.parallel_for(Range, Krn); +} + +template +void nd_launch(queue Q, launch_config, Properties> Config, + kernel_function_s KernelFunc, ArgsT &&...Args) { + (void)KernelFunc; + submit(Q, [&](handler &CGH) { + nd_launch(CGH, Config, KernelFunc, std::forward(Args)...); + }); +} + +template +void nd_launch(handler &CGH, + launch_config, Properties> Config, + kernel_function_s KernelFunc, ArgsT &&...Args) { + (void)KernelFunc; + queue Q = CGH.getQueue(); + sycl::kernel_bundle Bndl = + get_kernel_bundle(Q.get_context()); + sycl::kernel Krn = Bndl.template ext_oneapi_get_kernel(); + ext::oneapi::experimental::detail::LaunchConfigAccess, + Properties> + ConfigAccess(Config); + CGH.set_args(std::forward(Args)...); + sycl::detail::HandlerAccess::parallelForImpl( + CGH, ConfigAccess.getRange(), ConfigAccess.getProperties(), Krn); +} + inline void memcpy(handler &CGH, void *Dest, const void *Src, size_t NumBytes) { CGH.memcpy(Dest, Src, NumBytes); } diff --git a/sycl/include/sycl/ext/oneapi/experimental/free_function_traits.hpp b/sycl/include/sycl/ext/oneapi/experimental/free_function_traits.hpp index 2b5d1f4190d21..e0b15593566f3 100644 --- a/sycl/include/sycl/ext/oneapi/experimental/free_function_traits.hpp +++ b/sycl/include/sycl/ext/oneapi/experimental/free_function_traits.hpp @@ -44,6 +44,10 @@ template struct is_kernel { template inline constexpr bool is_kernel_v = is_kernel::value; +template struct kernel_function_s {}; + +template inline constexpr kernel_function_s kernel_function; + } // namespace ext::oneapi::experimental } // namespace _V1 } // namespace sycl diff --git a/sycl/include/sycl/handler.hpp b/sycl/include/sycl/handler.hpp index d8d46d2a27814..0d26620039e90 100644 --- a/sycl/include/sycl/handler.hpp +++ b/sycl/include/sycl/handler.hpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -146,6 +147,15 @@ class pipe; } namespace ext ::oneapi ::experimental { +template struct kernel_function_s; +template +void single_task(handler &, kernel_function_s, Args &&...); +template +void nd_launch(handler &, nd_range, kernel_function_s, + Args &&...); +template +void nd_launch(handler &, launch_config, Properties>, + kernel_function_s, Args &&...); template class work_group_memory; template class dynamic_work_group_memory; struct image_descriptor; @@ -3229,6 +3239,23 @@ class __SYCL_EXPORT handler { friend const decltype(Obj::impl) & sycl::detail::getSyclObjImpl(const Obj &SyclObject); + template + friend void ext::oneapi::experimental::single_task( + handler &, ext::oneapi::experimental::kernel_function_s, + Args &&...); + + template + friend void ext::oneapi::experimental::nd_launch( + handler &, nd_range, + ext::oneapi::experimental::kernel_function_s, Args &&...); + + template + friend void ext::oneapi::experimental::nd_launch( + handler &, + ext::oneapi::experimental::launch_config, + Properties>, + ext::oneapi::experimental::kernel_function_s, Args &&...); + /// Read from a host pipe given a host address and /// \param Name name of the host pipe to be passed into lower level runtime /// \param Ptr host pointer of host pipe as identified by address of its const diff --git a/sycl/include/sycl/sycl.hpp b/sycl/include/sycl/sycl.hpp index ec3708a32cf63..51f99b7f3dd16 100644 --- a/sycl/include/sycl/sycl.hpp +++ b/sycl/include/sycl/sycl.hpp @@ -122,6 +122,7 @@ can be disabled by setting SYCL_DISABLE_FSYCL_SYCLHPP_WARNING macro.") #include #include #include +#include #include #include #include diff --git a/sycl/test-e2e/FreeFunctionKernels/free_function_kernels_enqueue.cpp b/sycl/test-e2e/FreeFunctionKernels/free_function_kernels_enqueue.cpp new file mode 100644 index 0000000000000..957a13c562812 --- /dev/null +++ b/sycl/test-e2e/FreeFunctionKernels/free_function_kernels_enqueue.cpp @@ -0,0 +1,152 @@ +// REQUIRES: aspect-usm_shared_allocations + +// RUN: %{build} -o %t.out +// RUN: %{run} %t.out + +// XFAIL: target-native_cpu +// XFAIL-TRACKER: https://github.com/intel/llvm/issues/20142 + +// This test checks that free function kernels can be submitted using the +// enqueued functions defined in the free function kernel extension, namely the +// single_task and the nd_launch functions that take a queue/handler as an +// argument. These were added in https://github.com/intel/llvm/pull/19995. + +#include +#include +#include +#include +#include +#include + +namespace syclext = sycl::ext::oneapi; +namespace syclexp = sycl::ext::oneapi::experimental; + +SYCL_EXT_ONEAPI_FUNCTION_PROPERTY((syclexp::single_task_kernel)) +void empty() {} + +SYCL_EXT_ONEAPI_FUNCTION_PROPERTY((syclexp::nd_range_kernel<1>)) +void initialize(int *ptr) { + size_t Lid = syclext::this_work_item::get_nd_item<1>().get_local_linear_id(); + ptr[Lid] = Lid; +} + +SYCL_EXT_ONEAPI_FUNCTION_PROPERTY((syclexp::single_task_kernel)) +void successor(int *src, int *dst) { *dst = *src + 1; } + +SYCL_EXT_ONEAPI_FUNCTION_PROPERTY((syclexp::nd_range_kernel<1>)) +void square(int *src, int *dst) { + size_t Lid = syclext::this_work_item::get_nd_item<1>().get_local_linear_id(); + dst[Lid] = src[Lid] * src[Lid]; +} + +template +SYCL_EXT_ONEAPI_FUNCTION_PROPERTY((syclexp::nd_range_kernel<1>)) +void squareWithScratchMemoryTemplated(T *src, T *dst) { + size_t Lid = syclext::this_work_item::get_nd_item<1>().get_local_linear_id(); + T *LocalMem = reinterpret_cast(syclexp::get_work_group_scratch_memory()); + LocalMem[Lid] = src[Lid] * src[Lid]; + dst[Lid] = LocalMem[Lid]; +} + +constexpr int SIZE = 16; + +int main() { + sycl::queue Q; + int *Src = sycl::malloc_shared(SIZE, Q); + int *Dst = sycl::malloc_shared(SIZE, Q); + + syclexp::single_task(Q, syclexp::kernel_function_s{}); + + syclexp::nd_launch( + Q, ::sycl::nd_range<1>(::sycl::range<1>(SIZE), ::sycl::range<1>(SIZE)), + syclexp::kernel_function, Src); + + syclexp::launch_config Config{ + ::sycl::nd_range<1>(::sycl::range<1>(SIZE), ::sycl::range<1>(SIZE)), + syclexp::properties{ + syclexp::work_group_scratch_size(SIZE * sizeof(int))}}; + + static_assert( + std::is_same_v< + decltype(syclexp::nd_launch( + Q, Config, + syclexp::kernel_function>, + Src, Dst)), + void>); + + syclexp::nd_launch( + Q, Config, + syclexp::kernel_function>, Src, + Dst); + Q.wait(); + + for (int I = 0; I < SIZE; I++) { + assert(Dst[I] == Src[I] * Src[I]); + } + + syclexp::nd_launch( + Q, ::sycl::nd_range<1>(::sycl::range<1>(SIZE), ::sycl::range<1>(SIZE)), + syclexp::kernel_function, Src, Dst); + Q.wait(); + + for (int I = 0; I < SIZE; I++) { + assert(Dst[I] == Src[I] * Src[I]); + } + + static_assert( + std::is_same_v, Src, Dst)), + void>); + syclexp::single_task(Q, syclexp::kernel_function, Src, Dst); + Q.wait(); + + assert(Dst[0] == Src[0] + 1); + + Q.submit([&](sycl::handler &CGH) { + static_assert( + std::is_same_v>, + Src, Dst)), + void>); + syclexp::nd_launch( + CGH, Config, + syclexp::kernel_function>, Src, + Dst); + }).wait(); + + for (int I = 0; I < SIZE; I++) { + assert(Dst[I] == Src[I] * Src[I]); + } + + Q.submit([&](sycl::handler &CGH) { + static_assert( + std::is_same_v(::sycl::range<1>(SIZE), + ::sycl::range<1>(SIZE)), + syclexp::kernel_function, Src, Dst)), + void>); + + syclexp::nd_launch( + CGH, + ::sycl::nd_range<1>(::sycl::range<1>(SIZE), ::sycl::range<1>(SIZE)), + syclexp::kernel_function, Src, Dst); + }).wait(); + + for (int I = 0; I < SIZE; I++) { + assert(Dst[I] == Src[I] * Src[I]); + } + + Q.submit([&](sycl::handler &CGH) { + static_assert(std::is_same_v, + Src, Dst)), + void>); + syclexp::single_task(CGH, syclexp::kernel_function, Src, Dst); + }).wait(); + + assert(Dst[0] == Src[0] + 1); + return 0; +} diff --git a/sycl/test/extensions/properties/kernel_properties_negative.cpp b/sycl/test/extensions/properties/kernel_properties_negative.cpp index 90010dd48d278..c15959d581f37 100644 --- a/sycl/test/extensions/properties/kernel_properties_negative.cpp +++ b/sycl/test/extensions/properties/kernel_properties_negative.cpp @@ -17,9 +17,9 @@ int main() { oneapi::work_group_progress}; - // expected-error-re@sycl/ext/oneapi/experimental/enqueue_functions.hpp:* {{static assertion failed due to requirement {{.*}} launch_config does not allow properties with compile-time kernel effects.}} + // expected-error-re@sycl/ext/oneapi/experimental/detail/properties/launch_config.hpp:* {{static assertion failed due to requirement {{.*}} launch_config does not allow properties with compile-time kernel effects.}} oneapi::launch_config LC1{sycl::range<1>{1}, props1}; - // expected-error-re@sycl/ext/oneapi/experimental/enqueue_functions.hpp:* {{static assertion failed due to requirement {{.*}} launch_config does not allow properties with compile-time kernel effects.}} + // expected-error-re@sycl/ext/oneapi/experimental/detail/properties/launch_config.hpp:* {{static assertion failed due to requirement {{.*}} launch_config does not allow properties with compile-time kernel effects.}} oneapi::launch_config LC22{sycl::range<1>{1}, props2}; } diff --git a/sycl/test/include_deps/sycl_detail_core.hpp.cpp b/sycl/test/include_deps/sycl_detail_core.hpp.cpp index 5174c8a29bb6b..9da96a56acc10 100644 --- a/sycl/test/include_deps/sycl_detail_core.hpp.cpp +++ b/sycl/test/include_deps/sycl_detail_core.hpp.cpp @@ -148,6 +148,7 @@ // CHECK-NEXT: ext/oneapi/bindless_images_interop.hpp // CHECK-NEXT: ext/oneapi/interop_common.hpp // CHECK-NEXT: ext/oneapi/bindless_images_mem_handle.hpp +// CHECK-NEXT: ext/oneapi/experimental/detail/properties/launch_config.hpp // CHECK-NEXT: ext/oneapi/experimental/raw_kernel_arg.hpp // CHECK-NEXT: kernel.hpp // CHECK-NEXT: sampler.hpp diff --git a/sycl/test/include_deps/sycl_khr_includes_handler.hpp.cpp b/sycl/test/include_deps/sycl_khr_includes_handler.hpp.cpp index 862394bd4f656..bc7cb888af2df 100644 --- a/sycl/test/include_deps/sycl_khr_includes_handler.hpp.cpp +++ b/sycl/test/include_deps/sycl_khr_includes_handler.hpp.cpp @@ -146,6 +146,7 @@ // CHECK-NEXT: ext/oneapi/bindless_images_mem_handle.hpp // CHECK-NEXT: ext/oneapi/device_global/device_global.hpp // CHECK-NEXT: ext/oneapi/device_global/properties.hpp +// CHECK-NEXT: ext/oneapi/experimental/detail/properties/launch_config.hpp // CHECK-NEXT: ext/oneapi/experimental/raw_kernel_arg.hpp // CHECK-NEXT: kernel.hpp // CHECK-NEXT: sampler.hpp diff --git a/sycl/test/include_deps/sycl_khr_includes_kernel_bundle.hpp.cpp b/sycl/test/include_deps/sycl_khr_includes_kernel_bundle.hpp.cpp index 7f606a58d8a68..b328c185cd079 100644 --- a/sycl/test/include_deps/sycl_khr_includes_kernel_bundle.hpp.cpp +++ b/sycl/test/include_deps/sycl_khr_includes_kernel_bundle.hpp.cpp @@ -148,6 +148,7 @@ // CHECK-NEXT: ext/oneapi/bindless_images_mem_handle.hpp // CHECK-NEXT: ext/oneapi/device_global/device_global.hpp // CHECK-NEXT: ext/oneapi/device_global/properties.hpp +// CHECK-NEXT: ext/oneapi/experimental/detail/properties/launch_config.hpp // CHECK-NEXT: ext/oneapi/experimental/raw_kernel_arg.hpp // CHECK-NEXT: sampler.hpp // CHECK-NEXT: sycl_span.hpp diff --git a/sycl/test/include_deps/sycl_khr_includes_queue.hpp.cpp b/sycl/test/include_deps/sycl_khr_includes_queue.hpp.cpp index 76570a99bdda7..0dd336f1d9c3b 100644 --- a/sycl/test/include_deps/sycl_khr_includes_queue.hpp.cpp +++ b/sycl/test/include_deps/sycl_khr_includes_queue.hpp.cpp @@ -152,6 +152,7 @@ // CHECK-NEXT: ext/oneapi/bindless_images_interop.hpp // CHECK-NEXT: ext/oneapi/interop_common.hpp // CHECK-NEXT: ext/oneapi/bindless_images_mem_handle.hpp +// CHECK-NEXT: ext/oneapi/experimental/detail/properties/launch_config.hpp // CHECK-NEXT: ext/oneapi/experimental/raw_kernel_arg.hpp // CHECK-NEXT: kernel.hpp // CHECK-NEXT: sampler.hpp diff --git a/sycl/test/include_deps/sycl_khr_includes_reduction.hpp.cpp b/sycl/test/include_deps/sycl_khr_includes_reduction.hpp.cpp index 50abdf954cca0..c50e7c119eeaf 100644 --- a/sycl/test/include_deps/sycl_khr_includes_reduction.hpp.cpp +++ b/sycl/test/include_deps/sycl_khr_includes_reduction.hpp.cpp @@ -176,6 +176,7 @@ // CHECK-NEXT: ext/oneapi/bindless_images_mem_handle.hpp // CHECK-NEXT: ext/oneapi/device_global/device_global.hpp // CHECK-NEXT: ext/oneapi/device_global/properties.hpp +// CHECK-NEXT: ext/oneapi/experimental/detail/properties/launch_config.hpp // CHECK-NEXT: ext/oneapi/experimental/raw_kernel_arg.hpp // CHECK-NEXT: kernel.hpp // CHECK-NEXT: sampler.hpp diff --git a/sycl/test/include_deps/sycl_khr_includes_stream.hpp.cpp b/sycl/test/include_deps/sycl_khr_includes_stream.hpp.cpp index efaf1605c801f..75c674bfbff24 100644 --- a/sycl/test/include_deps/sycl_khr_includes_stream.hpp.cpp +++ b/sycl/test/include_deps/sycl_khr_includes_stream.hpp.cpp @@ -165,6 +165,7 @@ // CHECK-NEXT: ext/oneapi/bindless_images_mem_handle.hpp // CHECK-NEXT: ext/oneapi/device_global/device_global.hpp // CHECK-NEXT: ext/oneapi/device_global/properties.hpp +// CHECK-NEXT: ext/oneapi/experimental/detail/properties/launch_config.hpp // CHECK-NEXT: ext/oneapi/experimental/raw_kernel_arg.hpp // CHECK-NEXT: kernel.hpp // CHECK-NEXT: sampler.hpp diff --git a/sycl/test/include_deps/sycl_khr_includes_usm.hpp.cpp b/sycl/test/include_deps/sycl_khr_includes_usm.hpp.cpp index f2feef5bd9871..713b6daa2c5ba 100644 --- a/sycl/test/include_deps/sycl_khr_includes_usm.hpp.cpp +++ b/sycl/test/include_deps/sycl_khr_includes_usm.hpp.cpp @@ -167,6 +167,7 @@ // CHECK-NEXT: ext/oneapi/bindless_images_interop.hpp // CHECK-NEXT: ext/oneapi/interop_common.hpp // CHECK-NEXT: ext/oneapi/bindless_images_mem_handle.hpp +// CHECK-NEXT: ext/oneapi/experimental/detail/properties/launch_config.hpp // CHECK-NEXT: ext/oneapi/experimental/raw_kernel_arg.hpp // CHECK-NEXT: kernel.hpp // CHECK-NEXT: sampler.hpp