DPC++ Runtime
Runtime libraries for oneAPI DPC++
annotated_arg.hpp
Go to the documentation of this file.
1 //==----------- annotated_arg.hpp - SYCL annotated_arg extension -----------==//
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/defines.hpp>
16 #include <sycl/pointers.hpp>
17 
18 #include <cstddef>
19 #include <type_traits>
20 #include <utility>
21 #include <variant>
22 
23 namespace sycl {
24 
25 // device_copyable trait
26 template <typename T, typename PropertyList>
28  ext::oneapi::experimental::annotated_arg<T, PropertyList>>
29  : is_device_copyable<T> {};
30 
31 inline namespace _V1 {
32 namespace ext {
33 namespace oneapi {
34 namespace experimental {
35 
36 namespace detail {
37 
38 // Type-trait for checking if a type defines `operator[]`.
39 template <typename T>
41  : std::bool_constant<
42  !std::is_void_v<decltype(std::declval<T>().operator[](0))>> {};
43 
44 template <class T> struct is_ann_arg_impl : std::false_type {};
45 template <class T, class P>
46 struct is_ann_arg_impl<annotated_arg<T, P>> : std::true_type {};
47 template <class T, class P>
48 struct is_ann_arg_impl<const annotated_arg<T, P>> : std::true_type {};
49 template <class T>
50 constexpr bool is_ann_arg_v =
52 
53 template <class T> struct GetUnderlyingTImpl;
54 template <class T, class P> struct GetUnderlyingTImpl<annotated_arg<T, P>> {
55  using type = T;
56 };
57 template <class T>
59  std::remove_cv_t<std::remove_reference_t<T>>>::type;
60 
61 } // namespace detail
62 
63 // Deduction guide
64 template <typename T, typename... Args>
65 annotated_arg(T, Args...)
66  -> annotated_arg<T, typename detail::DeducedProperties<Args...>::type>;
67 
68 template <typename T, typename old, typename... ArgT>
70  -> annotated_arg<
72 
73 template <typename T, typename PropertyListT = empty_properties_t>
75  // This should always fail when instantiating the unspecialized version.
76  static constexpr bool is_valid_property_list =
78  static_assert(is_valid_property_list, "Property list is invalid.");
79 };
80 
81 // Partial specialization for pointer type
82 template <typename T, typename... Props>
85  using property_list_t = detail::properties_t<Props...>;
86 
87  T *obj;
88 
89  template <typename T2, typename PropertyListT> friend class annotated_arg;
90 
91 #ifdef __ENABLE_USM_ADDR_SPACE__
92  using global_pointer_t = std::conditional_t<
95  std::conditional_t<
99 #else // __ENABLE_USM_ADDR_SPACE__
101 #endif // __ENABLE_USM_ADDR_SPACE__
102 
103 #ifdef __SYCL_DEVICE_ONLY__
104  void __init([[__sycl_detail__::add_ir_attributes_kernel_parameter(
107  obj = _obj;
108  }
109 #endif
110 
111 public:
112  annotated_arg() noexcept = default;
113  annotated_arg(const annotated_arg &) = default;
114  annotated_arg &operator=(annotated_arg &) = default;
115 
116  annotated_arg(T *_ptr,
117  const property_list_t &PropList = property_list_t{}) noexcept
118  : obj(_ptr) {
119  (void)PropList;
120  }
121 
122  // Constructs an annotated_arg object from a raw pointer and variadic
123  // properties. The new property set contains all properties of the input
124  // variadic properties. The same property in `Props...` and
125  // `PropertyValueTs...` must have the same property value.
126  template <typename... PropertyValueTs>
127  annotated_arg(T *_ptr, const PropertyValueTs &...props) noexcept : obj(_ptr) {
128  static constexpr bool has_same_properties = std::is_same<
131  decltype(properties{props...})>>::value;
132  static_assert(
133  has_same_properties,
134  "The property list must contain all properties of the input of the "
135  "constructor");
136  }
137 
138  // Constructs an annotated_arg object from another annotated_arg object.
139  // The new property set contains all properties of the input
140  // annotated_arg object. The same property in `Props...` and `PropertyList2`
141  // must have the same property value.
142  template <typename T2, typename PropertyList2>
144  : obj(other.obj) {
145  static constexpr bool is_input_convertible =
146  std::is_convertible<T2, T *>::value;
147  static_assert(is_input_convertible,
148  "The underlying data type of the input annotated_arg is not "
149  "compatible");
150 
151  static constexpr bool has_same_properties = std::is_same<
154  static_assert(
155  has_same_properties,
156  "The constructed annotated_arg type must contain all the properties "
157  "of the input annotated_arg");
158  }
159 
160  // Constructs an annotated_arg object from another annotated_arg object and a
161  // property list. The new property set is the union of property lists
162  // `PropertyListU` and `PropertyListV`. The same property in `PropertyListU`
163  // and `PropertyListV` must have the same property value.
164  template <typename T2, typename PropertyListU, typename PropertyListV>
166  const PropertyListV &proplist) noexcept
167  : obj(other.obj) {
168  (void)proplist;
169  static constexpr bool is_input_convertible =
170  std::is_convertible<T2, T *>::value;
171  static_assert(is_input_convertible,
172  "The underlying data type of the input annotated_arg is not "
173  "compatible");
174 
175  static constexpr bool has_same_properties = std::is_same<
178  static_assert(
179  has_same_properties,
180  "The property list of constructed annotated_arg type must be the union "
181  "of the input property lists");
182  }
183 
184  operator T *() noexcept { return obj; }
185  operator T *() const noexcept { return obj; }
186 
187  T &operator[](std::ptrdiff_t idx) const noexcept { return obj[idx]; }
188 
189  T *operator->() const noexcept { return obj; }
190 
191  template <typename PropertyT> static constexpr bool has_property() {
192  return property_list_t::template has_property<PropertyT>();
193  }
194 
195  template <typename PropertyT> static constexpr auto get_property() {
196  return property_list_t::template get_property<PropertyT>();
197  }
198 
199  // *************************************************************************
200  // All static error checking is added here instead of placing inside neat
201  // functions to minimize the number lines printed out when an assert
202  // is triggered.
203  // static constexprs are used to ensure that the triggered assert prints
204  // a message that is very readable. Without these, the assert will
205  // print out long templated names
206  // *************************************************************************
207  static constexpr bool is_valid_property_list =
209  static_assert(is_valid_property_list, "Property list is invalid.");
210  static constexpr bool contains_valid_properties =
211  check_property_list<T *, Props...>::value;
212  static_assert(contains_valid_properties,
213  "The property list contains invalid property.");
214  // check the set if FPGA specificed properties are used
215  static constexpr bool hasValidFPGAProperties =
216  detail::checkValidFPGAPropertySet<Props...>::value;
217  static_assert(hasValidFPGAProperties,
218  "FPGA Interface properties (i.e. awidth, dwidth, etc.) "
219  "can only be set with BufferLocation together.");
220  // check if conduit and register_map properties are specified together
221  static constexpr bool hasConduitAndRegisterMapProperties =
222  detail::checkHasConduitAndRegisterMap<Props...>::value;
224  "The properties conduit and register_map cannot be "
225  "specified at the same time.");
226 };
227 
228 // Partial specialization for non-pointer type
229 template <typename T, typename... Props>
231 __SYCL_TYPE(annotated_arg) annotated_arg<T, detail::properties_t<Props...>> {
232  using property_list_t = detail::properties_t<Props...>;
233  using UnderlyingT = T;
234 
235  template <typename T2, typename PropertyListT> friend class annotated_arg;
236 
237  T obj;
238 
239 #ifdef __SYCL_DEVICE_ONLY__
240  void __init([[__sycl_detail__::add_ir_attributes_kernel_parameter(
243  obj = _obj;
244  }
245 #endif
246 
247 public:
248  annotated_arg() noexcept = default;
249  annotated_arg(const annotated_arg &) = default;
250  annotated_arg &operator=(annotated_arg &) = default;
251 
252  annotated_arg(const T &_obj,
253  const property_list_t &PropList = property_list_t{}) noexcept
254  : obj(_obj) {
255  (void)PropList;
256  }
257 
258  // Constructs an annotated_arg object from a raw pointer and variadic
259  // properties. The new property set contains all properties of the input
260  // variadic properties. The same property in `Props...` and
261  // `PropertyValueTs...` must have the same property value.
262  template <typename... PropertyValueTs>
263  annotated_arg(const T &_obj, PropertyValueTs... props) noexcept : obj(_obj) {
264  static constexpr bool has_same_properties = std::is_same<
267  decltype(properties{props...})>>::value;
268  static_assert(
269  has_same_properties,
270  "The property list must contain all properties of the input of the "
271  "constructor");
272  }
273 
274  // Constructs an annotated_arg object from another annotated_arg object.
275  // The new property set contains all properties of the input
276  // annotated_arg object. The same property in `Props...` and `PropertyList2`
277  // must have the same property value.
278  template <typename T2, typename PropertyList2>
279  explicit annotated_arg(const annotated_arg<T2, PropertyList2> &other) noexcept
280  : obj(other.obj) {
281  static constexpr bool is_input_convertible =
282  std::is_convertible<T2, T>::value;
283  static_assert(is_input_convertible,
284  "The underlying data type of the input annotated_arg is not "
285  "compatible");
286 
287  static constexpr bool has_same_properties = std::is_same<
289  detail::merged_properties_t<property_list_t, PropertyList2>>::value;
290  static_assert(
291  has_same_properties,
292  "The constructed annotated_arg type must contain all the properties "
293  "of the input annotated_arg");
294  }
295 
296  // Constructs an annotated_arg object from another annotated_arg object and a
297  // property list. The new property set is the union of property lists
298  // `PropertyListU` and `PropertyListV`. The same property in `PropertyListU`
299  // and `PropertyListV` must have the same property value.
300  template <typename T2, typename PropertyListU, typename PropertyListV>
301  explicit annotated_arg(const annotated_arg<T2, PropertyListU> &other,
302  const PropertyListV &proplist) noexcept
303  : obj(other.obj) {
304  (void)proplist;
305  static constexpr bool is_input_convertible =
306  std::is_convertible<T2, T>::value;
307  static_assert(is_input_convertible,
308  "The underlying data type of the input annotated_arg is not "
309  "compatible");
310 
311  static constexpr bool has_same_properties = std::is_same<
313  detail::merged_properties_t<PropertyListU, PropertyListV>>::value;
314  static_assert(
315  has_same_properties,
316  "The property list of constructed annotated_arg type must be the union "
317  "of the input property lists");
318  }
319 
320  operator T() noexcept { return obj; }
321  operator T() const noexcept { return obj; }
322 
323  template <class RelayT = T>
324  std::enable_if_t<detail::HasSubscriptOperator<RelayT>::value,
325  decltype(std::declval<RelayT>().operator[](0))> &
326  operator[](std::ptrdiff_t idx) const noexcept {
327  return obj.operator[](idx);
328  }
329 
330  template <typename PropertyT> static constexpr bool has_property() {
331  return property_list_t::template has_property<PropertyT>();
332  }
333 
334  template <typename PropertyT> static constexpr auto get_property() {
335  return property_list_t::template get_property<PropertyT>();
336  }
337 
338 // propagate binary operators
339 #define PROPAGATE_OP(op) \
340  template <class O> friend auto operator op(O &&a, const annotated_arg &b) { \
341  if constexpr (!detail::is_ann_arg_v<O>) \
342  return std::forward<O>(a) op b.operator T(); \
343  else \
344  return a.operator detail::GetUnderlyingT<O>() op b.operator T(); \
345  } \
346  template <class O, typename = std::enable_if_t<!detail::is_ann_arg_v<O>>> \
347  friend auto operator op(const annotated_arg &a, O &&b) \
348  -> decltype(std::declval<T>() op std::forward<O>(b)) { \
349  return a.operator T() op std::forward<O>(b); \
350  }
351  PROPAGATE_OP(+)
352  PROPAGATE_OP(-)
353  PROPAGATE_OP(*)
354  PROPAGATE_OP(/)
355  PROPAGATE_OP(%)
356  PROPAGATE_OP(|)
357  PROPAGATE_OP(&)
358  PROPAGATE_OP(^)
359  PROPAGATE_OP(<<)
360  PROPAGATE_OP(>>)
361  PROPAGATE_OP(<)
362  PROPAGATE_OP(<=)
363  PROPAGATE_OP(>)
364  PROPAGATE_OP(>=)
365  PROPAGATE_OP(==)
366  PROPAGATE_OP(!=)
367  PROPAGATE_OP(&&)
368  PROPAGATE_OP(||)
369 #undef PROPAGATE_OP
370 
371 // Propagate unary operators
372 // by setting a default template we get SFINAE to kick in
373 #define PROPAGATE_OP(op) \
374  template <typename O = T> \
375  auto operator op() const -> decltype(op std::declval<O>()) { \
376  return op this->operator O(); \
377  }
378  PROPAGATE_OP(+)
379  PROPAGATE_OP(-)
380  PROPAGATE_OP(!)
381  PROPAGATE_OP(~)
382 #undef PROPAGATE_OP
383 
384  // *************************************************************************
385  // All static error checking is added here instead of placing inside neat
386  // functions to minimize the number lines printed out when an assert
387  // is triggered.
388  // static constexprs are used to ensure that the triggered assert prints
389  // a message that is very readable. Without these, the assert will
390  // print out long templated names
391  // *************************************************************************
392  static constexpr bool is_device_copyable = is_device_copyable_v<T>;
393  static_assert(is_device_copyable, "Type T must be device copyable.");
394 
395  // check if invalid properties are specified for non pointer type
396  static constexpr bool has_buffer_location =
397  has_property<buffer_location_key>();
398  static_assert(!has_buffer_location,
399  "Property buffer_location cannot be specified for "
400  "annotated_arg<T> when T is a non pointer type.");
401 
402  static constexpr bool has_awidth = has_property<awidth_key>();
403  static_assert(!has_awidth, "Property awidth cannot be specified for "
404  "annotated_arg<T> when T is a non pointer type.");
405 
406  static constexpr bool has_dwidth = has_property<dwidth_key>();
407  static_assert(!has_dwidth, "Property dwidth cannot be specified for "
408  "annotated_arg<T> when T is a non pointer type.");
409 
410  static constexpr bool has_latency = has_property<latency_key>();
411  static_assert(!has_latency, "Property latency cannot be specified for "
412  "annotated_arg<T> when T is a non pointer type.");
413 
414  static constexpr bool has_read_write_mode =
415  has_property<read_write_mode_key>();
416  static_assert(!has_read_write_mode,
417  "Property read_write_mode cannot be specified for "
418  "annotated_arg<T> when T is a non pointer type.");
419 
420  static constexpr bool has_maxburst = has_property<maxburst_key>();
421  static_assert(!has_maxburst,
422  "Property maxburst cannot be specified for "
423  "annotated_arg<T> when T is a non pointer type.");
424 
425  static constexpr bool has_wait_request = has_property<wait_request_key>();
426  static_assert(!has_wait_request,
427  "Property wait_request cannot be specified for "
428  "annotated_arg<T> when T is a non pointer type.");
429 
430  static constexpr bool has_alignment = has_property<alignment_key>();
431  static_assert(!has_alignment,
432  "Property alignment cannot be specified for "
433  "annotated_arg<T> when T is a non pointer type.");
434 
435  static constexpr bool has_usm_kind = has_property<usm_kind_key>();
436  static_assert(!has_usm_kind,
437  "Property usm_kind cannot be specified for "
438  "annotated_arg<T> when T is a non pointer type.");
439 
440  static constexpr bool is_valid_property_list =
442  static_assert(is_valid_property_list, "Property list is invalid.");
443  static constexpr bool contains_valid_properties =
444  check_property_list<T, Props...>::value;
445  static_assert(contains_valid_properties,
446  "The property list contains invalid property.");
447  // check the set if FPGA specificed properties are used
448  static constexpr bool hasValidFPGAProperties =
449  detail::checkValidFPGAPropertySet<Props...>::value;
450  static_assert(hasValidFPGAProperties,
451  "FPGA Interface properties (i.e. awidth, dwidth, etc.) "
452  "can only be set with BufferLocation together.");
453  // check if conduit and register_map properties are specified together
454  static constexpr bool hasConduitAndRegisterMapProperties =
455  detail::checkHasConduitAndRegisterMap<Props...>::value;
457  "The properties conduit and register_map cannot be "
458  "specified at the same time.");
459 };
460 
461 } // namespace experimental
462 } // namespace oneapi
463 } // namespace ext
464 } // namespace _V1
465 } // namespace sycl
#define PROPAGATE_OP(op)
#define __SYCL_SPECIAL_CLASS
Definition: defines.hpp:29
typename GetUnderlyingTImpl< std::remove_cv_t< std::remove_reference_t< T > >>::type GetUnderlyingT
typename merged_properties< LHSPropertiesT, RHSPropertiesT >::type merged_properties_t
Definition: properties.hpp:267
properties< std::tuple< PropertyValueTs... > > properties_t
Definition: properties.hpp:254
annotated_arg(const T &_obj, PropertyValueTs... props) noexcept
static constexpr bool has_property()
static constexpr bool hasValidFPGAProperties
class __SYCL_SPECIAL_CLASS __SYCL_TYPE(annotated_arg) annotated_arg< T *
static constexpr bool is_valid_property_list
static constexpr bool has_buffer_location
static constexpr bool has_wait_request
static constexpr auto get_property()
detail::properties_t< Props... > property_list_t
static constexpr bool contains_valid_properties
T & operator[](std::ptrdiff_t idx) const noexcept
static constexpr bool hasConduitAndRegisterMapProperties
static constexpr bool has_read_write_mode
typename decorated_global_ptr< T >::pointer global_pointer_t
Definition: access.hpp:18
_Abi const simd< _Tp, _Abi > & noexcept
Definition: simd.hpp:1324
is_device_copyable is a user specializable class template to indicate that a type T is device copyabl...