kazutab commited on
Commit
a779940
·
verified ·
1 Parent(s): 80e5f6d

Upload folder using huggingface_hub (part 5)

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. backend/llama.cpp/ggml/src/ggml-opencl/kernels/flash_attn_f32_q8_0.cl +1791 -0
  2. backend/llama.cpp/ggml/src/ggml-opencl/kernels/flash_attn_pre_f16.cl +156 -0
  3. backend/llama.cpp/ggml/src/ggml-opencl/kernels/gated_delta_net.cl +249 -0
  4. backend/llama.cpp/ggml/src/ggml-opencl/kernels/gelu.cl +89 -0
  5. backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_moe_mxfp4_f32.cl +162 -0
  6. backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_moe_mxfp4_f32_ns.cl +374 -0
  7. backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_moe_mxfp4_q8_1_dp4a.cl +186 -0
  8. backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_moe_q4_0_f32_ns.cl +324 -0
  9. backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_moe_q4_0_q8_1_dp4a.cl +165 -0
  10. backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_moe_q4_1_f32_ns.cl +326 -0
  11. backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_moe_q4_k_f32_ns.cl +348 -0
  12. backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_moe_q4_k_q8_1_dp4a.cl +202 -0
  13. backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_moe_q5_0_f32_ns.cl +328 -0
  14. backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_moe_q5_1_f32_ns.cl +330 -0
  15. backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_moe_q5_k_f32_ns.cl +356 -0
  16. backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_moe_q6_k_f32_ns.cl +335 -0
  17. backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_moe_q6_k_q8_1_dp4a.cl +196 -0
  18. backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_moe_q8_0_f32_ns.cl +221 -0
  19. backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_moe_q8_1_dp4a.cl +221 -0
  20. backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_noshuffle_iq4_nl_f32.cl +150 -0
  21. backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_noshuffle_iq4_nl_q8_1_dp4a.cl +143 -0
  22. backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_noshuffle_q1_0_f32.cl +94 -0
  23. backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_noshuffle_q4_0_f32.cl +139 -0
  24. backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_noshuffle_q4_0_q8_1_dp4a.cl +127 -0
  25. backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_noshuffle_q4_1_f32.cl +132 -0
  26. backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_noshuffle_q4_k_f32.cl +172 -0
  27. backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_noshuffle_q4_k_q8_1_dp4a.cl +281 -0
  28. backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_noshuffle_q5_0_f32.cl +131 -0
  29. backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_noshuffle_q5_0_q8_1_dp4a.cl +235 -0
  30. backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_noshuffle_q5_1_f32.cl +134 -0
  31. backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_noshuffle_q5_k_f32.cl +176 -0
  32. backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_noshuffle_q5_k_q8_1_dp4a.cl +164 -0
  33. backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_noshuffle_q6_k_f32.cl +140 -0
  34. backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_noshuffle_q6_k_q8_1_dp4a.cl +144 -0
  35. backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_noshuffle_q8_0_f32.cl +129 -0
  36. backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_noshuffle_q8_0_q8_1_dp4a.cl +212 -0
  37. backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_xmem_f16_f32_os8.cl +233 -0
  38. backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemv_moe_mxfp4_f32.cl +156 -0
  39. backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemv_moe_mxfp4_f32_ns.cl +257 -0
  40. backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemv_moe_q4_0_f32_ns.cl +120 -0
  41. backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemv_moe_q4_1_f32_ns.cl +123 -0
  42. backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemv_moe_q4_k_f32_ns.cl +266 -0
  43. backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemv_moe_q5_0_f32_ns.cl +123 -0
  44. backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemv_moe_q5_1_f32_ns.cl +125 -0
  45. backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemv_moe_q5_k_f32_ns.cl +160 -0
  46. backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemv_moe_q6_k_f32_ns.cl +141 -0
  47. backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemv_noshuffle_iq4_nl_f32.cl +302 -0
  48. backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemv_noshuffle_q1_0_f32.cl +121 -0
  49. backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemv_noshuffle_q4_0_f32.cl +274 -0
  50. backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemv_noshuffle_q4_0_f32_spec.cl +268 -0
backend/llama.cpp/ggml/src/ggml-opencl/kernels/flash_attn_f32_q8_0.cl ADDED
@@ -0,0 +1,1791 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #pragma OPENCL EXTENSION cl_khr_fp16 : enable
2
+ #ifdef cl_khr_integer_dot_product
3
+ #pragma OPENCL EXTENSION cl_khr_integer_dot_product : enable
4
+ #define FA_HAVE_INT_DOT 1
5
+ #endif
6
+
7
+ #ifdef cl_khr_subgroup_shuffle
8
+ #pragma OPENCL EXTENSION cl_khr_subgroup_shuffle : enable
9
+ #define HAS_SUBGROUP_SHUFFLE 1
10
+ #elif defined(cl_qcom_subgroup_shuffle)
11
+ #pragma OPENCL EXTENSION cl_qcom_subgroup_shuffle : enable
12
+ #define HAS_SUBGROUP_SHUFFLE 1
13
+ #endif
14
+
15
+ // Flash attention: Q=f32, K=q8_0, V=q8_0.
16
+
17
+ #define ACC_TYPE float
18
+ #define ACC_TYPE4 float4
19
+ #define Q_DATA_TYPE4 float4
20
+ #define O_DATA_TYPE4 float4
21
+ #define MASK_DATA_TYPE half
22
+ #define CONVERT_Q_ACC4(x) (x)
23
+ #define CONVERT_O_DATA4(x) (x)
24
+
25
+ #define DK_VEC (DK/4)
26
+ #define DV_VEC (DV/4)
27
+
28
+ #ifndef FA_SG
29
+ #define FA_SG 64
30
+ #endif
31
+ #define Q1_WG_SIZE FA_SG
32
+
33
+ // The kernels are built with -cl-finite-math-only. On some older Adreno GPUs,
34
+ // infinite operand can cause undefined behavior and miscompilation for exp.
35
+ // Therefore, a large negative value is used instead.
36
+ #define FA_M_INIT (-3.0e38f)
37
+
38
+ // q8_0 block: 2B scale (half) + 32B int8 quants.
39
+ #define QK8_0 32
40
+ #define Q8_0_BLOCK_SIZE 34
41
+
42
+ #define DK_Q8_BLOCKS (DK / QK8_0)
43
+ #define DV_Q8_BLOCKS (DV / QK8_0)
44
+
45
+ inline float dot_q8_0_f32(const global char * block_ptr, ACC_TYPE4 * q_slice) {
46
+ float d = vload_half(0, (const global half *)block_ptr);
47
+ const global char * qs = block_ptr + 2;
48
+
49
+ float sum = 0.0f;
50
+ #pragma unroll
51
+ for (int i = 0; i < 8; i++) {
52
+ float4 qv = (float4)((float)qs[i*4], (float)qs[i*4+1], (float)qs[i*4+2], (float)qs[i*4+3]);
53
+ sum += dot(q_slice[i], qv);
54
+ }
55
+ return sum * d;
56
+ }
57
+
58
+ #ifdef FA_HAVE_INT_DOT
59
+ inline uint pack_i8x4(char a, char b, char c, char d) {
60
+ return ((uint)(uchar)a) |
61
+ ((uint)(uchar)b) << 8 |
62
+ ((uint)(uchar)c) << 16 |
63
+ ((uint)(uchar)d) << 24;
64
+ }
65
+
66
+ inline float quant_q_block_int8_packed(const ACC_TYPE4 * q_block,
67
+ uint * out_packed) {
68
+ float amax = 0.0f;
69
+ #pragma unroll
70
+ for (int i = 0; i < 8; ++i) {
71
+ float4 av = fabs(q_block[i]);
72
+ amax = fmax(amax, fmax(fmax(av.s0, av.s1), fmax(av.s2, av.s3)));
73
+ }
74
+ float qd = amax / 127.0f;
75
+ float qid = (amax > 0.0f) ? 127.0f / amax : 0.0f;
76
+
77
+ #pragma unroll
78
+ for (int i = 0; i < 8; ++i) {
79
+ float4 v = q_block[i] * qid;
80
+ char a = (char)((int)round(v.s0));
81
+ char b = (char)((int)round(v.s1));
82
+ char c = (char)((int)round(v.s2));
83
+ char d = (char)((int)round(v.s3));
84
+ out_packed[i] = pack_i8x4(a, b, c, d);
85
+ }
86
+ return qd;
87
+ }
88
+
89
+ inline float dot_q8_0_int(const global char * k_block_ptr,
90
+ const uint * q_packed,
91
+ float q_d) {
92
+ float kd = vload_half(0, (const global half *)k_block_ptr);
93
+ const global uchar * k_qs = (const global uchar *)(k_block_ptr + 2);
94
+
95
+ // k_qs is 2-byte aligned; pack chars per iteration rather than cast to uint*.
96
+ int sum = 0;
97
+ #pragma unroll
98
+ for (int i = 0; i < 8; ++i) {
99
+ uint k_packed =
100
+ (uint)k_qs[i*4 + 0] |
101
+ ((uint)k_qs[i*4 + 1]) << 8 |
102
+ ((uint)k_qs[i*4 + 2]) << 16 |
103
+ ((uint)k_qs[i*4 + 3]) << 24;
104
+ sum = dot_acc_sat_4x8packed_ss_int(q_packed[i], k_packed, sum);
105
+ }
106
+ return (float)sum * q_d * kd;
107
+ }
108
+ #endif // FA_HAVE_INT_DOT
109
+
110
+ inline void dequant_q8_0_f32(const global char * block_ptr, ACC_TYPE4 * out) {
111
+ float d = vload_half(0, (const global half *)block_ptr);
112
+ const global char * qs = block_ptr + 2;
113
+
114
+ #pragma unroll
115
+ for (int i = 0; i < 8; i++) {
116
+ out[i] = d * (float4)((float)qs[i*4], (float)qs[i*4+1], (float)qs[i*4+2], (float)qs[i*4+3]);
117
+ }
118
+ }
119
+
120
+ // max_bias<=0 returns 1.0 so score += 1.0 * mask[k] stays a no-op multiplier.
121
+ inline float get_alibi_slope(float max_bias, int head_idx, int n_head_log2, float m0, float m1) {
122
+ if (max_bias <= 0.0f) return 1.0f;
123
+ float base = (head_idx < n_head_log2) ? m0 : m1;
124
+ int exph = (head_idx < n_head_log2) ? (head_idx + 1) : (2*(head_idx - n_head_log2) + 1);
125
+ return pow(base, (float)exph);
126
+ }
127
+
128
+ // q1 decode: one query row per WG, threads sweep KV positions.
129
+ __kernel void flash_attn_f32_q8_0_q1(
130
+ const global void * q_void, ulong q_offset,
131
+ const global void * k_void, ulong k_offset,
132
+ const global void * v_void, ulong v_offset,
133
+ global void * o_void, ulong o_offset,
134
+ const float scale,
135
+ const int n_q,
136
+ const int n_kv,
137
+ const int is_causal,
138
+ const int n_head,
139
+ const ulong q_nb1, const ulong q_nb2, const ulong q_nb3,
140
+ const ulong k_nb1, const ulong k_nb2, const ulong k_nb3,
141
+ const ulong v_nb1, const ulong v_nb2, const ulong v_nb3,
142
+ const ulong o_nb1, const ulong o_nb2, const ulong o_nb3,
143
+ const float max_bias,
144
+ const float m0,
145
+ const float m1,
146
+ const int n_head_log2,
147
+ const float logit_softcap,
148
+ const int n_head_kv,
149
+ const global void* mask_void,
150
+ const ulong mask_offset,
151
+ const ulong mask_nb1,
152
+ const ulong mask_nb2,
153
+ const ulong mask_nb3,
154
+ const int mask_ne2,
155
+ const int mask_ne3,
156
+ const global void* sinks_void,
157
+ const ulong sinks_offset
158
+ ) {
159
+ const int tid = get_local_id(0);
160
+ const int head_batch_idx = get_global_id(1);
161
+
162
+ const int batch_idx = head_batch_idx / n_head;
163
+ const int head_idx = head_batch_idx % n_head;
164
+
165
+ const int gqa_ratio = n_head / n_head_kv;
166
+ const int head_kv_idx = head_idx / gqa_ratio;
167
+
168
+ const global char* q_base = (const global char*)q_void + q_offset;
169
+ const global char* k_base = (const global char*)k_void + k_offset;
170
+ const global char* v_base = (const global char*)v_void + v_offset;
171
+ global char* o_base = (global char*)o_void + o_offset;
172
+
173
+ const global char* mask_base = NULL;
174
+ if (mask_void != NULL) {
175
+ const int mask_head_idx = head_idx % mask_ne2;
176
+ const int mask_batch_idx = batch_idx % mask_ne3;
177
+ mask_base = (const global char*)mask_void + mask_offset + mask_batch_idx * mask_nb3 + mask_head_idx * mask_nb2;
178
+ }
179
+
180
+ ACC_TYPE4 q_priv[DK_VEC];
181
+ const ulong q_row_offset = batch_idx * q_nb3 + head_idx * q_nb2;
182
+ const global Q_DATA_TYPE4* q_ptr = (const global Q_DATA_TYPE4*)(q_base + q_row_offset);
183
+ #pragma unroll
184
+ for (int i = 0; i < DK_VEC; ++i) {
185
+ q_priv[i] = CONVERT_Q_ACC4(q_ptr[i]);
186
+ }
187
+
188
+ #ifdef FA_HAVE_INT_DOT
189
+ // Quantise Q once per thread; q_priv stays as fp for the V accumulate.
190
+ uint q_packed[DK_Q8_BLOCKS * 8];
191
+ float q_d_scale[DK_Q8_BLOCKS];
192
+ #pragma unroll
193
+ for (int b = 0; b < DK_Q8_BLOCKS; ++b) {
194
+ q_d_scale[b] = quant_q_block_int8_packed(&q_priv[b * 8], &q_packed[b * 8]);
195
+ }
196
+ #endif
197
+
198
+ float slope = get_alibi_slope(max_bias, head_idx, n_head_log2, m0, m1);
199
+
200
+ const global ACC_TYPE* sinks_ptr = NULL;
201
+ if (sinks_void != NULL) {
202
+ sinks_ptr = (const global ACC_TYPE*)((const global char*)sinks_void + sinks_offset);
203
+ }
204
+
205
+ // One-pass online softmax: per-thread maintains running (m_i, l_i, o_acc),
206
+ // updating each as new K positions are processed. Eliminates the second
207
+ // K read of the original two-pass implementation. After the loop, threads
208
+ // are merged via the standard FA-2 cross-thread reduction (rescale each
209
+ // thread's l_i and o_acc by alpha=exp(m_i_thread - m_final), then sum).
210
+ ACC_TYPE m_i = (sinks_ptr != NULL) ? sinks_ptr[head_idx] : FA_M_INIT;
211
+ ACC_TYPE l_i = 0.0f;
212
+ ACC_TYPE4 o_acc[DV_VEC];
213
+ #pragma unroll
214
+ for (int i = 0; i < DV_VEC; ++i) o_acc[i] = (ACC_TYPE4)(0.0f);
215
+
216
+ for (int k_idx = tid; k_idx < n_kv; k_idx += Q1_WG_SIZE) {
217
+ const global char* k_row = k_base + batch_idx * k_nb3 + head_kv_idx * k_nb2 + k_idx * k_nb1;
218
+ const global char* v_row = v_base + batch_idx * v_nb3 + head_kv_idx * v_nb2 + k_idx * v_nb1;
219
+
220
+ ACC_TYPE score = 0.0f;
221
+ #pragma unroll
222
+ for (int b = 0; b < DK_Q8_BLOCKS; b++) {
223
+ #ifdef FA_HAVE_INT_DOT
224
+ score += dot_q8_0_int(k_row + b * Q8_0_BLOCK_SIZE,
225
+ &q_packed[b * 8], q_d_scale[b]);
226
+ #else
227
+ score += dot_q8_0_f32(k_row + b * Q8_0_BLOCK_SIZE, &q_priv[b * 8]);
228
+ #endif
229
+ }
230
+ score *= scale;
231
+
232
+ if (mask_base != NULL) {
233
+ const global MASK_DATA_TYPE* mask_ptr = (const global MASK_DATA_TYPE*)(mask_base);
234
+ score += slope * (ACC_TYPE)mask_ptr[k_idx];
235
+ }
236
+ if (logit_softcap > 0.0f) {
237
+ score = logit_softcap * tanh(score / logit_softcap);
238
+ }
239
+
240
+ // Online softmax step.
241
+ const ACC_TYPE m_new = max(m_i, score);
242
+ const ACC_TYPE alpha = exp(m_i - m_new);
243
+ const ACC_TYPE p = exp(score - m_new);
244
+
245
+ l_i = alpha * l_i + p;
246
+ #pragma unroll
247
+ for (int i = 0; i < DV_VEC; ++i) o_acc[i] *= alpha;
248
+
249
+ #pragma unroll
250
+ for (int b = 0; b < DV_Q8_BLOCKS; b++) {
251
+ ACC_TYPE4 v_dequant[8];
252
+ dequant_q8_0_f32(v_row + b * Q8_0_BLOCK_SIZE, v_dequant);
253
+ #pragma unroll
254
+ for (int i = 0; i < 8; i++) {
255
+ o_acc[b * 8 + i] = mad(p, v_dequant[i], o_acc[b * 8 + i]);
256
+ }
257
+ }
258
+
259
+ m_i = m_new;
260
+ }
261
+
262
+ // Cross-thread reduce: max(m_i) -> m_final, then rescale per-thread l_i
263
+ // and o_acc by alpha = exp(m_i_thread - m_final) before sum-reduce.
264
+ __local ACC_TYPE local_m[Q1_WG_SIZE];
265
+ local_m[tid] = m_i;
266
+ barrier(CLK_LOCAL_MEM_FENCE);
267
+ #pragma unroll
268
+ for (int s = Q1_WG_SIZE / 2; s > 0; s >>= 1) {
269
+ if (tid < s) local_m[tid] = max(local_m[tid], local_m[tid + s]);
270
+ barrier(CLK_LOCAL_MEM_FENCE);
271
+ }
272
+ const ACC_TYPE m_final = local_m[0];
273
+
274
+ const ACC_TYPE alpha_final = exp(m_i - m_final);
275
+ l_i *= alpha_final;
276
+ #pragma unroll
277
+ for (int i = 0; i < DV_VEC; ++i) o_acc[i] *= alpha_final;
278
+
279
+ __local ACC_TYPE local_l[Q1_WG_SIZE];
280
+ __local ACC_TYPE4 local_o_comp[Q1_WG_SIZE];
281
+ local_l[tid] = l_i;
282
+ barrier(CLK_LOCAL_MEM_FENCE);
283
+ #pragma unroll
284
+ for (int s = Q1_WG_SIZE / 2; s > 0; s >>= 1) {
285
+ if (tid < s) local_l[tid] += local_l[tid + s];
286
+ barrier(CLK_LOCAL_MEM_FENCE);
287
+ }
288
+
289
+ const ulong o_row_offset = batch_idx * o_nb3 + head_idx * o_nb1;
290
+ global O_DATA_TYPE4 *o_row = (global O_DATA_TYPE4 *)(o_base + o_row_offset);
291
+ ACC_TYPE l_final = local_l[0];
292
+
293
+ if (sinks_ptr != NULL) {
294
+ l_final += exp(sinks_ptr[head_idx] - m_final);
295
+ }
296
+
297
+ if (l_final > 0.0f) {
298
+ const ACC_TYPE l_inv = 1.0f / l_final;
299
+ for (int i = 0; i < DV_VEC; i++) {
300
+ local_o_comp[tid] = o_acc[i];
301
+ barrier(CLK_LOCAL_MEM_FENCE);
302
+ #pragma unroll
303
+ for (int s = Q1_WG_SIZE / 2; s > 0; s >>= 1) {
304
+ if (tid < s) local_o_comp[tid] += local_o_comp[tid + s];
305
+ barrier(CLK_LOCAL_MEM_FENCE);
306
+ }
307
+ if (tid == 0) {
308
+ o_row[i] = CONVERT_O_DATA4(local_o_comp[0] * l_inv);
309
+ }
310
+ }
311
+ } else if (tid == 0) {
312
+ #pragma unroll
313
+ for (int i = 0; i < DV_VEC; ++i) o_row[i] = (O_DATA_TYPE4)(0.0f);
314
+ }
315
+ }
316
+
317
+ #ifdef cl_intel_subgroups
318
+ #pragma OPENCL EXTENSION cl_intel_subgroups : enable
319
+ #else
320
+ #pragma OPENCL EXTENSION cl_khr_subgroups : enable
321
+ #endif
322
+
323
+ #ifdef cl_qcom_reqd_sub_group_size
324
+ #pragma OPENCL EXTENSION cl_qcom_reqd_sub_group_size : enable
325
+ #define REQD_SUBGROUP_SIZE_64 __attribute__((qcom_reqd_sub_group_size("half")))
326
+ #else
327
+ #define REQD_SUBGROUP_SIZE_64
328
+ #endif
329
+
330
+ #define VEC_NSG 4
331
+ #define VEC_WG_SIZE (Q1_WG_SIZE * VEC_NSG)
332
+ #define Q1V_DV_PER_THREAD ((DV_VEC + Q1_WG_SIZE - 1) / Q1_WG_SIZE)
333
+
334
+ inline float4 dequant_q8_0_lane(const global char * block_ptr, int lane) {
335
+ const float d = vload_half(0, (const global half *)block_ptr);
336
+ const global char * qs = block_ptr + 2 + lane * 4;
337
+ return d * (float4)((float)qs[0], (float)qs[1], (float)qs[2], (float)qs[3]);
338
+ }
339
+
340
+ REQD_SUBGROUP_SIZE_64
341
+ __kernel void flash_attn_f32_q8_0_q1_vec(
342
+ const global void * q_void, ulong q_offset,
343
+ const global void * k_void, ulong k_offset,
344
+ const global void * v_void, ulong v_offset,
345
+ global void * o_void, ulong o_offset,
346
+ const float scale,
347
+ const int n_q,
348
+ const int n_kv,
349
+ const int is_causal,
350
+ const int n_head,
351
+ const ulong q_nb1, const ulong q_nb2, const ulong q_nb3,
352
+ const ulong k_nb1, const ulong k_nb2, const ulong k_nb3,
353
+ const ulong v_nb1, const ulong v_nb2, const ulong v_nb3,
354
+ const ulong o_nb1, const ulong o_nb2, const ulong o_nb3,
355
+ const float max_bias,
356
+ const float m0,
357
+ const float m1,
358
+ const int n_head_log2,
359
+ const float logit_softcap,
360
+ const int n_head_kv,
361
+ const global void* mask_void,
362
+ const ulong mask_offset,
363
+ const ulong mask_nb1,
364
+ const ulong mask_nb2,
365
+ const ulong mask_nb3,
366
+ const int mask_ne2,
367
+ const int mask_ne3,
368
+ const global void* sinks_void,
369
+ const ulong sinks_offset
370
+ ) {
371
+ const int tid = get_local_id(0);
372
+ const int sgid = tid / Q1_WG_SIZE;
373
+ const int tid_sg = tid % Q1_WG_SIZE;
374
+ const int head_batch_idx = get_global_id(1);
375
+
376
+ const int batch_idx = head_batch_idx / n_head;
377
+ const int head_idx = head_batch_idx % n_head;
378
+
379
+ const int gqa_ratio = n_head / n_head_kv;
380
+ const int head_kv_idx = head_idx / gqa_ratio;
381
+
382
+ const global char * q_base = (const global char *) q_void + q_offset;
383
+ const global char * k_base = (const global char *) k_void + k_offset;
384
+ const global char * v_base = (const global char *) v_void + v_offset;
385
+ global char * o_base = (global char *) o_void + o_offset;
386
+
387
+ const global char * mask_base = NULL;
388
+ if (mask_void != NULL) {
389
+ const int mask_head_idx = head_idx % mask_ne2;
390
+ const int mask_batch_idx = batch_idx % mask_ne3;
391
+ mask_base = (const global char *) mask_void + mask_offset +
392
+ mask_batch_idx * mask_nb3 + mask_head_idx * mask_nb2;
393
+ }
394
+
395
+ __local ACC_TYPE4 q_shared[DK_VEC];
396
+ {
397
+ const ulong q_row_offset = batch_idx * q_nb3 + head_idx * q_nb2;
398
+ const global Q_DATA_TYPE4 * q_ptr = (const global Q_DATA_TYPE4 *) (q_base + q_row_offset);
399
+ for (int i = tid; i < DK_VEC; i += VEC_WG_SIZE) {
400
+ q_shared[i] = CONVERT_Q_ACC4(q_ptr[i]);
401
+ }
402
+ }
403
+ barrier(CLK_LOCAL_MEM_FENCE);
404
+
405
+ const float slope = get_alibi_slope(max_bias, head_idx, n_head_log2, m0, m1);
406
+
407
+ const global ACC_TYPE * sinks_ptr = NULL;
408
+ if (sinks_void != NULL) {
409
+ sinks_ptr = (const global ACC_TYPE *) ((const global char *) sinks_void + sinks_offset);
410
+ }
411
+
412
+ ACC_TYPE4 o_acc[Q1V_DV_PER_THREAD];
413
+ #pragma unroll
414
+ for (int i = 0; i < Q1V_DV_PER_THREAD; ++i) o_acc[i] = (ACC_TYPE4)(0.0f);
415
+
416
+ ACC_TYPE m_i = FA_M_INIT;
417
+ ACC_TYPE l_i = 0.0f;
418
+
419
+ const int kv_per_sg = (n_kv + VEC_NSG - 1) / VEC_NSG;
420
+ const int kv_start = sgid * kv_per_sg;
421
+ const int kv_end = min(n_kv, kv_start + kv_per_sg);
422
+
423
+ for (int k_idx = kv_start; k_idx < kv_end; ++k_idx) {
424
+ const global char * k_row = k_base + batch_idx * k_nb3 + head_kv_idx * k_nb2 + k_idx * k_nb1;
425
+ const global char * v_row = v_base + batch_idx * v_nb3 + head_kv_idx * v_nb2 + k_idx * v_nb1;
426
+
427
+ ACC_TYPE4 dot4 = (ACC_TYPE4)(0.0f);
428
+ for (int qk = tid_sg; qk < DK_VEC; qk += Q1_WG_SIZE) {
429
+ const int block_idx = qk / 8;
430
+ const int lane = qk % 8;
431
+ const float4 k_v = dequant_q8_0_lane(k_row + block_idx * Q8_0_BLOCK_SIZE, lane);
432
+ dot4 = mad(q_shared[qk], k_v, dot4);
433
+ }
434
+ ACC_TYPE dot_partial = dot4.s0 + dot4.s1 + dot4.s2 + dot4.s3;
435
+ ACC_TYPE score = sub_group_reduce_add(dot_partial) * scale;
436
+
437
+ if (mask_base != NULL) {
438
+ const global MASK_DATA_TYPE * mask_ptr = (const global MASK_DATA_TYPE *) mask_base;
439
+ score += slope * (ACC_TYPE) mask_ptr[k_idx];
440
+ }
441
+ if (logit_softcap > 0.0f) {
442
+ score = logit_softcap * tanh(score / logit_softcap);
443
+ }
444
+
445
+ const ACC_TYPE m_new = max(m_i, score);
446
+ const ACC_TYPE scale_prev = native_exp(m_i - m_new);
447
+ const ACC_TYPE p = native_exp(score - m_new);
448
+
449
+ int idx = 0;
450
+ for (int dv = tid_sg; dv < DV_VEC; dv += Q1_WG_SIZE, ++idx) {
451
+ const int block_idx = dv / 8;
452
+ const int lane = dv % 8;
453
+ const float4 v_v = dequant_q8_0_lane(v_row + block_idx * Q8_0_BLOCK_SIZE, lane);
454
+ o_acc[idx] = mad(p, v_v, o_acc[idx] * scale_prev);
455
+ }
456
+ l_i = l_i * scale_prev + p;
457
+ m_i = m_new;
458
+ }
459
+
460
+ __local ACC_TYPE sg_m[VEC_NSG];
461
+ __local ACC_TYPE sg_l[VEC_NSG];
462
+ __local ACC_TYPE4 sg_o[VEC_NSG][DV_VEC];
463
+
464
+ if (tid_sg == 0) {
465
+ sg_m[sgid] = m_i;
466
+ sg_l[sgid] = l_i;
467
+ }
468
+ {
469
+ int idx = 0;
470
+ for (int dv = tid_sg; dv < DV_VEC; dv += Q1_WG_SIZE, ++idx) {
471
+ sg_o[sgid][dv] = o_acc[idx];
472
+ }
473
+ }
474
+ barrier(CLK_LOCAL_MEM_FENCE);
475
+
476
+ if (sgid == 0) {
477
+ ACC_TYPE m_final = sg_m[0];
478
+ #pragma unroll
479
+ for (int s = 1; s < VEC_NSG; ++s) {
480
+ m_final = max(m_final, sg_m[s]);
481
+ }
482
+ if (sinks_ptr != NULL) {
483
+ m_final = max(m_final, sinks_ptr[head_idx]);
484
+ }
485
+
486
+ ACC_TYPE l_final = 0.0f;
487
+ #pragma unroll
488
+ for (int s = 0; s < VEC_NSG; ++s) {
489
+ l_final += sg_l[s] * native_exp(sg_m[s] - m_final);
490
+ }
491
+ if (sinks_ptr != NULL) {
492
+ l_final += native_exp(sinks_ptr[head_idx] - m_final);
493
+ }
494
+ const ACC_TYPE l_inv = (l_final > 0.0f) ? (1.0f / l_final) : 0.0f;
495
+
496
+ const ulong o_row_offset = batch_idx * o_nb3 + head_idx * o_nb1;
497
+ global O_DATA_TYPE4 * o_row = (global O_DATA_TYPE4 *) (o_base + o_row_offset);
498
+
499
+ int idx = 0;
500
+ for (int dv = tid_sg; dv < DV_VEC; dv += Q1_WG_SIZE, ++idx) {
501
+ ACC_TYPE4 o_merged = (ACC_TYPE4)(0.0f);
502
+ #pragma unroll
503
+ for (int s = 0; s < VEC_NSG; ++s) {
504
+ const ACC_TYPE alpha = native_exp(sg_m[s] - m_final);
505
+ o_merged = mad((ACC_TYPE4)(alpha), sg_o[s][dv], o_merged);
506
+ }
507
+ o_row[dv] = CONVERT_O_DATA4(o_merged * l_inv);
508
+ }
509
+ }
510
+ }
511
+
512
+ // Flash-decoding split pass for q8_0 KV. Partial record: [m, l, O[DV]].
513
+ // Merge kernel from flash_attn_f32_f16.cl is type-agnostic and reused.
514
+ #define FA_PARTIAL_FLOATS (2 + DV)
515
+
516
+ __kernel void flash_attn_f32_q8_0_q1_split(
517
+ const global void * q_void, ulong q_offset,
518
+ const global void * k_void, ulong k_offset,
519
+ const global void * v_void, ulong v_offset,
520
+ const float scale,
521
+ const int n_q,
522
+ const int n_kv,
523
+ const int n_head,
524
+ const ulong q_nb1, const ulong q_nb2, const ulong q_nb3,
525
+ const ulong k_nb1, const ulong k_nb2, const ulong k_nb3,
526
+ const ulong v_nb1, const ulong v_nb2, const ulong v_nb3,
527
+ const float max_bias,
528
+ const float m0,
529
+ const float m1,
530
+ const int n_head_log2,
531
+ const float logit_softcap,
532
+ const int n_head_kv,
533
+ const global void * mask_void,
534
+ const ulong mask_offset,
535
+ const ulong mask_nb1,
536
+ const ulong mask_nb2,
537
+ const ulong mask_nb3,
538
+ const int mask_ne2,
539
+ const int mask_ne3,
540
+ global float * partial_void,
541
+ const int n_splits,
542
+ const int kv_per_split
543
+ ) {
544
+ const int tid = get_local_id(0);
545
+ const int head_batch_idx = get_global_id(1);
546
+ const int split_q_idx = get_global_id(2);
547
+ const int split_idx = split_q_idx % n_splits;
548
+ const int q_idx = split_q_idx / n_splits;
549
+ const int batch_idx = head_batch_idx / n_head;
550
+ const int head_idx = head_batch_idx % n_head;
551
+ const int gqa_ratio = n_head / n_head_kv;
552
+ const int head_kv_idx = head_idx / gqa_ratio;
553
+
554
+ const int kv_start = split_idx * kv_per_split;
555
+ const int kv_end = min(kv_start + kv_per_split, n_kv);
556
+
557
+ const ulong record_stride = (ulong) FA_PARTIAL_FLOATS;
558
+ const ulong record_idx = ((((ulong) batch_idx * n_head + head_idx) * n_q + q_idx)
559
+ * n_splits + split_idx);
560
+ global float * rec = partial_void + record_idx * record_stride;
561
+ global float4 * rec_o = (global float4 *) (rec + 2);
562
+
563
+ if (kv_start >= kv_end) {
564
+ // Empty split: leave sentinel partial for merge.
565
+ if (tid == 0) {
566
+ rec[0] = FA_M_INIT;
567
+ rec[1] = 0.0f;
568
+ }
569
+ return;
570
+ }
571
+
572
+ const global char * q_base = (const global char *) q_void + q_offset;
573
+ const global char * k_base = (const global char *) k_void + k_offset;
574
+ const global char * v_base = (const global char *) v_void + v_offset;
575
+
576
+ const global char * mask_base = NULL;
577
+ if (mask_void != NULL) {
578
+ const int mask_head_idx = head_idx % mask_ne2;
579
+ const int mask_batch_idx = batch_idx % mask_ne3;
580
+ mask_base = (const global char *) mask_void + mask_offset +
581
+ mask_batch_idx * mask_nb3 + mask_head_idx * mask_nb2 +
582
+ (ulong) q_idx * mask_nb1;
583
+ }
584
+
585
+ ACC_TYPE4 q_priv[DK_VEC];
586
+ const ulong q_row_offset = batch_idx * q_nb3 + head_idx * q_nb2 + (ulong) q_idx * q_nb1;
587
+ const global Q_DATA_TYPE4 * q_ptr = (const global Q_DATA_TYPE4 *) (q_base + q_row_offset);
588
+ #pragma unroll
589
+ for (int i = 0; i < DK_VEC; ++i) {
590
+ q_priv[i] = CONVERT_Q_ACC4(q_ptr[i]);
591
+ }
592
+
593
+ #ifdef FA_HAVE_INT_DOT
594
+ uint q_packed[DK_Q8_BLOCKS * 8];
595
+ float q_d_scale[DK_Q8_BLOCKS];
596
+ #pragma unroll
597
+ for (int b = 0; b < DK_Q8_BLOCKS; ++b) {
598
+ q_d_scale[b] = quant_q_block_int8_packed(&q_priv[b * 8], &q_packed[b * 8]);
599
+ }
600
+ #endif
601
+
602
+ const float slope = get_alibi_slope(max_bias, head_idx, n_head_log2, m0, m1);
603
+
604
+ // One-pass online softmax (FA-2): single sweep over the split's K range,
605
+ // updating per-thread (m_i, l_i, o_acc) per position. Eliminates the
606
+ // second K read of the original two-pass implementation.
607
+ ACC_TYPE m_i = FA_M_INIT;
608
+ ACC_TYPE l_i = 0.0f;
609
+ ACC_TYPE4 o_acc[DV_VEC];
610
+ #pragma unroll
611
+ for (int i = 0; i < DV_VEC; ++i) o_acc[i] = (ACC_TYPE4)(0.0f);
612
+
613
+ for (int k_idx = kv_start + tid; k_idx < kv_end; k_idx += Q1_WG_SIZE) {
614
+ const global char * k_row = k_base + batch_idx * k_nb3 + head_kv_idx * k_nb2 + k_idx * k_nb1;
615
+ const global char * v_row = v_base + batch_idx * v_nb3 + head_kv_idx * v_nb2 + k_idx * v_nb1;
616
+ ACC_TYPE score = 0.0f;
617
+ #pragma unroll
618
+ for (int b = 0; b < DK_Q8_BLOCKS; ++b) {
619
+ #ifdef FA_HAVE_INT_DOT
620
+ score += dot_q8_0_int(k_row + b * Q8_0_BLOCK_SIZE, &q_packed[b * 8], q_d_scale[b]);
621
+ #else
622
+ score += dot_q8_0_f32(k_row + b * Q8_0_BLOCK_SIZE, &q_priv[b * 8]);
623
+ #endif
624
+ }
625
+ score *= scale;
626
+ if (mask_base != NULL) {
627
+ const global MASK_DATA_TYPE * mask_ptr = (const global MASK_DATA_TYPE *) (mask_base);
628
+ score += slope * (ACC_TYPE) mask_ptr[k_idx];
629
+ }
630
+ if (logit_softcap > 0.0f) {
631
+ score = logit_softcap * tanh(score / logit_softcap);
632
+ }
633
+
634
+ // Online softmax step.
635
+ const ACC_TYPE m_new = max(m_i, score);
636
+ const ACC_TYPE alpha = exp(m_i - m_new);
637
+ const ACC_TYPE p = exp(score - m_new);
638
+
639
+ l_i = alpha * l_i + p;
640
+ #pragma unroll
641
+ for (int i = 0; i < DV_VEC; ++i) o_acc[i] *= alpha;
642
+
643
+ #pragma unroll
644
+ for (int b = 0; b < DV_Q8_BLOCKS; ++b) {
645
+ ACC_TYPE4 v_dequant[8];
646
+ dequant_q8_0_f32(v_row + b * Q8_0_BLOCK_SIZE, v_dequant);
647
+ #pragma unroll
648
+ for (int i = 0; i < 8; ++i) {
649
+ o_acc[b * 8 + i] = mad(p, v_dequant[i], o_acc[b * 8 + i]);
650
+ }
651
+ }
652
+
653
+ m_i = m_new;
654
+ }
655
+
656
+ // Cross-thread reduce: max(m_i) -> m_c, then rescale per-thread l_i and
657
+ // o_acc by alpha = exp(m_i_thread - m_c) before sum-reduce.
658
+ __local ACC_TYPE local_m[Q1_WG_SIZE];
659
+ local_m[tid] = m_i;
660
+ barrier(CLK_LOCAL_MEM_FENCE);
661
+ #pragma unroll
662
+ for (int s = Q1_WG_SIZE / 2; s > 0; s >>= 1) {
663
+ if (tid < s) local_m[tid] = max(local_m[tid], local_m[tid + s]);
664
+ barrier(CLK_LOCAL_MEM_FENCE);
665
+ }
666
+ const ACC_TYPE m_c = local_m[0];
667
+
668
+ const ACC_TYPE alpha_final = exp(m_i - m_c);
669
+ l_i *= alpha_final;
670
+ #pragma unroll
671
+ for (int i = 0; i < DV_VEC; ++i) o_acc[i] *= alpha_final;
672
+
673
+ __local ACC_TYPE local_l[Q1_WG_SIZE];
674
+ __local ACC_TYPE4 local_o[Q1_WG_SIZE];
675
+ local_l[tid] = l_i;
676
+ barrier(CLK_LOCAL_MEM_FENCE);
677
+ #pragma unroll
678
+ for (int s = Q1_WG_SIZE / 2; s > 0; s >>= 1) {
679
+ if (tid < s) local_l[tid] += local_l[tid + s];
680
+ barrier(CLK_LOCAL_MEM_FENCE);
681
+ }
682
+ const ACC_TYPE l_c = local_l[0];
683
+
684
+ if (tid == 0) {
685
+ rec[0] = (float) m_c;
686
+ rec[1] = (float) l_c;
687
+ }
688
+ for (int i = 0; i < DV_VEC; ++i) {
689
+ local_o[tid] = o_acc[i];
690
+ barrier(CLK_LOCAL_MEM_FENCE);
691
+ #pragma unroll
692
+ for (int s = Q1_WG_SIZE / 2; s > 0; s >>= 1) {
693
+ if (tid < s) local_o[tid] += local_o[tid + s];
694
+ barrier(CLK_LOCAL_MEM_FENCE);
695
+ }
696
+ if (tid == 0) {
697
+ rec_o[i] = local_o[0];
698
+ }
699
+ }
700
+ }
701
+
702
+ // Prefill: q8_0 K/V, n_q > 1. BLOCK_M × BLOCK_N tiling.
703
+ // K path keeps packed int8 in local for dp4a QK dot; V path dequant -> half in local.
704
+ // Requires DK % QK8_0 == 0 and DV % QK8_0 == 0 (gated in supports_op).
705
+ #define KV_DATA_TYPE4 half4
706
+ #define CONVERT_KV_ACC4(x) convert_float4(x)
707
+
708
+ #define DK_Q8_BLOCKS_PREFILL (DK / QK8_0)
709
+ #define DV_Q8_BLOCKS_PREFILL (DV / QK8_0)
710
+
711
+ // N_SPLIT>1 splits DK/DV across N_SPLIT threads per query row; needs
712
+ // sub_group_shuffle_xor and DK_Q8_BLOCKS_PREFILL % N_SPLIT == 0.
713
+ #ifndef N_SPLIT
714
+ #define N_SPLIT 1
715
+ #endif
716
+
717
+ #if N_SPLIT > 1
718
+ #define SPLIT_DK_VEC (DK_VEC / N_SPLIT)
719
+ #define SPLIT_DV_VEC (DV_VEC / N_SPLIT)
720
+ #define SPLIT_DK_Q8_BLOCKS (DK_Q8_BLOCKS_PREFILL / N_SPLIT)
721
+ #define WG_SIZE (BLOCK_M * N_SPLIT)
722
+ #else
723
+ #define SPLIT_DK_VEC DK_VEC
724
+ #define SPLIT_DV_VEC DV_VEC
725
+ #define SPLIT_DK_Q8_BLOCKS DK_Q8_BLOCKS_PREFILL
726
+ #define WG_SIZE BLOCK_M
727
+ #endif
728
+
729
+ // FA_V_STRATEGY: 0 = dequant V to half in local (default); 2 = keep packed
730
+ // int8 in local, dequant in the accumulate loop (smaller local, slightly slower).
731
+ #ifndef FA_V_STRATEGY
732
+ #define FA_V_STRATEGY 0
733
+ #endif
734
+
735
+ #ifndef MQ_GQA
736
+ #define MQ_GQA 4
737
+ #endif
738
+ #ifndef MQ_NSG_SPLIT
739
+ #define MQ_NSG_SPLIT 4
740
+ #endif
741
+ #define MQ_SPLIT_WG_SIZE_Q8 (Q1_WG_SIZE * MQ_NSG_SPLIT)
742
+
743
+ REQD_SUBGROUP_SIZE_64
744
+ __kernel void flash_attn_f32_q8_0_q1_vec_mq_split(
745
+ const global void * q_void, ulong q_offset,
746
+ const global void * k_void, ulong k_offset,
747
+ const global void * v_void, ulong v_offset,
748
+ const float scale,
749
+ const int n_q,
750
+ const int n_kv,
751
+ const int n_head,
752
+ const ulong q_nb1, const ulong q_nb2, const ulong q_nb3,
753
+ const ulong k_nb1, const ulong k_nb2, const ulong k_nb3,
754
+ const ulong v_nb1, const ulong v_nb2, const ulong v_nb3,
755
+ const float max_bias,
756
+ const float m0,
757
+ const float m1,
758
+ const int n_head_log2,
759
+ const float logit_softcap,
760
+ const int n_head_kv,
761
+ const global void * mask_void,
762
+ const ulong mask_offset,
763
+ const ulong mask_nb1,
764
+ const ulong mask_nb2,
765
+ const ulong mask_nb3,
766
+ const int mask_ne2,
767
+ const int mask_ne3,
768
+ global float * partial_void,
769
+ const int n_splits,
770
+ const int kv_per_split
771
+ ) {
772
+ const int tid = get_local_id(0);
773
+ const int sgid = tid / Q1_WG_SIZE;
774
+ const int tid_sg = tid % Q1_WG_SIZE;
775
+ const int kvhead_batch_idx = get_global_id(1);
776
+ const int split_q_idx = get_global_id(2);
777
+ const int split_idx = split_q_idx % n_splits;
778
+ const int q_idx = split_q_idx / n_splits;
779
+
780
+ const int batch_idx = kvhead_batch_idx / n_head_kv;
781
+ const int head_kv_idx = kvhead_batch_idx % n_head_kv;
782
+
783
+ const int kv_start = split_idx * kv_per_split;
784
+ const int kv_end = min(kv_start + kv_per_split, n_kv);
785
+
786
+ const ulong record_stride = (ulong) FA_PARTIAL_FLOATS;
787
+
788
+ if (kv_start >= kv_end) {
789
+ // Empty split — write sentinel for each of the MQ_GQA Q-heads.
790
+ if (tid == 0) {
791
+ #pragma unroll
792
+ for (int h = 0; h < MQ_GQA; ++h) {
793
+ const int head_idx = head_kv_idx * MQ_GQA + h;
794
+ const ulong rec_idx = ((((ulong) batch_idx * n_head + head_idx) * n_q + q_idx)
795
+ * n_splits + split_idx);
796
+ global float * rec = partial_void + rec_idx * record_stride;
797
+ rec[0] = FA_M_INIT;
798
+ rec[1] = 0.0f;
799
+ }
800
+ }
801
+ return;
802
+ }
803
+
804
+ const global char * q_base = (const global char *) q_void + q_offset;
805
+ const global char * k_base = (const global char *) k_void + k_offset;
806
+ const global char * v_base = (const global char *) v_void + v_offset;
807
+
808
+ __local ACC_TYPE4 q_shared[MQ_GQA * DK_VEC];
809
+ for (int i = tid; i < MQ_GQA * DK_VEC; i += MQ_SPLIT_WG_SIZE_Q8) {
810
+ const int h = i / DK_VEC;
811
+ const int k = i % DK_VEC;
812
+ const int head_idx = head_kv_idx * MQ_GQA + h;
813
+ const ulong q_row_offset = batch_idx * q_nb3 + head_idx * q_nb2 + (ulong) q_idx * q_nb1;
814
+ const global Q_DATA_TYPE4 * q_ptr = (const global Q_DATA_TYPE4 *) (q_base + q_row_offset);
815
+ q_shared[h * DK_VEC + k] = CONVERT_Q_ACC4(q_ptr[k]);
816
+ }
817
+ barrier(CLK_LOCAL_MEM_FENCE);
818
+
819
+ float slope[MQ_GQA];
820
+ #pragma unroll
821
+ for (int h = 0; h < MQ_GQA; ++h) {
822
+ slope[h] = get_alibi_slope(max_bias, head_kv_idx * MQ_GQA + h, n_head_log2, m0, m1);
823
+ }
824
+
825
+ const global char * mask_base[MQ_GQA];
826
+ if (mask_void != NULL) {
827
+ const int mask_batch_idx = batch_idx % mask_ne3;
828
+ const global char * mask_base_b = (const global char *) mask_void + mask_offset +
829
+ mask_batch_idx * mask_nb3 +
830
+ (ulong) q_idx * mask_nb1;
831
+ #pragma unroll
832
+ for (int h = 0; h < MQ_GQA; ++h) {
833
+ const int head_idx = head_kv_idx * MQ_GQA + h;
834
+ const int mask_head_idx = head_idx % mask_ne2;
835
+ mask_base[h] = mask_base_b + mask_head_idx * mask_nb2;
836
+ }
837
+ } else {
838
+ #pragma unroll
839
+ for (int h = 0; h < MQ_GQA; ++h) mask_base[h] = NULL;
840
+ }
841
+
842
+ ACC_TYPE4 o_acc[MQ_GQA][Q1V_DV_PER_THREAD];
843
+ ACC_TYPE m_i[MQ_GQA];
844
+ ACC_TYPE l_i[MQ_GQA];
845
+ #pragma unroll
846
+ for (int h = 0; h < MQ_GQA; ++h) {
847
+ m_i[h] = FA_M_INIT;
848
+ l_i[h] = 0.0f;
849
+ #pragma unroll
850
+ for (int i = 0; i < Q1V_DV_PER_THREAD; ++i) o_acc[h][i] = (ACC_TYPE4)(0.0f);
851
+ }
852
+
853
+ const int kv_len = kv_end - kv_start;
854
+ const int kv_per_sg = (kv_len + MQ_NSG_SPLIT - 1) / MQ_NSG_SPLIT;
855
+ const int kv_lo = kv_start + sgid * kv_per_sg;
856
+ const int kv_hi = min(kv_end, kv_lo + kv_per_sg);
857
+
858
+ for (int k_idx = kv_lo; k_idx < kv_hi; ++k_idx) {
859
+ const global char * k_row = k_base + batch_idx * k_nb3 + head_kv_idx * k_nb2 + k_idx * k_nb1;
860
+ const global char * v_row = v_base + batch_idx * v_nb3 + head_kv_idx * v_nb2 + k_idx * v_nb1;
861
+
862
+ ACC_TYPE4 dot4[MQ_GQA];
863
+ #pragma unroll
864
+ for (int h = 0; h < MQ_GQA; ++h) dot4[h] = (ACC_TYPE4)(0.0f);
865
+
866
+ for (int qk = tid_sg; qk < DK_VEC; qk += Q1_WG_SIZE) {
867
+ const int block_idx = qk / 8;
868
+ const int lane = qk % 8;
869
+ const float4 k_v = dequant_q8_0_lane(k_row + block_idx * Q8_0_BLOCK_SIZE, lane);
870
+ #pragma unroll
871
+ for (int h = 0; h < MQ_GQA; ++h) {
872
+ dot4[h] = mad(q_shared[h * DK_VEC + qk], k_v, dot4[h]);
873
+ }
874
+ }
875
+
876
+ ACC_TYPE score[MQ_GQA];
877
+ #pragma unroll
878
+ for (int h = 0; h < MQ_GQA; ++h) {
879
+ const ACC_TYPE dot_partial = dot4[h].s0 + dot4[h].s1 + dot4[h].s2 + dot4[h].s3;
880
+ ACC_TYPE s = sub_group_reduce_add(dot_partial) * scale;
881
+ if (mask_base[h] != NULL) {
882
+ const global MASK_DATA_TYPE * mask_ptr = (const global MASK_DATA_TYPE *) mask_base[h];
883
+ s += slope[h] * (ACC_TYPE) mask_ptr[k_idx];
884
+ }
885
+ if (logit_softcap > 0.0f) {
886
+ s = logit_softcap * tanh(s / logit_softcap);
887
+ }
888
+ score[h] = s;
889
+ }
890
+
891
+ ACC_TYPE p_h[MQ_GQA];
892
+ ACC_TYPE sp_h[MQ_GQA];
893
+ #pragma unroll
894
+ for (int h = 0; h < MQ_GQA; ++h) {
895
+ const ACC_TYPE m_new = max(m_i[h], score[h]);
896
+ sp_h[h] = native_exp(m_i[h] - m_new);
897
+ p_h[h] = native_exp(score[h] - m_new);
898
+ l_i[h] = l_i[h] * sp_h[h] + p_h[h];
899
+ m_i[h] = m_new;
900
+ }
901
+
902
+ int idx = 0;
903
+ for (int dv = tid_sg; dv < DV_VEC; dv += Q1_WG_SIZE, ++idx) {
904
+ const int block_idx = dv / 8;
905
+ const int lane = dv % 8;
906
+ const float4 v_v = dequant_q8_0_lane(v_row + block_idx * Q8_0_BLOCK_SIZE, lane);
907
+ #pragma unroll
908
+ for (int h = 0; h < MQ_GQA; ++h) {
909
+ o_acc[h][idx] = mad(p_h[h], v_v, o_acc[h][idx] * sp_h[h]);
910
+ }
911
+ }
912
+ }
913
+
914
+ __local ACC_TYPE sg_m[MQ_GQA][MQ_NSG_SPLIT];
915
+ __local ACC_TYPE sg_l[MQ_GQA][MQ_NSG_SPLIT];
916
+ __local ACC_TYPE4 sg_o[MQ_NSG_SPLIT][DV_VEC];
917
+
918
+ if (tid_sg == 0) {
919
+ #pragma unroll
920
+ for (int h = 0; h < MQ_GQA; ++h) {
921
+ sg_m[h][sgid] = m_i[h];
922
+ sg_l[h][sgid] = l_i[h];
923
+ }
924
+ }
925
+
926
+ #pragma unroll
927
+ for (int h = 0; h < MQ_GQA; ++h) {
928
+ {
929
+ int idx = 0;
930
+ for (int dv_idx = tid_sg; dv_idx < DV_VEC; dv_idx += Q1_WG_SIZE, ++idx) {
931
+ sg_o[sgid][dv_idx] = o_acc[h][idx];
932
+ }
933
+ }
934
+ barrier(CLK_LOCAL_MEM_FENCE);
935
+
936
+ if (sgid == 0) {
937
+ const int head_idx = head_kv_idx * MQ_GQA + h;
938
+
939
+ ACC_TYPE m_c = sg_m[h][0];
940
+ #pragma unroll
941
+ for (int s = 1; s < MQ_NSG_SPLIT; ++s) {
942
+ m_c = max(m_c, sg_m[h][s]);
943
+ }
944
+ ACC_TYPE l_c = 0.0f;
945
+ #pragma unroll
946
+ for (int s = 0; s < MQ_NSG_SPLIT; ++s) {
947
+ l_c += sg_l[h][s] * native_exp(sg_m[h][s] - m_c);
948
+ }
949
+
950
+ const ulong rec_idx = ((((ulong) batch_idx * n_head + head_idx) * n_q + q_idx)
951
+ * n_splits + split_idx);
952
+ global float * rec = partial_void + rec_idx * record_stride;
953
+ global float4 * rec_o = (global float4 *) (rec + 2);
954
+
955
+ if (tid_sg == 0) {
956
+ rec[0] = (float) m_c;
957
+ rec[1] = (float) l_c;
958
+ }
959
+ for (int dv_idx = tid_sg; dv_idx < DV_VEC; dv_idx += Q1_WG_SIZE) {
960
+ ACC_TYPE4 o_merged = (ACC_TYPE4)(0.0f);
961
+ #pragma unroll
962
+ for (int s = 0; s < MQ_NSG_SPLIT; ++s) {
963
+ const ACC_TYPE alpha = native_exp(sg_m[h][s] - m_c);
964
+ o_merged = mad((ACC_TYPE4)(alpha), sg_o[s][dv_idx], o_merged);
965
+ }
966
+ rec_o[dv_idx] = o_merged;
967
+ }
968
+ }
969
+ barrier(CLK_LOCAL_MEM_FENCE);
970
+ }
971
+ }
972
+
973
+ // flash_attn_f32_q8_0_q1_vec_mq_split_c8 — cluster-parallel variant of the MQ
974
+ // split above, port of the f16/q4_0 c8 kernels
975
+
976
+ #ifdef HAS_SUBGROUP_SHUFFLE
977
+
978
+ #ifndef FA_CL_C
979
+ #define FA_CL_C 8
980
+ #endif
981
+
982
+ // Lane striping requires DK/DV to divide across the cluster (see f16 c8).
983
+ #if (DK_VEC % FA_CL_C) == 0 && (DV_VEC % FA_CL_C) == 0
984
+ #define FA_CL_NCL (Q1_WG_SIZE / FA_CL_C) // clusters (position streams) per subgroup
985
+ #define FA_CL_DKQ (DK_VEC / FA_CL_C) // K quartets per lane per row
986
+ #define FA_CL_DVQ (DV_VEC / FA_CL_C) // V quartets (o_acc float4s) per lane per head
987
+
988
+ #ifdef FA_C8_NO_SG_PIN
989
+ #define FA_C8_SG_ATTR_Q8
990
+ #else
991
+ #define FA_C8_SG_ATTR_Q8 REQD_SUBGROUP_SIZE_64
992
+ #endif
993
+
994
+ FA_C8_SG_ATTR_Q8
995
+ __kernel void flash_attn_f32_q8_0_q1_vec_mq_split_c8(
996
+ const global void * q_void, ulong q_offset,
997
+ const global void * k_void, ulong k_offset,
998
+ const global void * v_void, ulong v_offset,
999
+ const float scale,
1000
+ const int n_q,
1001
+ const int n_kv,
1002
+ const int n_head,
1003
+ const ulong q_nb1, const ulong q_nb2, const ulong q_nb3,
1004
+ const ulong k_nb1, const ulong k_nb2, const ulong k_nb3,
1005
+ const ulong v_nb1, const ulong v_nb2, const ulong v_nb3,
1006
+ const float max_bias,
1007
+ const float m0,
1008
+ const float m1,
1009
+ const int n_head_log2,
1010
+ const float logit_softcap,
1011
+ const int n_head_kv,
1012
+ const global void * mask_void,
1013
+ const ulong mask_offset,
1014
+ const ulong mask_nb1,
1015
+ const ulong mask_nb2,
1016
+ const ulong mask_nb3,
1017
+ const int mask_ne2,
1018
+ const int mask_ne3,
1019
+ global float * partial_void,
1020
+ const int n_splits,
1021
+ const int kv_per_split
1022
+ ) {
1023
+ const int tid = get_local_id(0);
1024
+ const int sgid = tid / Q1_WG_SIZE;
1025
+ const int tid_sg = tid % Q1_WG_SIZE;
1026
+ const int cl = tid_sg / FA_CL_C; // cluster id
1027
+ const int lic = tid_sg % FA_CL_C; // lane in cluster
1028
+ const int kvhead_batch_idx = get_global_id(1);
1029
+ const int split_q_idx = get_global_id(2);
1030
+ const int split_idx = split_q_idx % n_splits;
1031
+ const int q_idx = split_q_idx / n_splits;
1032
+
1033
+ const int batch_idx = kvhead_batch_idx / n_head_kv;
1034
+ const int head_kv_idx = kvhead_batch_idx % n_head_kv;
1035
+
1036
+ const int kv_start = split_idx * kv_per_split;
1037
+ const int kv_end = min(kv_start + kv_per_split, n_kv);
1038
+
1039
+ const ulong record_stride = (ulong) FA_PARTIAL_FLOATS;
1040
+
1041
+ if (kv_start >= kv_end) {
1042
+ if (tid == 0) {
1043
+ #pragma unroll
1044
+ for (int h = 0; h < MQ_GQA; ++h) {
1045
+ const int head_idx = head_kv_idx * MQ_GQA + h;
1046
+ const ulong rec_idx = ((((ulong) batch_idx * n_head + head_idx) * n_q + q_idx)
1047
+ * n_splits + split_idx);
1048
+ global float * rec = partial_void + rec_idx * record_stride;
1049
+ rec[0] = FA_M_INIT;
1050
+ rec[1] = 0.0f;
1051
+ }
1052
+ }
1053
+ return;
1054
+ }
1055
+
1056
+ const global char * q_base = (const global char *) q_void + q_offset;
1057
+ const global char * k_base = (const global char *) k_void + k_offset;
1058
+ const global char * v_base = (const global char *) v_void + v_offset;
1059
+
1060
+ // Stage MQ_GQA Q rows in __local once (uniform across WG).
1061
+ __local ACC_TYPE4 q_shared[MQ_GQA * DK_VEC];
1062
+ for (int i = tid; i < MQ_GQA * DK_VEC; i += MQ_SPLIT_WG_SIZE_Q8) {
1063
+ const int h = i / DK_VEC;
1064
+ const int k = i % DK_VEC;
1065
+ const int head_idx = head_kv_idx * MQ_GQA + h;
1066
+ const ulong q_row_offset = batch_idx * q_nb3 + head_idx * q_nb2 + (ulong) q_idx * q_nb1;
1067
+ const global Q_DATA_TYPE4 * q_ptr = (const global Q_DATA_TYPE4 *) (q_base + q_row_offset);
1068
+ q_shared[h * DK_VEC + k] = CONVERT_Q_ACC4(q_ptr[k]);
1069
+ }
1070
+ barrier(CLK_LOCAL_MEM_FENCE);
1071
+
1072
+ float slope[MQ_GQA];
1073
+ #pragma unroll
1074
+ for (int h = 0; h < MQ_GQA; ++h) {
1075
+ slope[h] = get_alibi_slope(max_bias, head_kv_idx * MQ_GQA + h, n_head_log2, m0, m1);
1076
+ }
1077
+
1078
+ const global char * mask_base[MQ_GQA];
1079
+ if (mask_void != NULL) {
1080
+ const int mask_batch_idx = batch_idx % mask_ne3;
1081
+ const global char * mask_base_b = (const global char *) mask_void + mask_offset +
1082
+ mask_batch_idx * mask_nb3 +
1083
+ (ulong) q_idx * mask_nb1;
1084
+ #pragma unroll
1085
+ for (int h = 0; h < MQ_GQA; ++h) {
1086
+ const int head_idx = head_kv_idx * MQ_GQA + h;
1087
+ const int mask_head_idx = head_idx % mask_ne2;
1088
+ mask_base[h] = mask_base_b + mask_head_idx * mask_nb2;
1089
+ }
1090
+ } else {
1091
+ #pragma unroll
1092
+ for (int h = 0; h < MQ_GQA; ++h) mask_base[h] = NULL;
1093
+ }
1094
+
1095
+ // Per-CLUSTER online state; o_acc holds this lane's V quartets {lic + FA_CL_C*i}.
1096
+ ACC_TYPE4 o_acc[MQ_GQA][FA_CL_DVQ];
1097
+ ACC_TYPE m_i[MQ_GQA];
1098
+ ACC_TYPE l_i[MQ_GQA];
1099
+ #pragma unroll
1100
+ for (int h = 0; h < MQ_GQA; ++h) {
1101
+ m_i[h] = FA_M_INIT;
1102
+ l_i[h] = 0.0f;
1103
+ #pragma unroll
1104
+ for (int i = 0; i < FA_CL_DVQ; ++i) o_acc[h][i] = (ACC_TYPE4)(0.0f);
1105
+ }
1106
+
1107
+ const int kv_len = kv_end - kv_start;
1108
+ const int kv_per_sg = (kv_len + MQ_NSG_SPLIT - 1) / MQ_NSG_SPLIT;
1109
+ const int kv_lo = kv_start + sgid * kv_per_sg;
1110
+ const int kv_hi = min(kv_end, kv_lo + kv_per_sg);
1111
+
1112
+ // Uniform trip count; tail clamps the row address and drops the score to
1113
+ // FA_M_INIT (p underflows to 0) so shuffles stay convergent.
1114
+ const int n_iter = (kv_hi - kv_lo + FA_CL_NCL - 1) / FA_CL_NCL;
1115
+ const ulong k_row_base = batch_idx * k_nb3 + head_kv_idx * k_nb2;
1116
+ const ulong v_row_base = batch_idx * v_nb3 + head_kv_idx * v_nb2;
1117
+
1118
+ for (int it = 0; it < n_iter; ++it) {
1119
+ const int k_idx = kv_lo + cl + it * FA_CL_NCL;
1120
+ const int valid = k_idx < kv_hi;
1121
+ const int k_safe = valid ? k_idx : (kv_hi - 1);
1122
+
1123
+ const global char * k_row = k_base + k_row_base + (ulong) k_safe * k_nb1;
1124
+ const global char * v_row = v_base + v_row_base + (ulong) k_safe * v_nb1;
1125
+
1126
+ // Float-dequant K dot over this lane's quartets of the cluster's row.
1127
+ ACC_TYPE4 dot4[MQ_GQA];
1128
+ #pragma unroll
1129
+ for (int h = 0; h < MQ_GQA; ++h) dot4[h] = (ACC_TYPE4)(0.0f);
1130
+ #pragma unroll
1131
+ for (int i = 0; i < FA_CL_DKQ; ++i) {
1132
+ const int qk = lic + FA_CL_C * i;
1133
+ const float4 k_v = dequant_q8_0_lane(k_row + (qk / 8) * Q8_0_BLOCK_SIZE, qk % 8);
1134
+ #pragma unroll
1135
+ for (int h = 0; h < MQ_GQA; ++h) {
1136
+ dot4[h] = mad(q_shared[h * DK_VEC + qk], k_v, dot4[h]);
1137
+ }
1138
+ }
1139
+
1140
+ // Cluster-reduce (xor steps < FA_CL_C stay inside the cluster) + score.
1141
+ ACC_TYPE score[MQ_GQA];
1142
+ #pragma unroll
1143
+ for (int h = 0; h < MQ_GQA; ++h) {
1144
+ ACC_TYPE s = dot4[h].s0 + dot4[h].s1 + dot4[h].s2 + dot4[h].s3;
1145
+ #pragma unroll
1146
+ for (int step = 1; step < FA_CL_C; step <<= 1) {
1147
+ s += sub_group_shuffle_xor(s, step);
1148
+ }
1149
+ s *= scale;
1150
+ if (mask_base[h] != NULL) {
1151
+ const global MASK_DATA_TYPE * mask_ptr = (const global MASK_DATA_TYPE *) mask_base[h];
1152
+ s += slope[h] * (ACC_TYPE) mask_ptr[k_safe];
1153
+ }
1154
+ if (logit_softcap > 0.0f) {
1155
+ s = logit_softcap * tanh(s / logit_softcap);
1156
+ }
1157
+ score[h] = valid ? s : FA_M_INIT;
1158
+ }
1159
+
1160
+ // Per-cluster online update (serial chain depth n_iter, not kv_per_sg).
1161
+ ACC_TYPE p_h[MQ_GQA];
1162
+ ACC_TYPE sp_h[MQ_GQA];
1163
+ #pragma unroll
1164
+ for (int h = 0; h < MQ_GQA; ++h) {
1165
+ const ACC_TYPE m_new = max(m_i[h], score[h]);
1166
+ sp_h[h] = native_exp(m_i[h] - m_new);
1167
+ p_h[h] = native_exp(score[h] - m_new);
1168
+ l_i[h] = l_i[h] * sp_h[h] + p_h[h];
1169
+ m_i[h] = m_new;
1170
+ }
1171
+
1172
+ // V accumulate on this lane's quartets (p = 0 on tail -> inert).
1173
+ #pragma unroll
1174
+ for (int i = 0; i < FA_CL_DVQ; ++i) {
1175
+ const int dv = lic + FA_CL_C * i;
1176
+ const float4 v_v = dequant_q8_0_lane(v_row + (dv / 8) * Q8_0_BLOCK_SIZE, dv % 8);
1177
+ #pragma unroll
1178
+ for (int h = 0; h < MQ_GQA; ++h) {
1179
+ o_acc[h][i] = mad(p_h[h], v_v, o_acc[h][i] * sp_h[h]);
1180
+ }
1181
+ }
1182
+ }
1183
+
1184
+ // Merge stage 1: fold cluster partials inside the subgroup via shuffles.
1185
+ #pragma unroll
1186
+ for (int h = 0; h < MQ_GQA; ++h) {
1187
+ ACC_TYPE m_c = m_i[h];
1188
+ #pragma unroll
1189
+ for (int step = FA_CL_C; step < Q1_WG_SIZE; step <<= 1) {
1190
+ m_c = max(m_c, sub_group_shuffle_xor(m_c, step));
1191
+ }
1192
+ const ACC_TYPE alpha = native_exp(m_i[h] - m_c);
1193
+ ACC_TYPE l_c = l_i[h] * alpha;
1194
+ #pragma unroll
1195
+ for (int step = FA_CL_C; step < Q1_WG_SIZE; step <<= 1) {
1196
+ l_c += sub_group_shuffle_xor(l_c, step);
1197
+ }
1198
+ #pragma unroll
1199
+ for (int i = 0; i < FA_CL_DVQ; ++i) {
1200
+ ACC_TYPE4 o = o_acc[h][i] * alpha;
1201
+ #pragma unroll
1202
+ for (int step = FA_CL_C; step < Q1_WG_SIZE; step <<= 1) {
1203
+ o.s0 += sub_group_shuffle_xor(o.s0, step);
1204
+ o.s1 += sub_group_shuffle_xor(o.s1, step);
1205
+ o.s2 += sub_group_shuffle_xor(o.s2, step);
1206
+ o.s3 += sub_group_shuffle_xor(o.s3, step);
1207
+ }
1208
+ o_acc[h][i] = o;
1209
+ }
1210
+ m_i[h] = m_c;
1211
+ l_i[h] = l_c;
1212
+ }
1213
+
1214
+ // Merge stage 2: baseline cross-subgroup LDS merge (o published by
1215
+ // cluster 0's lanes; layout identical to the baseline sg_o).
1216
+ __local ACC_TYPE sg_m[MQ_GQA][MQ_NSG_SPLIT];
1217
+ __local ACC_TYPE sg_l[MQ_GQA][MQ_NSG_SPLIT];
1218
+ __local ACC_TYPE4 sg_o[MQ_NSG_SPLIT][DV_VEC];
1219
+
1220
+ if (tid_sg == 0) {
1221
+ #pragma unroll
1222
+ for (int h = 0; h < MQ_GQA; ++h) {
1223
+ sg_m[h][sgid] = m_i[h];
1224
+ sg_l[h][sgid] = l_i[h];
1225
+ }
1226
+ }
1227
+
1228
+ #pragma unroll
1229
+ for (int h = 0; h < MQ_GQA; ++h) {
1230
+ if (cl == 0) {
1231
+ #pragma unroll
1232
+ for (int i = 0; i < FA_CL_DVQ; ++i) {
1233
+ sg_o[sgid][lic + FA_CL_C * i] = o_acc[h][i];
1234
+ }
1235
+ }
1236
+ barrier(CLK_LOCAL_MEM_FENCE);
1237
+
1238
+ if (sgid == 0) {
1239
+ const int head_idx = head_kv_idx * MQ_GQA + h;
1240
+
1241
+ ACC_TYPE m_c = sg_m[h][0];
1242
+ #pragma unroll
1243
+ for (int s = 1; s < MQ_NSG_SPLIT; ++s) {
1244
+ m_c = max(m_c, sg_m[h][s]);
1245
+ }
1246
+ ACC_TYPE l_c = 0.0f;
1247
+ #pragma unroll
1248
+ for (int s = 0; s < MQ_NSG_SPLIT; ++s) {
1249
+ l_c += sg_l[h][s] * native_exp(sg_m[h][s] - m_c);
1250
+ }
1251
+
1252
+ const ulong rec_idx = ((((ulong) batch_idx * n_head + head_idx) * n_q + q_idx)
1253
+ * n_splits + split_idx);
1254
+ global float * rec = partial_void + rec_idx * record_stride;
1255
+ global float4 * rec_o = (global float4 *) (rec + 2);
1256
+
1257
+ if (tid_sg == 0) {
1258
+ rec[0] = (float) m_c;
1259
+ rec[1] = (float) l_c;
1260
+ }
1261
+ for (int dv_idx = tid_sg; dv_idx < DV_VEC; dv_idx += Q1_WG_SIZE) {
1262
+ ACC_TYPE4 o_merged = (ACC_TYPE4)(0.0f);
1263
+ #pragma unroll
1264
+ for (int s = 0; s < MQ_NSG_SPLIT; ++s) {
1265
+ const ACC_TYPE alpha = native_exp(sg_m[h][s] - m_c);
1266
+ o_merged = mad((ACC_TYPE4)(alpha), sg_o[s][dv_idx], o_merged);
1267
+ }
1268
+ rec_o[dv_idx] = o_merged;
1269
+ }
1270
+ }
1271
+ barrier(CLK_LOCAL_MEM_FENCE);
1272
+ }
1273
+ }
1274
+
1275
+ #endif // DK_VEC/DV_VEC divisible by FA_CL_C
1276
+ #endif // HAS_SUBGROUP_SHUFFLE (q1_vec_mq_split_c8)
1277
+
1278
+ __kernel void flash_attn_f32_q8_0(
1279
+ const global void * q_void, ulong q_offset,
1280
+ const global void * k_void, ulong k_offset,
1281
+ const global void * v_void, ulong v_offset,
1282
+ global void * o_void, ulong o_offset,
1283
+ const float scale,
1284
+ const int n_q,
1285
+ const int n_kv,
1286
+ const int is_causal,
1287
+ const int n_head,
1288
+ const ulong q_nb1, const ulong q_nb2, const ulong q_nb3,
1289
+ const ulong k_nb1, const ulong k_nb2, const ulong k_nb3,
1290
+ const ulong v_nb1, const ulong v_nb2, const ulong v_nb3,
1291
+ const ulong o_nb1, const ulong o_nb2, const ulong o_nb3,
1292
+ const float max_bias,
1293
+ const float m0,
1294
+ const float m1,
1295
+ const int n_head_log2,
1296
+ const float logit_softcap,
1297
+ const int n_head_kv,
1298
+ const global void* mask_void,
1299
+ const ulong mask_offset,
1300
+ const ulong mask_nb1,
1301
+ const ulong mask_nb2,
1302
+ const ulong mask_nb3,
1303
+ const int mask_ne2,
1304
+ const int mask_ne3,
1305
+ const global void* sinks_void,
1306
+ const ulong sinks_offset,
1307
+ // blk: per-(qblock,kvblock) class from flash_attn_blk_f16
1308
+ // (0=masked, 1=mixed, 2=unmasked). NULL disables the prepass opt.
1309
+ const global void * blk_void
1310
+ ) {
1311
+ const int tid = get_local_id(0);
1312
+ const int block_q_idx = get_group_id(0);
1313
+ const int head_batch_idx = get_global_id(1);
1314
+
1315
+ #if N_SPLIT > 1
1316
+ const int q_lane = tid / N_SPLIT;
1317
+ const int split_idx = tid % N_SPLIT;
1318
+ #else
1319
+ const int q_lane = tid;
1320
+ const int split_idx = 0;
1321
+ #endif
1322
+ const int my_query_row = block_q_idx * BLOCK_M + q_lane;
1323
+ const int query_valid = my_query_row < n_q;
1324
+
1325
+ const int batch_idx = head_batch_idx / n_head;
1326
+ const int head_idx = head_batch_idx % n_head;
1327
+
1328
+ const int gqa_ratio = n_head / n_head_kv;
1329
+ const int head_kv_idx = head_idx / gqa_ratio;
1330
+ const int mask_head_idx = mask_void != NULL ? head_idx % mask_ne2 : 0;
1331
+ const int mask_batch_idx = mask_void != NULL ? batch_idx % mask_ne3 : 0;
1332
+
1333
+ const global char * q_base = (const global char *) q_void + q_offset;
1334
+ const global char * k_base = (const global char *) k_void + k_offset;
1335
+ const global char * v_base = (const global char *) v_void + v_offset;
1336
+ global char * o_base = (global char *) o_void + o_offset;
1337
+
1338
+ const global char * mask_base = NULL;
1339
+ if (mask_void != NULL) {
1340
+ mask_base = (const global char *) mask_void + mask_offset +
1341
+ mask_batch_idx * mask_nb3 + mask_head_idx * mask_nb2;
1342
+ }
1343
+
1344
+ // BLK_PREPASS_BM may differ from this kernel's BLOCK_M; scale q-block idx.
1345
+ #ifndef BLK_PREPASS_BM
1346
+ #define BLK_PREPASS_BM BLOCK_M
1347
+ #endif
1348
+ const global char * blk_base = NULL;
1349
+ int n_kv_blocks = 0;
1350
+ if (blk_void != NULL) {
1351
+ n_kv_blocks = (n_kv + BLOCK_N - 1) / BLOCK_N;
1352
+ const int n_q_blocks_prepass = (n_q + BLK_PREPASS_BM - 1) / BLK_PREPASS_BM;
1353
+ const int prepass_q_block = (block_q_idx * BLOCK_M) / BLK_PREPASS_BM;
1354
+ blk_base = (const global char *) blk_void +
1355
+ (((mask_batch_idx * mask_ne2) + mask_head_idx) * n_q_blocks_prepass + prepass_q_block) * n_kv_blocks;
1356
+ }
1357
+
1358
+ const int dk_off_vec = split_idx * SPLIT_DK_VEC;
1359
+ ACC_TYPE4 q_priv[SPLIT_DK_VEC];
1360
+ if (query_valid) {
1361
+ const ulong q_row_offset = batch_idx * q_nb3 + head_idx * q_nb2 + my_query_row * q_nb1;
1362
+ const global float4 * q_ptr = (const global float4 *) (q_base + q_row_offset);
1363
+ #pragma unroll
1364
+ for (int i = 0; i < SPLIT_DK_VEC; ++i) {
1365
+ q_priv[i] = q_ptr[dk_off_vec + i];
1366
+ }
1367
+ } else {
1368
+ #pragma unroll
1369
+ for (int i = 0; i < SPLIT_DK_VEC; ++i) q_priv[i] = (ACC_TYPE4)(0.0f);
1370
+ }
1371
+
1372
+ #ifdef FA_HAVE_INT_DOT
1373
+ uint q_packed_pf[SPLIT_DK_Q8_BLOCKS * 8];
1374
+ float q_d_pf[SPLIT_DK_Q8_BLOCKS];
1375
+ #pragma unroll
1376
+ for (int b = 0; b < SPLIT_DK_Q8_BLOCKS; ++b) {
1377
+ q_d_pf[b] = quant_q_block_int8_packed(&q_priv[b * 8], &q_packed_pf[b * 8]);
1378
+ }
1379
+ #endif
1380
+
1381
+ const int dv_off_vec = split_idx * SPLIT_DV_VEC;
1382
+ ACC_TYPE4 o_acc[SPLIT_DV_VEC];
1383
+ #pragma unroll
1384
+ for (int i = 0; i < SPLIT_DV_VEC; ++i) o_acc[i] = (ACC_TYPE4)(0.0f);
1385
+
1386
+ ACC_TYPE m_i = FA_M_INIT;
1387
+ ACC_TYPE l_i = 0.0f;
1388
+
1389
+ float slope = get_alibi_slope(max_bias, head_idx, n_head_log2, m0, m1);
1390
+
1391
+ #ifdef FA_HAVE_INT_DOT
1392
+ __local uint l_k_packed[BLOCK_N][DK_Q8_BLOCKS_PREFILL * 8];
1393
+ __local float l_k_scale [BLOCK_N][DK_Q8_BLOCKS_PREFILL];
1394
+ #else
1395
+ __local half4 l_k[BLOCK_N][DK_VEC];
1396
+ #endif
1397
+
1398
+ #if FA_V_STRATEGY == 2
1399
+ __local uint l_v_packed[BLOCK_N][DV_Q8_BLOCKS_PREFILL * 8];
1400
+ __local float l_v_scale [BLOCK_N][DV_Q8_BLOCKS_PREFILL];
1401
+ #else
1402
+ __local half4 l_v[BLOCK_N][DV_VEC];
1403
+ #endif
1404
+
1405
+ for (int k_start = 0; k_start < n_kv; k_start += BLOCK_N) {
1406
+ // Skip fully-masked KV tiles (uniform branch across WG).
1407
+ char blk_cur = 1;
1408
+ if (blk_base != NULL) {
1409
+ blk_cur = blk_base[k_start / BLOCK_N];
1410
+ if (blk_cur == 0) continue;
1411
+ }
1412
+
1413
+ {
1414
+ #ifdef FA_HAVE_INT_DOT
1415
+ const int k_blocks_per_row = DK_Q8_BLOCKS_PREFILL;
1416
+ const int n_blocks_total = BLOCK_N * k_blocks_per_row;
1417
+ for (int i = tid; i < n_blocks_total; i += WG_SIZE) {
1418
+ const int row = i / k_blocks_per_row;
1419
+ const int blk = i % k_blocks_per_row;
1420
+ const int k_row_idx = k_start + row;
1421
+ if (k_row_idx < n_kv) {
1422
+ const ulong k_row_off = batch_idx * k_nb3 + head_kv_idx * k_nb2 + k_row_idx * k_nb1;
1423
+ const global char * blk_ptr = k_base + k_row_off + blk * Q8_0_BLOCK_SIZE;
1424
+ const float df = (float) vload_half(0, (const global half *) blk_ptr);
1425
+ const global uchar * qs = (const global uchar *)(blk_ptr + 2);
1426
+ l_k_scale[row][blk] = df;
1427
+ #pragma unroll
1428
+ for (int j = 0; j < 8; ++j) {
1429
+ uint k_packed =
1430
+ (uint) qs[j*4 + 0] |
1431
+ ((uint) qs[j*4 + 1]) << 8 |
1432
+ ((uint) qs[j*4 + 2]) << 16 |
1433
+ ((uint) qs[j*4 + 3]) << 24;
1434
+ l_k_packed[row][blk * 8 + j] = k_packed;
1435
+ }
1436
+ } else {
1437
+ l_k_scale[row][blk] = 0.0f;
1438
+ #pragma unroll
1439
+ for (int j = 0; j < 8; ++j) l_k_packed[row][blk * 8 + j] = 0u;
1440
+ }
1441
+ }
1442
+ #else
1443
+ // Fallback: dequant q8_0 -> half in local memory.
1444
+ const int k_blocks_per_row = DK / QK8_0;
1445
+ const int n_blocks_total = BLOCK_N * k_blocks_per_row;
1446
+ for (int i = tid; i < n_blocks_total; i += WG_SIZE) {
1447
+ const int row = i / k_blocks_per_row;
1448
+ const int blk = i % k_blocks_per_row;
1449
+ const int k_row_idx = k_start + row;
1450
+ if (k_row_idx < n_kv) {
1451
+ const ulong k_row_off = batch_idx * k_nb3 + head_kv_idx * k_nb2 + k_row_idx * k_nb1;
1452
+ const global char * blk_ptr = k_base + k_row_off + blk * Q8_0_BLOCK_SIZE;
1453
+ const float df = (float) vload_half(0, (const global half *) blk_ptr);
1454
+ const global char * qs = blk_ptr + 2;
1455
+ #pragma unroll
1456
+ for (int j = 0; j < 8; ++j) {
1457
+ const float4 v = df * (float4)((float) qs[j*4 + 0],
1458
+ (float) qs[j*4 + 1],
1459
+ (float) qs[j*4 + 2],
1460
+ (float) qs[j*4 + 3]);
1461
+ l_k[row][blk * 8 + j] = (half4)((half) v.s0, (half) v.s1, (half) v.s2, (half) v.s3);
1462
+ }
1463
+ } else {
1464
+ #pragma unroll
1465
+ for (int j = 0; j < 8; ++j) l_k[row][blk * 8 + j] = (half4)(0.0h);
1466
+ }
1467
+ }
1468
+ #endif
1469
+ }
1470
+ // V tile load — strategy-dependent.
1471
+ #if FA_V_STRATEGY == 2
1472
+ {
1473
+ // Int8 packed V in local memory + per-block scale. Accumulate
1474
+ // step unpacks inline.
1475
+ const int v_blocks_per_row = DV_Q8_BLOCKS_PREFILL;
1476
+ const int n_blocks_total = BLOCK_N * v_blocks_per_row;
1477
+ for (int i = tid; i < n_blocks_total; i += WG_SIZE) {
1478
+ const int row = i / v_blocks_per_row;
1479
+ const int blk = i % v_blocks_per_row;
1480
+ const int v_row_idx = k_start + row;
1481
+ if (v_row_idx < n_kv) {
1482
+ const ulong v_row_off = batch_idx * v_nb3 + head_kv_idx * v_nb2 + v_row_idx * v_nb1;
1483
+ const global char * blk_ptr = v_base + v_row_off + blk * Q8_0_BLOCK_SIZE;
1484
+ const float df = (float) vload_half(0, (const global half *) blk_ptr);
1485
+ const global uchar * qs = (const global uchar *)(blk_ptr + 2);
1486
+ l_v_scale[row][blk] = df;
1487
+ #pragma unroll
1488
+ for (int j = 0; j < 8; ++j) {
1489
+ uint v_packed =
1490
+ (uint) qs[j*4 + 0] |
1491
+ ((uint) qs[j*4 + 1]) << 8 |
1492
+ ((uint) qs[j*4 + 2]) << 16 |
1493
+ ((uint) qs[j*4 + 3]) << 24;
1494
+ l_v_packed[row][blk * 8 + j] = v_packed;
1495
+ }
1496
+ } else {
1497
+ l_v_scale[row][blk] = 0.0f;
1498
+ #pragma unroll
1499
+ for (int j = 0; j < 8; ++j) l_v_packed[row][blk * 8 + j] = 0u;
1500
+ }
1501
+ }
1502
+ }
1503
+ #else
1504
+ {
1505
+ // Default: dequant V -> half in local memory.
1506
+ const int v_blocks_per_row = DV / QK8_0;
1507
+ const int n_blocks_total = BLOCK_N * v_blocks_per_row;
1508
+ for (int i = tid; i < n_blocks_total; i += WG_SIZE) {
1509
+ const int row = i / v_blocks_per_row;
1510
+ const int blk = i % v_blocks_per_row;
1511
+ const int v_row_idx = k_start + row;
1512
+ if (v_row_idx < n_kv) {
1513
+ const ulong v_row_off = batch_idx * v_nb3 + head_kv_idx * v_nb2 + v_row_idx * v_nb1;
1514
+ const global char * blk_ptr = v_base + v_row_off + blk * Q8_0_BLOCK_SIZE;
1515
+ const float df = (float) vload_half(0, (const global half *) blk_ptr);
1516
+ const global char * qs = blk_ptr + 2;
1517
+ #pragma unroll
1518
+ for (int j = 0; j < 8; ++j) {
1519
+ const float4 v = df * (float4)((float) qs[j*4 + 0],
1520
+ (float) qs[j*4 + 1],
1521
+ (float) qs[j*4 + 2],
1522
+ (float) qs[j*4 + 3]);
1523
+ l_v[row][blk * 8 + j] = (half4)((half) v.s0, (half) v.s1, (half) v.s2, (half) v.s3);
1524
+ }
1525
+ } else {
1526
+ #pragma unroll
1527
+ for (int j = 0; j < 8; ++j) l_v[row][blk * 8 + j] = (half4)(0.0h);
1528
+ }
1529
+ }
1530
+ }
1531
+ #endif
1532
+ barrier(CLK_LOCAL_MEM_FENCE);
1533
+
1534
+ // QK dot + online softmax. N_SPLIT>1 reduces per-thread partials via shuffle_xor.
1535
+ #if N_SPLIT > 1
1536
+ {
1537
+ #else
1538
+ if (query_valid) {
1539
+ #endif
1540
+ const int k_blk_base = split_idx * SPLIT_DK_Q8_BLOCKS;
1541
+ for (int j = 0; j < BLOCK_N; j += 4) {
1542
+ const int k_row0 = k_start + j;
1543
+ const int k_row1 = k_start + j + 1;
1544
+ const int k_row2 = k_start + j + 2;
1545
+ const int k_row3 = k_start + j + 3;
1546
+
1547
+ ACC_TYPE s0, s1, s2, s3;
1548
+ #ifdef FA_HAVE_INT_DOT
1549
+ // dp4a-accelerated QK dot over owned blocks.
1550
+ s0 = 0.0f; s1 = 0.0f; s2 = 0.0f; s3 = 0.0f;
1551
+ #pragma unroll
1552
+ for (int b_local = 0; b_local < SPLIT_DK_Q8_BLOCKS; ++b_local) {
1553
+ const int b = k_blk_base + b_local;
1554
+ int sum0 = 0, sum1 = 0, sum2 = 0, sum3 = 0;
1555
+ #pragma unroll
1556
+ for (int g = 0; g < 8; ++g) {
1557
+ const uint qp = q_packed_pf[b_local * 8 + g];
1558
+ sum0 = dot_acc_sat_4x8packed_ss_int(qp, l_k_packed[j ][b * 8 + g], sum0);
1559
+ sum1 = dot_acc_sat_4x8packed_ss_int(qp, l_k_packed[j+1][b * 8 + g], sum1);
1560
+ sum2 = dot_acc_sat_4x8packed_ss_int(qp, l_k_packed[j+2][b * 8 + g], sum2);
1561
+ sum3 = dot_acc_sat_4x8packed_ss_int(qp, l_k_packed[j+3][b * 8 + g], sum3);
1562
+ }
1563
+ const float qd = q_d_pf[b_local];
1564
+ s0 += (float)sum0 * qd * l_k_scale[j ][b];
1565
+ s1 += (float)sum1 * qd * l_k_scale[j+1][b];
1566
+ s2 += (float)sum2 * qd * l_k_scale[j+2][b];
1567
+ s3 += (float)sum3 * qd * l_k_scale[j+3][b];
1568
+ }
1569
+ #else
1570
+ ACC_TYPE4 dot_acc0 = (ACC_TYPE4)(0.0f);
1571
+ ACC_TYPE4 dot_acc1 = (ACC_TYPE4)(0.0f);
1572
+ ACC_TYPE4 dot_acc2 = (ACC_TYPE4)(0.0f);
1573
+ ACC_TYPE4 dot_acc3 = (ACC_TYPE4)(0.0f);
1574
+ #pragma unroll
1575
+ for (int k = 0; k < SPLIT_DK_VEC; ++k) {
1576
+ const ACC_TYPE4 qk = q_priv[k];
1577
+ const int k_abs = dk_off_vec + k;
1578
+ dot_acc0 = mad(qk, CONVERT_KV_ACC4(l_k[j ][k_abs]), dot_acc0);
1579
+ dot_acc1 = mad(qk, CONVERT_KV_ACC4(l_k[j+1][k_abs]), dot_acc1);
1580
+ dot_acc2 = mad(qk, CONVERT_KV_ACC4(l_k[j+2][k_abs]), dot_acc2);
1581
+ dot_acc3 = mad(qk, CONVERT_KV_ACC4(l_k[j+3][k_abs]), dot_acc3);
1582
+ }
1583
+ s0 = dot_acc0.s0 + dot_acc0.s1 + dot_acc0.s2 + dot_acc0.s3;
1584
+ s1 = dot_acc1.s0 + dot_acc1.s1 + dot_acc1.s2 + dot_acc1.s3;
1585
+ s2 = dot_acc2.s0 + dot_acc2.s1 + dot_acc2.s2 + dot_acc2.s3;
1586
+ s3 = dot_acc3.s0 + dot_acc3.s1 + dot_acc3.s2 + dot_acc3.s3;
1587
+ #endif
1588
+
1589
+ #if N_SPLIT > 1
1590
+ // Power-of-2 N_SPLIT: shuffle_xor butterfly. N_SPLIT=3 (DK=96): 3-way shuffle.
1591
+ #if (N_SPLIT & (N_SPLIT - 1)) == 0
1592
+ #pragma unroll
1593
+ for (int step = 1; step < N_SPLIT; step <<= 1) {
1594
+ s0 += sub_group_shuffle_xor(s0, step);
1595
+ s1 += sub_group_shuffle_xor(s1, step);
1596
+ s2 += sub_group_shuffle_xor(s2, step);
1597
+ s3 += sub_group_shuffle_xor(s3, step);
1598
+ }
1599
+ #else
1600
+ const uint tri_base = (get_sub_group_local_id() / N_SPLIT) * N_SPLIT;
1601
+ s0 = sub_group_shuffle(s0, tri_base + 0) + sub_group_shuffle(s0, tri_base + 1) + sub_group_shuffle(s0, tri_base + 2);
1602
+ s1 = sub_group_shuffle(s1, tri_base + 0) + sub_group_shuffle(s1, tri_base + 1) + sub_group_shuffle(s1, tri_base + 2);
1603
+ s2 = sub_group_shuffle(s2, tri_base + 0) + sub_group_shuffle(s2, tri_base + 1) + sub_group_shuffle(s2, tri_base + 2);
1604
+ s3 = sub_group_shuffle(s3, tri_base + 0) + sub_group_shuffle(s3, tri_base + 1) + sub_group_shuffle(s3, tri_base + 2);
1605
+ #endif
1606
+ if (!query_valid) { s0 = FA_M_INIT; s1 = FA_M_INIT; s2 = FA_M_INIT; s3 = FA_M_INIT; }
1607
+ #endif
1608
+ s0 *= scale; s1 *= scale; s2 *= scale; s3 *= scale;
1609
+
1610
+ if (is_causal) {
1611
+ const int causal_limit = n_kv - n_q + my_query_row;
1612
+ if (k_row0 > causal_limit) s0 = FA_M_INIT;
1613
+ if (k_row1 > causal_limit) s1 = FA_M_INIT;
1614
+ if (k_row2 > causal_limit) s2 = FA_M_INIT;
1615
+ if (k_row3 > causal_limit) s3 = FA_M_INIT;
1616
+ }
1617
+ if (k_row0 >= n_kv) s0 = FA_M_INIT;
1618
+ if (k_row1 >= n_kv) s1 = FA_M_INIT;
1619
+ if (k_row2 >= n_kv) s2 = FA_M_INIT;
1620
+ if (k_row3 >= n_kv) s3 = FA_M_INIT;
1621
+
1622
+ if (query_valid && mask_base != NULL && blk_cur != 2) {
1623
+ const global MASK_DATA_TYPE * mask_ptr =
1624
+ (const global MASK_DATA_TYPE *) (mask_base + my_query_row * mask_nb1);
1625
+ if (k_row0 < n_kv) s0 += slope * (ACC_TYPE) mask_ptr[k_row0];
1626
+ if (k_row1 < n_kv) s1 += slope * (ACC_TYPE) mask_ptr[k_row1];
1627
+ if (k_row2 < n_kv) s2 += slope * (ACC_TYPE) mask_ptr[k_row2];
1628
+ if (k_row3 < n_kv) s3 += slope * (ACC_TYPE) mask_ptr[k_row3];
1629
+ }
1630
+ if (logit_softcap > 0.0f) {
1631
+ s0 = logit_softcap * tanh(s0 / logit_softcap);
1632
+ s1 = logit_softcap * tanh(s1 / logit_softcap);
1633
+ s2 = logit_softcap * tanh(s2 / logit_softcap);
1634
+ s3 = logit_softcap * tanh(s3 / logit_softcap);
1635
+ }
1636
+
1637
+ const ACC_TYPE m_new = max(m_i, max(max(s0, s1), max(s2, s3)));
1638
+ // Whole tile masked (m_new == FA_M_INIT): force the exp() args
1639
+ // far negative so the tile contributes 0, not exp(0)=1.
1640
+ const ACC_TYPE m_exp = (m_new == FA_M_INIT) ? 0.0f : m_new;
1641
+ const ACC_TYPE scale_prev = native_exp(m_i - m_exp);
1642
+ const ACC_TYPE p0 = native_exp(s0 - m_exp);
1643
+ const ACC_TYPE p1 = native_exp(s1 - m_exp);
1644
+ const ACC_TYPE p2 = native_exp(s2 - m_exp);
1645
+ const ACC_TYPE p3 = native_exp(s3 - m_exp);
1646
+
1647
+ #if FA_V_STRATEGY == 2
1648
+ #pragma unroll
1649
+ for (int b_local = 0; b_local < DV_Q8_BLOCKS_PREFILL / N_SPLIT; ++b_local) {
1650
+ const int b_abs = split_idx * (DV_Q8_BLOCKS_PREFILL / N_SPLIT) + b_local;
1651
+ const float d0 = l_v_scale[j ][b_abs];
1652
+ const float d1 = l_v_scale[j+1][b_abs];
1653
+ const float d2 = l_v_scale[j+2][b_abs];
1654
+ const float d3 = l_v_scale[j+3][b_abs];
1655
+ #pragma unroll
1656
+ for (int g = 0; g < 8; ++g) {
1657
+ const int lane_abs = b_abs * 8 + g;
1658
+ const int lane_local = b_local * 8 + g;
1659
+ uint pk0 = l_v_packed[j ][lane_abs];
1660
+ uint pk1 = l_v_packed[j+1][lane_abs];
1661
+ uint pk2 = l_v_packed[j+2][lane_abs];
1662
+ uint pk3 = l_v_packed[j+3][lane_abs];
1663
+ float4 v0 = d0 * (float4)((float)(char)(pk0 & 0xff), (float)(char)((pk0>>8)&0xff), (float)(char)((pk0>>16)&0xff), (float)(char)((pk0>>24)&0xff));
1664
+ float4 v1 = d1 * (float4)((float)(char)(pk1 & 0xff), (float)(char)((pk1>>8)&0xff), (float)(char)((pk1>>16)&0xff), (float)(char)((pk1>>24)&0xff));
1665
+ float4 v2 = d2 * (float4)((float)(char)(pk2 & 0xff), (float)(char)((pk2>>8)&0xff), (float)(char)((pk2>>16)&0xff), (float)(char)((pk2>>24)&0xff));
1666
+ float4 v3 = d3 * (float4)((float)(char)(pk3 & 0xff), (float)(char)((pk3>>8)&0xff), (float)(char)((pk3>>16)&0xff), (float)(char)((pk3>>24)&0xff));
1667
+ o_acc[lane_local] = mad(p3, v3,
1668
+ mad(p2, v2,
1669
+ mad(p1, v1,
1670
+ mad(p0, v0,
1671
+ o_acc[lane_local] * scale_prev))));
1672
+ }
1673
+ }
1674
+ #else // FA_V_STRATEGY == 0
1675
+ #pragma unroll
1676
+ for (int i = 0; i < SPLIT_DV_VEC; ++i) {
1677
+ const int i_abs = dv_off_vec + i;
1678
+ o_acc[i] = mad(p3, CONVERT_KV_ACC4(l_v[j+3][i_abs]),
1679
+ mad(p2, CONVERT_KV_ACC4(l_v[j+2][i_abs]),
1680
+ mad(p1, CONVERT_KV_ACC4(l_v[j+1][i_abs]),
1681
+ mad(p0, CONVERT_KV_ACC4(l_v[j ][i_abs]),
1682
+ o_acc[i] * scale_prev))));
1683
+ }
1684
+ #endif
1685
+ l_i = l_i * scale_prev + p0 + p1 + p2 + p3;
1686
+ m_i = m_new;
1687
+ }
1688
+ }
1689
+ barrier(CLK_LOCAL_MEM_FENCE);
1690
+ }
1691
+
1692
+ // Write output. With N_SPLIT>1 each thread writes its SPLIT_DV_VEC slice.
1693
+ if (query_valid) {
1694
+ if (sinks_void != NULL) {
1695
+ const global ACC_TYPE * sinks_ptr =
1696
+ (const global ACC_TYPE *) ((const global char *) sinks_void + sinks_offset);
1697
+ const ACC_TYPE m_sink = sinks_ptr[head_idx];
1698
+ const ACC_TYPE m_final = max(m_i, m_sink);
1699
+ const ACC_TYPE scale_o = exp(m_i - m_final);
1700
+ #pragma unroll
1701
+ for (int i = 0; i < SPLIT_DV_VEC; ++i) o_acc[i] *= scale_o;
1702
+ l_i = l_i * scale_o + exp(m_sink - m_final);
1703
+ m_i = m_final;
1704
+ }
1705
+ const ACC_TYPE l_inv = (l_i > 0.0f) ? (1.0f / l_i) : 0.0f;
1706
+ const ulong o_row_offset = batch_idx * o_nb3 + my_query_row * o_nb2 + head_idx * o_nb1;
1707
+ global float4 * o_row = (global float4 *) (o_base + o_row_offset);
1708
+ if (l_inv > 0.0f) {
1709
+ #pragma unroll
1710
+ for (int i = 0; i < SPLIT_DV_VEC; ++i) o_row[dv_off_vec + i] = o_acc[i] * l_inv;
1711
+ } else {
1712
+ #pragma unroll
1713
+ for (int i = 0; i < SPLIT_DV_VEC; ++i) o_row[dv_off_vec + i] = (float4)(0.0f);
1714
+ }
1715
+ }
1716
+ }
1717
+
1718
+ // FD Pass 2: merge split partials. Identical across q4_0/q8_0/f16; each FA
1719
+ // source owns a copy since kernels compile per-source-program.
1720
+ __kernel void flash_attn_f32_merge(
1721
+ const global float * partial_void,
1722
+ global void * o_void,
1723
+ const ulong o_offset,
1724
+ const int n_head,
1725
+ const int n_splits,
1726
+ const ulong o_nb1, const ulong o_nb2, const ulong o_nb3,
1727
+ const global void * sinks_void,
1728
+ const ulong sinks_offset,
1729
+ const int n_q
1730
+ ) {
1731
+ const int lane = get_local_id(0);
1732
+ const int head_batch_idx = get_global_id(1);
1733
+ const int q_idx = get_global_id(2);
1734
+ const int batch_idx = head_batch_idx / n_head;
1735
+ const int head_idx = head_batch_idx % n_head;
1736
+
1737
+ const ulong record_stride = (ulong) FA_PARTIAL_FLOATS;
1738
+ const ulong record_idx_0 = (((ulong) batch_idx * n_head + head_idx) * n_q + q_idx) * n_splits;
1739
+ const global float * rec0 = partial_void + record_idx_0 * record_stride;
1740
+
1741
+ __local ACC_TYPE m_final_shared;
1742
+ __local ACC_TYPE l_final_shared;
1743
+ if (lane == 0) {
1744
+ ACC_TYPE m = FA_M_INIT;
1745
+ for (int c = 0; c < n_splits; ++c) {
1746
+ const ACC_TYPE m_c = rec0[c * record_stride + 0];
1747
+ m = max(m, m_c);
1748
+ }
1749
+ ACC_TYPE m_sink = 0.0f;
1750
+ bool has_sink = false;
1751
+ if (sinks_void != NULL) {
1752
+ const global ACC_TYPE * sinks_ptr =
1753
+ (const global ACC_TYPE *) ((const global char *) sinks_void + sinks_offset);
1754
+ m_sink = sinks_ptr[head_idx];
1755
+ has_sink = true;
1756
+ m = max(m, m_sink);
1757
+ }
1758
+ ACC_TYPE l = 0.0f;
1759
+ for (int c = 0; c < n_splits; ++c) {
1760
+ const ACC_TYPE m_c = rec0[c * record_stride + 0];
1761
+ const ACC_TYPE l_c = rec0[c * record_stride + 1];
1762
+ if (m_c > FA_M_INIT) {
1763
+ l += l_c * exp(m_c - m);
1764
+ }
1765
+ }
1766
+ if (has_sink) {
1767
+ l += exp(m_sink - m);
1768
+ }
1769
+ m_final_shared = m;
1770
+ l_final_shared = l;
1771
+ }
1772
+ barrier(CLK_LOCAL_MEM_FENCE);
1773
+ const ACC_TYPE m_final = m_final_shared;
1774
+ const ACC_TYPE l_final = l_final_shared;
1775
+ const ACC_TYPE l_inv = (l_final > 0.0f) ? (1.0f / l_final) : 0.0f;
1776
+
1777
+ ACC_TYPE4 o = (ACC_TYPE4)(0.0f);
1778
+ for (int c = 0; c < n_splits; ++c) {
1779
+ const global float * rec_c = rec0 + c * record_stride;
1780
+ const ACC_TYPE m_c = rec_c[0];
1781
+ if (m_c <= FA_M_INIT) continue;
1782
+ const global float4 * rec_oc = (const global float4 *) (rec_c + 2);
1783
+ const ACC_TYPE scale_c = exp(m_c - m_final);
1784
+ o = mad((ACC_TYPE4)(scale_c), rec_oc[lane], o);
1785
+ }
1786
+ o = o * l_inv;
1787
+
1788
+ const ulong o_row_offset = (ulong) batch_idx * o_nb3 + (ulong) q_idx * o_nb2 + (ulong) head_idx * o_nb1;
1789
+ global O_DATA_TYPE4 * o_row = (global O_DATA_TYPE4 *) ((global char *) o_void + o_offset + o_row_offset);
1790
+ o_row[lane] = CONVERT_O_DATA4(o);
1791
+ }
backend/llama.cpp/ggml/src/ggml-opencl/kernels/flash_attn_pre_f16.cl ADDED
@@ -0,0 +1,156 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #pragma OPENCL EXTENSION cl_khr_fp16 : enable
2
+
3
+ __kernel void flash_attn_kv_pad_f16(
4
+ const global void * k_void, ulong k_offset,
5
+ const global void * v_void, ulong v_offset,
6
+ global void * k_pad_void,
7
+ global void * v_pad_void,
8
+ const int n_kv,
9
+ const int n_head_kv,
10
+ const int n_batch,
11
+ const ulong k_nb1, const ulong k_nb2, const ulong k_nb3,
12
+ const ulong v_nb1, const ulong v_nb2, const ulong v_nb3
13
+ ) {
14
+ const int row_idx = get_global_id(0);
15
+ const int head_kv_idx = get_global_id(1);
16
+ const int batch_idx = get_global_id(2);
17
+
18
+ if (row_idx >= BLOCK_N || head_kv_idx >= n_head_kv || batch_idx >= n_batch) {
19
+ return;
20
+ }
21
+
22
+ const int tail_start = n_kv - (n_kv % BLOCK_N);
23
+ const int src_row_idx = tail_start + row_idx;
24
+
25
+ const global char * k_src = (const global char *) k_void + k_offset;
26
+ const global char * v_src = (const global char *) v_void + v_offset;
27
+ global char * k_pad = (global char *) k_pad_void;
28
+ global char * v_pad = (global char *) v_pad_void;
29
+
30
+ const ulong k_dst_offset = ((ulong) batch_idx * (ulong) n_head_kv + (ulong) head_kv_idx) * ((ulong) BLOCK_N * k_nb1) + (ulong) row_idx * k_nb1;
31
+ const ulong v_dst_offset = ((ulong) batch_idx * (ulong) n_head_kv + (ulong) head_kv_idx) * ((ulong) BLOCK_N * v_nb1) + (ulong) row_idx * v_nb1;
32
+
33
+ if (src_row_idx < n_kv) {
34
+ const ulong k_src_offset = (ulong) batch_idx * k_nb3 + (ulong) head_kv_idx * k_nb2 + (ulong) src_row_idx * k_nb1;
35
+ const ulong v_src_offset = (ulong) batch_idx * v_nb3 + (ulong) head_kv_idx * v_nb2 + (ulong) src_row_idx * v_nb1;
36
+
37
+ for (ulong i = 0; i < k_nb1; ++i) {
38
+ k_pad[k_dst_offset + i] = k_src[k_src_offset + i];
39
+ }
40
+ for (ulong i = 0; i < v_nb1; ++i) {
41
+ v_pad[v_dst_offset + i] = v_src[v_src_offset + i];
42
+ }
43
+ } else {
44
+ for (ulong i = 0; i < k_nb1; ++i) {
45
+ k_pad[k_dst_offset + i] = 0;
46
+ }
47
+ for (ulong i = 0; i < v_nb1; ++i) {
48
+ v_pad[v_dst_offset + i] = 0;
49
+ }
50
+ }
51
+ }
52
+
53
+ __kernel void flash_attn_mask_pad_f16(
54
+ const global void * mask_void, ulong mask_offset,
55
+ global void * mask_pad_void,
56
+ const int n_q,
57
+ const int n_kv,
58
+ const ulong mask_nb1,
59
+ const ulong mask_nb2,
60
+ const ulong mask_nb3,
61
+ const int mask_ne2,
62
+ const int mask_ne3
63
+ ) {
64
+ const int col_idx = get_global_id(0);
65
+ const int q_row = get_global_id(1);
66
+ const int mask_slice = get_global_id(2);
67
+
68
+ if (col_idx >= BLOCK_N || q_row >= n_q || mask_slice >= mask_ne2 * mask_ne3) {
69
+ return;
70
+ }
71
+
72
+ const int tail_start = n_kv - (n_kv % BLOCK_N);
73
+ const int src_col_idx = tail_start + col_idx;
74
+ const int mask_head_idx = mask_slice % mask_ne2;
75
+ const int mask_batch_idx = mask_slice / mask_ne2;
76
+
77
+ const global char * mask_src_base = (const global char *) mask_void + mask_offset +
78
+ (ulong) mask_batch_idx * mask_nb3 +
79
+ (ulong) mask_head_idx * mask_nb2 +
80
+ (ulong) q_row * mask_nb1;
81
+ const global half * mask_src = (const global half *) mask_src_base;
82
+
83
+ global half * mask_pad = (global half *) mask_pad_void;
84
+ const ulong dst_idx =
85
+ (((ulong) mask_batch_idx * (ulong) mask_ne2 + (ulong) mask_head_idx) * (ulong) n_q + (ulong) q_row) * (ulong) BLOCK_N +
86
+ (ulong) col_idx;
87
+
88
+ mask_pad[dst_idx] = src_col_idx < n_kv ? mask_src[src_col_idx] : (half) (-INFINITY);
89
+ }
90
+
91
+ // Per-KV-tile mask class. 0=all -inf (skip tile), 1=mixed (apply mask),
92
+ // 2=all zero, no -inf (skip mask lookup). Causal diagonal tiles are class 1.
93
+ __kernel void flash_attn_blk_f16(
94
+ const global void * mask_void, ulong mask_offset,
95
+ global char * blk,
96
+ const int n_q,
97
+ const int n_kv,
98
+ const ulong mask_nb1,
99
+ const ulong mask_nb2,
100
+ const ulong mask_nb3,
101
+ const int mask_ne2,
102
+ const int mask_ne3
103
+ ) {
104
+ const int kv_block_idx = get_global_id(0);
105
+ const int q_block_idx = get_global_id(1);
106
+ const int mask_slice = get_global_id(2);
107
+
108
+ const int n_q_blocks = (n_q + BLOCK_M - 1) / BLOCK_M;
109
+ const int n_kv_blocks = (n_kv + BLOCK_N - 1) / BLOCK_N;
110
+ if (kv_block_idx >= n_kv_blocks || q_block_idx >= n_q_blocks || mask_slice >= mask_ne2 * mask_ne3) {
111
+ return;
112
+ }
113
+
114
+ const int mask_head_idx = mask_slice % mask_ne2;
115
+ const int mask_batch_idx = mask_slice / mask_ne2;
116
+ const int q_start = q_block_idx * BLOCK_M;
117
+ const int k_start = kv_block_idx * BLOCK_N;
118
+ const int q_count = min(BLOCK_M, n_q - q_start);
119
+ const int k_count = min(BLOCK_N, n_kv - k_start);
120
+
121
+ const half neg_max_half = (half) (-65504.0f);
122
+ char has_unmasked = 0;
123
+ char has_masked = 0;
124
+ char has_nonzero = 0;
125
+
126
+ const global char * mask_base = (const global char *) mask_void + mask_offset +
127
+ (ulong) mask_batch_idx * mask_nb3 +
128
+ (ulong) mask_head_idx * mask_nb2;
129
+
130
+ for (int qi = 0; qi < q_count; ++qi) {
131
+ const global half * mask_row = (const global half *) (mask_base + (ulong) (q_start + qi) * mask_nb1) + k_start;
132
+ for (int ki = 0; ki < k_count; ++ki) {
133
+ const half v = mask_row[ki];
134
+ if (v <= neg_max_half) {
135
+ has_masked = 1;
136
+ } else {
137
+ has_unmasked = 1;
138
+ if (v != (half) 0.0f) {
139
+ has_nonzero = 1;
140
+ }
141
+ }
142
+ }
143
+ if (has_masked && has_unmasked) break; // mixed tile — short-circuit.
144
+ }
145
+
146
+ char res;
147
+ if (has_unmasked == 0) {
148
+ res = 0;
149
+ } else if (has_masked || has_nonzero) {
150
+ res = 1;
151
+ } else {
152
+ res = 2;
153
+ }
154
+
155
+ blk[((ulong) mask_slice * (ulong) n_q_blocks + (ulong) q_block_idx) * (ulong) n_kv_blocks + (ulong) kv_block_idx] = res;
156
+ }
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gated_delta_net.cl ADDED
@@ -0,0 +1,249 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #pragma OPENCL EXTENSION cl_khr_subgroups : enable
2
+
3
+ #ifdef cl_intel_required_subgroup_size
4
+ #pragma OPENCL EXTENSION cl_intel_required_subgroup_size : enable
5
+ #define INTEL_GPU 1
6
+ #define REQD_SUBGROUP_SIZE_16 __attribute__((intel_reqd_sub_group_size(16)))
7
+ #define REQD_SUBGROUP_SIZE_32 __attribute__((intel_reqd_sub_group_size(32)))
8
+ #elif defined(cl_qcom_reqd_sub_group_size)
9
+ #pragma OPENCL EXTENSION cl_qcom_reqd_sub_group_size : enable
10
+ #define ADRENO_GPU 1
11
+ #define REQD_SUBGROUP_SIZE_64 __attribute__((qcom_reqd_sub_group_size("half")))
12
+ #define REQD_SUBGROUP_SIZE_128 __attribute__((qcom_reqd_sub_group_size("full")))
13
+ #endif
14
+
15
+ #ifndef S_V
16
+ #define S_V 128
17
+ #endif
18
+ #ifndef KDA
19
+ #define KDA 0
20
+ #endif
21
+ #ifndef SUBGROUP_SIZE
22
+ #define SUBGROUP_SIZE 64
23
+ #endif
24
+ #ifndef LANES_PER_COLUMN
25
+ #define LANES_PER_COLUMN 8
26
+ #endif
27
+ #ifndef COLS_PER_LANE_GROUP
28
+ #define COLS_PER_LANE_GROUP 1
29
+ #endif
30
+ #ifndef SUBGROUPS_PER_WG
31
+ #define SUBGROUPS_PER_WG 1
32
+ #endif
33
+ #ifndef USE_QCOM_SUBGROUP_SHUFFLE
34
+ #define USE_QCOM_SUBGROUP_SHUFFLE 0
35
+ #endif
36
+
37
+ #define WG_SIZE (SUBGROUP_SIZE * SUBGROUPS_PER_WG)
38
+ #define LANE_GROUPS_PER_SG (SUBGROUP_SIZE / LANES_PER_COLUMN)
39
+ #define COLS_PER_SG (LANE_GROUPS_PER_SG * COLS_PER_LANE_GROUP)
40
+ #define COLS_PER_WG (SUBGROUPS_PER_WG * COLS_PER_SG)
41
+ #define ROWS_PER_LANE (S_V / LANES_PER_COLUMN)
42
+
43
+ #if USE_QCOM_SUBGROUP_SHUFFLE
44
+ #pragma OPENCL EXTENSION cl_qcom_subgroup_shuffle : enable
45
+ #endif
46
+
47
+ // XOR-based parallel sum
48
+ // This does a reduction across groups of LANES_PER_COLUMN
49
+ static inline float reduce_add_shmem(float partial, __local float * temp, uint lane) {
50
+ #if USE_QCOM_SUBGROUP_SHUFFLE
51
+ #pragma unroll
52
+ for (uint s = LANES_PER_COLUMN / 2u; s > 0u; s >>= 1u) {
53
+ partial += qcom_sub_group_shuffle_xor(partial, s, CLK_SUB_GROUP_SHUFFLE_WIDTH_WAVE_SIZE_QCOM, partial);
54
+ }
55
+ return partial;
56
+ #else
57
+ temp[lane] = partial;
58
+ sub_group_barrier(CLK_LOCAL_MEM_FENCE);
59
+ #pragma unroll
60
+ for (uint s = LANES_PER_COLUMN / 2u; s > 0u; s >>= 1u) {
61
+ float other = temp[lane ^ s];
62
+ sub_group_barrier(CLK_LOCAL_MEM_FENCE);
63
+ temp[lane] += other;
64
+ sub_group_barrier(CLK_LOCAL_MEM_FENCE);
65
+ }
66
+ const float result = temp[lane];
67
+ sub_group_barrier(CLK_LOCAL_MEM_FENCE);
68
+ return result;
69
+ #endif
70
+ }
71
+
72
+ #define REDUCE_PARTIAL(partial, temp_ptr, lid) \
73
+ ((LANES_PER_COLUMN == 1u) ? (partial) : reduce_add_shmem((partial), (temp_ptr), (lid)))
74
+
75
+ // force compiler to optimize kernel for a specific fixed work-group size
76
+ __attribute__((reqd_work_group_size(WG_SIZE, 1, 1)))
77
+ #ifdef INTEL_GPU
78
+ REQD_SUBGROUP_SIZE_32
79
+ #elif defined (ADRENO_GPU)
80
+ REQD_SUBGROUP_SIZE_64
81
+ #endif
82
+ kernel void kernel_gated_delta_net(
83
+ global const char * q_buf, ulong off_q,
84
+ global const char * k_buf, ulong off_k,
85
+ global const char * v_buf, ulong off_v,
86
+ global const char * g_buf, ulong off_g,
87
+ global const char * beta_buf, ulong off_beta,
88
+ global const char * state_buf, ulong off_state,
89
+ global char * dst_buf, ulong off_dst,
90
+ uint H_v,
91
+ uint n_tokens,
92
+ uint n_seqs,
93
+ uint s_off,
94
+ uint sq1, uint sq2, uint sq3,
95
+ uint sv1, uint sv2, uint sv3,
96
+ uint sb1, uint sb2, uint sb3,
97
+ uint H_k,
98
+ uint rq3,
99
+ float scale,
100
+ uint K) {
101
+
102
+ global const float * data_q = (global const float *)(q_buf + off_q);
103
+ global const float * data_k = (global const float *)(k_buf + off_k);
104
+ global const float * data_v = (global const float *)(v_buf + off_v);
105
+ global const float * data_g = (global const float *)(g_buf + off_g);
106
+ global const float * data_beta = (global const float *)(beta_buf + off_beta);
107
+ global const float * data_state = (global const float *)(state_buf + off_state);
108
+ global float * data_dst = (global float *)(dst_buf + off_dst);
109
+
110
+ const uint head_id = get_group_id(0);
111
+ const uint seq_id = get_group_id(1);
112
+ const uint tid = (uint)get_local_id(0);
113
+
114
+ const uint sg_id = get_sub_group_id(); // subgroup id
115
+ const uint sg_lid = get_sub_group_local_id(); // subgroup lane id
116
+
117
+ const uint lane = sg_lid % LANES_PER_COLUMN;
118
+ const uint lane_group = sg_lid / LANES_PER_COLUMN;
119
+ const uint wg_col_base = get_group_id(2) * COLS_PER_WG;
120
+ const uint sg_col_base = wg_col_base + sg_id * COLS_PER_SG;
121
+
122
+ const uint iq1 = head_id % H_k; // head index for Q and K
123
+ const uint iq3 = seq_id / rq3; // seq index for Q and K
124
+
125
+ const uint state_size = S_V * S_V;
126
+ // input state holds s0 only [S_v, S_v, H, n_seqs]: per-seq stride is H*D.
127
+ const uint state_base = (seq_id * H_v + head_id) * state_size;
128
+ const uint q_off_base = iq3 * sq3 + iq1 * sq1;
129
+ const uint v_off_base = seq_id * sv3 + head_id * sv1;
130
+ const uint gb_off_base = seq_id * sb3 + head_id * sb1;
131
+ const uint state_out_base = (seq_id * H_v + head_id) * state_size;
132
+ const uint state_size_per_snap = state_size * H_v * n_seqs;
133
+
134
+ __local float reduce_temp[WG_SIZE];
135
+ __local float * temp_ptr = reduce_temp + sg_id * SUBGROUP_SIZE;
136
+
137
+ float s_shard[COLS_PER_LANE_GROUP][ROWS_PER_LANE];
138
+ #pragma unroll
139
+ for (uint cg = 0; cg < COLS_PER_LANE_GROUP; cg++) {
140
+ const uint col = sg_col_base + cg * LANE_GROUPS_PER_SG + lane_group;
141
+ #pragma unroll
142
+ for (uint r = 0; r < ROWS_PER_LANE; r++) {
143
+ s_shard[cg][r] = data_state[state_base + col * S_V + r * LANES_PER_COLUMN + lane];
144
+ }
145
+ }
146
+
147
+ // snapshot slot mapping: slot 0 = most recent state, slot s = s tokens back.
148
+ // When n_tokens < K only slots 0..n_tokens-1 are written; older slots are caller-owned.
149
+ uint attn_off = (seq_id * n_tokens * H_v + head_id) * S_V;
150
+
151
+ for (uint t = 0; t < n_tokens; t++) {
152
+ const uint q_off = q_off_base + t * sq2;
153
+ const uint k_off = q_off;
154
+ const uint v_off = v_off_base + t * sv2;
155
+ const uint gb_off = gb_off_base + t * sb2;
156
+ const float beta_val = data_beta[gb_off];
157
+
158
+ float k_reg[ROWS_PER_LANE];
159
+ float q_reg[ROWS_PER_LANE];
160
+ #if KDA
161
+ float g_exp[ROWS_PER_LANE];
162
+ #pragma unroll
163
+ for (uint r = 0; r < ROWS_PER_LANE; r++) {
164
+ const uint i = r * LANES_PER_COLUMN + lane;
165
+ k_reg[r] = data_k[k_off + i];
166
+ q_reg[r] = data_q[q_off + i];
167
+ g_exp[r] = exp(data_g[gb_off * S_V + i]);
168
+ }
169
+ #else
170
+ const float g_val = exp(data_g[gb_off]);
171
+
172
+ #pragma unroll
173
+ for (uint r = 0; r < ROWS_PER_LANE; r++) {
174
+ const uint i = r * LANES_PER_COLUMN + lane;
175
+ k_reg[r] = data_k[k_off + i];
176
+ q_reg[r] = data_q[q_off + i];
177
+ }
178
+ #endif
179
+
180
+ #pragma unroll
181
+ for (uint cg = 0; cg < COLS_PER_LANE_GROUP; cg++) {
182
+ const uint col = sg_col_base + cg * LANE_GROUPS_PER_SG + lane_group;
183
+ float v_val = data_v[v_off + col];
184
+
185
+ float kv_shard = 0.0f;
186
+ #pragma unroll
187
+ for (uint r = 0; r < ROWS_PER_LANE; r++) {
188
+ #if KDA
189
+ float gs = g_exp[r] * s_shard[cg][r];
190
+ kv_shard += gs * k_reg[r];
191
+ #else
192
+ kv_shard += s_shard[cg][r] * k_reg[r];
193
+ #endif
194
+ }
195
+
196
+ #if !KDA
197
+ kv_shard *= g_val; // Applied once instead of ROWS_PER_LANE times
198
+ #endif
199
+
200
+ const float kv_col = REDUCE_PARTIAL(kv_shard, temp_ptr, sg_lid);
201
+
202
+ const float delta_col = (v_val - kv_col) * beta_val;
203
+
204
+ float attn_partial = 0.0f;
205
+ #pragma unroll
206
+ for (uint r = 0; r < ROWS_PER_LANE; r++) {
207
+ #if KDA
208
+ float gs = g_exp[r] * s_shard[cg][r];
209
+ #else
210
+ float gs = g_val * s_shard[cg][r];
211
+ #endif
212
+ s_shard[cg][r] = gs + k_reg[r] * delta_col;
213
+ attn_partial += s_shard[cg][r] * q_reg[r];
214
+ }
215
+ const float attn_col = REDUCE_PARTIAL(attn_partial, temp_ptr, sg_lid);
216
+
217
+ if (lane == 0) {
218
+ data_dst[attn_off + col] = attn_col * scale;
219
+ }
220
+ }
221
+ attn_off += S_V * H_v;
222
+
223
+ if (K > 1u) {
224
+ const int target_slot = (int)n_tokens - 1 - (int)t;
225
+ if (target_slot >= 0 && target_slot < (int)K) {
226
+ #pragma unroll
227
+ for (uint cg = 0; cg < COLS_PER_LANE_GROUP; cg++) {
228
+ const uint col = sg_col_base + cg * LANE_GROUPS_PER_SG + lane_group;
229
+ const uint slot_base = s_off + (uint)target_slot * state_size_per_snap + state_out_base;
230
+ #pragma unroll
231
+ for (uint r = 0; r < ROWS_PER_LANE; r++) {
232
+ data_dst[slot_base + col * S_V + r * LANES_PER_COLUMN + lane] = s_shard[cg][r];
233
+ }
234
+ }
235
+ }
236
+ }
237
+ }
238
+
239
+ if (K == 1u) {
240
+ #pragma unroll
241
+ for (uint cg = 0; cg < COLS_PER_LANE_GROUP; cg++) {
242
+ const uint col = sg_col_base + cg * LANE_GROUPS_PER_SG + lane_group;
243
+ #pragma unroll
244
+ for (uint r = 0; r < ROWS_PER_LANE; r++) {
245
+ data_dst[s_off + state_base + col * S_V + r * LANES_PER_COLUMN + lane] = s_shard[cg][r];
246
+ }
247
+ }
248
+ }
249
+ }
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gelu.cl ADDED
@@ -0,0 +1,89 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #pragma OPENCL EXTENSION cl_khr_fp16 : enable
2
+
3
+ //------------------------------------------------------------------------------
4
+ // gelu
5
+ //------------------------------------------------------------------------------
6
+ #define GELU_COEF_A 0.044715f
7
+ #define GELU_QUICK_COEF -1.702f
8
+ #define SQRT_2_OVER_PI 0.79788456080286535587989211986876f
9
+ #define SQRT_2_INV 0.70710678118654752440084436210484f
10
+
11
+ kernel void kernel_gelu(
12
+ global float * src0,
13
+ ulong offset0,
14
+ global float * dst,
15
+ ulong offsetd
16
+ ) {
17
+ src0 = (global float*)((global char*)src0 + offset0);
18
+ dst = (global float*)((global char*)dst + offsetd);
19
+
20
+ float x = src0[get_global_id(0)];
21
+
22
+ dst[get_global_id(0)] = 0.5f*x*(1.0f + tanh(SQRT_2_OVER_PI*x*(1.0f + GELU_COEF_A*x*x)));
23
+ }
24
+
25
+ kernel void kernel_gelu_4(
26
+ global float4 * src0,
27
+ ulong offset0,
28
+ global float4 * dst,
29
+ ulong offsetd
30
+ ) {
31
+ src0 = (global float4*)((global char*)src0 + offset0);
32
+ dst = (global float4*)((global char*)dst + offsetd);
33
+
34
+ float4 x = src0[get_global_id(0)];
35
+
36
+ dst[get_global_id(0)] = 0.5f*x*(1.0f + tanh(SQRT_2_OVER_PI*x*(1.0f + GELU_COEF_A*x*x)));
37
+ }
38
+
39
+ kernel void kernel_gelu_erf(
40
+ global float * src0,
41
+ ulong offset0,
42
+ global float * dst,
43
+ ulong offsetd
44
+ ) {
45
+ src0 = (global float*)((global char*)src0 + offset0);
46
+ dst = (global float*)((global char*)dst + offsetd);
47
+
48
+ float x = src0[get_global_id(0)];
49
+ dst[get_global_id(0)] = 0.5f*x*(1.0f + erf(x*SQRT_2_INV));
50
+ }
51
+
52
+ kernel void kernel_gelu_erf_4(
53
+ global float4 * src0,
54
+ ulong offset0,
55
+ global float4 * dst,
56
+ ulong offsetd
57
+ ) {
58
+ src0 = (global float4*)((global char*)src0 + offset0);
59
+ dst = (global float4*)((global char*)dst + offsetd);
60
+
61
+ float4 x = src0[get_global_id(0)];
62
+ dst[get_global_id(0)] = 0.5f*x*(1.0f + erf(x*SQRT_2_INV));
63
+ }
64
+
65
+ kernel void kernel_gelu_quick(
66
+ global float * src0,
67
+ ulong offset0,
68
+ global float * dst,
69
+ ulong offsetd
70
+ ) {
71
+ src0 = (global float*)((global char*)src0 + offset0);
72
+ dst = (global float*)((global char*)dst + offsetd);
73
+
74
+ float x = src0[get_global_id(0)];
75
+ dst[get_global_id(0)] = x*(1.0f/(1.0f+exp(GELU_QUICK_COEF*x)));
76
+ }
77
+
78
+ kernel void kernel_gelu_quick_4(
79
+ global float4 * src0,
80
+ ulong offset0,
81
+ global float4 * dst,
82
+ ulong offsetd
83
+ ) {
84
+ src0 = (global float4*)((global char*)src0 + offset0);
85
+ dst = (global float4*)((global char*)dst + offsetd);
86
+
87
+ float4 x = src0[get_global_id(0)];
88
+ dst[get_global_id(0)] = x*(1.0f/(1.0f+exp(GELU_QUICK_COEF*x)));
89
+ }
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_moe_mxfp4_f32.cl ADDED
@@ -0,0 +1,162 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #pragma OPENCL EXTENSION cl_khr_fp16 : enable
2
+ #pragma OPENCL EXTENSION cl_khr_subgroups : enable
3
+ #pragma OPENCL EXTENSION cl_qcom_reqd_sub_group_size : enable
4
+
5
+ #define QK_MXFP4 32
6
+ #define N_SIMDGROUP 2
7
+ #define SIMDGROUP_WIDTH 64
8
+
9
+ static inline half8 mxfp4_to_fp16_packed8(ushort2 fp4x8) { //, ushort 0x0E00, ushort 0x8000) {
10
+ ushort2 fp16_packed_a_0, fp16_packed_b_0, bias_a, bias_b, sign_a, sign_b;
11
+ fp16_packed_a_0.lo = (fp4x8.s0 << 9) & 0x0E00;
12
+ fp16_packed_a_0.hi = (fp4x8.s0 << 5) & 0x0E00;
13
+ fp16_packed_b_0.lo = (fp4x8.s0 << 1) & 0x0E00;
14
+ fp16_packed_b_0.hi = (fp4x8.s0 >> 3) & 0x0E00;
15
+
16
+ bias_a.lo = (fp16_packed_a_0.lo != 0) ? 0x3800 : 0x0;
17
+ bias_a.hi = (fp16_packed_a_0.hi != 0) ? 0x3800 : 0x0;
18
+ bias_b.lo = (fp16_packed_b_0.lo != 0) ? 0x3800 : 0x0;
19
+ bias_b.hi = (fp16_packed_b_0.hi != 0) ? 0x3800 : 0x0;
20
+
21
+ fp16_packed_a_0.lo = (fp16_packed_a_0.lo != 0x0200) ? fp16_packed_a_0.lo : 0x0;
22
+ fp16_packed_a_0.hi = (fp16_packed_a_0.hi != 0x0200) ? fp16_packed_a_0.hi : 0x0;
23
+ fp16_packed_b_0.lo = (fp16_packed_b_0.lo != 0x0200) ? fp16_packed_b_0.lo : 0x0;
24
+ fp16_packed_b_0.hi = (fp16_packed_b_0.hi != 0x0200) ? fp16_packed_b_0.hi : 0x0;
25
+
26
+ sign_a.lo = (fp4x8.s0 << 12) & 0x8000;
27
+ sign_a.hi = (fp4x8.s0 << 8) & 0x8000;
28
+ sign_b.lo = (fp4x8.s0 << 4) & 0x8000;
29
+ sign_b.hi = fp4x8.s0 & 0x8000;
30
+
31
+ fp16_packed_a_0 = sign_a + bias_a + fp16_packed_a_0;
32
+ fp16_packed_b_0 = sign_b + bias_b + fp16_packed_b_0;
33
+
34
+ ushort2 fp16_packed_a_1, fp16_packed_b_1;
35
+ fp16_packed_a_1.lo = (fp4x8.s1 << 9) & 0x0E00;
36
+ fp16_packed_a_1.hi = (fp4x8.s1 << 5) & 0x0E00;
37
+ fp16_packed_b_1.lo = (fp4x8.s1 << 1) & 0x0E00;
38
+ fp16_packed_b_1.hi = (fp4x8.s1 >> 3) & 0x0E00;
39
+
40
+ bias_a.lo = (fp16_packed_a_1.lo != 0) ? 0x3800 : 0x0;
41
+ bias_a.hi = (fp16_packed_a_1.hi != 0) ? 0x3800 : 0x0;
42
+ bias_b.lo = (fp16_packed_b_1.lo != 0) ? 0x3800 : 0x0;
43
+ bias_b.hi = (fp16_packed_b_1.hi != 0) ? 0x3800 : 0x0;
44
+
45
+ fp16_packed_a_1.lo = (fp16_packed_a_1.lo != 0x0200) ? fp16_packed_a_1.lo : 0x0;
46
+ fp16_packed_a_1.hi = (fp16_packed_a_1.hi != 0x0200) ? fp16_packed_a_1.hi : 0x0;
47
+ fp16_packed_b_1.lo = (fp16_packed_b_1.lo != 0x0200) ? fp16_packed_b_1.lo : 0x0;
48
+ fp16_packed_b_1.hi = (fp16_packed_b_1.hi != 0x0200) ? fp16_packed_b_1.hi : 0x0;
49
+
50
+ sign_a.lo = (fp4x8.s1 << 12) & 0x8000;
51
+ sign_a.hi = (fp4x8.s1 << 8) & 0x8000;
52
+ sign_b.lo = (fp4x8.s1 << 4) & 0x8000;
53
+ sign_b.hi = fp4x8.s1 & 0x8000;
54
+
55
+ fp16_packed_a_1 = sign_a + bias_a + fp16_packed_a_1;
56
+ fp16_packed_b_1 = sign_b + bias_b + fp16_packed_b_1;
57
+
58
+ return as_half8((ushort8)(fp16_packed_a_0, fp16_packed_b_0, fp16_packed_a_1, fp16_packed_b_1));
59
+ }
60
+
61
+ static inline float e8m0_to_fp32(uchar x) {
62
+ int bits;
63
+ bits = (x == 0) ? 0x00400000 : ((uint) x << 23);
64
+ return as_float(bits);
65
+ }
66
+
67
+
68
+ __attribute__((qcom_reqd_sub_group_size("half")))
69
+ __kernel void kernel_gemm_moe_mxfp4_f32(
70
+ __global uint4 * src0_q,
71
+ __global uchar * src0_e,
72
+ __read_only image1d_buffer_t src1,
73
+ __global ushort4 * src2,
74
+ __global float * dst,
75
+ ulong offsetd,
76
+ int ne00,
77
+ int ne01,
78
+ int tile_size
79
+ ) {
80
+ uint i01 = get_global_id(0);
81
+ uint i20 = get_global_id(2);
82
+ uint sgid = get_local_id(1);
83
+ uint slid = get_sub_group_local_id();
84
+
85
+ ushort4 router = src2[i20];
86
+ ushort expert_id = router.x;
87
+ ushort i11 = router.y;
88
+ ushort i1 = router.z;
89
+ ushort tile_id = router.w;
90
+
91
+ if (tile_id * tile_size + i01 >= ne01) { // handle edge case when ne01 is not multiple of tile_size
92
+ return;
93
+ }
94
+
95
+ uint expert_offset = expert_id * ne00 * ne01 / 32;
96
+ uint tile_offset = expert_offset + tile_id * tile_size + i01;
97
+
98
+ __private float sum = 0.0f; // each thread calculate partial sum of one output
99
+
100
+ // loop along ne00 in block granularity, skip 4 blocks every iter
101
+ for (uint ib00 = sgid; ib00 < (ne00 / QK_MXFP4); ib00 += N_SIMDGROUP) {
102
+ // load one block of q
103
+ uint4 regQ = src0_q[tile_offset + ib00 * ne01];
104
+ // convert 8 fp4 to fp16
105
+ half8 fp16x8 = mxfp4_to_fp16_packed8(as_ushort2(regQ.s0));
106
+
107
+ uint offset = i11 * ne00 / 4 + ib00 * 8;
108
+ float4 shared_y4;
109
+ shared_y4 = read_imagef(src1, (offset + 0));
110
+ float4 acc = shared_y4 * (float4)(fp16x8.s0, fp16x8.s2, fp16x8.s4, fp16x8.s6);
111
+
112
+ shared_y4 = read_imagef(src1, (offset + 4));
113
+ acc += shared_y4 * (float4)(fp16x8.s1, fp16x8.s3, fp16x8.s5, fp16x8.s7);
114
+
115
+
116
+ fp16x8 = mxfp4_to_fp16_packed8(as_ushort2(regQ.s1));
117
+
118
+ shared_y4 = read_imagef(src1, (offset + 1));
119
+ acc += shared_y4 * (float4)(fp16x8.s0, fp16x8.s2, fp16x8.s4, fp16x8.s6);
120
+
121
+ shared_y4 = read_imagef(src1, (offset + 5));
122
+ acc += shared_y4 * (float4)(fp16x8.s1, fp16x8.s3, fp16x8.s5, fp16x8.s7);
123
+
124
+
125
+ fp16x8 = mxfp4_to_fp16_packed8(as_ushort2(regQ.s2));
126
+
127
+ shared_y4 = read_imagef(src1, (offset + 2));
128
+ acc += shared_y4 * (float4)(fp16x8.s0, fp16x8.s2, fp16x8.s4, fp16x8.s6);
129
+
130
+ shared_y4 = read_imagef(src1, (offset + 6));
131
+ acc += shared_y4 * (float4)(fp16x8.s1, fp16x8.s3, fp16x8.s5, fp16x8.s7);
132
+
133
+
134
+ fp16x8 = mxfp4_to_fp16_packed8(as_ushort2(regQ.s3));
135
+
136
+ shared_y4 = read_imagef(src1, (offset + 3));
137
+ acc += shared_y4 * (float4)(fp16x8.s0, fp16x8.s2, fp16x8.s4, fp16x8.s6);
138
+
139
+ shared_y4 = read_imagef(src1, (offset + 7));
140
+ acc += shared_y4 * (float4)(fp16x8.s1, fp16x8.s3, fp16x8.s5, fp16x8.s7);
141
+
142
+ uchar regE = src0_e[tile_offset + ib00 * ne01];
143
+ sum += e8m0_to_fp32(regE) * ((acc.s0 + acc.s1) + (acc.s2 + acc.s3));
144
+ }
145
+
146
+ // reduction in local memory, assumes #subgroups=4
147
+ __local float reduceLM[SIMDGROUP_WIDTH * (N_SIMDGROUP - 1)];
148
+ if (sgid == 1) reduceLM[SIMDGROUP_WIDTH * 0 + slid] = sum;
149
+ // if (sgid == 2) reduceLM[SIMDGROUP_WIDTH * 1 + slid] = sum;
150
+ // if (sgid == 3) reduceLM[SIMDGROUP_WIDTH * 2 + slid] = sum;
151
+ barrier(CLK_LOCAL_MEM_FENCE);
152
+ if (sgid == 0) sum += reduceLM[SIMDGROUP_WIDTH * 0 + slid];
153
+ // if (sgid == 0) sum += reduceLM[SIMDGROUP_WIDTH * 1 + slid];
154
+ // if (sgid == 0) sum += reduceLM[SIMDGROUP_WIDTH * 2 + slid];
155
+
156
+ // 1 outputs per thread in subgroup 0
157
+ if (sgid == 0) {
158
+ dst = dst + (offsetd >> 2);
159
+ dst[i01 + tile_id * tile_size + i1 * ne01] = sum;
160
+ }
161
+
162
+ }
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_moe_mxfp4_f32_ns.cl ADDED
@@ -0,0 +1,374 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #pragma OPENCL EXTENSION cl_khr_fp16 : enable
2
+ #pragma OPENCL EXTENSION cl_khr_subgroups : enable
3
+ #pragma OPENCL EXTENSION cl_qcom_subgroup_uniform_load: enable
4
+ #pragma OPENCL EXTENSION cl_qcom_subgroup_constant_load: enable
5
+ #pragma OPENCL EXTENSION cl_qcom_extra_vector_types : enable
6
+
7
+ #define TILESIZE_K 16
8
+ #define TILESIZE_M 64
9
+ #define TILESIZE_N 32
10
+
11
+
12
+ static inline half8 mxfp4_to_fp16_packed8(ushort2 fp4x8) {
13
+ ushort2 fp16_packed_a_0, fp16_packed_b_0, bias_a, bias_b, sign_a, sign_b;
14
+ fp16_packed_a_0.lo = (fp4x8.s0 << 9) & 0x0E00;
15
+ fp16_packed_a_0.hi = (fp4x8.s0 << 5) & 0x0E00;
16
+ fp16_packed_b_0.lo = (fp4x8.s0 << 1) & 0x0E00;
17
+ fp16_packed_b_0.hi = (fp4x8.s0 >> 3) & 0x0E00;
18
+
19
+ bias_a.lo = (fp16_packed_a_0.lo != 0) ? 0x3800 : 0x0;
20
+ bias_a.hi = (fp16_packed_a_0.hi != 0) ? 0x3800 : 0x0;
21
+ bias_b.lo = (fp16_packed_b_0.lo != 0) ? 0x3800 : 0x0;
22
+ bias_b.hi = (fp16_packed_b_0.hi != 0) ? 0x3800 : 0x0;
23
+
24
+ fp16_packed_a_0.lo = (fp16_packed_a_0.lo != 0x0200) ? fp16_packed_a_0.lo : 0x0;
25
+ fp16_packed_a_0.hi = (fp16_packed_a_0.hi != 0x0200) ? fp16_packed_a_0.hi : 0x0;
26
+ fp16_packed_b_0.lo = (fp16_packed_b_0.lo != 0x0200) ? fp16_packed_b_0.lo : 0x0;
27
+ fp16_packed_b_0.hi = (fp16_packed_b_0.hi != 0x0200) ? fp16_packed_b_0.hi : 0x0;
28
+
29
+ sign_a.lo = (fp4x8.s0 << 12) & 0x8000;
30
+ sign_a.hi = (fp4x8.s0 << 8) & 0x8000;
31
+ sign_b.lo = (fp4x8.s0 << 4) & 0x8000;
32
+ sign_b.hi = fp4x8.s0 & 0x8000;
33
+
34
+ fp16_packed_a_0 = sign_a + bias_a + fp16_packed_a_0;
35
+ fp16_packed_b_0 = sign_b + bias_b + fp16_packed_b_0;
36
+
37
+ ushort2 fp16_packed_a_1, fp16_packed_b_1;
38
+ fp16_packed_a_1.lo = (fp4x8.s1 << 9) & 0x0E00;
39
+ fp16_packed_a_1.hi = (fp4x8.s1 << 5) & 0x0E00;
40
+ fp16_packed_b_1.lo = (fp4x8.s1 << 1) & 0x0E00;
41
+ fp16_packed_b_1.hi = (fp4x8.s1 >> 3) & 0x0E00;
42
+
43
+ bias_a.lo = (fp16_packed_a_1.lo != 0) ? 0x3800 : 0x0;
44
+ bias_a.hi = (fp16_packed_a_1.hi != 0) ? 0x3800 : 0x0;
45
+ bias_b.lo = (fp16_packed_b_1.lo != 0) ? 0x3800 : 0x0;
46
+ bias_b.hi = (fp16_packed_b_1.hi != 0) ? 0x3800 : 0x0;
47
+
48
+ fp16_packed_a_1.lo = (fp16_packed_a_1.lo != 0x0200) ? fp16_packed_a_1.lo : 0x0;
49
+ fp16_packed_a_1.hi = (fp16_packed_a_1.hi != 0x0200) ? fp16_packed_a_1.hi : 0x0;
50
+ fp16_packed_b_1.lo = (fp16_packed_b_1.lo != 0x0200) ? fp16_packed_b_1.lo : 0x0;
51
+ fp16_packed_b_1.hi = (fp16_packed_b_1.hi != 0x0200) ? fp16_packed_b_1.hi : 0x0;
52
+
53
+ sign_a.lo = (fp4x8.s1 << 12) & 0x8000;
54
+ sign_a.hi = (fp4x8.s1 << 8) & 0x8000;
55
+ sign_b.lo = (fp4x8.s1 << 4) & 0x8000;
56
+ sign_b.hi = fp4x8.s1 & 0x8000;
57
+
58
+ fp16_packed_a_1 = sign_a + bias_a + fp16_packed_a_1;
59
+ fp16_packed_b_1 = sign_b + bias_b + fp16_packed_b_1;
60
+
61
+ return as_half8((ushort8)(fp16_packed_a_0, fp16_packed_b_0, fp16_packed_a_1, fp16_packed_b_1));
62
+ }
63
+
64
+
65
+ #define dotx16_reduce8(a_reg, b_lm, c_reg, lm_offset) \
66
+ acc.s0 = dot(a_reg.s0123, b_lm[lm_offset + 0]); \
67
+ acc.s1 = dot(a_reg.s0123, b_lm[lm_offset + 1]); \
68
+ acc.s2 = dot(a_reg.s0123, b_lm[lm_offset + 2]); \
69
+ acc.s3 = dot(a_reg.s0123, b_lm[lm_offset + 3]); \
70
+ acc.s4 = dot(a_reg.s0123, b_lm[lm_offset + 4]); \
71
+ acc.s5 = dot(a_reg.s0123, b_lm[lm_offset + 5]); \
72
+ acc.s6 = dot(a_reg.s0123, b_lm[lm_offset + 6]); \
73
+ acc.s7 = dot(a_reg.s0123, b_lm[lm_offset + 7]); \
74
+ acc.s8 = dot(a_reg.s0123, b_lm[lm_offset + 8]); \
75
+ acc.s9 = dot(a_reg.s0123, b_lm[lm_offset + 9]); \
76
+ acc.sa = dot(a_reg.s0123, b_lm[lm_offset + 10]); \
77
+ acc.sb = dot(a_reg.s0123, b_lm[lm_offset + 11]); \
78
+ acc.sc = dot(a_reg.s0123, b_lm[lm_offset + 12]); \
79
+ acc.sd = dot(a_reg.s0123, b_lm[lm_offset + 13]); \
80
+ acc.se = dot(a_reg.s0123, b_lm[lm_offset + 14]); \
81
+ acc.sf = dot(a_reg.s0123, b_lm[lm_offset + 15]); \
82
+ acc.s0 += dot(a_reg.s4567, b_lm[lm_offset + 32]); \
83
+ acc.s1 += dot(a_reg.s4567, b_lm[lm_offset + 33]); \
84
+ acc.s2 += dot(a_reg.s4567, b_lm[lm_offset + 34]); \
85
+ acc.s3 += dot(a_reg.s4567, b_lm[lm_offset + 35]); \
86
+ acc.s4 += dot(a_reg.s4567, b_lm[lm_offset + 36]); \
87
+ acc.s5 += dot(a_reg.s4567, b_lm[lm_offset + 37]); \
88
+ acc.s6 += dot(a_reg.s4567, b_lm[lm_offset + 38]); \
89
+ acc.s7 += dot(a_reg.s4567, b_lm[lm_offset + 39]); \
90
+ acc.s8 += dot(a_reg.s4567, b_lm[lm_offset + 40]); \
91
+ acc.s9 += dot(a_reg.s4567, b_lm[lm_offset + 41]); \
92
+ acc.sa += dot(a_reg.s4567, b_lm[lm_offset + 42]); \
93
+ acc.sb += dot(a_reg.s4567, b_lm[lm_offset + 43]); \
94
+ acc.sc += dot(a_reg.s4567, b_lm[lm_offset + 44]); \
95
+ acc.sd += dot(a_reg.s4567, b_lm[lm_offset + 45]); \
96
+ acc.se += dot(a_reg.s4567, b_lm[lm_offset + 46]); \
97
+ acc.sf += dot(a_reg.s4567, b_lm[lm_offset + 47]); \
98
+ c_reg.lo += convert_float8(acc.lo); \
99
+ c_reg.hi += convert_float8(acc.hi); \
100
+ acc.s0 = dot(a_reg.s89ab, b_lm[lm_offset + 64]); \
101
+ acc.s1 = dot(a_reg.s89ab, b_lm[lm_offset + 65]); \
102
+ acc.s2 = dot(a_reg.s89ab, b_lm[lm_offset + 66]); \
103
+ acc.s3 = dot(a_reg.s89ab, b_lm[lm_offset + 67]); \
104
+ acc.s4 = dot(a_reg.s89ab, b_lm[lm_offset + 68]); \
105
+ acc.s5 = dot(a_reg.s89ab, b_lm[lm_offset + 69]); \
106
+ acc.s6 = dot(a_reg.s89ab, b_lm[lm_offset + 70]); \
107
+ acc.s7 = dot(a_reg.s89ab, b_lm[lm_offset + 71]); \
108
+ acc.s8 = dot(a_reg.s89ab, b_lm[lm_offset + 72]); \
109
+ acc.s9 = dot(a_reg.s89ab, b_lm[lm_offset + 73]); \
110
+ acc.sa = dot(a_reg.s89ab, b_lm[lm_offset + 74]); \
111
+ acc.sb = dot(a_reg.s89ab, b_lm[lm_offset + 75]); \
112
+ acc.sc = dot(a_reg.s89ab, b_lm[lm_offset + 76]); \
113
+ acc.sd = dot(a_reg.s89ab, b_lm[lm_offset + 77]); \
114
+ acc.se = dot(a_reg.s89ab, b_lm[lm_offset + 78]); \
115
+ acc.sf = dot(a_reg.s89ab, b_lm[lm_offset + 79]); \
116
+ acc.s0 += dot(a_reg.scdef, b_lm[lm_offset + 96]); \
117
+ acc.s1 += dot(a_reg.scdef, b_lm[lm_offset + 97]); \
118
+ acc.s2 += dot(a_reg.scdef, b_lm[lm_offset + 98]); \
119
+ acc.s3 += dot(a_reg.scdef, b_lm[lm_offset + 99]); \
120
+ acc.s4 += dot(a_reg.scdef, b_lm[lm_offset + 100]); \
121
+ acc.s5 += dot(a_reg.scdef, b_lm[lm_offset + 101]); \
122
+ acc.s6 += dot(a_reg.scdef, b_lm[lm_offset + 102]); \
123
+ acc.s7 += dot(a_reg.scdef, b_lm[lm_offset + 103]); \
124
+ acc.s8 += dot(a_reg.scdef, b_lm[lm_offset + 104]); \
125
+ acc.s9 += dot(a_reg.scdef, b_lm[lm_offset + 105]); \
126
+ acc.sa += dot(a_reg.scdef, b_lm[lm_offset + 106]); \
127
+ acc.sb += dot(a_reg.scdef, b_lm[lm_offset + 107]); \
128
+ acc.sc += dot(a_reg.scdef, b_lm[lm_offset + 108]); \
129
+ acc.sd += dot(a_reg.scdef, b_lm[lm_offset + 109]); \
130
+ acc.se += dot(a_reg.scdef, b_lm[lm_offset + 110]); \
131
+ acc.sf += dot(a_reg.scdef, b_lm[lm_offset + 111]); \
132
+ c_reg.lo += convert_float8(acc.lo); \
133
+ c_reg.hi += convert_float8(acc.hi); \
134
+
135
+ // Quarter-tile variant: computes 8 output columns (one skip-group) into a float8
136
+ // accumulator. Same reduction order / flush cadence as dotx16_reduce8, so the
137
+ // non-skipped path is byte-identical; it just lets the caller skip empty
138
+ // 8-column groups at finer granularity. Uses a private half8 `acc8`.
139
+ #define dotx8_reduce4(a_reg, b_lm, c_reg, lm_offset) \
140
+ acc8.s0 = dot(a_reg.s0123, b_lm[lm_offset + 0]); \
141
+ acc8.s1 = dot(a_reg.s0123, b_lm[lm_offset + 1]); \
142
+ acc8.s2 = dot(a_reg.s0123, b_lm[lm_offset + 2]); \
143
+ acc8.s3 = dot(a_reg.s0123, b_lm[lm_offset + 3]); \
144
+ acc8.s4 = dot(a_reg.s0123, b_lm[lm_offset + 4]); \
145
+ acc8.s5 = dot(a_reg.s0123, b_lm[lm_offset + 5]); \
146
+ acc8.s6 = dot(a_reg.s0123, b_lm[lm_offset + 6]); \
147
+ acc8.s7 = dot(a_reg.s0123, b_lm[lm_offset + 7]); \
148
+ acc8.s0 += dot(a_reg.s4567, b_lm[lm_offset + 32]); \
149
+ acc8.s1 += dot(a_reg.s4567, b_lm[lm_offset + 33]); \
150
+ acc8.s2 += dot(a_reg.s4567, b_lm[lm_offset + 34]); \
151
+ acc8.s3 += dot(a_reg.s4567, b_lm[lm_offset + 35]); \
152
+ acc8.s4 += dot(a_reg.s4567, b_lm[lm_offset + 36]); \
153
+ acc8.s5 += dot(a_reg.s4567, b_lm[lm_offset + 37]); \
154
+ acc8.s6 += dot(a_reg.s4567, b_lm[lm_offset + 38]); \
155
+ acc8.s7 += dot(a_reg.s4567, b_lm[lm_offset + 39]); \
156
+ c_reg += convert_float8(acc8); \
157
+ acc8.s0 = dot(a_reg.s89ab, b_lm[lm_offset + 64]); \
158
+ acc8.s1 = dot(a_reg.s89ab, b_lm[lm_offset + 65]); \
159
+ acc8.s2 = dot(a_reg.s89ab, b_lm[lm_offset + 66]); \
160
+ acc8.s3 = dot(a_reg.s89ab, b_lm[lm_offset + 67]); \
161
+ acc8.s4 = dot(a_reg.s89ab, b_lm[lm_offset + 68]); \
162
+ acc8.s5 = dot(a_reg.s89ab, b_lm[lm_offset + 69]); \
163
+ acc8.s6 = dot(a_reg.s89ab, b_lm[lm_offset + 70]); \
164
+ acc8.s7 = dot(a_reg.s89ab, b_lm[lm_offset + 71]); \
165
+ acc8.s0 += dot(a_reg.scdef, b_lm[lm_offset + 96]); \
166
+ acc8.s1 += dot(a_reg.scdef, b_lm[lm_offset + 97]); \
167
+ acc8.s2 += dot(a_reg.scdef, b_lm[lm_offset + 98]); \
168
+ acc8.s3 += dot(a_reg.scdef, b_lm[lm_offset + 99]); \
169
+ acc8.s4 += dot(a_reg.scdef, b_lm[lm_offset + 100]); \
170
+ acc8.s5 += dot(a_reg.scdef, b_lm[lm_offset + 101]); \
171
+ acc8.s6 += dot(a_reg.scdef, b_lm[lm_offset + 102]); \
172
+ acc8.s7 += dot(a_reg.scdef, b_lm[lm_offset + 103]); \
173
+ c_reg += convert_float8(acc8); \
174
+
175
+
176
+ static inline half e8m0_to_fp16(uchar x) {
177
+ ushort bits;
178
+ bits = (ushort)(x) - (ushort)(112);
179
+ bits = ((bits & 0x00E0) != 0) ? 0x7C00 : (bits << 10);
180
+ return as_half(bits);
181
+ }
182
+
183
+ static inline float e8m0_to_fp32(uchar x) {
184
+ int bits;
185
+ bits = (x == 0) ? 0x00400000 : ((uint) x << 23);
186
+ return as_float(bits);
187
+ }
188
+
189
+
190
+ __attribute__((qcom_wave_pair_mode(1))) // 1=force single 2=force pair
191
+ kernel void kernel_gemm_moe_mxfp4_f32_ns(
192
+ __read_only image1d_buffer_t src0_q,
193
+ __global uchar * src0_d,
194
+ __read_only image1d_buffer_t src1,
195
+ __global uint * src2,
196
+ __global ushort * src2_emap,
197
+ __write_only image1d_buffer_t dst,
198
+ __global int * total_tiles,
199
+ uint ne00,
200
+ uint ne01,
201
+ uint is_ragged,
202
+ uint skip_gran
203
+ ) {
204
+ uint block_id_m = get_global_id(1); // m_tile
205
+ uint block_id_n = get_global_id(2); // n_tile
206
+
207
+ // Boundary check
208
+ if (block_id_n >= total_tiles[0]) {
209
+ return;
210
+ }
211
+
212
+ // Ragged tile-skip: when is_ragged and the upper 16 token-slots of this tile are all
213
+ // padding (router 0xFFFFFFFF), skip the second (reg_c.hi) dotx16_reduce8 half -> ~half
214
+ // the GEMM dot for sparse tiles. Numerically identical (the skipped lanes are padding).
215
+ // Ragged tile-skip: tokens are packed contiguously per expert (moe_scatter fills
216
+ // lanes 0..V-1, moe_fill pre-pads the rest), so router padding (0xFFFFFFFF) is always
217
+ // trailing. Find the valid-token count V and round it UP to the skip granularity
218
+ // skip_gran (columns per skip-group: 8 = quarter, 16 = half/legacy, 32 = disabled).
219
+ // A 8-column group g is all-padding iff its first column (8*g) >= n_active, so its
220
+ // dotx8_reduce4 is skipped. Numerically identical (skipped lanes are padding).
221
+ uint n_active = TILESIZE_N;
222
+ if (is_ragged && skip_gran < TILESIZE_N) {
223
+ uint n_valid = TILESIZE_N;
224
+ for (uint _t = 0; _t < TILESIZE_N; ++_t) {
225
+ if (src2[block_id_n * TILESIZE_N + _t] == 0xFFFFFFFFu) { n_valid = _t; break; }
226
+ }
227
+ n_active = min((uint)TILESIZE_N, ((n_valid + skip_gran - 1) / skip_gran) * skip_gran);
228
+ }
229
+ // Group 0 (cols 0-7) always runs; groups 1-3 skip when fully padding.
230
+ bool skip_g1 = (8u >= n_active);
231
+ bool skip_g2 = (16u >= n_active);
232
+ bool skip_g3 = (24u >= n_active);
233
+
234
+ __private half16 reg_a;
235
+ __private float32 reg_c = (float32)(0);
236
+ __local half4 shared_b[128];
237
+
238
+ const ushort expert_id = src2_emap[block_id_n];
239
+
240
+ const uint row = block_id_m * TILESIZE_M;
241
+ const uint col = block_id_n * TILESIZE_N;
242
+
243
+ uint sub_block_id_m = get_local_id(0);
244
+ uint2 b_global_offset;
245
+ b_global_offset.x = ((sub_block_id_m & 3) << 2) + (sub_block_id_m >> 2) * ne00;
246
+ b_global_offset.y = b_global_offset.x + (16 * ne00);
247
+ uint2 b_local_offset;
248
+ b_local_offset.x = (sub_block_id_m & 3) * 32 + (sub_block_id_m >> 2);
249
+ b_local_offset.y = b_local_offset.x + 16;
250
+
251
+ // Loop along K axis, 32 elements (one block) for each iteration, divided into 2 sub-blocks
252
+ for (uint step = 0; step < ne00; step += TILESIZE_K * 2) {
253
+ // First sub-block
254
+ uint q_sub_offset = row + ((ne01 * step) >> 3) + ((expert_id * ne00 * ne01) >> 3);
255
+ uint s_sub_offset = row + ((ne01 * step) >> 5) + ((expert_id * ne00 * ne01) >> 5);
256
+ uint b_sub_offset = col * ne00 + step;
257
+
258
+ // Load scale for current mxfp4 block
259
+ uint s_offset = s_sub_offset + get_global_id(0);
260
+ float s = e8m0_to_fp32(src0_d[s_offset]);
261
+
262
+ // Load 16 fp4 (64-bits) in transposed layout
263
+ uint2 mxfp4x16;
264
+ mxfp4x16.x = read_imageui(src0_q, q_sub_offset + sub_block_id_m).x;
265
+ mxfp4x16.y = read_imageui(src0_q, q_sub_offset + sub_block_id_m + ne01).x;
266
+
267
+ // Load 16x32 floats from matrix B, each fiber out of 64 in a sub-group loads 8 elements
268
+ float8 bx8_f32;
269
+ bx8_f32.lo = read_imagef(src1, (b_sub_offset + b_global_offset.x) / 4);
270
+ bx8_f32.hi = read_imagef(src1, (b_sub_offset + b_global_offset.y) / 4);
271
+ // Convert to half and store to LM to share within the subgroup
272
+ half8 bx8_f16 = convert_half8(bx8_f32);
273
+ shared_b[b_local_offset.x] = bx8_f16.lo;
274
+ shared_b[b_local_offset.y] = bx8_f16.hi;
275
+
276
+ // Dequantization
277
+ reg_a.lo = mxfp4_to_fp16_packed8(as_ushort2(mxfp4x16.lo)) * s;
278
+ reg_a.hi = mxfp4_to_fp16_packed8(as_ushort2(mxfp4x16.hi)) * s;
279
+
280
+ sub_group_barrier(CLK_LOCAL_MEM_FENCE);
281
+
282
+ // 32 16x16 fp16 dot product with 8 elements reduction for better precision
283
+ half8 acc8;
284
+ dotx8_reduce4(reg_a, shared_b, reg_c.lo.lo, 0);
285
+ if (!skip_g1) { dotx8_reduce4(reg_a, shared_b, reg_c.lo.hi, 8); }
286
+ if (!skip_g2) { dotx8_reduce4(reg_a, shared_b, reg_c.hi.lo, 16); }
287
+ if (!skip_g3) { dotx8_reduce4(reg_a, shared_b, reg_c.hi.hi, 24); }
288
+
289
+ // Repeat for second sub-block
290
+ uint half_step = step + TILESIZE_K;
291
+ q_sub_offset = row + ((ne01 * half_step) >> 3) + ((expert_id * ne00 * ne01) >> 3);
292
+ b_sub_offset = col * ne00 + half_step;
293
+
294
+ // Load next 16 fp4 (64-bits) in transposed layout
295
+ mxfp4x16.x = read_imageui(src0_q, q_sub_offset + sub_block_id_m).x;
296
+ mxfp4x16.y = read_imageui(src0_q, q_sub_offset + sub_block_id_m + ne01).x;
297
+
298
+ // Load 16x32 floats from matrix B, each fiber out of 64 in a sub-group loads 8 elements
299
+ bx8_f32.lo = read_imagef(src1, (b_sub_offset + b_global_offset.x) / 4);
300
+ bx8_f32.hi = read_imagef(src1, (b_sub_offset + b_global_offset.y) / 4);
301
+ // Convert to half and store to LM to share within the subgroup
302
+ bx8_f16 = convert_half8(bx8_f32);
303
+ shared_b[b_local_offset.x] = bx8_f16.lo;
304
+ shared_b[b_local_offset.y] = bx8_f16.hi;
305
+
306
+ // Dequantization
307
+ reg_a.lo = mxfp4_to_fp16_packed8(as_ushort2(mxfp4x16.lo)) * s;
308
+ reg_a.hi = mxfp4_to_fp16_packed8(as_ushort2(mxfp4x16.hi)) * s;
309
+
310
+ sub_group_barrier(CLK_LOCAL_MEM_FENCE);
311
+
312
+ // 32 16x16 fp16 dot product with 3-levels reduction for better precision
313
+ dotx8_reduce4(reg_a, shared_b, reg_c.lo.lo, 0);
314
+ if (!skip_g1) { dotx8_reduce4(reg_a, shared_b, reg_c.lo.hi, 8); }
315
+ if (!skip_g2) { dotx8_reduce4(reg_a, shared_b, reg_c.hi.lo, 16); }
316
+ if (!skip_g3) { dotx8_reduce4(reg_a, shared_b, reg_c.hi.hi, 24); }
317
+ }
318
+
319
+ if ((get_global_id(0) + block_id_m * TILESIZE_M) >= ne01) {
320
+ return;
321
+ }
322
+
323
+ // Load poster router and share in LM
324
+ __local uint out_idx[TILESIZE_N];
325
+
326
+ if (get_local_id(0) < TILESIZE_N) {
327
+ uint idx = src2[block_id_n * TILESIZE_N + get_local_id(0)];
328
+ if (idx == 0xFFFFFFFF) {
329
+ idx = src2[block_id_n * TILESIZE_N + 0];
330
+ }
331
+ out_idx[get_local_id(0)] = idx * ne01;
332
+ }
333
+
334
+ barrier(CLK_LOCAL_MEM_FENCE);
335
+
336
+ // Scatter results back to original position in output grid
337
+ uint m_offset = row + get_local_id(0);
338
+
339
+ write_imagef(dst, out_idx[1] + m_offset, (reg_c.s1));
340
+ write_imagef(dst, out_idx[2] + m_offset, (reg_c.s2));
341
+ write_imagef(dst, out_idx[3] + m_offset, (reg_c.s3));
342
+ write_imagef(dst, out_idx[4] + m_offset, (reg_c.s4));
343
+ write_imagef(dst, out_idx[5] + m_offset, (reg_c.s5));
344
+ write_imagef(dst, out_idx[6] + m_offset, (reg_c.s6));
345
+ write_imagef(dst, out_idx[7] + m_offset, (reg_c.s7));
346
+ write_imagef(dst, out_idx[8] + m_offset, (reg_c.s8));
347
+ write_imagef(dst, out_idx[9] + m_offset, (reg_c.s9));
348
+ write_imagef(dst, out_idx[10] + m_offset, (reg_c.sa));
349
+ write_imagef(dst, out_idx[11] + m_offset, (reg_c.sb));
350
+ write_imagef(dst, out_idx[12] + m_offset, (reg_c.sc));
351
+ write_imagef(dst, out_idx[13] + m_offset, (reg_c.sd));
352
+ write_imagef(dst, out_idx[14] + m_offset, (reg_c.se));
353
+ write_imagef(dst, out_idx[15] + m_offset, (reg_c.sf));
354
+ write_imagef(dst, out_idx[16] + m_offset, (reg_c.sg));
355
+ write_imagef(dst, out_idx[17] + m_offset, (reg_c.sh));
356
+ write_imagef(dst, out_idx[18] + m_offset, (reg_c.si));
357
+ write_imagef(dst, out_idx[19] + m_offset, (reg_c.sj));
358
+ write_imagef(dst, out_idx[20] + m_offset, (reg_c.sk));
359
+ write_imagef(dst, out_idx[21] + m_offset, (reg_c.sl));
360
+ write_imagef(dst, out_idx[22] + m_offset, (reg_c.sm));
361
+ write_imagef(dst, out_idx[23] + m_offset, (reg_c.sn));
362
+ write_imagef(dst, out_idx[24] + m_offset, (reg_c.so));
363
+ write_imagef(dst, out_idx[25] + m_offset, (reg_c.sp));
364
+ write_imagef(dst, out_idx[26] + m_offset, (reg_c.sq));
365
+ write_imagef(dst, out_idx[27] + m_offset, (reg_c.sr));
366
+ write_imagef(dst, out_idx[28] + m_offset, (reg_c.ss));
367
+ write_imagef(dst, out_idx[29] + m_offset, (reg_c.st));
368
+ write_imagef(dst, out_idx[30] + m_offset, (reg_c.su));
369
+ write_imagef(dst, out_idx[31] + m_offset, (reg_c.sv));
370
+
371
+ // Store zero padding parts to the index of first output in tile, override correct result in the end
372
+ barrier(CLK_GLOBAL_MEM_FENCE);
373
+ write_imagef(dst, out_idx[0] + m_offset, (reg_c.s0));
374
+ }
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_moe_mxfp4_q8_1_dp4a.cl ADDED
@@ -0,0 +1,186 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #pragma OPENCL EXTENSION cl_khr_fp16 : enable
2
+ #pragma OPENCL EXTENSION cl_khr_subgroups : enable
3
+ #ifdef cl_khr_integer_dot_product
4
+ #pragma OPENCL EXTENSION cl_khr_integer_dot_product : enable
5
+ #endif
6
+
7
+ #define TILESIZE_M 64
8
+ #define TILESIZE_N 32
9
+
10
+ // 2*mxfp4_value as signed int8, packed 4 codes per uint. Divergent nibble
11
+ // lookups read a __constant *uint* array + shift, never a byte array
12
+ // (byte-indexed __constant loads serialize on Adreno and are far slower).
13
+ // idx 0-3: 0, 1, 2, 3 = 0x03020100
14
+ // idx 4-7: 4, 6, 8, 12 = 0x0C080604
15
+ // idx 8-11: 0, -1, -2, -3 = 0xFDFEFF00 (-1=0xFF,-2=0xFE,-3=0xFD)
16
+ // idx 12-15:-4, -6, -8,-12 = 0xF4F8FAFC (-4=0xFC,-6=0xFA,-8=0xF8,-12=0xF4)
17
+ __constant uint mxfp4_i8x4[4] = {
18
+ 0x03020100u, 0x0C080604u, 0xFDFEFF00u, 0xF4F8FAFCu
19
+ };
20
+ inline uint mxfp4_code(uint n) {
21
+ return (mxfp4_i8x4[n >> 2] >> ((n & 3u) * 8u)) & 0xFFu;
22
+ }
23
+ // 4 nibbles in the low 16 bits of u -> 4 codebook int8, packed for dp4a.
24
+ inline uint mxfp4_pack(ushort u) {
25
+ return mxfp4_code((uint)( u & 0xF))
26
+ | (mxfp4_code((uint)((u >> 4) & 0xF)) << 8)
27
+ | (mxfp4_code((uint)((u >> 8) & 0xF)) << 16)
28
+ | (mxfp4_code((uint)((u >> 12) & 0xF)) << 24);
29
+ }
30
+
31
+ static inline float e8m0_to_fp32(uchar x) {
32
+ int bits;
33
+ bits = (x == 0) ? 0x00400000 : ((uint) x << 23);
34
+ return as_float(bits);
35
+ }
36
+
37
+ // One token's dp4a dot (8 uints = 32 K elems) + mxfp4 block-scale epilogue.
38
+ // blk_scale already carries the 0.5 factor (== 0.5 * 2^e).
39
+ #define MOE_MXFP4_DP4A_T(t) do { \
40
+ int raw = 0; \
41
+ raw = dot_acc_sat_4x8packed_ss_int(qw[0], sh_qa[t][0], raw); \
42
+ raw = dot_acc_sat_4x8packed_ss_int(qw[1], sh_qa[t][1], raw); \
43
+ raw = dot_acc_sat_4x8packed_ss_int(qw[2], sh_qa[t][2], raw); \
44
+ raw = dot_acc_sat_4x8packed_ss_int(qw[3], sh_qa[t][3], raw); \
45
+ raw = dot_acc_sat_4x8packed_ss_int(qw[4], sh_qa[t][4], raw); \
46
+ raw = dot_acc_sat_4x8packed_ss_int(qw[5], sh_qa[t][5], raw); \
47
+ raw = dot_acc_sat_4x8packed_ss_int(qw[6], sh_qa[t][6], raw); \
48
+ raw = dot_acc_sat_4x8packed_ss_int(qw[7], sh_qa[t][7], raw); \
49
+ acc[t] += blk_scale * (float)sh_d[t] * (float)raw; \
50
+ } while (0)
51
+
52
+ __attribute__((qcom_wave_pair_mode(1)))
53
+ kernel void kernel_gemm_moe_mxfp4_q8_1_dp4a(
54
+ __read_only image1d_buffer_t src0_q, // mxfp4 codes (transposed, packed nibbles)
55
+ __global uchar * src0_e, // e8m0 per-32-block scale
56
+ __global uint * src1_qa, // q8_1 activations: int8 quants (as uint, 4/elem)
57
+ __global half * src1_da, // q8_1 per-block scale [tok_slot * ne00/32]
58
+ __global uint * src2, // post-router (orig out positions)
59
+ __global ushort * src2_emap, // tile -> expert id
60
+ __write_only image1d_buffer_t dst,
61
+ __global int * total_tiles,
62
+ uint ne00,
63
+ uint ne01,
64
+ int is_ragged // 1: compute only real tokens per tile
65
+ ) {
66
+ const uint block_id_m = get_global_id(1); // m_tile
67
+ const uint block_id_n = get_global_id(2); // n_tile
68
+
69
+ if (block_id_n >= total_tiles[0]) {
70
+ return;
71
+ }
72
+
73
+ const uint lid = get_local_id(0); // 0..63, == this WI's output row in the M-tile
74
+
75
+ const ushort expert_id = src2_emap[block_id_n];
76
+ const uint row = block_id_m * TILESIZE_M;
77
+ const uint col = block_id_n * TILESIZE_N;
78
+
79
+ const uint num_blocks = ne00 >> 5; // blocks-of-32 per token
80
+ const uint row_idx = row + lid;
81
+
82
+ const uint ne00_u = ne00 >> 2; // ne00 in uint (int8x4) units
83
+
84
+ __local uint sh_qa[TILESIZE_N][8]; // 32 tokens x 8 uints (32 int8) = 1 KiB
85
+ __local half sh_d[TILESIZE_N];
86
+
87
+ // Real token count for this tile.
88
+ // Real tokens are packed contiguously at the tile start; padded slots hold
89
+ // 0xFFFFFFFF (only the last tile of each expert is partial). is_ragged skips
90
+ // the dp4a/staging/scatter for padded slots; is_ragged==0 forces n_real=32.
91
+ __local uint sh_src2[TILESIZE_N];
92
+ __local int sh_nreal;
93
+ if (lid < TILESIZE_N) {
94
+ sh_src2[lid] = src2[col + lid];
95
+ }
96
+ barrier(CLK_LOCAL_MEM_FENCE);
97
+ if (lid == 0) {
98
+ int nr = TILESIZE_N;
99
+ if (is_ragged) {
100
+ nr = 0;
101
+ #pragma unroll
102
+ for (int t = 0; t < TILESIZE_N; ++t) {
103
+ if (sh_src2[t] != 0xFFFFFFFFu) ++nr;
104
+ }
105
+ }
106
+ sh_nreal = nr;
107
+ }
108
+ barrier(CLK_LOCAL_MEM_FENCE);
109
+ const int n_real = sh_nreal;
110
+
111
+ float acc[TILESIZE_N];
112
+ #pragma unroll
113
+ for (int t = 0; t < TILESIZE_N; ++t) acc[t] = 0.0f;
114
+
115
+ for (uint step = 0; step < ne00; step += 32) {
116
+ const uint sub = step >> 5; // 32-block index along K
117
+
118
+ // e8m0 block scale for this WI's row, this 32-block (folded x0.5)
119
+ const uint e_offset = row_idx + sub * ne01 + expert_id * num_blocks * ne01;
120
+ const float blk_scale = 0.5f * e8m0_to_fp32(src0_e[e_offset]);
121
+
122
+ // repack this WI's 32 weight nibbles into 8 dp4a uints
123
+ const uint qoff0 = row + ((ne01 * step) >> 3) + ((expert_id * ne00 * ne01) >> 3);
124
+ const uint qoff1 = row + ((ne01 * (step + 16)) >> 3) + ((expert_id * ne00 * ne01) >> 3);
125
+ const uint r0 = read_imageui(src0_q, qoff0 + lid).x;
126
+ const uint r1 = read_imageui(src0_q, qoff0 + lid + ne01).x;
127
+ const uint r2 = read_imageui(src0_q, qoff1 + lid).x;
128
+ const uint r3 = read_imageui(src0_q, qoff1 + lid + ne01).x;
129
+ uint qw[8];
130
+ qw[0] = mxfp4_pack((ushort)(r0)); qw[1] = mxfp4_pack((ushort)(r0 >> 16));
131
+ qw[2] = mxfp4_pack((ushort)(r1)); qw[3] = mxfp4_pack((ushort)(r1 >> 16));
132
+ qw[4] = mxfp4_pack((ushort)(r2)); qw[5] = mxfp4_pack((ushort)(r2 >> 16));
133
+ qw[6] = mxfp4_pack((ushort)(r3)); qw[7] = mxfp4_pack((ushort)(r3 >> 16));
134
+
135
+ // cooperatively stage the n_real-token x 32-K int8 activations
136
+ const uint stage_lim = (uint)n_real * 8;
137
+ for (uint idx = lid; idx < stage_lim; idx += 64) {
138
+ const uint t = idx >> 3;
139
+ const uint u = idx & 7;
140
+ sh_qa[t][u] = src1_qa[(col + t) * ne00_u + (step >> 2) + u];
141
+ }
142
+ if (lid < (uint)n_real) {
143
+ sh_d[lid] = src1_da[(col + lid) * num_blocks + sub];
144
+ }
145
+ barrier(CLK_LOCAL_MEM_FENCE);
146
+
147
+ // Full tiles keep the fully-unrolled 32-wide loop; partial tiles run only n_real
148
+ if (n_real == TILESIZE_N) {
149
+ #pragma unroll
150
+ for (int t = 0; t < TILESIZE_N; ++t) { MOE_MXFP4_DP4A_T(t); }
151
+ } else {
152
+ #pragma unroll 4
153
+ for (int t = 0; t < n_real; ++t) { MOE_MXFP4_DP4A_T(t); }
154
+ }
155
+ barrier(CLK_LOCAL_MEM_FENCE);
156
+ }
157
+
158
+ if (row_idx >= ne01) {
159
+ return;
160
+ }
161
+
162
+ // scatter results to original output rows (reuse sh_src2 from the top)
163
+ __local uint out_idx[TILESIZE_N];
164
+ if (lid < TILESIZE_N) {
165
+ uint idx = sh_src2[lid];
166
+ if (idx == 0xFFFFFFFF) {
167
+ idx = sh_src2[0];
168
+ }
169
+ out_idx[lid] = idx * ne01;
170
+ }
171
+ barrier(CLK_LOCAL_MEM_FENCE);
172
+
173
+ const uint m_offset = row + lid;
174
+ if (n_real == TILESIZE_N) {
175
+ #pragma unroll
176
+ for (int t = 1; t < TILESIZE_N; ++t) {
177
+ write_imagef(dst, out_idx[t] + m_offset, acc[t]);
178
+ }
179
+ barrier(CLK_GLOBAL_MEM_FENCE);
180
+ write_imagef(dst, out_idx[0] + m_offset, acc[0]);
181
+ } else {
182
+ for (int t = 0; t < n_real; ++t) {
183
+ write_imagef(dst, out_idx[t] + m_offset, acc[t]);
184
+ }
185
+ }
186
+ }
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_moe_q4_0_f32_ns.cl ADDED
@@ -0,0 +1,324 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #pragma OPENCL EXTENSION cl_khr_fp16 : enable
2
+ #pragma OPENCL EXTENSION cl_khr_subgroups : enable
3
+ #pragma OPENCL EXTENSION cl_qcom_subgroup_uniform_load: enable
4
+ #pragma OPENCL EXTENSION cl_qcom_subgroup_constant_load: enable
5
+ #pragma OPENCL EXTENSION cl_qcom_extra_vector_types : enable
6
+
7
+ #define TILESIZE_K 16
8
+ #define TILESIZE_M 64
9
+ #define TILESIZE_N 32
10
+
11
+
12
+ #define dequantize_q4_0(q4, a_f16, scale) \
13
+ a_f16.s0 = (half)((q4.s0 & 0x000F) - 8) * scale; \
14
+ a_f16.s1 = (half)(((q4.s0 & 0x00F0) >> 4) - 8) * scale; \
15
+ a_f16.s2 = (half)(((q4.s0 & 0x0F00) >> 8) - 8) * scale; \
16
+ a_f16.s3 = (half)(((q4.s0 & 0xF000) >> 12) - 8) * scale; \
17
+ a_f16.s4 = (half)((q4.s1 & 0x000F) - 8) * scale; \
18
+ a_f16.s5 = (half)(((q4.s1 & 0x00F0) >> 4) - 8) * scale; \
19
+ a_f16.s6 = (half)(((q4.s1 & 0x0F00) >> 8) - 8) * scale; \
20
+ a_f16.s7 = (half)(((q4.s1 & 0xF000) >> 12) - 8) * scale; \
21
+ a_f16.s8 = (half)((q4.s2 & 0x000F) - 8) * scale; \
22
+ a_f16.s9 = (half)(((q4.s2 & 0x00F0) >> 4) - 8) * scale; \
23
+ a_f16.sa = (half)(((q4.s2 & 0x0F00) >> 8) - 8) * scale; \
24
+ a_f16.sb = (half)(((q4.s2 & 0xF000) >> 12) - 8) * scale; \
25
+ a_f16.sc = (half)((q4.s3 & 0x000F) - 8) * scale; \
26
+ a_f16.sd = (half)(((q4.s3 & 0x00F0) >> 4) - 8) * scale; \
27
+ a_f16.se = (half)(((q4.s3 & 0x0F00) >> 8) - 8) * scale; \
28
+ a_f16.sf = (half)(((q4.s3 & 0xF000) >> 12) - 8) * scale; \
29
+
30
+
31
+ #define dotx16_reduce8(a_reg, b_lm, c_reg, lm_offset) \
32
+ acc.s0 = dot(a_reg.s0123, b_lm[lm_offset + 0]); \
33
+ acc.s1 = dot(a_reg.s0123, b_lm[lm_offset + 1]); \
34
+ acc.s2 = dot(a_reg.s0123, b_lm[lm_offset + 2]); \
35
+ acc.s3 = dot(a_reg.s0123, b_lm[lm_offset + 3]); \
36
+ acc.s4 = dot(a_reg.s0123, b_lm[lm_offset + 4]); \
37
+ acc.s5 = dot(a_reg.s0123, b_lm[lm_offset + 5]); \
38
+ acc.s6 = dot(a_reg.s0123, b_lm[lm_offset + 6]); \
39
+ acc.s7 = dot(a_reg.s0123, b_lm[lm_offset + 7]); \
40
+ acc.s8 = dot(a_reg.s0123, b_lm[lm_offset + 8]); \
41
+ acc.s9 = dot(a_reg.s0123, b_lm[lm_offset + 9]); \
42
+ acc.sa = dot(a_reg.s0123, b_lm[lm_offset + 10]); \
43
+ acc.sb = dot(a_reg.s0123, b_lm[lm_offset + 11]); \
44
+ acc.sc = dot(a_reg.s0123, b_lm[lm_offset + 12]); \
45
+ acc.sd = dot(a_reg.s0123, b_lm[lm_offset + 13]); \
46
+ acc.se = dot(a_reg.s0123, b_lm[lm_offset + 14]); \
47
+ acc.sf = dot(a_reg.s0123, b_lm[lm_offset + 15]); \
48
+ acc.s0 += dot(a_reg.s4567, b_lm[lm_offset + 32]); \
49
+ acc.s1 += dot(a_reg.s4567, b_lm[lm_offset + 33]); \
50
+ acc.s2 += dot(a_reg.s4567, b_lm[lm_offset + 34]); \
51
+ acc.s3 += dot(a_reg.s4567, b_lm[lm_offset + 35]); \
52
+ acc.s4 += dot(a_reg.s4567, b_lm[lm_offset + 36]); \
53
+ acc.s5 += dot(a_reg.s4567, b_lm[lm_offset + 37]); \
54
+ acc.s6 += dot(a_reg.s4567, b_lm[lm_offset + 38]); \
55
+ acc.s7 += dot(a_reg.s4567, b_lm[lm_offset + 39]); \
56
+ acc.s8 += dot(a_reg.s4567, b_lm[lm_offset + 40]); \
57
+ acc.s9 += dot(a_reg.s4567, b_lm[lm_offset + 41]); \
58
+ acc.sa += dot(a_reg.s4567, b_lm[lm_offset + 42]); \
59
+ acc.sb += dot(a_reg.s4567, b_lm[lm_offset + 43]); \
60
+ acc.sc += dot(a_reg.s4567, b_lm[lm_offset + 44]); \
61
+ acc.sd += dot(a_reg.s4567, b_lm[lm_offset + 45]); \
62
+ acc.se += dot(a_reg.s4567, b_lm[lm_offset + 46]); \
63
+ acc.sf += dot(a_reg.s4567, b_lm[lm_offset + 47]); \
64
+ c_reg.lo += convert_float8(acc.lo); \
65
+ c_reg.hi += convert_float8(acc.hi); \
66
+ acc.s0 = dot(a_reg.s89ab, b_lm[lm_offset + 64]); \
67
+ acc.s1 = dot(a_reg.s89ab, b_lm[lm_offset + 65]); \
68
+ acc.s2 = dot(a_reg.s89ab, b_lm[lm_offset + 66]); \
69
+ acc.s3 = dot(a_reg.s89ab, b_lm[lm_offset + 67]); \
70
+ acc.s4 = dot(a_reg.s89ab, b_lm[lm_offset + 68]); \
71
+ acc.s5 = dot(a_reg.s89ab, b_lm[lm_offset + 69]); \
72
+ acc.s6 = dot(a_reg.s89ab, b_lm[lm_offset + 70]); \
73
+ acc.s7 = dot(a_reg.s89ab, b_lm[lm_offset + 71]); \
74
+ acc.s8 = dot(a_reg.s89ab, b_lm[lm_offset + 72]); \
75
+ acc.s9 = dot(a_reg.s89ab, b_lm[lm_offset + 73]); \
76
+ acc.sa = dot(a_reg.s89ab, b_lm[lm_offset + 74]); \
77
+ acc.sb = dot(a_reg.s89ab, b_lm[lm_offset + 75]); \
78
+ acc.sc = dot(a_reg.s89ab, b_lm[lm_offset + 76]); \
79
+ acc.sd = dot(a_reg.s89ab, b_lm[lm_offset + 77]); \
80
+ acc.se = dot(a_reg.s89ab, b_lm[lm_offset + 78]); \
81
+ acc.sf = dot(a_reg.s89ab, b_lm[lm_offset + 79]); \
82
+ acc.s0 += dot(a_reg.scdef, b_lm[lm_offset + 96]); \
83
+ acc.s1 += dot(a_reg.scdef, b_lm[lm_offset + 97]); \
84
+ acc.s2 += dot(a_reg.scdef, b_lm[lm_offset + 98]); \
85
+ acc.s3 += dot(a_reg.scdef, b_lm[lm_offset + 99]); \
86
+ acc.s4 += dot(a_reg.scdef, b_lm[lm_offset + 100]); \
87
+ acc.s5 += dot(a_reg.scdef, b_lm[lm_offset + 101]); \
88
+ acc.s6 += dot(a_reg.scdef, b_lm[lm_offset + 102]); \
89
+ acc.s7 += dot(a_reg.scdef, b_lm[lm_offset + 103]); \
90
+ acc.s8 += dot(a_reg.scdef, b_lm[lm_offset + 104]); \
91
+ acc.s9 += dot(a_reg.scdef, b_lm[lm_offset + 105]); \
92
+ acc.sa += dot(a_reg.scdef, b_lm[lm_offset + 106]); \
93
+ acc.sb += dot(a_reg.scdef, b_lm[lm_offset + 107]); \
94
+ acc.sc += dot(a_reg.scdef, b_lm[lm_offset + 108]); \
95
+ acc.sd += dot(a_reg.scdef, b_lm[lm_offset + 109]); \
96
+ acc.se += dot(a_reg.scdef, b_lm[lm_offset + 110]); \
97
+ acc.sf += dot(a_reg.scdef, b_lm[lm_offset + 111]); \
98
+ c_reg.lo += convert_float8(acc.lo); \
99
+ c_reg.hi += convert_float8(acc.hi); \
100
+
101
+ // Quarter-tile variant: computes 8 output columns (one skip-group) into a float8
102
+ // accumulator. Same reduction order / flush cadence as dotx16_reduce8, so the
103
+ // non-skipped path is byte-identical; it just lets the caller skip empty
104
+ // 8-column groups at finer granularity. Uses a private half8 `acc8`.
105
+ #define dotx8_reduce4(a_reg, b_lm, c_reg, lm_offset) \
106
+ acc8.s0 = dot(a_reg.s0123, b_lm[lm_offset + 0]); \
107
+ acc8.s1 = dot(a_reg.s0123, b_lm[lm_offset + 1]); \
108
+ acc8.s2 = dot(a_reg.s0123, b_lm[lm_offset + 2]); \
109
+ acc8.s3 = dot(a_reg.s0123, b_lm[lm_offset + 3]); \
110
+ acc8.s4 = dot(a_reg.s0123, b_lm[lm_offset + 4]); \
111
+ acc8.s5 = dot(a_reg.s0123, b_lm[lm_offset + 5]); \
112
+ acc8.s6 = dot(a_reg.s0123, b_lm[lm_offset + 6]); \
113
+ acc8.s7 = dot(a_reg.s0123, b_lm[lm_offset + 7]); \
114
+ acc8.s0 += dot(a_reg.s4567, b_lm[lm_offset + 32]); \
115
+ acc8.s1 += dot(a_reg.s4567, b_lm[lm_offset + 33]); \
116
+ acc8.s2 += dot(a_reg.s4567, b_lm[lm_offset + 34]); \
117
+ acc8.s3 += dot(a_reg.s4567, b_lm[lm_offset + 35]); \
118
+ acc8.s4 += dot(a_reg.s4567, b_lm[lm_offset + 36]); \
119
+ acc8.s5 += dot(a_reg.s4567, b_lm[lm_offset + 37]); \
120
+ acc8.s6 += dot(a_reg.s4567, b_lm[lm_offset + 38]); \
121
+ acc8.s7 += dot(a_reg.s4567, b_lm[lm_offset + 39]); \
122
+ c_reg += convert_float8(acc8); \
123
+ acc8.s0 = dot(a_reg.s89ab, b_lm[lm_offset + 64]); \
124
+ acc8.s1 = dot(a_reg.s89ab, b_lm[lm_offset + 65]); \
125
+ acc8.s2 = dot(a_reg.s89ab, b_lm[lm_offset + 66]); \
126
+ acc8.s3 = dot(a_reg.s89ab, b_lm[lm_offset + 67]); \
127
+ acc8.s4 = dot(a_reg.s89ab, b_lm[lm_offset + 68]); \
128
+ acc8.s5 = dot(a_reg.s89ab, b_lm[lm_offset + 69]); \
129
+ acc8.s6 = dot(a_reg.s89ab, b_lm[lm_offset + 70]); \
130
+ acc8.s7 = dot(a_reg.s89ab, b_lm[lm_offset + 71]); \
131
+ acc8.s0 += dot(a_reg.scdef, b_lm[lm_offset + 96]); \
132
+ acc8.s1 += dot(a_reg.scdef, b_lm[lm_offset + 97]); \
133
+ acc8.s2 += dot(a_reg.scdef, b_lm[lm_offset + 98]); \
134
+ acc8.s3 += dot(a_reg.scdef, b_lm[lm_offset + 99]); \
135
+ acc8.s4 += dot(a_reg.scdef, b_lm[lm_offset + 100]); \
136
+ acc8.s5 += dot(a_reg.scdef, b_lm[lm_offset + 101]); \
137
+ acc8.s6 += dot(a_reg.scdef, b_lm[lm_offset + 102]); \
138
+ acc8.s7 += dot(a_reg.scdef, b_lm[lm_offset + 103]); \
139
+ c_reg += convert_float8(acc8); \
140
+
141
+
142
+ __attribute__((qcom_wave_pair_mode(1))) // 1=force single 2=force pair
143
+ kernel void kernel_gemm_moe_q4_0_f32_ns(
144
+ __read_only image1d_buffer_t src0_q,
145
+ __global half * src0_d,
146
+ __read_only image1d_buffer_t src1,
147
+ __global uint * src2,
148
+ __global ushort * src2_emap,
149
+ __write_only image1d_buffer_t dst,
150
+ __global int * total_tiles,
151
+ uint ne00,
152
+ uint ne01,
153
+ uint is_ragged,
154
+ uint skip_gran
155
+ ) {
156
+ uint block_id_m = get_global_id(1); // m_tile
157
+ uint block_id_n = get_global_id(2); // n_tile
158
+
159
+ // Boundary check
160
+ if (block_id_n >= total_tiles[0]) {
161
+ return;
162
+ }
163
+
164
+ // Ragged tile-skip: when is_ragged and the upper 16 token-slots of this tile are all
165
+ // padding (router 0xFFFFFFFF), skip the second (reg_c.hi) dotx16_reduce8 half -> ~half
166
+ // the GEMM dot for sparse tiles. Numerically identical (the skipped lanes are padding).
167
+ // Ragged tile-skip: tokens are packed contiguously per expert (moe_scatter fills
168
+ // lanes 0..V-1, moe_fill pre-pads the rest), so router padding (0xFFFFFFFF) is always
169
+ // trailing. Find the valid-token count V and round it UP to the skip granularity
170
+ // skip_gran (columns per skip-group: 8 = quarter, 16 = half/legacy, 32 = disabled).
171
+ // A 8-column group g is all-padding iff its first column (8*g) >= n_active, so its
172
+ // dotx8_reduce4 is skipped. Numerically identical (skipped lanes are padding).
173
+ uint n_active = TILESIZE_N;
174
+ if (is_ragged && skip_gran < TILESIZE_N) {
175
+ uint n_valid = TILESIZE_N;
176
+ for (uint _t = 0; _t < TILESIZE_N; ++_t) {
177
+ if (src2[block_id_n * TILESIZE_N + _t] == 0xFFFFFFFFu) { n_valid = _t; break; }
178
+ }
179
+ n_active = min((uint)TILESIZE_N, ((n_valid + skip_gran - 1) / skip_gran) * skip_gran);
180
+ }
181
+ // Group 0 (cols 0-7) always runs; groups 1-3 skip when fully padding.
182
+ bool skip_g1 = (8u >= n_active);
183
+ bool skip_g2 = (16u >= n_active);
184
+ bool skip_g3 = (24u >= n_active);
185
+
186
+ __private half16 reg_a;
187
+ __private float32 reg_c = (float32)(0);
188
+ __local half4 shared_b[128];
189
+
190
+ const ushort expert_id = src2_emap[block_id_n];
191
+
192
+ const uint row = block_id_m * TILESIZE_M;
193
+ const uint col = block_id_n * TILESIZE_N;
194
+
195
+ uint sub_block_id_m = get_local_id(0);
196
+ uint2 b_global_offset;
197
+ b_global_offset.x = ((sub_block_id_m & 3) << 2) + (sub_block_id_m >> 2) * ne00;
198
+ b_global_offset.y = b_global_offset.x + (16 * ne00);
199
+ uint2 b_local_offset;
200
+ b_local_offset.x = (sub_block_id_m & 3) * 32 + (sub_block_id_m >> 2);
201
+ b_local_offset.y = b_local_offset.x + 16;
202
+
203
+ // Loop along K axis, 32 elements (one block) for each iteration, divided into 2 sub-blocks
204
+ for (uint step = 0; step < ne00; step += TILESIZE_K * 2) {
205
+ // First sub-block
206
+ uint q_sub_offset = row + ((ne01 * step) >> 3) + ((expert_id * ne00 * ne01) >> 3);
207
+ uint s_sub_offset = row + ((ne01 * step) >> 5) + ((expert_id * ne00 * ne01) >> 5);
208
+ uint b_sub_offset = col * ne00 + step;
209
+
210
+ // Load scale for current Q4_0 block
211
+ uint s_offset = s_sub_offset + get_global_id(0);
212
+ half s = src0_d[s_offset];
213
+
214
+ // Load 16 q (64-bits) in transposed layout
215
+ uint2 q4x16;
216
+ q4x16.x = read_imageui(src0_q, q_sub_offset + sub_block_id_m).x;
217
+ q4x16.y = read_imageui(src0_q, q_sub_offset + sub_block_id_m + ne01).x;
218
+
219
+ // Load 16x32 floats from matrix B, each fiber out of 64 in a sub-group loads 8 elements
220
+ float8 bx8_f32;
221
+ bx8_f32.lo = read_imagef(src1, (b_sub_offset + b_global_offset.x) / 4);
222
+ bx8_f32.hi = read_imagef(src1, (b_sub_offset + b_global_offset.y) / 4);
223
+ // Convert to half and store to LM to share within the subgroup
224
+ half8 bx8_f16 = convert_half8(bx8_f32);
225
+ shared_b[b_local_offset.x] = bx8_f16.lo;
226
+ shared_b[b_local_offset.y] = bx8_f16.hi;
227
+
228
+ // Dequantization
229
+ dequantize_q4_0(as_ushort4(q4x16), reg_a, s);
230
+
231
+ sub_group_barrier(CLK_LOCAL_MEM_FENCE);
232
+
233
+ // 32 16x16 fp16 dot product with 8 elements reduction for better precision
234
+ half8 acc8;
235
+ dotx8_reduce4(reg_a, shared_b, reg_c.lo.lo, 0);
236
+ if (!skip_g1) { dotx8_reduce4(reg_a, shared_b, reg_c.lo.hi, 8); }
237
+ if (!skip_g2) { dotx8_reduce4(reg_a, shared_b, reg_c.hi.lo, 16); }
238
+ if (!skip_g3) { dotx8_reduce4(reg_a, shared_b, reg_c.hi.hi, 24); }
239
+
240
+ // Repeat for second sub-block
241
+ uint half_step = step + TILESIZE_K;
242
+ q_sub_offset = row + ((ne01 * half_step) >> 3) + ((expert_id * ne00 * ne01) >> 3);
243
+ b_sub_offset = col * ne00 + half_step;
244
+
245
+ // Load next 16 q (64-bits) in transposed layout
246
+ q4x16.x = read_imageui(src0_q, q_sub_offset + sub_block_id_m).x;
247
+ q4x16.y = read_imageui(src0_q, q_sub_offset + sub_block_id_m + ne01).x;
248
+
249
+ // Load 16x32 floats from matrix B, each fiber out of 64 in a sub-group loads 8 elements
250
+ bx8_f32.lo = read_imagef(src1, (b_sub_offset + b_global_offset.x) / 4);
251
+ bx8_f32.hi = read_imagef(src1, (b_sub_offset + b_global_offset.y) / 4);
252
+ // Convert to half and store to LM to share within the subgroup
253
+ bx8_f16 = convert_half8(bx8_f32);
254
+ shared_b[b_local_offset.x] = bx8_f16.lo;
255
+ shared_b[b_local_offset.y] = bx8_f16.hi;
256
+
257
+ // Dequantization
258
+ dequantize_q4_0(as_ushort4(q4x16), reg_a, s);
259
+
260
+ sub_group_barrier(CLK_LOCAL_MEM_FENCE);
261
+
262
+ // 32 16x16 fp16 dot product with 3-levels reduction for better precision
263
+ dotx8_reduce4(reg_a, shared_b, reg_c.lo.lo, 0);
264
+ if (!skip_g1) { dotx8_reduce4(reg_a, shared_b, reg_c.lo.hi, 8); }
265
+ if (!skip_g2) { dotx8_reduce4(reg_a, shared_b, reg_c.hi.lo, 16); }
266
+ if (!skip_g3) { dotx8_reduce4(reg_a, shared_b, reg_c.hi.hi, 24); }
267
+ }
268
+
269
+ if ((get_global_id(0) + block_id_m * TILESIZE_M) >= ne01) {
270
+ return;
271
+ }
272
+
273
+ // Load poster router and share in LM
274
+ __local uint out_idx[TILESIZE_N];
275
+
276
+ if (get_local_id(0) < TILESIZE_N) {
277
+ uint idx = src2[block_id_n * TILESIZE_N + get_local_id(0)];
278
+ if (idx == 0xFFFFFFFF) {
279
+ idx = src2[block_id_n * TILESIZE_N + 0];
280
+ }
281
+ out_idx[get_local_id(0)] = idx * ne01;
282
+ }
283
+
284
+ barrier(CLK_LOCAL_MEM_FENCE);
285
+
286
+ // Scatter results back to original position in output grid
287
+ uint m_offset = row + get_local_id(0);
288
+
289
+ write_imagef(dst, out_idx[1] + m_offset, (reg_c.s1));
290
+ write_imagef(dst, out_idx[2] + m_offset, (reg_c.s2));
291
+ write_imagef(dst, out_idx[3] + m_offset, (reg_c.s3));
292
+ write_imagef(dst, out_idx[4] + m_offset, (reg_c.s4));
293
+ write_imagef(dst, out_idx[5] + m_offset, (reg_c.s5));
294
+ write_imagef(dst, out_idx[6] + m_offset, (reg_c.s6));
295
+ write_imagef(dst, out_idx[7] + m_offset, (reg_c.s7));
296
+ write_imagef(dst, out_idx[8] + m_offset, (reg_c.s8));
297
+ write_imagef(dst, out_idx[9] + m_offset, (reg_c.s9));
298
+ write_imagef(dst, out_idx[10] + m_offset, (reg_c.sa));
299
+ write_imagef(dst, out_idx[11] + m_offset, (reg_c.sb));
300
+ write_imagef(dst, out_idx[12] + m_offset, (reg_c.sc));
301
+ write_imagef(dst, out_idx[13] + m_offset, (reg_c.sd));
302
+ write_imagef(dst, out_idx[14] + m_offset, (reg_c.se));
303
+ write_imagef(dst, out_idx[15] + m_offset, (reg_c.sf));
304
+ write_imagef(dst, out_idx[16] + m_offset, (reg_c.sg));
305
+ write_imagef(dst, out_idx[17] + m_offset, (reg_c.sh));
306
+ write_imagef(dst, out_idx[18] + m_offset, (reg_c.si));
307
+ write_imagef(dst, out_idx[19] + m_offset, (reg_c.sj));
308
+ write_imagef(dst, out_idx[20] + m_offset, (reg_c.sk));
309
+ write_imagef(dst, out_idx[21] + m_offset, (reg_c.sl));
310
+ write_imagef(dst, out_idx[22] + m_offset, (reg_c.sm));
311
+ write_imagef(dst, out_idx[23] + m_offset, (reg_c.sn));
312
+ write_imagef(dst, out_idx[24] + m_offset, (reg_c.so));
313
+ write_imagef(dst, out_idx[25] + m_offset, (reg_c.sp));
314
+ write_imagef(dst, out_idx[26] + m_offset, (reg_c.sq));
315
+ write_imagef(dst, out_idx[27] + m_offset, (reg_c.sr));
316
+ write_imagef(dst, out_idx[28] + m_offset, (reg_c.ss));
317
+ write_imagef(dst, out_idx[29] + m_offset, (reg_c.st));
318
+ write_imagef(dst, out_idx[30] + m_offset, (reg_c.su));
319
+ write_imagef(dst, out_idx[31] + m_offset, (reg_c.sv));
320
+
321
+ // Store zero padding parts to the index of first output in tile, override correct result in the end
322
+ barrier(CLK_GLOBAL_MEM_FENCE);
323
+ write_imagef(dst, out_idx[0] + m_offset, (reg_c.s0));
324
+ }
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_moe_q4_0_q8_1_dp4a.cl ADDED
@@ -0,0 +1,165 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #pragma OPENCL EXTENSION cl_khr_fp16 : enable
2
+ #pragma OPENCL EXTENSION cl_khr_subgroups : enable
3
+ #ifdef cl_khr_integer_dot_product
4
+ #pragma OPENCL EXTENSION cl_khr_integer_dot_product : enable
5
+ #endif
6
+
7
+ #define TILESIZE_M 64
8
+ #define TILESIZE_N 32
9
+
10
+ // Expand the 4 nibbles held in the low 16 bits of `u` into 4 bytes (one nibble
11
+ // per byte, value 0..15), packed for the int8 dp4a. The -8 zero-point is applied
12
+ // in the epilogue via the activation sum term (cheaper than biasing every byte).
13
+ #define EXP4(u) ( ((uint)((u) & 0x000Fu)) | \
14
+ (((uint)((u) & 0x00F0u)) << 4) | \
15
+ (((uint)((u) & 0x0F00u)) << 8) | \
16
+ (((uint)((u) & 0xF000u)) << 12) )
17
+
18
+ // One token's dp4a dot (8 uints = 32 K elems) + q4_0 scale/zero-point epilogue.
19
+ #define MOE_Q40_DP4A_T(t) do { \
20
+ int raw = 0; \
21
+ raw = dot_acc_sat_4x8packed_ss_int(qw[0], sh_qa[t][0], raw); \
22
+ raw = dot_acc_sat_4x8packed_ss_int(qw[1], sh_qa[t][1], raw); \
23
+ raw = dot_acc_sat_4x8packed_ss_int(qw[2], sh_qa[t][2], raw); \
24
+ raw = dot_acc_sat_4x8packed_ss_int(qw[3], sh_qa[t][3], raw); \
25
+ raw = dot_acc_sat_4x8packed_ss_int(qw[4], sh_qa[t][4], raw); \
26
+ raw = dot_acc_sat_4x8packed_ss_int(qw[5], sh_qa[t][5], raw); \
27
+ raw = dot_acc_sat_4x8packed_ss_int(qw[6], sh_qa[t][6], raw); \
28
+ raw = dot_acc_sat_4x8packed_ss_int(qw[7], sh_qa[t][7], raw); \
29
+ acc[t] += d_val * ((float)sh_d[t] * (float)raw - 8.0f * (float)sh_s[t]); \
30
+ } while (0)
31
+
32
+ __attribute__((qcom_wave_pair_mode(1)))
33
+ kernel void kernel_gemm_moe_q4_0_q8_1_dp4a(
34
+ __read_only image1d_buffer_t src0_q, // q4_0 weights (transposed, packed nibbles)
35
+ __global half * src0_d, // per-32-block scale
36
+ __global uint * src1_qa, // q8_1 activations: int8 quants (as uint, 4/elem)
37
+ __global half * src1_da, // q8_1 per-block scale [tok_slot * ne00/32]
38
+ __global half * src1_sa, // q8_1 per-block sum*d [tok_slot * ne00/32]
39
+ __global uint * src2, // post-router (orig out positions)
40
+ __global ushort * src2_emap,// tile -> expert id
41
+ __write_only image1d_buffer_t dst,
42
+ __global int * total_tiles,
43
+ uint ne00,
44
+ uint ne01,
45
+ int is_ragged // 1: compute only real tokens per tile
46
+ ) {
47
+ const uint block_id_m = get_global_id(1); // m_tile
48
+ const uint block_id_n = get_global_id(2); // n_tile
49
+
50
+ if (block_id_n >= total_tiles[0]) {
51
+ return;
52
+ }
53
+
54
+ const uint lid = get_local_id(0); // 0..63, == this WI's output row in the M-tile
55
+
56
+ const ushort expert_id = src2_emap[block_id_n];
57
+ const uint row = block_id_m * TILESIZE_M;
58
+ const uint col = block_id_n * TILESIZE_N;
59
+
60
+ const uint num_blocks = ne00 >> 5; // blocks-of-32 per token
61
+ const uint row_idx = row + lid;
62
+
63
+ const uint ne00_u = ne00 >> 2; // ne00 in uint (int8x4) units
64
+
65
+ __local uint sh_qa[TILESIZE_N][8]; // 32 tokens x 8 uints (32 int8) = 1 KiB
66
+ __local half sh_d[TILESIZE_N];
67
+ __local half sh_s[TILESIZE_N];
68
+
69
+ // Real-token count for this tile
70
+ __local uint sh_src2[TILESIZE_N];
71
+ __local int sh_nreal;
72
+ if (lid < TILESIZE_N) {
73
+ sh_src2[lid] = src2[col + lid];
74
+ }
75
+ barrier(CLK_LOCAL_MEM_FENCE);
76
+ if (lid == 0) {
77
+ int nr = TILESIZE_N;
78
+ if (is_ragged) {
79
+ nr = 0;
80
+ #pragma unroll
81
+ for (int t = 0; t < TILESIZE_N; ++t) {
82
+ if (sh_src2[t] != 0xFFFFFFFFu) ++nr;
83
+ }
84
+ }
85
+ sh_nreal = nr;
86
+ }
87
+ barrier(CLK_LOCAL_MEM_FENCE);
88
+ const int n_real = sh_nreal;
89
+
90
+ float acc[TILESIZE_N];
91
+ #pragma unroll
92
+ for (int t = 0; t < TILESIZE_N; ++t) acc[t] = 0.0f;
93
+
94
+ for (uint step = 0; step < ne00; step += 32) {
95
+ const uint sub = step >> 5; // 32-block index along K
96
+
97
+ // per-32-block scale for this WI's row
98
+ const uint d_offset = row_idx + sub * ne01 + expert_id * num_blocks * ne01;
99
+ const float d_val = (float)src0_d[d_offset];
100
+
101
+ // repack this WI's 32 weight nibbles into 8 dp4a uints
102
+ const uint qoff0 = row + ((ne01 * step) >> 3) + ((expert_id * ne00 * ne01) >> 3);
103
+ const uint qoff1 = row + ((ne01 * (step + 16)) >> 3) + ((expert_id * ne00 * ne01) >> 3);
104
+ const uint r0 = read_imageui(src0_q, qoff0 + lid).x;
105
+ const uint r1 = read_imageui(src0_q, qoff0 + lid + ne01).x;
106
+ const uint r2 = read_imageui(src0_q, qoff1 + lid).x;
107
+ const uint r3 = read_imageui(src0_q, qoff1 + lid + ne01).x;
108
+ uint qw[8];
109
+ qw[0] = EXP4(r0); qw[1] = EXP4(r0 >> 16);
110
+ qw[2] = EXP4(r1); qw[3] = EXP4(r1 >> 16);
111
+ qw[4] = EXP4(r2); qw[5] = EXP4(r2 >> 16);
112
+ qw[6] = EXP4(r3); qw[7] = EXP4(r3 >> 16);
113
+
114
+ // cooperatively stage the n_real-token x 32-K int8 activations
115
+ const uint stage_lim = (uint)n_real * 8;
116
+ for (uint idx = lid; idx < stage_lim; idx += 64) {
117
+ const uint t = idx >> 3;
118
+ const uint u = idx & 7;
119
+ sh_qa[t][u] = src1_qa[(col + t) * ne00_u + (step >> 2) + u];
120
+ }
121
+ if (lid < (uint)n_real) {
122
+ sh_d[lid] = src1_da[(col + lid) * num_blocks + sub];
123
+ sh_s[lid] = src1_sa[(col + lid) * num_blocks + sub];
124
+ }
125
+ barrier(CLK_LOCAL_MEM_FENCE);
126
+
127
+ if (n_real == TILESIZE_N) {
128
+ #pragma unroll
129
+ for (int t = 0; t < TILESIZE_N; ++t) { MOE_Q40_DP4A_T(t); }
130
+ } else {
131
+ #pragma unroll 4
132
+ for (int t = 0; t < n_real; ++t) { MOE_Q40_DP4A_T(t); }
133
+ }
134
+ barrier(CLK_LOCAL_MEM_FENCE);
135
+ }
136
+
137
+ if (row_idx >= ne01) {
138
+ return;
139
+ }
140
+
141
+ // scatter results to original output rows (reuse sh_src2 from the top)
142
+ __local uint out_idx[TILESIZE_N];
143
+ if (lid < TILESIZE_N) {
144
+ uint idx = sh_src2[lid];
145
+ if (idx == 0xFFFFFFFF) {
146
+ idx = sh_src2[0];
147
+ }
148
+ out_idx[lid] = idx * ne01;
149
+ }
150
+ barrier(CLK_LOCAL_MEM_FENCE);
151
+
152
+ const uint m_offset = row + lid;
153
+ if (n_real == TILESIZE_N) {
154
+ #pragma unroll
155
+ for (int t = 1; t < TILESIZE_N; ++t) {
156
+ write_imagef(dst, out_idx[t] + m_offset, acc[t]);
157
+ }
158
+ barrier(CLK_GLOBAL_MEM_FENCE);
159
+ write_imagef(dst, out_idx[0] + m_offset, acc[0]);
160
+ } else {
161
+ for (int t = 0; t < n_real; ++t) {
162
+ write_imagef(dst, out_idx[t] + m_offset, acc[t]);
163
+ }
164
+ }
165
+ }
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_moe_q4_1_f32_ns.cl ADDED
@@ -0,0 +1,326 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #pragma OPENCL EXTENSION cl_khr_fp16 : enable
2
+ #pragma OPENCL EXTENSION cl_khr_subgroups : enable
3
+ #pragma OPENCL EXTENSION cl_qcom_subgroup_uniform_load: enable
4
+ #pragma OPENCL EXTENSION cl_qcom_subgroup_constant_load: enable
5
+ #pragma OPENCL EXTENSION cl_qcom_extra_vector_types : enable
6
+
7
+ #define TILESIZE_K 16
8
+ #define TILESIZE_M 64
9
+ #define TILESIZE_N 32
10
+
11
+
12
+ #define dequantize_q4_1(q4, a_f16, scale, m) \
13
+ a_f16.s0 = (half)(q4.s0 & 0x000F) * scale + m; \
14
+ a_f16.s1 = (half)((q4.s0 & 0x00F0) >> 4) * scale + m; \
15
+ a_f16.s2 = (half)((q4.s0 & 0x0F00) >> 8) * scale + m; \
16
+ a_f16.s3 = (half)((q4.s0 & 0xF000) >> 12) * scale + m; \
17
+ a_f16.s4 = (half)(q4.s1 & 0x000F) * scale + m; \
18
+ a_f16.s5 = (half)((q4.s1 & 0x00F0) >> 4) * scale + m; \
19
+ a_f16.s6 = (half)((q4.s1 & 0x0F00) >> 8) * scale + m; \
20
+ a_f16.s7 = (half)((q4.s1 & 0xF000) >> 12) * scale + m; \
21
+ a_f16.s8 = (half)(q4.s2 & 0x000F) * scale + m; \
22
+ a_f16.s9 = (half)((q4.s2 & 0x00F0) >> 4) * scale + m; \
23
+ a_f16.sa = (half)((q4.s2 & 0x0F00) >> 8) * scale + m; \
24
+ a_f16.sb = (half)((q4.s2 & 0xF000) >> 12) * scale + m; \
25
+ a_f16.sc = (half)(q4.s3 & 0x000F) * scale + m; \
26
+ a_f16.sd = (half)((q4.s3 & 0x00F0) >> 4) * scale + m; \
27
+ a_f16.se = (half)((q4.s3 & 0x0F00) >> 8) * scale + m; \
28
+ a_f16.sf = (half)((q4.s3 & 0xF000) >> 12) * scale + m; \
29
+
30
+
31
+ #define dotx16_reduce8(a_reg, b_lm, c_reg, lm_offset) \
32
+ acc.s0 = dot(a_reg.s0123, b_lm[lm_offset + 0]); \
33
+ acc.s1 = dot(a_reg.s0123, b_lm[lm_offset + 1]); \
34
+ acc.s2 = dot(a_reg.s0123, b_lm[lm_offset + 2]); \
35
+ acc.s3 = dot(a_reg.s0123, b_lm[lm_offset + 3]); \
36
+ acc.s4 = dot(a_reg.s0123, b_lm[lm_offset + 4]); \
37
+ acc.s5 = dot(a_reg.s0123, b_lm[lm_offset + 5]); \
38
+ acc.s6 = dot(a_reg.s0123, b_lm[lm_offset + 6]); \
39
+ acc.s7 = dot(a_reg.s0123, b_lm[lm_offset + 7]); \
40
+ acc.s8 = dot(a_reg.s0123, b_lm[lm_offset + 8]); \
41
+ acc.s9 = dot(a_reg.s0123, b_lm[lm_offset + 9]); \
42
+ acc.sa = dot(a_reg.s0123, b_lm[lm_offset + 10]); \
43
+ acc.sb = dot(a_reg.s0123, b_lm[lm_offset + 11]); \
44
+ acc.sc = dot(a_reg.s0123, b_lm[lm_offset + 12]); \
45
+ acc.sd = dot(a_reg.s0123, b_lm[lm_offset + 13]); \
46
+ acc.se = dot(a_reg.s0123, b_lm[lm_offset + 14]); \
47
+ acc.sf = dot(a_reg.s0123, b_lm[lm_offset + 15]); \
48
+ acc.s0 += dot(a_reg.s4567, b_lm[lm_offset + 32]); \
49
+ acc.s1 += dot(a_reg.s4567, b_lm[lm_offset + 33]); \
50
+ acc.s2 += dot(a_reg.s4567, b_lm[lm_offset + 34]); \
51
+ acc.s3 += dot(a_reg.s4567, b_lm[lm_offset + 35]); \
52
+ acc.s4 += dot(a_reg.s4567, b_lm[lm_offset + 36]); \
53
+ acc.s5 += dot(a_reg.s4567, b_lm[lm_offset + 37]); \
54
+ acc.s6 += dot(a_reg.s4567, b_lm[lm_offset + 38]); \
55
+ acc.s7 += dot(a_reg.s4567, b_lm[lm_offset + 39]); \
56
+ acc.s8 += dot(a_reg.s4567, b_lm[lm_offset + 40]); \
57
+ acc.s9 += dot(a_reg.s4567, b_lm[lm_offset + 41]); \
58
+ acc.sa += dot(a_reg.s4567, b_lm[lm_offset + 42]); \
59
+ acc.sb += dot(a_reg.s4567, b_lm[lm_offset + 43]); \
60
+ acc.sc += dot(a_reg.s4567, b_lm[lm_offset + 44]); \
61
+ acc.sd += dot(a_reg.s4567, b_lm[lm_offset + 45]); \
62
+ acc.se += dot(a_reg.s4567, b_lm[lm_offset + 46]); \
63
+ acc.sf += dot(a_reg.s4567, b_lm[lm_offset + 47]); \
64
+ c_reg.lo += convert_float8(acc.lo); \
65
+ c_reg.hi += convert_float8(acc.hi); \
66
+ acc.s0 = dot(a_reg.s89ab, b_lm[lm_offset + 64]); \
67
+ acc.s1 = dot(a_reg.s89ab, b_lm[lm_offset + 65]); \
68
+ acc.s2 = dot(a_reg.s89ab, b_lm[lm_offset + 66]); \
69
+ acc.s3 = dot(a_reg.s89ab, b_lm[lm_offset + 67]); \
70
+ acc.s4 = dot(a_reg.s89ab, b_lm[lm_offset + 68]); \
71
+ acc.s5 = dot(a_reg.s89ab, b_lm[lm_offset + 69]); \
72
+ acc.s6 = dot(a_reg.s89ab, b_lm[lm_offset + 70]); \
73
+ acc.s7 = dot(a_reg.s89ab, b_lm[lm_offset + 71]); \
74
+ acc.s8 = dot(a_reg.s89ab, b_lm[lm_offset + 72]); \
75
+ acc.s9 = dot(a_reg.s89ab, b_lm[lm_offset + 73]); \
76
+ acc.sa = dot(a_reg.s89ab, b_lm[lm_offset + 74]); \
77
+ acc.sb = dot(a_reg.s89ab, b_lm[lm_offset + 75]); \
78
+ acc.sc = dot(a_reg.s89ab, b_lm[lm_offset + 76]); \
79
+ acc.sd = dot(a_reg.s89ab, b_lm[lm_offset + 77]); \
80
+ acc.se = dot(a_reg.s89ab, b_lm[lm_offset + 78]); \
81
+ acc.sf = dot(a_reg.s89ab, b_lm[lm_offset + 79]); \
82
+ acc.s0 += dot(a_reg.scdef, b_lm[lm_offset + 96]); \
83
+ acc.s1 += dot(a_reg.scdef, b_lm[lm_offset + 97]); \
84
+ acc.s2 += dot(a_reg.scdef, b_lm[lm_offset + 98]); \
85
+ acc.s3 += dot(a_reg.scdef, b_lm[lm_offset + 99]); \
86
+ acc.s4 += dot(a_reg.scdef, b_lm[lm_offset + 100]); \
87
+ acc.s5 += dot(a_reg.scdef, b_lm[lm_offset + 101]); \
88
+ acc.s6 += dot(a_reg.scdef, b_lm[lm_offset + 102]); \
89
+ acc.s7 += dot(a_reg.scdef, b_lm[lm_offset + 103]); \
90
+ acc.s8 += dot(a_reg.scdef, b_lm[lm_offset + 104]); \
91
+ acc.s9 += dot(a_reg.scdef, b_lm[lm_offset + 105]); \
92
+ acc.sa += dot(a_reg.scdef, b_lm[lm_offset + 106]); \
93
+ acc.sb += dot(a_reg.scdef, b_lm[lm_offset + 107]); \
94
+ acc.sc += dot(a_reg.scdef, b_lm[lm_offset + 108]); \
95
+ acc.sd += dot(a_reg.scdef, b_lm[lm_offset + 109]); \
96
+ acc.se += dot(a_reg.scdef, b_lm[lm_offset + 110]); \
97
+ acc.sf += dot(a_reg.scdef, b_lm[lm_offset + 111]); \
98
+ c_reg.lo += convert_float8(acc.lo); \
99
+ c_reg.hi += convert_float8(acc.hi); \
100
+
101
+ // Quarter-tile variant: computes 8 output columns (one skip-group) into a float8
102
+ // accumulator. Same reduction order / flush cadence as dotx16_reduce8, so the
103
+ // non-skipped path is byte-identical; it just lets the caller skip empty
104
+ // 8-column groups at finer granularity. Uses a private half8 `acc8`.
105
+ #define dotx8_reduce4(a_reg, b_lm, c_reg, lm_offset) \
106
+ acc8.s0 = dot(a_reg.s0123, b_lm[lm_offset + 0]); \
107
+ acc8.s1 = dot(a_reg.s0123, b_lm[lm_offset + 1]); \
108
+ acc8.s2 = dot(a_reg.s0123, b_lm[lm_offset + 2]); \
109
+ acc8.s3 = dot(a_reg.s0123, b_lm[lm_offset + 3]); \
110
+ acc8.s4 = dot(a_reg.s0123, b_lm[lm_offset + 4]); \
111
+ acc8.s5 = dot(a_reg.s0123, b_lm[lm_offset + 5]); \
112
+ acc8.s6 = dot(a_reg.s0123, b_lm[lm_offset + 6]); \
113
+ acc8.s7 = dot(a_reg.s0123, b_lm[lm_offset + 7]); \
114
+ acc8.s0 += dot(a_reg.s4567, b_lm[lm_offset + 32]); \
115
+ acc8.s1 += dot(a_reg.s4567, b_lm[lm_offset + 33]); \
116
+ acc8.s2 += dot(a_reg.s4567, b_lm[lm_offset + 34]); \
117
+ acc8.s3 += dot(a_reg.s4567, b_lm[lm_offset + 35]); \
118
+ acc8.s4 += dot(a_reg.s4567, b_lm[lm_offset + 36]); \
119
+ acc8.s5 += dot(a_reg.s4567, b_lm[lm_offset + 37]); \
120
+ acc8.s6 += dot(a_reg.s4567, b_lm[lm_offset + 38]); \
121
+ acc8.s7 += dot(a_reg.s4567, b_lm[lm_offset + 39]); \
122
+ c_reg += convert_float8(acc8); \
123
+ acc8.s0 = dot(a_reg.s89ab, b_lm[lm_offset + 64]); \
124
+ acc8.s1 = dot(a_reg.s89ab, b_lm[lm_offset + 65]); \
125
+ acc8.s2 = dot(a_reg.s89ab, b_lm[lm_offset + 66]); \
126
+ acc8.s3 = dot(a_reg.s89ab, b_lm[lm_offset + 67]); \
127
+ acc8.s4 = dot(a_reg.s89ab, b_lm[lm_offset + 68]); \
128
+ acc8.s5 = dot(a_reg.s89ab, b_lm[lm_offset + 69]); \
129
+ acc8.s6 = dot(a_reg.s89ab, b_lm[lm_offset + 70]); \
130
+ acc8.s7 = dot(a_reg.s89ab, b_lm[lm_offset + 71]); \
131
+ acc8.s0 += dot(a_reg.scdef, b_lm[lm_offset + 96]); \
132
+ acc8.s1 += dot(a_reg.scdef, b_lm[lm_offset + 97]); \
133
+ acc8.s2 += dot(a_reg.scdef, b_lm[lm_offset + 98]); \
134
+ acc8.s3 += dot(a_reg.scdef, b_lm[lm_offset + 99]); \
135
+ acc8.s4 += dot(a_reg.scdef, b_lm[lm_offset + 100]); \
136
+ acc8.s5 += dot(a_reg.scdef, b_lm[lm_offset + 101]); \
137
+ acc8.s6 += dot(a_reg.scdef, b_lm[lm_offset + 102]); \
138
+ acc8.s7 += dot(a_reg.scdef, b_lm[lm_offset + 103]); \
139
+ c_reg += convert_float8(acc8); \
140
+
141
+
142
+ __attribute__((qcom_wave_pair_mode(1))) // 1=force single 2=force pair
143
+ kernel void kernel_gemm_moe_q4_1_f32_ns(
144
+ __read_only image1d_buffer_t src0_q,
145
+ __global half * src0_d,
146
+ __global half * src0_m,
147
+ __read_only image1d_buffer_t src1,
148
+ __global uint * src2,
149
+ __global ushort * src2_emap,
150
+ __write_only image1d_buffer_t dst,
151
+ __global int * total_tiles,
152
+ uint ne00,
153
+ uint ne01,
154
+ uint is_ragged,
155
+ uint skip_gran
156
+ ) {
157
+ uint block_id_m = get_global_id(1); // m_tile
158
+ uint block_id_n = get_global_id(2); // n_tile
159
+
160
+ // Boundary check
161
+ if (block_id_n >= total_tiles[0]) {
162
+ return;
163
+ }
164
+
165
+ // Ragged tile-skip: when is_ragged and the upper 16 token-slots of this tile are all
166
+ // padding (router 0xFFFFFFFF), skip the second (reg_c.hi) dotx16_reduce8 half -> ~half
167
+ // the GEMM dot for sparse tiles. Numerically identical (the skipped lanes are padding).
168
+ // Ragged tile-skip: tokens are packed contiguously per expert (moe_scatter fills
169
+ // lanes 0..V-1, moe_fill pre-pads the rest), so router padding (0xFFFFFFFF) is always
170
+ // trailing. Find the valid-token count V and round it UP to the skip granularity
171
+ // skip_gran (columns per skip-group: 8 = quarter, 16 = half/legacy, 32 = disabled).
172
+ // A 8-column group g is all-padding iff its first column (8*g) >= n_active, so its
173
+ // dotx8_reduce4 is skipped. Numerically identical (skipped lanes are padding).
174
+ uint n_active = TILESIZE_N;
175
+ if (is_ragged && skip_gran < TILESIZE_N) {
176
+ uint n_valid = TILESIZE_N;
177
+ for (uint _t = 0; _t < TILESIZE_N; ++_t) {
178
+ if (src2[block_id_n * TILESIZE_N + _t] == 0xFFFFFFFFu) { n_valid = _t; break; }
179
+ }
180
+ n_active = min((uint)TILESIZE_N, ((n_valid + skip_gran - 1) / skip_gran) * skip_gran);
181
+ }
182
+ // Group 0 (cols 0-7) always runs; groups 1-3 skip when fully padding.
183
+ bool skip_g1 = (8u >= n_active);
184
+ bool skip_g2 = (16u >= n_active);
185
+ bool skip_g3 = (24u >= n_active);
186
+
187
+ __private half16 reg_a;
188
+ __private float32 reg_c = (float32)(0);
189
+ __local half4 shared_b[128];
190
+
191
+ const ushort expert_id = src2_emap[block_id_n];
192
+
193
+ const uint row = block_id_m * TILESIZE_M;
194
+ const uint col = block_id_n * TILESIZE_N;
195
+
196
+ uint sub_block_id_m = get_local_id(0);
197
+ uint2 b_global_offset;
198
+ b_global_offset.x = ((sub_block_id_m & 3) << 2) + (sub_block_id_m >> 2) * ne00;
199
+ b_global_offset.y = b_global_offset.x + (16 * ne00);
200
+ uint2 b_local_offset;
201
+ b_local_offset.x = (sub_block_id_m & 3) * 32 + (sub_block_id_m >> 2);
202
+ b_local_offset.y = b_local_offset.x + 16;
203
+
204
+ // Loop along K axis, 32 elements (one block) for each iteration, divided into 2 sub-blocks
205
+ for (uint step = 0; step < ne00; step += TILESIZE_K * 2) {
206
+ // First sub-block
207
+ uint q_sub_offset = row + ((ne01 * step) >> 3) + ((expert_id * ne00 * ne01) >> 3);
208
+ uint s_sub_offset = row + ((ne01 * step) >> 5) + ((expert_id * ne00 * ne01) >> 5);
209
+ uint b_sub_offset = col * ne00 + step;
210
+
211
+ // Load scale and m for current Q4_1 block
212
+ uint sm_offset = s_sub_offset + get_global_id(0);
213
+ half s = src0_d[sm_offset];
214
+ half m = src0_m[sm_offset];
215
+
216
+ // Load 16 q (64-bits) in transposed layout
217
+ uint2 q4x16;
218
+ q4x16.x = read_imageui(src0_q, q_sub_offset + sub_block_id_m).x;
219
+ q4x16.y = read_imageui(src0_q, q_sub_offset + sub_block_id_m + ne01).x;
220
+
221
+ // Load 16x32 floats from matrix B, each fiber out of 64 in a sub-group loads 8 elements
222
+ float8 bx8_f32;
223
+ bx8_f32.lo = read_imagef(src1, (b_sub_offset + b_global_offset.x) / 4);
224
+ bx8_f32.hi = read_imagef(src1, (b_sub_offset + b_global_offset.y) / 4);
225
+ // Convert to half and store to LM to share within the subgroup
226
+ half8 bx8_f16 = convert_half8(bx8_f32);
227
+ shared_b[b_local_offset.x] = bx8_f16.lo;
228
+ shared_b[b_local_offset.y] = bx8_f16.hi;
229
+
230
+ // Dequantization
231
+ dequantize_q4_1(as_ushort4(q4x16), reg_a, s, m);
232
+
233
+ sub_group_barrier(CLK_LOCAL_MEM_FENCE);
234
+
235
+ // 32 16x16 fp16 dot product with 8 elements reduction for better precision
236
+ half8 acc8;
237
+ dotx8_reduce4(reg_a, shared_b, reg_c.lo.lo, 0);
238
+ if (!skip_g1) { dotx8_reduce4(reg_a, shared_b, reg_c.lo.hi, 8); }
239
+ if (!skip_g2) { dotx8_reduce4(reg_a, shared_b, reg_c.hi.lo, 16); }
240
+ if (!skip_g3) { dotx8_reduce4(reg_a, shared_b, reg_c.hi.hi, 24); }
241
+
242
+ // Repeat for second sub-block
243
+ uint half_step = step + TILESIZE_K;
244
+ q_sub_offset = row + ((ne01 * half_step) >> 3) + ((expert_id * ne00 * ne01) >> 3);
245
+ b_sub_offset = col * ne00 + half_step;
246
+
247
+ // Load next 16 q (64-bits) in transposed layout
248
+ q4x16.x = read_imageui(src0_q, q_sub_offset + sub_block_id_m).x;
249
+ q4x16.y = read_imageui(src0_q, q_sub_offset + sub_block_id_m + ne01).x;
250
+
251
+ // Load 16x32 floats from matrix B, each fiber out of 64 in a sub-group loads 8 elements
252
+ bx8_f32.lo = read_imagef(src1, (b_sub_offset + b_global_offset.x) / 4);
253
+ bx8_f32.hi = read_imagef(src1, (b_sub_offset + b_global_offset.y) / 4);
254
+ // Convert to half and store to LM to share within the subgroup
255
+ bx8_f16 = convert_half8(bx8_f32);
256
+ shared_b[b_local_offset.x] = bx8_f16.lo;
257
+ shared_b[b_local_offset.y] = bx8_f16.hi;
258
+
259
+ // Dequantization
260
+ dequantize_q4_1(as_ushort4(q4x16), reg_a, s, m);
261
+
262
+ sub_group_barrier(CLK_LOCAL_MEM_FENCE);
263
+
264
+ // 32 16x16 fp16 dot product with 3-levels reduction for better precision
265
+ dotx8_reduce4(reg_a, shared_b, reg_c.lo.lo, 0);
266
+ if (!skip_g1) { dotx8_reduce4(reg_a, shared_b, reg_c.lo.hi, 8); }
267
+ if (!skip_g2) { dotx8_reduce4(reg_a, shared_b, reg_c.hi.lo, 16); }
268
+ if (!skip_g3) { dotx8_reduce4(reg_a, shared_b, reg_c.hi.hi, 24); }
269
+ }
270
+
271
+ if ((get_global_id(0) + block_id_m * TILESIZE_M) >= ne01) {
272
+ return;
273
+ }
274
+
275
+ // Load poster router and share in LM
276
+ __local uint out_idx[TILESIZE_N];
277
+
278
+ if (get_local_id(0) < TILESIZE_N) {
279
+ uint idx = src2[block_id_n * TILESIZE_N + get_local_id(0)];
280
+ if (idx == 0xFFFFFFFF) {
281
+ idx = src2[block_id_n * TILESIZE_N + 0];
282
+ }
283
+ out_idx[get_local_id(0)] = idx * ne01;
284
+ }
285
+
286
+ barrier(CLK_LOCAL_MEM_FENCE);
287
+
288
+ // Scatter results back to original position in output grid
289
+ uint m_offset = row + get_local_id(0);
290
+
291
+ write_imagef(dst, out_idx[1] + m_offset, (reg_c.s1));
292
+ write_imagef(dst, out_idx[2] + m_offset, (reg_c.s2));
293
+ write_imagef(dst, out_idx[3] + m_offset, (reg_c.s3));
294
+ write_imagef(dst, out_idx[4] + m_offset, (reg_c.s4));
295
+ write_imagef(dst, out_idx[5] + m_offset, (reg_c.s5));
296
+ write_imagef(dst, out_idx[6] + m_offset, (reg_c.s6));
297
+ write_imagef(dst, out_idx[7] + m_offset, (reg_c.s7));
298
+ write_imagef(dst, out_idx[8] + m_offset, (reg_c.s8));
299
+ write_imagef(dst, out_idx[9] + m_offset, (reg_c.s9));
300
+ write_imagef(dst, out_idx[10] + m_offset, (reg_c.sa));
301
+ write_imagef(dst, out_idx[11] + m_offset, (reg_c.sb));
302
+ write_imagef(dst, out_idx[12] + m_offset, (reg_c.sc));
303
+ write_imagef(dst, out_idx[13] + m_offset, (reg_c.sd));
304
+ write_imagef(dst, out_idx[14] + m_offset, (reg_c.se));
305
+ write_imagef(dst, out_idx[15] + m_offset, (reg_c.sf));
306
+ write_imagef(dst, out_idx[16] + m_offset, (reg_c.sg));
307
+ write_imagef(dst, out_idx[17] + m_offset, (reg_c.sh));
308
+ write_imagef(dst, out_idx[18] + m_offset, (reg_c.si));
309
+ write_imagef(dst, out_idx[19] + m_offset, (reg_c.sj));
310
+ write_imagef(dst, out_idx[20] + m_offset, (reg_c.sk));
311
+ write_imagef(dst, out_idx[21] + m_offset, (reg_c.sl));
312
+ write_imagef(dst, out_idx[22] + m_offset, (reg_c.sm));
313
+ write_imagef(dst, out_idx[23] + m_offset, (reg_c.sn));
314
+ write_imagef(dst, out_idx[24] + m_offset, (reg_c.so));
315
+ write_imagef(dst, out_idx[25] + m_offset, (reg_c.sp));
316
+ write_imagef(dst, out_idx[26] + m_offset, (reg_c.sq));
317
+ write_imagef(dst, out_idx[27] + m_offset, (reg_c.sr));
318
+ write_imagef(dst, out_idx[28] + m_offset, (reg_c.ss));
319
+ write_imagef(dst, out_idx[29] + m_offset, (reg_c.st));
320
+ write_imagef(dst, out_idx[30] + m_offset, (reg_c.su));
321
+ write_imagef(dst, out_idx[31] + m_offset, (reg_c.sv));
322
+
323
+ // Store zero padding parts to the index of first output in tile, override correct result in the end
324
+ barrier(CLK_GLOBAL_MEM_FENCE);
325
+ write_imagef(dst, out_idx[0] + m_offset, (reg_c.s0));
326
+ }
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_moe_q4_k_f32_ns.cl ADDED
@@ -0,0 +1,348 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #pragma OPENCL EXTENSION cl_khr_fp16 : enable
2
+ #pragma OPENCL EXTENSION cl_khr_subgroups : enable
3
+ #pragma OPENCL EXTENSION cl_qcom_subgroup_uniform_load: enable
4
+ #pragma OPENCL EXTENSION cl_qcom_subgroup_constant_load: enable
5
+ #pragma OPENCL EXTENSION cl_qcom_extra_vector_types : enable
6
+
7
+ #define TILESIZE_K 16
8
+ #define TILESIZE_M 64
9
+ #define TILESIZE_N 32
10
+ #define QK_K 256
11
+ #define K_SCALE_SIZE 12
12
+
13
+ inline void get_scale_min_k4(
14
+ int j,
15
+ global const uchar * q,
16
+ uchar * d,
17
+ uchar * m
18
+ ) {
19
+ if (j < 4) {
20
+ *d = q[j] & 63;
21
+ *m = q[j+4] & 63;
22
+ } else {
23
+ *d = (q[j+4] & 0x0F) | ((q[j-4] & 0xC0) >> 2);
24
+ *m = ((q[j+4] >> 4) & 0x0F) | ((q[j] & 0xC0) >> 2);
25
+ }
26
+ }
27
+
28
+ #define dequantize_q4_k(q4, a_f16, scale, minv) \
29
+ a_f16.s0 = (half)((float)(q4.s0 & 0x000F) * scale - minv); \
30
+ a_f16.s1 = (half)((float)((q4.s0 & 0x00F0) >> 4) * scale - minv); \
31
+ a_f16.s2 = (half)((float)((q4.s0 & 0x0F00) >> 8) * scale - minv); \
32
+ a_f16.s3 = (half)((float)((q4.s0 & 0xF000) >> 12) * scale - minv); \
33
+ a_f16.s4 = (half)((float)(q4.s1 & 0x000F) * scale - minv); \
34
+ a_f16.s5 = (half)((float)((q4.s1 & 0x00F0) >> 4) * scale - minv); \
35
+ a_f16.s6 = (half)((float)((q4.s1 & 0x0F00) >> 8) * scale - minv); \
36
+ a_f16.s7 = (half)((float)((q4.s1 & 0xF000) >> 12) * scale - minv); \
37
+ a_f16.s8 = (half)((float)(q4.s2 & 0x000F) * scale - minv); \
38
+ a_f16.s9 = (half)((float)((q4.s2 & 0x00F0) >> 4) * scale - minv); \
39
+ a_f16.sa = (half)((float)((q4.s2 & 0x0F00) >> 8) * scale - minv); \
40
+ a_f16.sb = (half)((float)((q4.s2 & 0xF000) >> 12) * scale - minv); \
41
+ a_f16.sc = (half)((float)(q4.s3 & 0x000F) * scale - minv); \
42
+ a_f16.sd = (half)((float)((q4.s3 & 0x00F0) >> 4) * scale - minv); \
43
+ a_f16.se = (half)((float)((q4.s3 & 0x0F00) >> 8) * scale - minv); \
44
+ a_f16.sf = (half)((float)((q4.s3 & 0xF000) >> 12) * scale - minv); \
45
+
46
+
47
+ #define dotx16_reduce8(a_reg, b_lm, c_reg, lm_offset) \
48
+ acc.s0 = dot(a_reg.s0123, b_lm[lm_offset + 0]); \
49
+ acc.s1 = dot(a_reg.s0123, b_lm[lm_offset + 1]); \
50
+ acc.s2 = dot(a_reg.s0123, b_lm[lm_offset + 2]); \
51
+ acc.s3 = dot(a_reg.s0123, b_lm[lm_offset + 3]); \
52
+ acc.s4 = dot(a_reg.s0123, b_lm[lm_offset + 4]); \
53
+ acc.s5 = dot(a_reg.s0123, b_lm[lm_offset + 5]); \
54
+ acc.s6 = dot(a_reg.s0123, b_lm[lm_offset + 6]); \
55
+ acc.s7 = dot(a_reg.s0123, b_lm[lm_offset + 7]); \
56
+ acc.s8 = dot(a_reg.s0123, b_lm[lm_offset + 8]); \
57
+ acc.s9 = dot(a_reg.s0123, b_lm[lm_offset + 9]); \
58
+ acc.sa = dot(a_reg.s0123, b_lm[lm_offset + 10]); \
59
+ acc.sb = dot(a_reg.s0123, b_lm[lm_offset + 11]); \
60
+ acc.sc = dot(a_reg.s0123, b_lm[lm_offset + 12]); \
61
+ acc.sd = dot(a_reg.s0123, b_lm[lm_offset + 13]); \
62
+ acc.se = dot(a_reg.s0123, b_lm[lm_offset + 14]); \
63
+ acc.sf = dot(a_reg.s0123, b_lm[lm_offset + 15]); \
64
+ acc.s0 += dot(a_reg.s4567, b_lm[lm_offset + 32]); \
65
+ acc.s1 += dot(a_reg.s4567, b_lm[lm_offset + 33]); \
66
+ acc.s2 += dot(a_reg.s4567, b_lm[lm_offset + 34]); \
67
+ acc.s3 += dot(a_reg.s4567, b_lm[lm_offset + 35]); \
68
+ acc.s4 += dot(a_reg.s4567, b_lm[lm_offset + 36]); \
69
+ acc.s5 += dot(a_reg.s4567, b_lm[lm_offset + 37]); \
70
+ acc.s6 += dot(a_reg.s4567, b_lm[lm_offset + 38]); \
71
+ acc.s7 += dot(a_reg.s4567, b_lm[lm_offset + 39]); \
72
+ acc.s8 += dot(a_reg.s4567, b_lm[lm_offset + 40]); \
73
+ acc.s9 += dot(a_reg.s4567, b_lm[lm_offset + 41]); \
74
+ acc.sa += dot(a_reg.s4567, b_lm[lm_offset + 42]); \
75
+ acc.sb += dot(a_reg.s4567, b_lm[lm_offset + 43]); \
76
+ acc.sc += dot(a_reg.s4567, b_lm[lm_offset + 44]); \
77
+ acc.sd += dot(a_reg.s4567, b_lm[lm_offset + 45]); \
78
+ acc.se += dot(a_reg.s4567, b_lm[lm_offset + 46]); \
79
+ acc.sf += dot(a_reg.s4567, b_lm[lm_offset + 47]); \
80
+ c_reg.lo += convert_float8(acc.lo); \
81
+ c_reg.hi += convert_float8(acc.hi); \
82
+ acc.s0 = dot(a_reg.s89ab, b_lm[lm_offset + 64]); \
83
+ acc.s1 = dot(a_reg.s89ab, b_lm[lm_offset + 65]); \
84
+ acc.s2 = dot(a_reg.s89ab, b_lm[lm_offset + 66]); \
85
+ acc.s3 = dot(a_reg.s89ab, b_lm[lm_offset + 67]); \
86
+ acc.s4 = dot(a_reg.s89ab, b_lm[lm_offset + 68]); \
87
+ acc.s5 = dot(a_reg.s89ab, b_lm[lm_offset + 69]); \
88
+ acc.s6 = dot(a_reg.s89ab, b_lm[lm_offset + 70]); \
89
+ acc.s7 = dot(a_reg.s89ab, b_lm[lm_offset + 71]); \
90
+ acc.s8 = dot(a_reg.s89ab, b_lm[lm_offset + 72]); \
91
+ acc.s9 = dot(a_reg.s89ab, b_lm[lm_offset + 73]); \
92
+ acc.sa = dot(a_reg.s89ab, b_lm[lm_offset + 74]); \
93
+ acc.sb = dot(a_reg.s89ab, b_lm[lm_offset + 75]); \
94
+ acc.sc = dot(a_reg.s89ab, b_lm[lm_offset + 76]); \
95
+ acc.sd = dot(a_reg.s89ab, b_lm[lm_offset + 77]); \
96
+ acc.se = dot(a_reg.s89ab, b_lm[lm_offset + 78]); \
97
+ acc.sf = dot(a_reg.s89ab, b_lm[lm_offset + 79]); \
98
+ acc.s0 += dot(a_reg.scdef, b_lm[lm_offset + 96]); \
99
+ acc.s1 += dot(a_reg.scdef, b_lm[lm_offset + 97]); \
100
+ acc.s2 += dot(a_reg.scdef, b_lm[lm_offset + 98]); \
101
+ acc.s3 += dot(a_reg.scdef, b_lm[lm_offset + 99]); \
102
+ acc.s4 += dot(a_reg.scdef, b_lm[lm_offset + 100]); \
103
+ acc.s5 += dot(a_reg.scdef, b_lm[lm_offset + 101]); \
104
+ acc.s6 += dot(a_reg.scdef, b_lm[lm_offset + 102]); \
105
+ acc.s7 += dot(a_reg.scdef, b_lm[lm_offset + 103]); \
106
+ acc.s8 += dot(a_reg.scdef, b_lm[lm_offset + 104]); \
107
+ acc.s9 += dot(a_reg.scdef, b_lm[lm_offset + 105]); \
108
+ acc.sa += dot(a_reg.scdef, b_lm[lm_offset + 106]); \
109
+ acc.sb += dot(a_reg.scdef, b_lm[lm_offset + 107]); \
110
+ acc.sc += dot(a_reg.scdef, b_lm[lm_offset + 108]); \
111
+ acc.sd += dot(a_reg.scdef, b_lm[lm_offset + 109]); \
112
+ acc.se += dot(a_reg.scdef, b_lm[lm_offset + 110]); \
113
+ acc.sf += dot(a_reg.scdef, b_lm[lm_offset + 111]); \
114
+ c_reg.lo += convert_float8(acc.lo); \
115
+ c_reg.hi += convert_float8(acc.hi); \
116
+
117
+ // Quarter-tile variant: computes 8 output columns (one skip-group) into a float8
118
+ // accumulator. Same reduction order / flush cadence as dotx16_reduce8, so the
119
+ // non-skipped path is byte-identical; it just lets the caller skip empty
120
+ // 8-column groups at finer granularity. Uses a private half8 `acc8`.
121
+ #define dotx8_reduce4(a_reg, b_lm, c_reg, lm_offset) \
122
+ acc8.s0 = dot(a_reg.s0123, b_lm[lm_offset + 0]); \
123
+ acc8.s1 = dot(a_reg.s0123, b_lm[lm_offset + 1]); \
124
+ acc8.s2 = dot(a_reg.s0123, b_lm[lm_offset + 2]); \
125
+ acc8.s3 = dot(a_reg.s0123, b_lm[lm_offset + 3]); \
126
+ acc8.s4 = dot(a_reg.s0123, b_lm[lm_offset + 4]); \
127
+ acc8.s5 = dot(a_reg.s0123, b_lm[lm_offset + 5]); \
128
+ acc8.s6 = dot(a_reg.s0123, b_lm[lm_offset + 6]); \
129
+ acc8.s7 = dot(a_reg.s0123, b_lm[lm_offset + 7]); \
130
+ acc8.s0 += dot(a_reg.s4567, b_lm[lm_offset + 32]); \
131
+ acc8.s1 += dot(a_reg.s4567, b_lm[lm_offset + 33]); \
132
+ acc8.s2 += dot(a_reg.s4567, b_lm[lm_offset + 34]); \
133
+ acc8.s3 += dot(a_reg.s4567, b_lm[lm_offset + 35]); \
134
+ acc8.s4 += dot(a_reg.s4567, b_lm[lm_offset + 36]); \
135
+ acc8.s5 += dot(a_reg.s4567, b_lm[lm_offset + 37]); \
136
+ acc8.s6 += dot(a_reg.s4567, b_lm[lm_offset + 38]); \
137
+ acc8.s7 += dot(a_reg.s4567, b_lm[lm_offset + 39]); \
138
+ c_reg += convert_float8(acc8); \
139
+ acc8.s0 = dot(a_reg.s89ab, b_lm[lm_offset + 64]); \
140
+ acc8.s1 = dot(a_reg.s89ab, b_lm[lm_offset + 65]); \
141
+ acc8.s2 = dot(a_reg.s89ab, b_lm[lm_offset + 66]); \
142
+ acc8.s3 = dot(a_reg.s89ab, b_lm[lm_offset + 67]); \
143
+ acc8.s4 = dot(a_reg.s89ab, b_lm[lm_offset + 68]); \
144
+ acc8.s5 = dot(a_reg.s89ab, b_lm[lm_offset + 69]); \
145
+ acc8.s6 = dot(a_reg.s89ab, b_lm[lm_offset + 70]); \
146
+ acc8.s7 = dot(a_reg.s89ab, b_lm[lm_offset + 71]); \
147
+ acc8.s0 += dot(a_reg.scdef, b_lm[lm_offset + 96]); \
148
+ acc8.s1 += dot(a_reg.scdef, b_lm[lm_offset + 97]); \
149
+ acc8.s2 += dot(a_reg.scdef, b_lm[lm_offset + 98]); \
150
+ acc8.s3 += dot(a_reg.scdef, b_lm[lm_offset + 99]); \
151
+ acc8.s4 += dot(a_reg.scdef, b_lm[lm_offset + 100]); \
152
+ acc8.s5 += dot(a_reg.scdef, b_lm[lm_offset + 101]); \
153
+ acc8.s6 += dot(a_reg.scdef, b_lm[lm_offset + 102]); \
154
+ acc8.s7 += dot(a_reg.scdef, b_lm[lm_offset + 103]); \
155
+ c_reg += convert_float8(acc8); \
156
+
157
+
158
+ __attribute__((qcom_wave_pair_mode(1)))
159
+ kernel void kernel_gemm_moe_q4_k_f32_ns(
160
+ __read_only image1d_buffer_t src0_q,
161
+ __global half * src0_d,
162
+ __global half * src0_dm,
163
+ __global uchar * src0_s,
164
+ __read_only image1d_buffer_t src1,
165
+ __global uint * src2,
166
+ __global ushort * src2_emap,
167
+ __write_only image1d_buffer_t dst,
168
+ __global int * total_tiles,
169
+ uint ne00,
170
+ uint ne01,
171
+ uint is_ragged,
172
+ uint skip_gran
173
+ ) {
174
+ uint block_id_m = get_global_id(1); // m_tile
175
+ uint block_id_n = get_global_id(2); // n_tile
176
+
177
+ // Boundary check
178
+ if (block_id_n >= total_tiles[0]) {
179
+ return;
180
+ }
181
+
182
+ // Ragged tile-skip: tokens are packed contiguously per expert (moe_scatter fills
183
+ // lanes 0..V-1, moe_fill pre-pads the rest), so router padding (0xFFFFFFFF) is always
184
+ // trailing. Find the valid-token count V and round it UP to the skip granularity
185
+ // skip_gran (columns per skip-group: 8 = quarter, 16 = half/legacy, 32 = disabled).
186
+ // A 8-column group g is all-padding iff its first column (8*g) >= n_active, so its
187
+ // dotx8_reduce4 is skipped. Numerically identical (skipped lanes are padding).
188
+ uint n_active = TILESIZE_N;
189
+ if (is_ragged && skip_gran < TILESIZE_N) {
190
+ uint n_valid = TILESIZE_N;
191
+ for (uint _t = 0; _t < TILESIZE_N; ++_t) {
192
+ if (src2[block_id_n * TILESIZE_N + _t] == 0xFFFFFFFFu) { n_valid = _t; break; }
193
+ }
194
+ n_active = min((uint)TILESIZE_N, ((n_valid + skip_gran - 1) / skip_gran) * skip_gran);
195
+ }
196
+ // Group 0 (cols 0-7) always runs; groups 1-3 skip when fully padding.
197
+ bool skip_g1 = (8u >= n_active);
198
+ bool skip_g2 = (16u >= n_active);
199
+ bool skip_g3 = (24u >= n_active);
200
+
201
+ __private half16 reg_a;
202
+ __private float32 reg_c = (float32)(0);
203
+ __local half4 shared_b[128];
204
+
205
+ const ushort expert_id = src2_emap[block_id_n];
206
+
207
+ const uint row = block_id_m * TILESIZE_M;
208
+ const uint col = block_id_n * TILESIZE_N;
209
+
210
+ uint sub_block_id_m = get_local_id(0);
211
+ uint2 b_global_offset;
212
+ b_global_offset.x = ((sub_block_id_m & 3) << 2) + (sub_block_id_m >> 2) * ne00;
213
+ b_global_offset.y = b_global_offset.x + (16 * ne00);
214
+ uint2 b_local_offset;
215
+ b_local_offset.x = (sub_block_id_m & 3) * 32 + (sub_block_id_m >> 2);
216
+ b_local_offset.y = b_local_offset.x + 16;
217
+
218
+ uint num_superblocks = ne00 / QK_K;
219
+ uint scales_per_row = num_superblocks * K_SCALE_SIZE;
220
+ uint row_idx = row + get_global_id(0);
221
+
222
+ // Loop along K axis, 32 elements per iteration (one sub-block), divided into 2 halves of 16
223
+ for (uint step = 0; step < ne00; step += TILESIZE_K * 2) {
224
+ uint sub = step / 32;
225
+ uint sb = sub / 8;
226
+ uint j = sub % 8;
227
+
228
+ // Load d and dm for super-block
229
+ uint d_offset = row + sb * ne01 + expert_id * num_superblocks * ne01 + get_global_id(0);
230
+ half d_val = src0_d[d_offset];
231
+ half dm_val = src0_dm[d_offset];
232
+
233
+ // Load sub-block scale and min
234
+ global const uchar * sc = src0_s + (expert_id * ne01 + row_idx) * scales_per_row + sb * K_SCALE_SIZE;
235
+ uchar sv, mn;
236
+ get_scale_min_k4(j, sc, &sv, &mn);
237
+
238
+ float scale = (float)d_val * (float)sv;
239
+ float minv = (float)dm_val * (float)mn;
240
+
241
+ // First sub-block (16 elements)
242
+ uint q_sub_offset = row + ((ne01 * step) >> 3) + ((expert_id * ne00 * ne01) >> 3);
243
+ uint b_sub_offset = col * ne00 + step;
244
+
245
+ // Load 16 q (64-bits) in transposed layout
246
+ uint2 q4x16;
247
+ q4x16.x = read_imageui(src0_q, q_sub_offset + sub_block_id_m).x;
248
+ q4x16.y = read_imageui(src0_q, q_sub_offset + sub_block_id_m + ne01).x;
249
+
250
+ // Load 16x32 floats from matrix B
251
+ float8 bx8_f32;
252
+ bx8_f32.lo = read_imagef(src1, (b_sub_offset + b_global_offset.x) / 4);
253
+ bx8_f32.hi = read_imagef(src1, (b_sub_offset + b_global_offset.y) / 4);
254
+ half8 bx8_f16 = convert_half8(bx8_f32);
255
+ shared_b[b_local_offset.x] = bx8_f16.lo;
256
+ shared_b[b_local_offset.y] = bx8_f16.hi;
257
+
258
+ // Dequantization
259
+ dequantize_q4_k(as_ushort4(q4x16), reg_a, scale, minv);
260
+
261
+ sub_group_barrier(CLK_LOCAL_MEM_FENCE);
262
+
263
+ half8 acc8;
264
+ dotx8_reduce4(reg_a, shared_b, reg_c.lo.lo, 0);
265
+ if (!skip_g1) { dotx8_reduce4(reg_a, shared_b, reg_c.lo.hi, 8); }
266
+ if (!skip_g2) { dotx8_reduce4(reg_a, shared_b, reg_c.hi.lo, 16); }
267
+ if (!skip_g3) { dotx8_reduce4(reg_a, shared_b, reg_c.hi.hi, 24); }
268
+
269
+ // Second half (next 16 elements, same sub-block scale)
270
+ uint half_step = step + TILESIZE_K;
271
+ q_sub_offset = row + ((ne01 * half_step) >> 3) + ((expert_id * ne00 * ne01) >> 3);
272
+ b_sub_offset = col * ne00 + half_step;
273
+
274
+ q4x16.x = read_imageui(src0_q, q_sub_offset + sub_block_id_m).x;
275
+ q4x16.y = read_imageui(src0_q, q_sub_offset + sub_block_id_m + ne01).x;
276
+
277
+ bx8_f32.lo = read_imagef(src1, (b_sub_offset + b_global_offset.x) / 4);
278
+ bx8_f32.hi = read_imagef(src1, (b_sub_offset + b_global_offset.y) / 4);
279
+ bx8_f16 = convert_half8(bx8_f32);
280
+ shared_b[b_local_offset.x] = bx8_f16.lo;
281
+ shared_b[b_local_offset.y] = bx8_f16.hi;
282
+
283
+ dequantize_q4_k(as_ushort4(q4x16), reg_a, scale, minv);
284
+
285
+ sub_group_barrier(CLK_LOCAL_MEM_FENCE);
286
+
287
+ dotx8_reduce4(reg_a, shared_b, reg_c.lo.lo, 0);
288
+ if (!skip_g1) { dotx8_reduce4(reg_a, shared_b, reg_c.lo.hi, 8); }
289
+ if (!skip_g2) { dotx8_reduce4(reg_a, shared_b, reg_c.hi.lo, 16); }
290
+ if (!skip_g3) { dotx8_reduce4(reg_a, shared_b, reg_c.hi.hi, 24); }
291
+ }
292
+
293
+ if ((get_global_id(0) + block_id_m * TILESIZE_M) >= ne01) {
294
+ return;
295
+ }
296
+
297
+ // Load post router and share in LM
298
+ __local uint out_idx[TILESIZE_N];
299
+
300
+ if (get_local_id(0) < TILESIZE_N) {
301
+ uint idx = src2[block_id_n * TILESIZE_N + get_local_id(0)];
302
+ if (idx == 0xFFFFFFFF) {
303
+ idx = src2[block_id_n * TILESIZE_N + 0];
304
+ }
305
+ out_idx[get_local_id(0)] = idx * ne01;
306
+ }
307
+
308
+ barrier(CLK_LOCAL_MEM_FENCE);
309
+
310
+ // Scatter results back to original position in output grid
311
+ uint m_offset = row + get_local_id(0);
312
+
313
+ write_imagef(dst, out_idx[1] + m_offset, (reg_c.s1));
314
+ write_imagef(dst, out_idx[2] + m_offset, (reg_c.s2));
315
+ write_imagef(dst, out_idx[3] + m_offset, (reg_c.s3));
316
+ write_imagef(dst, out_idx[4] + m_offset, (reg_c.s4));
317
+ write_imagef(dst, out_idx[5] + m_offset, (reg_c.s5));
318
+ write_imagef(dst, out_idx[6] + m_offset, (reg_c.s6));
319
+ write_imagef(dst, out_idx[7] + m_offset, (reg_c.s7));
320
+ write_imagef(dst, out_idx[8] + m_offset, (reg_c.s8));
321
+ write_imagef(dst, out_idx[9] + m_offset, (reg_c.s9));
322
+ write_imagef(dst, out_idx[10] + m_offset, (reg_c.sa));
323
+ write_imagef(dst, out_idx[11] + m_offset, (reg_c.sb));
324
+ write_imagef(dst, out_idx[12] + m_offset, (reg_c.sc));
325
+ write_imagef(dst, out_idx[13] + m_offset, (reg_c.sd));
326
+ write_imagef(dst, out_idx[14] + m_offset, (reg_c.se));
327
+ write_imagef(dst, out_idx[15] + m_offset, (reg_c.sf));
328
+ write_imagef(dst, out_idx[16] + m_offset, (reg_c.sg));
329
+ write_imagef(dst, out_idx[17] + m_offset, (reg_c.sh));
330
+ write_imagef(dst, out_idx[18] + m_offset, (reg_c.si));
331
+ write_imagef(dst, out_idx[19] + m_offset, (reg_c.sj));
332
+ write_imagef(dst, out_idx[20] + m_offset, (reg_c.sk));
333
+ write_imagef(dst, out_idx[21] + m_offset, (reg_c.sl));
334
+ write_imagef(dst, out_idx[22] + m_offset, (reg_c.sm));
335
+ write_imagef(dst, out_idx[23] + m_offset, (reg_c.sn));
336
+ write_imagef(dst, out_idx[24] + m_offset, (reg_c.so));
337
+ write_imagef(dst, out_idx[25] + m_offset, (reg_c.sp));
338
+ write_imagef(dst, out_idx[26] + m_offset, (reg_c.sq));
339
+ write_imagef(dst, out_idx[27] + m_offset, (reg_c.sr));
340
+ write_imagef(dst, out_idx[28] + m_offset, (reg_c.ss));
341
+ write_imagef(dst, out_idx[29] + m_offset, (reg_c.st));
342
+ write_imagef(dst, out_idx[30] + m_offset, (reg_c.su));
343
+ write_imagef(dst, out_idx[31] + m_offset, (reg_c.sv));
344
+
345
+ // Store zero padding parts to the index of first output in tile
346
+ barrier(CLK_GLOBAL_MEM_FENCE);
347
+ write_imagef(dst, out_idx[0] + m_offset, (reg_c.s0));
348
+ }
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_moe_q4_k_q8_1_dp4a.cl ADDED
@@ -0,0 +1,202 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #pragma OPENCL EXTENSION cl_khr_fp16 : enable
2
+ #pragma OPENCL EXTENSION cl_khr_subgroups : enable
3
+ #ifdef cl_khr_integer_dot_product
4
+ #pragma OPENCL EXTENSION cl_khr_integer_dot_product : enable
5
+ #endif
6
+
7
+ // q4_K subblock (32 elems): w_i = scale*q_i - minv, q_i in [0,15], scale =
8
+ // d_super*sv6, minv = dmin_super*mn6. With activation block (a_d, a_s, qa[32]):
9
+ // Sum_i w_i * a_i = scale * a_d * dp4a(q, qa) - minv * a_s
10
+ // where a_s = a_d * Sum(qa) (the q8_1 "s" field)
11
+
12
+ #define TILESIZE_M 64
13
+ #define TILESIZE_N 32
14
+ #define QK_K 256
15
+ #define K_SCALE_SIZE 12
16
+
17
+ inline void get_scale_min_k4(
18
+ int j,
19
+ global const uchar * q,
20
+ uchar * d,
21
+ uchar * m
22
+ ) {
23
+ if (j < 4) {
24
+ *d = q[j] & 63;
25
+ *m = q[j+4] & 63;
26
+ } else {
27
+ *d = (q[j+4] & 0x0F) | ((q[j-4] & 0xC0) >> 2);
28
+ *m = ((q[j+4] >> 4) & 0x0F) | ((q[j] & 0xC0) >> 2);
29
+ }
30
+ }
31
+
32
+ // Expand the 4 nibbles held in the low 16 bits of `u` into 4 bytes (one nibble
33
+ // per byte, value 0..15), packed for the int8 dp4a.
34
+ #define EXP4(u) ( ((uint)((u) & 0x000Fu)) | \
35
+ (((uint)((u) & 0x00F0u)) << 4) | \
36
+ (((uint)((u) & 0x0F00u)) << 8) | \
37
+ (((uint)((u) & 0xF000u)) << 12) )
38
+
39
+ // One token's dp4a dot (8 uints = 32 K elems) + q4_K scale/min epilogue into acc[t].
40
+ #define MOE_Q4K_DP4A_T(t) do { \
41
+ int raw = 0; \
42
+ raw = dot_acc_sat_4x8packed_ss_int(qw[0], sh_qa[t][0], raw); \
43
+ raw = dot_acc_sat_4x8packed_ss_int(qw[1], sh_qa[t][1], raw); \
44
+ raw = dot_acc_sat_4x8packed_ss_int(qw[2], sh_qa[t][2], raw); \
45
+ raw = dot_acc_sat_4x8packed_ss_int(qw[3], sh_qa[t][3], raw); \
46
+ raw = dot_acc_sat_4x8packed_ss_int(qw[4], sh_qa[t][4], raw); \
47
+ raw = dot_acc_sat_4x8packed_ss_int(qw[5], sh_qa[t][5], raw); \
48
+ raw = dot_acc_sat_4x8packed_ss_int(qw[6], sh_qa[t][6], raw); \
49
+ raw = dot_acc_sat_4x8packed_ss_int(qw[7], sh_qa[t][7], raw); \
50
+ acc[t] += scale * (float)sh_d[t] * (float)raw - minv * (float)sh_s[t]; \
51
+ } while (0)
52
+
53
+ __attribute__((qcom_wave_pair_mode(1)))
54
+ kernel void kernel_gemm_moe_q4_k_q8_1_dp4a(
55
+ __read_only image1d_buffer_t src0_q, // q4_K weights (transposed, packed nibbles)
56
+ __global half * src0_d, // per-superblock scale
57
+ __global half * src0_dm, // per-superblock min
58
+ __global uchar * src0_s, // 6-bit scale/min codes
59
+ __global uint * src1_qa, // q8_1 activations: int8 quants (as uint, 4/elem)
60
+ __global half * src1_da, // q8_1 per-block scale [tok_slot * ne00/32]
61
+ __global half * src1_sa, // q8_1 per-block sum*d [tok_slot * ne00/32]
62
+ __global uint * src2, // post-router (orig out positions)
63
+ __global ushort * src2_emap,// tile -> expert id
64
+ __write_only image1d_buffer_t dst,
65
+ __global int * total_tiles,
66
+ uint ne00,
67
+ uint ne01,
68
+ int is_ragged // 1: compute only real tokens per tile
69
+ ) {
70
+ const uint block_id_m = get_global_id(1); // m_tile
71
+ const uint block_id_n = get_global_id(2); // n_tile
72
+
73
+ if (block_id_n >= total_tiles[0]) {
74
+ return;
75
+ }
76
+
77
+ const uint lid = get_local_id(0); // 0..63, == this WI's output row in the M-tile
78
+
79
+ const ushort expert_id = src2_emap[block_id_n];
80
+ const uint row = block_id_m * TILESIZE_M;
81
+ const uint col = block_id_n * TILESIZE_N;
82
+
83
+ const uint num_superblocks = ne00 / QK_K;
84
+ const uint scales_per_row = num_superblocks * K_SCALE_SIZE;
85
+ const uint row_idx = row + lid;
86
+
87
+ const uint ne00_u = ne00 >> 2; // ne00 in uint (int8x4) units
88
+ const uint ne00_b = ne00 >> 5; // blocks-of-32 per token
89
+
90
+ __local uint sh_qa[TILESIZE_N][8]; // 32 tokens x 8 uints (32 int8) = 1 KiB
91
+ __local half sh_d[TILESIZE_N];
92
+ __local half sh_s[TILESIZE_N];
93
+
94
+ // Real token count for this tile
95
+ __local uint sh_src2[TILESIZE_N];
96
+ __local int sh_nreal;
97
+ if (lid < TILESIZE_N) {
98
+ sh_src2[lid] = src2[col + lid];
99
+ }
100
+ barrier(CLK_LOCAL_MEM_FENCE);
101
+ if (lid == 0) {
102
+ int nr = TILESIZE_N;
103
+ if (is_ragged) {
104
+ nr = 0;
105
+ #pragma unroll
106
+ for (int t = 0; t < TILESIZE_N; ++t) {
107
+ if (sh_src2[t] != 0xFFFFFFFFu) ++nr;
108
+ }
109
+ }
110
+ sh_nreal = nr;
111
+ }
112
+ barrier(CLK_LOCAL_MEM_FENCE);
113
+ const int n_real = sh_nreal;
114
+
115
+ float acc[TILESIZE_N];
116
+ #pragma unroll
117
+ for (int t = 0; t < TILESIZE_N; ++t) acc[t] = 0.0f;
118
+
119
+ for (uint step = 0; step < ne00; step += 32) {
120
+ const uint sub = step >> 5; // subblock index along K
121
+ const uint sb = sub >> 3; // superblock index
122
+ const uint j = sub & 7; // subblock within superblock
123
+
124
+ // --- weight scale / min for this WI's row, this subblock ---
125
+ const uint d_offset = row + sb * ne01 + expert_id * num_superblocks * ne01 + lid;
126
+ const float d_val = (float)src0_d[d_offset];
127
+ const float dm_val = (float)src0_dm[d_offset];
128
+
129
+ global const uchar * sc = src0_s + (expert_id * ne01 + row_idx) * scales_per_row + sb * K_SCALE_SIZE;
130
+ uchar sv, mn;
131
+ get_scale_min_k4(j, sc, &sv, &mn);
132
+ const float scale = d_val * (float)sv;
133
+ const float minv = dm_val * (float)mn;
134
+
135
+ // --- repack this WI's 32 weight nibbles into 8 dp4a uints ---
136
+ const uint qoff0 = row + ((ne01 * step) >> 3) + ((expert_id * ne00 * ne01) >> 3);
137
+ const uint qoff1 = row + ((ne01 * (step + 16)) >> 3) + ((expert_id * ne00 * ne01) >> 3);
138
+ const uint r0 = read_imageui(src0_q, qoff0 + lid).x;
139
+ const uint r1 = read_imageui(src0_q, qoff0 + lid + ne01).x;
140
+ const uint r2 = read_imageui(src0_q, qoff1 + lid).x;
141
+ const uint r3 = read_imageui(src0_q, qoff1 + lid + ne01).x;
142
+ uint qw[8];
143
+ qw[0] = EXP4(r0); qw[1] = EXP4(r0 >> 16);
144
+ qw[2] = EXP4(r1); qw[3] = EXP4(r1 >> 16);
145
+ qw[4] = EXP4(r2); qw[5] = EXP4(r2 >> 16);
146
+ qw[6] = EXP4(r3); qw[7] = EXP4(r3 >> 16);
147
+
148
+ // --- cooperatively stage the n_real-token x 32-K int8 activations to LDS ---
149
+ const uint stage_lim = (uint)n_real * 8;
150
+ for (uint idx = lid; idx < stage_lim; idx += 64) {
151
+ const uint t = idx >> 3;
152
+ const uint u = idx & 7;
153
+ sh_qa[t][u] = src1_qa[(col + t) * ne00_u + (step >> 2) + u];
154
+ }
155
+ if (lid < (uint)n_real) {
156
+ sh_d[lid] = src1_da[(col + lid) * ne00_b + sub];
157
+ sh_s[lid] = src1_sa[(col + lid) * ne00_b + sub];
158
+ }
159
+ barrier(CLK_LOCAL_MEM_FENCE);
160
+
161
+ // dp4a - each real token sum over 8 uints (32 K), then scale/min
162
+ // Full tiles keep the fully-unrolled 32-wide loop;
163
+ // partial tiles run only n_real (saves the padded-slot dp4a + staging).
164
+ if (n_real == TILESIZE_N) {
165
+ #pragma unroll
166
+ for (int t = 0; t < TILESIZE_N; ++t) { MOE_Q4K_DP4A_T(t); }
167
+ } else {
168
+ #pragma unroll 4
169
+ for (int t = 0; t < n_real; ++t) { MOE_Q4K_DP4A_T(t); }
170
+ }
171
+ barrier(CLK_LOCAL_MEM_FENCE);
172
+ }
173
+
174
+ if (row_idx >= ne01) {
175
+ return;
176
+ }
177
+
178
+ // scatter results to original output rows
179
+ __local uint out_idx[TILESIZE_N];
180
+ if (lid < TILESIZE_N) {
181
+ uint idx = sh_src2[lid];
182
+ if (idx == 0xFFFFFFFF) {
183
+ idx = sh_src2[0];
184
+ }
185
+ out_idx[lid] = idx * ne01;
186
+ }
187
+ barrier(CLK_LOCAL_MEM_FENCE);
188
+
189
+ const uint m_offset = row + lid;
190
+ if (n_real == TILESIZE_N) {
191
+ #pragma unroll
192
+ for (int t = 1; t < TILESIZE_N; ++t) {
193
+ write_imagef(dst, out_idx[t] + m_offset, acc[t]);
194
+ }
195
+ barrier(CLK_GLOBAL_MEM_FENCE);
196
+ write_imagef(dst, out_idx[0] + m_offset, acc[0]);
197
+ } else {
198
+ for (int t = 0; t < n_real; ++t) {
199
+ write_imagef(dst, out_idx[t] + m_offset, acc[t]);
200
+ }
201
+ }
202
+ }
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_moe_q5_0_f32_ns.cl ADDED
@@ -0,0 +1,328 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #pragma OPENCL EXTENSION cl_khr_fp16 : enable
2
+ #pragma OPENCL EXTENSION cl_khr_subgroups : enable
3
+ #pragma OPENCL EXTENSION cl_qcom_subgroup_uniform_load: enable
4
+ #pragma OPENCL EXTENSION cl_qcom_subgroup_constant_load: enable
5
+ #pragma OPENCL EXTENSION cl_qcom_extra_vector_types : enable
6
+
7
+ #define TILESIZE_K 16
8
+ #define TILESIZE_M 64
9
+ #define TILESIZE_N 32
10
+
11
+
12
+ #define dequantize_q5_0(qs5x16, qh5x16, a_f16, scale) \
13
+ a_f16.s0 = (half)((( qs5x16.s0 & 0x000F) | (( qh5x16.s0 & 0x01) << 4)) - 16) * scale; \
14
+ a_f16.s1 = (half)((((qs5x16.s0 & 0x00F0) >> 4 ) | (((qh5x16.s0 >> 1) & 0x01) << 4)) - 16) * scale; \
15
+ a_f16.s2 = (half)((((qs5x16.s0 & 0x0F00) >> 8 ) | (((qh5x16.s0 >> 2) & 0x01) << 4)) - 16) * scale; \
16
+ a_f16.s3 = (half)((((qs5x16.s0 & 0xF000) >> 12) | (((qh5x16.s0 >> 3) & 0x01) << 4)) - 16) * scale; \
17
+ a_f16.s4 = (half)((( qs5x16.s1 & 0x000F) | (((qh5x16.s0 >> 4) & 0x01) << 4)) - 16) * scale; \
18
+ a_f16.s5 = (half)((((qs5x16.s1 & 0x00F0) >> 4 ) | (((qh5x16.s0 >> 5) & 0x01) << 4)) - 16) * scale; \
19
+ a_f16.s6 = (half)((((qs5x16.s1 & 0x0F00) >> 8 ) | (((qh5x16.s0 >> 6) & 0x01) << 4)) - 16) * scale; \
20
+ a_f16.s7 = (half)((((qs5x16.s1 & 0xF000) >> 12) | (((qh5x16.s0 >> 7) & 0x01) << 4)) - 16) * scale; \
21
+ a_f16.s8 = (half)((( qs5x16.s2 & 0x000F) | (( qh5x16.s1 & 0x01) << 4)) - 16) * scale; \
22
+ a_f16.s9 = (half)((((qs5x16.s2 & 0x00F0) >> 4 ) | (((qh5x16.s1 >> 1) & 0x01) << 4)) - 16) * scale; \
23
+ a_f16.sa = (half)((((qs5x16.s2 & 0x0F00) >> 8 ) | (((qh5x16.s1 >> 2) & 0x01) << 4)) - 16) * scale; \
24
+ a_f16.sb = (half)((((qs5x16.s2 & 0xF000) >> 12) | (((qh5x16.s1 >> 3) & 0x01) << 4)) - 16) * scale; \
25
+ a_f16.sc = (half)((( qs5x16.s3 & 0x000F) | (((qh5x16.s1 >> 4) & 0x01) << 4)) - 16) * scale; \
26
+ a_f16.sd = (half)((((qs5x16.s3 & 0x00F0) >> 4 ) | (((qh5x16.s1 >> 5) & 0x01) << 4)) - 16) * scale; \
27
+ a_f16.se = (half)((((qs5x16.s3 & 0x0F00) >> 8 ) | (((qh5x16.s1 >> 6) & 0x01) << 4)) - 16) * scale; \
28
+ a_f16.sf = (half)((((qs5x16.s3 & 0xF000) >> 12) | (((qh5x16.s1 >> 7) & 0x01) << 4)) - 16) * scale; \
29
+
30
+
31
+ #define dotx16_reduce8(a_reg, b_lm, c_reg, lm_offset) \
32
+ acc.s0 = dot(a_reg.s0123, b_lm[lm_offset + 0]); \
33
+ acc.s1 = dot(a_reg.s0123, b_lm[lm_offset + 1]); \
34
+ acc.s2 = dot(a_reg.s0123, b_lm[lm_offset + 2]); \
35
+ acc.s3 = dot(a_reg.s0123, b_lm[lm_offset + 3]); \
36
+ acc.s4 = dot(a_reg.s0123, b_lm[lm_offset + 4]); \
37
+ acc.s5 = dot(a_reg.s0123, b_lm[lm_offset + 5]); \
38
+ acc.s6 = dot(a_reg.s0123, b_lm[lm_offset + 6]); \
39
+ acc.s7 = dot(a_reg.s0123, b_lm[lm_offset + 7]); \
40
+ acc.s8 = dot(a_reg.s0123, b_lm[lm_offset + 8]); \
41
+ acc.s9 = dot(a_reg.s0123, b_lm[lm_offset + 9]); \
42
+ acc.sa = dot(a_reg.s0123, b_lm[lm_offset + 10]); \
43
+ acc.sb = dot(a_reg.s0123, b_lm[lm_offset + 11]); \
44
+ acc.sc = dot(a_reg.s0123, b_lm[lm_offset + 12]); \
45
+ acc.sd = dot(a_reg.s0123, b_lm[lm_offset + 13]); \
46
+ acc.se = dot(a_reg.s0123, b_lm[lm_offset + 14]); \
47
+ acc.sf = dot(a_reg.s0123, b_lm[lm_offset + 15]); \
48
+ acc.s0 += dot(a_reg.s4567, b_lm[lm_offset + 32]); \
49
+ acc.s1 += dot(a_reg.s4567, b_lm[lm_offset + 33]); \
50
+ acc.s2 += dot(a_reg.s4567, b_lm[lm_offset + 34]); \
51
+ acc.s3 += dot(a_reg.s4567, b_lm[lm_offset + 35]); \
52
+ acc.s4 += dot(a_reg.s4567, b_lm[lm_offset + 36]); \
53
+ acc.s5 += dot(a_reg.s4567, b_lm[lm_offset + 37]); \
54
+ acc.s6 += dot(a_reg.s4567, b_lm[lm_offset + 38]); \
55
+ acc.s7 += dot(a_reg.s4567, b_lm[lm_offset + 39]); \
56
+ acc.s8 += dot(a_reg.s4567, b_lm[lm_offset + 40]); \
57
+ acc.s9 += dot(a_reg.s4567, b_lm[lm_offset + 41]); \
58
+ acc.sa += dot(a_reg.s4567, b_lm[lm_offset + 42]); \
59
+ acc.sb += dot(a_reg.s4567, b_lm[lm_offset + 43]); \
60
+ acc.sc += dot(a_reg.s4567, b_lm[lm_offset + 44]); \
61
+ acc.sd += dot(a_reg.s4567, b_lm[lm_offset + 45]); \
62
+ acc.se += dot(a_reg.s4567, b_lm[lm_offset + 46]); \
63
+ acc.sf += dot(a_reg.s4567, b_lm[lm_offset + 47]); \
64
+ c_reg.lo += convert_float8(acc.lo); \
65
+ c_reg.hi += convert_float8(acc.hi); \
66
+ acc.s0 = dot(a_reg.s89ab, b_lm[lm_offset + 64]); \
67
+ acc.s1 = dot(a_reg.s89ab, b_lm[lm_offset + 65]); \
68
+ acc.s2 = dot(a_reg.s89ab, b_lm[lm_offset + 66]); \
69
+ acc.s3 = dot(a_reg.s89ab, b_lm[lm_offset + 67]); \
70
+ acc.s4 = dot(a_reg.s89ab, b_lm[lm_offset + 68]); \
71
+ acc.s5 = dot(a_reg.s89ab, b_lm[lm_offset + 69]); \
72
+ acc.s6 = dot(a_reg.s89ab, b_lm[lm_offset + 70]); \
73
+ acc.s7 = dot(a_reg.s89ab, b_lm[lm_offset + 71]); \
74
+ acc.s8 = dot(a_reg.s89ab, b_lm[lm_offset + 72]); \
75
+ acc.s9 = dot(a_reg.s89ab, b_lm[lm_offset + 73]); \
76
+ acc.sa = dot(a_reg.s89ab, b_lm[lm_offset + 74]); \
77
+ acc.sb = dot(a_reg.s89ab, b_lm[lm_offset + 75]); \
78
+ acc.sc = dot(a_reg.s89ab, b_lm[lm_offset + 76]); \
79
+ acc.sd = dot(a_reg.s89ab, b_lm[lm_offset + 77]); \
80
+ acc.se = dot(a_reg.s89ab, b_lm[lm_offset + 78]); \
81
+ acc.sf = dot(a_reg.s89ab, b_lm[lm_offset + 79]); \
82
+ acc.s0 += dot(a_reg.scdef, b_lm[lm_offset + 96]); \
83
+ acc.s1 += dot(a_reg.scdef, b_lm[lm_offset + 97]); \
84
+ acc.s2 += dot(a_reg.scdef, b_lm[lm_offset + 98]); \
85
+ acc.s3 += dot(a_reg.scdef, b_lm[lm_offset + 99]); \
86
+ acc.s4 += dot(a_reg.scdef, b_lm[lm_offset + 100]); \
87
+ acc.s5 += dot(a_reg.scdef, b_lm[lm_offset + 101]); \
88
+ acc.s6 += dot(a_reg.scdef, b_lm[lm_offset + 102]); \
89
+ acc.s7 += dot(a_reg.scdef, b_lm[lm_offset + 103]); \
90
+ acc.s8 += dot(a_reg.scdef, b_lm[lm_offset + 104]); \
91
+ acc.s9 += dot(a_reg.scdef, b_lm[lm_offset + 105]); \
92
+ acc.sa += dot(a_reg.scdef, b_lm[lm_offset + 106]); \
93
+ acc.sb += dot(a_reg.scdef, b_lm[lm_offset + 107]); \
94
+ acc.sc += dot(a_reg.scdef, b_lm[lm_offset + 108]); \
95
+ acc.sd += dot(a_reg.scdef, b_lm[lm_offset + 109]); \
96
+ acc.se += dot(a_reg.scdef, b_lm[lm_offset + 110]); \
97
+ acc.sf += dot(a_reg.scdef, b_lm[lm_offset + 111]); \
98
+ c_reg.lo += convert_float8(acc.lo); \
99
+ c_reg.hi += convert_float8(acc.hi); \
100
+
101
+ // Quarter-tile variant: computes 8 output columns (one skip-group) into a float8
102
+ // accumulator. Same reduction order / flush cadence as dotx16_reduce8, so the
103
+ // non-skipped path is byte-identical; it just lets the caller skip empty
104
+ // 8-column groups at finer granularity. Uses a private half8 `acc8`.
105
+ #define dotx8_reduce4(a_reg, b_lm, c_reg, lm_offset) \
106
+ acc8.s0 = dot(a_reg.s0123, b_lm[lm_offset + 0]); \
107
+ acc8.s1 = dot(a_reg.s0123, b_lm[lm_offset + 1]); \
108
+ acc8.s2 = dot(a_reg.s0123, b_lm[lm_offset + 2]); \
109
+ acc8.s3 = dot(a_reg.s0123, b_lm[lm_offset + 3]); \
110
+ acc8.s4 = dot(a_reg.s0123, b_lm[lm_offset + 4]); \
111
+ acc8.s5 = dot(a_reg.s0123, b_lm[lm_offset + 5]); \
112
+ acc8.s6 = dot(a_reg.s0123, b_lm[lm_offset + 6]); \
113
+ acc8.s7 = dot(a_reg.s0123, b_lm[lm_offset + 7]); \
114
+ acc8.s0 += dot(a_reg.s4567, b_lm[lm_offset + 32]); \
115
+ acc8.s1 += dot(a_reg.s4567, b_lm[lm_offset + 33]); \
116
+ acc8.s2 += dot(a_reg.s4567, b_lm[lm_offset + 34]); \
117
+ acc8.s3 += dot(a_reg.s4567, b_lm[lm_offset + 35]); \
118
+ acc8.s4 += dot(a_reg.s4567, b_lm[lm_offset + 36]); \
119
+ acc8.s5 += dot(a_reg.s4567, b_lm[lm_offset + 37]); \
120
+ acc8.s6 += dot(a_reg.s4567, b_lm[lm_offset + 38]); \
121
+ acc8.s7 += dot(a_reg.s4567, b_lm[lm_offset + 39]); \
122
+ c_reg += convert_float8(acc8); \
123
+ acc8.s0 = dot(a_reg.s89ab, b_lm[lm_offset + 64]); \
124
+ acc8.s1 = dot(a_reg.s89ab, b_lm[lm_offset + 65]); \
125
+ acc8.s2 = dot(a_reg.s89ab, b_lm[lm_offset + 66]); \
126
+ acc8.s3 = dot(a_reg.s89ab, b_lm[lm_offset + 67]); \
127
+ acc8.s4 = dot(a_reg.s89ab, b_lm[lm_offset + 68]); \
128
+ acc8.s5 = dot(a_reg.s89ab, b_lm[lm_offset + 69]); \
129
+ acc8.s6 = dot(a_reg.s89ab, b_lm[lm_offset + 70]); \
130
+ acc8.s7 = dot(a_reg.s89ab, b_lm[lm_offset + 71]); \
131
+ acc8.s0 += dot(a_reg.scdef, b_lm[lm_offset + 96]); \
132
+ acc8.s1 += dot(a_reg.scdef, b_lm[lm_offset + 97]); \
133
+ acc8.s2 += dot(a_reg.scdef, b_lm[lm_offset + 98]); \
134
+ acc8.s3 += dot(a_reg.scdef, b_lm[lm_offset + 99]); \
135
+ acc8.s4 += dot(a_reg.scdef, b_lm[lm_offset + 100]); \
136
+ acc8.s5 += dot(a_reg.scdef, b_lm[lm_offset + 101]); \
137
+ acc8.s6 += dot(a_reg.scdef, b_lm[lm_offset + 102]); \
138
+ acc8.s7 += dot(a_reg.scdef, b_lm[lm_offset + 103]); \
139
+ c_reg += convert_float8(acc8); \
140
+
141
+
142
+ __attribute__((qcom_wave_pair_mode(1))) // 1=force single 2=force pair
143
+ kernel void kernel_gemm_moe_q5_0_f32_ns(
144
+ __read_only image1d_buffer_t src0_qs,
145
+ __global uint * src0_qh,
146
+ __global half * src0_d,
147
+ __read_only image1d_buffer_t src1,
148
+ __global uint * src2,
149
+ __global ushort * src2_emap,
150
+ __write_only image1d_buffer_t dst,
151
+ __global int * total_tiles,
152
+ uint ne00,
153
+ uint ne01,
154
+ uint is_ragged,
155
+ uint skip_gran
156
+ ) {
157
+ uint block_id_m = get_global_id(1); // m_tile
158
+ uint block_id_n = get_global_id(2); // n_tile
159
+
160
+ // Boundary check
161
+ if (block_id_n >= total_tiles[0]) {
162
+ return;
163
+ }
164
+
165
+ // Ragged tile-skip: when is_ragged and the upper 16 token-slots of this tile are all
166
+ // padding (router 0xFFFFFFFF), skip the second (reg_c.hi) dotx16_reduce8 half -> ~half
167
+ // the GEMM dot for sparse tiles. Numerically identical (the skipped lanes are padding).
168
+ // Ragged tile-skip: tokens are packed contiguously per expert (moe_scatter fills
169
+ // lanes 0..V-1, moe_fill pre-pads the rest), so router padding (0xFFFFFFFF) is always
170
+ // trailing. Find the valid-token count V and round it UP to the skip granularity
171
+ // skip_gran (columns per skip-group: 8 = quarter, 16 = half/legacy, 32 = disabled).
172
+ // A 8-column group g is all-padding iff its first column (8*g) >= n_active, so its
173
+ // dotx8_reduce4 is skipped. Numerically identical (skipped lanes are padding).
174
+ uint n_active = TILESIZE_N;
175
+ if (is_ragged && skip_gran < TILESIZE_N) {
176
+ uint n_valid = TILESIZE_N;
177
+ for (uint _t = 0; _t < TILESIZE_N; ++_t) {
178
+ if (src2[block_id_n * TILESIZE_N + _t] == 0xFFFFFFFFu) { n_valid = _t; break; }
179
+ }
180
+ n_active = min((uint)TILESIZE_N, ((n_valid + skip_gran - 1) / skip_gran) * skip_gran);
181
+ }
182
+ // Group 0 (cols 0-7) always runs; groups 1-3 skip when fully padding.
183
+ bool skip_g1 = (8u >= n_active);
184
+ bool skip_g2 = (16u >= n_active);
185
+ bool skip_g3 = (24u >= n_active);
186
+
187
+ __private half16 reg_a;
188
+ __private float32 reg_c = (float32)(0);
189
+ __local half4 shared_b[128];
190
+
191
+ const ushort expert_id = src2_emap[block_id_n];
192
+
193
+ const uint row = block_id_m * TILESIZE_M;
194
+ const uint col = block_id_n * TILESIZE_N;
195
+
196
+ uint sub_block_id_m = get_local_id(0);
197
+ uint2 b_global_offset;
198
+ b_global_offset.x = ((sub_block_id_m & 3) << 2) + (sub_block_id_m >> 2) * ne00;
199
+ b_global_offset.y = b_global_offset.x + (16 * ne00);
200
+ uint2 b_local_offset;
201
+ b_local_offset.x = (sub_block_id_m & 3) * 32 + (sub_block_id_m >> 2);
202
+ b_local_offset.y = b_local_offset.x + 16;
203
+
204
+ // Loop along K axis, 32 elements (one block) for each iteration, divided into 2 sub-blocks
205
+ for (uint step = 0; step < ne00; step += TILESIZE_K * 2) {
206
+ // First sub-block
207
+ uint q_sub_offset = row + ((ne01 * step) >> 3) + ((expert_id * ne00 * ne01) >> 3);
208
+ uint s_sub_offset = row + ((ne01 * step) >> 5) + ((expert_id * ne00 * ne01) >> 5);
209
+ uint b_sub_offset = col * ne00 + step;
210
+
211
+ // Load scale for current Q5_0 block
212
+ uint blk_offset = s_sub_offset + get_global_id(0);
213
+ half s = src0_d[blk_offset];
214
+
215
+ // Load 32 qh (5-th bit of each Q5) for the entire block
216
+ uchar4 qhx32 = as_uchar4(src0_qh[blk_offset]);
217
+
218
+ // Load 16 qs (half block) in transposed layout
219
+ uint2 qsx16;
220
+ qsx16.x = read_imageui(src0_qs, q_sub_offset + sub_block_id_m).x;
221
+ qsx16.y = read_imageui(src0_qs, q_sub_offset + sub_block_id_m + ne01).x;
222
+
223
+ // Load 16x32 floats from matrix B, each fiber out of 64 in a sub-group loads 8 elements
224
+ float8 bx8_f32;
225
+ bx8_f32.lo = read_imagef(src1, (b_sub_offset + b_global_offset.x) / 4);
226
+ bx8_f32.hi = read_imagef(src1, (b_sub_offset + b_global_offset.y) / 4);
227
+ // Convert to half and store to LM to share within the subgroup
228
+ half8 bx8_f16 = convert_half8(bx8_f32);
229
+ shared_b[b_local_offset.x] = bx8_f16.lo;
230
+ shared_b[b_local_offset.y] = bx8_f16.hi;
231
+
232
+ // Dequantization
233
+ dequantize_q5_0(as_ushort4(qsx16), qhx32.lo, reg_a, s);
234
+
235
+ sub_group_barrier(CLK_LOCAL_MEM_FENCE);
236
+
237
+ // 32 16x16 fp16 dot product with 8 elements reduction for better precision
238
+ half8 acc8;
239
+ dotx8_reduce4(reg_a, shared_b, reg_c.lo.lo, 0);
240
+ if (!skip_g1) { dotx8_reduce4(reg_a, shared_b, reg_c.lo.hi, 8); }
241
+ if (!skip_g2) { dotx8_reduce4(reg_a, shared_b, reg_c.hi.lo, 16); }
242
+ if (!skip_g3) { dotx8_reduce4(reg_a, shared_b, reg_c.hi.hi, 24); }
243
+
244
+ // Repeat for second sub-block
245
+ uint half_step = step + TILESIZE_K;
246
+ q_sub_offset = row + ((ne01 * half_step) >> 3) + ((expert_id * ne00 * ne01) >> 3);
247
+ b_sub_offset = col * ne00 + half_step;
248
+
249
+ // Load next 16 qs in transposed layout
250
+ qsx16.x = read_imageui(src0_qs, q_sub_offset + sub_block_id_m).x;
251
+ qsx16.y = read_imageui(src0_qs, q_sub_offset + sub_block_id_m + ne01).x;
252
+
253
+ // Load 16x32 floats from matrix B, each fiber out of 64 in a sub-group loads 8 elements
254
+ bx8_f32.lo = read_imagef(src1, (b_sub_offset + b_global_offset.x) / 4);
255
+ bx8_f32.hi = read_imagef(src1, (b_sub_offset + b_global_offset.y) / 4);
256
+ // Convert to half and store to LM to share within the subgroup
257
+ bx8_f16 = convert_half8(bx8_f32);
258
+ shared_b[b_local_offset.x] = bx8_f16.lo;
259
+ shared_b[b_local_offset.y] = bx8_f16.hi;
260
+
261
+ // Dequantization
262
+ dequantize_q5_0(as_ushort4(qsx16), qhx32.hi, reg_a, s);
263
+
264
+ sub_group_barrier(CLK_LOCAL_MEM_FENCE);
265
+
266
+ // 32 16x16 fp16 dot product with 3-levels reduction for better precision
267
+ dotx8_reduce4(reg_a, shared_b, reg_c.lo.lo, 0);
268
+ if (!skip_g1) { dotx8_reduce4(reg_a, shared_b, reg_c.lo.hi, 8); }
269
+ if (!skip_g2) { dotx8_reduce4(reg_a, shared_b, reg_c.hi.lo, 16); }
270
+ if (!skip_g3) { dotx8_reduce4(reg_a, shared_b, reg_c.hi.hi, 24); }
271
+ }
272
+
273
+ if ((get_global_id(0) + block_id_m * TILESIZE_M) >= ne01) {
274
+ return;
275
+ }
276
+
277
+ // Load poster router and share in LM
278
+ __local uint out_idx[TILESIZE_N];
279
+
280
+ if (get_local_id(0) < TILESIZE_N) {
281
+ uint idx = src2[block_id_n * TILESIZE_N + get_local_id(0)];
282
+ if (idx == 0xFFFFFFFF) {
283
+ idx = src2[block_id_n * TILESIZE_N + 0];
284
+ }
285
+ out_idx[get_local_id(0)] = idx * ne01;
286
+ }
287
+
288
+ barrier(CLK_LOCAL_MEM_FENCE);
289
+
290
+ // Scatter results back to original position in output grid
291
+ uint m_offset = row + get_local_id(0);
292
+
293
+ write_imagef(dst, out_idx[1] + m_offset, (reg_c.s1));
294
+ write_imagef(dst, out_idx[2] + m_offset, (reg_c.s2));
295
+ write_imagef(dst, out_idx[3] + m_offset, (reg_c.s3));
296
+ write_imagef(dst, out_idx[4] + m_offset, (reg_c.s4));
297
+ write_imagef(dst, out_idx[5] + m_offset, (reg_c.s5));
298
+ write_imagef(dst, out_idx[6] + m_offset, (reg_c.s6));
299
+ write_imagef(dst, out_idx[7] + m_offset, (reg_c.s7));
300
+ write_imagef(dst, out_idx[8] + m_offset, (reg_c.s8));
301
+ write_imagef(dst, out_idx[9] + m_offset, (reg_c.s9));
302
+ write_imagef(dst, out_idx[10] + m_offset, (reg_c.sa));
303
+ write_imagef(dst, out_idx[11] + m_offset, (reg_c.sb));
304
+ write_imagef(dst, out_idx[12] + m_offset, (reg_c.sc));
305
+ write_imagef(dst, out_idx[13] + m_offset, (reg_c.sd));
306
+ write_imagef(dst, out_idx[14] + m_offset, (reg_c.se));
307
+ write_imagef(dst, out_idx[15] + m_offset, (reg_c.sf));
308
+ write_imagef(dst, out_idx[16] + m_offset, (reg_c.sg));
309
+ write_imagef(dst, out_idx[17] + m_offset, (reg_c.sh));
310
+ write_imagef(dst, out_idx[18] + m_offset, (reg_c.si));
311
+ write_imagef(dst, out_idx[19] + m_offset, (reg_c.sj));
312
+ write_imagef(dst, out_idx[20] + m_offset, (reg_c.sk));
313
+ write_imagef(dst, out_idx[21] + m_offset, (reg_c.sl));
314
+ write_imagef(dst, out_idx[22] + m_offset, (reg_c.sm));
315
+ write_imagef(dst, out_idx[23] + m_offset, (reg_c.sn));
316
+ write_imagef(dst, out_idx[24] + m_offset, (reg_c.so));
317
+ write_imagef(dst, out_idx[25] + m_offset, (reg_c.sp));
318
+ write_imagef(dst, out_idx[26] + m_offset, (reg_c.sq));
319
+ write_imagef(dst, out_idx[27] + m_offset, (reg_c.sr));
320
+ write_imagef(dst, out_idx[28] + m_offset, (reg_c.ss));
321
+ write_imagef(dst, out_idx[29] + m_offset, (reg_c.st));
322
+ write_imagef(dst, out_idx[30] + m_offset, (reg_c.su));
323
+ write_imagef(dst, out_idx[31] + m_offset, (reg_c.sv));
324
+
325
+ // Store zero padding parts to the index of first output in tile, override correct result in the end
326
+ barrier(CLK_GLOBAL_MEM_FENCE);
327
+ write_imagef(dst, out_idx[0] + m_offset, (reg_c.s0));
328
+ }
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_moe_q5_1_f32_ns.cl ADDED
@@ -0,0 +1,330 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #pragma OPENCL EXTENSION cl_khr_fp16 : enable
2
+ #pragma OPENCL EXTENSION cl_khr_subgroups : enable
3
+ #pragma OPENCL EXTENSION cl_qcom_subgroup_uniform_load: enable
4
+ #pragma OPENCL EXTENSION cl_qcom_subgroup_constant_load: enable
5
+ #pragma OPENCL EXTENSION cl_qcom_extra_vector_types : enable
6
+
7
+ #define TILESIZE_K 16
8
+ #define TILESIZE_M 64
9
+ #define TILESIZE_N 32
10
+
11
+
12
+ #define dequantize_q5_1(qs5x16, qh5x16, a_f16, scale, m) \
13
+ a_f16.s0 = (half)((( qs5x16.s0 & 0x000F) | (( qh5x16.s0 & 0x01) << 4)) * scale + m); \
14
+ a_f16.s1 = (half)((((qs5x16.s0 & 0x00F0) >> 4 ) | (((qh5x16.s0 >> 1) & 0x01) << 4)) * scale + m); \
15
+ a_f16.s2 = (half)((((qs5x16.s0 & 0x0F00) >> 8 ) | (((qh5x16.s0 >> 2) & 0x01) << 4)) * scale + m); \
16
+ a_f16.s3 = (half)((((qs5x16.s0 & 0xF000) >> 12) | (((qh5x16.s0 >> 3) & 0x01) << 4)) * scale + m); \
17
+ a_f16.s4 = (half)((( qs5x16.s1 & 0x000F) | (((qh5x16.s0 >> 4) & 0x01) << 4)) * scale + m); \
18
+ a_f16.s5 = (half)((((qs5x16.s1 & 0x00F0) >> 4 ) | (((qh5x16.s0 >> 5) & 0x01) << 4)) * scale + m); \
19
+ a_f16.s6 = (half)((((qs5x16.s1 & 0x0F00) >> 8 ) | (((qh5x16.s0 >> 6) & 0x01) << 4)) * scale + m); \
20
+ a_f16.s7 = (half)((((qs5x16.s1 & 0xF000) >> 12) | (((qh5x16.s0 >> 7) & 0x01) << 4)) * scale + m); \
21
+ a_f16.s8 = (half)((( qs5x16.s2 & 0x000F) | (( qh5x16.s1 & 0x01) << 4)) * scale + m); \
22
+ a_f16.s9 = (half)((((qs5x16.s2 & 0x00F0) >> 4 ) | (((qh5x16.s1 >> 1) & 0x01) << 4)) * scale + m); \
23
+ a_f16.sa = (half)((((qs5x16.s2 & 0x0F00) >> 8 ) | (((qh5x16.s1 >> 2) & 0x01) << 4)) * scale + m); \
24
+ a_f16.sb = (half)((((qs5x16.s2 & 0xF000) >> 12) | (((qh5x16.s1 >> 3) & 0x01) << 4)) * scale + m); \
25
+ a_f16.sc = (half)((( qs5x16.s3 & 0x000F) | (((qh5x16.s1 >> 4) & 0x01) << 4)) * scale + m); \
26
+ a_f16.sd = (half)((((qs5x16.s3 & 0x00F0) >> 4 ) | (((qh5x16.s1 >> 5) & 0x01) << 4)) * scale + m); \
27
+ a_f16.se = (half)((((qs5x16.s3 & 0x0F00) >> 8 ) | (((qh5x16.s1 >> 6) & 0x01) << 4)) * scale + m); \
28
+ a_f16.sf = (half)((((qs5x16.s3 & 0xF000) >> 12) | (((qh5x16.s1 >> 7) & 0x01) << 4)) * scale + m); \
29
+
30
+
31
+ #define dotx16_reduce8(a_reg, b_lm, c_reg, lm_offset) \
32
+ acc.s0 = dot(a_reg.s0123, b_lm[lm_offset + 0]); \
33
+ acc.s1 = dot(a_reg.s0123, b_lm[lm_offset + 1]); \
34
+ acc.s2 = dot(a_reg.s0123, b_lm[lm_offset + 2]); \
35
+ acc.s3 = dot(a_reg.s0123, b_lm[lm_offset + 3]); \
36
+ acc.s4 = dot(a_reg.s0123, b_lm[lm_offset + 4]); \
37
+ acc.s5 = dot(a_reg.s0123, b_lm[lm_offset + 5]); \
38
+ acc.s6 = dot(a_reg.s0123, b_lm[lm_offset + 6]); \
39
+ acc.s7 = dot(a_reg.s0123, b_lm[lm_offset + 7]); \
40
+ acc.s8 = dot(a_reg.s0123, b_lm[lm_offset + 8]); \
41
+ acc.s9 = dot(a_reg.s0123, b_lm[lm_offset + 9]); \
42
+ acc.sa = dot(a_reg.s0123, b_lm[lm_offset + 10]); \
43
+ acc.sb = dot(a_reg.s0123, b_lm[lm_offset + 11]); \
44
+ acc.sc = dot(a_reg.s0123, b_lm[lm_offset + 12]); \
45
+ acc.sd = dot(a_reg.s0123, b_lm[lm_offset + 13]); \
46
+ acc.se = dot(a_reg.s0123, b_lm[lm_offset + 14]); \
47
+ acc.sf = dot(a_reg.s0123, b_lm[lm_offset + 15]); \
48
+ acc.s0 += dot(a_reg.s4567, b_lm[lm_offset + 32]); \
49
+ acc.s1 += dot(a_reg.s4567, b_lm[lm_offset + 33]); \
50
+ acc.s2 += dot(a_reg.s4567, b_lm[lm_offset + 34]); \
51
+ acc.s3 += dot(a_reg.s4567, b_lm[lm_offset + 35]); \
52
+ acc.s4 += dot(a_reg.s4567, b_lm[lm_offset + 36]); \
53
+ acc.s5 += dot(a_reg.s4567, b_lm[lm_offset + 37]); \
54
+ acc.s6 += dot(a_reg.s4567, b_lm[lm_offset + 38]); \
55
+ acc.s7 += dot(a_reg.s4567, b_lm[lm_offset + 39]); \
56
+ acc.s8 += dot(a_reg.s4567, b_lm[lm_offset + 40]); \
57
+ acc.s9 += dot(a_reg.s4567, b_lm[lm_offset + 41]); \
58
+ acc.sa += dot(a_reg.s4567, b_lm[lm_offset + 42]); \
59
+ acc.sb += dot(a_reg.s4567, b_lm[lm_offset + 43]); \
60
+ acc.sc += dot(a_reg.s4567, b_lm[lm_offset + 44]); \
61
+ acc.sd += dot(a_reg.s4567, b_lm[lm_offset + 45]); \
62
+ acc.se += dot(a_reg.s4567, b_lm[lm_offset + 46]); \
63
+ acc.sf += dot(a_reg.s4567, b_lm[lm_offset + 47]); \
64
+ c_reg.lo += convert_float8(acc.lo); \
65
+ c_reg.hi += convert_float8(acc.hi); \
66
+ acc.s0 = dot(a_reg.s89ab, b_lm[lm_offset + 64]); \
67
+ acc.s1 = dot(a_reg.s89ab, b_lm[lm_offset + 65]); \
68
+ acc.s2 = dot(a_reg.s89ab, b_lm[lm_offset + 66]); \
69
+ acc.s3 = dot(a_reg.s89ab, b_lm[lm_offset + 67]); \
70
+ acc.s4 = dot(a_reg.s89ab, b_lm[lm_offset + 68]); \
71
+ acc.s5 = dot(a_reg.s89ab, b_lm[lm_offset + 69]); \
72
+ acc.s6 = dot(a_reg.s89ab, b_lm[lm_offset + 70]); \
73
+ acc.s7 = dot(a_reg.s89ab, b_lm[lm_offset + 71]); \
74
+ acc.s8 = dot(a_reg.s89ab, b_lm[lm_offset + 72]); \
75
+ acc.s9 = dot(a_reg.s89ab, b_lm[lm_offset + 73]); \
76
+ acc.sa = dot(a_reg.s89ab, b_lm[lm_offset + 74]); \
77
+ acc.sb = dot(a_reg.s89ab, b_lm[lm_offset + 75]); \
78
+ acc.sc = dot(a_reg.s89ab, b_lm[lm_offset + 76]); \
79
+ acc.sd = dot(a_reg.s89ab, b_lm[lm_offset + 77]); \
80
+ acc.se = dot(a_reg.s89ab, b_lm[lm_offset + 78]); \
81
+ acc.sf = dot(a_reg.s89ab, b_lm[lm_offset + 79]); \
82
+ acc.s0 += dot(a_reg.scdef, b_lm[lm_offset + 96]); \
83
+ acc.s1 += dot(a_reg.scdef, b_lm[lm_offset + 97]); \
84
+ acc.s2 += dot(a_reg.scdef, b_lm[lm_offset + 98]); \
85
+ acc.s3 += dot(a_reg.scdef, b_lm[lm_offset + 99]); \
86
+ acc.s4 += dot(a_reg.scdef, b_lm[lm_offset + 100]); \
87
+ acc.s5 += dot(a_reg.scdef, b_lm[lm_offset + 101]); \
88
+ acc.s6 += dot(a_reg.scdef, b_lm[lm_offset + 102]); \
89
+ acc.s7 += dot(a_reg.scdef, b_lm[lm_offset + 103]); \
90
+ acc.s8 += dot(a_reg.scdef, b_lm[lm_offset + 104]); \
91
+ acc.s9 += dot(a_reg.scdef, b_lm[lm_offset + 105]); \
92
+ acc.sa += dot(a_reg.scdef, b_lm[lm_offset + 106]); \
93
+ acc.sb += dot(a_reg.scdef, b_lm[lm_offset + 107]); \
94
+ acc.sc += dot(a_reg.scdef, b_lm[lm_offset + 108]); \
95
+ acc.sd += dot(a_reg.scdef, b_lm[lm_offset + 109]); \
96
+ acc.se += dot(a_reg.scdef, b_lm[lm_offset + 110]); \
97
+ acc.sf += dot(a_reg.scdef, b_lm[lm_offset + 111]); \
98
+ c_reg.lo += convert_float8(acc.lo); \
99
+ c_reg.hi += convert_float8(acc.hi); \
100
+
101
+ // Quarter-tile variant: computes 8 output columns (one skip-group) into a float8
102
+ // accumulator. Same reduction order / flush cadence as dotx16_reduce8, so the
103
+ // non-skipped path is byte-identical; it just lets the caller skip empty
104
+ // 8-column groups at finer granularity. Uses a private half8 `acc8`.
105
+ #define dotx8_reduce4(a_reg, b_lm, c_reg, lm_offset) \
106
+ acc8.s0 = dot(a_reg.s0123, b_lm[lm_offset + 0]); \
107
+ acc8.s1 = dot(a_reg.s0123, b_lm[lm_offset + 1]); \
108
+ acc8.s2 = dot(a_reg.s0123, b_lm[lm_offset + 2]); \
109
+ acc8.s3 = dot(a_reg.s0123, b_lm[lm_offset + 3]); \
110
+ acc8.s4 = dot(a_reg.s0123, b_lm[lm_offset + 4]); \
111
+ acc8.s5 = dot(a_reg.s0123, b_lm[lm_offset + 5]); \
112
+ acc8.s6 = dot(a_reg.s0123, b_lm[lm_offset + 6]); \
113
+ acc8.s7 = dot(a_reg.s0123, b_lm[lm_offset + 7]); \
114
+ acc8.s0 += dot(a_reg.s4567, b_lm[lm_offset + 32]); \
115
+ acc8.s1 += dot(a_reg.s4567, b_lm[lm_offset + 33]); \
116
+ acc8.s2 += dot(a_reg.s4567, b_lm[lm_offset + 34]); \
117
+ acc8.s3 += dot(a_reg.s4567, b_lm[lm_offset + 35]); \
118
+ acc8.s4 += dot(a_reg.s4567, b_lm[lm_offset + 36]); \
119
+ acc8.s5 += dot(a_reg.s4567, b_lm[lm_offset + 37]); \
120
+ acc8.s6 += dot(a_reg.s4567, b_lm[lm_offset + 38]); \
121
+ acc8.s7 += dot(a_reg.s4567, b_lm[lm_offset + 39]); \
122
+ c_reg += convert_float8(acc8); \
123
+ acc8.s0 = dot(a_reg.s89ab, b_lm[lm_offset + 64]); \
124
+ acc8.s1 = dot(a_reg.s89ab, b_lm[lm_offset + 65]); \
125
+ acc8.s2 = dot(a_reg.s89ab, b_lm[lm_offset + 66]); \
126
+ acc8.s3 = dot(a_reg.s89ab, b_lm[lm_offset + 67]); \
127
+ acc8.s4 = dot(a_reg.s89ab, b_lm[lm_offset + 68]); \
128
+ acc8.s5 = dot(a_reg.s89ab, b_lm[lm_offset + 69]); \
129
+ acc8.s6 = dot(a_reg.s89ab, b_lm[lm_offset + 70]); \
130
+ acc8.s7 = dot(a_reg.s89ab, b_lm[lm_offset + 71]); \
131
+ acc8.s0 += dot(a_reg.scdef, b_lm[lm_offset + 96]); \
132
+ acc8.s1 += dot(a_reg.scdef, b_lm[lm_offset + 97]); \
133
+ acc8.s2 += dot(a_reg.scdef, b_lm[lm_offset + 98]); \
134
+ acc8.s3 += dot(a_reg.scdef, b_lm[lm_offset + 99]); \
135
+ acc8.s4 += dot(a_reg.scdef, b_lm[lm_offset + 100]); \
136
+ acc8.s5 += dot(a_reg.scdef, b_lm[lm_offset + 101]); \
137
+ acc8.s6 += dot(a_reg.scdef, b_lm[lm_offset + 102]); \
138
+ acc8.s7 += dot(a_reg.scdef, b_lm[lm_offset + 103]); \
139
+ c_reg += convert_float8(acc8); \
140
+
141
+
142
+ __attribute__((qcom_wave_pair_mode(1))) // 1=force single 2=force pair
143
+ kernel void kernel_gemm_moe_q5_1_f32_ns(
144
+ __read_only image1d_buffer_t src0_qs,
145
+ __global uint * src0_qh,
146
+ __global half * src0_d,
147
+ __global half * src0_m,
148
+ __read_only image1d_buffer_t src1,
149
+ __global uint * src2,
150
+ __global ushort * src2_emap,
151
+ __write_only image1d_buffer_t dst,
152
+ __global int * total_tiles,
153
+ uint ne00,
154
+ uint ne01,
155
+ uint is_ragged,
156
+ uint skip_gran
157
+ ) {
158
+ uint block_id_m = get_global_id(1); // m_tile
159
+ uint block_id_n = get_global_id(2); // n_tile
160
+
161
+ // Boundary check
162
+ if (block_id_n >= total_tiles[0]) {
163
+ return;
164
+ }
165
+
166
+ // Ragged tile-skip: when is_ragged and the upper 16 token-slots of this tile are all
167
+ // padding (router 0xFFFFFFFF), skip the second (reg_c.hi) dotx16_reduce8 half -> ~half
168
+ // the GEMM dot for sparse tiles. Numerically identical (the skipped lanes are padding).
169
+ // Ragged tile-skip: tokens are packed contiguously per expert (moe_scatter fills
170
+ // lanes 0..V-1, moe_fill pre-pads the rest), so router padding (0xFFFFFFFF) is always
171
+ // trailing. Find the valid-token count V and round it UP to the skip granularity
172
+ // skip_gran (columns per skip-group: 8 = quarter, 16 = half/legacy, 32 = disabled).
173
+ // A 8-column group g is all-padding iff its first column (8*g) >= n_active, so its
174
+ // dotx8_reduce4 is skipped. Numerically identical (skipped lanes are padding).
175
+ uint n_active = TILESIZE_N;
176
+ if (is_ragged && skip_gran < TILESIZE_N) {
177
+ uint n_valid = TILESIZE_N;
178
+ for (uint _t = 0; _t < TILESIZE_N; ++_t) {
179
+ if (src2[block_id_n * TILESIZE_N + _t] == 0xFFFFFFFFu) { n_valid = _t; break; }
180
+ }
181
+ n_active = min((uint)TILESIZE_N, ((n_valid + skip_gran - 1) / skip_gran) * skip_gran);
182
+ }
183
+ // Group 0 (cols 0-7) always runs; groups 1-3 skip when fully padding.
184
+ bool skip_g1 = (8u >= n_active);
185
+ bool skip_g2 = (16u >= n_active);
186
+ bool skip_g3 = (24u >= n_active);
187
+
188
+ __private half16 reg_a;
189
+ __private float32 reg_c = (float32)(0);
190
+ __local half4 shared_b[128];
191
+
192
+ const ushort expert_id = src2_emap[block_id_n];
193
+
194
+ const uint row = block_id_m * TILESIZE_M;
195
+ const uint col = block_id_n * TILESIZE_N;
196
+
197
+ uint sub_block_id_m = get_local_id(0);
198
+ uint2 b_global_offset;
199
+ b_global_offset.x = ((sub_block_id_m & 3) << 2) + (sub_block_id_m >> 2) * ne00;
200
+ b_global_offset.y = b_global_offset.x + (16 * ne00);
201
+ uint2 b_local_offset;
202
+ b_local_offset.x = (sub_block_id_m & 3) * 32 + (sub_block_id_m >> 2);
203
+ b_local_offset.y = b_local_offset.x + 16;
204
+
205
+ // Loop along K axis, 32 elements (one block) for each iteration, divided into 2 sub-blocks
206
+ for (uint step = 0; step < ne00; step += TILESIZE_K * 2) {
207
+ // First sub-block
208
+ uint q_sub_offset = row + ((ne01 * step) >> 3) + ((expert_id * ne00 * ne01) >> 3);
209
+ uint s_sub_offset = row + ((ne01 * step) >> 5) + ((expert_id * ne00 * ne01) >> 5);
210
+ uint b_sub_offset = col * ne00 + step;
211
+
212
+ // Load scale and m for current Q5_1 block
213
+ uint blk_offset = s_sub_offset + get_global_id(0);
214
+ half s = src0_d[blk_offset];
215
+ half m = src0_m[blk_offset];
216
+
217
+ // Load 32 qh (5-th bit of each Q5) for the entire block
218
+ uchar4 qhx32 = as_uchar4(src0_qh[blk_offset]);
219
+
220
+ // Load 16 qs (half block) in transposed layout
221
+ uint2 qsx16;
222
+ qsx16.x = read_imageui(src0_qs, q_sub_offset + sub_block_id_m).x;
223
+ qsx16.y = read_imageui(src0_qs, q_sub_offset + sub_block_id_m + ne01).x;
224
+
225
+ // Load 16x32 floats from matrix B, each fiber out of 64 in a sub-group loads 8 elements
226
+ float8 bx8_f32;
227
+ bx8_f32.lo = read_imagef(src1, (b_sub_offset + b_global_offset.x) / 4);
228
+ bx8_f32.hi = read_imagef(src1, (b_sub_offset + b_global_offset.y) / 4);
229
+ // Convert to half and store to LM to share within the subgroup
230
+ half8 bx8_f16 = convert_half8(bx8_f32);
231
+ shared_b[b_local_offset.x] = bx8_f16.lo;
232
+ shared_b[b_local_offset.y] = bx8_f16.hi;
233
+
234
+ // Dequantization
235
+ dequantize_q5_1(as_ushort4(qsx16), qhx32.lo, reg_a, s, m);
236
+
237
+ sub_group_barrier(CLK_LOCAL_MEM_FENCE);
238
+
239
+ // 32 16x16 fp16 dot product with 8 elements reduction for better precision
240
+ half8 acc8;
241
+ dotx8_reduce4(reg_a, shared_b, reg_c.lo.lo, 0);
242
+ if (!skip_g1) { dotx8_reduce4(reg_a, shared_b, reg_c.lo.hi, 8); }
243
+ if (!skip_g2) { dotx8_reduce4(reg_a, shared_b, reg_c.hi.lo, 16); }
244
+ if (!skip_g3) { dotx8_reduce4(reg_a, shared_b, reg_c.hi.hi, 24); }
245
+
246
+ // Repeat for second sub-block
247
+ uint half_step = step + TILESIZE_K;
248
+ q_sub_offset = row + ((ne01 * half_step) >> 3) + ((expert_id * ne00 * ne01) >> 3);
249
+ b_sub_offset = col * ne00 + half_step;
250
+
251
+ // Load next 16 qs in transposed layout
252
+ qsx16.x = read_imageui(src0_qs, q_sub_offset + sub_block_id_m).x;
253
+ qsx16.y = read_imageui(src0_qs, q_sub_offset + sub_block_id_m + ne01).x;
254
+
255
+ // Load 16x32 floats from matrix B, each fiber out of 64 in a sub-group loads 8 elements
256
+ bx8_f32.lo = read_imagef(src1, (b_sub_offset + b_global_offset.x) / 4);
257
+ bx8_f32.hi = read_imagef(src1, (b_sub_offset + b_global_offset.y) / 4);
258
+ // Convert to half and store to LM to share within the subgroup
259
+ bx8_f16 = convert_half8(bx8_f32);
260
+ shared_b[b_local_offset.x] = bx8_f16.lo;
261
+ shared_b[b_local_offset.y] = bx8_f16.hi;
262
+
263
+ // Dequantization
264
+ dequantize_q5_1(as_ushort4(qsx16), qhx32.hi, reg_a, s, m);
265
+
266
+ sub_group_barrier(CLK_LOCAL_MEM_FENCE);
267
+
268
+ // 32 16x16 fp16 dot product with 3-levels reduction for better precision
269
+ dotx8_reduce4(reg_a, shared_b, reg_c.lo.lo, 0);
270
+ if (!skip_g1) { dotx8_reduce4(reg_a, shared_b, reg_c.lo.hi, 8); }
271
+ if (!skip_g2) { dotx8_reduce4(reg_a, shared_b, reg_c.hi.lo, 16); }
272
+ if (!skip_g3) { dotx8_reduce4(reg_a, shared_b, reg_c.hi.hi, 24); }
273
+ }
274
+
275
+ if ((get_global_id(0) + block_id_m * TILESIZE_M) >= ne01) {
276
+ return;
277
+ }
278
+
279
+ // Load poster router and share in LM
280
+ __local uint out_idx[TILESIZE_N];
281
+
282
+ if (get_local_id(0) < TILESIZE_N) {
283
+ uint idx = src2[block_id_n * TILESIZE_N + get_local_id(0)];
284
+ if (idx == 0xFFFFFFFF) {
285
+ idx = src2[block_id_n * TILESIZE_N + 0];
286
+ }
287
+ out_idx[get_local_id(0)] = idx * ne01;
288
+ }
289
+
290
+ barrier(CLK_LOCAL_MEM_FENCE);
291
+
292
+ // Scatter results back to original position in output grid
293
+ uint m_offset = row + get_local_id(0);
294
+
295
+ write_imagef(dst, out_idx[1] + m_offset, (reg_c.s1));
296
+ write_imagef(dst, out_idx[2] + m_offset, (reg_c.s2));
297
+ write_imagef(dst, out_idx[3] + m_offset, (reg_c.s3));
298
+ write_imagef(dst, out_idx[4] + m_offset, (reg_c.s4));
299
+ write_imagef(dst, out_idx[5] + m_offset, (reg_c.s5));
300
+ write_imagef(dst, out_idx[6] + m_offset, (reg_c.s6));
301
+ write_imagef(dst, out_idx[7] + m_offset, (reg_c.s7));
302
+ write_imagef(dst, out_idx[8] + m_offset, (reg_c.s8));
303
+ write_imagef(dst, out_idx[9] + m_offset, (reg_c.s9));
304
+ write_imagef(dst, out_idx[10] + m_offset, (reg_c.sa));
305
+ write_imagef(dst, out_idx[11] + m_offset, (reg_c.sb));
306
+ write_imagef(dst, out_idx[12] + m_offset, (reg_c.sc));
307
+ write_imagef(dst, out_idx[13] + m_offset, (reg_c.sd));
308
+ write_imagef(dst, out_idx[14] + m_offset, (reg_c.se));
309
+ write_imagef(dst, out_idx[15] + m_offset, (reg_c.sf));
310
+ write_imagef(dst, out_idx[16] + m_offset, (reg_c.sg));
311
+ write_imagef(dst, out_idx[17] + m_offset, (reg_c.sh));
312
+ write_imagef(dst, out_idx[18] + m_offset, (reg_c.si));
313
+ write_imagef(dst, out_idx[19] + m_offset, (reg_c.sj));
314
+ write_imagef(dst, out_idx[20] + m_offset, (reg_c.sk));
315
+ write_imagef(dst, out_idx[21] + m_offset, (reg_c.sl));
316
+ write_imagef(dst, out_idx[22] + m_offset, (reg_c.sm));
317
+ write_imagef(dst, out_idx[23] + m_offset, (reg_c.sn));
318
+ write_imagef(dst, out_idx[24] + m_offset, (reg_c.so));
319
+ write_imagef(dst, out_idx[25] + m_offset, (reg_c.sp));
320
+ write_imagef(dst, out_idx[26] + m_offset, (reg_c.sq));
321
+ write_imagef(dst, out_idx[27] + m_offset, (reg_c.sr));
322
+ write_imagef(dst, out_idx[28] + m_offset, (reg_c.ss));
323
+ write_imagef(dst, out_idx[29] + m_offset, (reg_c.st));
324
+ write_imagef(dst, out_idx[30] + m_offset, (reg_c.su));
325
+ write_imagef(dst, out_idx[31] + m_offset, (reg_c.sv));
326
+
327
+ // Store zero padding parts to the index of first output in tile, override correct result in the end
328
+ barrier(CLK_GLOBAL_MEM_FENCE);
329
+ write_imagef(dst, out_idx[0] + m_offset, (reg_c.s0));
330
+ }
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_moe_q5_k_f32_ns.cl ADDED
@@ -0,0 +1,356 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #pragma OPENCL EXTENSION cl_khr_fp16 : enable
2
+ #pragma OPENCL EXTENSION cl_khr_subgroups : enable
3
+ #pragma OPENCL EXTENSION cl_qcom_subgroup_uniform_load: enable
4
+ #pragma OPENCL EXTENSION cl_qcom_subgroup_constant_load: enable
5
+ #pragma OPENCL EXTENSION cl_qcom_extra_vector_types : enable
6
+
7
+ #define TILESIZE_K 16
8
+ #define TILESIZE_M 64
9
+ #define TILESIZE_N 32
10
+ #define QK_K 256
11
+ #define K_SCALE_SIZE 12
12
+
13
+ inline void get_scale_min_k4(
14
+ int j,
15
+ global const uchar * q,
16
+ uchar * d,
17
+ uchar * m
18
+ ) {
19
+ if (j < 4) {
20
+ *d = q[j] & 63;
21
+ *m = q[j+4] & 63;
22
+ } else {
23
+ *d = (q[j+4] & 0x0F) | ((q[j-4] & 0xC0) >> 2);
24
+ *m = ((q[j+4] >> 4) & 0x0F) | ((q[j] & 0xC0) >> 2);
25
+ }
26
+ }
27
+
28
+ #define dequantize_q5_k(qs5x16, qh5x16, a_f16, scale, m) \
29
+ a_f16.s0 = (half)((float)(( qs5x16.s0 & 0x000F) | (( qh5x16.s0 & 0x01) << 4)) * scale + m); \
30
+ a_f16.s1 = (half)((float)((((qs5x16.s0 & 0x00F0) >> 4 ) | (((qh5x16.s0 >> 1) & 0x01) << 4)) * scale + m)); \
31
+ a_f16.s2 = (half)((float)((((qs5x16.s0 & 0x0F00) >> 8 ) | (((qh5x16.s0 >> 2) & 0x01) << 4)) * scale + m)); \
32
+ a_f16.s3 = (half)((float)((((qs5x16.s0 & 0xF000) >> 12) | (((qh5x16.s0 >> 3) & 0x01) << 4)) * scale + m)); \
33
+ a_f16.s4 = (half)((float)((( qs5x16.s1 & 0x000F) | (((qh5x16.s0 >> 4) & 0x01) << 4)) * scale + m)); \
34
+ a_f16.s5 = (half)((float)((((qs5x16.s1 & 0x00F0) >> 4 ) | (((qh5x16.s0 >> 5) & 0x01) << 4)) * scale + m)); \
35
+ a_f16.s6 = (half)((float)(((qs5x16.s1 & 0x0F00) >> 8 ) | (((qh5x16.s0 >> 6) & 0x01) << 4)) * scale + m); \
36
+ a_f16.s7 = (half)((float)((((qs5x16.s1 & 0xF000) >> 12) | (((qh5x16.s0 >> 7) & 0x01) << 4)) * scale + m)); \
37
+ a_f16.s8 = (half)((float)((( qs5x16.s2 & 0x000F) | (( qh5x16.s1 & 0x01) << 4)) * scale + m)); \
38
+ a_f16.s9 = (half)((float)((((qs5x16.s2 & 0x00F0) >> 4 ) | (((qh5x16.s1 >> 1) & 0x01) << 4)) * scale + m)); \
39
+ a_f16.sa = (half)((float)((((qs5x16.s2 & 0x0F00) >> 8 ) | (((qh5x16.s1 >> 2) & 0x01) << 4)) * scale + m)); \
40
+ a_f16.sb = (half)((float)((((qs5x16.s2 & 0xF000) >> 12) | (((qh5x16.s1 >> 3) & 0x01) << 4)) * scale + m)); \
41
+ a_f16.sc = (half)((float)((( qs5x16.s3 & 0x000F) | (((qh5x16.s1 >> 4) & 0x01) << 4)) * scale + m)); \
42
+ a_f16.sd = (half)((float)((((qs5x16.s3 & 0x00F0) >> 4 ) | (((qh5x16.s1 >> 5) & 0x01) << 4)) * scale + m)); \
43
+ a_f16.se = (half)((float)((((qs5x16.s3 & 0x0F00) >> 8 ) | (((qh5x16.s1 >> 6) & 0x01) << 4)) * scale + m)); \
44
+ a_f16.sf = (half)((float)((((qs5x16.s3 & 0xF000) >> 12) | (((qh5x16.s1 >> 7) & 0x01) << 4)) * scale + m)); \
45
+
46
+
47
+ #define dotx16_reduce8(a_reg, b_lm, c_reg, lm_offset) \
48
+ acc.s0 = dot(a_reg.s0123, b_lm[lm_offset + 0]); \
49
+ acc.s1 = dot(a_reg.s0123, b_lm[lm_offset + 1]); \
50
+ acc.s2 = dot(a_reg.s0123, b_lm[lm_offset + 2]); \
51
+ acc.s3 = dot(a_reg.s0123, b_lm[lm_offset + 3]); \
52
+ acc.s4 = dot(a_reg.s0123, b_lm[lm_offset + 4]); \
53
+ acc.s5 = dot(a_reg.s0123, b_lm[lm_offset + 5]); \
54
+ acc.s6 = dot(a_reg.s0123, b_lm[lm_offset + 6]); \
55
+ acc.s7 = dot(a_reg.s0123, b_lm[lm_offset + 7]); \
56
+ acc.s8 = dot(a_reg.s0123, b_lm[lm_offset + 8]); \
57
+ acc.s9 = dot(a_reg.s0123, b_lm[lm_offset + 9]); \
58
+ acc.sa = dot(a_reg.s0123, b_lm[lm_offset + 10]); \
59
+ acc.sb = dot(a_reg.s0123, b_lm[lm_offset + 11]); \
60
+ acc.sc = dot(a_reg.s0123, b_lm[lm_offset + 12]); \
61
+ acc.sd = dot(a_reg.s0123, b_lm[lm_offset + 13]); \
62
+ acc.se = dot(a_reg.s0123, b_lm[lm_offset + 14]); \
63
+ acc.sf = dot(a_reg.s0123, b_lm[lm_offset + 15]); \
64
+ acc.s0 += dot(a_reg.s4567, b_lm[lm_offset + 32]); \
65
+ acc.s1 += dot(a_reg.s4567, b_lm[lm_offset + 33]); \
66
+ acc.s2 += dot(a_reg.s4567, b_lm[lm_offset + 34]); \
67
+ acc.s3 += dot(a_reg.s4567, b_lm[lm_offset + 35]); \
68
+ acc.s4 += dot(a_reg.s4567, b_lm[lm_offset + 36]); \
69
+ acc.s5 += dot(a_reg.s4567, b_lm[lm_offset + 37]); \
70
+ acc.s6 += dot(a_reg.s4567, b_lm[lm_offset + 38]); \
71
+ acc.s7 += dot(a_reg.s4567, b_lm[lm_offset + 39]); \
72
+ acc.s8 += dot(a_reg.s4567, b_lm[lm_offset + 40]); \
73
+ acc.s9 += dot(a_reg.s4567, b_lm[lm_offset + 41]); \
74
+ acc.sa += dot(a_reg.s4567, b_lm[lm_offset + 42]); \
75
+ acc.sb += dot(a_reg.s4567, b_lm[lm_offset + 43]); \
76
+ acc.sc += dot(a_reg.s4567, b_lm[lm_offset + 44]); \
77
+ acc.sd += dot(a_reg.s4567, b_lm[lm_offset + 45]); \
78
+ acc.se += dot(a_reg.s4567, b_lm[lm_offset + 46]); \
79
+ acc.sf += dot(a_reg.s4567, b_lm[lm_offset + 47]); \
80
+ c_reg.lo += convert_float8(acc.lo); \
81
+ c_reg.hi += convert_float8(acc.hi); \
82
+ acc.s0 = dot(a_reg.s89ab, b_lm[lm_offset + 64]); \
83
+ acc.s1 = dot(a_reg.s89ab, b_lm[lm_offset + 65]); \
84
+ acc.s2 = dot(a_reg.s89ab, b_lm[lm_offset + 66]); \
85
+ acc.s3 = dot(a_reg.s89ab, b_lm[lm_offset + 67]); \
86
+ acc.s4 = dot(a_reg.s89ab, b_lm[lm_offset + 68]); \
87
+ acc.s5 = dot(a_reg.s89ab, b_lm[lm_offset + 69]); \
88
+ acc.s6 = dot(a_reg.s89ab, b_lm[lm_offset + 70]); \
89
+ acc.s7 = dot(a_reg.s89ab, b_lm[lm_offset + 71]); \
90
+ acc.s8 = dot(a_reg.s89ab, b_lm[lm_offset + 72]); \
91
+ acc.s9 = dot(a_reg.s89ab, b_lm[lm_offset + 73]); \
92
+ acc.sa = dot(a_reg.s89ab, b_lm[lm_offset + 74]); \
93
+ acc.sb = dot(a_reg.s89ab, b_lm[lm_offset + 75]); \
94
+ acc.sc = dot(a_reg.s89ab, b_lm[lm_offset + 76]); \
95
+ acc.sd = dot(a_reg.s89ab, b_lm[lm_offset + 77]); \
96
+ acc.se = dot(a_reg.s89ab, b_lm[lm_offset + 78]); \
97
+ acc.sf = dot(a_reg.s89ab, b_lm[lm_offset + 79]); \
98
+ acc.s0 += dot(a_reg.scdef, b_lm[lm_offset + 96]); \
99
+ acc.s1 += dot(a_reg.scdef, b_lm[lm_offset + 97]); \
100
+ acc.s2 += dot(a_reg.scdef, b_lm[lm_offset + 98]); \
101
+ acc.s3 += dot(a_reg.scdef, b_lm[lm_offset + 99]); \
102
+ acc.s4 += dot(a_reg.scdef, b_lm[lm_offset + 100]); \
103
+ acc.s5 += dot(a_reg.scdef, b_lm[lm_offset + 101]); \
104
+ acc.s6 += dot(a_reg.scdef, b_lm[lm_offset + 102]); \
105
+ acc.s7 += dot(a_reg.scdef, b_lm[lm_offset + 103]); \
106
+ acc.s8 += dot(a_reg.scdef, b_lm[lm_offset + 104]); \
107
+ acc.s9 += dot(a_reg.scdef, b_lm[lm_offset + 105]); \
108
+ acc.sa += dot(a_reg.scdef, b_lm[lm_offset + 106]); \
109
+ acc.sb += dot(a_reg.scdef, b_lm[lm_offset + 107]); \
110
+ acc.sc += dot(a_reg.scdef, b_lm[lm_offset + 108]); \
111
+ acc.sd += dot(a_reg.scdef, b_lm[lm_offset + 109]); \
112
+ acc.se += dot(a_reg.scdef, b_lm[lm_offset + 110]); \
113
+ acc.sf += dot(a_reg.scdef, b_lm[lm_offset + 111]); \
114
+ c_reg.lo += convert_float8(acc.lo); \
115
+ c_reg.hi += convert_float8(acc.hi); \
116
+
117
+ // Quarter-tile variant: computes 8 output columns (one skip-group) into a float8
118
+ // accumulator. Same reduction order / flush cadence as dotx16_reduce8, so the
119
+ // non-skipped path is byte-identical; it just lets the caller skip empty
120
+ // 8-column groups at finer granularity. Uses a private half8 `acc8`.
121
+ #define dotx8_reduce4(a_reg, b_lm, c_reg, lm_offset) \
122
+ acc8.s0 = dot(a_reg.s0123, b_lm[lm_offset + 0]); \
123
+ acc8.s1 = dot(a_reg.s0123, b_lm[lm_offset + 1]); \
124
+ acc8.s2 = dot(a_reg.s0123, b_lm[lm_offset + 2]); \
125
+ acc8.s3 = dot(a_reg.s0123, b_lm[lm_offset + 3]); \
126
+ acc8.s4 = dot(a_reg.s0123, b_lm[lm_offset + 4]); \
127
+ acc8.s5 = dot(a_reg.s0123, b_lm[lm_offset + 5]); \
128
+ acc8.s6 = dot(a_reg.s0123, b_lm[lm_offset + 6]); \
129
+ acc8.s7 = dot(a_reg.s0123, b_lm[lm_offset + 7]); \
130
+ acc8.s0 += dot(a_reg.s4567, b_lm[lm_offset + 32]); \
131
+ acc8.s1 += dot(a_reg.s4567, b_lm[lm_offset + 33]); \
132
+ acc8.s2 += dot(a_reg.s4567, b_lm[lm_offset + 34]); \
133
+ acc8.s3 += dot(a_reg.s4567, b_lm[lm_offset + 35]); \
134
+ acc8.s4 += dot(a_reg.s4567, b_lm[lm_offset + 36]); \
135
+ acc8.s5 += dot(a_reg.s4567, b_lm[lm_offset + 37]); \
136
+ acc8.s6 += dot(a_reg.s4567, b_lm[lm_offset + 38]); \
137
+ acc8.s7 += dot(a_reg.s4567, b_lm[lm_offset + 39]); \
138
+ c_reg += convert_float8(acc8); \
139
+ acc8.s0 = dot(a_reg.s89ab, b_lm[lm_offset + 64]); \
140
+ acc8.s1 = dot(a_reg.s89ab, b_lm[lm_offset + 65]); \
141
+ acc8.s2 = dot(a_reg.s89ab, b_lm[lm_offset + 66]); \
142
+ acc8.s3 = dot(a_reg.s89ab, b_lm[lm_offset + 67]); \
143
+ acc8.s4 = dot(a_reg.s89ab, b_lm[lm_offset + 68]); \
144
+ acc8.s5 = dot(a_reg.s89ab, b_lm[lm_offset + 69]); \
145
+ acc8.s6 = dot(a_reg.s89ab, b_lm[lm_offset + 70]); \
146
+ acc8.s7 = dot(a_reg.s89ab, b_lm[lm_offset + 71]); \
147
+ acc8.s0 += dot(a_reg.scdef, b_lm[lm_offset + 96]); \
148
+ acc8.s1 += dot(a_reg.scdef, b_lm[lm_offset + 97]); \
149
+ acc8.s2 += dot(a_reg.scdef, b_lm[lm_offset + 98]); \
150
+ acc8.s3 += dot(a_reg.scdef, b_lm[lm_offset + 99]); \
151
+ acc8.s4 += dot(a_reg.scdef, b_lm[lm_offset + 100]); \
152
+ acc8.s5 += dot(a_reg.scdef, b_lm[lm_offset + 101]); \
153
+ acc8.s6 += dot(a_reg.scdef, b_lm[lm_offset + 102]); \
154
+ acc8.s7 += dot(a_reg.scdef, b_lm[lm_offset + 103]); \
155
+ c_reg += convert_float8(acc8); \
156
+
157
+
158
+ __attribute__((qcom_wave_pair_mode(1)))
159
+ kernel void kernel_gemm_moe_q5_k_f32_ns(
160
+ __read_only image1d_buffer_t src0_q,
161
+ __global uint * src0_qh,
162
+ __global uchar * src0_s,
163
+ __global half * src0_d,
164
+ __global half * src0_dm,
165
+ __read_only image1d_buffer_t src1,
166
+ __global uint * src2,
167
+ __global ushort * src2_emap,
168
+ __write_only image1d_buffer_t dst,
169
+ __global int * total_tiles,
170
+ uint ne00,
171
+ uint ne01,
172
+ uint is_ragged,
173
+ uint skip_gran
174
+ ) {
175
+ uint block_id_m = get_global_id(1); // m_tile
176
+ uint block_id_n = get_global_id(2); // n_tile
177
+
178
+ // Boundary check
179
+ if (block_id_n >= total_tiles[0]) {
180
+ return;
181
+ }
182
+
183
+ // Ragged tile-skip: when is_ragged and the upper 16 token-slots of this tile are all
184
+ // padding (router 0xFFFFFFFF), skip the second (reg_c.hi) dotx16_reduce8 half -> ~half
185
+ // the GEMM dot for sparse tiles. Numerically identical (the skipped lanes are padding).
186
+ // Ragged tile-skip: tokens are packed contiguously per expert (moe_scatter fills
187
+ // lanes 0..V-1, moe_fill pre-pads the rest), so router padding (0xFFFFFFFF) is always
188
+ // trailing. Find the valid-token count V and round it UP to the skip granularity
189
+ // skip_gran (columns per skip-group: 8 = quarter, 16 = half/legacy, 32 = disabled).
190
+ // A 8-column group g is all-padding iff its first column (8*g) >= n_active, so its
191
+ // dotx8_reduce4 is skipped. Numerically identical (skipped lanes are padding).
192
+ uint n_active = TILESIZE_N;
193
+ if (is_ragged && skip_gran < TILESIZE_N) {
194
+ uint n_valid = TILESIZE_N;
195
+ for (uint _t = 0; _t < TILESIZE_N; ++_t) {
196
+ if (src2[block_id_n * TILESIZE_N + _t] == 0xFFFFFFFFu) { n_valid = _t; break; }
197
+ }
198
+ n_active = min((uint)TILESIZE_N, ((n_valid + skip_gran - 1) / skip_gran) * skip_gran);
199
+ }
200
+ // Group 0 (cols 0-7) always runs; groups 1-3 skip when fully padding.
201
+ bool skip_g1 = (8u >= n_active);
202
+ bool skip_g2 = (16u >= n_active);
203
+ bool skip_g3 = (24u >= n_active);
204
+
205
+ __private half16 reg_a;
206
+ __private float32 reg_c = (float32)(0);
207
+ __local half4 shared_b[128];
208
+
209
+ const ushort expert_id = src2_emap[block_id_n];
210
+
211
+ const uint row = block_id_m * TILESIZE_M;
212
+ const uint col = block_id_n * TILESIZE_N;
213
+
214
+ uint sub_block_id_m = get_local_id(0);
215
+ uint2 b_global_offset;
216
+ b_global_offset.x = ((sub_block_id_m & 3) << 2) + (sub_block_id_m >> 2) * ne00;
217
+ b_global_offset.y = b_global_offset.x + (16 * ne00);
218
+ uint2 b_local_offset;
219
+ b_local_offset.x = (sub_block_id_m & 3) * 32 + (sub_block_id_m >> 2);
220
+ b_local_offset.y = b_local_offset.x + 16;
221
+
222
+ uint num_superblocks = ne00 / QK_K;
223
+ uint scales_per_row = num_superblocks * K_SCALE_SIZE;
224
+ uint row_idx = row + get_global_id(0);
225
+
226
+ // Loop along K axis, 32 elements per iteration (one sub-block), divided into 2 halves of 16
227
+ for (uint step = 0; step < ne00; step += TILESIZE_K * 2) {
228
+ uint sub = step / 32;
229
+ uint sb = sub / 8;
230
+ uint j = sub % 8;
231
+
232
+ // Load d and dm for super-block
233
+ uint d_offset = row + sb * ne01 + expert_id * num_superblocks * ne01 + get_global_id(0);
234
+ half d_val = src0_d[d_offset];
235
+ half dm_val = src0_dm[d_offset];
236
+
237
+ // Load sub-block scale and min
238
+ global const uchar * sc = src0_s + (expert_id * ne01 + row_idx) * scales_per_row + sb * K_SCALE_SIZE;
239
+ uchar sv, mn;
240
+ get_scale_min_k4(j, sc, &sv, &mn);
241
+
242
+ float scale = (float)d_val * (float)sv;
243
+ float minv = -(float)dm_val * (float)mn;
244
+
245
+ // qh is stored at sub-block granularity
246
+ uint qh_offset = row + sub * ne01 + expert_id * num_superblocks * 8 * ne01 + get_global_id(0);
247
+ uchar4 qhx32 = as_uchar4(src0_qh[qh_offset]);
248
+
249
+ // First sub-block (16 elements)
250
+ uint q_sub_offset = row + ((ne01 * step) >> 3) + ((expert_id * ne00 * ne01) >> 3);
251
+ uint b_sub_offset = col * ne00 + step;
252
+
253
+ // Load 16 q (64-bits) in transposed layout
254
+ uint2 q4x16;
255
+ q4x16.x = read_imageui(src0_q, q_sub_offset + sub_block_id_m).x;
256
+ q4x16.y = read_imageui(src0_q, q_sub_offset + sub_block_id_m + ne01).x;
257
+
258
+ // Load 16x32 floats from matrix B
259
+ float8 bx8_f32;
260
+ bx8_f32.lo = read_imagef(src1, (b_sub_offset + b_global_offset.x) / 4);
261
+ bx8_f32.hi = read_imagef(src1, (b_sub_offset + b_global_offset.y) / 4);
262
+ half8 bx8_f16 = convert_half8(bx8_f32);
263
+ shared_b[b_local_offset.x] = bx8_f16.lo;
264
+ shared_b[b_local_offset.y] = bx8_f16.hi;
265
+
266
+ // Dequantization
267
+ dequantize_q5_k(as_ushort4(q4x16), qhx32.lo, reg_a, scale, minv);
268
+
269
+ sub_group_barrier(CLK_LOCAL_MEM_FENCE);
270
+
271
+ half8 acc8;
272
+ dotx8_reduce4(reg_a, shared_b, reg_c.lo.lo, 0);
273
+ if (!skip_g1) { dotx8_reduce4(reg_a, shared_b, reg_c.lo.hi, 8); }
274
+ if (!skip_g2) { dotx8_reduce4(reg_a, shared_b, reg_c.hi.lo, 16); }
275
+ if (!skip_g3) { dotx8_reduce4(reg_a, shared_b, reg_c.hi.hi, 24); }
276
+
277
+ // Second half
278
+ uint half_step = step + TILESIZE_K;
279
+ q_sub_offset = row + ((ne01 * half_step) >> 3) + ((expert_id * ne00 * ne01) >> 3);
280
+ b_sub_offset = col * ne00 + half_step;
281
+
282
+ q4x16.x = read_imageui(src0_q, q_sub_offset + sub_block_id_m).x;
283
+ q4x16.y = read_imageui(src0_q, q_sub_offset + sub_block_id_m + ne01).x;
284
+
285
+ bx8_f32.lo = read_imagef(src1, (b_sub_offset + b_global_offset.x) / 4);
286
+ bx8_f32.hi = read_imagef(src1, (b_sub_offset + b_global_offset.y) / 4);
287
+ bx8_f16 = convert_half8(bx8_f32);
288
+ shared_b[b_local_offset.x] = bx8_f16.lo;
289
+ shared_b[b_local_offset.y] = bx8_f16.hi;
290
+
291
+ dequantize_q5_k(as_ushort4(q4x16), qhx32.hi, reg_a, scale, minv);
292
+
293
+ sub_group_barrier(CLK_LOCAL_MEM_FENCE);
294
+
295
+ dotx8_reduce4(reg_a, shared_b, reg_c.lo.lo, 0);
296
+ if (!skip_g1) { dotx8_reduce4(reg_a, shared_b, reg_c.lo.hi, 8); }
297
+ if (!skip_g2) { dotx8_reduce4(reg_a, shared_b, reg_c.hi.lo, 16); }
298
+ if (!skip_g3) { dotx8_reduce4(reg_a, shared_b, reg_c.hi.hi, 24); }
299
+ }
300
+
301
+ if ((get_global_id(0) + block_id_m * TILESIZE_M) >= ne01) {
302
+ return;
303
+ }
304
+
305
+ // Load post router and share in LM
306
+ __local uint out_idx[TILESIZE_N];
307
+
308
+ if (get_local_id(0) < TILESIZE_N) {
309
+ uint idx = src2[block_id_n * TILESIZE_N + get_local_id(0)];
310
+ if (idx == 0xFFFFFFFF) {
311
+ idx = src2[block_id_n * TILESIZE_N + 0];
312
+ }
313
+ out_idx[get_local_id(0)] = idx * ne01;
314
+ }
315
+
316
+ barrier(CLK_LOCAL_MEM_FENCE);
317
+
318
+ // Scatter results back to original position in output grid
319
+ uint m_offset = row + get_local_id(0);
320
+
321
+ write_imagef(dst, out_idx[1] + m_offset, (reg_c.s1));
322
+ write_imagef(dst, out_idx[2] + m_offset, (reg_c.s2));
323
+ write_imagef(dst, out_idx[3] + m_offset, (reg_c.s3));
324
+ write_imagef(dst, out_idx[4] + m_offset, (reg_c.s4));
325
+ write_imagef(dst, out_idx[5] + m_offset, (reg_c.s5));
326
+ write_imagef(dst, out_idx[6] + m_offset, (reg_c.s6));
327
+ write_imagef(dst, out_idx[7] + m_offset, (reg_c.s7));
328
+ write_imagef(dst, out_idx[8] + m_offset, (reg_c.s8));
329
+ write_imagef(dst, out_idx[9] + m_offset, (reg_c.s9));
330
+ write_imagef(dst, out_idx[10] + m_offset, (reg_c.sa));
331
+ write_imagef(dst, out_idx[11] + m_offset, (reg_c.sb));
332
+ write_imagef(dst, out_idx[12] + m_offset, (reg_c.sc));
333
+ write_imagef(dst, out_idx[13] + m_offset, (reg_c.sd));
334
+ write_imagef(dst, out_idx[14] + m_offset, (reg_c.se));
335
+ write_imagef(dst, out_idx[15] + m_offset, (reg_c.sf));
336
+ write_imagef(dst, out_idx[16] + m_offset, (reg_c.sg));
337
+ write_imagef(dst, out_idx[17] + m_offset, (reg_c.sh));
338
+ write_imagef(dst, out_idx[18] + m_offset, (reg_c.si));
339
+ write_imagef(dst, out_idx[19] + m_offset, (reg_c.sj));
340
+ write_imagef(dst, out_idx[20] + m_offset, (reg_c.sk));
341
+ write_imagef(dst, out_idx[21] + m_offset, (reg_c.sl));
342
+ write_imagef(dst, out_idx[22] + m_offset, (reg_c.sm));
343
+ write_imagef(dst, out_idx[23] + m_offset, (reg_c.sn));
344
+ write_imagef(dst, out_idx[24] + m_offset, (reg_c.so));
345
+ write_imagef(dst, out_idx[25] + m_offset, (reg_c.sp));
346
+ write_imagef(dst, out_idx[26] + m_offset, (reg_c.sq));
347
+ write_imagef(dst, out_idx[27] + m_offset, (reg_c.sr));
348
+ write_imagef(dst, out_idx[28] + m_offset, (reg_c.ss));
349
+ write_imagef(dst, out_idx[29] + m_offset, (reg_c.st));
350
+ write_imagef(dst, out_idx[30] + m_offset, (reg_c.su));
351
+ write_imagef(dst, out_idx[31] + m_offset, (reg_c.sv));
352
+
353
+ // Store zero padding parts to the index of first output in tile
354
+ barrier(CLK_GLOBAL_MEM_FENCE);
355
+ write_imagef(dst, out_idx[0] + m_offset, (reg_c.s0));
356
+ }
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_moe_q6_k_f32_ns.cl ADDED
@@ -0,0 +1,335 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #pragma OPENCL EXTENSION cl_khr_fp16 : enable
2
+ #pragma OPENCL EXTENSION cl_khr_subgroups : enable
3
+ #pragma OPENCL EXTENSION cl_qcom_subgroup_uniform_load: enable
4
+ #pragma OPENCL EXTENSION cl_qcom_subgroup_constant_load: enable
5
+ #pragma OPENCL EXTENSION cl_qcom_extra_vector_types : enable
6
+
7
+ #define TILESIZE_K 16
8
+ #define TILESIZE_M 64
9
+ #define TILESIZE_N 32
10
+ #define QK_K 256
11
+
12
+ #define dequantize_q6_k(qs16, qh16, a_f16, scale) \
13
+ a_f16.s0 = (half)(((float)(( qs16.s0 & 0x000F) | ((uint)(( qh16 ) & 0x3) << 4)) - 32.f) * scale); \
14
+ a_f16.s1 = (half)(((float)((( qs16.s0 >> 4) & 0x000F) | ((uint)(( qh16 >> 2) & 0x3) << 4)) - 32.f) * scale); \
15
+ a_f16.s2 = (half)(((float)((( qs16.s0 >> 8) & 0x000F) | ((uint)(( qh16 >> 4) & 0x3) << 4)) - 32.f) * scale); \
16
+ a_f16.s3 = (half)(((float)((( qs16.s0 >>12) & 0x000F) | ((uint)(( qh16 >> 6) & 0x3) << 4)) - 32.f) * scale); \
17
+ a_f16.s4 = (half)(((float)(( qs16.s1 & 0x000F) | ((uint)(( qh16 >> 8) & 0x3) << 4)) - 32.f) * scale); \
18
+ a_f16.s5 = (half)(((float)((( qs16.s1 >> 4) & 0x000F) | ((uint)(( qh16 >> 10) & 0x3) << 4)) - 32.f) * scale); \
19
+ a_f16.s6 = (half)(((float)((( qs16.s1 >> 8) & 0x000F) | ((uint)(( qh16 >> 12) & 0x3) << 4)) - 32.f) * scale); \
20
+ a_f16.s7 = (half)(((float)((( qs16.s1 >>12) & 0x000F) | ((uint)(( qh16 >> 14) & 0x3) << 4)) - 32.f) * scale); \
21
+ a_f16.s8 = (half)(((float)(( qs16.s2 & 0x000F) | ((uint)(( qh16 >> 16) & 0x3) << 4)) - 32.f) * scale); \
22
+ a_f16.s9 = (half)(((float)((( qs16.s2 >> 4) & 0x000F) | ((uint)(( qh16 >> 18) & 0x3) << 4)) - 32.f) * scale); \
23
+ a_f16.sa = (half)(((float)((( qs16.s2 >> 8) & 0x000F) | ((uint)(( qh16 >> 20) & 0x3) << 4)) - 32.f) * scale); \
24
+ a_f16.sb = (half)(((float)((( qs16.s2 >>12) & 0x000F) | ((uint)(( qh16 >> 22) & 0x3) << 4)) - 32.f) * scale); \
25
+ a_f16.sc = (half)(((float)(( qs16.s3 & 0x000F) | ((uint)(( qh16 >> 24) & 0x3) << 4)) - 32.f) * scale); \
26
+ a_f16.sd = (half)(((float)((( qs16.s3 >> 4) & 0x000F) | ((uint)(( qh16 >> 26) & 0x3) << 4)) - 32.f) * scale); \
27
+ a_f16.se = (half)(((float)((( qs16.s3 >> 8) & 0x000F) | ((uint)(( qh16 >> 28) & 0x3) << 4)) - 32.f) * scale); \
28
+ a_f16.sf = (half)(((float)((( qs16.s3 >>12) & 0x000F) | ((uint)(( qh16 >> 30) & 0x3) << 4)) - 32.f) * scale); \
29
+
30
+
31
+ #define dotx16_reduce8(a_reg, b_lm, c_reg, lm_offset) \
32
+ acc.s0 = dot(a_reg.s0123, b_lm[lm_offset + 0]); \
33
+ acc.s1 = dot(a_reg.s0123, b_lm[lm_offset + 1]); \
34
+ acc.s2 = dot(a_reg.s0123, b_lm[lm_offset + 2]); \
35
+ acc.s3 = dot(a_reg.s0123, b_lm[lm_offset + 3]); \
36
+ acc.s4 = dot(a_reg.s0123, b_lm[lm_offset + 4]); \
37
+ acc.s5 = dot(a_reg.s0123, b_lm[lm_offset + 5]); \
38
+ acc.s6 = dot(a_reg.s0123, b_lm[lm_offset + 6]); \
39
+ acc.s7 = dot(a_reg.s0123, b_lm[lm_offset + 7]); \
40
+ acc.s8 = dot(a_reg.s0123, b_lm[lm_offset + 8]); \
41
+ acc.s9 = dot(a_reg.s0123, b_lm[lm_offset + 9]); \
42
+ acc.sa = dot(a_reg.s0123, b_lm[lm_offset + 10]); \
43
+ acc.sb = dot(a_reg.s0123, b_lm[lm_offset + 11]); \
44
+ acc.sc = dot(a_reg.s0123, b_lm[lm_offset + 12]); \
45
+ acc.sd = dot(a_reg.s0123, b_lm[lm_offset + 13]); \
46
+ acc.se = dot(a_reg.s0123, b_lm[lm_offset + 14]); \
47
+ acc.sf = dot(a_reg.s0123, b_lm[lm_offset + 15]); \
48
+ acc.s0 += dot(a_reg.s4567, b_lm[lm_offset + 32]); \
49
+ acc.s1 += dot(a_reg.s4567, b_lm[lm_offset + 33]); \
50
+ acc.s2 += dot(a_reg.s4567, b_lm[lm_offset + 34]); \
51
+ acc.s3 += dot(a_reg.s4567, b_lm[lm_offset + 35]); \
52
+ acc.s4 += dot(a_reg.s4567, b_lm[lm_offset + 36]); \
53
+ acc.s5 += dot(a_reg.s4567, b_lm[lm_offset + 37]); \
54
+ acc.s6 += dot(a_reg.s4567, b_lm[lm_offset + 38]); \
55
+ acc.s7 += dot(a_reg.s4567, b_lm[lm_offset + 39]); \
56
+ acc.s8 += dot(a_reg.s4567, b_lm[lm_offset + 40]); \
57
+ acc.s9 += dot(a_reg.s4567, b_lm[lm_offset + 41]); \
58
+ acc.sa += dot(a_reg.s4567, b_lm[lm_offset + 42]); \
59
+ acc.sb += dot(a_reg.s4567, b_lm[lm_offset + 43]); \
60
+ acc.sc += dot(a_reg.s4567, b_lm[lm_offset + 44]); \
61
+ acc.sd += dot(a_reg.s4567, b_lm[lm_offset + 45]); \
62
+ acc.se += dot(a_reg.s4567, b_lm[lm_offset + 46]); \
63
+ acc.sf += dot(a_reg.s4567, b_lm[lm_offset + 47]); \
64
+ c_reg.lo += convert_float8(acc.lo); \
65
+ c_reg.hi += convert_float8(acc.hi); \
66
+ acc.s0 = dot(a_reg.s89ab, b_lm[lm_offset + 64]); \
67
+ acc.s1 = dot(a_reg.s89ab, b_lm[lm_offset + 65]); \
68
+ acc.s2 = dot(a_reg.s89ab, b_lm[lm_offset + 66]); \
69
+ acc.s3 = dot(a_reg.s89ab, b_lm[lm_offset + 67]); \
70
+ acc.s4 = dot(a_reg.s89ab, b_lm[lm_offset + 68]); \
71
+ acc.s5 = dot(a_reg.s89ab, b_lm[lm_offset + 69]); \
72
+ acc.s6 = dot(a_reg.s89ab, b_lm[lm_offset + 70]); \
73
+ acc.s7 = dot(a_reg.s89ab, b_lm[lm_offset + 71]); \
74
+ acc.s8 = dot(a_reg.s89ab, b_lm[lm_offset + 72]); \
75
+ acc.s9 = dot(a_reg.s89ab, b_lm[lm_offset + 73]); \
76
+ acc.sa = dot(a_reg.s89ab, b_lm[lm_offset + 74]); \
77
+ acc.sb = dot(a_reg.s89ab, b_lm[lm_offset + 75]); \
78
+ acc.sc = dot(a_reg.s89ab, b_lm[lm_offset + 76]); \
79
+ acc.sd = dot(a_reg.s89ab, b_lm[lm_offset + 77]); \
80
+ acc.se = dot(a_reg.s89ab, b_lm[lm_offset + 78]); \
81
+ acc.sf = dot(a_reg.s89ab, b_lm[lm_offset + 79]); \
82
+ acc.s0 += dot(a_reg.scdef, b_lm[lm_offset + 96]); \
83
+ acc.s1 += dot(a_reg.scdef, b_lm[lm_offset + 97]); \
84
+ acc.s2 += dot(a_reg.scdef, b_lm[lm_offset + 98]); \
85
+ acc.s3 += dot(a_reg.scdef, b_lm[lm_offset + 99]); \
86
+ acc.s4 += dot(a_reg.scdef, b_lm[lm_offset + 100]); \
87
+ acc.s5 += dot(a_reg.scdef, b_lm[lm_offset + 101]); \
88
+ acc.s6 += dot(a_reg.scdef, b_lm[lm_offset + 102]); \
89
+ acc.s7 += dot(a_reg.scdef, b_lm[lm_offset + 103]); \
90
+ acc.s8 += dot(a_reg.scdef, b_lm[lm_offset + 104]); \
91
+ acc.s9 += dot(a_reg.scdef, b_lm[lm_offset + 105]); \
92
+ acc.sa += dot(a_reg.scdef, b_lm[lm_offset + 106]); \
93
+ acc.sb += dot(a_reg.scdef, b_lm[lm_offset + 107]); \
94
+ acc.sc += dot(a_reg.scdef, b_lm[lm_offset + 108]); \
95
+ acc.sd += dot(a_reg.scdef, b_lm[lm_offset + 109]); \
96
+ acc.se += dot(a_reg.scdef, b_lm[lm_offset + 110]); \
97
+ acc.sf += dot(a_reg.scdef, b_lm[lm_offset + 111]); \
98
+ c_reg.lo += convert_float8(acc.lo); \
99
+ c_reg.hi += convert_float8(acc.hi); \
100
+
101
+ // Quarter-tile variant: computes 8 output columns (one skip-group) into a float8
102
+ // accumulator. Same reduction order / flush cadence as dotx16_reduce8, so the
103
+ // non-skipped path is byte-identical; it just lets the caller skip empty
104
+ // 8-column groups at finer granularity. Uses a private half8 `acc8`.
105
+ #define dotx8_reduce4(a_reg, b_lm, c_reg, lm_offset) \
106
+ acc8.s0 = dot(a_reg.s0123, b_lm[lm_offset + 0]); \
107
+ acc8.s1 = dot(a_reg.s0123, b_lm[lm_offset + 1]); \
108
+ acc8.s2 = dot(a_reg.s0123, b_lm[lm_offset + 2]); \
109
+ acc8.s3 = dot(a_reg.s0123, b_lm[lm_offset + 3]); \
110
+ acc8.s4 = dot(a_reg.s0123, b_lm[lm_offset + 4]); \
111
+ acc8.s5 = dot(a_reg.s0123, b_lm[lm_offset + 5]); \
112
+ acc8.s6 = dot(a_reg.s0123, b_lm[lm_offset + 6]); \
113
+ acc8.s7 = dot(a_reg.s0123, b_lm[lm_offset + 7]); \
114
+ acc8.s0 += dot(a_reg.s4567, b_lm[lm_offset + 32]); \
115
+ acc8.s1 += dot(a_reg.s4567, b_lm[lm_offset + 33]); \
116
+ acc8.s2 += dot(a_reg.s4567, b_lm[lm_offset + 34]); \
117
+ acc8.s3 += dot(a_reg.s4567, b_lm[lm_offset + 35]); \
118
+ acc8.s4 += dot(a_reg.s4567, b_lm[lm_offset + 36]); \
119
+ acc8.s5 += dot(a_reg.s4567, b_lm[lm_offset + 37]); \
120
+ acc8.s6 += dot(a_reg.s4567, b_lm[lm_offset + 38]); \
121
+ acc8.s7 += dot(a_reg.s4567, b_lm[lm_offset + 39]); \
122
+ c_reg += convert_float8(acc8); \
123
+ acc8.s0 = dot(a_reg.s89ab, b_lm[lm_offset + 64]); \
124
+ acc8.s1 = dot(a_reg.s89ab, b_lm[lm_offset + 65]); \
125
+ acc8.s2 = dot(a_reg.s89ab, b_lm[lm_offset + 66]); \
126
+ acc8.s3 = dot(a_reg.s89ab, b_lm[lm_offset + 67]); \
127
+ acc8.s4 = dot(a_reg.s89ab, b_lm[lm_offset + 68]); \
128
+ acc8.s5 = dot(a_reg.s89ab, b_lm[lm_offset + 69]); \
129
+ acc8.s6 = dot(a_reg.s89ab, b_lm[lm_offset + 70]); \
130
+ acc8.s7 = dot(a_reg.s89ab, b_lm[lm_offset + 71]); \
131
+ acc8.s0 += dot(a_reg.scdef, b_lm[lm_offset + 96]); \
132
+ acc8.s1 += dot(a_reg.scdef, b_lm[lm_offset + 97]); \
133
+ acc8.s2 += dot(a_reg.scdef, b_lm[lm_offset + 98]); \
134
+ acc8.s3 += dot(a_reg.scdef, b_lm[lm_offset + 99]); \
135
+ acc8.s4 += dot(a_reg.scdef, b_lm[lm_offset + 100]); \
136
+ acc8.s5 += dot(a_reg.scdef, b_lm[lm_offset + 101]); \
137
+ acc8.s6 += dot(a_reg.scdef, b_lm[lm_offset + 102]); \
138
+ acc8.s7 += dot(a_reg.scdef, b_lm[lm_offset + 103]); \
139
+ c_reg += convert_float8(acc8); \
140
+
141
+
142
+ __attribute__((qcom_wave_pair_mode(1)))
143
+ kernel void kernel_gemm_moe_q6_k_f32_ns(
144
+ __read_only image1d_buffer_t src0_ql,
145
+ __global uint * src0_qh,
146
+ __global char * src0_s,
147
+ __global half * src0_d,
148
+ __read_only image1d_buffer_t src1,
149
+ __global uint * src2,
150
+ __global ushort * src2_emap,
151
+ __write_only image1d_buffer_t dst,
152
+ __global int * total_tiles,
153
+ uint ne00,
154
+ uint ne01,
155
+ uint is_ragged,
156
+ uint skip_gran
157
+ ) {
158
+ uint block_id_m = get_global_id(1); // m_tile
159
+ uint block_id_n = get_global_id(2); // n_tile
160
+
161
+ // Boundary check
162
+ if (block_id_n >= total_tiles[0]) {
163
+ return;
164
+ }
165
+
166
+ // Ragged tile-skip: when is_ragged and the upper 16 token-slots of this tile are all
167
+ // padding (router 0xFFFFFFFF), skip the second (reg_c.hi) dotx16_reduce8 half -> ~half
168
+ // the GEMM dot for sparse tiles. Numerically identical (the skipped lanes are padding).
169
+ // Ragged tile-skip: tokens are packed contiguously per expert (moe_scatter fills
170
+ // lanes 0..V-1, moe_fill pre-pads the rest), so router padding (0xFFFFFFFF) is always
171
+ // trailing. Find the valid-token count V and round it UP to the skip granularity
172
+ // skip_gran (columns per skip-group: 8 = quarter, 16 = half/legacy, 32 = disabled).
173
+ // A 8-column group g is all-padding iff its first column (8*g) >= n_active, so its
174
+ // dotx8_reduce4 is skipped. Numerically identical (skipped lanes are padding).
175
+ uint n_active = TILESIZE_N;
176
+ if (is_ragged && skip_gran < TILESIZE_N) {
177
+ uint n_valid = TILESIZE_N;
178
+ for (uint _t = 0; _t < TILESIZE_N; ++_t) {
179
+ if (src2[block_id_n * TILESIZE_N + _t] == 0xFFFFFFFFu) { n_valid = _t; break; }
180
+ }
181
+ n_active = min((uint)TILESIZE_N, ((n_valid + skip_gran - 1) / skip_gran) * skip_gran);
182
+ }
183
+ // Group 0 (cols 0-7) always runs; groups 1-3 skip when fully padding.
184
+ bool skip_g1 = (8u >= n_active);
185
+ bool skip_g2 = (16u >= n_active);
186
+ bool skip_g3 = (24u >= n_active);
187
+
188
+ __private half16 reg_a;
189
+ __private float32 reg_c = (float32)(0);
190
+ __local half4 shared_b[128];
191
+
192
+ const ushort expert_id = src2_emap[block_id_n];
193
+
194
+ const uint row = block_id_m * TILESIZE_M;
195
+ const uint col = block_id_n * TILESIZE_N;
196
+
197
+ uint sub_block_id_m = get_local_id(0);
198
+ uint2 b_global_offset;
199
+ b_global_offset.x = ((sub_block_id_m & 3) << 2) + (sub_block_id_m >> 2) * ne00;
200
+ b_global_offset.y = b_global_offset.x + (16 * ne00);
201
+ uint2 b_local_offset;
202
+ b_local_offset.x = (sub_block_id_m & 3) * 32 + (sub_block_id_m >> 2);
203
+ b_local_offset.y = b_local_offset.x + 16;
204
+
205
+ uint num_superblocks = ne00 / QK_K;
206
+ uint scales_per_row = num_superblocks * 16;
207
+ uint row_idx = row + get_global_id(0);
208
+
209
+ // Loop along K axis, 32 elements per iteration (one sub-block), divided into 2 halves of 16
210
+ for (uint step = 0; step < ne00; step += TILESIZE_K * 2) {
211
+ uint sub = step / 32; // 32-element group index
212
+ uint sb = sub / 8; // super-block index
213
+ uint j = sub % 8; // group within super-block
214
+
215
+ // Load d for super-block
216
+ uint d_offset = row + sb * ne01 + expert_id * num_superblocks * ne01 + get_global_id(0);
217
+ half d_val = src0_d[d_offset];
218
+
219
+ // Load sub-block scales
220
+ global const char * sc = src0_s + (expert_id * ne01 + row_idx) * scales_per_row + sb * 16;
221
+ float scale0 = (float)d_val * (float)sc[j * 2];
222
+ float scale1 = (float)d_val * (float)sc[j * 2 + 1];
223
+
224
+ uint qh_base = row + (sub * 2) * ne01 + expert_id * (num_superblocks * 16) * ne01 + get_global_id(0);
225
+ uint qh_first16 = src0_qh[qh_base];
226
+ uint qh_second16 = src0_qh[qh_base + ne01];
227
+
228
+ // First half (16 elements)
229
+ uint q_sub_offset = row + ((ne01 * step) >> 3) + ((expert_id * ne00 * ne01) >> 3);
230
+ uint b_sub_offset = col * ne00 + step;
231
+
232
+ // Load 16 ql nibbles (2 uints) from image
233
+ uint2 q4x16;
234
+ q4x16.x = read_imageui(src0_ql, q_sub_offset + sub_block_id_m).x;
235
+ q4x16.y = read_imageui(src0_ql, q_sub_offset + sub_block_id_m + ne01).x;
236
+
237
+ // Load 16x32 floats from matrix B
238
+ float8 bx8_f32;
239
+ bx8_f32.lo = read_imagef(src1, (b_sub_offset + b_global_offset.x) / 4);
240
+ bx8_f32.hi = read_imagef(src1, (b_sub_offset + b_global_offset.y) / 4);
241
+ half8 bx8_f16 = convert_half8(bx8_f32);
242
+ shared_b[b_local_offset.x] = bx8_f16.lo;
243
+ shared_b[b_local_offset.y] = bx8_f16.hi;
244
+
245
+ // Dequantize first 16 elements (scale0)
246
+ dequantize_q6_k(as_ushort4(q4x16), qh_first16, reg_a, scale0);
247
+
248
+ sub_group_barrier(CLK_LOCAL_MEM_FENCE);
249
+
250
+ half8 acc8;
251
+ dotx8_reduce4(reg_a, shared_b, reg_c.lo.lo, 0);
252
+ if (!skip_g1) { dotx8_reduce4(reg_a, shared_b, reg_c.lo.hi, 8); }
253
+ if (!skip_g2) { dotx8_reduce4(reg_a, shared_b, reg_c.hi.lo, 16); }
254
+ if (!skip_g3) { dotx8_reduce4(reg_a, shared_b, reg_c.hi.hi, 24); }
255
+
256
+ // Second half
257
+ uint half_step = step + TILESIZE_K;
258
+ q_sub_offset = row + ((ne01 * half_step) >> 3) + ((expert_id * ne00 * ne01) >> 3);
259
+ b_sub_offset = col * ne00 + half_step;
260
+
261
+ q4x16.x = read_imageui(src0_ql, q_sub_offset + sub_block_id_m).x;
262
+ q4x16.y = read_imageui(src0_ql, q_sub_offset + sub_block_id_m + ne01).x;
263
+
264
+ bx8_f32.lo = read_imagef(src1, (b_sub_offset + b_global_offset.x) / 4);
265
+ bx8_f32.hi = read_imagef(src1, (b_sub_offset + b_global_offset.y) / 4);
266
+ bx8_f16 = convert_half8(bx8_f32);
267
+ shared_b[b_local_offset.x] = bx8_f16.lo;
268
+ shared_b[b_local_offset.y] = bx8_f16.hi;
269
+
270
+ dequantize_q6_k(as_ushort4(q4x16), qh_second16, reg_a, scale1);
271
+
272
+ sub_group_barrier(CLK_LOCAL_MEM_FENCE);
273
+
274
+ dotx8_reduce4(reg_a, shared_b, reg_c.lo.lo, 0);
275
+ if (!skip_g1) { dotx8_reduce4(reg_a, shared_b, reg_c.lo.hi, 8); }
276
+ if (!skip_g2) { dotx8_reduce4(reg_a, shared_b, reg_c.hi.lo, 16); }
277
+ if (!skip_g3) { dotx8_reduce4(reg_a, shared_b, reg_c.hi.hi, 24); }
278
+ }
279
+
280
+ if ((get_global_id(0) + block_id_m * TILESIZE_M) >= ne01) {
281
+ return;
282
+ }
283
+
284
+ // Load post router and share in LM
285
+ __local uint out_idx[TILESIZE_N];
286
+
287
+ if (get_local_id(0) < TILESIZE_N) {
288
+ uint idx = src2[block_id_n * TILESIZE_N + get_local_id(0)];
289
+ if (idx == 0xFFFFFFFF) {
290
+ idx = src2[block_id_n * TILESIZE_N + 0];
291
+ }
292
+ out_idx[get_local_id(0)] = idx * ne01;
293
+ }
294
+
295
+ barrier(CLK_LOCAL_MEM_FENCE);
296
+
297
+ // Scatter results back to original position in output grid
298
+ uint m_offset = row + get_local_id(0);
299
+
300
+ write_imagef(dst, out_idx[1] + m_offset, (reg_c.s1));
301
+ write_imagef(dst, out_idx[2] + m_offset, (reg_c.s2));
302
+ write_imagef(dst, out_idx[3] + m_offset, (reg_c.s3));
303
+ write_imagef(dst, out_idx[4] + m_offset, (reg_c.s4));
304
+ write_imagef(dst, out_idx[5] + m_offset, (reg_c.s5));
305
+ write_imagef(dst, out_idx[6] + m_offset, (reg_c.s6));
306
+ write_imagef(dst, out_idx[7] + m_offset, (reg_c.s7));
307
+ write_imagef(dst, out_idx[8] + m_offset, (reg_c.s8));
308
+ write_imagef(dst, out_idx[9] + m_offset, (reg_c.s9));
309
+ write_imagef(dst, out_idx[10] + m_offset, (reg_c.sa));
310
+ write_imagef(dst, out_idx[11] + m_offset, (reg_c.sb));
311
+ write_imagef(dst, out_idx[12] + m_offset, (reg_c.sc));
312
+ write_imagef(dst, out_idx[13] + m_offset, (reg_c.sd));
313
+ write_imagef(dst, out_idx[14] + m_offset, (reg_c.se));
314
+ write_imagef(dst, out_idx[15] + m_offset, (reg_c.sf));
315
+ write_imagef(dst, out_idx[16] + m_offset, (reg_c.sg));
316
+ write_imagef(dst, out_idx[17] + m_offset, (reg_c.sh));
317
+ write_imagef(dst, out_idx[18] + m_offset, (reg_c.si));
318
+ write_imagef(dst, out_idx[19] + m_offset, (reg_c.sj));
319
+ write_imagef(dst, out_idx[20] + m_offset, (reg_c.sk));
320
+ write_imagef(dst, out_idx[21] + m_offset, (reg_c.sl));
321
+ write_imagef(dst, out_idx[22] + m_offset, (reg_c.sm));
322
+ write_imagef(dst, out_idx[23] + m_offset, (reg_c.sn));
323
+ write_imagef(dst, out_idx[24] + m_offset, (reg_c.so));
324
+ write_imagef(dst, out_idx[25] + m_offset, (reg_c.sp));
325
+ write_imagef(dst, out_idx[26] + m_offset, (reg_c.sq));
326
+ write_imagef(dst, out_idx[27] + m_offset, (reg_c.sr));
327
+ write_imagef(dst, out_idx[28] + m_offset, (reg_c.ss));
328
+ write_imagef(dst, out_idx[29] + m_offset, (reg_c.st));
329
+ write_imagef(dst, out_idx[30] + m_offset, (reg_c.su));
330
+ write_imagef(dst, out_idx[31] + m_offset, (reg_c.sv));
331
+
332
+ // Store zero padding parts to the index of first output in tile
333
+ barrier(CLK_GLOBAL_MEM_FENCE);
334
+ write_imagef(dst, out_idx[0] + m_offset, (reg_c.s0));
335
+ }
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_moe_q6_k_q8_1_dp4a.cl ADDED
@@ -0,0 +1,196 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #pragma OPENCL EXTENSION cl_khr_fp16 : enable
2
+ #pragma OPENCL EXTENSION cl_khr_subgroups : enable
3
+ #ifdef cl_khr_integer_dot_product
4
+ #pragma OPENCL EXTENSION cl_khr_integer_dot_product : enable
5
+ #endif
6
+
7
+ #define TILESIZE_N 32
8
+ #define QK_K 256
9
+
10
+ // 4 nibbles in the low 16 bits of `u` -> 4 bytes (value 0..15, in bits 0-3).
11
+ #define EXP4(u) ( ((uint)((u) & 0x000Fu)) | \
12
+ (((uint)((u) & 0x00F0u)) << 4) | \
13
+ (((uint)((u) & 0x0F00u)) << 8) | \
14
+ (((uint)((u) & 0xF000u)) << 12) )
15
+
16
+ // 4 2-bit highs in byte `b` (8 bits) -> 4 bytes, value 0..3 in bits 4-5
17
+ // (pre-multiplied by 16 so it ORs with the EXP4 nibble to form q6 in 0..63).
18
+ #define EXP2(b) ( (((uint)((b) & 0x03u)) << 4) | \
19
+ (((uint)((b) & 0x0Cu)) << 10) | \
20
+ (((uint)((b) & 0x30u)) << 16) | \
21
+ (((uint)((b) & 0xC0u)) << 22) )
22
+
23
+ // q6 (0..63, bits 0-5 of each byte) -> (q6-32) as a signed int8 per byte.
24
+ // Flipping bit5 subtracts 32 in 6-bit two's complement; then replicate bit5
25
+ // into bits 6-7 to sign-extend to int8. Per-byte, no inter-byte carry.
26
+ inline uint SIGN6(uint q6p) {
27
+ uint x = q6p ^ 0x20202020u;
28
+ uint s = x & 0x20202020u;
29
+ return x | (s << 1) | (s << 2);
30
+ }
31
+
32
+ inline int dp4a_q6(uint qw0, uint qw1, uint qw2, uint qw3,
33
+ uint a0, uint a1, uint a2, uint a3) {
34
+ int raw = 0;
35
+ raw = dot_acc_sat_4x8packed_ss_int(qw0, a0, raw);
36
+ raw = dot_acc_sat_4x8packed_ss_int(qw1, a1, raw);
37
+ raw = dot_acc_sat_4x8packed_ss_int(qw2, a2, raw);
38
+ raw = dot_acc_sat_4x8packed_ss_int(qw3, a3, raw);
39
+ return raw;
40
+ }
41
+
42
+ // One token's q6_K dp4a dot (two halves, per-16 scales) + epilogue into acc[t].
43
+ #define MOE_Q6K_DP4A_T(t) do { \
44
+ const int raw1 = dp4a_q6(qw[0], qw[1], qw[2], qw[3], sh_qa[t][0], sh_qa[t][1], sh_qa[t][2], sh_qa[t][3]); \
45
+ const int raw2 = dp4a_q6(qw[4], qw[5], qw[6], qw[7], sh_qa[t][4], sh_qa[t][5], sh_qa[t][6], sh_qa[t][7]); \
46
+ const float a_d = (float)sh_d[t]; \
47
+ acc[t] += scale0 * a_d * (float)raw1 + scale1 * a_d * (float)raw2; \
48
+ } while (0)
49
+
50
+ __attribute__((qcom_wave_pair_mode(1)))
51
+ kernel void kernel_gemm_moe_q6_k_q8_1_dp4a(
52
+ __read_only image1d_buffer_t src0_ql, // q6_K low nibbles (image, q4_K-style layout)
53
+ __global uint * src0_qh, // q6_K high 2-bit (16 elems/uint)
54
+ __global char * src0_s, // int8 scales (one per 16 elems)
55
+ __global half * src0_d, // per-superblock scale
56
+ __global uint * src1_qa, // q8_1 activations int8 (as uint, 4/elem)
57
+ __global half * src1_da, // q8_1 per-block scale [tok_slot * ne00/32]
58
+ __global uint * src2, // post-router (orig out positions)
59
+ __global ushort * src2_emap, // tile -> expert id
60
+ __write_only image1d_buffer_t dst,
61
+ __global int * total_tiles,
62
+ uint ne00,
63
+ uint ne01,
64
+ int is_ragged // 1: compute only real tokens per tile
65
+ ) {
66
+ const uint block_id_m = get_global_id(1);
67
+ const uint block_id_n = get_global_id(2);
68
+
69
+ if (block_id_n >= total_tiles[0]) {
70
+ return;
71
+ }
72
+
73
+ const uint lid = get_local_id(0); // 0..63 -> row within M-tile
74
+
75
+ const ushort expert_id = src2_emap[block_id_n];
76
+ const uint row = block_id_m * 64;
77
+ const uint col = block_id_n * TILESIZE_N;
78
+
79
+ const uint num_superblocks = ne00 / QK_K;
80
+ const uint scales_per_row = num_superblocks * 16;
81
+ const uint row_idx = row + lid;
82
+
83
+ const uint ne00_u = ne00 >> 2;
84
+ const uint ne00_b = ne00 >> 5;
85
+
86
+ __local uint sh_qa[TILESIZE_N][8];
87
+ __local half sh_d[TILESIZE_N];
88
+
89
+ // Real token count for this tile
90
+ __local uint sh_src2[TILESIZE_N];
91
+ __local int sh_nreal;
92
+ if (lid < TILESIZE_N) {
93
+ sh_src2[lid] = src2[col + lid];
94
+ }
95
+ barrier(CLK_LOCAL_MEM_FENCE);
96
+ if (lid == 0) {
97
+ int nr = TILESIZE_N;
98
+ if (is_ragged) {
99
+ nr = 0;
100
+ #pragma unroll
101
+ for (int t = 0; t < TILESIZE_N; ++t) {
102
+ if (sh_src2[t] != 0xFFFFFFFFu) ++nr;
103
+ }
104
+ }
105
+ sh_nreal = nr;
106
+ }
107
+ barrier(CLK_LOCAL_MEM_FENCE);
108
+ const int n_real = sh_nreal;
109
+
110
+ float acc[TILESIZE_N];
111
+ #pragma unroll
112
+ for (int t = 0; t < TILESIZE_N; ++t) acc[t] = 0.0f;
113
+
114
+ for (uint step = 0; step < ne00; step += 32) {
115
+ const uint sub = step >> 5;
116
+ const uint sb = sub >> 3;
117
+ const uint j = sub & 7;
118
+
119
+ const float d_val = (float)src0_d[row + sb * ne01 + expert_id * num_superblocks * ne01 + lid];
120
+ global const char * sc = src0_s + (expert_id * ne01 + row_idx) * scales_per_row + sb * 16;
121
+ const float scale0 = d_val * (float)sc[j * 2];
122
+ const float scale1 = d_val * (float)sc[j * 2 + 1];
123
+
124
+ // high bits: one uint covers 16 elems; first/second 16 of this 32-block
125
+ const uint qh_base = row + (sub * 2) * ne01 + expert_id * (num_superblocks * 16) * ne01 + lid;
126
+ const uint qh1 = src0_qh[qh_base];
127
+ const uint qh2 = src0_qh[qh_base + ne01];
128
+
129
+ // low nibbles: same image layout as q4_K (8 ushorts over the 32 K)
130
+ const uint qoff0 = row + ((ne01 * step) >> 3) + ((expert_id * ne00 * ne01) >> 3);
131
+ const uint qoff1 = row + ((ne01 * (step + 16)) >> 3) + ((expert_id * ne00 * ne01) >> 3);
132
+ const uint r0 = read_imageui(src0_ql, qoff0 + lid).x;
133
+ const uint r1 = read_imageui(src0_ql, qoff0 + lid + ne01).x;
134
+ const uint r2 = read_imageui(src0_ql, qoff1 + lid).x;
135
+ const uint r3 = read_imageui(src0_ql, qoff1 + lid + ne01).x;
136
+
137
+ uint qw[8];
138
+ qw[0] = SIGN6(EXP4(r0) | EXP2((qh1) & 0xFFu));
139
+ qw[1] = SIGN6(EXP4(r0 >> 16) | EXP2((qh1 >> 8) & 0xFFu));
140
+ qw[2] = SIGN6(EXP4(r1) | EXP2((qh1 >> 16) & 0xFFu));
141
+ qw[3] = SIGN6(EXP4(r1 >> 16) | EXP2((qh1 >> 24) & 0xFFu));
142
+ qw[4] = SIGN6(EXP4(r2) | EXP2((qh2) & 0xFFu));
143
+ qw[5] = SIGN6(EXP4(r2 >> 16) | EXP2((qh2 >> 8) & 0xFFu));
144
+ qw[6] = SIGN6(EXP4(r3) | EXP2((qh2 >> 16) & 0xFFu));
145
+ qw[7] = SIGN6(EXP4(r3 >> 16) | EXP2((qh2 >> 24) & 0xFFu));
146
+
147
+ const uint stage_lim = (uint)n_real * 8;
148
+ for (uint idx = lid; idx < stage_lim; idx += 64) {
149
+ const uint t = idx >> 3;
150
+ const uint u = idx & 7;
151
+ sh_qa[t][u] = src1_qa[(col + t) * ne00_u + (step >> 2) + u];
152
+ }
153
+ if (lid < (uint)n_real) {
154
+ sh_d[lid] = src1_da[(col + lid) * ne00_b + sub];
155
+ }
156
+ barrier(CLK_LOCAL_MEM_FENCE);
157
+
158
+ // Full tiles keep the fully-unrolled 32-wide loop; partial tiles run n_real.
159
+ if (n_real == TILESIZE_N) {
160
+ #pragma unroll
161
+ for (int t = 0; t < TILESIZE_N; ++t) { MOE_Q6K_DP4A_T(t); }
162
+ } else {
163
+ #pragma unroll 4
164
+ for (int t = 0; t < n_real; ++t) { MOE_Q6K_DP4A_T(t); }
165
+ }
166
+ barrier(CLK_LOCAL_MEM_FENCE);
167
+ }
168
+
169
+ if (row_idx >= ne01) {
170
+ return;
171
+ }
172
+
173
+ __local uint out_idx[TILESIZE_N];
174
+ if (lid < TILESIZE_N) {
175
+ uint idx = sh_src2[lid];
176
+ if (idx == 0xFFFFFFFF) {
177
+ idx = sh_src2[0];
178
+ }
179
+ out_idx[lid] = idx * ne01;
180
+ }
181
+ barrier(CLK_LOCAL_MEM_FENCE);
182
+
183
+ const uint m_offset = row + lid;
184
+ if (n_real == TILESIZE_N) {
185
+ #pragma unroll
186
+ for (int t = 1; t < TILESIZE_N; ++t) {
187
+ write_imagef(dst, out_idx[t] + m_offset, acc[t]);
188
+ }
189
+ barrier(CLK_GLOBAL_MEM_FENCE);
190
+ write_imagef(dst, out_idx[0] + m_offset, acc[0]);
191
+ } else {
192
+ for (int t = 0; t < n_real; ++t) {
193
+ write_imagef(dst, out_idx[t] + m_offset, acc[t]);
194
+ }
195
+ }
196
+ }
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_moe_q8_0_f32_ns.cl ADDED
@@ -0,0 +1,221 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #pragma OPENCL EXTENSION cl_khr_fp16 : enable
2
+ #pragma OPENCL EXTENSION cl_khr_subgroups : enable
3
+ #pragma OPENCL EXTENSION cl_qcom_subgroup_uniform_load: enable
4
+ #pragma OPENCL EXTENSION cl_qcom_subgroup_constant_load: enable
5
+ #pragma OPENCL EXTENSION cl_qcom_extra_vector_types : enable
6
+
7
+ #define TILESIZE_K 16
8
+ #define TILESIZE_M 64
9
+ #define TILESIZE_N 32
10
+
11
+ // q8_0: 16 signed int8 weights (one uint4 = 16 chars) -> half16, scaled.
12
+ #define dequantize_q8_0(q4, a_f16, scale) \
13
+ a_f16 = convert_half16(as_char16(q4)) * scale;
14
+
15
+ #define dotx16_reduce8(a_reg, b_lm, c_reg, lm_offset) \
16
+ acc.s0 = dot(a_reg.s0123, b_lm[lm_offset + 0]); \
17
+ acc.s1 = dot(a_reg.s0123, b_lm[lm_offset + 1]); \
18
+ acc.s2 = dot(a_reg.s0123, b_lm[lm_offset + 2]); \
19
+ acc.s3 = dot(a_reg.s0123, b_lm[lm_offset + 3]); \
20
+ acc.s4 = dot(a_reg.s0123, b_lm[lm_offset + 4]); \
21
+ acc.s5 = dot(a_reg.s0123, b_lm[lm_offset + 5]); \
22
+ acc.s6 = dot(a_reg.s0123, b_lm[lm_offset + 6]); \
23
+ acc.s7 = dot(a_reg.s0123, b_lm[lm_offset + 7]); \
24
+ acc.s8 = dot(a_reg.s0123, b_lm[lm_offset + 8]); \
25
+ acc.s9 = dot(a_reg.s0123, b_lm[lm_offset + 9]); \
26
+ acc.sa = dot(a_reg.s0123, b_lm[lm_offset + 10]); \
27
+ acc.sb = dot(a_reg.s0123, b_lm[lm_offset + 11]); \
28
+ acc.sc = dot(a_reg.s0123, b_lm[lm_offset + 12]); \
29
+ acc.sd = dot(a_reg.s0123, b_lm[lm_offset + 13]); \
30
+ acc.se = dot(a_reg.s0123, b_lm[lm_offset + 14]); \
31
+ acc.sf = dot(a_reg.s0123, b_lm[lm_offset + 15]); \
32
+ acc.s0 += dot(a_reg.s4567, b_lm[lm_offset + 32]); \
33
+ acc.s1 += dot(a_reg.s4567, b_lm[lm_offset + 33]); \
34
+ acc.s2 += dot(a_reg.s4567, b_lm[lm_offset + 34]); \
35
+ acc.s3 += dot(a_reg.s4567, b_lm[lm_offset + 35]); \
36
+ acc.s4 += dot(a_reg.s4567, b_lm[lm_offset + 36]); \
37
+ acc.s5 += dot(a_reg.s4567, b_lm[lm_offset + 37]); \
38
+ acc.s6 += dot(a_reg.s4567, b_lm[lm_offset + 38]); \
39
+ acc.s7 += dot(a_reg.s4567, b_lm[lm_offset + 39]); \
40
+ acc.s8 += dot(a_reg.s4567, b_lm[lm_offset + 40]); \
41
+ acc.s9 += dot(a_reg.s4567, b_lm[lm_offset + 41]); \
42
+ acc.sa += dot(a_reg.s4567, b_lm[lm_offset + 42]); \
43
+ acc.sb += dot(a_reg.s4567, b_lm[lm_offset + 43]); \
44
+ acc.sc += dot(a_reg.s4567, b_lm[lm_offset + 44]); \
45
+ acc.sd += dot(a_reg.s4567, b_lm[lm_offset + 45]); \
46
+ acc.se += dot(a_reg.s4567, b_lm[lm_offset + 46]); \
47
+ acc.sf += dot(a_reg.s4567, b_lm[lm_offset + 47]); \
48
+ c_reg.lo += convert_float8(acc.lo); \
49
+ c_reg.hi += convert_float8(acc.hi); \
50
+ acc.s0 = dot(a_reg.s89ab, b_lm[lm_offset + 64]); \
51
+ acc.s1 = dot(a_reg.s89ab, b_lm[lm_offset + 65]); \
52
+ acc.s2 = dot(a_reg.s89ab, b_lm[lm_offset + 66]); \
53
+ acc.s3 = dot(a_reg.s89ab, b_lm[lm_offset + 67]); \
54
+ acc.s4 = dot(a_reg.s89ab, b_lm[lm_offset + 68]); \
55
+ acc.s5 = dot(a_reg.s89ab, b_lm[lm_offset + 69]); \
56
+ acc.s6 = dot(a_reg.s89ab, b_lm[lm_offset + 70]); \
57
+ acc.s7 = dot(a_reg.s89ab, b_lm[lm_offset + 71]); \
58
+ acc.s8 = dot(a_reg.s89ab, b_lm[lm_offset + 72]); \
59
+ acc.s9 = dot(a_reg.s89ab, b_lm[lm_offset + 73]); \
60
+ acc.sa = dot(a_reg.s89ab, b_lm[lm_offset + 74]); \
61
+ acc.sb = dot(a_reg.s89ab, b_lm[lm_offset + 75]); \
62
+ acc.sc = dot(a_reg.s89ab, b_lm[lm_offset + 76]); \
63
+ acc.sd = dot(a_reg.s89ab, b_lm[lm_offset + 77]); \
64
+ acc.se = dot(a_reg.s89ab, b_lm[lm_offset + 78]); \
65
+ acc.sf = dot(a_reg.s89ab, b_lm[lm_offset + 79]); \
66
+ acc.s0 += dot(a_reg.scdef, b_lm[lm_offset + 96]); \
67
+ acc.s1 += dot(a_reg.scdef, b_lm[lm_offset + 97]); \
68
+ acc.s2 += dot(a_reg.scdef, b_lm[lm_offset + 98]); \
69
+ acc.s3 += dot(a_reg.scdef, b_lm[lm_offset + 99]); \
70
+ acc.s4 += dot(a_reg.scdef, b_lm[lm_offset + 100]); \
71
+ acc.s5 += dot(a_reg.scdef, b_lm[lm_offset + 101]); \
72
+ acc.s6 += dot(a_reg.scdef, b_lm[lm_offset + 102]); \
73
+ acc.s7 += dot(a_reg.scdef, b_lm[lm_offset + 103]); \
74
+ acc.s8 += dot(a_reg.scdef, b_lm[lm_offset + 104]); \
75
+ acc.s9 += dot(a_reg.scdef, b_lm[lm_offset + 105]); \
76
+ acc.sa += dot(a_reg.scdef, b_lm[lm_offset + 106]); \
77
+ acc.sb += dot(a_reg.scdef, b_lm[lm_offset + 107]); \
78
+ acc.sc += dot(a_reg.scdef, b_lm[lm_offset + 108]); \
79
+ acc.sd += dot(a_reg.scdef, b_lm[lm_offset + 109]); \
80
+ acc.se += dot(a_reg.scdef, b_lm[lm_offset + 110]); \
81
+ acc.sf += dot(a_reg.scdef, b_lm[lm_offset + 111]); \
82
+ c_reg.lo += convert_float8(acc.lo); \
83
+ c_reg.hi += convert_float8(acc.hi); \
84
+
85
+
86
+ __attribute__((qcom_wave_pair_mode(1)))
87
+ kernel void kernel_gemm_moe_q8_0_f32_ns(
88
+ __global char * src0_q, // flat q8_0 quants [n_expert*ne01*ne00]
89
+ __global half * src0_d, // flat q8_0 scales [n_expert*ne01*nb]
90
+ __read_only image1d_buffer_t src1, // reordered activations (f32)
91
+ __global uint * src2, // post-router out indices
92
+ __global ushort * src2_emap,// expert per tile
93
+ __write_only image1d_buffer_t dst,
94
+ __global int * total_tiles,
95
+ uint ne00,
96
+ uint ne01
97
+ ) {
98
+ uint block_id_m = get_global_id(1); // m_tile
99
+ uint block_id_n = get_global_id(2); // n_tile
100
+
101
+ if (block_id_n >= total_tiles[0]) {
102
+ return;
103
+ }
104
+
105
+ __private half16 reg_a;
106
+ __private float32 reg_c = (float32)(0);
107
+ __local half4 shared_b[128];
108
+
109
+ const ushort expert_id = src2_emap[block_id_n];
110
+
111
+ const uint row = block_id_m * TILESIZE_M;
112
+ const uint col = block_id_n * TILESIZE_N;
113
+
114
+ const uint nb = ne00 >> 5; // blocks per row (ne00/32)
115
+ const uint w_row = expert_id * ne01 + row + get_local_id(0); // this lane's output row
116
+ __global char * w_q = src0_q + (ulong)w_row * ne00; // char base for the row
117
+ __global half * w_d = src0_d + (ulong)w_row * nb; // scale base for the row
118
+
119
+ uint sub_block_id_m = get_local_id(0);
120
+ uint2 b_global_offset;
121
+ b_global_offset.x = ((sub_block_id_m & 3) << 2) + (sub_block_id_m >> 2) * ne00;
122
+ b_global_offset.y = b_global_offset.x + (16 * ne00);
123
+ uint2 b_local_offset;
124
+ b_local_offset.x = (sub_block_id_m & 3) * 32 + (sub_block_id_m >> 2);
125
+ b_local_offset.y = b_local_offset.x + 16;
126
+
127
+ // Loop along K axis, 32 elements per iteration, split into 2 sub-blocks.
128
+ for (uint step = 0; step < ne00; step += TILESIZE_K * 2) {
129
+ half s = w_d[step >> 5]; // one q8_0 scale per 32-element block
130
+
131
+ // First sub-block: 16 weights (16 chars = one uint4) at K=step
132
+ uint4 q8x16 = *((__global uint4 *)(w_q + step));
133
+
134
+ uint b_sub_offset = col * ne00 + step;
135
+ float8 bx8_f32;
136
+ bx8_f32.lo = read_imagef(src1, (b_sub_offset + b_global_offset.x) / 4);
137
+ bx8_f32.hi = read_imagef(src1, (b_sub_offset + b_global_offset.y) / 4);
138
+ half8 bx8_f16 = convert_half8(bx8_f32);
139
+ shared_b[b_local_offset.x] = bx8_f16.lo;
140
+ shared_b[b_local_offset.y] = bx8_f16.hi;
141
+
142
+ dequantize_q8_0(q8x16, reg_a, s);
143
+
144
+ sub_group_barrier(CLK_LOCAL_MEM_FENCE);
145
+
146
+ half16 acc;
147
+ dotx16_reduce8(reg_a, shared_b, reg_c.lo, 0);
148
+ dotx16_reduce8(reg_a, shared_b, reg_c.hi, 16);
149
+
150
+ // Second sub-block: next 16 weights at K=step+16
151
+ uint half_step = step + TILESIZE_K;
152
+ q8x16 = *((__global uint4 *)(w_q + half_step));
153
+ b_sub_offset = col * ne00 + half_step;
154
+
155
+ bx8_f32.lo = read_imagef(src1, (b_sub_offset + b_global_offset.x) / 4);
156
+ bx8_f32.hi = read_imagef(src1, (b_sub_offset + b_global_offset.y) / 4);
157
+ bx8_f16 = convert_half8(bx8_f32);
158
+ shared_b[b_local_offset.x] = bx8_f16.lo;
159
+ shared_b[b_local_offset.y] = bx8_f16.hi;
160
+
161
+ dequantize_q8_0(q8x16, reg_a, s);
162
+
163
+ sub_group_barrier(CLK_LOCAL_MEM_FENCE);
164
+
165
+ dotx16_reduce8(reg_a, shared_b, reg_c.lo, 0);
166
+ dotx16_reduce8(reg_a, shared_b, reg_c.hi, 16);
167
+ }
168
+
169
+ if ((get_global_id(0) + block_id_m * TILESIZE_M) >= ne01) {
170
+ return;
171
+ }
172
+
173
+ __local uint out_idx[TILESIZE_N];
174
+
175
+ if (get_local_id(0) < TILESIZE_N) {
176
+ uint idx = src2[block_id_n * TILESIZE_N + get_local_id(0)];
177
+ if (idx == 0xFFFFFFFF) {
178
+ idx = src2[block_id_n * TILESIZE_N + 0];
179
+ }
180
+ out_idx[get_local_id(0)] = idx * ne01;
181
+ }
182
+
183
+ barrier(CLK_LOCAL_MEM_FENCE);
184
+
185
+ uint m_offset = row + get_local_id(0);
186
+
187
+ write_imagef(dst, out_idx[1] + m_offset, (reg_c.s1));
188
+ write_imagef(dst, out_idx[2] + m_offset, (reg_c.s2));
189
+ write_imagef(dst, out_idx[3] + m_offset, (reg_c.s3));
190
+ write_imagef(dst, out_idx[4] + m_offset, (reg_c.s4));
191
+ write_imagef(dst, out_idx[5] + m_offset, (reg_c.s5));
192
+ write_imagef(dst, out_idx[6] + m_offset, (reg_c.s6));
193
+ write_imagef(dst, out_idx[7] + m_offset, (reg_c.s7));
194
+ write_imagef(dst, out_idx[8] + m_offset, (reg_c.s8));
195
+ write_imagef(dst, out_idx[9] + m_offset, (reg_c.s9));
196
+ write_imagef(dst, out_idx[10] + m_offset, (reg_c.sa));
197
+ write_imagef(dst, out_idx[11] + m_offset, (reg_c.sb));
198
+ write_imagef(dst, out_idx[12] + m_offset, (reg_c.sc));
199
+ write_imagef(dst, out_idx[13] + m_offset, (reg_c.sd));
200
+ write_imagef(dst, out_idx[14] + m_offset, (reg_c.se));
201
+ write_imagef(dst, out_idx[15] + m_offset, (reg_c.sf));
202
+ write_imagef(dst, out_idx[16] + m_offset, (reg_c.sg));
203
+ write_imagef(dst, out_idx[17] + m_offset, (reg_c.sh));
204
+ write_imagef(dst, out_idx[18] + m_offset, (reg_c.si));
205
+ write_imagef(dst, out_idx[19] + m_offset, (reg_c.sj));
206
+ write_imagef(dst, out_idx[20] + m_offset, (reg_c.sk));
207
+ write_imagef(dst, out_idx[21] + m_offset, (reg_c.sl));
208
+ write_imagef(dst, out_idx[22] + m_offset, (reg_c.sm));
209
+ write_imagef(dst, out_idx[23] + m_offset, (reg_c.sn));
210
+ write_imagef(dst, out_idx[24] + m_offset, (reg_c.so));
211
+ write_imagef(dst, out_idx[25] + m_offset, (reg_c.sp));
212
+ write_imagef(dst, out_idx[26] + m_offset, (reg_c.sq));
213
+ write_imagef(dst, out_idx[27] + m_offset, (reg_c.sr));
214
+ write_imagef(dst, out_idx[28] + m_offset, (reg_c.ss));
215
+ write_imagef(dst, out_idx[29] + m_offset, (reg_c.st));
216
+ write_imagef(dst, out_idx[30] + m_offset, (reg_c.su));
217
+ write_imagef(dst, out_idx[31] + m_offset, (reg_c.sv));
218
+
219
+ barrier(CLK_GLOBAL_MEM_FENCE);
220
+ write_imagef(dst, out_idx[0] + m_offset, (reg_c.s0));
221
+ }
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_moe_q8_1_dp4a.cl ADDED
@@ -0,0 +1,221 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #pragma OPENCL EXTENSION cl_khr_fp16 : enable
2
+ #pragma OPENCL EXTENSION cl_khr_subgroups : enable
3
+ #ifdef cl_khr_integer_dot_product
4
+ #pragma OPENCL EXTENSION cl_khr_integer_dot_product : enable
5
+ #endif
6
+
7
+ // Generic int8 dp4a MoE GEMM, specialized versions also exist
8
+ // MOE_QT:
9
+ // 4 (q4_K)/41(q4_1)/40(q4_0) NIBBLE image low nibbles -> EXP4
10
+ // 5 (q5_K)/51(q5_1)/50(q5_0) NIBBLE+HI image nibbles + qh high-bit plane
11
+ // 6 (q6_K) Q6 image nibbles + qh 2-bit -> SIGN6((nibble|hi2))
12
+ // 80(q8_0)/82(mxfp4) INT8 global int8 codes (mxfp4: convert applies kvalues LUT)
13
+
14
+ #define TILESIZE_M 64
15
+ #define TILESIZE_N 32
16
+ #define QK_K 256
17
+
18
+ #ifndef MOE_QT
19
+ #define MOE_QT 4
20
+ #endif
21
+
22
+ // 4 nibbles in low 16 bits of u -> 4 bytes (value 0..15)
23
+ #define EXP4(u) ( ((uint)((u) & 0x000Fu)) | \
24
+ (((uint)((u) & 0x00F0u)) << 4) | \
25
+ (((uint)((u) & 0x0F00u)) << 8) | \
26
+ (((uint)((u) & 0xF000u)) << 12) )
27
+ // 4 2-bit highs in byte b -> 4 bytes, bits 4-5 (q6_K)
28
+ #define EXP2(b) ( (((uint)((b) & 0x03u)) << 4) | \
29
+ (((uint)((b) & 0x0Cu)) << 10) | \
30
+ (((uint)((b) & 0x30u)) << 16) | \
31
+ (((uint)((b) & 0xC0u)) << 22) )
32
+
33
+ // q6 (0..63) -> (q6-32) signed int8/byte (no inter-byte carry)
34
+ inline uint SIGN6(uint q6p){ uint x=q6p^0x20202020u; uint s=x&0x20202020u; return x|(s<<1)|(s<<2); }
35
+
36
+ // 4 high bits (one per element, in bits 0..3 of h) -> bit4 of each of 4 bytes (5-bit hi)
37
+ #define EXP1(h) ( (((uint)((h) & 0x1u)) << 4) | \
38
+ (((uint)((h) & 0x2u)) << 11) | \
39
+ (((uint)((h) & 0x4u)) << 18) | \
40
+ (((uint)((h) & 0x8u)) << 25) )
41
+
42
+ // per-type weight params + per-32-step unpack into qw[8] (8 int8 uints)
43
+ #if MOE_QT == 4 || MOE_QT == 41 || MOE_QT == 40
44
+ #define WEIGHT_PARAMS __read_only image1d_buffer_t src0_q,
45
+ #define LOAD_QW(step, sub) \
46
+ uint qw[8]; { \
47
+ const uint qoff0 = row + ((ne01*(step))>>3) + ((expert_id*ne00*ne01)>>3); \
48
+ const uint qoff1 = row + ((ne01*((step)+16))>>3) + ((expert_id*ne00*ne01)>>3); \
49
+ const uint r0=read_imageui(src0_q,qoff0+lid).x, r1=read_imageui(src0_q,qoff0+lid+ne01).x; \
50
+ const uint r2=read_imageui(src0_q,qoff1+lid).x, r3=read_imageui(src0_q,qoff1+lid+ne01).x; \
51
+ qw[0]=EXP4(r0); qw[1]=EXP4(r0>>16); qw[2]=EXP4(r1); qw[3]=EXP4(r1>>16); \
52
+ qw[4]=EXP4(r2); qw[5]=EXP4(r2>>16); qw[6]=EXP4(r3); qw[7]=EXP4(r3>>16); }
53
+
54
+ #elif MOE_QT == 5 || MOE_QT == 51 || MOE_QT == 50
55
+ // low nibbles via image (q4_K layout) + high-bit plane src0_qh: 1 uint per 32-block
56
+ // (bit i = high bit of element i). qh laid out [expert][block][row] to match the
57
+ // existing q5_0 trans4 convert
58
+ #define WEIGHT_PARAMS __read_only image1d_buffer_t src0_q, __global uint * src0_qh,
59
+ #define LOAD_QW(step, sub) \
60
+ uint qw[8]; { \
61
+ const uint qoff0 = row + ((ne01*(step))>>3) + ((expert_id*ne00*ne01)>>3); \
62
+ const uint qoff1 = row + ((ne01*((step)+16))>>3) + ((expert_id*ne00*ne01)>>3); \
63
+ const uint r0=read_imageui(src0_q,qoff0+lid).x, r1=read_imageui(src0_q,qoff0+lid+ne01).x; \
64
+ const uint r2=read_imageui(src0_q,qoff1+lid).x, r3=read_imageui(src0_q,qoff1+lid+ne01).x; \
65
+ const uint h = src0_qh[row_idx + (sub)*ne01 + expert_id*(ne00>>5)*ne01]; \
66
+ qw[0]=EXP4(r0)|EXP1(h); qw[1]=EXP4(r0>>16)|EXP1(h>>4); \
67
+ qw[2]=EXP4(r1)|EXP1(h>>8); qw[3]=EXP4(r1>>16)|EXP1(h>>12); \
68
+ qw[4]=EXP4(r2)|EXP1(h>>16); qw[5]=EXP4(r2>>16)|EXP1(h>>20); \
69
+ qw[6]=EXP4(r3)|EXP1(h>>24); qw[7]=EXP4(r3>>16)|EXP1(h>>28); }
70
+
71
+ #elif MOE_QT == 6
72
+ #define WEIGHT_PARAMS __read_only image1d_buffer_t src0_ql, __global uint * src0_qh,
73
+ #define LOAD_QW(step, sub) \
74
+ uint qw[8]; { \
75
+ const uint qoff0 = row + ((ne01*(step))>>3) + ((expert_id*ne00*ne01)>>3); \
76
+ const uint qoff1 = row + ((ne01*((step)+16))>>3) + ((expert_id*ne00*ne01)>>3); \
77
+ const uint r0=read_imageui(src0_ql,qoff0+lid).x, r1=read_imageui(src0_ql,qoff0+lid+ne01).x; \
78
+ const uint r2=read_imageui(src0_ql,qoff1+lid).x, r3=read_imageui(src0_ql,qoff1+lid+ne01).x; \
79
+ const uint qhb = row + ((sub)*2)*ne01 + expert_id*((ne00>>5)*2)*ne01 + lid; \
80
+ const uint qh1=src0_qh[qhb], qh2=src0_qh[qhb+ne01]; \
81
+ qw[0]=SIGN6(EXP4(r0)|EXP2(qh1&0xFFu)); qw[1]=SIGN6(EXP4(r0>>16)|EXP2((qh1>>8)&0xFFu)); \
82
+ qw[2]=SIGN6(EXP4(r1)|EXP2((qh1>>16)&0xFFu)); qw[3]=SIGN6(EXP4(r1>>16)|EXP2((qh1>>24)&0xFFu)); \
83
+ qw[4]=SIGN6(EXP4(r2)|EXP2(qh2&0xFFu)); qw[5]=SIGN6(EXP4(r2>>16)|EXP2((qh2>>8)&0xFFu)); \
84
+ qw[6]=SIGN6(EXP4(r3)|EXP2((qh2>>16)&0xFFu)); qw[7]=SIGN6(EXP4(r3>>16)|EXP2((qh2>>24)&0xFFu)); }
85
+
86
+ #elif MOE_QT == 80 || MOE_QT == 82
87
+ // 8-bit direct: int8 codes 8 uints / 32-block, [expert][row][8*sub]. mxfp4: the
88
+ // convert resolves kvalues_mxfp4[nibble] -> int8 and stores the e8m0_half scale.
89
+ #define WEIGHT_PARAMS __global uint * src0_q8,
90
+ #define LOAD_QW(step, sub) \
91
+ uint qw[8]; { \
92
+ const uint qb = (expert_id*ne01 + row_idx)*(ne00>>2) + (sub)*8; \
93
+ qw[0]=src0_q8[qb+0]; qw[1]=src0_q8[qb+1]; qw[2]=src0_q8[qb+2]; qw[3]=src0_q8[qb+3]; \
94
+ qw[4]=src0_q8[qb+4]; qw[5]=src0_q8[qb+5]; qw[6]=src0_q8[qb+6]; qw[7]=src0_q8[qb+7]; }
95
+ #else
96
+ #error "unknown MOE_QT"
97
+ #endif
98
+
99
+ inline int dp4a4(uint w0,uint w1,uint w2,uint w3,uint a0,uint a1,uint a2,uint a3){
100
+ int r=0; r=dot_acc_sat_4x8packed_ss_int(w0,a0,r); r=dot_acc_sat_4x8packed_ss_int(w1,a1,r);
101
+ r=dot_acc_sat_4x8packed_ss_int(w2,a2,r); r=dot_acc_sat_4x8packed_ss_int(w3,a3,r); return r; }
102
+
103
+ // One token's two-half dp4a + uniform scale/min epilogue into acc[t].
104
+ #define MOE_DP4A_T(t) do { \
105
+ const int raw1 = dp4a4(qw[0],qw[1],qw[2],qw[3], sh_qa[t][0],sh_qa[t][1],sh_qa[t][2],sh_qa[t][3]); \
106
+ const int raw2 = dp4a4(qw[4],qw[5],qw[6],qw[7], sh_qa[t][4],sh_qa[t][5],sh_qa[t][6],sh_qa[t][7]); \
107
+ const float a_d = (float)sh_d[t]; \
108
+ acc[t] += sc0*a_d*(float)raw1 + sc1*a_d*(float)raw2 - mn*(float)sh_s[t]; \
109
+ } while (0)
110
+
111
+ __attribute__((qcom_wave_pair_mode(1)))
112
+ kernel void kernel_gemm_moe_q8_1_dp4a(
113
+ WEIGHT_PARAMS // per-type native weight buffer(s)
114
+ __global half * src0_scale,// uniform f16 16/superblock (per-16), [expert,row]
115
+ __global half * src0_min, // uniform f16 8/superblock (per-32), [expert,row]
116
+ __global uint * src1_qa, // q8_1 activations int8 (as uint, 4/elem)
117
+ __global half * src1_da, // q8_1 per-block scale [tok_slot * ne00/32]
118
+ __global half * src1_sa, // q8_1 per-block sum*d [tok_slot * ne00/32]
119
+ __global uint * src2, // post-router (orig out positions)
120
+ __global ushort * src2_emap, // tile -> expert id
121
+ __write_only image1d_buffer_t dst,
122
+ __global int * total_tiles,
123
+ uint ne00,
124
+ uint ne01,
125
+ int is_ragged,
126
+ int has_min // 0 for symmetric types (q8_0/q6_K/q4_0/...): skip min read
127
+ ) {
128
+ const uint block_id_m = get_global_id(1);
129
+ const uint block_id_n = get_global_id(2);
130
+ if (block_id_n >= total_tiles[0]) return;
131
+
132
+ const uint lid = get_local_id(0); // 0..63 -> output row within M-tile
133
+ const ushort expert_id = src2_emap[block_id_n];
134
+ const uint row = block_id_m * TILESIZE_M;
135
+ const uint col = block_id_n * TILESIZE_N;
136
+ const uint row_idx = row + lid;
137
+
138
+ // Scale/min are laid out FLAT per-32-block (2 per-16-segment scales + 1 min per
139
+ // 32-block), so K only needs to be a multiple of 32 — works for the 32-block
140
+ // types (q8_0/q5_0/q4_0/...) as well as the K-quants (K%256==0, same bytes).
141
+ const uint nblk32 = ne00 / 32;
142
+ const uint sc_per_row = nblk32 * 2;
143
+ const uint mn_per_row = nblk32;
144
+ const uint ne00_u = ne00 >> 2;
145
+ const uint ne00_b = ne00 >> 5;
146
+
147
+ __local uint sh_qa[TILESIZE_N][8];
148
+ __local half sh_d[TILESIZE_N];
149
+ __local half sh_s[TILESIZE_N];
150
+
151
+ __local uint sh_src2[TILESIZE_N];
152
+ __local int sh_nreal;
153
+ if (lid < TILESIZE_N) sh_src2[lid] = src2[col + lid];
154
+ barrier(CLK_LOCAL_MEM_FENCE);
155
+ if (lid == 0) {
156
+ int nr = TILESIZE_N;
157
+ if (is_ragged) { nr = 0;
158
+ #pragma unroll
159
+ for (int t = 0; t < TILESIZE_N; ++t) if (sh_src2[t] != 0xFFFFFFFFu) ++nr; }
160
+ sh_nreal = nr;
161
+ }
162
+ barrier(CLK_LOCAL_MEM_FENCE);
163
+ const int n_real = sh_nreal;
164
+
165
+ float acc[TILESIZE_N];
166
+ #pragma unroll
167
+ for (int t = 0; t < TILESIZE_N; ++t) acc[t] = 0.0f;
168
+
169
+ for (uint step = 0; step < ne00; step += 32) {
170
+ const uint sub = step >> 5; // 32-block index along K
171
+
172
+ // uniform pre-decoded scale (2 per-16-seg) + min (1) for this row, this 32-block
173
+ __global half * scl = src0_scale + (expert_id*ne01 + row_idx)*sc_per_row + sub*2;
174
+ const float sc0 = (float)scl[0];
175
+ const float sc1 = (float)scl[1];
176
+ float mn = 0.0f;
177
+ if (has_min) mn = (float)src0_min[(expert_id*ne01 + row_idx)*mn_per_row + sub];
178
+
179
+ LOAD_QW(step, sub)
180
+
181
+ const uint stage_lim = (uint)n_real * 8;
182
+ for (uint idx = lid; idx < stage_lim; idx += 64) {
183
+ const uint t = idx >> 3, u = idx & 7;
184
+ sh_qa[t][u] = src1_qa[(col + t) * ne00_u + (step >> 2) + u];
185
+ }
186
+ if (lid < (uint)n_real) {
187
+ sh_d[lid] = src1_da[(col + lid) * ne00_b + sub];
188
+ sh_s[lid] = src1_sa[(col + lid) * ne00_b + sub];
189
+ }
190
+ barrier(CLK_LOCAL_MEM_FENCE);
191
+
192
+ if (n_real == TILESIZE_N) {
193
+ #pragma unroll
194
+ for (int t = 0; t < TILESIZE_N; ++t) { MOE_DP4A_T(t); }
195
+ } else {
196
+ #pragma unroll 4
197
+ for (int t = 0; t < n_real; ++t) { MOE_DP4A_T(t); }
198
+ }
199
+ barrier(CLK_LOCAL_MEM_FENCE);
200
+ }
201
+
202
+ if (row_idx >= ne01) return;
203
+
204
+ __local uint out_idx[TILESIZE_N];
205
+ if (lid < TILESIZE_N) {
206
+ uint idx = sh_src2[lid];
207
+ if (idx == 0xFFFFFFFF) idx = sh_src2[0];
208
+ out_idx[lid] = idx * ne01;
209
+ }
210
+ barrier(CLK_LOCAL_MEM_FENCE);
211
+
212
+ const uint m_offset = row + lid;
213
+ if (n_real == TILESIZE_N) {
214
+ #pragma unroll
215
+ for (int t = 1; t < TILESIZE_N; ++t) write_imagef(dst, out_idx[t] + m_offset, acc[t]);
216
+ barrier(CLK_GLOBAL_MEM_FENCE);
217
+ write_imagef(dst, out_idx[0] + m_offset, acc[0]);
218
+ } else {
219
+ for (int t = 0; t < n_real; ++t) write_imagef(dst, out_idx[t] + m_offset, acc[t]);
220
+ }
221
+ }
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_noshuffle_iq4_nl_f32.cl ADDED
@@ -0,0 +1,150 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #pragma OPENCL EXTENSION cl_khr_fp16 : enable
2
+ #pragma OPENCL EXTENSION cl_qcom_reqd_sub_group_size : enable
3
+
4
+ #ifdef cl_qcom_reqd_sub_group_size
5
+ #define ADRENO_GPU 1
6
+ #define REQD_SUBGROUP_SIZE_128 __attribute__((qcom_reqd_sub_group_size("full")))
7
+ #endif
8
+
9
+ constant half kvalues_iq4nl[16] = {
10
+ (half)-127.f, (half)-104.f, (half)-83.f, (half)-65.f,
11
+ (half) -49.f, (half) -35.f, (half)-22.f, (half)-10.f,
12
+ (half) 1.f, (half) 13.f, (half) 25.f, (half) 38.f,
13
+ (half) 53.f, (half) 69.f, (half) 89.f, (half)113.f
14
+ };
15
+
16
+ // Packed LUT: 2 FP16 values per uint, 8 unique constant loads instead of 16
17
+ constant uint iq4nl_packed[8] = {
18
+ 0xD680D7F0u, // idx 0,1: -127, -104
19
+ 0xD410D530u, // idx 2,3: -83, -65
20
+ 0xD060D220u, // idx 4,5: -49, -35
21
+ 0xC900CD80u, // idx 6,7: -22, -10
22
+ 0x4A803C00u, // idx 8,9: 1, 13
23
+ 0x50C04E40u, // idx 10,11: 25, 38
24
+ 0x545052A0u, // idx 12,13: 53, 69
25
+ 0x57105590u // idx 14,15: 89, 113
26
+ };
27
+
28
+ // Packed dequant: 1 uint constant load (8-way divergence) + shift + as_half
29
+ #define IQ4_NL_DEQUANT(nibble) as_half((ushort)(iq4nl_packed[(nibble) >> 1] >> (((nibble) & 1u) << 4)))
30
+
31
+ #ifdef ADRENO_GPU
32
+ REQD_SUBGROUP_SIZE_128
33
+ #endif
34
+
35
+ kernel void kernel_gemm_noshuffle_iq4_nl_f32(
36
+ global const ushort * src0_q,
37
+ global const half * src0_d,
38
+ read_only image1d_buffer_t src1,
39
+ global float * dst,
40
+ ulong offsetd,
41
+ int m,
42
+ int n,
43
+ int k,
44
+ int n_no_padding
45
+ ) {
46
+ dst = (global float *)((global char *)dst + offsetd);
47
+
48
+ int m_4 = m >> 2;
49
+ int n_4 = n >> 2;
50
+
51
+ int gy = get_global_id(0);
52
+ int gx = get_global_id(1);
53
+ int gx_2 = gx << 2;
54
+
55
+ half8 c0 = 0, c1 = 0, c2 = 0, c3 = 0;
56
+ half8 B;
57
+ half4 dequantized_weights;
58
+
59
+ global const ushort * weight_ptr = src0_q + gx_2;
60
+ global const half * scale_ptr = src0_d + gx_2;
61
+
62
+ for (int i = 0; i < k; i += 4) {
63
+ B.s0123 = read_imageh(src1, gy*2 + (i)*(n_4));
64
+ B.s4567 = read_imageh(src1, gy*2 + (i)*(n_4)+1);
65
+
66
+ ushort4 bits4 = vload4(0, weight_ptr + (i/4)*(m));
67
+
68
+ half4 scale = vload4(0, scale_ptr + (i/32)*(m));
69
+
70
+ // j=0
71
+ dequantized_weights.s0 = IQ4_NL_DEQUANT(bits4.s0 & 0x000Fu) * scale.s0;
72
+ dequantized_weights.s1 = IQ4_NL_DEQUANT(bits4.s1 & 0x000Fu) * scale.s1;
73
+ dequantized_weights.s2 = IQ4_NL_DEQUANT(bits4.s2 & 0x000Fu) * scale.s2;
74
+ dequantized_weights.s3 = IQ4_NL_DEQUANT(bits4.s3 & 0x000Fu) * scale.s3;
75
+ c0 += B * dequantized_weights.s0;
76
+ c1 += B * dequantized_weights.s1;
77
+ c2 += B * dequantized_weights.s2;
78
+ c3 += B * dequantized_weights.s3;
79
+
80
+ // j=1
81
+ B.s0123 = read_imageh(src1, gy*2 + (i+1)*(n_4));
82
+ B.s4567 = read_imageh(src1, gy*2 + (i+1)*(n_4)+1);
83
+ dequantized_weights.s0 = IQ4_NL_DEQUANT((bits4.s0 >> 4) & 0x000Fu) * scale.s0;
84
+ dequantized_weights.s1 = IQ4_NL_DEQUANT((bits4.s1 >> 4) & 0x000Fu) * scale.s1;
85
+ dequantized_weights.s2 = IQ4_NL_DEQUANT((bits4.s2 >> 4) & 0x000Fu) * scale.s2;
86
+ dequantized_weights.s3 = IQ4_NL_DEQUANT((bits4.s3 >> 4) & 0x000Fu) * scale.s3;
87
+ c0 += B * dequantized_weights.s0;
88
+ c1 += B * dequantized_weights.s1;
89
+ c2 += B * dequantized_weights.s2;
90
+ c3 += B * dequantized_weights.s3;
91
+
92
+ // j=2
93
+ B.s0123 = read_imageh(src1, gy*2 + (i+2)*(n_4));
94
+ B.s4567 = read_imageh(src1, gy*2 + (i+2)*(n_4)+1);
95
+ dequantized_weights.s0 = IQ4_NL_DEQUANT((bits4.s0 >> 8) & 0x000Fu) * scale.s0;
96
+ dequantized_weights.s1 = IQ4_NL_DEQUANT((bits4.s1 >> 8) & 0x000Fu) * scale.s1;
97
+ dequantized_weights.s2 = IQ4_NL_DEQUANT((bits4.s2 >> 8) & 0x000Fu) * scale.s2;
98
+ dequantized_weights.s3 = IQ4_NL_DEQUANT((bits4.s3 >> 8) & 0x000Fu) * scale.s3;
99
+ c0 += B * dequantized_weights.s0;
100
+ c1 += B * dequantized_weights.s1;
101
+ c2 += B * dequantized_weights.s2;
102
+ c3 += B * dequantized_weights.s3;
103
+
104
+ // j=3
105
+ B.s0123 = read_imageh(src1, gy*2 + (i+3)*(n_4));
106
+ B.s4567 = read_imageh(src1, gy*2 + (i+3)*(n_4)+1);
107
+ dequantized_weights.s0 = IQ4_NL_DEQUANT((bits4.s0 >> 12) & 0x000Fu) * scale.s0;
108
+ dequantized_weights.s1 = IQ4_NL_DEQUANT((bits4.s1 >> 12) & 0x000Fu) * scale.s1;
109
+ dequantized_weights.s2 = IQ4_NL_DEQUANT((bits4.s2 >> 12) & 0x000Fu) * scale.s2;
110
+ dequantized_weights.s3 = IQ4_NL_DEQUANT((bits4.s3 >> 12) & 0x000Fu) * scale.s3;
111
+ c0 += B * dequantized_weights.s0;
112
+ c1 += B * dequantized_weights.s1;
113
+ c2 += B * dequantized_weights.s2;
114
+ c3 += B * dequantized_weights.s3;
115
+ }
116
+
117
+ int idx = (gy<<3)*m + (gx<<2);
118
+
119
+ if(idx+3 < m*n_no_padding){
120
+ vstore4((float4)(c0.s0, c1.s0, c2.s0, c3.s0), 0, dst + idx);
121
+ idx += m;
122
+ }
123
+ if(idx+3 < m*n_no_padding){
124
+ vstore4((float4)(c0.s1, c1.s1, c2.s1, c3.s1), 0, dst + idx);
125
+ idx += m;
126
+ }
127
+ if(idx+3 < m*n_no_padding){
128
+ vstore4((float4)(c0.s2, c1.s2, c2.s2, c3.s2), 0, dst + idx);
129
+ idx += m;
130
+ }
131
+ if(idx+3 < m*n_no_padding){
132
+ vstore4((float4)(c0.s3, c1.s3, c2.s3, c3.s3), 0, dst + idx);
133
+ idx += m;
134
+ }
135
+ if(idx+3 < m*n_no_padding){
136
+ vstore4((float4)(c0.s4, c1.s4, c2.s4, c3.s4), 0, dst + idx);
137
+ idx += m;
138
+ }
139
+ if(idx+3 < m*n_no_padding){
140
+ vstore4((float4)(c0.s5, c1.s5, c2.s5, c3.s5), 0, dst + idx);
141
+ idx += m;
142
+ }
143
+ if(idx+3 < m*n_no_padding){
144
+ vstore4((float4)(c0.s6, c1.s6, c2.s6, c3.s6), 0, dst + idx);
145
+ idx += m;
146
+ }
147
+ if(idx+3 < m*n_no_padding){
148
+ vstore4((float4)(c0.s7, c1.s7, c2.s7, c3.s7), 0, dst + idx);
149
+ }
150
+ }
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_noshuffle_iq4_nl_q8_1_dp4a.cl ADDED
@@ -0,0 +1,143 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #pragma OPENCL EXTENSION cl_khr_fp16 : enable
2
+ #pragma OPENCL EXTENSION cl_khr_subgroups : enable
3
+ #ifdef cl_khr_integer_dot_product
4
+ #pragma OPENCL EXTENSION cl_khr_integer_dot_product : enable
5
+ #endif
6
+
7
+ // Weight layout, feature-major:
8
+ // src0_q[row + (k/4)*m] ushort = 4 nibbles (K = 4*grp .. +3)
9
+ // src0_d[row + (k/32)*m] half = per-32-block scale
10
+
11
+ #define TILESIZE_N 32
12
+
13
+ // IQ4_NL non-linear codebook as signed int8, packed 4 codes per uint.
14
+ // divergent nibble lookups read a small __constant uint array + shift,
15
+ // never a byte array because byte-indexed __constant loads serialize on Adreno and tank perf
16
+ // idx 0-3: -127,-104,-83,-65 = 0x81,0x98,0xAD,0xBF
17
+ // idx 4-7: -49,-35,-22,-10 = 0xCF,0xDD,0xEA,0xF6
18
+ // idx 8-11: 1, 13, 25, 38 = 0x01,0x0D,0x19,0x26
19
+ // idx 12-15: 53, 69, 89,113 = 0x35,0x45,0x59,0x71
20
+ __constant uint kvalues_iq4nl_i8x4[4] = {
21
+ 0xBFAD9881u, 0xF6EADDCFu, 0x26190D01u, 0x71594535u
22
+ };
23
+
24
+ // nibble (0..15) -> its codebook byte in the low 8 bits.
25
+ inline uint iq4nl_code(uint n) {
26
+ return (kvalues_iq4nl_i8x4[n >> 2] >> ((n & 3u) * 8u)) & 0xFFu;
27
+ }
28
+
29
+ // 4 nibbles in low 16 bits of u -> 4 codebook int8, packed for dp4a.
30
+ inline uint iq4nl_pack(ushort u) {
31
+ return iq4nl_code((uint)( u & 0xF))
32
+ | (iq4nl_code((uint)((u >> 4) & 0xF)) << 8)
33
+ | (iq4nl_code((uint)((u >> 8) & 0xF)) << 16)
34
+ | (iq4nl_code((uint)((u >> 12) & 0xF)) << 24);
35
+ }
36
+
37
+ inline int dot8_q8a(uint8 qw, __local const uint * a) {
38
+ int r = 0;
39
+ r = dot_acc_sat_4x8packed_ss_int(qw.s0, a[0], r);
40
+ r = dot_acc_sat_4x8packed_ss_int(qw.s1, a[1], r);
41
+ r = dot_acc_sat_4x8packed_ss_int(qw.s2, a[2], r);
42
+ r = dot_acc_sat_4x8packed_ss_int(qw.s3, a[3], r);
43
+ r = dot_acc_sat_4x8packed_ss_int(qw.s4, a[4], r);
44
+ r = dot_acc_sat_4x8packed_ss_int(qw.s5, a[5], r);
45
+ r = dot_acc_sat_4x8packed_ss_int(qw.s6, a[6], r);
46
+ r = dot_acc_sat_4x8packed_ss_int(qw.s7, a[7], r);
47
+ return r;
48
+ }
49
+
50
+ __attribute__((qcom_wave_pair_mode(1)))
51
+ kernel void kernel_gemm_noshuffle_iq4_nl_q8_1_dp4a(
52
+ __global const ushort * src0_q, // IQ4_NL nibbles (4/ushort, feature-major)
53
+ __global const half * src0_d, // per-32-block scale, feature-major
54
+ __global const uint * src1_qa, // q8_1 activations int8 (as uint, 4/elem) [N, K]
55
+ __global const half * src1_da, // q8_1 per-block scale [N, K/32]
56
+ __global float * dst,
57
+ ulong offsetd,
58
+ int m, // output features (rows)
59
+ int n_no_padding, // tokens (cols)
60
+ int k // K (== ne00)
61
+ ) {
62
+ dst = (global float *)((global char *)dst + offsetd);
63
+
64
+ const uint lid = get_local_id(0); // 0..63 -> row within the M-tile
65
+ const uint block_id_m = get_global_id(1);
66
+ const uint block_id_n = get_global_id(2);
67
+
68
+ const uint row = block_id_m * 64 + lid;
69
+ const uint col_base = block_id_n * TILESIZE_N;
70
+ const bool row_valid = row < (uint)m;
71
+ const uint rrow = row_valid ? row : 0; // clamp OOB rows; their writes are masked
72
+
73
+ const uint k_u = (uint)k >> 2; // K in uint (int8x4) units
74
+ const uint k_b = (uint)k >> 5; // blocks-of-32 along K
75
+
76
+ __local uint sh_qa[TILESIZE_N][8];
77
+ __local half sh_d[TILESIZE_N];
78
+
79
+ #define NGROUPS (TILESIZE_N / 4)
80
+ float4 acc[NGROUPS];
81
+ #pragma unroll
82
+ for (int g = 0; g < NGROUPS; ++g) acc[g] = (float4)(0.0f);
83
+
84
+ for (uint step = 0; step < (uint)k; step += 32) {
85
+ const uint sub = step >> 5;
86
+
87
+ const float d_w = (float)src0_d[rrow + sub * (uint)m];
88
+
89
+ // 8 weight uints (32 codebook int8) for this row, this 32-block.
90
+ const uint qsbase = rrow + (step >> 2) * (uint)m;
91
+ uint8 qw;
92
+ qw.s0 = iq4nl_pack(src0_q[qsbase + 0 * m]);
93
+ qw.s1 = iq4nl_pack(src0_q[qsbase + 1 * m]);
94
+ qw.s2 = iq4nl_pack(src0_q[qsbase + 2 * m]);
95
+ qw.s3 = iq4nl_pack(src0_q[qsbase + 3 * m]);
96
+ qw.s4 = iq4nl_pack(src0_q[qsbase + 4 * m]);
97
+ qw.s5 = iq4nl_pack(src0_q[qsbase + 5 * m]);
98
+ qw.s6 = iq4nl_pack(src0_q[qsbase + 6 * m]);
99
+ qw.s7 = iq4nl_pack(src0_q[qsbase + 7 * m]);
100
+
101
+ // cooperatively stage the 32-token x 32-K int8 activations to lm
102
+ for (uint idx = lid; idx < TILESIZE_N * 8; idx += 64) {
103
+ const uint t = idx >> 3;
104
+ const uint u = idx & 7;
105
+ const uint c = col_base + t;
106
+ sh_qa[t][u] = (c < (uint)n_no_padding) ? src1_qa[c * k_u + (step >> 2) + u] : 0u;
107
+ }
108
+ if (lid < TILESIZE_N) {
109
+ const uint c = col_base + lid;
110
+ sh_d[lid] = (c < (uint)n_no_padding) ? src1_da[c * k_b + sub] : (half)0;
111
+ }
112
+ barrier(CLK_LOCAL_MEM_FENCE);
113
+
114
+ #define LD4(arr, b) ((float4)((float)arr[(b)+0], (float)arr[(b)+1], (float)arr[(b)+2], (float)arr[(b)+3]))
115
+ #pragma unroll
116
+ for (int g = 0; g < NGROUPS; ++g) {
117
+ const int b = g * 4;
118
+ float4 rf;
119
+ rf.s0 = (float)dot8_q8a(qw, sh_qa[b+0]); rf.s1 = (float)dot8_q8a(qw, sh_qa[b+1]);
120
+ rf.s2 = (float)dot8_q8a(qw, sh_qa[b+2]); rf.s3 = (float)dot8_q8a(qw, sh_qa[b+3]);
121
+ acc[g] += d_w * LD4(sh_d, b) * rf;
122
+ }
123
+ #undef LD4
124
+ barrier(CLK_LOCAL_MEM_FENCE);
125
+ }
126
+
127
+ if (!row_valid) {
128
+ return;
129
+ }
130
+
131
+ // dst is [token, feature] row-major (stride m): dst[col*m + row].
132
+ #pragma unroll
133
+ for (int g = 0; g < NGROUPS; ++g) {
134
+ const uint b = (uint)(g * 4);
135
+ const float4 a = acc[g];
136
+ const uint c0 = col_base + b;
137
+ if (c0 + 0 < (uint)n_no_padding) dst[(c0 + 0) * (uint)m + row] = a.s0;
138
+ if (c0 + 1 < (uint)n_no_padding) dst[(c0 + 1) * (uint)m + row] = a.s1;
139
+ if (c0 + 2 < (uint)n_no_padding) dst[(c0 + 2) * (uint)m + row] = a.s2;
140
+ if (c0 + 3 < (uint)n_no_padding) dst[(c0 + 3) * (uint)m + row] = a.s3;
141
+ }
142
+ #undef NGROUPS
143
+ }
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_noshuffle_q1_0_f32.cl ADDED
@@ -0,0 +1,94 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #pragma OPENCL EXTENSION cl_khr_fp16 : enable
2
+ #pragma OPENCL EXTENSION cl_qcom_reqd_sub_group_size : enable
3
+
4
+ #ifdef cl_qcom_reqd_sub_group_size
5
+ #pragma OPENCL EXTENSION cl_qcom_reqd_sub_group_size : enable
6
+ #define ADRENO_GPU 1
7
+ #define REQD_SUBGROUP_SIZE_128 __attribute__((qcom_reqd_sub_group_size("full")))
8
+ #endif
9
+
10
+ // each work-item computes a 4 (rows of A / m) x 8 (cols of B / n) output tile.
11
+ #ifdef ADRENO_GPU
12
+ REQD_SUBGROUP_SIZE_128
13
+ #endif
14
+ kernel void kernel_gemm_noshuffle_q1_0_f32(
15
+ global const uint * src0_q,
16
+ global const half * src0_d,
17
+ read_only image1d_buffer_t src1,
18
+ global float * dst,
19
+ int k,
20
+ int m,
21
+ int n,
22
+ int n_no_padding,
23
+ ulong offsetd
24
+ ) {
25
+ int n_4 = n >> 2;
26
+
27
+ int gy = get_global_id(0);
28
+ int gx = get_global_id(1);
29
+ int gx_2 = gx << 2;
30
+ dst = (global float *)((global char*)dst + offsetd);
31
+
32
+ half8 c0 = 0, c1 = 0, c2 = 0, c3 = 0;
33
+ half8 B;
34
+
35
+ global const uint* wptr = src0_q + gx_2;
36
+ global const half* sptr = src0_d + gx_2;
37
+
38
+ // 32 weights per uint32, 128 weights (one block / one scale) per 4 uint32.
39
+ for (int i = 0; i < k; i += 32) {
40
+ uint4 pack4 = vload4(0, wptr + (i / 32) * m); // 4 rows, 32 K-values each
41
+ half4 scale = vload4(0, sptr + (i / 128) * m); // 4 rows, one scale per 128
42
+
43
+ for (int j = 0; j < 32; ++j) {
44
+ B.s0123 = read_imageh(src1, gy * 2 + (i + j) * n_4);
45
+ B.s4567 = read_imageh(src1, gy * 2 + (i + j) * n_4 + 1);
46
+
47
+ // sign bit -> +-1 (half arithmetic avoids unsigned underflow)
48
+ half4 wj = (half4)(
49
+ 2.0h * (half)((pack4.s0 >> j) & 1u) - 1.0h,
50
+ 2.0h * (half)((pack4.s1 >> j) & 1u) - 1.0h,
51
+ 2.0h * (half)((pack4.s2 >> j) & 1u) - 1.0h,
52
+ 2.0h * (half)((pack4.s3 >> j) & 1u) - 1.0h) * scale;
53
+
54
+ c0 += B * wj.s0;
55
+ c1 += B * wj.s1;
56
+ c2 += B * wj.s2;
57
+ c3 += B * wj.s3;
58
+ }
59
+ }
60
+
61
+ int idx = (gy << 3) * m + (gx << 2);
62
+
63
+ if(idx+3 < m*n_no_padding){
64
+ vstore4((float4)(c0.s0, c1.s0, c2.s0, c3.s0), 0, dst + idx);
65
+ idx += m;
66
+ }
67
+ if(idx+3 < m*n_no_padding){
68
+ vstore4((float4)(c0.s1, c1.s1, c2.s1, c3.s1), 0, dst + idx);
69
+ idx += m;
70
+ }
71
+ if(idx+3 < m*n_no_padding){
72
+ vstore4((float4)(c0.s2, c1.s2, c2.s2, c3.s2), 0, dst + idx);
73
+ idx += m;
74
+ }
75
+ if(idx+3 < m*n_no_padding){
76
+ vstore4((float4)(c0.s3, c1.s3, c2.s3, c3.s3), 0, dst + idx);
77
+ idx += m;
78
+ }
79
+ if(idx+3 < m*n_no_padding){
80
+ vstore4((float4)(c0.s4, c1.s4, c2.s4, c3.s4), 0, dst + idx);
81
+ idx += m;
82
+ }
83
+ if(idx+3 < m*n_no_padding){
84
+ vstore4((float4)(c0.s5, c1.s5, c2.s5, c3.s5), 0, dst + idx);
85
+ idx += m;
86
+ }
87
+ if(idx+3 < m*n_no_padding){
88
+ vstore4((float4)(c0.s6, c1.s6, c2.s6, c3.s6), 0, dst + idx);
89
+ idx += m;
90
+ }
91
+ if(idx+3 < m*n_no_padding){
92
+ vstore4((float4)(c0.s7, c1.s7, c2.s7, c3.s7), 0, dst + idx);
93
+ }
94
+ }
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_noshuffle_q4_0_f32.cl ADDED
@@ -0,0 +1,139 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // src0_q, src0_d, src1 are transposed as a preprocessing step
2
+ // 4-bit weights are transposed in groups of 4 (unsigned short int)
3
+ // consider weights originally "next to each other", now "on top of each other"
4
+ // each fiber computes a 8x4 tile of output elements
5
+ // using unshuffled weights
6
+
7
+ #pragma OPENCL EXTENSION cl_khr_fp16 : enable
8
+ #pragma OPENCL EXTENSION cl_qcom_reqd_sub_group_size : enable
9
+
10
+ #ifdef cl_qcom_reqd_sub_group_size
11
+ #pragma OPENCL EXTENSION cl_qcom_reqd_sub_group_size : enable
12
+ #define ADRENO_GPU 1
13
+ #define REQD_SUBGROUP_SIZE_128 __attribute__((qcom_reqd_sub_group_size("full")))
14
+ #endif
15
+
16
+ #ifdef ADRENO_GPU
17
+ REQD_SUBGROUP_SIZE_128
18
+ #endif
19
+
20
+ kernel void kernel_gemm_noshuffle_q4_0_f32(
21
+ global const ushort * src0_q, // quantized A
22
+ global const half * src0_d, // A scales
23
+ __read_only image1d_buffer_t src1, // B (1d image)
24
+ global float * dst, // C
25
+ int m, // M
26
+ int n, // N with padding
27
+ int k, // K
28
+ int n_no_padding // N without padding
29
+ ) {
30
+
31
+ int m_4 = m >> 2;
32
+ int n_4 = n >> 2;
33
+
34
+ int gy = get_global_id(0);
35
+ int gx = get_global_id(1);
36
+ int gx_2 = gx << 2;
37
+
38
+ half8 c0 = 0, c1 = 0, c2 = 0, c3 = 0; // 8x4 output elements
39
+ half8 B; // registers for activations
40
+ half4 dequantized_weights; // registers for dequantized weights
41
+ __global const ushort* weight_ptr = src0_q + gx_2; // pointer for weights
42
+ __global const half* scale_ptr = src0_d + gx_2; // pointer for scales
43
+
44
+ for(int i=0; i<k; i+=4){ //loop through K dimension
45
+
46
+ B.s0123 = read_imageh(src1, gy*2 + (i)*(n_4));
47
+ B.s4567 = read_imageh(src1, gy*2 + (i)*(n_4)+1);
48
+
49
+ // keep (i/4) and (i/32) in parenthesis, rounds down
50
+ // load 4 consecutive groups of 4 weights
51
+ ushort4 bits4 = vload4(0, weight_ptr + (i/4)*(m)); // (i/4) because weights grouped in 4s
52
+
53
+ // load 4 consecutive scales
54
+ half4 scale = vload4(0, scale_ptr + (i/32)*(m));// (i/32) because 1 scale per 32 elements
55
+
56
+ // j=0
57
+ dequantized_weights.s0 = ((bits4.s0 & (0x000F)) - 8) * scale.s0; // dequantize a row of the 16 weights
58
+ dequantized_weights.s1 = ((bits4.s1 & (0x000F)) - 8) * scale.s1;
59
+ dequantized_weights.s2 = ((bits4.s2 & (0x000F)) - 8) * scale.s2;
60
+ dequantized_weights.s3 = ((bits4.s3 & (0x000F)) - 8) * scale.s3;
61
+ c0 += B * dequantized_weights.s0; // vector-scalar multiplication to accumulate
62
+ c1 += B * dequantized_weights.s1;
63
+ c2 += B * dequantized_weights.s2;
64
+ c3 += B * dequantized_weights.s3;
65
+
66
+ // j=1
67
+ B.s0123 = read_imageh(src1, gy*2 + (i+1)*(n_4));
68
+ B.s4567 = read_imageh(src1, gy*2 + (i+1)*(n_4)+1);
69
+ dequantized_weights.s0 = (((bits4.s0 & (0x00F0)) >> 4) - 8) * scale.s0; // dequantize a row of the 16 weights
70
+ dequantized_weights.s1 = (((bits4.s1 & (0x00F0)) >> 4) - 8) * scale.s1;
71
+ dequantized_weights.s2 = (((bits4.s2 & (0x00F0)) >> 4) - 8) * scale.s2;
72
+ dequantized_weights.s3 = (((bits4.s3 & (0x00F0)) >> 4) - 8) * scale.s3;
73
+ c0 += B * dequantized_weights.s0; //vector-scalar multiplication to accumulate
74
+ c1 += B * dequantized_weights.s1;
75
+ c2 += B * dequantized_weights.s2;
76
+ c3 += B * dequantized_weights.s3;
77
+
78
+ // j=2
79
+ B.s0123 = read_imageh(src1, gy*2 + (i+2)*(n_4));
80
+ B.s4567 = read_imageh(src1, gy*2 + (i+2)*(n_4)+1);
81
+ dequantized_weights.s0 = (((bits4.s0 & (0x0F00)) >> 8) - 8) * scale.s0; // dequantize a row of the 16 weights
82
+ dequantized_weights.s1 = (((bits4.s1 & (0x0F00)) >> 8) - 8) * scale.s1;
83
+ dequantized_weights.s2 = (((bits4.s2 & (0x0F00)) >> 8) - 8) * scale.s2;
84
+ dequantized_weights.s3 = (((bits4.s3 & (0x0F00)) >> 8) - 8) * scale.s3;
85
+ c0 += B * dequantized_weights.s0; // vector-scalar multiplication to accumulate
86
+ c1 += B * dequantized_weights.s1;
87
+ c2 += B * dequantized_weights.s2;
88
+ c3 += B * dequantized_weights.s3;
89
+
90
+ // j=3
91
+ B.s0123 = read_imageh(src1, gy*2 + (i+3)*(n_4));
92
+ B.s4567 = read_imageh(src1, gy*2 + (i+3)*(n_4)+1);
93
+ dequantized_weights.s0 = (((bits4.s0 & (0xF000)) >> 12) - 8) * scale.s0; // dequantize a row of the 16 weights
94
+ dequantized_weights.s1 = (((bits4.s1 & (0xF000)) >> 12) - 8) * scale.s1;
95
+ dequantized_weights.s2 = (((bits4.s2 & (0xF000)) >> 12) - 8) * scale.s2;
96
+ dequantized_weights.s3 = (((bits4.s3 & (0xF000)) >> 12) - 8) * scale.s3;
97
+ c0 += B * dequantized_weights.s0; // vector-scalar multiplication to accumulate
98
+ c1 += B * dequantized_weights.s1;
99
+ c2 += B * dequantized_weights.s2;
100
+ c3 += B * dequantized_weights.s3;
101
+ }
102
+
103
+ int idx = (gy<<3)*m + (gx<<2); // vectorized store 16 elements
104
+
105
+ // conditional check if store is to a valid location. Required when N is not a multiple of 8
106
+ // if statements allow registers to be reused for each store
107
+ // provides a performance boost due to reduced register footprint, which increases number of concurrent waves
108
+ if(idx+3 < m*n_no_padding){
109
+ vstore4((float4)(c0.s0, c1.s0, c2.s0, c3.s0), 0, dst + idx);
110
+ idx += m;
111
+ }
112
+ if(idx+3 < m*n_no_padding){
113
+ vstore4((float4)(c0.s1, c1.s1, c2.s1, c3.s1), 0, dst + idx);
114
+ idx += m;
115
+ }
116
+ if(idx+3 < m*n_no_padding){
117
+ vstore4((float4)(c0.s2, c1.s2, c2.s2, c3.s2), 0, dst + idx);
118
+ idx += m;
119
+ }
120
+ if(idx+3 < m*n_no_padding){
121
+ vstore4((float4)(c0.s3, c1.s3, c2.s3, c3.s3), 0, dst + idx);
122
+ idx += m;
123
+ }
124
+ if(idx+3 < m*n_no_padding){
125
+ vstore4((float4)(c0.s4, c1.s4, c2.s4, c3.s4), 0, dst + idx);
126
+ idx += m;
127
+ }
128
+ if(idx+3 < m*n_no_padding){
129
+ vstore4((float4)(c0.s5, c1.s5, c2.s5, c3.s5), 0, dst + idx);
130
+ idx += m;
131
+ }
132
+ if(idx+3 < m*n_no_padding){
133
+ vstore4((float4)(c0.s6, c1.s6, c2.s6, c3.s6), 0, dst + idx);
134
+ idx += m;
135
+ }
136
+ if(idx+3 < m*n_no_padding){
137
+ vstore4((float4)(c0.s7, c1.s7, c2.s7, c3.s7), 0, dst + idx);
138
+ }
139
+ }
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_noshuffle_q4_0_q8_1_dp4a.cl ADDED
@@ -0,0 +1,127 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #pragma OPENCL EXTENSION cl_khr_fp16 : enable
2
+ #pragma OPENCL EXTENSION cl_khr_subgroups : enable
3
+ #ifdef cl_khr_integer_dot_product
4
+ #pragma OPENCL EXTENSION cl_khr_integer_dot_product : enable
5
+ #endif
6
+
7
+ #define TILESIZE_N 32
8
+
9
+ // Expand the 4 nibbles in the low 16 bits of u into 4 bytes (value 0..15),
10
+ // packed for the int8 dp4a. The -8 zero-point is applied via the sum term.
11
+ #define EXP4(u) ( ((uint)((u) & 0x000Fu)) | \
12
+ (((uint)((u) & 0x00F0u)) << 4) | \
13
+ (((uint)((u) & 0x0F00u)) << 8) | \
14
+ (((uint)((u) & 0xF000u)) << 12) )
15
+
16
+ inline int dot8_q8a(uint8 qw, __local const uint * a) {
17
+ int r = 0;
18
+ r = dot_acc_sat_4x8packed_ss_int(qw.s0, a[0], r);
19
+ r = dot_acc_sat_4x8packed_ss_int(qw.s1, a[1], r);
20
+ r = dot_acc_sat_4x8packed_ss_int(qw.s2, a[2], r);
21
+ r = dot_acc_sat_4x8packed_ss_int(qw.s3, a[3], r);
22
+ r = dot_acc_sat_4x8packed_ss_int(qw.s4, a[4], r);
23
+ r = dot_acc_sat_4x8packed_ss_int(qw.s5, a[5], r);
24
+ r = dot_acc_sat_4x8packed_ss_int(qw.s6, a[6], r);
25
+ r = dot_acc_sat_4x8packed_ss_int(qw.s7, a[7], r);
26
+ return r;
27
+ }
28
+
29
+ __attribute__((qcom_wave_pair_mode(1)))
30
+ kernel void kernel_gemm_noshuffle_q4_0_q8_1_dp4a(
31
+ __global const ushort * src0_q, // q4_0 nibbles (4/ushort, feature-major)
32
+ __global const half * src0_d, // per-32-block scale, feature-major
33
+ __global const uint * src1_qa, // q8_1 activations int8 (as uint, 4/elem) [N, K]
34
+ __global const half * src1_da, // q8_1 per-block scale [N, K/32]
35
+ __global const half * src1_sa, // q8_1 per-block sum*d [N, K/32]
36
+ __global float * dst,
37
+ ulong offsetd,
38
+ int m, // output features (rows)
39
+ int n_no_padding, // tokens (cols)
40
+ int k // K (== ne00)
41
+ ) {
42
+ dst = (global float *)((global char *)dst + offsetd);
43
+
44
+ const uint lid = get_local_id(0); // 0..63 -> row within the M-tile
45
+ const uint block_id_m = get_global_id(1);
46
+ const uint block_id_n = get_global_id(2);
47
+
48
+ const uint row = block_id_m * 64 + lid;
49
+ const uint col_base = block_id_n * TILESIZE_N;
50
+ const bool row_valid = row < (uint)m;
51
+ const uint rrow = row_valid ? row : 0; // clamp OOB rows; their writes are masked
52
+
53
+ const uint k_u = (uint)k >> 2; // K in uint (int8x4) units
54
+ const uint k_b = (uint)k >> 5; // blocks-of-32 along K
55
+
56
+ __local uint sh_qa[TILESIZE_N][8];
57
+ __local half sh_d[TILESIZE_N];
58
+ __local half sh_s[TILESIZE_N];
59
+
60
+ #define NGROUPS (TILESIZE_N / 4)
61
+ float4 acc[NGROUPS];
62
+ #pragma unroll
63
+ for (int g = 0; g < NGROUPS; ++g) acc[g] = (float4)(0.0f);
64
+
65
+ for (uint step = 0; step < (uint)k; step += 32) {
66
+ const uint sub = step >> 5;
67
+
68
+ const float d_w = (float)src0_d[rrow + sub * (uint)m];
69
+
70
+ // 8 weight uints (32 nibbles) for this row, this 32-block. Feature-major:
71
+ // src0_q[row + (k/4 + u)*m], k/4 = step/4 (= step>>2). EXP4 -> dp4a int8.
72
+ const uint qsbase = rrow + (step >> 2) * (uint)m;
73
+ uint8 qw;
74
+ qw.s0 = EXP4(src0_q[qsbase + 0 * m]);
75
+ qw.s1 = EXP4(src0_q[qsbase + 1 * m]);
76
+ qw.s2 = EXP4(src0_q[qsbase + 2 * m]);
77
+ qw.s3 = EXP4(src0_q[qsbase + 3 * m]);
78
+ qw.s4 = EXP4(src0_q[qsbase + 4 * m]);
79
+ qw.s5 = EXP4(src0_q[qsbase + 5 * m]);
80
+ qw.s6 = EXP4(src0_q[qsbase + 6 * m]);
81
+ qw.s7 = EXP4(src0_q[qsbase + 7 * m]);
82
+
83
+ // cooperatively stage the 32-token x 32-K int8 activations to LDS
84
+ for (uint idx = lid; idx < TILESIZE_N * 8; idx += 64) {
85
+ const uint t = idx >> 3;
86
+ const uint u = idx & 7;
87
+ const uint c = col_base + t;
88
+ sh_qa[t][u] = (c < (uint)n_no_padding) ? src1_qa[c * k_u + (step >> 2) + u] : 0u;
89
+ }
90
+ if (lid < TILESIZE_N) {
91
+ const uint c = col_base + lid;
92
+ sh_d[lid] = (c < (uint)n_no_padding) ? src1_da[c * k_b + sub] : (half)0;
93
+ sh_s[lid] = (c < (uint)n_no_padding) ? src1_sa[c * k_b + sub] : (half)0;
94
+ }
95
+ barrier(CLK_LOCAL_MEM_FENCE);
96
+
97
+ #define LD4(arr, b) ((float4)((float)arr[(b)+0], (float)arr[(b)+1], (float)arr[(b)+2], (float)arr[(b)+3]))
98
+ #pragma unroll
99
+ for (int g = 0; g < NGROUPS; ++g) {
100
+ const int b = g * 4;
101
+ float4 rf;
102
+ rf.s0 = (float)dot8_q8a(qw, sh_qa[b+0]); rf.s1 = (float)dot8_q8a(qw, sh_qa[b+1]);
103
+ rf.s2 = (float)dot8_q8a(qw, sh_qa[b+2]); rf.s3 = (float)dot8_q8a(qw, sh_qa[b+3]);
104
+ // q4_0: w = d*(q-8) -> d_w * (a_d * dp4a(q,qa) - 8 * a_s)
105
+ acc[g] += d_w * (LD4(sh_d, b) * rf - 8.0f * LD4(sh_s, b));
106
+ }
107
+ #undef LD4
108
+ barrier(CLK_LOCAL_MEM_FENCE);
109
+ }
110
+
111
+ if (!row_valid) {
112
+ return;
113
+ }
114
+
115
+ // dst is [token, feature] row-major (stride m): dst[col*m + row].
116
+ #pragma unroll
117
+ for (int g = 0; g < NGROUPS; ++g) {
118
+ const uint b = (uint)(g * 4);
119
+ const float4 a = acc[g];
120
+ const uint c0 = col_base + b;
121
+ if (c0 + 0 < (uint)n_no_padding) dst[(c0 + 0) * (uint)m + row] = a.s0;
122
+ if (c0 + 1 < (uint)n_no_padding) dst[(c0 + 1) * (uint)m + row] = a.s1;
123
+ if (c0 + 2 < (uint)n_no_padding) dst[(c0 + 2) * (uint)m + row] = a.s2;
124
+ if (c0 + 3 < (uint)n_no_padding) dst[(c0 + 3) * (uint)m + row] = a.s3;
125
+ }
126
+ #undef NGROUPS
127
+ }
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_noshuffle_q4_1_f32.cl ADDED
@@ -0,0 +1,132 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #pragma OPENCL EXTENSION cl_khr_fp16 : enable
2
+ #pragma OPENCL EXTENSION cl_qcom_reqd_sub_group_size : enable
3
+
4
+ #ifdef cl_qcom_reqd_sub_group_size
5
+ #pragma OPENCL EXTENSION cl_qcom_reqd_sub_group_size : enable
6
+ #define ADRENO_GPU 1
7
+ #define REQD_SUBGROUP_SIZE_128 __attribute__((qcom_reqd_sub_group_size("full")))
8
+ #endif
9
+
10
+ #ifdef ADRENO_GPU
11
+ REQD_SUBGROUP_SIZE_128
12
+ #endif
13
+
14
+ kernel void kernel_gemm_noshuffle_q4_1_f32(
15
+ global const ushort * src0_q,
16
+ global const half * src0_d,
17
+ global const half * src0_m,
18
+ read_only image1d_buffer_t src1,
19
+ global float * dst,
20
+ ulong offsetd,
21
+ int m,
22
+ int n,
23
+ int k,
24
+ int n_no_padding
25
+ ) {
26
+ dst = (global float *)((global char *)dst + offsetd);
27
+
28
+ int m_4 = m >> 2;
29
+ int n_4 = n >> 2;
30
+
31
+ int gy = get_global_id(0);
32
+ int gx = get_global_id(1);
33
+ int gx_2 = gx << 2;
34
+
35
+ half8 c0 = 0, c1 = 0, c2 = 0, c3 = 0;
36
+ half8 B;
37
+ half4 dequantized_weights;
38
+
39
+ global const ushort* weight_ptr = src0_q + gx_2;
40
+ global const half* scale_ptr = src0_d + gx_2;
41
+ global const half* min_ptr = src0_m + gx_2;
42
+
43
+ for(int i = 0; i < k; i += 4) {
44
+ B.s0123 = read_imageh(src1, gy*2 + (i)*(n_4));
45
+ B.s4567 = read_imageh(src1, gy*2 + (i)*(n_4)+1);
46
+
47
+ ushort4 bits4 = vload4(0, weight_ptr + (i/4)*(m));
48
+
49
+ half4 scale = vload4(0, scale_ptr + (i/32)*(m));
50
+ half4 minv = vload4(0, min_ptr + (i/32)*(m));
51
+
52
+ // j=0
53
+ dequantized_weights.s0 = (bits4.s0 & (0x000F)) * scale.s0 + minv.s0;
54
+ dequantized_weights.s1 = (bits4.s1 & (0x000F)) * scale.s1 + minv.s1;
55
+ dequantized_weights.s2 = (bits4.s2 & (0x000F)) * scale.s2 + minv.s2;
56
+ dequantized_weights.s3 = (bits4.s3 & (0x000F)) * scale.s3 + minv.s3;
57
+ c0 += B * dequantized_weights.s0;
58
+ c1 += B * dequantized_weights.s1;
59
+ c2 += B * dequantized_weights.s2;
60
+ c3 += B * dequantized_weights.s3;
61
+
62
+ // j=1
63
+ B.s0123 = read_imageh(src1, gy*2 + (i+1)*(n_4));
64
+ B.s4567 = read_imageh(src1, gy*2 + (i+1)*(n_4)+1);
65
+ dequantized_weights.s0 = ((bits4.s0 & (0x00F0)) >> 4) * scale.s0 + minv.s0;
66
+ dequantized_weights.s1 = ((bits4.s1 & (0x00F0)) >> 4) * scale.s1 + minv.s1;
67
+ dequantized_weights.s2 = ((bits4.s2 & (0x00F0)) >> 4) * scale.s2 + minv.s2;
68
+ dequantized_weights.s3 = ((bits4.s3 & (0x00F0)) >> 4) * scale.s3 + minv.s3;
69
+ c0 += B * dequantized_weights.s0;
70
+ c1 += B * dequantized_weights.s1;
71
+ c2 += B * dequantized_weights.s2;
72
+ c3 += B * dequantized_weights.s3;
73
+
74
+ // j=2
75
+ B.s0123 = read_imageh(src1, gy*2 + (i+2)*(n_4));
76
+ B.s4567 = read_imageh(src1, gy*2 + (i+2)*(n_4)+1);
77
+ dequantized_weights.s0 = ((bits4.s0 & (0x0F00)) >> 8) * scale.s0 + minv.s0;
78
+ dequantized_weights.s1 = ((bits4.s1 & (0x0F00)) >> 8) * scale.s1 + minv.s1;
79
+ dequantized_weights.s2 = ((bits4.s2 & (0x0F00)) >> 8) * scale.s2 + minv.s2;
80
+ dequantized_weights.s3 = ((bits4.s3 & (0x0F00)) >> 8) * scale.s3 + minv.s3;
81
+ c0 += B * dequantized_weights.s0;
82
+ c1 += B * dequantized_weights.s1;
83
+ c2 += B * dequantized_weights.s2;
84
+ c3 += B * dequantized_weights.s3;
85
+
86
+ // j=3
87
+ B.s0123 = read_imageh(src1, gy*2 + (i+3)*(n_4));
88
+ B.s4567 = read_imageh(src1, gy*2 + (i+3)*(n_4)+1);
89
+ dequantized_weights.s0 = ((bits4.s0 & (0xF000)) >> 12) * scale.s0 + minv.s0;
90
+ dequantized_weights.s1 = ((bits4.s1 & (0xF000)) >> 12) * scale.s1 + minv.s1;
91
+ dequantized_weights.s2 = ((bits4.s2 & (0xF000)) >> 12) * scale.s2 + minv.s2;
92
+ dequantized_weights.s3 = ((bits4.s3 & (0xF000)) >> 12) * scale.s3 + minv.s3;
93
+ c0 += B * dequantized_weights.s0;
94
+ c1 += B * dequantized_weights.s1;
95
+ c2 += B * dequantized_weights.s2;
96
+ c3 += B * dequantized_weights.s3;
97
+ }
98
+
99
+ int idx = (gy<<3)*m + (gx<<2);
100
+
101
+ if(idx+3 < m*n_no_padding){
102
+ vstore4((float4)(c0.s0, c1.s0, c2.s0, c3.s0), 0, dst + idx);
103
+ idx += m;
104
+ }
105
+ if(idx+3 < m*n_no_padding){
106
+ vstore4((float4)(c0.s1, c1.s1, c2.s1, c3.s1), 0, dst + idx);
107
+ idx += m;
108
+ }
109
+ if(idx+3 < m*n_no_padding){
110
+ vstore4((float4)(c0.s2, c1.s2, c2.s2, c3.s2), 0, dst + idx);
111
+ idx += m;
112
+ }
113
+ if(idx+3 < m*n_no_padding){
114
+ vstore4((float4)(c0.s3, c1.s3, c2.s3, c3.s3), 0, dst + idx);
115
+ idx += m;
116
+ }
117
+ if(idx+3 < m*n_no_padding){
118
+ vstore4((float4)(c0.s4, c1.s4, c2.s4, c3.s4), 0, dst + idx);
119
+ idx += m;
120
+ }
121
+ if(idx+3 < m*n_no_padding){
122
+ vstore4((float4)(c0.s5, c1.s5, c2.s5, c3.s5), 0, dst + idx);
123
+ idx += m;
124
+ }
125
+ if(idx+3 < m*n_no_padding){
126
+ vstore4((float4)(c0.s6, c1.s6, c2.s6, c3.s6), 0, dst + idx);
127
+ idx += m;
128
+ }
129
+ if(idx+3 < m*n_no_padding){
130
+ vstore4((float4)(c0.s7, c1.s7, c2.s7, c3.s7), 0, dst + idx);
131
+ }
132
+ }
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_noshuffle_q4_k_f32.cl ADDED
@@ -0,0 +1,172 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #pragma OPENCL EXTENSION cl_khr_fp16 : enable
2
+
3
+ #ifdef cl_qcom_reqd_sub_group_size
4
+ #pragma OPENCL EXTENSION cl_qcom_reqd_sub_group_size : enable
5
+ #define ADRENO_GPU 1
6
+ #define REQD_SUBGROUP_SIZE_128 __attribute__((qcom_reqd_sub_group_size("full")))
7
+ #endif
8
+ #define QK_K 256
9
+ #define K_SCALE_SIZE 12
10
+
11
+ inline void get_scale_min_k4(
12
+ int j,
13
+ global const uchar * q,
14
+ uchar * d,
15
+ uchar * m,
16
+ uchar mask_d6,
17
+ uchar mask_d4,
18
+ uchar mask_hi2
19
+ ) {
20
+ if (j < 4) {
21
+ *d = q[j] & mask_d6;
22
+ *m = q[j+4] & mask_d6;
23
+ } else {
24
+ *d = (q[j+4] & mask_d4) | ((q[j-4] & mask_hi2) >> 2);
25
+ *m = ((q[j+4] >> 4) & mask_d4) | ((q[j] & mask_hi2) >> 2);
26
+ }
27
+ }
28
+
29
+ #ifdef ADRENO_GPU
30
+ REQD_SUBGROUP_SIZE_128
31
+ #endif
32
+ kernel void kernel_gemm_noshuffle_q4_k_f32(
33
+ global const ushort * src0_q,
34
+ global const uchar * src0_s,
35
+ global const half * src0_d,
36
+ global const half * src0_dm,
37
+ read_only image1d_buffer_t src1,
38
+ global float * dst,
39
+ ulong offsetd,
40
+ int m,
41
+ int n,
42
+ int k,
43
+ int n_no_padding,
44
+ uchar mask_d6,
45
+ uchar mask_d4,
46
+ uchar mask_hi2
47
+ ) {
48
+ dst = (global float *)((global char *)dst + offsetd);
49
+ int n_4 = n >> 2;
50
+ int gy = get_global_id(0);
51
+ int gx = get_global_id(1);
52
+ int gx_2 = gx << 2;
53
+
54
+ half8 c0 = 0, c1 = 0, c2 = 0, c3 = 0;
55
+ half8 B;
56
+ half4 dequantized_weights;
57
+
58
+ int num_blocks_K = k / QK_K;
59
+
60
+ global const ushort * weight_ptr = src0_q + gx_2;
61
+ global const half * d_ptr = src0_d + gx_2;
62
+ global const half * dm_ptr = src0_dm + gx_2;
63
+
64
+ for (int i = 0; i < k; i += 32) {
65
+ int sb_idx = i / QK_K;
66
+ int sub_idx = (i / 32) % 8;
67
+
68
+ half4 d = vload4(0, d_ptr + sb_idx * m);
69
+ half4 dm = vload4(0, dm_ptr + sb_idx * m);
70
+
71
+ global const uchar * sc0 = src0_s + (gx_2+0) * num_blocks_K * K_SCALE_SIZE + sb_idx * K_SCALE_SIZE;
72
+ global const uchar * sc1 = src0_s + (gx_2+1) * num_blocks_K * K_SCALE_SIZE + sb_idx * K_SCALE_SIZE;
73
+ global const uchar * sc2 = src0_s + (gx_2+2) * num_blocks_K * K_SCALE_SIZE + sb_idx * K_SCALE_SIZE;
74
+ global const uchar * sc3 = src0_s + (gx_2+3) * num_blocks_K * K_SCALE_SIZE + sb_idx * K_SCALE_SIZE;
75
+
76
+ uchar sv0, mn0, sv1, mn1, sv2, mn2, sv3, mn3;
77
+ get_scale_min_k4(sub_idx, sc0, &sv0, &mn0, mask_d6, mask_d4, mask_hi2);
78
+ get_scale_min_k4(sub_idx, sc1, &sv1, &mn1, mask_d6, mask_d4, mask_hi2);
79
+ get_scale_min_k4(sub_idx, sc2, &sv2, &mn2, mask_d6, mask_d4, mask_hi2);
80
+ get_scale_min_k4(sub_idx, sc3, &sv3, &mn3, mask_d6, mask_d4, mask_hi2);
81
+
82
+ half4 scale = convert_half4(convert_float4(d) * convert_float4((uchar4)(sv0, sv1, sv2, sv3)));
83
+ half4 mval = convert_half4(convert_float4(dm) * convert_float4((uchar4)(mn0, mn1, mn2, mn3)));
84
+
85
+ for (int l = 0; l < 32; l += 4) {
86
+ int ki = i + l;
87
+ ushort4 bits4 = vload4(0, weight_ptr + (ki/4) * m);
88
+
89
+ // j=0
90
+ B.s0123 = read_imageh(src1, gy*2 + (ki+0) * n_4);
91
+ B.s4567 = read_imageh(src1, gy*2+1 + (ki+0) * n_4);
92
+ dequantized_weights.s0 = (bits4.s0 & 0x000F) * scale.s0 - mval.s0;
93
+ dequantized_weights.s1 = (bits4.s1 & 0x000F) * scale.s1 - mval.s1;
94
+ dequantized_weights.s2 = (bits4.s2 & 0x000F) * scale.s2 - mval.s2;
95
+ dequantized_weights.s3 = (bits4.s3 & 0x000F) * scale.s3 - mval.s3;
96
+ c0 += B * dequantized_weights.s0;
97
+ c1 += B * dequantized_weights.s1;
98
+ c2 += B * dequantized_weights.s2;
99
+ c3 += B * dequantized_weights.s3;
100
+
101
+ // j=1
102
+ B.s0123 = read_imageh(src1, gy*2 + (ki+1) * n_4);
103
+ B.s4567 = read_imageh(src1, gy*2+1 + (ki+1) * n_4);
104
+ dequantized_weights.s0 = ((bits4.s0 & 0x00F0) >> 4) * scale.s0 - mval.s0;
105
+ dequantized_weights.s1 = ((bits4.s1 & 0x00F0) >> 4) * scale.s1 - mval.s1;
106
+ dequantized_weights.s2 = ((bits4.s2 & 0x00F0) >> 4) * scale.s2 - mval.s2;
107
+ dequantized_weights.s3 = ((bits4.s3 & 0x00F0) >> 4) * scale.s3 - mval.s3;
108
+ c0 += B * dequantized_weights.s0;
109
+ c1 += B * dequantized_weights.s1;
110
+ c2 += B * dequantized_weights.s2;
111
+ c3 += B * dequantized_weights.s3;
112
+
113
+ // j=2
114
+ B.s0123 = read_imageh(src1, gy*2 + (ki+2) * n_4);
115
+ B.s4567 = read_imageh(src1, gy*2+1 + (ki+2) * n_4);
116
+ dequantized_weights.s0 = ((bits4.s0 & 0x0F00) >> 8) * scale.s0 - mval.s0;
117
+ dequantized_weights.s1 = ((bits4.s1 & 0x0F00) >> 8) * scale.s1 - mval.s1;
118
+ dequantized_weights.s2 = ((bits4.s2 & 0x0F00) >> 8) * scale.s2 - mval.s2;
119
+ dequantized_weights.s3 = ((bits4.s3 & 0x0F00) >> 8) * scale.s3 - mval.s3;
120
+ c0 += B * dequantized_weights.s0;
121
+ c1 += B * dequantized_weights.s1;
122
+ c2 += B * dequantized_weights.s2;
123
+ c3 += B * dequantized_weights.s3;
124
+
125
+ // j=3
126
+ B.s0123 = read_imageh(src1, gy*2 + (ki+3) * n_4);
127
+ B.s4567 = read_imageh(src1, gy*2+1 + (ki+3) * n_4);
128
+ dequantized_weights.s0 = ((bits4.s0 & 0xF000) >> 12) * scale.s0 - mval.s0;
129
+ dequantized_weights.s1 = ((bits4.s1 & 0xF000) >> 12) * scale.s1 - mval.s1;
130
+ dequantized_weights.s2 = ((bits4.s2 & 0xF000) >> 12) * scale.s2 - mval.s2;
131
+ dequantized_weights.s3 = ((bits4.s3 & 0xF000) >> 12) * scale.s3 - mval.s3;
132
+ c0 += B * dequantized_weights.s0;
133
+ c1 += B * dequantized_weights.s1;
134
+ c2 += B * dequantized_weights.s2;
135
+ c3 += B * dequantized_weights.s3;
136
+ }
137
+ }
138
+
139
+ int idx = (gy<<3)*m + (gx<<2);
140
+
141
+ if (idx+3 < m*n_no_padding) {
142
+ vstore4((float4)(c0.s0, c1.s0, c2.s0, c3.s0), 0, dst + idx);
143
+ idx += m;
144
+ }
145
+ if (idx+3 < m*n_no_padding) {
146
+ vstore4((float4)(c0.s1, c1.s1, c2.s1, c3.s1), 0, dst + idx);
147
+ idx += m;
148
+ }
149
+ if (idx+3 < m*n_no_padding) {
150
+ vstore4((float4)(c0.s2, c1.s2, c2.s2, c3.s2), 0, dst + idx);
151
+ idx += m;
152
+ }
153
+ if (idx+3 < m*n_no_padding) {
154
+ vstore4((float4)(c0.s3, c1.s3, c2.s3, c3.s3), 0, dst + idx);
155
+ idx += m;
156
+ }
157
+ if (idx+3 < m*n_no_padding) {
158
+ vstore4((float4)(c0.s4, c1.s4, c2.s4, c3.s4), 0, dst + idx);
159
+ idx += m;
160
+ }
161
+ if (idx+3 < m*n_no_padding) {
162
+ vstore4((float4)(c0.s5, c1.s5, c2.s5, c3.s5), 0, dst + idx);
163
+ idx += m;
164
+ }
165
+ if (idx+3 < m*n_no_padding) {
166
+ vstore4((float4)(c0.s6, c1.s6, c2.s6, c3.s6), 0, dst + idx);
167
+ idx += m;
168
+ }
169
+ if (idx+3 < m*n_no_padding) {
170
+ vstore4((float4)(c0.s7, c1.s7, c2.s7, c3.s7), 0, dst + idx);
171
+ }
172
+ }
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_noshuffle_q4_k_q8_1_dp4a.cl ADDED
@@ -0,0 +1,281 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #pragma OPENCL EXTENSION cl_khr_fp16 : enable
2
+ #pragma OPENCL EXTENSION cl_khr_subgroups : enable
3
+ #ifdef cl_khr_integer_dot_product
4
+ #pragma OPENCL EXTENSION cl_khr_integer_dot_product : enable
5
+ #endif
6
+
7
+ #ifndef TILESIZE_N
8
+ #define TILESIZE_N 32
9
+ #endif
10
+ #define QK_K 256
11
+ #define K_SCALE_SIZE 12
12
+
13
+ inline void get_scale_min_k4(
14
+ int j,
15
+ global const uchar * q,
16
+ uchar * d,
17
+ uchar * m,
18
+ uchar mask_d6,
19
+ uchar mask_d4,
20
+ uchar mask_hi2
21
+ ) {
22
+ if (j < 4) {
23
+ *d = q[j] & mask_d6;
24
+ *m = q[j+4] & mask_d6;
25
+ } else {
26
+ *d = (q[j+4] & mask_d4) | ((q[j-4] & mask_hi2) >> 2);
27
+ *m = ((q[j+4] >> 4) & mask_d4) | ((q[j] & mask_hi2) >> 2);
28
+ }
29
+ }
30
+
31
+ // Expand the 4 nibbles in the low 16 bits of `u` into 4 bytes (one nibble per
32
+ // byte, value 0..15), packed for the int8 dp4a.
33
+ #define EXP4(u) ( ((uint)((u) & 0x000Fu)) | \
34
+ (((uint)((u) & 0x00F0u)) << 4) | \
35
+ (((uint)((u) & 0x0F00u)) << 8) | \
36
+ (((uint)((u) & 0xF000u)) << 12) )
37
+
38
+ // 32-K dp4a dot of one token's int8 activations (8 packed uints in lm) against the
39
+ // row's 8 packed weight uints. qw passed by value as a uint8 (register), not an array.
40
+ inline int dot8_q8a(uint8 qw, __local const uint * a) {
41
+ int r = 0;
42
+ r = dot_acc_sat_4x8packed_ss_int(qw.s0, a[0], r);
43
+ r = dot_acc_sat_4x8packed_ss_int(qw.s1, a[1], r);
44
+ r = dot_acc_sat_4x8packed_ss_int(qw.s2, a[2], r);
45
+ r = dot_acc_sat_4x8packed_ss_int(qw.s3, a[3], r);
46
+ r = dot_acc_sat_4x8packed_ss_int(qw.s4, a[4], r);
47
+ r = dot_acc_sat_4x8packed_ss_int(qw.s5, a[5], r);
48
+ r = dot_acc_sat_4x8packed_ss_int(qw.s6, a[6], r);
49
+ r = dot_acc_sat_4x8packed_ss_int(qw.s7, a[7], r);
50
+ return r;
51
+ }
52
+
53
+ __attribute__((qcom_wave_pair_mode(1)))
54
+ kernel void kernel_gemm_noshuffle_q4_k_q8_1_dp4a(
55
+ __global const ushort * src0_q, // q4_K weights (noshuffle, packed nibbles)
56
+ __global const uchar * src0_s, // 6-bit scale/min codes
57
+ __global const half * src0_d, // per-superblock scale
58
+ __global const half * src0_dm, // per-superblock min
59
+ __global const uint * src1_qa, // q8_1 activations int8 (as uint, 4/elem) [N, K]
60
+ __global const half * src1_da, // q8_1 per-block scale [N, K/32]
61
+ __global const half * src1_sa, // q8_1 per-block sum*d [N, K/32]
62
+ __global float * dst,
63
+ ulong offsetd,
64
+ int m, // output features (rows)
65
+ int n_no_padding, // tokens (cols)
66
+ int k, // K (== ne00)
67
+ uchar mask_d6,
68
+ uchar mask_d4,
69
+ uchar mask_hi2
70
+ ) {
71
+ dst = (global float *)((global char *)dst + offsetd);
72
+
73
+ const uint lid = get_local_id(0); // 0..63 -> row within the M-tile
74
+ const uint block_id_m = get_global_id(1);
75
+ const uint block_id_n = get_global_id(2);
76
+
77
+ const uint row = block_id_m * 64 + lid;
78
+ const uint col_base = block_id_n * TILESIZE_N;
79
+ const bool row_valid = row < (uint)m;
80
+ const uint rrow = row_valid ? row : 0; // clamp OOB rows; their writes are masked
81
+
82
+ const uint num_superblocks = (uint)k / QK_K;
83
+ const uint k_u = (uint)k >> 2; // K in uint (int8x4) units
84
+ const uint k_b = (uint)k >> 5; // blocks-of-32 along K
85
+
86
+ __local uint sh_qa[TILESIZE_N][8];
87
+ __local half sh_d[TILESIZE_N];
88
+ __local half sh_s[TILESIZE_N];
89
+
90
+ // One float4 vector-register accumulator per group of 4 tokens (NGROUPS = TILESIZE_N/4).
91
+ #define NGROUPS (TILESIZE_N / 4)
92
+ float4 acc[NGROUPS];
93
+ #pragma unroll
94
+ for (int g = 0; g < NGROUPS; ++g) { acc[g] = (float4)(0.0f); }
95
+
96
+ for (uint step = 0; step < (uint)k; step += 32) {
97
+ const uint sub = step >> 5;
98
+ const uint sb_idx = step / QK_K;
99
+ const uint sub_idx = sub & 7;
100
+
101
+ // weight scale/min for this WI's row, this subblock
102
+ const float dd = (float)src0_d [rrow + sb_idx * m];
103
+ const float dmm = (float)src0_dm[rrow + sb_idx * m];
104
+ global const uchar * sc = src0_s + rrow * num_superblocks * K_SCALE_SIZE + sb_idx * K_SCALE_SIZE;
105
+ uchar sv, mn;
106
+ get_scale_min_k4(sub_idx, sc, &sv, &mn, mask_d6, mask_d4, mask_hi2);
107
+ const float scale = dd * (float)sv;
108
+ const float minv = dmm * (float)mn;
109
+
110
+ // repack this row's 32 weight nibbles into 8 dp4a uints. The packed q4_K
111
+ // layout stores one ushort = 4 consecutive-K nibbles for a row at
112
+ // src0_q[row + (K_group)*m], K_group = step/4 + u.
113
+ const uint wbase = rrow + (step >> 2) * (uint)m;
114
+ uint8 qw;
115
+ qw.s0 = EXP4(src0_q[wbase + 0 * m]);
116
+ qw.s1 = EXP4(src0_q[wbase + 1 * m]);
117
+ qw.s2 = EXP4(src0_q[wbase + 2 * m]);
118
+ qw.s3 = EXP4(src0_q[wbase + 3 * m]);
119
+ qw.s4 = EXP4(src0_q[wbase + 4 * m]);
120
+ qw.s5 = EXP4(src0_q[wbase + 5 * m]);
121
+ qw.s6 = EXP4(src0_q[wbase + 6 * m]);
122
+ qw.s7 = EXP4(src0_q[wbase + 7 * m]);
123
+
124
+ // cooperatively stage the 32-token x 32-K int8 activations to lm
125
+ for (uint idx = lid; idx < TILESIZE_N * 8; idx += 64) {
126
+ const uint t = idx >> 3;
127
+ const uint u = idx & 7;
128
+ const uint c = col_base + t;
129
+ sh_qa[t][u] = (c < (uint)n_no_padding) ? src1_qa[c * k_u + (step >> 2) + u] : 0u;
130
+ }
131
+ if (lid < TILESIZE_N) {
132
+ const uint c = col_base + lid;
133
+ sh_d[lid] = (c < (uint)n_no_padding) ? src1_da[c * k_b + sub] : (half)0;
134
+ sh_s[lid] = (c < (uint)n_no_padding) ? src1_sa[c * k_b + sub] : (half)0;
135
+ }
136
+ barrier(CLK_LOCAL_MEM_FENCE);
137
+
138
+ #define LD4(arr, b) ((float4)((float)arr[(b)+0], (float)arr[(b)+1], (float)arr[(b)+2], (float)arr[(b)+3]))
139
+ #pragma unroll
140
+ for (int g = 0; g < NGROUPS; ++g) {
141
+ const int b = g * 4;
142
+ float4 rf;
143
+ rf.s0 = (float)dot8_q8a(qw, sh_qa[b+0]); rf.s1 = (float)dot8_q8a(qw, sh_qa[b+1]);
144
+ rf.s2 = (float)dot8_q8a(qw, sh_qa[b+2]); rf.s3 = (float)dot8_q8a(qw, sh_qa[b+3]);
145
+ acc[g] += scale * LD4(sh_d, b) * rf - minv * LD4(sh_s, b);
146
+ }
147
+ #undef LD4
148
+ barrier(CLK_LOCAL_MEM_FENCE);
149
+ }
150
+
151
+ if (!row_valid) {
152
+ return;
153
+ }
154
+
155
+ // dst is [token, feature] row-major (stride m): dst[col*m + row]. Scatter each
156
+ // lane with a per-token padding guard (dst is non-contiguous in token).
157
+ #pragma unroll
158
+ for (int g = 0; g < NGROUPS; ++g) {
159
+ const uint b = (uint)(g * 4);
160
+ const float4 a = acc[g];
161
+ const uint c0 = col_base + b;
162
+ if (c0 + 0 < (uint)n_no_padding) dst[(c0 + 0) * (uint)m + row] = a.s0;
163
+ if (c0 + 1 < (uint)n_no_padding) dst[(c0 + 1) * (uint)m + row] = a.s1;
164
+ if (c0 + 2 < (uint)n_no_padding) dst[(c0 + 2) * (uint)m + row] = a.s2;
165
+ if (c0 + 3 < (uint)n_no_padding) dst[(c0 + 3) * (uint)m + row] = a.s3;
166
+ }
167
+ #undef NGROUPS
168
+ }
169
+
170
+ __attribute__((qcom_wave_pair_mode(1)))
171
+ kernel void kernel_gemm_noshuffle_q4_k_q8_1_dp4a_wimg(
172
+ __read_only image1d_buffer_t src0_q_img, // q4_K weights as uint32 texels (2 ushorts/texel)
173
+ __global const uchar * src0_s, // 6-bit scale/min codes
174
+ __global const half * src0_d, // per-superblock scale
175
+ __global const half * src0_dm, // per-superblock min
176
+ __global const uint * src1_qa, // q8_1 activations int8 (as uint, 4/elem) [N, K]
177
+ __global const half * src1_da, // q8_1 per-block scale [N, K/32]
178
+ __global const half * src1_sa, // q8_1 per-block sum*d [N, K/32]
179
+ __global float * dst,
180
+ ulong offsetd,
181
+ int m, // output features (rows)
182
+ int n_no_padding, // tokens (cols)
183
+ int k, // K (== ne00)
184
+ uchar mask_d6,
185
+ uchar mask_d4,
186
+ uchar mask_hi2
187
+ ) {
188
+ dst = (global float *)((global char *)dst + offsetd);
189
+
190
+ const uint lid = get_local_id(0); // 0..63 -> row within the M-tile
191
+ const uint block_id_m = get_global_id(1);
192
+ const uint block_id_n = get_global_id(2);
193
+
194
+ const uint row = block_id_m * 64 + lid;
195
+ const uint col_base = block_id_n * TILESIZE_N;
196
+ const bool row_valid = row < (uint)m;
197
+ const uint rrow = row_valid ? row : 0; // clamp OOB rows; their writes are masked
198
+
199
+ // Constant per WI: the ushort the row needs always sits in the same half of
200
+ // its uint32 texel (m even => index parity == rrow parity). Hoist the shift.
201
+ const uint sel = (rrow & 1u) * 16u;
202
+
203
+ const uint k_u = (uint)k >> 2; // K in uint (int8x4) units
204
+ const uint k_b = (uint)k >> 5; // blocks-of-32 along K
205
+ const uint num_superblocks = (uint)k / QK_K;
206
+
207
+ __local uint sh_qa[TILESIZE_N][8];
208
+ __local half sh_d[TILESIZE_N];
209
+ __local half sh_s[TILESIZE_N];
210
+
211
+ #define NGROUPS (TILESIZE_N / 4)
212
+ float4 acc[NGROUPS];
213
+ #pragma unroll
214
+ for (int g = 0; g < NGROUPS; ++g) acc[g] = (float4)(0.0f);
215
+
216
+ for (uint step = 0; step < (uint)k; step += 32) {
217
+ const uint sub = step >> 5;
218
+ const uint sb_idx = step / QK_K;
219
+ const uint sub_idx = sub & 7;
220
+
221
+ const float dd = (float)src0_d [rrow + sb_idx * m];
222
+ const float dmm = (float)src0_dm[rrow + sb_idx * m];
223
+ global const uchar * sc = src0_s + rrow * num_superblocks * K_SCALE_SIZE + sb_idx * K_SCALE_SIZE;
224
+ uchar sv, mn;
225
+ get_scale_min_k4(sub_idx, sc, &sv, &mn, mask_d6, mask_d4, mask_hi2);
226
+ const float scale = dd * (float)sv;
227
+ const float minv = dmm * (float)mn;
228
+
229
+ const uint wbase = rrow + (step >> 2) * (uint)m;
230
+ uint8 qw;
231
+ qw.s0 = EXP4(read_imageui(src0_q_img, (int)((wbase + 0 * m) >> 1)).x >> sel);
232
+ qw.s1 = EXP4(read_imageui(src0_q_img, (int)((wbase + 1 * m) >> 1)).x >> sel);
233
+ qw.s2 = EXP4(read_imageui(src0_q_img, (int)((wbase + 2 * m) >> 1)).x >> sel);
234
+ qw.s3 = EXP4(read_imageui(src0_q_img, (int)((wbase + 3 * m) >> 1)).x >> sel);
235
+ qw.s4 = EXP4(read_imageui(src0_q_img, (int)((wbase + 4 * m) >> 1)).x >> sel);
236
+ qw.s5 = EXP4(read_imageui(src0_q_img, (int)((wbase + 5 * m) >> 1)).x >> sel);
237
+ qw.s6 = EXP4(read_imageui(src0_q_img, (int)((wbase + 6 * m) >> 1)).x >> sel);
238
+ qw.s7 = EXP4(read_imageui(src0_q_img, (int)((wbase + 7 * m) >> 1)).x >> sel);
239
+
240
+ for (uint idx = lid; idx < TILESIZE_N * 8; idx += 64) {
241
+ const uint t = idx >> 3;
242
+ const uint u = idx & 7;
243
+ const uint c = col_base + t;
244
+ sh_qa[t][u] = (c < (uint)n_no_padding) ? src1_qa[c * k_u + (step >> 2) + u] : 0u;
245
+ }
246
+ if (lid < TILESIZE_N) {
247
+ const uint c = col_base + lid;
248
+ sh_d[lid] = (c < (uint)n_no_padding) ? src1_da[c * k_b + sub] : (half)0;
249
+ sh_s[lid] = (c < (uint)n_no_padding) ? src1_sa[c * k_b + sub] : (half)0;
250
+ }
251
+ barrier(CLK_LOCAL_MEM_FENCE);
252
+
253
+ #define LD4(arr, b) ((float4)((float)arr[(b)+0], (float)arr[(b)+1], (float)arr[(b)+2], (float)arr[(b)+3]))
254
+ #pragma unroll
255
+ for (int g = 0; g < NGROUPS; ++g) {
256
+ const int b = g * 4;
257
+ float4 rf;
258
+ rf.s0 = (float)dot8_q8a(qw, sh_qa[b+0]); rf.s1 = (float)dot8_q8a(qw, sh_qa[b+1]);
259
+ rf.s2 = (float)dot8_q8a(qw, sh_qa[b+2]); rf.s3 = (float)dot8_q8a(qw, sh_qa[b+3]);
260
+ acc[g] += scale * LD4(sh_d, b) * rf - minv * LD4(sh_s, b);
261
+ }
262
+ #undef LD4
263
+ barrier(CLK_LOCAL_MEM_FENCE);
264
+ }
265
+
266
+ if (!row_valid) {
267
+ return;
268
+ }
269
+
270
+ #pragma unroll
271
+ for (int g = 0; g < NGROUPS; ++g) {
272
+ const uint b = (uint)(g * 4);
273
+ const float4 a = acc[g];
274
+ const uint c0 = col_base + b;
275
+ if (c0 + 0 < (uint)n_no_padding) dst[(c0 + 0) * (uint)m + row] = a.s0;
276
+ if (c0 + 1 < (uint)n_no_padding) dst[(c0 + 1) * (uint)m + row] = a.s1;
277
+ if (c0 + 2 < (uint)n_no_padding) dst[(c0 + 2) * (uint)m + row] = a.s2;
278
+ if (c0 + 3 < (uint)n_no_padding) dst[(c0 + 3) * (uint)m + row] = a.s3;
279
+ }
280
+ #undef NGROUPS
281
+ }
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_noshuffle_q5_0_f32.cl ADDED
@@ -0,0 +1,131 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #pragma OPENCL EXTENSION cl_khr_fp16 : enable
2
+ #pragma OPENCL EXTENSION cl_qcom_reqd_sub_group_size : enable
3
+
4
+ #ifdef cl_qcom_reqd_sub_group_size
5
+ #pragma OPENCL EXTENSION cl_qcom_reqd_sub_group_size : enable
6
+ #define ADRENO_GPU 1
7
+ #define REQD_SUBGROUP_SIZE_128 __attribute__((qcom_reqd_sub_group_size("full")))
8
+ #endif
9
+
10
+ #ifdef ADRENO_GPU
11
+ REQD_SUBGROUP_SIZE_128
12
+ #endif
13
+
14
+ kernel void kernel_gemm_noshuffle_q5_0_f32(
15
+ global const ushort * src0_qs, // quantized A
16
+ global const uchar * src0_qh, // 5th bits
17
+ global const half * src0_d, // A scales
18
+ __read_only image1d_buffer_t src1, // B (1d image)
19
+ global float * dst, // C
20
+ int m, // M
21
+ int n, // N with padding
22
+ int k, // K
23
+ int n_no_padding // N without padding
24
+ ) {
25
+
26
+ int n_4 = n >> 2;
27
+
28
+ int gy = get_global_id(0);
29
+ int gx = get_global_id(1);
30
+ int gx_2 = gx << 2;
31
+
32
+ half8 c0 = 0, c1 = 0, c2 = 0, c3 = 0;
33
+ half8 B;
34
+ half4 dequantized_weights;
35
+
36
+ global const ushort * weight_ptr = src0_qs + gx_2;
37
+ global const uchar * qh_ptr = src0_qh + gx_2;
38
+ global const half * scale_ptr = src0_d + gx_2;
39
+
40
+ for (int i = 0; i < k; i += 4) {
41
+
42
+ B.s0123 = read_imageh(src1, gy*2 + i*n_4);
43
+ B.s4567 = read_imageh(src1, gy*2 + i*n_4 + 1);
44
+
45
+ ushort4 bits4 = vload4(0, weight_ptr + (i >> 2)*m);
46
+ uchar4 bits1 = vload4(0, qh_ptr + (i >> 3)*m);
47
+ uchar4 qh = bits1 >> (uchar4)(i & 4);
48
+
49
+ half4 scale = vload4(0, scale_ptr + (i >> 5)*m);
50
+
51
+ // j=0
52
+ dequantized_weights.s0 = (convert_half((bits4.s0 & 0x000F) | ((qh.s0 & 0x01) << 4)) - 16.0h) * scale.s0;
53
+ dequantized_weights.s1 = (convert_half((bits4.s1 & 0x000F) | ((qh.s1 & 0x01) << 4)) - 16.0h) * scale.s1;
54
+ dequantized_weights.s2 = (convert_half((bits4.s2 & 0x000F) | ((qh.s2 & 0x01) << 4)) - 16.0h) * scale.s2;
55
+ dequantized_weights.s3 = (convert_half((bits4.s3 & 0x000F) | ((qh.s3 & 0x01) << 4)) - 16.0h) * scale.s3;
56
+ c0 += B * dequantized_weights.s0;
57
+ c1 += B * dequantized_weights.s1;
58
+ c2 += B * dequantized_weights.s2;
59
+ c3 += B * dequantized_weights.s3;
60
+
61
+ // j=1
62
+ B.s0123 = read_imageh(src1, gy*2 + (i+1)*n_4);
63
+ B.s4567 = read_imageh(src1, gy*2 + (i+1)*n_4 + 1);
64
+ dequantized_weights.s0 = (convert_half(((bits4.s0 & 0x00F0) >> 4) | ((qh.s0 & 0x02) << 3)) - 16.0h) * scale.s0;
65
+ dequantized_weights.s1 = (convert_half(((bits4.s1 & 0x00F0) >> 4) | ((qh.s1 & 0x02) << 3)) - 16.0h) * scale.s1;
66
+ dequantized_weights.s2 = (convert_half(((bits4.s2 & 0x00F0) >> 4) | ((qh.s2 & 0x02) << 3)) - 16.0h) * scale.s2;
67
+ dequantized_weights.s3 = (convert_half(((bits4.s3 & 0x00F0) >> 4) | ((qh.s3 & 0x02) << 3)) - 16.0h) * scale.s3;
68
+ c0 += B * dequantized_weights.s0;
69
+ c1 += B * dequantized_weights.s1;
70
+ c2 += B * dequantized_weights.s2;
71
+ c3 += B * dequantized_weights.s3;
72
+
73
+ // j=2
74
+ B.s0123 = read_imageh(src1, gy*2 + (i+2)*n_4);
75
+ B.s4567 = read_imageh(src1, gy*2 + (i+2)*n_4 + 1);
76
+ dequantized_weights.s0 = (convert_half(((bits4.s0 & 0x0F00) >> 8) | ((qh.s0 & 0x04) << 2)) - 16.0h) * scale.s0;
77
+ dequantized_weights.s1 = (convert_half(((bits4.s1 & 0x0F00) >> 8) | ((qh.s1 & 0x04) << 2)) - 16.0h) * scale.s1;
78
+ dequantized_weights.s2 = (convert_half(((bits4.s2 & 0x0F00) >> 8) | ((qh.s2 & 0x04) << 2)) - 16.0h) * scale.s2;
79
+ dequantized_weights.s3 = (convert_half(((bits4.s3 & 0x0F00) >> 8) | ((qh.s3 & 0x04) << 2)) - 16.0h) * scale.s3;
80
+ c0 += B * dequantized_weights.s0;
81
+ c1 += B * dequantized_weights.s1;
82
+ c2 += B * dequantized_weights.s2;
83
+ c3 += B * dequantized_weights.s3;
84
+
85
+ // j=3
86
+ B.s0123 = read_imageh(src1, gy*2 + (i+3)*n_4);
87
+ B.s4567 = read_imageh(src1, gy*2 + (i+3)*n_4 + 1);
88
+ dequantized_weights.s0 = (convert_half(((bits4.s0 & 0xF000) >> 12) | ((qh.s0 & 0x08) << 1)) - 16.0h) * scale.s0;
89
+ dequantized_weights.s1 = (convert_half(((bits4.s1 & 0xF000) >> 12) | ((qh.s1 & 0x08) << 1)) - 16.0h) * scale.s1;
90
+ dequantized_weights.s2 = (convert_half(((bits4.s2 & 0xF000) >> 12) | ((qh.s2 & 0x08) << 1)) - 16.0h) * scale.s2;
91
+ dequantized_weights.s3 = (convert_half(((bits4.s3 & 0xF000) >> 12) | ((qh.s3 & 0x08) << 1)) - 16.0h) * scale.s3;
92
+ c0 += B * dequantized_weights.s0;
93
+ c1 += B * dequantized_weights.s1;
94
+ c2 += B * dequantized_weights.s2;
95
+ c3 += B * dequantized_weights.s3;
96
+ }
97
+
98
+ int idx = (gy<<3)*m + (gx<<2);
99
+
100
+ if(idx+3 < m*n_no_padding){
101
+ vstore4((float4)(c0.s0, c1.s0, c2.s0, c3.s0), 0, dst + idx);
102
+ idx += m;
103
+ }
104
+ if(idx+3 < m*n_no_padding){
105
+ vstore4((float4)(c0.s1, c1.s1, c2.s1, c3.s1), 0, dst + idx);
106
+ idx += m;
107
+ }
108
+ if(idx+3 < m*n_no_padding){
109
+ vstore4((float4)(c0.s2, c1.s2, c2.s2, c3.s2), 0, dst + idx);
110
+ idx += m;
111
+ }
112
+ if(idx+3 < m*n_no_padding){
113
+ vstore4((float4)(c0.s3, c1.s3, c2.s3, c3.s3), 0, dst + idx);
114
+ idx += m;
115
+ }
116
+ if(idx+3 < m*n_no_padding){
117
+ vstore4((float4)(c0.s4, c1.s4, c2.s4, c3.s4), 0, dst + idx);
118
+ idx += m;
119
+ }
120
+ if(idx+3 < m*n_no_padding){
121
+ vstore4((float4)(c0.s5, c1.s5, c2.s5, c3.s5), 0, dst + idx);
122
+ idx += m;
123
+ }
124
+ if(idx+3 < m*n_no_padding){
125
+ vstore4((float4)(c0.s6, c1.s6, c2.s6, c3.s6), 0, dst + idx);
126
+ idx += m;
127
+ }
128
+ if(idx+3 < m*n_no_padding){
129
+ vstore4((float4)(c0.s7, c1.s7, c2.s7, c3.s7), 0, dst + idx);
130
+ }
131
+ }
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_noshuffle_q5_0_q8_1_dp4a.cl ADDED
@@ -0,0 +1,235 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #pragma OPENCL EXTENSION cl_khr_fp16 : enable
2
+ #pragma OPENCL EXTENSION cl_khr_subgroups : enable
3
+ #ifdef cl_khr_integer_dot_product
4
+ #pragma OPENCL EXTENSION cl_khr_integer_dot_product : enable
5
+ #endif
6
+
7
+ // Weight layout
8
+ // src0_qs[row + (k/4)*m] ushort = 4 low nibbles (K = 4*grp .. +3)
9
+ // src0_qh[row + (k/8)*m] uchar = 8 high bits (one per element)
10
+ // src0_d [row + (k/32)*m] half = per-32-block scale
11
+
12
+ #define TILESIZE_N 32
13
+
14
+ // 4 nibbles in low 16 bits of u -> 4 bytes (value 0..15)
15
+ #define EXP4(u) ( ((uint)((u) & 0x000Fu)) | \
16
+ (((uint)((u) & 0x00F0u)) << 4) | \
17
+ (((uint)((u) & 0x0F00u)) << 8) | \
18
+ (((uint)((u) & 0xF000u)) << 12) )
19
+ // 4 high bits (one per element, in bits 0..3 of h) -> bit4 of each of 4 bytes
20
+ #define EXP1(h) ( (((uint)((h) & 0x1u)) << 4) | \
21
+ (((uint)((h) & 0x2u)) << 11) | \
22
+ (((uint)((h) & 0x4u)) << 18) | \
23
+ (((uint)((h) & 0x8u)) << 25) )
24
+
25
+ inline int dot8_q8a(uint8 qw, __local const uint * a) {
26
+ int r = 0;
27
+ r = dot_acc_sat_4x8packed_ss_int(qw.s0, a[0], r);
28
+ r = dot_acc_sat_4x8packed_ss_int(qw.s1, a[1], r);
29
+ r = dot_acc_sat_4x8packed_ss_int(qw.s2, a[2], r);
30
+ r = dot_acc_sat_4x8packed_ss_int(qw.s3, a[3], r);
31
+ r = dot_acc_sat_4x8packed_ss_int(qw.s4, a[4], r);
32
+ r = dot_acc_sat_4x8packed_ss_int(qw.s5, a[5], r);
33
+ r = dot_acc_sat_4x8packed_ss_int(qw.s6, a[6], r);
34
+ r = dot_acc_sat_4x8packed_ss_int(qw.s7, a[7], r);
35
+ return r;
36
+ }
37
+
38
+ __attribute__((qcom_wave_pair_mode(1)))
39
+ kernel void kernel_gemm_noshuffle_q5_0_q8_1_dp4a(
40
+ __global const ushort * src0_qs, // q5_0 low nibbles (4/ushort, feature-major)
41
+ __global const uchar * src0_qh, // q5_0 high-bit plane (8/uchar, feature-major)
42
+ __global const half * src0_d, // per-32-block scale, feature-major
43
+ __global const uint * src1_qa, // q8_1 activations int8 (as uint, 4/elem) [N, K]
44
+ __global const half * src1_da, // q8_1 per-block scale [N, K/32]
45
+ __global const half * src1_sa, // q8_1 per-block sum*d [N, K/32]
46
+ __global float * dst,
47
+ ulong offsetd,
48
+ int m, // output features (rows)
49
+ int n_no_padding, // tokens (cols)
50
+ int k // K (== ne00)
51
+ ) {
52
+ dst = (global float *)((global char *)dst + offsetd);
53
+
54
+ const uint lid = get_local_id(0); // 0..63 -> row within the M-tile
55
+ const uint block_id_m = get_global_id(1);
56
+ const uint block_id_n = get_global_id(2);
57
+
58
+ const uint row = block_id_m * 64 + lid;
59
+ const uint col_base = block_id_n * TILESIZE_N;
60
+ const bool row_valid = row < (uint)m;
61
+ const uint rrow = row_valid ? row : 0; // clamp OOB rows; their writes are masked
62
+
63
+ const uint k_u = (uint)k >> 2; // K in uint (int8x4) units
64
+ const uint k_b = (uint)k >> 5; // blocks-of-32 along K
65
+
66
+ __local uint sh_qa[TILESIZE_N][8];
67
+ __local half sh_d[TILESIZE_N];
68
+ __local half sh_s[TILESIZE_N];
69
+
70
+ #define NGROUPS (TILESIZE_N / 4)
71
+ float4 acc[NGROUPS];
72
+ #pragma unroll
73
+ for (int g = 0; g < NGROUPS; ++g) acc[g] = (float4)(0.0f);
74
+
75
+ for (uint step = 0; step < (uint)k; step += 32) {
76
+ const uint sub = step >> 5;
77
+
78
+ const float d_w = (float)src0_d[rrow + sub * (uint)m];
79
+ const float minv = d_w * 16.0f; // -16 centering -> subtract via q8_1 sum
80
+
81
+ // 8 weight uints (32 elements) for this row, this 32-block.
82
+ // nibbles: src0_qs[row + (step/4 + u)*m]; high bits: src0_qh[row + (step/8 + u/2)*m],
83
+ // 4-bit group selected by (u&1)*4.
84
+ const uint qsbase = rrow + (step >> 2) * (uint)m;
85
+ const uint qhbase = rrow + (step >> 3) * (uint)m;
86
+ uint8 qw;
87
+ #define QW(u) (EXP4(src0_qs[qsbase + (u) * m]) | \
88
+ EXP1((uint)(src0_qh[qhbase + ((u) >> 1) * m] >> (((u) & 1u) * 4u)) & 0xFu))
89
+ qw.s0 = QW(0); qw.s1 = QW(1); qw.s2 = QW(2); qw.s3 = QW(3);
90
+ qw.s4 = QW(4); qw.s5 = QW(5); qw.s6 = QW(6); qw.s7 = QW(7);
91
+ #undef QW
92
+
93
+ // cooperatively stage the 32-token x 32-K int8 activations to lm
94
+ for (uint idx = lid; idx < TILESIZE_N * 8; idx += 64) {
95
+ const uint t = idx >> 3;
96
+ const uint u = idx & 7;
97
+ const uint c = col_base + t;
98
+ sh_qa[t][u] = (c < (uint)n_no_padding) ? src1_qa[c * k_u + (step >> 2) + u] : 0u;
99
+ }
100
+ if (lid < TILESIZE_N) {
101
+ const uint c = col_base + lid;
102
+ sh_d[lid] = (c < (uint)n_no_padding) ? src1_da[c * k_b + sub] : (half)0;
103
+ sh_s[lid] = (c < (uint)n_no_padding) ? src1_sa[c * k_b + sub] : (half)0;
104
+ }
105
+ barrier(CLK_LOCAL_MEM_FENCE);
106
+
107
+ #define LD4(arr, b) ((float4)((float)arr[(b)+0], (float)arr[(b)+1], (float)arr[(b)+2], (float)arr[(b)+3]))
108
+ #pragma unroll
109
+ for (int g = 0; g < NGROUPS; ++g) {
110
+ const int b = g * 4;
111
+ float4 rf;
112
+ rf.s0 = (float)dot8_q8a(qw, sh_qa[b+0]); rf.s1 = (float)dot8_q8a(qw, sh_qa[b+1]);
113
+ rf.s2 = (float)dot8_q8a(qw, sh_qa[b+2]); rf.s3 = (float)dot8_q8a(qw, sh_qa[b+3]);
114
+ acc[g] += d_w * LD4(sh_d, b) * rf - minv * LD4(sh_s, b);
115
+ }
116
+ #undef LD4
117
+ barrier(CLK_LOCAL_MEM_FENCE);
118
+ }
119
+
120
+ if (!row_valid) {
121
+ return;
122
+ }
123
+
124
+ #pragma unroll
125
+ for (int g = 0; g < NGROUPS; ++g) {
126
+ const uint b = (uint)(g * 4);
127
+ const float4 a = acc[g];
128
+ const uint c0 = col_base + b;
129
+ if (c0 + 0 < (uint)n_no_padding) dst[(c0 + 0) * (uint)m + row] = a.s0;
130
+ if (c0 + 1 < (uint)n_no_padding) dst[(c0 + 1) * (uint)m + row] = a.s1;
131
+ if (c0 + 2 < (uint)n_no_padding) dst[(c0 + 2) * (uint)m + row] = a.s2;
132
+ if (c0 + 3 < (uint)n_no_padding) dst[(c0 + 3) * (uint)m + row] = a.s3;
133
+ }
134
+ #undef NGROUPS
135
+ }
136
+
137
+ __attribute__((qcom_wave_pair_mode(1)))
138
+ kernel void kernel_gemm_noshuffle_q5_0_q8_1_dp4a_wimg(
139
+ __read_only image1d_buffer_t src0_qs_img, // q5_0 low nibbles as uint32 texels (2 ushorts/texel)
140
+ __global const uchar * src0_qh,
141
+ __global const half * src0_d,
142
+ __global const uint * src1_qa,
143
+ __global const half * src1_da,
144
+ __global const half * src1_sa,
145
+ __global float * dst,
146
+ ulong offsetd,
147
+ int m,
148
+ int n_no_padding,
149
+ int k
150
+ ) {
151
+ dst = (global float *)((global char *)dst + offsetd);
152
+
153
+ const uint lid = get_local_id(0);
154
+ const uint block_id_m = get_global_id(1);
155
+ const uint block_id_n = get_global_id(2);
156
+
157
+ const uint row = block_id_m * 64 + lid;
158
+ const uint col_base = block_id_n * TILESIZE_N;
159
+ const bool row_valid = row < (uint)m;
160
+ const uint rrow = row_valid ? row : 0;
161
+
162
+ const uint sel = (rrow & 1u) * 16u; // constant per WI: qs ushort half in its uint32 texel
163
+
164
+ const uint k_u = (uint)k >> 2;
165
+ const uint k_b = (uint)k >> 5;
166
+
167
+ __local uint sh_qa[TILESIZE_N][8];
168
+ __local half sh_d[TILESIZE_N];
169
+ __local half sh_s[TILESIZE_N];
170
+
171
+ #define NGROUPS (TILESIZE_N / 4)
172
+ float4 acc[NGROUPS];
173
+ #pragma unroll
174
+ for (int g = 0; g < NGROUPS; ++g) acc[g] = (float4)(0.0f);
175
+
176
+ for (uint step = 0; step < (uint)k; step += 32) {
177
+ const uint sub = step >> 5;
178
+
179
+ const float d_w = (float)src0_d[rrow + sub * (uint)m];
180
+ const float minv = d_w * 16.0f;
181
+
182
+ const uint qsbase = rrow + (step >> 2) * (uint)m; // ushort index
183
+ const uint qhbase = rrow + (step >> 3) * (uint)m;
184
+ uint8 qw;
185
+ // qs ushort via texture: uint32 texel = ushort_index>>1, half = sel.
186
+ #define QSU(u) ((read_imageui(src0_qs_img, (int)((qsbase + (u) * m) >> 1)).x >> sel) & 0xFFFFu)
187
+ #define QW(u) (EXP4(QSU(u)) | \
188
+ EXP1((uint)(src0_qh[qhbase + ((u) >> 1) * m] >> (((u) & 1u) * 4u)) & 0xFu))
189
+ qw.s0 = QW(0); qw.s1 = QW(1); qw.s2 = QW(2); qw.s3 = QW(3);
190
+ qw.s4 = QW(4); qw.s5 = QW(5); qw.s6 = QW(6); qw.s7 = QW(7);
191
+ #undef QW
192
+ #undef QSU
193
+
194
+ for (uint idx = lid; idx < TILESIZE_N * 8; idx += 64) {
195
+ const uint t = idx >> 3;
196
+ const uint u = idx & 7;
197
+ const uint c = col_base + t;
198
+ sh_qa[t][u] = (c < (uint)n_no_padding) ? src1_qa[c * k_u + (step >> 2) + u] : 0u;
199
+ }
200
+ if (lid < TILESIZE_N) {
201
+ const uint c = col_base + lid;
202
+ sh_d[lid] = (c < (uint)n_no_padding) ? src1_da[c * k_b + sub] : (half)0;
203
+ sh_s[lid] = (c < (uint)n_no_padding) ? src1_sa[c * k_b + sub] : (half)0;
204
+ }
205
+ barrier(CLK_LOCAL_MEM_FENCE);
206
+
207
+ #define LD4(arr, b) ((float4)((float)arr[(b)+0], (float)arr[(b)+1], (float)arr[(b)+2], (float)arr[(b)+3]))
208
+ #pragma unroll
209
+ for (int g = 0; g < NGROUPS; ++g) {
210
+ const int b = g * 4;
211
+ float4 rf;
212
+ rf.s0 = (float)dot8_q8a(qw, sh_qa[b+0]); rf.s1 = (float)dot8_q8a(qw, sh_qa[b+1]);
213
+ rf.s2 = (float)dot8_q8a(qw, sh_qa[b+2]); rf.s3 = (float)dot8_q8a(qw, sh_qa[b+3]);
214
+ acc[g] += d_w * LD4(sh_d, b) * rf - minv * LD4(sh_s, b);
215
+ }
216
+ #undef LD4
217
+ barrier(CLK_LOCAL_MEM_FENCE);
218
+ }
219
+
220
+ if (!row_valid) {
221
+ return;
222
+ }
223
+
224
+ #pragma unroll
225
+ for (int g = 0; g < NGROUPS; ++g) {
226
+ const uint b = (uint)(g * 4);
227
+ const float4 a = acc[g];
228
+ const uint c0 = col_base + b;
229
+ if (c0 + 0 < (uint)n_no_padding) dst[(c0 + 0) * (uint)m + row] = a.s0;
230
+ if (c0 + 1 < (uint)n_no_padding) dst[(c0 + 1) * (uint)m + row] = a.s1;
231
+ if (c0 + 2 < (uint)n_no_padding) dst[(c0 + 2) * (uint)m + row] = a.s2;
232
+ if (c0 + 3 < (uint)n_no_padding) dst[(c0 + 3) * (uint)m + row] = a.s3;
233
+ }
234
+ #undef NGROUPS
235
+ }
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_noshuffle_q5_1_f32.cl ADDED
@@ -0,0 +1,134 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #pragma OPENCL EXTENSION cl_khr_fp16 : enable
2
+ #pragma OPENCL EXTENSION cl_qcom_reqd_sub_group_size : enable
3
+
4
+ #ifdef cl_qcom_reqd_sub_group_size
5
+ #pragma OPENCL EXTENSION cl_qcom_reqd_sub_group_size : enable
6
+ #define ADRENO_GPU 1
7
+ #define REQD_SUBGROUP_SIZE_128 __attribute__((qcom_reqd_sub_group_size("full")))
8
+ #endif
9
+
10
+ #ifdef ADRENO_GPU
11
+ REQD_SUBGROUP_SIZE_128
12
+ #endif
13
+
14
+ kernel void kernel_gemm_noshuffle_q5_1_f32(
15
+ global const ushort * src0_qs, // quantized A
16
+ global const uchar * src0_qh, // 5th bits
17
+ global const half * src0_d, // A scales
18
+ global const half * src0_m, // A mins
19
+ __read_only image1d_buffer_t src1, // B (1d image)
20
+ global float * dst, // C
21
+ int m, // M
22
+ int n, // N with padding
23
+ int k, // K
24
+ int n_no_padding // N without padding
25
+ ) {
26
+
27
+ int n_4 = n >> 2;
28
+
29
+ int gy = get_global_id(0);
30
+ int gx = get_global_id(1);
31
+ int gx_2 = gx << 2;
32
+
33
+ half8 c0 = 0, c1 = 0, c2 = 0, c3 = 0;
34
+ half8 B;
35
+ half4 dequantized_weights;
36
+
37
+ global const ushort * weight_ptr = src0_qs + gx_2;
38
+ global const uchar * qh_ptr = src0_qh + gx_2;
39
+ global const half * scale_ptr = src0_d + gx_2;
40
+ global const half * min_ptr = src0_m + gx_2;
41
+
42
+ for (int i = 0; i < k; i += 4) {
43
+
44
+ B.s0123 = read_imageh(src1, gy*2 + i*n_4);
45
+ B.s4567 = read_imageh(src1, gy*2 + i*n_4 + 1);
46
+
47
+ ushort4 bits4 = vload4(0, weight_ptr + (i >> 2)*m);
48
+ uchar4 bits1 = vload4(0, qh_ptr + (i >> 3)*m);
49
+ uchar4 qh = bits1 >> (uchar4)(i & 4);
50
+
51
+ half4 scale = vload4(0, scale_ptr + (i >> 5)*m);
52
+ half4 minv = vload4(0, min_ptr + (i >> 5)*m);
53
+
54
+ // j=0
55
+ dequantized_weights.s0 = convert_half((bits4.s0 & 0x000F) | ((qh.s0 & 0x01) << 4)) * scale.s0 + minv.s0;
56
+ dequantized_weights.s1 = convert_half((bits4.s1 & 0x000F) | ((qh.s1 & 0x01) << 4)) * scale.s1 + minv.s1;
57
+ dequantized_weights.s2 = convert_half((bits4.s2 & 0x000F) | ((qh.s2 & 0x01) << 4)) * scale.s2 + minv.s2;
58
+ dequantized_weights.s3 = convert_half((bits4.s3 & 0x000F) | ((qh.s3 & 0x01) << 4)) * scale.s3 + minv.s3;
59
+ c0 += B * dequantized_weights.s0;
60
+ c1 += B * dequantized_weights.s1;
61
+ c2 += B * dequantized_weights.s2;
62
+ c3 += B * dequantized_weights.s3;
63
+
64
+ // j=1
65
+ B.s0123 = read_imageh(src1, gy*2 + (i+1)*n_4);
66
+ B.s4567 = read_imageh(src1, gy*2 + (i+1)*n_4 + 1);
67
+ dequantized_weights.s0 = convert_half(((bits4.s0 & 0x00F0) >> 4) | ((qh.s0 & 0x02) << 3)) * scale.s0 + minv.s0;
68
+ dequantized_weights.s1 = convert_half(((bits4.s1 & 0x00F0) >> 4) | ((qh.s1 & 0x02) << 3)) * scale.s1 + minv.s1;
69
+ dequantized_weights.s2 = convert_half(((bits4.s2 & 0x00F0) >> 4) | ((qh.s2 & 0x02) << 3)) * scale.s2 + minv.s2;
70
+ dequantized_weights.s3 = convert_half(((bits4.s3 & 0x00F0) >> 4) | ((qh.s3 & 0x02) << 3)) * scale.s3 + minv.s3;
71
+ c0 += B * dequantized_weights.s0;
72
+ c1 += B * dequantized_weights.s1;
73
+ c2 += B * dequantized_weights.s2;
74
+ c3 += B * dequantized_weights.s3;
75
+
76
+ // j=2
77
+ B.s0123 = read_imageh(src1, gy*2 + (i+2)*n_4);
78
+ B.s4567 = read_imageh(src1, gy*2 + (i+2)*n_4 + 1);
79
+ dequantized_weights.s0 = convert_half(((bits4.s0 & 0x0F00) >> 8) | ((qh.s0 & 0x04) << 2)) * scale.s0 + minv.s0;
80
+ dequantized_weights.s1 = convert_half(((bits4.s1 & 0x0F00) >> 8) | ((qh.s1 & 0x04) << 2)) * scale.s1 + minv.s1;
81
+ dequantized_weights.s2 = convert_half(((bits4.s2 & 0x0F00) >> 8) | ((qh.s2 & 0x04) << 2)) * scale.s2 + minv.s2;
82
+ dequantized_weights.s3 = convert_half(((bits4.s3 & 0x0F00) >> 8) | ((qh.s3 & 0x04) << 2)) * scale.s3 + minv.s3;
83
+ c0 += B * dequantized_weights.s0;
84
+ c1 += B * dequantized_weights.s1;
85
+ c2 += B * dequantized_weights.s2;
86
+ c3 += B * dequantized_weights.s3;
87
+
88
+ // j=3
89
+ B.s0123 = read_imageh(src1, gy*2 + (i+3)*n_4);
90
+ B.s4567 = read_imageh(src1, gy*2 + (i+3)*n_4 + 1);
91
+ dequantized_weights.s0 = convert_half(((bits4.s0 & 0xF000) >> 12) | ((qh.s0 & 0x08) << 1)) * scale.s0 + minv.s0;
92
+ dequantized_weights.s1 = convert_half(((bits4.s1 & 0xF000) >> 12) | ((qh.s1 & 0x08) << 1)) * scale.s1 + minv.s1;
93
+ dequantized_weights.s2 = convert_half(((bits4.s2 & 0xF000) >> 12) | ((qh.s2 & 0x08) << 1)) * scale.s2 + minv.s2;
94
+ dequantized_weights.s3 = convert_half(((bits4.s3 & 0xF000) >> 12) | ((qh.s3 & 0x08) << 1)) * scale.s3 + minv.s3;
95
+ c0 += B * dequantized_weights.s0;
96
+ c1 += B * dequantized_weights.s1;
97
+ c2 += B * dequantized_weights.s2;
98
+ c3 += B * dequantized_weights.s3;
99
+ }
100
+
101
+ int idx = (gy<<3)*m + (gx<<2);
102
+
103
+ if(idx+3 < m*n_no_padding){
104
+ vstore4((float4)(c0.s0, c1.s0, c2.s0, c3.s0), 0, dst + idx);
105
+ idx += m;
106
+ }
107
+ if(idx+3 < m*n_no_padding){
108
+ vstore4((float4)(c0.s1, c1.s1, c2.s1, c3.s1), 0, dst + idx);
109
+ idx += m;
110
+ }
111
+ if(idx+3 < m*n_no_padding){
112
+ vstore4((float4)(c0.s2, c1.s2, c2.s2, c3.s2), 0, dst + idx);
113
+ idx += m;
114
+ }
115
+ if(idx+3 < m*n_no_padding){
116
+ vstore4((float4)(c0.s3, c1.s3, c2.s3, c3.s3), 0, dst + idx);
117
+ idx += m;
118
+ }
119
+ if(idx+3 < m*n_no_padding){
120
+ vstore4((float4)(c0.s4, c1.s4, c2.s4, c3.s4), 0, dst + idx);
121
+ idx += m;
122
+ }
123
+ if(idx+3 < m*n_no_padding){
124
+ vstore4((float4)(c0.s5, c1.s5, c2.s5, c3.s5), 0, dst + idx);
125
+ idx += m;
126
+ }
127
+ if(idx+3 < m*n_no_padding){
128
+ vstore4((float4)(c0.s6, c1.s6, c2.s6, c3.s6), 0, dst + idx);
129
+ idx += m;
130
+ }
131
+ if(idx+3 < m*n_no_padding){
132
+ vstore4((float4)(c0.s7, c1.s7, c2.s7, c3.s7), 0, dst + idx);
133
+ }
134
+ }
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_noshuffle_q5_k_f32.cl ADDED
@@ -0,0 +1,176 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #pragma OPENCL EXTENSION cl_khr_fp16 : enable
2
+
3
+ #ifdef cl_qcom_reqd_sub_group_size
4
+ #pragma OPENCL EXTENSION cl_qcom_reqd_sub_group_size : enable
5
+ #define ADRENO_GPU 1
6
+ #define REQD_SUBGROUP_SIZE_128 __attribute__((qcom_reqd_sub_group_size("full")))
7
+ #endif
8
+ #define QK_K 256
9
+ #define K_SCALE_SIZE 12
10
+
11
+ inline void get_scale_min_k4(
12
+ int j,
13
+ global const uchar * q,
14
+ uchar * d,
15
+ uchar * m,
16
+ uchar mask_d6,
17
+ uchar mask_d4,
18
+ uchar mask_hi2
19
+ ) {
20
+ if (j < 4) {
21
+ *d = q[j] & mask_d6;
22
+ *m = q[j+4] & mask_d6;
23
+ } else {
24
+ *d = (q[j+4] & mask_d4) | ((q[j-4] & mask_hi2) >> 2);
25
+ *m = ((q[j+4] >> 4) & mask_d4) | ((q[j] & mask_hi2) >> 2);
26
+ }
27
+ }
28
+
29
+ #ifdef ADRENO_GPU
30
+ REQD_SUBGROUP_SIZE_128
31
+ #endif
32
+ kernel void kernel_gemm_noshuffle_q5_k_f32(
33
+ global const ushort * src0_q,
34
+ global const uchar * src0_qh,
35
+ global const uchar * src0_s,
36
+ global const half * src0_d,
37
+ global const half * src0_dm,
38
+ read_only image1d_buffer_t src1,
39
+ global float * dst,
40
+ ulong offsetd,
41
+ int m,
42
+ int n,
43
+ int k,
44
+ int n_no_padding,
45
+ uchar mask_d6,
46
+ uchar mask_d4,
47
+ uchar mask_hi2
48
+ ) {
49
+ dst = (global float *)((global char *)dst + offsetd);
50
+ int n_4 = n >> 2;
51
+ int gy = get_global_id(0);
52
+ int gx = get_global_id(1);
53
+ int gx_2 = gx << 2;
54
+
55
+ half8 c0 = 0, c1 = 0, c2 = 0, c3 = 0;
56
+ half8 B;
57
+ half4 dequantized_weights;
58
+
59
+ int num_blocks_K = k / QK_K;
60
+
61
+ global const ushort * weight_ptr = src0_q + gx_2;
62
+ global const uchar * qh_ptr = src0_qh + gx_2;
63
+ global const half * d_ptr = src0_d + gx_2;
64
+ global const half * dm_ptr = src0_dm + gx_2;
65
+
66
+ for (int i = 0; i < k; i += 32) {
67
+ int sb_idx = i / QK_K;
68
+ int sub_idx = (i / 32) % 8;
69
+
70
+ half4 d = vload4(0, d_ptr + sb_idx * m);
71
+ half4 dm = vload4(0, dm_ptr + sb_idx * m);
72
+
73
+ global const uchar * sc0 = src0_s + (gx_2+0) * num_blocks_K * K_SCALE_SIZE + sb_idx * K_SCALE_SIZE;
74
+ global const uchar * sc1 = src0_s + (gx_2+1) * num_blocks_K * K_SCALE_SIZE + sb_idx * K_SCALE_SIZE;
75
+ global const uchar * sc2 = src0_s + (gx_2+2) * num_blocks_K * K_SCALE_SIZE + sb_idx * K_SCALE_SIZE;
76
+ global const uchar * sc3 = src0_s + (gx_2+3) * num_blocks_K * K_SCALE_SIZE + sb_idx * K_SCALE_SIZE;
77
+
78
+ uchar sv0, mn0, sv1, mn1, sv2, mn2, sv3, mn3;
79
+ get_scale_min_k4(sub_idx, sc0, &sv0, &mn0, mask_d6, mask_d4, mask_hi2);
80
+ get_scale_min_k4(sub_idx, sc1, &sv1, &mn1, mask_d6, mask_d4, mask_hi2);
81
+ get_scale_min_k4(sub_idx, sc2, &sv2, &mn2, mask_d6, mask_d4, mask_hi2);
82
+ get_scale_min_k4(sub_idx, sc3, &sv3, &mn3, mask_d6, mask_d4, mask_hi2);
83
+
84
+ half4 scale = convert_half4(convert_float4(d) * convert_float4((uchar4)(sv0, sv1, sv2, sv3)));
85
+ half4 mval = convert_half4(convert_float4(dm) * convert_float4((uchar4)(mn0, mn1, mn2, mn3)));
86
+
87
+ for (int l = 0; l < 32; l += 4) {
88
+ int ki = i + l;
89
+ ushort4 bits4 = vload4(0, weight_ptr + (ki/4) * m);
90
+ uchar4 qh_bits = vload4(0, qh_ptr + (ki/8) * m);
91
+ int qh_shift = ki % 8;
92
+
93
+ // j=0
94
+ B.s0123 = read_imageh(src1, gy*2 + (ki+0) * n_4);
95
+ B.s4567 = read_imageh(src1, gy*2+1 + (ki+0) * n_4);
96
+ dequantized_weights.s0 = ((bits4.s0 & 0x000F) | (((qh_bits.s0 >> (qh_shift+0)) & 1) << 4)) * scale.s0 - mval.s0;
97
+ dequantized_weights.s1 = ((bits4.s1 & 0x000F) | (((qh_bits.s1 >> (qh_shift+0)) & 1) << 4)) * scale.s1 - mval.s1;
98
+ dequantized_weights.s2 = ((bits4.s2 & 0x000F) | (((qh_bits.s2 >> (qh_shift+0)) & 1) << 4)) * scale.s2 - mval.s2;
99
+ dequantized_weights.s3 = ((bits4.s3 & 0x000F) | (((qh_bits.s3 >> (qh_shift+0)) & 1) << 4)) * scale.s3 - mval.s3;
100
+ c0 += B * dequantized_weights.s0;
101
+ c1 += B * dequantized_weights.s1;
102
+ c2 += B * dequantized_weights.s2;
103
+ c3 += B * dequantized_weights.s3;
104
+
105
+ // j=1
106
+ B.s0123 = read_imageh(src1, gy*2 + (ki+1) * n_4);
107
+ B.s4567 = read_imageh(src1, gy*2+1 + (ki+1) * n_4);
108
+ dequantized_weights.s0 = (((bits4.s0 & 0x00F0) >> 4) | (((qh_bits.s0 >> (qh_shift+1)) & 1) << 4)) * scale.s0 - mval.s0;
109
+ dequantized_weights.s1 = (((bits4.s1 & 0x00F0) >> 4) | (((qh_bits.s1 >> (qh_shift+1)) & 1) << 4)) * scale.s1 - mval.s1;
110
+ dequantized_weights.s2 = (((bits4.s2 & 0x00F0) >> 4) | (((qh_bits.s2 >> (qh_shift+1)) & 1) << 4)) * scale.s2 - mval.s2;
111
+ dequantized_weights.s3 = (((bits4.s3 & 0x00F0) >> 4) | (((qh_bits.s3 >> (qh_shift+1)) & 1) << 4)) * scale.s3 - mval.s3;
112
+ c0 += B * dequantized_weights.s0;
113
+ c1 += B * dequantized_weights.s1;
114
+ c2 += B * dequantized_weights.s2;
115
+ c3 += B * dequantized_weights.s3;
116
+
117
+ // j=2
118
+ B.s0123 = read_imageh(src1, gy*2 + (ki+2) * n_4);
119
+ B.s4567 = read_imageh(src1, gy*2+1 + (ki+2) * n_4);
120
+ dequantized_weights.s0 = (((bits4.s0 & 0x0F00) >> 8) | (((qh_bits.s0 >> (qh_shift+2)) & 1) << 4)) * scale.s0 - mval.s0;
121
+ dequantized_weights.s1 = (((bits4.s1 & 0x0F00) >> 8) | (((qh_bits.s1 >> (qh_shift+2)) & 1) << 4)) * scale.s1 - mval.s1;
122
+ dequantized_weights.s2 = (((bits4.s2 & 0x0F00) >> 8) | (((qh_bits.s2 >> (qh_shift+2)) & 1) << 4)) * scale.s2 - mval.s2;
123
+ dequantized_weights.s3 = (((bits4.s3 & 0x0F00) >> 8) | (((qh_bits.s3 >> (qh_shift+2)) & 1) << 4)) * scale.s3 - mval.s3;
124
+ c0 += B * dequantized_weights.s0;
125
+ c1 += B * dequantized_weights.s1;
126
+ c2 += B * dequantized_weights.s2;
127
+ c3 += B * dequantized_weights.s3;
128
+
129
+ // j=3
130
+ B.s0123 = read_imageh(src1, gy*2 + (ki+3) * n_4);
131
+ B.s4567 = read_imageh(src1, gy*2+1 + (ki+3) * n_4);
132
+ dequantized_weights.s0 = (((bits4.s0 & 0xF000) >> 12) | (((qh_bits.s0 >> (qh_shift+3)) & 1) << 4)) * scale.s0 - mval.s0;
133
+ dequantized_weights.s1 = (((bits4.s1 & 0xF000) >> 12) | (((qh_bits.s1 >> (qh_shift+3)) & 1) << 4)) * scale.s1 - mval.s1;
134
+ dequantized_weights.s2 = (((bits4.s2 & 0xF000) >> 12) | (((qh_bits.s2 >> (qh_shift+3)) & 1) << 4)) * scale.s2 - mval.s2;
135
+ dequantized_weights.s3 = (((bits4.s3 & 0xF000) >> 12) | (((qh_bits.s3 >> (qh_shift+3)) & 1) << 4)) * scale.s3 - mval.s3;
136
+ c0 += B * dequantized_weights.s0;
137
+ c1 += B * dequantized_weights.s1;
138
+ c2 += B * dequantized_weights.s2;
139
+ c3 += B * dequantized_weights.s3;
140
+ }
141
+ }
142
+
143
+ int idx = (gy<<3)*m + (gx<<2);
144
+
145
+ if (idx+3 < m*n_no_padding) {
146
+ vstore4((float4)(c0.s0, c1.s0, c2.s0, c3.s0), 0, dst + idx);
147
+ idx += m;
148
+ }
149
+ if (idx+3 < m*n_no_padding) {
150
+ vstore4((float4)(c0.s1, c1.s1, c2.s1, c3.s1), 0, dst + idx);
151
+ idx += m;
152
+ }
153
+ if (idx+3 < m*n_no_padding) {
154
+ vstore4((float4)(c0.s2, c1.s2, c2.s2, c3.s2), 0, dst + idx);
155
+ idx += m;
156
+ }
157
+ if (idx+3 < m*n_no_padding) {
158
+ vstore4((float4)(c0.s3, c1.s3, c2.s3, c3.s3), 0, dst + idx);
159
+ idx += m;
160
+ }
161
+ if (idx+3 < m*n_no_padding) {
162
+ vstore4((float4)(c0.s4, c1.s4, c2.s4, c3.s4), 0, dst + idx);
163
+ idx += m;
164
+ }
165
+ if (idx+3 < m*n_no_padding) {
166
+ vstore4((float4)(c0.s5, c1.s5, c2.s5, c3.s5), 0, dst + idx);
167
+ idx += m;
168
+ }
169
+ if (idx+3 < m*n_no_padding) {
170
+ vstore4((float4)(c0.s6, c1.s6, c2.s6, c3.s6), 0, dst + idx);
171
+ idx += m;
172
+ }
173
+ if (idx+3 < m*n_no_padding) {
174
+ vstore4((float4)(c0.s7, c1.s7, c2.s7, c3.s7), 0, dst + idx);
175
+ }
176
+ }
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_noshuffle_q5_k_q8_1_dp4a.cl ADDED
@@ -0,0 +1,164 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #pragma OPENCL EXTENSION cl_khr_fp16 : enable
2
+ #pragma OPENCL EXTENSION cl_khr_subgroups : enable
3
+ #ifdef cl_khr_integer_dot_product
4
+ #pragma OPENCL EXTENSION cl_khr_integer_dot_product : enable
5
+ #endif
6
+
7
+ #define TILESIZE_N 32
8
+ #define QK_K 256
9
+ #define K_SCALE_SIZE 12
10
+
11
+ inline void get_scale_min_k4(
12
+ int j,
13
+ global const uchar * q,
14
+ uchar * d,
15
+ uchar * m,
16
+ uchar mask_d6,
17
+ uchar mask_d4,
18
+ uchar mask_hi2
19
+ ) {
20
+ if (j < 4) {
21
+ *d = q[j] & mask_d6;
22
+ *m = q[j+4] & mask_d6;
23
+ } else {
24
+ *d = (q[j+4] & mask_d4) | ((q[j-4] & mask_hi2) >> 2);
25
+ *m = ((q[j+4] >> 4) & mask_d4) | ((q[j] & mask_hi2) >> 2);
26
+ }
27
+ }
28
+
29
+ // 4 nibbles in the low 16 bits of `u` -> 4 bytes (value 0..15, bits 0-3).
30
+ #define EXP4(u) ( ((uint)((u) & 0x000Fu)) | \
31
+ (((uint)((u) & 0x00F0u)) << 4) | \
32
+ (((uint)((u) & 0x0F00u)) << 8) | \
33
+ (((uint)((u) & 0xF000u)) << 12) )
34
+
35
+ // 4 high bits (one per element, in bits 0-3 of h) -> bit 4 of each of 4 bytes,
36
+ // so OR with EXP4 forms the 5-bit q5_K code 0..31.
37
+ #define EXP1(h) ( (((uint)((h) & 0x1u)) << 4) | \
38
+ (((uint)((h) & 0x2u)) << 11) | \
39
+ (((uint)((h) & 0x4u)) << 18) | \
40
+ (((uint)((h) & 0x8u)) << 25) )
41
+
42
+ inline int dot8_q8a(uint8 qw, __local const uint * a) {
43
+ int r = 0;
44
+ r = dot_acc_sat_4x8packed_ss_int(qw.s0, a[0], r);
45
+ r = dot_acc_sat_4x8packed_ss_int(qw.s1, a[1], r);
46
+ r = dot_acc_sat_4x8packed_ss_int(qw.s2, a[2], r);
47
+ r = dot_acc_sat_4x8packed_ss_int(qw.s3, a[3], r);
48
+ r = dot_acc_sat_4x8packed_ss_int(qw.s4, a[4], r);
49
+ r = dot_acc_sat_4x8packed_ss_int(qw.s5, a[5], r);
50
+ r = dot_acc_sat_4x8packed_ss_int(qw.s6, a[6], r);
51
+ r = dot_acc_sat_4x8packed_ss_int(qw.s7, a[7], r);
52
+ return r;
53
+ }
54
+
55
+ __attribute__((qcom_wave_pair_mode(1)))
56
+ kernel void kernel_gemm_noshuffle_q5_k_q8_1_dp4a(
57
+ __global const ushort * src0_q, // q5_K low nibbles (transposed, ushort = 4 nibbles)
58
+ __global const uchar * src0_qh, // q5_K high bits (transposed, uchar = 8 elems/byte)
59
+ __global const uchar * src0_s, // 6-bit scale/min codes [row][superblock][12]
60
+ __global const half * src0_d, // per-superblock scale (transposed)
61
+ __global const half * src0_dm, // per-superblock min (transposed)
62
+ __global const uint * src1_qa, // q8_1 activations int8 (as uint, 4/elem) [N, K]
63
+ __global const half * src1_da, // q8_1 per-block scale [N, K/32]
64
+ __global const half * src1_sa, // q8_1 per-block sum*d [N, K/32]
65
+ __global float * dst,
66
+ ulong offsetd,
67
+ int m, // output features (rows)
68
+ int n_no_padding, // tokens (cols)
69
+ int k, // K (== ne00)
70
+ uchar mask_d6,
71
+ uchar mask_d4,
72
+ uchar mask_hi2
73
+ ) {
74
+ dst = (global float *)((global char *)dst + offsetd);
75
+
76
+ const uint lid = get_local_id(0); // 0..63 -> row within the M-tile
77
+ const uint block_id_m = get_global_id(1);
78
+ const uint block_id_n = get_global_id(2);
79
+
80
+ const uint row = block_id_m * 64 + lid;
81
+ const uint col_base = block_id_n * TILESIZE_N;
82
+ const bool row_valid = row < (uint)m;
83
+ const uint rrow = row_valid ? row : 0;
84
+
85
+ const uint num_superblocks = (uint)k / QK_K;
86
+ const uint k_u = (uint)k >> 2;
87
+ const uint k_b = (uint)k >> 5;
88
+
89
+ __local uint sh_qa[TILESIZE_N][8];
90
+ __local half sh_d[TILESIZE_N];
91
+ __local half sh_s[TILESIZE_N];
92
+
93
+ #define NGROUPS (TILESIZE_N / 4)
94
+ float4 acc[NGROUPS];
95
+ #pragma unroll
96
+ for (int g = 0; g < NGROUPS; ++g) acc[g] = (float4)(0.0f);
97
+
98
+ for (uint step = 0; step < (uint)k; step += 32) {
99
+ const uint sub = step >> 5;
100
+ const uint sb_idx = step / QK_K;
101
+ const uint sub_idx = sub & 7;
102
+
103
+ const float dd = (float)src0_d [rrow + sb_idx * m];
104
+ const float dmm = (float)src0_dm[rrow + sb_idx * m];
105
+ global const uchar * sc = src0_s + rrow * num_superblocks * K_SCALE_SIZE + sb_idx * K_SCALE_SIZE;
106
+ uchar sv, mn;
107
+ get_scale_min_k4(sub_idx, sc, &sv, &mn, mask_d6, mask_d4, mask_hi2);
108
+ const float scale = dd * (float)sv;
109
+ const float minv = dmm * (float)mn;
110
+
111
+ // repack this row's 32 weights (nibble | high-bit) into 8 dp4a uints.
112
+ // ushort u -> 4 elements at K = step + u*4; its 4 high bits are nibble
113
+ // (u&1) of qh byte (step/8 + u/2).
114
+ const uint wbase = rrow + (step >> 2) * (uint)m;
115
+ const uint qhbase = rrow + (step >> 3) * (uint)m;
116
+ uint8 qw;
117
+ #define QWU(u) ( EXP4((uint)src0_q[wbase + (uint)(u) * m]) \
118
+ | EXP1( (uint)((src0_qh[qhbase + (uint)((u) >> 1) * m] >> (((u) & 1) * 4)) & 0x0Fu) ) )
119
+ qw.s0 = QWU(0); qw.s1 = QWU(1); qw.s2 = QWU(2); qw.s3 = QWU(3);
120
+ qw.s4 = QWU(4); qw.s5 = QWU(5); qw.s6 = QWU(6); qw.s7 = QWU(7);
121
+ #undef QWU
122
+
123
+ for (uint idx = lid; idx < TILESIZE_N * 8; idx += 64) {
124
+ const uint t = idx >> 3;
125
+ const uint u = idx & 7;
126
+ const uint c = col_base + t;
127
+ sh_qa[t][u] = (c < (uint)n_no_padding) ? src1_qa[c * k_u + (step >> 2) + u] : 0u;
128
+ }
129
+ if (lid < TILESIZE_N) {
130
+ const uint c = col_base + lid;
131
+ sh_d[lid] = (c < (uint)n_no_padding) ? src1_da[c * k_b + sub] : (half)0;
132
+ sh_s[lid] = (c < (uint)n_no_padding) ? src1_sa[c * k_b + sub] : (half)0;
133
+ }
134
+ barrier(CLK_LOCAL_MEM_FENCE);
135
+
136
+ #define LD4(arr, b) ((float4)((float)arr[(b)+0], (float)arr[(b)+1], (float)arr[(b)+2], (float)arr[(b)+3]))
137
+ #pragma unroll
138
+ for (int g = 0; g < NGROUPS; ++g) {
139
+ const int b = g * 4;
140
+ float4 rf;
141
+ rf.s0 = (float)dot8_q8a(qw, sh_qa[b+0]); rf.s1 = (float)dot8_q8a(qw, sh_qa[b+1]);
142
+ rf.s2 = (float)dot8_q8a(qw, sh_qa[b+2]); rf.s3 = (float)dot8_q8a(qw, sh_qa[b+3]);
143
+ acc[g] += scale * LD4(sh_d, b) * rf - minv * LD4(sh_s, b);
144
+ }
145
+ #undef LD4
146
+ barrier(CLK_LOCAL_MEM_FENCE);
147
+ }
148
+
149
+ if (!row_valid) {
150
+ return;
151
+ }
152
+
153
+ #pragma unroll
154
+ for (int g = 0; g < NGROUPS; ++g) {
155
+ const uint b = (uint)(g * 4);
156
+ const float4 a = acc[g];
157
+ const uint c0 = col_base + b;
158
+ if (c0 + 0 < (uint)n_no_padding) dst[(c0 + 0) * (uint)m + row] = a.s0;
159
+ if (c0 + 1 < (uint)n_no_padding) dst[(c0 + 1) * (uint)m + row] = a.s1;
160
+ if (c0 + 2 < (uint)n_no_padding) dst[(c0 + 2) * (uint)m + row] = a.s2;
161
+ if (c0 + 3 < (uint)n_no_padding) dst[(c0 + 3) * (uint)m + row] = a.s3;
162
+ }
163
+ #undef NGROUPS
164
+ }
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_noshuffle_q6_k_f32.cl ADDED
@@ -0,0 +1,140 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #pragma OPENCL EXTENSION cl_khr_fp16 : enable
2
+ #pragma OPENCL EXTENSION cl_qcom_reqd_sub_group_size : enable
3
+
4
+ #ifdef cl_qcom_reqd_sub_group_size
5
+ #pragma OPENCL EXTENSION cl_qcom_reqd_sub_group_size : enable
6
+ #define ADRENO_GPU 1
7
+ #define REQD_SUBGROUP_SIZE_128 __attribute__((qcom_reqd_sub_group_size("full")))
8
+ #endif
9
+
10
+ #ifdef ADRENO_GPU
11
+ REQD_SUBGROUP_SIZE_128
12
+ #endif
13
+ kernel void kernel_gemm_noshuffle_q6_K_f32(
14
+ global const ushort * src0_ql,
15
+ global const uchar * src0_qh,
16
+ global const ushort * src0_s,
17
+ global const half * src0_d,
18
+ read_only image1d_buffer_t src1,
19
+ global float * dst,
20
+ ulong offsetd,
21
+ int m,
22
+ int n,
23
+ int k,
24
+ int n_no_padding,
25
+ ushort mask_f000,
26
+ uchar mask_c0
27
+ ) {
28
+ dst = (global float *)( (global char *)dst + offsetd );
29
+
30
+ int m_4 = m >> 2;
31
+ int n_4 = n >> 2;
32
+
33
+ int gy = get_global_id(0); // n
34
+ int gx = get_global_id(1); // m
35
+ int gx_2 = gx << 2;
36
+
37
+ half8 c0 = 0, c1 = 0, c2 = 0, c3 = 0;
38
+ half8 B;
39
+ half4 dequantized_weights;
40
+
41
+ global const ushort * ptr_ql = src0_ql + gx_2;
42
+ global const uchar * ptr_qh = src0_qh + gx_2;
43
+ global const ushort * ptr_s = src0_s + gx_2;
44
+ global const half * ptr_d = src0_d + gx_2;
45
+
46
+ for (int i = 0; i < k; i += 4) {
47
+ // load 4x elements (ushort) of ql on M, each ushort contains 4 weights
48
+ // 4x ushort correspons to 4 rows on M
49
+ ushort4 bits4 = vload4(0, ptr_ql + (i/4)*m); // ql packed in 4s in ushort
50
+ uchar4 bits2 = vload4(0, ptr_qh + (i/4)*m); // qh packed in 4s in uchar
51
+
52
+ // load 4 consecutive scales
53
+ char8 scale_s_8 = as_char8(vload4(0, ptr_s + (i/16/2)*m)); // 1 char scale every 16 elements, packed in 2s
54
+ char4 scale_s = ((i/16) % 2) == 0 ? scale_s_8.s0246 : scale_s_8.s1357; // transposed as ushort, 2 blocks
55
+ half4 scale_d = vload4(0, ptr_d + (i/256)*m); // 1 half scale every 256 elements
56
+
57
+ // j=0
58
+ // load 2x 4 elements of activations on N, corresponding to 8 rows on N
59
+ B.s0123 = read_imageh(src1, gy*2 + (i + 0)*n_4 + 0);
60
+ B.s4567 = read_imageh(src1, gy*2 + (i + 0)*n_4 + 1);
61
+ dequantized_weights.s0 = (convert_half((bits4.s0 & 0x000F) | ((bits2.s0 & 0x03) << 4)) - 32.f) * scale_s.s0 * scale_d.s0;
62
+ dequantized_weights.s1 = (convert_half((bits4.s1 & 0x000F) | ((bits2.s1 & 0x03) << 4)) - 32.f) * scale_s.s1 * scale_d.s1;
63
+ dequantized_weights.s2 = (convert_half((bits4.s2 & 0x000F) | ((bits2.s2 & 0x03) << 4)) - 32.f) * scale_s.s2 * scale_d.s2;
64
+ dequantized_weights.s3 = (convert_half((bits4.s3 & 0x000F) | ((bits2.s3 & 0x03) << 4)) - 32.f) * scale_s.s3 * scale_d.s3;
65
+ c0 += B * dequantized_weights.s0;
66
+ c1 += B * dequantized_weights.s1;
67
+ c2 += B * dequantized_weights.s2;
68
+ c3 += B * dequantized_weights.s3;
69
+
70
+ // j=1
71
+ B.s0123 = read_imageh(src1, gy*2 + (i + 1)*n_4 + 0);
72
+ B.s4567 = read_imageh(src1, gy*2 + (i + 1)*n_4 + 1);
73
+ dequantized_weights.s0 = (convert_half((((bits4.s0 & 0x00F0) >> 4) | ((bits2.s0 & 0x0C) << 2))) - 32.f) * scale_s.s0 * scale_d.s0;
74
+ dequantized_weights.s1 = (convert_half((((bits4.s1 & 0x00F0) >> 4) | ((bits2.s1 & 0x0C) << 2))) - 32.f) * scale_s.s1 * scale_d.s1;
75
+ dequantized_weights.s2 = (convert_half((((bits4.s2 & 0x00F0) >> 4) | ((bits2.s2 & 0x0C) << 2))) - 32.f) * scale_s.s2 * scale_d.s2;
76
+ dequantized_weights.s3 = (convert_half((((bits4.s3 & 0x00F0) >> 4) | ((bits2.s3 & 0x0C) << 2))) - 32.f) * scale_s.s3 * scale_d.s3;
77
+ c0 += B * dequantized_weights.s0;
78
+ c1 += B * dequantized_weights.s1;
79
+ c2 += B * dequantized_weights.s2;
80
+ c3 += B * dequantized_weights.s3;
81
+
82
+ // j=2
83
+ B.s0123 = read_imageh(src1, gy*2 + (i + 2)*n_4 + 0);
84
+ B.s4567 = read_imageh(src1, gy*2 + (i + 2)*n_4 + 1);
85
+ dequantized_weights.s0 = (convert_half((((bits4.s0 & 0x0F00) >> 8) | (bits2.s0 & 0x30))) - 32.f) * scale_s.s0 * scale_d.s0;
86
+ dequantized_weights.s1 = (convert_half((((bits4.s1 & 0x0F00) >> 8) | (bits2.s1 & 0x30))) - 32.f) * scale_s.s1 * scale_d.s1;
87
+ dequantized_weights.s2 = (convert_half((((bits4.s2 & 0x0F00) >> 8) | (bits2.s2 & 0x30))) - 32.f) * scale_s.s2 * scale_d.s2;
88
+ dequantized_weights.s3 = (convert_half((((bits4.s3 & 0x0F00) >> 8) | (bits2.s3 & 0x30))) - 32.f) * scale_s.s3 * scale_d.s3;
89
+ c0 += B * dequantized_weights.s0;
90
+ c1 += B * dequantized_weights.s1;
91
+ c2 += B * dequantized_weights.s2;
92
+ c3 += B * dequantized_weights.s3;
93
+
94
+ // j=3
95
+ B.s0123 = read_imageh(src1, gy*2 + (i + 3)*n_4 + 0);
96
+ B.s4567 = read_imageh(src1, gy*2 + (i + 3)*n_4 + 1);
97
+ dequantized_weights.s0 = (convert_half((((bits4.s0 & mask_f000) >> 12) | ((bits2.s0 & mask_c0) >> 2))) - 32.f) * scale_s.s0 * scale_d.s0;
98
+ dequantized_weights.s1 = (convert_half((((bits4.s1 & mask_f000) >> 12) | ((bits2.s1 & mask_c0) >> 2))) - 32.f) * scale_s.s1 * scale_d.s1;
99
+ dequantized_weights.s2 = (convert_half((((bits4.s2 & mask_f000) >> 12) | ((bits2.s2 & mask_c0) >> 2))) - 32.f) * scale_s.s2 * scale_d.s2;
100
+ dequantized_weights.s3 = (convert_half((((bits4.s3 & mask_f000) >> 12) | ((bits2.s3 & mask_c0) >> 2))) - 32.f) * scale_s.s3 * scale_d.s3;
101
+ c0 += B * dequantized_weights.s0;
102
+ c1 += B * dequantized_weights.s1;
103
+ c2 += B * dequantized_weights.s2;
104
+ c3 += B * dequantized_weights.s3;
105
+ }
106
+
107
+ int idx = (gy<<3)*m + (gx<<2);
108
+
109
+ if(idx+3 < m*n_no_padding){
110
+ vstore4((float4)(c0.s0, c1.s0, c2.s0, c3.s0), 0, dst + idx);
111
+ idx += m;
112
+ }
113
+ if(idx+3 < m*n_no_padding){
114
+ vstore4((float4)(c0.s1, c1.s1, c2.s1, c3.s1), 0, dst + idx);
115
+ idx += m;
116
+ }
117
+ if(idx+3 < m*n_no_padding){
118
+ vstore4((float4)(c0.s2, c1.s2, c2.s2, c3.s2), 0, dst + idx);
119
+ idx += m;
120
+ }
121
+ if(idx+3 < m*n_no_padding){
122
+ vstore4((float4)(c0.s3, c1.s3, c2.s3, c3.s3), 0, dst + idx);
123
+ idx += m;
124
+ }
125
+ if(idx+3 < m*n_no_padding){
126
+ vstore4((float4)(c0.s4, c1.s4, c2.s4, c3.s4), 0, dst + idx);
127
+ idx += m;
128
+ }
129
+ if(idx+3 < m*n_no_padding){
130
+ vstore4((float4)(c0.s5, c1.s5, c2.s5, c3.s5), 0, dst + idx);
131
+ idx += m;
132
+ }
133
+ if(idx+3 < m*n_no_padding){
134
+ vstore4((float4)(c0.s6, c1.s6, c2.s6, c3.s6), 0, dst + idx);
135
+ idx += m;
136
+ }
137
+ if(idx+3 < m*n_no_padding){
138
+ vstore4((float4)(c0.s7, c1.s7, c2.s7, c3.s7), 0, dst + idx);
139
+ }
140
+ }
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_noshuffle_q6_k_q8_1_dp4a.cl ADDED
@@ -0,0 +1,144 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #pragma OPENCL EXTENSION cl_khr_fp16 : enable
2
+ #pragma OPENCL EXTENSION cl_khr_subgroups : enable
3
+ #ifdef cl_khr_integer_dot_product
4
+ #pragma OPENCL EXTENSION cl_khr_integer_dot_product : enable
5
+ #endif
6
+
7
+ #define TILESIZE_N 32
8
+ #define QK_K 256
9
+
10
+ // 4 nibbles in the low 16 bits of `u` -> 4 bytes (value 0..15, in bits 0-3).
11
+ #define EXP4(u) ( ((uint)((u) & 0x000Fu)) | \
12
+ (((uint)((u) & 0x00F0u)) << 4) | \
13
+ (((uint)((u) & 0x0F00u)) << 8) | \
14
+ (((uint)((u) & 0xF000u)) << 12) )
15
+
16
+ // 4 2-bit highs in byte `b` -> 4 bytes, value 0..3 in bits 4-5 (pre-multiplied
17
+ // by 16 so it ORs with the EXP4 nibble to form q6 in 0..63).
18
+ #define EXP2(b) ( (((uint)((b) & 0x03u)) << 4) | \
19
+ (((uint)((b) & 0x0Cu)) << 10) | \
20
+ (((uint)((b) & 0x30u)) << 16) | \
21
+ (((uint)((b) & 0xC0u)) << 22) )
22
+
23
+ // q6 (0..63, bits 0-5 of each byte) -> (q6-32) as a signed int8 per byte.
24
+ inline uint SIGN6(uint q6p) {
25
+ uint x = q6p ^ 0x20202020u;
26
+ uint s = x & 0x20202020u;
27
+ return x | (s << 1) | (s << 2);
28
+ }
29
+
30
+ // 16-K dp4a dot: 4 packed weight uints against 4 packed int8 activation uints.
31
+ inline int dot4_q8a(uint w0, uint w1, uint w2, uint w3,
32
+ uint a0, uint a1, uint a2, uint a3) {
33
+ int r = 0;
34
+ r = dot_acc_sat_4x8packed_ss_int(w0, a0, r);
35
+ r = dot_acc_sat_4x8packed_ss_int(w1, a1, r);
36
+ r = dot_acc_sat_4x8packed_ss_int(w2, a2, r);
37
+ r = dot_acc_sat_4x8packed_ss_int(w3, a3, r);
38
+ return r;
39
+ }
40
+
41
+ __attribute__((qcom_wave_pair_mode(1)))
42
+ kernel void kernel_gemm_noshuffle_q6_k_q8_1_dp4a(
43
+ __global const ushort * src0_ql, // q6_K low nibbles (noshuffle)
44
+ __global const uchar * src0_qh, // q6_K high 2-bit (uchar, 4 highs/elem)
45
+ __global const ushort * src0_s, // int8 scale codes (2 chars/ushort, per 16)
46
+ __global const half * src0_d, // per-superblock scale
47
+ __global const uint * src1_qa, // q8_1 activations int8 (as uint, 4/elem) [N, K]
48
+ __global const half * src1_da, // q8_1 per-block scale [N, K/32]
49
+ __global float * dst,
50
+ ulong offsetd,
51
+ int m, // output features (rows)
52
+ int n_no_padding, // tokens (cols)
53
+ int k // K (== ne00)
54
+ ) {
55
+ dst = (global float *)((global char *)dst + offsetd);
56
+
57
+ const uint lid = get_local_id(0); // 0..63 -> row within the M-tile
58
+ const uint block_id_m = get_global_id(1);
59
+ const uint block_id_n = get_global_id(2);
60
+
61
+ const uint row = block_id_m * 64 + lid;
62
+ const uint col_base = block_id_n * TILESIZE_N;
63
+ const bool row_valid = row < (uint)m;
64
+ const uint rrow = row_valid ? row : 0; // clamp OOB rows; their writes are masked
65
+
66
+ const uint k_u = (uint)k >> 2; // K in uint (int8x4) units
67
+ const uint k_b = (uint)k >> 5; // blocks-of-32 along K
68
+
69
+ __local uint sh_qa[TILESIZE_N][8];
70
+ __local half sh_d[TILESIZE_N];
71
+
72
+ #define NGROUPS (TILESIZE_N / 4)
73
+ float4 acc[NGROUPS];
74
+ #pragma unroll
75
+ for (int g = 0; g < NGROUPS; ++g) acc[g] = (float4)(0.0f);
76
+
77
+ for (uint step = 0; step < (uint)k; step += 32) {
78
+ const uint sub = step >> 5; // 32-block index along K
79
+ const uint sb_idx = step / QK_K; // superblock index
80
+
81
+ // q6_K superblock scale + the two int8 sub-scales spanning this 32-block
82
+ const float dd = (float)src0_d[rrow + sb_idx * m];
83
+ const char2 sc = as_char2(src0_s[rrow + sub * m]);
84
+ const float scale0 = dd * (float)sc.s0; // K step..step+15
85
+ const float scale1 = dd * (float)sc.s1; // K step+16..step+31
86
+
87
+ // repack this row's 32 weights into 8 dp4a uints (4 K each). ql ushort +
88
+ // qh uchar are co-located at src0_*[row + (step/4 + u)*m].
89
+ const uint wbase = rrow + (step >> 2) * (uint)m;
90
+ uint qw[8];
91
+ #pragma unroll
92
+ for (int u = 0; u < 8; ++u) {
93
+ const uint o = wbase + (uint)u * (uint)m;
94
+ qw[u] = SIGN6(EXP4((uint)src0_ql[o]) | EXP2((uint)src0_qh[o]));
95
+ }
96
+
97
+ // cooperatively stage the 32-token x 32-K int8 activations + scale
98
+ for (uint idx = lid; idx < TILESIZE_N * 8; idx += 64) {
99
+ const uint t = idx >> 3;
100
+ const uint u = idx & 7;
101
+ const uint c = col_base + t;
102
+ sh_qa[t][u] = (c < (uint)n_no_padding) ? src1_qa[c * k_u + (step >> 2) + u] : 0u;
103
+ }
104
+ if (lid < TILESIZE_N) {
105
+ const uint c = col_base + lid;
106
+ sh_d[lid] = (c < (uint)n_no_padding) ? src1_da[c * k_b + sub] : (half)0;
107
+ }
108
+ barrier(CLK_LOCAL_MEM_FENCE);
109
+
110
+ #pragma unroll
111
+ for (int g = 0; g < NGROUPS; ++g) {
112
+ const int b = g * 4;
113
+ float4 rf;
114
+ #define DOT_TOK(j) { \
115
+ __local const uint * a = sh_qa[b + (j)]; \
116
+ const int raw1 = dot4_q8a(qw[0], qw[1], qw[2], qw[3], a[0], a[1], a[2], a[3]); \
117
+ const int raw2 = dot4_q8a(qw[4], qw[5], qw[6], qw[7], a[4], a[5], a[6], a[7]); \
118
+ rf.s##j = scale0 * (float)raw1 + scale1 * (float)raw2; \
119
+ }
120
+ DOT_TOK(0); DOT_TOK(1); DOT_TOK(2); DOT_TOK(3);
121
+ #undef DOT_TOK
122
+ const float4 ad = (float4)((float)sh_d[b+0], (float)sh_d[b+1], (float)sh_d[b+2], (float)sh_d[b+3]);
123
+ acc[g] += ad * rf;
124
+ }
125
+ barrier(CLK_LOCAL_MEM_FENCE);
126
+ }
127
+
128
+ if (!row_valid) {
129
+ return;
130
+ }
131
+
132
+ // dst is [token, feature] row-major (stride m): dst[col*m + row].
133
+ #pragma unroll
134
+ for (int g = 0; g < NGROUPS; ++g) {
135
+ const uint b = (uint)(g * 4);
136
+ const float4 a = acc[g];
137
+ const uint c0 = col_base + b;
138
+ if (c0 + 0 < (uint)n_no_padding) dst[(c0 + 0) * (uint)m + row] = a.s0;
139
+ if (c0 + 1 < (uint)n_no_padding) dst[(c0 + 1) * (uint)m + row] = a.s1;
140
+ if (c0 + 2 < (uint)n_no_padding) dst[(c0 + 2) * (uint)m + row] = a.s2;
141
+ if (c0 + 3 < (uint)n_no_padding) dst[(c0 + 3) * (uint)m + row] = a.s3;
142
+ }
143
+ #undef NGROUPS
144
+ }
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_noshuffle_q8_0_f32.cl ADDED
@@ -0,0 +1,129 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #pragma OPENCL EXTENSION cl_khr_fp16 : enable
2
+ #pragma OPENCL EXTENSION cl_qcom_reqd_sub_group_size : enable
3
+
4
+ #ifdef cl_qcom_reqd_sub_group_size
5
+ #pragma OPENCL EXTENSION cl_qcom_reqd_sub_group_size : enable
6
+ #define ADRENO_GPU 1
7
+ #define REQD_SUBGROUP_SIZE_128 __attribute__((qcom_reqd_sub_group_size("full")))
8
+ #endif
9
+
10
+ #ifdef ADRENO_GPU
11
+ REQD_SUBGROUP_SIZE_128
12
+ #endif
13
+
14
+ kernel void kernel_gemm_noshuffle_q8_0_f32(
15
+ global const uint * src0_q,
16
+ global const half * src0_d,
17
+ __read_only image1d_buffer_t src1,
18
+ global float * dst,
19
+ int k,
20
+ int m,
21
+ int n,
22
+ int n_no_padding,
23
+ ulong offsetd
24
+ ) {
25
+
26
+ int m_4 = m >> 2;
27
+ int n_4 = n >> 2;
28
+
29
+ int gy = get_global_id(0);
30
+ int gx = get_global_id(1);
31
+ int gx_2 = gx << 2;
32
+ dst = (global float *)((global char*)dst + offsetd);
33
+
34
+
35
+ half8 c0 = 0, c1 = 0, c2 = 0, c3 = 0;
36
+ half8 B;
37
+ half4 deq;
38
+
39
+ __global const uint* wptr = src0_q + gx_2;
40
+ __global const half* sptr = src0_d + gx_2;
41
+
42
+ for (int i = 0; i < k; i += 4) {
43
+ uint4 pack4 = vload4(0, wptr + (i / 4) * m);
44
+ half4 scale = vload4(0, sptr + (i / 32) * m);
45
+
46
+ char4 p0 = as_char4(pack4.s0);
47
+ char4 p1 = as_char4(pack4.s1);
48
+ char4 p2 = as_char4(pack4.s2);
49
+ char4 p3 = as_char4(pack4.s3);
50
+
51
+ // ------------------- j = 0 (k = i+0) -------------------
52
+ B.s0123 = read_imageh(src1, gy * 2 + (i + 0) * n_4);
53
+ B.s4567 = read_imageh(src1, gy * 2 + (i + 0) * n_4 + 1);
54
+
55
+ half4 wj0 = convert_half4((char4)(p0.s0, p1.s0, p2.s0, p3.s0)) * scale;
56
+
57
+ c0 += B * wj0.s0;
58
+ c1 += B * wj0.s1;
59
+ c2 += B * wj0.s2;
60
+ c3 += B * wj0.s3;
61
+
62
+ // ------------------- j = 1 (k = i+1) -------------------
63
+ B.s0123 = read_imageh(src1, gy * 2 + (i + 1) * n_4);
64
+ B.s4567 = read_imageh(src1, gy * 2 + (i + 1) * n_4 + 1);
65
+
66
+ half4 wj1 = convert_half4((char4)(p0.s1, p1.s1, p2.s1, p3.s1)) * scale;
67
+
68
+ c0 += B * wj1.s0;
69
+ c1 += B * wj1.s1;
70
+ c2 += B * wj1.s2;
71
+ c3 += B * wj1.s3;
72
+
73
+ // ------------------- j = 2 (k = i+2) -------------------
74
+ B.s0123 = read_imageh(src1, gy * 2 + (i + 2) * n_4);
75
+ B.s4567 = read_imageh(src1, gy * 2 + (i + 2) * n_4 + 1);
76
+
77
+ half4 wj2 = convert_half4((char4)(p0.s2, p1.s2, p2.s2, p3.s2)) * scale;
78
+
79
+ c0 += B * wj2.s0;
80
+ c1 += B * wj2.s1;
81
+ c2 += B * wj2.s2;
82
+ c3 += B * wj2.s3;
83
+
84
+ // ------------------- j = 3 (k = i+3) -------------------
85
+ B.s0123 = read_imageh(src1, gy * 2 + (i + 3) * n_4);
86
+ B.s4567 = read_imageh(src1, gy * 2 + (i + 3) * n_4 + 1);
87
+
88
+ half4 wj3 = convert_half4((char4)(p0.s3, p1.s3, p2.s3, p3.s3)) * scale;
89
+
90
+ c0 += B * wj3.s0;
91
+ c1 += B * wj3.s1;
92
+ c2 += B * wj3.s2;
93
+ c3 += B * wj3.s3;
94
+ }
95
+
96
+ int idx = (gy << 3) * m + (gx << 2);
97
+
98
+ if(idx+3 < m*n_no_padding){
99
+ vstore4((float4)(c0.s0, c1.s0, c2.s0, c3.s0), 0, dst + idx);
100
+ idx += m;
101
+ }
102
+ if(idx+3 < m*n_no_padding){
103
+ vstore4((float4)(c0.s1, c1.s1, c2.s1, c3.s1), 0, dst + idx);
104
+ idx += m;
105
+ }
106
+ if(idx+3 < m*n_no_padding){
107
+ vstore4((float4)(c0.s2, c1.s2, c2.s2, c3.s2), 0, dst + idx);
108
+ idx += m;
109
+ }
110
+ if(idx+3 < m*n_no_padding){
111
+ vstore4((float4)(c0.s3, c1.s3, c2.s3, c3.s3), 0, dst + idx);
112
+ idx += m;
113
+ }
114
+ if(idx+3 < m*n_no_padding){
115
+ vstore4((float4)(c0.s4, c1.s4, c2.s4, c3.s4), 0, dst + idx);
116
+ idx += m;
117
+ }
118
+ if(idx+3 < m*n_no_padding){
119
+ vstore4((float4)(c0.s5, c1.s5, c2.s5, c3.s5), 0, dst + idx);
120
+ idx += m;
121
+ }
122
+ if(idx+3 < m*n_no_padding){
123
+ vstore4((float4)(c0.s6, c1.s6, c2.s6, c3.s6), 0, dst + idx);
124
+ idx += m;
125
+ }
126
+ if(idx+3 < m*n_no_padding){
127
+ vstore4((float4)(c0.s7, c1.s7, c2.s7, c3.s7), 0, dst + idx);
128
+ }
129
+ }
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_noshuffle_q8_0_q8_1_dp4a.cl ADDED
@@ -0,0 +1,212 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #pragma OPENCL EXTENSION cl_khr_fp16 : enable
2
+ #pragma OPENCL EXTENSION cl_khr_subgroups : enable
3
+ #ifdef cl_khr_integer_dot_product
4
+ #pragma OPENCL EXTENSION cl_khr_integer_dot_product : enable
5
+ #endif
6
+
7
+ // ne1<=8 keeps the f16 / bin small-batch path.
8
+
9
+ #define TILESIZE_N 32
10
+
11
+ // 32-K dp4a dot of one token's int8 activations (8 packed uints in lm) against
12
+ // 8 packed weight uints. q8_0 weights are already dp4a-format signed int8.
13
+ inline int dot8_q8a(uint8 qw, __local const uint * a) {
14
+ int r = 0;
15
+ r = dot_acc_sat_4x8packed_ss_int(qw.s0, a[0], r);
16
+ r = dot_acc_sat_4x8packed_ss_int(qw.s1, a[1], r);
17
+ r = dot_acc_sat_4x8packed_ss_int(qw.s2, a[2], r);
18
+ r = dot_acc_sat_4x8packed_ss_int(qw.s3, a[3], r);
19
+ r = dot_acc_sat_4x8packed_ss_int(qw.s4, a[4], r);
20
+ r = dot_acc_sat_4x8packed_ss_int(qw.s5, a[5], r);
21
+ r = dot_acc_sat_4x8packed_ss_int(qw.s6, a[6], r);
22
+ r = dot_acc_sat_4x8packed_ss_int(qw.s7, a[7], r);
23
+ return r;
24
+ }
25
+
26
+ __attribute__((qcom_wave_pair_mode(1)))
27
+ kernel void kernel_gemm_noshuffle_q8_0_q8_1_dp4a(
28
+ __global const uint * src0_q, // q8_0 weights: signed int8, 4/uint, feature-major
29
+ __global const half * src0_d, // per-32-block scale, feature-major [row + (k/32)*m]
30
+ __global const uint * src1_qa, // q8_1 activations int8 (as uint, 4/elem) [N, K]
31
+ __global const half * src1_da, // q8_1 per-block scale [N, K/32]
32
+ __global float * dst,
33
+ ulong offsetd,
34
+ int m, // output features (rows)
35
+ int n_no_padding, // tokens (cols)
36
+ int k // K (== ne00)
37
+ ) {
38
+ dst = (global float *)((global char *)dst + offsetd);
39
+
40
+ const uint lid = get_local_id(0); // 0..63 -> row within the M-tile
41
+ const uint block_id_m = get_global_id(1);
42
+ const uint block_id_n = get_global_id(2);
43
+
44
+ const uint row = block_id_m * 64 + lid;
45
+ const uint col_base = block_id_n * TILESIZE_N;
46
+ const bool row_valid = row < (uint)m;
47
+ const uint rrow = row_valid ? row : 0; // clamp OOB rows; their writes are masked
48
+
49
+ const uint k_u = (uint)k >> 2; // K in uint (int8x4) units
50
+ const uint k_b = (uint)k >> 5; // blocks-of-32 along K
51
+
52
+ __local uint sh_qa[TILESIZE_N][8];
53
+ __local half sh_d[TILESIZE_N];
54
+
55
+ #define NGROUPS (TILESIZE_N / 4)
56
+ float4 acc[NGROUPS];
57
+ #pragma unroll
58
+ for (int g = 0; g < NGROUPS; ++g) acc[g] = (float4)(0.0f);
59
+
60
+ for (uint step = 0; step < (uint)k; step += 32) {
61
+ const uint sub = step >> 5;
62
+
63
+ const float d_w = (float)src0_d[rrow + sub * (uint)m];
64
+
65
+ // 8 weight uints (32 int8) for this row, this 32-block. Feature-major:
66
+ // src0_q[row + (k/4 + u)*m], k/4 = step/4 (= step>>2).
67
+ const uint wbase = rrow + (step >> 2) * (uint)m;
68
+ uint8 qw;
69
+ qw.s0 = src0_q[wbase + 0 * m];
70
+ qw.s1 = src0_q[wbase + 1 * m];
71
+ qw.s2 = src0_q[wbase + 2 * m];
72
+ qw.s3 = src0_q[wbase + 3 * m];
73
+ qw.s4 = src0_q[wbase + 4 * m];
74
+ qw.s5 = src0_q[wbase + 5 * m];
75
+ qw.s6 = src0_q[wbase + 6 * m];
76
+ qw.s7 = src0_q[wbase + 7 * m];
77
+
78
+ // cooperatively stage the 32-token x 32-K int8 activations to LDS
79
+ for (uint idx = lid; idx < TILESIZE_N * 8; idx += 64) {
80
+ const uint t = idx >> 3;
81
+ const uint u = idx & 7;
82
+ const uint c = col_base + t;
83
+ sh_qa[t][u] = (c < (uint)n_no_padding) ? src1_qa[c * k_u + (step >> 2) + u] : 0u;
84
+ }
85
+ if (lid < TILESIZE_N) {
86
+ const uint c = col_base + lid;
87
+ sh_d[lid] = (c < (uint)n_no_padding) ? src1_da[c * k_b + sub] : (half)0;
88
+ }
89
+ barrier(CLK_LOCAL_MEM_FENCE);
90
+
91
+ #define LD4(arr, b) ((float4)((float)arr[(b)+0], (float)arr[(b)+1], (float)arr[(b)+2], (float)arr[(b)+3]))
92
+ #pragma unroll
93
+ for (int g = 0; g < NGROUPS; ++g) {
94
+ const int b = g * 4;
95
+ float4 rf;
96
+ rf.s0 = (float)dot8_q8a(qw, sh_qa[b+0]); rf.s1 = (float)dot8_q8a(qw, sh_qa[b+1]);
97
+ rf.s2 = (float)dot8_q8a(qw, sh_qa[b+2]); rf.s3 = (float)dot8_q8a(qw, sh_qa[b+3]);
98
+ acc[g] += d_w * LD4(sh_d, b) * rf;
99
+ }
100
+ #undef LD4
101
+ barrier(CLK_LOCAL_MEM_FENCE);
102
+ }
103
+
104
+ if (!row_valid) {
105
+ return;
106
+ }
107
+
108
+ // dst is [token, feature] row-major (stride m): dst[col*m + row].
109
+ #pragma unroll
110
+ for (int g = 0; g < NGROUPS; ++g) {
111
+ const uint b = (uint)(g * 4);
112
+ const float4 a = acc[g];
113
+ const uint c0 = col_base + b;
114
+ if (c0 + 0 < (uint)n_no_padding) dst[(c0 + 0) * (uint)m + row] = a.s0;
115
+ if (c0 + 1 < (uint)n_no_padding) dst[(c0 + 1) * (uint)m + row] = a.s1;
116
+ if (c0 + 2 < (uint)n_no_padding) dst[(c0 + 2) * (uint)m + row] = a.s2;
117
+ if (c0 + 3 < (uint)n_no_padding) dst[(c0 + 3) * (uint)m + row] = a.s3;
118
+ }
119
+ #undef NGROUPS
120
+ }
121
+
122
+ __attribute__((qcom_wave_pair_mode(1)))
123
+ kernel void kernel_gemm_noshuffle_q8_0_q8_1_dp4a_wimg(
124
+ __read_only image1d_buffer_t src0_q_img, // q8_0 weights as uint32 texels (4 int8/texel)
125
+ __global const half * src0_d,
126
+ __global const uint * src1_qa,
127
+ __global const half * src1_da,
128
+ __global float * dst,
129
+ ulong offsetd,
130
+ int m,
131
+ int n_no_padding,
132
+ int k
133
+ ) {
134
+ dst = (global float *)((global char *)dst + offsetd);
135
+
136
+ const uint lid = get_local_id(0);
137
+ const uint block_id_m = get_global_id(1);
138
+ const uint block_id_n = get_global_id(2);
139
+
140
+ const uint row = block_id_m * 64 + lid;
141
+ const uint col_base = block_id_n * TILESIZE_N;
142
+ const bool row_valid = row < (uint)m;
143
+ const uint rrow = row_valid ? row : 0;
144
+
145
+ const uint k_u = (uint)k >> 2;
146
+ const uint k_b = (uint)k >> 5;
147
+
148
+ __local uint sh_qa[TILESIZE_N][8];
149
+ __local half sh_d[TILESIZE_N];
150
+
151
+ #define NGROUPS (TILESIZE_N / 4)
152
+ float4 acc[NGROUPS];
153
+ #pragma unroll
154
+ for (int g = 0; g < NGROUPS; ++g) acc[g] = (float4)(0.0f);
155
+
156
+ for (uint step = 0; step < (uint)k; step += 32) {
157
+ const uint sub = step >> 5;
158
+
159
+ const float d_w = (float)src0_d[rrow + sub * (uint)m];
160
+
161
+ const uint wbase = rrow + (step >> 2) * (uint)m;
162
+ uint8 qw;
163
+ qw.s0 = read_imageui(src0_q_img, (int)(wbase + 0 * m)).x;
164
+ qw.s1 = read_imageui(src0_q_img, (int)(wbase + 1 * m)).x;
165
+ qw.s2 = read_imageui(src0_q_img, (int)(wbase + 2 * m)).x;
166
+ qw.s3 = read_imageui(src0_q_img, (int)(wbase + 3 * m)).x;
167
+ qw.s4 = read_imageui(src0_q_img, (int)(wbase + 4 * m)).x;
168
+ qw.s5 = read_imageui(src0_q_img, (int)(wbase + 5 * m)).x;
169
+ qw.s6 = read_imageui(src0_q_img, (int)(wbase + 6 * m)).x;
170
+ qw.s7 = read_imageui(src0_q_img, (int)(wbase + 7 * m)).x;
171
+
172
+ for (uint idx = lid; idx < TILESIZE_N * 8; idx += 64) {
173
+ const uint t = idx >> 3;
174
+ const uint u = idx & 7;
175
+ const uint c = col_base + t;
176
+ sh_qa[t][u] = (c < (uint)n_no_padding) ? src1_qa[c * k_u + (step >> 2) + u] : 0u;
177
+ }
178
+ if (lid < TILESIZE_N) {
179
+ const uint c = col_base + lid;
180
+ sh_d[lid] = (c < (uint)n_no_padding) ? src1_da[c * k_b + sub] : (half)0;
181
+ }
182
+ barrier(CLK_LOCAL_MEM_FENCE);
183
+
184
+ #define LD4(arr, b) ((float4)((float)arr[(b)+0], (float)arr[(b)+1], (float)arr[(b)+2], (float)arr[(b)+3]))
185
+ #pragma unroll
186
+ for (int g = 0; g < NGROUPS; ++g) {
187
+ const int b = g * 4;
188
+ float4 rf;
189
+ rf.s0 = (float)dot8_q8a(qw, sh_qa[b+0]); rf.s1 = (float)dot8_q8a(qw, sh_qa[b+1]);
190
+ rf.s2 = (float)dot8_q8a(qw, sh_qa[b+2]); rf.s3 = (float)dot8_q8a(qw, sh_qa[b+3]);
191
+ acc[g] += d_w * LD4(sh_d, b) * rf;
192
+ }
193
+ #undef LD4
194
+ barrier(CLK_LOCAL_MEM_FENCE);
195
+ }
196
+
197
+ if (!row_valid) {
198
+ return;
199
+ }
200
+
201
+ #pragma unroll
202
+ for (int g = 0; g < NGROUPS; ++g) {
203
+ const uint b = (uint)(g * 4);
204
+ const float4 a = acc[g];
205
+ const uint c0 = col_base + b;
206
+ if (c0 + 0 < (uint)n_no_padding) dst[(c0 + 0) * (uint)m + row] = a.s0;
207
+ if (c0 + 1 < (uint)n_no_padding) dst[(c0 + 1) * (uint)m + row] = a.s1;
208
+ if (c0 + 2 < (uint)n_no_padding) dst[(c0 + 2) * (uint)m + row] = a.s2;
209
+ if (c0 + 3 < (uint)n_no_padding) dst[(c0 + 3) * (uint)m + row] = a.s3;
210
+ }
211
+ #undef NGROUPS
212
+ }
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_xmem_f16_f32_os8.cl ADDED
@@ -0,0 +1,233 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #pragma OPENCL EXTENSION cl_khr_fp16 : enable
2
+ #pragma OPENCL EXTENSION cl_qcom_subgroup_uniform_load : enable
3
+ #pragma OPENCL EXTENSION cl_qcom_subgroup_constant_load : enable
4
+
5
+ __constant sampler_t smp_zero = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP | CLK_FILTER_NEAREST;
6
+
7
+ __kernel void adreno_xmem_pack_src_f32(
8
+ __global const void * src_void,
9
+ ulong offset,
10
+ __write_only image2d_t src_img,
11
+ int K,
12
+ int N) {
13
+ const int x = get_global_id(0);
14
+ const int y = get_global_id(1);
15
+ const int kpack = K / 4;
16
+
17
+ if (x >= N || y >= kpack) {
18
+ return;
19
+ }
20
+
21
+ __global const float * src = (__global const float *)((__global const char *)src_void + offset);
22
+ const int base = x*K + y*4;
23
+ const half4 v = (half4)((half)src[base + 0], (half)src[base + 1], (half)src[base + 2], (half)src[base + 3]);
24
+ write_imageh(src_img, (int2)(x, y), v);
25
+ }
26
+
27
+ __kernel void adreno_xmem_prepack_weight_f16(
28
+ __global half4 * dst,
29
+ __global const void * src_void,
30
+ ulong offset,
31
+ int K,
32
+ int M,
33
+ int kpack,
34
+ int npack,
35
+ int os) {
36
+ const int linear = get_global_id(0);
37
+ const int total = kpack*npack;
38
+ if (linear >= total) {
39
+ return;
40
+ }
41
+
42
+ __global const half * src = (__global const half *)((__global const char *)src_void + offset);
43
+
44
+ const int dst_ogroup = linear % os;
45
+ const int dst_o_sp_i = linear / os;
46
+ const int dst_i = dst_o_sp_i % kpack;
47
+ const int dst_o = dst_o_sp_i / kpack;
48
+ const int o_slice = dst_o*os + dst_ogroup;
49
+ const int k_base = dst_i*4;
50
+
51
+ half4 w0 = (half4)(0.0h);
52
+ half4 w1 = (half4)(0.0h);
53
+ half4 w2 = (half4)(0.0h);
54
+ half4 w3 = (half4)(0.0h);
55
+
56
+ const int o0 = o_slice*4 + 0;
57
+ const int o1 = o_slice*4 + 1;
58
+ const int o2 = o_slice*4 + 2;
59
+ const int o3 = o_slice*4 + 3;
60
+
61
+ if (k_base + 0 < K) {
62
+ if (o0 < M) w0.s0 = src[o0*K + k_base + 0];
63
+ if (o1 < M) w0.s1 = src[o1*K + k_base + 0];
64
+ if (o2 < M) w0.s2 = src[o2*K + k_base + 0];
65
+ if (o3 < M) w0.s3 = src[o3*K + k_base + 0];
66
+ }
67
+ if (k_base + 1 < K) {
68
+ if (o0 < M) w1.s0 = src[o0*K + k_base + 1];
69
+ if (o1 < M) w1.s1 = src[o1*K + k_base + 1];
70
+ if (o2 < M) w1.s2 = src[o2*K + k_base + 1];
71
+ if (o3 < M) w1.s3 = src[o3*K + k_base + 1];
72
+ }
73
+ if (k_base + 2 < K) {
74
+ if (o0 < M) w2.s0 = src[o0*K + k_base + 2];
75
+ if (o1 < M) w2.s1 = src[o1*K + k_base + 2];
76
+ if (o2 < M) w2.s2 = src[o2*K + k_base + 2];
77
+ if (o3 < M) w2.s3 = src[o3*K + k_base + 2];
78
+ }
79
+ if (k_base + 3 < K) {
80
+ if (o0 < M) w3.s0 = src[o0*K + k_base + 3];
81
+ if (o1 < M) w3.s1 = src[o1*K + k_base + 3];
82
+ if (o2 < M) w3.s2 = src[o2*K + k_base + 3];
83
+ if (o3 < M) w3.s3 = src[o3*K + k_base + 3];
84
+ }
85
+
86
+ dst[linear*4 + 0] = w0;
87
+ dst[linear*4 + 1] = w1;
88
+ dst[linear*4 + 2] = w2;
89
+ dst[linear*4 + 3] = w3;
90
+ }
91
+
92
+ __attribute__((qcom_max_concurrent_subgroups(12)))
93
+ __kernel void kernel_gemm_xmem_f16_f32_os8(
94
+ __constant half8 * weights_buffer __attribute__((sub_group_uniform)),
95
+ __constant half8 * xmem_buffer __attribute__((max_constant_size((6144)))),
96
+ __read_only image2d_t src_img,
97
+ __write_only image2d_t dst_img,
98
+ int N,
99
+ int npack,
100
+ int kpack) {
101
+ const int X = get_group_id(1)*get_local_size(0) + get_local_id(0);
102
+ const int Z = get_group_id(0)*get_local_size(2) + get_local_id(2);
103
+
104
+ if (X >= N || Z*8 >= npack) {
105
+ return;
106
+ }
107
+
108
+ half4 r0 = (half4)(0.0h);
109
+ half4 r1 = (half4)(0.0h);
110
+ half4 r2 = (half4)(0.0h);
111
+ half4 r3 = (half4)(0.0h);
112
+ half4 r4 = (half4)(0.0h);
113
+ half4 r5 = (half4)(0.0h);
114
+ half4 r6 = (half4)(0.0h);
115
+ half4 r7 = (half4)(0.0h);
116
+
117
+ int f_offset = Z*kpack*32;
118
+ int subgroup_id = (int)(0x1F & qcom_get_physical_sub_group_id());
119
+ subgroup_id = subgroup_id % 12;
120
+ const int c_offset = subgroup_id*32;
121
+ __constant half16 * weights_cache = (__constant half16 *)&xmem_buffer[c_offset];
122
+
123
+ int coord_s = 0;
124
+ do {
125
+ const half4 src0 = read_imageh(src_img, smp_zero, (int2)(X, coord_s));
126
+ coord_s++;
127
+ const half4 src1 = read_imageh(src_img, smp_zero, (int2)(X, coord_s));
128
+ coord_s++;
129
+
130
+ qcom_sub_group_constant_load8(xmem_buffer, weights_buffer, c_offset, f_offset >> 1, 32);
131
+ f_offset += 64;
132
+ qcom_sub_group_sync(QCOM_CLK_CONST_LOAD_SYNC);
133
+
134
+ r0 += src0.x * weights_cache[0].s0123;
135
+ r0 += src0.y * weights_cache[0].s4567;
136
+ r0 += src0.z * weights_cache[0].s89ab;
137
+ r0 += src0.w * weights_cache[0].scdef;
138
+ r1 += src0.x * weights_cache[1].s0123;
139
+ r1 += src0.y * weights_cache[1].s4567;
140
+ r1 += src0.z * weights_cache[1].s89ab;
141
+ r1 += src0.w * weights_cache[1].scdef;
142
+ r2 += src0.x * weights_cache[2].s0123;
143
+ r2 += src0.y * weights_cache[2].s4567;
144
+ r2 += src0.z * weights_cache[2].s89ab;
145
+ r2 += src0.w * weights_cache[2].scdef;
146
+ r3 += src0.x * weights_cache[3].s0123;
147
+ r3 += src0.y * weights_cache[3].s4567;
148
+ r3 += src0.z * weights_cache[3].s89ab;
149
+ r3 += src0.w * weights_cache[3].scdef;
150
+ r4 += src0.x * weights_cache[4].s0123;
151
+ r4 += src0.y * weights_cache[4].s4567;
152
+ r4 += src0.z * weights_cache[4].s89ab;
153
+ r4 += src0.w * weights_cache[4].scdef;
154
+ r5 += src0.x * weights_cache[5].s0123;
155
+ r5 += src0.y * weights_cache[5].s4567;
156
+ r5 += src0.z * weights_cache[5].s89ab;
157
+ r5 += src0.w * weights_cache[5].scdef;
158
+ r6 += src0.x * weights_cache[6].s0123;
159
+ r6 += src0.y * weights_cache[6].s4567;
160
+ r6 += src0.z * weights_cache[6].s89ab;
161
+ r6 += src0.w * weights_cache[6].scdef;
162
+ r7 += src0.x * weights_cache[7].s0123;
163
+ r7 += src0.y * weights_cache[7].s4567;
164
+ r7 += src0.z * weights_cache[7].s89ab;
165
+ r7 += src0.w * weights_cache[7].scdef;
166
+
167
+ r0 += src1.x * weights_cache[8].s0123;
168
+ r0 += src1.y * weights_cache[8].s4567;
169
+ r0 += src1.z * weights_cache[8].s89ab;
170
+ r0 += src1.w * weights_cache[8].scdef;
171
+ r1 += src1.x * weights_cache[9].s0123;
172
+ r1 += src1.y * weights_cache[9].s4567;
173
+ r1 += src1.z * weights_cache[9].s89ab;
174
+ r1 += src1.w * weights_cache[9].scdef;
175
+ r2 += src1.x * weights_cache[10].s0123;
176
+ r2 += src1.y * weights_cache[10].s4567;
177
+ r2 += src1.z * weights_cache[10].s89ab;
178
+ r2 += src1.w * weights_cache[10].scdef;
179
+ r3 += src1.x * weights_cache[11].s0123;
180
+ r3 += src1.y * weights_cache[11].s4567;
181
+ r3 += src1.z * weights_cache[11].s89ab;
182
+ r3 += src1.w * weights_cache[11].scdef;
183
+ r4 += src1.x * weights_cache[12].s0123;
184
+ r4 += src1.y * weights_cache[12].s4567;
185
+ r4 += src1.z * weights_cache[12].s89ab;
186
+ r4 += src1.w * weights_cache[12].scdef;
187
+ r5 += src1.x * weights_cache[13].s0123;
188
+ r5 += src1.y * weights_cache[13].s4567;
189
+ r5 += src1.z * weights_cache[13].s89ab;
190
+ r5 += src1.w * weights_cache[13].scdef;
191
+ r6 += src1.x * weights_cache[14].s0123;
192
+ r6 += src1.y * weights_cache[14].s4567;
193
+ r6 += src1.z * weights_cache[14].s89ab;
194
+ r6 += src1.w * weights_cache[14].scdef;
195
+ r7 += src1.x * weights_cache[15].s0123;
196
+ r7 += src1.y * weights_cache[15].s4567;
197
+ r7 += src1.z * weights_cache[15].s89ab;
198
+ r7 += src1.w * weights_cache[15].scdef;
199
+ } while (coord_s < kpack);
200
+
201
+ int coord_s_out = Z*8;
202
+ if (coord_s_out < npack) { write_imageh(dst_img, (int2)(X, coord_s_out), r0); coord_s_out++; }
203
+ if (coord_s_out < npack) { write_imageh(dst_img, (int2)(X, coord_s_out), r1); coord_s_out++; }
204
+ if (coord_s_out < npack) { write_imageh(dst_img, (int2)(X, coord_s_out), r2); coord_s_out++; }
205
+ if (coord_s_out < npack) { write_imageh(dst_img, (int2)(X, coord_s_out), r3); coord_s_out++; }
206
+ if (coord_s_out < npack) { write_imageh(dst_img, (int2)(X, coord_s_out), r4); coord_s_out++; }
207
+ if (coord_s_out < npack) { write_imageh(dst_img, (int2)(X, coord_s_out), r5); coord_s_out++; }
208
+ if (coord_s_out < npack) { write_imageh(dst_img, (int2)(X, coord_s_out), r6); coord_s_out++; }
209
+ if (coord_s_out < npack) { write_imageh(dst_img, (int2)(X, coord_s_out), r7); }
210
+ }
211
+
212
+ __kernel void adreno_xmem_store_dst_f32(
213
+ __read_only image2d_t dst_img,
214
+ __global void * dst_void,
215
+ ulong offset,
216
+ int M,
217
+ int N) {
218
+ const int x = get_global_id(0);
219
+ const int y = get_global_id(1);
220
+ const int npack = (M + 3) / 4;
221
+
222
+ if (x >= N || y >= npack) {
223
+ return;
224
+ }
225
+
226
+ __global float * dst = (__global float *)((__global char *)dst_void + offset);
227
+ const half4 hv = read_imageh(dst_img, smp_zero, (int2)(x, y));
228
+ const int m = y*4;
229
+ if (m + 0 < M) dst[x*M + m + 0] = (float)hv.s0;
230
+ if (m + 1 < M) dst[x*M + m + 1] = (float)hv.s1;
231
+ if (m + 2 < M) dst[x*M + m + 2] = (float)hv.s2;
232
+ if (m + 3 < M) dst[x*M + m + 3] = (float)hv.s3;
233
+ }
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemv_moe_mxfp4_f32.cl ADDED
@@ -0,0 +1,156 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #pragma OPENCL EXTENSION cl_khr_fp16 : enable
2
+ #pragma OPENCL EXTENSION cl_khr_subgroups : enable
3
+ #pragma OPENCL EXTENSION cl_qcom_reqd_sub_group_size : enable
4
+
5
+ #define QK_MXFP4 32
6
+ #define N_SIMDGROUP 4
7
+ #define SIMDGROUP_WIDTH 64
8
+
9
+ static inline half8 mxfp4_to_fp16_packed8(ushort2 fp4x8) { //, ushort 0x0E00, ushort 0x8000) {
10
+ ushort2 fp16_packed_a_0, fp16_packed_b_0, bias_a, bias_b, sign_a, sign_b;
11
+ fp16_packed_a_0.lo = (fp4x8.s0 << 9) & 0x0E00;
12
+ fp16_packed_a_0.hi = (fp4x8.s0 << 5) & 0x0E00;
13
+ fp16_packed_b_0.lo = (fp4x8.s0 << 1) & 0x0E00;
14
+ fp16_packed_b_0.hi = (fp4x8.s0 >> 3) & 0x0E00;
15
+
16
+ bias_a.lo = (fp16_packed_a_0.lo != 0) ? 0x3800 : 0x0;
17
+ bias_a.hi = (fp16_packed_a_0.hi != 0) ? 0x3800 : 0x0;
18
+ bias_b.lo = (fp16_packed_b_0.lo != 0) ? 0x3800 : 0x0;
19
+ bias_b.hi = (fp16_packed_b_0.hi != 0) ? 0x3800 : 0x0;
20
+
21
+ fp16_packed_a_0.lo = (fp16_packed_a_0.lo != 0x0200) ? fp16_packed_a_0.lo : 0x0;
22
+ fp16_packed_a_0.hi = (fp16_packed_a_0.hi != 0x0200) ? fp16_packed_a_0.hi : 0x0;
23
+ fp16_packed_b_0.lo = (fp16_packed_b_0.lo != 0x0200) ? fp16_packed_b_0.lo : 0x0;
24
+ fp16_packed_b_0.hi = (fp16_packed_b_0.hi != 0x0200) ? fp16_packed_b_0.hi : 0x0;
25
+
26
+ sign_a.lo = (fp4x8.s0 << 12) & 0x8000;
27
+ sign_a.hi = (fp4x8.s0 << 8) & 0x8000;
28
+ sign_b.lo = (fp4x8.s0 << 4) & 0x8000;
29
+ sign_b.hi = fp4x8.s0 & 0x8000;
30
+
31
+ fp16_packed_a_0 = sign_a + bias_a + fp16_packed_a_0;
32
+ fp16_packed_b_0 = sign_b + bias_b + fp16_packed_b_0;
33
+
34
+ ushort2 fp16_packed_a_1, fp16_packed_b_1;
35
+ fp16_packed_a_1.lo = (fp4x8.s1 << 9) & 0x0E00;
36
+ fp16_packed_a_1.hi = (fp4x8.s1 << 5) & 0x0E00;
37
+ fp16_packed_b_1.lo = (fp4x8.s1 << 1) & 0x0E00;
38
+ fp16_packed_b_1.hi = (fp4x8.s1 >> 3) & 0x0E00;
39
+
40
+ bias_a.lo = (fp16_packed_a_1.lo != 0) ? 0x3800 : 0x0;
41
+ bias_a.hi = (fp16_packed_a_1.hi != 0) ? 0x3800 : 0x0;
42
+ bias_b.lo = (fp16_packed_b_1.lo != 0) ? 0x3800 : 0x0;
43
+ bias_b.hi = (fp16_packed_b_1.hi != 0) ? 0x3800 : 0x0;
44
+
45
+ fp16_packed_a_1.lo = (fp16_packed_a_1.lo != 0x0200) ? fp16_packed_a_1.lo : 0x0;
46
+ fp16_packed_a_1.hi = (fp16_packed_a_1.hi != 0x0200) ? fp16_packed_a_1.hi : 0x0;
47
+ fp16_packed_b_1.lo = (fp16_packed_b_1.lo != 0x0200) ? fp16_packed_b_1.lo : 0x0;
48
+ fp16_packed_b_1.hi = (fp16_packed_b_1.hi != 0x0200) ? fp16_packed_b_1.hi : 0x0;
49
+
50
+ sign_a.lo = (fp4x8.s1 << 12) & 0x8000;
51
+ sign_a.hi = (fp4x8.s1 << 8) & 0x8000;
52
+ sign_b.lo = (fp4x8.s1 << 4) & 0x8000;
53
+ sign_b.hi = fp4x8.s1 & 0x8000;
54
+
55
+ fp16_packed_a_1 = sign_a + bias_a + fp16_packed_a_1;
56
+ fp16_packed_b_1 = sign_b + bias_b + fp16_packed_b_1;
57
+
58
+ return as_half8((ushort8)(fp16_packed_a_0, fp16_packed_b_0, fp16_packed_a_1, fp16_packed_b_1));
59
+ }
60
+
61
+ static inline float e8m0_to_fp32(uchar x) {
62
+ int bits;
63
+ bits = (x == 0) ? 0x00400000 : ((uint) x << 23);
64
+ return as_float(bits);
65
+ }
66
+
67
+
68
+ __attribute__((qcom_reqd_sub_group_size("half")))
69
+ __kernel void kernel_gemv_moe_mxfp4_f32(
70
+ __global uint4 * src0_q,
71
+ __global uchar * src0_e,
72
+ __read_only image1d_buffer_t src1,
73
+ __global uint * src2,
74
+ __global float * dst,
75
+ ulong offsetd,
76
+ int ne00,
77
+ int ne01,
78
+ int ne11
79
+ ) {
80
+ uint i01 = get_global_id(0);
81
+ uint i20 = get_global_id(2);
82
+ uint sgid = get_local_id(1);
83
+ uint slid = get_sub_group_local_id();
84
+
85
+ uint i11 = i20 % ne11;
86
+
87
+ uint expert_id = src2[i20];
88
+ uint expert_offset = expert_id * ne00 * ne01 / 32;
89
+
90
+ __private float sum = 0.0f; // each thread calculate partial sum of one output
91
+
92
+ // loop along ne00 in block granularity, skip 4 blocks every iter
93
+ for (uint ib00 = sgid; ib00 < (ne00 / QK_MXFP4); ib00 += N_SIMDGROUP) {
94
+
95
+ // load one block of q
96
+ uint4 regQ = src0_q[expert_offset + ib00 * ne01 + i01];
97
+
98
+ uint offset = i11 * ne00 / 4 + ib00 * 8;
99
+
100
+ half8 fp16x8 = mxfp4_to_fp16_packed8(as_ushort2(regQ.s0));
101
+
102
+ float4 shared_y4;
103
+ shared_y4 = read_imagef(src1, (offset + 0));
104
+ float4 acc = shared_y4 * (float4)(fp16x8.s0, fp16x8.s2, fp16x8.s4, fp16x8.s6);
105
+
106
+ shared_y4 = read_imagef(src1, (offset + 4));
107
+ acc += shared_y4 * (float4)(fp16x8.s1, fp16x8.s3, fp16x8.s5, fp16x8.s7);
108
+
109
+
110
+ fp16x8 = mxfp4_to_fp16_packed8(as_ushort2(regQ.s1));
111
+
112
+ shared_y4 = read_imagef(src1, (offset + 1));
113
+ acc += shared_y4 * (float4)(fp16x8.s0, fp16x8.s2, fp16x8.s4, fp16x8.s6);
114
+
115
+ shared_y4 = read_imagef(src1, (offset + 5));
116
+ acc += shared_y4 * (float4)(fp16x8.s1, fp16x8.s3, fp16x8.s5, fp16x8.s7);
117
+
118
+
119
+ fp16x8 = mxfp4_to_fp16_packed8(as_ushort2(regQ.s2));
120
+
121
+ shared_y4 = read_imagef(src1, (offset + 2));
122
+ acc += shared_y4 * (float4)(fp16x8.s0, fp16x8.s2, fp16x8.s4, fp16x8.s6);
123
+
124
+ shared_y4 = read_imagef(src1, (offset + 6));
125
+ acc += shared_y4 * (float4)(fp16x8.s1, fp16x8.s3, fp16x8.s5, fp16x8.s7);
126
+
127
+
128
+ fp16x8 = mxfp4_to_fp16_packed8(as_ushort2(regQ.s3));
129
+
130
+ shared_y4 = read_imagef(src1, (offset + 3));
131
+ acc += shared_y4 * (float4)(fp16x8.s0, fp16x8.s2, fp16x8.s4, fp16x8.s6);
132
+
133
+ shared_y4 = read_imagef(src1, (offset + 7));
134
+ acc += shared_y4 * (float4)(fp16x8.s1, fp16x8.s3, fp16x8.s5, fp16x8.s7);
135
+
136
+ uchar regE = src0_e[ib00 * ne01 + i01 + expert_offset];
137
+ sum += e8m0_to_fp32(regE) * ((acc.s0 + acc.s1) + (acc.s2 + acc.s3));
138
+ }
139
+
140
+ // reduction in local memory, assumes #subgroups=4
141
+ __local float reduceLM[SIMDGROUP_WIDTH * (N_SIMDGROUP - 1)];
142
+ if (sgid == 1) reduceLM[SIMDGROUP_WIDTH * 0 + slid] = sum;
143
+ if (sgid == 2) reduceLM[SIMDGROUP_WIDTH * 1 + slid] = sum;
144
+ if (sgid == 3) reduceLM[SIMDGROUP_WIDTH * 2 + slid] = sum;
145
+ barrier(CLK_LOCAL_MEM_FENCE);
146
+ if (sgid == 0) sum += reduceLM[SIMDGROUP_WIDTH * 0 + slid];
147
+ if (sgid == 0) sum += reduceLM[SIMDGROUP_WIDTH * 1 + slid];
148
+ if (sgid == 0) sum += reduceLM[SIMDGROUP_WIDTH * 2 + slid];
149
+
150
+ // 1 outputs per thread in subgroup 0
151
+ if (sgid == 0) {
152
+ dst = dst + (offsetd >> 2);
153
+ dst[i01 + i20 * ne01] = sum;
154
+ }
155
+
156
+ }
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemv_moe_mxfp4_f32_ns.cl ADDED
@@ -0,0 +1,257 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #pragma OPENCL EXTENSION cl_khr_fp16 : enable
2
+ #pragma OPENCL EXTENSION cl_khr_subgroups : enable
3
+ #pragma OPENCL EXTENSION cl_qcom_reqd_sub_group_size : enable
4
+
5
+ #define QK_MXFP4 32
6
+ #define N_SIMDGROUP 4
7
+ #define SIMDGROUP_WIDTH 64
8
+
9
+ static inline half8 mxfp4_to_fp16_packed8(ushort2 fp4x8) {
10
+ ushort2 fp16_packed_a_0, fp16_packed_b_0, bias_a, bias_b, sign_a, sign_b;
11
+ fp16_packed_a_0.lo = (fp4x8.s0 << 9) & 0x0E00;
12
+ fp16_packed_a_0.hi = (fp4x8.s0 << 5) & 0x0E00;
13
+ fp16_packed_b_0.lo = (fp4x8.s0 << 1) & 0x0E00;
14
+ fp16_packed_b_0.hi = (fp4x8.s0 >> 3) & 0x0E00;
15
+
16
+ bias_a.lo = (fp16_packed_a_0.lo != 0) ? 0x3800 : 0x0;
17
+ bias_a.hi = (fp16_packed_a_0.hi != 0) ? 0x3800 : 0x0;
18
+ bias_b.lo = (fp16_packed_b_0.lo != 0) ? 0x3800 : 0x0;
19
+ bias_b.hi = (fp16_packed_b_0.hi != 0) ? 0x3800 : 0x0;
20
+
21
+ fp16_packed_a_0.lo = (fp16_packed_a_0.lo != 0x0200) ? fp16_packed_a_0.lo : 0x0;
22
+ fp16_packed_a_0.hi = (fp16_packed_a_0.hi != 0x0200) ? fp16_packed_a_0.hi : 0x0;
23
+ fp16_packed_b_0.lo = (fp16_packed_b_0.lo != 0x0200) ? fp16_packed_b_0.lo : 0x0;
24
+ fp16_packed_b_0.hi = (fp16_packed_b_0.hi != 0x0200) ? fp16_packed_b_0.hi : 0x0;
25
+
26
+ sign_a.lo = (fp4x8.s0 << 12) & 0x8000;
27
+ sign_a.hi = (fp4x8.s0 << 8) & 0x8000;
28
+ sign_b.lo = (fp4x8.s0 << 4) & 0x8000;
29
+ sign_b.hi = fp4x8.s0 & 0x8000;
30
+
31
+ fp16_packed_a_0 = sign_a + bias_a + fp16_packed_a_0;
32
+ fp16_packed_b_0 = sign_b + bias_b + fp16_packed_b_0;
33
+
34
+ ushort2 fp16_packed_a_1, fp16_packed_b_1;
35
+ fp16_packed_a_1.lo = (fp4x8.s1 << 9) & 0x0E00;
36
+ fp16_packed_a_1.hi = (fp4x8.s1 << 5) & 0x0E00;
37
+ fp16_packed_b_1.lo = (fp4x8.s1 << 1) & 0x0E00;
38
+ fp16_packed_b_1.hi = (fp4x8.s1 >> 3) & 0x0E00;
39
+
40
+ bias_a.lo = (fp16_packed_a_1.lo != 0) ? 0x3800 : 0x0;
41
+ bias_a.hi = (fp16_packed_a_1.hi != 0) ? 0x3800 : 0x0;
42
+ bias_b.lo = (fp16_packed_b_1.lo != 0) ? 0x3800 : 0x0;
43
+ bias_b.hi = (fp16_packed_b_1.hi != 0) ? 0x3800 : 0x0;
44
+
45
+ fp16_packed_a_1.lo = (fp16_packed_a_1.lo != 0x0200) ? fp16_packed_a_1.lo : 0x0;
46
+ fp16_packed_a_1.hi = (fp16_packed_a_1.hi != 0x0200) ? fp16_packed_a_1.hi : 0x0;
47
+ fp16_packed_b_1.lo = (fp16_packed_b_1.lo != 0x0200) ? fp16_packed_b_1.lo : 0x0;
48
+ fp16_packed_b_1.hi = (fp16_packed_b_1.hi != 0x0200) ? fp16_packed_b_1.hi : 0x0;
49
+
50
+ sign_a.lo = (fp4x8.s1 << 12) & 0x8000;
51
+ sign_a.hi = (fp4x8.s1 << 8) & 0x8000;
52
+ sign_b.lo = (fp4x8.s1 << 4) & 0x8000;
53
+ sign_b.hi = fp4x8.s1 & 0x8000;
54
+
55
+ fp16_packed_a_1 = sign_a + bias_a + fp16_packed_a_1;
56
+ fp16_packed_b_1 = sign_b + bias_b + fp16_packed_b_1;
57
+
58
+ return as_half8((ushort8)(fp16_packed_a_0, fp16_packed_b_0, fp16_packed_a_1, fp16_packed_b_1));
59
+ }
60
+
61
+ static inline float e8m0_to_fp32(uchar x) {
62
+ int bits;
63
+ bits = (x == 0) ? 0x00400000 : ((uint) x << 23);
64
+ return as_float(bits);
65
+ }
66
+
67
+
68
+ __attribute__((qcom_reqd_sub_group_size("half")))
69
+ __kernel void kernel_gemv_moe_mxfp4_f32_ns(
70
+ __global uint * src0_q,
71
+ __global uchar * src0_e,
72
+ __read_only image1d_buffer_t src1,
73
+ __global uint * src2,
74
+ __global float * dst,
75
+ ulong offsetd,
76
+ int ne00,
77
+ int ne01,
78
+ int ne11
79
+ ) {
80
+ uint i01 = get_global_id(0);
81
+ uint i20 = get_global_id(2);
82
+ uint sgid = get_local_id(1);
83
+ uint slid = get_sub_group_local_id();
84
+
85
+ if (i01 >= ne01) {
86
+ return;
87
+ }
88
+
89
+ uint i11 = i20 % ne11;
90
+
91
+ uint expert_id = src2[i20];
92
+ uint expert_offset = expert_id * ne00 * ne01 / 32;
93
+
94
+ __private float sum = 0.0f; // each thread calculate partial sum of one output
95
+
96
+ // loop along ne00 in block granularity, skip 4 blocks every iter
97
+ for (uint ib00 = sgid; ib00 < (ne00 / QK_MXFP4); ib00 += N_SIMDGROUP) {
98
+
99
+ // load one block of q
100
+ uint4 regQ;
101
+ uint block_offset = expert_offset * 4 + ib00 * ne01 * 4 + i01;
102
+
103
+ regQ.s0 = src0_q[block_offset];
104
+ regQ.s1 = src0_q[block_offset + ne01];
105
+ regQ.s2 = src0_q[block_offset + ne01 * 2];
106
+ regQ.s3 = src0_q[block_offset + ne01 * 3];
107
+
108
+ uint offset = i11 * ne00 / 4 + ib00 * 8;
109
+
110
+ half8 fp16x8 = mxfp4_to_fp16_packed8(as_ushort2(regQ.s0));
111
+
112
+ float4 shared_y4;
113
+ shared_y4 = read_imagef(src1, (offset + 0));
114
+ float4 acc = shared_y4 * convert_float4(fp16x8.lo);
115
+
116
+ shared_y4 = read_imagef(src1, (offset + 1));
117
+ acc += shared_y4 * convert_float4(fp16x8.hi);
118
+
119
+ fp16x8 = mxfp4_to_fp16_packed8(as_ushort2(regQ.s1));
120
+
121
+ shared_y4 = read_imagef(src1, (offset + 2));
122
+ acc += shared_y4 * convert_float4(fp16x8.lo);
123
+
124
+ shared_y4 = read_imagef(src1, (offset + 3));
125
+ acc += shared_y4 * convert_float4(fp16x8.hi);
126
+
127
+
128
+ fp16x8 = mxfp4_to_fp16_packed8(as_ushort2(regQ.s2));
129
+
130
+ shared_y4 = read_imagef(src1, (offset + 4));
131
+ acc += shared_y4 * convert_float4(fp16x8.lo);
132
+
133
+ shared_y4 = read_imagef(src1, (offset + 5));
134
+ acc += shared_y4 * convert_float4(fp16x8.hi);
135
+
136
+
137
+ fp16x8 = mxfp4_to_fp16_packed8(as_ushort2(regQ.s3));
138
+
139
+ shared_y4 = read_imagef(src1, (offset + 6));
140
+ acc += shared_y4 * convert_float4(fp16x8.lo);
141
+
142
+ shared_y4 = read_imagef(src1, (offset + 7));
143
+ acc += shared_y4 * convert_float4(fp16x8.hi);
144
+
145
+ uchar regE = src0_e[ib00 * ne01 + i01 + expert_offset];
146
+ sum += e8m0_to_fp32(regE) * ((acc.s0 + acc.s1) + (acc.s2 + acc.s3));
147
+ }
148
+
149
+ // reduction in local memory, assumes #subgroups=4
150
+ __local float reduceLM[SIMDGROUP_WIDTH * (N_SIMDGROUP - 1)];
151
+ if (sgid == 1) reduceLM[SIMDGROUP_WIDTH * 0 + slid] = sum;
152
+ if (sgid == 2) reduceLM[SIMDGROUP_WIDTH * 1 + slid] = sum;
153
+ if (sgid == 3) reduceLM[SIMDGROUP_WIDTH * 2 + slid] = sum;
154
+ barrier(CLK_LOCAL_MEM_FENCE);
155
+ if (sgid == 0) sum += reduceLM[SIMDGROUP_WIDTH * 0 + slid];
156
+ if (sgid == 0) sum += reduceLM[SIMDGROUP_WIDTH * 1 + slid];
157
+ if (sgid == 0) sum += reduceLM[SIMDGROUP_WIDTH * 2 + slid];
158
+
159
+ // 1 outputs per thread in subgroup 0
160
+ if (sgid == 0) {
161
+ dst = dst + (offsetd >> 2);
162
+ dst[i01 + i20 * ne01] = sum;
163
+ }
164
+
165
+ }
166
+
167
+ __attribute__((qcom_reqd_sub_group_size("half")))
168
+ __kernel void kernel_gemv_moe_mxfp4_f32_ns_wimg(
169
+ __read_only image1d_buffer_t src0_q,
170
+ __global uchar * src0_e,
171
+ __read_only image1d_buffer_t src1,
172
+ __global uint * src2,
173
+ __global float * dst,
174
+ ulong offsetd,
175
+ int ne00,
176
+ int ne01,
177
+ int ne11
178
+ ) {
179
+ uint i01 = get_global_id(0);
180
+ uint i20 = get_global_id(2);
181
+ uint sgid = get_local_id(1);
182
+ uint slid = get_sub_group_local_id();
183
+
184
+ if (i01 >= ne01) {
185
+ return;
186
+ }
187
+
188
+ uint i11 = i20 % ne11;
189
+
190
+ uint expert_id = src2[i20];
191
+ uint expert_offset = expert_id * ne00 * ne01 / 32;
192
+
193
+ __private float sum = 0.0f;
194
+
195
+ for (uint ib00 = sgid; ib00 < (ne00 / QK_MXFP4); ib00 += N_SIMDGROUP) {
196
+
197
+ uint4 regQ;
198
+ uint block_offset = expert_offset * 4 + ib00 * ne01 * 4 + i01;
199
+
200
+ regQ.s0 = read_imageui(src0_q, (int)(block_offset)).x;
201
+ regQ.s1 = read_imageui(src0_q, (int)(block_offset + ne01)).x;
202
+ regQ.s2 = read_imageui(src0_q, (int)(block_offset + ne01 * 2)).x;
203
+ regQ.s3 = read_imageui(src0_q, (int)(block_offset + ne01 * 3)).x;
204
+
205
+ uint offset = i11 * ne00 / 4 + ib00 * 8;
206
+
207
+ half8 fp16x8 = mxfp4_to_fp16_packed8(as_ushort2(regQ.s0));
208
+
209
+ float4 shared_y4;
210
+ shared_y4 = read_imagef(src1, (offset + 0));
211
+ float4 acc = shared_y4 * convert_float4(fp16x8.lo);
212
+
213
+ shared_y4 = read_imagef(src1, (offset + 1));
214
+ acc += shared_y4 * convert_float4(fp16x8.hi);
215
+
216
+ fp16x8 = mxfp4_to_fp16_packed8(as_ushort2(regQ.s1));
217
+
218
+ shared_y4 = read_imagef(src1, (offset + 2));
219
+ acc += shared_y4 * convert_float4(fp16x8.lo);
220
+
221
+ shared_y4 = read_imagef(src1, (offset + 3));
222
+ acc += shared_y4 * convert_float4(fp16x8.hi);
223
+
224
+ fp16x8 = mxfp4_to_fp16_packed8(as_ushort2(regQ.s2));
225
+
226
+ shared_y4 = read_imagef(src1, (offset + 4));
227
+ acc += shared_y4 * convert_float4(fp16x8.lo);
228
+
229
+ shared_y4 = read_imagef(src1, (offset + 5));
230
+ acc += shared_y4 * convert_float4(fp16x8.hi);
231
+
232
+ fp16x8 = mxfp4_to_fp16_packed8(as_ushort2(regQ.s3));
233
+
234
+ shared_y4 = read_imagef(src1, (offset + 6));
235
+ acc += shared_y4 * convert_float4(fp16x8.lo);
236
+
237
+ shared_y4 = read_imagef(src1, (offset + 7));
238
+ acc += shared_y4 * convert_float4(fp16x8.hi);
239
+
240
+ uchar regE = src0_e[ib00 * ne01 + i01 + expert_offset];
241
+ sum += e8m0_to_fp32(regE) * ((acc.s0 + acc.s1) + (acc.s2 + acc.s3));
242
+ }
243
+
244
+ __local float reduceLM[SIMDGROUP_WIDTH * (N_SIMDGROUP - 1)];
245
+ if (sgid == 1) reduceLM[SIMDGROUP_WIDTH * 0 + slid] = sum;
246
+ if (sgid == 2) reduceLM[SIMDGROUP_WIDTH * 1 + slid] = sum;
247
+ if (sgid == 3) reduceLM[SIMDGROUP_WIDTH * 2 + slid] = sum;
248
+ barrier(CLK_LOCAL_MEM_FENCE);
249
+ if (sgid == 0) sum += reduceLM[SIMDGROUP_WIDTH * 0 + slid];
250
+ if (sgid == 0) sum += reduceLM[SIMDGROUP_WIDTH * 1 + slid];
251
+ if (sgid == 0) sum += reduceLM[SIMDGROUP_WIDTH * 2 + slid];
252
+
253
+ if (sgid == 0) {
254
+ dst = dst + (offsetd >> 2);
255
+ dst[i01 + i20 * ne01] = sum;
256
+ }
257
+ }
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemv_moe_q4_0_f32_ns.cl ADDED
@@ -0,0 +1,120 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #pragma OPENCL EXTENSION cl_khr_fp16 : enable
2
+ #pragma OPENCL EXTENSION cl_khr_subgroups : enable
3
+ #pragma OPENCL EXTENSION cl_qcom_reqd_sub_group_size : enable
4
+
5
+ #define QK_Q4_0 32
6
+ #define N_SIMDGROUP 4
7
+ #define SIMDGROUP_WIDTH 64
8
+
9
+ static inline float8 q4_0_to_fp32_packed8(ushort2 q4x8) {
10
+ float8 fp32x8;
11
+ fp32x8.s0 = (float)((q4x8.s0 & 0x000F) - 8);
12
+ fp32x8.s1 = (float)(((q4x8.s0 & 0x00F0) >> 4) - 8);
13
+ fp32x8.s2 = (float)(((q4x8.s0 & 0x0F00) >> 8) - 8);
14
+ fp32x8.s3 = (float)(((q4x8.s0 & 0xF000) >> 12) - 8);
15
+ fp32x8.s4 = (float)((q4x8.s1 & 0x000F) - 8);
16
+ fp32x8.s5 = (float)(((q4x8.s1 & 0x00F0) >> 4) - 8);
17
+ fp32x8.s6 = (float)(((q4x8.s1 & 0x0F00) >> 8) - 8);
18
+ fp32x8.s7 = (float)(((q4x8.s1 & 0xF000) >> 12) - 8);
19
+ return fp32x8;
20
+ }
21
+
22
+
23
+ __attribute__((qcom_reqd_sub_group_size("half")))
24
+ __kernel void kernel_gemv_moe_q4_0_f32_ns(
25
+ __global uint * src0_q,
26
+ __global half * src0_d,
27
+ __read_only image1d_buffer_t src1,
28
+ __global uint * src2,
29
+ __global float * dst,
30
+ ulong offsetd,
31
+ int ne00,
32
+ int ne01,
33
+ int ne11
34
+ ) {
35
+ uint i01 = get_global_id(0);
36
+ uint i20 = get_global_id(2);
37
+ uint sgid = get_local_id(1);
38
+ uint slid = get_sub_group_local_id();
39
+
40
+ if (i01 >= ne01) {
41
+ return;
42
+ }
43
+
44
+ uint i11 = i20 % ne11;
45
+
46
+ uint expert_id = src2[i20];
47
+ uint expert_offset = expert_id * ne00 * ne01 / 32;
48
+
49
+ __private float sum = 0.0f; // each thread calculate partial sum of one output
50
+
51
+ // loop along ne00 in block granularity, skip 4 blocks every iter
52
+ for (uint ib00 = sgid; ib00 < (ne00 / QK_Q4_0); ib00 += N_SIMDGROUP) {
53
+
54
+ // load one block of q
55
+ uint4 regQ;
56
+ uint block_offset = expert_offset * 4 + ib00 * ne01 * 4 + i01;
57
+
58
+ regQ.s0 = src0_q[block_offset];
59
+ regQ.s1 = src0_q[block_offset + ne01];
60
+ regQ.s2 = src0_q[block_offset + ne01 * 2];
61
+ regQ.s3 = src0_q[block_offset + ne01 * 3];
62
+
63
+ uint offset = i11 * ne00 / 4 + ib00 * 8;
64
+
65
+ float8 fp32x8 = q4_0_to_fp32_packed8(as_ushort2(regQ.s0));
66
+
67
+ float4 shared_y4;
68
+ shared_y4 = read_imagef(src1, (offset + 0));
69
+ float4 acc = shared_y4 * fp32x8.lo;
70
+
71
+ shared_y4 = read_imagef(src1, (offset + 1));
72
+ acc += shared_y4 * fp32x8.hi;
73
+
74
+ fp32x8 = q4_0_to_fp32_packed8(as_ushort2(regQ.s1));
75
+
76
+ shared_y4 = read_imagef(src1, (offset + 2));
77
+ acc += shared_y4 * fp32x8.lo;
78
+
79
+ shared_y4 = read_imagef(src1, (offset + 3));
80
+ acc += shared_y4 * fp32x8.hi;
81
+
82
+
83
+ fp32x8 = q4_0_to_fp32_packed8(as_ushort2(regQ.s2));
84
+
85
+ shared_y4 = read_imagef(src1, (offset + 4));
86
+ acc += shared_y4 * fp32x8.lo;
87
+
88
+ shared_y4 = read_imagef(src1, (offset + 5));
89
+ acc += shared_y4 * fp32x8.hi;
90
+
91
+
92
+ fp32x8 = q4_0_to_fp32_packed8(as_ushort2(regQ.s3));
93
+
94
+ shared_y4 = read_imagef(src1, (offset + 6));
95
+ acc += shared_y4 * fp32x8.lo;
96
+
97
+ shared_y4 = read_imagef(src1, (offset + 7));
98
+ acc += shared_y4 * fp32x8.hi;
99
+
100
+ half regS = src0_d[ib00 * ne01 + i01 + expert_offset];
101
+ sum += (float)(regS) * ((acc.s0 + acc.s1) + (acc.s2 + acc.s3));
102
+ }
103
+
104
+ // reduction in local memory, assumes #subgroups=4
105
+ __local float reduceLM[SIMDGROUP_WIDTH * (N_SIMDGROUP - 1)];
106
+ if (sgid == 1) reduceLM[SIMDGROUP_WIDTH * 0 + slid] = sum;
107
+ if (sgid == 2) reduceLM[SIMDGROUP_WIDTH * 1 + slid] = sum;
108
+ if (sgid == 3) reduceLM[SIMDGROUP_WIDTH * 2 + slid] = sum;
109
+ barrier(CLK_LOCAL_MEM_FENCE);
110
+ if (sgid == 0) sum += reduceLM[SIMDGROUP_WIDTH * 0 + slid];
111
+ if (sgid == 0) sum += reduceLM[SIMDGROUP_WIDTH * 1 + slid];
112
+ if (sgid == 0) sum += reduceLM[SIMDGROUP_WIDTH * 2 + slid];
113
+
114
+ // 1 outputs per thread in subgroup 0
115
+ if (sgid == 0) {
116
+ dst = dst + (offsetd >> 2);
117
+ dst[i01 + i20 * ne01] = sum;
118
+ }
119
+
120
+ }
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemv_moe_q4_1_f32_ns.cl ADDED
@@ -0,0 +1,123 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #pragma OPENCL EXTENSION cl_khr_fp16 : enable
2
+ #pragma OPENCL EXTENSION cl_khr_subgroups : enable
3
+ #pragma OPENCL EXTENSION cl_qcom_reqd_sub_group_size : enable
4
+
5
+ #define QK_Q4_1 32
6
+ #define N_SIMDGROUP 4
7
+ #define SIMDGROUP_WIDTH 64
8
+
9
+ static inline float8 q4_1_to_fp32_packed8(ushort2 q4x8, half s, half m) {
10
+ float8 fp32x8;
11
+ fp32x8.s0 = (float)((q4x8.s0 & 0x000F) * s + m);
12
+ fp32x8.s1 = (float)(((q4x8.s0 & 0x00F0) >> 4) * s + m);
13
+ fp32x8.s2 = (float)(((q4x8.s0 & 0x0F00) >> 8) * s + m);
14
+ fp32x8.s3 = (float)(((q4x8.s0 & 0xF000) >> 12) * s + m);
15
+ fp32x8.s4 = (float)((q4x8.s1 & 0x000F) * s + m);
16
+ fp32x8.s5 = (float)(((q4x8.s1 & 0x00F0) >> 4) * s + m);
17
+ fp32x8.s6 = (float)(((q4x8.s1 & 0x0F00) >> 8) * s + m);
18
+ fp32x8.s7 = (float)(((q4x8.s1 & 0xF000) >> 12) * s + m);
19
+ return fp32x8;
20
+ }
21
+
22
+
23
+ __attribute__((qcom_reqd_sub_group_size("half")))
24
+ __kernel void kernel_gemv_moe_q4_1_f32_ns(
25
+ __global uint * src0_q,
26
+ __global half * src0_d,
27
+ __global half * src0_m,
28
+ __read_only image1d_buffer_t src1,
29
+ __global uint * src2,
30
+ __global float * dst,
31
+ ulong offsetd,
32
+ int ne00,
33
+ int ne01,
34
+ int ne11
35
+ ) {
36
+ uint i01 = get_global_id(0);
37
+ uint i20 = get_global_id(2);
38
+ uint sgid = get_local_id(1);
39
+ uint slid = get_sub_group_local_id();
40
+
41
+ if (i01 >= ne01) {
42
+ return;
43
+ }
44
+
45
+ uint i11 = i20 % ne11;
46
+
47
+ uint expert_id = src2[i20];
48
+ uint expert_offset = expert_id * ne00 * ne01 / 32;
49
+
50
+ __private float sum = 0.0f; // each thread calculate partial sum of one output
51
+
52
+ // loop along ne00 in block granularity, skip 4 blocks every iter
53
+ for (uint ib00 = sgid; ib00 < (ne00 / QK_Q4_1); ib00 += N_SIMDGROUP) {
54
+
55
+ // load one block of q
56
+ uint4 regQ;
57
+ uint block_offset = expert_offset * 4 + ib00 * ne01 * 4 + i01;
58
+
59
+ regQ.s0 = src0_q[block_offset];
60
+ regQ.s1 = src0_q[block_offset + ne01];
61
+ regQ.s2 = src0_q[block_offset + ne01 * 2];
62
+ regQ.s3 = src0_q[block_offset + ne01 * 3];
63
+
64
+ uint offset = i11 * ne00 / 4 + ib00 * 8;
65
+
66
+ half regM = src0_m[ib00 * ne01 + i01 + expert_offset];
67
+ half regS = src0_d[ib00 * ne01 + i01 + expert_offset];
68
+
69
+ float8 fp32x8 = q4_1_to_fp32_packed8(as_ushort2(regQ.s0), regS, regM);
70
+
71
+ float4 shared_y4;
72
+ shared_y4 = read_imagef(src1, (offset + 0));
73
+ float4 acc = shared_y4 * fp32x8.lo;
74
+
75
+ shared_y4 = read_imagef(src1, (offset + 1));
76
+ acc += shared_y4 * fp32x8.hi;
77
+
78
+ fp32x8 = q4_1_to_fp32_packed8(as_ushort2(regQ.s1), regS, regM);
79
+
80
+ shared_y4 = read_imagef(src1, (offset + 2));
81
+ acc += shared_y4 * fp32x8.lo;
82
+
83
+ shared_y4 = read_imagef(src1, (offset + 3));
84
+ acc += shared_y4 * fp32x8.hi;
85
+
86
+
87
+ fp32x8 = q4_1_to_fp32_packed8(as_ushort2(regQ.s2), regS, regM);
88
+
89
+ shared_y4 = read_imagef(src1, (offset + 4));
90
+ acc += shared_y4 * fp32x8.lo;
91
+
92
+ shared_y4 = read_imagef(src1, (offset + 5));
93
+ acc += shared_y4 * fp32x8.hi;
94
+
95
+
96
+ fp32x8 = q4_1_to_fp32_packed8(as_ushort2(regQ.s3), regS, regM);
97
+
98
+ shared_y4 = read_imagef(src1, (offset + 6));
99
+ acc += shared_y4 * fp32x8.lo;
100
+
101
+ shared_y4 = read_imagef(src1, (offset + 7));
102
+ acc += shared_y4 * fp32x8.hi;
103
+
104
+ sum += ((acc.s0 + acc.s1) + (acc.s2 + acc.s3));
105
+ }
106
+
107
+ // reduction in local memory, assumes #subgroups=4
108
+ __local float reduceLM[SIMDGROUP_WIDTH * (N_SIMDGROUP - 1)];
109
+ if (sgid == 1) reduceLM[SIMDGROUP_WIDTH * 0 + slid] = sum;
110
+ if (sgid == 2) reduceLM[SIMDGROUP_WIDTH * 1 + slid] = sum;
111
+ if (sgid == 3) reduceLM[SIMDGROUP_WIDTH * 2 + slid] = sum;
112
+ barrier(CLK_LOCAL_MEM_FENCE);
113
+ if (sgid == 0) sum += reduceLM[SIMDGROUP_WIDTH * 0 + slid];
114
+ if (sgid == 0) sum += reduceLM[SIMDGROUP_WIDTH * 1 + slid];
115
+ if (sgid == 0) sum += reduceLM[SIMDGROUP_WIDTH * 2 + slid];
116
+
117
+ // 1 outputs per thread in subgroup 0
118
+ if (sgid == 0) {
119
+ dst = dst + (offsetd >> 2);
120
+ dst[i01 + i20 * ne01] = sum;
121
+ }
122
+
123
+ }
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemv_moe_q4_k_f32_ns.cl ADDED
@@ -0,0 +1,266 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #pragma OPENCL EXTENSION cl_khr_fp16 : enable
2
+ #pragma OPENCL EXTENSION cl_khr_subgroups : enable
3
+ #pragma OPENCL EXTENSION cl_qcom_reqd_sub_group_size : enable
4
+
5
+ #define QK_K 256
6
+ #define K_SCALE_SIZE 12
7
+ #define N_SIMDGROUP 4
8
+ #define SIMDGROUP_WIDTH 64
9
+
10
+ inline void get_scale_min_k4(
11
+ int j,
12
+ global const uchar * q,
13
+ uchar * d,
14
+ uchar * m
15
+ ) {
16
+ if (j < 4) {
17
+ *d = q[j] & 63;
18
+ *m = q[j+4] & 63;
19
+ } else {
20
+ *d = (q[j+4] & 0x0F) | ((q[j-4] & 0xC0) >> 2);
21
+ *m = ((q[j+4] >> 4) & 0x0F) | ((q[j] & 0xC0) >> 2);
22
+ }
23
+ }
24
+
25
+ static inline float8 q4_k_to_fp32_packed8(ushort2 q4x8, float scale, float minv) {
26
+ float8 fp32x8;
27
+ fp32x8.s0 = (q4x8.s0 & 0x000F) * scale - minv;
28
+ fp32x8.s1 = ((q4x8.s0 & 0x00F0) >> 4) * scale - minv;
29
+ fp32x8.s2 = ((q4x8.s0 & 0x0F00) >> 8) * scale - minv;
30
+ fp32x8.s3 = ((q4x8.s0 & 0xF000) >> 12) * scale - minv;
31
+ fp32x8.s4 = (q4x8.s1 & 0x000F) * scale - minv;
32
+ fp32x8.s5 = ((q4x8.s1 & 0x00F0) >> 4) * scale - minv;
33
+ fp32x8.s6 = ((q4x8.s1 & 0x0F00) >> 8) * scale - minv;
34
+ fp32x8.s7 = ((q4x8.s1 & 0xF000) >> 12) * scale - minv;
35
+ return fp32x8;
36
+ }
37
+
38
+ __attribute__((qcom_reqd_sub_group_size("half")))
39
+ __kernel void kernel_gemv_moe_q4_k_f32_ns(
40
+ __global uint * src0_q,
41
+ __global half * src0_d,
42
+ __global half * src0_dm,
43
+ __global uchar * src0_s,
44
+ __read_only image1d_buffer_t src1,
45
+ __global uint * src2,
46
+ __global float * dst,
47
+ ulong offsetd,
48
+ int ne00,
49
+ int ne01,
50
+ int ne11
51
+ ) {
52
+ uint i01 = get_global_id(0);
53
+ uint i20 = get_global_id(2);
54
+ uint sgid = get_local_id(1);
55
+ uint slid = get_sub_group_local_id();
56
+
57
+ if (i01 >= ne01) {
58
+ return;
59
+ }
60
+
61
+ uint i11 = i20 % ne11;
62
+
63
+ uint expert_id = src2[i20];
64
+
65
+ int num_superblocks = ne00 / QK_K;
66
+ int num_subblocks = ne00 / 32;
67
+ int scales_per_row = num_superblocks * K_SCALE_SIZE;
68
+
69
+ // Expert offsets in the transposed noshuffle layout
70
+ uint expert_q_offset = expert_id * (ne00 / 8) * ne01;
71
+ uint expert_d_offset = expert_id * num_superblocks * ne01;
72
+
73
+ __private float sum = 0.0f;
74
+
75
+ // Loop over sub-blocks of 32 elements, N_SIMDGROUP sub-blocks per iter
76
+ for (uint ib = sgid; ib < num_subblocks; ib += N_SIMDGROUP) {
77
+ uint sb = ib / 8;
78
+ uint j = ib % 8;
79
+
80
+ // Load d and dmin for this super-block
81
+ half d_val = src0_d[expert_d_offset + sb * ne01 + i01];
82
+ half dm_val = src0_dm[expert_d_offset + sb * ne01 + i01];
83
+
84
+ // Load sub-block scale and min
85
+ global const uchar * sc = src0_s + (expert_id * ne01 + i01) * scales_per_row + sb * K_SCALE_SIZE;
86
+ uchar sv, mn;
87
+ get_scale_min_k4(j, sc, &sv, &mn);
88
+
89
+ float scale = (float)d_val * (float)sv;
90
+ float minv = (float)dm_val * (float)mn;
91
+
92
+ // Load 4 uints of quants (32 nibbles = 32 elements)
93
+ uint q_base = expert_q_offset + ib * ne01 * 4 + i01;
94
+
95
+ uint4 regQ;
96
+ regQ.s0 = src0_q[q_base];
97
+ regQ.s1 = src0_q[q_base + ne01];
98
+ regQ.s2 = src0_q[q_base + ne01 * 2];
99
+ regQ.s3 = src0_q[q_base + ne01 * 3];
100
+
101
+ // Load activations: 32 floats = 8 float4s
102
+ uint y_offset = i11 * ne00 / 4 + ib * 8;
103
+
104
+ float8 fp32x8 = q4_k_to_fp32_packed8(as_ushort2(regQ.s0), scale, minv);
105
+
106
+ float4 shared_y4;
107
+ shared_y4 = read_imagef(src1, (y_offset + 0));
108
+ float4 acc = shared_y4 * fp32x8.lo;
109
+
110
+ shared_y4 = read_imagef(src1, (y_offset + 1));
111
+ acc += shared_y4 * fp32x8.hi;
112
+
113
+ fp32x8 = q4_k_to_fp32_packed8(as_ushort2(regQ.s1), scale, minv);
114
+
115
+ shared_y4 = read_imagef(src1, (y_offset + 2));
116
+ acc += shared_y4 * fp32x8.lo;
117
+
118
+ shared_y4 = read_imagef(src1, (y_offset + 3));
119
+ acc += shared_y4 * fp32x8.hi;
120
+
121
+ fp32x8 = q4_k_to_fp32_packed8(as_ushort2(regQ.s2), scale, minv);
122
+
123
+ shared_y4 = read_imagef(src1, (y_offset + 4));
124
+ acc += shared_y4 * fp32x8.lo;
125
+
126
+ shared_y4 = read_imagef(src1, (y_offset + 5));
127
+ acc += shared_y4 * fp32x8.hi;
128
+
129
+ fp32x8 = q4_k_to_fp32_packed8(as_ushort2(regQ.s3), scale, minv);
130
+
131
+ shared_y4 = read_imagef(src1, (y_offset + 6));
132
+ acc += shared_y4 * fp32x8.lo;
133
+
134
+ shared_y4 = read_imagef(src1, (y_offset + 7));
135
+ acc += shared_y4 * fp32x8.hi;
136
+
137
+ sum += ((acc.s0 + acc.s1) + (acc.s2 + acc.s3));
138
+ }
139
+
140
+ // reduction in local memory, assumes #subgroups=4
141
+ __local float reduceLM[SIMDGROUP_WIDTH * (N_SIMDGROUP - 1)];
142
+ if (sgid == 1) reduceLM[SIMDGROUP_WIDTH * 0 + slid] = sum;
143
+ if (sgid == 2) reduceLM[SIMDGROUP_WIDTH * 1 + slid] = sum;
144
+ if (sgid == 3) reduceLM[SIMDGROUP_WIDTH * 2 + slid] = sum;
145
+ barrier(CLK_LOCAL_MEM_FENCE);
146
+ if (sgid == 0) sum += reduceLM[SIMDGROUP_WIDTH * 0 + slid];
147
+ if (sgid == 0) sum += reduceLM[SIMDGROUP_WIDTH * 1 + slid];
148
+ if (sgid == 0) sum += reduceLM[SIMDGROUP_WIDTH * 2 + slid];
149
+
150
+ // 1 output per thread in subgroup 0
151
+ if (sgid == 0) {
152
+ dst = dst + (offsetd >> 2);
153
+ dst[i01 + i20 * ne01] = sum;
154
+ }
155
+ }
156
+
157
+ __attribute__((qcom_reqd_sub_group_size("half")))
158
+ __kernel void kernel_gemv_moe_q4_k_f32_ns_wimg(
159
+ __read_only image1d_buffer_t src0_q,
160
+ __global half * src0_d,
161
+ __global half * src0_dm,
162
+ __global uchar * src0_s,
163
+ __read_only image1d_buffer_t src1,
164
+ __global uint * src2,
165
+ __global float * dst,
166
+ ulong offsetd,
167
+ int ne00,
168
+ int ne01,
169
+ int ne11
170
+ ) {
171
+ uint i01 = get_global_id(0);
172
+ uint i20 = get_global_id(2);
173
+ uint sgid = get_local_id(1);
174
+ uint slid = get_sub_group_local_id();
175
+
176
+ if (i01 >= ne01) {
177
+ return;
178
+ }
179
+
180
+ uint i11 = i20 % ne11;
181
+
182
+ uint expert_id = src2[i20];
183
+
184
+ int num_superblocks = ne00 / QK_K;
185
+ int num_subblocks = ne00 / 32;
186
+ int scales_per_row = num_superblocks * K_SCALE_SIZE;
187
+
188
+ uint expert_q_offset = expert_id * (ne00 / 8) * ne01;
189
+ uint expert_d_offset = expert_id * num_superblocks * ne01;
190
+
191
+ __private float sum = 0.0f;
192
+
193
+ for (uint ib = sgid; ib < num_subblocks; ib += N_SIMDGROUP) {
194
+ uint sb = ib / 8;
195
+ uint j = ib % 8;
196
+
197
+ half d_val = src0_d[expert_d_offset + sb * ne01 + i01];
198
+ half dm_val = src0_dm[expert_d_offset + sb * ne01 + i01];
199
+
200
+ global const uchar * sc = src0_s + (expert_id * ne01 + i01) * scales_per_row + sb * K_SCALE_SIZE;
201
+ uchar sv, mn;
202
+ get_scale_min_k4(j, sc, &sv, &mn);
203
+
204
+ float scale = (float)d_val * (float)sv;
205
+ float minv = (float)dm_val * (float)mn;
206
+
207
+ uint q_base = expert_q_offset + ib * ne01 * 4 + i01;
208
+
209
+ uint4 regQ;
210
+ regQ.s0 = read_imageui(src0_q, (int)(q_base)).x;
211
+ regQ.s1 = read_imageui(src0_q, (int)(q_base + ne01)).x;
212
+ regQ.s2 = read_imageui(src0_q, (int)(q_base + ne01 * 2)).x;
213
+ regQ.s3 = read_imageui(src0_q, (int)(q_base + ne01 * 3)).x;
214
+
215
+ uint y_offset = i11 * ne00 / 4 + ib * 8;
216
+
217
+ float8 fp32x8 = q4_k_to_fp32_packed8(as_ushort2(regQ.s0), scale, minv);
218
+
219
+ float4 shared_y4;
220
+ shared_y4 = read_imagef(src1, (y_offset + 0));
221
+ float4 acc = shared_y4 * fp32x8.lo;
222
+
223
+ shared_y4 = read_imagef(src1, (y_offset + 1));
224
+ acc += shared_y4 * fp32x8.hi;
225
+
226
+ fp32x8 = q4_k_to_fp32_packed8(as_ushort2(regQ.s1), scale, minv);
227
+
228
+ shared_y4 = read_imagef(src1, (y_offset + 2));
229
+ acc += shared_y4 * fp32x8.lo;
230
+
231
+ shared_y4 = read_imagef(src1, (y_offset + 3));
232
+ acc += shared_y4 * fp32x8.hi;
233
+
234
+ fp32x8 = q4_k_to_fp32_packed8(as_ushort2(regQ.s2), scale, minv);
235
+
236
+ shared_y4 = read_imagef(src1, (y_offset + 4));
237
+ acc += shared_y4 * fp32x8.lo;
238
+
239
+ shared_y4 = read_imagef(src1, (y_offset + 5));
240
+ acc += shared_y4 * fp32x8.hi;
241
+
242
+ fp32x8 = q4_k_to_fp32_packed8(as_ushort2(regQ.s3), scale, minv);
243
+
244
+ shared_y4 = read_imagef(src1, (y_offset + 6));
245
+ acc += shared_y4 * fp32x8.lo;
246
+
247
+ shared_y4 = read_imagef(src1, (y_offset + 7));
248
+ acc += shared_y4 * fp32x8.hi;
249
+
250
+ sum += ((acc.s0 + acc.s1) + (acc.s2 + acc.s3));
251
+ }
252
+
253
+ __local float reduceLM[SIMDGROUP_WIDTH * (N_SIMDGROUP - 1)];
254
+ if (sgid == 1) reduceLM[SIMDGROUP_WIDTH * 0 + slid] = sum;
255
+ if (sgid == 2) reduceLM[SIMDGROUP_WIDTH * 1 + slid] = sum;
256
+ if (sgid == 3) reduceLM[SIMDGROUP_WIDTH * 2 + slid] = sum;
257
+ barrier(CLK_LOCAL_MEM_FENCE);
258
+ if (sgid == 0) sum += reduceLM[SIMDGROUP_WIDTH * 0 + slid];
259
+ if (sgid == 0) sum += reduceLM[SIMDGROUP_WIDTH * 1 + slid];
260
+ if (sgid == 0) sum += reduceLM[SIMDGROUP_WIDTH * 2 + slid];
261
+
262
+ if (sgid == 0) {
263
+ dst = dst + (offsetd >> 2);
264
+ dst[i01 + i20 * ne01] = sum;
265
+ }
266
+ }
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemv_moe_q5_0_f32_ns.cl ADDED
@@ -0,0 +1,123 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #pragma OPENCL EXTENSION cl_khr_fp16 : enable
2
+ #pragma OPENCL EXTENSION cl_khr_subgroups : enable
3
+ #pragma OPENCL EXTENSION cl_qcom_reqd_sub_group_size : enable
4
+
5
+ #define QK_Q5_0 32
6
+ #define N_SIMDGROUP 4
7
+ #define SIMDGROUP_WIDTH 64
8
+
9
+ static inline float8 q5_0_to_fp32_packed8(ushort2 qs5x8, uchar qh5x8) {
10
+ float8 fp32x8;
11
+ fp32x8.s0 = (float)((( qs5x8.s0 & 0x000F) | (( qh5x8 & 0x01) << 4)) - 16);
12
+ fp32x8.s1 = (float)((((qs5x8.s0 & 0x00F0) >> 4 ) | (((qh5x8 >> 1) & 0x01) << 4)) - 16);
13
+ fp32x8.s2 = (float)((((qs5x8.s0 & 0x0F00) >> 8 ) | (((qh5x8 >> 2) & 0x01) << 4)) - 16);
14
+ fp32x8.s3 = (float)((((qs5x8.s0 & 0xF000) >> 12) | (((qh5x8 >> 3) & 0x01) << 4)) - 16);
15
+ fp32x8.s4 = (float)((( qs5x8.s1 & 0x000F) | (((qh5x8 >> 4) & 0x01) << 4)) - 16);
16
+ fp32x8.s5 = (float)((((qs5x8.s1 & 0x00F0) >> 4 ) | (((qh5x8 >> 5) & 0x01) << 4)) - 16);
17
+ fp32x8.s6 = (float)((((qs5x8.s1 & 0x0F00) >> 8 ) | (((qh5x8 >> 6) & 0x01) << 4)) - 16);
18
+ fp32x8.s7 = (float)((((qs5x8.s1 & 0xF000) >> 12) | (((qh5x8 >> 7) & 0x01) << 4)) - 16);
19
+ return fp32x8;
20
+ }
21
+
22
+
23
+ __attribute__((qcom_reqd_sub_group_size("half")))
24
+ __kernel void kernel_gemv_moe_q5_0_f32_ns(
25
+ __global uint * src0_qs,
26
+ __global uint * src0_qh,
27
+ __global half * src0_d,
28
+ __read_only image1d_buffer_t src1,
29
+ __global uint * src2,
30
+ __global float * dst,
31
+ ulong offsetd,
32
+ uint ne00,
33
+ uint ne01,
34
+ uint ne11
35
+ ) {
36
+ uint i01 = get_global_id(0);
37
+ uint i20 = get_global_id(2);
38
+ uint sgid = get_local_id(1);
39
+ uint slid = get_sub_group_local_id();
40
+
41
+ if (i01 >= ne01) {
42
+ return;
43
+ }
44
+
45
+ uint i11 = i20 % ne11;
46
+
47
+ uint expert_id = src2[i20];
48
+ uint expert_offset = expert_id * ne00 * ne01 / 32;
49
+
50
+ __private float sum = 0.0f; // each thread calculate partial sum of one output
51
+
52
+ // loop along ne00 in block granularity, skip 4 blocks every iter
53
+ for (uint ib00 = sgid; ib00 < (ne00 / QK_Q5_0); ib00 += N_SIMDGROUP) {
54
+
55
+ // load one block of q
56
+ uint4 regQ;
57
+ uint block_offset = expert_offset * 4 + ib00 * ne01 * 4 + i01;
58
+
59
+ regQ.s0 = src0_qs[block_offset];
60
+ regQ.s1 = src0_qs[block_offset + ne01];
61
+ regQ.s2 = src0_qs[block_offset + ne01 * 2];
62
+ regQ.s3 = src0_qs[block_offset + ne01 * 3];
63
+
64
+ uint offset = i11 * ne00 / 4 + ib00 * 8;
65
+
66
+ uchar4 regQh = as_uchar4(src0_qh[ib00 * ne01 + i01 + expert_offset]);
67
+ half regS = src0_d[ib00 * ne01 + i01 + expert_offset];
68
+
69
+ float8 fp32x8 = q5_0_to_fp32_packed8(as_ushort2(regQ.s0), regQh.s0);
70
+
71
+ float4 shared_y4;
72
+ shared_y4 = read_imagef(src1, (offset + 0));
73
+ float4 acc = shared_y4 * fp32x8.lo;
74
+
75
+ shared_y4 = read_imagef(src1, (offset + 1));
76
+ acc += shared_y4 * fp32x8.hi;
77
+
78
+ fp32x8 = q5_0_to_fp32_packed8(as_ushort2(regQ.s1), regQh.s1);
79
+
80
+ shared_y4 = read_imagef(src1, (offset + 2));
81
+ acc += shared_y4 * fp32x8.lo;
82
+
83
+ shared_y4 = read_imagef(src1, (offset + 3));
84
+ acc += shared_y4 * fp32x8.hi;
85
+
86
+
87
+ fp32x8 = q5_0_to_fp32_packed8(as_ushort2(regQ.s2), regQh.s2);
88
+
89
+ shared_y4 = read_imagef(src1, (offset + 4));
90
+ acc += shared_y4 * fp32x8.lo;
91
+
92
+ shared_y4 = read_imagef(src1, (offset + 5));
93
+ acc += shared_y4 * fp32x8.hi;
94
+
95
+
96
+ fp32x8 = q5_0_to_fp32_packed8(as_ushort2(regQ.s3), regQh.s3);
97
+
98
+ shared_y4 = read_imagef(src1, (offset + 6));
99
+ acc += shared_y4 * fp32x8.lo;
100
+
101
+ shared_y4 = read_imagef(src1, (offset + 7));
102
+ acc += shared_y4 * fp32x8.hi;
103
+
104
+ sum += (float)(regS) * ((acc.s0 + acc.s1) + (acc.s2 + acc.s3));
105
+ }
106
+
107
+ // reduction in local memory, assumes #subgroups=4
108
+ __local float reduceLM[SIMDGROUP_WIDTH * (N_SIMDGROUP - 1)];
109
+ if (sgid == 1) reduceLM[SIMDGROUP_WIDTH * 0 + slid] = sum;
110
+ if (sgid == 2) reduceLM[SIMDGROUP_WIDTH * 1 + slid] = sum;
111
+ if (sgid == 3) reduceLM[SIMDGROUP_WIDTH * 2 + slid] = sum;
112
+ barrier(CLK_LOCAL_MEM_FENCE);
113
+ if (sgid == 0) sum += reduceLM[SIMDGROUP_WIDTH * 0 + slid];
114
+ if (sgid == 0) sum += reduceLM[SIMDGROUP_WIDTH * 1 + slid];
115
+ if (sgid == 0) sum += reduceLM[SIMDGROUP_WIDTH * 2 + slid];
116
+
117
+ // 1 outputs per thread in subgroup 0
118
+ if (sgid == 0) {
119
+ dst = dst + (offsetd >> 2);
120
+ dst[i01 + i20 * ne01] = sum;
121
+ }
122
+
123
+ }
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemv_moe_q5_1_f32_ns.cl ADDED
@@ -0,0 +1,125 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #pragma OPENCL EXTENSION cl_khr_fp16 : enable
2
+ #pragma OPENCL EXTENSION cl_khr_subgroups : enable
3
+ #pragma OPENCL EXTENSION cl_qcom_reqd_sub_group_size : enable
4
+
5
+ #define QK_Q5_1 32
6
+ #define N_SIMDGROUP 4
7
+ #define SIMDGROUP_WIDTH 64
8
+
9
+ static inline float8 q5_1_to_fp32_packed8(ushort2 qs5x8, uchar qh5x8, half s, half m) {
10
+ float8 fp32x8;
11
+ fp32x8.s0 = (float)((( qs5x8.s0 & 0x000F) | (( qh5x8 & 0x01) << 4)) * s + m);
12
+ fp32x8.s1 = (float)((((qs5x8.s0 & 0x00F0) >> 4 ) | (((qh5x8 >> 1) & 0x01) << 4)) * s + m);
13
+ fp32x8.s2 = (float)((((qs5x8.s0 & 0x0F00) >> 8 ) | (((qh5x8 >> 2) & 0x01) << 4)) * s + m);
14
+ fp32x8.s3 = (float)((((qs5x8.s0 & 0xF000) >> 12) | (((qh5x8 >> 3) & 0x01) << 4)) * s + m);
15
+ fp32x8.s4 = (float)((( qs5x8.s1 & 0x000F) | (((qh5x8 >> 4) & 0x01) << 4)) * s + m);
16
+ fp32x8.s5 = (float)((((qs5x8.s1 & 0x00F0) >> 4 ) | (((qh5x8 >> 5) & 0x01) << 4)) * s + m);
17
+ fp32x8.s6 = (float)((((qs5x8.s1 & 0x0F00) >> 8 ) | (((qh5x8 >> 6) & 0x01) << 4)) * s + m);
18
+ fp32x8.s7 = (float)((((qs5x8.s1 & 0xF000) >> 12) | (((qh5x8 >> 7) & 0x01) << 4)) * s + m);
19
+ return fp32x8;
20
+ }
21
+
22
+
23
+ __attribute__((qcom_reqd_sub_group_size("half")))
24
+ __kernel void kernel_gemv_moe_q5_1_f32_ns(
25
+ __global uint * src0_qs,
26
+ __global uint * src0_qh,
27
+ __global half * src0_d,
28
+ __global half * src0_m,
29
+ __read_only image1d_buffer_t src1,
30
+ __global uint * src2,
31
+ __global float * dst,
32
+ ulong offsetd,
33
+ uint ne00,
34
+ uint ne01,
35
+ uint ne11
36
+ ) {
37
+ uint i01 = get_global_id(0);
38
+ uint i20 = get_global_id(2);
39
+ uint sgid = get_local_id(1);
40
+ uint slid = get_sub_group_local_id();
41
+
42
+ if (i01 >= ne01) {
43
+ return;
44
+ }
45
+
46
+ uint i11 = i20 % ne11;
47
+
48
+ uint expert_id = src2[i20];
49
+ uint expert_offset = expert_id * ne00 * ne01 / 32;
50
+
51
+ __private float sum = 0.0f; // each thread calculate partial sum of one output
52
+
53
+ // loop along ne00 in block granularity, skip 4 blocks every iter
54
+ for (uint ib00 = sgid; ib00 < (ne00 / QK_Q5_1); ib00 += N_SIMDGROUP) {
55
+
56
+ // load one block of q
57
+ uint4 regQ;
58
+ uint block_offset = expert_offset * 4 + ib00 * ne01 * 4 + i01;
59
+
60
+ regQ.s0 = src0_qs[block_offset];
61
+ regQ.s1 = src0_qs[block_offset + ne01];
62
+ regQ.s2 = src0_qs[block_offset + ne01 * 2];
63
+ regQ.s3 = src0_qs[block_offset + ne01 * 3];
64
+
65
+ uint offset = i11 * ne00 / 4 + ib00 * 8;
66
+
67
+ uchar4 regQh = as_uchar4(src0_qh[ib00 * ne01 + i01 + expert_offset]);
68
+ half regM = src0_m[ib00 * ne01 + i01 + expert_offset];
69
+ half regS = src0_d[ib00 * ne01 + i01 + expert_offset];
70
+
71
+ float8 fp32x8 = q5_1_to_fp32_packed8(as_ushort2(regQ.s0), regQh.s0, regS, regM);
72
+
73
+ float4 shared_y4;
74
+ shared_y4 = read_imagef(src1, (offset + 0));
75
+ float4 acc = shared_y4 * fp32x8.lo;
76
+
77
+ shared_y4 = read_imagef(src1, (offset + 1));
78
+ acc += shared_y4 * fp32x8.hi;
79
+
80
+ fp32x8 = q5_1_to_fp32_packed8(as_ushort2(regQ.s1), regQh.s1, regS, regM);
81
+
82
+ shared_y4 = read_imagef(src1, (offset + 2));
83
+ acc += shared_y4 * fp32x8.lo;
84
+
85
+ shared_y4 = read_imagef(src1, (offset + 3));
86
+ acc += shared_y4 * fp32x8.hi;
87
+
88
+
89
+ fp32x8 = q5_1_to_fp32_packed8(as_ushort2(regQ.s2), regQh.s2, regS, regM);
90
+
91
+ shared_y4 = read_imagef(src1, (offset + 4));
92
+ acc += shared_y4 * fp32x8.lo;
93
+
94
+ shared_y4 = read_imagef(src1, (offset + 5));
95
+ acc += shared_y4 * fp32x8.hi;
96
+
97
+
98
+ fp32x8 = q5_1_to_fp32_packed8(as_ushort2(regQ.s3), regQh.s3, regS, regM);
99
+
100
+ shared_y4 = read_imagef(src1, (offset + 6));
101
+ acc += shared_y4 * fp32x8.lo;
102
+
103
+ shared_y4 = read_imagef(src1, (offset + 7));
104
+ acc += shared_y4 * fp32x8.hi;
105
+
106
+ sum += ((acc.s0 + acc.s1) + (acc.s2 + acc.s3));
107
+ }
108
+
109
+ // reduction in local memory, assumes #subgroups=4
110
+ __local float reduceLM[SIMDGROUP_WIDTH * (N_SIMDGROUP - 1)];
111
+ if (sgid == 1) reduceLM[SIMDGROUP_WIDTH * 0 + slid] = sum;
112
+ if (sgid == 2) reduceLM[SIMDGROUP_WIDTH * 1 + slid] = sum;
113
+ if (sgid == 3) reduceLM[SIMDGROUP_WIDTH * 2 + slid] = sum;
114
+ barrier(CLK_LOCAL_MEM_FENCE);
115
+ if (sgid == 0) sum += reduceLM[SIMDGROUP_WIDTH * 0 + slid];
116
+ if (sgid == 0) sum += reduceLM[SIMDGROUP_WIDTH * 1 + slid];
117
+ if (sgid == 0) sum += reduceLM[SIMDGROUP_WIDTH * 2 + slid];
118
+
119
+ // 1 outputs per thread in subgroup 0
120
+ if (sgid == 0) {
121
+ dst = dst + (offsetd >> 2);
122
+ dst[i01 + i20 * ne01] = sum;
123
+ }
124
+
125
+ }
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemv_moe_q5_k_f32_ns.cl ADDED
@@ -0,0 +1,160 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #pragma OPENCL EXTENSION cl_khr_fp16 : enable
2
+ #pragma OPENCL EXTENSION cl_khr_subgroups : enable
3
+ #pragma OPENCL EXTENSION cl_qcom_reqd_sub_group_size : enable
4
+
5
+ #define QK_K 256
6
+ #define K_SCALE_SIZE 12
7
+ #define N_SIMDGROUP 4
8
+ #define SIMDGROUP_WIDTH 64
9
+
10
+ inline void get_scale_min_k4(
11
+ int j,
12
+ global const uchar * q,
13
+ uchar * d,
14
+ uchar * m
15
+ ) {
16
+ if (j < 4) {
17
+ *d = q[j] & 63;
18
+ *m = q[j+4] & 63;
19
+ } else {
20
+ *d = (q[j+4] & 0x0F) | ((q[j-4] & 0xC0) >> 2);
21
+ *m = ((q[j+4] >> 4) & 0x0F) | ((q[j] & 0xC0) >> 2);
22
+ }
23
+ }
24
+
25
+ static inline float8 q5_k_to_fp32_packed8(ushort2 qs5x8, uchar qh5x8, half s, half m) {
26
+ float8 fp32x8;
27
+ fp32x8.s0 = (float)((( qs5x8.s0 & 0x000F) | (( qh5x8 & 0x01) << 4)) * s + m);
28
+ fp32x8.s1 = (float)((((qs5x8.s0 & 0x00F0) >> 4 ) | (((qh5x8 >> 1) & 0x01) << 4)) * s + m);
29
+ fp32x8.s2 = (float)((((qs5x8.s0 & 0x0F00) >> 8 ) | (((qh5x8 >> 2) & 0x01) << 4)) * s + m);
30
+ fp32x8.s3 = (float)((((qs5x8.s0 & 0xF000) >> 12) | (((qh5x8 >> 3) & 0x01) << 4)) * s + m);
31
+ fp32x8.s4 = (float)((( qs5x8.s1 & 0x000F) | (((qh5x8 >> 4) & 0x01) << 4)) * s + m);
32
+ fp32x8.s5 = (float)((((qs5x8.s1 & 0x00F0) >> 4 ) | (((qh5x8 >> 5) & 0x01) << 4)) * s + m);
33
+ fp32x8.s6 = (float)((((qs5x8.s1 & 0x0F00) >> 8 ) | (((qh5x8 >> 6) & 0x01) << 4)) * s + m);
34
+ fp32x8.s7 = (float)((((qs5x8.s1 & 0xF000) >> 12) | (((qh5x8 >> 7) & 0x01) << 4)) * s + m);
35
+ return fp32x8;
36
+ }
37
+
38
+ __attribute__((qcom_reqd_sub_group_size("half")))
39
+ __kernel void kernel_gemv_moe_q5_k_f32_ns(
40
+ __global uint * src0_q,
41
+ __global uint * src0_qh,
42
+ __global half * src0_d,
43
+ __global half * src0_dm,
44
+ __global uchar * src0_s,
45
+ __read_only image1d_buffer_t src1,
46
+ __global uint * src2,
47
+ __global float * dst,
48
+ ulong offsetd,
49
+ int ne00,
50
+ int ne01,
51
+ int ne11
52
+ ) {
53
+ uint i01 = get_global_id(0);
54
+ uint i20 = get_global_id(2);
55
+ uint sgid = get_local_id(1);
56
+ uint slid = get_sub_group_local_id();
57
+
58
+ if (i01 >= ne01) {
59
+ return;
60
+ }
61
+
62
+ uint i11 = i20 % ne11;
63
+
64
+ uint expert_id = src2[i20];
65
+
66
+ int num_superblocks = ne00 / QK_K;
67
+ int num_subblocks = ne00 / 32;
68
+ int scales_per_row = num_superblocks * K_SCALE_SIZE;
69
+
70
+ // Expert offsets in the transposed noshuffle layout
71
+ uint expert_q_offset = expert_id * (ne00 / 8) * ne01;
72
+ uint expert_d_offset = expert_id * num_superblocks * ne01;
73
+
74
+ __private float sum = 0.0f;
75
+
76
+ // Loop over sub-blocks of 32 elements, N_SIMDGROUP sub-blocks per iter
77
+ for (uint ib = sgid; ib < num_subblocks; ib += N_SIMDGROUP) {
78
+ uint sb = ib / 8;
79
+ uint j = ib % 8;
80
+
81
+ // Load d and dmin for this super-block
82
+ half d_val = src0_d[expert_d_offset + sb * ne01 + i01];
83
+ half dm_val = src0_dm[expert_d_offset + sb * ne01 + i01];
84
+
85
+ // sub_block index = sb * 8 + j
86
+ uint expert_qh_offset = expert_id * num_superblocks * 8 * ne01;
87
+ uchar4 regQh = as_uchar4(src0_qh[expert_qh_offset + (sb * 8 + j) * ne01 + i01]);
88
+
89
+ // Load sub-block scale and min
90
+ global const uchar * sc = src0_s + (expert_id * ne01 + i01) * scales_per_row + sb * K_SCALE_SIZE;
91
+ uchar sv, mn;
92
+ get_scale_min_k4(j, sc, &sv, &mn);
93
+
94
+ float scale = (float)d_val * (float)sv;
95
+ float minv = -(float)dm_val * (float)mn;
96
+
97
+ // Load 4 uints of quants (32 nibbles = 32 elements)
98
+ uint q_base = expert_q_offset + ib * ne01 * 4 + i01;
99
+
100
+ uint4 regQ;
101
+ regQ.s0 = src0_q[q_base];
102
+ regQ.s1 = src0_q[q_base + ne01];
103
+ regQ.s2 = src0_q[q_base + ne01 * 2];
104
+ regQ.s3 = src0_q[q_base + ne01 * 3];
105
+
106
+ // Load activations: 32 floats = 8 float4s
107
+ uint y_offset = i11 * ne00 / 4 + ib * 8;
108
+
109
+ float8 fp32x8 = q5_k_to_fp32_packed8(as_ushort2(regQ.s0), regQh.s0, scale, minv);
110
+
111
+ float4 shared_y4;
112
+ shared_y4 = read_imagef(src1, (y_offset + 0));
113
+ float4 acc = shared_y4 * fp32x8.lo;
114
+
115
+ shared_y4 = read_imagef(src1, (y_offset + 1));
116
+ acc += shared_y4 * fp32x8.hi;
117
+
118
+ fp32x8 = q5_k_to_fp32_packed8(as_ushort2(regQ.s1), regQh.s1, scale, minv);
119
+
120
+ shared_y4 = read_imagef(src1, (y_offset + 2));
121
+ acc += shared_y4 * fp32x8.lo;
122
+
123
+ shared_y4 = read_imagef(src1, (y_offset + 3));
124
+ acc += shared_y4 * fp32x8.hi;
125
+
126
+ fp32x8 = q5_k_to_fp32_packed8(as_ushort2(regQ.s2), regQh.s2, scale, minv);
127
+
128
+ shared_y4 = read_imagef(src1, (y_offset + 4));
129
+ acc += shared_y4 * fp32x8.lo;
130
+
131
+ shared_y4 = read_imagef(src1, (y_offset + 5));
132
+ acc += shared_y4 * fp32x8.hi;
133
+
134
+ fp32x8 = q5_k_to_fp32_packed8(as_ushort2(regQ.s3), regQh.s3, scale, minv);
135
+
136
+ shared_y4 = read_imagef(src1, (y_offset + 6));
137
+ acc += shared_y4 * fp32x8.lo;
138
+
139
+ shared_y4 = read_imagef(src1, (y_offset + 7));
140
+ acc += shared_y4 * fp32x8.hi;
141
+
142
+ sum += ((acc.s0 + acc.s1) + (acc.s2 + acc.s3));
143
+ }
144
+
145
+ // reduction in local memory, assumes #subgroups=4
146
+ __local float reduceLM[SIMDGROUP_WIDTH * (N_SIMDGROUP - 1)];
147
+ if (sgid == 1) reduceLM[SIMDGROUP_WIDTH * 0 + slid] = sum;
148
+ if (sgid == 2) reduceLM[SIMDGROUP_WIDTH * 1 + slid] = sum;
149
+ if (sgid == 3) reduceLM[SIMDGROUP_WIDTH * 2 + slid] = sum;
150
+ barrier(CLK_LOCAL_MEM_FENCE);
151
+ if (sgid == 0) sum += reduceLM[SIMDGROUP_WIDTH * 0 + slid];
152
+ if (sgid == 0) sum += reduceLM[SIMDGROUP_WIDTH * 1 + slid];
153
+ if (sgid == 0) sum += reduceLM[SIMDGROUP_WIDTH * 2 + slid];
154
+
155
+ // 1 output per thread in subgroup 0
156
+ if (sgid == 0) {
157
+ dst = dst + (offsetd >> 2);
158
+ dst[i01 + i20 * ne01] = sum;
159
+ }
160
+ }
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemv_moe_q6_k_f32_ns.cl ADDED
@@ -0,0 +1,141 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #pragma OPENCL EXTENSION cl_khr_fp16 : enable
2
+ #pragma OPENCL EXTENSION cl_khr_subgroups : enable
3
+ #pragma OPENCL EXTENSION cl_qcom_reqd_sub_group_size : enable
4
+
5
+ #define QK_K 256
6
+ #define N_SIMDGROUP 4
7
+ #define SIMDGROUP_WIDTH 64
8
+
9
+ static inline float8 q6_k_to_fp32_packed8(ushort2 ql8, ushort qh8, float d_scale) {
10
+ float8 fp32x8;
11
+ fp32x8.s0 = ((float)(( ql8.s0 & 0x000F) | ((uint)((qh8 ) & 0x3) << 4)) - 32.f) * d_scale;
12
+ fp32x8.s1 = ((float)((( ql8.s0 >> 4) & 0x000F) | ((uint)((qh8 >> 2) & 0x3) << 4)) - 32.f) * d_scale;
13
+ fp32x8.s2 = ((float)((( ql8.s0 >> 8) & 0x000F) | ((uint)((qh8 >> 4) & 0x3) << 4)) - 32.f) * d_scale;
14
+ fp32x8.s3 = ((float)((( ql8.s0 >> 12)& 0x000F) | ((uint)((qh8 >> 6) & 0x3) << 4)) - 32.f) * d_scale;
15
+ fp32x8.s4 = ((float)(( ql8.s1 & 0x000F) | ((uint)((qh8 >> 8) & 0x3) << 4)) - 32.f) * d_scale;
16
+ fp32x8.s5 = ((float)((( ql8.s1 >> 4) & 0x000F) | ((uint)((qh8 >>10) & 0x3) << 4)) - 32.f) * d_scale;
17
+ fp32x8.s6 = ((float)((( ql8.s1 >> 8) & 0x000F) | ((uint)((qh8 >>12) & 0x3) << 4)) - 32.f) * d_scale;
18
+ fp32x8.s7 = ((float)((( ql8.s1 >> 12)& 0x000F) | ((uint)((qh8 >>14) & 0x3) << 4)) - 32.f) * d_scale;
19
+ return fp32x8;
20
+ }
21
+
22
+ __attribute__((qcom_reqd_sub_group_size("half")))
23
+ __kernel void kernel_gemv_moe_q6_k_f32_ns(
24
+ __global uint * src0_ql,
25
+ __global uint * src0_qh,
26
+ __global char * src0_s,
27
+ __global half * src0_d,
28
+ __read_only image1d_buffer_t src1,
29
+ __global uint * src2,
30
+ __global float * dst,
31
+ ulong offsetd,
32
+ int ne00,
33
+ int ne01,
34
+ int ne11
35
+ ) {
36
+ uint i01 = get_global_id(0);
37
+ uint i20 = get_global_id(2);
38
+ uint sgid = get_local_id(1);
39
+ uint slid = get_sub_group_local_id();
40
+
41
+ if (i01 >= ne01) {
42
+ return;
43
+ }
44
+
45
+ uint i11 = i20 % ne11;
46
+
47
+ uint expert_id = src2[i20];
48
+
49
+ int num_superblocks = ne00 / QK_K;
50
+ int num_subblocks = ne00 / 32; // 8 sub-blocks of 32 per super-block
51
+ int scales_per_row = num_superblocks * 16;
52
+
53
+ // Expert offsets in the transposed noshuffle layout
54
+ uint expert_ql_offset = expert_id * (ne00 / 8) * ne01; // 32 uints per super-block
55
+ uint expert_qh_offset = expert_id * (ne00 / 16) * ne01; // 16 uints per super-block
56
+ uint expert_d_offset = expert_id * num_superblocks * ne01;
57
+
58
+ __private float sum = 0.0f;
59
+
60
+ // Loop over sub-blocks of 32 elements, N_SIMDGROUP sub-blocks per iter
61
+ for (uint ib = sgid; ib < num_subblocks; ib += N_SIMDGROUP) {
62
+ uint sb = ib / 8; // super-block index
63
+ uint j = ib % 8; // 32-element group within super-block
64
+
65
+ // Load d for this super-block
66
+ half d_val = src0_d[expert_d_offset + sb * ne01 + i01];
67
+
68
+ // Load 2 sub-block scales
69
+ global const char * sc = src0_s + (expert_id * ne01 + i01) * scales_per_row + sb * 16;
70
+ float scale0 = (float)d_val * (float)sc[j * 2];
71
+ float scale1 = (float)d_val * (float)sc[j * 2 + 1];
72
+
73
+ // Load 4 uints of ql
74
+ uint ql_base = expert_ql_offset + (ib * 4) * ne01 + i01;
75
+ uint4 regQL;
76
+ regQL.s0 = src0_ql[ql_base];
77
+ regQL.s1 = src0_ql[ql_base + ne01];
78
+ regQL.s2 = src0_ql[ql_base + ne01 * 2];
79
+ regQL.s3 = src0_ql[ql_base + ne01 * 3];
80
+
81
+ // Load 2 uints of qh
82
+ uint qh_base = expert_qh_offset + (ib * 2) * ne01 + i01;
83
+ uint2 regQH;
84
+ regQH.s0 = src0_qh[qh_base];
85
+ regQH.s1 = src0_qh[qh_base + ne01];
86
+
87
+ // Load activations: 32 floats = 8 float4s
88
+ uint y_offset = i11 * ne00 / 4 + ib * 8;
89
+
90
+ float8 fp32x8 = q6_k_to_fp32_packed8(as_ushort2(regQL.s0), (ushort)(regQH.s0 & 0xFFFF), scale0);
91
+
92
+ float4 shared_y4;
93
+ shared_y4 = read_imagef(src1, (y_offset + 0));
94
+ float4 acc = shared_y4 * fp32x8.lo;
95
+
96
+ shared_y4 = read_imagef(src1, (y_offset + 1));
97
+ acc += shared_y4 * fp32x8.hi;
98
+
99
+ fp32x8 = q6_k_to_fp32_packed8(as_ushort2(regQL.s1), (ushort)(regQH.s0 >> 16), scale0);
100
+
101
+ shared_y4 = read_imagef(src1, (y_offset + 2));
102
+ acc += shared_y4 * fp32x8.lo;
103
+
104
+ shared_y4 = read_imagef(src1, (y_offset + 3));
105
+ acc += shared_y4 * fp32x8.hi;
106
+
107
+ fp32x8 = q6_k_to_fp32_packed8(as_ushort2(regQL.s2), (ushort)(regQH.s1 & 0xFFFF), scale1);
108
+
109
+ shared_y4 = read_imagef(src1, (y_offset + 4));
110
+ acc += shared_y4 * fp32x8.lo;
111
+
112
+ shared_y4 = read_imagef(src1, (y_offset + 5));
113
+ acc += shared_y4 * fp32x8.hi;
114
+
115
+ fp32x8 = q6_k_to_fp32_packed8(as_ushort2(regQL.s3), (ushort)(regQH.s1 >> 16), scale1);
116
+
117
+ shared_y4 = read_imagef(src1, (y_offset + 6));
118
+ acc += shared_y4 * fp32x8.lo;
119
+
120
+ shared_y4 = read_imagef(src1, (y_offset + 7));
121
+ acc += shared_y4 * fp32x8.hi;
122
+
123
+ sum += ((acc.s0 + acc.s1) + (acc.s2 + acc.s3));
124
+ }
125
+
126
+ // reduction in local memory, assumes #subgroups=4
127
+ __local float reduceLM[SIMDGROUP_WIDTH * (N_SIMDGROUP - 1)];
128
+ if (sgid == 1) reduceLM[SIMDGROUP_WIDTH * 0 + slid] = sum;
129
+ if (sgid == 2) reduceLM[SIMDGROUP_WIDTH * 1 + slid] = sum;
130
+ if (sgid == 3) reduceLM[SIMDGROUP_WIDTH * 2 + slid] = sum;
131
+ barrier(CLK_LOCAL_MEM_FENCE);
132
+ if (sgid == 0) sum += reduceLM[SIMDGROUP_WIDTH * 0 + slid];
133
+ if (sgid == 0) sum += reduceLM[SIMDGROUP_WIDTH * 1 + slid];
134
+ if (sgid == 0) sum += reduceLM[SIMDGROUP_WIDTH * 2 + slid];
135
+
136
+ // 1 output per thread in subgroup 0
137
+ if (sgid == 0) {
138
+ dst = dst + (offsetd >> 2);
139
+ dst[i01 + i20 * ne01] = sum;
140
+ }
141
+ }
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemv_noshuffle_iq4_nl_f32.cl ADDED
@@ -0,0 +1,302 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #pragma OPENCL EXTENSION cl_khr_fp16 : enable
2
+ #pragma OPENCL EXTENSION cl_khr_subgroups : enable
3
+
4
+ #ifdef cl_qcom_reqd_sub_group_size
5
+ #pragma OPENCL EXTENSION cl_qcom_reqd_sub_group_size : enable
6
+ #define ADRENO_GPU 1
7
+ #define REQD_SUBGROUP_SIZE_64 __attribute__((qcom_reqd_sub_group_size("half")))
8
+ #endif
9
+
10
+ #define QK4_NL 32
11
+ #define NSUBGROUPS 4
12
+ #define SUBGROUP_SIZE 64
13
+
14
+ constant half kvalues_iq4nl[16] = {
15
+ (half)-127.f, (half)-104.f, (half)-83.f, (half)-65.f,
16
+ (half) -49.f, (half) -35.f, (half)-22.f, (half)-10.f,
17
+ (half) 1.f, (half) 13.f, (half) 25.f, (half) 38.f,
18
+ (half) 53.f, (half) 69.f, (half) 89.f, (half)113.f
19
+ };
20
+
21
+ // Packed LUT: 2 FP16 values per uint, 8 unique constant loads instead of 16
22
+ constant uint iq4nl_packed[8] = {
23
+ 0xD680D7F0u, // idx 0,1: -127, -104
24
+ 0xD410D530u, // idx 2,3: -83, -65
25
+ 0xD060D220u, // idx 4,5: -49, -35
26
+ 0xC900CD80u, // idx 6,7: -22, -10
27
+ 0x4A803C00u, // idx 8,9: 1, 13
28
+ 0x50C04E40u, // idx 10,11: 25, 38
29
+ 0x545052A0u, // idx 12,13: 53, 69
30
+ 0x57105590u // idx 14,15: 89, 113
31
+ };
32
+
33
+ // Packed dequant: 1 uint constant load (8-way divergence) + shift + as_half
34
+ #define IQ4_NL_DEQUANT(nibble) as_half((ushort)(iq4nl_packed[(nibble) >> 1] >> (((nibble) & 1u) << 4)))
35
+
36
+ #define dequantizeBlockAccum_ns_sgbroadcast_1_hi(total_sums, bits4, scale, y) \
37
+ float shared_y; \
38
+ shared_y = sub_group_broadcast(y.s0, 0); \
39
+ total_sums.s0 += IQ4_NL_DEQUANT((bits4.s0 & 0x000F)) * scale.s0 * shared_y; \
40
+ total_sums.s1 += IQ4_NL_DEQUANT((bits4.s1 & 0x000F)) * scale.s1 * shared_y; \
41
+ shared_y = sub_group_broadcast(y.s1, 0); \
42
+ total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s0 & 0x00F0) >> 4)) * scale.s0 * shared_y; \
43
+ total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s1 & 0x00F0) >> 4)) * scale.s1 * shared_y; \
44
+ shared_y = sub_group_broadcast(y.s2, 0); \
45
+ total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s0 & 0x0F00) >> 8)) * scale.s0 * shared_y; \
46
+ total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s1 & 0x0F00) >> 8)) * scale.s1 * shared_y; \
47
+ shared_y = sub_group_broadcast(y.s3, 0); \
48
+ total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s0 & 0xF000) >> 12)) * scale.s0 * shared_y; \
49
+ total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s1 & 0xF000) >> 12)) * scale.s1 * shared_y; \
50
+ shared_y = sub_group_broadcast(y.s4, 0); \
51
+ total_sums.s0 += IQ4_NL_DEQUANT((bits4.s2 & 0x000F)) * scale.s0 * shared_y; \
52
+ total_sums.s1 += IQ4_NL_DEQUANT((bits4.s3 & 0x000F)) * scale.s1 * shared_y; \
53
+ shared_y = sub_group_broadcast(y.s5, 0); \
54
+ total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s2 & 0x00F0) >> 4)) * scale.s0 * shared_y; \
55
+ total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s3 & 0x00F0) >> 4)) * scale.s1 * shared_y; \
56
+ shared_y = sub_group_broadcast(y.s6, 0); \
57
+ total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s2 & 0x0F00) >> 8)) * scale.s0 * shared_y; \
58
+ total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s3 & 0x0F00) >> 8)) * scale.s1 * shared_y; \
59
+ shared_y = sub_group_broadcast(y.s7, 0); \
60
+ total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s2 & 0xF000) >> 12)) * scale.s0 * shared_y; \
61
+ total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s3 & 0xF000) >> 12)) * scale.s1 * shared_y; \
62
+ shared_y = sub_group_broadcast(y.s0, 1); \
63
+ total_sums.s0 += IQ4_NL_DEQUANT((bits4.s4 & 0x000F)) * scale.s0 * shared_y; \
64
+ total_sums.s1 += IQ4_NL_DEQUANT((bits4.s5 & 0x000F)) * scale.s1 * shared_y; \
65
+ shared_y = sub_group_broadcast(y.s1, 1); \
66
+ total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s4 & 0x00F0) >> 4)) * scale.s0 * shared_y; \
67
+ total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s5 & 0x00F0) >> 4)) * scale.s1 * shared_y; \
68
+ shared_y = sub_group_broadcast(y.s2, 1); \
69
+ total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s4 & 0x0F00) >> 8)) * scale.s0 * shared_y; \
70
+ total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s5 & 0x0F00) >> 8)) * scale.s1 * shared_y; \
71
+ shared_y = sub_group_broadcast(y.s3, 1); \
72
+ total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s4 & 0xF000) >> 12)) * scale.s0 * shared_y; \
73
+ total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s5 & 0xF000) >> 12)) * scale.s1 * shared_y; \
74
+ shared_y = sub_group_broadcast(y.s4, 1); \
75
+ total_sums.s0 += IQ4_NL_DEQUANT((bits4.s6 & 0x000F)) * scale.s0 * shared_y; \
76
+ total_sums.s1 += IQ4_NL_DEQUANT((bits4.s7 & 0x000F)) * scale.s1 * shared_y; \
77
+ shared_y = sub_group_broadcast(y.s5, 1); \
78
+ total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s6 & 0x00F0) >> 4)) * scale.s0 * shared_y; \
79
+ total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s7 & 0x00F0) >> 4)) * scale.s1 * shared_y; \
80
+ shared_y = sub_group_broadcast(y.s6, 1); \
81
+ total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s6 & 0x0F00) >> 8)) * scale.s0 * shared_y; \
82
+ total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s7 & 0x0F00) >> 8)) * scale.s1 * shared_y; \
83
+ shared_y = sub_group_broadcast(y.s7, 1); \
84
+ total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s6 & 0xF000) >> 12)) * scale.s0 * shared_y; \
85
+ total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s7 & 0xF000) >> 12)) * scale.s1 * shared_y; \
86
+
87
+
88
+ #define dequantizeBlockAccum_ns_sgbroadcast_1_lo(total_sums, bits4, scale, y) \
89
+ shared_y = sub_group_broadcast(y.s0, 2); \
90
+ total_sums.s0 += IQ4_NL_DEQUANT((bits4.s0 & 0x000F)) * scale.s0 * shared_y; \
91
+ total_sums.s1 += IQ4_NL_DEQUANT((bits4.s1 & 0x000F)) * scale.s1 * shared_y; \
92
+ shared_y = sub_group_broadcast(y.s1, 2); \
93
+ total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s0 & 0x00F0) >> 4)) * scale.s0 * shared_y; \
94
+ total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s1 & 0x00F0) >> 4)) * scale.s1 * shared_y; \
95
+ shared_y = sub_group_broadcast(y.s2, 2); \
96
+ total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s0 & 0x0F00) >> 8)) * scale.s0 * shared_y; \
97
+ total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s1 & 0x0F00) >> 8)) * scale.s1 * shared_y; \
98
+ shared_y = sub_group_broadcast(y.s3, 2); \
99
+ total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s0 & 0xF000) >> 12)) * scale.s0 * shared_y; \
100
+ total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s1 & 0xF000) >> 12)) * scale.s1 * shared_y; \
101
+ shared_y = sub_group_broadcast(y.s4, 2); \
102
+ total_sums.s0 += IQ4_NL_DEQUANT((bits4.s2 & 0x000F)) * scale.s0 * shared_y; \
103
+ total_sums.s1 += IQ4_NL_DEQUANT((bits4.s3 & 0x000F)) * scale.s1 * shared_y; \
104
+ shared_y = sub_group_broadcast(y.s5, 2); \
105
+ total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s2 & 0x00F0) >> 4)) * scale.s0 * shared_y; \
106
+ total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s3 & 0x00F0) >> 4)) * scale.s1 * shared_y; \
107
+ shared_y = sub_group_broadcast(y.s6, 2); \
108
+ total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s2 & 0x0F00) >> 8)) * scale.s0 * shared_y; \
109
+ total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s3 & 0x0F00) >> 8)) * scale.s1 * shared_y; \
110
+ shared_y = sub_group_broadcast(y.s7, 2); \
111
+ total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s2 & 0xF000) >> 12)) * scale.s0 * shared_y; \
112
+ total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s3 & 0xF000) >> 12)) * scale.s1 * shared_y; \
113
+ shared_y = sub_group_broadcast(y.s0, 3); \
114
+ total_sums.s0 += IQ4_NL_DEQUANT((bits4.s4 & 0x000F)) * scale.s0 * shared_y; \
115
+ total_sums.s1 += IQ4_NL_DEQUANT((bits4.s5 & 0x000F)) * scale.s1 * shared_y; \
116
+ shared_y = sub_group_broadcast(y.s1, 3); \
117
+ total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s4 & 0x00F0) >> 4)) * scale.s0 * shared_y; \
118
+ total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s5 & 0x00F0) >> 4)) * scale.s1 * shared_y; \
119
+ shared_y = sub_group_broadcast(y.s2, 3); \
120
+ total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s4 & 0x0F00) >> 8)) * scale.s0 * shared_y; \
121
+ total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s5 & 0x0F00) >> 8)) * scale.s1 * shared_y; \
122
+ shared_y = sub_group_broadcast(y.s3, 3); \
123
+ total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s4 & 0xF000) >> 12)) * scale.s0 * shared_y; \
124
+ total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s5 & 0xF000) >> 12)) * scale.s1 * shared_y; \
125
+ shared_y = sub_group_broadcast(y.s4, 3); \
126
+ total_sums.s0 += IQ4_NL_DEQUANT((bits4.s6 & 0x000F)) * scale.s0 * shared_y; \
127
+ total_sums.s1 += IQ4_NL_DEQUANT((bits4.s7 & 0x000F)) * scale.s1 * shared_y; \
128
+ shared_y = sub_group_broadcast(y.s5, 3); \
129
+ total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s6 & 0x00F0) >> 4)) * scale.s0 * shared_y; \
130
+ total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s7 & 0x00F0) >> 4)) * scale.s1 * shared_y; \
131
+ shared_y = sub_group_broadcast(y.s6, 3); \
132
+ total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s6 & 0x0F00) >> 8)) * scale.s0 * shared_y; \
133
+ total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s7 & 0x0F00) >> 8)) * scale.s1 * shared_y; \
134
+ shared_y = sub_group_broadcast(y.s7, 3); \
135
+ total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s6 & 0xF000) >> 12)) * scale.s0 * shared_y; \
136
+ total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s7 & 0xF000) >> 12)) * scale.s1 * shared_y; \
137
+
138
+
139
+ #define dequantizeBlockAccum_ns_sgbroadcast_8_hi(total_sums, bits4, scale, y) \
140
+ float8 shared_y; \
141
+ shared_y = sub_group_broadcast(y, 0); \
142
+ total_sums.s0 += IQ4_NL_DEQUANT((bits4.s0 & 0x000F)) * scale.s0 * shared_y.s0; \
143
+ total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s0 & 0x00F0) >> 4)) * scale.s0 * shared_y.s1; \
144
+ total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s0 & 0x0F00) >> 8)) * scale.s0 * shared_y.s2; \
145
+ total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s0 & 0xF000) >> 12)) * scale.s0 * shared_y.s3; \
146
+ total_sums.s0 += IQ4_NL_DEQUANT((bits4.s2 & 0x000F)) * scale.s0 * shared_y.s4; \
147
+ total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s2 & 0x00F0) >> 4)) * scale.s0 * shared_y.s5; \
148
+ total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s2 & 0x0F00) >> 8)) * scale.s0 * shared_y.s6; \
149
+ total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s2 & 0xF000) >> 12)) * scale.s0 * shared_y.s7; \
150
+ total_sums.s1 += IQ4_NL_DEQUANT((bits4.s1 & 0x000F)) * scale.s1 * shared_y.s0; \
151
+ total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s1 & 0x00F0) >> 4)) * scale.s1 * shared_y.s1; \
152
+ total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s1 & 0x0F00) >> 8)) * scale.s1 * shared_y.s2; \
153
+ total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s1 & 0xF000) >> 12)) * scale.s1 * shared_y.s3; \
154
+ total_sums.s1 += IQ4_NL_DEQUANT((bits4.s3 & 0x000F)) * scale.s1 * shared_y.s4; \
155
+ total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s3 & 0x00F0) >> 4)) * scale.s1 * shared_y.s5; \
156
+ total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s3 & 0x0F00) >> 8)) * scale.s1 * shared_y.s6; \
157
+ total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s3 & 0xF000) >> 12)) * scale.s1 * shared_y.s7; \
158
+ shared_y = sub_group_broadcast(y, 1); \
159
+ total_sums.s0 += IQ4_NL_DEQUANT((bits4.s4 & 0x000F)) * scale.s0 * shared_y.s0; \
160
+ total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s4 & 0x00F0) >> 4)) * scale.s0 * shared_y.s1; \
161
+ total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s4 & 0x0F00) >> 8)) * scale.s0 * shared_y.s2; \
162
+ total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s4 & 0xF000) >> 12)) * scale.s0 * shared_y.s3; \
163
+ total_sums.s0 += IQ4_NL_DEQUANT((bits4.s6 & 0x000F)) * scale.s0 * shared_y.s4; \
164
+ total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s6 & 0x00F0) >> 4)) * scale.s0 * shared_y.s5; \
165
+ total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s6 & 0x0F00) >> 8)) * scale.s0 * shared_y.s6; \
166
+ total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s6 & 0xF000) >> 12)) * scale.s0 * shared_y.s7; \
167
+ total_sums.s1 += IQ4_NL_DEQUANT((bits4.s5 & 0x000F)) * scale.s1 * shared_y.s0; \
168
+ total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s5 & 0x00F0) >> 4)) * scale.s1 * shared_y.s1; \
169
+ total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s5 & 0x0F00) >> 8)) * scale.s1 * shared_y.s2; \
170
+ total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s5 & 0xF000) >> 12)) * scale.s1 * shared_y.s3; \
171
+ total_sums.s1 += IQ4_NL_DEQUANT((bits4.s7 & 0x000F)) * scale.s1 * shared_y.s4; \
172
+ total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s7 & 0x00F0) >> 4)) * scale.s1 * shared_y.s5; \
173
+ total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s7 & 0x0F00) >> 8)) * scale.s1 * shared_y.s6; \
174
+ total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s7 & 0xF000) >> 12)) * scale.s1 * shared_y.s7; \
175
+
176
+
177
+ #define dequantizeBlockAccum_ns_sgbroadcast_8_lo(total_sums, bits4, scale, y) \
178
+ shared_y = sub_group_broadcast(y, 2); \
179
+ total_sums.s0 += IQ4_NL_DEQUANT((bits4.s0 & 0x000F)) * scale.s0 * shared_y.s0; \
180
+ total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s0 & 0x00F0) >> 4)) * scale.s0 * shared_y.s1; \
181
+ total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s0 & 0x0F00) >> 8)) * scale.s0 * shared_y.s2; \
182
+ total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s0 & 0xF000) >> 12)) * scale.s0 * shared_y.s3; \
183
+ total_sums.s0 += IQ4_NL_DEQUANT((bits4.s2 & 0x000F)) * scale.s0 * shared_y.s4; \
184
+ total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s2 & 0x00F0) >> 4)) * scale.s0 * shared_y.s5; \
185
+ total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s2 & 0x0F00) >> 8)) * scale.s0 * shared_y.s6; \
186
+ total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s2 & 0xF000) >> 12)) * scale.s0 * shared_y.s7; \
187
+ total_sums.s1 += IQ4_NL_DEQUANT((bits4.s1 & 0x000F)) * scale.s1 * shared_y.s0; \
188
+ total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s1 & 0x00F0) >> 4)) * scale.s1 * shared_y.s1; \
189
+ total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s1 & 0x0F00) >> 8)) * scale.s1 * shared_y.s2; \
190
+ total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s1 & 0xF000) >> 12)) * scale.s1 * shared_y.s3; \
191
+ total_sums.s1 += IQ4_NL_DEQUANT((bits4.s3 & 0x000F)) * scale.s1 * shared_y.s4; \
192
+ total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s3 & 0x00F0) >> 4)) * scale.s1 * shared_y.s5; \
193
+ total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s3 & 0x0F00) >> 8)) * scale.s1 * shared_y.s6; \
194
+ total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s3 & 0xF000) >> 12)) * scale.s1 * shared_y.s7; \
195
+ shared_y = sub_group_broadcast(y, 3); \
196
+ total_sums.s0 += IQ4_NL_DEQUANT((bits4.s4 & 0x000F)) * scale.s0 * shared_y.s0; \
197
+ total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s4 & 0x00F0) >> 4)) * scale.s0 * shared_y.s1; \
198
+ total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s4 & 0x0F00) >> 8)) * scale.s0 * shared_y.s2; \
199
+ total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s4 & 0xF000) >> 12)) * scale.s0 * shared_y.s3; \
200
+ total_sums.s0 += IQ4_NL_DEQUANT((bits4.s6 & 0x000F)) * scale.s0 * shared_y.s4; \
201
+ total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s6 & 0x00F0) >> 4)) * scale.s0 * shared_y.s5; \
202
+ total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s6 & 0x0F00) >> 8)) * scale.s0 * shared_y.s6; \
203
+ total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s6 & 0xF000) >> 12)) * scale.s0 * shared_y.s7; \
204
+ total_sums.s1 += IQ4_NL_DEQUANT((bits4.s5 & 0x000F)) * scale.s1 * shared_y.s0; \
205
+ total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s5 & 0x00F0) >> 4)) * scale.s1 * shared_y.s1; \
206
+ total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s5 & 0x0F00) >> 8)) * scale.s1 * shared_y.s2; \
207
+ total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s5 & 0xF000) >> 12)) * scale.s1 * shared_y.s3; \
208
+ total_sums.s1 += IQ4_NL_DEQUANT((bits4.s7 & 0x000F)) * scale.s1 * shared_y.s4; \
209
+ total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s7 & 0x00F0) >> 4)) * scale.s1 * shared_y.s5; \
210
+ total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s7 & 0x0F00) >> 8)) * scale.s1 * shared_y.s6; \
211
+ total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s7 & 0xF000) >> 12)) * scale.s1 * shared_y.s7; \
212
+
213
+ #ifdef ADRENO_GPU
214
+ REQD_SUBGROUP_SIZE_64
215
+ #endif
216
+ kernel void kernel_gemv_noshuffle_iq4_nl_f32(
217
+ read_only image1d_buffer_t src0_q,
218
+ global half2 * src0_d,
219
+ read_only image1d_buffer_t src1,
220
+ global float * dst,
221
+ ulong offsetd,
222
+ int ne00,
223
+ int ne01)
224
+ {
225
+ uint groupId = get_local_id(1);
226
+ uint gid = get_global_id(0);
227
+ ushort slid = get_sub_group_local_id();
228
+
229
+ uint K = ne00;
230
+ uint M = ne01;
231
+
232
+ uint LINE_STRIDE_A = M / 2;
233
+ uint BLOCK_STRIDE_A = NSUBGROUPS * M;
234
+
235
+ private uint4 regA;
236
+ private half2 regS;
237
+ private float8 regB;
238
+
239
+ private float2 totalSum = (float2)(0.0f);
240
+
241
+ // loop along K in block granularity, skip 4 blocks every iter
242
+ for (uint k = groupId; k < (K / QK4_NL); k += NSUBGROUPS) {
243
+ regS = src0_d[gid + k * LINE_STRIDE_A]; // each fiber loads scale of two rows
244
+ // first 4 fibers in each wave load 8 B values to its private scope
245
+ if (slid < 4) {
246
+ regB.s0123 = read_imagef(src1, (slid * 2 + k * 8));
247
+ regB.s4567 = read_imagef(src1, (1 + slid * 2 + k * 8));
248
+ }
249
+
250
+ // load half weights for two blocks in consecutive rows
251
+ regA.s0 = read_imageui(src0_q, (gid + k * BLOCK_STRIDE_A + LINE_STRIDE_A * 0)).x;
252
+ regA.s1 = read_imageui(src0_q, (gid + k * BLOCK_STRIDE_A + LINE_STRIDE_A * 1)).x;
253
+ regA.s2 = read_imageui(src0_q, (gid + k * BLOCK_STRIDE_A + LINE_STRIDE_A * 2)).x;
254
+ regA.s3 = read_imageui(src0_q, (gid + k * BLOCK_STRIDE_A + LINE_STRIDE_A * 3)).x;
255
+ #ifdef VECTOR_SUB_GROUP_BROADCAST
256
+ dequantizeBlockAccum_ns_sgbroadcast_8_hi(totalSum, as_ushort8(regA), regS, regB);
257
+ #else
258
+ dequantizeBlockAccum_ns_sgbroadcast_1_hi(totalSum, as_ushort8(regA), regS, regB);
259
+ #endif // VECTOR_SUB_GROUP_BROADCAST
260
+
261
+ regA.s0 = read_imageui(src0_q, (gid + k * BLOCK_STRIDE_A + LINE_STRIDE_A * 4)).x;
262
+ regA.s1 = read_imageui(src0_q, (gid + k * BLOCK_STRIDE_A + LINE_STRIDE_A * 5)).x;
263
+ regA.s2 = read_imageui(src0_q, (gid + k * BLOCK_STRIDE_A + LINE_STRIDE_A * 6)).x;
264
+ regA.s3 = read_imageui(src0_q, (gid + k * BLOCK_STRIDE_A + LINE_STRIDE_A * 7)).x;
265
+ #ifdef VECTOR_SUB_GROUP_BROADCAST
266
+ dequantizeBlockAccum_ns_sgbroadcast_8_lo(totalSum, as_ushort8(regA), regS, regB);
267
+ #else
268
+ dequantizeBlockAccum_ns_sgbroadcast_1_lo(totalSum, as_ushort8(regA), regS, regB);
269
+ #endif // VECTOR_SUB_GROUP_BROADCAST
270
+ }
271
+
272
+ // reduction in local memory, assumes #wave=4
273
+ local float2 reduceLM[SUBGROUP_SIZE * 3];
274
+ if (groupId == 1) {
275
+ reduceLM[SUBGROUP_SIZE * 0 + slid] = totalSum;
276
+ }
277
+ if (groupId == 2) {
278
+ reduceLM[SUBGROUP_SIZE * 1 + slid] = totalSum;
279
+ }
280
+ if (groupId == 3) {
281
+ reduceLM[SUBGROUP_SIZE * 2 + slid] = totalSum;
282
+ }
283
+
284
+ barrier(CLK_LOCAL_MEM_FENCE);
285
+
286
+ if (groupId == 0) {
287
+ totalSum += reduceLM[SUBGROUP_SIZE * 0 + slid];
288
+ }
289
+ if (groupId == 0) {
290
+ totalSum += reduceLM[SUBGROUP_SIZE * 1 + slid];
291
+ }
292
+ if (groupId == 0) {
293
+ totalSum += reduceLM[SUBGROUP_SIZE * 2 + slid];
294
+ }
295
+
296
+ // 2 outputs per fiber in wave 0
297
+ if (groupId == 0) {
298
+ dst = (global float*)((global char*)dst + offsetd);
299
+ vstore2(totalSum, 0, &(dst[gid * 2]));
300
+ }
301
+
302
+ }
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemv_noshuffle_q1_0_f32.cl ADDED
@@ -0,0 +1,121 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #pragma OPENCL EXTENSION cl_khr_fp16 : enable
2
+ #pragma OPENCL EXTENSION cl_khr_subgroups : enable
3
+
4
+ #ifdef cl_qcom_reqd_sub_group_size
5
+ #pragma OPENCL EXTENSION cl_qcom_reqd_sub_group_size : enable
6
+ #define ADRENO_GPU 1
7
+ #define REQD_SUBGROUP_SIZE_64 __attribute__((qcom_reqd_sub_group_size("half")))
8
+ #endif
9
+
10
+ #define QK1_0 128
11
+ #define N_SIMDGROUP 4
12
+
13
+ #define dequantizeBlockAccum_q1(total, bits, scale, regB, lb) \
14
+ total += (2.0f*(float)((bits >> 0) & 1u) - 1.0f) * scale * sub_group_broadcast(regB.s0, lb+0); \
15
+ total += (2.0f*(float)((bits >> 1) & 1u) - 1.0f) * scale * sub_group_broadcast(regB.s1, lb+0); \
16
+ total += (2.0f*(float)((bits >> 2) & 1u) - 1.0f) * scale * sub_group_broadcast(regB.s2, lb+0); \
17
+ total += (2.0f*(float)((bits >> 3) & 1u) - 1.0f) * scale * sub_group_broadcast(regB.s3, lb+0); \
18
+ total += (2.0f*(float)((bits >> 4) & 1u) - 1.0f) * scale * sub_group_broadcast(regB.s4, lb+0); \
19
+ total += (2.0f*(float)((bits >> 5) & 1u) - 1.0f) * scale * sub_group_broadcast(regB.s5, lb+0); \
20
+ total += (2.0f*(float)((bits >> 6) & 1u) - 1.0f) * scale * sub_group_broadcast(regB.s6, lb+0); \
21
+ total += (2.0f*(float)((bits >> 7) & 1u) - 1.0f) * scale * sub_group_broadcast(regB.s7, lb+0); \
22
+ total += (2.0f*(float)((bits >> 8) & 1u) - 1.0f) * scale * sub_group_broadcast(regB.s0, lb+1); \
23
+ total += (2.0f*(float)((bits >> 9) & 1u) - 1.0f) * scale * sub_group_broadcast(regB.s1, lb+1); \
24
+ total += (2.0f*(float)((bits >> 10) & 1u) - 1.0f) * scale * sub_group_broadcast(regB.s2, lb+1); \
25
+ total += (2.0f*(float)((bits >> 11) & 1u) - 1.0f) * scale * sub_group_broadcast(regB.s3, lb+1); \
26
+ total += (2.0f*(float)((bits >> 12) & 1u) - 1.0f) * scale * sub_group_broadcast(regB.s4, lb+1); \
27
+ total += (2.0f*(float)((bits >> 13) & 1u) - 1.0f) * scale * sub_group_broadcast(regB.s5, lb+1); \
28
+ total += (2.0f*(float)((bits >> 14) & 1u) - 1.0f) * scale * sub_group_broadcast(regB.s6, lb+1); \
29
+ total += (2.0f*(float)((bits >> 15) & 1u) - 1.0f) * scale * sub_group_broadcast(regB.s7, lb+1); \
30
+ total += (2.0f*(float)((bits >> 16) & 1u) - 1.0f) * scale * sub_group_broadcast(regB.s0, lb+2); \
31
+ total += (2.0f*(float)((bits >> 17) & 1u) - 1.0f) * scale * sub_group_broadcast(regB.s1, lb+2); \
32
+ total += (2.0f*(float)((bits >> 18) & 1u) - 1.0f) * scale * sub_group_broadcast(regB.s2, lb+2); \
33
+ total += (2.0f*(float)((bits >> 19) & 1u) - 1.0f) * scale * sub_group_broadcast(regB.s3, lb+2); \
34
+ total += (2.0f*(float)((bits >> 20) & 1u) - 1.0f) * scale * sub_group_broadcast(regB.s4, lb+2); \
35
+ total += (2.0f*(float)((bits >> 21) & 1u) - 1.0f) * scale * sub_group_broadcast(regB.s5, lb+2); \
36
+ total += (2.0f*(float)((bits >> 22) & 1u) - 1.0f) * scale * sub_group_broadcast(regB.s6, lb+2); \
37
+ total += (2.0f*(float)((bits >> 23) & 1u) - 1.0f) * scale * sub_group_broadcast(regB.s7, lb+2); \
38
+ total += (2.0f*(float)((bits >> 24) & 1u) - 1.0f) * scale * sub_group_broadcast(regB.s0, lb+3); \
39
+ total += (2.0f*(float)((bits >> 25) & 1u) - 1.0f) * scale * sub_group_broadcast(regB.s1, lb+3); \
40
+ total += (2.0f*(float)((bits >> 26) & 1u) - 1.0f) * scale * sub_group_broadcast(regB.s2, lb+3); \
41
+ total += (2.0f*(float)((bits >> 27) & 1u) - 1.0f) * scale * sub_group_broadcast(regB.s3, lb+3); \
42
+ total += (2.0f*(float)((bits >> 28) & 1u) - 1.0f) * scale * sub_group_broadcast(regB.s4, lb+3); \
43
+ total += (2.0f*(float)((bits >> 29) & 1u) - 1.0f) * scale * sub_group_broadcast(regB.s5, lb+3); \
44
+ total += (2.0f*(float)((bits >> 30) & 1u) - 1.0f) * scale * sub_group_broadcast(regB.s6, lb+3); \
45
+ total += (2.0f*(float)((bits >> 31) & 1u) - 1.0f) * scale * sub_group_broadcast(regB.s7, lb+3);
46
+
47
+
48
+ #ifdef ADRENO_GPU
49
+ REQD_SUBGROUP_SIZE_64
50
+ #endif
51
+ __kernel void kernel_gemv_noshuffle_q1_0_f32(
52
+ read_only image1d_buffer_t src0_q,
53
+ global half * src0_d,
54
+ read_only image1d_buffer_t src1,
55
+ ulong offset1,
56
+ global float * dst,
57
+ ulong offsetd,
58
+ int ne00,
59
+ int ne01,
60
+ int ne02,
61
+ int ne10,
62
+ int ne12,
63
+ int ne0,
64
+ int ne1,
65
+ int r2,
66
+ int r3)
67
+ {
68
+ uint groupId = get_local_id(1);
69
+ uint gid = get_global_id(0);
70
+ ushort slid = get_sub_group_local_id();
71
+
72
+ uint K = ne00;
73
+ uint M = ne01;
74
+
75
+ uint LINE_STRIDE_A = M;
76
+ uint BLOCK_STRIDE_A = 4 * M;
77
+
78
+ uint4 regA;
79
+ half regS;
80
+ float8 regB;
81
+
82
+ float totalSum = 0.0f;
83
+
84
+ #pragma unroll 1
85
+ for (uint kb = groupId; kb < (K / QK1_0); kb += N_SIMDGROUP) {
86
+ regS = src0_d[gid + kb * LINE_STRIDE_A]; // each fiber loads its row's scale
87
+
88
+ // first 16 fibers load 8 B values each -> 128 activations for this block
89
+ if (slid < 16) {
90
+ regB.s0123 = read_imagef(src1, (slid * 2 + kb * 32));
91
+ regB.s4567 = read_imagef(src1, (1 + slid * 2 + kb * 32));
92
+ }
93
+
94
+ // load this row's 4 uint32 (128 sign bits)
95
+ regA.s0 = read_imageui(src0_q, (gid + kb * BLOCK_STRIDE_A + LINE_STRIDE_A * 0)).x;
96
+ regA.s1 = read_imageui(src0_q, (gid + kb * BLOCK_STRIDE_A + LINE_STRIDE_A * 1)).x;
97
+ regA.s2 = read_imageui(src0_q, (gid + kb * BLOCK_STRIDE_A + LINE_STRIDE_A * 2)).x;
98
+ regA.s3 = read_imageui(src0_q, (gid + kb * BLOCK_STRIDE_A + LINE_STRIDE_A * 3)).x;
99
+
100
+ float scale = (float)regS;
101
+ dequantizeBlockAccum_q1(totalSum, regA.s0, scale, regB, 0);
102
+ dequantizeBlockAccum_q1(totalSum, regA.s1, scale, regB, 4);
103
+ dequantizeBlockAccum_q1(totalSum, regA.s2, scale, regB, 8);
104
+ dequantizeBlockAccum_q1(totalSum, regA.s3, scale, regB, 12);
105
+ }
106
+
107
+ // reduction in local memory, assumes #wave = N_SIMDGROUP = 4
108
+ local float reduceLM[SIMDGROUP_WIDTH * 3];
109
+ if (groupId == 1) reduceLM[SIMDGROUP_WIDTH * 0 + slid] = totalSum;
110
+ if (groupId == 2) reduceLM[SIMDGROUP_WIDTH * 1 + slid] = totalSum;
111
+ if (groupId == 3) reduceLM[SIMDGROUP_WIDTH * 2 + slid] = totalSum;
112
+ barrier(CLK_LOCAL_MEM_FENCE);
113
+ if (groupId == 0) totalSum += reduceLM[SIMDGROUP_WIDTH * 0 + slid];
114
+ if (groupId == 0) totalSum += reduceLM[SIMDGROUP_WIDTH * 1 + slid];
115
+ if (groupId == 0) totalSum += reduceLM[SIMDGROUP_WIDTH * 2 + slid];
116
+
117
+ if (groupId == 0) {
118
+ dst = (global float*)((global char*)dst + offsetd);
119
+ dst[gid] = totalSum;
120
+ }
121
+ }
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemv_noshuffle_q4_0_f32.cl ADDED
@@ -0,0 +1,274 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #pragma OPENCL EXTENSION cl_khr_fp16 : enable
2
+ #pragma OPENCL EXTENSION cl_khr_subgroups : enable
3
+
4
+ #ifdef cl_qcom_reqd_sub_group_size
5
+ #pragma OPENCL EXTENSION cl_qcom_reqd_sub_group_size : enable
6
+ #define ADRENO_GPU 1
7
+ #define REQD_SUBGROUP_SIZE_64 __attribute__((qcom_reqd_sub_group_size("half")))
8
+ #endif
9
+
10
+ // assume
11
+ #define QK4_0 32
12
+ #define N_SIMDGROUP 4
13
+
14
+ #define dequantizeBlockAccum_ns_sgbroadcast_1_hi(total_sums, bits4, scale, y) \
15
+ float shared_y; \
16
+ shared_y = sub_group_broadcast(y.s0, 0); \
17
+ total_sums.s0 += ((bits4.s0 & 0x000F) - 8) * scale.s0 * shared_y; \
18
+ total_sums.s1 += ((bits4.s1 & 0x000F) - 8) * scale.s1 * shared_y; \
19
+ shared_y = sub_group_broadcast(y.s1, 0); \
20
+ total_sums.s0 += (((bits4.s0 & 0x00F0) >> 4) - 8) * scale.s0 * shared_y; \
21
+ total_sums.s1 += (((bits4.s1 & 0x00F0) >> 4) - 8) * scale.s1 * shared_y; \
22
+ shared_y = sub_group_broadcast(y.s2, 0); \
23
+ total_sums.s0 += (((bits4.s0 & 0x0F00) >> 8) - 8) * scale.s0 * shared_y; \
24
+ total_sums.s1 += (((bits4.s1 & 0x0F00) >> 8) - 8) * scale.s1 * shared_y; \
25
+ shared_y = sub_group_broadcast(y.s3, 0); \
26
+ total_sums.s0 += (((bits4.s0 & 0xF000) >> 12) - 8) * scale.s0 * shared_y; \
27
+ total_sums.s1 += (((bits4.s1 & 0xF000) >> 12) - 8) * scale.s1 * shared_y; \
28
+ shared_y = sub_group_broadcast(y.s4, 0); \
29
+ total_sums.s0 += ((bits4.s2 & 0x000F) - 8) * scale.s0 * shared_y; \
30
+ total_sums.s1 += ((bits4.s3 & 0x000F) - 8) * scale.s1 * shared_y; \
31
+ shared_y = sub_group_broadcast(y.s5, 0); \
32
+ total_sums.s0 += (((bits4.s2 & 0x00F0) >> 4) - 8) * scale.s0 * shared_y; \
33
+ total_sums.s1 += (((bits4.s3 & 0x00F0) >> 4) - 8) * scale.s1 * shared_y; \
34
+ shared_y = sub_group_broadcast(y.s6, 0); \
35
+ total_sums.s0 += (((bits4.s2 & 0x0F00) >> 8) - 8) * scale.s0 * shared_y; \
36
+ total_sums.s1 += (((bits4.s3 & 0x0F00) >> 8) - 8) * scale.s1 * shared_y; \
37
+ shared_y = sub_group_broadcast(y.s7, 0); \
38
+ total_sums.s0 += (((bits4.s2 & 0xF000) >> 12) - 8) * scale.s0 * shared_y; \
39
+ total_sums.s1 += (((bits4.s3 & 0xF000) >> 12) - 8) * scale.s1 * shared_y; \
40
+ shared_y = sub_group_broadcast(y.s0, 1); \
41
+ total_sums.s0 += ((bits4.s4 & 0x000F) - 8) * scale.s0 * shared_y; \
42
+ total_sums.s1 += ((bits4.s5 & 0x000F) - 8) * scale.s1 * shared_y; \
43
+ shared_y = sub_group_broadcast(y.s1, 1); \
44
+ total_sums.s0 += (((bits4.s4 & 0x00F0) >> 4) - 8) * scale.s0 * shared_y; \
45
+ total_sums.s1 += (((bits4.s5 & 0x00F0) >> 4) - 8) * scale.s1 * shared_y; \
46
+ shared_y = sub_group_broadcast(y.s2, 1); \
47
+ total_sums.s0 += (((bits4.s4 & 0x0F00) >> 8) - 8) * scale.s0 * shared_y; \
48
+ total_sums.s1 += (((bits4.s5 & 0x0F00) >> 8) - 8) * scale.s1 * shared_y; \
49
+ shared_y = sub_group_broadcast(y.s3, 1); \
50
+ total_sums.s0 += (((bits4.s4 & 0xF000) >> 12) - 8) * scale.s0 * shared_y; \
51
+ total_sums.s1 += (((bits4.s5 & 0xF000) >> 12) - 8) * scale.s1 * shared_y; \
52
+ shared_y = sub_group_broadcast(y.s4, 1); \
53
+ total_sums.s0 += ((bits4.s6 & 0x000F) - 8) * scale.s0 * shared_y; \
54
+ total_sums.s1 += ((bits4.s7 & 0x000F) - 8) * scale.s1 * shared_y; \
55
+ shared_y = sub_group_broadcast(y.s5, 1); \
56
+ total_sums.s0 += (((bits4.s6 & 0x00F0) >> 4) - 8) * scale.s0 * shared_y; \
57
+ total_sums.s1 += (((bits4.s7 & 0x00F0) >> 4) - 8) * scale.s1 * shared_y; \
58
+ shared_y = sub_group_broadcast(y.s6, 1); \
59
+ total_sums.s0 += (((bits4.s6 & 0x0F00) >> 8) - 8) * scale.s0 * shared_y; \
60
+ total_sums.s1 += (((bits4.s7 & 0x0F00) >> 8) - 8) * scale.s1 * shared_y; \
61
+ shared_y = sub_group_broadcast(y.s7, 1); \
62
+ total_sums.s0 += (((bits4.s6 & 0xF000) >> 12) - 8) * scale.s0 * shared_y; \
63
+ total_sums.s1 += (((bits4.s7 & 0xF000) >> 12) - 8) * scale.s1 * shared_y; \
64
+
65
+
66
+ #define dequantizeBlockAccum_ns_sgbroadcast_1_lo(total_sums, bits4, scale, y) \
67
+ shared_y = sub_group_broadcast(y.s0, 2); \
68
+ total_sums.s0 += ((bits4.s0 & 0x000F) - 8) * scale.s0 * shared_y; \
69
+ total_sums.s1 += ((bits4.s1 & 0x000F) - 8) * scale.s1 * shared_y; \
70
+ shared_y = sub_group_broadcast(y.s1, 2); \
71
+ total_sums.s0 += (((bits4.s0 & 0x00F0) >> 4) - 8) * scale.s0 * shared_y; \
72
+ total_sums.s1 += (((bits4.s1 & 0x00F0) >> 4) - 8) * scale.s1 * shared_y; \
73
+ shared_y = sub_group_broadcast(y.s2, 2); \
74
+ total_sums.s0 += (((bits4.s0 & 0x0F00) >> 8) - 8) * scale.s0 * shared_y; \
75
+ total_sums.s1 += (((bits4.s1 & 0x0F00) >> 8) - 8) * scale.s1 * shared_y; \
76
+ shared_y = sub_group_broadcast(y.s3, 2); \
77
+ total_sums.s0 += (((bits4.s0 & 0xF000) >> 12) - 8) * scale.s0 * shared_y; \
78
+ total_sums.s1 += (((bits4.s1 & 0xF000) >> 12) - 8) * scale.s1 * shared_y; \
79
+ shared_y = sub_group_broadcast(y.s4, 2); \
80
+ total_sums.s0 += ((bits4.s2 & 0x000F) - 8) * scale.s0 * shared_y; \
81
+ total_sums.s1 += ((bits4.s3 & 0x000F) - 8) * scale.s1 * shared_y; \
82
+ shared_y = sub_group_broadcast(y.s5, 2); \
83
+ total_sums.s0 += (((bits4.s2 & 0x00F0) >> 4) - 8) * scale.s0 * shared_y; \
84
+ total_sums.s1 += (((bits4.s3 & 0x00F0) >> 4) - 8) * scale.s1 * shared_y; \
85
+ shared_y = sub_group_broadcast(y.s6, 2); \
86
+ total_sums.s0 += (((bits4.s2 & 0x0F00) >> 8) - 8) * scale.s0 * shared_y; \
87
+ total_sums.s1 += (((bits4.s3 & 0x0F00) >> 8) - 8) * scale.s1 * shared_y; \
88
+ shared_y = sub_group_broadcast(y.s7, 2); \
89
+ total_sums.s0 += (((bits4.s2 & 0xF000) >> 12) - 8) * scale.s0 * shared_y; \
90
+ total_sums.s1 += (((bits4.s3 & 0xF000) >> 12) - 8) * scale.s1 * shared_y; \
91
+ shared_y = sub_group_broadcast(y.s0, 3); \
92
+ total_sums.s0 += ((bits4.s4 & 0x000F) - 8) * scale.s0 * shared_y; \
93
+ total_sums.s1 += ((bits4.s5 & 0x000F) - 8) * scale.s1 * shared_y; \
94
+ shared_y = sub_group_broadcast(y.s1, 3); \
95
+ total_sums.s0 += (((bits4.s4 & 0x00F0) >> 4) - 8) * scale.s0 * shared_y; \
96
+ total_sums.s1 += (((bits4.s5 & 0x00F0) >> 4) - 8) * scale.s1 * shared_y; \
97
+ shared_y = sub_group_broadcast(y.s2, 3); \
98
+ total_sums.s0 += (((bits4.s4 & 0x0F00) >> 8) - 8) * scale.s0 * shared_y; \
99
+ total_sums.s1 += (((bits4.s5 & 0x0F00) >> 8) - 8) * scale.s1 * shared_y; \
100
+ shared_y = sub_group_broadcast(y.s3, 3); \
101
+ total_sums.s0 += (((bits4.s4 & 0xF000) >> 12) - 8) * scale.s0 * shared_y; \
102
+ total_sums.s1 += (((bits4.s5 & 0xF000) >> 12) - 8) * scale.s1 * shared_y; \
103
+ shared_y = sub_group_broadcast(y.s4, 3); \
104
+ total_sums.s0 += ((bits4.s6 & 0x000F) - 8) * scale.s0 * shared_y; \
105
+ total_sums.s1 += ((bits4.s7 & 0x000F) - 8) * scale.s1 * shared_y; \
106
+ shared_y = sub_group_broadcast(y.s5, 3); \
107
+ total_sums.s0 += (((bits4.s6 & 0x00F0) >> 4) - 8) * scale.s0 * shared_y; \
108
+ total_sums.s1 += (((bits4.s7 & 0x00F0) >> 4) - 8) * scale.s1 * shared_y; \
109
+ shared_y = sub_group_broadcast(y.s6, 3); \
110
+ total_sums.s0 += (((bits4.s6 & 0x0F00) >> 8) - 8) * scale.s0 * shared_y; \
111
+ total_sums.s1 += (((bits4.s7 & 0x0F00) >> 8) - 8) * scale.s1 * shared_y; \
112
+ shared_y = sub_group_broadcast(y.s7, 3); \
113
+ total_sums.s0 += (((bits4.s6 & 0xF000) >> 12) - 8) * scale.s0 * shared_y; \
114
+ total_sums.s1 += (((bits4.s7 & 0xF000) >> 12) - 8) * scale.s1 * shared_y; \
115
+
116
+
117
+ #define dequantizeBlockAccum_ns_sgbroadcast_8_hi(total_sums, bits4, scale, y) \
118
+ float8 shared_y; \
119
+ shared_y = sub_group_broadcast(y, 0); \
120
+ total_sums.s0 += ((bits4.s0 & 0x000F) - 8) * scale.s0 * shared_y.s0; \
121
+ total_sums.s0 += (((bits4.s0 & 0x00F0) >> 4) - 8) * scale.s0 * shared_y.s1; \
122
+ total_sums.s0 += (((bits4.s0 & 0x0F00) >> 8) - 8) * scale.s0 * shared_y.s2; \
123
+ total_sums.s0 += (((bits4.s0 & 0xF000) >> 12) - 8) * scale.s0 * shared_y.s3; \
124
+ total_sums.s0 += ((bits4.s2 & 0x000F) - 8) * scale.s0 * shared_y.s4; \
125
+ total_sums.s0 += (((bits4.s2 & 0x00F0) >> 4) - 8) * scale.s0 * shared_y.s5; \
126
+ total_sums.s0 += (((bits4.s2 & 0x0F00) >> 8) - 8) * scale.s0 * shared_y.s6; \
127
+ total_sums.s0 += (((bits4.s2 & 0xF000) >> 12) - 8) * scale.s0 * shared_y.s7; \
128
+ total_sums.s1 += ((bits4.s1 & 0x000F) - 8) * scale.s1 * shared_y.s0; \
129
+ total_sums.s1 += (((bits4.s1 & 0x00F0) >> 4) - 8) * scale.s1 * shared_y.s1; \
130
+ total_sums.s1 += (((bits4.s1 & 0x0F00) >> 8) - 8) * scale.s1 * shared_y.s2; \
131
+ total_sums.s1 += (((bits4.s1 & 0xF000) >> 12) - 8) * scale.s1 * shared_y.s3; \
132
+ total_sums.s1 += ((bits4.s3 & 0x000F) - 8) * scale.s1 * shared_y.s4; \
133
+ total_sums.s1 += (((bits4.s3 & 0x00F0) >> 4) - 8) * scale.s1 * shared_y.s5; \
134
+ total_sums.s1 += (((bits4.s3 & 0x0F00) >> 8) - 8) * scale.s1 * shared_y.s6; \
135
+ total_sums.s1 += (((bits4.s3 & 0xF000) >> 12) - 8) * scale.s1 * shared_y.s7; \
136
+ shared_y = sub_group_broadcast(y, 1); \
137
+ total_sums.s0 += ((bits4.s4 & 0x000F) - 8) * scale.s0 * shared_y.s0; \
138
+ total_sums.s0 += (((bits4.s4 & 0x00F0) >> 4) - 8) * scale.s0 * shared_y.s1; \
139
+ total_sums.s0 += (((bits4.s4 & 0x0F00) >> 8) - 8) * scale.s0 * shared_y.s2; \
140
+ total_sums.s0 += (((bits4.s4 & 0xF000) >> 12) - 8) * scale.s0 * shared_y.s3; \
141
+ total_sums.s0 += ((bits4.s6 & 0x000F) - 8) * scale.s0 * shared_y.s4; \
142
+ total_sums.s0 += (((bits4.s6 & 0x00F0) >> 4) - 8) * scale.s0 * shared_y.s5; \
143
+ total_sums.s0 += (((bits4.s6 & 0x0F00) >> 8) - 8) * scale.s0 * shared_y.s6; \
144
+ total_sums.s0 += (((bits4.s6 & 0xF000) >> 12) - 8) * scale.s0 * shared_y.s7; \
145
+ total_sums.s1 += ((bits4.s5 & 0x000F) - 8) * scale.s1 * shared_y.s0; \
146
+ total_sums.s1 += (((bits4.s5 & 0x00F0) >> 4) - 8) * scale.s1 * shared_y.s1; \
147
+ total_sums.s1 += (((bits4.s5 & 0x0F00) >> 8) - 8) * scale.s1 * shared_y.s2; \
148
+ total_sums.s1 += (((bits4.s5 & 0xF000) >> 12) - 8) * scale.s1 * shared_y.s3; \
149
+ total_sums.s1 += ((bits4.s7 & 0x000F) - 8) * scale.s1 * shared_y.s4; \
150
+ total_sums.s1 += (((bits4.s7 & 0x00F0) >> 4) - 8) * scale.s1 * shared_y.s5; \
151
+ total_sums.s1 += (((bits4.s7 & 0x0F00) >> 8) - 8) * scale.s1 * shared_y.s6; \
152
+ total_sums.s1 += (((bits4.s7 & 0xF000) >> 12) - 8) * scale.s1 * shared_y.s7; \
153
+
154
+
155
+ #define dequantizeBlockAccum_ns_sgbroadcast_8_lo(total_sums, bits4, scale, y) \
156
+ shared_y = sub_group_broadcast(y, 2); \
157
+ total_sums.s0 += ((bits4.s0 & 0x000F) - 8) * scale.s0 * shared_y.s0; \
158
+ total_sums.s0 += (((bits4.s0 & 0x00F0) >> 4) - 8) * scale.s0 * shared_y.s1; \
159
+ total_sums.s0 += (((bits4.s0 & 0x0F00) >> 8) - 8) * scale.s0 * shared_y.s2; \
160
+ total_sums.s0 += (((bits4.s0 & 0xF000) >> 12) - 8) * scale.s0 * shared_y.s3; \
161
+ total_sums.s0 += ((bits4.s2 & 0x000F) - 8) * scale.s0 * shared_y.s4; \
162
+ total_sums.s0 += (((bits4.s2 & 0x00F0) >> 4) - 8) * scale.s0 * shared_y.s5; \
163
+ total_sums.s0 += (((bits4.s2 & 0x0F00) >> 8) - 8) * scale.s0 * shared_y.s6; \
164
+ total_sums.s0 += (((bits4.s2 & 0xF000) >> 12) - 8) * scale.s0 * shared_y.s7; \
165
+ total_sums.s1 += ((bits4.s1 & 0x000F) - 8) * scale.s1 * shared_y.s0; \
166
+ total_sums.s1 += (((bits4.s1 & 0x00F0) >> 4) - 8) * scale.s1 * shared_y.s1; \
167
+ total_sums.s1 += (((bits4.s1 & 0x0F00) >> 8) - 8) * scale.s1 * shared_y.s2; \
168
+ total_sums.s1 += (((bits4.s1 & 0xF000) >> 12) - 8) * scale.s1 * shared_y.s3; \
169
+ total_sums.s1 += ((bits4.s3 & 0x000F) - 8) * scale.s1 * shared_y.s4; \
170
+ total_sums.s1 += (((bits4.s3 & 0x00F0) >> 4) - 8) * scale.s1 * shared_y.s5; \
171
+ total_sums.s1 += (((bits4.s3 & 0x0F00) >> 8) - 8) * scale.s1 * shared_y.s6; \
172
+ total_sums.s1 += (((bits4.s3 & 0xF000) >> 12) - 8) * scale.s1 * shared_y.s7; \
173
+ shared_y = sub_group_broadcast(y, 3); \
174
+ total_sums.s0 += ((bits4.s4 & 0x000F) - 8) * scale.s0 * shared_y.s0; \
175
+ total_sums.s0 += (((bits4.s4 & 0x00F0) >> 4) - 8) * scale.s0 * shared_y.s1; \
176
+ total_sums.s0 += (((bits4.s4 & 0x0F00) >> 8) - 8) * scale.s0 * shared_y.s2; \
177
+ total_sums.s0 += (((bits4.s4 & 0xF000) >> 12) - 8) * scale.s0 * shared_y.s3; \
178
+ total_sums.s0 += ((bits4.s6 & 0x000F) - 8) * scale.s0 * shared_y.s4; \
179
+ total_sums.s0 += (((bits4.s6 & 0x00F0) >> 4) - 8) * scale.s0 * shared_y.s5; \
180
+ total_sums.s0 += (((bits4.s6 & 0x0F00) >> 8) - 8) * scale.s0 * shared_y.s6; \
181
+ total_sums.s0 += (((bits4.s6 & 0xF000) >> 12) - 8) * scale.s0 * shared_y.s7; \
182
+ total_sums.s1 += ((bits4.s5 & 0x000F) - 8) * scale.s1 * shared_y.s0; \
183
+ total_sums.s1 += (((bits4.s5 & 0x00F0) >> 4) - 8) * scale.s1 * shared_y.s1; \
184
+ total_sums.s1 += (((bits4.s5 & 0x0F00) >> 8) - 8) * scale.s1 * shared_y.s2; \
185
+ total_sums.s1 += (((bits4.s5 & 0xF000) >> 12) - 8) * scale.s1 * shared_y.s3; \
186
+ total_sums.s1 += ((bits4.s7 & 0x000F) - 8) * scale.s1 * shared_y.s4; \
187
+ total_sums.s1 += (((bits4.s7 & 0x00F0) >> 4) - 8) * scale.s1 * shared_y.s5; \
188
+ total_sums.s1 += (((bits4.s7 & 0x0F00) >> 8) - 8) * scale.s1 * shared_y.s6; \
189
+ total_sums.s1 += (((bits4.s7 & 0xF000) >> 12) - 8) * scale.s1 * shared_y.s7; \
190
+
191
+ #ifdef ADRENO_GPU
192
+ REQD_SUBGROUP_SIZE_64
193
+ #endif
194
+ __kernel void kernel_gemv_noshuffle_q4_0_f32(
195
+ __read_only image1d_buffer_t src0_q, // quantized A
196
+ global half2 * src0_d, // A scales
197
+ __read_only image1d_buffer_t src1, // B
198
+ ulong offset1, // offset to B (0)
199
+ global float * dst, // C
200
+ ulong offsetd, // offset to C (0)
201
+ int ne00, // K
202
+ int ne01, // M
203
+ int ne02, // 1
204
+ int ne10, // K
205
+ int ne12, // 1
206
+ int ne0, // M
207
+ int ne1, // N
208
+ int r2, // 1
209
+ int r3)
210
+ {
211
+ uint groupId = get_local_id(1);
212
+ uint gid = get_global_id(0);
213
+ ushort slid = get_sub_group_local_id();
214
+
215
+ uint K = ne00;
216
+ uint M = ne01;
217
+
218
+ uint LINE_STRIDE_A = M / 2;
219
+ uint BLOCK_STRIDE_A = N_SIMDGROUP * M;
220
+
221
+ __private uint4 regA;
222
+ __private half2 regS;
223
+ __private float8 regB;
224
+
225
+ __private float2 totalSum = (float2)(0.0f);
226
+
227
+ // loop along K in block granularity, skip 4 blocks every iter
228
+ for (uint k = groupId; k < (K / QK4_0); k += N_SIMDGROUP) {
229
+ regS = src0_d[gid + k * LINE_STRIDE_A]; // each fiber loads scale of two rows
230
+ // first 4 fibers in each wave load 8 B values to its private scope
231
+ if (slid < 4) {
232
+ regB.s0123 = read_imagef(src1, (slid * 2 + k * 8));
233
+ regB.s4567 = read_imagef(src1, (1 + slid * 2 + k * 8));
234
+ }
235
+
236
+ // load half weights for two blocks in consecutive rows
237
+ regA.s0 = read_imageui(src0_q, (gid + k * BLOCK_STRIDE_A + LINE_STRIDE_A * 0)).x;
238
+ regA.s1 = read_imageui(src0_q, (gid + k * BLOCK_STRIDE_A + LINE_STRIDE_A * 1)).x;
239
+ regA.s2 = read_imageui(src0_q, (gid + k * BLOCK_STRIDE_A + LINE_STRIDE_A * 2)).x;
240
+ regA.s3 = read_imageui(src0_q, (gid + k * BLOCK_STRIDE_A + LINE_STRIDE_A * 3)).x;
241
+ #ifdef VECTOR_SUB_GROUP_BROADCAST
242
+ dequantizeBlockAccum_ns_sgbroadcast_8_hi(totalSum, as_ushort8(regA), regS, regB);
243
+ #else
244
+ dequantizeBlockAccum_ns_sgbroadcast_1_hi(totalSum, as_ushort8(regA), regS, regB);
245
+ #endif // VECTOR_SUB_GROUP_BROADCAST
246
+
247
+ regA.s0 = read_imageui(src0_q, (gid + k * BLOCK_STRIDE_A + LINE_STRIDE_A * 4)).x;
248
+ regA.s1 = read_imageui(src0_q, (gid + k * BLOCK_STRIDE_A + LINE_STRIDE_A * 5)).x;
249
+ regA.s2 = read_imageui(src0_q, (gid + k * BLOCK_STRIDE_A + LINE_STRIDE_A * 6)).x;
250
+ regA.s3 = read_imageui(src0_q, (gid + k * BLOCK_STRIDE_A + LINE_STRIDE_A * 7)).x;
251
+ #ifdef VECTOR_SUB_GROUP_BROADCAST
252
+ dequantizeBlockAccum_ns_sgbroadcast_8_lo(totalSum, as_ushort8(regA), regS, regB);
253
+ #else
254
+ dequantizeBlockAccum_ns_sgbroadcast_1_lo(totalSum, as_ushort8(regA), regS, regB);
255
+ #endif // VECTOR_SUB_GROUP_BROADCAST
256
+ }
257
+
258
+ // reduction in local memory, assumes #wave=4
259
+ __local float2 reduceLM[SIMDGROUP_WIDTH * 3];
260
+ if (groupId == 1) reduceLM[SIMDGROUP_WIDTH * 0 + slid] = totalSum;
261
+ if (groupId == 2) reduceLM[SIMDGROUP_WIDTH * 1 + slid] = totalSum;
262
+ if (groupId == 3) reduceLM[SIMDGROUP_WIDTH * 2 + slid] = totalSum;
263
+ barrier(CLK_LOCAL_MEM_FENCE);
264
+ if (groupId == 0) totalSum += reduceLM[SIMDGROUP_WIDTH * 0 + slid];
265
+ if (groupId == 0) totalSum += reduceLM[SIMDGROUP_WIDTH * 1 + slid];
266
+ if (groupId == 0) totalSum += reduceLM[SIMDGROUP_WIDTH * 2 + slid];
267
+
268
+ // 2 outputs per fiber in wave 0
269
+ if (groupId == 0) {
270
+ dst = (global float*)((global char*)dst + offsetd);
271
+ vstore2(totalSum, 0, &(dst[gid * 2]));
272
+ }
273
+
274
+ }
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemv_noshuffle_q4_0_f32_spec.cl ADDED
@@ -0,0 +1,268 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #pragma OPENCL EXTENSION cl_khr_fp16 : enable
2
+ #pragma OPENCL EXTENSION cl_khr_subgroups : enable
3
+
4
+ #ifdef cl_qcom_reqd_sub_group_size
5
+ #pragma OPENCL EXTENSION cl_qcom_reqd_sub_group_size : enable
6
+ #define ADRENO_GPU 1
7
+ #define REQD_SUBGROUP_SIZE_64 __attribute__((qcom_reqd_sub_group_size("half")))
8
+ #endif
9
+
10
+ // assume
11
+ #define QK4_0 32
12
+ #define N_SIMDGROUP 4
13
+
14
+ #define dequantizeBlockAccum_ns_sgbroadcast_1_hi(total_sums, bits4, scale, y) \
15
+ float shared_y; \
16
+ shared_y = sub_group_broadcast(y.s0, 0); \
17
+ total_sums.s0 += ((bits4.s0 & 0x000F) - 8) * scale.s0 * shared_y; \
18
+ total_sums.s1 += ((bits4.s1 & 0x000F) - 8) * scale.s1 * shared_y; \
19
+ shared_y = sub_group_broadcast(y.s1, 0); \
20
+ total_sums.s0 += (((bits4.s0 & 0x00F0) >> 4) - 8) * scale.s0 * shared_y; \
21
+ total_sums.s1 += (((bits4.s1 & 0x00F0) >> 4) - 8) * scale.s1 * shared_y; \
22
+ shared_y = sub_group_broadcast(y.s2, 0); \
23
+ total_sums.s0 += (((bits4.s0 & 0x0F00) >> 8) - 8) * scale.s0 * shared_y; \
24
+ total_sums.s1 += (((bits4.s1 & 0x0F00) >> 8) - 8) * scale.s1 * shared_y; \
25
+ shared_y = sub_group_broadcast(y.s3, 0); \
26
+ total_sums.s0 += (((bits4.s0 & 0xF000) >> 12) - 8) * scale.s0 * shared_y; \
27
+ total_sums.s1 += (((bits4.s1 & 0xF000) >> 12) - 8) * scale.s1 * shared_y; \
28
+ shared_y = sub_group_broadcast(y.s4, 0); \
29
+ total_sums.s0 += ((bits4.s2 & 0x000F) - 8) * scale.s0 * shared_y; \
30
+ total_sums.s1 += ((bits4.s3 & 0x000F) - 8) * scale.s1 * shared_y; \
31
+ shared_y = sub_group_broadcast(y.s5, 0); \
32
+ total_sums.s0 += (((bits4.s2 & 0x00F0) >> 4) - 8) * scale.s0 * shared_y; \
33
+ total_sums.s1 += (((bits4.s3 & 0x00F0) >> 4) - 8) * scale.s1 * shared_y; \
34
+ shared_y = sub_group_broadcast(y.s6, 0); \
35
+ total_sums.s0 += (((bits4.s2 & 0x0F00) >> 8) - 8) * scale.s0 * shared_y; \
36
+ total_sums.s1 += (((bits4.s3 & 0x0F00) >> 8) - 8) * scale.s1 * shared_y; \
37
+ shared_y = sub_group_broadcast(y.s7, 0); \
38
+ total_sums.s0 += (((bits4.s2 & 0xF000) >> 12) - 8) * scale.s0 * shared_y; \
39
+ total_sums.s1 += (((bits4.s3 & 0xF000) >> 12) - 8) * scale.s1 * shared_y; \
40
+ shared_y = sub_group_broadcast(y.s0, 1); \
41
+ total_sums.s0 += ((bits4.s4 & 0x000F) - 8) * scale.s0 * shared_y; \
42
+ total_sums.s1 += ((bits4.s5 & 0x000F) - 8) * scale.s1 * shared_y; \
43
+ shared_y = sub_group_broadcast(y.s1, 1); \
44
+ total_sums.s0 += (((bits4.s4 & 0x00F0) >> 4) - 8) * scale.s0 * shared_y; \
45
+ total_sums.s1 += (((bits4.s5 & 0x00F0) >> 4) - 8) * scale.s1 * shared_y; \
46
+ shared_y = sub_group_broadcast(y.s2, 1); \
47
+ total_sums.s0 += (((bits4.s4 & 0x0F00) >> 8) - 8) * scale.s0 * shared_y; \
48
+ total_sums.s1 += (((bits4.s5 & 0x0F00) >> 8) - 8) * scale.s1 * shared_y; \
49
+ shared_y = sub_group_broadcast(y.s3, 1); \
50
+ total_sums.s0 += (((bits4.s4 & 0xF000) >> 12) - 8) * scale.s0 * shared_y; \
51
+ total_sums.s1 += (((bits4.s5 & 0xF000) >> 12) - 8) * scale.s1 * shared_y; \
52
+ shared_y = sub_group_broadcast(y.s4, 1); \
53
+ total_sums.s0 += ((bits4.s6 & 0x000F) - 8) * scale.s0 * shared_y; \
54
+ total_sums.s1 += ((bits4.s7 & 0x000F) - 8) * scale.s1 * shared_y; \
55
+ shared_y = sub_group_broadcast(y.s5, 1); \
56
+ total_sums.s0 += (((bits4.s6 & 0x00F0) >> 4) - 8) * scale.s0 * shared_y; \
57
+ total_sums.s1 += (((bits4.s7 & 0x00F0) >> 4) - 8) * scale.s1 * shared_y; \
58
+ shared_y = sub_group_broadcast(y.s6, 1); \
59
+ total_sums.s0 += (((bits4.s6 & 0x0F00) >> 8) - 8) * scale.s0 * shared_y; \
60
+ total_sums.s1 += (((bits4.s7 & 0x0F00) >> 8) - 8) * scale.s1 * shared_y; \
61
+ shared_y = sub_group_broadcast(y.s7, 1); \
62
+ total_sums.s0 += (((bits4.s6 & 0xF000) >> 12) - 8) * scale.s0 * shared_y; \
63
+ total_sums.s1 += (((bits4.s7 & 0xF000) >> 12) - 8) * scale.s1 * shared_y; \
64
+
65
+
66
+ #define dequantizeBlockAccum_ns_sgbroadcast_1_lo(total_sums, bits4, scale, y) \
67
+ shared_y = sub_group_broadcast(y.s0, 2); \
68
+ total_sums.s0 += ((bits4.s0 & 0x000F) - 8) * scale.s0 * shared_y; \
69
+ total_sums.s1 += ((bits4.s1 & 0x000F) - 8) * scale.s1 * shared_y; \
70
+ shared_y = sub_group_broadcast(y.s1, 2); \
71
+ total_sums.s0 += (((bits4.s0 & 0x00F0) >> 4) - 8) * scale.s0 * shared_y; \
72
+ total_sums.s1 += (((bits4.s1 & 0x00F0) >> 4) - 8) * scale.s1 * shared_y; \
73
+ shared_y = sub_group_broadcast(y.s2, 2); \
74
+ total_sums.s0 += (((bits4.s0 & 0x0F00) >> 8) - 8) * scale.s0 * shared_y; \
75
+ total_sums.s1 += (((bits4.s1 & 0x0F00) >> 8) - 8) * scale.s1 * shared_y; \
76
+ shared_y = sub_group_broadcast(y.s3, 2); \
77
+ total_sums.s0 += (((bits4.s0 & 0xF000) >> 12) - 8) * scale.s0 * shared_y; \
78
+ total_sums.s1 += (((bits4.s1 & 0xF000) >> 12) - 8) * scale.s1 * shared_y; \
79
+ shared_y = sub_group_broadcast(y.s4, 2); \
80
+ total_sums.s0 += ((bits4.s2 & 0x000F) - 8) * scale.s0 * shared_y; \
81
+ total_sums.s1 += ((bits4.s3 & 0x000F) - 8) * scale.s1 * shared_y; \
82
+ shared_y = sub_group_broadcast(y.s5, 2); \
83
+ total_sums.s0 += (((bits4.s2 & 0x00F0) >> 4) - 8) * scale.s0 * shared_y; \
84
+ total_sums.s1 += (((bits4.s3 & 0x00F0) >> 4) - 8) * scale.s1 * shared_y; \
85
+ shared_y = sub_group_broadcast(y.s6, 2); \
86
+ total_sums.s0 += (((bits4.s2 & 0x0F00) >> 8) - 8) * scale.s0 * shared_y; \
87
+ total_sums.s1 += (((bits4.s3 & 0x0F00) >> 8) - 8) * scale.s1 * shared_y; \
88
+ shared_y = sub_group_broadcast(y.s7, 2); \
89
+ total_sums.s0 += (((bits4.s2 & 0xF000) >> 12) - 8) * scale.s0 * shared_y; \
90
+ total_sums.s1 += (((bits4.s3 & 0xF000) >> 12) - 8) * scale.s1 * shared_y; \
91
+ shared_y = sub_group_broadcast(y.s0, 3); \
92
+ total_sums.s0 += ((bits4.s4 & 0x000F) - 8) * scale.s0 * shared_y; \
93
+ total_sums.s1 += ((bits4.s5 & 0x000F) - 8) * scale.s1 * shared_y; \
94
+ shared_y = sub_group_broadcast(y.s1, 3); \
95
+ total_sums.s0 += (((bits4.s4 & 0x00F0) >> 4) - 8) * scale.s0 * shared_y; \
96
+ total_sums.s1 += (((bits4.s5 & 0x00F0) >> 4) - 8) * scale.s1 * shared_y; \
97
+ shared_y = sub_group_broadcast(y.s2, 3); \
98
+ total_sums.s0 += (((bits4.s4 & 0x0F00) >> 8) - 8) * scale.s0 * shared_y; \
99
+ total_sums.s1 += (((bits4.s5 & 0x0F00) >> 8) - 8) * scale.s1 * shared_y; \
100
+ shared_y = sub_group_broadcast(y.s3, 3); \
101
+ total_sums.s0 += (((bits4.s4 & 0xF000) >> 12) - 8) * scale.s0 * shared_y; \
102
+ total_sums.s1 += (((bits4.s5 & 0xF000) >> 12) - 8) * scale.s1 * shared_y; \
103
+ shared_y = sub_group_broadcast(y.s4, 3); \
104
+ total_sums.s0 += ((bits4.s6 & 0x000F) - 8) * scale.s0 * shared_y; \
105
+ total_sums.s1 += ((bits4.s7 & 0x000F) - 8) * scale.s1 * shared_y; \
106
+ shared_y = sub_group_broadcast(y.s5, 3); \
107
+ total_sums.s0 += (((bits4.s6 & 0x00F0) >> 4) - 8) * scale.s0 * shared_y; \
108
+ total_sums.s1 += (((bits4.s7 & 0x00F0) >> 4) - 8) * scale.s1 * shared_y; \
109
+ shared_y = sub_group_broadcast(y.s6, 3); \
110
+ total_sums.s0 += (((bits4.s6 & 0x0F00) >> 8) - 8) * scale.s0 * shared_y; \
111
+ total_sums.s1 += (((bits4.s7 & 0x0F00) >> 8) - 8) * scale.s1 * shared_y; \
112
+ shared_y = sub_group_broadcast(y.s7, 3); \
113
+ total_sums.s0 += (((bits4.s6 & 0xF000) >> 12) - 8) * scale.s0 * shared_y; \
114
+ total_sums.s1 += (((bits4.s7 & 0xF000) >> 12) - 8) * scale.s1 * shared_y; \
115
+
116
+
117
+ #define dequantizeBlockAccum_ns_sgbroadcast_8_hi(total_sums, bits4, scale, y) \
118
+ float8 shared_y; \
119
+ shared_y = sub_group_broadcast(y, 0); \
120
+ total_sums.s0 += ((bits4.s0 & 0x000F) - 8) * scale.s0 * shared_y.s0; \
121
+ total_sums.s0 += (((bits4.s0 & 0x00F0) >> 4) - 8) * scale.s0 * shared_y.s1; \
122
+ total_sums.s0 += (((bits4.s0 & 0x0F00) >> 8) - 8) * scale.s0 * shared_y.s2; \
123
+ total_sums.s0 += (((bits4.s0 & 0xF000) >> 12) - 8) * scale.s0 * shared_y.s3; \
124
+ total_sums.s0 += ((bits4.s2 & 0x000F) - 8) * scale.s0 * shared_y.s4; \
125
+ total_sums.s0 += (((bits4.s2 & 0x00F0) >> 4) - 8) * scale.s0 * shared_y.s5; \
126
+ total_sums.s0 += (((bits4.s2 & 0x0F00) >> 8) - 8) * scale.s0 * shared_y.s6; \
127
+ total_sums.s0 += (((bits4.s2 & 0xF000) >> 12) - 8) * scale.s0 * shared_y.s7; \
128
+ total_sums.s1 += ((bits4.s1 & 0x000F) - 8) * scale.s1 * shared_y.s0; \
129
+ total_sums.s1 += (((bits4.s1 & 0x00F0) >> 4) - 8) * scale.s1 * shared_y.s1; \
130
+ total_sums.s1 += (((bits4.s1 & 0x0F00) >> 8) - 8) * scale.s1 * shared_y.s2; \
131
+ total_sums.s1 += (((bits4.s1 & 0xF000) >> 12) - 8) * scale.s1 * shared_y.s3; \
132
+ total_sums.s1 += ((bits4.s3 & 0x000F) - 8) * scale.s1 * shared_y.s4; \
133
+ total_sums.s1 += (((bits4.s3 & 0x00F0) >> 4) - 8) * scale.s1 * shared_y.s5; \
134
+ total_sums.s1 += (((bits4.s3 & 0x0F00) >> 8) - 8) * scale.s1 * shared_y.s6; \
135
+ total_sums.s1 += (((bits4.s3 & 0xF000) >> 12) - 8) * scale.s1 * shared_y.s7; \
136
+ shared_y = sub_group_broadcast(y, 1); \
137
+ total_sums.s0 += ((bits4.s4 & 0x000F) - 8) * scale.s0 * shared_y.s0; \
138
+ total_sums.s0 += (((bits4.s4 & 0x00F0) >> 4) - 8) * scale.s0 * shared_y.s1; \
139
+ total_sums.s0 += (((bits4.s4 & 0x0F00) >> 8) - 8) * scale.s0 * shared_y.s2; \
140
+ total_sums.s0 += (((bits4.s4 & 0xF000) >> 12) - 8) * scale.s0 * shared_y.s3; \
141
+ total_sums.s0 += ((bits4.s6 & 0x000F) - 8) * scale.s0 * shared_y.s4; \
142
+ total_sums.s0 += (((bits4.s6 & 0x00F0) >> 4) - 8) * scale.s0 * shared_y.s5; \
143
+ total_sums.s0 += (((bits4.s6 & 0x0F00) >> 8) - 8) * scale.s0 * shared_y.s6; \
144
+ total_sums.s0 += (((bits4.s6 & 0xF000) >> 12) - 8) * scale.s0 * shared_y.s7; \
145
+ total_sums.s1 += ((bits4.s5 & 0x000F) - 8) * scale.s1 * shared_y.s0; \
146
+ total_sums.s1 += (((bits4.s5 & 0x00F0) >> 4) - 8) * scale.s1 * shared_y.s1; \
147
+ total_sums.s1 += (((bits4.s5 & 0x0F00) >> 8) - 8) * scale.s1 * shared_y.s2; \
148
+ total_sums.s1 += (((bits4.s5 & 0xF000) >> 12) - 8) * scale.s1 * shared_y.s3; \
149
+ total_sums.s1 += ((bits4.s7 & 0x000F) - 8) * scale.s1 * shared_y.s4; \
150
+ total_sums.s1 += (((bits4.s7 & 0x00F0) >> 4) - 8) * scale.s1 * shared_y.s5; \
151
+ total_sums.s1 += (((bits4.s7 & 0x0F00) >> 8) - 8) * scale.s1 * shared_y.s6; \
152
+ total_sums.s1 += (((bits4.s7 & 0xF000) >> 12) - 8) * scale.s1 * shared_y.s7; \
153
+
154
+
155
+ #define dequantizeBlockAccum_ns_sgbroadcast_8_lo(total_sums, bits4, scale, y) \
156
+ shared_y = sub_group_broadcast(y, 2); \
157
+ total_sums.s0 += ((bits4.s0 & 0x000F) - 8) * scale.s0 * shared_y.s0; \
158
+ total_sums.s0 += (((bits4.s0 & 0x00F0) >> 4) - 8) * scale.s0 * shared_y.s1; \
159
+ total_sums.s0 += (((bits4.s0 & 0x0F00) >> 8) - 8) * scale.s0 * shared_y.s2; \
160
+ total_sums.s0 += (((bits4.s0 & 0xF000) >> 12) - 8) * scale.s0 * shared_y.s3; \
161
+ total_sums.s0 += ((bits4.s2 & 0x000F) - 8) * scale.s0 * shared_y.s4; \
162
+ total_sums.s0 += (((bits4.s2 & 0x00F0) >> 4) - 8) * scale.s0 * shared_y.s5; \
163
+ total_sums.s0 += (((bits4.s2 & 0x0F00) >> 8) - 8) * scale.s0 * shared_y.s6; \
164
+ total_sums.s0 += (((bits4.s2 & 0xF000) >> 12) - 8) * scale.s0 * shared_y.s7; \
165
+ total_sums.s1 += ((bits4.s1 & 0x000F) - 8) * scale.s1 * shared_y.s0; \
166
+ total_sums.s1 += (((bits4.s1 & 0x00F0) >> 4) - 8) * scale.s1 * shared_y.s1; \
167
+ total_sums.s1 += (((bits4.s1 & 0x0F00) >> 8) - 8) * scale.s1 * shared_y.s2; \
168
+ total_sums.s1 += (((bits4.s1 & 0xF000) >> 12) - 8) * scale.s1 * shared_y.s3; \
169
+ total_sums.s1 += ((bits4.s3 & 0x000F) - 8) * scale.s1 * shared_y.s4; \
170
+ total_sums.s1 += (((bits4.s3 & 0x00F0) >> 4) - 8) * scale.s1 * shared_y.s5; \
171
+ total_sums.s1 += (((bits4.s3 & 0x0F00) >> 8) - 8) * scale.s1 * shared_y.s6; \
172
+ total_sums.s1 += (((bits4.s3 & 0xF000) >> 12) - 8) * scale.s1 * shared_y.s7; \
173
+ shared_y = sub_group_broadcast(y, 3); \
174
+ total_sums.s0 += ((bits4.s4 & 0x000F) - 8) * scale.s0 * shared_y.s0; \
175
+ total_sums.s0 += (((bits4.s4 & 0x00F0) >> 4) - 8) * scale.s0 * shared_y.s1; \
176
+ total_sums.s0 += (((bits4.s4 & 0x0F00) >> 8) - 8) * scale.s0 * shared_y.s2; \
177
+ total_sums.s0 += (((bits4.s4 & 0xF000) >> 12) - 8) * scale.s0 * shared_y.s3; \
178
+ total_sums.s0 += ((bits4.s6 & 0x000F) - 8) * scale.s0 * shared_y.s4; \
179
+ total_sums.s0 += (((bits4.s6 & 0x00F0) >> 4) - 8) * scale.s0 * shared_y.s5; \
180
+ total_sums.s0 += (((bits4.s6 & 0x0F00) >> 8) - 8) * scale.s0 * shared_y.s6; \
181
+ total_sums.s0 += (((bits4.s6 & 0xF000) >> 12) - 8) * scale.s0 * shared_y.s7; \
182
+ total_sums.s1 += ((bits4.s5 & 0x000F) - 8) * scale.s1 * shared_y.s0; \
183
+ total_sums.s1 += (((bits4.s5 & 0x00F0) >> 4) - 8) * scale.s1 * shared_y.s1; \
184
+ total_sums.s1 += (((bits4.s5 & 0x0F00) >> 8) - 8) * scale.s1 * shared_y.s2; \
185
+ total_sums.s1 += (((bits4.s5 & 0xF000) >> 12) - 8) * scale.s1 * shared_y.s3; \
186
+ total_sums.s1 += ((bits4.s7 & 0x000F) - 8) * scale.s1 * shared_y.s4; \
187
+ total_sums.s1 += (((bits4.s7 & 0x00F0) >> 4) - 8) * scale.s1 * shared_y.s5; \
188
+ total_sums.s1 += (((bits4.s7 & 0x0F00) >> 8) - 8) * scale.s1 * shared_y.s6; \
189
+ total_sums.s1 += (((bits4.s7 & 0xF000) >> 12) - 8) * scale.s1 * shared_y.s7; \
190
+
191
+ #ifdef ADRENO_GPU
192
+ REQD_SUBGROUP_SIZE_64
193
+ #endif
194
+ __kernel void kernel_gemv_noshuffle_q4_0_f32(
195
+ __read_only image1d_buffer_t src0_q, // quantized A
196
+ global half2 * src0_d, // A scales
197
+ __read_only image1d_buffer_t src1, // B
198
+ ulong offset1, // offset to B (0)
199
+ global float * dst, // C
200
+ ulong offsetd, // offset to C (0)
201
+ uint K, // K
202
+ int ne01, // M
203
+ int ne02, // 1
204
+ int ne10, // K
205
+ int ne12, // 1
206
+ int ne0, // M
207
+ int ne1, // N
208
+ int r2, // 1
209
+ int r3)
210
+ {
211
+ uint groupId = get_local_id(1);
212
+ uint gid = get_global_id(0);
213
+ ushort slid = get_sub_group_local_id();
214
+
215
+ __private uint4 regA;
216
+ __private half2 regS;
217
+ __private float8 regB;
218
+
219
+ __private float2 totalSum = (float2)(0.0f);
220
+
221
+ // loop along K in block granularity, skip 4 blocks every iter
222
+ for (uint k = groupId; k < (K / QK4_0); k += N_SIMDGROUP) {
223
+ regS = src0_d[gid + k * LINE_STRIDE_A]; // each fiber loads scale of two rows
224
+ // first 4 fibers in each wave load 8 B values to its private scope
225
+ if (slid < 4) {
226
+ regB.s0123 = read_imagef(src1, (slid * 2 + k * 8));
227
+ regB.s4567 = read_imagef(src1, (1 + slid * 2 + k * 8));
228
+ }
229
+
230
+ // load half weights for two blocks in consecutive rows
231
+ regA.s0 = read_imageui(src0_q, (gid + k * BLOCK_STRIDE_A + LINE_STRIDE_A * 0)).x;
232
+ regA.s1 = read_imageui(src0_q, (gid + k * BLOCK_STRIDE_A + LINE_STRIDE_A * 1)).x;
233
+ regA.s2 = read_imageui(src0_q, (gid + k * BLOCK_STRIDE_A + LINE_STRIDE_A * 2)).x;
234
+ regA.s3 = read_imageui(src0_q, (gid + k * BLOCK_STRIDE_A + LINE_STRIDE_A * 3)).x;
235
+ #ifdef VECTOR_SUB_GROUP_BROADCAST
236
+ dequantizeBlockAccum_ns_sgbroadcast_8_hi(totalSum, as_ushort8(regA), regS, regB);
237
+ #else
238
+ dequantizeBlockAccum_ns_sgbroadcast_1_hi(totalSum, as_ushort8(regA), regS, regB);
239
+ #endif // VECTOR_SUB_GROUP_BROADCAST
240
+
241
+ regA.s0 = read_imageui(src0_q, (gid + k * BLOCK_STRIDE_A + LINE_STRIDE_A * 4)).x;
242
+ regA.s1 = read_imageui(src0_q, (gid + k * BLOCK_STRIDE_A + LINE_STRIDE_A * 5)).x;
243
+ regA.s2 = read_imageui(src0_q, (gid + k * BLOCK_STRIDE_A + LINE_STRIDE_A * 6)).x;
244
+ regA.s3 = read_imageui(src0_q, (gid + k * BLOCK_STRIDE_A + LINE_STRIDE_A * 7)).x;
245
+ #ifdef VECTOR_SUB_GROUP_BROADCAST
246
+ dequantizeBlockAccum_ns_sgbroadcast_8_lo(totalSum, as_ushort8(regA), regS, regB);
247
+ #else
248
+ dequantizeBlockAccum_ns_sgbroadcast_1_lo(totalSum, as_ushort8(regA), regS, regB);
249
+ #endif // VECTOR_SUB_GROUP_BROADCAST
250
+ }
251
+
252
+ // reduction in local memory, assumes #wave=4
253
+ __local float2 reduceLM[SIMDGROUP_WIDTH * 3];
254
+ if (groupId == 1) reduceLM[SIMDGROUP_WIDTH * 0 + slid] = totalSum;
255
+ if (groupId == 2) reduceLM[SIMDGROUP_WIDTH * 1 + slid] = totalSum;
256
+ if (groupId == 3) reduceLM[SIMDGROUP_WIDTH * 2 + slid] = totalSum;
257
+ barrier(CLK_LOCAL_MEM_FENCE);
258
+ if (groupId == 0) totalSum += reduceLM[SIMDGROUP_WIDTH * 0 + slid];
259
+ if (groupId == 0) totalSum += reduceLM[SIMDGROUP_WIDTH * 1 + slid];
260
+ if (groupId == 0) totalSum += reduceLM[SIMDGROUP_WIDTH * 2 + slid];
261
+
262
+ // 2 outputs per fiber in wave 0
263
+ if (groupId == 0) {
264
+ dst = (global float*)((global char*)dst + offsetd);
265
+ vstore2(totalSum, 0, &(dst[gid * 2]));
266
+ }
267
+
268
+ }