Skip to content

Commit 7c7efee

Browse files
[SYCL][Reduction] Make reducer uncopyable and immovable (#8654)
According to the SYCL 2020 specification, the reducer class should be neither moveable nor copyable. This commit deletes these constructors and assignment operators. Fixes #6065 --------- Signed-off-by: Larsen, Steffen <steffen.larsen@intel.com>
1 parent 27e5e55 commit 7c7efee

File tree

3 files changed

+354
-2
lines changed

3 files changed

+354
-2
lines changed

sycl/include/sycl/reduction.hpp

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,13 @@ class ReductionIdentityContainer<
422422
static constexpr bool has_identity = false;
423423
};
424424

425+
// Token class to help with the in-place construction of reducers.
426+
template <class BinaryOperation, typename IdentityContainerT>
427+
struct ReducerToken {
428+
const IdentityContainerT &IdentityContainer;
429+
const BinaryOperation BOp;
430+
};
431+
425432
} // namespace detail
426433

427434
/// Specialization of the generic class 'reducer'. It is used for reductions
@@ -458,6 +465,14 @@ class reducer<
458465
reducer(const IdentityContainerT &IdentityContainer, BinaryOperation BOp)
459466
: MValue(GetInitialValue(IdentityContainer)),
460467
MIdentity(IdentityContainer), MBinaryOp(BOp) {}
468+
reducer(
469+
const detail::ReducerToken<BinaryOperation, IdentityContainerT> &Token)
470+
: reducer(Token.IdentityContainer, Token.BOp) {}
471+
472+
reducer(const reducer &) = delete;
473+
reducer(reducer &&) = delete;
474+
reducer &operator=(const reducer &) = delete;
475+
reducer &operator=(reducer &&) = delete;
461476

462477
reducer &combine(const T &Partial) {
463478
if constexpr (has_identity)
@@ -515,6 +530,14 @@ class reducer<
515530
reducer() : MValue(getIdentity()) {}
516531
reducer(const IdentityContainerT & /* Identity */, BinaryOperation)
517532
: MValue(getIdentity()) {}
533+
reducer(
534+
const detail::ReducerToken<BinaryOperation, IdentityContainerT> &Token)
535+
: reducer(Token.IdentityContainer, Token.BOp) {}
536+
537+
reducer(const reducer &) = delete;
538+
reducer(reducer &&) = delete;
539+
reducer &operator=(const reducer &) = delete;
540+
reducer &operator=(reducer &&) = delete;
518541

519542
reducer &combine(const T &Partial) {
520543
BinaryOperation BOp;
@@ -553,6 +576,14 @@ class reducer<T, BinaryOperation, Dims, Extent, IdentityContainerT, View,
553576
public:
554577
reducer(internal_value_type &Ref, BinaryOperation BOp)
555578
: MElement(Ref), MBinaryOp(BOp) {}
579+
reducer(
580+
const detail::ReducerToken<BinaryOperation, IdentityContainerT> &Token)
581+
: reducer(Token.IdentityContainer, Token.BOp) {}
582+
583+
reducer(const reducer &) = delete;
584+
reducer(reducer &&) = delete;
585+
reducer &operator=(const reducer &) = delete;
586+
reducer &operator=(reducer &&) = delete;
556587

557588
reducer &combine(const T &Partial) {
558589
if constexpr (has_identity)
@@ -599,6 +630,14 @@ class reducer<
599630
reducer(const IdentityContainerT &IdentityContainer, BinaryOperation BOp)
600631
: MValue(GetInitialValue(IdentityContainer)),
601632
MIdentity(IdentityContainer), MBinaryOp(BOp) {}
633+
reducer(
634+
const detail::ReducerToken<BinaryOperation, IdentityContainerT> &Token)
635+
: reducer(Token.IdentityContainer, Token.BOp) {}
636+
637+
reducer(const reducer &) = delete;
638+
reducer(reducer &&) = delete;
639+
reducer &operator=(const reducer &) = delete;
640+
reducer &operator=(reducer &&) = delete;
602641

603642
reducer<T, BinaryOperation, Dims - 1, Extent, IdentityContainerT, true>
604643
operator[](size_t Index) {
@@ -650,6 +689,14 @@ class reducer<
650689
reducer() : MValue(getIdentity()) {}
651690
reducer(const IdentityContainerT & /* Identity */, BinaryOperation)
652691
: MValue(getIdentity()) {}
692+
reducer(
693+
const detail::ReducerToken<BinaryOperation, IdentityContainerT> &Token)
694+
: reducer(Token.IdentityContainer, Token.BOp) {}
695+
696+
reducer(const reducer &) = delete;
697+
reducer(reducer &&) = delete;
698+
reducer &operator=(const reducer &) = delete;
699+
reducer &operator=(reducer &&) = delete;
653700

654701
// SYCL 2020 revision 4 says this should be const, but this is a bug
655702
// see https://github.com/KhronosGroup/SYCL-Docs/pull/252
@@ -746,6 +793,8 @@ class reduction_impl_algo {
746793

747794
using identity_container_type =
748795
ReductionIdentityContainer<T, BinaryOperation, ExplicitIdentity>;
796+
using reducer_token_type =
797+
detail::ReducerToken<BinaryOperation, identity_container_type>;
749798
using reducer_type =
750799
reducer<T, BinaryOperation, Dims, Extent, identity_container_type>;
751800
using result_type = T;
@@ -2062,8 +2111,11 @@ void reduCGFuncMulti(handler &CGH, KernelType KernelFunc,
20622111
// Pass all reductions to user's lambda in the same order as supplied
20632112
// Each reducer initializes its own storage
20642113
auto ReduIndices = std::index_sequence_for<Reductions...>();
2065-
auto ReducersTuple = std::tuple{typename Reductions::reducer_type{
2066-
std::get<Is>(IdentitiesTuple), std::get<Is>(BOPsTuple)}...};
2114+
auto ReducerTokensTuple =
2115+
std::tuple{typename Reductions::reducer_token_type{
2116+
std::get<Is>(IdentitiesTuple), std::get<Is>(BOPsTuple)}...};
2117+
auto ReducersTuple = std::tuple<typename Reductions::reducer_type...>{
2118+
std::get<Is>(ReducerTokensTuple)...};
20672119
std::apply([&](auto &...Reducers) { KernelFunc(NDIt, Reducers...); },
20682120
ReducersTuple);
20692121

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
// RUN: %clangxx -fsycl -fsyntax-only %s
2+
3+
// Tests that the reducer class is neither movable nor copyable.
4+
5+
#include <sycl/sycl.hpp>
6+
7+
#include <type_traits>
8+
9+
template <class T> struct PlusWithoutIdentity {
10+
T operator()(const T &A, const T &B) const { return A + B; }
11+
};
12+
13+
template <typename ReducerT> static constexpr void checkReducer() {
14+
static_assert(!std::is_copy_constructible_v<ReducerT>);
15+
static_assert(!std::is_move_constructible_v<ReducerT>);
16+
static_assert(!std::is_copy_assignable_v<ReducerT>);
17+
static_assert(!std::is_move_assignable_v<ReducerT>);
18+
}
19+
20+
int main() {
21+
sycl::queue Q;
22+
23+
int *ScalarMem = sycl::malloc_shared<int>(1, Q);
24+
int *SpanMem = sycl::malloc_shared<int>(8, Q);
25+
auto ScalarRed1 = sycl::reduction(ScalarMem, std::plus<int>{});
26+
auto ScalarRed2 = sycl::reduction(ScalarMem, PlusWithoutIdentity<int>{});
27+
auto SpanRed1 =
28+
sycl::reduction(sycl::span<int, 8>{SpanMem, 8}, std::plus<int>{});
29+
auto SpanRed2 = sycl::reduction(sycl::span<int, 8>{SpanMem, 8},
30+
PlusWithoutIdentity<int>{});
31+
32+
Q.parallel_for(sycl::range<1>{1024}, ScalarRed1,
33+
[=](sycl::item<1>, auto &Reducer) {
34+
checkReducer<std::remove_reference_t<decltype(Reducer)>>();
35+
});
36+
37+
Q.parallel_for(sycl::nd_range<1>{1024, 1024}, ScalarRed1,
38+
[=](sycl::nd_item<1>, auto &Reducer) {
39+
checkReducer<std::remove_reference_t<decltype(Reducer)>>();
40+
});
41+
42+
Q.parallel_for(sycl::range<1>{1024}, ScalarRed2,
43+
[=](sycl::item<1>, auto &Reducer) {
44+
checkReducer<std::remove_reference_t<decltype(Reducer)>>();
45+
});
46+
47+
Q.parallel_for(sycl::nd_range<1>{1024, 1024}, ScalarRed2,
48+
[=](sycl::nd_item<1>, auto &Reducer) {
49+
checkReducer<std::remove_reference_t<decltype(Reducer)>>();
50+
});
51+
52+
Q.parallel_for(
53+
sycl::range<1>{1024}, SpanRed1, [=](sycl::item<1>, auto &Reducer) {
54+
checkReducer<std::remove_reference_t<decltype(Reducer)>>();
55+
checkReducer<std::remove_reference_t<decltype(Reducer[0])>>();
56+
});
57+
58+
Q.parallel_for(
59+
sycl::nd_range<1>{1024, 1024}, SpanRed1,
60+
[=](sycl::nd_item<1>, auto &Reducer) {
61+
checkReducer<std::remove_reference_t<decltype(Reducer)>>();
62+
checkReducer<std::remove_reference_t<decltype(Reducer[0])>>();
63+
});
64+
65+
Q.parallel_for(
66+
sycl::range<1>{1024}, SpanRed2, [=](sycl::item<1>, auto &Reducer) {
67+
checkReducer<std::remove_reference_t<decltype(Reducer)>>();
68+
checkReducer<std::remove_reference_t<decltype(Reducer[0])>>();
69+
});
70+
71+
Q.parallel_for(
72+
sycl::nd_range<1>{1024, 1024}, SpanRed2,
73+
[=](sycl::nd_item<1>, auto &Reducer) {
74+
checkReducer<std::remove_reference_t<decltype(Reducer)>>();
75+
checkReducer<std::remove_reference_t<decltype(Reducer[0])>>();
76+
});
77+
78+
return 0;
79+
}

0 commit comments

Comments
 (0)