Pixie
Loading...
Searching...
No Matches
packed_prefix_search.h
1#pragma once
2
3#include <pixie/bits.h>
4
5#include <array>
6#include <bit>
7#include <cassert>
8#include <cstddef>
9#include <cstdint>
10#include <optional>
11
12#if defined(PIXIE_AVX512_SUPPORT) && defined(__AVX512VBMI__)
13#include <immintrin.h>
14#endif
15
16namespace pixie::detail::compressed {
17
19 std::uint32_t basic;
20 std::uint32_t before;
21 std::uint32_t after;
22};
23
24// Two byte permutations gather every fourteen-bit field into a word lane.
25// Offsets repeat 0, 6, 4, 2. Only those with offsets 6 and 4 need a third byte.
26alignas(64) inline constexpr auto kPrefixLowBytes = [] {
27 std::array<std::uint8_t, 64> indexes{};
28 for (std::size_t i = 0; i < 32; ++i) {
29 indexes[2 * i] = 8 + i * 14 / 8;
30 indexes[2 * i + 1] = indexes[2 * i] + 1;
31 }
32 return indexes;
33}();
34
35alignas(64) inline constexpr auto kPrefixHighBytes = [] {
36 std::array<std::uint8_t, 64> indexes{};
37 for (std::size_t i = 0; i < 32; ++i) {
38 indexes[2 * i] = (10 + i * 14 / 8) & 63;
39 }
40 return indexes;
41}();
42
43// The selected superblock must be nonhomogeneous, with uniformly packed local
44// ends. This excludes the zero terminal alias. Unsupported targets return no
45// result so callers retain the established scalar interpolation/correction.
46template <bool Zero>
47inline std::optional<PackedPrefixLocation> packed_prefix_search(
48 const std::uint64_t* record,
49 std::uint64_t target,
50 std::size_t valid_bits) {
51#if defined(PIXIE_AVX512_SUPPORT) && defined(__AVX512VBMI__)
52 const auto packed = _mm512_loadu_si512(record);
53 const auto low = _mm512_permutexvar_epi8(
54 _mm512_load_si512(kPrefixLowBytes.data()), packed);
55 const auto high = _mm512_permutexvar_epi8(
56 _mm512_load_si512(kPrefixHighBytes.data()), packed);
57 const auto offsets = _mm512_set1_epi64(0x0002000400060000);
58 auto ends = _mm512_and_si512(
59 _mm512_or_si512(
60 _mm512_srlv_epi16(low, offsets),
61 _mm512_sllv_epi16(high,
62 _mm512_sub_epi16(_mm512_set1_epi16(16), offsets))),
63 _mm512_set1_epi16(0x3fff));
64 if constexpr (Zero) {
65 const auto positions = _mm512_set_epi16(
66 16384, 15872, 15360, 14848, 14336, 13824, 13312, 12800, 12288, 11776,
67 11264, 10752, 10240, 9728, 9216, 8704, 8192, 7680, 7168, 6656, 6144,
68 5632, 5120, 4608, 4096, 3584, 3072, 2560, 2048, 1536, 1024, 512);
69 ends = _mm512_sub_epi16(
70 _mm512_min_epu16(positions, _mm512_set1_epi16(valid_bits)), ends);
71 }
72 const std::uint32_t matches =
73 _mm512_cmpge_epu16_mask(ends, _mm512_set1_epi16(target));
74 assert(matches != 0);
75 const std::uint32_t basic = std::countr_zero(matches);
76 const auto indexes =
77 _mm512_set1_epi32((basic << 16) | ((basic - 1) & 0xffff));
78 const std::uint32_t bounds = _mm_cvtsi128_si32(
79 _mm512_castsi512_si128(_mm512_permutexvar_epi16(indexes, ends)));
80 return PackedPrefixLocation{basic, basic == 0 ? 0 : bounds & 0xffff,
81 bounds >> 16};
82#else
83 (void)record;
84 (void)target;
85 (void)valid_bits;
86 return std::nullopt;
87#endif
88}
89
90} // namespace pixie::detail::compressed
Definition packed_prefix_search.h:18