-
Notifications
You must be signed in to change notification settings - Fork 1
/
permute.h
141 lines (119 loc) · 3.7 KB
/
permute.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
/* SPDX-License-Identifier: BSD-3-Clause */
/* Copyright © 2023-2024 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH
* Matthias Kretz <[email protected]>
*/
// Implements non-members of P2664
#ifndef PROTOTYPE_PERMUTE_H_
#define PROTOTYPE_PERMUTE_H_
#include "simd.h"
#include "iota.h"
namespace std
{
constexpr int simd_permute_zero = INT_MIN;
namespace simd_permutations
{
struct _DuplicateEven
{
consteval unsigned
operator()(unsigned __i) const
{ return __i & ~1u; }
};
inline constexpr _DuplicateEven duplicate_even {};
struct _DuplicateOdd
{
consteval unsigned
operator()(unsigned __i) const
{ return __i | 1u; }
};
inline constexpr _DuplicateOdd duplicate_odd {};
template <unsigned _Np>
struct _SwapNeighbors
{
consteval unsigned
operator()(unsigned __i, auto __size) const
{
static_assert(__size % (2 * _Np) == 0,
"swap_neighbors<N> permutation requires a multiple of 2N elements");
if (std::has_single_bit(_Np))
return __i ^ _Np;
else if (__i % (2 * _Np) >= _Np)
return __i - _Np;
else
return __i + _Np;
}
};
template <unsigned _Np = 1u>
inline constexpr _SwapNeighbors<_Np> swap_neighbors {};
template <int _Position>
struct _Broadcast
{
consteval int
operator()(int) const
{ return _Position; }
};
template <int _Position>
inline constexpr _Broadcast<_Position> broadcast {};
inline constexpr _Broadcast<0> broadcast_first {};
inline constexpr _Broadcast<-1> broadcast_last {};
struct _Reverse
{
consteval int
operator()(int __i) const
{ return -1 - __i; }
};
inline constexpr _Reverse reverse {};
template <int _Offset>
struct _Rotate
{
consteval int
operator()(int __i, auto __size) const
{ return (__i + _Offset) % int(__size()); }
};
template <int _Offset>
inline constexpr _Rotate<_Offset> rotate {};
template <int _Offset>
struct _Shift
{
consteval int
operator()(int __i, auto __size) const
{
const int __j = __i + _Offset;
if (__j >= __size or -__j > __size)
return simd_permute_zero;
else
return __j;
}
};
template <int _Offset>
inline constexpr _Shift<_Offset> shift {};
}
template <__detail::_SimdSizeType _Np = 0, __detail::__simd_or_mask _Vp,
__detail::__index_permutation_function<_Vp> _Fp>
_GLIBCXX_SIMD_ALWAYS_INLINE constexpr std::resize_simd_t<_Np == 0 ? _Vp::size() : _Np, _Vp>
simd_permute(_Vp const& __v, _Fp const __idx_perm) noexcept
{
using _Tp = typename _Vp::value_type;
using _Rp = resize_simd_t<_Np == 0 ? _Vp::size() : _Np, _Vp>;
return _Rp([&] [[__gnu__::__always_inline__]] (auto __i) -> _Tp {
constexpr int __j = [&] {
if constexpr (__detail::__index_permutation_function_nosize<_Fp>)
return __idx_perm(__i);
else
return __idx_perm(__i, _Vp::size);
}();
if constexpr (__j == simd_permute_zero)
return 0;
else if constexpr (__j < 0)
{
static_assert(-__j <= int(_Vp::size()));
return __v[__v.size() + __j];
}
else
{
static_assert(__j < int(_Vp::size()));
return __v[__j];
}
});
}
}
#endif // PROTOTYPE_PERMUTE_H_