native 0.0.1
Vectors, masks and wide register packs for C++26
Loading...
Searching...
No Matches
bitalg.h
1// SPDX-License-Identifier: BSD-2-Clause OR Apache-2.0
2#pragma once
3#include "native/config.h"
4#include "native/attributes.h"
5#include "native/isa.h"
6#if NATIVE_HOST_X86
7#include <immintrin.h>
8#endif
9#if NATIVE_HOST_X86 || defined(NATIVE_DOXYGEN)
10namespace native::detail::x86_bitalg {
11 // Internal register helpers for native.x86.bitalg.
12
13 template<isa<x86> Arch>
14 requires(Arch.has(x86_feature::avx512f) &&
15 Arch.has(x86_feature::avx512bw) &&
16 Arch.has(x86_feature::avx512bitalg) &&
17 Arch.has(x86_feature::avx512vl))
18 native_nodiscard native_inline native_const native_target("avx512f,avx512bw,avx512bitalg,avx512vl")
19 __m128i vpopcntb(__m128i value) noexcept {
20 return _mm_popcnt_epi8(value);
21 }
22
23 template<isa<x86> Arch>
24 requires(Arch.has(x86_feature::avx512f) &&
25 Arch.has(x86_feature::avx512bw) &&
26 Arch.has(x86_feature::avx512bitalg) &&
27 Arch.has(x86_feature::avx512vl))
28 native_nodiscard native_inline native_const native_target("avx512f,avx512bw,avx512bitalg,avx512vl")
29 __m128i mask_vpopcntb(__m128i source, __mmask16 mask, __m128i value) noexcept {
30 return _mm_mask_popcnt_epi8(source, mask, value);
31 }
32
33 template<isa<x86> Arch>
34 requires(Arch.has(x86_feature::avx512f) &&
35 Arch.has(x86_feature::avx512bw) &&
36 Arch.has(x86_feature::avx512bitalg) &&
37 Arch.has(x86_feature::avx512vl))
38 native_nodiscard native_inline native_const native_target("avx512f,avx512bw,avx512bitalg,avx512vl")
39 __m128i maskz_vpopcntb(__mmask16 mask, __m128i value) noexcept {
40 return _mm_maskz_popcnt_epi8(mask, value);
41 }
42
43 template<isa<x86> Arch>
44 requires(Arch.has(x86_feature::avx512f) &&
45 Arch.has(x86_feature::avx512bw) &&
46 Arch.has(x86_feature::avx512bitalg) &&
47 Arch.has(x86_feature::avx512vl))
48 native_nodiscard native_inline native_const native_target("avx512f,avx512bw,avx512bitalg,avx512vl")
49 __m128i vpopcntw(__m128i value) noexcept {
50 return _mm_popcnt_epi16(value);
51 }
52
53 template<isa<x86> Arch>
54 requires(Arch.has(x86_feature::avx512f) &&
55 Arch.has(x86_feature::avx512bw) &&
56 Arch.has(x86_feature::avx512bitalg) &&
57 Arch.has(x86_feature::avx512vl))
58 native_nodiscard native_inline native_const native_target("avx512f,avx512bw,avx512bitalg,avx512vl")
59 __m128i mask_vpopcntw(__m128i source, __mmask8 mask, __m128i value) noexcept {
60 return _mm_mask_popcnt_epi16(source, mask, value);
61 }
62
63 template<isa<x86> Arch>
64 requires(Arch.has(x86_feature::avx512f) &&
65 Arch.has(x86_feature::avx512bw) &&
66 Arch.has(x86_feature::avx512bitalg) &&
67 Arch.has(x86_feature::avx512vl))
68 native_nodiscard native_inline native_const native_target("avx512f,avx512bw,avx512bitalg,avx512vl")
69 __m128i maskz_vpopcntw(__mmask8 mask, __m128i value) noexcept {
70 return _mm_maskz_popcnt_epi16(mask, value);
71 }
72
73 template<isa<x86> Arch>
74 requires(Arch.has(x86_feature::avx512f) &&
75 Arch.has(x86_feature::avx512bw) &&
76 Arch.has(x86_feature::avx512bitalg) &&
77 Arch.has(x86_feature::avx512vl))
78 native_nodiscard native_inline native_const native_target("avx512f,avx512bw,avx512bitalg,avx512vl")
79 __mmask16 vpshufbitqmb(__m128i value, __m128i control) noexcept {
80 return _mm_bitshuffle_epi64_mask(value, control);
81 }
82
83 template<isa<x86> Arch>
84 requires(Arch.has(x86_feature::avx512f) &&
85 Arch.has(x86_feature::avx512bw) &&
86 Arch.has(x86_feature::avx512bitalg) &&
87 Arch.has(x86_feature::avx512vl))
88 native_nodiscard native_inline native_const native_target("avx512f,avx512bw,avx512bitalg,avx512vl")
89 __mmask16 mask_vpshufbitqmb(__mmask16 mask, __m128i value, __m128i control) noexcept {
90 return _mm_mask_bitshuffle_epi64_mask(mask, value, control);
91 }
92
93 template<isa<x86> Arch>
94 requires(Arch.has(x86_feature::avx512f) &&
95 Arch.has(x86_feature::avx512bw) &&
96 Arch.has(x86_feature::avx512bitalg) &&
97 Arch.has(x86_feature::avx512vl))
98 native_nodiscard native_inline native_const native_target("avx512f,avx512bw,avx512bitalg,avx512vl")
99 __m256i vpopcntb(__m256i value) noexcept {
100 return _mm256_popcnt_epi8(value);
101 }
102
103 template<isa<x86> Arch>
104 requires(Arch.has(x86_feature::avx512f) &&
105 Arch.has(x86_feature::avx512bw) &&
106 Arch.has(x86_feature::avx512bitalg) &&
107 Arch.has(x86_feature::avx512vl))
108 native_nodiscard native_inline native_const native_target("avx512f,avx512bw,avx512bitalg,avx512vl")
109 __m256i mask_vpopcntb(__m256i source, __mmask32 mask, __m256i value) noexcept {
110 return _mm256_mask_popcnt_epi8(source, mask, value);
111 }
112
113 template<isa<x86> Arch>
114 requires(Arch.has(x86_feature::avx512f) &&
115 Arch.has(x86_feature::avx512bw) &&
116 Arch.has(x86_feature::avx512bitalg) &&
117 Arch.has(x86_feature::avx512vl))
118 native_nodiscard native_inline native_const native_target("avx512f,avx512bw,avx512bitalg,avx512vl")
119 __m256i maskz_vpopcntb(__mmask32 mask, __m256i value) noexcept {
120 return _mm256_maskz_popcnt_epi8(mask, value);
121 }
122
123 template<isa<x86> Arch>
124 requires(Arch.has(x86_feature::avx512f) &&
125 Arch.has(x86_feature::avx512bw) &&
126 Arch.has(x86_feature::avx512bitalg) &&
127 Arch.has(x86_feature::avx512vl))
128 native_nodiscard native_inline native_const native_target("avx512f,avx512bw,avx512bitalg,avx512vl")
129 __m256i vpopcntw(__m256i value) noexcept {
130 return _mm256_popcnt_epi16(value);
131 }
132
133 template<isa<x86> Arch>
134 requires(Arch.has(x86_feature::avx512f) &&
135 Arch.has(x86_feature::avx512bw) &&
136 Arch.has(x86_feature::avx512bitalg) &&
137 Arch.has(x86_feature::avx512vl))
138 native_nodiscard native_inline native_const native_target("avx512f,avx512bw,avx512bitalg,avx512vl")
139 __m256i mask_vpopcntw(__m256i source, __mmask16 mask, __m256i value) noexcept {
140 return _mm256_mask_popcnt_epi16(source, mask, value);
141 }
142
143 template<isa<x86> Arch>
144 requires(Arch.has(x86_feature::avx512f) &&
145 Arch.has(x86_feature::avx512bw) &&
146 Arch.has(x86_feature::avx512bitalg) &&
147 Arch.has(x86_feature::avx512vl))
148 native_nodiscard native_inline native_const native_target("avx512f,avx512bw,avx512bitalg,avx512vl")
149 __m256i maskz_vpopcntw(__mmask16 mask, __m256i value) noexcept {
150 return _mm256_maskz_popcnt_epi16(mask, value);
151 }
152
153 template<isa<x86> Arch>
154 requires(Arch.has(x86_feature::avx512f) &&
155 Arch.has(x86_feature::avx512bw) &&
156 Arch.has(x86_feature::avx512bitalg) &&
157 Arch.has(x86_feature::avx512vl))
158 native_nodiscard native_inline native_const native_target("avx512f,avx512bw,avx512bitalg,avx512vl")
159 __mmask32 vpshufbitqmb(__m256i value, __m256i control) noexcept {
160 return _mm256_bitshuffle_epi64_mask(value, control);
161 }
162
163 template<isa<x86> Arch>
164 requires(Arch.has(x86_feature::avx512f) &&
165 Arch.has(x86_feature::avx512bw) &&
166 Arch.has(x86_feature::avx512bitalg) &&
167 Arch.has(x86_feature::avx512vl))
168 native_nodiscard native_inline native_const native_target("avx512f,avx512bw,avx512bitalg,avx512vl")
169 __mmask32 mask_vpshufbitqmb(__mmask32 mask, __m256i value, __m256i control) noexcept {
170 return _mm256_mask_bitshuffle_epi64_mask(mask, value, control);
171 }
172
173 template<isa<x86> Arch>
174 requires(Arch.has(x86_feature::avx512f) &&
175 Arch.has(x86_feature::avx512bw) &&
176 Arch.has(x86_feature::avx512bitalg))
177 native_nodiscard native_inline native_const native_target("avx512f,avx512bw,avx512bitalg")
178 __m512i vpopcntb(__m512i value) noexcept {
179 return _mm512_popcnt_epi8(value);
180 }
181
182 template<isa<x86> Arch>
183 requires(Arch.has(x86_feature::avx512f) &&
184 Arch.has(x86_feature::avx512bw) &&
185 Arch.has(x86_feature::avx512bitalg))
186 native_nodiscard native_inline native_const native_target("avx512f,avx512bw,avx512bitalg")
187 __m512i mask_vpopcntb(__m512i source, __mmask64 mask, __m512i value) noexcept {
188 return _mm512_mask_popcnt_epi8(source, mask, value);
189 }
190
191 template<isa<x86> Arch>
192 requires(Arch.has(x86_feature::avx512f) &&
193 Arch.has(x86_feature::avx512bw) &&
194 Arch.has(x86_feature::avx512bitalg))
195 native_nodiscard native_inline native_const native_target("avx512f,avx512bw,avx512bitalg")
196 __m512i maskz_vpopcntb(__mmask64 mask, __m512i value) noexcept {
197 return _mm512_maskz_popcnt_epi8(mask, value);
198 }
199
200 template<isa<x86> Arch>
201 requires(Arch.has(x86_feature::avx512f) &&
202 Arch.has(x86_feature::avx512bw) &&
203 Arch.has(x86_feature::avx512bitalg))
204 native_nodiscard native_inline native_const native_target("avx512f,avx512bw,avx512bitalg")
205 __m512i vpopcntw(__m512i value) noexcept {
206 return _mm512_popcnt_epi16(value);
207 }
208
209 template<isa<x86> Arch>
210 requires(Arch.has(x86_feature::avx512f) &&
211 Arch.has(x86_feature::avx512bw) &&
212 Arch.has(x86_feature::avx512bitalg))
213 native_nodiscard native_inline native_const native_target("avx512f,avx512bw,avx512bitalg")
214 __m512i mask_vpopcntw(__m512i source, __mmask32 mask, __m512i value) noexcept {
215 return _mm512_mask_popcnt_epi16(source, mask, value);
216 }
217
218 template<isa<x86> Arch>
219 requires(Arch.has(x86_feature::avx512f) &&
220 Arch.has(x86_feature::avx512bw) &&
221 Arch.has(x86_feature::avx512bitalg))
222 native_nodiscard native_inline native_const native_target("avx512f,avx512bw,avx512bitalg")
223 __m512i maskz_vpopcntw(__mmask32 mask, __m512i value) noexcept {
224 return _mm512_maskz_popcnt_epi16(mask, value);
225 }
226
227 template<isa<x86> Arch>
228 requires(Arch.has(x86_feature::avx512f) &&
229 Arch.has(x86_feature::avx512bw) &&
230 Arch.has(x86_feature::avx512bitalg))
231 native_nodiscard native_inline native_const native_target("avx512f,avx512bw,avx512bitalg")
232 __mmask64 vpshufbitqmb(__m512i value, __m512i control) noexcept {
233 return _mm512_bitshuffle_epi64_mask(value, control);
234 }
235
236 template<isa<x86> Arch>
237 requires(Arch.has(x86_feature::avx512f) &&
238 Arch.has(x86_feature::avx512bw) &&
239 Arch.has(x86_feature::avx512bitalg))
240 native_nodiscard native_inline native_const native_target("avx512f,avx512bw,avx512bitalg")
241 __mmask64 mask_vpshufbitqmb(__mmask64 mask, __m512i value, __m512i control) noexcept {
242 return _mm512_mask_bitshuffle_epi64_mask(mask, value, control);
243 }
244}
245#endif
246
247#include <array>
248#include <bit>
249#include <cstddef>
250#include <cstdint>
251
252namespace native::detail::x86_bitalg_constant {
253 template<class V>
254 constexpr V population(V value, V source, std::uint64_t mask) noexcept {
255 using value_type = typename V::value_type;
256 std::array<value_type, V::lanes> input{};
257 std::array<value_type, V::lanes> result{};
258 value.store(input.data());
259 source.store(result.data());
260 for (std::size_t lane = 0; lane < V::lanes; ++lane) {
261 if ((mask >> lane) & 1) {
262 result[lane] = static_cast<value_type>(std::popcount(input[lane]));
263 }
264 }
265 return V::load(result.data());
266 }
267
268 template<class P, class V, class C>
269 constexpr P bitshuffle(V value, C control, std::uint64_t mask) noexcept {
270 std::array<std::uint64_t, V::lanes> words{};
271 std::array<std::uint8_t, C::lanes> selectors{};
272 value.store(words.data());
273 control.store(selectors.data());
274 std::uint64_t result = 0;
275 for (std::size_t lane = 0; lane < C::lanes; ++lane) {
276 // Each control byte selects within its own source qword. Bits 6/7 are ignored.
277 auto bit = (words[lane / 8] >> (selectors[lane] & 63)) & 1;
278 result |= bit << lane;
279 }
280 return P::from_bitset(result & mask);
281 }
282}
Compiler attributes for host code, with shader-safe shared modifiers.
#define native_inline
inline [[always_inline]]
Definition attributes.h:212
#define native_nodiscard
C++17 [[nodiscard]].
Definition attributes.h:189
#define native_const
[[const]] is not const
Definition attributes.h:108
#define native_target(x)
this indicates a required feature set for the current multiversioned function.
Definition attributes.h:476
typename mask_traits< std::remove_cvref_t< T > >::type mask
Definition mask_traits.h:22