DPC++ Runtime
Runtime libraries for oneAPI DPC++
is_device_copyable.hpp
Go to the documentation of this file.
1 //==------------ is_device_copyable.hpp - ----------------------------------==//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 #pragma once
9 
11 
12 #include <array>
13 #include <optional>
14 #include <type_traits>
15 #include <variant>
16 
20 #define SYCL_DEVICE_COPYABLE 1
21 
22 namespace sycl {
23 inline namespace _V1 {
31 template <typename T> struct is_device_copyable;
32 
33 namespace detail {
34 template <typename T, typename = void>
35 struct is_device_copyable_impl : std::is_trivially_copyable<T> {};
36 
37 template <typename T>
39  T, std::enable_if_t<!std::is_same_v<T, std::remove_cv_t<T>>>>
40  // Cannot express this "recursion" (to take user's partial non-cv
41  // specializations into account) without this helper struct.
42  : is_device_copyable<std::remove_cv_t<T>> {};
43 } // namespace detail
44 
45 template <typename T>
47 
48 // std::array<T, 0> is implicitly device copyable type.
49 template <typename T>
50 struct is_device_copyable<std::array<T, 0>> : std::true_type {};
51 
52 // std::array<T, N> is implicitly device copyable type if T is device copyable.
53 template <typename T, std::size_t N>
54 struct is_device_copyable<std::array<T, N>> : is_device_copyable<T> {};
55 
56 // std::optional<T> is implicitly device copyable type if T is device copyable.
57 template <typename T>
58 struct is_device_copyable<std::optional<T>> : is_device_copyable<T> {};
59 
60 // std::pair<T1, T2> is implicitly device copyable type if T1 and T2 are device
61 // copyable.
62 template <typename T1, typename T2>
63 struct is_device_copyable<std::pair<T1, T2>>
64  : std::bool_constant<is_device_copyable<T1>::value &&
65  is_device_copyable<T2>::value> {};
66 
67 // std::tuple<Ts...> is implicitly device copyable type if each type T of Ts...
68 // is device copyable.
69 template <typename... Ts>
70 struct is_device_copyable<std::tuple<Ts...>>
71  : std::bool_constant<(... && is_device_copyable<Ts>::value)> {};
72 
73 // std::variant<Ts...> is implicitly device copyable type if each type T of
74 // Ts... is device copyable.
75 template <typename... Ts>
76 struct is_device_copyable<std::variant<Ts...>>
77  : std::bool_constant<(... && is_device_copyable<Ts>::value)> {};
78 
79 // array is device copyable if element type is device copyable.
80 template <typename T, std::size_t N>
82 
83 template <typename T>
85 namespace detail {
86 template <typename T, typename = void>
87 struct IsDeprecatedDeviceCopyable : std::false_type {};
88 
89 // TODO: using C++ attribute [[deprecated]] or the macro __SYCL2020_DEPRECATED
90 // does not produce expected warning message for the type 'T'.
91 template <typename T>
92 struct __SYCL2020_DEPRECATED("This type isn't device copyable in SYCL 2020")
94  T, std::enable_if_t<std::is_trivially_copy_constructible_v<T> &&
95  std::is_trivially_destructible_v<T> &&
96  !is_device_copyable_v<T>>> : std::true_type {};
97 
98 template <typename T, int N>
99 struct __SYCL2020_DEPRECATED("This type isn't device copyable in SYCL 2020")
100  IsDeprecatedDeviceCopyable<T[N]> : IsDeprecatedDeviceCopyable<T> {};
101 
102 #ifdef __SYCL_DEVICE_ONLY__
103 // Checks that the fields of the type T with indices 0 to (NumFieldsToCheck -
104 // 1) are device copyable.
105 template <typename T, unsigned NumFieldsToCheck>
106 struct CheckFieldsAreDeviceCopyable
107  : CheckFieldsAreDeviceCopyable<T, NumFieldsToCheck - 1> {
108  using FieldT = decltype(__builtin_field_type(T, NumFieldsToCheck - 1));
109  static_assert(is_device_copyable_v<FieldT> ||
110  detail::IsDeprecatedDeviceCopyable<FieldT>::value,
111  "The specified type is not device copyable");
112 };
113 
114 template <typename T> struct CheckFieldsAreDeviceCopyable<T, 0> {};
115 
116 // Checks that the base classes of the type T with indices 0 to
117 // (NumFieldsToCheck - 1) are device copyable.
118 template <typename T, unsigned NumBasesToCheck>
119 struct CheckBasesAreDeviceCopyable
120  : CheckBasesAreDeviceCopyable<T, NumBasesToCheck - 1> {
121  using BaseT = decltype(__builtin_base_type(T, NumBasesToCheck - 1));
122  static_assert(is_device_copyable_v<BaseT> ||
123  detail::IsDeprecatedDeviceCopyable<BaseT>::value,
124  "The specified type is not device copyable");
125 };
126 
127 template <typename T> struct CheckBasesAreDeviceCopyable<T, 0> {};
128 
129 // All the captures of a lambda or functor of type FuncT passed to a kernel
130 // must be is_device_copyable, which extends to bases and fields of FuncT.
131 // Fields are captures of lambda/functors and bases are possible base classes
132 // of functors also allowed by SYCL.
133 // The SYCL-2020 implementation must check each of the fields & bases of the
134 // type FuncT, only one level deep, which is enough to see if they are all
135 // device copyable by using the result of is_device_copyable returned for them.
136 // At this moment though the check also allowes using types for which
137 // (is_trivially_copy_constructible && is_trivially_destructible) returns true
138 // and (is_device_copyable) returns false. That is the deprecated behavior and
139 // is currently/temporarily supported only to not break older SYCL programs.
140 template <typename FuncT>
141 struct CheckDeviceCopyable
142  : CheckFieldsAreDeviceCopyable<FuncT, __builtin_num_fields(FuncT)>,
143  CheckBasesAreDeviceCopyable<FuncT, __builtin_num_bases(FuncT)> {};
144 
145 template <typename TransformedArgType, int Dims, typename KernelType>
146 class RoundedRangeKernel;
147 template <typename TransformedArgType, int Dims, typename KernelType>
148 class RoundedRangeKernelWithKH;
149 
150 // Below are two specializations for CheckDeviceCopyable when a kernel lambda
151 // is wrapped after range rounding optimization.
152 template <typename TransformedArgType, int Dims, typename KernelType>
153 struct CheckDeviceCopyable<
154  RoundedRangeKernel<TransformedArgType, Dims, KernelType>>
155  : CheckDeviceCopyable<KernelType> {};
156 
157 template <typename TransformedArgType, int Dims, typename KernelType>
158 struct CheckDeviceCopyable<
159  RoundedRangeKernelWithKH<TransformedArgType, Dims, KernelType>>
160  : CheckDeviceCopyable<KernelType> {};
161 
162 #endif // __SYCL_DEVICE_ONLY__
163 } // namespace detail
164 } // namespace _V1
165 } // namespace sycl
The SYCL device class encapsulates a single SYCL device on which kernels may be executed.
Definition: device.hpp:64
signed char __SYCL2020_DEPRECATED
Definition: aliases.hpp:94
constexpr bool is_device_copyable_v
Definition: access.hpp:18
is_device_copyable is a user specializable class template to indicate that a type T is device copyabl...