Skip to content

Commit 48a87f9

Browse files
authored
[MLX] GGUF vectorized loads (#20675)
Small improvement to do vectorized loads in GGUF kernels, matching llama.cpp.
1 parent 6fac71d commit 48a87f9

6 files changed

Lines changed: 36 additions & 12 deletions

File tree

backends/mlx/custom_kernel_ops/gguf/q4k/common.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,14 @@
6464
#include <metal_simdgroup_matrix>
6565
using namespace metal;
6666
67+
#define FOR_UNROLL(x) _Pragma("clang loop unroll(full)") for (x)
68+
69+
typedef matrix<bfloat, 2, 4> bfloat2x4;
70+
template<typename T> struct vec2x4;
71+
template<> struct vec2x4<float> { using type = float2x4; };
72+
template<> struct vec2x4<half> { using type = half2x4; };
73+
template<> struct vec2x4<bfloat> { using type = bfloat2x4; };
74+
6775
#define QK_K 256
6876
#define K_SCALE_SIZE 12
6977

backends/mlx/custom_kernel_ops/gguf/q4k/linear.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ def _q4k_matvec_source(has_bias: bool) -> str:
105105
106106
float4 acc1 = {{0.f, 0.f, 0.f, 0.f}};
107107
float4 acc2 = {{0.f, 0.f, 0.f, 0.f}};
108-
for (short i = 0; i < 4; ++i) {{
108+
FOR_UNROLL (short i = 0; i < 4; ++i) {{
109109
acc1[0] += yl[2*i + 0] * (float)(q1[i] & 0x000F);
110110
acc1[1] += yl[2*i + 1] * (float)(q1[i] & 0x0F00);
111111
acc1[2] += yl[2*i + 8] * (float)(q1[i] & 0x00F0);
@@ -218,9 +218,9 @@ def _q4k_matmul_source(has_bias: bool) -> str:
218218
const short ly_b = (tid / NL1) % 8;
219219
const short ib_b = 4 * sx_b + sy_b;
220220
221-
for (short i = 0; i < 8; ++i) {{
222-
*(sb + 64 * ib_b + 8 * ly_b + i) = (half) *(yp + i);
223-
}}
221+
using InT2x4 = typename vec2x4<InT>::type;
222+
*(threadgroup half2x4 *)(sb + 64 * ib_b + 8 * ly_b) =
223+
(half2x4)(*(device const InT2x4 *)(yp));
224224
225225
// Advance weight pointer through Q4_K sub-blocks.
226226
il = (il + 2 < NL) ? il + 2 : il % 2;

backends/mlx/custom_kernel_ops/gguf/q5k/common.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,14 @@
7070
#include <metal_simdgroup_matrix>
7171
using namespace metal;
7272
73+
#define FOR_UNROLL(x) _Pragma("clang loop unroll(full)") for (x)
74+
75+
typedef matrix<bfloat, 2, 4> bfloat2x4;
76+
template<typename T> struct vec2x4;
77+
template<> struct vec2x4<float> { using type = float2x4; };
78+
template<> struct vec2x4<half> { using type = half2x4; };
79+
template<> struct vec2x4<bfloat> { using type = bfloat2x4; };
80+
7381
#define QK_K 256
7482
#define K_SCALE_SIZE 12
7583

backends/mlx/custom_kernel_ops/gguf/q5k/linear.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ def _q5k_matvec_source(has_bias: bool) -> str:
135135
136136
float4 acc1 = {{0.f, 0.f, 0.f, 0.f}};
137137
float4 acc2 = {{0.f, 0.f, 0.f, 0.f}};
138-
for (short l = 0; l < 8; ++l) {{
138+
FOR_UNROLL (short l = 0; l < 8; ++l) {{
139139
const uint8_t h = qh[l];
140140
acc1[0] += yl[l + 0] * (float)(q1[l] & 0x0F);
141141
acc1[1] += yl[l + 8] * (float)(q1[l] & 0xF0);
@@ -253,9 +253,9 @@ def _q5k_matmul_source(has_bias: bool) -> str:
253253
const short ly_b = (tid / NL1) % 8;
254254
const short ib_b = 4 * sx_b + sy_b;
255255
256-
for (short i = 0; i < 8; ++i) {{
257-
*(sb + 64 * ib_b + 8 * ly_b + i) = (half) *(yp + i);
258-
}}
256+
using InT2x4 = typename vec2x4<InT>::type;
257+
*(threadgroup half2x4 *)(sb + 64 * ib_b + 8 * ly_b) =
258+
(half2x4)(*(device const InT2x4 *)(yp));
259259
260260
// Advance weight pointer through Q5_K sub-blocks.
261261
il = (il + 2 < NL) ? il + 2 : il % 2;

backends/mlx/custom_kernel_ops/gguf/q6k/common.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,14 @@
6565
#include <metal_simdgroup_matrix>
6666
using namespace metal;
6767
68+
#define FOR_UNROLL(x) _Pragma("clang loop unroll(full)") for (x)
69+
70+
typedef matrix<bfloat, 2, 4> bfloat2x4;
71+
template<typename T> struct vec2x4;
72+
template<> struct vec2x4<float> { using type = float2x4; };
73+
template<> struct vec2x4<half> { using type = half2x4; };
74+
template<> struct vec2x4<bfloat> { using type = bfloat2x4; };
75+
6876
#define QK_K 256
6977
7078
typedef struct {

backends/mlx/custom_kernel_ops/gguf/q6k/linear.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ def _q6k_matvec_source(has_bias: bool) -> str:
126126
const float d = (float) blk->d;
127127
128128
float4 sums = {{0.f, 0.f, 0.f, 0.f}};
129-
for (short l = 0; l < 4; ++l) {{
129+
FOR_UNROLL (short l = 0; l < 4; ++l) {{
130130
sums[0] += yl[4*l + 0] * (float)((int8_t)((q1[l] & 0xF) | ((qh[l] & 0x03) << 4)) - 32);
131131
sums[1] += yl[4*l + 1] * (float)((int8_t)((q2[l] & 0xF) | ((qh[l] & 0x0C) << 2)) - 32);
132132
sums[2] += yl[4*l + 2] * (float)((int8_t)((q1[l] >> 4) | ((qh[l] & 0x30) << 0)) - 32);
@@ -228,9 +228,9 @@ def _q6k_matmul_source(has_bias: bool) -> str:
228228
const short ly_b = (tid / NL1) % 8;
229229
const short ib_b = 4 * sx_b + sy_b;
230230
231-
for (short i = 0; i < 8; ++i) {{
232-
*(sb + 64 * ib_b + 8 * ly_b + i) = (half) *(yp + i);
233-
}}
231+
using InT2x4 = typename vec2x4<InT>::type;
232+
*(threadgroup half2x4 *)(sb + 64 * ib_b + 8 * ly_b) =
233+
(half2x4)(*(device const InT2x4 *)(yp));
234234
235235
// Advance weight pointer through Q6_K sub-blocks.
236236
il = (il + 2 < NL) ? il + 2 : il % 2;

0 commit comments

Comments
 (0)