@@ -676,6 +676,44 @@ static void cpu_dequant_matvec(
676676 }
677677}
678678
679+ // 8-bit dequantized matrix-vector multiply (CPU fallback)
680+ // W is stored as packed uint32 (4 x 8-bit values per uint32)
681+ // scales/biases are bfloat16 per group
682+ static void cpu_dequant_matvec_8bit (
683+ const uint32_t *W, const uint16_t *scales, const uint16_t *biases,
684+ const float *x, float *out,
685+ int out_dim, int in_dim, int group_size
686+ ) {
687+ int num_groups = in_dim / group_size;
688+ int packed_per_group = group_size / 4 ;
689+ int packed_cols = in_dim / 4 ;
690+
691+ for (int row = 0 ; row < out_dim; row++) {
692+ float acc = 0 .0f ;
693+ const uint32_t *w_row = W + row * packed_cols;
694+ const uint16_t *s_row = scales + row * num_groups;
695+ const uint16_t *b_row = biases + row * num_groups;
696+
697+ for (int g = 0 ; g < num_groups; g++) {
698+ float scale = bf16_to_f32 (s_row[g]);
699+ float bias = bf16_to_f32 (b_row[g]);
700+ int base_packed = g * packed_per_group;
701+ int base_x = g * group_size;
702+
703+ for (int p = 0 ; p < packed_per_group; p++) {
704+ uint32_t packed = w_row[base_packed + p];
705+ int x_base = base_x + p * 4 ;
706+
707+ acc += ((float )((packed >> 0 ) & 0xFF ) * scale + bias) * x[x_base + 0 ];
708+ acc += ((float )((packed >> 8 ) & 0xFF ) * scale + bias) * x[x_base + 1 ];
709+ acc += ((float )((packed >> 16 ) & 0xFF ) * scale + bias) * x[x_base + 2 ];
710+ acc += ((float )((packed >> 24 ) & 0xFF ) * scale + bias) * x[x_base + 3 ];
711+ }
712+ }
713+ out[row] = acc;
714+ }
715+ }
716+
679717// RMS normalization: out = x * w / rms(x)
680718static void cpu_rms_norm (const float *x, const uint16_t *w_bf16, float *out, int dim, float eps) {
681719 float sum_sq = 0 .0f ;
@@ -847,6 +885,7 @@ static void cpu_conv1d_step(
847885 id <MTLComputePipelineState > matvec_v5; // LUT dequant variant
848886 id <MTLComputePipelineState > matvec_fast; // for in_dim > 4096
849887 id <MTLComputePipelineState > matvec_2bit; // 2-bit expert dequant kernel
888+ id <MTLComputePipelineState > matvec_8bit; // 8-bit gate dequant kernel
850889 id <MTLComputePipelineState > rms_norm_sum;
851890 id <MTLComputePipelineState > rms_norm_apply;
852891 id <MTLComputePipelineState > rms_norm_apply_bf16;
@@ -991,6 +1030,7 @@ static void cpu_conv1d_step(
9911030 ctx->matvec_v5 = makePipe (@" dequant_matvec_4bit_v5" ); // LUT variant (no uint→float conversions)
9921031 ctx->matvec_fast = makePipe (@" dequant_matvec_4bit_fast" );
9931032 ctx->matvec_2bit = makePipe (@" dequant_matvec_2bit" );
1033+ ctx->matvec_8bit = makePipe (@" dequant_matvec_8bit" );
9941034 ctx->rms_norm_sum = makePipe (@" rms_norm_sum_sq" );
9951035 ctx->rms_norm_apply = makePipe (@" rms_norm_apply" );
9961036 ctx->rms_norm_apply_bf16 = makePipe (@" rms_norm_apply_bf16" );
@@ -1309,6 +1349,7 @@ static void fast_dequant_matvec(
13091349 uint32_t in_dim;
13101350 uint32_t group_size;
13111351 int batch_slot; // which batch_out[slot] to use for GPU output
1352+ int bits; // quantization bits: 4 (default) or 8 (gate weights)
13121353} BatchMatvecSpec;
13131354
13141355// Run N matmuls in a single command buffer. All share the same input vector.
@@ -1332,8 +1373,12 @@ static void gpu_batch_matvec(
13321373 id <MTLBuffer > o_buf = ctx->batch_out [s->batch_slot];
13331374
13341375 id <MTLComputeCommandEncoder > enc = [cmdbuf computeCommandEncoder ];
1335- int use_v3 = (s->in_dim <= 4096 );
1336- [enc setComputePipelineState: use_v3 ? ctx->matvec_v3 : ctx->matvec_fast];
1376+ if (s->bits == 8 ) {
1377+ [enc setComputePipelineState: ctx->matvec_8bit];
1378+ } else {
1379+ int use_v3 = (s->in_dim <= 4096 );
1380+ [enc setComputePipelineState: use_v3 ? ctx->matvec_v3 : ctx->matvec_fast];
1381+ }
13371382 [enc setBuffer: ctx->wf_buf offset: w_off atIndex: 0 ];
13381383 [enc setBuffer: ctx->wf_buf offset: s_off atIndex: 1 ];
13391384 [enc setBuffer: ctx->wf_buf offset: b_off atIndex: 2 ];
@@ -1343,7 +1388,7 @@ static void gpu_batch_matvec(
13431388 [enc setBytes: &s->in_dim length: 4 atIndex: 6 ];
13441389 [enc setBytes: &s->group_size length: 4 atIndex: 7 ];
13451390
1346- if (use_v3 ) {
1391+ if (s-> bits == 8 || s-> in_dim <= 4096 ) {
13471392 uint32_t num_tgs = (s->out_dim + 7 ) / 8 ;
13481393 [enc dispatchThreadgroups: MTLSizeMake (num_tgs, 1 , 1 )
13491394 threadsPerThreadgroup: MTLSizeMake (256 , 1 , 1 )];
@@ -1386,8 +1431,12 @@ static void gpu_encode_batch_matvec(
13861431 id <MTLBuffer > o_buf = ctx->batch_out [s->batch_slot];
13871432
13881433 id <MTLComputeCommandEncoder > enc = [cmdbuf computeCommandEncoder ];
1389- int use_v3 = (s->in_dim <= 4096 );
1390- [enc setComputePipelineState: use_v3 ? ctx->matvec_v3 : ctx->matvec_fast];
1434+ if (s->bits == 8 ) {
1435+ [enc setComputePipelineState: ctx->matvec_8bit];
1436+ } else {
1437+ int use_v3 = (s->in_dim <= 4096 );
1438+ [enc setComputePipelineState: use_v3 ? ctx->matvec_v3 : ctx->matvec_fast];
1439+ }
13911440 [enc setBuffer: ctx->wf_buf offset: w_off atIndex: 0 ];
13921441 [enc setBuffer: ctx->wf_buf offset: s_off atIndex: 1 ];
13931442 [enc setBuffer: ctx->wf_buf offset: b_off atIndex: 2 ];
@@ -1397,7 +1446,7 @@ static void gpu_encode_batch_matvec(
13971446 [enc setBytes: &s->in_dim length: 4 atIndex: 6 ];
13981447 [enc setBytes: &s->group_size length: 4 atIndex: 7 ];
13991448
1400- if (use_v3 ) {
1449+ if (s-> bits == 8 || s-> in_dim <= 4096 ) {
14011450 uint32_t num_tgs = (s->out_dim + 7 ) / 8 ;
14021451 [enc dispatchThreadgroups: MTLSizeMake (num_tgs, 1 , 1 )
14031452 threadsPerThreadgroup: MTLSizeMake (256 , 1 , 1 )];
@@ -1846,8 +1895,13 @@ static void fast_batch_matvec(
18461895 } else {
18471896 for (int i = 0 ; i < num_specs; i++) {
18481897 BatchMatvecSpec *s = &specs[i];
1849- cpu_dequant_matvec (s->W , s->scales , s->biases , x, s->out_cpu ,
1850- s->out_dim , s->in_dim , s->group_size );
1898+ if (s->bits == 8 ) {
1899+ cpu_dequant_matvec_8bit (s->W , s->scales , s->biases , x, s->out_cpu ,
1900+ s->out_dim , s->in_dim , s->group_size );
1901+ } else {
1902+ cpu_dequant_matvec (s->W , s->scales , s->biases , x, s->out_cpu ,
1903+ s->out_dim , s->in_dim , s->group_size );
1904+ }
18511905 }
18521906 }
18531907}
@@ -2146,9 +2200,9 @@ static void full_attention_forward(
21462200 // Batch Q/K/V into one command buffer (3 dispatches, 1 commit)
21472201 if (qw && qs && qb && kw && ks && kb && vw && vs && vb) {
21482202 BatchMatvecSpec qkv_specs[3 ] = {
2149- { qw, qs, qb, q_proj_out, (uint32_t )q_proj_dim, HIDDEN_DIM , GROUP_SIZE , 0 },
2150- { kw, ks, kb, k, (uint32_t )kv_dim, HIDDEN_DIM , GROUP_SIZE , 1 },
2151- { vw, vs, vb, v, (uint32_t )kv_dim, HIDDEN_DIM , GROUP_SIZE , 2 },
2203+ { qw, qs, qb, q_proj_out, (uint32_t )q_proj_dim, HIDDEN_DIM , GROUP_SIZE , 0 , 4 },
2204+ { kw, ks, kb, k, (uint32_t )kv_dim, HIDDEN_DIM , GROUP_SIZE , 1 , 4 },
2205+ { vw, vs, vb, v, (uint32_t )kv_dim, HIDDEN_DIM , GROUP_SIZE , 2 , 4 },
21522206 };
21532207 fast_batch_matvec (normed, HIDDEN_DIM , qkv_specs, 3 );
21542208 }
@@ -2415,10 +2469,10 @@ static void linear_attention_forward(
24152469 if (qkv_w && qkv_s && qkv_b && z_w && z_s && z_b &&
24162470 b_w && b_s && b_b && a_w && a_s && a_b) {
24172471 BatchMatvecSpec la_specs[4 ] = {
2418- { qkv_w, qkv_s, qkv_b, qkv, (uint32_t )qkv_dim, HIDDEN_DIM , GROUP_SIZE , 0 },
2419- { z_w, z_s, z_b, z, (uint32_t )z_dim, HIDDEN_DIM , GROUP_SIZE , 1 },
2420- { b_w, b_s, b_b, beta, (uint32_t )LINEAR_NUM_V_HEADS , HIDDEN_DIM , GROUP_SIZE , 2 },
2421- { a_w, a_s, a_b, alpha, (uint32_t )LINEAR_NUM_V_HEADS , HIDDEN_DIM , GROUP_SIZE , 3 },
2472+ { qkv_w, qkv_s, qkv_b, qkv, (uint32_t )qkv_dim, HIDDEN_DIM , GROUP_SIZE , 0 , 4 },
2473+ { z_w, z_s, z_b, z, (uint32_t )z_dim, HIDDEN_DIM , GROUP_SIZE , 1 , 4 },
2474+ { b_w, b_s, b_b, beta, (uint32_t )LINEAR_NUM_V_HEADS , HIDDEN_DIM , GROUP_SIZE , 2 , 4 },
2475+ { a_w, a_s, a_b, alpha, (uint32_t )LINEAR_NUM_V_HEADS , HIDDEN_DIM , GROUP_SIZE , 3 , 4 },
24222476 };
24232477 fast_batch_matvec (normed, HIDDEN_DIM , la_specs, 4 );
24242478 }
@@ -2672,10 +2726,10 @@ static void moe_forward(
26722726 if (gate_w && gate_s && gate_b && sgw && sgs && sgb &&
26732727 suw && sus && sub && seg_w && seg_s && seg_b) {
26742728 BatchMatvecSpec moe_specs[4 ] = {
2675- { gate_w, gate_s, gate_b, gate_scores, (uint32_t )NUM_EXPERTS , HIDDEN_DIM , GROUP_SIZE , 0 },
2676- { sgw, sgs, sgb, shared_gate, (uint32_t )SHARED_INTERMEDIATE , HIDDEN_DIM , GROUP_SIZE , 1 },
2677- { suw, sus, sub, shared_up, (uint32_t )SHARED_INTERMEDIATE , HIDDEN_DIM , GROUP_SIZE , 2 },
2678- { seg_w, seg_s, seg_b, &shared_gate_score, 1 , HIDDEN_DIM , GROUP_SIZE , 3 },
2729+ { gate_w, gate_s, gate_b, gate_scores, (uint32_t )NUM_EXPERTS , HIDDEN_DIM , GROUP_SIZE , 0 , 8 },
2730+ { sgw, sgs, sgb, shared_gate, (uint32_t )SHARED_INTERMEDIATE , HIDDEN_DIM , GROUP_SIZE , 1 , 4 },
2731+ { suw, sus, sub, shared_up, (uint32_t )SHARED_INTERMEDIATE , HIDDEN_DIM , GROUP_SIZE , 2 , 4 },
2732+ { seg_w, seg_s, seg_b, &shared_gate_score, 1 , HIDDEN_DIM , GROUP_SIZE , 3 , 8 },
26792733 };
26802734 fast_batch_matvec (h_post, HIDDEN_DIM , moe_specs, 4 );
26812735 }
@@ -4043,9 +4097,9 @@ static void fused_layer_forward(
40434097
40444098 if (lc->q_w && lc->q_s && lc->q_b && lc->k_w && lc->k_s && lc->k_b &&
40454099 lc->v_w && lc->v_s && lc->v_b ) {
4046- attn_specs[0 ] = (BatchMatvecSpec){ lc->q_w , lc->q_s , lc->q_b , q_proj_out, (uint32_t )q_proj_dim, HIDDEN_DIM , GROUP_SIZE , 0 };
4047- attn_specs[1 ] = (BatchMatvecSpec){ lc->k_w , lc->k_s , lc->k_b , k_out, (uint32_t )kv_dim, HIDDEN_DIM , GROUP_SIZE , 1 };
4048- attn_specs[2 ] = (BatchMatvecSpec){ lc->v_w , lc->v_s , lc->v_b , v_out, (uint32_t )kv_dim, HIDDEN_DIM , GROUP_SIZE , 2 };
4100+ attn_specs[0 ] = (BatchMatvecSpec){ lc->q_w , lc->q_s , lc->q_b , q_proj_out, (uint32_t )q_proj_dim, HIDDEN_DIM , GROUP_SIZE , 0 , 4 };
4101+ attn_specs[1 ] = (BatchMatvecSpec){ lc->k_w , lc->k_s , lc->k_b , k_out, (uint32_t )kv_dim, HIDDEN_DIM , GROUP_SIZE , 1 , 4 };
4102+ attn_specs[2 ] = (BatchMatvecSpec){ lc->v_w , lc->v_s , lc->v_b , v_out, (uint32_t )kv_dim, HIDDEN_DIM , GROUP_SIZE , 2 , 4 };
40494103 num_attn_specs = 3 ;
40504104 }
40514105 }
@@ -4061,10 +4115,10 @@ static void fused_layer_forward(
40614115
40624116 if (lc->qkv_w && lc->qkv_s && lc->qkv_b && lc->z_w && lc->z_s && lc->z_b &&
40634117 lc->b_w && lc->b_s && lc->b_b && lc->a_w && lc->a_s && lc->a_b ) {
4064- attn_specs[0 ] = (BatchMatvecSpec){ lc->qkv_w , lc->qkv_s , lc->qkv_b , qkv_out, (uint32_t )qkv_dim, HIDDEN_DIM , GROUP_SIZE , 0 };
4065- attn_specs[1 ] = (BatchMatvecSpec){ lc->z_w , lc->z_s , lc->z_b , z_out, (uint32_t )z_dim, HIDDEN_DIM , GROUP_SIZE , 1 };
4066- attn_specs[2 ] = (BatchMatvecSpec){ lc->b_w , lc->b_s , lc->b_b , beta_out, (uint32_t )LINEAR_NUM_V_HEADS , HIDDEN_DIM , GROUP_SIZE , 2 };
4067- attn_specs[3 ] = (BatchMatvecSpec){ lc->a_w , lc->a_s , lc->a_b , alpha_out, (uint32_t )LINEAR_NUM_V_HEADS , HIDDEN_DIM , GROUP_SIZE , 3 };
4118+ attn_specs[0 ] = (BatchMatvecSpec){ lc->qkv_w , lc->qkv_s , lc->qkv_b , qkv_out, (uint32_t )qkv_dim, HIDDEN_DIM , GROUP_SIZE , 0 , 4 };
4119+ attn_specs[1 ] = (BatchMatvecSpec){ lc->z_w , lc->z_s , lc->z_b , z_out, (uint32_t )z_dim, HIDDEN_DIM , GROUP_SIZE , 1 , 4 };
4120+ attn_specs[2 ] = (BatchMatvecSpec){ lc->b_w , lc->b_s , lc->b_b , beta_out, (uint32_t )LINEAR_NUM_V_HEADS , HIDDEN_DIM , GROUP_SIZE , 2 , 4 };
4121+ attn_specs[3 ] = (BatchMatvecSpec){ lc->a_w , lc->a_s , lc->a_b , alpha_out, (uint32_t )LINEAR_NUM_V_HEADS , HIDDEN_DIM , GROUP_SIZE , 3 , 4 };
40684122 num_attn_specs = 4 ;
40694123 }
40704124 }
@@ -4359,8 +4413,13 @@ static void fused_layer_forward(
43594413 } else {
43604414 for (int i = 0 ; i < num_attn_specs; i++) {
43614415 BatchMatvecSpec *s = &attn_specs[i];
4362- cpu_dequant_matvec (s->W , s->scales , s->biases , normed, s->out_cpu ,
4363- s->out_dim , s->in_dim , s->group_size );
4416+ if (s->bits == 8 ) {
4417+ cpu_dequant_matvec_8bit (s->W , s->scales , s->biases , normed, s->out_cpu ,
4418+ s->out_dim , s->in_dim , s->group_size );
4419+ } else {
4420+ cpu_dequant_matvec (s->W , s->scales , s->biases , normed, s->out_cpu ,
4421+ s->out_dim , s->in_dim , s->group_size );
4422+ }
43644423 }
43654424 }
43664425 if (g_timing_enabled) { t1 = now_ms (); g_timing.cmd1_submit += t1 - t0; }
@@ -4398,9 +4457,9 @@ static void fused_layer_forward(
43984457 memset (spec_scores, 0 , NUM_EXPERTS * sizeof (float ));
43994458
44004459 // Gate projection matvec on pre-attention normed input (CPU, ~0.1ms for 512x4096)
4401- cpu_dequant_matvec (lc->gate_w , lc->gate_s , lc->gate_b ,
4402- normed, spec_scores,
4403- NUM_EXPERTS , HIDDEN_DIM , GROUP_SIZE );
4460+ cpu_dequant_matvec_8bit (lc->gate_w , lc->gate_s , lc->gate_b ,
4461+ normed, spec_scores,
4462+ NUM_EXPERTS , HIDDEN_DIM , GROUP_SIZE );
44044463 cpu_softmax (spec_scores, NUM_EXPERTS );
44054464
44064465 int spec_K = (K > MAX_K ) ? MAX_K : K;
@@ -5013,10 +5072,10 @@ static void fused_layer_forward(
50135072 // ---- Enc 5+: routing + shared expert projections (read buf_input) ----
50145073#if HAS_SHARED_EXPERT
50155074 BatchMatvecSpec moe_specs[4 ] = {
5016- { gate_w, gate_s, gate_b, gate_scores, (uint32_t )NUM_EXPERTS , HIDDEN_DIM , GROUP_SIZE , 0 },
5017- { sgw, sgs, sgb, shared_gate, (uint32_t )SHARED_INTERMEDIATE , HIDDEN_DIM , GROUP_SIZE , 1 },
5018- { suw, sus, sub, shared_up, (uint32_t )SHARED_INTERMEDIATE , HIDDEN_DIM , GROUP_SIZE , 2 },
5019- { seg_w, seg_s, seg_b, &shared_gate_score, 1 , HIDDEN_DIM , GROUP_SIZE , 3 },
5075+ { gate_w, gate_s, gate_b, gate_scores, (uint32_t )NUM_EXPERTS , HIDDEN_DIM , GROUP_SIZE , 0 , 8 },
5076+ { sgw, sgs, sgb, shared_gate, (uint32_t )SHARED_INTERMEDIATE , HIDDEN_DIM , GROUP_SIZE , 1 , 4 },
5077+ { suw, sus, sub, shared_up, (uint32_t )SHARED_INTERMEDIATE , HIDDEN_DIM , GROUP_SIZE , 2 , 4 },
5078+ { seg_w, seg_s, seg_b, &shared_gate_score, 1 , HIDDEN_DIM , GROUP_SIZE , 3 , 8 },
50205079 };
50215080 int num_moe_specs = 4 ;
50225081#else
@@ -5070,10 +5129,10 @@ static void fused_layer_forward(
50705129 if (have_moe_weights) {
50715130#if HAS_SHARED_EXPERT
50725131 BatchMatvecSpec moe_specs[4 ] = {
5073- { gate_w, gate_s, gate_b, gate_scores, (uint32_t )NUM_EXPERTS , HIDDEN_DIM , GROUP_SIZE , 0 },
5074- { sgw, sgs, sgb, shared_gate, (uint32_t )SHARED_INTERMEDIATE , HIDDEN_DIM , GROUP_SIZE , 1 },
5075- { suw, sus, sub, shared_up, (uint32_t )SHARED_INTERMEDIATE , HIDDEN_DIM , GROUP_SIZE , 2 },
5076- { seg_w, seg_s, seg_b, &shared_gate_score, 1 , HIDDEN_DIM , GROUP_SIZE , 3 },
5132+ { gate_w, gate_s, gate_b, gate_scores, (uint32_t )NUM_EXPERTS , HIDDEN_DIM , GROUP_SIZE , 0 , 8 },
5133+ { sgw, sgs, sgb, shared_gate, (uint32_t )SHARED_INTERMEDIATE , HIDDEN_DIM , GROUP_SIZE , 1 , 4 },
5134+ { suw, sus, sub, shared_up, (uint32_t )SHARED_INTERMEDIATE , HIDDEN_DIM , GROUP_SIZE , 2 , 4 },
5135+ { seg_w, seg_s, seg_b, &shared_gate_score, 1 , HIDDEN_DIM , GROUP_SIZE , 3 , 8 },
50775136 };
50785137 fast_batch_matvec (h_post, HIDDEN_DIM , moe_specs, 4 );
50795138#else
0 commit comments