51 casadi_int casadi_blazing_low(T1 x,
const T1* grid, casadi_int ng,
52 casadi_int lookup_mode,
const T1* grid_inv) {
53 switch (lookup_mode) {
64 T1 intercept = grid_inv[0];
65 T1 slope = grid_inv[1];
66 ret = (casadi_int) (x * slope + intercept);
70 T1 dg = grid[ng-1] - g0;
71 ret = (casadi_int) ((x - g0) * (ng-1) / dg);
74 if (ret > ng-2) ret = ng-2;
94 if (grid[lo + len] < x) lo += len + 1;
98 if (lo > ng - 2) lo = ng - 2;
106 casadi_int n = ng - 2;
107 if (n <= 0)
return 0;
108 simde__m256d xv = simde_mm256_set1_pd(
static_cast<T1
>(x));
110 for (; i + 4 <= n; i += 4) {
111 simde__m256d gv = simde_mm256_loadu_pd((
const T1*)(grid + i + 1));
112 simde__m256d cmp = simde_mm256_cmp_pd(xv, gv, SIMDE_CMP_LT_OQ);
113 int m = simde_mm256_movemask_pd(cmp);
115 if (m)
return i + ((m & 1) ? 0 : (m & 2) ? 1 : (m & 4) ? 2 : 3);
118 if (x < grid[i+1])
return i;
128 template<
typename T1>
129 void casadi_blazing_printvec(
const simde__m256d* e) {
131 simde_mm256_storeu_pd(elements, *e);
132 printf(
"mm256d: <%.4f %.4f %.4f %.4f>\n", elements[0], elements[1], elements[2], elements[3]);
136 template<
typename T1>
137 void casadi_blazing_de_boor(T1 x,
const T1* knots,
const T1* inv1,
const T1* inv2,
const T1* inv3, simde__m256d* boor_d0, simde__m256d* boor_d1, simde__m256d* boor_d2,
const simde__m256d* boor_d3) {
138 simde__m256d x_ = simde_mm256_set1_pd(x);
139 simde__m256d zero = simde_mm256_set1_pd(0.0);
140 simde__m256d mask_end = simde_mm256_set_pd(0.0, -1.0, -1.0, -1.0);
144 simde__m256d boor_d3i_1 = simde_mm256_permute4x64_pd(*boor_d3, SIMDE_MM_SHUFFLE(3, 3, 2, 1));
145 boor_d3i_1 = simde_mm256_blendv_pd(zero, boor_d3i_1, mask_end);
147 simde__m256d knotsi = simde_mm256_loadu_pd(knots);
148 simde__m256d knotsi_2 = simde_mm256_loadu_pd(knots+2);
149 simde__m256d knotsi_3 = simde_mm256_loadu_pd(knots+3);
150 simde__m256d knotsi_4 = simde_mm256_loadu_pd(knots+4);
155 r = simde_mm256_mul_pd(simde_mm256_sub_pd(x_, knotsi), simde_mm256_loadu_pd(inv1));
156 *boor_d2 = simde_mm256_mul_pd(r, *boor_d3);
157 r = simde_mm256_mul_pd(simde_mm256_sub_pd(knotsi_2, x_), simde_mm256_loadu_pd(inv1 + 1));
158 *boor_d2 = simde_mm256_fmadd_pd(r, boor_d3i_1, *boor_d2);
161 simde__m256d boor_d2i_1 = simde_mm256_permute4x64_pd(*boor_d2, SIMDE_MM_SHUFFLE(3, 3, 2, 1));
162 boor_d2i_1 = simde_mm256_blendv_pd(zero, boor_d2i_1, mask_end);
165 r = simde_mm256_mul_pd(simde_mm256_sub_pd(x_, knotsi), simde_mm256_loadu_pd(inv2));
166 *boor_d1 = simde_mm256_mul_pd(r, *boor_d2);
167 r = simde_mm256_mul_pd(simde_mm256_sub_pd(knotsi_3, x_), simde_mm256_loadu_pd(inv2 + 1));
168 *boor_d1 = simde_mm256_fmadd_pd(r, boor_d2i_1, *boor_d1);
171 simde__m256d boor_d1i_1 = simde_mm256_permute4x64_pd(*boor_d1, SIMDE_MM_SHUFFLE(3, 3, 2, 1));
172 boor_d1i_1 = simde_mm256_blendv_pd(zero, boor_d1i_1, mask_end);
175 r = simde_mm256_mul_pd(simde_mm256_sub_pd(x_, knotsi), simde_mm256_loadu_pd(inv3));
176 *boor_d0 = simde_mm256_mul_pd(r, *boor_d1);
177 r = simde_mm256_mul_pd(simde_mm256_sub_pd(knotsi_4, x_), simde_mm256_loadu_pd(inv3 + 1));
178 *boor_d0 = simde_mm256_fmadd_pd(r, boor_d1i_1, *boor_d0);
181 simde__m256d knotsi_1 = simde_mm256_loadu_pd(knots+1);
182 simde__m256d bottom, bottom_mask;
184 bottom = simde_mm256_sub_pd(knotsi_1, knotsi);
185 bottom_mask = simde_mm256_cmp_pd(bottom, zero, SIMDE_CMP_EQ_OQ);
186 r = simde_mm256_div_pd(simde_mm256_sub_pd(x_, knotsi), bottom);
187 r = simde_mm256_blendv_pd(r, zero, bottom_mask);
188 *boor_d2 = simde_mm256_mul_pd(r, *boor_d3);
189 *boor_d2 = simde_mm256_blendv_pd(*boor_d2, zero, bottom_mask);
191 bottom = simde_mm256_sub_pd(knotsi_2, knotsi_1);
192 bottom_mask = simde_mm256_cmp_pd(bottom, zero, SIMDE_CMP_EQ_OQ);
193 r = simde_mm256_div_pd(simde_mm256_sub_pd(knotsi_2, x_), bottom);
194 r = simde_mm256_blendv_pd(r, zero, bottom_mask);
195 *boor_d2 = simde_mm256_fmadd_pd(r, boor_d3i_1, *boor_d2);
197 simde__m256d boor_d2i_1 = simde_mm256_permute4x64_pd(*boor_d2, SIMDE_MM_SHUFFLE(3, 3, 2, 1));
198 boor_d2i_1 = simde_mm256_blendv_pd(zero, boor_d2i_1, mask_end);
200 bottom = simde_mm256_sub_pd(knotsi_2, knotsi);
201 bottom_mask = simde_mm256_cmp_pd(bottom, zero, SIMDE_CMP_EQ_OQ);
202 r = simde_mm256_div_pd(simde_mm256_sub_pd(x_, knotsi), bottom);
203 r = simde_mm256_blendv_pd(r, zero, bottom_mask);
204 *boor_d1 = simde_mm256_mul_pd(r, *boor_d2);
205 *boor_d1 = simde_mm256_blendv_pd(*boor_d1, zero, bottom_mask);
207 bottom = simde_mm256_sub_pd(knotsi_3, knotsi_1);
208 bottom_mask = simde_mm256_cmp_pd(bottom, zero, SIMDE_CMP_EQ_OQ);
209 r = simde_mm256_div_pd(simde_mm256_sub_pd(knotsi_3, x_), bottom);
210 r = simde_mm256_blendv_pd(r, zero, bottom_mask);
211 *boor_d1 = simde_mm256_fmadd_pd(r, boor_d2i_1, *boor_d1);
213 simde__m256d boor_d1i_1 = simde_mm256_permute4x64_pd(*boor_d1, SIMDE_MM_SHUFFLE(3, 3, 2, 1));
214 boor_d1i_1 = simde_mm256_blendv_pd(zero, boor_d1i_1, mask_end);
216 bottom = simde_mm256_sub_pd(knotsi_3, knotsi);
217 bottom_mask = simde_mm256_cmp_pd(bottom, zero, SIMDE_CMP_EQ_OQ);
218 r = simde_mm256_div_pd(simde_mm256_sub_pd(x_, knotsi), bottom);
219 r = simde_mm256_blendv_pd(r, zero, bottom_mask);
220 *boor_d0 = simde_mm256_mul_pd(r, *boor_d1);
221 *boor_d0 = simde_mm256_blendv_pd(*boor_d0, zero, bottom_mask);
223 bottom = simde_mm256_sub_pd(knotsi_4, knotsi_1);
224 bottom_mask = simde_mm256_cmp_pd(bottom, zero, SIMDE_CMP_EQ_OQ);
225 r = simde_mm256_div_pd(simde_mm256_sub_pd(knotsi_4, x_), bottom);
226 r = simde_mm256_blendv_pd(r, zero, bottom_mask);
227 *boor_d0 = simde_mm256_fmadd_pd(r, boor_d1i_1, *boor_d0);
251 template<
typename T1>
252 simde__m256d casadi_blazing_boor_der(simde__m256d boor, simde__m256d scale) {
253 simde__m256d sb = simde_mm256_mul_pd(boor, scale);
254 simde__m256d shifted = simde_mm256_permute4x64_pd(sb, SIMDE_MM_SHUFFLE(2, 1, 0, 0));
255 shifted = simde_mm256_blend_pd(simde_mm256_setzero_pd(), shifted, 0xE);
256 return simde_mm256_sub_pd(shifted, sb);
262 template<
typename T1>
263 simde__m256d casadi_blazing_shift_left(simde__m256d v) {
264 simde__m256d shifted = simde_mm256_permute4x64_pd(v, SIMDE_MM_SHUFFLE(3, 3, 2, 1));
265 return simde_mm256_blend_pd(shifted, simde_mm256_setzero_pd(), 0x8);
272 template<
typename T1>
273 simde__m256d casadi_blazing_knot_scale(simde__m256d degree, simde__m256d t_hi, simde__m256d t_lo) {
274 simde__m256d zero = simde_mm256_setzero_pd();
275 simde__m256d denom = simde_mm256_sub_pd(t_hi, t_lo);
276 simde__m256d denom_mask = simde_mm256_cmp_pd(denom, zero, SIMDE_CMP_EQ_OQ);
277 simde__m256d scale = simde_mm256_div_pd(degree, denom);
278 return simde_mm256_blendv_pd(scale, zero, denom_mask);
297 template<
typename T1>
298 casadi_int casadi_blazing_boor_init(
299 T1 x,
const T1* all_knots,
const T1* dim_cache,
300 casadi_int knot_offset, casadi_int knot_offset_next,
301 casadi_int lookup_mode,
302 simde__m256d* d0, simde__m256d* d1, simde__m256d* d2,
303 const T1** inv2_out,
const T1** inv3_out) {
304 casadi_int degree = 3;
305 const T1* knots = all_knots + knot_offset;
306 casadi_int n_knots = knot_offset_next - knot_offset;
307 casadi_int n_b = n_knots - degree - 1;
309 const T1* grid_inv = dim_cache;
310 casadi_int L = casadi_blazing_low<T1>(x, knots + degree,
312 lookup_mode, grid_inv);
313 casadi_int start = L;
314 if (start > n_b - degree - 1) start = n_b - degree - 1;
316 simde__m256d d3 = simde_mm256_setzero_pd();
317 if (x >= knots[0] && x <= knots[n_knots-1]) {
319 d3 = simde_mm256_set1_pd(1.0);
320 }
else if (x == knots[n_knots-1]) {
321 d3 = simde_mm256_set_pd(1.0, 0.0, 0.0, 0.0);
322 }
else if (knots[L+degree] == x) {
323 d3 = simde_mm256_set_pd(0.0, 1.0, 0.0, 0.0);
325 d3 = simde_mm256_set_pd(1.0, 0.0, 0.0, 0.0);
328 const T1 *inv1 = 0, *inv2 = 0, *inv3 = 0;
331 const T1* inv_base = dim_cache + 2;
332 inv1 = inv_base + start;
333 inv2 = inv_base + n_knots + start;
334 inv3 = inv_base + 2*n_knots + start;
335 if (inv2_out) *inv2_out = inv_base + n_knots + start + 1;
336 if (inv3_out) *inv3_out = inv_base + 2*n_knots + start + 1;
338 if (inv2_out) *inv2_out = 0;
339 if (inv3_out) *inv3_out = 0;
341 casadi_blazing_de_boor(x, knots + start, inv1, inv2, inv3, d0, d1, d2, &d3);
349 template<
typename T1>
350 simde__m256d casadi_blazing_dbasis(simde__m256d boor_d1,
const T1* t,
const T1* inv3) {
351 simde__m256d three = simde_mm256_set1_pd(3.0);
354 s1 = simde_mm256_mul_pd(three, simde_mm256_loadu_pd(inv3));
356 s1 = casadi_blazing_knot_scale<T1>(three,
357 simde_mm256_loadu_pd(t + 4), simde_mm256_loadu_pd(t + 1));
359 return casadi_blazing_boor_der<T1>(
360 casadi_blazing_shift_left<T1>(boor_d1), s1);
368 template<
typename T1>
369 simde__m256d casadi_blazing_d2basis(simde__m256d boor_d2,
const T1* t,
const T1* inv2,
const T1* inv3) {
370 simde__m256d three = simde_mm256_set1_pd(3.0);
371 simde__m256d two = simde_mm256_set1_pd(2.0);
374 s1 = simde_mm256_mul_pd(three, simde_mm256_loadu_pd(inv3));
375 s2 = simde_mm256_mul_pd(two, simde_mm256_loadu_pd(inv2));
377 s1 = casadi_blazing_knot_scale<T1>(three,
378 simde_mm256_loadu_pd(t + 4), simde_mm256_loadu_pd(t + 1));
379 s2 = casadi_blazing_knot_scale<T1>(two,
380 simde_mm256_loadu_pd(t + 3), simde_mm256_loadu_pd(t + 1));
382 simde__m256d inner = casadi_blazing_boor_der<T1>(
383 casadi_blazing_shift_left<T1>(boor_d2), s2);
384 return casadi_blazing_boor_der<T1>(
385 casadi_blazing_shift_left<T1>(inner), s1);
392 template<
typename T1>
393 T1 casadi_blazing_hsum(simde__m256d r) {
394 simde__m128d r0 = simde_mm256_castpd256_pd128(r);
395 simde__m128d r1 = simde_mm256_extractf128_pd(r, 1);
396 r0 = simde_mm_add_pd(r0, r1);
397 return simde_mm_cvtsd_f64(simde_mm_add_sd(r0, simde_mm_unpackhi_pd(r0, r0)));
408 template<
typename T1>
409 T1 casadi_blazing_tensor_ttv2(
const simde__m256d C[4],
410 simde__m256d a, simde__m256d b) {
413 simde__m256d ab0 = simde_mm256_mul_pd(a,
414 simde_mm256_permute4x64_pd(b, SIMDE_MM_SHUFFLE(0, 0, 0, 0)));
415 simde__m256d ab1 = simde_mm256_mul_pd(a,
416 simde_mm256_permute4x64_pd(b, SIMDE_MM_SHUFFLE(1, 1, 1, 1)));
417 simde__m256d ab2 = simde_mm256_mul_pd(a,
418 simde_mm256_permute4x64_pd(b, SIMDE_MM_SHUFFLE(2, 2, 2, 2)));
419 simde__m256d ab3 = simde_mm256_mul_pd(a,
420 simde_mm256_permute4x64_pd(b, SIMDE_MM_SHUFFLE(3, 3, 3, 3)));
422 r = simde_mm256_mul_pd(ab0, C[0]);
423 r = simde_mm256_fmadd_pd(ab1, C[1], r);
424 r = simde_mm256_fmadd_pd(ab2, C[2], r);
425 r = simde_mm256_fmadd_pd(ab3, C[3], r);
427 return casadi_blazing_hsum<T1>(r);
438 template<
typename T1>
439 T1 casadi_blazing_tensor_ttv3(
const simde__m256d C[16],
440 simde__m256d a, simde__m256d b, simde__m256d c) {
441 simde__m256d ab[4], cab[4], r;
444 simde__m256d b0 = simde_mm256_permute4x64_pd(b, SIMDE_MM_SHUFFLE(0, 0, 0, 0));
445 simde__m256d b1 = simde_mm256_permute4x64_pd(b, SIMDE_MM_SHUFFLE(1, 1, 1, 1));
446 simde__m256d b2 = simde_mm256_permute4x64_pd(b, SIMDE_MM_SHUFFLE(2, 2, 2, 2));
447 simde__m256d b3 = simde_mm256_permute4x64_pd(b, SIMDE_MM_SHUFFLE(3, 3, 3, 3));
448 ab[0] = simde_mm256_mul_pd(a, b0);
449 ab[1] = simde_mm256_mul_pd(a, b1);
450 ab[2] = simde_mm256_mul_pd(a, b2);
451 ab[3] = simde_mm256_mul_pd(a, b3);
453 for (i = 0; i < 4; ++i) {
454 cab[i] = simde_mm256_mul_pd(ab[0], C[4*i+0]);
455 cab[i] = simde_mm256_fmadd_pd(ab[1], C[4*i+1], cab[i]);
456 cab[i] = simde_mm256_fmadd_pd(ab[2], C[4*i+2], cab[i]);
457 cab[i] = simde_mm256_fmadd_pd(ab[3], C[4*i+3], cab[i]);
460 r = simde_mm256_mul_pd(cab[0],
461 simde_mm256_permute4x64_pd(c, SIMDE_MM_SHUFFLE(0, 0, 0, 0)));
462 r = simde_mm256_fmadd_pd(cab[1],
463 simde_mm256_permute4x64_pd(c, SIMDE_MM_SHUFFLE(1, 1, 1, 1)), r);
464 r = simde_mm256_fmadd_pd(cab[2],
465 simde_mm256_permute4x64_pd(c, SIMDE_MM_SHUFFLE(2, 2, 2, 2)), r);
466 r = simde_mm256_fmadd_pd(cab[3],
467 simde_mm256_permute4x64_pd(c, SIMDE_MM_SHUFFLE(3, 3, 3, 3)), r);
469 return casadi_blazing_hsum<T1>(r);
482 template<
typename T1>
483 T1 casadi_blazing_tensor_ttv4(
const T1* coeffs,
484 casadi_int s1, casadi_int s2, casadi_int s3,
485 simde__m256d a, simde__m256d b, simde__m256d c, simde__m256d d) {
489 simde__m256d dbr[4] = {
490 simde_mm256_permute4x64_pd(d, SIMDE_MM_SHUFFLE(0, 0, 0, 0)),
491 simde_mm256_permute4x64_pd(d, SIMDE_MM_SHUFFLE(1, 1, 1, 1)),
492 simde_mm256_permute4x64_pd(d, SIMDE_MM_SHUFFLE(2, 2, 2, 2)),
493 simde_mm256_permute4x64_pd(d, SIMDE_MM_SHUFFLE(3, 3, 3, 3))
498 for (
int idx = 0; idx < 16; ++idx) C[idx] = simde_mm256_setzero_pd();
499 for (l = 0; l < 4; ++l) {
500 const T1* base = coeffs + s3*l;
501 simde__m256d dl = dbr[l];
502 for (j = 0; j < 4; ++j) {
503 for (k = 0; k < 4; ++k) {
504 C[j+4*k] = simde_mm256_fmadd_pd(
505 simde_mm256_loadu_pd(base + s1*j + s2*k), dl, C[j+4*k]);
510 return casadi_blazing_tensor_ttv3<T1>(C, a, b, c);
523 template<
typename T1>
524 T1 casadi_blazing_tensor_ttv5(
const T1* coeffs,
525 casadi_int s1, casadi_int s2, casadi_int s3, casadi_int s4,
526 simde__m256d a, simde__m256d b, simde__m256d c,
527 simde__m256d d, simde__m256d e) {
532 simde__m256d dbr[4] = {
533 simde_mm256_permute4x64_pd(d, SIMDE_MM_SHUFFLE(0, 0, 0, 0)),
534 simde_mm256_permute4x64_pd(d, SIMDE_MM_SHUFFLE(1, 1, 1, 1)),
535 simde_mm256_permute4x64_pd(d, SIMDE_MM_SHUFFLE(2, 2, 2, 2)),
536 simde_mm256_permute4x64_pd(d, SIMDE_MM_SHUFFLE(3, 3, 3, 3))
538 simde__m256d ebr[4] = {
539 simde_mm256_permute4x64_pd(e, SIMDE_MM_SHUFFLE(0, 0, 0, 0)),
540 simde_mm256_permute4x64_pd(e, SIMDE_MM_SHUFFLE(1, 1, 1, 1)),
541 simde_mm256_permute4x64_pd(e, SIMDE_MM_SHUFFLE(2, 2, 2, 2)),
542 simde_mm256_permute4x64_pd(e, SIMDE_MM_SHUFFLE(3, 3, 3, 3))
545 for (l = 0; l < 4; ++l) {
546 for (m = 0; m < 4; ++m) {
547 de[l+4*m] = simde_mm256_mul_pd(dbr[l], ebr[m]);
553 for (
int idx = 0; idx < 16; ++idx) C[idx] = simde_mm256_setzero_pd();
554 for (l = 0; l < 4; ++l) {
555 for (m = 0; m < 4; ++m) {
556 const T1* base = coeffs + s3*l + s4*m;
557 simde__m256d delm = de[l+4*m];
558 for (j = 0; j < 4; ++j) {
559 for (k = 0; k < 4; ++k) {
560 C[j+4*k] = simde_mm256_fmadd_pd(
561 simde_mm256_loadu_pd(base + s1*j + s2*k),
568 return casadi_blazing_tensor_ttv3<T1>(C, a, b, c);