Skip to content

Commit 1537ca2

Browse files
[NFC] Use C++17 fold expressions in detail::CheckDeviceCopyable (#16679)
First, that's what idiomatic C++17 is (folds over recursion), second compile of folds scales much better than recursion when the number of fields/bases grow.
1 parent 2fcddee commit 1537ca2

File tree

2 files changed

+23
-39
lines changed

2 files changed

+23
-39
lines changed

sycl/include/sycl/detail/is_device_copyable.hpp

Lines changed: 19 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -90,30 +90,25 @@ template <typename T>
9090
inline constexpr bool is_device_copyable_v = is_device_copyable<T>::value;
9191
namespace detail {
9292
#ifdef __SYCL_DEVICE_ONLY__
93-
// Checks that the fields of the type T with indices 0 to (NumFieldsToCheck -
94-
// 1) are device copyable.
95-
template <typename T, unsigned NumFieldsToCheck>
96-
struct CheckFieldsAreDeviceCopyable
97-
: CheckFieldsAreDeviceCopyable<T, NumFieldsToCheck - 1> {
98-
using FieldT = decltype(__builtin_field_type(T, NumFieldsToCheck - 1));
99-
static_assert(is_device_copyable_v<FieldT>,
100-
"The specified type is not device copyable");
93+
template <typename T, typename> struct CheckFieldsAreDeviceCopyable;
94+
template <typename T, typename> struct CheckBasesAreDeviceCopyable;
95+
96+
template <typename T, unsigned... FieldIds>
97+
struct CheckFieldsAreDeviceCopyable<T, std::index_sequence<FieldIds...>> {
98+
static_assert(
99+
((is_device_copyable_v<decltype(__builtin_field_type(T, FieldIds))> &&
100+
...)),
101+
"The specified type is not device copyable");
101102
};
102103

103-
template <typename T> struct CheckFieldsAreDeviceCopyable<T, 0> {};
104-
105-
// Checks that the base classes of the type T with indices 0 to
106-
// (NumFieldsToCheck - 1) are device copyable.
107-
template <typename T, unsigned NumBasesToCheck>
108-
struct CheckBasesAreDeviceCopyable
109-
: CheckBasesAreDeviceCopyable<T, NumBasesToCheck - 1> {
110-
using BaseT = decltype(__builtin_base_type(T, NumBasesToCheck - 1));
111-
static_assert(is_device_copyable_v<BaseT>,
112-
"The specified type is not device copyable");
104+
template <typename T, unsigned... BaseIds>
105+
struct CheckBasesAreDeviceCopyable<T, std::index_sequence<BaseIds...>> {
106+
static_assert(
107+
((is_device_copyable_v<decltype(__builtin_base_type(T, BaseIds))> &&
108+
...)),
109+
"The specified type is not device copyable");
113110
};
114111

115-
template <typename T> struct CheckBasesAreDeviceCopyable<T, 0> {};
116-
117112
// All the captures of a lambda or functor of type FuncT passed to a kernel
118113
// must be is_device_copyable, which extends to bases and fields of FuncT.
119114
// Fields are captures of lambda/functors and bases are possible base classes
@@ -127,8 +122,10 @@ template <typename T> struct CheckBasesAreDeviceCopyable<T, 0> {};
127122
// is currently/temporarily supported only to not break older SYCL programs.
128123
template <typename FuncT>
129124
struct CheckDeviceCopyable
130-
: CheckFieldsAreDeviceCopyable<FuncT, __builtin_num_fields(FuncT)>,
131-
CheckBasesAreDeviceCopyable<FuncT, __builtin_num_bases(FuncT)> {};
125+
: CheckFieldsAreDeviceCopyable<
126+
FuncT, std::make_index_sequence<__builtin_num_fields(FuncT)>>,
127+
CheckBasesAreDeviceCopyable<
128+
FuncT, std::make_index_sequence<__builtin_num_bases(FuncT)>> {};
132129

133130
template <typename TransformedArgType, int Dims, typename KernelType>
134131
class RoundedRangeKernel;

sycl/test/basic_tests/is_device_copyable_neg.cpp

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
// RUN: not %clangxx -fsycl -fsycl-device-only -fsyntax-only \
2-
// RUN: %s -I %sycl_include 2>&1 | FileCheck %s
1+
// RUN: %clangxx -fsycl -fsycl-device-only -fsyntax-only -Xclang -verify -Xclang -verify-ignore-unexpected=warning,note %s
32

43
// This test checks if compiler reports compilation error on an attempt to pass
54
// a struct with type that is not device copyable as SYCL kernel parameter.
@@ -57,30 +56,18 @@ void test() {
5756
B IamAlsoBad{0};
5857
marray<B, 2> MarrayForNotCopyable;
5958
queue Q;
59+
// expected-error@*:* {{static assertion failed due to requirement 'is_device_copyable_v<A>': The specified type is not device copyable}}
6060
Q.single_task<class TestA>([=] {
6161
int A = IamBad.i;
6262
int B = IamAlsoBad.i;
6363
int MB = MarrayForNotCopyable[0].i;
6464
});
6565

6666
FunctorA FA;
67+
// expected-error@*:* {{static assertion failed due to requirement 'is_device_copyable_v<C>': The specified type is not device copyable}}
6768
Q.single_task<class TestB>(FA);
6869

6970
FunctorB FB;
71+
// expected-error@*:* {{static assertion failed due to requirement 'is_device_copyable_v<D>': The specified type is not device copyable}}
7072
Q.single_task<class TestC>(FB);
7173
}
72-
73-
// CHECK: static assertion failed due to requirement 'is_device_copyable_v<A>
74-
// CHECK: is_device_copyable_neg.cpp:60:5: note: in instantiation of function
75-
76-
// CHECK: static assertion failed due to requirement 'is_device_copyable_v<B>
77-
// CHECK: is_device_copyable_neg.cpp:60:5: note: in instantiation of function
78-
79-
// CHECK: static assertion failed due to requirement 'is_device_copyable_v<sycl::marray<B, 2>>
80-
// CHECK: is_device_copyable_neg.cpp:60:5: note: in instantiation of function
81-
82-
// CHECK: static assertion failed due to requirement 'is_device_copyable_v<C>
83-
// CHECK: is_device_copyable_neg.cpp:67:5: note: in instantiation of function
84-
85-
// CHECK: static assertion failed due to requirement 'is_device_copyable_v<D>
86-
// CHECK: is_device_copyable_neg.cpp:70:5: note: in instantiation of function

0 commit comments

Comments
 (0)