← Back to C-Kernel-Engine Docs Doxygen Source Documentation
 
Loading...
Searching...
No Matches
rmsnorm_kernels.c File Reference

RMSNorm forward/backward kernels with SIMD (SSE/AVX/AVX512) More...

#include "bf16_utils.h"
#include "ckernel_engine.h"
#include <math.h>
#include <stddef.h>
#include <stdlib.h>

Go to the source code of this file.

Functions

const char * ck_rmsnorm_provider_name (void)
 
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 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 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)
 
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_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_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_muse_centered_pytorch_bf16_storage (const float *input, const float *zero_centered_weight, float *output, float *rstd_cache, int tokens, int d_model, int aligned_embed_dim, float eps)
 
void rmsnorm_forward_muse_unweighted_pytorch_bf16_storage (const float *input, float *output, float *rstd_cache, int tokens, int d_model, int aligned_embed_dim, float eps)
 
void rmsnorm_forward_muse_weighted_pytorch_bf16_storage (const float *input, const float *weight, 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_no_weight_llama_production (const float *input, 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)
 
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 weight_mode, int use_pow_inverse)
 
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 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)
 
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)
 
static float rmsnorm_llama_production_rstd (float mean_eps)
 

Detailed Description

RMSNorm forward/backward kernels with SIMD (SSE/AVX/AVX512)

CK-ENGINE KERNEL RULES:

  1. NO malloc/free - memory via bump allocator, pointers passed in
  2. NO OpenMP - parallelization at orchestrator/codegen layer
  3. API must define: inputs, outputs, workspace, and memory layouts
  4. Pure computation - deterministic, no side effects

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

RMSNorm: y[i] = gamma[i] * x[i] / sqrt(mean(x^2) + eps)

Definition in file rmsnorm_kernels.c.

Function Documentation

◆ ck_rmsnorm_provider_name()

const char * ck_rmsnorm_provider_name ( void  )

Definition at line 859 of file rmsnorm_kernels.c.

860{
861 const char *exact_env = getenv("CK_RMSNORM_EXACT");
862 if (ck_strict_parity_enabled() || (exact_env && atoi(exact_env) != 0)) {
863 return "rmsnorm_strict_scalar";
864 }
865#if defined(__AVX512F__)
866 return "rmsnorm_avx512";
867#elif defined(__AVX__)
868 return "rmsnorm_avx";
869#elif defined(__ARM_NEON) || defined(__aarch64__)
870 return "rmsnorm_neon";
871#else
872 return "rmsnorm_scalar";
873#endif
874}
int ck_strict_parity_enabled(void)

References ck_strict_parity_enabled().

◆ 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 839 of file rmsnorm_kernels.c.

846{
847 if (!input || !output || tokens <= 0 || num_kv_heads <= 0 || head_dim <= 0) {
848 return;
849 }
851 input, output, rstd_cache,
852 tokens * num_kv_heads, head_dim, head_dim, eps);
853}
void rmsnorm_forward_no_weight_llama_production(const float *input, float *output, float *rstd_cache, int tokens, int d_model, int aligned_embed_dim, float eps)

References rmsnorm_forward_no_weight_llama_production().

◆ 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 888 of file rmsnorm_kernels.c.

897{
898 int T = tokens;
899 int D = d_model;
900 int aligned = aligned_embed_dim;
901
903 rmsnorm_backward_strict_scalar(d_output, input, gamma, rstd_cache, d_input, d_gamma, T, D, aligned);
904 return;
905 }
906
907 // Zero parameter gradients
908#if defined(__AVX512F__)
909 {
910 int d = 0;
911 for (; d + 16 <= D; d += 16) {
912 _mm512_storeu_ps(&d_gamma[d], _mm512_setzero_ps());
913 }
914 for (; d < D; ++d) {
915 d_gamma[d] = 0.0f;
916 }
917 }
918#elif defined(__AVX__)
919 {
920 int d = 0;
921 for (; d + 8 <= D; d += 8) {
922 _mm256_storeu_ps(&d_gamma[d], _mm256_setzero_ps());
923 }
924 for (; d < D; ++d) {
925 d_gamma[d] = 0.0f;
926 }
927 }
928#else
929 for (int d = 0; d < D; ++d) {
930 d_gamma[d] = 0.0f;
931 }
932#endif
933
934 for (int t = 0; t < T; ++t) {
935 const float *x = input + (size_t)t * aligned;
936 const float *dY = d_output + (size_t)t * aligned;
937 float *dX = d_input + (size_t)t * aligned;
938
939 float rstd = rstd_cache[t];
940
941#if defined(__AVX512F__)
942 // Compute m = (1/D) * sum_j (dY_j * gamma_j * x_hat_j)
943 __m512 rstd_vec = _mm512_set1_ps(rstd);
944 __m512 sum_vec = _mm512_setzero_ps();
945 int d = 0;
946
947 for (; d + 16 <= D; d += 16) {
948 __m512 xv = _mm512_loadu_ps(&x[d]);
949 __m512 dyv = _mm512_loadu_ps(&dY[d]);
950 __m512 gv = _mm512_loadu_ps(&gamma[d]);
951 __m512 x_hat = _mm512_mul_ps(xv, rstd_vec);
952 // sum += dY * gamma * x_hat
953 __m512 prod = _mm512_mul_ps(dyv, gv);
954 sum_vec = _mm512_fmadd_ps(prod, x_hat, sum_vec);
955 }
956 float sum_dY_g_xhat = _mm512_reduce_add_ps(sum_vec);
957
958 // Handle remaining elements
959 for (; d < D; ++d) {
960 float x_hat = x[d] * rstd;
961 sum_dY_g_xhat += dY[d] * gamma[d] * x_hat;
962 }
963 float m = sum_dY_g_xhat / (float)D;
964
965 // Compute dX and accumulate dGamma (vectorized)
966 __m512 m_vec = _mm512_set1_ps(m);
967 d = 0;
968 for (; d + 16 <= D; d += 16) {
969 __m512 xv = _mm512_loadu_ps(&x[d]);
970 __m512 dyv = _mm512_loadu_ps(&dY[d]);
971 __m512 gv = _mm512_loadu_ps(&gamma[d]);
972 __m512 dgv = _mm512_loadu_ps(&d_gamma[d]);
973
974 __m512 x_hat = _mm512_mul_ps(xv, rstd_vec);
975
976 // dX = rstd * (dY * gamma - x_hat * m)
977 __m512 dy_g = _mm512_mul_ps(dyv, gv);
978 __m512 xhat_m = _mm512_mul_ps(x_hat, m_vec);
979 __m512 diff = _mm512_sub_ps(dy_g, xhat_m);
980 __m512 dxv = _mm512_mul_ps(rstd_vec, diff);
981 _mm512_storeu_ps(&dX[d], dxv);
982
983 // d_gamma += dY * x_hat
984 dgv = _mm512_fmadd_ps(dyv, x_hat, dgv);
985 _mm512_storeu_ps(&d_gamma[d], dgv);
986 }
987 // Handle remaining elements
988 for (; d < D; ++d) {
989 float x_hat = x[d] * rstd;
990 float dy = dY[d];
991 dX[d] = rstd * (dy * gamma[d] - x_hat * m);
992 d_gamma[d] += dy * x_hat;
993 }
994
995#elif defined(__AVX__)
996 // Compute m = (1/D) * sum_j (dY_j * gamma_j * x_hat_j)
997 __m256 rstd_vec = _mm256_set1_ps(rstd);
998 __m256 sum_vec = _mm256_setzero_ps();
999 int d = 0;
1000
1001 for (; d + 8 <= D; d += 8) {
1002 __m256 xv = _mm256_loadu_ps(&x[d]);
1003 __m256 dyv = _mm256_loadu_ps(&dY[d]);
1004 __m256 gv = _mm256_loadu_ps(&gamma[d]);
1005 __m256 x_hat = _mm256_mul_ps(xv, rstd_vec);
1006 // sum += dY * gamma * x_hat (no FMA, use mul + mul + add)
1007 __m256 prod = _mm256_mul_ps(dyv, gv);
1008 __m256 prod2 = _mm256_mul_ps(prod, x_hat);
1009 sum_vec = _mm256_add_ps(sum_vec, prod2);
1010 }
1011 float sum_dY_g_xhat = hsum256_ps_rmsnorm(sum_vec);
1012
1013 // Handle remaining elements
1014 for (; d < D; ++d) {
1015 float x_hat = x[d] * rstd;
1016 sum_dY_g_xhat += dY[d] * gamma[d] * x_hat;
1017 }
1018 float m = sum_dY_g_xhat / (float)D;
1019
1020 // Compute dX and accumulate dGamma (vectorized)
1021 __m256 m_vec = _mm256_set1_ps(m);
1022 d = 0;
1023 for (; d + 8 <= D; d += 8) {
1024 __m256 xv = _mm256_loadu_ps(&x[d]);
1025 __m256 dyv = _mm256_loadu_ps(&dY[d]);
1026 __m256 gv = _mm256_loadu_ps(&gamma[d]);
1027 __m256 dgv = _mm256_loadu_ps(&d_gamma[d]);
1028
1029 __m256 x_hat = _mm256_mul_ps(xv, rstd_vec);
1030
1031 // dX = rstd * (dY * gamma - x_hat * m)
1032 __m256 dy_g = _mm256_mul_ps(dyv, gv);
1033 __m256 xhat_m = _mm256_mul_ps(x_hat, m_vec);
1034 __m256 diff = _mm256_sub_ps(dy_g, xhat_m);
1035 __m256 dxv = _mm256_mul_ps(rstd_vec, diff);
1036 _mm256_storeu_ps(&dX[d], dxv);
1037
1038 // d_gamma += dY * x_hat
1039 __m256 dy_xhat = _mm256_mul_ps(dyv, x_hat);
1040 dgv = _mm256_add_ps(dgv, dy_xhat);
1041 _mm256_storeu_ps(&d_gamma[d], dgv);
1042 }
1043 // Handle remaining elements
1044 for (; d < D; ++d) {
1045 float x_hat = x[d] * rstd;
1046 float dy = dY[d];
1047 dX[d] = rstd * (dy * gamma[d] - x_hat * m);
1048 d_gamma[d] += dy * x_hat;
1049 }
1050
1051#else
1052 // Scalar fallback
1053 // Compute m = (1/D) * sum_j (dY_j * gamma_j * x_hat_j)
1054 float sum_dY_g_xhat = 0.0f;
1055 for (int d = 0; d < D; ++d) {
1056 float x_hat = x[d] * rstd;
1057 sum_dY_g_xhat += dY[d] * gamma[d] * x_hat;
1058 }
1059 float m = sum_dY_g_xhat / (float)D;
1060
1061 // Compute dX and accumulate dGamma
1062 for (int d = 0; d < D; ++d) {
1063 float x_hat = x[d] * rstd;
1064 float dy = dY[d];
1065 dX[d] = rstd * (dy * gamma[d] - x_hat * m);
1066 d_gamma[d] += dy * x_hat;
1067 }
1068#endif
1069
1070 // Zero padding gradients (if any)
1071 for (int d = D; d < aligned; ++d) {
1072 dX[d] = 0.0f;
1073 }
1074 }
1075}
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(), qk_norm_backward(), rmsnorm_backward_int4(), and rmsnorm_backward_int8().

◆ rmsnorm_backward_strict_scalar()

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 
)
static

Definition at line 514 of file rmsnorm_kernels.c.

523{
524 const float inv_d = 1.0f / (float)d_model;
525 for (int d = 0; d < d_model; ++d) {
526 d_gamma[d] = 0.0f;
527 }
528
529 for (int t = 0; t < tokens; ++t) {
530 const float *x = input + (size_t)t * (size_t)aligned_embed_dim;
531 const float *dY = d_output + (size_t)t * (size_t)aligned_embed_dim;
532 float *dX = d_input + (size_t)t * (size_t)aligned_embed_dim;
533 const float rstd = rstd_cache[t];
534
535 float sum_dY_g_xhat = 0.0f;
536 for (int d = 0; d < d_model; ++d) {
537 const float x_hat = x[d] * rstd;
538 const float grad_x_hat = dY[d] * gamma[d];
539 sum_dY_g_xhat += x_hat * grad_x_hat;
540 }
541
542 for (int d = 0; d < d_model; ++d) {
543 const float x_hat = x[d] * rstd;
544 const float grad_x_hat = dY[d] * gamma[d];
545 dX[d] = (grad_x_hat - (x_hat * inv_d) * sum_dY_g_xhat) * rstd;
546 d_gamma[d] += dY[d] * x_hat;
547 }
548 for (int d = d_model; d < aligned_embed_dim; ++d) {
549 dX[d] = 0.0f;
550 }
551 }
552}

Referenced by 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 735 of file rmsnorm_kernels.c.

743{
745 input,
746 gamma,
747 output,
748 rstd_cache,
749 tokens,
750 d_model,
751 aligned_embed_dim,
752 aligned_embed_dim,
753 eps
754 );
755}
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(), ck_test_rmsnorm(), mega_fused_attention_decode_q5_0(), mega_fused_attention_decode_q5_0_parallel_simd(), 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(), q_norm_forward(), qk_norm_forward(), 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(), rmsnorm_forward_int8(), rmsnorm_forward_kv_lora(), and rmsnorm_qkv_q4k_fused().

◆ 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 154 of file rmsnorm_kernels.c.

162{
163 for (int t = 0; t < tokens; ++t) {
164 const float *x = input + (size_t)t * (size_t)aligned_embed_dim;
165 float *y = output + (size_t)t * (size_t)aligned_embed_dim;
166 /* This provider's contract requires an ascending scalar reduction.
167 * Keep the accumulator volatile so whole-program optimization cannot
168 * reassociate the sum or replace it with SIMD partial reductions. */
169 volatile double sum_sq = 0.0;
170 for (int d = 0; d < d_model; ++d) {
171 const float square = x[d] * x[d];
172 sum_sq = sum_sq + (double)square;
173 }
174 const float mean_sq = (float)(sum_sq / (double)d_model);
175 const float rstd = 1.0f / sqrtf(mean_sq + eps);
176 if (rstd_cache) {
177 rstd_cache[t] = rstd;
178 }
179 for (int d = 0; d < d_model; ++d) {
180 const float normalized = x[d] * rstd;
181 y[d] = normalized * gamma[d];
182 }
183 for (int d = d_model; d < aligned_embed_dim; ++d) {
184 y[d] = 0.0f;
185 }
186 }
187}

Referenced by qk_norm_forward_fp64_sum().

◆ 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 757 of file rmsnorm_kernels.c.

765{
766 rmsnorm_forward(input, gamma, output, rstd_cache, tokens, d_model, aligned_embed_dim, eps);
767}
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 213 of file rmsnorm_kernels.c.

221{
222 for (int t = 0; t < tokens; ++t) {
223 const float *x = input + (size_t)t * (size_t)aligned_embed_dim;
224 float *y = output + (size_t)t * (size_t)aligned_embed_dim;
225 volatile double sum_sq = 0.0;
226 for (int d = 0; d < d_model; ++d) {
227 const float square = x[d] * x[d];
228 sum_sq = sum_sq + (double)square;
229 }
230 const float mean_sq = (float)(sum_sq / (double)d_model);
231 const float rstd = rmsnorm_llama_production_rstd(mean_sq + eps);
232 if (rstd_cache) {
233 rstd_cache[t] = rstd;
234 }
235 for (int d = 0; d < d_model; ++d) {
236 /*
237 * Keep the RMSNorm + scale expression fused at the source level.
238 * llama.cpp's CPU graph fuses GGML_OP_RMS_NORM followed by
239 * GGML_OP_MUL and evaluates this left-associative expression in
240 * one kernel. Materializing the normalized value as a named
241 * float introduces a store/load rounding boundary under ICX and
242 * differs by one ULP for otherwise identical inputs.
243 */
244 y[d] = x[d] * rstd * gamma[d];
245 }
246 for (int d = d_model; d < aligned_embed_dim; ++d) {
247 y[d] = 0.0f;
248 }
249 }
250}
static float rmsnorm_llama_production_rstd(float mean_eps)

References rmsnorm_llama_production_rstd().

Referenced by ck_gemma4_embed_range(), qk_norm_forward_llama_production(), qwen4_group_rmsnorm_llama(), recurrent_norm_gate_llama_avx2_forward(), and recurrent_norm_sigmoid_gate_llama_avx2_forward().

◆ rmsnorm_forward_muse_centered_pytorch_bf16_storage()

void rmsnorm_forward_muse_centered_pytorch_bf16_storage ( const float *  input,
const float *  zero_centered_weight,
float *  output,
float *  rstd_cache,
int  tokens,
int  d_model,
int  aligned_embed_dim,
float  eps 
)

Definition at line 470 of file rmsnorm_kernels.c.

479{
481 input, zero_centered_weight, output, rstd_cache, tokens, d_model,
482 aligned_embed_dim, aligned_embed_dim, eps, 2, 0);
483}
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 weight_mode, int use_pow_inverse)

References rmsnorm_forward_pytorch_bf16_storage_impl().

◆ rmsnorm_forward_muse_unweighted_pytorch_bf16_storage()

void rmsnorm_forward_muse_unweighted_pytorch_bf16_storage ( const float *  input,
float *  output,
float *  rstd_cache,
int  tokens,
int  d_model,
int  aligned_embed_dim,
float  eps 
)

Definition at line 500 of file rmsnorm_kernels.c.

508{
510 input, NULL, output, rstd_cache, tokens, d_model,
511 aligned_embed_dim, aligned_embed_dim, eps, 3, 0);
512}

References rmsnorm_forward_pytorch_bf16_storage_impl().

Referenced by qk_norm_forward_muse_unweighted_scaled_pytorch_bf16_storage().

◆ rmsnorm_forward_muse_weighted_pytorch_bf16_storage()

void rmsnorm_forward_muse_weighted_pytorch_bf16_storage ( const float *  input,
const float *  weight,
float *  output,
float *  rstd_cache,
int  tokens,
int  d_model,
int  aligned_embed_dim,
float  eps 
)

Definition at line 485 of file rmsnorm_kernels.c.

494{
496 input, weight, output, rstd_cache, tokens, d_model,
497 aligned_embed_dim, aligned_embed_dim, eps, 1, 0);
498}

References rmsnorm_forward_pytorch_bf16_storage_impl().

◆ 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 769 of file rmsnorm_kernels.c.

776{
777 if (!input || !output || tokens <= 0 || d_model <= 0 || aligned_embed_dim <= 0) {
778 return;
779 }
780 const float inv_d = 1.0f / (float)d_model;
781 for (int t = 0; t < tokens; ++t) {
782 const float *x = input + (size_t)t * (size_t)aligned_embed_dim;
783 float *y = output + (size_t)t * (size_t)aligned_embed_dim;
784 double sum_sq = 0.0;
785 for (int d = 0; d < d_model; ++d) {
786 sum_sq += (double)x[d] * (double)x[d];
787 }
788 const float rstd = 1.0f / sqrtf((float)(sum_sq * (double)inv_d) + eps);
789 if (rstd_cache) {
790 rstd_cache[t] = rstd;
791 }
792 for (int d = 0; d < d_model; ++d) {
793 y[d] = x[d] * rstd;
794 }
795 for (int d = d_model; d < aligned_embed_dim; ++d) {
796 y[d] = 0.0f;
797 }
798 }
799}

◆ rmsnorm_forward_no_weight_llama_production()

void rmsnorm_forward_no_weight_llama_production ( const float *  input,
float *  output,
float *  rstd_cache,
int  tokens,
int  d_model,
int  aligned_embed_dim,
float  eps 
)

Definition at line 806 of file rmsnorm_kernels.c.

813{
814 if (!input || !output || tokens <= 0 || d_model <= 0 || aligned_embed_dim < d_model) {
815 return;
816 }
817 for (int t = 0; t < tokens; ++t) {
818 const float *x = input + (size_t)t * (size_t)aligned_embed_dim;
819 float *y = output + (size_t)t * (size_t)aligned_embed_dim;
820 volatile double sum_sq = 0.0;
821 for (int d = 0; d < d_model; ++d) {
822 const float square = x[d] * x[d];
823 sum_sq = sum_sq + (double)square;
824 }
825 const float mean_sq = (float)(sum_sq / (double)d_model);
826 const float rstd = rmsnorm_llama_production_rstd(mean_sq + eps);
827 if (rstd_cache) {
828 rstd_cache[t] = rstd;
829 }
830 for (int d = 0; d < d_model; ++d) {
831 y[d] = x[d] * rstd;
832 }
833 for (int d = d_model; d < aligned_embed_dim; ++d) {
834 y[d] = 0.0f;
835 }
836 }
837}

References rmsnorm_llama_production_rstd().

Referenced by gemma4_v_norm_forward().

◆ 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 426 of file rmsnorm_kernels.c.

434{
436 input, gamma, output, rstd_cache, tokens, d_model,
437 aligned_embed_dim, aligned_embed_dim, eps, 0, 0);
438}

References rmsnorm_forward_pytorch_bf16_storage_impl().

Referenced by qk_norm_forward_pytorch_bf16_storage(), recurrent_norm_gate_pytorch_bf16_storage(), and recurrent_norm_sigmoid_gate_pytorch_bf16_storage().

◆ rmsnorm_forward_pytorch_bf16_storage_impl()

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  weight_mode,
int  use_pow_inverse 
)
static

Definition at line 271 of file rmsnorm_kernels.c.

282{
283 for (int t = 0; t < tokens; ++t) {
284 const float *x = input + (size_t)t * (size_t)input_stride;
285 float *y = output + (size_t)t * (size_t)output_stride;
286 float sum_sq = 0.0f;
287
288#if defined(__AVX2__)
289 /* Match the installed ATen build's AVX2 floating-point cascade_sum
290 * contract. It treats the
291 * contiguous row as four interleaved vector streams, accumulates
292 * 16-item blocks through four hierarchy levels, then folds the four
293 * streams and vector lanes left-to-right. PyTorch materializes pow(2)
294 * before mean(), so keep the multiply separate from accumulation.
295 * The host supports AVX-512, but this PyTorch build has AVX2 reduction
296 * providers only; provider ISA is part of the numerical contract. */
297 __m256 level[4][4];
298 for (int hierarchy = 0; hierarchy < 4; ++hierarchy) {
299 for (int stream = 0; stream < 4; ++stream) {
300 level[hierarchy][stream] = _mm256_setzero_ps();
301 }
302 }
303 int d = 0;
304 const int vector_count = d_model / 8;
305 const int cascade_items = vector_count / 4;
306 int level_power = 4;
307 if (cascade_items > 1) {
308 int ceil_log2 = 0;
309 unsigned int value = (unsigned int)(cascade_items - 1);
310 while (value != 0) {
311 value >>= 1;
312 ++ceil_log2;
313 }
314 const int candidate = ceil_log2 / 4;
315 if (candidate > level_power) level_power = candidate;
316 }
317 const int level_step = 1 << level_power;
318 const int level_mask = level_step - 1;
319 int item = 0;
320 for (; item + level_step <= cascade_items;) {
321 for (int block = 0; block < level_step; ++block, ++item) {
322 for (int stream = 0; stream < 4; ++stream) {
323 const int offset = (item * 4 + stream) * 8;
324 const __m256 values = rmsnorm_load_bf16_values_avx2(x + offset);
325 const __m256 squared = rmsnorm_square_avx2_no_contract(values);
326 level[0][stream] = rmsnorm_add_avx2_ordered(
327 level[0][stream], squared
328 );
329 }
330 }
331 for (int hierarchy = 1; hierarchy < 4; ++hierarchy) {
332 for (int stream = 0; stream < 4; ++stream) {
333 level[hierarchy][stream] = rmsnorm_add_avx2_ordered(
334 level[hierarchy][stream], level[hierarchy - 1][stream]
335 );
336 level[hierarchy - 1][stream] = _mm256_setzero_ps();
337 }
338 const int mask = level_mask << (hierarchy * level_power);
339 if ((item & mask) != 0) break;
340 }
341 }
342 for (; item < cascade_items; ++item) {
343 for (int stream = 0; stream < 4; ++stream) {
344 const int offset = (item * 4 + stream) * 8;
345 const __m256 values = rmsnorm_load_bf16_values_avx2(x + offset);
346 const __m256 squared = rmsnorm_square_avx2_no_contract(values);
347 level[0][stream] = rmsnorm_add_avx2_ordered(
348 level[0][stream], squared
349 );
350 }
351 }
352 for (int hierarchy = 1; hierarchy < 4; ++hierarchy) {
353 for (int stream = 0; stream < 4; ++stream) {
354 level[0][stream] = rmsnorm_add_avx2_ordered(
355 level[0][stream], level[hierarchy][stream]
356 );
357 }
358 }
359 __m256 reduced = level[0][0];
360 for (int stream = 1; stream < 4; ++stream) {
361 reduced = rmsnorm_add_avx2_ordered(reduced, level[0][stream]);
362 }
363 d = cascade_items * 4 * 8;
364 for (; d + 8 <= d_model; d += 8) {
365 const __m256 values = rmsnorm_load_bf16_values_avx2(x + d);
366 const __m256 squared = rmsnorm_square_avx2_no_contract(values);
367 reduced = rmsnorm_add_avx2_ordered(reduced, squared);
368 }
369 _Alignas(32) float lanes[8];
370 _mm256_store_ps(lanes, reduced);
371 volatile float ordered_sum = 0.0f;
372 for (int lane = 0; lane < 8; ++lane) {
373 ordered_sum = ordered_sum + lanes[lane];
374 }
375 sum_sq = ordered_sum;
376 for (; d < d_model; ++d) {
377 const float value = bf16_to_float(float_to_bf16(x[d]));
378 sum_sq += value * value;
379 }
380#else
381 for (int d = 0; d < d_model; ++d) {
382 const float value = bf16_to_float(float_to_bf16(x[d]));
383 sum_sq += value * value;
384 }
385#endif
386
387#if defined(__i386__) || defined(__x86_64__)
388 const float variance = rmsnorm_div_f32_ordered(sum_sq, (float)d_model);
389 const float rstd = use_pow_inverse
390 ? powf(variance + eps, -0.5f)
391 : rmsnorm_div_f32_ordered(1.0f, sqrtf(variance + eps));
392#else
393 const float variance = sum_sq / (float)d_model;
394 const float rstd = use_pow_inverse
395 ? powf(variance + eps, -0.5f)
396 : 1.0f / sqrtf(variance + eps);
397#endif
398 if (rstd_cache) rstd_cache[t] = rstd;
399 for (int d = 0; d < d_model; ++d) {
400 const float value = bf16_to_float(float_to_bf16(x[d]));
401 if (weight_mode == 3) {
402 /* Muse unweighted normalization rounds only when the FP32
403 * normalized value returns to the BF16 hidden-state dtype. */
404 y[d] = bf16_to_float(float_to_bf16(value * rstd));
405 } else if (weight_mode == 2) {
406 /* Keep the checkpoint weight zero-centered. Form 1 + weight
407 * in FP32 at execution instead of pre-folding into BF16. */
409 (value * rstd) * (1.0f + gamma[d])));
410 } else if (weight_mode == 1) {
411 /* Qwen3Next: (FP32 normalized * FP32 weight).to(BF16). */
413 (value * rstd) * gamma[d]));
414 } else {
415 const float weight =
416 bf16_to_float(float_to_bf16(gamma[d]));
417 const float normalized =
418 bf16_to_float(float_to_bf16(value * rstd));
419 y[d] = bf16_to_float(float_to_bf16(normalized * weight));
420 }
421 }
422 for (int d = d_model; d < output_stride; ++d) y[d] = 0.0f;
423 }
424}
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
int32_t int32_t int32_t int32_t int32_t mask
Definition tokenizer.h:234

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

Referenced by rmsnorm_forward_muse_centered_pytorch_bf16_storage(), rmsnorm_forward_muse_unweighted_pytorch_bf16_storage(), rmsnorm_forward_muse_weighted_pytorch_bf16_storage(), rmsnorm_forward_pytorch_bf16_storage(), rmsnorm_forward_qwen3next_pytorch_bf16_storage(), and rmsnorm_forward_strided_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 455 of file rmsnorm_kernels.c.

464{
466 input, gamma, output, rstd_cache, tokens, d_model,
467 aligned_embed_dim, aligned_embed_dim, eps, 1, 0);
468}

References rmsnorm_forward_pytorch_bf16_storage_impl().

Referenced by hyper_connection_mix_bf16(), qk_norm_forward_qwen4_pytorch_bf16_storage(), and qwen4_group_rmsnorm_pytorch_bf16().

◆ rmsnorm_forward_strict_scalar()

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 
)
static

Definition at line 113 of file rmsnorm_kernels.c.

122{
123 const float inv_d = 1.0f / (float)d_model;
124 for (int t = 0; t < tokens; ++t) {
125 const float *x = input + (size_t)t * (size_t)input_stride;
126 float *y = output + (size_t)t * (size_t)output_stride;
127
128 float sum_sq = 0.0f;
129 for (int d = 0; d < d_model; ++d) {
130 const float v = x[d];
131 sum_sq += v * v;
132 }
133 const float mean_sq = sum_sq * inv_d;
134 const float rstd = 1.0f / sqrtf(mean_sq + eps);
135 if (rstd_cache) {
136 rstd_cache[t] = rstd;
137 }
138
139 for (int d = 0; d < d_model; ++d) {
140 const float x_hat = x[d] * rstd;
141 y[d] = x_hat * gamma[d];
142 }
143 for (int d = d_model; d < output_stride; ++d) {
144 y[d] = 0.0f;
145 }
146 }
147}

Referenced by rmsnorm_forward_strided_f32().

◆ 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 567 of file rmsnorm_kernels.c.

576{
577 int T = tokens;
578 int D = d_model;
579
580 const char *exact_env = getenv("CK_RMSNORM_EXACT");
581 if (ck_strict_parity_enabled() || (exact_env && atoi(exact_env) != 0)) {
583 input, gamma, output, rstd_cache, T, D, input_stride, output_stride, eps
584 );
585 return;
586 }
587
588 for (int t = 0; t < T; ++t) {
589 const float *x = input + (size_t)t * (size_t)input_stride;
590 float *y = output + (size_t)t * (size_t)output_stride;
591
592#if defined(__AVX512F__)
593 // AVX-512: Process 16 floats at a time
594 __m512 sum_sq_vec = _mm512_setzero_ps();
595 int d = 0;
596
597 // Vectorized sum of squares
598 for (; d + 16 <= D; d += 16) {
599 __m512 xv = _mm512_loadu_ps(&x[d]);
600 sum_sq_vec = _mm512_fmadd_ps(xv, xv, sum_sq_vec);
601 }
602 float sum_sq = _mm512_reduce_add_ps(sum_sq_vec);
603
604 // Handle remaining elements
605 for (; d < D; ++d) {
606 sum_sq += x[d] * x[d];
607 }
608
609 float mean_sq = sum_sq / (float)D;
610 float rstd = 1.0f / sqrtf(mean_sq + eps);
611 if (rstd_cache) {
612 rstd_cache[t] = rstd;
613 }
614
615 // Apply normalization and scale (vectorized)
616 __m512 rstd_vec = _mm512_set1_ps(rstd);
617 d = 0;
618 for (; d + 16 <= D; d += 16) {
619 __m512 xv = _mm512_loadu_ps(&x[d]);
620 __m512 gv = _mm512_loadu_ps(&gamma[d]);
621 __m512 x_hat = _mm512_mul_ps(xv, rstd_vec);
622 __m512 yv = _mm512_mul_ps(x_hat, gv);
623 _mm512_storeu_ps(&y[d], yv);
624 }
625 // Handle remaining elements
626 for (; d < D; ++d) {
627 y[d] = x[d] * rstd * gamma[d];
628 }
629
630#elif defined(__AVX__)
631 // AVX: Process 8 floats at a time
632 __m256 sum_sq_vec = _mm256_setzero_ps();
633 int d = 0;
634
635 // Vectorized sum of squares (no FMA in AVX1, use mul + add)
636 for (; d + 8 <= D; d += 8) {
637 __m256 xv = _mm256_loadu_ps(&x[d]);
638 __m256 xv_sq = _mm256_mul_ps(xv, xv);
639 sum_sq_vec = _mm256_add_ps(sum_sq_vec, xv_sq);
640 }
641 float sum_sq = hsum256_ps_rmsnorm(sum_sq_vec);
642
643 // Handle remaining elements
644 for (; d < D; ++d) {
645 sum_sq += x[d] * x[d];
646 }
647
648 float mean_sq = sum_sq / (float)D;
649 float rstd = 1.0f / sqrtf(mean_sq + eps);
650 if (rstd_cache) {
651 rstd_cache[t] = rstd;
652 }
653
654 // Apply normalization and scale (vectorized)
655 __m256 rstd_vec = _mm256_set1_ps(rstd);
656 d = 0;
657 for (; d + 8 <= D; d += 8) {
658 __m256 xv = _mm256_loadu_ps(&x[d]);
659 __m256 gv = _mm256_loadu_ps(&gamma[d]);
660 __m256 x_hat = _mm256_mul_ps(xv, rstd_vec);
661 __m256 yv = _mm256_mul_ps(x_hat, gv);
662 _mm256_storeu_ps(&y[d], yv);
663 }
664 // Handle remaining elements
665 for (; d < D; ++d) {
666 y[d] = x[d] * rstd * gamma[d];
667 }
668
669#elif defined(__ARM_NEON) || defined(__aarch64__)
670 /* NEON: 4 floats at a time. The sum-of-squares is reassociated
671 * through four lanes (FMA accumulation, like the AVX-512 branch),
672 * so results differ from the ascending scalar order by FP32
673 * reassociation noise only; CK_RMSNORM_EXACT / strict parity mode
674 * above still selects the scalar reference. */
675 float32x4_t sum_sq_vec = vdupq_n_f32(0.0f);
676 int d = 0;
677
678 for (; d + 4 <= D; d += 4) {
679 const float32x4_t xv = vld1q_f32(&x[d]);
680 sum_sq_vec = vfmaq_f32(sum_sq_vec, xv, xv);
681 }
682 float sum_sq = hsum128_ps_rmsnorm(sum_sq_vec);
683
684 for (; d < D; ++d) {
685 sum_sq += x[d] * x[d];
686 }
687
688 float mean_sq = sum_sq / (float)D;
689 float rstd = 1.0f / sqrtf(mean_sq + eps);
690 if (rstd_cache) {
691 rstd_cache[t] = rstd;
692 }
693
694 const float32x4_t rstd_vec = vdupq_n_f32(rstd);
695 d = 0;
696 for (; d + 4 <= D; d += 4) {
697 const float32x4_t xv = vld1q_f32(&x[d]);
698 const float32x4_t gv = vld1q_f32(&gamma[d]);
699 /* Keep the two separate rounding boundaries of the scalar tail:
700 * x_hat = x * rstd, then y = x_hat * gamma (no FMA fusion). */
701 const float32x4_t x_hat = vmulq_f32(xv, rstd_vec);
702 vst1q_f32(&y[d], vmulq_f32(x_hat, gv));
703 }
704 for (; d < D; ++d) {
705 y[d] = x[d] * rstd * gamma[d];
706 }
707
708#else
709 // Scalar fallback
710 float sum_sq = 0.0f;
711 for (int d = 0; d < D; ++d) {
712 float v = x[d];
713 sum_sq += v * v;
714 }
715 float mean_sq = sum_sq / (float)D;
716 float rstd = 1.0f / sqrtf(mean_sq + eps);
717 if (rstd_cache) {
718 rstd_cache[t] = rstd;
719 }
720
721 // Apply normalization and scale
722 for (int d = 0; d < D; ++d) {
723 float x_hat = x[d] * rstd;
724 y[d] = x_hat * gamma[d];
725 }
726#endif
727
728 // Zero padding (if any)
729 for (int d = D; d < output_stride; ++d) {
730 y[d] = 0.0f;
731 }
732 }
733}
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 440 of file rmsnorm_kernels.c.

449{
451 input, gamma, output, rstd_cache, tokens, d_model,
452 input_stride, output_stride, eps, 0, 0);
453}

References rmsnorm_forward_pytorch_bf16_storage_impl().

◆ rmsnorm_llama_production_rstd()

static float rmsnorm_llama_production_rstd ( float  mean_eps)
inlinestatic

Definition at line 189 of file rmsnorm_kernels.c.

190{
191 /*
192 * ggml's production CPU RMSNorm emits scalar sqrt followed by scalar
193 * division. With -fno-math-errno ICX otherwise strength-reduces the C
194 * expression to vrsqrt14ss plus one Newton step. That estimate differs by
195 * one ULP for some rows and the error is amplified by quantized
196 * projections in deep recurrent models.
197 */
198#if defined(CK_TARGET_X86)
199 const __m128 value = _mm_set_ss(mean_eps);
200 const __m128 root = _mm_sqrt_ss(value);
201 return _mm_cvtss_f32(_mm_div_ss(_mm_set_ss(1.0f), root));
202#else
203 const volatile float root = sqrtf(mean_eps);
204 return 1.0f / root;
205#endif
206}

Referenced by rmsnorm_forward_llama_production(), and rmsnorm_forward_no_weight_llama_production().