← Back to C-Kernel-Engine Docs Doxygen Source Documentation
 
Loading...
Searching...
No Matches
ckernel_engine.h File Reference
#include <stddef.h>
#include <stdint.h>
#include "ckernel_audio.h"
#include "cpu_features.h"
#include "ckernel_quant.h"
#include "mega_fused_attention.h"

Go to the source code of this file.

Data Structures

struct  CKMathBackend
 

Enumerations

enum  ck_attention_prefill_schedule_t {
  CK_ATTN_PREFILL_SCHEDULE_KV_HEADS = 0 , CK_ATTN_PREFILL_SCHEDULE_QUERY_HEADS = 1 , CK_ATTN_PREFILL_SCHEDULE_QUERY_TILES = 2 , CK_ATTN_PREFILL_SCHEDULE_KV_GROUP_QUERY_TILES = 3 ,
  CK_ATTN_PREFILL_SCHEDULE_GQA_SHARED_KV_TILES = 4
}
 
enum  ck_attention_reduction_t {
  CK_ATTN_REDUCTION_FP32_ONLINE = 0 , CK_ATTN_REDUCTION_F16_ONLINE_FP32_MERGE = 1 , CK_ATTN_REDUCTION_F16_ONLINE_SINGLE_RANGE = 2 , CK_ATTN_REDUCTION_F16_FLASH_AUTO_QTILE64 = 3 ,
  CK_ATTN_REDUCTION_BF16_PYTORCH_SDPA = 4
}
 
enum  ck_attention_status_t { CK_ATTENTION_STATUS_OK = 0 , CK_ATTENTION_STATUS_INVALID_ARGUMENT = -1 , CK_ATTENTION_STATUS_UNSUPPORTED_CONTRACT = -2 , CK_ATTENTION_STATUS_INSUFFICIENT_WORKSPACE = -3 }
 

Functions

void adamw_clip_update_multi_f32 (float *const *grads, float *const *weights, float *const *m_states, float *const *v_states, const size_t *numels, int tensor_count, float lr, float beta1, float beta2, float eps, float weight_decay, float max_grad_norm, int step)
 
void adamw_update_f32 (const float *grad, float *weight, float *m, float *v, size_t numel, float lr, float beta1, float beta2, float eps, float weight_decay, int step)
 
void add_backward_bf16 (const uint16_t *d_y, uint16_t *d_a, uint16_t *d_b, size_t n)
 
void add_forward_2d_bf16 (const uint16_t *a, const uint16_t *b, uint16_t *y, int tokens, int dim, int aligned_dim)
 
void add_forward_bf16 (const uint16_t *a, const uint16_t *b, uint16_t *y, size_t n)
 
void add_forward_f32 (const float *a, const float *b, float *y, size_t n)
 
void add_inplace_bf16 (uint16_t *a, const uint16_t *b, size_t n)
 
void add_inplace_f32 (float *a, const float *b, size_t n)
 
void add_scaled_forward_bf16 (const uint16_t *a, const uint16_t *b, uint16_t *y, float alpha, size_t n)
 
void add_scaled_inplace_bf16 (uint16_t *a, const uint16_t *b, float alpha, size_t n)
 
void add_stream_inplace (float *a, const float *b, size_t n)
 
void add_stream_reorder_2d (float *main_inout, float *aux_scratch, int grid_h, int grid_w, int embed_dim, int merge_size)
 
int argmax_f32 (const float *scores, int n)
 Find index of maximum value.
 
void assistant_layer_scale_forward (float *hidden, const float *scale, int tokens, int embed_dim)
 
void attention_backward_causal_head_major (const float *d_output, const float *q, const float *k, const float *v, const float *attn_weights, float *d_q, float *d_k, float *d_v, float *d_scores, int num_heads, int num_tokens, int head_dim, int aligned_head_dim, int aligned_context_window)
 
void attention_backward_causal_head_major_gqa (const float *d_output, const float *q, const float *k, const float *v, const float *attn_weights, float *d_q, float *d_k, float *d_v, float *d_scores, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int aligned_context_window)
 
void attention_backward_causal_head_major_gqa_bf16 (const uint16_t *d_output, float *d_x, const uint16_t *q, const uint16_t *k, const uint16_t *v, const float *attn_weights, float *d_q, float *d_k, float *d_v, float *d_scores, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int aligned_context_window, float *scratch_d_output, float *scratch_q, float *scratch_k, float *scratch_v)
 
void attention_flash_decode (float *out, const float *q, const float *k, const float *v, int T_q, int T_k, int H, int D_h, float scale)
 Main flash attention function with SIMD dispatch.
 
void attention_forward_causal_head_major (const float *q, const float *k, const float *v, float *scores, float *output, int num_heads, int num_tokens, int head_dim, int aligned_head_dim, int aligned_context_window)
 
void attention_forward_causal_head_major_exact (const float *q, const float *k, const float *v, float *scores, float *output, int num_heads, int num_tokens, int head_dim, int aligned_head_dim, int aligned_context_window)
 
void attention_forward_causal_head_major_gqa (const float *q, const float *k, const float *v, float *scores, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int aligned_context_window)
 
void attention_forward_causal_head_major_gqa_bf16 (const uint16_t *q, const uint16_t *k, const uint16_t *v, float *scores, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int aligned_context_window, float *scratch_q, float *scratch_k, float *scratch_v)
 
void attention_forward_causal_head_major_gqa_exact (const float *q, const float *k, const float *v, float *scores, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int aligned_context_window)
 
void attention_forward_causal_head_major_gqa_flash (const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim)
 
void attention_forward_causal_head_major_gqa_flash_strided (const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int kv_stride_tokens)
 
void attention_forward_causal_head_major_gqa_flash_strided_f16kv (const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int kv_stride_tokens)
 
void attention_forward_causal_head_major_gqa_flash_strided_f16kv_workspace (const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int kv_stride_tokens, float *rounded_kv, size_t rounded_kv_bytes)
 
void attention_forward_causal_head_major_gqa_flash_strided_gemma4 (const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int kv_stride_tokens)
 
void attention_forward_causal_head_major_gqa_flash_strided_gemma4_token_output (const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int kv_stride_tokens)
 
void attention_forward_causal_head_major_gqa_flash_strided_sliding (const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int kv_stride_tokens, int sliding_window)
 
void attention_forward_causal_head_major_gqa_flash_strided_sliding_gemma4 (const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int kv_stride_tokens, int sliding_window)
 
void attention_forward_causal_head_major_gqa_flash_strided_sliding_gemma4_token_output (const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int kv_stride_tokens, int sliding_window)
 
void attention_forward_causal_head_major_gqa_flash_strided_token_output (const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int kv_stride_tokens)
 
void attention_forward_causal_head_major_gqa_llama_regular_strided_sliding_workspace (const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int kv_stride_tokens, int sliding_window, float *scores, size_t scores_bytes, float *value_columns, size_t value_columns_bytes, float *scaled_scores, size_t scaled_scores_bytes)
 
ck_attention_status_t attention_forward_causal_head_major_gqa_prefill_append_bf16cache_pytorch_contract (const float *q, const uint16_t *k_cache, const uint16_t *v_cache, float *output, int num_heads, int num_kv_heads, int q_tokens, int past_tokens, int cache_capacity, int head_dim, int aligned_head_dim, ck_attention_reduction_t reduction)
 
ck_attention_status_t attention_forward_causal_head_major_gqa_prefill_append_bf16cache_pytorch_contract_workspace (const float *q, const uint16_t *k_cache, const uint16_t *v_cache, float *output, int num_heads, int num_kv_heads, int q_tokens, int past_tokens, int cache_capacity, int head_dim, int aligned_head_dim, ck_attention_reduction_t reduction, float *token_workspace, size_t token_workspace_bytes)
 
ck_attention_status_t attention_forward_causal_head_major_gqa_prefill_append_f16cache_auto_workspace (const float *q, const uint16_t *k_cache, const uint16_t *v_cache, float *output, int num_heads, int num_kv_heads, int q_tokens, int past_tokens, int cache_capacity, int head_dim, int aligned_head_dim, ck_attention_reduction_t reduction, float *token_workspace, size_t token_workspace_bytes, void *gqa_workspace, size_t gqa_workspace_bytes, int route_num_heads, int route_num_kv_heads, int route_head_dim, int route_query_tokens, int route_min_kv_tokens, int route_workers, int route_query_tile_size, int route_concurrent_query_tiles)
 
ck_attention_status_t attention_forward_causal_head_major_gqa_prefill_append_f16cache_contract (const float *q, const uint16_t *k_cache, const uint16_t *v_cache, float *output, int num_heads, int num_kv_heads, int q_tokens, int past_tokens, int cache_capacity, int head_dim, int aligned_head_dim, ck_attention_reduction_t reduction)
 
ck_attention_status_t attention_forward_causal_head_major_gqa_prefill_append_f16cache_contract_workspace (const float *q, const uint16_t *k_cache, const uint16_t *v_cache, float *output, int num_heads, int num_kv_heads, int q_tokens, int past_tokens, int cache_capacity, int head_dim, int aligned_head_dim, ck_attention_reduction_t reduction, float *token_workspace, size_t token_workspace_bytes)
 
ck_attention_status_t attention_forward_causal_head_major_gqa_prefill_append_f16cache_gqa_reuse_config (const float *q, const uint16_t *k_cache, const uint16_t *v_cache, float *output, int num_heads, int num_kv_heads, int q_tokens, int past_tokens, int cache_capacity, int head_dim, int aligned_head_dim, int query_tile_size, int concurrent_query_tiles, void *workspace, size_t workspace_bytes)
 
size_t attention_forward_causal_head_major_gqa_prefill_append_f16cache_gqa_reuse_workspace_bytes (int num_heads, int num_kv_heads, int head_dim, int workers, int query_tile_size, int concurrent_query_tiles)
 
ck_attention_status_t attention_forward_causal_head_major_gqa_prefill_append_f16cache_qtile64_schedule (const float *q, const uint16_t *k_cache, const uint16_t *v_cache, float *output, int num_heads, int num_kv_heads, int q_tokens, int past_tokens, int cache_capacity, int head_dim, int aligned_head_dim, ck_attention_prefill_schedule_t schedule)
 
ck_attention_status_t attention_forward_causal_head_major_gqa_prefill_full_bf16cache_pytorch_contract (const float *q, const uint16_t *k_cache, const uint16_t *v_cache, float *output, int num_heads, int num_kv_heads, int q_tokens, int past_tokens, int cache_capacity, int head_dim, int aligned_head_dim, ck_attention_reduction_t reduction)
 
ck_attention_status_t attention_forward_causal_head_major_gqa_prefill_segmented_f16cache_contract_workspace (const float *q, const uint16_t *k_cache, const uint16_t *v_cache, float *output, int num_heads, int num_kv_heads, int q_tokens, int past_tokens, int cache_capacity, int head_dim, int aligned_head_dim, ck_attention_reduction_t reduction, float *token_workspace, size_t token_workspace_bytes, const int *segment_lengths, int num_segments)
 
void attention_forward_causal_head_major_shared_kv_gemma4 (const float *q, float *output, int num_heads, int num_tokens, int head_dim, int aligned_head_dim, int kv_stride_tokens)
 
void attention_forward_causal_head_major_shared_kv_sliding_gemma4 (const float *q, float *output, int num_heads, int num_tokens, int head_dim, int aligned_head_dim, int kv_stride_tokens, int sliding_window)
 
void attention_forward_chunk_head_major_gqa_flash_gemma4 (const float *q_chunk, const float *k_cache, const float *v_cache, float *out_chunk, int num_heads, int num_kv_heads, int q_tokens, int kv_tokens, int cache_capacity, int head_dim, int aligned_head_dim)
 
ck_attention_status_t attention_forward_decode_head_major_gqa_bf16cache_pytorch_contract (const float *q_token, const uint16_t *k_cache, const uint16_t *v_cache, float *out_token, int num_heads, int num_kv_heads, int kv_tokens, int cache_capacity, int head_dim, int aligned_head_dim, ck_attention_reduction_t reduction)
 
void attention_forward_decode_head_major_gqa_flash (const float *q_token, const float *k_cache, const float *v_cache, float *out_token, int num_heads, int num_kv_heads, int kv_tokens, int cache_capacity, int head_dim, int aligned_head_dim)
 
void attention_forward_decode_head_major_gqa_flash_f16cache (const float *q_token, const uint16_t *k_cache, const uint16_t *v_cache, float *out_token, int num_heads, int num_kv_heads, int kv_tokens, int cache_capacity, int head_dim, int aligned_head_dim)
 
ck_attention_status_t attention_forward_decode_head_major_gqa_flash_f16cache_contract (const float *q_token, const uint16_t *k_cache, const uint16_t *v_cache, float *out_token, int num_heads, int num_kv_heads, int kv_tokens, int cache_capacity, int head_dim, int aligned_head_dim, ck_attention_reduction_t reduction)
 
void attention_forward_decode_head_major_gqa_flash_f16cache_split (const float *q_token, const uint16_t *k_cache, const uint16_t *v_cache, float *out_token, int num_heads, int num_kv_heads, int kv_tokens, int cache_capacity, int head_dim, int aligned_head_dim, int split_chunks)
 
void attention_forward_decode_head_major_gqa_flash_f16kv (const float *q_token, const float *k_cache, const float *v_cache, float *out_token, int num_heads, int num_kv_heads, int kv_tokens, int cache_capacity, int head_dim, int aligned_head_dim)
 
void attention_forward_decode_head_major_gqa_flash_gemma4 (const float *q_token, const float *k_cache, const float *v_cache, float *out_token, int num_heads, int num_kv_heads, int kv_tokens, int cache_capacity, int head_dim, int aligned_head_dim)
 
void attention_forward_decode_head_major_gqa_flash_sliding (const float *q_token, const float *k_cache, const float *v_cache, float *out_token, int num_heads, int num_kv_heads, int kv_tokens, int cache_capacity, int head_dim, int aligned_head_dim, int sliding_window)
 
void attention_forward_decode_head_major_gqa_flash_sliding_gemma4 (const float *q_token, const float *k_cache, const float *v_cache, float *out_token, int num_heads, int num_kv_heads, int kv_tokens, int cache_capacity, int head_dim, int aligned_head_dim, int sliding_window)
 
void attention_forward_decode_head_major_gqa_llama_regular_sliding_workspace (const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int live_tokens, int kv_stride_tokens, int head_dim, int aligned_head_dim, int sliding_window, float *scores, size_t scores_bytes, float *value_columns, size_t value_columns_bytes, float *scaled_scores, size_t scaled_scores_bytes)
 
void attention_forward_decode_head_major_gqa_regular (const float *q_token, const float *k_cache, const float *v_cache, float *out_token, int num_heads, int num_kv_heads, int kv_tokens, int cache_capacity, int head_dim, int aligned_head_dim)
 WARNING: This is NOT true flash attention!
 
void attention_forward_decode_head_major_shared_kv_gemma4 (const float *q_token, const float *k_cache, const float *v_cache, float *out_token, int num_heads, int kv_tokens, int cache_capacity, int head_dim, int aligned_head_dim)
 
void attention_forward_decode_head_major_shared_kv_sliding_gemma4 (const float *q_token, const float *k_cache, const float *v_cache, float *out_token, int num_heads, int kv_tokens, int cache_capacity, int head_dim, int aligned_head_dim, int sliding_window)
 
void attention_forward_full_head_major_gqa_exact_strided (const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int kv_stride_tokens)
 
void attention_forward_full_head_major_gqa_flash (const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim)
 
void attention_forward_full_head_major_gqa_flash_strided (const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int kv_stride_tokens)
 
void attention_forward_full_head_major_gqa_flash_strided_bf16_storage (const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int kv_stride_tokens)
 
void attention_forward_full_head_major_gqa_flash_strided_gemma4 (const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int kv_stride_tokens)
 
void attention_forward_full_head_major_gqa_ggml_strided (const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int kv_stride_tokens)
 
void attention_forward_full_head_major_gqa_ggml_strided_workspace (const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int kv_stride_tokens, float *score_rows, size_t score_rows_bytes, float *v_columns, size_t v_columns_bytes, float *probability_row, size_t probability_row_bytes)
 
void attention_forward_full_head_major_gqa_pytorch_cpu_flash_bf16_storage (const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int kv_stride_tokens)
 
void attention_forward_full_head_major_gqa_pytorch_cpu_flash_bf16_storage_token_output (const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int kv_stride_tokens)
 
void attention_forward_full_head_major_gqa_sdpa_bf16_storage (const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int kv_stride_tokens)
 
void attention_forward_full_head_major_gqa_tiled336_f16kv_fp32_strided (const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int kv_stride_tokens)
 
void attention_forward_full_head_major_gqa_tiled64_f16kv_fp32_strided (const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int kv_stride_tokens)
 
void attention_forward_full_head_major_gqa_tiled_f16kv_fp32_strided (const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int kv_stride_tokens)
 
void attention_forward_mixed_visual_chunk_head_major_gqa_flash_strided_gemma4 (const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int kv_stride_tokens, int visual_start, int visual_tokens)
 
void attention_forward_mixed_visual_chunk_head_major_gqa_flash_strided_gemma4_token_output (const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int kv_stride_tokens, int visual_start, int visual_tokens)
 
int attention_forward_query_key_head_major_f32 (const float *query, const float *key, const float *value, float *output, float *score_scratch, int num_heads, int query_tokens, int key_tokens, int head_dim, float scale)
 
int attention_forward_query_key_head_major_f32_packed_k (const float *query, const float *key, const float *value, float *output, float *score_scratch, float *key_transpose_scratch, int num_heads, int query_tokens, int key_tokens, int head_dim, float scale)
 
int attention_forward_query_key_head_major_tiled_f16kv_fp32 (const float *query, const float *key, const float *value, float *output, int num_heads, int query_tokens, int key_tokens, int head_dim, float scale)
 
void attention_forward_sparse_token_major_gqa_bf16cache_pytorch_cpu_flash_contract (const float *query, const uint16_t *key_cache, const uint16_t *value_cache, const float *selected_indices, float *output, float *score_scratch, int rows, int query_heads, int kv_heads, int head_dim, int selection_width, int context_length, int position)
 
void attn_gate_sigmoid_mul_backward (const float *d_out, const float *x, const float *gate, float *d_x, float *d_gate, int rows, int num_heads, int state_dim)
 
void attn_gate_sigmoid_mul_forward (const float *x, const float *gate, float *out, int rows, int num_heads, int state_dim)
 
void attn_gate_sigmoid_mul_pytorch_bf16_storage (const float *x, const float *gate, float *out, int rows, int num_heads, int state_dim)
 
void attn_gate_softplus_mul_forward (const float *x, const float *gate, float *out, int rows, int num_heads, int state_dim)
 
void axpy_2d_f32 (float *Y, const float *X, float alpha, int num_tokens, int dim, int y_stride, int x_stride)
 Batched AXPY for 2D tensors: Y[t,:] += alpha * X[t,:].
 
void axpy_f32 (float *y, const float *x, float alpha, int n)
 In-place AXPY: y += alpha * x.
 
void axpy_zero_f32 (float *y, const float *x, float alpha, int n)
 Zero output then accumulate: y = 0; y += alpha * x.
 
void backward_causal_softmax_head_major (float *d_scores, const float *weights, int num_heads, int num_tokens, int aligned_context_window)
 
void backward_causal_softmax_head_major_bf16 (uint16_t *d_scores, const uint16_t *weights, int num_heads, int num_tokens, int aligned_context_window, float *scratch_d_scores, float *scratch_weights)
 
void causal_softmax_head_major (float *scores, int num_heads, int num_tokens, int aligned_context_window)
 
void causal_softmax_head_major_bf16 (uint16_t *scores, int num_heads, int num_tokens, int aligned_context_window, float *scratch)
 
void causal_softmax_head_major_exact (float *scores, int num_heads, int num_tokens, int aligned_context_window)
 
int ck_attention_bf16_pytorch_gqa_available (void)
 
void ck_attention_flash_decode_wrapper (const float *q_token, const float *k_cache, const float *v_cache, float *out_token, int num_heads, int num_kv_heads, int kv_tokens, int cache_capacity, int head_dim, int aligned_head_dim)
 Wrapper to call TRUE flash attention from orchestration layer.
 
float ck_attention_pytorch_sdpa_scale_f32 (int head_dim)
 
int ck_attention_sparse_bf16_pytorch_gqa_available (void)
 
int ck_flash_attn_choose_tile_k (int D_h)
 
int ck_flash_attn_fast_exp_kind (void)
 
int ck_gemm_bf16_amx_available (void)
 
int ck_gemm_bf16_fp32out_amx_raw (const uint16_t *A, const uint16_t *B, float *C, int M, int N, int K, int accumulate)
 
int ck_gemm_nt_f16_ggml_oracle (const float *A, const void *B, const float *bias, float *C, int M, int N, int K)
 
int ck_gemm_nt_f16_simd_lanes (void)
 
void ck_gemm_nt_head_major_q5_0 (const float *attn_out, const void *wo, const float *bias, float *output, int tokens, int embed_dim, int num_heads, int head_dim)
 Output projection from head-major attention (auto-dispatch)
 
void ck_gemm_nt_head_major_q8_0 (const float *attn_out, const void *wo, const float *bias, float *output, int tokens, int embed_dim, int num_heads, int head_dim)
 Output projection from head-major attention (Q8_0 weights)
 
int ck_get_num_threads (void)
 
int ck_get_physical_cores (void)
 
void ck_layout_head_to_token_f32 (const float *src, float *dst, int heads, int tokens, int head_dim)
 
void ck_layout_token_to_head_f32 (const float *src, float *dst, int tokens, int heads, int head_dim)
 
void * ck_memcpy_parallel_dispatch (void *dst, const void *src, size_t size)
 
int ck_multimodal_mrope_positions_2d (int32_t *positions, int total_tokens, int prefix_start, int position_base, int prefix_tokens, int grid_x, int grid_y, int text_pos)
 
int ck_multimodal_prefix_insert_f32 (const float *source_rows, int32_t *token_ids, float *decoder_rows, int row_count, int source_row_stride, int decoder_row_stride, int copy_dim, int start_row, int decoder_capacity)
 
const char * ck_q6_k_prepared_provider_name (void)
 
const char * ck_q6_k_q8_k_provider_name (void)
 
void ck_residual_add_backward (const float *d_out, float *d_a, float *d_b, int tokens, int aligned_embed_dim)
 
void ck_residual_add_token_major (const float *a, const float *b, float *out, int tokens, int aligned_embed_dim)
 
void ck_residual_add_token_major_bf16_storage (const float *a, const float *b, float *out, int tokens, int aligned_embed_dim)
 
void ck_residual_add_token_major_parallel_dispatch (const float *a, const float *b, float *out, int tokens, int aligned_embed_dim)
 
void ck_set_num_threads (int num_threads)
 
void ck_set_strict_parity (int enabled)
 
const float * ck_strict_consume_next_gemm_a (size_t elems)
 
int ck_strict_mtmd_clip_encode_planar_f32 (const float *planar, int channels, int height, int width, float *out, size_t out_elems)
 
int ck_strict_parity_enabled (void)
 
void ck_strict_store_next_gemm_a (const float *data, size_t elems)
 
CKMathBackend ckernel_backend_native (void)
 
void deepseek_csa_attention_backward_f32 (const float *d_out, const float *q, const float *k, const float *v, const int *indices, const float *attn, float *d_q, float *d_k, float *d_v, int query_tokens, int key_tokens, int heads, int dim, int top_k, float scale)
 
void deepseek_csa_attention_f32 (const float *q, const float *k, const float *v, const int *indices, float *out, float *attn, int query_tokens, int key_tokens, int heads, int dim, int top_k, float scale)
 
void deepseek_dsa_topk_softmax_backward_f32 (const int *indices, const float *weights, const float *d_weights, float *d_scores, int tokens, int heads, int key_count, int top_k)
 
void deepseek_dsa_topk_softmax_f32 (const float *scores, int *indices, float *weights, int tokens, int heads, int key_count, int top_k)
 
void deepseek_hybrid_attention_f32 (const float *q, const float *k, const float *v, const int *indices, float *out, float *attn, int query_tokens, int key_tokens, int heads, int dim, int top_k, float scale, int mode)
 
void deepseek_mhc_mix_backward_f32 (const float *d_out, const float *streams, const float *mix, float *d_streams, float *d_mix, int tokens, int n_streams, int dim)
 
void deepseek_mhc_mix_f32 (const float *streams, const float *mix, float *out, int tokens, int n_streams, int dim)
 
void deepseek_mla_attention_decode_f32 (const float *q, const float *k_cache, const float *v_cache, float *output, int num_heads, int num_kv_heads, int cache_len, int qk_head_dim, int v_head_dim, int max_seq_len, int cache_stride)
 
void deepseek_mla_attention_decode_f32_workspace (const float *q, const float *k_cache, const float *v_cache, float *output, int num_heads, int num_kv_heads, int cache_len, int qk_head_dim, int v_head_dim, int max_seq_len, int cache_stride, float scale, float *scores, size_t scores_bytes)
 
void deepseek_mla_attention_f32 (const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int qk_head_dim, int v_head_dim)
 
void deepseek_mla_attention_f32_parallel_dispatch (const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int qk_head_dim, int v_head_dim, float scale, float *scores, size_t scores_bytes)
 
void deepseek_mla_attention_f32_workspace (const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int qk_head_dim, int v_head_dim, float scale, float *scores, size_t scores_bytes)
 
void deepseek_mla_kv_cache_batch_store_f32 (float *k_cache, float *v_cache, const float *k, const float *v, int num_tokens, int num_kv_heads, int qk_head_dim, int v_head_dim, int max_seq_len, int cache_stride)
 
void deepseek_mla_kv_cache_store_f32 (float *k_cache, float *v_cache, const float *k, const float *v, int pos, int num_kv_heads, int qk_head_dim, int v_head_dim, int max_seq_len, int cache_stride)
 
void deepseek_mla_kv_decompress_bf16 (const float *compressed_kv, const uint16_t *kv_b_proj, float *k_nope, float *value, int tokens, int heads, int kv_lora_rank, int qk_nope_dim, int v_dim)
 
void deepseek_mla_kv_decompress_bf16_parallel_dispatch (const float *compressed_kv, const uint16_t *kv_b_proj, float *k_nope, float *value, int tokens, int heads, int kv_lora_rank, int qk_nope_dim, int v_dim)
 
void deepseek_mla_kv_decompress_bf16_token_range (const float *compressed_kv, const uint16_t *kv_b_proj, float *k_nope, float *value, int tokens, int heads, int kv_lora_rank, int qk_nope_dim, int v_dim, int token_begin, int token_end)
 
void deepseek_mla_kv_decompress_f32 (const float *compressed_kv, const float *kv_b_proj, float *k_nope, float *value, int tokens, int heads, int kv_lora_rank, int qk_nope_dim, int v_dim)
 
void deepseek_mla_partial_rope_concat_f32 (const float *q_nope, const float *q_pe, const float *k_nope, const float *k_pe, const float *cos, const float *sin, float *query, float *key, int tokens, int heads, int qk_nope_dim, int qk_rope_dim)
 
void deepseek_mla_partial_rope_concat_packed_bf16_storage (const float *q_packed, const float *k_nope, const float *kv_a_packed, const float *cos, const float *sin, float *query, float *key, int tokens, int heads, int kv_lora_rank, int qk_nope_dim, int qk_rope_dim)
 
void deepseek_mla_partial_rope_concat_packed_f32 (const float *q_packed, const float *k_nope, const float *kv_a_packed, const float *cos, const float *sin, float *query, float *key, int tokens, int heads, int kv_lora_rank, int qk_nope_dim, int qk_rope_dim)
 
void dequant_q4_0_row (const void *src, float *dst, size_t n_elements)
 Dequantize Q4_0 row (multiple blocks)
 
void dequant_q4_1_row (const void *src, float *dst, size_t n_elements)
 Dequantize Q4_1 row (multiple blocks)
 
void dequant_q4_k_row (const void *src, float *dst, size_t n_elements)
 Dequantize Q4_K row (multiple blocks)
 
void dequant_q5_0_row (const void *src, float *dst, size_t n_elements)
 Dequantize Q5_0 row (multiple blocks)
 
void dequant_q5_1_row (const void *src, float *dst, size_t n_elements)
 Dequantize Q5_1 row (multiple blocks)
 
void dequant_q6_k_row (const void *src, float *dst, size_t n_elements)
 Dequantize Q6_K row (multiple blocks)
 
void dequant_q8_0_row (const void *src, float *dst, size_t n_elements)
 Dequantize Q8_0 row (multiple blocks)
 
void embedding_backward (const int32_t *token_ids, int token_count, const float *d_output, float *d_token_embeddings, float *d_pos_embeddings, int vocab_size, int embed_dim, int aligned_embed_dim, int context_window, int add_pos)
 
void embedding_backward_bf16 (const int32_t *token_ids, int token_count, const uint16_t *d_output, uint16_t *d_token_embeddings, uint16_t *d_pos_embeddings, int vocab_size, int embed_dim, int aligned_embed_dim, int context_window, int add_pos)
 
void embedding_backward_bf16_mixed (const int32_t *token_ids, int token_count, const uint16_t *d_output, float *d_token_embeddings, float *d_pos_embeddings, int vocab_size, int embed_dim, int aligned_embed_dim, int context_window, int add_pos)
 
void embedding_forward (const int32_t *token_ids, int token_count, int vocab_size, const float *token_embeddings, const float *pos_embeddings, float *output, int embed_dim, int aligned_embed_dim, int context_window, int add_pos)
 
void embedding_forward_bf16 (const int32_t *token_ids, int token_count, int vocab_size, const uint16_t *token_embeddings, const uint16_t *pos_embeddings, uint16_t *output, int embed_dim, int aligned_embed_dim, int context_window, int add_pos)
 
void embedding_forward_bf16_fp32 (const int32_t *token_ids, int token_count, int vocab_size, const uint16_t *token_embeddings, const float *pos_embeddings, float *output, int embed_dim, int aligned_embed_dim, int context_window, int add_pos)
 
void embedding_forward_q4_k (const int32_t *token_ids, int token_count, int vocab_size, const void *token_embeddings, const float *pos_embeddings, float *output, int embed_dim, int aligned_embed_dim, int context_window, int add_pos)
 
void embedding_forward_q5_0 (const int32_t *token_ids, int token_count, int vocab_size, const void *token_embeddings, const float *pos_embeddings, float *output, int embed_dim, int aligned_embed_dim, int context_window, int add_pos)
 
void embedding_forward_q6_k (const int32_t *token_ids, int token_count, int vocab_size, const void *token_embeddings, const float *pos_embeddings, float *output, int embed_dim, int aligned_embed_dim, int context_window, int add_pos)
 
void embedding_forward_q8_0 (const int32_t *token_ids, int token_count, int vocab_size, const void *token_embeddings, const float *pos_embeddings, float *output, int embed_dim, int aligned_embed_dim, int context_window, int add_pos)
 
void farskip_swiglu_shared_combine_bf16 (const float *hidden, const float *routed, const float *post_attn_residual, const uint16_t *shared_gate, const uint16_t *shared_up, const uint16_t *shared_down, float *main_output, float *routed_free_output, int rows, int hidden_dim, int intermediate_dim)
 
void farskip_swiglu_shared_combine_bf16_parallel_dispatch (const float *hidden, const float *routed, const float *post_attn_residual, const uint16_t *shared_gate, const uint16_t *shared_up, const uint16_t *shared_down, float *main_output, float *routed_free_output, int rows, int hidden_dim, int intermediate_dim)
 
void farskip_swiglu_shared_combine_bf16_row_range (const float *hidden, const float *routed, const float *post_attn_residual, const uint16_t *shared_gate, const uint16_t *shared_up, const uint16_t *shared_down, float *main_output, float *routed_free_output, int rows, int hidden_dim, int intermediate_dim, int row_begin, int row_end)
 
void fc1_backward_kernel (const float *d_output, const float *fc1_input, const float *W_fc1, float *d_input, float *d_W_fc1, float *d_b_fc1, int T, int aligned_in, int aligned_out, int num_threads)
 
void fc2_backward_kernel (const float *d_output, const float *fc2_input, const float *W_fc2, float *d_input, float *d_W_fc2, float *d_b_fc2, int T, int aligned_in, int aligned_out, int num_threads)
 
void feature_concat (const float *main_input, const float *branch_input, float *output, int rows, int main_dim, int branch_slice_dim, int num_branch_slices)
 
void feature_concat_2way (const float *main_input, const float *branch_input, float *output, int rows, int main_dim, int branch_slice_dim, int num_branch_slices)
 
void feature_slice_copy (const float *src, float *dst, int rows, int src_dim, int dst_dim, int dst_feature_offset)
 
void final_logit_scale_f32 (float *logits, int tokens, int vocab_size, float scale)
 
void fused_mlp_swiglu_decode (const float *x, const float *W_gate, const float *W_up, const float *W_down, const float *b_gate, const float *b_up, const float *b_down, float *output, int D, int Hff)
 
void fused_mlp_swiglu_decode_tiled (const float *x, const float *W_gate, const float *W_up, const float *W_down, const float *b_gate, const float *b_up, const float *b_down, float *output, int D, int Hff)
 
void fused_mlp_swiglu_decode_v2 (const float *x, const float *W_gate, const float *W_up, const float *W_down, const float *b_gate, const float *b_up, const float *b_down, float *output, int D, int Hff)
 
void fused_mlp_swiglu_prefill (const float *x, const float *W_gate, const float *W_up, const float *W_down, float *output, int seq_len, int hidden, int intermediate, float *scratch)
 Fused MLP (Gate + Up + SwiGLU + Down) for prefill.
 
void fused_mlp_swiglu_prefill_bias (const float *x, const float *W_gate, const float *W_up, const float *W_down, const float *B_gate, const float *B_up, const float *B_down, float *output, int seq_len, int hidden, int intermediate, float *scratch)
 Fused MLP (Gate + Up + SwiGLU + Down) for prefill with biases.
 
void fused_mlp_swiglu_prefill_w1w2_quant (const float *x, const void *W1, const float *B1, CKDataType w1_dt, const void *W2, const float *B2, CKDataType w2_dt, float *output, int seq_len, int embed_dim, int aligned_embed_dim, int intermediate_dim, int aligned_intermediate_dim, void *scratch)
 Quantized fused MLP for prefill (W1=gate+up, W2=down)
 
size_t fused_mlp_swiglu_prefill_w1w2_quant_scratch_size (int aligned_embed_dim, int aligned_intermediate_dim)
 Get scratch buffer size for fused_mlp_swiglu_prefill_w1w2_quant.
 
size_t fused_mlp_swiglu_scratch_size (int intermediate)
 Get scratch buffer size for fused_mlp_swiglu_prefill.
 
void fused_rmsnorm_qkv_prefill (const float *x, const float *gamma, const float *Wq, const float *Wk, const float *Wv, float *Q, float *K, float *V, int seq_len, int hidden, int q_dim, int kv_dim, float eps, float *scratch)
 Fused RMSNorm + QKV projection for prefill.
 
void fused_rmsnorm_qkv_prefill_head_major (const float *x, const float *gamma, const float *Wq, const float *Bq, const float *Wk, const float *Bk, const float *Wv, const float *Bv, float *Q, float *K, float *V, int seq_len, int embed_dim, int aligned_embed_dim, int num_heads, int num_kv_heads, int head_dim, int aligned_head_dim, int kv_stride_tokens, float eps, float *scratch)
 Fused RMSNorm + QKV projection for prefill (head-major outputs)
 
void fused_rmsnorm_qkv_prefill_head_major_quant (const float *x, const float *gamma, const void *Wq, const float *Bq, CKDataType wq_dt, const void *Wk, const float *Bk, CKDataType wk_dt, const void *Wv, const float *Bv, CKDataType wv_dt, float *Q, float *K, float *V, int seq_len, int embed_dim, int aligned_embed_dim, int num_heads, int num_kv_heads, int head_dim, int aligned_head_dim, int kv_stride_tokens, float eps, void *scratch)
 Fused RMSNorm + QKV projection for prefill (head-major, Q8 activations)
 
size_t fused_rmsnorm_qkv_prefill_head_major_quant_scratch_size (int aligned_embed_dim)
 Get scratch buffer size for fused_rmsnorm_qkv_prefill_head_major_quant.
 
size_t fused_rmsnorm_qkv_scratch_size (int hidden)
 Get scratch buffer size for fused_rmsnorm_qkv_prefill.
 
void gated_deltanet_autoregressive_backward (const float *d_out, const float *d_state_out, const float *q, const float *k, const float *v, const float *g, const float *beta, const float *state_in, const float *state_out, float *d_q, float *d_k, float *d_v, float *d_g, float *d_beta, float *d_state_in, int num_heads, int state_dim, float norm_eps)
 
void gated_deltanet_autoregressive_forward (const float *q, const float *k, const float *v, const float *g, const float *beta, const float *state_in, float *state_out, float *out, int num_heads, int state_dim, float norm_eps)
 
void gated_deltanet_llama_avx2_forward (const float *q, const float *k, const float *v, const float *g, const float *beta, const float *state_in, float *state_out, float *out, int num_heads, int group_count, int state_dim, float norm_eps)
 
void gated_deltanet_llama_avx2_prefill_forward (const float *q, const float *k, const float *v, const float *g, const float *beta, const float *state_in, float *state_out, float *out, int rows, int num_heads, int group_count, int state_dim, float norm_eps)
 
void gated_deltanet_llama_chunk64_head_forward (const float *q, const float *k, const float *v, const float *g, const float *beta, const float *state_in, float *state_out, float *out, int rows, int num_heads, int group_count, int head, int state_dim)
 
void gated_deltanet_llama_chunk64_prefill_forward (const float *q, const float *k, const float *v, const float *g, const float *beta, const float *state_in, float *state_out, float *out, int rows, int num_heads, int group_count, int state_dim, float norm_eps)
 
void gated_deltanet_prefill_forward (const float *q, const float *k, const float *v, const float *g, const float *beta, const float *state_in, float *state_out, float *out, int rows, int num_heads, int state_dim, float norm_eps)
 
void gated_deltanet_pytorch_grouped_bf16_forward (const float *q, const float *k, const float *v, const float *g, const float *beta, const float *state_in, float *state_out, float *out, int num_heads, int group_count, int state_dim, float norm_eps)
 
void gated_deltanet_pytorch_grouped_bf16_prefill_forward (const float *q, const float *k, const float *v, const float *g, const float *beta, const float *state_in, float *state_out, float *out, int rows, int num_heads, int group_count, int state_dim, float norm_eps)
 
void geglu_backward_bf16_mixed (const uint16_t *x, const uint16_t *d_out, float *d_x, int tokens, int dim)
 
void geglu_backward_fp32 (const float *x, const float *d_out, float *d_x, int tokens, int dim)
 
void geglu_forward_bf16 (const uint16_t *x, uint16_t *out, int tokens, int dim, float *scratch)
 
void geglu_forward_exact (const float *x, float *out, int tokens, int dim)
 
void geglu_forward_fp32 (const float *x, float *out, int tokens, int dim)
 
void geglu_forward_ggml_native (const float *x, float *out, int tokens, int dim)
 
void gelu_backward_exact (const float *input, const float *d_output, float *d_input, size_t n)
 
void gelu_backward_exact_bf16 (const uint16_t *input, const uint16_t *d_output, uint16_t *d_input, size_t n, float *scratch_input, float *scratch_d_output, float *scratch_d_input)
 
void gelu_backward_fast (const float *input, const float *d_output, float *d_input, size_t n)
 
void gelu_backward_fast_bf16 (const uint16_t *input, const uint16_t *d_output, uint16_t *d_input, size_t n, float *scratch_input, float *scratch_d_output, float *scratch_d_input)
 
void gelu_backward_scalar (const float *input, const float *d_output, float *d_input, size_t n)
 
void gelu_erf_bf16_storage (float *data, size_t n)
 
void gelu_erf_fp64_f32_inplace (float *data, size_t n)
 
void gelu_exact_inplace (float *data, size_t n)
 
void gelu_fast_inplace (float *data, size_t n)
 
void gelu_fast_inplace_bf16 (uint16_t *data, size_t n, float *scratch)
 
void gelu_ggml_inplace (float *data, size_t n)
 
void gelu_ggml_native_inplace (float *data, size_t n)
 
void gelu_pytorch_erf_f32_inplace (float *data, size_t n)
 
void gelu_pytorch_erf_sleef_bf16_storage (float *data, size_t n)
 
void gelu_pytorch_tanh_bf16_storage (float *data, size_t n)
 
void gemm_avx512_parallel (const float *A, const float *B, const float *bias, float *C, int M, int N, int K)
 
void gemm_backward_bf16_mixed (const uint16_t *d_output, const uint16_t *input, const uint16_t *weight, float *d_input, float *d_weight, float *d_bias, int tokens, int in_dim, int out_dim)
 
void gemm_backward_f32_train_parallel_dispatch (const float *d_output, const float *input, const float *W, float *d_input, float *d_W, float *d_b, int T, int aligned_in, int aligned_out, int num_threads)
 
void gemm_backward_f32_train_parallel_dispatch_v2 (const float *d_output, const float *input, const float *W, float *d_input, float *d_W, float *d_b, int T, int aligned_in, int aligned_out, int num_threads)
 
void gemm_bias_gelu_fused (const float *A, const float *B, const float *bias, float *C, int M, int N, int K)
 
void gemm_bias_relu_fused (const float *A, const float *B, const float *bias, float *C, int M, int N, int K)
 
void gemm_bias_silu_fused (const float *A, const float *B, const float *bias, float *C, int M, int N, int K)
 
void gemm_blocked_serial (const float *A, const float *B, const float *bias, float *C, int M, int N, int K)
 
void gemm_blocked_serial_bf16 (const uint16_t *A, const uint16_t *B, const uint16_t *bias, uint16_t *C, int M, int N, int K)
 
void gemm_blocked_serial_train_parallel_dispatch (const float *A, const float *B, const float *bias, float *C, int M, int N, int K)
 
void gemm_fine_grained_parallel (const float *A, const float *B, const float *bias, float *C, int M, int N, int K)
 
void gemm_microkernel (const float *A, const float *B, float *C, int M, int N, int K, int B_transposed)
 
void gemm_microkernel_blocked (const float *A, const float *B, float *C, int M, int N, int K)
 
void gemm_microkernel_blocked_bt (const float *A, const float *B, float *C, int M, int N, int K)
 
void gemm_microkernel_packed (const float *A, const float *B, float *C, int M, int N, int K)
 
void gemm_naive_parallel (const float *A, const float *B, const float *bias, float *C, int M, int N, int K)
 
void gemm_nn_avx512 (const float *A, const float *B, const float *bias, float *C, int M, int N, int K)
 
void gemm_nn_blocked (const float *A, const float *B, const float *bias, float *C, int M, int N, int K)
 
void gemm_nn_parallel (const float *A, const float *B, const float *bias, float *C, int M, int N, int K)
 
void gemm_nn_simd (const float *A, const float *B, const float *bias, float *C, int M, int N, int K)
 
void gemm_nt_bf16 (const float *A, const void *B, const float *bias, float *C, int M, int N, int K)
 
void gemm_nt_bf16_amx_bf16_storage (const float *A, const void *B, const float *bias, float *C, int M, int N, int K)
 
void gemm_nt_bf16_amx_bf16_storage_workspace (const float *A, const void *B, const float *bias, float *C, int M, int N, int K, uint16_t *a_bf16, size_t a_bf16_bytes)
 
void gemm_nt_bf16_bf16_storage (const float *A, const void *B, const float *bias, float *C, int M, int N, int K)
 
void gemm_nt_bf16_bf16_storage_parallel_dispatch (const float *A, const void *B, const float *bias, float *C, int M, int N, int K)
 
void gemm_nt_bf16_bf16_storage_row_range (const float *A, const void *B, const float *bias, float *C, int M, int N, int K, int row_begin, int row_end)
 
void gemm_nt_bf16_native_bf16_storage (const float *A, const void *B, const float *bias, float *C, int M, int N, int K)
 
void gemm_nt_bf16_parallel_dispatch (const float *A, const void *B, const float *bias, float *C, int M, int N, int K)
 
void gemm_nt_bf16_prefill_shape_safe_bf16_storage (const float *A, const void *B, const float *bias, float *C, int M, int N, int K)
 
void gemm_nt_bf16_prefill_shape_safe_bf16_storage_workspace (const float *A, const void *B, const float *bias, float *C, int M, int N, int K, uint16_t *a_bf16, size_t a_bf16_bytes)
 
void gemm_nt_bf16_pytorch_onednn_3_12_brgemm_bf16_storage (const float *A, const void *B, const float *bias, float *C, int M, int N, int K)
 
void gemm_nt_bf16_pytorch_onednn_brgemm_bf16_storage (const float *A, const void *B, const float *bias, float *C, int M, int N, int K)
 
void gemm_nt_bf16_row_range (const float *A, const void *B, const float *bias, float *C, int M, int N, int K, int row_begin, int row_end)
 
void gemm_nt_f16 (const float *A, const void *B, const float *bias, float *C, int M, int N, int K)
 NT GEMM wrapper for FP16 weights with the engine's standard ABI.
 
void gemm_nt_f16_clipped (const float *A, const void *B, const float *bias, const float *input_min, const float *input_max, const float *output_min, const float *output_max, float *C, int M, int N, int K)
 
void gemm_nt_f32_llama_production (const float *A, const float *B, const float *bias, float *C, int M, int N, int K)
 
void gemm_nt_f32_llama_production_output_range (const float *A, const float *B, const float *bias, float *C, int M, int N, int K, int output_begin, int output_end)
 
void gemm_nt_fp32_exact_parallel_dispatch (const float *A, const float *B, const float *bias, float *C, int M, int N, int K)
 
void gemm_nt_q4_0 (const float *A, const void *B, const float *bias, float *C, int M, int N, int K)
 Matrix-matrix multiply: C[M,N] = A[M,K] @ B[N,K]^T + bias.
 
void gemm_nt_q4_1 (const float *A, const void *B, const float *bias, float *C, int M, int N, int K)
 GEMM with transposed Q4_1 weights: C = A @ B^T.
 
void gemm_nt_q4_k (const float *A, const void *B, const float *bias, float *C, int M, int N, int K)
 
void gemm_nt_q4_k_q8_k (const void *A_q8, const void *B, const float *bias, float *C, int M, int N, int K)
 
void gemm_nt_q5_0 (const float *A, const void *B, const float *bias, float *C, int M, int N, int K)
 
void gemm_nt_q5_1 (const float *A, const void *B, const float *bias, float *C, int M, int N, int K)
 GEMM with transposed Q5_1 weights: C = A @ B^T.
 
void gemm_nt_q5_1_q8_1 (const float *A, const void *B, const float *bias, float *C, int M, int N, int K)
 
void gemm_nt_q5_1_q8_1_ref (const void *A_q8, const void *B, const float *bias, float *C, int M, int N, int K)
 
void gemm_nt_q5_k (const float *A, const void *B, const float *bias, float *C, int M, int N, int K)
 
void gemm_nt_q5_k_q8_k (const void *A_q8, const void *B, const float *bias, float *C, int M, int N, int K)
 
void gemm_nt_q6_k (const float *A, const void *B, const float *bias, float *C, int M, int N, int K)
 
void gemm_nt_q6_k_q8_k (const void *A_q8, const void *B, const float *bias, float *C, int M, int N, int K)
 NT GEMM: C = A @ B^T where A is Q8_K and B is Q6_K.
 
void gemm_nt_q6_k_q8_k_m4_tile (const void *A_q8, const void *B, const float *bias, float *C, int M, int N, int K, int m0, int m1, int n0, int n1)
 
void gemm_nt_q6_k_q8_k_tile (const void *A_q8, const void *B, const float *bias, float *C, int M, int N, int K, int m0, int m1, int n0, int n1)
 Compute one C[m0:m1, n0:n1] tile for Q8_K activations x Q6_K weights.
 
void gemm_nt_q6_k_q8_k_tiled (const void *A_q8, const void *B, const float *bias, float *C, int M, int N, int K)
 Experimental single-thread tiled NT GEMM wrapper.
 
void gemm_nt_q8_0 (const float *A, const void *B, const float *bias, float *C, int M, int N, int K)
 
void gemm_nt_q8_0_q8_0 (const void *A_q8, const void *B, const float *bias, float *C, int M, int N, int K)
 gemm_nt_q8_0_q8_0 with optional bias (matches header signature)
 
void gemm_nt_q8_0_q8_0_contract (const float *A, const void *B, const float *bias, float *C, int M, int N, int K)
 
void gemm_nt_q8_0_q8_0_m2n4 (const void *A_q8, const void *B, const float *bias, float *C, int M, int N, int K)
 
void gemm_nt_q8_0_q8_0_m2n4_tile (const void *A_q8, const void *B, const float *bias, float *C, int M, int N, int K, int ldc)
 
void gemm_q4_k (float *Y, const void *W, const float *X, int M, int N, int K)
 Auto-dispatch GEMM based on available SIMD.
 
void gemm_q4_k_q8_k (float *Y, const void *W, const void *X_q8, int M, int N, int K)
 
void gemm_q6_k (float *Y, const void *W, const float *X, int M, int N, int K)
 
void gemm_q6_k_q8_k (float *Y, const void *W, const void *X_q8, int M, int N, int K)
 GEMM: Y = W @ X^T where W is Q6_K and X is Q8_K.
 
void gemm_swiglu_fused (const float *x, const float *W_gate, const float *W_up, const float *b_gate, const float *b_up, float *output, int M, int N, int K)
 
void gemm_tn_avx512 (const float *A, const float *B, const float *bias, float *C, int M, int N, int K)
 
void gemm_tn_blocked (const float *A, const float *B, const float *bias, float *C, int M, int N, int K)
 
void gemm_tn_parallel (const float *A, const float *B, const float *bias, float *C, int M, int N, int K)
 
void gemma4_final_logit_softcap_forward (float *logits, int tokens, int vocab_size, float cap)
 
void gemma4_per_layer_embed_forward (float *hidden, const float *per_layer_input, const float *inp_gate, const float *proj, const float *post_norm, const float *out_scale, int tokens, int layer, int num_layers, int embed_dim, int per_layer_dim, float eps)
 
void gemma4_per_layer_prepare_bf16_forward (float *per_layer_input, const float *hidden, const int32_t *token_ids, const uint16_t *per_layer_token_emb, const uint16_t *per_layer_model_proj, const float *per_layer_proj_norm, int tokens, int num_layers, int embed_dim, int per_layer_dim, int vocab_size, float eps)
 
void gemma4_per_layer_prepare_forward (float *per_layer_input, const float *hidden, const int32_t *token_ids, const void *per_layer_token_emb, const uint16_t *per_layer_model_proj, const float *per_layer_proj_norm, int tokens, int num_layers, int embed_dim, int per_layer_dim, int vocab_size, float eps)
 
void gemma4_v_norm_forward (const float *input, float *output, float *rstd_cache, int tokens, int num_kv_heads, int head_dim, float eps)
 
void gemma4_v_norm_forward_parallel_dispatch (const float *input, float *output, float *rstd_cache, int tokens, int num_kv_heads, int head_dim, float eps)
 
void gemma4_vision_projector_prep_forward (const float *input, float *output, int tokens, int dim, float scale, float eps)
 
void gemv_bf16 (float *y, const void *W, const float *x, int M, int K)
 
void gemv_bf16_bf16_storage (float *y, const void *W, const float *x, int M, int K)
 
void gemv_bf16_bf16_storage_parallel_dispatch (float *y, const void *W, const float *x, int M, int K)
 
void gemv_bf16_parallel_dispatch (float *y, const void *W, const float *x, int M, int K)
 
void gemv_fused_q5_0_bias_dispatch (float *y, const void *W, const float *x, const float *bias, int M, int K)
 
void gemv_fused_q8_0_bias_dispatch (float *y, const void *W, const float *x, const float *bias, int M, int K)
 
void gemv_q4_0 (float *y, const void *W, const float *x, int M, int K)
 Auto-dispatch GEMV.
 
void gemv_q4_k (float *y, const void *W, const float *x, int M, int K)
 Auto-dispatch GEMV based on available SIMD.
 
void gemv_q4_k_q8_k (float *y, const void *W, const void *x_q8, int M, int K)
 
void gemv_q4_k_q8_k_parallel (float *y, const void *W, const void *x_q8, int M, int K, int ith, int nth)
 
void gemv_q4_k_q8_k_parallel_simd (float *y, const void *W, const void *x_q8, int M, int K, int ith, int nth)
 
void gemv_q4_k_q8_k_ref (float *y, const void *W, const void *x_q8, int M, int K)
 
void gemv_q5_0 (float *y, const void *W, const float *x, int M, int K)
 Auto-dispatch GEMV for Q5_0 weights based on CPU features.
 
void gemv_q5_0_parallel (float *y, const void *W, const float *x, int M, int K, int ith, int nth)
 Parallel reference GEMV for Q5_0 × FP32.
 
void gemv_q5_0_parallel_simd (float *y, const void *W, const float *x, int M, int K, int ith, int nth)
 Parallel SIMD GEMV for Q5_0 × FP32 with prefetching.
 
void gemv_q5_0_q8_0 (float *y, const void *W, const void *x_q8, int M, int K)
 Matrix-vector multiply with Q5_0 weights and Q8_0 input.
 
void gemv_q5_1 (float *y, const void *W, const float *x, int M, int K)
 Auto-dispatch GEMV.
 
void gemv_q5_1_q8_1 (float *y, const void *W, const float *x, int M, int K)
 
void gemv_q5_1_q8_1_ref (float *y, const void *W, const void *x_q8, int M, int K)
 
void gemv_q5_k (float *y, const void *W, const float *x, int M, int K)
 
void gemv_q5_k_q8_k (float *y, const void *W, const void *x_q8, int M, int K)
 
void gemv_q6_k (float *y, const void *W, const float *x, int M, int K)
 
void gemv_q6_k_q8_k (float *y, const void *W, const void *x_q8, int M, int K)
 GEMV: y = W @ x where W is Q6_K and x is Q8_K.
 
void gemv_q6_k_q8_k_parallel (float *y, const void *W, const void *x_q8, int M, int K, int ith, int nth)
 Parallel reference GEMV for Q6_K × Q8_K.
 
void gemv_q6_k_q8_k_parallel_simd (float *y, const void *W, const void *x_q8, int M, int K, int ith, int nth)
 Parallel SIMD GEMV for Q6_K × Q8_K.
 
void gemv_q8_0 (float *y, const void *W, const float *x, int M, int K)
 Auto-dispatch GEMV for Q8_0 weights based on CPU features.
 
void gemv_q8_0_q8_0 (float *y, const void *W, const void *x_q8, int M, int K)
 Matrix-vector multiply with Q8_0 weights and Q8_0 input.
 
void gemv_q8_0_q8_0_contract (float *y, const void *W, const float *x, int M, int K)
 
void gemv_q8_0_q8_0_x4 (float *y, const void *W, const void *x_q8, int M, int K)
 
void gradient_accumulate_f32 (float *dst, const float *src, size_t numel)
 
void gradient_accumulate_multi_f32 (float *const *dsts, const float *const *srcs, const size_t *numels, int tensor_count)
 
float gradient_clip_norm_f32 (float *grad, size_t numel, float max_norm)
 Clip gradient norm (fp32)
 
float gradient_global_norm_multi_f32 (const float *const *grads, const size_t *numels, int tensor_count)
 
void gradient_scale_f32 (float *grad, size_t numel, float scale)
 
void group_limited_topk_router_sigmoid_f32 (const float *logits, const float *correction_bias, int *indices, float *weights, int rows, int n_experts, int top_k, int n_group, int topk_group, int norm_topk_prob, float routed_scaling_factor)
 
void hyper_connection_mix_bf16 (const float *hyper_input, const float *norm_weight, const uint16_t *mix_down_weight, const uint16_t *mix_up_weight, const uint16_t *inject_weight, float *mixed_output, float *injection_output, float *normalized_scratch, float *dynamic_scratch, float *mix_scratch, int rows, int streams, int hidden_dim, int dynamic_dim, float eps, int emit_injection)
 
void hyper_connection_mix_q4k_q5_0_q4k (const float *hyper_input, const float *norm_weight, const void *mix_down_weight, const void *mix_up_weight, const void *inject_weight, float *mixed_output, float *injection_output, float *normalized_scratch, float *dynamic_scratch, float *mix_scratch, int rows, int streams, int hidden_dim, int dynamic_dim, float eps, int emit_injection)
 
void hyper_connection_mix_q6k_q5_0_q4k (const float *hyper_input, const float *norm_weight, const void *mix_down_weight, const void *mix_up_weight, const void *inject_weight, float *mixed_output, float *injection_output, float *normalized_scratch, float *dynamic_scratch, float *mix_scratch, int rows, int streams, int hidden_dim, int dynamic_dim, float eps, int emit_injection)
 
void hyper_stream_expand_bf16 (const float *input, float *output, int rows, int streams, int hidden_dim)
 
void hyper_stream_expand_f32 (const float *input, float *output, int rows, int streams, int hidden_dim)
 
void hyper_stream_inject_bf16 (const float *hyper_input, const float *block_output, const float *injection_weight, float *output, int rows, int streams, int hidden_dim)
 
void hyper_stream_inject_f32 (const float *hyper_input, const float *block_output, const float *injection_weight, float *output, int rows, int streams, int hidden_dim)
 
void im2patch (const float *image, float *patches, int C, int H, int W, int P)
 
void im2patch_bf16 (const uint16_t *image, uint16_t *patches, int C, int H, int W, int P)
 
void kv_cache_repack_head_major_inplace (float *buf, int num_heads, int tokens, int cache_capacity, int aligned_head_dim)
 
void kv_cache_store (float *__restrict kv_cache_k, float *__restrict kv_cache_v, const float *__restrict k, const float *__restrict v, int layer, int pos, int num_kv_heads, int head_dim, int max_seq_len)
 
void kv_cache_store_batch_bf16 (uint16_t *__restrict kv_cache_k, uint16_t *__restrict kv_cache_v, const float *__restrict k, const float *__restrict v, int start_pos, int num_tokens, int num_kv_heads, int head_dim, int max_seq_len)
 
void kv_cache_store_batch_f16 (uint16_t *__restrict kv_cache_k, uint16_t *__restrict kv_cache_v, const float *__restrict k, const float *__restrict v, int start_pos, int num_tokens, int num_kv_heads, int head_dim, int max_seq_len)
 
void kv_cache_store_batch_f32 (float *__restrict kv_cache_k, float *__restrict kv_cache_v, const float *__restrict k, const float *__restrict v, int start_pos, int num_tokens, int num_kv_heads, int head_dim, int max_seq_len)
 
void kv_cache_store_bf16 (uint16_t *__restrict kv_cache_k, uint16_t *__restrict kv_cache_v, const float *__restrict k, const float *__restrict v, int layer, int pos, int num_kv_heads, int head_dim, int max_seq_len)
 
void kv_cache_store_f16 (uint16_t *__restrict kv_cache_k, uint16_t *__restrict kv_cache_v, const float *__restrict k, const float *__restrict v, int layer, int pos, int num_kv_heads, int head_dim, int max_seq_len)
 
void kv_cache_store_shared_q (float *__restrict kv_cache_k, float *__restrict kv_cache_v, const float *__restrict q, int layer, int pos, int num_heads, int head_dim, int max_seq_len)
 
void kv_cache_write_head_major (const float *__restrict k_token, const float *__restrict v_token, float *__restrict k_cache, float *__restrict v_cache, int num_kv_heads, int token_index, int cache_capacity, int head_dim, int aligned_head_dim)
 
void layernorm_backward_kernel (const float *d_output, const float *input, const float *gamma, const float *mean, const float *rstd, float *d_input, float *d_gamma, float *d_beta, int tokens, int d_model, int aligned_embed_dim)
 
void layernorm_backward_kernel_bf16 (const uint16_t *d_output, const uint16_t *input, const float *gamma, const float *mean, const float *rstd, uint16_t *d_input, float *d_gamma, float *d_beta, int tokens, int d_model, int aligned_embed_dim, float *scratch_d_output, float *scratch_input, float *scratch_d_input)
 
void layernorm_forward_rolled_slice (const float *__restrict input_slice_base, const float *__restrict gamma, const float *__restrict beta, float *__restrict output_slice_base, float *__restrict mean_cache_slice, float *__restrict rstd_cache_slice, int num_tokens_in_slice, int d_model, int aligned_embed_dim, float eps)
 
void layernorm_forward_rolled_slice_bf16 (const uint16_t *__restrict input_slice_base, const float *__restrict gamma, const float *__restrict beta, uint16_t *__restrict output_slice_base, float *__restrict mean_cache_slice, float *__restrict rstd_cache_slice, int num_tokens_in_slice, int d_model, int aligned_embed_dim, float eps, float *scratch_input, float *scratch_output)
 
void layernorm_forward_unrolled_slice (const float *__restrict input_slice_base, const float *__restrict gamma, const float *__restrict beta, float *__restrict output_slice_base, float *__restrict mean_cache_slice, float *__restrict rstd_cache_slice, int num_tokens_in_slice, int d_model, float eps)
 
void layernorm_forward_unrolled_slice_bf16 (const uint16_t *__restrict input_slice_base, const float *__restrict gamma, const float *__restrict beta, uint16_t *__restrict output_slice_base, float *__restrict mean_cache_slice, float *__restrict rstd_cache_slice, int num_tokens_in_slice, int d_model, float eps, float *scratch_input, float *scratch_output)
 
void layernorm_naive_serial (const float *input, const float *gamma, const float *beta, float *output, float *mean_cache, float *rstd_cache, int tokens, int d_model, int aligned_embed_dim, float eps)
 
void layernorm_naive_serial_bf16_storage (const float *input, const float *gamma, const float *beta, float *output, float *mean_cache, float *rstd_cache, int tokens, int d_model, float eps)
 
void layernorm_naive_serial_matched_precision (const float *input, const float *gamma, const float *beta, float *output, float *mean_cache, float *rstd_cache, int tokens, int d_model, float eps)
 
void layernorm_pytorch_welford_bf16_storage (const float *input, const float *gamma, const float *beta, float *output, float *mean_cache, float *rstd_cache, int tokens, int d_model, float eps)
 
void mamba2_conv1d_decode_f32 (const float *state_in, const float *x, const float *weight, const float *bias, float *conv_out, float *state_out, int rows, int conv_dim, int kernel_size)
 
void mamba2_conv1d_f32_channel_range (const float *state_in, const float *x, const float *weight, const float *bias, float *conv_out, float *state_out, int rows, int conv_dim, int kernel_size, int channel_begin, int channel_end)
 
void mamba2_conv1d_f32_parallel_dispatch (const float *state_in, const float *x, const float *weight, const float *bias, float *conv_out, float *state_out, int rows, int conv_dim, int kernel_size)
 
void mamba2_dt_softplus_f32 (const float *dt, const float *dt_bias, float *dt_out, int rows, int num_heads, float dt_min, float dt_max)
 
void mamba2_in_proj_split_f32 (const float *projected, float *gate, float *hidden_bc, float *dt, int rows, int d_mlp, int intermediate_dim, int conv_dim, int num_heads)
 
void mamba2_rmsnorm_gate_f32 (const float *x, const float *gate, const float *weight, float *out, int rows, int inner_dim, int group_size, float eps)
 
void mamba2_selective_scan_f32 (const float *state_init, const float *x, const float *dt, const float *a, const float *b, const float *c, const float *d, float *state_out, float *y, int batch, int seq_len, int num_heads, int head_dim, int state_dim, int num_groups)
 
void mamba2_selective_scan_f32_head_range (const float *state_init, const float *x, const float *dt, const float *a, const float *b, const float *c, const float *d, float *state_out, float *y, int batch, int seq_len, int num_heads, int head_dim, int state_dim, int num_groups, int head_begin, int head_end)
 
void mamba2_selective_scan_f32_parallel_dispatch (const float *state_init, const float *x, const float *dt, const float *a, const float *b, const float *c, const float *d, float *state_out, float *y, int batch, int seq_len, int num_heads, int head_dim, int state_dim, int num_groups)
 
void mamba2_selective_state_update_decode_f32 (const float *state_in, const float *x, const float *dt, const float *a, const float *b, const float *c, const float *d, float *state_out, float *y, int rows, int num_heads, int head_dim, int state_dim, int num_groups)
 
void mlp_token_parallel (const float *input, const float *W_fc1, const float *b_fc1, const float *W_fc2, const float *b_fc2, float *fc1_output, float *output, int T, int aligned_dim, int num_threads)
 
void mlp_token_parallel_bf16 (const uint16_t *input, const uint16_t *W_fc1, const uint16_t *b_fc1, const uint16_t *W_fc2, const uint16_t *b_fc2, float *fc1_output, float *output, int T, int aligned_dim, int num_threads, float *scratch_bias1_f, float *scratch_bias2_f, uint16_t *scratch_fc1_bf16)
 
void mlp_token_parallel_bf16_backward_mixed (const uint16_t *input, const uint16_t *W_fc1, const uint16_t *b_fc1, const uint16_t *W_fc2, const uint16_t *d_output, float *d_input, float *d_W_fc1, float *d_b_fc1, float *d_W_fc2, float *d_b_fc2, int T, int aligned_dim, int num_threads, float *scratch_fc1_pre, uint16_t *scratch_fc1_act_bf16, float *scratch_d_fc1)
 
void mlp_token_parallel_bf16_fp32act (const uint16_t *input, const uint16_t *W_fc1, const uint16_t *b_fc1, const uint16_t *W_fc2, const uint16_t *b_fc2, float *fc1_output, float *output, int T, int aligned_dim, int num_threads, float *scratch_input_f, float *scratch_bias1_f, float *scratch_bias2_f, uint16_t *scratch_fc1_bf16)
 
void mlp_token_parallel_exact (const float *input, const float *W_fc1, const float *b_fc1, const float *W_fc2, const float *b_fc2, float *fc1_output, float *output, int T, int aligned_dim, int num_threads)
 
void moe_accumulate_expert_f32 (float *output, const float *expert_output, float routing_weight, int hidden_dim)
 Accumulate expert output: output += routing_weight * expert_output.
 
void moe_relu2_expert_backward_f32 (const float *d_output, const float *hidden, const int *indices, const float *routing_weights, const float *expert_up, const float *expert_down, float *d_hidden, float *d_routing_weights, float *d_expert_up, float *d_expert_down, int rows, int hidden_dim, int intermediate_dim, int n_experts, int top_k)
 
void moe_relu2_expert_forward_f32 (const float *hidden, const int *indices, const float *routing_weights, const float *expert_up, const float *expert_down, float *output, int rows, int hidden_dim, int intermediate_dim, int n_experts, int top_k)
 
void moe_relu2_expert_forward_q5_0_q5_0 (const float *hidden, const int *indices, const float *routing_weights, const void *expert_up, const void *expert_down, float *output, int rows, int hidden_dim, int intermediate_dim, int n_experts, int top_k)
 
void moe_relu2_expert_forward_q5_0_q8_0 (const float *hidden, const int *indices, const float *routing_weights, const void *expert_up, const void *expert_down, float *output, int rows, int hidden_dim, int intermediate_dim, int n_experts, int top_k)
 
void moe_relu2_shared_forward_q5_1_q8_0 (const float *hidden, const float *routed, const void *shared_up, const void *shared_down, float *output, int rows, int hidden_dim, int intermediate_dim)
 
int moe_softmax_topk_router_llama_f32_workspace (const float *logits, int *indices, float *weights, int rows, int n_experts, int top_k, float routed_scaling_factor, void *workspace, size_t workspace_bytes)
 
int moe_softmax_topk_router_pytorch_bf16_workspace (const float *logits, int *indices, float *weights, int rows, int n_experts, int top_k, float routed_scaling_factor, void *workspace, size_t workspace_bytes)
 
size_t moe_softmax_topk_router_workspace_bytes (int n_experts)
 
void moe_swiglu_expert_forward_bf16 (const float *hidden, const int *indices, const float *routing_weights, const uint16_t *expert_gate, const uint16_t *expert_up, const uint16_t *expert_down, float *output, int rows, int hidden_dim, int intermediate_dim, int n_experts, int top_k)
 
void moe_swiglu_expert_forward_bf16_parallel_dispatch (const float *hidden, const int *indices, const float *routing_weights, const uint16_t *expert_gate, const uint16_t *expert_up, const uint16_t *expert_down, float *output, int rows, int hidden_dim, int intermediate_dim, int n_experts, int top_k)
 
void moe_swiglu_expert_forward_bf16_row_range (const float *hidden, const int *indices, const float *routing_weights, const uint16_t *expert_gate, const uint16_t *expert_up, const uint16_t *expert_down, float *output, int rows, int hidden_dim, int intermediate_dim, int n_experts, int top_k, int row_begin, int row_end)
 
void moe_swiglu_expert_forward_f32 (const float *hidden, const int *indices, const float *routing_weights, const float *expert_gate, const float *expert_up, const float *expert_down, float *output, int rows, int hidden_dim, int intermediate_dim, int n_experts, int top_k)
 
int moe_swiglu_expert_forward_q4k_q4k_parallel_workspace (const float *hidden, const int *indices, const float *routing_weights, const void *expert_gate, const void *expert_up, const void *expert_down, float *output, int rows, int hidden_dim, int intermediate_dim, int n_experts, int top_k, void *workspace, size_t workspace_bytes)
 
int moe_swiglu_expert_forward_q4k_q4k_workspace (const float *hidden, const int *indices, const float *routing_weights, const void *expert_gate, const void *expert_up, const void *expert_down, float *output, int rows, int hidden_dim, int intermediate_dim, int n_experts, int top_k, void *workspace, size_t workspace_bytes)
 
int moe_swiglu_expert_forward_q4k_q5_0_parallel_workspace (const float *hidden, const int *indices, const float *routing_weights, const void *expert_gate, const void *expert_up, const void *expert_down, float *output, int rows, int hidden_dim, int intermediate_dim, int n_experts, int top_k, void *workspace, size_t workspace_bytes)
 
int moe_swiglu_expert_forward_q4k_q5_0_workspace (const float *hidden, const int *indices, const float *routing_weights, const void *expert_gate, const void *expert_up, const void *expert_down, float *output, int rows, int hidden_dim, int intermediate_dim, int n_experts, int top_k, void *workspace, size_t workspace_bytes)
 
int moe_swiglu_expert_forward_q4k_q5k_auto_prepared_workspace (const float *hidden, const int *indices, const float *routing_weights, const void *expert_gate, const void *expert_up, const void *expert_down, float *output, int rows, int hidden_dim, int intermediate_dim, int n_experts, int top_k, void *workspace, size_t workspace_bytes)
 
int moe_swiglu_expert_forward_q4k_q5k_auto_workspace (const float *hidden, const int *indices, const float *routing_weights, const void *expert_gate, const void *expert_up, const void *expert_down, float *output, int rows, int hidden_dim, int intermediate_dim, int n_experts, int top_k, void *workspace, size_t workspace_bytes)
 
int moe_swiglu_expert_forward_q4k_q5k_bucketed_prepared_workspace (const float *hidden, const int *indices, const float *routing_weights, const void *expert_gate, const void *expert_up, const void *expert_down, const void *expert_gate_packed, const void *expert_up_packed, float *output, int rows, int hidden_dim, int intermediate_dim, int n_experts, int top_k, void *workspace, size_t workspace_bytes)
 
int moe_swiglu_expert_forward_q4k_q5k_bucketed_workspace (const float *hidden, const int *indices, const float *routing_weights, const void *expert_gate, const void *expert_up, const void *expert_down, float *output, int rows, int hidden_dim, int intermediate_dim, int n_experts, int top_k, void *workspace, size_t workspace_bytes)
 
int moe_swiglu_expert_forward_q4k_q5k_parallel_workspace (const float *hidden, const int *indices, const float *routing_weights, const void *expert_gate, const void *expert_up, const void *expert_down, float *output, int rows, int hidden_dim, int intermediate_dim, int n_experts, int top_k, void *workspace, size_t workspace_bytes)
 
int moe_swiglu_expert_forward_q4k_q5k_workspace (const float *hidden, const int *indices, const float *routing_weights, const void *expert_gate, const void *expert_up, const void *expert_down, float *output, int rows, int hidden_dim, int intermediate_dim, int n_experts, int top_k, void *workspace, size_t workspace_bytes)
 
int moe_swiglu_expert_forward_q4k_q6k_parallel_workspace (const float *hidden, const int *indices, const float *routing_weights, const void *expert_gate, const void *expert_up, const void *expert_down, float *output, int rows, int hidden_dim, int intermediate_dim, int n_experts, int top_k, void *workspace, size_t workspace_bytes)
 
int moe_swiglu_expert_forward_q4k_q6k_workspace (const float *hidden, const int *indices, const float *routing_weights, const void *expert_gate, const void *expert_up, const void *expert_down, float *output, int rows, int hidden_dim, int intermediate_dim, int n_experts, int top_k, void *workspace, size_t workspace_bytes)
 
int moe_swiglu_expert_forward_q4k_q8_0_parallel_workspace (const float *hidden, const int *indices, const float *routing_weights, const void *expert_gate, const void *expert_up, const void *expert_down, float *output, int rows, int hidden_dim, int intermediate_dim, int n_experts, int top_k, void *workspace, size_t workspace_bytes)
 
int moe_swiglu_expert_forward_q4k_q8_0_workspace (const float *hidden, const int *indices, const float *routing_weights, const void *expert_gate, const void *expert_up, const void *expert_down, float *output, int rows, int hidden_dim, int intermediate_dim, int n_experts, int top_k, void *workspace, size_t workspace_bytes)
 
size_t moe_swiglu_expert_q4k_q5k_workspace_bytes (int hidden_dim, int intermediate_dim)
 
size_t moe_swiglu_expert_q4k_q8_0_workspace_bytes (int hidden_dim, int intermediate_dim)
 
void moe_swiglu_packed_expert_forward_bf16 (const float *hidden, const int *indices, const float *routing_weights, const uint16_t *expert_gate_up, const uint16_t *expert_down, float *output, int rows, int hidden_dim, int intermediate_dim, int n_experts, int top_k)
 
void moe_swiglu_shared_forward_bf16 (const float *hidden, const float *routed, const uint16_t *shared_gate, const uint16_t *shared_up, const uint16_t *shared_down, float *output, int rows, int hidden_dim, int intermediate_dim)
 
void moe_swiglu_shared_forward_bf16_gated (const float *hidden, const float *routed, const uint16_t *shared_gate, const uint16_t *shared_up, const uint16_t *shared_down, const uint16_t *shared_router, float *output, int rows, int hidden_dim, int intermediate_dim)
 
void moe_swiglu_shared_forward_bf16_gated_parallel_dispatch (const float *hidden, const float *routed, const uint16_t *shared_gate, const uint16_t *shared_up, const uint16_t *shared_down, const uint16_t *shared_router, float *output, int rows, int hidden_dim, int intermediate_dim)
 
void moe_swiglu_shared_forward_bf16_gated_row_range (const float *hidden, const float *routed, const uint16_t *shared_gate, const uint16_t *shared_up, const uint16_t *shared_down, const uint16_t *shared_router, float *output, int rows, int hidden_dim, int intermediate_dim, int row_begin, int row_end)
 
void moe_swiglu_shared_forward_bf16_parallel_dispatch (const float *hidden, const float *routed, const uint16_t *shared_gate, const uint16_t *shared_up, const uint16_t *shared_down, float *output, int rows, int hidden_dim, int intermediate_dim)
 
void moe_swiglu_shared_forward_bf16_row_range (const float *hidden, const float *routed, const uint16_t *shared_gate, const uint16_t *shared_up, const uint16_t *shared_down, float *output, int rows, int hidden_dim, int intermediate_dim, int row_begin, int row_end)
 
void moe_swiglu_shared_forward_f32 (const float *hidden, const float *routed, const float *shared_gate, const float *shared_up, const float *shared_down, float *output, int rows, int hidden_dim, int intermediate_dim)
 
int moe_swiglu_shared_forward_q4k_q4k_parallel_workspace (const float *hidden, const float *routed, const void *shared_gate, const void *shared_up, const void *shared_down, float *output, int rows, int hidden_dim, int intermediate_dim, void *workspace, size_t workspace_bytes)
 
int moe_swiglu_shared_forward_q4k_q4k_workspace (const float *hidden, const float *routed, const void *shared_gate, const void *shared_up, const void *shared_down, float *output, int rows, int hidden_dim, int intermediate_dim, void *workspace, size_t workspace_bytes)
 
int moe_swiglu_shared_forward_q4k_q5_0_gated_parallel_workspace (const float *hidden, const float *routed, const void *shared_gate, const void *shared_up, const void *shared_down, const float *shared_gate_input, float *output, int rows, int hidden_dim, int intermediate_dim, void *workspace, size_t workspace_bytes)
 
int moe_swiglu_shared_forward_q4k_q5_0_gated_workspace (const float *hidden, const float *routed, const void *shared_gate, const void *shared_up, const void *shared_down, const float *shared_gate_input, float *output, int rows, int hidden_dim, int intermediate_dim, void *workspace, size_t workspace_bytes)
 
int moe_swiglu_shared_forward_q4k_q6k_parallel_workspace (const float *hidden, const float *routed, const void *shared_gate, const void *shared_up, const void *shared_down, float *output, int rows, int hidden_dim, int intermediate_dim, void *workspace, size_t workspace_bytes)
 
int moe_swiglu_shared_forward_q4k_q6k_workspace (const float *hidden, const float *routed, const void *shared_gate, const void *shared_up, const void *shared_down, float *output, int rows, int hidden_dim, int intermediate_dim, void *workspace, size_t workspace_bytes)
 
int moe_swiglu_shared_forward_q4k_q8_0_gated_parallel_workspace (const float *hidden, const float *routed, const void *shared_gate, const void *shared_up, const void *shared_down, const float *shared_gate_input, float *output, int rows, int hidden_dim, int intermediate_dim, void *workspace, size_t workspace_bytes)
 
int moe_swiglu_shared_forward_q4k_q8_0_gated_workspace (const float *hidden, const float *routed, const void *shared_gate, const void *shared_up, const void *shared_down, const float *shared_gate_input, float *output, int rows, int hidden_dim, int intermediate_dim, void *workspace, size_t workspace_bytes)
 
int moe_swiglu_shared_forward_q8_0_gated_parallel_workspace (const float *hidden, const float *routed, const void *shared_gate, const void *shared_up, const void *shared_down, const float *shared_gate_input, float *output, int rows, int hidden_dim, int intermediate_dim, void *workspace, size_t workspace_bytes)
 
int moe_swiglu_shared_forward_q8_0_gated_workspace (const float *hidden, const float *routed, const void *shared_gate, const void *shared_up, const void *shared_down, const float *shared_gate_input, float *output, int rows, int hidden_dim, int intermediate_dim, void *workspace, size_t workspace_bytes)
 
size_t moe_swiglu_shared_q4k_q8_0_gated_workspace_bytes (int hidden_dim, int intermediate_dim)
 
size_t moe_swiglu_shared_q8_0_gated_workspace_bytes (int hidden_dim, int intermediate_dim)
 
void mrope_qk_imrope_positions (float *q, float *k, const int32_t *positions, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int n_dims, int section_0, int section_1, int section_2, int section_3, int n_ctx_orig, float freq_base, float freq_scale, float ext_factor, float attn_factor, float beta_fast, float beta_slow)
 
void mrope_qk_text (float *q, float *k, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int pos_offset, int n_dims, int section_0, int section_1, int section_2, int section_3, int n_ctx_orig, float freq_base, float freq_scale, float ext_factor, float attn_factor, float beta_fast, float beta_slow)
 
void mrope_qk_text_imrope (float *q, float *k, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int pos_offset, int n_dims, int section_0, int section_1, int section_2, int section_3, int n_ctx_orig, float freq_base, float freq_scale, float ext_factor, float attn_factor, float beta_fast, float beta_slow)
 
void mrope_qk_text_imrope_bf16_pytorch_storage (float *q, float *k, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int pos_offset, int n_dims, int section_0, int section_1, int section_2, int section_3, int n_ctx_orig, float freq_base, float freq_scale, float ext_factor, float attn_factor, float beta_fast, float beta_slow)
 
void mrope_qk_text_imrope_positions_bf16_pytorch_storage (float *q, float *k, const int32_t *positions, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int n_dims, int section_0, int section_1, int section_2, int section_3, int n_ctx_orig, float freq_base, float freq_scale, float ext_factor, float attn_factor, float beta_fast, float beta_slow)
 
void mrope_qk_vision (float *q, float *k, const int32_t *positions, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int n_dims, int section_0, int section_1, int section_2, int section_3, int n_ctx_orig, float freq_base, float freq_scale, float ext_factor, float attn_factor, float beta_fast, float beta_slow)
 
void mrope_qk_vision_bf16_pytorch_storage (float *q, float *k, const int32_t *positions, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int n_dims, int section_0, int section_1, int section_2, int section_3, int n_ctx_orig, float freq_base, float freq_scale, float ext_factor, float attn_factor, float beta_fast, float beta_slow)
 
void mrope_qk_vision_bf16_storage (float *q, float *k, const int32_t *positions, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int n_dims, int section_0, int section_1, int section_2, int section_3, int n_ctx_orig, float freq_base, float freq_scale, float ext_factor, float attn_factor, float beta_fast, float beta_slow)
 
void mrope_qk_vision_fp16_storage (float *q, float *k, const int32_t *positions, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int n_dims, int section_0, int section_1, int section_2, int section_3, int n_ctx_orig, float freq_base, float freq_scale, float ext_factor, float attn_factor, float beta_fast, float beta_slow)
 
void nemotron_group_limited_topk_router_f32 (const float *scores, const float *correction_bias, int *indices, float *weights, int rows, int n_experts, int top_k, int n_group, int topk_group, int norm_topk_prob, float routed_scaling_factor)
 
void patch2im (const float *d_patches, float *d_image, int C, int H, int W, int P)
 
void patch2im_bf16 (const uint16_t *d_patches, uint16_t *d_image, int C, int H, int W, int P)
 
void patch_projection_bf16_pytorch_onednn_conv3d_storage (const float *input, const void *weights, const float *bias, float *output, int batch, int out_channels, int in_channels, int temporal, int patch_h, int patch_w)
 
void patch_projection_image_bf16_native_storage (const float *image, const void *weights_t0, const void *weights_t1, const float *bias, float *output, int channels, int image_h, int image_w, int patch_size, int out_channels, int merge_size)
 
void patch_projection_image_bf16_pytorch_onednn_conv3d_storage (const float *image, const void *weights_t0, const void *weights_t1, const float *bias, float *output, int channels, int image_h, int image_w, int patch_size, int out_channels, int merge_size)
 
void position_embeddings_add (float *x, const float *position_embd, int num_tokens, int embed_dim, int num_positions)
 
void position_embeddings_add_at_offset (float *x, const float *position_embd, int num_tokens, int embed_dim, int num_positions, int start_position)
 
void position_embeddings_add_gemma4v_xy (float *x, const float *position_embd, int grid_h, int grid_w, int embed_dim, int source_grid_size)
 
void position_embeddings_add_tiled_2d (float *x, const float *position_embd, int grid_h, int grid_w, int embed_dim, int merge_size, int source_grid_size)
 
void position_embeddings_add_tiled_2d_align_corners (float *x, const float *position_embd, int grid_h, int grid_w, int embed_dim, int merge_size, int source_grid_size)
 
void position_embeddings_add_tiled_2d_align_corners_bf16 (float *x, const float *position_embd, int grid_h, int grid_w, int embed_dim, int merge_size, int source_grid_size)
 
void position_embeddings_add_tiled_2d_align_corners_fp32_interp_bf16 (float *x, const float *position_embd, int grid_h, int grid_w, int embed_dim, int merge_size, int source_grid_size)
 
void q_norm_forward (float *q, const float *q_gamma, int num_heads, int num_tokens, int head_dim, float eps)
 
void qk_norm_backward (const float *d_q_out, const float *d_k_out, const float *q_in, const float *k_in, const float *q_gamma, const float *k_gamma, float *d_q_in, float *d_k_in, float *d_q_gamma, float *d_k_gamma, int num_heads, int num_kv_heads, int num_tokens, int head_dim, float eps)
 
int qk_norm_backward_last_isa (void)
 
void qk_norm_forward (float *q, float *k, const float *q_gamma, const float *k_gamma, int num_heads, int num_kv_heads, int num_tokens, int head_dim, float eps)
 
void qk_norm_forward_decode_exact (float *q, float *k, const float *q_gamma, const float *k_gamma, int num_heads, int num_kv_heads, int num_tokens, int head_dim, float eps)
 
void qk_norm_forward_fp64_sum (float *q, float *k, const float *q_gamma, const float *k_gamma, int num_heads, int num_kv_heads, int num_tokens, int head_dim, float eps)
 
void qk_norm_forward_llama_production (float *q, float *k, const float *q_gamma, const float *k_gamma, int num_heads, int num_kv_heads, int num_tokens, int head_dim, float eps)
 
void qk_norm_forward_parallel_dispatch (float *q, float *k, const float *q_gamma, const float *k_gamma, int num_heads, int num_kv_heads, int num_tokens, int head_dim, float eps)
 
void qk_norm_forward_prefill_exact (float *q, float *k, const float *q_gamma, const float *k_gamma, int num_heads, int num_kv_heads, int num_tokens, int head_dim, float eps)
 
void qk_norm_forward_pytorch_bf16_storage (float *q, float *k, const float *q_gamma, const float *k_gamma, int num_heads, int num_kv_heads, int num_tokens, int head_dim, float eps)
 
void qk_norm_forward_qwen4_pytorch_bf16_storage (float *q, float *k, const float *q_gamma, const float *k_gamma, int num_heads, int num_kv_heads, int num_tokens, int head_dim, float eps)
 
void quantize_batch_q8_0 (const float *x, void *y, int num_rows, int k)
 Batch quantize FP32 to Q8_0 format (row-major output)
 
void quantize_batch_q8_k (const float *x, void *y, int num_rows, int k)
 Batch quantize FP32 to Q8_K format (row-major output)
 
void quantize_batch_q8_k_4row_nearest_even (const float *x, void *y, int num_rows, int k)
 
void quantize_row_q8_0 (const float *x, void *y, int k)
 Quantize FP32 to Q8_0 format (scalar reference)
 
void quantize_row_q8_k (const float *x, void *y, int k)
 
void qwen4_ple_gate_conv_inject_bf16 (const float *hyper_input, const float *key_projected, const float *value_projected, const float *norm_key_weight, const float *norm_query_weight, const float *norm_conv_weight, const uint16_t *conv_weight, float *hyper_output, float *key_norm_scratch, float *query_norm_scratch, float *gated_scratch, float *conv_norm_scratch, const float *conv_state_in, float *conv_state_out, int rows, int streams, int hidden_dim, int kernel_size, int dilation, float eps)
 
void qwen4_ple_gate_conv_inject_fp16 (const float *hyper_input, const float *key_projected, const float *value_projected, const float *norm_key_weight, const float *norm_query_weight, const float *norm_conv_weight, const uint16_t *conv_weight, float *hyper_output, float *key_norm_scratch, float *query_norm_scratch, float *gated_scratch, float *conv_norm_scratch, const float *conv_state_in, float *conv_state_out, int rows, int streams, int hidden_dim, int kernel_size, int dilation, float eps)
 
void qwen4_ple_gate_conv_inject_llama_fp16 (const float *hyper_input, const float *key_projected, const float *value_projected, const float *norm_key_weight, const float *norm_query_weight, const float *norm_conv_weight, const uint16_t *conv_weight, float *hyper_output, float *key_norm_scratch, float *query_norm_scratch, float *gated_scratch, float *conv_norm_scratch, const float *conv_state_in, float *conv_state_out, int rows, int streams, int hidden_dim, int kernel_size, int dilation, float eps)
 
void qwen4_ple_ngram_embed_bf16 (const int32_t *token_ids, const uint16_t *embedding, const int64_t *layer_multipliers, const int64_t *head_offsets, const int64_t *head_vocab_sizes, float *output, const float *token_state_in, float *token_state_out, int rows, int ngram_size, int heads_per_ngram, int head_dim, int eos_token_id, int position)
 
void qwen4_ple_ngram_embed_q5_0 (const int32_t *token_ids, const void *embedding, const int64_t *layer_multipliers, const int64_t *head_offsets, const int64_t *head_vocab_sizes, float *output, const float *token_state_in, float *token_state_out, int rows, int ngram_size, int heads_per_ngram, int head_dim, int eos_token_id, int position)
 
void qwen4_qsa_index_select_bf16 (const float *projected_qk, const float *index_key_cache_in, const float *q_norm_weight, const float *k_norm_weight, float *selected_indices, float *index_key_cache_out, float *q_norm_scratch, float *pooled_key_scratch, float *block_score_scratch, int32_t *block_index_scratch, int rows, int query_heads, int index_head_dim, int token_budget, int compress_ratio, int rotary_dim, int context_length, int position, float rope_theta, float eps)
 
void recurrent_conv_state_update_backward (const float *d_conv_x, const float *d_state_out, float *d_state_in, float *d_q, float *d_k, float *d_v, int history_len, int num_seqs, int num_tokens, int q_dim, int k_dim, int v_dim)
 
void recurrent_conv_state_update_backward_workspace (const float *d_conv_x, const float *d_state_out, float *d_state_in, float *d_q, float *d_k, float *d_v, float *d_conv_total, int history_len, int num_seqs, int num_tokens, int q_dim, int k_dim, int v_dim)
 
void recurrent_conv_state_update_forward (const float *state_in, const float *q, const float *k, const float *v, float *conv_x, float *state_out, int history_len, int num_seqs, int num_tokens, int q_dim, int k_dim, int v_dim)
 
void recurrent_dt_gate_backward (const float *d_gate, const float *alpha, const float *dt_bias, const float *a, float *d_alpha, float *d_dt_bias, float *d_a, int rows, int dim)
 
void recurrent_dt_gate_expanded_forward (const float *alpha, const float *dt_bias, const float *a, float *gate, int rows, int num_heads, int state_dim)
 
void recurrent_dt_gate_forward (const float *alpha, const float *dt_bias, const float *a, float *gate, int rows, int num_heads, int state_dim)
 
void recurrent_dt_gate_forward_pytorch_fp32 (const float *alpha, const float *dt_bias, const float *a, float *gate, int rows, int num_heads, int state_dim)
 
void recurrent_norm_gate_backward (const float *d_out, const float *x, const float *gate, const float *weight, float *d_x, float *d_gate, float *d_weight, int rows, int num_heads, int head_dim, float eps)
 
void recurrent_norm_gate_forward (const float *x, const float *gate, const float *weight, float *out, int rows, int num_heads, int head_dim, float eps)
 
void recurrent_norm_gate_llama_avx2_forward (const float *x, const float *gate, const float *weight, float *out, int rows, int num_heads, int head_dim, float eps)
 
void recurrent_norm_gate_pytorch_bf16_storage (const float *x, const float *gate, const float *weight, float *out, int rows, int num_heads, int head_dim, float eps)
 
void recurrent_norm_sigmoid_gate_llama_avx2_forward (const float *x, const float *gate, const float *weight, float *out, int rows, int num_heads, int head_dim, float eps)
 
void recurrent_norm_sigmoid_gate_pytorch_bf16_storage (const float *x, const float *gate, const float *weight, float *out, int rows, int num_heads, int head_dim, float eps)
 
void recurrent_qk_l2_norm_backward (const float *d_q_out, const float *d_k_out, const float *q, const float *k, float *d_q, float *d_k, int rows, int q_dim, int k_dim, int head_dim, float eps)
 
void recurrent_qk_l2_norm_forward (float *q, float *k, int rows, int q_dim, int k_dim, int head_dim, float eps)
 
void recurrent_qk_l2_norm_pytorch_bf16_storage (float *q, float *k, int rows, int q_dim, int k_dim, int expanded_heads, int head_dim, float eps)
 
void recurrent_qk_l2_norm_pytorch_fp32_output (float *q, float *k, int rows, int q_dim, int k_dim, int head_dim, float eps)
 
void recurrent_sigmoid_forward_ggml (const float *x, float *out, int rows, int dim)
 
void recurrent_sigmoid_forward_pytorch_bf16_input_fp32_output (const float *x, float *out, int rows, int dim)
 
void recurrent_silu_backward (const float *d_out, const float *x, float *d_x, int rows, int dim)
 
void recurrent_silu_forward (const float *x, float *out, int rows, int dim)
 
void recurrent_silu_forward_ggml (const float *x, float *out, int rows, int dim)
 
void recurrent_silu_forward_pytorch_bf16_input_fp32_output (const float *x, float *out, int rows, int dim)
 
void recurrent_silu_forward_pytorch_bf16_storage (const float *x, float *out, int rows, int dim)
 
void recurrent_split_conv_qkv_backward (const float *d_q, const float *d_k, const float *d_v, float *d_packed_qkv, int rows, int q_dim, int k_dim, int v_dim)
 
void recurrent_split_conv_qkv_forward (const float *packed_qkv, float *q, float *k, float *v, int rows, int q_dim, int k_dim, int v_dim)
 
void recurrent_split_qkv_backward (const float *d_q, const float *d_k, const float *d_v, float *d_packed_qkv, int rows, int q_dim, int k_dim, int v_dim)
 
void recurrent_split_qkv_forward (const float *packed_qkv, float *q, float *k, float *v, int rows, int q_dim, int k_dim, int v_dim)
 
void relu2_backward (const float *input, const float *d_output, float *d_input, size_t n)
 
void relu2_forward (const float *input, float *output, size_t n)
 
void relu_backward (const float *input, const float *d_output, float *d_input, size_t n)
 
void relu_backward_bf16 (const uint16_t *input, const uint16_t *d_output, uint16_t *d_input, size_t n)
 
void relu_forward (const float *input, float *output, size_t n)
 
void relu_forward_bf16 (const uint16_t *input, uint16_t *output, size_t n)
 
void relu_forward_inplace (float *data, size_t n)
 
void relu_forward_inplace_bf16 (uint16_t *data, size_t n)
 
void rmsnorm_backward (const float *d_output, const float *input, const float *gamma, const float *rstd_cache, float *d_input, float *d_gamma, int tokens, int d_model, int aligned_embed_dim)
 
void rmsnorm_backward_bf16 (const uint16_t *d_output, const uint16_t *input, const float *gamma, const float *rstd_cache, uint16_t *d_input, float *d_gamma, int tokens, int d_model, int aligned_embed_dim)
 
void rmsnorm_backward_int4 (const uint8_t *d_output, const uint8_t *input, const float *gamma, const float *rstd_cache, uint8_t *d_input, float *d_gamma, int tokens, int d_model, int aligned_embed_dim, float *scratch_d_output, float *scratch_input, float *scratch_d_input)
 
void rmsnorm_backward_int8 (const int8_t *d_output, const int8_t *input, const float *gamma, const float *rstd_cache, int8_t *d_input, float *d_gamma, int tokens, int d_model, int aligned_embed_dim, float *scratch_d_output, float *scratch_input, float *scratch_d_input)
 
void rmsnorm_forward (const float *input, const float *gamma, float *output, float *rstd_cache, int tokens, int d_model, int aligned_embed_dim, float eps)
 
void rmsnorm_forward_bf16 (const uint16_t *input, const float *gamma, uint16_t *output, float *rstd_cache, int tokens, int d_model, int aligned_embed_dim, float eps)
 
void rmsnorm_forward_fp32_square_fp64_sum (const float *input, const float *gamma, float *output, float *rstd_cache, int tokens, int d_model, int aligned_embed_dim, float eps)
 
void rmsnorm_forward_fp64_sum (const float *input, const float *gamma, float *output, float *rstd_cache, int tokens, int d_model, int aligned_embed_dim, float eps)
 
void rmsnorm_forward_int4 (const uint8_t *input, const float *gamma, uint8_t *output, float *rstd_cache, int tokens, int d_model, int aligned_embed_dim, float eps, float *scratch_input, float *scratch_output)
 
void rmsnorm_forward_int8 (const int8_t *input, const float *gamma, int8_t *output, float *rstd_cache, int tokens, int d_model, int aligned_embed_dim, float eps, float *scratch_input, float *scratch_output)
 
void rmsnorm_forward_kv_lora (const float *input, const float *gamma, float *output, float *rstd_cache, int tokens, int d_model, int aligned_embed_dim, float eps)
 
void rmsnorm_forward_llama_production (const float *input, const float *gamma, float *output, float *rstd_cache, int tokens, int d_model, int aligned_embed_dim, float eps)
 
void rmsnorm_forward_no_weight (const float *input, float *output, float *rstd_cache, int tokens, int d_model, int aligned_embed_dim, float eps)
 
void rmsnorm_forward_parallel_dispatch (const float *input, const float *gamma, float *output, float *rstd_cache, int tokens, int d_model, int aligned_embed_dim, float eps)
 
void rmsnorm_forward_pytorch_bf16_storage (const float *input, const float *gamma, float *output, float *rstd_cache, int tokens, int d_model, int aligned_embed_dim, float eps)
 
void rmsnorm_forward_qwen3next_pytorch_bf16_storage (const float *input, const float *gamma, float *output, float *rstd_cache, int tokens, int d_model, int aligned_embed_dim, float eps)
 
void rmsnorm_forward_strided_f32 (const float *input, const float *gamma, float *output, float *rstd_cache, int tokens, int d_model, int input_stride, int output_stride, float eps)
 
void rmsnorm_forward_strided_pytorch_bf16_storage (const float *input, const float *gamma, float *output, float *rstd_cache, int tokens, int d_model, int input_stride, int output_stride, float eps)
 
void rope_backward (const float *d_out, float *d_x, const float *cos_cache, const float *sin_cache, int num_heads, int num_tokens, int head_dim, int aligned_head_dim, int pos_offset)
 
void rope_backward_bf16 (const uint16_t *d_out, uint16_t *d_x, const float *cos_cache, const float *sin_cache, int num_heads, int num_tokens, int head_dim, int aligned_head_dim, int pos_offset, float *scratch_d_out, float *scratch_d_x)
 
void rope_backward_inplace (float *d_x, const float *cos_cache, const float *sin_cache, int num_heads, int num_tokens, int head_dim, int aligned_head_dim, int pos_offset)
 
void rope_backward_qk (const float *d_q_out, const float *d_k_out, float *d_q, float *d_k, const float *cos_cache, const float *sin_cache, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int pos_offset)
 
void rope_backward_qk_bf16 (const uint16_t *d_q_out, const uint16_t *d_k_out, uint16_t *d_q, uint16_t *d_k, const float *cos_cache, const float *sin_cache, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int pos_offset, float *scratch_dq_out, float *scratch_dq, float *scratch_dk_out, float *scratch_dk)
 
void rope_backward_qk_pairwise_with_rotary_dim (const float *d_q_out, const float *d_k_out, float *d_q, float *d_k, const float *cos_cache, const float *sin_cache, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int pos_offset, int rotary_dim)
 
void rope_forward (float *x, const float *cos_cache, const float *sin_cache, int num_heads, int num_tokens, int head_dim, int aligned_head_dim, int pos_offset)
 
void rope_forward_bf16 (uint16_t *x, const float *cos_cache, const float *sin_cache, int num_heads, int num_tokens, int head_dim, int aligned_head_dim, int pos_offset, float *scratch)
 
void rope_forward_bf16_with_rotary_dim (uint16_t *x, const float *cos_cache, const float *sin_cache, int num_heads, int num_tokens, int head_dim, int aligned_head_dim, int pos_offset, int rotary_dim, float *scratch)
 
void rope_forward_q_split_direct_f32 (float *q, const float *freq_factors, int use_freq_factors, int num_heads, int num_tokens, int head_dim, int aligned_head_dim, int pos_offset, int rotary_dim, float freq_base)
 
void rope_forward_qk (float *q, float *k, const float *cos_cache, const float *sin_cache, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int pos_offset)
 
void rope_forward_qk_bf16 (uint16_t *q, uint16_t *k, const float *cos_cache, const float *sin_cache, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int pos_offset, float *scratch_q, float *scratch_k)
 
void rope_forward_qk_bf16_with_rotary_dim (uint16_t *q, uint16_t *k, const float *cos_cache, const float *sin_cache, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int pos_offset, int rotary_dim, float *scratch_q, float *scratch_k)
 
void rope_forward_qk_gemma4_direct (float *q, float *k, const float *freq_factors, int use_freq_factors, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int pos_offset, int rotary_dim, float freq_base)
 
void rope_forward_qk_gemma4v_vision_xy (float *q, float *k, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int grid_w, int rotary_dim, float freq_base)
 
void rope_forward_qk_pairwise_llama_cpu (float *q, float *k, const float *cos_cache, const float *sin_cache, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int pos_offset, int rotary_dim)
 
void rope_forward_qk_pairwise_with_rotary_dim (float *q, float *k, const float *cos_cache, const float *sin_cache, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int pos_offset, int rotary_dim)
 
void rope_forward_qk_split_direct_f32 (float *q, float *k, const float *freq_factors, int use_freq_factors, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int pos_offset, int rotary_dim, float freq_base)
 
void rope_forward_qk_split_direct_token_range_f32 (float *q, float *k, const float *freq_factors, int use_freq_factors, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int pos_offset, int rotary_dim, float freq_base, int token_begin, int token_end)
 
void rope_forward_qk_split_llama_token_range_f32 (float *q, float *k, const float *freq_factors, int use_freq_factors, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int pos_offset, int rotary_dim, float freq_base, int token_begin, int token_end)
 
void rope_forward_qk_strided (float *q, float *k, const float *cos_cache, const float *sin_cache, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int pos_offset, int q_stride_tokens, int k_stride_tokens)
 
void rope_forward_qk_strided_with_rotary_dim (float *q, float *k, const float *cos_cache, const float *sin_cache, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int pos_offset, int q_stride_tokens, int k_stride_tokens, int rotary_dim)
 
void rope_forward_qk_with_rotary_dim (float *q, float *k, const float *cos_cache, const float *sin_cache, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int pos_offset, int rotary_dim)
 
void rope_forward_qk_with_rotary_dim_cache_stride (float *q, float *k, const float *cos_cache, const float *sin_cache, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int pos_offset, int rotary_dim, int cache_rotary_dim)
 
void rope_forward_strided (float *x, const float *cos_cache, const float *sin_cache, int num_heads, int num_tokens, int head_dim, int aligned_head_dim, int pos_offset, int head_stride_tokens)
 
void rope_forward_strided_with_rotary_dim (float *x, const float *cos_cache, const float *sin_cache, int num_heads, int num_tokens, int head_dim, int aligned_head_dim, int pos_offset, int head_stride_tokens, int rotary_dim)
 
void rope_forward_with_rotary_dim (float *x, const float *cos_cache, const float *sin_cache, int num_heads, int num_tokens, int head_dim, int aligned_head_dim, int pos_offset, int rotary_dim)
 
void rope_precompute_cache (float *cos_cache, float *sin_cache, int max_seq_len, int head_dim, float base, int rotary_dim, const char *scaling_type, float scaling_factor)
 
void rope_precompute_cache_llama_cpu (float *cos_cache, float *sin_cache, int max_seq_len, int head_dim, float base, int rotary_dim, const char *scaling_type, float scaling_factor)
 
void rope_precompute_cache_split (float *cos_cache, float *sin_cache, int max_seq_len, int head_dim, float base)
 
void rowwise_bias_add (float *x, const float *bias, int rows, int dim)
 
void scal_copy_f32 (float *y, const float *x, float alpha, int n)
 Scaled copy: y = alpha * x.
 
void sigmoid_backward (const float *input, const float *d_output, float *d_input, size_t n)
 
void sigmoid_backward_bf16 (const uint16_t *input, const uint16_t *d_output, uint16_t *d_input, size_t n, float *scratch_input, float *scratch_d_output, float *scratch_d_input)
 
void sigmoid_forward (const float *input, float *output, size_t n)
 
void sigmoid_forward_bf16 (const uint16_t *input, uint16_t *output, size_t n, float *scratch_input, float *scratch_output)
 
float sigmoid_scalar (float x)
 
void softmax_cross_entropy_loss (const float *logits, const int32_t *targets, int tokens, int vocab_size, float *d_logits, float *loss_out)
 
void softmax_cross_entropy_loss_bf16 (const uint16_t *logits, const int32_t *targets, int tokens, int vocab_size, uint16_t *d_logits, float *loss_out, float *scratch_logits, float *scratch_d_logits)
 
void softmax_cross_entropy_loss_ptref (const float *logits, const int32_t *targets, int tokens, int vocab_size, float *d_logits, float *loss_out)
 
void spatial_average_pool_contiguous (const float *input, float *output, int grid_h, int grid_w, int embed_dim, int merge_size)
 
void spatial_merge_2x2 (const float *input, float *output, int grid_h, int grid_w, int embed_dim)
 
void spatial_merge_contiguous_tiled (const float *input, float *output, int grid_h, int grid_w, int embed_dim, int merge_size)
 
void speculative_commit_one_i32 (int accepted, int verified_token, int *token_buffer, int *token_count, int max_tokens, int *target_position, int *draft_position, int *accepted_count, int *rejected_count)
 Commit one verified speculative token and update decode counters.
 
void speculative_verify_greedy_f32 (const float *target_logits, int vocab_size, int draft_token, int *accepted, int *verified_token)
 Greedy one-token speculative verification.
 
void split_q_gate_backward (const float *d_q, const float *d_gate, float *d_packed_qg, int rows, int q_dim, int gate_dim, int group_dim)
 
void split_q_gate_forward (const float *packed_qg, float *q, float *gate, int rows, int q_dim, int gate_dim, int group_dim)
 
void split_qkv_packed_head_major_forward (const float *packed_qkv, float *q, float *k, float *v, int rows, int q_dim, int k_dim, int v_dim, int num_heads, int num_kv_heads)
 
void ssm_conv1d_backward (const float *d_out, const float *conv_x, const float *kernel, float *d_conv_x, float *d_kernel, int kernel_size, int num_channels, int num_tokens, int num_seqs)
 
void ssm_conv1d_forward (const float *conv_x, const float *kernel, float *out, int kernel_size, int num_channels, int num_tokens, int num_seqs)
 
void ssm_conv1d_forward_llama_fma (const float *conv_x, const float *kernel, float *out, int kernel_size, int num_channels, int num_tokens, int num_seqs)
 
void ssm_conv1d_forward_llama_production (const float *conv_x, const float *kernel, float *out, int kernel_size, int num_channels, int num_tokens, int num_seqs)
 
void ssm_conv1d_forward_llama_production_serial (const float *conv_x, const float *kernel, float *out, int kernel_size, int num_channels, int num_tokens, int num_seqs)
 
void ssm_conv1d_forward_pytorch_bf16_storage (const float *conv_x, const float *kernel, float *out, int kernel_size, int num_channels, int num_tokens, int num_seqs)
 
void swiglu_backward (const float *input, const float *d_output, float *d_input, int tokens, int dim)
 
void swiglu_backward_bf16 (const uint16_t *input, const uint16_t *d_output, uint16_t *d_input, int tokens, int dim)
 
void swiglu_backward_exact (const float *input, const float *d_output, float *d_input, int tokens, int dim)
 
void swiglu_forward (const float *input, float *output, int tokens, int dim)
 
void swiglu_forward_bf16 (const uint16_t *input, uint16_t *output, int tokens, int dim)
 
void swiglu_forward_exact (const float *input, float *output, int tokens, int dim)
 
void swiglu_forward_ggml (const float *input, float *output, int tokens, int dim)
 
void swiglu_forward_ggml_split (const float *gate, const float *up, float *output, int tokens, int dim)
 
void swiglu_forward_pytorch_bf16_storage (const float *input, float *output, int tokens, int dim)
 
void swiglu_forward_q8_k (const float *input, void *output_q8, int tokens, int dim)
 
void topk_batched_f32 (const float *scores, int num_tokens, int n_experts, int k, int *indices, float *weights)
 Batched top-K selection for multiple tokens.
 
void topk_f32 (const float *scores, int n, int k, int *indices, float *values)
 Find top-K indices and values from a score vector.
 
void topk_softmax_backward_f32 (const int *indices, const float *weights, const float *d_weights, float *d_scores, int num_tokens, int n_experts_or_keys, int k)
 Backward for hard top-k followed by softmax over selected values.
 
void topk_softmax_f32 (const float *scores, int n, int k, int *indices, float *weights)
 Find top-K indices with softmax-normalized weights.
 
void unfused_rmsnorm_qkv_prefill (const float *x, const float *gamma, const float *Wq, const float *Wk, const float *Wv, float *x_norm, float *Q, float *K, float *V, int seq_len, int hidden, int q_dim, int kv_dim, float eps)
 Unfused version for benchmarking comparison.
 
void vec_dot_q6_k_q8_k (int n, float *s, const void *vx, const void *vy)
 Q6_K x Q8_K dot product (single row)
 
void vision_position_ids_2d_merge (int32_t *positions, int grid_h, int grid_w, int merge_size)
 
void weighted_sum_f32 (float *y, const float **vectors, const float *weights, int k, int n)
 Weighted sum of k vectors: y = sum_i(weights[i] * vectors[i])
 
void yarn_rope_cache_contiguous_positions_f32 (float *cos_cache, float *sin_cache, int num_tokens, int rotary_dim, float freq_base, float factor, int original_context, float beta_fast, float beta_slow, float mscale, float mscale_all_dim)
 
void yarn_rope_cache_explicit_positions_bf16 (uint16_t *cos_cache, uint16_t *sin_cache, const int32_t *positions, int num_tokens, int rotary_dim, float freq_base, float factor, int original_context, float beta_fast, float beta_slow, float mscale, float mscale_all_dim)
 
void yarn_rope_cache_explicit_positions_f32 (float *cos_cache, float *sin_cache, const int32_t *positions, int num_tokens, int rotary_dim, float freq_base, float factor, int original_context, float beta_fast, float beta_slow, float mscale, float mscale_all_dim)
 

Enumeration Type Documentation

◆ ck_attention_prefill_schedule_t

Enumerator
CK_ATTN_PREFILL_SCHEDULE_KV_HEADS 
CK_ATTN_PREFILL_SCHEDULE_QUERY_HEADS 
CK_ATTN_PREFILL_SCHEDULE_QUERY_TILES 
CK_ATTN_PREFILL_SCHEDULE_KV_GROUP_QUERY_TILES 
CK_ATTN_PREFILL_SCHEDULE_GQA_SHARED_KV_TILES 

Definition at line 2124 of file ckernel_engine.h.

◆ ck_attention_reduction_t

Enumerator
CK_ATTN_REDUCTION_FP32_ONLINE 
CK_ATTN_REDUCTION_F16_ONLINE_FP32_MERGE 
CK_ATTN_REDUCTION_F16_ONLINE_SINGLE_RANGE 
CK_ATTN_REDUCTION_F16_FLASH_AUTO_QTILE64 
CK_ATTN_REDUCTION_BF16_PYTORCH_SDPA 

Definition at line 2114 of file ckernel_engine.h.

◆ ck_attention_status_t

Enumerator
CK_ATTENTION_STATUS_OK 
CK_ATTENTION_STATUS_INVALID_ARGUMENT 
CK_ATTENTION_STATUS_UNSUPPORTED_CONTRACT 
CK_ATTENTION_STATUS_INSUFFICIENT_WORKSPACE 

Definition at line 2132 of file ckernel_engine.h.

2132 {
ck_attention_status_t
@ CK_ATTENTION_STATUS_UNSUPPORTED_CONTRACT
@ CK_ATTENTION_STATUS_OK
@ CK_ATTENTION_STATUS_INVALID_ARGUMENT
@ CK_ATTENTION_STATUS_INSUFFICIENT_WORKSPACE

Function Documentation

◆ adamw_clip_update_multi_f32()

void adamw_clip_update_multi_f32 ( float *const *  grads,
float *const *  weights,
float *const *  m_states,
float *const *  v_states,
const size_t *  numels,
int  tensor_count,
float  lr,
float  beta1,
float  beta2,
float  eps,
float  weight_decay,
float  max_grad_norm,
int  step 
)

Definition at line 638 of file optimizer_kernels.c.

652{
653 if (!grads || !weights || !m_states || !v_states || !numels || tensor_count <= 0) {
654 return;
655 }
656
657 size_t total_numel = 0;
658 int valid_tensors = 0;
659 for (int i = 0; i < tensor_count; ++i) {
660 if (grads[i] && weights[i] && m_states[i] && v_states[i] && numels[i] > 0) {
661 total_numel += numels[i];
662 valid_tensors += 1;
663 }
664 }
665 if (valid_tensors == 0 || total_numel == 0) {
666 return;
667 }
668
669 float grad_scale = 1.0f;
670 if (max_grad_norm > 0.0f) {
671 float global_norm = gradient_global_norm_multi_f32((const float *const *)grads, numels, tensor_count);
672 if (global_norm > max_grad_norm) {
673 grad_scale = max_grad_norm / global_norm;
674 }
675 }
676
677 ck_threadpool_t *pool = ck_threadpool_global();
678 int nth = pool ? ck_threadpool_n_threads(pool) : 1;
679
680 if (!pool || nth <= 1 || nth > CK_OPT_PAR_MAX_THREADS ||
681 total_numel < CK_OPT_PAR_MIN_NUMEL || valid_tensors < 2) {
682 for (int i = 0; i < tensor_count; ++i) {
683 float *g = grads[i];
684 float *w = weights[i];
685 float *m = m_states[i];
686 float *v = v_states[i];
687 size_t n = numels[i];
688 if (!g || !w || !m || !v || n == 0) {
689 continue;
690 }
691 if (grad_scale != 1.0f) {
692 gradient_scale_f32_impl(g, n, grad_scale);
693 }
694 adamw_update_f32_impl(g, w, m, v, n, lr, beta1, beta2, eps, weight_decay, step);
695 }
696 return;
697 }
698 int active_nth = ck_opt_pick_active_threads(nth, total_numel, CK_OPT_PAR_MIN_NUMEL);
699 if (active_nth > valid_tensors) {
700 active_nth = valid_tensors;
701 }
702 if (active_nth <= 1) {
703 for (int i = 0; i < tensor_count; ++i) {
704 float *g = grads[i];
705 float *w = weights[i];
706 float *m = m_states[i];
707 float *v = v_states[i];
708 size_t n = numels[i];
709 if (!g || !w || !m || !v || n == 0) {
710 continue;
711 }
712 if (grad_scale != 1.0f) {
713 gradient_scale_f32_impl(g, n, grad_scale);
714 }
715 adamw_update_f32_impl(g, w, m, v, n, lr, beta1, beta2, eps, weight_decay, step);
716 }
717 return;
718 }
719
720 ck_adamw_multi_parallel_args_t args = {
721 .grads = grads,
722 .weights = weights,
723 .m_states = m_states,
724 .v_states = v_states,
725 .numels = numels,
726 .tensor_count = tensor_count,
727 .lr = lr,
728 .beta1 = beta1,
729 .beta2 = beta2,
730 .eps = eps,
731 .weight_decay = weight_decay,
732 .grad_scale = grad_scale,
733 .step = step,
734 };
736}
void ck_threadpool_dispatch_n(ck_threadpool_t *pool, int active_threads, ck_work_fn_t fn, void *args)
ck_threadpool_t * ck_threadpool_global(void)
int ck_threadpool_n_threads(const ck_threadpool_t *pool)
static void adamw_update_f32_impl(const float *grad, float *weight, float *m, float *v, size_t numel, float lr, float beta1, float beta2, float eps, float weight_decay, int step)
AdamW optimizer update (fp32 version)
static int ck_opt_pick_active_threads(int nth, size_t work_items, size_t min_chunk)
#define CK_OPT_PAR_MIN_NUMEL
float gradient_global_norm_multi_f32(const float *const *grads, const size_t *numels, int tensor_count)
static void ck_adamw_multi_parallel_work(int ith, int nth, void *argp)
static void gradient_scale_f32_impl(float *grad, size_t numel, float scale)
Scale gradients by a constant: grad *= scale (fp32)
#define CK_OPT_PAR_MAX_THREADS

References adamw_update_f32_impl(), ck_adamw_multi_parallel_work(), CK_OPT_PAR_MAX_THREADS, CK_OPT_PAR_MIN_NUMEL, ck_opt_pick_active_threads(), ck_threadpool_dispatch_n(), ck_threadpool_global(), ck_threadpool_n_threads(), gradient_global_norm_multi_f32(), and gradient_scale_f32_impl().

◆ adamw_update_f32()

void adamw_update_f32 ( const float *  grad,
float *  weight,
float *  m,
float *  v,
size_t  numel,
float  lr,
float  beta1,
float  beta2,
float  eps,
float  weight_decay,
int  step 
)

Definition at line 592 of file optimizer_kernels.c.

604{
605 if (!grad || !weight || !m || !v || numel == 0) {
606 return;
607 }
608
609 ck_threadpool_t *pool = ck_threadpool_global();
610 int nth = pool ? ck_threadpool_n_threads(pool) : 1;
611 if (!pool || nth <= 1 || nth > CK_OPT_PAR_MAX_THREADS || numel < CK_OPT_PAR_MIN_NUMEL) {
612 adamw_update_f32_impl(grad, weight, m, v, numel, lr, beta1, beta2, eps, weight_decay, step);
613 return;
614 }
615 int active_nth = ck_opt_pick_active_threads(nth, numel, CK_OPT_PAR_MIN_NUMEL);
616 if (active_nth <= 1) {
617 adamw_update_f32_impl(grad, weight, m, v, numel, lr, beta1, beta2, eps, weight_decay, step);
618 return;
619 }
620
621 ck_adamw_parallel_args_t args = {
622 .grad = grad,
623 .weight = weight,
624 .m = m,
625 .v = v,
626 .numel = numel,
627 .lr = lr,
628 .beta1 = beta1,
629 .beta2 = beta2,
630 .eps = eps,
631 .weight_decay = weight_decay,
632 .step = step,
633 };
634 ck_threadpool_dispatch_n(pool, active_nth, ck_adamw_parallel_work, &args);
635}
static void ck_adamw_parallel_work(int ith, int nth, void *argp)

References adamw_update_f32_impl(), ck_adamw_parallel_work(), CK_OPT_PAR_MAX_THREADS, CK_OPT_PAR_MIN_NUMEL, ck_opt_pick_active_threads(), ck_threadpool_dispatch_n(), ck_threadpool_global(), and ck_threadpool_n_threads().

◆ add_backward_bf16()

void add_backward_bf16 ( const uint16_t *  d_y,
uint16_t *  d_a,
uint16_t *  d_b,
size_t  n 
)

Definition at line 187 of file add_kernels_bf16.c.

191{
192 if (!d_y || n == 0) {
193 return;
194 }
195
196 size_t i = 0;
197
198 /* Copy to d_a if not in-place */
199 if (d_a && d_a != d_y) {
200#if defined(__AVX512F__)
201 for (; i + 32 <= n; i += 32) {
202 __m512i v0 = _mm512_loadu_si512((const __m512i*)&d_y[i]);
203 __m512i v1 = _mm512_loadu_si512((const __m512i*)&d_y[i + 32]);
204 _mm512_storeu_si512((__m512i*)&d_a[i], v0);
205 _mm512_storeu_si512((__m512i*)&d_a[i + 32], v1);
206 }
207#endif
208 for (; i < n; ++i) {
209 d_a[i] = d_y[i];
210 }
211 }
212
213 /* Copy to d_b if not in-place */
214 i = 0;
215 if (d_b && d_b != d_y) {
216#if defined(__AVX512F__)
217 for (; i + 32 <= n; i += 32) {
218 __m512i v0 = _mm512_loadu_si512((const __m512i*)&d_y[i]);
219 __m512i v1 = _mm512_loadu_si512((const __m512i*)&d_y[i + 32]);
220 _mm512_storeu_si512((__m512i*)&d_b[i], v0);
221 _mm512_storeu_si512((__m512i*)&d_b[i + 32], v1);
222 }
223#endif
224 for (; i < n; ++i) {
225 d_b[i] = d_y[i];
226 }
227 }
228}

◆ add_forward_2d_bf16()

void add_forward_2d_bf16 ( const uint16_t *  a,
const uint16_t *  b,
uint16_t *  y,
int  tokens,
int  dim,
int  aligned_dim 
)

Definition at line 235 of file add_kernels_bf16.c.

241{
242 if (!a || !b || !y || tokens <= 0 || dim <= 0) {
243 return;
244 }
245
246 for (int t = 0; t < tokens; ++t) {
247 const uint16_t *a_row = a + (size_t)t * aligned_dim;
248 const uint16_t *b_row = b + (size_t)t * aligned_dim;
249 uint16_t *y_row = y + (size_t)t * aligned_dim;
250
251 int d = 0;
252
253#if defined(__AVX512F__)
254 for (; d + 16 <= dim; d += 16) {
255 __m512 av = bf16_loadu_cvt_fp32(&a_row[d]);
256 __m512 bv = bf16_loadu_cvt_fp32(&b_row[d]);
257 __m512 yv = _mm512_add_ps(av, bv);
258 fp32_cvt_storeu_bf16(&y_row[d], yv);
259 }
260#endif
261
262 for (; d < dim; ++d) {
263 float af = bf16_to_float(a_row[d]);
264 float bf = bf16_to_float(b_row[d]);
265 y_row[d] = float_to_bf16(af + bf);
266 }
267 }
268}
static uint16_t float_to_bf16(float f)
Definition bf16_utils.h:90
static float bf16_to_float(uint16_t v)
Definition bf16_utils.h:38

References bf16_to_float(), and float_to_bf16().

◆ add_forward_bf16()

void add_forward_bf16 ( const uint16_t *  a,
const uint16_t *  b,
uint16_t *  y,
size_t  n 
)

Definition at line 38 of file add_kernels_bf16.c.

42{
43 if (!a || !b || !y || n == 0) {
44 return;
45 }
46
47 size_t i = 0;
48
49#if defined(__AVX512F__)
50 /* AVX-512: Process 16 bf16 elements at a time */
51 for (; i + 16 <= n; i += 16) {
52 __m512 av = bf16_loadu_cvt_fp32(&a[i]);
53 __m512 bv = bf16_loadu_cvt_fp32(&b[i]);
54 __m512 yv = _mm512_add_ps(av, bv);
55 fp32_cvt_storeu_bf16(&y[i], yv);
56 }
57#endif
58
59 /* Scalar fallback */
60 for (; i < n; ++i) {
61 float af = bf16_to_float(a[i]);
62 float bf = bf16_to_float(b[i]);
63 y[i] = float_to_bf16(af + bf);
64 }
65}

References bf16_to_float(), and float_to_bf16().

◆ add_forward_f32()

void add_forward_f32 ( const float *  a,
const float *  b,
float *  y,
size_t  n 
)

Element-wise add: y = a + b

Test:

test_add.py::TestAddForward::test_add_forward_f32

test_add.py::TestAddForward::test_add_inplace_f32

test_multi_layer_parity.py::TestMultiLayerParity::test_residual_add

Element-wise addition of two vectors.

After changes: make test

Definition at line 284 of file add_kernels_bf16.c.

288{
289 if (!a || !b || !y || n == 0) {
290 return;
291 }
292
293 size_t i = 0;
294
295#if defined(__AVX512F__)
296 for (; i + 16 <= n; i += 16) {
297 __m512 av = _mm512_loadu_ps(&a[i]);
298 __m512 bv = _mm512_loadu_ps(&b[i]);
299 __m512 yv = _mm512_add_ps(av, bv);
300 _mm512_storeu_ps(&y[i], yv);
301 }
302#endif
303
304#if defined(__AVX2__)
305 for (; i + 8 <= n; i += 8) {
306 __m256 av = _mm256_loadu_ps(&a[i]);
307 __m256 bv = _mm256_loadu_ps(&b[i]);
308 __m256 yv = _mm256_add_ps(av, bv);
309 _mm256_storeu_ps(&y[i], yv);
310 }
311#endif
312
313 for (; i < n; ++i) {
314 y[i] = a[i] + b[i];
315 }
316}

◆ add_inplace_bf16()

void add_inplace_bf16 ( uint16_t *  a,
const uint16_t *  b,
size_t  n 
)

Definition at line 119 of file add_kernels_bf16.c.

122{
123 if (!a || !b || n == 0) {
124 return;
125 }
126
127 size_t i = 0;
128
129#if defined(__AVX512F__)
130 for (; i + 16 <= n; i += 16) {
131 __m512 av = bf16_loadu_cvt_fp32(&a[i]);
132 __m512 bv = bf16_loadu_cvt_fp32(&b[i]);
133 __m512 yv = _mm512_add_ps(av, bv);
134 fp32_cvt_storeu_bf16(&a[i], yv);
135 }
136#endif
137
138 for (; i < n; ++i) {
139 float af = bf16_to_float(a[i]);
140 float bf = bf16_to_float(b[i]);
141 a[i] = float_to_bf16(af + bf);
142 }
143}

References bf16_to_float(), and float_to_bf16().

◆ add_inplace_f32()

void add_inplace_f32 ( float *  a,
const float *  b,
size_t  n 
)

Definition at line 318 of file add_kernels_bf16.c.

321{
322 if (!a || !b || n == 0) {
323 return;
324 }
325
326 size_t i = 0;
327
328#if defined(__AVX512F__)
329 for (; i + 16 <= n; i += 16) {
330 __m512 av = _mm512_loadu_ps(&a[i]);
331 __m512 bv = _mm512_loadu_ps(&b[i]);
332 __m512 yv = _mm512_add_ps(av, bv);
333 _mm512_storeu_ps(&a[i], yv);
334 }
335#endif
336
337#if defined(__AVX2__)
338 for (; i + 8 <= n; i += 8) {
339 __m256 av = _mm256_loadu_ps(&a[i]);
340 __m256 bv = _mm256_loadu_ps(&b[i]);
341 __m256 yv = _mm256_add_ps(av, bv);
342 _mm256_storeu_ps(&a[i], yv);
343 }
344#endif
345
346 for (; i < n; ++i) {
347 a[i] = a[i] + b[i];
348 }
349}

Referenced by mega_fused_outproj_mlp_prefill().

◆ add_scaled_forward_bf16()

void add_scaled_forward_bf16 ( const uint16_t *  a,
const uint16_t *  b,
uint16_t *  y,
float  alpha,
size_t  n 
)

Definition at line 86 of file add_kernels_bf16.c.

91{
92 if (!a || !b || !y || n == 0) {
93 return;
94 }
95
96 size_t i = 0;
97
98#if defined(__AVX512F__)
99 __m512 alpha_v = _mm512_set1_ps(alpha);
100 for (; i + 16 <= n; i += 16) {
101 __m512 av = bf16_loadu_cvt_fp32(&a[i]);
102 __m512 bv = bf16_loadu_cvt_fp32(&b[i]);
103 __m512 yv = _mm512_fmadd_ps(bv, alpha_v, av); /* a + alpha * b */
104 fp32_cvt_storeu_bf16(&y[i], yv);
105 }
106#endif
107
108 for (; i < n; ++i) {
109 float af = bf16_to_float(a[i]);
110 float bf = bf16_to_float(b[i]);
111 y[i] = float_to_bf16(af + alpha * bf);
112 }
113}

References bf16_to_float(), and float_to_bf16().

◆ add_scaled_inplace_bf16()

void add_scaled_inplace_bf16 ( uint16_t *  a,
const uint16_t *  b,
float  alpha,
size_t  n 
)

Definition at line 149 of file add_kernels_bf16.c.

153{
154 if (!a || !b || n == 0) {
155 return;
156 }
157
158 size_t i = 0;
159
160#if defined(__AVX512F__)
161 __m512 alpha_v = _mm512_set1_ps(alpha);
162 for (; i + 16 <= n; i += 16) {
163 __m512 av = bf16_loadu_cvt_fp32(&a[i]);
164 __m512 bv = bf16_loadu_cvt_fp32(&b[i]);
165 __m512 yv = _mm512_fmadd_ps(bv, alpha_v, av);
166 fp32_cvt_storeu_bf16(&a[i], yv);
167 }
168#endif
169
170 for (; i < n; ++i) {
171 float af = bf16_to_float(a[i]);
172 float bf = bf16_to_float(b[i]);
173 a[i] = float_to_bf16(af + alpha * bf);
174 }
175}

References bf16_to_float(), and float_to_bf16().

◆ add_stream_inplace()

void add_stream_inplace ( float *  a,
const float *  b,
size_t  n 
)

Definition at line 713 of file vision_kernels.c.

716{
717 if (!a || !b || n == 0) {
718 return;
719 }
720
721 for (size_t i = 0; i < n; ++i) {
722 a[i] += b[i];
723 }
724}

◆ add_stream_reorder_2d()

void add_stream_reorder_2d ( float *  main_inout,
float *  aux_scratch,
int  grid_h,
int  grid_w,
int  embed_dim,
int  merge_size 
)

Definition at line 726 of file vision_kernels.c.

732{
733 if (!main_inout || !aux_scratch || grid_h <= 0 || grid_w <= 0 || embed_dim <= 0 || merge_size <= 0) {
734 return;
735 }
736
737 const int num_tokens = grid_h * grid_w;
738 const size_t total_elems = (size_t) num_tokens * (size_t) embed_dim;
739
740 for (size_t i = 0; i < total_elems; ++i) {
741 main_inout[i] += aux_scratch[i];
742 }
743
744 for (int tok = 0; tok < num_tokens; ++tok) {
745 const int src_tok = tile_order_index_2d(tok, grid_h, grid_w, merge_size);
746 const float *src_main = main_inout + (size_t) src_tok * (size_t) embed_dim;
747 float *dst = aux_scratch + (size_t) tok * (size_t) embed_dim;
748 for (int d = 0; d < embed_dim; ++d) {
749 dst[d] = src_main[d];
750 }
751 }
752
753 memcpy(main_inout, aux_scratch, total_elems * sizeof(float));
754}
static int tile_order_index_2d(int linear_idx, int grid_h, int grid_w, int merge_size)

References tile_order_index_2d().

◆ argmax_f32()

int argmax_f32 ( const float *  scores,
int  n 
)

Find index of maximum value.

Parameters
scoresInput scores [n]
nNumber of scores
Returns
Index of maximum value

Definition at line 500 of file topk_kernels.c.

501{
502 if (!scores || n <= 0) {
503 return -1;
504 }
505
506 int max_idx = 0;
507 float max_val = scores[0];
508
509#ifdef __AVX512F__
510 /* AVX-512 vectorized argmax for large arrays */
511 if (n >= 16) {
512 __m512 vmax = _mm512_set1_ps(-FLT_MAX);
513 __m512i vidx = _mm512_setzero_si512();
514 __m512i vcur_max_idx = _mm512_setzero_si512();
515
516 int i = 0;
517 for (; i + 16 <= n; i += 16) {
518 __m512 v = _mm512_loadu_ps(&scores[i]);
519 __m512i cur_idx = _mm512_add_epi32(
520 _mm512_set1_epi32(i),
521 _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15)
522 );
523
524 __mmask16 gt_mask = _mm512_cmp_ps_mask(v, vmax, _CMP_GT_OQ);
525 vmax = _mm512_mask_blend_ps(gt_mask, vmax, v);
526 vcur_max_idx = _mm512_mask_blend_epi32(gt_mask, vcur_max_idx, cur_idx);
527 }
528
529 /* Horizontal reduction */
530 float vals[16];
531 int idxs[16];
532 _mm512_storeu_ps(vals, vmax);
533 _mm512_storeu_si512(idxs, vcur_max_idx);
534
535 max_val = vals[0];
536 max_idx = idxs[0];
537 for (int j = 1; j < 16; j++) {
538 if (vals[j] > max_val) {
539 max_val = vals[j];
540 max_idx = idxs[j];
541 }
542 }
543
544 /* Handle remainder */
545 for (; i < n; i++) {
546 if (scores[i] > max_val) {
547 max_val = scores[i];
548 max_idx = i;
549 }
550 }
551
552 return max_idx;
553 }
554#endif
555
556 /* Scalar fallback */
557 for (int i = 1; i < n; i++) {
558 if (scores[i] > max_val) {
559 max_val = scores[i];
560 max_idx = i;
561 }
562 }
563
564 return max_idx;
565}

Referenced by speculative_verify_greedy_f32().

◆ assistant_layer_scale_forward()

void assistant_layer_scale_forward ( float *  hidden,
const float *  scale,
int  tokens,
int  embed_dim 
)

Definition at line 389 of file gemma4_per_layer_embed.c.

393{
394 if (!hidden || !scale || tokens <= 0 || embed_dim <= 0) {
395 return;
396 }
397
398 const float s = scale[0];
399 const size_t n = (size_t)tokens * (size_t)embed_dim;
400 for (size_t i = 0; i < n; ++i) {
401 hidden[i] *= s;
402 }
403}

◆ attention_backward_causal_head_major()

void attention_backward_causal_head_major ( const float *  d_output,
const float *  q,
const float *  k,
const float *  v,
const float *  attn_weights,
float *  d_q,
float *  d_k,
float *  d_v,
float *  d_scores,
int  num_heads,
int  num_tokens,
int  head_dim,
int  aligned_head_dim,
int  aligned_context_window 
)

Causal attention backward (non-GQA version)

Test:

test_attention_backward.py::TestAttentionBackward::test_backward

test_attention_backward.py::TestAttentionBackward::test_backward_vs_separate

test_parity.py::test_attention_backward_parity

Non-GQA version where num_heads == num_kv_heads. Simpler than GQA, no head broadcasting needed.

After changes: make test && make llamacpp-parity-full

Definition at line 9175 of file attention_kernels.c.

9190{
9192 d_output, q, k, v, attn_weights,
9193 d_q, d_k, d_v, d_scores,
9194 num_heads, num_heads, // num_kv_heads == num_heads
9195 num_tokens, head_dim, aligned_head_dim, aligned_context_window);
9196}
void attention_backward_causal_head_major_gqa(const float *d_output, const float *q, const float *k, const float *v, const float *attn_weights, float *d_q, float *d_k, float *d_v, float *d_scores, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int aligned_context_window)

References attention_backward_causal_head_major_gqa().

◆ attention_backward_causal_head_major_gqa()

void attention_backward_causal_head_major_gqa ( const float *  d_output,
const float *  q,
const float *  k,
const float *  v,
const float *  attn_weights,
float *  d_q,
float *  d_k,
float *  d_v,
float *  d_scores,
int  num_heads,
int  num_kv_heads,
int  num_tokens,
int  head_dim,
int  aligned_head_dim,
int  aligned_context_window 
)

GQA causal attention backward (score-matrix version)

Test:

test_attention_backward.py::TestAttentionBackwardGQA::test_gqa_backward

test_attention_backward.py::TestAttentionBackwardGQA::test_gqa_vs_separate

test_parity.py::test_attention_backward_parity

Computes dQ, dK, dV given dOutput and attention weights. Supports grouped-query attention with head broadcasting.

After changes: make test && make llamacpp-parity-full

Definition at line 9036 of file attention_kernels.c.

9052{
9053 const float scale = 1.0f / sqrtf((float)head_dim);
9054 int T = num_tokens;
9055 int H = num_heads;
9056 int H_kv = num_kv_heads;
9057 int hd = head_dim;
9058 int ad = aligned_head_dim;
9059 int aw = aligned_context_window;
9060
9061 const size_t d_q_elems = (size_t)H * (size_t)T * (size_t)ad;
9062 const size_t kv_elems = (size_t)H_kv * (size_t)T * (size_t)ad;
9063 /* Zero the aligned outputs so padded lanes never leak garbage to downstream GEMMs. */
9064 for (size_t idx = 0; idx < d_q_elems; ++idx) {
9065 d_q[idx] = 0.0f;
9066 }
9067 for (size_t idx = 0; idx < kv_elems; ++idx) {
9068 d_k[idx] = 0.0f;
9069 d_v[idx] = 0.0f;
9070 }
9071
9072 // Process each query head
9073 for (int h = 0; h < H; ++h) {
9074 // Which KV head does this query head use?
9075 int kv_h = (int)((long long)h * (long long)H_kv / (long long)H);
9076
9077 // ----------------------------------------------------------------
9078 // Step 1: d_weights = d_output @ V^T and d_v += weights^T @ d_output
9079 // ----------------------------------------------------------------
9080 // For each query position i, compute d_weights[i, j] for j <= i
9081 // and accumulate d_v[j] contributions
9082
9083 for (int i = 0; i < T; ++i) {
9084 size_t d_out_base = qkv_index(h, i, 0, T, ad);
9085
9086 for (int j = 0; j <= i; ++j) {
9087 size_t v_base = qkv_index(kv_h, j, 0, T, ad);
9088 size_t w_idx = score_index(h, i, j, aw);
9089 float w = attn_weights[w_idx];
9090
9091 // d_weights[h, i, j] = d_output[h, i, :] @ v[kv_h, j, :]^T
9092 float dot = 0.0f;
9093 for (int dd = 0; dd < hd; ++dd) {
9094 dot += d_output[d_out_base + dd] * v[v_base + dd];
9095 }
9096 d_scores[w_idx] = dot;
9097
9098 // d_v[kv_h, j, :] += weights[h, i, j] * d_output[h, i, :]
9099 for (int dd = 0; dd < hd; ++dd) {
9100 d_v[v_base + dd] += w * d_output[d_out_base + dd];
9101 }
9102 }
9103
9104 // Zero out upper triangle of d_scores
9105 for (int j = i + 1; j < T; ++j) {
9106 d_scores[score_index(h, i, j, aw)] = 0.0f;
9107 }
9108 /* Scores scratch uses aligned_context_window, zero the padded columns. */
9109 for (int j = T; j < aw; ++j) {
9110 d_scores[score_index(h, i, j, aw)] = 0.0f;
9111 }
9112 }
9113
9114 // ----------------------------------------------------------------
9115 // Step 2: Backward through softmax (in-place on d_scores for this head)
9116 // ----------------------------------------------------------------
9117 // d_scores = softmax_backward(d_scores, attn_weights)
9118 // Formula: d_score[i,j] = w[i,j] * (d_w[i,j] - sum_k(w[i,k] * d_w[i,k]))
9119
9120 for (int i = 0; i < T; ++i) {
9121 int base = h * aw * aw + i * aw;
9122
9123 // Compute dot product: sum_j w[i,j] * d_w[i,j]
9124 float dot_product = 0.0f;
9125 for (int j = 0; j <= i; ++j) {
9126 float wt = attn_weights[base + j];
9127 float dw = d_scores[base + j];
9128 dot_product += wt * dw;
9129 }
9130
9131 // Apply softmax backward formula
9132 for (int j = 0; j <= i; ++j) {
9133 float wt = attn_weights[base + j];
9134 float dw = d_scores[base + j];
9135 d_scores[base + j] = wt * (dw - dot_product);
9136 }
9137 }
9138
9139 // ----------------------------------------------------------------
9140 // Step 3: d_q = d_scores @ K * scale
9141 // d_k += d_scores^T @ Q * scale
9142 // ----------------------------------------------------------------
9143
9144 for (int i = 0; i < T; ++i) {
9145 size_t d_q_base = qkv_index(h, i, 0, T, ad);
9146 size_t q_base = qkv_index(h, i, 0, T, ad);
9147
9148 // d_q[h, i, :] = sum_j d_scores[h, i, j] * k[kv_h, j, :] * scale
9149 // d_k[kv_h, j, :] += d_scores[h, i, j] * q[h, i, :] * scale
9150 for (int j = 0; j <= i; ++j) {
9151 size_t k_base = qkv_index(kv_h, j, 0, T, ad);
9152 size_t d_k_base = qkv_index(kv_h, j, 0, T, ad);
9153 float ds = d_scores[score_index(h, i, j, aw)] * scale;
9154
9155 for (int dd = 0; dd < hd; ++dd) {
9156 d_q[d_q_base + dd] += ds * k[k_base + dd];
9157 d_k[d_k_base + dd] += ds * q[q_base + dd];
9158 }
9159 }
9160 }
9161 }
9162}
static size_t qkv_index(int h, int t, int d, int num_tokens, int aligned_head_dim)
static size_t score_index(int h, int i, int j, int aligned_context_window)

References qkv_index(), and score_index().

Referenced by attention_backward_causal_head_major(), attention_backward_causal_head_major_gqa_bf16(), and ck_layer_backward_rmsnorm_swiglu().

◆ attention_backward_causal_head_major_gqa_bf16()

void attention_backward_causal_head_major_gqa_bf16 ( const uint16_t *  d_output,
float *  d_x,
const uint16_t *  q,
const uint16_t *  k,
const uint16_t *  v,
const float *  attn_weights,
float *  d_q,
float *  d_k,
float *  d_v,
float *  d_scores,
int  num_heads,
int  num_kv_heads,
int  num_tokens,
int  head_dim,
int  aligned_head_dim,
int  aligned_context_window,
float *  scratch_d_output,
float *  scratch_q,
float *  scratch_k,
float *  scratch_v 
)

BF16 attention backward with caller-provided scratch buffers

Test:
bf16/test_attention_bf16.py::TestAttentionBF16::test_bf16_backward

Accepts BF16 inputs, converts to FP32, runs FP32 backward. Caller provides scratch buffers (no per-call malloc).

After changes: make test

Definition at line 8983 of file attention_kernels.c.

9004{
9005 (void)d_x;
9006 const size_t head_elems = (size_t)num_heads * (size_t)num_tokens * (size_t)aligned_head_dim;
9007 const size_t kv_elems = (size_t)num_kv_heads * (size_t)num_tokens * (size_t)aligned_head_dim;
9008
9009 if (!scratch_d_output || !scratch_q || !scratch_k || !scratch_v) return;
9010
9011 convert_bf16_tensor_to_buf(d_output, scratch_d_output, head_elems);
9012 convert_bf16_tensor_to_buf(q, scratch_q, head_elems);
9013 convert_bf16_tensor_to_buf(k, scratch_k, kv_elems);
9014 convert_bf16_tensor_to_buf(v, scratch_v, kv_elems);
9015
9016 attention_backward_causal_head_major_gqa(scratch_d_output, scratch_q, scratch_k, scratch_v,
9017 attn_weights,
9018 d_q, d_k, d_v, d_scores,
9019 num_heads, num_kv_heads,
9020 num_tokens, head_dim,
9021 aligned_head_dim, aligned_context_window);
9022 /* No free - caller owns scratch buffers */
9023}
static void convert_bf16_tensor_to_buf(const uint16_t *src, float *dst, size_t count)

References attention_backward_causal_head_major_gqa(), and convert_bf16_tensor_to_buf().

◆ attention_flash_decode()

void attention_flash_decode ( float *  out,
const float *  q,
const float *  k,
const float *  v,
int  T_q,
int  T_k,
int  H,
int  D_h,
float  scale 
)

Main flash attention function with SIMD dispatch.

Parameters
outOutput [T_q, H, D_h]
qQuery [T_q, H, D_h]
kKey [T_k, H, D_h]
vValue [T_k, H, D_h]
T_qNumber of query tokens (1 for decode)
T_kNumber of key/value tokens (context length)
HNumber of heads
D_hHead dimension
scale1/sqrt(D_h)

Definition at line 696 of file attention_flash_true.c.

706{
707 if (!out || !q || !k || !v) {
708 return;
709 }
710 if (T_q <= 0 || T_k <= 0 || H <= 0 || D_h <= 0) {
711 return;
712 }
713
714 // Dispatch based on CPU features
715#if defined(__AVX512F__)
716 attention_flash_decode_avx512(out, q, k, v, T_q, T_k, H, D_h, scale);
717#elif defined(__AVX__) && !defined(__AVX512F__)
718 attention_flash_decode_avx(out, q, k, v, T_q, T_k, H, D_h, scale);
719#else
720 attention_flash_decode_scalar(out, q, k, v, T_q, T_k, H, D_h, scale);
721#endif
722}
static void attention_flash_decode_scalar(float *out, const float *q, const float *k, const float *v, int T_q, int T_k, int H, int D_h, float scale)
Scalar flash-style attention (online softmax)

References attention_flash_decode_scalar().

Referenced by attention_forward_chunk_head_major_gqa_flash_gemma4(), attention_forward_decode_head_major_gqa_flash(), attention_forward_decode_head_major_gqa_flash_f16cache(), attention_forward_decode_head_major_gqa_flash_gemma4(), ck_attention_flash_decode_wrapper(), mega_fused_attention_prefill(), and mega_fused_attention_prefill_q8_0().

◆ attention_forward_causal_head_major()

void attention_forward_causal_head_major ( const float *  q,
const float *  k,
const float *  v,
float *  scores,
float *  output,
int  num_heads,
int  num_tokens,
int  head_dim,
int  aligned_head_dim,
int  aligned_context_window 
)

Causal attention forward (score-matrix version)

Test:

test_attention.py::TestAttentionForward::test_causal_forward

test_attention.py::TestAttentionForward::test_gqa_broadcast

test_attention.py::TestAttentionForward::test_exact_vs_fast

test_parity.py::test_attention_parity

Computes softmax(Q @ K^T / sqrt(d)) @ V with causal masking. Uses O(N^2) memory for scores matrix.

After changes: make test && make llamacpp-parity-full

Definition at line 1281 of file attention_kernels.c.

1291{
1292 const float scale = 1.0f / sqrtf((float)head_dim);
1293
1294 // Phase 1: compute scaled dot-product scores Q·K^T / sqrt(d_k),
1295 // lower triangle only (j <= i).
1296 for (int h = 0; h < num_heads; ++h) {
1297 for (int i = 0; i < num_tokens; ++i) {
1298 for (int j = 0; j <= i; ++j) {
1299 float dot = 0.0f;
1300 size_t base_q = qkv_index(h, i, 0, num_tokens, aligned_head_dim);
1301 size_t base_k = qkv_index(h, j, 0, num_tokens, aligned_head_dim);
1302
1303 for (int d = 0; d < head_dim; ++d) {
1304 dot += q[base_q + d] * k[base_k + d];
1305 }
1306
1307 scores[score_index(h, i, j, aligned_context_window)] = dot * scale;
1308 }
1309
1310 // Ensure upper triangle is zeroed so there are no stale values
1311 // before the softmax kernel runs.
1312 for (int j = i + 1; j < num_tokens; ++j) {
1313 scores[score_index(h, i, j, aligned_context_window)] = 0.0f;
1314 }
1315 }
1316 }
1317
1318 // Phase 2: apply causal row-wise softmax in-place over j <= i.
1320 num_heads,
1321 num_tokens,
1322 aligned_context_window);
1323
1324 // Phase 3: attention weights · V.
1325 for (int h = 0; h < num_heads; ++h) {
1326 for (int i = 0; i < num_tokens; ++i) {
1327 size_t out_base = qkv_index(h, i, 0, num_tokens, aligned_head_dim);
1328
1329 // Zero the full aligned head slice so padded dims stay clean.
1330 for (int d = 0; d < aligned_head_dim; ++d) {
1331 output[out_base + d] = 0.0f;
1332 }
1333
1334 // Weighted sum over causal positions.
1335 for (int j = 0; j <= i; ++j) {
1336 float w = scores[score_index(h, i, j, aligned_context_window)];
1337 size_t v_base = qkv_index(h, j, 0, num_tokens, aligned_head_dim);
1338
1339 for (int d = 0; d < head_dim; ++d) {
1340 output[out_base + d] += w * v[v_base + d];
1341 }
1342 }
1343 }
1344 }
1345}
void causal_softmax_head_major(float *scores, int num_heads, int num_tokens, int aligned_context_window)

References causal_softmax_head_major(), qkv_index(), and score_index().

◆ attention_forward_causal_head_major_exact()

void attention_forward_causal_head_major_exact ( const float *  q,
const float *  k,
const float *  v,
float *  scores,
float *  output,
int  num_heads,
int  num_tokens,
int  head_dim,
int  aligned_head_dim,
int  aligned_context_window 
)

Causal attention forward (exact version using stdlib expf)

Test:

test_attention.py::TestAttentionForward::test_exact_single

test_attention.py::TestAttentionForward::test_exact_vs_fast

Uses standard library expf for numerical accuracy reference. Slower but provides maximum accuracy.

After changes: make test

Definition at line 1357 of file attention_kernels.c.

1367{
1368 const float scale = 1.0f / sqrtf((float)head_dim);
1369
1370 // Phase 1: compute scaled dot-product scores Q·K^T / sqrt(d_k),
1371 // lower triangle only (j <= i).
1372 for (int h = 0; h < num_heads; ++h) {
1373 for (int i = 0; i < num_tokens; ++i) {
1374 for (int j = 0; j <= i; ++j) {
1375 float dot = 0.0f;
1376 size_t base_q = qkv_index(h, i, 0, num_tokens, aligned_head_dim);
1377 size_t base_k = qkv_index(h, j, 0, num_tokens, aligned_head_dim);
1378
1379 for (int d = 0; d < head_dim; ++d) {
1380 dot += q[base_q + d] * k[base_k + d];
1381 }
1382
1383 scores[score_index(h, i, j, aligned_context_window)] = dot * scale;
1384 }
1385
1386 // Ensure upper triangle is zeroed so there are no stale values
1387 // before the softmax kernel runs.
1388 for (int j = i + 1; j < num_tokens; ++j) {
1389 scores[score_index(h, i, j, aligned_context_window)] = 0.0f;
1390 }
1391 }
1392 }
1393
1394 // Phase 2: apply causal row-wise softmax using exact expf.
1396 num_heads,
1397 num_tokens,
1398 aligned_context_window);
1399
1400 // Phase 3: attention weights · V.
1401 for (int h = 0; h < num_heads; ++h) {
1402 for (int i = 0; i < num_tokens; ++i) {
1403 size_t out_base = qkv_index(h, i, 0, num_tokens, aligned_head_dim);
1404
1405 // Zero the full aligned head slice so padded dims stay clean.
1406 for (int d = 0; d < aligned_head_dim; ++d) {
1407 output[out_base + d] = 0.0f;
1408 }
1409
1410 // Weighted sum over causal positions.
1411 for (int j = 0; j <= i; ++j) {
1412 float w = scores[score_index(h, i, j, aligned_context_window)];
1413 size_t v_base = qkv_index(h, j, 0, num_tokens, aligned_head_dim);
1414
1415 for (int d = 0; d < head_dim; ++d) {
1416 output[out_base + d] += w * v[v_base + d];
1417 }
1418 }
1419 }
1420 }
1421}
void causal_softmax_head_major_exact(float *scores, int num_heads, int num_tokens, int aligned_context_window)

References causal_softmax_head_major_exact(), qkv_index(), and score_index().

◆ attention_forward_causal_head_major_gqa()

void attention_forward_causal_head_major_gqa ( const float *  q,
const float *  k,
const float *  v,
float *  scores,
float *  output,
int  num_heads,
int  num_kv_heads,
int  num_tokens,
int  head_dim,
int  aligned_head_dim,
int  aligned_context_window 
)

GQA causal attention forward (score-matrix version)

Test:

test_attention.py::TestAttentionForward::test_gqa_forward

test_attention.py::TestAttentionForward::test_gqa_broadcast

test_attention_backward.py::TestAttentionBackwardGQA::test_gqa_backward

test_parity.py::test_attention_gqa_parity

Grouped-query attention: Q has num_heads, K/V have num_kv_heads. Each query head maps to a KV head via ratio.

After changes: make test && make llamacpp-parity-full

Definition at line 1435 of file attention_kernels.c.

1446{
1447 const float scale = 1.0f / sqrtf((float)head_dim);
1448
1449 for (int h = 0; h < num_heads; ++h) {
1450 int kv_head = (int)((long long)h * (long long)num_kv_heads / (long long)num_heads);
1451 for (int i = 0; i < num_tokens; ++i) {
1452 for (int j = 0; j <= i; ++j) {
1453 float dot = 0.0f;
1454 size_t base_q = qkv_index(h, i, 0, num_tokens, aligned_head_dim);
1455 size_t base_k = qkv_index(kv_head, j, 0, num_tokens, aligned_head_dim);
1456
1457 for (int d = 0; d < head_dim; ++d) {
1458 dot += q[base_q + d] * k[base_k + d];
1459 }
1460
1461 scores[score_index(h, i, j, aligned_context_window)] = dot * scale;
1462 }
1463
1464 for (int j = i + 1; j < num_tokens; ++j) {
1465 scores[score_index(h, i, j, aligned_context_window)] = 0.0f;
1466 }
1467 }
1468 }
1469
1471 num_heads,
1472 num_tokens,
1473 aligned_context_window);
1474
1475 for (int h = 0; h < num_heads; ++h) {
1476 int kv_head = (int)((long long)h * (long long)num_kv_heads / (long long)num_heads);
1477 for (int i = 0; i < num_tokens; ++i) {
1478 size_t out_base = qkv_index(h, i, 0, num_tokens, aligned_head_dim);
1479 for (int d = 0; d < aligned_head_dim; ++d) {
1480 output[out_base + d] = 0.0f;
1481 }
1482
1483 for (int j = 0; j <= i; ++j) {
1484 float w = scores[score_index(h, i, j, aligned_context_window)];
1485 size_t v_base = qkv_index(kv_head, j, 0, num_tokens, aligned_head_dim);
1486
1487 for (int d = 0; d < head_dim; ++d) {
1488 output[out_base + d] += w * v[v_base + d];
1489 }
1490 }
1491 }
1492 }
1493}

References causal_softmax_head_major(), qkv_index(), and score_index().

Referenced by ck_layer_forward_rmsnorm_swiglu(), ck_layer_forward_rmsnorm_swiglu_q4_k(), ck_layer_forward_rmsnorm_swiglu_quant(), and ck_layer_forward_rmsnorm_swiglu_ref().

◆ attention_forward_causal_head_major_gqa_bf16()

void attention_forward_causal_head_major_gqa_bf16 ( const uint16_t *  q,
const uint16_t *  k,
const uint16_t *  v,
float *  scores,
float *  output,
int  num_heads,
int  num_kv_heads,
int  num_tokens,
int  head_dim,
int  aligned_head_dim,
int  aligned_context_window,
float *  scratch_q,
float *  scratch_k,
float *  scratch_v 
)

BF16 GQA causal attention forward

Test:

bf16/test_attention_bf16.py::TestAttentionBF16::test_bf16_forward

bf16/test_attention_bf16.py::TestAttentionBF16::test_bf16_gqa

bf16/test_attention_bf16.py::TestAttentionBF16::test_bf16_flash

Accepts BF16 inputs, converts to FP32, uses exact softmax. Caller provides scratch buffers (no per-call malloc).

After changes: make test

Definition at line 1577 of file attention_kernels.c.

1591{
1592 const size_t q_elems = (size_t)num_heads * (size_t)num_tokens * (size_t)aligned_head_dim;
1593 const size_t kv_elems = (size_t)num_kv_heads * (size_t)num_tokens * (size_t)aligned_head_dim;
1594
1595 if (!scratch_q || !scratch_k || !scratch_v) return;
1596
1597 convert_bf16_tensor_to_buf(q, scratch_q, q_elems);
1598 convert_bf16_tensor_to_buf(k, scratch_k, kv_elems);
1599 convert_bf16_tensor_to_buf(v, scratch_v, kv_elems);
1600
1601 // Use exact version to avoid fast exp approximation error accumulating
1602 // with BF16 precision loss.
1603 attention_forward_causal_head_major_gqa_exact(scratch_q, scratch_k, scratch_v,
1604 scores, output,
1605 num_heads, num_kv_heads,
1606 num_tokens, head_dim,
1607 aligned_head_dim, aligned_context_window);
1608 /* No free - caller owns scratch buffers */
1609}
void attention_forward_causal_head_major_gqa_exact(const float *q, const float *k, const float *v, float *scores, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int aligned_context_window)

References attention_forward_causal_head_major_gqa_exact(), and convert_bf16_tensor_to_buf().

◆ attention_forward_causal_head_major_gqa_exact()

void attention_forward_causal_head_major_gqa_exact ( const float *  q,
const float *  k,
const float *  v,
float *  scores,
float *  output,
int  num_heads,
int  num_kv_heads,
int  num_tokens,
int  head_dim,
int  aligned_head_dim,
int  aligned_context_window 
)

GQA causal attention forward (exact version using stdlib expf)

Test:

test_attention.py::TestAttentionForward::test_gqa_exact

bf16/test_attention_bf16.py::TestAttentionBF16::test_bf16_gqa

Uses standard library expf for numerical accuracy reference. Used by BF16 wrapper to avoid approximation error accumulation.

After changes: make test

Definition at line 1505 of file attention_kernels.c.

1516{
1517 const float scale = 1.0f / sqrtf((float)head_dim);
1518
1519 for (int h = 0; h < num_heads; ++h) {
1520 int kv_head = (int)((long long)h * (long long)num_kv_heads / (long long)num_heads);
1521 for (int i = 0; i < num_tokens; ++i) {
1522 for (int j = 0; j <= i; ++j) {
1523 float dot = 0.0f;
1524 size_t base_q = qkv_index(h, i, 0, num_tokens, aligned_head_dim);
1525 size_t base_k = qkv_index(kv_head, j, 0, num_tokens, aligned_head_dim);
1526
1527 for (int d = 0; d < head_dim; ++d) {
1528 dot += q[base_q + d] * k[base_k + d];
1529 }
1530
1531 scores[score_index(h, i, j, aligned_context_window)] = dot * scale;
1532 }
1533
1534 for (int j = i + 1; j < num_tokens; ++j) {
1535 scores[score_index(h, i, j, aligned_context_window)] = 0.0f;
1536 }
1537 }
1538 }
1539
1540 // Use exact softmax with standard library expf
1542 num_heads,
1543 num_tokens,
1544 aligned_context_window);
1545
1546 for (int h = 0; h < num_heads; ++h) {
1547 int kv_head = (int)((long long)h * (long long)num_kv_heads / (long long)num_heads);
1548 for (int i = 0; i < num_tokens; ++i) {
1549 size_t out_base = qkv_index(h, i, 0, num_tokens, aligned_head_dim);
1550 for (int d = 0; d < aligned_head_dim; ++d) {
1551 output[out_base + d] = 0.0f;
1552 }
1553
1554 for (int j = 0; j <= i; ++j) {
1555 float w = scores[score_index(h, i, j, aligned_context_window)];
1556 size_t v_base = qkv_index(kv_head, j, 0, num_tokens, aligned_head_dim);
1557
1558 for (int d = 0; d < head_dim; ++d) {
1559 output[out_base + d] += w * v[v_base + d];
1560 }
1561 }
1562 }
1563 }
1564}

References causal_softmax_head_major_exact(), qkv_index(), and score_index().

Referenced by attention_forward_causal_head_major_gqa_bf16(), ck_layer_forward_rmsnorm_swiglu(), and ck_layer_forward_rmsnorm_swiglu_ref().

◆ attention_forward_causal_head_major_gqa_flash()

void attention_forward_causal_head_major_gqa_flash ( const float *  q,
const float *  k,
const float *  v,
float *  output,
int  num_heads,
int  num_kv_heads,
int  num_tokens,
int  head_dim,
int  aligned_head_dim 
)

Definition at line 4370 of file attention_kernels.c.

4379{
4381 num_heads, num_kv_heads,
4382 num_tokens, head_dim,
4383 aligned_head_dim,
4384 /*kv_stride_tokens=*/num_tokens,
4385 /*causal=*/1,
4386 /*round_full_kv_fp16=*/0,
4387 /*output_token_major=*/0,
4388 1.0f / sqrtf((float)head_dim));
4389}
static void attention_forward_head_major_gqa_flash_impl(const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int kv_stride_tokens, int causal, int round_full_kv_fp16, int output_token_major, float scale)

References attention_forward_head_major_gqa_flash_impl().

Referenced by ck_layer_forward_rmsnorm_swiglu(), ck_layer_forward_rmsnorm_swiglu_q4_k(), ck_layer_forward_rmsnorm_swiglu_quant(), ck_layer_forward_rmsnorm_swiglu_ref(), qwen2_0_5b_decode_layer_0_prefill(), qwen2_0_5b_decode_layer_0_prefill(), qwen2_0_5b_decode_layer_10_prefill(), qwen2_0_5b_decode_layer_10_prefill(), qwen2_0_5b_decode_layer_11_prefill(), qwen2_0_5b_decode_layer_11_prefill(), qwen2_0_5b_decode_layer_12_prefill(), qwen2_0_5b_decode_layer_12_prefill(), qwen2_0_5b_decode_layer_13_prefill(), qwen2_0_5b_decode_layer_13_prefill(), qwen2_0_5b_decode_layer_14_prefill(), qwen2_0_5b_decode_layer_14_prefill(), qwen2_0_5b_decode_layer_15_prefill(), qwen2_0_5b_decode_layer_15_prefill(), qwen2_0_5b_decode_layer_16_prefill(), qwen2_0_5b_decode_layer_16_prefill(), qwen2_0_5b_decode_layer_17_prefill(), qwen2_0_5b_decode_layer_17_prefill(), qwen2_0_5b_decode_layer_18_prefill(), qwen2_0_5b_decode_layer_18_prefill(), qwen2_0_5b_decode_layer_19_prefill(), qwen2_0_5b_decode_layer_19_prefill(), qwen2_0_5b_decode_layer_1_prefill(), qwen2_0_5b_decode_layer_1_prefill(), qwen2_0_5b_decode_layer_20_prefill(), qwen2_0_5b_decode_layer_20_prefill(), qwen2_0_5b_decode_layer_21_prefill(), qwen2_0_5b_decode_layer_21_prefill(), qwen2_0_5b_decode_layer_22_prefill(), qwen2_0_5b_decode_layer_22_prefill(), qwen2_0_5b_decode_layer_23_prefill(), qwen2_0_5b_decode_layer_23_prefill(), qwen2_0_5b_decode_layer_2_prefill(), qwen2_0_5b_decode_layer_2_prefill(), qwen2_0_5b_decode_layer_3_prefill(), qwen2_0_5b_decode_layer_3_prefill(), qwen2_0_5b_decode_layer_4_prefill(), qwen2_0_5b_decode_layer_4_prefill(), qwen2_0_5b_decode_layer_5_prefill(), qwen2_0_5b_decode_layer_5_prefill(), qwen2_0_5b_decode_layer_6_prefill(), qwen2_0_5b_decode_layer_6_prefill(), qwen2_0_5b_decode_layer_7_prefill(), qwen2_0_5b_decode_layer_7_prefill(), qwen2_0_5b_decode_layer_8_prefill(), qwen2_0_5b_decode_layer_8_prefill(), qwen2_0_5b_decode_layer_9_prefill(), and qwen2_0_5b_decode_layer_9_prefill().

◆ attention_forward_causal_head_major_gqa_flash_strided()

void attention_forward_causal_head_major_gqa_flash_strided ( const float *  q,
const float *  k,
const float *  v,
float *  output,
int  num_heads,
int  num_kv_heads,
int  num_tokens,
int  head_dim,
int  aligned_head_dim,
int  kv_stride_tokens 
)

Flash attention forward with custom KV stride (for KV cache)

Test:

test_flash_attention.py::TestFlashAttention::test_flash_strided

test_kv_cache_attention.py::TestKVCacheAttention::test_flash_attention

Variant with configurable kv_stride_tokens for KV cache layouts where K/V may not be contiguous in memory.

After changes: make test

Definition at line 4422 of file attention_kernels.c.

4432{
4434 num_heads, num_kv_heads,
4435 num_tokens, head_dim,
4436 aligned_head_dim,
4437 kv_stride_tokens,
4438 /*causal=*/1,
4439 /*round_full_kv_fp16=*/0,
4440 /*output_token_major=*/0,
4441 1.0f / sqrtf((float)head_dim));
4442}

References attention_forward_head_major_gqa_flash_impl().

Referenced by attention_forward_causal_head_major_gqa_flash_strided_sliding(), mega_fused_attention_prefill(), mega_fused_attention_prefill_q8_0(), model_layer_0_prefill(), model_layer_0_prefill(), model_layer_0_prefill(), model_layer_0_prefill(), model_layer_10_prefill(), model_layer_10_prefill(), model_layer_10_prefill(), model_layer_10_prefill(), model_layer_11_prefill(), model_layer_11_prefill(), model_layer_11_prefill(), model_layer_11_prefill(), model_layer_12_prefill(), model_layer_12_prefill(), model_layer_12_prefill(), model_layer_12_prefill(), model_layer_13_prefill(), model_layer_13_prefill(), model_layer_13_prefill(), model_layer_13_prefill(), model_layer_14_prefill(), model_layer_14_prefill(), model_layer_14_prefill(), model_layer_14_prefill(), model_layer_15_prefill(), model_layer_15_prefill(), model_layer_15_prefill(), model_layer_15_prefill(), model_layer_16_prefill(), model_layer_16_prefill(), model_layer_16_prefill(), model_layer_16_prefill(), model_layer_17_prefill(), model_layer_17_prefill(), model_layer_17_prefill(), model_layer_17_prefill(), model_layer_18_prefill(), model_layer_18_prefill(), model_layer_18_prefill(), model_layer_18_prefill(), model_layer_19_prefill(), model_layer_19_prefill(), model_layer_19_prefill(), model_layer_19_prefill(), model_layer_1_prefill(), model_layer_1_prefill(), model_layer_1_prefill(), model_layer_1_prefill(), model_layer_20_prefill(), model_layer_20_prefill(), model_layer_20_prefill(), model_layer_20_prefill(), model_layer_21_prefill(), model_layer_21_prefill(), model_layer_21_prefill(), model_layer_21_prefill(), model_layer_22_prefill(), model_layer_22_prefill(), model_layer_22_prefill(), model_layer_22_prefill(), model_layer_23_prefill(), model_layer_23_prefill(), model_layer_23_prefill(), model_layer_23_prefill(), model_layer_2_prefill(), model_layer_2_prefill(), model_layer_2_prefill(), model_layer_2_prefill(), model_layer_3_prefill(), model_layer_3_prefill(), model_layer_3_prefill(), model_layer_3_prefill(), model_layer_4_prefill(), model_layer_4_prefill(), model_layer_4_prefill(), model_layer_4_prefill(), model_layer_5_prefill(), model_layer_5_prefill(), model_layer_5_prefill(), model_layer_5_prefill(), model_layer_6_prefill(), model_layer_6_prefill(), model_layer_6_prefill(), model_layer_6_prefill(), model_layer_7_prefill(), model_layer_7_prefill(), model_layer_7_prefill(), model_layer_7_prefill(), model_layer_8_prefill(), model_layer_8_prefill(), model_layer_8_prefill(), model_layer_8_prefill(), model_layer_9_prefill(), model_layer_9_prefill(), model_layer_9_prefill(), model_layer_9_prefill(), qwen2_0_5b_decode_layer_0_prefill(), qwen2_0_5b_decode_layer_0_prefill(), qwen2_0_5b_decode_layer_10_prefill(), qwen2_0_5b_decode_layer_10_prefill(), qwen2_0_5b_decode_layer_11_prefill(), qwen2_0_5b_decode_layer_11_prefill(), qwen2_0_5b_decode_layer_12_prefill(), qwen2_0_5b_decode_layer_12_prefill(), qwen2_0_5b_decode_layer_13_prefill(), qwen2_0_5b_decode_layer_13_prefill(), qwen2_0_5b_decode_layer_14_prefill(), qwen2_0_5b_decode_layer_14_prefill(), qwen2_0_5b_decode_layer_15_prefill(), qwen2_0_5b_decode_layer_15_prefill(), qwen2_0_5b_decode_layer_16_prefill(), qwen2_0_5b_decode_layer_16_prefill(), qwen2_0_5b_decode_layer_17_prefill(), qwen2_0_5b_decode_layer_17_prefill(), qwen2_0_5b_decode_layer_18_prefill(), qwen2_0_5b_decode_layer_18_prefill(), qwen2_0_5b_decode_layer_19_prefill(), qwen2_0_5b_decode_layer_19_prefill(), qwen2_0_5b_decode_layer_1_prefill(), qwen2_0_5b_decode_layer_1_prefill(), qwen2_0_5b_decode_layer_20_prefill(), qwen2_0_5b_decode_layer_20_prefill(), qwen2_0_5b_decode_layer_21_prefill(), qwen2_0_5b_decode_layer_21_prefill(), qwen2_0_5b_decode_layer_22_prefill(), qwen2_0_5b_decode_layer_22_prefill(), qwen2_0_5b_decode_layer_23_prefill(), qwen2_0_5b_decode_layer_23_prefill(), qwen2_0_5b_decode_layer_2_prefill(), qwen2_0_5b_decode_layer_2_prefill(), qwen2_0_5b_decode_layer_3_prefill(), qwen2_0_5b_decode_layer_3_prefill(), qwen2_0_5b_decode_layer_4_prefill(), qwen2_0_5b_decode_layer_4_prefill(), qwen2_0_5b_decode_layer_5_prefill(), qwen2_0_5b_decode_layer_5_prefill(), qwen2_0_5b_decode_layer_6_prefill(), qwen2_0_5b_decode_layer_6_prefill(), qwen2_0_5b_decode_layer_7_prefill(), qwen2_0_5b_decode_layer_7_prefill(), qwen2_0_5b_decode_layer_8_prefill(), qwen2_0_5b_decode_layer_8_prefill(), qwen2_0_5b_decode_layer_9_prefill(), and qwen2_0_5b_decode_layer_9_prefill().

◆ attention_forward_causal_head_major_gqa_flash_strided_f16kv()

void attention_forward_causal_head_major_gqa_flash_strided_f16kv ( const float *  q,
const float *  k,
const float *  v,
float *  output,
int  num_heads,
int  num_kv_heads,
int  num_tokens,
int  head_dim,
int  aligned_head_dim,
int  kv_stride_tokens 
)

Definition at line 5343 of file attention_kernels.c.

5347{
5348 size_t elements = 0;
5349 if (num_kv_heads > 0 && kv_stride_tokens > 0 && aligned_head_dim > 0 &&
5350 (size_t)num_kv_heads <= SIZE_MAX / (size_t)kv_stride_tokens) {
5351 const size_t rows = (size_t)num_kv_heads * (size_t)kv_stride_tokens;
5352 if (rows <= SIZE_MAX / (size_t)aligned_head_dim) {
5353 elements = rows * (size_t)aligned_head_dim;
5354 }
5355 }
5356 float *workspace = elements > 0 && elements <= SIZE_MAX / (2 * sizeof(float))
5357 ? (float *)malloc(2 * elements * sizeof(float))
5358 : NULL;
5359 if (!workspace) {
5361 q, k, v, output, num_heads, num_kv_heads, num_tokens,
5362 head_dim, aligned_head_dim, kv_stride_tokens);
5363 return;
5364 }
5366 q, k, v, output, num_heads, num_kv_heads, num_tokens, head_dim,
5367 aligned_head_dim, kv_stride_tokens, workspace,
5368 2 * elements * sizeof(float));
5369 free(workspace);
5370}
void attention_forward_causal_head_major_gqa_flash_strided_f16kv_workspace(const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int kv_stride_tokens, float *rounded_kv, size_t rounded_kv_bytes)
void attention_forward_causal_head_major_gqa_flash_strided_f16kv_serial(const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int kv_stride_tokens)

References attention_forward_causal_head_major_gqa_flash_strided_f16kv_serial(), and attention_forward_causal_head_major_gqa_flash_strided_f16kv_workspace().

◆ attention_forward_causal_head_major_gqa_flash_strided_f16kv_workspace()

void attention_forward_causal_head_major_gqa_flash_strided_f16kv_workspace ( const float *  q,
const float *  k,
const float *  v,
float *  output,
int  num_heads,
int  num_kv_heads,
int  num_tokens,
int  head_dim,
int  aligned_head_dim,
int  kv_stride_tokens,
float *  rounded_kv,
size_t  rounded_kv_bytes 
)

Definition at line 5303 of file attention_kernels.c.

5308{
5309 if (!q || !k || !v || !output || num_heads <= 0 || num_kv_heads <= 0 ||
5310 num_tokens <= 0 || kv_stride_tokens < num_tokens) {
5311 return;
5312 }
5313 size_t elements = 0;
5314 if ((size_t)num_kv_heads <= SIZE_MAX / (size_t)kv_stride_tokens) {
5315 const size_t rows = (size_t)num_kv_heads * (size_t)kv_stride_tokens;
5316 if (rows <= SIZE_MAX / (size_t)aligned_head_dim) {
5317 elements = rows * (size_t)aligned_head_dim;
5318 }
5319 }
5320 if (elements == 0 || elements > SIZE_MAX / (2 * sizeof(float)) ||
5321 !rounded_kv || rounded_kv_bytes < 2 * elements * sizeof(float)) {
5322 fprintf(stderr,
5323 "HARD KERNEL CONTRACT FAULT: FP16-KV attention workspace is too small\n");
5324 abort();
5325 }
5326 ck_round_fp16_buffer(k, rounded_kv, elements);
5327 ck_round_fp16_buffer(v, rounded_kv + elements, elements);
5328 ck_attention_causal_f16kv_args_t args = {
5329 q, rounded_kv, rounded_kv + elements, output,
5330 num_heads, num_kv_heads, num_tokens,
5331 head_dim, aligned_head_dim, kv_stride_tokens, 1,
5332 };
5333 ck_threadpool_t *pool = ck_threadpool_global();
5334 const int workers = pool ? ck_threadpool_n_threads(pool) : 1;
5335 const int active = workers < num_heads ? workers : num_heads;
5336 if (active > 1) {
5338 } else {
5339 ck_attention_causal_f16kv_work(0, 1, &args);
5340 }
5341}
static void ck_round_fp16_buffer(const float *src, float *dst, size_t count)
static void ck_attention_causal_f16kv_work(int ith, int nth, void *opaque)

References ck_attention_causal_f16kv_work(), ck_round_fp16_buffer(), ck_threadpool_dispatch_n(), ck_threadpool_global(), and ck_threadpool_n_threads().

Referenced by attention_forward_causal_head_major_gqa_flash_strided_f16kv().

◆ attention_forward_causal_head_major_gqa_flash_strided_gemma4()

void attention_forward_causal_head_major_gqa_flash_strided_gemma4 ( const float *  q,
const float *  k,
const float *  v,
float *  output,
int  num_heads,
int  num_kv_heads,
int  num_tokens,
int  head_dim,
int  aligned_head_dim,
int  kv_stride_tokens 
)

Definition at line 5024 of file attention_kernels.c.

5034{
5035 (void)head_dim;
5037 num_heads, num_kv_heads,
5038 num_tokens, head_dim,
5039 aligned_head_dim,
5040 kv_stride_tokens,
5041 /*causal=*/1,
5042 /*round_full_kv_fp16=*/0,
5043 /*output_token_major=*/0,
5044 1.0f);
5045}

References attention_forward_head_major_gqa_flash_impl().

Referenced by attention_forward_causal_head_major_gqa_flash_strided_sliding_gemma4_impl(), and attention_forward_causal_head_major_shared_kv_gemma4().

◆ attention_forward_causal_head_major_gqa_flash_strided_gemma4_token_output()

void attention_forward_causal_head_major_gqa_flash_strided_gemma4_token_output ( const float *  q,
const float *  k,
const float *  v,
float *  output,
int  num_heads,
int  num_kv_heads,
int  num_tokens,
int  head_dim,
int  aligned_head_dim,
int  kv_stride_tokens 
)

Definition at line 5047 of file attention_kernels.c.

5058{
5060 num_heads, num_kv_heads,
5061 num_tokens, head_dim,
5062 aligned_head_dim,
5063 kv_stride_tokens,
5064 /*causal=*/1,
5065 /*round_full_kv_fp16=*/0,
5066 /*output_token_major=*/1,
5067 1.0f);
5068}

References attention_forward_head_major_gqa_flash_impl().

Referenced by attention_forward_causal_head_major_gqa_flash_strided_sliding_gemma4_impl().

◆ attention_forward_causal_head_major_gqa_flash_strided_sliding()

void attention_forward_causal_head_major_gqa_flash_strided_sliding ( const float *  q,
const float *  k,
const float *  v,
float *  output,
int  num_heads,
int  num_kv_heads,
int  num_tokens,
int  head_dim,
int  aligned_head_dim,
int  kv_stride_tokens,
int  sliding_window 
)

Flash attention forward with sliding window (prefill)

Test:
test_attention.py::TestAttentionForward::test_sliding_window_prefill

Sliding-window attention for prefill: each token attends to the last W tokens. When sliding_window <= 0, behaves like regular causal attention.

After changes: make test

Definition at line 566 of file attention_kernels_sliding.c.

578{
579 if (!q || !k || !v || !output) {
580 return;
581 }
582 if (num_heads <= 0 || num_kv_heads <= 0 || num_tokens <= 0) {
583 return;
584 }
585 if (kv_stride_tokens < num_tokens) {
586 return;
587 }
588
589 /* Debug escape hatch:
590 * For Gemma bring-up, force the proven non-sliding flash kernel to isolate
591 * whether divergence is caused by sliding-window implementation details.
592 */
593 if (getenv("CK_FORCE_NONSLIDING_ATTN")) {
595 q, k, v, output, num_heads, num_kv_heads, num_tokens,
596 head_dim, aligned_head_dim, kv_stride_tokens
597 );
598 return;
599 }
600
601 const float scale = 1.0f / sqrtf((float)head_dim);
602 const int T = num_tokens;
603 const size_t kv_head_stride = (size_t)kv_stride_tokens * (size_t)aligned_head_dim;
604
605 const int total_jobs = num_heads * T;
606 ck_threadpool_t *pool = ck_threadpool_global();
607 const int active = ck_sliding_attention_pick_threads(pool, total_jobs, T, head_dim);
608 if (pool && active > 1) {
609 ck_sliding_attention_args_t args = {
610 .q = q,
611 .k = k,
612 .v = v,
613 .output = output,
614 .num_heads = num_heads,
615 .num_kv_heads = num_kv_heads,
616 .num_tokens = T,
617 .head_dim = head_dim,
618 .aligned_head_dim = aligned_head_dim,
619 .kv_stride_tokens = kv_stride_tokens,
620 .sliding_window = sliding_window,
621 .output_token_major = 0,
622 .scale = scale,
623 };
625 return;
626 }
627
628#if defined(__AVX512F__)
629 #define SLIDING_FLASH_IMPL attention_flash_query_sliding_avx512
630#elif defined(__AVX2__)
631 #define SLIDING_FLASH_IMPL attention_flash_query_sliding_avx2
632#elif defined(__AVX__)
633 #define SLIDING_FLASH_IMPL attention_flash_query_sliding_avx
634#else
635 #define SLIDING_FLASH_IMPL attention_flash_query_sliding
636#endif
637
638 for (int h = 0; h < num_heads; ++h) {
639 int kv_head = (int)((long long)h * (long long)num_kv_heads / (long long)num_heads);
640 const float *k_head = k + (size_t)kv_head * kv_head_stride;
641 const float *v_head = v + (size_t)kv_head * kv_head_stride;
642
643 for (int i = 0; i < T; ++i) {
644 const float *q_vec = q + qkv_index(h, i, 0, T, aligned_head_dim);
645 float *out_vec = output + attention_output_index(
646 h, i, num_heads, T, aligned_head_dim, 0);
647 SLIDING_FLASH_IMPL(q_vec, k_head, v_head,
648 /*query_pos=*/i,
649 /*kv_tokens=*/T,
650 head_dim, aligned_head_dim,
651 scale, out_vec,
652 sliding_window);
653 }
654 }
655
656#undef SLIDING_FLASH_IMPL
657}
static size_t qkv_index(int h, int t, int d, int num_tokens, int aligned_head_dim)
static int ck_sliding_attention_pick_threads(ck_threadpool_t *pool, int total_jobs, int num_tokens, int head_dim)
#define SLIDING_FLASH_IMPL
static size_t attention_output_index(int h, int t, int num_heads, int num_tokens, int aligned_head_dim, int output_token_major)
static void ck_sliding_attention_work_fn(int ith, int nth, void *args)
void attention_forward_causal_head_major_gqa_flash_strided(const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int kv_stride_tokens)

References attention_forward_causal_head_major_gqa_flash_strided(), attention_output_index(), ck_sliding_attention_pick_threads(), ck_sliding_attention_work_fn(), ck_threadpool_dispatch_n(), ck_threadpool_global(), qkv_index(), and SLIDING_FLASH_IMPL.

◆ attention_forward_causal_head_major_gqa_flash_strided_sliding_gemma4()

void attention_forward_causal_head_major_gqa_flash_strided_sliding_gemma4 ( const float *  q,
const float *  k,
const float *  v,
float *  output,
int  num_heads,
int  num_kv_heads,
int  num_tokens,
int  head_dim,
int  aligned_head_dim,
int  kv_stride_tokens,
int  sliding_window 
)

Definition at line 763 of file attention_kernels_sliding.c.

775{
777 q, k, v, output, num_heads, num_kv_heads, num_tokens, head_dim,
778 aligned_head_dim, kv_stride_tokens, sliding_window,
779 /*output_token_major=*/0);
780}
static void attention_forward_causal_head_major_gqa_flash_strided_sliding_gemma4_impl(const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int kv_stride_tokens, int sliding_window, int output_token_major)

References attention_forward_causal_head_major_gqa_flash_strided_sliding_gemma4_impl().

Referenced by attention_forward_causal_head_major_shared_kv_sliding_gemma4().

◆ attention_forward_causal_head_major_gqa_flash_strided_sliding_gemma4_token_output()

void attention_forward_causal_head_major_gqa_flash_strided_sliding_gemma4_token_output ( const float *  q,
const float *  k,
const float *  v,
float *  output,
int  num_heads,
int  num_kv_heads,
int  num_tokens,
int  head_dim,
int  aligned_head_dim,
int  kv_stride_tokens,
int  sliding_window 
)

Definition at line 782 of file attention_kernels_sliding.c.

794{
796 q, k, v, output, num_heads, num_kv_heads, num_tokens, head_dim,
797 aligned_head_dim, kv_stride_tokens, sliding_window,
798 /*output_token_major=*/1);
799}

References attention_forward_causal_head_major_gqa_flash_strided_sliding_gemma4_impl().

◆ attention_forward_causal_head_major_gqa_flash_strided_token_output()

void attention_forward_causal_head_major_gqa_flash_strided_token_output ( const float *  q,
const float *  k,
const float *  v,
float *  output,
int  num_heads,
int  num_kv_heads,
int  num_tokens,
int  head_dim,
int  aligned_head_dim,
int  kv_stride_tokens 
)

Definition at line 4444 of file attention_kernels.c.

4455{
4457 num_heads, num_kv_heads,
4458 num_tokens, head_dim,
4459 aligned_head_dim,
4460 kv_stride_tokens,
4461 /*causal=*/1,
4462 /*round_full_kv_fp16=*/0,
4463 /*output_token_major=*/1,
4464 1.0f / sqrtf((float)head_dim));
4465}

References attention_forward_head_major_gqa_flash_impl().

◆ attention_forward_causal_head_major_gqa_llama_regular_strided_sliding_workspace()

void attention_forward_causal_head_major_gqa_llama_regular_strided_sliding_workspace ( const float *  q,
const float *  k,
const float *  v,
float *  output,
int  num_heads,
int  num_kv_heads,
int  num_tokens,
int  head_dim,
int  aligned_head_dim,
int  kv_stride_tokens,
int  sliding_window,
float *  scores,
size_t  scores_bytes,
float *  value_columns,
size_t  value_columns_bytes,
float *  scaled_scores,
size_t  scaled_scores_bytes 
)

Definition at line 5960 of file attention_kernels.c.

5967{
5969 q, k, v, output, num_heads, num_kv_heads, num_tokens, num_tokens,
5970 head_dim, aligned_head_dim, kv_stride_tokens, sliding_window,
5971 scores, scores_bytes, value_columns, value_columns_bytes,
5972 scaled_scores, scaled_scores_bytes, 1);
5973}
static void ck_attention_llama_regular_impl(const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int query_tokens, int live_tokens, int head_dim, int aligned_head_dim, int kv_stride_tokens, int sliding_window, float *scores, size_t scores_bytes, float *value_columns, size_t value_columns_bytes, float *scaled_scores, size_t scaled_scores_bytes, int batched_prefill)

References ck_attention_llama_regular_impl().

◆ attention_forward_causal_head_major_gqa_prefill_append_bf16cache_pytorch_contract()

ck_attention_status_t attention_forward_causal_head_major_gqa_prefill_append_bf16cache_pytorch_contract ( const float *  q,
const uint16_t *  k_cache,
const uint16_t *  v_cache,
float *  output,
int  num_heads,
int  num_kv_heads,
int  q_tokens,
int  past_tokens,
int  cache_capacity,
int  head_dim,
int  aligned_head_dim,
ck_attention_reduction_t  reduction 
)

Definition at line 8673 of file attention_kernels.c.

8686{
8687 if (q_tokens >= CK_GGML_FA_TILE_Q) {
8689 q, k_cache, v_cache, output, num_heads, num_kv_heads, q_tokens,
8690 past_tokens, cache_capacity, head_dim, aligned_head_dim, reduction,
8691 NULL, 0);
8692 }
8693 if (num_heads <= 0 || aligned_head_dim <= 0 ||
8694 (size_t) num_heads > SIZE_MAX / (size_t) aligned_head_dim) {
8696 }
8697 const size_t token_elements = (size_t) num_heads * (size_t) aligned_head_dim;
8698 if (token_elements > SIZE_MAX / (2 * sizeof(float))) {
8700 }
8701 const size_t workspace_bytes = 2 * token_elements * sizeof(float);
8702 float *workspace = (float *) malloc(workspace_bytes);
8703 if (!workspace) return CK_ATTENTION_STATUS_INVALID_ARGUMENT;
8704 const ck_attention_status_t status =
8706 q, k_cache, v_cache, output, num_heads, num_kv_heads, q_tokens,
8707 past_tokens, cache_capacity, head_dim, aligned_head_dim, reduction,
8708 workspace, workspace_bytes);
8709 free(workspace);
8710 return status;
8711}
#define CK_GGML_FA_TILE_Q
ck_attention_status_t attention_forward_causal_head_major_gqa_prefill_append_bf16cache_pytorch_contract_workspace(const float *q, const uint16_t *k_cache, const uint16_t *v_cache, float *output, int num_heads, int num_kv_heads, int q_tokens, int past_tokens, int cache_capacity, int head_dim, int aligned_head_dim, ck_attention_reduction_t reduction, float *token_workspace, size_t token_workspace_bytes)

References attention_forward_causal_head_major_gqa_prefill_append_bf16cache_pytorch_contract_workspace(), CK_ATTENTION_STATUS_INVALID_ARGUMENT, and CK_GGML_FA_TILE_Q.

◆ attention_forward_causal_head_major_gqa_prefill_append_bf16cache_pytorch_contract_workspace()

ck_attention_status_t attention_forward_causal_head_major_gqa_prefill_append_bf16cache_pytorch_contract_workspace ( const float *  q,
const uint16_t *  k_cache,
const uint16_t *  v_cache,
float *  output,
int  num_heads,
int  num_kv_heads,
int  q_tokens,
int  past_tokens,
int  cache_capacity,
int  head_dim,
int  aligned_head_dim,
ck_attention_reduction_t  reduction,
float *  token_workspace,
size_t  token_workspace_bytes 
)

Definition at line 8596 of file attention_kernels.c.

8611{
8612 if (!q || !k_cache || !v_cache || !output ||
8613 num_heads <= 0 || num_kv_heads <= 0 || q_tokens <= 0 ||
8614 past_tokens < 0 || past_tokens + q_tokens > cache_capacity ||
8615 head_dim <= 0 || aligned_head_dim < head_dim) {
8617 }
8618 if (reduction != CK_ATTN_REDUCTION_BF16_PYTORCH_SDPA) {
8620 }
8621
8622 if (q_tokens >= CK_GGML_FA_TILE_Q) {
8623 ck_attention_f16_prefill_qtile64_args_t args = {
8624 .q = q, .k_cache = k_cache, .v_cache = v_cache, .output = output,
8625 .num_heads = num_heads, .num_kv_heads = num_kv_heads,
8626 .q_tokens = q_tokens, .past_tokens = past_tokens,
8627 .cache_capacity = cache_capacity, .head_dim = head_dim,
8628 .aligned_head_dim = aligned_head_dim, .cache_is_bf16 = 1,
8629 };
8630 ck_threadpool_t *pool = ck_threadpool_global();
8631 int active = pool ? ck_threadpool_n_threads(pool) : 1;
8632 if (active > num_kv_heads) active = num_kv_heads;
8633 if (pool && active > 1 && ck_threadpool_thread_id(pool) <= 0) {
8635 } else {
8637 }
8638 const size_t count = (size_t)num_heads * (size_t)q_tokens * (size_t)aligned_head_dim;
8639 for (size_t i = 0; i < count; ++i) {
8640 output[i] = bf16_to_float(float_to_bf16(output[i]));
8641 }
8643 }
8644
8645 const size_t token_elems = (size_t)num_heads * (size_t)aligned_head_dim;
8646 if (token_elems > SIZE_MAX / (2 * sizeof(float)) ||
8647 !token_workspace || token_workspace_bytes < 2 * token_elems * sizeof(float)) {
8649 }
8650 float *q_token = token_workspace;
8651 float *out_token = token_workspace + token_elems;
8653 for (int t = 0; t < q_tokens; ++t) {
8654 for (int h = 0; h < num_heads; ++h) {
8655 memcpy(q_token + (size_t)h * (size_t)aligned_head_dim,
8656 q + ((size_t)h * (size_t)q_tokens + (size_t)t) * (size_t)aligned_head_dim,
8657 (size_t)aligned_head_dim * sizeof(float));
8658 }
8660 q_token, k_cache, v_cache, out_token,
8661 num_heads, num_kv_heads, past_tokens + t + 1, cache_capacity,
8662 head_dim, aligned_head_dim, reduction);
8663 if (status != CK_ATTENTION_STATUS_OK) break;
8664 for (int h = 0; h < num_heads; ++h) {
8665 memcpy(output + ((size_t)h * (size_t)q_tokens + (size_t)t) * (size_t)aligned_head_dim,
8666 out_token + (size_t)h * (size_t)aligned_head_dim,
8667 (size_t)aligned_head_dim * sizeof(float));
8668 }
8669 }
8670 return status;
8671}
static void ck_attention_f16_prefill_qtile64_work(int ith, int nth, void *opaque)
ck_attention_status_t attention_forward_decode_head_major_gqa_bf16cache_pytorch_contract(const float *q_token, const uint16_t *k_cache, const uint16_t *v_cache, float *out_token, int num_heads, int num_kv_heads, int kv_tokens, int cache_capacity, int head_dim, int aligned_head_dim, ck_attention_reduction_t reduction)
int ck_threadpool_thread_id(const ck_threadpool_t *pool)

References attention_forward_decode_head_major_gqa_bf16cache_pytorch_contract(), bf16_to_float(), ck_attention_f16_prefill_qtile64_work(), CK_ATTENTION_STATUS_INVALID_ARGUMENT, CK_ATTENTION_STATUS_OK, CK_ATTENTION_STATUS_UNSUPPORTED_CONTRACT, CK_ATTN_REDUCTION_BF16_PYTORCH_SDPA, CK_GGML_FA_TILE_Q, ck_threadpool_dispatch_n(), ck_threadpool_global(), ck_threadpool_n_threads(), ck_threadpool_thread_id(), and float_to_bf16().

Referenced by attention_forward_causal_head_major_gqa_prefill_append_bf16cache_pytorch_contract().

◆ attention_forward_causal_head_major_gqa_prefill_append_f16cache_auto_workspace()

ck_attention_status_t attention_forward_causal_head_major_gqa_prefill_append_f16cache_auto_workspace ( const float *  q,
const uint16_t *  k_cache,
const uint16_t *  v_cache,
float *  output,
int  num_heads,
int  num_kv_heads,
int  q_tokens,
int  past_tokens,
int  cache_capacity,
int  head_dim,
int  aligned_head_dim,
ck_attention_reduction_t  reduction,
float *  token_workspace,
size_t  token_workspace_bytes,
void *  gqa_workspace,
size_t  gqa_workspace_bytes,
int  route_num_heads,
int  route_num_kv_heads,
int  route_head_dim,
int  route_query_tokens,
int  route_min_kv_tokens,
int  route_workers,
int  route_query_tile_size,
int  route_concurrent_query_tiles 
)

Definition at line 7335 of file attention_kernels.c.

7360{
7361 if (route_num_heads <= 0 || route_num_kv_heads <= 0 ||
7362 route_num_heads % route_num_kv_heads != 0 || route_head_dim <= 0 ||
7363 route_query_tokens <= 0 || route_min_kv_tokens < route_query_tokens ||
7364 route_workers < route_num_kv_heads ||
7365 route_workers % route_num_kv_heads != 0 ||
7366 route_query_tile_size < 16 || route_query_tile_size > 128 ||
7367 route_query_tile_size % 16 != 0 ||
7368 route_concurrent_query_tiles <= 0 ||
7369 route_concurrent_query_tiles > 4) {
7371 }
7372 ck_threadpool_t *pool = ck_threadpool_global();
7373 const int active = pool ? ck_threadpool_n_threads(pool) : 1;
7374 const int kv_tokens = past_tokens + q_tokens;
7376 num_heads == route_num_heads && num_kv_heads == route_num_kv_heads &&
7377 head_dim == route_head_dim && aligned_head_dim == route_head_dim &&
7378 q_tokens == route_query_tokens && kv_tokens >= route_min_kv_tokens &&
7379 active == route_workers) {
7381 q, k_cache, v_cache, output, num_heads, num_kv_heads,
7382 q_tokens, past_tokens, cache_capacity, head_dim, aligned_head_dim,
7383 route_query_tile_size, route_concurrent_query_tiles,
7384 gqa_workspace, gqa_workspace_bytes);
7385 }
7387 q, k_cache, v_cache, output, num_heads, num_kv_heads,
7388 q_tokens, past_tokens, cache_capacity, head_dim, aligned_head_dim,
7389 reduction, token_workspace, token_workspace_bytes);
7390}
ck_attention_status_t attention_forward_causal_head_major_gqa_prefill_append_f16cache_gqa_reuse_config(const float *q, const uint16_t *k_cache, const uint16_t *v_cache, float *output, int num_heads, int num_kv_heads, int q_tokens, int past_tokens, int cache_capacity, int head_dim, int aligned_head_dim, int query_tile_size, int concurrent_query_tiles, void *workspace, size_t workspace_bytes)
ck_attention_status_t attention_forward_causal_head_major_gqa_prefill_append_f16cache_contract_workspace(const float *q, const uint16_t *k_cache, const uint16_t *v_cache, float *output, int num_heads, int num_kv_heads, int q_tokens, int past_tokens, int cache_capacity, int head_dim, int aligned_head_dim, ck_attention_reduction_t reduction, float *token_workspace, size_t token_workspace_bytes)

References attention_forward_causal_head_major_gqa_prefill_append_f16cache_contract_workspace(), attention_forward_causal_head_major_gqa_prefill_append_f16cache_gqa_reuse_config(), CK_ATTENTION_STATUS_INVALID_ARGUMENT, CK_ATTN_REDUCTION_F16_FLASH_AUTO_QTILE64, ck_threadpool_global(), and ck_threadpool_n_threads().

◆ attention_forward_causal_head_major_gqa_prefill_append_f16cache_contract()

ck_attention_status_t attention_forward_causal_head_major_gqa_prefill_append_f16cache_contract ( const float *  q,
const uint16_t *  k_cache,
const uint16_t *  v_cache,
float *  output,
int  num_heads,
int  num_kv_heads,
int  q_tokens,
int  past_tokens,
int  cache_capacity,
int  head_dim,
int  aligned_head_dim,
ck_attention_reduction_t  reduction 
)

Definition at line 7641 of file attention_kernels.c.

7654{
7656 q_tokens >= CK_GGML_FA_TILE_Q) {
7658 q, k_cache, v_cache, output, num_heads, num_kv_heads, q_tokens,
7659 past_tokens, cache_capacity, head_dim, aligned_head_dim, reduction,
7660 NULL, 0);
7661 }
7662
7663 if (num_heads <= 0 || aligned_head_dim <= 0 ||
7664 (size_t) num_heads > SIZE_MAX / (size_t) aligned_head_dim) {
7666 }
7667 const size_t token_elements = (size_t) num_heads * (size_t) aligned_head_dim;
7668 if (token_elements > SIZE_MAX / (2 * sizeof(float))) {
7670 }
7671 const size_t workspace_bytes = 2 * token_elements * sizeof(float);
7672 float *workspace = (float *) malloc(workspace_bytes);
7673 if (!workspace) {
7675 }
7676 const ck_attention_status_t status =
7678 q, k_cache, v_cache, output, num_heads, num_kv_heads, q_tokens,
7679 past_tokens, cache_capacity, head_dim, aligned_head_dim, reduction,
7680 workspace, workspace_bytes);
7681 free(workspace);
7682 return status;
7683}

References attention_forward_causal_head_major_gqa_prefill_append_f16cache_contract_workspace(), CK_ATTENTION_STATUS_INVALID_ARGUMENT, CK_ATTN_REDUCTION_F16_FLASH_AUTO_QTILE64, and CK_GGML_FA_TILE_Q.

◆ attention_forward_causal_head_major_gqa_prefill_append_f16cache_contract_workspace()

ck_attention_status_t attention_forward_causal_head_major_gqa_prefill_append_f16cache_contract_workspace ( const float *  q,
const uint16_t *  k_cache,
const uint16_t *  v_cache,
float *  output,
int  num_heads,
int  num_kv_heads,
int  q_tokens,
int  past_tokens,
int  cache_capacity,
int  head_dim,
int  aligned_head_dim,
ck_attention_reduction_t  reduction,
float *  token_workspace,
size_t  token_workspace_bytes 
)

Definition at line 7419 of file attention_kernels.c.

7434{
7435 if (!q || !k_cache || !v_cache || !output ||
7436 num_heads <= 0 || num_kv_heads <= 0 || q_tokens <= 0 ||
7437 past_tokens < 0 || past_tokens + q_tokens > cache_capacity ||
7438 head_dim <= 0 || aligned_head_dim < head_dim) {
7440 }
7441
7443 q_tokens < CK_GGML_FA_TILE_Q) {
7445 }
7446
7449 q, k_cache, v_cache, output, num_heads, num_kv_heads, q_tokens,
7450 past_tokens, cache_capacity, head_dim, aligned_head_dim, 0,
7451 (size_t) q_tokens * (size_t) aligned_head_dim,
7452 (size_t) q_tokens * (size_t) aligned_head_dim,
7454 }
7455
7458 reduction != CK_ATTN_REDUCTION_FP32_ONLINE) {
7460 }
7461
7462 const size_t token_elems = (size_t) num_heads * (size_t) aligned_head_dim;
7463 if (token_elems > SIZE_MAX / (2 * sizeof(float))) {
7465 }
7466 const size_t required_bytes = 2 * token_elems * sizeof(float);
7467 if (!token_workspace || token_workspace_bytes < required_bytes) {
7469 }
7470 float *q_token = token_workspace;
7471 float *out_token = token_workspace + token_elems;
7472
7474 for (int t = 0; t < q_tokens; ++t) {
7475 for (int h = 0; h < num_heads; ++h) {
7476 const float *src = q +
7477 ((size_t) h * (size_t) q_tokens + (size_t) t) * (size_t) aligned_head_dim;
7478 memcpy(q_token + (size_t) h * (size_t) aligned_head_dim,
7479 src,
7480 (size_t) aligned_head_dim * sizeof(float));
7481 }
7482
7484 q_token, k_cache, v_cache, out_token,
7485 num_heads, num_kv_heads, past_tokens + t + 1, cache_capacity,
7486 head_dim, aligned_head_dim, reduction);
7487 if (status != CK_ATTENTION_STATUS_OK) {
7488 break;
7489 }
7490
7491 for (int h = 0; h < num_heads; ++h) {
7492 float *dst = output +
7493 ((size_t) h * (size_t) q_tokens + (size_t) t) * (size_t) aligned_head_dim;
7494 memcpy(dst,
7495 out_token + (size_t) h * (size_t) aligned_head_dim,
7496 (size_t) aligned_head_dim * sizeof(float));
7497 }
7498 }
7499
7500 return status;
7501}
static ck_attention_status_t ck_attention_f16_prefill_qtile64_dispatch(const float *q, const uint16_t *k_cache, const uint16_t *v_cache, float *output, int num_heads, int num_kv_heads, int q_tokens, int past_tokens, int cache_capacity, int head_dim, int aligned_head_dim, int cache_is_bf16, size_t q_head_stride, size_t output_head_stride, ck_attention_prefill_schedule_t schedule)
ck_attention_status_t attention_forward_decode_head_major_gqa_flash_f16cache_contract(const float *q_token, const uint16_t *k_cache, const uint16_t *v_cache, float *out_token, int num_heads, int num_kv_heads, int kv_tokens, int cache_capacity, int head_dim, int aligned_head_dim, ck_attention_reduction_t reduction)

References attention_forward_decode_head_major_gqa_flash_f16cache_contract(), ck_attention_f16_prefill_qtile64_dispatch(), CK_ATTENTION_STATUS_INVALID_ARGUMENT, CK_ATTENTION_STATUS_OK, CK_ATTENTION_STATUS_UNSUPPORTED_CONTRACT, CK_ATTN_PREFILL_SCHEDULE_QUERY_TILES, CK_ATTN_REDUCTION_F16_FLASH_AUTO_QTILE64, CK_ATTN_REDUCTION_F16_ONLINE_FP32_MERGE, CK_ATTN_REDUCTION_F16_ONLINE_SINGLE_RANGE, CK_ATTN_REDUCTION_FP32_ONLINE, and CK_GGML_FA_TILE_Q.

Referenced by attention_forward_causal_head_major_gqa_prefill_append_f16cache_auto_workspace(), and attention_forward_causal_head_major_gqa_prefill_append_f16cache_contract().

◆ attention_forward_causal_head_major_gqa_prefill_append_f16cache_gqa_reuse_config()

ck_attention_status_t attention_forward_causal_head_major_gqa_prefill_append_f16cache_gqa_reuse_config ( const float *  q,
const uint16_t *  k_cache,
const uint16_t *  v_cache,
float *  output,
int  num_heads,
int  num_kv_heads,
int  q_tokens,
int  past_tokens,
int  cache_capacity,
int  head_dim,
int  aligned_head_dim,
int  query_tile_size,
int  concurrent_query_tiles,
void *  workspace,
size_t  workspace_bytes 
)

Definition at line 7234 of file attention_kernels.c.

7250{
7251 if (!q || !k_cache || !v_cache || !output || !workspace || num_heads <= 0 ||
7252 num_kv_heads <= 0 || num_heads % num_kv_heads != 0 ||
7253 query_tile_size <= 0 || q_tokens < query_tile_size || past_tokens < 0 ||
7254 past_tokens + q_tokens > cache_capacity || head_dim <= 0 ||
7255 aligned_head_dim < head_dim || query_tile_size < 16 ||
7256 query_tile_size > 128 || query_tile_size % 16 != 0 ||
7257 concurrent_query_tiles <= 0 || concurrent_query_tiles > 4) {
7259 }
7260
7261 ck_threadpool_t *pool = ck_threadpool_global();
7262 const int active = pool ? ck_threadpool_n_threads(pool) : 1;
7263 if (!pool || active < num_kv_heads || active % num_kv_heads != 0 ||
7264 ck_threadpool_thread_id(pool) > 0) {
7266 }
7267 const size_t required_workspace =
7269 num_heads, num_kv_heads, head_dim, active,
7270 query_tile_size, concurrent_query_tiles);
7271 if (required_workspace == 0 || workspace_bytes < required_workspace) {
7273 }
7274 const int lanes = active / num_kv_heads;
7275 const size_t tile_elems =
7276 (size_t) num_kv_heads * (size_t) head_dim * CK_GGML_FA_TILE_KV;
7277 uintptr_t workspace_address = (uintptr_t) workspace;
7278 workspace_address = (workspace_address + 63u) & ~(uintptr_t) 63u;
7279 unsigned char *workspace_base = (unsigned char *) workspace_address;
7280 size_t cursor = 0;
7281 float *shared_k_tiles = (float *) (workspace_base + cursor);
7282 cursor += tile_elems * sizeof(float);
7283 cursor = ck_attention_align64_size(cursor);
7284 float *shared_v_tiles = (float *) (workspace_base + cursor);
7285 cursor += tile_elems * sizeof(float);
7286 cursor = ck_attention_align64_size(cursor);
7287 ck_attention_gqa_team_barrier_t *barriers =
7288 (ck_attention_gqa_team_barrier_t *) (workspace_base + cursor);
7289 cursor += (size_t) num_kv_heads * sizeof(*barriers);
7290 cursor = ck_attention_align64_size(cursor);
7291 unsigned char *worker_workspace = workspace_base + cursor;
7292 const size_t worker_workspace_stride =
7294 num_heads, num_kv_heads, head_dim, active,
7295 query_tile_size, concurrent_query_tiles);
7296 for (int group = 0; group < num_kv_heads; ++group) {
7297 __atomic_store_n(&barriers[group].arrived, 0, __ATOMIC_RELAXED);
7298 __atomic_store_n(&barriers[group].phase, 0, __ATOMIC_RELAXED);
7299 barriers[group].lanes = lanes;
7300 }
7301
7302 ck_attention_f16_prefill_gqa_reuse_args_t args = {
7303 .base = {
7304 .q = q,
7305 .k_cache = k_cache,
7306 .v_cache = v_cache,
7307 .output = output,
7308 .num_heads = num_heads,
7309 .num_kv_heads = num_kv_heads,
7310 .q_tokens = q_tokens,
7311 .past_tokens = past_tokens,
7312 .cache_capacity = cache_capacity,
7313 .head_dim = head_dim,
7314 .aligned_head_dim = aligned_head_dim,
7315 .cache_is_bf16 = 0,
7317 .q_head_stride =
7318 (size_t) q_tokens * (size_t) aligned_head_dim,
7319 .output_head_stride =
7320 (size_t) q_tokens * (size_t) aligned_head_dim,
7321 },
7322 .shared_k_tiles = shared_k_tiles,
7323 .shared_v_tiles = shared_v_tiles,
7324 .barriers = barriers,
7325 .worker_workspace = worker_workspace,
7326 .worker_workspace_stride = worker_workspace_stride,
7327 .query_tile_size = query_tile_size,
7328 .concurrent_query_tiles = concurrent_query_tiles,
7329 };
7331 pool, active, ck_attention_f16_prefill_gqa_reuse_work, &args);
7333}
#define CK_GGML_FA_TILE_KV
static void ck_attention_f16_prefill_gqa_reuse_work(int ith, int nth, void *opaque)
size_t attention_forward_causal_head_major_gqa_prefill_append_f16cache_gqa_reuse_workspace_bytes(int num_heads, int num_kv_heads, int head_dim, int workers, int query_tile_size, int concurrent_query_tiles)
static size_t ck_attention_f16_prefill_gqa_reuse_worker_bytes(int num_heads, int num_kv_heads, int head_dim, int workers, int query_tile_size, int concurrent_query_tiles)
static size_t ck_attention_align64_size(size_t value)

References attention_forward_causal_head_major_gqa_prefill_append_f16cache_gqa_reuse_workspace_bytes(), ck_attention_align64_size(), ck_attention_f16_prefill_gqa_reuse_work(), ck_attention_f16_prefill_gqa_reuse_worker_bytes(), CK_ATTENTION_STATUS_INSUFFICIENT_WORKSPACE, CK_ATTENTION_STATUS_INVALID_ARGUMENT, CK_ATTENTION_STATUS_OK, CK_ATTENTION_STATUS_UNSUPPORTED_CONTRACT, CK_ATTN_PREFILL_SCHEDULE_GQA_SHARED_KV_TILES, CK_GGML_FA_TILE_KV, ck_threadpool_dispatch_n(), ck_threadpool_global(), ck_threadpool_n_threads(), and ck_threadpool_thread_id().

Referenced by attention_forward_causal_head_major_gqa_prefill_append_f16cache_auto_workspace().

◆ attention_forward_causal_head_major_gqa_prefill_append_f16cache_gqa_reuse_workspace_bytes()

size_t attention_forward_causal_head_major_gqa_prefill_append_f16cache_gqa_reuse_workspace_bytes ( int  num_heads,
int  num_kv_heads,
int  head_dim,
int  workers,
int  query_tile_size,
int  concurrent_query_tiles 
)

Definition at line 6716 of file attention_kernels.c.

6723{
6724 const size_t worker_bytes =
6726 num_heads, num_kv_heads, head_dim, workers,
6727 query_tile_size, concurrent_query_tiles);
6728 if (worker_bytes == 0) return 0;
6729 size_t bytes = 63u;
6730 bytes = ck_attention_align64_size(bytes) +
6731 (size_t) num_kv_heads * (size_t) head_dim * CK_GGML_FA_TILE_KV *
6732 sizeof(float);
6733 bytes = ck_attention_align64_size(bytes) +
6734 (size_t) num_kv_heads * CK_GGML_FA_TILE_KV * (size_t) head_dim *
6735 sizeof(float);
6736 bytes = ck_attention_align64_size(bytes) +
6737 (size_t) num_kv_heads * sizeof(ck_attention_gqa_team_barrier_t);
6738 bytes = ck_attention_align64_size(bytes) +
6739 (size_t) workers * worker_bytes;
6740 return bytes;
6741}

References ck_attention_align64_size(), ck_attention_f16_prefill_gqa_reuse_worker_bytes(), and CK_GGML_FA_TILE_KV.

Referenced by attention_forward_causal_head_major_gqa_prefill_append_f16cache_gqa_reuse_config().

◆ attention_forward_causal_head_major_gqa_prefill_append_f16cache_qtile64_schedule()

ck_attention_status_t attention_forward_causal_head_major_gqa_prefill_append_f16cache_qtile64_schedule ( const float *  q,
const uint16_t *  k_cache,
const uint16_t *  v_cache,
float *  output,
int  num_heads,
int  num_kv_heads,
int  q_tokens,
int  past_tokens,
int  cache_capacity,
int  head_dim,
int  aligned_head_dim,
ck_attention_prefill_schedule_t  schedule 
)

Definition at line 7392 of file attention_kernels.c.

7405{
7406 if (!q || !k_cache || !v_cache || !output || num_heads <= 0 ||
7407 num_kv_heads <= 0 || q_tokens < CK_GGML_FA_TILE_Q || past_tokens < 0 ||
7408 past_tokens + q_tokens > cache_capacity || head_dim <= 0 ||
7409 aligned_head_dim < head_dim) {
7411 }
7413 q, k_cache, v_cache, output, num_heads, num_kv_heads, q_tokens,
7414 past_tokens, cache_capacity, head_dim, aligned_head_dim, 0,
7415 (size_t) q_tokens * (size_t) aligned_head_dim,
7416 (size_t) q_tokens * (size_t) aligned_head_dim, schedule);
7417}

References ck_attention_f16_prefill_qtile64_dispatch(), CK_ATTENTION_STATUS_INVALID_ARGUMENT, and CK_GGML_FA_TILE_Q.

◆ attention_forward_causal_head_major_gqa_prefill_full_bf16cache_pytorch_contract()

ck_attention_status_t attention_forward_causal_head_major_gqa_prefill_full_bf16cache_pytorch_contract ( const float *  q,
const uint16_t *  k_cache,
const uint16_t *  v_cache,
float *  output,
int  num_heads,
int  num_kv_heads,
int  q_tokens,
int  past_tokens,
int  cache_capacity,
int  head_dim,
int  aligned_head_dim,
ck_attention_reduction_t  reduction 
)

Definition at line 8713 of file attention_kernels.c.

8726{
8727 if (!q || !k_cache || !v_cache || !output ||
8728 num_heads <= 0 || num_kv_heads <= 0 ||
8729 num_heads % num_kv_heads != 0 ||
8730 q_tokens <= 0 || past_tokens < 0 ||
8731 past_tokens + q_tokens > cache_capacity ||
8732 head_dim <= 0 || aligned_head_dim < head_dim) {
8734 }
8735 if (reduction != CK_ATTN_REDUCTION_BF16_PYTORCH_SDPA) {
8737 }
8738
8739#if defined(__AVX512F__)
8740 pthread_once(&ck_pytorch_attention_once, ck_bind_pytorch_attention_primitives);
8741 return ck_attention_prefill_bf16_pytorch_math_gqa_full(
8742 q, k_cache, v_cache, output,
8743 num_heads, num_kv_heads, q_tokens, past_tokens, cache_capacity,
8744 head_dim, aligned_head_dim);
8745#else
8747#endif
8748}

References CK_ATTENTION_STATUS_INVALID_ARGUMENT, CK_ATTENTION_STATUS_UNSUPPORTED_CONTRACT, and CK_ATTN_REDUCTION_BF16_PYTORCH_SDPA.

◆ attention_forward_causal_head_major_gqa_prefill_segmented_f16cache_contract_workspace()

ck_attention_status_t attention_forward_causal_head_major_gqa_prefill_segmented_f16cache_contract_workspace ( const float *  q,
const uint16_t *  k_cache,
const uint16_t *  v_cache,
float *  output,
int  num_heads,
int  num_kv_heads,
int  q_tokens,
int  past_tokens,
int  cache_capacity,
int  head_dim,
int  aligned_head_dim,
ck_attention_reduction_t  reduction,
float *  token_workspace,
size_t  token_workspace_bytes,
const int *  segment_lengths,
int  num_segments 
)

Definition at line 7616 of file attention_kernels.c.

7633{
7635 q, k_cache, v_cache, output, num_heads, num_kv_heads, q_tokens,
7636 past_tokens, cache_capacity, head_dim, aligned_head_dim, reduction,
7637 token_workspace, token_workspace_bytes, segment_lengths, num_segments,
7639}
static ck_attention_status_t ck_attention_forward_causal_head_major_gqa_prefill_segmented_f16cache_schedule_workspace(const float *q, const uint16_t *k_cache, const uint16_t *v_cache, float *output, int num_heads, int num_kv_heads, int q_tokens, int past_tokens, int cache_capacity, int head_dim, int aligned_head_dim, ck_attention_reduction_t reduction, float *token_workspace, size_t token_workspace_bytes, const int *segment_lengths, int num_segments, ck_attention_prefill_schedule_t schedule)

References ck_attention_forward_causal_head_major_gqa_prefill_segmented_f16cache_schedule_workspace(), and CK_ATTN_PREFILL_SCHEDULE_QUERY_TILES.

◆ attention_forward_causal_head_major_shared_kv_gemma4()

void attention_forward_causal_head_major_shared_kv_gemma4 ( const float *  q,
float *  output,
int  num_heads,
int  num_tokens,
int  head_dim,
int  aligned_head_dim,
int  kv_stride_tokens 
)

Definition at line 5070 of file attention_kernels.c.

5077{
5079 q, q, q, output, num_heads, num_heads, num_tokens,
5080 head_dim, aligned_head_dim, kv_stride_tokens
5081 );
5082}
void attention_forward_causal_head_major_gqa_flash_strided_gemma4(const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int kv_stride_tokens)

References attention_forward_causal_head_major_gqa_flash_strided_gemma4().

◆ attention_forward_causal_head_major_shared_kv_sliding_gemma4()

void attention_forward_causal_head_major_shared_kv_sliding_gemma4 ( const float *  q,
float *  output,
int  num_heads,
int  num_tokens,
int  head_dim,
int  aligned_head_dim,
int  kv_stride_tokens,
int  sliding_window 
)

Definition at line 801 of file attention_kernels_sliding.c.

810{
812 q, q, q, output, num_heads, num_heads, num_tokens,
813 head_dim, aligned_head_dim, kv_stride_tokens, sliding_window
814 );
815}
void attention_forward_causal_head_major_gqa_flash_strided_sliding_gemma4(const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int kv_stride_tokens, int sliding_window)

References attention_forward_causal_head_major_gqa_flash_strided_sliding_gemma4().

◆ attention_forward_chunk_head_major_gqa_flash_gemma4()

void attention_forward_chunk_head_major_gqa_flash_gemma4 ( const float *  q_chunk,
const float *  k_cache,
const float *  v_cache,
float *  out_chunk,
int  num_heads,
int  num_kv_heads,
int  q_tokens,
int  kv_tokens,
int  cache_capacity,
int  head_dim,
int  aligned_head_dim 
)

Definition at line 6089 of file attention_kernels.c.

6100{
6101 if (!q_chunk || !k_cache || !v_cache || !out_chunk) {
6102 return;
6103 }
6104 if (num_heads <= 0 || num_kv_heads <= 0 || q_tokens <= 0 || kv_tokens <= 0 || cache_capacity <= 0) {
6105 return;
6106 }
6107 if (kv_tokens > cache_capacity || head_dim <= 0 || aligned_head_dim <= 0) {
6108 return;
6109 }
6110
6111 const float scale = 1.0f;
6112 const size_t cache_head_stride = (size_t)cache_capacity * (size_t)aligned_head_dim;
6113 const size_t q_head_stride = (size_t)q_tokens * (size_t)aligned_head_dim;
6114
6115 for (int h = 0; h < num_heads; ++h) {
6116 int kv_head = (int)((long long)h * (long long)num_kv_heads / (long long)num_heads);
6117 const float *k_head = k_cache + (size_t)kv_head * cache_head_stride;
6118 const float *v_head = v_cache + (size_t)kv_head * cache_head_stride;
6119 for (int t = 0; t < q_tokens; ++t) {
6120 const float *q_head = q_chunk + (size_t)h * q_head_stride + (size_t)t * (size_t)aligned_head_dim;
6121 float *out_head = out_chunk + (size_t)h * q_head_stride + (size_t)t * (size_t)aligned_head_dim;
6122 attention_flash_decode(out_head,
6123 q_head,
6124 k_head,
6125 v_head,
6126 1,
6127 kv_tokens,
6128 1,
6129 aligned_head_dim,
6130 scale);
6131 }
6132 }
6133}
void attention_flash_decode(float *out, const float *q, const float *k, const float *v, int T_q, int T_k, int H, int D_h, float scale)
Main flash attention function with SIMD dispatch.

References attention_flash_decode().

◆ attention_forward_decode_head_major_gqa_bf16cache_pytorch_contract()

ck_attention_status_t attention_forward_decode_head_major_gqa_bf16cache_pytorch_contract ( const float *  q_token,
const uint16_t *  k_cache,
const uint16_t *  v_cache,
float *  out_token,
int  num_heads,
int  num_kv_heads,
int  kv_tokens,
int  cache_capacity,
int  head_dim,
int  aligned_head_dim,
ck_attention_reduction_t  reduction 
)

Definition at line 8522 of file attention_kernels.c.

8534{
8535 if (!q_token || !k_cache || !v_cache || !out_token ||
8536 num_heads <= 0 || num_kv_heads <= 0 || kv_tokens <= 0 ||
8537 cache_capacity <= 0 || kv_tokens > cache_capacity ||
8538 head_dim <= 0 || aligned_head_dim < head_dim ||
8539 num_heads % num_kv_heads != 0) {
8541 }
8542 if (reduction != CK_ATTN_REDUCTION_BF16_PYTORCH_SDPA) {
8544 }
8545
8546#if defined(__AVX512F__)
8547 pthread_once(&ck_pytorch_attention_once, ck_bind_pytorch_attention_primitives);
8548 return ck_attention_decode_bf16_pytorch_math_gqa(
8549 q_token, k_cache, v_cache, out_token, num_heads, num_kv_heads,
8550 kv_tokens, cache_capacity, head_dim, aligned_head_dim);
8551#else
8552 const float scale = 1.0f / sqrtf((float)head_dim);
8553 const size_t head_stride = (size_t)cache_capacity * (size_t)aligned_head_dim;
8554 for (int h = 0; h < num_heads; ++h) {
8555 const int kv_head = (int)((long long)h * (long long)num_kv_heads / (long long)num_heads);
8556 const float *q_head = q_token + (size_t)h * (size_t)aligned_head_dim;
8557 const uint16_t *k_head = k_cache + (size_t)kv_head * head_stride;
8558 const uint16_t *v_head = v_cache + (size_t)kv_head * head_stride;
8559 float *out_head = out_token + (size_t)h * (size_t)aligned_head_dim;
8560
8561 float maximum = -INFINITY;
8562 for (int token = 0; token < kv_tokens; ++token) {
8563 const uint16_t *k_row = k_head + (size_t)token * (size_t)aligned_head_dim;
8564 float dot = 0.0f;
8565 for (int d = 0; d < head_dim; ++d) {
8566 dot = fmaf(q_head[d], bf16_to_float(k_row[d]), dot);
8567 }
8568 const float score = dot * scale;
8569 if (score > maximum) maximum = score;
8570 }
8571
8572 for (int d = 0; d < aligned_head_dim; ++d) out_head[d] = 0.0f;
8573 float denominator = 0.0f;
8574 for (int token = 0; token < kv_tokens; ++token) {
8575 const uint16_t *k_row = k_head + (size_t)token * (size_t)aligned_head_dim;
8576 const uint16_t *v_row = v_head + (size_t)token * (size_t)aligned_head_dim;
8577 float dot = 0.0f;
8578 for (int d = 0; d < head_dim; ++d) {
8579 dot = fmaf(q_head[d], bf16_to_float(k_row[d]), dot);
8580 }
8581 const float probability = expf(dot * scale - maximum);
8582 denominator += probability;
8583 for (int d = 0; d < head_dim; ++d) {
8584 out_head[d] = fmaf(probability, bf16_to_float(v_row[d]), out_head[d]);
8585 }
8586 }
8587 const float inverse = denominator > 0.0f ? 1.0f / denominator : 0.0f;
8588 for (int d = 0; d < head_dim; ++d) {
8589 out_head[d] = bf16_to_float(float_to_bf16(out_head[d] * inverse));
8590 }
8591 }
8593#endif
8594}
const char * token
Definition tokenizer.h:307
int32_t float * score
Definition tokenizer.h:328

References bf16_to_float(), CK_ATTENTION_STATUS_INVALID_ARGUMENT, CK_ATTENTION_STATUS_OK, CK_ATTENTION_STATUS_UNSUPPORTED_CONTRACT, CK_ATTN_REDUCTION_BF16_PYTORCH_SDPA, float_to_bf16(), score, and token.

Referenced by attention_forward_causal_head_major_gqa_prefill_append_bf16cache_pytorch_contract_workspace().

◆ attention_forward_decode_head_major_gqa_flash()

void attention_forward_decode_head_major_gqa_flash ( const float *  q_token,
const float *  k_cache,
const float *  v_cache,
float *  out_token,
int  num_heads,
int  num_kv_heads,
int  kv_tokens,
int  cache_capacity,
int  head_dim,
int  aligned_head_dim 
)

Flash attention decode (single token attends to KV cache)

Test:

test_flash_attention.py::TestFlashAttention::test_flash_decode

test_kv_cache_attention.py::TestKVCacheAttention::test_flash_decode

test_fused_attention_decode.py::TestFusedAttentionDecode::test_flash_decode

test_attention.py::TestAttentionForward::test_flash_decode

Single query token attends to kv_tokens in KV cache. Uses true flash attention from attention_flash_true.c.

After changes: make test && make llamacpp-parity-full

Definition at line 6002 of file attention_kernels.c.

6012{
6013 if (!q_token || !k_cache || !v_cache || !out_token) {
6014 return;
6015 }
6016 if (num_heads <= 0 || num_kv_heads <= 0 || kv_tokens <= 0 || cache_capacity <= 0) {
6017 return;
6018 }
6019 if (kv_tokens > cache_capacity || head_dim <= 0 || aligned_head_dim <= 0) {
6020 return;
6021 }
6022
6023 const float scale = 1.0f / sqrtf((float)head_dim);
6024 const size_t head_stride = (size_t)cache_capacity * (size_t)aligned_head_dim;
6025
6026 for (int h = 0; h < num_heads; ++h) {
6027 int kv_head = (int)((long long)h * (long long)num_kv_heads / (long long)num_heads);
6028 const float *q_head = q_token + (size_t)h * (size_t)aligned_head_dim;
6029 const float *k_head = k_cache + (size_t)kv_head * head_stride;
6030 const float *v_head = v_cache + (size_t)kv_head * head_stride;
6031 float *out_head = out_token + (size_t)h * (size_t)aligned_head_dim;
6032
6033 attention_flash_decode(out_head,
6034 q_head,
6035 k_head,
6036 v_head,
6037 1,
6038 kv_tokens,
6039 1,
6040 aligned_head_dim,
6041 scale);
6042 }
6043}

References attention_flash_decode().

Referenced by attention_forward_decode_head_major_gqa_flash_sliding(), model_layer_0_decode(), model_layer_0_decode(), model_layer_0_decode(), model_layer_0_decode(), model_layer_10_decode(), model_layer_10_decode(), model_layer_10_decode(), model_layer_10_decode(), model_layer_11_decode(), model_layer_11_decode(), model_layer_11_decode(), model_layer_11_decode(), model_layer_12_decode(), model_layer_12_decode(), model_layer_12_decode(), model_layer_12_decode(), model_layer_13_decode(), model_layer_13_decode(), model_layer_13_decode(), model_layer_13_decode(), model_layer_14_decode(), model_layer_14_decode(), model_layer_14_decode(), model_layer_14_decode(), model_layer_15_decode(), model_layer_15_decode(), model_layer_15_decode(), model_layer_15_decode(), model_layer_16_decode(), model_layer_16_decode(), model_layer_16_decode(), model_layer_16_decode(), model_layer_17_decode(), model_layer_17_decode(), model_layer_17_decode(), model_layer_17_decode(), model_layer_18_decode(), model_layer_18_decode(), model_layer_18_decode(), model_layer_18_decode(), model_layer_19_decode(), model_layer_19_decode(), model_layer_19_decode(), model_layer_19_decode(), model_layer_1_decode(), model_layer_1_decode(), model_layer_1_decode(), model_layer_1_decode(), model_layer_20_decode(), model_layer_20_decode(), model_layer_20_decode(), model_layer_20_decode(), model_layer_21_decode(), model_layer_21_decode(), model_layer_21_decode(), model_layer_21_decode(), model_layer_22_decode(), model_layer_22_decode(), model_layer_22_decode(), model_layer_22_decode(), model_layer_23_decode(), model_layer_23_decode(), model_layer_23_decode(), model_layer_23_decode(), model_layer_2_decode(), model_layer_2_decode(), model_layer_2_decode(), model_layer_2_decode(), model_layer_3_decode(), model_layer_3_decode(), model_layer_3_decode(), model_layer_3_decode(), model_layer_4_decode(), model_layer_4_decode(), model_layer_4_decode(), model_layer_4_decode(), model_layer_5_decode(), model_layer_5_decode(), model_layer_5_decode(), model_layer_5_decode(), model_layer_6_decode(), model_layer_6_decode(), model_layer_6_decode(), model_layer_6_decode(), model_layer_7_decode(), model_layer_7_decode(), model_layer_7_decode(), model_layer_7_decode(), model_layer_8_decode(), model_layer_8_decode(), model_layer_8_decode(), model_layer_8_decode(), model_layer_9_decode(), model_layer_9_decode(), model_layer_9_decode(), model_layer_9_decode(), qwen2_0_5b_decode_layer_0_decode(), qwen2_0_5b_decode_layer_0_decode(), qwen2_0_5b_decode_layer_10_decode(), qwen2_0_5b_decode_layer_10_decode(), qwen2_0_5b_decode_layer_11_decode(), qwen2_0_5b_decode_layer_11_decode(), qwen2_0_5b_decode_layer_12_decode(), qwen2_0_5b_decode_layer_12_decode(), qwen2_0_5b_decode_layer_13_decode(), qwen2_0_5b_decode_layer_13_decode(), qwen2_0_5b_decode_layer_14_decode(), qwen2_0_5b_decode_layer_14_decode(), qwen2_0_5b_decode_layer_15_decode(), qwen2_0_5b_decode_layer_15_decode(), qwen2_0_5b_decode_layer_16_decode(), qwen2_0_5b_decode_layer_16_decode(), qwen2_0_5b_decode_layer_17_decode(), qwen2_0_5b_decode_layer_17_decode(), qwen2_0_5b_decode_layer_18_decode(), qwen2_0_5b_decode_layer_18_decode(), qwen2_0_5b_decode_layer_19_decode(), qwen2_0_5b_decode_layer_19_decode(), qwen2_0_5b_decode_layer_1_decode(), qwen2_0_5b_decode_layer_1_decode(), qwen2_0_5b_decode_layer_20_decode(), qwen2_0_5b_decode_layer_20_decode(), qwen2_0_5b_decode_layer_21_decode(), qwen2_0_5b_decode_layer_21_decode(), qwen2_0_5b_decode_layer_22_decode(), qwen2_0_5b_decode_layer_22_decode(), qwen2_0_5b_decode_layer_23_decode(), qwen2_0_5b_decode_layer_23_decode(), qwen2_0_5b_decode_layer_2_decode(), qwen2_0_5b_decode_layer_2_decode(), qwen2_0_5b_decode_layer_3_decode(), qwen2_0_5b_decode_layer_3_decode(), qwen2_0_5b_decode_layer_4_decode(), qwen2_0_5b_decode_layer_4_decode(), qwen2_0_5b_decode_layer_5_decode(), qwen2_0_5b_decode_layer_5_decode(), qwen2_0_5b_decode_layer_6_decode(), qwen2_0_5b_decode_layer_6_decode(), qwen2_0_5b_decode_layer_7_decode(), qwen2_0_5b_decode_layer_7_decode(), qwen2_0_5b_decode_layer_8_decode(), qwen2_0_5b_decode_layer_8_decode(), qwen2_0_5b_decode_layer_9_decode(), and qwen2_0_5b_decode_layer_9_decode().

◆ attention_forward_decode_head_major_gqa_flash_f16cache()

void attention_forward_decode_head_major_gqa_flash_f16cache ( const float *  q_token,
const uint16_t *  k_cache,
const uint16_t *  v_cache,
float *  out_token,
int  num_heads,
int  num_kv_heads,
int  kv_tokens,
int  cache_capacity,
int  head_dim,
int  aligned_head_dim 
)

Definition at line 8750 of file attention_kernels.c.

8760{
8761 if (!q_token || !k_cache || !v_cache || !out_token) {
8762 return;
8763 }
8764 if (num_heads <= 0 || num_kv_heads <= 0 || kv_tokens <= 0 || cache_capacity <= 0) {
8765 return;
8766 }
8767 if (kv_tokens > cache_capacity || head_dim <= 0 || aligned_head_dim <= 0) {
8768 return;
8769 }
8770
8771 const float scale = 1.0f / sqrtf((float)head_dim);
8772 const size_t head_stride = (size_t)cache_capacity * (size_t)aligned_head_dim;
8773 const size_t scratch_elems = (size_t)kv_tokens * (size_t)aligned_head_dim;
8774 const size_t scratch_bytes = scratch_elems * sizeof(float);
8775 const size_t max_stack_bytes = 1024u * 1024u;
8776
8777 if (scratch_bytes * 2u > max_stack_bytes) {
8778 for (int h = 0; h < num_heads; ++h) {
8779 int kv_head = (int)((long long)h * (long long)num_kv_heads / (long long)num_heads);
8780 const float *q_head = q_token + (size_t)h * (size_t)aligned_head_dim;
8781 const uint16_t *k_head = k_cache + (size_t)kv_head * head_stride;
8782 const uint16_t *v_head = v_cache + (size_t)kv_head * head_stride;
8783 float *out_head = out_token + (size_t)h * (size_t)aligned_head_dim;
8784
8785 for (int d = 0; d < aligned_head_dim; ++d) {
8786 out_head[d] = 0.0f;
8787 }
8788
8789 float max_score = -INFINITY;
8790 for (int j = 0; j < kv_tokens; ++j) {
8791 const uint16_t *k_vec = k_head + (size_t)j * (size_t)aligned_head_dim;
8792 float dot = 0.0f;
8793 for (int d = 0; d < head_dim; ++d) {
8794 dot += q_head[d] * CK_FP16_TO_FP32(k_vec[d]);
8795 }
8796 const float score = dot * scale;
8797 if (score > max_score) {
8798 max_score = score;
8799 }
8800 }
8801
8802 float sum = 0.0f;
8803 for (int j = 0; j < kv_tokens; ++j) {
8804 const uint16_t *k_vec = k_head + (size_t)j * (size_t)aligned_head_dim;
8805 const uint16_t *v_vec = v_head + (size_t)j * (size_t)aligned_head_dim;
8806 float dot = 0.0f;
8807 for (int d = 0; d < head_dim; ++d) {
8808 dot += q_head[d] * CK_FP16_TO_FP32(k_vec[d]);
8809 }
8810 const float w = expf(dot * scale - max_score);
8811 sum += w;
8812 for (int d = 0; d < head_dim; ++d) {
8813 out_head[d] += w * CK_FP16_TO_FP32(v_vec[d]);
8814 }
8815 }
8816
8817 if (sum > 0.0f) {
8818 const float inv_sum = 1.0f / sum;
8819 for (int d = 0; d < head_dim; ++d) {
8820 out_head[d] *= inv_sum;
8821 }
8822 }
8823 for (int d = head_dim; d < aligned_head_dim; ++d) {
8824 out_head[d] = 0.0f;
8825 }
8826 }
8827 return;
8828 }
8829
8830 float *k_head_fp32 = (float *)alloca(scratch_bytes);
8831 float *v_head_fp32 = (float *)alloca(scratch_bytes);
8832
8833 for (int kv_head = 0; kv_head < num_kv_heads; ++kv_head) {
8834 const uint16_t *k_head = k_cache + (size_t)kv_head * head_stride;
8835 const uint16_t *v_head = v_cache + (size_t)kv_head * head_stride;
8836 const int q_begin = (int)((long long)kv_head * (long long)num_heads / (long long)num_kv_heads);
8837 const int q_end = (int)((long long)(kv_head + 1) * (long long)num_heads / (long long)num_kv_heads);
8838
8839 ck_local_fp16_to_fp32_2d(k_head, k_head_fp32, kv_tokens, aligned_head_dim, aligned_head_dim, aligned_head_dim);
8840 ck_local_fp16_to_fp32_2d(v_head, v_head_fp32, kv_tokens, aligned_head_dim, aligned_head_dim, aligned_head_dim);
8841
8842 for (int h = q_begin; h < q_end; ++h) {
8843 const float *q_head = q_token + (size_t)h * (size_t)aligned_head_dim;
8844 float *out_head = out_token + (size_t)h * (size_t)aligned_head_dim;
8845
8846 attention_flash_decode(out_head,
8847 q_head,
8848 k_head_fp32,
8849 v_head_fp32,
8850 1,
8851 kv_tokens,
8852 1,
8853 aligned_head_dim,
8854 scale);
8855 }
8856 }
8857}
static void ck_local_fp16_to_fp32_2d(const uint16_t *src, float *dst, int rows, int cols, int src_stride, int dst_stride)
#define CK_FP16_TO_FP32(x)

References attention_flash_decode(), CK_FP16_TO_FP32, ck_local_fp16_to_fp32_2d(), and score.

Referenced by attention_forward_decode_head_major_gqa_flash_f16cache_contract().

◆ attention_forward_decode_head_major_gqa_flash_f16cache_contract()

ck_attention_status_t attention_forward_decode_head_major_gqa_flash_f16cache_contract ( const float *  q_token,
const uint16_t *  k_cache,
const uint16_t *  v_cache,
float *  out_token,
int  num_heads,
int  num_kv_heads,
int  kv_tokens,
int  cache_capacity,
int  head_dim,
int  aligned_head_dim,
ck_attention_reduction_t  reduction 
)

Definition at line 6586 of file attention_kernels.c.

6598{
6599 if (!q_token || !k_cache || !v_cache || !out_token ||
6600 num_heads <= 0 || num_kv_heads <= 0 || kv_tokens <= 0 ||
6601 cache_capacity <= 0 || kv_tokens > cache_capacity ||
6602 head_dim <= 0 || aligned_head_dim < head_dim) {
6604 }
6605
6606 switch (reduction) {
6609 q_token, k_cache, v_cache, out_token,
6610 num_heads, num_kv_heads, kv_tokens, cache_capacity,
6611 head_dim, aligned_head_dim);
6613
6615 const int partition_alignment = 256;
6616 const int partition_tokens =
6617 ((kv_tokens + partition_alignment - 1) / partition_alignment) * partition_alignment;
6618 const int split_chunks = partition_tokens >= 512 ? ck_get_num_threads() : 1;
6620 q_token, k_cache, v_cache, out_token,
6621 num_heads, num_kv_heads, kv_tokens, cache_capacity,
6622 head_dim, aligned_head_dim, split_chunks);
6624 }
6625
6628 q_token, k_cache, v_cache, out_token,
6629 num_heads, num_kv_heads, kv_tokens, cache_capacity,
6630 head_dim, aligned_head_dim, 1);
6632
6633 default:
6635 }
6636}
void attention_forward_decode_head_major_gqa_flash_f16cache(const float *q_token, const uint16_t *k_cache, const uint16_t *v_cache, float *out_token, int num_heads, int num_kv_heads, int kv_tokens, int cache_capacity, int head_dim, int aligned_head_dim)
void attention_forward_decode_head_major_gqa_flash_f16cache_split(const float *q_token, const uint16_t *k_cache, const uint16_t *v_cache, float *out_token, int num_heads, int num_kv_heads, int kv_tokens, int cache_capacity, int head_dim, int aligned_head_dim, int split_chunks)
int ck_get_num_threads(void)

References attention_forward_decode_head_major_gqa_flash_f16cache(), attention_forward_decode_head_major_gqa_flash_f16cache_split(), CK_ATTENTION_STATUS_INVALID_ARGUMENT, CK_ATTENTION_STATUS_OK, CK_ATTENTION_STATUS_UNSUPPORTED_CONTRACT, CK_ATTN_REDUCTION_F16_ONLINE_FP32_MERGE, CK_ATTN_REDUCTION_F16_ONLINE_SINGLE_RANGE, CK_ATTN_REDUCTION_FP32_ONLINE, and ck_get_num_threads().

Referenced by attention_forward_causal_head_major_gqa_prefill_append_f16cache_contract_workspace(), and ck_attention_forward_causal_head_major_gqa_prefill_segmented_f16cache_schedule_workspace().

◆ attention_forward_decode_head_major_gqa_flash_f16cache_split()

void attention_forward_decode_head_major_gqa_flash_f16cache_split ( const float *  q_token,
const uint16_t *  k_cache,
const uint16_t *  v_cache,
float *  out_token,
int  num_heads,
int  num_kv_heads,
int  kv_tokens,
int  cache_capacity,
int  head_dim,
int  aligned_head_dim,
int  split_chunks 
)

Definition at line 6565 of file attention_kernels.c.

6576{
6577 const int partition_alignment = 256;
6578 const int partition_tokens =
6579 ((kv_tokens + partition_alignment - 1) / partition_alignment) * partition_alignment;
6581 q_token, k_cache, v_cache, out_token,
6582 num_heads, num_kv_heads, kv_tokens, cache_capacity,
6583 head_dim, aligned_head_dim, split_chunks, partition_tokens);
6584}
static void attention_forward_decode_head_major_gqa_flash_f16cache_split_partitioned(const float *q_token, const uint16_t *k_cache, const uint16_t *v_cache, float *out_token, int num_heads, int num_kv_heads, int kv_tokens, int cache_capacity, int head_dim, int aligned_head_dim, int split_chunks, int partition_tokens)

References attention_forward_decode_head_major_gqa_flash_f16cache_split_partitioned().

Referenced by attention_forward_decode_head_major_gqa_flash_f16cache_contract().

◆ attention_forward_decode_head_major_gqa_flash_f16kv()

void attention_forward_decode_head_major_gqa_flash_f16kv ( const float *  q_token,
const float *  k_cache,
const float *  v_cache,
float *  out_token,
int  num_heads,
int  num_kv_heads,
int  kv_tokens,
int  cache_capacity,
int  head_dim,
int  aligned_head_dim 
)

Definition at line 6151 of file attention_kernels.c.

6161{
6162 if (!q_token || !k_cache || !v_cache || !out_token) {
6163 return;
6164 }
6165 if (num_heads <= 0 || num_kv_heads <= 0 || kv_tokens <= 0 || cache_capacity <= 0) {
6166 return;
6167 }
6168 if (kv_tokens > cache_capacity || head_dim <= 0 || aligned_head_dim <= 0) {
6169 return;
6170 }
6171
6172 const float scale = 1.0f / sqrtf((float)head_dim);
6173 const size_t head_stride = (size_t)cache_capacity * (size_t)aligned_head_dim;
6174
6175 for (int h = 0; h < num_heads; ++h) {
6176 int kv_head = (int)((long long)h * (long long)num_kv_heads / (long long)num_heads);
6177 const float *q_head = q_token + (size_t)h * (size_t)aligned_head_dim;
6178 const float *k_head = k_cache + (size_t)kv_head * head_stride;
6179 const float *v_head = v_cache + (size_t)kv_head * head_stride;
6180 float *out_head = out_token + (size_t)h * (size_t)aligned_head_dim;
6181
6183 k_head,
6184 v_head,
6185 kv_tokens,
6186 head_dim,
6187 aligned_head_dim,
6188 scale,
6189 out_head);
6190 }
6191}
static void attention_flash_query_causal_exact_f16kv(const float *q_vec, const float *k_head, const float *v_head, int kv_tokens, int head_dim, int aligned_head_dim, float scale, float *out_vec)

References attention_flash_query_causal_exact_f16kv().

◆ attention_forward_decode_head_major_gqa_flash_gemma4()

void attention_forward_decode_head_major_gqa_flash_gemma4 ( const float *  q_token,
const float *  k_cache,
const float *  v_cache,
float *  out_token,
int  num_heads,
int  num_kv_heads,
int  kv_tokens,
int  cache_capacity,
int  head_dim,
int  aligned_head_dim 
)

Definition at line 6046 of file attention_kernels.c.

6056{
6057 if (!q_token || !k_cache || !v_cache || !out_token) {
6058 return;
6059 }
6060 if (num_heads <= 0 || num_kv_heads <= 0 || kv_tokens <= 0 || cache_capacity <= 0) {
6061 return;
6062 }
6063 if (kv_tokens > cache_capacity || head_dim <= 0 || aligned_head_dim <= 0) {
6064 return;
6065 }
6066
6067 const float scale = 1.0f;
6068 const size_t head_stride = (size_t)cache_capacity * (size_t)aligned_head_dim;
6069
6070 for (int h = 0; h < num_heads; ++h) {
6071 int kv_head = (int)((long long)h * (long long)num_kv_heads / (long long)num_heads);
6072 const float *q_head = q_token + (size_t)h * (size_t)aligned_head_dim;
6073 const float *k_head = k_cache + (size_t)kv_head * head_stride;
6074 const float *v_head = v_cache + (size_t)kv_head * head_stride;
6075 float *out_head = out_token + (size_t)h * (size_t)aligned_head_dim;
6076
6077 attention_flash_decode(out_head,
6078 q_head,
6079 k_head,
6080 v_head,
6081 1,
6082 kv_tokens,
6083 1,
6084 aligned_head_dim,
6085 scale);
6086 }
6087}

References attention_flash_decode().

Referenced by attention_forward_decode_head_major_gqa_flash_sliding_gemma4(), and attention_forward_decode_head_major_shared_kv_gemma4().

◆ attention_forward_decode_head_major_gqa_flash_sliding()

void attention_forward_decode_head_major_gqa_flash_sliding ( const float *  q_token,
const float *  k_cache,
const float *  v_cache,
float *  out_token,
int  num_heads,
int  num_kv_heads,
int  kv_tokens,
int  cache_capacity,
int  head_dim,
int  aligned_head_dim,
int  sliding_window 
)

Definition at line 817 of file attention_kernels_sliding.c.

829{
830 if (!q_token || !k_cache || !v_cache || !out_token) {
831 return;
832 }
833 if (num_heads <= 0 || num_kv_heads <= 0 || cache_capacity <= 0) {
834 return;
835 }
836 if (kv_tokens <= 0 || kv_tokens > cache_capacity || head_dim <= 0 || aligned_head_dim <= 0) {
837 return;
838 }
839
840 /* Debug escape hatch:
841 * Route decode through non-sliding flash attention when requested to
842 * quickly A/B check sliding-window kernel correctness.
843 */
844 if (getenv("CK_FORCE_NONSLIDING_ATTN")) {
846 q_token, k_cache, v_cache, out_token,
847 num_heads, num_kv_heads, kv_tokens, cache_capacity,
848 head_dim, aligned_head_dim
849 );
850 return;
851 }
852
853 const float scale = 1.0f / sqrtf((float)head_dim);
854 const size_t head_stride = (size_t)cache_capacity * (size_t)aligned_head_dim;
855
856 // Compute effective KV tokens based on sliding window
857 int effective_kv_tokens = kv_tokens;
858 if (sliding_window > 0 && sliding_window < kv_tokens) {
859 effective_kv_tokens = sliding_window;
860 }
861
862 // Guard against empty window (shouldn't happen with kv_tokens >= 1)
863 if (effective_kv_tokens <= 0) {
864 return;
865 }
866
867 // Offset to start reading from the last effective_kv_tokens entries
868 int kv_start_offset = kv_tokens - effective_kv_tokens;
869
870#if defined(__AVX512F__)
871 #define SLIDING_DECODE_IMPL attention_flash_query_sliding_avx512
872#elif defined(__AVX2__)
873 #define SLIDING_DECODE_IMPL attention_flash_query_sliding_avx2
874#elif defined(__AVX__)
875 #define SLIDING_DECODE_IMPL attention_flash_query_sliding_avx
876#else
877 #define SLIDING_DECODE_IMPL attention_flash_query_sliding
878#endif
879
880 for (int h = 0; h < num_heads; ++h) {
881 int kv_head = (int)((long long)h * (long long)num_kv_heads / (long long)num_heads);
882 const float *q_head = q_token + (size_t)h * (size_t)aligned_head_dim;
883 // Offset K/V pointer to start from the first token in the sliding window
884 const float *k_head = k_cache + (size_t)kv_head * head_stride
885 + (size_t)kv_start_offset * (size_t)aligned_head_dim;
886 const float *v_head = v_cache + (size_t)kv_head * head_stride
887 + (size_t)kv_start_offset * (size_t)aligned_head_dim;
888 float *out_head = out_token + (size_t)h * (size_t)aligned_head_dim;
889
890 // Use query_pos relative to the windowed KV (last token = effective_kv_tokens - 1)
891 // sliding_window = 0 since we've already windowed via K/V pointer offset
892 SLIDING_DECODE_IMPL(q_head, k_head, v_head,
893 /*query_pos=*/effective_kv_tokens - 1,
894 /*kv_tokens=*/effective_kv_tokens,
895 head_dim, aligned_head_dim,
896 scale, out_head,
897 /*sliding_window=*/0);
898 }
899
900#undef SLIDING_DECODE_IMPL
901}
#define SLIDING_DECODE_IMPL
void attention_forward_decode_head_major_gqa_flash(const float *q_token, const float *k_cache, const float *v_cache, float *out_token, int num_heads, int num_kv_heads, int kv_tokens, int cache_capacity, int head_dim, int aligned_head_dim)

References attention_forward_decode_head_major_gqa_flash(), and SLIDING_DECODE_IMPL.

◆ attention_forward_decode_head_major_gqa_flash_sliding_gemma4()

void attention_forward_decode_head_major_gqa_flash_sliding_gemma4 ( const float *  q_token,
const float *  k_cache,
const float *  v_cache,
float *  out_token,
int  num_heads,
int  num_kv_heads,
int  kv_tokens,
int  cache_capacity,
int  head_dim,
int  aligned_head_dim,
int  sliding_window 
)

Definition at line 903 of file attention_kernels_sliding.c.

915{
916 if (!q_token || !k_cache || !v_cache || !out_token) {
917 return;
918 }
919 if (num_heads <= 0 || num_kv_heads <= 0 || cache_capacity <= 0) {
920 return;
921 }
922 if (kv_tokens <= 0 || kv_tokens > cache_capacity || head_dim <= 0 || aligned_head_dim <= 0) {
923 return;
924 }
925
926 if (getenv("CK_FORCE_NONSLIDING_ATTN")) {
928 q_token, k_cache, v_cache, out_token,
929 num_heads, num_kv_heads, kv_tokens, cache_capacity,
930 head_dim, aligned_head_dim
931 );
932 return;
933 }
934
935 const float scale = 1.0f;
936 const size_t head_stride = (size_t)cache_capacity * (size_t)aligned_head_dim;
937 int effective_kv_tokens = kv_tokens;
938 if (sliding_window > 0 && sliding_window < kv_tokens) {
939 effective_kv_tokens = sliding_window;
940 }
941 if (effective_kv_tokens <= 0) {
942 return;
943 }
944 int kv_start_offset = kv_tokens - effective_kv_tokens;
945
946#if defined(__AVX512F__)
947 #define SLIDING_DECODE_IMPL_GEMMA4 attention_flash_query_sliding_avx512
948#elif defined(__AVX2__)
949 #define SLIDING_DECODE_IMPL_GEMMA4 attention_flash_query_sliding_avx2
950#elif defined(__AVX__)
951 #define SLIDING_DECODE_IMPL_GEMMA4 attention_flash_query_sliding_avx
952#else
953 #define SLIDING_DECODE_IMPL_GEMMA4 attention_flash_query_sliding
954#endif
955
956 for (int h = 0; h < num_heads; ++h) {
957 int kv_head = (int)((long long)h * (long long)num_kv_heads / (long long)num_heads);
958 const float *q_head = q_token + (size_t)h * (size_t)aligned_head_dim;
959 const float *k_head = k_cache + (size_t)kv_head * head_stride
960 + (size_t)kv_start_offset * (size_t)aligned_head_dim;
961 const float *v_head = v_cache + (size_t)kv_head * head_stride
962 + (size_t)kv_start_offset * (size_t)aligned_head_dim;
963 float *out_head = out_token + (size_t)h * (size_t)aligned_head_dim;
964
965 SLIDING_DECODE_IMPL_GEMMA4(q_head, k_head, v_head,
966 /*query_pos=*/effective_kv_tokens - 1,
967 /*kv_tokens=*/effective_kv_tokens,
968 head_dim, aligned_head_dim,
969 scale, out_head,
970 /*sliding_window=*/0);
971 }
972
973#undef SLIDING_DECODE_IMPL_GEMMA4
974}
#define SLIDING_DECODE_IMPL_GEMMA4
void attention_forward_decode_head_major_gqa_flash_gemma4(const float *q_token, const float *k_cache, const float *v_cache, float *out_token, int num_heads, int num_kv_heads, int kv_tokens, int cache_capacity, int head_dim, int aligned_head_dim)

References attention_forward_decode_head_major_gqa_flash_gemma4(), and SLIDING_DECODE_IMPL_GEMMA4.

Referenced by attention_forward_decode_head_major_shared_kv_sliding_gemma4().

◆ attention_forward_decode_head_major_gqa_llama_regular_sliding_workspace()

void attention_forward_decode_head_major_gqa_llama_regular_sliding_workspace ( const float *  q,
const float *  k,
const float *  v,
float *  output,
int  num_heads,
int  num_kv_heads,
int  live_tokens,
int  kv_stride_tokens,
int  head_dim,
int  aligned_head_dim,
int  sliding_window,
float *  scores,
size_t  scores_bytes,
float *  value_columns,
size_t  value_columns_bytes,
float *  scaled_scores,
size_t  scaled_scores_bytes 
)

Definition at line 5975 of file attention_kernels.c.

5982{
5984 q, k, v, output, num_heads, num_kv_heads, 1, live_tokens,
5985 head_dim, aligned_head_dim, kv_stride_tokens, sliding_window,
5986 scores, scores_bytes, value_columns, value_columns_bytes,
5987 scaled_scores, scaled_scores_bytes, 0);
5988}

References ck_attention_llama_regular_impl().

◆ attention_forward_decode_head_major_gqa_regular()

void attention_forward_decode_head_major_gqa_regular ( const float *  q_token,
const float *  k_cache,
const float *  v_cache,
float *  out_token,
int  num_heads,
int  num_kv_heads,
int  kv_tokens,
int  cache_capacity,
int  head_dim,
int  aligned_head_dim 
)

WARNING: This is NOT true flash attention!

This function is named "flash" but implements regular attention with O(n) complexity. It's kept for reference and as a fallback.

TRUE flash attention is implemented in attention_flash_true.c

Test:

test_kv_cache_attention.py::TestKVCacheAttention::test_regular_decode

test_attention.py::TestAttentionForward::test_regular_decode

Regular attention decode (score-matrix version) for fallback.

After changes: make test

Definition at line 8873 of file attention_kernels.c.

8883{
8884 if (!q_token || !k_cache || !v_cache || !out_token) {
8885 return;
8886 }
8887 if (num_heads <= 0 || num_kv_heads <= 0 || kv_tokens <= 0 || cache_capacity <= 0) {
8888 return;
8889 }
8890 if (kv_tokens > cache_capacity) {
8891 return;
8892 }
8893
8894 const int strict = ck_strict_parity_enabled();
8895 const float scale = strict
8897 : 1.0f / sqrtf((float) head_dim);
8898 const size_t head_stride = (size_t)cache_capacity * (size_t)aligned_head_dim;
8899
8900 // Select SIMD implementation based on compile-time CPU features
8901#if defined(__AVX512F__)
8902 #define FLASH_QUERY_IMPL_DECODE attention_flash_query_causal_avx512
8903#elif defined(__AVX2__)
8904 #define FLASH_QUERY_IMPL_DECODE attention_flash_query_causal_avx2
8905#elif defined(__AVX__)
8906 #define FLASH_QUERY_IMPL_DECODE attention_flash_query_causal_avx
8907#else
8908 #define FLASH_QUERY_IMPL_DECODE attention_flash_query_causal
8909#endif
8910
8911#pragma omp parallel for schedule(static) if(num_heads > 1)
8912 for (int h = 0; h < num_heads; ++h) {
8913 int kv_head = (int)((long long)h * (long long)num_kv_heads / (long long)num_heads);
8914 const float *q_vec = q_token + (size_t)h * (size_t)aligned_head_dim;
8915 const float *k_head = k_cache + (size_t)kv_head * head_stride;
8916 const float *v_head = v_cache + (size_t)kv_head * head_stride;
8917 float *out_vec = out_token + (size_t)h * (size_t)aligned_head_dim;
8918
8919 if (strict) {
8921 k_head,
8922 v_head,
8923 kv_tokens,
8924 head_dim,
8925 aligned_head_dim,
8926 scale,
8927 out_vec);
8928 continue;
8929 }
8930
8931 FLASH_QUERY_IMPL_DECODE(q_vec, k_head, v_head,
8932 kv_tokens, head_dim, aligned_head_dim,
8933 scale, out_vec);
8934 }
8935
8936#undef FLASH_QUERY_IMPL_DECODE
8937}
static float ck_attention_strict_scale_f32(int head_dim)
#define FLASH_QUERY_IMPL_DECODE
int ck_strict_parity_enabled(void)

References attention_flash_query_causal_exact_f16kv(), ck_attention_strict_scale_f32(), ck_strict_parity_enabled(), and FLASH_QUERY_IMPL_DECODE.

Referenced by ck_attention_flash_decode_wrapper(), ck_layer_forward_rmsnorm_swiglu_decode_fused_attn_impl(), ck_layer_forward_rmsnorm_swiglu_decode_q4_k(), qwen2_0_5b_decode_layer_0_decode(), qwen2_0_5b_decode_layer_0_decode(), qwen2_0_5b_decode_layer_0_decode(), qwen2_0_5b_decode_layer_10_decode(), qwen2_0_5b_decode_layer_10_decode(), qwen2_0_5b_decode_layer_10_decode(), qwen2_0_5b_decode_layer_11_decode(), qwen2_0_5b_decode_layer_11_decode(), qwen2_0_5b_decode_layer_11_decode(), qwen2_0_5b_decode_layer_12_decode(), qwen2_0_5b_decode_layer_12_decode(), qwen2_0_5b_decode_layer_12_decode(), qwen2_0_5b_decode_layer_13_decode(), qwen2_0_5b_decode_layer_13_decode(), qwen2_0_5b_decode_layer_13_decode(), qwen2_0_5b_decode_layer_14_decode(), qwen2_0_5b_decode_layer_14_decode(), qwen2_0_5b_decode_layer_14_decode(), qwen2_0_5b_decode_layer_15_decode(), qwen2_0_5b_decode_layer_15_decode(), qwen2_0_5b_decode_layer_15_decode(), qwen2_0_5b_decode_layer_16_decode(), qwen2_0_5b_decode_layer_16_decode(), qwen2_0_5b_decode_layer_16_decode(), qwen2_0_5b_decode_layer_17_decode(), qwen2_0_5b_decode_layer_17_decode(), qwen2_0_5b_decode_layer_17_decode(), qwen2_0_5b_decode_layer_18_decode(), qwen2_0_5b_decode_layer_18_decode(), qwen2_0_5b_decode_layer_18_decode(), qwen2_0_5b_decode_layer_19_decode(), qwen2_0_5b_decode_layer_19_decode(), qwen2_0_5b_decode_layer_19_decode(), qwen2_0_5b_decode_layer_1_decode(), qwen2_0_5b_decode_layer_1_decode(), qwen2_0_5b_decode_layer_1_decode(), qwen2_0_5b_decode_layer_20_decode(), qwen2_0_5b_decode_layer_20_decode(), qwen2_0_5b_decode_layer_20_decode(), qwen2_0_5b_decode_layer_21_decode(), qwen2_0_5b_decode_layer_21_decode(), qwen2_0_5b_decode_layer_21_decode(), qwen2_0_5b_decode_layer_22_decode(), qwen2_0_5b_decode_layer_22_decode(), qwen2_0_5b_decode_layer_22_decode(), qwen2_0_5b_decode_layer_23_decode(), qwen2_0_5b_decode_layer_23_decode(), qwen2_0_5b_decode_layer_23_decode(), qwen2_0_5b_decode_layer_2_decode(), qwen2_0_5b_decode_layer_2_decode(), qwen2_0_5b_decode_layer_2_decode(), qwen2_0_5b_decode_layer_3_decode(), qwen2_0_5b_decode_layer_3_decode(), qwen2_0_5b_decode_layer_3_decode(), qwen2_0_5b_decode_layer_4_decode(), qwen2_0_5b_decode_layer_4_decode(), qwen2_0_5b_decode_layer_4_decode(), qwen2_0_5b_decode_layer_5_decode(), qwen2_0_5b_decode_layer_5_decode(), qwen2_0_5b_decode_layer_5_decode(), qwen2_0_5b_decode_layer_6_decode(), qwen2_0_5b_decode_layer_6_decode(), qwen2_0_5b_decode_layer_6_decode(), qwen2_0_5b_decode_layer_7_decode(), qwen2_0_5b_decode_layer_7_decode(), qwen2_0_5b_decode_layer_7_decode(), qwen2_0_5b_decode_layer_8_decode(), qwen2_0_5b_decode_layer_8_decode(), qwen2_0_5b_decode_layer_8_decode(), qwen2_0_5b_decode_layer_9_decode(), qwen2_0_5b_decode_layer_9_decode(), and qwen2_0_5b_decode_layer_9_decode().

◆ attention_forward_decode_head_major_shared_kv_gemma4()

void attention_forward_decode_head_major_shared_kv_gemma4 ( const float *  q_token,
const float *  k_cache,
const float *  v_cache,
float *  out_token,
int  num_heads,
int  kv_tokens,
int  cache_capacity,
int  head_dim,
int  aligned_head_dim 
)

Definition at line 6135 of file attention_kernels.c.

6144{
6146 q_token, k_cache, v_cache, out_token, num_heads, num_heads,
6147 kv_tokens, cache_capacity, head_dim, aligned_head_dim
6148 );
6149}
void attention_forward_decode_head_major_gqa_flash_gemma4(const float *q_token, const float *k_cache, const float *v_cache, float *out_token, int num_heads, int num_kv_heads, int kv_tokens, int cache_capacity, int head_dim, int aligned_head_dim)

References attention_forward_decode_head_major_gqa_flash_gemma4().

◆ attention_forward_decode_head_major_shared_kv_sliding_gemma4()

void attention_forward_decode_head_major_shared_kv_sliding_gemma4 ( const float *  q_token,
const float *  k_cache,
const float *  v_cache,
float *  out_token,
int  num_heads,
int  kv_tokens,
int  cache_capacity,
int  head_dim,
int  aligned_head_dim,
int  sliding_window 
)

Definition at line 976 of file attention_kernels_sliding.c.

987{
989 q_token, k_cache, v_cache, out_token, num_heads, num_heads,
990 kv_tokens, cache_capacity, head_dim, aligned_head_dim, sliding_window
991 );
992}
void attention_forward_decode_head_major_gqa_flash_sliding_gemma4(const float *q_token, const float *k_cache, const float *v_cache, float *out_token, int num_heads, int num_kv_heads, int kv_tokens, int cache_capacity, int head_dim, int aligned_head_dim, int sliding_window)

References attention_forward_decode_head_major_gqa_flash_sliding_gemma4().

◆ attention_forward_full_head_major_gqa_exact_strided()

void attention_forward_full_head_major_gqa_exact_strided ( const float *  q,
const float *  k,
const float *  v,
float *  output,
int  num_heads,
int  num_kv_heads,
int  num_tokens,
int  head_dim,
int  aligned_head_dim,
int  kv_stride_tokens 
)

Definition at line 5372 of file attention_kernels.c.

5382{
5383 if (!q || !k || !v || !output) {
5384 return;
5385 }
5386 if (num_heads <= 0 || num_kv_heads <= 0 || num_tokens <= 0) {
5387 return;
5388 }
5389 if (kv_stride_tokens < num_tokens) {
5390 return;
5391 }
5392
5393 const float scale = ck_strict_parity_enabled()
5395 : 1.0f / sqrtf((float) head_dim);
5396 const int T = num_tokens;
5397 const size_t kv_head_stride = (size_t) kv_stride_tokens * (size_t) aligned_head_dim;
5398 const int debug_layer_id = ck_strict_parity_enabled() ? ck_attention_vec_dump_next_layer_id() : -1;
5399 float *score_row = (float *) alloca((size_t) T * sizeof(float));
5400 float *v_cols = (float *) alloca((size_t) head_dim * (size_t) T * sizeof(float));
5401 for (int h = 0; h < num_heads; ++h) {
5402 const int kv_head = (int) ((long long) h * (long long) num_kv_heads / (long long) num_heads);
5403 const float *k_head = k + (size_t) kv_head * kv_head_stride;
5404 const float *v_head = v + (size_t) kv_head * kv_head_stride;
5405
5406#if CK_ENABLE_LLAMA_CPP_PARITY
5407 float *out_head = output + (size_t) h * (size_t) T * (size_t) aligned_head_dim;
5410 q + (size_t) h * (size_t) T * (size_t) aligned_head_dim,
5411 k_head,
5412 v_head,
5413 out_head,
5414 T,
5415 head_dim,
5416 aligned_head_dim,
5417 scale)) {
5418 ck_attention_trace("regular_graph_oracle", debug_layer_id, h);
5419 continue;
5420 }
5421#endif
5422
5423 for (int d = 0; d < head_dim; ++d) {
5424 float *dst_col = v_cols + (size_t) d * (size_t) T;
5425 for (int j = 0; j < T; ++j) {
5426 dst_col[j] = v_head[(size_t) j * (size_t) aligned_head_dim + (size_t) d];
5427 }
5428 }
5429
5430 for (int i = 0; i < T; ++i) {
5431 const float *q_vec = q + qkv_index(h, i, 0, T, aligned_head_dim);
5432 float *out_vec = output + qkv_index(h, i, 0, T, aligned_head_dim);
5434 k_head,
5435 v_cols,
5436 T,
5437 head_dim,
5438 aligned_head_dim,
5439 scale,
5440 score_row,
5441 out_vec,
5442 debug_layer_id,
5443 h,
5444 i);
5445 }
5446 }
5447}
static int ck_attention_vec_dump_next_layer_id(void)
static void attention_query_full_exact_regular(const float *q_vec, const float *k_head, const float *v_cols, int kv_tokens, int head_dim, int aligned_head_dim, float scale, float *score_row, float *out_vec, int layer_id, int head_id, int query_id)
static void ck_attention_trace(const char *branch, int layer_id, int head_id)
int ck_attention_head_full_ggml_graph_oracle_regular(const float *q_head, const float *k_head, const float *v_head, float *out_head, int num_tokens, int head_dim, int aligned_head_dim, float scale)

References attention_query_full_exact_regular(), ck_attention_head_full_ggml_graph_oracle_regular(), ck_attention_strict_scale_f32(), ck_attention_trace(), ck_attention_vec_dump_next_layer_id(), ck_strict_parity_enabled(), and qkv_index().

◆ attention_forward_full_head_major_gqa_flash()

void attention_forward_full_head_major_gqa_flash ( const float *  q,
const float *  k,
const float *  v,
float *  output,
int  num_heads,
int  num_kv_heads,
int  num_tokens,
int  head_dim,
int  aligned_head_dim 
)

Definition at line 4391 of file attention_kernels.c.

4400{
4402 num_heads, num_kv_heads,
4403 num_tokens, head_dim,
4404 aligned_head_dim,
4405 /*kv_stride_tokens=*/num_tokens,
4406 /*causal=*/0,
4407 /*round_full_kv_fp16=*/1,
4408 /*output_token_major=*/0,
4409 1.0f / sqrtf((float)head_dim));
4410}

References attention_forward_head_major_gqa_flash_impl().

◆ attention_forward_full_head_major_gqa_flash_strided()

void attention_forward_full_head_major_gqa_flash_strided ( const float *  q,
const float *  k,
const float *  v,
float *  output,
int  num_heads,
int  num_kv_heads,
int  num_tokens,
int  head_dim,
int  aligned_head_dim,
int  kv_stride_tokens 
)

Definition at line 4467 of file attention_kernels.c.

4477{
4479 num_heads, num_kv_heads,
4480 num_tokens, head_dim,
4481 aligned_head_dim,
4482 kv_stride_tokens,
4483 /*causal=*/0,
4484 /*round_full_kv_fp16=*/1,
4485 /*output_token_major=*/0,
4486 1.0f / sqrtf((float)head_dim));
4487}

References attention_forward_head_major_gqa_flash_impl().

◆ attention_forward_full_head_major_gqa_flash_strided_bf16_storage()

void attention_forward_full_head_major_gqa_flash_strided_bf16_storage ( const float *  q,
const float *  k,
const float *  v,
float *  output,
int  num_heads,
int  num_kv_heads,
int  num_tokens,
int  head_dim,
int  aligned_head_dim,
int  kv_stride_tokens 
)

Definition at line 4920 of file attention_kernels.c.

4931{
4933 q, k, v, output,
4934 num_heads, num_kv_heads, num_tokens, head_dim,
4935 aligned_head_dim, kv_stride_tokens,
4936 /*causal=*/0,
4937 /*round_full_kv_fp16=*/0,
4938 /*output_token_major=*/0,
4939 1.0f / sqrtf((float)head_dim)
4940 );
4941 const size_t count = (size_t)num_heads * (size_t)num_tokens
4942 * (size_t)aligned_head_dim;
4943 for (size_t i = 0; i < count; ++i) {
4944 output[i] = bf16_to_float(float_to_bf16(output[i]));
4945 }
4946}

References attention_forward_head_major_gqa_flash_impl(), bf16_to_float(), and float_to_bf16().

◆ attention_forward_full_head_major_gqa_flash_strided_gemma4()

void attention_forward_full_head_major_gqa_flash_strided_gemma4 ( const float *  q,
const float *  k,
const float *  v,
float *  output,
int  num_heads,
int  num_kv_heads,
int  num_tokens,
int  head_dim,
int  aligned_head_dim,
int  kv_stride_tokens 
)

Definition at line 5084 of file attention_kernels.c.

5094{
5095 (void)head_dim;
5097 num_heads, num_kv_heads,
5098 num_tokens, head_dim,
5099 aligned_head_dim,
5100 kv_stride_tokens,
5101 /*causal=*/0,
5102 /*round_full_kv_fp16=*/1,
5103 /*output_token_major=*/0,
5104 1.0f);
5105}

References attention_forward_head_major_gqa_flash_impl().

◆ attention_forward_full_head_major_gqa_ggml_strided()

void attention_forward_full_head_major_gqa_ggml_strided ( const float *  q,
const float *  k,
const float *  v,
float *  output,
int  num_heads,
int  num_kv_heads,
int  num_tokens,
int  head_dim,
int  aligned_head_dim,
int  kv_stride_tokens 
)

Definition at line 5690 of file attention_kernels.c.

5700{
5701 if (num_heads <= 0 || num_tokens <= 0 || head_dim <= 0 ||
5702 (size_t) num_heads > SIZE_MAX / (size_t) num_tokens ||
5703 (size_t) head_dim > SIZE_MAX / (size_t) num_tokens) {
5704 return;
5705 }
5706 const size_t score_elements = (size_t) num_heads * (size_t) num_tokens;
5707 const size_t columns_per_head = (size_t) head_dim * (size_t) num_tokens;
5708 if ((size_t) num_heads > SIZE_MAX / columns_per_head) return;
5709 const size_t column_elements = (size_t) num_heads * columns_per_head;
5710 if (score_elements > SIZE_MAX - column_elements ||
5711 score_elements + column_elements > SIZE_MAX - (size_t) num_tokens) return;
5712 const size_t total_elements = score_elements + column_elements + (size_t) num_tokens;
5713 if (total_elements > SIZE_MAX / sizeof(float)) return;
5714 float *workspace = (float *) malloc(total_elements * sizeof(float));
5715 if (!workspace) return;
5716 float *score_rows = workspace;
5717 float *v_columns = score_rows + score_elements;
5718 float *probability_row = v_columns + column_elements;
5720 q, k, v, output, num_heads, num_kv_heads, num_tokens, head_dim,
5721 aligned_head_dim, kv_stride_tokens,
5722 score_rows, score_elements * sizeof(float),
5723 v_columns, column_elements * sizeof(float),
5724 probability_row, (size_t) num_tokens * sizeof(float));
5725 free(workspace);
5726}
void attention_forward_full_head_major_gqa_ggml_strided_workspace(const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int kv_stride_tokens, float *score_rows, size_t score_rows_bytes, float *v_columns, size_t v_columns_bytes, float *probability_row, size_t probability_row_bytes)

References attention_forward_full_head_major_gqa_ggml_strided_workspace().

◆ attention_forward_full_head_major_gqa_ggml_strided_workspace()

void attention_forward_full_head_major_gqa_ggml_strided_workspace ( const float *  q,
const float *  k,
const float *  v,
float *  output,
int  num_heads,
int  num_kv_heads,
int  num_tokens,
int  head_dim,
int  aligned_head_dim,
int  kv_stride_tokens,
float *  score_rows,
size_t  score_rows_bytes,
float *  v_columns,
size_t  v_columns_bytes,
float *  probability_row,
size_t  probability_row_bytes 
)

Definition at line 5449 of file attention_kernels.c.

5466{
5467 if (!q || !k || !v || !output) {
5468 return;
5469 }
5470 if (num_heads <= 0 || num_kv_heads <= 0 || num_tokens <= 0) {
5471 return;
5472 }
5473 if (kv_stride_tokens < num_tokens) {
5474 return;
5475 }
5476
5477 const size_t T = (size_t) num_tokens;
5478 if ((size_t) num_heads > SIZE_MAX / T ||
5479 (size_t) head_dim > SIZE_MAX / T) {
5480 return;
5481 }
5482 const size_t score_elements = (size_t) num_heads * T;
5483 const size_t columns_per_head = (size_t) head_dim * T;
5484 if ((size_t) num_heads > SIZE_MAX / columns_per_head ||
5485 score_elements > SIZE_MAX / sizeof(float) ||
5486 columns_per_head * (size_t) num_heads > SIZE_MAX / sizeof(float) ||
5487 T > SIZE_MAX / sizeof(float)) {
5488 return;
5489 }
5490 const size_t column_elements = columns_per_head * (size_t) num_heads;
5491 if (!score_rows || score_rows_bytes < score_elements * sizeof(float) ||
5492 !v_columns || v_columns_bytes < column_elements * sizeof(float) ||
5493 !probability_row || probability_row_bytes < T * sizeof(float)) {
5494 return;
5495 }
5496
5497 const int strict = ck_strict_parity_enabled();
5498 const float scale = strict
5500 : 1.0f / sqrtf((float) head_dim);
5501 const int token_count = num_tokens;
5502 const size_t kv_head_stride = (size_t) kv_stride_tokens * (size_t) aligned_head_dim;
5503 const int debug_layer_id = strict ? ck_attention_vec_dump_next_layer_id() : -1;
5504#if CK_ENABLE_LLAMA_CPP_PARITY
5505 ck_ggml_vec_dot_f32_fn dot_fn = NULL;
5506 ck_ggml_vec_soft_max_f32_fn softmax_fn = NULL;
5507 ck_ggml_compute_forward_mul_mat_fn mul_mat_fn = NULL;
5508 ck_ggml_compute_forward_soft_max_fn softmax_compute_fn = NULL;
5509 if (strict) {
5511 k,
5512 v,
5513 output,
5514 num_heads,
5515 num_kv_heads,
5516 num_tokens,
5517 head_dim,
5518 aligned_head_dim,
5519 kv_stride_tokens,
5520 scale)) {
5521 return;
5522 }
5523 dot_fn = ck_resolve_ggml_vec_dot_f32();
5524 softmax_fn = ck_resolve_ggml_vec_soft_max_f32();
5525 mul_mat_fn = ck_resolve_ggml_compute_forward_mul_mat();
5526 softmax_compute_fn = ck_resolve_ggml_compute_forward_soft_max();
5527 }
5528#endif
5529 if (strict) {
5530 float *score_row = score_rows;
5531 float *v_cols = v_columns;
5532#if CK_ENABLE_LLAMA_CPP_PARITY
5533 float *prob_row = probability_row;
5534#endif
5535
5536 for (int h = 0; h < num_heads; ++h) {
5537 const int kv_head = (int) ((long long) h * (long long) num_kv_heads / (long long) num_heads);
5538 const float *k_head = k + (size_t) kv_head * kv_head_stride;
5539 const float *v_head = v + (size_t) kv_head * kv_head_stride;
5540
5541#if CK_ENABLE_LLAMA_CPP_PARITY
5542 float *out_head = output + (size_t) h * (size_t) T * (size_t) aligned_head_dim;
5544 q + (size_t) h * (size_t) T * (size_t) aligned_head_dim,
5545 k_head,
5546 v_head,
5547 out_head,
5548 token_count,
5549 head_dim,
5550 aligned_head_dim,
5551 scale)) {
5552 continue;
5553 }
5554#endif
5555
5556 for (int d = 0; d < head_dim; ++d) {
5557 float *dst_col = v_cols + (size_t) d * (size_t) token_count;
5558 for (int j = 0; j < token_count; ++j) {
5559 dst_col[j] = v_head[(size_t) j * (size_t) aligned_head_dim + (size_t) d];
5560 }
5561 }
5562
5563#if CK_ENABLE_LLAMA_CPP_PARITY
5564 if (dot_fn && softmax_fn && ck_attention_ggml_out_graph_enabled()) {
5565 if (attention_head_full_dyn_ggml_regular_graph_out(
5566 q + (size_t) h * (size_t) T * (size_t) aligned_head_dim,
5567 k_head,
5568 v_cols,
5569 token_count,
5570 head_dim,
5571 aligned_head_dim,
5572 scale,
5573 score_row,
5574 prob_row,
5575 out_head,
5576 dot_fn,
5577 softmax_fn,
5578 debug_layer_id,
5579 h)) {
5580 if (token_count > 0) {
5581 ck_attention_trace("dyn_ggml_regular_graph_out", debug_layer_id, h);
5582 ck_attention_trace_float("scale", debug_layer_id, h, scale);
5583 }
5584 continue;
5585 }
5586 }
5587#endif
5588
5589 for (int i = 0; i < token_count; ++i) {
5590 const float *q_vec = q + qkv_index(h, i, 0, token_count, aligned_head_dim);
5591 float *out_vec = output + qkv_index(h, i, 0, token_count, aligned_head_dim);
5592#if CK_ENABLE_LLAMA_CPP_PARITY
5593 if (dot_fn && softmax_fn) {
5594 if (i == 0) {
5595 ck_attention_trace("dyn_ggml_regular", debug_layer_id, h);
5596 ck_attention_trace_float("scale", debug_layer_id, h, scale);
5597 }
5598 attention_query_full_dyn_ggml_regular(q_vec,
5599 k_head,
5600 v_cols,
5601 token_count,
5602 head_dim,
5603 aligned_head_dim,
5604 scale,
5605 score_row,
5606 prob_row,
5607 out_vec,
5608 dot_fn,
5609 softmax_fn,
5610 debug_layer_id,
5611 h,
5612 i);
5613 } else if (dot_fn && mul_mat_fn && softmax_compute_fn) {
5614 if (i == 0) {
5615 ck_attention_trace("ggml_compute_regular", debug_layer_id, h);
5616 }
5617 attention_query_full_ggml_compute_regular(q_vec,
5618 k_head,
5619 v_cols,
5620 token_count,
5621 head_dim,
5622 aligned_head_dim,
5623 scale,
5624 score_row,
5625 prob_row,
5626 out_vec,
5627 dot_fn,
5628 mul_mat_fn,
5629 softmax_compute_fn);
5630 } else
5631#endif
5632 {
5633 if (i == 0) {
5634 ck_attention_trace("ggml_regular", debug_layer_id, h);
5635 }
5637 k_head,
5638 v_cols,
5639 token_count,
5640 head_dim,
5641 aligned_head_dim,
5642 scale,
5643 score_row,
5644 out_vec,
5645 debug_layer_id,
5646 h,
5647 i);
5648 }
5649 }
5650 }
5651 return;
5652 }
5653
5654#pragma omp parallel for schedule(static) if(num_heads > 1)
5655 for (int h = 0; h < num_heads; ++h) {
5656 float *score_row = score_rows + (size_t) h * (size_t) token_count;
5657 float *v_cols = v_columns + (size_t) h * (size_t) head_dim * (size_t) token_count;
5658 const int kv_head = (int) ((long long) h * (long long) num_kv_heads / (long long) num_heads);
5659 const float *k_head = k + (size_t) kv_head * kv_head_stride;
5660 const float *v_head = v + (size_t) kv_head * kv_head_stride;
5661
5662 if (v_cols) {
5663 for (int d = 0; d < head_dim; ++d) {
5664 float *dst_col = v_cols + (size_t) d * (size_t) token_count;
5665 for (int j = 0; j < token_count; ++j) {
5666 dst_col[j] = v_head[(size_t) j * (size_t) aligned_head_dim + (size_t) d];
5667 }
5668 }
5669 }
5670
5671 for (int i = 0; i < token_count; ++i) {
5672 const float *q_vec = q + qkv_index(h, i, 0, token_count, aligned_head_dim);
5673 float *out_vec = output + qkv_index(h, i, 0, token_count, aligned_head_dim);
5675 k_head,
5676 v_cols,
5677 token_count,
5678 head_dim,
5679 aligned_head_dim,
5680 scale,
5681 score_row,
5682 out_vec,
5683 -1,
5684 h,
5685 i);
5686 }
5687 }
5688}
static void ck_attention_trace_float(const char *tag, int layer_id, int head_id, float value)
static int ck_attention_ggml_out_graph_enabled(void)
static void attention_query_full_ggml_regular(const float *q_vec, const float *k_head, const float *v_cols, int kv_tokens, int head_dim, int aligned_head_dim, float scale, float *score_row, float *out_vec, int layer_id, int head_id, int query_id)
int ck_attention_full_ggml_graph_oracle_multihead(const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int kv_stride_tokens, float scale)

References attention_query_full_ggml_regular(), ck_attention_full_ggml_graph_oracle_multihead(), ck_attention_ggml_out_graph_enabled(), ck_attention_head_full_ggml_graph_oracle_regular(), ck_attention_strict_scale_f32(), ck_attention_trace(), ck_attention_trace_float(), ck_attention_vec_dump_next_layer_id(), ck_strict_parity_enabled(), and qkv_index().

Referenced by attention_forward_full_head_major_gqa_ggml_strided().

◆ attention_forward_full_head_major_gqa_pytorch_cpu_flash_bf16_storage()

void attention_forward_full_head_major_gqa_pytorch_cpu_flash_bf16_storage ( const float *  q,
const float *  k,
const float *  v,
float *  output,
int  num_heads,
int  num_kv_heads,
int  num_tokens,
int  head_dim,
int  aligned_head_dim,
int  kv_stride_tokens 
)

Definition at line 4973 of file attention_kernels.c.

4984{
4986 q, k, v, output, num_heads, num_kv_heads, num_tokens,
4987 head_dim, aligned_head_dim, kv_stride_tokens,
4988 /*output_token_major=*/0)) {
4989 return;
4990 }
4991 fprintf(stderr,
4992 "HARD KERNEL CONTRACT FAULT: PyTorch CPU-flash BF16 attention "
4993 "requires AMX-BF16, AVX-512, D=72/A=72 and a token multiple of 16; "
4994 "no numerically different fallback is permitted\n");
4995 abort();
4996}
static int ck_attention_full_bf16_pytorch_flash(const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int kv_stride_tokens, int output_token_major)

References ck_attention_full_bf16_pytorch_flash().

◆ attention_forward_full_head_major_gqa_pytorch_cpu_flash_bf16_storage_token_output()

void attention_forward_full_head_major_gqa_pytorch_cpu_flash_bf16_storage_token_output ( const float *  q,
const float *  k,
const float *  v,
float *  output,
int  num_heads,
int  num_kv_heads,
int  num_tokens,
int  head_dim,
int  aligned_head_dim,
int  kv_stride_tokens 
)

Definition at line 4998 of file attention_kernels.c.

5009{
5011 q, k, v, output, num_heads, num_kv_heads, num_tokens,
5012 head_dim, aligned_head_dim, kv_stride_tokens,
5013 /*output_token_major=*/1)) {
5014 return;
5015 }
5016 fprintf(stderr,
5017 "HARD KERNEL CONTRACT FAULT: PyTorch CPU-flash BF16 token-output "
5018 "attention requires AMX-BF16, AVX-512, D=72/A=72 and a token "
5019 "multiple of 16; no numerically different fallback is permitted\n");
5020 abort();
5021}

References ck_attention_full_bf16_pytorch_flash().

◆ attention_forward_full_head_major_gqa_sdpa_bf16_storage()

void attention_forward_full_head_major_gqa_sdpa_bf16_storage ( const float *  q,
const float *  k,
const float *  v,
float *  output,
int  num_heads,
int  num_kv_heads,
int  num_tokens,
int  head_dim,
int  aligned_head_dim,
int  kv_stride_tokens 
)

Definition at line 4948 of file attention_kernels.c.

4959{
4961 q, k, v, output, num_heads, num_kv_heads, num_tokens,
4962 head_dim, aligned_head_dim, kv_stride_tokens)) {
4963 const size_t count = (size_t)num_heads * (size_t)num_tokens
4964 * (size_t)aligned_head_dim;
4965 for (size_t i = 0; i < count; ++i) {
4966 output[i] = bf16_to_float(float_to_bf16(output[i]));
4967 }
4968 return;
4969 }
4970 fprintf(stderr, "CK numerical contract failure: BF16 tiled SDPA received invalid dimensions or could not allocate scratch\n");
4971}
static int ck_attention_full_bf16_sdpa_tiled(const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int kv_stride_tokens)

References bf16_to_float(), ck_attention_full_bf16_sdpa_tiled(), and float_to_bf16().

◆ attention_forward_full_head_major_gqa_tiled336_f16kv_fp32_strided()

void attention_forward_full_head_major_gqa_tiled336_f16kv_fp32_strided ( const float *  q,
const float *  k,
const float *  v,
float *  output,
int  num_heads,
int  num_kv_heads,
int  num_tokens,
int  head_dim,
int  aligned_head_dim,
int  kv_stride_tokens 
)

Definition at line 3564 of file attention_kernels.c.

3575{
3577 q, k, v, output, num_heads, num_kv_heads, num_tokens,
3578 head_dim, aligned_head_dim, kv_stride_tokens, CK_GGML_FA_TILE_Q_LARGE);
3579}
#define CK_GGML_FA_TILE_Q_LARGE
static void ck_attention_forward_full_head_major_gqa_tiled_f16kv_fp32_strided(const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int kv_stride_tokens, int query_tile_size)

References ck_attention_forward_full_head_major_gqa_tiled_f16kv_fp32_strided(), and CK_GGML_FA_TILE_Q_LARGE.

◆ attention_forward_full_head_major_gqa_tiled64_f16kv_fp32_strided()

void attention_forward_full_head_major_gqa_tiled64_f16kv_fp32_strided ( const float *  q,
const float *  k,
const float *  v,
float *  output,
int  num_heads,
int  num_kv_heads,
int  num_tokens,
int  head_dim,
int  aligned_head_dim,
int  kv_stride_tokens 
)

Definition at line 3547 of file attention_kernels.c.

3558{
3560 q, k, v, output, num_heads, num_kv_heads, num_tokens,
3561 head_dim, aligned_head_dim, kv_stride_tokens, CK_GGML_FA_TILE_Q);
3562}

References ck_attention_forward_full_head_major_gqa_tiled_f16kv_fp32_strided(), and CK_GGML_FA_TILE_Q.

◆ attention_forward_full_head_major_gqa_tiled_f16kv_fp32_strided()

void attention_forward_full_head_major_gqa_tiled_f16kv_fp32_strided ( const float *  q,
const float *  k,
const float *  v,
float *  output,
int  num_heads,
int  num_kv_heads,
int  num_tokens,
int  head_dim,
int  aligned_head_dim,
int  kv_stride_tokens 
)

Definition at line 3527 of file attention_kernels.c.

3538{
3539 const int query_tile_size = num_tokens >= CK_GGML_FA_TILE_Q_LARGE_MIN_TOKENS
3543 q, k, v, output, num_heads, num_kv_heads, num_tokens,
3544 head_dim, aligned_head_dim, kv_stride_tokens, query_tile_size);
3545}
#define CK_GGML_FA_TILE_Q_LARGE_MIN_TOKENS

References ck_attention_forward_full_head_major_gqa_tiled_f16kv_fp32_strided(), CK_GGML_FA_TILE_Q, CK_GGML_FA_TILE_Q_LARGE, and CK_GGML_FA_TILE_Q_LARGE_MIN_TOKENS.

◆ attention_forward_mixed_visual_chunk_head_major_gqa_flash_strided_gemma4()

void attention_forward_mixed_visual_chunk_head_major_gqa_flash_strided_gemma4 ( const float *  q,
const float *  k,
const float *  v,
float *  output,
int  num_heads,
int  num_kv_heads,
int  num_tokens,
int  head_dim,
int  aligned_head_dim,
int  kv_stride_tokens,
int  visual_start,
int  visual_tokens 
)

Definition at line 5216 of file attention_kernels.c.

5221{
5223 q, k, v, output, num_heads, num_kv_heads, num_tokens, head_dim,
5224 aligned_head_dim, kv_stride_tokens, visual_start, visual_tokens,
5225 /*output_token_major=*/0);
5226}
static void attention_forward_mixed_visual_chunk_head_major_gqa_flash_strided_gemma4_impl(const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int kv_stride_tokens, int visual_start, int visual_tokens, int output_token_major)

References attention_forward_mixed_visual_chunk_head_major_gqa_flash_strided_gemma4_impl().

◆ attention_forward_mixed_visual_chunk_head_major_gqa_flash_strided_gemma4_token_output()

void attention_forward_mixed_visual_chunk_head_major_gqa_flash_strided_gemma4_token_output ( const float *  q,
const float *  k,
const float *  v,
float *  output,
int  num_heads,
int  num_kv_heads,
int  num_tokens,
int  head_dim,
int  aligned_head_dim,
int  kv_stride_tokens,
int  visual_start,
int  visual_tokens 
)

Definition at line 5228 of file attention_kernels.c.

5233{
5235 q, k, v, output, num_heads, num_kv_heads, num_tokens, head_dim,
5236 aligned_head_dim, kv_stride_tokens, visual_start, visual_tokens,
5237 /*output_token_major=*/1);
5238}

References attention_forward_mixed_visual_chunk_head_major_gqa_flash_strided_gemma4_impl().

◆ attention_forward_query_key_head_major_f32()

int attention_forward_query_key_head_major_f32 ( const float *  query,
const float *  key,
const float *  value,
float *  output,
float *  score_scratch,
int  num_heads,
int  query_tokens,
int  key_tokens,
int  head_dim,
float  scale 
)

Definition at line 210 of file attention_kernels.c.

221{
223 query, key, value, output, score_scratch, NULL, num_heads,
224 query_tokens, key_tokens, head_dim, scale);
225}
static int ck_attention_forward_query_key_head_major_f32_run(const float *query, const float *key, const float *value, float *output, float *score_scratch, float *key_transpose_scratch, int num_heads, int query_tokens, int key_tokens, int head_dim, float scale)

References ck_attention_forward_query_key_head_major_f32_run().

◆ attention_forward_query_key_head_major_f32_packed_k()

int attention_forward_query_key_head_major_f32_packed_k ( const float *  query,
const float *  key,
const float *  value,
float *  output,
float *  score_scratch,
float *  key_transpose_scratch,
int  num_heads,
int  query_tokens,
int  key_tokens,
int  head_dim,
float  scale 
)

Definition at line 227 of file attention_kernels.c.

239{
240 if (key_transpose_scratch == NULL) return -1;
242 query, key, value, output, score_scratch, key_transpose_scratch,
243 num_heads, query_tokens, key_tokens, head_dim, scale);
244}

References ck_attention_forward_query_key_head_major_f32_run().

◆ attention_forward_query_key_head_major_tiled_f16kv_fp32()

int attention_forward_query_key_head_major_tiled_f16kv_fp32 ( const float *  query,
const float *  key,
const float *  value,
float *  output,
int  num_heads,
int  query_tokens,
int  key_tokens,
int  head_dim,
float  scale 
)

Definition at line 3581 of file attention_kernels.c.

3591{
3592 if (!query || !key || !value || !output || num_heads <= 0 ||
3593 query_tokens <= 0 || key_tokens != query_tokens || head_dim <= 0) {
3594 return -1;
3595 }
3596
3597 const float contract_scale = ck_attention_strict_scale_f32(head_dim);
3598 if (scale != contract_scale) {
3599 return -1;
3600 }
3601
3602 const int query_tile_size = query_tokens >= CK_GGML_FA_TILE_Q_LARGE_MIN_TOKENS
3606 query, key, value, output,
3607 num_heads, num_heads, query_tokens,
3608 head_dim, head_dim, key_tokens, query_tile_size);
3609 return 0;
3610}

References ck_attention_forward_full_head_major_gqa_tiled_f16kv_fp32_strided(), ck_attention_strict_scale_f32(), CK_GGML_FA_TILE_Q, CK_GGML_FA_TILE_Q_LARGE, and CK_GGML_FA_TILE_Q_LARGE_MIN_TOKENS.

◆ attention_forward_sparse_token_major_gqa_bf16cache_pytorch_cpu_flash_contract()

void attention_forward_sparse_token_major_gqa_bf16cache_pytorch_cpu_flash_contract ( const float *  query,
const uint16_t *  key_cache,
const uint16_t *  value_cache,
const float *  selected_indices,
float *  output,
float *  score_scratch,
int  rows,
int  query_heads,
int  kv_heads,
int  head_dim,
int  selection_width,
int  context_length,
int  position 
)

Definition at line 8452 of file attention_kernels.c.

8466{
8467 (void)score_scratch;
8468 if (!query || !key_cache || !value_cache || !selected_indices || !output ||
8469 rows <= 0 || query_heads <= 0 || kv_heads <= 0 || head_dim <= 0 ||
8470 selection_width <= 0 || context_length <= 0 || position < 0 ||
8471 position + rows > context_length || query_heads % kv_heads != 0) {
8472 fprintf(stderr, "CK sparse BF16 CPU-flash attention: invalid contract\n");
8473 abort();
8474 }
8475
8476#if defined(__AVX512F__)
8477 for (int row = 0; row < rows; ++row) {
8478 const int visible_tokens = position + row + 1;
8479 const ck_attention_status_t status =
8480 ck_attention_decode_bf16_pytorch_cpu_flash_masked(
8481 query + (size_t)row * (size_t)query_heads * (size_t)head_dim,
8482 key_cache, value_cache,
8483 output + (size_t)row * (size_t)query_heads * (size_t)head_dim,
8484 selected_indices + (size_t)row * (size_t)selection_width,
8485 selection_width, query_heads, kv_heads, visible_tokens,
8486 context_length, head_dim, head_dim);
8487 if (status != CK_ATTENTION_STATUS_OK) {
8488 fprintf(stderr,
8489 "CK sparse BF16 CPU-flash attention unavailable (status=%d)\n",
8490 (int)status);
8491 abort();
8492 }
8493 }
8494#else
8495 fprintf(stderr,
8496 "CK sparse BF16 CPU-flash attention requires AVX-512F; "
8497 "no numerically different fallback is permitted\n");
8498 abort();
8499#endif
8500}

References CK_ATTENTION_STATUS_OK.

◆ attn_gate_sigmoid_mul_backward()

void attn_gate_sigmoid_mul_backward ( const float *  d_out,
const float *  x,
const float *  gate,
float *  d_x,
float *  d_gate,
int  rows,
int  num_heads,
int  state_dim 
)

Definition at line 187 of file hybrid_attention_kernels.c.

194 {
195 const int dim = num_heads * state_dim;
196 for (int row = 0; row < rows; ++row) {
197 const float *d_out_row = d_out + (size_t) row * (size_t) dim;
198 const float *x_row = x + (size_t) row * (size_t) dim;
199 const float *gate_row = gate + (size_t) row * (size_t) dim;
200 float *d_x_row = d_x + (size_t) row * (size_t) dim;
201 float *d_gate_row = d_gate + (size_t) row * (size_t) dim;
202 for (int col = 0; col < dim; ++col) {
203 const float sig = hybrid_sigmoid(gate_row[col]);
204 d_x_row[col] = d_out_row[col] * sig;
205 d_gate_row[col] = d_out_row[col] * x_row[col] * sig * (1.0f - sig);
206 }
207 }
208}
static float hybrid_sigmoid(float x)

References hybrid_sigmoid().

◆ attn_gate_sigmoid_mul_forward()

void attn_gate_sigmoid_mul_forward ( const float *  x,
const float *  gate,
float *  out,
int  rows,
int  num_heads,
int  state_dim 
)

Definition at line 116 of file hybrid_attention_kernels.c.

121 {
122 const int dim = num_heads * state_dim;
123 for (int row = 0; row < rows; ++row) {
124 const float *x_row = x + (size_t) row * (size_t) dim;
125 const float *gate_row = gate + (size_t) row * (size_t) dim;
126 float *out_row = out + (size_t) row * (size_t) dim;
127 for (int col = 0; col < dim; ++col) {
128 out_row[col] = x_row[col] * hybrid_sigmoid(gate_row[col]);
129 }
130 }
131}

References hybrid_sigmoid().

◆ attn_gate_sigmoid_mul_pytorch_bf16_storage()

void attn_gate_sigmoid_mul_pytorch_bf16_storage ( const float *  x,
const float *  gate,
float *  out,
int  rows,
int  num_heads,
int  state_dim 
)

Definition at line 133 of file hybrid_attention_kernels.c.

138 {
139 if (!x || !gate || !out || rows <= 0 || num_heads <= 0 || state_dim <= 0) {
140 return;
141 }
142 const int dim = num_heads * state_dim;
143 for (int row = 0; row < rows; ++row) {
144 const float *x_row = x + (size_t)row * (size_t)dim;
145 const float *gate_row = gate + (size_t)row * (size_t)dim;
146 float *out_row = out + (size_t)row * (size_t)dim;
147 for (int col = 0; col < dim; col += 16) {
148 const int width = dim - col < 16 ? dim - col : 16;
149 float sigmoid[16];
151 gate_row + col, sigmoid, 1, width);
152 for (int lane = 0; lane < width; ++lane) {
153 const float x_bf16 = bf16_to_float(float_to_bf16(x_row[col + lane]));
154 const float sigmoid_bf16 = bf16_to_float(float_to_bf16(sigmoid[lane]));
155 out_row[col + lane] = bf16_to_float(float_to_bf16(
156 x_bf16 * sigmoid_bf16));
157 }
158 }
159 }
160}
void recurrent_sigmoid_forward_pytorch_bf16_input_fp32_output(const float *x, float *out, int rows, int dim)

References bf16_to_float(), float_to_bf16(), and recurrent_sigmoid_forward_pytorch_bf16_input_fp32_output().

◆ attn_gate_softplus_mul_forward()

void attn_gate_softplus_mul_forward ( const float *  x,
const float *  gate,
float *  out,
int  rows,
int  num_heads,
int  state_dim 
)

Definition at line 162 of file hybrid_attention_kernels.c.

167 {
168 const int dim = num_heads * state_dim;
169 for (int row = 0; row < rows; ++row) {
170 const float *x_row = x + (size_t) row * (size_t) dim;
171 const float *gate_row = gate + (size_t) row * (size_t) num_heads;
172 float *out_row = out + (size_t) row * (size_t) dim;
173 for (int head = 0; head < num_heads; ++head) {
174 const float value = gate_row[head];
175 const float scale = value > 20.0f
176 ? value
177 : log1pf(expf(value));
178 const size_t base = (size_t) head * (size_t) state_dim;
179 for (int col = 0; col < state_dim; ++col) {
180 out_row[base + (size_t) col] =
181 x_row[base + (size_t) col] * scale;
182 }
183 }
184 }
185}

◆ axpy_2d_f32()

void axpy_2d_f32 ( float *  Y,
const float *  X,
float  alpha,
int  num_tokens,
int  dim,
int  y_stride,
int  x_stride 
)

Batched AXPY for 2D tensors: Y[t,:] += alpha * X[t,:].

Parameters
YOutput tensor [num_tokens, dim]
XInput tensor [num_tokens, dim]
alphaScalar multiplier
num_tokensNumber of tokens
dimHidden dimension
y_strideStride between Y rows (for alignment)
x_strideStride between X rows

Definition at line 272 of file axpy_kernels.c.

279{
280 if (!Y || !X || num_tokens <= 0 || dim <= 0) {
281 return;
282 }
283
284 /* Default strides if not specified */
285 if (y_stride <= 0) y_stride = dim;
286 if (x_stride <= 0) x_stride = dim;
287
288 for (int t = 0; t < num_tokens; t++) {
289 axpy_f32(Y + t * y_stride, X + t * x_stride, alpha, dim);
290 }
291}
void axpy_f32(float *y, const float *x, float alpha, int n)
In-place AXPY: y += alpha * x.

References axpy_f32().

◆ axpy_f32()

void axpy_f32 ( float *  y,
const float *  x,
float  alpha,
int  n 
)

In-place AXPY: y += alpha * x.

Test:

test_axpy.py::TestAXPY::test_axpy_f32

test_axpy.py::TestAXPY::test_axpy_vs_naive

In-place scaled vector addition: y += alpha * x BLAS-like axpy operation.

After changes: make test

Definition at line 105 of file axpy_kernels.c.

109{
110 if (!y || !x || n <= 0) {
111 return;
112 }
113
114 int i = 0;
115
116#ifdef __AVX512F__
117 __m512 valpha = _mm512_set1_ps(alpha);
118 for (; i + 16 <= n; i += 16) {
119 __m512 vy = _mm512_loadu_ps(&y[i]);
120 __m512 vx = _mm512_loadu_ps(&x[i]);
121 vy = _mm512_fmadd_ps(vx, valpha, vy); /* y = y + alpha * x */
122 _mm512_storeu_ps(&y[i], vy);
123 }
124#endif
125
126#ifdef __AVX2__
127 __m256 valpha256 = _mm256_set1_ps(alpha);
128 for (; i + 8 <= n; i += 8) {
129 __m256 vy = _mm256_loadu_ps(&y[i]);
130 __m256 vx = _mm256_loadu_ps(&x[i]);
131 vy = _mm256_fmadd_ps(vx, valpha256, vy);
132 _mm256_storeu_ps(&y[i], vy);
133 }
134#endif
135
136 /* Scalar remainder */
137 for (; i < n; i++) {
138 y[i] += alpha * x[i];
139 }
140}

Referenced by axpy_2d_f32(), axpy_zero_f32(), ck_moe_q4k_mixed_route_parallel(), ck_moe_q4k_q5k_bucket_work(), ck_moe_q4k_q5k_route_parallel(), moe_accumulate_expert_f32(), moe_swiglu_expert_forward_q4k_q4k_workspace(), moe_swiglu_expert_forward_q4k_q5k_workspace(), moe_swiglu_expert_forward_q4k_q6k_workspace(), and weighted_sum_f32().

◆ axpy_zero_f32()

void axpy_zero_f32 ( float *  y,
const float *  x,
float  alpha,
int  n 
)

Zero output then accumulate: y = 0; y += alpha * x.

Parameters
yOutput vector [n], zeroed then accumulated
xInput vector [n]
alphaScalar multiplier
nVector length

Definition at line 239 of file axpy_kernels.c.

243{
244 if (!y || n <= 0) {
245 return;
246 }
247
248 memset(y, 0, n * sizeof(float));
249
250 if (x) {
251 axpy_f32(y, x, alpha, n);
252 }
253}

References axpy_f32().

◆ backward_causal_softmax_head_major()

void backward_causal_softmax_head_major ( float *  d_scores,
const float *  weights,
int  num_heads,
int  num_tokens,
int  aligned_context_window 
)

Definition at line 382 of file softmax_kernels.c.

387{
388 int H = num_heads;
389 int T = num_tokens;
390
391 for (int h = 0; h < H; ++h) {
392 for (int i = 0; i < T; ++i) {
393 int base = h * aligned_context_window * aligned_context_window
394 + i * aligned_context_window;
395 float *drow = &d_scores[base];
396 const float *wrow = &weights[base];
397 int len = i + 1;
398
399#if defined(__AVX512F__)
400 // Compute dot product (vectorized)
401 __m512 dot_vec = _mm512_setzero_ps();
402 int j = 0;
403 for (; j + 16 <= len; j += 16) {
404 __m512 w = _mm512_loadu_ps(&wrow[j]);
405 __m512 dw = _mm512_loadu_ps(&drow[j]);
406 dot_vec = _mm512_fmadd_ps(w, dw, dot_vec);
407 }
408 float dot_product = _mm512_reduce_add_ps(dot_vec);
409 for (; j < len; ++j) {
410 dot_product += wrow[j] * drow[j];
411 }
412
413 // Compute gradient: d_scores = w * (dw - dot_product)
414 __m512 dot_broadcast = _mm512_set1_ps(dot_product);
415 j = 0;
416 for (; j + 16 <= len; j += 16) {
417 __m512 w = _mm512_loadu_ps(&wrow[j]);
418 __m512 dw = _mm512_loadu_ps(&drow[j]);
419 __m512 diff = _mm512_sub_ps(dw, dot_broadcast);
420 __m512 result = _mm512_mul_ps(w, diff);
421 _mm512_storeu_ps(&drow[j], result);
422 }
423 for (; j < len; ++j) {
424 drow[j] = wrow[j] * (drow[j] - dot_product);
425 }
426
427 // Zero out future tokens
428 __m512 zero = _mm512_setzero_ps();
429 for (; j + 16 <= T; j += 16) {
430 _mm512_storeu_ps(&drow[j], zero);
431 }
432 for (; j < T; ++j) {
433 drow[j] = 0.0f;
434 }
435
436#elif defined(__AVX__)
437 // Compute dot product (vectorized)
438 __m256 dot_vec = _mm256_setzero_ps();
439 int j = 0;
440 for (; j + 8 <= len; j += 8) {
441 __m256 w = _mm256_loadu_ps(&wrow[j]);
442 __m256 dw = _mm256_loadu_ps(&drow[j]);
443 // No FMA in AVX1: use mul + add
444 __m256 prod = _mm256_mul_ps(w, dw);
445 dot_vec = _mm256_add_ps(dot_vec, prod);
446 }
447 float dot_product = hsum256_ps_softmax(dot_vec);
448 for (; j < len; ++j) {
449 dot_product += wrow[j] * drow[j];
450 }
451
452 // Compute gradient: d_scores = w * (dw - dot_product)
453 __m256 dot_broadcast = _mm256_set1_ps(dot_product);
454 j = 0;
455 for (; j + 8 <= len; j += 8) {
456 __m256 w = _mm256_loadu_ps(&wrow[j]);
457 __m256 dw = _mm256_loadu_ps(&drow[j]);
458 __m256 diff = _mm256_sub_ps(dw, dot_broadcast);
459 __m256 result = _mm256_mul_ps(w, diff);
460 _mm256_storeu_ps(&drow[j], result);
461 }
462 for (; j < len; ++j) {
463 drow[j] = wrow[j] * (drow[j] - dot_product);
464 }
465
466 // Zero out future tokens
467 __m256 zero = _mm256_setzero_ps();
468 for (; j + 8 <= T; j += 8) {
469 _mm256_storeu_ps(&drow[j], zero);
470 }
471 for (; j < T; ++j) {
472 drow[j] = 0.0f;
473 }
474
475#else
476 // Scalar fallback
477 float dot_product = 0.0f;
478 for (int j = 0; j < len; ++j) {
479 dot_product += wrow[j] * drow[j];
480 }
481
482 for (int j = 0; j < len; ++j) {
483 drow[j] = wrow[j] * (drow[j] - dot_product);
484 }
485
486 for (int j = len; j < T; ++j) {
487 drow[j] = 0.0f;
488 }
489#endif
490 }
491 }
492}

Referenced by backward_causal_softmax_head_major_bf16().

◆ backward_causal_softmax_head_major_bf16()

void backward_causal_softmax_head_major_bf16 ( uint16_t *  d_scores,
const uint16_t *  weights,
int  num_heads,
int  num_tokens,
int  aligned_context_window,
float *  scratch_d_scores,
float *  scratch_weights 
)

Definition at line 53 of file softmax_kernels_bf16.c.

60{
61 if (!d_scores || !weights || num_heads <= 0 || num_tokens <= 0 || aligned_context_window <= 0) return;
62 if (!scratch_d_scores || !scratch_weights) return;
63
64 const size_t total = (size_t)num_heads *
65 (size_t)aligned_context_window *
66 (size_t)aligned_context_window;
67
68 bf16_tensor_to_float(d_scores, scratch_d_scores, total);
69 bf16_tensor_to_float(weights, scratch_weights, total);
70 backward_causal_softmax_head_major(scratch_d_scores, scratch_weights, num_heads, num_tokens, aligned_context_window);
71 float_tensor_to_bf16(scratch_d_scores, d_scores, total);
72}
static void float_tensor_to_bf16(const float *src, uint16_t *dst, size_t count)
Definition bf16_utils.h:271
static void bf16_tensor_to_float(const uint16_t *src, float *dst, size_t count)
Definition bf16_utils.h:250
void backward_causal_softmax_head_major(float *d_scores, const float *weights, int num_heads, int num_tokens, int aligned_context_window)

References backward_causal_softmax_head_major(), bf16_tensor_to_float(), and float_tensor_to_bf16().

◆ causal_softmax_head_major()

void causal_softmax_head_major ( float *  scores,
int  num_heads,
int  num_tokens,
int  aligned_context_window 
)

Causal softmax (in-place, row-wise)

Test:

test_softmax.py::TestSoftmaxForward::test_causal_softmax

test_softmax.py::TestSoftmaxForward::test_causal_vs_softmax

test_attention.py::TestAttentionForward::test_softmax_correctness

Applies causal mask (j > i => 0) and softmax to scores matrix. In-place on [num_heads, T, T] scores matrix.

After changes: make test && make llamacpp-parity-full

Definition at line 144 of file softmax_kernels.c.

148{
149 for (int h = 0; h < num_heads; ++h) {
150 for (int i = 0; i < num_tokens; ++i) {
151 int base = h * aligned_context_window * aligned_context_window
152 + i * aligned_context_window;
153 float *row = &scores[base];
154 int len = i + 1; // Number of valid elements (0..i inclusive)
155
156#if defined(__AVX512F__)
157 // Find max (vectorized)
158 __m512 max_vec = _mm512_set1_ps(-INFINITY);
159 int j = 0;
160 for (; j + 16 <= len; j += 16) {
161 __m512 v = _mm512_loadu_ps(&row[j]);
162 max_vec = _mm512_max_ps(max_vec, v);
163 }
164 float max_val = _mm512_reduce_max_ps(max_vec);
165 for (; j < len; ++j) {
166 if (row[j] > max_val) max_val = row[j];
167 }
168
169 // Compute exp and sum (vectorized)
170 __m512 max_broadcast = _mm512_set1_ps(max_val);
171 __m512 sum_vec = _mm512_setzero_ps();
172 j = 0;
173 for (; j + 16 <= len; j += 16) {
174 __m512 v = _mm512_loadu_ps(&row[j]);
175 __m512 e = exp512_approx(_mm512_sub_ps(v, max_broadcast));
176 _mm512_storeu_ps(&row[j], e);
177 sum_vec = _mm512_add_ps(sum_vec, e);
178 }
179 float sum = _mm512_reduce_add_ps(sum_vec);
180 for (; j < len; ++j) {
181 float e = expf(row[j] - max_val);
182 row[j] = e;
183 sum += e;
184 }
185
186 // Normalize (vectorized)
187 float inv_sum = 1.0f / sum;
188 __m512 inv_sum_vec = _mm512_set1_ps(inv_sum);
189 j = 0;
190 for (; j + 16 <= len; j += 16) {
191 __m512 v = _mm512_loadu_ps(&row[j]);
192 _mm512_storeu_ps(&row[j], _mm512_mul_ps(v, inv_sum_vec));
193 }
194 for (; j < len; ++j) {
195 row[j] *= inv_sum;
196 }
197
198 // Zero out future tokens (vectorized)
199 __m512 zero = _mm512_setzero_ps();
200 for (; j + 16 <= num_tokens; j += 16) {
201 _mm512_storeu_ps(&row[j], zero);
202 }
203 for (; j < num_tokens; ++j) {
204 row[j] = 0.0f;
205 }
206
207#elif defined(__AVX2__)
208 // AVX2: Find max (vectorized)
209 __m256 max_vec = _mm256_set1_ps(-INFINITY);
210 int j = 0;
211 for (; j + 8 <= len; j += 8) {
212 __m256 v = _mm256_loadu_ps(&row[j]);
213 max_vec = _mm256_max_ps(max_vec, v);
214 }
215 float max_val = hmax256_ps(max_vec);
216 for (; j < len; ++j) {
217 if (row[j] > max_val) max_val = row[j];
218 }
219
220 // Compute exp and sum (vectorized with fast exp)
221 __m256 max_broadcast = _mm256_set1_ps(max_val);
222 __m256 sum_vec = _mm256_setzero_ps();
223 j = 0;
224 for (; j + 8 <= len; j += 8) {
225 __m256 v = _mm256_loadu_ps(&row[j]);
226 __m256 e = exp256_approx(_mm256_sub_ps(v, max_broadcast));
227 _mm256_storeu_ps(&row[j], e);
228 sum_vec = _mm256_add_ps(sum_vec, e);
229 }
230 float sum = hsum256_ps_softmax(sum_vec);
231 for (; j < len; ++j) {
232 float e = expf(row[j] - max_val);
233 row[j] = e;
234 sum += e;
235 }
236
237 // Normalize (vectorized)
238 float inv_sum = 1.0f / sum;
239 __m256 inv_sum_vec = _mm256_set1_ps(inv_sum);
240 j = 0;
241 for (; j + 8 <= len; j += 8) {
242 __m256 v = _mm256_loadu_ps(&row[j]);
243 _mm256_storeu_ps(&row[j], _mm256_mul_ps(v, inv_sum_vec));
244 }
245 for (; j < len; ++j) {
246 row[j] *= inv_sum;
247 }
248
249 // Zero out future tokens (vectorized)
250 __m256 zero = _mm256_setzero_ps();
251 for (; j + 8 <= num_tokens; j += 8) {
252 _mm256_storeu_ps(&row[j], zero);
253 }
254 for (; j < num_tokens; ++j) {
255 row[j] = 0.0f;
256 }
257
258#elif defined(__AVX__)
259 // AVX1: vectorized max/sum/normalize, scalar exp
260 __m256 max_vec = _mm256_set1_ps(-INFINITY);
261 int j = 0;
262 for (; j + 8 <= len; j += 8) {
263 __m256 v = _mm256_loadu_ps(&row[j]);
264 max_vec = _mm256_max_ps(max_vec, v);
265 }
266 float max_val = hmax256_ps(max_vec);
267 for (; j < len; ++j) {
268 if (row[j] > max_val) max_val = row[j];
269 }
270
271 // Compute exp and sum (scalar exp, no fast approx for AVX1)
272 float sum = 0.0f;
273 for (j = 0; j < len; ++j) {
274 float e = expf(row[j] - max_val);
275 row[j] = e;
276 sum += e;
277 }
278
279 // Normalize (vectorized)
280 float inv_sum = 1.0f / sum;
281 __m256 inv_sum_vec = _mm256_set1_ps(inv_sum);
282 j = 0;
283 for (; j + 8 <= len; j += 8) {
284 __m256 v = _mm256_loadu_ps(&row[j]);
285 _mm256_storeu_ps(&row[j], _mm256_mul_ps(v, inv_sum_vec));
286 }
287 for (; j < len; ++j) {
288 row[j] *= inv_sum;
289 }
290
291 // Zero out future tokens (vectorized)
292 __m256 zero = _mm256_setzero_ps();
293 for (; j + 8 <= num_tokens; j += 8) {
294 _mm256_storeu_ps(&row[j], zero);
295 }
296 for (; j < num_tokens; ++j) {
297 row[j] = 0.0f;
298 }
299
300#else
301 // Scalar fallback
302 float max_val = row[0];
303 for (int j = 1; j < len; ++j) {
304 if (row[j] > max_val) max_val = row[j];
305 }
306
307 float sum = 0.0f;
308 for (int j = 0; j < len; ++j) {
309 float e = expf(row[j] - max_val);
310 row[j] = e;
311 sum += e;
312 }
313
314 float inv_sum = 1.0f / sum;
315 for (int j = 0; j < len; ++j) {
316 row[j] *= inv_sum;
317 }
318
319 for (int j = len; j < num_tokens; ++j) {
320 row[j] = 0.0f;
321 }
322#endif
323 }
324 }
325}

Referenced by attention_forward_causal_head_major(), attention_forward_causal_head_major_gqa(), and causal_softmax_head_major_bf16().

◆ causal_softmax_head_major_bf16()

void causal_softmax_head_major_bf16 ( uint16_t *  scores,
int  num_heads,
int  num_tokens,
int  aligned_context_window,
float *  scratch 
)

Definition at line 31 of file softmax_kernels_bf16.c.

36{
37 if (!scores || num_heads <= 0 || num_tokens <= 0 || aligned_context_window <= 0) return;
38 if (!scratch) return;
39
40 const size_t total = (size_t)num_heads *
41 (size_t)aligned_context_window *
42 (size_t)aligned_context_window;
43
44 bf16_tensor_to_float(scores, scratch, total);
45 causal_softmax_head_major(scratch, num_heads, num_tokens, aligned_context_window);
46 float_tensor_to_bf16(scratch, scores, total);
47}

References bf16_tensor_to_float(), causal_softmax_head_major(), and float_tensor_to_bf16().

◆ causal_softmax_head_major_exact()

void causal_softmax_head_major_exact ( float *  scores,
int  num_heads,
int  num_tokens,
int  aligned_context_window 
)

Causal softmax (exact version using stdlib expf)

Test:

test_softmax.py::TestSoftmaxForward::test_causal_softmax_exact

test_softmax.py::TestSoftmaxForward::test_exact_vs_fast

Exact causal softmax using standard library expf for numerical accuracy reference.

After changes: make test

Definition at line 339 of file softmax_kernels.c.

343{
344 for (int h = 0; h < num_heads; ++h) {
345 for (int i = 0; i < num_tokens; ++i) {
346 int base = h * aligned_context_window * aligned_context_window
347 + i * aligned_context_window;
348 float *row = &scores[base];
349 int len = i + 1;
350
351 // Find max
352 float max_val = -INFINITY;
353 for (int j = 0; j < len; ++j) {
354 if (row[j] > max_val) max_val = row[j];
355 }
356
357 // Compute exp and sum using standard library expf
358 float sum = 0.0f;
359 for (int j = 0; j < len; ++j) {
360 float e = expf(row[j] - max_val);
361 row[j] = e;
362 sum += e;
363 }
364
365 // Normalize
366 float inv_sum = 1.0f / sum;
367 for (int j = 0; j < len; ++j) {
368 row[j] *= inv_sum;
369 }
370
371 // Zero out future tokens
372 for (int j = len; j < num_tokens; ++j) {
373 row[j] = 0.0f;
374 }
375 }
376 }
377}

Referenced by attention_forward_causal_head_major_exact(), and attention_forward_causal_head_major_gqa_exact().

◆ ck_attention_bf16_pytorch_gqa_available()

int ck_attention_bf16_pytorch_gqa_available ( void  )

Definition at line 8511 of file attention_kernels.c.

8512{
8513#if defined(__AVX512F__)
8514 pthread_once(&ck_pytorch_attention_once, ck_bind_pytorch_attention_primitives);
8515 return ck_pytorch_sgemm_batch != NULL &&
8516 ck_pytorch_attention_expf16 != NULL;
8517#else
8518 return 1;
8519#endif
8520}

Referenced by ck_attention_sparse_bf16_pytorch_gqa_available().

◆ ck_attention_flash_decode_wrapper()

void ck_attention_flash_decode_wrapper ( const float *  q_token,
const float *  k_cache,
const float *  v_cache,
float *  out_token,
int  num_heads,
int  num_kv_heads,
int  kv_tokens,
int  cache_capacity,
int  head_dim,
int  aligned_head_dim 
)

Wrapper to call TRUE flash attention from orchestration layer.

Parameters
q_tokenQuery token [H, D_h]
k_cacheCached keys [T_k, H, D_h]
v_cacheCached values [T_k, H, D_h]
out_tokenOutput [H, D_h]
num_headsNumber of heads
num_kv_headsNumber of KV heads (for GQA)
kv_tokensNumber of tokens in KV cache
cache_capacityCache capacity
head_dimHead dimension
aligned_head_dimAligned head dimension

Definition at line 72 of file ckernel_orchestration.c.

83{
84 if (!q_token || !k_cache || !v_cache || !out_token) {
85 return;
86 }
87 if (num_heads <= 0 || num_kv_heads <= 0 || kv_tokens <= 0 || cache_capacity <= 0) {
88 return;
89 }
90 if (kv_tokens > cache_capacity || head_dim <= 0 || aligned_head_dim <= 0) {
91 return;
92 }
93
94 static int use_strict = -1;
95 if (use_strict < 0) {
96 const char *env = getenv("CK_FLASH_ATTN_STRICT");
97 use_strict = (env && env[0] && env[0] != '0') ? 1 : 0;
98 }
99
100 if (use_strict) {
102 k_cache,
103 v_cache,
104 out_token,
105 num_heads,
106 num_kv_heads,
107 kv_tokens,
108 cache_capacity,
109 head_dim,
110 aligned_head_dim);
111 return;
112 }
113
114 // Scale factor: 1/sqrt(head_dim)
115 const float scale = 1.0f / sqrtf((float)head_dim);
116 const size_t head_stride = (size_t)cache_capacity * (size_t)aligned_head_dim;
117
118#pragma omp parallel for schedule(static) if(num_heads > 1)
119 for (int h = 0; h < num_heads; ++h) {
120 const int kv_head = (int)((long long)h * (long long)num_kv_heads / (long long)num_heads);
121 const float *q_head = q_token + (size_t)h * (size_t)aligned_head_dim;
122 const float *k_head = k_cache + (size_t)kv_head * head_stride;
123 const float *v_head = v_cache + (size_t)kv_head * head_stride;
124 float *out_head = out_token + (size_t)h * (size_t)aligned_head_dim;
125
126 // Use aligned_head_dim as D_h so per-token stride matches the cache layout.
127 attention_flash_decode(out_head,
128 q_head,
129 k_head,
130 v_head,
131 1,
132 kv_tokens,
133 1,
134 aligned_head_dim,
135 scale);
136 }
137}
void attention_forward_decode_head_major_gqa_regular(const float *q_token, const float *k_cache, const float *v_cache, float *out_token, int num_heads, int num_kv_heads, int kv_tokens, int cache_capacity, int head_dim, int aligned_head_dim)
WARNING: This is NOT true flash attention!

References attention_flash_decode(), and attention_forward_decode_head_major_gqa_regular().

Referenced by ck_layer_forward_rmsnorm_swiglu_decode(), ck_layer_forward_rmsnorm_swiglu_decode_fused(), ck_layer_forward_rmsnorm_swiglu_decode_q4_k(), and ck_layer_forward_rmsnorm_swiglu_decode_quant().

◆ ck_attention_pytorch_sdpa_scale_f32()

float ck_attention_pytorch_sdpa_scale_f32 ( int  head_dim)

Definition at line 4518 of file attention_kernels.c.

4519{
4520 /* PyTorch CPU flash calculate_scale evaluates in FP64, then narrows. */
4521 return head_dim > 0 ? (float)(1.0 / sqrt((double)head_dim)) : 0.0f;
4522}

Referenced by ck_attention_full_bf16_sdpa_amx_range(), and ck_attention_full_bf16_sdpa_tiled_range().

◆ ck_attention_sparse_bf16_pytorch_gqa_available()

int ck_attention_sparse_bf16_pytorch_gqa_available ( void  )

Definition at line 8502 of file attention_kernels.c.

8503{
8504#if defined(__AVX512F__)
8506#else
8507 return 0;
8508#endif
8509}
int ck_attention_bf16_pytorch_gqa_available(void)

References ck_attention_bf16_pytorch_gqa_available().

◆ ck_flash_attn_choose_tile_k()

int ck_flash_attn_choose_tile_k ( int  D_h)

Definition at line 108 of file attention_flash_true.c.

108 {
109 return ck_flash_attn_tile_k(D_h);
110}
static int ck_flash_attn_tile_k(int D_h)

References ck_flash_attn_tile_k().

◆ ck_flash_attn_fast_exp_kind()

int ck_flash_attn_fast_exp_kind ( void  )

Definition at line 112 of file attention_flash_true.c.

112 {
113#if CK_FLASH_ATTN_FAST_EXP
114#if defined(__AVX512F__)
115 return 512;
116#elif defined(__AVX__)
117 return 256;
118#else
119 return 0;
120#endif
121#else
122 return 0;
123#endif
124}

◆ ck_gemm_bf16_amx_available()

int ck_gemm_bf16_amx_available ( void  )

Definition at line 1196 of file gemm_kernels_bf16.c.

1197{
1198#if HAVE_AMX_BF16
1199 return ck_amx_request_xtile_data();
1200#else
1201 return 0;
1202#endif
1203}

Referenced by ck_attention_full_bf16_sdpa_amx_range(), gemm_nt_bf16_prefill_shape_safe_bf16_storage(), and gemm_nt_bf16_prefill_shape_safe_bf16_storage_workspace().

◆ ck_gemm_bf16_fp32out_amx_raw()

int ck_gemm_bf16_fp32out_amx_raw ( const uint16_t *  A,
const uint16_t *  B,
float *  C,
int  M,
int  N,
int  K,
int  accumulate 
)

Definition at line 1205 of file gemm_kernels_bf16.c.

1210{
1211#if HAVE_AMX_BF16
1212 if (!A || !B || !C || M <= 0 || N <= 0 || K <= 0 ||
1213 (M % 16) != 0 || (N % 16) != 0 || (K % 2) != 0 ||
1214 !ck_amx_request_xtile_data()) {
1215 return 0;
1216 }
1217 /* Match oneDNN BRGEMM: largest even divisor of K no greater than 32. */
1218 int k_block = K < 32 ? K : 32;
1219 while (k_block > 2 && K % k_block != 0) k_block -= 2;
1220 ck_amx_config_bf16_16x16_kblock(k_block);
1221 uint16_t b_tile[16 * 32];
1222 for (int i = 0; i < M; i += 16) {
1223 for (int j = 0; j < N; j += 16) {
1224 if (accumulate) {
1225 _tile_loadd(2, C + (size_t)i * (size_t)N + (size_t)j,
1226 N * (int)sizeof(float));
1227 } else {
1228 _tile_zero(2);
1229 }
1230 for (int k = 0; k < K; k += k_block) {
1231 memset(b_tile, 0, sizeof(b_tile));
1232 for (int kp = 0; kp < k_block / 2; ++kp) {
1233 const int k0 = k + kp * 2;
1234 for (int nn = 0; nn < 16; ++nn) {
1235 b_tile[(size_t)kp * 32u + (size_t)nn * 2u] =
1236 B[(size_t)(j + nn) * (size_t)K + (size_t)k0];
1237 b_tile[(size_t)kp * 32u + (size_t)nn * 2u + 1u] =
1238 B[(size_t)(j + nn) * (size_t)K + (size_t)k0 + 1u];
1239 }
1240 }
1241 _tile_loadd(0, A + (size_t)i * (size_t)K + (size_t)k,
1242 K * (int)sizeof(uint16_t));
1243 _tile_loadd(1, b_tile, 32 * (int)sizeof(uint16_t));
1244 _tile_dpbf16ps(2, 0, 1);
1245 }
1246 _tile_stored(2, C + (size_t)i * (size_t)N + (size_t)j,
1247 N * (int)sizeof(float));
1248 }
1249 }
1250 _tile_release();
1251 return 1;
1252#else
1253 (void)A; (void)B; (void)C; (void)M; (void)N; (void)K; (void)accumulate;
1254 return 0;
1255#endif
1256}
#define C(color)
Definition show_config.c:39

References C.

Referenced by ck_attention_full_bf16_sdpa_amx_range().

◆ ck_gemm_nt_f16_ggml_oracle()

int ck_gemm_nt_f16_ggml_oracle ( const float *  A,
const void *  B,
const float *  bias,
float *  C,
int  M,
int  N,
int  K 
)

Definition at line 262 of file gemm_kernels_f16.c.

269{
270 return gemm_nt_f16_ggml_strict(A, B, bias, C, M, N, K);
271}
static int gemm_nt_f16_ggml_strict(const float *A, const void *B, const float *bias, float *C, int M, int N, int K)

References C, and gemm_nt_f16_ggml_strict().

◆ ck_gemm_nt_f16_simd_lanes()

int ck_gemm_nt_f16_simd_lanes ( void  )

Definition at line 583 of file gemm_kernels_f16.c.

584{
585#if defined(__AVX512F__) && defined(__F16C__)
586 return 16;
587#elif defined(__F16C__) && defined(__AVX__)
588 return 8;
589#else
590 return 1;
591#endif
592}

◆ ck_gemm_nt_head_major_q5_0()

void ck_gemm_nt_head_major_q5_0 ( const float *  attn_out,
const void *  wo,
const float *  bias,
float *  output,
int  tokens,
int  embed_dim,
int  num_heads,
int  head_dim 
)

Output projection from head-major attention (auto-dispatch)

This replaces flatten_head_major() + ck_gemm_nt_quant() with a single strided-access kernel that reads head-major attention output directly.

Definition at line 290 of file gemm_head_major_output.c.

298{
299#if defined(__AVX__)
300 gemv_nt_q5_0_head_major_output_avx(output, attn_out, wo, bias,
301 tokens, embed_dim, num_heads, head_dim);
302#else
303 gemv_nt_q5_0_head_major_output(output, attn_out, wo, bias,
304 tokens, embed_dim, num_heads, head_dim);
305#endif
306}
void gemv_nt_q5_0_head_major_output(float *output, const float *attn_out, const void *wo, const float *bias, int tokens, int embed_dim, int num_heads, int head_dim)
Output projection reading head-major attention output (Q5_0 weights)

References gemv_nt_q5_0_head_major_output().

Referenced by mega_fused_attention_prefill().

◆ ck_gemm_nt_head_major_q8_0()

void ck_gemm_nt_head_major_q8_0 ( const float *  attn_out,
const void *  wo,
const float *  bias,
float *  output,
int  tokens,
int  embed_dim,
int  num_heads,
int  head_dim 
)

Output projection from head-major attention (Q8_0 weights)

Definition at line 315 of file gemm_head_major_output.c.

323{
324 if (!output || !attn_out || !wo) return;
325 if (tokens <= 0 || embed_dim <= 0 || num_heads <= 0 || head_dim <= 0) return;
326
327 const int blocks_per_head = head_dim / QK8_0;
328 const int blocks_per_row = embed_dim / QK8_0;
329 const block_q8_0 *weights = (const block_q8_0 *)wo;
330
331 const size_t token_stride = head_dim;
332 const size_t head_stride = (size_t)tokens * token_stride;
333
334 /* Initialize output */
335 if (bias) {
336 for (int t = 0; t < tokens; t++) {
337 float *out_row = output + (size_t)t * embed_dim;
338 for (int n = 0; n < embed_dim; n++) {
339 out_row[n] = bias[n];
340 }
341 }
342 } else {
343 memset(output, 0, (size_t)tokens * embed_dim * sizeof(float));
344 }
345
346 /* Accumulate from each head */
347 for (int h = 0; h < num_heads; h++) {
348 const float *head_data = attn_out + (size_t)h * head_stride;
349 const int head_offset = h * blocks_per_head;
350
351 for (int n_block = 0; n_block < blocks_per_head; n_block++) {
352 for (int n = 0; n < embed_dim; n++) {
353 const block_q8_0 *w_row = weights + (size_t)n * blocks_per_row + head_offset + n_block;
354 const float d = CK_FP16_TO_FP32(w_row->d);
355
356 for (int t = 0; t < tokens; t++) {
357 const float *token_vec = head_data + (size_t)t * token_stride + (size_t)n_block * QK8_0;
358 float sum = 0.0f;
359
360 for (int j = 0; j < QK8_0; j++) {
361 sum += d * (float)w_row->qs[j] * token_vec[j];
362 }
363
364 output[(size_t)t * embed_dim + n] += sum;
365 }
366 }
367 }
368 }
369}
#define QK8_0
int8_t qs[32]

References CK_FP16_TO_FP32, block_q8_0::d, QK8_0, and block_q8_0::qs.

Referenced by mega_fused_attention_prefill().

◆ ck_get_num_threads()

int ck_get_num_threads ( void  )

Definition at line 310 of file ckernel_strict.c.

311{
312 // Auto-initialize if not set
314 ck_set_num_threads(0); // Auto-detect
315 }
316 return g_num_threads;
317}
void ck_set_num_threads(int num_threads)
static int g_num_threads
static int g_threads_initialized

References ck_set_num_threads(), g_num_threads, and g_threads_initialized.

Referenced by attention_forward_decode_head_major_gqa_flash_f16cache_contract(), and gemm_blocked_serial().

◆ ck_get_physical_cores()

int ck_get_physical_cores ( void  )

Definition at line 170 of file ckernel_strict.c.

171{
172 int physical_cores = 0;
173 int logical_cores = (int)sysconf(_SC_NPROCESSORS_ONLN);
174 if (logical_cores <= 0) {
175 logical_cores = 1;
176 }
177
178 int cpu_cores_hint = 0;
179 int siblings_hint = 0;
180
181 // Read from /proc/cpuinfo (Linux) and count unique (physical id, core id) pairs.
182 FILE *f = fopen("/proc/cpuinfo", "r");
183 if (f) {
184 char line[256];
185 int physical_id = -1;
186 int core_id = -1;
187
188 struct {
189 int physical_id;
190 int core_id;
191 } seen[8192];
192 int seen_count = 0;
193
194 const int seen_cap = (int)(sizeof(seen) / sizeof(seen[0]));
195
196 // Helper: add (pid,cid) to set if not present.
197 #define CK_ADD_PAIR(pid, cid) \
198 do { \
199 if ((pid) >= 0 && (cid) >= 0) { \
200 int exists = 0; \
201 for (int ii = 0; ii < seen_count; ++ii) { \
202 if (seen[ii].physical_id == (pid) && \
203 seen[ii].core_id == (cid)) { \
204 exists = 1; \
205 break; \
206 } \
207 } \
208 if (!exists && seen_count < seen_cap) { \
209 seen[seen_count].physical_id = (pid); \
210 seen[seen_count].core_id = (cid); \
211 ++seen_count; \
212 } \
213 } \
214 } while (0)
215
216 while (fgets(line, sizeof(line), f)) {
217 int val;
218
219 // Blank line separates processor blocks.
220 if (line[0] == '\n' || line[0] == '\0') {
221 CK_ADD_PAIR(physical_id, core_id);
222 physical_id = -1;
223 core_id = -1;
224 continue;
225 }
226
227 if (sscanf(line, "physical id : %d", &val) == 1) {
228 physical_id = val;
229 continue;
230 }
231 if (sscanf(line, "core id : %d", &val) == 1) {
232 core_id = val;
233 continue;
234 }
235 if (sscanf(line, "cpu cores : %d", &val) == 1) {
236 if (val > cpu_cores_hint) cpu_cores_hint = val;
237 continue;
238 }
239 if (sscanf(line, "siblings : %d", &val) == 1) {
240 if (val > siblings_hint) siblings_hint = val;
241 continue;
242 }
243 }
244 fclose(f);
245
246 // Handle file without trailing blank line.
247 CK_ADD_PAIR(physical_id, core_id);
248
249 #undef CK_ADD_PAIR
250
251 physical_cores = seen_count;
252 }
253
254 // Fallback: infer threads-per-core from siblings/cpu cores when pair data
255 // is missing (common in containers/VMs).
256 if (physical_cores <= 1 && logical_cores > 1) {
257 int threads_per_core = 0;
258 if (siblings_hint > 0 && cpu_cores_hint > 0 && siblings_hint >= cpu_cores_hint) {
259 threads_per_core = siblings_hint / cpu_cores_hint;
260 }
261 if (threads_per_core > 1) {
262 int inferred_physical = logical_cores / threads_per_core;
263 if (inferred_physical > 1) {
264 return inferred_physical;
265 }
266 }
267 if (cpu_cores_hint > 1 && cpu_cores_hint <= logical_cores) {
268 return cpu_cores_hint;
269 }
270 return logical_cores;
271 }
272
273 if (physical_cores > 1) {
274 return physical_cores;
275 }
276
277 return logical_cores;
278}
#define CK_ADD_PAIR(pid, cid)

References CK_ADD_PAIR.

◆ ck_layout_head_to_token_f32()

void ck_layout_head_to_token_f32 ( const float *  src,
float *  dst,
int  heads,
int  tokens,
int  head_dim 
)

Definition at line 19 of file layout_kernels.c.

21{
22 if (!src || !dst || heads <= 0 || tokens <= 0 || head_dim <= 0) return;
23 for (int h = 0; h < heads; ++h) {
24 for (int t = 0; t < tokens; ++t) {
25 memcpy(dst + ((size_t)t * (size_t)heads + (size_t)h) * (size_t)head_dim,
26 src + ((size_t)h * (size_t)tokens + (size_t)t) * (size_t)head_dim,
27 (size_t)head_dim * sizeof(float));
28 }
29 }
30}

◆ ck_layout_token_to_head_f32()

void ck_layout_token_to_head_f32 ( const float *  src,
float *  dst,
int  tokens,
int  heads,
int  head_dim 
)

Definition at line 6 of file layout_kernels.c.

8{
9 if (!src || !dst || tokens <= 0 || heads <= 0 || head_dim <= 0) return;
10 for (int t = 0; t < tokens; ++t) {
11 for (int h = 0; h < heads; ++h) {
12 memcpy(dst + ((size_t)h * (size_t)tokens + (size_t)t) * (size_t)head_dim,
13 src + ((size_t)t * (size_t)heads + (size_t)h) * (size_t)head_dim,
14 (size_t)head_dim * sizeof(float));
15 }
16 }
17}

◆ ck_memcpy_parallel_dispatch()

void * ck_memcpy_parallel_dispatch ( void *  dst,
const void *  src,
size_t  size 
)

◆ ck_multimodal_mrope_positions_2d()

int ck_multimodal_mrope_positions_2d ( int32_t *  positions,
int  total_tokens,
int  prefix_start,
int  position_base,
int  prefix_tokens,
int  grid_x,
int  grid_y,
int  text_pos 
)

Definition at line 2892 of file rope_kernels.c.

2900{
2901 if (!positions || total_tokens <= 0 || prefix_tokens <= 0) {
2902 return -1;
2903 }
2904 if (grid_x <= 0 || grid_y <= 0 || grid_x * grid_y != prefix_tokens) {
2905 return -2;
2906 }
2907 if (prefix_start < 0 || prefix_start > total_tokens) {
2908 return -3;
2909 }
2910 if (prefix_tokens > total_tokens - prefix_start) {
2911 return -4;
2912 }
2913
2914 const int prefix_end = prefix_start + prefix_tokens;
2915 const int grid_extent = grid_x > grid_y ? grid_x : grid_y;
2916 const int resolved_text_pos = text_pos > 0
2917 ? text_pos
2918 : prefix_start + grid_extent;
2919
2920 for (int token = 0; token < total_tokens; ++token) {
2921 int32_t pos0;
2922 int32_t pos1;
2923 int32_t pos2;
2924 if (token < prefix_start) {
2925 pos0 = pos1 = pos2 = (int32_t)token;
2926 } else if (token < prefix_end) {
2927 const int local_token = token - prefix_start;
2928 pos0 = (int32_t)position_base;
2929 pos1 = (int32_t)(position_base + local_token / grid_x);
2930 pos2 = (int32_t)(position_base + local_token % grid_x);
2931 } else {
2932 pos0 = pos1 = pos2 = (int32_t)(resolved_text_pos + token - prefix_end);
2933 }
2934 positions[token] = pos0;
2935 positions[token + total_tokens] = pos1;
2936 positions[token + 2 * total_tokens] = pos2;
2937 positions[token + 3 * total_tokens] = 0;
2938 }
2939 return resolved_text_pos;
2940}

References token.

◆ ck_multimodal_prefix_insert_f32()

int ck_multimodal_prefix_insert_f32 ( const float *  source_rows,
int32_t *  token_ids,
float *  decoder_rows,
int  row_count,
int  source_row_stride,
int  decoder_row_stride,
int  copy_dim,
int  start_row,
int  decoder_capacity 
)

Definition at line 342 of file embedding_kernels.c.

351{
352 if (!source_rows || !token_ids || !decoder_rows || row_count <= 0) {
353 return -1;
354 }
355 if (source_row_stride < copy_dim || decoder_row_stride < copy_dim || copy_dim <= 0) {
356 return -2;
357 }
358 if (start_row < 0 || start_row >= decoder_capacity) {
359 return -3;
360 }
361 if (row_count > decoder_capacity - start_row) {
362 row_count = decoder_capacity - start_row;
363 }
364
365 for (int row = 0; row < row_count; ++row) {
366 const float *src = source_rows + (size_t)row * (size_t)source_row_stride;
367 float *dst = decoder_rows
368 + (size_t)(start_row + row) * (size_t)decoder_row_stride;
369 memcpy(dst, src, (size_t)copy_dim * sizeof(float));
370 token_ids[start_row + row] = 0;
371 }
372 return row_count;
373}

◆ ck_q6_k_prepared_provider_name()

const char * ck_q6_k_prepared_provider_name ( void  )

Definition at line 62 of file gemm_kernels_q6k_q8k.c.

63{
64#if defined(__AVX512F__) && defined(__AVX512BW__) && \
65 defined(__AVX512VNNI__)
66 return "q6_k_prepared_avx512_vnni_exact";
67#elif defined(__AVX2__)
68 return "q6_k_prepared_avx2_exact";
69#else
70 return "q6_k_prepared_unavailable";
71#endif
72}

◆ ck_q6_k_q8_k_provider_name()

const char * ck_q6_k_q8_k_provider_name ( void  )

Definition at line 1367 of file gemm_kernels_q6k_q8k.c.

1368{
1370 return "q6_k_q8_k_ref";
1371 }
1372#if defined(__AVX2__)
1373 return "q6_k_q8_k_avx2";
1374#elif defined(__AVX__)
1375 return "q6_k_q8_k_avx";
1376#elif defined(__SSE4_1__)
1377 return "q6_k_q8_k_sse";
1378#else
1379 return "q6_k_q8_k_ref";
1380#endif
1381}
static int ck_q6k_q8k_force_ref(void)

References ck_q6k_q8k_force_ref(), and ck_strict_parity_enabled().

◆ ck_residual_add_backward()

void ck_residual_add_backward ( const float *  d_out,
float *  d_a,
float *  d_b,
int  tokens,
int  aligned_embed_dim 
)

Definition at line 151 of file ckernel_orchestration.c.

156{
157 if (!d_out || !d_a || !d_b) {
158 return;
159 }
160 size_t total = (size_t)tokens * (size_t)aligned_embed_dim;
161 for (size_t i = 0; i < total; ++i) {
162 float v = d_out[i];
163 d_a[i] = v;
164 d_b[i] = v;
165 }
166}

◆ ck_residual_add_token_major()

void ck_residual_add_token_major ( const float *  a,
const float *  b,
float *  out,
int  tokens,
int  aligned_embed_dim 
)

Definition at line 139 of file ckernel_orchestration.c.

144{
145 size_t total = (size_t)tokens * (size_t)aligned_embed_dim;
146 for (size_t i = 0; i < total; ++i) {
147 out[i] = a[i] + b[i];
148 }
149}

Referenced by ck_layer_forward_rmsnorm_swiglu_decode_fused_attn_impl(), mega_fused_attention_prefill(), and mega_fused_attention_prefill_q8_0().

◆ ck_residual_add_token_major_bf16_storage()

void ck_residual_add_token_major_bf16_storage ( const float *  a,
const float *  b,
float *  out,
int  tokens,
int  aligned_embed_dim 
)

Definition at line 67 of file add_kernels_bf16.c.

72{
73 const size_t count = (size_t)tokens * (size_t)aligned_embed_dim;
74 for (size_t i = 0; i < count; ++i) {
75 const float av = bf16_to_float(float_to_bf16(a[i]));
76 const float bv = bf16_to_float(float_to_bf16(b[i]));
77 out[i] = bf16_to_float(float_to_bf16(av + bv));
78 }
79}

References bf16_to_float(), and float_to_bf16().

◆ ck_residual_add_token_major_parallel_dispatch()

void ck_residual_add_token_major_parallel_dispatch ( const float *  a,
const float *  b,
float *  out,
int  tokens,
int  aligned_embed_dim 
)

◆ ck_set_num_threads()

void ck_set_num_threads ( int  num_threads)

Definition at line 280 of file ckernel_strict.c.

281{
282 // 0 = auto-detect
283 if (num_threads <= 0) {
284 // Prefer explicit env controls when present:
285 // - CK_NUM_THREADS: engine-level override
286 // - OMP_NUM_THREADS: standard OpenMP control (set by `ck run --threads`)
287 int env_threads = ck_parse_env_int("CK_NUM_THREADS");
288 if (env_threads <= 0) {
289 env_threads = ck_parse_env_int("OMP_NUM_THREADS");
290 }
291 num_threads = env_threads > 0 ? env_threads : ck_get_physical_cores();
292 }
293
294 g_num_threads = num_threads;
296
297#ifdef _OPENMP
298 omp_set_dynamic(0); // Disable dynamic adjustment
299 omp_set_num_threads(num_threads);
300#endif
301
302#if defined(USE_MKL)
303 mkl_set_num_threads(num_threads);
304#endif
305
306 fprintf(stderr, "[CK] Set %d threads (auto=%d)\n",
307 num_threads, ck_get_physical_cores());
308}
static int ck_parse_env_int(const char *name)
int ck_get_physical_cores(void)

References ck_get_physical_cores(), ck_parse_env_int(), g_num_threads, and g_threads_initialized.

Referenced by ck_get_num_threads().

◆ ck_set_strict_parity()

void ck_set_strict_parity ( int  enabled)

Definition at line 28 of file ckernel_strict.c.

29{
30 ck_strict_parity = enabled ? 1 : 0;
31 if (!ck_strict_parity) {
34 }
35#ifdef _OPENMP
36 if (ck_strict_parity) {
37 omp_set_dynamic(0);
38 omp_set_num_threads(1);
39 }
40#endif
41}
static size_t ck_strict_next_gemm_a_size
static int ck_strict_parity
static int ck_strict_next_gemm_a_valid

References ck_strict_next_gemm_a_size, ck_strict_next_gemm_a_valid, and ck_strict_parity.

◆ ck_strict_consume_next_gemm_a()

const float * ck_strict_consume_next_gemm_a ( size_t  elems)

Definition at line 70 of file ckernel_strict.c.

71{
73 return NULL;
74 }
77}
static float * ck_strict_next_gemm_a

References ck_strict_next_gemm_a, ck_strict_next_gemm_a_size, ck_strict_next_gemm_a_valid, and ck_strict_parity.

Referenced by gemm_nt_q8_0_q8_0_contract().

◆ ck_strict_mtmd_clip_encode_planar_f32()

int ck_strict_mtmd_clip_encode_planar_f32 ( const float *  planar,
int  channels,
int  height,
int  width,
float *  out,
size_t  out_elems 
)

Definition at line 84 of file ckernel_strict.c.

90{
91 const char *gguf_path = getenv("CK_STRICT_GGUF_PATH");
92 const char *shim_path = getenv("CK_STRICT_MTMD_SHIM_SO");
93 if (!gguf_path || !gguf_path[0] || !shim_path || !shim_path[0]) {
94 return 0;
95 }
96 if (!planar || !out || channels != 3 || height <= 0 || width <= 0) {
97 return 0;
98 }
99
100 void *shim = dlopen(shim_path, RTLD_LAZY | RTLD_LOCAL);
101 if (!shim) {
102 return 0;
103 }
104
106 (ck_strict_mtmd_clip_init_fn) dlsym(shim, "ck_mtmd_clip_init");
108 (ck_strict_mtmd_clip_free_fn) dlsym(shim, "ck_mtmd_clip_free");
110 (ck_strict_mtmd_clip_embd_nbytes_by_img_fn) dlsym(shim, "ck_mtmd_clip_embd_nbytes_by_img");
112 (ck_strict_mtmd_clip_encode_float_image_fn) dlsym(shim, "ck_mtmd_clip_encode_float_image");
113
114 if (!init_fn || !free_fn || !embd_nbytes_fn || !encode_fn) {
115 dlclose(shim);
116 return 0;
117 }
118
119 const size_t pixel_count = (size_t) height * (size_t) width;
120 float *interleaved = (float *) malloc(pixel_count * (size_t) channels * sizeof(float));
121 if (!interleaved) {
122 dlclose(shim);
123 return 0;
124 }
125 for (size_t idx = 0; idx < pixel_count; ++idx) {
126 interleaved[idx * 3 + 0] = planar[idx];
127 interleaved[idx * 3 + 1] = planar[pixel_count + idx];
128 interleaved[idx * 3 + 2] = planar[2 * pixel_count + idx];
129 }
130
131 int ok = 0;
132 void *handle = init_fn(gguf_path, 0, 0, 0, 0, 0);
133 if (handle) {
134 const size_t needed_bytes = embd_nbytes_fn(handle, width, height);
135 if (needed_bytes > 0 && needed_bytes <= out_elems * sizeof(float)) {
136 ok = encode_fn(handle, 1, interleaved, height, width, out) ? 1 : 0;
137 }
138 free_fn(handle);
139 }
140
141 free(interleaved);
142 dlclose(shim);
143 return ok;
144}
void(* ck_strict_mtmd_clip_free_fn)(void *)
void *(* ck_strict_mtmd_clip_init_fn)(const char *, int, int, int, int, int)
size_t(* ck_strict_mtmd_clip_embd_nbytes_by_img_fn)(void *, int, int)
int(* ck_strict_mtmd_clip_encode_float_image_fn)(void *, int, float *, int, int, float *)

◆ ck_strict_parity_enabled()

int ck_strict_parity_enabled ( void  )

Definition at line 43 of file ckernel_strict.c.

44{
45 return ck_strict_parity;
46}

References ck_strict_parity.

Referenced by adamw_update_f32_impl(), attention_forward_decode_head_major_gqa_regular(), attention_forward_full_head_major_gqa_exact_strided(), attention_forward_full_head_major_gqa_ggml_strided_workspace(), attention_forward_head_major_gqa_flash_impl(), attention_forward_mixed_visual_chunk_head_major_gqa_flash_strided_gemma4_impl(), ck_dot_q6_k_q8_k_fast_or_ref(), ck_layer_forward_rmsnorm_swiglu(), ck_layer_forward_rmsnorm_swiglu_ref(), ck_mlp_swiglu_forward(), ck_mlp_swiglu_forward_ref(), ck_q6_k_q8_k_provider_name(), ck_q8k_activations_enabled(), gated_deltanet_autoregressive_forward(), gated_deltanet_impl_name(), geglu_forward_fp32(), gemm_avx512_parallel(), gemm_blocked_serial(), gemm_fine_grained_parallel(), gemm_naive_parallel(), gemm_nn_avx512(), gemm_nn_avx512_probe(), gemm_nn_blocked(), gemm_nn_parallel(), gemm_nt_f16(), gemm_nt_fp32_exact_parallel_dispatch(), gemm_nt_q6_k_q8_k_m4_tile(), gemm_nt_q8_0_q8_0_contract(), gemm_tn_avx512(), gemm_tn_blocked(), gemm_tn_parallel(), gemv_q4_k_q8_k_vnni(), gemv_q6_k_q8_k(), gemv_q6_k_q8_k_parallel_simd(), gemv_q8_0_q8_0_contract(), layernorm_forward_rolled_slice(), layernorm_forward_unrolled_slice(), mrope_qk_imrope_positions(), mrope_qk_vision(), rmsnorm_backward(), rmsnorm_forward_strided_f32(), softmax_cross_entropy_loss_index_mean_impl(), softmax_cross_entropy_loss_legacy_mean_impl(), swiglu_backward(), swiglu_forward(), and swiglu_forward_q8_k().

◆ ck_strict_store_next_gemm_a()

void ck_strict_store_next_gemm_a ( const float *  data,
size_t  elems 
)

Definition at line 48 of file ckernel_strict.c.

49{
50 if (!ck_strict_parity || !data || elems == 0) {
53 return;
54 }
55 if (elems > ck_strict_next_gemm_a_cap) {
56 float *next = (float *) realloc(ck_strict_next_gemm_a, elems * sizeof(float));
57 if (!next) {
60 return;
61 }
64 }
65 memcpy(ck_strict_next_gemm_a, data, elems * sizeof(float));
68}
static size_t ck_strict_next_gemm_a_cap

References ck_strict_next_gemm_a, ck_strict_next_gemm_a_cap, ck_strict_next_gemm_a_size, ck_strict_next_gemm_a_valid, and ck_strict_parity.

Referenced by ck_attention_full_ggml_graph_oracle_multihead().

◆ ckernel_backend_native()

CKMathBackend ckernel_backend_native ( void  )

Obtain the built-in native backend (single-node CPU, C + intrinsics).

Definition at line 39 of file backend_native.c.

40{
43 return b;
44}
static void ckernel_sgemm_native(int M, int N, int K, const float *A, int lda, const float *B, int ldb, const float *bias, float *C, int ldc)
void(* sgemm)(int M, int N, int K, const float *A, int lda, const float *B, int ldb, const float *bias, float *C, int ldc)

References ckernel_sgemm_native(), and CKMathBackend::sgemm.

◆ deepseek_csa_attention_backward_f32()

void deepseek_csa_attention_backward_f32 ( const float *  d_out,
const float *  q,
const float *  k,
const float *  v,
const int *  indices,
const float *  attn,
float *  d_q,
float *  d_k,
float *  d_v,
int  query_tokens,
int  key_tokens,
int  heads,
int  dim,
int  top_k,
float  scale 
)

Definition at line 621 of file deepseek_kernels.c.

636{
637 if (!d_out || !q || !k || !v || !indices || !attn || !d_q || !d_k || !d_v ||
638 query_tokens <= 0 || key_tokens <= 0 || heads <= 0 || dim <= 0 || top_k <= 0) return;
639
640 const size_t q_count = (size_t)query_tokens * (size_t)heads * (size_t)dim;
641 const size_t kv_count = (size_t)key_tokens * (size_t)heads * (size_t)dim;
642 for (size_t i = 0; i < q_count; ++i) d_q[i] = 0.0f;
643 for (size_t i = 0; i < kv_count; ++i) {
644 d_k[i] = 0.0f;
645 d_v[i] = 0.0f;
646 }
647
648 for (int tq = 0; tq < query_tokens; ++tq) {
649 for (int h = 0; h < heads; ++h) {
650 float d_attn[top_k];
651 float attn_dot = 0.0f;
652 for (int j = 0; j < top_k; ++j) {
653 const int tk = indices[((size_t)tq * (size_t)heads + (size_t)h) * (size_t)top_k + (size_t)j];
654 float da = 0.0f;
655 if (tk >= 0 && tk < key_tokens) {
656 const float a = attn[((size_t)tq * (size_t)heads + (size_t)h) * (size_t)top_k + (size_t)j];
657 for (int d = 0; d < dim; ++d) {
658 const float go = d_out[ds_qkv_idx(tq, h, d, heads, dim)];
659 da += go * v[ds_qkv_idx(tk, h, d, heads, dim)];
660 d_v[ds_qkv_idx(tk, h, d, heads, dim)] += a * go;
661 }
662 attn_dot += a * da;
663 }
664 d_attn[j] = da;
665 }
666
667 for (int j = 0; j < top_k; ++j) {
668 const int tk = indices[((size_t)tq * (size_t)heads + (size_t)h) * (size_t)top_k + (size_t)j];
669 if (tk < 0 || tk >= key_tokens) continue;
670 const float a = attn[((size_t)tq * (size_t)heads + (size_t)h) * (size_t)top_k + (size_t)j];
671 const float d_score = a * (d_attn[j] - attn_dot);
672 for (int d = 0; d < dim; ++d) {
673 const float qv = q[ds_qkv_idx(tq, h, d, heads, dim)];
674 const float kv = k[ds_qkv_idx(tk, h, d, heads, dim)];
675 d_q[ds_qkv_idx(tq, h, d, heads, dim)] += scale * d_score * kv;
676 d_k[ds_qkv_idx(tk, h, d, heads, dim)] += scale * d_score * qv;
677 }
678 }
679 }
680 }
681}
static size_t ds_qkv_idx(int token, int head, int d, int heads, int dim)

References ds_qkv_idx().

◆ deepseek_csa_attention_f32()

void deepseek_csa_attention_f32 ( const float *  q,
const float *  k,
const float *  v,
const int *  indices,
float *  out,
float *  attn,
int  query_tokens,
int  key_tokens,
int  heads,
int  dim,
int  top_k,
float  scale 
)

Definition at line 562 of file deepseek_kernels.c.

574{
575 if (!q || !k || !v || !indices || !out || query_tokens <= 0 || key_tokens <= 0 ||
576 heads <= 0 || dim <= 0 || top_k <= 0) return;
577
578 for (int tq = 0; tq < query_tokens; ++tq) {
579 for (int h = 0; h < heads; ++h) {
580 float local_scores[top_k];
581 int valid = 0;
582 for (int j = 0; j < top_k; ++j) {
583 const int tk = indices[((size_t)tq * (size_t)heads + (size_t)h) * (size_t)top_k + (size_t)j];
584 if (tk < 0 || tk >= key_tokens) {
585 local_scores[j] = -FLT_MAX;
586 continue;
587 }
588 float dot = 0.0f;
589 for (int d = 0; d < dim; ++d) {
590 dot += q[ds_qkv_idx(tq, h, d, heads, dim)] * k[ds_qkv_idx(tk, h, d, heads, dim)];
591 }
592 local_scores[j] = dot * scale;
593 valid++;
594 }
595
596 float *out_row = out + ds_qkv_idx(tq, h, 0, heads, dim);
597 for (int d = 0; d < dim; ++d) out_row[d] = 0.0f;
598 if (valid == 0) {
599 if (attn) {
600 for (int j = 0; j < top_k; ++j) {
601 attn[((size_t)tq * (size_t)heads + (size_t)h) * (size_t)top_k + (size_t)j] = 0.0f;
602 }
603 }
604 continue;
605 }
606
607 ds_softmax(local_scores, top_k);
608 for (int j = 0; j < top_k; ++j) {
609 const int tk = indices[((size_t)tq * (size_t)heads + (size_t)h) * (size_t)top_k + (size_t)j];
610 const float a = (tk >= 0 && tk < key_tokens) ? local_scores[j] : 0.0f;
611 if (attn) attn[((size_t)tq * (size_t)heads + (size_t)h) * (size_t)top_k + (size_t)j] = a;
612 if (a == 0.0f) continue;
613 for (int d = 0; d < dim; ++d) {
614 out_row[d] += a * v[ds_qkv_idx(tk, h, d, heads, dim)];
615 }
616 }
617 }
618 }
619}
static void ds_softmax(float *x, int n)

References ds_qkv_idx(), and ds_softmax().

Referenced by deepseek_hybrid_attention_f32().

◆ deepseek_dsa_topk_softmax_backward_f32()

void deepseek_dsa_topk_softmax_backward_f32 ( const int *  indices,
const float *  weights,
const float *  d_weights,
float *  d_scores,
int  tokens,
int  heads,
int  key_count,
int  top_k 
)

Definition at line 153 of file deepseek_kernels.c.

161{
162 if (!indices || !weights || !d_weights || !d_scores ||
163 tokens <= 0 || heads <= 0 || key_count <= 0 || top_k <= 0) return;
164
166 weights,
167 d_weights,
168 d_scores,
169 tokens * heads,
170 key_count,
171 top_k);
172}
void topk_softmax_backward_f32(const int *indices, const float *weights, const float *d_weights, float *d_scores, int num_tokens, int n_experts_or_keys, int k)
Backward for hard top-k followed by softmax over selected values.

References topk_softmax_backward_f32().

◆ deepseek_dsa_topk_softmax_f32()

void deepseek_dsa_topk_softmax_f32 ( const float *  scores,
int *  indices,
float *  weights,
int  tokens,
int  heads,
int  key_count,
int  top_k 
)

Definition at line 86 of file deepseek_kernels.c.

93{
94 if (!scores || !indices || !weights || tokens <= 0 || heads <= 0 ||
95 key_count <= 0 || top_k <= 0) return;
96
97 if (top_k > key_count) top_k = key_count;
98
99 for (int t = 0; t < tokens; ++t) {
100 for (int h = 0; h < heads; ++h) {
101 const float *row = scores + ((size_t)t * (size_t)heads + (size_t)h) * (size_t)key_count;
102 int *idx = indices + ((size_t)t * (size_t)heads + (size_t)h) * (size_t)top_k;
103 float *w = weights + ((size_t)t * (size_t)heads + (size_t)h) * (size_t)top_k;
104
105 for (int k = 0; k < top_k; ++k) {
106 idx[k] = -1;
107 w[k] = -FLT_MAX;
108 }
109
110 for (int j = 0; j < key_count; ++j) {
111 const float v = row[j];
112 int pos = -1;
113 for (int k = 0; k < top_k; ++k) {
114 if (idx[k] < 0 || v > w[k] || (v == w[k] && j < idx[k])) {
115 pos = k;
116 break;
117 }
118 }
119 if (pos >= 0) {
120 for (int k = top_k - 1; k > pos; --k) {
121 idx[k] = idx[k - 1];
122 w[k] = w[k - 1];
123 }
124 idx[pos] = j;
125 w[pos] = v;
126 }
127 }
128
129 float max_v = w[0];
130 for (int k = 1; k < top_k; ++k) if (w[k] > max_v) max_v = w[k];
131 float sum = 0.0f;
132 for (int k = 0; k < top_k; ++k) {
133 w[k] = expf(w[k] - max_v);
134 sum += w[k];
135 }
136 if (sum > 0.0f) {
137 const float inv = 1.0f / sum;
138 for (int k = 0; k < top_k; ++k) w[k] *= inv;
139 }
140 }
141 }
142}

◆ deepseek_hybrid_attention_f32()

void deepseek_hybrid_attention_f32 ( const float *  q,
const float *  k,
const float *  v,
const int *  indices,
float *  out,
float *  attn,
int  query_tokens,
int  key_tokens,
int  heads,
int  dim,
int  top_k,
float  scale,
int  mode 
)

Definition at line 683 of file deepseek_kernels.c.

696{
697 if (mode != 0) {
698 deepseek_csa_attention_f32(q, k, v, indices, out, attn,
699 query_tokens, key_tokens, heads, dim, top_k, scale);
700 return;
701 }
702
703 int dense_indices[query_tokens * heads * key_tokens];
704 for (int tq = 0; tq < query_tokens; ++tq) {
705 for (int h = 0; h < heads; ++h) {
706 for (int tk = 0; tk < key_tokens; ++tk) {
707 dense_indices[((size_t)tq * (size_t)heads + (size_t)h) * (size_t)key_tokens + (size_t)tk] = tk;
708 }
709 }
710 }
711 deepseek_csa_attention_f32(q, k, v, dense_indices, out, attn,
712 query_tokens, key_tokens, heads, dim, key_tokens, scale);
713}
void deepseek_csa_attention_f32(const float *q, const float *k, const float *v, const int *indices, float *out, float *attn, int query_tokens, int key_tokens, int heads, int dim, int top_k, float scale)

References deepseek_csa_attention_f32().

◆ deepseek_mhc_mix_backward_f32()

void deepseek_mhc_mix_backward_f32 ( const float *  d_out,
const float *  streams,
const float *  mix,
float *  d_streams,
float *  d_mix,
int  tokens,
int  n_streams,
int  dim 
)

Definition at line 53 of file deepseek_kernels.c.

61{
62 if (!d_out || !streams || !mix || !d_streams || !d_mix ||
63 tokens <= 0 || n_streams <= 0 || dim <= 0) return;
64
65 const size_t stream_count = (size_t)tokens * (size_t)n_streams * (size_t)dim;
66 const size_t mix_count = (size_t)tokens * (size_t)n_streams * (size_t)n_streams;
67 for (size_t i = 0; i < stream_count; ++i) d_streams[i] = 0.0f;
68 for (size_t i = 0; i < mix_count; ++i) d_mix[i] = 0.0f;
69
70 for (int t = 0; t < tokens; ++t) {
71 for (int os = 0; os < n_streams; ++os) {
72 for (int is = 0; is < n_streams; ++is) {
73 float d_mix_acc = 0.0f;
74 const float m = mix[ds_mix_idx(t, os, is, n_streams)];
75 for (int d = 0; d < dim; ++d) {
76 const float go = d_out[ds_mhc_idx(t, os, d, n_streams, dim)];
77 d_streams[ds_mhc_idx(t, is, d, n_streams, dim)] += m * go;
78 d_mix_acc += go * streams[ds_mhc_idx(t, is, d, n_streams, dim)];
79 }
80 d_mix[ds_mix_idx(t, os, is, n_streams)] = d_mix_acc;
81 }
82 }
83 }
84}
static size_t ds_mix_idx(int t, int out_s, int in_s, int n_streams)
static size_t ds_mhc_idx(int t, int s, int d, int n_streams, int dim)

References ds_mhc_idx(), and ds_mix_idx().

◆ deepseek_mhc_mix_f32()

void deepseek_mhc_mix_f32 ( const float *  streams,
const float *  mix,
float *  out,
int  tokens,
int  n_streams,
int  dim 
)

Definition at line 30 of file deepseek_kernels.c.

36{
37 if (!streams || !mix || !out || tokens <= 0 || n_streams <= 0 || dim <= 0) return;
38
39 for (int t = 0; t < tokens; ++t) {
40 for (int os = 0; os < n_streams; ++os) {
41 for (int d = 0; d < dim; ++d) {
42 float acc = 0.0f;
43 for (int is = 0; is < n_streams; ++is) {
44 acc += mix[ds_mix_idx(t, os, is, n_streams)] *
45 streams[ds_mhc_idx(t, is, d, n_streams, dim)];
46 }
47 out[ds_mhc_idx(t, os, d, n_streams, dim)] = acc;
48 }
49 }
50 }
51}

References ds_mhc_idx(), and ds_mix_idx().

◆ deepseek_mla_attention_decode_f32()

void deepseek_mla_attention_decode_f32 ( const float *  q,
const float *  k_cache,
const float *  v_cache,
float *  output,
int  num_heads,
int  num_kv_heads,
int  cache_len,
int  qk_head_dim,
int  v_head_dim,
int  max_seq_len,
int  cache_stride 
)

Definition at line 1044 of file deepseek_kernels.c.

1055{
1056 if (cache_len <= 0 || (size_t)cache_len > SIZE_MAX / sizeof(float)) return;
1057 const size_t scores_bytes = (size_t)cache_len * sizeof(float);
1058 float *scores = (float *)malloc(scores_bytes);
1059 if (!scores) return;
1061 q, k_cache, v_cache, output, num_heads, num_kv_heads, cache_len,
1062 qk_head_dim, v_head_dim, max_seq_len, cache_stride,
1063 1.0f / sqrtf((float)qk_head_dim), scores, scores_bytes);
1064 free(scores);
1065}
void deepseek_mla_attention_decode_f32_workspace(const float *q, const float *k_cache, const float *v_cache, float *output, int num_heads, int num_kv_heads, int cache_len, int qk_head_dim, int v_head_dim, int max_seq_len, int cache_stride, float scale, float *scores, size_t scores_bytes)

References deepseek_mla_attention_decode_f32_workspace().

◆ deepseek_mla_attention_decode_f32_workspace()

void deepseek_mla_attention_decode_f32_workspace ( const float *  q,
const float *  k_cache,
const float *  v_cache,
float *  output,
int  num_heads,
int  num_kv_heads,
int  cache_len,
int  qk_head_dim,
int  v_head_dim,
int  max_seq_len,
int  cache_stride,
float  scale,
float *  scores,
size_t  scores_bytes 
)

Definition at line 978 of file deepseek_kernels.c.

992{
993 if (!q || !k_cache || !v_cache || !output || num_heads <= 0 ||
994 num_kv_heads <= 0 || cache_len <= 0 || qk_head_dim <= 0 ||
995 v_head_dim <= 0 || max_seq_len <= 0 || cache_stride <= 0 ||
996 !isfinite(scale) || scale <= 0.0f) {
997 return;
998 }
999 if (qk_head_dim > cache_stride || v_head_dim > cache_stride) {
1000 return;
1001 }
1002 if ((size_t)cache_len > SIZE_MAX / sizeof(float) || !scores ||
1003 scores_bytes < (size_t)cache_len * sizeof(float)) {
1004 return;
1005 }
1006
1007 for (int h = 0; h < num_heads; ++h) {
1008 const int kv_h = (int)((long long)h * (long long)num_kv_heads / (long long)num_heads);
1009 const float *q_vec = q + (size_t)h * (size_t)qk_head_dim;
1010
1011 float max_score = -FLT_MAX;
1012 for (int j = 0; j < cache_len; ++j) {
1013 const float *k_vec = k_cache + ((size_t)kv_h * (size_t)max_seq_len + (size_t)j) * (size_t)cache_stride;
1014 float dot = 0.0f;
1015 for (int d = 0; d < qk_head_dim; ++d) {
1016 dot += q_vec[d] * k_vec[d];
1017 }
1018 const float score = dot * scale;
1019 scores[j] = score;
1020 if (score > max_score) max_score = score;
1021 }
1022
1023 float sum = 0.0f;
1024 for (int j = 0; j < cache_len; ++j) {
1025 const float e = expf(scores[j] - max_score);
1026 scores[j] = e;
1027 sum += e;
1028 }
1029
1030 const float inv_sum = sum > 0.0f ? (1.0f / sum) : 0.0f;
1031 float *out = output + (size_t)h * (size_t)v_head_dim;
1032 for (int d = 0; d < v_head_dim; ++d) out[d] = 0.0f;
1033 for (int j = 0; j < cache_len; ++j) {
1034 const float w = scores[j] * inv_sum;
1035 const float *v_vec = v_cache + ((size_t)kv_h * (size_t)max_seq_len + (size_t)j) * (size_t)cache_stride;
1036 for (int d = 0; d < v_head_dim; ++d) {
1037 out[d] += w * v_vec[d];
1038 }
1039 }
1040 }
1041
1042}

References score.

Referenced by deepseek_mla_attention_decode_f32().

◆ deepseek_mla_attention_f32()

void deepseek_mla_attention_f32 ( const float *  q,
const float *  k,
const float *  v,
float *  output,
int  num_heads,
int  num_kv_heads,
int  num_tokens,
int  qk_head_dim,
int  v_head_dim 
)

Definition at line 879 of file deepseek_kernels.c.

888{
889 if (num_tokens <= 0 || (size_t)num_tokens > SIZE_MAX / sizeof(float)) return;
890 const size_t scores_bytes = (size_t)num_tokens * sizeof(float);
891 float *scores = (float *)malloc(scores_bytes);
892 if (!scores) return;
894 q, k, v, output, num_heads, num_kv_heads, num_tokens,
895 qk_head_dim, v_head_dim, 1.0f / sqrtf((float)qk_head_dim),
896 scores, scores_bytes);
897 free(scores);
898}
void deepseek_mla_attention_f32_workspace(const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int qk_head_dim, int v_head_dim, float scale, float *scores, size_t scores_bytes)

References deepseek_mla_attention_f32_workspace().

◆ deepseek_mla_attention_f32_parallel_dispatch()

void deepseek_mla_attention_f32_parallel_dispatch ( const float *  q,
const float *  k,
const float *  v,
float *  output,
int  num_heads,
int  num_kv_heads,
int  num_tokens,
int  qk_head_dim,
int  v_head_dim,
float  scale,
float *  scores,
size_t  scores_bytes 
)

Definition at line 839 of file deepseek_kernels.c.

852{
853 ck_threadpool_t *pool = ck_threadpool_global();
854 const char *disabled = getenv("CK_DISABLE_MLA_PARALLEL_PREFILL");
855 int active = pool ? ck_threadpool_n_threads(pool) : 1;
856 if (active > num_heads) active = num_heads;
857 const size_t score_row_bytes =
858 num_tokens > 0 ? (size_t)num_tokens * sizeof(float) : 0;
859 if ((disabled && disabled[0] && strcmp(disabled, "0") != 0) ||
860 !pool || active <= 1 || num_tokens <= 0 || num_heads <= 0 ||
861 num_tokens > INT_MAX / num_heads ||
862 score_row_bytes == 0 || (size_t)active > SIZE_MAX / score_row_bytes ||
863 scores_bytes < (size_t)active * score_row_bytes) {
865 q, k, v, output, num_heads, num_kv_heads, num_tokens,
866 qk_head_dim, v_head_dim, scale, scores, scores_bytes);
867 return;
868 }
869 ds_mla_attention_f32_args_t args = {
870 .q = q, .k = k, .v = v, .output = output,
871 .num_heads = num_heads, .num_kv_heads = num_kv_heads,
872 .num_tokens = num_tokens, .qk_head_dim = qk_head_dim,
873 .v_head_dim = v_head_dim, .scale = scale, .scores = scores,
874 };
875 atomic_init(&args.next_token, 0);
877}
static void ds_mla_attention_f32_work(int ith, int nth, void *opaque)

References ck_threadpool_dispatch_n(), ck_threadpool_global(), ck_threadpool_n_threads(), deepseek_mla_attention_f32_workspace(), and ds_mla_attention_f32_work().

◆ deepseek_mla_attention_f32_workspace()

void deepseek_mla_attention_f32_workspace ( const float *  q,
const float *  k,
const float *  v,
float *  output,
int  num_heads,
int  num_kv_heads,
int  num_tokens,
int  qk_head_dim,
int  v_head_dim,
float  scale,
float *  scores,
size_t  scores_bytes 
)

Definition at line 768 of file deepseek_kernels.c.

780{
781 if (!q || !k || !v || !output || num_heads <= 0 || num_kv_heads <= 0 ||
782 num_tokens <= 0 || qk_head_dim <= 0 || v_head_dim <= 0 ||
783 num_tokens > INT_MAX / num_heads ||
784 !isfinite(scale) || scale <= 0.0f) {
785 return;
786 }
787 if ((size_t)num_tokens > SIZE_MAX / sizeof(float) || !scores ||
788 scores_bytes < (size_t)num_tokens * sizeof(float)) {
789 return;
790 }
791
793 q, k, v, output, num_heads, num_kv_heads, num_tokens,
794 qk_head_dim, v_head_dim, scale, scores,
795 0, num_tokens * num_heads, 1);
796}
static void ds_mla_attention_f32_query_range(const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int qk_head_dim, int v_head_dim, float scale, float *scores, int query_begin, int query_end, int query_step)

References ds_mla_attention_f32_query_range().

Referenced by deepseek_mla_attention_f32(), and deepseek_mla_attention_f32_parallel_dispatch().

◆ deepseek_mla_kv_cache_batch_store_f32()

void deepseek_mla_kv_cache_batch_store_f32 ( float *  k_cache,
float *  v_cache,
const float *  k,
const float *  v,
int  num_tokens,
int  num_kv_heads,
int  qk_head_dim,
int  v_head_dim,
int  max_seq_len,
int  cache_stride 
)

Definition at line 900 of file deepseek_kernels.c.

910{
911 if (!k_cache || !v_cache || !k || !v || num_tokens <= 0 ||
912 num_kv_heads <= 0 || qk_head_dim <= 0 || v_head_dim <= 0 ||
913 max_seq_len <= 0 || cache_stride <= 0) {
914 return;
915 }
916 if (qk_head_dim > cache_stride || v_head_dim > cache_stride) {
917 return;
918 }
919 if (num_tokens > max_seq_len) {
920 num_tokens = max_seq_len;
921 }
922
923 for (int t = 0; t < num_tokens; ++t) {
924 for (int h = 0; h < num_kv_heads; ++h) {
925 const float *k_src = k + ((size_t)t * (size_t)num_kv_heads + (size_t)h) * (size_t)qk_head_dim;
926 const float *v_src = v + ((size_t)t * (size_t)num_kv_heads + (size_t)h) * (size_t)v_head_dim;
927 float *k_dst = k_cache + ((size_t)h * (size_t)max_seq_len + (size_t)t) * (size_t)cache_stride;
928 float *v_dst = v_cache + ((size_t)h * (size_t)max_seq_len + (size_t)t) * (size_t)cache_stride;
929 for (int d = 0; d < qk_head_dim; ++d) k_dst[d] = k_src[d];
930 for (int d = qk_head_dim; d < cache_stride; ++d) k_dst[d] = 0.0f;
931 for (int d = 0; d < v_head_dim; ++d) v_dst[d] = v_src[d];
932 for (int d = v_head_dim; d < cache_stride; ++d) v_dst[d] = 0.0f;
933 }
934 }
935}

◆ deepseek_mla_kv_cache_store_f32()

void deepseek_mla_kv_cache_store_f32 ( float *  k_cache,
float *  v_cache,
const float *  k,
const float *  v,
int  pos,
int  num_kv_heads,
int  qk_head_dim,
int  v_head_dim,
int  max_seq_len,
int  cache_stride 
)

Definition at line 937 of file deepseek_kernels.c.

947{
948 if (!k_cache || !v_cache || !k || !v || pos < 0 ||
949 num_kv_heads <= 0 || qk_head_dim <= 0 || v_head_dim <= 0 ||
950 max_seq_len <= 0 || cache_stride <= 0) {
951 return;
952 }
953 if (pos >= max_seq_len || qk_head_dim > cache_stride || v_head_dim > cache_stride) {
954 return;
955 }
956
957 for (int h = 0; h < num_kv_heads; ++h) {
958 const float *k_src = k + ((size_t)h * (size_t)qk_head_dim);
959 const float *v_src = v + ((size_t)h * (size_t)v_head_dim);
960 float *k_dst = k_cache + ((size_t)h * (size_t)max_seq_len + (size_t)pos) * (size_t)cache_stride;
961 float *v_dst = v_cache + ((size_t)h * (size_t)max_seq_len + (size_t)pos) * (size_t)cache_stride;
962
963 for (int d = 0; d < qk_head_dim; ++d) {
964 k_dst[d] = k_src[d];
965 }
966 for (int d = qk_head_dim; d < cache_stride; ++d) {
967 k_dst[d] = 0.0f;
968 }
969 for (int d = 0; d < v_head_dim; ++d) {
970 v_dst[d] = v_src[d];
971 }
972 for (int d = v_head_dim; d < cache_stride; ++d) {
973 v_dst[d] = 0.0f;
974 }
975 }
976}

◆ deepseek_mla_kv_decompress_bf16()

void deepseek_mla_kv_decompress_bf16 ( const float *  compressed_kv,
const uint16_t *  kv_b_proj,
float *  k_nope,
float *  value,
int  tokens,
int  heads,
int  kv_lora_rank,
int  qk_nope_dim,
int  v_dim 
)

Definition at line 270 of file deepseek_kernels.c.

279{
280 if (tokens <= 0) return;
282 compressed_kv, kv_b_proj, k_nope, value, tokens, heads,
283 kv_lora_rank, qk_nope_dim, v_dim, 0, tokens);
284}
void deepseek_mla_kv_decompress_bf16_token_range(const float *compressed_kv, const uint16_t *kv_b_proj, float *k_nope, float *value, int tokens, int heads, int kv_lora_rank, int qk_nope_dim, int v_dim, int token_begin, int token_end)

References deepseek_mla_kv_decompress_bf16_token_range().

Referenced by deepseek_mla_kv_decompress_bf16_parallel_dispatch().

◆ deepseek_mla_kv_decompress_bf16_parallel_dispatch()

void deepseek_mla_kv_decompress_bf16_parallel_dispatch ( const float *  compressed_kv,
const uint16_t *  kv_b_proj,
float *  k_nope,
float *  value,
int  tokens,
int  heads,
int  kv_lora_rank,
int  qk_nope_dim,
int  v_dim 
)

Definition at line 308 of file deepseek_kernels.c.

318{
319 ck_threadpool_t *pool = ck_threadpool_global();
320 const char *disabled = getenv("CK_DISABLE_MLA_PARALLEL_PREFILL");
321 if ((disabled && disabled[0] && strcmp(disabled, "0") != 0) ||
322 !pool || ck_threadpool_n_threads(pool) <= 1 || tokens < 2) {
324 compressed_kv, kv_b_proj, k_nope, value, tokens, heads,
325 kv_lora_rank, qk_nope_dim, v_dim);
326 return;
327 }
328 ds_mla_kv_decompress_bf16_args_t args = {
329 .compressed_kv = compressed_kv,
330 .kv_b_proj = kv_b_proj,
331 .k_nope = k_nope,
332 .value = value,
333 .tokens = tokens,
334 .heads = heads,
335 .kv_lora_rank = kv_lora_rank,
336 .qk_nope_dim = qk_nope_dim,
337 .v_dim = v_dim,
338 };
339 int active = ck_threadpool_n_threads(pool);
340 if (active > tokens) active = tokens;
341 int grain = tokens / (active * 4);
342 if (grain < 1) grain = 1;
344 pool, active, 0, tokens, grain, ds_mla_kv_decompress_bf16_rows, &args);
345}
void ck_threadpool_parallel_for_n(ck_threadpool_t *pool, int active_threads, int begin, int end, int grain_size, ck_range_fn_t fn, void *args)
void deepseek_mla_kv_decompress_bf16(const float *compressed_kv, const uint16_t *kv_b_proj, float *k_nope, float *value, int tokens, int heads, int kv_lora_rank, int qk_nope_dim, int v_dim)
static void ds_mla_kv_decompress_bf16_rows(int begin, int end, void *opaque)

References ck_threadpool_global(), ck_threadpool_n_threads(), ck_threadpool_parallel_for_n(), deepseek_mla_kv_decompress_bf16(), and ds_mla_kv_decompress_bf16_rows().

◆ deepseek_mla_kv_decompress_bf16_token_range()

void deepseek_mla_kv_decompress_bf16_token_range ( const float *  compressed_kv,
const uint16_t *  kv_b_proj,
float *  k_nope,
float *  value,
int  tokens,
int  heads,
int  kv_lora_rank,
int  qk_nope_dim,
int  v_dim,
int  token_begin,
int  token_end 
)

Definition at line 225 of file deepseek_kernels.c.

236{
237 if (!compressed_kv || !kv_b_proj || !k_nope || !value ||
238 tokens <= 0 || heads <= 0 || kv_lora_rank <= 0 || qk_nope_dim <= 0 || v_dim <= 0 ||
239 token_begin < 0 || token_begin >= token_end || token_end > tokens) {
240 return;
241 }
242
243 const int out_per_head = qk_nope_dim + v_dim;
244 for (int t = token_begin; t < token_end; ++t) {
245 for (int h = 0; h < heads; ++h) {
246 for (int d = 0; d < qk_nope_dim; ++d) {
247 const int out_col = h * out_per_head + d;
248 float acc = 0.0f;
249 for (int r = 0; r < kv_lora_rank; ++r) {
250 acc += bf16_to_float(kv_b_proj[(size_t)out_col * (size_t)kv_lora_rank + (size_t)r]) *
251 compressed_kv[ds_mla_tok_idx(t, r, kv_lora_rank)];
252 }
253 k_nope[ds_mla_thd_idx(t, h, d, heads, qk_nope_dim)] =
255 }
256 for (int d = 0; d < v_dim; ++d) {
257 const int out_col = h * out_per_head + qk_nope_dim + d;
258 float acc = 0.0f;
259 for (int r = 0; r < kv_lora_rank; ++r) {
260 acc += bf16_to_float(kv_b_proj[(size_t)out_col * (size_t)kv_lora_rank + (size_t)r]) *
261 compressed_kv[ds_mla_tok_idx(t, r, kv_lora_rank)];
262 }
263 value[ds_mla_thd_idx(t, h, d, heads, v_dim)] =
265 }
266 }
267 }
268}
static size_t ds_mla_thd_idx(int t, int h, int d, int heads, int dim)
static size_t ds_mla_tok_idx(int t, int d, int dim)

References bf16_to_float(), ds_mla_thd_idx(), ds_mla_tok_idx(), and float_to_bf16().

Referenced by deepseek_mla_kv_decompress_bf16(), and ds_mla_kv_decompress_bf16_rows().

◆ deepseek_mla_kv_decompress_f32()

void deepseek_mla_kv_decompress_f32 ( const float *  compressed_kv,
const float *  kv_b_proj,
float *  k_nope,
float *  value,
int  tokens,
int  heads,
int  kv_lora_rank,
int  qk_nope_dim,
int  v_dim 
)

Definition at line 185 of file deepseek_kernels.c.

194{
195 if (!compressed_kv || !kv_b_proj || !k_nope || !value ||
196 tokens <= 0 || heads <= 0 || kv_lora_rank <= 0 || qk_nope_dim <= 0 || v_dim <= 0) {
197 return;
198 }
199
200 const int out_per_head = qk_nope_dim + v_dim;
201 for (int t = 0; t < tokens; ++t) {
202 for (int h = 0; h < heads; ++h) {
203 for (int d = 0; d < qk_nope_dim; ++d) {
204 const int out_col = h * out_per_head + d;
205 float acc = 0.0f;
206 for (int r = 0; r < kv_lora_rank; ++r) {
207 acc += kv_b_proj[(size_t)out_col * (size_t)kv_lora_rank + (size_t)r] *
208 compressed_kv[ds_mla_tok_idx(t, r, kv_lora_rank)];
209 }
210 k_nope[ds_mla_thd_idx(t, h, d, heads, qk_nope_dim)] = acc;
211 }
212 for (int d = 0; d < v_dim; ++d) {
213 const int out_col = h * out_per_head + qk_nope_dim + d;
214 float acc = 0.0f;
215 for (int r = 0; r < kv_lora_rank; ++r) {
216 acc += kv_b_proj[(size_t)out_col * (size_t)kv_lora_rank + (size_t)r] *
217 compressed_kv[ds_mla_tok_idx(t, r, kv_lora_rank)];
218 }
219 value[ds_mla_thd_idx(t, h, d, heads, v_dim)] = acc;
220 }
221 }
222 }
223}

References ds_mla_thd_idx(), and ds_mla_tok_idx().

◆ deepseek_mla_partial_rope_concat_f32()

void deepseek_mla_partial_rope_concat_f32 ( const float *  q_nope,
const float *  q_pe,
const float *  k_nope,
const float *  k_pe,
const float *  cos,
const float *  sin,
float *  query,
float *  key,
int  tokens,
int  heads,
int  qk_nope_dim,
int  qk_rope_dim 
)

Definition at line 367 of file deepseek_kernels.c.

379{
380 if (!q_nope || !q_pe || !k_nope || !k_pe || !cos || !sin || !query || !key ||
381 tokens <= 0 || heads <= 0 || qk_nope_dim <= 0 || qk_rope_dim <= 0 || (qk_rope_dim % 2) != 0) {
382 return;
383 }
384
385 const int q_head_dim = qk_nope_dim + qk_rope_dim;
386 for (int t = 0; t < tokens; ++t) {
387 const float *cos_row = cos + (size_t)t * (size_t)(qk_rope_dim / 2);
388 const float *sin_row = sin + (size_t)t * (size_t)(qk_rope_dim / 2);
389 for (int h = 0; h < heads; ++h) {
390 float *q_out = query + ds_mla_thd_idx(t, h, 0, heads, q_head_dim);
391 float *k_out = key + ds_mla_thd_idx(t, h, 0, heads, q_head_dim);
392 const float *qn = q_nope + ds_mla_thd_idx(t, h, 0, heads, qk_nope_dim);
393 const float *qp = q_pe + ds_mla_thd_idx(t, h, 0, heads, qk_rope_dim);
394 const float *kn = k_nope + ds_mla_thd_idx(t, h, 0, heads, qk_nope_dim);
395 const float *kp = k_pe + ds_mla_tok_idx(t, 0, qk_rope_dim);
396 for (int d = 0; d < qk_nope_dim; ++d) {
397 q_out[d] = qn[d];
398 k_out[d] = kn[d];
399 }
400 ds_mla_apply_kimi_rope(qp, q_out + qk_nope_dim, cos_row, sin_row, qk_rope_dim);
401 ds_mla_apply_kimi_rope(kp, k_out + qk_nope_dim, cos_row, sin_row, qk_rope_dim);
402 }
403 }
404}
static void ds_mla_apply_kimi_rope(const float *src, float *dst, const float *cos_row, const float *sin_row, int dim)

References ds_mla_apply_kimi_rope(), ds_mla_thd_idx(), and ds_mla_tok_idx().

◆ deepseek_mla_partial_rope_concat_packed_bf16_storage()

void deepseek_mla_partial_rope_concat_packed_bf16_storage ( const float *  q_packed,
const float *  k_nope,
const float *  kv_a_packed,
const float *  cos,
const float *  sin,
float *  query,
float *  key,
int  tokens,
int  heads,
int  kv_lora_rank,
int  qk_nope_dim,
int  qk_rope_dim 
)

Definition at line 473 of file deepseek_kernels.c.

486{
487 if (!q_packed || !k_nope || !kv_a_packed || !cos || !sin || !query || !key ||
488 tokens <= 0 || heads <= 0 || kv_lora_rank <= 0 || qk_nope_dim <= 0 ||
489 qk_rope_dim <= 0 || (qk_rope_dim % 2) != 0) {
490 return;
491 }
492
493 const int q_head_dim = qk_nope_dim + qk_rope_dim;
494 const int kv_a_dim = kv_lora_rank + qk_rope_dim;
495 const int half = qk_rope_dim / 2;
496 for (int t = 0; t < tokens; ++t) {
497 const float *cos_row = cos + (size_t)t * (size_t)half;
498 const float *sin_row = sin + (size_t)t * (size_t)half;
499 const float *kp = kv_a_packed + (size_t)t * (size_t)kv_a_dim + (size_t)kv_lora_rank;
500 for (int h = 0; h < heads; ++h) {
501 const float *q_in = q_packed + ds_mla_thd_idx(t, h, 0, heads, q_head_dim);
502 const float *kn = k_nope + ds_mla_thd_idx(t, h, 0, heads, qk_nope_dim);
503 float *q_out = query + ds_mla_thd_idx(t, h, 0, heads, q_head_dim);
504 float *k_out = key + ds_mla_thd_idx(t, h, 0, heads, q_head_dim);
505
506 for (int d = 0; d < qk_nope_dim; ++d) {
507 q_out[d] = ds_mla_bf16_round(q_in[d]);
508 k_out[d] = ds_mla_bf16_round(kn[d]);
509 }
510
511 float q_pe_tmp[256];
512 for (int i = 0; i < qk_rope_dim; ++i) {
513 q_pe_tmp[i] = ds_mla_bf16_round(q_in[qk_nope_dim + i]);
514 }
515 for (int i = 0; i < half; ++i) {
516 const float q_first = q_pe_tmp[2 * i];
517 const float q_second = q_pe_tmp[2 * i + 1];
518 const float k_first = ds_mla_bf16_round(kp[2 * i]);
519 const float k_second = ds_mla_bf16_round(kp[2 * i + 1]);
520 const float c = ds_mla_bf16_round(cos_row[i]);
521 const float s = ds_mla_bf16_round(sin_row[i]);
522
523 const float q_first_cos = ds_mla_bf16_round(q_first * c);
524 const float q_second_sin = ds_mla_bf16_round(q_second * s);
525 const float q_second_cos = ds_mla_bf16_round(q_second * c);
526 const float q_first_sin = ds_mla_bf16_round(q_first * s);
527 const float k_first_cos = ds_mla_bf16_round(k_first * c);
528 const float k_second_sin = ds_mla_bf16_round(k_second * s);
529 const float k_second_cos = ds_mla_bf16_round(k_second * c);
530 const float k_first_sin = ds_mla_bf16_round(k_first * s);
531
532 q_out[qk_nope_dim + i] = ds_mla_bf16_round(q_first_cos - q_second_sin);
533 q_out[qk_nope_dim + half + i] = ds_mla_bf16_round(q_second_cos + q_first_sin);
534 k_out[qk_nope_dim + i] = ds_mla_bf16_round(k_first_cos - k_second_sin);
535 k_out[qk_nope_dim + half + i] = ds_mla_bf16_round(k_second_cos + k_first_sin);
536 }
537 }
538 }
539}
static float ds_mla_bf16_round(float value)

References ds_mla_bf16_round(), and ds_mla_thd_idx().

◆ deepseek_mla_partial_rope_concat_packed_f32()

void deepseek_mla_partial_rope_concat_packed_f32 ( const float *  q_packed,
const float *  k_nope,
const float *  kv_a_packed,
const float *  cos,
const float *  sin,
float *  query,
float *  key,
int  tokens,
int  heads,
int  kv_lora_rank,
int  qk_nope_dim,
int  qk_rope_dim 
)

Definition at line 406 of file deepseek_kernels.c.

418{
419 if (!q_packed || !k_nope || !kv_a_packed || !cos || !sin || !query || !key ||
420 tokens <= 0 || heads <= 0 || kv_lora_rank <= 0 || qk_nope_dim <= 0 ||
421 qk_rope_dim <= 0 || qk_rope_dim > 256 || (qk_rope_dim % 2) != 0) {
422 return;
423 }
424
425 const int q_head_dim = qk_nope_dim + qk_rope_dim;
426 const int kv_a_dim = kv_lora_rank + qk_rope_dim;
427 const int half = qk_rope_dim / 2;
428 if (qk_rope_dim > 256) {
429 return;
430 }
431 for (int t = 0; t < tokens; ++t) {
432 const float *cos_row = cos + (size_t)t * (size_t)half;
433 const float *sin_row = sin + (size_t)t * (size_t)half;
434 const float *kp = kv_a_packed + (size_t)t * (size_t)kv_a_dim + (size_t)kv_lora_rank;
435 for (int h = 0; h < heads; ++h) {
436 const float *q_in = q_packed + ds_mla_thd_idx(t, h, 0, heads, q_head_dim);
437 const float *kn = k_nope + ds_mla_thd_idx(t, h, 0, heads, qk_nope_dim);
438 float *q_out = query + ds_mla_thd_idx(t, h, 0, heads, q_head_dim);
439 float *k_out = key + ds_mla_thd_idx(t, h, 0, heads, q_head_dim);
440
441 for (int d = 0; d < qk_nope_dim; ++d) {
442 q_out[d] = q_in[d];
443 k_out[d] = kn[d];
444 }
445
446 const float *qp = q_in + qk_nope_dim;
447 float q_pe_tmp[256];
448 if (qk_rope_dim > (int)(sizeof(q_pe_tmp) / sizeof(q_pe_tmp[0]))) {
449 return;
450 }
451 for (int i = 0; i < qk_rope_dim; ++i) q_pe_tmp[i] = qp[i];
452 for (int i = 0; i < half; ++i) {
453 const float q_first = q_pe_tmp[2 * i];
454 const float q_second = q_pe_tmp[2 * i + 1];
455 const float k_first = kp[2 * i];
456 const float k_second = kp[2 * i + 1];
457 const float c = cos_row[i];
458 const float ss = sin_row[i];
459 q_out[qk_nope_dim + i] = q_first * c - q_second * ss;
460 q_out[qk_nope_dim + half + i] = q_second * c + q_first * ss;
461 k_out[qk_nope_dim + i] = k_first * c - k_second * ss;
462 k_out[qk_nope_dim + half + i] = k_second * c + k_first * ss;
463 }
464 }
465 }
466}

References ds_mla_thd_idx().

◆ dequant_q4_0_row()

void dequant_q4_0_row ( const void *  src,
float *  dst,
size_t  n_elements 
)

Dequantize Q4_0 row (multiple blocks)

Parameters
srcQ4_0 data
dstFP32 output
n_elementsNumber of elements to dequantize

Definition at line 63 of file dequant_kernels.c.

64{
65 const block_q4_0 *blocks = (const block_q4_0 *)src;
66 const size_t n_blocks = n_elements / QK4_0;
67
68 for (size_t b = 0; b < n_blocks; b++) {
69 dequant_q4_0_block(&blocks[b], &dst[b * QK4_0]);
70 }
71}
#define QK4_0
void dequant_q4_0_block(const block_q4_0 *block, float *output)
Dequantize a single Q4_0 block to FP32.

References dequant_q4_0_block(), and QK4_0.

◆ dequant_q4_1_row()

void dequant_q4_1_row ( const void *  src,
float *  dst,
size_t  n_elements 
)

Dequantize Q4_1 row (multiple blocks)

Definition at line 141 of file dequant_kernels.c.

142{
143 const block_q4_1 *blocks = (const block_q4_1 *)src;
144 const size_t n_blocks = n_elements / QK4_1;
145
146 for (size_t b = 0; b < n_blocks; b++) {
147 dequant_q4_1_block(&blocks[b], &dst[b * QK4_1]);
148 }
149}
#define QK4_1
void dequant_q4_1_block(const block_q4_1 *block, float *output)
Dequantize a single Q4_1 block to FP32.

References dequant_q4_1_block(), and QK4_1.

Referenced by dequant_row().

◆ dequant_q4_k_row()

void dequant_q4_k_row ( const void *  src,
float *  dst,
size_t  n_elements 
)

Dequantize Q4_K row (multiple blocks)

Definition at line 372 of file dequant_kernels.c.

373{
374 const block_q4_K *blocks = (const block_q4_K *)src;
375 const size_t n_blocks = n_elements / QK_K;
376
377 for (size_t b = 0; b < n_blocks; b++) {
378 dequant_q4_k_block(&blocks[b], &dst[b * QK_K]);
379 }
380}
#define QK_K
void dequant_q4_k_block(const block_q4_K *block, float *output)
Dequantize a single Q4_K block to FP32.

References dequant_q4_k_block(), and QK_K.

Referenced by embedding_forward_q4_k().

◆ dequant_q5_0_row()

void dequant_q5_0_row ( const void *  src,
float *  dst,
size_t  n_elements 
)

Dequantize Q5_0 row (multiple blocks)

Definition at line 198 of file dequant_kernels.c.

199{
200 const block_q5_0 *blocks = (const block_q5_0 *)src;
201 const size_t n_blocks = n_elements / QK5_0;
202
203 for (size_t b = 0; b < n_blocks; b++) {
204 dequant_q5_0_block(&blocks[b], &dst[b * QK5_0]);
205 }
206}
#define QK5_0
void dequant_q5_0_block(const block_q5_0 *block, float *output)
Dequantize a single Q5_0 block to FP32.

References dequant_q5_0_block(), and QK5_0.

Referenced by embedding_forward_q5_0(), moe_relu2_expert_forward_q5_0_q5_0(), moe_relu2_expert_forward_q5_0_q8_0(), and qwen4_ple_ngram_embed_impl().

◆ dequant_q5_1_row()

void dequant_q5_1_row ( const void *  src,
float *  dst,
size_t  n_elements 
)

Dequantize Q5_1 row (multiple blocks)

Definition at line 257 of file dequant_kernels.c.

258{
259 const block_q5_1 *blocks = (const block_q5_1 *)src;
260 const size_t n_blocks = n_elements / QK5_1;
261
262 for (size_t b = 0; b < n_blocks; b++) {
263 dequant_q5_1_block(&blocks[b], &dst[b * QK5_1]);
264 }
265}
#define QK5_1
void dequant_q5_1_block(const block_q5_1 *block, float *output)
Dequantize a single Q5_1 block to FP32.

References dequant_q5_1_block(), and QK5_1.

Referenced by dequant_row(), and moe_relu2_shared_forward_q5_1_q8_0().

◆ dequant_q6_k_row()

void dequant_q6_k_row ( const void *  src,
float *  dst,
size_t  n_elements 
)

Dequantize Q6_K row (multiple blocks)

Definition at line 422 of file dequant_kernels.c.

423{
424 const block_q6_K *blocks = (const block_q6_K *)src;
425 const size_t n_blocks = n_elements / QK_K;
426
427 for (size_t b = 0; b < n_blocks; b++) {
428 dequant_q6_k_block(&blocks[b], &dst[b * QK_K]);
429 }
430}
void dequant_q6_k_block(const block_q6_K *block, float *output)
Dequantize a single Q6_K block to FP32.

References dequant_q6_k_block(), and QK_K.

Referenced by embedding_forward_q6_k().

◆ dequant_q8_0_row()

void dequant_q8_0_row ( const void *  src,
float *  dst,
size_t  n_elements 
)

Dequantize Q8_0 row (multiple blocks)

Definition at line 288 of file dequant_kernels.c.

289{
290 const block_q8_0 *blocks = (const block_q8_0 *)src;
291 const size_t n_blocks = n_elements / QK8_0;
292
293 for (size_t b = 0; b < n_blocks; b++) {
294 dequant_q8_0_block(&blocks[b], &dst[b * QK8_0]);
295 }
296}
void dequant_q8_0_block(const block_q8_0 *block, float *output)
Dequantize a single Q8_0 block to FP32.

References dequant_q8_0_block(), and QK8_0.

Referenced by dequant_row(), embedding_forward_q8_0(), moe_relu2_expert_forward_q5_0_q8_0(), and moe_relu2_shared_forward_q5_1_q8_0().

◆ embedding_backward()

void embedding_backward ( const int32_t *  token_ids,
int  token_count,
const float *  d_output,
float *  d_token_embeddings,
float *  d_pos_embeddings,
int  vocab_size,
int  embed_dim,
int  aligned_embed_dim,
int  context_window,
int  add_pos 
)

Definition at line 296 of file embedding_kernels.c.

306{
307 if (!token_ids || !d_output || !d_token_embeddings) {
308 return;
309 }
310
311 int tokens = token_count;
312 if (tokens < 0) {
313 tokens = 0;
314 }
315 if (tokens > context_window) {
316 tokens = context_window;
317 }
318
319 for (int t = 0; t < tokens; ++t) {
320 int id = token_ids[t];
321 if (id < 0 || id >= vocab_size) {
322 id = 0;
323 }
324
325 const float *d_out = d_output + (size_t)t * (size_t)aligned_embed_dim;
326 float *d_tok = d_token_embeddings + (size_t)id * (size_t)aligned_embed_dim;
327 float *d_pos = d_pos_embeddings ? (d_pos_embeddings + (size_t)t * (size_t)aligned_embed_dim) : NULL;
328
329 for (int d = 0; d < embed_dim; ++d) {
330 float grad = d_out[d];
331 d_tok[d] += grad;
332 if (add_pos && d_pos) {
333 d_pos[d] += grad;
334 }
335 }
336 }
337}
int vocab_size
Definition true_bpe.h:193

References vocab_size.

◆ embedding_backward_bf16()

void embedding_backward_bf16 ( const int32_t *  token_ids,
int  token_count,
const uint16_t *  d_output,
uint16_t *  d_token_embeddings,
uint16_t *  d_pos_embeddings,
int  vocab_size,
int  embed_dim,
int  aligned_embed_dim,
int  context_window,
int  add_pos 
)

Definition at line 123 of file embedding_kernels_bf16.c.

133{
134 if (!token_ids || !d_output || !d_token_embeddings) {
135 return;
136 }
137
138 int tokens = token_count;
139 if (tokens < 0) tokens = 0;
140 if (tokens > context_window) tokens = context_window;
141
142 for (int t = 0; t < tokens; ++t) {
143 int id = token_ids[t];
144 if (id < 0 || id >= vocab_size) {
145 id = 0;
146 }
147
148 const uint16_t *d_out = d_output + (size_t)t * (size_t)aligned_embed_dim;
149 uint16_t *d_tok = d_token_embeddings + (size_t)id * (size_t)aligned_embed_dim;
150 uint16_t *d_pos = d_pos_embeddings ? (d_pos_embeddings + (size_t)t * (size_t)aligned_embed_dim) : NULL;
151
152 for (int d = 0; d < embed_dim; ++d) {
153 float grad = bf16_to_float(d_out[d]);
154
155 float cur_tok = bf16_to_float(d_tok[d]);
156 d_tok[d] = float_to_bf16(cur_tok + grad);
157
158 if (add_pos && d_pos) {
159 float cur_pos = bf16_to_float(d_pos[d]);
160 d_pos[d] = float_to_bf16(cur_pos + grad);
161 }
162 }
163 }
164}

References bf16_to_float(), float_to_bf16(), and vocab_size.

◆ embedding_backward_bf16_mixed()

void embedding_backward_bf16_mixed ( const int32_t *  token_ids,
int  token_count,
const uint16_t *  d_output,
float *  d_token_embeddings,
float *  d_pos_embeddings,
int  vocab_size,
int  embed_dim,
int  aligned_embed_dim,
int  context_window,
int  add_pos 
)

Definition at line 166 of file embedding_kernels_bf16.c.

176{
177 if (!token_ids || !d_output || !d_token_embeddings) {
178 return;
179 }
180
181 int tokens = token_count;
182 if (tokens < 0) tokens = 0;
183 if (tokens > context_window) tokens = context_window;
184
185 for (int t = 0; t < tokens; ++t) {
186 int id = token_ids[t];
187 if (id < 0 || id >= vocab_size) {
188 id = 0;
189 }
190
191 const uint16_t *d_out = d_output + (size_t)t * (size_t)aligned_embed_dim;
192 float *d_tok = d_token_embeddings + (size_t)id * (size_t)aligned_embed_dim;
193 float *d_pos = d_pos_embeddings ? (d_pos_embeddings + (size_t)t * (size_t)aligned_embed_dim) : NULL;
194
195 for (int d = 0; d < embed_dim; ++d) {
196 const float grad = bf16_to_float(d_out[d]);
197 d_tok[d] += grad;
198 if (add_pos && d_pos) {
199 d_pos[d] += grad;
200 }
201 }
202 }
203}

References bf16_to_float(), and vocab_size.

◆ embedding_forward()

void embedding_forward ( const int32_t *  token_ids,
int  token_count,
int  vocab_size,
const float *  token_embeddings,
const float *  pos_embeddings,
float *  output,
int  embed_dim,
int  aligned_embed_dim,
int  context_window,
int  add_pos 
)

Definition at line 22 of file embedding_kernels.c.

32{
33 if (!token_ids || !token_embeddings || !output) {
34 return;
35 }
36
37 int tokens = token_count;
38 if (tokens < 0) {
39 tokens = 0;
40 }
41 if (tokens > context_window) {
42 tokens = context_window;
43 }
44
45 for (int t = 0; t < tokens; ++t) {
46 int id = token_ids[t];
47 if (id < 0 || id >= vocab_size) {
48 id = 0;
49 }
50
51 const float *tok = token_embeddings + (size_t)id * (size_t)aligned_embed_dim;
52 const float *pos = pos_embeddings ? (pos_embeddings + (size_t)t * (size_t)aligned_embed_dim) : NULL;
53 float *out = output + (size_t)t * (size_t)aligned_embed_dim;
54
55 if (add_pos && pos) {
56 for (int d = 0; d < embed_dim; ++d) {
57 out[d] = tok[d] + pos[d];
58 }
59 } else {
60 for (int d = 0; d < embed_dim; ++d) {
61 out[d] = tok[d];
62 }
63 }
64
65 for (int d = embed_dim; d < aligned_embed_dim; ++d) {
66 out[d] = 0.0f;
67 }
68 }
69
70 for (int t = tokens; t < context_window; ++t) {
71 float *out = output + (size_t)t * (size_t)aligned_embed_dim;
72 memset(out, 0, (size_t)aligned_embed_dim * sizeof(float));
73 }
74}

References vocab_size.

◆ embedding_forward_bf16()

void embedding_forward_bf16 ( const int32_t *  token_ids,
int  token_count,
int  vocab_size,
const uint16_t *  token_embeddings,
const uint16_t *  pos_embeddings,
uint16_t *  output,
int  embed_dim,
int  aligned_embed_dim,
int  context_window,
int  add_pos 
)

Definition at line 21 of file embedding_kernels_bf16.c.

31{
32 if (!token_ids || !token_embeddings || !output) {
33 return;
34 }
35
36 int tokens = token_count;
37 if (tokens < 0) tokens = 0;
38 if (tokens > context_window) tokens = context_window;
39
40 for (int t = 0; t < tokens; ++t) {
41 int id = token_ids[t];
42 if (id < 0 || id >= vocab_size) {
43 id = 0;
44 }
45
46 const uint16_t *tok = token_embeddings + (size_t)id * (size_t)aligned_embed_dim;
47 const uint16_t *pos = pos_embeddings ? (pos_embeddings + (size_t)t * (size_t)aligned_embed_dim) : NULL;
48 uint16_t *out = output + (size_t)t * (size_t)aligned_embed_dim;
49
50 if (add_pos && pos) {
51 for (int d = 0; d < embed_dim; ++d) {
52 float v = bf16_to_float(tok[d]) + bf16_to_float(pos[d]);
53 out[d] = float_to_bf16(v);
54 }
55 } else {
56 for (int d = 0; d < embed_dim; ++d) {
57 out[d] = tok[d];
58 }
59 }
60
61 for (int d = embed_dim; d < aligned_embed_dim; ++d) {
62 out[d] = 0;
63 }
64 }
65
66 for (int t = tokens; t < context_window; ++t) {
67 uint16_t *out = output + (size_t)t * (size_t)aligned_embed_dim;
68 memset(out, 0, (size_t)aligned_embed_dim * sizeof(uint16_t));
69 }
70}

References bf16_to_float(), float_to_bf16(), and vocab_size.

◆ embedding_forward_bf16_fp32()

void embedding_forward_bf16_fp32 ( const int32_t *  token_ids,
int  token_count,
int  vocab_size,
const uint16_t *  token_embeddings,
const float *  pos_embeddings,
float *  output,
int  embed_dim,
int  aligned_embed_dim,
int  context_window,
int  add_pos 
)

Definition at line 73 of file embedding_kernels_bf16.c.

83{
84 if (!token_ids || !token_embeddings || !output) {
85 return;
86 }
87
88 int tokens = token_count;
89 if (tokens < 0) tokens = 0;
90 if (tokens > context_window) tokens = context_window;
91
92 for (int t = 0; t < tokens; ++t) {
93 int id = token_ids[t];
94 if (id < 0 || id >= vocab_size) {
95 id = 0;
96 }
97
98 const uint16_t *tok = token_embeddings + (size_t)id * (size_t)aligned_embed_dim;
99 const float *pos = pos_embeddings ? (pos_embeddings + (size_t)t * (size_t)aligned_embed_dim) : NULL;
100 float *out = output + (size_t)t * (size_t)aligned_embed_dim;
101
102 if (add_pos && pos) {
103 for (int d = 0; d < embed_dim; ++d) {
104 out[d] = bf16_to_float(tok[d]) + pos[d];
105 }
106 } else {
107 for (int d = 0; d < embed_dim; ++d) {
108 out[d] = bf16_to_float(tok[d]);
109 }
110 }
111
112 for (int d = embed_dim; d < aligned_embed_dim; ++d) {
113 out[d] = 0.0f;
114 }
115 }
116
117 for (int t = tokens; t < context_window; ++t) {
118 float *out = output + (size_t)t * (size_t)aligned_embed_dim;
119 memset(out, 0, (size_t)aligned_embed_dim * sizeof(float));
120 }
121}

References bf16_to_float(), and vocab_size.

◆ embedding_forward_q4_k()

void embedding_forward_q4_k ( const int32_t *  token_ids,
int  token_count,
int  vocab_size,
const void *  token_embeddings,
const float *  pos_embeddings,
float *  output,
int  embed_dim,
int  aligned_embed_dim,
int  context_window,
int  add_pos 
)

Definition at line 76 of file embedding_kernels.c.

86{
87 if (!token_ids || !token_embeddings || !output) {
88 return;
89 }
90
91 int tokens = token_count;
92 if (tokens < 0) {
93 tokens = 0;
94 }
95 if (tokens > context_window) {
96 tokens = context_window;
97 }
98
99 const size_t row_bytes = ck_dtype_row_bytes(CK_DT_Q4_K, (size_t)aligned_embed_dim);
100 const uint8_t *base = (const uint8_t *)token_embeddings;
101
102 for (int t = 0; t < tokens; ++t) {
103 int id = token_ids[t];
104 if (id < 0 || id >= vocab_size) {
105 id = 0;
106 }
107
108 const void *tok = base + (size_t)id * row_bytes;
109 const float *pos = pos_embeddings ? (pos_embeddings + (size_t)t * (size_t)aligned_embed_dim) : NULL;
110 float *out = output + (size_t)t * (size_t)aligned_embed_dim;
111
112 dequant_q4_k_row(tok, out, (size_t)aligned_embed_dim);
113
114 if (add_pos && pos) {
115 for (int d = 0; d < embed_dim; ++d) {
116 out[d] += pos[d];
117 }
118 }
119
120 for (int d = embed_dim; d < aligned_embed_dim; ++d) {
121 out[d] = 0.0f;
122 }
123 }
124
125 for (int t = tokens; t < context_window; ++t) {
126 float *out = output + (size_t)t * (size_t)aligned_embed_dim;
127 memset(out, 0, (size_t)aligned_embed_dim * sizeof(float));
128 }
129}
@ CK_DT_Q4_K
static size_t ck_dtype_row_bytes(CKDataType dt, size_t n_elements)
Calculate total bytes for n_elements of given dtype.
void dequant_q4_k_row(const void *src, float *dst, size_t n_elements)
Dequantize Q4_K row (multiple blocks)

References CK_DT_Q4_K, ck_dtype_row_bytes(), dequant_q4_k_row(), and vocab_size.

Referenced by model_decode_token(), model_decode_token(), model_decode_token(), model_decode_token(), model_forward_prefill_impl(), model_forward_prefill_impl(), model_forward_prefill_impl(), model_forward_prefill_impl(), qwen2_0_5b_decode_decode_token(), qwen2_0_5b_decode_decode_token(), qwen2_0_5b_decode_decode_token(), qwen2_0_5b_decode_decode_token(), qwen2_0_5b_decode_forward_prefill_impl(), qwen2_0_5b_decode_forward_prefill_impl(), qwen2_0_5b_decode_forward_prefill_impl(), and qwen2_0_5b_decode_forward_prefill_impl().

◆ embedding_forward_q5_0()

void embedding_forward_q5_0 ( const int32_t *  token_ids,
int  token_count,
int  vocab_size,
const void *  token_embeddings,
const float *  pos_embeddings,
float *  output,
int  embed_dim,
int  aligned_embed_dim,
int  context_window,
int  add_pos 
)

Definition at line 131 of file embedding_kernels.c.

141{
142 if (!token_ids || !token_embeddings || !output) {
143 return;
144 }
145
146 int tokens = token_count;
147 if (tokens < 0) {
148 tokens = 0;
149 }
150 if (tokens > context_window) {
151 tokens = context_window;
152 }
153
154 const size_t row_bytes = ck_dtype_row_bytes(CK_DT_Q5_0, (size_t)aligned_embed_dim);
155 const uint8_t *base = (const uint8_t *)token_embeddings;
156
157 for (int t = 0; t < tokens; ++t) {
158 int id = token_ids[t];
159 if (id < 0 || id >= vocab_size) {
160 id = 0;
161 }
162
163 const void *tok = base + (size_t)id * row_bytes;
164 const float *pos = pos_embeddings ? (pos_embeddings + (size_t)t * (size_t)aligned_embed_dim) : NULL;
165 float *out = output + (size_t)t * (size_t)aligned_embed_dim;
166
167 dequant_q5_0_row(tok, out, (size_t)aligned_embed_dim);
168
169 if (add_pos && pos) {
170 for (int d = 0; d < embed_dim; ++d) {
171 out[d] += pos[d];
172 }
173 }
174
175 for (int d = embed_dim; d < aligned_embed_dim; ++d) {
176 out[d] = 0.0f;
177 }
178 }
179
180 for (int t = tokens; t < context_window; ++t) {
181 float *out = output + (size_t)t * (size_t)aligned_embed_dim;
182 memset(out, 0, (size_t)aligned_embed_dim * sizeof(float));
183 }
184}
@ CK_DT_Q5_0
void dequant_q5_0_row(const void *src, float *dst, size_t n_elements)
Dequantize Q5_0 row (multiple blocks)

References CK_DT_Q5_0, ck_dtype_row_bytes(), dequant_q5_0_row(), and vocab_size.

◆ embedding_forward_q6_k()

void embedding_forward_q6_k ( const int32_t *  token_ids,
int  token_count,
int  vocab_size,
const void *  token_embeddings,
const float *  pos_embeddings,
float *  output,
int  embed_dim,
int  aligned_embed_dim,
int  context_window,
int  add_pos 
)

Definition at line 241 of file embedding_kernels.c.

251{
252 if (!token_ids || !token_embeddings || !output) {
253 return;
254 }
255
256 int tokens = token_count;
257 if (tokens < 0) {
258 tokens = 0;
259 }
260 if (tokens > context_window) {
261 tokens = context_window;
262 }
263
264 const size_t row_bytes = ck_dtype_row_bytes(CK_DT_Q6_K, (size_t)aligned_embed_dim);
265 const uint8_t *base = (const uint8_t *)token_embeddings;
266
267 for (int t = 0; t < tokens; ++t) {
268 int id = token_ids[t];
269 if (id < 0 || id >= vocab_size) {
270 id = 0;
271 }
272
273 const void *tok = base + (size_t)id * row_bytes;
274 const float *pos = pos_embeddings ? (pos_embeddings + (size_t)t * (size_t)aligned_embed_dim) : NULL;
275 float *out = output + (size_t)t * (size_t)aligned_embed_dim;
276
277 dequant_q6_k_row(tok, out, (size_t)aligned_embed_dim);
278
279 if (add_pos && pos) {
280 for (int d = 0; d < embed_dim; ++d) {
281 out[d] += pos[d];
282 }
283 }
284
285 for (int d = embed_dim; d < aligned_embed_dim; ++d) {
286 out[d] = 0.0f;
287 }
288 }
289
290 for (int t = tokens; t < context_window; ++t) {
291 float *out = output + (size_t)t * (size_t)aligned_embed_dim;
292 memset(out, 0, (size_t)aligned_embed_dim * sizeof(float));
293 }
294}
@ CK_DT_Q6_K
void dequant_q6_k_row(const void *src, float *dst, size_t n_elements)
Dequantize Q6_K row (multiple blocks)

References CK_DT_Q6_K, ck_dtype_row_bytes(), dequant_q6_k_row(), and vocab_size.

◆ embedding_forward_q8_0()

void embedding_forward_q8_0 ( const int32_t *  token_ids,
int  token_count,
int  vocab_size,
const void *  token_embeddings,
const float *  pos_embeddings,
float *  output,
int  embed_dim,
int  aligned_embed_dim,
int  context_window,
int  add_pos 
)

Definition at line 186 of file embedding_kernels.c.

196{
197 if (!token_ids || !token_embeddings || !output) {
198 return;
199 }
200
201 int tokens = token_count;
202 if (tokens < 0) {
203 tokens = 0;
204 }
205 if (tokens > context_window) {
206 tokens = context_window;
207 }
208
209 const size_t row_bytes = ck_dtype_row_bytes(CK_DT_Q8_0, (size_t)aligned_embed_dim);
210 const uint8_t *base = (const uint8_t *)token_embeddings;
211
212 for (int t = 0; t < tokens; ++t) {
213 int id = token_ids[t];
214 if (id < 0 || id >= vocab_size) {
215 id = 0;
216 }
217
218 const void *tok = base + (size_t)id * row_bytes;
219 const float *pos = pos_embeddings ? (pos_embeddings + (size_t)t * (size_t)aligned_embed_dim) : NULL;
220 float *out = output + (size_t)t * (size_t)aligned_embed_dim;
221
222 dequant_q8_0_row(tok, out, (size_t)aligned_embed_dim);
223
224 if (add_pos && pos) {
225 for (int d = 0; d < embed_dim; ++d) {
226 out[d] += pos[d];
227 }
228 }
229
230 for (int d = embed_dim; d < aligned_embed_dim; ++d) {
231 out[d] = 0.0f;
232 }
233 }
234
235 for (int t = tokens; t < context_window; ++t) {
236 float *out = output + (size_t)t * (size_t)aligned_embed_dim;
237 memset(out, 0, (size_t)aligned_embed_dim * sizeof(float));
238 }
239}
@ CK_DT_Q8_0
void dequant_q8_0_row(const void *src, float *dst, size_t n_elements)
Dequantize Q8_0 row (multiple blocks)

References CK_DT_Q8_0, ck_dtype_row_bytes(), dequant_q8_0_row(), and vocab_size.

Referenced by qwen2_0_5b_decode_decode_token(), and qwen2_0_5b_decode_forward_prefill_impl().

◆ farskip_swiglu_shared_combine_bf16()

void farskip_swiglu_shared_combine_bf16 ( const float *  hidden,
const float *  routed,
const float *  post_attn_residual,
const uint16_t *  shared_gate,
const uint16_t *  shared_up,
const uint16_t *  shared_down,
float *  main_output,
float *  routed_free_output,
int  rows,
int  hidden_dim,
int  intermediate_dim 
)

Definition at line 3381 of file axpy_kernels.c.

3392{
3393 if (rows <= 0) return;
3395 hidden, routed, post_attn_residual, shared_gate, shared_up, shared_down,
3396 main_output, routed_free_output, rows, hidden_dim, intermediate_dim,
3397 0, rows);
3398}
void farskip_swiglu_shared_combine_bf16_row_range(const float *hidden, const float *routed, const float *post_attn_residual, const uint16_t *shared_gate, const uint16_t *shared_up, const uint16_t *shared_down, float *main_output, float *routed_free_output, int rows, int hidden_dim, int intermediate_dim, int row_begin, int row_end)

References farskip_swiglu_shared_combine_bf16_row_range().

◆ farskip_swiglu_shared_combine_bf16_parallel_dispatch()

void farskip_swiglu_shared_combine_bf16_parallel_dispatch ( const float *  hidden,
const float *  routed,
const float *  post_attn_residual,
const uint16_t *  shared_gate,
const uint16_t *  shared_up,
const uint16_t *  shared_down,
float *  main_output,
float *  routed_free_output,
int  rows,
int  hidden_dim,
int  intermediate_dim 
)

◆ farskip_swiglu_shared_combine_bf16_row_range()

void farskip_swiglu_shared_combine_bf16_row_range ( const float *  hidden,
const float *  routed,
const float *  post_attn_residual,
const uint16_t *  shared_gate,
const uint16_t *  shared_up,
const uint16_t *  shared_down,
float *  main_output,
float *  routed_free_output,
int  rows,
int  hidden_dim,
int  intermediate_dim,
int  row_begin,
int  row_end 
)

Definition at line 3328 of file axpy_kernels.c.

3342{
3343 if (!hidden || !routed || !post_attn_residual || !shared_gate || !shared_up ||
3344 !shared_down || !main_output || !routed_free_output || rows <= 0 ||
3345 hidden_dim <= 0 || intermediate_dim <= 0 || row_begin < 0 ||
3346 row_begin >= row_end || row_end > rows) {
3347 return;
3348 }
3349
3350 float act[intermediate_dim];
3351
3352 for (int r = row_begin; r < row_end; ++r) {
3353 const float *x = hidden + (size_t)r * (size_t)hidden_dim;
3354 const float *route = routed + (size_t)r * (size_t)hidden_dim;
3355 const float *residual = post_attn_residual + (size_t)r * (size_t)hidden_dim;
3356 float *main = main_output + (size_t)r * (size_t)hidden_dim;
3357 float *routed_free = routed_free_output + (size_t)r * (size_t)hidden_dim;
3358
3359 for (int i = 0; i < intermediate_dim; ++i) {
3360 float gv = 0.0f;
3361 float uv = 0.0f;
3362 for (int h = 0; h < hidden_dim; ++h) {
3363 gv += bf16_to_float(shared_gate[(size_t)i * (size_t)hidden_dim + (size_t)h]) * x[h];
3364 uv += bf16_to_float(shared_up[(size_t)i * (size_t)hidden_dim + (size_t)h]) * x[h];
3365 }
3366 act[i] = ck_moe_silu_f32(gv) * uv;
3367 }
3368
3369 for (int h = 0; h < hidden_dim; ++h) {
3370 float shared = 0.0f;
3371 for (int i = 0; i < intermediate_dim; ++i) {
3372 shared += bf16_to_float(shared_down[(size_t)h * (size_t)intermediate_dim + (size_t)i]) * act[i];
3373 }
3374 const float mlp_output = route[h] + shared;
3375 routed_free[h] = residual[h] + shared;
3376 main[h] = residual[h] + mlp_output;
3377 }
3378 }
3379}
static float ck_moe_silu_f32(float x)
int main(int argc, char **argv)
Definition ck_cli_v5.c:110

References bf16_to_float(), ck_moe_silu_f32(), and main().

Referenced by farskip_swiglu_shared_combine_bf16().

◆ fc1_backward_kernel()

void fc1_backward_kernel ( const float *  d_output,
const float *  fc1_input,
const float *  W_fc1,
float *  d_input,
float *  d_W_fc1,
float *  d_b_fc1,
int  T,
int  aligned_in,
int  aligned_out,
int  num_threads 
)

Definition at line 174 of file mlp_kernels.c.

184{
185 (void)num_threads; // Threading handled by GEMM kernels
186
187 // 1. d_input[T, in] = d_output[T, out] @ W[out, in]
188 // Using gemm_nn: C[M,N] = A[M,K] @ B[K,N]
189 // A = d_output [T, out], B = W [out, in], C = d_input [T, in]
190 // M = T, N = aligned_in, K = aligned_out
191 gemm_nn_simd(d_output, W_fc1, NULL, d_input,
192 T, aligned_in, aligned_out);
193
194 // 2. d_W[out, in] = d_output[T, out].T @ fc1_input[T, in]
195 // Using gemm_tn: C[M,N] = A[K,M].T @ B[K,N]
196 // A = d_output [T, out] (stored as [K=T, M=out]), B = fc1_input [T, in]
197 // C = d_W [out, in], M = aligned_out, N = aligned_in, K = T
198 gemm_tn_parallel(d_output, fc1_input, NULL, d_W_fc1,
199 aligned_out, aligned_in, T);
200
201 // 3. d_b_fc1 = sum_over_T(d_output)
202 for (int out_idx = 0; out_idx < aligned_out; ++out_idx) {
203 float bias_grad = 0.0f;
204 for (int t = 0; t < T; ++t) {
205 bias_grad += d_output[(size_t)t * aligned_out + out_idx];
206 }
207 d_b_fc1[out_idx] += bias_grad;
208 }
209}
void gemm_tn_parallel(const float *A, const float *B, const float *bias, float *C, int M, int N, int K)
void gemm_nn_simd(const float *A, const float *B, const float *bias, float *C, int M, int N, int K)

References gemm_nn_simd(), and gemm_tn_parallel().

Referenced by ck_layer_backward_rmsnorm_swiglu().

◆ fc2_backward_kernel()

void fc2_backward_kernel ( const float *  d_output,
const float *  fc2_input,
const float *  W_fc2,
float *  d_input,
float *  d_W_fc2,
float *  d_b_fc2,
int  T,
int  aligned_in,
int  aligned_out,
int  num_threads 
)

Definition at line 126 of file mlp_kernels.c.

136{
137 (void)num_threads; // Threading handled by GEMM kernels
138
139 // 1. d_input[T, in] = d_output[T, out] @ W[out, in]
140 // Using gemm_nn: C[M,N] = A[M,K] @ B[K,N]
141 // A = d_output [T, out], B = W [out, in], C = d_input [T, in]
142 // M = T, N = aligned_in, K = aligned_out
143 gemm_nn_simd(d_output, W_fc2, NULL, d_input,
144 T, aligned_in, aligned_out);
145
146 // 2. d_W[out, in] = d_output[T, out].T @ fc2_input[T, in]
147 // Using gemm_tn: C[M,N] = A[K,M].T @ B[K,N]
148 // A = d_output [T, out] (stored as [K=T, M=out]), B = fc2_input [T, in]
149 // C = d_W [out, in], M = aligned_out, N = aligned_in, K = T
150 // Note: gemm_tn overwrites, so we need to save and add if accumulating
151 // For now, assume d_W starts zeroed (gradient accumulation handled at higher level)
152 gemm_tn_parallel(d_output, fc2_input, NULL, d_W_fc2,
153 aligned_out, aligned_in, T);
154
155 // 3. d_b_fc2 = sum_over_T(d_output)
156 for (int out_idx = 0; out_idx < aligned_out; ++out_idx) {
157 float bias_grad = 0.0f;
158 for (int t = 0; t < T; ++t) {
159 bias_grad += d_output[(size_t)t * aligned_out + out_idx];
160 }
161 d_b_fc2[out_idx] += bias_grad;
162 }
163}

References gemm_nn_simd(), and gemm_tn_parallel().

Referenced by ck_attention_project_head_major_backward(), ck_layer_backward_rmsnorm_swiglu(), and ck_qkv_project_head_major_backward().

◆ feature_concat()

void feature_concat ( const float *  main_input,
const float *  branch_input,
float *  output,
int  rows,
int  main_dim,
int  branch_slice_dim,
int  num_branch_slices 
)

Definition at line 804 of file vision_kernels.c.

811{
812 if (!main_input || !output || rows <= 0 || main_dim < 0 || branch_slice_dim < 0 || num_branch_slices < 0) {
813 return;
814 }
815
816 const int branch_total_dim = branch_slice_dim * num_branch_slices;
817 const int out_dim = main_dim + branch_total_dim;
818
819 const int in_place_expand = (main_input == output) && (out_dim > main_dim);
820 const int row_start = in_place_expand ? rows - 1 : 0;
821 const int row_end = in_place_expand ? -1 : rows;
822 const int row_step = in_place_expand ? -1 : 1;
823
824 for (int row = row_start; row != row_end; row += row_step) {
825 const float *src_main = main_input + (size_t) row * (size_t) main_dim;
826 float *dst_row = output + (size_t) row * (size_t) out_dim;
827
828 if (main_dim > 0) {
829 memmove(dst_row, src_main, (size_t) main_dim * sizeof(float));
830 }
831
832 for (int slice = 0; slice < num_branch_slices; ++slice) {
833 const float *src_branch = branch_input
834 + (size_t) slice * (size_t) rows * (size_t) branch_slice_dim
835 + (size_t) row * (size_t) branch_slice_dim;
836 float *dst_branch = dst_row + (size_t) main_dim + (size_t) slice * (size_t) branch_slice_dim;
837 if (branch_slice_dim > 0) {
838 memcpy(dst_branch, src_branch, (size_t) branch_slice_dim * sizeof(float));
839 }
840 }
841 }
842}

◆ feature_concat_2way()

void feature_concat_2way ( const float *  main_input,
const float *  branch_input,
float *  output,
int  rows,
int  main_dim,
int  branch_slice_dim,
int  num_branch_slices 
)

Definition at line 756 of file vision_kernels.c.

763{
764 if (!main_input || !branch_input || !output || rows <= 0 || main_dim <= 0 ||
765 branch_slice_dim < 0 || num_branch_slices < 0) {
766 return;
767 }
768
769 const int branch_dim = branch_slice_dim * num_branch_slices;
770 const size_t main_bytes = (size_t) main_dim * sizeof(float);
771 const size_t branch_bytes = (size_t) branch_dim * sizeof(float);
772 const size_t out_stride = (size_t) (main_dim + branch_dim);
773
774 for (int r = 0; r < rows; ++r) {
775 const float *src_main = main_input + ((size_t) r * (size_t) main_dim);
776 const float *src_branch = branch_input + ((size_t) r * (size_t) branch_dim);
777 float *dst = output + ((size_t) r * out_stride);
778 memcpy(dst, src_main, main_bytes);
779 memcpy(dst + main_dim, src_branch, branch_bytes);
780 }
781}

◆ feature_slice_copy()

void feature_slice_copy ( const float *  src,
float *  dst,
int  rows,
int  src_dim,
int  dst_dim,
int  dst_feature_offset 
)

Definition at line 783 of file vision_kernels.c.

789{
790 if (!src || !dst || rows <= 0 || src_dim <= 0 || dst_dim <= 0 || dst_feature_offset < 0) {
791 return;
792 }
793 if (dst_feature_offset + src_dim > dst_dim) {
794 return;
795 }
796
797 for (int row = 0; row < rows; ++row) {
798 const float *src_row = src + (size_t) row * (size_t) src_dim;
799 float *dst_row = dst + (size_t) row * (size_t) dst_dim + (size_t) dst_feature_offset;
800 memcpy(dst_row, src_row, (size_t) src_dim * sizeof(float));
801 }
802}

◆ final_logit_scale_f32()

void final_logit_scale_f32 ( float *  logits,
int  tokens,
int  vocab_size,
float  scale 
)

Definition at line 7 of file logit_kernels.c.

11{
12 if (!logits || tokens <= 0 || vocab_size <= 0) {
13 return;
14 }
15
16 const size_t total = (size_t) tokens * (size_t) vocab_size;
17 for (size_t i = 0; i < total; ++i) {
18 logits[i] *= scale;
19 }
20}

References vocab_size.

◆ fused_mlp_swiglu_decode()

void fused_mlp_swiglu_decode ( const float *  x,
const float *  W_gate,
const float *  W_up,
const float *  W_down,
const float *  b_gate,
const float *  b_up,
const float *  b_down,
float *  output,
int  D,
int  Hff 
)

Definition at line 154 of file mlp_fused_decode.c.

165{
166#if defined(__AVX512F__)
167 // Initialize output with bias or zero
168 if (b_down) {
169 memcpy(output, b_down, D * sizeof(float));
170 } else {
171 memset(output, 0, D * sizeof(float));
172 }
173
174 // Process intermediate dimension in tiles
175 // Each tile computes MLP_TILE_SIZE swiglu values and immediately
176 // accumulates them into the output
177
178 /* Bounds check for stack allocation */
179 if (D > 4096) return;
180
181 #pragma omp parallel
182 {
183 /* Thread-local accumulator on stack (no malloc!) */
184 float local_output[4096] __attribute__((aligned(64)));
185 memset(local_output, 0, D * sizeof(float));
186
187 #pragma omp for schedule(static)
188 for (int t = 0; t < Hff; t += MLP_TILE_SIZE) {
189 int tile_end = (t + MLP_TILE_SIZE < Hff) ? t + MLP_TILE_SIZE : Hff;
190 int tile_size = tile_end - t;
191
192 // Compute SwiGLU for this tile (stays in L1 cache)
193 float swiglu_tile[MLP_TILE_SIZE] __attribute__((aligned(64)));
194
195 for (int j = t; j < tile_end; j++) {
196 const float *wg_row = &W_gate[j * D];
197 const float *wu_row = &W_up[j * D];
198
199 // Compute gate = x @ W_gate[j] using AVX-512
200 __m512 gate_acc = _mm512_setzero_ps();
201 __m512 up_acc = _mm512_setzero_ps();
202
203 int k = 0;
204 for (; k <= D - 16; k += 16) {
205 __m512 x_vec = _mm512_loadu_ps(&x[k]);
206 __m512 wg_vec = _mm512_loadu_ps(&wg_row[k]);
207 __m512 wu_vec = _mm512_loadu_ps(&wu_row[k]);
208
209 gate_acc = _mm512_fmadd_ps(x_vec, wg_vec, gate_acc);
210 up_acc = _mm512_fmadd_ps(x_vec, wu_vec, up_acc);
211 }
212
213 float gate = hsum512_ps(gate_acc);
214 float up = hsum512_ps(up_acc);
215
216 // Scalar remainder
217 for (; k < D; k++) {
218 gate += x[k] * wg_row[k];
219 up += x[k] * wu_row[k];
220 }
221
222 // Add biases
223 if (b_gate) gate += b_gate[j];
224 if (b_up) up += b_up[j];
225
226 // SwiGLU: SiLU(gate) * up
227 swiglu_tile[j - t] = silu_scalar(gate) * up;
228 }
229
230 // Accumulate into output via W_down
231 // output[i] += sum_j(swiglu_tile[j] * W_down[i, t+j])
232 for (int i = 0; i < D; i++) {
233 const float *wd_row = &W_down[i * Hff + t];
234
235 __m512 acc = _mm512_setzero_ps();
236 int j = 0;
237 for (; j <= tile_size - 16; j += 16) {
238 __m512 sw_vec = _mm512_loadu_ps(&swiglu_tile[j]);
239 __m512 wd_vec = _mm512_loadu_ps(&wd_row[j]);
240 acc = _mm512_fmadd_ps(sw_vec, wd_vec, acc);
241 }
242
243 float sum = hsum512_ps(acc);
244 for (; j < tile_size; j++) {
245 sum += swiglu_tile[j] * wd_row[j];
246 }
247
248 local_output[i] += sum;
249 }
250 }
251
252 // Reduce thread-local outputs
253 #pragma omp critical
254 {
255 for (int i = 0; i < D; i++) {
256 output[i] += local_output[i];
257 }
258 }
259 /* No free - stack buffer auto-deallocates */
260 }
261
262#else
263 // Scalar fallback (same algorithm, no SIMD)
264 if (b_down) {
265 memcpy(output, b_down, D * sizeof(float));
266 } else {
267 memset(output, 0, D * sizeof(float));
268 }
269
270 for (int t = 0; t < Hff; t += MLP_TILE_SIZE) {
271 int tile_end = (t + MLP_TILE_SIZE < Hff) ? t + MLP_TILE_SIZE : Hff;
272 int tile_size = tile_end - t;
273
274 float swiglu_tile[MLP_TILE_SIZE];
275
276 for (int j = t; j < tile_end; j++) {
277 float gate = 0.0f;
278 float up = 0.0f;
279
280 for (int k = 0; k < D; k++) {
281 gate += x[k] * W_gate[j * D + k];
282 up += x[k] * W_up[j * D + k];
283 }
284
285 if (b_gate) gate += b_gate[j];
286 if (b_up) up += b_up[j];
287
288 swiglu_tile[j - t] = silu_scalar(gate) * up;
289 }
290
291 for (int i = 0; i < D; i++) {
292 for (int j = 0; j < tile_size; j++) {
293 output[i] += swiglu_tile[j] * W_down[i * Hff + t + j];
294 }
295 }
296 }
297#endif
298}
#define MLP_TILE_SIZE
static float silu_scalar(float x)
__attribute__((visibility("default"))) CKTokenizer *ck_tokenizer_create(CKTokenizerType type)

References __attribute__(), MLP_TILE_SIZE, and silu_scalar().

◆ fused_mlp_swiglu_decode_tiled()

void fused_mlp_swiglu_decode_tiled ( const float *  x,
const float *  W_gate,
const float *  W_up,
const float *  W_down,
const float *  b_gate,
const float *  b_up,
const float *  b_down,
float *  output,
int  D,
int  Hff 
)

Definition at line 429 of file mlp_fused_decode.c.

440{
441 // Tile size chosen to fit in L2 with W_down tile
442 // Tile of swiglu: 256 floats = 1KB
443 // Tile of W_down: 256 * D floats = 256 * 896 * 4 = 896KB
444 // Fits in 2MB L2 with room for x and prefetch
445 const int TILE = 256;
446
447#if defined(__AVX512F__)
448 // Initialize output
449 #pragma omp parallel for schedule(static)
450 for (int i = 0; i < D; i++) {
451 output[i] = b_down ? b_down[i] : 0.0f;
452 }
453
454 // Process tiles of intermediate dimension
455 for (int t = 0; t < Hff; t += TILE) {
456 int tile_end = (t + TILE < Hff) ? t + TILE : Hff;
457 int tile_size = tile_end - t;
458
459 // Compute swiglu tile
460 float swiglu_tile[256] __attribute__((aligned(64)));
461
462 #pragma omp parallel for schedule(static)
463 for (int jj = 0; jj < tile_size; jj++) {
464 int j = t + jj;
465 const float *wg_row = &W_gate[j * D];
466 const float *wu_row = &W_up[j * D];
467
468 __m512 gate_acc = _mm512_setzero_ps();
469 __m512 up_acc = _mm512_setzero_ps();
470
471 int k = 0;
472 for (; k <= D - 16; k += 16) {
473 __m512 x_vec = _mm512_loadu_ps(&x[k]);
474 __m512 wg_vec = _mm512_loadu_ps(&wg_row[k]);
475 __m512 wu_vec = _mm512_loadu_ps(&wu_row[k]);
476
477 gate_acc = _mm512_fmadd_ps(x_vec, wg_vec, gate_acc);
478 up_acc = _mm512_fmadd_ps(x_vec, wu_vec, up_acc);
479 }
480
481 float gate = hsum512_ps(gate_acc);
482 float up = hsum512_ps(up_acc);
483
484 for (; k < D; k++) {
485 gate += x[k] * wg_row[k];
486 up += x[k] * wu_row[k];
487 }
488
489 if (b_gate) gate += b_gate[j];
490 if (b_up) up += b_up[j];
491
492 swiglu_tile[jj] = silu_scalar(gate) * up;
493 }
494
495 // Accumulate into output (parallelize over D)
496 #pragma omp parallel for schedule(static)
497 for (int i = 0; i < D; i++) {
498 const float *wd_row = &W_down[i * Hff + t];
499
500 __m512 acc = _mm512_setzero_ps();
501 int j = 0;
502 for (; j <= tile_size - 16; j += 16) {
503 __m512 sw_vec = _mm512_loadu_ps(&swiglu_tile[j]);
504 __m512 wd_vec = _mm512_loadu_ps(&wd_row[j]);
505 acc = _mm512_fmadd_ps(sw_vec, wd_vec, acc);
506 }
507
508 float sum = hsum512_ps(acc);
509 for (; j < tile_size; j++) {
510 sum += swiglu_tile[j] * wd_row[j];
511 }
512
513 // Atomic add (or use thread-local buffers for better perf)
514 #pragma omp atomic
515 output[i] += sum;
516 }
517 }
518
519#else
520 // Scalar fallback
521 for (int i = 0; i < D; i++) {
522 output[i] = b_down ? b_down[i] : 0.0f;
523 }
524
525 for (int t = 0; t < Hff; t += TILE) {
526 int tile_end = (t + TILE < Hff) ? t + TILE : Hff;
527
528 float swiglu_tile[256];
529
530 for (int j = t; j < tile_end; j++) {
531 float gate = 0.0f, up = 0.0f;
532 for (int k = 0; k < D; k++) {
533 gate += x[k] * W_gate[j * D + k];
534 up += x[k] * W_up[j * D + k];
535 }
536 if (b_gate) gate += b_gate[j];
537 if (b_up) up += b_up[j];
538 swiglu_tile[j - t] = silu_scalar(gate) * up;
539 }
540
541 for (int i = 0; i < D; i++) {
542 for (int j = t; j < tile_end; j++) {
543 output[i] += swiglu_tile[j - t] * W_down[i * Hff + j];
544 }
545 }
546 }
547#endif
548}

References __attribute__(), and silu_scalar().

Referenced by fused_mlp_swiglu_decode_v2().

◆ fused_mlp_swiglu_decode_v2()

void fused_mlp_swiglu_decode_v2 ( const float *  x,
const float *  W_gate,
const float *  W_up,
const float *  W_down,
const float *  b_gate,
const float *  b_up,
const float *  b_down,
float *  output,
int  D,
int  Hff 
)

Definition at line 318 of file mlp_fused_decode.c.

329{
330 // For large Hff, use tiled version to avoid stack overflow
331 if (Hff > MAX_SWIGLU_STACK) {
332 fused_mlp_swiglu_decode_tiled(x, W_gate, W_up, W_down,
333 b_gate, b_up, b_down, output, D, Hff);
334 return;
335 }
336
337#if defined(__AVX512F__)
338 // Stack-allocated swiglu buffer (max 32KB)
339 float swiglu[MAX_SWIGLU_STACK] __attribute__((aligned(64)));
340
341 // Phase 1: Compute all swiglu values (parallelize over Hff)
342 #pragma omp parallel for schedule(static)
343 for (int j = 0; j < Hff; j++) {
344 const float *wg_row = &W_gate[j * D];
345 const float *wu_row = &W_up[j * D];
346
347 __m512 gate_acc = _mm512_setzero_ps();
348 __m512 up_acc = _mm512_setzero_ps();
349
350 int k = 0;
351 for (; k <= D - 16; k += 16) {
352 __m512 x_vec = _mm512_loadu_ps(&x[k]);
353 __m512 wg_vec = _mm512_loadu_ps(&wg_row[k]);
354 __m512 wu_vec = _mm512_loadu_ps(&wu_row[k]);
355
356 gate_acc = _mm512_fmadd_ps(x_vec, wg_vec, gate_acc);
357 up_acc = _mm512_fmadd_ps(x_vec, wu_vec, up_acc);
358 }
359
360 float gate = hsum512_ps(gate_acc);
361 float up = hsum512_ps(up_acc);
362
363 for (; k < D; k++) {
364 gate += x[k] * wg_row[k];
365 up += x[k] * wu_row[k];
366 }
367
368 if (b_gate) gate += b_gate[j];
369 if (b_up) up += b_up[j];
370
371 swiglu[j] = silu_scalar(gate) * up;
372 }
373
374 // Phase 2: Down projection (parallelize over D)
375 #pragma omp parallel for schedule(static)
376 for (int i = 0; i < D; i++) {
377 const float *wd_row = &W_down[i * Hff];
378
379 __m512 acc = _mm512_setzero_ps();
380 int j = 0;
381 for (; j <= Hff - 16; j += 16) {
382 __m512 sw_vec = _mm512_loadu_ps(&swiglu[j]);
383 __m512 wd_vec = _mm512_loadu_ps(&wd_row[j]);
384 acc = _mm512_fmadd_ps(sw_vec, wd_vec, acc);
385 }
386
387 float sum = hsum512_ps(acc);
388 for (; j < Hff; j++) {
389 sum += swiglu[j] * wd_row[j];
390 }
391
392 output[i] = sum + (b_down ? b_down[i] : 0.0f);
393 }
394
395#else
396 // Scalar fallback with stack buffer
397 float swiglu[MAX_SWIGLU_STACK];
398
399 for (int j = 0; j < Hff; j++) {
400 float gate = 0.0f, up = 0.0f;
401 for (int k = 0; k < D; k++) {
402 gate += x[k] * W_gate[j * D + k];
403 up += x[k] * W_up[j * D + k];
404 }
405 if (b_gate) gate += b_gate[j];
406 if (b_up) up += b_up[j];
407 swiglu[j] = silu_scalar(gate) * up;
408 }
409
410 for (int i = 0; i < D; i++) {
411 float sum = 0.0f;
412 for (int j = 0; j < Hff; j++) {
413 sum += swiglu[j] * W_down[i * Hff + j];
414 }
415 output[i] = sum + (b_down ? b_down[i] : 0.0f);
416 }
417#endif
418}
void fused_mlp_swiglu_decode_tiled(const float *x, const float *W_gate, const float *W_up, const float *W_down, const float *b_gate, const float *b_up, const float *b_down, float *output, int D, int Hff)
#define MAX_SWIGLU_STACK

References __attribute__(), fused_mlp_swiglu_decode_tiled(), MAX_SWIGLU_STACK, and silu_scalar().

Referenced by ck_mlp_swiglu_forward_fully_fused_token().

◆ fused_mlp_swiglu_prefill()

void fused_mlp_swiglu_prefill ( const float *  x,
const float *  W_gate,
const float *  W_up,
const float *  W_down,
float *  output,
int  seq_len,
int  hidden,
int  intermediate,
float *  scratch 
)

Fused MLP (Gate + Up + SwiGLU + Down) for prefill.

Tiles along token dimension to keep gate/up/hidden in L3 cache.

Parameters
scratchTemporary buffer from fused_mlp_swiglu_scratch_size()

Definition at line 878 of file prefill_fused_gemm.c.

888{
889 fused_mlp_swiglu_prefill_bias(x, W_gate, W_up, W_down,
890 NULL, NULL, NULL,
891 output, seq_len, hidden, intermediate,
892 scratch);
893}
void fused_mlp_swiglu_prefill_bias(const float *x, const float *W_gate, const float *W_up, const float *W_down, const float *B_gate, const float *B_up, const float *B_down, float *output, int seq_len, int hidden, int intermediate, float *scratch)
Fused MLP for prefill with proper tiling.

References fused_mlp_swiglu_prefill_bias().

◆ fused_mlp_swiglu_prefill_bias()

void fused_mlp_swiglu_prefill_bias ( const float *  x,
const float *  W_gate,
const float *  W_up,
const float *  W_down,
const float *  B_gate,
const float *  B_up,
const float *  B_down,
float *  output,
int  seq_len,
int  hidden,
int  intermediate,
float *  scratch 
)

Fused MLP (Gate + Up + SwiGLU + Down) for prefill with biases.

Fused MLP (Gate + Up + SwiGLU + Down) for prefill with biases.

Definition at line 746 of file prefill_fused_gemm.c.

759{
760 /* MLP is more complex because we have:
761 * gate = x @ W_gate
762 * up = x @ W_up
763 * hidden = silu(gate) * up
764 * out = hidden @ W_down
765 *
766 * The intermediate (gate, up, hidden) is large: seq_len × intermediate
767 * For Qwen2-0.5B: 1024 × 4864 × 4 = 19.4MB (way bigger than L3!)
768 *
769 * Strategy: Tile along intermediate dimension for gate/up,
770 * then fuse SwiGLU, then tile down projection.
771 */
772
773 /* scratch layout:
774 * [gate_tile: TILE_M × TILE_N_INTER]
775 * [up_tile: TILE_M × TILE_N_INTER]
776 */
777 const int TILE_N_INTER = 512; /* Intermediate tile size */
778 float *gate_tile = scratch;
779 float *up_tile = scratch + (size_t)PREFILL_TILE_M * TILE_N_INTER;
780 float *hidden_tile = gate_tile; /* Reuse gate_tile for hidden after SwiGLU */
781
782 /* For each chunk of intermediate dimension */
783 for (int inter_start = 0; inter_start < intermediate; inter_start += TILE_N_INTER) {
784 int tile_inter = (inter_start + TILE_N_INTER <= intermediate)
785 ? TILE_N_INTER : (intermediate - inter_start);
786
787 const float *W_gate_tile = W_gate + (size_t)inter_start * hidden;
788 const float *W_up_tile = W_up + (size_t)inter_start * hidden;
789
790 /* For each chunk of tokens */
791 for (int m_start = 0; m_start < seq_len; m_start += PREFILL_TILE_M) {
792 int tile_m = (m_start + PREFILL_TILE_M <= seq_len)
793 ? PREFILL_TILE_M : (seq_len - m_start);
794
795 const float *x_tile = x + (size_t)m_start * hidden;
796
797 /* Compute gate and up projections for this tile */
798 gemm_tile_nt_strided(x_tile, W_gate_tile, gate_tile,
799 tile_m, tile_inter, hidden, tile_inter);
800 gemm_tile_nt_strided(x_tile, W_up_tile, up_tile,
801 tile_m, tile_inter, hidden, tile_inter);
802 if (B_gate) {
803 add_bias_tile(gate_tile, B_gate + inter_start, tile_m, tile_inter);
804 }
805 if (B_up) {
806 add_bias_tile(up_tile, B_up + inter_start, tile_m, tile_inter);
807 }
808
809 /* Fused SwiGLU: hidden = silu(gate) * up */
810 for (int i = 0; i < tile_m; ++i) {
811 float *g = gate_tile + (size_t)i * tile_inter;
812 float *u = up_tile + (size_t)i * tile_inter;
813 for (int j = 0; j < tile_inter; ++j) {
814 float gv = g[j];
815 float silu = gv / (1.0f + expf(-gv));
816 g[j] = silu * u[j]; /* hidden_tile = gate_tile */
817 }
818 }
819
820 /* Down projection: accumulate into output
821 * out[m_start:, :] += hidden_tile @ W_down[inter_start:, :]^T
822 */
823 float *out_tile = output + (size_t)m_start * hidden;
824
825 /* This is trickier - W_down is [hidden × intermediate]
826 * We have hidden_tile[tile_m × tile_inter]
827 * We want out[tile_m × hidden] += hidden_tile × W_down[:, inter_start:inter_start+tile_inter]^T
828 *
829 * For proper accumulation, need to handle this carefully.
830 * For now, use a simpler approach: accumulate partial results.
831 */
832 for (int i = 0; i < tile_m; ++i) {
833 float *h = hidden_tile + (size_t)i * tile_inter;
834 float *o = out_tile + (size_t)i * hidden;
835
836 for (int d = 0; d < hidden; ++d) {
837 const float *w_row = W_down + (size_t)d * intermediate + inter_start;
838 float sum = (inter_start == 0)
839 ? (B_down ? B_down[d] : 0.0f)
840 : o[d];
841
842#if defined(__AVX512F__)
843 __m512 acc = _mm512_setzero_ps();
844 int j = 0;
845 for (; j + 16 <= tile_inter; j += 16) {
846 __m512 hv = _mm512_loadu_ps(h + j);
847 __m512 wv = _mm512_loadu_ps(w_row + j);
848 acc = _mm512_fmadd_ps(hv, wv, acc);
849 }
850 sum += _mm512_reduce_add_ps(acc);
851 for (; j < tile_inter; ++j) {
852 sum += h[j] * w_row[j];
853 }
854#elif defined(__AVX__)
855 __m256 acc = _mm256_setzero_ps();
856 int j = 0;
857 for (; j + 8 <= tile_inter; j += 8) {
858 __m256 hv = _mm256_loadu_ps(h + j);
859 __m256 wv = _mm256_loadu_ps(w_row + j);
860 acc = _mm256_add_ps(acc, _mm256_mul_ps(hv, wv));
861 }
862 sum += hsum256_prefill(acc);
863 for (; j < tile_inter; ++j) {
864 sum += h[j] * w_row[j];
865 }
866#else
867 for (int j = 0; j < tile_inter; ++j) {
868 sum += h[j] * w_row[j];
869 }
870#endif
871 o[d] = sum;
872 }
873 }
874 }
875 }
876}
#define PREFILL_TILE_M
static void add_bias_tile(float *out, const float *bias, int tile_m, int out_dim)
static void gemm_tile_nt_strided(const float *A, const float *B_tile, float *C, int tile_m, int tile_n, int K, int C_stride)
GEMM tile with N-dimension tiling (weight reuse)
static void silu(float *x, int n)

References add_bias_tile(), gemm_tile_nt_strided(), PREFILL_TILE_M, and silu().

Referenced by fused_mlp_swiglu_prefill().

◆ fused_mlp_swiglu_prefill_w1w2_quant()

void fused_mlp_swiglu_prefill_w1w2_quant ( const float *  x,
const void *  W1,
const float *  B1,
CKDataType  w1_dt,
const void *  W2,
const float *  B2,
CKDataType  w2_dt,
float *  output,
int  seq_len,
int  embed_dim,
int  aligned_embed_dim,
int  intermediate_dim,
int  aligned_intermediate_dim,
void *  scratch 
)

Quantized fused MLP for prefill (W1=gate+up, W2=down)

W1 uses Q8_0 activations (Q5_0/Q8_0 weights), W2 uses Q8_K activations (Q4_K/Q6_K weights).

Uses Q8_0 activations for W1 (Q5_0/Q8_0 weights) and Q8_K activations for W2 (Q4_K/Q6_K weights).

Definition at line 964 of file prefill_fused_gemm.c.

979{
980 if (!x || !W1 || !W2 || !output || !scratch) {
981 return;
982 }
983 if (seq_len <= 0 || embed_dim <= 0 || aligned_embed_dim <= 0 ||
984 intermediate_dim <= 0 || aligned_intermediate_dim <= 0) {
985 return;
986 }
987 if (aligned_embed_dim < embed_dim || aligned_intermediate_dim < intermediate_dim) {
988 return;
989 }
990 if ((aligned_embed_dim % 32) != 0 || (aligned_intermediate_dim % 256) != 0) {
991 return;
992 }
993 if (!mlp_q8_0_dtype_supported(w1_dt) || !mlp_q8_k_dtype_supported(w2_dt)) {
994 return;
995 }
996
997 const int tile_m_max = PREFILL_TILE_M;
998 const int inter = aligned_intermediate_dim;
999 const size_t q8_row_bytes = ck_dtype_row_bytes(CK_DT_Q8_0, (size_t)aligned_embed_dim);
1000 const size_t q8k_row_bytes = ck_dtype_row_bytes(CK_DT_Q8_K, (size_t)aligned_intermediate_dim);
1001 const size_t w1_row_bytes = ck_dtype_row_bytes(w1_dt, (size_t)aligned_embed_dim);
1002
1003 uint8_t *scratch_bytes = (uint8_t *)scratch;
1004 size_t q8_bytes = (size_t)tile_m_max * q8_row_bytes;
1005 size_t gate_bytes = (size_t)tile_m_max * (size_t)inter * sizeof(float);
1006 size_t up_bytes = gate_bytes;
1007 size_t gate_offset = align_up_size(q8_bytes, 64);
1008 size_t up_offset = gate_offset + align_up_size(gate_bytes, 64);
1009 size_t q8k_offset = up_offset + align_up_size(up_bytes, 64);
1010
1011 uint8_t *q8_tile = scratch_bytes;
1012 float *gate_tile = (float *)(scratch_bytes + gate_offset);
1013 float *up_tile = (float *)(scratch_bytes + up_offset);
1014 uint8_t *q8k_tile = scratch_bytes + q8k_offset;
1015
1016 const uint8_t *w1_base = (const uint8_t *)W1;
1017 const uint8_t *w_gate = w1_base;
1018 const uint8_t *w_up = w1_base + (size_t)inter * w1_row_bytes;
1019
1020 const float *b_gate = B1;
1021 const float *b_up = B1 ? (B1 + (size_t)inter) : NULL;
1022
1023 for (int m_start = 0; m_start < seq_len; m_start += tile_m_max) {
1024 int tile_m = (m_start + tile_m_max <= seq_len)
1025 ? tile_m_max : (seq_len - m_start);
1026
1027 const float *x_tile = x + (size_t)m_start * (size_t)aligned_embed_dim;
1028 float *out_tile = output + (size_t)m_start * (size_t)aligned_embed_dim;
1029
1030 for (int t = 0; t < tile_m; ++t) {
1031 const float *row = x_tile + (size_t)t * (size_t)aligned_embed_dim;
1033 q8_tile + (size_t)t * q8_row_bytes,
1034 aligned_embed_dim);
1035 }
1036
1037 gemm_nt_q8_0_mlp_dispatch(q8_tile, w_gate, b_gate, gate_tile,
1038 tile_m, inter, aligned_embed_dim, w1_dt);
1039 gemm_nt_q8_0_mlp_dispatch(q8_tile, w_up, b_up, up_tile,
1040 tile_m, inter, aligned_embed_dim, w1_dt);
1041
1042 for (int i = 0; i < tile_m; ++i) {
1043 float *g = gate_tile + (size_t)i * (size_t)inter;
1044 float *u = up_tile + (size_t)i * (size_t)inter;
1045 for (int j = 0; j < inter; ++j) {
1046 g[j] = silu_prefill(g[j]) * u[j];
1047 }
1048 }
1049
1050 for (int i = 0; i < tile_m; ++i) {
1051 const float *row = gate_tile + (size_t)i * (size_t)inter;
1053 q8k_tile + (size_t)i * q8k_row_bytes,
1054 aligned_intermediate_dim);
1055 }
1056
1057 gemm_nt_q8_k_mlp_dispatch(q8k_tile, W2, B2, out_tile,
1058 tile_m, aligned_embed_dim, aligned_intermediate_dim, w2_dt);
1059 }
1060}
@ CK_DT_Q8_K
void quantize_row_q8_k(const float *x, void *y, int k)
void quantize_row_q8_0(const float *x, void *y, int k)
Quantize FP32 to Q8_0 format (scalar reference)
static void gemm_nt_q8_0_mlp_dispatch(const void *A_q8, const void *B, const float *bias, float *C, int M, int N, int K, CKDataType dt)
static size_t align_up_size(size_t value, size_t align)
static int mlp_q8_k_dtype_supported(CKDataType dt)
static float silu_prefill(float x)
static int mlp_q8_0_dtype_supported(CKDataType dt)
static void gemm_nt_q8_k_mlp_dispatch(const void *A_q8, const void *B, const float *bias, float *C, int M, int N, int K, CKDataType dt)

References align_up_size(), CK_DT_Q8_0, CK_DT_Q8_K, ck_dtype_row_bytes(), gemm_nt_q8_0_mlp_dispatch(), gemm_nt_q8_k_mlp_dispatch(), mlp_q8_0_dtype_supported(), mlp_q8_k_dtype_supported(), PREFILL_TILE_M, quantize_row_q8_0(), quantize_row_q8_k(), and silu_prefill().

Referenced by mega_fused_outproj_mlp_prefill().

◆ fused_mlp_swiglu_prefill_w1w2_quant_scratch_size()

size_t fused_mlp_swiglu_prefill_w1w2_quant_scratch_size ( int  aligned_embed_dim,
int  aligned_intermediate_dim 
)

Get scratch buffer size for fused_mlp_swiglu_prefill_w1w2_quant.

Definition at line 1062 of file prefill_fused_gemm.c.

1064{
1065 if (aligned_embed_dim <= 0 || aligned_intermediate_dim <= 0) {
1066 return 0;
1067 }
1068 const size_t q8_row_bytes = ck_dtype_row_bytes(CK_DT_Q8_0, (size_t)aligned_embed_dim);
1069 const size_t q8k_row_bytes = ck_dtype_row_bytes(CK_DT_Q8_K, (size_t)aligned_intermediate_dim);
1070 const size_t q8_bytes = (size_t)PREFILL_TILE_M * q8_row_bytes;
1071 const size_t gate_bytes = (size_t)PREFILL_TILE_M * (size_t)aligned_intermediate_dim * sizeof(float);
1072 const size_t up_bytes = gate_bytes;
1073 const size_t q8k_bytes = (size_t)PREFILL_TILE_M * q8k_row_bytes;
1074
1075 return align_up_size(q8_bytes, 64) +
1076 align_up_size(gate_bytes, 64) +
1077 align_up_size(up_bytes, 64) +
1078 align_up_size(q8k_bytes, 64);
1079}

References align_up_size(), CK_DT_Q8_0, CK_DT_Q8_K, ck_dtype_row_bytes(), and PREFILL_TILE_M.

Referenced by mega_fused_outproj_mlp_prefill_scratch_size().

◆ fused_mlp_swiglu_scratch_size()

size_t fused_mlp_swiglu_scratch_size ( int  intermediate)

Get scratch buffer size for fused_mlp_swiglu_prefill.

Get scratch buffer size for fused_mlp_swiglu_prefill.

Definition at line 898 of file prefill_fused_gemm.c.

898 {
899 const int TILE_N_INTER = 512;
900 /* gate_tile + up_tile */
901 return 2 * (size_t)PREFILL_TILE_M * TILE_N_INTER * sizeof(float);
902}

References PREFILL_TILE_M.

◆ fused_rmsnorm_qkv_prefill()

void fused_rmsnorm_qkv_prefill ( const float *  x,
const float *  gamma,
const float *  Wq,
const float *  Wk,
const float *  Wv,
float *  Q,
float *  K,
float *  V,
int  seq_len,
int  hidden,
int  q_dim,
int  kv_dim,
float  eps,
float *  scratch 
)

Fused RMSNorm + QKV projection for prefill.

Tiles along token dimension to keep intermediate x_norm in L2 cache. Avoids ~7MB DRAM traffic per layer for seq_len=1024, hidden=896.

Parameters
scratchTemporary buffer from fused_rmsnorm_qkv_scratch_size()

Fused RMSNorm + QKV projection for prefill.

KEY INSIGHT: For Qwen2-0.5B, all QKV weights fit in L3: Wq (896×896) + Wk (128×896) + Wv (128×896) = 4.1MB < 6MB L3

So we use M-tiling (tokens) only:

  1. For each token tile: a. Compute RMSNorm ONCE into scratch (x_norm stays in L2) b. Do all three GEMMs (Q, K, V) against cached x_norm c. Weights stay hot in L3 across all token tiles

This avoids both:

  • Large x_norm intermediate buffer (only TILE_M × hidden in L2)
  • RMSNorm recomputation (done once per token tile, used 3×)

Definition at line 393 of file prefill_fused_gemm.c.

408{
409 /* scratch is x_norm tile: [TILE_M × hidden] fits in L2 */
410
411 /* Process token tiles - weights stay in L3 across all tiles */
412 for (int m_start = 0; m_start < seq_len; m_start += PREFILL_TILE_M) {
413 int tile_m = (m_start + PREFILL_TILE_M <= seq_len)
414 ? PREFILL_TILE_M : (seq_len - m_start);
415
416 const float *x_tile = x + (size_t)m_start * hidden;
417
418 /* Step 1: RMSNorm for this token tile (computed ONCE, used 3×) */
419 rmsnorm_tile(x_tile, gamma, scratch, tile_m, hidden, hidden, eps);
420
421 /* Step 2: Q projection - x_norm is hot in L2, Wq hot in L3 */
422 float *Q_tile = Q + (size_t)m_start * q_dim;
423 gemm_tile_nt_strided(scratch, Wq, Q_tile, tile_m, q_dim, hidden, q_dim);
424
425 /* Step 3: K projection - x_norm still hot, Wk displaces some Wq */
426 float *K_tile = K + (size_t)m_start * kv_dim;
427 gemm_tile_nt_strided(scratch, Wk, K_tile, tile_m, kv_dim, hidden, kv_dim);
428
429 /* Step 4: V projection - x_norm still hot, Wv displaces Wk */
430 float *V_tile = V + (size_t)m_start * kv_dim;
431 gemm_tile_nt_strided(scratch, Wv, V_tile, tile_m, kv_dim, hidden, kv_dim);
432 }
433}
static void rmsnorm_tile(const float *input, const float *gamma, float *output, int tile_m, int embed_dim, int aligned_embed_dim, float eps)
Compute RMSNorm for a tile of tokens.

References gemm_tile_nt_strided(), PREFILL_TILE_M, and rmsnorm_tile().

◆ fused_rmsnorm_qkv_prefill_head_major()

void fused_rmsnorm_qkv_prefill_head_major ( const float *  x,
const float *  gamma,
const float *  Wq,
const float *  Bq,
const float *  Wk,
const float *  Bk,
const float *  Wv,
const float *  Bv,
float *  Q,
float *  K,
float *  V,
int  seq_len,
int  embed_dim,
int  aligned_embed_dim,
int  num_heads,
int  num_kv_heads,
int  head_dim,
int  aligned_head_dim,
int  kv_stride_tokens,
float  eps,
float *  scratch 
)

Fused RMSNorm + QKV projection for prefill (head-major outputs)

Writes Q as [num_heads, seq_len, aligned_head_dim] and K/V with stride kv_stride_tokens for KV-cache compatibility.

Q is written as [num_heads, seq_len, aligned_head_dim]. K/V are written with kv_stride_tokens for KV-cache compatibility.

Definition at line 441 of file prefill_fused_gemm.c.

460{
461 if (!x || !gamma || !Wq || !Wk || !Wv || !Q || !K || !V || !scratch) {
462 return;
463 }
464 if (seq_len <= 0 || embed_dim <= 0 || aligned_embed_dim <= 0 ||
465 head_dim <= 0 || aligned_head_dim <= 0 ||
466 num_heads <= 0 || num_kv_heads <= 0) {
467 return;
468 }
469 if (kv_stride_tokens < seq_len) {
470 return;
471 }
472
473 const size_t q_head_stride = (size_t)seq_len * (size_t)aligned_head_dim;
474 const size_t kv_head_stride = (size_t)kv_stride_tokens * (size_t)aligned_head_dim;
475 const size_t head_w_stride = (size_t)aligned_head_dim * (size_t)aligned_embed_dim;
476
477 for (int m_start = 0; m_start < seq_len; m_start += PREFILL_TILE_M) {
478 int tile_m = (m_start + PREFILL_TILE_M <= seq_len)
479 ? PREFILL_TILE_M : (seq_len - m_start);
480
481 const float *x_tile = x + (size_t)m_start * (size_t)aligned_embed_dim;
482 rmsnorm_tile(x_tile, gamma, scratch, tile_m, embed_dim, aligned_embed_dim, eps);
483
484 for (int h = 0; h < num_heads; ++h) {
485 const float *wq_h = Wq + (size_t)h * head_w_stride;
486 const float *bq_h = Bq ? (Bq + (size_t)h * (size_t)aligned_head_dim) : NULL;
487 float *q_h = Q + (size_t)h * q_head_stride + (size_t)m_start * (size_t)aligned_head_dim;
488
489 gemm_tile_nt_strided(scratch, wq_h, q_h,
490 tile_m, aligned_head_dim, aligned_embed_dim, aligned_head_dim);
491 add_bias_tile(q_h, bq_h, tile_m, aligned_head_dim);
492 }
493
494 for (int h = 0; h < num_kv_heads; ++h) {
495 const float *wk_h = Wk + (size_t)h * head_w_stride;
496 const float *wv_h = Wv + (size_t)h * head_w_stride;
497 const float *bk_h = Bk ? (Bk + (size_t)h * (size_t)aligned_head_dim) : NULL;
498 const float *bv_h = Bv ? (Bv + (size_t)h * (size_t)aligned_head_dim) : NULL;
499 float *k_h = K + (size_t)h * kv_head_stride + (size_t)m_start * (size_t)aligned_head_dim;
500 float *v_h = V + (size_t)h * kv_head_stride + (size_t)m_start * (size_t)aligned_head_dim;
501
502 gemm_tile_nt_strided(scratch, wk_h, k_h,
503 tile_m, aligned_head_dim, aligned_embed_dim, aligned_head_dim);
504 add_bias_tile(k_h, bk_h, tile_m, aligned_head_dim);
505
506 gemm_tile_nt_strided(scratch, wv_h, v_h,
507 tile_m, aligned_head_dim, aligned_embed_dim, aligned_head_dim);
508 add_bias_tile(v_h, bv_h, tile_m, aligned_head_dim);
509 }
510 }
511}

References add_bias_tile(), gemm_tile_nt_strided(), PREFILL_TILE_M, and rmsnorm_tile().

Referenced by mega_fused_attention_prefill(), and mega_fused_attention_prefill_q8_0().

◆ fused_rmsnorm_qkv_prefill_head_major_quant()

void fused_rmsnorm_qkv_prefill_head_major_quant ( const float *  x,
const float *  gamma,
const void *  Wq,
const float *  Bq,
CKDataType  wq_dt,
const void *  Wk,
const float *  Bk,
CKDataType  wk_dt,
const void *  Wv,
const float *  Bv,
CKDataType  wv_dt,
float *  Q,
float *  K,
float *  V,
int  seq_len,
int  embed_dim,
int  aligned_embed_dim,
int  num_heads,
int  num_kv_heads,
int  head_dim,
int  aligned_head_dim,
int  kv_stride_tokens,
float  eps,
void *  scratch 
)

Fused RMSNorm + QKV projection for prefill (head-major, Q8 activations)

Supports Q5_0 or Q8_0 weights with Q8_0 activations.

Supports Q5_0 or Q8_0 weights with Q8_0 activations. Writes K/V directly into KV cache layout (kv_stride_tokens).

Definition at line 519 of file prefill_fused_gemm.c.

538{
539 if (!x || !gamma || !Wq || !Wk || !Wv || !Q || !K || !V || !scratch) {
540 return;
541 }
542 if (seq_len <= 0 || embed_dim <= 0 || aligned_embed_dim <= 0 ||
543 head_dim <= 0 || aligned_head_dim <= 0 ||
544 num_heads <= 0 || num_kv_heads <= 0) {
545 return;
546 }
547 if (aligned_embed_dim % 32 != 0) {
548 return;
549 }
550 if (kv_stride_tokens < seq_len) {
551 return;
552 }
553 /* Determine quantization path: Q8_0 activations for Q5_0/Q8_0 weights,
554 * Q8_K activations for Q4_K/Q6_K weights. All QKV weights must use
555 * the same quantization family. */
556 int use_q8_k_path = qkv_q8_k_dtype_supported(wq_dt);
557 int use_q8_0_path = qkv_q8_0_dtype_supported(wq_dt);
558
559 if (!use_q8_k_path && !use_q8_0_path) {
560 /* Unsupported dtype for wq */
561 return;
562 }
563
564 /* Verify all dtypes are from the same family */
565 if (use_q8_k_path) {
566 if (!qkv_q8_k_dtype_supported(wk_dt) || !qkv_q8_k_dtype_supported(wv_dt)) {
567 return; /* Mixed Q8_K and Q8_0 paths not supported */
568 }
569 } else {
570 if (!qkv_q8_0_dtype_supported(wk_dt) || !qkv_q8_0_dtype_supported(wv_dt)) {
571 return;
572 }
573 }
574
575 const size_t float_bytes = (size_t)PREFILL_TILE_M * (size_t)aligned_embed_dim * sizeof(float);
576 /* Q8_K has larger blocks (256) than Q8_0 (32), so use appropriate size */
577 const CKDataType act_quant_type = use_q8_k_path ? CK_DT_Q8_K : CK_DT_Q8_0;
578 const size_t q8_row_bytes = ck_dtype_row_bytes(act_quant_type, (size_t)aligned_embed_dim);
579 const size_t q8_bytes = (size_t)PREFILL_TILE_M * q8_row_bytes;
580 const size_t q8_offset = align_up_size(float_bytes, 64);
581
582 float *normed = (float *)scratch;
583 uint8_t *q8_tile = (uint8_t *)scratch + q8_offset;
584 (void)q8_bytes;
585
586 const size_t q_head_stride = (size_t)seq_len * (size_t)aligned_head_dim;
587 const size_t kv_head_stride = (size_t)kv_stride_tokens * (size_t)aligned_head_dim;
588 const size_t head_w_elems = (size_t)aligned_head_dim * (size_t)aligned_embed_dim;
589 const size_t wq_head_bytes = ck_dtype_row_bytes(wq_dt, head_w_elems);
590 const size_t wk_head_bytes = ck_dtype_row_bytes(wk_dt, head_w_elems);
591 const size_t wv_head_bytes = ck_dtype_row_bytes(wv_dt, head_w_elems);
592
593 for (int m_start = 0; m_start < seq_len; m_start += PREFILL_TILE_M) {
594 int tile_m = (m_start + PREFILL_TILE_M <= seq_len)
595 ? PREFILL_TILE_M : (seq_len - m_start);
596
597 const float *x_tile = x + (size_t)m_start * (size_t)aligned_embed_dim;
598 rmsnorm_tile(x_tile, gamma, normed, tile_m, embed_dim, aligned_embed_dim, eps);
599
600 /* Quantize activations to appropriate format */
601 for (int t = 0; t < tile_m; ++t) {
602 const float *row = normed + (size_t)t * (size_t)aligned_embed_dim;
603 if (use_q8_k_path) {
605 q8_tile + (size_t)t * q8_row_bytes,
606 aligned_embed_dim);
607 } else {
609 q8_tile + (size_t)t * q8_row_bytes,
610 aligned_embed_dim);
611 }
612 }
613
614 for (int h = 0; h < num_heads; ++h) {
615 const uint8_t *wq_h = (const uint8_t *)Wq + (size_t)h * wq_head_bytes;
616 const float *bq_h = Bq ? (Bq + (size_t)h * (size_t)aligned_head_dim) : NULL;
617 float *q_h = Q + (size_t)h * q_head_stride + (size_t)m_start * (size_t)aligned_head_dim;
618
619 if (use_q8_k_path) {
620 gemm_nt_q8_k_qkv_dispatch(q8_tile, wq_h, bq_h, q_h,
621 tile_m, aligned_head_dim, aligned_embed_dim, wq_dt);
622 } else {
623 gemm_nt_q8_0_dispatch(q8_tile, wq_h, bq_h, q_h,
624 tile_m, aligned_head_dim, aligned_embed_dim, wq_dt);
625 }
626 }
627
628 for (int h = 0; h < num_kv_heads; ++h) {
629 const uint8_t *wk_h = (const uint8_t *)Wk + (size_t)h * wk_head_bytes;
630 const uint8_t *wv_h = (const uint8_t *)Wv + (size_t)h * wv_head_bytes;
631 const float *bk_h = Bk ? (Bk + (size_t)h * (size_t)aligned_head_dim) : NULL;
632 const float *bv_h = Bv ? (Bv + (size_t)h * (size_t)aligned_head_dim) : NULL;
633 float *k_h = K + (size_t)h * kv_head_stride + (size_t)m_start * (size_t)aligned_head_dim;
634 float *v_h = V + (size_t)h * kv_head_stride + (size_t)m_start * (size_t)aligned_head_dim;
635
636 if (use_q8_k_path) {
637 gemm_nt_q8_k_qkv_dispatch(q8_tile, wk_h, bk_h, k_h,
638 tile_m, aligned_head_dim, aligned_embed_dim, wk_dt);
639 gemm_nt_q8_k_qkv_dispatch(q8_tile, wv_h, bv_h, v_h,
640 tile_m, aligned_head_dim, aligned_embed_dim, wv_dt);
641 } else {
642 gemm_nt_q8_0_dispatch(q8_tile, wk_h, bk_h, k_h,
643 tile_m, aligned_head_dim, aligned_embed_dim, wk_dt);
644 gemm_nt_q8_0_dispatch(q8_tile, wv_h, bv_h, v_h,
645 tile_m, aligned_head_dim, aligned_embed_dim, wv_dt);
646 }
647 }
648 }
649}
CKDataType
Supported data types in C-Kernel-Engine.
static void gemm_nt_q8_0_dispatch(const void *A_q8, const void *B, const float *bias, float *C, int M, int N, int K, CKDataType dt)
static int qkv_q8_k_dtype_supported(CKDataType dt)
static void gemm_nt_q8_k_qkv_dispatch(const void *A_q8k, const void *B, const float *bias, float *C, int M, int N, int K, CKDataType dt)
static int qkv_q8_0_dtype_supported(CKDataType dt)

References align_up_size(), CK_DT_Q8_0, CK_DT_Q8_K, ck_dtype_row_bytes(), gemm_nt_q8_0_dispatch(), gemm_nt_q8_k_qkv_dispatch(), PREFILL_TILE_M, qkv_q8_0_dtype_supported(), qkv_q8_k_dtype_supported(), quantize_row_q8_0(), quantize_row_q8_k(), and rmsnorm_tile().

Referenced by mega_fused_attention_prefill(), and mega_fused_attention_prefill_q8_0().

◆ fused_rmsnorm_qkv_prefill_head_major_quant_scratch_size()

size_t fused_rmsnorm_qkv_prefill_head_major_quant_scratch_size ( int  aligned_embed_dim)

Get scratch buffer size for fused_rmsnorm_qkv_prefill_head_major_quant.

Definition at line 651 of file prefill_fused_gemm.c.

651 {
652 if (aligned_embed_dim <= 0) {
653 return 0;
654 }
655 const size_t float_bytes = (size_t)PREFILL_TILE_M * (size_t)aligned_embed_dim * sizeof(float);
656 /* Use max of Q8_0 and Q8_K sizes to support both paths */
657 const size_t q8_0_row_bytes = ck_dtype_row_bytes(CK_DT_Q8_0, (size_t)aligned_embed_dim);
658 const size_t q8_k_row_bytes = ck_dtype_row_bytes(CK_DT_Q8_K, (size_t)aligned_embed_dim);
659 const size_t q8_row_bytes = (q8_k_row_bytes > q8_0_row_bytes) ? q8_k_row_bytes : q8_0_row_bytes;
660 const size_t q8_bytes = (size_t)PREFILL_TILE_M * q8_row_bytes;
661 return align_up_size(float_bytes, 64) + q8_bytes;
662}

References align_up_size(), CK_DT_Q8_0, CK_DT_Q8_K, ck_dtype_row_bytes(), and PREFILL_TILE_M.

Referenced by mega_fused_attention_prefill(), mega_fused_attention_prefill_q8_0(), mega_fused_attention_prefill_q8_0_scratch_size(), and mega_fused_attention_prefill_scratch_size().

◆ fused_rmsnorm_qkv_scratch_size()

size_t fused_rmsnorm_qkv_scratch_size ( int  hidden)

Get scratch buffer size for fused_rmsnorm_qkv_prefill.

Get scratch buffer size for fused_rmsnorm_qkv_prefill.

Definition at line 739 of file prefill_fused_gemm.c.

739 {
740 return (size_t)PREFILL_TILE_M * hidden * sizeof(float);
741}

References PREFILL_TILE_M.

◆ gated_deltanet_autoregressive_backward()

void gated_deltanet_autoregressive_backward ( const float *  d_out,
const float *  d_state_out,
const float *  q,
const float *  k,
const float *  v,
const float *  g,
const float *  beta,
const float *  state_in,
const float *  state_out,
float *  d_q,
float *  d_k,
float *  d_v,
float *  d_g,
float *  d_beta,
float *  d_state_in,
int  num_heads,
int  state_dim,
float  norm_eps 
)

Definition at line 1988 of file deltanet_kernels.c.

2006{
2007 if (!d_out || !d_state_out || !q || !k || !v || !g || !beta || !state_in || !state_out ||
2008 !d_q || !d_k || !d_v || !d_g || !d_beta || !d_state_in) {
2009 return;
2010 }
2011 if (num_heads <= 0 || state_dim <= 0 || state_dim > CK_DELTANET_MAX_STACK_DIM) {
2012 return;
2013 }
2014
2016 d_out,
2017 d_state_out,
2018 q,
2019 k,
2020 v,
2021 g,
2022 beta,
2023 state_in,
2024 state_out,
2025 d_q,
2026 d_k,
2027 d_v,
2028 d_g,
2029 d_beta,
2030 d_state_in,
2031 num_heads,
2032 state_dim,
2033 norm_eps);
2034}
#define CK_DELTANET_MAX_STACK_DIM
void gated_deltanet_autoregressive_backward_ref(const float *d_out, const float *d_state_out, const float *q, const float *k, const float *v, const float *g, const float *beta, const float *state_in, const float *state_out, float *d_q, float *d_k, float *d_v, float *d_g, float *d_beta, float *d_state_in, int num_heads, int state_dim, float norm_eps)

References CK_DELTANET_MAX_STACK_DIM, and gated_deltanet_autoregressive_backward_ref().

◆ gated_deltanet_autoregressive_forward()

void gated_deltanet_autoregressive_forward ( const float *  q,
const float *  k,
const float *  v,
const float *  g,
const float *  beta,
const float *  state_in,
float *  state_out,
float *  out,
int  num_heads,
int  state_dim,
float  norm_eps 
)

Definition at line 1906 of file deltanet_kernels.c.

1917{
1918 if (!q || !k || !v || !g || !beta || !state_in || !state_out || !out) {
1919 return;
1920 }
1921 if (num_heads <= 0 || state_dim <= 0) {
1922 return;
1923 }
1924
1925 /*
1926 * q and k arrive pre-normalized by recurrent_qk_l2_norm, so the
1927 * ISA-specialized kernels can follow the same contract as the scalar ref.
1928 */
1931 q, k, v, g, beta, state_in, state_out, out, num_heads, state_dim, norm_eps);
1932 return;
1933 }
1934#if defined(__AVX512F__)
1935 gated_deltanet_autoregressive_forward_avx512(
1936 q, k, v, g, beta, state_in, state_out, out, num_heads, state_dim, norm_eps);
1937#elif defined(__AVX2__)
1938 gated_deltanet_autoregressive_forward_avx2(
1939 q, k, v, g, beta, state_in, state_out, out, num_heads, state_dim, norm_eps);
1940#elif defined(__AVX__)
1941 gated_deltanet_autoregressive_forward_avx(
1942 q, k, v, g, beta, state_in, state_out, out, num_heads, state_dim, norm_eps);
1943#else
1945 q, k, v, g, beta, state_in, state_out, out, num_heads, state_dim, norm_eps);
1946#endif
1947}
void gated_deltanet_autoregressive_forward_ref(const float *q, const float *k, const float *v, const float *g, const float *beta, const float *state_in, float *state_out, float *out, int num_heads, int state_dim, float norm_eps)
static int ck_deltanet_force_ref(void)

References ck_deltanet_force_ref(), ck_strict_parity_enabled(), and gated_deltanet_autoregressive_forward_ref().

◆ gated_deltanet_llama_avx2_forward()

void gated_deltanet_llama_avx2_forward ( const float *  q,
const float *  k,
const float *  v,
const float *  g,
const float *  beta,
const float *  state_in,
float *  state_out,
float *  out,
int  num_heads,
int  group_count,
int  state_dim,
float  norm_eps 
)

Definition at line 767 of file deltanet_kernels.c.

779{
781 q, k, v, g, beta, state_in, state_out, out,
782 num_heads, group_count, state_dim, norm_eps, 0, num_heads);
783}
static void gated_deltanet_llama_avx2_grouped_forward_transposed_impl(const float *q, const float *k, const float *v, const float *g, const float *beta, const float *state_in, float *state_out, float *out, int num_heads, int group_count, int state_dim, float norm_eps, int head_begin, int head_end)

References gated_deltanet_llama_avx2_grouped_forward_transposed_impl().

Referenced by gated_deltanet_llama_avx2_prefill_forward().

◆ gated_deltanet_llama_avx2_prefill_forward()

void gated_deltanet_llama_avx2_prefill_forward ( const float *  q,
const float *  k,
const float *  v,
const float *  g,
const float *  beta,
const float *  state_in,
float *  state_out,
float *  out,
int  rows,
int  num_heads,
int  group_count,
int  state_dim,
float  norm_eps 
)

Definition at line 1131 of file deltanet_kernels.c.

1144{
1145 if (!q || !k || !v || !g || !beta || !state_in || !state_out || !out ||
1146 rows <= 0 || num_heads <= 0 || group_count <= 0 ||
1147 num_heads % group_count != 0 || state_dim <= 0) {
1148 return;
1149 }
1150 const size_t qk_stride = (size_t) group_count * (size_t) state_dim;
1151 const size_t value_stride = (size_t) num_heads * (size_t) state_dim;
1152 const size_t gate_stride = (size_t) num_heads;
1153 for (int row = 0; row < rows; ++row) {
1155 q + (size_t) row * qk_stride,
1156 k + (size_t) row * qk_stride,
1157 v + (size_t) row * value_stride,
1158 g + (size_t) row * gate_stride,
1159 beta + (size_t) row * gate_stride,
1160 row == 0 ? state_in : state_out,
1161 state_out,
1162 out + (size_t) row * value_stride,
1163 num_heads, group_count, state_dim, norm_eps);
1164 }
1165}
void gated_deltanet_llama_avx2_forward(const float *q, const float *k, const float *v, const float *g, const float *beta, const float *state_in, float *state_out, float *out, int num_heads, int group_count, int state_dim, float norm_eps)

References gated_deltanet_llama_avx2_forward().

Referenced by gated_deltanet_llama_chunk64_prefill_forward().

◆ gated_deltanet_llama_chunk64_head_forward()

void gated_deltanet_llama_chunk64_head_forward ( const float *  q,
const float *  k,
const float *  v,
const float *  g,
const float *  beta,
const float *  state_in,
float *  state_out,
float *  out,
int  rows,
int  num_heads,
int  group_count,
int  head,
int  state_dim 
)

Definition at line 1202 of file deltanet_kernels.c.

1215{
1216#if defined(__AVX2__)
1217 if (!q || !k || !v || !g || !beta || !state_in || !state_out || !out ||
1218 rows <= 0 || num_heads <= 0 || group_count <= 0 ||
1219 num_heads % group_count != 0 || head < 0 || head >= num_heads ||
1220 state_dim <= 0 || state_dim > CK_DELTANET_LLAMA_CHUNK_MAX_DIM) {
1221 return;
1222 }
1223 gated_deltanet_llama_chunk64_head(
1224 q, k, v, g, beta, state_in, state_out, out,
1225 rows, num_heads, group_count, head, state_dim);
1226#else
1227 (void)q;
1228 (void)k;
1229 (void)v;
1230 (void)g;
1231 (void)beta;
1232 (void)state_in;
1233 (void)state_out;
1234 (void)out;
1235 (void)rows;
1236 (void)num_heads;
1237 (void)group_count;
1238 (void)head;
1239 (void)state_dim;
1240#endif
1241}
#define CK_DELTANET_LLAMA_CHUNK_MAX_DIM

References CK_DELTANET_LLAMA_CHUNK_MAX_DIM.

◆ gated_deltanet_llama_chunk64_prefill_forward()

void gated_deltanet_llama_chunk64_prefill_forward ( const float *  q,
const float *  k,
const float *  v,
const float *  g,
const float *  beta,
const float *  state_in,
float *  state_out,
float *  out,
int  rows,
int  num_heads,
int  group_count,
int  state_dim,
float  norm_eps 
)

Definition at line 1167 of file deltanet_kernels.c.

1180{
1181 if (!q || !k || !v || !g || !beta || !state_in || !state_out || !out ||
1182 rows <= 0 || num_heads <= 0 || group_count <= 0 ||
1183 num_heads % group_count != 0 || state_dim <= 0) {
1184 return;
1185 }
1186#if defined(__AVX2__)
1187 (void)norm_eps;
1188 if (state_dim <= CK_DELTANET_LLAMA_CHUNK_MAX_DIM) {
1189 for (int head = 0; head < num_heads; ++head) {
1190 gated_deltanet_llama_chunk64_head(
1191 q, k, v, g, beta, state_in, state_out, out,
1192 rows, num_heads, group_count, head, state_dim);
1193 }
1194 return;
1195 }
1196#endif
1198 q, k, v, g, beta, state_in, state_out, out,
1199 rows, num_heads, group_count, state_dim, norm_eps);
1200}
void gated_deltanet_llama_avx2_prefill_forward(const float *q, const float *k, const float *v, const float *g, const float *beta, const float *state_in, float *state_out, float *out, int rows, int num_heads, int group_count, int state_dim, float norm_eps)

References CK_DELTANET_LLAMA_CHUNK_MAX_DIM, and gated_deltanet_llama_avx2_prefill_forward().

◆ gated_deltanet_prefill_forward()

void gated_deltanet_prefill_forward ( const float *  q,
const float *  k,
const float *  v,
const float *  g,
const float *  beta,
const float *  state_in,
float *  state_out,
float *  out,
int  rows,
int  num_heads,
int  state_dim,
float  norm_eps 
)

Definition at line 1949 of file deltanet_kernels.c.

1961{
1962 if (!q || !k || !v || !g || !beta || !state_in || !state_out || !out) {
1963 return;
1964 }
1965 if (rows <= 0 || num_heads <= 0 || state_dim <= 0) {
1966 return;
1967 }
1968
1969 const size_t vector_stride = (size_t)num_heads * (size_t)state_dim;
1970 const size_t gate_stride = (size_t)num_heads;
1971 for (int row = 0; row < rows; ++row) {
1972 const float *row_state_in = row == 0 ? state_in : state_out;
1974 q + (size_t)row * vector_stride,
1975 k + (size_t)row * vector_stride,
1976 v + (size_t)row * vector_stride,
1977 g + (size_t)row * gate_stride,
1978 beta + (size_t)row * gate_stride,
1979 row_state_in,
1980 state_out,
1981 out + (size_t)row * vector_stride,
1982 num_heads,
1983 state_dim,
1984 norm_eps);
1985 }
1986}
void gated_deltanet_autoregressive_forward(const float *q, const float *k, const float *v, const float *g, const float *beta, const float *state_in, float *state_out, float *out, int num_heads, int state_dim, float norm_eps)

References gated_deltanet_autoregressive_forward().

◆ gated_deltanet_pytorch_grouped_bf16_forward()

void gated_deltanet_pytorch_grouped_bf16_forward ( const float *  q,
const float *  k,
const float *  v,
const float *  g,
const float *  beta,
const float *  state_in,
float *  state_out,
float *  out,
int  num_heads,
int  group_count,
int  state_dim,
float  norm_eps 
)

Definition at line 1089 of file deltanet_kernels.c.

1101{
1103 q, k, v, g, beta, state_in, state_out, out,
1104 NULL, NULL, NULL,
1105 num_heads, group_count, state_dim, norm_eps);
1106}
static void gated_deltanet_pytorch_grouped_bf16_forward_impl(const float *q, const float *k, const float *v, const float *g, const float *beta, const float *state_in, float *state_out, float *out, float *debug_decayed_state, float *debug_memory, float *debug_delta, int num_heads, int group_count, int state_dim, float norm_eps)

References gated_deltanet_pytorch_grouped_bf16_forward_impl().

Referenced by gated_deltanet_pytorch_grouped_bf16_prefill_forward().

◆ gated_deltanet_pytorch_grouped_bf16_prefill_forward()

void gated_deltanet_pytorch_grouped_bf16_prefill_forward ( const float *  q,
const float *  k,
const float *  v,
const float *  g,
const float *  beta,
const float *  state_in,
float *  state_out,
float *  out,
int  rows,
int  num_heads,
int  group_count,
int  state_dim,
float  norm_eps 
)

Definition at line 1243 of file deltanet_kernels.c.

1257{
1258 if (!q || !k || !v || !g || !beta || !state_in || !state_out || !out ||
1259 rows <= 0 || num_heads <= 0 || group_count <= 0 ||
1260 num_heads % group_count != 0 || state_dim <= 0) {
1261 return;
1262 }
1263 const size_t qk_stride = (size_t)group_count * (size_t)state_dim;
1264 const size_t value_stride = (size_t)num_heads * (size_t)state_dim;
1265 const size_t gate_stride = (size_t)num_heads;
1266 for (int row = 0; row < rows; ++row) {
1268 q + (size_t)row * qk_stride,
1269 k + (size_t)row * qk_stride,
1270 v + (size_t)row * value_stride,
1271 g + (size_t)row * gate_stride,
1272 beta + (size_t)row * gate_stride,
1273 row == 0 ? state_in : state_out,
1274 state_out,
1275 out + (size_t)row * value_stride,
1276 num_heads, group_count, state_dim, norm_eps);
1277 }
1278}
void gated_deltanet_pytorch_grouped_bf16_forward(const float *q, const float *k, const float *v, const float *g, const float *beta, const float *state_in, float *state_out, float *out, int num_heads, int group_count, int state_dim, float norm_eps)

References gated_deltanet_pytorch_grouped_bf16_forward().

◆ geglu_backward_bf16_mixed()

void geglu_backward_bf16_mixed ( const uint16_t *  x,
const uint16_t *  d_out,
float *  d_x,
int  tokens,
int  dim 
)

Definition at line 139 of file geglu_kernels.c.

144{
145 if (!x || !d_out || !d_x || tokens <= 0 || dim <= 0) {
146 return;
147 }
148
149 const float sqrt_2_over_pi = 0.7978845608f;
150 const float coeff = 0.044715f;
151 const int inner_dim = dim * 2;
152
153 for (int t = 0; t < tokens; ++t) {
154 const uint16_t *x_ptr = x + (size_t)t * (size_t)inner_dim;
155 const uint16_t *d_out_ptr = d_out + (size_t)t * (size_t)dim;
156 float *d_x_ptr = d_x + (size_t)t * (size_t)inner_dim;
157
158 for (int d = 0; d < dim; ++d) {
159 const float a = bf16_to_float(x_ptr[d]);
160 const float b = bf16_to_float(x_ptr[dim + d]);
161 const float dout = bf16_to_float(d_out_ptr[d]);
162
163 const float a2 = a * a;
164 const float a3 = a2 * a;
165 const float g = sqrt_2_over_pi * (a + coeff * a3);
166 const float tanh_g = tanhf(g);
167 const float sech2_g = 1.0f - tanh_g * tanh_g;
168 const float g_prime = sqrt_2_over_pi * (1.0f + 3.0f * coeff * a2);
169
170 const float d_gelu = 0.5f * (1.0f + tanh_g) + 0.5f * a * sech2_g * g_prime;
171 d_x_ptr[d] = dout * d_gelu * b;
172
173 const float gelu_a = 0.5f * a * (1.0f + tanh_g);
174 d_x_ptr[dim + d] = dout * gelu_a;
175 }
176 }
177}

References bf16_to_float().

◆ geglu_backward_fp32()

void geglu_backward_fp32 ( const float *  x,
const float *  d_out,
float *  d_x,
int  tokens,
int  dim 
)

Definition at line 99 of file geglu_kernels.c.

104{
105 if (!x || !d_out || !d_x || tokens <= 0 || dim <= 0) {
106 return;
107 }
108
109 const float sqrt_2_over_pi = 0.7978845608f;
110 const float coeff = 0.044715f;
111 const int inner_dim = dim * 2;
112
113 for (int t = 0; t < tokens; ++t) {
114 const float *x_ptr = x + (size_t)t * (size_t)inner_dim;
115 const float *d_out_ptr = d_out + (size_t)t * (size_t)dim;
116 float *d_x_ptr = d_x + (size_t)t * (size_t)inner_dim;
117
118 for (int d = 0; d < dim; ++d) {
119 float a = x_ptr[d];
120 float b = x_ptr[dim + d];
121 float dout = d_out_ptr[d];
122
123 float a2 = a * a;
124 float a3 = a2 * a;
125 float g = sqrt_2_over_pi * (a + coeff * a3);
126 float tanh_g = tanhf(g);
127 float sech2_g = 1.0f - tanh_g * tanh_g;
128 float g_prime = sqrt_2_over_pi * (1.0f + 3.0f * coeff * a2);
129
130 float d_gelu = 0.5f * (1.0f + tanh_g) + 0.5f * a * sech2_g * g_prime;
131 d_x_ptr[d] = dout * d_gelu * b;
132
133 float gelu_a = 0.5f * a * (1.0f + tanh_g);
134 d_x_ptr[dim + d] = dout * gelu_a;
135 }
136 }
137}

◆ geglu_forward_bf16()

void geglu_forward_bf16 ( const uint16_t *  x,
uint16_t *  out,
int  tokens,
int  dim,
float *  scratch 
)

Definition at line 83 of file geglu_kernels.c.

84{
85 if (!x || !out || !scratch || tokens <= 0 || dim <= 0) {
86 return;
87 }
88
89 const size_t fp32_size = (size_t)tokens * (size_t)dim;
90 const size_t input_size = fp32_size * 2;
91 float *fp32_input = scratch;
92 float *fp32_output = scratch + input_size;
93
94 bf16_tensor_to_float(x, fp32_input, input_size);
95 geglu_forward_fp32(fp32_input, fp32_output, tokens, dim);
96 float_tensor_to_bf16(fp32_output, out, fp32_size);
97}
void geglu_forward_fp32(const float *x, float *out, int tokens, int dim)

References bf16_tensor_to_float(), float_tensor_to_bf16(), and geglu_forward_fp32().

◆ geglu_forward_exact()

void geglu_forward_exact ( const float *  x,
float *  out,
int  tokens,
int  dim 
)

Definition at line 42 of file geglu_kernels.c.

43{
44 const int inner_dim = dim * 2;
45 for (int t = 0; t < tokens; ++t) {
46 const float *x_ptr = x + (size_t)t * (size_t)inner_dim;
47 float *out_ptr = out + (size_t)t * (size_t)dim;
48
49 for (int d = 0; d < dim; ++d) {
50 out_ptr[d] = ck_gelu_tanh_parity_f32(x_ptr[d]) * x_ptr[dim + d];
51 }
52 }
53}
static float ck_gelu_tanh_parity_f32(float x)

References ck_gelu_tanh_parity_f32().

Referenced by geglu_forward_fp32().

◆ geglu_forward_fp32()

void geglu_forward_fp32 ( const float *  x,
float *  out,
int  tokens,
int  dim 
)

Definition at line 55 of file geglu_kernels.c.

56{
57 if (!x || !out || tokens <= 0 || dim <= 0) {
58 return;
59 }
60
62 geglu_forward_exact(x, out, tokens, dim);
63 return;
64 }
65
66 const int inner_dim = dim * 2;
67 for (int t = 0; t < tokens; ++t) {
68 const float *x_ptr = x + (size_t)t * (size_t)inner_dim;
69 float *out_ptr = out + (size_t)t * (size_t)dim;
70
71 for (int d = 0; d < dim; ++d) {
72 out_ptr[d] = x_ptr[d];
73 }
74
75 gelu_fast_inplace(out_ptr, (size_t)dim);
76
77 for (int d = 0; d < dim; ++d) {
78 out_ptr[d] *= x_ptr[dim + d];
79 }
80 }
81}
void geglu_forward_exact(const float *x, float *out, int tokens, int dim)
void gelu_fast_inplace(float *data, size_t n)

References ck_strict_parity_enabled(), geglu_forward_exact(), and gelu_fast_inplace().

Referenced by geglu_forward_bf16().

◆ geglu_forward_ggml_native()

void geglu_forward_ggml_native ( const float *  x,
float *  out,
int  tokens,
int  dim 
)

Definition at line 17 of file geglu_kernels.c.

18{
19 if (!x || !out || tokens <= 0 || dim <= 0) return;
20 /* Preserve ascending compaction when output aliases the gate/up input. */
21 for (int t = 0; t < tokens; ++t) {
22 const float *row = x + (size_t)t * (size_t)dim * 2;
23 float *dst = out + (size_t)t * dim;
24 for (int d = 0; d < dim; ++d) {
25 const float gate = row[d], up = row[dim + d];
26 float value = gate;
27 gelu_ggml_native_inplace(&value, 1);
28 dst[d] = gate <= -10.0f ? 0.0f : value * up;
29 }
30 }
31}
void gelu_ggml_native_inplace(float *data, size_t n)

References gelu_ggml_native_inplace().

◆ gelu_backward_exact()

void gelu_backward_exact ( const float *  input,
const float *  d_output,
float *  d_input,
size_t  n 
)

Definition at line 368 of file gelu_kernels.c.

372{
373 const float sqrt_2_over_pi = 0.7978845608f;
374 const float coeff = 0.044715f;
375
376#if defined(__AVX512F__)
377 const __m512 sqrt_2_pi_vec = _mm512_set1_ps(sqrt_2_over_pi);
378 const __m512 coeff_vec = _mm512_set1_ps(coeff);
379 const __m512 coeff3_vec = _mm512_set1_ps(3.0f * coeff);
380 const __m512 half_vec = _mm512_set1_ps(0.5f);
381 const __m512 one_vec = _mm512_set1_ps(1.0f);
382
383 size_t i = 0;
384 for (; i + 16 <= n; i += 16) {
385 __m512 x = _mm512_loadu_ps(&input[i]);
386 __m512 dy = _mm512_loadu_ps(&d_output[i]);
387
388 __m512 x2 = _mm512_mul_ps(x, x);
389 __m512 x3 = _mm512_mul_ps(x2, x);
390
391 // g = sqrt(2/pi) * (x + 0.044715 * x^3)
392 __m512 g = _mm512_fmadd_ps(coeff_vec, x3, x);
393 g = _mm512_mul_ps(sqrt_2_pi_vec, g);
394
395 __m512 tanh_g = tanh512_fast(g);
396
397 // g' = sqrt(2/pi) * (1 + 3 * 0.044715 * x^2)
398 __m512 g_prime = _mm512_fmadd_ps(coeff3_vec, x2, one_vec);
399 g_prime = _mm512_mul_ps(sqrt_2_pi_vec, g_prime);
400
401 // sech^2(g) = 1 - tanh^2(g)
402 __m512 sech2_g = _mm512_fnmadd_ps(tanh_g, tanh_g, one_vec);
403
404 // gelu_derivative = 0.5 * (1 + tanh_g) + 0.5 * x * sech2_g * g_prime
405 __m512 term1 = _mm512_mul_ps(half_vec, _mm512_add_ps(one_vec, tanh_g));
406 __m512 term2 = _mm512_mul_ps(half_vec, _mm512_mul_ps(x, _mm512_mul_ps(sech2_g, g_prime)));
407 __m512 gelu_deriv = _mm512_add_ps(term1, term2);
408
409 __m512 result = _mm512_mul_ps(dy, gelu_deriv);
410 _mm512_storeu_ps(&d_input[i], result);
411 }
412 // Handle remaining elements
413 for (; i < n; ++i) {
414 float x = input[i];
415 float x3 = x * x * x;
416 float g = sqrt_2_over_pi * (x + coeff * x3);
417 float tanh_g = tanhf(g);
418 float x2 = x * x;
419 float g_prime = sqrt_2_over_pi * (1.0f + 3.0f * coeff * x2);
420 float sech2_g = 1.0f - tanh_g * tanh_g;
421 float gelu_derivative = 0.5f * (1.0f + tanh_g) + 0.5f * x * sech2_g * g_prime;
422 d_input[i] = d_output[i] * gelu_derivative;
423 }
424
425#elif defined(__AVX2__)
426 const __m256 sqrt_2_pi_vec = _mm256_set1_ps(sqrt_2_over_pi);
427 const __m256 coeff_vec = _mm256_set1_ps(coeff);
428 const __m256 coeff3_vec = _mm256_set1_ps(3.0f * coeff);
429 const __m256 half_vec = _mm256_set1_ps(0.5f);
430 const __m256 one_vec = _mm256_set1_ps(1.0f);
431
432 size_t i = 0;
433 for (; i + 8 <= n; i += 8) {
434 __m256 x = _mm256_loadu_ps(&input[i]);
435 __m256 dy = _mm256_loadu_ps(&d_output[i]);
436
437 __m256 x2 = _mm256_mul_ps(x, x);
438 __m256 x3 = _mm256_mul_ps(x2, x);
439
440 // g = sqrt(2/pi) * (x + 0.044715 * x^3)
441 __m256 g = _mm256_fmadd_ps(coeff_vec, x3, x);
442 g = _mm256_mul_ps(sqrt_2_pi_vec, g);
443
444 __m256 tanh_g = tanh256_fast(g);
445
446 // g' = sqrt(2/pi) * (1 + 3 * 0.044715 * x^2)
447 __m256 g_prime = _mm256_fmadd_ps(coeff3_vec, x2, one_vec);
448 g_prime = _mm256_mul_ps(sqrt_2_pi_vec, g_prime);
449
450 // sech^2(g) = 1 - tanh^2(g)
451 __m256 sech2_g = _mm256_fnmadd_ps(tanh_g, tanh_g, one_vec);
452
453 // gelu_derivative = 0.5 * (1 + tanh_g) + 0.5 * x * sech2_g * g_prime
454 __m256 term1 = _mm256_mul_ps(half_vec, _mm256_add_ps(one_vec, tanh_g));
455 __m256 term2 = _mm256_mul_ps(half_vec, _mm256_mul_ps(x, _mm256_mul_ps(sech2_g, g_prime)));
456 __m256 gelu_deriv = _mm256_add_ps(term1, term2);
457
458 __m256 result = _mm256_mul_ps(dy, gelu_deriv);
459 _mm256_storeu_ps(&d_input[i], result);
460 }
461 // Handle remaining elements
462 for (; i < n; ++i) {
463 float x = input[i];
464 float x3 = x * x * x;
465 float g = sqrt_2_over_pi * (x + coeff * x3);
466 float tanh_g = tanhf(g);
467 float x2 = x * x;
468 float g_prime = sqrt_2_over_pi * (1.0f + 3.0f * coeff * x2);
469 float sech2_g = 1.0f - tanh_g * tanh_g;
470 float gelu_derivative = 0.5f * (1.0f + tanh_g) + 0.5f * x * sech2_g * g_prime;
471 d_input[i] = d_output[i] * gelu_derivative;
472 }
473
474#elif defined(__AVX__)
475 // AVX1: Vectorize arithmetic, use scalar tanh
476 const __m256 sqrt_2_pi_vec = _mm256_set1_ps(sqrt_2_over_pi);
477 const __m256 coeff_vec = _mm256_set1_ps(coeff);
478 const __m256 coeff3_vec = _mm256_set1_ps(3.0f * coeff);
479 const __m256 half_vec = _mm256_set1_ps(0.5f);
480 const __m256 one_vec = _mm256_set1_ps(1.0f);
481
482 size_t i = 0;
483 float g_arr[8] __attribute__((aligned(32)));
484 float tanh_arr[8] __attribute__((aligned(32)));
485
486 for (; i + 8 <= n; i += 8) {
487 __m256 x = _mm256_loadu_ps(&input[i]);
488 __m256 dy = _mm256_loadu_ps(&d_output[i]);
489
490 __m256 x2 = _mm256_mul_ps(x, x);
491 __m256 x3 = _mm256_mul_ps(x2, x);
492
493 // g = sqrt(2/pi) * (x + 0.044715 * x^3)
494 __m256 coeff_x3 = _mm256_mul_ps(coeff_vec, x3);
495 __m256 g = _mm256_mul_ps(sqrt_2_pi_vec, _mm256_add_ps(x, coeff_x3));
496
497 // Compute tanh scalarly
498 _mm256_store_ps(g_arr, g);
499 for (int j = 0; j < 8; ++j) {
500 tanh_arr[j] = tanhf(g_arr[j]);
501 }
502 __m256 tanh_g = _mm256_load_ps(tanh_arr);
503
504 // g' = sqrt(2/pi) * (1 + 3 * 0.044715 * x^2)
505 __m256 coeff3_x2 = _mm256_mul_ps(coeff3_vec, x2);
506 __m256 g_prime = _mm256_mul_ps(sqrt_2_pi_vec, _mm256_add_ps(one_vec, coeff3_x2));
507
508 // sech^2(g) = 1 - tanh^2(g)
509 __m256 tanh_g_sq = _mm256_mul_ps(tanh_g, tanh_g);
510 __m256 sech2_g = _mm256_sub_ps(one_vec, tanh_g_sq);
511
512 // gelu_derivative = 0.5 * (1 + tanh_g) + 0.5 * x * sech2_g * g_prime
513 __m256 term1 = _mm256_mul_ps(half_vec, _mm256_add_ps(one_vec, tanh_g));
514 __m256 term2 = _mm256_mul_ps(half_vec, _mm256_mul_ps(x, _mm256_mul_ps(sech2_g, g_prime)));
515 __m256 gelu_deriv = _mm256_add_ps(term1, term2);
516
517 __m256 result = _mm256_mul_ps(dy, gelu_deriv);
518 _mm256_storeu_ps(&d_input[i], result);
519 }
520 // Handle remaining elements
521 for (; i < n; ++i) {
522 float x = input[i];
523 float x3 = x * x * x;
524 float g = sqrt_2_over_pi * (x + coeff * x3);
525 float tanh_g = tanhf(g);
526 float x2 = x * x;
527 float g_prime = sqrt_2_over_pi * (1.0f + 3.0f * coeff * x2);
528 float sech2_g = 1.0f - tanh_g * tanh_g;
529 float gelu_derivative = 0.5f * (1.0f + tanh_g) + 0.5f * x * sech2_g * g_prime;
530 d_input[i] = d_output[i] * gelu_derivative;
531 }
532
533#else
534 // Scalar fallback
535 for (size_t i = 0; i < n; ++i) {
536 float x = input[i];
537
538 float x3 = x * x * x;
539 float g = sqrt_2_over_pi * (x + coeff * x3);
540 float tanh_g = tanhf(g);
541
542 float x2 = x * x;
543 float g_prime = sqrt_2_over_pi * (1.0f + 3.0f * coeff * x2);
544
545 float sech2_g = 1.0f - tanh_g * tanh_g;
546 float gelu_derivative =
547 0.5f * (1.0f + tanh_g) + 0.5f * x * sech2_g * g_prime;
548
549 d_input[i] = d_output[i] * gelu_derivative;
550 }
551#endif
552}

References __attribute__().

◆ gelu_backward_exact_bf16()

void gelu_backward_exact_bf16 ( const uint16_t *  input,
const uint16_t *  d_output,
uint16_t *  d_input,
size_t  n,
float *  scratch_input,
float *  scratch_d_output,
float *  scratch_d_input 
)

Definition at line 46 of file gelu_kernels_bf16.c.

53{
54 if (!scratch_input || !scratch_d_output || !scratch_d_input) return;
55
56 bf16_tensor_to_float(input, scratch_input, n);
57 bf16_tensor_to_float(d_output, scratch_d_output, n);
58
59 // Use scalar exact version to avoid fast tanh approximation error
60 // accumulating with BF16 precision loss.
61 gelu_backward_scalar(scratch_input, scratch_d_output, scratch_d_input, n);
62
63 float_tensor_to_bf16(scratch_d_input, d_input, n);
64}
void gelu_backward_scalar(const float *input, const float *d_output, float *d_input, size_t n)

References bf16_tensor_to_float(), float_tensor_to_bf16(), and gelu_backward_scalar().

◆ gelu_backward_fast()

void gelu_backward_fast ( const float *  input,
const float *  d_output,
float *  d_input,
size_t  n 
)

Definition at line 818 of file gelu_kernels.c.

822{
823 const float beta = 1.702f;
824
825#if defined(__AVX512F__)
826 const __m512 beta_vec = _mm512_set1_ps(beta);
827 const __m512 one_vec = _mm512_set1_ps(1.0f);
828 const __m512 neg_beta_vec = _mm512_set1_ps(-beta);
829
830 size_t i = 0;
831 for (; i + 16 <= n; i += 16) {
832 __m512 x = _mm512_loadu_ps(&input[i]);
833 __m512 dy = _mm512_loadu_ps(&d_output[i]);
834
835 // s = sigmoid(beta * x) = 1 / (1 + exp(-beta * x))
836 __m512 neg_beta_x = _mm512_mul_ps(neg_beta_vec, x);
837 __m512 exp_neg = exp512_fast(neg_beta_x);
838 __m512 s = _mm512_div_ps(one_vec, _mm512_add_ps(one_vec, exp_neg));
839
840 // gelu_derivative = s * (1 + x * (1 - s) * beta)
841 __m512 one_minus_s = _mm512_sub_ps(one_vec, s);
842 __m512 inner = _mm512_fmadd_ps(_mm512_mul_ps(x, one_minus_s), beta_vec, one_vec);
843 __m512 gelu_deriv = _mm512_mul_ps(s, inner);
844
845 __m512 result = _mm512_mul_ps(dy, gelu_deriv);
846 _mm512_storeu_ps(&d_input[i], result);
847 }
848 // Handle remaining elements
849 for (; i < n; ++i) {
850 float x = input[i];
851 float s = 1.0f / (1.0f + expf(-beta * x));
852 float gelu_derivative = s * (1.0f + x * (1.0f - s) * beta);
853 d_input[i] = d_output[i] * gelu_derivative;
854 }
855
856#elif defined(__AVX2__)
857 const __m256 beta_vec = _mm256_set1_ps(beta);
858 const __m256 one_vec = _mm256_set1_ps(1.0f);
859 const __m256 neg_beta_vec = _mm256_set1_ps(-beta);
860
861 size_t i = 0;
862 for (; i + 8 <= n; i += 8) {
863 __m256 x = _mm256_loadu_ps(&input[i]);
864 __m256 dy = _mm256_loadu_ps(&d_output[i]);
865
866 // s = sigmoid(beta * x) = 1 / (1 + exp(-beta * x))
867 __m256 neg_beta_x = _mm256_mul_ps(neg_beta_vec, x);
868 __m256 exp_neg = exp256_fast(neg_beta_x);
869 __m256 s = _mm256_div_ps(one_vec, _mm256_add_ps(one_vec, exp_neg));
870
871 // gelu_derivative = s * (1 + x * (1 - s) * beta)
872 __m256 one_minus_s = _mm256_sub_ps(one_vec, s);
873 __m256 inner = _mm256_fmadd_ps(_mm256_mul_ps(x, one_minus_s), beta_vec, one_vec);
874 __m256 gelu_deriv = _mm256_mul_ps(s, inner);
875
876 __m256 result = _mm256_mul_ps(dy, gelu_deriv);
877 _mm256_storeu_ps(&d_input[i], result);
878 }
879 // Handle remaining elements
880 for (; i < n; ++i) {
881 float x = input[i];
882 float s = 1.0f / (1.0f + expf(-beta * x));
883 float gelu_derivative = s * (1.0f + x * (1.0f - s) * beta);
884 d_input[i] = d_output[i] * gelu_derivative;
885 }
886
887#elif defined(__AVX__)
888 // AVX1: Vectorize arithmetic, use scalar exp
889 const __m256 beta_vec = _mm256_set1_ps(beta);
890 const __m256 one_vec = _mm256_set1_ps(1.0f);
891 const __m256 neg_beta_vec = _mm256_set1_ps(-beta);
892
893 size_t i = 0;
894 float neg_beta_x_arr[8] __attribute__((aligned(32)));
895 float exp_arr[8] __attribute__((aligned(32)));
896
897 for (; i + 8 <= n; i += 8) {
898 __m256 x = _mm256_loadu_ps(&input[i]);
899 __m256 dy = _mm256_loadu_ps(&d_output[i]);
900
901 // s = sigmoid(beta * x) = 1 / (1 + exp(-beta * x))
902 __m256 neg_beta_x = _mm256_mul_ps(neg_beta_vec, x);
903
904 // Compute exp scalarly
905 _mm256_store_ps(neg_beta_x_arr, neg_beta_x);
906 for (int j = 0; j < 8; ++j) {
907 exp_arr[j] = expf(neg_beta_x_arr[j]);
908 }
909 __m256 exp_neg = _mm256_load_ps(exp_arr);
910
911 __m256 s = _mm256_div_ps(one_vec, _mm256_add_ps(one_vec, exp_neg));
912
913 // gelu_derivative = s * (1 + x * (1 - s) * beta)
914 __m256 one_minus_s = _mm256_sub_ps(one_vec, s);
915 __m256 x_one_minus_s = _mm256_mul_ps(x, one_minus_s);
916 __m256 x_one_minus_s_beta = _mm256_mul_ps(x_one_minus_s, beta_vec);
917 __m256 inner = _mm256_add_ps(one_vec, x_one_minus_s_beta);
918 __m256 gelu_deriv = _mm256_mul_ps(s, inner);
919
920 __m256 result = _mm256_mul_ps(dy, gelu_deriv);
921 _mm256_storeu_ps(&d_input[i], result);
922 }
923 // Handle remaining elements
924 for (; i < n; ++i) {
925 float x = input[i];
926 float s = 1.0f / (1.0f + expf(-beta * x));
927 float gelu_derivative = s * (1.0f + x * (1.0f - s) * beta);
928 d_input[i] = d_output[i] * gelu_derivative;
929 }
930
931#else
932 // Scalar fallback
933 for (size_t i = 0; i < n; ++i) {
934 float x = input[i];
935 float s = 1.0f / (1.0f + expf(-beta * x));
936 float gelu_derivative = s * (1.0f + x * (1.0f - s) * beta);
937 d_input[i] = d_output[i] * gelu_derivative;
938 }
939#endif
940}

References __attribute__().

Referenced by gelu_backward_fast_bf16().

◆ gelu_backward_fast_bf16()

void gelu_backward_fast_bf16 ( const uint16_t *  input,
const uint16_t *  d_output,
uint16_t *  d_input,
size_t  n,
float *  scratch_input,
float *  scratch_d_output,
float *  scratch_d_input 
)

Definition at line 69 of file gelu_kernels_bf16.c.

76{
77 if (!scratch_input || !scratch_d_output || !scratch_d_input) return;
78
79 bf16_tensor_to_float(input, scratch_input, n);
80 bf16_tensor_to_float(d_output, scratch_d_output, n);
81
82 gelu_backward_fast(scratch_input, scratch_d_output, scratch_d_input, n);
83
84 float_tensor_to_bf16(scratch_d_input, d_input, n);
85}
void gelu_backward_fast(const float *input, const float *d_output, float *d_input, size_t n)

References bf16_tensor_to_float(), float_tensor_to_bf16(), and gelu_backward_fast().

◆ gelu_backward_scalar()

void gelu_backward_scalar ( const float *  input,
const float *  d_output,
float *  d_input,
size_t  n 
)

Definition at line 794 of file gelu_kernels.c.

798{
799 const float sqrt_2_over_pi = 0.7978845608f;
800 const float coeff = 0.044715f;
801
802 for (size_t i = 0; i < n; ++i) {
803 float x = input[i];
804 float x3 = x * x * x;
805 float g = sqrt_2_over_pi * (x + coeff * x3);
806 float tanh_g = tanhf(g);
807 float x2 = x * x;
808 float g_prime = sqrt_2_over_pi * (1.0f + 3.0f * coeff * x2);
809 float sech2_g = 1.0f - tanh_g * tanh_g;
810 float gelu_derivative = 0.5f * (1.0f + tanh_g) + 0.5f * x * sech2_g * g_prime;
811 d_input[i] = d_output[i] * gelu_derivative;
812 }
813}

Referenced by gelu_backward_exact_bf16().

◆ gelu_erf_bf16_storage()

void gelu_erf_bf16_storage ( float *  data,
size_t  n 
)

Definition at line 609 of file gelu_kernels.c.

610{
611 const double inv_sqrt_2 = 0.707106781186547524400844362104849039;
612 ck_gelu_math_f64_fn reference_erf = ck_gelu_system_erf();
613 for (size_t i = 0; i < n; ++i) {
614 const float x = bf16_to_float(float_to_bf16(data[i]));
615 const double scaled = (double)x * inv_sqrt_2;
616 const double erf_value = reference_erf ? reference_erf(scaled) : erf(scaled);
617 const float output = (float)(0.5 * (double)x * (1.0 + erf_value));
618 data[i] = bf16_to_float(float_to_bf16(output));
619 }
620}
double(* ck_gelu_math_f64_fn)(double)
static ck_gelu_math_f64_fn ck_gelu_system_erf(void)

References bf16_to_float(), ck_gelu_system_erf(), and float_to_bf16().

◆ gelu_erf_fp64_f32_inplace()

void gelu_erf_fp64_f32_inplace ( float *  data,
size_t  n 
)

Definition at line 566 of file gelu_kernels.c.

567{
568 const double inv_sqrt_2 = 0.707106781186547524400844362104849039;
569 ck_gelu_math_f64_fn reference_erf = ck_gelu_system_erf();
570 for (size_t i = 0; i < n; ++i) {
571 const float x = data[i];
572 const double scaled = (double)x * inv_sqrt_2;
573 const double erf_value = reference_erf ? reference_erf(scaled) : erf(scaled);
574 data[i] = (float)(0.5 * (double)x * (1.0 + erf_value));
575 }
576}

References ck_gelu_system_erf().

Referenced by gelu_pytorch_erf_f32_inplace().

◆ gelu_exact_inplace()

void gelu_exact_inplace ( float *  data,
size_t  n 
)

Definition at line 557 of file gelu_kernels.c.

558{
559 for (size_t i = 0; i < n; ++i) {
560 data[i] = ck_gelu_tanh_f32(data[i]);
561 }
562}
static float ck_gelu_tanh_f32(float x)

References ck_gelu_tanh_f32().

Referenced by gelu_fast_inplace_bf16(), and mlp_token_parallel_exact().

◆ gelu_fast_inplace()

void gelu_fast_inplace ( float *  data,
size_t  n 
)

GELU activation forward (fast approximation, in-place)

Test:

test_gelu.py::TestGELUForward::test_gelu_fast_inplace

test_gelu.py::TestGELUForward::test_gelu_vs_exact

test_parity.py::test_gelu_parity

Fast GELU approximation: 0.5 * x * (1 + tanh(sqrt(2/pi) * (x + 0.044715 * x^3))) In-place on contiguous buffer.

After changes: make test && make llamacpp-parity-full

Definition at line 243 of file gelu_kernels.c.

244{
245 const float sqrt_2_over_pi = 0.7978845608f;
246 const float coeff = 0.044715f;
247
248#if defined(__AVX512F__)
249 const __m512 sqrt_2_pi_vec = _mm512_set1_ps(sqrt_2_over_pi);
250 const __m512 coeff_vec = _mm512_set1_ps(coeff);
251 const __m512 half_vec = _mm512_set1_ps(0.5f);
252 const __m512 one_vec = _mm512_set1_ps(1.0f);
253
254 size_t i = 0;
255 for (; i + 16 <= n; i += 16) {
256 __m512 x = _mm512_loadu_ps(&data[i]);
257 __m512 x2 = _mm512_mul_ps(x, x);
258 __m512 x3 = _mm512_mul_ps(x2, x);
259
260 // inner = sqrt(2/pi) * (x + 0.044715 * x^3)
261 __m512 inner = _mm512_fmadd_ps(coeff_vec, x3, x);
262 inner = _mm512_mul_ps(sqrt_2_pi_vec, inner);
263
264 // result = 0.5 * x * (1 + tanh(inner))
265 __m512 tanh_val = tanh512_fast(inner);
266 __m512 one_plus_tanh = _mm512_add_ps(one_vec, tanh_val);
267 __m512 result = _mm512_mul_ps(half_vec, _mm512_mul_ps(x, one_plus_tanh));
268
269 _mm512_storeu_ps(&data[i], result);
270 }
271 // Handle remaining elements
272 for (; i < n; ++i) {
273 float x = data[i];
274 float x3 = x * x * x;
275 float inner = sqrt_2_over_pi * (x + coeff * x3);
276 data[i] = 0.5f * x * (1.0f + tanhf(inner));
277 }
278
279#elif defined(__AVX2__)
280 const __m256 sqrt_2_pi_vec = _mm256_set1_ps(sqrt_2_over_pi);
281 const __m256 coeff_vec = _mm256_set1_ps(coeff);
282 const __m256 half_vec = _mm256_set1_ps(0.5f);
283 const __m256 one_vec = _mm256_set1_ps(1.0f);
284
285 size_t i = 0;
286 for (; i + 8 <= n; i += 8) {
287 __m256 x = _mm256_loadu_ps(&data[i]);
288 __m256 x2 = _mm256_mul_ps(x, x);
289 __m256 x3 = _mm256_mul_ps(x2, x);
290
291 // inner = sqrt(2/pi) * (x + 0.044715 * x^3)
292 __m256 inner = _mm256_fmadd_ps(coeff_vec, x3, x);
293 inner = _mm256_mul_ps(sqrt_2_pi_vec, inner);
294
295 // result = 0.5 * x * (1 + tanh(inner))
296 __m256 tanh_val = tanh256_fast(inner);
297 __m256 one_plus_tanh = _mm256_add_ps(one_vec, tanh_val);
298 __m256 result = _mm256_mul_ps(half_vec, _mm256_mul_ps(x, one_plus_tanh));
299
300 _mm256_storeu_ps(&data[i], result);
301 }
302 // Handle remaining elements
303 for (; i < n; ++i) {
304 float x = data[i];
305 float x3 = x * x * x;
306 float inner = sqrt_2_over_pi * (x + coeff * x3);
307 data[i] = 0.5f * x * (1.0f + tanhf(inner));
308 }
309
310#elif defined(__AVX__)
311 // AVX1: Vectorize arithmetic, use scalar tanh
312 const __m256 sqrt_2_pi_vec = _mm256_set1_ps(sqrt_2_over_pi);
313 const __m256 coeff_vec = _mm256_set1_ps(coeff);
314 const __m256 half_vec = _mm256_set1_ps(0.5f);
315 const __m256 one_vec = _mm256_set1_ps(1.0f);
316
317 size_t i = 0;
318 float inner_arr[8] __attribute__((aligned(32)));
319 float tanh_arr[8] __attribute__((aligned(32)));
320
321 for (; i + 8 <= n; i += 8) {
322 __m256 x = _mm256_loadu_ps(&data[i]);
323 __m256 x2 = _mm256_mul_ps(x, x);
324 __m256 x3 = _mm256_mul_ps(x2, x);
325
326 // inner = sqrt(2/pi) * (x + 0.044715 * x^3)
327 __m256 coeff_x3 = _mm256_mul_ps(coeff_vec, x3);
328 __m256 inner = _mm256_mul_ps(sqrt_2_pi_vec, _mm256_add_ps(x, coeff_x3));
329
330 // Compute tanh scalarly
331 _mm256_store_ps(inner_arr, inner);
332 for (int j = 0; j < 8; ++j) {
333 tanh_arr[j] = tanhf(inner_arr[j]);
334 }
335 __m256 tanh_val = _mm256_load_ps(tanh_arr);
336
337 // result = 0.5 * x * (1 + tanh(inner))
338 __m256 one_plus_tanh = _mm256_add_ps(one_vec, tanh_val);
339 __m256 result = _mm256_mul_ps(half_vec, _mm256_mul_ps(x, one_plus_tanh));
340
341 _mm256_storeu_ps(&data[i], result);
342 }
343 // Handle remaining elements
344 for (; i < n; ++i) {
345 float x = data[i];
346 float x3 = x * x * x;
347 float inner = sqrt_2_over_pi * (x + coeff * x3);
348 data[i] = 0.5f * x * (1.0f + tanhf(inner));
349 }
350
351#else
352 // Scalar fallback
353 for (size_t i = 0; i < n; ++i) {
354 float x = data[i];
355 float x3 = x * x * x;
356 float inner = sqrt_2_over_pi * (x + coeff * x3);
357 data[i] = 0.5f * x * (1.0f + tanhf(inner));
358 }
359#endif
360}

References __attribute__().

Referenced by mlp_token_parallel().

◆ gelu_fast_inplace_bf16()

void gelu_fast_inplace_bf16 ( uint16_t *  data,
size_t  n,
float *  scratch 
)

Definition at line 31 of file gelu_kernels_bf16.c.

32{
33 if (!scratch) return;
34
35 bf16_tensor_to_float(data, scratch, n);
36 // Use exact version to avoid fast tanh approximation error accumulating
37 // with BF16 precision loss. Conversion overhead dominates anyway.
38 gelu_exact_inplace(scratch, n);
39 float_tensor_to_bf16(scratch, data, n);
40}
void gelu_exact_inplace(float *data, size_t n)

References bf16_tensor_to_float(), float_tensor_to_bf16(), and gelu_exact_inplace().

◆ gelu_ggml_inplace()

void gelu_ggml_inplace ( float *  data,
size_t  n 
)

Definition at line 753 of file gelu_kernels.c.

754{
757 for (size_t i = 0; i < n; ++i) {
758 const float x = data[i];
759 if (x <= -10.0f) {
760 data[i] = 0.0f;
761 continue;
762 }
763 if (x >= 10.0f) {
764 data[i] = x;
765 continue;
766 }
767 const ck_half x_fp16 = ck_gelu_runtime_fp32_to_fp16(x);
768 const ck_half y_fp16 = ck_gelu_runtime_table_f16[(uint16_t) x_fp16];
769 data[i] = ck_gelu_runtime_fp16_to_fp32(y_fp16);
770 }
771 return;
772 }
773
775 for (size_t i = 0; i < n; ++i) {
776 const float x = data[i];
777 if (x <= -10.0f) {
778 data[i] = 0.0f;
779 continue;
780 }
781 if (x >= 10.0f) {
782 data[i] = x;
783 continue;
784 }
785 const ck_half x_fp16 = ggml_fp32_to_fp16(x);
786 const ck_half y_fp16 = ck_gelu_ggml_table_f16[(uint16_t) x_fp16];
787 data[i] = ggml_fp16_to_fp32(y_fp16);
788 }
789}
#define ggml_fp32_to_fp16
uint16_t ck_half
#define ggml_fp16_to_fp32
static void ck_gelu_ggml_runtime_init(void)
static const ck_half * ck_gelu_runtime_table_f16
static int ck_gelu_runtime_ready
static pthread_once_t ck_gelu_ggml_table_once
static ck_gelu_ggml_fp32_to_fp16_fn ck_gelu_runtime_fp32_to_fp16
static ck_gelu_ggml_fp16_to_fp32_fn ck_gelu_runtime_fp16_to_fp32
static void ck_gelu_ggml_table_init(void)
static ck_half ck_gelu_ggml_table_f16[1u<< 16]
static pthread_once_t ck_gelu_ggml_runtime_once

References ck_gelu_ggml_runtime_init(), ck_gelu_ggml_runtime_once, ck_gelu_ggml_table_f16, ck_gelu_ggml_table_init(), ck_gelu_ggml_table_once, ck_gelu_runtime_fp16_to_fp32, ck_gelu_runtime_fp32_to_fp16, ck_gelu_runtime_ready, ck_gelu_runtime_table_f16, ggml_fp16_to_fp32, and ggml_fp32_to_fp16.

◆ gelu_ggml_native_inplace()

void gelu_ggml_native_inplace ( float *  data,
size_t  n 
)

Definition at line 741 of file gelu_kernels.c.

742{
744 for (size_t i = 0; i < n; ++i) {
745 const float x = data[i];
746 if (x <= -10.0f) data[i] = 0.0f;
747 else if (x >= 10.0f) data[i] = x;
748 else data[i] = ggml_fp16_to_fp32(
750 }
751}

References ck_gelu_ggml_table_f16, ck_gelu_ggml_table_init(), ck_gelu_ggml_table_once, ggml_fp16_to_fp32, and ggml_fp32_to_fp16.

◆ gelu_pytorch_erf_f32_inplace()

void gelu_pytorch_erf_f32_inplace ( float *  data,
size_t  n 
)

Definition at line 580 of file gelu_kernels.c.

581{
583}
void gelu_erf_fp64_f32_inplace(float *data, size_t n)

References gelu_erf_fp64_f32_inplace().

◆ gelu_pytorch_erf_sleef_bf16_storage()

void gelu_pytorch_erf_sleef_bf16_storage ( float *  data,
size_t  n 
)

Definition at line 682 of file gelu_kernels.c.

683{
684#if defined(__AVX512F__)
685 pthread_once(&ck_pytorch_sleef_once, ck_bind_pytorch_sleef);
686 if (!ck_pytorch_sleef_expf16) {
687 fprintf(stderr,
688 "[CK] PyTorch-exact BF16 GELU requires Sleef_expf16_u10; "
689 "set CK_SLEEF_LIBRARY to libtorch_cpu.so or libsleef.so\n");
690 abort();
691 }
692
693 const __m512 alpha = _mm512_set1_ps(0.70710678118654752440f);
694 const __m512 half = _mm512_set1_ps(0.5f);
695 const __m512 one = _mm512_set1_ps(1.0f);
696 const __m512 neg_zero = _mm512_set1_ps(-0.0f);
697 const __m512 p = _mm512_set1_ps(0.3275911f);
698 const __m512 p1 = _mm512_set1_ps(0.254829592f);
699 const __m512 p2 = _mm512_set1_ps(-0.284496736f);
700 const __m512 p3 = _mm512_set1_ps(1.421413741f);
701 const __m512 p4 = _mm512_set1_ps(-1.453152027f);
702 const __m512 p5 = _mm512_set1_ps(1.061405429f);
703 size_t i = 0;
704 for (; i + 16 <= n; i += 16) {
705 __m512 x = _mm512_loadu_ps(data + i);
706 __m512 erf_arg = _mm512_mul_ps(x, alpha);
707 __m512 sign = _mm512_and_ps(neg_zero, erf_arg);
708 __m512 abs_arg = _mm512_abs_ps(erf_arg);
709 __m512 t = _mm512_div_ps(one, _mm512_fmadd_ps(p, abs_arg, one));
710 __m512 r = _mm512_fmadd_ps(p5, t, p4);
711 r = _mm512_fmadd_ps(r, t, p3);
712 r = _mm512_fmadd_ps(r, t, p2);
713 r = _mm512_fmadd_ps(r, t, p1);
714 __m512 arg_sq = _mm512_mul_ps(erf_arg, erf_arg);
715 __m512 exp_neg_sq = ck_pytorch_sleef_expf16(_mm512_xor_ps(neg_zero, arg_sq));
716 __m512 neg_exp_t = _mm512_mul_ps(_mm512_xor_ps(neg_zero, exp_neg_sq), t);
717 __m512 erf_x = _mm512_xor_ps(sign, _mm512_fmadd_ps(neg_exp_t, r, one));
718 __m512 y = _mm512_mul_ps(_mm512_mul_ps(x, half), _mm512_add_ps(one, erf_x));
719 float lanes[16];
720 _mm512_storeu_ps(lanes, y);
721 for (size_t lane = 0; lane < 16; ++lane) {
722 const uint16_t input_code = float_to_bf16(data[i + lane]);
723 const uint16_t output_code = ck_pytorch_gelu_erf_bf16_edge(
724 input_code, float_to_bf16(lanes[lane]));
725 data[i + lane] = bf16_to_float(output_code);
726 }
727 }
728 for (; i < n; ++i) {
729 const float x = bf16_to_float(float_to_bf16(data[i]));
730 const float y = (x * 0.5f) * (1.0f + erff(x * 0.70710678118654752440f));
731 data[i] = bf16_to_float(float_to_bf16(y));
732 }
733#else
734 (void)data;
735 (void)n;
736 fprintf(stderr, "[CK] PyTorch-exact BF16 GELU requires an AVX-512 build\n");
737 abort();
738#endif
739}

References bf16_to_float(), and float_to_bf16().

◆ gelu_pytorch_tanh_bf16_storage()

void gelu_pytorch_tanh_bf16_storage ( float *  data,
size_t  n 
)

Definition at line 590 of file gelu_kernels.c.

591{
592 /* PyTorch's x86 BF16 kernel widens to FP32 and evaluates tanh through
593 * SLEEF's vector u10 provider. That provider saturates at this exact
594 * inner-argument boundary; libc tanhf retains a small tail and can round
595 * to a different BF16 code before the following projection. */
596 const float sleef_tanh_saturation = 8.664339742f;
597 for (size_t i = 0; i < n; ++i) {
598 const float x = bf16_to_float(float_to_bf16(data[i]));
599 const float x3 = x * x * x;
600 const float inner = 0.7978845608f * (x + 0.044715f * x3);
601 const float tanh_inner = fabsf(inner) > sleef_tanh_saturation
602 ? copysignf(1.0f, inner)
603 : tanhf(inner);
604 const float output = 0.5f * x * (1.0f + tanh_inner);
605 data[i] = bf16_to_float(float_to_bf16(output));
606 }
607}

References bf16_to_float(), and float_to_bf16().

◆ gemm_avx512_parallel()

void gemm_avx512_parallel ( const float *  A,
const float *  B,
const float *  bias,
float *  C,
int  M,
int  N,
int  K 
)

Definition at line 230 of file gemm_kernels.c.

235{
237 gemm_naive_serial_float(A, B, bias, C, M, N, K);
238 return;
239 }
240#if defined(__AVX512F__)
241#pragma omp parallel for
242 for (int i = 0; i < M; i++) {
243 for (int j = 0; j < N; j++) {
244 __m512 sum_vec = _mm512_setzero_ps();
245 int k;
246 for (k = 0; k <= K - 16; k += 16) {
247 __m512 a_vec = _mm512_loadu_ps(&A[i * K + k]);
248 __m512 b_vec = _mm512_loadu_ps(&B[j * K + k]);
249 sum_vec = _mm512_fmadd_ps(a_vec, b_vec, sum_vec);
250 }
251 float sum = _mm512_reduce_add_ps(sum_vec);
252 for (; k < K; k++) {
253 sum += A[i * K + k] * B[j * K + k];
254 }
255 float bias_val = bias ? bias[j] : 0.0f;
256 C[i * N + j] = sum + bias_val;
257 }
258 }
259#elif defined(__AVX__)
260 // AVX1 path: 256-bit vectors, no FMA (use mul + add)
261#pragma omp parallel for
262 for (int i = 0; i < M; i++) {
263 for (int j = 0; j < N; j++) {
264 __m256 sum_vec = _mm256_setzero_ps();
265 int k;
266 for (k = 0; k <= K - 8; k += 8) {
267 __m256 a_vec = _mm256_loadu_ps(&A[i * K + k]);
268 __m256 b_vec = _mm256_loadu_ps(&B[j * K + k]);
269 __m256 prod = _mm256_mul_ps(a_vec, b_vec);
270 sum_vec = _mm256_add_ps(sum_vec, prod);
271 }
272 float sum = hsum256_ps(sum_vec);
273 for (; k < K; k++) {
274 sum += A[i * K + k] * B[j * K + k];
275 }
276 float bias_val = bias ? bias[j] : 0.0f;
277 C[i * N + j] = sum + bias_val;
278 }
279 }
280#else
281 gemm_naive_parallel(A, B, bias, C, M, N, K);
282#endif
283}
void gemm_naive_parallel(const float *A, const float *B, const float *bias, float *C, int M, int N, int K)
static void gemm_naive_serial_float(const float *A, const float *B, const float *bias, float *C, int M, int N, int K)

References C, ck_strict_parity_enabled(), gemm_naive_parallel(), and gemm_naive_serial_float().

◆ gemm_backward_bf16_mixed()

void gemm_backward_bf16_mixed ( const uint16_t *  d_output,
const uint16_t *  input,
const uint16_t *  weight,
float *  d_input,
float *  d_weight,
float *  d_bias,
int  tokens,
int  in_dim,
int  out_dim 
)

Definition at line 2043 of file gemm_kernels_bf16.c.

2052{
2053 if (!d_output || !input || !weight || tokens <= 0 || in_dim <= 0 || out_dim <= 0) {
2054 return;
2055 }
2056
2057 if (d_input) {
2058 for (int t = 0; t < tokens; ++t) {
2059 for (int i = 0; i < in_dim; ++i) {
2060 float sum = 0.0f;
2061 for (int o = 0; o < out_dim; ++o) {
2062 const float dy = bf16_to_float(d_output[(size_t)t * (size_t)out_dim + (size_t)o]);
2063 const float w = bf16_to_float(weight[(size_t)o * (size_t)in_dim + (size_t)i]);
2064 sum += dy * w;
2065 }
2066 d_input[(size_t)t * (size_t)in_dim + (size_t)i] = sum;
2067 }
2068 }
2069 }
2070
2071 if (d_weight) {
2072 for (int o = 0; o < out_dim; ++o) {
2073 for (int i = 0; i < in_dim; ++i) {
2074 float sum = 0.0f;
2075 for (int t = 0; t < tokens; ++t) {
2076 const float dy = bf16_to_float(d_output[(size_t)t * (size_t)out_dim + (size_t)o]);
2077 const float x = bf16_to_float(input[(size_t)t * (size_t)in_dim + (size_t)i]);
2078 sum += dy * x;
2079 }
2080 d_weight[(size_t)o * (size_t)in_dim + (size_t)i] = sum;
2081 }
2082 }
2083 }
2084
2085 if (d_bias) {
2086 for (int o = 0; o < out_dim; ++o) {
2087 float sum = 0.0f;
2088 for (int t = 0; t < tokens; ++t) {
2089 sum += bf16_to_float(d_output[(size_t)t * (size_t)out_dim + (size_t)o]);
2090 }
2091 d_bias[o] = sum;
2092 }
2093 }
2094}

References bf16_to_float().

◆ gemm_backward_f32_train_parallel_dispatch()

void gemm_backward_f32_train_parallel_dispatch ( const float *  d_output,
const float *  input,
const float *  W,
float *  d_input,
float *  d_W,
float *  d_b,
int  T,
int  aligned_in,
int  aligned_out,
int  num_threads 
)

Definition at line 610 of file ck_parallel_train.c.

619 {
620 if (!d_output || !input || !W || !d_input || !d_W) {
621 return;
622 }
623 if (T <= 0 || aligned_in <= 0 || aligned_out <= 0) {
624 return;
625 }
626
627 ck_threadpool_t *pool = ck_threadpool_global();
628 int nth = pool ? ck_threadpool_n_threads(pool) : 1;
629 if (num_threads > 0 && num_threads < nth) {
630 nth = num_threads;
631 }
632
633 if (!pool || nth <= 1) {
634 ck_train_gemm_backward_serial(d_output, input, W, d_input, d_W, d_b, T, aligned_in, aligned_out);
635 return;
636 }
637
638 /* T=1 is the dominant runtime shape in generated train microsteps.
639 * Use vectorized d_input and parallel outer-product for dW/db. */
640 if (T == 1) {
641 gemm_nn_simd(d_output, W, NULL, d_input, 1, aligned_in, aligned_out);
642
643 const size_t outer_work = (size_t)aligned_out * (size_t)aligned_in;
644 if (aligned_out < nth * 2 || aligned_in < 64 || outer_work < (size_t)524288) {
645 ck_train_outer_t1_compute_range(d_output, input, d_W, d_b, 0, aligned_out, aligned_in);
646 } else {
647 const int active_outer = ck_train_pick_active_threads(nth, (size_t)aligned_out, (size_t)64);
648 ck_train_outer_t1_args_t t1_args = {
649 .d_output = d_output,
650 .input = input,
651 .d_W = d_W,
652 .d_b = d_b,
653 .aligned_in = aligned_in,
654 .aligned_out = aligned_out,
655 };
656 if (active_outer <= 1) {
657 ck_train_outer_t1_compute_range(d_output, input, d_W, d_b, 0, aligned_out, aligned_in);
658 } else {
659 ck_threadpool_dispatch_n(pool, active_outer, ck_train_outer_t1_work, &t1_args);
660 }
661 }
662 return;
663 }
664
665 const size_t nn_work = (size_t)T * (size_t)aligned_in * (size_t)aligned_out;
666 const size_t tn_work = (size_t)aligned_out * (size_t)aligned_in * (size_t)T;
667 if ((T < 2 && aligned_out < nth * 2) || (nn_work < (size_t)131072 && tn_work < (size_t)131072)) {
668 ck_train_gemm_backward_serial(d_output, input, W, d_input, d_W, d_b, T, aligned_in, aligned_out);
669 return;
670 }
671
672 ck_train_gemm_backward_args_t bw_args = {
673 .d_output = d_output,
674 .input = input,
675 .W = W,
676 .d_input = d_input,
677 .d_W = d_W,
678 .d_b = d_b,
679 .T = T,
680 .aligned_in = aligned_in,
681 .aligned_out = aligned_out,
682 };
683 {
684 const size_t bw_rows = (size_t)aligned_out > (size_t)T ? (size_t)aligned_out : (size_t)T;
685 const int active_bw = ck_train_pick_active_threads(nth, bw_rows, (size_t)64);
686 if (active_bw <= 1) {
687 ck_train_gemm_backward_serial(d_output, input, W, d_input, d_W, d_b, T, aligned_in, aligned_out);
688 } else {
689 ck_threadpool_dispatch_n(pool, active_bw, ck_train_gemm_backward_work, &bw_args);
690 }
691 }
692}
static void ck_train_outer_t1_compute_range(const float *d_output, const float *input, float *d_W, float *d_b, int out_start, int out_end, int aligned_in)
static void ck_train_gemm_backward_serial(const float *d_output, const float *input, const float *W, float *d_input, float *d_W, float *d_b, int T, int aligned_in, int aligned_out)
static int ck_train_pick_active_threads(int nth, size_t work_items, size_t min_chunk)
static void ck_train_gemm_backward_work(int ith, int nth, void *argp)
static void ck_train_outer_t1_work(int ith, int nth, void *argp)

References ck_threadpool_dispatch_n(), ck_threadpool_global(), ck_threadpool_n_threads(), ck_train_gemm_backward_serial(), ck_train_gemm_backward_work(), ck_train_outer_t1_compute_range(), ck_train_outer_t1_work(), ck_train_pick_active_threads(), and gemm_nn_simd().

◆ gemm_backward_f32_train_parallel_dispatch_v2()

void gemm_backward_f32_train_parallel_dispatch_v2 ( const float *  d_output,
const float *  input,
const float *  W,
float *  d_input,
float *  d_W,
float *  d_b,
int  T,
int  aligned_in,
int  aligned_out,
int  num_threads 
)

Definition at line 699 of file ck_parallel_train.c.

708 {
709 if (!d_output || !input || !W || !d_input || !d_W) {
710 return;
711 }
712 if (T <= 0 || aligned_in <= 0 || aligned_out <= 0) {
713 return;
714 }
715
716 ck_threadpool_t *pool = ck_threadpool_global();
717 int nth = pool ? ck_threadpool_n_threads(pool) : 1;
718 if (num_threads > 0 && num_threads < nth) {
719 nth = num_threads;
720 }
721
722 if (!pool || nth <= 1) {
723 ck_train_gemm_backward_serial(d_output, input, W, d_input, d_W, d_b, T, aligned_in, aligned_out);
724 return;
725 }
726
727 if (T == 1) {
728 const size_t nn_work = (size_t)aligned_in * (size_t)aligned_out;
729 if (aligned_in >= nth * 32 && nn_work >= (size_t)131072) {
730 const int active_nn = ck_train_pick_active_threads(nth, (size_t)aligned_in, (size_t)64);
731 ck_train_gemm_nn_args_t nn_args = {
732 .A = d_output,
733 .B = W,
734 .bias = NULL,
735 .C = d_input,
736 .M = 1,
737 .N = aligned_in,
738 .K = aligned_out,
739 .split_n = 1,
740 };
741 if (active_nn <= 1) {
742 gemm_nn_simd(d_output, W, NULL, d_input, 1, aligned_in, aligned_out);
743 } else {
744 ck_threadpool_dispatch_n(pool, active_nn, ck_train_gemm_nn_work, &nn_args);
745 }
746 } else {
747 gemm_nn_simd(d_output, W, NULL, d_input, 1, aligned_in, aligned_out);
748 }
749
750 const size_t outer_work = (size_t)aligned_out * (size_t)aligned_in;
751 if (aligned_out >= nth && outer_work >= (size_t)131072) {
752 const int active_outer = ck_train_pick_active_threads(nth, (size_t)aligned_out, (size_t)64);
753 ck_train_outer_t1_args_t t1_args = {
754 .d_output = d_output,
755 .input = input,
756 .d_W = d_W,
757 .d_b = d_b,
758 .aligned_in = aligned_in,
759 .aligned_out = aligned_out,
760 };
761 if (active_outer <= 1) {
762 ck_train_outer_t1_compute_range(d_output, input, d_W, d_b, 0, aligned_out, aligned_in);
763 } else {
764 ck_threadpool_dispatch_n(pool, active_outer, ck_train_outer_t1_work, &t1_args);
765 }
766 } else {
767 ck_train_outer_t1_compute_range(d_output, input, d_W, d_b, 0, aligned_out, aligned_in);
768 }
769 return;
770 }
771
772 const size_t nn_work = (size_t)T * (size_t)aligned_in * (size_t)aligned_out;
773 const size_t tn_work = (size_t)aligned_out * (size_t)aligned_in * (size_t)T;
774 if ((T < nth && aligned_out < nth) || (nn_work < (size_t)131072 && tn_work < (size_t)131072)) {
775 ck_train_gemm_backward_serial(d_output, input, W, d_input, d_W, d_b, T, aligned_in, aligned_out);
776 return;
777 }
778
779 ck_train_gemm_backward_args_t bw_args = {
780 .d_output = d_output,
781 .input = input,
782 .W = W,
783 .d_input = d_input,
784 .d_W = d_W,
785 .d_b = d_b,
786 .T = T,
787 .aligned_in = aligned_in,
788 .aligned_out = aligned_out,
789 };
790 {
791 const size_t bw_rows = (size_t)aligned_out > (size_t)T ? (size_t)aligned_out : (size_t)T;
792 const int active_bw = ck_train_pick_active_threads(nth, bw_rows, (size_t)64);
793 if (active_bw <= 1) {
794 ck_train_gemm_backward_serial(d_output, input, W, d_input, d_W, d_b, T, aligned_in, aligned_out);
795 } else {
796 ck_threadpool_dispatch_n(pool, active_bw, ck_train_gemm_backward_work, &bw_args);
797 }
798 }
799}
static void ck_train_gemm_nn_work(int ith, int nth, void *argp)

References ck_threadpool_dispatch_n(), ck_threadpool_global(), ck_threadpool_n_threads(), ck_train_gemm_backward_serial(), ck_train_gemm_backward_work(), ck_train_gemm_nn_work(), ck_train_outer_t1_compute_range(), ck_train_outer_t1_work(), ck_train_pick_active_threads(), and gemm_nn_simd().

◆ gemm_bias_gelu_fused()

void gemm_bias_gelu_fused ( const float *  A,
const float *  B,
const float *  bias,
float *  C,
int  M,
int  N,
int  K 
)

Definition at line 131 of file gemm_fused_kernels.c.

136{
137#if defined(__AVX__)
138#pragma omp parallel for
139 for (int i = 0; i < M; i++) {
140 for (int j = 0; j < N; j++) {
141 __m256 sum_vec = _mm256_setzero_ps();
142 int k;
143 for (k = 0; k <= K - 8; k += 8) {
144 __m256 a_vec = _mm256_loadu_ps(&A[i * K + k]);
145 __m256 b_vec = _mm256_loadu_ps(&B[j * K + k]);
146 __m256 prod = _mm256_mul_ps(a_vec, b_vec);
147 sum_vec = _mm256_add_ps(sum_vec, prod);
148 }
149 float sum = hsum256_ps_fused(sum_vec);
150 for (; k < K; k++) {
151 sum += A[i * K + k] * B[j * K + k];
152 }
153 sum += bias[j];
154 C[i * N + j] = fast_gelu_scalar(sum);
155 }
156 }
157#else
158#pragma omp parallel for
159 for (int i = 0; i < M; i++) {
160 for (int j = 0; j < N; j++) {
161 float sum = 0.0f;
162 for (int k = 0; k < K; k++) {
163 sum += A[i * K + k] * B[j * K + k];
164 }
165 sum += bias[j];
166 C[i * N + j] = fast_gelu_scalar(sum);
167 }
168 }
169#endif
170}
static float fast_gelu_scalar(float x)

References C, and fast_gelu_scalar().

◆ gemm_bias_relu_fused()

void gemm_bias_relu_fused ( const float *  A,
const float *  B,
const float *  bias,
float *  C,
int  M,
int  N,
int  K 
)

Definition at line 84 of file gemm_fused_kernels.c.

89{
90#if defined(__AVX__)
91#pragma omp parallel for
92 for (int i = 0; i < M; i++) {
93 for (int j = 0; j < N; j++) {
94 __m256 sum_vec = _mm256_setzero_ps();
95 int k;
96 for (k = 0; k <= K - 8; k += 8) {
97 __m256 a_vec = _mm256_loadu_ps(&A[i * K + k]);
98 __m256 b_vec = _mm256_loadu_ps(&B[j * K + k]);
99 __m256 prod = _mm256_mul_ps(a_vec, b_vec);
100 sum_vec = _mm256_add_ps(sum_vec, prod);
101 }
102 float sum = hsum256_ps_fused(sum_vec);
103 for (; k < K; k++) {
104 sum += A[i * K + k] * B[j * K + k];
105 }
106 // Fused: add bias and ReLU while still in register
107 sum += bias[j];
108 C[i * N + j] = sum > 0.0f ? sum : 0.0f;
109 }
110 }
111#else
112#pragma omp parallel for
113 for (int i = 0; i < M; i++) {
114 for (int j = 0; j < N; j++) {
115 float sum = 0.0f;
116 for (int k = 0; k < K; k++) {
117 sum += A[i * K + k] * B[j * K + k];
118 }
119 sum += bias[j];
120 C[i * N + j] = sum > 0.0f ? sum : 0.0f;
121 }
122 }
123#endif
124}

References C.

◆ gemm_bias_silu_fused()

void gemm_bias_silu_fused ( const float *  A,
const float *  B,
const float *  bias,
float *  C,
int  M,
int  N,
int  K 
)

Definition at line 177 of file gemm_fused_kernels.c.

182{
183#if defined(__AVX__)
184#pragma omp parallel for
185 for (int i = 0; i < M; i++) {
186 for (int j = 0; j < N; j++) {
187 __m256 sum_vec = _mm256_setzero_ps();
188 int k;
189 for (k = 0; k <= K - 8; k += 8) {
190 __m256 a_vec = _mm256_loadu_ps(&A[i * K + k]);
191 __m256 b_vec = _mm256_loadu_ps(&B[j * K + k]);
192 __m256 prod = _mm256_mul_ps(a_vec, b_vec);
193 sum_vec = _mm256_add_ps(sum_vec, prod);
194 }
195 float sum = hsum256_ps_fused(sum_vec);
196 for (; k < K; k++) {
197 sum += A[i * K + k] * B[j * K + k];
198 }
199 sum += bias[j];
200 // SiLU: x * sigmoid(x)
201 float sig = 1.0f / (1.0f + expf(-sum));
202 C[i * N + j] = sum * sig;
203 }
204 }
205#else
206#pragma omp parallel for
207 for (int i = 0; i < M; i++) {
208 for (int j = 0; j < N; j++) {
209 float sum = 0.0f;
210 for (int k = 0; k < K; k++) {
211 sum += A[i * K + k] * B[j * K + k];
212 }
213 sum += bias[j];
214 float sig = 1.0f / (1.0f + expf(-sum));
215 C[i * N + j] = sum * sig;
216 }
217 }
218#endif
219}

References C.

◆ gemm_blocked_serial()

void gemm_blocked_serial ( const float *  A,
const float *  B,
const float *  bias,
float *  C,
int  M,
int  N,
int  K 
)

Definition at line 849 of file gemm_kernels.c.

854{
855 // Ensure threads are initialized (auto-detects on first call)
856 (void)ck_get_num_threads();
857
859 gemm_naive_serial_float(A, B, bias, C, M, N, K);
860 return;
861 }
862
863 // Decode-time matvec (M=1) is extremely common and benefits from parallelism over N.
864 // Lower threshold to parallelize more ops; OpenMP overhead is ~1-2μs per barrier.
865 // For N*K >= 64K elements, parallel is worthwhile.
866 if (M == 1 && (size_t)N * (size_t)K >= 65536) {
867 gemm_nt_matvec_parallel(A, B, bias, C, N, K);
868 return;
869 }
870
871 /*
872 * Use gemm_microkernel for large matrices - it uses MKL/oneDNN when available,
873 * which is substantially faster than our hand-written SIMD kernels.
874 * B is stored as [N x K] (transposed), so we pass B_transposed=1.
875 * Note: Use threshold of 32 to avoid numerical precision issues with small matrices.
876 */
877 if (M >= 32 && N >= 32 && K >= 32) {
878 gemm_microkernel(A, B, C, M, N, K, 1); // B_transposed=1
879 ck_gemm_add_bias(C, bias, M, N);
880 return;
881 }
882#if defined(__AVX512F__)
883 const int block_size = 64;
884#elif defined(__AVX__)
885 const int block_size = 32;
886#else
887 const int block_size = 32;
888#endif
889 for (int i = 0; i < M; i++) {
890 for (int j = 0; j < N; j++) {
891 C[i * N + j] = bias ? bias[j] : 0.0f;
892 }
893 }
894 for (int ii = 0; ii < M; ii += block_size) {
895 for (int jj = 0; jj < N; jj += block_size) {
896 for (int kk = 0; kk < K; kk += block_size) {
897 int i_end = ck_min(ii + block_size, M);
898 int j_end = ck_min(jj + block_size, N);
899 int k_end = ck_min(kk + block_size, K);
900
901 for (int i = ii; i < i_end; i++) {
902 for (int j = jj; j < j_end; j++) {
903#if defined(__AVX512F__)
904 __m512 sum_vec = _mm512_setzero_ps();
905 int k;
906 for (k = kk; k <= k_end - 16; k += 16) {
907 __m512 a_vec = _mm512_loadu_ps(&A[i * K + k]);
908 __m512 b_vec = _mm512_loadu_ps(&B[j * K + k]);
909 sum_vec = _mm512_fmadd_ps(a_vec, b_vec, sum_vec);
910 }
911 float partial_sum = _mm512_reduce_add_ps(sum_vec);
912 for (; k < k_end; k++) {
913 partial_sum += A[i * K + k] * B[j * K + k];
914 }
915#elif defined(__AVX__)
916 __m256 sum_vec = _mm256_setzero_ps();
917 int k;
918 for (k = kk; k <= k_end - 8; k += 8) {
919 __m256 a_vec = _mm256_loadu_ps(&A[i * K + k]);
920 __m256 b_vec = _mm256_loadu_ps(&B[j * K + k]);
921 __m256 prod = _mm256_mul_ps(a_vec, b_vec);
922 sum_vec = _mm256_add_ps(sum_vec, prod);
923 }
924 float partial_sum = hsum256_ps(sum_vec);
925 for (; k < k_end; k++) {
926 partial_sum += A[i * K + k] * B[j * K + k];
927 }
928#else
929 float partial_sum = 0.0f;
930 for (int k = kk; k < k_end; k++) {
931 partial_sum += A[i * K + k] * B[j * K + k];
932 }
933#endif
934 C[i * N + j] += partial_sum;
935 }
936 }
937 }
938 }
939 }
940}
void gemm_microkernel(const float *A, const float *B, float *C, int M, int N, int K, int B_transposed)
static int ck_min(int a, int b)
static void gemm_nt_matvec_parallel(const float *A, const float *B, const float *bias, float *C, int N, int K)
static void ck_gemm_add_bias(float *C, const float *bias, int M, int N)

References C, ck_gemm_add_bias(), ck_get_num_threads(), ck_min(), ck_strict_parity_enabled(), gemm_microkernel(), gemm_naive_serial_float(), and gemm_nt_matvec_parallel().

Referenced by ck_attention_project_head_major(), ck_gemm_nt_quant(), ck_mlp_swiglu_forward(), ck_mlp_swiglu_forward_fused_token(), ck_qkv_project_head_major(), ck_qkv_project_head_major_token(), ck_train_gemm_work(), gemm_blocked_serial_train_parallel_dispatch(), mlp_token_parallel(), and mlp_token_parallel_exact().

◆ gemm_blocked_serial_bf16()

void gemm_blocked_serial_bf16 ( const uint16_t *  A,
const uint16_t *  B,
const uint16_t *  bias,
uint16_t *  C,
int  M,
int  N,
int  K 
)

Definition at line 424 of file gemm_kernels_bf16.c.

429{
430 if (!A || !B || !C || M <= 0 || N <= 0 || K <= 0) {
431 return;
432 }
433
434#if HAVE_NATIVE_BF16
435 /* Native BF16 instructions available (Ice Lake / Sapphire Rapids+) */
436 gemm_bf16_native(A, B, bias, C, M, N, K);
437#elif defined(__AVX512F__)
438 /* Use AVX-512F with software BF16 conversion */
439 if (M * N > 4096) {
440 gemm_bf16_blocked_avx512(A, B, bias, C, M, N, K);
441 } else {
442 gemm_bf16_avx512(A, B, bias, C, M, N, K);
443 }
444#else
445 /* Scalar fallback */
446 gemm_bf16_scalar(A, B, bias, C, M, N, K);
447#endif
448}

References C.

◆ gemm_blocked_serial_train_parallel_dispatch()

void gemm_blocked_serial_train_parallel_dispatch ( const float *  A,
const float *  B,
const float *  bias,
float *  C,
int  M,
int  N,
int  K 
)

Definition at line 167 of file ck_parallel_train.c.

173 {
174 if (!A || !B || !C || M <= 0 || N <= 0 || K <= 0) {
175 return;
176 }
177
178 ck_threadpool_t *pool = ck_threadpool_global();
179 const int nth = pool ? ck_threadpool_n_threads(pool) : 1;
180
181 /* Keep small shapes on serial path to avoid dispatch overhead. */
182 const size_t work = (size_t)M * (size_t)N * (size_t)K;
183 if (!pool || nth <= 1 || work < (size_t)131072) {
184 gemm_blocked_serial(A, B, bias, C, M, N, K);
185 return;
186 }
187
188 int split_n = 0;
189 int active_nth = nth;
190 if (M == 1) {
191 /* Tensor-parallel decode-style split only when each worker has enough columns. */
192 const int cols_per_worker = (N + nth - 1) / nth;
193 if (cols_per_worker >= 256 && K >= 512 && work >= (size_t)2097152) {
194 split_n = 1;
195 } else {
196 gemm_blocked_serial(A, B, bias, C, M, N, K);
197 return;
198 }
199 } else {
200 /* Row split for prefill/train batches with coarser chunks. */
201 active_nth = M / 2;
202 if (active_nth > nth) {
203 active_nth = nth;
204 }
205 if (active_nth <= 1) {
206 gemm_blocked_serial(A, B, bias, C, M, N, K);
207 return;
208 }
209 }
210
211 ck_train_gemm_args_t args = {
212 .A = A,
213 .B = B,
214 .bias = bias,
215 .C = C,
216 .M = M,
217 .N = N,
218 .K = K,
219 .split_n = split_n,
220 };
221
222 ck_threadpool_dispatch_n(pool, active_nth, ck_train_gemm_work, &args);
223}
static void ck_train_gemm_work(int ith, int nth, void *argp)
void gemm_blocked_serial(const float *A, const float *B, const float *bias, float *C, int M, int N, int K)

References C, ck_threadpool_dispatch_n(), ck_threadpool_global(), ck_threadpool_n_threads(), ck_train_gemm_work(), and gemm_blocked_serial().

◆ gemm_fine_grained_parallel()

void gemm_fine_grained_parallel ( const float *  A,
const float *  B,
const float *  bias,
float *  C,
int  M,
int  N,
int  K 
)

Definition at line 286 of file gemm_kernels.c.

291{
293 gemm_naive_serial_float(A, B, bias, C, M, N, K);
294 return;
295 }
296#if defined(__AVX512F__)
297 const int block_size = 64;
298#pragma omp parallel for
299 for (int i = 0; i < M; i++) {
300 for (int j = 0; j < N; j++) {
301 C[i * N + j] = bias ? bias[j] : 0.0f;
302 }
303 }
304#pragma omp parallel for collapse(3)
305 for (int ii = 0; ii < M; ii += block_size) {
306 for (int jj = 0; jj < N; jj += block_size) {
307 for (int kk = 0; kk < K; kk += block_size) {
308 int i_end = ck_min(ii + block_size, M);
309 int j_end = ck_min(jj + block_size, N);
310 int k_end = ck_min(kk + block_size, K);
311
312 for (int i = ii; i < i_end; i++) {
313 for (int j = jj; j < j_end; j++) {
314 __m512 sum_vec = _mm512_setzero_ps();
315 int k;
316 for (k = kk; k <= k_end - 16; k += 16) {
317 __m512 a_vec = _mm512_loadu_ps(&A[i * K + k]);
318 __m512 b_vec = _mm512_loadu_ps(&B[j * K + k]);
319 sum_vec = _mm512_fmadd_ps(a_vec, b_vec, sum_vec);
320 }
321 float partial_sum = _mm512_reduce_add_ps(sum_vec);
322 for (; k < k_end; k++) {
323 partial_sum += A[i * K + k] * B[j * K + k];
324 }
325#pragma omp atomic
326 C[i * N + j] += partial_sum;
327 }
328 }
329 }
330 }
331 }
332#elif defined(__AVX__)
333 // AVX1 cache-blocked version
334 const int block_size = 32; // Smaller block for L1 cache
335#pragma omp parallel for
336 for (int i = 0; i < M; i++) {
337 for (int j = 0; j < N; j++) {
338 C[i * N + j] = bias ? bias[j] : 0.0f;
339 }
340 }
341#pragma omp parallel for collapse(3)
342 for (int ii = 0; ii < M; ii += block_size) {
343 for (int jj = 0; jj < N; jj += block_size) {
344 for (int kk = 0; kk < K; kk += block_size) {
345 int i_end = ck_min(ii + block_size, M);
346 int j_end = ck_min(jj + block_size, N);
347 int k_end = ck_min(kk + block_size, K);
348
349 for (int i = ii; i < i_end; i++) {
350 for (int j = jj; j < j_end; j++) {
351 __m256 sum_vec = _mm256_setzero_ps();
352 int k;
353 for (k = kk; k <= k_end - 8; k += 8) {
354 __m256 a_vec = _mm256_loadu_ps(&A[i * K + k]);
355 __m256 b_vec = _mm256_loadu_ps(&B[j * K + k]);
356 __m256 prod = _mm256_mul_ps(a_vec, b_vec);
357 sum_vec = _mm256_add_ps(sum_vec, prod);
358 }
359 float partial_sum = hsum256_ps(sum_vec);
360 for (; k < k_end; k++) {
361 partial_sum += A[i * K + k] * B[j * K + k];
362 }
363#pragma omp atomic
364 C[i * N + j] += partial_sum;
365 }
366 }
367 }
368 }
369 }
370#else
371 gemm_naive_parallel(A, B, bias, C, M, N, K);
372#endif
373}

References C, ck_min(), ck_strict_parity_enabled(), gemm_naive_parallel(), and gemm_naive_serial_float().

◆ gemm_microkernel()

void gemm_microkernel ( const float *  A,
const float *  B,
float *  C,
int  M,
int  N,
int  K,
int  B_transposed 
)

Definition at line 1134 of file gemm_microkernel.c.

1141{
1142 if (B_transposed) {
1143 gemm_microkernel_blocked_bt(A, B, C, M, N, K);
1144 } else {
1145 // Use packed version for large matrices
1146 if (M >= PACK_THRESHOLD && N >= PACK_THRESHOLD && K >= PACK_THRESHOLD) {
1147 gemm_microkernel_packed(A, B, C, M, N, K);
1148 } else {
1149 gemm_microkernel_blocked(A, B, C, M, N, K);
1150 }
1151 }
1152}
#define PACK_THRESHOLD
void gemm_microkernel_blocked(const float *A, const float *B, float *C, int M, int N, int K)
void gemm_microkernel_blocked_bt(const float *A, const float *B, float *C, int M, int N, int K)
void gemm_microkernel_packed(const float *A, const float *B, float *C, int M, int N, int K)

References C, gemm_microkernel_blocked(), gemm_microkernel_blocked_bt(), gemm_microkernel_packed(), and PACK_THRESHOLD.

Referenced by gemm_blocked_serial().

◆ gemm_microkernel_blocked()

void gemm_microkernel_blocked ( const float *  A,
const float *  B,
float *  C,
int  M,
int  N,
int  K 
)

Definition at line 934 of file gemm_microkernel.c.

940{
941 const int mr = MR;
942 const int nr = NR;
943
944 // Use sequential version for small matrices to avoid OpenMP overhead
945 // Threshold tuned for typical 4-8 core systems
946 if ((size_t)M * N * K <= 512ULL * 512 * 512) {
947 gemm_microkernel_sequential(A, B, C, M, N, K);
948 return;
949 }
950
951 // Initialize thread count to physical cores (once)
953
954 // Zero output first
955 #pragma omp parallel for schedule(static)
956 for (int i = 0; i < M; i++) {
957 memset(&C[i * N], 0, N * sizeof(float));
958 }
959
960 // Block over K (outermost - for accumulation across all threads)
961 for (int k0 = 0; k0 < K; k0 += KC) {
962 int kb = (k0 + KC <= K) ? KC : (K - k0);
963 int first_k = (k0 == 0);
964
965 // Parallelize over M rows - each thread gets a chunk of M
966 // This gives better cache locality than tile-level parallelism
967 #pragma omp parallel for schedule(static)
968 for (int m0 = 0; m0 < M; m0 += mr) {
969 int mr_actual = (m0 + mr <= M) ? mr : (M - m0);
970
971 // Each thread processes all N tiles for its M rows
972 for (int n0 = 0; n0 < N; n0 += nr) {
973 int nr_actual = (n0 + nr <= N) ? nr : (N - n0);
974
975 const float *A_tile = &A[m0 * K + k0];
976 const float *B_tile = &B[k0 * N + n0];
977 float *C_tile = &C[m0 * N + n0];
978
979 if (mr_actual == mr && nr_actual == nr) {
980#if defined(__AVX512F__)
981 gemm_microkernel_6x32_avx512(kb, A_tile, K, B_tile, N, C_tile, N, first_k);
982#elif defined(__FMA__)
983 gemm_microkernel_6x16_avx(kb, A_tile, K, B_tile, N, C_tile, N, first_k);
984#elif defined(__AVX__)
985 gemm_microkernel_4x16_avx(kb, A_tile, K, B_tile, N, C_tile, N, first_k);
986#else
987 gemm_microkernel_edge(mr_actual, nr_actual, kb, A_tile, K, B_tile, N, C_tile, N, first_k);
988#endif
989 } else {
990 gemm_microkernel_edge(mr_actual, nr_actual, kb, A_tile, K, B_tile, N, C_tile, N, first_k);
991 }
992 }
993 }
994 }
995}
static void gemm_microkernel_edge(int m, int n, int K, const float *A, int lda, const float *B, int ldb, float *C, int ldc, int first_k)
static void gemm_microkernel_sequential(const float *A, const float *B, float *C, int M, int N, int K)
static void gemm_init_threads(void)
#define KC
#define MR
#define NR

References C, gemm_init_threads(), gemm_microkernel_edge(), gemm_microkernel_sequential(), KC, MR, and NR.

Referenced by gemm_microkernel(), and gemm_microkernel_packed().

◆ gemm_microkernel_blocked_bt()

void gemm_microkernel_blocked_bt ( const float *  A,
const float *  B,
float *  C,
int  M,
int  N,
int  K 
)

Definition at line 1058 of file gemm_microkernel.c.

1064{
1065 // Zero output first
1066 #pragma omp parallel for schedule(static)
1067 for (int i = 0; i < M; i++) {
1068 memset(&C[i * N], 0, N * sizeof(float));
1069 }
1070
1071 const int mr = MR;
1072 const int nr = NR;
1073
1074 #pragma omp parallel for schedule(dynamic) collapse(2)
1075 for (int m0 = 0; m0 < M; m0 += MC) {
1076 for (int n0 = 0; n0 < N; n0 += NC) {
1077 int mb = (m0 + MC <= M) ? MC : (M - m0);
1078 int nb = (n0 + NC <= N) ? NC : (N - n0);
1079
1080 for (int k0 = 0; k0 < K; k0 += KC) {
1081 int kb = (k0 + KC <= K) ? KC : (K - k0);
1082 int first_k = (k0 == 0);
1083
1084 for (int m1 = 0; m1 < mb; m1 += mr) {
1085 int mr_actual = (m1 + mr <= mb) ? mr : (mb - m1);
1086
1087 for (int n1 = 0; n1 < nb; n1 += nr) {
1088 int nr_actual = (n1 + nr <= nb) ? nr : (nb - n1);
1089
1090 const float *A_tile = &A[(m0 + m1) * K + k0];
1091 const float *B_tile = &B[(n0 + n1) * K + k0];
1092 float *C_tile = &C[(m0 + m1) * N + (n0 + n1)];
1093
1094 if (mr_actual == mr && nr_actual == nr) {
1095#if defined(__AVX512F__)
1096 gemm_microkernel_6x32_bt_avx512(kb, A_tile, K, B_tile, K, C_tile, N, first_k);
1097#else
1098 // Scalar fallback for B-transposed
1099 for (int i = 0; i < mr; i++) {
1100 for (int j = 0; j < nr; j++) {
1101 float sum = first_k ? 0.0f : C_tile[i * N + j];
1102 for (int kk = 0; kk < kb; kk++) {
1103 sum += A_tile[i * K + kk] * B_tile[j * K + kk];
1104 }
1105 C_tile[i * N + j] = sum;
1106 }
1107 }
1108#endif
1109 } else {
1110 // Edge case
1111 for (int i = 0; i < mr_actual; i++) {
1112 for (int j = 0; j < nr_actual; j++) {
1113 float sum = first_k ? 0.0f : C_tile[i * N + j];
1114 for (int kk = 0; kk < kb; kk++) {
1115 sum += A_tile[i * K + kk] * B_tile[j * K + kk];
1116 }
1117 C_tile[i * N + j] = sum;
1118 }
1119 }
1120 }
1121 }
1122 }
1123 }
1124 }
1125 }
1126}
#define NC
#define MC

References C, KC, MC, MR, NC, and NR.

Referenced by gemm_microkernel().

◆ gemm_microkernel_packed()

void gemm_microkernel_packed ( const float *  A,
const float *  B,
float *  C,
int  M,
int  N,
int  K 
)

Definition at line 840 of file gemm_microkernel.c.

846{
847 // Use tile-parallel blocked version - scales better on many-core systems
848 gemm_microkernel_blocked(A, B, C, M, N, K);
849}

References C, and gemm_microkernel_blocked().

Referenced by gemm_microkernel().

◆ gemm_naive_parallel()

void gemm_naive_parallel ( const float *  A,
const float *  B,
const float *  bias,
float *  C,
int  M,
int  N,
int  K 
)

Definition at line 206 of file gemm_kernels.c.

211{
213 gemm_naive_serial_float(A, B, bias, C, M, N, K);
214 return;
215 }
216#pragma omp parallel for
217 for (int i = 0; i < M; i++) {
218 for (int j = 0; j < N; j++) {
219 float sum = 0.0f;
220 for (int k = 0; k < K; k++) {
221 sum += A[i * K + k] * B[j * K + k];
222 }
223 float bias_val = bias ? bias[j] : 0.0f;
224 C[i * N + j] = sum + bias_val;
225 }
226 }
227}

References C, ck_strict_parity_enabled(), and gemm_naive_serial_float().

Referenced by ck_attention_project_head_major_ref(), ck_mlp_swiglu_forward_ref(), ck_qkv_project_head_major_ref(), gemm_avx512_parallel(), and gemm_fine_grained_parallel().

◆ gemm_nn_avx512()

void gemm_nn_avx512 ( const float *  A,
const float *  B,
const float *  bias,
float *  C,
int  M,
int  N,
int  K 
)

Definition at line 420 of file gemm_kernels.c.

425{
427 gemm_nn_serial_double(A, B, bias, C, M, N, K);
428 return;
429 }
430#if defined(__AVX512F__)
431 // For gemm_nn, we can't vectorize over K easily since B[k,j] has stride N.
432 // Instead, vectorize over N (output columns) when N >= 16.
433#pragma omp parallel for
434 for (int i = 0; i < M; i++) {
435 int j = 0;
436 // Process 16 output columns at a time
437 for (; j <= N - 16; j += 16) {
438 __m512 sum_vec = bias ? _mm512_loadu_ps(&bias[j]) : _mm512_setzero_ps();
439 for (int k = 0; k < K; k++) {
440 __m512 a_broadcast = _mm512_set1_ps(A[i * K + k]);
441 __m512 b_vec = _mm512_loadu_ps(&B[k * N + j]);
442 sum_vec = _mm512_fmadd_ps(a_broadcast, b_vec, sum_vec);
443 }
444 _mm512_storeu_ps(&C[i * N + j], sum_vec);
445 }
446 // Handle remaining columns
447 for (; j < N; j++) {
448 float sum = bias ? bias[j] : 0.0f;
449 for (int k = 0; k < K; k++) {
450 sum += A[i * K + k] * B[k * N + j];
451 }
452 C[i * N + j] = sum;
453 }
454 }
455#elif defined(__AVX__)
456 // AVX1: vectorize over N (8 columns at a time)
457#pragma omp parallel for
458 for (int i = 0; i < M; i++) {
459 int j = 0;
460 for (; j <= N - 8; j += 8) {
461 __m256 sum_vec = bias ? _mm256_loadu_ps(&bias[j]) : _mm256_setzero_ps();
462 for (int k = 0; k < K; k++) {
463 __m256 a_broadcast = _mm256_set1_ps(A[i * K + k]);
464 __m256 b_vec = _mm256_loadu_ps(&B[k * N + j]);
465 __m256 prod = _mm256_mul_ps(a_broadcast, b_vec);
466 sum_vec = _mm256_add_ps(sum_vec, prod);
467 }
468 _mm256_storeu_ps(&C[i * N + j], sum_vec);
469 }
470 for (; j < N; j++) {
471 float sum = bias ? bias[j] : 0.0f;
472 for (int k = 0; k < K; k++) {
473 sum += A[i * K + k] * B[k * N + j];
474 }
475 C[i * N + j] = sum;
476 }
477 }
478#else
479 gemm_nn_parallel(A, B, bias, C, M, N, K);
480#endif
481}
static void gemm_nn_serial_double(const float *A, const float *B, const float *bias, float *C, int M, int N, int K)
void gemm_nn_parallel(const float *A, const float *B, const float *bias, float *C, int M, int N, int K)

References C, ck_strict_parity_enabled(), gemm_nn_parallel(), and gemm_nn_serial_double().

Referenced by gemm_nn_simd().

◆ gemm_nn_blocked()

void gemm_nn_blocked ( const float *  A,
const float *  B,
const float *  bias,
float *  C,
int  M,
int  N,
int  K 
)

Definition at line 590 of file gemm_kernels.c.

595{
597 gemm_nn_serial_double(A, B, bias, C, M, N, K);
598 return;
599 }
600#if defined(__AVX512F__)
601 const int block_size = 64;
602#elif defined(__AVX__)
603 const int block_size = 32;
604#else
605 const int block_size = 32;
606#endif
607 // Initialize C with bias (parallelized)
608#pragma omp parallel for
609 for (int i = 0; i < M; i++) {
610 for (int j = 0; j < N; j++) {
611 C[i * N + j] = bias ? bias[j] : 0.0f;
612 }
613 }
614 // Blocked multiply-accumulate (parallelized over M blocks)
615#pragma omp parallel for
616 for (int ii = 0; ii < M; ii += block_size) {
617 for (int kk = 0; kk < K; kk += block_size) {
618 for (int jj = 0; jj < N; jj += block_size) {
619 int i_end = ck_min(ii + block_size, M);
620 int k_end = ck_min(kk + block_size, K);
621 int j_end = ck_min(jj + block_size, N);
622
623 for (int i = ii; i < i_end; i++) {
624 for (int k = kk; k < k_end; k++) {
625 float a_val = A[i * K + k];
626#if defined(__AVX512F__)
627 __m512 a_broadcast = _mm512_set1_ps(a_val);
628 int j;
629 for (j = jj; j <= j_end - 16; j += 16) {
630 __m512 b_vec = _mm512_loadu_ps(&B[k * N + j]);
631 __m512 c_vec = _mm512_loadu_ps(&C[i * N + j]);
632 c_vec = _mm512_fmadd_ps(a_broadcast, b_vec, c_vec);
633 _mm512_storeu_ps(&C[i * N + j], c_vec);
634 }
635 for (; j < j_end; j++) {
636 C[i * N + j] += a_val * B[k * N + j];
637 }
638#elif defined(__AVX__)
639 __m256 a_broadcast = _mm256_set1_ps(a_val);
640 int j;
641 for (j = jj; j <= j_end - 8; j += 8) {
642 __m256 b_vec = _mm256_loadu_ps(&B[k * N + j]);
643 __m256 c_vec = _mm256_loadu_ps(&C[i * N + j]);
644 __m256 prod = _mm256_mul_ps(a_broadcast, b_vec);
645 c_vec = _mm256_add_ps(c_vec, prod);
646 _mm256_storeu_ps(&C[i * N + j], c_vec);
647 }
648 for (; j < j_end; j++) {
649 C[i * N + j] += a_val * B[k * N + j];
650 }
651#else
652 for (int j = jj; j < j_end; j++) {
653 C[i * N + j] += a_val * B[k * N + j];
654 }
655#endif
656 }
657 }
658 }
659 }
660 }
661}

References C, ck_min(), ck_strict_parity_enabled(), and gemm_nn_serial_double().

◆ gemm_nn_parallel()

void gemm_nn_parallel ( const float *  A,
const float *  B,
const float *  bias,
float *  C,
int  M,
int  N,
int  K 
)

Definition at line 398 of file gemm_kernels.c.

403{
405 gemm_nn_serial_double(A, B, bias, C, M, N, K);
406 return;
407 }
408#pragma omp parallel for
409 for (int i = 0; i < M; i++) {
410 for (int j = 0; j < N; j++) {
411 float sum = bias ? bias[j] : 0.0f;
412 for (int k = 0; k < K; k++) {
413 sum += A[i * K + k] * B[k * N + j];
414 }
415 C[i * N + j] = sum;
416 }
417 }
418}

References C, ck_strict_parity_enabled(), and gemm_nn_serial_double().

Referenced by gemm_nn_avx512(), and gemm_nn_avx512_probe().

◆ gemm_nn_simd()

void gemm_nn_simd ( const float *  A,
const float *  B,
const float *  bias,
float *  C,
int  M,
int  N,
int  K 
)

Definition at line 577 of file gemm_kernels.c.

582{
584 gemm_nn_avx512_probe(A, B, bias, C, M, N, K);
585 return;
586 }
587 gemm_nn_avx512(A, B, bias, C, M, N, K);
588}
static int ck_gemm_nn_impl_probe_enabled(void)
void gemm_nn_avx512_probe(const float *A, const float *B, const float *bias, float *C, int M, int N, int K)
void gemm_nn_avx512(const float *A, const float *B, const float *bias, float *C, int M, int N, int K)

References C, ck_gemm_nn_impl_probe_enabled(), gemm_nn_avx512(), and gemm_nn_avx512_probe().

Referenced by fc1_backward_kernel(), fc2_backward_kernel(), gemm_backward_f32_train_parallel_dispatch(), and gemm_backward_f32_train_parallel_dispatch_v2().

◆ gemm_nt_bf16()

void gemm_nt_bf16 ( const float *  A,
const void *  B,
const float *  bias,
float *  C,
int  M,
int  N,
int  K 
)

Definition at line 748 of file gemm_kernels_bf16.c.

753{
754 if (M <= 0) return;
755 gemm_nt_bf16_row_range(A, B, bias, C, M, N, K, 0, M);
756}
void gemm_nt_bf16_row_range(const float *A, const void *B, const float *bias, float *C, int M, int N, int K, int row_begin, int row_end)

References C, and gemm_nt_bf16_row_range().

Referenced by gemm_nt_bf16_parallel_dispatch().

◆ gemm_nt_bf16_amx_bf16_storage()

void gemm_nt_bf16_amx_bf16_storage ( const float *  A,
const void *  B,
const float *  bias,
float *  C,
int  M,
int  N,
int  K 
)

Definition at line 1311 of file gemm_kernels_bf16.c.

1316{
1317 size_t input_count = 0;
1318 if (M > 0 && K > 0 && (size_t)M <= SIZE_MAX / (size_t)K) {
1319 input_count = (size_t)M * (size_t)K;
1320 }
1321 uint16_t *workspace = input_count > 0 && input_count <= SIZE_MAX / sizeof(uint16_t)
1322 ? (uint16_t *)malloc(input_count * sizeof(uint16_t))
1323 : NULL;
1324 if (!workspace) {
1325 fprintf(stderr, "HARD KERNEL CONTRACT FAULT: AMX BF16 compatibility workspace allocation failed\n");
1326 abort();
1327 }
1329 A, B, bias, C, M, N, K, workspace, input_count * sizeof(uint16_t));
1330 free(workspace);
1331}
void gemm_nt_bf16_amx_bf16_storage_workspace(const float *A, const void *B, const float *bias, float *C, int M, int N, int K, uint16_t *a_bf16, size_t a_bf16_bytes)

References C, and gemm_nt_bf16_amx_bf16_storage_workspace().

Referenced by gemm_nt_bf16_prefill_shape_safe_bf16_storage().

◆ gemm_nt_bf16_amx_bf16_storage_workspace()

void gemm_nt_bf16_amx_bf16_storage_workspace ( const float *  A,
const void *  B,
const float *  bias,
float *  C,
int  M,
int  N,
int  K,
uint16_t *  a_bf16,
size_t  a_bf16_bytes 
)

Definition at line 1258 of file gemm_kernels_bf16.c.

1265{
1266#if HAVE_AMX_BF16
1267 if (!A || !B || !C || M < 16 || N < 16 || K < 32 ||
1268 (M % 16) != 0 || (N % 16) != 0 || (K % 32) != 0) {
1269 fprintf(stderr,
1270 "HARD KERNEL CONTRACT FAULT: AMX BF16 GEMM requires non-null buffers "
1271 "and M%%16=N%%16=K%%32=0 (M=%d N=%d K=%d)\n",
1272 M, N, K);
1273 abort();
1274 }
1275 const size_t input_count = (size_t)M * K;
1276 if (!a_bf16 || input_count > SIZE_MAX / sizeof(uint16_t) ||
1277 a_bf16_bytes < input_count * sizeof(uint16_t)) {
1278 fprintf(stderr, "HARD KERNEL CONTRACT FAULT: AMX BF16 activation workspace is too small\n");
1279 abort();
1280 }
1281 ck_threadpool_t *pool = ck_threadpool_global();
1282 int active = pool ? ck_threadpool_n_threads(pool) : 1;
1283 if (active > 24) active = 24;
1284 ck_bf16_convert_args_t convert = {.src=A, .dst=a_bf16, .count=input_count};
1285 if (pool && active > 1) ck_threadpool_dispatch_n(pool, active, ck_bf16_convert_work, &convert);
1286 else ck_bf16_convert_work(0, 1, &convert);
1287 ck_gemm_bf16_amx_args_t gemm = {
1288 .A=a_bf16, .B=(const uint16_t *)B, .bias=bias, .C=C,
1289 .M=M, .N=N, .K=K, .failed=0
1290 };
1291 if (pool && active > 1) ck_threadpool_dispatch_n(pool, active, ck_gemm_bf16_amx_work, &gemm);
1292 else ck_gemm_bf16_amx_work(0, 1, &gemm);
1293 if (__atomic_load_n(&gemm.failed, __ATOMIC_RELAXED)) {
1294 fprintf(stderr, "HARD KERNEL CONTRACT FAULT: AMX tile permission request failed\n");
1295 abort();
1296 }
1297 ck_bf16_round_args_t round = {.values=C, .count=(size_t)M * N};
1298 if (pool && active > 1) ck_threadpool_dispatch_n(pool, active, ck_bf16_round_work, &round);
1299 else ck_bf16_round_work(0, 1, &round);
1300 return;
1301#else
1302 (void)A; (void)B; (void)bias; (void)C; (void)M; (void)N; (void)K;
1303 (void)a_bf16; (void)a_bf16_bytes;
1304 fprintf(stderr,
1305 "HARD KERNEL CONTRACT FAULT: gemm_nt_bf16_amx_bf16_storage was selected "
1306 "without AMX BF16 support\n");
1307 abort();
1308#endif
1309}
static void ck_bf16_convert_work(int ith, int nth, void *opaque)
static void ck_bf16_round_work(int ith, int nth, void *opaque)
static void ck_gemm_bf16_amx_work(int ith, int nth, void *opaque)

References C, ck_bf16_convert_work(), ck_bf16_round_work(), ck_gemm_bf16_amx_work(), ck_threadpool_dispatch_n(), ck_threadpool_global(), and ck_threadpool_n_threads().

Referenced by gemm_nt_bf16_amx_bf16_storage(), and gemm_nt_bf16_prefill_shape_safe_bf16_storage_workspace().

◆ gemm_nt_bf16_bf16_storage()

void gemm_nt_bf16_bf16_storage ( const float *  A,
const void *  B,
const float *  bias,
float *  C,
int  M,
int  N,
int  K 
)

Definition at line 2034 of file gemm_kernels_bf16.c.

2039{
2040 gemm_nt_bf16_bf16_storage_parallel_dispatch(A, B, bias, C, M, N, K);
2041}
void gemm_nt_bf16_bf16_storage_parallel_dispatch(const float *A, const void *B, const float *bias, float *C, int M, int N, int K)

References C, and gemm_nt_bf16_bf16_storage_parallel_dispatch().

◆ gemm_nt_bf16_bf16_storage_parallel_dispatch()

void gemm_nt_bf16_bf16_storage_parallel_dispatch ( const float *  A,
const void *  B,
const float *  bias,
float *  C,
int  M,
int  N,
int  K 
)

Definition at line 2010 of file gemm_kernels_bf16.c.

2015{
2016 ck_threadpool_t *pool = ck_threadpool_global();
2017 if (!pool || ck_threadpool_n_threads(pool) <= 1 || M < 2 ||
2018 (size_t)M * (size_t)N <= 4096) {
2019 gemm_nt_bf16_bf16_storage_row_range(A, B, bias, C, M, N, K, 0, M);
2020 return;
2021 }
2022
2023 ck_gemm_nt_bf16_exact_args_t args = {
2024 .A = A, .B = B, .bias = bias, .C = C, .M = M, .N = N, .K = K,
2025 };
2026 int active = ck_threadpool_n_threads(pool);
2027 if (active > M) active = M;
2028 int grain = M / (active * 4);
2029 if (grain < 1) grain = 1;
2031 pool, active, 0, M, grain, ck_gemm_nt_bf16_storage_exact_rows, &args);
2032}
void gemm_nt_bf16_bf16_storage_row_range(const float *A, const void *B, const float *bias, float *C, int M, int N, int K, int row_begin, int row_end)
static void ck_gemm_nt_bf16_storage_exact_rows(int begin, int end, void *opaque)

References C, ck_gemm_nt_bf16_storage_exact_rows(), ck_threadpool_global(), ck_threadpool_n_threads(), ck_threadpool_parallel_for_n(), and gemm_nt_bf16_bf16_storage_row_range().

Referenced by gemm_nt_bf16_bf16_storage().

◆ gemm_nt_bf16_bf16_storage_row_range()

void gemm_nt_bf16_bf16_storage_row_range ( const float *  A,
const void *  B,
const float *  bias,
float *  C,
int  M,
int  N,
int  K,
int  row_begin,
int  row_end 
)

Definition at line 1985 of file gemm_kernels_bf16.c.

1991{
1992 gemm_nt_bf16_row_range(A, B, bias, C, M, N, K, row_begin, row_end);
1993 for (int row = row_begin; row < row_end; ++row) {
1994 float *dst = C + (size_t)row * (size_t)N;
1995 for (int col = 0; col < N; ++col) {
1996 dst[col] = bf16_to_float(float_to_bf16(dst[col]));
1997 }
1998 }
1999}

References bf16_to_float(), C, float_to_bf16(), and gemm_nt_bf16_row_range().

Referenced by ck_gemm_nt_bf16_storage_exact_rows(), and gemm_nt_bf16_bf16_storage_parallel_dispatch().

◆ gemm_nt_bf16_native_bf16_storage()

void gemm_nt_bf16_native_bf16_storage ( const float *  A,
const void *  B,
const float *  bias,
float *  C,
int  M,
int  N,
int  K 
)

Definition at line 1071 of file gemm_kernels_bf16.c.

1076{
1077 const uint16_t *weights = (const uint16_t *)B;
1078 if (!A || !weights || !C || M <= 0 || N <= 0 || K <= 0) return;
1079
1080 ck_gemm_bf16_native_args_t args = {
1081 .A = A, .B = weights, .bias = bias, .C = C, .M = M, .N = N, .K = K
1082 };
1083 ck_threadpool_t *pool = ck_threadpool_global();
1084 int active = pool ? ck_threadpool_n_threads(pool) : 1;
1085 if (active > M) active = M;
1086 if (active > 24) active = 24;
1087 if (!pool || active <= 1 || (size_t)M * (size_t)N <= 4096) {
1088 ck_gemm_bf16_native_work(0, 1, &args);
1089 return;
1090 }
1092}
static void ck_gemm_bf16_native_work(int ith, int nth, void *opaque)

References C, ck_gemm_bf16_native_work(), ck_threadpool_dispatch_n(), ck_threadpool_global(), and ck_threadpool_n_threads().

Referenced by gemm_nt_bf16_prefill_shape_safe_bf16_storage(), and gemm_nt_bf16_prefill_shape_safe_bf16_storage_workspace().

◆ gemm_nt_bf16_parallel_dispatch()

void gemm_nt_bf16_parallel_dispatch ( const float *  A,
const void *  B,
const float *  bias,
float *  C,
int  M,
int  N,
int  K 
)

Definition at line 777 of file gemm_kernels_bf16.c.

782{
783 ck_threadpool_t *pool = ck_threadpool_global();
784 const char *disabled = getenv("CK_DISABLE_BF16_GEMM_PARALLEL_PREFILL");
785 if ((disabled && disabled[0] && strcmp(disabled, "0") != 0) ||
786 !pool || ck_threadpool_n_threads(pool) <= 1 || M < 2 ||
787 (size_t)M * (size_t)N <= 4096) {
788 gemm_nt_bf16(A, B, bias, C, M, N, K);
789 return;
790 }
791
792 ck_gemm_nt_bf16_exact_args_t args = {
793 .A = A, .B = B, .bias = bias, .C = C, .M = M, .N = N, .K = K,
794 };
795 int active = ck_threadpool_n_threads(pool);
796 if (active > M) active = M;
797 int grain = M / (active * 4);
798 if (grain < 1) grain = 1;
800 pool, active, 0, M, grain, ck_gemm_nt_bf16_exact_rows, &args);
801}
void gemm_nt_bf16(const float *A, const void *B, const float *bias, float *C, int M, int N, int K)
static void ck_gemm_nt_bf16_exact_rows(int begin, int end, void *opaque)

References C, ck_gemm_nt_bf16_exact_rows(), ck_threadpool_global(), ck_threadpool_n_threads(), ck_threadpool_parallel_for_n(), and gemm_nt_bf16().

◆ gemm_nt_bf16_prefill_shape_safe_bf16_storage()

void gemm_nt_bf16_prefill_shape_safe_bf16_storage ( const float *  A,
const void *  B,
const float *  bias,
float *  C,
int  M,
int  N,
int  K 
)

Definition at line 1347 of file gemm_kernels_bf16.c.

1352{
1353 const int amx_shape = M >= 16 && N >= 16 && K >= 32 &&
1354 (M % 16) == 0 && (N % 16) == 0 && (K % 32) == 0;
1355 if (amx_shape && ck_gemm_bf16_amx_available()) {
1356 gemm_nt_bf16_amx_bf16_storage(A, B, bias, C, M, N, K);
1357 return;
1358 }
1359 gemm_nt_bf16_native_bf16_storage(A, B, bias, C, M, N, K);
1360}
int ck_gemm_bf16_amx_available(void)
void gemm_nt_bf16_native_bf16_storage(const float *A, const void *B, const float *bias, float *C, int M, int N, int K)
void gemm_nt_bf16_amx_bf16_storage(const float *A, const void *B, const float *bias, float *C, int M, int N, int K)

References C, ck_gemm_bf16_amx_available(), gemm_nt_bf16_amx_bf16_storage(), and gemm_nt_bf16_native_bf16_storage().

◆ gemm_nt_bf16_prefill_shape_safe_bf16_storage_workspace()

void gemm_nt_bf16_prefill_shape_safe_bf16_storage_workspace ( const float *  A,
const void *  B,
const float *  bias,
float *  C,
int  M,
int  N,
int  K,
uint16_t *  a_bf16,
size_t  a_bf16_bytes 
)

Definition at line 1333 of file gemm_kernels_bf16.c.

1336{
1337 const int amx_shape = M >= 16 && N >= 16 && K >= 32 &&
1338 (M % 16) == 0 && (N % 16) == 0 && (K % 32) == 0;
1339 if (amx_shape && ck_gemm_bf16_amx_available()) {
1341 A, B, bias, C, M, N, K, a_bf16, a_bf16_bytes);
1342 return;
1343 }
1344 gemm_nt_bf16_native_bf16_storage(A, B, bias, C, M, N, K);
1345}

References C, ck_gemm_bf16_amx_available(), gemm_nt_bf16_amx_bf16_storage_workspace(), and gemm_nt_bf16_native_bf16_storage().

◆ gemm_nt_bf16_pytorch_onednn_3_12_brgemm_bf16_storage()

void gemm_nt_bf16_pytorch_onednn_3_12_brgemm_bf16_storage ( const float *  A,
const void *  B,
const float *  bias,
float *  C,
int  M,
int  N,
int  K 
)

Definition at line 1551 of file gemm_kernels_bf16.c.

1554{
1555#ifdef USE_ONEDNN
1556 ck_pytorch_brgemm_require_version(
1557 3, 12, 0, "80afa71049cd69a3df32adcccb623b12cd7baa22",
1558 "gemm_nt_bf16_pytorch_onednn_3_12_brgemm_bf16_storage", M, N, K);
1559#endif
1561 A, B, bias, C, M, N, K);
1562}
static void gemm_nt_bf16_pytorch_onednn_brgemm_bf16_storage_impl(const float *A, const void *B, const float *bias, float *C, int M, int N, int K)

References C, and gemm_nt_bf16_pytorch_onednn_brgemm_bf16_storage_impl().

◆ gemm_nt_bf16_pytorch_onednn_brgemm_bf16_storage()

void gemm_nt_bf16_pytorch_onednn_brgemm_bf16_storage ( const float *  A,
const void *  B,
const float *  bias,
float *  C,
int  M,
int  N,
int  K 
)

Definition at line 1536 of file gemm_kernels_bf16.c.

1541{
1542#ifdef USE_ONEDNN
1543 ck_pytorch_brgemm_require_version(
1544 3, 7, 1, "8d263e693366ef8db40acc569cc7d8edf644556d",
1545 "gemm_nt_bf16_pytorch_onednn_brgemm_bf16_storage", M, N, K);
1546#endif
1548 A, B, bias, C, M, N, K);
1549}

References C, and gemm_nt_bf16_pytorch_onednn_brgemm_bf16_storage_impl().

◆ gemm_nt_bf16_row_range()

void gemm_nt_bf16_row_range ( const float *  A,
const void *  B,
const float *  bias,
float *  C,
int  M,
int  N,
int  K,
int  row_begin,
int  row_end 
)

Definition at line 720 of file gemm_kernels_bf16.c.

726{
727 const uint16_t *w = (const uint16_t *)B;
728 if (!A || !w || !C || M <= 0 || N <= 0 || K <= 0 ||
729 row_begin < 0 || row_begin >= row_end || row_end > M) {
730 return;
731 }
732
733 for (int i = row_begin; i < row_end; ++i) {
734 const float *a_row = A + (size_t)i * (size_t)K;
735 float *c_row = C + (size_t)i * (size_t)N;
736 for (int j = 0; j < N; ++j) {
737 const uint16_t *w_row = w + (size_t)j * (size_t)K;
738 float sum = bias ? bias[j] : 0.0f;
739 for (int k = 0; k < K; ++k) {
740 const float ab = bf16_to_float(float_to_bf16(a_row[k]));
741 sum += ab * bf16_to_float(w_row[k]);
742 }
743 c_row[j] = sum;
744 }
745 }
746}

References bf16_to_float(), C, and float_to_bf16().

Referenced by ck_gemm_nt_bf16_exact_rows(), gemm_nt_bf16(), and gemm_nt_bf16_bf16_storage_row_range().

◆ gemm_nt_f16()

void gemm_nt_f16 ( const float *  A,
const void *  B,
const float *  bias,
float *  C,
int  M,
int  N,
int  K 
)

NT GEMM wrapper for FP16 weights with the engine's standard ABI.

Contract: A: [M, K] fp32 activation matrix B: [N, K] fp16 weight matrix stored row-major (transposed layout) C: [M, N] fp32 output matrix

This wrapper follows llama.cpp's CPU F16 mul_mat contract: activation rows are rounded to FP16 first, then the dot runs as F16 x F16 with FP32 output accumulation. The lower-level gemm_f16() helper remains the direct F16-weight x FP32-activation operator for generic use.

Definition at line 970 of file gemm_kernels_f16.c.

975{
977 gemm_nt_f16_ggml_strict(A, B, bias, C, M, N, K)) {
978 return;
979 }
980
981 if (!gemm_f16_input_fp16_threadpool(C, (const uint16_t *)B, A, N, M, K)) {
982 gemm_f16_input_fp16_ref(C, (const uint16_t *)B, A, N, M, K);
983 }
984
985 if (!bias) {
986 return;
987 }
988
989#pragma omp parallel for schedule(static) if(M > 1)
990 for (int i = 0; i < M; ++i) {
991 float *c_row = C + (size_t)i * (size_t)N;
992 for (int j = 0; j < N; ++j) {
993 c_row[j] += bias[j];
994 }
995 }
996}
static void gemm_f16_input_fp16_ref(float *Y, const uint16_t *W, const float *X, int M, int N, int K)
static int gemm_f16_input_fp16_threadpool(float *Y, const uint16_t *W, const float *X, int M, int N, int K)

References C, ck_strict_parity_enabled(), gemm_f16_input_fp16_ref(), gemm_f16_input_fp16_threadpool(), and gemm_nt_f16_ggml_strict().

◆ gemm_nt_f16_clipped()

void gemm_nt_f16_clipped ( const float *  A,
const void *  B,
const float *  bias,
const float *  input_min,
const float *  input_max,
const float *  output_min,
const float *  output_max,
float *  C,
int  M,
int  N,
int  K 
)

Definition at line 998 of file gemm_kernels_f16.c.

1007{
1008 const float in_min = input_min ? input_min[0] : -3.4028234663852886e38f;
1009 const float in_max = input_max ? input_max[0] : 3.4028234663852886e38f;
1010 const float out_min = output_min ? output_min[0] : -3.4028234663852886e38f;
1011 const float out_max = output_max ? output_max[0] : 3.4028234663852886e38f;
1012 const uint16_t *W = (const uint16_t *)B;
1013
1014#pragma omp parallel for schedule(static) if(M > 1)
1015 for (int m = 0; m < M; ++m) {
1016 const float *a_row = A + (size_t)m * (size_t)K;
1017 uint16_t a_f16[K];
1018
1019 for (int k = 0; k < K; ++k) {
1020 float x = a_row[k];
1021 if (x < in_min) x = in_min;
1022 if (x > in_max) x = in_max;
1023 a_f16[k] = fp32_to_fp16(x);
1024 }
1025
1026 float *c_row = C + (size_t)m * (size_t)N;
1027 for (int n = 0; n < N; ++n) {
1028 const uint16_t *w_row = W + (size_t)n * (size_t)K;
1029 float sum = bias ? bias[n] : 0.0f;
1030 for (int k = 0; k < K; ++k) {
1031 sum += fp16_to_fp32(w_row[k]) * fp16_to_fp32(a_f16[k]);
1032 }
1033 if (sum < out_min) sum = out_min;
1034 if (sum > out_max) sum = out_max;
1035 c_row[n] = sum;
1036 }
1037 }
1038}
#define fp16_to_fp32(x)
#define fp32_to_fp16(x)

References C, fp16_to_fp32, and fp32_to_fp16.

◆ gemm_nt_f32_llama_production()

void gemm_nt_f32_llama_production ( const float *  A,
const float *  B,
const float *  bias,
float *  C,
int  M,
int  N,
int  K 
)

Definition at line 1062 of file gemm_kernels.c.

1067{
1068 if (!A || !B || !C || M <= 0 || N <= 0 || K <= 0) {
1069 return;
1070 }
1071
1072#pragma omp parallel for schedule(static) if ((size_t)M * (size_t)N >= 96)
1073 for (int index = 0; index < M * N; ++index) {
1074 ck_gemm_nt_f32_llama_production_output(A, B, bias, C, M, N, K, index);
1075 }
1076}
static void ck_gemm_nt_f32_llama_production_output(const float *A, const float *B, const float *bias, float *C, int M, int N, int K, int index)

References C, and ck_gemm_nt_f32_llama_production_output().

Referenced by ck_moe_shared_q4k_gated_workspace(), and moe_swiglu_shared_forward_q8_0_gated_workspace().

◆ gemm_nt_f32_llama_production_output_range()

void gemm_nt_f32_llama_production_output_range ( const float *  A,
const float *  B,
const float *  bias,
float *  C,
int  M,
int  N,
int  K,
int  output_begin,
int  output_end 
)

Definition at line 1049 of file gemm_kernels.c.

1052{
1053 if (!A || !B || !C || M <= 0 || N <= 0 || K <= 0) return;
1054 const int total = M * N;
1055 if (output_begin < 0) output_begin = 0;
1056 if (output_end > total) output_end = total;
1057 for (int index = output_begin; index < output_end; ++index) {
1058 ck_gemm_nt_f32_llama_production_output(A, B, bias, C, M, N, K, index);
1059 }
1060}

References C, and ck_gemm_nt_f32_llama_production_output().

◆ gemm_nt_fp32_exact_parallel_dispatch()

void gemm_nt_fp32_exact_parallel_dispatch ( const float *  A,
const float *  B,
const float *  bias,
float *  C,
int  M,
int  N,
int  K 
)

Definition at line 179 of file gemm_kernels.c.

184{
185 if (!A || !B || !C || M <= 0 || N <= 0 || K <= 0) return;
186 ck_gemm_nt_fp32_exact_args_t args = {
187 .A = A, .B = B, .bias = bias, .C = C,
188 .M = M, .N = N, .K = K,
189 .bias_before_reduction = ck_strict_parity_enabled(),
190 };
191 ck_threadpool_t *pool = ck_threadpool_global();
192 if (!pool || ck_threadpool_n_threads(pool) <= 1 || M < 2 ||
193 (size_t)M * (size_t)N <= 4096) {
194 ck_gemm_nt_fp32_exact_rows(0, M, &args);
195 return;
196 }
197 int active = ck_threadpool_n_threads(pool);
198 if (active > M) active = M;
199 int grain = M / (active * 4);
200 if (grain < 1) grain = 1;
202 pool, active, 0, M, grain, ck_gemm_nt_fp32_exact_rows, &args);
203}
static void ck_gemm_nt_fp32_exact_rows(int begin, int end, void *opaque)

References C, ck_gemm_nt_fp32_exact_rows(), ck_strict_parity_enabled(), ck_threadpool_global(), ck_threadpool_n_threads(), and ck_threadpool_parallel_for_n().

◆ gemm_nt_q4_0()

void gemm_nt_q4_0 ( const float *  A,
const void *  B,
const float *  bias,
float *  C,
int  M,
int  N,
int  K 
)

Matrix-matrix multiply: C[M,N] = A[M,K] @ B[N,K]^T + bias.

Parameters
AInput matrix [M x K], row-major FP32
BWeight matrix in Q4_0 format, [N x K] stored row-major
biasOptional bias [N], NULL if not used
COutput [M x N], row-major FP32
MBatch size (number of tokens)
NOutput dimension (number of rows in B)
KInput dimension

Definition at line 176 of file gemm_kernels_q4_0.c.

181{
182 const block_q4_0 *blocks = (const block_q4_0 *)B;
183 const int blocks_per_row = K / QK4_0;
184
185 for (int m = 0; m < M; m++) {
186 const float *a_row = &A[m * K];
187
188 for (int n = 0; n < N; n++) {
189 float sum = 0.0f;
190
191 for (int b = 0; b < blocks_per_row; b++) {
192 const block_q4_0 *block = &blocks[n * blocks_per_row + b];
193 const float d = CK_FP16_TO_FP32(block->d);
194 const float *ap = &a_row[b * QK4_0];
195
196 for (int i = 0; i < QK4_0 / 2; i++) {
197 const uint8_t packed = block->qs[i];
198 const int q0 = (packed & 0x0F) - 8;
199 const int q1 = (packed >> 4) - 8;
200
201 sum += d * (float)q0 * ap[2 * i + 0];
202 sum += d * (float)q1 * ap[2 * i + 1];
203 }
204 }
205
206 C[m * N + n] = sum + (bias ? bias[n] : 0.0f);
207 }
208 }
209}
uint8_t qs[32/2]

References C, CK_FP16_TO_FP32, block_q4_0::d, QK4_0, and block_q4_0::qs.

Referenced by ck_gemm_nt_quant().

◆ gemm_nt_q4_1()

void gemm_nt_q4_1 ( const float *  A,
const void *  B,
const float *  bias,
float *  C,
int  M,
int  N,
int  K 
)

GEMM with transposed Q4_1 weights: C = A @ B^T.

Parameters
AInput activations [M x K], row-major FP32
BWeight matrix in Q4_1 format [N x K], row-major quantized
biasOptional bias [N], NULL if not used
COutput [M x N], row-major FP32
MBatch size (number of tokens)
NOutput dimension
KInput dimension

Definition at line 256 of file gemm_kernels_q4_1.c.

261{
262 const block_q4_1 *blocks = (const block_q4_1 *)B;
263 const int blocks_per_row = K / QK4_1;
264
265 for (int m = 0; m < M; m++) {
266 const float *a_row = &A[m * K];
267
268 for (int n = 0; n < N; n++) {
269 float sum = 0.0f;
270
271 for (int b = 0; b < blocks_per_row; b++) {
272 const block_q4_1 *block = &blocks[n * blocks_per_row + b];
273 const float d = CK_FP16_TO_FP32(block->d);
274 const float min = CK_FP16_TO_FP32(block->m);
275 const float *ap = &a_row[b * QK4_1];
276
277 for (int i = 0; i < QK4_1 / 2; i++) {
278 const uint8_t packed = block->qs[i];
279 const int q0 = (packed & 0x0F);
280 const int q1 = (packed >> 4);
281
282 const float w0 = d * (float)q0 + min;
283 const float w1 = d * (float)q1 + min;
284
285 sum += w0 * ap[2 * i + 0];
286 sum += w1 * ap[2 * i + 1];
287 }
288 }
289
290 C[m * N + n] = sum + (bias ? bias[n] : 0.0f);
291 }
292 }
293}
uint8_t qs[32/2]

References C, CK_FP16_TO_FP32, block_q4_1::d, block_q4_1::m, QK4_1, and block_q4_1::qs.

Referenced by ck_gemm_nt_quant().

◆ gemm_nt_q4_k()

void gemm_nt_q4_k ( const float *  A,
const void *  B,
const float *  bias,
float *  C,
int  M,
int  N,
int  K 
)

Definition at line 708 of file gemm_kernels_q4k.c.

713{
714 if (!A || !B || !C) {
715 return;
716 }
717 if (M <= 0 || N <= 0 || K <= 0) {
718 return;
719 }
720
721 /* gemm_q4_k produces Y as [batch x M_out]. Here:
722 * batch = M (tokens)
723 * M_out = N (output channels) */
724 gemm_q4_k(C, B, A, /*M_out=*/N, /*N_batch=*/M, K);
725
726 if (!bias) {
727 return;
728 }
729
730 for (int i = 0; i < M; ++i) {
731 float *row = C + (size_t)i * (size_t)N;
732 for (int j = 0; j < N; ++j) {
733 row[j] += bias[j];
734 }
735 }
736}
void gemm_q4_k(float *Y, const void *W, const float *X, int M, int N, int K)
Auto-dispatch GEMM based on available SIMD.

References C, and gemm_q4_k().

Referenced by ck_attention_project_head_major_q4_k(), ck_gemm_nt_quant(), ck_layer_forward_rmsnorm_swiglu_decode_q4_k(), ck_mlp_swiglu_forward_q4_k(), ck_qkv_project_head_major_q4_k(), ck_qkv_project_head_major_token_q4_k(), model_decode_token(), model_decode_token(), model_layer_0_decode(), model_layer_0_decode(), model_layer_0_prefill(), model_layer_0_prefill(), model_layer_0_prefill(), model_layer_0_prefill(), model_layer_10_decode(), model_layer_10_decode(), model_layer_10_prefill(), model_layer_10_prefill(), model_layer_10_prefill(), model_layer_10_prefill(), model_layer_11_decode(), model_layer_11_decode(), model_layer_11_prefill(), model_layer_11_prefill(), model_layer_11_prefill(), model_layer_11_prefill(), model_layer_12_decode(), model_layer_12_decode(), model_layer_12_prefill(), model_layer_12_prefill(), model_layer_12_prefill(), model_layer_12_prefill(), model_layer_13_decode(), model_layer_13_decode(), model_layer_13_prefill(), model_layer_13_prefill(), model_layer_13_prefill(), model_layer_13_prefill(), model_layer_14_decode(), model_layer_14_decode(), model_layer_14_prefill(), model_layer_14_prefill(), model_layer_14_prefill(), model_layer_14_prefill(), model_layer_15_decode(), model_layer_15_decode(), model_layer_15_prefill(), model_layer_15_prefill(), model_layer_15_prefill(), model_layer_15_prefill(), model_layer_16_decode(), model_layer_16_decode(), model_layer_16_prefill(), model_layer_16_prefill(), model_layer_16_prefill(), model_layer_16_prefill(), model_layer_17_decode(), model_layer_17_decode(), model_layer_17_prefill(), model_layer_17_prefill(), model_layer_17_prefill(), model_layer_17_prefill(), model_layer_18_decode(), model_layer_18_decode(), model_layer_18_prefill(), model_layer_18_prefill(), model_layer_18_prefill(), model_layer_18_prefill(), model_layer_19_decode(), model_layer_19_decode(), model_layer_19_prefill(), model_layer_19_prefill(), model_layer_19_prefill(), model_layer_19_prefill(), model_layer_1_decode(), model_layer_1_decode(), model_layer_1_prefill(), model_layer_1_prefill(), model_layer_1_prefill(), model_layer_1_prefill(), model_layer_20_decode(), model_layer_20_decode(), model_layer_20_prefill(), model_layer_20_prefill(), model_layer_20_prefill(), model_layer_20_prefill(), model_layer_21_decode(), model_layer_21_decode(), model_layer_21_prefill(), model_layer_21_prefill(), model_layer_21_prefill(), model_layer_21_prefill(), model_layer_22_decode(), model_layer_22_decode(), model_layer_22_prefill(), model_layer_22_prefill(), model_layer_22_prefill(), model_layer_22_prefill(), model_layer_23_decode(), model_layer_23_decode(), model_layer_23_prefill(), model_layer_23_prefill(), model_layer_23_prefill(), model_layer_23_prefill(), model_layer_2_decode(), model_layer_2_decode(), model_layer_2_prefill(), model_layer_2_prefill(), model_layer_2_prefill(), model_layer_2_prefill(), model_layer_3_decode(), model_layer_3_decode(), model_layer_3_prefill(), model_layer_3_prefill(), model_layer_3_prefill(), model_layer_3_prefill(), model_layer_4_decode(), model_layer_4_decode(), model_layer_4_prefill(), model_layer_4_prefill(), model_layer_4_prefill(), model_layer_4_prefill(), model_layer_5_decode(), model_layer_5_decode(), model_layer_5_prefill(), model_layer_5_prefill(), model_layer_5_prefill(), model_layer_5_prefill(), model_layer_6_decode(), model_layer_6_decode(), model_layer_6_prefill(), model_layer_6_prefill(), model_layer_6_prefill(), model_layer_6_prefill(), model_layer_7_decode(), model_layer_7_decode(), model_layer_7_prefill(), model_layer_7_prefill(), model_layer_7_prefill(), model_layer_7_prefill(), model_layer_8_decode(), model_layer_8_decode(), model_layer_8_prefill(), model_layer_8_prefill(), model_layer_8_prefill(), model_layer_8_prefill(), model_layer_9_decode(), model_layer_9_decode(), model_layer_9_prefill(), model_layer_9_prefill(), model_layer_9_prefill(), model_layer_9_prefill(), qwen2_0_5b_decode_decode_token(), qwen2_0_5b_decode_decode_token(), qwen2_0_5b_decode_layer_0_decode(), qwen2_0_5b_decode_layer_0_decode(), qwen2_0_5b_decode_layer_0_prefill(), qwen2_0_5b_decode_layer_0_prefill(), qwen2_0_5b_decode_layer_0_prefill(), qwen2_0_5b_decode_layer_0_prefill(), qwen2_0_5b_decode_layer_10_decode(), qwen2_0_5b_decode_layer_10_decode(), qwen2_0_5b_decode_layer_10_prefill(), qwen2_0_5b_decode_layer_10_prefill(), qwen2_0_5b_decode_layer_10_prefill(), qwen2_0_5b_decode_layer_10_prefill(), qwen2_0_5b_decode_layer_11_decode(), qwen2_0_5b_decode_layer_11_decode(), qwen2_0_5b_decode_layer_11_decode(), qwen2_0_5b_decode_layer_11_prefill(), qwen2_0_5b_decode_layer_11_prefill(), qwen2_0_5b_decode_layer_11_prefill(), qwen2_0_5b_decode_layer_11_prefill(), qwen2_0_5b_decode_layer_12_decode(), qwen2_0_5b_decode_layer_12_decode(), qwen2_0_5b_decode_layer_12_decode(), qwen2_0_5b_decode_layer_12_prefill(), qwen2_0_5b_decode_layer_12_prefill(), qwen2_0_5b_decode_layer_12_prefill(), qwen2_0_5b_decode_layer_12_prefill(), qwen2_0_5b_decode_layer_13_decode(), qwen2_0_5b_decode_layer_13_decode(), qwen2_0_5b_decode_layer_13_prefill(), qwen2_0_5b_decode_layer_13_prefill(), qwen2_0_5b_decode_layer_13_prefill(), qwen2_0_5b_decode_layer_13_prefill(), qwen2_0_5b_decode_layer_14_decode(), qwen2_0_5b_decode_layer_14_decode(), qwen2_0_5b_decode_layer_14_decode(), qwen2_0_5b_decode_layer_14_prefill(), qwen2_0_5b_decode_layer_14_prefill(), qwen2_0_5b_decode_layer_14_prefill(), qwen2_0_5b_decode_layer_14_prefill(), qwen2_0_5b_decode_layer_15_decode(), qwen2_0_5b_decode_layer_15_decode(), qwen2_0_5b_decode_layer_15_decode(), qwen2_0_5b_decode_layer_15_prefill(), qwen2_0_5b_decode_layer_15_prefill(), qwen2_0_5b_decode_layer_15_prefill(), qwen2_0_5b_decode_layer_15_prefill(), qwen2_0_5b_decode_layer_16_decode(), qwen2_0_5b_decode_layer_16_decode(), qwen2_0_5b_decode_layer_16_prefill(), qwen2_0_5b_decode_layer_16_prefill(), qwen2_0_5b_decode_layer_16_prefill(), qwen2_0_5b_decode_layer_16_prefill(), qwen2_0_5b_decode_layer_17_decode(), qwen2_0_5b_decode_layer_17_decode(), qwen2_0_5b_decode_layer_17_decode(), qwen2_0_5b_decode_layer_17_prefill(), qwen2_0_5b_decode_layer_17_prefill(), qwen2_0_5b_decode_layer_17_prefill(), qwen2_0_5b_decode_layer_17_prefill(), qwen2_0_5b_decode_layer_18_decode(), qwen2_0_5b_decode_layer_18_decode(), qwen2_0_5b_decode_layer_18_decode(), qwen2_0_5b_decode_layer_18_prefill(), qwen2_0_5b_decode_layer_18_prefill(), qwen2_0_5b_decode_layer_18_prefill(), qwen2_0_5b_decode_layer_18_prefill(), qwen2_0_5b_decode_layer_19_decode(), qwen2_0_5b_decode_layer_19_decode(), qwen2_0_5b_decode_layer_19_prefill(), qwen2_0_5b_decode_layer_19_prefill(), qwen2_0_5b_decode_layer_19_prefill(), qwen2_0_5b_decode_layer_19_prefill(), qwen2_0_5b_decode_layer_1_decode(), qwen2_0_5b_decode_layer_1_decode(), qwen2_0_5b_decode_layer_1_prefill(), qwen2_0_5b_decode_layer_1_prefill(), qwen2_0_5b_decode_layer_1_prefill(), qwen2_0_5b_decode_layer_1_prefill(), qwen2_0_5b_decode_layer_20_decode(), qwen2_0_5b_decode_layer_20_decode(), qwen2_0_5b_decode_layer_20_decode(), qwen2_0_5b_decode_layer_20_prefill(), qwen2_0_5b_decode_layer_20_prefill(), qwen2_0_5b_decode_layer_20_prefill(), qwen2_0_5b_decode_layer_20_prefill(), qwen2_0_5b_decode_layer_21_decode(), qwen2_0_5b_decode_layer_21_decode(), qwen2_0_5b_decode_layer_21_prefill(), qwen2_0_5b_decode_layer_21_prefill(), qwen2_0_5b_decode_layer_21_prefill(), qwen2_0_5b_decode_layer_21_prefill(), qwen2_0_5b_decode_layer_22_decode(), qwen2_0_5b_decode_layer_22_decode(), qwen2_0_5b_decode_layer_22_decode(), qwen2_0_5b_decode_layer_22_prefill(), qwen2_0_5b_decode_layer_22_prefill(), qwen2_0_5b_decode_layer_22_prefill(), qwen2_0_5b_decode_layer_22_prefill(), qwen2_0_5b_decode_layer_23_decode(), qwen2_0_5b_decode_layer_23_decode(), qwen2_0_5b_decode_layer_23_decode(), qwen2_0_5b_decode_layer_23_prefill(), qwen2_0_5b_decode_layer_23_prefill(), qwen2_0_5b_decode_layer_23_prefill(), qwen2_0_5b_decode_layer_23_prefill(), qwen2_0_5b_decode_layer_2_decode(), qwen2_0_5b_decode_layer_2_decode(), qwen2_0_5b_decode_layer_2_decode(), qwen2_0_5b_decode_layer_2_prefill(), qwen2_0_5b_decode_layer_2_prefill(), qwen2_0_5b_decode_layer_2_prefill(), qwen2_0_5b_decode_layer_2_prefill(), qwen2_0_5b_decode_layer_3_decode(), qwen2_0_5b_decode_layer_3_decode(), qwen2_0_5b_decode_layer_3_prefill(), qwen2_0_5b_decode_layer_3_prefill(), qwen2_0_5b_decode_layer_3_prefill(), qwen2_0_5b_decode_layer_3_prefill(), qwen2_0_5b_decode_layer_4_decode(), qwen2_0_5b_decode_layer_4_decode(), qwen2_0_5b_decode_layer_4_decode(), qwen2_0_5b_decode_layer_4_prefill(), qwen2_0_5b_decode_layer_4_prefill(), qwen2_0_5b_decode_layer_4_prefill(), qwen2_0_5b_decode_layer_4_prefill(), qwen2_0_5b_decode_layer_5_decode(), qwen2_0_5b_decode_layer_5_decode(), qwen2_0_5b_decode_layer_5_decode(), qwen2_0_5b_decode_layer_5_prefill(), qwen2_0_5b_decode_layer_5_prefill(), qwen2_0_5b_decode_layer_5_prefill(), qwen2_0_5b_decode_layer_5_prefill(), qwen2_0_5b_decode_layer_6_decode(), qwen2_0_5b_decode_layer_6_decode(), qwen2_0_5b_decode_layer_6_prefill(), qwen2_0_5b_decode_layer_6_prefill(), qwen2_0_5b_decode_layer_6_prefill(), qwen2_0_5b_decode_layer_6_prefill(), qwen2_0_5b_decode_layer_7_decode(), qwen2_0_5b_decode_layer_7_decode(), qwen2_0_5b_decode_layer_7_prefill(), qwen2_0_5b_decode_layer_7_prefill(), qwen2_0_5b_decode_layer_7_prefill(), qwen2_0_5b_decode_layer_7_prefill(), qwen2_0_5b_decode_layer_8_decode(), qwen2_0_5b_decode_layer_8_decode(), qwen2_0_5b_decode_layer_8_prefill(), qwen2_0_5b_decode_layer_8_prefill(), qwen2_0_5b_decode_layer_8_prefill(), qwen2_0_5b_decode_layer_8_prefill(), qwen2_0_5b_decode_layer_9_decode(), qwen2_0_5b_decode_layer_9_decode(), qwen2_0_5b_decode_layer_9_prefill(), qwen2_0_5b_decode_layer_9_prefill(), qwen2_0_5b_decode_layer_9_prefill(), and qwen2_0_5b_decode_layer_9_prefill().

◆ gemm_nt_q4_k_q8_k()

void gemm_nt_q4_k_q8_k ( const void *  A_q8,
const void *  B,
const float *  bias,
float *  C,
int  M,
int  N,
int  K 
)

Definition at line 397 of file gemm_kernels_q4k_q8k.c.

402{
403 if (!A_q8 || !B || !C) {
404 return;
405 }
406 if (M <= 0 || N <= 0 || K <= 0) {
407 return;
408 }
409
410 gemm_q4_k_q8_k(C, B, A_q8, /*M_out=*/N, /*N_batch=*/M, K);
411
412 if (!bias) {
413 return;
414 }
415
416 for (int i = 0; i < M; ++i) {
417 float *row = C + (size_t)i * (size_t)N;
418 for (int j = 0; j < N; ++j) {
419 row[j] += bias[j];
420 }
421 }
422}
void gemm_q4_k_q8_k(float *Y, const void *W, const void *X_q8, int M, int N, int K)

References C, and gemm_q4_k_q8_k().

Referenced by ck_attention_project_head_major_q4_k_q8_k(), ck_layer_forward_rmsnorm_swiglu_decode_q4_k(), ck_mlp_swiglu_forward_q4_k_q8_k(), ck_mlp_swiglu_forward_q4_k_q8_k_prefill(), ck_qkv_project_head_major_token_q4_k_q8_k(), gemm_nt_q8_k_mlp_dispatch(), gemm_nt_q8_k_qkv_dispatch(), model_forward_prefill_impl(), model_forward_prefill_impl(), model_forward_prefill_impl(), model_forward_prefill_impl(), qwen2_0_5b_decode_forward_prefill_impl(), qwen2_0_5b_decode_forward_prefill_impl(), qwen2_0_5b_decode_forward_prefill_impl(), and qwen2_0_5b_decode_forward_prefill_impl().

◆ gemm_nt_q5_0()

void gemm_nt_q5_0 ( const float *  A,
const void *  B,
const float *  bias,
float *  C,
int  M,
int  N,
int  K 
)

Definition at line 833 of file gemm_kernels_q5_0.c.

838{
839 /* For decode (M=1), use direct GEMV which has AVX optimization */
840 if (M == 1) {
841 /* gemm_q5_0 expects column-major output, but we need row-major
842 * So we call gemv_q5_0 directly for each output element */
843 gemv_q5_0(C, B, A, N, K);
844 if (bias) {
845 for (int n = 0; n < N; n++) {
846 C[n] += bias[n];
847 }
848 }
849 return;
850 }
851
852 /* For prefill (M>1), use GEMM which dispatches to GEMV with AVX/AVX512 */
853 /* gemm_q5_0 produces Y as [batch x M_out]. Here:
854 * batch = M (tokens)
855 * M_out = N (output channels) */
856 gemm_q5_0(C, B, A, /*M_out=*/N, /*N_batch=*/M, K);
857
858 if (bias) {
859 for (int m = 0; m < M; m++) {
860 float *row = C + (size_t)m * (size_t)N;
861 for (int n = 0; n < N; n++) {
862 row[n] += bias[n];
863 }
864 }
865 }
866}
void gemv_q5_0(float *y, const void *W, const float *x, int M, int K)
Auto-dispatch GEMV for Q5_0 weights based on CPU features.
void gemm_q5_0(float *Y, const void *W, const float *X, int M, int N, int K)
Matrix-matrix multiply with Q5_0 weights.

References C, gemm_q5_0(), and gemv_q5_0().

Referenced by ck_gemm_nt_quant(), qwen2_0_5b_decode_layer_0_decode(), qwen2_0_5b_decode_layer_10_decode(), qwen2_0_5b_decode_layer_11_decode(), qwen2_0_5b_decode_layer_12_decode(), qwen2_0_5b_decode_layer_13_decode(), qwen2_0_5b_decode_layer_14_decode(), qwen2_0_5b_decode_layer_15_decode(), qwen2_0_5b_decode_layer_16_decode(), qwen2_0_5b_decode_layer_17_decode(), qwen2_0_5b_decode_layer_18_decode(), qwen2_0_5b_decode_layer_19_decode(), qwen2_0_5b_decode_layer_1_decode(), qwen2_0_5b_decode_layer_20_decode(), qwen2_0_5b_decode_layer_21_decode(), qwen2_0_5b_decode_layer_22_decode(), qwen2_0_5b_decode_layer_23_decode(), qwen2_0_5b_decode_layer_2_decode(), qwen2_0_5b_decode_layer_3_decode(), qwen2_0_5b_decode_layer_4_decode(), qwen2_0_5b_decode_layer_5_decode(), qwen2_0_5b_decode_layer_6_decode(), qwen2_0_5b_decode_layer_7_decode(), qwen2_0_5b_decode_layer_8_decode(), and qwen2_0_5b_decode_layer_9_decode().

◆ gemm_nt_q5_1()

void gemm_nt_q5_1 ( const float *  A,
const void *  B,
const float *  bias,
float *  C,
int  M,
int  N,
int  K 
)

GEMM with transposed Q5_1 weights: C = A @ B^T.

Parameters
AInput activations [M x K], row-major FP32
BWeight matrix in Q5_1 format [N x K], row-major quantized
biasOptional bias [N], NULL if not used
COutput [M x N], row-major FP32
MBatch size (number of tokens)
NOutput dimension
KInput dimension

Definition at line 314 of file gemm_kernels_q5_1.c.

319{
320 const block_q5_1 *blocks = (const block_q5_1 *)B;
321 const int blocks_per_row = K / QK5_1;
322
323 for (int m = 0; m < M; m++) {
324 const float *a_row = &A[m * K];
325
326 for (int n = 0; n < N; n++) {
327 float sum = 0.0f;
328
329 for (int b = 0; b < blocks_per_row; b++) {
330 const block_q5_1 *block = &blocks[n * blocks_per_row + b];
331 const float d = CK_FP16_TO_FP32(block->d);
332 const float min = CK_FP16_TO_FP32(block->m);
333 const float *ap = &a_row[b * QK5_1];
334
335 uint32_t qh;
336 memcpy(&qh, block->qh, sizeof(qh));
337
338 for (int i = 0; i < QK5_1 / 2; i++) {
339 const uint8_t packed = block->qs[i];
340 const int lo0 = (packed & 0x0F);
341 const int lo1 = (packed >> 4);
342 const int hi0 = ((qh >> (2 * i + 0)) & 1) << 4;
343 const int hi1 = ((qh >> (2 * i + 1)) & 1) << 4;
344 const int q0 = lo0 | hi0;
345 const int q1 = lo1 | hi1;
346
347 const float w0 = d * (float)q0 + min;
348 const float w1 = d * (float)q1 + min;
349
350 sum += w0 * ap[2 * i + 0];
351 sum += w1 * ap[2 * i + 1];
352 }
353 }
354
355 C[m * N + n] = sum + (bias ? bias[n] : 0.0f);
356 }
357 }
358}
uint8_t qs[32/2]
uint8_t qh[4]

References C, CK_FP16_TO_FP32, block_q5_1::d, block_q5_1::m, block_q5_1::qh, QK5_1, and block_q5_1::qs.

Referenced by ck_gemm_nt_quant().

◆ gemm_nt_q5_1_q8_1()

void gemm_nt_q5_1_q8_1 ( const float *  A,
const void *  B,
const float *  bias,
float *  C,
int  M,
int  N,
int  K 
)

Definition at line 289 of file gemm_kernels_q5_1_q8_1.c.

296{
297 if (!A || !B || !C || M <= 0 || N <= 0 || K <= 0 || (K % QK5_1) != 0) {
298 return;
299 }
300
301 const int blocks_per_row = K / QK5_1;
302 if (blocks_per_row > CK_Q51_STACK_Q8_BLOCKS) {
303 return;
304 }
305
306 const block_q5_1 *W = (const block_q5_1 *)B;
307
308 for (int m = 0; m < M; ++m) {
309 block_q8_1 a_q8[CK_Q51_STACK_Q8_BLOCKS];
310 quantize_row_q8_1_scalar(&A[m * K], a_q8, K);
311 float *c_row = &C[(size_t)m * (size_t)N];
312
313 int n = 0;
314 for (; n + 7 < N; n += 8) {
315 const block_q5_1 *w0 = &W[(size_t)(n + 0) * (size_t)blocks_per_row];
316 const block_q5_1 *w1 = &W[(size_t)(n + 1) * (size_t)blocks_per_row];
317 const block_q5_1 *w2 = &W[(size_t)(n + 2) * (size_t)blocks_per_row];
318 const block_q5_1 *w3 = &W[(size_t)(n + 3) * (size_t)blocks_per_row];
319 const block_q5_1 *w4 = &W[(size_t)(n + 4) * (size_t)blocks_per_row];
320 const block_q5_1 *w5 = &W[(size_t)(n + 5) * (size_t)blocks_per_row];
321 const block_q5_1 *w6 = &W[(size_t)(n + 6) * (size_t)blocks_per_row];
322 const block_q5_1 *w7 = &W[(size_t)(n + 7) * (size_t)blocks_per_row];
323 float s0 = 0.0f;
324 float s1 = 0.0f;
325 float s2 = 0.0f;
326 float s3 = 0.0f;
327 float s4 = 0.0f;
328 float s5 = 0.0f;
329 float s6 = 0.0f;
330 float s7 = 0.0f;
331
332 for (int b = 0; b < blocks_per_row; ++b) {
333 const block_q8_1 *x = &a_q8[b];
334 s0 += dot_q5_1_q8_1_block(&w0[b], x);
335 s1 += dot_q5_1_q8_1_block(&w1[b], x);
336 s2 += dot_q5_1_q8_1_block(&w2[b], x);
337 s3 += dot_q5_1_q8_1_block(&w3[b], x);
338 s4 += dot_q5_1_q8_1_block(&w4[b], x);
339 s5 += dot_q5_1_q8_1_block(&w5[b], x);
340 s6 += dot_q5_1_q8_1_block(&w6[b], x);
341 s7 += dot_q5_1_q8_1_block(&w7[b], x);
342 }
343
344 c_row[n + 0] = s0 + (bias ? bias[n + 0] : 0.0f);
345 c_row[n + 1] = s1 + (bias ? bias[n + 1] : 0.0f);
346 c_row[n + 2] = s2 + (bias ? bias[n + 2] : 0.0f);
347 c_row[n + 3] = s3 + (bias ? bias[n + 3] : 0.0f);
348 c_row[n + 4] = s4 + (bias ? bias[n + 4] : 0.0f);
349 c_row[n + 5] = s5 + (bias ? bias[n + 5] : 0.0f);
350 c_row[n + 6] = s6 + (bias ? bias[n + 6] : 0.0f);
351 c_row[n + 7] = s7 + (bias ? bias[n + 7] : 0.0f);
352 }
353
354 for (; n < N; ++n) {
355 const block_q5_1 *w_row = &W[(size_t)n * (size_t)blocks_per_row];
356 float sum = 0.0f;
357 for (int b = 0; b < blocks_per_row; ++b) {
358 sum += dot_q5_1_q8_1_block(&w_row[b], &a_q8[b]);
359 }
360 c_row[n] = sum + (bias ? bias[n] : 0.0f);
361 }
362 }
363}
static void quantize_row_q8_1_scalar(const float *x, block_q8_1 *y, int k)
#define CK_Q51_STACK_Q8_BLOCKS
static float dot_q5_1_q8_1_block(const block_q5_1 *w, const block_q8_1 *x)

References C, CK_Q51_STACK_Q8_BLOCKS, dot_q5_1_q8_1_block(), QK5_1, and quantize_row_q8_1_scalar().

Referenced by gemm_nt_q5_1_q8_1_m4().

◆ gemm_nt_q5_1_q8_1_ref()

void gemm_nt_q5_1_q8_1_ref ( const void *  A_q8,
const void *  B,
const float *  bias,
float *  C,
int  M,
int  N,
int  K 
)

Definition at line 242 of file gemm_kernels_q5_1_q8_1.c.

247{
248 if (!A_q8 || !B || !C || M <= 0 || N <= 0 || K <= 0 || (K % QK5_1) != 0) {
249 return;
250 }
251
252 const block_q8_1 *A = (const block_q8_1 *)A_q8;
253 const block_q5_1 *W = (const block_q5_1 *)B;
254 const int blocks_per_row = K / QK5_1;
255
256 for (int m = 0; m < M; ++m) {
257 const block_q8_1 *a_row = &A[m * blocks_per_row];
258 for (int n = 0; n < N; ++n) {
259 const block_q5_1 *w_row = &W[n * blocks_per_row];
260 float sum = 0.0f;
261 for (int b = 0; b < blocks_per_row; ++b) {
262 sum += dot_q5_1_q8_1_block(&w_row[b], &a_row[b]);
263 }
264 C[m * N + n] = sum + (bias ? bias[n] : 0.0f);
265 }
266 }
267}

References C, dot_q5_1_q8_1_block(), and QK5_1.

◆ gemm_nt_q5_k()

void gemm_nt_q5_k ( const float *  A,
const void *  B,
const float *  bias,
float *  C,
int  M,
int  N,
int  K 
)

Definition at line 1001 of file gemm_kernels_q5_k.c.

1006{
1007#if defined(__AVX512F__)
1008 /* TODO: AVX-512 implementation */
1009 gemm_nt_q5_k_ref(A, B, bias, C, M, N, K);
1010#elif defined(__AVX2__)
1011 /* TODO: AVX-2 implementation */
1012 gemm_nt_q5_k_ref(A, B, bias, C, M, N, K);
1013#elif defined(__AVX__)
1014 /* TODO: AVX implementation */
1015 gemm_nt_q5_k_ref(A, B, bias, C, M, N, K);
1016#elif defined(__SSE4_1__)
1017 /* TODO: SSE4.1 implementation */
1018 gemm_nt_q5_k_ref(A, B, bias, C, M, N, K);
1019#else
1020 gemm_nt_q5_k_ref(A, B, bias, C, M, N, K);
1021#endif
1022}
void gemm_nt_q5_k_ref(const float *A, const void *B, const float *bias, float *C, int M, int N, int K)

References C, and gemm_nt_q5_k_ref().

◆ gemm_nt_q5_k_q8_k()

void gemm_nt_q5_k_q8_k ( const void *  A_q8,
const void *  B,
const float *  bias,
float *  C,
int  M,
int  N,
int  K 
)

Definition at line 914 of file gemm_kernels_q5_k.c.

919{
920#if defined(__AVX512F__)
921 /* TODO: AVX-512 implementation */
922 gemm_nt_q5_k_q8_k_ref(A_q8, B, bias, C, M, N, K);
923#elif defined(__AVX2__)
924 /* TODO: AVX-2 implementation */
925 gemm_nt_q5_k_q8_k_ref(A_q8, B, bias, C, M, N, K);
926#elif defined(__AVX__)
927 /* TODO: AVX implementation */
928 gemm_nt_q5_k_q8_k_ref(A_q8, B, bias, C, M, N, K);
929#elif defined(__SSE4_1__)
930 /* TODO: SSE4.1 implementation */
931 gemm_nt_q5_k_q8_k_ref(A_q8, B, bias, C, M, N, K);
932#else
933 gemm_nt_q5_k_q8_k_ref(A_q8, B, bias, C, M, N, K);
934#endif
935}
void gemm_nt_q5_k_q8_k_ref(const void *A_q8, const void *B, const float *bias, float *C, int M, int N, int K)

References C, and gemm_nt_q5_k_q8_k_ref().

◆ gemm_nt_q6_k()

void gemm_nt_q6_k ( const float *  A,
const void *  B,
const float *  bias,
float *  C,
int  M,
int  N,
int  K 
)

Definition at line 212 of file gemm_kernels_q6k.c.

217{
218 if (!A || !B || !C) {
219 return;
220 }
221 if (M <= 0 || N <= 0 || K <= 0) {
222 return;
223 }
224
225 /* gemm_q6_k produces Y as [batch x M_out] where:
226 * batch = M (tokens)
227 * M_out = N (output channels) */
228 gemm_q6_k(C, B, A, /*M_out=*/N, /*N_batch=*/M, K);
229
230 if (!bias) {
231 return;
232 }
233
234 for (int i = 0; i < M; ++i) {
235 float *row = C + (size_t)i * (size_t)N;
236 for (int j = 0; j < N; ++j) {
237 row[j] += bias[j];
238 }
239 }
240}
void gemm_q6_k(float *Y, const void *W, const float *X, int M, int N, int K)

References C, and gemm_q6_k().

Referenced by ck_gemm_nt_quant(), gemm_nt_q6_k_ref(), qwen2_0_5b_decode_layer_0_decode(), qwen2_0_5b_decode_layer_10_decode(), qwen2_0_5b_decode_layer_13_decode(), qwen2_0_5b_decode_layer_16_decode(), qwen2_0_5b_decode_layer_19_decode(), qwen2_0_5b_decode_layer_1_decode(), qwen2_0_5b_decode_layer_21_decode(), qwen2_0_5b_decode_layer_3_decode(), qwen2_0_5b_decode_layer_6_decode(), qwen2_0_5b_decode_layer_7_decode(), qwen2_0_5b_decode_layer_8_decode(), and qwen2_0_5b_decode_layer_9_decode().

◆ gemm_nt_q6_k_q8_k()

void gemm_nt_q6_k_q8_k ( const void *  A_q8,
const void *  B,
const float *  bias,
float *  C,
int  M,
int  N,
int  K 
)

NT GEMM: C = A @ B^T where A is Q8_K and B is Q6_K.

This is the typical inference pattern:

  • A: Activations in Q8_K format [M x K]
  • B: Weights in Q6_K format [N x K]
  • C: Output [M x N]
Parameters
A_q8Input activations in Q8_K format
BWeight matrix in Q6_K format
biasOptional bias vector [N]
COutput matrix
MBatch size (number of tokens)
NOutput dimension
KInput dimension

Definition at line 1515 of file gemm_kernels_q6k_q8k.c.

1520{
1521 if (!A_q8 || !B || !C) {
1522 return;
1523 }
1524 if (M <= 0 || N <= 0 || K <= 0) {
1525 return;
1526 }
1527
1528 /* Prefill GEMM is the hot Qwen2/Qwen3.5 MLP-down path. Keep decode
1529 * gemv_q6_k_q8_k() conservative, but allow GEMM/prefill to use the
1530 * parity-gated SIMD dot helper by default. CK strict parity and
1531 * CK_DEBUG_Q6K_Q8K_REF=1 still force the scalar reference reduction. */
1532 const block_q8_K *A = (const block_q8_K *)A_q8;
1533 const block_q6_K *W = (const block_q6_K *)B;
1534 const int blocks_per_vec = K / QK_K;
1535 const int blocks_per_row = K / QK_K;
1536
1537 for (int m = 0; m < M; ++m) {
1538 const block_q8_K *a_row = A + (size_t)m * (size_t)blocks_per_vec;
1539 float *c_row = C + (size_t)m * (size_t)N;
1540 for (int n = 0; n < N; ++n) {
1541 const block_q6_K *w_row = W + (size_t)n * (size_t)blocks_per_row;
1542 const float b = bias ? bias[n] : 0.0f;
1543 c_row[n] = ck_dot_q6_k_q8_k_fast_or_ref(w_row, a_row, K) + b;
1544 }
1545 }
1546}
static float ck_dot_q6_k_q8_k_fast_or_ref(const block_q6_K *w, const block_q8_K *x, int K)

References C, ck_dot_q6_k_q8_k_fast_or_ref(), and QK_K.

Referenced by gemm_nt_q8_k_mlp_dispatch(), and gemm_nt_q8_k_qkv_dispatch().

◆ gemm_nt_q6_k_q8_k_m4_tile()

void gemm_nt_q6_k_q8_k_m4_tile ( const void *  A_q8,
const void *  B,
const float *  bias,
float *  C,
int  M,
int  N,
int  K,
int  m0,
int  m1,
int  n0,
int  n1 
)

Definition at line 1702 of file gemm_kernels_q6k_q8k.c.

1709{
1710 if (!A_q8 || !B || !C || M <= 0 || N <= 0 || K <= 0 ||
1711 K % QK_K != 0) {
1712 return;
1713 }
1714 if (m0 < 0) m0 = 0;
1715 if (n0 < 0) n0 = 0;
1716 if (m1 > M) m1 = M;
1717 if (n1 > N) n1 = N;
1718 if (m0 >= m1 || n0 >= n1) return;
1719
1720#if defined(__AVX2__)
1722 const block_q8_K *A = (const block_q8_K *)A_q8;
1723 const block_q6_K *W = (const block_q6_K *)B;
1724 const int blocks_per_vec = K / QK_K;
1725 for (int n = n0; n < n1; ++n) {
1726 const block_q6_K *w_row =
1727 W + (size_t)n * (size_t)blocks_per_vec;
1728 const float b = bias ? bias[n] : 0.0f;
1729 int m = m0;
1730 for (; m + 4 <= m1; m += 4) {
1731 float values[4];
1732 dot_q6_k_q8_k_avx2_m4(
1733 w_row, A + (size_t)m * (size_t)blocks_per_vec,
1734 blocks_per_vec, 4, K, values);
1735 for (int r = 0; r < 4; ++r) {
1736 C[(size_t)(m + r) * (size_t)N + (size_t)n] = values[r] + b;
1737 }
1738 }
1739 if (m < m1) {
1740 float values[4];
1741 const int rows = m1 - m;
1742 dot_q6_k_q8_k_avx2_m4(
1743 w_row, A + (size_t)m * (size_t)blocks_per_vec,
1744 blocks_per_vec, rows, K, values);
1745 for (int r = 0; r < rows; ++r) {
1746 C[(size_t)(m + r) * (size_t)N + (size_t)n] = values[r] + b;
1747 }
1748 }
1749 }
1750 return;
1751 }
1752#endif
1754 A_q8, B, bias, C, M, N, K, m0, m1, n0, n1);
1755}
void gemm_nt_q6_k_q8_k_tile(const void *A_q8, const void *B, const float *bias, float *C, int M, int N, int K, int m0, int m1, int n0, int n1)
Compute one C[m0:m1, n0:n1] tile for Q8_K activations x Q6_K weights.

References C, ck_q6k_q8k_force_ref(), ck_strict_parity_enabled(), gemm_nt_q6_k_q8_k_tile(), and QK_K.

◆ gemm_nt_q6_k_q8_k_tile()

void gemm_nt_q6_k_q8_k_tile ( const void *  A_q8,
const void *  B,
const float *  bias,
float *  C,
int  M,
int  N,
int  K,
int  m0,
int  m1,
int  n0,
int  n1 
)

Compute one C[m0:m1, n0:n1] tile for Q8_K activations x Q6_K weights.

Pure tile math only: no threadpool, no global scheduling, no allocation. The orchestrator decides how to split tile jobs across cores.

Definition at line 1665 of file gemm_kernels_q6k_q8k.c.

1672{
1673 if (!A_q8 || !B || !C) {
1674 return;
1675 }
1676 if (M <= 0 || N <= 0 || K <= 0 || K % QK_K != 0) {
1677 return;
1678 }
1679 if (m0 < 0) m0 = 0;
1680 if (n0 < 0) n0 = 0;
1681 if (m1 > M) m1 = M;
1682 if (n1 > N) n1 = N;
1683 if (m0 >= m1 || n0 >= n1) {
1684 return;
1685 }
1686
1687 const block_q8_K *A = (const block_q8_K *)A_q8;
1688 const block_q6_K *W = (const block_q6_K *)B;
1689 const int blocks_per_vec = K / QK_K;
1690 const int blocks_per_row = K / QK_K;
1691
1692 for (int n = n0; n < n1; ++n) {
1693 const block_q6_K *w_row = W + (size_t)n * (size_t)blocks_per_row;
1694 const float b = bias ? bias[n] : 0.0f;
1695 for (int m = m0; m < m1; ++m) {
1696 const block_q8_K *a_row = A + (size_t)m * (size_t)blocks_per_vec;
1697 C[(size_t)m * (size_t)N + (size_t)n] = ck_dot_q6_k_q8_k_fast_or_ref(w_row, a_row, K) + b;
1698 }
1699 }
1700}

References C, ck_dot_q6_k_q8_k_fast_or_ref(), and QK_K.

Referenced by gemm_nt_q6_k_q8_k_m4_tile(), and gemm_nt_q6_k_q8_k_tiled().

◆ gemm_nt_q6_k_q8_k_tiled()

void gemm_nt_q6_k_q8_k_tiled ( const void *  A_q8,
const void *  B,
const float *  bias,
float *  C,
int  M,
int  N,
int  K 
)

Experimental single-thread tiled NT GEMM wrapper.

Kept as a separate symbol from gemm_nt_q6_k_q8_k for benchmarks and parity. Production prefill should prefer the v8 2D tile scheduler when enabled.

Definition at line 1763 of file gemm_kernels_q6k_q8k.c.

1768{
1769 enum { TILE_M = 8, TILE_N = 16 };
1770 for (int n0 = 0; n0 < N; n0 += TILE_N) {
1771 const int n1 = (n0 + TILE_N < N) ? (n0 + TILE_N) : N;
1772 for (int m0 = 0; m0 < M; m0 += TILE_M) {
1773 const int m1 = (m0 + TILE_M < M) ? (m0 + TILE_M) : M;
1774 gemm_nt_q6_k_q8_k_tile(A_q8, B, bias, C, M, N, K, m0, m1, n0, n1);
1775 }
1776 }
1777}

References C, and gemm_nt_q6_k_q8_k_tile().

◆ gemm_nt_q8_0()

void gemm_nt_q8_0 ( const float *  A,
const void *  B,
const float *  bias,
float *  C,
int  M,
int  N,
int  K 
)

Definition at line 879 of file gemm_kernels_q8_0.c.

884{
885#if defined(__AVX512F__)
886 if (ck_q8_0_fp32_m4n4_enabled() && M >= 4 && N >= 4 && K % QK8_0 == 0) {
887 gemm_nt_q8_0_m4n4_avx512(A, B, bias, C, M, N, K);
888 return;
889 }
890#endif
891 gemm_nt_q8_0_rowloop(A, B, bias, C, M, N, K);
892}
static void gemm_nt_q8_0_rowloop(const float *A, const void *B, const float *bias, float *C, int M, int N, int K)
Matrix-matrix multiply: C[M,N] = A[M,K] @ B[N,K]^T + bias.
static int ck_q8_0_fp32_m4n4_enabled(void)

References C, ck_q8_0_fp32_m4n4_enabled(), gemm_nt_q8_0_rowloop(), and QK8_0.

Referenced by ck_gemm_nt_quant(), qwen2_0_5b_decode_decode_token(), qwen2_0_5b_decode_forward_prefill_impl(), qwen2_0_5b_decode_layer_0_decode(), qwen2_0_5b_decode_layer_10_decode(), qwen2_0_5b_decode_layer_13_decode(), qwen2_0_5b_decode_layer_16_decode(), qwen2_0_5b_decode_layer_19_decode(), qwen2_0_5b_decode_layer_1_decode(), qwen2_0_5b_decode_layer_21_decode(), qwen2_0_5b_decode_layer_3_decode(), qwen2_0_5b_decode_layer_6_decode(), qwen2_0_5b_decode_layer_7_decode(), qwen2_0_5b_decode_layer_8_decode(), and qwen2_0_5b_decode_layer_9_decode().

◆ gemm_nt_q8_0_q8_0()

void gemm_nt_q8_0_q8_0 ( const void *  A,
const void *  B,
const float *  bias,
float *  C,
int  M,
int  N,
int  K 
)

gemm_nt_q8_0_q8_0 with optional bias (matches header signature)

C[m,n] = A[m,K] @ B[n,K]^T + bias[n]

Definition at line 552 of file gemm_batch_int8.c.

558{
559 /* First compute GEMM */
560#if defined(__AVX2__)
561 /*
562 * The production contract is bit-exact with llama.cpp's eight-lane
563 * FP32 accumulation tree. AVX-512/VNNI changes the integer dot, but it
564 * must not silently replace that FP32 reduction with the scalar-per-block
565 * candidate above. The AVX2-named entry point delegates each activation
566 * row to the certified x4 provider, which also uses VNNI instructions when
567 * they are available while preserving the declared reduction order.
568 */
569 gemm_nt_q8_0_q8_0_avx2(A, B, C, M, N, K);
570#elif defined(__AVX__)
571 gemm_nt_q8_0_q8_0_avx(A, B, C, M, N, K);
572#else
573 gemm_nt_q8_0_q8_0_ref(A, B, C, M, N, K);
574#endif
575
576 /* Add bias if provided */
577 if (bias != NULL) {
578 for (int m = 0; m < M; m++) {
579 for (int n = 0; n < N; n++) {
580 C[(size_t)m * N + n] += bias[n];
581 }
582 }
583 }
584}
void gemm_nt_q8_0_q8_0_ref(const void *A, const void *B, float *C, int M, int N, int K)
Scalar reference: gemm_nt_q8_0_q8_0.

References C, and gemm_nt_q8_0_q8_0_ref().

Referenced by gemm_nt_q8_0_dispatch(), and gemm_nt_q8_0_mlp_dispatch().

◆ gemm_nt_q8_0_q8_0_contract()

void gemm_nt_q8_0_q8_0_contract ( const float *  A,
const void *  B,
const float *  bias,
float *  C,
int  M,
int  N,
int  K 
)

Definition at line 414 of file gemm_kernels_q8_0_q8_0_contract.c.

421{
422 if (!A || !B || !C || M <= 0 || N <= 0 || K <= 0) {
423 return;
424 }
425
426 const float *A_use = A;
427 const int strict = ck_strict_parity_enabled();
428 const int dump_enabled = strict && ck_q80_contract_dump_enabled();
429 int strict_cached_layer = -1;
430 int strict_dump_layer = -1;
432 const float *cached = ck_strict_consume_next_gemm_a((size_t) M * (size_t) K);
433 if (cached) {
434 A_use = cached;
435 strict_cached_layer = ck_q80_contract_cached_gemm_seq++;
436 }
437 }
438 if (dump_enabled) {
439 strict_dump_layer = strict_cached_layer >= 0
440 ? strict_cached_layer
442 }
443
444 if (dump_enabled && strict_dump_layer >= 0) {
445 ck_q80_contract_dump_tensor(strict_cached_layer >= 0
446 ? "strict_out_proj_input_cached"
447 : "strict_out_proj_input_live",
448 strict_dump_layer,
449 A_use,
450 (size_t) M * (size_t) K);
451 }
452
453 if (strict &&
454 gemm_nt_q8_0_q8_0_ggml_strict(A_use, B, bias, C, M, N, K)) {
455 if (dump_enabled && strict_dump_layer >= 0) {
456 ck_q80_contract_dump_tensor("strict_out_proj_output_ggml",
457 strict_dump_layer,
458 C,
459 (size_t) M * (size_t) N);
460 }
461 return;
462 }
463
464 if (!strict) {
465#pragma omp parallel for schedule(static) if(M > 1)
466 for (int m = 0; m < M; ++m) {
467 gemv_q8_0_q8_0_contract(&C[m * N], B, &A_use[m * K], N, K);
468 if (bias) {
469 for (int n = 0; n < N; ++n) {
470 C[m * N + n] += bias[n];
471 }
472 }
473 }
474 return;
475 }
476
477 for (int m = 0; m < M; ++m) {
478 gemv_q8_0_q8_0_contract(&C[m * N], B, &A_use[m * K], N, K);
479 if (bias) {
480 for (int n = 0; n < N; ++n) {
481 C[m * N + n] += bias[n];
482 }
483 }
484 }
485
486 if (dump_enabled && strict_dump_layer >= 0) {
487 ck_q80_contract_dump_tensor("strict_out_proj_output_fallback",
488 strict_dump_layer,
489 C,
490 (size_t) M * (size_t) N);
491 }
492}
const float * ck_strict_consume_next_gemm_a(size_t elems)
static int gemm_nt_q8_0_q8_0_ggml_strict(const float *A, const void *B, const float *bias, float *C, int M, int N, int K)
void gemv_q8_0_q8_0_contract(float *y, const void *W, const float *x, int M, int K)
static int ck_q80_contract_cached_input_enabled(void)
static void ck_q80_contract_dump_tensor(const char *name, int layer_id, const float *data, size_t elem_count)
static int ck_q80_contract_cached_gemm_seq
static int ck_q80_contract_dump_enabled(void)

References C, ck_q80_contract_cached_gemm_seq, ck_q80_contract_cached_input_enabled(), ck_q80_contract_dump_enabled(), ck_q80_contract_dump_tensor(), ck_strict_consume_next_gemm_a(), ck_strict_parity_enabled(), gemm_nt_q8_0_q8_0_ggml_strict(), and gemv_q8_0_q8_0_contract().

◆ gemm_nt_q8_0_q8_0_m2n4()

void gemm_nt_q8_0_q8_0_m2n4 ( const void *  A_q8,
const void *  B,
const float *  bias,
float *  C,
int  M,
int  N,
int  K 
)

Definition at line 586 of file gemm_batch_int8.c.

592{
593 gemm_q8_0_q8_0_m2n4(C, B, A, M, N, K);
594 if (bias != NULL) {
595 for (int m = 0; m < M; ++m) {
596 for (int n = 0; n < N; ++n) {
597 C[(size_t)m * (size_t)N + n] += bias[n];
598 }
599 }
600 }
601}
void gemm_q8_0_q8_0_m2n4(float *C, const void *W, const void *A_q8, int M, int N, int K)

References C, and gemm_q8_0_q8_0_m2n4().

◆ gemm_nt_q8_0_q8_0_m2n4_tile()

void gemm_nt_q8_0_q8_0_m2n4_tile ( const void *  A_q8,
const void *  B,
const float *  bias,
float *  C,
int  M,
int  N,
int  K,
int  ldc 
)

Definition at line 603 of file gemm_batch_int8.c.

609{
610 gemm_q8_0_q8_0_m2n4_strided(C, ldc, B, A, M, N, K);
611 if (bias != NULL) {
612 for (int m = 0; m < M; ++m) {
613 for (int n = 0; n < N; ++n) {
614 C[(size_t)m * (size_t)ldc + n] += bias[n];
615 }
616 }
617 }
618}
void gemm_q8_0_q8_0_m2n4_strided(float *C, int ldc, const void *W, const void *A_q8, int M, int N, int K)

References C, and gemm_q8_0_q8_0_m2n4_strided().

◆ gemm_q4_k()

void gemm_q4_k ( float *  Y,
const void *  W,
const float *  X,
int  M,
int  N,
int  K 
)

Auto-dispatch GEMM based on available SIMD.

Definition at line 486 of file gemm_kernels_q4k.c.

490{
491 /* Use reference implementation for correctness
492 * TODO: Fix AVX-512 version to match llama.cpp layout */
493 gemm_q4_k_ref(Y, W, X, M, N, K);
494}
void gemm_q4_k_ref(float *Y, const void *W, const float *X, int M, int N, int K)
Matrix-matrix multiply with Q4_K weights (scalar reference)

References gemm_q4_k_ref().

Referenced by gemm_nt_q4_k().

◆ gemm_q4_k_q8_k()

void gemm_q4_k_q8_k ( float *  Y,
const void *  W,
const void *  X_q8,
int  M,
int  N,
int  K 
)

Definition at line 354 of file gemm_kernels_q4k_q8k.c.

358{
359 if (!Y || !W || !X_q8 || M <= 0 || N <= 0 || K <= 0) {
360 return;
361 }
362
363 const block_q8_K *X = (const block_q8_K *)X_q8;
364 const int blocks_per_vec = K / QK_K;
365 const int blocks_per_row = K / QK_K;
366 const size_t work_items = (size_t)M * (size_t)N;
367
368 if (work_items >= 4096u && M >= 512 && N > 1) {
369 ck_threadpool_t *pool = ck_threadpool_global();
370 const int pool_threads = pool ? ck_threadpool_n_threads(pool) : 1;
371 int active_threads = pool_threads;
372 if (active_threads > M) {
373 active_threads = M;
374 }
375 if (active_threads > 1) {
376 gemm_q4_k_q8_k_work_t work = {
377 .Y = Y,
378 .W = W,
379 .X = X,
380 .M_out = M,
381 .N_batch = N,
382 .K = K,
383 .blocks_per_vec = blocks_per_vec,
384 .blocks_per_row = blocks_per_row,
385 };
386 ck_threadpool_dispatch_n(pool, active_threads, gemm_q4_k_q8_k_thread_fn, &work);
387 return;
388 }
389 }
390
391 for (int n = 0; n < N; ++n) {
392 const block_q8_K *x_row = X + (size_t)n * (size_t)blocks_per_vec;
393 gemv_q4_k_q8_k(&Y[n * M], W, x_row, M, K);
394 }
395}
void gemv_q4_k_q8_k(float *y, const void *W, const void *x_q8, int M, int K)
static void gemm_q4_k_q8_k_thread_fn(int ith, int nth, void *args)

References ck_threadpool_dispatch_n(), ck_threadpool_global(), ck_threadpool_n_threads(), gemm_q4_k_q8_k_thread_fn(), gemv_q4_k_q8_k(), and QK_K.

Referenced by gemm_nt_q4_k_q8_k().

◆ gemm_q6_k()

void gemm_q6_k ( float *  Y,
const void *  W,
const float *  X,
int  M,
int  N,
int  K 
)

Definition at line 195 of file gemm_kernels_q6k.c.

199{
200 if (!Y || !W || !X) {
201 return;
202 }
203 if (M <= 0 || N <= 0 || K <= 0) {
204 return;
205 }
206
207 for (int n = 0; n < N; ++n) {
208 gemv_q6_k(&Y[n * M], W, &X[n * K], M, K);
209 }
210}
void gemv_q6_k(float *y, const void *W, const float *x, int M, int K)

References gemv_q6_k().

Referenced by gemm_nt_q6_k().

◆ gemm_q6_k_q8_k()

void gemm_q6_k_q8_k ( float *  Y,
const void *  W,
const void *  X_q8,
int  M,
int  N,
int  K 
)

GEMM: Y = W @ X^T where W is Q6_K and X is Q8_K.

Parameters
YOutput matrix [N x M] in row-major
WWeight matrix in Q6_K format [M x K]
X_q8Input matrix in Q8_K format [N x K]
MNumber of output rows (output dim)
NNumber of input vectors (batch size)
KInput dimension

Definition at line 1481 of file gemm_kernels_q6k_q8k.c.

1485{
1486 if (!Y || !W || !X_q8 || M <= 0 || N <= 0 || K <= 0) {
1487 return;
1488 }
1489
1490 const block_q8_K *X = (const block_q8_K *)X_q8;
1491 const int blocks_per_vec = K / QK_K;
1492
1493 for (int n = 0; n < N; ++n) {
1494 const block_q8_K *x_row = X + (size_t)n * (size_t)blocks_per_vec;
1495 gemv_q6_k_q8_k(&Y[n * M], W, x_row, M, K);
1496 }
1497}
void gemv_q6_k_q8_k(float *y, const void *W, const void *x_q8, int M, int K)
GEMV: y = W @ x where W is Q6_K and x is Q8_K.

References gemv_q6_k_q8_k(), and QK_K.

◆ gemm_swiglu_fused()

void gemm_swiglu_fused ( const float *  x,
const float *  W_gate,
const float *  W_up,
const float *  b_gate,
const float *  b_up,
float *  output,
int  M,
int  N,
int  K 
)

Definition at line 241 of file gemm_fused_kernels.c.

248{
249#if defined(__AVX__)
250#pragma omp parallel for
251 for (int i = 0; i < M; i++) {
252 const float *x_row = &x[i * K];
253 float *out_row = &output[i * N];
254
255 for (int j = 0; j < N; j++) {
256 const float *w_gate_row = &W_gate[j * K];
257 const float *w_up_row = &W_up[j * K];
258
259 // Compute both dot products in parallel using SIMD
260 __m256 gate_vec = _mm256_setzero_ps();
261 __m256 up_vec = _mm256_setzero_ps();
262
263 int k;
264 for (k = 0; k <= K - 8; k += 8) {
265 __m256 x_vec = _mm256_loadu_ps(&x_row[k]);
266 __m256 wg_vec = _mm256_loadu_ps(&w_gate_row[k]);
267 __m256 wu_vec = _mm256_loadu_ps(&w_up_row[k]);
268
269 // gate += x * W_gate
270 gate_vec = _mm256_add_ps(gate_vec, _mm256_mul_ps(x_vec, wg_vec));
271 // up += x * W_up
272 up_vec = _mm256_add_ps(up_vec, _mm256_mul_ps(x_vec, wu_vec));
273 }
274
275 // Horizontal sum
276 float gate = hsum256_ps_fused(gate_vec);
277 float up = hsum256_ps_fused(up_vec);
278
279 // Scalar remainder
280 for (; k < K; k++) {
281 gate += x_row[k] * w_gate_row[k];
282 up += x_row[k] * w_up_row[k];
283 }
284
285 // Add biases
286 if (b_gate) gate += b_gate[j];
287 if (b_up) up += b_up[j];
288
289 // SwiGLU: SiLU(gate) * up = gate * sigmoid(gate) * up
290 float sig = 1.0f / (1.0f + expf(-gate));
291 out_row[j] = gate * sig * up;
292 }
293 }
294#else
295 // Scalar fallback
296#pragma omp parallel for
297 for (int i = 0; i < M; i++) {
298 for (int j = 0; j < N; j++) {
299 float gate = 0.0f;
300 float up = 0.0f;
301
302 for (int k = 0; k < K; k++) {
303 gate += x[i * K + k] * W_gate[j * K + k];
304 up += x[i * K + k] * W_up[j * K + k];
305 }
306
307 if (b_gate) gate += b_gate[j];
308 if (b_up) up += b_up[j];
309
310 // SwiGLU: SiLU(gate) * up
311 float sig = 1.0f / (1.0f + expf(-gate));
312 output[i * N + j] = gate * sig * up;
313 }
314 }
315#endif
316}

Referenced by ck_mlp_swiglu_forward_fused_token().

◆ gemm_tn_avx512()

void gemm_tn_avx512 ( const float *  A,
const float *  B,
const float *  bias,
float *  C,
int  M,
int  N,
int  K 
)

Definition at line 709 of file gemm_kernels.c.

714{
716 gemm_tn_serial_double(A, B, bias, C, M, N, K);
717 return;
718 }
719#if defined(__AVX512F__)
720 // Vectorize over N (output columns)
721#pragma omp parallel for
722 for (int i = 0; i < M; i++) {
723 int j = 0;
724 for (; j <= N - 16; j += 16) {
725 __m512 sum_vec = bias ? _mm512_loadu_ps(&bias[j]) : _mm512_setzero_ps();
726 for (int k = 0; k < K; k++) {
727 __m512 a_broadcast = _mm512_set1_ps(A[k * M + i]);
728 __m512 b_vec = _mm512_loadu_ps(&B[k * N + j]);
729 sum_vec = _mm512_fmadd_ps(a_broadcast, b_vec, sum_vec);
730 }
731 _mm512_storeu_ps(&C[i * N + j], sum_vec);
732 }
733 for (; j < N; j++) {
734 float sum = bias ? bias[j] : 0.0f;
735 for (int k = 0; k < K; k++) {
736 sum += A[k * M + i] * B[k * N + j];
737 }
738 C[i * N + j] = sum;
739 }
740 }
741#elif defined(__AVX__)
742 // AVX1: vectorize over N (8 columns at a time)
743#pragma omp parallel for
744 for (int i = 0; i < M; i++) {
745 int j = 0;
746 for (; j <= N - 8; j += 8) {
747 __m256 sum_vec = bias ? _mm256_loadu_ps(&bias[j]) : _mm256_setzero_ps();
748 for (int k = 0; k < K; k++) {
749 __m256 a_broadcast = _mm256_set1_ps(A[k * M + i]);
750 __m256 b_vec = _mm256_loadu_ps(&B[k * N + j]);
751 __m256 prod = _mm256_mul_ps(a_broadcast, b_vec);
752 sum_vec = _mm256_add_ps(sum_vec, prod);
753 }
754 _mm256_storeu_ps(&C[i * N + j], sum_vec);
755 }
756 for (; j < N; j++) {
757 float sum = bias ? bias[j] : 0.0f;
758 for (int k = 0; k < K; k++) {
759 sum += A[k * M + i] * B[k * N + j];
760 }
761 C[i * N + j] = sum;
762 }
763 }
764#else
765 gemm_tn_parallel(A, B, bias, C, M, N, K);
766#endif
767}
void gemm_tn_parallel(const float *A, const float *B, const float *bias, float *C, int M, int N, int K)
static void gemm_tn_serial_double(const float *A, const float *B, const float *bias, float *C, int M, int N, int K)

References C, ck_strict_parity_enabled(), gemm_tn_parallel(), and gemm_tn_serial_double().

◆ gemm_tn_blocked()

void gemm_tn_blocked ( const float *  A,
const float *  B,
const float *  bias,
float *  C,
int  M,
int  N,
int  K 
)

Definition at line 769 of file gemm_kernels.c.

774{
776 gemm_tn_serial_double(A, B, bias, C, M, N, K);
777 return;
778 }
779#if defined(__AVX512F__)
780 const int block_size = 64;
781#elif defined(__AVX__)
782 const int block_size = 32;
783#else
784 const int block_size = 32;
785#endif
786 // Initialize C with bias (parallelized)
787#pragma omp parallel for
788 for (int i = 0; i < M; i++) {
789 for (int j = 0; j < N; j++) {
790 C[i * N + j] = bias ? bias[j] : 0.0f;
791 }
792 }
793 // Blocked multiply-accumulate (parallelized over M blocks)
794#pragma omp parallel for
795 for (int ii = 0; ii < M; ii += block_size) {
796 for (int kk = 0; kk < K; kk += block_size) {
797 for (int jj = 0; jj < N; jj += block_size) {
798 int i_end = ck_min(ii + block_size, M);
799 int k_end = ck_min(kk + block_size, K);
800 int j_end = ck_min(jj + block_size, N);
801
802 for (int k = kk; k < k_end; k++) {
803 for (int i = ii; i < i_end; i++) {
804 float a_val = A[k * M + i];
805#if defined(__AVX512F__)
806 __m512 a_broadcast = _mm512_set1_ps(a_val);
807 int j;
808 for (j = jj; j <= j_end - 16; j += 16) {
809 __m512 b_vec = _mm512_loadu_ps(&B[k * N + j]);
810 __m512 c_vec = _mm512_loadu_ps(&C[i * N + j]);
811 c_vec = _mm512_fmadd_ps(a_broadcast, b_vec, c_vec);
812 _mm512_storeu_ps(&C[i * N + j], c_vec);
813 }
814 for (; j < j_end; j++) {
815 C[i * N + j] += a_val * B[k * N + j];
816 }
817#elif defined(__AVX__)
818 __m256 a_broadcast = _mm256_set1_ps(a_val);
819 int j;
820 for (j = jj; j <= j_end - 8; j += 8) {
821 __m256 b_vec = _mm256_loadu_ps(&B[k * N + j]);
822 __m256 c_vec = _mm256_loadu_ps(&C[i * N + j]);
823 __m256 prod = _mm256_mul_ps(a_broadcast, b_vec);
824 c_vec = _mm256_add_ps(c_vec, prod);
825 _mm256_storeu_ps(&C[i * N + j], c_vec);
826 }
827 for (; j < j_end; j++) {
828 C[i * N + j] += a_val * B[k * N + j];
829 }
830#else
831 for (int j = jj; j < j_end; j++) {
832 C[i * N + j] += a_val * B[k * N + j];
833 }
834#endif
835 }
836 }
837 }
838 }
839 }
840}

References C, ck_min(), ck_strict_parity_enabled(), and gemm_tn_serial_double().

◆ gemm_tn_parallel()

void gemm_tn_parallel ( const float *  A,
const float *  B,
const float *  bias,
float *  C,
int  M,
int  N,
int  K 
)

Definition at line 687 of file gemm_kernels.c.

692{
694 gemm_tn_serial_double(A, B, bias, C, M, N, K);
695 return;
696 }
697#pragma omp parallel for
698 for (int i = 0; i < M; i++) {
699 for (int j = 0; j < N; j++) {
700 float sum = bias ? bias[j] : 0.0f;
701 for (int k = 0; k < K; k++) {
702 sum += A[k * M + i] * B[k * N + j];
703 }
704 C[i * N + j] = sum;
705 }
706 }
707}

References C, ck_strict_parity_enabled(), and gemm_tn_serial_double().

Referenced by fc1_backward_kernel(), fc2_backward_kernel(), and gemm_tn_avx512().

◆ gemma4_final_logit_softcap_forward()

void gemma4_final_logit_softcap_forward ( float *  logits,
int  tokens,
int  vocab_size,
float  cap 
)

Definition at line 405 of file gemma4_per_layer_embed.c.

409{
410 if (!logits || tokens <= 0 || vocab_size <= 0 || cap <= 0.0f) {
411 return;
412 }
413 const float inv_cap = 1.0f / cap;
414 const size_t total = (size_t)tokens * (size_t)vocab_size;
415 for (size_t i = 0; i < total; ++i) {
416 logits[i] = tanhf(logits[i] * inv_cap) * cap;
417 }
418}

References vocab_size.

◆ gemma4_per_layer_embed_forward()

void gemma4_per_layer_embed_forward ( float *  hidden,
const float *  per_layer_input,
const float *  inp_gate,
const float *  proj,
const float *  post_norm,
const float *  out_scale,
int  tokens,
int  layer,
int  num_layers,
int  embed_dim,
int  per_layer_dim,
float  eps 
)

Definition at line 348 of file gemma4_per_layer_embed.c.

360{
361 if (!hidden || !per_layer_input || !inp_gate || !proj || !post_norm ||
362 tokens <= 0 || layer < 0 || layer >= num_layers || embed_dim <= 0 ||
363 per_layer_dim != QK_K || embed_dim > 4096) {
364 return;
365 }
366
367 ck_gemma4_embed_args_t args = {
368 .hidden = hidden,
369 .per_layer_input = per_layer_input,
370 .inp_gate = inp_gate,
371 .proj = proj,
372 .post_norm = post_norm,
373 .out_scale = out_scale,
374 .layer = layer,
375 .num_layers = num_layers,
376 .embed_dim = embed_dim,
377 .per_layer_dim = per_layer_dim,
378 .eps = eps,
379 };
380 ck_threadpool_t *pool = ck_threadpool_global();
381 int active = pool ? ck_threadpool_n_threads(pool) : 1;
382 const char *disabled = getenv("CK_DISABLE_GEMMA4_EMBED_PARALLEL");
383 if (disabled && disabled[0] && strcmp(disabled, "0") != 0) active = 1;
384 if (active > tokens) active = tokens;
386 pool, active, 0, tokens, 1, ck_gemma4_embed_range, &args);
387}
static void ck_gemma4_embed_range(int begin, int end, void *opaque)

References ck_gemma4_embed_range(), ck_threadpool_global(), ck_threadpool_n_threads(), ck_threadpool_parallel_for_n(), and QK_K.

◆ gemma4_per_layer_prepare_bf16_forward()

void gemma4_per_layer_prepare_bf16_forward ( float *  per_layer_input,
const float *  hidden,
const int32_t *  token_ids,
const uint16_t *  per_layer_token_emb,
const uint16_t *  per_layer_model_proj,
const float *  per_layer_proj_norm,
int  tokens,
int  num_layers,
int  embed_dim,
int  per_layer_dim,
int  vocab_size,
float  eps 
)

Definition at line 254 of file gemma4_per_layer_embed.c.

266{
267 if (!per_layer_input || !hidden || !token_ids || !per_layer_token_emb ||
268 !per_layer_model_proj || !per_layer_proj_norm || tokens <= 0 ||
269 num_layers <= 0 || embed_dim <= 0 || per_layer_dim <= 0 || vocab_size <= 0) {
270 return;
271 }
272
273 if (per_layer_dim > QK_K) {
274 return;
275 }
276 ck_gemma4_prepare_args_t args = {
277 .per_layer_input = per_layer_input,
278 .hidden = hidden,
279 .token_ids = token_ids,
280 .per_layer_token_emb = per_layer_token_emb,
281 .per_layer_model_proj = per_layer_model_proj,
282 .per_layer_proj_norm = per_layer_proj_norm,
283 .num_layers = num_layers,
284 .embed_dim = embed_dim,
285 .per_layer_dim = per_layer_dim,
286 .vocab_size = vocab_size,
287 .eps = eps,
288 };
290}
static void ck_gemma4_prepare_parallel(int tokens, ck_range_fn_t fn, ck_gemma4_prepare_args_t *args)
static void ck_gemma4_prepare_bf16_range(int begin, int end, void *opaque)

References ck_gemma4_prepare_bf16_range(), ck_gemma4_prepare_parallel(), QK_K, and vocab_size.

◆ gemma4_per_layer_prepare_forward()

void gemma4_per_layer_prepare_forward ( float *  per_layer_input,
const float *  hidden,
const int32_t *  token_ids,
const void *  per_layer_token_emb,
const uint16_t *  per_layer_model_proj,
const float *  per_layer_proj_norm,
int  tokens,
int  num_layers,
int  embed_dim,
int  per_layer_dim,
int  vocab_size,
float  eps 
)

Definition at line 218 of file gemma4_per_layer_embed.c.

230{
231 if (!per_layer_input || !hidden || !token_ids || !per_layer_token_emb ||
232 !per_layer_model_proj || !per_layer_proj_norm || tokens <= 0 ||
233 num_layers <= 0 || embed_dim <= 0 || per_layer_dim != QK_K || vocab_size <= 0) {
234 return;
235 }
236
237 ck_gemma4_prepare_args_t args = {
238 .per_layer_input = per_layer_input,
239 .hidden = hidden,
240 .token_ids = token_ids,
241 .per_layer_token_emb = per_layer_token_emb,
242 .per_layer_model_proj = per_layer_model_proj,
243 .per_layer_proj_norm = per_layer_proj_norm,
244 .num_layers = num_layers,
245 .embed_dim = embed_dim,
246 .per_layer_dim = per_layer_dim,
247 .vocab_size = vocab_size,
248 .eps = eps,
249 };
251}
static void ck_gemma4_prepare_q5_range(int begin, int end, void *opaque)

References ck_gemma4_prepare_parallel(), ck_gemma4_prepare_q5_range(), QK_K, and vocab_size.

◆ gemma4_v_norm_forward()

void gemma4_v_norm_forward ( const float *  input,
float *  output,
float *  rstd_cache,
int  tokens,
int  num_kv_heads,
int  head_dim,
float  eps 
)

Definition at line 687 of file rmsnorm_kernels.c.

694{
695 if (!input || !output || tokens <= 0 || num_kv_heads <= 0 || head_dim <= 0) {
696 return;
697 }
698 rmsnorm_forward_no_weight(input, output, rstd_cache,
699 tokens * num_kv_heads, head_dim, head_dim, eps);
700}
void rmsnorm_forward_no_weight(const float *input, float *output, float *rstd_cache, int tokens, int d_model, int aligned_embed_dim, float eps)

References rmsnorm_forward_no_weight().

◆ gemma4_v_norm_forward_parallel_dispatch()

void gemma4_v_norm_forward_parallel_dispatch ( const float *  input,
float *  output,
float *  rstd_cache,
int  tokens,
int  num_kv_heads,
int  head_dim,
float  eps 
)

◆ gemma4_vision_projector_prep_forward()

void gemma4_vision_projector_prep_forward ( const float *  input,
float *  output,
int  tokens,
int  dim,
float  scale,
float  eps 
)

Definition at line 633 of file vision_kernels.c.

639{
640 if (input == NULL || output == NULL || tokens <= 0 || dim <= 0) return;
641 if (eps <= 0.0f) eps = 1.0e-6f;
642 for (int t = 0; t < tokens; ++t) {
643 const float *src = input + (size_t)t * (size_t)dim;
644 float *dst = output + (size_t)t * (size_t)dim;
645 double ss = 0.0;
646 for (int i = 0; i < dim; ++i) {
647 const float v = src[i] * scale;
648 ss += (double)v * (double)v;
649 }
650 const float inv_rms = 1.0f / sqrtf((float)(ss / (double)dim) + eps);
651 for (int i = 0; i < dim; ++i) {
652 dst[i] = (src[i] * scale) * inv_rms;
653 }
654 }
655}

◆ gemv_bf16()

void gemv_bf16 ( float *  y,
const void *  W,
const float *  x,
int  M,
int  K 
)

Definition at line 622 of file gemm_kernels_bf16.c.

626{
628 y, (const uint16_t *)W, x, M, K, 0, M);
629}
static void gemv_bf16_row_range(float *y, const uint16_t *w, const float *x, int M, int K, int row_begin, int row_end)

References gemv_bf16_row_range().

Referenced by gemv_bf16_parallel_dispatch().

◆ gemv_bf16_bf16_storage()

void gemv_bf16_bf16_storage ( float *  y,
const void *  W,
const float *  x,
int  M,
int  K 
)

Definition at line 712 of file gemm_kernels_bf16.c.

716{
718}
void gemv_bf16_bf16_storage_parallel_dispatch(float *y, const void *W, const float *x, int M, int K)

References gemv_bf16_bf16_storage_parallel_dispatch().

◆ gemv_bf16_bf16_storage_parallel_dispatch()

void gemv_bf16_bf16_storage_parallel_dispatch ( float *  y,
const void *  W,
const float *  x,
int  M,
int  K 
)

Definition at line 688 of file gemm_kernels_bf16.c.

692{
693 ck_threadpool_t *pool = ck_threadpool_global();
694 if (!pool || ck_threadpool_n_threads(pool) <= 1 || M < 2 ||
695 (size_t)M * (size_t)K <= 65536) {
697 y, (const uint16_t *)W, x, M, K, 0, M);
698 return;
699 }
700
701 ck_gemv_bf16_args_t args = {
702 .y = y, .w = (const uint16_t *)W, .x = x, .M = M, .K = K,
703 };
704 int active = ck_threadpool_n_threads(pool);
705 if (active > M) active = M;
706 int grain = M / (active * 4);
707 if (grain < 1) grain = 1;
709 pool, active, 0, M, grain, ck_gemv_bf16_storage_rows, &args);
710}
static void gemv_bf16_bf16_storage_row_range(float *y, const uint16_t *w, const float *x, int M, int K, int row_begin, int row_end)
static void ck_gemv_bf16_storage_rows(int begin, int end, void *opaque)

References ck_gemv_bf16_storage_rows(), ck_threadpool_global(), ck_threadpool_n_threads(), ck_threadpool_parallel_for_n(), and gemv_bf16_bf16_storage_row_range().

Referenced by gemv_bf16_bf16_storage().

◆ gemv_bf16_parallel_dispatch()

void gemv_bf16_parallel_dispatch ( float *  y,
const void *  W,
const float *  x,
int  M,
int  K 
)

Definition at line 646 of file gemm_kernels_bf16.c.

650{
651 ck_threadpool_t *pool = ck_threadpool_global();
652 if (!pool || ck_threadpool_n_threads(pool) <= 1 || M < 2 ||
653 (size_t)M * (size_t)K <= 65536) {
654 gemv_bf16(y, W, x, M, K);
655 return;
656 }
657
658 ck_gemv_bf16_args_t args = {
659 .y = y, .w = (const uint16_t *)W, .x = x, .M = M, .K = K,
660 };
661 int active = ck_threadpool_n_threads(pool);
662 if (active > M) active = M;
663 int grain = M / (active * 4);
664 if (grain < 1) grain = 1;
666 pool, active, 0, M, grain, ck_gemv_bf16_rows, &args);
667}
static void ck_gemv_bf16_rows(int begin, int end, void *opaque)
void gemv_bf16(float *y, const void *W, const float *x, int M, int K)

References ck_gemv_bf16_rows(), ck_threadpool_global(), ck_threadpool_n_threads(), ck_threadpool_parallel_for_n(), and gemv_bf16().

◆ gemv_fused_q5_0_bias_dispatch()

void gemv_fused_q5_0_bias_dispatch ( float *  y,
const void *  W,
const float *  x,
const float *  bias,
int  M,
int  K 
)

Definition at line 510 of file gemv_fused_quant_bias.c.

517{
518#if defined(__AVX__)
519 gemv_fused_q5_0_bias_avx(y, W, x, bias, M, K);
520#else
521 gemv_fused_q5_0_bias(y, W, x, bias, M, K);
522#endif
523}
void gemv_fused_q5_0_bias(float *y, const void *W, const float *x, const float *bias, int M, int K)

References gemv_fused_q5_0_bias().

◆ gemv_fused_q8_0_bias_dispatch()

void gemv_fused_q8_0_bias_dispatch ( float *  y,
const void *  W,
const float *  x,
const float *  bias,
int  M,
int  K 
)

Definition at line 525 of file gemv_fused_quant_bias.c.

532{
533#if defined(__AVX__)
534 gemv_fused_q8_0_bias_avx(y, W, x, bias, M, K);
535#else
536 gemv_fused_q8_0_bias(y, W, x, bias, M, K);
537#endif
538}
void gemv_fused_q8_0_bias(float *y, const void *W, const float *x, const float *bias, int M, int K)

References gemv_fused_q8_0_bias().

◆ gemv_q4_0()

void gemv_q4_0 ( float *  y,
const void *  W,
const float *  x,
int  M,
int  K 
)

Auto-dispatch GEMV.

Definition at line 132 of file gemm_kernels_q4_0.c.

136{
137#ifdef __AVX512F__
138 gemv_q4_0_avx512(y, W, x, M, K);
139#else
140 gemv_q4_0_ref(y, W, x, M, K);
141#endif
142}
void gemv_q4_0_ref(float *y, const void *W, const float *x, int M, int K)
Matrix-vector multiply with Q4_0 weights (scalar reference)

References gemv_q4_0_ref().

Referenced by dot_q4_0(), and gemm_q4_0().

◆ gemv_q4_k()

void gemv_q4_k ( float *  y,
const void *  W,
const float *  x,
int  M,
int  K 
)

Auto-dispatch GEMV based on available SIMD.

Definition at line 301 of file gemm_kernels_q4k.c.

305{
306 if (ck_q4k_debug_q8_contract() && K > 0 && (K % QK_K) == 0) {
307 const int nb = K / QK_K;
308 if (nb <= CK_Q4K_STACK_Q8_BLOCKS) {
310 quantize_row_q8_k(x, x_q8, K);
311 gemv_q4_k_q8_k(y, W, x_q8, M, K);
312 return;
313 }
314 }
315#ifdef __AVX512F__
316 gemv_q4_k_avx512(y, W, x, M, K);
317#elif defined(__AVX__)
318 gemv_q4_k_avx(y, W, x, M, K);
319#else
320 gemv_q4_k_ref(y, W, x, M, K);
321#endif
322}
void gemv_q4_k_ref(float *y, const void *W, const float *x, int M, int K)
Matrix-vector multiply with Q4_K weights (scalar reference)
#define CK_Q4K_STACK_Q8_BLOCKS
void quantize_row_q8_k(const float *x, void *vy, int k)
void gemv_q4_k_q8_k(float *y, const void *W, const void *x_q8, int M, int K)
static int ck_q4k_debug_q8_contract(void)

References ck_q4k_debug_q8_contract(), CK_Q4K_STACK_Q8_BLOCKS, gemv_q4_k_q8_k(), gemv_q4_k_ref(), QK_K, and quantize_row_q8_k().

Referenced by attention_mlp_fused_q4k(), dot_q4_k(), gemm_q4_k_ref(), layer_fused_attn_mlp_qkv_q4k(), and rmsnorm_qkv_q4k_fused().

◆ gemv_q4_k_q8_k()

void gemv_q4_k_q8_k ( float *  y,
const void *  W,
const void *  x_q8,
int  M,
int  K 
)

Definition at line 273 of file gemm_kernels_q4k_q8k.c.

277{
278 if (ck_q4k_q8k_force_ref()) {
279 gemv_q4_k_q8_k_ref(y, W, x_q8, M, K);
280 return;
281 }
282#if defined(__AVX512VNNI__) && defined(__AVX512VL__) && !defined(CK_NO_AVX512_VNNI)
283 /* VNNI: Best for decode (single token) - INT8 dot product acceleration */
284 gemv_q4_k_q8_k_vnni(y, W, x_q8, M, K);
285#elif defined(__AVX2__)
286 gemv_q4_k_q8_k_avx2(y, W, x_q8, M, K);
287#elif defined(__AVX__)
288 /* AVX version uses maddubs_epi16 (more efficient than SSE) */
289 gemv_q4_k_q8_k_avx(y, W, x_q8, M, K);
290#elif defined(__SSE4_1__)
291 gemv_q4_k_q8_k_sse(y, W, x_q8, M, K);
292#else
293 gemv_q4_k_q8_k_ref(y, W, x_q8, M, K);
294#endif
295}
void gemv_q4_k_q8_k_avx2(float *y, const void *W, const void *x_q8, int M, int K)
void gemv_q4_k_q8_k_vnni(float *y, const void *W, const void *x_q8, int M, int K)
void gemv_q4_k_q8_k_ref(float *y, const void *W, const void *x_q8, int M, int K)
static int ck_q4k_q8k_force_ref(void)
void gemv_q4_k_q8_k_avx(float *y, const void *W, const void *x_q8, int M, int K)
void gemv_q4_k_q8_k_sse(float *y, const void *W, const void *x_q8, int M, int K)

References ck_q4k_q8k_force_ref(), gemv_q4_k_q8_k_avx(), gemv_q4_k_q8_k_avx2(), gemv_q4_k_q8_k_ref(), gemv_q4_k_q8_k_sse(), and gemv_q4_k_q8_k_vnni().

Referenced by ck_moe_q4k_llama_projection(), ck_moe_q4k_mixed_route_work(), ck_moe_q4k_q5k_route_work(), gemm_q4_k_q8_k_compact_rows4(), model_decode_token(), model_decode_token(), model_layer_0_decode(), model_layer_0_decode(), model_layer_10_decode(), model_layer_10_decode(), model_layer_11_decode(), model_layer_11_decode(), model_layer_12_decode(), model_layer_12_decode(), model_layer_13_decode(), model_layer_13_decode(), model_layer_14_decode(), model_layer_14_decode(), model_layer_15_decode(), model_layer_15_decode(), model_layer_16_decode(), model_layer_16_decode(), model_layer_17_decode(), model_layer_17_decode(), model_layer_18_decode(), model_layer_18_decode(), model_layer_19_decode(), model_layer_19_decode(), model_layer_1_decode(), model_layer_1_decode(), model_layer_20_decode(), model_layer_20_decode(), model_layer_21_decode(), model_layer_21_decode(), model_layer_22_decode(), model_layer_22_decode(), model_layer_23_decode(), model_layer_23_decode(), model_layer_2_decode(), model_layer_2_decode(), model_layer_3_decode(), model_layer_3_decode(), model_layer_4_decode(), model_layer_4_decode(), model_layer_5_decode(), model_layer_5_decode(), model_layer_6_decode(), model_layer_6_decode(), model_layer_7_decode(), model_layer_7_decode(), model_layer_8_decode(), model_layer_8_decode(), model_layer_9_decode(), model_layer_9_decode(), moe_swiglu_expert_forward_q4k_q4k_workspace(), moe_swiglu_expert_forward_q4k_q5k_workspace(), moe_swiglu_expert_forward_q4k_q6k_workspace(), moe_swiglu_shared_forward_q4k_q4k_workspace(), moe_swiglu_shared_forward_q4k_q6k_workspace(), qwen2_0_5b_decode_decode_token(), qwen2_0_5b_decode_decode_token(), qwen2_0_5b_decode_layer_0_decode(), qwen2_0_5b_decode_layer_0_decode(), qwen2_0_5b_decode_layer_10_decode(), qwen2_0_5b_decode_layer_10_decode(), qwen2_0_5b_decode_layer_11_decode(), qwen2_0_5b_decode_layer_11_decode(), qwen2_0_5b_decode_layer_12_decode(), qwen2_0_5b_decode_layer_12_decode(), qwen2_0_5b_decode_layer_13_decode(), qwen2_0_5b_decode_layer_13_decode(), qwen2_0_5b_decode_layer_14_decode(), qwen2_0_5b_decode_layer_14_decode(), qwen2_0_5b_decode_layer_15_decode(), qwen2_0_5b_decode_layer_15_decode(), qwen2_0_5b_decode_layer_16_decode(), qwen2_0_5b_decode_layer_16_decode(), qwen2_0_5b_decode_layer_17_decode(), qwen2_0_5b_decode_layer_17_decode(), qwen2_0_5b_decode_layer_18_decode(), qwen2_0_5b_decode_layer_18_decode(), qwen2_0_5b_decode_layer_19_decode(), qwen2_0_5b_decode_layer_19_decode(), qwen2_0_5b_decode_layer_1_decode(), qwen2_0_5b_decode_layer_1_decode(), qwen2_0_5b_decode_layer_20_decode(), qwen2_0_5b_decode_layer_20_decode(), qwen2_0_5b_decode_layer_21_decode(), qwen2_0_5b_decode_layer_21_decode(), qwen2_0_5b_decode_layer_22_decode(), qwen2_0_5b_decode_layer_22_decode(), qwen2_0_5b_decode_layer_23_decode(), qwen2_0_5b_decode_layer_23_decode(), qwen2_0_5b_decode_layer_2_decode(), qwen2_0_5b_decode_layer_2_decode(), qwen2_0_5b_decode_layer_3_decode(), qwen2_0_5b_decode_layer_3_decode(), qwen2_0_5b_decode_layer_4_decode(), qwen2_0_5b_decode_layer_4_decode(), qwen2_0_5b_decode_layer_5_decode(), qwen2_0_5b_decode_layer_5_decode(), qwen2_0_5b_decode_layer_6_decode(), qwen2_0_5b_decode_layer_6_decode(), qwen2_0_5b_decode_layer_7_decode(), qwen2_0_5b_decode_layer_7_decode(), qwen2_0_5b_decode_layer_8_decode(), qwen2_0_5b_decode_layer_8_decode(), qwen2_0_5b_decode_layer_9_decode(), and qwen2_0_5b_decode_layer_9_decode().

◆ gemv_q4_k_q8_k_parallel()

void gemv_q4_k_q8_k_parallel ( float *  y,
const void *  W,
const void *  x_q8,
int  M,
int  K,
int  ith,
int  nth 
)

Definition at line 240 of file gemm_kernels_q4k_q8k.c.

245{
246 if (!y || !W || !x_q8 || M <= 0 || K <= 0) {
247 return;
248 }
249 if (ith < 0 || nth <= 0 || ith >= nth) {
250 return;
251 }
252
253 /* Compute row range for this thread */
254 const int dr = (M + nth - 1) / nth;
255 const int r0 = dr * ith;
256 const int r1 = (r0 + dr < M) ? (r0 + dr) : M;
257
258 if (r0 >= M) {
259 return; /* This thread has no work */
260 }
261
262 const block_q4_K *blocks = (const block_q4_K *)W;
263 const block_q8_K *x = (const block_q8_K *)x_q8;
264 const int blocks_per_row = K / QK_K;
265
266 /* Only process rows [r0, r1) */
267 for (int row = r0; row < r1; ++row) {
268 const block_q4_K *w_row = blocks + (size_t)row * (size_t)blocks_per_row;
269 y[row] = dot_q4_k_q8_k_ref(w_row, x, K);
270 }
271}
static float dot_q4_k_q8_k_ref(const block_q4_K *w, const block_q8_K *x, int k)

References dot_q4_k_q8_k_ref(), and QK_K.

◆ gemv_q4_k_q8_k_parallel_simd()

void gemv_q4_k_q8_k_parallel_simd ( float *  y,
const void *  W,
const void *  x_q8,
int  M,
int  K,
int  ith,
int  nth 
)

Definition at line 263 of file gemm_kernels_q4k_avx.c.

268{
269 /* Fall back to reference parallel version */
270 gemv_q4_k_q8_k_parallel(y, W, x_q8, M, K, ith, nth);
271}
void gemv_q4_k_q8_k_parallel(float *y, const void *W, const void *x_q8, int M, int K, int ith, int nth)

References gemv_q4_k_q8_k_parallel().

Referenced by decode_layer_parallel(), mlp_parallel(), and qkv_projection_parallel().

◆ gemv_q4_k_q8_k_ref()

void gemv_q4_k_q8_k_ref ( float *  y,
const void *  W,
const void *  x_q8,
int  M,
int  K 
)

Definition at line 201 of file gemm_kernels_q4k_q8k.c.

205{
206 if (!y || !W || !x_q8 || M <= 0 || K <= 0) {
207 return;
208 }
209
210 const block_q4_K *blocks = (const block_q4_K *)W;
211 const block_q8_K *x = (const block_q8_K *)x_q8;
212 const int blocks_per_row = K / QK_K;
213
214 for (int row = 0; row < M; ++row) {
215 const block_q4_K *w_row = blocks + (size_t)row * (size_t)blocks_per_row;
216 y[row] = dot_q4_k_q8_k_ref(w_row, x, K);
217 }
218}

References dot_q4_k_q8_k_ref(), and QK_K.

◆ gemv_q5_0()

void gemv_q5_0 ( float *  y,
const void *  W,
const float *  x,
int  M,
int  K 
)

Auto-dispatch GEMV for Q5_0 weights based on CPU features.

Dispatch priority (best available):

  1. AVX-512 (512-bit vectors) - Intel Skylake-X+
  2. AVX2+FMA (256-bit vectors) - Intel Haswell+
  3. AVX (256-bit vectors) - Intel Sandy Bridge+
  4. SSE4.1 (128-bit vectors) - Intel Nehalem+
  5. Reference (scalar) - Fallback

Uses ck_features.h for standardized feature detection.

Parameters
yOutput vector [M]
WWeight matrix in Q5_0 format [M x K]
xInput vector [K]
MNumber of output rows
KNumber of input columns (hidden dimension)

Definition at line 550 of file gemm_kernels_q5_0.c.

554{
555// Dispatch order: AVX512 > AVX2 > AVX > SSE > ref
556#if defined(__AVX512F__)
557 gemv_q5_0_avx512(y, W, x, M, K);
558#elif defined(__AVX2__)
559 gemv_q5_0_avx2(y, W, x, M, K);
560#elif defined(__AVX__)
561 gemv_q5_0_avx(y, W, x, M, K);
562#elif defined(__SSE4_1__)
563 gemv_q5_0_ref(y, W, x, M, K);
564#else
565 gemv_q5_0_ref(y, W, x, M, K);
566#endif
567}
void gemv_q5_0_ref(float *y, const void *W, const float *x, int M, int K)
Matrix-vector multiply with Q5_0 weights (scalar reference)

References gemv_q5_0_ref().

◆ gemv_q5_0_parallel()

void gemv_q5_0_parallel ( float *  y,
const void *  W,
const float *  x,
int  M,
int  K,
int  ith,
int  nth 
)

Parallel reference GEMV for Q5_0 × FP32.

Definition at line 579 of file gemm_kernels_q5_0.c.

584{
585 if (!y || !W || !x || M <= 0 || K <= 0) return;
586 if (ith < 0 || nth <= 0 || ith >= nth) return;
587
588 const int dr = (M + nth - 1) / nth;
589 const int r0 = dr * ith;
590 const int r1 = (r0 + dr < M) ? (r0 + dr) : M;
591
592 if (r0 >= M) return;
593
594 const block_q5_0 *blocks = (const block_q5_0 *)W;
595 const int blocks_per_row = K / QK5_0;
596
597 for (int row = r0; row < r1; row++) {
598 float sum = 0.0f;
599 for (int b = 0; b < blocks_per_row; b++) {
600 const block_q5_0 *block = &blocks[row * blocks_per_row + b];
601 const float d = CK_FP16_TO_FP32(block->d);
602 const float *xp = &x[b * QK5_0];
603
604 uint32_t qh;
605 memcpy(&qh, block->qh, sizeof(qh));
606
607 for (int j = 0; j < QK5_0 / 2; j++) {
608 const uint8_t packed = block->qs[j];
609 const int lo = (packed & 0x0F);
610 const int hi = (packed >> 4);
611 const int xh_0 = ((qh >> (j + 0)) << 4) & 0x10;
612 const int xh_1 = ((qh >> (j + 12))) & 0x10;
613 const int w0 = (lo | xh_0) - 16;
614 const int w1 = (hi | xh_1) - 16;
615 sum += d * (w0 * xp[j] + w1 * xp[j + QK5_0/2]);
616 }
617 }
618 y[row] = sum;
619 }
620}
uint8_t qh[4]
uint8_t qs[32/2]

References CK_FP16_TO_FP32, block_q5_0::d, block_q5_0::qh, QK5_0, and block_q5_0::qs.

Referenced by gemv_q5_0_parallel_simd().

◆ gemv_q5_0_parallel_simd()

void gemv_q5_0_parallel_simd ( float *  y,
const void *  W,
const float *  x,
int  M,
int  K,
int  ith,
int  nth 
)

Parallel SIMD GEMV for Q5_0 × FP32 with prefetching.

Definition at line 625 of file gemm_kernels_q5_0.c.

630{
631 if (!y || !W || !x || M <= 0 || K <= 0) return;
632 if (ith < 0 || nth <= 0 || ith >= nth) return;
633
634 const int dr = (M + nth - 1) / nth;
635 const int r0 = dr * ith;
636 const int r1 = (r0 + dr < M) ? (r0 + dr) : M;
637
638 if (r0 >= M) return;
639
640#if defined(__AVX__) || defined(__SSE4_1__)
641 const block_q5_0 *blocks = (const block_q5_0 *)W;
642 const int blocks_per_row = K / QK5_0;
643 /* Prefetch first few rows */
644 const int PREFETCH_ROWS = 4;
645 for (int p = 0; p < PREFETCH_ROWS && r0 + p < r1; ++p) {
646 const char *row_ptr = (const char *)(blocks + (r0 + p) * blocks_per_row);
647 _mm_prefetch(row_ptr, _MM_HINT_T0);
648 _mm_prefetch(row_ptr + 64, _MM_HINT_T0);
649 }
650
651 for (int row = r0; row < r1; ++row) {
652 /* Prefetch rows ahead */
653 if (row + PREFETCH_ROWS < r1) {
654 const char *prefetch_ptr = (const char *)(blocks + (row + PREFETCH_ROWS) * blocks_per_row);
655 _mm_prefetch(prefetch_ptr, _MM_HINT_T0);
656 _mm_prefetch(prefetch_ptr + 64, _MM_HINT_T0);
657 }
658
659 /* Use SIMD dot product for this row */
660#if defined(__AVX512F__)
661 /* Call single-row AVX512 implementation */
662 gemv_q5_0_avx512(&y[row], (const char *)blocks + row * blocks_per_row * sizeof(block_q5_0), x, 1, K);
663#elif defined(__AVX2__)
664 gemv_q5_0_avx2(&y[row], (const char *)blocks + row * blocks_per_row * sizeof(block_q5_0), x, 1, K);
665#elif defined(__AVX__)
666 gemv_q5_0_avx(&y[row], (const char *)blocks + row * blocks_per_row * sizeof(block_q5_0), x, 1, K);
667#else
668 gemv_q5_0_ref(&y[row], (const char *)blocks + row * blocks_per_row * sizeof(block_q5_0), x, 1, K);
669#endif
670 }
671#else
672 /* Fallback to reference parallel */
673 gemv_q5_0_parallel(y, W, x, M, K, ith, nth);
674#endif
675}
void gemv_q5_0_parallel(float *y, const void *W, const float *x, int M, int K, int ith, int nth)
Parallel reference GEMV for Q5_0 × FP32.

References gemv_q5_0_parallel(), gemv_q5_0_ref(), and QK5_0.

◆ gemv_q5_0_q8_0()

void gemv_q5_0_q8_0 ( float *  y,
const void *  W,
const void *  x_q8,
int  M,
int  K 
)

Matrix-vector multiply with Q5_0 weights and Q8_0 input.

Parameters
yOutput vector [M]
WWeight matrix in Q5_0 format [M x K]
x_q8Input vector in Q8_0 format [K]
MNumber of output rows
KNumber of columns (must be multiple of 32)

Definition at line 1640 of file gemm_kernels_q5_0.c.

1644{
1645 const block_q5_0 *w_blocks = (const block_q5_0 *)W;
1646 const block_q8_0 *x_blocks = (const block_q8_0 *)x_q8;
1647 const int blocks_per_row = K / QK5_0;
1648
1649 for (int row = 0; row < M; row++) {
1650 vec_dot_q5_0_q8_0(K, &y[row],
1651 &w_blocks[row * blocks_per_row],
1652 x_blocks);
1653 }
1654}
void vec_dot_q5_0_q8_0(int n, float *s, const void *vx, const void *vy)
Auto-dispatch quantized dot product Q5_0 x Q8_0.

References QK5_0, and vec_dot_q5_0_q8_0().

Referenced by ck_moe_q4k_mixed_route_work(), moe_swiglu_expert_forward_q4k_q5_0_workspace(), and moe_swiglu_shared_forward_q4k_q5_0_gated_workspace().

◆ gemv_q5_1()

void gemv_q5_1 ( float *  y,
const void *  W,
const float *  x,
int  M,
int  K 
)

Auto-dispatch GEMV.

Definition at line 187 of file gemm_kernels_q5_1.c.

191{
192#ifdef __AVX512F__
193 gemv_q5_1_avx512(y, W, x, M, K);
194#else
195 gemv_q5_1_ref(y, W, x, M, K);
196#endif
197}
void gemv_q5_1_ref(float *y, const void *W, const float *x, int M, int K)
Matrix-vector multiply with Q5_1 weights (scalar reference)

References gemv_q5_1_ref().

Referenced by dot_q5_1(), and gemm_q5_1().

◆ gemv_q5_1_q8_1()

void gemv_q5_1_q8_1 ( float *  y,
const void *  W,
const float *  x,
int  M,
int  K 
)

Definition at line 269 of file gemm_kernels_q5_1_q8_1.c.

274{
275 if (!y || !W || !x || M <= 0 || K <= 0 || (K % QK5_1) != 0) {
276 return;
277 }
278
279 const int blocks_per_row = K / QK5_1;
280 if (blocks_per_row > CK_Q51_STACK_Q8_BLOCKS) {
281 return;
282 }
283
284 block_q8_1 x_q8[CK_Q51_STACK_Q8_BLOCKS];
285 quantize_row_q8_1_scalar(x, x_q8, K);
286 gemv_q5_1_q8_1_ref(y, W, x_q8, M, K);
287}
void gemv_q5_1_q8_1_ref(float *y, const void *W, const void *x_q8, int M, int K)

References CK_Q51_STACK_Q8_BLOCKS, gemv_q5_1_q8_1_ref(), QK5_1, and quantize_row_q8_1_scalar().

◆ gemv_q5_1_q8_1_ref()

void gemv_q5_1_q8_1_ref ( float *  y,
const void *  W,
const void *  x_q8,
int  M,
int  K 
)

Definition at line 219 of file gemm_kernels_q5_1_q8_1.c.

223{
224 if (!y || !W || !x_q8 || M <= 0 || K <= 0 || (K % QK5_1) != 0) {
225 return;
226 }
227
228 const block_q5_1 *blocks = (const block_q5_1 *)W;
229 const block_q8_1 *x = (const block_q8_1 *)x_q8;
230 const int blocks_per_row = K / QK5_1;
231
232 for (int row = 0; row < M; ++row) {
233 const block_q5_1 *w_row = &blocks[row * blocks_per_row];
234 float sum = 0.0f;
235 for (int b = 0; b < blocks_per_row; ++b) {
236 sum += dot_q5_1_q8_1_block(&w_row[b], &x[b]);
237 }
238 y[row] = sum;
239 }
240}

References dot_q5_1_q8_1_block(), and QK5_1.

Referenced by gemv_q5_1_q8_1().

◆ gemv_q5_k()

void gemv_q5_k ( float *  y,
const void *  W,
const float *  x,
int  M,
int  K 
)

Definition at line 982 of file gemm_kernels_q5_k.c.

983{
984#if defined(__AVX512F__)
985 /* TODO: AVX-512 implementation */
986 gemv_q5_k_ref(y, W, x, M, K);
987#elif defined(__AVX2__)
988 /* TODO: AVX-2 implementation */
989 gemv_q5_k_ref(y, W, x, M, K);
990#elif defined(__AVX__)
991 /* TODO: AVX implementation */
992 gemv_q5_k_ref(y, W, x, M, K);
993#elif defined(__SSE4_1__)
994 /* TODO: SSE4.1 implementation */
995 gemv_q5_k_ref(y, W, x, M, K);
996#else
997 gemv_q5_k_ref(y, W, x, M, K);
998#endif
999}
void gemv_q5_k_ref(float *y, const void *W, const float *x, int M, int K)

References gemv_q5_k_ref().

◆ gemv_q5_k_q8_k()

void gemv_q5_k_q8_k ( float *  y,
const void *  W,
const void *  x_q8,
int  M,
int  K 
)

Definition at line 892 of file gemm_kernels_q5_k.c.

896{
897#if defined(__AVX512F__)
898 /* TODO: AVX-512 implementation */
899 gemv_q5_k_q8_k_ref(y, W, x_q8, M, K);
900#elif defined(__AVX2__)
901 /* TODO: AVX-2 implementation */
902 gemv_q5_k_q8_k_ref(y, W, x_q8, M, K);
903#elif defined(__AVX__)
904 /* TODO: AVX implementation */
905 gemv_q5_k_q8_k_ref(y, W, x_q8, M, K);
906#elif defined(__SSE4_1__)
907 /* TODO: SSE4.1 implementation */
908 gemv_q5_k_q8_k_ref(y, W, x_q8, M, K);
909#else
910 gemv_q5_k_q8_k_ref(y, W, x_q8, M, K);
911#endif
912}
void gemv_q5_k_q8_k_ref(float *y, const void *W, const void *x_q8, int M, int K)

References gemv_q5_k_q8_k_ref().

Referenced by ck_moe_q4k_q5k_route_work(), gemm_q5_k_q8_k_compact_rows4(), and moe_swiglu_expert_forward_q4k_q5k_workspace().

◆ gemv_q6_k()

void gemv_q6_k ( float *  y,
const void *  W,
const float *  x,
int  M,
int  K 
)

Definition at line 169 of file gemm_kernels_q6k.c.

173{
174 if (!y || !W || !x) {
175 return;
176 }
177 if (M <= 0 || K <= 0) {
178 return;
179 }
180 // TEMPORARILY DISABLE NEW AVX KERNELS - USE REFERENCE ONLY
181
182 const block_q6_K *blocks = (const block_q6_K *)W;
183 const int blocks_per_row = K / QK_K;
184
185 for (int row = 0; row < M; ++row) {
186 const block_q6_K *w_row = blocks + (size_t)row * (size_t)blocks_per_row;
187#if defined(__AVX__) && !defined(__AVX512F__)
188 y[row] = dot_q6_k_avx(w_row, x, K);
189#else
190 y[row] = dot_q6_k_ref(w_row, x, K);
191#endif
192 }
193}
static float dot_q6_k_ref(const block_q6_K *w, const float *x, int K)

References dot_q6_k_ref(), and QK_K.

Referenced by gemm_q6_k().

◆ gemv_q6_k_q8_k()

void gemv_q6_k_q8_k ( float *  y,
const void *  W,
const void *  x_q8,
int  M,
int  K 
)

GEMV: y = W @ x where W is Q6_K and x is Q8_K.

Definition at line 1341 of file gemm_kernels_q6k_q8k.c.

1345{
1347 gemv_q6_k_q8_k_ref(y, W, x_q8, M, K);
1348 return;
1349 }
1350
1351#if defined(__AVX2__)
1352 /* llama.cpp's x86 Q6_K production graph keeps the AVX2 reduction order
1353 * even when AVX-512 is available. Wider ISA availability is not a license
1354 * to change this numerical contract. */
1355 gemv_q6_k_q8_k_avx2(y, W, x_q8, M, K);
1356 return;
1357#elif defined(__AVX__)
1358 gemv_q6_k_q8_k_avx(y, W, x_q8, M, K);
1359 return;
1360#elif defined(__SSE4_1__)
1361 gemv_q6_k_q8_k_sse(y, W, x_q8, M, K);
1362 return;
1363#endif
1364 gemv_q6_k_q8_k_ref(y, W, x_q8, M, K);
1365}
void gemv_q6_k_q8_k_ref(float *y, const void *W, const void *x_q8, int M, int K)
void gemv_q6_k_q8_k_sse(float *y, const void *W, const void *x_q8, int M, int K)
void gemv_q6_k_q8_k_avx(float *y, const void *W, const void *x_q8, int M, int K)
void gemv_q6_k_q8_k_avx2(float *y, const void *W, const void *x_q8, int M, int K)

References ck_q6k_q8k_force_ref(), ck_strict_parity_enabled(), gemv_q6_k_q8_k_avx(), gemv_q6_k_q8_k_avx2(), gemv_q6_k_q8_k_ref(), and gemv_q6_k_q8_k_sse().

Referenced by ck_moe_q4k_mixed_route_work(), moe_swiglu_expert_forward_q4k_q6k_workspace(), and moe_swiglu_shared_forward_q4k_q6k_workspace().

◆ gemv_q6_k_q8_k_parallel()

void gemv_q6_k_q8_k_parallel ( float *  y,
const void *  W,
const void *  x_q8,
int  M,
int  K,
int  ith,
int  nth 
)

Parallel reference GEMV for Q6_K × Q8_K.

Caller provides ith (thread index) and nth (total threads). Each thread processes rows [r0, r1).

Definition at line 1398 of file gemm_kernels_q6k_q8k.c.

1403{
1404 if (!y || !W || !x_q8 || M <= 0 || K <= 0) return;
1405 if (ith < 0 || nth <= 0 || ith >= nth) return;
1406
1407 /* Compute row range for this thread */
1408 const int dr = (M + nth - 1) / nth;
1409 const int r0 = dr * ith;
1410 const int r1 = (r0 + dr < M) ? (r0 + dr) : M;
1411
1412 if (r0 >= M) return;
1413
1414 const block_q6_K *blocks = (const block_q6_K *)W;
1415 const block_q8_K *x = (const block_q8_K *)x_q8;
1416 const int blocks_per_row = K / QK_K;
1417
1418 for (int row = r0; row < r1; ++row) {
1419 const block_q6_K *w_row = blocks + (size_t)row * (size_t)blocks_per_row;
1420 y[row] = dot_q6_k_q8_k_ref(w_row, x, K);
1421 }
1422}
static float dot_q6_k_q8_k_ref(const block_q6_K *w, const block_q8_K *x, int K)
Scalar dot product for Q6_K x Q8_K.

References dot_q6_k_q8_k_ref(), and QK_K.

◆ gemv_q6_k_q8_k_parallel_simd()

void gemv_q6_k_q8_k_parallel_simd ( float *  y,
const void *  W,
const void *  x_q8,
int  M,
int  K,
int  ith,
int  nth 
)

Parallel SIMD GEMV for Q6_K × Q8_K.

Uses best available SIMD (AVX/SSE) with row prefetching. Caller provides ith/nth from OpenMP region.

Definition at line 1430 of file gemm_kernels_q6k_q8k.c.

1435{
1436 if (!y || !W || !x_q8 || M <= 0 || K <= 0) return;
1437 if (ith < 0 || nth <= 0 || ith >= nth) return;
1438
1439 const int dr = (M + nth - 1) / nth;
1440 const int r0 = dr * ith;
1441 const int r1 = (r0 + dr < M) ? (r0 + dr) : M;
1442
1443 if (r0 >= M) return;
1444
1445 const block_q6_K *blocks = (const block_q6_K *)W;
1446 const block_q8_K *x = (const block_q8_K *)x_q8;
1447 const int blocks_per_row = K / QK_K;
1448 const int strict = ck_strict_parity_enabled() || ck_q6k_q8k_force_ref();
1449
1450 for (int row = r0; row < r1; ++row) {
1451 const block_q6_K *w_row = blocks + (size_t)row * (size_t)blocks_per_row;
1452#if defined(__AVX2__)
1453 y[row] = strict ? dot_q6_k_q8_k_ref(w_row, x, K)
1454 : dot_q6_k_q8_k_avx2(w_row, x, K);
1455#elif defined(__AVX__)
1456 y[row] = strict ? dot_q6_k_q8_k_ref(w_row, x, K)
1457 : dot_q6_k_q8_k_avx(w_row, x, K);
1458#elif defined(__SSE4_1__)
1459 y[row] = strict ? dot_q6_k_q8_k_ref(w_row, x, K)
1460 : dot_q6_k_q8_k_sse(w_row, x, K);
1461#else
1462 y[row] = dot_q6_k_q8_k_ref(w_row, x, K);
1463#endif
1464 }
1465}

References ck_q6k_q8k_force_ref(), ck_strict_parity_enabled(), dot_q6_k_q8_k_ref(), and QK_K.

◆ gemv_q8_0()

void gemv_q8_0 ( float *  y,
const void *  W,
const float *  x,
int  M,
int  K 
)

Auto-dispatch GEMV for Q8_0 weights based on CPU features.

Dispatch priority (best available):

  1. AVX-512 (512-bit vectors) - Intel Skylake-X+
  2. AVX2+FMA (256-bit vectors) - Intel Haswell+
  3. AVX (256-bit vectors) - Intel Sandy Bridge+
  4. SSE4.1 (128-bit vectors) - Intel Nehalem+
  5. Reference (scalar) - Fallback

Uses ck_features.h for standardized feature detection.

Parameters
yOutput vector [M]
WWeight matrix in Q8_0 format [M x K]
xInput vector [K]
MNumber of output rows
KNumber of input columns (hidden dimension)

Definition at line 694 of file gemm_kernels_q8_0.c.

698{
699 if (ck_q8_0_debug_ref()) {
700 gemv_q8_0_ref(y, W, x, M, K);
701 return;
702 }
703
704// Dispatch order: AVX512 > AVX2 > AVX > SSE > ref
705#if defined(__AVX512F__)
706 gemv_q8_0_avx512(y, W, x, M, K);
707#elif defined(__AVX2__)
708 gemv_q8_0_avx2(y, W, x, M, K);
709#elif defined(__AVX__)
710 gemv_q8_0_avx(y, W, x, M, K);
711#elif defined(__SSE4_1__)
712 gemv_q8_0_sse(y, W, x, M, K);
713#else
714 gemv_q8_0_ref(y, W, x, M, K);
715#endif
716}
static int ck_q8_0_debug_ref(void)
void gemv_q8_0_ref(float *y, const void *W, const float *x, int M, int K)
Matrix-vector multiply with Q8_0 weights (scalar reference)

References ck_q8_0_debug_ref(), and gemv_q8_0_ref().

Referenced by gemv_q8_0_q8_0_contract().

◆ gemv_q8_0_q8_0()

void gemv_q8_0_q8_0 ( float *  y,
const void *  W,
const void *  x_q8,
int  M,
int  K 
)

Matrix-vector multiply with Q8_0 weights and Q8_0 input.

Parameters
yOutput vector [M]
WWeight matrix in Q8_0 format [M x K]
x_q8Input vector in Q8_0 format [K]
MNumber of output rows
KNumber of columns (must be multiple of 32)

Definition at line 1405 of file gemm_kernels_q8_0.c.

1409{
1410 const block_q8_0 *w_blocks = (const block_q8_0 *)W;
1411 const block_q8_0 *x_blocks = (const block_q8_0 *)x_q8;
1412 const int blocks_per_row = K / QK8_0;
1413
1414 for (int row = 0; row < M; row++) {
1415 vec_dot_q8_0_q8_0(K, &y[row],
1416 &w_blocks[row * blocks_per_row],
1417 x_blocks);
1418 }
1419}
void vec_dot_q8_0_q8_0(int n, float *s, const void *vx, const void *vy)
Auto-dispatch quantized dot product Q8_0 x Q8_0.

References QK8_0, and vec_dot_q8_0_q8_0().

Referenced by ck_moe_q4k_mixed_route_work(), moe_swiglu_expert_forward_q4k_q8_0_workspace(), moe_swiglu_shared_forward_q4k_q8_0_gated_workspace(), and moe_swiglu_shared_forward_q8_0_gated_workspace().

◆ gemv_q8_0_q8_0_contract()

void gemv_q8_0_q8_0_contract ( float *  y,
const void *  W,
const float *  x,
int  M,
int  K 
)

Definition at line 383 of file gemm_kernels_q8_0_q8_0_contract.c.

388{
389 if (!y || !W || !x || M <= 0 || K <= 0) {
390 return;
391 }
392
393 if ((K % QK8_0) != 0) {
394 gemv_q8_0(y, W, x, M, K);
395 return;
396 }
397
398 const int blocks_per_row = K / QK8_0;
399 if (blocks_per_row > CK_Q80_STACK_Q8_BLOCKS) {
400 gemv_q8_0(y, W, x, M, K);
401 return;
402 }
403
406 quantize_row_q8_0_ref_local(x, x_q8, K);
407 gemv_q8_0_q8_0_ref_rows(y, W, x_q8, M, K);
408 return;
409 }
410 quantize_row_q8_0(x, x_q8, K);
411 gemv_q8_0_q8_0_x4(y, W, x_q8, M, K);
412}
void gemv_q8_0(float *y, const void *W, const float *x, int M, int K)
Auto-dispatch GEMV for Q8_0 weights based on CPU features.
void gemv_q8_0_q8_0_x4(float *y, const void *W, const void *x_q8, int M, int K)
static void quantize_row_q8_0_ref_local(const float *x, block_q8_0 *y, int k)
static void gemv_q8_0_q8_0_ref_rows(float *y, const void *W, const void *x_q8, int M, int K)
#define CK_Q80_STACK_Q8_BLOCKS

References CK_Q80_STACK_Q8_BLOCKS, ck_strict_parity_enabled(), gemv_q8_0(), gemv_q8_0_q8_0_ref_rows(), gemv_q8_0_q8_0_x4(), QK8_0, quantize_row_q8_0(), and quantize_row_q8_0_ref_local().

Referenced by gemm_nt_q8_0_q8_0_contract().

◆ gemv_q8_0_q8_0_x4()

void gemv_q8_0_q8_0_x4 ( float *  y,
const void *  W,
const void *  x_q8,
int  M,
int  K 
)

Definition at line 1428 of file gemm_kernels_q8_0.c.

1432{
1433#if defined(__AVX2__) || defined(__AVX512F__)
1434 if (ck_q8_0_q8_0_debug_ref() || (K % QK8_0) != 0) {
1435 gemv_q8_0_q8_0(y, W, x_q8, M, K);
1436 return;
1437 }
1438
1439 const block_q8_0 *w = (const block_q8_0 *)W;
1440 const block_q8_0 *x = (const block_q8_0 *)x_q8;
1441 const int nb = K / QK8_0;
1442 int row = 0;
1443 for (; row + 3 < M; row += 4) {
1444 __m256 acc0 = _mm256_setzero_ps();
1445 __m256 acc1 = _mm256_setzero_ps();
1446 __m256 acc2 = _mm256_setzero_ps();
1447 __m256 acc3 = _mm256_setzero_ps();
1448 const block_q8_0 *w0 = w + (size_t)(row + 0) * (size_t)nb;
1449 const block_q8_0 *w1 = w + (size_t)(row + 1) * (size_t)nb;
1450 const block_q8_0 *w2 = w + (size_t)(row + 2) * (size_t)nb;
1451 const block_q8_0 *w3 = w + (size_t)(row + 3) * (size_t)nb;
1452
1453 for (int ib = 0; ib < nb; ++ib) {
1454 const __m256i qx = _mm256_loadu_si256((const __m256i *)x[ib].qs);
1455 const float dx = CK_FP16_TO_FP32(x[ib].d);
1456 const __m256i qw0 = _mm256_loadu_si256((const __m256i *)w0[ib].qs);
1457 const __m256i qw1 = _mm256_loadu_si256((const __m256i *)w1[ib].qs);
1458 const __m256i qw2 = _mm256_loadu_si256((const __m256i *)w2[ib].qs);
1459 const __m256i qw3 = _mm256_loadu_si256((const __m256i *)w3[ib].qs);
1460 const __m256 p0 = mul_sum_i8_pairs_float_q8_0_avx2(qw0, qx);
1461 const __m256 p1 = mul_sum_i8_pairs_float_q8_0_avx2(qw1, qx);
1462 const __m256 p2 = mul_sum_i8_pairs_float_q8_0_avx2(qw2, qx);
1463 const __m256 p3 = mul_sum_i8_pairs_float_q8_0_avx2(qw3, qx);
1464 const __m256 d0 = _mm256_set1_ps(CK_FP16_TO_FP32(w0[ib].d) * dx);
1465 const __m256 d1 = _mm256_set1_ps(CK_FP16_TO_FP32(w1[ib].d) * dx);
1466 const __m256 d2 = _mm256_set1_ps(CK_FP16_TO_FP32(w2[ib].d) * dx);
1467 const __m256 d3 = _mm256_set1_ps(CK_FP16_TO_FP32(w3[ib].d) * dx);
1468#if defined(__FMA__)
1469 acc0 = _mm256_fmadd_ps(d0, p0, acc0);
1470 acc1 = _mm256_fmadd_ps(d1, p1, acc1);
1471 acc2 = _mm256_fmadd_ps(d2, p2, acc2);
1472 acc3 = _mm256_fmadd_ps(d3, p3, acc3);
1473#else
1474 acc0 = _mm256_add_ps(_mm256_mul_ps(d0, p0), acc0);
1475 acc1 = _mm256_add_ps(_mm256_mul_ps(d1, p1), acc1);
1476 acc2 = _mm256_add_ps(_mm256_mul_ps(d2, p2), acc2);
1477 acc3 = _mm256_add_ps(_mm256_mul_ps(d3, p3), acc3);
1478#endif
1479 }
1480 y[row + 0] = hsum_float_8_q8_0(acc0);
1481 y[row + 1] = hsum_float_8_q8_0(acc1);
1482 y[row + 2] = hsum_float_8_q8_0(acc2);
1483 y[row + 3] = hsum_float_8_q8_0(acc3);
1484 }
1485 if (row < M) {
1486 gemv_q8_0_q8_0(y + row, w + (size_t)row * (size_t)nb,
1487 x, M - row, K);
1488 }
1489#else
1490 gemv_q8_0_q8_0(y, W, x_q8, M, K);
1491#endif
1492}
static int ck_q8_0_q8_0_debug_ref(void)
void gemv_q8_0_q8_0(float *y, const void *W, const void *x_q8, int M, int K)
Matrix-vector multiply with Q8_0 weights and Q8_0 input.

References CK_FP16_TO_FP32, ck_q8_0_q8_0_debug_ref(), gemv_q8_0_q8_0(), and QK8_0.

Referenced by gemv_q8_0_q8_0_contract().

◆ gradient_accumulate_f32()

void gradient_accumulate_f32 ( float *  dst,
const float *  src,
size_t  numel 
)

Definition at line 925 of file optimizer_kernels.c.

926{
927 if (!dst || !src || numel == 0) {
928 return;
929 }
930
931 ck_threadpool_t *pool = ck_threadpool_global();
932 int nth = pool ? ck_threadpool_n_threads(pool) : 1;
933 if (!pool || nth <= 1 || nth > CK_OPT_PAR_MAX_THREADS || numel < CK_OPT_PAR_MIN_NUMEL) {
934 gradient_accumulate_f32_impl(dst, src, numel);
935 return;
936 }
937 int active_nth = ck_opt_pick_active_threads(nth, numel, CK_OPT_PAR_MIN_NUMEL);
938 if (active_nth <= 1) {
939 gradient_accumulate_f32_impl(dst, src, numel);
940 return;
941 }
942
943 ck_accum_parallel_args_t args = {
944 .dst = dst,
945 .src = src,
946 .numel = numel,
947 };
948 ck_threadpool_dispatch_n(pool, active_nth, ck_accum_parallel_work, &args);
949}
static void gradient_accumulate_f32_impl(float *dst, const float *src, size_t numel)
Accumulate gradients: dst += src (fp32)
static void ck_accum_parallel_work(int ith, int nth, void *argp)

References ck_accum_parallel_work(), CK_OPT_PAR_MAX_THREADS, CK_OPT_PAR_MIN_NUMEL, ck_opt_pick_active_threads(), ck_threadpool_dispatch_n(), ck_threadpool_global(), ck_threadpool_n_threads(), and gradient_accumulate_f32_impl().

◆ gradient_accumulate_multi_f32()

void gradient_accumulate_multi_f32 ( float *const *  dsts,
const float *const *  srcs,
const size_t *  numels,
int  tensor_count 
)

Definition at line 951 of file optimizer_kernels.c.

956{
957 if (!dsts || !srcs || !numels || tensor_count <= 0) {
958 return;
959 }
960
961 size_t total_numel = 0;
962 int valid_tensors = 0;
963 for (int i = 0; i < tensor_count; ++i) {
964 float *dst = dsts[i];
965 const float *src = srcs[i];
966 size_t n = numels[i];
967 if (!dst || !src || n == 0) {
968 continue;
969 }
970 total_numel += n;
971 valid_tensors += 1;
972 }
973 if (total_numel == 0 || valid_tensors == 0) {
974 return;
975 }
976
977 ck_threadpool_t *pool = ck_threadpool_global();
978 int nth = pool ? ck_threadpool_n_threads(pool) : 1;
979 if (!pool || nth <= 1 || nth > CK_OPT_PAR_MAX_THREADS || total_numel < CK_OPT_PAR_MIN_NUMEL) {
980 for (int i = 0; i < tensor_count; ++i) {
981 float *dst = dsts[i];
982 const float *src = srcs[i];
983 size_t n = numels[i];
984 if (!dst || !src || n == 0) {
985 continue;
986 }
987 gradient_accumulate_f32_impl(dst, src, n);
988 }
989 return;
990 }
991
992 int active_nth = ck_opt_pick_active_threads(nth, total_numel, CK_OPT_PAR_MIN_NUMEL);
993 if (active_nth <= 1) {
994 for (int i = 0; i < tensor_count; ++i) {
995 float *dst = dsts[i];
996 const float *src = srcs[i];
997 size_t n = numels[i];
998 if (!dst || !src || n == 0) {
999 continue;
1000 }
1001 gradient_accumulate_f32_impl(dst, src, n);
1002 }
1003 return;
1004 }
1005
1006 ck_accum_multi_parallel_args_t args = {
1007 .dsts = dsts,
1008 .srcs = srcs,
1009 .numels = numels,
1010 .tensor_count = tensor_count,
1011 .total_numel = total_numel,
1012 };
1014}
static void ck_accum_multi_parallel_work(int ith, int nth, void *argp)

References ck_accum_multi_parallel_work(), CK_OPT_PAR_MAX_THREADS, CK_OPT_PAR_MIN_NUMEL, ck_opt_pick_active_threads(), ck_threadpool_dispatch_n(), ck_threadpool_global(), ck_threadpool_n_threads(), and gradient_accumulate_f32_impl().

◆ gradient_clip_norm_f32()

float gradient_clip_norm_f32 ( float *  grad,
size_t  numel,
float  max_norm 
)

Clip gradient norm (fp32)

If ||grad||_2 > max_norm, scale grad so that ||grad||_2 = max_norm

Parameters
gradGradient tensor to clip (in-place) [numel]
numelNumber of elements
max_normMaximum allowed L2 norm
Returns
The original L2 norm before clipping

Definition at line 1169 of file optimizer_kernels.c.

1170{
1171 if (!grad || numel == 0 || max_norm <= 0.0f) {
1172 return 0.0f;
1173 }
1174
1175 double sum_sq = 0.0;
1176 ck_threadpool_t *pool = ck_threadpool_global();
1177 int nth = pool ? ck_threadpool_n_threads(pool) : 1;
1178
1179 if (pool && nth > 1 && nth <= CK_OPT_PAR_MAX_THREADS && numel >= CK_OPT_PAR_MIN_NUMEL) {
1180 int active_nth = ck_opt_pick_active_threads(nth, numel, CK_OPT_PAR_MIN_NUMEL);
1181 if (active_nth <= 1) {
1182 sum_sq = gradient_sum_sq_f32_impl(grad, numel);
1183 } else {
1184 ck_sum_sq_parallel_args_t args;
1185 args.grad = grad;
1186 args.numel = numel;
1187 for (int i = 0; i < CK_OPT_PAR_MAX_THREADS; ++i) {
1188 args.partial[i] = 0.0;
1189 }
1190 ck_threadpool_dispatch_n(pool, active_nth, ck_sum_sq_parallel_work, &args);
1191 for (int i = 0; i < active_nth; ++i) {
1192 sum_sq += args.partial[i];
1193 }
1194 }
1195 } else {
1196 sum_sq = gradient_sum_sq_f32_impl(grad, numel);
1197 }
1198
1199 float norm = sqrtf((float)sum_sq);
1200 if (norm > max_norm) {
1201 float scale = max_norm / norm;
1202 gradient_scale_f32(grad, numel, scale);
1203 }
1204 return norm;
1205}
static double gradient_sum_sq_f32_impl(const float *grad, size_t numel)
static void ck_sum_sq_parallel_work(int ith, int nth, void *argp)
void gradient_scale_f32(float *grad, size_t numel, float scale)

References CK_OPT_PAR_MAX_THREADS, CK_OPT_PAR_MIN_NUMEL, ck_opt_pick_active_threads(), ck_sum_sq_parallel_work(), ck_threadpool_dispatch_n(), ck_threadpool_global(), ck_threadpool_n_threads(), gradient_scale_f32(), and gradient_sum_sq_f32_impl().

◆ gradient_global_norm_multi_f32()

float gradient_global_norm_multi_f32 ( const float *const *  grads,
const size_t *  numels,
int  tensor_count 
)

Definition at line 1207 of file optimizer_kernels.c.

1208{
1209 if (!grads || !numels || tensor_count <= 0) {
1210 return 0.0f;
1211 }
1212
1213 size_t total_numel = 0;
1214 int valid_tensors = 0;
1215 for (int i = 0; i < tensor_count; ++i) {
1216 if (!grads[i] || numels[i] == 0) {
1217 continue;
1218 }
1219 total_numel += numels[i];
1220 valid_tensors += 1;
1221 }
1222 if (total_numel == 0 || valid_tensors == 0) {
1223 return 0.0f;
1224 }
1225
1226 double sum_sq = 0.0;
1227 ck_threadpool_t *pool = ck_threadpool_global();
1228 int nth = pool ? ck_threadpool_n_threads(pool) : 1;
1229
1230 if (pool && nth > 1 && nth <= CK_OPT_PAR_MAX_THREADS &&
1231 total_numel >= CK_OPT_PAR_MIN_NUMEL && valid_tensors > 1) {
1232 int active_nth = ck_opt_pick_active_threads(nth, total_numel, CK_OPT_PAR_MIN_NUMEL);
1233 if (active_nth > valid_tensors) {
1234 active_nth = valid_tensors;
1235 }
1236 if (active_nth <= 1) {
1237 for (int i = 0; i < tensor_count; ++i) {
1238 const float *g = grads[i];
1239 size_t n = numels[i];
1240 if (!g || n == 0) {
1241 continue;
1242 }
1243 sum_sq += gradient_sum_sq_f32_impl(g, n);
1244 }
1245 } else {
1246 ck_sum_sq_multi_parallel_args_t args;
1247 args.grads = grads;
1248 args.numels = numels;
1249 args.tensor_count = tensor_count;
1250 for (int i = 0; i < CK_OPT_PAR_MAX_THREADS; ++i) {
1251 args.partial[i] = 0.0;
1252 }
1254 for (int i = 0; i < active_nth; ++i) {
1255 sum_sq += args.partial[i];
1256 }
1257 }
1258 } else {
1259 for (int i = 0; i < tensor_count; ++i) {
1260 const float *g = grads[i];
1261 size_t n = numels[i];
1262 if (!g || n == 0) {
1263 continue;
1264 }
1265 sum_sq += gradient_sum_sq_f32_impl(g, n);
1266 }
1267 }
1268
1269 if (!(sum_sq > 0.0)) {
1270 return 0.0f;
1271 }
1272 return sqrtf((float)sum_sq);
1273}
static void ck_sum_sq_multi_parallel_work(int ith, int nth, void *argp)

References CK_OPT_PAR_MAX_THREADS, CK_OPT_PAR_MIN_NUMEL, ck_opt_pick_active_threads(), ck_sum_sq_multi_parallel_work(), ck_threadpool_dispatch_n(), ck_threadpool_global(), ck_threadpool_n_threads(), and gradient_sum_sq_f32_impl().

Referenced by adamw_clip_update_multi_f32().

◆ gradient_scale_f32()

void gradient_scale_f32 ( float *  grad,
size_t  numel,
float  scale 
)

Definition at line 1073 of file optimizer_kernels.c.

1074{
1075 if (!grad || numel == 0) {
1076 return;
1077 }
1078
1079 ck_threadpool_t *pool = ck_threadpool_global();
1080 int nth = pool ? ck_threadpool_n_threads(pool) : 1;
1081 if (!pool || nth <= 1 || nth > CK_OPT_PAR_MAX_THREADS || numel < CK_OPT_PAR_MIN_NUMEL) {
1082 gradient_scale_f32_impl(grad, numel, scale);
1083 return;
1084 }
1085 int active_nth = ck_opt_pick_active_threads(nth, numel, CK_OPT_PAR_MIN_NUMEL);
1086 if (active_nth <= 1) {
1087 gradient_scale_f32_impl(grad, numel, scale);
1088 return;
1089 }
1090
1091 ck_scale_parallel_args_t args = {
1092 .grad = grad,
1093 .numel = numel,
1094 .scale = scale,
1095 };
1096 ck_threadpool_dispatch_n(pool, active_nth, ck_scale_parallel_work, &args);
1097}
static void ck_scale_parallel_work(int ith, int nth, void *argp)

References CK_OPT_PAR_MAX_THREADS, CK_OPT_PAR_MIN_NUMEL, ck_opt_pick_active_threads(), ck_scale_parallel_work(), ck_threadpool_dispatch_n(), ck_threadpool_global(), ck_threadpool_n_threads(), and gradient_scale_f32_impl().

◆ group_limited_topk_router_sigmoid_f32()

void group_limited_topk_router_sigmoid_f32 ( const float *  logits,
const float *  correction_bias,
int *  indices,
float *  weights,
int  rows,
int  n_experts,
int  top_k,
int  n_group,
int  topk_group,
int  norm_topk_prob,
float  routed_scaling_factor 
)

Definition at line 798 of file topk_kernels.c.

809{
811 logits, correction_bias, indices, weights, rows, n_experts, top_k,
812 n_group, topk_group, norm_topk_prob, routed_scaling_factor, 1
813 );
814}
static void group_limited_topk_router_f32_impl(const float *scores, const float *correction_bias, int *indices, float *weights, int rows, int n_experts, int top_k, int n_group, int topk_group, int norm_topk_prob, float routed_scaling_factor, int apply_sigmoid)

References group_limited_topk_router_f32_impl().

◆ hyper_connection_mix_bf16()

void hyper_connection_mix_bf16 ( const float *  hyper_input,
const float *  norm_weight,
const uint16_t *  mix_down_weight,
const uint16_t *  mix_up_weight,
const uint16_t *  inject_weight,
float *  mixed_output,
float *  injection_output,
float *  normalized_scratch,
float *  dynamic_scratch,
float *  mix_scratch,
int  rows,
int  streams,
int  hidden_dim,
int  dynamic_dim,
float  eps,
int  emit_injection 
)

Definition at line 71 of file hyper_connection_kernels.c.

86 {
87 if (!hyper_input || !norm_weight || !mix_down_weight || !mix_up_weight ||
88 !mixed_output || !normalized_scratch || !dynamic_scratch || !mix_scratch ||
89 rows <= 0 || streams <= 0 || hidden_dim <= 0 || dynamic_dim <= 0) {
90 return;
91 }
92 if (emit_injection && (!inject_weight || !injection_output)) {
93 return;
94 }
95
96 const int hyper_dim = streams * hidden_dim;
97 const float inv_streams = 1.0f / (float)streams;
98
99 for (int row = 0; row < rows; ++row) {
100 const float *input_row =
101 hyper_input + (size_t)row * (size_t)hyper_dim;
102 float *norm_row =
103 normalized_scratch + (size_t)row * (size_t)hyper_dim;
104 float *dynamic_row =
105 dynamic_scratch + (size_t)row * (size_t)dynamic_dim;
106 float *mix_row = mix_scratch + (size_t)row * (size_t)hyper_dim;
107
108 for (int stream = 0; stream < streams; ++stream) {
109 const int base = stream * hidden_dim;
111 input_row + base,
112 norm_weight + base,
113 norm_row + base,
114 NULL,
115 1,
116 hidden_dim,
117 hidden_dim,
118 eps
119 );
120 }
121
122 for (int out = 0; out < dynamic_dim; ++out) {
123 const uint16_t *weight_row =
124 mix_down_weight + (size_t)out * (size_t)hyper_dim;
125 float sum = 0.0f;
126 for (int col = 0; col < hyper_dim; ++col) {
127 sum += norm_row[col] * bf16_to_float(weight_row[col]);
128 }
129 const float projected = ck_bf16_round(sum * inv_streams);
130 dynamic_row[out] = ck_bf16_round(
131 projected / (1.0f + expf(-projected)));
132 }
133
134 for (int out = 0; out < hyper_dim; ++out) {
135 const uint16_t *weight_row =
136 mix_up_weight + (size_t)out * (size_t)dynamic_dim;
137 float sum = 0.0f;
138 for (int col = 0; col < dynamic_dim; ++col) {
139 sum += dynamic_row[col] * bf16_to_float(weight_row[col]);
140 }
141 mix_row[out] = ck_sigmoid_bf16(ck_bf16_round(sum));
142 }
143
144 float *mixed_row =
145 mixed_output + (size_t)row * (size_t)hidden_dim;
146 for (int col = 0; col < hidden_dim; ++col) {
147 float sum = 0.0f;
148 for (int stream = 0; stream < streams; ++stream) {
149 const int index = stream * hidden_dim + col;
150 sum += ck_bf16_round(norm_row[index] * mix_row[index]);
151 }
152 mixed_row[col] = ck_bf16_round(sum * inv_streams);
153 }
154
155 if (emit_injection) {
156 float *injection_row =
157 injection_output + (size_t)row * (size_t)streams;
158 for (int stream = 0; stream < streams; ++stream) {
159 const uint16_t *weight_row =
160 inject_weight + (size_t)stream * (size_t)hyper_dim;
161 float sum = 0.0f;
162 for (int col = 0; col < hyper_dim; ++col) {
163 sum += norm_row[col] * bf16_to_float(weight_row[col]);
164 }
165 injection_row[stream] = ck_bf16_round(
166 2.0f * ck_sigmoid_bf16(ck_bf16_round(sum * inv_streams)));
167 }
168 }
169 }
170}
void rmsnorm_forward_qwen3next_pytorch_bf16_storage(const float *input, const float *gamma, float *output, float *rstd_cache, int tokens, int d_model, int aligned_embed_dim, float eps)
static float ck_sigmoid_bf16(float value)
static float ck_bf16_round(float value)

References bf16_to_float(), ck_bf16_round(), ck_sigmoid_bf16(), and rmsnorm_forward_qwen3next_pytorch_bf16_storage().

◆ hyper_connection_mix_q4k_q5_0_q4k()

void hyper_connection_mix_q4k_q5_0_q4k ( const float *  hyper_input,
const float *  norm_weight,
const void *  mix_down_weight,
const void *  mix_up_weight,
const void *  inject_weight,
float *  mixed_output,
float *  injection_output,
float *  normalized_scratch,
float *  dynamic_scratch,
float *  mix_scratch,
int  rows,
int  streams,
int  hidden_dim,
int  dynamic_dim,
float  eps,
int  emit_injection 
)

Definition at line 344 of file hyper_connection_kernels.c.

359 {
361 hyper_input, norm_weight, mix_down_weight, mix_up_weight, inject_weight,
362 mixed_output, injection_output, normalized_scratch, dynamic_scratch,
363 mix_scratch, rows, streams, hidden_dim, dynamic_dim, eps,
366}
void gemm_nt_q4_k_q8_k_pairwise_split_min_parallel_dispatch(const void *A, const void *B, const float *bias, float *C, int M, int N, int K)
static void hyper_connection_mix_quantized(const float *hyper_input, const float *norm_weight, const void *mix_down_weight, const void *mix_up_weight, const void *inject_weight, float *mixed_output, float *injection_output, float *normalized_scratch, float *dynamic_scratch, float *mix_scratch, int rows, int streams, int hidden_dim, int dynamic_dim, float eps, int emit_injection, ck_hyper_q8k_gemm_fn injection_gemm, ck_hyper_q8k_gemm_fn down_gemm)
static void hyper_injection_q4k_q8k_llama_dispatch(const void *input, const void *weight, const float *bias, float *output, int rows, int output_dim, int input_dim)

References gemm_nt_q4_k_q8_k_pairwise_split_min_parallel_dispatch(), hyper_connection_mix_quantized(), and hyper_injection_q4k_q8k_llama_dispatch().

◆ hyper_connection_mix_q6k_q5_0_q4k()

void hyper_connection_mix_q6k_q5_0_q4k ( const float *  hyper_input,
const float *  norm_weight,
const void *  mix_down_weight,
const void *  mix_up_weight,
const void *  inject_weight,
float *  mixed_output,
float *  injection_output,
float *  normalized_scratch,
float *  dynamic_scratch,
float *  mix_scratch,
int  rows,
int  streams,
int  hidden_dim,
int  dynamic_dim,
float  eps,
int  emit_injection 
)

Definition at line 368 of file hyper_connection_kernels.c.

383 {
385 hyper_input, norm_weight, mix_down_weight, mix_up_weight, inject_weight,
386 mixed_output, injection_output, normalized_scratch, dynamic_scratch,
387 mix_scratch, rows, streams, hidden_dim, dynamic_dim, eps,
390}
void gemm_nt_q6_k_q8_k_parallel_dispatch(const void *A, const void *B, const float *bias, float *C, int M, int N, int K)

References gemm_nt_q6_k_q8_k_parallel_dispatch(), hyper_connection_mix_quantized(), and hyper_injection_q4k_q8k_llama_dispatch().

◆ hyper_stream_expand_bf16()

void hyper_stream_expand_bf16 ( const float *  input,
float *  output,
int  rows,
int  streams,
int  hidden_dim 
)

Definition at line 51 of file hyper_connection_kernels.c.

55 {
56 if (!input || !output || rows <= 0 || streams <= 0 || hidden_dim <= 0) {
57 return;
58 }
59 for (int row = 0; row < rows; ++row) {
60 const float *src = input + (size_t)row * (size_t)hidden_dim;
61 float *dst = output + (size_t)row * (size_t)streams * (size_t)hidden_dim;
62 for (int stream = 0; stream < streams; ++stream) {
63 for (int col = 0; col < hidden_dim; ++col) {
64 dst[(size_t)stream * (size_t)hidden_dim + (size_t)col] =
65 ck_bf16_round(src[col]);
66 }
67 }
68 }
69}

References ck_bf16_round().

◆ hyper_stream_expand_f32()

void hyper_stream_expand_f32 ( const float *  input,
float *  output,
int  rows,
int  streams,
int  hidden_dim 
)

Definition at line 32 of file hyper_connection_kernels.c.

36 {
37 if (!input || !output || rows <= 0 || streams <= 0 || hidden_dim <= 0) {
38 return;
39 }
40 for (int row = 0; row < rows; ++row) {
41 const float *src = input + (size_t)row * (size_t)hidden_dim;
42 float *dst = output + (size_t)row * (size_t)streams * (size_t)hidden_dim;
43 for (int stream = 0; stream < streams; ++stream) {
44 for (int col = 0; col < hidden_dim; ++col) {
45 dst[(size_t)stream * (size_t)hidden_dim + (size_t)col] = src[col];
46 }
47 }
48 }
49}

◆ hyper_stream_inject_bf16()

void hyper_stream_inject_bf16 ( const float *  hyper_input,
const float *  block_output,
const float *  injection_weight,
float *  output,
int  rows,
int  streams,
int  hidden_dim 
)

Definition at line 392 of file hyper_connection_kernels.c.

398 {
399 if (!hyper_input || !block_output || !injection_weight || !output ||
400 rows <= 0 || streams <= 0 || hidden_dim <= 0) {
401 return;
402 }
403 const int hyper_dim = streams * hidden_dim;
404 for (int row = 0; row < rows; ++row) {
405 const float *hyper_row =
406 hyper_input + (size_t)row * (size_t)hyper_dim;
407 const float *block_row =
408 block_output + (size_t)row * (size_t)hidden_dim;
409 const float *inject_row =
410 injection_weight + (size_t)row * (size_t)streams;
411 float *output_row = output + (size_t)row * (size_t)hyper_dim;
412 for (int stream = 0; stream < streams; ++stream) {
413 for (int col = 0; col < hidden_dim; ++col) {
414 const int index = stream * hidden_dim + col;
415 output_row[index] = ck_bf16_round(
416 hyper_row[index] +
417 ck_bf16_round(block_row[col] * inject_row[stream]));
418 }
419 }
420 }
421}

References ck_bf16_round().

◆ hyper_stream_inject_f32()

void hyper_stream_inject_f32 ( const float *  hyper_input,
const float *  block_output,
const float *  injection_weight,
float *  output,
int  rows,
int  streams,
int  hidden_dim 
)

Definition at line 423 of file hyper_connection_kernels.c.

429 {
430 if (!hyper_input || !block_output || !injection_weight || !output ||
431 rows <= 0 || streams <= 0 || hidden_dim <= 0) {
432 return;
433 }
434 const int hyper_dim = streams * hidden_dim;
435 for (int row = 0; row < rows; ++row) {
436 const float *hyper_row =
437 hyper_input + (size_t)row * (size_t)hyper_dim;
438 const float *block_row =
439 block_output + (size_t)row * (size_t)hidden_dim;
440 const float *inject_row =
441 injection_weight + (size_t)row * (size_t)streams;
442 float *output_row = output + (size_t)row * (size_t)hyper_dim;
443 for (int stream = 0; stream < streams; ++stream) {
444 for (int col = 0; col < hidden_dim; ++col) {
445 const int index = stream * hidden_dim + col;
446 volatile const float weighted =
447 block_row[col] * inject_row[stream];
448 output_row[index] = hyper_row[index] + weighted;
449 }
450 }
451 }
452}

◆ im2patch()

void im2patch ( const float *  image,
float *  patches,
int  C,
int  H,
int  W,
int  P 
)

im2patch: Transforms an image into a sequence of flattened patches.

Image Layout: [C, H, W] (Row-major: W is fastest moving) Output Layout: [num_patches, C * P * P]

num_patches = (H/P) * (W/P) P = patch_size

Definition at line 82 of file vision_kernels.c.

85{
86 int num_patches_h = H / P;
87 int num_patches_w = W / P;
88 int patch_dim = C * P * P;
89
90 // ph, pw: patch grid coordinates
91 for (int ph = 0; ph < num_patches_h; ++ph) {
92 for (int pw = 0; pw < num_patches_w; ++pw) {
93
94 int patch_idx = ph * num_patches_w + pw;
95 float *dst_patch = patches + (size_t)patch_idx * patch_dim;
96
97 // For each patch, grab pixels from all channels
98 for (int c = 0; c < C; ++c) {
99 for (int py = 0; py < P; ++py) {
100 int y = ph * P + py;
101 int x = pw * P;
102
103 // Input row start in the image
104 const float *src_row = image + (size_t)c * H * W + (size_t)y * W + x;
105
106 // Destination row in the flattened patch sequence
107 float *dst_row = dst_patch + (size_t)c * P * P + (size_t)py * P;
108
109 // Copy P pixels (one row of the patch)
110 memcpy(dst_row, src_row, P * sizeof(float));
111 }
112 }
113 }
114 }
115}

References C.

◆ im2patch_bf16()

void im2patch_bf16 ( const uint16_t *  image,
uint16_t *  patches,
int  C,
int  H,
int  W,
int  P 
)

Definition at line 22 of file vision_kernels_bf16.c.

28{
29 if (!image || !patches || C <= 0 || H <= 0 || W <= 0 || P <= 0) {
30 return;
31 }
32
33 int num_patches_h = H / P;
34 int num_patches_w = W / P;
35 int patch_dim = C * P * P;
36
37 for (int ph = 0; ph < num_patches_h; ++ph) {
38 for (int pw = 0; pw < num_patches_w; ++pw) {
39 int patch_idx = ph * num_patches_w + pw;
40 uint16_t *dst_patch = patches + (size_t)patch_idx * (size_t)patch_dim;
41
42 for (int c = 0; c < C; ++c) {
43 for (int py = 0; py < P; ++py) {
44 int y = ph * P + py;
45 int x = pw * P;
46
47 const uint16_t *src_row = image + (size_t)c * (size_t)H * (size_t)W + (size_t)y * (size_t)W + (size_t)x;
48 uint16_t *dst_row = dst_patch + (size_t)c * (size_t)P * (size_t)P + (size_t)py * (size_t)P;
49
50 memcpy(dst_row, src_row, (size_t)P * sizeof(uint16_t));
51 }
52 }
53 }
54 }
55}

References C.

◆ kv_cache_repack_head_major_inplace()

void kv_cache_repack_head_major_inplace ( float *  buf,
int  num_heads,
int  tokens,
int  cache_capacity,
int  aligned_head_dim 
)

Definition at line 49 of file kv_cache_kernels.c.

54{
55 if (!buf) {
56 return;
57 }
58 if (num_heads <= 0 || tokens <= 0 || cache_capacity <= 0 || aligned_head_dim <= 0) {
59 return;
60 }
61 if (tokens > cache_capacity) {
62 tokens = cache_capacity;
63 }
64 if (tokens == cache_capacity) {
65 return;
66 }
67
68 const size_t old_head_stride = (size_t)tokens * (size_t)aligned_head_dim;
69 const size_t new_head_stride = (size_t)cache_capacity * (size_t)aligned_head_dim;
70 const size_t bytes = (size_t)tokens * (size_t)aligned_head_dim * sizeof(float);
71
72 // Move head blocks from high to low to avoid overwriting source data
73 // for heads that have not yet been moved.
74 for (int h = num_heads - 1; h >= 0; --h) {
75 float *src = buf + (size_t)h * old_head_stride;
76 float *dst = buf + (size_t)h * new_head_stride;
77 memmove(dst, src, bytes);
78 }
79}

Referenced by qwen2_0_5b_decode_forward_prefill_impl(), qwen2_0_5b_decode_forward_prefill_impl(), and qwen2_0_5b_decode_forward_prefill_impl().

◆ kv_cache_store()

void kv_cache_store ( float *__restrict  kv_cache_k,
float *__restrict  kv_cache_v,
const float *__restrict  k,
const float *__restrict  v,
int  layer,
int  pos,
int  num_kv_heads,
int  head_dim,
int  max_seq_len 
)

Definition at line 122 of file kv_cache_kernels.c.

131{
132 (void)layer;
134 kv_cache_k, kv_cache_v,
135 num_kv_heads,
136 pos,
137 max_seq_len,
138 head_dim,
139 head_dim);
140}
void kv_cache_write_head_major(const float *__restrict k_token, const float *__restrict v_token, float *__restrict k_cache, float *__restrict v_cache, int num_kv_heads, int token_index, int cache_capacity, int head_dim, int aligned_head_dim)

References kv_cache_write_head_major().

◆ kv_cache_store_batch_bf16()

void kv_cache_store_batch_bf16 ( uint16_t *__restrict  kv_cache_k,
uint16_t *__restrict  kv_cache_v,
const float *__restrict  k,
const float *__restrict  v,
int  start_pos,
int  num_tokens,
int  num_kv_heads,
int  head_dim,
int  max_seq_len 
)

Definition at line 291 of file kv_cache_kernels.c.

300{
301 if (!kv_cache_k || !kv_cache_v || !k || !v ||
302 start_pos < 0 || num_tokens <= 0 || num_kv_heads <= 0 ||
303 head_dim <= 0 || max_seq_len <= 0 ||
304 start_pos > max_seq_len - num_tokens) {
305 return;
306 }
307
308 const size_t compact_head_stride = (size_t)num_tokens * (size_t)head_dim;
309 const size_t cache_head_stride = (size_t)max_seq_len * (size_t)head_dim;
310 for (int h = 0; h < num_kv_heads; ++h) {
311 const float *k_head = k + (size_t)h * compact_head_stride;
312 const float *v_head = v + (size_t)h * compact_head_stride;
313 uint16_t *k_head_cache = kv_cache_k + (size_t)h * cache_head_stride;
314 uint16_t *v_head_cache = kv_cache_v + (size_t)h * cache_head_stride;
315 for (int t = 0; t < num_tokens; ++t) {
316 const size_t src_offset = (size_t)t * (size_t)head_dim;
317 const size_t dst_offset = (size_t)(start_pos + t) * (size_t)head_dim;
318 ck_local_fp32_to_bf16_row(k_head + src_offset, k_head_cache + dst_offset, head_dim);
319 ck_local_fp32_to_bf16_row(v_head + src_offset, v_head_cache + dst_offset, head_dim);
320 }
321 }
322}
static void ck_local_fp32_to_bf16_row(const float *src, uint16_t *dst, int n)

References ck_local_fp32_to_bf16_row().

◆ kv_cache_store_batch_f16()

void kv_cache_store_batch_f16 ( uint16_t *__restrict  kv_cache_k,
uint16_t *__restrict  kv_cache_v,
const float *__restrict  k,
const float *__restrict  v,
int  start_pos,
int  num_tokens,
int  num_kv_heads,
int  head_dim,
int  max_seq_len 
)

Definition at line 255 of file kv_cache_kernels.c.

264{
265 if (!kv_cache_k || !kv_cache_v || !k || !v) {
266 return;
267 }
268 if (start_pos < 0 || num_tokens <= 0 || num_kv_heads <= 0 ||
269 head_dim <= 0 || max_seq_len <= 0 ||
270 start_pos > max_seq_len - num_tokens) {
271 return;
272 }
273
274 const size_t compact_head_stride = (size_t)num_tokens * (size_t)head_dim;
275 const size_t cache_head_stride = (size_t)max_seq_len * (size_t)head_dim;
276
277 for (int h = 0; h < num_kv_heads; ++h) {
278 const float *k_head = k + (size_t)h * compact_head_stride;
279 const float *v_head = v + (size_t)h * compact_head_stride;
280 uint16_t *k_head_cache = kv_cache_k + (size_t)h * cache_head_stride;
281 uint16_t *v_head_cache = kv_cache_v + (size_t)h * cache_head_stride;
282 for (int t = 0; t < num_tokens; ++t) {
283 const size_t src_offset = (size_t)t * (size_t)head_dim;
284 const size_t dst_offset = (size_t)(start_pos + t) * (size_t)head_dim;
285 ck_local_fp32_to_fp16_row(k_head + src_offset, k_head_cache + dst_offset, head_dim);
286 ck_local_fp32_to_fp16_row(v_head + src_offset, v_head_cache + dst_offset, head_dim);
287 }
288 }
289}
static void ck_local_fp32_to_fp16_row(const float *src, uint16_t *dst, int n)

References ck_local_fp32_to_fp16_row().

◆ kv_cache_store_batch_f32()

void kv_cache_store_batch_f32 ( float *__restrict  kv_cache_k,
float *__restrict  kv_cache_v,
const float *__restrict  k,
const float *__restrict  v,
int  start_pos,
int  num_tokens,
int  num_kv_heads,
int  head_dim,
int  max_seq_len 
)

Definition at line 223 of file kv_cache_kernels.c.

232{
233 if (!kv_cache_k || !kv_cache_v || !k || !v ||
234 start_pos < 0 || num_tokens <= 0 || num_kv_heads <= 0 ||
235 head_dim <= 0 || max_seq_len <= 0 ||
236 start_pos > max_seq_len - num_tokens) {
237 return;
238 }
239
240 const size_t compact_head_stride = (size_t)num_tokens * (size_t)head_dim;
241 const size_t cache_head_stride = (size_t)max_seq_len * (size_t)head_dim;
242 const size_t token_bytes = (size_t)num_tokens * (size_t)head_dim * sizeof(float);
243 for (int h = 0; h < num_kv_heads; ++h) {
244 const float *k_head = k + (size_t)h * compact_head_stride;
245 const float *v_head = v + (size_t)h * compact_head_stride;
246 float *k_head_cache = kv_cache_k + (size_t)h * cache_head_stride
247 + (size_t)start_pos * (size_t)head_dim;
248 float *v_head_cache = kv_cache_v + (size_t)h * cache_head_stride
249 + (size_t)start_pos * (size_t)head_dim;
250 memcpy(k_head_cache, k_head, token_bytes);
251 memcpy(v_head_cache, v_head, token_bytes);
252 }
253}

◆ kv_cache_store_bf16()

void kv_cache_store_bf16 ( uint16_t *__restrict  kv_cache_k,
uint16_t *__restrict  kv_cache_v,
const float *__restrict  k,
const float *__restrict  v,
int  layer,
int  pos,
int  num_kv_heads,
int  head_dim,
int  max_seq_len 
)

Definition at line 195 of file kv_cache_kernels.c.

204{
205 (void)layer;
206 if (!kv_cache_k || !kv_cache_v || !k || !v ||
207 num_kv_heads <= 0 || pos < 0 || pos >= max_seq_len ||
208 head_dim <= 0 || max_seq_len <= 0) {
209 return;
210 }
211
212 const size_t head_stride = (size_t)max_seq_len * (size_t)head_dim;
213 for (int h = 0; h < num_kv_heads; ++h) {
214 const float *k_src = k + (size_t)h * (size_t)head_dim;
215 const float *v_src = v + (size_t)h * (size_t)head_dim;
216 uint16_t *k_dst = kv_cache_k + (size_t)h * head_stride + (size_t)pos * (size_t)head_dim;
217 uint16_t *v_dst = kv_cache_v + (size_t)h * head_stride + (size_t)pos * (size_t)head_dim;
218 ck_local_fp32_to_bf16_row(k_src, k_dst, head_dim);
219 ck_local_fp32_to_bf16_row(v_src, v_dst, head_dim);
220 }
221}

References ck_local_fp32_to_bf16_row().

◆ kv_cache_store_f16()

void kv_cache_store_f16 ( uint16_t *__restrict  kv_cache_k,
uint16_t *__restrict  kv_cache_v,
const float *__restrict  k,
const float *__restrict  v,
int  layer,
int  pos,
int  num_kv_heads,
int  head_dim,
int  max_seq_len 
)

Definition at line 161 of file kv_cache_kernels.c.

170{
171 (void)layer;
172 if (!kv_cache_k || !kv_cache_v || !k || !v) {
173 return;
174 }
175 if (num_kv_heads <= 0 || pos < 0 || head_dim <= 0 || max_seq_len <= 0) {
176 return;
177 }
178 if (pos >= max_seq_len) {
179 return;
180 }
181
182 const size_t head_stride = (size_t)max_seq_len * (size_t)head_dim;
183 const size_t token_stride = (size_t)head_dim;
184
185 for (int h = 0; h < num_kv_heads; ++h) {
186 const float *k_src = k + (size_t)h * token_stride;
187 const float *v_src = v + (size_t)h * token_stride;
188 uint16_t *k_dst = kv_cache_k + (size_t)h * head_stride + (size_t)pos * token_stride;
189 uint16_t *v_dst = kv_cache_v + (size_t)h * head_stride + (size_t)pos * token_stride;
190 ck_local_fp32_to_fp16_row(k_src, k_dst, head_dim);
191 ck_local_fp32_to_fp16_row(v_src, v_dst, head_dim);
192 }
193}

References ck_local_fp32_to_fp16_row().

◆ kv_cache_store_shared_q()

void kv_cache_store_shared_q ( float *__restrict  kv_cache_k,
float *__restrict  kv_cache_v,
const float *__restrict  q,
int  layer,
int  pos,
int  num_heads,
int  head_dim,
int  max_seq_len 
)

Definition at line 142 of file kv_cache_kernels.c.

150{
151 (void)layer;
153 kv_cache_k, kv_cache_v,
154 num_heads,
155 pos,
156 max_seq_len,
157 head_dim,
158 head_dim);
159}

References kv_cache_write_head_major().

◆ kv_cache_write_head_major()

void kv_cache_write_head_major ( const float *__restrict  k_token,
const float *__restrict  v_token,
float *__restrict  k_cache,
float *__restrict  v_cache,
int  num_kv_heads,
int  token_index,
int  cache_capacity,
int  head_dim,
int  aligned_head_dim 
)

Definition at line 81 of file kv_cache_kernels.c.

90{
91 if (!k_token || !v_token || !k_cache || !v_cache) {
92 return;
93 }
94 if (num_kv_heads <= 0 || token_index < 0 || cache_capacity <= 0) {
95 return;
96 }
97 if (token_index >= cache_capacity || head_dim <= 0 || aligned_head_dim <= 0) {
98 return;
99 }
100
101 const size_t head_stride = (size_t)cache_capacity * (size_t)aligned_head_dim;
102 const size_t token_stride = (size_t)aligned_head_dim;
103
104 for (int h = 0; h < num_kv_heads; ++h) {
105 const float *k_src = k_token + (size_t)h * token_stride;
106 const float *v_src = v_token + (size_t)h * token_stride;
107
108 float *k_dst = k_cache + (size_t)h * head_stride + (size_t)token_index * token_stride;
109 float *v_dst = v_cache + (size_t)h * head_stride + (size_t)token_index * token_stride;
110
111 for (int d = 0; d < head_dim; ++d) {
112 k_dst[d] = k_src[d];
113 v_dst[d] = v_src[d];
114 }
115 for (int d = head_dim; d < aligned_head_dim; ++d) {
116 k_dst[d] = 0.0f;
117 v_dst[d] = 0.0f;
118 }
119 }
120}

Referenced by ck_layer_forward_rmsnorm_swiglu_decode(), ck_layer_forward_rmsnorm_swiglu_decode_fused(), ck_layer_forward_rmsnorm_swiglu_decode_fused_attn_impl(), ck_layer_forward_rmsnorm_swiglu_decode_q4_k(), ck_layer_forward_rmsnorm_swiglu_decode_quant(), kv_cache_store(), kv_cache_store_shared_q(), mega_fused_attention_decode_workspace(), qwen2_0_5b_decode_layer_0_decode(), qwen2_0_5b_decode_layer_0_decode(), qwen2_0_5b_decode_layer_0_decode(), qwen2_0_5b_decode_layer_10_decode(), qwen2_0_5b_decode_layer_10_decode(), qwen2_0_5b_decode_layer_10_decode(), qwen2_0_5b_decode_layer_11_decode(), qwen2_0_5b_decode_layer_11_decode(), qwen2_0_5b_decode_layer_11_decode(), qwen2_0_5b_decode_layer_12_decode(), qwen2_0_5b_decode_layer_12_decode(), qwen2_0_5b_decode_layer_12_decode(), qwen2_0_5b_decode_layer_13_decode(), qwen2_0_5b_decode_layer_13_decode(), qwen2_0_5b_decode_layer_13_decode(), qwen2_0_5b_decode_layer_14_decode(), qwen2_0_5b_decode_layer_14_decode(), qwen2_0_5b_decode_layer_14_decode(), qwen2_0_5b_decode_layer_15_decode(), qwen2_0_5b_decode_layer_15_decode(), qwen2_0_5b_decode_layer_15_decode(), qwen2_0_5b_decode_layer_16_decode(), qwen2_0_5b_decode_layer_16_decode(), qwen2_0_5b_decode_layer_16_decode(), qwen2_0_5b_decode_layer_17_decode(), qwen2_0_5b_decode_layer_17_decode(), qwen2_0_5b_decode_layer_17_decode(), qwen2_0_5b_decode_layer_18_decode(), qwen2_0_5b_decode_layer_18_decode(), qwen2_0_5b_decode_layer_18_decode(), qwen2_0_5b_decode_layer_19_decode(), qwen2_0_5b_decode_layer_19_decode(), qwen2_0_5b_decode_layer_19_decode(), qwen2_0_5b_decode_layer_1_decode(), qwen2_0_5b_decode_layer_1_decode(), qwen2_0_5b_decode_layer_1_decode(), qwen2_0_5b_decode_layer_20_decode(), qwen2_0_5b_decode_layer_20_decode(), qwen2_0_5b_decode_layer_20_decode(), qwen2_0_5b_decode_layer_21_decode(), qwen2_0_5b_decode_layer_21_decode(), qwen2_0_5b_decode_layer_21_decode(), qwen2_0_5b_decode_layer_22_decode(), qwen2_0_5b_decode_layer_22_decode(), qwen2_0_5b_decode_layer_22_decode(), qwen2_0_5b_decode_layer_23_decode(), qwen2_0_5b_decode_layer_23_decode(), qwen2_0_5b_decode_layer_23_decode(), qwen2_0_5b_decode_layer_2_decode(), qwen2_0_5b_decode_layer_2_decode(), qwen2_0_5b_decode_layer_2_decode(), qwen2_0_5b_decode_layer_3_decode(), qwen2_0_5b_decode_layer_3_decode(), qwen2_0_5b_decode_layer_3_decode(), qwen2_0_5b_decode_layer_4_decode(), qwen2_0_5b_decode_layer_4_decode(), qwen2_0_5b_decode_layer_4_decode(), qwen2_0_5b_decode_layer_5_decode(), qwen2_0_5b_decode_layer_5_decode(), qwen2_0_5b_decode_layer_5_decode(), qwen2_0_5b_decode_layer_6_decode(), qwen2_0_5b_decode_layer_6_decode(), qwen2_0_5b_decode_layer_6_decode(), qwen2_0_5b_decode_layer_7_decode(), qwen2_0_5b_decode_layer_7_decode(), qwen2_0_5b_decode_layer_7_decode(), qwen2_0_5b_decode_layer_8_decode(), qwen2_0_5b_decode_layer_8_decode(), qwen2_0_5b_decode_layer_8_decode(), qwen2_0_5b_decode_layer_9_decode(), qwen2_0_5b_decode_layer_9_decode(), and qwen2_0_5b_decode_layer_9_decode().

◆ layernorm_backward_kernel()

void layernorm_backward_kernel ( const float *  d_output,
const float *  input,
const float *  gamma,
const float *  mean,
const float *  rstd,
float *  d_input,
float *  d_gamma,
float *  d_beta,
int  tokens,
int  d_model,
int  aligned_embed_dim 
)

Definition at line 1007 of file layernorm_kernels.c.

1016{
1017 int T = tokens;
1018 int D = d_model;
1019 int aligned_D = aligned_embed_dim;
1020
1021 // Per-token input gradients
1022 for (int t = 0; t < T; ++t) {
1023 float mean_t = mean[t];
1024 float rstd_t = rstd[t];
1025
1026 float d_y_gamma_sum = 0.0f;
1027 float d_y_gamma_xhat_sum = 0.0f;
1028
1029 // First pass: compute sums
1030 for (int d = 0; d < D; ++d) {
1031 float x = input[t * aligned_D + d];
1032 float x_hat = (x - mean_t) * rstd_t;
1033 float d_y = d_output[t * aligned_D + d];
1034 float d_y_gamma = d_y * gamma[d];
1035
1036 d_y_gamma_sum += d_y_gamma;
1037 d_y_gamma_xhat_sum += d_y_gamma * x_hat;
1038 }
1039
1040 // Second pass: compute input gradients
1041 float scale = rstd_t / (float)D;
1042 for (int d = 0; d < D; ++d) {
1043 float x = input[t * aligned_D + d];
1044 float x_hat = (x - mean_t) * rstd_t;
1045 float d_y = d_output[t * aligned_D + d];
1046
1047 d_input[t * aligned_D + d] =
1048 scale * ((float)D * d_y * gamma[d] - d_y_gamma_sum - x_hat * d_y_gamma_xhat_sum);
1049 }
1050
1051 // Zero padding for aligned dimension beyond D
1052 for (int d = D; d < aligned_D; ++d) {
1053 d_input[t * aligned_D + d] = 0.0f;
1054 }
1055 }
1056
1057 // Parameter gradients (gamma, beta)
1058 for (int d = 0; d < D; ++d) {
1059 float gamma_grad = 0.0f;
1060 float beta_grad = 0.0f;
1061
1062 for (int t = 0; t < T; ++t) {
1063 float x = input[t * aligned_D + d];
1064 float x_hat = (x - mean[t]) * rstd[t];
1065 float d_y = d_output[t * aligned_D + d];
1066
1067 gamma_grad += d_y * x_hat;
1068 beta_grad += d_y;
1069 }
1070
1071 d_gamma[d] += gamma_grad;
1072 d_beta[d] += beta_grad;
1073 }
1074}

Referenced by layernorm_backward_kernel_bf16().

◆ layernorm_backward_kernel_bf16()

void layernorm_backward_kernel_bf16 ( const uint16_t *  d_output,
const uint16_t *  input,
const float *  gamma,
const float *  mean,
const float *  rstd,
uint16_t *  d_input,
float *  d_gamma,
float *  d_beta,
int  tokens,
int  d_model,
int  aligned_embed_dim,
float *  scratch_d_output,
float *  scratch_input,
float *  scratch_d_input 
)

Definition at line 84 of file layernorm_kernels_bf16.c.

96{
97 if (!scratch_d_output || !scratch_input || !scratch_d_input) return;
98
99 size_t total = (size_t)tokens * (size_t)aligned_embed_dim;
100
101 bf16_tensor_to_float(d_output, scratch_d_output, total);
102 bf16_tensor_to_float(input, scratch_input, total);
103
104 layernorm_backward_kernel(scratch_d_output, scratch_input, gamma, mean, rstd,
105 scratch_d_input, d_gamma, d_beta,
106 tokens, d_model, aligned_embed_dim);
107
108 float_tensor_to_bf16(scratch_d_input, d_input, total);
109}
void layernorm_backward_kernel(const float *d_output, const float *input, const float *gamma, const float *mean, const float *rstd, float *d_input, float *d_gamma, float *d_beta, int tokens, int d_model, int aligned_embed_dim)

References bf16_tensor_to_float(), float_tensor_to_bf16(), and layernorm_backward_kernel().

◆ layernorm_forward_rolled_slice()

void layernorm_forward_rolled_slice ( const float *__restrict  input_slice_base,
const float *__restrict  gamma,
const float *__restrict  beta,
float *__restrict  output_slice_base,
float *__restrict  mean_cache_slice,
float *__restrict  rstd_cache_slice,
int  num_tokens_in_slice,
int  d_model,
int  aligned_embed_dim,
float  eps 
)

Definition at line 398 of file layernorm_kernels.c.

408{
410 layernorm_forward_ggml_exact(input_slice_base, gamma, beta,
411 output_slice_base, mean_cache_slice, rstd_cache_slice,
412 num_tokens_in_slice, d_model,
413 aligned_embed_dim, aligned_embed_dim, aligned_embed_dim, eps);
414 return;
415 }
416
417#if defined(__AVX512F__)
418 layernorm_forward_rolled_slice_avx512(input_slice_base, gamma, beta,
419 output_slice_base, mean_cache_slice, rstd_cache_slice,
420 num_tokens_in_slice, d_model, aligned_embed_dim, eps);
421#elif defined(__AVX2__) || defined(__AVX__)
422 layernorm_forward_rolled_slice_avx256(input_slice_base, gamma, beta,
423 output_slice_base, mean_cache_slice, rstd_cache_slice,
424 num_tokens_in_slice, d_model, aligned_embed_dim, eps);
425#else
426 layernorm_naive_serial(input_slice_base, gamma, beta,
427 output_slice_base, mean_cache_slice, rstd_cache_slice,
428 num_tokens_in_slice, d_model, aligned_embed_dim, eps);
429#endif
430}
static void layernorm_forward_ggml_exact(const float *input, const float *gamma, const float *beta, float *output, float *mean_cache, float *rstd_cache, int tokens, int d_model, int input_stride, int output_stride, int aligned_embed_dim, float eps)
void layernorm_naive_serial(const float *input, const float *gamma, const float *beta, float *output, float *mean_cache, float *rstd_cache, int tokens, int d_model, int aligned_embed_dim, float eps)

References ck_strict_parity_enabled(), layernorm_forward_ggml_exact(), and layernorm_naive_serial().

Referenced by layernorm_forward_rolled_slice_bf16().

◆ layernorm_forward_rolled_slice_bf16()

void layernorm_forward_rolled_slice_bf16 ( const uint16_t *__restrict  input_slice_base,
const float *__restrict  gamma,
const float *__restrict  beta,
uint16_t *__restrict  output_slice_base,
float *__restrict  mean_cache_slice,
float *__restrict  rstd_cache_slice,
int  num_tokens_in_slice,
int  d_model,
int  aligned_embed_dim,
float  eps,
float *  scratch_input,
float *  scratch_output 
)

Definition at line 30 of file layernorm_kernels_bf16.c.

42{
43 if (!scratch_input || !scratch_output) return;
44
45 size_t total = (size_t)num_tokens_in_slice * (size_t)aligned_embed_dim;
46
47 bf16_tensor_to_float(input_slice_base, scratch_input, total);
48 layernorm_forward_rolled_slice(scratch_input, gamma, beta,
49 scratch_output, mean_cache_slice, rstd_cache_slice,
50 num_tokens_in_slice, d_model, aligned_embed_dim, eps);
51 float_tensor_to_bf16(scratch_output, output_slice_base, total);
52}
void layernorm_forward_rolled_slice(const float *__restrict input_slice_base, const float *__restrict gamma, const float *__restrict beta, float *__restrict output_slice_base, float *__restrict mean_cache_slice, float *__restrict rstd_cache_slice, int num_tokens_in_slice, int d_model, int aligned_embed_dim, float eps)

References bf16_tensor_to_float(), float_tensor_to_bf16(), and layernorm_forward_rolled_slice().

◆ layernorm_forward_unrolled_slice()

void layernorm_forward_unrolled_slice ( const float *__restrict  input_slice_base,
const float *__restrict  gamma,
const float *__restrict  beta,
float *__restrict  output_slice_base,
float *__restrict  mean_cache_slice,
float *__restrict  rstd_cache_slice,
int  num_tokens_in_slice,
int  d_model,
float  eps 
)

Definition at line 730 of file layernorm_kernels.c.

739{
741 layernorm_forward_ggml_exact(input_slice_base, gamma, beta,
742 output_slice_base, mean_cache_slice, rstd_cache_slice,
743 num_tokens_in_slice, d_model,
744 d_model, d_model, d_model, eps);
745 return;
746 }
747
748#if defined(__AVX512F__)
749 layernorm_forward_unrolled_slice_avx512(input_slice_base, gamma, beta,
750 output_slice_base, mean_cache_slice, rstd_cache_slice,
751 num_tokens_in_slice, d_model, eps);
752#elif defined(__AVX2__) || defined(__AVX__)
753 layernorm_forward_unrolled_slice_avx256(input_slice_base, gamma, beta,
754 output_slice_base, mean_cache_slice, rstd_cache_slice,
755 num_tokens_in_slice, d_model, eps);
756#else
757 layernorm_forward_unrolled_slice_scalar(input_slice_base, gamma, beta,
758 output_slice_base, mean_cache_slice, rstd_cache_slice,
759 num_tokens_in_slice, d_model, eps);
760#endif
761}
static void layernorm_forward_unrolled_slice_scalar(const float *__restrict input_slice_base, const float *__restrict gamma, const float *__restrict beta, float *__restrict output_slice_base, float *__restrict mean_cache_slice, float *__restrict rstd_cache_slice, int num_tokens_in_slice, int d_model, float eps)

References ck_strict_parity_enabled(), layernorm_forward_ggml_exact(), and layernorm_forward_unrolled_slice_scalar().

Referenced by layernorm_forward_unrolled_slice_bf16().

◆ layernorm_forward_unrolled_slice_bf16()

void layernorm_forward_unrolled_slice_bf16 ( const uint16_t *__restrict  input_slice_base,
const float *__restrict  gamma,
const float *__restrict  beta,
uint16_t *__restrict  output_slice_base,
float *__restrict  mean_cache_slice,
float *__restrict  rstd_cache_slice,
int  num_tokens_in_slice,
int  d_model,
float  eps,
float *  scratch_input,
float *  scratch_output 
)

Definition at line 57 of file layernorm_kernels_bf16.c.

68{
69 if (!scratch_input || !scratch_output) return;
70
71 size_t total = (size_t)num_tokens_in_slice * (size_t)d_model;
72
73 bf16_tensor_to_float(input_slice_base, scratch_input, total);
74 layernorm_forward_unrolled_slice(scratch_input, gamma, beta,
75 scratch_output, mean_cache_slice, rstd_cache_slice,
76 num_tokens_in_slice, d_model, eps);
77 float_tensor_to_bf16(scratch_output, output_slice_base, total);
78}
void layernorm_forward_unrolled_slice(const float *__restrict input_slice_base, const float *__restrict gamma, const float *__restrict beta, float *__restrict output_slice_base, float *__restrict mean_cache_slice, float *__restrict rstd_cache_slice, int num_tokens_in_slice, int d_model, float eps)

References bf16_tensor_to_float(), float_tensor_to_bf16(), and layernorm_forward_unrolled_slice().

◆ layernorm_naive_serial()

void layernorm_naive_serial ( const float *  input,
const float *  gamma,
const float *  beta,
float *  output,
float *  mean_cache,
float *  rstd_cache,
int  tokens,
int  d_model,
int  aligned_embed_dim,
float  eps 
)

Definition at line 175 of file layernorm_kernels.c.

183{
184 for (int t = 0; t < tokens; ++t) {
185 const float *in_ptr = input + t * aligned_embed_dim;
186 float *out_ptr = output + t * aligned_embed_dim;
187
188 float sum_val = 0.0f;
189 for (int i = 0; i < d_model; ++i) {
190 sum_val += in_ptr[i];
191 }
192 float mean = sum_val / (float)d_model;
193
194 float sum_sq_diff = 0.0f;
195 for (int i = 0; i < d_model; ++i) {
196 float diff = in_ptr[i] - mean;
197 sum_sq_diff += diff * diff;
198 }
199 float variance = sum_sq_diff / (float)d_model + eps;
200
201 double var_double = (double)variance;
202 float inv_std = (float)(1.0 / sqrt(var_double));
203
204 for (int i = 0; i < d_model; ++i) {
205 float normalized_val = (in_ptr[i] - mean) * inv_std;
206 out_ptr[i] = normalized_val * gamma[i] + beta[i];
207 }
208
209 if (mean_cache) {
210 mean_cache[t] = mean;
211 }
212 if (rstd_cache) {
213 rstd_cache[t] = inv_std;
214 }
215 /* Keep aligned padding quiet so future GEMMs see deterministic memory. */
216 if (aligned_embed_dim > d_model) {
217 /* Keep padded lanes zeroed so subsequent GEMMs never read stale data. */
218 for (int i = d_model; i < aligned_embed_dim; ++i) {
219 out_ptr[i] = 0.0f;
220 }
221 }
222 }
223}

Referenced by layernorm_forward_rolled_slice().

◆ layernorm_naive_serial_bf16_storage()

void layernorm_naive_serial_bf16_storage ( const float *  input,
const float *  gamma,
const float *  beta,
float *  output,
float *  mean_cache,
float *  rstd_cache,
int  tokens,
int  d_model,
float  eps 
)

Definition at line 786 of file layernorm_kernels.c.

793{
794 const size_t count = (size_t)tokens * (size_t)d_model;
795 for (size_t i = 0; i < count; ++i) {
796 output[i] = bf16_to_float(float_to_bf16(input[i]));
797 }
798 layernorm_forward_ggml_exact(output, gamma, beta,
799 output, mean_cache, rstd_cache,
800 tokens, d_model,
801 d_model, d_model, d_model, eps);
802 for (size_t i = 0; i < count; ++i) {
803 output[i] = bf16_to_float(float_to_bf16(output[i]));
804 }
805}

References bf16_to_float(), float_to_bf16(), and layernorm_forward_ggml_exact().

◆ layernorm_naive_serial_matched_precision()

void layernorm_naive_serial_matched_precision ( const float *  input,
const float *  gamma,
const float *  beta,
float *  output,
float *  mean_cache,
float *  rstd_cache,
int  tokens,
int  d_model,
float  eps 
)

Definition at line 764 of file layernorm_kernels.c.

771{
772 layernorm_forward_ggml_exact(input, gamma, beta,
773 output, mean_cache, rstd_cache,
774 tokens, d_model,
775 d_model, d_model, d_model, eps);
776}

References layernorm_forward_ggml_exact().

Referenced by layernorm_forward_unrolled_slice_scalar().

◆ layernorm_pytorch_welford_bf16_storage()

void layernorm_pytorch_welford_bf16_storage ( const float *  input,
const float *  gamma,
const float *  beta,
float *  output,
float *  mean_cache,
float *  rstd_cache,
int  tokens,
int  d_model,
float  eps 
)

Definition at line 952 of file layernorm_kernels.c.

961{
962#if !defined(__AVX2__) || !defined(__FMA__)
963 (void)input; (void)gamma; (void)beta; (void)output;
964 (void)mean_cache; (void)rstd_cache; (void)tokens; (void)d_model; (void)eps;
965 abort();
966#else
967 for (int t = 0; t < tokens; ++t) {
968 const float *x = input + (size_t)t * (size_t)d_model;
969 float *y = output + (size_t)t * (size_t)d_model;
970 float mean;
971 float variance;
972 layernorm_pytorch_bf16_rowwise_moments_avx2(x, d_model, &mean, &variance);
973 const float rstd = 1.0f / sqrtf(variance + eps);
974 const float bias = -rstd * mean;
975 int i = 0;
976 for (; i + 7 < d_model; i += 8) {
977 const __m256 x_vec = _mm256_loadu_ps(x + i);
978 const __m256 gamma_vec = gamma ? _mm256_loadu_ps(gamma + i) : _mm256_set1_ps(1.0f);
979 const __m256 beta_vec = beta ? _mm256_loadu_ps(beta + i) : _mm256_setzero_ps();
980 const __m256 normalized = _mm256_fmadd_ps(
981 x_vec, _mm256_set1_ps(rstd), _mm256_set1_ps(bias));
982 const __m256 transformed = _mm256_fmadd_ps(normalized, gamma_vec, beta_vec);
983 float lanes[8];
984 _mm256_storeu_ps(lanes, transformed);
985 for (int lane = 0; lane < 8; ++lane) {
986 y[i + lane] = bf16_to_float(float_to_bf16(lanes[lane]));
987 }
988 }
989 for (; i < d_model; ++i) {
990 const float gamma_v = gamma ? gamma[i] : 1.0f;
991 const float beta_v = beta ? beta[i] : 0.0f;
992 const float value = fmaf(fmaf(x[i], rstd, bias), gamma_v, beta_v);
993 y[i] = bf16_to_float(float_to_bf16(value));
994 }
995 if (mean_cache) {
996 mean_cache[t] = mean;
997 }
998 if (rstd_cache) {
999 rstd_cache[t] = rstd;
1000 }
1001 }
1002#endif
1003}

References bf16_to_float(), and float_to_bf16().

◆ mamba2_conv1d_decode_f32()

void mamba2_conv1d_decode_f32 ( const float *  state_in,
const float *  x,
const float *  weight,
const float *  bias,
float *  conv_out,
float *  state_out,
int  rows,
int  conv_dim,
int  kernel_size 
)

Definition at line 148 of file mamba2_kernels.c.

156 {
157 if (!state_in || !x || !weight || !conv_out || !state_out ||
158 rows <= 0 || conv_dim <= 0 || kernel_size <= 0) {
159 return;
160 }
161
162 ck_mamba_debug_finite("conv.state_in", state_in, (size_t)conv_dim * (size_t)kernel_size);
163 ck_mamba_debug_finite("conv.x[0]", x, (size_t)conv_dim);
165 state_in, x, weight, bias, conv_out, state_out,
166 rows, conv_dim, kernel_size, 0, conv_dim);
167 ck_mamba_debug_finite("conv.out[0]", conv_out, (size_t)conv_dim);
168 ck_mamba_debug_finite("conv.state_out", state_out, (size_t)conv_dim * (size_t)kernel_size);
169}
void mamba2_conv1d_f32_channel_range(const float *state_in, const float *x, const float *weight, const float *bias, float *conv_out, float *state_out, int rows, int conv_dim, int kernel_size, int channel_begin, int channel_end)
static void ck_mamba_debug_finite(const char *name, const float *x, size_t n)

References ck_mamba_debug_finite(), and mamba2_conv1d_f32_channel_range().

◆ mamba2_conv1d_f32_channel_range()

void mamba2_conv1d_f32_channel_range ( const float *  state_in,
const float *  x,
const float *  weight,
const float *  bias,
float *  conv_out,
float *  state_out,
int  rows,
int  conv_dim,
int  kernel_size,
int  channel_begin,
int  channel_end 
)

Definition at line 102 of file mamba2_kernels.c.

112 {
113 if (!state_in || !x || !weight || !conv_out || !state_out ||
114 rows <= 0 || conv_dim <= 0 || kernel_size <= 0 ||
115 channel_begin < 0 || channel_begin >= channel_end ||
116 channel_end > conv_dim) {
117 return;
118 }
119
120 /* Time rows are dependent, but channels are independent. Keeping one
121 * channel's rolling state local preserves its exact update order while
122 * allowing disjoint channel ranges to execute concurrently.
123 */
124 for (int ch = channel_begin; ch < channel_end; ++ch) {
125 float state_work[(size_t)kernel_size];
126 const size_t base = (size_t)ch * (size_t)kernel_size;
127 memcpy(state_work, state_in + base,
128 (size_t)kernel_size * sizeof(float));
129 for (int row = 0; row < rows; ++row) {
130 for (int k = 0; k < kernel_size - 1; ++k) {
131 state_work[(size_t)k] = state_work[(size_t)k + 1u];
132 }
133 state_work[(size_t)kernel_size - 1u] =
134 x[(size_t)row * (size_t)conv_dim + (size_t)ch];
135
136 float acc = bias ? bias[ch] : 0.0f;
137 for (int k = 0; k < kernel_size; ++k) {
138 acc += state_work[(size_t)k] *
139 weight[(size_t)ch * (size_t)kernel_size + (size_t)k];
140 }
141 conv_out[(size_t)row * (size_t)conv_dim + (size_t)ch] = mamba2_silu_f32(acc);
142 }
143 memcpy(state_out + base, state_work,
144 (size_t)kernel_size * sizeof(float));
145 }
146}
static float mamba2_silu_f32(float x)

References mamba2_silu_f32().

Referenced by mamba2_conv1d_decode_f32().

◆ mamba2_conv1d_f32_parallel_dispatch()

void mamba2_conv1d_f32_parallel_dispatch ( const float *  state_in,
const float *  x,
const float *  weight,
const float *  bias,
float *  conv_out,
float *  state_out,
int  rows,
int  conv_dim,
int  kernel_size 
)

◆ mamba2_dt_softplus_f32()

void mamba2_dt_softplus_f32 ( const float *  dt,
const float *  dt_bias,
float *  dt_out,
int  rows,
int  num_heads,
float  dt_min,
float  dt_max 
)

Definition at line 171 of file mamba2_kernels.c.

177 {
178 if (!dt || !dt_out || rows <= 0 || num_heads <= 0) {
179 return;
180 }
181
182 ck_mamba_debug_finite("dt.in[0]", dt, (size_t)num_heads);
183 ck_mamba_debug_finite("dt.bias", dt_bias, (size_t)num_heads);
184 for (int row = 0; row < rows; ++row) {
185 for (int h = 0; h < num_heads; ++h) {
186 float v = dt[(size_t)row * (size_t)num_heads + (size_t)h];
187 if (dt_bias) {
188 v += dt_bias[h];
189 }
190 v = mamba2_softplus_f32(v);
191 if (dt_min < dt_max) {
192 if (v < dt_min) {
193 v = dt_min;
194 } else if (v > dt_max) {
195 v = dt_max;
196 }
197 }
198 dt_out[(size_t)row * (size_t)num_heads + (size_t)h] = v;
199 }
200 }
201 ck_mamba_debug_finite("dt.out[0]", dt_out, (size_t)num_heads);
202}
static float mamba2_softplus_f32(float x)

References ck_mamba_debug_finite(), and mamba2_softplus_f32().

◆ mamba2_in_proj_split_f32()

void mamba2_in_proj_split_f32 ( const float *  projected,
float *  gate,
float *  hidden_bc,
float *  dt,
int  rows,
int  d_mlp,
int  intermediate_dim,
int  conv_dim,
int  num_heads 
)

Definition at line 65 of file mamba2_kernels.c.

73 {
74 if (!projected || !gate || !hidden_bc || !dt ||
75 rows <= 0 || d_mlp < 0 || intermediate_dim <= 0 || conv_dim <= 0 || num_heads <= 0) {
76 return;
77 }
78
79 const int projection_dim = 2 * d_mlp + intermediate_dim + conv_dim + num_heads;
80 const int gate_offset = 2 * d_mlp;
81 const int hidden_bc_offset = gate_offset + intermediate_dim;
82 const int dt_offset = hidden_bc_offset + conv_dim;
83
84 ck_mamba_debug_finite("split.projected[0]", projected, (size_t)projection_dim);
85 for (int row = 0; row < rows; ++row) {
86 const float *src = projected + (size_t)row * (size_t)projection_dim;
87 memcpy(gate + (size_t)row * (size_t)intermediate_dim,
88 src + gate_offset,
89 (size_t)intermediate_dim * sizeof(float));
90 memcpy(hidden_bc + (size_t)row * (size_t)conv_dim,
91 src + hidden_bc_offset,
92 (size_t)conv_dim * sizeof(float));
93 memcpy(dt + (size_t)row * (size_t)num_heads,
94 src + dt_offset,
95 (size_t)num_heads * sizeof(float));
96 }
97 ck_mamba_debug_finite("split.gate[0]", gate, (size_t)intermediate_dim);
98 ck_mamba_debug_finite("split.hidden_bc[0]", hidden_bc, (size_t)conv_dim);
99 ck_mamba_debug_finite("split.dt[0]", dt, (size_t)num_heads);
100}

References ck_mamba_debug_finite().

◆ mamba2_rmsnorm_gate_f32()

void mamba2_rmsnorm_gate_f32 ( const float *  x,
const float *  gate,
const float *  weight,
float *  out,
int  rows,
int  inner_dim,
int  group_size,
float  eps 
)

Definition at line 373 of file mamba2_kernels.c.

380 {
381 if (!x || !gate || !weight || !out || rows <= 0 || inner_dim <= 0 || group_size <= 0) {
382 return;
383 }
384
385 ck_mamba_debug_finite("rmsgate.x[0]", x, (size_t)inner_dim);
386 ck_mamba_debug_finite("rmsgate.gate[0]", gate, (size_t)inner_dim);
387 ck_mamba_debug_finite("rmsgate.weight", weight, (size_t)inner_dim);
388 for (int row = 0; row < rows; ++row) {
389 const float *x_row = x + (size_t)row * (size_t)inner_dim;
390 const float *gate_row = gate + (size_t)row * (size_t)inner_dim;
391 float *out_row = out + (size_t)row * (size_t)inner_dim;
392
393 for (int start = 0; start < inner_dim; start += group_size) {
394 int end = start + group_size;
395 if (end > inner_dim) {
396 end = inner_dim;
397 }
398 const int count = end - start;
399 float ms = 0.0f;
400 for (int col = start; col < end; ++col) {
401 const float gated = x_row[col] * mamba2_silu_f32(gate_row[col]);
402 ms += gated * gated;
403 }
404 const float inv_rms = 1.0f / sqrtf(ms / (float)count + eps);
405 for (int col = start; col < end; ++col) {
406 const float gated = x_row[col] * mamba2_silu_f32(gate_row[col]);
407 out_row[col] = gated * inv_rms * weight[col];
408 }
409 }
410 }
411 ck_mamba_debug_finite("rmsgate.out[0]", out, (size_t)inner_dim);
412}
uint32_t end
Definition utf8.c:215
uint32_t start
Definition utf8.c:214

References ck_mamba_debug_finite(), end, mamba2_silu_f32(), and start.

◆ mamba2_selective_scan_f32()

void mamba2_selective_scan_f32 ( const float *  state_init,
const float *  x,
const float *  dt,
const float *  a,
const float *  b,
const float *  c,
const float *  d,
float *  state_out,
float *  y,
int  batch,
int  seq_len,
int  num_heads,
int  head_dim,
int  state_dim,
int  num_groups 
)

Definition at line 339 of file mamba2_kernels.c.

353 {
354 if (!state_init || !x || !dt || !a || !b || !c || !d || !state_out || !y ||
355 batch <= 0 || seq_len <= 0 || num_heads <= 0 || head_dim <= 0 || state_dim <= 0 || num_groups <= 0) {
356 return;
357 }
358
359 const size_t state_per_batch = (size_t)num_heads * (size_t)head_dim * (size_t)state_dim;
360 ck_mamba_debug_finite("scan.state_init", state_init, state_per_batch);
361 ck_mamba_debug_finite("scan.x[0]", x, (size_t)num_heads * (size_t)head_dim + 2u * (size_t)num_groups * (size_t)state_dim);
362 ck_mamba_debug_finite("scan.dt[0]", dt, (size_t)num_heads);
363 ck_mamba_debug_finite("scan.a", a, (size_t)num_heads);
364 ck_mamba_debug_finite("scan.d", d, (size_t)num_heads);
366 state_init, x, dt, a, b, c, d, state_out, y,
367 batch, seq_len, num_heads, head_dim, state_dim, num_groups,
368 0, num_heads);
369 ck_mamba_debug_finite("scan.state_out", state_out, (size_t)batch * state_per_batch);
370 ck_mamba_debug_finite("scan.y[0]", y, (size_t)num_heads * (size_t)head_dim);
371}
void mamba2_selective_scan_f32_head_range(const float *state_init, const float *x, const float *dt, const float *a, const float *b, const float *c, const float *d, float *state_out, float *y, int batch, int seq_len, int num_heads, int head_dim, int state_dim, int num_groups, int head_begin, int head_end)

References ck_mamba_debug_finite(), and mamba2_selective_scan_f32_head_range().

◆ mamba2_selective_scan_f32_head_range()

void mamba2_selective_scan_f32_head_range ( const float *  state_init,
const float *  x,
const float *  dt,
const float *  a,
const float *  b,
const float *  c,
const float *  d,
float *  state_out,
float *  y,
int  batch,
int  seq_len,
int  num_heads,
int  head_dim,
int  state_dim,
int  num_groups,
int  head_begin,
int  head_end 
)

Definition at line 264 of file mamba2_kernels.c.

280 {
281 if (!state_init || !x || !dt || !a || !b || !c || !d || !state_out || !y ||
282 batch <= 0 || seq_len <= 0 || num_heads <= 0 || head_dim <= 0 ||
283 state_dim <= 0 || num_groups <= 0 || head_begin < 0 ||
284 head_begin >= head_end || head_end > num_heads) {
285 return;
286 }
287
288 const size_t state_per_batch = (size_t)num_heads * (size_t)head_dim * (size_t)state_dim;
289 const size_t head_state = (size_t)head_dim * (size_t)state_dim;
290 const int packed_xbc = (x == b && b == c);
291 const size_t inner_dim = (size_t)num_heads * (size_t)head_dim;
292 const size_t bc_dim = (size_t)num_groups * (size_t)state_dim;
293 const size_t packed_stride = inner_dim + 2u * bc_dim;
294 const int heads_per_group = (num_heads + num_groups - 1) / num_groups;
295
296 for (int bs = 0; bs < batch; ++bs) {
297 float *state_batch = state_out + (size_t)bs * state_per_batch;
298 memcpy(state_batch + (size_t)head_begin * head_state,
299 state_init + (size_t)bs * state_per_batch + (size_t)head_begin * head_state,
300 (size_t)(head_end - head_begin) * head_state * sizeof(float));
301 for (int t = 0; t < seq_len; ++t) {
302 for (int h = head_begin; h < head_end; ++h) {
303 /* Nemotron-H prefill and decode both use the repeating
304 * B/C group map from repeat_interleave semantics. Keeping
305 * this in sync is required for full-prefix and incremental
306 * decode equivalence.
307 */
308 int group = h / heads_per_group;
309 if (group >= num_groups) group = num_groups - 1;
310 const float dt_h = dt[((size_t)bs * (size_t)seq_len + (size_t)t) * (size_t)num_heads + (size_t)h];
311 const float d_a = expf(dt_h * a[h]);
312 const float d_h = d[h];
313 const float *packed_row = x + ((size_t)bs * (size_t)seq_len + (size_t)t) * packed_stride;
314 const float *b_row = packed_xbc
315 ? (packed_row + inner_dim + (size_t)group * (size_t)state_dim)
316 : (b + (((size_t)bs * (size_t)seq_len + (size_t)t) * (size_t)num_groups + (size_t)group) * (size_t)state_dim);
317 const float *c_row = packed_xbc
318 ? (packed_row + inner_dim + bc_dim + (size_t)group * (size_t)state_dim)
319 : (c + (((size_t)bs * (size_t)seq_len + (size_t)t) * (size_t)num_groups + (size_t)group) * (size_t)state_dim);
320
321 for (int hd = 0; hd < head_dim; ++hd) {
322 const size_t x_idx = (((size_t)bs * (size_t)seq_len + (size_t)t) * (size_t)num_heads + (size_t)h) * (size_t)head_dim + (size_t)hd;
323 const float x_val = packed_xbc ? packed_row[(size_t)h * (size_t)head_dim + (size_t)hd] : x[x_idx];
324 const size_t state_base = ((size_t)h * (size_t)head_dim + (size_t)hd) * (size_t)state_dim;
325 float acc = 0.0f;
326 for (int st = 0; st < state_dim; ++st) {
327 const size_t si = state_base + (size_t)st;
328 const float new_state = state_batch[si] * d_a + dt_h * b_row[st] * x_val;
329 state_batch[si] = new_state;
330 acc += new_state * c_row[st];
331 }
332 y[x_idx] = acc + d_h * x_val;
333 }
334 }
335 }
336 }
337}

Referenced by mamba2_selective_scan_f32().

◆ mamba2_selective_scan_f32_parallel_dispatch()

void mamba2_selective_scan_f32_parallel_dispatch ( const float *  state_init,
const float *  x,
const float *  dt,
const float *  a,
const float *  b,
const float *  c,
const float *  d,
float *  state_out,
float *  y,
int  batch,
int  seq_len,
int  num_heads,
int  head_dim,
int  state_dim,
int  num_groups 
)

◆ mamba2_selective_state_update_decode_f32()

void mamba2_selective_state_update_decode_f32 ( const float *  state_in,
const float *  x,
const float *  dt,
const float *  a,
const float *  b,
const float *  c,
const float *  d,
float *  state_out,
float *  y,
int  rows,
int  num_heads,
int  head_dim,
int  state_dim,
int  num_groups 
)

Definition at line 204 of file mamba2_kernels.c.

217 {
218 if (!state_in || !x || !dt || !a || !b || !c || !d || !state_out || !y ||
219 rows <= 0 || num_heads <= 0 || head_dim <= 0 || state_dim <= 0 || num_groups <= 0) {
220 return;
221 }
222
223 const int packed_xbc = (x == b && b == c);
224 const size_t inner_dim = (size_t)num_heads * (size_t)head_dim;
225 const size_t bc_dim = (size_t)num_groups * (size_t)state_dim;
226 const size_t packed_stride = inner_dim + 2u * bc_dim;
227
228 for (int row = 0; row < rows; ++row) {
229 const float *packed_row = packed_xbc ? x + (size_t)row * packed_stride : NULL;
230 for (int h = 0; h < num_heads; ++h) {
231 const int heads_per_group = (num_heads + num_groups - 1) / num_groups;
232 int group = h / heads_per_group;
233 if (group >= num_groups) group = num_groups - 1;
234 const float dt_h = dt[(size_t)row * (size_t)num_heads + (size_t)h];
235 const float d_a = expf(dt_h * a[h]);
236 const float d_h = d[h];
237 const float *b_row = packed_xbc
238 ? (packed_row + inner_dim + (size_t)group * (size_t)state_dim)
239 : (b + ((size_t)row * (size_t)num_groups + (size_t)group) * (size_t)state_dim);
240 const float *c_row = packed_xbc
241 ? (packed_row + inner_dim + bc_dim + (size_t)group * (size_t)state_dim)
242 : (c + ((size_t)row * (size_t)num_groups + (size_t)group) * (size_t)state_dim);
243
244 for (int hd = 0; hd < head_dim; ++hd) {
245 const size_t x_idx = ((size_t)row * (size_t)num_heads + (size_t)h) * (size_t)head_dim + (size_t)hd;
246 const float x_val = packed_xbc ? packed_row[(size_t)h * (size_t)head_dim + (size_t)hd] : x[x_idx];
247 const size_t state_base =
248 (((size_t)row * (size_t)num_heads + (size_t)h) * (size_t)head_dim + (size_t)hd) *
249 (size_t)state_dim;
250 float acc = 0.0f;
251 for (int s = 0; s < state_dim; ++s) {
252 const size_t si = state_base + (size_t)s;
253 const float new_state = state_in[si] * d_a + dt_h * b_row[s] * x_val;
254 state_out[si] = new_state;
255 acc += new_state * c_row[s];
256 }
257 y[x_idx] = acc + d_h * x_val;
258 }
259 }
260 }
261}

◆ mlp_token_parallel()

void mlp_token_parallel ( const float *  input,
const float *  W_fc1,
const float *  b_fc1,
const float *  W_fc2,
const float *  b_fc2,
float *  fc1_output,
float *  output,
int  T,
int  aligned_dim,
int  num_threads 
)

Definition at line 49 of file mlp_kernels.c.

59{
60 int D = aligned_dim;
61 int fourD = 4 * D;
62
63 // FC1: [T × D] · [D × 4D] -> [T × 4D]
64 // Our GEMM layout: A[M×K], B[N×K], so B is [4D × D].
65 gemm_blocked_serial(input, W_fc1, b_fc1,
66 fc1_output,
67 T, // M
68 fourD, // N
69 D); // K
70
71 // GELU in-place on FC1 output
72 gelu_fast_inplace(fc1_output, (size_t)T * (size_t)fourD);
73
74 // FC2: [T × 4D] · [4D × D] -> [T × D]
75 gemm_blocked_serial(fc1_output, W_fc2, b_fc2,
76 output,
77 T, // M
78 D, // N
79 fourD); // K
80}
void gelu_fast_inplace(float *data, size_t n)

References gelu_fast_inplace(), and gemm_blocked_serial().

◆ mlp_token_parallel_bf16()

void mlp_token_parallel_bf16 ( const uint16_t *  input,
const uint16_t *  W_fc1,
const uint16_t *  b_fc1,
const uint16_t *  W_fc2,
const uint16_t *  b_fc2,
float *  fc1_output,
float *  output,
int  T,
int  aligned_dim,
int  num_threads,
float *  scratch_bias1_f,
float *  scratch_bias2_f,
uint16_t *  scratch_fc1_bf16 
)

Optimized MLP Forward (BF16 weights, FP32 activations)

Caller-provided scratch buffers: scratch_bias1_f: [4*D] floats scratch_bias2_f: [D] floats scratch_fc1_bf16: [T * 4*D] uint16_t (BF16)

Definition at line 104 of file mlp_kernels_bf16.c.

117{
118 if (!input || !W_fc1 || !b_fc1 || !W_fc2 || !b_fc2 || !fc1_output || !output) return;
119 if (!scratch_bias1_f || !scratch_bias2_f || !scratch_fc1_bf16) return;
120
121 (void)num_threads;
122 const int D = aligned_dim;
123 const int fourD = 4 * D;
124
125 /* Convert biases to FP32 */
126 for (int i = 0; i < fourD; ++i) {
127 scratch_bias1_f[i] = bf16_to_float(b_fc1[i]);
128 }
129 for (int i = 0; i < D; ++i) {
130 scratch_bias2_f[i] = bf16_to_float(b_fc2[i]);
131 }
132
133 /* FC1: [T, D] x [4D, D].T -> [T, 4D] */
134 gemm_bf16_fp32out(input, W_fc1, scratch_bias1_f, fc1_output, T, fourD, D);
135
136 /* GELU activation */
137#if defined(__AVX512F__)
138 #pragma omp parallel for
139 for (int t = 0; t < T; ++t) {
140 float *row = fc1_output + (size_t)t * fourD;
141 int j = 0;
142 for (; j <= fourD - 16; j += 16) {
143 __m512 x = _mm512_loadu_ps(row + j);
144 _mm512_storeu_ps(row + j, gelu_avx512(x));
145 }
146 for (; j < fourD; ++j) {
147 row[j] = gelu_scalar(row[j]);
148 }
149 }
150#else
151 for (int t = 0; t < T; ++t) {
152 for (int j = 0; j < fourD; ++j) {
153 fc1_output[t * fourD + j] = gelu_scalar(fc1_output[t * fourD + j]);
154 }
155 }
156#endif
157
158 /* Convert FP32 activations to BF16 */
159#if defined(__AVX512F__)
160 #pragma omp parallel for
161 for (int t = 0; t < T; ++t) {
162 float *src = fc1_output + (size_t)t * fourD;
163 uint16_t *dst = scratch_fc1_bf16 + (size_t)t * fourD;
164 int j = 0;
165 for (; j <= fourD - 16; j += 16) {
166 __m512 fp32 = _mm512_loadu_ps(src + j);
167 __m512i as_int = _mm512_castps_si512(fp32);
168 __m512i lsb = _mm512_srli_epi32(as_int, 16);
169 lsb = _mm512_and_si512(lsb, _mm512_set1_epi32(1));
170 __m512i rounding = _mm512_add_epi32(_mm512_set1_epi32(0x7FFF), lsb);
171 __m512i rounded = _mm512_add_epi32(as_int, rounding);
172 __m512i shifted = _mm512_srli_epi32(rounded, 16);
173 __m256i bf16 = _mm512_cvtepi32_epi16(shifted);
174 _mm256_storeu_si256((__m256i *)(dst + j), bf16);
175 }
176 for (; j < fourD; ++j) {
177 dst[j] = float_to_bf16(src[j]);
178 }
179 }
180#else
181 for (size_t i = 0; i < (size_t)T * fourD; ++i) {
182 scratch_fc1_bf16[i] = float_to_bf16(fc1_output[i]);
183 }
184#endif
185
186 /* FC2: BF16 GEMM with FP32 output */
187 gemm_bf16_fp32out(scratch_fc1_bf16, W_fc2, scratch_bias2_f, output, T, D, fourD);
188}
static float gelu_scalar(float x)
void gemm_bf16_fp32out(const uint16_t *A, const uint16_t *B, const float *bias, float *C, int M, int N, int K)

References bf16_to_float(), float_to_bf16(), gelu_scalar(), and gemm_bf16_fp32out().

◆ mlp_token_parallel_bf16_backward_mixed()

void mlp_token_parallel_bf16_backward_mixed ( const uint16_t *  input,
const uint16_t *  W_fc1,
const uint16_t *  b_fc1,
const uint16_t *  W_fc2,
const uint16_t *  d_output,
float *  d_input,
float *  d_W_fc1,
float *  d_b_fc1,
float *  d_W_fc2,
float *  d_b_fc2,
int  T,
int  aligned_dim,
int  num_threads,
float *  scratch_fc1_pre,
uint16_t *  scratch_fc1_act_bf16,
float *  scratch_d_fc1 
)

BF16 MLP backward with FP32 gradient accumulation.

Forward contract matched here: z1 = input_bf16 @ W_fc1_bf16.T + b_fc1_bf16 h = GELU(z1) hq = round_to_bf16(h) y = hq @ W_fc2_bf16.T + b_fc2_bf16

Gradients are accumulated and written as FP32. The BF16 activation cast is treated like PyTorch's mixed-precision cast: gradient flows through to h, while d_W_fc2 uses the rounded hq values that FC2 actually consumed.

Definition at line 268 of file mlp_kernels_bf16.c.

284{
285 if (!input || !W_fc1 || !b_fc1 || !W_fc2 || !d_output) return;
286 if (!scratch_fc1_pre || !scratch_fc1_act_bf16 || !scratch_d_fc1) return;
287 if (T <= 0 || aligned_dim <= 0) return;
288
289 (void)num_threads;
290 const int D = aligned_dim;
291 const int fourD = 4 * D;
292
293 /* Recompute FC1 pre-activation and the rounded activation consumed by FC2. */
294 for (int t = 0; t < T; ++t) {
295 for (int j = 0; j < fourD; ++j) {
296 float sum = bf16_to_float(b_fc1[j]);
297 for (int i = 0; i < D; ++i) {
298 const float x = bf16_to_float(input[(size_t)t * (size_t)D + (size_t)i]);
299 const float w = bf16_to_float(W_fc1[(size_t)j * (size_t)D + (size_t)i]);
300 sum += x * w;
301 }
302 scratch_fc1_pre[(size_t)t * (size_t)fourD + (size_t)j] = sum;
303 scratch_fc1_act_bf16[(size_t)t * (size_t)fourD + (size_t)j] = float_to_bf16(gelu_scalar(sum));
304 }
305 }
306
307 if (d_input) {
308 for (int t = 0; t < T; ++t) {
309 for (int i = 0; i < D; ++i) {
310 d_input[(size_t)t * (size_t)D + (size_t)i] = 0.0f;
311 }
312 }
313 }
314 if (d_W_fc1) {
315 for (size_t i = 0; i < (size_t)fourD * (size_t)D; ++i) d_W_fc1[i] = 0.0f;
316 }
317 if (d_b_fc1) {
318 for (int j = 0; j < fourD; ++j) d_b_fc1[j] = 0.0f;
319 }
320 if (d_W_fc2) {
321 for (size_t i = 0; i < (size_t)D * (size_t)fourD; ++i) d_W_fc2[i] = 0.0f;
322 }
323 if (d_b_fc2) {
324 for (int o = 0; o < D; ++o) d_b_fc2[o] = 0.0f;
325 }
326
327 /* d_W_fc2, d_b_fc2, and d_h = d_output @ W_fc2. */
328 for (int t = 0; t < T; ++t) {
329 for (int j = 0; j < fourD; ++j) {
330 float dh = 0.0f;
331 const float hq = bf16_to_float(scratch_fc1_act_bf16[(size_t)t * (size_t)fourD + (size_t)j]);
332 for (int o = 0; o < D; ++o) {
333 const float dy = bf16_to_float(d_output[(size_t)t * (size_t)D + (size_t)o]);
334 const float w2 = bf16_to_float(W_fc2[(size_t)o * (size_t)fourD + (size_t)j]);
335 dh += dy * w2;
336 if (d_W_fc2) {
337 d_W_fc2[(size_t)o * (size_t)fourD + (size_t)j] += dy * hq;
338 }
339 }
340 const float z = scratch_fc1_pre[(size_t)t * (size_t)fourD + (size_t)j];
341 scratch_d_fc1[(size_t)t * (size_t)fourD + (size_t)j] = dh * gelu_derivative_scalar(z);
342 }
343 if (d_b_fc2) {
344 for (int o = 0; o < D; ++o) {
345 d_b_fc2[o] += bf16_to_float(d_output[(size_t)t * (size_t)D + (size_t)o]);
346 }
347 }
348 }
349
350 /* Backprop through FC1. */
351 for (int t = 0; t < T; ++t) {
352 for (int j = 0; j < fourD; ++j) {
353 const float dz = scratch_d_fc1[(size_t)t * (size_t)fourD + (size_t)j];
354 if (d_b_fc1) d_b_fc1[j] += dz;
355 for (int i = 0; i < D; ++i) {
356 const float x = bf16_to_float(input[(size_t)t * (size_t)D + (size_t)i]);
357 const float w1 = bf16_to_float(W_fc1[(size_t)j * (size_t)D + (size_t)i]);
358 if (d_W_fc1) d_W_fc1[(size_t)j * (size_t)D + (size_t)i] += dz * x;
359 if (d_input) d_input[(size_t)t * (size_t)D + (size_t)i] += dz * w1;
360 }
361 }
362 }
363}
static float gelu_derivative_scalar(float x)

References bf16_to_float(), float_to_bf16(), gelu_derivative_scalar(), and gelu_scalar().

◆ mlp_token_parallel_bf16_fp32act()

void mlp_token_parallel_bf16_fp32act ( const uint16_t *  input,
const uint16_t *  W_fc1,
const uint16_t *  b_fc1,
const uint16_t *  W_fc2,
const uint16_t *  b_fc2,
float *  fc1_output,
float *  output,
int  T,
int  aligned_dim,
int  num_threads,
float *  scratch_input_f,
float *  scratch_bias1_f,
float *  scratch_bias2_f,
uint16_t *  scratch_fc1_bf16 
)

Alternative: Fully FP32 activations throughout

Caller-provided scratch buffers: scratch_input_f: [T * D] floats scratch_bias1_f: [4*D] floats scratch_bias2_f: [D] floats scratch_fc1_bf16: [T * 4*D] uint16_t (BF16)

Definition at line 199 of file mlp_kernels_bf16.c.

213{
214 if (!input || !W_fc1 || !b_fc1 || !W_fc2 || !b_fc2 || !fc1_output || !output) return;
215 if (!scratch_input_f || !scratch_bias1_f || !scratch_bias2_f || !scratch_fc1_bf16) return;
216
217 (void)num_threads;
218 const int D = aligned_dim;
219 const int fourD = 4 * D;
220
221 /* Convert input and biases to FP32 */
222 bf16_tensor_to_float(input, scratch_input_f, (size_t)T * D);
223 bf16_tensor_to_float(b_fc1, scratch_bias1_f, fourD);
224 bf16_tensor_to_float(b_fc2, scratch_bias2_f, D);
225
226 /* FC1 */
227 gemm_bf16_fp32out(input, W_fc1, scratch_bias1_f, fc1_output, T, fourD, D);
228
229 /* GELU */
230#if defined(__AVX512F__)
231 #pragma omp parallel for
232 for (int t = 0; t < T; ++t) {
233 float *row = fc1_output + (size_t)t * fourD;
234 int j = 0;
235 for (; j <= fourD - 16; j += 16) {
236 __m512 x = _mm512_loadu_ps(row + j);
237 _mm512_storeu_ps(row + j, gelu_avx512(x));
238 }
239 for (; j < fourD; ++j) {
240 row[j] = gelu_scalar(row[j]);
241 }
242 }
243#else
244 for (size_t i = 0; i < (size_t)T * fourD; ++i) {
245 fc1_output[i] = gelu_scalar(fc1_output[i]);
246 }
247#endif
248
249 /* Convert fc1_output to BF16 for FC2 */
250 float_tensor_to_bf16(fc1_output, scratch_fc1_bf16, (size_t)T * fourD);
251 gemm_bf16_fp32out(scratch_fc1_bf16, W_fc2, scratch_bias2_f, output, T, D, fourD);
252}

References bf16_tensor_to_float(), float_tensor_to_bf16(), gelu_scalar(), and gemm_bf16_fp32out().

◆ mlp_token_parallel_exact()

void mlp_token_parallel_exact ( const float *  input,
const float *  W_fc1,
const float *  b_fc1,
const float *  W_fc2,
const float *  b_fc2,
float *  fc1_output,
float *  output,
int  T,
int  aligned_dim,
int  num_threads 
)

Definition at line 84 of file mlp_kernels.c.

94{
95 (void)num_threads;
96 int D = aligned_dim;
97 int fourD = 4 * D;
98
99 // FC1: [T × D] · [D × 4D] -> [T × 4D]
100 gemm_blocked_serial(input, W_fc1, b_fc1,
101 fc1_output,
102 T, // M
103 fourD, // N
104 D); // K
105
106 // Exact GELU using standard library tanhf
107 gelu_exact_inplace(fc1_output, (size_t)T * (size_t)fourD);
108
109 // FC2: [T × 4D] · [4D × D] -> [T × D]
110 gemm_blocked_serial(fc1_output, W_fc2, b_fc2,
111 output,
112 T, // M
113 D, // N
114 fourD); // K
115}

References gelu_exact_inplace(), and gemm_blocked_serial().

◆ moe_accumulate_expert_f32()

void moe_accumulate_expert_f32 ( float *  output,
const float *  expert_output,
float  routing_weight,
int  hidden_dim 
)

Accumulate expert output: output += routing_weight * expert_output.

Parameters
outputToken output buffer [hidden_dim], accumulated in place
expert_outputExpert's output for this token [hidden_dim]
routing_weightSoftmax routing weight for this expert
hidden_dimHidden dimension

Definition at line 307 of file axpy_kernels.c.

311{
312 axpy_f32(output, expert_output, routing_weight, hidden_dim);
313}

References axpy_f32().

◆ moe_relu2_expert_backward_f32()

void moe_relu2_expert_backward_f32 ( const float *  d_output,
const float *  hidden,
const int *  indices,
const float *  routing_weights,
const float *  expert_up,
const float *  expert_down,
float *  d_hidden,
float *  d_routing_weights,
float *  d_expert_up,
float *  d_expert_down,
int  rows,
int  hidden_dim,
int  intermediate_dim,
int  n_experts,
int  top_k 
)

Definition at line 3706 of file axpy_kernels.c.

3721{
3722 if (!d_output || !hidden || !indices || !routing_weights || !expert_up || !expert_down ||
3723 !d_hidden || !d_routing_weights || !d_expert_up || !d_expert_down ||
3724 rows <= 0 || hidden_dim <= 0 || intermediate_dim <= 0 || n_experts <= 0 || top_k <= 0) {
3725 return;
3726 }
3727
3728 for (size_t p = 0; p < (size_t)rows * (size_t)hidden_dim; ++p) d_hidden[p] = 0.0f;
3729 for (size_t p = 0; p < (size_t)rows * (size_t)top_k; ++p) d_routing_weights[p] = 0.0f;
3730 for (size_t p = 0; p < (size_t)n_experts * (size_t)intermediate_dim * (size_t)hidden_dim; ++p) d_expert_up[p] = 0.0f;
3731 for (size_t p = 0; p < (size_t)n_experts * (size_t)hidden_dim * (size_t)intermediate_dim; ++p) d_expert_down[p] = 0.0f;
3732
3733 float pre[intermediate_dim];
3734 float act[intermediate_dim];
3735 float d_act[intermediate_dim];
3736 float d_pre[intermediate_dim];
3737 float expert_out[hidden_dim];
3738
3739 for (int r = 0; r < rows; ++r) {
3740 const float *x = hidden + (size_t)r * (size_t)hidden_dim;
3741 const float *dy = d_output + (size_t)r * (size_t)hidden_dim;
3742 float *dx = d_hidden + (size_t)r * (size_t)hidden_dim;
3743
3744 for (int slot = 0; slot < top_k; ++slot) {
3745 const int e = indices[(size_t)r * (size_t)top_k + (size_t)slot];
3746 if (e < 0 || e >= n_experts) continue;
3747 const float route_w = routing_weights[(size_t)r * (size_t)top_k + (size_t)slot];
3748
3749 for (int i = 0; i < intermediate_dim; ++i) {
3750 float v = 0.0f;
3751 for (int h = 0; h < hidden_dim; ++h) {
3752 v += expert_up[ck_moe_up_idx(e, i, h, intermediate_dim, hidden_dim)] * x[h];
3753 }
3754 pre[i] = v;
3755 act[i] = (v > 0.0f) ? v * v : 0.0f;
3756 d_act[i] = 0.0f;
3757 }
3758
3759 for (int h = 0; h < hidden_dim; ++h) {
3760 float v = 0.0f;
3761 for (int i = 0; i < intermediate_dim; ++i) {
3762 v += expert_down[ck_moe_down_idx(e, h, i, hidden_dim, intermediate_dim)] * act[i];
3763 }
3764 expert_out[h] = v;
3765 }
3766
3767 float d_route = 0.0f;
3768 for (int h = 0; h < hidden_dim; ++h) {
3769 const float d_expert_out = dy[h] * route_w;
3770 d_route += dy[h] * expert_out[h];
3771 for (int i = 0; i < intermediate_dim; ++i) {
3772 d_expert_down[ck_moe_down_idx(e, h, i, hidden_dim, intermediate_dim)] += d_expert_out * act[i];
3773 d_act[i] += d_expert_out * expert_down[ck_moe_down_idx(e, h, i, hidden_dim, intermediate_dim)];
3774 }
3775 }
3776 d_routing_weights[(size_t)r * (size_t)top_k + (size_t)slot] += d_route;
3777
3778 for (int i = 0; i < intermediate_dim; ++i) {
3779 d_pre[i] = (pre[i] > 0.0f) ? d_act[i] * 2.0f * pre[i] : 0.0f;
3780 }
3781
3782 for (int i = 0; i < intermediate_dim; ++i) {
3783 const float dpi = d_pre[i];
3784 for (int h = 0; h < hidden_dim; ++h) {
3785 d_expert_up[ck_moe_up_idx(e, i, h, intermediate_dim, hidden_dim)] += dpi * x[h];
3786 dx[h] += dpi * expert_up[ck_moe_up_idx(e, i, h, intermediate_dim, hidden_dim)];
3787 }
3788 }
3789 }
3790 }
3791}
static size_t ck_moe_up_idx(int e, int i, int h, int intermediate_dim, int hidden_dim)
static size_t ck_moe_down_idx(int e, int h, int i, int hidden_dim, int intermediate_dim)

References ck_moe_down_idx(), and ck_moe_up_idx().

◆ moe_relu2_expert_forward_f32()

void moe_relu2_expert_forward_f32 ( const float *  hidden,
const int *  indices,
const float *  routing_weights,
const float *  expert_up,
const float *  expert_down,
float *  output,
int  rows,
int  hidden_dim,
int  intermediate_dim,
int  n_experts,
int  top_k 
)

Definition at line 374 of file axpy_kernels.c.

385{
386 if (!hidden || !indices || !routing_weights || !expert_up || !expert_down || !output ||
387 rows <= 0 || hidden_dim <= 0 || intermediate_dim <= 0 || n_experts <= 0 || top_k <= 0) {
388 return;
389 }
390
391 const size_t out_count = (size_t)rows * (size_t)hidden_dim;
392 for (size_t p = 0; p < out_count; ++p) output[p] = 0.0f;
393
394 float pre[intermediate_dim];
395 float gate[intermediate_dim];
396 float up[intermediate_dim];
397 float act[intermediate_dim];
398
399 for (int r = 0; r < rows; ++r) {
400 const float *x = hidden + (size_t)r * (size_t)hidden_dim;
401 float *y = output + (size_t)r * (size_t)hidden_dim;
402 for (int slot = 0; slot < top_k; ++slot) {
403 const int e = indices[(size_t)r * (size_t)top_k + (size_t)slot];
404 if (e < 0 || e >= n_experts) continue;
405 const float route_w = routing_weights[(size_t)r * (size_t)top_k + (size_t)slot];
406
407 for (int i = 0; i < intermediate_dim; ++i) {
408 float v = 0.0f;
409 for (int h = 0; h < hidden_dim; ++h) {
410 v += expert_up[ck_moe_up_idx(e, i, h, intermediate_dim, hidden_dim)] * x[h];
411 }
412 pre[i] = v;
413 act[i] = (v > 0.0f) ? v * v : 0.0f;
414 }
415
416 for (int h = 0; h < hidden_dim; ++h) {
417 float v = 0.0f;
418 for (int i = 0; i < intermediate_dim; ++i) {
419 v += expert_down[ck_moe_down_idx(e, h, i, hidden_dim, intermediate_dim)] * act[i];
420 }
421 y[h] += route_w * v;
422 }
423 }
424 }
425}

References ck_moe_down_idx(), and ck_moe_up_idx().

◆ moe_relu2_expert_forward_q5_0_q5_0()

void moe_relu2_expert_forward_q5_0_q5_0 ( const float *  hidden,
const int *  indices,
const float *  routing_weights,
const void *  expert_up,
const void *  expert_down,
float *  output,
int  rows,
int  hidden_dim,
int  intermediate_dim,
int  n_experts,
int  top_k 
)

Definition at line 3557 of file axpy_kernels.c.

3568{
3569 if (!hidden || !indices || !routing_weights || !expert_up || !expert_down || !output ||
3570 rows <= 0 || hidden_dim <= 0 || intermediate_dim <= 0 || n_experts <= 0 || top_k <= 0) {
3571 return;
3572 }
3573
3574 const size_t out_count = (size_t)rows * (size_t)hidden_dim;
3575 for (size_t p = 0; p < out_count; ++p) output[p] = 0.0f;
3576
3577 const size_t up_row_bytes = ck_dtype_row_bytes(CK_DT_Q5_0, (size_t)hidden_dim);
3578 const size_t down_row_bytes = ck_dtype_row_bytes(CK_DT_Q5_0, (size_t)intermediate_dim);
3579 const uint8_t *up_base = (const uint8_t *)expert_up;
3580 const uint8_t *down_base = (const uint8_t *)expert_down;
3581
3582 float up_row[hidden_dim];
3583 float down_row[intermediate_dim];
3584 float act[intermediate_dim];
3585
3586 for (int r = 0; r < rows; ++r) {
3587 const float *x = hidden + (size_t)r * (size_t)hidden_dim;
3588 float *y = output + (size_t)r * (size_t)hidden_dim;
3589 if (ck_moe_debug_enabled() && r == 0) {
3590 fprintf(stderr,
3591 "[CK_DEBUG_MOE] routed_q5q5 rows=%d hidden=%d intermediate=%d experts=%d top_k=%d up_row_bytes=%zu down_row_bytes=%zu\n",
3592 rows,
3593 hidden_dim,
3594 intermediate_dim,
3595 n_experts,
3596 top_k,
3597 up_row_bytes,
3598 down_row_bytes);
3599 fprintf(stderr, "[CK_DEBUG_MOE] routed slots:");
3600 for (int dbg_slot = 0; dbg_slot < top_k; ++dbg_slot) {
3601 fprintf(stderr,
3602 " (%d,%g)",
3603 indices[(size_t)r * (size_t)top_k + (size_t)dbg_slot],
3604 routing_weights[(size_t)r * (size_t)top_k + (size_t)dbg_slot]);
3605 }
3606 fprintf(stderr, "\n");
3607 ck_moe_debug_finite("routed.hidden[0]", x, (size_t)hidden_dim);
3608 ck_moe_debug_finite("routed.hidden_all", hidden, (size_t)rows * (size_t)hidden_dim);
3609 }
3610 for (int slot = 0; slot < top_k; ++slot) {
3611 const int e = indices[(size_t)r * (size_t)top_k + (size_t)slot];
3612 if (e < 0 || e >= n_experts) continue;
3613 const float route_w = routing_weights[(size_t)r * (size_t)top_k + (size_t)slot];
3614 const uint8_t *expert_up_base = up_base + (size_t)e * (size_t)intermediate_dim * up_row_bytes;
3615 const uint8_t *expert_down_base = down_base + (size_t)e * (size_t)hidden_dim * down_row_bytes;
3616
3617 for (int i = 0; i < intermediate_dim; ++i) {
3618 dequant_q5_0_row(expert_up_base + (size_t)i * up_row_bytes, up_row, (size_t)hidden_dim);
3619 float v = 0.0f;
3620 for (int h = 0; h < hidden_dim; ++h) v += up_row[h] * x[h];
3621 act[i] = (v > 0.0f) ? v * v : 0.0f;
3622 }
3623
3624 for (int h = 0; h < hidden_dim; ++h) {
3625 dequant_q5_0_row(expert_down_base + (size_t)h * down_row_bytes, down_row, (size_t)intermediate_dim);
3626 float v = 0.0f;
3627 for (int i = 0; i < intermediate_dim; ++i) v += down_row[i] * act[i];
3628 y[h] += route_w * v;
3629 }
3630 }
3631 if (ck_moe_debug_enabled() && r == 0) {
3632 ck_moe_debug_finite("routed.output[0]", y, (size_t)hidden_dim);
3633 ck_moe_debug_finite("routed.output_all", output, (size_t)rows * (size_t)hidden_dim);
3634 }
3635 }
3636}
static int ck_moe_debug_enabled(void)
static void ck_moe_debug_finite(const char *name, const float *x, size_t n)

References CK_DT_Q5_0, ck_dtype_row_bytes(), ck_moe_debug_enabled(), ck_moe_debug_finite(), and dequant_q5_0_row().

◆ moe_relu2_expert_forward_q5_0_q8_0()

void moe_relu2_expert_forward_q5_0_q8_0 ( const float *  hidden,
const int *  indices,
const float *  routing_weights,
const void *  expert_up,
const void *  expert_down,
float *  output,
int  rows,
int  hidden_dim,
int  intermediate_dim,
int  n_experts,
int  top_k 
)

Definition at line 3475 of file axpy_kernels.c.

3486{
3487 if (!hidden || !indices || !routing_weights || !expert_up || !expert_down || !output ||
3488 rows <= 0 || hidden_dim <= 0 || intermediate_dim <= 0 || n_experts <= 0 || top_k <= 0) {
3489 return;
3490 }
3491
3492 const size_t out_count = (size_t)rows * (size_t)hidden_dim;
3493 for (size_t p = 0; p < out_count; ++p) output[p] = 0.0f;
3494
3495 const size_t up_row_bytes = ck_dtype_row_bytes(CK_DT_Q5_0, (size_t)hidden_dim);
3496 const size_t down_row_bytes = ck_dtype_row_bytes(CK_DT_Q8_0, (size_t)intermediate_dim);
3497 const uint8_t *up_base = (const uint8_t *)expert_up;
3498 const uint8_t *down_base = (const uint8_t *)expert_down;
3499
3500 float up_row[hidden_dim];
3501 float down_row[intermediate_dim];
3502 float act[intermediate_dim];
3503
3504 for (int r = 0; r < rows; ++r) {
3505 const float *x = hidden + (size_t)r * (size_t)hidden_dim;
3506 float *y = output + (size_t)r * (size_t)hidden_dim;
3507 if (ck_moe_debug_enabled() && r == 0) {
3508 fprintf(stderr,
3509 "[CK_DEBUG_MOE] routed_q5q8 rows=%d hidden=%d intermediate=%d experts=%d top_k=%d up_row_bytes=%zu down_row_bytes=%zu\n",
3510 rows,
3511 hidden_dim,
3512 intermediate_dim,
3513 n_experts,
3514 top_k,
3515 up_row_bytes,
3516 down_row_bytes);
3517 fprintf(stderr, "[CK_DEBUG_MOE] routed slots:");
3518 for (int dbg_slot = 0; dbg_slot < top_k; ++dbg_slot) {
3519 fprintf(stderr,
3520 " (%d,%g)",
3521 indices[(size_t)r * (size_t)top_k + (size_t)dbg_slot],
3522 routing_weights[(size_t)r * (size_t)top_k + (size_t)dbg_slot]);
3523 }
3524 fprintf(stderr, "\n");
3525 ck_moe_debug_finite("routed.hidden[0]", x, (size_t)hidden_dim);
3526 ck_moe_debug_finite("routed.hidden_all", hidden, (size_t)rows * (size_t)hidden_dim);
3527 }
3528 for (int slot = 0; slot < top_k; ++slot) {
3529 const int e = indices[(size_t)r * (size_t)top_k + (size_t)slot];
3530 if (e < 0 || e >= n_experts) continue;
3531 const float route_w = routing_weights[(size_t)r * (size_t)top_k + (size_t)slot];
3532 const uint8_t *expert_up_base = up_base + (size_t)e * (size_t)intermediate_dim * up_row_bytes;
3533 const uint8_t *expert_down_base = down_base + (size_t)e * (size_t)hidden_dim * down_row_bytes;
3534
3535 for (int i = 0; i < intermediate_dim; ++i) {
3536 dequant_q5_0_row(expert_up_base + (size_t)i * up_row_bytes, up_row, (size_t)hidden_dim);
3537 float v = 0.0f;
3538 for (int h = 0; h < hidden_dim; ++h) v += up_row[h] * x[h];
3539 act[i] = (v > 0.0f) ? v * v : 0.0f;
3540 }
3541
3542 for (int h = 0; h < hidden_dim; ++h) {
3543 dequant_q8_0_row(expert_down_base + (size_t)h * down_row_bytes, down_row, (size_t)intermediate_dim);
3544 float v = 0.0f;
3545 for (int i = 0; i < intermediate_dim; ++i) v += down_row[i] * act[i];
3546 y[h] += route_w * v;
3547 }
3548 }
3549 if (ck_moe_debug_enabled() && r == 0) {
3550 ck_moe_debug_finite("routed.output[0]", y, (size_t)hidden_dim);
3551 ck_moe_debug_finite("routed.output_all", output, (size_t)rows * (size_t)hidden_dim);
3552 }
3553 }
3554}

References CK_DT_Q5_0, CK_DT_Q8_0, ck_dtype_row_bytes(), ck_moe_debug_enabled(), ck_moe_debug_finite(), dequant_q5_0_row(), and dequant_q8_0_row().

◆ moe_relu2_shared_forward_q5_1_q8_0()

void moe_relu2_shared_forward_q5_1_q8_0 ( const float *  hidden,
const float *  routed,
const void *  shared_up,
const void *  shared_down,
float *  output,
int  rows,
int  hidden_dim,
int  intermediate_dim 
)

Definition at line 3638 of file axpy_kernels.c.

3646{
3647 if (!hidden || !shared_up || !shared_down || !output || rows <= 0 || hidden_dim <= 0 || intermediate_dim <= 0) {
3648 return;
3649 }
3650
3651 const size_t up_row_bytes = ck_dtype_row_bytes(CK_DT_Q5_1, (size_t)hidden_dim);
3652 const size_t down_row_bytes = ck_dtype_row_bytes(CK_DT_Q8_0, (size_t)intermediate_dim);
3653 const uint8_t *up_base = (const uint8_t *)shared_up;
3654 const uint8_t *down_base = (const uint8_t *)shared_down;
3655
3656 float up_row[hidden_dim];
3657 float down_row[intermediate_dim];
3658 float act[intermediate_dim];
3659
3660 for (int r = 0; r < rows; ++r) {
3661 const float *x = hidden + (size_t)r * (size_t)hidden_dim;
3662 const float *route = routed ? (routed + (size_t)r * (size_t)hidden_dim) : NULL;
3663 float *y = output + (size_t)r * (size_t)hidden_dim;
3664 float x_alias[hidden_dim];
3665 if (output == hidden) {
3666 memcpy(x_alias, x, (size_t)hidden_dim * sizeof(float));
3667 x = x_alias;
3668 }
3669
3670 if (ck_moe_debug_enabled() && r == 0) {
3671 fprintf(stderr,
3672 "[CK_DEBUG_MOE] shared_q5q8 rows=%d hidden=%d intermediate=%d up_row_bytes=%zu down_row_bytes=%zu alias=%d\n",
3673 rows,
3674 hidden_dim,
3675 intermediate_dim,
3676 up_row_bytes,
3677 down_row_bytes,
3678 output == hidden);
3679 ck_moe_debug_finite("shared.hidden[0]", x, (size_t)hidden_dim);
3680 ck_moe_debug_finite("shared.hidden_all", hidden, (size_t)rows * (size_t)hidden_dim);
3681 ck_moe_debug_finite("shared.routed[0]", route, (size_t)hidden_dim);
3682 if (routed) ck_moe_debug_finite("shared.routed_all", routed, (size_t)rows * (size_t)hidden_dim);
3683 }
3684
3685 for (int i = 0; i < intermediate_dim; ++i) {
3686 dequant_q5_1_row(up_base + (size_t)i * up_row_bytes, up_row, (size_t)hidden_dim);
3687 float v = 0.0f;
3688 for (int h = 0; h < hidden_dim; ++h) v += up_row[h] * x[h];
3689 act[i] = (v > 0.0f) ? v * v : 0.0f;
3690 }
3691
3692 for (int h = 0; h < hidden_dim; ++h) {
3693 dequant_q8_0_row(down_base + (size_t)h * down_row_bytes, down_row, (size_t)intermediate_dim);
3694 float v = route ? route[h] : 0.0f;
3695 for (int i = 0; i < intermediate_dim; ++i) v += down_row[i] * act[i];
3696 y[h] = v;
3697 }
3698
3699 if (ck_moe_debug_enabled() && r == 0) {
3700 ck_moe_debug_finite("shared.output[0]", y, (size_t)hidden_dim);
3701 ck_moe_debug_finite("shared.output_all", output, (size_t)rows * (size_t)hidden_dim);
3702 }
3703 }
3704}
@ CK_DT_Q5_1
void dequant_q5_1_row(const void *src, float *dst, size_t n_elements)
Dequantize Q5_1 row (multiple blocks)

References CK_DT_Q5_1, CK_DT_Q8_0, ck_dtype_row_bytes(), ck_moe_debug_enabled(), ck_moe_debug_finite(), dequant_q5_1_row(), and dequant_q8_0_row().

◆ moe_softmax_topk_router_llama_f32_workspace()

int moe_softmax_topk_router_llama_f32_workspace ( const float *  logits,
int *  indices,
float *  weights,
int  rows,
int  n_experts,
int  top_k,
float  routed_scaling_factor,
void *  workspace,
size_t  workspace_bytes 
)

Definition at line 316 of file topk_kernels.c.

326{
327 const size_t required = moe_softmax_topk_router_workspace_bytes(n_experts);
328 if (!logits || !indices || !weights || !workspace || rows <= 0 ||
329 n_experts <= 0 || top_k <= 0 || top_k > n_experts ||
330 !isfinite(routed_scaling_factor) || required == 0 ||
331 workspace_bytes < required) {
332 return -1;
333 }
334
335 float *probabilities = (float *)workspace;
336 for (int row = 0; row < rows; ++row) {
337 const float *row_logits = logits + (size_t)row * (size_t)n_experts;
338 int *row_indices = indices + (size_t)row * (size_t)top_k;
339 float *row_weights = weights + (size_t)row * (size_t)top_k;
340 float max_value = -INFINITY;
341 for (int expert = 0; expert < n_experts; ++expert) {
342 if (!isfinite(row_logits[expert])) {
343 return -2;
344 }
345 if (row_logits[expert] > max_value) {
346 max_value = row_logits[expert];
347 }
348 }
349
350 const double softmax_sum = ck_moe_llama_softmax_row(
351 probabilities, row_logits, n_experts, max_value);
352 const float inverse_softmax_sum = (float)(1.0 / softmax_sum);
353 for (int expert = 0; expert < n_experts; ++expert) {
354 probabilities[expert] *= inverse_softmax_sum;
355 }
356
357 topk_f32(probabilities, n_experts, top_k, row_indices, NULL);
358 double selected_sum_f64 = 0.0;
359 for (int slot = 0; slot < top_k; ++slot) {
360 row_weights[slot] = probabilities[row_indices[slot]];
361 selected_sum_f64 += (double)row_weights[slot];
362 }
363 float selected_sum = (float)selected_sum_f64;
364 if (selected_sum < 6.103515625e-5f) {
365 selected_sum = 6.103515625e-5f;
366 }
367 for (int slot = 0; slot < top_k; ++slot) {
368 row_weights[slot] =
369 (row_weights[slot] / selected_sum) * routed_scaling_factor;
370 }
371 }
372 return 0;
373}
static double ck_moe_llama_softmax_row(float *probabilities, const float *logits, int n_experts, float max_value)
size_t moe_softmax_topk_router_workspace_bytes(int n_experts)
void topk_f32(const float *scores, int n, int k, int *indices, float *values)
Find top-K indices and values from a score vector.

References ck_moe_llama_softmax_row(), moe_softmax_topk_router_workspace_bytes(), and topk_f32().

Referenced by moe_softmax_topk_router_pytorch_bf16_workspace().

◆ moe_softmax_topk_router_pytorch_bf16_workspace()

int moe_softmax_topk_router_pytorch_bf16_workspace ( const float *  logits,
int *  indices,
float *  weights,
int  rows,
int  n_experts,
int  top_k,
float  routed_scaling_factor,
void *  workspace,
size_t  workspace_bytes 
)

Definition at line 375 of file topk_kernels.c.

385{
387 logits, indices, weights, rows, n_experts, top_k,
388 routed_scaling_factor, workspace, workspace_bytes);
389 if (status != 0) {
390 return status;
391 }
392 for (size_t index = 0; index < (size_t)rows * (size_t)top_k; ++index) {
393 weights[index] = bf16_to_float(float_to_bf16(weights[index]));
394 }
395 return 0;
396}
int moe_softmax_topk_router_llama_f32_workspace(const float *logits, int *indices, float *weights, int rows, int n_experts, int top_k, float routed_scaling_factor, void *workspace, size_t workspace_bytes)

References bf16_to_float(), float_to_bf16(), and moe_softmax_topk_router_llama_f32_workspace().

◆ moe_softmax_topk_router_workspace_bytes()

size_t moe_softmax_topk_router_workspace_bytes ( int  n_experts)

Definition at line 177 of file topk_kernels.c.

178{
179 if (n_experts <= 0) {
180 return 0;
181 }
182 return ((size_t)n_experts * sizeof(float) + 63u) & ~(size_t)63u;
183}

Referenced by moe_softmax_topk_router_llama_f32_workspace().

◆ moe_swiglu_expert_forward_bf16()

void moe_swiglu_expert_forward_bf16 ( const float *  hidden,
const int *  indices,
const float *  routing_weights,
const uint16_t *  expert_gate,
const uint16_t *  expert_up,
const uint16_t *  expert_down,
float *  output,
int  rows,
int  hidden_dim,
int  intermediate_dim,
int  n_experts,
int  top_k 
)

Definition at line 563 of file axpy_kernels.c.

575{
576 if (rows <= 0) return;
578 hidden, indices, routing_weights, expert_gate, expert_up, expert_down,
579 output, rows, hidden_dim, intermediate_dim, n_experts, top_k, 0, rows);
580}
void moe_swiglu_expert_forward_bf16_row_range(const float *hidden, const int *indices, const float *routing_weights, const uint16_t *expert_gate, const uint16_t *expert_up, const uint16_t *expert_down, float *output, int rows, int hidden_dim, int intermediate_dim, int n_experts, int top_k, int row_begin, int row_end)

References moe_swiglu_expert_forward_bf16_row_range().

◆ moe_swiglu_expert_forward_bf16_parallel_dispatch()

void moe_swiglu_expert_forward_bf16_parallel_dispatch ( const float *  hidden,
const int *  indices,
const float *  routing_weights,
const uint16_t *  expert_gate,
const uint16_t *  expert_up,
const uint16_t *  expert_down,
float *  output,
int  rows,
int  hidden_dim,
int  intermediate_dim,
int  n_experts,
int  top_k 
)

◆ moe_swiglu_expert_forward_bf16_row_range()

void moe_swiglu_expert_forward_bf16_row_range ( const float *  hidden,
const int *  indices,
const float *  routing_weights,
const uint16_t *  expert_gate,
const uint16_t *  expert_up,
const uint16_t *  expert_down,
float *  output,
int  rows,
int  hidden_dim,
int  intermediate_dim,
int  n_experts,
int  top_k,
int  row_begin,
int  row_end 
)

Definition at line 505 of file axpy_kernels.c.

520{
521 if (!hidden || !indices || !routing_weights || !expert_gate || !expert_up || !expert_down || !output ||
522 rows <= 0 || hidden_dim <= 0 || intermediate_dim <= 0 || n_experts <= 0 || top_k <= 0 ||
523 row_begin < 0 || row_begin >= row_end || row_end > rows) {
524 return;
525 }
526
527 float gate[intermediate_dim];
528 float up[intermediate_dim];
529 float act[intermediate_dim];
530
531 for (int r = row_begin; r < row_end; ++r) {
532 const float *x = hidden + (size_t)r * (size_t)hidden_dim;
533 float *y = output + (size_t)r * (size_t)hidden_dim;
534 for (int h = 0; h < hidden_dim; ++h) y[h] = 0.0f;
535 for (int slot = 0; slot < top_k; ++slot) {
536 const int e = indices[(size_t)r * (size_t)top_k + (size_t)slot];
537 if (e < 0 || e >= n_experts) continue;
538 const float route_w = routing_weights[(size_t)r * (size_t)top_k + (size_t)slot];
539
540 for (int i = 0; i < intermediate_dim; ++i) {
541 float gv = 0.0f;
542 float uv = 0.0f;
543 for (int h = 0; h < hidden_dim; ++h) {
544 gv += bf16_to_float(expert_gate[ck_moe_up_idx(e, i, h, intermediate_dim, hidden_dim)]) * x[h];
545 uv += bf16_to_float(expert_up[ck_moe_up_idx(e, i, h, intermediate_dim, hidden_dim)]) * x[h];
546 }
547 gate[i] = gv;
548 up[i] = uv;
549 act[i] = ck_moe_silu_f32(gv) * uv;
550 }
551
552 for (int h = 0; h < hidden_dim; ++h) {
553 float v = 0.0f;
554 for (int i = 0; i < intermediate_dim; ++i) {
555 v += bf16_to_float(expert_down[ck_moe_down_idx(e, h, i, hidden_dim, intermediate_dim)]) * act[i];
556 }
557 y[h] += route_w * v;
558 }
559 }
560 }
561}

References bf16_to_float(), ck_moe_down_idx(), ck_moe_silu_f32(), and ck_moe_up_idx().

Referenced by moe_swiglu_expert_forward_bf16().

◆ moe_swiglu_expert_forward_f32()

void moe_swiglu_expert_forward_f32 ( const float *  hidden,
const int *  indices,
const float *  routing_weights,
const float *  expert_gate,
const float *  expert_up,
const float *  expert_down,
float *  output,
int  rows,
int  hidden_dim,
int  intermediate_dim,
int  n_experts,
int  top_k 
)

Definition at line 450 of file axpy_kernels.c.

462{
463 if (!hidden || !indices || !routing_weights || !expert_gate || !expert_up || !expert_down || !output ||
464 rows <= 0 || hidden_dim <= 0 || intermediate_dim <= 0 || n_experts <= 0 || top_k <= 0) {
465 return;
466 }
467
468 for (size_t p = 0; p < (size_t)rows * (size_t)hidden_dim; ++p) output[p] = 0.0f;
469
470 float gate[intermediate_dim];
471 float up[intermediate_dim];
472 float act[intermediate_dim];
473
474 for (int r = 0; r < rows; ++r) {
475 const float *x = hidden + (size_t)r * (size_t)hidden_dim;
476 float *y = output + (size_t)r * (size_t)hidden_dim;
477 for (int slot = 0; slot < top_k; ++slot) {
478 const int e = indices[(size_t)r * (size_t)top_k + (size_t)slot];
479 if (e < 0 || e >= n_experts) continue;
480 const float route_w = routing_weights[(size_t)r * (size_t)top_k + (size_t)slot];
481
482 for (int i = 0; i < intermediate_dim; ++i) {
483 float gv = 0.0f;
484 float uv = 0.0f;
485 for (int h = 0; h < hidden_dim; ++h) {
486 gv += expert_gate[ck_moe_up_idx(e, i, h, intermediate_dim, hidden_dim)] * x[h];
487 uv += expert_up[ck_moe_up_idx(e, i, h, intermediate_dim, hidden_dim)] * x[h];
488 }
489 gate[i] = gv;
490 up[i] = uv;
491 act[i] = ck_moe_silu_f32(gv) * uv;
492 }
493
494 for (int h = 0; h < hidden_dim; ++h) {
495 float v = 0.0f;
496 for (int i = 0; i < intermediate_dim; ++i) {
497 v += expert_down[ck_moe_down_idx(e, h, i, hidden_dim, intermediate_dim)] * act[i];
498 }
499 y[h] += route_w * v;
500 }
501 }
502 }
503}

References ck_moe_down_idx(), ck_moe_silu_f32(), and ck_moe_up_idx().

◆ moe_swiglu_expert_forward_q4k_q4k_parallel_workspace()

int moe_swiglu_expert_forward_q4k_q4k_parallel_workspace ( const float *  hidden,
const int *  indices,
const float *  routing_weights,
const void *  expert_gate,
const void *  expert_up,
const void *  expert_down,
float *  output,
int  rows,
int  hidden_dim,
int  intermediate_dim,
int  n_experts,
int  top_k,
void *  workspace,
size_t  workspace_bytes 
)

Definition at line 1881 of file axpy_kernels.c.

1896{
1898 hidden, indices, routing_weights, expert_gate, expert_up, expert_down,
1899 output, rows, hidden_dim, intermediate_dim, n_experts, top_k,
1900 workspace, workspace_bytes,
1902}
int moe_swiglu_expert_forward_q4k_q4k_workspace(const float *hidden, const int *indices, const float *routing_weights, const void *expert_gate, const void *expert_up, const void *expert_down, float *output, int rows, int hidden_dim, int intermediate_dim, int n_experts, int top_k, void *workspace, size_t workspace_bytes)
static int ck_moe_q4k_mixed_parallel_workspace(const float *hidden, const int *indices, const float *routing_weights, const void *expert_gate, const void *expert_up, const void *expert_down, float *output, int rows, int hidden_dim, int intermediate_dim, int n_experts, int top_k, void *workspace, size_t workspace_bytes, ck_moe_expert_workspace_fn serial_fn, ck_moe_down_kind_t down_kind)
@ CK_MOE_DOWN_Q4_K

References CK_MOE_DOWN_Q4_K, ck_moe_q4k_mixed_parallel_workspace(), and moe_swiglu_expert_forward_q4k_q4k_workspace().

◆ moe_swiglu_expert_forward_q4k_q4k_workspace()

int moe_swiglu_expert_forward_q4k_q4k_workspace ( const float *  hidden,
const int *  indices,
const float *  routing_weights,
const void *  expert_gate,
const void *  expert_up,
const void *  expert_down,
float *  output,
int  rows,
int  hidden_dim,
int  intermediate_dim,
int  n_experts,
int  top_k,
void *  workspace,
size_t  workspace_bytes 
)

Definition at line 1108 of file axpy_kernels.c.

1123{
1124 const size_t required = moe_swiglu_expert_q4k_q5k_workspace_bytes(
1125 hidden_dim, intermediate_dim);
1126 if (!hidden || !indices || !routing_weights || !expert_gate ||
1127 !expert_up || !expert_down || !output || !workspace || required == 0 ||
1128 workspace_bytes < required || rows <= 0 || n_experts <= 0 ||
1129 top_k <= 0 || top_k > n_experts) {
1130 return -1;
1131 }
1132
1133 const size_t hidden_q8_bytes = ck_moe_align64(
1134 ck_dtype_row_bytes(CK_DT_Q8_K, (size_t)hidden_dim));
1135 const size_t gate_up_bytes = ck_moe_align64(
1136 2u * (size_t)intermediate_dim * sizeof(float));
1137 const size_t act_q8_bytes = ck_moe_align64(
1138 ck_dtype_row_bytes(CK_DT_Q8_K, (size_t)intermediate_dim));
1139 uint8_t *cursor = (uint8_t *)workspace;
1140 void *hidden_q8 = cursor;
1141 cursor += hidden_q8_bytes;
1142 float *gate_up = (float *)cursor;
1143 cursor += gate_up_bytes;
1144 void *act_q8 = cursor;
1145 cursor += act_q8_bytes;
1146 float *expert_output = (float *)cursor;
1147
1148 const size_t gate_row_bytes = ck_dtype_row_bytes(
1149 CK_DT_Q4_K, (size_t)hidden_dim);
1150 const size_t down_row_bytes = ck_dtype_row_bytes(
1151 CK_DT_Q4_K, (size_t)intermediate_dim);
1152 const uint8_t *gate_base = (const uint8_t *)expert_gate;
1153 const uint8_t *up_base = (const uint8_t *)expert_up;
1154 const uint8_t *down_base = (const uint8_t *)expert_down;
1155
1156 memset(output, 0, (size_t)rows * (size_t)hidden_dim * sizeof(float));
1157 for (int row = 0; row < rows; ++row) {
1158 const float *x = hidden + (size_t)row * (size_t)hidden_dim;
1159 float *y = output + (size_t)row * (size_t)hidden_dim;
1160 quantize_row_q8_k(x, hidden_q8, hidden_dim);
1161 for (int slot = 0; slot < top_k; ++slot) {
1162 const size_t route_index =
1163 (size_t)row * (size_t)top_k + (size_t)slot;
1164 const int expert = indices[route_index];
1165 if (expert < 0 || expert >= n_experts) return -2;
1166 const size_t up_offset =
1167 (size_t)expert * (size_t)intermediate_dim * gate_row_bytes;
1168 const size_t down_offset =
1169 (size_t)expert * (size_t)hidden_dim * down_row_bytes;
1170 gemv_q4_k_q8_k(gate_up, gate_base + up_offset, hidden_q8,
1171 intermediate_dim, hidden_dim);
1172 gemv_q4_k_q8_k(gate_up + intermediate_dim,
1173 up_base + up_offset, hidden_q8,
1174 intermediate_dim, hidden_dim);
1175 swiglu_forward_ggml(gate_up, gate_up, 1, intermediate_dim);
1176 quantize_row_q8_k(gate_up, act_q8, intermediate_dim);
1177 gemv_q4_k_q8_k(expert_output, down_base + down_offset, act_q8,
1178 hidden_dim, intermediate_dim);
1179 axpy_f32(y, expert_output, routing_weights[route_index], hidden_dim);
1180 }
1181 }
1182 return 0;
1183}
size_t moe_swiglu_expert_q4k_q5k_workspace_bytes(int hidden_dim, int intermediate_dim)
static size_t ck_moe_align64(size_t value)
void gemv_q4_k_q8_k(float *y, const void *W, const void *x_q8, int M, int K)
void swiglu_forward_ggml(const float *input, float *output, int tokens, int dim)

References axpy_f32(), CK_DT_Q4_K, CK_DT_Q8_K, ck_dtype_row_bytes(), ck_moe_align64(), gemv_q4_k_q8_k(), moe_swiglu_expert_q4k_q5k_workspace_bytes(), quantize_row_q8_k(), and swiglu_forward_ggml().

Referenced by moe_swiglu_expert_forward_q4k_q4k_parallel_workspace().

◆ moe_swiglu_expert_forward_q4k_q5_0_parallel_workspace()

int moe_swiglu_expert_forward_q4k_q5_0_parallel_workspace ( const float *  hidden,
const int *  indices,
const float *  routing_weights,
const void *  expert_gate,
const void *  expert_up,
const void *  expert_down,
float *  output,
int  rows,
int  hidden_dim,
int  intermediate_dim,
int  n_experts,
int  top_k,
void *  workspace,
size_t  workspace_bytes 
)

Definition at line 1927 of file axpy_kernels.c.

1942{
1944 hidden, indices, routing_weights, expert_gate, expert_up, expert_down,
1945 output, rows, hidden_dim, intermediate_dim, n_experts, top_k,
1946 workspace, workspace_bytes,
1948}
int moe_swiglu_expert_forward_q4k_q5_0_workspace(const float *hidden, const int *indices, const float *routing_weights, const void *expert_gate, const void *expert_up, const void *expert_down, float *output, int rows, int hidden_dim, int intermediate_dim, int n_experts, int top_k, void *workspace, size_t workspace_bytes)
@ CK_MOE_DOWN_Q5_0

References CK_MOE_DOWN_Q5_0, ck_moe_q4k_mixed_parallel_workspace(), and moe_swiglu_expert_forward_q4k_q5_0_workspace().

◆ moe_swiglu_expert_forward_q4k_q5_0_workspace()

int moe_swiglu_expert_forward_q4k_q5_0_workspace ( const float *  hidden,
const int *  indices,
const float *  routing_weights,
const void *  expert_gate,
const void *  expert_up,
const void *  expert_down,
float *  output,
int  rows,
int  hidden_dim,
int  intermediate_dim,
int  n_experts,
int  top_k,
void *  workspace,
size_t  workspace_bytes 
)

Definition at line 1027 of file axpy_kernels.c.

1042{
1043 const size_t required = moe_swiglu_expert_q4k_q8_0_workspace_bytes(
1044 hidden_dim, intermediate_dim);
1045 if (!hidden || !indices || !routing_weights || !expert_gate ||
1046 !expert_up || !expert_down || !output || !workspace || required == 0 ||
1047 workspace_bytes < required || rows <= 0 || n_experts <= 0 ||
1048 top_k <= 0 || top_k > n_experts) {
1049 return -1;
1050 }
1051
1052 const size_t hidden_q8_bytes = ck_moe_align64(
1053 ck_dtype_row_bytes(CK_DT_Q8_K, (size_t)hidden_dim));
1054 const size_t gate_up_bytes = ck_moe_align64(
1055 2u * (size_t)intermediate_dim * sizeof(float));
1056 const size_t act_q8_bytes = ck_moe_align64(
1057 ck_dtype_row_bytes(CK_DT_Q8_0, (size_t)intermediate_dim));
1058 uint8_t *cursor = (uint8_t *)workspace;
1059 void *hidden_q8 = cursor;
1060 cursor += hidden_q8_bytes;
1061 float *gate_up = (float *)cursor;
1062 cursor += gate_up_bytes;
1063 void *act_q8 = cursor;
1064 cursor += act_q8_bytes;
1065 float *expert_output = (float *)cursor;
1066 cursor += ck_moe_align64((size_t)hidden_dim * sizeof(float));
1067 void *projection_scratch = cursor;
1068
1069 const size_t gate_row_bytes = ck_dtype_row_bytes(
1070 CK_DT_Q4_K, (size_t)hidden_dim);
1071 const size_t down_row_bytes = ck_dtype_row_bytes(
1072 CK_DT_Q5_0, (size_t)intermediate_dim);
1073 const uint8_t *gate_base = (const uint8_t *)expert_gate;
1074 const uint8_t *up_base = (const uint8_t *)expert_up;
1075 const uint8_t *down_base = (const uint8_t *)expert_down;
1076
1077 memset(output, 0, (size_t)rows * (size_t)hidden_dim * sizeof(float));
1078 for (int row = 0; row < rows; ++row) {
1079 const float *x = hidden + (size_t)row * (size_t)hidden_dim;
1080 float *y = output + (size_t)row * (size_t)hidden_dim;
1081 quantize_row_q8_k(x, hidden_q8, hidden_dim);
1082 for (int slot = 0; slot < top_k; ++slot) {
1083 const size_t route_index =
1084 (size_t)row * (size_t)top_k + (size_t)slot;
1085 const int expert = indices[route_index];
1086 if (expert < 0 || expert >= n_experts) return -2;
1087 const size_t gate_offset =
1088 (size_t)expert * (size_t)intermediate_dim * gate_row_bytes;
1089 const size_t down_offset =
1090 (size_t)expert * (size_t)hidden_dim * down_row_bytes;
1092 gate_up, gate_base + gate_offset, hidden_q8,
1093 intermediate_dim, hidden_dim, projection_scratch);
1095 gate_up + intermediate_dim, up_base + gate_offset, hidden_q8,
1096 intermediate_dim, hidden_dim, projection_scratch);
1097 swiglu_forward_ggml(gate_up, gate_up, 1, intermediate_dim);
1098 quantize_row_q8_0(gate_up, act_q8, intermediate_dim);
1099 gemv_q5_0_q8_0(expert_output, down_base + down_offset, act_q8,
1100 hidden_dim, intermediate_dim);
1102 y, expert_output, routing_weights[route_index], hidden_dim);
1103 }
1104 }
1105 return 0;
1106}
static void ck_moe_q4k_llama_projection(float *output, const void *weights, const void *input_q8, int output_dim, int input_dim, void *scratch)
static void ck_moe_llama_weighted_accumulate(float *output, const float *expert_output, float route_weight, int n)
size_t moe_swiglu_expert_q4k_q8_0_workspace_bytes(int hidden_dim, int intermediate_dim)
void gemv_q5_0_q8_0(float *y, const void *W, const void *x_q8, int M, int K)
Matrix-vector multiply with Q5_0 weights and Q8_0 input.

References CK_DT_Q4_K, CK_DT_Q5_0, CK_DT_Q8_0, CK_DT_Q8_K, ck_dtype_row_bytes(), ck_moe_align64(), ck_moe_llama_weighted_accumulate(), ck_moe_q4k_llama_projection(), gemv_q5_0_q8_0(), moe_swiglu_expert_q4k_q8_0_workspace_bytes(), quantize_row_q8_0(), quantize_row_q8_k(), and swiglu_forward_ggml().

Referenced by moe_swiglu_expert_forward_q4k_q5_0_parallel_workspace().

◆ moe_swiglu_expert_forward_q4k_q5k_auto_prepared_workspace()

int moe_swiglu_expert_forward_q4k_q5k_auto_prepared_workspace ( const float *  hidden,
const int *  indices,
const float *  routing_weights,
const void *  expert_gate,
const void *  expert_up,
const void *  expert_down,
float *  output,
int  rows,
int  hidden_dim,
int  intermediate_dim,
int  n_experts,
int  top_k,
void *  workspace,
size_t  workspace_bytes 
)

◆ moe_swiglu_expert_forward_q4k_q5k_auto_workspace()

int moe_swiglu_expert_forward_q4k_q5k_auto_workspace ( const float *  hidden,
const int *  indices,
const float *  routing_weights,
const void *  expert_gate,
const void *  expert_up,
const void *  expert_down,
float *  output,
int  rows,
int  hidden_dim,
int  intermediate_dim,
int  n_experts,
int  top_k,
void *  workspace,
size_t  workspace_bytes 
)

Definition at line 2595 of file axpy_kernels.c.

2610{
2611 if (rows < 512) {
2613 hidden, indices, routing_weights,
2614 expert_gate, expert_up, expert_down, output,
2615 rows, hidden_dim, intermediate_dim, n_experts, top_k,
2616 workspace, workspace_bytes);
2617 }
2619 hidden, indices, routing_weights,
2620 expert_gate, expert_up, expert_down, output,
2621 rows, hidden_dim, intermediate_dim, n_experts, top_k,
2622 workspace, workspace_bytes);
2623}
int moe_swiglu_expert_forward_q4k_q5k_parallel_workspace(const float *hidden, const int *indices, const float *routing_weights, const void *expert_gate, const void *expert_up, const void *expert_down, float *output, int rows, int hidden_dim, int intermediate_dim, int n_experts, int top_k, void *workspace, size_t workspace_bytes)
int moe_swiglu_expert_forward_q4k_q5k_bucketed_workspace(const float *hidden, const int *indices, const float *routing_weights, const void *expert_gate, const void *expert_up, const void *expert_down, float *output, int rows, int hidden_dim, int intermediate_dim, int n_experts, int top_k, void *workspace, size_t workspace_bytes)

References moe_swiglu_expert_forward_q4k_q5k_bucketed_workspace(), and moe_swiglu_expert_forward_q4k_q5k_parallel_workspace().

◆ moe_swiglu_expert_forward_q4k_q5k_bucketed_prepared_workspace()

int moe_swiglu_expert_forward_q4k_q5k_bucketed_prepared_workspace ( const float *  hidden,
const int *  indices,
const float *  routing_weights,
const void *  expert_gate,
const void *  expert_up,
const void *  expert_down,
const void *  expert_gate_packed,
const void *  expert_up_packed,
float *  output,
int  rows,
int  hidden_dim,
int  intermediate_dim,
int  n_experts,
int  top_k,
void *  workspace,
size_t  workspace_bytes 
)

Definition at line 2569 of file axpy_kernels.c.

2586{
2588 hidden, indices, routing_weights,
2589 expert_gate, expert_up, expert_down,
2590 expert_gate_packed, expert_up_packed, output,
2591 rows, hidden_dim, intermediate_dim, n_experts, top_k,
2592 workspace, workspace_bytes);
2593}
static int ck_moe_swiglu_expert_forward_q4k_q5k_bucketed_impl(const float *hidden, const int *indices, const float *routing_weights, const void *expert_gate, const void *expert_up, const void *expert_down, const void *expert_gate_packed, const void *expert_up_packed, float *output, int rows, int hidden_dim, int intermediate_dim, int n_experts, int top_k, void *workspace, size_t workspace_bytes)

References ck_moe_swiglu_expert_forward_q4k_q5k_bucketed_impl().

◆ moe_swiglu_expert_forward_q4k_q5k_bucketed_workspace()

int moe_swiglu_expert_forward_q4k_q5k_bucketed_workspace ( const float *  hidden,
const int *  indices,
const float *  routing_weights,
const void *  expert_gate,
const void *  expert_up,
const void *  expert_down,
float *  output,
int  rows,
int  hidden_dim,
int  intermediate_dim,
int  n_experts,
int  top_k,
void *  workspace,
size_t  workspace_bytes 
)

Definition at line 2546 of file axpy_kernels.c.

2561{
2563 hidden, indices, routing_weights,
2564 expert_gate, expert_up, expert_down, NULL, NULL, output,
2565 rows, hidden_dim, intermediate_dim, n_experts, top_k,
2566 workspace, workspace_bytes);
2567}

References ck_moe_swiglu_expert_forward_q4k_q5k_bucketed_impl().

Referenced by moe_swiglu_expert_forward_q4k_q5k_auto_workspace().

◆ moe_swiglu_expert_forward_q4k_q5k_parallel_workspace()

int moe_swiglu_expert_forward_q4k_q5k_parallel_workspace ( const float *  hidden,
const int *  indices,
const float *  routing_weights,
const void *  expert_gate,
const void *  expert_up,
const void *  expert_down,
float *  output,
int  rows,
int  hidden_dim,
int  intermediate_dim,
int  n_experts,
int  top_k,
void *  workspace,
size_t  workspace_bytes 
)

Definition at line 1470 of file axpy_kernels.c.

1485{
1486 const size_t stride = moe_swiglu_expert_q4k_q5k_workspace_bytes(
1487 hidden_dim, intermediate_dim);
1488 if (!hidden || !indices || !routing_weights || !expert_gate || !expert_up ||
1489 !expert_down || !output || !workspace || stride == 0 || rows <= 0 ||
1490 n_experts <= 0 || top_k <= 0 || top_k > n_experts) {
1491 return -1;
1492 }
1493
1494 ck_threadpool_t *pool = ck_threadpool_global();
1495 if (rows == 1) {
1496 const int route_status = ck_moe_q4k_q5k_route_parallel(
1497 hidden, indices, routing_weights,
1498 expert_gate, expert_up, expert_down, output,
1499 hidden_dim, intermediate_dim, n_experts, top_k,
1500 workspace, workspace_bytes, stride, pool);
1501 if (route_status <= 0) return route_status;
1502 }
1503
1504 int active = pool ? ck_threadpool_n_threads(pool) : 1;
1505 if (active > rows) active = rows;
1507 const size_t workspace_workers = workspace_bytes / stride;
1508 if (workspace_workers == 0) return -1;
1509 if ((size_t)active > workspace_workers) active = (int)workspace_workers;
1510 if (active <= 1) {
1512 hidden, indices, routing_weights, expert_gate, expert_up, expert_down,
1513 output, rows, hidden_dim, intermediate_dim, n_experts, top_k,
1514 workspace, stride);
1515 }
1516
1517 ck_moe_q4k_q5k_parallel_args_t args = {
1518 .hidden = hidden,
1519 .indices = indices,
1520 .routing_weights = routing_weights,
1521 .expert_gate = expert_gate,
1522 .expert_up = expert_up,
1523 .expert_down = expert_down,
1524 .output = output,
1525 .rows = rows,
1526 .hidden_dim = hidden_dim,
1527 .intermediate_dim = intermediate_dim,
1528 .n_experts = n_experts,
1529 .top_k = top_k,
1530 .workspace = (uint8_t *)workspace,
1531 .workspace_stride = stride,
1532 .status = {0},
1533 };
1535 for (int ith = 0; ith < active; ++ith) {
1536 if (args.status[ith] != 0) return args.status[ith];
1537 }
1538 return 0;
1539}
static void ck_moe_q4k_q5k_parallel_work(int ith, int nth, void *opaque)
int moe_swiglu_expert_forward_q4k_q5k_workspace(const float *hidden, const int *indices, const float *routing_weights, const void *expert_gate, const void *expert_up, const void *expert_down, float *output, int rows, int hidden_dim, int intermediate_dim, int n_experts, int top_k, void *workspace, size_t workspace_bytes)
static int ck_moe_q4k_q5k_route_parallel(const float *hidden, const int *indices, const float *routing_weights, const void *expert_gate, const void *expert_up, const void *expert_down, float *output, int hidden_dim, int intermediate_dim, int n_experts, int top_k, void *workspace, size_t workspace_bytes, size_t workspace_stride, ck_threadpool_t *pool)
#define CK_THREADPOOL_MAX_THREADS

References ck_moe_q4k_q5k_parallel_work(), ck_moe_q4k_q5k_route_parallel(), ck_threadpool_dispatch_n(), ck_threadpool_global(), CK_THREADPOOL_MAX_THREADS, ck_threadpool_n_threads(), moe_swiglu_expert_forward_q4k_q5k_workspace(), and moe_swiglu_expert_q4k_q5k_workspace_bytes().

Referenced by moe_swiglu_expert_forward_q4k_q5k_auto_workspace().

◆ moe_swiglu_expert_forward_q4k_q5k_workspace()

int moe_swiglu_expert_forward_q4k_q5k_workspace ( const float *  hidden,
const int *  indices,
const float *  routing_weights,
const void *  expert_gate,
const void *  expert_up,
const void *  expert_down,
float *  output,
int  rows,
int  hidden_dim,
int  intermediate_dim,
int  n_experts,
int  top_k,
void *  workspace,
size_t  workspace_bytes 
)

Definition at line 781 of file axpy_kernels.c.

796{
797 const size_t required = moe_swiglu_expert_q4k_q5k_workspace_bytes(
798 hidden_dim, intermediate_dim);
799 if (!hidden || !indices || !routing_weights || !expert_gate || !expert_up ||
800 !expert_down || !output || !workspace || required == 0 ||
801 workspace_bytes < required || rows <= 0 || n_experts <= 0 ||
802 top_k <= 0 || top_k > n_experts) {
803 return -1;
804 }
805
806 const size_t hidden_q8_bytes = ck_moe_align64(
807 ck_dtype_row_bytes(CK_DT_Q8_K, (size_t)hidden_dim));
808 const size_t gate_up_bytes = ck_moe_align64(
809 2u * (size_t)intermediate_dim * sizeof(float));
810 const size_t act_q8_bytes = ck_moe_align64(
811 ck_dtype_row_bytes(CK_DT_Q8_K, (size_t)intermediate_dim));
812 uint8_t *cursor = (uint8_t *)workspace;
813 void *hidden_q8 = cursor;
814 cursor += hidden_q8_bytes;
815 float *gate_up = (float *)cursor;
816 cursor += gate_up_bytes;
817 void *act_q8 = cursor;
818 cursor += act_q8_bytes;
819 float *expert_output = (float *)cursor;
820
821 const size_t q4_row_bytes = ck_dtype_row_bytes(CK_DT_Q4_K, (size_t)hidden_dim);
822 const size_t q5_row_bytes = ck_dtype_row_bytes(CK_DT_Q5_K, (size_t)intermediate_dim);
823 const uint8_t *gate_base = (const uint8_t *)expert_gate;
824 const uint8_t *up_base = (const uint8_t *)expert_up;
825 const uint8_t *down_base = (const uint8_t *)expert_down;
826
827 memset(output, 0, (size_t)rows * (size_t)hidden_dim * sizeof(float));
828 for (int row = 0; row < rows; ++row) {
829 const float *x = hidden + (size_t)row * (size_t)hidden_dim;
830 float *y = output + (size_t)row * (size_t)hidden_dim;
831 quantize_row_q8_k(x, hidden_q8, hidden_dim);
832
833 for (int slot = 0; slot < top_k; ++slot) {
834 const size_t route_index = (size_t)row * (size_t)top_k + (size_t)slot;
835 const int expert = indices[route_index];
836 if (expert < 0 || expert >= n_experts) {
837 return -2;
838 }
839
840 const size_t up_expert_offset =
841 (size_t)expert * (size_t)intermediate_dim * q4_row_bytes;
842 const size_t down_expert_offset =
843 (size_t)expert * (size_t)hidden_dim * q5_row_bytes;
844 gemv_q4_k_q8_k(gate_up,
845 gate_base + up_expert_offset,
846 hidden_q8,
847 intermediate_dim,
848 hidden_dim);
849 gemv_q4_k_q8_k(gate_up + intermediate_dim,
850 up_base + up_expert_offset,
851 hidden_q8,
852 intermediate_dim,
853 hidden_dim);
854 swiglu_forward_ggml(gate_up, gate_up, 1, intermediate_dim);
855 quantize_row_q8_k(gate_up, act_q8, intermediate_dim);
856 gemv_q5_k_q8_k(expert_output,
857 down_base + down_expert_offset,
858 act_q8,
859 hidden_dim,
860 intermediate_dim);
861
862 const float route_weight = routing_weights[route_index];
863 axpy_f32(y, expert_output, route_weight, hidden_dim);
864 }
865 }
866 return 0;
867}
@ CK_DT_Q5_K
void gemv_q5_k_q8_k(float *y, const void *W, const void *x_q8, int M, int K)

References axpy_f32(), CK_DT_Q4_K, CK_DT_Q5_K, CK_DT_Q8_K, ck_dtype_row_bytes(), ck_moe_align64(), gemv_q4_k_q8_k(), gemv_q5_k_q8_k(), moe_swiglu_expert_q4k_q5k_workspace_bytes(), quantize_row_q8_k(), and swiglu_forward_ggml().

Referenced by ck_moe_q4k_q5k_parallel_work(), and moe_swiglu_expert_forward_q4k_q5k_parallel_workspace().

◆ moe_swiglu_expert_forward_q4k_q6k_parallel_workspace()

int moe_swiglu_expert_forward_q4k_q6k_parallel_workspace ( const float *  hidden,
const int *  indices,
const float *  routing_weights,
const void *  expert_gate,
const void *  expert_up,
const void *  expert_down,
float *  output,
int  rows,
int  hidden_dim,
int  intermediate_dim,
int  n_experts,
int  top_k,
void *  workspace,
size_t  workspace_bytes 
)

Definition at line 1858 of file axpy_kernels.c.

1873{
1875 hidden, indices, routing_weights, expert_gate, expert_up, expert_down,
1876 output, rows, hidden_dim, intermediate_dim, n_experts, top_k,
1877 workspace, workspace_bytes,
1879}
int moe_swiglu_expert_forward_q4k_q6k_workspace(const float *hidden, const int *indices, const float *routing_weights, const void *expert_gate, const void *expert_up, const void *expert_down, float *output, int rows, int hidden_dim, int intermediate_dim, int n_experts, int top_k, void *workspace, size_t workspace_bytes)
@ CK_MOE_DOWN_Q6_K

References CK_MOE_DOWN_Q6_K, ck_moe_q4k_mixed_parallel_workspace(), and moe_swiglu_expert_forward_q4k_q6k_workspace().

◆ moe_swiglu_expert_forward_q4k_q6k_workspace()

int moe_swiglu_expert_forward_q4k_q6k_workspace ( const float *  hidden,
const int *  indices,
const float *  routing_weights,
const void *  expert_gate,
const void *  expert_up,
const void *  expert_down,
float *  output,
int  rows,
int  hidden_dim,
int  intermediate_dim,
int  n_experts,
int  top_k,
void *  workspace,
size_t  workspace_bytes 
)

Definition at line 869 of file axpy_kernels.c.

884{
885 const size_t required = moe_swiglu_expert_q4k_q5k_workspace_bytes(
886 hidden_dim, intermediate_dim);
887 if (!hidden || !indices || !routing_weights || !expert_gate ||
888 !expert_up || !expert_down || !output || !workspace || required == 0 ||
889 workspace_bytes < required || rows <= 0 || n_experts <= 0 ||
890 top_k <= 0 || top_k > n_experts) {
891 return -1;
892 }
893
894 const size_t hidden_q8_bytes = ck_moe_align64(
895 ck_dtype_row_bytes(CK_DT_Q8_K, (size_t)hidden_dim));
896 const size_t gate_up_bytes = ck_moe_align64(
897 2u * (size_t)intermediate_dim * sizeof(float));
898 const size_t act_q8_bytes = ck_moe_align64(
899 ck_dtype_row_bytes(CK_DT_Q8_K, (size_t)intermediate_dim));
900 uint8_t *cursor = (uint8_t *)workspace;
901 void *hidden_q8 = cursor;
902 cursor += hidden_q8_bytes;
903 float *gate_up = (float *)cursor;
904 cursor += gate_up_bytes;
905 void *act_q8 = cursor;
906 cursor += act_q8_bytes;
907 float *expert_output = (float *)cursor;
908
909 const size_t q4_row_bytes = ck_dtype_row_bytes(
910 CK_DT_Q4_K, (size_t)hidden_dim);
911 const size_t q6_row_bytes = ck_dtype_row_bytes(
912 CK_DT_Q6_K, (size_t)intermediate_dim);
913 const uint8_t *gate_base = (const uint8_t *)expert_gate;
914 const uint8_t *up_base = (const uint8_t *)expert_up;
915 const uint8_t *down_base = (const uint8_t *)expert_down;
916
917 memset(output, 0, (size_t)rows * (size_t)hidden_dim * sizeof(float));
918 for (int row = 0; row < rows; ++row) {
919 const float *x = hidden + (size_t)row * (size_t)hidden_dim;
920 float *y = output + (size_t)row * (size_t)hidden_dim;
921 quantize_row_q8_k(x, hidden_q8, hidden_dim);
922 for (int slot = 0; slot < top_k; ++slot) {
923 const size_t route_index =
924 (size_t)row * (size_t)top_k + (size_t)slot;
925 const int expert = indices[route_index];
926 if (expert < 0 || expert >= n_experts) return -2;
927 const size_t up_offset =
928 (size_t)expert * (size_t)intermediate_dim * q4_row_bytes;
929 const size_t down_offset =
930 (size_t)expert * (size_t)hidden_dim * q6_row_bytes;
931 gemv_q4_k_q8_k(gate_up, gate_base + up_offset, hidden_q8,
932 intermediate_dim, hidden_dim);
933 gemv_q4_k_q8_k(gate_up + intermediate_dim,
934 up_base + up_offset, hidden_q8,
935 intermediate_dim, hidden_dim);
936 swiglu_forward_ggml(gate_up, gate_up, 1, intermediate_dim);
937 quantize_row_q8_k(gate_up, act_q8, intermediate_dim);
938 gemv_q6_k_q8_k(expert_output, down_base + down_offset, act_q8,
939 hidden_dim, intermediate_dim);
940 axpy_f32(y, expert_output, routing_weights[route_index], hidden_dim);
941 }
942 }
943 return 0;
944}
void gemv_q6_k_q8_k(float *y, const void *W, const void *x_q8, int M, int K)
GEMV: y = W @ x where W is Q6_K and x is Q8_K.

References axpy_f32(), CK_DT_Q4_K, CK_DT_Q6_K, CK_DT_Q8_K, ck_dtype_row_bytes(), ck_moe_align64(), gemv_q4_k_q8_k(), gemv_q6_k_q8_k(), moe_swiglu_expert_q4k_q5k_workspace_bytes(), quantize_row_q8_k(), and swiglu_forward_ggml().

Referenced by moe_swiglu_expert_forward_q4k_q6k_parallel_workspace().

◆ moe_swiglu_expert_forward_q4k_q8_0_parallel_workspace()

int moe_swiglu_expert_forward_q4k_q8_0_parallel_workspace ( const float *  hidden,
const int *  indices,
const float *  routing_weights,
const void *  expert_gate,
const void *  expert_up,
const void *  expert_down,
float *  output,
int  rows,
int  hidden_dim,
int  intermediate_dim,
int  n_experts,
int  top_k,
void *  workspace,
size_t  workspace_bytes 
)

Definition at line 1904 of file axpy_kernels.c.

1919{
1921 hidden, indices, routing_weights, expert_gate, expert_up, expert_down,
1922 output, rows, hidden_dim, intermediate_dim, n_experts, top_k,
1923 workspace, workspace_bytes,
1925}
int moe_swiglu_expert_forward_q4k_q8_0_workspace(const float *hidden, const int *indices, const float *routing_weights, const void *expert_gate, const void *expert_up, const void *expert_down, float *output, int rows, int hidden_dim, int intermediate_dim, int n_experts, int top_k, void *workspace, size_t workspace_bytes)
@ CK_MOE_DOWN_Q8_0

References CK_MOE_DOWN_Q8_0, ck_moe_q4k_mixed_parallel_workspace(), and moe_swiglu_expert_forward_q4k_q8_0_workspace().

◆ moe_swiglu_expert_forward_q4k_q8_0_workspace()

int moe_swiglu_expert_forward_q4k_q8_0_workspace ( const float *  hidden,
const int *  indices,
const float *  routing_weights,
const void *  expert_gate,
const void *  expert_up,
const void *  expert_down,
float *  output,
int  rows,
int  hidden_dim,
int  intermediate_dim,
int  n_experts,
int  top_k,
void *  workspace,
size_t  workspace_bytes 
)

Definition at line 946 of file axpy_kernels.c.

961{
962 const size_t required = moe_swiglu_expert_q4k_q8_0_workspace_bytes(
963 hidden_dim, intermediate_dim);
964 if (!hidden || !indices || !routing_weights || !expert_gate ||
965 !expert_up || !expert_down || !output || !workspace || required == 0 ||
966 workspace_bytes < required || rows <= 0 || n_experts <= 0 ||
967 top_k <= 0 || top_k > n_experts) {
968 return -1;
969 }
970
971 const size_t hidden_q8_bytes = ck_moe_align64(
972 ck_dtype_row_bytes(CK_DT_Q8_K, (size_t)hidden_dim));
973 const size_t gate_up_bytes = ck_moe_align64(
974 2u * (size_t)intermediate_dim * sizeof(float));
975 const size_t act_q8_bytes = ck_moe_align64(
976 ck_dtype_row_bytes(CK_DT_Q8_0, (size_t)intermediate_dim));
977 uint8_t *cursor = (uint8_t *)workspace;
978 void *hidden_q8 = cursor;
979 cursor += hidden_q8_bytes;
980 float *gate_up = (float *)cursor;
981 cursor += gate_up_bytes;
982 void *act_q8 = cursor;
983 cursor += act_q8_bytes;
984 float *expert_output = (float *)cursor;
985 cursor += ck_moe_align64((size_t)hidden_dim * sizeof(float));
986 void *projection_scratch = cursor;
987
988 const size_t gate_row_bytes = ck_dtype_row_bytes(
989 CK_DT_Q4_K, (size_t)hidden_dim);
990 const size_t down_row_bytes = ck_dtype_row_bytes(
991 CK_DT_Q8_0, (size_t)intermediate_dim);
992 const uint8_t *gate_base = (const uint8_t *)expert_gate;
993 const uint8_t *up_base = (const uint8_t *)expert_up;
994 const uint8_t *down_base = (const uint8_t *)expert_down;
995
996 memset(output, 0, (size_t)rows * (size_t)hidden_dim * sizeof(float));
997 for (int row = 0; row < rows; ++row) {
998 const float *x = hidden + (size_t)row * (size_t)hidden_dim;
999 float *y = output + (size_t)row * (size_t)hidden_dim;
1000 quantize_row_q8_k(x, hidden_q8, hidden_dim);
1001 for (int slot = 0; slot < top_k; ++slot) {
1002 const size_t route_index =
1003 (size_t)row * (size_t)top_k + (size_t)slot;
1004 const int expert = indices[route_index];
1005 if (expert < 0 || expert >= n_experts) return -2;
1006 const size_t gate_offset =
1007 (size_t)expert * (size_t)intermediate_dim * gate_row_bytes;
1008 const size_t down_offset =
1009 (size_t)expert * (size_t)hidden_dim * down_row_bytes;
1011 gate_up, gate_base + gate_offset, hidden_q8,
1012 intermediate_dim, hidden_dim, projection_scratch);
1014 gate_up + intermediate_dim, up_base + gate_offset, hidden_q8,
1015 intermediate_dim, hidden_dim, projection_scratch);
1016 swiglu_forward_ggml(gate_up, gate_up, 1, intermediate_dim);
1017 quantize_row_q8_0(gate_up, act_q8, intermediate_dim);
1018 gemv_q8_0_q8_0(expert_output, down_base + down_offset, act_q8,
1019 hidden_dim, intermediate_dim);
1021 y, expert_output, routing_weights[route_index], hidden_dim);
1022 }
1023 }
1024 return 0;
1025}
void gemv_q8_0_q8_0(float *y, const void *W, const void *x_q8, int M, int K)
Matrix-vector multiply with Q8_0 weights and Q8_0 input.

References CK_DT_Q4_K, CK_DT_Q8_0, CK_DT_Q8_K, ck_dtype_row_bytes(), ck_moe_align64(), ck_moe_llama_weighted_accumulate(), ck_moe_q4k_llama_projection(), gemv_q8_0_q8_0(), moe_swiglu_expert_q4k_q8_0_workspace_bytes(), quantize_row_q8_0(), quantize_row_q8_k(), and swiglu_forward_ggml().

Referenced by moe_swiglu_expert_forward_q4k_q8_0_parallel_workspace().

◆ moe_swiglu_expert_q4k_q5k_workspace_bytes()

size_t moe_swiglu_expert_q4k_q5k_workspace_bytes ( int  hidden_dim,
int  intermediate_dim 
)

Definition at line 727 of file axpy_kernels.c.

729{
730 if (hidden_dim <= 0 || intermediate_dim <= 0 ||
731 hidden_dim % 256 != 0 || intermediate_dim % 256 != 0) {
732 return 0;
733 }
734
735 size_t bytes = ck_moe_align64(ck_dtype_row_bytes(CK_DT_Q8_K, (size_t)hidden_dim));
736 bytes += ck_moe_align64(2u * (size_t)intermediate_dim * sizeof(float));
737 bytes += ck_moe_align64(ck_dtype_row_bytes(CK_DT_Q8_K, (size_t)intermediate_dim));
738 bytes += ck_moe_align64((size_t)hidden_dim * sizeof(float));
739 return bytes;
740}

References CK_DT_Q8_K, ck_dtype_row_bytes(), and ck_moe_align64().

Referenced by ck_moe_q4k_mixed_parallel_workspace(), ck_moe_shared_q4k_parallel_workspace(), moe_swiglu_expert_forward_q4k_q4k_workspace(), moe_swiglu_expert_forward_q4k_q5k_parallel_workspace(), moe_swiglu_expert_forward_q4k_q5k_workspace(), moe_swiglu_expert_forward_q4k_q6k_workspace(), moe_swiglu_shared_forward_q4k_q4k_workspace(), and moe_swiglu_shared_forward_q4k_q6k_workspace().

◆ moe_swiglu_expert_q4k_q8_0_workspace_bytes()

size_t moe_swiglu_expert_q4k_q8_0_workspace_bytes ( int  hidden_dim,
int  intermediate_dim 
)

Definition at line 742 of file axpy_kernels.c.

744{
745 if (hidden_dim <= 0 || intermediate_dim <= 0 ||
746 hidden_dim % 256 != 0 || intermediate_dim % QK8_0 != 0) {
747 return 0;
748 }
749
750 size_t bytes = ck_moe_align64(
751 ck_dtype_row_bytes(CK_DT_Q8_K, (size_t)hidden_dim));
752 bytes += ck_moe_align64(2u * (size_t)intermediate_dim * sizeof(float));
753 bytes += ck_moe_align64(
754 ck_dtype_row_bytes(CK_DT_Q8_0, (size_t)intermediate_dim));
755 bytes += ck_moe_align64((size_t)hidden_dim * sizeof(float));
757 intermediate_dim, hidden_dim);
758 return bytes;
759}
static size_t ck_moe_q4k_llama_projection_scratch_bytes(int output_dim, int input_dim)

References CK_DT_Q8_0, CK_DT_Q8_K, ck_dtype_row_bytes(), ck_moe_align64(), ck_moe_q4k_llama_projection_scratch_bytes(), and QK8_0.

Referenced by ck_moe_q4k_mixed_parallel_workspace(), moe_swiglu_expert_forward_q4k_q5_0_workspace(), and moe_swiglu_expert_forward_q4k_q8_0_workspace().

◆ moe_swiglu_packed_expert_forward_bf16()

void moe_swiglu_packed_expert_forward_bf16 ( const float *  hidden,
const int *  indices,
const float *  routing_weights,
const uint16_t *  expert_gate_up,
const uint16_t *  expert_down,
float *  output,
int  rows,
int  hidden_dim,
int  intermediate_dim,
int  n_experts,
int  top_k 
)

Definition at line 582 of file axpy_kernels.c.

594{
595 if (!hidden || !indices || !routing_weights || !expert_gate_up ||
596 !expert_down || !output || rows <= 0 || hidden_dim <= 0 ||
597 intermediate_dim <= 0 || n_experts <= 0 || top_k <= 0) {
598 return;
599 }
600
601 float projection[2 * intermediate_dim];
602 float activation[intermediate_dim];
603 const size_t packed_expert_stride =
604 (size_t)2 * (size_t)intermediate_dim * (size_t)hidden_dim;
605 const size_t packed_up_offset =
606 (size_t)intermediate_dim * (size_t)hidden_dim;
607 for (int row = 0; row < rows; ++row) {
608 float *y = output + (size_t)row * (size_t)hidden_dim;
609 for (int hidden_col = 0; hidden_col < hidden_dim; ++hidden_col) {
610 y[hidden_col] = 0.0f;
611 }
612 }
613 for (int row = 0; row < rows; ++row) {
614 const float *x = hidden + (size_t)row * (size_t)hidden_dim;
615 float *y = output + (size_t)row * (size_t)hidden_dim;
616 for (int slot = 0; slot < top_k; ++slot) {
617 const size_t route_index =
618 (size_t)row * (size_t)top_k + (size_t)slot;
619 const int expert = indices[route_index];
620 if (expert < 0 || expert >= n_experts) continue;
621 const uint16_t *packed =
622 expert_gate_up + (size_t)expert * packed_expert_stride;
623 const uint16_t *gate = packed;
624 const uint16_t *up = packed + packed_up_offset;
625 for (int intermediate = 0; intermediate < intermediate_dim;
626 ++intermediate) {
627 float gate_value = 0.0f;
628 float up_value = 0.0f;
629 const size_t row_offset =
630 (size_t)intermediate * (size_t)hidden_dim;
631 for (int hidden_col = 0; hidden_col < hidden_dim;
632 ++hidden_col) {
633 const float input =
634 ck_moe_bf16_round(x[hidden_col]);
635 gate_value +=
636 bf16_to_float(gate[row_offset + hidden_col]) * input;
637 up_value +=
638 bf16_to_float(up[row_offset + hidden_col]) * input;
639 }
640 projection[intermediate] =
641 ck_moe_bf16_round(gate_value);
642 projection[intermediate_dim + intermediate] =
643 ck_moe_bf16_round(up_value);
644 }
646 projection, activation, 1, intermediate_dim);
647
648 const float route_weight =
649 ck_moe_bf16_round(routing_weights[route_index]);
650 for (int hidden_col = 0; hidden_col < hidden_dim;
651 ++hidden_col) {
652 float value = 0.0f;
653 for (int intermediate = 0;
654 intermediate < intermediate_dim; ++intermediate) {
655 value += bf16_to_float(expert_down[
656 ck_moe_down_idx(expert, hidden_col, intermediate,
657 hidden_dim, intermediate_dim)]) *
658 activation[intermediate];
659 }
660 const float down_stored = ck_moe_bf16_round(value);
661 const float weighted = ck_moe_bf16_round(
662 down_stored * route_weight);
663 y[hidden_col] += weighted;
664 }
665 }
666 for (int hidden_col = 0; hidden_col < hidden_dim; ++hidden_col) {
667 y[hidden_col] = ck_moe_bf16_round(y[hidden_col]);
668 }
669 }
670}
static float ck_moe_bf16_round(float x)
void swiglu_forward_pytorch_bf16_storage(const float *input, float *output, int tokens, int dim)

References bf16_to_float(), ck_moe_bf16_round(), ck_moe_down_idx(), and swiglu_forward_pytorch_bf16_storage().

◆ moe_swiglu_shared_forward_bf16()

void moe_swiglu_shared_forward_bf16 ( const float *  hidden,
const float *  routed,
const uint16_t *  shared_gate,
const uint16_t *  shared_up,
const uint16_t *  shared_down,
float *  output,
int  rows,
int  hidden_dim,
int  intermediate_dim 
)

Definition at line 3205 of file axpy_kernels.c.

3214{
3215 if (rows <= 0) return;
3217 hidden, routed, shared_gate, shared_up, shared_down, output,
3218 rows, hidden_dim, intermediate_dim, 0, rows);
3219}
void moe_swiglu_shared_forward_bf16_row_range(const float *hidden, const float *routed, const uint16_t *shared_gate, const uint16_t *shared_up, const uint16_t *shared_down, float *output, int rows, int hidden_dim, int intermediate_dim, int row_begin, int row_end)

References moe_swiglu_shared_forward_bf16_row_range().

◆ moe_swiglu_shared_forward_bf16_gated()

void moe_swiglu_shared_forward_bf16_gated ( const float *  hidden,
const float *  routed,
const uint16_t *  shared_gate,
const uint16_t *  shared_up,
const uint16_t *  shared_down,
const uint16_t *  shared_router,
float *  output,
int  rows,
int  hidden_dim,
int  intermediate_dim 
)

Definition at line 3298 of file axpy_kernels.c.

3309{
3310 if (rows <= 0) return;
3312 hidden, routed, shared_gate, shared_up, shared_down, shared_router,
3313 output, rows, hidden_dim, intermediate_dim, 0, rows);
3314}
void moe_swiglu_shared_forward_bf16_gated_row_range(const float *hidden, const float *routed, const uint16_t *shared_gate, const uint16_t *shared_up, const uint16_t *shared_down, const uint16_t *shared_router, float *output, int rows, int hidden_dim, int intermediate_dim, int row_begin, int row_end)

References moe_swiglu_shared_forward_bf16_gated_row_range().

◆ moe_swiglu_shared_forward_bf16_gated_parallel_dispatch()

void moe_swiglu_shared_forward_bf16_gated_parallel_dispatch ( const float *  hidden,
const float *  routed,
const uint16_t *  shared_gate,
const uint16_t *  shared_up,
const uint16_t *  shared_down,
const uint16_t *  shared_router,
float *  output,
int  rows,
int  hidden_dim,
int  intermediate_dim 
)

◆ moe_swiglu_shared_forward_bf16_gated_row_range()

void moe_swiglu_shared_forward_bf16_gated_row_range ( const float *  hidden,
const float *  routed,
const uint16_t *  shared_gate,
const uint16_t *  shared_up,
const uint16_t *  shared_down,
const uint16_t *  shared_router,
float *  output,
int  rows,
int  hidden_dim,
int  intermediate_dim,
int  row_begin,
int  row_end 
)

Definition at line 3221 of file axpy_kernels.c.

3234{
3235 if (!hidden || !shared_gate || !shared_up || !shared_down ||
3236 !shared_router || !output || rows <= 0 || hidden_dim <= 0 ||
3237 intermediate_dim <= 0 || row_begin < 0 || row_begin >= row_end ||
3238 row_end > rows) {
3239 return;
3240 }
3241
3242 float activation[intermediate_dim];
3243 for (int row = row_begin; row < row_end; ++row) {
3244 const float *x = hidden + (size_t)row * (size_t)hidden_dim;
3245 const float *route = routed
3246 ? routed + (size_t)row * (size_t)hidden_dim
3247 : NULL;
3248 float *y = output + (size_t)row * (size_t)hidden_dim;
3249
3250 for (int intermediate = 0; intermediate < intermediate_dim;
3251 ++intermediate) {
3252 float gate_sum = 0.0f;
3253 float up_sum = 0.0f;
3254 const size_t weight_base =
3255 (size_t)intermediate * (size_t)hidden_dim;
3256 for (int hidden_col = 0; hidden_col < hidden_dim; ++hidden_col) {
3257 const float value = ck_moe_bf16_round(x[hidden_col]);
3258 gate_sum += bf16_to_float(
3259 shared_gate[weight_base + (size_t)hidden_col]) * value;
3260 up_sum += bf16_to_float(
3261 shared_up[weight_base + (size_t)hidden_col]) * value;
3262 }
3263 const float gate_value = ck_moe_bf16_round(gate_sum);
3264 const float up_value = ck_moe_bf16_round(up_sum);
3265 const float silu = ck_moe_bf16_round(
3266 ck_moe_silu_f32(gate_value));
3267 activation[intermediate] = ck_moe_bf16_round(silu * up_value);
3268 }
3269
3270 float router_sum = 0.0f;
3271 for (int hidden_col = 0; hidden_col < hidden_dim; ++hidden_col) {
3272 router_sum += bf16_to_float(shared_router[hidden_col]) *
3273 ck_moe_bf16_round(x[hidden_col]);
3274 }
3275 const float shared_scale = ck_moe_bf16_round(
3277
3278 for (int hidden_col = 0; hidden_col < hidden_dim; ++hidden_col) {
3279 float down_sum = 0.0f;
3280 const size_t weight_base =
3281 (size_t)hidden_col * (size_t)intermediate_dim;
3282 for (int intermediate = 0; intermediate < intermediate_dim;
3283 ++intermediate) {
3284 down_sum += bf16_to_float(
3285 shared_down[weight_base + (size_t)intermediate]) *
3286 activation[intermediate];
3287 }
3288 const float shared = ck_moe_bf16_round(down_sum);
3289 const float gated_shared = ck_moe_bf16_round(shared * shared_scale);
3290 const float routed_value = route
3291 ? ck_moe_bf16_round(route[hidden_col])
3292 : 0.0f;
3293 y[hidden_col] = ck_moe_bf16_round(routed_value + gated_shared);
3294 }
3295 }
3296}
static float ck_moe_sigmoid_f32(float x)

References bf16_to_float(), ck_moe_bf16_round(), ck_moe_sigmoid_f32(), ck_moe_silu_f32(), and silu().

Referenced by moe_swiglu_shared_forward_bf16_gated().

◆ moe_swiglu_shared_forward_bf16_parallel_dispatch()

void moe_swiglu_shared_forward_bf16_parallel_dispatch ( const float *  hidden,
const float *  routed,
const uint16_t *  shared_gate,
const uint16_t *  shared_up,
const uint16_t *  shared_down,
float *  output,
int  rows,
int  hidden_dim,
int  intermediate_dim 
)

◆ moe_swiglu_shared_forward_bf16_row_range()

void moe_swiglu_shared_forward_bf16_row_range ( const float *  hidden,
const float *  routed,
const uint16_t *  shared_gate,
const uint16_t *  shared_up,
const uint16_t *  shared_down,
float *  output,
int  rows,
int  hidden_dim,
int  intermediate_dim,
int  row_begin,
int  row_end 
)

Definition at line 3157 of file axpy_kernels.c.

3169{
3170 if (!hidden || !shared_gate || !shared_up || !shared_down || !output ||
3171 rows <= 0 || hidden_dim <= 0 || intermediate_dim <= 0 ||
3172 row_begin < 0 || row_begin >= row_end || row_end > rows) {
3173 return;
3174 }
3175
3176 float gate[intermediate_dim];
3177 float up[intermediate_dim];
3178 float act[intermediate_dim];
3179
3180 for (int r = row_begin; r < row_end; ++r) {
3181 const float *x = hidden + (size_t)r * (size_t)hidden_dim;
3182 const float *route = routed ? (routed + (size_t)r * (size_t)hidden_dim) : NULL;
3183 float *y = output + (size_t)r * (size_t)hidden_dim;
3184 for (int i = 0; i < intermediate_dim; ++i) {
3185 float gv = 0.0f;
3186 float uv = 0.0f;
3187 for (int h = 0; h < hidden_dim; ++h) {
3188 gv += bf16_to_float(shared_gate[(size_t)i * (size_t)hidden_dim + (size_t)h]) * x[h];
3189 uv += bf16_to_float(shared_up[(size_t)i * (size_t)hidden_dim + (size_t)h]) * x[h];
3190 }
3191 gate[i] = gv;
3192 up[i] = uv;
3193 act[i] = ck_moe_silu_f32(gv) * uv;
3194 }
3195 for (int h = 0; h < hidden_dim; ++h) {
3196 float v = route ? route[h] : 0.0f;
3197 for (int i = 0; i < intermediate_dim; ++i) {
3198 v += bf16_to_float(shared_down[(size_t)h * (size_t)intermediate_dim + (size_t)i]) * act[i];
3199 }
3200 y[h] = v;
3201 }
3202 }
3203}

References bf16_to_float(), and ck_moe_silu_f32().

Referenced by moe_swiglu_shared_forward_bf16().

◆ moe_swiglu_shared_forward_f32()

void moe_swiglu_shared_forward_f32 ( const float *  hidden,
const float *  routed,
const float *  shared_gate,
const float *  shared_up,
const float *  shared_down,
float *  output,
int  rows,
int  hidden_dim,
int  intermediate_dim 
)

Definition at line 3116 of file axpy_kernels.c.

3125{
3126 if (!hidden || !shared_gate || !shared_up || !shared_down || !output || rows <= 0 || hidden_dim <= 0 || intermediate_dim <= 0) {
3127 return;
3128 }
3129
3130 float gate[intermediate_dim];
3131 float up[intermediate_dim];
3132 float act[intermediate_dim];
3133
3134 for (int r = 0; r < rows; ++r) {
3135 const float *x = hidden + (size_t)r * (size_t)hidden_dim;
3136 const float *route = routed ? (routed + (size_t)r * (size_t)hidden_dim) : NULL;
3137 float *y = output + (size_t)r * (size_t)hidden_dim;
3138 for (int i = 0; i < intermediate_dim; ++i) {
3139 float gv = 0.0f;
3140 float uv = 0.0f;
3141 for (int h = 0; h < hidden_dim; ++h) {
3142 gv += shared_gate[(size_t)i * (size_t)hidden_dim + (size_t)h] * x[h];
3143 uv += shared_up[(size_t)i * (size_t)hidden_dim + (size_t)h] * x[h];
3144 }
3145 act[i] = ck_moe_silu_f32(gv) * uv;
3146 }
3147 for (int h = 0; h < hidden_dim; ++h) {
3148 float v = route ? route[h] : 0.0f;
3149 for (int i = 0; i < intermediate_dim; ++i) {
3150 v += shared_down[(size_t)h * (size_t)intermediate_dim + (size_t)i] * act[i];
3151 }
3152 y[h] = v;
3153 }
3154 }
3155}

References ck_moe_silu_f32().

◆ moe_swiglu_shared_forward_q4k_q4k_parallel_workspace()

int moe_swiglu_shared_forward_q4k_q4k_parallel_workspace ( const float *  hidden,
const float *  routed,
const void *  shared_gate,
const void *  shared_up,
const void *  shared_down,
float *  output,
int  rows,
int  hidden_dim,
int  intermediate_dim,
void *  workspace,
size_t  workspace_bytes 
)

Definition at line 2071 of file axpy_kernels.c.

2083{
2085 hidden, routed, shared_gate, shared_up, shared_down, output, rows,
2086 hidden_dim, intermediate_dim, workspace, workspace_bytes,
2088}
static int ck_moe_shared_q4k_parallel_workspace(const float *hidden, const float *routed, const void *shared_gate, const void *shared_up, const void *shared_down, float *output, int rows, int hidden_dim, int intermediate_dim, void *workspace, size_t workspace_bytes, ck_moe_shared_workspace_fn serial_fn)
int moe_swiglu_shared_forward_q4k_q4k_workspace(const float *hidden, const float *routed, const void *shared_gate, const void *shared_up, const void *shared_down, float *output, int rows, int hidden_dim, int intermediate_dim, void *workspace, size_t workspace_bytes)

References ck_moe_shared_q4k_parallel_workspace(), and moe_swiglu_shared_forward_q4k_q4k_workspace().

◆ moe_swiglu_shared_forward_q4k_q4k_workspace()

int moe_swiglu_shared_forward_q4k_q4k_workspace ( const float *  hidden,
const float *  routed,
const void *  shared_gate,
const void *  shared_up,
const void *  shared_down,
float *  output,
int  rows,
int  hidden_dim,
int  intermediate_dim,
void *  workspace,
size_t  workspace_bytes 
)

Definition at line 1242 of file axpy_kernels.c.

1254{
1255 const size_t required = moe_swiglu_expert_q4k_q5k_workspace_bytes(
1256 hidden_dim, intermediate_dim);
1257 if (!hidden || !shared_gate || !shared_up || !shared_down || !output ||
1258 !workspace || required == 0 || workspace_bytes < required || rows <= 0) {
1259 return -1;
1260 }
1261
1262 const size_t hidden_q8_bytes = ck_moe_align64(
1263 ck_dtype_row_bytes(CK_DT_Q8_K, (size_t)hidden_dim));
1264 const size_t gate_up_bytes = ck_moe_align64(
1265 2u * (size_t)intermediate_dim * sizeof(float));
1266 const size_t act_q8_bytes = ck_moe_align64(
1267 ck_dtype_row_bytes(CK_DT_Q8_K, (size_t)intermediate_dim));
1268 uint8_t *cursor = (uint8_t *)workspace;
1269 void *hidden_q8 = cursor;
1270 cursor += hidden_q8_bytes;
1271 float *gate_up = (float *)cursor;
1272 cursor += gate_up_bytes;
1273 void *act_q8 = cursor;
1274 cursor += act_q8_bytes;
1275 float *shared_output = (float *)cursor;
1276
1277 for (int row = 0; row < rows; ++row) {
1278 const float *x = hidden + (size_t)row * (size_t)hidden_dim;
1279 float *y = output + (size_t)row * (size_t)hidden_dim;
1280 quantize_row_q8_k(x, hidden_q8, hidden_dim);
1281 gemv_q4_k_q8_k(gate_up, shared_gate, hidden_q8,
1282 intermediate_dim, hidden_dim);
1283 gemv_q4_k_q8_k(gate_up + intermediate_dim, shared_up, hidden_q8,
1284 intermediate_dim, hidden_dim);
1285 swiglu_forward_ggml(gate_up, gate_up, 1, intermediate_dim);
1286 quantize_row_q8_k(gate_up, act_q8, intermediate_dim);
1287 gemv_q4_k_q8_k(shared_output, shared_down, act_q8,
1288 hidden_dim, intermediate_dim);
1289 const float *route = routed
1290 ? routed + (size_t)row * (size_t)hidden_dim
1291 : NULL;
1292 for (int col = 0; col < hidden_dim; ++col) {
1293 y[col] = shared_output[col] + (route ? route[col] : 0.0f);
1294 }
1295 }
1296 return 0;
1297}

References CK_DT_Q8_K, ck_dtype_row_bytes(), ck_moe_align64(), gemv_q4_k_q8_k(), moe_swiglu_expert_q4k_q5k_workspace_bytes(), quantize_row_q8_k(), and swiglu_forward_ggml().

Referenced by moe_swiglu_shared_forward_q4k_q4k_parallel_workspace().

◆ moe_swiglu_shared_forward_q4k_q5_0_gated_parallel_workspace()

int moe_swiglu_shared_forward_q4k_q5_0_gated_parallel_workspace ( const float *  hidden,
const float *  routed,
const void *  shared_gate,
const void *  shared_up,
const void *  shared_down,
const float *  shared_gate_input,
float *  output,
int  rows,
int  hidden_dim,
int  intermediate_dim,
void *  workspace,
size_t  workspace_bytes 
)

Definition at line 2999 of file axpy_kernels.c.

3012{
3013 /* See the Q8_0-down variant above: inner projection dispatch owns the
3014 * pool so nested row dispatch would deadlock. */
3016 hidden, routed, shared_gate, shared_up, shared_down, shared_gate_input,
3017 output, rows, hidden_dim, intermediate_dim, workspace, workspace_bytes);
3018}
int moe_swiglu_shared_forward_q4k_q5_0_gated_workspace(const float *hidden, const float *routed, const void *shared_gate, const void *shared_up, const void *shared_down, const float *shared_gate_input, float *output, int rows, int hidden_dim, int intermediate_dim, void *workspace, size_t workspace_bytes)

References moe_swiglu_shared_forward_q4k_q5_0_gated_workspace().

◆ moe_swiglu_shared_forward_q4k_q5_0_gated_workspace()

int moe_swiglu_shared_forward_q4k_q5_0_gated_workspace ( const float *  hidden,
const float *  routed,
const void *  shared_gate,
const void *  shared_up,
const void *  shared_down,
const float *  shared_gate_input,
float *  output,
int  rows,
int  hidden_dim,
int  intermediate_dim,
void *  workspace,
size_t  workspace_bytes 
)

Definition at line 2828 of file axpy_kernels.c.

2841{
2843 hidden, routed, shared_gate, shared_up, shared_down, shared_gate_input,
2844 output, rows, hidden_dim, intermediate_dim, workspace, workspace_bytes,
2846}
static int ck_moe_shared_q4k_gated_workspace(const float *hidden, const float *routed, const void *shared_gate, const void *shared_up, const void *shared_down, const float *shared_gate_input, float *output, int rows, int hidden_dim, int intermediate_dim, void *workspace, size_t workspace_bytes, void(*down_projection)(float *, const void *, const void *, int, int))

References ck_moe_shared_q4k_gated_workspace(), and gemv_q5_0_q8_0().

Referenced by moe_swiglu_shared_forward_q4k_q5_0_gated_parallel_workspace().

◆ moe_swiglu_shared_forward_q4k_q6k_parallel_workspace()

int moe_swiglu_shared_forward_q4k_q6k_parallel_workspace ( const float *  hidden,
const float *  routed,
const void *  shared_gate,
const void *  shared_up,
const void *  shared_down,
float *  output,
int  rows,
int  hidden_dim,
int  intermediate_dim,
void *  workspace,
size_t  workspace_bytes 
)

Definition at line 2052 of file axpy_kernels.c.

2064{
2066 hidden, routed, shared_gate, shared_up, shared_down, output, rows,
2067 hidden_dim, intermediate_dim, workspace, workspace_bytes,
2069}
int moe_swiglu_shared_forward_q4k_q6k_workspace(const float *hidden, const float *routed, const void *shared_gate, const void *shared_up, const void *shared_down, float *output, int rows, int hidden_dim, int intermediate_dim, void *workspace, size_t workspace_bytes)

References ck_moe_shared_q4k_parallel_workspace(), and moe_swiglu_shared_forward_q4k_q6k_workspace().

◆ moe_swiglu_shared_forward_q4k_q6k_workspace()

int moe_swiglu_shared_forward_q4k_q6k_workspace ( const float *  hidden,
const float *  routed,
const void *  shared_gate,
const void *  shared_up,
const void *  shared_down,
float *  output,
int  rows,
int  hidden_dim,
int  intermediate_dim,
void *  workspace,
size_t  workspace_bytes 
)

Definition at line 1185 of file axpy_kernels.c.

1197{
1198 const size_t required = moe_swiglu_expert_q4k_q5k_workspace_bytes(
1199 hidden_dim, intermediate_dim);
1200 if (!hidden || !shared_gate || !shared_up || !shared_down || !output ||
1201 !workspace || required == 0 || workspace_bytes < required || rows <= 0) {
1202 return -1;
1203 }
1204
1205 const size_t hidden_q8_bytes = ck_moe_align64(
1206 ck_dtype_row_bytes(CK_DT_Q8_K, (size_t)hidden_dim));
1207 const size_t gate_up_bytes = ck_moe_align64(
1208 2u * (size_t)intermediate_dim * sizeof(float));
1209 const size_t act_q8_bytes = ck_moe_align64(
1210 ck_dtype_row_bytes(CK_DT_Q8_K, (size_t)intermediate_dim));
1211 uint8_t *cursor = (uint8_t *)workspace;
1212 void *hidden_q8 = cursor;
1213 cursor += hidden_q8_bytes;
1214 float *gate_up = (float *)cursor;
1215 cursor += gate_up_bytes;
1216 void *act_q8 = cursor;
1217 cursor += act_q8_bytes;
1218 float *shared_output = (float *)cursor;
1219
1220 for (int row = 0; row < rows; ++row) {
1221 const float *x = hidden + (size_t)row * (size_t)hidden_dim;
1222 float *y = output + (size_t)row * (size_t)hidden_dim;
1223 quantize_row_q8_k(x, hidden_q8, hidden_dim);
1224 gemv_q4_k_q8_k(gate_up, shared_gate, hidden_q8,
1225 intermediate_dim, hidden_dim);
1226 gemv_q4_k_q8_k(gate_up + intermediate_dim, shared_up, hidden_q8,
1227 intermediate_dim, hidden_dim);
1228 swiglu_forward_ggml(gate_up, gate_up, 1, intermediate_dim);
1229 quantize_row_q8_k(gate_up, act_q8, intermediate_dim);
1230 gemv_q6_k_q8_k(shared_output, shared_down, act_q8,
1231 hidden_dim, intermediate_dim);
1232 const float *route = routed
1233 ? routed + (size_t)row * (size_t)hidden_dim
1234 : NULL;
1235 for (int col = 0; col < hidden_dim; ++col) {
1236 y[col] = shared_output[col] + (route ? route[col] : 0.0f);
1237 }
1238 }
1239 return 0;
1240}

References CK_DT_Q8_K, ck_dtype_row_bytes(), ck_moe_align64(), gemv_q4_k_q8_k(), gemv_q6_k_q8_k(), moe_swiglu_expert_q4k_q5k_workspace_bytes(), quantize_row_q8_k(), and swiglu_forward_ggml().

Referenced by moe_swiglu_shared_forward_q4k_q6k_parallel_workspace().

◆ moe_swiglu_shared_forward_q4k_q8_0_gated_parallel_workspace()

int moe_swiglu_shared_forward_q4k_q8_0_gated_parallel_workspace ( const float *  hidden,
const float *  routed,
const void *  shared_gate,
const void *  shared_up,
const void *  shared_down,
const float *  shared_gate_input,
float *  output,
int  rows,
int  hidden_dim,
int  intermediate_dim,
void *  workspace,
size_t  workspace_bytes 
)

Definition at line 2978 of file axpy_kernels.c.

2991{
2992 /* Gate/up use the output-parallel pairwise Q4_K provider. Do not wrap
2993 * that provider in a second dispatch on the same persistent pool. */
2995 hidden, routed, shared_gate, shared_up, shared_down, shared_gate_input,
2996 output, rows, hidden_dim, intermediate_dim, workspace, workspace_bytes);
2997}
int moe_swiglu_shared_forward_q4k_q8_0_gated_workspace(const float *hidden, const float *routed, const void *shared_gate, const void *shared_up, const void *shared_down, const float *shared_gate_input, float *output, int rows, int hidden_dim, int intermediate_dim, void *workspace, size_t workspace_bytes)

References moe_swiglu_shared_forward_q4k_q8_0_gated_workspace().

◆ moe_swiglu_shared_forward_q4k_q8_0_gated_workspace()

int moe_swiglu_shared_forward_q4k_q8_0_gated_workspace ( const float *  hidden,
const float *  routed,
const void *  shared_gate,
const void *  shared_up,
const void *  shared_down,
const float *  shared_gate_input,
float *  output,
int  rows,
int  hidden_dim,
int  intermediate_dim,
void *  workspace,
size_t  workspace_bytes 
)

Definition at line 2815 of file axpy_kernels.c.

2821{
2823 hidden, routed, shared_gate, shared_up, shared_down, shared_gate_input,
2824 output, rows, hidden_dim, intermediate_dim, workspace, workspace_bytes,
2826}

References ck_moe_shared_q4k_gated_workspace(), and gemv_q8_0_q8_0().

Referenced by moe_swiglu_shared_forward_q4k_q8_0_gated_parallel_workspace().

◆ moe_swiglu_shared_forward_q8_0_gated_parallel_workspace()

int moe_swiglu_shared_forward_q8_0_gated_parallel_workspace ( const float *  hidden,
const float *  routed,
const void *  shared_gate,
const void *  shared_up,
const void *  shared_down,
const float *  shared_gate_input,
float *  output,
int  rows,
int  hidden_dim,
int  intermediate_dim,
void *  workspace,
size_t  workspace_bytes 
)

Definition at line 2957 of file axpy_kernels.c.

2970{
2972 hidden, routed, shared_gate, shared_up, shared_down, shared_gate_input,
2973 output, rows, hidden_dim, intermediate_dim, workspace, workspace_bytes,
2974 moe_swiglu_shared_q8_0_gated_workspace_bytes(hidden_dim, intermediate_dim),
2976}
int moe_swiglu_shared_forward_q8_0_gated_workspace(const float *hidden, const float *routed, const void *shared_gate, const void *shared_up, const void *shared_down, const float *shared_gate_input, float *output, int rows, int hidden_dim, int intermediate_dim, void *workspace, size_t workspace_bytes)
static int ck_moe_shared_gated_parallel_workspace(const float *hidden, const float *routed, const void *shared_gate, const void *shared_up, const void *shared_down, const float *shared_gate_input, float *output, int rows, int hidden_dim, int intermediate_dim, void *workspace, size_t workspace_bytes, size_t stride, ck_moe_shared_gated_workspace_fn serial_fn)
size_t moe_swiglu_shared_q8_0_gated_workspace_bytes(int hidden_dim, int intermediate_dim)

References ck_moe_shared_gated_parallel_workspace(), moe_swiglu_shared_forward_q8_0_gated_workspace(), and moe_swiglu_shared_q8_0_gated_workspace_bytes().

◆ moe_swiglu_shared_forward_q8_0_gated_workspace()

int moe_swiglu_shared_forward_q8_0_gated_workspace ( const float *  hidden,
const float *  routed,
const void *  shared_gate,
const void *  shared_up,
const void *  shared_down,
const float *  shared_gate_input,
float *  output,
int  rows,
int  hidden_dim,
int  intermediate_dim,
void *  workspace,
size_t  workspace_bytes 
)

Definition at line 2642 of file axpy_kernels.c.

2655{
2656 const size_t required = moe_swiglu_shared_q8_0_gated_workspace_bytes(
2657 hidden_dim, intermediate_dim);
2658 if (!hidden || !shared_gate || !shared_up || !shared_down ||
2659 !shared_gate_input || !output || !workspace || required == 0 ||
2660 workspace_bytes < required || rows <= 0) {
2661 return -1;
2662 }
2663
2664 const size_t hidden_q8_bytes = ck_moe_align64(
2665 ck_dtype_row_bytes(CK_DT_Q8_0, (size_t)hidden_dim));
2666 const size_t gate_up_bytes = ck_moe_align64(
2667 2u * (size_t)intermediate_dim * sizeof(float));
2668 const size_t activation_q8_bytes = ck_moe_align64(
2669 ck_dtype_row_bytes(CK_DT_Q8_0, (size_t)intermediate_dim));
2670 uint8_t *cursor = (uint8_t *)workspace;
2671 void *hidden_q8 = cursor;
2672 cursor += hidden_q8_bytes;
2673 float *gate_up = (float *)cursor;
2674 cursor += gate_up_bytes;
2675 void *activation_q8 = cursor;
2676 cursor += activation_q8_bytes;
2677 float *shared_output = (float *)cursor;
2678
2679 for (int row = 0; row < rows; ++row) {
2680 const float *x = hidden + (size_t)row * (size_t)hidden_dim;
2681 const float *routed_row = routed
2682 ? routed + (size_t)row * (size_t)hidden_dim
2683 : NULL;
2684 float *output_row = output + (size_t)row * (size_t)hidden_dim;
2685
2686 quantize_row_q8_0(x, hidden_q8, hidden_dim);
2687 gemv_q8_0_q8_0(gate_up, shared_gate, hidden_q8,
2688 intermediate_dim, hidden_dim);
2689 gemv_q8_0_q8_0(gate_up + intermediate_dim, shared_up, hidden_q8,
2690 intermediate_dim, hidden_dim);
2691 swiglu_forward_ggml(gate_up, gate_up, 1, intermediate_dim);
2692 quantize_row_q8_0(gate_up, activation_q8, intermediate_dim);
2693 gemv_q8_0_q8_0(shared_output, shared_down, activation_q8,
2694 hidden_dim, intermediate_dim);
2695
2696 float gate_value = 0.0f;
2698 x, shared_gate_input, NULL, &gate_value, 1, 1, hidden_dim);
2699 const float gate_scale = 1.0f / (1.0f + expf(-gate_value));
2700 for (int h = 0; h < hidden_dim; ++h) {
2701 const float routed_value = routed_row ? routed_row[h] : 0.0f;
2702 volatile float gated_shared = shared_output[h] * gate_scale;
2703 output_row[h] = routed_value + gated_shared;
2704 }
2705 }
2706 return 0;
2707}
void gemm_nt_f32_llama_production(const float *A, const float *B, const float *bias, float *C, int M, int N, int K)

References CK_DT_Q8_0, ck_dtype_row_bytes(), ck_moe_align64(), gemm_nt_f32_llama_production(), gemv_q8_0_q8_0(), moe_swiglu_shared_q8_0_gated_workspace_bytes(), quantize_row_q8_0(), and swiglu_forward_ggml().

Referenced by moe_swiglu_shared_forward_q8_0_gated_parallel_workspace().

◆ moe_swiglu_shared_q4k_q8_0_gated_workspace_bytes()

size_t moe_swiglu_shared_q4k_q8_0_gated_workspace_bytes ( int  hidden_dim,
int  intermediate_dim 
)

Definition at line 761 of file axpy_kernels.c.

763{
764 enum { batch_rows = 4 };
765 if (hidden_dim <= 0 || intermediate_dim <= 0 ||
766 hidden_dim % 256 != 0 || intermediate_dim % QK8_0 != 0) {
767 return 0;
768 }
769
770 size_t bytes = ck_moe_align64(
771 batch_rows * ck_dtype_row_bytes(CK_DT_Q8_K, (size_t)hidden_dim));
772 bytes += 2u * ck_moe_align64(
773 batch_rows * (size_t)intermediate_dim * sizeof(float));
774 bytes += ck_moe_align64(
775 batch_rows * ck_dtype_row_bytes(CK_DT_Q8_0, (size_t)intermediate_dim));
776 bytes += ck_moe_align64(
777 batch_rows * (size_t)hidden_dim * sizeof(float));
778 return bytes;
779}

References CK_DT_Q8_0, CK_DT_Q8_K, ck_dtype_row_bytes(), ck_moe_align64(), and QK8_0.

Referenced by ck_moe_shared_q4k_gated_workspace().

◆ moe_swiglu_shared_q8_0_gated_workspace_bytes()

size_t moe_swiglu_shared_q8_0_gated_workspace_bytes ( int  hidden_dim,
int  intermediate_dim 
)

Definition at line 2625 of file axpy_kernels.c.

2627{
2628 if (hidden_dim <= 0 || intermediate_dim <= 0 ||
2629 hidden_dim % 32 != 0 || intermediate_dim % 32 != 0) {
2630 return 0;
2631 }
2632
2633 size_t bytes = ck_moe_align64(
2634 ck_dtype_row_bytes(CK_DT_Q8_0, (size_t)hidden_dim));
2635 bytes += ck_moe_align64(2u * (size_t)intermediate_dim * sizeof(float));
2636 bytes += ck_moe_align64(
2637 ck_dtype_row_bytes(CK_DT_Q8_0, (size_t)intermediate_dim));
2638 bytes += ck_moe_align64((size_t)hidden_dim * sizeof(float));
2639 return bytes;
2640}

References CK_DT_Q8_0, ck_dtype_row_bytes(), and ck_moe_align64().

Referenced by moe_swiglu_shared_forward_q8_0_gated_parallel_workspace(), and moe_swiglu_shared_forward_q8_0_gated_workspace().

◆ mrope_qk_imrope_positions()

void mrope_qk_imrope_positions ( float *  q,
float *  k,
const int32_t *  positions,
int  num_heads,
int  num_kv_heads,
int  num_tokens,
int  head_dim,
int  aligned_head_dim,
int  n_dims,
int  section_0,
int  section_1,
int  section_2,
int  section_3,
int  n_ctx_orig,
float  freq_base,
float  freq_scale,
float  ext_factor,
float  attn_factor,
float  beta_fast,
float  beta_slow 
)

Definition at line 2686 of file rope_kernels.c.

2706{
2707 if (!q || !k || !positions || num_heads <= 0 || num_kv_heads <= 0 || num_tokens <= 0) {
2708 return;
2709 }
2710
2711 const int sections[4] = {section_0, section_1, section_2, section_3};
2712
2714 const int q_ok = explicit_mrope_apply_ggml_exact(
2715 q, positions, num_heads, num_tokens, head_dim, aligned_head_dim, n_dims, sections,
2716 n_ctx_orig, freq_base, freq_scale, ext_factor, attn_factor, beta_fast, beta_slow, GGML_ROPE_TYPE_IMROPE);
2717 const int k_ok = explicit_mrope_apply_ggml_exact(
2718 k, positions, num_kv_heads, num_tokens, head_dim, aligned_head_dim, n_dims, sections,
2719 n_ctx_orig, freq_base, freq_scale, ext_factor, attn_factor, beta_fast, beta_slow, GGML_ROPE_TYPE_IMROPE);
2720 if (q_ok && k_ok) {
2721 return;
2722 }
2723 }
2724
2725 const size_t q_head_stride = (size_t) num_tokens * (size_t) aligned_head_dim;
2726 const size_t k_head_stride = (size_t) num_tokens * (size_t) aligned_head_dim;
2727
2728 for (int h = 0; h < num_heads; ++h) {
2730 q + (size_t) h * q_head_stride,
2731 positions,
2732 num_tokens,
2733 head_dim,
2734 aligned_head_dim,
2735 n_dims,
2736 sections,
2737 n_ctx_orig,
2738 freq_base,
2739 freq_scale,
2740 ext_factor,
2741 attn_factor,
2742 beta_fast,
2743 beta_slow,
2744 1
2745 );
2746 }
2747
2748 for (int h = 0; h < num_kv_heads; ++h) {
2750 k + (size_t) h * k_head_stride,
2751 positions,
2752 num_tokens,
2753 head_dim,
2754 aligned_head_dim,
2755 n_dims,
2756 sections,
2757 n_ctx_orig,
2758 freq_base,
2759 freq_scale,
2760 ext_factor,
2761 attn_factor,
2762 beta_fast,
2763 beta_slow,
2764 1
2765 );
2766 }
2767}
#define GGML_ROPE_TYPE_IMROPE
static int explicit_mrope_apply_ggml_exact(float *x, const int32_t *positions, int num_heads, int num_tokens, int head_dim, int aligned_head_dim, int n_dims, const int sections[4], int n_ctx_orig, float freq_base, float freq_scale, float ext_factor, float attn_factor, float beta_fast, float beta_slow, int rope_type)
static void explicit_mrope_apply_head(float *x, const int32_t *positions, int num_tokens, int head_dim, int aligned_head_dim, int n_dims, const int sections[4], int n_ctx_orig, float freq_base, float freq_scale, float ext_factor, float attn_factor, float beta_fast, float beta_slow, int is_imrope)

References ck_strict_parity_enabled(), explicit_mrope_apply_ggml_exact(), explicit_mrope_apply_head(), and GGML_ROPE_TYPE_IMROPE.

◆ mrope_qk_text()

void mrope_qk_text ( float *  q,
float *  k,
int  num_heads,
int  num_kv_heads,
int  num_tokens,
int  head_dim,
int  aligned_head_dim,
int  pos_offset,
int  n_dims,
int  section_0,
int  section_1,
int  section_2,
int  section_3,
int  n_ctx_orig,
float  freq_base,
float  freq_scale,
float  ext_factor,
float  attn_factor,
float  beta_fast,
float  beta_slow 
)

Definition at line 2203 of file rope_kernels.c.

2223{
2224 if (!q || !k || num_heads <= 0 || num_kv_heads <= 0 || num_tokens <= 0) {
2225 return;
2226 }
2227
2228 const int sections[4] = {section_0, section_1, section_2, section_3};
2229 const size_t q_head_stride = (size_t) num_tokens * (size_t) aligned_head_dim;
2230 const size_t k_head_stride = (size_t) num_tokens * (size_t) aligned_head_dim;
2231
2232 for (int h = 0; h < num_heads; ++h) {
2234 q + (size_t) h * q_head_stride,
2235 num_tokens,
2236 head_dim,
2237 aligned_head_dim,
2238 pos_offset,
2239 n_dims,
2240 sections,
2241 n_ctx_orig,
2242 freq_base,
2243 freq_scale,
2244 ext_factor,
2245 attn_factor,
2246 beta_fast,
2247 beta_slow,
2248 0
2249 );
2250 }
2251
2252 for (int h = 0; h < num_kv_heads; ++h) {
2254 k + (size_t) h * k_head_stride,
2255 num_tokens,
2256 head_dim,
2257 aligned_head_dim,
2258 pos_offset,
2259 n_dims,
2260 sections,
2261 n_ctx_orig,
2262 freq_base,
2263 freq_scale,
2264 ext_factor,
2265 attn_factor,
2266 beta_fast,
2267 beta_slow,
2268 0
2269 );
2270 }
2271}
static void text_mrope_apply_head(float *x, int num_tokens, int head_dim, int aligned_head_dim, int pos_offset, int n_dims, const int sections[4], int n_ctx_orig, float freq_base, float freq_scale, float ext_factor, float attn_factor, float beta_fast, float beta_slow, int is_imrope)

References text_mrope_apply_head().

◆ mrope_qk_text_imrope()

void mrope_qk_text_imrope ( float *  q,
float *  k,
int  num_heads,
int  num_kv_heads,
int  num_tokens,
int  head_dim,
int  aligned_head_dim,
int  pos_offset,
int  n_dims,
int  section_0,
int  section_1,
int  section_2,
int  section_3,
int  n_ctx_orig,
float  freq_base,
float  freq_scale,
float  ext_factor,
float  attn_factor,
float  beta_fast,
float  beta_slow 
)

Definition at line 2273 of file rope_kernels.c.

2293{
2294 if (!q || !k || num_heads <= 0 || num_kv_heads <= 0 || num_tokens <= 0) {
2295 return;
2296 }
2297
2298 const int sections[4] = {section_0, section_1, section_2, section_3};
2299 const size_t q_head_stride = (size_t) num_tokens * (size_t) aligned_head_dim;
2300 const size_t k_head_stride = (size_t) num_tokens * (size_t) aligned_head_dim;
2301
2302 for (int h = 0; h < num_heads; ++h) {
2304 q + (size_t) h * q_head_stride,
2305 num_tokens,
2306 head_dim,
2307 aligned_head_dim,
2308 pos_offset,
2309 n_dims,
2310 sections,
2311 n_ctx_orig,
2312 freq_base,
2313 freq_scale,
2314 ext_factor,
2315 attn_factor,
2316 beta_fast,
2317 beta_slow,
2318 1
2319 );
2320 }
2321
2322 for (int h = 0; h < num_kv_heads; ++h) {
2324 k + (size_t) h * k_head_stride,
2325 num_tokens,
2326 head_dim,
2327 aligned_head_dim,
2328 pos_offset,
2329 n_dims,
2330 sections,
2331 n_ctx_orig,
2332 freq_base,
2333 freq_scale,
2334 ext_factor,
2335 attn_factor,
2336 beta_fast,
2337 beta_slow,
2338 1
2339 );
2340 }
2341}

References text_mrope_apply_head().

◆ mrope_qk_text_imrope_bf16_pytorch_storage()

void mrope_qk_text_imrope_bf16_pytorch_storage ( float *  q,
float *  k,
int  num_heads,
int  num_kv_heads,
int  num_tokens,
int  head_dim,
int  aligned_head_dim,
int  pos_offset,
int  n_dims,
int  section_0,
int  section_1,
int  section_2,
int  section_3,
int  n_ctx_orig,
float  freq_base,
float  freq_scale,
float  ext_factor,
float  attn_factor,
float  beta_fast,
float  beta_slow 
)

Definition at line 2496 of file rope_kernels.c.

2516{
2517 (void)section_0;
2518 (void)section_1;
2519 (void)section_2;
2520 (void)section_3;
2521 (void)n_ctx_orig;
2522 (void)ext_factor;
2523 (void)attn_factor;
2524 (void)beta_fast;
2525 (void)beta_slow;
2526 text_mrope_apply_pytorch_bf16_storage(q, num_heads, num_tokens, head_dim,
2527 aligned_head_dim, pos_offset, n_dims,
2528 freq_base, freq_scale);
2529 text_mrope_apply_pytorch_bf16_storage(k, num_kv_heads, num_tokens, head_dim,
2530 aligned_head_dim, pos_offset, n_dims,
2531 freq_base, freq_scale);
2532}
static void text_mrope_apply_pytorch_bf16_storage(float *x, int num_heads, int num_tokens, int head_dim, int aligned_head_dim, int pos_offset, int n_dims, float freq_base, float freq_scale)

References text_mrope_apply_pytorch_bf16_storage().

◆ mrope_qk_text_imrope_positions_bf16_pytorch_storage()

void mrope_qk_text_imrope_positions_bf16_pytorch_storage ( float *  q,
float *  k,
const int32_t *  positions,
int  num_heads,
int  num_kv_heads,
int  num_tokens,
int  head_dim,
int  aligned_head_dim,
int  n_dims,
int  section_0,
int  section_1,
int  section_2,
int  section_3,
int  n_ctx_orig,
float  freq_base,
float  freq_scale,
float  ext_factor,
float  attn_factor,
float  beta_fast,
float  beta_slow 
)

Definition at line 2460 of file rope_kernels.c.

2481{
2482 (void)n_ctx_orig;
2483 (void)ext_factor;
2484 (void)attn_factor;
2485 (void)beta_fast;
2486 (void)beta_slow;
2487 const int sections[4] = {section_0, section_1, section_2, section_3};
2489 q, positions, num_heads, num_tokens, head_dim, aligned_head_dim, n_dims,
2490 sections, freq_base, freq_scale);
2492 k, positions, num_kv_heads, num_tokens, head_dim, aligned_head_dim, n_dims,
2493 sections, freq_base, freq_scale);
2494}
static void text_mrope_apply_positions_pytorch_bf16_storage(float *x, const int32_t *positions, int num_heads, int num_tokens, int head_dim, int aligned_head_dim, int n_dims, const int sections[4], float freq_base, float freq_scale)

References text_mrope_apply_positions_pytorch_bf16_storage().

◆ mrope_qk_vision()

void mrope_qk_vision ( float *  q,
float *  k,
const int32_t *  positions,
int  num_heads,
int  num_kv_heads,
int  num_tokens,
int  head_dim,
int  aligned_head_dim,
int  n_dims,
int  section_0,
int  section_1,
int  section_2,
int  section_3,
int  n_ctx_orig,
float  freq_base,
float  freq_scale,
float  ext_factor,
float  attn_factor,
float  beta_fast,
float  beta_slow 
)

Definition at line 2534 of file rope_kernels.c.

2554{
2555 if (!q || !k || !positions || num_heads <= 0 || num_kv_heads <= 0 || num_tokens <= 0) {
2556 return;
2557 }
2558
2559 const int sections[4] = {section_0, section_1, section_2, section_3};
2560
2563 q, positions, num_heads, num_tokens, head_dim, aligned_head_dim, n_dims, sections,
2564 n_ctx_orig, freq_base, freq_scale, ext_factor, attn_factor, beta_fast, beta_slow, GGML_ROPE_TYPE_VISION) &&
2566 k, positions, num_kv_heads, num_tokens, head_dim, aligned_head_dim, n_dims, sections,
2567 n_ctx_orig, freq_base, freq_scale, ext_factor, attn_factor, beta_fast, beta_slow, GGML_ROPE_TYPE_VISION)) {
2568 return;
2569 }
2570 }
2571
2572 const size_t q_head_stride = (size_t) num_tokens * (size_t) aligned_head_dim;
2573 const size_t k_head_stride = (size_t) num_tokens * (size_t) aligned_head_dim;
2574
2575 for (int h = 0; h < num_heads; ++h) {
2577 q + (size_t) h * q_head_stride,
2578 positions,
2579 num_tokens,
2580 head_dim,
2581 aligned_head_dim,
2582 n_dims,
2583 sections,
2584 n_ctx_orig,
2585 freq_base,
2586 freq_scale,
2587 ext_factor,
2588 attn_factor,
2589 beta_fast,
2590 beta_slow
2591 );
2592 }
2593
2594 for (int h = 0; h < num_kv_heads; ++h) {
2596 k + (size_t) h * k_head_stride,
2597 positions,
2598 num_tokens,
2599 head_dim,
2600 aligned_head_dim,
2601 n_dims,
2602 sections,
2603 n_ctx_orig,
2604 freq_base,
2605 freq_scale,
2606 ext_factor,
2607 attn_factor,
2608 beta_fast,
2609 beta_slow
2610 );
2611 }
2612}
#define GGML_ROPE_TYPE_VISION
static void vision_mrope_apply_head(float *x, const int32_t *positions, int num_tokens, int head_dim, int aligned_head_dim, int n_dims, const int sections[4], int n_ctx_orig, float freq_base, float freq_scale, float ext_factor, float attn_factor, float beta_fast, float beta_slow)

References ck_strict_parity_enabled(), explicit_mrope_apply_ggml_exact(), GGML_ROPE_TYPE_VISION, and vision_mrope_apply_head().

◆ mrope_qk_vision_bf16_pytorch_storage()

void mrope_qk_vision_bf16_pytorch_storage ( float *  q,
float *  k,
const int32_t *  positions,
int  num_heads,
int  num_kv_heads,
int  num_tokens,
int  head_dim,
int  aligned_head_dim,
int  n_dims,
int  section_0,
int  section_1,
int  section_2,
int  section_3,
int  n_ctx_orig,
float  freq_base,
float  freq_scale,
float  ext_factor,
float  attn_factor,
float  beta_fast,
float  beta_slow 
)

◆ mrope_qk_vision_bf16_storage()

void mrope_qk_vision_bf16_storage ( float *  q,
float *  k,
const int32_t *  positions,
int  num_heads,
int  num_kv_heads,
int  num_tokens,
int  head_dim,
int  aligned_head_dim,
int  n_dims,
int  section_0,
int  section_1,
int  section_2,
int  section_3,
int  n_ctx_orig,
float  freq_base,
float  freq_scale,
float  ext_factor,
float  attn_factor,
float  beta_fast,
float  beta_slow 
)

Definition at line 2645 of file rope_kernels.c.

◆ mrope_qk_vision_fp16_storage()

void mrope_qk_vision_fp16_storage ( float *  q,
float *  k,
const int32_t *  positions,
int  num_heads,
int  num_kv_heads,
int  num_tokens,
int  head_dim,
int  aligned_head_dim,
int  n_dims,
int  section_0,
int  section_1,
int  section_2,
int  section_3,
int  n_ctx_orig,
float  freq_base,
float  freq_scale,
float  ext_factor,
float  attn_factor,
float  beta_fast,
float  beta_slow 
)

Definition at line 2646 of file rope_kernels.c.

◆ nemotron_group_limited_topk_router_f32()

void nemotron_group_limited_topk_router_f32 ( const float *  scores,
const float *  correction_bias,
int *  indices,
float *  weights,
int  rows,
int  n_experts,
int  top_k,
int  n_group,
int  topk_group,
int  norm_topk_prob,
float  routed_scaling_factor 
)

Definition at line 780 of file topk_kernels.c.

791{
793 scores, correction_bias, indices, weights, rows, n_experts, top_k,
794 n_group, topk_group, norm_topk_prob, routed_scaling_factor, 0
795 );
796}

References group_limited_topk_router_f32_impl().

◆ patch2im()

void patch2im ( const float *  d_patches,
float *  d_image,
int  C,
int  H,
int  W,
int  P 
)

patch2im: Accumulates gradients from patches back into the image. (Backward pass)

d_patches: [num_patches, C * P * P] d_image: [C, H, W] (Accumulated)

Definition at line 123 of file vision_kernels.c.

126{
127 int num_patches_h = H / P;
128 int num_patches_w = W / P;
129 int patch_dim = C * P * P;
130
131 // Zero out the image first as we are accumulating gradients
132 memset(d_image, 0, (size_t)C * H * W * sizeof(float));
133
134 for (int ph = 0; ph < num_patches_h; ++ph) {
135 for (int pw = 0; pw < num_patches_w; ++pw) {
136
137 int patch_idx = ph * num_patches_w + pw;
138 const float *src_patch = d_patches + (size_t)patch_idx * patch_dim;
139
140 for (int c = 0; c < C; ++c) {
141 for (int py = 0; py < P; ++py) {
142 int y = ph * P + py;
143 int x = pw * P;
144
145 float *dst_row = d_image + (size_t)c * H * W + (size_t)y * W + x;
146 const float *src_row = src_patch + (size_t)c * P * P + (size_t)py * P;
147
148 // Add the patch gradient to the image gradient
149 for (int px = 0; px < P; ++px) {
150 dst_row[px] += src_row[px];
151 }
152 }
153 }
154 }
155 }
156}

References C.

◆ patch2im_bf16()

void patch2im_bf16 ( const uint16_t *  d_patches,
uint16_t *  d_image,
int  C,
int  H,
int  W,
int  P 
)

Definition at line 57 of file vision_kernels_bf16.c.

63{
64 if (!d_patches || !d_image || C <= 0 || H <= 0 || W <= 0 || P <= 0) {
65 return;
66 }
67
68 int num_patches_h = H / P;
69 int num_patches_w = W / P;
70 int patch_dim = C * P * P;
71
72 memset(d_image, 0, (size_t)C * (size_t)H * (size_t)W * sizeof(uint16_t));
73
74 for (int ph = 0; ph < num_patches_h; ++ph) {
75 for (int pw = 0; pw < num_patches_w; ++pw) {
76 int patch_idx = ph * num_patches_w + pw;
77 const uint16_t *src_patch = d_patches + (size_t)patch_idx * (size_t)patch_dim;
78
79 for (int c = 0; c < C; ++c) {
80 for (int py = 0; py < P; ++py) {
81 int y = ph * P + py;
82 int x = pw * P;
83
84 uint16_t *dst_row = d_image + (size_t)c * (size_t)H * (size_t)W + (size_t)y * (size_t)W + (size_t)x;
85 const uint16_t *src_row = src_patch + (size_t)c * (size_t)P * (size_t)P + (size_t)py * (size_t)P;
86
87 for (int px = 0; px < P; ++px) {
88 float acc = bf16_to_float(dst_row[px]) + bf16_to_float(src_row[px]);
89 dst_row[px] = float_to_bf16(acc);
90 }
91 }
92 }
93 }
94 }
95}

References bf16_to_float(), C, and float_to_bf16().

◆ patch_projection_bf16_pytorch_onednn_conv3d_storage()

void patch_projection_bf16_pytorch_onednn_conv3d_storage ( const float *  input,
const void *  weights,
const float *  bias,
float *  output,
int  batch,
int  out_channels,
int  in_channels,
int  temporal,
int  patch_h,
int  patch_w 
)

Definition at line 1564 of file gemm_kernels_bf16.c.

1568{
1569#ifdef USE_ONEDNN
1570 if (!input || !weights || !bias || !output || batch <= 0 ||
1571 out_channels <= 0 || in_channels <= 0 || temporal <= 0 ||
1572 patch_h <= 0 || patch_w <= 0) {
1573 ck_pytorch_brgemm_fault("invalid Conv3D patch contract", batch,
1574 out_channels, in_channels * temporal * patch_h * patch_w);
1575 }
1576 pthread_once(&ck_pytorch_brgemm_once, ck_pytorch_brgemm_init);
1577 if (ck_pytorch_brgemm_init_status != 0) {
1578 ck_pytorch_brgemm_fault("could not initialize oneDNN Conv3D", batch,
1579 out_channels, in_channels * temporal * patch_h * patch_w);
1580 }
1581 ck_pytorch_brgemm_require_version(
1582 3, 7, 1, "8d263e693366ef8db40acc569cc7d8edf644556d",
1583 "patch_projection_bf16_pytorch_onednn_conv3d_storage",
1584 batch, out_channels, in_channels * temporal * patch_h * patch_w);
1585
1586 const size_t input_count = (size_t)batch * (size_t)in_channels *
1587 (size_t)temporal * (size_t)patch_h * (size_t)patch_w;
1588 const size_t output_count = (size_t)batch * (size_t)out_channels;
1589 uint16_t *input_bf16 = (uint16_t *)malloc(input_count * sizeof(*input_bf16));
1590 uint16_t *bias_bf16 = (uint16_t *)malloc((size_t)out_channels * sizeof(*bias_bf16));
1591 uint16_t *output_bf16 = (uint16_t *)malloc(output_count * sizeof(*output_bf16));
1592 if (!input_bf16 || !bias_bf16 || !output_bf16) {
1593 free(output_bf16);
1594 free(bias_bf16);
1595 free(input_bf16);
1596 ck_pytorch_brgemm_fault("Conv3D workspace allocation failed", batch,
1597 out_channels, in_channels * temporal * patch_h * patch_w);
1598 }
1599 for (size_t i = 0; i < input_count; ++i) input_bf16[i] = float_to_bf16(input[i]);
1600 for (int i = 0; i < out_channels; ++i) bias_bf16[i] = float_to_bf16(bias[i]);
1601
1602 dnnl_dims_t src_dims = {batch, in_channels, temporal, patch_h, patch_w};
1603 dnnl_dims_t weight_dims = {
1604 out_channels, in_channels, temporal, patch_h, patch_w};
1605 dnnl_dims_t bias_dims = {out_channels};
1606 dnnl_dims_t dst_dims = {batch, out_channels, 1, 1, 1};
1607 dnnl_dims_t strides = {temporal, patch_h, patch_w};
1608 dnnl_dims_t dilates = {0, 0, 0};
1609 dnnl_dims_t padding = {0, 0, 0};
1610
1611 dnnl_memory_desc_t user_src_md = NULL, user_weight_md = NULL;
1612 dnnl_memory_desc_t bias_md = NULL, user_dst_md = NULL;
1613 dnnl_memory_desc_t any_src_md = NULL, any_weight_md = NULL, any_dst_md = NULL;
1614 dnnl_primitive_desc_t conv_pd = NULL;
1615 dnnl_primitive_t conv = NULL;
1616 dnnl_primitive_desc_t reorder_pd = NULL;
1617 dnnl_primitive_t reorder = NULL;
1618 dnnl_exec_arg_t reorder_args[2];
1619 dnnl_memory_t user_src = NULL, user_weight = NULL, bias_mem = NULL, user_dst = NULL;
1620 dnnl_memory_t conv_src = NULL, conv_weight = NULL, conv_dst = NULL;
1621 dnnl_status_t status = dnnl_success;
1622
1623#define CK_DNNL_CONV(call) do { status = (call); if (status != dnnl_success) goto cleanup_conv; } while (0)
1624 pthread_mutex_lock(&ck_pytorch_brgemm_lock);
1625 CK_DNNL_CONV(dnnl_memory_desc_create_with_tag(
1626 &user_src_md, 5, src_dims, dnnl_bf16, dnnl_ncdhw));
1627 CK_DNNL_CONV(dnnl_memory_desc_create_with_tag(
1628 &user_weight_md, 5, weight_dims, dnnl_bf16, dnnl_oidhw));
1629 CK_DNNL_CONV(dnnl_memory_desc_create_with_tag(
1630 &bias_md, 1, bias_dims, dnnl_bf16, dnnl_x));
1631 CK_DNNL_CONV(dnnl_memory_desc_create_with_tag(
1632 &user_dst_md, 5, dst_dims, dnnl_bf16, dnnl_ncdhw));
1633 CK_DNNL_CONV(dnnl_memory_desc_create_with_tag(
1634 &any_src_md, 5, src_dims, dnnl_bf16, dnnl_format_tag_any));
1635 CK_DNNL_CONV(dnnl_memory_desc_create_with_tag(
1636 &any_weight_md, 5, weight_dims, dnnl_bf16, dnnl_format_tag_any));
1637 CK_DNNL_CONV(dnnl_memory_desc_create_with_tag(
1638 &any_dst_md, 5, dst_dims, dnnl_bf16, dnnl_format_tag_any));
1639 CK_DNNL_CONV(dnnl_convolution_forward_primitive_desc_create(
1640 &conv_pd, ck_pytorch_brgemm_engine, dnnl_forward_training,
1641 dnnl_convolution_direct, any_src_md, any_weight_md, bias_md, any_dst_md,
1642 strides, dilates, padding, padding, NULL));
1643
1644 const_dnnl_memory_desc_t conv_src_md =
1645 dnnl_primitive_desc_query_md(conv_pd, dnnl_query_src_md, 0);
1646 const_dnnl_memory_desc_t conv_weight_md =
1647 dnnl_primitive_desc_query_md(conv_pd, dnnl_query_weights_md, 0);
1648 const_dnnl_memory_desc_t conv_dst_md =
1649 dnnl_primitive_desc_query_md(conv_pd, dnnl_query_dst_md, 0);
1650 CK_DNNL_CONV(dnnl_memory_create(
1651 &user_src, user_src_md, ck_pytorch_brgemm_engine, input_bf16));
1652 CK_DNNL_CONV(dnnl_memory_create(
1653 &user_weight, user_weight_md, ck_pytorch_brgemm_engine, (void *)weights));
1654 CK_DNNL_CONV(dnnl_memory_create(
1655 &bias_mem, bias_md, ck_pytorch_brgemm_engine, bias_bf16));
1656 CK_DNNL_CONV(dnnl_memory_create(
1657 &user_dst, user_dst_md, ck_pytorch_brgemm_engine, output_bf16));
1658 CK_DNNL_CONV(dnnl_memory_create(
1659 &conv_src, conv_src_md, ck_pytorch_brgemm_engine, DNNL_MEMORY_ALLOCATE));
1660 CK_DNNL_CONV(dnnl_memory_create(
1661 &conv_weight, conv_weight_md, ck_pytorch_brgemm_engine, DNNL_MEMORY_ALLOCATE));
1662 CK_DNNL_CONV(dnnl_memory_create(
1663 &conv_dst, conv_dst_md, ck_pytorch_brgemm_engine, DNNL_MEMORY_ALLOCATE));
1664
1665 CK_DNNL_CONV(dnnl_reorder_primitive_desc_create(
1666 &reorder_pd, user_src_md, ck_pytorch_brgemm_engine,
1667 conv_src_md, ck_pytorch_brgemm_engine, NULL));
1668 CK_DNNL_CONV(dnnl_primitive_create(&reorder, reorder_pd));
1669 reorder_args[0] = (dnnl_exec_arg_t){DNNL_ARG_FROM, user_src};
1670 reorder_args[1] = (dnnl_exec_arg_t){DNNL_ARG_TO, conv_src};
1671 CK_DNNL_CONV(dnnl_primitive_execute(
1672 reorder, ck_pytorch_brgemm_stream, 2, reorder_args));
1673 dnnl_primitive_destroy(reorder); reorder = NULL;
1674 dnnl_primitive_desc_destroy(reorder_pd); reorder_pd = NULL;
1675
1676 CK_DNNL_CONV(dnnl_reorder_primitive_desc_create(
1677 &reorder_pd, user_weight_md, ck_pytorch_brgemm_engine,
1678 conv_weight_md, ck_pytorch_brgemm_engine, NULL));
1679 CK_DNNL_CONV(dnnl_primitive_create(&reorder, reorder_pd));
1680 reorder_args[0] = (dnnl_exec_arg_t){DNNL_ARG_FROM, user_weight};
1681 reorder_args[1] = (dnnl_exec_arg_t){DNNL_ARG_TO, conv_weight};
1682 CK_DNNL_CONV(dnnl_primitive_execute(
1683 reorder, ck_pytorch_brgemm_stream, 2, reorder_args));
1684 dnnl_primitive_destroy(reorder); reorder = NULL;
1685 dnnl_primitive_desc_destroy(reorder_pd); reorder_pd = NULL;
1686
1687 CK_DNNL_CONV(dnnl_primitive_create(&conv, conv_pd));
1688 dnnl_exec_arg_t conv_args[] = {
1689 {DNNL_ARG_SRC, conv_src},
1690 {DNNL_ARG_WEIGHTS, conv_weight},
1691 {DNNL_ARG_BIAS, bias_mem},
1692 {DNNL_ARG_DST, conv_dst},
1693 };
1694 CK_DNNL_CONV(dnnl_primitive_execute(
1695 conv, ck_pytorch_brgemm_stream,
1696 (int)(sizeof(conv_args) / sizeof(conv_args[0])), conv_args));
1697
1698 CK_DNNL_CONV(dnnl_reorder_primitive_desc_create(
1699 &reorder_pd, conv_dst_md, ck_pytorch_brgemm_engine,
1700 user_dst_md, ck_pytorch_brgemm_engine, NULL));
1701 CK_DNNL_CONV(dnnl_primitive_create(&reorder, reorder_pd));
1702 reorder_args[0] = (dnnl_exec_arg_t){DNNL_ARG_FROM, conv_dst};
1703 reorder_args[1] = (dnnl_exec_arg_t){DNNL_ARG_TO, user_dst};
1704 CK_DNNL_CONV(dnnl_primitive_execute(
1705 reorder, ck_pytorch_brgemm_stream, 2, reorder_args));
1706 CK_DNNL_CONV(dnnl_stream_wait(ck_pytorch_brgemm_stream));
1707
1708cleanup_conv:
1709 if (reorder) dnnl_primitive_destroy(reorder);
1710 if (reorder_pd) dnnl_primitive_desc_destroy(reorder_pd);
1711 if (conv) dnnl_primitive_destroy(conv);
1712 if (conv_dst) dnnl_memory_destroy(conv_dst);
1713 if (conv_weight) dnnl_memory_destroy(conv_weight);
1714 if (conv_src) dnnl_memory_destroy(conv_src);
1715 if (user_dst) dnnl_memory_destroy(user_dst);
1716 if (bias_mem) dnnl_memory_destroy(bias_mem);
1717 if (user_weight) dnnl_memory_destroy(user_weight);
1718 if (user_src) dnnl_memory_destroy(user_src);
1719 if (conv_pd) dnnl_primitive_desc_destroy(conv_pd);
1720 if (any_dst_md) dnnl_memory_desc_destroy(any_dst_md);
1721 if (any_weight_md) dnnl_memory_desc_destroy(any_weight_md);
1722 if (any_src_md) dnnl_memory_desc_destroy(any_src_md);
1723 if (user_dst_md) dnnl_memory_desc_destroy(user_dst_md);
1724 if (bias_md) dnnl_memory_desc_destroy(bias_md);
1725 if (user_weight_md) dnnl_memory_desc_destroy(user_weight_md);
1726 if (user_src_md) dnnl_memory_desc_destroy(user_src_md);
1727 pthread_mutex_unlock(&ck_pytorch_brgemm_lock);
1728#undef CK_DNNL_CONV
1729
1730 if (status != dnnl_success) {
1731 free(output_bf16);
1732 free(bias_bf16);
1733 free(input_bf16);
1734 ck_pytorch_brgemm_fault("oneDNN Conv3D execution failed", batch,
1735 out_channels, in_channels * temporal * patch_h * patch_w);
1736 }
1737 for (size_t i = 0; i < output_count; ++i) output[i] = bf16_to_float(output_bf16[i]);
1738 free(output_bf16);
1739 free(bias_bf16);
1740 free(input_bf16);
1741#else
1742 (void)input; (void)weights; (void)bias; (void)output; (void)batch;
1743 (void)out_channels; (void)in_channels; (void)temporal; (void)patch_h; (void)patch_w;
1744 fprintf(stderr, "HARD KERNEL CONTRACT FAULT: PyTorch oneDNN BF16 Conv3D "
1745 "was selected without USE_ONEDNN=1\n");
1746 abort();
1747#endif
1748}

References bf16_to_float(), and float_to_bf16().

Referenced by patch_projection_image_bf16_pytorch_onednn_conv3d_storage().

◆ patch_projection_image_bf16_native_storage()

void patch_projection_image_bf16_native_storage ( const float *  image,
const void *  weights_t0,
const void *  weights_t1,
const float *  bias,
float *  output,
int  channels,
int  image_h,
int  image_w,
int  patch_size,
int  out_channels,
int  merge_size 
)

Definition at line 1940 of file gemm_kernels_bf16.c.

1944{
1945 if (!image || !weights_t0 || !weights_t1 || !output || channels <= 0 ||
1946 image_h <= 0 || image_w <= 0 || patch_size <= 0 || out_channels <= 0 ||
1947 merge_size <= 0 || image_h % patch_size != 0 ||
1948 image_w % patch_size != 0) {
1949 fprintf(stderr, "HARD KERNEL CONTRACT FAULT: invalid native BF16 image patch projection\n");
1950 abort();
1951 }
1952 const int grid_h = image_h / patch_size;
1953 const int grid_w = image_w / patch_size;
1954 if (grid_h % merge_size != 0 || grid_w % merge_size != 0) {
1955 fprintf(stderr, "HARD KERNEL CONTRACT FAULT: native BF16 patch grid is not merge aligned\n");
1956 abort();
1957 }
1958 ck_patch_projection_bf16_native_args_t args = {
1959 .image = image,
1960 .weights_t0 = (const uint16_t *)weights_t0,
1961 .weights_t1 = (const uint16_t *)weights_t1,
1962 .bias = bias,
1963 .output = output,
1964 .channels = channels,
1965 .image_h = image_h,
1966 .image_w = image_w,
1967 .patch_size = patch_size,
1968 .out_channels = out_channels,
1969 .merge_size = merge_size,
1970 .grid_w = grid_w,
1971 .batch = grid_h * grid_w,
1972 };
1973 ck_threadpool_t *pool = ck_threadpool_global();
1974 int active = pool ? ck_threadpool_n_threads(pool) : 1;
1975 if (active > args.batch) active = args.batch;
1976 if (active > 24) active = 24;
1977 if (pool && active > 1) {
1979 pool, active, ck_patch_projection_bf16_native_work, &args);
1980 } else {
1982 }
1983}
static void ck_patch_projection_bf16_native_work(int ith, int nth, void *opaque)

References ck_patch_projection_bf16_native_work(), ck_threadpool_dispatch_n(), ck_threadpool_global(), and ck_threadpool_n_threads().

◆ patch_projection_image_bf16_pytorch_onednn_conv3d_storage()

void patch_projection_image_bf16_pytorch_onednn_conv3d_storage ( const float *  image,
const void *  weights_t0,
const void *  weights_t1,
const float *  bias,
float *  output,
int  channels,
int  image_h,
int  image_w,
int  patch_size,
int  out_channels,
int  merge_size 
)

Definition at line 1750 of file gemm_kernels_bf16.c.

1754{
1755#ifdef USE_ONEDNN
1756 if (!image || !weights_t0 || !weights_t1 || !bias || !output ||
1757 channels <= 0 || image_h <= 0 || image_w <= 0 || patch_size <= 0 ||
1758 out_channels <= 0 || merge_size <= 0 || image_h % patch_size != 0 ||
1759 image_w % patch_size != 0) {
1760 ck_pytorch_brgemm_fault("invalid image patch projection contract",
1761 image_h, image_w, patch_size);
1762 }
1763 const int grid_h = image_h / patch_size;
1764 const int grid_w = image_w / patch_size;
1765 if (grid_h % merge_size != 0 || grid_w % merge_size != 0) {
1766 ck_pytorch_brgemm_fault("patch grid is not merge-tile aligned",
1767 grid_h, grid_w, merge_size);
1768 }
1769 const int batch = grid_h * grid_w;
1770 const int temporal = 2;
1771 const int half_k = channels * patch_size * patch_size;
1772 const int full_k = temporal * half_k;
1773 float *patches = (float *)malloc((size_t)batch * (size_t)full_k * sizeof(*patches));
1774 uint16_t *weights = (uint16_t *)malloc(
1775 (size_t)out_channels * (size_t)full_k * sizeof(*weights));
1776 if (!patches || !weights) {
1777 free(weights);
1778 free(patches);
1779 ck_pytorch_brgemm_fault("image patch projection workspace allocation failed",
1780 batch, out_channels, full_k);
1781 }
1782
1783 for (int tok = 0; tok < batch; ++tok) {
1784 const int tiles_per_row = grid_w / merge_size;
1785 const int tile_area = merge_size * merge_size;
1786 const int tile = tok / tile_area;
1787 const int within = tok % tile_area;
1788 const int patch_y = (tile / tiles_per_row) * merge_size + within / merge_size;
1789 const int patch_x = (tile % tiles_per_row) * merge_size + within % merge_size;
1790 float *dst = patches + (size_t)tok * (size_t)full_k;
1791 for (int c = 0; c < channels; ++c) {
1792 for (int t = 0; t < temporal; ++t) {
1793 for (int py = 0; py < patch_size; ++py) {
1794 const float *src = image +
1795 ((size_t)c * (size_t)image_h +
1796 (size_t)(patch_y * patch_size + py)) * (size_t)image_w +
1797 (size_t)(patch_x * patch_size);
1798 memcpy(dst, src, (size_t)patch_size * sizeof(*dst));
1799 dst += patch_size;
1800 }
1801 }
1802 }
1803 }
1804
1805 const uint16_t *w0 = (const uint16_t *)weights_t0;
1806 const uint16_t *w1 = (const uint16_t *)weights_t1;
1807 for (int n = 0; n < out_channels; ++n) {
1808 uint16_t *dst = weights + (size_t)n * (size_t)full_k;
1809 for (int c = 0; c < channels; ++c) {
1810 const size_t channel_offset =
1811 (size_t)n * (size_t)half_k +
1812 (size_t)c * (size_t)patch_size * (size_t)patch_size;
1813 const size_t plane_bytes =
1814 (size_t)patch_size * (size_t)patch_size * sizeof(*dst);
1815 memcpy(dst, w0 + channel_offset, plane_bytes);
1816 dst += patch_size * patch_size;
1817 memcpy(dst, w1 + channel_offset, plane_bytes);
1818 dst += patch_size * patch_size;
1819 }
1820 }
1821
1823 patches, weights, bias, output, batch, out_channels, channels,
1824 temporal, patch_size, patch_size);
1825 free(weights);
1826 free(patches);
1827#else
1828 (void)image; (void)weights_t0; (void)weights_t1; (void)bias; (void)output;
1829 (void)channels; (void)image_h; (void)image_w; (void)patch_size;
1830 (void)out_channels; (void)merge_size;
1831 fprintf(stderr, "HARD KERNEL CONTRACT FAULT: PyTorch oneDNN BF16 image "
1832 "patch projection was selected without USE_ONEDNN=1\n");
1833 abort();
1834#endif
1835}
void patch_projection_bf16_pytorch_onednn_conv3d_storage(const float *input, const void *weights, const float *bias, float *output, int batch, int out_channels, int in_channels, int temporal, int patch_h, int patch_w)

References patch_projection_bf16_pytorch_onednn_conv3d_storage().

◆ position_embeddings_add()

void position_embeddings_add ( float *  x,
const float *  position_embd,
int  num_tokens,
int  embed_dim,
int  num_positions 
)

Add learned absolute position embeddings in-place.

x layout: [num_tokens, embed_dim] position_embd: [num_positions, embed_dim]

This first v8 vision path intentionally assumes native resized embeddings are already materialized in the weight tensor, so token i maps directly to position_embd[i]. This is the correct contract for fixed-size bring-up.

Definition at line 168 of file vision_kernels.c.

173{
174 if (x == NULL || position_embd == NULL || num_tokens <= 0 || embed_dim <= 0) {
175 return;
176 }
177 const int limit = num_tokens < num_positions ? num_tokens : num_positions;
178 for (int tok = 0; tok < limit; ++tok) {
179 float *dst = x + (size_t)tok * embed_dim;
180 const float *src = position_embd + (size_t)tok * embed_dim;
181 for (int d = 0; d < embed_dim; ++d) {
182 dst[d] += src[d];
183 }
184 }
185}

◆ position_embeddings_add_at_offset()

void position_embeddings_add_at_offset ( float *  x,
const float *  position_embd,
int  num_tokens,
int  embed_dim,
int  num_positions,
int  start_position 
)

Definition at line 187 of file vision_kernels.c.

193{
194 if (x == NULL || position_embd == NULL || num_tokens <= 0 || embed_dim <= 0 ||
195 num_positions <= 0 || start_position < 0 || start_position >= num_positions) {
196 return;
197 }
198 const int available = num_positions - start_position;
199 const int limit = num_tokens < available ? num_tokens : available;
200 for (int tok = 0; tok < limit; ++tok) {
201 float *dst = x + (size_t)tok * embed_dim;
202 const float *src = position_embd + (size_t)(start_position + tok) * embed_dim;
203 for (int d = 0; d < embed_dim; ++d) {
204 dst[d] += src[d];
205 }
206 }
207}

◆ position_embeddings_add_gemma4v_xy()

void position_embeddings_add_gemma4v_xy ( float *  x,
const float *  position_embd,
int  grid_h,
int  grid_w,
int  embed_dim,
int  source_grid_size 
)

Definition at line 209 of file vision_kernels.c.

215{
216 if (x == NULL || position_embd == NULL || grid_h <= 0 || grid_w <= 0 || embed_dim <= 0) {
217 return;
218 }
219 if (source_grid_size <= 0) {
220 source_grid_size = grid_w > grid_h ? grid_w : grid_h;
221 }
222
223 const size_t table_stride = (size_t) source_grid_size * (size_t) embed_dim;
224 const float *table_x = position_embd;
225 const float *table_y = position_embd + table_stride;
226
227 for (int y = 0; y < grid_h; ++y) {
228 const int yy = y < source_grid_size ? y : (source_grid_size - 1);
229 const float *row_y = table_y + (size_t) yy * (size_t) embed_dim;
230 for (int x_pos = 0; x_pos < grid_w; ++x_pos) {
231 const int xx = x_pos < source_grid_size ? x_pos : (source_grid_size - 1);
232 const float *row_x = table_x + (size_t) xx * (size_t) embed_dim;
233 float *dst = x + ((size_t) y * (size_t) grid_w + (size_t) x_pos) * (size_t) embed_dim;
234 for (int d = 0; d < embed_dim; ++d) {
235 dst[d] += row_x[d] + row_y[d];
236 }
237 }
238 }
239}

◆ position_embeddings_add_tiled_2d()

void position_embeddings_add_tiled_2d ( float *  x,
const float *  position_embd,
int  grid_h,
int  grid_w,
int  embed_dim,
int  merge_size,
int  source_grid_size 
)

Definition at line 248 of file vision_kernels.c.

255{
256 if (x == NULL || position_embd == NULL || grid_h <= 0 || grid_w <= 0 || embed_dim <= 0 || merge_size <= 0) {
257 return;
258 }
259
260 if (source_grid_size <= 0) {
261 source_grid_size = grid_h == grid_w ? grid_h : (grid_h > grid_w ? grid_h : grid_w);
262 }
263
264 const int num_tokens = grid_h * grid_w;
265 const int source_tokens = source_grid_size * source_grid_size;
266 const int needs_resize = source_grid_size != grid_h || source_grid_size != grid_w;
267
268 if (!needs_resize) {
269 for (int tok = 0; tok < num_tokens; ++tok) {
270 const int flat = tile_order_index_2d(tok, grid_h, grid_w, merge_size);
271 if (flat < 0 || flat >= source_tokens) {
272 continue;
273 }
274 float *dst = x + (size_t) tok * (size_t) embed_dim;
275 const float *src = position_embd + (size_t) flat * (size_t) embed_dim;
276 for (int d = 0; d < embed_dim; ++d) {
277 dst[d] += src[d];
278 }
279 }
280 return;
281 }
282
283 const float sf_x = (float) grid_w / (float) source_grid_size;
284 const float sf_y = (float) grid_h / (float) source_grid_size;
285 const float pixel_offset = 0.5f;
286 const float support_x = fmaxf(1.0f, 1.0f / sf_x);
287 const float support_y = fmaxf(1.0f, 1.0f / sf_y);
288 const float invscale_x = 1.0f / support_x;
289 const float invscale_y = 1.0f / support_y;
290
291 /* Preserve ggml's channel -> row -> column loop nesting. The destination
292 * index converts the row-major interpolation result directly to CK's
293 * merge-tiled token layout without allocating an intermediate tensor. */
294 for (int d = 0; d < embed_dim; ++d) {
295 for (int dst_y = 0; dst_y < grid_h; ++dst_y) {
296 const float y_src = ((float) dst_y + pixel_offset) / sf_y;
297 int y_min = (int) (y_src - support_y + pixel_offset);
298 int y_max = (int) (y_src + support_y + pixel_offset);
299 if (y_min < 0) y_min = 0;
300 if (y_max > source_grid_size) y_max = source_grid_size;
301
302 for (int dst_x = 0; dst_x < grid_w; ++dst_x) {
303 const float x_src = ((float) dst_x + pixel_offset) / sf_x;
304 int x_min = (int) (x_src - support_x + pixel_offset);
305 int x_max = (int) (x_src + support_x + pixel_offset);
306 if (x_min < 0) x_min = 0;
307 if (x_max > source_grid_size) x_max = source_grid_size;
308 float val = 0.0f;
309 float total_weight = 0.0f;
310 for (int sy = y_min; sy < y_max; ++sy) {
311 const float wy_arg = ((float) sy - y_src + pixel_offset) * invscale_y;
312 const float wy = fmaxf(1.0f - fabsf(wy_arg), 0.0f);
313 if (wy <= 0.0f) {
314 continue;
315 }
316 for (int sx = x_min; sx < x_max; ++sx) {
317 const float wx_arg = ((float) sx - x_src + pixel_offset) * invscale_x;
318 const float wx = fmaxf(1.0f - fabsf(wx_arg), 0.0f);
319 const float weight = wx * wy;
320 if (weight <= 0.0f) {
321 continue;
322 }
323 const float sample = position_embd[((size_t) sy * (size_t) source_grid_size + (size_t) sx) * (size_t) embed_dim + (size_t) d];
324 val = fmaf(sample, weight, val);
325 total_weight += weight;
326 }
327 }
328 if (total_weight > 0.0f) {
329 val /= total_weight;
330 const int tok = tile_order_linear_index_2d(
331 dst_y, dst_x, grid_h, grid_w, merge_size);
332 x[(size_t) tok * (size_t) embed_dim + (size_t) d] += val;
333 }
334 }
335 }
336 }
337}
static int tile_order_linear_index_2d(int y, int x, int grid_h, int grid_w, int merge_size)

References tile_order_index_2d(), and tile_order_linear_index_2d().

◆ position_embeddings_add_tiled_2d_align_corners()

void position_embeddings_add_tiled_2d_align_corners ( float *  x,
const float *  position_embd,
int  grid_h,
int  grid_w,
int  embed_dim,
int  merge_size,
int  source_grid_size 
)

Definition at line 342 of file vision_kernels.c.

349{
350 if (x == NULL || position_embd == NULL || grid_h <= 0 || grid_w <= 0 ||
351 embed_dim <= 0 || merge_size <= 0 || source_grid_size <= 0) {
352 return;
353 }
354
355 const float y_scale = grid_h > 1
356 ? (float)(source_grid_size - 1) / (float)(grid_h - 1)
357 : 0.0f;
358 const float x_scale = grid_w > 1
359 ? (float)(source_grid_size - 1) / (float)(grid_w - 1)
360 : 0.0f;
361
362 for (int tok = 0; tok < grid_h * grid_w; ++tok) {
363 const int row_major = tile_order_index_2d(tok, grid_h, grid_w, merge_size);
364 const int dst_y = row_major / grid_w;
365 const int dst_x = row_major % grid_w;
366 const float src_y = (float)dst_y * y_scale;
367 const float src_x = (float)dst_x * x_scale;
368 const int y0 = (int)src_y;
369 const int x0 = (int)src_x;
370 const int y1 = y0 + 1 < source_grid_size ? y0 + 1 : y0;
371 const int x1 = x0 + 1 < source_grid_size ? x0 + 1 : x0;
372 const float dy = src_y - (float)y0;
373 const float dx = src_x - (float)x0;
374 const float w00 = (1.0f - dy) * (1.0f - dx);
375 const float w01 = (1.0f - dy) * dx;
376 const float w10 = dy * (1.0f - dx);
377 const float w11 = dy * dx;
378 const float *p00 = position_embd + ((size_t)y0 * source_grid_size + x0) * embed_dim;
379 const float *p01 = position_embd + ((size_t)y0 * source_grid_size + x1) * embed_dim;
380 const float *p10 = position_embd + ((size_t)y1 * source_grid_size + x0) * embed_dim;
381 const float *p11 = position_embd + ((size_t)y1 * source_grid_size + x1) * embed_dim;
382 float *dst = x + (size_t)tok * embed_dim;
383
384 for (int d = 0; d < embed_dim; ++d) {
385 const float pos = p00[d] * w00 + p01[d] * w01 + p10[d] * w10 + p11[d] * w11;
386 dst[d] += pos;
387 }
388 }
389}

References tile_order_index_2d().

◆ position_embeddings_add_tiled_2d_align_corners_bf16()

void position_embeddings_add_tiled_2d_align_corners_bf16 ( float *  x,
const float *  position_embd,
int  grid_h,
int  grid_w,
int  embed_dim,
int  merge_size,
int  source_grid_size 
)

Definition at line 397 of file vision_kernels.c.

404{
405 if (x == NULL || position_embd == NULL || grid_h <= 0 || grid_w <= 0 ||
406 embed_dim <= 0 || merge_size <= 0 || source_grid_size <= 0) {
407 return;
408 }
409
410 for (int tok = 0; tok < grid_h * grid_w; ++tok) {
411 const int row_major = tile_order_index_2d(tok, grid_h, grid_w, merge_size);
412 const int dst_y = row_major / grid_w;
413 const int dst_x = row_major % grid_w;
414 /* torch.linspace computes each rational coordinate before FP32 storage. */
415 const float src_y = grid_h > 1
416 ? (float)((double)dst_y * (double)(source_grid_size - 1) / (double)(grid_h - 1))
417 : 0.0f;
418 const float src_x = grid_w > 1
419 ? (float)((double)dst_x * (double)(source_grid_size - 1) / (double)(grid_w - 1))
420 : 0.0f;
421 const int y0 = (int)src_y;
422 const int x0 = (int)src_x;
423 const int y1 = y0 + 1 < source_grid_size ? y0 + 1 : y0;
424 const int x1 = x0 + 1 < source_grid_size ? x0 + 1 : x0;
425 const float dy = src_y - (float)y0;
426 const float dx = src_x - (float)x0;
427 const float w00 = bf16_to_float(float_to_bf16((1.0f - dy) * (1.0f - dx)));
428 const float w01 = bf16_to_float(float_to_bf16((1.0f - dy) * dx));
429 const float w10 = bf16_to_float(float_to_bf16(dy * (1.0f - dx)));
430 const float w11 = bf16_to_float(float_to_bf16(dy * dx));
431 const float *p00 = position_embd + ((size_t)y0 * source_grid_size + x0) * embed_dim;
432 const float *p01 = position_embd + ((size_t)y0 * source_grid_size + x1) * embed_dim;
433 const float *p10 = position_embd + ((size_t)y1 * source_grid_size + x0) * embed_dim;
434 const float *p11 = position_embd + ((size_t)y1 * source_grid_size + x1) * embed_dim;
435 float *dst = x + (size_t)tok * embed_dim;
436
437 for (int d = 0; d < embed_dim; ++d) {
438 const float v00 = bf16_to_float(float_to_bf16(p00[d] * w00));
439 const float v01 = bf16_to_float(float_to_bf16(p01[d] * w01));
440 const float v10 = bf16_to_float(float_to_bf16(p10[d] * w10));
441 const float v11 = bf16_to_float(float_to_bf16(p11[d] * w11));
442 float pos = bf16_to_float(float_to_bf16(v00 + v01));
443 pos = bf16_to_float(float_to_bf16(pos + v10));
444 pos = bf16_to_float(float_to_bf16(pos + v11));
445 const float hidden = bf16_to_float(float_to_bf16(dst[d]));
446 dst[d] = bf16_to_float(float_to_bf16(hidden + pos));
447 }
448 }
449}

References bf16_to_float(), float_to_bf16(), and tile_order_index_2d().

◆ position_embeddings_add_tiled_2d_align_corners_fp32_interp_bf16()

void position_embeddings_add_tiled_2d_align_corners_fp32_interp_bf16 ( float *  x,
const float *  position_embd,
int  grid_h,
int  grid_w,
int  embed_dim,
int  merge_size,
int  source_grid_size 
)

Definition at line 458 of file vision_kernels.c.

466{
467 if (x == NULL || position_embd == NULL || grid_h <= 0 || grid_w <= 0 ||
468 embed_dim <= 0 || merge_size <= 0 || source_grid_size <= 0) {
469 return;
470 }
471
472 for (int tok = 0; tok < grid_h * grid_w; ++tok) {
473 const int row_major = tile_order_index_2d(tok, grid_h, grid_w, merge_size);
474 const int dst_y = row_major / grid_w;
475 const int dst_x = row_major % grid_w;
476 const float src_y = grid_h > 1
477 ? (float)dst_y * (float)(source_grid_size - 1) / (float)(grid_h - 1)
478 : 0.0f;
479 const float src_x = grid_w > 1
480 ? (float)dst_x * (float)(source_grid_size - 1) / (float)(grid_w - 1)
481 : 0.0f;
482 const int y0 = (int)src_y;
483 const int x0 = (int)src_x;
484 const int y1 = y0 + 1 < source_grid_size ? y0 + 1 : y0;
485 const int x1 = x0 + 1 < source_grid_size ? x0 + 1 : x0;
486 const float y_distance0 = fabsf(src_y - (float)y0);
487 const float y_distance1 = fabsf(src_y - (float)y0 - 1.0f);
488 const float x_distance0 = fabsf(src_x - (float)x0);
489 const float x_distance1 = fabsf(src_x - (float)x0 - 1.0f);
490 const float wy0 = fmaxf(1.0f - y_distance0, 0.0f);
491 const float wy1 = fmaxf(1.0f - y_distance1, 0.0f);
492 const float wx0 = fmaxf(1.0f - x_distance0, 0.0f);
493 const float wx1 = fmaxf(1.0f - x_distance1, 0.0f);
494 const float w00 = wy0 * wx0;
495 const float w01 = wy0 * wx1;
496 const float w10 = wy1 * wx0;
497 const float w11 = wy1 * wx1;
498 const float *p00 = position_embd + ((size_t)y0 * source_grid_size + x0) * embed_dim;
499 const float *p01 = position_embd + ((size_t)y0 * source_grid_size + x1) * embed_dim;
500 const float *p10 = position_embd + ((size_t)y1 * source_grid_size + x0) * embed_dim;
501 const float *p11 = position_embd + ((size_t)y1 * source_grid_size + x1) * embed_dim;
502 float *dst = x + (size_t)tok * embed_dim;
503
504 for (int d = 0; d < embed_dim; ++d) {
505 /* Materialize products before the reduction, as torch.sum does. */
506 volatile float v00 = p00[d] * w00;
507 volatile float v01 = p01[d] * w01;
508 volatile float v10 = p10[d] * w10;
509 volatile float v11 = p11[d] * w11;
510 volatile float pos01 = v00 + v01;
511 volatile float pos012 = pos01 + v10;
512 const float pos = pos012 + v11;
513 const float pos_bf16 = bf16_to_float(float_to_bf16(pos));
514 const float hidden = bf16_to_float(float_to_bf16(dst[d]));
515 dst[d] = bf16_to_float(float_to_bf16(hidden + pos_bf16));
516 }
517 }
518}

References bf16_to_float(), float_to_bf16(), and tile_order_index_2d().

◆ q_norm_forward()

void q_norm_forward ( float *  q,
const float *  q_gamma,
int  num_heads,
int  num_tokens,
int  head_dim,
float  eps 
)

Forward pass for Gemma4-assistant q-only per-head RMSNorm.

Some Gemma4 assistant/drafter checkpoints project only Q and then reuse Q as the shared K/V stream. This wrapper keeps that public kernel contract explicit while reusing the same row-wise RMSNorm implementation as qk_norm_forward.

Definition at line 405 of file qk_norm_kernels.c.

411{
412 rmsnorm_forward(q, q_gamma, q, NULL,
413 num_heads * num_tokens, head_dim, head_dim, eps);
414}
void rmsnorm_forward(const float *input, const float *gamma, float *output, float *rstd_cache, int tokens, int d_model, int aligned_embed_dim, float eps)

References rmsnorm_forward().

◆ qk_norm_backward()

void qk_norm_backward ( const float *  d_q_out,
const float *  d_k_out,
const float *  q_in,
const float *  k_in,
const float *  q_gamma,
const float *  k_gamma,
float *  d_q_in,
float *  d_k_in,
float *  d_q_gamma,
float *  d_k_gamma,
int  num_heads,
int  num_kv_heads,
int  num_tokens,
int  head_dim,
float  eps 
)

Backward pass for per-head QK RMSNorm.

This computes:

  • d_q / d_k for the Q and K activations
  • d_q_gamma / d_k_gamma for shared per-head gamma vectors

Implementation is reference-first and deterministic: 1) recompute row rstd values from saved q/k inputs 2) call rmsnorm_backward on flattened [rows, head_dim] views

Definition at line 427 of file qk_norm_kernels.c.

434{
435 int q_rows = num_heads * num_tokens;
436 int k_rows = num_kv_heads * num_tokens;
437
438 if (q_rows > 0) {
439 float q_rstd_cache[q_rows];
440 qk_norm_compute_rstd(q_in, q_rstd_cache, q_rows, head_dim, eps);
441 rmsnorm_backward(d_q_out, q_in, q_gamma, q_rstd_cache,
442 d_q_in, d_q_gamma, q_rows, head_dim, head_dim);
443 }
444
445 if (k_rows > 0) {
446 float k_rstd_cache[k_rows];
447 qk_norm_compute_rstd(k_in, k_rstd_cache, k_rows, head_dim, eps);
448 rmsnorm_backward(d_k_out, k_in, k_gamma, k_rstd_cache,
449 d_k_in, d_k_gamma, k_rows, head_dim, head_dim);
450 }
451}
static void qk_norm_compute_rstd(const float *input, float *rstd_cache, int rows, int head_dim, float eps)
void rmsnorm_backward(const float *d_output, const float *input, const float *gamma, const float *rstd_cache, float *d_input, float *d_gamma, int tokens, int d_model, int aligned_embed_dim)

References qk_norm_compute_rstd(), and rmsnorm_backward().

◆ qk_norm_backward_last_isa()

int qk_norm_backward_last_isa ( void  )

Definition at line 111 of file qk_norm_kernels.c.

112{
113 return g_qk_norm_last_isa;
114}
static int g_qk_norm_last_isa

References g_qk_norm_last_isa.

◆ qk_norm_forward()

void qk_norm_forward ( float *  q,
float *  k,
const float *  q_gamma,
const float *  k_gamma,
int  num_heads,
int  num_kv_heads,
int  num_tokens,
int  head_dim,
float  eps 
)

Per-head RMSNorm on Q and K.

Parameters
qQ scratch buffer [num_heads * num_tokens * head_dim], in-place
kK scratch buffer [num_kv_heads * num_tokens * head_dim], in-place
q_gammaQ norm gamma weights [head_dim]
k_gammaK norm gamma weights [head_dim]
num_headsNumber of query heads (e.g. 32 for Qwen3-8B)
num_kv_headsNumber of KV heads (e.g. 8 for Qwen3-8B with GQA)
num_tokensNumber of tokens (1 for decode, T for prefill)
head_dimDimension per head (e.g. 128)
epsRMSNorm epsilon (e.g. 1e-6)
Test:
unittest/test_qk_norm.py

Definition at line 326 of file qk_norm_kernels.c.

330{
331 /* Q norm: [num_heads * num_tokens] rows of [head_dim]
332 * Each row is one head's vector for one token. */
333 rmsnorm_forward(q, q_gamma, q, NULL,
334 num_heads * num_tokens, head_dim, head_dim, eps);
335
336 /* K norm: [num_kv_heads * num_tokens] rows of [head_dim]
337 * Same logic, fewer rows when using GQA. */
338 rmsnorm_forward(k, k_gamma, k, NULL,
339 num_kv_heads * num_tokens, head_dim, head_dim, eps);
340}

References rmsnorm_forward().

◆ qk_norm_forward_decode_exact()

void qk_norm_forward_decode_exact ( float *  q,
float *  k,
const float *  q_gamma,
const float *  k_gamma,
int  num_heads,
int  num_kv_heads,
int  num_tokens,
int  head_dim,
float  eps 
)

◆ qk_norm_forward_fp64_sum()

void qk_norm_forward_fp64_sum ( float *  q,
float *  k,
const float *  q_gamma,
const float *  k_gamma,
int  num_heads,
int  num_kv_heads,
int  num_tokens,
int  head_dim,
float  eps 
)

Definition at line 342 of file qk_norm_kernels.c.

346{
347 rmsnorm_forward_fp64_sum(q, q_gamma, q, NULL,
348 num_heads * num_tokens, head_dim, head_dim, eps);
349 rmsnorm_forward_fp64_sum(k, k_gamma, k, NULL,
350 num_kv_heads * num_tokens, head_dim, head_dim, eps);
351}
void rmsnorm_forward_fp64_sum(const float *input, const float *gamma, float *output, float *rstd_cache, int tokens, int d_model, int aligned_embed_dim, float eps)

References rmsnorm_forward_fp64_sum().

◆ qk_norm_forward_llama_production()

void qk_norm_forward_llama_production ( float *  q,
float *  k,
const float *  q_gamma,
const float *  k_gamma,
int  num_heads,
int  num_kv_heads,
int  num_tokens,
int  head_dim,
float  eps 
)

Definition at line 353 of file qk_norm_kernels.c.

357{
359 q, q_gamma, q, NULL,
360 num_heads * num_tokens, head_dim, head_dim, eps);
362 k, k_gamma, k, NULL,
363 num_kv_heads * num_tokens, head_dim, head_dim, eps);
364}
void rmsnorm_forward_llama_production(const float *input, const float *gamma, float *output, float *rstd_cache, int tokens, int d_model, int aligned_embed_dim, float eps)

References rmsnorm_forward_llama_production().

◆ qk_norm_forward_parallel_dispatch()

void qk_norm_forward_parallel_dispatch ( float *  q,
float *  k,
const float *  q_gamma,
const float *  k_gamma,
int  num_heads,
int  num_kv_heads,
int  num_tokens,
int  head_dim,
float  eps 
)

◆ qk_norm_forward_prefill_exact()

void qk_norm_forward_prefill_exact ( float *  q,
float *  k,
const float *  q_gamma,
const float *  k_gamma,
int  num_heads,
int  num_kv_heads,
int  num_tokens,
int  head_dim,
float  eps 
)

◆ qk_norm_forward_pytorch_bf16_storage()

void qk_norm_forward_pytorch_bf16_storage ( float *  q,
float *  k,
const float *  q_gamma,
const float *  k_gamma,
int  num_heads,
int  num_kv_heads,
int  num_tokens,
int  head_dim,
float  eps 
)

Definition at line 366 of file qk_norm_kernels.c.

372{
374 q, q_gamma, q, NULL,
375 num_heads * num_tokens, head_dim, head_dim, eps);
377 k, k_gamma, k, NULL,
378 num_kv_heads * num_tokens, head_dim, head_dim, eps);
379}
void rmsnorm_forward_pytorch_bf16_storage(const float *input, const float *gamma, float *output, float *rstd_cache, int tokens, int d_model, int aligned_embed_dim, float eps)

References rmsnorm_forward_pytorch_bf16_storage().

◆ qk_norm_forward_qwen4_pytorch_bf16_storage()

void qk_norm_forward_qwen4_pytorch_bf16_storage ( float *  q,
float *  k,
const float *  q_gamma,
const float *  k_gamma,
int  num_heads,
int  num_kv_heads,
int  num_tokens,
int  head_dim,
float  eps 
)

Definition at line 381 of file qk_norm_kernels.c.

389{
391 q, q_gamma, q, NULL,
392 num_heads * num_tokens, head_dim, head_dim, eps);
394 k, k_gamma, k, NULL,
395 num_kv_heads * num_tokens, head_dim, head_dim, eps);
396}
void rmsnorm_forward_qwen3next_pytorch_bf16_storage(const float *input, const float *gamma, float *output, float *rstd_cache, int tokens, int d_model, int aligned_embed_dim, float eps)

References rmsnorm_forward_qwen3next_pytorch_bf16_storage().

◆ quantize_batch_q8_0()

void quantize_batch_q8_0 ( const float *  x,
void *  vy,
int  num_rows,
int  k 
)

Batch quantize FP32 to Q8_0 format (row-major output)

Quantizes multiple rows of FP32 data to Q8_0 format, placing each row's Q8_0 output at the correct byte offset for GEMM compatibility.

Memory layout: Input: [num_rows, k] FP32, row-major (stride = k * sizeof(float)) Output: [num_rows, q8_row_bytes] Q8_0, row-major (stride = q8_row_bytes)

where q8_row_bytes = (k / 32) * sizeof(block_q8_0) = (k / 32) * 34

Parameters
xInput FP32 values [num_rows * k]
vyOutput Q8_0 blocks [num_rows * (k/32) blocks]
num_rowsNumber of rows (batch size / tokens)
kElements per row (must be multiple of 32)

Definition at line 256 of file gemm_kernels_q8_0.c.

257{
258 const size_t row_bytes_in = (size_t)k * sizeof(float);
259 const size_t row_bytes_out = (size_t)(k / QK8_0) * sizeof(block_q8_0);
260
261 uint8_t *out = (uint8_t *)vy;
262 const uint8_t *in = (const uint8_t *)x;
263
264 for (int row = 0; row < num_rows; ++row) {
266 (const float *)(in + row * row_bytes_in),
267 (void *)(out + row * row_bytes_out),
268 k
269 );
270 }
271}
void quantize_row_q8_0(const float *x, void *vy, int k)
Quantize FP32 to Q8_0 format (scalar reference)

References QK8_0, and quantize_row_q8_0().

◆ quantize_batch_q8_k()

void quantize_batch_q8_k ( const float *  x,
void *  vy,
int  num_rows,
int  k 
)

Batch quantize FP32 to Q8_K format (row-major output)

Same as quantize_batch_q8_0 but for Q8_K format (super-blocks).

Parameters
xInput FP32 values [num_rows * k]
vyOutput Q8_K blocks
num_rowsNumber of rows (batch size / tokens)
kElements per row (must be multiple of 256)

Definition at line 283 of file gemm_kernels_q8_0.c.

284{
285 /* Q8_K: 256 elements per super-block, each block is larger */
286 const size_t row_bytes_in = (size_t)k * sizeof(float);
287 /* Q8_K block size = 2 (d) + 256 (qs) + 32 (bsums/2) = ~274 bytes for 256 elements */
288 /* Actual: sizeof(block_q8_K) from ckernel_quant.h */
289 const size_t row_bytes_out = (size_t)(k / 256) * sizeof(block_q8_K);
290
291 uint8_t *out = (uint8_t *)vy;
292 const uint8_t *in = (const uint8_t *)x;
293
294 for (int row = 0; row < num_rows; ++row) {
296 (const float *)(in + row * row_bytes_in),
297 (void *)(out + row * row_bytes_out),
298 k
299 );
300 }
301}
void quantize_row_q8_k(const float *x, void *vy, int k)

References quantize_row_q8_k().

◆ quantize_batch_q8_k_4row_nearest_even()

void quantize_batch_q8_k_4row_nearest_even ( const float *  x,
void *  y,
int  num_rows,
int  k 
)

Definition at line 140 of file gemm_kernels_q4k_q8k.c.

141 {
142 if (!x || !vy || num_rows <= 0 || k <= 0) {
143 return;
144 }
145 assert(k % QK_K == 0);
146
147 block_q8_K *y = (block_q8_K *)vy;
148 const int blocks_per_row = k / QK_K;
149
150 /* Q8_K bytes are a numerical ABI. The previous four-row AVX2 path used
151 * a different max/scale evaluation order and changed real Qwen3-VL
152 * visual-prefix scales by one FP32 ULP. Keep this public grouped ABI on
153 * the canonical row provider until an optimized implementation is
154 * byte-exact against llama.cpp on both synthetic and production inputs. */
155 for (int row = 0; row < num_rows; ++row) {
157 x + (size_t)row * (size_t)k,
158 y + (size_t)row * (size_t)blocks_per_row,
159 k);
160 }
161}
void quantize_row_q8_k(const float *x, void *vy, int k)

References QK_K, and quantize_row_q8_k().

◆ quantize_row_q8_0()

void quantize_row_q8_0 ( const float *  x,
void *  vy,
int  k 
)

Quantize FP32 to Q8_0 format (scalar reference)

Parameters
xInput FP32 values
vyOutput Q8_0 blocks
kNumber of elements (must be multiple of 32)

Definition at line 125 of file gemm_kernels_q8_0.c.

126{
127 block_q8_0 *y = (block_q8_0 *)vy;
128 const int nb = k / QK8_0; /* QK8_0 = 32 */
129
130#if defined(__AVX__)
131 const __m256 sign_bit = _mm256_set1_ps(-0.0f);
132
133 for (int i = 0; i < nb; i++) {
134 __m256 v0 = _mm256_loadu_ps(x + 0);
135 __m256 v1 = _mm256_loadu_ps(x + 8);
136 __m256 v2 = _mm256_loadu_ps(x + 16);
137 __m256 v3 = _mm256_loadu_ps(x + 24);
138 x += QK8_0;
139
140 __m256 max_abs = _mm256_andnot_ps(sign_bit, v0);
141 max_abs = _mm256_max_ps(max_abs, _mm256_andnot_ps(sign_bit, v1));
142 max_abs = _mm256_max_ps(max_abs, _mm256_andnot_ps(sign_bit, v2));
143 max_abs = _mm256_max_ps(max_abs, _mm256_andnot_ps(sign_bit, v3));
144
145 __m128 max4 = _mm_max_ps(_mm256_extractf128_ps(max_abs, 1),
146 _mm256_castps256_ps128(max_abs));
147 max4 = _mm_max_ps(max4, _mm_movehl_ps(max4, max4));
148 max4 = _mm_max_ss(max4, _mm_movehdup_ps(max4));
149 const float max_scalar = _mm_cvtss_f32(max4);
150
151#if defined(__INTEL_LLVM_COMPILER)
152 const float d = ck_q8_0_div_rounded_f32(max_scalar, 127.0f);
153 const float id = max_scalar != 0.0f
154 ? ck_q8_0_div_rounded_f32(127.0f, max_scalar)
155 : 0.0f;
156#else
157 const float d = max_scalar / 127.0f;
158 const float id = max_scalar != 0.0f ? 127.0f / max_scalar : 0.0f;
159#endif
160 y[i].d = CK_FP32_TO_FP16(d);
161
162 const __m256 mul = _mm256_set1_ps(id);
163 v0 = _mm256_mul_ps(v0, mul);
164 v1 = _mm256_mul_ps(v1, mul);
165 v2 = _mm256_mul_ps(v2, mul);
166 v3 = _mm256_mul_ps(v3, mul);
167
168 /* Match llama.cpp x86 Q8 quantization: nearest-even rounding. */
169 v0 = _mm256_round_ps(v0, _MM_ROUND_NEAREST);
170 v1 = _mm256_round_ps(v1, _MM_ROUND_NEAREST);
171 v2 = _mm256_round_ps(v2, _MM_ROUND_NEAREST);
172 v3 = _mm256_round_ps(v3, _MM_ROUND_NEAREST);
173
174 __m256i i0 = _mm256_cvtps_epi32(v0);
175 __m256i i1 = _mm256_cvtps_epi32(v1);
176 __m256i i2 = _mm256_cvtps_epi32(v2);
177 __m256i i3 = _mm256_cvtps_epi32(v3);
178
179#if defined(__AVX2__)
180 i0 = _mm256_packs_epi32(i0, i1);
181 i2 = _mm256_packs_epi32(i2, i3);
182 i0 = _mm256_packs_epi16(i0, i2);
183
184 const __m256i perm = _mm256_setr_epi32(0, 4, 1, 5, 2, 6, 3, 7);
185 i0 = _mm256_permutevar8x32_epi32(i0, perm);
186 _mm256_storeu_si256((__m256i *)y[i].qs, i0);
187#else
188 __m128i ni0 = _mm256_castsi256_si128(i0);
189 __m128i ni1 = _mm256_extractf128_si256(i0, 1);
190 __m128i ni2 = _mm256_castsi256_si128(i1);
191 __m128i ni3 = _mm256_extractf128_si256(i1, 1);
192 __m128i ni4 = _mm256_castsi256_si128(i2);
193 __m128i ni5 = _mm256_extractf128_si256(i2, 1);
194 __m128i ni6 = _mm256_castsi256_si128(i3);
195 __m128i ni7 = _mm256_extractf128_si256(i3, 1);
196
197 ni0 = _mm_packs_epi32(ni0, ni1);
198 ni2 = _mm_packs_epi32(ni2, ni3);
199 ni4 = _mm_packs_epi32(ni4, ni5);
200 ni6 = _mm_packs_epi32(ni6, ni7);
201
202 ni0 = _mm_packs_epi16(ni0, ni2);
203 ni4 = _mm_packs_epi16(ni4, ni6);
204
205 _mm_storeu_si128((__m128i *)(y[i].qs + 0), ni0);
206 _mm_storeu_si128((__m128i *)(y[i].qs + 16), ni4);
207#endif
208 }
209#else
210 for (int i = 0; i < nb; i++) {
211 const float *xb = x + i * QK8_0;
212
213 /* Find max absolute value in block */
214 float amax = 0.0f;
215 for (int j = 0; j < QK8_0; j++) {
216 float av = xb[j] >= 0 ? xb[j] : -xb[j];
217 if (av > amax) amax = av;
218 }
219
220 /* Compute scale: d = max / 127 */
221 float d = amax / 127.0f;
222 float id = d != 0.0f ? 127.0f / amax : 0.0f;
223
224 /* Store scale as FP16 */
225 y[i].d = CK_FP32_TO_FP16(d);
226
227 /* Quantize values */
228 for (int j = 0; j < QK8_0; j++) {
229 float v = xb[j] * id;
230 int q = ck_nearest_int_q8_0(v);
231 if (q > 127) q = 127;
232 if (q < -127) q = -127;
233 y[i].qs[j] = (int8_t)q;
234 }
235 }
236#endif
237}
#define CK_FP32_TO_FP16(x)
static int ck_nearest_int_q8_0(float fval)
int32_t id
Definition tokenizer.h:316

References CK_FP32_TO_FP16, ck_nearest_int_q8_0(), block_q8_0::d, id, QK8_0, and block_q8_0::qs.

Referenced by ck_moe_q4k_mixed_route_work(), ck_moe_shared_q4k_gated_workspace(), ck_moe_swiglu_nvfp4_projection(), fused_mlp_swiglu_prefill_w1w2_quant(), fused_rmsnorm_qkv_prefill_head_major_quant(), gemv_q8_0_q8_0_contract(), hyper_connection_mix_quantized(), moe_swiglu_expert_forward_q4k_q5_0_workspace(), moe_swiglu_expert_forward_q4k_q8_0_workspace(), moe_swiglu_shared_forward_q8_0_gated_workspace(), quantize_attn_out_head_major_q8_0(), quantize_attn_out_head_major_q8_0(), and quantize_attn_out_head_major_q8_0().

◆ quantize_row_q8_k()

void quantize_row_q8_k ( const float *  x,
void *  y,
int  k 
)

Definition at line 121 of file gemm_kernels_q4k_q8k.c.

121 {
122 const char *ref_env = getenv("CK_DEBUG_Q8K_REF");
123 if (ref_env && atoi(ref_env) != 0) {
124 quantize_row_q8_k_ref(x, vy, k);
125 return;
126 }
127#if defined(__AVX512F__) && defined(__AVX512BW__)
128 quantize_row_q8_k_avx512(x, vy, k);
129#elif defined(__AVX2__)
130 quantize_row_q8_k_avx2(x, vy, k);
131#elif defined(__AVX__)
132 quantize_row_q8_k_avx(x, vy, k);
133#elif defined(__SSE4_1__)
134 quantize_row_q8_k_sse(x, vy, k);
135#else
136 quantize_row_q8_k_ref(x, vy, k);
137#endif
138}
void quantize_row_q8_k_avx512(const float *x, void *vy, int k)
void quantize_row_q8_k_avx2(const float *x, void *vy, int k)
void quantize_row_q8_k_avx(const float *x, void *vy, int k)
void quantize_row_q8_k_sse(const float *x, void *vy, int k)
void quantize_row_q8_k_ref(const float *x, void *vy, int k)

References quantize_row_q8_k_avx(), quantize_row_q8_k_avx2(), quantize_row_q8_k_avx512(), quantize_row_q8_k_ref(), and quantize_row_q8_k_sse().

Referenced by ck_attention_project_head_major_q4_k_q8_k(), ck_layer_forward_rmsnorm_swiglu_decode_q4_k(), ck_mlp_swiglu_forward_q4_k_q8_k(), ck_mlp_swiglu_forward_q4_k_q8_k_prefill(), ck_moe_q4k_mixed_route_parallel(), ck_moe_q4k_mixed_route_work(), ck_moe_q4k_q5k_bucket_work(), ck_moe_q4k_q5k_quantize_work(), ck_moe_q4k_q5k_route_parallel(), ck_moe_q4k_q5k_route_work(), ck_moe_shared_q4k_gated_workspace(), ck_qkv_project_head_major_q4_k_q8_k(), decode_layer_parallel(), fused_mlp_swiglu_prefill_w1w2_quant(), fused_rmsnorm_qkv_prefill_head_major_quant(), hyper_connection_mix_quantized(), mlp_parallel(), model_decode_token(), model_decode_token(), model_forward_prefill_impl(), model_forward_prefill_impl(), model_forward_prefill_impl(), model_forward_prefill_impl(), model_layer_0_decode(), model_layer_0_decode(), model_layer_10_decode(), model_layer_10_decode(), model_layer_11_decode(), model_layer_11_decode(), model_layer_12_decode(), model_layer_12_decode(), model_layer_13_decode(), model_layer_13_decode(), model_layer_14_decode(), model_layer_14_decode(), model_layer_15_decode(), model_layer_15_decode(), model_layer_16_decode(), model_layer_16_decode(), model_layer_17_decode(), model_layer_17_decode(), model_layer_18_decode(), model_layer_18_decode(), model_layer_19_decode(), model_layer_19_decode(), model_layer_1_decode(), model_layer_1_decode(), model_layer_20_decode(), model_layer_20_decode(), model_layer_21_decode(), model_layer_21_decode(), model_layer_22_decode(), model_layer_22_decode(), model_layer_23_decode(), model_layer_23_decode(), model_layer_2_decode(), model_layer_2_decode(), model_layer_3_decode(), model_layer_3_decode(), model_layer_4_decode(), model_layer_4_decode(), model_layer_5_decode(), model_layer_5_decode(), model_layer_6_decode(), model_layer_6_decode(), model_layer_7_decode(), model_layer_7_decode(), model_layer_8_decode(), model_layer_8_decode(), model_layer_9_decode(), model_layer_9_decode(), moe_swiglu_expert_forward_q4k_q4k_workspace(), moe_swiglu_expert_forward_q4k_q5_0_workspace(), moe_swiglu_expert_forward_q4k_q5k_workspace(), moe_swiglu_expert_forward_q4k_q6k_workspace(), moe_swiglu_expert_forward_q4k_q8_0_workspace(), moe_swiglu_shared_forward_q4k_q4k_workspace(), moe_swiglu_shared_forward_q4k_q6k_workspace(), qwen2_0_5b_decode_decode_token(), qwen2_0_5b_decode_decode_token(), qwen2_0_5b_decode_forward_prefill_impl(), qwen2_0_5b_decode_forward_prefill_impl(), qwen2_0_5b_decode_forward_prefill_impl(), qwen2_0_5b_decode_forward_prefill_impl(), qwen2_0_5b_decode_layer_0_decode(), qwen2_0_5b_decode_layer_0_decode(), qwen2_0_5b_decode_layer_10_decode(), qwen2_0_5b_decode_layer_10_decode(), qwen2_0_5b_decode_layer_11_decode(), qwen2_0_5b_decode_layer_11_decode(), qwen2_0_5b_decode_layer_12_decode(), qwen2_0_5b_decode_layer_12_decode(), qwen2_0_5b_decode_layer_13_decode(), qwen2_0_5b_decode_layer_13_decode(), qwen2_0_5b_decode_layer_14_decode(), qwen2_0_5b_decode_layer_14_decode(), qwen2_0_5b_decode_layer_15_decode(), qwen2_0_5b_decode_layer_15_decode(), qwen2_0_5b_decode_layer_16_decode(), qwen2_0_5b_decode_layer_16_decode(), qwen2_0_5b_decode_layer_17_decode(), qwen2_0_5b_decode_layer_17_decode(), qwen2_0_5b_decode_layer_18_decode(), qwen2_0_5b_decode_layer_18_decode(), qwen2_0_5b_decode_layer_19_decode(), qwen2_0_5b_decode_layer_19_decode(), qwen2_0_5b_decode_layer_1_decode(), qwen2_0_5b_decode_layer_1_decode(), qwen2_0_5b_decode_layer_20_decode(), qwen2_0_5b_decode_layer_20_decode(), qwen2_0_5b_decode_layer_21_decode(), qwen2_0_5b_decode_layer_21_decode(), qwen2_0_5b_decode_layer_22_decode(), qwen2_0_5b_decode_layer_22_decode(), qwen2_0_5b_decode_layer_23_decode(), qwen2_0_5b_decode_layer_23_decode(), qwen2_0_5b_decode_layer_2_decode(), qwen2_0_5b_decode_layer_2_decode(), qwen2_0_5b_decode_layer_3_decode(), qwen2_0_5b_decode_layer_3_decode(), qwen2_0_5b_decode_layer_4_decode(), qwen2_0_5b_decode_layer_4_decode(), qwen2_0_5b_decode_layer_5_decode(), qwen2_0_5b_decode_layer_5_decode(), qwen2_0_5b_decode_layer_6_decode(), qwen2_0_5b_decode_layer_6_decode(), qwen2_0_5b_decode_layer_7_decode(), qwen2_0_5b_decode_layer_7_decode(), qwen2_0_5b_decode_layer_8_decode(), qwen2_0_5b_decode_layer_8_decode(), qwen2_0_5b_decode_layer_9_decode(), qwen2_0_5b_decode_layer_9_decode(), swiglu_forward_q8_k(), and unfused_rmsnorm_linear_q4k_ref().

◆ qwen4_ple_gate_conv_inject_bf16()

void qwen4_ple_gate_conv_inject_bf16 ( const float *  hyper_input,
const float *  key_projected,
const float *  value_projected,
const float *  norm_key_weight,
const float *  norm_query_weight,
const float *  norm_conv_weight,
const uint16_t *  conv_weight,
float *  hyper_output,
float *  key_norm_scratch,
float *  query_norm_scratch,
float *  gated_scratch,
float *  conv_norm_scratch,
const float *  conv_state_in,
float *  conv_state_out,
int  rows,
int  streams,
int  hidden_dim,
int  kernel_size,
int  dilation,
float  eps 
)

Definition at line 402 of file qwen4_exp_kernels.c.

410 {
412 hyper_input, key_projected, value_projected, norm_key_weight,
413 norm_query_weight, norm_conv_weight, conv_weight, hyper_output,
414 key_norm_scratch, query_norm_scratch, gated_scratch, conv_norm_scratch,
415 conv_state_in, conv_state_out, rows, streams, hidden_dim, kernel_size,
416 dilation, eps, 0, 0);
417}
static void qwen4_ple_gate_conv_inject_impl(const float *hyper_input, const float *key_projected, const float *value_projected, const float *norm_key_weight, const float *norm_query_weight, const float *norm_conv_weight, const void *conv_weight, float *hyper_output, float *key_norm_scratch, float *query_norm_scratch, float *gated_scratch, float *conv_norm_scratch, const float *conv_state_in, float *conv_state_out, int rows, int streams, int hidden_dim, int kernel_size, int dilation, float eps, int conv_weight_is_fp16, int llama_fp32_arithmetic)

References qwen4_ple_gate_conv_inject_impl().

◆ qwen4_ple_gate_conv_inject_fp16()

void qwen4_ple_gate_conv_inject_fp16 ( const float *  hyper_input,
const float *  key_projected,
const float *  value_projected,
const float *  norm_key_weight,
const float *  norm_query_weight,
const float *  norm_conv_weight,
const uint16_t *  conv_weight,
float *  hyper_output,
float *  key_norm_scratch,
float *  query_norm_scratch,
float *  gated_scratch,
float *  conv_norm_scratch,
const float *  conv_state_in,
float *  conv_state_out,
int  rows,
int  streams,
int  hidden_dim,
int  kernel_size,
int  dilation,
float  eps 
)

Definition at line 419 of file qwen4_exp_kernels.c.

427 {
429 hyper_input, key_projected, value_projected, norm_key_weight,
430 norm_query_weight, norm_conv_weight, conv_weight, hyper_output,
431 key_norm_scratch, query_norm_scratch, gated_scratch, conv_norm_scratch,
432 conv_state_in, conv_state_out, rows, streams, hidden_dim, kernel_size,
433 dilation, eps, 1, 0);
434}

References qwen4_ple_gate_conv_inject_impl().

◆ qwen4_ple_gate_conv_inject_llama_fp16()

void qwen4_ple_gate_conv_inject_llama_fp16 ( const float *  hyper_input,
const float *  key_projected,
const float *  value_projected,
const float *  norm_key_weight,
const float *  norm_query_weight,
const float *  norm_conv_weight,
const uint16_t *  conv_weight,
float *  hyper_output,
float *  key_norm_scratch,
float *  query_norm_scratch,
float *  gated_scratch,
float *  conv_norm_scratch,
const float *  conv_state_in,
float *  conv_state_out,
int  rows,
int  streams,
int  hidden_dim,
int  kernel_size,
int  dilation,
float  eps 
)

Definition at line 436 of file qwen4_exp_kernels.c.

444 {
446 hyper_input, key_projected, value_projected, norm_key_weight,
447 norm_query_weight, norm_conv_weight, conv_weight, hyper_output,
448 key_norm_scratch, query_norm_scratch, gated_scratch, conv_norm_scratch,
449 conv_state_in, conv_state_out, rows, streams, hidden_dim, kernel_size,
450 dilation, eps, 1, 1);
451}

References qwen4_ple_gate_conv_inject_impl().

◆ qwen4_ple_ngram_embed_bf16()

void qwen4_ple_ngram_embed_bf16 ( const int32_t *  token_ids,
const uint16_t *  embedding,
const int64_t *  layer_multipliers,
const int64_t *  head_offsets,
const int64_t *  head_vocab_sizes,
float *  output,
const float *  token_state_in,
float *  token_state_out,
int  rows,
int  ngram_size,
int  heads_per_ngram,
int  head_dim,
int  eos_token_id,
int  position 
)

Definition at line 121 of file qwen4_exp_kernels.c.

134 {
136 token_ids, embedding, layer_multipliers, head_offsets,
137 head_vocab_sizes, output, token_state_in, token_state_out, rows,
138 ngram_size, heads_per_ngram, head_dim, eos_token_id, position_offset, 0);
139}
static void qwen4_ple_ngram_embed_impl(const int32_t *token_ids, const void *embedding, const int64_t *layer_multipliers, const int64_t *head_offsets, const int64_t *head_vocab_sizes, float *output, const float *token_state_in, float *token_state_out, int rows, int ngram_size, int heads_per_ngram, int head_dim, int eos_token_id, int position_offset, int embedding_is_q5_0)

References qwen4_ple_ngram_embed_impl().

◆ qwen4_ple_ngram_embed_q5_0()

void qwen4_ple_ngram_embed_q5_0 ( const int32_t *  token_ids,
const void *  embedding,
const int64_t *  layer_multipliers,
const int64_t *  head_offsets,
const int64_t *  head_vocab_sizes,
float *  output,
const float *  token_state_in,
float *  token_state_out,
int  rows,
int  ngram_size,
int  heads_per_ngram,
int  head_dim,
int  eos_token_id,
int  position 
)

Definition at line 141 of file qwen4_exp_kernels.c.

154 {
156 token_ids, embedding, layer_multipliers, head_offsets,
157 head_vocab_sizes, output, token_state_in, token_state_out, rows,
158 ngram_size, heads_per_ngram, head_dim, eos_token_id, position_offset, 1);
159}

References qwen4_ple_ngram_embed_impl().

◆ qwen4_qsa_index_select_bf16()

void qwen4_qsa_index_select_bf16 ( const float *  projected_qk,
const float *  index_key_cache_in,
const float *  q_norm_weight,
const float *  k_norm_weight,
float *  selected_indices,
float *  index_key_cache_out,
float *  q_norm_scratch,
float *  pooled_key_scratch,
float *  block_score_scratch,
int32_t *  block_index_scratch,
int  rows,
int  query_heads,
int  index_head_dim,
int  token_budget,
int  compress_ratio,
int  rotary_dim,
int  context_length,
int  position,
float  rope_theta,
float  eps 
)

Definition at line 488 of file qwen4_exp_kernels.c.

508 {
509 if (!projected_qk || !index_key_cache_in || !q_norm_weight || !k_norm_weight ||
510 !selected_indices || !index_key_cache_out || !q_norm_scratch ||
511 !pooled_key_scratch || !block_score_scratch || !block_index_scratch ||
512 rows <= 0 || query_heads <= 0 || index_head_dim <= 0 || token_budget <= 0 ||
513 compress_ratio <= 0 || rotary_dim <= 0 || rotary_dim > index_head_dim ||
514 context_length <= 0 || position < 0 || rows > context_length - position) return;
515
516 const int projected_dim = (query_heads + 1) * index_head_dim;
517 const int selection_width = token_budget + compress_ratio - 1;
518 const int block_topk = token_budget / compress_ratio;
519 if (index_key_cache_out != index_key_cache_in && position > 0) {
520 memcpy(index_key_cache_out, index_key_cache_in,
521 (size_t)position * index_head_dim * sizeof(*index_key_cache_out));
522 }
523
524 for (int row = 0; row < rows; ++row) {
525 const int absolute_position = position + row;
526 const float *projected = projected_qk + (size_t)row * projected_dim;
527 float *query_normed = q_norm_scratch;
528 qwen4_shared_head_rmsnorm(projected, q_norm_weight, query_normed,
529 query_heads, index_head_dim, eps);
530 for (int head = 0; head < query_heads; ++head) {
531 qwen4_rope_split_inplace(query_normed + (size_t)head * index_head_dim,
532 rotary_dim, absolute_position, rope_theta);
533 }
534 float *raw_key = index_key_cache_out + (size_t)absolute_position * index_head_dim;
535 const float *projected_key = projected + (size_t)query_heads * index_head_dim;
536 for (int col = 0; col < index_head_dim; ++col) {
537 raw_key[col] = qwen4_bf16_round(projected_key[col]);
538 }
539
540 float *selected_row = selected_indices + (size_t)row * selection_width;
541 for (int slot = 0; slot < selection_width; ++slot) selected_row[slot] = -1.0f;
542 const int visible = absolute_position + 1;
543 const int complete_blocks = visible / compress_ratio;
544 const int selected_blocks = complete_blocks < block_topk ? complete_blocks : block_topk;
545 for (int slot = 0; slot < selected_blocks; ++slot) {
546 block_score_scratch[slot] = -INFINITY;
547 block_index_scratch[slot] = -1;
548 }
549
550 for (int block = 0; block < complete_blocks; ++block) {
551 const int block_start = block * compress_ratio;
552 for (int col = 0; col < index_head_dim; ++col) {
553 float sum = 0.0f;
554 for (int token = 0; token < compress_ratio; ++token) {
555 sum += index_key_cache_out[
556 (size_t)(block_start + token) * index_head_dim + col];
557 }
558 pooled_key_scratch[col] = qwen4_bf16_round(sum / (float)compress_ratio);
559 }
560 qwen4_shared_head_rmsnorm(pooled_key_scratch, k_norm_weight,
561 pooled_key_scratch, 1, index_head_dim, eps);
562 qwen4_rope_split_inplace(pooled_key_scratch, rotary_dim, block_start, rope_theta);
563 float score = 0.0f;
564 for (int head = 0; head < query_heads; ++head) {
565 const float *query_head = query_normed + (size_t)head * index_head_dim;
566 float dot = 0.0f;
567 for (int col = 0; col < index_head_dim; ++col) {
568 dot += query_head[col] * pooled_key_scratch[col];
569 }
570 if (dot > 0.0f) score += dot;
571 }
572 score /= sqrtf((float)index_head_dim);
573 int target = -1;
574 for (int slot = 0; slot < selected_blocks; ++slot) {
575 if (target < 0 || block_score_scratch[slot] < block_score_scratch[target]) target = slot;
576 }
577 if (target >= 0 && score > block_score_scratch[target]) {
578 block_score_scratch[target] = score;
579 block_index_scratch[target] = block;
580 }
581 }
582
583 for (int outer = 1; outer < selected_blocks; ++outer) {
584 const int32_t value = block_index_scratch[outer];
585 int inner = outer - 1;
586 while (inner >= 0 && block_index_scratch[inner] > value) {
587 block_index_scratch[inner + 1] = block_index_scratch[inner];
588 --inner;
589 }
590 block_index_scratch[inner + 1] = value;
591 }
592 int output_count = 0;
593 for (int slot = 0; slot < selected_blocks; ++slot) {
594 const int block = block_index_scratch[slot];
595 if (block < 0) continue;
596 for (int token = 0; token < compress_ratio; ++token) {
597 selected_row[output_count++] = (float)(block * compress_ratio + token);
598 }
599 }
600 for (int token = complete_blocks * compress_ratio;
601 token < visible && output_count < selection_width; ++token) {
602 selected_row[output_count++] = (float)token;
603 }
604 }
605}
static float qwen4_bf16_round(float value)
static void qwen4_rope_split_inplace(float *vector, int rotary_dim, int position, float theta)
static void qwen4_shared_head_rmsnorm(const float *input, const float *weight, float *output, int heads, int head_dim, float eps)

References qwen4_bf16_round(), qwen4_rope_split_inplace(), qwen4_shared_head_rmsnorm(), score, and token.

◆ recurrent_conv_state_update_backward()

void recurrent_conv_state_update_backward ( const float *  d_conv_x,
const float *  d_state_out,
float *  d_state_in,
float *  d_q,
float *  d_k,
float *  d_v,
int  history_len,
int  num_seqs,
int  num_tokens,
int  q_dim,
int  k_dim,
int  v_dim 
)

Definition at line 160 of file recurrent_state_kernels.c.

171 {
172 int channels = 0;
173 int total_len = 0;
174 size_t elements = 0;
176 history_len, num_seqs, num_tokens, q_dim, k_dim, v_dim,
177 &channels, &total_len, &elements) ||
178 elements > SIZE_MAX / sizeof(float)) {
179 return;
180 }
181 (void)channels;
182 (void)total_len;
183 float *workspace = (float *)malloc(elements * sizeof(float));
184 if (!workspace) {
185 return;
186 }
188 d_conv_x, d_state_out, d_state_in, d_q, d_k, d_v, workspace,
189 history_len, num_seqs, num_tokens, q_dim, k_dim, v_dim);
190 free(workspace);
191}
static int recurrent_conv_backward_extents(int history_len, int num_seqs, int num_tokens, int q_dim, int k_dim, int v_dim, int *channels_out, int *total_len_out, size_t *elements_out)
void recurrent_conv_state_update_backward_workspace(const float *d_conv_x, const float *d_state_out, float *d_state_in, float *d_q, float *d_k, float *d_v, float *d_conv_total, int history_len, int num_seqs, int num_tokens, int q_dim, int k_dim, int v_dim)

References recurrent_conv_backward_extents(), and recurrent_conv_state_update_backward_workspace().

◆ recurrent_conv_state_update_backward_workspace()

void recurrent_conv_state_update_backward_workspace ( const float *  d_conv_x,
const float *  d_state_out,
float *  d_state_in,
float *  d_q,
float *  d_k,
float *  d_v,
float *  d_conv_total,
int  history_len,
int  num_seqs,
int  num_tokens,
int  q_dim,
int  k_dim,
int  v_dim 
)

Definition at line 91 of file recurrent_state_kernels.c.

103 {
104 int channels = 0;
105 int total_len = 0;
106 size_t elements = 0;
107 if (!d_conv_x || !d_state_out || !d_state_in || !d_q || !d_k || !d_v ||
108 !d_conv_total || !recurrent_conv_backward_extents(
109 history_len, num_seqs, num_tokens, q_dim, k_dim, v_dim,
110 &channels, &total_len, &elements)) {
111 return;
112 }
113 if (elements > SIZE_MAX / sizeof(float)) {
114 return;
115 }
116
117 memcpy(d_conv_total, d_conv_x, elements * sizeof(float));
118
119 for (int seq = 0; seq < num_seqs; ++seq) {
120 const float *d_state_out_seq = d_state_out + (size_t) seq * (size_t) channels * (size_t) history_len;
121 float *d_conv_seq = d_conv_total + (size_t) seq * (size_t) channels * (size_t) total_len;
122 for (int ch = 0; ch < channels; ++ch) {
123 float *dst = d_conv_seq + (size_t) ch * (size_t) total_len + (size_t) num_tokens;
124 const float *src = d_state_out_seq + (size_t) ch * (size_t) history_len;
125 for (int idx = 0; idx < history_len; ++idx) {
126 dst[idx] += src[idx];
127 }
128 }
129 }
130
131 for (int seq = 0; seq < num_seqs; ++seq) {
132 const float *d_conv_seq = d_conv_total + (size_t) seq * (size_t) channels * (size_t) total_len;
133 float *d_state_in_seq = d_state_in + (size_t) seq * (size_t) channels * (size_t) history_len;
134
135 for (int ch = 0; ch < channels; ++ch) {
136 memcpy(
137 d_state_in_seq + (size_t) ch * (size_t) history_len,
138 d_conv_seq + (size_t) ch * (size_t) total_len,
139 (size_t) history_len * sizeof(float));
140 }
141
142 for (int tok = 0; tok < num_tokens; ++tok) {
143 const int row = seq * num_tokens + tok;
144 float *d_q_row = d_q + (size_t) row * (size_t) q_dim;
145 float *d_k_row = d_k + (size_t) row * (size_t) k_dim;
146 float *d_v_row = d_v + (size_t) row * (size_t) v_dim;
147 for (int col = 0; col < q_dim; ++col) {
148 d_q_row[col] = d_conv_seq[(size_t) col * (size_t) total_len + (size_t) (history_len + tok)];
149 }
150 for (int col = 0; col < k_dim; ++col) {
151 d_k_row[col] = d_conv_seq[(size_t) (q_dim + col) * (size_t) total_len + (size_t) (history_len + tok)];
152 }
153 for (int col = 0; col < v_dim; ++col) {
154 d_v_row[col] = d_conv_seq[(size_t) (q_dim + k_dim + col) * (size_t) total_len + (size_t) (history_len + tok)];
155 }
156 }
157 }
158}

References recurrent_conv_backward_extents().

Referenced by recurrent_conv_state_update_backward().

◆ recurrent_conv_state_update_forward()

void recurrent_conv_state_update_forward ( const float *  state_in,
const float *  q,
const float *  k,
const float *  v,
float *  conv_x,
float *  state_out,
int  history_len,
int  num_seqs,
int  num_tokens,
int  q_dim,
int  k_dim,
int  v_dim 
)

Definition at line 8 of file recurrent_state_kernels.c.

19 {
20 const int channels = q_dim + k_dim + v_dim;
21 const int total_len = history_len + num_tokens;
22 for (int seq = 0; seq < num_seqs; ++seq) {
23 const float *state_seq = state_in + (size_t) seq * (size_t) channels * (size_t) history_len;
24 float *conv_seq = conv_x + (size_t) seq * (size_t) channels * (size_t) total_len;
25 float *state_out_seq = state_out + (size_t) seq * (size_t) channels * (size_t) history_len;
26 for (int ch = 0; ch < channels; ++ch) {
27 memcpy(
28 conv_seq + (size_t) ch * (size_t) total_len,
29 state_seq + (size_t) ch * (size_t) history_len,
30 (size_t) history_len * sizeof(float));
31 }
32
33 for (int tok = 0; tok < num_tokens; ++tok) {
34 const int row = seq * num_tokens + tok;
35 const float *q_row = q + (size_t) row * (size_t) q_dim;
36 const float *k_row = k + (size_t) row * (size_t) k_dim;
37 const float *v_row = v + (size_t) row * (size_t) v_dim;
38 for (int col = 0; col < q_dim; ++col) {
39 conv_seq[(size_t) col * (size_t) total_len + (size_t) (history_len + tok)] = q_row[col];
40 }
41 for (int col = 0; col < k_dim; ++col) {
42 conv_seq[(size_t) (q_dim + col) * (size_t) total_len + (size_t) (history_len + tok)] = k_row[col];
43 }
44 for (int col = 0; col < v_dim; ++col) {
45 conv_seq[(size_t) (q_dim + k_dim + col) * (size_t) total_len + (size_t) (history_len + tok)] = v_row[col];
46 }
47 }
48
49 for (int ch = 0; ch < channels; ++ch) {
50 memcpy(
51 state_out_seq + (size_t) ch * (size_t) history_len,
52 conv_seq + (size_t) ch * (size_t) total_len + (size_t) num_tokens,
53 (size_t) history_len * sizeof(float));
54 }
55 }
56}

◆ recurrent_dt_gate_backward()

void recurrent_dt_gate_backward ( const float *  d_gate,
const float *  alpha,
const float *  dt_bias,
const float *  a,
float *  d_alpha,
float *  d_dt_bias,
float *  d_a,
int  rows,
int  dim 
)

Definition at line 104 of file recurrent_gate_kernels.c.

112 {
113 for (int col = 0; col < dim; ++col) {
114 d_dt_bias[col] = 0.0f;
115 d_a[col] = 0.0f;
116 }
117
118 for (int row = 0; row < rows; ++row) {
119 const float *d_gate_row = d_gate + (size_t) row * (size_t) dim;
120 const float *alpha_row = alpha + (size_t) row * (size_t) dim;
121 float *d_alpha_row = d_alpha + (size_t) row * (size_t) dim;
122 for (int col = 0; col < dim; ++col) {
123 const float x = alpha_row[col] + dt_bias[col];
124 const float sp = recurrent_softplus(x);
125 const float sig = recurrent_sigmoid(x);
126 const float d_out = d_gate_row[col];
127 d_a[col] += d_out * sp;
128 {
129 const float d_x = d_out * a[col] * sig;
130 d_alpha_row[col] = d_x;
131 d_dt_bias[col] += d_x;
132 }
133 }
134 }
135}
static float recurrent_softplus(float x)
static float recurrent_sigmoid(float x)

References recurrent_sigmoid(), and recurrent_softplus().

◆ recurrent_dt_gate_expanded_forward()

void recurrent_dt_gate_expanded_forward ( const float *  alpha,
const float *  dt_bias,
const float *  a,
float *  gate,
int  rows,
int  num_heads,
int  state_dim 
)

Definition at line 83 of file recurrent_gate_kernels.c.

89 {
90 for (int row = 0; row < rows; ++row) {
91 const float *alpha_row = alpha + (size_t) row * (size_t) num_heads;
92 float *gate_row = gate + (size_t) row * (size_t) num_heads * (size_t) state_dim;
93 for (int h = 0; h < num_heads; ++h) {
94 const float sp = recurrent_softplus(alpha_row[h] + dt_bias[h]);
95 const float *a_head = a + (size_t) h * (size_t) state_dim;
96 float *gate_head = gate_row + (size_t) h * (size_t) state_dim;
97 for (int col = 0; col < state_dim; ++col) {
98 gate_head[col] = sp * a_head[col];
99 }
100 }
101 }
102}

References recurrent_softplus().

◆ recurrent_dt_gate_forward()

void recurrent_dt_gate_forward ( const float *  alpha,
const float *  dt_bias,
const float *  a,
float *  gate,
int  rows,
int  num_heads,
int  state_dim 
)

Definition at line 65 of file recurrent_gate_kernels.c.

71 {
72 const int dim = num_heads * state_dim;
73 for (int row = 0; row < rows; ++row) {
74 const float *alpha_row = alpha + (size_t) row * (size_t) dim;
75 float *gate_row = gate + (size_t) row * (size_t) dim;
76 for (int col = 0; col < dim; ++col) {
77 const float x = alpha_row[col] + dt_bias[col];
78 gate_row[col] = recurrent_softplus(x) * a[col];
79 }
80 }
81}

References recurrent_softplus().

◆ recurrent_dt_gate_forward_pytorch_fp32()

void recurrent_dt_gate_forward_pytorch_fp32 ( const float *  alpha,
const float *  dt_bias,
const float *  a,
float *  gate,
int  rows,
int  num_heads,
int  state_dim 
)

Definition at line 179 of file recurrent_gate_kernels.c.

186{
187 if (!alpha || !dt_bias || !a || !gate || rows < 0 || num_heads < 0 || state_dim != 1) {
188 fprintf(stderr,
189 "HARD KERNEL CONTRACT FAULT: invalid PyTorch FP32 recurrent dt-gate arguments\n");
190 abort();
191 }
192#if defined(__AVX512F__)
193 pthread_once(&ck_recurrent_sleef_once, ck_bind_recurrent_pytorch_sleef);
194 if (!ck_recurrent_pytorch_expf16 || !ck_recurrent_pytorch_log1pf16) {
195 fprintf(stderr,
196 "HARD KERNEL CONTRACT FAULT: PyTorch FP32 recurrent dt gate requires "
197 "SLEEF Sleef_expf16_u10 and Sleef_log1pf16_u10; set CK_SLEEF_LIBRARY\n");
198 abort();
199 }
200 if ((num_heads & 15) != 0) {
201 fprintf(stderr,
202 "HARD KERNEL CONTRACT FAULT: PyTorch AVX-512 recurrent dt gate requires "
203 "a head count divisible by 16 (got %d)\n",
204 num_heads);
205 abort();
206 }
209 fprintf(stderr,
210 "HARD KERNEL CONTRACT FAULT: PyTorch FP32 recurrent dt gate requires "
211 "log1pf from libm.so.6\n");
212 abort();
213 }
214 const __m512 threshold = _mm512_set1_ps(20.0f);
215 const int count = rows * num_heads;
216 int index = 0;
217 for (; index + 32 <= count; index += 32) {
218 for (int half = 0; half < 2; ++half) {
219 float x_lanes[16] __attribute__((aligned(64)));
220 float a_lanes[16] __attribute__((aligned(64)));
221 const int base = index + half * 16;
222 for (int lane = 0; lane < 16; ++lane) {
223 const int head = (base + lane) % num_heads;
224 x_lanes[lane] = alpha[base + lane] + dt_bias[head];
225 a_lanes[lane] = a[head];
226 }
227 const __m512 x = _mm512_load_ps(x_lanes);
228 const __m512 softplus = _mm512_mask_blend_ps(
229 _mm512_cmp_ps_mask(x, threshold, _CMP_GT_OQ),
230 ck_recurrent_pytorch_log1pf16(ck_recurrent_pytorch_expf16(x)),
231 x);
232 _mm512_storeu_ps(
233 gate + base,
234 _mm512_mul_ps(softplus, _mm512_load_ps(a_lanes)));
235 }
236 }
237 for (; index < count; ++index) {
238 const int head = index % num_heads;
239 const float x = alpha[index] + dt_bias[head];
240 const float softplus = x > 20.0f
241 ? x
243 gate[index] = softplus * a[head];
244 }
245#else
246 fprintf(stderr,
247 "HARD KERNEL CONTRACT FAULT: PyTorch FP32 recurrent dt gate requires AVX-512\n");
248 abort();
249#endif
250}
static ck_recurrent_libm_f32_fn ck_recurrent_pytorch_log1pf
static void ck_bind_recurrent_llama_libm(void)
static ck_recurrent_libm_f32_fn ck_recurrent_llama_expf
static pthread_once_t ck_recurrent_libm_once

References __attribute__(), ck_bind_recurrent_llama_libm(), ck_recurrent_libm_once, ck_recurrent_llama_expf, and ck_recurrent_pytorch_log1pf.

◆ recurrent_norm_gate_backward()

void recurrent_norm_gate_backward ( const float *  d_out,
const float *  x,
const float *  gate,
const float *  weight,
float *  d_x,
float *  d_gate,
float *  d_weight,
int  rows,
int  num_heads,
int  head_dim,
float  eps 
)

Definition at line 182 of file recurrent_norm_kernels.c.

192 {
193 const int inner_dim = num_heads * head_dim;
194 memset(d_weight, 0, (size_t) head_dim * sizeof(float));
195
196 for (int row = 0; row < rows; ++row) {
197 const float *d_out_row = d_out + (size_t) row * (size_t) inner_dim;
198 const float *x_row = x + (size_t) row * (size_t) inner_dim;
199 const float *gate_row = gate + (size_t) row * (size_t) inner_dim;
200 float *d_x_row = d_x + (size_t) row * (size_t) inner_dim;
201 float *d_gate_row = d_gate + (size_t) row * (size_t) inner_dim;
202
203 for (int head = 0; head < num_heads; ++head) {
204 const float *x_head = x_row + (size_t) head * (size_t) head_dim;
205 const float *gate_head = gate_row + (size_t) head * (size_t) head_dim;
206 const float *d_out_head = d_out_row + (size_t) head * (size_t) head_dim;
207 float *d_x_head = d_x_row + (size_t) head * (size_t) head_dim;
208 float *d_gate_head = d_gate_row + (size_t) head * (size_t) head_dim;
209
210 float ms = 0.0f;
211 for (int col = 0; col < head_dim; ++col) {
212 ms += x_head[col] * x_head[col];
213 }
214 ms /= (float) head_dim;
215 const float inv_rms = 1.0f / sqrtf(ms + eps);
216 const float inv_rms3_over_dim = (inv_rms * inv_rms * inv_rms) / (float) head_dim;
217
218 float dot = 0.0f;
219 for (int col = 0; col < head_dim; ++col) {
220 const float g = gate_head[col];
221 const float sig = recurrent_sigmoid_local(g);
222 const float silu = g * sig;
223 dot += d_out_head[col] * weight[col] * silu * x_head[col];
224 }
225
226 for (int col = 0; col < head_dim; ++col) {
227 const float g = gate_head[col];
228 const float sig = recurrent_sigmoid_local(g);
229 const float silu = g * sig;
230 const float scaled = inv_rms * weight[col] * silu;
231 d_x_head[col] = d_out_head[col] * scaled - x_head[col] * inv_rms3_over_dim * dot;
232 d_weight[col] += d_out_head[col] * (x_head[col] * inv_rms) * silu;
233 d_gate_head[col] = d_out_head[col] * (x_head[col] * inv_rms * weight[col]) *
234 (sig + g * sig * (1.0f - sig));
235 }
236 }
237 }
238}
static float recurrent_sigmoid_local(float x)

References recurrent_sigmoid_local(), and silu().

◆ recurrent_norm_gate_forward()

void recurrent_norm_gate_forward ( const float *  x,
const float *  gate,
const float *  weight,
float *  out,
int  rows,
int  num_heads,
int  head_dim,
float  eps 
)

Definition at line 18 of file recurrent_norm_kernels.c.

25 {
26 const int inner_dim = num_heads * head_dim;
27 for (int row = 0; row < rows; ++row) {
28 const float *x_row = x + (size_t) row * (size_t) inner_dim;
29 const float *gate_row = gate + (size_t) row * (size_t) inner_dim;
30 float *out_row = out + (size_t) row * (size_t) inner_dim;
31
32 for (int head = 0; head < num_heads; ++head) {
33 const float *x_head = x_row + (size_t) head * (size_t) head_dim;
34 const float *gate_head = gate_row + (size_t) head * (size_t) head_dim;
35 float *out_head = out_row + (size_t) head * (size_t) head_dim;
36
37 float ms = 0.0f;
38 for (int col = 0; col < head_dim; ++col) {
39 ms += x_head[col] * x_head[col];
40 }
41 ms /= (float) head_dim;
42 const float inv_rms = 1.0f / sqrtf(ms + eps);
43
44 for (int col = 0; col < head_dim; ++col) {
45 const float g = gate_head[col];
46 const float silu = g * recurrent_sigmoid_local(g);
47 out_head[col] = x_head[col] * inv_rms * weight[col] * silu;
48 }
49 }
50 }
51}

References recurrent_sigmoid_local(), and silu().

◆ recurrent_norm_gate_llama_avx2_forward()

void recurrent_norm_gate_llama_avx2_forward ( const float *  x,
const float *  gate,
const float *  weight,
float *  out,
int  rows,
int  num_heads,
int  head_dim,
float  eps 
)

Definition at line 53 of file recurrent_norm_kernels.c.

60 {
61 if (!x || !gate || !weight || !out || rows <= 0 || num_heads <= 0 ||
62 head_dim <= 0 || head_dim > 4096) {
63 return;
64 }
65 const int inner_dim = num_heads * head_dim;
66 float normalized[4096];
67 float silu[4096];
68 for (int row = 0; row < rows; ++row) {
69 for (int head = 0; head < num_heads; ++head) {
70 const size_t offset = (size_t) row * (size_t) inner_dim
71 + (size_t) head * (size_t) head_dim;
73 x + offset, weight, normalized, NULL, 1, head_dim, head_dim, eps);
74 recurrent_silu_forward_ggml(gate + offset, silu, 1, head_dim);
75 for (int col = 0; col < head_dim; ++col) {
76 out[offset + (size_t) col] = normalized[col] * silu[col];
77 }
78 }
79 }
80}
void rmsnorm_forward_llama_production(const float *input, const float *gamma, float *output, float *rstd_cache, int tokens, int d_model, int aligned_embed_dim, float eps)
void recurrent_silu_forward_ggml(const float *x, float *out, int rows, int dim)

References recurrent_silu_forward_ggml(), rmsnorm_forward_llama_production(), and silu().

◆ recurrent_norm_gate_pytorch_bf16_storage()

void recurrent_norm_gate_pytorch_bf16_storage ( const float *  x,
const float *  gate,
const float *  weight,
float *  out,
int  rows,
int  num_heads,
int  head_dim,
float  eps 
)

Definition at line 111 of file recurrent_norm_kernels.c.

119{
120 if (!x || !gate || !weight || !out || rows <= 0 || num_heads <= 0 ||
121 head_dim <= 0 || head_dim > 4096) {
122 return;
123 }
124 const int inner_dim = num_heads * head_dim;
125 float normalized[4096];
126 float silu[4096];
127 for (int row = 0; row < rows; ++row) {
128 for (int head = 0; head < num_heads; ++head) {
129 const size_t offset = (size_t)row * (size_t)inner_dim +
130 (size_t)head * (size_t)head_dim;
131 /*
132 * Qwen3Next order:
133 * FP32 RMS statistics -> BF16 normalized value -> BF16 weight
134 * multiply -> FP32 SiLU(gate) -> BF16 final output.
135 */
137 x + offset, weight, normalized, NULL,
138 1, head_dim, head_dim, eps);
140 gate + offset, silu, 1, head_dim);
141 for (int col = 0; col < head_dim; ++col) {
142 out[offset + (size_t)col] = bf16_to_float(float_to_bf16(
143 normalized[col] * silu[col]));
144 }
145 }
146 }
147}
void recurrent_silu_forward_pytorch_bf16_input_fp32_output(const float *x, float *out, int rows, int dim)
void rmsnorm_forward_pytorch_bf16_storage(const float *input, const float *gamma, float *output, float *rstd_cache, int tokens, int d_model, int aligned_embed_dim, float eps)

References bf16_to_float(), float_to_bf16(), recurrent_silu_forward_pytorch_bf16_input_fp32_output(), rmsnorm_forward_pytorch_bf16_storage(), and silu().

◆ recurrent_norm_sigmoid_gate_llama_avx2_forward()

void recurrent_norm_sigmoid_gate_llama_avx2_forward ( const float *  x,
const float *  gate,
const float *  weight,
float *  out,
int  rows,
int  num_heads,
int  head_dim,
float  eps 
)

Definition at line 82 of file recurrent_norm_kernels.c.

89 {
90 if (!x || !gate || !weight || !out || rows <= 0 || num_heads <= 0 ||
91 head_dim <= 0 || head_dim > 4096) {
92 return;
93 }
94 const int inner_dim = num_heads * head_dim;
95 float normalized[4096];
96 float sigmoid[4096];
97 for (int row = 0; row < rows; ++row) {
98 for (int head = 0; head < num_heads; ++head) {
99 const size_t offset = (size_t) row * (size_t) inner_dim
100 + (size_t) head * (size_t) head_dim;
102 x + offset, weight, normalized, NULL, 1, head_dim, head_dim, eps);
103 recurrent_sigmoid_forward_ggml(gate + offset, sigmoid, 1, head_dim);
104 for (int col = 0; col < head_dim; ++col) {
105 out[offset + (size_t) col] = normalized[col] * sigmoid[col];
106 }
107 }
108 }
109}
void recurrent_sigmoid_forward_ggml(const float *x, float *out, int rows, int dim)

References recurrent_sigmoid_forward_ggml(), and rmsnorm_forward_llama_production().

◆ recurrent_norm_sigmoid_gate_pytorch_bf16_storage()

void recurrent_norm_sigmoid_gate_pytorch_bf16_storage ( const float *  x,
const float *  gate,
const float *  weight,
float *  out,
int  rows,
int  num_heads,
int  head_dim,
float  eps 
)

Definition at line 149 of file recurrent_norm_kernels.c.

157{
158 if (!x || !gate || !weight || !out || rows <= 0 || num_heads <= 0 ||
159 head_dim <= 0 || head_dim > 4096) {
160 return;
161 }
162 const int inner_dim = num_heads * head_dim;
163 float normalized[4096];
164 float sigmoid[4096];
165 for (int row = 0; row < rows; ++row) {
166 for (int head = 0; head < num_heads; ++head) {
167 const size_t offset = (size_t)row * (size_t)inner_dim +
168 (size_t)head * (size_t)head_dim;
170 x + offset, weight, normalized, NULL,
171 1, head_dim, head_dim, eps);
173 gate + offset, sigmoid, 1, head_dim);
174 for (int col = 0; col < head_dim; ++col) {
175 out[offset + (size_t)col] = bf16_to_float(float_to_bf16(
176 normalized[col] * sigmoid[col]));
177 }
178 }
179 }
180}

References bf16_to_float(), float_to_bf16(), recurrent_sigmoid_forward_pytorch_bf16_input_fp32_output(), and rmsnorm_forward_pytorch_bf16_storage().

◆ recurrent_qk_l2_norm_backward()

void recurrent_qk_l2_norm_backward ( const float *  d_q_out,
const float *  d_k_out,
const float *  q,
const float *  k,
float *  d_q,
float *  d_k,
int  rows,
int  q_dim,
int  k_dim,
int  head_dim,
float  eps 
)

Definition at line 383 of file recurrent_qk_norm_kernels.c.

393 {
394 recurrent_l2_norm_rows_backward_one(d_q_out, q, d_q, rows, q_dim, head_dim, eps);
395 recurrent_l2_norm_rows_backward_one(d_k_out, k, d_k, rows, k_dim, head_dim, eps);
396}
static void recurrent_l2_norm_rows_backward_one(const float *d_out, const float *x, float *d_x, int rows, int dim, int head_dim, float eps)

References recurrent_l2_norm_rows_backward_one().

◆ recurrent_qk_l2_norm_forward()

void recurrent_qk_l2_norm_forward ( float *  q,
float *  k,
int  rows,
int  q_dim,
int  k_dim,
int  head_dim,
float  eps 
)

Definition at line 86 of file recurrent_qk_norm_kernels.c.

92 {
93 recurrent_l2_norm_rows_forward_one(q, rows, q_dim, head_dim, eps);
94 recurrent_l2_norm_rows_forward_one(k, rows, k_dim, head_dim, eps);
95}
static void recurrent_l2_norm_rows_forward_one(float *x, int rows, int dim, int head_dim, float eps)

References recurrent_l2_norm_rows_forward_one().

◆ recurrent_qk_l2_norm_pytorch_bf16_storage()

void recurrent_qk_l2_norm_pytorch_bf16_storage ( float *  q,
float *  k,
int  rows,
int  q_dim,
int  k_dim,
int  expanded_heads,
int  head_dim,
float  eps 
)

Definition at line 368 of file recurrent_qk_norm_kernels.c.

376{
378 q, rows, q_dim, expanded_heads, head_dim, eps);
380 k, rows, k_dim, expanded_heads, head_dim, eps);
381}
static void recurrent_pytorch_bf16_l2_rows(float *x, int rows, int dim, int expanded_heads, int head_dim, float eps)

References recurrent_pytorch_bf16_l2_rows().

◆ recurrent_qk_l2_norm_pytorch_fp32_output()

void recurrent_qk_l2_norm_pytorch_fp32_output ( float *  q,
float *  k,
int  rows,
int  q_dim,
int  k_dim,
int  head_dim,
float  eps 
)

Definition at line 246 of file recurrent_qk_norm_kernels.c.

253{
254 recurrent_pytorch_fp32_l2_rows(q, rows, q_dim, head_dim, eps);
255 recurrent_pytorch_fp32_l2_rows(k, rows, k_dim, head_dim, eps);
256}
static void recurrent_pytorch_fp32_l2_rows(float *x, int rows, int dim, int head_dim, float eps)

References recurrent_pytorch_fp32_l2_rows().

◆ recurrent_sigmoid_forward_ggml()

void recurrent_sigmoid_forward_ggml ( const float *  x,
float *  out,
int  rows,
int  dim 
)

Definition at line 501 of file recurrent_gate_kernels.c.

504 {
505 float (*volatile llama_expf)(float) = expf;
506 for (int row = 0; row < rows; ++row) {
507 const float *x_row = x + (size_t) row * (size_t) dim;
508 float *out_row = out + (size_t) row * (size_t) dim;
509 for (int col = 0; col < dim; ++col) {
510 out_row[col] = 1.0f / (1.0f + llama_expf(-x_row[col]));
511 }
512 }
513}

Referenced by hyper_connection_mix_quantized(), and recurrent_norm_sigmoid_gate_llama_avx2_forward().

◆ recurrent_sigmoid_forward_pytorch_bf16_input_fp32_output()

void recurrent_sigmoid_forward_pytorch_bf16_input_fp32_output ( const float *  x,
float *  out,
int  rows,
int  dim 
)

Definition at line 339 of file recurrent_gate_kernels.c.

344{
345 if (!x || !out || rows < 0 || dim < 0) {
346 fprintf(stderr, "HARD KERNEL CONTRACT FAULT: invalid BF16-input FP32-output sigmoid arguments\n");
347 abort();
348 }
349#if defined(__AVX512F__)
350 pthread_once(&ck_recurrent_sleef_once, ck_bind_recurrent_pytorch_sleef);
351 if (!ck_recurrent_pytorch_expf16) {
352 fprintf(stderr,
353 "HARD KERNEL CONTRACT FAULT: PyTorch BF16-input sigmoid requires "
354 "SLEEF Sleef_expf16_u10; set CK_SLEEF_LIBRARY\n");
355 abort();
356 }
357#endif
358 const int count = rows * dim;
359 int i = 0;
360#if defined(__AVX512F__)
361 for (; i + 16 <= count; i += 16) {
362 float lanes[16] __attribute__((aligned(64)));
363 for (int lane = 0; lane < 16; ++lane) {
364 lanes[lane] = bf16_to_float(float_to_bf16(x[i + lane]));
365 }
366 const __m512 values = _mm512_load_ps(lanes);
367 const __m512 denominator = _mm512_add_ps(
368 _mm512_set1_ps(1.0f),
369 ck_recurrent_pytorch_expf16(
370 _mm512_sub_ps(_mm512_setzero_ps(), values)));
371 _mm512_storeu_ps(out + i,
372 _mm512_div_ps(_mm512_set1_ps(1.0f), denominator));
373 }
374#endif
375 for (; i < count; ++i) {
376 const float value = bf16_to_float(float_to_bf16(x[i]));
377 out[i] = 1.0f / (1.0f + expf(-value));
378 }
379}

References __attribute__(), bf16_to_float(), and float_to_bf16().

Referenced by attn_gate_sigmoid_mul_pytorch_bf16_storage(), and recurrent_norm_sigmoid_gate_pytorch_bf16_storage().

◆ recurrent_silu_backward()

void recurrent_silu_backward ( const float *  d_out,
const float *  x,
float *  d_x,
int  rows,
int  dim 
)

Definition at line 515 of file recurrent_gate_kernels.c.

519 {
520 for (int row = 0; row < rows; ++row) {
521 const float *d_out_row = d_out + (size_t) row * (size_t) dim;
522 const float *x_row = x + (size_t) row * (size_t) dim;
523 float *d_x_row = d_x + (size_t) row * (size_t) dim;
524 for (int col = 0; col < dim; ++col) {
525 const float xv = x_row[col];
526 const float sig = recurrent_sigmoid(xv);
527 d_x_row[col] = d_out_row[col] * (sig + xv * sig * (1.0f - sig));
528 }
529 }
530}

References recurrent_sigmoid().

◆ recurrent_silu_forward()

void recurrent_silu_forward ( const float *  x,
float *  out,
int  rows,
int  dim 
)

Definition at line 137 of file recurrent_gate_kernels.c.

140 {
141 for (int row = 0; row < rows; ++row) {
142 const float *x_row = x + (size_t) row * (size_t) dim;
143 float *out_row = out + (size_t) row * (size_t) dim;
144 for (int col = 0; col < dim; ++col) {
145 const float xv = x_row[col];
146 out_row[col] = xv * recurrent_sigmoid(xv);
147 }
148 }
149}

References recurrent_sigmoid().

◆ recurrent_silu_forward_ggml()

void recurrent_silu_forward_ggml ( const float *  x,
float *  out,
int  rows,
int  dim 
)

Definition at line 468 of file recurrent_gate_kernels.c.

471 {
472 for (int row = 0; row < rows; ++row) {
473 const float *x_row = x + (size_t) row * (size_t) dim;
474 float *out_row = out + (size_t) row * (size_t) dim;
475 int col = 0;
476#if defined(__AVX512F__) && defined(__AVX512DQ__)
477 for (; col + 16 <= dim; col += 16) {
478 const __m512 xv = _mm512_loadu_ps(x_row + col);
479 const __m512 neg = _mm512_sub_ps(_mm512_setzero_ps(), xv);
480 const __m512 denom = _mm512_add_ps(
481 _mm512_set1_ps(1.0f), recurrent_ggml_expf_avx512(neg));
482 _mm512_storeu_ps(out_row + col, _mm512_div_ps(xv, denom));
483 }
484#elif defined(__AVX2__) && defined(__FMA__)
485 for (; col + 8 <= dim; col += 8) {
486 const __m256 xv = _mm256_loadu_ps(x_row + col);
487 const __m256 neg = _mm256_sub_ps(_mm256_setzero_ps(), xv);
488 const __m256 denom = _mm256_add_ps(
489 _mm256_set1_ps(1.0f), recurrent_ggml_expf_avx2(neg));
490 _mm256_storeu_ps(out_row + col, _mm256_div_ps(xv, denom));
491 }
492#endif
493 float (*volatile llama_expf)(float) = expf;
494 for (; col < dim; ++col) {
495 const float xv = x_row[col];
496 out_row[col] = xv / (1.0f + llama_expf(-xv));
497 }
498 }
499}

Referenced by hyper_connection_mix_quantized(), qwen4_ple_gate_conv_inject_impl(), and recurrent_norm_gate_llama_avx2_forward().

◆ recurrent_silu_forward_pytorch_bf16_input_fp32_output()

void recurrent_silu_forward_pytorch_bf16_input_fp32_output ( const float *  x,
float *  out,
int  rows,
int  dim 
)

Definition at line 299 of file recurrent_gate_kernels.c.

303{
304 if (!x || !out || rows < 0 || dim < 0) {
305 fprintf(stderr, "HARD KERNEL CONTRACT FAULT: invalid BF16-input FP32-output SiLU arguments\n");
306 abort();
307 }
308#if defined(__AVX512F__)
309 pthread_once(&ck_recurrent_sleef_once, ck_bind_recurrent_pytorch_sleef);
310 if (!ck_recurrent_pytorch_expf16) {
311 fprintf(stderr,
312 "HARD KERNEL CONTRACT FAULT: PyTorch BF16-input SiLU requires "
313 "SLEEF Sleef_expf16_u10; set CK_SLEEF_LIBRARY\n");
314 abort();
315 }
316#endif
317 const int count = rows * dim;
318 int i = 0;
319#if defined(__AVX512F__)
320 for (; i + 16 <= count; i += 16) {
321 float lanes[16] __attribute__((aligned(64)));
322 for (int lane = 0; lane < 16; ++lane) {
323 lanes[lane] = bf16_to_float(float_to_bf16(x[i + lane]));
324 }
325 const __m512 values = _mm512_load_ps(lanes);
326 const __m512 denominator = _mm512_add_ps(
327 _mm512_set1_ps(1.0f),
328 ck_recurrent_pytorch_expf16(
329 _mm512_sub_ps(_mm512_setzero_ps(), values)));
330 _mm512_storeu_ps(out + i, _mm512_div_ps(values, denominator));
331 }
332#endif
333 for (; i < count; ++i) {
334 const float value = bf16_to_float(float_to_bf16(x[i]));
335 out[i] = value / (1.0f + expf(-value));
336 }
337}

References __attribute__(), bf16_to_float(), and float_to_bf16().

Referenced by recurrent_norm_gate_pytorch_bf16_storage().

◆ recurrent_silu_forward_pytorch_bf16_storage()

void recurrent_silu_forward_pytorch_bf16_storage ( const float *  x,
float *  out,
int  rows,
int  dim 
)

Definition at line 252 of file recurrent_gate_kernels.c.

256{
257 if (!x || !out || rows < 0 || dim < 0) {
258 fprintf(stderr, "HARD KERNEL CONTRACT FAULT: invalid PyTorch BF16 recurrent SiLU arguments\n");
259 abort();
260 }
261#if defined(__AVX512F__)
262 pthread_once(&ck_recurrent_sleef_once, ck_bind_recurrent_pytorch_sleef);
263 if (!ck_recurrent_pytorch_expf16) {
264 fprintf(stderr,
265 "HARD KERNEL CONTRACT FAULT: PyTorch BF16 recurrent SiLU requires "
266 "SLEEF Sleef_expf16_u10; set CK_SLEEF_LIBRARY\n");
267 abort();
268 }
269#endif
270 for (int row = 0; row < rows; ++row) {
271 const float *src = x + (size_t)row * (size_t)dim;
272 float *dst = out + (size_t)row * (size_t)dim;
273 int col = 0;
274#if defined(__AVX512F__)
275 for (; col + 16 <= dim; col += 16) {
276 float lanes[16] __attribute__((aligned(64)));
277 for (int lane = 0; lane < 16; ++lane) {
278 lanes[lane] = bf16_to_float(float_to_bf16(src[col + lane]));
279 }
280 const __m512 values = _mm512_load_ps(lanes);
281 const __m512 denominator = _mm512_add_ps(
282 _mm512_set1_ps(1.0f),
283 ck_recurrent_pytorch_expf16(
284 _mm512_sub_ps(_mm512_setzero_ps(), values)));
285 _mm512_store_ps(lanes, _mm512_div_ps(values, denominator));
286 for (int lane = 0; lane < 16; ++lane) {
287 dst[col + lane] = bf16_to_float(float_to_bf16(lanes[lane]));
288 }
289 }
290#endif
291 for (; col < dim; ++col) {
292 const float value = bf16_to_float(float_to_bf16(src[col]));
293 const float silu = value / (1.0f + expf(-value));
294 dst[col] = bf16_to_float(float_to_bf16(silu));
295 }
296 }
297}

References __attribute__(), bf16_to_float(), float_to_bf16(), and silu().

◆ recurrent_split_conv_qkv_backward()

void recurrent_split_conv_qkv_backward ( const float *  d_q,
const float *  d_k,
const float *  d_v,
float *  d_packed_qkv,
int  rows,
int  q_dim,
int  k_dim,
int  v_dim 
)

Definition at line 108 of file recurrent_split_kernels.c.

115 {
116 recurrent_split_qkv_backward(d_q, d_k, d_v, d_packed_qkv, rows, q_dim, k_dim, v_dim);
117}
void recurrent_split_qkv_backward(const float *d_q, const float *d_k, const float *d_v, float *d_packed_qkv, int rows, int q_dim, int k_dim, int v_dim)

References recurrent_split_qkv_backward().

◆ recurrent_split_conv_qkv_forward()

void recurrent_split_conv_qkv_forward ( const float *  packed_qkv,
float *  q,
float *  k,
float *  v,
int  rows,
int  q_dim,
int  k_dim,
int  v_dim 
)

Definition at line 97 of file recurrent_split_kernels.c.

104 {
105 recurrent_split_qkv_forward(packed_qkv, q, k, v, rows, q_dim, k_dim, v_dim);
106}
void recurrent_split_qkv_forward(const float *packed_qkv, float *q, float *k, float *v, int rows, int q_dim, int k_dim, int v_dim)

References recurrent_split_qkv_forward().

◆ recurrent_split_qkv_backward()

void recurrent_split_qkv_backward ( const float *  d_q,
const float *  d_k,
const float *  d_v,
float *  d_packed_qkv,
int  rows,
int  q_dim,
int  k_dim,
int  v_dim 
)

Definition at line 77 of file recurrent_split_kernels.c.

84 {
85 const int packed_dim = q_dim + k_dim + v_dim;
86 for (int row = 0; row < rows; ++row) {
87 const float *dq_src = d_q + (size_t) row * (size_t) q_dim;
88 const float *dk_src = d_k + (size_t) row * (size_t) k_dim;
89 const float *dv_src = d_v + (size_t) row * (size_t) v_dim;
90 float *dst = d_packed_qkv + (size_t) row * (size_t) packed_dim;
91 memcpy(dst, dq_src, (size_t) q_dim * sizeof(float));
92 memcpy(dst + q_dim, dk_src, (size_t) k_dim * sizeof(float));
93 memcpy(dst + q_dim + k_dim, dv_src, (size_t) v_dim * sizeof(float));
94 }
95}

Referenced by recurrent_split_conv_qkv_backward().

◆ recurrent_split_qkv_forward()

void recurrent_split_qkv_forward ( const float *  packed_qkv,
float *  q,
float *  k,
float *  v,
int  rows,
int  q_dim,
int  k_dim,
int  v_dim 
)

Definition at line 5 of file recurrent_split_kernels.c.

12 {
13 const int packed_dim = q_dim + k_dim + v_dim;
14 for (int row = 0; row < rows; ++row) {
15 const float *src = packed_qkv + (size_t) row * (size_t) packed_dim;
16 float *q_dst = q + (size_t) row * (size_t) q_dim;
17 float *k_dst = k + (size_t) row * (size_t) k_dim;
18 float *v_dst = v + (size_t) row * (size_t) v_dim;
19 memcpy(q_dst, src, (size_t) q_dim * sizeof(float));
20 memcpy(k_dst, src + q_dim, (size_t) k_dim * sizeof(float));
21 memcpy(v_dst, src + q_dim + k_dim, (size_t) v_dim * sizeof(float));
22 }
23}

◆ relu2_backward()

void relu2_backward ( const float *  input,
const float *  d_output,
float *  d_input,
size_t  n 
)

Definition at line 147 of file relu_kernels.c.

151{
152 size_t i = 0;
153
154#if defined(__AVX512F__)
155 const __m512 vzero = _mm512_setzero_ps();
156 const __m512 vtwo = _mm512_set1_ps(2.0f);
157 for (; i + 15 < n; i += 16) {
158 const __m512 vx = _mm512_loadu_ps(input + i);
159 const __m512 vdy = _mm512_loadu_ps(d_output + i);
160 const __mmask16 mask = _mm512_cmp_ps_mask(vx, vzero, _CMP_GT_OQ);
161 const __m512 vdx = _mm512_mul_ps(_mm512_mul_ps(vtwo, vx), vdy);
162 _mm512_storeu_ps(d_input + i, _mm512_maskz_mov_ps(mask, vdx));
163 }
164#elif defined(__AVX2__) || defined(__AVX__)
165 const __m256 vzero = _mm256_setzero_ps();
166 const __m256 vtwo = _mm256_set1_ps(2.0f);
167 for (; i + 7 < n; i += 8) {
168 const __m256 vx = _mm256_loadu_ps(input + i);
169 const __m256 vdy = _mm256_loadu_ps(d_output + i);
170 const __m256 mask = _mm256_cmp_ps(vx, vzero, _CMP_GT_OQ);
171 const __m256 vdx = _mm256_mul_ps(_mm256_mul_ps(vtwo, vx), vdy);
172 _mm256_storeu_ps(d_input + i, _mm256_and_ps(mask, vdx));
173 }
174#endif
175
176 for (; i < n; ++i) {
177 const float x = input[i];
178 d_input[i] = (x > 0.0f) ? d_output[i] * 2.0f * x : 0.0f;
179 }
180}
int32_t int32_t int32_t int32_t int32_t mask
Definition tokenizer.h:234

References mask.

◆ relu2_forward()

void relu2_forward ( const float *  input,
float *  output,
size_t  n 
)

Definition at line 120 of file relu_kernels.c.

121{
122 size_t i = 0;
123
124#if defined(__AVX512F__)
125 const __m512 vzero = _mm512_setzero_ps();
126 for (; i + 15 < n; i += 16) {
127 const __m512 vx = _mm512_loadu_ps(input + i);
128 const __m512 vr = _mm512_max_ps(vx, vzero);
129 _mm512_storeu_ps(output + i, _mm512_mul_ps(vr, vr));
130 }
131#elif defined(__AVX2__) || defined(__AVX__)
132 const __m256 vzero = _mm256_setzero_ps();
133 for (; i + 7 < n; i += 8) {
134 const __m256 vx = _mm256_loadu_ps(input + i);
135 const __m256 vr = _mm256_max_ps(vx, vzero);
136 _mm256_storeu_ps(output + i, _mm256_mul_ps(vr, vr));
137 }
138#endif
139
140 for (; i < n; ++i) {
141 const float x = input[i];
142 output[i] = (x > 0.0f) ? x * x : 0.0f;
143 }
144}

◆ relu_backward()

void relu_backward ( const float *  input,
const float *  d_output,
float *  d_input,
size_t  n 
)

Definition at line 84 of file relu_kernels.c.

88{
89 size_t i = 0;
90
91#if defined(__AVX512F__)
92 __m512 vzero = _mm512_setzero_ps();
93 for (; i + 15 < n; i += 16) {
94 __m512 vx = _mm512_loadu_ps(input + i);
95 __m512 vdy = _mm512_loadu_ps(d_output + i);
96 __mmask16 mask = _mm512_cmp_ps_mask(vx, vzero, _CMP_GT_OQ);
97 __m512 vdx = _mm512_maskz_mov_ps(mask, vdy);
98 _mm512_storeu_ps(d_input + i, vdx);
99 }
100#elif defined(__AVX2__) || defined(__AVX__)
101 __m256 vzero = _mm256_setzero_ps();
102 for (; i + 7 < n; i += 8) {
103 __m256 vx = _mm256_loadu_ps(input + i);
104 __m256 vdy = _mm256_loadu_ps(d_output + i);
105 // Result is all 1s (0xFFFFFFFF) if true, 0 if false.
106 __m256 mask = _mm256_cmp_ps(vx, vzero, _CMP_GT_OQ);
107 __m256 vdx = _mm256_and_ps(mask, vdy);
108 _mm256_storeu_ps(d_input + i, vdx);
109 }
110#endif
111
112 // Scalar fallback
113 for (; i < n; ++i) {
114 d_input[i] = (input[i] > 0.0f) ? d_output[i] : 0.0f;
115 }
116}

References mask.

◆ relu_backward_bf16()

void relu_backward_bf16 ( const uint16_t *  input,
const uint16_t *  d_output,
uint16_t *  d_input,
size_t  n 
)

Definition at line 69 of file relu_kernels_bf16.c.

73{
74 if (!input || !d_output || !d_input) {
75 return;
76 }
77
78 size_t i = 0;
79#if defined(__AVX2__)
80 const __m256i zero = _mm256_setzero_si256();
81 for (; i + 16 <= n; i += 16) {
82 const __m256i x = _mm256_loadu_si256((const __m256i *)(input + i));
83 const __m256i dy = _mm256_loadu_si256((const __m256i *)(d_output + i));
84 const __m256i mask = _mm256_cmpgt_epi16(x, zero);
85 const __m256i dx = _mm256_and_si256(dy, mask);
86 _mm256_storeu_si256((__m256i *)(d_input + i), dx);
87 }
88#endif
89 for (; i < n; ++i) {
90 d_input[i] = ((input[i] & 0x8000u) == 0u && (input[i] & 0x7fffu) != 0u) ? d_output[i] : 0u;
91 }
92}

References mask.

◆ relu_forward()

void relu_forward ( const float *  input,
float *  output,
size_t  n 
)

Definition at line 26 of file relu_kernels.c.

27{
28 size_t i = 0;
29
30#if defined(__AVX512F__)
31 __m512 vzero = _mm512_setzero_ps();
32 for (; i + 15 < n; i += 16) {
33 __m512 vx = _mm512_loadu_ps(input + i);
34 __m512 vy = _mm512_max_ps(vx, vzero);
35 _mm512_storeu_ps(output + i, vy);
36 }
37#elif defined(__AVX2__) || defined(__AVX__)
38 __m256 vzero = _mm256_setzero_ps();
39 for (; i + 7 < n; i += 8) {
40 __m256 vx = _mm256_loadu_ps(input + i);
41 __m256 vy = _mm256_max_ps(vx, vzero);
42 _mm256_storeu_ps(output + i, vy);
43 }
44#endif
45
46 // Scalar fallback
47 for (; i < n; ++i) {
48 float x = input[i];
49 output[i] = (x > 0.0f) ? x : 0.0f;
50 }
51}

◆ relu_forward_bf16()

void relu_forward_bf16 ( const uint16_t *  input,
uint16_t *  output,
size_t  n 
)

Definition at line 27 of file relu_kernels_bf16.c.

28{
29 if (!input || !output) {
30 return;
31 }
32
33 size_t i = 0;
34#if defined(__AVX2__)
35 const __m256i zero = _mm256_setzero_si256();
36 for (; i + 16 <= n; i += 16) {
37 const __m256i x = _mm256_loadu_si256((const __m256i *)(input + i));
38 const __m256i mask = _mm256_cmpgt_epi16(x, zero);
39 const __m256i y = _mm256_and_si256(x, mask);
40 _mm256_storeu_si256((__m256i *)(output + i), y);
41 }
42#endif
43 for (; i < n; ++i) {
44 output[i] = (input[i] & 0x8000u) ? 0u : input[i];
45 }
46}

References mask.

◆ relu_forward_inplace()

void relu_forward_inplace ( float *  data,
size_t  n 
)

Definition at line 54 of file relu_kernels.c.

55{
56 size_t i = 0;
57
58#if defined(__AVX512F__)
59 __m512 vzero = _mm512_setzero_ps();
60 for (; i + 15 < n; i += 16) {
61 __m512 vx = _mm512_loadu_ps(data + i);
62 __m512 vy = _mm512_max_ps(vx, vzero);
63 _mm512_storeu_ps(data + i, vy);
64 }
65#elif defined(__AVX2__) || defined(__AVX__)
66 __m256 vzero = _mm256_setzero_ps();
67 for (; i + 7 < n; i += 8) {
68 __m256 vx = _mm256_loadu_ps(data + i);
69 __m256 vy = _mm256_max_ps(vx, vzero);
70 _mm256_storeu_ps(data + i, vy);
71 }
72#endif
73
74 // Scalar fallback
75 for (; i < n; ++i) {
76 float x = data[i];
77 if (x < 0.0f) {
78 data[i] = 0.0f;
79 }
80 }
81}

◆ relu_forward_inplace_bf16()

void relu_forward_inplace_bf16 ( uint16_t *  data,
size_t  n 
)

Definition at line 48 of file relu_kernels_bf16.c.

49{
50 if (!data) {
51 return;
52 }
53
54 size_t i = 0;
55#if defined(__AVX2__)
56 const __m256i zero = _mm256_setzero_si256();
57 for (; i + 16 <= n; i += 16) {
58 const __m256i x = _mm256_loadu_si256((const __m256i *)(data + i));
59 const __m256i mask = _mm256_cmpgt_epi16(x, zero);
60 const __m256i y = _mm256_and_si256(x, mask);
61 _mm256_storeu_si256((__m256i *)(data + i), y);
62 }
63#endif
64 for (; i < n; ++i) {
65 data[i] = (data[i] & 0x8000u) ? 0u : data[i];
66 }
67}

References mask.

◆ rmsnorm_backward()

void rmsnorm_backward ( const float *  d_output,
const float *  input,
const float *  gamma,
const float *  rstd_cache,
float *  d_input,
float *  d_gamma,
int  tokens,
int  d_model,
int  aligned_embed_dim 
)

RMSNorm backward pass

Test:

test_rmsnorm.py::TestRMSNormBackward::test_backward_tokens

test_rmsnorm.py::TestRMSNormBackward::test_backward_single

test_parity.py::test_rmsnorm_backward_parity

Computes dX and dGamma given dY, X, gamma, and cached rstd. dX_i = rstd * (dY_i * gamma_i - x_hat_i * m) dGamma_i = sum_t (dY_i * x_hat_i)

After changes: make test && make llamacpp-parity-full

Definition at line 715 of file rmsnorm_kernels.c.

724{
725 int T = tokens;
726 int D = d_model;
727 int aligned = aligned_embed_dim;
728
730 rmsnorm_backward_strict_scalar(d_output, input, gamma, rstd_cache, d_input, d_gamma, T, D, aligned);
731 return;
732 }
733
734 // Zero parameter gradients
735#if defined(__AVX512F__)
736 {
737 int d = 0;
738 for (; d + 16 <= D; d += 16) {
739 _mm512_storeu_ps(&d_gamma[d], _mm512_setzero_ps());
740 }
741 for (; d < D; ++d) {
742 d_gamma[d] = 0.0f;
743 }
744 }
745#elif defined(__AVX__)
746 {
747 int d = 0;
748 for (; d + 8 <= D; d += 8) {
749 _mm256_storeu_ps(&d_gamma[d], _mm256_setzero_ps());
750 }
751 for (; d < D; ++d) {
752 d_gamma[d] = 0.0f;
753 }
754 }
755#else
756 for (int d = 0; d < D; ++d) {
757 d_gamma[d] = 0.0f;
758 }
759#endif
760
761 for (int t = 0; t < T; ++t) {
762 const float *x = input + (size_t)t * aligned;
763 const float *dY = d_output + (size_t)t * aligned;
764 float *dX = d_input + (size_t)t * aligned;
765
766 float rstd = rstd_cache[t];
767
768#if defined(__AVX512F__)
769 // Compute m = (1/D) * sum_j (dY_j * gamma_j * x_hat_j)
770 __m512 rstd_vec = _mm512_set1_ps(rstd);
771 __m512 sum_vec = _mm512_setzero_ps();
772 int d = 0;
773
774 for (; d + 16 <= D; d += 16) {
775 __m512 xv = _mm512_loadu_ps(&x[d]);
776 __m512 dyv = _mm512_loadu_ps(&dY[d]);
777 __m512 gv = _mm512_loadu_ps(&gamma[d]);
778 __m512 x_hat = _mm512_mul_ps(xv, rstd_vec);
779 // sum += dY * gamma * x_hat
780 __m512 prod = _mm512_mul_ps(dyv, gv);
781 sum_vec = _mm512_fmadd_ps(prod, x_hat, sum_vec);
782 }
783 float sum_dY_g_xhat = _mm512_reduce_add_ps(sum_vec);
784
785 // Handle remaining elements
786 for (; d < D; ++d) {
787 float x_hat = x[d] * rstd;
788 sum_dY_g_xhat += dY[d] * gamma[d] * x_hat;
789 }
790 float m = sum_dY_g_xhat / (float)D;
791
792 // Compute dX and accumulate dGamma (vectorized)
793 __m512 m_vec = _mm512_set1_ps(m);
794 d = 0;
795 for (; d + 16 <= D; d += 16) {
796 __m512 xv = _mm512_loadu_ps(&x[d]);
797 __m512 dyv = _mm512_loadu_ps(&dY[d]);
798 __m512 gv = _mm512_loadu_ps(&gamma[d]);
799 __m512 dgv = _mm512_loadu_ps(&d_gamma[d]);
800
801 __m512 x_hat = _mm512_mul_ps(xv, rstd_vec);
802
803 // dX = rstd * (dY * gamma - x_hat * m)
804 __m512 dy_g = _mm512_mul_ps(dyv, gv);
805 __m512 xhat_m = _mm512_mul_ps(x_hat, m_vec);
806 __m512 diff = _mm512_sub_ps(dy_g, xhat_m);
807 __m512 dxv = _mm512_mul_ps(rstd_vec, diff);
808 _mm512_storeu_ps(&dX[d], dxv);
809
810 // d_gamma += dY * x_hat
811 dgv = _mm512_fmadd_ps(dyv, x_hat, dgv);
812 _mm512_storeu_ps(&d_gamma[d], dgv);
813 }
814 // Handle remaining elements
815 for (; d < D; ++d) {
816 float x_hat = x[d] * rstd;
817 float dy = dY[d];
818 dX[d] = rstd * (dy * gamma[d] - x_hat * m);
819 d_gamma[d] += dy * x_hat;
820 }
821
822#elif defined(__AVX__)
823 // Compute m = (1/D) * sum_j (dY_j * gamma_j * x_hat_j)
824 __m256 rstd_vec = _mm256_set1_ps(rstd);
825 __m256 sum_vec = _mm256_setzero_ps();
826 int d = 0;
827
828 for (; d + 8 <= D; d += 8) {
829 __m256 xv = _mm256_loadu_ps(&x[d]);
830 __m256 dyv = _mm256_loadu_ps(&dY[d]);
831 __m256 gv = _mm256_loadu_ps(&gamma[d]);
832 __m256 x_hat = _mm256_mul_ps(xv, rstd_vec);
833 // sum += dY * gamma * x_hat (no FMA, use mul + mul + add)
834 __m256 prod = _mm256_mul_ps(dyv, gv);
835 __m256 prod2 = _mm256_mul_ps(prod, x_hat);
836 sum_vec = _mm256_add_ps(sum_vec, prod2);
837 }
838 float sum_dY_g_xhat = hsum256_ps_rmsnorm(sum_vec);
839
840 // Handle remaining elements
841 for (; d < D; ++d) {
842 float x_hat = x[d] * rstd;
843 sum_dY_g_xhat += dY[d] * gamma[d] * x_hat;
844 }
845 float m = sum_dY_g_xhat / (float)D;
846
847 // Compute dX and accumulate dGamma (vectorized)
848 __m256 m_vec = _mm256_set1_ps(m);
849 d = 0;
850 for (; d + 8 <= D; d += 8) {
851 __m256 xv = _mm256_loadu_ps(&x[d]);
852 __m256 dyv = _mm256_loadu_ps(&dY[d]);
853 __m256 gv = _mm256_loadu_ps(&gamma[d]);
854 __m256 dgv = _mm256_loadu_ps(&d_gamma[d]);
855
856 __m256 x_hat = _mm256_mul_ps(xv, rstd_vec);
857
858 // dX = rstd * (dY * gamma - x_hat * m)
859 __m256 dy_g = _mm256_mul_ps(dyv, gv);
860 __m256 xhat_m = _mm256_mul_ps(x_hat, m_vec);
861 __m256 diff = _mm256_sub_ps(dy_g, xhat_m);
862 __m256 dxv = _mm256_mul_ps(rstd_vec, diff);
863 _mm256_storeu_ps(&dX[d], dxv);
864
865 // d_gamma += dY * x_hat
866 __m256 dy_xhat = _mm256_mul_ps(dyv, x_hat);
867 dgv = _mm256_add_ps(dgv, dy_xhat);
868 _mm256_storeu_ps(&d_gamma[d], dgv);
869 }
870 // Handle remaining elements
871 for (; d < D; ++d) {
872 float x_hat = x[d] * rstd;
873 float dy = dY[d];
874 dX[d] = rstd * (dy * gamma[d] - x_hat * m);
875 d_gamma[d] += dy * x_hat;
876 }
877
878#else
879 // Scalar fallback
880 // Compute m = (1/D) * sum_j (dY_j * gamma_j * x_hat_j)
881 float sum_dY_g_xhat = 0.0f;
882 for (int d = 0; d < D; ++d) {
883 float x_hat = x[d] * rstd;
884 sum_dY_g_xhat += dY[d] * gamma[d] * x_hat;
885 }
886 float m = sum_dY_g_xhat / (float)D;
887
888 // Compute dX and accumulate dGamma
889 for (int d = 0; d < D; ++d) {
890 float x_hat = x[d] * rstd;
891 float dy = dY[d];
892 dX[d] = rstd * (dy * gamma[d] - x_hat * m);
893 d_gamma[d] += dy * x_hat;
894 }
895#endif
896
897 // Zero padding gradients (if any)
898 for (int d = D; d < aligned; ++d) {
899 dX[d] = 0.0f;
900 }
901 }
902}
static void rmsnorm_backward_strict_scalar(const float *d_output, const float *input, const float *gamma, const float *rstd_cache, float *d_input, float *d_gamma, int tokens, int d_model, int aligned_embed_dim)

References ck_strict_parity_enabled(), and rmsnorm_backward_strict_scalar().

Referenced by ck_layer_backward_rmsnorm_swiglu(), rmsnorm_backward_int4(), and rmsnorm_backward_int8().

◆ rmsnorm_backward_bf16()

void rmsnorm_backward_bf16 ( const uint16_t *  d_output,
const uint16_t *  input,
const float *  gamma,
const float *  rstd_cache,
uint16_t *  d_input,
float *  d_gamma,
int  tokens,
int  d_model,
int  aligned_embed_dim 
)

Definition at line 113 of file rmsnorm_kernels_bf16.c.

122{
123 int T = tokens;
124 int D = d_model;
125 int aligned = aligned_embed_dim;
126
127 if (!d_output || !input || !gamma || !rstd_cache || !d_input || !d_gamma) {
128 return;
129 }
130
131 // Zero parameter gradients
132#if defined(__AVX512F__)
133 {
134 int d = 0;
135 for (; d + 16 <= D; d += 16) {
136 _mm512_storeu_ps(&d_gamma[d], _mm512_setzero_ps());
137 }
138 for (; d < D; ++d) {
139 d_gamma[d] = 0.0f;
140 }
141 }
142#else
143 for (int d = 0; d < D; ++d) {
144 d_gamma[d] = 0.0f;
145 }
146#endif
147
148 for (int t = 0; t < T; ++t) {
149 const uint16_t *x_bf16 = input + (size_t)t * aligned;
150 const uint16_t *dY_bf16 = d_output + (size_t)t * aligned;
151 uint16_t *dX_bf16 = d_input + (size_t)t * aligned;
152 float rstd = rstd_cache[t];
153
154#if defined(__AVX512F__)
155 // Compute m = (1/D) * sum_j (dY_j * gamma_j * x_hat_j)
156 __m512 rstd_vec = _mm512_set1_ps(rstd);
157 __m512 sum_vec = _mm512_setzero_ps();
158 int d = 0;
159
160 for (; d + 16 <= D; d += 16) {
161 __m512 xv = bf16_loadu_cvt_fp32(&x_bf16[d]);
162 __m512 dyv = bf16_loadu_cvt_fp32(&dY_bf16[d]);
163 __m512 gv = _mm512_loadu_ps(&gamma[d]);
164 __m512 x_hat = _mm512_mul_ps(xv, rstd_vec);
165 // sum += dY * gamma * x_hat
166 __m512 prod = _mm512_mul_ps(dyv, gv);
167 sum_vec = _mm512_fmadd_ps(prod, x_hat, sum_vec);
168 }
169 float sum_dY_g_xhat = _mm512_reduce_add_ps(sum_vec);
170
171 // Handle remaining elements
172 for (; d < D; ++d) {
173 float x = bf16_to_float(x_bf16[d]);
174 float x_hat = x * rstd;
175 float dy = bf16_to_float(dY_bf16[d]);
176 sum_dY_g_xhat += dy * gamma[d] * x_hat;
177 }
178 float m = sum_dY_g_xhat / (float)D;
179
180 // Compute dX and accumulate dGamma (vectorized)
181 __m512 m_vec = _mm512_set1_ps(m);
182 d = 0;
183 for (; d + 16 <= D; d += 16) {
184 __m512 xv = bf16_loadu_cvt_fp32(&x_bf16[d]);
185 __m512 dyv = bf16_loadu_cvt_fp32(&dY_bf16[d]);
186 __m512 gv = _mm512_loadu_ps(&gamma[d]);
187 __m512 dgv = _mm512_loadu_ps(&d_gamma[d]);
188
189 __m512 x_hat = _mm512_mul_ps(xv, rstd_vec);
190
191 // dX = rstd * (dY * gamma - x_hat * m)
192 __m512 dy_g = _mm512_mul_ps(dyv, gv);
193 __m512 xhat_m = _mm512_mul_ps(x_hat, m_vec);
194 __m512 diff = _mm512_sub_ps(dy_g, xhat_m);
195 __m512 dxv = _mm512_mul_ps(rstd_vec, diff);
196 fp32_cvt_storeu_bf16(&dX_bf16[d], dxv);
197
198 // d_gamma += dY * x_hat
199 dgv = _mm512_fmadd_ps(dyv, x_hat, dgv);
200 _mm512_storeu_ps(&d_gamma[d], dgv);
201 }
202 // Handle remaining elements
203 for (; d < D; ++d) {
204 float x = bf16_to_float(x_bf16[d]);
205 float x_hat = x * rstd;
206 float dy = bf16_to_float(dY_bf16[d]);
207 float dx = rstd * (dy * gamma[d] - x_hat * m);
208 dX_bf16[d] = float_to_bf16(dx);
209 d_gamma[d] += dy * x_hat;
210 }
211
212#else
213 // Scalar fallback
214 double sum_dY_g_xhat = 0.0;
215 for (int d = 0; d < D; ++d) {
216 float x = bf16_to_float(x_bf16[d]);
217 float x_hat = x * rstd;
218 float dy = bf16_to_float(dY_bf16[d]);
219 sum_dY_g_xhat += (double)dy * (double)gamma[d] * (double)x_hat;
220 }
221 float m = (float)(sum_dY_g_xhat / (double)D);
222
223 for (int d = 0; d < D; ++d) {
224 float x = bf16_to_float(x_bf16[d]);
225 float x_hat = x * rstd;
226 float dy = bf16_to_float(dY_bf16[d]);
227 float dx = rstd * (dy * gamma[d] - x_hat * m);
228 dX_bf16[d] = float_to_bf16(dx);
229 d_gamma[d] += dy * x_hat;
230 }
231#endif
232
233 // Zero padding gradients
234 for (int d = D; d < aligned; ++d) {
235 dX_bf16[d] = 0;
236 }
237 }
238}

References bf16_to_float(), and float_to_bf16().

◆ rmsnorm_backward_int4()

void rmsnorm_backward_int4 ( const uint8_t *  d_output,
const uint8_t *  input,
const float *  gamma,
const float *  rstd_cache,
uint8_t *  d_input,
float *  d_gamma,
int  tokens,
int  d_model,
int  aligned_embed_dim,
float *  scratch_d_output,
float *  scratch_input,
float *  scratch_d_input 
)

Definition at line 104 of file rmsnorm_kernels_int4.c.

116{
117 if (!d_output || !input || !gamma || !rstd_cache || !d_input || !d_gamma) return;
118 if (!scratch_d_output || !scratch_input || !scratch_d_input) return;
119
120 size_t total = (size_t)tokens * (size_t)aligned_embed_dim;
121
122 convert_int4_to_float(d_output, scratch_d_output, total);
123 convert_int4_to_float(input, scratch_input, total);
124
125 for (int d = 0; d < d_model; ++d) {
126 d_gamma[d] = 0.0f;
127 }
128
129 rmsnorm_backward(scratch_d_output,
130 scratch_input,
131 gamma,
132 rstd_cache,
133 scratch_d_input,
134 d_gamma,
135 tokens,
136 d_model,
137 aligned_embed_dim);
138
139 convert_float_to_int4(scratch_d_input, d_input, total);
140}
void rmsnorm_backward(const float *d_output, const float *input, const float *gamma, const float *rstd_cache, float *d_input, float *d_gamma, int tokens, int d_model, int aligned_embed_dim)
static void convert_int4_to_float(const uint8_t *src, float *dst, size_t count)
static void convert_float_to_int4(const float *src, uint8_t *dst, size_t count)

References convert_float_to_int4(), convert_int4_to_float(), and rmsnorm_backward().

◆ rmsnorm_backward_int8()

void rmsnorm_backward_int8 ( const int8_t *  d_output,
const int8_t *  input,
const float *  gamma,
const float *  rstd_cache,
int8_t *  d_input,
float *  d_gamma,
int  tokens,
int  d_model,
int  aligned_embed_dim,
float *  scratch_d_output,
float *  scratch_input,
float *  scratch_d_input 
)

Definition at line 84 of file rmsnorm_kernels_int8.c.

96{
97 if (!d_output || !input || !gamma || !rstd_cache || !d_input || !d_gamma) return;
98 if (!scratch_d_output || !scratch_input || !scratch_d_input) return;
99
100 size_t total = (size_t)tokens * (size_t)aligned_embed_dim;
101
102 convert_int8_to_float(d_output, scratch_d_output, total);
103 convert_int8_to_float(input, scratch_input, total);
104
105 // Zero gamma gradient before accumulation.
106 for (int d = 0; d < d_model; ++d) {
107 d_gamma[d] = 0.0f;
108 }
109
110 rmsnorm_backward(scratch_d_output,
111 scratch_input,
112 gamma,
113 rstd_cache,
114 scratch_d_input,
115 d_gamma,
116 tokens,
117 d_model,
118 aligned_embed_dim);
119
120 convert_float_to_int8(scratch_d_input, d_input, total);
121}
static void convert_int8_to_float(const int8_t *src, float *dst, size_t count)
static void convert_float_to_int8(const float *src, int8_t *dst, size_t count)

References convert_float_to_int8(), convert_int8_to_float(), and rmsnorm_backward().

◆ rmsnorm_forward()

void rmsnorm_forward ( const float *  input,
const float *  gamma,
float *  output,
float *  rstd_cache,
int  tokens,
int  d_model,
int  aligned_embed_dim,
float  eps 
)

Definition at line 621 of file rmsnorm_kernels.c.

629{
631 input,
632 gamma,
633 output,
634 rstd_cache,
635 tokens,
636 d_model,
637 aligned_embed_dim,
638 aligned_embed_dim,
639 eps
640 );
641}
void rmsnorm_forward_strided_f32(const float *input, const float *gamma, float *output, float *rstd_cache, int tokens, int d_model, int input_stride, int output_stride, float eps)

References rmsnorm_forward_strided_f32().

Referenced by ck_layer_forward_rmsnorm_swiglu(), ck_layer_forward_rmsnorm_swiglu_decode(), ck_layer_forward_rmsnorm_swiglu_decode_fused(), ck_layer_forward_rmsnorm_swiglu_decode_fused_attn_impl(), ck_layer_forward_rmsnorm_swiglu_decode_q4_k(), ck_layer_forward_rmsnorm_swiglu_decode_quant(), ck_layer_forward_rmsnorm_swiglu_q4_k(), ck_layer_forward_rmsnorm_swiglu_quant(), ck_layer_forward_rmsnorm_swiglu_ref(), mega_fused_outproj_mlp_prefill(), model_decode_token(), model_decode_token(), model_decode_token(), model_decode_token(), model_forward_prefill_impl(), model_forward_prefill_impl(), model_forward_prefill_impl(), model_forward_prefill_impl(), model_layer_0_decode(), model_layer_0_decode(), model_layer_0_decode(), model_layer_0_decode(), model_layer_0_prefill(), model_layer_0_prefill(), model_layer_0_prefill(), model_layer_0_prefill(), model_layer_10_decode(), model_layer_10_decode(), model_layer_10_decode(), model_layer_10_decode(), model_layer_10_prefill(), model_layer_10_prefill(), model_layer_10_prefill(), model_layer_10_prefill(), model_layer_11_decode(), model_layer_11_decode(), model_layer_11_decode(), model_layer_11_decode(), model_layer_11_prefill(), model_layer_11_prefill(), model_layer_11_prefill(), model_layer_11_prefill(), model_layer_12_decode(), model_layer_12_decode(), model_layer_12_decode(), model_layer_12_decode(), model_layer_12_prefill(), model_layer_12_prefill(), model_layer_12_prefill(), model_layer_12_prefill(), model_layer_13_decode(), model_layer_13_decode(), model_layer_13_decode(), model_layer_13_decode(), model_layer_13_prefill(), model_layer_13_prefill(), model_layer_13_prefill(), model_layer_13_prefill(), model_layer_14_decode(), model_layer_14_decode(), model_layer_14_decode(), model_layer_14_decode(), model_layer_14_prefill(), model_layer_14_prefill(), model_layer_14_prefill(), model_layer_14_prefill(), model_layer_15_decode(), model_layer_15_decode(), model_layer_15_decode(), model_layer_15_decode(), model_layer_15_prefill(), model_layer_15_prefill(), model_layer_15_prefill(), model_layer_15_prefill(), model_layer_16_decode(), model_layer_16_decode(), model_layer_16_decode(), model_layer_16_decode(), model_layer_16_prefill(), model_layer_16_prefill(), model_layer_16_prefill(), model_layer_16_prefill(), model_layer_17_decode(), model_layer_17_decode(), model_layer_17_decode(), model_layer_17_decode(), model_layer_17_prefill(), model_layer_17_prefill(), model_layer_17_prefill(), model_layer_17_prefill(), model_layer_18_decode(), model_layer_18_decode(), model_layer_18_decode(), model_layer_18_decode(), model_layer_18_prefill(), model_layer_18_prefill(), model_layer_18_prefill(), model_layer_18_prefill(), model_layer_19_decode(), model_layer_19_decode(), model_layer_19_decode(), model_layer_19_decode(), model_layer_19_prefill(), model_layer_19_prefill(), model_layer_19_prefill(), model_layer_19_prefill(), model_layer_1_decode(), model_layer_1_decode(), model_layer_1_decode(), model_layer_1_decode(), model_layer_1_prefill(), model_layer_1_prefill(), model_layer_1_prefill(), model_layer_1_prefill(), model_layer_20_decode(), model_layer_20_decode(), model_layer_20_decode(), model_layer_20_decode(), model_layer_20_prefill(), model_layer_20_prefill(), model_layer_20_prefill(), model_layer_20_prefill(), model_layer_21_decode(), model_layer_21_decode(), model_layer_21_decode(), model_layer_21_decode(), model_layer_21_prefill(), model_layer_21_prefill(), model_layer_21_prefill(), model_layer_21_prefill(), model_layer_22_decode(), model_layer_22_decode(), model_layer_22_decode(), model_layer_22_decode(), model_layer_22_prefill(), model_layer_22_prefill(), model_layer_22_prefill(), model_layer_22_prefill(), model_layer_23_decode(), model_layer_23_decode(), model_layer_23_decode(), model_layer_23_decode(), model_layer_23_prefill(), model_layer_23_prefill(), model_layer_23_prefill(), model_layer_23_prefill(), model_layer_2_decode(), model_layer_2_decode(), model_layer_2_decode(), model_layer_2_decode(), model_layer_2_prefill(), model_layer_2_prefill(), model_layer_2_prefill(), model_layer_2_prefill(), model_layer_3_decode(), model_layer_3_decode(), model_layer_3_decode(), model_layer_3_decode(), model_layer_3_prefill(), model_layer_3_prefill(), model_layer_3_prefill(), model_layer_3_prefill(), model_layer_4_decode(), model_layer_4_decode(), model_layer_4_decode(), model_layer_4_decode(), model_layer_4_prefill(), model_layer_4_prefill(), model_layer_4_prefill(), model_layer_4_prefill(), model_layer_5_decode(), model_layer_5_decode(), model_layer_5_decode(), model_layer_5_decode(), model_layer_5_prefill(), model_layer_5_prefill(), model_layer_5_prefill(), model_layer_5_prefill(), model_layer_6_decode(), model_layer_6_decode(), model_layer_6_decode(), model_layer_6_decode(), model_layer_6_prefill(), model_layer_6_prefill(), model_layer_6_prefill(), model_layer_6_prefill(), model_layer_7_decode(), model_layer_7_decode(), model_layer_7_decode(), model_layer_7_decode(), model_layer_7_prefill(), model_layer_7_prefill(), model_layer_7_prefill(), model_layer_7_prefill(), model_layer_8_decode(), model_layer_8_decode(), model_layer_8_decode(), model_layer_8_decode(), model_layer_8_prefill(), model_layer_8_prefill(), model_layer_8_prefill(), model_layer_8_prefill(), model_layer_9_decode(), model_layer_9_decode(), model_layer_9_decode(), model_layer_9_decode(), model_layer_9_prefill(), model_layer_9_prefill(), model_layer_9_prefill(), model_layer_9_prefill(), qwen2_0_5b_decode_decode_token(), qwen2_0_5b_decode_decode_token(), qwen2_0_5b_decode_decode_token(), qwen2_0_5b_decode_decode_token(), qwen2_0_5b_decode_decode_token(), qwen2_0_5b_decode_forward_prefill_impl(), qwen2_0_5b_decode_forward_prefill_impl(), qwen2_0_5b_decode_forward_prefill_impl(), qwen2_0_5b_decode_forward_prefill_impl(), qwen2_0_5b_decode_forward_prefill_impl(), qwen2_0_5b_decode_layer_0_decode(), qwen2_0_5b_decode_layer_0_decode(), qwen2_0_5b_decode_layer_0_decode(), qwen2_0_5b_decode_layer_0_decode(), qwen2_0_5b_decode_layer_0_decode(), qwen2_0_5b_decode_layer_0_prefill(), qwen2_0_5b_decode_layer_0_prefill(), qwen2_0_5b_decode_layer_0_prefill(), qwen2_0_5b_decode_layer_0_prefill(), qwen2_0_5b_decode_layer_10_decode(), qwen2_0_5b_decode_layer_10_decode(), qwen2_0_5b_decode_layer_10_decode(), qwen2_0_5b_decode_layer_10_decode(), qwen2_0_5b_decode_layer_10_decode(), qwen2_0_5b_decode_layer_10_prefill(), qwen2_0_5b_decode_layer_10_prefill(), qwen2_0_5b_decode_layer_10_prefill(), qwen2_0_5b_decode_layer_10_prefill(), qwen2_0_5b_decode_layer_11_decode(), qwen2_0_5b_decode_layer_11_decode(), qwen2_0_5b_decode_layer_11_decode(), qwen2_0_5b_decode_layer_11_decode(), qwen2_0_5b_decode_layer_11_decode(), qwen2_0_5b_decode_layer_11_prefill(), qwen2_0_5b_decode_layer_11_prefill(), qwen2_0_5b_decode_layer_11_prefill(), qwen2_0_5b_decode_layer_11_prefill(), qwen2_0_5b_decode_layer_12_decode(), qwen2_0_5b_decode_layer_12_decode(), qwen2_0_5b_decode_layer_12_decode(), qwen2_0_5b_decode_layer_12_decode(), qwen2_0_5b_decode_layer_12_decode(), qwen2_0_5b_decode_layer_12_prefill(), qwen2_0_5b_decode_layer_12_prefill(), qwen2_0_5b_decode_layer_12_prefill(), qwen2_0_5b_decode_layer_12_prefill(), qwen2_0_5b_decode_layer_13_decode(), qwen2_0_5b_decode_layer_13_decode(), qwen2_0_5b_decode_layer_13_decode(), qwen2_0_5b_decode_layer_13_decode(), qwen2_0_5b_decode_layer_13_decode(), qwen2_0_5b_decode_layer_13_prefill(), qwen2_0_5b_decode_layer_13_prefill(), qwen2_0_5b_decode_layer_13_prefill(), qwen2_0_5b_decode_layer_13_prefill(), qwen2_0_5b_decode_layer_14_decode(), qwen2_0_5b_decode_layer_14_decode(), qwen2_0_5b_decode_layer_14_decode(), qwen2_0_5b_decode_layer_14_decode(), qwen2_0_5b_decode_layer_14_decode(), qwen2_0_5b_decode_layer_14_prefill(), qwen2_0_5b_decode_layer_14_prefill(), qwen2_0_5b_decode_layer_14_prefill(), qwen2_0_5b_decode_layer_14_prefill(), qwen2_0_5b_decode_layer_15_decode(), qwen2_0_5b_decode_layer_15_decode(), qwen2_0_5b_decode_layer_15_decode(), qwen2_0_5b_decode_layer_15_decode(), qwen2_0_5b_decode_layer_15_decode(), qwen2_0_5b_decode_layer_15_prefill(), qwen2_0_5b_decode_layer_15_prefill(), qwen2_0_5b_decode_layer_15_prefill(), qwen2_0_5b_decode_layer_15_prefill(), qwen2_0_5b_decode_layer_16_decode(), qwen2_0_5b_decode_layer_16_decode(), qwen2_0_5b_decode_layer_16_decode(), qwen2_0_5b_decode_layer_16_decode(), qwen2_0_5b_decode_layer_16_decode(), qwen2_0_5b_decode_layer_16_prefill(), qwen2_0_5b_decode_layer_16_prefill(), qwen2_0_5b_decode_layer_16_prefill(), qwen2_0_5b_decode_layer_16_prefill(), qwen2_0_5b_decode_layer_17_decode(), qwen2_0_5b_decode_layer_17_decode(), qwen2_0_5b_decode_layer_17_decode(), qwen2_0_5b_decode_layer_17_decode(), qwen2_0_5b_decode_layer_17_decode(), qwen2_0_5b_decode_layer_17_prefill(), qwen2_0_5b_decode_layer_17_prefill(), qwen2_0_5b_decode_layer_17_prefill(), qwen2_0_5b_decode_layer_17_prefill(), qwen2_0_5b_decode_layer_18_decode(), qwen2_0_5b_decode_layer_18_decode(), qwen2_0_5b_decode_layer_18_decode(), qwen2_0_5b_decode_layer_18_decode(), qwen2_0_5b_decode_layer_18_decode(), qwen2_0_5b_decode_layer_18_prefill(), qwen2_0_5b_decode_layer_18_prefill(), qwen2_0_5b_decode_layer_18_prefill(), qwen2_0_5b_decode_layer_18_prefill(), qwen2_0_5b_decode_layer_19_decode(), qwen2_0_5b_decode_layer_19_decode(), qwen2_0_5b_decode_layer_19_decode(), qwen2_0_5b_decode_layer_19_decode(), qwen2_0_5b_decode_layer_19_decode(), qwen2_0_5b_decode_layer_19_prefill(), qwen2_0_5b_decode_layer_19_prefill(), qwen2_0_5b_decode_layer_19_prefill(), qwen2_0_5b_decode_layer_19_prefill(), qwen2_0_5b_decode_layer_1_decode(), qwen2_0_5b_decode_layer_1_decode(), qwen2_0_5b_decode_layer_1_decode(), qwen2_0_5b_decode_layer_1_decode(), qwen2_0_5b_decode_layer_1_decode(), qwen2_0_5b_decode_layer_1_prefill(), qwen2_0_5b_decode_layer_1_prefill(), qwen2_0_5b_decode_layer_1_prefill(), qwen2_0_5b_decode_layer_1_prefill(), qwen2_0_5b_decode_layer_20_decode(), qwen2_0_5b_decode_layer_20_decode(), qwen2_0_5b_decode_layer_20_decode(), qwen2_0_5b_decode_layer_20_decode(), qwen2_0_5b_decode_layer_20_decode(), qwen2_0_5b_decode_layer_20_prefill(), qwen2_0_5b_decode_layer_20_prefill(), qwen2_0_5b_decode_layer_20_prefill(), qwen2_0_5b_decode_layer_20_prefill(), qwen2_0_5b_decode_layer_21_decode(), qwen2_0_5b_decode_layer_21_decode(), qwen2_0_5b_decode_layer_21_decode(), qwen2_0_5b_decode_layer_21_decode(), qwen2_0_5b_decode_layer_21_decode(), qwen2_0_5b_decode_layer_21_prefill(), qwen2_0_5b_decode_layer_21_prefill(), qwen2_0_5b_decode_layer_21_prefill(), qwen2_0_5b_decode_layer_21_prefill(), qwen2_0_5b_decode_layer_22_decode(), qwen2_0_5b_decode_layer_22_decode(), qwen2_0_5b_decode_layer_22_decode(), qwen2_0_5b_decode_layer_22_decode(), qwen2_0_5b_decode_layer_22_decode(), qwen2_0_5b_decode_layer_22_prefill(), qwen2_0_5b_decode_layer_22_prefill(), qwen2_0_5b_decode_layer_22_prefill(), qwen2_0_5b_decode_layer_22_prefill(), qwen2_0_5b_decode_layer_23_decode(), qwen2_0_5b_decode_layer_23_decode(), qwen2_0_5b_decode_layer_23_decode(), qwen2_0_5b_decode_layer_23_decode(), qwen2_0_5b_decode_layer_23_decode(), qwen2_0_5b_decode_layer_23_prefill(), qwen2_0_5b_decode_layer_23_prefill(), qwen2_0_5b_decode_layer_23_prefill(), qwen2_0_5b_decode_layer_23_prefill(), qwen2_0_5b_decode_layer_2_decode(), qwen2_0_5b_decode_layer_2_decode(), qwen2_0_5b_decode_layer_2_decode(), qwen2_0_5b_decode_layer_2_decode(), qwen2_0_5b_decode_layer_2_decode(), qwen2_0_5b_decode_layer_2_prefill(), qwen2_0_5b_decode_layer_2_prefill(), qwen2_0_5b_decode_layer_2_prefill(), qwen2_0_5b_decode_layer_2_prefill(), qwen2_0_5b_decode_layer_3_decode(), qwen2_0_5b_decode_layer_3_decode(), qwen2_0_5b_decode_layer_3_decode(), qwen2_0_5b_decode_layer_3_decode(), qwen2_0_5b_decode_layer_3_decode(), qwen2_0_5b_decode_layer_3_prefill(), qwen2_0_5b_decode_layer_3_prefill(), qwen2_0_5b_decode_layer_3_prefill(), qwen2_0_5b_decode_layer_3_prefill(), qwen2_0_5b_decode_layer_4_decode(), qwen2_0_5b_decode_layer_4_decode(), qwen2_0_5b_decode_layer_4_decode(), qwen2_0_5b_decode_layer_4_decode(), qwen2_0_5b_decode_layer_4_decode(), qwen2_0_5b_decode_layer_4_prefill(), qwen2_0_5b_decode_layer_4_prefill(), qwen2_0_5b_decode_layer_4_prefill(), qwen2_0_5b_decode_layer_4_prefill(), qwen2_0_5b_decode_layer_5_decode(), qwen2_0_5b_decode_layer_5_decode(), qwen2_0_5b_decode_layer_5_decode(), qwen2_0_5b_decode_layer_5_decode(), qwen2_0_5b_decode_layer_5_decode(), qwen2_0_5b_decode_layer_5_prefill(), qwen2_0_5b_decode_layer_5_prefill(), qwen2_0_5b_decode_layer_5_prefill(), qwen2_0_5b_decode_layer_5_prefill(), qwen2_0_5b_decode_layer_6_decode(), qwen2_0_5b_decode_layer_6_decode(), qwen2_0_5b_decode_layer_6_decode(), qwen2_0_5b_decode_layer_6_decode(), qwen2_0_5b_decode_layer_6_decode(), qwen2_0_5b_decode_layer_6_prefill(), qwen2_0_5b_decode_layer_6_prefill(), qwen2_0_5b_decode_layer_6_prefill(), qwen2_0_5b_decode_layer_6_prefill(), qwen2_0_5b_decode_layer_7_decode(), qwen2_0_5b_decode_layer_7_decode(), qwen2_0_5b_decode_layer_7_decode(), qwen2_0_5b_decode_layer_7_decode(), qwen2_0_5b_decode_layer_7_decode(), qwen2_0_5b_decode_layer_7_prefill(), qwen2_0_5b_decode_layer_7_prefill(), qwen2_0_5b_decode_layer_7_prefill(), qwen2_0_5b_decode_layer_7_prefill(), qwen2_0_5b_decode_layer_8_decode(), qwen2_0_5b_decode_layer_8_decode(), qwen2_0_5b_decode_layer_8_decode(), qwen2_0_5b_decode_layer_8_decode(), qwen2_0_5b_decode_layer_8_decode(), qwen2_0_5b_decode_layer_8_prefill(), qwen2_0_5b_decode_layer_8_prefill(), qwen2_0_5b_decode_layer_8_prefill(), qwen2_0_5b_decode_layer_8_prefill(), qwen2_0_5b_decode_layer_9_decode(), qwen2_0_5b_decode_layer_9_decode(), qwen2_0_5b_decode_layer_9_decode(), qwen2_0_5b_decode_layer_9_decode(), qwen2_0_5b_decode_layer_9_decode(), qwen2_0_5b_decode_layer_9_prefill(), qwen2_0_5b_decode_layer_9_prefill(), qwen2_0_5b_decode_layer_9_prefill(), qwen2_0_5b_decode_layer_9_prefill(), rmsnorm_forward_int4(), and rmsnorm_forward_int8().

◆ rmsnorm_forward_bf16()

void rmsnorm_forward_bf16 ( const uint16_t *  input,
const float *  gamma,
uint16_t *  output,
float *  rstd_cache,
int  tokens,
int  d_model,
int  aligned_embed_dim,
float  eps 
)

Definition at line 24 of file rmsnorm_kernels_bf16.c.

32{
33 int T = tokens;
34 int D = d_model;
35 int aligned = aligned_embed_dim;
36
37 for (int t = 0; t < T; ++t) {
38 const uint16_t *x_bf16 = input + (size_t)t * aligned;
39 float *rstd_ptr = rstd_cache ? (rstd_cache + t) : NULL;
40 uint16_t *out_bf16 = output + (size_t)t * aligned;
41
42#if defined(__AVX512F__)
43 // AVX-512: Process 16 floats at a time
44 __m512 sum_sq_vec = _mm512_setzero_ps();
45 int d = 0;
46
47 // Vectorized sum of squares
48 for (; d + 16 <= D; d += 16) {
49 __m512 xv = bf16_loadu_cvt_fp32(&x_bf16[d]);
50 sum_sq_vec = _mm512_fmadd_ps(xv, xv, sum_sq_vec);
51 }
52 float sum_sq = _mm512_reduce_add_ps(sum_sq_vec);
53
54 // Handle remaining elements
55 for (; d < D; ++d) {
56 float x = bf16_to_float(x_bf16[d]);
57 sum_sq += x * x;
58 }
59
60 float mean_sq = sum_sq / (float)D;
61 float rstd = 1.0f / sqrtf(mean_sq + eps);
62 if (rstd_ptr) {
63 *rstd_ptr = rstd;
64 }
65
66 // Apply normalization and scale (vectorized)
67 __m512 rstd_vec = _mm512_set1_ps(rstd);
68 d = 0;
69 for (; d + 16 <= D; d += 16) {
70 __m512 xv = bf16_loadu_cvt_fp32(&x_bf16[d]);
71 __m512 gv = _mm512_loadu_ps(&gamma[d]);
72 __m512 x_hat = _mm512_mul_ps(xv, rstd_vec);
73 __m512 yv = _mm512_mul_ps(x_hat, gv);
74 fp32_cvt_storeu_bf16(&out_bf16[d], yv);
75 }
76 // Handle remaining elements
77 for (; d < D; ++d) {
78 float x = bf16_to_float(x_bf16[d]);
79 float y = x * rstd * gamma[d];
80 out_bf16[d] = float_to_bf16(y);
81 }
82
83#else
84 // Scalar fallback
85 double sum_sq = 0.0;
86 for (int d = 0; d < D; ++d) {
87 float x = bf16_to_float(x_bf16[d]);
88 sum_sq += (double)x * (double)x;
89 }
90 double mean_sq = sum_sq / (double)D;
91 double r = sqrt(mean_sq + (double)eps);
92 float rstd = (float)(1.0 / r);
93 if (rstd_ptr) {
94 *rstd_ptr = rstd;
95 }
96
97 for (int d = 0; d < D; ++d) {
98 float x = bf16_to_float(x_bf16[d]);
99 float x_hat = x * rstd;
100 float y = x_hat * gamma[d];
101 out_bf16[d] = float_to_bf16(y);
102 }
103#endif
104
105 // Zero padding
106 for (int d = D; d < aligned; ++d) {
107 out_bf16[d] = 0;
108 }
109 }
110}

References bf16_to_float(), and float_to_bf16().

◆ rmsnorm_forward_fp32_square_fp64_sum()

void rmsnorm_forward_fp32_square_fp64_sum ( const float *  input,
const float *  gamma,
float *  output,
float *  rstd_cache,
int  tokens,
int  d_model,
int  aligned_embed_dim,
float  eps 
)

◆ rmsnorm_forward_fp64_sum()

void rmsnorm_forward_fp64_sum ( const float *  input,
const float *  gamma,
float *  output,
float *  rstd_cache,
int  tokens,
int  d_model,
int  aligned_embed_dim,
float  eps 
)

Definition at line 137 of file rmsnorm_kernels.c.

145{
146 for (int t = 0; t < tokens; ++t) {
147 const float *x = input + (size_t)t * (size_t)aligned_embed_dim;
148 float *y = output + (size_t)t * (size_t)aligned_embed_dim;
149 /* This provider's contract requires an ascending scalar reduction.
150 * Keep the accumulator volatile so whole-program optimization cannot
151 * reassociate the sum or replace it with SIMD partial reductions. */
152 volatile double sum_sq = 0.0;
153 for (int d = 0; d < d_model; ++d) {
154 const float square = x[d] * x[d];
155 sum_sq = sum_sq + (double)square;
156 }
157 const float mean_sq = (float)(sum_sq / (double)d_model);
158 const float rstd = 1.0f / sqrtf(mean_sq + eps);
159 if (rstd_cache) {
160 rstd_cache[t] = rstd;
161 }
162 for (int d = 0; d < d_model; ++d) {
163 const float normalized = x[d] * rstd;
164 y[d] = normalized * gamma[d];
165 }
166 for (int d = d_model; d < aligned_embed_dim; ++d) {
167 y[d] = 0.0f;
168 }
169 }
170}

◆ rmsnorm_forward_int4()

void rmsnorm_forward_int4 ( const uint8_t *  input,
const float *  gamma,
uint8_t *  output,
float *  rstd_cache,
int  tokens,
int  d_model,
int  aligned_embed_dim,
float  eps,
float *  scratch_input,
float *  scratch_output 
)

Definition at line 78 of file rmsnorm_kernels_int4.c.

88{
89 if (!input || !gamma || !output) return;
90 if (!scratch_input || !scratch_output) return;
91
92 size_t total = (size_t)tokens * (size_t)aligned_embed_dim;
93
94 convert_int4_to_float(input, scratch_input, total);
95 rmsnorm_forward(scratch_input, gamma, scratch_output, rstd_cache,
96 tokens, d_model, aligned_embed_dim, eps);
97 convert_float_to_int4(scratch_output, output, total);
98}
void rmsnorm_forward(const float *input, const float *gamma, float *output, float *rstd_cache, int tokens, int d_model, int aligned_embed_dim, float eps)

References convert_float_to_int4(), convert_int4_to_float(), and rmsnorm_forward().

◆ rmsnorm_forward_int8()

void rmsnorm_forward_int8 ( const int8_t *  input,
const float *  gamma,
int8_t *  output,
float *  rstd_cache,
int  tokens,
int  d_model,
int  aligned_embed_dim,
float  eps,
float *  scratch_input,
float *  scratch_output 
)

Definition at line 58 of file rmsnorm_kernels_int8.c.

68{
69 if (!input || !gamma || !output) return;
70 if (!scratch_input || !scratch_output) return;
71
72 size_t total = (size_t)tokens * (size_t)aligned_embed_dim;
73
74 convert_int8_to_float(input, scratch_input, total);
75 rmsnorm_forward(scratch_input, gamma, scratch_output, rstd_cache,
76 tokens, d_model, aligned_embed_dim, eps);
77 convert_float_to_int8(scratch_output, output, total);
78}

References convert_float_to_int8(), convert_int8_to_float(), and rmsnorm_forward().

◆ rmsnorm_forward_kv_lora()

void rmsnorm_forward_kv_lora ( const float *  input,
const float *  gamma,
float *  output,
float *  rstd_cache,
int  tokens,
int  d_model,
int  aligned_embed_dim,
float  eps 
)

Definition at line 643 of file rmsnorm_kernels.c.

651{
652 rmsnorm_forward(input, gamma, output, rstd_cache, tokens, d_model, aligned_embed_dim, eps);
653}
void rmsnorm_forward(const float *input, const float *gamma, float *output, float *rstd_cache, int tokens, int d_model, int aligned_embed_dim, float eps)

References rmsnorm_forward().

◆ rmsnorm_forward_llama_production()

void rmsnorm_forward_llama_production ( const float *  input,
const float *  gamma,
float *  output,
float *  rstd_cache,
int  tokens,
int  d_model,
int  aligned_embed_dim,
float  eps 
)

Definition at line 196 of file rmsnorm_kernels.c.

204{
205 for (int t = 0; t < tokens; ++t) {
206 const float *x = input + (size_t)t * (size_t)aligned_embed_dim;
207 float *y = output + (size_t)t * (size_t)aligned_embed_dim;
208 volatile double sum_sq = 0.0;
209 for (int d = 0; d < d_model; ++d) {
210 const float square = x[d] * x[d];
211 sum_sq = sum_sq + (double)square;
212 }
213 const float mean_sq = (float)(sum_sq / (double)d_model);
214 const float rstd = rmsnorm_llama_production_rstd(mean_sq + eps);
215 if (rstd_cache) {
216 rstd_cache[t] = rstd;
217 }
218 for (int d = 0; d < d_model; ++d) {
219 /*
220 * Keep the RMSNorm + scale expression fused at the source level.
221 * llama.cpp's CPU graph fuses GGML_OP_RMS_NORM followed by
222 * GGML_OP_MUL and evaluates this left-associative expression in
223 * one kernel. Materializing the normalized value as a named
224 * float introduces a store/load rounding boundary under ICX and
225 * differs by one ULP for otherwise identical inputs.
226 */
227 y[d] = x[d] * rstd * gamma[d];
228 }
229 for (int d = d_model; d < aligned_embed_dim; ++d) {
230 y[d] = 0.0f;
231 }
232 }
233}
static float rmsnorm_llama_production_rstd(float mean_eps)

References rmsnorm_llama_production_rstd().

Referenced by qwen4_group_rmsnorm_llama(), recurrent_norm_gate_llama_avx2_forward(), and recurrent_norm_sigmoid_gate_llama_avx2_forward().

◆ rmsnorm_forward_no_weight()

void rmsnorm_forward_no_weight ( const float *  input,
float *  output,
float *  rstd_cache,
int  tokens,
int  d_model,
int  aligned_embed_dim,
float  eps 
)

Definition at line 655 of file rmsnorm_kernels.c.

662{
663 if (!input || !output || tokens <= 0 || d_model <= 0 || aligned_embed_dim <= 0) {
664 return;
665 }
666 const float inv_d = 1.0f / (float)d_model;
667 for (int t = 0; t < tokens; ++t) {
668 const float *x = input + (size_t)t * (size_t)aligned_embed_dim;
669 float *y = output + (size_t)t * (size_t)aligned_embed_dim;
670 double sum_sq = 0.0;
671 for (int d = 0; d < d_model; ++d) {
672 sum_sq += (double)x[d] * (double)x[d];
673 }
674 const float rstd = 1.0f / sqrtf((float)(sum_sq * (double)inv_d) + eps);
675 if (rstd_cache) {
676 rstd_cache[t] = rstd;
677 }
678 for (int d = 0; d < d_model; ++d) {
679 y[d] = x[d] * rstd;
680 }
681 for (int d = d_model; d < aligned_embed_dim; ++d) {
682 y[d] = 0.0f;
683 }
684 }
685}

Referenced by gemma4_v_norm_forward().

◆ rmsnorm_forward_parallel_dispatch()

void rmsnorm_forward_parallel_dispatch ( const float *  input,
const float *  gamma,
float *  output,
float *  rstd_cache,
int  tokens,
int  d_model,
int  aligned_embed_dim,
float  eps 
)

◆ rmsnorm_forward_pytorch_bf16_storage()

void rmsnorm_forward_pytorch_bf16_storage ( const float *  input,
const float *  gamma,
float *  output,
float *  rstd_cache,
int  tokens,
int  d_model,
int  aligned_embed_dim,
float  eps 
)

Definition at line 395 of file rmsnorm_kernels.c.

403{
405 input, gamma, output, rstd_cache, tokens, d_model,
406 aligned_embed_dim, aligned_embed_dim, eps, 0);
407}
static void rmsnorm_forward_pytorch_bf16_storage_impl(const float *input, const float *gamma, float *output, float *rstd_cache, int tokens, int d_model, int input_stride, int output_stride, float eps, int qwen3next_weight_order)

References rmsnorm_forward_pytorch_bf16_storage_impl().

Referenced by recurrent_norm_gate_pytorch_bf16_storage(), and recurrent_norm_sigmoid_gate_pytorch_bf16_storage().

◆ rmsnorm_forward_qwen3next_pytorch_bf16_storage()

void rmsnorm_forward_qwen3next_pytorch_bf16_storage ( const float *  input,
const float *  gamma,
float *  output,
float *  rstd_cache,
int  tokens,
int  d_model,
int  aligned_embed_dim,
float  eps 
)

Definition at line 424 of file rmsnorm_kernels.c.

433{
435 input, gamma, output, rstd_cache, tokens, d_model,
436 aligned_embed_dim, aligned_embed_dim, eps, 1);
437}

References rmsnorm_forward_pytorch_bf16_storage_impl().

Referenced by hyper_connection_mix_bf16(), and qwen4_group_rmsnorm_pytorch_bf16().

◆ rmsnorm_forward_strided_f32()

void rmsnorm_forward_strided_f32 ( const float *  input,
const float *  gamma,
float *  output,
float *  rstd_cache,
int  tokens,
int  d_model,
int  input_stride,
int  output_stride,
float  eps 
)

RMSNorm forward pass

Test:

test_rmsnorm.py::TestRMSNormForward::test_fp32_tokens

test_rmsnorm.py::TestRMSNormForward::test_fp32_single

test_rmsnorm.py::TestRMSNormForward::test_perf_rolled

test_layernorm.py::TestLayerNormForward::test_rmsnorm_compat

test_parity.py::test_rmsnorm_parity

RMSNorm: y[i] = gamma[i] * x[i] / sqrt(mean(x^2) + eps)

After changes: make test && make llamacpp-parity-full

Definition at line 492 of file rmsnorm_kernels.c.

501{
502 int T = tokens;
503 int D = d_model;
504
505 const char *exact_env = getenv("CK_RMSNORM_EXACT");
506 if (ck_strict_parity_enabled() || (exact_env && atoi(exact_env) != 0)) {
508 input, gamma, output, rstd_cache, T, D, input_stride, output_stride, eps
509 );
510 return;
511 }
512
513 for (int t = 0; t < T; ++t) {
514 const float *x = input + (size_t)t * (size_t)input_stride;
515 float *y = output + (size_t)t * (size_t)output_stride;
516
517#if defined(__AVX512F__)
518 // AVX-512: Process 16 floats at a time
519 __m512 sum_sq_vec = _mm512_setzero_ps();
520 int d = 0;
521
522 // Vectorized sum of squares
523 for (; d + 16 <= D; d += 16) {
524 __m512 xv = _mm512_loadu_ps(&x[d]);
525 sum_sq_vec = _mm512_fmadd_ps(xv, xv, sum_sq_vec);
526 }
527 float sum_sq = _mm512_reduce_add_ps(sum_sq_vec);
528
529 // Handle remaining elements
530 for (; d < D; ++d) {
531 sum_sq += x[d] * x[d];
532 }
533
534 float mean_sq = sum_sq / (float)D;
535 float rstd = 1.0f / sqrtf(mean_sq + eps);
536 if (rstd_cache) {
537 rstd_cache[t] = rstd;
538 }
539
540 // Apply normalization and scale (vectorized)
541 __m512 rstd_vec = _mm512_set1_ps(rstd);
542 d = 0;
543 for (; d + 16 <= D; d += 16) {
544 __m512 xv = _mm512_loadu_ps(&x[d]);
545 __m512 gv = _mm512_loadu_ps(&gamma[d]);
546 __m512 x_hat = _mm512_mul_ps(xv, rstd_vec);
547 __m512 yv = _mm512_mul_ps(x_hat, gv);
548 _mm512_storeu_ps(&y[d], yv);
549 }
550 // Handle remaining elements
551 for (; d < D; ++d) {
552 y[d] = x[d] * rstd * gamma[d];
553 }
554
555#elif defined(__AVX__)
556 // AVX: Process 8 floats at a time
557 __m256 sum_sq_vec = _mm256_setzero_ps();
558 int d = 0;
559
560 // Vectorized sum of squares (no FMA in AVX1, use mul + add)
561 for (; d + 8 <= D; d += 8) {
562 __m256 xv = _mm256_loadu_ps(&x[d]);
563 __m256 xv_sq = _mm256_mul_ps(xv, xv);
564 sum_sq_vec = _mm256_add_ps(sum_sq_vec, xv_sq);
565 }
566 float sum_sq = hsum256_ps_rmsnorm(sum_sq_vec);
567
568 // Handle remaining elements
569 for (; d < D; ++d) {
570 sum_sq += x[d] * x[d];
571 }
572
573 float mean_sq = sum_sq / (float)D;
574 float rstd = 1.0f / sqrtf(mean_sq + eps);
575 if (rstd_cache) {
576 rstd_cache[t] = rstd;
577 }
578
579 // Apply normalization and scale (vectorized)
580 __m256 rstd_vec = _mm256_set1_ps(rstd);
581 d = 0;
582 for (; d + 8 <= D; d += 8) {
583 __m256 xv = _mm256_loadu_ps(&x[d]);
584 __m256 gv = _mm256_loadu_ps(&gamma[d]);
585 __m256 x_hat = _mm256_mul_ps(xv, rstd_vec);
586 __m256 yv = _mm256_mul_ps(x_hat, gv);
587 _mm256_storeu_ps(&y[d], yv);
588 }
589 // Handle remaining elements
590 for (; d < D; ++d) {
591 y[d] = x[d] * rstd * gamma[d];
592 }
593
594#else
595 // Scalar fallback
596 float sum_sq = 0.0f;
597 for (int d = 0; d < D; ++d) {
598 float v = x[d];
599 sum_sq += v * v;
600 }
601 float mean_sq = sum_sq / (float)D;
602 float rstd = 1.0f / sqrtf(mean_sq + eps);
603 if (rstd_cache) {
604 rstd_cache[t] = rstd;
605 }
606
607 // Apply normalization and scale
608 for (int d = 0; d < D; ++d) {
609 float x_hat = x[d] * rstd;
610 y[d] = x_hat * gamma[d];
611 }
612#endif
613
614 // Zero padding (if any)
615 for (int d = D; d < output_stride; ++d) {
616 y[d] = 0.0f;
617 }
618 }
619}
static void rmsnorm_forward_strict_scalar(const float *input, const float *gamma, float *output, float *rstd_cache, int tokens, int d_model, int input_stride, int output_stride, float eps)

References ck_strict_parity_enabled(), and rmsnorm_forward_strict_scalar().

Referenced by rmsnorm_forward().

◆ rmsnorm_forward_strided_pytorch_bf16_storage()

void rmsnorm_forward_strided_pytorch_bf16_storage ( const float *  input,
const float *  gamma,
float *  output,
float *  rstd_cache,
int  tokens,
int  d_model,
int  input_stride,
int  output_stride,
float  eps 
)

Definition at line 409 of file rmsnorm_kernels.c.

418{
420 input, gamma, output, rstd_cache, tokens, d_model,
421 input_stride, output_stride, eps, 0);
422}

References rmsnorm_forward_pytorch_bf16_storage_impl().

◆ rope_backward()

void rope_backward ( const float *  d_out,
float *  d_x,
const float *  cos_cache,
const float *  sin_cache,
int  num_heads,
int  num_tokens,
int  head_dim,
int  aligned_head_dim,
int  pos_offset 
)

RoPE backward (inverse rotation)

Test:

test_rope.py::TestRoPEBackward::test_rope_backward

test_rope.py::TestRoPEBackward::test_rope_backward_vs_separate

RoPE backward: inverse rotation (rotate by -θ). Since cos(-θ) = cos(θ) and sin(-θ) = -sin(θ): d_x[2i] = d0 * c + d1 * s d_x[2i+1] = -d0 * s + d1 * c

After changes: make test

Definition at line 884 of file rope_kernels.c.

893{
894 size_t head_stride = (size_t)num_tokens * (size_t)aligned_head_dim;
895 int half_dim = head_dim / 2;
896
897 for (int h = 0; h < num_heads; ++h) {
898 for (int t = 0; t < num_tokens; ++t) {
899 int pos = pos_offset + t;
900 const float *cos_row = cos_cache + pos * half_dim;
901 const float *sin_row = sin_cache + pos * half_dim;
902
903 size_t idx = h * head_stride + (size_t)t * (size_t)aligned_head_dim;
904 const float *d_out_row = d_out + idx;
905 float *d_x_row = d_x + idx;
906
907#if defined(__AVX512F__)
908 int i = 0;
909 for (; i + 16 <= half_dim; i += 16) {
910 __m512 d0 = _mm512_loadu_ps(&d_out_row[i]);
911 __m512 d1 = _mm512_loadu_ps(&d_out_row[i + half_dim]);
912 __m512 c = _mm512_loadu_ps(&cos_row[i]);
913 __m512 s = _mm512_loadu_ps(&sin_row[i]);
914
915 // Inverse: d_x[i] = d0 * c + d1 * s
916 __m512 r0 = _mm512_fmadd_ps(d0, c, _mm512_mul_ps(d1, s));
917 // Inverse: d_x[i+half] = -d0 * s + d1 * c
918 __m512 r1 = _mm512_fmsub_ps(d1, c, _mm512_mul_ps(d0, s));
919
920 _mm512_storeu_ps(&d_x_row[i], r0);
921 _mm512_storeu_ps(&d_x_row[i + half_dim], r1);
922 }
923 for (; i < half_dim; ++i) {
924 float d0 = d_out_row[i];
925 float d1 = d_out_row[i + half_dim];
926 float c = cos_row[i];
927 float s = sin_row[i];
928 d_x_row[i] = d0 * c + d1 * s;
929 d_x_row[i + half_dim] = -d0 * s + d1 * c;
930 }
931
932#elif defined(__AVX__)
933 int i = 0;
934 for (; i + 8 <= half_dim; i += 8) {
935 __m256 d0 = _mm256_loadu_ps(&d_out_row[i]);
936 __m256 d1 = _mm256_loadu_ps(&d_out_row[i + half_dim]);
937 __m256 c = _mm256_loadu_ps(&cos_row[i]);
938 __m256 s = _mm256_loadu_ps(&sin_row[i]);
939
940 // Inverse: d_x[i] = d0 * c + d1 * s
941 __m256 d0c = _mm256_mul_ps(d0, c);
942 __m256 d1s = _mm256_mul_ps(d1, s);
943 __m256 r0 = _mm256_add_ps(d0c, d1s);
944
945 // Inverse: d_x[i+half] = -d0 * s + d1 * c = d1 * c - d0 * s
946 __m256 d1c = _mm256_mul_ps(d1, c);
947 __m256 d0s = _mm256_mul_ps(d0, s);
948 __m256 r1 = _mm256_sub_ps(d1c, d0s);
949
950 _mm256_storeu_ps(&d_x_row[i], r0);
951 _mm256_storeu_ps(&d_x_row[i + half_dim], r1);
952 }
953 for (; i < half_dim; ++i) {
954 float d0 = d_out_row[i];
955 float d1 = d_out_row[i + half_dim];
956 float c = cos_row[i];
957 float s = sin_row[i];
958 d_x_row[i] = d0 * c + d1 * s;
959 d_x_row[i + half_dim] = -d0 * s + d1 * c;
960 }
961
962#else
963 for (int i = 0; i < half_dim; ++i) {
964 float d0 = d_out_row[i];
965 float d1 = d_out_row[i + half_dim];
966 float c = cos_row[i];
967 float s = sin_row[i];
968
969 // Inverse rotation: rotate by -θ
970 d_x_row[i] = d0 * c + d1 * s;
971 d_x_row[i + half_dim] = -d0 * s + d1 * c;
972 }
973#endif
974
975 for (int i = head_dim; i < aligned_head_dim; ++i) {
976 d_x_row[i] = 0.0f;
977 }
978 }
979 }
980}

Referenced by rope_backward_bf16(), and rope_backward_qk().

◆ rope_backward_bf16()

void rope_backward_bf16 ( const uint16_t *  d_out,
uint16_t *  d_x,
const float *  cos_cache,
const float *  sin_cache,
int  num_heads,
int  num_tokens,
int  head_dim,
int  aligned_head_dim,
int  pos_offset,
float *  scratch_d_out,
float *  scratch_d_x 
)

Definition at line 67 of file rope_kernels_bf16.c.

78{
79 if (!scratch_d_out || !scratch_d_x) return;
80
81 size_t total = (size_t)num_heads * (size_t)num_tokens * (size_t)aligned_head_dim;
82
83 bf16_tensor_to_float(d_out, scratch_d_out, total);
84 rope_backward(scratch_d_out, scratch_d_x, cos_cache, sin_cache,
85 num_heads, num_tokens, head_dim, aligned_head_dim, pos_offset);
86 float_tensor_to_bf16(scratch_d_x, d_x, total);
87}
void rope_backward(const float *d_out, float *d_x, const float *cos_cache, const float *sin_cache, int num_heads, int num_tokens, int head_dim, int aligned_head_dim, int pos_offset)

References bf16_tensor_to_float(), float_tensor_to_bf16(), and rope_backward().

Referenced by rope_backward_qk_bf16().

◆ rope_backward_inplace()

void rope_backward_inplace ( float *  d_x,
const float *  cos_cache,
const float *  sin_cache,
int  num_heads,
int  num_tokens,
int  head_dim,
int  aligned_head_dim,
int  pos_offset 
)

RoPE backward in-place (overwrite with inverse rotation)

Test:
test_rope.py::TestRoPEBackward::test_rope_backward_inplace

In-place backward: overwrite d_out with inverse-rotated gradients. Useful when d_x == d_out is acceptable (saves memory).

After changes: make test

Definition at line 991 of file rope_kernels.c.

999{
1000 size_t head_stride = (size_t)num_tokens * (size_t)aligned_head_dim;
1001 int half_dim = head_dim / 2;
1002
1003 for (int h = 0; h < num_heads; ++h) {
1004 for (int t = 0; t < num_tokens; ++t) {
1005 int pos = pos_offset + t;
1006 const float *cos_row = cos_cache + pos * half_dim;
1007 const float *sin_row = sin_cache + pos * half_dim;
1008
1009 float *d_row = d_x + h * head_stride + (size_t)t * (size_t)aligned_head_dim;
1010
1011#if defined(__AVX512F__)
1012 int i = 0;
1013 for (; i + 16 <= half_dim; i += 16) {
1014 __m512 d0 = _mm512_loadu_ps(&d_row[i]);
1015 __m512 d1 = _mm512_loadu_ps(&d_row[i + half_dim]);
1016 __m512 c = _mm512_loadu_ps(&cos_row[i]);
1017 __m512 s = _mm512_loadu_ps(&sin_row[i]);
1018
1019 __m512 r0 = _mm512_fmadd_ps(d0, c, _mm512_mul_ps(d1, s));
1020 __m512 r1 = _mm512_fmsub_ps(d1, c, _mm512_mul_ps(d0, s));
1021
1022 _mm512_storeu_ps(&d_row[i], r0);
1023 _mm512_storeu_ps(&d_row[i + half_dim], r1);
1024 }
1025 for (; i < half_dim; ++i) {
1026 float d0 = d_row[i];
1027 float d1 = d_row[i + half_dim];
1028 float c = cos_row[i];
1029 float s = sin_row[i];
1030 d_row[i] = d0 * c + d1 * s;
1031 d_row[i + half_dim] = -d0 * s + d1 * c;
1032 }
1033
1034#elif defined(__AVX__)
1035 int i = 0;
1036 for (; i + 8 <= half_dim; i += 8) {
1037 __m256 d0 = _mm256_loadu_ps(&d_row[i]);
1038 __m256 d1 = _mm256_loadu_ps(&d_row[i + half_dim]);
1039 __m256 c = _mm256_loadu_ps(&cos_row[i]);
1040 __m256 s = _mm256_loadu_ps(&sin_row[i]);
1041
1042 __m256 d0c = _mm256_mul_ps(d0, c);
1043 __m256 d1s = _mm256_mul_ps(d1, s);
1044 __m256 r0 = _mm256_add_ps(d0c, d1s);
1045
1046 __m256 d1c = _mm256_mul_ps(d1, c);
1047 __m256 d0s = _mm256_mul_ps(d0, s);
1048 __m256 r1 = _mm256_sub_ps(d1c, d0s);
1049
1050 _mm256_storeu_ps(&d_row[i], r0);
1051 _mm256_storeu_ps(&d_row[i + half_dim], r1);
1052 }
1053 for (; i < half_dim; ++i) {
1054 float d0 = d_row[i];
1055 float d1 = d_row[i + half_dim];
1056 float c = cos_row[i];
1057 float s = sin_row[i];
1058 d_row[i] = d0 * c + d1 * s;
1059 d_row[i + half_dim] = -d0 * s + d1 * c;
1060 }
1061
1062#else
1063 for (int i = 0; i < half_dim; ++i) {
1064 float d0 = d_row[i];
1065 float d1 = d_row[i + half_dim];
1066 float c = cos_row[i];
1067 float s = sin_row[i];
1068
1069 // Inverse rotation: rotate by -θ
1070 d_row[i] = d0 * c + d1 * s;
1071 d_row[i + half_dim] = -d0 * s + d1 * c;
1072 }
1073#endif
1074
1075 for (int i = head_dim; i < aligned_head_dim; ++i) {
1076 d_row[i] = 0.0f;
1077 }
1078 }
1079 }
1080}

◆ rope_backward_qk()

void rope_backward_qk ( const float *  d_q_out,
const float *  d_k_out,
float *  d_q,
float *  d_k,
const float *  cos_cache,
const float *  sin_cache,
int  num_heads,
int  num_kv_heads,
int  num_tokens,
int  head_dim,
int  aligned_head_dim,
int  pos_offset 
)

RoPE backward for both dQ and dK

Test:
test_rope.py::TestRoPEBackward::test_rope_backward_qk

Combined RoPE backward for both dQ and dK gradients.

After changes: make test

Definition at line 2826 of file rope_kernels.c.

2838{
2839 rope_backward(d_q_out, d_q, cos_cache, sin_cache, num_heads, num_tokens, head_dim, aligned_head_dim, pos_offset);
2840 rope_backward(d_k_out, d_k, cos_cache, sin_cache, num_kv_heads, num_tokens, head_dim, aligned_head_dim, pos_offset);
2841}
void rope_backward(const float *d_out, float *d_x, const float *cos_cache, const float *sin_cache, int num_heads, int num_tokens, int head_dim, int aligned_head_dim, int pos_offset)

References rope_backward().

Referenced by ck_layer_backward_rmsnorm_swiglu().

◆ rope_backward_qk_bf16()

void rope_backward_qk_bf16 ( const uint16_t *  d_q_out,
const uint16_t *  d_k_out,
uint16_t *  d_q,
uint16_t *  d_k,
const float *  cos_cache,
const float *  sin_cache,
int  num_heads,
int  num_kv_heads,
int  num_tokens,
int  head_dim,
int  aligned_head_dim,
int  pos_offset,
float *  scratch_dq_out,
float *  scratch_dq,
float *  scratch_dk_out,
float *  scratch_dk 
)

Definition at line 139 of file rope_kernels_bf16.c.

155{
156 if (!d_q_out || !d_k_out || !d_q || !d_k) return;
157
158 rope_backward_bf16(d_q_out, d_q, cos_cache, sin_cache,
159 num_heads, num_tokens, head_dim, aligned_head_dim, pos_offset,
160 scratch_dq_out, scratch_dq);
161 rope_backward_bf16(d_k_out, d_k, cos_cache, sin_cache,
162 num_kv_heads, num_tokens, head_dim, aligned_head_dim, pos_offset,
163 scratch_dk_out, scratch_dk);
164}
void rope_backward_bf16(const uint16_t *d_out, uint16_t *d_x, const float *cos_cache, const float *sin_cache, int num_heads, int num_tokens, int head_dim, int aligned_head_dim, int pos_offset, float *scratch_d_out, float *scratch_d_x)

References rope_backward_bf16().

◆ rope_backward_qk_pairwise_with_rotary_dim()

void rope_backward_qk_pairwise_with_rotary_dim ( const float *  d_q_out,
const float *  d_k_out,
float *  d_q,
float *  d_k,
const float *  cos_cache,
const float *  sin_cache,
int  num_heads,
int  num_kv_heads,
int  num_tokens,
int  head_dim,
int  aligned_head_dim,
int  pos_offset,
int  rotary_dim 
)

Definition at line 2843 of file rope_kernels.c.

2856{
2857 size_t q_head_stride = (size_t)num_tokens * (size_t)aligned_head_dim;
2858 size_t k_head_stride = (size_t)num_tokens * (size_t)aligned_head_dim;
2859
2860 for (int h = 0; h < num_heads; ++h) {
2862 d_q_out + (size_t)h * q_head_stride,
2863 d_q + (size_t)h * q_head_stride,
2864 cos_cache,
2865 sin_cache,
2866 num_tokens,
2867 head_dim,
2868 aligned_head_dim,
2869 pos_offset,
2870 rotary_dim
2871 );
2872 }
2873
2874 for (int h = 0; h < num_kv_heads; ++h) {
2876 d_k_out + (size_t)h * k_head_stride,
2877 d_k + (size_t)h * k_head_stride,
2878 cos_cache,
2879 sin_cache,
2880 num_tokens,
2881 head_dim,
2882 aligned_head_dim,
2883 pos_offset,
2884 rotary_dim
2885 );
2886 }
2887}
static void rope_backward_apply_head_pairwise(const float *d_out, float *d_x, const float *cos_cache, const float *sin_cache, int num_tokens, int head_dim, int aligned_head_dim, int pos_offset, int rotary_dim)

References rope_backward_apply_head_pairwise().

◆ rope_forward()

void rope_forward ( float *  x,
const float *  cos_cache,
const float *  sin_cache,
int  num_heads,
int  num_tokens,
int  head_dim,
int  aligned_head_dim,
int  pos_offset 
)

RoPE forward (head-major layout, in-place)

Test:

test_rope.py::TestRoPEForward::test_rope_forward

test_rope.py::TestRoPEForward::test_rope_vs_separate

test_parity.py::test_rope_parity

Applies rotary position embeddings in-place to Q or K tensor. x: [num_heads, num_tokens, head_dim] head-major

After changes: make test && make llamacpp-parity-full

Definition at line 796 of file rope_kernels.c.

804{
805 rope_forward_with_rotary_dim(x, cos_cache, sin_cache, num_heads, num_tokens,
806 head_dim, aligned_head_dim, pos_offset, head_dim);
807}
void rope_forward_with_rotary_dim(float *x, const float *cos_cache, const float *sin_cache, int num_heads, int num_tokens, int head_dim, int aligned_head_dim, int pos_offset, int rotary_dim)

References rope_forward_with_rotary_dim().

Referenced by model_layer_0_decode(), model_layer_0_decode(), model_layer_0_decode(), model_layer_0_decode(), model_layer_10_decode(), model_layer_10_decode(), model_layer_10_decode(), model_layer_10_decode(), model_layer_11_decode(), model_layer_11_decode(), model_layer_11_decode(), model_layer_11_decode(), model_layer_12_decode(), model_layer_12_decode(), model_layer_12_decode(), model_layer_12_decode(), model_layer_13_decode(), model_layer_13_decode(), model_layer_13_decode(), model_layer_13_decode(), model_layer_14_decode(), model_layer_14_decode(), model_layer_14_decode(), model_layer_14_decode(), model_layer_15_decode(), model_layer_15_decode(), model_layer_15_decode(), model_layer_15_decode(), model_layer_16_decode(), model_layer_16_decode(), model_layer_16_decode(), model_layer_16_decode(), model_layer_17_decode(), model_layer_17_decode(), model_layer_17_decode(), model_layer_17_decode(), model_layer_18_decode(), model_layer_18_decode(), model_layer_18_decode(), model_layer_18_decode(), model_layer_19_decode(), model_layer_19_decode(), model_layer_19_decode(), model_layer_19_decode(), model_layer_1_decode(), model_layer_1_decode(), model_layer_1_decode(), model_layer_1_decode(), model_layer_20_decode(), model_layer_20_decode(), model_layer_20_decode(), model_layer_20_decode(), model_layer_21_decode(), model_layer_21_decode(), model_layer_21_decode(), model_layer_21_decode(), model_layer_22_decode(), model_layer_22_decode(), model_layer_22_decode(), model_layer_22_decode(), model_layer_23_decode(), model_layer_23_decode(), model_layer_23_decode(), model_layer_23_decode(), model_layer_2_decode(), model_layer_2_decode(), model_layer_2_decode(), model_layer_2_decode(), model_layer_3_decode(), model_layer_3_decode(), model_layer_3_decode(), model_layer_3_decode(), model_layer_4_decode(), model_layer_4_decode(), model_layer_4_decode(), model_layer_4_decode(), model_layer_5_decode(), model_layer_5_decode(), model_layer_5_decode(), model_layer_5_decode(), model_layer_6_decode(), model_layer_6_decode(), model_layer_6_decode(), model_layer_6_decode(), model_layer_7_decode(), model_layer_7_decode(), model_layer_7_decode(), model_layer_7_decode(), model_layer_8_decode(), model_layer_8_decode(), model_layer_8_decode(), model_layer_8_decode(), model_layer_9_decode(), model_layer_9_decode(), model_layer_9_decode(), model_layer_9_decode(), qwen2_0_5b_decode_layer_0_decode(), qwen2_0_5b_decode_layer_0_decode(), qwen2_0_5b_decode_layer_10_decode(), qwen2_0_5b_decode_layer_10_decode(), qwen2_0_5b_decode_layer_11_decode(), qwen2_0_5b_decode_layer_11_decode(), qwen2_0_5b_decode_layer_12_decode(), qwen2_0_5b_decode_layer_12_decode(), qwen2_0_5b_decode_layer_13_decode(), qwen2_0_5b_decode_layer_13_decode(), qwen2_0_5b_decode_layer_14_decode(), qwen2_0_5b_decode_layer_14_decode(), qwen2_0_5b_decode_layer_15_decode(), qwen2_0_5b_decode_layer_15_decode(), qwen2_0_5b_decode_layer_16_decode(), qwen2_0_5b_decode_layer_16_decode(), qwen2_0_5b_decode_layer_17_decode(), qwen2_0_5b_decode_layer_17_decode(), qwen2_0_5b_decode_layer_18_decode(), qwen2_0_5b_decode_layer_18_decode(), qwen2_0_5b_decode_layer_19_decode(), qwen2_0_5b_decode_layer_19_decode(), qwen2_0_5b_decode_layer_1_decode(), qwen2_0_5b_decode_layer_1_decode(), qwen2_0_5b_decode_layer_20_decode(), qwen2_0_5b_decode_layer_20_decode(), qwen2_0_5b_decode_layer_21_decode(), qwen2_0_5b_decode_layer_21_decode(), qwen2_0_5b_decode_layer_22_decode(), qwen2_0_5b_decode_layer_22_decode(), qwen2_0_5b_decode_layer_23_decode(), qwen2_0_5b_decode_layer_23_decode(), qwen2_0_5b_decode_layer_2_decode(), qwen2_0_5b_decode_layer_2_decode(), qwen2_0_5b_decode_layer_3_decode(), qwen2_0_5b_decode_layer_3_decode(), qwen2_0_5b_decode_layer_4_decode(), qwen2_0_5b_decode_layer_4_decode(), qwen2_0_5b_decode_layer_5_decode(), qwen2_0_5b_decode_layer_5_decode(), qwen2_0_5b_decode_layer_6_decode(), qwen2_0_5b_decode_layer_6_decode(), qwen2_0_5b_decode_layer_7_decode(), qwen2_0_5b_decode_layer_7_decode(), qwen2_0_5b_decode_layer_8_decode(), qwen2_0_5b_decode_layer_8_decode(), qwen2_0_5b_decode_layer_9_decode(), and qwen2_0_5b_decode_layer_9_decode().

◆ rope_forward_bf16()

void rope_forward_bf16 ( uint16_t *  x,
const float *  cos_cache,
const float *  sin_cache,
int  num_heads,
int  num_tokens,
int  head_dim,
int  aligned_head_dim,
int  pos_offset,
float *  scratch 
)

Definition at line 28 of file rope_kernels_bf16.c.

37{
38 rope_forward_bf16_with_rotary_dim(x, cos_cache, sin_cache, num_heads, num_tokens,
39 head_dim, aligned_head_dim, pos_offset, head_dim, scratch);
40}
void rope_forward_bf16_with_rotary_dim(uint16_t *x, const float *cos_cache, const float *sin_cache, int num_heads, int num_tokens, int head_dim, int aligned_head_dim, int pos_offset, int rotary_dim, float *scratch)

References rope_forward_bf16_with_rotary_dim().

◆ rope_forward_bf16_with_rotary_dim()

void rope_forward_bf16_with_rotary_dim ( uint16_t *  x,
const float *  cos_cache,
const float *  sin_cache,
int  num_heads,
int  num_tokens,
int  head_dim,
int  aligned_head_dim,
int  pos_offset,
int  rotary_dim,
float *  scratch 
)

Definition at line 42 of file rope_kernels_bf16.c.

52{
53 if (!scratch) return;
54
55 size_t total = (size_t)num_heads * (size_t)num_tokens * (size_t)aligned_head_dim;
56
57 bf16_tensor_to_float(x, scratch, total);
58 rope_forward_with_rotary_dim(scratch, cos_cache, sin_cache,
59 num_heads, num_tokens, head_dim, aligned_head_dim, pos_offset, rotary_dim);
60 float_tensor_to_bf16(scratch, x, total);
61}
void rope_forward_with_rotary_dim(float *x, const float *cos_cache, const float *sin_cache, int num_heads, int num_tokens, int head_dim, int aligned_head_dim, int pos_offset, int rotary_dim)

References bf16_tensor_to_float(), float_tensor_to_bf16(), and rope_forward_with_rotary_dim().

Referenced by rope_forward_bf16(), and rope_forward_qk_bf16_with_rotary_dim().

◆ rope_forward_q_split_direct_f32()

void rope_forward_q_split_direct_f32 ( float *  q,
const float *  freq_factors,
int  use_freq_factors,
int  num_heads,
int  num_tokens,
int  head_dim,
int  aligned_head_dim,
int  pos_offset,
int  rotary_dim,
float  freq_base 
)

Definition at line 1301 of file rope_kernels.c.

1311{
1312 rope_forward_split_direct_one(q, freq_factors, use_freq_factors,
1313 num_heads, num_tokens, head_dim, aligned_head_dim,
1314 pos_offset, rotary_dim, freq_base);
1315}
static void rope_forward_split_direct_one(float *x, const float *freq_factors, int use_freq_factors, int num_heads, int num_tokens, int head_dim, int aligned_head_dim, int pos_offset, int rotary_dim, float freq_base)

References rope_forward_split_direct_one().

◆ rope_forward_qk()

void rope_forward_qk ( float *  q,
float *  k,
const float *  cos_cache,
const float *  sin_cache,
int  num_heads,
int  num_kv_heads,
int  num_tokens,
int  head_dim,
int  aligned_head_dim,
int  pos_offset 
)

RoPE forward for both Q and K (common inference pattern)

Test:

test_rope.py::TestRoPEForward::test_rope_forward_qk

test_fused_attention_decode.py::TestFusedAttentionDecode::test_qk_rope

test_parity.py::test_rope_qk_parity

Combined RoPE forward for both Q and K in one call. q: [num_heads, num_tokens, head_dim] k: [num_kv_heads, num_tokens, head_dim]

After changes: make test && make llamacpp-parity-full

Definition at line 1094 of file rope_kernels.c.

1104{
1105 rope_forward_qk_with_rotary_dim(q, k, cos_cache, sin_cache, num_heads, num_kv_heads,
1106 num_tokens, head_dim, aligned_head_dim, pos_offset, head_dim);
1107}
void rope_forward_qk_with_rotary_dim(float *q, float *k, const float *cos_cache, const float *sin_cache, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int pos_offset, int rotary_dim)

References rope_forward_qk_with_rotary_dim().

Referenced by ck_layer_forward_rmsnorm_swiglu(), ck_layer_forward_rmsnorm_swiglu_decode(), ck_layer_forward_rmsnorm_swiglu_decode_fused(), ck_layer_forward_rmsnorm_swiglu_decode_fused_attn_impl(), ck_layer_forward_rmsnorm_swiglu_decode_q4_k(), ck_layer_forward_rmsnorm_swiglu_decode_quant(), ck_layer_forward_rmsnorm_swiglu_q4_k(), ck_layer_forward_rmsnorm_swiglu_quant(), ck_layer_forward_rmsnorm_swiglu_ref(), qwen2_0_5b_decode_layer_0_decode(), qwen2_0_5b_decode_layer_0_decode(), qwen2_0_5b_decode_layer_0_decode(), qwen2_0_5b_decode_layer_0_prefill(), qwen2_0_5b_decode_layer_0_prefill(), qwen2_0_5b_decode_layer_10_decode(), qwen2_0_5b_decode_layer_10_decode(), qwen2_0_5b_decode_layer_10_decode(), qwen2_0_5b_decode_layer_10_prefill(), qwen2_0_5b_decode_layer_10_prefill(), qwen2_0_5b_decode_layer_11_decode(), qwen2_0_5b_decode_layer_11_decode(), qwen2_0_5b_decode_layer_11_decode(), qwen2_0_5b_decode_layer_11_prefill(), qwen2_0_5b_decode_layer_11_prefill(), qwen2_0_5b_decode_layer_12_decode(), qwen2_0_5b_decode_layer_12_decode(), qwen2_0_5b_decode_layer_12_decode(), qwen2_0_5b_decode_layer_12_prefill(), qwen2_0_5b_decode_layer_12_prefill(), qwen2_0_5b_decode_layer_13_decode(), qwen2_0_5b_decode_layer_13_decode(), qwen2_0_5b_decode_layer_13_decode(), qwen2_0_5b_decode_layer_13_prefill(), qwen2_0_5b_decode_layer_13_prefill(), qwen2_0_5b_decode_layer_14_decode(), qwen2_0_5b_decode_layer_14_decode(), qwen2_0_5b_decode_layer_14_decode(), qwen2_0_5b_decode_layer_14_prefill(), qwen2_0_5b_decode_layer_14_prefill(), qwen2_0_5b_decode_layer_15_decode(), qwen2_0_5b_decode_layer_15_decode(), qwen2_0_5b_decode_layer_15_decode(), qwen2_0_5b_decode_layer_15_prefill(), qwen2_0_5b_decode_layer_15_prefill(), qwen2_0_5b_decode_layer_16_decode(), qwen2_0_5b_decode_layer_16_decode(), qwen2_0_5b_decode_layer_16_decode(), qwen2_0_5b_decode_layer_16_prefill(), qwen2_0_5b_decode_layer_16_prefill(), qwen2_0_5b_decode_layer_17_decode(), qwen2_0_5b_decode_layer_17_decode(), qwen2_0_5b_decode_layer_17_decode(), qwen2_0_5b_decode_layer_17_prefill(), qwen2_0_5b_decode_layer_17_prefill(), qwen2_0_5b_decode_layer_18_decode(), qwen2_0_5b_decode_layer_18_decode(), qwen2_0_5b_decode_layer_18_decode(), qwen2_0_5b_decode_layer_18_prefill(), qwen2_0_5b_decode_layer_18_prefill(), qwen2_0_5b_decode_layer_19_decode(), qwen2_0_5b_decode_layer_19_decode(), qwen2_0_5b_decode_layer_19_decode(), qwen2_0_5b_decode_layer_19_prefill(), qwen2_0_5b_decode_layer_19_prefill(), qwen2_0_5b_decode_layer_1_decode(), qwen2_0_5b_decode_layer_1_decode(), qwen2_0_5b_decode_layer_1_decode(), qwen2_0_5b_decode_layer_1_prefill(), qwen2_0_5b_decode_layer_1_prefill(), qwen2_0_5b_decode_layer_20_decode(), qwen2_0_5b_decode_layer_20_decode(), qwen2_0_5b_decode_layer_20_decode(), qwen2_0_5b_decode_layer_20_prefill(), qwen2_0_5b_decode_layer_20_prefill(), qwen2_0_5b_decode_layer_21_decode(), qwen2_0_5b_decode_layer_21_decode(), qwen2_0_5b_decode_layer_21_decode(), qwen2_0_5b_decode_layer_21_prefill(), qwen2_0_5b_decode_layer_21_prefill(), qwen2_0_5b_decode_layer_22_decode(), qwen2_0_5b_decode_layer_22_decode(), qwen2_0_5b_decode_layer_22_decode(), qwen2_0_5b_decode_layer_22_prefill(), qwen2_0_5b_decode_layer_22_prefill(), qwen2_0_5b_decode_layer_23_decode(), qwen2_0_5b_decode_layer_23_decode(), qwen2_0_5b_decode_layer_23_decode(), qwen2_0_5b_decode_layer_23_prefill(), qwen2_0_5b_decode_layer_23_prefill(), qwen2_0_5b_decode_layer_2_decode(), qwen2_0_5b_decode_layer_2_decode(), qwen2_0_5b_decode_layer_2_decode(), qwen2_0_5b_decode_layer_2_prefill(), qwen2_0_5b_decode_layer_2_prefill(), qwen2_0_5b_decode_layer_3_decode(), qwen2_0_5b_decode_layer_3_decode(), qwen2_0_5b_decode_layer_3_decode(), qwen2_0_5b_decode_layer_3_prefill(), qwen2_0_5b_decode_layer_3_prefill(), qwen2_0_5b_decode_layer_4_decode(), qwen2_0_5b_decode_layer_4_decode(), qwen2_0_5b_decode_layer_4_decode(), qwen2_0_5b_decode_layer_4_prefill(), qwen2_0_5b_decode_layer_4_prefill(), qwen2_0_5b_decode_layer_5_decode(), qwen2_0_5b_decode_layer_5_decode(), qwen2_0_5b_decode_layer_5_decode(), qwen2_0_5b_decode_layer_5_prefill(), qwen2_0_5b_decode_layer_5_prefill(), qwen2_0_5b_decode_layer_6_decode(), qwen2_0_5b_decode_layer_6_decode(), qwen2_0_5b_decode_layer_6_decode(), qwen2_0_5b_decode_layer_6_prefill(), qwen2_0_5b_decode_layer_6_prefill(), qwen2_0_5b_decode_layer_7_decode(), qwen2_0_5b_decode_layer_7_decode(), qwen2_0_5b_decode_layer_7_decode(), qwen2_0_5b_decode_layer_7_prefill(), qwen2_0_5b_decode_layer_7_prefill(), qwen2_0_5b_decode_layer_8_decode(), qwen2_0_5b_decode_layer_8_decode(), qwen2_0_5b_decode_layer_8_decode(), qwen2_0_5b_decode_layer_8_prefill(), qwen2_0_5b_decode_layer_8_prefill(), qwen2_0_5b_decode_layer_9_decode(), qwen2_0_5b_decode_layer_9_decode(), qwen2_0_5b_decode_layer_9_decode(), qwen2_0_5b_decode_layer_9_prefill(), and qwen2_0_5b_decode_layer_9_prefill().

◆ rope_forward_qk_bf16()

void rope_forward_qk_bf16 ( uint16_t *  q,
uint16_t *  k,
const float *  cos_cache,
const float *  sin_cache,
int  num_heads,
int  num_kv_heads,
int  num_tokens,
int  head_dim,
int  aligned_head_dim,
int  pos_offset,
float *  scratch_q,
float *  scratch_k 
)

Definition at line 94 of file rope_kernels_bf16.c.

106{
107 rope_forward_qk_bf16_with_rotary_dim(q, k, cos_cache, sin_cache, num_heads, num_kv_heads,
108 num_tokens, head_dim, aligned_head_dim, pos_offset,
109 head_dim, scratch_q, scratch_k);
110}
void rope_forward_qk_bf16_with_rotary_dim(uint16_t *q, uint16_t *k, const float *cos_cache, const float *sin_cache, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int pos_offset, int rotary_dim, float *scratch_q, float *scratch_k)

References rope_forward_qk_bf16_with_rotary_dim().

◆ rope_forward_qk_bf16_with_rotary_dim()

void rope_forward_qk_bf16_with_rotary_dim ( uint16_t *  q,
uint16_t *  k,
const float *  cos_cache,
const float *  sin_cache,
int  num_heads,
int  num_kv_heads,
int  num_tokens,
int  head_dim,
int  aligned_head_dim,
int  pos_offset,
int  rotary_dim,
float *  scratch_q,
float *  scratch_k 
)

Definition at line 112 of file rope_kernels_bf16.c.

125{
126 if (!q || !k) return;
127
128 rope_forward_bf16_with_rotary_dim(q, cos_cache, sin_cache,
129 num_heads, num_tokens, head_dim, aligned_head_dim, pos_offset,
130 rotary_dim, scratch_q);
131 rope_forward_bf16_with_rotary_dim(k, cos_cache, sin_cache,
132 num_kv_heads, num_tokens, head_dim, aligned_head_dim, pos_offset,
133 rotary_dim, scratch_k);
134}

References rope_forward_bf16_with_rotary_dim().

Referenced by rope_forward_qk_bf16().

◆ rope_forward_qk_gemma4_direct()

void rope_forward_qk_gemma4_direct ( float *  q,
float *  k,
const float *  freq_factors,
int  use_freq_factors,
int  num_heads,
int  num_kv_heads,
int  num_tokens,
int  head_dim,
int  aligned_head_dim,
int  pos_offset,
int  rotary_dim,
float  freq_base 
)

Definition at line 1317 of file rope_kernels.c.

1329{
1330 rope_forward_qk_split_direct_f32(q, k, freq_factors, use_freq_factors,
1331 num_heads, num_kv_heads, num_tokens,
1332 head_dim, aligned_head_dim, pos_offset,
1333 rotary_dim, freq_base);
1334}
void rope_forward_qk_split_direct_f32(float *q, float *k, const float *freq_factors, int use_freq_factors, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int pos_offset, int rotary_dim, float freq_base)

References rope_forward_qk_split_direct_f32().

◆ rope_forward_qk_gemma4v_vision_xy()

void rope_forward_qk_gemma4v_vision_xy ( float *  q,
float *  k,
int  num_heads,
int  num_kv_heads,
int  num_tokens,
int  head_dim,
int  aligned_head_dim,
int  grid_w,
int  rotary_dim,
float  freq_base 
)

Definition at line 1404 of file rope_kernels.c.

1414{
1415 rope_forward_gemma4v_vision_xy_one(q, num_heads, num_tokens, head_dim, aligned_head_dim, grid_w, rotary_dim, freq_base);
1416 rope_forward_gemma4v_vision_xy_one(k, num_kv_heads, num_tokens, head_dim, aligned_head_dim, grid_w, rotary_dim, freq_base);
1417}
static void rope_forward_gemma4v_vision_xy_one(float *x, int num_heads, int num_tokens, int head_dim, int aligned_head_dim, int grid_w, int rotary_dim, float freq_base)

References rope_forward_gemma4v_vision_xy_one().

◆ rope_forward_qk_pairwise_llama_cpu()

void rope_forward_qk_pairwise_llama_cpu ( float *  q,
float *  k,
const float *  cos_cache,
const float *  sin_cache,
int  num_heads,
int  num_kv_heads,
int  num_tokens,
int  head_dim,
int  aligned_head_dim,
int  pos_offset,
int  rotary_dim 
)

Definition at line 1540 of file rope_kernels.c.

1551{
1552 if (!q || !k || !cos_cache || !sin_cache || num_tokens <= 0) {
1553 return;
1554 }
1555 if (rotary_dim <= 0 || rotary_dim > head_dim) {
1556 rotary_dim = head_dim;
1557 }
1558 const int cache_half = rotary_dim / 2;
1559 const size_t head_stride =
1560 (size_t)num_tokens * (size_t)aligned_head_dim;
1561 if (num_tokens == 1) {
1562 const float *cos_row =
1563 cos_cache + (size_t)pos_offset * (size_t)cache_half;
1564 const float *sin_row =
1565 sin_cache + (size_t)pos_offset * (size_t)cache_half;
1567 q, cos_row, sin_row, num_heads, aligned_head_dim, rotary_dim);
1569 k, cos_row, sin_row, num_kv_heads, aligned_head_dim, rotary_dim);
1570 return;
1571 }
1572 for (int token = 0; token < num_tokens; ++token) {
1573 const int pos = pos_offset + token;
1574 const float *cos_row =
1575 cos_cache + (size_t)pos * (size_t)cache_half;
1576 const float *sin_row =
1577 sin_cache + (size_t)pos * (size_t)cache_half;
1578 for (int head = 0; head < num_heads; ++head) {
1580 q + (size_t)head * head_stride
1581 + (size_t)token * (size_t)aligned_head_dim,
1582 cos_row,
1583 sin_row,
1584 1,
1585 aligned_head_dim,
1586 rotary_dim);
1587 }
1588 for (int head = 0; head < num_kv_heads; ++head) {
1590 k + (size_t)head * head_stride
1591 + (size_t)token * (size_t)aligned_head_dim,
1592 cos_row,
1593 sin_row,
1594 1,
1595 aligned_head_dim,
1596 rotary_dim);
1597 }
1598 }
1599}
static void rope_apply_decode_pairwise_llama_cpu(float *rows, const float *cos_row, const float *sin_row, int num_heads, int aligned_head_dim, int rotary_dim)

References rope_apply_decode_pairwise_llama_cpu(), and token.

◆ rope_forward_qk_pairwise_with_rotary_dim()

void rope_forward_qk_pairwise_with_rotary_dim ( float *  q,
float *  k,
const float *  cos_cache,
const float *  sin_cache,
int  num_heads,
int  num_kv_heads,
int  num_tokens,
int  head_dim,
int  aligned_head_dim,
int  pos_offset,
int  rotary_dim 
)

Definition at line 1483 of file rope_kernels.c.

1494{
1495 size_t q_head_stride = (size_t)num_tokens * (size_t)aligned_head_dim;
1496 size_t k_head_stride = (size_t)num_tokens * (size_t)aligned_head_dim;
1497
1498 for (int h = 0; h < num_heads; ++h) {
1499 rope_apply_head_pairwise(q + (size_t) h * q_head_stride,
1500 cos_cache, sin_cache,
1501 num_tokens, head_dim, aligned_head_dim, pos_offset, rotary_dim);
1502 }
1503
1504 for (int h = 0; h < num_kv_heads; ++h) {
1505 rope_apply_head_pairwise(k + (size_t) h * k_head_stride,
1506 cos_cache, sin_cache,
1507 num_tokens, head_dim, aligned_head_dim, pos_offset, rotary_dim);
1508 }
1509}
static void rope_apply_head_pairwise(float *x, const float *cos_cache, const float *sin_cache, int num_tokens, int head_dim, int aligned_head_dim, int pos_offset, int rotary_dim)

References rope_apply_head_pairwise().

◆ rope_forward_qk_split_direct_f32()

void rope_forward_qk_split_direct_f32 ( float *  q,
float *  k,
const float *  freq_factors,
int  use_freq_factors,
int  num_heads,
int  num_kv_heads,
int  num_tokens,
int  head_dim,
int  aligned_head_dim,
int  pos_offset,
int  rotary_dim,
float  freq_base 
)

Definition at line 1180 of file rope_kernels.c.

1192{
1193 rope_forward_split_direct_one(q, freq_factors, use_freq_factors,
1194 num_heads, num_tokens, head_dim, aligned_head_dim,
1195 pos_offset, rotary_dim, freq_base);
1196 rope_forward_split_direct_one(k, freq_factors, use_freq_factors,
1197 num_kv_heads, num_tokens, head_dim, aligned_head_dim,
1198 pos_offset, rotary_dim, freq_base);
1199}

References rope_forward_split_direct_one().

Referenced by rope_forward_qk_gemma4_direct().

◆ rope_forward_qk_split_direct_token_range_f32()

void rope_forward_qk_split_direct_token_range_f32 ( float *  q,
float *  k,
const float *  freq_factors,
int  use_freq_factors,
int  num_heads,
int  num_kv_heads,
int  num_tokens,
int  head_dim,
int  aligned_head_dim,
int  pos_offset,
int  rotary_dim,
float  freq_base,
int  token_begin,
int  token_end 
)

Definition at line 1201 of file rope_kernels.c.

1216{
1217 if ((!q && !k) || num_tokens <= 0 || head_dim <= 0 ||
1218 aligned_head_dim <= 0 || token_begin < 0 ||
1219 token_begin >= token_end || token_end > num_tokens) {
1220 return;
1221 }
1222 if (rotary_dim <= 0 || rotary_dim > head_dim) {
1223 rotary_dim = head_dim;
1224 }
1225 if (freq_base <= 0.0f) {
1226 freq_base = 10000.0f;
1227 }
1228
1229 const int rotary_half = rotary_dim / 2;
1230 const size_t head_stride =
1231 (size_t)num_tokens * (size_t)aligned_head_dim;
1232 const float theta_scale = powf(freq_base, -2.0f / (float)rotary_dim);
1233
1234 for (int t = token_begin; t < token_end; ++t) {
1235 const float pos = (float)(pos_offset + t);
1236 for (int i = 0; i < rotary_half; ++i) {
1237 const int idx0 = i;
1238 const int idx1 = i + rotary_half;
1239 const float ff =
1240 (use_freq_factors && freq_factors) ? freq_factors[i] : 1.0f;
1241 const float theta = pos * powf(theta_scale, (float)i) / ff;
1242 const float c = cosf(theta);
1243 const float sv = sinf(theta);
1244
1245 for (int h = 0; q && h < num_heads; ++h) {
1246 float *row = q + (size_t)h * head_stride +
1247 (size_t)t * (size_t)aligned_head_dim;
1248 const float x0 = row[idx0];
1249 const float x1 = row[idx1];
1250 row[idx0] = x0 * c - x1 * sv;
1251 row[idx1] = x1 * c + x0 * sv;
1252 }
1253 for (int h = 0; k && h < num_kv_heads; ++h) {
1254 float *row = k + (size_t)h * head_stride +
1255 (size_t)t * (size_t)aligned_head_dim;
1256 const float x0 = row[idx0];
1257 const float x1 = row[idx1];
1258 row[idx0] = x0 * c - x1 * sv;
1259 row[idx1] = x1 * c + x0 * sv;
1260 }
1261 }
1262 }
1263}

◆ rope_forward_qk_split_llama_token_range_f32()

void rope_forward_qk_split_llama_token_range_f32 ( float *  q,
float *  k,
const float *  freq_factors,
int  use_freq_factors,
int  num_heads,
int  num_kv_heads,
int  num_tokens,
int  head_dim,
int  aligned_head_dim,
int  pos_offset,
int  rotary_dim,
float  freq_base,
int  token_begin,
int  token_end 
)

Definition at line 1265 of file rope_kernels.c.

1270{
1271 if ((!q && !k) || num_tokens <= 0 || head_dim <= 0 ||
1272 aligned_head_dim < head_dim || token_begin < 0 ||
1273 token_begin >= token_end || token_end > num_tokens) return;
1274 if (rotary_dim <= 0 || rotary_dim > head_dim) rotary_dim = head_dim;
1275 if (freq_base <= 0.0f) freq_base = 10000.0f;
1276 const int half = rotary_dim / 2;
1277 const size_t stride = (size_t)num_tokens * aligned_head_dim;
1278 const float scale = ck_rope_reference_powf(freq_base, -2.0f / rotary_dim);
1279 for (int t = token_begin; t < token_end; ++t) {
1280 /* The rounded recurrence is part of the ggml CPU numerical contract. */
1281 volatile float theta = (float)(pos_offset + t);
1282 for (int i = 0; i < half; ++i) {
1283 const float ff = use_freq_factors && freq_factors ? freq_factors[i] : 1.0f;
1284 const float angle = theta / ff;
1285 const float c = ck_rope_reference_cosf(angle);
1286 const float s = ck_rope_reference_sinf(angle);
1287 for (int h = 0; h < num_heads + num_kv_heads; ++h) {
1288 float *base = h < num_heads ? q : k;
1289 if (!base) continue;
1290 const int head = h < num_heads ? h : h - num_heads;
1291 float *row = base + (size_t)head * stride + (size_t)t * aligned_head_dim;
1292 const float x0 = row[i], x1 = row[i + half];
1293 row[i] = fmaf(x0, c, -(x1 * s));
1294 row[i + half] = fmaf(x0, s, x1 * c);
1295 }
1296 theta *= scale;
1297 }
1298 }
1299}
static float ck_rope_reference_sinf(float value)
static float ck_rope_reference_powf(float base, float exponent)
static float ck_rope_reference_cosf(float value)

References ck_rope_reference_cosf(), ck_rope_reference_powf(), and ck_rope_reference_sinf().

◆ rope_forward_qk_strided()

void rope_forward_qk_strided ( float *  q,
float *  k,
const float *  cos_cache,
const float *  sin_cache,
int  num_heads,
int  num_kv_heads,
int  num_tokens,
int  head_dim,
int  aligned_head_dim,
int  pos_offset,
int  q_stride_tokens,
int  k_stride_tokens 
)

RoPE forward for both Q and K with custom strides (KV cache layouts)

Test:

test_rope.py::TestRoPEForward::test_rope_forward_qk_strided

test_kv_cache_attention.py::TestKVCacheAttention::test_qk_rope_strided

Combined QK RoPE with configurable strides for KV cache layouts.

After changes: make test

Definition at line 2778 of file rope_kernels.c.

2790{
2791 rope_forward_qk_strided_with_rotary_dim(q, k, cos_cache, sin_cache, num_heads, num_kv_heads,
2792 num_tokens, head_dim, aligned_head_dim, pos_offset,
2793 q_stride_tokens, k_stride_tokens, head_dim);
2794}
void rope_forward_qk_strided_with_rotary_dim(float *q, float *k, const float *cos_cache, const float *sin_cache, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int pos_offset, int q_stride_tokens, int k_stride_tokens, int rotary_dim)

References rope_forward_qk_strided_with_rotary_dim().

Referenced by mega_fused_attention_prefill(), mega_fused_attention_prefill_q8_0(), model_layer_0_prefill(), model_layer_0_prefill(), model_layer_0_prefill(), model_layer_0_prefill(), model_layer_10_prefill(), model_layer_10_prefill(), model_layer_10_prefill(), model_layer_10_prefill(), model_layer_11_prefill(), model_layer_11_prefill(), model_layer_11_prefill(), model_layer_11_prefill(), model_layer_12_prefill(), model_layer_12_prefill(), model_layer_12_prefill(), model_layer_12_prefill(), model_layer_13_prefill(), model_layer_13_prefill(), model_layer_13_prefill(), model_layer_13_prefill(), model_layer_14_prefill(), model_layer_14_prefill(), model_layer_14_prefill(), model_layer_14_prefill(), model_layer_15_prefill(), model_layer_15_prefill(), model_layer_15_prefill(), model_layer_15_prefill(), model_layer_16_prefill(), model_layer_16_prefill(), model_layer_16_prefill(), model_layer_16_prefill(), model_layer_17_prefill(), model_layer_17_prefill(), model_layer_17_prefill(), model_layer_17_prefill(), model_layer_18_prefill(), model_layer_18_prefill(), model_layer_18_prefill(), model_layer_18_prefill(), model_layer_19_prefill(), model_layer_19_prefill(), model_layer_19_prefill(), model_layer_19_prefill(), model_layer_1_prefill(), model_layer_1_prefill(), model_layer_1_prefill(), model_layer_1_prefill(), model_layer_20_prefill(), model_layer_20_prefill(), model_layer_20_prefill(), model_layer_20_prefill(), model_layer_21_prefill(), model_layer_21_prefill(), model_layer_21_prefill(), model_layer_21_prefill(), model_layer_22_prefill(), model_layer_22_prefill(), model_layer_22_prefill(), model_layer_22_prefill(), model_layer_23_prefill(), model_layer_23_prefill(), model_layer_23_prefill(), model_layer_23_prefill(), model_layer_2_prefill(), model_layer_2_prefill(), model_layer_2_prefill(), model_layer_2_prefill(), model_layer_3_prefill(), model_layer_3_prefill(), model_layer_3_prefill(), model_layer_3_prefill(), model_layer_4_prefill(), model_layer_4_prefill(), model_layer_4_prefill(), model_layer_4_prefill(), model_layer_5_prefill(), model_layer_5_prefill(), model_layer_5_prefill(), model_layer_5_prefill(), model_layer_6_prefill(), model_layer_6_prefill(), model_layer_6_prefill(), model_layer_6_prefill(), model_layer_7_prefill(), model_layer_7_prefill(), model_layer_7_prefill(), model_layer_7_prefill(), model_layer_8_prefill(), model_layer_8_prefill(), model_layer_8_prefill(), model_layer_8_prefill(), model_layer_9_prefill(), model_layer_9_prefill(), model_layer_9_prefill(), model_layer_9_prefill(), qwen2_0_5b_decode_layer_0_prefill(), qwen2_0_5b_decode_layer_0_prefill(), qwen2_0_5b_decode_layer_10_prefill(), qwen2_0_5b_decode_layer_10_prefill(), qwen2_0_5b_decode_layer_11_prefill(), qwen2_0_5b_decode_layer_11_prefill(), qwen2_0_5b_decode_layer_12_prefill(), qwen2_0_5b_decode_layer_12_prefill(), qwen2_0_5b_decode_layer_13_prefill(), qwen2_0_5b_decode_layer_13_prefill(), qwen2_0_5b_decode_layer_14_prefill(), qwen2_0_5b_decode_layer_14_prefill(), qwen2_0_5b_decode_layer_15_prefill(), qwen2_0_5b_decode_layer_15_prefill(), qwen2_0_5b_decode_layer_16_prefill(), qwen2_0_5b_decode_layer_16_prefill(), qwen2_0_5b_decode_layer_17_prefill(), qwen2_0_5b_decode_layer_17_prefill(), qwen2_0_5b_decode_layer_18_prefill(), qwen2_0_5b_decode_layer_18_prefill(), qwen2_0_5b_decode_layer_19_prefill(), qwen2_0_5b_decode_layer_19_prefill(), qwen2_0_5b_decode_layer_1_prefill(), qwen2_0_5b_decode_layer_1_prefill(), qwen2_0_5b_decode_layer_20_prefill(), qwen2_0_5b_decode_layer_20_prefill(), qwen2_0_5b_decode_layer_21_prefill(), qwen2_0_5b_decode_layer_21_prefill(), qwen2_0_5b_decode_layer_22_prefill(), qwen2_0_5b_decode_layer_22_prefill(), qwen2_0_5b_decode_layer_23_prefill(), qwen2_0_5b_decode_layer_23_prefill(), qwen2_0_5b_decode_layer_2_prefill(), qwen2_0_5b_decode_layer_2_prefill(), qwen2_0_5b_decode_layer_3_prefill(), qwen2_0_5b_decode_layer_3_prefill(), qwen2_0_5b_decode_layer_4_prefill(), qwen2_0_5b_decode_layer_4_prefill(), qwen2_0_5b_decode_layer_5_prefill(), qwen2_0_5b_decode_layer_5_prefill(), qwen2_0_5b_decode_layer_6_prefill(), qwen2_0_5b_decode_layer_6_prefill(), qwen2_0_5b_decode_layer_7_prefill(), qwen2_0_5b_decode_layer_7_prefill(), qwen2_0_5b_decode_layer_8_prefill(), qwen2_0_5b_decode_layer_8_prefill(), qwen2_0_5b_decode_layer_9_prefill(), and qwen2_0_5b_decode_layer_9_prefill().

◆ rope_forward_qk_strided_with_rotary_dim()

void rope_forward_qk_strided_with_rotary_dim ( float *  q,
float *  k,
const float *  cos_cache,
const float *  sin_cache,
int  num_heads,
int  num_kv_heads,
int  num_tokens,
int  head_dim,
int  aligned_head_dim,
int  pos_offset,
int  q_stride_tokens,
int  k_stride_tokens,
int  rotary_dim 
)

Definition at line 2796 of file rope_kernels.c.

2809{
2810 rope_forward_strided_with_rotary_dim(q, cos_cache, sin_cache, num_heads, num_tokens,
2811 head_dim, aligned_head_dim, pos_offset,
2812 q_stride_tokens, rotary_dim);
2813 rope_forward_strided_with_rotary_dim(k, cos_cache, sin_cache, num_kv_heads, num_tokens,
2814 head_dim, aligned_head_dim, pos_offset,
2815 k_stride_tokens, rotary_dim);
2816}
void rope_forward_strided_with_rotary_dim(float *x, const float *cos_cache, const float *sin_cache, int num_heads, int num_tokens, int head_dim, int aligned_head_dim, int pos_offset, int head_stride_tokens, int rotary_dim)

References rope_forward_strided_with_rotary_dim().

Referenced by rope_forward_qk_strided().

◆ rope_forward_qk_with_rotary_dim()

void rope_forward_qk_with_rotary_dim ( float *  q,
float *  k,
const float *  cos_cache,
const float *  sin_cache,
int  num_heads,
int  num_kv_heads,
int  num_tokens,
int  head_dim,
int  aligned_head_dim,
int  pos_offset,
int  rotary_dim 
)

Definition at line 1109 of file rope_kernels.c.

1120{
1121 rope_forward_with_rotary_dim(q, cos_cache, sin_cache, num_heads, num_tokens,
1122 head_dim, aligned_head_dim, pos_offset, rotary_dim);
1123 rope_forward_with_rotary_dim(k, cos_cache, sin_cache, num_kv_heads, num_tokens,
1124 head_dim, aligned_head_dim, pos_offset, rotary_dim);
1125}

References rope_forward_with_rotary_dim().

Referenced by rope_forward_qk().

◆ rope_forward_qk_with_rotary_dim_cache_stride()

void rope_forward_qk_with_rotary_dim_cache_stride ( float *  q,
float *  k,
const float *  cos_cache,
const float *  sin_cache,
int  num_heads,
int  num_kv_heads,
int  num_tokens,
int  head_dim,
int  aligned_head_dim,
int  pos_offset,
int  rotary_dim,
int  cache_rotary_dim 
)

Definition at line 1419 of file rope_kernels.c.

1431{
1432 if (rotary_dim <= 0 || rotary_dim > head_dim) {
1433 rotary_dim = head_dim;
1434 }
1435 if (cache_rotary_dim < rotary_dim) {
1436 cache_rotary_dim = rotary_dim;
1437 }
1438 const int rotary_half = rotary_dim / 2;
1439 const int cache_half = cache_rotary_dim / 2;
1440 const size_t head_stride = (size_t)num_tokens * (size_t)aligned_head_dim;
1441
1442 for (int h = 0; h < num_heads; ++h) {
1443 float *head = q + (size_t)h * head_stride;
1444 for (int t = 0; t < num_tokens; ++t) {
1445 const int pos = pos_offset + t;
1446 const float *cos_row = cos_cache + (size_t)pos * (size_t)cache_half;
1447 const float *sin_row = sin_cache + (size_t)pos * (size_t)cache_half;
1448 float *x_row = head + (size_t)t * (size_t)aligned_head_dim;
1449 for (int i = 0; i < rotary_half; ++i) {
1450 const int idx0 = 2 * i;
1451 const int idx1 = idx0 + 1;
1452 const float x0 = x_row[idx0];
1453 const float x1 = x_row[idx1];
1454 const float c = cos_row[i];
1455 const float sv = sin_row[i];
1456 x_row[idx0] = x0 * c - x1 * sv;
1457 x_row[idx1] = x0 * sv + x1 * c;
1458 }
1459 }
1460 }
1461
1462 for (int h = 0; h < num_kv_heads; ++h) {
1463 float *head = k + (size_t)h * head_stride;
1464 for (int t = 0; t < num_tokens; ++t) {
1465 const int pos = pos_offset + t;
1466 const float *cos_row = cos_cache + (size_t)pos * (size_t)cache_half;
1467 const float *sin_row = sin_cache + (size_t)pos * (size_t)cache_half;
1468 float *x_row = head + (size_t)t * (size_t)aligned_head_dim;
1469 for (int i = 0; i < rotary_half; ++i) {
1470 const int idx0 = 2 * i;
1471 const int idx1 = idx0 + 1;
1472 const float x0 = x_row[idx0];
1473 const float x1 = x_row[idx1];
1474 const float c = cos_row[i];
1475 const float sv = sin_row[i];
1476 x_row[idx0] = x0 * c - x1 * sv;
1477 x_row[idx1] = x0 * sv + x1 * c;
1478 }
1479 }
1480 }
1481}

◆ rope_forward_strided()

void rope_forward_strided ( float *  x,
const float *  cos_cache,
const float *  sin_cache,
int  num_heads,
int  num_tokens,
int  head_dim,
int  aligned_head_dim,
int  pos_offset,
int  head_stride_tokens 
)

RoPE forward with custom head stride (for KV cache layouts)

Test:

test_rope.py::TestRoPEForward::test_rope_strided

test_kv_cache_attention.py::TestKVCacheAttention::test_rope_decode

Variant with configurable head_stride_tokens for non-contiguous head layouts.

After changes: make test

Definition at line 837 of file rope_kernels.c.

846{
847 rope_forward_strided_with_rotary_dim(x, cos_cache, sin_cache, num_heads, num_tokens,
848 head_dim, aligned_head_dim, pos_offset,
849 head_stride_tokens, head_dim);
850}

References rope_forward_strided_with_rotary_dim().

◆ rope_forward_strided_with_rotary_dim()

void rope_forward_strided_with_rotary_dim ( float *  x,
const float *  cos_cache,
const float *  sin_cache,
int  num_heads,
int  num_tokens,
int  head_dim,
int  aligned_head_dim,
int  pos_offset,
int  head_stride_tokens,
int  rotary_dim 
)

Definition at line 852 of file rope_kernels.c.

862{
863 size_t head_stride = (size_t)head_stride_tokens * (size_t)aligned_head_dim;
864
865 for (int h = 0; h < num_heads; ++h) {
866 rope_apply_head(x + h * head_stride,
867 cos_cache, sin_cache,
868 num_tokens, head_dim, aligned_head_dim, pos_offset, rotary_dim);
869 }
870}
static void rope_apply_head(float *x, const float *cos_cache, const float *sin_cache, int num_tokens, int head_dim, int aligned_head_dim, int pos_offset, int rotary_dim)

References rope_apply_head().

Referenced by rope_forward_qk_strided_with_rotary_dim(), and rope_forward_strided().

◆ rope_forward_with_rotary_dim()

void rope_forward_with_rotary_dim ( float *  x,
const float *  cos_cache,
const float *  sin_cache,
int  num_heads,
int  num_tokens,
int  head_dim,
int  aligned_head_dim,
int  pos_offset,
int  rotary_dim 
)

Definition at line 809 of file rope_kernels.c.

818{
819 size_t head_stride = (size_t)num_tokens * (size_t)aligned_head_dim;
820
821 for (int h = 0; h < num_heads; ++h) {
822 rope_apply_head(x + h * head_stride,
823 cos_cache, sin_cache,
824 num_tokens, head_dim, aligned_head_dim, pos_offset, rotary_dim);
825 }
826}

References rope_apply_head().

Referenced by rope_forward(), rope_forward_bf16_with_rotary_dim(), and rope_forward_qk_with_rotary_dim().

◆ rope_precompute_cache()

void rope_precompute_cache ( float *  cos_cache,
float *  sin_cache,
int  max_seq_len,
int  head_dim,
float  base,
int  rotary_dim,
const char *  scaling_type,
float  scaling_factor 
)

Precompute RoPE cos/sin cache with rotary_dim and scaling support

Test:

test_rope.py::TestRoPECache::test_cache_computation

test_rope.py::TestRoPECache::test_cache_values

Precomputes cos(m * theta_i) and sin(m * theta_i) for positions 0..max_seq_len-1. Only computes for first rotary_dim channels; remaining head_dim - rotary_dim channels are NOT rotated (pass through unchanged).

Scaling types:

  • "none": Standard RoPE
  • "linear": Scale positions by 1/scaling_factor
  • "dynamic": NTK-aware dynamic scaling
  • "yarn": YaRN scaling (beta-based)
Parameters
cos_cacheOutput: [max_seq_len, rotary_dim/2] cos values
sin_cacheOutput: [max_seq_len, rotary_dim/2] sin values
max_seq_lenMaximum sequence length for cache
head_dimFull head dimension (for frequency computation)
baseRoPE base frequency (theta)
rotary_dimNumber of dimensions to rotate (0 = use head_dim)
scaling_typeScaling type string: "none", "linear", "dynamic", "yarn"
scaling_factorScaling factor (1.0 = no scaling)

After changes: make test

Definition at line 384 of file rope_kernels.c.

392{
393 // Use rotary_dim = head_dim if not specified
394 if (rotary_dim <= 0 || rotary_dim > head_dim) {
395 rotary_dim = head_dim;
396 }
397
398 // Use no scaling if not specified
399 int is_linear_scaling = 0;
400 if (scaling_type != NULL && strcmp(scaling_type, "linear") == 0 && scaling_factor > 0.0f && scaling_factor != 1.0f) {
401 is_linear_scaling = 1;
402 }
403
404 int rotary_half = rotary_dim / 2;
405
406 for (int pos = 0; pos < max_seq_len; ++pos) {
407 // Apply linear scaling to position if needed
408 float effective_pos = (float)pos;
409 if (is_linear_scaling) {
410 effective_pos = (float)pos / scaling_factor;
411 }
412
413 for (int i = 0; i < rotary_half; ++i) {
414 // Match the FP32 reference contract directly. Computing this via
415 // long-double log/exp makes the final float depend on the host
416 // libm and long-double ABI.
417 const float exponent = ((float)(2 * i)) / (float)rotary_dim;
418 const float freq_f = 1.0f / powf(base, exponent);
419 float angle_f = effective_pos * freq_f;
420 cos_cache[pos * rotary_half + i] = cosf(angle_f);
421 sin_cache[pos * rotary_half + i] = sinf(angle_f);
422 }
423 }
424}

◆ rope_precompute_cache_llama_cpu()

void rope_precompute_cache_llama_cpu ( float *  cos_cache,
float *  sin_cache,
int  max_seq_len,
int  head_dim,
float  base,
int  rotary_dim,
const char *  scaling_type,
float  scaling_factor 
)

Definition at line 560 of file rope_kernels.c.

568{
569 if (!cos_cache || !sin_cache || max_seq_len <= 0 || head_dim <= 0) {
570 return;
571 }
572 if (rotary_dim <= 0 || rotary_dim > head_dim) {
573 rotary_dim = head_dim;
574 }
575 if (base <= 0.0f) {
576 base = 10000.0f;
577 }
578
579 const int linear_scaling =
580 scaling_type != NULL &&
581 strcmp(scaling_type, "linear") == 0 &&
582 scaling_factor > 0.0f &&
583 scaling_factor != 1.0f;
584 const int rotary_half = rotary_dim / 2;
585 const float theta_scale =
586 ck_rope_reference_powf(base, -2.0f / (float)rotary_dim);
587
588 for (int pos = 0; pos < max_seq_len; ++pos) {
589 float theta = (float)pos;
590 if (linear_scaling) {
591 theta /= scaling_factor;
592 }
593 for (int i = 0; i < rotary_half; ++i) {
594 cos_cache[(size_t)pos * (size_t)rotary_half + (size_t)i] =
596 sin_cache[(size_t)pos * (size_t)rotary_half + (size_t)i] =
598 theta *= theta_scale;
599 }
600 }
601}

References ck_rope_reference_cosf(), ck_rope_reference_powf(), and ck_rope_reference_sinf().

◆ rope_precompute_cache_split()

void rope_precompute_cache_split ( float *  cos_cache,
float *  sin_cache,
int  max_seq_len,
int  head_dim,
float  base 
)

Precompute RoPE cos/sin cache (split layout: head_dim/2) Legacy layout used before rotary_dim/scaling support.

Parameters
cos_cacheOutput: [max_seq_len, head_dim/2] cos values
sin_cacheOutput: [max_seq_len, head_dim/2] sin values
max_seq_lenMaximum sequence length for cache
head_dimFull head dimension
baseRoPE base frequency (theta)

Definition at line 340 of file rope_kernels.c.

345{
346 int half_dim = head_dim / 2;
347 for (int pos = 0; pos < max_seq_len; ++pos) {
348 for (int i = 0; i < half_dim; ++i) {
349 const float exponent = ((float)(2 * i)) / (float)head_dim;
350 const float freq_f = 1.0f / powf(base, exponent);
351 const float angle_f = (float)pos * freq_f;
352 cos_cache[pos * half_dim + i] = cosf(angle_f);
353 sin_cache[pos * half_dim + i] = sinf(angle_f);
354 }
355 }
356}

◆ rowwise_bias_add()

void rowwise_bias_add ( float *  x,
const float *  bias,
int  rows,
int  dim 
)

Definition at line 696 of file vision_kernels.c.

700{
701 if (!x || !bias || rows <= 0 || dim <= 0) {
702 return;
703 }
704
705 for (int r = 0; r < rows; ++r) {
706 float *row = x + ((size_t) r * (size_t) dim);
707 for (int c = 0; c < dim; ++c) {
708 row[c] += bias[c];
709 }
710 }
711}

◆ scal_copy_f32()

void scal_copy_f32 ( float *  y,
const float *  x,
float  alpha,
int  n 
)

Scaled copy: y = alpha * x.

Parameters
yOutput vector [n]
xInput vector [n]
alphaScalar multiplier
nVector length

Definition at line 156 of file axpy_kernels.c.

160{
161 if (!y || !x || n <= 0) {
162 return;
163 }
164
165 int i = 0;
166
167#ifdef __AVX512F__
168 __m512 valpha = _mm512_set1_ps(alpha);
169 for (; i + 16 <= n; i += 16) {
170 __m512 vx = _mm512_loadu_ps(&x[i]);
171 __m512 vy = _mm512_mul_ps(vx, valpha);
172 _mm512_storeu_ps(&y[i], vy);
173 }
174#endif
175
176#ifdef __AVX2__
177 __m256 valpha256 = _mm256_set1_ps(alpha);
178 for (; i + 8 <= n; i += 8) {
179 __m256 vx = _mm256_loadu_ps(&x[i]);
180 __m256 vy = _mm256_mul_ps(vx, valpha256);
181 _mm256_storeu_ps(&y[i], vy);
182 }
183#endif
184
185 for (; i < n; i++) {
186 y[i] = alpha * x[i];
187 }
188}

Referenced by weighted_sum_f32().

◆ sigmoid_backward()

void sigmoid_backward ( const float *  input,
const float *  d_output,
float *  d_input,
size_t  n 
)

Definition at line 138 of file sigmoid_kernels.c.

142{
143#if defined(__AVX512F__)
144 sigmoid_backward_avx512(input, d_output, d_input, n);
145#else
146 for (size_t i = 0; i < n; ++i) {
147 float x = input[i];
148 float s = sigmoid_scalar(x);
149 float s_prime = s * (1.0f - s);
150 d_input[i] = d_output[i] * s_prime;
151 }
152#endif
153}
float sigmoid_scalar(float x)

References sigmoid_scalar().

Referenced by sigmoid_backward_bf16().

◆ sigmoid_backward_bf16()

void sigmoid_backward_bf16 ( const uint16_t *  input,
const uint16_t *  d_output,
uint16_t *  d_input,
size_t  n,
float *  scratch_input,
float *  scratch_d_output,
float *  scratch_d_input 
)

Definition at line 45 of file sigmoid_kernels_bf16.c.

52{
53 if (!input || !d_output || !d_input || n == 0) return;
54 if (!scratch_input || !scratch_d_output || !scratch_d_input) return;
55
56 bf16_tensor_to_float(input, scratch_input, n);
57 bf16_tensor_to_float(d_output, scratch_d_output, n);
58 sigmoid_backward(scratch_input, scratch_d_output, scratch_d_input, n);
59 float_tensor_to_bf16(scratch_d_input, d_input, n);
60}
void sigmoid_backward(const float *input, const float *d_output, float *d_input, size_t n)

References bf16_tensor_to_float(), float_tensor_to_bf16(), and sigmoid_backward().

◆ sigmoid_forward()

void sigmoid_forward ( const float *  input,
float *  output,
size_t  n 
)

Definition at line 122 of file sigmoid_kernels.c.

125{
126#if defined(__AVX512F__)
127 sigmoid_forward_avx512(input, output, n);
128#else
129 for (size_t i = 0; i < n; ++i) {
130 output[i] = sigmoid_scalar(input[i]);
131 }
132#endif
133}

References sigmoid_scalar().

Referenced by sigmoid_forward_bf16().

◆ sigmoid_forward_bf16()

void sigmoid_forward_bf16 ( const uint16_t *  input,
uint16_t *  output,
size_t  n,
float *  scratch_input,
float *  scratch_output 
)

Definition at line 27 of file sigmoid_kernels_bf16.c.

32{
33 if (!input || !output || n == 0) return;
34 if (!scratch_input || !scratch_output) return;
35
36 bf16_tensor_to_float(input, scratch_input, n);
37 sigmoid_forward(scratch_input, scratch_output, n);
38 float_tensor_to_bf16(scratch_output, output, n);
39}
void sigmoid_forward(const float *input, float *output, size_t n)

References bf16_tensor_to_float(), float_tensor_to_bf16(), and sigmoid_forward().

◆ sigmoid_scalar()

float sigmoid_scalar ( float  x)

Definition at line 26 of file sigmoid_kernels.c.

27{
28 return 1.0f / (1.0f + expf(-x));
29}

Referenced by sigmoid_backward(), sigmoid_forward(), swiglu_backward(), swiglu_backward_bf16(), swiglu_forward(), swiglu_forward_bf16(), and swiglu_forward_q8_k().

◆ softmax_cross_entropy_loss()

void softmax_cross_entropy_loss ( const float *  logits,
const int32_t *  targets,
int  tokens,
int  vocab_size,
float *  d_logits,
float *  loss_out 
)

Definition at line 259 of file loss_kernels.c.

265{
266 if (!logits || !targets || !d_logits || tokens <= 0 || vocab_size <= 0) {
267 if (loss_out) {
268 *loss_out = 0.0f;
269 }
270 return;
271 }
272
275 logits, targets, tokens, vocab_size, d_logits, loss_out);
276 return;
277 }
278
280 logits, targets, tokens, vocab_size, d_logits, loss_out, -1);
281}
static int ce_targets_all_valid_no_ignore(const int32_t *targets, int tokens, int vocab_size)
static int ce_legacy_mode_enabled(void)
static void softmax_cross_entropy_loss_index_mean_impl(const float *logits, const int32_t *targets, int tokens, int vocab_size, float *d_logits, float *loss_out, int force_strict_math)
static void softmax_cross_entropy_loss_legacy_mean_impl(const float *logits, const int32_t *targets, int tokens, int vocab_size, float *d_logits, float *loss_out)

References ce_legacy_mode_enabled(), ce_targets_all_valid_no_ignore(), softmax_cross_entropy_loss_index_mean_impl(), softmax_cross_entropy_loss_legacy_mean_impl(), and vocab_size.

Referenced by softmax_cross_entropy_loss_bf16().

◆ softmax_cross_entropy_loss_bf16()

void softmax_cross_entropy_loss_bf16 ( const uint16_t *  logits,
const int32_t *  targets,
int  tokens,
int  vocab_size,
uint16_t *  d_logits,
float *  loss_out,
float *  scratch_logits,
float *  scratch_d_logits 
)

Definition at line 25 of file loss_kernels_bf16.c.

33{
34 if (!logits || !targets || !d_logits || tokens <= 0 || vocab_size <= 0) {
35 if (loss_out) *loss_out = 0.0f;
36 return;
37 }
38 if (!scratch_logits || !scratch_d_logits) {
39 if (loss_out) *loss_out = 0.0f;
40 return;
41 }
42
43 const size_t count = (size_t)tokens * (size_t)vocab_size;
44
45 bf16_tensor_to_float(logits, scratch_logits, count);
46 softmax_cross_entropy_loss(scratch_logits, targets, tokens, vocab_size, scratch_d_logits, loss_out);
47 float_tensor_to_bf16(scratch_d_logits, d_logits, count);
48}
void softmax_cross_entropy_loss(const float *logits, const int32_t *targets, int tokens, int vocab_size, float *d_logits, float *loss_out)

References bf16_tensor_to_float(), float_tensor_to_bf16(), softmax_cross_entropy_loss(), and vocab_size.

◆ softmax_cross_entropy_loss_ptref()

void softmax_cross_entropy_loss_ptref ( const float *  logits,
const int32_t *  targets,
int  tokens,
int  vocab_size,
float *  d_logits,
float *  loss_out 
)

Definition at line 292 of file loss_kernels.c.

298{
299 /*
300 * Keep a strict reference variant for parity experiments:
301 * - always uses strict math path,
302 * - same reduction / ignore semantics as default kernel.
303 */
305 logits, targets, tokens, vocab_size, d_logits, loss_out, 1);
306}

References softmax_cross_entropy_loss_index_mean_impl(), and vocab_size.

◆ spatial_average_pool_contiguous()

void spatial_average_pool_contiguous ( const float *  input,
float *  output,
int  grid_h,
int  grid_w,
int  embed_dim,
int  merge_size 
)

Definition at line 657 of file vision_kernels.c.

663{
664 if (input == NULL || output == NULL || grid_h <= 0 || grid_w <= 0 || embed_dim <= 0 || merge_size <= 0) {
665 return;
666 }
667
668 const int out_h = grid_h / merge_size;
669 const int out_w = grid_w / merge_size;
670 if (out_h <= 0 || out_w <= 0) {
671 return;
672 }
673
674 const float inv_area = 1.0f / (float)(merge_size * merge_size);
675 for (int oy = 0; oy < out_h; ++oy) {
676 for (int ox = 0; ox < out_w; ++ox) {
677 float *dst = output + ((size_t)oy * (size_t)out_w + (size_t)ox) * (size_t)embed_dim;
678 memset(dst, 0, (size_t)embed_dim * sizeof(float));
679 for (int dy = 0; dy < merge_size; ++dy) {
680 const int iy = oy * merge_size + dy;
681 for (int dx = 0; dx < merge_size; ++dx) {
682 const int ix = ox * merge_size + dx;
683 const float *src = input + ((size_t)iy * (size_t)grid_w + (size_t)ix) * (size_t)embed_dim;
684 for (int c = 0; c < embed_dim; ++c) {
685 dst[c] += src[c];
686 }
687 }
688 }
689 for (int c = 0; c < embed_dim; ++c) {
690 dst[c] *= inv_area;
691 }
692 }
693 }
694}

◆ spatial_merge_2x2()

void spatial_merge_2x2 ( const float *  input,
float *  output,
int  grid_h,
int  grid_w,
int  embed_dim 
)

Merge 2x2 neighboring tokens into a single wider token.

Input layout: [grid_h * grid_w, embed_dim] Output layout: [(grid_h/2) * (grid_w/2), embed_dim * 4]

Pack order within each merged token: top-left, top-right, bottom-left, bottom-right

Definition at line 577 of file vision_kernels.c.

582{
583 if (input == NULL || output == NULL || grid_h <= 0 || grid_w <= 0 || embed_dim <= 0) {
584 return;
585 }
586
587 const int merged_h = grid_h / 2;
588 const int merged_w = grid_w / 2;
589 const size_t token_stride = (size_t)embed_dim;
590 const size_t merged_stride = (size_t)embed_dim * 4;
591
592 for (int mh = 0; mh < merged_h; ++mh) {
593 for (int mw = 0; mw < merged_w; ++mw) {
594 const int y0 = mh * 2;
595 const int x0 = mw * 2;
596 const int in_idx00 = y0 * grid_w + x0;
597 const int in_idx01 = in_idx00 + 1;
598 const int in_idx10 = in_idx00 + grid_w;
599 const int in_idx11 = in_idx10 + 1;
600 const int out_idx = mh * merged_w + mw;
601
602 const float *src00 = input + (size_t)in_idx00 * token_stride;
603 const float *src01 = input + (size_t)in_idx01 * token_stride;
604 const float *src10 = input + (size_t)in_idx10 * token_stride;
605 const float *src11 = input + (size_t)in_idx11 * token_stride;
606 float *dst = output + (size_t)out_idx * merged_stride;
607
608 memcpy(dst + 0 * embed_dim, src00, (size_t)embed_dim * sizeof(float));
609 memcpy(dst + 1 * embed_dim, src01, (size_t)embed_dim * sizeof(float));
610 memcpy(dst + 2 * embed_dim, src10, (size_t)embed_dim * sizeof(float));
611 memcpy(dst + 3 * embed_dim, src11, (size_t)embed_dim * sizeof(float));
612 }
613 }
614}

◆ spatial_merge_contiguous_tiled()

void spatial_merge_contiguous_tiled ( const float *  input,
float *  output,
int  grid_h,
int  grid_w,
int  embed_dim,
int  merge_size 
)

Definition at line 616 of file vision_kernels.c.

622{
623 if (input == NULL || output == NULL || grid_h <= 0 || grid_w <= 0 || embed_dim <= 0 || merge_size <= 0) {
624 return;
625 }
626
627 const size_t num_tokens = (size_t) grid_h * (size_t) grid_w;
628 const size_t merge_factor = (size_t) merge_size * (size_t) merge_size;
629 const size_t merged_tokens = num_tokens / merge_factor;
630 memcpy(output, input, merged_tokens * (size_t) embed_dim * merge_factor * sizeof(float));
631}

◆ speculative_commit_one_i32()

void speculative_commit_one_i32 ( int  accepted,
int  verified_token,
int *  token_buffer,
int *  token_count,
int  max_tokens,
int *  target_position,
int *  draft_position,
int *  accepted_count,
int *  rejected_count 
)

Commit one verified speculative token and update decode counters.

This is the minimal state transition for the first Gemma4 assistant bridge: greedy, one draft token, target remains authoritative. For this milestone the draft cache is kept synchronized with the target position after each token. Multi-token speculative decoding can later replace this with prefix accept and partial draft-cache rollback.

Definition at line 611 of file topk_kernels.c.

620{
621 int next_count = token_count ? *token_count : 0;
622 if (token_buffer && token_count && next_count >= 0 && next_count < max_tokens) {
623 token_buffer[next_count] = verified_token;
624 next_count += 1;
625 *token_count = next_count;
626 }
627
628 if (target_position) {
629 *target_position += 1;
630 if (draft_position) {
631 *draft_position = *target_position;
632 }
633 } else if (draft_position) {
634 *draft_position += 1;
635 }
636
637 if (accepted) {
638 if (accepted_count) {
639 *accepted_count += 1;
640 }
641 } else {
642 if (rejected_count) {
643 *rejected_count += 1;
644 }
645 }
646}

◆ speculative_verify_greedy_f32()

void speculative_verify_greedy_f32 ( const float *  target_logits,
int  vocab_size,
int  draft_token,
int *  accepted,
int *  verified_token 
)

Greedy one-token speculative verification.

The draft model proposes draft_token. The target model is authoritative: if draft_token equals argmax(target_logits), the candidate is accepted and emitted. Otherwise the target argmax is emitted and the draft path must be reset or rewound by the runtime loop.

Parameters
target_logitsTarget/backbone logits [vocab_size]
vocab_sizeNumber of logits
draft_tokenCandidate token from draft/assistant model
acceptedOutput scalar: 1 if accepted, 0 otherwise
verified_tokenOutput scalar: accepted draft token or target argmax

Definition at line 585 of file topk_kernels.c.

590{
591 const int target_token = argmax_f32(target_logits, vocab_size);
592 const int ok = (target_token >= 0 && draft_token == target_token) ? 1 : 0;
593
594 if (accepted) {
595 *accepted = ok;
596 }
597 if (verified_token) {
598 *verified_token = ok ? draft_token : target_token;
599 }
600}
int argmax_f32(const float *scores, int n)
Find index of maximum value.

References argmax_f32(), and vocab_size.

◆ split_q_gate_backward()

void split_q_gate_backward ( const float *  d_q,
const float *  d_gate,
float *  d_packed_qg,
int  rows,
int  q_dim,
int  gate_dim,
int  group_dim 
)

Definition at line 77 of file hybrid_attention_kernels.c.

83 {
84 const int packed_dim = q_dim + gate_dim;
85 if (!d_q || !d_gate || !d_packed_qg || rows <= 0 || q_dim <= 0 || gate_dim <= 0) {
86 return;
87 }
88 if (group_dim <= 0) {
89 group_dim = q_dim;
90 }
91 const int q_groups = q_dim / group_dim;
92 const int gate_group_dim = (q_groups > 0 && gate_dim % q_groups == 0) ? (gate_dim / q_groups) : gate_dim;
93 for (int row = 0; row < rows; ++row) {
94 const float *dq_src = d_q + (size_t) row * (size_t) q_dim;
95 const float *dg_src = d_gate + (size_t) row * (size_t) gate_dim;
96 float *dst = d_packed_qg + (size_t) row * (size_t) packed_dim;
97 if (q_groups > 0 && q_groups * group_dim == q_dim && q_groups * gate_group_dim == gate_dim) {
98 for (int group = 0; group < q_groups; ++group) {
99 const size_t dst_group_off = (size_t) group * (size_t) (group_dim + gate_group_dim);
100 memcpy(
101 dst + dst_group_off,
102 dq_src + (size_t) group * (size_t) group_dim,
103 (size_t) group_dim * sizeof(float));
104 memcpy(
105 dst + dst_group_off + (size_t) group_dim,
106 dg_src + (size_t) group * (size_t) gate_group_dim,
107 (size_t) gate_group_dim * sizeof(float));
108 }
109 } else {
110 memcpy(dst, dq_src, (size_t) q_dim * sizeof(float));
111 memcpy(dst + q_dim, dg_src, (size_t) gate_dim * sizeof(float));
112 }
113 }
114}

◆ split_q_gate_forward()

void split_q_gate_forward ( const float *  packed_qg,
float *  q,
float *  gate,
int  rows,
int  q_dim,
int  gate_dim,
int  group_dim 
)

Definition at line 38 of file hybrid_attention_kernels.c.

44 {
45 const int packed_dim = q_dim + gate_dim;
46 if (!packed_qg || !q || !gate || rows <= 0 || q_dim <= 0 || gate_dim <= 0) {
47 return;
48 }
49 if (group_dim <= 0) {
50 group_dim = q_dim;
51 }
52 const int q_groups = q_dim / group_dim;
53 const int gate_group_dim = (q_groups > 0 && gate_dim % q_groups == 0) ? (gate_dim / q_groups) : gate_dim;
54 for (int row = 0; row < rows; ++row) {
55 const float *src = packed_qg + (size_t) row * (size_t) packed_dim;
56 float *q_dst = q + (size_t) row * (size_t) q_dim;
57 float *gate_dst = gate + (size_t) row * (size_t) gate_dim;
58 if (q_groups > 0 && q_groups * group_dim == q_dim && q_groups * gate_group_dim == gate_dim) {
59 for (int group = 0; group < q_groups; ++group) {
60 const size_t src_group_off = (size_t) group * (size_t) (group_dim + gate_group_dim);
61 memcpy(
62 q_dst + (size_t) group * (size_t) group_dim,
63 src + src_group_off,
64 (size_t) group_dim * sizeof(float));
65 memcpy(
66 gate_dst + (size_t) group * (size_t) gate_group_dim,
67 src + src_group_off + (size_t) group_dim,
68 (size_t) gate_group_dim * sizeof(float));
69 }
70 } else {
71 memcpy(q_dst, src, (size_t) q_dim * sizeof(float));
72 memcpy(gate_dst, src + q_dim, (size_t) gate_dim * sizeof(float));
73 }
74 }
75}

◆ split_qkv_packed_head_major_forward()

void split_qkv_packed_head_major_forward ( const float *  packed_qkv,
float *  q,
float *  k,
float *  v,
int  rows,
int  q_dim,
int  k_dim,
int  v_dim,
int  num_heads,
int  num_kv_heads 
)

Definition at line 25 of file recurrent_split_kernels.c.

34 {
35 if (!packed_qkv || !q || !k || !v || rows <= 0 || q_dim <= 0 || k_dim <= 0 || v_dim <= 0 ||
36 num_heads <= 0 || num_kv_heads <= 0) {
37 return;
38 }
39
40 const int q_head_dim = q_dim / num_heads;
41 const int k_head_dim = k_dim / num_kv_heads;
42 const int v_head_dim = v_dim / num_kv_heads;
43 if (q_head_dim <= 0 || k_head_dim <= 0 || v_head_dim <= 0) {
44 return;
45 }
46 if (q_head_dim * num_heads != q_dim || k_head_dim * num_kv_heads != k_dim || v_head_dim * num_kv_heads != v_dim) {
47 return;
48 }
49
50 const int packed_dim = q_dim + k_dim + v_dim;
51 const size_t q_head_stride = (size_t) rows * (size_t) q_head_dim;
52 const size_t k_head_stride = (size_t) rows * (size_t) k_head_dim;
53 const size_t v_head_stride = (size_t) rows * (size_t) v_head_dim;
54
55 for (int row = 0; row < rows; ++row) {
56 const float *src = packed_qkv + (size_t) row * (size_t) packed_dim;
57
58 for (int head = 0; head < num_heads; ++head) {
59 const float *src_q = src + (size_t) head * (size_t) q_head_dim;
60 float *dst_q = q + (size_t) head * q_head_stride + (size_t) row * (size_t) q_head_dim;
61 memcpy(dst_q, src_q, (size_t) q_head_dim * sizeof(float));
62 }
63
64 const float *src_k_base = src + (size_t) q_dim;
65 const float *src_v_base = src + (size_t) q_dim + (size_t) k_dim;
66 for (int head = 0; head < num_kv_heads; ++head) {
67 const float *src_k = src_k_base + (size_t) head * (size_t) k_head_dim;
68 const float *src_v = src_v_base + (size_t) head * (size_t) v_head_dim;
69 float *dst_k = k + (size_t) head * k_head_stride + (size_t) row * (size_t) k_head_dim;
70 float *dst_v = v + (size_t) head * v_head_stride + (size_t) row * (size_t) v_head_dim;
71 memcpy(dst_k, src_k, (size_t) k_head_dim * sizeof(float));
72 memcpy(dst_v, src_v, (size_t) v_head_dim * sizeof(float));
73 }
74 }
75}

◆ ssm_conv1d_backward()

void ssm_conv1d_backward ( const float *  d_out,
const float *  conv_x,
const float *  kernel,
float *  d_conv_x,
float *  d_kernel,
int  kernel_size,
int  num_channels,
int  num_tokens,
int  num_seqs 
)

Definition at line 316 of file ssm_kernels.c.

325{
326 ssm_conv1d_backward_ref(d_out, conv_x, kernel, d_conv_x, d_kernel, kernel_size, num_channels, num_tokens, num_seqs);
327}
void ssm_conv1d_backward_ref(const float *d_out, const float *conv_x, const float *kernel, float *d_conv_x, float *d_kernel, int kernel_size, int num_channels, int num_tokens, int num_seqs)
Definition ssm_kernels.c:78

References ssm_conv1d_backward_ref().

◆ ssm_conv1d_forward()

void ssm_conv1d_forward ( const float *  conv_x,
const float *  kernel,
float *  out,
int  kernel_size,
int  num_channels,
int  num_tokens,
int  num_seqs 
)

Definition at line 128 of file ssm_kernels.c.

135{
136 ssm_conv1d_forward_ref(conv_x, kernel, out, kernel_size, num_channels, num_tokens, num_seqs);
137}
void ssm_conv1d_forward_ref(const float *conv_x, const float *kernel, float *out, int kernel_size, int num_channels, int num_tokens, int num_seqs)
Definition ssm_kernels.c:39

References ssm_conv1d_forward_ref().

◆ ssm_conv1d_forward_llama_fma()

void ssm_conv1d_forward_llama_fma ( const float *  conv_x,
const float *  kernel,
float *  out,
int  kernel_size,
int  num_channels,
int  num_tokens,
int  num_seqs 
)

Definition at line 272 of file ssm_kernels.c.

279{
280 if (!conv_x || !kernel || !out || kernel_size <= 0 || num_channels <= 0 ||
281 num_tokens < 0 || num_seqs <= 0) {
282 return;
283 }
284 ck_ssm_conv1d_llama_args_t args = {
285 conv_x, kernel, out, kernel_size, num_channels, num_tokens, num_seqs,
286 };
287 ck_threadpool_t *pool = ck_threadpool_global();
288 const int workers = pool ? ck_threadpool_n_threads(pool) : 1;
289 const int active = workers < num_channels ? workers : num_channels;
290 if (active > 1 && num_tokens > 1) {
292 pool, active, 0, num_channels, 32,
294 } else {
295 ck_ssm_conv1d_llama_fma_channel_range(0, num_channels, &args);
296 }
297}
static void ck_ssm_conv1d_llama_fma_channel_range(int begin, int end, void *opaque)

References ck_ssm_conv1d_llama_fma_channel_range(), ck_threadpool_global(), ck_threadpool_n_threads(), and ck_threadpool_parallel_for_n().

◆ ssm_conv1d_forward_llama_production()

void ssm_conv1d_forward_llama_production ( const float *  conv_x,
const float *  kernel,
float *  out,
int  kernel_size,
int  num_channels,
int  num_tokens,
int  num_seqs 
)

Definition at line 207 of file ssm_kernels.c.

214{
215 if (!conv_x || !kernel || !out || kernel_size <= 0 || num_channels <= 0 ||
216 num_tokens < 0 || num_seqs <= 0) {
217 return;
218 }
219 ck_ssm_conv1d_llama_args_t args = {
220 conv_x, kernel, out, kernel_size, num_channels, num_tokens, num_seqs,
221 };
222 ck_threadpool_t *pool = ck_threadpool_global();
223 const int workers = pool ? ck_threadpool_n_threads(pool) : 1;
224 const int active = workers < num_channels ? workers : num_channels;
225 if (active > 1 && num_tokens > 1) {
227 pool, active, 0, num_channels, 32,
229 } else {
230 ck_ssm_conv1d_llama_channel_range(0, num_channels, &args);
231 }
232}
static void ck_ssm_conv1d_llama_channel_range(int begin, int end, void *opaque)

References ck_ssm_conv1d_llama_channel_range(), ck_threadpool_global(), ck_threadpool_n_threads(), and ck_threadpool_parallel_for_n().

◆ ssm_conv1d_forward_llama_production_serial()

void ssm_conv1d_forward_llama_production_serial ( const float *  conv_x,
const float *  kernel,
float *  out,
int  kernel_size,
int  num_channels,
int  num_tokens,
int  num_seqs 
)

Definition at line 189 of file ssm_kernels.c.

196{
197 if (!conv_x || !kernel || !out || kernel_size <= 0 || num_channels <= 0 ||
198 num_tokens < 0 || num_seqs <= 0) {
199 return;
200 }
201 ck_ssm_conv1d_llama_args_t args = {
202 conv_x, kernel, out, kernel_size, num_channels, num_tokens, num_seqs,
203 };
204 ck_ssm_conv1d_llama_channel_range(0, num_channels, &args);
205}

References ck_ssm_conv1d_llama_channel_range().

◆ ssm_conv1d_forward_pytorch_bf16_storage()

void ssm_conv1d_forward_pytorch_bf16_storage ( const float *  conv_x,
const float *  kernel,
float *  out,
int  kernel_size,
int  num_channels,
int  num_tokens,
int  num_seqs 
)

Definition at line 299 of file ssm_kernels.c.

306{
308 conv_x, kernel, out, kernel_size, num_channels, num_tokens, num_seqs);
309 const size_t count =
310 (size_t)num_seqs * (size_t)num_tokens * (size_t)num_channels;
311 for (size_t i = 0; i < count; ++i) {
312 out[i] = bf16_to_float(float_to_bf16(out[i]));
313 }
314}

References bf16_to_float(), float_to_bf16(), and ssm_conv1d_forward_ref().

◆ swiglu_backward()

void swiglu_backward ( const float *  input,
const float *  d_output,
float *  d_input,
int  tokens,
int  dim 
)

SwiGLU backward pass

Test:

test_swiglu.py::TestSwiGLUBackward::test_backward_tokens

test_swiglu.py::TestSwiGLUBackward::test_backward_single

test_parity.py::test_swiglu_backward_parity

Computes dGate and dUp given dY. dGate = dy * b * silu'(a), dUp = dy * silu(a)

After changes: make test && make llamacpp-parity-full

Definition at line 386 of file swiglu_kernels.c.

391{
393 swiglu_backward_exact(input, d_output, d_input, tokens, dim);
394 return;
395 }
396
397 int T = tokens;
398 int D = dim;
399
400 for (int t = 0; t < T; ++t) {
401 const float *row = input + (size_t)t * (2 * D);
402 const float *dy_row = d_output + (size_t)t * D;
403 float *dx_row = d_input + (size_t)t * (2 * D);
404 int d = 0;
405
406#if defined(__AVX512F__)
407 // AVX-512: Process 16 floats at a time
408 __m512 one = _mm512_set1_ps(1.0f);
409 for (; d + 16 <= D; d += 16) {
410 __m512 a = _mm512_loadu_ps(&row[d]); // gate
411 __m512 b = _mm512_loadu_ps(&row[D + d]); // value
412 __m512 dy = _mm512_loadu_ps(&dy_row[d]);
413
414 __m512 s = sigmoid512_fast(a); // sigmoid(a)
415 __m512 silu = _mm512_mul_ps(a, s); // silu(a) = a * s
416 __m512 one_minus_s = _mm512_sub_ps(one, s);
417 __m512 inner = _mm512_fmadd_ps(a, one_minus_s, one); // 1 + a * (1 - s)
418 __m512 silu_prime = _mm512_mul_ps(s, inner); // s * (1 + a * (1 - s))
419
420 // dA = dy * b * silu_prime
421 __m512 dA = _mm512_mul_ps(dy, _mm512_mul_ps(b, silu_prime));
422 // dB = dy * silu
423 __m512 dB = _mm512_mul_ps(dy, silu);
424
425 _mm512_storeu_ps(&dx_row[d], dA);
426 _mm512_storeu_ps(&dx_row[D + d], dB);
427 }
428#elif defined(__AVX2__)
429 // AVX2: Process 8 floats at a time
430 __m256 one = _mm256_set1_ps(1.0f);
431 for (; d + 8 <= D; d += 8) {
432 __m256 a = _mm256_loadu_ps(&row[d]); // gate
433 __m256 b = _mm256_loadu_ps(&row[D + d]); // value
434 __m256 dy = _mm256_loadu_ps(&dy_row[d]);
435
436 __m256 s = sigmoid256_fast(a); // sigmoid(a)
437 __m256 silu = _mm256_mul_ps(a, s); // silu(a) = a * s
438 __m256 one_minus_s = _mm256_sub_ps(one, s);
439 __m256 inner = _mm256_fmadd_ps(a, one_minus_s, one); // 1 + a * (1 - s)
440 __m256 silu_prime = _mm256_mul_ps(s, inner); // s * (1 + a * (1 - s))
441
442 // dA = dy * b * silu_prime
443 __m256 dA = _mm256_mul_ps(dy, _mm256_mul_ps(b, silu_prime));
444 // dB = dy * silu
445 __m256 dB = _mm256_mul_ps(dy, silu);
446
447 _mm256_storeu_ps(&dx_row[d], dA);
448 _mm256_storeu_ps(&dx_row[D + d], dB);
449 }
450#elif defined(__AVX__)
451 // AVX1: Vectorize arithmetic, use scalar sigmoid
452 __m256 one = _mm256_set1_ps(1.0f);
453 float a_arr[8] __attribute__((aligned(32)));
454 float s_arr[8] __attribute__((aligned(32)));
455
456 for (; d + 8 <= D; d += 8) {
457 __m256 a = _mm256_loadu_ps(&row[d]); // gate
458 __m256 b = _mm256_loadu_ps(&row[D + d]); // value
459 __m256 dy = _mm256_loadu_ps(&dy_row[d]);
460
461 // Compute sigmoid scalarly
462 _mm256_store_ps(a_arr, a);
463 for (int j = 0; j < 8; ++j) {
464 s_arr[j] = sigmoid_scalar(a_arr[j]);
465 }
466 __m256 s = _mm256_load_ps(s_arr);
467
468 __m256 silu = _mm256_mul_ps(a, s); // silu(a) = a * s
469 __m256 one_minus_s = _mm256_sub_ps(one, s);
470 __m256 a_one_minus_s = _mm256_mul_ps(a, one_minus_s);
471 __m256 inner = _mm256_add_ps(one, a_one_minus_s); // 1 + a * (1 - s)
472 __m256 silu_prime = _mm256_mul_ps(s, inner); // s * (1 + a * (1 - s))
473
474 // dA = dy * b * silu_prime
475 __m256 dA = _mm256_mul_ps(dy, _mm256_mul_ps(b, silu_prime));
476 // dB = dy * silu
477 __m256 dB = _mm256_mul_ps(dy, silu);
478
479 _mm256_storeu_ps(&dx_row[d], dA);
480 _mm256_storeu_ps(&dx_row[D + d], dB);
481 }
482#endif
483
484 // Scalar fallback for remaining elements
485 for (; d < D; ++d) {
486 float a = row[d]; // gate
487 float b = row[D + d]; // value
488 float dy = dy_row[d];
489
490 float s = sigmoid_scalar(a); // sigmoid(a)
491 float silu = a * s; // silu(a)
492 float silu_prime = s * (1.0f + a * (1.0f - s)); // silu'(a), PyTorch form
493
494 float dA = dy * b * silu_prime;
495 float dB = dy * silu;
496
497 dx_row[d] = dA;
498 dx_row[D + d] = dB;
499 }
500 }
501}
float sigmoid_scalar(float x)
void swiglu_backward_exact(const float *input, const float *d_output, float *d_input, int tokens, int dim)

References __attribute__(), ck_strict_parity_enabled(), sigmoid_scalar(), silu(), and swiglu_backward_exact().

Referenced by ck_layer_backward_rmsnorm_swiglu().

◆ swiglu_backward_bf16()

void swiglu_backward_bf16 ( const uint16_t *  input,
const uint16_t *  d_output,
uint16_t *  d_input,
int  tokens,
int  dim 
)

Definition at line 108 of file swiglu_kernels_bf16.c.

113{
114 if (!input || !d_output || !d_input || tokens <= 0 || dim <= 0) {
115 return;
116 }
117
118 const int T = tokens;
119 const int D = dim;
120
121 for (int t = 0; t < T; ++t) {
122 const uint16_t *row = input + (size_t)t * (size_t)(2 * D);
123 const uint16_t *dy_row = d_output + (size_t)t * (size_t)D;
124 uint16_t *dx_row = d_input + (size_t)t * (size_t)(2 * D);
125 int d = 0;
126
127#if defined(__AVX512F__)
128 // AVX-512: Process 16 floats at a time
129 __m512 one = _mm512_set1_ps(1.0f);
130 for (; d + 16 <= D; d += 16) {
131 __m512 a = bf16_loadu_cvt_fp32(&row[d]); // gate
132 __m512 b = bf16_loadu_cvt_fp32(&row[D + d]); // value
133 __m512 dy = bf16_loadu_cvt_fp32(&dy_row[d]);
134
135 __m512 s = sigmoid512_fast_bf16(a); // sigmoid(a)
136 __m512 silu = _mm512_mul_ps(a, s); // silu(a) = a * s
137 __m512 s_prime = _mm512_mul_ps(s, _mm512_sub_ps(one, s)); // s * (1 - s)
138 __m512 silu_prime = _mm512_fmadd_ps(a, s_prime, s); // s + a * s_prime
139
140 // dA = dy * b * silu_prime
141 __m512 dA = _mm512_mul_ps(dy, _mm512_mul_ps(b, silu_prime));
142 // dB = dy * silu
143 __m512 dB = _mm512_mul_ps(dy, silu);
144
145 fp32_cvt_storeu_bf16(&dx_row[d], dA);
146 fp32_cvt_storeu_bf16(&dx_row[D + d], dB);
147 }
148#endif
149
150 // Scalar fallback for remaining elements
151 for (; d < D; ++d) {
152 float a = bf16_to_float(row[d]);
153 float b = bf16_to_float(row[D + d]);
154 float dy = bf16_to_float(dy_row[d]);
155
156 float s = sigmoid_scalar(a);
157 float silu = a * s;
158 float s_prime = s * (1.0f - s);
159 float silu_prime = s + a * s_prime;
160
161 float dA = dy * b * silu_prime;
162 float dB = dy * silu;
163
164 dx_row[d] = float_to_bf16(dA);
165 dx_row[D + d] = float_to_bf16(dB);
166 }
167 }
168}

References bf16_to_float(), float_to_bf16(), sigmoid_scalar(), and silu().

◆ swiglu_backward_exact()

void swiglu_backward_exact ( const float *  input,
const float *  d_output,
float *  d_input,
int  tokens,
int  dim 
)

SwiGLU backward pass (exact version using stdlib sigmoid)

Test:

test_swiglu.py::TestSwiGLUBackward::test_exact_vs_fast

test_swiglu.py::TestSwiGLUBackward::test_exact_single

Uses standard library expf for numerical accuracy reference.

After changes: make test

Definition at line 719 of file swiglu_kernels.c.

724{
725 int T = tokens;
726 int D = dim;
727
728 for (int t = 0; t < T; ++t) {
729 const float *row = input + (size_t)t * (2 * D);
730 const float *dy_row = d_output + (size_t)t * D;
731 float *dx_row = d_input + (size_t)t * (2 * D);
732
733 for (int d = 0; d < D; ++d) {
734 float a = row[d]; // gate
735 float b = row[D + d]; // value
736 float dy = dy_row[d];
737
738 float s = sigmoid_scalar_parity(a); // sigmoid(a)
739 float silu = a * s; // silu(a)
740 float silu_prime = s * (1.0f + a * (1.0f - s)); // silu'(a), PyTorch form
741
742 float dA = dy * b * silu_prime;
743 float dB = dy * silu;
744
745 dx_row[d] = dA;
746 dx_row[D + d] = dB;
747 }
748 }
749}
static float sigmoid_scalar_parity(float x)

References sigmoid_scalar_parity(), and silu().

Referenced by swiglu_backward().

◆ swiglu_forward()

void swiglu_forward ( const float *  input,
float *  output,
int  tokens,
int  dim 
)

SwiGLU forward pass

Test:

test_swiglu.py::TestSwiGLUForward::test_forward_tokens

test_swiglu.py::TestSwiGLUForward::test_forward_single

test_mlp.py::TestMLPForward::test_swiglu_mlp

test_fused_swiglu_decode.py::TestFusedSwiGLUDecode::test_fused_swiglu_decode

test_parity.py::test_swiglu_parity

SwiGLU: y = silu(gate) * up where silu(x) = x * sigmoid(x)

After changes: make test && make llamacpp-parity-full

Definition at line 237 of file swiglu_kernels.c.

241{
242 const char *fast_env = getenv("CK_SWIGLU_FAST");
243 const char *exact_env = getenv("CK_SWIGLU_EXACT");
245 !(fast_env && atoi(fast_env) != 0) ||
246 (exact_env && atoi(exact_env) != 0)) {
247 swiglu_forward_exact(input, output, tokens, dim);
248 return;
249 }
250
251 int T = tokens;
252 int D = dim;
253
254 for (int t = 0; t < T; ++t) {
255 const float *row = input + (size_t)t * (2 * D);
256 float *out_row = output + (size_t)t * D;
257 int d = 0;
258
259#if defined(__AVX512F__)
260 // AVX-512: Process 16 floats at a time
261 for (; d + 16 <= D; d += 16) {
262 __m512 a = _mm512_loadu_ps(&row[d]); // gate
263 __m512 b = _mm512_loadu_ps(&row[D + d]); // value
264
265 __m512 s = sigmoid512_fast(a); // sigmoid(a)
266 __m512 silu = _mm512_mul_ps(a, s); // silu(a) = a * sigmoid(a)
267 __m512 y = _mm512_mul_ps(silu, b); // y = silu(a) * b
268
269 _mm512_storeu_ps(&out_row[d], y);
270 }
271#elif defined(__AVX2__)
272 // AVX2: Process 8 floats at a time
273 for (; d + 8 <= D; d += 8) {
274 __m256 a = _mm256_loadu_ps(&row[d]); // gate
275 __m256 b = _mm256_loadu_ps(&row[D + d]); // value
276
277 __m256 s = sigmoid256_fast(a); // sigmoid(a)
278 __m256 silu = _mm256_mul_ps(a, s); // silu(a) = a * sigmoid(a)
279 __m256 y = _mm256_mul_ps(silu, b); // y = silu(a) * b
280
281 _mm256_storeu_ps(&out_row[d], y);
282 }
283#elif defined(__AVX__)
284 // AVX1: Vectorize arithmetic, use scalar sigmoid
285 float a_arr[8] __attribute__((aligned(32)));
286 float s_arr[8] __attribute__((aligned(32)));
287
288 for (; d + 8 <= D; d += 8) {
289 __m256 a = _mm256_loadu_ps(&row[d]); // gate
290 __m256 b = _mm256_loadu_ps(&row[D + d]); // value
291
292 // Compute sigmoid scalarly
293 _mm256_store_ps(a_arr, a);
294 for (int j = 0; j < 8; ++j) {
295 s_arr[j] = sigmoid_scalar(a_arr[j]);
296 }
297 __m256 s = _mm256_load_ps(s_arr);
298
299 __m256 silu = _mm256_mul_ps(a, s); // silu(a) = a * sigmoid(a)
300 __m256 y = _mm256_mul_ps(silu, b); // y = silu(a) * b
301
302 _mm256_storeu_ps(&out_row[d], y);
303 }
304#endif
305
306 // Scalar fallback for remaining elements
307 for (; d < D; ++d) {
308 float a = row[d]; // gate
309 float b = row[D + d]; // value
310
311 float s = sigmoid_scalar(a); // sigmoid(a)
312 float silu = a * s; // silu(a) = a * sigmoid(a)
313
314 out_row[d] = silu * b;
315 }
316 }
317}
void swiglu_forward_exact(const float *input, float *output, int tokens, int dim)

References __attribute__(), ck_strict_parity_enabled(), sigmoid_scalar(), silu(), and swiglu_forward_exact().

Referenced by ck_mlp_swiglu_forward(), ck_mlp_swiglu_forward_q4_k(), ck_mlp_swiglu_forward_q4_k_q8_k(), ck_mlp_swiglu_forward_q4_k_q8_k_prefill(), ck_mlp_swiglu_forward_quant(), ck_mlp_swiglu_forward_ref(), model_layer_0_decode(), model_layer_0_decode(), model_layer_0_decode(), model_layer_0_decode(), model_layer_0_prefill(), model_layer_0_prefill(), model_layer_0_prefill(), model_layer_0_prefill(), model_layer_10_decode(), model_layer_10_decode(), model_layer_10_decode(), model_layer_10_decode(), model_layer_10_prefill(), model_layer_10_prefill(), model_layer_10_prefill(), model_layer_10_prefill(), model_layer_11_decode(), model_layer_11_decode(), model_layer_11_decode(), model_layer_11_decode(), model_layer_11_prefill(), model_layer_11_prefill(), model_layer_11_prefill(), model_layer_11_prefill(), model_layer_12_decode(), model_layer_12_decode(), model_layer_12_decode(), model_layer_12_decode(), model_layer_12_prefill(), model_layer_12_prefill(), model_layer_12_prefill(), model_layer_12_prefill(), model_layer_13_decode(), model_layer_13_decode(), model_layer_13_decode(), model_layer_13_decode(), model_layer_13_prefill(), model_layer_13_prefill(), model_layer_13_prefill(), model_layer_13_prefill(), model_layer_14_decode(), model_layer_14_decode(), model_layer_14_decode(), model_layer_14_decode(), model_layer_14_prefill(), model_layer_14_prefill(), model_layer_14_prefill(), model_layer_14_prefill(), model_layer_15_decode(), model_layer_15_decode(), model_layer_15_decode(), model_layer_15_decode(), model_layer_15_prefill(), model_layer_15_prefill(), model_layer_15_prefill(), model_layer_15_prefill(), model_layer_16_decode(), model_layer_16_decode(), model_layer_16_decode(), model_layer_16_decode(), model_layer_16_prefill(), model_layer_16_prefill(), model_layer_16_prefill(), model_layer_16_prefill(), model_layer_17_decode(), model_layer_17_decode(), model_layer_17_decode(), model_layer_17_decode(), model_layer_17_prefill(), model_layer_17_prefill(), model_layer_17_prefill(), model_layer_17_prefill(), model_layer_18_decode(), model_layer_18_decode(), model_layer_18_decode(), model_layer_18_decode(), model_layer_18_prefill(), model_layer_18_prefill(), model_layer_18_prefill(), model_layer_18_prefill(), model_layer_19_decode(), model_layer_19_decode(), model_layer_19_decode(), model_layer_19_decode(), model_layer_19_prefill(), model_layer_19_prefill(), model_layer_19_prefill(), model_layer_19_prefill(), model_layer_1_decode(), model_layer_1_decode(), model_layer_1_decode(), model_layer_1_decode(), model_layer_1_prefill(), model_layer_1_prefill(), model_layer_1_prefill(), model_layer_1_prefill(), model_layer_20_decode(), model_layer_20_decode(), model_layer_20_decode(), model_layer_20_decode(), model_layer_20_prefill(), model_layer_20_prefill(), model_layer_20_prefill(), model_layer_20_prefill(), model_layer_21_decode(), model_layer_21_decode(), model_layer_21_decode(), model_layer_21_decode(), model_layer_21_prefill(), model_layer_21_prefill(), model_layer_21_prefill(), model_layer_21_prefill(), model_layer_22_decode(), model_layer_22_decode(), model_layer_22_decode(), model_layer_22_decode(), model_layer_22_prefill(), model_layer_22_prefill(), model_layer_22_prefill(), model_layer_22_prefill(), model_layer_23_decode(), model_layer_23_decode(), model_layer_23_decode(), model_layer_23_decode(), model_layer_23_prefill(), model_layer_23_prefill(), model_layer_23_prefill(), model_layer_23_prefill(), model_layer_2_decode(), model_layer_2_decode(), model_layer_2_decode(), model_layer_2_decode(), model_layer_2_prefill(), model_layer_2_prefill(), model_layer_2_prefill(), model_layer_2_prefill(), model_layer_3_decode(), model_layer_3_decode(), model_layer_3_decode(), model_layer_3_decode(), model_layer_3_prefill(), model_layer_3_prefill(), model_layer_3_prefill(), model_layer_3_prefill(), model_layer_4_decode(), model_layer_4_decode(), model_layer_4_decode(), model_layer_4_decode(), model_layer_4_prefill(), model_layer_4_prefill(), model_layer_4_prefill(), model_layer_4_prefill(), model_layer_5_decode(), model_layer_5_decode(), model_layer_5_decode(), model_layer_5_decode(), model_layer_5_prefill(), model_layer_5_prefill(), model_layer_5_prefill(), model_layer_5_prefill(), model_layer_6_decode(), model_layer_6_decode(), model_layer_6_decode(), model_layer_6_decode(), model_layer_6_prefill(), model_layer_6_prefill(), model_layer_6_prefill(), model_layer_6_prefill(), model_layer_7_decode(), model_layer_7_decode(), model_layer_7_decode(), model_layer_7_decode(), model_layer_7_prefill(), model_layer_7_prefill(), model_layer_7_prefill(), model_layer_7_prefill(), model_layer_8_decode(), model_layer_8_decode(), model_layer_8_decode(), model_layer_8_decode(), model_layer_8_prefill(), model_layer_8_prefill(), model_layer_8_prefill(), model_layer_8_prefill(), model_layer_9_decode(), model_layer_9_decode(), model_layer_9_decode(), model_layer_9_decode(), model_layer_9_prefill(), model_layer_9_prefill(), model_layer_9_prefill(), model_layer_9_prefill(), qwen2_0_5b_decode_layer_0_decode(), qwen2_0_5b_decode_layer_0_decode(), qwen2_0_5b_decode_layer_0_decode(), qwen2_0_5b_decode_layer_0_decode(), qwen2_0_5b_decode_layer_0_decode(), qwen2_0_5b_decode_layer_0_prefill(), qwen2_0_5b_decode_layer_0_prefill(), qwen2_0_5b_decode_layer_0_prefill(), qwen2_0_5b_decode_layer_0_prefill(), qwen2_0_5b_decode_layer_10_decode(), qwen2_0_5b_decode_layer_10_decode(), qwen2_0_5b_decode_layer_10_decode(), qwen2_0_5b_decode_layer_10_decode(), qwen2_0_5b_decode_layer_10_decode(), qwen2_0_5b_decode_layer_10_prefill(), qwen2_0_5b_decode_layer_10_prefill(), qwen2_0_5b_decode_layer_10_prefill(), qwen2_0_5b_decode_layer_10_prefill(), qwen2_0_5b_decode_layer_11_decode(), qwen2_0_5b_decode_layer_11_decode(), qwen2_0_5b_decode_layer_11_decode(), qwen2_0_5b_decode_layer_11_decode(), qwen2_0_5b_decode_layer_11_decode(), qwen2_0_5b_decode_layer_11_prefill(), qwen2_0_5b_decode_layer_11_prefill(), qwen2_0_5b_decode_layer_11_prefill(), qwen2_0_5b_decode_layer_11_prefill(), qwen2_0_5b_decode_layer_12_decode(), qwen2_0_5b_decode_layer_12_decode(), qwen2_0_5b_decode_layer_12_decode(), qwen2_0_5b_decode_layer_12_decode(), qwen2_0_5b_decode_layer_12_decode(), qwen2_0_5b_decode_layer_12_prefill(), qwen2_0_5b_decode_layer_12_prefill(), qwen2_0_5b_decode_layer_12_prefill(), qwen2_0_5b_decode_layer_12_prefill(), qwen2_0_5b_decode_layer_13_decode(), qwen2_0_5b_decode_layer_13_decode(), qwen2_0_5b_decode_layer_13_decode(), qwen2_0_5b_decode_layer_13_decode(), qwen2_0_5b_decode_layer_13_decode(), qwen2_0_5b_decode_layer_13_prefill(), qwen2_0_5b_decode_layer_13_prefill(), qwen2_0_5b_decode_layer_13_prefill(), qwen2_0_5b_decode_layer_13_prefill(), qwen2_0_5b_decode_layer_14_decode(), qwen2_0_5b_decode_layer_14_decode(), qwen2_0_5b_decode_layer_14_decode(), qwen2_0_5b_decode_layer_14_decode(), qwen2_0_5b_decode_layer_14_decode(), qwen2_0_5b_decode_layer_14_prefill(), qwen2_0_5b_decode_layer_14_prefill(), qwen2_0_5b_decode_layer_14_prefill(), qwen2_0_5b_decode_layer_14_prefill(), qwen2_0_5b_decode_layer_15_decode(), qwen2_0_5b_decode_layer_15_decode(), qwen2_0_5b_decode_layer_15_decode(), qwen2_0_5b_decode_layer_15_decode(), qwen2_0_5b_decode_layer_15_decode(), qwen2_0_5b_decode_layer_15_prefill(), qwen2_0_5b_decode_layer_15_prefill(), qwen2_0_5b_decode_layer_15_prefill(), qwen2_0_5b_decode_layer_15_prefill(), qwen2_0_5b_decode_layer_16_decode(), qwen2_0_5b_decode_layer_16_decode(), qwen2_0_5b_decode_layer_16_decode(), qwen2_0_5b_decode_layer_16_decode(), qwen2_0_5b_decode_layer_16_decode(), qwen2_0_5b_decode_layer_16_prefill(), qwen2_0_5b_decode_layer_16_prefill(), qwen2_0_5b_decode_layer_16_prefill(), qwen2_0_5b_decode_layer_16_prefill(), qwen2_0_5b_decode_layer_17_decode(), qwen2_0_5b_decode_layer_17_decode(), qwen2_0_5b_decode_layer_17_decode(), qwen2_0_5b_decode_layer_17_decode(), qwen2_0_5b_decode_layer_17_decode(), qwen2_0_5b_decode_layer_17_prefill(), qwen2_0_5b_decode_layer_17_prefill(), qwen2_0_5b_decode_layer_17_prefill(), qwen2_0_5b_decode_layer_17_prefill(), qwen2_0_5b_decode_layer_18_decode(), qwen2_0_5b_decode_layer_18_decode(), qwen2_0_5b_decode_layer_18_decode(), qwen2_0_5b_decode_layer_18_decode(), qwen2_0_5b_decode_layer_18_decode(), qwen2_0_5b_decode_layer_18_prefill(), qwen2_0_5b_decode_layer_18_prefill(), qwen2_0_5b_decode_layer_18_prefill(), qwen2_0_5b_decode_layer_18_prefill(), qwen2_0_5b_decode_layer_19_decode(), qwen2_0_5b_decode_layer_19_decode(), qwen2_0_5b_decode_layer_19_decode(), qwen2_0_5b_decode_layer_19_decode(), qwen2_0_5b_decode_layer_19_decode(), qwen2_0_5b_decode_layer_19_prefill(), qwen2_0_5b_decode_layer_19_prefill(), qwen2_0_5b_decode_layer_19_prefill(), qwen2_0_5b_decode_layer_19_prefill(), qwen2_0_5b_decode_layer_1_decode(), qwen2_0_5b_decode_layer_1_decode(), qwen2_0_5b_decode_layer_1_decode(), qwen2_0_5b_decode_layer_1_decode(), qwen2_0_5b_decode_layer_1_decode(), qwen2_0_5b_decode_layer_1_prefill(), qwen2_0_5b_decode_layer_1_prefill(), qwen2_0_5b_decode_layer_1_prefill(), qwen2_0_5b_decode_layer_1_prefill(), qwen2_0_5b_decode_layer_20_decode(), qwen2_0_5b_decode_layer_20_decode(), qwen2_0_5b_decode_layer_20_decode(), qwen2_0_5b_decode_layer_20_decode(), qwen2_0_5b_decode_layer_20_decode(), qwen2_0_5b_decode_layer_20_prefill(), qwen2_0_5b_decode_layer_20_prefill(), qwen2_0_5b_decode_layer_20_prefill(), qwen2_0_5b_decode_layer_20_prefill(), qwen2_0_5b_decode_layer_21_decode(), qwen2_0_5b_decode_layer_21_decode(), qwen2_0_5b_decode_layer_21_decode(), qwen2_0_5b_decode_layer_21_decode(), qwen2_0_5b_decode_layer_21_decode(), qwen2_0_5b_decode_layer_21_prefill(), qwen2_0_5b_decode_layer_21_prefill(), qwen2_0_5b_decode_layer_21_prefill(), qwen2_0_5b_decode_layer_21_prefill(), qwen2_0_5b_decode_layer_22_decode(), qwen2_0_5b_decode_layer_22_decode(), qwen2_0_5b_decode_layer_22_decode(), qwen2_0_5b_decode_layer_22_decode(), qwen2_0_5b_decode_layer_22_decode(), qwen2_0_5b_decode_layer_22_prefill(), qwen2_0_5b_decode_layer_22_prefill(), qwen2_0_5b_decode_layer_22_prefill(), qwen2_0_5b_decode_layer_22_prefill(), qwen2_0_5b_decode_layer_23_decode(), qwen2_0_5b_decode_layer_23_decode(), qwen2_0_5b_decode_layer_23_decode(), qwen2_0_5b_decode_layer_23_decode(), qwen2_0_5b_decode_layer_23_decode(), qwen2_0_5b_decode_layer_23_prefill(), qwen2_0_5b_decode_layer_23_prefill(), qwen2_0_5b_decode_layer_23_prefill(), qwen2_0_5b_decode_layer_23_prefill(), qwen2_0_5b_decode_layer_2_decode(), qwen2_0_5b_decode_layer_2_decode(), qwen2_0_5b_decode_layer_2_decode(), qwen2_0_5b_decode_layer_2_decode(), qwen2_0_5b_decode_layer_2_decode(), qwen2_0_5b_decode_layer_2_prefill(), qwen2_0_5b_decode_layer_2_prefill(), qwen2_0_5b_decode_layer_2_prefill(), qwen2_0_5b_decode_layer_2_prefill(), qwen2_0_5b_decode_layer_3_decode(), qwen2_0_5b_decode_layer_3_decode(), qwen2_0_5b_decode_layer_3_decode(), qwen2_0_5b_decode_layer_3_decode(), qwen2_0_5b_decode_layer_3_decode(), qwen2_0_5b_decode_layer_3_prefill(), qwen2_0_5b_decode_layer_3_prefill(), qwen2_0_5b_decode_layer_3_prefill(), qwen2_0_5b_decode_layer_3_prefill(), qwen2_0_5b_decode_layer_4_decode(), qwen2_0_5b_decode_layer_4_decode(), qwen2_0_5b_decode_layer_4_decode(), qwen2_0_5b_decode_layer_4_decode(), qwen2_0_5b_decode_layer_4_decode(), qwen2_0_5b_decode_layer_4_prefill(), qwen2_0_5b_decode_layer_4_prefill(), qwen2_0_5b_decode_layer_4_prefill(), qwen2_0_5b_decode_layer_4_prefill(), qwen2_0_5b_decode_layer_5_decode(), qwen2_0_5b_decode_layer_5_decode(), qwen2_0_5b_decode_layer_5_decode(), qwen2_0_5b_decode_layer_5_decode(), qwen2_0_5b_decode_layer_5_decode(), qwen2_0_5b_decode_layer_5_prefill(), qwen2_0_5b_decode_layer_5_prefill(), qwen2_0_5b_decode_layer_5_prefill(), qwen2_0_5b_decode_layer_5_prefill(), qwen2_0_5b_decode_layer_6_decode(), qwen2_0_5b_decode_layer_6_decode(), qwen2_0_5b_decode_layer_6_decode(), qwen2_0_5b_decode_layer_6_decode(), qwen2_0_5b_decode_layer_6_decode(), qwen2_0_5b_decode_layer_6_prefill(), qwen2_0_5b_decode_layer_6_prefill(), qwen2_0_5b_decode_layer_6_prefill(), qwen2_0_5b_decode_layer_6_prefill(), qwen2_0_5b_decode_layer_7_decode(), qwen2_0_5b_decode_layer_7_decode(), qwen2_0_5b_decode_layer_7_decode(), qwen2_0_5b_decode_layer_7_decode(), qwen2_0_5b_decode_layer_7_decode(), qwen2_0_5b_decode_layer_7_prefill(), qwen2_0_5b_decode_layer_7_prefill(), qwen2_0_5b_decode_layer_7_prefill(), qwen2_0_5b_decode_layer_7_prefill(), qwen2_0_5b_decode_layer_8_decode(), qwen2_0_5b_decode_layer_8_decode(), qwen2_0_5b_decode_layer_8_decode(), qwen2_0_5b_decode_layer_8_decode(), qwen2_0_5b_decode_layer_8_decode(), qwen2_0_5b_decode_layer_8_prefill(), qwen2_0_5b_decode_layer_8_prefill(), qwen2_0_5b_decode_layer_8_prefill(), qwen2_0_5b_decode_layer_8_prefill(), qwen2_0_5b_decode_layer_9_decode(), qwen2_0_5b_decode_layer_9_decode(), qwen2_0_5b_decode_layer_9_decode(), qwen2_0_5b_decode_layer_9_decode(), qwen2_0_5b_decode_layer_9_decode(), qwen2_0_5b_decode_layer_9_prefill(), qwen2_0_5b_decode_layer_9_prefill(), qwen2_0_5b_decode_layer_9_prefill(), and qwen2_0_5b_decode_layer_9_prefill().

◆ swiglu_forward_bf16()

void swiglu_forward_bf16 ( const uint16_t *  input,
uint16_t *  output,
int  tokens,
int  dim 
)

Definition at line 66 of file swiglu_kernels_bf16.c.

70{
71 if (!input || !output || tokens <= 0 || dim <= 0) {
72 return;
73 }
74
75 const int T = tokens;
76 const int D = dim;
77
78 for (int t = 0; t < T; ++t) {
79 const uint16_t *row = input + (size_t)t * (size_t)(2 * D);
80 uint16_t *out_row = output + (size_t)t * (size_t)D;
81 int d = 0;
82
83#if defined(__AVX512F__)
84 // AVX-512: Process 16 floats at a time
85 for (; d + 16 <= D; d += 16) {
86 __m512 a = bf16_loadu_cvt_fp32(&row[d]); // gate
87 __m512 b = bf16_loadu_cvt_fp32(&row[D + d]); // value
88
89 __m512 s = sigmoid512_fast_bf16(a); // sigmoid(a)
90 __m512 silu = _mm512_mul_ps(a, s); // silu(a) = a * sigmoid(a)
91 __m512 y = _mm512_mul_ps(silu, b); // y = silu(a) * b
92
93 fp32_cvt_storeu_bf16(&out_row[d], y);
94 }
95#endif
96
97 // Scalar fallback for remaining elements
98 for (; d < D; ++d) {
99 float a = bf16_to_float(row[d]);
100 float b = bf16_to_float(row[D + d]);
101 float s = sigmoid_scalar(a);
102 float silu = a * s;
103 out_row[d] = float_to_bf16(silu * b);
104 }
105 }
106}

References bf16_to_float(), float_to_bf16(), sigmoid_scalar(), and silu().

◆ swiglu_forward_exact()

void swiglu_forward_exact ( const float *  input,
float *  output,
int  tokens,
int  dim 
)

SwiGLU forward pass (exact version using stdlib sigmoid)

Test:

test_swiglu.py::TestSwiGLUForward::test_exact_vs_fast

test_swiglu.py::TestSwiGLUForward::test_exact_single

Uses standard library expf for numerical accuracy reference.

After changes: make test

Definition at line 515 of file swiglu_kernels.c.

519{
520 int T = tokens;
521 int D = dim;
522
523 for (int t = 0; t < T; ++t) {
524 const float *row = input + (size_t)t * (2 * D);
525 float *out_row = output + (size_t)t * D;
526
527 for (int d = 0; d < D; ++d) {
528 float a = row[d]; // gate
529 float b = row[D + d]; // value
530
531 float s = sigmoid_scalar_parity(a); // sigmoid(a)
532 float silu = a * s; // silu(a)
533 out_row[d] = silu * b;
534 }
535 }
536}

References sigmoid_scalar_parity(), and silu().

Referenced by ck_mlp_swiglu_forward(), ck_mlp_swiglu_forward_ref(), and swiglu_forward().

◆ swiglu_forward_ggml()

void swiglu_forward_ggml ( const float *  input,
float *  output,
int  tokens,
int  dim 
)

Definition at line 538 of file swiglu_kernels.c.

542{
543 for (int t = 0; t < tokens; ++t) {
544 const float *row = input + (size_t)t * (2 * dim);
545 float *out_row = output + (size_t)t * dim;
546 int d = 0;
547
548#if defined(__AVX512F__) && defined(__AVX512DQ__)
549 for (; d + 16 <= dim; d += 16) {
550 const __m512 gate = _mm512_loadu_ps(row + d);
551 const __m512 up = _mm512_loadu_ps(row + dim + d);
552 const __m512 neg_gate = _mm512_sub_ps(_mm512_setzero_ps(), gate);
553 const __m512 denom = _mm512_add_ps(
554 _mm512_set1_ps(1.0f), ck_ggml_expf_avx512(neg_gate));
555 const __m512 silu = _mm512_div_ps(gate, denom);
556 _mm512_storeu_ps(out_row + d, _mm512_mul_ps(silu, up));
557 }
558#elif defined(__AVX2__) && defined(__FMA__)
559 for (; d + 8 <= dim; d += 8) {
560 const __m256 gate = _mm256_loadu_ps(row + d);
561 const __m256 up = _mm256_loadu_ps(row + dim + d);
562 const __m256 neg_gate = _mm256_sub_ps(_mm256_setzero_ps(), gate);
563 const __m256 denom = _mm256_add_ps(
564 _mm256_set1_ps(1.0f), ck_ggml_expf_avx2(neg_gate));
565 const __m256 silu = _mm256_div_ps(gate, denom);
566 _mm256_storeu_ps(out_row + d, _mm256_mul_ps(silu, up));
567 }
568#endif
569 for (; d < dim; ++d) {
570 const float gate = row[d];
571 out_row[d] = (gate / (1.0f + expf(-gate))) * row[dim + d];
572 }
573 }
574}

References silu().

Referenced by ck_moe_q4k_mixed_route_work(), ck_moe_q4k_q5k_bucket_work(), ck_moe_q4k_q5k_route_work(), moe_swiglu_expert_forward_q4k_q4k_workspace(), moe_swiglu_expert_forward_q4k_q5_0_workspace(), moe_swiglu_expert_forward_q4k_q5k_workspace(), moe_swiglu_expert_forward_q4k_q6k_workspace(), moe_swiglu_expert_forward_q4k_q8_0_workspace(), moe_swiglu_shared_forward_q4k_q4k_workspace(), moe_swiglu_shared_forward_q4k_q6k_workspace(), and moe_swiglu_shared_forward_q8_0_gated_workspace().

◆ swiglu_forward_ggml_split()

void swiglu_forward_ggml_split ( const float *  gate,
const float *  up,
float *  output,
int  tokens,
int  dim 
)

Definition at line 576 of file swiglu_kernels.c.

581{
582 if (!gate || !up || !output || tokens <= 0 || dim <= 0) {
583 return;
584 }
585 for (int t = 0; t < tokens; ++t) {
586 const float *gate_row = gate + (size_t)t * (size_t)dim;
587 const float *up_row = up + (size_t)t * (size_t)dim;
588 float *out_row = output + (size_t)t * (size_t)dim;
589 int d = 0;
590
591#if defined(__AVX512F__) && defined(__AVX512DQ__)
592 for (; d + 16 <= dim; d += 16) {
593 const __m512 gate_v = _mm512_loadu_ps(gate_row + d);
594 const __m512 up_v = _mm512_loadu_ps(up_row + d);
595 const __m512 neg_gate = _mm512_sub_ps(_mm512_setzero_ps(), gate_v);
596 const __m512 denom = _mm512_add_ps(
597 _mm512_set1_ps(1.0f), ck_ggml_expf_avx512(neg_gate));
598 const __m512 silu = _mm512_div_ps(gate_v, denom);
599 _mm512_storeu_ps(out_row + d, _mm512_mul_ps(silu, up_v));
600 }
601#elif defined(__AVX2__) && defined(__FMA__)
602 for (; d + 8 <= dim; d += 8) {
603 const __m256 gate_v = _mm256_loadu_ps(gate_row + d);
604 const __m256 up_v = _mm256_loadu_ps(up_row + d);
605 const __m256 neg_gate = _mm256_sub_ps(_mm256_setzero_ps(), gate_v);
606 const __m256 denom = _mm256_add_ps(
607 _mm256_set1_ps(1.0f), ck_ggml_expf_avx2(neg_gate));
608 const __m256 silu = _mm256_div_ps(gate_v, denom);
609 _mm256_storeu_ps(out_row + d, _mm256_mul_ps(silu, up_v));
610 }
611#endif
612 for (; d < dim; ++d) {
613 const float gate_v = gate_row[d];
614 out_row[d] = (gate_v / (1.0f + expf(-gate_v))) * up_row[d];
615 }
616 }
617}

References silu().

Referenced by ck_moe_q4k_q5k_bucket_work(), and ck_moe_shared_q4k_gated_workspace().

◆ swiglu_forward_pytorch_bf16_storage()

void swiglu_forward_pytorch_bf16_storage ( const float *  input,
float *  output,
int  tokens,
int  dim 
)

Definition at line 658 of file swiglu_kernels.c.

662{
663 if (!input || !output || tokens < 0 || dim < 0) {
664 fprintf(stderr, "HARD KERNEL CONTRACT FAULT: invalid PyTorch BF16 SwiGLU arguments\n");
665 abort();
666 }
667
668#if defined(__AVX512F__)
669 pthread_once(&ck_pytorch_swiglu_once, ck_bind_pytorch_swiglu_sleef);
670 if (!ck_pytorch_swiglu_expf16) {
671 fprintf(stderr,
672 "HARD KERNEL CONTRACT FAULT: PyTorch BF16 SwiGLU requires "
673 "SLEEF Sleef_expf16_u10; set CK_SLEEF_LIBRARY\n");
674 abort();
675 }
676#endif
677
678 for (int t = 0; t < tokens; ++t) {
679 const float *row = input + (size_t)t * (size_t)(2 * dim);
680 float *out_row = output + (size_t)t * (size_t)dim;
681 int d = 0;
682
683#if defined(__AVX512F__)
684 for (; d + 16 <= dim; d += 16) {
685 const __m512 gate = _mm512_loadu_ps(row + d);
686 const __m512 denominator = _mm512_add_ps(
687 _mm512_set1_ps(1.0f),
688 ck_pytorch_swiglu_expf16(_mm512_sub_ps(_mm512_setzero_ps(), gate)));
689 const __m512 silu = _mm512_div_ps(gate, denominator);
690 float silu_lanes[16] __attribute__((aligned(64)));
691 _mm512_store_ps(silu_lanes, silu);
692 for (int lane = 0; lane < 16; ++lane) {
693 const float silu_bf16 = bf16_to_float(float_to_bf16(silu_lanes[lane]));
694 const float up_bf16 = bf16_to_float(float_to_bf16(row[dim + d + lane]));
695 out_row[d + lane] = bf16_to_float(
696 float_to_bf16(silu_bf16 * up_bf16));
697 }
698 }
699#endif
700 for (; d < dim; ++d) {
701 const float gate_bf16 = bf16_to_float(float_to_bf16(row[d]));
702 const float up_bf16 = bf16_to_float(float_to_bf16(row[dim + d]));
703 const float silu = gate_bf16 / (1.0f + expf(-gate_bf16));
704 const float silu_bf16 = bf16_to_float(float_to_bf16(silu));
705 out_row[d] = bf16_to_float(float_to_bf16(silu_bf16 * up_bf16));
706 }
707 }
708}

References __attribute__(), bf16_to_float(), float_to_bf16(), and silu().

Referenced by moe_swiglu_packed_expert_forward_bf16().

◆ swiglu_forward_q8_k()

void swiglu_forward_q8_k ( const float *  input,
void *  output_q8,
int  tokens,
int  dim 
)

Definition at line 319 of file swiglu_kernels.c.

323{
324 if (!input || !output_q8 || tokens <= 0 || dim <= 0) {
325 return;
326 }
327 if ((dim % QK_K) != 0) {
328 return;
329 }
330
331 const char *fast_env = getenv("CK_SWIGLU_FAST");
332 const char *exact_env = getenv("CK_SWIGLU_EXACT");
333 const int use_fast = !ck_strict_parity_enabled() &&
334 (fast_env && atoi(fast_env) != 0) &&
335 !(exact_env && atoi(exact_env) != 0);
336
337 const int blocks_per_row = dim / QK_K;
338 block_q8_K *q8 = (block_q8_K *)output_q8;
339 float tmp[QK_K];
340
341 for (int t = 0; t < tokens; ++t) {
342 const float *row = input + (size_t)t * (size_t)(2 * dim);
343 block_q8_K *q8_row = q8 + (size_t)t * (size_t)blocks_per_row;
344
345 for (int block = 0; block < blocks_per_row; ++block) {
346 const int base = block * QK_K;
347 int d = 0;
348
349#if defined(__AVX2__)
350 if (use_fast) {
351 for (; d + 8 <= QK_K; d += 8) {
352 const __m256 a = _mm256_loadu_ps(row + base + d);
353 const __m256 b = _mm256_loadu_ps(row + dim + base + d);
354 const __m256 s = sigmoid256_fast(a);
355 const __m256 y = _mm256_mul_ps(_mm256_mul_ps(a, s), b);
356 _mm256_storeu_ps(tmp + d, y);
357 }
358 }
359#else
360 (void)use_fast;
361#endif
362
363 for (; d < QK_K; ++d) {
364 const float a = row[base + d];
365 const float b = row[dim + base + d];
366 const float s = use_fast ? sigmoid_scalar(a) : sigmoid_scalar_parity(a);
367 tmp[d] = (a * s) * b;
368 }
369
370 quantize_row_q8_k(tmp, (void *)&q8_row[block], QK_K);
371 }
372 }
373}

References ck_strict_parity_enabled(), QK_K, quantize_row_q8_k(), sigmoid_scalar(), and sigmoid_scalar_parity().

◆ topk_batched_f32()

void topk_batched_f32 ( const float *  scores,
int  num_tokens,
int  n_experts,
int  k,
int *  indices,
float *  weights 
)

Batched top-K selection for multiple tokens.

Parameters
scoresInput scores [num_tokens, n_experts]
num_tokensNumber of tokens
n_expertsNumber of experts
kNumber of experts to select per token
indicesOutput: selected expert indices [num_tokens, k]
weightsOutput: routing weights [num_tokens, k] (can be NULL for no softmax)

Definition at line 465 of file topk_kernels.c.

471{
472 if (!scores || !indices || num_tokens <= 0 || n_experts <= 0 || k <= 0) {
473 return;
474 }
475
476 for (int t = 0; t < num_tokens; t++) {
477 const float *token_scores = scores + t * n_experts;
478 int *token_indices = indices + t * k;
479
480 if (weights) {
481 float *token_weights = weights + t * k;
482 topk_softmax_f32(token_scores, n_experts, k, token_indices, token_weights);
483 } else {
484 topk_f32(token_scores, n_experts, k, token_indices, NULL);
485 }
486 }
487}
void topk_softmax_f32(const float *scores, int n, int k, int *indices, float *weights)
Find top-K indices with softmax-normalized weights.

References topk_f32(), and topk_softmax_f32().

◆ topk_f32()

void topk_f32 ( const float *  scores,
int  n,
int  k,
int *  indices,
float *  values 
)

Find top-K indices and values from a score vector.

Parameters
scoresInput scores [n]
nNumber of scores (e.g., number of experts)
kNumber of top scores to select
indicesOutput: indices of top-K scores [k], sorted descending by value
valuesOutput: top-K score values [k], sorted descending (can be NULL)

Definition at line 51 of file topk_kernels.c.

56{
57 if (!scores || !indices || n <= 0 || k <= 0) {
58 return;
59 }
60
61 /* Clamp k to n */
62 if (k > n) {
63 k = n;
64 }
65
66 /* Initialize with first k elements */
67 float local_values[k];
68 for (int i = 0; i < k; i++) {
69 indices[i] = i;
70 local_values[i] = scores[i];
71 }
72
73 /* Find the minimum in our current top-k */
74 int min_idx = 0;
75 for (int i = 1; i < k; i++) {
76 if (local_values[i] < local_values[min_idx]) {
77 min_idx = i;
78 }
79 }
80
81 /* Scan remaining elements */
82 for (int i = k; i < n; i++) {
83 if (scores[i] > local_values[min_idx]) {
84 /* Replace the minimum */
85 indices[min_idx] = i;
86 local_values[min_idx] = scores[i];
87
88 /* Find new minimum */
89 min_idx = 0;
90 for (int j = 1; j < k; j++) {
91 if (local_values[j] < local_values[min_idx]) {
92 min_idx = j;
93 }
94 }
95 }
96 }
97
98 /* Sort results in descending order (simple insertion sort for small k) */
99 for (int i = 1; i < k; i++) {
100 float val = local_values[i];
101 int idx = indices[i];
102 int j = i - 1;
103 while (j >= 0 && local_values[j] < val) {
104 local_values[j + 1] = local_values[j];
105 indices[j + 1] = indices[j];
106 j--;
107 }
108 local_values[j + 1] = val;
109 indices[j + 1] = idx;
110 }
111
112 /* Copy values if output requested */
113 if (values) {
114 for (int i = 0; i < k; i++) {
115 values[i] = local_values[i];
116 }
117 }
118}

Referenced by moe_softmax_topk_router_llama_f32_workspace(), topk_batched_f32(), and topk_softmax_f32().

◆ topk_softmax_backward_f32()

void topk_softmax_backward_f32 ( const int *  indices,
const float *  weights,
const float *  d_weights,
float *  d_scores,
int  num_tokens,
int  n_experts_or_keys,
int  k 
)

Backward for hard top-k followed by softmax over selected values.

Matches PyTorch behavior for: values, indices = torch.topk(scores, k, dim=-1) weights = torch.softmax(values, dim=-1)

The hard selected indices are treated as fixed for this backward pass. Gradients are scattered only to selected scores; unselected scores are zero.

Definition at line 408 of file topk_kernels.c.

415{
416 if (!indices || !weights || !d_weights || !d_scores ||
417 num_tokens <= 0 || n_experts_or_keys <= 0 || k <= 0) {
418 return;
419 }
420
421 const size_t total = (size_t)num_tokens * (size_t)n_experts_or_keys;
422 for (size_t i = 0; i < total; ++i) {
423 d_scores[i] = 0.0f;
424 }
425
426 for (int t = 0; t < num_tokens; ++t) {
427 const int *row_indices = indices + (size_t)t * (size_t)k;
428 const float *row_weights = weights + (size_t)t * (size_t)k;
429 const float *row_d_weights = d_weights + (size_t)t * (size_t)k;
430 float *row_d_scores = d_scores + (size_t)t * (size_t)n_experts_or_keys;
431
432 float dot = 0.0f;
433 for (int i = 0; i < k; ++i) {
434 const int idx = row_indices[i];
435 if (idx >= 0 && idx < n_experts_or_keys) {
436 dot += row_weights[i] * row_d_weights[i];
437 }
438 }
439
440 for (int i = 0; i < k; ++i) {
441 const int idx = row_indices[i];
442 if (idx >= 0 && idx < n_experts_or_keys) {
443 row_d_scores[idx] += row_weights[i] * (row_d_weights[i] - dot);
444 }
445 }
446 }
447}

◆ topk_softmax_f32()

void topk_softmax_f32 ( const float *  scores,
int  n,
int  k,
int *  indices,
float *  weights 
)

Find top-K indices with softmax-normalized weights.

Parameters
scoresInput scores [n] (router logits)
nNumber of scores
kNumber of top scores to select
indicesOutput: indices of top-K scores [k]
weightsOutput: softmax-normalized weights for selected [k], sum to 1.0

Definition at line 136 of file topk_kernels.c.

141{
142 if (!scores || !indices || !weights || n <= 0 || k <= 0) {
143 return;
144 }
145
146 if (k > n) {
147 k = n;
148 }
149
150 /* First get top-K indices and values */
151 float values[k];
152 topk_f32(scores, n, k, indices, values);
153
154 /* Compute softmax over the selected values */
155 /* Find max for numerical stability */
156 float max_val = values[0];
157 for (int i = 1; i < k; i++) {
158 if (values[i] > max_val) {
159 max_val = values[i];
160 }
161 }
162
163 /* Compute exp and sum */
164 float sum = 0.0f;
165 for (int i = 0; i < k; i++) {
166 weights[i] = expf(values[i] - max_val);
167 sum += weights[i];
168 }
169
170 /* Normalize */
171 float inv_sum = 1.0f / sum;
172 for (int i = 0; i < k; i++) {
173 weights[i] *= inv_sum;
174 }
175}

References topk_f32().

Referenced by topk_batched_f32().

◆ unfused_rmsnorm_qkv_prefill()

void unfused_rmsnorm_qkv_prefill ( const float *  x,
const float *  gamma,
const float *  Wq,
const float *  Wk,
const float *  Wv,
float *  x_norm,
float *  Q,
float *  K,
float *  V,
int  seq_len,
int  hidden,
int  q_dim,
int  kv_dim,
float  eps 
)

Unfused version for benchmarking comparison.

Unfused version for benchmarking comparison.

Definition at line 667 of file prefill_fused_gemm.c.

682{
683 /* Step 1: Full RMSNorm → writes x_norm to memory */
684 rmsnorm_tile(x, gamma, x_norm, seq_len, hidden, hidden, eps);
685
686 /* Step 2: Separate GEMMs with N-outer tiling for weight reuse */
687 /* Q projection */
688 for (int n_start = 0; n_start < q_dim; n_start += PREFILL_TILE_N) {
689 int tile_n = (n_start + PREFILL_TILE_N <= q_dim)
690 ? PREFILL_TILE_N : (q_dim - n_start);
691 const float *W_tile = Wq + (size_t)n_start * hidden;
692
693 for (int m_start = 0; m_start < seq_len; m_start += PREFILL_TILE_M) {
694 int tile_m = (m_start + PREFILL_TILE_M <= seq_len)
695 ? PREFILL_TILE_M : (seq_len - m_start);
696 const float *x_tile = x_norm + (size_t)m_start * hidden;
697 float *out_tile = Q + (size_t)m_start * q_dim + n_start;
698 gemm_tile_nt_strided(x_tile, W_tile, out_tile,
699 tile_m, tile_n, hidden, q_dim);
700 }
701 }
702
703 /* K projection */
704 for (int n_start = 0; n_start < kv_dim; n_start += PREFILL_TILE_N) {
705 int tile_n = (n_start + PREFILL_TILE_N <= kv_dim)
706 ? PREFILL_TILE_N : (kv_dim - n_start);
707 const float *W_tile = Wk + (size_t)n_start * hidden;
708
709 for (int m_start = 0; m_start < seq_len; m_start += PREFILL_TILE_M) {
710 int tile_m = (m_start + PREFILL_TILE_M <= seq_len)
711 ? PREFILL_TILE_M : (seq_len - m_start);
712 const float *x_tile = x_norm + (size_t)m_start * hidden;
713 float *out_tile = K + (size_t)m_start * kv_dim + n_start;
714 gemm_tile_nt_strided(x_tile, W_tile, out_tile,
715 tile_m, tile_n, hidden, kv_dim);
716 }
717 }
718
719 /* V projection */
720 for (int n_start = 0; n_start < kv_dim; n_start += PREFILL_TILE_N) {
721 int tile_n = (n_start + PREFILL_TILE_N <= kv_dim)
722 ? PREFILL_TILE_N : (kv_dim - n_start);
723 const float *W_tile = Wv + (size_t)n_start * hidden;
724
725 for (int m_start = 0; m_start < seq_len; m_start += PREFILL_TILE_M) {
726 int tile_m = (m_start + PREFILL_TILE_M <= seq_len)
727 ? PREFILL_TILE_M : (seq_len - m_start);
728 const float *x_tile = x_norm + (size_t)m_start * hidden;
729 float *out_tile = V + (size_t)m_start * kv_dim + n_start;
730 gemm_tile_nt_strided(x_tile, W_tile, out_tile,
731 tile_m, tile_n, hidden, kv_dim);
732 }
733 }
734}
#define PREFILL_TILE_N

References gemm_tile_nt_strided(), PREFILL_TILE_M, PREFILL_TILE_N, and rmsnorm_tile().

◆ vec_dot_q6_k_q8_k()

void vec_dot_q6_k_q8_k ( int  n,
float *  s,
const void *  vx,
const void *  vy 
)

Q6_K x Q8_K dot product (single row)

Definition at line 1324 of file gemm_kernels_q6k_q8k.c.

1325{
1326 if (!s || !vx || !vy || n <= 0) {
1327 return;
1328 }
1329
1330 const block_q6_K *x = (const block_q6_K *)vx;
1331 const block_q8_K *y = (const block_q8_K *)vy;
1332
1333 /* This is the architecture-neutral scalar oracle. Production x86 dispatch
1334 * uses the separately parity-tested SIMD reduction tree. */
1335 *s = dot_q6_k_q8_k_ref(x, y, n);
1336}

References dot_q6_k_q8_k_ref().

◆ vision_position_ids_2d_merge()

void vision_position_ids_2d_merge ( int32_t *  positions,
int  grid_h,
int  grid_w,
int  merge_size 
)

Build merged 2D vision position IDs in the layout expected by vision M-RoPE.

Output layout: [4, grid_h * grid_w] flattened as [y_stream | x_stream | y_stream_dup | x_stream_dup]

Tokens are emitted in merged-tile traversal order so the position buffer matches the same 2x2 grouping used by Qwen-style vision encoders.

Definition at line 529 of file vision_kernels.c.

533{
534 if (!positions || grid_h <= 0 || grid_w <= 0 || merge_size <= 0) {
535 return;
536 }
537
538 const int num_tokens = grid_h * grid_w;
539 int ptr = 0;
540
541 for (int y = 0; y < grid_h; y += merge_size) {
542 for (int x = 0; x < grid_w; x += merge_size) {
543 for (int dy = 0; dy < merge_size; ++dy) {
544 for (int dx = 0; dx < merge_size; ++dx) {
545 const int yy = y + dy;
546 const int xx = x + dx;
547 if (yy >= grid_h || xx >= grid_w || ptr >= num_tokens) {
548 continue;
549 }
550 positions[ptr] = yy;
551 positions[num_tokens + ptr] = xx;
552 positions[2 * num_tokens + ptr] = yy;
553 positions[3 * num_tokens + ptr] = xx;
554 ++ptr;
555 }
556 }
557 }
558 }
559
560 for (; ptr < num_tokens; ++ptr) {
561 positions[ptr] = 0;
562 positions[num_tokens + ptr] = 0;
563 positions[2 * num_tokens + ptr] = 0;
564 positions[3 * num_tokens + ptr] = 0;
565 }
566}

◆ weighted_sum_f32()

void weighted_sum_f32 ( float *  y,
const float **  vectors,
const float *  weights,
int  k,
int  n 
)

Weighted sum of k vectors: y = sum_i(weights[i] * vectors[i])

Parameters
yOutput vector [n]
vectorsArray of k input vector pointers, each [n]
weightsArray of k scalar weights
kNumber of vectors to combine
nVector length

Definition at line 206 of file axpy_kernels.c.

211{
212 if (!y || !vectors || !weights || k <= 0 || n <= 0) {
213 return;
214 }
215
216 /* Initialize with first vector */
217 scal_copy_f32(y, vectors[0], weights[0], n);
218
219 /* Accumulate rest */
220 for (int i = 1; i < k; i++) {
221 axpy_f32(y, vectors[i], weights[i], n);
222 }
223}
void scal_copy_f32(float *y, const float *x, float alpha, int n)
Scaled copy: y = alpha * x.

References axpy_f32(), and scal_copy_f32().

◆ yarn_rope_cache_contiguous_positions_f32()

void yarn_rope_cache_contiguous_positions_f32 ( float *  cos_cache,
float *  sin_cache,
int  num_tokens,
int  rotary_dim,
float  freq_base,
float  factor,
int  original_context,
float  beta_fast,
float  beta_slow,
float  mscale,
float  mscale_all_dim 
)

Definition at line 517 of file rope_kernels.c.

528{
530 cos_cache, sin_cache, NULL, NULL, NULL, num_tokens, rotary_dim,
531 freq_base, factor, original_context, beta_fast, beta_slow, mscale,
532 mscale_all_dim);
533}
static void yarn_rope_cache_explicit_positions_impl(float *cos_f32, float *sin_f32, uint16_t *cos_bf16, uint16_t *sin_bf16, const int32_t *positions, int num_tokens, int rotary_dim, float freq_base, float factor, int original_context, float beta_fast, float beta_slow, float mscale, float mscale_all_dim)

References yarn_rope_cache_explicit_positions_impl().

◆ yarn_rope_cache_explicit_positions_bf16()

void yarn_rope_cache_explicit_positions_bf16 ( uint16_t *  cos_cache,
uint16_t *  sin_cache,
const int32_t *  positions,
int  num_tokens,
int  rotary_dim,
float  freq_base,
float  factor,
int  original_context,
float  beta_fast,
float  beta_slow,
float  mscale,
float  mscale_all_dim 
)

Definition at line 535 of file rope_kernels.c.

547{
549 NULL, NULL, cos_cache, sin_cache, positions, num_tokens, rotary_dim,
550 freq_base, factor, original_context, beta_fast, beta_slow, mscale,
551 mscale_all_dim);
552}

References yarn_rope_cache_explicit_positions_impl().

◆ yarn_rope_cache_explicit_positions_f32()

void yarn_rope_cache_explicit_positions_f32 ( float *  cos_cache,
float *  sin_cache,
const int32_t *  positions,
int  num_tokens,
int  rotary_dim,
float  freq_base,
float  factor,
int  original_context,
float  beta_fast,
float  beta_slow,
float  mscale,
float  mscale_all_dim 
)

Definition at line 498 of file rope_kernels.c.

510{
512 cos_cache, sin_cache, NULL, NULL, positions, num_tokens, rotary_dim,
513 freq_base, factor, original_context, beta_fast, beta_slow, mscale,
514 mscale_all_dim);
515}

References yarn_rope_cache_explicit_positions_impl().