| 387 | #endif |
| 388 | |
| 389 | SZ_PUBLIC void sz_fill_haswell(sz_ptr_t target, sz_size_t length, sz_u8_t value) { |
| 390 | char value_char = *(char *)&value; |
| 391 | __m256i value_vec = _mm256_set1_epi8(value_char); |
| 392 | // The naive implementation of this function is very simple. |
| 393 | // It assumes the CPU is great at handling unaligned "stores". |
| 394 | // |
| 395 | // for (; length >= 32; target += 32, length -= 32) _mm256_storeu_si256(target, value_vec); |
| 396 | // sz_fill_serial(target, length, value); |
| 397 | // |
| 398 | // When the buffer is small, there isn't much to innovate. |
| 399 | if (length <= 32) sz_fill_serial(target, length, value); |
| 400 | // When the buffer is aligned, we can avoid any split-stores. |
| 401 | else { |
| 402 | sz_size_t head_length = (32 - ((sz_size_t)target % 32)) % 32; // 31 or less. |
| 403 | sz_size_t tail_length = (sz_size_t)(target + length) % 32; // 31 or less. |
| 404 | sz_size_t body_length = length - head_length - tail_length; // Multiple of 32. |
| 405 | sz_u16_t value16 = (sz_u16_t)value * 0x0101u; |
| 406 | sz_u32_t value32 = (sz_u32_t)value16 * 0x00010001u; |
| 407 | sz_u64_t value64 = (sz_u64_t)value32 * 0x0000000100000001ull; |
| 408 | |
| 409 | // Fill the head of the buffer. This part is much cleaner with AVX-512. |
| 410 | if (head_length & 1) *(sz_u8_t *)target = value, target++, head_length--; |
| 411 | if (head_length & 2) *(sz_u16_t *)target = value16, target += 2, head_length -= 2; |
| 412 | if (head_length & 4) *(sz_u32_t *)target = value32, target += 4, head_length -= 4; |
| 413 | if (head_length & 8) *(sz_u64_t *)target = value64, target += 8, head_length -= 8; |
| 414 | if (head_length & 16) |
| 415 | _mm_store_si128((__m128i *)target, _mm_set1_epi8(value_char)), target += 16, head_length -= 16; |
| 416 | sz_assert_((sz_size_t)target % 32 == 0 && "Target is supposed to be aligned to the YMM register size."); |
| 417 | |
| 418 | // Fill the aligned body of the buffer. |
| 419 | for (; body_length >= 32; target += 32, body_length -= 32) _mm256_store_si256((__m256i *)target, value_vec); |
| 420 | |
| 421 | // Fill the tail of the buffer. This part is much cleaner with AVX-512. |
| 422 | sz_assert_((sz_size_t)target % 32 == 0 && "Target is supposed to be aligned to the YMM register size."); |
| 423 | if (tail_length & 16) |
| 424 | _mm_store_si128((__m128i *)target, _mm_set1_epi8(value_char)), target += 16, tail_length -= 16; |
| 425 | if (tail_length & 8) *(sz_u64_t *)target = value64, target += 8, tail_length -= 8; |
| 426 | if (tail_length & 4) *(sz_u32_t *)target = value32, target += 4, tail_length -= 4; |
| 427 | if (tail_length & 2) *(sz_u16_t *)target = value16, target += 2, tail_length -= 2; |
| 428 | if (tail_length & 1) *(sz_u8_t *)target = value, target++, tail_length--; |
| 429 | } |
| 430 | } |
| 431 | |
| 432 | SZ_PUBLIC void sz_copy_haswell(sz_ptr_t target, sz_cptr_t source, sz_size_t length) { |
| 433 | // The naive implementation of this function is very simple. |
no test coverage detected
searching dependent graphs…