Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 29 additions & 16 deletions ggml/src/ggml-cpu/arch/x86/quants.c
Original file line number Diff line number Diff line change
Expand Up @@ -716,29 +716,42 @@ void ggml_vec_dot_q4_0_q8_0(int n, float * GGML_RESTRICT s, size_t bs, const voi
float sumf = 0;

#if defined(__AVX2__)
// Initialize accumulator with zeros
__m256 acc = _mm256_setzero_ps();

// Main loop
for (; ib < nb; ++ib) {
/* Compute combined scale for the block */
const __m256 d = _mm256_set1_ps( GGML_CPU_FP16_TO_FP32(x[ib].d) * GGML_CPU_FP16_TO_FP32(y[ib].d) );

__m256i qx = bytes_from_nibbles_32(x[ib].qs);
// Two independent FMA accumulator chains to hide the latency of the
// `_mm256_fmadd_ps` reduction: the original loop accumulated every block
// into a single `acc`, forming a serial dependency chain one FMA long per
// block. Processing two blocks per iteration into `acc0`/`acc1` keeps two
// FMAs in flight and halves the loop-control overhead. The two partial
// sums are combined before the final horizontal reduce.
const __m256i off = _mm256_set1_epi8( 8 );

__m256 acc0 = _mm256_setzero_ps();
__m256 acc1 = _mm256_setzero_ps();

// Main loop, two blocks per iteration.
for (; ib + 1 < nb; ib += 2) {
const __m256 d0 = _mm256_set1_ps( GGML_CPU_FP16_TO_FP32(x[ib+0].d) * GGML_CPU_FP16_TO_FP32(y[ib+0].d) );
const __m256 d1 = _mm256_set1_ps( GGML_CPU_FP16_TO_FP32(x[ib+1].d) * GGML_CPU_FP16_TO_FP32(y[ib+1].d) );

// Now we have a vector with bytes in [ 0 .. 15 ] interval. Offset them into [ -8 .. +7 ] interval.
const __m256i off = _mm256_set1_epi8( 8 );
qx = _mm256_sub_epi8( qx, off );
const __m256i qx0 = _mm256_sub_epi8( bytes_from_nibbles_32(x[ib+0].qs), off );
const __m256i qx1 = _mm256_sub_epi8( bytes_from_nibbles_32(x[ib+1].qs), off );

__m256i qy = _mm256_loadu_si256((const __m256i *)y[ib].qs);
const __m256i qy0 = _mm256_loadu_si256((const __m256i *)y[ib+0].qs);
const __m256i qy1 = _mm256_loadu_si256((const __m256i *)y[ib+1].qs);

const __m256 q = mul_sum_i8_pairs_float(qx, qy);
acc0 = _mm256_fmadd_ps( d0, mul_sum_i8_pairs_float(qx0, qy0), acc0 );
acc1 = _mm256_fmadd_ps( d1, mul_sum_i8_pairs_float(qx1, qy1), acc1 );
}

/* Multiply q with scale and accumulate */
acc = _mm256_fmadd_ps( d, q, acc );
// Trailing odd block.
for (; ib < nb; ++ib) {
const __m256 d = _mm256_set1_ps( GGML_CPU_FP16_TO_FP32(x[ib].d) * GGML_CPU_FP16_TO_FP32(y[ib].d) );
const __m256i qx = _mm256_sub_epi8( bytes_from_nibbles_32(x[ib].qs), off );
const __m256i qy = _mm256_loadu_si256((const __m256i *)y[ib].qs);
acc0 = _mm256_fmadd_ps( d, mul_sum_i8_pairs_float(qx, qy), acc0 );
}

sumf = hsum_float_8(acc);
sumf = hsum_float_8(_mm256_add_ps(acc0, acc1));
#elif defined(__AVX__)
__m256 accum = _mm256_setzero_ps();
for (; ib + 1 < nb; ib += 2) {
Expand Down
Loading