arnaucube
arnaucube/poulpyPublic Self-hosted repository
poulpy/poulpy-backend/src/cpu_spqlios/spqlios-arithmetic/spqlios/arithmetic/vec_rnx_arithmetic_avx.c
poulpy-backend/src/cpu_spqlios/spqlios-arithmetic/spqlios/arithmetic/vec_rnx_arithmetic_avx.cRaw
  1#include <immintrin.h>
  2#include <string.h>
  3
  4#include "vec_rnx_arithmetic_private.h"
  5
  6void rnx_add_avx(uint64_t nn, double* res, const double* a, const double* b) {
  7  if (nn < 8) {
  8    if (nn == 4) {
  9      _mm256_storeu_pd(res, _mm256_add_pd(_mm256_loadu_pd(a), _mm256_loadu_pd(b)));
 10    } else if (nn == 2) {
 11      _mm_storeu_pd(res, _mm_add_pd(_mm_loadu_pd(a), _mm_loadu_pd(b)));
 12    } else if (nn == 1) {
 13      *res = *a + *b;
 14    } else {
 15      NOT_SUPPORTED();  // not a power of 2
 16    }
 17    return;
 18  }
 19  // general case: nn >= 8
 20  __m256d x0, x1, x2, x3, x4, x5;
 21  const double* aa = a;
 22  const double* bb = b;
 23  double* rr = res;
 24  double* const rrend = res + nn;
 25  do {
 26    x0 = _mm256_loadu_pd(aa);
 27    x1 = _mm256_loadu_pd(aa + 4);
 28    x2 = _mm256_loadu_pd(bb);
 29    x3 = _mm256_loadu_pd(bb + 4);
 30    x4 = _mm256_add_pd(x0, x2);
 31    x5 = _mm256_add_pd(x1, x3);
 32    _mm256_storeu_pd(rr, x4);
 33    _mm256_storeu_pd(rr + 4, x5);
 34    aa += 8;
 35    bb += 8;
 36    rr += 8;
 37  } while (rr < rrend);
 38}
 39
 40void rnx_sub_avx(uint64_t nn, double* res, const double* a, const double* b) {
 41  if (nn < 8) {
 42    if (nn == 4) {
 43      _mm256_storeu_pd(res, _mm256_sub_pd(_mm256_loadu_pd(a), _mm256_loadu_pd(b)));
 44    } else if (nn == 2) {
 45      _mm_storeu_pd(res, _mm_sub_pd(_mm_loadu_pd(a), _mm_loadu_pd(b)));
 46    } else if (nn == 1) {
 47      *res = *a - *b;
 48    } else {
 49      NOT_SUPPORTED();  // not a power of 2
 50    }
 51    return;
 52  }
 53  // general case: nn >= 8
 54  __m256d x0, x1, x2, x3, x4, x5;
 55  const double* aa = a;
 56  const double* bb = b;
 57  double* rr = res;
 58  double* const rrend = res + nn;
 59  do {
 60    x0 = _mm256_loadu_pd(aa);
 61    x1 = _mm256_loadu_pd(aa + 4);
 62    x2 = _mm256_loadu_pd(bb);
 63    x3 = _mm256_loadu_pd(bb + 4);
 64    x4 = _mm256_sub_pd(x0, x2);
 65    x5 = _mm256_sub_pd(x1, x3);
 66    _mm256_storeu_pd(rr, x4);
 67    _mm256_storeu_pd(rr + 4, x5);
 68    aa += 8;
 69    bb += 8;
 70    rr += 8;
 71  } while (rr < rrend);
 72}
 73
 74void rnx_negate_avx(uint64_t nn, double* res, const double* b) {
 75  if (nn < 8) {
 76    if (nn == 4) {
 77      _mm256_storeu_pd(res, _mm256_sub_pd(_mm256_set1_pd(0), _mm256_loadu_pd(b)));
 78    } else if (nn == 2) {
 79      _mm_storeu_pd(res, _mm_sub_pd(_mm_set1_pd(0), _mm_loadu_pd(b)));
 80    } else if (nn == 1) {
 81      *res = -*b;
 82    } else {
 83      NOT_SUPPORTED();  // not a power of 2
 84    }
 85    return;
 86  }
 87  // general case: nn >= 8
 88  __m256d x2, x3, x4, x5;
 89  const __m256d ZERO = _mm256_set1_pd(0);
 90  const double* bb = b;
 91  double* rr = res;
 92  double* const rrend = res + nn;
 93  do {
 94    x2 = _mm256_loadu_pd(bb);
 95    x3 = _mm256_loadu_pd(bb + 4);
 96    x4 = _mm256_sub_pd(ZERO, x2);
 97    x5 = _mm256_sub_pd(ZERO, x3);
 98    _mm256_storeu_pd(rr, x4);
 99    _mm256_storeu_pd(rr + 4, x5);
100    bb += 8;
101    rr += 8;
102  } while (rr < rrend);
103}
104
105/** @brief sets res = a + b */
106EXPORT void vec_rnx_add_avx(                          //
107    const MOD_RNX* module,                            // N
108    double* res, uint64_t res_size, uint64_t res_sl,  // res
109    const double* a, uint64_t a_size, uint64_t a_sl,  // a
110    const double* b, uint64_t b_size, uint64_t b_sl   // b
111) {
112  const uint64_t nn = module->n;
113  if (a_size < b_size) {
114    const uint64_t msize = res_size < a_size ? res_size : a_size;
115    const uint64_t nsize = res_size < b_size ? res_size : b_size;
116    for (uint64_t i = 0; i < msize; ++i) {
117      rnx_add_avx(nn, res + i * res_sl, a + i * a_sl, b + i * b_sl);
118    }
119    for (uint64_t i = msize; i < nsize; ++i) {
120      memcpy(res + i * res_sl, b + i * b_sl, nn * sizeof(double));
121    }
122    for (uint64_t i = nsize; i < res_size; ++i) {
123      memset(res + i * res_sl, 0, nn * sizeof(double));
124    }
125  } else {
126    const uint64_t msize = res_size < b_size ? res_size : b_size;
127    const uint64_t nsize = res_size < a_size ? res_size : a_size;
128    for (uint64_t i = 0; i < msize; ++i) {
129      rnx_add_avx(nn, res + i * res_sl, a + i * a_sl, b + i * b_sl);
130    }
131    for (uint64_t i = msize; i < nsize; ++i) {
132      memcpy(res + i * res_sl, a + i * a_sl, nn * sizeof(double));
133    }
134    for (uint64_t i = nsize; i < res_size; ++i) {
135      memset(res + i * res_sl, 0, nn * sizeof(double));
136    }
137  }
138}
139
140/** @brief sets res = -a */
141EXPORT void vec_rnx_negate_avx(                       //
142    const MOD_RNX* module,                            // N
143    double* res, uint64_t res_size, uint64_t res_sl,  // res
144    const double* a, uint64_t a_size, uint64_t a_sl   // a
145) {
146  const uint64_t nn = module->n;
147  const uint64_t msize = res_size < a_size ? res_size : a_size;
148  for (uint64_t i = 0; i < msize; ++i) {
149    rnx_negate_avx(nn, res + i * res_sl, a + i * a_sl);
150  }
151  for (uint64_t i = msize; i < res_size; ++i) {
152    memset(res + i * res_sl, 0, nn * sizeof(double));
153  }
154}
155
156/** @brief sets res = a - b */
157EXPORT void vec_rnx_sub_avx(                          //
158    const MOD_RNX* module,                            // N
159    double* res, uint64_t res_size, uint64_t res_sl,  // res
160    const double* a, uint64_t a_size, uint64_t a_sl,  // a
161    const double* b, uint64_t b_size, uint64_t b_sl   // b
162) {
163  const uint64_t nn = module->n;
164  if (a_size < b_size) {
165    const uint64_t msize = res_size < a_size ? res_size : a_size;
166    const uint64_t nsize = res_size < b_size ? res_size : b_size;
167    for (uint64_t i = 0; i < msize; ++i) {
168      rnx_sub_avx(nn, res + i * res_sl, a + i * a_sl, b + i * b_sl);
169    }
170    for (uint64_t i = msize; i < nsize; ++i) {
171      rnx_negate_avx(nn, res + i * res_sl, b + i * b_sl);
172    }
173    for (uint64_t i = nsize; i < res_size; ++i) {
174      memset(res + i * res_sl, 0, nn * sizeof(double));
175    }
176  } else {
177    const uint64_t msize = res_size < b_size ? res_size : b_size;
178    const uint64_t nsize = res_size < a_size ? res_size : a_size;
179    for (uint64_t i = 0; i < msize; ++i) {
180      rnx_sub_avx(nn, res + i * res_sl, a + i * a_sl, b + i * b_sl);
181    }
182    for (uint64_t i = msize; i < nsize; ++i) {
183      memcpy(res + i * res_sl, a + i * a_sl, nn * sizeof(double));
184    }
185    for (uint64_t i = nsize; i < res_size; ++i) {
186      memset(res + i * res_sl, 0, nn * sizeof(double));
187    }
188  }
189}