Coverage Report

Created: 2026-01-09 06:26

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