annotate src/fftw-3.3.5/kernel/twiddle.c @ 83:ae30d91d2ffe

Replace these with versions built using an older toolset (so as to avoid ABI compatibilities when linking on Ubuntu 14.04 for packaging purposes)
author Chris Cannam
date Fri, 07 Feb 2020 11:51:13 +0000
parents 2cd0e3b3e1fd
children
rev   line source
Chris@42 1 /*
Chris@42 2 * Copyright (c) 2003, 2007-14 Matteo Frigo
Chris@42 3 * Copyright (c) 2003, 2007-14 Massachusetts Institute of Technology
Chris@42 4 *
Chris@42 5 * This program is free software; you can redistribute it and/or modify
Chris@42 6 * it under the terms of the GNU General Public License as published by
Chris@42 7 * the Free Software Foundation; either version 2 of the License, or
Chris@42 8 * (at your option) any later version.
Chris@42 9 *
Chris@42 10 * This program is distributed in the hope that it will be useful,
Chris@42 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Chris@42 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Chris@42 13 * GNU General Public License for more details.
Chris@42 14 *
Chris@42 15 * You should have received a copy of the GNU General Public License
Chris@42 16 * along with this program; if not, write to the Free Software
Chris@42 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Chris@42 18 *
Chris@42 19 */
Chris@42 20
Chris@42 21
Chris@42 22 /* Twiddle manipulation */
Chris@42 23
Chris@42 24 #include "ifftw.h"
Chris@42 25 #include <math.h>
Chris@42 26
Chris@42 27 #define HASHSZ 109
Chris@42 28
Chris@42 29 /* hash table of known twiddle factors */
Chris@42 30 static twid *twlist[HASHSZ];
Chris@42 31
Chris@42 32 static INT hash(INT n, INT r)
Chris@42 33 {
Chris@42 34 INT h = n * 17 + r;
Chris@42 35
Chris@42 36 if (h < 0) h = -h;
Chris@42 37
Chris@42 38 return (h % HASHSZ);
Chris@42 39 }
Chris@42 40
Chris@42 41 static int equal_instr(const tw_instr *p, const tw_instr *q)
Chris@42 42 {
Chris@42 43 if (p == q)
Chris@42 44 return 1;
Chris@42 45
Chris@42 46 for (;; ++p, ++q) {
Chris@42 47 if (p->op != q->op)
Chris@42 48 return 0;
Chris@42 49
Chris@42 50 switch (p->op) {
Chris@42 51 case TW_NEXT:
Chris@42 52 return (p->v == q->v); /* p->i is ignored */
Chris@42 53
Chris@42 54 case TW_FULL:
Chris@42 55 case TW_HALF:
Chris@42 56 if (p->v != q->v) return 0; /* p->i is ignored */
Chris@42 57 break;
Chris@42 58
Chris@42 59 default:
Chris@42 60 if (p->v != q->v || p->i != q->i) return 0;
Chris@42 61 break;
Chris@42 62 }
Chris@42 63 }
Chris@42 64 A(0 /* can't happen */);
Chris@42 65 }
Chris@42 66
Chris@42 67 static int ok_twid(const twid *t,
Chris@42 68 enum wakefulness wakefulness,
Chris@42 69 const tw_instr *q, INT n, INT r, INT m)
Chris@42 70 {
Chris@42 71 return (wakefulness == t->wakefulness &&
Chris@42 72 n == t->n &&
Chris@42 73 r == t->r &&
Chris@42 74 m <= t->m &&
Chris@42 75 equal_instr(t->instr, q));
Chris@42 76 }
Chris@42 77
Chris@42 78 static twid *lookup(enum wakefulness wakefulness,
Chris@42 79 const tw_instr *q, INT n, INT r, INT m)
Chris@42 80 {
Chris@42 81 twid *p;
Chris@42 82
Chris@42 83 for (p = twlist[hash(n,r)];
Chris@42 84 p && !ok_twid(p, wakefulness, q, n, r, m);
Chris@42 85 p = p->cdr)
Chris@42 86 ;
Chris@42 87 return p;
Chris@42 88 }
Chris@42 89
Chris@42 90 static INT twlen0(INT r, const tw_instr *p, INT *vl)
Chris@42 91 {
Chris@42 92 INT ntwiddle = 0;
Chris@42 93
Chris@42 94 /* compute length of bytecode program */
Chris@42 95 A(r > 0);
Chris@42 96 for ( ; p->op != TW_NEXT; ++p) {
Chris@42 97 switch (p->op) {
Chris@42 98 case TW_FULL:
Chris@42 99 ntwiddle += (r - 1) * 2;
Chris@42 100 break;
Chris@42 101 case TW_HALF:
Chris@42 102 ntwiddle += (r - 1);
Chris@42 103 break;
Chris@42 104 case TW_CEXP:
Chris@42 105 ntwiddle += 2;
Chris@42 106 break;
Chris@42 107 case TW_COS:
Chris@42 108 case TW_SIN:
Chris@42 109 ntwiddle += 1;
Chris@42 110 break;
Chris@42 111 }
Chris@42 112 }
Chris@42 113
Chris@42 114 *vl = (INT)p->v;
Chris@42 115 return ntwiddle;
Chris@42 116 }
Chris@42 117
Chris@42 118 INT X(twiddle_length)(INT r, const tw_instr *p)
Chris@42 119 {
Chris@42 120 INT vl;
Chris@42 121 return twlen0(r, p, &vl);
Chris@42 122 }
Chris@42 123
Chris@42 124 static R *compute(enum wakefulness wakefulness,
Chris@42 125 const tw_instr *instr, INT n, INT r, INT m)
Chris@42 126 {
Chris@42 127 INT ntwiddle, j, vl;
Chris@42 128 R *W, *W0;
Chris@42 129 const tw_instr *p;
Chris@42 130 triggen *t = X(mktriggen)(wakefulness, n);
Chris@42 131
Chris@42 132 p = instr;
Chris@42 133 ntwiddle = twlen0(r, p, &vl);
Chris@42 134
Chris@42 135 A(m % vl == 0);
Chris@42 136
Chris@42 137 W0 = W = (R *)MALLOC((ntwiddle * (m / vl)) * sizeof(R), TWIDDLES);
Chris@42 138
Chris@42 139 for (j = 0; j < m; j += vl) {
Chris@42 140 for (p = instr; p->op != TW_NEXT; ++p) {
Chris@42 141 switch (p->op) {
Chris@42 142 case TW_FULL: {
Chris@42 143 INT i;
Chris@42 144 for (i = 1; i < r; ++i) {
Chris@42 145 A((j + (INT)p->v) * i < n);
Chris@42 146 A((j + (INT)p->v) * i > -n);
Chris@42 147 t->cexp(t, (j + (INT)p->v) * i, W);
Chris@42 148 W += 2;
Chris@42 149 }
Chris@42 150 break;
Chris@42 151 }
Chris@42 152
Chris@42 153 case TW_HALF: {
Chris@42 154 INT i;
Chris@42 155 A((r % 2) == 1);
Chris@42 156 for (i = 1; i + i < r; ++i) {
Chris@42 157 t->cexp(t, MULMOD(i, (j + (INT)p->v), n), W);
Chris@42 158 W += 2;
Chris@42 159 }
Chris@42 160 break;
Chris@42 161 }
Chris@42 162
Chris@42 163 case TW_COS: {
Chris@42 164 R d[2];
Chris@42 165
Chris@42 166 A((j + (INT)p->v) * p->i < n);
Chris@42 167 A((j + (INT)p->v) * p->i > -n);
Chris@42 168 t->cexp(t, (j + (INT)p->v) * (INT)p->i, d);
Chris@42 169 *W++ = d[0];
Chris@42 170 break;
Chris@42 171 }
Chris@42 172
Chris@42 173 case TW_SIN: {
Chris@42 174 R d[2];
Chris@42 175
Chris@42 176 A((j + (INT)p->v) * p->i < n);
Chris@42 177 A((j + (INT)p->v) * p->i > -n);
Chris@42 178 t->cexp(t, (j + (INT)p->v) * (INT)p->i, d);
Chris@42 179 *W++ = d[1];
Chris@42 180 break;
Chris@42 181 }
Chris@42 182
Chris@42 183 case TW_CEXP:
Chris@42 184 A((j + (INT)p->v) * p->i < n);
Chris@42 185 A((j + (INT)p->v) * p->i > -n);
Chris@42 186 t->cexp(t, (j + (INT)p->v) * (INT)p->i, W);
Chris@42 187 W += 2;
Chris@42 188 break;
Chris@42 189 }
Chris@42 190 }
Chris@42 191 }
Chris@42 192
Chris@42 193 X(triggen_destroy)(t);
Chris@42 194 return W0;
Chris@42 195 }
Chris@42 196
Chris@42 197 static void mktwiddle(enum wakefulness wakefulness,
Chris@42 198 twid **pp, const tw_instr *instr, INT n, INT r, INT m)
Chris@42 199 {
Chris@42 200 twid *p;
Chris@42 201 INT h;
Chris@42 202
Chris@42 203 if ((p = lookup(wakefulness, instr, n, r, m))) {
Chris@42 204 ++p->refcnt;
Chris@42 205 } else {
Chris@42 206 p = (twid *) MALLOC(sizeof(twid), TWIDDLES);
Chris@42 207 p->n = n;
Chris@42 208 p->r = r;
Chris@42 209 p->m = m;
Chris@42 210 p->instr = instr;
Chris@42 211 p->refcnt = 1;
Chris@42 212 p->wakefulness = wakefulness;
Chris@42 213 p->W = compute(wakefulness, instr, n, r, m);
Chris@42 214
Chris@42 215 /* cons! onto twlist */
Chris@42 216 h = hash(n, r);
Chris@42 217 p->cdr = twlist[h];
Chris@42 218 twlist[h] = p;
Chris@42 219 }
Chris@42 220
Chris@42 221 *pp = p;
Chris@42 222 }
Chris@42 223
Chris@42 224 static void twiddle_destroy(twid **pp)
Chris@42 225 {
Chris@42 226 twid *p = *pp;
Chris@42 227 twid **q;
Chris@42 228
Chris@42 229 if ((--p->refcnt) == 0) {
Chris@42 230 /* remove p from twiddle list */
Chris@42 231 for (q = &twlist[hash(p->n, p->r)]; *q; q = &((*q)->cdr)) {
Chris@42 232 if (*q == p) {
Chris@42 233 *q = p->cdr;
Chris@42 234 X(ifree)(p->W);
Chris@42 235 X(ifree)(p);
Chris@42 236 *pp = 0;
Chris@42 237 return;
Chris@42 238 }
Chris@42 239 }
Chris@42 240 A(0 /* can't happen */ );
Chris@42 241 }
Chris@42 242 }
Chris@42 243
Chris@42 244
Chris@42 245 void X(twiddle_awake)(enum wakefulness wakefulness, twid **pp,
Chris@42 246 const tw_instr *instr, INT n, INT r, INT m)
Chris@42 247 {
Chris@42 248 switch (wakefulness) {
Chris@42 249 case SLEEPY:
Chris@42 250 twiddle_destroy(pp);
Chris@42 251 break;
Chris@42 252 default:
Chris@42 253 mktwiddle(wakefulness, pp, instr, n, r, m);
Chris@42 254 break;
Chris@42 255 }
Chris@42 256 }