← Back to C-Kernel-Engine Docs Doxygen Source Documentation
 
Loading...
Searching...
No Matches
quantize_row_q8_k_avx.c File Reference

AVX entrypoint for exact Q8_K row quantization. More...

#include "ckernel_quant.h"

Go to the source code of this file.

Functions

void quantize_row_q8_k_avx (const float *x, void *vy, int k)
 
void quantize_row_q8_k_ref (const float *x, void *vy, int k)
 
void quantize_row_q8_k_sse (const float *x, void *vy, int k)
 

Detailed Description

AVX entrypoint for exact Q8_K row quantization.

CK-ENGINE KERNEL RULES:

  1. NO malloc/free - memory via bump allocator, pointers passed in
  2. NO OpenMP - parallelization at orchestrator/codegen layer
  3. API must define: inputs, outputs, workspace, and memory layouts
  4. Pure computation - deterministic, no side effects

After changes: make test && make llamacpp-parity-full

Definition in file quantize_row_q8_k_avx.c.

Function Documentation

◆ quantize_row_q8_k_avx()

void quantize_row_q8_k_avx ( const float *  x,
void *  vy,
int  k 
)

Definition at line 20 of file quantize_row_q8_k_avx.c.

20 {
21 /* Reuse the parity-clean SIMD implementation until a wider AVX variant is
22 * worth maintaining separately. */
23#if defined(__SSE4_1__)
24 quantize_row_q8_k_sse(x, vy, k);
25#else
26 quantize_row_q8_k_ref(x, vy, k);
27#endif
28}
void quantize_row_q8_k_sse(const float *x, void *vy, int k)
void quantize_row_q8_k_ref(const float *x, void *vy, int k)

References quantize_row_q8_k_ref(), and quantize_row_q8_k_sse().

Referenced by quantize_row_q8_k().

◆ quantize_row_q8_k_ref()

void quantize_row_q8_k_ref ( const float *  x,
void *  vy,
int  k 
)

Definition at line 61 of file gemm_kernels_q4k_q8k.c.

61 {
62 if (!x || !vy || k <= 0) {
63 return;
64 }
65 assert(k % QK_K == 0);
66 const int nb = k / QK_K;
67 block_q8_K *y = (block_q8_K *)vy;
68
69 for (int i = 0; i < nb; ++i) {
70 float max = 0.0f;
71 float amax = 0.0f;
72 for (int j = 0; j < QK_K; ++j) {
73 float ax = fabsf(x[j]);
74 if (ax > amax) {
75 amax = ax;
76 max = x[j];
77 }
78 }
79 if (!amax) {
80 y[i].d = 0.0f;
81 memset(y[i].qs, 0, sizeof(y[i].qs));
82 memset(y[i].bsums, 0, sizeof(y[i].bsums));
83 x += QK_K;
84 continue;
85 }
86
87 const float iscale = -127.0f / max;
88 for (int j = 0; j < QK_K; ++j) {
89 /* llama.cpp rounds the multiply before adding nearest_int's magic
90 * constant. Contracting both operations changes Q8_K tie cases. */
91 float scaled = iscale * x[j];
92 int v = ck_nearest_int(scaled);
93 if (v > 127) {
94 v = 127;
95 }
96 if (v < -128) {
97 v = -128;
98 }
99 y[i].qs[j] = (int8_t)v;
100 }
101
102 for (int j = 0; j < QK_K / 16; ++j) {
103 int sum = 0;
104 const int8_t *qs = &y[i].qs[j * 16];
105 for (int ii = 0; ii < 16; ++ii) {
106 sum += qs[ii];
107 }
108 y[i].bsums[j] = (int16_t)sum;
109 }
110
111 y[i].d = 1.0f / iscale;
112 x += QK_K;
113 }
114}
#define QK_K
static int ck_nearest_int(float fval)
int8_t qs[256]
int16_t bsums[256/16]

Referenced by quantize_row_q8_k_avx().

◆ quantize_row_q8_k_sse()

void quantize_row_q8_k_sse ( const float *  x,
void *  vy,
int  k 
)

Definition at line 22 of file quantize_row_q8_k_sse.c.

22 {
23 if (!x || !vy || k <= 0) {
24 return;
25 }
26 assert(k % QK_K == 0);
27
28 const int nb = k / QK_K;
29 block_q8_K *y = (block_q8_K *)vy;
30
31 for (int i = 0; i < nb; ++i) {
32 /* Keep the exact signed-max selection contract from llama.cpp/ref. */
33 float max = 0.0f;
34 float amax = 0.0f;
35 for (int j = 0; j < QK_K; ++j) {
36 const float xv = x[j];
37 const float ax = fabsf(xv);
38 if (ax > amax) {
39 amax = ax;
40 max = xv;
41 }
42 }
43
44 if (amax == 0.0f) {
45 y[i].d = 0.0f;
46 memset(y[i].qs, 0, sizeof(y[i].qs));
47 memset(y[i].bsums, 0, sizeof(y[i].bsums));
48 x += QK_K;
49 continue;
50 }
51
52 const float iscale = -127.0f / max;
53 const __m128 v_iscale = _mm_set1_ps(iscale);
54 const __m128 v_magic = _mm_set1_ps(12582912.0f);
55 const __m128i v_mantissa = _mm_set1_epi32(0x007fffff);
56 const __m128i v_bias = _mm_set1_epi32(0x00400000);
57 const __m128i v_min = _mm_set1_epi32(-128);
58 const __m128i v_max = _mm_set1_epi32(127);
59
60 for (int j = 0; j < QK_K; j += 16) {
61 const __m128 x0 = _mm_loadu_ps(x + j + 0);
62 const __m128 x1 = _mm_loadu_ps(x + j + 4);
63 const __m128 x2 = _mm_loadu_ps(x + j + 8);
64 const __m128 x3 = _mm_loadu_ps(x + j + 12);
65
66 __m128i q0 = _mm_sub_epi32(
67 _mm_and_si128(_mm_castps_si128(_mm_add_ps(_mm_mul_ps(x0, v_iscale), v_magic)), v_mantissa),
68 v_bias);
69 __m128i q1 = _mm_sub_epi32(
70 _mm_and_si128(_mm_castps_si128(_mm_add_ps(_mm_mul_ps(x1, v_iscale), v_magic)), v_mantissa),
71 v_bias);
72 __m128i q2 = _mm_sub_epi32(
73 _mm_and_si128(_mm_castps_si128(_mm_add_ps(_mm_mul_ps(x2, v_iscale), v_magic)), v_mantissa),
74 v_bias);
75 __m128i q3 = _mm_sub_epi32(
76 _mm_and_si128(_mm_castps_si128(_mm_add_ps(_mm_mul_ps(x3, v_iscale), v_magic)), v_mantissa),
77 v_bias);
78
79 q0 = _mm_min_epi32(_mm_max_epi32(q0, v_min), v_max);
80 q1 = _mm_min_epi32(_mm_max_epi32(q1, v_min), v_max);
81 q2 = _mm_min_epi32(_mm_max_epi32(q2, v_min), v_max);
82 q3 = _mm_min_epi32(_mm_max_epi32(q3, v_min), v_max);
83
84 const __m128i q01 = _mm_packs_epi32(q0, q1);
85 const __m128i q23 = _mm_packs_epi32(q2, q3);
86 const __m128i q0123 = _mm_packs_epi16(q01, q23);
87
88 _mm_storeu_si128((__m128i *)(y[i].qs + j), q0123);
89
90 int sum = 0;
91 for (int ii = 0; ii < 16; ++ii) {
92 sum += y[i].qs[j + ii];
93 }
94 y[i].bsums[j / 16] = (int16_t)sum;
95 }
96
97 y[i].d = 1.0f / iscale;
98 x += QK_K;
99 }
100}

Referenced by quantize_row_q8_k_avx().