arnaucube
arnaucube/poulpyPublic Self-hosted repository
poulpy/spqlios/lib/spqlios/reim/reim_fft_core_template.h
spqlios/lib/spqlios/reim/reim_fft_core_template.hRaw
  1#ifndef SPQLIOS_REIM_FFT_CORE_TEMPLATE_H
  2#define SPQLIOS_REIM_FFT_CORE_TEMPLATE_H
  3
  4// this file contains the main template for the fft strategy.
  5// it is meant to be included once for each specialization (ref, avx, neon)
  6// all the leaf functions it uses shall be defined in the following macros,
  7// before including this header.
  8
  9#if !defined(reim_fft16_f) || !defined(reim_fft16_pom_offset) || !defined(fill_reim_fft16_omegas_f)
 10#error "missing reim16 definitions"
 11#endif
 12#if !defined(reim_fft8_f) || !defined(reim_fft8_pom_offset) || !defined(fill_reim_fft8_omegas_f)
 13#error "missing reim8 definitions"
 14#endif
 15#if !defined(reim_fft4_f) || !defined(reim_fft4_pom_offset) || !defined(fill_reim_fft4_omegas_f)
 16#error "missing reim4 definitions"
 17#endif
 18#if !defined(reim_fft2_f) || !defined(reim_fft2_pom_offset) || !defined(fill_reim_fft2_omegas_f)
 19#error "missing reim2 definitions"
 20#endif
 21#if !defined(reim_twiddle_fft_f) || !defined(reim_twiddle_fft_pom_offset) || !defined(fill_reim_twiddle_fft_omegas_f)
 22#error "missing twiddle definitions"
 23#endif
 24#if !defined(reim_bitwiddle_fft_f) || !defined(reim_bitwiddle_fft_pom_offset) || \
 25    !defined(fill_reim_bitwiddle_fft_omegas_f)
 26#error "missing bitwiddle definitions"
 27#endif
 28#if !defined(reim_fft_bfs_16_f) || !defined(fill_reim_fft_bfs_16_omegas_f)
 29#error "missing bfs_16 definitions"
 30#endif
 31#if !defined(reim_fft_rec_16_f) || !defined(fill_reim_fft_rec_16_omegas_f)
 32#error "missing rec_16 definitions"
 33#endif
 34#if !defined(reim_fft_f) || !defined(fill_reim_fft_omegas_f)
 35#error "missing main definitions"
 36#endif
 37
 38void reim_fft_bfs_16_f(uint64_t m, double* re, double* im, double** omg) {
 39  uint64_t log2m = log2(m);
 40  uint64_t mm = m;
 41  if (log2m & 1) {
 42    uint64_t h = mm >> 1;
 43    // do the first twiddle iteration normally
 44    reim_twiddle_fft_f(h, re, im, *omg);
 45    *omg += reim_twiddle_fft_pom_offset;
 46    mm = h;
 47  }
 48  while (mm > 16) {
 49    uint64_t h = mm >> 2;
 50    for (uint64_t off = 0; off < m; off += mm) {
 51      reim_bitwiddle_fft_f(h, re + off, im + off, *omg);
 52      *omg += reim_bitwiddle_fft_pom_offset;
 53    }
 54    mm = h;
 55  }
 56  if (mm != 16) abort();  // bug!
 57  for (uint64_t off = 0; off < m; off += 16) {
 58    reim_fft16_f(re + off, im + off, *omg);
 59    *omg += reim_fft16_pom_offset;
 60  }
 61}
 62
 63void fill_reim_fft_bfs_16_omegas_f(uint64_t m, double entry_pwr, double** omg) {
 64  uint64_t log2m = log2(m);
 65  uint64_t mm = m;
 66  double ss = entry_pwr;
 67  if (log2m % 2 != 0) {
 68    uint64_t h = mm >> 1;
 69    double s = ss / 2.;
 70    // do the first twiddle iteration normally
 71    fill_reim_twiddle_fft_omegas_f(s, omg);
 72    mm = h;
 73    ss = s;
 74  }
 75  while (mm > 16) {
 76    uint64_t h = mm >> 2;
 77    double s = ss / 4.;
 78    for (uint64_t off = 0; off < m; off += mm) {
 79      double rs0 = s + fracrevbits(off / mm) / 4.;
 80      fill_reim_bitwiddle_fft_omegas_f(rs0, omg);
 81    }
 82    mm = h;
 83    ss = s;
 84  }
 85  if (mm != 16) abort();  // bug!
 86  for (uint64_t off = 0; off < m; off += 16) {
 87    double s = ss + fracrevbits(off / 16);
 88    fill_reim_fft16_omegas_f(s, omg);
 89  }
 90}
 91
 92void reim_fft_rec_16_f(uint64_t m, double* re, double* im, double** omg) {
 93  if (m <= 2048) return reim_fft_bfs_16_f(m, re, im, omg);
 94  const uint32_t h = m >> 1;
 95  reim_twiddle_fft_f(h, re, im, *omg);
 96  *omg += reim_twiddle_fft_pom_offset;
 97  reim_fft_rec_16_f(h, re, im, omg);
 98  reim_fft_rec_16_f(h, re + h, im + h, omg);
 99}
100
101void fill_reim_fft_rec_16_omegas_f(uint64_t m, double entry_pwr, double** omg) {
102  if (m <= 2048) return fill_reim_fft_bfs_16_omegas_f(m, entry_pwr, omg);
103  const uint64_t h = m / 2;
104  const double s = entry_pwr / 2;
105  fill_reim_twiddle_fft_omegas_f(s, omg);
106  fill_reim_fft_rec_16_omegas_f(h, s, omg);
107  fill_reim_fft_rec_16_omegas_f(h, s + 0.5, omg);
108}
109
110void reim_fft_f(const REIM_FFT_PRECOMP* precomp, double* dat) {
111  const int32_t m = precomp->m;
112  double* omg = precomp->powomegas;
113  double* re = dat;
114  double* im = dat + m;
115  if (m <= 16) {
116    switch (m) {
117      case 1:
118        return;
119      case 2:
120        return reim_fft2_f(re, im, omg);
121      case 4:
122        return reim_fft4_f(re, im, omg);
123      case 8:
124        return reim_fft8_f(re, im, omg);
125      case 16:
126        return reim_fft16_f(re, im, omg);
127      default:
128        abort();  // m is not a power of 2
129    }
130  }
131  if (m <= 2048) return reim_fft_bfs_16_f(m, re, im, &omg);
132  return reim_fft_rec_16_f(m, re, im, &omg);
133}
134
135void fill_reim_fft_omegas_f(uint64_t m, double entry_pwr, double** omg) {
136  if (m <= 16) {
137    switch (m) {
138      case 1:
139        break;
140      case 2:
141        fill_reim_fft2_omegas_f(entry_pwr, omg);
142        break;
143      case 4:
144        fill_reim_fft4_omegas_f(entry_pwr, omg);
145        break;
146      case 8:
147        fill_reim_fft8_omegas_f(entry_pwr, omg);
148        break;
149      case 16:
150        fill_reim_fft16_omegas_f(entry_pwr, omg);
151        break;
152      default:
153        abort();  // m is not a power of 2
154    }
155  } else if (m <= 2048) {
156    fill_reim_fft_bfs_16_omegas_f(m, entry_pwr, omg);
157  } else {
158    fill_reim_fft_rec_16_omegas_f(m, entry_pwr, omg);
159  }
160}
161
162#endif  // SPQLIOS_REIM_FFT_CORE_TEMPLATE_H