23#if defined(__AVX__) || defined(__AVX2__) || defined(__AVX512F__)
28static inline __m256 rmsnorm_square_avx2_no_contract(__m256 values)
30#if defined(__GNUC__) || defined(__clang__)
32 __asm__
volatile (
"vmulps %1, %1, %0" :
"=x"(squared) :
"x"(values));
37 _Alignas(32) volatile
float materialized[8];
38 _mm256_store_ps((
float *)materialized, _mm256_mul_ps(values, values));
39 return _mm256_load_ps((const
float *)materialized);
43static inline __m256 rmsnorm_add_avx2_ordered(__m256
left, __m256
right)
45#if defined(__GNUC__) || defined(__clang__)
47 __asm__
volatile (
"vaddps %2, %1, %0" :
"=x"(sum) :
"x"(
left),
"x"(
right));
50 _Alignas(32) volatile
float materialized[8];
51 _mm256_store_ps((
float *)materialized, _mm256_add_ps(
left,
right));
52 return _mm256_load_ps((const
float *)materialized);
56static inline __m256 rmsnorm_load_bf16_values_avx2(
const float *values)
58 _Alignas(32) float rounded[8];
59 for (
int lane = 0; lane < 8; ++lane) {
62 return _mm256_load_ps(rounded);
66#if defined(__i386__) || defined(__x86_64__)
67static inline float rmsnorm_div_f32_ordered(
float numerator,
float denominator)
69#if defined(__GNUC__) || defined(__clang__)
71 __asm__
volatile (
"vdivss %2, %1, %0"
73 :
"x"(numerator),
"x"(denominator));
76 volatile float ordered_numerator = numerator;
77 volatile float ordered_denominator = denominator;
78 return ordered_numerator / ordered_denominator;
84#if defined(__AVX__) && !defined(__AVX512F__)
85static inline float hsum256_ps_rmsnorm(__m256 v) {
87 __m128 hi = _mm256_extractf128_ps(v, 1);
88 __m128 lo = _mm256_castps256_ps128(v);
89 __m128 sum128 = _mm_add_ps(lo, hi);
91 sum128 = _mm_hadd_ps(sum128, sum128);
92 sum128 = _mm_hadd_ps(sum128, sum128);
93 return _mm_cvtss_f32(sum128);
106 const float inv_d = 1.0f / (float)d_model;
107 for (
int t = 0; t < tokens; ++t) {
108 const float *x = input + (size_t)t * (
size_t)input_stride;
109 float *y = output + (size_t)t * (
size_t)output_stride;
112 for (
int d = 0; d < d_model; ++d) {
113 const float v = x[d];
116 const float mean_sq = sum_sq * inv_d;
117 const float rstd = 1.0f / sqrtf(mean_sq + eps);
119 rstd_cache[t] = rstd;
122 for (
int d = 0; d < d_model; ++d) {
123 const float x_hat = x[d] * rstd;
124 y[d] = x_hat * gamma[d];
126 for (
int d = d_model; d < output_stride; ++d) {
132#if defined(__clang__)
134#elif defined(__GNUC__)
135__attribute__((optimize(
"O1,no-tree-vectorize,no-tree-slp-vectorize"), noinline))
143 int aligned_embed_dim,
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;
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;
157 const float mean_sq = (float)(sum_sq / (
double)d_model);
158 const float rstd = 1.0f / sqrtf(mean_sq + eps);
160 rstd_cache[t] = rstd;
162 for (
int d = 0; d < d_model; ++d) {
163 const float normalized = x[d] * rstd;
164 y[d] = normalized * gamma[d];
166 for (
int d = d_model; d < aligned_embed_dim; ++d) {
181#if defined(CK_TARGET_X86)
182 const __m128 value = _mm_set_ss(mean_eps);
183 const __m128 root = _mm_sqrt_ss(value);
184 return _mm_cvtss_f32(_mm_div_ss(_mm_set_ss(1.0f), root));
186 const volatile float root = sqrtf(mean_eps);
191#if defined(__clang__)
193#elif defined(__GNUC__)
194__attribute__((optimize(
"O1,no-tree-vectorize,no-tree-slp-vectorize"), noinline))
202 int aligned_embed_dim,
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;
213 const float mean_sq = (float)(sum_sq / (
double)d_model);
216 rstd_cache[t] = rstd;
218 for (
int d = 0; d < d_model; ++d) {
227 y[d] = x[d] * rstd * gamma[d];
229 for (
int d = d_model; d < aligned_embed_dim; ++d) {
263 int qwen3next_weight_order)
265 for (
int t = 0; t < tokens; ++t) {
266 const float *x = input + (size_t)t * (
size_t)input_stride;
267 float *y = output + (size_t)t * (
size_t)output_stride;
280 for (
int hierarchy = 0; hierarchy < 4; ++hierarchy) {
281 for (
int stream = 0; stream < 4; ++stream) {
282 level[hierarchy][stream] = _mm256_setzero_ps();
286 const int vector_count = d_model / 8;
287 const int cascade_items = vector_count / 4;
289 if (cascade_items > 1) {
291 unsigned int value = (
unsigned int)(cascade_items - 1);
296 const int candidate = ceil_log2 / 4;
297 if (candidate > level_power) level_power = candidate;
299 const int level_step = 1 << level_power;
300 const int level_mask = level_step - 1;
302 for (; item + level_step <= cascade_items;) {
303 for (
int block = 0; block < level_step; ++block, ++item) {
304 for (
int stream = 0; stream < 4; ++stream) {
305 const int offset = (item * 4 + stream) * 8;
306 const __m256 values = rmsnorm_load_bf16_values_avx2(x + offset);
307 const __m256 squared = rmsnorm_square_avx2_no_contract(values);
308 level[0][stream] = rmsnorm_add_avx2_ordered(
309 level[0][stream], squared
313 for (
int hierarchy = 1; hierarchy < 4; ++hierarchy) {
314 for (
int stream = 0; stream < 4; ++stream) {
315 level[hierarchy][stream] = rmsnorm_add_avx2_ordered(
316 level[hierarchy][stream], level[hierarchy - 1][stream]
318 level[hierarchy - 1][stream] = _mm256_setzero_ps();
320 const int mask = level_mask << (hierarchy * level_power);
321 if ((item &
mask) != 0)
break;
324 for (; item < cascade_items; ++item) {
325 for (
int stream = 0; stream < 4; ++stream) {
326 const int offset = (item * 4 + stream) * 8;
327 const __m256 values = rmsnorm_load_bf16_values_avx2(x + offset);
328 const __m256 squared = rmsnorm_square_avx2_no_contract(values);
329 level[0][stream] = rmsnorm_add_avx2_ordered(
330 level[0][stream], squared
334 for (
int hierarchy = 1; hierarchy < 4; ++hierarchy) {
335 for (
int stream = 0; stream < 4; ++stream) {
336 level[0][stream] = rmsnorm_add_avx2_ordered(
337 level[0][stream], level[hierarchy][stream]
341 __m256 reduced = level[0][0];
342 for (
int stream = 1; stream < 4; ++stream) {
343 reduced = rmsnorm_add_avx2_ordered(reduced, level[0][stream]);
345 d = cascade_items * 4 * 8;
346 for (; d + 8 <= d_model; d += 8) {
347 const __m256 values = rmsnorm_load_bf16_values_avx2(x + d);
348 const __m256 squared = rmsnorm_square_avx2_no_contract(values);
349 reduced = rmsnorm_add_avx2_ordered(reduced, squared);
351 _Alignas(32)
float lanes[8];
352 _mm256_store_ps(lanes, reduced);
353 volatile float ordered_sum = 0.0f;
354 for (
int lane = 0; lane < 8; ++lane) {
355 ordered_sum = ordered_sum + lanes[lane];
357 sum_sq = ordered_sum;
358 for (; d < d_model; ++d) {
360 sum_sq += value * value;
363 for (
int d = 0; d < d_model; ++d) {
365 sum_sq += value * value;
369#if defined(__i386__) || defined(__x86_64__)
370 const float variance = rmsnorm_div_f32_ordered(sum_sq, (
float)d_model);
371 const float rstd = rmsnorm_div_f32_ordered(1.0f, sqrtf(variance + eps));
373 const float variance = sum_sq / (float)d_model;
374 const float rstd = 1.0f / sqrtf(variance + eps);
376 if (rstd_cache) rstd_cache[t] = rstd;
377 for (
int d = 0; d < d_model; ++d) {
379 if (qwen3next_weight_order) {
382 (value * rstd) * gamma[d]));
386 const float normalized =
391 for (
int d = d_model; d < output_stride; ++d) y[d] = 0.0f;
401 int aligned_embed_dim,
405 input, gamma, output, rstd_cache, tokens, d_model,
406 aligned_embed_dim, aligned_embed_dim, eps, 0);
420 input, gamma, output, rstd_cache, tokens, d_model,
421 input_stride, output_stride, eps, 0);
431 int aligned_embed_dim,
435 input, gamma, output, rstd_cache, tokens, d_model,
436 aligned_embed_dim, aligned_embed_dim, eps, 1);
442 const float *rstd_cache,
447 int aligned_embed_dim)
449 const float inv_d = 1.0f / (float)d_model;
450 for (
int d = 0; d < d_model; ++d) {
454 for (
int t = 0; t < tokens; ++t) {
455 const float *x = input + (size_t)t * (
size_t)aligned_embed_dim;
456 const float *dY = d_output + (size_t)t * (
size_t)aligned_embed_dim;
457 float *dX = d_input + (size_t)t * (
size_t)aligned_embed_dim;
458 const float rstd = rstd_cache[t];
460 float sum_dY_g_xhat = 0.0f;
461 for (
int d = 0; d < d_model; ++d) {
462 const float x_hat = x[d] * rstd;
463 const float grad_x_hat = dY[d] * gamma[d];
464 sum_dY_g_xhat += x_hat * grad_x_hat;
467 for (
int d = 0; d < d_model; ++d) {
468 const float x_hat = x[d] * rstd;
469 const float grad_x_hat = dY[d] * gamma[d];
470 dX[d] = (grad_x_hat - (x_hat * inv_d) * sum_dY_g_xhat) * rstd;
471 d_gamma[d] += dY[d] * x_hat;
473 for (
int d = d_model; d < aligned_embed_dim; ++d) {
505 const char *exact_env = getenv(
"CK_RMSNORM_EXACT");
508 input, gamma, output, rstd_cache, T, D, input_stride, output_stride, eps
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;
517#if defined(__AVX512F__)
519 __m512 sum_sq_vec = _mm512_setzero_ps();
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);
527 float sum_sq = _mm512_reduce_add_ps(sum_sq_vec);
531 sum_sq += x[d] * x[d];
534 float mean_sq = sum_sq / (float)D;
535 float rstd = 1.0f / sqrtf(mean_sq + eps);
537 rstd_cache[t] = rstd;
541 __m512 rstd_vec = _mm512_set1_ps(rstd);
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);
552 y[d] = x[d] * rstd * gamma[d];
555#elif defined(__AVX__)
557 __m256 sum_sq_vec = _mm256_setzero_ps();
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);
566 float sum_sq = hsum256_ps_rmsnorm(sum_sq_vec);
570 sum_sq += x[d] * x[d];
573 float mean_sq = sum_sq / (float)D;
574 float rstd = 1.0f / sqrtf(mean_sq + eps);
576 rstd_cache[t] = rstd;
580 __m256 rstd_vec = _mm256_set1_ps(rstd);
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);
591 y[d] = x[d] * rstd * gamma[d];
597 for (
int d = 0; d < D; ++d) {
601 float mean_sq = sum_sq / (float)D;
602 float rstd = 1.0f / sqrtf(mean_sq + eps);
604 rstd_cache[t] = rstd;
608 for (
int d = 0; d < D; ++d) {
609 float x_hat = x[d] * rstd;
610 y[d] = x_hat * gamma[d];
615 for (
int d = D; d < output_stride; ++d) {
627 int aligned_embed_dim,
649 int aligned_embed_dim,
652 rmsnorm_forward(input, gamma, output, rstd_cache, tokens, d_model, aligned_embed_dim, eps);
660 int aligned_embed_dim,
663 if (!input || !output || tokens <= 0 || d_model <= 0 || aligned_embed_dim <= 0) {
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;
671 for (
int d = 0; d < d_model; ++d) {
672 sum_sq += (double)x[d] * (
double)x[d];
674 const float rstd = 1.0f / sqrtf((
float)(sum_sq * (
double)inv_d) + eps);
676 rstd_cache[t] = rstd;
678 for (
int d = 0; d < d_model; ++d) {
681 for (
int d = d_model; d < aligned_embed_dim; ++d) {
695 if (!input || !output || tokens <= 0 || num_kv_heads <= 0 || head_dim <= 0) {
699 tokens * num_kv_heads, head_dim, head_dim, eps);
718 const float *rstd_cache,
723 int aligned_embed_dim)
727 int aligned = aligned_embed_dim;
735#if defined(__AVX512F__)
738 for (; d + 16 <= D; d += 16) {
739 _mm512_storeu_ps(&d_gamma[d], _mm512_setzero_ps());
745#elif defined(__AVX__)
748 for (; d + 8 <= D; d += 8) {
749 _mm256_storeu_ps(&d_gamma[d], _mm256_setzero_ps());
756 for (
int d = 0; d < D; ++d) {
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;
766 float rstd = rstd_cache[t];
768#if defined(__AVX512F__)
770 __m512 rstd_vec = _mm512_set1_ps(rstd);
771 __m512 sum_vec = _mm512_setzero_ps();
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);
780 __m512 prod = _mm512_mul_ps(dyv, gv);
781 sum_vec = _mm512_fmadd_ps(prod, x_hat, sum_vec);
783 float sum_dY_g_xhat = _mm512_reduce_add_ps(sum_vec);
787 float x_hat = x[d] * rstd;
788 sum_dY_g_xhat += dY[d] * gamma[d] * x_hat;
790 float m = sum_dY_g_xhat / (float)D;
793 __m512 m_vec = _mm512_set1_ps(m);
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]);
801 __m512 x_hat = _mm512_mul_ps(xv, rstd_vec);
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);
811 dgv = _mm512_fmadd_ps(dyv, x_hat, dgv);
812 _mm512_storeu_ps(&d_gamma[d], dgv);
816 float x_hat = x[d] * rstd;
818 dX[d] = rstd * (dy * gamma[d] - x_hat * m);
819 d_gamma[d] += dy * x_hat;
822#elif defined(__AVX__)
824 __m256 rstd_vec = _mm256_set1_ps(rstd);
825 __m256 sum_vec = _mm256_setzero_ps();
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);
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);
838 float sum_dY_g_xhat = hsum256_ps_rmsnorm(sum_vec);
842 float x_hat = x[d] * rstd;
843 sum_dY_g_xhat += dY[d] * gamma[d] * x_hat;
845 float m = sum_dY_g_xhat / (float)D;
848 __m256 m_vec = _mm256_set1_ps(m);
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]);
856 __m256 x_hat = _mm256_mul_ps(xv, rstd_vec);
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);
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);
872 float x_hat = x[d] * rstd;
874 dX[d] = rstd * (dy * gamma[d] - x_hat * m);
875 d_gamma[d] += dy * x_hat;
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;
886 float m = sum_dY_g_xhat / (float)D;
889 for (
int d = 0; d < D; ++d) {
890 float x_hat = x[d] * rstd;
892 dX[d] = rstd * (dy * gamma[d] - x_hat * m);
893 d_gamma[d] += dy * x_hat;
898 for (
int d = D; d < aligned; ++d) {
static uint16_t float_to_bf16(float f)
static float bf16_to_float(uint16_t v)
int ck_strict_parity_enabled(void)
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_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_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_llama_production(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_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(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 qwen3next_weight_order)
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_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 gemma4_v_norm_forward(const float *input, float *output, float *rstd_cache, int tokens, int num_kv_heads, int head_dim, float eps)
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_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 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 float rmsnorm_llama_production_rstd(float mean_eps)
int32_t int32_t int32_t int32_t int32_t mask
__attribute__((visibility("default"))) CKTokenizer *ck_tokenizer_create(CKTokenizerType type)
const char const char * right