Pixie
Loading...
Searching...
No Matches
select_loaded_block.h
1#pragma once
2
3#include <pixie/bits.h>
4
5#include <bit>
6#include <cstddef>
7#include <cstdint>
8
9namespace pixie::detail::compressed {
10
11// Select a zero-based occurrence in eight readable words. The caller guarantees
12// that the occurrence exists. Keep the loaded block in registers through word
13// localization; extracting the winner must not reload source memory.
14template <bool Zero>
15inline std::size_t select_loaded_block(const std::uint64_t* words,
16 std::size_t rank) {
17#ifdef PIXIE_AVX512_SUPPORT
18 auto bits = _mm512_loadu_si512(words);
19 if constexpr (Zero) {
20 bits = _mm512_xor_si512(bits, _mm512_set1_epi64(-1));
21 }
22 const auto zero = _mm512_setzero_si512();
23 auto prefixes = _mm512_popcnt_epi64(bits);
24 prefixes = _mm512_add_epi64(prefixes, _mm512_alignr_epi64(prefixes, zero, 7));
25 prefixes = _mm512_add_epi64(prefixes, _mm512_alignr_epi64(prefixes, zero, 6));
26 prefixes = _mm512_add_epi64(prefixes, _mm512_alignr_epi64(prefixes, zero, 4));
27 const auto candidates =
28 _mm512_cmp_epu64_mask(prefixes, _mm512_set1_epi64(rank), _MM_CMPINT_GT);
29 const auto lane = std::countr_zero(static_cast<unsigned>(candidates));
30 const auto selector = _mm512_set1_epi64(lane);
31 const auto word = static_cast<std::uint64_t>(_mm_cvtsi128_si64(
32 _mm512_castsi512_si128(_mm512_permutexvar_epi64(selector, bits))));
33 const auto end = static_cast<std::uint64_t>(_mm_cvtsi128_si64(
34 _mm512_castsi512_si128(_mm512_permutexvar_epi64(selector, prefixes))));
35 const auto before = end - std::popcount(word);
36 return lane * 64 + ::select_64(word, rank - before);
37#else
38 // The established primitive supplies AVX2 and scalar dispatch on other
39 // targets. Callers need no SIMD feature guards.
40 if constexpr (Zero) {
41 return ::select0_512(words, rank);
42 } else {
43 return ::select_512(words, rank);
44 }
45#endif
46}
47
48} // namespace pixie::detail::compressed