char-fork/llama.cpp

git clone https://git.t4t.associates/char-fork/llama.cpp

Pranesh GonegandlaCUDA: branchless Q4_K/Q5_K unpack to speed up mmvq, L2 prefetch on DGX Spark (#26705)73ab7599b

char/aliceai-t5-moe
48.6 KiB1380 linesraw
1#pragma once
2
3#include "common.cuh"
4
5#include <cstdint>
6
7static __device__ __forceinline__ int get_int_b1(const void * x, const int & i32) {
8    const uint8_t * x8 = (const uint8_t *) x;
9
10    int x32  = x8[4*i32 + 0] <<  0;
11    x32     |= x8[4*i32 + 1] <<  8;
12    x32     |= x8[4*i32 + 2] << 16;
13    x32     |= x8[4*i32 + 3] << 24;
14
15    return x32;
16}
17
18static __device__ __forceinline__ int get_int_b2(const void * x, const int & i32) {
19    const uint16_t * x16 = (const uint16_t *) x; // assume at least 2 byte alignment
20
21    int x32  = x16[2*i32 + 0] <<  0;
22    x32     |= x16[2*i32 + 1] << 16;
23
24    return x32;
25}
26
27static __device__ __forceinline__ int get_int_b4(const void * x, const int & i32) {
28    return ((const int *) x)[i32]; // assume at least 4 byte alignment
29}
30
31// q4 contains 8 indices with 4 bit each.
32// This function selects those bytes from table that are at those indices and returns them as int2.
33// The first int contains the bytes with even indices in q4, the second int contains the bytes with odd indices in q4.
34static __device__ __forceinline__ int2 get_int_from_table_16(const int & q4, const int8_t * table) {
35#if defined(GGML_USE_HIP)
36    // Load the 16-byte table into four 32-bit unsigned integers.
37    const uint32_t *values = (const uint32_t *)table;
38
39    const uint32_t q_even = q4;
40    const uint32_t q_odd  = (q4 >> 4);
41
42    // Perform lookups in the lower half of the table (indices 0-7).
43    uint32_t v_even_low = __builtin_amdgcn_perm(values[1], values[0], q_even & 0x07070707);
44    uint32_t v_odd_low = __builtin_amdgcn_perm(values[1], values[0], q_odd & 0x07070707);
45
46    // Perform lookups in the upper half of the table (indices 8-15).
47    uint32_t v_even_high = __builtin_amdgcn_perm(values[3], values[2], q_even & 0x07070707);
48    uint32_t v_odd_high = __builtin_amdgcn_perm(values[3], values[2], q_odd & 0x07070707);
49
50    // Select between the low and high results based on the MSB of each index nibble.
51    uint32_t mask_even = 0x03020100 | ((q_even & 0x08080808) >> 1);
52    uint32_t res_x = __builtin_amdgcn_perm(v_even_high, v_even_low, mask_even);
53    uint32_t mask_odd = 0x03020100 | ((q_odd & 0x08080808) >> 1);
54    uint32_t res_y = __builtin_amdgcn_perm(v_odd_high, v_odd_low, mask_odd);
55
56    return make_int2(res_x, res_y);
57#elif !defined(GGML_USE_MUSA)
58    // CUDA does not have an instruction for selecting bytes with 4 bit indices.
59    // However, __byte_perm is an instruction that selects bytes with 3 bit indices that can be used instead.
60    const uint32_t * table32 = (const uint32_t *) table;
61
62    // __byte_perm selects bytes based on the lower 16 bits in its third argument.
63    // Therefore, do 2 iterations over the 32 bits in q4 with 0 and 16 shift.
64    // To handle the fourth bit, first call _byte_perm both for the low and the high 64 bit of table, using the low 3 bits.
65    // Then, call __byte_perm again to select from the low and high bytes based on the fourth bit.
66    uint32_t tmp[2];
67    const uint32_t low_high_selection_indices = (0x32103210 | ((q4 & 0x88888888) >> 1));
68#pragma unroll
69    for (uint32_t i = 0; i < 2; ++i) {
70        const uint32_t shift = 16 * i;
71
72        const uint32_t low  = __byte_perm(table32[0], table32[1], q4 >> shift);
73        const uint32_t high = __byte_perm(table32[2], table32[3], q4 >> shift);
74        tmp[i] = __byte_perm(low, high, low_high_selection_indices >> shift);
75    }
76
77    // tmp contains the bytes from tyble in the same order as the 4 bit indices in q4.
78    // However, for the result we need ints with all even/odd 4 bit indices in q4.
79    // Therefore, 2 more calls to __byte_perm to put the bytes in the correct order.
80    return make_int2(__byte_perm(tmp[0], tmp[1], 0x6420), __byte_perm(tmp[0], tmp[1], 0x7531));
81#else
82    // Generic implementation.
83    const int      q0_32  = (q4 >> 0) & 0x0F0F0F0F;
84    const int8_t * q0_8   = (const int8_t *) &q0_32;
85    const char4    val0_8 = make_char4(
86        table[q0_8[0]], table[q0_8[1]], table[q0_8[2]], table[q0_8[3]]);
87
88    const int      q1_32  = (q4 >> 4) & 0x0F0F0F0F;
89    const int8_t * q1_8   = (const int8_t *) &q1_32;
90    const char4    val1_8 = make_char4(
91        table[q1_8[0]], table[q1_8[1]], table[q1_8[2]], table[q1_8[3]]);
92
93    return make_int2(*((const int *) &val0_8), *((const int *) &val1_8));
94#endif
95}
96
97static __device__ __forceinline__ uint32_t unpack_ksigns(const uint8_t v) {
98    // v is a 7 bit int, with the 8th sign being encodable as popcnt
99    // with xor we can "correct" the bit instead of having to mask
100    const uint32_t p = __popc(v) & 1;
101    const uint32_t s = v ^ p << 7;
102    // broadcast over uint to allow for 0x08040201 / 0x80402010 as selectors
103    return s * 0x01010101;
104}
105
106// VDR = vec dot ratio, how many contiguous integers each thread processes when the vec dot kernel is called
107// MMVQ = mul_mat_vec_q, MMQ = mul_mat_q
108
109#define VDR_Q1_0_Q8_1_MMVQ 1  // Process one 32-element chunk at a time for parallelism
110#define VDR_Q1_0_Q8_1_MMQ  4  // Q1_0 has 128 bits (4 ints) per block
111
112#define VDR_Q2_0_Q8_1_MMVQ 1  // Process one 32-element chunk at a time for parallelism
113#define VDR_Q2_0_Q8_1_MMQ  2  // Q2_0 group 64: 128 bits (4 ints) per block, 2 32-element chunks
114
115#define VDR_Q4_0_Q8_1_MMVQ 2
116#define VDR_Q4_0_Q8_1_MMQ  4
117
118template <int vdr> static __device__ __forceinline__ float vec_dot_q4_0_q8_1_impl(
119    const int * v, const int * u, const float & d4, const half2 & ds8) {
120
121    int sumi = 0;
122
123#pragma unroll
124    for (int i = 0; i < vdr; ++i) {
125        const int vi0 = (v[i] >> 0) & 0x0F0F0F0F;
126        const int vi1 = (v[i] >> 4) & 0x0F0F0F0F;
127
128        // SIMD dot product of quantized values
129        sumi = ggml_cuda_dp4a(vi0, u[2*i+0], sumi);
130        sumi = ggml_cuda_dp4a(vi1, u[2*i+1], sumi);
131    }
132
133    const float2 ds8f = __half22float2(ds8);
134
135    // second part effectively subtracts 8 from each quant value
136    return d4 * (sumi * ds8f.x - (8*vdr/QI4_0) * ds8f.y);
137}
138
139#define VDR_Q4_1_Q8_1_MMVQ 2
140#define VDR_Q4_1_Q8_1_MMQ  4
141
142template <int vdr> static __device__ __forceinline__ float vec_dot_q4_1_q8_1_impl(
143    const int * v, const int * u, const half2 & dm4, const half2 & ds8) {
144
145    int sumi = 0;
146
147#pragma unroll
148    for (int i = 0; i < vdr; ++i) {
149        const int vi0 = (v[i] >> 0) & 0x0F0F0F0F;
150        const int vi1 = (v[i] >> 4) & 0x0F0F0F0F;
151
152        // SIMD dot product of quantized values
153        sumi = ggml_cuda_dp4a(vi0, u[2*i+0], sumi);
154        sumi = ggml_cuda_dp4a(vi1, u[2*i+1], sumi);
155    }
156
157#ifdef FAST_FP16_AVAILABLE
158    const float2 tmp = __half22float2(__hmul2(dm4, ds8));
159    const float d4d8 = tmp.x;
160    const float m4s8 = tmp.y;
161#else
162    const float2 dm4f = __half22float2(dm4);
163    const float2 ds8f = __half22float2(ds8);
164    const float d4d8 = dm4f.x * ds8f.x;
165    const float m4s8 = dm4f.y * ds8f.y;
166#endif // FAST_FP16_AVAILABLE
167
168    // scale second part of sum by QI8_1/(vdr * QR4_1) to compensate for multiple threads adding it
169    return sumi * d4d8 + m4s8 / (QI8_1 / (vdr * QR4_1));
170}
171
172#define VDR_Q5_0_Q8_1_MMVQ 2
173#define VDR_Q5_0_Q8_1_MMQ  4
174
175template <int vdr> static __device__ __forceinline__ float vec_dot_q5_0_q8_1_impl(
176    const int * vl, const int * vh, const int * u, const float & d5, const half2 & ds8) {
177
178    int sumi = 0;
179
180#pragma unroll
181    for (int i = 0; i < vdr; ++i) {
182        int vi0 = (vl[i] >>  0) & 0x0F0F0F0F; // lower 4 qs bits, still need qh as 5th bits
183        vi0    |= (vh[i] <<  4) & 0x00000010; // 0 ->  4
184        vi0    |= (vh[i] << 11) & 0x00001000; // 1 -> 12
185        vi0    |= (vh[i] << 18) & 0x00100000; // 2 -> 20
186        vi0    |= (vh[i] << 25) & 0x10000000; // 3 -> 28
187        sumi = ggml_cuda_dp4a(vi0, u[2*i+0], sumi); // SIMD dot product of quantized values
188
189        int vi1 = (vl[i] >>  4) & 0x0F0F0F0F; // upper 4 qs bits, still need qh as 5th bits
190        vi1    |= (vh[i] >> 12) & 0x00000010; // 16 ->  4
191        vi1    |= (vh[i] >>  5) & 0x00001000; // 17 -> 12
192        vi1    |= (vh[i] <<  2) & 0x00100000; // 18 -> 20
193        vi1    |= (vh[i] <<  9) & 0x10000000; // 19 -> 28
194        sumi = ggml_cuda_dp4a(vi1, u[2*i+1], sumi); // SIMD dot product of quantized values
195    }
196
197    const float2 ds8f = __half22float2(ds8);
198
199    // second part effectively subtracts 16 from each quant value
200    return d5 * (sumi * ds8f.x - (16*vdr/QI5_0) * ds8f.y);
201}
202
203#define VDR_Q5_1_Q8_1_MMVQ 2
204#define VDR_Q5_1_Q8_1_MMQ  4
205
206template <int vdr> static __device__ __forceinline__ float vec_dot_q5_1_q8_1_impl(
207    const int * vl, const int * vh, const int * u, const half2 & dm5, const half2 & ds8) {
208
209    int sumi = 0;
210
211#pragma unroll
212    for (int i = 0; i < vdr; ++i) {
213        int vi0 = (vl[i] >>  0) & 0x0F0F0F0F; // lower 4 qs bits, still need qh as 5th bits
214        vi0    |= (vh[i] <<  4) & 0x00000010; // 0 ->  4
215        vi0    |= (vh[i] << 11) & 0x00001000; // 1 -> 12
216        vi0    |= (vh[i] << 18) & 0x00100000; // 2 -> 20
217        vi0    |= (vh[i] << 25) & 0x10000000; // 3 -> 28
218        sumi = ggml_cuda_dp4a(vi0, u[2*i+0], sumi); // SIMD dot product of quantized values
219
220        int vi1 = (vl[i] >>  4) & 0x0F0F0F0F; // upper 4 qs bits, still need qh as 5th bits
221        vi1    |= (vh[i] >> 12) & 0x00000010; // 16 ->  4
222        vi1    |= (vh[i] >>  5) & 0x00001000; // 17 -> 12
223        vi1    |= (vh[i] <<  2) & 0x00100000; // 18 -> 20
224        vi1    |= (vh[i] <<  9) & 0x10000000; // 19 -> 28
225        sumi = ggml_cuda_dp4a(vi1, u[2*i+1], sumi); // SIMD dot product of quantized values
226    }
227
228#ifdef FAST_FP16_AVAILABLE
229    const float2 tmp = __half22float2(__hmul2(dm5, ds8));
230    const float d5d8 = tmp.x;
231    const float m5s8 = tmp.y;
232#else
233    const float2 dm5f = __half22float2(dm5);
234    const float2 ds8f = __half22float2(ds8);
235    const float d5d8 = dm5f.x * ds8f.x;
236    const float m5s8 = dm5f.y * ds8f.y;
237#endif // FAST_FP16_AVAILABLE
238
239    // scale second part of sum by QI5_1 / vdr to compensate for multiple threads adding it
240    return sumi*d5d8 + m5s8 / (QI5_1 / vdr);
241}
242
243#define VDR_Q8_0_Q8_1_MMVQ 2
244#define VDR_Q8_0_Q8_1_MMQ 8
245
246template <typename T, int vdr> static __device__ __forceinline__ T vec_dot_q8_0_q8_1_impl(
247    const int * v, const int * u, const T & d8_0, const T & d8_1) {
248
249    int sumi = 0;
250
251#pragma unroll
252    for (int i = 0; i < vdr; ++i) {
253        // SIMD dot product of quantized values
254        sumi = ggml_cuda_dp4a(v[i], u[i], sumi);
255    }
256
257    return d8_0*d8_1 * ((T) sumi);
258}
259
260template <int vdr> static __device__ __forceinline__ float vec_dot_q8_1_q8_1_impl(
261    const int * v, const int * u, const half2 & dm8, const half2 & ds8) {
262
263    int sumi = 0;
264
265#pragma unroll
266    for (int i = 0; i < vdr; ++i) {
267        // SIMD dot product of quantized values
268        sumi = ggml_cuda_dp4a(v[i], u[i], sumi);
269    }
270
271#ifdef FAST_FP16_AVAILABLE
272    const float2 tmp = __half22float2(__hmul2(dm8, ds8));
273    const float d8d8 = tmp.x;
274    const float m8s8 = tmp.y;
275#else
276    const float2 dm8f = __half22float2(dm8);
277    const float2 ds8f = __half22float2(ds8);
278    const float d8d8 = dm8f.x * ds8f.x;
279    const float m8s8 = dm8f.y * ds8f.y;
280#endif // FAST_FP16_AVAILABLE
281
282    // scale second part of sum by QI8_1/ vdr to compensate for multiple threads adding it
283    return sumi*d8d8 + m8s8 / (QI8_1 / vdr);
284}
285
286template <int vdr> static __device__ __forceinline__ float vec_dot_q8_0_16_q8_1_impl(
287    const int * v, const int * u, const float * d8_0, const float & d8_1) {
288
289    float sumf = 0.0f;
290
291#pragma unroll
292    for (int i0 = 0; i0 < vdr; i0 += QI8_0/2) {
293        int sumi = 0;
294
295#pragma unroll
296        for (int i = i0; i < i0 + QI8_0/2; ++i) {
297            // SIMD dot product of quantized values
298            sumi = ggml_cuda_dp4a(v[i], u[i], sumi);
299        }
300
301        sumf += d8_0[i0/(QI8_0/2)]*sumi;
302    }
303
304    return d8_1*sumf;
305}
306
307#define VDR_MXFP4_Q8_1_MMVQ 2
308#define VDR_MXFP4_Q8_1_MMQ  4
309
310static __device__ __forceinline__ float vec_dot_mxfp4_q8_1(
311    const void * __restrict__ vbq, const block_q8_1 * __restrict__ bq8_1, const int & kbx, const int & iqs) {
312
313    const block_mxfp4 * bq4 = (const block_mxfp4 *) vbq + kbx;
314
315    const int * q8 = (const int *) bq8_1->qs + iqs;
316
317    int sumi = 0;
318#pragma unroll
319    for (int l = 0; l < VDR_MXFP4_Q8_1_MMVQ; ++l) {
320        const int aux_q4 = get_int_b1(bq4->qs, iqs + l);
321        const int2 v = get_int_from_table_16(aux_q4, kvalues_mxfp4);
322
323        sumi = ggml_cuda_dp4a(v.x, q8[l + 0], sumi);
324        sumi = ggml_cuda_dp4a(v.y, q8[l + 4], sumi);
325    }
326
327    const float d = ggml_cuda_e8m0_to_fp32(bq4->e) * 0.5f * __low2float(bq8_1->ds);
328    return d * sumi;
329}
330
331#define VDR_NVFP4_Q8_1_MMVQ 4
332#define VDR_NVFP4_Q8_1_MMQ  8
333
334static __device__ __forceinline__ float vec_dot_nvfp4_q8_1(
335                                        const void * __restrict__ vbq,
336                                        const block_q8_1 * __restrict__ bq8_1,
337                                        const int32_t & kbx,
338                                        const int32_t & iqs) {
339
340    const block_nvfp4 * bq4 = (const block_nvfp4 *) vbq + kbx;
341    float sum = 0.0f;
342#pragma unroll
343    for (int i = 0; i < VDR_NVFP4_Q8_1_MMVQ/2; i++) {
344        const int32_t iqs0 = iqs + 2*i;
345        const int32_t iqs1 = iqs0 + 1;
346        const int32_t is = iqs0 >> 1;
347        const int2 v0 = get_int_from_table_16(get_int_b4(bq4->qs, iqs0), kvalues_mxfp4);
348        const int2 v1 = get_int_from_table_16(get_int_b4(bq4->qs, iqs1), kvalues_mxfp4);
349        const block_q8_1 * bq8 = bq8_1 + (is >> 1);
350        const int32_t i8 = ((is & 1) << 2);
351
352        int sumi = ggml_cuda_dp4a(v0.x, get_int_b4(bq8->qs, i8 + 0), 0);
353        sumi = ggml_cuda_dp4a(v0.y, get_int_b4(bq8->qs, i8 + 2), sumi);
354        sumi = ggml_cuda_dp4a(v1.x, get_int_b4(bq8->qs, i8 + 1), sumi);
355        sumi = ggml_cuda_dp4a(v1.y, get_int_b4(bq8->qs, i8 + 3), sumi);
356
357        const float d = ggml_cuda_ue4m3_to_fp32(bq4->d[is]) * __low2float(bq8->ds);
358        sum += d * float(sumi);
359    }
360
361    return sum;
362}
363#define VDR_Q2_K_Q8_1_MMVQ 1
364#define VDR_Q2_K_Q8_1_MMQ  4
365
366// contiguous v/x values
367static __device__ __forceinline__ float vec_dot_q2_K_q8_1_impl_mmvq(
368    const int & v, const int * __restrict__ u, const uint8_t * __restrict__ scales,
369    const half2 & dm2, const float * __restrict__ d8) {
370
371    float sumf_d = 0.0f;
372    float sumf_m = 0.0f;
373
374#pragma unroll
375    for (int i = 0; i < QR2_K; ++i) {
376        const int sc = scales[2*i];
377
378        const int vi = (v >> (2*i)) & 0x03030303;
379
380        sumf_d += d8[i] * (ggml_cuda_dp4a(vi, u[i], 0) * (sc & 0xF)); // SIMD dot product
381
382        // fill int with 4x m
383        int m = sc >> 4;
384        m |= m <<  8;
385        m |= m << 16;
386        sumf_m += d8[i] * ggml_cuda_dp4a(m, u[i], 0); // multiply constant q2_K part with sum of q8_1 values
387    }
388
389    const float2 dm2f = __half22float2(dm2);
390
391    return dm2f.x*sumf_d - dm2f.y*sumf_m;
392}
393
394// contiguous v/x + u/y values
395template <int ns8>
396static __device__ __forceinline__ float vec_dot_q2_K_q8_1_impl_mmq(
397    const int * __restrict__ v, const int * __restrict__ u, const half2 * dm2, const float & d8, const half2 * s8) {
398
399    float sumf    = 0.0f;
400    float sumf_d8 = 0.0f;
401
402#pragma unroll
403    for (int i0 = 0; i0 < QR2_K*VDR_Q2_K_Q8_1_MMQ; i0 += QI8_1) {
404        const float2 dm2f0 = __half22float2(dm2[i0/(QI8_1/2) + 0]);
405        int sumi_d0 = 0;
406
407        const float2 dm2f1 = __half22float2(dm2[i0/(QI8_1/2) + 1]);
408        int sumi_d1 = 0;
409
410#pragma unroll
411        for (int i = i0; i < i0 + QI8_1/2; ++i) {
412            sumi_d0 = ggml_cuda_dp4a(v[i], u[i], sumi_d0);
413        }
414        sumf_d8 += dm2f0.x * sumi_d0;
415
416#pragma unroll
417        for (int i = i0 + QI8_1/2; i < i0 + QI8_1; ++i) {
418            sumi_d1 = ggml_cuda_dp4a(v[i], u[i], sumi_d1);
419        }
420        sumf_d8 += dm2f1.x * sumi_d1;
421
422        if (i0/QI8_1 < ns8) {
423            const float2 s8f = __half22float2(s8[i0/QI8_1]);
424            sumf -= dm2f0.y*s8f.x;
425            sumf -= dm2f1.y*s8f.y;
426        } else {
427            int sumi_m0 = 0;
428#pragma unroll
429            for (int i = i0; i < i0 + QI8_1/2; ++i) {
430                sumi_m0 = ggml_cuda_dp4a(0x01010101, u[i], sumi_m0);
431            }
432            sumf_d8 -= dm2f0.y * sumi_m0;
433
434            int sumi_m1 = 0;
435#pragma unroll
436            for (int i = i0 + QI8_1/2; i < i0 + QI8_1; ++i) {
437                sumi_m1 = ggml_cuda_dp4a(0x01010101, u[i], sumi_m1);
438            }
439            sumf_d8 -= dm2f1.y * sumi_m1;
440        }
441    }
442
443    return sumf + d8*sumf_d8;
444}
445
446#define VDR_Q3_K_Q8_1_MMVQ 1
447#define VDR_Q3_K_Q8_1_MMQ  2
448
449// contiguous v/x values
450static __device__ __forceinline__ float vec_dot_q3_K_q8_1_impl_mmvq(
451    const int & vl, const int & vh, const int * __restrict__ u, const uint8_t * __restrict__ scales,
452    const int & scale_offset, const float & d3, const float * __restrict__ d8) {
453
454    float sumf = 0.0f;
455
456#pragma unroll
457    for (int i = 0; i < QR3_K; ++i) {
458        const int isc = scale_offset + 2*i;
459
460        const int isc_low = isc % (QK_K/32);
461        const int sc_shift_low = 4 * (isc / (QK_K/32));
462        const int sc_low  = (scales[isc_low] >> sc_shift_low) & 0xF;
463
464        const int isc_high = isc % (QK_K/64);
465        const int sc_shift_high = 2 * (isc / (QK_K/64));
466        const int sc_high = ((scales[(QK_K/32) + isc_high] >> sc_shift_high) & 3) << 4;
467
468        const int sc = (sc_low | sc_high) - 32;
469
470        const int vil = (vl >> (2*i)) & 0x03030303;
471
472        const int vih = ((vh >> i) << 2) & 0x04040404;
473
474        const int vi = __vsubss4(vil, vih);
475
476        sumf += d8[i] * (ggml_cuda_dp4a(vi, u[i], 0) * sc); // SIMD dot product
477    }
478
479    return d3 * sumf;
480}
481
482// contiguous v/x + u/y values
483static __device__ __forceinline__ float vec_dot_q3_K_q8_1_impl_mmq(
484    const int * __restrict__ v, const int * __restrict__ u, const int8_t * __restrict__ scales,
485    const float & d3, const float & d8) {
486
487    int sumi = 0;
488
489#pragma unroll
490    for (int i0 = 0; i0 < QR3_K*VDR_Q3_K_Q8_1_MMQ; i0 += QI8_1/2) {
491        int sumi_sc = 0;
492
493#pragma unroll
494        for (int i = i0; i < i0 + QI8_1/2; ++i) {
495            sumi_sc = ggml_cuda_dp4a(v[i], u[i], sumi_sc); // SIMD dot product
496        }
497
498        sumi += sumi_sc * scales[i0 / (QI8_1/2)];
499    }
500
501    return d3*d8 * sumi;
502}
503
504#define VDR_Q4_K_Q8_1_MMVQ 2
505#define VDR_Q4_K_Q8_1_MMQ  8
506
507// contiguous v/x values
508static __device__ __forceinline__ float vec_dot_q4_K_q8_1_impl_vmmq(
509    const int * __restrict__ v, const int * __restrict__ u, const uint8_t * __restrict__ sc,
510    const uint8_t * __restrict__ m, const half2 & dm4, const float * __restrict__ d8) {
511
512    float sumf_d = 0.0f;
513    float sumf_m = 0.0f;
514
515#pragma unroll
516    for (int i = 0; i < QR4_K; ++i) {
517        const int v0i = (v[0] >> (4*i)) & 0x0F0F0F0F;
518        const int v1i = (v[1] >> (4*i)) & 0x0F0F0F0F;
519
520        const int dot1 = ggml_cuda_dp4a(v1i, u[2*i+1], ggml_cuda_dp4a(v0i, u[2*i+0], 0)); // SIMD dot product
521        const int dot2 = ggml_cuda_dp4a(0x01010101, u[2*i+1], ggml_cuda_dp4a(0x01010101, u[2*i+0], 0)); // sum of u
522
523        sumf_d += d8[i] * (dot1 * sc[i]);
524        sumf_m += d8[i] * (dot2 * m[i]);  // multiply constant part of q4_K with sum of q8_1 values
525    }
526
527    const float2 dm4f = __half22float2(dm4);
528
529    return dm4f.x*sumf_d - dm4f.y*sumf_m;
530}
531
532// contiguous v/x + u/y values
533static __device__ __forceinline__ float vec_dot_q4_K_q8_1_impl_mmq(
534    const int * __restrict__ v, const int * __restrict__ u, const uint8_t * __restrict__ sc,
535    const uint8_t * __restrict__ m, const half2 & dm4, const half2 * __restrict__ ds8) {
536
537    float sumf_d = 0.0f;
538    float sumf_m = 0.0f;
539
540#pragma unroll
541    for (int i = 0; i < QR4_K*VDR_Q4_K_Q8_1_MMQ/QI8_1; ++i) {
542        int sumi_d = 0;
543
544#pragma unroll
545        for (int j = 0; j < QI8_1; ++j) {
546            sumi_d = ggml_cuda_dp4a((v[j] >> (4*i)) & 0x0F0F0F0F, u[i*QI8_1 + j], sumi_d); // SIMD dot product
547        }
548
549        const float2 ds8f = __half22float2(ds8[i]);
550
551        sumf_d += ds8f.x * (sc[i] * sumi_d);
552        sumf_m += ds8f.y *   m[i]; // sum of q8_1 block * q4_K min val
553    }
554
555    const float2 dm4f = __half22float2(dm4);
556
557    return dm4f.x*sumf_d - dm4f.y*sumf_m;
558}
559
560#define VDR_Q5_K_Q8_1_MMVQ 2
561#define VDR_Q5_K_Q8_1_MMQ  8
562
563// contiguous v/x values
564static __device__ __forceinline__ float vec_dot_q5_K_q8_1_impl_vmmq(
565    const int * __restrict__ vl, const int * __restrict__ vh, const int * __restrict__ u, const uint8_t * __restrict__ sc,
566    const uint8_t * __restrict__ m, const half2 & dm5, const float * __restrict__ d8) {
567
568    float sumf_d = 0.0f;
569    float sumf_m = 0.0f;
570
571#pragma unroll
572    for (int i = 0; i < QR5_K; ++i) {
573        const int vl0i = (vl[0] >> (4*i)) & 0x0F0F0F0F;
574        const int vl1i = (vl[1] >> (4*i)) & 0x0F0F0F0F;
575
576        const int vh0i = ((vh[0] >> i) << 4) & 0x10101010;
577        const int vh1i = ((vh[1] >> i) << 4) & 0x10101010;
578
579        const int v0i = vl0i | vh0i;
580        const int v1i = vl1i | vh1i;
581
582        const int dot1 = ggml_cuda_dp4a(v0i, u[2*i+0], ggml_cuda_dp4a(v1i, u[2*i+1], 0)); // SIMD dot product
583        const int dot2 = ggml_cuda_dp4a(0x01010101, u[2*i+0], ggml_cuda_dp4a(0x01010101, u[2*i+1], 0)); // sum of u
584
585        sumf_d += d8[i] * (dot1 * sc[i]);
586        sumf_m += d8[i] * (dot2 * m[i]);
587
588    }
589
590    const float2 dm5f = __half22float2(dm5);
591
592    return dm5f.x*sumf_d - dm5f.y*sumf_m;
593}
594
595// contiguous v/x + u/y values
596static __device__ __forceinline__ float vec_dot_q5_K_q8_1_impl_mmq(
597    const int * __restrict__ v, const int * __restrict__ u, const uint8_t * __restrict__ sc,
598    const uint8_t * __restrict__ m, const half2 & dm4, const half2 * __restrict__ ds8) {
599
600    float sumf_d = 0.0f;
601    float sumf_m = 0.0f;
602
603#pragma unroll
604    for (int i = 0; i < QR5_K*VDR_Q5_K_Q8_1_MMQ/QI8_1; ++i) {
605        int sumi_d = 0;
606
607#pragma unroll
608        for (int j = 0; j < QI8_1; ++j) {
609            sumi_d = ggml_cuda_dp4a(v[i*QI8_1 + j], u[i*QI8_1 + j], sumi_d); // SIMD dot product
610        }
611
612        const float2 ds8f = __half22float2(ds8[i]);
613
614        sumf_d += ds8f.x * (sc[i] * sumi_d);
615        sumf_m += ds8f.y *   m[i]; // sum of q8_1 block * q4_K min val
616    }
617
618    const float2 dm4f = __half22float2(dm4);
619
620    return dm4f.x*sumf_d - dm4f.y*sumf_m;
621}
622
623#define VDR_Q6_K_Q8_1_MMVQ 1
624#define VDR_Q6_K_Q8_1_MMQ  8
625
626// contiguous v/x values
627static __device__ __forceinline__ float vec_dot_q6_K_q8_1_impl_mmvq(
628    const int & vl, const int & vh, const int * __restrict__ u, const int8_t * __restrict__ scales,
629    const float & d, const float * __restrict__ d8) {
630
631    float sumf = 0.0f;
632
633#pragma unroll
634    for (int i = 0; i < QR6_K; ++i) {
635        const int sc = scales[4*i];
636
637        const int vil = (vl >> (4*i)) & 0x0F0F0F0F;
638
639        const int vih = ((vh >> (4*i)) << 4) & 0x30303030;
640
641        const int vi = __vsubss4((vil | vih), 0x20202020); // vi = (vil | vih) - 32
642
643        sumf += d8[i] * (ggml_cuda_dp4a(vi, u[i], 0) * sc); // SIMD dot product
644    }
645
646    return d*sumf;
647}
648
649// contiguous v/x + u/y values
650static __device__ __forceinline__ float vec_dot_q6_K_q8_1_impl_mmq(
651    const int * __restrict__ v, const int * __restrict__ u, const int8_t * __restrict__ sc,
652    const float & d6, const float * __restrict__ d8) {
653
654    float sumf_d = 0.0f;
655
656    const int      sc_packed = get_int_b4(sc, 0);
657    const int8_t * sc_reg    = (const int8_t *) &sc_packed;
658
659#pragma unroll
660    for (int i0 = 0; i0 < VDR_Q6_K_Q8_1_MMQ; i0 += 4) {
661        int2 sumi_d = {0, 0}; // 2 q6_K scales per q8_1 scale
662
663#pragma unroll
664        for (int i = i0; i < i0 + 2; ++i) {
665            sumi_d.x = ggml_cuda_dp4a(v[2*i+0], u[2*i+0], sumi_d.x); // SIMD dot product
666            sumi_d.x = ggml_cuda_dp4a(v[2*i+1], u[2*i+1], sumi_d.x); // SIMD dot product
667
668            sumi_d.y = ggml_cuda_dp4a(v[2*i+4], u[2*i+4], sumi_d.y); // SIMD dot product
669            sumi_d.y = ggml_cuda_dp4a(v[2*i+5], u[2*i+5], sumi_d.y); // SIMD dot product
670        }
671
672        sumf_d += d8[i0/4] * (sc_reg[i0/2+0]*sumi_d.x + sc_reg[i0/2+1]*sumi_d.y);
673    }
674
675    return d6 * sumf_d;
676}
677
678static __device__ __forceinline__ float vec_dot_q1_0_q8_1(
679    const void * __restrict__ vbq, const block_q8_1 * __restrict__ bq8_1, const int & kbx, const int & iqs) {
680
681    const block_q1_0 * bq1_0 = (const block_q1_0 *) vbq + kbx;
682
683    // Q1_0: 128 elements with ONE scale
684    // Q8_1: 32 elements per block with individual scales
685    // iqs selects which of the 4 chunks of 32 elements to process (0-3)
686
687    const float     d1 = bq1_0->d;
688    const int16_t * qs = (const int16_t *) bq1_0->qs + iqs * 2;
689
690    // Process only the chunk specified by iqs
691    const block_q8_1 * bq8_1_chunk = bq8_1 + iqs;
692
693    int sumi = 0;
694#pragma unroll
695    for (int j = 0; j < 2; ++j) {
696        const int q  = qs[j];
697
698        const int u0 = get_int_b4(bq8_1_chunk->qs, j*4+0);
699        const int u1 = get_int_b4(bq8_1_chunk->qs, j*4+1);
700        const int u2 = get_int_b4(bq8_1_chunk->qs, j*4+2);
701        const int u3 = get_int_b4(bq8_1_chunk->qs, j*4+3);
702
703        // unpack crumbs into nibble indices
704        const int n0 = __byte_perm(0x11100100, 0x11100100, q >> 0); // [0, 1, 4, 5] [ 8,  9, 12, 13]
705        const int n1 = __byte_perm(0x11100100, 0x11100100, q >> 2); // [2, 3, 6, 7] [10, 11, 14, 15]
706        // unpack nibbles into byte values
707        const int s0 = __byte_perm(0x01FF, 0x01FF, n0 >>  0);
708        const int s1 = __byte_perm(0x01FF, 0x01FF, n1 >>  0);
709        const int s2 = __byte_perm(0x01FF, 0x01FF, n0 >> 16);
710        const int s3 = __byte_perm(0x01FF, 0x01FF, n1 >> 16);
711        // unshuffle values
712        const int v0 = __byte_perm(s0, s1, 0x5410);
713        const int v1 = __byte_perm(s0, s1, 0x7632);
714        const int v2 = __byte_perm(s2, s3, 0x5410);
715        const int v3 = __byte_perm(s2, s3, 0x7632);
716
717        sumi = ggml_cuda_dp4a(v0, u0, sumi);
718        sumi = ggml_cuda_dp4a(v1, u1, sumi);
719        sumi = ggml_cuda_dp4a(v2, u2, sumi);
720        sumi = ggml_cuda_dp4a(v3, u3, sumi);
721    }
722
723    // Apply Q1_0's single scale and this chunk's Q8_1 scale
724    const float d8 = __low2float(bq8_1_chunk->ds);
725    return d1 * d8 * sumi;
726}
727
728static __device__ __forceinline__ float vec_dot_q2_0_q8_1(
729    const void * __restrict__ vbq, const block_q8_1 * __restrict__ bq8_1, const int & kbx, const int & iqs) {
730
731    const block_q2_0 * bq2_0 = (const block_q2_0 *) vbq + kbx;
732
733    // Q2_0 (group 64): 64 elements with ONE scale, 2 bits per element (4 elements per byte)
734    // Q8_1: 32 elements per block with individual scales
735    // iqs selects which of the 2 chunks of 32 elements to process (0-1)
736
737    const float     d2 = bq2_0->d;
738    const int16_t * qs = (const int16_t *) bq2_0->qs + iqs * 4;
739
740    // Process only the chunk specified by iqs
741    const block_q8_1 * bq8_1_chunk = bq8_1 + iqs;
742
743    int sumi = 0;
744#pragma unroll
745    for (int j = 0; j < 4; ++j) {
746        const int q  = qs[j];
747        const int u  = get_int_b4(bq8_1_chunk->qs, j*2+0);
748        const int v  = get_int_b4(bq8_1_chunk->qs, j*2+1);
749
750#if defined(GGML_USE_HIP)
751        const uint32_t qx_indices = (q & 0x03) | ((q & 0x0C) << 6) | ((q & 0x30) << 12) | ((q & 0xC0) << 18);
752        const uint32_t qy_bits    = q >> 8;
753        const uint32_t qy_indices = (qy_bits & 0x03) | ((qy_bits & 0x0C) << 6) | ((qy_bits & 0x30) << 12) | ((qy_bits & 0xC0) << 18);
754        const int qx = __builtin_amdgcn_perm(0x020100FF, 0x020100FF, qx_indices);
755        const int qy = __builtin_amdgcn_perm(0x020100FF, 0x020100FF, qy_indices);
756#else
757        // unpack even and odd crumbs into byte values
758        const int qe = __byte_perm(0x020100FF, 0x020100FF, q >> 0);
759        const int qo = __byte_perm(0x020100FF, 0x020100FF, q >> 2);
760        // unshuffle values
761        const int qx = __byte_perm(qe, qo, 0x5140);
762        const int qy = __byte_perm(qe, qo, 0x7362);
763#endif // defined(GGML_USE_HIP)
764
765        sumi = ggml_cuda_dp4a(u, qx, sumi);
766        sumi = ggml_cuda_dp4a(v, qy, sumi);
767    }
768
769    // Apply Q2_0's single scale and this chunk's Q8_1 scale
770    const float d8 = __low2float(bq8_1_chunk->ds);
771    return d2 * d8 * sumi;
772}
773
774static __device__ __forceinline__ float vec_dot_q4_0_q8_1(
775    const void * __restrict__ vbq, const block_q8_1 * __restrict__ bq8_1, const int & kbx, const int & iqs) {
776
777    const block_q4_0 * bq4_0 = (const block_q4_0 *) vbq + kbx;
778
779    int v[VDR_Q4_0_Q8_1_MMVQ];
780    int u[2*VDR_Q4_0_Q8_1_MMVQ];
781
782#pragma unroll
783    for (int i = 0; i < VDR_Q4_0_Q8_1_MMVQ; ++i) {
784        v[i]     = get_int_b2(bq4_0->qs, iqs + i);
785        u[2*i+0] = get_int_b4(bq8_1->qs, iqs + i);
786        u[2*i+1] = get_int_b4(bq8_1->qs, iqs + i + QI4_0);
787    }
788
789    return vec_dot_q4_0_q8_1_impl<VDR_Q4_0_Q8_1_MMVQ>(v, u, bq4_0->d, bq8_1->ds);
790}
791
792
793static __device__ __forceinline__ float vec_dot_q4_1_q8_1(
794    const void * __restrict__ vbq, const block_q8_1 * __restrict__ bq8_1, const int & kbx, const int & iqs) {
795
796    const block_q4_1 * bq4_1 = (const block_q4_1 *) vbq + kbx;
797
798    int v[VDR_Q4_1_Q8_1_MMVQ];
799    int u[2*VDR_Q4_1_Q8_1_MMVQ];
800
801#pragma unroll
802    for (int i = 0; i < VDR_Q4_1_Q8_1_MMVQ; ++i) {
803        v[i]     = get_int_b4(bq4_1->qs, iqs + i);
804        u[2*i+0] = get_int_b4(bq8_1->qs, iqs + i);
805        u[2*i+1] = get_int_b4(bq8_1->qs, iqs + i + QI4_1);
806    }
807
808    return vec_dot_q4_1_q8_1_impl<VDR_Q4_1_Q8_1_MMVQ>(v, u, bq4_1->dm, bq8_1->ds);
809}
810
811static __device__ __forceinline__ float vec_dot_q5_0_q8_1(
812    const void * __restrict__ vbq, const block_q8_1 * __restrict__ bq8_1, const int & kbx, const int & iqs) {
813
814    const block_q5_0 * bq5_0 = (const block_q5_0 *) vbq + kbx;
815
816    int vl[VDR_Q5_0_Q8_1_MMVQ];
817    int vh[VDR_Q5_0_Q8_1_MMVQ];
818    int  u[2*VDR_Q5_0_Q8_1_MMVQ];
819
820#pragma unroll
821    for (int i = 0; i < VDR_Q5_0_Q8_1_MMVQ; ++i) {
822        vl[i]    = get_int_b2(bq5_0->qs, iqs + i);
823        vh[i]    = get_int_b2(bq5_0->qh, 0) >> (4 * (iqs + i));
824        u[2*i+0] = get_int_b4(bq8_1->qs, iqs + i);
825        u[2*i+1] = get_int_b4(bq8_1->qs, iqs + i + QI5_0);
826    }
827
828    return vec_dot_q5_0_q8_1_impl<VDR_Q5_0_Q8_1_MMVQ>(vl, vh, u, bq5_0->d, bq8_1->ds);
829}
830
831static __device__ __forceinline__ float vec_dot_q5_1_q8_1(
832    const void * __restrict__ vbq, const block_q8_1 * __restrict__ bq8_1, const int & kbx, const int & iqs) {
833
834    const block_q5_1 * bq5_1 = (const block_q5_1 *) vbq + kbx;
835
836    int vl[VDR_Q5_1_Q8_1_MMVQ];
837    int vh[VDR_Q5_1_Q8_1_MMVQ];
838    int  u[2*VDR_Q5_1_Q8_1_MMVQ];
839
840#pragma unroll
841    for (int i = 0; i < VDR_Q5_1_Q8_1_MMVQ; ++i) {
842        vl[i]    = get_int_b4(bq5_1->qs, iqs + i);
843        vh[i]    = get_int_b4(bq5_1->qh, 0) >> (4 * (iqs + i));
844        u[2*i+0] = get_int_b4(bq8_1->qs, iqs + i);
845        u[2*i+1] = get_int_b4(bq8_1->qs, iqs + i + QI5_1);
846    }
847
848    return vec_dot_q5_1_q8_1_impl<VDR_Q5_1_Q8_1_MMVQ>(vl, vh, u, bq5_1->dm, bq8_1->ds);
849}
850
851static __device__ __forceinline__ float vec_dot_q8_0_q8_1(
852    const void * __restrict__ vbq, const block_q8_1 * __restrict__ bq8_1, const int & kbx, const int & iqs) {
853
854    const block_q8_0 * bq8_0 = (const block_q8_0 *) vbq + kbx;
855
856    int v[VDR_Q8_0_Q8_1_MMVQ];
857    int u[VDR_Q8_0_Q8_1_MMVQ];
858
859#pragma unroll
860    for (int i = 0; i < VDR_Q8_0_Q8_1_MMVQ; ++i) {
861        v[i] = get_int_b2(bq8_0->qs, iqs + i);
862        u[i] = get_int_b4(bq8_1->qs, iqs + i);
863    }
864
865    return vec_dot_q8_0_q8_1_impl<float, VDR_Q8_0_Q8_1_MMVQ>(v, u, bq8_0->d, __low2half(bq8_1->ds));
866}
867
868static __device__ __forceinline__ float vec_dot_q2_K_q8_1(
869    const void * __restrict__ vbq, const block_q8_1 * __restrict__ bq8_1, const int & kbx, const int & iqs) {
870
871    const block_q2_K * bq2_K = (const block_q2_K *) vbq + kbx;
872
873    const int bq8_offset = QR2_K * (iqs / QI8_1);
874    const int scale_offset = iqs - iqs % QI8_1 + (iqs % QI8_1) / (QI8_1/2);
875
876    const uint8_t * scales = bq2_K->scales + scale_offset;
877
878    const int v = get_int_b4(bq2_K->qs, iqs);
879    int    u[QR2_K];
880    float d8[QR2_K];
881
882#pragma unroll
883    for (int i = 0; i < QR2_K; ++ i) {
884        u[i]  = get_int_b4(bq8_1[bq8_offset + i].qs, iqs % QI8_1);
885        d8[i] = __low2float(bq8_1[bq8_offset + i].ds);
886    }
887
888    return vec_dot_q2_K_q8_1_impl_mmvq(v, u, scales, bq2_K->dm, d8);
889}
890
891static __device__ __forceinline__ float vec_dot_q3_K_q8_1(
892    const void * __restrict__ vbq, const block_q8_1 * __restrict__ bq8_1, const int & kbx, const int & iqs) {
893
894    const block_q3_K * bq3_K = (const block_q3_K *) vbq + kbx;
895
896    const int bq8_offset = QR3_K * (iqs / (QI3_K/2));
897    const int scale_offset = iqs - iqs % QI8_1 + (iqs % QI8_1) / (QI8_1/2);
898
899    const float d = bq3_K->d;
900
901    const int vl = get_int_b2(bq3_K->qs, iqs);
902
903    // invert the mask with ~ so that a 0/1 results in 4/0 being subtracted
904    const int vh = ~get_int_b2(bq3_K->hmask, iqs % (QI3_K/2)) >> bq8_offset;
905
906    int    u[QR3_K];
907    float d8[QR3_K];
908
909#pragma unroll
910    for (int i = 0; i < QR3_K; ++i) {
911        u[i]  = get_int_b4(bq8_1[bq8_offset + i].qs, iqs % QI8_1);
912        d8[i] = __low2float(bq8_1[bq8_offset + i].ds);
913    }
914
915    return vec_dot_q3_K_q8_1_impl_mmvq(vl, vh, u, bq3_K->scales, scale_offset, d, d8);
916}
917
918static __device__ __forceinline__ float vec_dot_q4_K_q8_1(
919    const void * __restrict__ vbq, const block_q8_1 * __restrict__ bq8_1, const int & kbx, const int & iqs) {
920
921    const block_q4_K * bq4_K = (const block_q4_K *) vbq + kbx;
922
923    int    v[2];
924    int    u[2*QR4_K];
925    float d8[QR4_K];
926
927    // iqs is in 0,2..30. bq8_offset = iqs/4 -> bq8_offset = 0, 2, 4, 6
928    const int bq8_offset = QR4_K * ((iqs/2) / (QI8_1/2));
929
930    // iqs = 0....3 -> bq8_offset = 0, want q4_offset = 0, 4, 8, 12
931    // iqs = 4....7 -> bq8_offset = 2, want q4_offset = 32, 36, 40, 44
932    // iqs = 8...11 -> bq8_offset = 4, want q4_offset = 64, 68, 72, 76
933    // iqs = 12..15 -> bq8_offset = 6, want q4_offset = 96, 100, 104, 108
934
935    const int * q4 = (const int *)(bq4_K->qs + 16 * bq8_offset + 4 * ((iqs/2)%4));
936    v[0] = q4[0];
937    v[1] = q4[4];
938
939    // branchless so nvcc can hoist this out of the ncols_dst loop
940    const uint16_t * scales = (const uint16_t *)bq4_K->scales;
941    const int j  = bq8_offset/2;
942    const int jm = j & 1;
943
944    const uint32_t s0 = scales[jm + 0];
945    const uint32_t s2 = scales[jm + 2];
946    const uint32_t s4 = scales[jm + 4];
947
948    const uint32_t hi = (uint32_t) -(int32_t) (j >= 2);
949
950    uint16_t aux[2];
951    aux[0] = (uint16_t) (((s0 & 0x3f3f) & ~hi) | ((((s4 >> 0) & 0x0f0f) | ((s0 & 0xc0c0) >> 2)) & hi));
952    aux[1] = (uint16_t) (((s2 & 0x3f3f) & ~hi) | ((((s4 >> 4) & 0x0f0f) | ((s2 & 0xc0c0) >> 2)) & hi));
953    const uint8_t * sc = (const uint8_t *)aux;
954    const uint8_t * m  = sc + 2;
955
956    for (int i = 0; i < QR4_K; ++i) {
957        const block_q8_1 * bq8i = bq8_1 + bq8_offset + i;
958        d8[i] = __low2float(bq8i->ds);
959
960        const int * q8 = (const int *)bq8i->qs + ((iqs/2)%4);
961        u[2*i+0] = q8[0];
962        u[2*i+1] = q8[4];
963    }
964
965    return vec_dot_q4_K_q8_1_impl_vmmq(v, u, sc, m, bq4_K->dm, d8);
966}
967
968static __device__ __forceinline__ float vec_dot_q5_K_q8_1(
969    const void * __restrict__ vbq, const block_q8_1 * __restrict__ bq8_1, const int & kbx, const int & iqs) {
970
971    const block_q5_K * bq5_K = (const block_q5_K *) vbq + kbx;
972
973    int   vl[2];
974    int   vh[2];
975    int    u[2*QR5_K];
976    float d8[QR5_K];
977
978    const int bq8_offset = QR5_K * ((iqs/2) / (QI8_1/2));
979    const int * ql = (const int *)(bq5_K->qs + 16 * bq8_offset + 4 * ((iqs/2)%4));
980    const int * qh = (const int *)(bq5_K->qh + 4 * ((iqs/2)%4));
981
982    vl[0] = ql[0];
983    vl[1] = ql[4];
984
985    vh[0] = qh[0] >> bq8_offset;
986    vh[1] = qh[4] >> bq8_offset;
987
988    // same as q4_K
989    const uint16_t * scales = (const uint16_t *)bq5_K->scales;
990    const int j  = bq8_offset/2;
991    const int jm = j & 1;
992
993    const uint32_t s0 = scales[jm + 0];
994    const uint32_t s2 = scales[jm + 2];
995    const uint32_t s4 = scales[jm + 4];
996
997    const uint32_t hi = (uint32_t) -(int32_t) (j >= 2);
998
999    uint16_t aux[2];
1000    aux[0] = (uint16_t) (((s0 & 0x3f3f) & ~hi) | ((((s4 >> 0) & 0x0f0f) | ((s0 & 0xc0c0) >> 2)) & hi));
1001    aux[1] = (uint16_t) (((s2 & 0x3f3f) & ~hi) | ((((s4 >> 4) & 0x0f0f) | ((s2 & 0xc0c0) >> 2)) & hi));
1002
1003    const uint8_t * sc = (const uint8_t *)aux;
1004    const uint8_t * m  = sc + 2;
1005
1006#pragma unroll
1007    for (int i = 0; i < QR5_K; ++i) {
1008        const block_q8_1 * bq8i = bq8_1 + bq8_offset + i;
1009        d8[i] = __low2float(bq8i->ds);
1010
1011        const int * q8 = (const int *)bq8i->qs + ((iqs/2)%4);
1012        u[2*i+0] = q8[0];
1013        u[2*i+1] = q8[4];
1014    }
1015
1016    return vec_dot_q5_K_q8_1_impl_vmmq(vl, vh, u, sc, m, bq5_K->dm, d8);
1017}
1018
1019static __device__ __forceinline__ float vec_dot_q6_K_q8_1(
1020    const void * __restrict__ vbq, const block_q8_1 * __restrict__ bq8_1, const int & kbx, const int & iqs) {
1021
1022    const block_q6_K * bq6_K = (const block_q6_K *) vbq + kbx;
1023
1024    const int bq8_offset = 2 * QR6_K * (iqs / (QI6_K/2)) + (iqs % (QI6_K/2)) / (QI6_K/4);
1025    const int scale_offset = (QI6_K/4) * (iqs / (QI6_K/2)) + (iqs % (QI6_K/2)) / (QI6_K/8);
1026    const int vh_shift = 2 * ((iqs % (QI6_K/2)) / (QI6_K/4));
1027
1028    const int vl = get_int_b2(bq6_K->ql, iqs);
1029    const int vh = get_int_b2(bq6_K->qh, (QI6_K/4) * (iqs / (QI6_K/2)) + iqs % (QI6_K/4)) >> vh_shift;
1030
1031    const int8_t * scales = bq6_K->scales + scale_offset;
1032
1033    int    u[QR6_K];
1034    float d8[QR6_K];
1035
1036#pragma unroll
1037    for (int i = 0; i < QR6_K; ++i) {
1038        u[i]  = get_int_b4(bq8_1[bq8_offset + 2*i].qs, iqs % QI8_1);
1039        d8[i] = __low2float(bq8_1[bq8_offset + 2*i].ds);
1040    }
1041
1042    return vec_dot_q6_K_q8_1_impl_mmvq(vl, vh, u, scales, bq6_K->d, d8);
1043}
1044
1045#define VDR_IQ2_XXS_Q8_1_MMVQ 2
1046#define VDR_IQ2_XXS_Q8_1_MMQ  2
1047
1048static __device__ __forceinline__ float vec_dot_iq2_xxs_q8_1(
1049    const void * __restrict__ vbq, const block_q8_1 * __restrict__ bq8_1, const int & kbx, const int & iqs) {
1050
1051    const block_iq2_xxs * bq2 = (const block_iq2_xxs *) vbq + kbx;
1052
1053    const int q2 = get_int_b2(bq2->qs, iqs);
1054    const uint8_t * aux8 = (const uint8_t *) &q2;
1055    const uint32_t aux32 = get_int_b2(bq2->qs, iqs + 1);
1056
1057    int sumi = 0;
1058#pragma unroll
1059    for (int k0 = 0; k0 < 8; k0 += 2) {
1060        const uint2 grid_pos = ((const uint2*)iq2xxs_grid)[aux8[k0/2]];
1061        const uint32_t signs = unpack_ksigns(aux32 >> (7 * k0 / 2));
1062
1063        const int signs0 = __vcmpne4(signs & 0x08040201, 0);
1064        const int grid0 = __vsub4(grid_pos.x ^ signs0, signs0);
1065        const int u0 = get_int_b4(bq8_1[iqs/2].qs, k0 + 0);
1066        sumi = ggml_cuda_dp4a(grid0, u0, sumi);
1067
1068        const int signs1 = __vcmpne4(signs & 0x80402010, 0);
1069        const int grid1 = __vsub4(grid_pos.y ^ signs1, signs1);
1070        const int u1 = get_int_b4(bq8_1[iqs/2].qs, k0 + 1);
1071        sumi = ggml_cuda_dp4a(grid1, u1, sumi);
1072    }
1073
1074    const int ls = aux32 >> 27 | 1; // (scale * 2 + 1)
1075    sumi = sumi * ls / 8;           // (sumi * scale + sumi / 2) / 4
1076    const float d = __half2float(bq2->d) * __low2float(bq8_1[iqs/2].ds);
1077    return d * sumi;
1078}
1079
1080#define VDR_IQ2_XS_Q8_1_MMVQ 2
1081#define VDR_IQ2_XS_Q8_1_MMQ  2
1082
1083static __device__ __forceinline__ float vec_dot_iq2_xs_q8_1(
1084    const void * __restrict__ vbq, const block_q8_1 * __restrict__ bq8_1, const int & kbx, const int & iqs) {
1085
1086    const block_iq2_xs * bq2 = (const block_iq2_xs *) vbq + kbx;
1087
1088    const int2 q2_packed = make_int2(get_int_b2(bq2->qs, iqs + 0), get_int_b2(bq2->qs, iqs + 1));
1089    const uint16_t * q2 = (const uint16_t *) &q2_packed;
1090    const int ls0 = bq2->scales[iqs/2] & 0x0F;
1091    const int ls1 = bq2->scales[iqs/2] >> 4;
1092
1093    int sumi0 = 0;
1094    int sumi1 = 0;
1095#pragma unroll
1096    for (int l0 = 0; l0 < 8; l0 += 2) {
1097        const uint2 grid_pos = ((const uint2*)iq2xs_grid)[q2[l0/2] & 0x1FF];
1098        const uint32_t signs = unpack_ksigns(q2[l0/2] >> 9);
1099
1100        const int signs0 = __vcmpne4(signs & 0x08040201, 0);
1101        const int grid_l = __vsub4(grid_pos.x ^ signs0, signs0);
1102        const int u0 = get_int_b4(bq8_1[iqs/2].qs, l0 + 0);
1103
1104        const int signs1 = __vcmpne4(signs & 0x80402010, 0);
1105        const int grid_h = __vsub4(grid_pos.y ^ signs1, signs1);
1106        const int u1 = get_int_b4(bq8_1[iqs/2].qs, l0 + 1);
1107
1108        if (l0 < 4) {
1109            sumi0 = ggml_cuda_dp4a(grid_l, u0, sumi0);
1110            sumi0 = ggml_cuda_dp4a(grid_h, u1, sumi0);
1111        } else {
1112            sumi1 = ggml_cuda_dp4a(grid_l, u0, sumi1);
1113            sumi1 = ggml_cuda_dp4a(grid_h, u1, sumi1);
1114        }
1115    }
1116    const int sumi = (sumi0*ls0 + sumi1*ls1 + (sumi0 + sumi1)/2)/4;
1117    const float d = __half2float(bq2->d) * __low2float(bq8_1[iqs/2].ds);
1118    return d * sumi;
1119}
1120
1121#define VDR_IQ2_S_Q8_1_MMVQ 2
1122#define VDR_IQ2_S_Q8_1_MMQ  2
1123
1124static __device__ __forceinline__ float vec_dot_iq2_s_q8_1(
1125    const void * __restrict__ vbq, const block_q8_1 * __restrict__ bq8_1, const int & kbx, const int & iqs) {
1126
1127    const block_iq2_s * bq2 = (const block_iq2_s *) vbq + kbx;
1128
1129    const int       qs_packed = get_int_b2(bq2->qs, iqs/2);
1130    const uint8_t * qs        = (const uint8_t *) &qs_packed;
1131
1132    const int qh = bq2->qh[iqs/2];
1133
1134    const int       signs_packed_32 = get_int_b2(bq2->qs, QK_K/32 + iqs/2);
1135    const uint8_t * signs_packed_8  = (const uint8_t *) &signs_packed_32;
1136
1137    const int ls0 = bq2->scales[iqs/2] & 0x0F;
1138    const int ls1 = bq2->scales[iqs/2] >> 4;
1139
1140    int sumi0 = 0;
1141    int sumi1 = 0;
1142#pragma unroll
1143    for (int l0 = 0; l0 < 8; l0 += 2) {
1144        const int * grid_pos = (const int *)(iq2s_grid + (qs[l0/2] | ((qh << (8-l0)) & 0x300)));
1145
1146        const int signs0 = __vcmpne4(((signs_packed_8[l0/2] & 0x03) << 7) | ((signs_packed_8[l0/2] & 0x0C) << 21), 0x00000000);
1147        const int signs1 = __vcmpne4(((signs_packed_8[l0/2] & 0x30) << 3) | ((signs_packed_8[l0/2] & 0xC0) << 17), 0x00000000);
1148
1149        const int grid_l = __vsub4(grid_pos[0] ^ signs0, signs0);
1150        const int grid_h = __vsub4(grid_pos[1] ^ signs1, signs1);
1151
1152        const int u0 = get_int_b4(bq8_1[iqs/2].qs, l0 + 0);
1153        const int u1 = get_int_b4(bq8_1[iqs/2].qs, l0 + 1);
1154
1155        if (l0 < 4) {
1156            sumi0 = ggml_cuda_dp4a(grid_l, u0, sumi0);
1157            sumi0 = ggml_cuda_dp4a(grid_h, u1, sumi0);
1158        } else {
1159            sumi1 = ggml_cuda_dp4a(grid_l, u0, sumi1);
1160            sumi1 = ggml_cuda_dp4a(grid_h, u1, sumi1);
1161        }
1162    }
1163    const int sumi = (sumi0*ls0 + sumi1*ls1 + (sumi0 + sumi1)/2)/4;
1164
1165    const float d = __half2float(bq2->d) * __low2float(bq8_1[iqs/2].ds);
1166    return d * sumi;
1167}
1168
1169#define VDR_IQ3_XXS_Q8_1_MMVQ 2
1170#define VDR_IQ3_XXS_Q8_1_MMQ  2
1171
1172static __device__ __forceinline__ float vec_dot_iq3_xxs_q8_1(
1173    const void * __restrict__ vbq, const block_q8_1 * __restrict__ bq8_1, const int & kbx, const int & iqs) {
1174
1175    const block_iq3_xxs * bq3 = (const block_iq3_xxs *) vbq + kbx;
1176
1177    const int2 q3_packed = make_int2(get_int_b2(bq3->qs, iqs), get_int_b2(bq3->qs, iqs+1));
1178    const uint8_t * q3 = (const uint8_t *) &q3_packed;
1179    const uint32_t aux32 = get_int_b2(bq3->qs, QK_K/16 + iqs/2);
1180
1181    int sumi = 0;
1182#pragma unroll
1183    for (int l0 = 0; l0 < 8; l0 += 2) {
1184        const int2 grid_pos = make_int2(iq3xxs_grid[q3[l0 + 0]], iq3xxs_grid[q3[l0 + 1]]);
1185        const uint32_t signs = unpack_ksigns(aux32 >> (7*l0/2));
1186
1187        const int signs0 = __vcmpne4(signs & 0x08040201, 0);
1188        const int grid_l = __vsub4(grid_pos.x ^ signs0, signs0);
1189
1190        const int u0 = get_int_b4(bq8_1[iqs/2].qs, l0 + 0);
1191
1192        const int signs1 = __vcmpne4(signs & 0x80402010, 0);
1193        const int grid_h = __vsub4(grid_pos.y ^ signs1, signs1);
1194
1195        const int u1 = get_int_b4(bq8_1[iqs/2].qs, l0 + 1);
1196
1197        sumi = ggml_cuda_dp4a(grid_l, u0, sumi);
1198        sumi = ggml_cuda_dp4a(grid_h, u1, sumi);
1199    }
1200
1201    const int ls = aux32 >> 28;
1202    sumi = (ls*sumi + sumi/2)/2;
1203    const float d = __half2float(bq3->d) * __low2float(bq8_1[iqs/2].ds);
1204    return d * sumi;
1205}
1206
1207#define VDR_IQ3_S_Q8_1_MMVQ 2
1208#define VDR_IQ3_S_Q8_1_MMQ  2
1209
1210// TODO: don't use lookup table for signs
1211static __device__ __forceinline__ float vec_dot_iq3_s_q8_1(
1212    const void * __restrict__ vbq, const block_q8_1 * __restrict__ bq8_1, const int & kbx, const int & iqs) {
1213
1214    const block_iq3_s * bq3 = (const block_iq3_s *) vbq + kbx;
1215
1216    const int2      qs_packed = make_int2(get_int_b2(bq3->qs, iqs + 0), get_int_b2(bq3->qs, iqs + 1));
1217    const uint8_t * qs        = (const uint8_t *) &qs_packed;
1218
1219    const int qh = bq3->qh[iqs/2];
1220
1221    const int       signs_packed_32 = get_int_b2(bq3->signs, iqs/2);
1222    const uint8_t * signs_packed_8  = (const uint8_t *) &signs_packed_32;
1223
1224    int sumi = 0;
1225#pragma unroll
1226    for (int l0 = 0; l0 < 8; l0 += 2) {
1227        const int2 grid_pos = make_int2(
1228            iq3s_grid[qs[l0 + 0] | ((qh << (8 - l0)) & 0x100)],
1229            iq3s_grid[qs[l0 + 1] | ((qh << (7 - l0)) & 0x100)]);
1230
1231        const int signs0 = __vcmpne4(((signs_packed_8[l0/2] & 0x03) << 7) | ((signs_packed_8[l0/2] & 0x0C) << 21), 0x00000000);
1232        const int signs1 = __vcmpne4(((signs_packed_8[l0/2] & 0x30) << 3) | ((signs_packed_8[l0/2] & 0xC0) << 17), 0x00000000);
1233
1234        const int grid_l = __vsub4(grid_pos.x ^ signs0, signs0);
1235        const int grid_h = __vsub4(grid_pos.y ^ signs1, signs1);
1236
1237        const int u0 = get_int_b4(bq8_1[iqs/2].qs, l0 + 0);
1238        const int u1 = get_int_b4(bq8_1[iqs/2].qs, l0 + 1);
1239
1240        sumi = ggml_cuda_dp4a(grid_l, u0, sumi);
1241        sumi = ggml_cuda_dp4a(grid_h, u1, sumi);
1242    }
1243
1244    sumi *= 1 + 2*((bq3->scales[iqs/4] >> ((iqs << 1) & 0x04)) & 0x0F);
1245
1246    const float d = __half2float(bq3->d) * __low2float(bq8_1[iqs/2].ds);
1247    return d * sumi;
1248}
1249
1250#define VDR_IQ1_S_Q8_1_MMVQ 1
1251#define VDR_IQ1_S_Q8_1_MMQ  1
1252
1253static __device__ __forceinline__ float vec_dot_iq1_s_q8_1(
1254    const void * __restrict__ vbq, const block_q8_1 * __restrict__ bq8_1, const int & kbx, const int & iqs) {
1255    const block_iq1_s * bq1 = (const block_iq1_s *) vbq + kbx;
1256
1257    const int       qs_packed = get_int_b2(bq1->qs, iqs);
1258    const uint8_t * qs        = (const uint8_t *) &qs_packed;
1259
1260    const int qh = bq1->qh[iqs];
1261
1262    int sumi = 0;
1263#pragma unroll
1264    for (int l0 = 0; l0 < 8; l0 += 2) {
1265        const int grid = iq1s_grid_gpu[qs[l0/2] | (((qh >> 3*(l0/2)) & 0x07) << 8)];
1266
1267        const int grid0 = (grid >> 0) & 0x0F0F0F0F;
1268        const int grid1 = (grid >> 4) & 0x0F0F0F0F;
1269
1270        const int u0 = get_int_b4(bq8_1[iqs].qs, l0 + 0);
1271        const int u1 = get_int_b4(bq8_1[iqs].qs, l0 + 1);
1272
1273        sumi = ggml_cuda_dp4a(grid0, u0, sumi);
1274        sumi = ggml_cuda_dp4a(grid1, u1, sumi);
1275    }
1276
1277    const float  d1q   = __half2float(bq1->d) * (((qh >> 11) & 0x0E) + 1);
1278    const float  delta = -1.0f + IQ1S_DELTA - (qh & 0x8000) * (2.0f*IQ1S_DELTA/0x8000);
1279    const float2 ds    = __half22float2(bq8_1[iqs].ds);
1280    return d1q * (ds.x*sumi + ds.y*delta);
1281}
1282
1283#define VDR_IQ1_M_Q8_1_MMVQ 1
1284#define VDR_IQ1_M_Q8_1_MMQ  1
1285
1286static __device__ __forceinline__ float vec_dot_iq1_m_q8_1(
1287    const void * __restrict__ vbq, const block_q8_1 * __restrict__ bq8_1, const int & kbx, const int & iqs) {
1288
1289    const block_iq1_m * bq1 = (const block_iq1_m *) vbq + kbx;
1290
1291    const int       qs_packed = get_int_b4(bq1->qs, iqs);
1292    const uint8_t * qs        = (const uint8_t *) &qs_packed;
1293
1294    int   sumi[2] = {0};
1295    float sumf[2] = {0.0f};
1296#pragma unroll
1297    for (int l0 = 0; l0 < 8; l0 += 2) {
1298        const int qhl = bq1->qh[2*iqs + l0/4] >> (4 * ((l0/2) % 2));
1299
1300        const int grid = iq1s_grid_gpu[qs[l0/2] | ((qhl & 0x07) << 8)];
1301
1302        const int grid0 = (grid >> 0) & 0x0F0F0F0F;
1303        const int grid1 = (grid >> 4) & 0x0F0F0F0F;
1304
1305        const int u0 = get_int_b4(bq8_1[iqs].qs, l0 + 0);
1306        const int u1 = get_int_b4(bq8_1[iqs].qs, l0 + 1);
1307
1308        sumi[l0/4] = ggml_cuda_dp4a(grid0, u0, sumi[l0/4]);
1309        sumi[l0/4] = ggml_cuda_dp4a(grid1, u1, sumi[l0/4]);
1310
1311        const float delta = -1.0f + IQ1M_DELTA - (qhl & 0x08) * (2.0f*IQ1M_DELTA/0x08);
1312        int sumy = 0;
1313        sumy = ggml_cuda_dp4a(u0, 0x01010101, sumy);
1314        sumy = ggml_cuda_dp4a(u1, 0x01010101, sumy);
1315        sumf[l0/4] += delta*sumy;
1316    }
1317
1318    const uint16_t * sc = (const uint16_t *) bq1->scales;
1319
1320    iq1m_scale_t scale;
1321    scale.u16 = (sc[0] >> 12) | ((sc[1] >> 8) & 0x00F0) | ((sc[2] >> 4) & 0x0F00) | (sc[3] & 0xF000);
1322    const float d = __half2float(scale.f16) * __low2float(bq8_1[iqs].ds);
1323
1324    const int tmp = sc[iqs/2] >> (6*(iqs%2));
1325    const int sc0 = 2*((tmp >> 0) & 0x07) + 1;
1326    const int sc1 = 2*((tmp >> 3) & 0x07) + 1;
1327    return d * ((sumi[0] + sumf[0]) * sc0 + (sumi[1] + sumf[1]) * sc1);
1328}
1329
1330#define VDR_IQ4_NL_Q8_1_MMVQ 2
1331#define VDR_IQ4_NL_Q8_1_MMQ  4
1332
1333static __device__ __forceinline__ float vec_dot_iq4_nl_q8_1(
1334    const void * __restrict__ vbq, const block_q8_1 * __restrict__ bq8_1, const int & kbx, const int & iqs) {
1335
1336    const block_iq4_nl * bq4 = (const block_iq4_nl *) vbq + kbx;
1337
1338    const int * q8 = (const int *) bq8_1->qs + iqs;
1339
1340    int sumi = 0;
1341#pragma unroll
1342    for (int l = 0; l < VDR_Q4_0_Q8_1_MMVQ; ++l) {
1343        const int aux_q4 = get_int_b2(bq4->qs, iqs + l);
1344        const int2 v = get_int_from_table_16(aux_q4, kvalues_iq4nl);
1345
1346        sumi = ggml_cuda_dp4a(v.x, q8[l + 0], sumi);
1347        sumi = ggml_cuda_dp4a(v.y, q8[l + 4], sumi);
1348    }
1349
1350    const float d = __half2float(bq4->d) * __low2float(bq8_1->ds);
1351    return d * sumi;
1352}
1353
1354#define VDR_IQ4_XS_Q8_1_MMVQ 4
1355#define VDR_IQ4_XS_Q8_1_MMQ  4
1356
1357static __device__ __forceinline__ float vec_dot_iq4_xs_q8_1(
1358    const void * __restrict__ vbq, const block_q8_1 * __restrict__ bq8_1, const int & kbx, const int & iqs) {
1359
1360    const block_iq4_xs * bq4 = (const block_iq4_xs *) vbq + kbx;
1361
1362    int sumi = 0;
1363#pragma unroll
1364    for (int j = 0; j < 4; ++j) {
1365        const int aux_q4 = get_int_b4(bq4->qs, iqs + j);
1366        const int2 v = get_int_from_table_16(aux_q4, kvalues_iq4nl);
1367
1368        const int u0 = get_int_b4(bq8_1[iqs/4].qs, j + 0);
1369        const int u1 = get_int_b4(bq8_1[iqs/4].qs, j + 4);
1370
1371        sumi = ggml_cuda_dp4a(v.x, u0, sumi);
1372        sumi = ggml_cuda_dp4a(v.y, u1, sumi);
1373    }
1374
1375    const int ls = ((bq4->scales_l[iqs/8] >> (iqs & 0x04)) & 0x0F) | (((bq4->scales_h >> (iqs/2)) & 0x03) << 4);
1376    sumi *= ls - 32;
1377
1378    const float d = __half2float(bq4->d) * __low2float(bq8_1[iqs/4].ds);
1379    return d * sumi;
1380}