-
Notifications
You must be signed in to change notification settings - Fork 1
/
flags.h
225 lines (186 loc) · 6.73 KB
/
flags.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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
/* SPDX-License-Identifier: GPL-3.0-or-later WITH GCC-exception-3.1 */
/* Copyright © 2023-2024 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH
* Matthias Kretz <[email protected]>
*/
#ifndef PROTOTYPE_FLAGS_H_
#define PROTOTYPE_FLAGS_H_
#include "simd_config.h"
#include "fwddecl.h"
#include <bit>
#include <concepts>
namespace std::__detail
{
struct _LoadStoreTag
{};
struct _Convert
: _LoadStoreTag
{};
template <typename _To>
struct _ConvertTo
: _LoadStoreTag
{
using type = _To;
};
struct _Aligned
: _LoadStoreTag
{
template <typename _Tp, typename _Up>
_GLIBCXX_SIMD_INTRINSIC static constexpr _Up*
_S_adjust_pointer(_Up* __ptr)
{ return static_cast<_Up*>(__builtin_assume_aligned(__ptr, simd_alignment_v<_Tp, _Up>)); }
};
template <std::size_t _Np>
struct _Overaligned
: _LoadStoreTag
{
static_assert(std::__has_single_bit(_Np));
template <typename, typename _Up>
_GLIBCXX_SIMD_INTRINSIC static constexpr _Up*
_S_adjust_pointer(_Up* __ptr)
{ return static_cast<_Up*>(__builtin_assume_aligned(__ptr, _Np)); }
};
struct _Streaming
: _LoadStoreTag
{};
template <int _L1, int _L2 /*, exclusive vs. shared*/>
struct _Prefetch
: _LoadStoreTag
{
template <typename, typename _Up>
_GLIBCXX_SIMD_ALWAYS_INLINE static _Up*
_S_adjust_pointer(_Up* __ptr)
{
// one read: 0, 0
// L1: 0, 1
// L2: 0, 2
// L3: 0, 3
// (exclusive cache line) for writing: 1, 0 / 1, 1
/* constexpr int __write = 1;
constexpr int __level = 0-3;
__builtin_prefetch(__ptr, __write, __level)
_mm_prefetch(reinterpret_cast<char const*>(__ptr), _MM_HINT_T0);
_mm_prefetch(reinterpret_cast<char const*>(__ptr), _MM_HINT_T1);
_mm_prefetch(reinterpret_cast<char const*>(__ptr), _MM_HINT_T2);
_mm_prefetch(reinterpret_cast<char const*>(__ptr), _MM_HINT_ET0);
_mm_prefetch(reinterpret_cast<char const*>(__ptr), _MM_HINT_ET1);
_mm_prefetch(reinterpret_cast<char const*>(__ptr), _MM_HINT_NTA);*/
return __ptr;
}
};
template <typename _Tp>
concept __loadstore_tag = std::is_base_of_v<_LoadStoreTag, _Tp>;
} // namespace __detail
namespace std
{
template <typename... _Flags>
requires (__detail::__loadstore_tag<_Flags> and ...)
struct simd_flags<_Flags...>
{
consteval bool
_M_is_equal(simd_flags) const
{ return true; }
template <typename... _Other>
consteval bool
_M_is_equal(simd_flags<_Other...> __y) const
{ return std::same_as<simd_flags<>, decltype(_M_xor(__y))>; }
template <typename... _Other>
consteval bool
_M_test(simd_flags<_Other...> __x) const noexcept
{ return __x._M_is_equal(_M_and(__x)); }
friend consteval auto
operator|(simd_flags, simd_flags<>)
{ return simd_flags{}; }
template <typename _T0, typename... _More>
friend consteval auto
operator|(simd_flags, simd_flags<_T0, _More...>)
{
if constexpr ((std::same_as<_Flags, _T0> or ...))
return simd_flags<_Flags...>{} | simd_flags<_More...>{};
else
return simd_flags<_Flags..., _T0>{} | simd_flags<_More...>{};
}
consteval auto
_M_and(simd_flags<>) const
{ return simd_flags<>{}; }
template <typename _T0, typename... _More>
consteval auto
_M_and(simd_flags<_T0, _More...>) const
{
if constexpr ((std::same_as<_Flags, _T0> or ...))
return simd_flags<_T0>{} | (simd_flags{}._M_and(simd_flags<_More...>{}));
else
return simd_flags{}._M_and(simd_flags<_More...>{});
}
consteval auto
_M_xor(simd_flags<>) const
{ return simd_flags{}; }
template <typename _T0, typename... _More>
consteval auto
_M_xor(simd_flags<_T0, _More...>) const
{
if constexpr ((std::same_as<_Flags, _T0> or ...))
{
constexpr auto __removed
= (std::conditional_t<std::same_as<_Flags, _T0>, simd_flags<>,
simd_flags<_Flags>>{} | ...);
return __removed._M_xor(simd_flags<_More...>{});
}
else
return (simd_flags{} | simd_flags<_T0>{})._M_xor(simd_flags<_More...>{});
}
// LEWG took this out
#if LEWG_WANTS_FLAGS_WITH_FULL_API
template <typename... _Other>
consteval bool
test(simd_flags<_Other...> __x) const noexcept
{ return _M_test(__x); }
template <typename... _Other>
friend consteval bool
operator==(simd_flags __x, simd_flags<_Other...> __y)
{ return __x._M_is_equal(__y); }
template <typename... _Other>
friend consteval auto
operator&(simd_flags __lhs, simd_flags<_Other...> __rhs)
{ return __lhs._M_and(__rhs); }
template <typename... _Other>
friend consteval auto
operator^(simd_flags __lhs, simd_flags<_Other...> __rhs)
{ return __lhs._M_xor(__rhs); }
#endif
template <typename _F0, typename _Tp>
static constexpr void
_S_apply_adjust_pointer(auto& __ptr)
{
if constexpr (requires{ _F0::template _S_adjust_pointer<_Tp>(__ptr); })
__ptr = _F0::template _S_adjust_pointer<_Tp>(__ptr);
}
template <typename _Tp, typename _Up>
static constexpr _Up*
_S_adjust_pointer(_Up* __ptr)
{
(_S_apply_adjust_pointer<_Flags, _Tp>(__ptr), ...);
return __ptr;
}
};
// [simd.flags]
inline constexpr simd_flags<> simd_flag_default;
inline constexpr simd_flags<__detail::_Convert> simd_flag_convert;
inline constexpr simd_flags<__detail::_Aligned> simd_flag_aligned;
template <std::size_t _Np>
requires(std::has_single_bit(_Np))
inline constexpr simd_flags<__detail::_Overaligned<_Np>> simd_flag_overaligned;
// extensions
template <typename _To>
inline constexpr simd_flags<__detail::_ConvertTo<_To>> simd_flag_convert_to;
inline constexpr std::simd_flags<std::__detail::_Streaming> __simd_flag_streaming;
template <int _L1, int _L2>
inline constexpr std::simd_flags<std::__detail::_Prefetch<_L1, _L2>> __simd_flag_prefetch;
[[deprecated("use simd_flag_default")]]
inline constexpr auto element_aligned = simd_flag_default;
[[deprecated("use simd_flag_aligned")]]
inline constexpr auto vector_aligned = simd_flag_aligned;
template <size_t _Np>
[[deprecated("use simd_flag_overaligned")]]
inline constexpr auto overaligned = simd_flag_overaligned<_Np>;
} // namespace std
#endif // PROTOTYPE_FLAGS_H_