| 573 | |
| 574 | template <typename T> |
| 575 | void quantize_cpu_impl(float* code, const T* A, float* absmax, unsigned char* out, long long blocksize, long long n) { |
| 576 | if (blocksize <= 0 || n <= 0) |
| 577 | return; |
| 578 | |
| 579 | // Get LUT from global cache (built once per codebook, shared by all OMP threads) |
| 580 | const unsigned char* lut = get_global_lut(code); |
| 581 | |
| 582 | const long long num_blocks = (n + blocksize - 1) / blocksize; |
| 583 | |
| 584 | BNB_OMP_PARALLEL_FOR |
| 585 | for (long long b = 0; b < num_blocks; ++b) { |
| 586 | const long long block_start = b * blocksize; |
| 587 | const long long block_end = std::min(block_start + blocksize, n); |
| 588 | const long long block_len = block_end - block_start; |
| 589 | |
| 590 | // Compute absmax for this block |
| 591 | float absmax_block = 0.0f; |
| 592 | |
| 593 | #if defined(_M_ARM64) || defined(__aarch64__) |
| 594 | absmax_block = neon_absmax<T>(A + block_start, block_len); |
| 595 | #else |
| 596 | #pragma omp simd reduction(max : absmax_block) |
| 597 | for (long long i = block_start; i < block_end; ++i) { |
| 598 | float val; |
| 599 | if constexpr (std::is_same<T, float>::value) |
| 600 | val = A[i]; |
| 601 | else if constexpr (std::is_same<T, bf16_t>::value) |
| 602 | val = bf16_to_float(A[i].v); |
| 603 | else |
| 604 | val = fp16_to_float(A[i].v); |
| 605 | absmax_block = std::max(absmax_block, std::fabs(val)); |
| 606 | } |
| 607 | #endif |
| 608 | |
| 609 | absmax[b] = absmax_block; |
| 610 | |
| 611 | if (absmax_block == 0.0f) { |
| 612 | for (long long i = block_start; i < block_end; ++i) { |
| 613 | out[i] = 0; |
| 614 | } |
| 615 | continue; |
| 616 | } |
| 617 | |
| 618 | const float inv_absmax = 1.0f / absmax_block; |
| 619 | |
| 620 | #if defined(_M_ARM64) || defined(__aarch64__) |
| 621 | { |
| 622 | long long i = 0; |
| 623 | float32x4_t vinv = vdupq_n_f32(inv_absmax); |
| 624 | for (; i + 4 <= block_len; i += 4) { |
| 625 | float32x4_t v; |
| 626 | if constexpr (std::is_same<T, float>::value) |
| 627 | v = vld1q_f32(reinterpret_cast<const float*>(A + block_start + i)); |
| 628 | else if constexpr (std::is_same<T, bf16_t>::value) |
| 629 | v = neon_bf16x4_to_f32(A + block_start + i); |
| 630 | else |
| 631 | v = neon_fp16x4_to_f32(A + block_start + i); |
| 632 | v = vmulq_f32(v, vinv); |
nothing calls this directly
no test coverage detected