File indexing completed on 2026-11-07 10:15:27
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013 #ifndef MACHINE_VECTORS_H
0014 #define MACHINE_VECTORS_H
0015
0016 #define ALIGN_STRUCT(x) __attribute__((aligned(x)))
0017
0018 #include <math.h>
0019
0020 #if defined(__GNUC__)
0021 # if defined(__AVX2__)
0022 # include <immintrin.h>
0023 # elif defined(__ARM_NEON)
0024 # include <arm_neon.h>
0025 # endif
0026 #elif defined(_MSC_VER)
0027 # if defined(__AVX2__)
0028 # include <intrin.h>
0029 # elif defined(_M_ARM64)
0030 # include <arm_neon.h>
0031 # endif
0032 #endif
0033
0034 #include "flint.h"
0035 #include "templates.h"
0036
0037 #ifdef __cplusplus
0038 extern "C" {
0039 #endif
0040
0041 #if defined(__AVX2__)
0042
0043
0044
0045
0046
0047
0048 typedef ulong vec1n;
0049 typedef __m128i vec2n;
0050 typedef __m256i vec4n;
0051 typedef struct {__m256i e1, e2;} vec8n;
0052
0053 typedef double vec1d;
0054 typedef __m128d vec2d;
0055 typedef __m256d vec4d;
0056 typedef struct {__m256d e1, e2;} vec8d;
0057
0058
0059
0060
0061
0062 FLINT_FORCE_INLINE vec1d vec1d_load(const double* a) {
0063 return a[0];
0064 }
0065
0066 FLINT_FORCE_INLINE vec1d vec1d_load_aligned(const double* a) {
0067 return a[0];
0068 }
0069
0070 FLINT_FORCE_INLINE vec1d vec1d_load_unaligned(const double* a) {
0071 return a[0];
0072 }
0073
0074 FLINT_FORCE_INLINE void vec1d_store(double* z, vec1d a) {
0075 z[0] = a;
0076 }
0077
0078 FLINT_FORCE_INLINE void vec1d_store_aligned(double* z, vec1d a) {
0079 z[0] = a;
0080 }
0081
0082 FLINT_FORCE_INLINE void vec1d_store_unaligned(double* z, vec1d a) {
0083 z[0] = a;
0084 }
0085
0086 FLINT_FORCE_INLINE int vec1d_same(double a, double b) {
0087 return a == b;
0088 }
0089
0090 FLINT_FORCE_INLINE vec1d vec1d_set_d(double a) {
0091 return a;
0092 }
0093
0094 FLINT_FORCE_INLINE vec1d vec1d_round(vec1d a) {
0095 return rint(a);
0096 }
0097
0098 FLINT_FORCE_INLINE vec1d vec1d_zero(void) {
0099 return 0.0;
0100 }
0101
0102 FLINT_FORCE_INLINE vec1d vec1d_one(void) {
0103 return 1.0;
0104 }
0105
0106 FLINT_FORCE_INLINE vec1d vec1d_add(vec1d a, vec1d b) {
0107 return a + b;
0108 }
0109
0110 FLINT_FORCE_INLINE vec1d vec1d_sub(vec1d a, vec1d b) {
0111 return a - b;
0112 }
0113
0114 FLINT_FORCE_INLINE vec1d vec1d_addsub(vec1d a, vec1d b) {
0115 return a - b;
0116 }
0117
0118 FLINT_FORCE_INLINE vec1d vec1d_neg(vec1d a) {
0119 return -a;
0120 }
0121
0122 FLINT_FORCE_INLINE vec1d vec1d_abs(vec1d a) {
0123 return fabs(a);
0124 }
0125
0126 FLINT_FORCE_INLINE vec1d vec1d_max(vec1d a, vec1d b) {
0127 return fmax(a, b);
0128 }
0129
0130 FLINT_FORCE_INLINE vec1d vec1d_min(vec1d a, vec1d b) {
0131 return fmin(a, b);
0132 }
0133
0134 FLINT_FORCE_INLINE vec1d vec1d_mul(vec1d a, vec1d b) {
0135 return a*b;
0136 }
0137
0138 FLINT_FORCE_INLINE vec1d vec1d_half(vec1d a) {
0139 return a*0.5;
0140 }
0141
0142 FLINT_FORCE_INLINE vec1d vec1d_div(vec1d a, vec1d b) {
0143 return a/b;
0144 }
0145
0146 FLINT_FORCE_INLINE vec1d vec1d_fmadd(vec1d a, vec1d b, vec1d c) {
0147 return fma(a, b, c);
0148 }
0149
0150 FLINT_FORCE_INLINE vec1d vec1d_fmsub(vec1d a, vec1d b, vec1d c) {
0151 return fma(a, b, -c);
0152 }
0153
0154 FLINT_FORCE_INLINE vec1d vec1d_fnmadd(vec1d a, vec1d b, vec1d c) {
0155 return fma(-a, b, c);
0156 }
0157
0158 FLINT_FORCE_INLINE vec1d vec1d_fnmsub(vec1d a, vec1d b, vec1d c) {
0159 return fma(-a, b, -c);
0160 }
0161
0162 FLINT_FORCE_INLINE vec1d vec1d_blendv(vec1d a, vec1d b, vec1d c) {
0163 return c >= 0 ? a : b;
0164 }
0165
0166
0167 FLINT_FORCE_INLINE vec1d vec1d_reduce_0n_to_pmhn(vec1d a, vec1d n) {
0168 vec1d halfn = 0.5*n;
0169 return a > halfn ? a - n : a;
0170 }
0171
0172 FLINT_FORCE_INLINE vec1d vec1d_reduce_pm1n_to_pmhn(vec1d a, vec1d n) {
0173 vec1d t = a + n;
0174 vec1d halfn = 0.5*n;
0175 if (a > halfn)
0176 return a - n;
0177 else if (t < halfn)
0178 return t;
0179 else
0180 return a;
0181 }
0182
0183
0184 FLINT_FORCE_INLINE vec1d vec1d_reduce_2n_to_n(vec1d a, vec1d n) {
0185 return a-n >= 0 ? a-n : a;
0186 }
0187
0188
0189
0190
0191 FLINT_FORCE_INLINE void vec4d_print(vec4d a)
0192 {
0193 #ifdef _MSC_VER
0194 double as[4];
0195 _mm256_storeu_pd(as, a);
0196 flint_printf("{%f, %f, %f, %f}", as[0], as[1], as[2], as[3]);
0197 #else
0198 flint_printf("{%f, %f, %f, %f}", a[0], a[1], a[2], a[3]);
0199 #endif
0200 }
0201
0202 FLINT_FORCE_INLINE double vec4d_get_index(vec4d a, const int i) {
0203 #ifdef _MSC_VER
0204 double as[4];
0205 _mm256_storeu_pd(as, a);
0206 return as[i];
0207 #else
0208 return a[i];
0209 #endif
0210 }
0211
0212 FLINT_FORCE_INLINE vec4d vec4d_load(const double* a) {
0213 return _mm256_load_pd(a);
0214 }
0215
0216 FLINT_FORCE_INLINE vec4d vec4d_load_aligned(const double* a) {
0217 return _mm256_load_pd(a);
0218 }
0219
0220 FLINT_FORCE_INLINE vec4d vec4d_load_unaligned(const double* a) {
0221 return _mm256_loadu_pd(a);
0222 }
0223
0224 FLINT_FORCE_INLINE void vec4d_store(double* z, vec4d a) {
0225 _mm256_store_pd(z, a);
0226 }
0227
0228 FLINT_FORCE_INLINE void vec4d_store_aligned(double* z, vec4d a) {
0229 _mm256_store_pd(z, a);
0230 }
0231
0232 FLINT_FORCE_INLINE void vec4d_store_unaligned(double* z, vec4d a) {
0233 _mm256_storeu_pd(z, a);
0234 }
0235
0236 FLINT_FORCE_INLINE int vec4d_same(vec4d a, vec4d b) {
0237 #ifdef _MSC_VER
0238 double as[4], bs[4];
0239 _mm256_storeu_pd(as, a);
0240 _mm256_storeu_pd(bs, b);
0241 return as[0] == bs[0] && as[1] == bs[1] && as[2] == bs[2] && as[3] == bs[3];
0242 #else
0243 return a[0] == b[0] && a[1] == b[1] && a[2] == b[2] && a[3] == b[3];
0244 #endif
0245 }
0246
0247 FLINT_FORCE_INLINE vec4d vec4d_set_d(double a) {
0248 return _mm256_set1_pd(a);
0249 }
0250
0251 FLINT_FORCE_INLINE vec4d vec4d_set_d4(double a0, double a1, double a2, double a3) {
0252 return _mm256_set_pd(a3, a2, a1, a0);
0253 }
0254
0255 FLINT_FORCE_INLINE vec4d vec4d_round(vec4d a) {
0256 return _mm256_round_pd(a, 4);
0257 }
0258
0259 FLINT_FORCE_INLINE vec4d vec4d_zero(void) {
0260 return _mm256_setzero_pd();
0261 }
0262
0263 FLINT_FORCE_INLINE vec4d vec4d_one(void) {
0264 return vec4d_set_d(1);
0265 }
0266
0267 FLINT_FORCE_INLINE vec4d vec4d_add(vec4d a, vec4d b) {
0268 return _mm256_add_pd(a, b);
0269 }
0270
0271 FLINT_FORCE_INLINE vec4d vec4d_sub(vec4d a, vec4d b) {
0272 return _mm256_sub_pd(a, b);
0273 }
0274
0275 FLINT_FORCE_INLINE vec4d vec4d_addsub(vec4d a, vec4d b) {
0276 return _mm256_addsub_pd(a, b);
0277 }
0278
0279 FLINT_FORCE_INLINE vec4d vec4d_neg(vec4d a) {
0280 __m256d mask = _mm256_castsi256_pd(_mm256_set1_epi64x(UWORD(0x8000000000000000)));
0281 return _mm256_xor_pd(a, mask);
0282 }
0283
0284 FLINT_FORCE_INLINE vec4d vec4d_abs(vec4d a) {
0285 __m256d mask = _mm256_castsi256_pd(_mm256_set1_epi64x(UWORD(0x7fffffffffffffff)));
0286 return _mm256_and_pd(a, mask);
0287 }
0288
0289 FLINT_FORCE_INLINE vec4d vec4d_max(vec4d a, vec4d b) {
0290 return _mm256_max_pd(a, b);
0291 }
0292
0293 FLINT_FORCE_INLINE vec4d vec4d_min(vec4d a, vec4d b) {
0294 return _mm256_min_pd(a, b);
0295 }
0296
0297 FLINT_FORCE_INLINE vec4d vec4d_mul(vec4d a, vec4d b) {
0298 return _mm256_mul_pd(a, b);
0299 }
0300
0301 FLINT_FORCE_INLINE vec4d vec4d_half(vec4d a) {
0302 return vec4d_mul(a, vec4d_set_d(0.5));
0303 }
0304
0305 FLINT_FORCE_INLINE vec4d vec4d_div(vec4d a, vec4d b) {
0306 return _mm256_div_pd(a, b);
0307 }
0308
0309 FLINT_FORCE_INLINE vec4d vec4d_fmadd(vec4d a, vec4d b, vec4d c) {
0310 #ifndef AVOID_AVX2
0311 return _mm256_fmadd_pd(a, b, c);
0312 #else
0313 return _mm256_macc_pd(a, b, c);
0314 #endif
0315 }
0316
0317 FLINT_FORCE_INLINE vec4d vec4d_fmsub(vec4d a, vec4d b, vec4d c) {
0318 #ifndef AVOID_AVX2
0319 return _mm256_fmsub_pd(a, b, c);
0320 #else
0321 return _mm256_msub_pd(a, b, c);
0322 #endif
0323 }
0324
0325 FLINT_FORCE_INLINE vec4d vec4d_fnmadd(vec4d a, vec4d b, vec4d c) {
0326 #ifndef AVOID_AVX2
0327 return _mm256_fnmadd_pd(a, b, c);
0328 #else
0329 return _mm256_nmacc_pd(a, b, c);
0330 #endif
0331 }
0332
0333 FLINT_FORCE_INLINE vec4d vec4d_fnmsub(vec4d a, vec4d b, vec4d c) {
0334 #ifndef AVOID_AVX2
0335 return _mm256_fnmsub_pd(a, b, c);
0336 #else
0337 return _mm256_nmsub_pd(a, b, c);
0338 #endif
0339 }
0340
0341
0342 FLINT_FORCE_INLINE vec4d vec4d_blendv(vec4d a, vec4d b, vec4d c) {
0343 return _mm256_blendv_pd(a, b, c);
0344 }
0345
0346
0347 FLINT_FORCE_INLINE vec4d vec4d_unpacklo(vec4d a, vec4d b) {
0348 return _mm256_unpacklo_pd(a, b);
0349 }
0350
0351
0352 FLINT_FORCE_INLINE vec4d vec4d_unpackhi(vec4d a, vec4d b) {
0353 return _mm256_unpackhi_pd(a, b);
0354 }
0355
0356
0357 #ifndef AVOID_AVX2
0358 #define DEFINE_IT(i0, i1, i2, i3) \
0359 FLINT_FORCE_INLINE vec4d CAT6(vec4d, permute, i0, i1, i2, i3)(vec4d a) { \
0360 return _mm256_permute4x64_pd(a, i0 + 4*(i1 + 4*(i2 + 4*i3))); \
0361 }
0362 #else
0363 #define DEFINE_IT(i0, i1, i2, i3) \
0364 FLINT_FORCE_INLINE vec4d CAT6(vec4d, permute, i0, i1, i2, i3)(vec4d a) { \
0365 return vec4d_set_d4(a[i0], a[i1], a[i2], a[i3]); \
0366 }
0367 #endif
0368 DEFINE_IT(0,2,1,3)
0369 DEFINE_IT(3,1,2,0)
0370 DEFINE_IT(3,2,1,0)
0371 #undef DEFINE_IT
0372
0373
0374
0375
0376
0377 #define DEFINE_IT(i0, i1) \
0378 FLINT_FORCE_INLINE vec4d CAT4(vec4d, permute2, i0, i1)(vec4d a, vec4d b) { \
0379 return _mm256_permute2f128_pd(a, b, i0 + 16*i1); \
0380 }
0381 DEFINE_IT(0,2)
0382 DEFINE_IT(1,3)
0383 #undef DEFINE_IT
0384
0385 FLINT_FORCE_INLINE vec4d vec4d_unpack_lo_permute_0_2_1_3(vec4d u, vec4d v) {
0386 return vec4d_permute_0_2_1_3(vec4d_unpacklo(u, v));
0387 }
0388
0389 FLINT_FORCE_INLINE vec4d vec4d_unpack_hi_permute_0_2_1_3(vec4d u, vec4d v) {
0390 return vec4d_permute_0_2_1_3(vec4d_unpackhi(u, v));
0391 }
0392
0393 FLINT_FORCE_INLINE vec4d vec4d_unpackhi_permute_3_1_2_0(vec4d u, vec4d v) {
0394 return vec4d_permute_3_1_2_0(vec4d_unpackhi(u, v));
0395 }
0396
0397 FLINT_FORCE_INLINE vec4d vec4d_unpacklo_permute_3_1_2_0(vec4d u, vec4d v) {
0398 return vec4d_permute_3_1_2_0(vec4d_unpacklo(u, v));
0399 }
0400
0401
0402 #define VEC4D_TRANSPOSE(z0, z1, z2, z3, a0, a1, a2, a3) \
0403 { \
0404 vec4d _t0, _t1, _t2, _t3; \
0405 _t0 = vec4d_unpacklo(a0, a1); \
0406 _t1 = vec4d_unpackhi(a0, a1); \
0407 _t2 = vec4d_unpacklo(a2, a3); \
0408 _t3 = vec4d_unpackhi(a2, a3); \
0409 z0 = vec4d_permute2_0_2(_t0, _t2); \
0410 z1 = vec4d_permute2_0_2(_t1, _t3); \
0411 z2 = vec4d_permute2_1_3(_t0, _t2); \
0412 z3 = vec4d_permute2_1_3(_t1, _t3); \
0413 }
0414
0415 FLINT_FORCE_INLINE vec4d vec4d_cmp_ge(vec4d a, vec4d b) {
0416 return _mm256_cmp_pd(a, b, _CMP_GE_OQ);
0417 }
0418
0419 FLINT_FORCE_INLINE vec4d vec4d_cmp_gt(vec4d a, vec4d b) {
0420 return _mm256_cmp_pd(a, b, _CMP_GT_OQ);
0421 }
0422
0423 FLINT_FORCE_INLINE vec4d vec4d_reduce_0n_to_pmhn(vec4d a, vec4d n) {
0424 vec4d halfn = vec4d_half(n);
0425 return vec4d_blendv(a, vec4d_sub(a, n), vec4d_cmp_gt(a, halfn));
0426 }
0427
0428 FLINT_FORCE_INLINE vec4d vec4d_reduce_pm1n_to_pmhn(vec4d a, vec4d n) {
0429 vec4d halfn = vec4d_half(n);
0430 vec4d t = vec4d_blendv(n, vec4d_neg(n), a);
0431 a = vec4d_blendv(a, vec4d_sub(a, t), vec4d_cmp_gt(vec4d_abs(a), halfn));
0432 return a;
0433 }
0434
0435
0436 FLINT_FORCE_INLINE vec4d vec4d_reduce_2n_to_n(vec4d a, vec4d n) {
0437 vec4d s = vec4d_sub(a, n);
0438 return vec4d_blendv(s, a, s);
0439 }
0440
0441 FLINT_FORCE_INLINE vec4n vec4d_convert_limited_vec4n(vec4d a) {
0442 __m256d t = _mm256_set1_pd(0x1.0p52);
0443 return _mm256_castpd_si256(_mm256_xor_pd(_mm256_add_pd(a, t), t));
0444 }
0445
0446
0447
0448 FLINT_FORCE_INLINE void vec4n_print(vec4n a)
0449 {
0450 flint_printf("[hi %016llx_%016llx_%016llx_%016llx lo]",
0451 _mm256_extract_epi64(a, 3),
0452 _mm256_extract_epi64(a, 2),
0453 _mm256_extract_epi64(a, 1),
0454 _mm256_extract_epi64(a, 0));
0455 }
0456
0457 FLINT_FORCE_INLINE vec4n vec4n_load_unaligned(const ulong* a) {
0458 return _mm256_loadu_si256((__m256i*) a);
0459 }
0460
0461 FLINT_FORCE_INLINE void vec4n_store_unaligned(ulong* z, vec4n a) {
0462 _mm256_storeu_si256((__m256i*) z, a);
0463 }
0464
0465
0466 #ifndef AVOID_AVX2
0467 #define DEFINE_IT(i0, i1, i2, i3) \
0468 FLINT_FORCE_INLINE vec4n CAT6(vec4n, permute, i0, i1, i2, i3)(vec4n a) { \
0469 return _mm256_permute4x64_epi64(a, i0 + 4*(i1 + 4*(i2 + 4*i3))); \
0470 }
0471 #else
0472 #define DEFINE_IT(i0, i1, i2, i3) \
0473 FLINT_FORCE_INLINE vec4n CAT6(vec4n, permute, i0, i1, i2, i3)(vec4n a) { \
0474 return vec4n_set_n4(a[i0], a[i1], a[i2], a[i3]); \
0475 }
0476 #endif
0477 DEFINE_IT(3,2,1,0)
0478 #undef DEFINE_IT
0479
0480 FLINT_FORCE_INLINE vec4n vec4n_zero(void)
0481 {
0482 return _mm256_setzero_si256();
0483 }
0484
0485 FLINT_FORCE_INLINE vec4n vec4n_set_n4(ulong a0, ulong a1, ulong a2, ulong a3) {
0486 return _mm256_set_epi64x(a3, a2, a1, a0);
0487 }
0488
0489 FLINT_FORCE_INLINE vec4n vec4n_set_n(ulong a) {
0490 return _mm256_set1_epi64x(a);
0491 }
0492
0493 FLINT_FORCE_INLINE vec4n vec4n_add(vec4n a, vec4n b)
0494 {
0495 return _mm256_add_epi64(a, b);
0496 }
0497
0498 FLINT_FORCE_INLINE vec4n vec4n_sub(vec4n a, vec4n b)
0499 {
0500 return _mm256_sub_epi64(a, b);
0501 }
0502
0503
0504 FLINT_FORCE_INLINE vec4n vec4n_addmod_limited(vec4n a, vec4n b, vec4n n)
0505 {
0506 vec4n s = vec4n_add(a, b);
0507 vec4n t = vec4n_sub(s, n);
0508 vec4n m = _mm256_srai_epi32(t, 31);
0509 m = _mm256_shuffle_epi32(m, 1 + 4*(1 + 4*(3 + 4*(3))));
0510 return _mm256_blendv_epi8(t, s, m);
0511 }
0512
0513 FLINT_FORCE_INLINE vec4n vec4n_addmod(vec4n a, vec4n b, vec4n n)
0514 {
0515 vec4n tt = vec4n_set_n(0x8000000000000000);
0516 vec4n s = vec4n_add(a, b);
0517 #if 0
0518 vec4n m = vec4n_sub(n, tt);
0519 vec4n t0 = vec4n_sub(m, a);
0520 vec4n t1 = vec4n_sub(b, tt);
0521 vec4n t2 = vec4n_sub(t1, t0);
0522 return _mm256_blendv_epi8(s, t2, _mm256_cmpgt_epi64(t1, t0));
0523 #else
0524 vec4n t0 = vec4n_sub(s, n);
0525 vec4n t1 = vec4n_sub(a, tt);
0526 vec4n t2 = vec4n_sub(t0, tt);
0527 return _mm256_blendv_epi8(t0, s, _mm256_cmpgt_epi64(t2, t1));
0528 #endif
0529 }
0530
0531 FLINT_FORCE_INLINE vec4n vec4n_mul(vec4n u, vec4n v)
0532 {
0533 return _mm256_mul_epu32(u, v);
0534 }
0535
0536
0537
0538 FLINT_FORCE_INLINE vec4n vec4n_bit_shift_right(vec4n a, ulong b) {
0539 return _mm256_srli_epi64(a, b);
0540 }
0541
0542 #define vec4n_bit_shift_right_32(a) vec4n_bit_shift_right((a), 32)
0543
0544 FLINT_FORCE_INLINE vec4n vec4n_bit_and(vec4n a, vec4n b) {
0545 return _mm256_and_si256(a, b);
0546 }
0547
0548 FLINT_FORCE_INLINE vec4d vec4n_convert_limited_vec4d(vec4n a) {
0549 __m256d t = _mm256_set1_pd(0x1.0p52);
0550 return _mm256_sub_pd(_mm256_or_pd(_mm256_castsi256_pd(a), t), t);
0551 }
0552
0553
0554 FLINT_FORCE_INLINE ulong vec4n_horizontal_sum(vec4n a) {
0555 vec4n a_hi = _mm256_shuffle_epi32(a, 14);
0556 vec4n sum_lo = _mm256_add_epi64(a, a_hi);
0557 vec2n sum_hi = _mm256_extracti128_si256(sum_lo, 1);
0558 vec2n sum = _mm_add_epi64(_mm256_castsi256_si128(sum_lo), sum_hi);
0559 return (ulong) _mm_cvtsi128_si64(sum);
0560 }
0561
0562
0563
0564
0565 FLINT_FORCE_INLINE double vec8d_get_index(vec8d a, int i) {
0566 return i < 4 ? vec4d_get_index(a.e1, i) : vec4d_get_index(a.e2, i - 4);
0567 }
0568
0569 FLINT_FORCE_INLINE vec8d vec8d_set_d(double a) {
0570 vec4d z1 = vec4d_set_d(a);
0571 vec8d z = {z1, z1};
0572 return z;
0573 }
0574
0575 FLINT_FORCE_INLINE vec8d vec8d_set_d8(double a0, double a1, double a2, double a3, double a4, double a5, double a6, double a7) {
0576 vec4d z1 = vec4d_set_d4(a0, a1, a2, a3);
0577 vec4d z2 = vec4d_set_d4(a4, a5, a6, a7);
0578 vec8d z = {z1, z2};
0579 return z;
0580 }
0581
0582 FLINT_FORCE_INLINE vec8d vec8d_load(const double* a) {
0583 vec8d z = {vec4d_load(a+0), vec4d_load(a+4)};
0584 return z;
0585 }
0586
0587 FLINT_FORCE_INLINE vec8d vec8d_load_aligned(const double* a) {
0588 vec8d z = {vec4d_load_aligned(a+0), vec4d_load_aligned(a+4)};
0589 return z;
0590 }
0591
0592 FLINT_FORCE_INLINE vec8d vec8d_load_unaligned(const double* a) {
0593 vec8d z = {vec4d_load_unaligned(a+0), vec4d_load_unaligned(a+4)};
0594 return z;
0595 }
0596
0597 FLINT_FORCE_INLINE void vec8d_store(double* z, vec8d a) {
0598 vec4d_store(z+0, a.e1);
0599 vec4d_store(z+4, a.e2);
0600 }
0601
0602 FLINT_FORCE_INLINE void vec8d_store_aligned(double* z, vec8d a) {
0603 vec4d_store_aligned(z+0, a.e1);
0604 vec4d_store_aligned(z+4, a.e2);
0605 }
0606
0607 FLINT_FORCE_INLINE void vec8d_store_unaligned(double* z, vec8d a) {
0608 vec4d_store_unaligned(z+0, a.e1);
0609 vec4d_store_unaligned(z+4, a.e2);
0610 }
0611
0612 FLINT_FORCE_INLINE int vec8d_same(vec8d a, vec8d b) {
0613 return vec4d_same(a.e1, b.e1) && vec4d_same(a.e2, b.e2);
0614 }
0615
0616 FLINT_FORCE_INLINE vec8d vec8n_convert_limited_vec8d(vec8n a) {
0617 vec8d z = {vec4n_convert_limited_vec4d(a.e1), vec4n_convert_limited_vec4d(a.e2)};
0618 return z;
0619 }
0620
0621
0622 FLINT_FORCE_INLINE vec8d _vec8i32_convert_vec8d(__m256i a)
0623 {
0624 __m256i mask = _mm256_set1_epi32(0x43300000);
0625 __m256i ak0 = _mm256_unpacklo_epi32(a, mask);
0626 __m256i ak1 = _mm256_unpackhi_epi32(a, mask);
0627 __m256d t = _mm256_set1_pd(0x1.0p52);
0628 vec8d z;
0629 z.e1 = _mm256_sub_pd(_mm256_castsi256_pd(ak0), t);
0630 z.e2 = _mm256_sub_pd(_mm256_castsi256_pd(ak1), t);
0631 return z;
0632 }
0633
0634
0635
0636 #define DEFINE_IT(V) \
0637 FLINT_FORCE_INLINE V V##_reduce_pm1no_to_0n(V a, V n) { \
0638 return V##_blendv(a, V##_add(a, n), a); \
0639 }
0640 DEFINE_IT(vec1d)
0641 DEFINE_IT(vec4d)
0642 #undef DEFINE_IT
0643
0644
0645 #define DEFINE_IT(V) \
0646 FLINT_FORCE_INLINE V V##_reduce_to_pm1n(V a, V n, V ninv) { \
0647 return V##_fnmadd(V##_round(V##_mul(a, ninv)), n, a); \
0648 }
0649 DEFINE_IT(vec1d)
0650 DEFINE_IT(vec4d)
0651 #undef DEFINE_IT
0652
0653
0654 #define DEFINE_IT(V) \
0655 FLINT_FORCE_INLINE V V##_reduce_to_pm1no(V a, V n, V ninv) { \
0656 return V##_fnmadd(V##_round(V##_mul(a, ninv)), n, a); \
0657 }
0658 DEFINE_IT(vec1d)
0659 DEFINE_IT(vec4d)
0660 #undef DEFINE_IT
0661
0662
0663
0664 #define DEFINE_IT(V) \
0665 FLINT_FORCE_INLINE V V##_reduce_to_0n(V a, V n, V ninv) { \
0666 return V##_reduce_pm1no_to_0n(V##_reduce_to_pm1no(a, n, ninv), n); \
0667 }
0668 DEFINE_IT(vec1d)
0669 DEFINE_IT(vec4d)
0670 #undef DEFINE_IT
0671
0672 #define DEFINE_IT(V) \
0673 FLINT_FORCE_INLINE int V##_same_mod(V a, V b, V n, V ninv) { \
0674 return V##_same(V##_reduce_to_0n(a, n, ninv), V##_reduce_to_0n(b, n, ninv)); \
0675 }
0676 DEFINE_IT(vec1d)
0677 DEFINE_IT(vec4d)
0678 #undef DEFINE_IT
0679
0680
0681
0682
0683
0684
0685
0686
0687
0688
0689
0690 #define DEFINE_IT(V) \
0691 FLINT_FORCE_INLINE V V##_mulmod(V a, V b, V n, V ninv) { \
0692 V h = V##_mul(a, b); \
0693 V q = V##_round(V##_mul(h, ninv)); \
0694 V l = V##_fmsub(a, b, h); \
0695 return V##_add(V##_fnmadd(q, n, h), l); \
0696 } \
0697 \
0698 FLINT_FORCE_INLINE V V##_nmulmod(V a, V b, V n, V ninv) { \
0699 V h = V##_mul(a, b); \
0700 V q = V##_round(V##_mul(h, ninv)); \
0701 V l = V##_fnmadd(a, b, h); \
0702 return V##_sub(l, V##_fnmadd(q, n, h)); \
0703 }
0704
0705 DEFINE_IT(vec1d)
0706 DEFINE_IT(vec4d)
0707 #undef DEFINE_IT
0708
0709
0710
0711
0712 #define EXTEND_VEC_DEF0(U, V, f) \
0713 FLINT_FORCE_INLINE V V##f(void) { \
0714 U z1 = U##f(); \
0715 U z2 = U##f(); \
0716 V z = {z1, z2}; \
0717 return z; \
0718 }
0719
0720 #define EXTEND_VEC_DEF1(U, V, f) \
0721 FLINT_FORCE_INLINE V V##f(V a) { \
0722 U z1 = U##f(a.e1); \
0723 U z2 = U##f(a.e2); \
0724 V z = {z1, z2}; \
0725 return z; \
0726 }
0727
0728 #define EXTEND_VEC_DEF2(U, V, f) \
0729 FLINT_FORCE_INLINE V V##f(V a, V b) { \
0730 U z1 = U##f(a.e1, b.e1); \
0731 U z2 = U##f(a.e2, b.e2); \
0732 V z = {z1, z2}; \
0733 return z; \
0734 }
0735
0736 #define EXTEND_VEC_DEF3(U, V, f) \
0737 FLINT_FORCE_INLINE V V##f(V a, V b, V c) { \
0738 U z1 = U##f(a.e1, b.e1, c.e1); \
0739 U z2 = U##f(a.e2, b.e2, c.e2); \
0740 V z = {z1, z2}; \
0741 return z; \
0742 }
0743
0744 #define EXTEND_VEC_DEF4(U, V, f) \
0745 FLINT_FORCE_INLINE V V##f(V a, V b, V c, V d) { \
0746 U z1 = U##f(a.e1, b.e1, c.e1, d.e1); \
0747 U z2 = U##f(a.e2, b.e2, c.e2, d.e2); \
0748 V z = {z1, z2}; \
0749 return z; \
0750 }
0751
0752 EXTEND_VEC_DEF0(vec4d, vec8d, _zero)
0753 EXTEND_VEC_DEF1(vec4d, vec8d, _neg)
0754 EXTEND_VEC_DEF1(vec4d, vec8d, _round)
0755 EXTEND_VEC_DEF2(vec4d, vec8d, _add)
0756 EXTEND_VEC_DEF2(vec4d, vec8d, _sub)
0757 EXTEND_VEC_DEF2(vec4d, vec8d, _min)
0758 EXTEND_VEC_DEF2(vec4d, vec8d, _max)
0759 EXTEND_VEC_DEF2(vec4d, vec8d, _mul)
0760 EXTEND_VEC_DEF2(vec4d, vec8d, _div)
0761 EXTEND_VEC_DEF2(vec4d, vec8d, _reduce_pm1n_to_pmhn)
0762 EXTEND_VEC_DEF2(vec4d, vec8d, _reduce_pm1no_to_0n)
0763 EXTEND_VEC_DEF2(vec4d, vec8d, _reduce_2n_to_n)
0764 EXTEND_VEC_DEF3(vec4d, vec8d, _reduce_to_pm1n)
0765 EXTEND_VEC_DEF3(vec4d, vec8d, _reduce_to_pm1no)
0766 EXTEND_VEC_DEF3(vec4d, vec8d, _reduce_to_0n)
0767 EXTEND_VEC_DEF3(vec4d, vec8d, _fmadd)
0768 EXTEND_VEC_DEF3(vec4d, vec8d, _fmsub)
0769 EXTEND_VEC_DEF3(vec4d, vec8d, _fnmadd)
0770 EXTEND_VEC_DEF3(vec4d, vec8d, _fnmsub)
0771 EXTEND_VEC_DEF3(vec4d, vec8d, _blendv)
0772 EXTEND_VEC_DEF3(vec4n, vec8n, _addmod)
0773 EXTEND_VEC_DEF3(vec4n, vec8n, _addmod_limited)
0774 EXTEND_VEC_DEF4(vec4d, vec8d, _mulmod)
0775 EXTEND_VEC_DEF4(vec4d, vec8d, _nmulmod)
0776
0777 #undef EXTEND_VEC_DEF4
0778 #undef EXTEND_VEC_DEF3
0779 #undef EXTEND_VEC_DEF2
0780 #undef EXTEND_VEC_DEF1
0781 #undef EXTEND_VEC_DEF0
0782
0783
0784
0785
0786
0787 FLINT_FORCE_INLINE vec8n vec8n_load_unaligned(const ulong* a) {
0788 vec8n z = {vec4n_load_unaligned(a+0), vec4n_load_unaligned(a+4)};
0789 return z;
0790 }
0791
0792 FLINT_FORCE_INLINE vec8n vec8n_set_n(ulong a) {
0793 vec4n x = vec4n_set_n(a);
0794 vec8n z = {x, x};
0795 return z;
0796 }
0797
0798 FLINT_FORCE_INLINE vec8n vec8n_bit_shift_right(vec8n a, ulong b) {
0799 vec8n z = {vec4n_bit_shift_right(a.e1, b), vec4n_bit_shift_right(a.e2, b)};
0800 return z;
0801 }
0802
0803 #define vec8n_bit_shift_right_32(a) vec8n_bit_shift_right((a), 32)
0804
0805 FLINT_FORCE_INLINE vec8n vec8n_bit_and(vec8n a, vec8n b) {
0806 vec8n z = {vec4n_bit_and(a.e1, b.e1), vec4n_bit_and(a.e2, b.e2)};
0807 return z;
0808 }
0809
0810
0811
0812 #elif defined(__ARM_NEON) || defined(_M_ARM64)
0813
0814 typedef ulong vec1n;
0815 typedef uint64x2_t vec2n;
0816 typedef struct {vec2n e1, e2;} vec4n;
0817 typedef struct {vec4n e1, e2;} vec8n;
0818
0819 typedef double vec1d;
0820 typedef float64x2_t vec2d;
0821 typedef struct {vec2d e1, e2;} vec4d;
0822 typedef struct {vec4d e1, e2;} vec8d;
0823
0824 #define EXTEND_VEC_DEF0(U, V, f) \
0825 FLINT_FORCE_INLINE V V##f(void) { \
0826 U z1 = U##f(); \
0827 U z2 = U##f(); \
0828 V z = {z1, z2}; return z; \
0829 }
0830
0831 #define EXTEND_VEC_DEF1(U, V, f) \
0832 FLINT_FORCE_INLINE V V##f(V a) { \
0833 U z1 = U##f(a.e1); \
0834 U z2 = U##f(a.e2); \
0835 V z = {z1, z2}; return z; \
0836 }
0837
0838 #define EXTEND_VEC_DEF2(U, V, f) \
0839 FLINT_FORCE_INLINE V V##f(V a, V b) { \
0840 U z1 = U##f(a.e1, b.e1); \
0841 U z2 = U##f(a.e2, b.e2); \
0842 V z = {z1, z2}; return z; \
0843 }
0844
0845 #define EXTEND_VEC_DEF3(U, V, f) \
0846 FLINT_FORCE_INLINE V V##f(V a, V b, V c) { \
0847 U z1 = U##f(a.e1, b.e1, c.e1); \
0848 U z2 = U##f(a.e2, b.e2, c.e2); \
0849 V z = {z1, z2}; return z; \
0850 }
0851
0852 #define EXTEND_VEC_DEF4(U, V, f) \
0853 FLINT_FORCE_INLINE V V##f(V a, V b, V c, V d) { \
0854 U z1 = U##f(a.e1, b.e1, c.e1, d.e1); \
0855 U z2 = U##f(a.e2, b.e2, c.e2, d.e2); \
0856 V z = {z1, z2}; return z; \
0857 }
0858
0859
0860
0861
0862
0863
0864 FLINT_FORCE_INLINE vec1d vec1d_load(const double* a) {
0865 return a[0];
0866 }
0867
0868 FLINT_FORCE_INLINE vec1d vec1d_load_aligned(const double* a) {
0869 return a[0];
0870 }
0871
0872 FLINT_FORCE_INLINE vec1d vec1d_load_unaligned(const double* a) {
0873 return a[0];
0874 }
0875
0876 FLINT_FORCE_INLINE void vec1d_store(double* z, vec1d a) {
0877 z[0] = a;
0878 }
0879
0880 FLINT_FORCE_INLINE void vec1d_store_aligned(double* z, vec1d a) {
0881 z[0] = a;
0882 }
0883
0884 FLINT_FORCE_INLINE void vec1d_store_unaligned(double* z, vec1d a) {
0885 z[0] = a;
0886 }
0887
0888 FLINT_FORCE_INLINE int vec1d_same(double a, double b) {
0889 return a == b;
0890 }
0891
0892 FLINT_FORCE_INLINE vec1d vec1d_set_d(double a) {
0893 return a;
0894 }
0895
0896 FLINT_FORCE_INLINE vec1d vec1d_round(vec1d a) {
0897 return rint(a);
0898 }
0899
0900 FLINT_FORCE_INLINE vec1d vec1d_zero(void) {
0901 return 0.0;
0902 }
0903
0904 FLINT_FORCE_INLINE vec1d vec1d_one(void) {
0905 return 1.0;
0906 }
0907
0908 FLINT_FORCE_INLINE vec1d vec1d_add(vec1d a, vec1d b) {
0909 return a + b;
0910 }
0911
0912 FLINT_FORCE_INLINE vec1d vec1d_sub(vec1d a, vec1d b) {
0913 return a - b;
0914 }
0915
0916 FLINT_FORCE_INLINE vec1d vec1d_addsub(vec1d a, vec1d b) {
0917 return a - b;
0918 }
0919
0920 FLINT_FORCE_INLINE vec1d vec1d_neg(vec1d a) {
0921 return -a;
0922 }
0923
0924 FLINT_FORCE_INLINE vec1d vec1d_abs(vec1d a) {
0925 return fabs(a);
0926 }
0927
0928 FLINT_FORCE_INLINE vec1d vec1d_max(vec1d a, vec1d b) {
0929 return fmax(a, b);
0930 }
0931
0932 FLINT_FORCE_INLINE vec1d vec1d_min(vec1d a, vec1d b) {
0933 return fmin(a, b);
0934 }
0935
0936 FLINT_FORCE_INLINE vec1d vec1d_mul(vec1d a, vec1d b) {
0937 return a*b;
0938 }
0939
0940 FLINT_FORCE_INLINE vec1d vec1d_half(vec1d a) {
0941 return a*0.5;
0942 }
0943
0944 FLINT_FORCE_INLINE vec1d vec1d_div(vec1d a, vec1d b) {
0945 return a/b;
0946 }
0947
0948 FLINT_FORCE_INLINE vec1d vec1d_fmadd(vec1d a, vec1d b, vec1d c) {
0949 return fma(a, b, c);
0950 }
0951
0952 FLINT_FORCE_INLINE vec1d vec1d_fmsub(vec1d a, vec1d b, vec1d c) {
0953 return fma(a, b, -c);
0954 }
0955
0956 FLINT_FORCE_INLINE vec1d vec1d_fnmadd(vec1d a, vec1d b, vec1d c) {
0957 return fma(-a, b, c);
0958 }
0959
0960 FLINT_FORCE_INLINE vec1d vec1d_fnmsub(vec1d a, vec1d b, vec1d c) {
0961 return fma(-a, b, -c);
0962 }
0963
0964 FLINT_FORCE_INLINE vec1d vec1d_blendv(vec1d a, vec1d b, vec1d c) {
0965 return c >= 0 ? a : b;
0966 }
0967
0968
0969 FLINT_FORCE_INLINE vec1d vec1d_reduce_0n_to_pmhn(vec1d a, vec1d n) {
0970 vec1d halfn = 0.5*n;
0971 return a > halfn ? a - n : a;
0972 }
0973
0974 FLINT_FORCE_INLINE vec1d vec1d_reduce_pm1n_to_pmhn(vec1d a, vec1d n) {
0975 vec1d t = a + n;
0976 vec1d halfn = 0.5*n;
0977 if (a > halfn)
0978 return a - n;
0979 else if (t < halfn)
0980 return t;
0981 else
0982 return a;
0983 }
0984
0985
0986
0987 FLINT_FORCE_INLINE double vec2d_get_index(vec2d a, int i) {
0988 return a[i];
0989 }
0990
0991 FLINT_FORCE_INLINE vec2d vec2d_set_d2(double a0, double a1)
0992 {
0993 double ALIGN_STRUCT(16) data[2] = {a0, a1};
0994 return vld1q_f64((float64_t *) data);
0995 }
0996
0997 FLINT_FORCE_INLINE vec2d vec2d_set_d(double a)
0998 {
0999 return vdupq_n_f64(a);
1000 }
1001
1002 FLINT_FORCE_INLINE vec2d vec2d_load(const double* a)
1003 {
1004 return vld1q_f64(a);
1005 }
1006
1007 FLINT_FORCE_INLINE vec2d vec2d_load_unaligned(const double* a)
1008 {
1009 return vld1q_f64(a);
1010 }
1011
1012 FLINT_FORCE_INLINE vec2d vec2d_load_aligned(const double* a)
1013 {
1014 return vld1q_f64(a);
1015 }
1016
1017 FLINT_FORCE_INLINE void vec2d_store(double* z, vec2d a)
1018 {
1019 vst1q_f64(z, a);
1020 }
1021
1022 FLINT_FORCE_INLINE void vec2d_store_unaligned(double* z, vec2d a)
1023 {
1024 vst1q_f64(z, a);
1025 }
1026
1027 FLINT_FORCE_INLINE void vec2d_store_aligned(double* z, vec2d a)
1028 {
1029 vst1q_f64(z, a);
1030 }
1031
1032 FLINT_FORCE_INLINE vec2d vec2d_zero(void)
1033 {
1034 return vdupq_n_f64(0.0);
1035 }
1036
1037 FLINT_FORCE_INLINE vec2d vec2d_one(void)
1038 {
1039 return vdupq_n_f64(1.0);
1040 }
1041
1042 FLINT_FORCE_INLINE vec2d vec2d_neg(vec2d a)
1043 {
1044 return vnegq_f64(a);
1045 }
1046
1047 FLINT_FORCE_INLINE vec2d vec2d_abs(vec2d a)
1048 {
1049 return vabsq_f64(a);
1050 }
1051
1052 FLINT_FORCE_INLINE vec2d vec2d_min(vec2d a, vec2d b)
1053 {
1054 return vminq_f64(a, b);
1055 }
1056
1057 FLINT_FORCE_INLINE vec2d vec2d_max(vec2d a, vec2d b)
1058 {
1059 return vmaxq_f64(a, b);
1060 }
1061
1062 FLINT_FORCE_INLINE vec2d vec2d_cmp_lt(vec2d a, vec2d b) {
1063 return vcvtq_f64_u64(vcltq_f64(a, b));
1064 }
1065
1066 FLINT_FORCE_INLINE vec2d vec2d_cmp_gt(vec2d a, vec2d b) {
1067 return vcvtq_f64_u64(vcgtq_f64(a, b));
1068 }
1069
1070 FLINT_FORCE_INLINE vec2d vec2d_blendv(vec2d a, vec2d b, vec2d c) {
1071 return vbslq_f64(vcvtq_u64_f64(c), b, a);
1072 }
1073
1074 FLINT_FORCE_INLINE vec2d vec2d_add(vec2d a, vec2d b)
1075 {
1076 return vaddq_f64(a, b);
1077 }
1078
1079 FLINT_FORCE_INLINE vec2d vec2d_sub(vec2d a, vec2d b)
1080 {
1081 return vsubq_f64(a, b);
1082 }
1083
1084 FLINT_FORCE_INLINE vec2d vec2d_mul(vec2d a, vec2d b)
1085 {
1086 return vmulq_f64(a, b);
1087 }
1088
1089 FLINT_FORCE_INLINE vec2d vec2d_half(vec2d a)
1090 {
1091 return vmulq_n_f64(a, 0.5);
1092 }
1093
1094 FLINT_FORCE_INLINE vec2d vec2d_fmadd(vec2d a, vec2d b, vec2d c) {
1095 return vfmaq_f64(c, a, b);
1096 }
1097
1098 FLINT_FORCE_INLINE vec2d vec2d_fnmadd(vec2d a, vec2d b, vec2d c) {
1099 return vfmsq_f64(c, a, b);
1100 }
1101
1102
1103 FLINT_FORCE_INLINE vec2d vec2d_fmsub(vec2d a, vec2d b, vec2d c) {
1104 return -vfmsq_f64(c, a, b);
1105 }
1106
1107 FLINT_FORCE_INLINE vec2d vec2d_fnmsub(vec2d a, vec2d b, vec2d c) {
1108 return -vfmaq_f64(c, a, b);
1109 }
1110
1111 FLINT_FORCE_INLINE vec2d vec2d_div(vec2d a, vec2d b)
1112 {
1113 return vdivq_f64(a, b);
1114 }
1115
1116 FLINT_FORCE_INLINE vec2d vec2d_round(vec2d a)
1117 {
1118 return vrndnq_f64(a);
1119 }
1120
1121 FLINT_FORCE_INLINE vec2d vec2d_unpacklo(vec2d a, vec2d b) {
1122 return vtrn1q_f64(a, b);
1123 }
1124
1125 FLINT_FORCE_INLINE vec2d vec2d_unpackhi(vec2d a, vec2d b) {
1126 return vtrn2q_f64(a, b);
1127 }
1128
1129 FLINT_FORCE_INLINE vec1d vec1d_reduce_to_pm1no(vec1d a, vec1d n, vec1d ninv) {
1130 return vec1d_fnmadd(vec1d_round(vec1d_mul(a, ninv)), n, a);
1131 }
1132
1133 FLINT_FORCE_INLINE vec2d vec2d_reduce_to_pm1no(vec2d a, vec2d n, vec2d ninv) {
1134 return vec2d_fnmadd(vec2d_round(vec2d_mul(a, ninv)), n, a);
1135 }
1136
1137 FLINT_FORCE_INLINE vec1d vec1d_reduce_to_pm1n(vec1d a, vec1d n, vec1d ninv) {
1138 return vec1d_fnmadd(vec1d_round(vec1d_mul(a, ninv)), n, a);
1139 }
1140
1141 FLINT_FORCE_INLINE vec2d vec2d_reduce_to_pm1n(vec2d a, vec2d n, vec2d ninv) {
1142 return vec2d_fnmadd(vec2d_round(vec2d_mul(a, ninv)), n, a);
1143 }
1144
1145 FLINT_FORCE_INLINE vec2d vec2d_reduce_0n_to_pmhn(vec2d a, vec2d n) {
1146 vec2d halfn = vec2d_half(n);
1147 return vbslq_f64(vcgtq_f64(a, halfn), vec2d_sub(a, n), a);
1148 }
1149
1150 FLINT_FORCE_INLINE vec2d vec2d_reduce_pm1n_to_pmhn(vec2d a, vec2d n) {
1151 vec2d halfn = vec2d_half(n);
1152 vec2d t = vec2d_add(a, n);
1153
1154 vec2n condition_a = vcgtq_f64(a, halfn);
1155 vec2n condition_t = vcltq_f64(t, halfn);
1156
1157 return vbslq_f64(condition_a, vec2d_sub(a, n), vbslq_f64(condition_t, t, a));
1158 }
1159
1160 FLINT_FORCE_INLINE vec1d vec1d_reduce_pm1no_to_0n(vec1d a, vec1d n) {
1161 return a >= 0 ? a : a + n;
1162 }
1163
1164 FLINT_FORCE_INLINE vec2d vec2d_reduce_pm1no_to_0n(vec2d a, vec2d n) {
1165 return vbslq_f64(vcgeq_f64(a, vec2d_zero()), a, vaddq_f64(a, n));
1166 }
1167
1168 FLINT_FORCE_INLINE vec1d vec1d_reduce_to_0n(vec1d a, vec1d n, vec1d ninv) {
1169 return vec1d_reduce_pm1no_to_0n(vec1d_reduce_to_pm1no(a, n, ninv), n);
1170 }
1171
1172 FLINT_FORCE_INLINE vec2d vec2d_reduce_to_0n(vec2d a, vec2d n, vec2d ninv) {
1173 return vec2d_reduce_pm1no_to_0n(vec2d_reduce_to_pm1no(a, n, ninv), n);
1174 }
1175
1176
1177
1178 #define DEFINE_IT(V) \
1179 FLINT_FORCE_INLINE V V##_mulmod(V a, V b, V n, V ninv) { \
1180 V h = V##_mul(a, b); \
1181 V q = V##_round(V##_mul(h, ninv)); \
1182 V l = V##_fnmadd(a, b, h); \
1183 return V##_sub(V##_fnmadd(q, n, h), l); \
1184 } \
1185 \
1186 FLINT_FORCE_INLINE V V##_nmulmod(V a, V b, V n, V ninv) { \
1187 V h = V##_mul(a, b); \
1188 V q = V##_round(V##_mul(h, ninv)); \
1189 V l = V##_fnmadd(a, b, h); \
1190 return V##_sub(l, V##_fnmadd(q, n, h)); \
1191 }
1192
1193 DEFINE_IT(vec1d)
1194 DEFINE_IT(vec2d)
1195 #undef DEFINE_IT
1196
1197
1198
1199
1200
1201 FLINT_FORCE_INLINE vec4d vec4d_set_vec2d2(vec2d a, vec2d b) {
1202 vec4d z = {a, b}; return z;
1203 }
1204
1205 FLINT_FORCE_INLINE double vec4d_get_index(vec4d a, int i) {
1206 return i < 2 ? vec2d_get_index(a.e1, i) : vec2d_get_index(a.e2, i - 2);
1207 }
1208
1209 FLINT_FORCE_INLINE vec4d vec4d_set_d4(double a0, double a1, double a2, double a3)
1210 {
1211 return vec4d_set_vec2d2(vec2d_set_d2(a0, a1), vec2d_set_d2(a2, a3));
1212 }
1213
1214 FLINT_FORCE_INLINE vec4d vec4d_set_d(double a)
1215 {
1216 vec2d z1 = vec2d_set_d(a);
1217 vec4d z = {z1, z1}; return z;
1218 }
1219
1220 FLINT_FORCE_INLINE void vec4d_store(double* z, vec4d a)
1221 {
1222 vec2d_store(z+0, a.e1);
1223 vec2d_store(z+2, a.e2);
1224 }
1225
1226 FLINT_FORCE_INLINE void vec4d_store_aligned(double* z, vec4d a)
1227 {
1228 vec2d_store_aligned(z+0, a.e1);
1229 vec2d_store_aligned(z+2, a.e2);
1230 }
1231
1232 FLINT_FORCE_INLINE void vec4d_store_unaligned(double* z, vec4d a)
1233 {
1234 vec2d_store_unaligned(z+0, a.e1);
1235 vec2d_store_unaligned(z+2, a.e2);
1236 }
1237
1238 FLINT_FORCE_INLINE vec4d vec4d_load(const double* a)
1239 {
1240 return vec4d_set_vec2d2(vec2d_load(a+0),
1241 vec2d_load(a+2));
1242 }
1243
1244 FLINT_FORCE_INLINE vec4d vec4d_load_aligned(const double* a)
1245 {
1246 return vec4d_set_vec2d2(vec2d_load_aligned(a+0),
1247 vec2d_load_aligned(a+2));
1248 }
1249
1250 FLINT_FORCE_INLINE vec4d vec4d_load_unaligned(const double* a)
1251 {
1252 return vec4d_set_vec2d2(vec2d_load_unaligned(a+0),
1253 vec2d_load_unaligned(a+2));
1254 }
1255
1256 FLINT_FORCE_INLINE vec4d vec4d_permute_0_2_1_3(vec4d a)
1257 {
1258 return vec4d_set_vec2d2(vec2d_unpacklo(a.e1, a.e2),
1259 vec2d_unpackhi(a.e1, a.e2));
1260 }
1261
1262 FLINT_FORCE_INLINE vec4d vec4d_permute_3_2_1_0(vec4d a) {
1263 return vec4d_set_vec2d2(vextq_f64(a.e2, a.e2, 1),
1264 vextq_f64(a.e1, a.e1, 1));
1265 }
1266
1267 FLINT_FORCE_INLINE vec4d vec4d_permute_3_1_2_0(vec4d a) {
1268 vec2d z1 = vzip2q_f64(a.e2, a.e1);
1269 vec2d z2 = vzip1q_f64(a.e2, a.e1);
1270 return vec4d_set_vec2d2(z1, z2);
1271 }
1272
1273 FLINT_FORCE_INLINE vec4d vec4d_permute2_0_2(vec4d a, vec4d b) {
1274 return vec4d_set_vec2d2(a.e1, b.e1);
1275 }
1276
1277 FLINT_FORCE_INLINE vec4d vec4d_permute2_1_3(vec4d a, vec4d b) {
1278 return vec4d_set_vec2d2(a.e2, b.e2);
1279 }
1280
1281 FLINT_FORCE_INLINE vec4d vec4d_unpack_lo_permute_0_2_1_3(vec4d u, vec4d v) {
1282 return vec4d_set_vec2d2(vec2d_unpacklo(u.e1, u.e2),
1283 vec2d_unpacklo(v.e1, v.e2));
1284 }
1285
1286 FLINT_FORCE_INLINE vec4d vec4d_unpack_hi_permute_0_2_1_3(vec4d u, vec4d v) {
1287 return vec4d_set_vec2d2(vec2d_unpackhi(u.e1, u.e2),
1288 vec2d_unpackhi(v.e1, v.e2));
1289 }
1290
1291 FLINT_FORCE_INLINE vec4d vec4d_unpackhi_permute_3_1_2_0(vec4d u, vec4d v) {
1292 return vec4d_set_vec2d2(vec2d_unpackhi(v.e2, v.e1),
1293 vec2d_unpackhi(u.e2, u.e1));
1294 }
1295
1296 FLINT_FORCE_INLINE vec4d vec4d_unpacklo_permute_3_1_2_0(vec4d u, vec4d v) {
1297 return vec4d_set_vec2d2(vec2d_unpacklo(v.e2, v.e1),
1298 vec2d_unpacklo(u.e2, u.e1));
1299 }
1300
1301 #define VEC4D_TRANSPOSE(z0, z1, z2, z3, a0, a1, a2, a3) \
1302 { \
1303 vec4d _t0, _t1, _t2, _t3; \
1304 _t0 = vec4d_unpacklo(a0, a1); \
1305 _t1 = vec4d_unpackhi(a0, a1); \
1306 _t2 = vec4d_unpacklo(a2, a3); \
1307 _t3 = vec4d_unpackhi(a2, a3); \
1308 z0 = vec4d_permute2_0_2(_t0, _t2); \
1309 z1 = vec4d_permute2_0_2(_t1, _t3); \
1310 z2 = vec4d_permute2_1_3(_t0, _t2); \
1311 z3 = vec4d_permute2_1_3(_t1, _t3); \
1312 }
1313
1314 EXTEND_VEC_DEF0(vec2d, vec4d, _zero)
1315 EXTEND_VEC_DEF0(vec2d, vec4d, _one)
1316 EXTEND_VEC_DEF1(vec2d, vec4d, _neg)
1317 EXTEND_VEC_DEF1(vec2d, vec4d, _round)
1318 EXTEND_VEC_DEF2(vec2d, vec4d, _add)
1319 EXTEND_VEC_DEF2(vec2d, vec4d, _sub)
1320 EXTEND_VEC_DEF2(vec2d, vec4d, _min)
1321 EXTEND_VEC_DEF2(vec2d, vec4d, _max)
1322 EXTEND_VEC_DEF2(vec2d, vec4d, _mul)
1323 EXTEND_VEC_DEF2(vec2d, vec4d, _div)
1324 EXTEND_VEC_DEF2(vec2d, vec4d, _reduce_pm1n_to_pmhn)
1325 EXTEND_VEC_DEF2(vec2d, vec4d, _reduce_pm1no_to_0n)
1326 EXTEND_VEC_DEF2(vec2d, vec4d, _unpacklo)
1327 EXTEND_VEC_DEF2(vec2d, vec4d, _unpackhi)
1328 EXTEND_VEC_DEF3(vec2d, vec4d, _reduce_to_pm1n)
1329 EXTEND_VEC_DEF3(vec2d, vec4d, _reduce_to_pm1no)
1330 EXTEND_VEC_DEF3(vec2d, vec4d, _reduce_to_0n)
1331 EXTEND_VEC_DEF3(vec2d, vec4d, _fmadd)
1332 EXTEND_VEC_DEF3(vec2d, vec4d, _fmsub)
1333 EXTEND_VEC_DEF3(vec2d, vec4d, _fnmadd)
1334 EXTEND_VEC_DEF3(vec2d, vec4d, _fnmsub)
1335 EXTEND_VEC_DEF3(vec2d, vec4d, _blendv)
1336 EXTEND_VEC_DEF4(vec2d, vec4d, _mulmod)
1337 EXTEND_VEC_DEF4(vec2d, vec4d, _nmulmod)
1338
1339
1340
1341
1342 FLINT_FORCE_INLINE vec8d vec8d_set_vec4d2(vec4d a, vec4d b) {
1343 vec8d z = {a, b}; return z;
1344 }
1345
1346 FLINT_FORCE_INLINE double vec8d_get_index(vec8d a, int i) {
1347 return i < 4 ? vec4d_get_index(a.e1, i) : vec4d_get_index(a.e2, i - 4);
1348 }
1349
1350 FLINT_FORCE_INLINE vec8d vec8d_set_d8(double a0, double a1, double a2, double a3,
1351 double a4, double a5, double a6, double a7)
1352 {
1353 vec4d z1 = vec4d_set_d4(a0, a1, a2, a3);
1354 vec4d z2 = vec4d_set_d4(a4, a5, a6, a7);
1355 vec8d z = {z1, z2}; return z;
1356 }
1357
1358 FLINT_FORCE_INLINE vec8d vec8d_set_d(double a)
1359 {
1360 vec4d z1 = vec4d_set_d(a);
1361 vec8d z = {z1, z1}; return z;
1362 }
1363
1364 FLINT_FORCE_INLINE void vec8d_store(double* z, vec8d a)
1365 {
1366 vec4d_store(z+0, a.e1);
1367 vec4d_store(z+4, a.e2);
1368 }
1369
1370 FLINT_FORCE_INLINE void vec8d_store_aligned(double* z, vec8d a)
1371 {
1372 vec4d_store_aligned(z+0, a.e1);
1373 vec4d_store_aligned(z+4, a.e2);
1374 }
1375
1376 FLINT_FORCE_INLINE void vec8d_store_unaligned(double* z, vec8d a)
1377 {
1378 vec4d_store_unaligned(z+0, a.e1);
1379 vec4d_store_unaligned(z+4, a.e2);
1380 }
1381
1382
1383 FLINT_FORCE_INLINE vec8d vec8d_load(const double* a)
1384 {
1385 vec4d z1 = vec4d_load(a+0);
1386 vec4d z2 = vec4d_load(a+4);
1387 vec8d z = {z1, z2}; return z;
1388 }
1389
1390 FLINT_FORCE_INLINE vec8d vec8d_load_aligned(const double* a)
1391 {
1392 vec4d z1 = vec4d_load_aligned(a+0);
1393 vec4d z2 = vec4d_load_aligned(a+4);
1394 vec8d z = {z1, z2}; return z;
1395 }
1396
1397 FLINT_FORCE_INLINE vec8d vec8d_load_unaligned(const double* a)
1398 {
1399 vec4d z1 = vec4d_load_unaligned(a+0);
1400 vec4d z2 = vec4d_load_unaligned(a+4);
1401 vec8d z = {z1, z2}; return z;
1402 }
1403
1404
1405 EXTEND_VEC_DEF0(vec4d, vec8d, _zero)
1406 EXTEND_VEC_DEF0(vec4d, vec8d, _one)
1407 EXTEND_VEC_DEF1(vec4d, vec8d, _neg)
1408 EXTEND_VEC_DEF1(vec4d, vec8d, _round)
1409 EXTEND_VEC_DEF2(vec4d, vec8d, _add)
1410 EXTEND_VEC_DEF2(vec4d, vec8d, _sub)
1411 EXTEND_VEC_DEF2(vec4d, vec8d, _min)
1412 EXTEND_VEC_DEF2(vec4d, vec8d, _max)
1413 EXTEND_VEC_DEF2(vec4d, vec8d, _mul)
1414 EXTEND_VEC_DEF2(vec4d, vec8d, _div)
1415 EXTEND_VEC_DEF2(vec4d, vec8d, _reduce_pm1n_to_pmhn)
1416 EXTEND_VEC_DEF2(vec4d, vec8d, _reduce_pm1no_to_0n)
1417 EXTEND_VEC_DEF2(vec4d, vec8d, _unpacklo)
1418 EXTEND_VEC_DEF2(vec4d, vec8d, _unpackhi)
1419 EXTEND_VEC_DEF3(vec4d, vec8d, _reduce_to_pm1n)
1420 EXTEND_VEC_DEF3(vec4d, vec8d, _reduce_to_pm1no)
1421 EXTEND_VEC_DEF3(vec4d, vec8d, _reduce_to_0n)
1422 EXTEND_VEC_DEF3(vec4d, vec8d, _fmadd)
1423 EXTEND_VEC_DEF3(vec4d, vec8d, _fmsub)
1424 EXTEND_VEC_DEF3(vec4d, vec8d, _fnmadd)
1425 EXTEND_VEC_DEF3(vec4d, vec8d, _fnmsub)
1426 EXTEND_VEC_DEF3(vec4d, vec8d, _blendv)
1427 EXTEND_VEC_DEF4(vec4d, vec8d, _mulmod)
1428 EXTEND_VEC_DEF4(vec4d, vec8d, _nmulmod)
1429
1430
1431
1432
1433 FLINT_FORCE_INLINE int vec2d_same(vec2d a, vec2d b) {
1434 return a[0] == b[0] && a[1] == b[1];
1435 }
1436
1437
1438 #define DEFINE_IT(V) \
1439 FLINT_FORCE_INLINE int V##_same_mod(V a, V b, V n, V ninv) { \
1440 return V##_same(V##_reduce_to_0n(a, n, ninv), V##_reduce_to_0n(b, n, ninv)); \
1441 }
1442 DEFINE_IT(vec1d)
1443 DEFINE_IT(vec2d)
1444 #undef DEFINE_IT
1445
1446
1447
1448
1449
1450 FLINT_FORCE_INLINE void vec1n_store_unaligned(ulong* z, vec1n a) {
1451 z[0] = a;
1452 }
1453
1454 FLINT_FORCE_INLINE vec1n vec1d_convert_limited_vec1n(vec1d a) {
1455 return (slong)a;
1456 }
1457
1458
1459 FLINT_FORCE_INLINE vec1n vec1n_addmod(vec1n a, vec1n b, vec1n n) {
1460 vec1n nmb = n - b;
1461 return nmb > a ? a + b : a - nmb;
1462 }
1463
1464
1465
1466 FLINT_FORCE_INLINE vec2d vec2n_convert_limited_vec2d(vec2n a) {
1467 float64x2_t t = vdupq_n_f64(0x1.0p52);
1468 return vsubq_f64(vreinterpretq_f64_u64(vorrq_u64(a, vreinterpretq_u64_f64(t))), t);
1469 }
1470
1471 FLINT_FORCE_INLINE void vec2n_store_unaligned(ulong* z, vec2n a) {
1472 vst1q_u64((uint64_t *) z, a);
1473 }
1474
1475 FLINT_FORCE_INLINE vec2n vec2d_convert_limited_vec2n(vec2d a) {
1476 return vcvtnq_u64_f64(a);
1477 }
1478
1479 FLINT_FORCE_INLINE vec2n vec2n_set_n(ulong a) {
1480 vec2n x = vdupq_n_u64(a);
1481 return x;
1482 }
1483
1484 FLINT_FORCE_INLINE vec2n vec2n_load_unaligned(const ulong* a) {
1485 return vld1q_u64((const uint64_t *) a);
1486 }
1487
1488
1489 FLINT_FORCE_INLINE vec2n vec2n_bit_shift_right_32(vec2n a) {
1490 return vshrq_n_u64(a, 32);
1491 }
1492
1493
1494 FLINT_FORCE_INLINE vec2n vec2n_bit_and(vec2n a, vec2n b) {
1495 return vandq_u64(a, b);
1496 }
1497
1498
1499 FLINT_FORCE_INLINE vec2n vec2n_add(vec2n a, vec2n b) {
1500 return vaddq_u64(a, b);
1501 }
1502
1503
1504 FLINT_FORCE_INLINE vec2n vec2n_sub(vec2n a, vec2n b) {
1505 return vsubq_u64(a, b);
1506 }
1507
1508
1509 FLINT_FORCE_INLINE vec2n vec2n_addmod(vec2n a, vec2n b, vec2n n) {
1510 vec2n nmb = vec2n_sub(n, b);
1511 vec2n sum = vec2n_sub(a, nmb);
1512
1513 vec2n mask = vcgtq_u64(nmb, a);
1514
1515 return vec2n_add(sum, vandq_u64(n, mask));
1516 }
1517
1518
1519 FLINT_FORCE_INLINE vec2n vec2n_addmod_limited(vec2n a, vec2n b, vec2n n) {
1520 vec2n s = vec2n_add(a, b);
1521
1522 vec2n mask = vcgeq_u64(s, n);
1523
1524 return vec2n_sub(s, vandq_u64(n, mask));
1525 }
1526
1527
1528
1529 FLINT_FORCE_INLINE vec4d vec4n_convert_limited_vec4d(vec4n a) {
1530 vec2d z1 = vec2n_convert_limited_vec2d(a.e1);
1531 vec2d z2 = vec2n_convert_limited_vec2d(a.e2);
1532 vec4d z = {z1, z2}; return z;
1533 }
1534
1535 FLINT_FORCE_INLINE void vec4n_store_unaligned(ulong* z, vec4n a) {
1536 vec2n_store_unaligned(z+0, a.e1);
1537 vec2n_store_unaligned(z+2, a.e2);
1538 }
1539
1540 FLINT_FORCE_INLINE vec4n vec4d_convert_limited_vec4n(vec4d a) {
1541 vec2n z1 = vec2d_convert_limited_vec2n(a.e1);
1542 vec2n z2 = vec2d_convert_limited_vec2n(a.e2);
1543 vec4n z = {z1, z2}; return z;
1544 }
1545
1546 FLINT_FORCE_INLINE vec4n vec4n_set_n(ulong a) {
1547 vec2n x = vec2n_set_n(a);
1548 vec4n z = {x, x};
1549 return z;
1550 }
1551
1552 FLINT_FORCE_INLINE vec4n vec4n_load_unaligned(const ulong* a) {
1553 vec2n z1 = vec2n_load_unaligned(a+0);
1554 vec2n z2 = vec2n_load_unaligned(a+2);
1555 vec4n z = {z1, z2}; return z;
1556 }
1557
1558 EXTEND_VEC_DEF1(vec2n, vec4n, _bit_shift_right_32)
1559 EXTEND_VEC_DEF2(vec2n, vec4n, _bit_and)
1560 EXTEND_VEC_DEF2(vec2n, vec4n, _add)
1561 EXTEND_VEC_DEF2(vec2n, vec4n, _sub)
1562 EXTEND_VEC_DEF3(vec2n, vec4n, _addmod)
1563 EXTEND_VEC_DEF3(vec2n, vec4n, _addmod_limited)
1564
1565
1566
1567 FLINT_FORCE_INLINE vec8d vec8n_convert_limited_vec8d(vec8n a) {
1568 vec4d z1 = vec4n_convert_limited_vec4d(a.e1);
1569 vec4d z2 = vec4n_convert_limited_vec4d(a.e2);
1570 vec8d z = {z1, z2}; return z;
1571 }
1572
1573 FLINT_FORCE_INLINE vec8n vec8n_set_n(ulong a) {
1574 vec4n x = vec4n_set_n(a);
1575 vec8n z = {x, x};
1576 return z;
1577 }
1578
1579 FLINT_FORCE_INLINE vec8n vec8n_load_unaligned(const ulong* a)
1580 {
1581 vec4n z1 = vec4n_load_unaligned(a+0);
1582 vec4n z2 = vec4n_load_unaligned(a+4);
1583 vec8n z = {z1, z2}; return z;
1584 }
1585
1586
1587 EXTEND_VEC_DEF1(vec4n, vec8n, _bit_shift_right_32)
1588 EXTEND_VEC_DEF2(vec4n, vec8n, _bit_and)
1589 EXTEND_VEC_DEF2(vec4n, vec8n, _add)
1590 EXTEND_VEC_DEF2(vec4n, vec8n, _sub)
1591 EXTEND_VEC_DEF3(vec4n, vec8n, _addmod)
1592 EXTEND_VEC_DEF3(vec4n, vec8n, _addmod_limited)
1593
1594
1595 #if 0
1596
1597
1598
1599
1600
1601
1602
1603 FLINT_FORCE_INLINE vec2n vec2n_bit_shift_right(vec2n a, ulong n)
1604 {
1605 return vshrq_n_u64(a, n);
1606 }
1607
1608 FLINT_FORCE_INLINE vec4n vec4n_bit_shift_right(vec4n a, ulong n)
1609 {
1610 vec4n z = {vec2n_bit_shift_right(a.e1, n), vec2n_bit_shift_right(a.e2, n)};
1611 return z;
1612 }
1613
1614 FLINT_FORCE_INLINE vec8n vec8n_bit_shift_right(vec8n a, ulong n)
1615 {
1616 vec8n z = {vec4n_bit_shift_right(a.e1, n), vec4n_bit_shift_right(a.e2, n)};
1617 return z;
1618 }
1619 #endif
1620
1621
1622 #undef EXTEND_VEC_DEF4
1623 #undef EXTEND_VEC_DEF3
1624 #undef EXTEND_VEC_DEF2
1625 #undef EXTEND_VEC_DEF1
1626 #undef EXTEND_VEC_DEF0
1627
1628
1629 #else
1630
1631 #error machine_vector.h not implemented
1632
1633 #endif
1634
1635
1636 #ifdef __cplusplus
1637 }
1638 #endif
1639
1640 #endif