char-fork/llama.cpp
git clone https://git.t4t.associates/char-fork/llama.cpp
eafe15a5e
char/aliceai-t5-moe
1// HMX tile-level inline helpers (FP16 32x32 tile operations). 2// Ported from htp-ops-lib/include/dsp/hmx_utils.h. (https://github.com/haozixu/htp-ops-lib) 3 4#ifndef HMX_UTILS_H 5#define HMX_UTILS_H 6 7#include "hvx-base.h" 8 9#include <assert.h> 10#include <hexagon_types.h> 11#include <stddef.h> 12 13#define HMX_FP16_TILE_N_ROWS 32 14#define HMX_FP16_TILE_N_COLS 32 15#define HMX_FP16_TILE_N_ELMS 1024 16#define HMX_FP16_TILE_SIZE 2048 17 18// Initialise aligned 256-byte area with scale vector + zero padding. 19static inline void hmx_init_column_scales (void * out_scales ,HVX_Vector v_scale ) { 20volatile HVX_Vector * pv = (HVX_Vector * )out_scales ; 21pv [0 ]= v_scale ; 22pv [1 ]= Q6_V_vzero (); 23} 24 25// --- Shared scatter offsets and interleave helper --- 26 27// vscatter offsets for fused dequant+transpose: write K-values directly to [K][N] tile. 28// word[i] = i*128 maps K-row-pair i to byte offset i*128. 29// Column offset (n*4) is added at runtime. Entries 0..15 cover one tile (region 2047); 30// entries 16..31 cover the next adjacent tile (region 4095) - pick region size at the 31// call site to scatter into one tile (masked) or two contiguous tiles (unmasked). 32static const int32_t hmx_transpose_scatter_offsets [32 ] __attribute__((aligned (VLEN )))= { 330 * 128 ,1 * 128 ,2 * 128 ,3 * 128 ,4 * 128 ,5 * 128 ,6 * 128 ,7 * 128 ,8 * 128 ,9 * 128 ,10 * 128 , 3411 * 128 ,12 * 128 ,13 * 128 ,14 * 128 ,15 * 128 ,16 * 128 ,17 * 128 ,18 * 128 ,19 * 128 ,20 * 128 ,21 * 128 , 3522 * 128 ,23 * 128 ,24 * 128 ,25 * 128 ,26 * 128 ,27 * 128 ,28 * 128 ,29 * 128 ,30 * 128 ,31 * 128 , 36}; 37 38// Scatter row-major FP16 data (in VTCM scratch) into transposed [K][N] tiles. 39// vtcm_src: [n_cols][src_stride] row-major fp16 (only first k elements per row are used) 40// vtcm_dst: [n_col_tiles][n_k_tiles][HMX_FP16_TILE_N_ELMS] tile-major interleaved fp16 41// Processes rows [start_row, end_row) for multi-thread slicing. 42// Full range: start_row=0, end_row=n_cols. 43static inline void hmx_interleave_rows_to_tiles (__fp16 * restrictvtcm_dst , 44const __fp16 * restrictvtcm_src , 45uint32_t n_cols , 46uint32_t k , 47size_t src_stride , 48uint32_t start_row , 49uint32_t end_row ) { 50assert (k %HMX_FP16_TILE_N_COLS == 0 ); 51 52const uint32_t n_k_tiles = k /HMX_FP16_TILE_N_COLS ; 53const HVX_Vector v_scat_base = hvx_vmem (hmx_transpose_scatter_offsets ); 54const HVX_Vector v_scat_step = Q6_V_vsplat_R (4 ); 55const HVX_VectorPred q_mask64 = Q6_Q_vsetq_R (64 ); 56// Each hvx_vmemu load brings 64 fp16 = 128 bytes covering 2 adjacent K-tiles. 57// When n_k_tiles is even, scatter into 2 K-tiles per call (region 4095, no mask) 58// using the upper half of hmx_transpose_scatter_offsets. Tail one K-tile (when 59// n_k_tiles is odd) falls back to single-tile masked scatter. 60const bool pair_scatter = (n_k_tiles & 1 )== 0 ; 61const size_t pair_region = (size_t ) (2 * HMX_FP16_TILE_SIZE - 1 ); 62const size_t single_region = (size_t ) (HMX_FP16_TILE_SIZE - 1 ); 63__builtin_assume (k > 0 ); 64__builtin_assume (end_row > start_row ); 65 66if (pair_scatter ) { 67// Step c by 64 fp16 (two K-tiles per scatter), advance dst by 2 tiles per iter. 68const uint32_t c_step = 2 * HMX_FP16_TILE_N_COLS ; 69const size_t c_byte_step = (size_t )c_step * sizeof (__fp16 ); 70const size_t dst_step = 2 * (size_t )HMX_FP16_TILE_N_ELMS ; 71const uint32_t n_c_iters = k /c_step ; 72 73for (uint32_t r = start_row ;r < end_row ;r += 2 ) { 74const uint32_t ct = r /HMX_FP16_TILE_N_ROWS ; 75const uint32_t local_r = r %HMX_FP16_TILE_N_ROWS ; 76const bool next_row_valid = (r + 1 )< end_row && (r + 1 )< n_cols ; 77const HVX_Vector v_off0 = Q6_Vw_vadd_VwVw (v_scat_base ,Q6_V_vsplat_R (local_r * 4 )); 78const HVX_Vector v_off1 = Q6_Vw_vadd_VwVw (v_off0 ,v_scat_step ); 79 80__fp16 * tile_base = vtcm_dst + (size_t )ct * n_k_tiles * HMX_FP16_TILE_N_ELMS ; 81const uint8_t * p0 = (const uint8_t * ) (vtcm_src + r * src_stride ); 82const uint8_t * p1 = next_row_valid ? (const uint8_t * ) (vtcm_src + (r + 1 )* src_stride ) :NULL ; 83 84assert (hex_is_aligned (p0 ,128 )); 85assert (hex_is_aligned (p1 ,128 )); 86assert (c_byte_step %128 == 0 ); 87 88if (p1 ) { 89for (uint32_t i = 0 ;i < n_c_iters ;++ i ) { 90HVX_Vector v0 = hvx_vmem (p0 );p0 += c_byte_step ; 91HVX_Vector v1 = hvx_vmem (p1 );p1 += c_byte_step ; 92Q6_vscatter_RMVwV ((size_t )tile_base ,pair_region ,v_off0 ,v0 ); 93Q6_vscatter_RMVwV ((size_t )tile_base ,pair_region ,v_off1 ,v1 ); 94tile_base += dst_step ; 95 } 96 }else { 97const HVX_Vector vzero = Q6_V_vzero (); 98for (uint32_t i = 0 ;i < n_c_iters ;++ i ) { 99HVX_Vector v0 = hvx_vmem (p0 );p0 += c_byte_step ; 100Q6_vscatter_RMVwV ((size_t )tile_base ,pair_region ,v_off0 ,v0 ); 101Q6_vscatter_RMVwV ((size_t )tile_base ,pair_region ,v_off1 ,vzero ); 102tile_base += dst_step ; 103 } 104 } 105 } 106 }else { 107// Fallback: scatter one K-tile per call (region 2047, masked). 108const uint32_t c_step = HMX_FP16_TILE_N_COLS ; 109const size_t c_byte_step = (size_t )c_step * sizeof (__fp16 ); 110const size_t dst_step = (size_t )HMX_FP16_TILE_N_ELMS ; 111const uint32_t n_c_iters = k /c_step ; 112 113for (uint32_t r = start_row ;r < end_row ;r += 2 ) { 114const uint32_t ct = r /HMX_FP16_TILE_N_ROWS ; 115const uint32_t local_r = r %HMX_FP16_TILE_N_ROWS ; 116const bool next_row_valid = (r + 1 )< end_row && (r + 1 )< n_cols ; 117const HVX_Vector v_off0 = Q6_Vw_vadd_VwVw (v_scat_base ,Q6_V_vsplat_R (local_r * 4 )); 118const HVX_Vector v_off1 = Q6_Vw_vadd_VwVw (v_off0 ,v_scat_step ); 119 120__fp16 * tile_base = vtcm_dst + (size_t )ct * n_k_tiles * HMX_FP16_TILE_N_ELMS ; 121const uint8_t * p0 = (const uint8_t * ) (vtcm_src + r * src_stride ); 122const uint8_t * p1 = next_row_valid ? (const uint8_t * ) (vtcm_src + (r + 1 )* src_stride ) :NULL ; 123 124if (p1 ) { 125for (uint32_t i = 0 ;i < n_c_iters ;++ i ) { 126HVX_Vector v0 = hvx_vmemu (p0 );p0 += c_byte_step ; 127HVX_Vector v1 = hvx_vmemu (p1 );p1 += c_byte_step ; 128Q6_vscatter_QRMVwV (q_mask64 , (size_t )tile_base ,single_region ,v_off0 ,v0 ); 129Q6_vscatter_QRMVwV (q_mask64 , (size_t )tile_base ,single_region ,v_off1 ,v1 ); 130tile_base += dst_step ; 131 } 132 }else { 133const HVX_Vector vzero = Q6_V_vzero (); 134for (uint32_t i = 0 ;i < n_c_iters ;++ i ) { 135HVX_Vector v0 = hvx_vmemu (p0 );p0 += c_byte_step ; 136Q6_vscatter_QRMVwV (q_mask64 , (size_t )tile_base ,single_region ,v_off0 ,v0 ); 137Q6_vscatter_QRMVwV (q_mask64 , (size_t )tile_base ,single_region ,v_off1 ,vzero ); 138tile_base += dst_step ; 139 } 140 } 141 } 142 } 143} 144 145// Interleave row-major FP16 data into column-major tile format. 146// Input: [n_rows, head_dim] row-major. Output: tile[dim_tile][row_tile]. 147// Processes rows [start_row, end_row) for multi-thread slicing. 148// Full range: start_row=0, end_row=n_rows. 149static inline void hmx_interleave_cols_to_tiles (__fp16 * restricttiles_out , 150const __fp16 * restrictsrc , 151uint32_t n_rows , 152uint32_t head_dim , 153size_t src_stride , 154uint32_t n_row_tiles , 155uint32_t start_row , 156uint32_t end_row ) { 157__builtin_assume (head_dim > 0 ); 158const size_t tile_stride_elms = (size_t )n_row_tiles * HMX_FP16_TILE_N_ELMS ; 159 160for (uint32_t r = start_row ;r < end_row ;r += 2 ) { 161const bool next_row_valid = (r + 1 )< end_row && (r + 1 )< n_rows ; 162 163const HVX_Vector * pv_in0 = (const HVX_Vector * ) (src + r * src_stride ); 164const HVX_Vector * pv_in1 = next_row_valid ? (const HVX_Vector * ) (src + (r + 1 )* src_stride ) :NULL ; 165 166// Row-pair invariants hoisted out of the c loop. 167const uint32_t r0 = r /HMX_FP16_TILE_N_ROWS ; 168const uint32_t r1_half = (r %HMX_FP16_TILE_N_ROWS ) /2 ; 169 170// tb0 starts at tile (c0=0, r0); tb1 at the adjacent dim-tile (c0=1, r0). 171// Each c step (+= 64) advances both by 2 dim-tiles worth of fp16. 172__fp16 * tb0 = tiles_out + (size_t )r0 * HMX_FP16_TILE_N_ELMS ; 173__fp16 * tb1 = tb0 + tile_stride_elms ; 174const size_t tb_step = 2 * tile_stride_elms ; 175 176if (pv_in1 ) { 177for (uint32_t c = 0 ;c < head_dim ;c += 64 ) { 178HVX_Vector v0 = * pv_in0 ++ ; 179HVX_Vector v1 = * pv_in1 ++ ; 180HVX_VectorPair vp = Q6_W_vshuff_VVR (v1 ,v0 ,-2 ); 181 ((HVX_Vector * )tb0 )[r1_half ]= Q6_V_lo_W (vp ); 182 ((HVX_Vector * )tb1 )[r1_half ]= Q6_V_hi_W (vp ); 183tb0 += tb_step ; 184tb1 += tb_step ; 185 } 186 }else { 187const HVX_Vector vzero = Q6_V_vzero (); 188for (uint32_t c = 0 ;c < head_dim ;c += 64 ) { 189HVX_Vector v0 = * pv_in0 ++ ; 190HVX_VectorPair vp = Q6_W_vshuff_VVR (vzero ,v0 ,-2 ); 191 ((HVX_Vector * )tb0 )[r1_half ]= Q6_V_lo_W (vp ); 192 ((HVX_Vector * )tb1 )[r1_half ]= Q6_V_hi_W (vp ); 193tb0 += tb_step ; 194tb1 += tb_step ; 195 } 196 } 197 } 198} 199 200// --- HMX inline asm macros for load-store packetization --- 201#define HMX_LOAD_MPY_F16 (act ,wt ,range ) \ 202 "{\n" \ 203 " activation.hf = mxmem(" act ", " range ")\n" \ 204 " weight.hf = mxmem(" wt ", " range ")\n" \ 205 "}\n" 206 207#define HMX_LOAD_MPY_DEEP_F16 (act ,wt ,range ) \ 208 "{\n" \ 209 " activation.hf = mxmem(" act ", " range "):deep\n" \ 210 " weight.hf = mxmem(" wt ", " range ")\n" \ 211 "}\n" 212 213#define HMX_STORE_AFTER_F16 (out ,scale_reg ) \ 214 "mxmem(" out ", " scale_reg "):after.hf = acc\n" 215 216#define HMX_SET_BIAS (scales ) \ 217 "bias = mxmem2(" scales ")\n" 218 219#define HMX_CLRACC_F16 () \ 220 "mxclracc.hf\n" 221 222#endif // HMX_UTILS_H