← Back to C-Kernel-Engine Docs Doxygen Source Documentation
 
Loading...
Searching...
No Matches
rope_kernels.c
Go to the documentation of this file.
1/**
2 * @file rope_kernels.c
3 * @brief RoPE (Rotary Position Embedding) kernels with SIMD
4 *
5 * CK-ENGINE KERNEL RULES:
6 * =======================
7 * 1. NO malloc/free - memory via bump allocator, pointers passed in
8 * 2. NO OpenMP - parallelization at orchestrator/codegen layer
9 * 3. API must define: inputs, outputs, workspace, and memory layouts
10 * 4. Pure computation - deterministic, no side effects
11 *
12 * After changes: make test && make llamacpp-parity-full
13 *
14 * Applies rotary position embeddings to query and key vectors.
15 * Used by Llama, SmolLM, and most modern transformer architectures.
16 *
17 * Math (Llama-style rotate-half):
18 * Split rotary_dim into two halves (0..half-1, half..rotary_dim-1).
19 * For each position m and index i in [0, half):
20 * x0 = x[i], x1 = x[i + half]
21 * x'[i] = x0 * cos(m * theta_i) - x1 * sin(m * theta_i)
22 * x'[i+half] = x0 * sin(m * theta_i) + x1 * cos(m * theta_i)
23 *
24 * Where theta_i = 1 / (base^(2i/d)), typically base=10000.
25 *
26 * Layout:
27 * x: [num_heads, num_tokens, head_dim] head-major
28 * cos_cache, sin_cache: [max_seq_len, rotary_dim/2] precomputed
29 */
30
31#ifndef _GNU_SOURCE
32#define _GNU_SOURCE
33#endif
34
35#include "ckernel_engine.h"
36#include "bf16_utils.h"
37#include "ckernel_quant.h"
38#include "ggml_runtime_compat.h"
39
40#include <dlfcn.h>
41#include <math.h>
42#include <stddef.h>
43#include <stdio.h>
44#include <stdlib.h>
45#include <string.h>
46
47#ifdef USE_MKL
48#include <mkl_vml_functions.h>
49#endif
50
51#if defined(__AVX__) || defined(__AVX2__) || defined(__AVX512F__)
52#include <immintrin.h>
53#endif
54
55#ifndef M_PI
56#define M_PI 3.14159265358979323846
57#endif
58
59typedef void (*ck_ggml_cpu_init_fn)(void);
60typedef struct ggml_context *(*ck_ggml_init_fn)(struct ggml_init_params);
61typedef void (*ck_ggml_free_fn)(struct ggml_context *);
62typedef struct ggml_tensor *(*ck_ggml_new_tensor_1d_fn)(struct ggml_context *, enum ggml_type, int64_t);
63typedef struct ggml_tensor *(*ck_ggml_view_3d_fn)(struct ggml_context *, struct ggml_tensor *, int64_t, int64_t, int64_t, size_t, size_t, size_t);
64typedef struct ggml_tensor *(*ck_ggml_rope_multi_inplace_fn)(struct ggml_context *,
65 struct ggml_tensor *,
66 struct ggml_tensor *,
67 struct ggml_tensor *,
68 int,
70 int,
71 int,
72 float,
73 float,
74 float,
75 float,
76 float,
77 float);
78typedef struct ggml_cgraph *(*ck_ggml_new_graph_fn)(struct ggml_context *);
79typedef void (*ck_ggml_build_forward_expand_fn)(struct ggml_cgraph *, struct ggml_tensor *);
80typedef enum ggml_status (*ck_ggml_graph_compute_with_ctx_fn)(struct ggml_context *, struct ggml_cgraph *, int);
81typedef void *(*ck_ggml_get_data_fn)(const struct ggml_tensor *);
82typedef float (*ck_rope_math_f32_fn)(float);
83typedef float (*ck_rope_math_f32_binary_fn)(float, float);
84
86{
87#if defined(__linux__)
88 static void *libm_handle = NULL;
89 if (!libm_handle) {
90 libm_handle = dlopen("libm.so.6", RTLD_NOW | RTLD_LOCAL);
91 }
92 if (libm_handle) {
93 ck_rope_math_f32_fn fn = (ck_rope_math_f32_fn)dlsym(libm_handle, name);
94 if (fn) {
95 return fn;
96 }
97 }
98#else
99 (void)name;
100#endif
101 return NULL;
102}
103
104/* ICX links libimf ahead of the system math library. Its sinf/cosf results can
105 * differ from a GCC-built ggml oracle by one ULP, which is enough to alter Q8
106 * blocks downstream. Resolve the platform libm implementation explicitly for
107 * the ggml-compatible M-RoPE arithmetic contract. */
108static float ck_rope_reference_cosf(float value)
109{
110 static ck_rope_math_f32_fn fn = NULL;
111 if (!fn) {
113 }
114 return fn ? fn(value) : cosf(value);
115}
116
117static float ck_rope_reference_sinf(float value)
118{
119 static ck_rope_math_f32_fn fn = NULL;
120 if (!fn) {
122 }
123 return fn ? fn(value) : sinf(value);
124}
125
126static float ck_rope_reference_powf(float base, float exponent)
127{
128 static ck_rope_math_f32_binary_fn fn = NULL;
129 if (!fn) {
130#if defined(__linux__)
131 static void *libm_handle = NULL;
132 if (!libm_handle) {
133 libm_handle = dlopen("libm.so.6", RTLD_NOW | RTLD_LOCAL);
134 }
135 if (libm_handle) {
136 fn = (ck_rope_math_f32_binary_fn)dlsym(libm_handle, "powf");
137 }
138#endif
139 }
140 return fn ? fn(base, exponent) : powf(base, exponent);
141}
142
144{
145 static int tried = 0;
146 if (tried) {
147 return;
148 }
149 tried = 1;
150
151 const char *env_dir = getenv("CK_GGML_LIB_DIR");
152 const char *dirs[] = {
153 "/opt/app-root/src/Software/llama.cpp/build/bin",
154 "./llama.cpp/build/bin",
155 "llama.cpp/build/bin",
156 NULL,
157 };
158 char path_buf[512];
159 if (env_dir && env_dir[0]) {
160 snprintf(path_buf, sizeof(path_buf), "%s/libggml-base.so", env_dir);
161 dlopen(path_buf, RTLD_NOW | RTLD_GLOBAL);
162 snprintf(path_buf, sizeof(path_buf), "%s/libggml.so", env_dir);
163 dlopen(path_buf, RTLD_NOW | RTLD_GLOBAL);
164 snprintf(path_buf, sizeof(path_buf), "%s/libggml-cpu.so", env_dir);
165 void *cpu = dlopen(path_buf, RTLD_NOW | RTLD_GLOBAL);
166 if (cpu) {
167 return;
168 }
169 }
170 for (int i = 0; dirs[i] != NULL; ++i) {
171 snprintf(path_buf, sizeof(path_buf), "%s/libggml-base.so", dirs[i]);
172 dlopen(path_buf, RTLD_NOW | RTLD_GLOBAL);
173 snprintf(path_buf, sizeof(path_buf), "%s/libggml.so", dirs[i]);
174 dlopen(path_buf, RTLD_NOW | RTLD_GLOBAL);
175 snprintf(path_buf, sizeof(path_buf), "%s/libggml-cpu.so", dirs[i]);
176 void *cpu = dlopen(path_buf, RTLD_NOW | RTLD_GLOBAL);
177 if (cpu) {
178 return;
179 }
180 }
181}
182
183static void *ck_rope_resolve_ggml_symbol(const char *name)
184{
185 void *sym = dlsym(RTLD_DEFAULT, name);
186 if (sym) {
187 return sym;
188 }
190 sym = dlsym(RTLD_DEFAULT, name);
191 return sym;
192}
193
195 static ck_ggml_cpu_init_fn fn = NULL;
196 if (!fn) {
197 fn = (ck_ggml_cpu_init_fn) ck_rope_resolve_ggml_symbol("ggml_cpu_init");
198 }
199 return fn;
200}
201
203 static ck_ggml_init_fn fn = NULL;
204 if (!fn) {
206 }
207 return fn;
208}
209
211 static ck_ggml_free_fn fn = NULL;
212 if (!fn) {
214 }
215 return fn;
216}
217
219 static ck_ggml_new_tensor_1d_fn fn = NULL;
220 if (!fn) {
221 fn = (ck_ggml_new_tensor_1d_fn) ck_rope_resolve_ggml_symbol("ggml_new_tensor_1d");
222 }
223 return fn;
224}
225
227 static ck_ggml_view_3d_fn fn = NULL;
228 if (!fn) {
229 fn = (ck_ggml_view_3d_fn) ck_rope_resolve_ggml_symbol("ggml_view_3d");
230 }
231 return fn;
232}
233
235 static ck_ggml_rope_multi_inplace_fn fn = NULL;
236 if (!fn) {
237 fn = (ck_ggml_rope_multi_inplace_fn) ck_rope_resolve_ggml_symbol("ggml_rope_multi_inplace");
238 }
239 return fn;
240}
241
243 static ck_ggml_new_graph_fn fn = NULL;
244 if (!fn) {
245 fn = (ck_ggml_new_graph_fn) ck_rope_resolve_ggml_symbol("ggml_new_graph");
246 }
247 return fn;
248}
249
251 static ck_ggml_build_forward_expand_fn fn = NULL;
252 if (!fn) {
253 fn = (ck_ggml_build_forward_expand_fn) ck_rope_resolve_ggml_symbol("ggml_build_forward_expand");
254 }
255 return fn;
256}
257
259 static ck_ggml_graph_compute_with_ctx_fn fn = NULL;
260 if (!fn) {
261 fn = (ck_ggml_graph_compute_with_ctx_fn) ck_rope_resolve_ggml_symbol("ggml_graph_compute_with_ctx");
262 }
263 return fn;
264}
265
267 static ck_ggml_get_data_fn fn = NULL;
268 if (!fn) {
269 fn = (ck_ggml_get_data_fn) ck_rope_resolve_ggml_symbol("ggml_get_data");
270 }
271 return fn;
272}
273
274/* Forward declarations for extended RoPE entry points used by wrappers. */
275void rope_forward_with_rotary_dim(float *x,
276 const float *cos_cache,
277 const float *sin_cache,
278 int num_heads,
279 int num_tokens,
280 int head_dim,
281 int aligned_head_dim,
282 int pos_offset,
283 int rotary_dim);
285 const float *cos_cache,
286 const float *sin_cache,
287 int num_heads,
288 int num_tokens,
289 int head_dim,
290 int aligned_head_dim,
291 int pos_offset,
292 int head_stride_tokens,
293 int rotary_dim);
295 float *k,
296 const float *cos_cache,
297 const float *sin_cache,
298 int num_heads,
299 int num_kv_heads,
300 int num_tokens,
301 int head_dim,
302 int aligned_head_dim,
303 int pos_offset,
304 int rotary_dim);
306 float *k,
307 const float *cos_cache,
308 const float *sin_cache,
309 int num_heads,
310 int num_kv_heads,
311 int num_tokens,
312 int head_dim,
313 int aligned_head_dim,
314 int pos_offset,
315 int q_stride_tokens,
316 int k_stride_tokens,
317 int rotary_dim);
319 float *k,
320 const float *cos_cache,
321 const float *sin_cache,
322 int num_heads,
323 int num_kv_heads,
324 int num_tokens,
325 int head_dim,
326 int aligned_head_dim,
327 int pos_offset,
328 int rotary_dim);
329
330/**
331 * Precompute RoPE cos/sin cache (split layout: head_dim/2)
332 * Legacy layout used before rotary_dim/scaling support.
333 *
334 * @param cos_cache Output: [max_seq_len, head_dim/2] cos values
335 * @param sin_cache Output: [max_seq_len, head_dim/2] sin values
336 * @param max_seq_len Maximum sequence length for cache
337 * @param head_dim Full head dimension
338 * @param base RoPE base frequency (theta)
339 */
340void rope_precompute_cache_split(float *cos_cache,
341 float *sin_cache,
342 int max_seq_len,
343 int head_dim,
344 float base)
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}
357
358/**
359 * Precompute RoPE cos/sin cache with rotary_dim and scaling support
360 * @test test_rope.py::TestRoPECache::test_cache_computation
361 * @test test_rope.py::TestRoPECache::test_cache_values
362 *
363 * Precomputes cos(m * theta_i) and sin(m * theta_i) for positions 0..max_seq_len-1.
364 * Only computes for first rotary_dim channels; remaining head_dim - rotary_dim
365 * channels are NOT rotated (pass through unchanged).
366 *
367 * Scaling types:
368 * - "none": Standard RoPE
369 * - "linear": Scale positions by 1/scaling_factor
370 * - "dynamic": NTK-aware dynamic scaling
371 * - "yarn": YaRN scaling (beta-based)
372 *
373 * @param cos_cache Output: [max_seq_len, rotary_dim/2] cos values
374 * @param sin_cache Output: [max_seq_len, rotary_dim/2] sin values
375 * @param max_seq_len Maximum sequence length for cache
376 * @param head_dim Full head dimension (for frequency computation)
377 * @param base RoPE base frequency (theta)
378 * @param rotary_dim Number of dimensions to rotate (0 = use head_dim)
379 * @param scaling_type Scaling type string: "none", "linear", "dynamic", "yarn"
380 * @param scaling_factor Scaling factor (1.0 = no scaling)
381 *
382 * After changes: make test
383 */
384void rope_precompute_cache(float *cos_cache,
385 float *sin_cache,
386 int max_seq_len,
387 int head_dim,
388 float base,
389 int rotary_dim,
390 const char *scaling_type,
391 float scaling_factor)
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}
425
426static float yarn_correction_dim(float rotations,
427 int rotary_dim,
428 float freq_base,
429 int original_context)
430{
431 return ((float)rotary_dim *
432 logf((float)original_context / (rotations * 2.0f * (float)M_PI))) /
433 (2.0f * logf(freq_base));
434}
435
436static float yarn_mscale(float factor, float scale)
437{
438 return factor <= 1.0f ? 1.0f : 0.1f * scale * logf(factor) + 1.0f;
439}
440
442 float *sin_f32,
443 uint16_t *cos_bf16,
444 uint16_t *sin_bf16,
445 const int32_t *positions,
446 int num_tokens,
447 int rotary_dim,
448 float freq_base,
449 float factor,
450 int original_context,
451 float beta_fast,
452 float beta_slow,
453 float mscale,
454 float mscale_all_dim)
455{
456 if ((!cos_f32 && !cos_bf16) || (!sin_f32 && !sin_bf16) ||
457 num_tokens <= 0 || rotary_dim <= 0 || (rotary_dim & 1) != 0 ||
458 freq_base <= 0.0f || factor <= 0.0f || original_context <= 0 ||
459 beta_fast <= 0.0f || beta_slow <= 0.0f) {
460 return;
461 }
462
463 const int pairs = rotary_dim / 2;
464 float low = floorf(yarn_correction_dim(
465 beta_fast, rotary_dim, freq_base, original_context));
466 float high = ceilf(yarn_correction_dim(
467 beta_slow, rotary_dim, freq_base, original_context));
468 low = fmaxf(low, 0.0f);
469 high = fminf(high, (float)(rotary_dim - 1));
470 if (low == high) high += 0.001f;
471
472 const float attention_factor =
473 yarn_mscale(factor, mscale) /
474 yarn_mscale(factor, mscale_all_dim);
475
476 for (int token = 0; token < num_tokens; ++token) {
477 const float position = (float)(positions ? positions[token] : token);
478 for (int pair = 0; pair < pairs; ++pair) {
479 const float exponent = (2.0f * (float)pair) / (float)rotary_dim;
480 const float pos_freq = ck_rope_reference_powf(freq_base, exponent);
481 const float inv_extrap = 1.0f / pos_freq;
482 const float inv_interp = 1.0f / (factor * pos_freq);
483 float ramp = ((float)pair - low) / (high - low);
484 ramp = fminf(1.0f, fmaxf(0.0f, ramp));
485 const float inv_freq = inv_interp * ramp + inv_extrap * (1.0f - ramp);
486 const float angle = position * inv_freq;
487 const float cosine = ck_rope_reference_cosf(angle) * attention_factor;
488 const float sine = ck_rope_reference_sinf(angle) * attention_factor;
489 const size_t index = (size_t)token * (size_t)pairs + (size_t)pair;
490 if (cos_f32) cos_f32[index] = cosine;
491 if (sin_f32) sin_f32[index] = sine;
492 if (cos_bf16) cos_bf16[index] = float_to_bf16(cosine);
493 if (sin_bf16) sin_bf16[index] = float_to_bf16(sine);
494 }
495 }
496}
497
499 float *sin_cache,
500 const int32_t *positions,
501 int num_tokens,
502 int rotary_dim,
503 float freq_base,
504 float factor,
505 int original_context,
506 float beta_fast,
507 float beta_slow,
508 float mscale,
509 float mscale_all_dim)
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}
516
518 float *sin_cache,
519 int num_tokens,
520 int rotary_dim,
521 float freq_base,
522 float factor,
523 int original_context,
524 float beta_fast,
525 float beta_slow,
526 float mscale,
527 float mscale_all_dim)
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}
534
536 uint16_t *sin_cache,
537 const int32_t *positions,
538 int num_tokens,
539 int rotary_dim,
540 float freq_base,
541 float factor,
542 int original_context,
543 float beta_fast,
544 float beta_slow,
545 float mscale,
546 float mscale_all_dim)
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}
553
554/*
555 * Match ggml's CPU RoPE cache arithmetic. ggml computes theta_scale once,
556 * starts each position at theta=pos, and advances frequencies by repeated
557 * FP32 multiplication. Computing each frequency independently with powf is
558 * mathematically equivalent but can differ by several ULPs at later pairs.
559 */
561 float *sin_cache,
562 int max_seq_len,
563 int head_dim,
564 float base,
565 int rotary_dim,
566 const char *scaling_type,
567 float scaling_factor)
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}
602
603// Apply RoPE to a single head's Q or K tensor in-place.
604// x: [num_tokens, head_dim] for one head
605// cos_cache, sin_cache: [max_seq_len, rotary_dim/2]
606// pos_offset: starting position (for KV cache continuation)
607// rotary_dim: number of dimensions to rotate (0 = use head_dim)
608static inline void rope_apply_head(float *x,
609 const float *cos_cache,
610 const float *sin_cache,
611 int num_tokens,
612 int head_dim,
613 int aligned_head_dim,
614 int pos_offset,
615 int rotary_dim)
616{
617 // Use head_dim if rotary_dim not specified or invalid
618 if (rotary_dim <= 0 || rotary_dim > head_dim) {
619 rotary_dim = head_dim;
620 }
621
622 int rotary_half = rotary_dim / 2;
623
624 for (int t = 0; t < num_tokens; ++t) {
625 int pos = pos_offset + t;
626 const float *cos_row = cos_cache + pos * rotary_half;
627 const float *sin_row = sin_cache + pos * rotary_half;
628 float *x_row = x + (size_t)t * (size_t)aligned_head_dim;
629
630#if defined(__AVX512F__)
631 // Process 16 pairs at a time (within rotary_half)
632 int i = 0;
633 for (; i + 16 <= rotary_half; i += 16) {
634 __m512 x0 = _mm512_loadu_ps(&x_row[i]);
635 __m512 x1 = _mm512_loadu_ps(&x_row[i + rotary_half]);
636 __m512 c = _mm512_loadu_ps(&cos_row[i]);
637 __m512 s = _mm512_loadu_ps(&sin_row[i]);
638
639 // x'[i] = x0 * c - x1 * s
640 __m512 r0 = _mm512_fmsub_ps(x0, c, _mm512_mul_ps(x1, s));
641 // x'[i+half] = x0 * s + x1 * c
642 __m512 r1 = _mm512_fmadd_ps(x0, s, _mm512_mul_ps(x1, c));
643
644 _mm512_storeu_ps(&x_row[i], r0);
645 _mm512_storeu_ps(&x_row[i + rotary_half], r1);
646 }
647 // Handle remaining elements in rotary portion
648 for (; i < rotary_half; ++i) {
649 float x0 = x_row[i];
650 float x1 = x_row[i + rotary_half];
651 float c = cos_row[i];
652 float s = sin_row[i];
653 x_row[i] = x0 * c - x1 * s;
654 x_row[i + rotary_half] = x0 * s + x1 * c;
655 }
656
657#elif defined(__AVX__)
658 // Process 8 pairs at a time (within rotary_half)
659 int i = 0;
660 for (; i + 8 <= rotary_half; i += 8) {
661 __m256 x0 = _mm256_loadu_ps(&x_row[i]);
662 __m256 x1 = _mm256_loadu_ps(&x_row[i + rotary_half]);
663 __m256 c = _mm256_loadu_ps(&cos_row[i]);
664 __m256 s = _mm256_loadu_ps(&sin_row[i]);
665
666 // x'[i] = x0 * c - x1 * s (no FMA in AVX1)
667 __m256 x0c = _mm256_mul_ps(x0, c);
668 __m256 x1s = _mm256_mul_ps(x1, s);
669 __m256 r0 = _mm256_sub_ps(x0c, x1s);
670
671 // x'[i+half] = x0 * s + x1 * c
672 __m256 x0s = _mm256_mul_ps(x0, s);
673 __m256 x1c = _mm256_mul_ps(x1, c);
674 __m256 r1 = _mm256_add_ps(x0s, x1c);
675
676 _mm256_storeu_ps(&x_row[i], r0);
677 _mm256_storeu_ps(&x_row[i + rotary_half], r1);
678 }
679 // Handle remaining elements in rotary portion
680 for (; i < rotary_half; ++i) {
681 float x0 = x_row[i];
682 float x1 = x_row[i + rotary_half];
683 float c = cos_row[i];
684 float s = sin_row[i];
685 x_row[i] = x0 * c - x1 * s;
686 x_row[i + rotary_half] = x0 * s + x1 * c;
687 }
688
689#else
690 // Scalar fallback
691 for (int i = 0; i < rotary_half; ++i) {
692 float x0 = x_row[i];
693 float x1 = x_row[i + rotary_half];
694 float c = cos_row[i];
695 float s = sin_row[i];
696
697 x_row[i] = x0 * c - x1 * s;
698 x_row[i + rotary_half] = x0 * s + x1 * c;
699 }
700#endif
701
702 // Channels [rotary_dim, head_dim) pass through unchanged - nothing to do
703 // They're already in place and don't need rotation
704 }
705}
706
707static inline void rope_apply_head_pairwise(float *x,
708 const float *cos_cache,
709 const float *sin_cache,
710 int num_tokens,
711 int head_dim,
712 int aligned_head_dim,
713 int pos_offset,
714 int rotary_dim)
715{
716 if (rotary_dim <= 0 || rotary_dim > head_dim) {
717 rotary_dim = head_dim;
718 }
719
720 int rotary_half = rotary_dim / 2;
721
722 for (int t = 0; t < num_tokens; ++t) {
723 int pos = pos_offset + t;
724 const float *cos_row = cos_cache + pos * rotary_half;
725 const float *sin_row = sin_cache + pos * rotary_half;
726 float *x_row = x + (size_t)t * (size_t)aligned_head_dim;
727
728 for (int i = 0; i < rotary_half; ++i) {
729 const int idx0 = 2 * i;
730 const int idx1 = idx0 + 1;
731 float x0 = x_row[idx0];
732 float x1 = x_row[idx1];
733 float c = cos_row[i];
734 float s = sin_row[i];
735 x_row[idx0] = x0 * c - x1 * s;
736 x_row[idx1] = x0 * s + x1 * c;
737 }
738 }
739}
740
741static inline void rope_backward_apply_head_pairwise(const float *d_out,
742 float *d_x,
743 const float *cos_cache,
744 const float *sin_cache,
745 int num_tokens,
746 int head_dim,
747 int aligned_head_dim,
748 int pos_offset,
749 int rotary_dim)
750{
751 if (rotary_dim <= 0 || rotary_dim > head_dim) {
752 rotary_dim = head_dim;
753 }
754
755 int rotary_even = rotary_dim - (rotary_dim % 2);
756 int rotary_half = rotary_even / 2;
757
758 for (int t = 0; t < num_tokens; ++t) {
759 int pos = pos_offset + t;
760 const float *cos_row = cos_cache + pos * rotary_half;
761 const float *sin_row = sin_cache + pos * rotary_half;
762 const float *d_out_row = d_out + (size_t)t * (size_t)aligned_head_dim;
763 float *d_x_row = d_x + (size_t)t * (size_t)aligned_head_dim;
764
765 for (int i = 0; i < rotary_half; ++i) {
766 const int idx0 = 2 * i;
767 const int idx1 = idx0 + 1;
768 float d0 = d_out_row[idx0];
769 float d1 = d_out_row[idx1];
770 float c = cos_row[i];
771 float s = sin_row[i];
772 d_x_row[idx0] = d0 * c + d1 * s;
773 d_x_row[idx1] = -d0 * s + d1 * c;
774 }
775
776 for (int i = rotary_even; i < head_dim; ++i) {
777 d_x_row[i] = d_out_row[i];
778 }
779 for (int i = head_dim; i < aligned_head_dim; ++i) {
780 d_x_row[i] = 0.0f;
781 }
782 }
783}
784
785/**
786 * RoPE forward (head-major layout, in-place)
787 * @test test_rope.py::TestRoPEForward::test_rope_forward
788 * @test test_rope.py::TestRoPEForward::test_rope_vs_separate
789 * @test test_parity.py::test_rope_parity
790 *
791 * Applies rotary position embeddings in-place to Q or K tensor.
792 * x: [num_heads, num_tokens, head_dim] head-major
793 *
794 * After changes: make test && make llamacpp-parity-full
795 */
796void rope_forward(float *x,
797 const float *cos_cache,
798 const float *sin_cache,
799 int num_heads,
800 int num_tokens,
801 int head_dim,
802 int aligned_head_dim,
803 int pos_offset)
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}
808
810 const float *cos_cache,
811 const float *sin_cache,
812 int num_heads,
813 int num_tokens,
814 int head_dim,
815 int aligned_head_dim,
816 int pos_offset,
817 int rotary_dim)
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}
827
828/**
829 * RoPE forward with custom head stride (for KV cache layouts)
830 * @test test_rope.py::TestRoPEForward::test_rope_strided
831 * @test test_kv_cache_attention.py::TestKVCacheAttention::test_rope_decode
832 *
833 * Variant with configurable head_stride_tokens for non-contiguous head layouts.
834 *
835 * After changes: make test
836 */
838 const float *cos_cache,
839 const float *sin_cache,
840 int num_heads,
841 int num_tokens,
842 int head_dim,
843 int aligned_head_dim,
844 int pos_offset,
845 int head_stride_tokens)
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}
851
853 const float *cos_cache,
854 const float *sin_cache,
855 int num_heads,
856 int num_tokens,
857 int head_dim,
858 int aligned_head_dim,
859 int pos_offset,
860 int head_stride_tokens,
861 int rotary_dim)
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}
871
872/**
873 * RoPE backward (inverse rotation)
874 * @test test_rope.py::TestRoPEBackward::test_rope_backward
875 * @test test_rope.py::TestRoPEBackward::test_rope_backward_vs_separate
876 *
877 * RoPE backward: inverse rotation (rotate by -θ).
878 * Since cos(-θ) = cos(θ) and sin(-θ) = -sin(θ):
879 * d_x[2i] = d0 * c + d1 * s
880 * d_x[2i+1] = -d0 * s + d1 * c
881 *
882 * After changes: make test
883 */
884void rope_backward(const float *d_out,
885 float *d_x,
886 const float *cos_cache,
887 const float *sin_cache,
888 int num_heads,
889 int num_tokens,
890 int head_dim,
891 int aligned_head_dim,
892 int pos_offset)
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}
981
982/**
983 * RoPE backward in-place (overwrite with inverse rotation)
984 * @test test_rope.py::TestRoPEBackward::test_rope_backward_inplace
985 *
986 * In-place backward: overwrite d_out with inverse-rotated gradients.
987 * Useful when d_x == d_out is acceptable (saves memory).
988 *
989 * After changes: make test
990 */
991void rope_backward_inplace(float *d_x,
992 const float *cos_cache,
993 const float *sin_cache,
994 int num_heads,
995 int num_tokens,
996 int head_dim,
997 int aligned_head_dim,
998 int pos_offset)
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}
1081
1082/**
1083 * RoPE forward for both Q and K (common inference pattern)
1084 * @test test_rope.py::TestRoPEForward::test_rope_forward_qk
1085 * @test test_fused_attention_decode.py::TestFusedAttentionDecode::test_qk_rope
1086 * @test test_parity.py::test_rope_qk_parity
1087 *
1088 * Combined RoPE forward for both Q and K in one call.
1089 * q: [num_heads, num_tokens, head_dim]
1090 * k: [num_kv_heads, num_tokens, head_dim]
1091 *
1092 * After changes: make test && make llamacpp-parity-full
1093 */
1094void rope_forward_qk(float *q,
1095 float *k,
1096 const float *cos_cache,
1097 const float *sin_cache,
1098 int num_heads,
1099 int num_kv_heads,
1100 int num_tokens,
1101 int head_dim,
1102 int aligned_head_dim,
1103 int pos_offset)
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}
1108
1110 float *k,
1111 const float *cos_cache,
1112 const float *sin_cache,
1113 int num_heads,
1114 int num_kv_heads,
1115 int num_tokens,
1116 int head_dim,
1117 int aligned_head_dim,
1118 int pos_offset,
1119 int rotary_dim)
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}
1126
1127
1129 const float *freq_factors,
1130 int use_freq_factors,
1131 int num_heads,
1132 int num_tokens,
1133 int head_dim,
1134 int aligned_head_dim,
1135 int pos_offset,
1136 int rotary_dim,
1137 float freq_base)
1138{
1139 if (!x || num_heads <= 0 || num_tokens <= 0 || head_dim <= 0 || aligned_head_dim <= 0) {
1140 return;
1141 }
1142 if (rotary_dim <= 0 || rotary_dim > head_dim) {
1143 rotary_dim = head_dim;
1144 }
1145 if (freq_base <= 0.0f) {
1146 freq_base = 10000.0f;
1147 }
1148
1149 /* Split-half rotate_half layout, matching HF/Llama-style RoPE:
1150 * [x0...xH, y0...yH] -> [-y0...-yH, x0...xH]
1151 * Gemma4 is currently the first v8 model that needs direct per-layer
1152 * theta/rotary_dim control; keep this model-neutral and select it from
1153 * the IR via rope_layout=split_half + rope_param_mode=per_layer/direct.
1154 */
1155 const int rotary_half = rotary_dim / 2;
1156 const size_t head_stride = (size_t)num_tokens * (size_t)aligned_head_dim;
1157 const float theta_scale = powf(freq_base, -2.0f / (float)rotary_dim);
1158
1159 for (int h = 0; h < num_heads; ++h) {
1160 float *head = x + (size_t)h * head_stride;
1161 for (int t = 0; t < num_tokens; ++t) {
1162 const float pos = (float)(pos_offset + t);
1163 float *x_row = head + (size_t)t * (size_t)aligned_head_dim;
1164 for (int i = 0; i < rotary_half; ++i) {
1165 const int idx0 = i;
1166 const int idx1 = i + rotary_half;
1167 const float ff = (use_freq_factors && freq_factors) ? freq_factors[i] : 1.0f;
1168 const float theta = pos * powf(theta_scale, (float)i) / ff;
1169 const float c = cosf(theta);
1170 const float sv = sinf(theta);
1171 const float x0 = x_row[idx0];
1172 const float x1 = x_row[idx1];
1173 x_row[idx0] = x0 * c - x1 * sv;
1174 x_row[idx1] = x1 * c + x0 * sv;
1175 }
1176 }
1177 }
1178}
1179
1181 float *k,
1182 const float *freq_factors,
1183 int use_freq_factors,
1184 int num_heads,
1185 int num_kv_heads,
1186 int num_tokens,
1187 int head_dim,
1188 int aligned_head_dim,
1189 int pos_offset,
1190 int rotary_dim,
1191 float freq_base)
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}
1200
1202 float *q,
1203 float *k,
1204 const float *freq_factors,
1205 int use_freq_factors,
1206 int num_heads,
1207 int num_kv_heads,
1208 int num_tokens,
1209 int head_dim,
1210 int aligned_head_dim,
1211 int pos_offset,
1212 int rotary_dim,
1213 float freq_base,
1214 int token_begin,
1215 int token_end)
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}
1264
1266 float *q, float *k, const float *freq_factors, int use_freq_factors,
1267 int num_heads, int num_kv_heads, int num_tokens, int head_dim,
1268 int aligned_head_dim, int pos_offset, int rotary_dim, float freq_base,
1269 int token_begin, int token_end)
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}
1300
1302 const float *freq_factors,
1303 int use_freq_factors,
1304 int num_heads,
1305 int num_tokens,
1306 int head_dim,
1307 int aligned_head_dim,
1308 int pos_offset,
1309 int rotary_dim,
1310 float freq_base)
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}
1316
1318 float *k,
1319 const float *freq_factors,
1320 int use_freq_factors,
1321 int num_heads,
1322 int num_kv_heads,
1323 int num_tokens,
1324 int head_dim,
1325 int aligned_head_dim,
1326 int pos_offset,
1327 int rotary_dim,
1328 float freq_base)
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}
1335
1336
1338 int num_heads,
1339 int num_tokens,
1340 int head_dim,
1341 int aligned_head_dim,
1342 int grid_w,
1343 int rotary_dim,
1344 float freq_base)
1345{
1346 if (!x || num_heads <= 0 || num_tokens <= 0 || head_dim <= 0 || aligned_head_dim <= 0) {
1347 return;
1348 }
1349 if (grid_w <= 0) {
1350 grid_w = num_tokens;
1351 }
1352 if (rotary_dim <= 0 || rotary_dim > head_dim) {
1353 rotary_dim = head_dim;
1354 }
1355 if (freq_base <= 0.0f) {
1356 freq_base = 100.0f;
1357 }
1358
1359 /* Gemma4V vision uses llama.cpp's 2D NEOX RoPE contract:
1360 * rotate the first half of the rotary span by patch x, and the second
1361 * half by patch y. Each half is itself split-half/NEOX rotated.
1362 */
1363 const int half_span = rotary_dim / 2;
1364 const int segment_half = half_span / 2;
1365 if (segment_half <= 0) {
1366 return;
1367 }
1368 const size_t head_stride = (size_t)num_tokens * (size_t)aligned_head_dim;
1369 const float theta_scale = powf(freq_base, -2.0f / (float)half_span);
1370
1371 for (int h = 0; h < num_heads; ++h) {
1372 float *head = x + (size_t)h * head_stride;
1373 for (int t = 0; t < num_tokens; ++t) {
1374 const int pos_x = t % grid_w;
1375 const int pos_y = t / grid_w;
1376 float *row = head + (size_t)t * (size_t)aligned_head_dim;
1377 for (int i = 0; i < segment_half; ++i) {
1378 const float inv_freq = powf(theta_scale, (float)i);
1379
1380 const float theta_x = (float)pos_x * inv_freq;
1381 const float cx = cosf(theta_x);
1382 const float sx = sinf(theta_x);
1383 const int x0i = i;
1384 const int x1i = i + segment_half;
1385 const float x0 = row[x0i];
1386 const float x1 = row[x1i];
1387 row[x0i] = x0 * cx - x1 * sx;
1388 row[x1i] = x1 * cx + x0 * sx;
1389
1390 const float theta_y = (float)pos_y * inv_freq;
1391 const float cy = cosf(theta_y);
1392 const float sy = sinf(theta_y);
1393 const int y0i = half_span + i;
1394 const int y1i = half_span + i + segment_half;
1395 const float y0 = row[y0i];
1396 const float y1 = row[y1i];
1397 row[y0i] = y0 * cy - y1 * sy;
1398 row[y1i] = y1 * cy + y0 * sy;
1399 }
1400 }
1401 }
1402}
1403
1405 float *k,
1406 int num_heads,
1407 int num_kv_heads,
1408 int num_tokens,
1409 int head_dim,
1410 int aligned_head_dim,
1411 int grid_w,
1412 int rotary_dim,
1413 float freq_base)
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}
1418
1420 float *k,
1421 const float *cos_cache,
1422 const float *sin_cache,
1423 int num_heads,
1424 int num_kv_heads,
1425 int num_tokens,
1426 int head_dim,
1427 int aligned_head_dim,
1428 int pos_offset,
1429 int rotary_dim,
1430 int cache_rotary_dim)
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}
1482
1484 float *k,
1485 const float *cos_cache,
1486 const float *sin_cache,
1487 int num_heads,
1488 int num_kv_heads,
1489 int num_tokens,
1490 int head_dim,
1491 int aligned_head_dim,
1492 int pos_offset,
1493 int rotary_dim)
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}
1510
1511/*
1512 * Preserve ggml's per-row pairwise loop as a separate numerical provider.
1513 * Keeping the row loop out of the combined Q/K function prevents whole-loop
1514 * vectorization from changing FP32 contraction at decode shapes.
1515 */
1516#if defined(__GNUC__) || defined(__clang__)
1517__attribute__((noinline))
1518#endif
1520 const float *cos_row,
1521 const float *sin_row,
1522 int num_heads,
1523 int aligned_head_dim,
1524 int rotary_dim)
1525{
1526 for (int head = 0; head < num_heads; ++head) {
1527 float *row = rows + (size_t)head * (size_t)aligned_head_dim;
1528 for (int i = 0; i < rotary_dim; i += 2) {
1529 const int pair = i / 2;
1530 const float x0 = row[i];
1531 const float x1 = row[i + 1];
1532 const float cosine = cos_row[pair];
1533 const float sine = sin_row[pair];
1534 row[i] = fmaf(x0, cosine, -x1 * sine);
1535 row[i + 1] = fmaf(x0, sine, x1 * cosine);
1536 }
1537 }
1538}
1539
1541 float *k,
1542 const float *cos_cache,
1543 const float *sin_cache,
1544 int num_heads,
1545 int num_kv_heads,
1546 int num_tokens,
1547 int head_dim,
1548 int aligned_head_dim,
1549 int pos_offset,
1550 int rotary_dim)
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}
1600
1601static float vision_mrope_yarn_corr_dim(int n_dims, int n_ctx_orig, float n_rot, float base) {
1602 return n_dims * logf((float) n_ctx_orig / (n_rot * 2.0f * (float) M_PI)) / (2.0f * logf(base));
1603}
1604
1606 int n_dims,
1607 int n_ctx_orig,
1608 float freq_base,
1609 float beta_fast,
1610 float beta_slow,
1611 float dims[2]
1612) {
1613 float start = floorf(vision_mrope_yarn_corr_dim(n_dims, n_ctx_orig, beta_fast, freq_base));
1614 float end = ceilf(vision_mrope_yarn_corr_dim(n_dims, n_ctx_orig, beta_slow, freq_base));
1615 dims[0] = start < 0.0f ? 0.0f : start;
1616 dims[1] = end > (float) (n_dims - 1) ? (float) (n_dims - 1) : end;
1617}
1618
1619static float vision_mrope_yarn_ramp(float low, float high, int chan) {
1620 const float y = ((float) chan - low) / fmaxf(0.001f, high - low);
1621 return 1.0f - fminf(1.0f, fmaxf(0.0f, y));
1622}
1623
1625 float theta_extrap,
1626 float freq_scale,
1627 const float corr_dims[2],
1628 int chan,
1629 float ext_factor,
1630 float attn_factor,
1631 float *cos_theta,
1632 float *sin_theta
1633) {
1634 float theta_interp = freq_scale * theta_extrap;
1635 float theta = theta_interp;
1636 float mscale = attn_factor;
1637
1638 if (ext_factor != 0.0f) {
1639 const float ramp_mix = vision_mrope_yarn_ramp(corr_dims[0], corr_dims[1], chan) * ext_factor;
1640 theta = theta_interp * (1.0f - ramp_mix) + theta_extrap * ramp_mix;
1641 mscale *= 1.0f + 0.1f * logf(1.0f / fmaxf(freq_scale, 1e-6f));
1642 }
1643
1644 *cos_theta = ck_rope_reference_cosf(theta) * mscale;
1645 *sin_theta = ck_rope_reference_sinf(theta) * mscale;
1646}
1647
1649 float theta_extrap,
1650 float freq_scale,
1651 const float corr_dims[2],
1652 int chan,
1653 float ext_factor,
1654 float attn_factor,
1655 float *cos_theta,
1656 float *sin_theta
1657) {
1658 float theta_interp = freq_scale * theta_extrap;
1659 float theta = theta_interp;
1660 float mscale = attn_factor;
1661
1662 if (ext_factor != 0.0f) {
1663 const float ramp_mix =
1664 vision_mrope_yarn_ramp(corr_dims[0], corr_dims[1], chan) * ext_factor;
1665 theta = theta_interp * (1.0f - ramp_mix) + theta_extrap * ramp_mix;
1666 mscale *= 1.0f + 0.1f * logf(1.0f / fmaxf(freq_scale, 1e-6f));
1667 }
1668
1669 *cos_theta = ck_rope_reference_cosf(theta) * mscale;
1670 *sin_theta = ck_rope_reference_sinf(theta) * mscale;
1671}
1672
1673static inline void mrope_rotate_pair(
1674 float x0,
1675 float x1,
1676 float cos_theta,
1677 float sin_theta,
1678 float *out0,
1679 float *out1
1680) {
1681 const float x1_sin = x1 * sin_theta;
1682 const float x1_cos = x1 * cos_theta;
1683 *out0 = fmaf(x0, cos_theta, -x1_sin);
1684 *out1 = fmaf(x0, sin_theta, x1_cos);
1685}
1686
1688 float *x,
1689 const int32_t *positions,
1690 int num_tokens,
1691 int head_dim,
1692 int aligned_head_dim,
1693 int n_dims,
1694 const int sections[4],
1695 int n_ctx_orig,
1696 float freq_base,
1697 float freq_scale,
1698 float ext_factor,
1699 float attn_factor,
1700 float beta_fast,
1701 float beta_slow
1702) {
1703 if (!x || !positions || num_tokens <= 0 || head_dim <= 0 || aligned_head_dim < head_dim || n_dims <= 0) {
1704 return;
1705 }
1706
1707 int rotary_width = n_dims;
1708 if (rotary_width > head_dim) {
1709 rotary_width = head_dim;
1710 }
1711 if (rotary_width <= 0 || (rotary_width & 1) != 0 || rotary_width > aligned_head_dim) {
1712 return;
1713 }
1714 const int rope_pairs = rotary_width / 2;
1715
1716 const int axis_y_pairs = sections[0];
1717 const int axis_x_pairs = sections[1];
1718 if (axis_y_pairs <= 0 || axis_x_pairs <= 0 || axis_y_pairs + axis_x_pairs > rope_pairs) {
1719 return;
1720 }
1721
1722 const int num_pos = num_tokens;
1723 const float theta_scale = ck_rope_reference_powf(freq_base, -2.0f / (float) rope_pairs);
1724 float corr_dims[2] = {0.0f, (float) (rope_pairs - 1)};
1725 vision_mrope_yarn_corr_dims(rope_pairs, n_ctx_orig, freq_base, beta_fast, beta_slow, corr_dims);
1726
1727 for (int tok = 0; tok < num_tokens; ++tok) {
1728 float theta_y = (float) positions[tok];
1729 float theta_x = (float) positions[tok + num_pos];
1730 float *row = x + (size_t) tok * (size_t) aligned_head_dim;
1731
1732 for (int pair = 0; pair < rope_pairs; ++pair) {
1733 const int is_x_axis = pair >= axis_y_pairs && pair < axis_y_pairs + axis_x_pairs;
1734 if (pair == axis_y_pairs) {
1735 theta_x = (float) positions[tok + num_pos];
1736 }
1737 const float theta = is_x_axis ? theta_x : theta_y;
1738
1739 float cos_theta = 0.0f;
1740 float sin_theta = 0.0f;
1742 theta,
1743 freq_scale,
1744 corr_dims,
1745 pair * 2,
1746 ext_factor,
1747 attn_factor,
1748 &cos_theta,
1749 &sin_theta
1750 );
1751
1752 const float x0 = row[pair];
1753 const float x1 = row[pair + rope_pairs];
1755 x0,
1756 x1,
1757 cos_theta,
1758 sin_theta,
1759 &row[pair],
1760 &row[pair + rope_pairs]
1761 );
1762
1763 theta_y *= theta_scale;
1764 theta_x *= theta_scale;
1765 }
1766 }
1767}
1768
1769/* Match transformers Qwen3VLVisionRotaryEmbedding and
1770 * apply_rotary_pos_emb_vision. The reference materializes every FP32
1771 * inv_freq independently and rounds the two products before addition. */
1772#ifdef USE_MKL
1773static void vision_mrope_apply_pytorch_bf16(
1774 float *x,
1775 const int32_t *positions,
1776 int num_heads,
1777 int num_tokens,
1778 int head_dim,
1779 int aligned_head_dim,
1780 int n_dims,
1781 const int sections[4],
1782 float freq_base,
1783 float freq_scale
1784) {
1785 if (!x || !positions || num_heads <= 0 || num_tokens <= 0 || head_dim <= 0 ||
1786 aligned_head_dim < head_dim || n_dims <= 0) {
1787 return;
1788 }
1789
1790 const int rotary_width = n_dims < head_dim ? n_dims : head_dim;
1791 if ((rotary_width & 1) != 0 || rotary_width <= 0) {
1792 return;
1793 }
1794 const int rope_pairs = rotary_width / 2;
1795 const int axis_pairs = sections[0];
1796 if (axis_pairs <= 0 || sections[1] != axis_pairs || axis_pairs * 2 != rope_pairs ||
1797 sections[2] != 0 || sections[3] != 0) {
1798 return;
1799 }
1800
1801 int max_pos = 0;
1802 for (int tok = 0; tok < num_tokens; ++tok) {
1803 if (positions[tok] > max_pos) max_pos = positions[tok];
1804 if (positions[tok + num_tokens] > max_pos) max_pos = positions[tok + num_tokens];
1805 }
1806 if (max_pos < 0 || max_pos > 65535 || axis_pairs > 256) {
1807 return;
1808 }
1809
1810 float inv_freq[256];
1811 for (int i = 0; i < axis_pairs; ++i) {
1812 const float exponent = (2.0f * (float)i) / (float)rope_pairs;
1813 inv_freq[i] = 1.0f / ck_rope_reference_powf(freq_base, exponent);
1814 }
1815
1816 const size_t table_count = (size_t)(max_pos + 1) * (size_t)axis_pairs;
1817 float angles[table_count];
1818 float cos_table[table_count];
1819 float sin_table[table_count];
1820 for (int pos = 0; pos <= max_pos; ++pos) {
1821 for (int i = 0; i < axis_pairs; ++i) {
1822 angles[(size_t)pos * (size_t)axis_pairs + (size_t)i] =
1823 ((float)pos * inv_freq[i]) * freq_scale;
1824 }
1825 }
1826 vsCos((MKL_INT)table_count, angles, cos_table);
1827 vsSin((MKL_INT)table_count, angles, sin_table);
1828
1829 const size_t head_stride = (size_t)num_tokens * (size_t)aligned_head_dim;
1830 for (int h = 0; h < num_heads; ++h) {
1831 float *head = x + (size_t)h * head_stride;
1832 for (int tok = 0; tok < num_tokens; ++tok) {
1833 const int pos_y = positions[tok];
1834 const int pos_x = positions[tok + num_tokens];
1835 float *row = head + (size_t)tok * (size_t)aligned_head_dim;
1836 for (int pair = 0; pair < rope_pairs; ++pair) {
1837 const int local_pair = pair < axis_pairs ? pair : pair - axis_pairs;
1838 const int pos = pair < axis_pairs ? pos_y : pos_x;
1839 const size_t table_idx = (size_t)pos * (size_t)axis_pairs + (size_t)local_pair;
1840 const float cosine = cos_table[table_idx];
1841 const float sine = sin_table[table_idx];
1842 const float x0 = row[pair];
1843 const float x1 = row[pair + rope_pairs];
1844
1845 volatile float x0_cos = x0 * cosine;
1846 volatile float x1_sin = x1 * sine;
1847 volatile float x0_sin = x0 * sine;
1848 volatile float x1_cos = x1 * cosine;
1849 row[pair] = bf16_to_float(float_to_bf16(x0_cos - x1_sin));
1850 row[pair + rope_pairs] = bf16_to_float(float_to_bf16(x0_sin + x1_cos));
1851 }
1852 }
1853 }
1854}
1855#endif
1856
1858 float *x,
1859 const int32_t *positions,
1860 int num_heads,
1861 int num_tokens,
1862 int head_dim,
1863 int aligned_head_dim,
1864 int n_dims,
1865 const int sections[4],
1866 int n_ctx_orig,
1867 float freq_base,
1868 float freq_scale,
1869 float ext_factor,
1870 float attn_factor,
1871 float beta_fast,
1872 float beta_slow,
1873 int rope_type
1874) {
1875 ck_ggml_cpu_init_fn ggml_cpu_init_fn = ck_resolve_ggml_cpu_init();
1876 ck_ggml_init_fn ggml_init_fn = ck_resolve_ggml_init();
1877 ck_ggml_free_fn ggml_free_fn = ck_resolve_ggml_free();
1879 ck_ggml_view_3d_fn ggml_view_3d_fn = ck_resolve_ggml_view_3d();
1881 ck_ggml_new_graph_fn ggml_new_graph_fn = ck_resolve_ggml_new_graph();
1884 ck_ggml_get_data_fn ggml_get_data_fn = ck_resolve_ggml_get_data();
1885
1886 if (!x || !positions || num_heads <= 0 || num_tokens <= 0 || head_dim <= 0 || aligned_head_dim < head_dim) {
1887 return 0;
1888 }
1889 if (!ggml_cpu_init_fn || !ggml_init_fn || !ggml_free_fn || !ggml_new_tensor_1d_fn ||
1890 !ggml_view_3d_fn || !ggml_rope_multi_inplace_fn || !ggml_new_graph_fn ||
1891 !ggml_build_forward_expand_fn || !ggml_graph_compute_with_ctx_fn || !ggml_get_data_fn) {
1892 return 0;
1893 }
1894
1895 ggml_cpu_init_fn();
1896
1897 const size_t row_bytes = (size_t) aligned_head_dim * sizeof(float);
1898 const size_t head_bytes = (size_t) num_tokens * row_bytes;
1899 const int64_t total_elems = (int64_t) num_heads * (int64_t) num_tokens * (int64_t) aligned_head_dim;
1900 const size_t mem_size =
1901 (size_t) 16 * 1024 * 1024 +
1902 (size_t) total_elems * sizeof(float) +
1903 (size_t) 4 * (size_t) num_tokens * sizeof(int32_t);
1904
1905 struct ggml_init_params params = {
1906 .mem_size = mem_size,
1907 .mem_buffer = NULL,
1908 .no_alloc = false,
1909 };
1910 struct ggml_context *ctx = ggml_init_fn(params);
1911 if (!ctx) {
1912 return 0;
1913 }
1914
1915 int ok = 0;
1916 struct ggml_tensor *x_base = ggml_new_tensor_1d_fn(ctx, GGML_TYPE_F32, total_elems);
1917 struct ggml_tensor *pos_base = ggml_new_tensor_1d_fn(ctx, GGML_TYPE_I32, (int64_t) 4 * (int64_t) num_tokens);
1918 if (!x_base || !pos_base) {
1919 ggml_free_fn(ctx);
1920 return 0;
1921 }
1922
1923 void *x_base_data = ggml_get_data_fn(x_base);
1924 void *pos_base_data = ggml_get_data_fn(pos_base);
1925 if (!x_base_data || !pos_base_data) {
1926 ggml_free_fn(ctx);
1927 return 0;
1928 }
1929
1930 memcpy(x_base_data, x, (size_t) total_elems * sizeof(float));
1931 memcpy(pos_base_data, positions, (size_t) 4 * (size_t) num_tokens * sizeof(int32_t));
1932
1933 struct ggml_tensor *x_view = ggml_view_3d_fn(ctx,
1934 x_base,
1935 head_dim,
1936 num_heads,
1937 num_tokens,
1938 head_bytes,
1939 row_bytes,
1940 0);
1941 if (!x_view) {
1942 ggml_free_fn(ctx);
1943 return 0;
1944 }
1945
1946 int ggml_sections[GGML_MROPE_SECTIONS] = {
1947 sections[0], sections[1], sections[2], sections[3]
1948 };
1949 /* CK's vision contract names the full rotary width. ggml's VISION mode
1950 * names the split-half stride (the number of frequency pairs). Keep this
1951 * unit conversion inside the oracle adapter so production kernels and IR
1952 * continue to carry the canonical full-width value. */
1953 const int ggml_n_dims = rope_type == GGML_ROPE_TYPE_VISION ? n_dims / 2 : n_dims;
1954 if (ggml_n_dims <= 0 || (rope_type == GGML_ROPE_TYPE_VISION && (n_dims & 1) != 0)) {
1955 ggml_free_fn(ctx);
1956 return 0;
1957 }
1958 struct ggml_tensor *rope = ggml_rope_multi_inplace_fn(ctx,
1959 x_view,
1960 pos_base,
1961 NULL,
1962 ggml_n_dims,
1963 ggml_sections,
1964 rope_type,
1965 n_ctx_orig,
1966 freq_base,
1967 freq_scale,
1968 ext_factor,
1969 attn_factor,
1970 beta_fast,
1971 beta_slow);
1972 if (!rope) {
1973 ggml_free_fn(ctx);
1974 return 0;
1975 }
1976
1977 struct ggml_cgraph *gf = ggml_new_graph_fn(ctx);
1978 if (!gf) {
1979 ggml_free_fn(ctx);
1980 return 0;
1981 }
1982 ggml_build_forward_expand_fn(gf, rope);
1983 if (ggml_graph_compute_with_ctx_fn(ctx, gf, 1) != GGML_STATUS_SUCCESS) {
1984 ggml_free_fn(ctx);
1985 return 0;
1986 }
1987
1988 memcpy(x, x_base_data, (size_t) total_elems * sizeof(float));
1989 ok = 1;
1990 ggml_free_fn(ctx);
1991 return ok;
1992}
1993
1995 float *x,
1996 const int32_t *positions,
1997 int num_tokens,
1998 int head_dim,
1999 int aligned_head_dim,
2000 int n_dims,
2001 const int sections[4],
2002 int n_ctx_orig,
2003 float freq_base,
2004 float freq_scale,
2005 float ext_factor,
2006 float attn_factor,
2007 float beta_fast,
2008 float beta_slow,
2009 int is_imrope
2010) {
2011 if (!x || !positions || num_tokens <= 0 || head_dim <= 0 || aligned_head_dim < head_dim || n_dims <= 0) {
2012 return;
2013 }
2014
2015 int rope_dims = n_dims;
2016 if (rope_dims > head_dim) {
2017 rope_dims = head_dim;
2018 }
2019 rope_dims &= ~1;
2020 if (rope_dims <= 0) {
2021 return;
2022 }
2023 const int rope_pairs = rope_dims / 2;
2024
2025 const int num_pos = num_tokens;
2026 const int sec_w = sections[0] + sections[1];
2027 const int sec_e = sec_w + sections[2];
2028 const int sect_dims = sections[0] + sections[1] + sections[2] + sections[3];
2029 const float theta_scale =
2030 ck_rope_reference_powf(freq_base, -2.0f / (float) rope_dims);
2031 float corr_dims[2] = {0.0f, (float) (rope_dims - 1)};
2032 vision_mrope_yarn_corr_dims(rope_dims, n_ctx_orig, freq_base, beta_fast, beta_slow, corr_dims);
2033
2034 for (int tok = 0; tok < num_tokens; ++tok) {
2035 float theta_t = (float) positions[tok];
2036 float theta_h = (float) positions[tok + num_pos];
2037 float theta_w = (float) positions[tok + 2 * num_pos];
2038 float theta_e = (float) positions[tok + 3 * num_pos];
2039 float *row = x + (size_t) tok * (size_t) aligned_head_dim;
2040
2041 for (int pair = 0; pair < rope_pairs; ++pair) {
2042 const int sector = sect_dims > 0 ? (pair % sect_dims) : pair;
2043 if (!is_imrope) {
2044 if (sector == 0) {
2045 theta_t = (float) positions[tok];
2046 } else if (sector == sections[0]) {
2047 theta_h = (float) positions[tok + num_pos];
2048 } else if (sector == sec_w) {
2049 theta_w = (float) positions[tok + 2 * num_pos];
2050 } else if (sector == sec_e) {
2051 theta_e = (float) positions[tok + 3 * num_pos];
2052 }
2053 }
2054
2055 float theta = theta_t;
2056 if (is_imrope) {
2057 if (sector % 3 == 1 && sector < 3 * sections[1]) {
2058 theta = theta_h;
2059 } else if (sector % 3 == 2 && sector < 3 * sections[2]) {
2060 theta = theta_w;
2061 } else if (sector % 3 == 0 && sector < 3 * sections[0]) {
2062 theta = theta_t;
2063 } else {
2064 theta = theta_e;
2065 }
2066 } else if (sector >= sections[0] && sector < sec_w) {
2067 theta = theta_h;
2068 } else if (sector >= sec_w && sector < sec_e) {
2069 theta = theta_w;
2070 } else if (sector >= sec_e) {
2071 theta = theta_e;
2072 }
2073
2074 float cos_theta = 0.0f;
2075 float sin_theta = 0.0f;
2077 theta,
2078 freq_scale,
2079 corr_dims,
2080 pair * 2,
2081 ext_factor,
2082 attn_factor,
2083 &cos_theta,
2084 &sin_theta
2085 );
2086
2087 const float x0 = row[pair];
2088 const float x1 = row[pair + rope_pairs];
2090 x0,
2091 x1,
2092 cos_theta,
2093 sin_theta,
2094 &row[pair],
2095 &row[pair + rope_pairs]
2096 );
2097
2098 theta_t *= theta_scale;
2099 theta_h *= theta_scale;
2100 theta_w *= theta_scale;
2101 theta_e *= theta_scale;
2102 }
2103 }
2104}
2105
2107 float *x,
2108 int num_tokens,
2109 int head_dim,
2110 int aligned_head_dim,
2111 int pos_offset,
2112 int n_dims,
2113 const int sections[4],
2114 int n_ctx_orig,
2115 float freq_base,
2116 float freq_scale,
2117 float ext_factor,
2118 float attn_factor,
2119 float beta_fast,
2120 float beta_slow,
2121 int is_imrope
2122) {
2123 if (!x || num_tokens <= 0 || head_dim <= 0 || aligned_head_dim < head_dim || n_dims <= 0) {
2124 return;
2125 }
2126
2127 int rope_dims = n_dims;
2128 if (rope_dims > head_dim) {
2129 rope_dims = head_dim;
2130 }
2131 rope_dims &= ~1;
2132 if (rope_dims <= 0) {
2133 return;
2134 }
2135 const int rope_pairs = rope_dims / 2;
2136
2137 const int sec_w = sections[0] + sections[1];
2138 const int sec_e = sec_w + sections[2];
2139 const int sect_dims = sections[0] + sections[1] + sections[2] + sections[3];
2140 const float theta_scale = powf(freq_base, -2.0f / (float) rope_dims);
2141 float corr_dims[2] = {0.0f, (float) (rope_dims - 1)};
2142 vision_mrope_yarn_corr_dims(rope_dims, n_ctx_orig, freq_base, beta_fast, beta_slow, corr_dims);
2143
2144 for (int tok = 0; tok < num_tokens; ++tok) {
2145 const float base_pos = (float) (pos_offset + tok);
2146 float theta_t = base_pos;
2147 float theta_h = base_pos;
2148 float theta_w = base_pos;
2149 float theta_e = 0.0f;
2150 float *row = x + (size_t) tok * (size_t) aligned_head_dim;
2151
2152 for (int pair = 0; pair < rope_pairs; ++pair) {
2153 const int sector = sect_dims > 0 ? (pair % sect_dims) : pair;
2154 float theta = theta_t;
2155 if (is_imrope && sector % 3 == 1 && sector < 3 * sections[1]) {
2156 theta = theta_h;
2157 } else if (is_imrope && sector % 3 == 2 && sector < 3 * sections[2]) {
2158 theta = theta_w;
2159 } else if (is_imrope && sector % 3 == 0 && sector < 3 * sections[0]) {
2160 theta = theta_t;
2161 } else if (is_imrope) {
2162 theta = theta_e;
2163 } else if (sector >= sections[0] && sector < sec_w) {
2164 theta = theta_h;
2165 } else if (sector >= sec_w && sector < sec_e) {
2166 theta = theta_w;
2167 } else if (sector >= sec_e) {
2168 theta = theta_e;
2169 }
2170
2171 float cos_theta = 0.0f;
2172 float sin_theta = 0.0f;
2174 theta,
2175 freq_scale,
2176 corr_dims,
2177 pair * 2,
2178 ext_factor,
2179 attn_factor,
2180 &cos_theta,
2181 &sin_theta
2182 );
2183
2184 const float x0 = row[pair];
2185 const float x1 = row[pair + rope_pairs];
2187 x0,
2188 x1,
2189 cos_theta,
2190 sin_theta,
2191 &row[pair],
2192 &row[pair + rope_pairs]
2193 );
2194
2195 theta_t *= theta_scale;
2196 theta_h *= theta_scale;
2197 theta_w *= theta_scale;
2198 theta_e *= theta_scale;
2199 }
2200 }
2201}
2202
2203void mrope_qk_text(float *q,
2204 float *k,
2205 int num_heads,
2206 int num_kv_heads,
2207 int num_tokens,
2208 int head_dim,
2209 int aligned_head_dim,
2210 int pos_offset,
2211 int n_dims,
2212 int section_0,
2213 int section_1,
2214 int section_2,
2215 int section_3,
2216 int n_ctx_orig,
2217 float freq_base,
2218 float freq_scale,
2219 float ext_factor,
2220 float attn_factor,
2221 float beta_fast,
2222 float beta_slow)
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}
2272
2274 float *k,
2275 int num_heads,
2276 int num_kv_heads,
2277 int num_tokens,
2278 int head_dim,
2279 int aligned_head_dim,
2280 int pos_offset,
2281 int n_dims,
2282 int section_0,
2283 int section_1,
2284 int section_2,
2285 int section_3,
2286 int n_ctx_orig,
2287 float freq_base,
2288 float freq_scale,
2289 float ext_factor,
2290 float attn_factor,
2291 float beta_fast,
2292 float beta_slow)
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}
2342
2344 int num_heads,
2345 int num_tokens,
2346 int head_dim,
2347 int aligned_head_dim,
2348 int pos_offset,
2349 int n_dims,
2350 float freq_base,
2351 float freq_scale)
2352{
2353 if (!x || num_heads <= 0 || num_tokens <= 0 || head_dim <= 0 ||
2354 aligned_head_dim < head_dim || n_dims <= 0) {
2355 return;
2356 }
2357 int rope_dims = n_dims < head_dim ? n_dims : head_dim;
2358 rope_dims &= ~1;
2359 if (rope_dims <= 0) return;
2360 const int pairs = rope_dims / 2;
2361 const size_t head_stride = (size_t)num_tokens * (size_t)aligned_head_dim;
2362
2363 for (int h = 0; h < num_heads; ++h) {
2364 float *head = x + (size_t)h * head_stride;
2365 for (int tok = 0; tok < num_tokens; ++tok) {
2366 float *row = head + (size_t)tok * (size_t)aligned_head_dim;
2367 const float position = (float)(pos_offset + tok);
2368 for (int pair = 0; pair < pairs; ++pair) {
2369 const float exponent = (2.0f * (float)pair) / (float)rope_dims;
2370 const float inv_freq = 1.0f / ck_rope_reference_powf(freq_base, exponent);
2371 const float angle = (position * inv_freq) * freq_scale;
2372 const float cosine = bf16_to_float(float_to_bf16(ck_rope_reference_cosf(angle)));
2373 const float sine = bf16_to_float(float_to_bf16(ck_rope_reference_sinf(angle)));
2374 const float x0 = row[pair];
2375 const float x1 = row[pair + pairs];
2376
2377 volatile uint16_t x0_cos_bits = float_to_bf16(x0 * cosine);
2378 volatile uint16_t x1_sin_bits = float_to_bf16((-x1) * sine);
2379 volatile uint16_t x1_cos_bits = float_to_bf16(x1 * cosine);
2380 volatile uint16_t x0_sin_bits = float_to_bf16(x0 * sine);
2381 const float x0_cos = bf16_to_float(x0_cos_bits);
2382 const float x1_sin = bf16_to_float(x1_sin_bits);
2383 const float x1_cos = bf16_to_float(x1_cos_bits);
2384 const float x0_sin = bf16_to_float(x0_sin_bits);
2385 volatile uint16_t out0_bits = float_to_bf16(x0_cos + x1_sin);
2386 volatile uint16_t out1_bits = float_to_bf16(x1_cos + x0_sin);
2387 row[pair] = bf16_to_float(out0_bits);
2388 row[pair + pairs] = bf16_to_float(out1_bits);
2389 }
2390 }
2391 }
2392}
2393
2394#if defined(__clang__)
2395#pragma float_control(precise, on, push)
2396#endif
2398 float *x,
2399 const int32_t *positions,
2400 int num_heads,
2401 int num_tokens,
2402 int head_dim,
2403 int aligned_head_dim,
2404 int n_dims,
2405 const int sections[4],
2406 float freq_base,
2407 float freq_scale)
2408{
2409 if (!x || !positions || num_heads <= 0 || num_tokens <= 0 || head_dim <= 0 ||
2410 aligned_head_dim < head_dim || n_dims <= 0) {
2411 return;
2412 }
2413 int rope_dims = n_dims < head_dim ? n_dims : head_dim;
2414 rope_dims &= ~1;
2415 if (rope_dims <= 0) return;
2416 const int pairs = rope_dims / 2;
2417 if (sections[0] <= 0 || sections[1] < 0 || sections[2] < 0 ||
2418 sections[3] != 0 || sections[0] + sections[1] + sections[2] != pairs) {
2419 return;
2420 }
2421 const size_t head_stride = (size_t)num_tokens * (size_t)aligned_head_dim;
2422
2423 for (int h = 0; h < num_heads; ++h) {
2424 float *head = x + (size_t)h * head_stride;
2425 for (int tok = 0; tok < num_tokens; ++tok) {
2426 float *row = head + (size_t)tok * (size_t)aligned_head_dim;
2427 for (int pair = 0; pair < pairs; ++pair) {
2428 int axis = 0;
2429 if (pair < sections[1] * 3 && pair % 3 == 1) axis = 1;
2430 if (pair < sections[2] * 3 && pair % 3 == 2) axis = 2;
2431 const float position = (float)positions[(size_t)axis * (size_t)num_tokens + (size_t)tok];
2432 const float exponent = (2.0f * (float)pair) / (float)rope_dims;
2433 const float inv_freq = 1.0f / ck_rope_reference_powf(freq_base, exponent);
2434 const float angle = (position * inv_freq) * freq_scale;
2435 const float cosine = bf16_to_float(float_to_bf16(ck_rope_reference_cosf(angle)));
2436 const float sine = bf16_to_float(float_to_bf16(ck_rope_reference_sinf(angle)));
2437 const float x0 = row[pair];
2438 const float x1 = row[pair + pairs];
2439
2440 volatile uint16_t x0_cos_bits = float_to_bf16(x0 * cosine);
2441 volatile uint16_t x1_sin_bits = float_to_bf16((-x1) * sine);
2442 volatile uint16_t x1_cos_bits = float_to_bf16(x1 * cosine);
2443 volatile uint16_t x0_sin_bits = float_to_bf16(x0 * sine);
2444 const float x0_cos = bf16_to_float(x0_cos_bits);
2445 const float x1_sin = bf16_to_float(x1_sin_bits);
2446 const float x1_cos = bf16_to_float(x1_cos_bits);
2447 const float x0_sin = bf16_to_float(x0_sin_bits);
2448 volatile uint16_t out0_bits = float_to_bf16(x0_cos + x1_sin);
2449 volatile uint16_t out1_bits = float_to_bf16(x1_cos + x0_sin);
2450 row[pair] = bf16_to_float(out0_bits);
2451 row[pair + pairs] = bf16_to_float(out1_bits);
2452 }
2453 }
2454 }
2455}
2456#if defined(__clang__)
2457#pragma float_control(pop)
2458#endif
2459
2461 float *q,
2462 float *k,
2463 const int32_t *positions,
2464 int num_heads,
2465 int num_kv_heads,
2466 int num_tokens,
2467 int head_dim,
2468 int aligned_head_dim,
2469 int n_dims,
2470 int section_0,
2471 int section_1,
2472 int section_2,
2473 int section_3,
2474 int n_ctx_orig,
2475 float freq_base,
2476 float freq_scale,
2477 float ext_factor,
2478 float attn_factor,
2479 float beta_fast,
2480 float beta_slow)
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}
2495
2497 float *k,
2498 int num_heads,
2499 int num_kv_heads,
2500 int num_tokens,
2501 int head_dim,
2502 int aligned_head_dim,
2503 int pos_offset,
2504 int n_dims,
2505 int section_0,
2506 int section_1,
2507 int section_2,
2508 int section_3,
2509 int n_ctx_orig,
2510 float freq_base,
2511 float freq_scale,
2512 float ext_factor,
2513 float attn_factor,
2514 float beta_fast,
2515 float beta_slow)
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}
2533
2534void mrope_qk_vision(float *q,
2535 float *k,
2536 const int32_t *positions,
2537 int num_heads,
2538 int num_kv_heads,
2539 int num_tokens,
2540 int head_dim,
2541 int aligned_head_dim,
2542 int n_dims,
2543 int section_0,
2544 int section_1,
2545 int section_2,
2546 int section_3,
2547 int n_ctx_orig,
2548 float freq_base,
2549 float freq_scale,
2550 float ext_factor,
2551 float attn_factor,
2552 float beta_fast,
2553 float beta_slow)
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}
2613
2614
2615static void ck_mrope_round_storage(float *data, size_t count, int storage_kind)
2616{
2617 if (!data) return;
2618 for (size_t i = 0; i < count; ++i) {
2619 if (storage_kind == 1) {
2620 data[i] = bf16_to_float(float_to_bf16(data[i]));
2621 } else if (storage_kind == 2) {
2622 data[i] = ck_fp16_to_fp32(ck_fp32_to_fp16(data[i]));
2623 }
2624 }
2625}
2626
2627#define CK_DEFINE_MROPE_STORAGE_WRAPPER(NAME, STORAGE_KIND) \
2628void NAME(float *q, float *k, const int32_t *positions, \
2629 int num_heads, int num_kv_heads, int num_tokens, \
2630 int head_dim, int aligned_head_dim, int n_dims, \
2631 int section_0, int section_1, int section_2, int section_3, \
2632 int n_ctx_orig, float freq_base, float freq_scale, \
2633 float ext_factor, float attn_factor, float beta_fast, float beta_slow) \
2634{ \
2635 mrope_qk_vision(q, k, positions, num_heads, num_kv_heads, num_tokens, \
2636 head_dim, aligned_head_dim, n_dims, section_0, section_1, \
2637 section_2, section_3, n_ctx_orig, freq_base, freq_scale, \
2638 ext_factor, attn_factor, beta_fast, beta_slow); \
2639 const size_t q_count = (size_t) num_heads * (size_t) num_tokens * (size_t) aligned_head_dim; \
2640 const size_t k_count = (size_t) num_kv_heads * (size_t) num_tokens * (size_t) aligned_head_dim; \
2641 ck_mrope_round_storage(q, q_count, STORAGE_KIND); \
2642 ck_mrope_round_storage(k, k_count, STORAGE_KIND); \
2643}
2644
2647
2648#ifdef USE_MKL
2650 float *k,
2651 const int32_t *positions,
2652 int num_heads,
2653 int num_kv_heads,
2654 int num_tokens,
2655 int head_dim,
2656 int aligned_head_dim,
2657 int n_dims,
2658 int section_0,
2659 int section_1,
2660 int section_2,
2661 int section_3,
2662 int n_ctx_orig,
2663 float freq_base,
2664 float freq_scale,
2665 float ext_factor,
2666 float attn_factor,
2667 float beta_fast,
2668 float beta_slow)
2669{
2670 (void)n_ctx_orig;
2671 (void)ext_factor;
2672 (void)attn_factor;
2673 (void)beta_fast;
2674 (void)beta_slow;
2675 if (!q || !k || !positions || num_heads <= 0 || num_kv_heads <= 0 || num_tokens <= 0) {
2676 return;
2677 }
2678 const int sections[4] = {section_0, section_1, section_2, section_3};
2679 vision_mrope_apply_pytorch_bf16(q, positions, num_heads, num_tokens, head_dim,
2680 aligned_head_dim, n_dims, sections, freq_base, freq_scale);
2681 vision_mrope_apply_pytorch_bf16(k, positions, num_kv_heads, num_tokens, head_dim,
2682 aligned_head_dim, n_dims, sections, freq_base, freq_scale);
2683}
2684#endif
2685
2687 float *k,
2688 const int32_t *positions,
2689 int num_heads,
2690 int num_kv_heads,
2691 int num_tokens,
2692 int head_dim,
2693 int aligned_head_dim,
2694 int n_dims,
2695 int section_0,
2696 int section_1,
2697 int section_2,
2698 int section_3,
2699 int n_ctx_orig,
2700 float freq_base,
2701 float freq_scale,
2702 float ext_factor,
2703 float attn_factor,
2704 float beta_fast,
2705 float beta_slow)
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}
2768
2769/**
2770 * RoPE forward for both Q and K with custom strides (KV cache layouts)
2771 * @test test_rope.py::TestRoPEForward::test_rope_forward_qk_strided
2772 * @test test_kv_cache_attention.py::TestKVCacheAttention::test_qk_rope_strided
2773 *
2774 * Combined QK RoPE with configurable strides for KV cache layouts.
2775 *
2776 * After changes: make test
2777 */
2779 float *k,
2780 const float *cos_cache,
2781 const float *sin_cache,
2782 int num_heads,
2783 int num_kv_heads,
2784 int num_tokens,
2785 int head_dim,
2786 int aligned_head_dim,
2787 int pos_offset,
2788 int q_stride_tokens,
2789 int k_stride_tokens)
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}
2795
2797 float *k,
2798 const float *cos_cache,
2799 const float *sin_cache,
2800 int num_heads,
2801 int num_kv_heads,
2802 int num_tokens,
2803 int head_dim,
2804 int aligned_head_dim,
2805 int pos_offset,
2806 int q_stride_tokens,
2807 int k_stride_tokens,
2808 int rotary_dim)
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}
2817
2818/**
2819 * RoPE backward for both dQ and dK
2820 * @test test_rope.py::TestRoPEBackward::test_rope_backward_qk
2821 *
2822 * Combined RoPE backward for both dQ and dK gradients.
2823 *
2824 * After changes: make test
2825 */
2826void rope_backward_qk(const float *d_q_out,
2827 const float *d_k_out,
2828 float *d_q,
2829 float *d_k,
2830 const float *cos_cache,
2831 const float *sin_cache,
2832 int num_heads,
2833 int num_kv_heads,
2834 int num_tokens,
2835 int head_dim,
2836 int aligned_head_dim,
2837 int pos_offset)
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}
2842
2844 const float *d_k_out,
2845 float *d_q,
2846 float *d_k,
2847 const float *cos_cache,
2848 const float *sin_cache,
2849 int num_heads,
2850 int num_kv_heads,
2851 int num_tokens,
2852 int head_dim,
2853 int aligned_head_dim,
2854 int pos_offset,
2855 int rotary_dim)
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}
2888
2889/* Build section-major 2-D multimodal RoPE positions for one mixed sequence.
2890 * Returns the resolved first text position after the visual prefix, or a
2891 * negative validation error. */
2893 int total_tokens,
2894 int prefix_start,
2895 int position_base,
2896 int prefix_tokens,
2897 int grid_x,
2898 int grid_y,
2899 int text_pos)
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}
#define RTLD_DEFAULT
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
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)
int ck_strict_parity_enabled(void)
Quantization block structures for weight-only quantization.
static ck_half ck_fp32_to_fp16(float f)
static float ck_fp16_to_fp32(ck_half h)
#define GGML_ROPE_TYPE_IMROPE
@ GGML_STATUS_SUCCESS
#define GGML_MROPE_SECTIONS
@ GGML_TYPE_F32
@ GGML_TYPE_I32
#define GGML_ROPE_TYPE_VISION
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)
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)
static ck_ggml_rope_multi_inplace_fn ck_resolve_ggml_rope_multi_inplace(void)
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(* ck_ggml_cpu_init_fn)(void)
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)
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)
struct ggml_tensor *(* ck_ggml_view_3d_fn)(struct ggml_context *, struct ggml_tensor *, int64_t, int64_t, int64_t, size_t, size_t, size_t)
struct ggml_cgraph *(* ck_ggml_new_graph_fn)(struct ggml_context *)
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)
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)
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)
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)
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)
static void ck_mrope_round_storage(float *data, size_t count, int storage_kind)
static ck_ggml_view_3d_fn ck_resolve_ggml_view_3d(void)
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)
#define CK_DEFINE_MROPE_STORAGE_WRAPPER(NAME, STORAGE_KIND)
float(* ck_rope_math_f32_binary_fn)(float, float)
static ck_ggml_new_tensor_1d_fn ck_resolve_ggml_new_tensor_1d(void)
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)
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)
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)
enum ggml_status(* ck_ggml_graph_compute_with_ctx_fn)(struct ggml_context *, struct ggml_cgraph *, int)
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 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_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_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)
static ck_ggml_build_forward_expand_fn ck_resolve_ggml_build_forward_expand(void)
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)
static ck_ggml_get_data_fn ck_resolve_ggml_get_data(void)
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)
static void ck_rope_ensure_ggml_loaded(void)
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)
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_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)
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)
void(* ck_ggml_free_fn)(struct ggml_context *)
static float ck_rope_reference_sinf(float value)
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)
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)
static float ck_rope_reference_powf(float base, float exponent)
void(* ck_ggml_build_forward_expand_fn)(struct ggml_cgraph *, struct ggml_tensor *)
static ck_ggml_graph_compute_with_ctx_fn ck_resolve_ggml_graph_compute_with_ctx(void)
static void * ck_rope_resolve_ggml_symbol(const char *name)
struct ggml_tensor *(* ck_ggml_rope_multi_inplace_fn)(struct ggml_context *, struct ggml_tensor *, struct ggml_tensor *, struct ggml_tensor *, int, int[4], int, int, float, float, float, float, float, float)
float(* ck_rope_math_f32_fn)(float)
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)
static ck_rope_math_f32_fn ck_rope_resolve_system_math_f32(const char *name)
static void vision_mrope_yarn(float theta_extrap, float freq_scale, const float corr_dims[2], int chan, float ext_factor, float attn_factor, float *cos_theta, float *sin_theta)
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 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 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_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)
static ck_ggml_new_graph_fn ck_resolve_ggml_new_graph(void)
static float ck_rope_reference_cosf(float value)
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)
static ck_ggml_free_fn ck_resolve_ggml_free(void)
static void vision_mrope_yarn_corr_dims(int n_dims, int n_ctx_orig, float freq_base, float beta_fast, float beta_slow, float dims[2])
struct ggml_tensor *(* ck_ggml_new_tensor_1d_fn)(struct ggml_context *, enum ggml_type, int64_t)
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)
static void text_mrope_yarn(float theta_extrap, float freq_scale, const float corr_dims[2], int chan, float ext_factor, float attn_factor, float *cos_theta, float *sin_theta)
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 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)
static float yarn_mscale(float factor, float scale)
struct ggml_context *(* ck_ggml_init_fn)(struct ggml_init_params)
static float vision_mrope_yarn_corr_dim(int n_dims, int n_ctx_orig, float n_rot, float base)
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 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_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)
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)
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)
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 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 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 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)
static float yarn_correction_dim(float rotations, int rotary_dim, float freq_base, int original_context)
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)
#define M_PI
void *(* ck_ggml_get_data_fn)(const struct ggml_tensor *)
static ck_ggml_init_fn ck_resolve_ggml_init(void)
static ck_ggml_cpu_init_fn ck_resolve_ggml_cpu_init(void)
void rope_precompute_cache_split(float *cos_cache, float *sin_cache, int max_seq_len, int head_dim, float base)
static void mrope_rotate_pair(float x0, float x1, float cos_theta, float sin_theta, float *out0, float *out1)
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_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)
static float vision_mrope_yarn_ramp(float low, float high, int chan)
__attribute__((visibility("default"))) CKTokenizer *ck_tokenizer_create(CKTokenizerType type)
const char * token
Definition tokenizer.h:307
uint32_t end
Definition utf8.c:215
uint32_t start
Definition utf8.c:214