arnaucube
arnaucube/poulpyPublic Self-hosted repository
poulpy/poulpy-backend/src/cpu_spqlios/spqlios-arithmetic/spqlios/coeffs/coeffs_arithmetic_avx.c
poulpy-backend/src/cpu_spqlios/spqlios-arithmetic/spqlios/coeffs/coeffs_arithmetic_avx.cRaw
  1#include <immintrin.h>
  2
  3#include "../commons_private.h"
  4#include "coeffs_arithmetic.h"
  5
  6// res = a + b. dimension n must be a power of 2
  7EXPORT void znx_add_i64_avx(uint64_t nn, int64_t* res, const int64_t* a, const int64_t* b) {
  8  if (nn <= 2) {
  9    if (nn == 1) {
 10      res[0] = a[0] + b[0];
 11    } else {
 12      _mm_storeu_si128((__m128i*)res,                     //
 13                       _mm_add_epi64(                     //
 14                           _mm_loadu_si128((__m128i*)a),  //
 15                           _mm_loadu_si128((__m128i*)b)));
 16    }
 17  } else {
 18    const __m256i* aa = (__m256i*)a;
 19    const __m256i* bb = (__m256i*)b;
 20    __m256i* rr = (__m256i*)res;
 21    __m256i* const rrend = (__m256i*)(res + nn);
 22    do {
 23      _mm256_storeu_si256(rr,                          //
 24                          _mm256_add_epi64(            //
 25                              _mm256_loadu_si256(aa),  //
 26                              _mm256_loadu_si256(bb)));
 27      ++rr;
 28      ++aa;
 29      ++bb;
 30    } while (rr < rrend);
 31  }
 32}
 33
 34// res = a - b. dimension n must be a power of 2
 35EXPORT void znx_sub_i64_avx(uint64_t nn, int64_t* res, const int64_t* a, const int64_t* b) {
 36  if (nn <= 2) {
 37    if (nn == 1) {
 38      res[0] = a[0] - b[0];
 39    } else {
 40      _mm_storeu_si128((__m128i*)res,                     //
 41                       _mm_sub_epi64(                     //
 42                           _mm_loadu_si128((__m128i*)a),  //
 43                           _mm_loadu_si128((__m128i*)b)));
 44    }
 45  } else {
 46    const __m256i* aa = (__m256i*)a;
 47    const __m256i* bb = (__m256i*)b;
 48    __m256i* rr = (__m256i*)res;
 49    __m256i* const rrend = (__m256i*)(res + nn);
 50    do {
 51      _mm256_storeu_si256(rr,                          //
 52                          _mm256_sub_epi64(            //
 53                              _mm256_loadu_si256(aa),  //
 54                              _mm256_loadu_si256(bb)));
 55      ++rr;
 56      ++aa;
 57      ++bb;
 58    } while (rr < rrend);
 59  }
 60}
 61
 62EXPORT void znx_negate_i64_avx(uint64_t nn, int64_t* res, const int64_t* a) {
 63  if (nn <= 2) {
 64    if (nn == 1) {
 65      res[0] = -a[0];
 66    } else {
 67      _mm_storeu_si128((__m128i*)res,           //
 68                       _mm_sub_epi64(           //
 69                           _mm_set1_epi64x(0),  //
 70                           _mm_loadu_si128((__m128i*)a)));
 71    }
 72  } else {
 73    const __m256i* aa = (__m256i*)a;
 74    __m256i* rr = (__m256i*)res;
 75    __m256i* const rrend = (__m256i*)(res + nn);
 76    do {
 77      _mm256_storeu_si256(rr,                         //
 78                          _mm256_sub_epi64(           //
 79                              _mm256_set1_epi64x(0),  //
 80                              _mm256_loadu_si256(aa)));
 81      ++rr;
 82      ++aa;
 83    } while (rr < rrend);
 84  }
 85}
 86
 87EXPORT void rnx_divide_by_m_avx(uint64_t n, double m, double* res, const double* a) {
 88  // TODO: see if there is a faster way of dividing by a power of 2?
 89  const double invm = 1. / m;
 90  if (n < 8) {
 91    switch (n) {
 92      case 1:
 93        *res = *a * invm;
 94        break;
 95      case 2:
 96        _mm_storeu_pd(res,                         //
 97                      _mm_mul_pd(_mm_loadu_pd(a),  //
 98                                 _mm_set1_pd(invm)));
 99        break;
100      case 4:
101        _mm256_storeu_pd(res,                               //
102                         _mm256_mul_pd(_mm256_loadu_pd(a),  //
103                                       _mm256_set1_pd(invm)));
104        break;
105      default:
106        NOT_SUPPORTED();  // non-power of 2
107    }
108    return;
109  }
110  const __m256d invm256 = _mm256_set1_pd(invm);
111  double* rr = res;
112  const double* aa = a;
113  const double* const aaend = a + n;
114  do {
115    _mm256_storeu_pd(rr,                                 //
116                     _mm256_mul_pd(_mm256_loadu_pd(aa),  //
117                                   invm256));
118    _mm256_storeu_pd(rr + 4,                                 //
119                     _mm256_mul_pd(_mm256_loadu_pd(aa + 4),  //
120                                   invm256));
121    rr += 8;
122    aa += 8;
123  } while (aa < aaend);
124}