17#ifndef MORTON_SIMD_HPP
18#define MORTON_SIMD_HPP
29#define MORTON_AVX512_TARGET __attribute__((target("avx512f")))
37MORTON_AVX512_TARGET
inline __m512i spread2(__m512i x) {
38 x = _mm512_and_si512(_mm512_or_si512(x, _mm512_slli_epi64(x, 16)),
39 _mm512_set1_epi64(0x0000FFFF0000FFFFLL));
40 x = _mm512_and_si512(_mm512_or_si512(x, _mm512_slli_epi64(x, 8)),
41 _mm512_set1_epi64(0x00FF00FF00FF00FFLL));
42 x = _mm512_and_si512(_mm512_or_si512(x, _mm512_slli_epi64(x, 4)),
43 _mm512_set1_epi64(0x0F0F0F0F0F0F0F0FLL));
44 x = _mm512_and_si512(_mm512_or_si512(x, _mm512_slli_epi64(x, 2)),
45 _mm512_set1_epi64(0x3333333333333333LL));
46 x = _mm512_and_si512(_mm512_or_si512(x, _mm512_slli_epi64(x, 1)),
47 _mm512_set1_epi64(0x5555555555555555LL));
51MORTON_AVX512_TARGET
inline __m512i compact2(__m512i x) {
52 x = _mm512_and_si512(x, _mm512_set1_epi64(0x5555555555555555LL));
53 x = _mm512_and_si512(_mm512_or_si512(x, _mm512_srli_epi64(x, 1)),
54 _mm512_set1_epi64(0x3333333333333333LL));
55 x = _mm512_and_si512(_mm512_or_si512(x, _mm512_srli_epi64(x, 2)),
56 _mm512_set1_epi64(0x0F0F0F0F0F0F0F0FLL));
57 x = _mm512_and_si512(_mm512_or_si512(x, _mm512_srli_epi64(x, 4)),
58 _mm512_set1_epi64(0x00FF00FF00FF00FFLL));
59 x = _mm512_and_si512(_mm512_or_si512(x, _mm512_srli_epi64(x, 8)),
60 _mm512_set1_epi64(0x0000FFFF0000FFFFLL));
61 x = _mm512_and_si512(_mm512_or_si512(x, _mm512_srli_epi64(x, 16)),
62 _mm512_set1_epi64(0x00000000FFFFFFFFLL));
68MORTON_AVX512_TARGET
inline __m512i spread3(__m512i x) {
69 x = _mm512_and_si512(x, _mm512_set1_epi64(0x1FFFFFLL));
70 x = _mm512_and_si512(_mm512_or_si512(x, _mm512_slli_epi64(x, 32)),
71 _mm512_set1_epi64(0x1F00000000FFFFLL));
72 x = _mm512_and_si512(_mm512_or_si512(x, _mm512_slli_epi64(x, 16)),
73 _mm512_set1_epi64(0x1F0000FF0000FFLL));
74 x = _mm512_and_si512(_mm512_or_si512(x, _mm512_slli_epi64(x, 8)),
75 _mm512_set1_epi64(0x100F00F00F00F00FLL));
76 x = _mm512_and_si512(_mm512_or_si512(x, _mm512_slli_epi64(x, 4)),
77 _mm512_set1_epi64(0x10C30C30C30C30C3LL));
78 x = _mm512_and_si512(_mm512_or_si512(x, _mm512_slli_epi64(x, 2)),
79 _mm512_set1_epi64(0x1249249249249249LL));
83MORTON_AVX512_TARGET
inline __m512i compact3(__m512i x) {
84 x = _mm512_and_si512(x, _mm512_set1_epi64(0x1249249249249249LL));
85 x = _mm512_and_si512(_mm512_or_si512(x, _mm512_srli_epi64(x, 2)),
86 _mm512_set1_epi64(0x10C30C30C30C30C3LL));
87 x = _mm512_and_si512(_mm512_or_si512(x, _mm512_srli_epi64(x, 4)),
88 _mm512_set1_epi64(0x100F00F00F00F00FLL));
89 x = _mm512_and_si512(_mm512_or_si512(x, _mm512_srli_epi64(x, 8)),
90 _mm512_set1_epi64(0x1F0000FF0000FFLL));
91 x = _mm512_and_si512(_mm512_or_si512(x, _mm512_srli_epi64(x, 16)),
92 _mm512_set1_epi64(0x1F00000000FFFFLL));
93 x = _mm512_and_si512(_mm512_or_si512(x, _mm512_srli_epi64(x, 32)), _mm512_set1_epi64(0x1FFFFFLL));
101MORTON_AVX512_TARGET
inline void encode2(
const std::uint32_t* x,
const std::uint32_t* y,
102 std::uint64_t* out, std::size_t n) {
104 for (; i + 8 <= n; i += 8) {
105 __m512i vx = _mm512_cvtepu32_epi64(_mm256_loadu_si256((
const __m256i*)(x + i)));
106 __m512i vy = _mm512_cvtepu32_epi64(_mm256_loadu_si256((
const __m256i*)(y + i)));
107 __m512i code = _mm512_or_si512(spread2(vx), _mm512_slli_epi64(spread2(vy), 1));
108 _mm512_storeu_si512((__m512i*)(out + i), code);
111 out[i] = Morton<2, 32>::encode(x[i], y[i]).code();
114MORTON_AVX512_TARGET
inline void decode2(
const std::uint64_t* in, std::uint32_t* x,
115 std::uint32_t* y, std::size_t n) {
117 for (; i + 8 <= n; i += 8) {
118 __m512i c = _mm512_loadu_si512((
const __m512i*)(in + i));
119 _mm256_storeu_si256((__m256i*)(x + i), _mm512_cvtepi64_epi32(compact2(c)));
120 _mm256_storeu_si256((__m256i*)(y + i),
121 _mm512_cvtepi64_epi32(compact2(_mm512_srli_epi64(c, 1))));
124 auto a = Morton<2, 32>::from_code(in[i]).decode();
130MORTON_AVX512_TARGET
inline void encode3(
const std::uint32_t* x,
const std::uint32_t* y,
131 const std::uint32_t* z, std::uint64_t* out,
134 for (; i + 8 <= n; i += 8) {
135 __m512i vx = _mm512_cvtepu32_epi64(_mm256_loadu_si256((
const __m256i*)(x + i)));
136 __m512i vy = _mm512_cvtepu32_epi64(_mm256_loadu_si256((
const __m256i*)(y + i)));
137 __m512i vz = _mm512_cvtepu32_epi64(_mm256_loadu_si256((
const __m256i*)(z + i)));
138 __m512i code = _mm512_or_si512(_mm512_or_si512(spread3(vx), _mm512_slli_epi64(spread3(vy), 1)),
139 _mm512_slli_epi64(spread3(vz), 2));
140 _mm512_storeu_si512((__m512i*)(out + i), code);
143 out[i] = Morton<3, 21>::encode(x[i], y[i], z[i]).code();
146MORTON_AVX512_TARGET
inline void decode3(
const std::uint64_t* in, std::uint32_t* x,
147 std::uint32_t* y, std::uint32_t* z, std::size_t n) {
149 for (; i + 8 <= n; i += 8) {
150 __m512i c = _mm512_loadu_si512((
const __m512i*)(in + i));
151 _mm256_storeu_si256((__m256i*)(x + i), _mm512_cvtepi64_epi32(compact3(c)));
152 _mm256_storeu_si256((__m256i*)(y + i),
153 _mm512_cvtepi64_epi32(compact3(_mm512_srli_epi64(c, 1))));
154 _mm256_storeu_si256((__m256i*)(z + i),
155 _mm512_cvtepi64_epi32(compact3(_mm512_srli_epi64(c, 2))));
158 auto a = Morton<3, 21>::from_code(in[i]).decode();
169MORTON_AVX512_TARGET
inline void add64(
const std::uint64_t* in, std::uint64_t* out, std::size_t n,
170 std::uint64_t notM, std::uint64_t dk, std::uint64_t mask,
171 std::uint64_t keep) {
172 const __m512i vnotM = _mm512_set1_epi64((
long long)notM);
173 const __m512i vdk = _mm512_set1_epi64((
long long)dk);
174 const __m512i vmask = _mm512_set1_epi64((
long long)mask);
175 const __m512i vkeep = _mm512_set1_epi64((
long long)keep);
177 for (; i + 8 <= n; i += 8) {
178 __m512i c = _mm512_loadu_si512((
const __m512i*)(in + i));
179 __m512i t = _mm512_add_epi64(_mm512_or_si512(c, vnotM), vdk);
180 __m512i r = _mm512_or_si512(_mm512_and_si512(t, vmask), _mm512_and_si512(c, vkeep));
181 _mm512_storeu_si512((__m512i*)(out + i), r);
184 out[i] = (((in[i] | notM) + dk) & mask) | (in[i] & keep);
187MORTON_AVX512_TARGET
inline void sub64(
const std::uint64_t* in, std::uint64_t* out, std::size_t n,
188 std::uint64_t dk, std::uint64_t mask, std::uint64_t keep) {
189 const __m512i vdk = _mm512_set1_epi64((
long long)dk);
190 const __m512i vmask = _mm512_set1_epi64((
long long)mask);
191 const __m512i vkeep = _mm512_set1_epi64((
long long)keep);
193 for (; i + 8 <= n; i += 8) {
194 __m512i c = _mm512_loadu_si512((
const __m512i*)(in + i));
195 __m512i t = _mm512_sub_epi64(_mm512_and_si512(c, vmask), vdk);
196 __m512i r = _mm512_or_si512(_mm512_and_si512(t, vmask), _mm512_and_si512(c, vkeep));
197 _mm512_storeu_si512((__m512i*)(out + i), r);
200 out[i] = (((in[i] & mask) - dk) & mask) | (in[i] & keep);
207#undef MORTON_AVX512_TARGET
Core Morton<Dim,Bits> type — Z-order codes with O(1) arithmetic in Morton space.
void decode2(const typename Morton< 2, Bits >::code_type *in, typename Morton< 2, Bits >::coord_type *x, typename Morton< 2, Bits >::coord_type *y, std::size_t n)
Decode an array of codes back to coordinate arrays (2D).
Definition batch.hpp:129
void encode3(const typename Morton< 3, Bits >::coord_type *x, const typename Morton< 3, Bits >::coord_type *y, const typename Morton< 3, Bits >::coord_type *z, typename Morton< 3, Bits >::code_type *out, std::size_t n)
Encode arrays of coordinates (3D) into codes.
Definition batch.hpp:110
void encode2(const typename Morton< 2, Bits >::coord_type *x, const typename Morton< 2, Bits >::coord_type *y, typename Morton< 2, Bits >::code_type *out, std::size_t n)
Encode arrays of coordinates (2D) into codes.
Definition batch.hpp:92
void decode3(const typename Morton< 3, Bits >::code_type *in, typename Morton< 3, Bits >::coord_type *x, typename Morton< 3, Bits >::coord_type *y, typename Morton< 3, Bits >::coord_type *z, std::size_t n)
Decode an array of codes back to coordinate arrays (3D).
Definition batch.hpp:149