DPC++ Runtime
Runtime libraries for oneAPI DPC++
group_algorithm.hpp
Go to the documentation of this file.
1 //==------------------------ group_algorithm.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 
9 #pragma once
10 
11 #include <sycl/detail/array.hpp> // for array
12 #include <sycl/detail/helpers.hpp> // for loop
13 #include <sycl/detail/item_base.hpp> // for id, range
14 #include <sycl/detail/type_list.hpp> // for is_contained, type_list
15 #include <sycl/detail/type_traits.hpp> // for remove_pointer, is_pointer
16 #include <sycl/exception.hpp> // for make_error_code, errc, exception
17 #include <sycl/functional.hpp> // for plus, multiplies, maximum
18 #include <sycl/group.hpp> // for group
19 #include <sycl/half_type.hpp> // for half
20 #include <sycl/id.hpp> // for id
21 #include <sycl/known_identity.hpp> // for known_identity_v
22 #include <sycl/nd_item.hpp> // for nd_item
23 #include <sycl/range.hpp> // for range
24 #include <sycl/sub_group.hpp> // for sub_group
25 #include <sycl/types.hpp> // for vec
26 
27 #ifdef __SYCL_DEVICE_ONLY__
29 #if defined(__NVPTX__)
32 #endif
33 #endif
34 
35 #include <stddef.h> // for size_t
36 #include <type_traits> // for enable_if_t, decay_t, integra...
37 
38 namespace sycl {
39 inline namespace _V1 {
40 namespace detail {
41 
42 // ---- linear_id_to_id
43 template <int Dimensions>
45 template <> inline id<1> linear_id_to_id(range<1>, size_t linear_id) {
46  return id<1>(linear_id);
47 }
48 template <> inline id<2> linear_id_to_id(range<2> r, size_t linear_id) {
49  id<2> result;
50  result[0] = linear_id / r[1];
51  result[1] = linear_id % r[1];
52  return result;
53 }
54 template <> inline id<3> linear_id_to_id(range<3> r, size_t linear_id) {
55  id<3> result;
56  result[0] = linear_id / (r[1] * r[2]);
57  result[1] = (linear_id % (r[1] * r[2])) / r[2];
58  result[2] = linear_id % r[2];
59  return result;
60 }
61 
62 // ---- get_local_linear_range
63 template <typename Group> inline auto get_local_linear_range(Group g) {
64  auto local_range = g.get_local_range();
65  auto result = local_range[0];
66  for (size_t i = 1; i < Group::dimensions; ++i)
67  result *= local_range[i];
68  return result;
69 }
70 
71 // ---- get_local_linear_id
72 template <typename Group> inline auto get_local_linear_id(Group g) {
73 #ifdef __SYCL_DEVICE_ONLY__
74  if constexpr (std::is_same_v<Group, group<1>> ||
75  std::is_same_v<Group, group<2>> ||
76  std::is_same_v<Group, group<3>>) {
77  auto it = sycl::detail::Builder::getNDItem<Group::dimensions>();
78  return it.get_local_linear_id();
79  }
80 #endif // __SYCL_DEVICE_ONLY__
81  return g.get_local_linear_id();
82 }
83 
84 // ---- is_native_op
85 template <typename T>
90 
91 template <typename T, typename BinaryOperation> struct is_native_op {
92  static constexpr bool value =
93  is_contained<BinaryOperation,
95  is_contained<BinaryOperation,
98 };
99 
100 // ---- is_plus
101 template <typename T, typename BinaryOperation>
102 using is_plus = std::integral_constant<
103  bool,
104  std::is_same_v<BinaryOperation, sycl::plus<std::remove_const_t<T>>> ||
105  std::is_same_v<BinaryOperation, sycl::plus<std::add_const_t<T>>> ||
106  std::is_same_v<BinaryOperation, sycl::plus<void>>>;
107 
108 // ---- is_multiplies
109 template <typename T, typename BinaryOperation>
110 using is_multiplies = std::integral_constant<
111  bool,
112  std::is_same_v<BinaryOperation, sycl::multiplies<std::remove_const_t<T>>> ||
113  std::is_same_v<BinaryOperation,
115  std::is_same_v<BinaryOperation, sycl::multiplies<void>>>;
116 
117 // ---- is_complex
118 // Use SFINAE so that the "true" branch could be implemented in
119 // include/sycl/stl_wrappers/complex that would only be available if STL's
120 // <complex> is included by users.
121 template <typename T, typename = void>
122 struct is_complex : public std::false_type {};
123 
124 // ---- is_arithmetic_or_complex
125 template <typename T>
127  std::integral_constant<bool, sycl::detail::is_complex<T>::value ||
128  sycl::detail::is_arithmetic<T>::value>;
129 
130 template <typename T>
132  : std::bool_constant<is_vec<T>::value &&
133  (is_arithmetic<T>::value ||
134  is_complex<vector_element_t<T>>::value)> {};
135 
136 // ---- is_plus_or_multiplies_if_complex
137 template <typename T, typename BinaryOperation>
138 using is_plus_or_multiplies_if_complex = std::integral_constant<
141  : std::true_type::value)>;
142 
143 // used to transform a vector op to a scalar op;
144 // e.g. sycl::plus<std::vec<T, N>> to sycl::plus<T>
145 template <typename T> struct get_scalar_binary_op;
146 
147 template <template <typename> typename F, typename T, int n>
148 struct get_scalar_binary_op<F<sycl::vec<T, n>>> {
149  using type = F<T>;
150 };
151 
152 template <template <typename> typename F> struct get_scalar_binary_op<F<void>> {
153  using type = F<void>;
154 };
155 
156 // ---- is_max_or_min
157 template <typename T> struct is_max_or_min : std::false_type {};
158 template <typename T>
159 struct is_max_or_min<sycl::maximum<T>> : std::true_type {};
160 template <typename T>
161 struct is_max_or_min<sycl::minimum<T>> : std::true_type {};
162 
163 // ---- identity_for_ga_op
164 // the group algorithms support std::complex, limited to sycl::plus operation
165 // get the correct identity for group algorithm operation.
166 // TODO: identiy_for_ga_op should be replaced with known_identity once the other
167 // callers of known_identity support complex numbers.
168 template <typename T, class BinaryOperation>
169 constexpr std::enable_if_t<
172  return {0, 0};
173 }
174 
175 template <typename T, class BinaryOperation>
176 constexpr std::enable_if_t<
177  (is_complex<T>::value && is_multiplies<T, BinaryOperation>::value), T>
179  return {1, 0};
180 }
181 
182 template <typename T, class BinaryOperation>
183 constexpr std::enable_if_t<!is_complex<T>::value, T> identity_for_ga_op() {
184  return sycl::known_identity_v<BinaryOperation, T>;
185 }
186 
187 // ---- for_each
188 template <typename Group, typename Ptr, class Function>
189 Function for_each(Group g, Ptr first, Ptr last, Function f) {
190 #ifdef __SYCL_DEVICE_ONLY__
191  ptrdiff_t offset = sycl::detail::get_local_linear_id(g);
192  ptrdiff_t stride = sycl::detail::get_local_linear_range(g);
193  for (Ptr p = first + offset; p < last; p += stride) {
194  f(*p);
195  }
196  return f;
197 #else
198  (void)g;
199  (void)first;
200  (void)last;
201  (void)f;
203  "Group algorithms are not supported on host.");
204 #endif
205 }
206 } // namespace detail
207 
208 // ---- reduce_over_group
209 // three argument variant is specialized thrice:
210 // scalar arithmetic, complex (plus only), and vector arithmetic
211 
212 template <typename Group, typename T, class BinaryOperation>
213 std::enable_if_t<(is_group_v<std::decay_t<Group>> &&
214  (detail::is_scalar_arithmetic<T>::value ||
215  (detail::is_complex<T>::value &&
216  detail::is_multiplies<T, BinaryOperation>::value)) &&
218  T>
219 reduce_over_group(Group g, T x, BinaryOperation binary_op) {
220  static_assert(
221  std::is_same_v<decltype(binary_op(x, x)), T>,
222  "Result type of binary_op must match reduction accumulation type.");
223 #ifdef __SYCL_DEVICE_ONLY__
224 #if defined(__NVPTX__)
225  if constexpr (ext::oneapi::experimental::is_user_constructed_group_v<Group>) {
226  sycl::vec<unsigned, 4> MemberMask =
228 #if (__SYCL_CUDA_ARCH__ >= 800)
229  return detail::masked_reduction_cuda_sm80(g, x, binary_op, MemberMask[0]);
230 #else
231  return detail::masked_reduction_cuda_shfls(g, x, binary_op, MemberMask[0]);
232 #endif
233  }
234 #endif
235  return sycl::detail::calc<__spv::GroupOperation::Reduce>(
236  g, typename sycl::detail::GroupOpTag<T>::type(), x, binary_op);
237 #else
238  (void)g;
240  "Group algorithms are not supported on host.");
241 #endif
242 }
243 
244 // complex specialization. T is std::complex<float> or similar.
245 // binary op is sycl::plus<std::complex<float>>
246 template <typename Group, typename T, class BinaryOperation>
247 std::enable_if_t<(is_group_v<std::decay_t<Group>> &&
248  detail::is_complex<T>::value &&
249  detail::is_native_op<T, sycl::plus<T>>::value &&
250  detail::is_plus<T, BinaryOperation>::value),
251  T>
252 reduce_over_group(Group g, T x, BinaryOperation) {
253 #ifdef __SYCL_DEVICE_ONLY__
254  T result;
255  result.real(reduce_over_group(g, x.real(), sycl::plus<>()));
256  result.imag(reduce_over_group(g, x.imag(), sycl::plus<>()));
257  return result;
258 #else
259  (void)g;
260  (void)x;
262  "Group algorithms are not supported on host.");
263 #endif
264 }
265 
266 template <typename Group, typename T, class BinaryOperation>
267 std::enable_if_t<(is_group_v<std::decay_t<Group>> &&
268  detail::is_vector_arithmetic_or_complex<T>::value &&
270  T>
271 reduce_over_group(Group g, T x, BinaryOperation binary_op) {
272  static_assert(
273  std::is_same_v<decltype(binary_op(x, x)), T>,
274  "Result type of binary_op must match reduction accumulation type.");
275  T result;
276  typename detail::get_scalar_binary_op<BinaryOperation>::type
277  scalar_binary_op{};
278  detail::loop<x.size()>([&](size_t s) {
279  result[s] = reduce_over_group(g, x[s], scalar_binary_op);
280  });
281  return result;
282 }
283 
284 // four argument variant of reduce_over_group specialized twice
285 // (scalar arithmetic || complex), and vector_arithmetic
286 template <typename Group, typename V, typename T, class BinaryOperation>
287 std::enable_if_t<
288  (is_group_v<std::decay_t<Group>> &&
289  (detail::is_scalar_arithmetic<V>::value || detail::is_complex<V>::value) &&
290  (detail::is_scalar_arithmetic<T>::value || detail::is_complex<T>::value) &&
292  detail::is_plus_or_multiplies_if_complex<T, BinaryOperation>::value &&
293  std::is_convertible_v<V, T>),
294  T>
295 reduce_over_group(Group g, V x, T init, BinaryOperation binary_op) {
296  static_assert(
297  std::is_same_v<decltype(binary_op(init, x)), T>,
298  "Result type of binary_op must match reduction accumulation type.");
299 #ifdef __SYCL_DEVICE_ONLY__
300  return binary_op(init, reduce_over_group(g, T(x), binary_op));
301 #else
302  (void)g;
304  "Group algorithms are not supported on host.");
305 #endif
306 }
307 
308 template <typename Group, typename V, typename T, class BinaryOperation>
309 std::enable_if_t<(is_group_v<std::decay_t<Group>> &&
310  detail::is_vector_arithmetic_or_complex<V>::value &&
311  detail::is_vector_arithmetic_or_complex<T>::value &&
314  T>
315 reduce_over_group(Group g, V x, T init, BinaryOperation binary_op) {
316  static_assert(
317  std::is_same_v<decltype(binary_op(init, x)), T>,
318  "Result type of binary_op must match reduction accumulation type.");
319  typename detail::get_scalar_binary_op<BinaryOperation>::type
320  scalar_binary_op{};
321 #ifdef __SYCL_DEVICE_ONLY__
322  T result = init;
323  for (int s = 0; s < x.size(); ++s) {
324  result[s] =
325  scalar_binary_op(init[s], reduce_over_group(g, x[s], scalar_binary_op));
326  }
327  return result;
328 #else
329  (void)g;
331  "Group algorithms are not supported on host.");
332 #endif
333 }
334 
335 // ---- joint_reduce
336 template <typename Group, typename Ptr, typename T, class BinaryOperation>
337 std::enable_if_t<
338  (is_group_v<std::decay_t<Group>> && detail::is_pointer_v<Ptr> &&
340  typename detail::remove_pointer<Ptr>::type>::value &&
341  detail::is_arithmetic_or_complex<T>::value &&
342  detail::is_plus_or_multiplies_if_complex<T, BinaryOperation>::value &&
344  T>
345 joint_reduce(Group g, Ptr first, Ptr last, T init, BinaryOperation binary_op) {
346  static_assert(
347  std::is_same_v<decltype(binary_op(init, *first)), T>,
348  "Result type of binary_op must match reduction accumulation type.");
349 #ifdef __SYCL_DEVICE_ONLY__
350  T partial = detail::identity_for_ga_op<T, BinaryOperation>();
352  g, first, last, [&](const typename detail::remove_pointer<Ptr>::type &x) {
353  partial = binary_op(partial, x);
354  });
355  return reduce_over_group(g, partial, init, binary_op);
356 #else
357  (void)g;
358  (void)last;
360  "Group algorithms are not supported on host.");
361 #endif
362 }
363 
364 template <typename Group, typename Ptr, class BinaryOperation>
365 std::enable_if_t<
366  (is_group_v<std::decay_t<Group>> && detail::is_pointer_v<Ptr> &&
368  typename detail::remove_pointer<Ptr>::type>::value &&
370  typename detail::remove_pointer<Ptr>::type, BinaryOperation>::value),
372 joint_reduce(Group g, Ptr first, Ptr last, BinaryOperation binary_op) {
373 #ifdef __SYCL_DEVICE_ONLY__
374  using T = typename detail::remove_pointer<Ptr>::type;
375  T init = detail::identity_for_ga_op<T, BinaryOperation>();
376  return joint_reduce(g, first, last, init, binary_op);
377 #else
378  (void)g;
379  (void)first;
380  (void)last;
381  (void)binary_op;
383  "Group algorithms are not supported on host.");
384 #endif
385 }
386 
387 // ---- any_of_group
388 template <typename Group>
389 std::enable_if_t<is_group_v<std::decay_t<Group>>, bool>
390 any_of_group(Group g, bool pred) {
391 #ifdef __SYCL_DEVICE_ONLY__
392 #if defined(__NVPTX__)
393  if constexpr (ext::oneapi::experimental::is_user_constructed_group_v<Group>) {
394  return __nvvm_vote_any_sync(detail::ExtractMask(detail::GetMask(g))[0],
395  pred);
396  }
397 #endif
398  return sycl::detail::spirv::GroupAny(g, pred);
399 #else
400  (void)g;
401  (void)pred;
403  "Group algorithms are not supported on host.");
404 #endif
405 }
406 
407 template <typename Group, typename T, class Predicate>
408 std::enable_if_t<is_group_v<Group>, bool> any_of_group(Group g, T x,
409  Predicate pred) {
410  return any_of_group(g, pred(x));
411 }
412 
413 // ---- joint_any_of
414 template <typename Group, typename Ptr, class Predicate>
415 std::enable_if_t<(is_group_v<std::decay_t<Group>> && detail::is_pointer_v<Ptr>),
416  bool>
417 joint_any_of(Group g, Ptr first, Ptr last, Predicate pred) {
418 #ifdef __SYCL_DEVICE_ONLY__
419  using T = typename detail::remove_pointer<Ptr>::type;
420  bool partial = false;
421  sycl::detail::for_each(g, first, last, [&](T &x) { partial |= pred(x); });
422  return any_of_group(g, partial);
423 #else
424  (void)g;
425  (void)first;
426  (void)last;
427  (void)pred;
429  "Group algorithms are not supported on host.");
430 #endif
431 }
432 
433 // ---- all_of_group
434 template <typename Group>
435 std::enable_if_t<is_group_v<std::decay_t<Group>>, bool>
436 all_of_group(Group g, bool pred) {
437 #ifdef __SYCL_DEVICE_ONLY__
438 #if defined(__NVPTX__)
439  if constexpr (ext::oneapi::experimental::is_user_constructed_group_v<Group>) {
440  return __nvvm_vote_all_sync(detail::ExtractMask(detail::GetMask(g))[0],
441  pred);
442  }
443 #endif
444  return sycl::detail::spirv::GroupAll(g, pred);
445 #else
446  (void)g;
447  (void)pred;
449  "Group algorithms are not supported on host.");
450 #endif
451 }
452 
453 template <typename Group, typename T, class Predicate>
454 std::enable_if_t<is_group_v<std::decay_t<Group>>, bool>
455 all_of_group(Group g, T x, Predicate pred) {
456  return all_of_group(g, pred(x));
457 }
458 
459 // ---- joint_all_of
460 template <typename Group, typename Ptr, class Predicate>
461 std::enable_if_t<(is_group_v<std::decay_t<Group>> && detail::is_pointer_v<Ptr>),
462  bool>
463 joint_all_of(Group g, Ptr first, Ptr last, Predicate pred) {
464 #ifdef __SYCL_DEVICE_ONLY__
465  using T = typename detail::remove_pointer<Ptr>::type;
466  bool partial = true;
467  sycl::detail::for_each(g, first, last, [&](T &x) { partial &= pred(x); });
468  return all_of_group(g, partial);
469 #else
470  (void)g;
471  (void)first;
472  (void)last;
473  (void)pred;
475  "Group algorithms are not supported on host.");
476 #endif
477 }
478 
479 // ---- none_of_group
480 template <typename Group>
481 std::enable_if_t<is_group_v<std::decay_t<Group>>, bool>
482 none_of_group(Group g, bool pred) {
483 #ifdef __SYCL_DEVICE_ONLY__
484 #if defined(__NVPTX__)
485  if constexpr (ext::oneapi::experimental::is_user_constructed_group_v<Group>) {
486  return __nvvm_vote_all_sync(detail::ExtractMask(detail::GetMask(g))[0],
487  !pred);
488  }
489 #endif
490  return sycl::detail::spirv::GroupAll(g, !pred);
491 #else
492  (void)g;
493  (void)pred;
495  "Group algorithms are not supported on host.");
496 #endif
497 }
498 
499 template <typename Group, typename T, class Predicate>
500 std::enable_if_t<is_group_v<std::decay_t<Group>>, bool>
501 none_of_group(Group g, T x, Predicate pred) {
502  return none_of_group(g, pred(x));
503 }
504 
505 // ---- joint_none_of
506 template <typename Group, typename Ptr, class Predicate>
507 std::enable_if_t<(is_group_v<std::decay_t<Group>> && detail::is_pointer_v<Ptr>),
508  bool>
509 joint_none_of(Group g, Ptr first, Ptr last, Predicate pred) {
510 #ifdef __SYCL_DEVICE_ONLY__
511  return !joint_any_of(g, first, last, pred);
512 #else
513  (void)g;
514  (void)first;
515  (void)last;
516  (void)pred;
518  "Group algorithms are not supported on host.");
519 #endif
520 }
521 
522 // ---- shift_group_left
523 // TODO: remove check for detail::is_vec<T> once sycl::vec is trivially
524 // copyable.
525 template <typename Group, typename T>
526 std::enable_if_t<((std::is_same_v<std::decay_t<Group>, sub_group> ||
528  std::decay_t<Group>>) &&
529  (std::is_trivially_copyable_v<T> ||
530  detail::is_vec<T>::value)),
531  T>
532 shift_group_left(Group g, T x, typename Group::linear_id_type delta = 1) {
533 #ifdef __SYCL_DEVICE_ONLY__
534  return sycl::detail::spirv::ShuffleDown(g, x, delta);
535 #else
536  (void)g;
537  (void)x;
538  (void)delta;
540  "Sub-groups are not supported on host.");
541 #endif
542 }
543 
544 // ---- shift_group_right
545 // TODO: remove check for detail::is_vec<T> once sycl::vec is trivially
546 // copyable.
547 template <typename Group, typename T>
548 std::enable_if_t<((std::is_same_v<std::decay_t<Group>, sub_group> ||
550  std::decay_t<Group>>) &&
551  (std::is_trivially_copyable_v<T> ||
552  detail::is_vec<T>::value)),
553  T>
554 shift_group_right(Group g, T x, typename Group::linear_id_type delta = 1) {
555 #ifdef __SYCL_DEVICE_ONLY__
556  return sycl::detail::spirv::ShuffleUp(g, x, delta);
557 #else
558  (void)g;
559  (void)x;
560  (void)delta;
562  "Sub-groups are not supported on host.");
563 #endif
564 }
565 
566 // ---- permute_group_by_xor
567 // TODO: remove check for detail::is_vec<T> once sycl::vec is trivially
568 // copyable.
569 template <typename Group, typename T>
570 std::enable_if_t<((std::is_same_v<std::decay_t<Group>, sub_group> ||
572  std::decay_t<Group>>) &&
573  (std::is_trivially_copyable_v<T> ||
574  detail::is_vec<T>::value)),
575  T>
576 permute_group_by_xor(Group g, T x, typename Group::linear_id_type mask) {
577 #ifdef __SYCL_DEVICE_ONLY__
578  return sycl::detail::spirv::ShuffleXor(g, x, mask);
579 #else
580  (void)g;
581  (void)x;
582  (void)mask;
584  "Sub-groups are not supported on host.");
585 #endif
586 }
587 
588 // ---- select_from_group
589 // TODO: remove check for detail::is_vec<T> once sycl::vec is trivially
590 // copyable.
591 template <typename Group, typename T>
592 std::enable_if_t<((std::is_same_v<std::decay_t<Group>, sub_group> ||
594  std::decay_t<Group>>) &&
595  (std::is_trivially_copyable_v<T> ||
596  detail::is_vec<T>::value)),
597  T>
598 select_from_group(Group g, T x, typename Group::id_type local_id) {
599 #ifdef __SYCL_DEVICE_ONLY__
600  return sycl::detail::spirv::Shuffle(g, x, local_id);
601 #else
602  (void)g;
603  (void)x;
604  (void)local_id;
606  "Sub-groups are not supported on host.");
607 #endif
608 }
609 
610 // ---- group_broadcast
611 // TODO: remove check for detail::is_vec<T> once sycl::vec is trivially
612 // copyable.
613 template <typename Group, typename T>
614 std::enable_if_t<(is_group_v<std::decay_t<Group>> &&
615  (std::is_trivially_copyable_v<T> ||
616  detail::is_vec<T>::value)),
617  T>
618 group_broadcast(Group g, T x, typename Group::id_type local_id) {
619 #ifdef __SYCL_DEVICE_ONLY__
620 #if defined(__NVPTX__)
621  if constexpr (ext::oneapi::experimental::is_user_constructed_group_v<Group>) {
622  auto LocalId = detail::IdToMaskPosition(g, local_id);
623  return __nvvm_shfl_sync_idx_i32(detail::ExtractMask(detail::GetMask(g))[0],
624  x, LocalId, 31);
625  }
626 #endif
627  return sycl::detail::spirv::GroupBroadcast(g, x, local_id);
628 #else
629  (void)g;
630  (void)x;
631  (void)local_id;
633  "Group algorithms are not supported on host.");
634 #endif
635 }
636 
637 template <typename Group, typename T>
638 std::enable_if_t<(is_group_v<std::decay_t<Group>> &&
639  (std::is_trivially_copyable_v<T> ||
640  detail::is_vec<T>::value)),
641  T>
642 group_broadcast(Group g, T x, typename Group::linear_id_type linear_local_id) {
643 #ifdef __SYCL_DEVICE_ONLY__
644  return group_broadcast(
645  g, x,
646  sycl::detail::linear_id_to_id(g.get_local_range(), linear_local_id));
647 #else
648  (void)g;
649  (void)x;
650  (void)linear_local_id;
652  "Group algorithms are not supported on host.");
653 #endif
654 }
655 
656 template <typename Group, typename T>
657 std::enable_if_t<(is_group_v<std::decay_t<Group>> &&
658  (std::is_trivially_copyable_v<T> ||
659  detail::is_vec<T>::value)),
660  T>
661 group_broadcast(Group g, T x) {
662 #ifdef __SYCL_DEVICE_ONLY__
663  return group_broadcast(g, x, 0);
664 #else
665  (void)g;
666  (void)x;
668  "Group algorithms are not supported on host.");
669 #endif
670 }
671 
672 // ---- exclusive_scan_over_group
673 // this function has two overloads, one with three arguments and one with four
674 // the three argument version is specialized thrice: scalar, complex, and
675 // vector
676 template <typename Group, typename T, class BinaryOperation>
677 std::enable_if_t<(is_group_v<std::decay_t<Group>> &&
678  (detail::is_scalar_arithmetic<T>::value ||
679  (detail::is_complex<T>::value &&
680  detail::is_multiplies<T, BinaryOperation>::value)) &&
682  T>
683 exclusive_scan_over_group(Group g, T x, BinaryOperation binary_op) {
684  static_assert(std::is_same_v<decltype(binary_op(x, x)), T>,
685  "Result type of binary_op must match scan accumulation type.");
686 #ifdef __SYCL_DEVICE_ONLY__
687 #if defined(__NVPTX__)
688  if constexpr (ext::oneapi::experimental::is_user_constructed_group_v<Group>) {
689  return detail::masked_scan_cuda_shfls<__spv::GroupOperation::ExclusiveScan>(
690  g, x, binary_op,
692  }
693 #endif
694  // For the first work item in the group, we cannot return the result
695  // of calc when T is a signed char or short type and the
696  // BinaryOperation is maximum or minimum. calc uses SPIRV group
697  // collective instructions, which only operate on 32 or 64 bit
698  // integers. So, when using calc with a short or char type, the
699  // argument is converted to a 32 bit integer, the 32 bit group
700  // operation is performed, and then converted back to the original
701  // short or char type. For an exclusive scan, the first work item
702  // returns the identity for the supplied operation. However, the
703  // identity of a 32 bit signed integer maximum or minimum when
704  // converted to a signed char or short does not correspond to the
705  // identity of a signed char or short maximum or minimum. For
706  // example, the identity of a signed 32 bit maximum is
707  // INT_MIN=-2**31, and when converted to a signed char, results in
708  // 0. However, the identity of a signed char maximum is
709  // SCHAR_MIN=-2**7. Therefore, we need the following check to
710  // circumvent this issue.
711  auto res = sycl::detail::calc<__spv::GroupOperation::ExclusiveScan>(
712  g, typename sycl::detail::GroupOpTag<T>::type(), x, binary_op);
713  if constexpr ((std::is_same_v<signed char, T> ||
714  std::is_same_v<signed short, T> ||
715  (std::is_signed_v<char> && std::is_same_v<char, T>)) &&
716  detail::is_max_or_min<BinaryOperation>::value) {
717  auto local_id = sycl::detail::get_local_linear_id(g);
718  if (local_id == 0)
719  return sycl::known_identity_v<BinaryOperation, T>;
720  }
721  return res;
722 #else
723  (void)g;
725  "Group algorithms are not supported on host.");
726 #endif
727 }
728 
729 // complex specialization. T is std::complex<float> or similar.
730 // binary op is sycl::plus<std::complex<float>>
731 template <typename Group, typename T, class BinaryOperation>
732 std::enable_if_t<(is_group_v<std::decay_t<Group>> &&
733  detail::is_complex<T>::value &&
734  detail::is_native_op<T, sycl::plus<T>>::value &&
735  detail::is_plus<T, BinaryOperation>::value),
736  T>
737 exclusive_scan_over_group(Group g, T x, BinaryOperation) {
738 #ifdef __SYCL_DEVICE_ONLY__
739  T result;
740  result.real(exclusive_scan_over_group(g, x.real(), sycl::plus<>()));
741  result.imag(exclusive_scan_over_group(g, x.imag(), sycl::plus<>()));
742  return result;
743 #else
744  (void)g;
745  (void)x;
747  "Group algorithms are not supported on host.");
748 #endif
749 }
750 
751 template <typename Group, typename T, class BinaryOperation>
752 std::enable_if_t<(is_group_v<std::decay_t<Group>> &&
753  detail::is_vector_arithmetic_or_complex<T>::value &&
755  T>
756 exclusive_scan_over_group(Group g, T x, BinaryOperation binary_op) {
757  static_assert(std::is_same_v<decltype(binary_op(x, x)), T>,
758  "Result type of binary_op must match scan accumulation type.");
759  T result;
760  typename detail::get_scalar_binary_op<BinaryOperation>::type
761  scalar_binary_op{};
762  for (int s = 0; s < x.size(); ++s) {
763  result[s] = exclusive_scan_over_group(g, x[s], scalar_binary_op);
764  }
765  return result;
766 }
767 
768 // four argument version of exclusive_scan_over_group is specialized twice
769 // once for vector_arithmetic, once for (scalar_arithmetic || complex)
770 template <typename Group, typename V, typename T, class BinaryOperation>
771 std::enable_if_t<
772  (is_group_v<std::decay_t<Group>> &&
773  (detail::is_scalar_arithmetic<V>::value || detail::is_complex<V>::value) &&
774  (detail::is_scalar_arithmetic<T>::value || detail::is_complex<T>::value) &&
776  detail::is_plus_or_multiplies_if_complex<T, BinaryOperation>::value &&
777  std::is_convertible_v<V, T>),
778  T>
779 exclusive_scan_over_group(Group g, V x, T init, BinaryOperation binary_op) {
780  static_assert(std::is_same_v<decltype(binary_op(init, x)), T>,
781  "Result type of binary_op must match scan accumulation type.");
782 #ifdef __SYCL_DEVICE_ONLY__
783  typename Group::linear_id_type local_linear_id =
785  T y = x;
786  if (local_linear_id == 0) {
787  y = binary_op(init, y);
788  }
789  T scan = exclusive_scan_over_group(g, y, binary_op);
790  if (local_linear_id == 0) {
791  scan = init;
792  }
793  return scan;
794 #else
795  (void)g;
797  "Group algorithms are not supported on host.");
798 #endif
799 }
800 
801 template <typename Group, typename V, typename T, class BinaryOperation>
802 std::enable_if_t<(is_group_v<std::decay_t<Group>> &&
803  detail::is_vector_arithmetic_or_complex<V>::value &&
804  detail::is_vector_arithmetic_or_complex<T>::value &&
807  T>
808 exclusive_scan_over_group(Group g, V x, T init, BinaryOperation binary_op) {
809  static_assert(std::is_same_v<decltype(binary_op(init, x)), T>,
810  "Result type of binary_op must match scan accumulation type.");
811  T result;
812  typename detail::get_scalar_binary_op<BinaryOperation>::type
813  scalar_binary_op{};
814  for (int s = 0; s < x.size(); ++s) {
815  result[s] = exclusive_scan_over_group(g, x[s], init[s], scalar_binary_op);
816  }
817  return result;
818 }
819 
820 // ---- joint_exclusive_scan
821 template <typename Group, typename InPtr, typename OutPtr, typename T,
822  class BinaryOperation>
823 std::enable_if_t<
824  (is_group_v<std::decay_t<Group>> && detail::is_pointer_v<InPtr> &&
825  detail::is_pointer_v<OutPtr> &&
827  typename detail::remove_pointer<InPtr>::type>::value &&
829  typename detail::remove_pointer<OutPtr>::type>::value &&
830  detail::is_arithmetic_or_complex<T>::value &&
832  detail::is_plus_or_multiplies_if_complex<T, BinaryOperation>::value),
833  OutPtr>
834 joint_exclusive_scan(Group g, InPtr first, InPtr last, OutPtr result, T init,
835  BinaryOperation binary_op) {
836  static_assert(std::is_same_v<decltype(binary_op(init, *first)), T>,
837  "Result type of binary_op must match scan accumulation type.");
838 #ifdef __SYCL_DEVICE_ONLY__
839  ptrdiff_t offset = sycl::detail::get_local_linear_id(g);
840  ptrdiff_t stride = sycl::detail::get_local_linear_range(g);
841  ptrdiff_t N = last - first;
842  auto roundup = [=](const ptrdiff_t &v,
843  const ptrdiff_t &divisor) -> ptrdiff_t {
844  return ((v + divisor - 1) / divisor) * divisor;
845  };
846  typename std::remove_const<typename detail::remove_pointer<InPtr>::type>::type
847  x = {};
848  T carry = init;
849  for (ptrdiff_t chunk = 0; chunk < roundup(N, stride); chunk += stride) {
850  ptrdiff_t i = chunk + offset;
851  if (i < N) {
852  x = first[i];
853  }
854  T out = exclusive_scan_over_group(g, x, carry, binary_op);
855  if (i < N) {
856  result[i] = out;
857  }
858  carry = group_broadcast(g, binary_op(out, x), stride - 1);
859  }
860  return result + N;
861 #else
862  (void)g;
863  (void)last;
864  (void)result;
865  (void)init;
867  "Group algorithms are not supported on host.");
868 #endif
869 }
870 
871 template <typename Group, typename InPtr, typename OutPtr,
872  class BinaryOperation>
873 std::enable_if_t<
874  (is_group_v<std::decay_t<Group>> && detail::is_pointer_v<InPtr> &&
875  detail::is_pointer_v<OutPtr> &&
877  typename detail::remove_pointer<InPtr>::type>::value &&
879  typename detail::remove_pointer<OutPtr>::type>::value &&
880  detail::is_native_op<typename detail::remove_pointer<OutPtr>::type,
881  BinaryOperation>::value &&
884  BinaryOperation>::value),
885  OutPtr>
886 joint_exclusive_scan(Group g, InPtr first, InPtr last, OutPtr result,
887  BinaryOperation binary_op) {
888  static_assert(std::is_same_v<decltype(binary_op(*first, *first)),
890  "Result type of binary_op must match scan accumulation type.");
891  using T = typename detail::remove_pointer<OutPtr>::type;
892  T init = detail::identity_for_ga_op<T, BinaryOperation>();
893  return joint_exclusive_scan(g, first, last, result, init, binary_op);
894 }
895 
896 // ---- inclusive_scan_over_group
897 // this function has two overloads, one with three arguments and one with four
898 // the three argument version is specialized thrice: vector, scalar, and
899 // complex
900 template <typename Group, typename T, class BinaryOperation>
901 std::enable_if_t<(is_group_v<std::decay_t<Group>> &&
902  (detail::is_scalar_arithmetic<T>::value ||
903  (detail::is_complex<T>::value &&
904  detail::is_multiplies<T, BinaryOperation>::value)) &&
906  T>
907 inclusive_scan_over_group(Group g, T x, BinaryOperation binary_op) {
908  static_assert(std::is_same_v<decltype(binary_op(x, x)), T>,
909  "Result type of binary_op must match scan accumulation type.");
910 #ifdef __SYCL_DEVICE_ONLY__
911 #if defined(__NVPTX__)
912  if constexpr (ext::oneapi::experimental::is_user_constructed_group_v<Group>) {
913  return detail::masked_scan_cuda_shfls<__spv::GroupOperation::InclusiveScan>(
914  g, x, binary_op,
916  }
917 #endif
918  return sycl::detail::calc<__spv::GroupOperation::InclusiveScan>(
919  g, typename sycl::detail::GroupOpTag<T>::type(), x, binary_op);
920 #else
921  (void)g;
923  "Group algorithms are not supported on host.");
924 #endif
925 }
926 
927 template <typename Group, typename T, class BinaryOperation>
928 std::enable_if_t<(is_group_v<std::decay_t<Group>> &&
929  detail::is_vector_arithmetic_or_complex<T>::value &&
931  T>
932 inclusive_scan_over_group(Group g, T x, BinaryOperation binary_op) {
933  static_assert(std::is_same_v<decltype(binary_op(x, x)), T>,
934  "Result type of binary_op must match scan accumulation type.");
935  T result;
936  typename detail::get_scalar_binary_op<BinaryOperation>::type
937  scalar_binary_op{};
938  for (int s = 0; s < x.size(); ++s) {
939  result[s] = inclusive_scan_over_group(g, x[s], scalar_binary_op);
940  }
941  return result;
942 }
943 
944 // complex specializaiton
945 template <typename Group, typename T, class BinaryOperation>
946 std::enable_if_t<(is_group_v<std::decay_t<Group>> &&
947  detail::is_complex<T>::value &&
948  detail::is_native_op<T, sycl::plus<T>>::value &&
949  detail::is_plus<T, BinaryOperation>::value),
950  T>
951 inclusive_scan_over_group(Group g, T x, BinaryOperation) {
952 #ifdef __SYCL_DEVICE_ONLY__
953  T result;
954  result.real(inclusive_scan_over_group(g, x.real(), sycl::plus<>()));
955  result.imag(inclusive_scan_over_group(g, x.imag(), sycl::plus<>()));
956  return result;
957 #else
958  (void)g;
959  (void)x;
961  "Group algorithms are not supported on host.");
962 #endif
963 }
964 
965 // four argument version of inclusive_scan_over_group is specialized twice
966 // once for (scalar_arithmetic || complex) and once for vector_arithmetic
967 template <typename Group, typename V, class BinaryOperation, typename T>
968 std::enable_if_t<
969  (is_group_v<std::decay_t<Group>> &&
970  (detail::is_scalar_arithmetic<V>::value || detail::is_complex<V>::value) &&
971  (detail::is_scalar_arithmetic<T>::value || detail::is_complex<T>::value) &&
973  detail::is_plus_or_multiplies_if_complex<T, BinaryOperation>::value &&
974  std::is_convertible_v<V, T>),
975  T>
976 inclusive_scan_over_group(Group g, V x, BinaryOperation binary_op, T init) {
977  static_assert(std::is_same_v<decltype(binary_op(init, x)), T>,
978  "Result type of binary_op must match scan accumulation type.");
979 #ifdef __SYCL_DEVICE_ONLY__
980  T y = x;
981  if (sycl::detail::get_local_linear_id(g) == 0) {
982  y = binary_op(init, y);
983  }
984  return inclusive_scan_over_group(g, y, binary_op);
985 #else
986  (void)g;
988  "Group algorithms are not supported on host.");
989 #endif
990 }
991 
992 template <typename Group, typename V, class BinaryOperation, typename T>
993 std::enable_if_t<(is_group_v<std::decay_t<Group>> &&
994  detail::is_vector_arithmetic_or_complex<V>::value &&
995  detail::is_vector_arithmetic_or_complex<T>::value &&
998  T>
999 inclusive_scan_over_group(Group g, V x, BinaryOperation binary_op, T init) {
1000  static_assert(std::is_same_v<decltype(binary_op(init, x)), T>,
1001  "Result type of binary_op must match scan accumulation type.");
1002  T result;
1003  typename detail::get_scalar_binary_op<BinaryOperation>::type
1004  scalar_binary_op{};
1005  for (int s = 0; s < x.size(); ++s) {
1006  result[s] = inclusive_scan_over_group(g, x[s], scalar_binary_op, init[s]);
1007  }
1008  return result;
1009 }
1010 
1011 // ---- joint_inclusive_scan
1012 template <typename Group, typename InPtr, typename OutPtr,
1013  class BinaryOperation, typename T>
1014 std::enable_if_t<
1015  (is_group_v<std::decay_t<Group>> && detail::is_pointer_v<InPtr> &&
1016  detail::is_pointer_v<OutPtr> &&
1018  typename detail::remove_pointer<InPtr>::type>::value &&
1020  typename detail::remove_pointer<OutPtr>::type>::value &&
1021  detail::is_arithmetic_or_complex<T>::value &&
1023  detail::is_plus_or_multiplies_if_complex<T, BinaryOperation>::value),
1024  OutPtr>
1025 joint_inclusive_scan(Group g, InPtr first, InPtr last, OutPtr result,
1026  BinaryOperation binary_op, T init) {
1027  static_assert(std::is_same_v<decltype(binary_op(init, *first)), T>,
1028  "Result type of binary_op must match scan accumulation type.");
1029 #ifdef __SYCL_DEVICE_ONLY__
1030  ptrdiff_t offset = sycl::detail::get_local_linear_id(g);
1031  ptrdiff_t stride = sycl::detail::get_local_linear_range(g);
1032  ptrdiff_t N = last - first;
1033  auto roundup = [=](const ptrdiff_t &v,
1034  const ptrdiff_t &divisor) -> ptrdiff_t {
1035  return ((v + divisor - 1) / divisor) * divisor;
1036  };
1037  typename std::remove_const<typename detail::remove_pointer<InPtr>::type>::type
1038  x = {};
1039  T carry = init;
1040  for (ptrdiff_t chunk = 0; chunk < roundup(N, stride); chunk += stride) {
1041  ptrdiff_t i = chunk + offset;
1042  if (i < N) {
1043  x = first[i];
1044  }
1045  T out = inclusive_scan_over_group(g, x, binary_op, carry);
1046  if (i < N) {
1047  result[i] = out;
1048  }
1049  carry = group_broadcast(g, out, stride - 1);
1050  }
1051  return result + N;
1052 #else
1053  (void)g;
1054  (void)last;
1055  (void)result;
1057  "Group algorithms are not supported on host.");
1058 #endif
1059 }
1060 
1061 template <typename Group, typename InPtr, typename OutPtr,
1062  class BinaryOperation>
1063 std::enable_if_t<
1064  (is_group_v<std::decay_t<Group>> && detail::is_pointer_v<InPtr> &&
1065  detail::is_pointer_v<OutPtr> &&
1067  typename detail::remove_pointer<InPtr>::type>::value &&
1068  detail::is_native_op<typename detail::remove_pointer<OutPtr>::type,
1069  BinaryOperation>::value &&
1072  BinaryOperation>::value),
1073  OutPtr>
1074 joint_inclusive_scan(Group g, InPtr first, InPtr last, OutPtr result,
1075  BinaryOperation binary_op) {
1076  static_assert(std::is_same_v<decltype(binary_op(*first, *first)),
1078  "Result type of binary_op must match scan accumulation type.");
1079 
1080  using T = typename detail::remove_pointer<OutPtr>::type;
1081  T init = detail::identity_for_ga_op<T, BinaryOperation>();
1082  return joint_inclusive_scan(g, first, last, result, binary_op, init);
1083 }
1084 
1085 } // namespace _V1
1086 } // namespace sycl
A unique identifier of an item in an index space.
Definition: id.hpp:36
id< Dimensions > linear_id_to_id(range< Dimensions >, size_t linear_id)
auto get_local_linear_id(Group g)
std::integral_constant< bool, std::is_same_v< BinaryOperation, sycl::multiplies< std::remove_const_t< T > >>||std::is_same_v< BinaryOperation, sycl::multiplies< std::add_const_t< T > >>||std::is_same_v< BinaryOperation, sycl::multiplies< void > >> is_multiplies
auto get_local_linear_range(Group g)
std::integral_constant< bool, std::is_same_v< BinaryOperation, sycl::plus< std::remove_const_t< T > >>||std::is_same_v< BinaryOperation, sycl::plus< std::add_const_t< T > >>||std::is_same_v< BinaryOperation, sycl::plus< void > >> is_plus
boost::mp11::mp_set_contains< TypeList, std::remove_cv_t< T > > is_contained
Definition: type_list.hpp:32
uint32_t IdToMaskPosition(NonUniformGroup Group, uint32_t Id)
boost::mp11::mp_list< T... > type_list
Definition: type_list.hpp:22
std::integral_constant< bool, sycl::detail::is_complex< T >::value||sycl::detail::is_arithmetic< T >::value > is_arithmetic_or_complex
ext::oneapi::sub_group_mask GetMask(NonUniformGroup Group)
std::integral_constant< bool,(is_complex< T >::value ?(is_plus< T, BinaryOperation >::value||is_multiplies< T, BinaryOperation >::value) :std::true_type::value)> is_plus_or_multiplies_if_complex
sycl::vec< unsigned, 4 > ExtractMask(ext::oneapi::sub_group_mask Mask)
id< 3 > linear_id_to_id(range< 3 > r, size_t linear_id)
void loop(F &&f)
Definition: helpers.hpp:250
type_list< sycl::plus< T >, sycl::bit_or< T >, sycl::bit_xor< T >, sycl::bit_and< T >, sycl::maximum< T >, sycl::minimum< T >, sycl::multiplies< T >, sycl::logical_or< T >, sycl::logical_and< T > > native_op_list
constexpr std::enable_if_t<(is_complex< T >::value &&is_plus< T, BinaryOperation >::value), T > identity_for_ga_op()
Function for_each(Group g, Ptr first, Ptr last, Function f)
std::enable_if_t<(is_group_v< std::decay_t< Group >> &&(std::is_trivially_copyable_v< T >||detail::is_vec< T >::value)), T > group_broadcast(Group g, T x, typename Group::id_type local_id)
std::enable_if_t<(is_group_v< std::decay_t< Group >> &&(detail::is_scalar_arithmetic< T >::value||(detail::is_complex< T >::value &&detail::is_multiplies< T, BinaryOperation >::value)) &&detail::is_native_op< T, BinaryOperation >::value), T > exclusive_scan_over_group(Group g, T x, BinaryOperation binary_op)
std::bit_and< T > bit_and
Definition: functional.hpp:20
std::enable_if_t<((std::is_same_v< std::decay_t< Group >, sub_group >||sycl::ext::oneapi::experimental::is_user_constructed_group_v< std::decay_t< Group >>) &&(std::is_trivially_copyable_v< T >||detail::is_vec< T >::value)), T > shift_group_left(Group g, T x, typename Group::linear_id_type delta=1)
std::enable_if_t<(is_group_v< std::decay_t< Group >> &&detail::is_pointer_v< Ptr > &&detail::is_arithmetic_or_complex< typename detail::remove_pointer< Ptr >::type >::value &&detail::is_arithmetic_or_complex< T >::value &&detail::is_plus_or_multiplies_if_complex< T, BinaryOperation >::value &&detail::is_native_op< T, BinaryOperation >::value), T > joint_reduce(Group g, Ptr first, Ptr last, T init, BinaryOperation binary_op)
std::enable_if_t< is_group_v< std::decay_t< Group > >, bool > any_of_group(Group g, bool pred)
std::enable_if_t<((std::is_same_v< std::decay_t< Group >, sub_group >||sycl::ext::oneapi::experimental::is_user_constructed_group_v< std::decay_t< Group >>) &&(std::is_trivially_copyable_v< T >||detail::is_vec< T >::value)), T > shift_group_right(Group g, T x, typename Group::linear_id_type delta=1)
std::enable_if_t<(is_group_v< std::decay_t< Group >> &&detail::is_pointer_v< InPtr > &&detail::is_pointer_v< OutPtr > &&detail::is_arithmetic_or_complex< typename detail::remove_pointer< InPtr >::type >::value &&detail::is_arithmetic_or_complex< typename detail::remove_pointer< OutPtr >::type >::value &&detail::is_arithmetic_or_complex< T >::value &&detail::is_native_op< T, BinaryOperation >::value &&detail::is_plus_or_multiplies_if_complex< T, BinaryOperation >::value), OutPtr > joint_exclusive_scan(Group g, InPtr first, InPtr last, OutPtr result, T init, BinaryOperation binary_op)
std::multiplies< T > multiplies
Definition: functional.hpp:19
std::bit_xor< T > bit_xor
Definition: functional.hpp:22
std::enable_if_t<(is_group_v< std::decay_t< Group >> &&detail::is_pointer_v< InPtr > &&detail::is_pointer_v< OutPtr > &&detail::is_arithmetic_or_complex< typename detail::remove_pointer< InPtr >::type >::value &&detail::is_arithmetic_or_complex< typename detail::remove_pointer< OutPtr >::type >::value &&detail::is_arithmetic_or_complex< T >::value &&detail::is_native_op< T, BinaryOperation >::value &&detail::is_plus_or_multiplies_if_complex< T, BinaryOperation >::value), OutPtr > joint_inclusive_scan(Group g, InPtr first, InPtr last, OutPtr result, BinaryOperation binary_op, T init)
std::plus< T > plus
Definition: functional.hpp:18
std::enable_if_t<(is_group_v< std::decay_t< Group >> &&(detail::is_scalar_arithmetic< T >::value||(detail::is_complex< T >::value &&detail::is_multiplies< T, BinaryOperation >::value)) &&detail::is_native_op< T, BinaryOperation >::value), T > reduce_over_group(Group g, T x, BinaryOperation binary_op)
std::bit_or< T > bit_or
Definition: functional.hpp:21
std::enable_if_t<(is_group_v< std::decay_t< Group >> &&detail::is_pointer_v< Ptr >), bool > joint_any_of(Group g, Ptr first, Ptr last, Predicate pred)
std::enable_if_t<((std::is_same_v< std::decay_t< Group >, sub_group >||sycl::ext::oneapi::experimental::is_user_constructed_group_v< std::decay_t< Group >>) &&(std::is_trivially_copyable_v< T >||detail::is_vec< T >::value)), T > select_from_group(Group g, T x, typename Group::id_type local_id)
std::enable_if_t<(is_group_v< std::decay_t< Group >> &&detail::is_pointer_v< Ptr >), bool > joint_all_of(Group g, Ptr first, Ptr last, Predicate pred)
std::enable_if_t< is_group_v< std::decay_t< Group > >, bool > none_of_group(Group g, bool pred)
std::enable_if_t<(is_group_v< std::decay_t< Group >> &&(detail::is_scalar_arithmetic< T >::value||(detail::is_complex< T >::value &&detail::is_multiplies< T, BinaryOperation >::value)) &&detail::is_native_op< T, BinaryOperation >::value), T > inclusive_scan_over_group(Group g, T x, BinaryOperation binary_op)
std::error_code make_error_code(sycl::errc E) noexcept
Constructs an error code using e and sycl_category()
Definition: exception.cpp:65
autodecltype(x) x
std::enable_if_t<((std::is_same_v< std::decay_t< Group >, sub_group >||sycl::ext::oneapi::experimental::is_user_constructed_group_v< std::decay_t< Group >>) &&(std::is_trivially_copyable_v< T >||detail::is_vec< T >::value)), T > permute_group_by_xor(Group g, T x, typename Group::linear_id_type mask)
std::enable_if_t<(is_group_v< std::decay_t< Group >> &&detail::is_pointer_v< Ptr >), bool > joint_none_of(Group g, Ptr first, Ptr last, Predicate pred)
std::enable_if_t< is_group_v< std::decay_t< Group > >, bool > all_of_group(Group g, bool pred)
Definition: access.hpp:18