Mercurial > hg > sv-dependency-builds
comparison src/fftw-3.3.8/genfft/to_alist.ml @ 167:bd3cc4d1df30
Add FFTW 3.3.8 source, and a Linux build
author | Chris Cannam <cannam@all-day-breakfast.com> |
---|---|
date | Tue, 19 Nov 2019 14:52:55 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
166:cbd6d7e562c7 | 167:bd3cc4d1df30 |
---|---|
1 (* | |
2 * Copyright (c) 1997-1999 Massachusetts Institute of Technology | |
3 * Copyright (c) 2003, 2007-14 Matteo Frigo | |
4 * Copyright (c) 2003, 2007-14 Massachusetts Institute of Technology | |
5 * | |
6 * This program is free software; you can redistribute it and/or modify | |
7 * it under the terms of the GNU General Public License as published by | |
8 * the Free Software Foundation; either version 2 of the License, or | |
9 * (at your option) any later version. | |
10 * | |
11 * This program is distributed in the hope that it will be useful, | |
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 * GNU General Public License for more details. | |
15 * | |
16 * You should have received a copy of the GNU General Public License | |
17 * along with this program; if not, write to the Free Software | |
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
19 * | |
20 *) | |
21 | |
22 (************************************************************* | |
23 * Conversion of the dag to an assignment list | |
24 *************************************************************) | |
25 (* | |
26 * This function is messy. The main problem is that we want to | |
27 * inline dag nodes conditionally, depending on how many times they | |
28 * are used. The Right Thing to do would be to modify the | |
29 * state monad to propagate some of the state backwards, so that | |
30 * we know whether a given node will be used again in the future. | |
31 * This modification is trivial in a lazy language, but it is | |
32 * messy in a strict language like ML. | |
33 * | |
34 * In this implementation, we just do the obvious thing, i.e., visit | |
35 * the dag twice, the first to count the node usages, and the second to | |
36 * produce the output. | |
37 *) | |
38 | |
39 open Monads.StateMonad | |
40 open Monads.MemoMonad | |
41 open Expr | |
42 | |
43 let fresh = Variable.make_temporary | |
44 let node_insert x = Assoctable.insert Expr.hash x | |
45 let node_lookup x = Assoctable.lookup Expr.hash (==) x | |
46 let empty = Assoctable.empty | |
47 | |
48 let fetchAl = | |
49 fetchState >>= (fun (al, _, _) -> returnM al) | |
50 | |
51 let storeAl al = | |
52 fetchState >>= (fun (_, visited, visited') -> | |
53 storeState (al, visited, visited')) | |
54 | |
55 let fetchVisited = fetchState >>= (fun (_, v, _) -> returnM v) | |
56 | |
57 let storeVisited visited = | |
58 fetchState >>= (fun (al, _, visited') -> | |
59 storeState (al, visited, visited')) | |
60 | |
61 let fetchVisited' = fetchState >>= (fun (_, _, v') -> returnM v') | |
62 let storeVisited' visited' = | |
63 fetchState >>= (fun (al, visited, _) -> | |
64 storeState (al, visited, visited')) | |
65 let lookupVisitedM' key = | |
66 fetchVisited' >>= fun table -> | |
67 returnM (node_lookup key table) | |
68 let insertVisitedM' key value = | |
69 fetchVisited' >>= fun table -> | |
70 storeVisited' (node_insert key value table) | |
71 | |
72 let counting f x = | |
73 fetchVisited >>= (fun v -> | |
74 match node_lookup x v with | |
75 Some count -> | |
76 let incr_cnt = | |
77 fetchVisited >>= (fun v' -> | |
78 storeVisited (node_insert x (count + 1) v')) | |
79 in | |
80 begin | |
81 match x with | |
82 (* Uminus is always inlined. Visit child *) | |
83 Uminus y -> f y >> incr_cnt | |
84 | _ -> incr_cnt | |
85 end | |
86 | None -> | |
87 f x >> fetchVisited >>= (fun v' -> | |
88 storeVisited (node_insert x 1 v'))) | |
89 | |
90 let with_varM v x = | |
91 fetchAl >>= (fun al -> storeAl ((v, x) :: al)) >> returnM (Load v) | |
92 | |
93 let inlineM = returnM | |
94 | |
95 let with_tempM x = match x with | |
96 | Load v when Variable.is_temporary v -> inlineM x (* avoid trivial moves *) | |
97 | _ -> with_varM (fresh ()) x | |
98 | |
99 (* declare a temporary only if node is used more than once *) | |
100 let with_temp_maybeM node x = | |
101 fetchVisited >>= (fun v -> | |
102 match node_lookup node v with | |
103 Some count -> | |
104 if (count = 1 && !Magic.inline_single) then | |
105 inlineM x | |
106 else | |
107 with_tempM x | |
108 | None -> | |
109 failwith "with_temp_maybeM") | |
110 type fma = | |
111 NO_FMA | |
112 | FMA of expr * expr * expr (* FMA (a, b, c) => a + b * c *) | |
113 | FMS of expr * expr * expr (* FMS (a, b, c) => -a + b * c *) | |
114 | FNMS of expr * expr * expr (* FNMS (a, b, c) => a - b * c *) | |
115 | |
116 let good_for_fma (a, b) = | |
117 let good = function | |
118 | NaN I -> true | |
119 | NaN CONJ -> true | |
120 | NaN _ -> false | |
121 | Times(NaN _, _) -> false | |
122 | Times(_, NaN _) -> false | |
123 | _ -> true | |
124 in good a && good b | |
125 | |
126 let build_fma l = | |
127 if (not !Magic.enable_fma) then NO_FMA | |
128 else match l with | |
129 | [a; Uminus (Times (b, c))] when good_for_fma (b, c) -> FNMS (a, b, c) | |
130 | [Uminus (Times (b, c)); a] when good_for_fma (b, c) -> FNMS (a, b, c) | |
131 | [Uminus a; Times (b, c)] when good_for_fma (b, c) -> FMS (a, b, c) | |
132 | [Times (b, c); Uminus a] when good_for_fma (b, c) -> FMS (a, b, c) | |
133 | [a; Times (b, c)] when good_for_fma (b, c) -> FMA (a, b, c) | |
134 | [Times (b, c); a] when good_for_fma (b, c) -> FMA (a, b, c) | |
135 | _ -> NO_FMA | |
136 | |
137 let children_fma l = match build_fma l with | |
138 | FMA (a, b, c) -> Some (a, b, c) | |
139 | FMS (a, b, c) -> Some (a, b, c) | |
140 | FNMS (a, b, c) -> Some (a, b, c) | |
141 | NO_FMA -> None | |
142 | |
143 | |
144 let rec visitM x = | |
145 counting (function | |
146 | Load v -> returnM () | |
147 | Num a -> returnM () | |
148 | NaN a -> returnM () | |
149 | Store (v, x) -> visitM x | |
150 | Plus a -> (match children_fma a with | |
151 None -> mapM visitM a >> returnM () | |
152 | Some (a, b, c) -> | |
153 (* visit fma's arguments twice to make sure they are not inlined *) | |
154 visitM a >> visitM a >> | |
155 visitM b >> visitM b >> | |
156 visitM c >> visitM c) | |
157 | Times (a, b) -> visitM a >> visitM b | |
158 | CTimes (a, b) -> visitM a >> visitM b | |
159 | CTimesJ (a, b) -> visitM a >> visitM b | |
160 | Uminus a -> visitM a) | |
161 x | |
162 | |
163 let visit_rootsM = mapM visitM | |
164 | |
165 | |
166 let rec expr_of_nodeM x = | |
167 memoizing lookupVisitedM' insertVisitedM' | |
168 (function x -> match x with | |
169 | Load v -> | |
170 if (Variable.is_temporary v) then | |
171 inlineM (Load v) | |
172 else if (Variable.is_locative v && !Magic.inline_loads) then | |
173 inlineM (Load v) | |
174 else if (Variable.is_constant v && !Magic.inline_loads_constants) then | |
175 inlineM (Load v) | |
176 else | |
177 with_tempM (Load v) | |
178 | Num a -> | |
179 if !Magic.inline_constants then | |
180 inlineM (Num a) | |
181 else | |
182 with_temp_maybeM x (Num a) | |
183 | NaN a -> inlineM (NaN a) | |
184 | Store (v, x) -> | |
185 expr_of_nodeM x >>= | |
186 (if !Magic.trivial_stores then with_tempM else inlineM) >>= | |
187 with_varM v | |
188 | |
189 | Plus a -> | |
190 begin | |
191 match build_fma a with | |
192 FMA (a, b, c) -> | |
193 expr_of_nodeM a >>= fun a' -> | |
194 expr_of_nodeM b >>= fun b' -> | |
195 expr_of_nodeM c >>= fun c' -> | |
196 with_temp_maybeM x (Plus [a'; Times (b', c')]) | |
197 | FMS (a, b, c) -> | |
198 expr_of_nodeM a >>= fun a' -> | |
199 expr_of_nodeM b >>= fun b' -> | |
200 expr_of_nodeM c >>= fun c' -> | |
201 with_temp_maybeM x | |
202 (Plus [Times (b', c'); Uminus a']) | |
203 | FNMS (a, b, c) -> | |
204 expr_of_nodeM a >>= fun a' -> | |
205 expr_of_nodeM b >>= fun b' -> | |
206 expr_of_nodeM c >>= fun c' -> | |
207 with_temp_maybeM x | |
208 (Plus [a'; Uminus (Times (b', c'))]) | |
209 | NO_FMA -> | |
210 mapM expr_of_nodeM a >>= fun a' -> | |
211 with_temp_maybeM x (Plus a') | |
212 end | |
213 | CTimes (Load _ as a, b) when !Magic.generate_bytw -> | |
214 expr_of_nodeM b >>= fun b' -> | |
215 with_tempM (CTimes (a, b')) | |
216 | CTimes (a, b) -> | |
217 expr_of_nodeM a >>= fun a' -> | |
218 expr_of_nodeM b >>= fun b' -> | |
219 with_tempM (CTimes (a', b')) | |
220 | CTimesJ (Load _ as a, b) when !Magic.generate_bytw -> | |
221 expr_of_nodeM b >>= fun b' -> | |
222 with_tempM (CTimesJ (a, b')) | |
223 | CTimesJ (a, b) -> | |
224 expr_of_nodeM a >>= fun a' -> | |
225 expr_of_nodeM b >>= fun b' -> | |
226 with_tempM (CTimesJ (a', b')) | |
227 | Times (a, b) -> | |
228 expr_of_nodeM a >>= fun a' -> | |
229 expr_of_nodeM b >>= fun b' -> | |
230 begin | |
231 match a' with | |
232 Num a'' when !Magic.strength_reduce_mul && Number.is_two a'' -> | |
233 (inlineM b' >>= fun b'' -> | |
234 with_temp_maybeM x (Plus [b''; b''])) | |
235 | _ -> with_temp_maybeM x (Times (a', b')) | |
236 end | |
237 | Uminus a -> | |
238 expr_of_nodeM a >>= fun a' -> | |
239 inlineM (Uminus a')) | |
240 x | |
241 | |
242 let expr_of_rootsM = mapM expr_of_nodeM | |
243 | |
244 let peek_alistM roots = | |
245 visit_rootsM roots >> expr_of_rootsM roots >> fetchAl | |
246 | |
247 let wrap_assign (a, b) = Expr.Assign (a, b) | |
248 | |
249 let to_assignments dag = | |
250 let () = Util.info "begin to_alist" in | |
251 let al = List.rev (runM ([], empty, empty) peek_alistM dag) in | |
252 let res = List.map wrap_assign al in | |
253 let () = Util.info "end to_alist" in | |
254 res | |
255 | |
256 | |
257 (* dump alist in `dot' format *) | |
258 let dump print alist = | |
259 let vs v = "\"" ^ (Variable.unparse v) ^ "\"" in | |
260 begin | |
261 print "digraph G {\n"; | |
262 print "\tsize=\"6,6\";\n"; | |
263 | |
264 (* all input nodes have the same rank *) | |
265 print "{ rank = same;\n"; | |
266 List.iter (fun (Expr.Assign (v, x)) -> | |
267 List.iter (fun y -> | |
268 if (Variable.is_locative y) then print("\t" ^ (vs y) ^ ";\n")) | |
269 (Expr.find_vars x)) | |
270 alist; | |
271 print "}\n"; | |
272 | |
273 (* all output nodes have the same rank *) | |
274 print "{ rank = same;\n"; | |
275 List.iter (fun (Expr.Assign (v, x)) -> | |
276 if (Variable.is_locative v) then print("\t" ^ (vs v) ^ ";\n")) | |
277 alist; | |
278 print "}\n"; | |
279 | |
280 (* edges *) | |
281 List.iter (fun (Expr.Assign (v, x)) -> | |
282 List.iter (fun y -> print("\t" ^ (vs y) ^ " -> " ^ (vs v) ^ ";\n")) | |
283 (Expr.find_vars x)) | |
284 alist; | |
285 | |
286 print "}\n"; | |
287 end | |
288 |