annotate src/fftw-3.3.5/kernel/twiddle.c @ 55:284acf908dcd

Add source for PortAudio stable v190600_20161030
author Chris Cannam
date Tue, 03 Jan 2017 13:44:07 +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 }