/src/fftw3/api/mapflags.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 | | #include "api/api.h" |
22 | | #include <math.h> |
23 | | |
24 | | /* a flag operation: x is either a flag, in which case xm == 0, or |
25 | | a mask, in which case xm == x; using this we can compactly code |
26 | | the various bit operations via (flags & x) ^ xm or (flags | x) ^ xm. */ |
27 | | typedef struct { |
28 | | unsigned x, xm; |
29 | | } flagmask; |
30 | | |
31 | | typedef struct { |
32 | | flagmask flag; |
33 | | flagmask op; |
34 | | } flagop; |
35 | | |
36 | 23.6k | #define FLAGP(f, msk)(((f) & (msk).x) ^ (msk).xm) |
37 | 12.6k | #define OP(f, msk)(((f) | (msk).x) ^ (msk).xm) |
38 | | |
39 | | #define YES(x) {x, 0} |
40 | | #define NO(x) {x, x} |
41 | 23.6k | #define IMPLIES(predicate, consequence) { predicate, consequence } |
42 | 8.64k | #define EQV(a, b) IMPLIES(YES(a), YES(b)), IMPLIES(NO(a), NO(b)) |
43 | 576 | #define NEQV(a, b) IMPLIES(YES(a), NO(b)), IMPLIES(NO(a), YES(b)) |
44 | | |
45 | | static void map_flags(unsigned *iflags, unsigned *oflags, |
46 | | const flagop flagmap[], size_t nmap) |
47 | 1.72k | { |
48 | 1.72k | size_t i; |
49 | 25.3k | for (i = 0; i < nmap; ++i) |
50 | 23.6k | if (FLAGP(*iflags, flagmap[i].flag)) |
51 | 12.6k | *oflags = OP(*oflags, flagmap[i].op); |
52 | 1.72k | } |
53 | | |
54 | | /* encoding of the planner timelimit into a BITS_FOR_TIMELIMIT-bits |
55 | | nonnegative integer, such that we can still view the integer as |
56 | | ``impatience'': higher means *lower* time limit, and 0 is the |
57 | | highest possible value (about 1 year of calendar time) */ |
58 | | static unsigned timelimit_to_flags(double timelimit) |
59 | 576 | { |
60 | 576 | const double tmax = 365 * 24 * 3600; |
61 | 576 | const double tstep = 1.05; |
62 | 576 | const int nsteps = (1 << BITS_FOR_TIMELIMIT); |
63 | 576 | int x; |
64 | | |
65 | 576 | if (timelimit < 0 || timelimit >= tmax) |
66 | 576 | return 0; |
67 | 0 | if (timelimit <= 1.0e-10) |
68 | 0 | return nsteps - 1; |
69 | | |
70 | 0 | x = (int) (0.5 + (log(tmax / timelimit) / log(tstep))); |
71 | |
|
72 | 0 | if (x < 0) x = 0; |
73 | 0 | if (x >= nsteps) x = nsteps - 1; |
74 | 0 | return x; |
75 | 0 | } |
76 | | |
77 | | void X(mapflags)(planner *plnr, unsigned flags) |
78 | 576 | { |
79 | 576 | unsigned l, u, t; |
80 | | |
81 | | /* map of api flags -> api flags, to implement consistency rules |
82 | | and combination flags */ |
83 | 576 | const flagop self_flagmap[] = { |
84 | | /* in some cases (notably for halfcomplex->real transforms), |
85 | | DESTROY_INPUT is the default, so we need to support |
86 | | an inverse flag to disable it. |
87 | | |
88 | | (PRESERVE, DESTROY) -> (PRESERVE, DESTROY) |
89 | | (0, 0) (1, 0) |
90 | | (0, 1) (0, 1) |
91 | | (1, 0) (1, 0) |
92 | | (1, 1) (1, 0) |
93 | | */ |
94 | 576 | IMPLIES(YES(FFTW_PRESERVE_INPUT), NO(FFTW_DESTROY_INPUT)), |
95 | 576 | IMPLIES(NO(FFTW_DESTROY_INPUT), YES(FFTW_PRESERVE_INPUT)), |
96 | | |
97 | 576 | IMPLIES(YES(FFTW_EXHAUSTIVE), YES(FFTW_PATIENT)), |
98 | | |
99 | 576 | IMPLIES(YES(FFTW_ESTIMATE), NO(FFTW_PATIENT)), |
100 | 576 | IMPLIES(YES(FFTW_ESTIMATE), |
101 | 576 | YES(FFTW_ESTIMATE_PATIENT |
102 | 576 | | FFTW_NO_INDIRECT_OP |
103 | 576 | | FFTW_ALLOW_PRUNING)), |
104 | | |
105 | 576 | IMPLIES(NO(FFTW_EXHAUSTIVE), |
106 | 576 | YES(FFTW_NO_SLOW)), |
107 | | |
108 | | /* a canonical set of fftw2-like impatience flags */ |
109 | 576 | IMPLIES(NO(FFTW_PATIENT), |
110 | 576 | YES(FFTW_NO_VRECURSE |
111 | 576 | | FFTW_NO_RANK_SPLITS |
112 | 576 | | FFTW_NO_VRANK_SPLITS |
113 | 576 | | FFTW_NO_NONTHREADED |
114 | 576 | | FFTW_NO_DFT_R2HC |
115 | 576 | | FFTW_NO_FIXED_RADIX_LARGE_N |
116 | 576 | | FFTW_BELIEVE_PCOST)) |
117 | 576 | }; |
118 | | |
119 | | /* map of (processed) api flags to internal problem/planner flags */ |
120 | 576 | const flagop l_flagmap[] = { |
121 | 576 | EQV(FFTW_PRESERVE_INPUT, NO_DESTROY_INPUT), |
122 | 576 | EQV(FFTW_NO_SIMD, NO_SIMD), |
123 | 576 | EQV(FFTW_CONSERVE_MEMORY, CONSERVE_MEMORY), |
124 | 576 | EQV(FFTW_NO_BUFFERING, NO_BUFFERING), |
125 | 576 | NEQV(FFTW_ALLOW_LARGE_GENERIC, NO_LARGE_GENERIC) |
126 | 576 | }; |
127 | | |
128 | 576 | const flagop u_flagmap[] = { |
129 | 576 | IMPLIES(YES(FFTW_EXHAUSTIVE), NO(0xFFFFFFFF)), |
130 | 576 | IMPLIES(NO(FFTW_EXHAUSTIVE), YES(NO_UGLY)), |
131 | | |
132 | | /* the following are undocumented, "beyond-guru" flags that |
133 | | require some understanding of FFTW internals */ |
134 | 576 | EQV(FFTW_ESTIMATE_PATIENT, ESTIMATE), |
135 | 576 | EQV(FFTW_ALLOW_PRUNING, ALLOW_PRUNING), |
136 | 576 | EQV(FFTW_BELIEVE_PCOST, BELIEVE_PCOST), |
137 | 576 | EQV(FFTW_NO_DFT_R2HC, NO_DFT_R2HC), |
138 | 576 | EQV(FFTW_NO_NONTHREADED, NO_NONTHREADED), |
139 | 576 | EQV(FFTW_NO_INDIRECT_OP, NO_INDIRECT_OP), |
140 | 576 | EQV(FFTW_NO_RANK_SPLITS, NO_RANK_SPLITS), |
141 | 576 | EQV(FFTW_NO_VRANK_SPLITS, NO_VRANK_SPLITS), |
142 | 576 | EQV(FFTW_NO_VRECURSE, NO_VRECURSE), |
143 | 576 | EQV(FFTW_NO_SLOW, NO_SLOW), |
144 | 576 | EQV(FFTW_NO_FIXED_RADIX_LARGE_N, NO_FIXED_RADIX_LARGE_N) |
145 | 576 | }; |
146 | | |
147 | 576 | map_flags(&flags, &flags, self_flagmap, NELEM(self_flagmap)); |
148 | | |
149 | 576 | l = u = 0; |
150 | 576 | map_flags(&flags, &l, l_flagmap, NELEM(l_flagmap)); |
151 | 576 | map_flags(&flags, &u, u_flagmap, NELEM(u_flagmap)); |
152 | | |
153 | | /* enforce l <= u */ |
154 | 576 | PLNR_L(plnr) = l; |
155 | 576 | PLNR_U(plnr) = u | l; |
156 | | |
157 | | /* assert that the conversion didn't lose bits */ |
158 | 576 | A(PLNR_L(plnr) == l); |
159 | 576 | A(PLNR_U(plnr) == (u | l)); |
160 | | |
161 | | /* compute flags representation of the timelimit */ |
162 | 576 | t = timelimit_to_flags(plnr->timelimit); |
163 | | |
164 | 576 | PLNR_TIMELIMIT_IMPATIENCE(plnr) = t; |
165 | 576 | A(PLNR_TIMELIMIT_IMPATIENCE(plnr) == t); |
166 | 576 | } |