| 270 | |
| 271 | template<int NBytes> |
| 272 | inline void lut_dists_block32_4b(const uint8_t* codes, const uint8_t* luts, |
| 273 | uint8_t* dists_out, int64_t nblocks) |
| 274 | { |
| 275 | static_assert(NBytes > 0, "Code length <= 0 is not valid"); |
| 276 | static const __m256i low_4bits_mask = _mm256_set1_epi8(0x0F); |
| 277 | |
| 278 | for (int64_t i = 0; i < nblocks; i++) { |
| 279 | auto totals = _mm256_setzero_si256(); |
| 280 | for (uint8_t j = 0; j < NBytes; j++) { |
| 281 | // auto x_col = load_si256i(codes); |
| 282 | auto x_col = stream_load_si256i(codes); |
| 283 | auto lut_low = load_si256i(luts); |
| 284 | auto lut_high = load_si256i(luts + 32); |
| 285 | // auto both_luts = load_si256i(luts); |
| 286 | // auto lut_low = _mm256_permute2x128_si256(both_luts, both_luts, 0 + (0 << 4)); |
| 287 | // auto lut_high = _mm256_permute2x128_si256(both_luts, both_luts, 1 + (1 << 4)); |
| 288 | |
| 289 | // compute distances via lookups; we have one table for the upper |
| 290 | // 4 bits of each byte in x, and one for the lower 4 bits; the |
| 291 | // shuffle instruction always looks at the lower 4 bits, so we |
| 292 | // have to shift x to look at its upper 4 bits; also note that |
| 293 | // we have to mask out the upper bit because the shuffle |
| 294 | // instruction will zero the corresponding byte if this bit is set |
| 295 | auto x_low = _mm256_and_si256(x_col, low_4bits_mask); |
| 296 | auto x_high = _mm256_srli_epi16(x_col, 4); |
| 297 | x_high = _mm256_and_si256(x_high, low_4bits_mask); |
| 298 | |
| 299 | auto dists_low = _mm256_shuffle_epi8(lut_low, x_low); |
| 300 | auto dists_high = _mm256_shuffle_epi8(lut_high, x_high); |
| 301 | |
| 302 | totals = _mm256_adds_epu8(totals, dists_low); |
| 303 | totals = _mm256_adds_epu8(totals, dists_high); |
| 304 | |
| 305 | codes += 32; |
| 306 | luts += 64; |
| 307 | } |
| 308 | // _mm256_store_si256((__m256i*)dists_out, totals); |
| 309 | _mm256_stream_si256((__m256i*)dists_out, totals); // "non-temporal memory hint" |
| 310 | luts -= NBytes * 64; |
| 311 | // luts -= 8 * 32; |
| 312 | dists_out += 32; |
| 313 | } |
| 314 | } |
| 315 | |
| 316 | // for debugging; should have same behavior as above (vectorized and |
| 317 | // non-unpacking) func |
nothing calls this directly
no test coverage detected