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

SSE-optimized Q8_K row quantization kernel. More...

#include <assert.h>
#include <math.h>
#include <string.h>
#include <immintrin.h>
#include "ckernel_quant.h"

Go to the source code of this file.

Functions

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

Detailed Description

SSE-optimized Q8_K row quantization kernel.

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_sse.c.

Function Documentation

◆ 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}
#define QK_K
int8_t qs[256]
int16_t bsums[256/16]

References block_q8_K::bsums, block_q8_K::d, QK_K, and block_q8_K::qs.

Referenced by quantize_row_q8_k(), and quantize_row_q8_k_avx().