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