DPC++ Runtime
Runtime libraries for oneAPI DPC++
annotated_ptr.hpp
Go to the documentation of this file.
1 //
2 //==----------- annotated_ptr.hpp - SYCL annotated_ptr extension -----------==//
3 //
4 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5 // See https://llvm.org/LICENSE.txt for license information.
6 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #pragma once
11 
12 #include <sycl/detail/defines.hpp>
20 #include <sycl/pointers.hpp>
21 
22 #include <cstddef>
23 #include <string_view>
24 #include <tuple>
25 #include <type_traits>
26 #include <utility>
27 #include <variant>
28 
29 namespace sycl {
30 inline namespace _V1 {
31 namespace ext {
32 namespace oneapi {
33 namespace experimental {
34 
35 template <typename T, typename PropertyListT = empty_properties_t>
37  // This should always fail when instantiating the unspecialized version.
38  static constexpr bool is_valid_property_list =
40  static_assert(is_valid_property_list, "Property list is invalid.");
41 };
42 
43 namespace detail {
44 template <class T> struct is_ann_ref_impl : std::false_type {};
45 template <class T, class P>
46 struct is_ann_ref_impl<annotated_ref<T, P>> : std::true_type {};
47 template <class T, class P>
48 struct is_ann_ref_impl<const annotated_ref<T, P>> : std::true_type {};
49 template <class T>
50 constexpr bool is_ann_ref_v =
52 
53 template <typename... Ts>
55  detail::ContainsProperty<alignment_key, std::tuple<Ts...>>;
56 
57 // properties filter
58 template <typename property_list, template <class...> typename filter>
60  sycl::detail::boost::mp11::mp_copy_if<property_list, filter>;
61 
62 // filter properties that are applied on annotations
63 template <typename... Props>
65  PropertiesFilter<std::tuple<Props...>, propagateToPtrAnnotation>>;
66 } // namespace detail
67 
68 template <typename I, typename P> struct annotationHelper {};
69 
70 // unpack properties to varadic template
71 template <typename I, typename... P>
72 struct annotationHelper<I, detail::properties_t<P...>> {
73  static I *annotate(I *ptr) {
74  return __builtin_intel_sycl_ptr_annotation(
77  }
78 
79  static I load(I *ptr) {
80  return *__builtin_intel_sycl_ptr_annotation(
83  }
84 
85  template <class O> static I store(I *ptr, O &&Obj) {
86  return *__builtin_intel_sycl_ptr_annotation(
88  detail::PropertyMetaInfo<P>::value...) = std::forward<O>(Obj);
89  }
90 };
91 
92 template <typename T, typename... Props>
93 class annotated_ref<T, detail::properties_t<Props...>> {
94  using property_list_t = detail::properties_t<Props...>;
95 
96  static_assert(
97  std::is_trivially_copyable_v<T>,
98  "annotated_ref can only encapsulate a trivially-copyable type!");
99 
100 private:
101  T *m_Ptr;
102  explicit annotated_ref(T *Ptr) : m_Ptr(Ptr) {}
103 
104 public:
105  annotated_ref(const annotated_ref &) = delete;
106 
107  // implicit conversion with annotaion
108  operator T() const {
109 #ifdef __SYCL_DEVICE_ONLY__
110  return annotationHelper<T, detail::annotation_filter<Props...>>::load(
111  m_Ptr);
112 #else
113  return *m_Ptr;
114 #endif
115  }
116 
117  // assignment operator with annotaion
118  template <class O, typename = std::enable_if_t<!detail::is_ann_ref_v<O>>>
119  T operator=(O &&Obj) const {
120 #ifdef __SYCL_DEVICE_ONLY__
121  return annotationHelper<T, detail::annotation_filter<Props...>>::store(
122  m_Ptr, Obj);
123 #else
124  return *m_Ptr = std::forward<O>(Obj);
125 #endif
126  }
127 
128  template <class O, class P>
129  T operator=(const annotated_ref<O, P> &Ref) const {
130  O t2 = Ref.operator O();
131  return *this = t2;
132  }
133 
134  // propagate compound operators
135 #define PROPAGATE_OP(op) \
136  template <class O, typename = std::enable_if_t<!detail::is_ann_ref_v<O>>> \
137  T operator op(O &&rhs) const { \
138  T t = this->operator T(); \
139  t op std::forward<O>(rhs); \
140  *this = t; \
141  return t; \
142  } \
143  template <class O, class P> \
144  T operator op(const annotated_ref<O, P> &rhs) const { \
145  T t = this->operator T(); \
146  O t2 = rhs.operator T(); \
147  t op t2; \
148  *this = t; \
149  return t; \
150  }
151  PROPAGATE_OP(+=)
152  PROPAGATE_OP(-=)
153  PROPAGATE_OP(*=)
154  PROPAGATE_OP(/=)
155  PROPAGATE_OP(%=)
156  PROPAGATE_OP(^=)
157  PROPAGATE_OP(&=)
158  PROPAGATE_OP(|=)
159  PROPAGATE_OP(<<=)
160  PROPAGATE_OP(>>=)
161 #undef PROPAGATE_OP
162 
163  // propagate binary operators
164 #define PROPAGATE_OP(op) \
165  template <class O> \
166  friend auto operator op(O &&a, const annotated_ref &b) \
167  ->decltype(std::forward<O>(a) op std::declval<T>()) { \
168  return std::forward<O>(a) op b.operator T(); \
169  } \
170  template <class O, typename = std::enable_if_t<!detail::is_ann_ref_v<O>>> \
171  friend auto operator op(const annotated_ref &a, O &&b) \
172  ->decltype(std::declval<T>() op std::forward<O>(b)) { \
173  return a.operator T() op std::forward<O>(b); \
174  }
175  PROPAGATE_OP(+)
176  PROPAGATE_OP(-)
177  PROPAGATE_OP(*)
178  PROPAGATE_OP(/)
179  PROPAGATE_OP(%)
180  PROPAGATE_OP(|)
181  PROPAGATE_OP(&)
182  PROPAGATE_OP(^)
183  PROPAGATE_OP(<<)
184  PROPAGATE_OP(>>)
185  PROPAGATE_OP(<)
186  PROPAGATE_OP(<=)
187  PROPAGATE_OP(>)
188  PROPAGATE_OP(>=)
189  PROPAGATE_OP(==)
190  PROPAGATE_OP(!=)
191  PROPAGATE_OP(&&)
192  PROPAGATE_OP(||)
193 #undef PROPAGATE_OP
194 
195 // Propagate unary operators
196 // by setting a default template we get SFINAE to kick in
197 #define PROPAGATE_OP(op) \
198  template <typename O = T> \
199  auto operator op() const->decltype(op std::declval<O>()) { \
200  return op this->operator O(); \
201  }
202  PROPAGATE_OP(+)
203  PROPAGATE_OP(-)
204  PROPAGATE_OP(!)
205  PROPAGATE_OP(~)
206 #undef PROPAGATE_OP
207 
208  // Propagate inc/dec operators
209  T operator++() const {
210  T t = this->operator T();
211  ++t;
212  *this = t;
213  return t;
214  }
215 
216  T operator++(int) const {
217  T t1 = this->operator T();
218  T t2 = t1;
219  t2++;
220  *this = t2;
221  return t1;
222  }
223 
224  T operator--() const {
225  T t = this->operator T();
226  --t;
227  *this = t;
228  return t;
229  }
230 
231  T operator--(int) const {
232  T t1 = this->operator T();
233  T t2 = t1;
234  t2--;
235  *this = t2;
236  return t1;
237  }
238 
239  template <class T2, class P2> friend class annotated_ptr;
240 };
241 
242 #ifdef __cpp_deduction_guides
243 template <typename T, typename... Args>
244 annotated_ptr(T *, Args...)
245  -> annotated_ptr<T, typename detail::DeducedProperties<Args...>::type>;
246 
247 template <typename T, typename old, typename... ArgT>
248 annotated_ptr(annotated_ptr<T, old>, properties<std::tuple<ArgT...>>)
249  -> annotated_ptr<
251 #endif // __cpp_deduction_guides
252 
253 template <typename T, typename PropertyListT = empty_properties_t>
255  // This should always fail when instantiating the unspecialized version.
256  static constexpr bool is_valid_property_list =
258  static_assert(is_valid_property_list, "Property list is invalid.");
259 };
260 
261 template <typename T, typename... Props>
263 __SYCL_TYPE(annotated_ptr) annotated_ptr<T, detail::properties_t<Props...>> {
264 
265  static_assert(std::is_same_v<T, void> || std::is_trivially_copyable_v<T>,
266  "annotated_ptr can only encapsulate either "
267  "a trivially-copyable type "
268  "or void!");
269 
271 
272  // annotated_ref type
273  using reference =
275 
276 #ifdef __ENABLE_USM_ADDR_SPACE__
277  using global_pointer_t = std::conditional_t<
280  std::conditional_t<
284 #else
286 #endif // __ENABLE_USM_ADDR_SPACE__
287 
288  T *m_Ptr;
289 
290  template <typename T2, typename PropertyListT> friend class annotated_ptr;
291 
292 #ifdef __SYCL_DEVICE_ONLY__
293  void __init([[__sycl_detail__::add_ir_attributes_kernel_parameter(
296  m_Ptr = Ptr;
297  }
298 #endif
299 
300 public:
301  annotated_ptr() noexcept = default;
302  annotated_ptr(const annotated_ptr &) = default;
303  annotated_ptr &operator=(const annotated_ptr &) = default;
304 
305  explicit annotated_ptr(T *Ptr,
307  : m_Ptr(Ptr) {}
308 
309  // Constructs an annotated_ptr object from a raw pointer and variadic
310  // properties. The new property set contains all properties of the input
311  // variadic properties. The same property in `Props...` and
312  // `PropertyValueTs...` must have the same property value.
313  template <typename... PropertyValueTs>
314  explicit annotated_ptr(T *Ptr, const PropertyValueTs &...props) noexcept
315  : m_Ptr(Ptr) {
316 
317  static constexpr bool has_same_properties = std::is_same<
320  decltype(properties{props...})>>::value;
321  static_assert(
322  has_same_properties,
323  "The property list must contain all properties of the input of the "
324  "constructor");
325  }
326 
327  // Constructs an annotated_ptr object from another annotated_ptr object.
328  // The new property set contains all properties of the input
329  // annotated_ptr object. The same property in `Props...` and `PropertyList2`
330  // must have the same property value.
331  template <typename T2, typename PropertyList2>
333  : m_Ptr(other.m_Ptr) {
334  static constexpr bool is_input_convertible =
335  std::is_convertible<T2 *, T *>::value;
336  static_assert(
337  is_input_convertible,
338  "The underlying pointer type of the input annotated_ptr is not "
339  "convertible to the target pointer type");
340 
341  static constexpr bool has_same_properties = std::is_same<
344  static_assert(
345  has_same_properties,
346  "The constructed annotated_ptr type must contain all the properties "
347  "of the input annotated_ptr");
348  }
349 
350  // Constructs an annotated_ptr object from another annotated_ptr object and
351  // a property list. The new property set is the union of property lists
352  // `PropertyListU` and `PropertyListV`. The same property in `PropertyListU`
353  // and `PropertyListV` must have the same property value.
354  template <typename T2, typename PropertyListU, typename PropertyListV>
356  const PropertyListV &) noexcept
357  : m_Ptr(other.m_Ptr) {
358  static constexpr bool is_input_convertible =
359  std::is_convertible<T2 *, T *>::value;
360  static_assert(
361  is_input_convertible,
362  "The underlying pointer type of the input annotated_ptr is not "
363  "convertible to the target pointer type");
364 
365  static constexpr bool has_same_properties = std::is_same<
368  static_assert(
369  has_same_properties,
370  "The property list of constructed annotated_ptr type must be the "
371  "union of the input property lists");
372  }
373 
375 
376  std::ptrdiff_t operator-(annotated_ptr other) const noexcept {
377  return m_Ptr - other.m_Ptr;
378  }
379 
380  explicit operator bool() const noexcept { return m_Ptr != nullptr; }
381 
382  operator T *() const noexcept = delete;
383 
384  T *get() const noexcept {
385 #ifdef __SYCL_DEVICE_ONLY__
386  return annotationHelper<T, detail::annotation_filter<Props...>>::annotate(
387  m_Ptr);
388 #else
389  return m_Ptr;
390 #endif
391  }
392 
393  // When the properties contain alignment, operator '[]', '+', '++' and '--'
394  // (both post- and prefix) are disabled. Calling these operators when
395  // alignment is present causes a compile error. Note that clang format is
396  // turned off for these operators to make sure the complete error notes are
397  // printed
398  // clang-format off
399  template <bool has_alignment = detail::contains_alignment<Props...>::value,
400  class = std::enable_if_t<!has_alignment>>
401  reference operator[](std::ptrdiff_t idx) const noexcept {
402  return reference(m_Ptr + idx);
403  }
404 
405  template <bool has_alignment = detail::contains_alignment<Props...>::value,
406  class = std::enable_if_t<has_alignment>>
407  auto operator[](std::ptrdiff_t idx) const noexcept -> decltype("operator[] is not available when alignment is specified!") = delete;
408 
409  template <bool has_alignment = detail::contains_alignment<Props...>::value,
410  class = std::enable_if_t<!has_alignment>>
411  annotated_ptr operator+(size_t offset) const noexcept {
412  return annotated_ptr(m_Ptr + offset);
413  }
414 
415  template <bool has_alignment = detail::contains_alignment<Props...>::value,
416  class = std::enable_if_t<has_alignment>>
417  auto operator+(size_t offset) const noexcept -> decltype("operator+ is not available when alignment is specified!") = delete;
418 
419  template <bool has_alignment = detail::contains_alignment<Props...>::value,
420  class = std::enable_if_t<!has_alignment>>
422  m_Ptr += 1;
423  return *this;
424  }
425 
426  template <bool has_alignment = detail::contains_alignment<Props...>::value,
427  class = std::enable_if_t<has_alignment>>
428  auto operator++() noexcept -> decltype("operator++ is not available when alignment is specified!") = delete;
429 
430  template <bool has_alignment = detail::contains_alignment<Props...>::value,
431  class = std::enable_if_t<!has_alignment>>
432  annotated_ptr operator++(int) noexcept {
433  auto tmp = *this;
434  m_Ptr += 1;
435  return tmp;
436  }
437 
438  template <bool has_alignment = detail::contains_alignment<Props...>::value,
439  class = std::enable_if_t<has_alignment>>
440  auto operator++(int) noexcept -> decltype("operator++ is not available when alignment is specified!") = delete;
441 
442  template <bool has_alignment = detail::contains_alignment<Props...>::value,
443  class = std::enable_if_t<!has_alignment>>
445  m_Ptr -= 1;
446  return *this;
447  }
448 
449  template <bool has_alignment = detail::contains_alignment<Props...>::value,
450  class = std::enable_if_t<has_alignment>>
451  auto operator--() noexcept -> decltype("operator-- is not available when alignment is specified!") = delete;
452 
453  template <bool has_alignment = detail::contains_alignment<Props...>::value,
454  class = std::enable_if_t<!has_alignment>>
455  annotated_ptr operator--(int) noexcept {
456  auto tmp = *this;
457  m_Ptr -= 1;
458  return tmp;
459  }
460 
461  template <bool has_alignment = detail::contains_alignment<Props...>::value,
462  class = std::enable_if_t<has_alignment>>
463  auto operator--(int) noexcept -> decltype("operator-- is not available when alignment is specified!") = delete;
464 
465  // clang-format on
466 
467  template <typename PropertyT> static constexpr bool has_property() {
468  return property_list_t::template has_property<PropertyT>();
469  }
470 
471  template <typename PropertyT> static constexpr auto get_property() {
472  return property_list_t::template get_property<PropertyT>();
473  }
474 
475  // *************************************************************************
476  // All static error checking is added here instead of placing inside neat
477  // functions to minimize the number lines printed out when an assert
478  // is triggered.
479  // static constexprs are used to ensure that the triggered assert prints
480  // a message that is very readable. Without these, the assert will
481  // print out long templated names
482  // *************************************************************************
483  static constexpr bool is_valid_property_list =
485  static_assert(is_valid_property_list, "Property list is invalid.");
486  static constexpr bool contains_valid_properties =
487  check_property_list<T *, Props...>::value;
488  static_assert(contains_valid_properties,
489  "The property list contains invalid property.");
490  // check the set if FPGA specificed properties are used
491  static constexpr bool hasValidFPGAProperties =
492  detail::checkValidFPGAPropertySet<Props...>::value;
493  static_assert(hasValidFPGAProperties,
494  "FPGA Interface properties (i.e. awidth, dwidth, etc.) "
495  "can only be set with BufferLocation together.");
496  // check if conduit and register_map properties are specified together
497  static constexpr bool hasConduitAndRegisterMapProperties =
498  detail::checkHasConduitAndRegisterMap<Props...>::value;
500  "The properties conduit and register_map cannot be "
501  "specified at the same time.");
502 };
503 
504 } // namespace experimental
505 } // namespace oneapi
506 } // namespace ext
507 } // namespace _V1
508 } // namespace sycl
#define PROPAGATE_OP(op)
Objects of the property_list class are containers for the SYCL properties.
#define __SYCL_SPECIAL_CLASS
Definition: defines.hpp:29
sycl::ext::oneapi::experimental::alignment_key alignment_key
The 'alignment' property is used to specify the alignment of memory accessed in ESIMD memory operatio...
sycl::detail::boost::mp11::mp_copy_if< property_list, filter > PropertiesFilter
typename merged_properties< LHSPropertiesT, RHSPropertiesT >::type merged_properties_t
Definition: properties.hpp:267
properties< std::tuple< PropertyValueTs... > > properties_t
Definition: properties.hpp:254
detail::ContainsProperty< alignment_key, std::tuple< Ts... > > contains_alignment
constexpr alignment_key::value_t< K > alignment
Definition: properties.hpp:75
annotated_ptr & operator++() noexcept
static constexpr bool has_property()
sycl::ext::oneapi::experimental::annotated_ref< T, property_list_t > reference
static constexpr bool hasValidFPGAProperties
std::ptrdiff_t operator-(annotated_ptr other) const noexcept
class __SYCL_SPECIAL_CLASS __SYCL_TYPE(annotated_arg) annotated_arg< T *
reference operator*() const noexcept
static constexpr bool is_valid_property_list
static constexpr auto get_property()
detail::properties_t< Props... > property_list_t
static constexpr bool is_valid_property_list
static constexpr bool contains_valid_properties
annotated_ptr & operator--() noexcept
T & operator[](std::ptrdiff_t idx) const noexcept
annotated_ptr operator+(size_t offset) const noexcept
static constexpr bool hasConduitAndRegisterMapProperties
typename decorated_global_ptr< T >::pointer global_pointer_t
Definition: access.hpp:18
_Abi const simd< _Tp, _Abi > & noexcept
Definition: simd.hpp:1324