DPC++ Runtime
Runtime libraries for oneAPI DPC++
simd_view_impl.hpp
Go to the documentation of this file.
1 //==------------ - simd_view_impl.hpp - DPC++ Explicit SIMD API ----------==//
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 // Implementation detail of Explicit SIMD vector view class.
9 //===----------------------------------------------------------------------===//
10 
11 #pragma once
12 
13 #include <sycl/aspects.hpp>
17 
18 namespace sycl {
19 inline namespace _V1 {
20 namespace ext::intel::esimd::detail {
21 
24 
39 template <typename BaseTy,
40  typename RegionTy =
41  region1d_t<typename BaseTy::element_type, BaseTy::length, 1>>
42 #ifndef __SYCL_DEVICE_ONLY__
44 #else
45 class [[__sycl_detail__::__uses_aspects__(
46  sycl::aspect::ext_intel_esimd)]] simd_view_impl {
47 #endif
48 public:
52 
53 protected:
55 
56  template <typename, int, class, class> friend class simd_obj_impl;
57  template <typename, int> friend class simd;
58  template <typename, typename> friend class simd_view_impl;
59  template <typename, int> friend class simd_mask_impl;
60 
61  static_assert(is_simd_obj_impl_derivative_v<BaseTy>);
62 
63 protected:
64  // Deduce the corresponding value type from its region type.
65  using ShapeTy = typename shape_type<RegionTy>::type;
66  static constexpr int length = ShapeTy::Size_x * ShapeTy::Size_y;
67 
68  using base_type = BaseTy;
69  template <typename ElT, int N>
70  using get_simd_t = construct_a_simd_type_t<base_type, ElT, N>;
71 
73  using region_type = RegionTy;
74 
76 
77 public:
80  using element_type = typename ShapeTy::element_type;
81 
83  using raw_element_type = __raw_t<element_type>;
84 
86  using value_type = get_simd_t<element_type, length>;
87 
89  using raw_vector_type = vector_type_t<__raw_t<element_type>, length>;
90 
91 private:
93 
94  Derived &cast_this_to_derived() { return reinterpret_cast<Derived &>(*this); }
95 
96 protected:
97  simd_view_impl(BaseTy &Base, RegionTy Region)
98  : M_base(Base), M_region(Region) {}
99 
100  simd_view_impl(BaseTy &Base) : M_base(Base), M_region(RegionTy(0)) {}
101 
103 
104 public:
106  simd_view_impl(const simd_view_impl &Other) = default;
107 
109  simd_view_impl(simd_view_impl &&Other) = default;
110 
116  template <typename ToTy, class T = BaseTy,
117  class = std::enable_if_t<is_simd_type_v<T>>>
118  inline operator simd<ToTy, length>() const {
119  if constexpr (std::is_same_v<element_type, ToTy>)
120  return read();
121  else
122  return convert_vector<ToTy, element_type, length>(read().data());
123  }
124 
128  template <class T = BaseTy, class = std::enable_if_t<is_simd_mask_type_v<T>>>
129  inline operator simd_mask_type<length>() const {
130  return read();
131  }
132 
134  static constexpr bool is1D() { return !ShapeTy::Is_2D; }
136  static constexpr bool is2D() { return ShapeTy::Is_2D; }
138  static constexpr int getSizeX() { return ShapeTy::Size_x; }
140  static constexpr int getStrideX() { return ShapeTy::Stride_x; }
142  static constexpr int getSizeY() { return ShapeTy::Size_y; }
144  static constexpr int getStrideY() { return ShapeTy::Stride_y; }
145 
148  constexpr uint16_t getOffsetX() const {
149  return getTopRegion(M_region).M_offset_x;
150  }
151 
154  constexpr uint16_t getOffsetY() const {
155  return getTopRegion(M_region).M_offset_y;
156  }
157 
161  value_type read() const {
162  using BT = typename BaseTy::element_type;
163  constexpr int BN = BaseTy::length;
164  return value_type{readRegion<BT, BN>(M_base.data(), M_region)};
165  }
166 
168  typename value_type::raw_vector_type data() const { return read().data(); }
169 
174  Derived &write(const value_type &Val) {
175  M_base.writeRegion(M_region, Val.data());
176  return cast_this_to_derived();
177  }
178 
184  void merge(const value_type &Val, const simd_mask_type<length> &Mask) {
185  merge(Val, read(), Mask);
186  }
187 
194  void merge(const value_type &Val1, value_type Val2,
195  const simd_mask_type<length> &Mask) {
196  Val2.merge(Val1, Mask);
197  write(Val2.read());
198  }
199 
205  template <typename EltTy> auto bit_cast_view() {
206  using TopRegionTy = detail::compute_format_type_t<Derived, EltTy>;
207  using NewRegionTy = std::pair<TopRegionTy, RegionTy>;
208  using RetTy = simd_view<BaseTy, NewRegionTy>;
209  TopRegionTy TopReg(0);
210  return RetTy{this->M_base, std::make_pair(TopReg, M_region)};
211  }
212 
223  template <typename EltTy, int Height, int Width> auto bit_cast_view() {
224  using TopRegionTy =
225  detail::compute_format_type_2d_t<Derived, EltTy, Height, Width>;
226  using NewRegionTy = std::pair<TopRegionTy, RegionTy>;
227  using RetTy = simd_view<BaseTy, NewRegionTy>;
228  TopRegionTy TopReg(0, 0);
229  return RetTy{this->M_base, std::make_pair(TopReg, M_region)};
230  }
231 
238  template <int Size, int Stride, typename T = Derived,
239  typename = std::enable_if_t<T::is1D()>>
240  auto select(uint16_t Offset = 0) {
241  using TopRegionTy = region1d_t<element_type, Size, Stride>;
242  using NewRegionTy = std::pair<TopRegionTy, RegionTy>;
243  using RetTy = simd_view<BaseTy, NewRegionTy>;
244  TopRegionTy TopReg(Offset);
245  return RetTy{this->M_base, std::make_pair(TopReg, M_region)};
246  }
247 
248  // clang-format off
287  // clang-format on
288  template <int SizeY, int StrideY, int SizeX, int StrideX,
289  typename T = Derived, typename = std::enable_if_t<T::is2D()>>
290  auto select(uint16_t OffsetY = 0, uint16_t OffsetX = 0) {
291  using TopRegionTy =
292  region2d_t<element_type, SizeY, StrideY, SizeX, StrideX>;
293  using NewRegionTy = std::pair<TopRegionTy, RegionTy>;
294  using RetTy = simd_view<BaseTy, NewRegionTy>;
295  TopRegionTy TopReg(OffsetY, OffsetX);
296  return RetTy{this->M_base, std::make_pair(TopReg, M_region)};
297  }
298 #define __ESIMD_DEF_SIMD_VIEW_IMPL_OPASSIGN(BINOP, OPASSIGN, COND) \
299  \
300  /* OPASSIGN simd_obj_impl */ \
301  template <class T1, int N1, class SimdT1, class T = element_type, \
302  class SimdT = BaseTy, \
303  class = \
304  std::enable_if_t<(is_simd_type_v<SimdT> == \
305  is_simd_type_v<SimdT1>)&&(N1 == length) && \
306  COND>> \
307  Derived &operator OPASSIGN(const simd_obj_impl<T1, N1, SimdT1> &RHS) { \
308  auto Res = read() BINOP RHS; \
309  write(Res); \
310  return cast_this_to_derived(); \
311  } \
312  \
313  /* OPASSIGN simd_view_impl */ \
314  template <class SimdT1, class RegionT1, \
315  class T1 = \
316  typename __ESIMD_NS::shape_type<RegionT1>::element_type, \
317  class T = element_type, class SimdT = BaseTy, \
318  class = std::enable_if_t< \
319  (is_simd_type_v<SimdT> == is_simd_type_v<SimdT1>)&&( \
320  length == __ESIMD_NS::shape_type<RegionT1>::length) && \
321  COND>> \
322  Derived &operator OPASSIGN(const simd_view_impl<SimdT1, RegionT1> &RHS) { \
323  *this OPASSIGN RHS.read(); \
324  return cast_this_to_derived(); \
325  } \
326  \
327  /* OPASSIGN scalar */ \
328  template <class T1, class T = element_type, class SimdT = BaseTy, \
329  class = std::enable_if_t<COND>> \
330  Derived &operator OPASSIGN(T1 RHS) { \
331  auto Res = read() BINOP RHS; \
332  write(Res); \
333  return cast_this_to_derived(); \
334  }
335 
336 #define __ESIMD_BITWISE_OP_FILTER std::is_integral_v<T> &&std::is_integral_v<T1>
341 #undef __ESIMD_BITWISE_OP_FILTER
342 
343 #define __ESIMD_SHIFT_OP_FILTER \
344  std::is_integral_v<T> &&std::is_integral_v<T1> &&is_simd_type_v<SimdT>
345 
348 #undef __ESIMD_SHIFT_OP_FILTER
349 
350 #define __ESIMD_ARITH_OP_FILTER \
351  is_valid_simd_elem_type_v<T> &&is_valid_simd_elem_type_v<T1> \
352  &&is_simd_type_v<SimdT>
353 
358 
359 #undef __ESIMD_ARITH_OP_FILTER
360 #undef __ESIMD_DEF_SIMD_VIEW_IMPL_OPASSIGN
361 
362 #define __ESIMD_DEF_UNARY_OP(UNARY_OP, COND) \
363  template <class T = element_type, class SimdT = BaseTy, \
364  class = std::enable_if_t<COND>> \
365  auto operator UNARY_OP() { \
366  auto V = UNARY_OP(read().data()); \
367  return get_simd_t<element_type, length>(V); \
368  }
369  __ESIMD_DEF_UNARY_OP(~, std::is_integral_v<T> &&is_simd_type_v<SimdT>)
370  __ESIMD_DEF_UNARY_OP(+, is_simd_type_v<SimdT>)
371  __ESIMD_DEF_UNARY_OP(-, is_simd_type_v<SimdT>)
372 
373 #undef __ESIMD_DEF_UNARY_OP
374 
376  template <class T = element_type,
377  class = std::enable_if_t<std::is_integral_v<T>>>
378  auto operator!() {
379  using MaskVecT = typename simd_mask_type<length>::raw_vector_type;
380  auto V = read().data() == 0;
381  return simd_mask_type<length>{__builtin_convertvector(V, MaskVecT) &
382  MaskVecT(1)};
383  }
384 
388  return write(Other.read());
389  }
390 
395  Derived &operator=(const Derived &Other) { return write(Other.read()); }
396 
401  Derived &operator=(const value_type &Val) { return write(Val); }
402 
408  __esimd_move_test_proxy(Other);
409  return write(Other.read());
410  }
411 
414  __esimd_move_test_proxy(Other);
415  return write(Other.read());
416  }
417 
426  template <class T, int N, class SimdT,
427  class = std::enable_if_t<(is_simd_type_v<SimdT> ==
428  is_simd_type_v<BaseTy>)&&(length ==
429  SimdT::length)>>
431  return write(convert_vector<element_type, typename SimdT::element_type, N>(
432  Other.data()));
433  }
434 
440  template <class T1, class = std::enable_if_t<is_valid_simd_elem_type_v<T1>>>
441  Derived &operator=(T1 RHS) {
442  return write(value_type(convert_scalar<element_type>(RHS)));
443  }
444 
448  *this += 1;
449  return cast_this_to_derived();
450  }
451 
456  value_type Ret(read());
457  operator++();
458  return Ret;
459  }
460 
464  *this -= 1;
465  return cast_this_to_derived();
466  }
467 
472  value_type Ret(read());
473  operator--();
474  return Ret;
475  }
476 
480  template <typename T = Derived, typename = std::enable_if_t<T::is2D()>>
481  auto row(int i) {
482  return select<1, 1, getSizeX(), 1>(i, 0)
483  .template bit_cast_view<element_type>();
484  }
485 
490  template <typename T = Derived, typename = std::enable_if_t<T::is2D()>>
491  auto column(int i) {
492  return select<getSizeY(), 1, 1, 1>(0, i);
493  }
494 
498  template <typename T = Derived, typename = std::enable_if_t<T::is1D()>>
499  element_type operator[](int i) const {
500  const auto v = read();
501  return v[i];
502  }
503 
507  template <typename T = Derived, typename = std::enable_if_t<T::is1D()>>
508  auto operator[](int i) {
509  return select<1, 1>(i);
510  }
511 
513  template <int Rep> get_simd_t<element_type, Rep> replicate() {
514  return read().template replicate<Rep>();
515  }
516 
520  template <int Rep, int W>
521  get_simd_t<element_type, Rep * W> replicate_w(uint16_t OffsetX) {
522  return replicate_vs_w<Rep, 0, W>(0, OffsetX);
523  }
524 
528  template <int Rep, int W>
529  get_simd_t<element_type, Rep * W> replicate_w(uint16_t OffsetY,
530  uint16_t OffsetX) {
531  return replicate_vs_w<Rep, 0, W>(OffsetY, OffsetX);
532  }
533 
534  // clang-format off
538  // clang-format on
539  template <int Rep, int VS, int W>
540  get_simd_t<element_type, Rep * W> replicate_vs_w(uint16_t OffsetX) {
541  return replicate_vs_w_hs<Rep, VS, W, 1>(0, OffsetX);
542  }
543 
544  // clang-format off
548  // clang-format on
549  template <int Rep, int VS, int W>
550  get_simd_t<element_type, Rep * W> replicate_vs_w(uint16_t OffsetY,
551  uint16_t OffsetX) {
552  return replicate_vs_w_hs<Rep, VS, W, 1>(OffsetY, OffsetX);
553  }
554 
557  template <int Rep, int VS, int W, int HS>
558  get_simd_t<element_type, Rep * W> replicate_vs_w_hs(uint16_t OffsetX) {
559  return read().template replicate_vs_w_hs<Rep, VS, W, HS>(OffsetX);
560  }
561 
566  template <int Rep, int VS, int W, int HS>
567  get_simd_t<element_type, Rep * W> replicate_vs_w_hs(uint16_t OffsetY,
568  uint16_t OffsetX) {
569  constexpr int RowSize = is2D() ? getSizeX() : 0;
570  return read().template replicate_vs_w_hs<Rep, VS, W, HS>(OffsetY * RowSize +
571  OffsetX);
572  }
573 
575  template <typename T1 = element_type, typename T2 = BaseTy,
576  typename = std::enable_if_t<std::is_integral_v<T1>, T2>>
577  uint16_t any() {
578  return read().any();
579  }
580 
582  template <typename T1 = element_type, typename T2 = BaseTy,
583  typename = std::enable_if_t<std::is_integral_v<T1>, T2>>
584  uint16_t all() {
585  return read().all();
586  }
587 
589 public:
590  // Getter for the test proxy member, if enabled
591  __ESIMD_DECLARE_TEST_PROXY_ACCESS
592 
593 protected:
594  // The reference to the base object, which must be a simd object
595  BaseTy &M_base;
596 
597  // The test proxy if enabled
598  __ESIMD_DECLARE_TEST_PROXY
599 
600  // The region applied on the base object. Its type could be
601  // - region1d_t
602  // - region2d_t
603  // - std::pair<top_region_type, base_region_type>
604  //
605  RegionTy M_region;
607 };
608 
610 
611 } // namespace ext::intel::esimd::detail
612 } // namespace _V1
613 } // namespace sycl
This class is a simd_obj_impl specialization representing a simd mask, which is basically a simd_obj_...
This is a base class for all ESIMD simd classes with real storage (simd, simd_mask_impl).
static constexpr bool is2D()
Tells whether this view is 2-dimensional.
simd_view_impl(const simd_view_impl &Other)=default
Default copy constructor.
auto select(uint16_t Offset=0)
1D region select.
get_simd_t< element_type, Rep *W > replicate_vs_w(uint16_t OffsetX)
Shortcut to replicate_vs_w_hs<int Rep, int VS, int W, int Hs>(uint16_t OffsetY, uint16_t OffsetX) wit...
get_simd_t< element_type, Rep > replicate()
Applies simd_obj_impl::replicate to the target region.
static constexpr int getStrideX()
Get element stride of the view along X dimension.
auto bit_cast_view()
Create a 1-dimensional view of the target region.
constexpr uint16_t getOffsetY() const
Get the offset of the first element of the view within the parent object along Y dimension.
constexpr uint16_t getOffsetX() const
Get the offset of the first element of the view within the parent object along X dimension.
get_simd_t< element_type, Rep *W > replicate_vs_w_hs(uint16_t OffsetX)
Applies simd_obj_impl::replicate_vs_w_hs<int Rep, int VS, int W, int HS> to the target region.
auto operator!()
Unary logical negeation operator. Applies only to integer element types.
static constexpr int getStrideY()
Get element stride of the view along Y dimension.
get_simd_t< element_type, length > value_type
The simd type of the viewed region of the target object.
Derived & operator=(T1 RHS)
Broadcast assignment of a scalar with conversion.
auto operator[](int i)
Return a writeable view of a single element in the target 1D region.
void merge(const value_type &Val, const simd_mask_type< length > &Mask)
"Merges" the viewed target's region with given value according to a per-element mask.
Derived & operator=(Derived &&Other)
Assignment from an rvalue object of the derived class.
element_type operator[](int i) const
Read a single element from the target 1D region.
Derived & operator=(const value_type &Val)
Assignment from a value_type object - simd or simd_mask.
void merge(const value_type &Val1, value_type Val2, const simd_mask_type< length > &Mask)
"Merges" given values according to a per-element mask and writes the result to the viewed target's re...
get_simd_t< element_type, Rep *W > replicate_vs_w_hs(uint16_t OffsetY, uint16_t OffsetX)
Applies simd_obj_impl::replicate_vs_w_hs<int Rep, int VS, int W, int HS> to the target region.
auto row(int i)
Reference a row from a 2D region.
Derived & operator=(const Derived &Other)
Assignment from an object of the derived class.
simd_view_impl(simd_view_impl &&Other)=default
Default move constructor.
auto bit_cast_view()
Create a 2-dimensional view of the target region.
Derived & operator=(const simd_obj_impl< T, N, SimdT > &Other)
Assignment with element type conversion from a vector object.
value_type read() const
Reads the viewed region from the target w/o any conversion and returns as an object of the value_type...
Derived & write(const value_type &Val)
Assigns a new value to the viewed target's region.
simd_view_impl & operator=(simd_view_impl &&Other)
Move assignment operator. Updates the target region viewed by this object.
simd_view< BaseTy, RegionTy > Derived
The only type which is supposed to extend this one and be used in user code.
auto select(uint16_t OffsetY=0, uint16_t OffsetX=0)
2D region select.
static constexpr int getSizeY()
Get number of elements in the view along Y dimension.
uint16_t any()
Applies simd_obj_impl::any operation to the target region.
get_simd_t< element_type, Rep *W > replicate_vs_w(uint16_t OffsetY, uint16_t OffsetX)
Shortcut to replicate_vs_w_hs<int Rep, int VS, int W, int Hs>(uint16_t OffsetY, uint16_t OffsetX) wit...
uint16_t all()
Applies simd_obj_impl::all operation to the target region.
__raw_t< element_type > raw_element_type
Corresponding "raw" (storage) type for the element type.
static constexpr int getSizeX()
Get number of elements in the view along X dimension.
simd_view_impl & operator=(const simd_view_impl &Other)
Copy assignment.
get_simd_t< element_type, Rep *W > replicate_w(uint16_t OffsetX)
Shortcut to replicate_vs_w<int Rep, int Vs, int W>(uint16_t) with with Vs = 0.
static constexpr bool is1D()
Tells whether this view is 1-dimensional.
auto column(int i)
Reference a column from a 2D region.
get_simd_t< element_type, Rep *W > replicate_w(uint16_t OffsetY, uint16_t OffsetX)
Shortcut to replicate_vs_w<int Rep, int Vs, int W>(uint16_t, uint16_t) with Vs = 0.
typename ShapeTy::element_type element_type
Element type of this view, may differ from the element type of the target object.
vector_type_t< __raw_t< element_type >, length > raw_vector_type
The underlying builtin vector type of the the viewed region.
This class represents a reference to a sub-region of a base simd object.
Definition: simd_view.hpp:37
The main simd vector class.
Definition: simd.hpp:53
Definition: access.hpp:18
ValueT length(const ValueT *a, const int len)
Calculate the square root of the input array.
Definition: math.hpp:161
#define __ESIMD_SHIFT_OP_FILTER
#define __ESIMD_DEF_UNARY_OP(UNARY_OP, COND)
#define __ESIMD_BITWISE_OP_FILTER
#define __ESIMD_ARITH_OP_FILTER
#define __ESIMD_DEF_SIMD_VIEW_IMPL_OPASSIGN(BINOP, OPASSIGN, COND)