DPC++ Runtime
Runtime libraries for oneAPI DPC++
tangle_group.hpp
Go to the documentation of this file.
1 //==------ tangle_group.hpp --- SYCL extension for non-uniform groups ------==//
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/aspects.hpp>
12 #include <sycl/detail/pi.h> // for PI_ERROR_INVALID_DEVICE
13 #include <sycl/detail/type_traits.hpp> // for is_group, is_user_cons...
14 #include <sycl/exception.hpp> // for runtime_error
16 #include <sycl/ext/oneapi/sub_group_mask.hpp> // for sub_group_mask
17 #include <sycl/id.hpp> // for id
18 #include <sycl/memory_enums.hpp> // for memory_scope
19 #include <sycl/range.hpp> // for range
20 #include <sycl/sub_group.hpp> // for sub_group
21 
22 #include <type_traits> // for enable_if_t, decay_t
23 
24 namespace sycl {
25 inline namespace _V1 {
26 namespace ext::oneapi::experimental {
27 
28 template <typename ParentGroup> class tangle_group;
29 
30 template <typename Group>
31 #ifdef __SYCL_DEVICE_ONLY__
32 [[__sycl_detail__::__uses_aspects__(sycl::aspect::ext_oneapi_tangle_group)]]
33 #endif
34 inline std::enable_if_t<sycl::is_group_v<std::decay_t<Group>> &&
35  std::is_same_v<Group, sycl::sub_group>,
36  tangle_group<Group>> get_tangle_group(Group group);
37 
38 template <typename ParentGroup> class tangle_group {
39 public:
40  using id_type = id<1>;
42  using linear_id_type = typename ParentGroup::linear_id_type;
43  static constexpr int dimensions = 1;
45 
47 #ifdef __SYCL_DEVICE_ONLY__
48  return static_cast<id_type>(0);
49 #else
50  throw runtime_error("Non-uniform groups are not supported on host device.",
51  PI_ERROR_INVALID_DEVICE);
52 #endif
53  }
54 
56 #ifdef __SYCL_DEVICE_ONLY__
57  return sycl::detail::CallerPositionInMask(Mask);
58 #else
59  throw runtime_error("Non-uniform groups are not supported on host device.",
60  PI_ERROR_INVALID_DEVICE);
61 #endif
62  }
63 
65 #ifdef __SYCL_DEVICE_ONLY__
66  return 1;
67 #else
68  throw runtime_error("Non-uniform groups are not supported on host device.",
69  PI_ERROR_INVALID_DEVICE);
70 #endif
71  }
72 
74 #ifdef __SYCL_DEVICE_ONLY__
75  return Mask.count();
76 #else
77  throw runtime_error("Non-uniform groups are not supported on host device.",
78  PI_ERROR_INVALID_DEVICE);
79 #endif
80  }
81 
83 #ifdef __SYCL_DEVICE_ONLY__
84  return static_cast<linear_id_type>(get_group_id()[0]);
85 #else
86  throw runtime_error("Non-uniform groups are not supported on host device.",
87  PI_ERROR_INVALID_DEVICE);
88 #endif
89  }
90 
92 #ifdef __SYCL_DEVICE_ONLY__
93  return static_cast<linear_id_type>(get_local_id()[0]);
94 #else
95  throw runtime_error("Non-uniform groups are not supported on host device.",
96  PI_ERROR_INVALID_DEVICE);
97 #endif
98  }
99 
101 #ifdef __SYCL_DEVICE_ONLY__
102  return static_cast<linear_id_type>(get_group_range()[0]);
103 #else
104  throw runtime_error("Non-uniform groups are not supported on host device.",
105  PI_ERROR_INVALID_DEVICE);
106 #endif
107  }
108 
110 #ifdef __SYCL_DEVICE_ONLY__
111  return static_cast<linear_id_type>(get_local_range()[0]);
112 #else
113  throw runtime_error("Non-uniform groups are not supported on host device.",
114  PI_ERROR_INVALID_DEVICE);
115 #endif
116  }
117 
118  bool leader() const {
119 #ifdef __SYCL_DEVICE_ONLY__
120  uint32_t Lowest = static_cast<uint32_t>(Mask.find_low()[0]);
121  return __spirv_SubgroupLocalInvocationId() == Lowest;
122 #else
123  throw runtime_error("Non-uniform groups are not supported on host device.",
124  PI_ERROR_INVALID_DEVICE);
125 #endif
126  }
127 
128 protected:
130 
132 
133  friend tangle_group<ParentGroup> get_tangle_group<ParentGroup>(ParentGroup);
134 
135  friend sub_group_mask sycl::detail::GetMask<tangle_group<ParentGroup>>(
137 };
138 
139 template <typename Group>
140 inline std::enable_if_t<sycl::is_group_v<std::decay_t<Group>> &&
141  std::is_same_v<Group, sycl::sub_group>,
144  (void)group;
145 #ifdef __SYCL_DEVICE_ONLY__
146 #if defined(__SPIR__) || defined(__SPIRV__)
147  // All SPIR-V devices that we currently target execute in SIMD fashion,
148  // and so the group of work-items in converged control flow is implicit.
149  // We store the mask here because it is required to calculate IDs, not
150  // because it is required to construct the group.
152  return tangle_group<sycl::sub_group>(mask);
153 #elif defined(__NVPTX__)
154  // TODO: Construct from compiler-generated mask. Return an invalid group in
155  // in the meantime. CUDA devices will report false for the tangle_group
156  // support aspect so kernels launch should ensure this is never run.
158 #endif
159 #else
160  throw runtime_error("Non-uniform groups are not supported on host device.",
161  PI_ERROR_INVALID_DEVICE);
162 #endif
163 
164 } // namespace this_kernel
165 
166 template <typename ParentGroup>
167 struct is_user_constructed_group<tangle_group<ParentGroup>> : std::true_type {};
168 
169 } // namespace ext::oneapi::experimental
170 
171 template <typename ParentGroup>
172 struct is_group<ext::oneapi::experimental::tangle_group<ParentGroup>>
173  : std::true_type {};
174 
175 } // namespace _V1
176 } // namespace sycl
typename ParentGroup::linear_id_type linear_id_type
static constexpr sycl::memory_scope fence_scope
fence_scope
The scope that fence() operation should apply to.
Definition: common.hpp:350
std::enable_if_t< sycl::is_group_v< std::decay_t< Group > > &&std::is_same_v< Group, sycl::sub_group >, tangle_group< Group > > get_tangle_group(Group group)
std::enable_if_t< std::is_same_v< std::decay_t< Group >, sub_group >||std::is_same_v< std::decay_t< Group >, sycl::sub_group >, sub_group_mask > group_ballot(Group g, bool predicate=true)
Definition: access.hpp:18