Coverage Report

Created: 2026-04-12 06:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/fftw3/kernel/twiddle.c
Line
Count
Source
1
/*
2
 * Copyright (c) 2003, 2007-14 Matteo Frigo
3
 * Copyright (c) 2003, 2007-14 Massachusetts Institute of Technology
4
 *
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.
9
 *
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.
14
 *
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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18
 *
19
 */
20
21
22
/* Twiddle manipulation */
23
24
#include "kernel/ifftw.h"
25
#include <math.h>
26
27
1.13k
#define HASHSZ 109
28
29
/* hash table of known twiddle factors */
30
static twid *twlist[HASHSZ];
31
32
static INT hash(INT n, INT r)
33
1.13k
{
34
1.13k
     INT h = n * 17 + r;
35
36
1.13k
     if (h < 0) h = -h;
37
38
1.13k
     return (h % HASHSZ);
39
1.13k
}
40
41
static int equal_instr(const tw_instr *p, const tw_instr *q)
42
90
{
43
90
     if (p == q)
44
90
          return 1;
45
46
0
     for (;; ++p, ++q) {
47
0
          if (p->op != q->op)
48
0
         return 0;
49
50
0
    switch (p->op) {
51
0
        case TW_NEXT:
52
0
       return (p->v == q->v); /* p->i is ignored */
53
54
0
        case TW_FULL:
55
0
        case TW_HALF:
56
0
       if (p->v != q->v) return 0; /* p->i is ignored */
57
0
       break;
58
59
0
        default:
60
0
       if (p->v != q->v || p->i != q->i) return 0;
61
0
       break;
62
0
    }
63
0
     }
64
0
     A(0 /* can't happen */);
65
0
}
66
67
static int ok_twid(const twid *t, 
68
       enum wakefulness wakefulness,
69
       const tw_instr *q, INT n, INT r, INT m)
70
90
{
71
90
     return (wakefulness == t->wakefulness &&
72
90
       n == t->n &&
73
90
       r == t->r && 
74
90
       m <= t->m && 
75
90
       equal_instr(t->instr, q));
76
90
}
77
78
static twid *lookup(enum wakefulness wakefulness,
79
        const tw_instr *q, INT n, INT r, INT m)
80
439
{
81
439
     twid *p;
82
83
439
     for (p = twlist[hash(n,r)]; 
84
439
    p && !ok_twid(p, wakefulness, q, n, r, m); 
85
439
    p = p->cdr)
86
0
          ;
87
439
     return p;
88
439
}
89
90
static INT twlen0(INT r, const tw_instr *p, INT *vl)
91
349
{
92
349
     INT ntwiddle = 0;
93
94
     /* compute length of bytecode program */
95
349
     A(r > 0);
96
891
     for ( ; p->op != TW_NEXT; ++p) {
97
542
    switch (p->op) {
98
173
        case TW_FULL:
99
173
       ntwiddle += (r - 1) * 2;
100
173
       break;
101
70
        case TW_HALF:
102
70
       ntwiddle += (r - 1);
103
70
       break;
104
299
        case TW_CEXP:
105
299
       ntwiddle += 2;
106
299
       break;
107
0
        case TW_COS:
108
0
        case TW_SIN:
109
0
       ntwiddle += 1;
110
0
       break;
111
542
    }
112
542
     }
113
114
349
     *vl = (INT)p->v;
115
349
     return ntwiddle;
116
349
}
117
118
INT X(twiddle_length)(INT r, const tw_instr *p)
119
0
{
120
0
     INT vl;
121
0
     return twlen0(r, p, &vl);
122
0
}
123
124
static R *compute(enum wakefulness wakefulness,
125
      const tw_instr *instr, INT n, INT r, INT m)
126
349
{
127
349
     INT ntwiddle, j, vl;
128
349
     R *W, *W0;
129
349
     const tw_instr *p;
130
349
     triggen *t = X(mktriggen)(wakefulness, n);
131
132
349
     p = instr;
133
349
     ntwiddle = twlen0(r, p, &vl);
134
135
349
     A(m % vl == 0);
136
137
349
     W0 = W = (R *)MALLOC((ntwiddle * (m / vl)) * sizeof(R), TWIDDLES);
138
139
7.61k
     for (j = 0; j < m; j += vl) {
140
17.8k
          for (p = instr; p->op != TW_NEXT; ++p) {
141
10.5k
         switch (p->op) {
142
4.25k
       case TW_FULL: {
143
4.25k
      INT i;
144
16.4k
      for (i = 1; i < r; ++i) {
145
12.1k
           A((j + (INT)p->v) * i < n);
146
12.1k
           A((j + (INT)p->v) * i > -n);
147
12.1k
           t->cexp(t, (j + (INT)p->v) * i, W);
148
12.1k
           W += 2;
149
12.1k
      }
150
4.25k
      break;
151
0
       }
152
153
1.21k
       case TW_HALF: {
154
1.21k
      INT i;
155
1.21k
      A((r % 2) == 1);
156
28.9k
      for (i = 1; i + i < r; ++i) {
157
27.7k
           t->cexp(t, MULMOD(i, (j + (INT)p->v), n), W);
158
27.7k
           W += 2;
159
27.7k
      }
160
1.21k
      break;
161
0
       }
162
163
0
       case TW_COS: {
164
0
      R d[2];
165
166
0
      A((j + (INT)p->v) * p->i < n);
167
0
      A((j + (INT)p->v) * p->i > -n);
168
0
      t->cexp(t, (j + (INT)p->v) * (INT)p->i, d);
169
0
      *W++ = d[0];
170
0
      break;
171
0
       }
172
173
0
       case TW_SIN: {
174
0
      R d[2];
175
176
0
      A((j + (INT)p->v) * p->i < n);
177
0
      A((j + (INT)p->v) * p->i > -n);
178
0
      t->cexp(t, (j + (INT)p->v) * (INT)p->i, d);
179
0
      *W++ = d[1];
180
0
      break;
181
0
       }
182
183
5.08k
       case TW_CEXP:
184
5.08k
      A((j + (INT)p->v) * p->i < n);
185
5.08k
      A((j + (INT)p->v) * p->i > -n);
186
5.08k
      t->cexp(t, (j + (INT)p->v) * (INT)p->i, W);
187
5.08k
      W += 2;
188
5.08k
      break;
189
10.5k
         }
190
10.5k
    }
191
7.26k
     }
192
193
349
     X(triggen_destroy)(t);
194
349
     return W0;
195
349
}
196
197
static void mktwiddle(enum wakefulness wakefulness,
198
          twid **pp, const tw_instr *instr, INT n, INT r, INT m)
199
439
{
200
439
     twid *p;
201
439
     INT h;
202
203
439
     if ((p = lookup(wakefulness, instr, n, r, m))) {
204
90
          ++p->refcnt;
205
349
     } else {
206
349
    p = (twid *) MALLOC(sizeof(twid), TWIDDLES);
207
349
    p->n = n;
208
349
    p->r = r;
209
349
    p->m = m;
210
349
    p->instr = instr;
211
349
    p->refcnt = 1;
212
349
    p->wakefulness = wakefulness;
213
349
    p->W = compute(wakefulness, instr, n, r, m);
214
215
    /* cons! onto twlist */
216
349
    h = hash(n, r);
217
349
    p->cdr = twlist[h];
218
349
    twlist[h] = p;
219
349
     }
220
221
439
     *pp = p;
222
439
}
223
224
static void twiddle_destroy(twid **pp)
225
439
{
226
439
     twid *p = *pp;
227
439
     twid **q;
228
229
439
     if ((--p->refcnt) == 0) {
230
    /* remove p from twiddle list */
231
349
    for (q = &twlist[hash(p->n, p->r)]; *q; q = &((*q)->cdr)) {
232
349
         if (*q == p) {
233
349
        *q = p->cdr;
234
349
        X(ifree)(p->W);
235
349
        X(ifree)(p);
236
349
        *pp = 0;
237
349
        return;
238
349
         }
239
349
    }
240
0
    A(0 /* can't happen */ );
241
0
     }
242
439
}
243
244
245
void X(twiddle_awake)(enum wakefulness wakefulness, twid **pp, 
246
          const tw_instr *instr, INT n, INT r, INT m)
247
878
{
248
878
     switch (wakefulness) {
249
439
   case SLEEPY: 
250
439
        twiddle_destroy(pp);
251
439
        break;
252
439
   default:
253
439
        mktwiddle(wakefulness, pp, instr, n, r, m);
254
439
        break;
255
878
     }
256
878
}