char-fork/llama.cpp
git clone https://git.t4t.associates/char-fork/llama.cpp
960dffab0
char/aliceai-t5-moe
1#ifndef HTP_MATMUL_OPS_H 2#define HTP_MATMUL_OPS_H 3 4#include <stdint.h> 5#include <stddef.h> 6#include "htp-ops.h" 7#include "hex-fastdiv.h" 8#include "hex-common.h" 9#include "htp-vtcm.h" 10 11#ifdef __cplusplus 12extern "C" { 13#endif 14 15// --- HMX Tile Constraints --- 16#define HTP_MM_HMX_TILE_N_COLS 32 17#define HTP_MM_HMX_TILE_N_ROWS 32 18#define HTP_MM_HMX_TILE_SIZE (32 * 32 * sizeof(__fp16)) // 2048 bytes 19#define HTP_MM_HMX_TILE_N_ELMS 1024 20#define HTP_MM_HMX_MIN_NROWS 4 21 22// --- Weight Repacked Tile Sizes --- 23#define HTP_MM_WEIGHT_TILE_SIZE_Q4_0 576 24#define HTP_MM_WEIGHT_TILE_SIZE_Q4_1 640 25#define HTP_MM_WEIGHT_TILE_SIZE_Q8_0 1088 26#define HTP_MM_WEIGHT_TILE_SIZE_IQ4_NL 576 27#define HTP_MM_WEIGHT_TILE_SIZE_MXFP4 544 28 29// --- Weight Repacked Aligned Tile Sizes --- 30#define HTP_MM_WEIGHT_ALIGNED_TILE_SIZE_Q4_0 640 31#define HTP_MM_WEIGHT_ALIGNED_TILE_SIZE_Q4_1 640 32#define HTP_MM_WEIGHT_ALIGNED_TILE_SIZE_Q8_0 1152 33#define HTP_MM_WEIGHT_ALIGNED_TILE_SIZE_IQ4_NL 640 34#define HTP_MM_WEIGHT_ALIGNED_TILE_SIZE_MXFP4 640 35 36// --- Activation Tiled Block Sizes (including padding) --- 37#define HTP_MM_ACT_TILE_SIZE_Q8_0 1152 38#define HTP_MM_ACT_TILE_SIZE_Q8_1 1280 39 40#define HTP_MM_MAX_PREFETCH 16 41 42// --- Solver Cost Model Penalty Weights (HMX-specific) --- 43#define HTP_MM_HMX_COST_W_DEQUANT 3 // cost penalty for quantized weight loading/dequantization 44#define HTP_MM_HMX_COST_A_CONVERT 2 // cost penalty for activation loading/conversion 45 46// --- DMA Activation Transfer Configuration --- 47#define HTP_MM_DMA_ACT_ROWS_PER_STEP 2 48#define HTP_MM_DMA_ACT_MULTIPLIER (2 * HTP_MM_DMA_ACT_ROWS_PER_STEP) 49 50enum htp_mm_kernel_type { 51HTP_MM_KERNEL_UNSUPPORTED = 0 , 52 53// HMX paths 54HTP_MM_KERNEL_HMX_2D , 55HTP_MM_KERNEL_HMX_F16_BATCHED , 56 57// HVX floating-point paths 58HTP_MM_KERNEL_HVX_F16_F16_VTCM , 59HTP_MM_KERNEL_HVX_F16_F16_DDR , 60HTP_MM_KERNEL_HVX_F16_F32_DDR , 61 62HTP_MM_KERNEL_HVX_F32_F32_VTCM , 63HTP_MM_KERNEL_HVX_F32_F32_DDR , 64HTP_MM_KERNEL_HVX_F32_F16_DDR , 65 66// HVX quantized paths 67HTP_MM_KERNEL_HVX_QUANT_ROW ,// standard row-wise parallel quantization 68HTP_MM_KERNEL_HVX_QUANT_BLOCK ,// parallel block-wise quantization 69HTP_MM_KERNEL_HVX_QUANT_ROW_FLAT ,// row-wise fallback flat quantization 70}; 71 72// Op-specific struct for precomputed matmul params 73struct htp_mm_kernel_params { 74int32_t kernel_type ;// enum htp_mm_kernel_type 75int32_t pipeline ;// 1 = pipelined execution, 0 = standard 76int32_t m_chunk ;// Row chunk size (M chunk) 77int32_t n_chunk ;// Col chunk size (N chunk) 78int32_t n_threads ;// Number of threads to spawn 79int32_t n_act_threads ;// Number of threads for activation preparation 80int32_t n_hmx ;// 1 = use HMX, 0 = use HVX 81int32_t n_prefetch ;// Prefetch lookahead buffers/rows in VTCM 82int32_t tile_size ;// Weight tile size 83int32_t aligned_tile_size ;// Aligned weight tile size (padded to 128) 84int32_t src1_row_size ;// Row size for quantized activation 85int32_t vtcm_size ;// Total required scratchpad size in VTCM 86int32_t vtcm_src0_size ;// src0 scratchpad size in VTCM 87int32_t vtcm_src1_size ;// src1 scratchpad size in VTCM 88int32_t vtcm_src2_size ;// src2 scratchpad size in VTCM (fused only) 89int32_t vtcm_src3_size ;// src3 scratchpad size in VTCM (fused only) 90int32_t vtcm_dst_size ;// dst scratchpad size in VTCM 91int32_t n_weights ;// Number of weights for fused NX 92 93// Precomputed division values 94struct fastdiv_values div_ne12_ne1 ; 95struct fastdiv_values div_ne1 ; 96struct fastdiv_values div_r2 ; 97struct fastdiv_values div_r3 ; 98struct fastdiv_values div_ne11 ; 99struct fastdiv_values div_n_act_threads ; 100struct fastdiv_values div_ne00_padded ; 101}; 102 103#if defined(__cplusplus ) 104static_assert (sizeof (struct htp_mm_kernel_params ) <=128 ,"htp_matmul_kernel_params is too large for kernel_params blob" ); 105#else 106_Static_assert (sizeof (struct htp_mm_kernel_params ) <=128 ,"htp_matmul_kernel_params is too large for kernel_params blob" ); 107#endif 108 109struct mmid_row_mapping { 110uint32_t i1 ; 111uint32_t i2 ; 112}; 113 114// Search for optimal (mc, nc) chunk sizes within VTCM budget. 115static inline int htp_mm_hmx_compute_chunks (size_t vtcm_total , 116size_t overhead , 117size_t per_n_cost , 118size_t per_m_cost , 119size_t per_mn_cost , 120size_t m , 121size_t n , 122size_t m_block_cost , 123size_t n_block_cost , 124size_t * m_chunk_out , 125size_t * n_chunk_out , 126size_t * total_out ) { 127if (m == 0 || n == 0 )return -1 ; 128if (vtcm_total <=overhead )return -1 ; 129if (per_n_cost == 0 || per_m_cost == 0 || per_mn_cost == 0 )return -1 ; 130 131const size_t usable = vtcm_total - overhead ; 132 133size_t best_cost = SIZE_MAX ; 134size_t best_mn = 0 ; 135size_t best_m = 0 ,best_n = 0 ; 136 137const size_t max_nc_budget = (usable /per_n_cost ); 138const size_t n_max = hex_align_down (hex_smin ((size_t )n ,max_nc_budget ),HTP_MM_HMX_TILE_N_COLS ); 139for (size_t nc = n_max ;nc >=HTP_MM_HMX_TILE_N_COLS ;nc -= HTP_MM_HMX_TILE_N_COLS ) { 140size_t n_fixed = 0 ,ncmn = 0 ,mc_denom = 0 ; 141if (hex_mul_overflow (nc ,per_n_cost ,& n_fixed ))continue ; 142if (n_fixed >=usable ) gotonext_nc ; 143 144if (hex_mul_overflow (nc ,per_mn_cost ,& ncmn )) gotonext_nc ; 145if (hex_add_overflow (per_m_cost ,ncmn ,& mc_denom )|| mc_denom == 0 ) gotonext_nc ; 146 147 { 148size_t remain = usable - n_fixed ; 149size_t mc = remain /mc_denom ; 150mc = hex_align_down (mc ,HTP_MM_HMX_TILE_N_ROWS ); 151mc = hex_smin (mc ,m ); 152 153if (mc == 0 ) { 154 gotonext_nc ; 155 } 156 157size_t mblocks = ((size_t )m + mc - 1 ) /mc ; 158size_t nblocks = ((size_t )n + nc - 1 ) /nc ; 159size_t cost = mblocks * m_block_cost + nblocks * n_block_cost ; 160size_t mn = mc * nc ; 161if (cost < best_cost || (cost == best_cost && mn > best_mn )) { 162best_cost = cost ; 163best_mn = mn ; 164best_m = mc ; 165best_n = nc ; 166 } 167 } 168 169next_nc : 170if (nc == HTP_MM_HMX_TILE_N_COLS )break ;// avoid size_t underflow 171 } 172 173if (best_m == 0 || best_n == 0 )return -1 ; 174 175// Compute exact total (with overflow checks) 176size_t t0 = 0 ,t1 = 0 ,t2 = 0 ,mn = 0 ,total = 0 ; 177if (hex_mul_overflow (best_n ,per_n_cost ,& t0 ))return -1 ; 178if (hex_mul_overflow (best_m ,per_m_cost ,& t1 ))return -1 ; 179if (hex_mul_overflow (best_m ,best_n ,& mn ))return -1 ; 180if (hex_mul_overflow (mn ,per_mn_cost ,& t2 ))return -1 ; 181if (hex_add_overflow (t0 ,t1 ,& total ))return -1 ; 182if (hex_add_overflow (total ,t2 ,& total ))return -1 ; 183if (hex_add_overflow (total ,overhead ,& total ))return -1 ; 184 185* m_chunk_out = best_m ; 186* n_chunk_out = best_n ; 187* total_out = total ; 188return 0 ; 189} 190 191// --- Tile Size Helpers --- 192static inline uint32_t htp_mm_get_weight_tile_size (int weight_type ) { 193switch (weight_type ) { 194case HTP_TYPE_Q4_0 : 195case HTP_TYPE_IQ4_NL : 196return HTP_MM_WEIGHT_TILE_SIZE_Q4_0 ; 197case HTP_TYPE_Q4_1 : 198return HTP_MM_WEIGHT_TILE_SIZE_Q4_1 ; 199case HTP_TYPE_Q8_0 : 200return HTP_MM_WEIGHT_TILE_SIZE_Q8_0 ; 201case HTP_TYPE_MXFP4 : 202return HTP_MM_WEIGHT_TILE_SIZE_MXFP4 ; 203default : 204return 0 ; 205 } 206} 207 208static inline uint32_t htp_mm_get_weight_aligned_tile_size (int weight_type ) { 209switch (weight_type ) { 210case HTP_TYPE_Q4_0 : 211case HTP_TYPE_IQ4_NL : 212return HTP_MM_WEIGHT_ALIGNED_TILE_SIZE_Q4_0 ; 213case HTP_TYPE_Q4_1 : 214return HTP_MM_WEIGHT_ALIGNED_TILE_SIZE_Q4_1 ; 215case HTP_TYPE_Q8_0 : 216return HTP_MM_WEIGHT_ALIGNED_TILE_SIZE_Q8_0 ; 217case HTP_TYPE_MXFP4 : 218return HTP_MM_WEIGHT_ALIGNED_TILE_SIZE_MXFP4 ; 219default : 220return 0 ; 221 } 222} 223 224// --- Activation/Row Size Helpers --- 225static inline size_t htp_mm_q8_0_tiled_row_size (uint32_t ne ) { 226const uint32_t ne_padded = ((ne + 127 ) /128 )* 128 ; 227const uint32_t nb_32 = ne_padded /32 ; 228return nb_32 * HTP_MM_ACT_TILE_SIZE_Q8_0 ; 229} 230 231static inline size_t htp_mm_q8_1_tiled_row_size (uint32_t ne ) { 232const uint32_t ne_padded = ((ne + 127 ) /128 )* 128 ; 233const uint32_t nb_32 = ne_padded /32 ; 234return nb_32 * HTP_MM_ACT_TILE_SIZE_Q8_1 ; 235} 236 237static inline size_t htp_mm_q8_0_flat_row_size (uint32_t ne ) { 238const uint32_t quants_size = hex_align_up (ne ,128 ); 239const uint32_t num_scales = (ne + 31 ) /32 ; 240const uint32_t scales_size = hex_align_up (num_scales * 2 ,128 ); 241return quants_size + scales_size ; 242} 243 244static inline size_t htp_mm_q8_1_flat_row_size (uint32_t ne ) { 245const uint32_t quants_size = hex_align_up (ne ,128 ); 246const uint32_t num_scales = (ne + 31 ) /32 ; 247const uint32_t scales_size = hex_align_up (num_scales * 4 ,128 ); 248return quants_size + scales_size ; 249} 250 251static inline size_t htp_mm_get_tiled_row_stride (int weight_type ,uint32_t k ) { 252uint32_t nb = (k + QK_Q4_0_TILED - 1 ) /QK_Q4_0_TILED ; 253switch (weight_type ) { 254case HTP_TYPE_Q4_0 : 255case HTP_TYPE_IQ4_NL : 256case HTP_TYPE_Q4_1 : 257case HTP_TYPE_Q8_0 : 258case HTP_TYPE_MXFP4 : 259return (size_t )nb * htp_mm_get_weight_tile_size (weight_type ); 260case HTP_TYPE_F16 : 261return (size_t )k * sizeof (__fp16 ); 262case HTP_TYPE_F32 : 263return (size_t )k * sizeof (float ); 264default : 265return 0 ; 266 } 267} 268 269static inline size_t htp_mm_round_up (size_t n ,size_t m ) { 270return ((n + m - 1 ) /m )* m ; 271} 272 273static inline bool htp_mm_hmx_pipeline (uint32_t m ) { 274return m > 32 ; 275} 276 277static inline void htp_mm_hmx_get_2d_chunk_costs ( 278int wtype ,uint32_t k ,bool pipeline ,uint32_t aligned_tile_size , 279size_t * size_per_n_out ,size_t * size_per_m_out ,size_t * size_per_mn_out 280) { 281const bool is_quant = (wtype != HTP_TYPE_F16 && wtype != HTP_TYPE_F32 ); 282const size_t row_stride = htp_mm_get_tiled_row_stride (wtype ,k ); 283const size_t vec_dot_size = k * sizeof (uint16_t ); 284const uint32_t n_k_tiles = k /HTP_MM_HMX_TILE_N_COLS ; 285const size_t qweight_row_stride = is_quant ? (size_t )(n_k_tiles * aligned_tile_size ) /32 :0 ; 286 287* size_per_n_out = (pipeline ?2 :1 )* (is_quant ?qweight_row_stride :row_stride )+ 288 (pipeline ?2 * vec_dot_size :vec_dot_size ); 289* size_per_m_out = vec_dot_size ; 290* size_per_mn_out = (pipeline ?2 :1 )* sizeof (uint16_t ); 291} 292 293static inline void htp_mm_hmx_get_batched_chunk_costs ( 294uint32_t k ,uint32_t group_size , 295size_t * size_per_n_out ,size_t * size_per_m_out ,size_t * size_per_mn_out 296) { 297const size_t vec_dot_size = k * sizeof (uint16_t ); 298* size_per_n_out = 3 * vec_dot_size ; 299* size_per_m_out = group_size * vec_dot_size ; 300* size_per_mn_out = sizeof (uint16_t ); 301} 302 303static inline size_t htp_mm_hmx_get_2d_overhead (bool pipeline ,bool is_matmul_id ) { 304size_t num_regions = pipeline ?7 : (is_matmul_id ?4 :5 ); 305return num_regions * HTP_MM_HMX_TILE_SIZE + 256 ; 306} 307 308static inline size_t htp_mm_hmx_get_batched_overhead (void ) { 309return 5 * HTP_MM_HMX_TILE_SIZE + 256 ; 310} 311 312struct htp_mm_hmx_vtcm_layout { 313// Byte offsets from vtcm_base for each region 314size_t off_weight [2 ];// [1] is only used when pipelined 315size_t off_act ; 316size_t off_act_f32 ;// fp32 activation conversion scratch 317size_t off_dst [2 ];// [1] is only used when pipelined 318size_t off_scratch [2 ];// dequantization scratch pads 319size_t off_scales ;// HMX scales (256 bytes) 320 321// Cached sizes of regions for HMX kernel use 322size_t weight_area_bytes ; 323size_t act_area_bytes ; 324size_t act_f32_bytes ; 325size_t output_area_bytes ; 326size_t scratch_bytes [2 ]; 327size_t act_head_stride ; 328 329size_t total_bytes ; 330}; 331 332struct htp_mm_hvx_vtcm_layout { 333// Byte offsets from vtcm_base for each region 334size_t off_src1 ;// vtcm_src1 (activation) 335size_t off_src0 ;// vtcm_src0 (weight/Wk) 336size_t off_src2 ;// vtcm_src2 (Wq / fused only) 337size_t off_src3 ;// vtcm_src3 (Wv / fused only) 338size_t off_dst ;// vtcm_dst (output scratch) 339 340// Cached sizes 341size_t src0_bytes ; 342size_t src1_bytes ; 343size_t src2_bytes ; 344size_t src3_bytes ; 345size_t dst_bytes ; 346 347size_t total_bytes ; 348}; 349 350static inline void htp_mm_hmx_vtcm_layout_build ( 351struct htp_mm_hmx_vtcm_layout * L , 352int kernel_type , 353int wtype , 354uint32_t k , 355size_t mc , 356size_t nc , 357uint32_t group_size , 358bool use_dma_activation , 359bool pipeline , 360uint32_t act_threads , 361uint32_t aligned_tile_size 362) { 363size_t off = 0 ; 364 365if (kernel_type == HTP_MM_KERNEL_HMX_F16_BATCHED ) { 366const size_t vec_dot_size = k * sizeof (uint16_t ); 367const size_t act_head_stride = mc * k ; 368const size_t weight_area_size = hex_align_up (nc * vec_dot_size ,HTP_MM_HMX_TILE_SIZE ); 369const size_t activation_area_size = hex_align_up (group_size * act_head_stride * sizeof (uint16_t ),HTP_MM_HMX_TILE_SIZE ); 370const size_t output_area_size = hex_align_up (group_size * mc * nc * sizeof (uint16_t ),HTP_MM_HMX_TILE_SIZE ); 371const size_t scratch_area_size = hex_align_up (nc * vec_dot_size ,HTP_MM_HMX_TILE_SIZE ); 372const size_t min_f32_size = use_dma_activation 373 ?hex_align_up (act_threads * HTP_MM_DMA_ACT_MULTIPLIER * k * sizeof (float ),128 ) :0 ; 374 375// Group A: Permanent activation tiles and scales 376size_t off_group_a = 0 ; 377VTCM_LAYOUT_ALLOC (off_group_a ,off_act ,activation_area_size ); 378VTCM_LAYOUT_ALLOC (off_group_a ,off_scales ,HTP_MM_HMX_TILE_SIZE );// Padded to 2K for alignment and future persistent data 379 380// Group B: Compute-only buffers (starts at off_group_a) 381size_t off_group_b = off_group_a ; 382VTCM_LAYOUT_ALLOC (off_group_b ,off_weight [0 ],weight_area_size ); 383VTCM_LAYOUT_ALLOC_OPTIONAL (off_group_b ,off_weight [1 ],weight_area_size , false); 384VTCM_LAYOUT_ALLOC (off_group_b ,off_dst [0 ],output_area_size ); 385VTCM_LAYOUT_ALLOC_OPTIONAL (off_group_b ,off_dst [1 ],output_area_size , false); 386VTCM_LAYOUT_ALLOC (off_group_b ,off_scratch [0 ],scratch_area_size ); 387VTCM_LAYOUT_ALLOC (off_group_b ,off_scratch [1 ],scratch_area_size ); 388 389const size_t group_b_size = off_group_b - off_group_a ; 390 391// Group C: Activation prep temporary buffer (overlaps Group B, starting at off_group_a) 392const size_t max_f32_size = act_threads * 64 * k * sizeof (float ); 393const size_t act_f32_size = use_dma_activation 394 ?hex_align_up (hex_smin (max_f32_size ,hex_smax (min_f32_size ,group_b_size )),128 ) :0 ; 395size_t off_group_c = off_group_a ; 396VTCM_LAYOUT_ALLOC_OPTIONAL (off_group_c ,off_act_f32 ,act_f32_size ,use_dma_activation ); 397 398const size_t group_c_size = off_group_c - off_group_a ; 399 400L -> weight_area_bytes = weight_area_size ; 401L -> act_area_bytes = activation_area_size ; 402L -> act_f32_bytes = act_f32_size ; 403L -> output_area_bytes = output_area_size ; 404L -> scratch_bytes [0 ]= scratch_area_size ; 405L -> scratch_bytes [1 ]= scratch_area_size ; 406L -> act_head_stride = act_head_stride ; 407 408off = off_group_a + hex_smax (group_b_size ,group_c_size ); 409 }else { 410// HTP_MM_KERNEL_HMX_2D 411const bool is_quant = (wtype != HTP_TYPE_F16 && wtype != HTP_TYPE_F32 ); 412const size_t row_stride = htp_mm_get_tiled_row_stride (wtype ,k ); 413const size_t vec_dot_size = k * sizeof (uint16_t ); 414const uint32_t n_k_tiles = k /HTP_MM_HMX_TILE_N_COLS ; 415 416const size_t min_f32_size = hex_align_up (act_threads * HTP_MM_DMA_ACT_MULTIPLIER * k * sizeof (float ),128 ); 417const size_t weight_area_size = is_quant 418 ?hex_align_up ((nc /32 )* n_k_tiles * aligned_tile_size ,HTP_MM_HMX_TILE_SIZE ) 419 :hex_align_up (nc * row_stride ,HTP_MM_HMX_TILE_SIZE ); 420const size_t act_area_size = hex_align_up (mc * vec_dot_size ,HTP_MM_HMX_TILE_SIZE ); 421const size_t output_area_size = hex_align_up (mc * nc * sizeof (__fp16 ),HTP_MM_HMX_TILE_SIZE ); 422 423const size_t scratch0_size = hex_align_up (nc * vec_dot_size ,HTP_MM_HMX_TILE_SIZE ); 424const size_t scratch1_size = pipeline ?scratch0_size :0 ; 425 426// Group A: Scales and activation tiles (must not overlap with Group B or C) 427size_t off_group_a = 0 ; 428VTCM_LAYOUT_ALLOC (off_group_a ,off_scales ,HTP_MM_HMX_TILE_SIZE );// Padded to 2K for alignment and future persistent data 429VTCM_LAYOUT_ALLOC (off_group_a ,off_act ,act_area_size ); 430 431// Group B: Compute-only buffers (starts at off_group_a) 432size_t off_group_b = off_group_a ; 433VTCM_LAYOUT_ALLOC (off_group_b ,off_weight [0 ],weight_area_size ); 434VTCM_LAYOUT_ALLOC_OPTIONAL (off_group_b ,off_weight [1 ],weight_area_size ,pipeline ); 435VTCM_LAYOUT_ALLOC (off_group_b ,off_dst [0 ],output_area_size ); 436VTCM_LAYOUT_ALLOC (off_group_b ,off_scratch [0 ],scratch0_size ); 437VTCM_LAYOUT_ALLOC_OPTIONAL (off_group_b ,off_scratch [1 ],scratch0_size ,pipeline ); 438VTCM_LAYOUT_ALLOC_OPTIONAL (off_group_b ,off_dst [1 ],output_area_size ,pipeline ); 439 440const size_t group_b_size = off_group_b - off_group_a ; 441 442// Group C: Activation prep temporary buffer (overlaps Group B, starting at off_group_a) 443const size_t max_f32_size = act_threads * 64 * k * sizeof (float ); 444const size_t act_f32_size = hex_align_up (hex_smin (max_f32_size ,hex_smax (min_f32_size ,group_b_size )),128 ); 445size_t off_group_c = off_group_a ; 446VTCM_LAYOUT_ALLOC (off_group_c ,off_act_f32 ,act_f32_size ); 447 448const size_t group_c_size = off_group_c - off_group_a ; 449 450L -> weight_area_bytes = weight_area_size ; 451L -> act_area_bytes = act_area_size ; 452L -> act_f32_bytes = act_f32_size ; 453L -> output_area_bytes = output_area_size ; 454L -> scratch_bytes [0 ]= scratch0_size ; 455L -> scratch_bytes [1 ]= scratch1_size ; 456L -> act_head_stride = 0 ; 457 458off = off_group_a + hex_smax (group_b_size ,group_c_size ); 459 } 460 461L -> total_bytes = off ; 462} 463 464static inline void htp_mm_hvx_vtcm_layout_build ( 465struct htp_mm_hvx_vtcm_layout * L , 466int kernel_type , 467int wtype , 468uint32_t ne10 ,// k 469uint32_t src1_nrows ,// m_total 470uint32_t n_threads , 471size_t dst_row_size , 472size_t src0_row_size , 473size_t src1_row_size , 474size_t src2_row_size , 475uint32_t n_prefetch , 476bool is_matmul_id , 477bool is_fused_nx 478) { 479size_t src0_sz = 0 ; 480size_t src1_sz = 0 ; 481size_t src2_sz = src2_row_size > 0 ?htp_mm_round_up (src2_row_size ,128 ) :0 ; 482size_t src3_sz = 0 ; 483size_t dst_sz = 0 ; 484 485const bool is_repack = (wtype == HTP_TYPE_Q4_0 || wtype == HTP_TYPE_Q4_1 || 486wtype == HTP_TYPE_Q8_0 || wtype == HTP_TYPE_IQ4_NL || 487wtype == HTP_TYPE_MXFP4 ); 488 489if (is_fused_nx ) { 490const size_t src0_row_size_padded = hex_round_up (src0_row_size ,128 ); 491const size_t quant_scratch_size = hex_round_up (ne10 * sizeof (float ),QK_Q8_0_TILED * sizeof (float ))* n_threads ; 492 493size_t weight_sz_per_thread = 0 ; 494 495if (is_repack ) { 496uint32_t aligned_tile_size = htp_mm_get_weight_aligned_tile_size (wtype ); 497uint32_t n_k_tiles = hex_round_up (ne10 ,32 ) /32 ; 498uint32_t tile_row_size = n_k_tiles * aligned_tile_size ; 499 500weight_sz_per_thread = hex_round_up (n_prefetch * tile_row_size ,128 ); 501 }else { 502weight_sz_per_thread = hex_round_up (n_prefetch * src0_row_size_padded ,128 ); 503 } 504 505size_t flat_act_row_size = (wtype == HTP_TYPE_Q4_1 ) ?htp_mm_q8_1_flat_row_size (ne10 ) :htp_mm_q8_0_flat_row_size (ne10 ); 506size_t tiled_act_row_size = (wtype == HTP_TYPE_Q4_1 ) ?htp_mm_q8_1_tiled_row_size (ne10 ) :htp_mm_q8_0_tiled_row_size (ne10 ); 507 508size_t act_sz = (kernel_type == HTP_MM_KERNEL_HVX_QUANT_ROW_FLAT ) 509 ?hex_round_up (flat_act_row_size * src1_nrows ,128 ) 510 :hex_round_up (tiled_act_row_size * src1_nrows ,128 ); 511 512src0_sz = weight_sz_per_thread * n_threads ;// shared single-weight prefetch buffer 513src1_sz = act_sz ;// quantized activation buffer 514src2_sz = 0 ; 515src3_sz = 0 ; 516dst_sz = quant_scratch_size ; 517 }else if (is_matmul_id ) { 518const size_t src0_row_size_padded = htp_mm_round_up (src0_row_size ,128 ); 519const size_t src1_row_size_tiled = (wtype == HTP_TYPE_Q4_1 ) ?htp_mm_q8_1_tiled_row_size (ne10 ) 520 :htp_mm_q8_0_tiled_row_size (ne10 ); 521 522size_t src0_sz_per_thread = htp_mm_round_up (n_prefetch * src0_row_size_padded ,256 ); 523src1_sz = htp_mm_round_up (src1_row_size_tiled * src1_nrows ,256 ); 524 525if (is_repack ) { 526const uint32_t aligned_tile_size = htp_mm_get_weight_aligned_tile_size (wtype ); 527const uint32_t n_k_tiles = ne10 /32 ; 528const uint32_t tile_row_size = n_k_tiles * aligned_tile_size ; 529size_t repacked_vtcm_size = htp_mm_round_up (n_prefetch * tile_row_size ,256 ); 530src0_sz_per_thread = repacked_vtcm_size ; 531 } 532 533src0_sz = src0_sz_per_thread * n_threads ; 534dst_sz = htp_mm_round_up (ne10 * sizeof (float ),QK_Q8_0_TILED * sizeof (float ))* n_threads ; 535 }else { 536const size_t src0_row_size_padded = htp_mm_round_up (src0_row_size ,128 ); 537const size_t dst_nrows = (src1_nrows > 1 ) ?0 :1 ; 538 539switch (kernel_type ) { 540case HTP_MM_KERNEL_HVX_F16_F16_VTCM : { 541size_t f16_src1_row_size = htp_mm_round_up (ne10 * 2 ,128 ); 542src1_sz = htp_mm_round_up (f16_src1_row_size * src1_nrows ,256 ); 543src0_sz = htp_mm_round_up (n_prefetch * src0_row_size_padded ,256 )* n_threads ; 544dst_sz = dst_nrows > 0 ?htp_mm_round_up (dst_row_size ,128 )* n_threads :0 ; 545break ; 546 } 547case HTP_MM_KERNEL_HVX_F16_F32_DDR : 548case HTP_MM_KERNEL_HVX_F16_F16_DDR : 549case HTP_MM_KERNEL_HVX_F32_F32_DDR : 550case HTP_MM_KERNEL_HVX_F32_F16_DDR : { 551src0_sz = htp_mm_round_up (n_prefetch * src0_row_size ,256 )* n_threads ; 552src1_sz = htp_mm_round_up (n_prefetch * src1_row_size ,256 )* n_threads ; 553dst_sz = dst_nrows > 0 ?htp_mm_round_up (dst_row_size ,128 )* n_threads :0 ; 554break ; 555 } 556case HTP_MM_KERNEL_HVX_F32_F32_VTCM : { 557size_t f32_src1_row_size = htp_mm_round_up (ne10 * 4 ,128 ); 558src1_sz = htp_mm_round_up (f32_src1_row_size * src1_nrows ,256 ); 559src0_sz = htp_mm_round_up (n_prefetch * src0_row_size_padded ,256 )* n_threads ; 560dst_sz = dst_nrows > 0 ?htp_mm_round_up (dst_row_size ,128 )* n_threads :0 ; 561break ; 562 } 563case HTP_MM_KERNEL_HVX_QUANT_BLOCK : 564case HTP_MM_KERNEL_HVX_QUANT_ROW : { 565size_t q_src1_row_size = (wtype == HTP_TYPE_Q4_1 ) ?htp_mm_q8_1_tiled_row_size (ne10 ) :htp_mm_q8_0_tiled_row_size (ne10 ); 566 567src0_sz = htp_mm_round_up (n_prefetch * src0_row_size_padded ,256 ); 568src1_sz = htp_mm_round_up (q_src1_row_size * src1_nrows ,256 ); 569 570src0_sz = src0_sz * n_threads ; 571 572if (is_repack ) { 573uint32_t aligned_tile_size = htp_mm_get_weight_aligned_tile_size (wtype ); 574uint32_t n_k_tiles = ne10 /32 ; 575uint32_t tile_row_size = n_k_tiles * aligned_tile_size ; 576size_t repacked_vtcm_size = htp_mm_round_up (n_prefetch * tile_row_size ,256 ); 577src0_sz = repacked_vtcm_size * n_threads ; 578 } 579 580size_t quant_scratch_size_per_thread = htp_mm_round_up (ne10 * sizeof (float ),QK_Q8_0_TILED * sizeof (float )); 581size_t dst_slice_per_thread = (dst_nrows > 0 && src1_nrows == 1 ) ?htp_mm_round_up ((dst_row_size + n_threads - 1 ) /n_threads ,128 ) :0 ; 582size_t dst_size_per_thread = (dst_slice_per_thread > quant_scratch_size_per_thread ) ?dst_slice_per_thread :quant_scratch_size_per_thread ; 583dst_sz = dst_size_per_thread * n_threads ; 584break ; 585 } 586case HTP_MM_KERNEL_HVX_QUANT_ROW_FLAT : { 587size_t q_src1_row_size = (wtype == HTP_TYPE_Q4_1 ) ?htp_mm_q8_1_flat_row_size (ne10 ) :htp_mm_q8_0_flat_row_size (ne10 ); 588 589src0_sz = htp_mm_round_up (n_prefetch * src0_row_size_padded ,256 ); 590src1_sz = htp_mm_round_up (q_src1_row_size * src1_nrows ,256 ); 591 592src0_sz = src0_sz * n_threads ; 593 594if (is_repack ) { 595uint32_t aligned_tile_size = htp_mm_get_weight_aligned_tile_size (wtype ); 596uint32_t n_k_tiles = ne10 /32 ; 597uint32_t tile_row_size = n_k_tiles * aligned_tile_size ; 598size_t repacked_vtcm_size = htp_mm_round_up (n_prefetch * tile_row_size ,256 ); 599src0_sz = repacked_vtcm_size * n_threads ; 600 } 601 602size_t quant_scratch_size_per_thread = htp_mm_round_up (ne10 * sizeof (float ),QK_Q8_0_TILED * sizeof (float )); 603size_t dst_slice_per_thread = dst_nrows > 0 ?htp_mm_round_up ((dst_row_size + n_threads - 1 ) /n_threads ,128 ) :0 ; 604size_t dst_size_per_thread = (dst_slice_per_thread > quant_scratch_size_per_thread ) ?dst_slice_per_thread :quant_scratch_size_per_thread ; 605dst_sz = dst_size_per_thread * n_threads ; 606break ; 607 } 608default : 609break ; 610 } 611 } 612 613size_t off = 0 ; 614VTCM_LAYOUT_ALLOC (off ,off_src0 ,src0_sz ); 615VTCM_LAYOUT_ALLOC (off ,off_src1 ,src1_sz ); 616VTCM_LAYOUT_ALLOC (off ,off_src2 ,src2_sz ); 617VTCM_LAYOUT_ALLOC (off ,off_src3 ,src3_sz ); 618VTCM_LAYOUT_ALLOC (off ,off_dst ,dst_sz ); 619 620L -> src0_bytes = src0_sz ; 621L -> src1_bytes = src1_sz ; 622L -> src2_bytes = src2_sz ; 623L -> src3_bytes = src3_sz ; 624L -> dst_bytes = dst_sz ; 625L -> total_bytes = off ; 626} 627 628static inline size_t htp_mm_hmx_get_2d_vtcm_size ( 629int wtype ,uint32_t k ,size_t mc ,size_t nc ,bool pipeline ,uint32_t act_threads ,uint32_t aligned_tile_size 630) { 631struct htp_mm_hmx_vtcm_layout L ; 632htp_mm_hmx_vtcm_layout_build (& L ,HTP_MM_KERNEL_HMX_2D ,wtype ,k ,mc ,nc ,1 , false,pipeline ,act_threads ,aligned_tile_size ); 633return L .total_bytes ; 634} 635 636static inline size_t htp_mm_hmx_get_batched_vtcm_size ( 637int wtype ,uint32_t k ,size_t mc ,size_t nc ,uint32_t group_size ,bool use_dma_activation ,bool pipeline ,uint32_t act_threads ) { 638 (void )pipeline ; 639struct htp_mm_hmx_vtcm_layout L ; 640htp_mm_hmx_vtcm_layout_build (& L ,HTP_MM_KERNEL_HMX_F16_BATCHED ,wtype ,k ,mc ,nc ,group_size ,use_dma_activation , false,act_threads ,0 ); 641return L .total_bytes ; 642} 643 644static inline bool htp_mm_hmx_solve_batched_params ( 645int wtype , 646uint32_t k , 647uint32_t ne01_padded , 648uint32_t ne11 , 649uint32_t group_size , 650bool use_dma_activation , 651int n_threads , 652bool pipeline , 653size_t vtcm_budget , 654size_t * m_chunk_out , 655size_t * n_chunk_out , 656int * act_threads_out , 657size_t * vtcm_size_out 658) { 659size_t best_mblocks = SIZE_MAX ; 660int best_act_threads = 0 ; 661size_t best_m_chunk = 0 ; 662size_t best_n_chunk = 0 ; 663size_t best_vtcm_size = 0 ; 664 665int act_threads = n_threads ; 666while (act_threads >=1 ) { 667size_t group_overhead = htp_mm_hmx_get_batched_overhead (); 668size_t group_size_per_n ,group_size_per_m ,group_size_per_mn ; 669htp_mm_hmx_get_batched_chunk_costs (k ,group_size ,& group_size_per_n ,& group_size_per_m ,& group_size_per_mn ); 670 671size_t m_chunk_candidate = 0 ; 672size_t n_chunk_candidate = 0 ; 673size_t vtcm_size_candidate = 0 ; 674 675if (htp_mm_hmx_compute_chunks (vtcm_budget ,group_overhead ,group_size_per_n ,group_size_per_m ,group_size_per_mn ,hex_align_up (ne11 ,32 ),ne01_padded , 676 (size_t )ne01_padded * HTP_MM_HMX_COST_W_DEQUANT , (size_t )ne11 * HTP_MM_HMX_COST_A_CONVERT , 677& m_chunk_candidate ,& n_chunk_candidate ,& vtcm_size_candidate )== 0 ) { 678size_t exact_size = htp_mm_hmx_get_batched_vtcm_size (wtype ,k ,m_chunk_candidate ,n_chunk_candidate ,group_size ,use_dma_activation ,pipeline ,act_threads ); 679if (exact_size <=vtcm_budget ) { 680size_t mblocks = ((size_t )ne11 + m_chunk_candidate - 1 ) /m_chunk_candidate ; 681if (mblocks < best_mblocks || (mblocks == best_mblocks && act_threads > best_act_threads )) { 682best_mblocks = mblocks ; 683best_act_threads = act_threads ; 684best_m_chunk = m_chunk_candidate ; 685best_n_chunk = n_chunk_candidate ; 686best_vtcm_size = exact_size ; 687 } 688 } 689 } 690if (act_threads == 1 ) { 691act_threads = 0 ; 692 }else { 693act_threads /=2 ; 694 } 695 } 696 697if (best_act_threads > 0 ) { 698* m_chunk_out = best_m_chunk ; 699* n_chunk_out = best_n_chunk ; 700* vtcm_size_out = best_vtcm_size ; 701* act_threads_out = best_act_threads ; 702return true; 703 } 704return false; 705} 706 707static inline bool htp_mm_hmx_solve_2d_params ( 708int wtype , 709uint32_t k , 710uint32_t m_id_rows , 711uint32_t ne01_padded , 712uint32_t ne11_padded , 713uint32_t m_for_cost , 714int n_threads , 715bool pipeline , 716bool is_matmul_id , 717uint32_t aligned_tile_size , 718size_t vtcm_budget , 719size_t * m_chunk_out , 720size_t * n_chunk_out , 721int * act_threads_out , 722size_t * vtcm_size_out 723) { 724size_t best_mblocks = SIZE_MAX ; 725int best_act_threads = 0 ; 726size_t best_m_chunk = 0 ; 727size_t best_n_chunk = 0 ; 728size_t best_vtcm_size = 0 ; 729 730const int m_for_chunks = is_matmul_id ?hex_align_up (m_id_rows ,32 ) :ne11_padded ; 731 732int act_threads = n_threads ; 733while (act_threads >=1 ) { 734size_t simple_2d_overhead = htp_mm_hmx_get_2d_overhead (pipeline ,is_matmul_id ); 735size_t simple_2d_size_per_n ,simple_2d_size_per_m ,simple_2d_size_per_mn ; 736htp_mm_hmx_get_2d_chunk_costs (wtype ,k ,pipeline ,aligned_tile_size ,& simple_2d_size_per_n ,& simple_2d_size_per_m ,& simple_2d_size_per_mn ); 737 738size_t m_chunk_candidate = 0 ; 739size_t n_chunk_candidate = 0 ; 740size_t vtcm_size_candidate = 0 ; 741 742if (htp_mm_hmx_compute_chunks (vtcm_budget ,simple_2d_overhead ,simple_2d_size_per_n ,simple_2d_size_per_m ,simple_2d_size_per_mn ,m_for_chunks ,ne01_padded , 743 (size_t )ne01_padded * HTP_MM_HMX_COST_W_DEQUANT , (size_t )m_for_cost * HTP_MM_HMX_COST_A_CONVERT , 744& m_chunk_candidate ,& n_chunk_candidate ,& vtcm_size_candidate )== 0 ) { 745size_t exact_size = htp_mm_hmx_get_2d_vtcm_size (wtype ,k ,m_chunk_candidate ,n_chunk_candidate ,pipeline ,is_matmul_id ?0 :act_threads ,aligned_tile_size ); 746if (exact_size <=vtcm_budget ) { 747size_t mblocks = ((size_t )m_for_cost + m_chunk_candidate - 1 ) /m_chunk_candidate ; 748if (mblocks < best_mblocks || (mblocks == best_mblocks && act_threads > best_act_threads )) { 749best_mblocks = mblocks ; 750best_act_threads = act_threads ; 751best_m_chunk = m_chunk_candidate ; 752best_n_chunk = n_chunk_candidate ; 753best_vtcm_size = exact_size ; 754 } 755 } 756 } 757if (act_threads == 1 ) { 758act_threads = 0 ; 759 }else { 760act_threads /=2 ; 761 } 762 } 763 764if (best_act_threads > 0 ) { 765* m_chunk_out = best_m_chunk ; 766* n_chunk_out = best_n_chunk ; 767* vtcm_size_out = best_vtcm_size ; 768* act_threads_out = best_act_threads ; 769return true; 770 } 771return false; 772} 773 774#ifdef __cplusplus 775} 776#endif 777 778#endif // HTP_MATMUL_OPS_H