Coverage Report

Created: 2026-09-14 06:11

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.12k
#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.12k
{
34
1.12k
     INT h = n * 17 + r;
35
36
1.12k
     if (h < 0) h = -h;
37
38
1.12k
     return (h % HASHSZ);
39
1.12k
}
40
41
static int equal_instr(const tw_instr *p, const tw_instr *q)
42
86
{
43
86
     if (p == q)
44
86
          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
86
{
71
86
     return (wakefulness == t->wakefulness &&
72
86
       n == t->n &&
73
86
       r == t->r && 
74
86
       m <= t->m && 
75
86
       equal_instr(t->instr, q));
76
86
}
77
78
static twid *lookup(enum wakefulness wakefulness,
79
        const tw_instr *q, INT n, INT r, INT m)
80
431
{
81
431
     twid *p;
82
83
431
     for (p = twlist[hash(n,r)]; 
84
431
    p && !ok_twid(p, wakefulness, q, n, r, m); 
85
431
    p = p->cdr)
86
0
          ;
87
431
     return p;
88
431
}
89
90
static INT twlen0(INT r, const tw_instr *p, INT *vl)
91
345
{
92
345
     INT ntwiddle = 0;
93
94
     /* compute length of bytecode program */
95
345
     A(r > 0);
96
886
     for ( ; p->op != TW_NEXT; ++p) {
97
541
    switch (p->op) {
98
170
        case TW_FULL:
99
170
       ntwiddle += (r - 1) * 2;
100
170
       break;
101
69
        case TW_HALF:
102
69
       ntwiddle += (r - 1);
103
69
       break;
104
302
        case TW_CEXP:
105
302
       ntwiddle += 2;
106
302
       break;
107
0
        case TW_COS:
108
0
        case TW_SIN:
109
0
       ntwiddle += 1;
110
0
       break;
111
541
    }
112
541
     }
113
114
345
     *vl = (INT)p->v;
115
345
     return ntwiddle;
116
345
}
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
345
{
127
345
     INT ntwiddle, j, vl;
128
345
     R *W, *W0;
129
345
     const tw_instr *p;
130
345
     triggen *t = X(mktriggen)(wakefulness, n);
131
132
345
     p = instr;
133
345
     ntwiddle = twlen0(r, p, &vl);
134
135
345
     A(m % vl == 0);
136
137
345
     W0 = W = (R *)MALLOC((ntwiddle * (m / vl)) * sizeof(R), TWIDDLES);
138
139
7.46k
     for (j = 0; j < m; j += vl) {
140
17.4k
          for (p = instr; p->op != TW_NEXT; ++p) {
141
10.3k
         switch (p->op) {
142
4.11k
       case TW_FULL: {
143
4.11k
      INT i;
144
15.8k
      for (i = 1; i < r; ++i) {
145
11.6k
           A((j + (INT)p->v) * i < n);
146
11.6k
           A((j + (INT)p->v) * i > -n);
147
11.6k
           t->cexp(t, (j + (INT)p->v) * i, W);
148
11.6k
           W += 2;
149
11.6k
      }
150
4.11k
      break;
151
0
       }
152
153
1.23k
       case TW_HALF: {
154
1.23k
      INT i;
155
1.23k
      A((r % 2) == 1);
156
32.0k
      for (i = 1; i + i < r; ++i) {
157
30.8k
           t->cexp(t, MULMOD(i, (j + (INT)p->v), n), W);
158
30.8k
           W += 2;
159
30.8k
      }
160
1.23k
      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
4.99k
       case TW_CEXP:
184
4.99k
      A((j + (INT)p->v) * p->i < n);
185
4.99k
      A((j + (INT)p->v) * p->i > -n);
186
4.99k
      t->cexp(t, (j + (INT)p->v) * (INT)p->i, W);
187
4.99k
      W += 2;
188
4.99k
      break;
189
10.3k
         }
190
10.3k
    }
191
7.12k
     }
192
193
345
     X(triggen_destroy)(t);
194
345
     return W0;
195
345
}
196
197
static void mktwiddle(enum wakefulness wakefulness,
198
          twid **pp, const tw_instr *instr, INT n, INT r, INT m)
199
431
{
200
431
     twid *p;
201
431
     INT h;
202
203
431
     if ((p = lookup(wakefulness, instr, n, r, m))) {
204
86
          ++p->refcnt;
205
345
     } else {
206
345
    p = (twid *) MALLOC(sizeof(twid), TWIDDLES);
207
345
    p->n = n;
208
345
    p->r = r;
209
345
    p->m = m;
210
345
    p->instr = instr;
211
345
    p->refcnt = 1;
212
345
    p->wakefulness = wakefulness;
213
345
    p->W = compute(wakefulness, instr, n, r, m);
214
215
    /* cons! onto twlist */
216
345
    h = hash(n, r);
217
345
    p->cdr = twlist[h];
218
345
    twlist[h] = p;
219
345
     }
220
221
431
     *pp = p;
222
431
}
223
224
static void twiddle_destroy(twid **pp)
225
431
{
226
431
     twid *p = *pp;
227
431
     twid **q;
228
229
431
     if ((--p->refcnt) == 0) {
230
    /* remove p from twiddle list */
231
345
    for (q = &twlist[hash(p->n, p->r)]; *q; q = &((*q)->cdr)) {
232
345
         if (*q == p) {
233
345
        *q = p->cdr;
234
345
        X(ifree)(p->W);
235
345
        X(ifree)(p);
236
345
        *pp = 0;
237
345
        return;
238
345
         }
239
345
    }
240
0
    A(0 /* can't happen */ );
241
0
     }
242
431
}
243
244
245
void X(twiddle_awake)(enum wakefulness wakefulness, twid **pp, 
246
          const tw_instr *instr, INT n, INT r, INT m)
247
862
{
248
862
     switch (wakefulness) {
249
431
   case SLEEPY: 
250
431
        twiddle_destroy(pp);
251
431
        break;
252
431
   default:
253
431
        mktwiddle(wakefulness, pp, instr, n, r, m);
254
431
        break;
255
862
     }
256
862
}