RAJA
RAJA provides a collection of platform portability abstractions for C++ HPC applications.
avx512_int32.hpp
Go to the documentation of this file.
1 
11 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
12 // Copyright (c) Lawrence Livermore National Security, LLC and other
13 // RAJA Project Developers. See top-level LICENSE and COPYRIGHT
14 // files for dates and other details. No copyright assignment is required
15 // to contribute to RAJA.
16 //
17 // SPDX-License-Identifier: (BSD-3-Clause)
18 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
19 
20 #ifdef __AVX512F__
21 
22 #ifndef RAJA_policy_vector_register_avx512_int32_HPP
23 #define RAJA_policy_vector_register_avx512_int32_HPP
24 
25 #include "RAJA/config.hpp"
26 #include "RAJA/util/macros.hpp"
28 
29 // Include SIMD intrinsics header file
30 #include <immintrin.h>
31 #include <cmath>
32 
33 namespace RAJA
34 {
35 namespace expt
36 {
37 template<>
38 class Register<int32_t, avx512_register>
39  : public internal::expt::RegisterBase<Register<int32_t, avx512_register>>
40 {
41 public:
42  using base_type =
43  internal::expt::RegisterBase<Register<int32_t, avx512_register>>;
44 
45  using register_policy = avx512_register;
46  using self_type = Register<int32_t, avx512_register>;
47  using element_type = int32_t;
48  using register_type = __m512i;
49 
50  using int_vector_type = Register<int32_t, avx512_register>;
51 
52 
53 private:
54  register_type m_value;
55 
56  RAJA_INLINE
57  __mmask16 createMask(camp::idx_t N) const
58  {
59  // Generate a mask
60  switch (N)
61  {
62  case 0:
63  return __mmask16(0x0000);
64  case 1:
65  return __mmask16(0x0001);
66  case 2:
67  return __mmask16(0x0003);
68  case 3:
69  return __mmask16(0x0007);
70  case 4:
71  return __mmask16(0x000F);
72  case 5:
73  return __mmask16(0x001F);
74  case 6:
75  return __mmask16(0x003F);
76  case 7:
77  return __mmask16(0x007F);
78  case 8:
79  return __mmask16(0x00FF);
80  case 9:
81  return __mmask16(0x01FF);
82  case 10:
83  return __mmask16(0x03FF);
84  case 11:
85  return __mmask16(0x07FF);
86  case 12:
87  return __mmask16(0x0FFF);
88  case 13:
89  return __mmask16(0x1FFF);
90  case 14:
91  return __mmask16(0x3FFF);
92  case 15:
93  return __mmask16(0x7FFF);
94  case 16:
95  return __mmask16(0xFFFF);
96  }
97  return __mmask16(0);
98  }
99 
100  RAJA_INLINE
101  __m512i createStridedOffsets(camp::idx_t stride) const
102  {
103  // Generate a strided offset list
104  auto vstride = _mm512_set1_epi32(stride);
105  auto vseq =
106  _mm512_set_epi32(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0);
107  return _mm512_mullo_epi32(vstride, vseq);
108  }
109 
110 public:
111  static constexpr camp::idx_t s_num_elem = 16;
112 
116  // AVX512F
117  RAJA_INLINE
118  Register() : base_type(), m_value(_mm512_setzero_epi32()) {}
119 
123  RAJA_INLINE
124  explicit Register(register_type const& c) : base_type(), m_value(c) {}
125 
129  RAJA_INLINE
130  Register(self_type const& c) : base_type(), m_value(c.m_value) {}
131 
135  RAJA_INLINE
136  self_type& operator=(self_type const& c)
137  {
138  m_value = c.m_value;
139  return *this;
140  }
141 
146  // AVX512F
147  RAJA_INLINE
148  Register(element_type const& c) : base_type(), m_value(_mm512_set1_epi32(c))
149  {}
150 
155  RAJA_INLINE
156  self_type& load_packed(element_type const* ptr)
157  {
158  // AVX512F
159 #if defined(__GNUC__) && ((__GNUC__ >= 7) && (__GNUC__ <= 9))
160  m_value = _mm512_loadu_si512(ptr);
161 #else
162  m_value = _mm512_loadu_epi32(ptr); // GNU 7-9 are missing this instruction.
163 #endif
164  return *this;
165  }
166 
172  RAJA_INLINE
173  self_type& load_packed_n(element_type const* ptr, camp::idx_t N)
174  {
175  // AVX512F
176  m_value =
177  _mm512_mask_loadu_epi32(_mm512_setzero_epi32(), createMask(N), ptr);
178  return *this;
179  }
180 
185  RAJA_INLINE
186  self_type& load_strided(element_type const* ptr, camp::idx_t stride)
187  {
188  // AVX512F
189  m_value = _mm512_i32gather_epi32(createStridedOffsets(stride), ptr,
190  sizeof(element_type));
191  return *this;
192  }
193 
199  RAJA_INLINE
200  self_type& load_strided_n(element_type const* ptr,
201  camp::idx_t stride,
202  camp::idx_t N)
203  {
204  // AVX512F
205  m_value = _mm512_mask_i32gather_epi32(_mm512_setzero_epi32(), createMask(N),
206  createStridedOffsets(stride), ptr,
207  sizeof(element_type));
208  return *this;
209  }
210 
215  RAJA_INLINE
216  self_type const& store_packed(element_type* ptr) const
217  {
218  // AVX512F
219 #if defined(__GNUC__) && ((__GNUC__ >= 7) && (__GNUC__ <= 9))
220  _mm512_storeu_si512(ptr, m_value);
221 #else
222  _mm512_storeu_epi32(ptr, m_value); // GNU 7-9 are missing this instruction.
223 #endif
224  return *this;
225  }
226 
231  RAJA_INLINE
232  self_type const& store_packed_n(element_type* ptr, camp::idx_t N) const
233  {
234  // AVX512F
235  _mm512_mask_storeu_epi32(ptr, createMask(N), m_value);
236  return *this;
237  }
238 
243  RAJA_INLINE
244  self_type const& store_strided(element_type* ptr, camp::idx_t stride) const
245  {
246  // AVX512F
247  _mm512_i32scatter_epi32(ptr, createStridedOffsets(stride), m_value,
248  sizeof(element_type));
249  return *this;
250  }
251 
256  RAJA_INLINE
257  self_type const& store_strided_n(element_type* ptr,
258  camp::idx_t stride,
259  camp::idx_t N) const
260  {
261  // AVX512F
262  _mm512_mask_i32scatter_epi32(ptr, createMask(N),
263  createStridedOffsets(stride), m_value,
264  sizeof(element_type));
265  return *this;
266  }
267 
273  RAJA_INLINE
274  element_type get(camp::idx_t i) const
275  {
276 // GNU 7-10 are missing this instruction.
277 #if defined(__GNUC__) && ((__GNUC__ >= 7) && (__GNUC__ <= 10))
278 #define _mm512_cvtsi512_si32(x) _mm_cvtsi128_si32(_mm512_castsi512_si128(x))
279 #endif
280 
281  switch (i)
282  {
283  case 0:
284  return _mm512_cvtsi512_si32(_mm512_alignr_epi32(m_value, m_value, 0));
285  case 1:
286  return _mm512_cvtsi512_si32(_mm512_alignr_epi32(m_value, m_value, 1));
287  case 2:
288  return _mm512_cvtsi512_si32(_mm512_alignr_epi32(m_value, m_value, 2));
289  case 3:
290  return _mm512_cvtsi512_si32(_mm512_alignr_epi32(m_value, m_value, 3));
291  case 4:
292  return _mm512_cvtsi512_si32(_mm512_alignr_epi32(m_value, m_value, 4));
293  case 5:
294  return _mm512_cvtsi512_si32(_mm512_alignr_epi32(m_value, m_value, 5));
295  case 6:
296  return _mm512_cvtsi512_si32(_mm512_alignr_epi32(m_value, m_value, 6));
297  case 7:
298  return _mm512_cvtsi512_si32(_mm512_alignr_epi32(m_value, m_value, 7));
299  case 8:
300  return _mm512_cvtsi512_si32(_mm512_alignr_epi32(m_value, m_value, 8));
301  case 9:
302  return _mm512_cvtsi512_si32(_mm512_alignr_epi32(m_value, m_value, 9));
303  case 10:
304  return _mm512_cvtsi512_si32(_mm512_alignr_epi32(m_value, m_value, 10));
305  case 11:
306  return _mm512_cvtsi512_si32(_mm512_alignr_epi32(m_value, m_value, 11));
307  case 12:
308  return _mm512_cvtsi512_si32(_mm512_alignr_epi32(m_value, m_value, 12));
309  case 13:
310  return _mm512_cvtsi512_si32(_mm512_alignr_epi32(m_value, m_value, 13));
311  case 14:
312  return _mm512_cvtsi512_si32(_mm512_alignr_epi32(m_value, m_value, 14));
313  case 15:
314  return _mm512_cvtsi512_si32(_mm512_alignr_epi32(m_value, m_value, 15));
315  }
316  return 0;
317  }
318 
324  RAJA_INLINE
325  self_type& set(element_type value, camp::idx_t i)
326  {
327  m_value = _mm512_mask_set1_epi32(m_value, 1 << i, value);
328  return *this;
329  }
330 
332 
333  RAJA_INLINE
334  self_type& broadcast(element_type const& value)
335  {
336  m_value = _mm512_set1_epi32(value);
337  return *this;
338  }
339 
341 
342  RAJA_INLINE
343  self_type& copy(self_type const& src)
344  {
345  m_value = src.m_value;
346  return *this;
347  }
348 
350 
351  RAJA_INLINE
352  self_type add(self_type const& b) const
353  {
354  return self_type(_mm512_add_epi32(m_value, b.m_value));
355  }
356 
358 
359  RAJA_INLINE
360  self_type subtract(self_type const& b) const
361  {
362  return self_type(_mm512_sub_epi32(m_value, b.m_value));
363  }
364 
366 
367  RAJA_INLINE
368  self_type multiply(self_type const& b) const
369  {
370  return self_type(_mm512_mullo_epi32(m_value, b.m_value));
371  }
372 
374 
375  RAJA_INLINE
376  self_type divide(self_type const& b) const
377  {
378  // AVX512 does not supply an integer divide, so do it manually
379  return self_type(_mm512_set_epi32(
380  get(15) / b.get(15), get(14) / b.get(14), get(13) / b.get(13),
381  get(12) / b.get(12), get(11) / b.get(11), get(10) / b.get(10),
382  get(9) / b.get(9), get(8) / b.get(8), get(7) / b.get(7),
383  get(6) / b.get(6), get(5) / b.get(5), get(4) / b.get(4),
384  get(3) / b.get(3), get(2) / b.get(2), get(1) / b.get(1),
385  get(0) / b.get(0)));
386  }
387 
389 
390  RAJA_INLINE
391  self_type divide_n(self_type const& b, camp::idx_t N) const
392  {
393  // AVX512 does not supply an integer divide, so do it manually
394  return self_type(_mm512_set_epi32(
395  N >= 16 ? get(15) / b.get(15) : 0, N >= 15 ? get(14) / b.get(14) : 0,
396  N >= 14 ? get(13) / b.get(13) : 0, N >= 13 ? get(12) / b.get(12) : 0,
397  N >= 12 ? get(11) / b.get(11) : 0, N >= 11 ? get(10) / b.get(10) : 0,
398  N >= 10 ? get(9) / b.get(9) : 0, N >= 9 ? get(8) / b.get(8) : 0,
399  N >= 8 ? get(7) / b.get(7) : 0, N >= 7 ? get(6) / b.get(6) : 0,
400  N >= 6 ? get(5) / b.get(5) : 0, N >= 5 ? get(4) / b.get(4) : 0,
401  N >= 4 ? get(3) / b.get(3) : 0, N >= 3 ? get(2) / b.get(2) : 0,
402  N >= 2 ? get(1) / b.get(1) : 0, N >= 1 ? get(0) / b.get(0) : 0));
403  }
404 
409  RAJA_INLINE
410  element_type sum() const { return _mm512_reduce_add_epi32(m_value); }
411 
416  RAJA_INLINE
417  element_type max() const { return _mm512_reduce_max_epi32(m_value); }
418 
423  RAJA_INLINE
424  element_type max_n(camp::idx_t N) const
425  {
426  return _mm512_mask_reduce_max_epi32(createMask(N), m_value);
427  }
428 
433  RAJA_INLINE
434  self_type vmax(self_type a) const
435  {
436  return self_type(_mm512_max_epi32(m_value, a.m_value));
437  }
438 
443  RAJA_INLINE
444  element_type min() const { return _mm512_reduce_min_epi32(m_value); }
445 
450  RAJA_INLINE
451  element_type min(camp::idx_t N) const
452  {
453  return _mm512_mask_reduce_min_epi32(createMask(N), m_value);
454  }
455 
460  RAJA_INLINE
461  self_type vmin(self_type a) const
462  {
463  return self_type(_mm512_min_epi32(m_value, a.m_value));
464  }
465 };
466 
467 } // namespace expt
468 
469 } // namespace RAJA
470 
471 
472 #endif
473 
474 #endif //__AVX512F__
RAJA header file defining SIMD/SIMT register operations.
Header file for common RAJA internal macro definitions.
#define RAJA_HOST_DEVICE
Definition: macros.hpp:65
Definition: AlignedRangeIndexSetBuilders.cpp:35
RAJA_HOST_DEVICE constexpr RAJA_INLINE Result min(Args... args)
Definition: foldl.hpp:161
RAJA_HOST_DEVICE constexpr RAJA_INLINE Result sum(Args... args)
Definition: foldl.hpp:143
RAJA_HOST_DEVICE constexpr RAJA_INLINE RAJA::zip_tuple_element_t< I, zip_tuple< is_val, Ts... > > & get(zip_tuple< is_val, Ts... > &z) noexcept
Definition: zip_tuple.hpp:56
RAJA_HOST_DEVICE constexpr RAJA_INLINE Result max(Args... args)
Definition: foldl.hpp:155