/src/fftw3/dft/dftw-generic.c
Line | Count | Source (jump to first uncovered line) |
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 | | /* express a twiddle problem in terms of dft + multiplication by |
22 | | twiddle factors */ |
23 | | |
24 | | #include "dft/ct.h" |
25 | | |
26 | | typedef ct_solver S; |
27 | | |
28 | | typedef struct { |
29 | | plan_dftw super; |
30 | | |
31 | | INT r, rs, m, mb, me, ms, v, vs; |
32 | | |
33 | | plan *cld; |
34 | | |
35 | | twid *td; |
36 | | |
37 | | const S *slv; |
38 | | int dec; |
39 | | } P; |
40 | | |
41 | | static void mktwiddle(P *ego, enum wakefulness wakefulness) |
42 | 16 | { |
43 | 16 | static const tw_instr tw[] = { { TW_FULL, 0, 0 }, { TW_NEXT, 1, 0 } }; |
44 | | |
45 | | /* note that R and M are swapped, to allow for sequential |
46 | | access both to data and twiddles */ |
47 | 16 | X(twiddle_awake)(wakefulness, &ego->td, tw, |
48 | 16 | ego->r * ego->m, ego->m, ego->r); |
49 | 16 | } |
50 | | |
51 | | static void bytwiddle(const P *ego, R *rio, R *iio) |
52 | 9 | { |
53 | 9 | INT iv, ir, im; |
54 | 9 | INT r = ego->r, rs = ego->rs; |
55 | 9 | INT m = ego->m, mb = ego->mb, me = ego->me, ms = ego->ms; |
56 | 9 | INT v = ego->v, vs = ego->vs; |
57 | 9 | const R *W = ego->td->W; |
58 | | |
59 | 9 | mb += (mb == 0); /* skip m=0 iteration */ |
60 | 18 | for (iv = 0; iv < v; ++iv) { |
61 | 105 | for (ir = 1; ir < r; ++ir) { |
62 | 1.32k | for (im = mb; im < me; ++im) { |
63 | 1.23k | R *pr = rio + ms * im + rs * ir; |
64 | 1.23k | R *pi = iio + ms * im + rs * ir; |
65 | 1.23k | E xr = *pr; |
66 | 1.23k | E xi = *pi; |
67 | 1.23k | E wr = W[2 * im + (2 * (m-1)) * ir - 2]; |
68 | 1.23k | E wi = W[2 * im + (2 * (m-1)) * ir - 1]; |
69 | 1.23k | *pr = xr * wr + xi * wi; |
70 | 1.23k | *pi = xi * wr - xr * wi; |
71 | 1.23k | } |
72 | 96 | } |
73 | 9 | rio += vs; |
74 | 9 | iio += vs; |
75 | 9 | } |
76 | 9 | } |
77 | | |
78 | | static int applicable(INT irs, INT ors, INT ivs, INT ovs, |
79 | | const planner *plnr) |
80 | 200 | { |
81 | 200 | return (1 |
82 | 200 | && irs == ors |
83 | 200 | && ivs == ovs |
84 | 200 | && !NO_SLOWP(plnr) |
85 | 200 | ); |
86 | 200 | } |
87 | | |
88 | | static void apply_dit(const plan *ego_, R *rio, R *iio) |
89 | 9 | { |
90 | 9 | const P *ego = (const P *) ego_; |
91 | 9 | plan_dft *cld; |
92 | 9 | INT dm = ego->ms * ego->mb; |
93 | | |
94 | 9 | bytwiddle(ego, rio, iio); |
95 | | |
96 | 9 | cld = (plan_dft *) ego->cld; |
97 | 9 | cld->apply(ego->cld, rio + dm, iio + dm, rio + dm, iio + dm); |
98 | 9 | } |
99 | | |
100 | | static void apply_dif(const plan *ego_, R *rio, R *iio) |
101 | 0 | { |
102 | 0 | const P *ego = (const P *) ego_; |
103 | 0 | plan_dft *cld; |
104 | 0 | INT dm = ego->ms * ego->mb; |
105 | |
|
106 | 0 | cld = (plan_dft *) ego->cld; |
107 | 0 | cld->apply(ego->cld, rio + dm, iio + dm, rio + dm, iio + dm); |
108 | |
|
109 | 0 | bytwiddle(ego, rio, iio); |
110 | 0 | } |
111 | | |
112 | | static void awake(plan *ego_, enum wakefulness wakefulness) |
113 | 16 | { |
114 | 16 | P *ego = (P *) ego_; |
115 | 16 | X(plan_awake)(ego->cld, wakefulness); |
116 | 16 | mktwiddle(ego, wakefulness); |
117 | 16 | } |
118 | | |
119 | | static void destroy(plan *ego_) |
120 | 19 | { |
121 | 19 | P *ego = (P *) ego_; |
122 | 19 | X(plan_destroy_internal)(ego->cld); |
123 | 19 | } |
124 | | |
125 | | static void print(const plan *ego_, printer *p) |
126 | 0 | { |
127 | 0 | const P *ego = (const P *) ego_; |
128 | 0 | p->print(p, "(dftw-generic-%s-%D-%D%v%(%p%))", |
129 | 0 | ego->dec == DECDIT ? "dit" : "dif", |
130 | 0 | ego->r, ego->m, ego->v, ego->cld); |
131 | 0 | } |
132 | | |
133 | | static plan *mkcldw(const ct_solver *ego_, |
134 | | INT r, INT irs, INT ors, |
135 | | INT m, INT ms, |
136 | | INT v, INT ivs, INT ovs, |
137 | | INT mstart, INT mcount, |
138 | | R *rio, R *iio, |
139 | | planner *plnr) |
140 | 200 | { |
141 | 200 | const S *ego = (const S *)ego_; |
142 | 200 | P *pln; |
143 | 200 | plan *cld = 0; |
144 | 200 | INT dm = ms * mstart; |
145 | | |
146 | 200 | static const plan_adt padt = { |
147 | 200 | 0, awake, print, destroy |
148 | 200 | }; |
149 | | |
150 | 200 | A(mstart >= 0 && mstart + mcount <= m); |
151 | 200 | if (!applicable(irs, ors, ivs, ovs, plnr)) |
152 | 181 | return (plan *)0; |
153 | | |
154 | 19 | cld = X(mkplan_d)(plnr, |
155 | 19 | X(mkproblem_dft_d)( |
156 | 19 | X(mktensor_1d)(r, irs, irs), |
157 | 19 | X(mktensor_2d)(mcount, ms, ms, v, ivs, ivs), |
158 | 19 | rio + dm, iio + dm, rio + dm, iio + dm) |
159 | 19 | ); |
160 | 19 | if (!cld) goto nada; |
161 | | |
162 | 19 | pln = MKPLAN_DFTW(P, &padt, ego->dec == DECDIT ? apply_dit : apply_dif); |
163 | 19 | pln->slv = ego; |
164 | 19 | pln->cld = cld; |
165 | 19 | pln->r = r; |
166 | 19 | pln->rs = irs; |
167 | 19 | pln->m = m; |
168 | 19 | pln->ms = ms; |
169 | 19 | pln->v = v; |
170 | 19 | pln->vs = ivs; |
171 | 19 | pln->mb = mstart; |
172 | 19 | pln->me = mstart + mcount; |
173 | 19 | pln->dec = ego->dec; |
174 | 19 | pln->td = 0; |
175 | | |
176 | 19 | { |
177 | 19 | double n0 = (r - 1) * (mcount - 1) * v; |
178 | 19 | pln->super.super.ops = cld->ops; |
179 | 19 | pln->super.super.ops.mul += 8 * n0; |
180 | 19 | pln->super.super.ops.add += 4 * n0; |
181 | 19 | pln->super.super.ops.other += 8 * n0; |
182 | 19 | } |
183 | 19 | return &(pln->super.super); |
184 | | |
185 | 0 | nada: |
186 | 0 | X(plan_destroy_internal)(cld); |
187 | 0 | return (plan *) 0; |
188 | 19 | } |
189 | | |
190 | | static void regsolver(planner *plnr, INT r, int dec) |
191 | 2 | { |
192 | 2 | S *slv = (S *)X(mksolver_ct)(sizeof(S), r, dec, mkcldw, 0); |
193 | 2 | REGISTER_SOLVER(plnr, &(slv->super)); |
194 | 2 | if (X(mksolver_ct_hook)) { |
195 | 0 | slv = (S *)X(mksolver_ct_hook)(sizeof(S), r, dec, mkcldw, 0); |
196 | 0 | REGISTER_SOLVER(plnr, &(slv->super)); |
197 | 0 | } |
198 | 2 | } |
199 | | |
200 | | void X(ct_generic_register)(planner *p) |
201 | 1 | { |
202 | 1 | regsolver(p, 0, DECDIT); |
203 | 1 | regsolver(p, 0, DECDIF); |
204 | 1 | } |