2
* Copyright (c) 2003, 2006 Matteo Frigo
3
* Copyright (c) 2003, 2006 Massachusetts Institute of Technology
5
* This program is free software; you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License as published by
7
* the Free Software Foundation; either version 2 of the License, or
8
* (at your option) any later version.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, write to the Free Software
17
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21
/* $Id: twiddle.c,v 1.33 2006-01-05 22:39:02 athena Exp $ */
23
/* Twiddle manipulation */
30
/* hash table of known twiddle factors */
31
static twid *twlist[HASHSZ];
33
static INT hash(INT n, INT r)
42
static int equal_instr(const tw_instr *p, const tw_instr *q)
57
if (p->v != q->v) return 0; /* p->i is ignored */
61
if (p->v != q->v || p->i != q->i) return 0;
65
A(0 /* can't happen */);
68
static int ok_twid(const twid *t,
69
enum wakefulness wakefulness,
70
const tw_instr *q, INT n, INT r, INT m)
72
return (wakefulness == t->wakefulness &&
76
equal_instr(t->instr, q));
79
static twid *lookup(enum wakefulness wakefulness,
80
const tw_instr *q, INT n, INT r, INT m)
84
for (p = twlist[hash(n,r)];
85
p && !ok_twid(p, wakefulness, q, n, r, m);
91
static INT twlen0(INT r, const tw_instr *p, INT *vl)
95
/* compute length of bytecode program */
97
for ( ; p->op != TW_NEXT; ++p) {
100
ntwiddle += (r - 1) * 2;
119
INT X(twiddle_length)(INT r, const tw_instr *p)
122
return twlen0(r, p, &vl);
125
static R *compute(enum wakefulness wakefulness,
126
const tw_instr *instr, INT n, INT r, INT m)
131
triggen *t = X(mktriggen)(wakefulness, n);
134
ntwiddle = twlen0(r, p, &vl);
138
W0 = W = (R *)MALLOC((ntwiddle * (m / vl)) * sizeof(R), TWIDDLES);
140
for (j = 0; j < m; j += vl) {
141
for (p = instr; p->op != TW_NEXT; ++p) {
146
for (i = 1; i < r; ++i) {
147
t->cexp(t, (j + (INT)p->v) * i, W);
156
for (i = 1; i + i < r; ++i) {
157
t->cexp(t, MULMOD(i, (j + (INT)p->v), n), W);
167
t->cexp(t, (j + (INT)p->v) * (INT)p->i, d);
177
t->cexp(t, (j + (INT)p->v) * (INT)p->i, d);
184
t->cexp(t, (j + (INT)p->v) * (INT)p->i, W);
191
X(triggen_destroy)(t);
195
static void mktwiddle(enum wakefulness wakefulness,
196
twid **pp, const tw_instr *instr, INT n, INT r, INT m)
201
if ((p = lookup(wakefulness, instr, n, r, m))) {
204
p = (twid *) MALLOC(sizeof(twid), TWIDDLES);
210
p->wakefulness = wakefulness;
211
p->W = compute(wakefulness, instr, n, r, m);
213
/* cons! onto twlist */
222
static void twiddle_destroy(twid **pp)
227
if ((--p->refcnt) == 0) {
228
/* remove p from twiddle list */
229
for (q = &twlist[hash(p->n, p->r)]; *q; q = &((*q)->cdr)) {
238
A(0 /* can't happen */ );
243
void X(twiddle_awake)(enum wakefulness wakefulness, twid **pp,
244
const tw_instr *instr, INT n, INT r, INT m)
246
switch (wakefulness) {
251
mktwiddle(wakefulness, pp, instr, n, r, m);
256
/* return a pointer to twiddles (0 if none) starting at mstart out of m */
257
const R *X(twiddle_shift)(const twid *p, INT mstart)
262
ntwiddle = twlen0(p->r, p->instr, &vl);
263
A((mstart % vl) == 0);
264
return (p->W + (mstart / vl) * ntwiddle);