Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-11-07 10:15:27

0001 /*
0002     Copyright (C) 2022 Daniel Schultz
0003     Copyright (C) 2023 Mathieu Gouttenoire
0004 
0005     This file is part of FLINT.
0006 
0007     FLINT is free software: you can redistribute it and/or modify it under
0008     the terms of the GNU Lesser General Public License (LGPL) as published
0009     by the Free Software Foundation; either version 3 of the License, or
0010     (at your option) any later version.  See <https://www.gnu.org/licenses/>.
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     In general the machine vector types should either be passed by const ref or
0044     the whole function should be forced inline as some platforms have buggy
0045     pass by value.
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 /* vec1d -- AVX2 ***********************************************************/
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 /* [0,n] -> [-n/2, n/2] */
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 /* [0,2n) to [0,n) */
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 /* vec4d -- AVX2 ***********************************************************/
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 // return {a[0], b[0], a[2], b[2]}
0347 FLINT_FORCE_INLINE vec4d vec4d_unpacklo(vec4d a, vec4d b) {
0348     return _mm256_unpacklo_pd(a, b);
0349 }
0350 
0351 // return {a[1], b[1], a[3], b[3]}
0352 FLINT_FORCE_INLINE vec4d vec4d_unpackhi(vec4d a, vec4d b) {
0353     return _mm256_unpackhi_pd(a, b);
0354 }
0355 
0356 /* permute_i0_i1_i2_i3(a): return {a[i0], a[i1], a[i2], a[i3]} */
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 /* permute2_i0_i1(a):  return {v[i0], v[i1]}
0374                     |   v[0]     |    v[1]    |    v[2]    |   v[3]     |
0375                       a[0], a[1]   a[2], a[3]   b[0], b[1]   b[2], b[3]
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 /* view the 4 vectors as the rows of a 4x4 matrix */
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 /* [0,2n) to [0,n) */
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 /* vec4n -- AVX2 ***********************************************************/
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 /* permute_i0_i1_i2_i3(a): return {a[i0], a[i1], a[i2], a[i3]} */
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 /* for n < 2^63 */
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 // compilers accept non-(compile-time-)constant b with srli
0537 // (still, faster if constant)
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 // horizontal sum
0554 FLINT_FORCE_INLINE ulong vec4n_horizontal_sum(vec4n a) {
0555     vec4n a_hi = _mm256_shuffle_epi32(a, 14);  // 14 == 0b00001110
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 /* vec8d -- AVX2 ***********************************************************/
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 /* !!! the outputs are also permuted !!! */
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 /* reduce_pm1no_to_0n(a, n): return a mod n in [0,n) assuming a in (-n,n) */
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 /* reduce_to_pm1n(a, n, ninv): return a mod n in [-n,n] */
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 /* reduce_to_pm1n(a, n, ninv): return a mod n in (-n,n) */
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 /* reduce_to_0n(a, n, ninv): return a mod n in [0,n) */
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     mulmod(a, b, n, 1.0/n): return a*b mod n
0682     assuming fft_small_mulmod_satisfies_bounds(n):
0683      Products a*b in the range (-2*n^2, 2*n^2) are reduced to the range (-1*n, 1*n).
0684      Products a*b in the range (-4*n^2, 4*n^2) are reduced to the range (-3/2*n, 3/2*n).
0685     otherwise the more pessimistic:
0686      Products a*b in the range (-2*n^2, 2*n^2) are reduced to the range (-9/8*n, 9/8*n).
0687      Products a*b in the range (-4*n^2, 4*n^2) are reduced to the range (-7/4*n, 7/4*n).
0688     floating point round mode is always assumed to be set to nearest
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 /* vec8n -- AVX2 ***********************************************************/
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 /* floating point stuff ******************************************************/
0861 
0862 /* vec1d -- NEON/ARM64 *********************************************/
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 /* [0,n] -> [-n/2, n/2] */
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 /* vec2d -- NEON/ARM64 *********************************************/
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 /* these two might be slow due to the extra negation */
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 /* mulmod(a, b, n, ninv): return a*b mod n in [-n,n] with assumptions */
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 /* vec4d -- NEON/ARM64 *********************************************/
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 /* vec8d -- NEON/ARM64 *********************************************/
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 /* integer stuff *************************************************************/
1447 
1448 /* vec1n -- NEON/ARM64 *********************************************/
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 // (a + b) % n
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 /* vec2n -- NEON/ARM64 *********************************************/
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 // Right shift 32bits
1489 FLINT_FORCE_INLINE vec2n vec2n_bit_shift_right_32(vec2n a) {
1490     return vshrq_n_u64(a, 32);
1491 }
1492 
1493 // AND operation
1494 FLINT_FORCE_INLINE vec2n vec2n_bit_and(vec2n a, vec2n b) {
1495     return vandq_u64(a, b);
1496 }
1497 
1498 // Addition
1499 FLINT_FORCE_INLINE vec2n vec2n_add(vec2n a, vec2n b) {
1500     return vaddq_u64(a, b);
1501 }
1502 
1503 // Substraction
1504 FLINT_FORCE_INLINE vec2n vec2n_sub(vec2n a, vec2n b) {
1505     return vsubq_u64(a, b);
1506 }
1507 
1508 // (a + b) % n
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 // (a + b) % n for n < 2^63
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 /* vec4n -- NEON/ARM64 *********************************************/
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 /* vec8n -- NEON/ARM64 *********************************************/
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     vshrq_n_u64(a, n) cannot be used because n must be a compile-time
1598     constant, and the compiler doesn't see that n is constant
1599     even if the function is forced inline.
1600     And vshlq_s64(a, vdupq_n_s64(-(slong) n)) cannot be used to emulate
1601     vshrq_n_u64(a, n) as it propagates the sign bit.
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