char-fork/llama.cpp

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

Max Krasnyanskyhexagon: new vtcm layouts and improved pipelines for MUL_MAT, MUL_MAT_ID and FLASH_ATTN_EXT (#25425)81ff7abe5

char/aliceai-t5-moe
22.1 KiB555 linesraw
1#ifndef HMX_FA_KERNELS_H
2#define HMX_FA_KERNELS_H
3
4#include <stdint.h>
5#include <stddef.h>
6#include <stdbool.h>
7#include "hvx-utils.h"
8#include "hmx-utils.h"
9#include "hex-fastdiv.h"
10
11// HMX-specific parameters, offsets and inner kernels for Flash Attention
12
13// Scatter offsets for diagonal tile: entry[2i] = i*136, entry[2i+1] = i*136+6
14// 136 = 4 * 32 + 8 = byte offset to diagonal in a 32x32 fp16 interleaved tile
15static const int16_t d_tile_scatter_offsets[64] __attribute__((aligned(128))) = {
16    0 * 136,  0 * 136 + 6,
17    1 * 136,  1 * 136 + 6,
18    2 * 136,  2 * 136 + 6,
19    3 * 136,  3 * 136 + 6,
20    4 * 136,  4 * 136 + 6,
21    5 * 136,  5 * 136 + 6,
22    6 * 136,  6 * 136 + 6,
23    7 * 136,  7 * 136 + 6,
24    8 * 136,  8 * 136 + 6,
25    9 * 136,  9 * 136 + 6,
26    10 * 136, 10 * 136 + 6,
27    11 * 136, 11 * 136 + 6,
28    12 * 136, 12 * 136 + 6,
29    13 * 136, 13 * 136 + 6,
30    14 * 136, 14 * 136 + 6,
31    15 * 136, 15 * 136 + 6,
32    0,        0,
33    0,        0,
34    0,        0,
35    0,        0,
36    0,        0,
37    0,        0,
38    0,        0,
39    0,        0,
40    0,        0,
41    0,        0,
42    0,        0,
43    0,        0,
44    0,        0,
45    0,        0,
46    0,        0,
47    0,        0,
48};
49// Inner HMX tile computation kernels
50
51static void hmx_fa_qk_dot_tile(
52    const __fp16 * row_tiles,
53    const __fp16 * col_tiles,
54    __fp16 *       out_tile,
55    size_t         n_dot_tiles
56) {
57    if (n_dot_tiles == 2) {
58        asm volatile(
59            HMX_LOAD_MPY_F16("%1", "%2", "%0")
60            HMX_LOAD_MPY_F16("%3", "%4", "%0")
61            :
62            : "r"(2047),
63              "r"(row_tiles + 0 * HMX_FP16_TILE_N_ELMS), "r"(col_tiles + 0 * HMX_FP16_TILE_N_ELMS),
64              "r"(row_tiles + 1 * HMX_FP16_TILE_N_ELMS), "r"(col_tiles + 1 * HMX_FP16_TILE_N_ELMS)
65        );
66    } else if (n_dot_tiles == 4) {
67        asm volatile(
68            HMX_LOAD_MPY_F16("%1", "%2", "%0")
69            HMX_LOAD_MPY_F16("%3", "%4", "%0")
70            HMX_LOAD_MPY_F16("%5", "%6", "%0")
71            HMX_LOAD_MPY_F16("%7", "%8", "%0")
72            :
73            : "r"(2047),
74              "r"(row_tiles + 0 * HMX_FP16_TILE_N_ELMS), "r"(col_tiles + 0 * HMX_FP16_TILE_N_ELMS),
75              "r"(row_tiles + 1 * HMX_FP16_TILE_N_ELMS), "r"(col_tiles + 1 * HMX_FP16_TILE_N_ELMS),
76              "r"(row_tiles + 2 * HMX_FP16_TILE_N_ELMS), "r"(col_tiles + 2 * HMX_FP16_TILE_N_ELMS),
77              "r"(row_tiles + 3 * HMX_FP16_TILE_N_ELMS), "r"(col_tiles + 3 * HMX_FP16_TILE_N_ELMS)
78        );
79    } else if (n_dot_tiles == 8) {
80        asm volatile(
81            HMX_LOAD_MPY_F16("%1", "%2", "%0")
82            HMX_LOAD_MPY_F16("%3", "%4", "%0")
83            HMX_LOAD_MPY_F16("%5", "%6", "%0")
84            HMX_LOAD_MPY_F16("%7", "%8", "%0")
85            HMX_LOAD_MPY_F16("%9", "%10", "%0")
86            HMX_LOAD_MPY_F16("%11", "%12", "%0")
87            HMX_LOAD_MPY_F16("%13", "%14", "%0")
88            HMX_LOAD_MPY_F16("%15", "%16", "%0")
89            :
90            : "r"(2047),
91              "r"(row_tiles + 0 * HMX_FP16_TILE_N_ELMS), "r"(col_tiles + 0 * HMX_FP16_TILE_N_ELMS),
92              "r"(row_tiles + 1 * HMX_FP16_TILE_N_ELMS), "r"(col_tiles + 1 * HMX_FP16_TILE_N_ELMS),
93              "r"(row_tiles + 2 * HMX_FP16_TILE_N_ELMS), "r"(col_tiles + 2 * HMX_FP16_TILE_N_ELMS),
94              "r"(row_tiles + 3 * HMX_FP16_TILE_N_ELMS), "r"(col_tiles + 3 * HMX_FP16_TILE_N_ELMS),
95              "r"(row_tiles + 4 * HMX_FP16_TILE_N_ELMS), "r"(col_tiles + 4 * HMX_FP16_TILE_N_ELMS),
96              "r"(row_tiles + 5 * HMX_FP16_TILE_N_ELMS), "r"(col_tiles + 5 * HMX_FP16_TILE_N_ELMS),
97              "r"(row_tiles + 6 * HMX_FP16_TILE_N_ELMS), "r"(col_tiles + 6 * HMX_FP16_TILE_N_ELMS),
98              "r"(row_tiles + 7 * HMX_FP16_TILE_N_ELMS), "r"(col_tiles + 7 * HMX_FP16_TILE_N_ELMS)
99        );
100    } else {
101        for (size_t k = 0; k < n_dot_tiles; ++k) {
102            asm volatile(
103                HMX_LOAD_MPY_F16("%1", "%2", "%0")
104                :
105                : "r"(2047), "r"(row_tiles), "r"(col_tiles)
106            );
107            row_tiles += HMX_FP16_TILE_N_ELMS;
108            col_tiles += HMX_FP16_TILE_N_ELMS;
109        }
110    }
111    asm volatile(
112        HMX_STORE_AFTER_F16("%0", "%1")
113        :
114        : "r"(out_tile), "r"(0)
115        : "memory"
116    );
117}
118
119static void hmx_fa_o_update_tile(
120    const __fp16 * d_diag,
121    const __fp16 * o_rc,
122    const __fp16 * p_tile_in,
123    const __fp16 * v_tile_in,
124    __fp16 *       o_tile_out,
125    size_t         n_col_tiles
126) {
127    asm volatile(
128        HMX_LOAD_MPY_F16("%1", "%2", "%0")
129        :
130        : "r"(2047), "r"(d_diag), "r"(o_rc)
131    );
132    if (n_col_tiles == 2) {
133        asm volatile(
134            HMX_LOAD_MPY_F16("%1", "%2", "%0")
135            HMX_LOAD_MPY_F16("%3", "%4", "%0")
136            :
137            : "r"(2047),
138              "r"(p_tile_in + 0 * HMX_FP16_TILE_N_ELMS), "r"(v_tile_in + 0 * HMX_FP16_TILE_N_ELMS),
139              "r"(p_tile_in + 1 * HMX_FP16_TILE_N_ELMS), "r"(v_tile_in + 1 * HMX_FP16_TILE_N_ELMS)
140        );
141    } else if (n_col_tiles == 4) {
142        asm volatile(
143            HMX_LOAD_MPY_F16("%1", "%2", "%0")
144            HMX_LOAD_MPY_F16("%3", "%4", "%0")
145            HMX_LOAD_MPY_F16("%5", "%6", "%0")
146            HMX_LOAD_MPY_F16("%7", "%8", "%0")
147            :
148            : "r"(2047),
149              "r"(p_tile_in + 0 * HMX_FP16_TILE_N_ELMS), "r"(v_tile_in + 0 * HMX_FP16_TILE_N_ELMS),
150              "r"(p_tile_in + 1 * HMX_FP16_TILE_N_ELMS), "r"(v_tile_in + 1 * HMX_FP16_TILE_N_ELMS),
151              "r"(p_tile_in + 2 * HMX_FP16_TILE_N_ELMS), "r"(v_tile_in + 2 * HMX_FP16_TILE_N_ELMS),
152              "r"(p_tile_in + 3 * HMX_FP16_TILE_N_ELMS), "r"(v_tile_in + 3 * HMX_FP16_TILE_N_ELMS)
153        );
154    } else if (n_col_tiles == 8) {
155        asm volatile(
156            HMX_LOAD_MPY_F16("%1", "%2", "%0")
157            HMX_LOAD_MPY_F16("%3", "%4", "%0")
158            HMX_LOAD_MPY_F16("%5", "%6", "%0")
159            HMX_LOAD_MPY_F16("%7", "%8", "%0")
160            HMX_LOAD_MPY_F16("%9", "%10", "%0")
161            HMX_LOAD_MPY_F16("%11", "%12", "%0")
162            HMX_LOAD_MPY_F16("%13", "%14", "%0")
163            HMX_LOAD_MPY_F16("%15", "%16", "%0")
164            :
165            : "r"(2047),
166              "r"(p_tile_in + 0 * HMX_FP16_TILE_N_ELMS), "r"(v_tile_in + 0 * HMX_FP16_TILE_N_ELMS),
167              "r"(p_tile_in + 1 * HMX_FP16_TILE_N_ELMS), "r"(v_tile_in + 1 * HMX_FP16_TILE_N_ELMS),
168              "r"(p_tile_in + 2 * HMX_FP16_TILE_N_ELMS), "r"(v_tile_in + 2 * HMX_FP16_TILE_N_ELMS),
169              "r"(p_tile_in + 3 * HMX_FP16_TILE_N_ELMS), "r"(v_tile_in + 3 * HMX_FP16_TILE_N_ELMS),
170              "r"(p_tile_in + 4 * HMX_FP16_TILE_N_ELMS), "r"(v_tile_in + 4 * HMX_FP16_TILE_N_ELMS),
171              "r"(p_tile_in + 5 * HMX_FP16_TILE_N_ELMS), "r"(v_tile_in + 5 * HMX_FP16_TILE_N_ELMS),
172              "r"(p_tile_in + 6 * HMX_FP16_TILE_N_ELMS), "r"(v_tile_in + 6 * HMX_FP16_TILE_N_ELMS),
173              "r"(p_tile_in + 7 * HMX_FP16_TILE_N_ELMS), "r"(v_tile_in + 7 * HMX_FP16_TILE_N_ELMS)
174        );
175    } else {
176        for (size_t k = 0; k < n_col_tiles; ++k) {
177            asm volatile(
178                HMX_LOAD_MPY_F16("%1", "%2", "%0")
179                :
180                : "r"(2047), "r"(p_tile_in), "r"(v_tile_in)
181            );
182            p_tile_in += HMX_FP16_TILE_N_ELMS;
183            v_tile_in += HMX_FP16_TILE_N_ELMS;
184        }
185    }
186    asm volatile(
187        HMX_STORE_AFTER_F16("%0", "%1")
188        :
189        : "r"(o_tile_out), "r"(0)
190        : "memory"
191    );
192}
193
194static inline void hmx_fa_o_norm_tile(
195    const __fp16 * d_diag,
196    const __fp16 * o_rc,
197    __fp16 *       o_out
198) {
199    asm volatile(
200        HMX_LOAD_MPY_F16("%1", "%2", "%0")
201        :
202        : "r"(2047), "r"(d_diag), "r"(o_rc)
203    );
204    asm volatile(
205        HMX_STORE_AFTER_F16("%0", "%1")
206        :
207        : "r"(o_out), "r"(0)
208        : "memory"
209    );
210}
211
212static inline void hmx_fa_q_prep_fp32_d2(
213    __fp16 * vtcm_q_tiles, const uint8_t * temp_q_vtcm,
214    size_t start, size_t end, size_t g_rows_end,
215    size_t DK, size_t G, size_t n_rows_q,
216    const struct fastdiv_values * div_G, bool q_transposed
217) {
218    for (size_t r = start; r < end; r += 2) {
219        size_t   r0       = r / HMX_FP16_TILE_N_ROWS;
220        size_t   r1       = r % HMX_FP16_TILE_N_ROWS;
221        __fp16 * out_base = vtcm_q_tiles + r0 * HMX_FP16_TILE_N_ROWS * DK;
222
223        if (r >= g_rows_end) {
224            ((HVX_Vector *) (out_base + 0 * HMX_FP16_TILE_N_ELMS))[r1 / 2] = Q6_V_vzero();
225            ((HVX_Vector *) (out_base + 1 * HMX_FP16_TILE_N_ELMS))[r1 / 2] = Q6_V_vzero();
226            continue;
227        }
228
229        const size_t q_idx0 = fastdiv(r + 0, div_G);
230        const size_t h_idx0 = fastmodulo(r + 0, G, div_G);
231        const size_t q_idx1 = fastdiv(r + 1, div_G);
232        const size_t h_idx1 = fastmodulo(r + 1, G, div_G);
233
234        const size_t offset0 = q_transposed ? (h_idx0 * n_rows_q + q_idx0) : (q_idx0 * G + h_idx0);
235        const size_t offset1 = q_transposed ? (h_idx1 * n_rows_q + q_idx1) : (q_idx1 * G + h_idx1);
236
237        const HVX_Vector * pv_in0 = (const HVX_Vector *) (temp_q_vtcm + offset0 * DK * sizeof(float));
238        const HVX_Vector * pv_in1 = (r + 1 < g_rows_end)
239            ? (const HVX_Vector *) (temp_q_vtcm + offset1 * DK * sizeof(float))
240            : NULL;
241
242        {
243            HVX_Vector v0 = pv_in0[0];
244            HVX_Vector v1 = pv_in1 ? pv_in1[0] : Q6_V_vzero();
245            HVX_Vector v_hf = hvx_vec_f32_to_f16_shuff(v0, v1);
246            ((HVX_Vector *) (out_base + 0 * HMX_FP16_TILE_N_ELMS))[r1 / 2] = v_hf;
247        }
248        {
249            HVX_Vector v0 = pv_in0[1];
250            HVX_Vector v1 = pv_in1 ? pv_in1[1] : Q6_V_vzero();
251            HVX_Vector v_hf = hvx_vec_f32_to_f16_shuff(v0, v1);
252            ((HVX_Vector *) (out_base + 1 * HMX_FP16_TILE_N_ELMS))[r1 / 2] = v_hf;
253        }
254    }
255}
256
257static inline void hmx_fa_q_prep_fp32_d4(
258    __fp16 * vtcm_q_tiles, const uint8_t * temp_q_vtcm,
259    size_t start, size_t end, size_t g_rows_end,
260    size_t DK, size_t G, size_t n_rows_q,
261    const struct fastdiv_values * div_G, bool q_transposed
262) {
263    for (size_t r = start; r < end; r += 2) {
264        size_t   r0       = r / HMX_FP16_TILE_N_ROWS;
265        size_t   r1       = r % HMX_FP16_TILE_N_ROWS;
266        __fp16 * out_base = vtcm_q_tiles + r0 * HMX_FP16_TILE_N_ROWS * DK;
267
268        if (r >= g_rows_end) {
269            for (uint32_t d = 0; d < 4; ++d) {
270                ((HVX_Vector *) (out_base + d * HMX_FP16_TILE_N_ELMS))[r1 / 2] = Q6_V_vzero();
271            }
272            continue;
273        }
274
275        const size_t q_idx0 = fastdiv(r + 0, div_G);
276        const size_t h_idx0 = fastmodulo(r + 0, G, div_G);
277        const size_t q_idx1 = fastdiv(r + 1, div_G);
278        const size_t h_idx1 = fastmodulo(r + 1, G, div_G);
279
280        const size_t offset0 = q_transposed ? (h_idx0 * n_rows_q + q_idx0) : (q_idx0 * G + h_idx0);
281        const size_t offset1 = q_transposed ? (h_idx1 * n_rows_q + q_idx1) : (q_idx1 * G + h_idx1);
282
283        const HVX_Vector * pv_in0 = (const HVX_Vector *) (temp_q_vtcm + offset0 * DK * sizeof(float));
284        const HVX_Vector * pv_in1 = (r + 1 < g_rows_end)
285            ? (const HVX_Vector *) (temp_q_vtcm + offset1 * DK * sizeof(float))
286            : NULL;
287
288        for (uint32_t d = 0; d < 4; ++d) {
289            HVX_Vector v0 = pv_in0[d];
290            HVX_Vector v1 = pv_in1 ? pv_in1[d] : Q6_V_vzero();
291            HVX_Vector v_hf = hvx_vec_f32_to_f16_shuff(v0, v1);
292            ((HVX_Vector *) (out_base + d * HMX_FP16_TILE_N_ELMS))[r1 / 2] = v_hf;
293        }
294    }
295}
296
297static inline void hmx_fa_q_prep_fp32(
298    __fp16 * vtcm_q_tiles, const uint8_t * temp_q_vtcm,
299    size_t start, size_t end, size_t g_rows_end,
300    size_t DK, size_t G, size_t n_rows_q,
301    const struct fastdiv_values * div_G, uint32_t d_limit, bool q_transposed
302) {
303    for (size_t r = start; r < end; r += 2) {
304        size_t   r0       = r / HMX_FP16_TILE_N_ROWS;
305        size_t   r1       = r % HMX_FP16_TILE_N_ROWS;
306        __fp16 * out_base = vtcm_q_tiles + r0 * HMX_FP16_TILE_N_ROWS * DK;
307
308        if (r >= g_rows_end) {
309            for (uint32_t d = 0; d < d_limit; ++d) {
310                ((HVX_Vector *) (out_base + d * HMX_FP16_TILE_N_ELMS))[r1 / 2] = Q6_V_vzero();
311            }
312            continue;
313        }
314
315        const size_t q_idx0 = fastdiv(r + 0, div_G);
316        const size_t h_idx0 = fastmodulo(r + 0, G, div_G);
317        const size_t q_idx1 = fastdiv(r + 1, div_G);
318        const size_t h_idx1 = fastmodulo(r + 1, G, div_G);
319
320        const size_t offset0 = q_transposed ? (h_idx0 * n_rows_q + q_idx0) : (q_idx0 * G + h_idx0);
321        const size_t offset1 = q_transposed ? (h_idx1 * n_rows_q + q_idx1) : (q_idx1 * G + h_idx1);
322
323        const HVX_Vector * pv_in0 = (const HVX_Vector *) (temp_q_vtcm + offset0 * DK * sizeof(float));
324        const HVX_Vector * pv_in1 = (r + 1 < g_rows_end)
325            ? (const HVX_Vector *) (temp_q_vtcm + offset1 * DK * sizeof(float))
326            : NULL;
327
328        for (uint32_t d = 0; d < d_limit; ++d) {
329            HVX_Vector v0   = pv_in0[d];
330            HVX_Vector v1   = pv_in1 ? pv_in1[d] : Q6_V_vzero();
331            HVX_Vector v_hf = hvx_vec_f32_to_f16_shuff(v0, v1);
332
333            HVX_Vector * out_tile = (HVX_Vector *) (out_base + d * HMX_FP16_TILE_N_ELMS);
334            out_tile[r1 / 2]      = v_hf;
335        }
336    }
337}
338
339static inline void hmx_fa_q_prep_fp16_d1(
340    __fp16 * vtcm_q_tiles, const uint8_t * temp_q_vtcm,
341    size_t start, size_t end, size_t g_rows_end,
342    size_t DK, size_t G, size_t n_rows_q,
343    const struct fastdiv_values * div_G, bool q_transposed
344) {
345    for (size_t r = start; r < end; r += 2) {
346        size_t   r0       = r / HMX_FP16_TILE_N_ROWS;
347        size_t   r1       = r % HMX_FP16_TILE_N_ROWS;
348        __fp16 * out_base = vtcm_q_tiles + r0 * HMX_FP16_TILE_N_ROWS * DK;
349
350        if (r >= g_rows_end) {
351            __fp16 *     out_dtile = out_base + 0 * HMX_FP16_TILE_N_ELMS * 2;
352            HVX_Vector * pv_out0   = ((HVX_Vector *) out_dtile) + r1 / 2;
353            HVX_Vector * pv_out1   = pv_out0 + 16;
354            *pv_out0 = Q6_V_vzero();
355            *pv_out1 = Q6_V_vzero();
356            continue;
357        }
358
359        const size_t q_idx0 = fastdiv(r + 0, div_G);
360        const size_t h_idx0 = fastmodulo(r + 0, G, div_G);
361        const size_t q_idx1 = fastdiv(r + 1, div_G);
362        const size_t h_idx1 = fastmodulo(r + 1, G, div_G);
363
364        const size_t offset0 = q_transposed ? (h_idx0 * n_rows_q + q_idx0) : (q_idx0 * G + h_idx0);
365        const size_t offset1 = q_transposed ? (h_idx1 * n_rows_q + q_idx1) : (q_idx1 * G + h_idx1);
366
367        const HVX_Vector * pv_in0 = (const HVX_Vector *) (temp_q_vtcm + offset0 * DK * sizeof(__fp16));
368        const HVX_Vector * pv_in1 = (r + 1 < g_rows_end)
369            ? (const HVX_Vector *) (temp_q_vtcm + offset1 * DK * sizeof(__fp16))
370            : NULL;
371
372        HVX_Vector     v0 = pv_in0[0];
373        HVX_Vector     v1 = pv_in1 ? pv_in1[0] : Q6_V_vzero();
374        HVX_VectorPair vp = Q6_W_vshuff_VVR(v1, v0, -2);
375
376        __fp16 *     out_dtile = out_base + 0 * HMX_FP16_TILE_N_ELMS * 2;
377        HVX_Vector * pv_out0   = ((HVX_Vector *) out_dtile) + r1 / 2;
378        HVX_Vector * pv_out1   = pv_out0 + 16;
379
380        *pv_out0 = Q6_V_lo_W(vp);
381        *pv_out1 = Q6_V_hi_W(vp);
382    }
383}
384
385static inline void hmx_fa_q_prep_fp16_d2(
386    __fp16 * vtcm_q_tiles, const uint8_t * temp_q_vtcm,
387    size_t start, size_t end, size_t g_rows_end,
388    size_t DK, size_t G, size_t n_rows_q,
389    const struct fastdiv_values * div_G, bool q_transposed
390) {
391    for (size_t r = start; r < end; r += 2) {
392        size_t   r0       = r / HMX_FP16_TILE_N_ROWS;
393        size_t   r1       = r % HMX_FP16_TILE_N_ROWS;
394        __fp16 * out_base = vtcm_q_tiles + r0 * HMX_FP16_TILE_N_ROWS * DK;
395
396        if (r >= g_rows_end) {
397            for (uint32_t d = 0; d < 2; ++d) {
398                __fp16 *     out_dtile = out_base + d * HMX_FP16_TILE_N_ELMS * 2;
399                HVX_Vector * pv_out0   = ((HVX_Vector *) out_dtile) + r1 / 2;
400                HVX_Vector * pv_out1   = pv_out0 + 16;
401                *pv_out0 = Q6_V_vzero();
402                *pv_out1 = Q6_V_vzero();
403            }
404            continue;
405        }
406
407        const size_t q_idx0 = fastdiv(r + 0, div_G);
408        const size_t h_idx0 = fastmodulo(r + 0, G, div_G);
409        const size_t q_idx1 = fastdiv(r + 1, div_G);
410        const size_t h_idx1 = fastmodulo(r + 1, G, div_G);
411
412        const size_t offset0 = q_transposed ? (h_idx0 * n_rows_q + q_idx0) : (q_idx0 * G + h_idx0);
413        const size_t offset1 = q_transposed ? (h_idx1 * n_rows_q + q_idx1) : (q_idx1 * G + h_idx1);
414
415        const HVX_Vector * pv_in0 = (const HVX_Vector *) (temp_q_vtcm + offset0 * DK * sizeof(__fp16));
416        const HVX_Vector * pv_in1 = (r + 1 < g_rows_end)
417            ? (const HVX_Vector *) (temp_q_vtcm + offset1 * DK * sizeof(__fp16))
418            : NULL;
419
420        {
421            HVX_Vector     v0 = pv_in0[0];
422            HVX_Vector     v1 = pv_in1 ? pv_in1[0] : Q6_V_vzero();
423            HVX_VectorPair vp = Q6_W_vshuff_VVR(v1, v0, -2);
424
425            __fp16 *     out_dtile = out_base + 0 * HMX_FP16_TILE_N_ELMS * 2;
426            HVX_Vector * pv_out0   = ((HVX_Vector *) out_dtile) + r1 / 2;
427            HVX_Vector * pv_out1   = pv_out0 + 16;
428
429            *pv_out0 = Q6_V_lo_W(vp);
430            *pv_out1 = Q6_V_hi_W(vp);
431        }
432        {
433            HVX_Vector     v0 = pv_in0[1];
434            HVX_Vector     v1 = pv_in1 ? pv_in1[1] : Q6_V_vzero();
435            HVX_VectorPair vp = Q6_W_vshuff_VVR(v1, v0, -2);
436
437            __fp16 *     out_dtile = out_base + 1 * HMX_FP16_TILE_N_ELMS * 2;
438            HVX_Vector * pv_out0   = ((HVX_Vector *) out_dtile) + r1 / 2;
439            HVX_Vector * pv_out1   = pv_out0 + 16;
440
441            *pv_out0 = Q6_V_lo_W(vp);
442            *pv_out1 = Q6_V_hi_W(vp);
443        }
444    }
445}
446
447static inline void hmx_fa_q_prep_fp16(
448    __fp16 * vtcm_q_tiles, const uint8_t * temp_q_vtcm,
449    size_t start, size_t end, size_t g_rows_end,
450    size_t DK, size_t G, size_t n_rows_q,
451    const struct fastdiv_values * div_G, uint32_t d_limit, bool q_transposed
452) {
453    for (size_t r = start; r < end; r += 2) {
454        size_t   r0       = r / HMX_FP16_TILE_N_ROWS;
455        size_t   r1       = r % HMX_FP16_TILE_N_ROWS;
456        __fp16 * out_base = vtcm_q_tiles + r0 * HMX_FP16_TILE_N_ROWS * DK;
457
458        if (r >= g_rows_end) {
459            for (uint32_t d = 0; d < d_limit; ++d) {
460                __fp16 *     out_dtile = out_base + d * HMX_FP16_TILE_N_ELMS * 2;
461                HVX_Vector * pv_out0   = ((HVX_Vector *) out_dtile) + r1 / 2;
462                HVX_Vector * pv_out1   = pv_out0 + 16;
463                *pv_out0 = Q6_V_vzero();
464                *pv_out1 = Q6_V_vzero();
465            }
466            continue;
467        }
468
469        const size_t q_idx0 = fastdiv(r + 0, div_G);
470        const size_t h_idx0 = fastmodulo(r + 0, G, div_G);
471        const size_t q_idx1 = fastdiv(r + 1, div_G);
472        const size_t h_idx1 = fastmodulo(r + 1, G, div_G);
473
474        const size_t offset0 = q_transposed ? (h_idx0 * n_rows_q + q_idx0) : (q_idx0 * G + h_idx0);
475        const size_t offset1 = q_transposed ? (h_idx1 * n_rows_q + q_idx1) : (q_idx1 * G + h_idx1);
476
477        const HVX_Vector * pv_in0 = (const HVX_Vector *) (temp_q_vtcm + offset0 * DK * sizeof(__fp16));
478        const HVX_Vector * pv_in1 = (r + 1 < g_rows_end)
479            ? (const HVX_Vector *) (temp_q_vtcm + offset1 * DK * sizeof(__fp16))
480            : NULL;
481
482        for (uint32_t d = 0; d < d_limit; ++d) {
483            HVX_Vector     v0 = pv_in0[d];
484            HVX_Vector     v1 = pv_in1 ? pv_in1[d] : Q6_V_vzero();
485            HVX_VectorPair vp = Q6_W_vshuff_VVR(v1, v0, -2);
486
487            __fp16 *     out_dtile = out_base + d * HMX_FP16_TILE_N_ELMS * 2;
488            HVX_Vector * pv_out0   = ((HVX_Vector *) out_dtile) + r1 / 2;
489            HVX_Vector * pv_out1   = pv_out0 + 16;
490
491            *pv_out0 = Q6_V_lo_W(vp);
492            *pv_out1 = Q6_V_hi_W(vp);
493        }
494    }
495}
496
497
498static inline void hmx_fa_q_prep_fallback(
499    __fp16 * vtcm_q_tiles, uintptr_t q_data,
500    size_t q_nb1, size_t q_nb2, size_t q_nb3,
501    uint32_t q_start, uint32_t kv_head, uint32_t ib3,
502    size_t start, size_t end, size_t n_rows_g,
503    size_t G, size_t DK, bool is_q_fp32,
504    const struct fastdiv_values * div_G
505) {
506    for (size_t r = start; r < end; r += 2) {
507        const size_t q_idx0 = fastdiv(r + 0, div_G);
508        const size_t h_idx0 = fastmodulo(r + 0, G, div_G);
509        const size_t q_idx1 = fastdiv(r + 1, div_G);
510        const size_t h_idx1 = fastmodulo(r + 1, G, div_G);
511
512        const uint8_t * q_ptr0 = (r + 0 < n_rows_g) ? ((const uint8_t *) q_data + (q_start + q_idx0) * q_nb1 +
513                                                      (kv_head * G + h_idx0) * q_nb2 + ib3 * q_nb3) :
514                                                      NULL;
515        const uint8_t * q_ptr1 = (r + 1 < n_rows_g) ? ((const uint8_t *) q_data + (q_start + q_idx1) * q_nb1 +
516                                                      (kv_head * G + h_idx1) * q_nb2 + ib3 * q_nb3) :
517                                                      NULL;
518
519        size_t   r0       = r / HMX_FP16_TILE_N_ROWS;
520        size_t   r1       = r % HMX_FP16_TILE_N_ROWS;
521        __fp16 * out_base = vtcm_q_tiles + r0 * HMX_FP16_TILE_N_ROWS * DK;
522
523        if (is_q_fp32) {
524            const HVX_UVector * pv_in0 = q_ptr0 ? (const HVX_UVector *) q_ptr0 : NULL;
525            const HVX_UVector * pv_in1 = q_ptr1 ? (const HVX_UVector *) q_ptr1 : NULL;
526
527            for (uint32_t d = 0; d < DK / 32; ++d) {
528                HVX_Vector v0   = pv_in0 ? pv_in0[d] : Q6_V_vzero();
529                HVX_Vector v1   = pv_in1 ? pv_in1[d] : Q6_V_vzero();
530                HVX_Vector v_hf = hvx_vec_f32_to_f16_shuff(v0, v1);
531
532                HVX_Vector * out_tile = (HVX_Vector *) (out_base + d * HMX_FP16_TILE_N_ELMS);
533                out_tile[r1 / 2]      = v_hf;
534            }
535        } else {
536            const HVX_UVector * pv_in0 = q_ptr0 ? (const HVX_UVector *) q_ptr0 : NULL;
537            const HVX_UVector * pv_in1 = q_ptr1 ? (const HVX_UVector *) q_ptr1 : NULL;
538
539            for (uint32_t d = 0; d < DK / 64; ++d) {
540                HVX_Vector     v0 = pv_in0 ? pv_in0[d] : Q6_V_vzero();
541                HVX_Vector     v1 = pv_in1 ? pv_in1[d] : Q6_V_vzero();
542                HVX_VectorPair vp = Q6_W_vshuff_VVR(v1, v0, -2);
543
544                __fp16 *     out_dtile = out_base + d * HMX_FP16_TILE_N_ELMS * 2;
545                HVX_Vector * pv_out0   = ((HVX_Vector *) out_dtile) + r1 / 2;
546                HVX_Vector * pv_out1   = pv_out0 + 16;
547
548                *pv_out0 = Q6_V_lo_W(vp);
549                *pv_out1 = Q6_V_hi_W(vp);
550            }
551        }
552    }
553}
554
555#endif /* HMX_FA_KERNELS_H */