Mercurial > hg > sv-dependency-builds
comparison src/fftw-3.3.5/genfft/c.ml @ 42:2cd0e3b3e1fd
Current fftw source
author | Chris Cannam |
---|---|
date | Tue, 18 Oct 2016 13:40:26 +0100 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
41:481f5f8c5634 | 42:2cd0e3b3e1fd |
---|---|
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 * This module contains the definition of a C-like abstract | |
24 * syntax tree, and functions to convert ML values into C | |
25 * programs | |
26 *) | |
27 | |
28 open Expr | |
29 open Annotate | |
30 open List | |
31 | |
32 let realtype = "R" | |
33 let realtypep = realtype ^ " *" | |
34 let extended_realtype = "E" | |
35 let constrealtype = "const " ^ realtype | |
36 let constrealtypep = constrealtype ^ " *" | |
37 | |
38 let stridetype = "stride" | |
39 | |
40 (*********************************** | |
41 * C program structure | |
42 ***********************************) | |
43 type c_decl = | |
44 | Decl of string * string | |
45 | Tdecl of string (* arbitrary text declaration *) | |
46 | |
47 and c_ast = | |
48 | Asch of annotated_schedule | |
49 | Simd_leavefun | |
50 | Return of c_ast | |
51 | For of c_ast * c_ast * c_ast * c_ast | |
52 | If of c_ast * c_ast | |
53 | Block of (c_decl list) * (c_ast list) | |
54 | Binop of string * c_ast * c_ast | |
55 | Expr_assign of c_ast * c_ast | |
56 | Stmt_assign of c_ast * c_ast | |
57 | Comma of c_ast * c_ast | |
58 | Integer of int | |
59 | CVar of string | |
60 | CCall of string * c_ast | |
61 | CPlus of c_ast list | |
62 | ITimes of c_ast * c_ast | |
63 | CUminus of c_ast | |
64 and c_fcn = Fcn of string * string * (c_decl list) * c_ast | |
65 | |
66 | |
67 let ctimes = function | |
68 | (Integer 1), a -> a | |
69 | a, (Integer 1) -> a | |
70 | a, b -> ITimes (a, b) | |
71 | |
72 (* | |
73 * C AST unparser | |
74 *) | |
75 let foldr_string_concat l = fold_right (^) l "" | |
76 | |
77 let rec unparse_expr_c = | |
78 let yes x = x and no x = "" in | |
79 | |
80 let rec unparse_plus maybe = | |
81 let maybep = maybe " + " in | |
82 function | |
83 | [] -> "" | |
84 | (Uminus (Times (a, b))) :: (Uminus c) :: d -> | |
85 maybep ^ (op "FNMA" a b c) ^ (unparse_plus yes d) | |
86 | (Uminus c) :: (Uminus (Times (a, b))) :: d -> | |
87 maybep ^ (op "FNMA" a b c) ^ (unparse_plus yes d) | |
88 | (Uminus (Times (a, b))) :: c :: d -> | |
89 maybep ^ (op "FNMS" a b c) ^ (unparse_plus yes d) | |
90 | c :: (Uminus (Times (a, b))) :: d -> | |
91 maybep ^ (op "FNMS" a b c) ^ (unparse_plus yes d) | |
92 | (Times (a, b)) :: (Uminus c) :: d -> | |
93 maybep ^ (op "FMS" a b c) ^ (unparse_plus yes d) | |
94 | (Uminus c) :: (Times (a, b)) :: d -> | |
95 maybep ^ (op "FMS" a b c) ^ (unparse_plus yes d) | |
96 | (Times (a, b)) :: c :: d -> | |
97 maybep ^ (op "FMA" a b c) ^ (unparse_plus yes d) | |
98 | c :: (Times (a, b)) :: d -> | |
99 maybep ^ (op "FMA" a b c) ^ (unparse_plus yes d) | |
100 | (Uminus a :: b) -> | |
101 " - " ^ (parenthesize a) ^ (unparse_plus yes b) | |
102 | (a :: b) -> | |
103 maybep ^ (parenthesize a) ^ (unparse_plus yes b) | |
104 and parenthesize x = match x with | |
105 | (Load _) -> unparse_expr_c x | |
106 | (Num _) -> unparse_expr_c x | |
107 | _ -> "(" ^ (unparse_expr_c x) ^ ")" | |
108 and op nam a b c = | |
109 nam ^ "(" ^ (unparse_expr_c a) ^ ", " ^ (unparse_expr_c b) ^ ", " ^ | |
110 (unparse_expr_c c) ^ ")" | |
111 | |
112 in function | |
113 | Load v -> Variable.unparse v | |
114 | Num n -> Number.to_konst n | |
115 | Plus [] -> "0.0 /* bug */" | |
116 | Plus [a] -> " /* bug */ " ^ (unparse_expr_c a) | |
117 | Plus a -> (unparse_plus no a) | |
118 | Times (a, b) -> (parenthesize a) ^ " * " ^ (parenthesize b) | |
119 | Uminus (Plus [a; Uminus b]) -> unparse_plus no [b; Uminus a] | |
120 | Uminus a -> "- " ^ (parenthesize a) | |
121 | _ -> failwith "unparse_expr_c" | |
122 | |
123 and unparse_expr_generic = | |
124 let rec u x = unparse_expr_generic x | |
125 and unary op a = Printf.sprintf "%s(%s)" op (u a) | |
126 and binary op a b = Printf.sprintf "%s(%s, %s)" op (u a) (u b) | |
127 and ternary op a b c = Printf.sprintf "%s(%s, %s, %s)" op (u a) (u b) (u c) | |
128 and quaternary op a b c d = | |
129 Printf.sprintf "%s(%s, %s, %s, %s)" op (u a) (u b) (u c) (u d) | |
130 and unparse_plus = function | |
131 | [(Uminus (Times (a, b))); Times (c, d)] -> quaternary "FNMMS" a b c d | |
132 | [Times (c, d); (Uminus (Times (a, b)))] -> quaternary "FNMMS" a b c d | |
133 | [Times (c, d); (Times (a, b))] -> quaternary "FMMA" a b c d | |
134 | [(Uminus (Times (a, b))); c] -> ternary "FNMS" a b c | |
135 | [c; (Uminus (Times (a, b)))] -> ternary "FNMS" a b c | |
136 | [(Uminus c); (Times (a, b))] -> ternary "FMS" a b c | |
137 | [(Times (a, b)); (Uminus c)] -> ternary "FMS" a b c | |
138 | [c; (Times (a, b))] -> ternary "FMA" a b c | |
139 | [(Times (a, b)); c] -> ternary "FMA" a b c | |
140 | [a; Uminus b] -> binary "SUB" a b | |
141 | [a; b] -> binary "ADD" a b | |
142 | a :: b :: c -> binary "ADD" a (Plus (b :: c)) | |
143 | _ -> failwith "unparse_plus" | |
144 in function | |
145 | Load v -> Variable.unparse v | |
146 | Num n -> Number.to_konst n | |
147 | Plus a -> unparse_plus a | |
148 | Times (a, b) -> binary "MUL" a b | |
149 | Uminus a -> unary "NEG" a | |
150 | _ -> failwith "unparse_expr" | |
151 | |
152 and unparse_expr x = | |
153 if !Magic.generic_arith then | |
154 unparse_expr_generic x | |
155 else | |
156 unparse_expr_c x | |
157 | |
158 and unparse_assignment (Assign (v, x)) = | |
159 (Variable.unparse v) ^ " = " ^ (unparse_expr x) ^ ";\n" | |
160 | |
161 and unparse_annotated force_bracket = | |
162 let rec unparse_code = function | |
163 ADone -> "" | |
164 | AInstr i -> unparse_assignment i | |
165 | ASeq (a, b) -> | |
166 (unparse_annotated false a) ^ (unparse_annotated false b) | |
167 and declare_variables l = | |
168 let rec uvar = function | |
169 [] -> failwith "uvar" | |
170 | [v] -> (Variable.unparse v) ^ ";\n" | |
171 | a :: b -> (Variable.unparse a) ^ ", " ^ (uvar b) | |
172 in let rec vvar l = | |
173 let s = if !Magic.compact then 15 else 1 in | |
174 if (List.length l <= s) then | |
175 match l with | |
176 [] -> "" | |
177 | _ -> extended_realtype ^ " " ^ (uvar l) | |
178 else | |
179 (vvar (Util.take s l)) ^ (vvar (Util.drop s l)) | |
180 in vvar (List.filter Variable.is_temporary l) | |
181 in function | |
182 Annotate (_, _, decl, _, code) -> | |
183 if (not force_bracket) && (Util.null decl) then | |
184 unparse_code code | |
185 else "{\n" ^ | |
186 (declare_variables decl) ^ | |
187 (unparse_code code) ^ | |
188 "}\n" | |
189 | |
190 and unparse_decl = function | |
191 | Decl (a, b) -> a ^ " " ^ b ^ ";\n" | |
192 | Tdecl x -> x | |
193 | |
194 and unparse_ast = | |
195 let rec unparse_plus = function | |
196 | [] -> "" | |
197 | (CUminus a :: b) -> " - " ^ (parenthesize a) ^ (unparse_plus b) | |
198 | (a :: b) -> " + " ^ (parenthesize a) ^ (unparse_plus b) | |
199 and parenthesize x = match x with | |
200 | (CVar _) -> unparse_ast x | |
201 | (CCall _) -> unparse_ast x | |
202 | (Integer _) -> unparse_ast x | |
203 | _ -> "(" ^ (unparse_ast x) ^ ")" | |
204 | |
205 in | |
206 function | |
207 | Asch a -> (unparse_annotated true a) | |
208 | Simd_leavefun -> "" (* used only in SIMD code *) | |
209 | Return x -> "return " ^ unparse_ast x ^ ";" | |
210 | For (a, b, c, d) -> | |
211 "for (" ^ | |
212 unparse_ast a ^ "; " ^ unparse_ast b ^ "; " ^ unparse_ast c | |
213 ^ ")" ^ unparse_ast d | |
214 | If (a, d) -> | |
215 "if (" ^ | |
216 unparse_ast a | |
217 ^ ")" ^ unparse_ast d | |
218 | Block (d, s) -> | |
219 if (s == []) then "" | |
220 else | |
221 "{\n" ^ | |
222 foldr_string_concat (map unparse_decl d) ^ | |
223 foldr_string_concat (map unparse_ast s) ^ | |
224 "}\n" | |
225 | Binop (op, a, b) -> (unparse_ast a) ^ op ^ (unparse_ast b) | |
226 | Expr_assign (a, b) -> (unparse_ast a) ^ " = " ^ (unparse_ast b) | |
227 | Stmt_assign (a, b) -> (unparse_ast a) ^ " = " ^ (unparse_ast b) ^ ";\n" | |
228 | Comma (a, b) -> (unparse_ast a) ^ ", " ^ (unparse_ast b) | |
229 | Integer i -> string_of_int i | |
230 | CVar s -> s | |
231 | CCall (s, x) -> s ^ "(" ^ (unparse_ast x) ^ ")" | |
232 | CPlus [] -> "0 /* bug */" | |
233 | CPlus [a] -> " /* bug */ " ^ (unparse_ast a) | |
234 | CPlus (a::b) -> (parenthesize a) ^ (unparse_plus b) | |
235 | ITimes (a, b) -> (parenthesize a) ^ " * " ^ (parenthesize b) | |
236 | CUminus a -> "- " ^ (parenthesize a) | |
237 | |
238 and unparse_function = function | |
239 Fcn (typ, name, args, body) -> | |
240 let rec unparse_args = function | |
241 [Decl (a, b)] -> a ^ " " ^ b | |
242 | (Decl (a, b)) :: s -> a ^ " " ^ b ^ ", " | |
243 ^ unparse_args s | |
244 | [] -> "" | |
245 | _ -> failwith "unparse_function" | |
246 in | |
247 (typ ^ " " ^ name ^ "(" ^ unparse_args args ^ ")\n" ^ | |
248 unparse_ast body) | |
249 | |
250 | |
251 (************************************************************* | |
252 * traverse a a function and return a list of all expressions, | |
253 * in the execution order | |
254 **************************************************************) | |
255 let rec fcn_to_expr_list = fun (Fcn (_, _, _, body)) -> ast_to_expr_list body | |
256 and acode_to_expr_list = function | |
257 AInstr (Assign (_, x)) -> [x] | |
258 | ASeq (a, b) -> | |
259 (asched_to_expr_list a) @ (asched_to_expr_list b) | |
260 | _ -> [] | |
261 and asched_to_expr_list (Annotate (_, _, _, _, code)) = | |
262 acode_to_expr_list code | |
263 and ast_to_expr_list = function | |
264 Asch a -> asched_to_expr_list a | |
265 | Block (_, a) -> flatten (map ast_to_expr_list a) | |
266 | For (_, _, _, body) -> ast_to_expr_list body | |
267 | If (_, body) -> ast_to_expr_list body | |
268 | _ -> [] | |
269 | |
270 (*********************** | |
271 * Extracting Constants | |
272 ***********************) | |
273 | |
274 (* add a new key & value to a list of (key,value) pairs, where | |
275 the keys are floats and each key is unique up to almost_equal *) | |
276 | |
277 let extract_constants f = | |
278 let constlist = flatten (map expr_to_constants (ast_to_expr_list f)) | |
279 in map | |
280 (fun n -> | |
281 Tdecl | |
282 ("DK(" ^ (Number.to_konst n) ^ ", " ^ (Number.to_string n) ^ | |
283 ");\n")) | |
284 (unique_constants constlist) | |
285 | |
286 (****************************** | |
287 Extracting operation counts | |
288 ******************************) | |
289 | |
290 let count_stack_vars = | |
291 let rec count_acode = function | |
292 | ASeq (a, b) -> max (count_asched a) (count_asched b) | |
293 | _ -> 0 | |
294 and count_asched (Annotate (_, _, decl, _, code)) = | |
295 (length decl) + (count_acode code) | |
296 and count_ast = function | |
297 | Asch a -> count_asched a | |
298 | Block (d, a) -> (length d) + (Util.max_list (map count_ast a)) | |
299 | For (_, _, _, body) -> count_ast body | |
300 | If (_, body) -> count_ast body | |
301 | _ -> 0 | |
302 in function (Fcn (_, _, _, body)) -> count_ast body | |
303 | |
304 let count_memory_acc f = | |
305 let rec count_var v = | |
306 if (Variable.is_locative v) then 1 else 0 | |
307 and count_acode = function | |
308 | AInstr (Assign (v, _)) -> count_var v | |
309 | ASeq (a, b) -> (count_asched a) + (count_asched b) | |
310 | _ -> 0 | |
311 and count_asched = function | |
312 Annotate (_, _, _, _, code) -> count_acode code | |
313 and count_ast = function | |
314 | Asch a -> count_asched a | |
315 | Block (_, a) -> (Util.sum_list (map count_ast a)) | |
316 | Comma (a, b) -> (count_ast a) + (count_ast b) | |
317 | For (_, _, _, body) -> count_ast body | |
318 | If (_, body) -> count_ast body | |
319 | _ -> 0 | |
320 and count_acc_expr_func acc = function | |
321 | Load v -> acc + (count_var v) | |
322 | Plus a -> fold_left count_acc_expr_func acc a | |
323 | Times (a, b) -> fold_left count_acc_expr_func acc [a; b] | |
324 | Uminus a -> count_acc_expr_func acc a | |
325 | _ -> acc | |
326 in let (Fcn (typ, name, args, body)) = f | |
327 in (count_ast body) + | |
328 fold_left count_acc_expr_func 0 (fcn_to_expr_list f) | |
329 | |
330 let good_for_fma = To_alist.good_for_fma | |
331 | |
332 let build_fma = function | |
333 | [a; Times (b, c)] when good_for_fma (b, c) -> Some (a, b, c) | |
334 | [Times (b, c); a] when good_for_fma (b, c) -> Some (a, b, c) | |
335 | [a; Uminus (Times (b, c))] when good_for_fma (b, c) -> Some (a, b, c) | |
336 | [Uminus (Times (b, c)); a] when good_for_fma (b, c) -> Some (a, b, c) | |
337 | _ -> None | |
338 | |
339 let rec count_flops_expr_func (adds, mults, fmas) = function | |
340 | Plus [] -> (adds, mults, fmas) | |
341 | Plus ([_; _] as a) -> | |
342 begin | |
343 match build_fma a with | |
344 | None -> | |
345 fold_left count_flops_expr_func | |
346 (adds + (length a) - 1, mults, fmas) a | |
347 | Some (a, b, c) -> | |
348 fold_left count_flops_expr_func (adds, mults, fmas+1) [a; b; c] | |
349 end | |
350 | Plus (a :: b) -> | |
351 count_flops_expr_func (adds, mults, fmas) (Plus [a; Plus b]) | |
352 | Times (NaN MULTI_A,_) -> (adds, mults, fmas) | |
353 | Times (NaN MULTI_B,_) -> (adds, mults, fmas) | |
354 | Times (NaN I,b) -> count_flops_expr_func (adds, mults, fmas) b | |
355 | Times (NaN CONJ,b) -> count_flops_expr_func (adds, mults, fmas) b | |
356 | Times (a,b) -> fold_left count_flops_expr_func (adds, mults+1, fmas) [a; b] | |
357 | CTimes (a,b) -> | |
358 fold_left count_flops_expr_func (adds+1, mults+2, fmas) [a; b] | |
359 | CTimesJ (a,b) -> | |
360 fold_left count_flops_expr_func (adds+1, mults+2, fmas) [a; b] | |
361 | Uminus a -> count_flops_expr_func (adds, mults, fmas) a | |
362 | _ -> (adds, mults, fmas) | |
363 | |
364 let count_flops f = | |
365 fold_left count_flops_expr_func (0, 0, 0) (fcn_to_expr_list f) | |
366 | |
367 let count_constants f = | |
368 length (unique_constants (flatten (map expr_to_constants (fcn_to_expr_list f)))) | |
369 | |
370 let arith_complexity f = | |
371 let (a, m, fmas) = count_flops f | |
372 and v = count_stack_vars f | |
373 and c = count_constants f | |
374 and mem = count_memory_acc f | |
375 in (a, m, fmas, v, c, mem) | |
376 | |
377 (* print the operation costs *) | |
378 let print_cost f = | |
379 let Fcn (_, _, _, _) = f | |
380 and (a, m, fmas, v, c, mem) = arith_complexity f | |
381 in | |
382 "/*\n"^ | |
383 " * This function contains " ^ | |
384 (string_of_int (a + fmas)) ^ " FP additions, " ^ | |
385 (string_of_int (m + fmas)) ^ " FP multiplications,\n" ^ | |
386 " * (or, " ^ | |
387 (string_of_int a) ^ " additions, " ^ | |
388 (string_of_int m) ^ " multiplications, " ^ | |
389 (string_of_int fmas) ^ " fused multiply/add),\n" ^ | |
390 " * " ^ (string_of_int v) ^ " stack variables, " ^ | |
391 (string_of_int c) ^ " constants, and " ^ | |
392 (string_of_int mem) ^ " memory accesses\n" ^ | |
393 " */\n" | |
394 | |
395 (***************************************** | |
396 * functions that create C arrays | |
397 *****************************************) | |
398 type stride = | |
399 | SVar of string | |
400 | SConst of string | |
401 | SInteger of int | |
402 | SNeg of stride | |
403 | |
404 type sstride = | |
405 | Simple of int | |
406 | Constant of (string * int) | |
407 | Composite of (string * int) | |
408 | Negative of sstride | |
409 | |
410 let rec simplify_stride stride i = | |
411 match (stride, i) with | |
412 (_, 0) -> Simple 0 | |
413 | (SInteger n, i) -> Simple (n * i) | |
414 | (SConst s, i) -> Constant (s, i) | |
415 | (SVar s, i) -> Composite (s, i) | |
416 | (SNeg x, i) -> | |
417 match (simplify_stride x i) with | |
418 | Negative y -> y | |
419 | y -> Negative y | |
420 | |
421 let rec cstride_to_string = function | |
422 | Simple i -> string_of_int i | |
423 | Constant (s, i) -> | |
424 if !Magic.lisp_syntax then | |
425 "(* " ^ s ^ " " ^ (string_of_int i) ^ ")" | |
426 else | |
427 s ^ " * " ^ (string_of_int i) | |
428 | Composite (s, i) -> | |
429 if !Magic.lisp_syntax then | |
430 "(* " ^ s ^ " " ^ (string_of_int i) ^ ")" | |
431 else | |
432 "WS(" ^ s ^ ", " ^ (string_of_int i) ^ ")" | |
433 | Negative x -> "-" ^ cstride_to_string x | |
434 | |
435 let aref name index = | |
436 if !Magic.lisp_syntax then | |
437 Printf.sprintf "(aref %s %s)" name index | |
438 else | |
439 Printf.sprintf "%s[%s]" name index | |
440 | |
441 let array_subscript name stride k = | |
442 aref name (cstride_to_string (simplify_stride stride k)) | |
443 | |
444 let varray_subscript name vstride stride v i = | |
445 let vindex = simplify_stride vstride v | |
446 and iindex = simplify_stride stride i | |
447 in | |
448 let index = | |
449 match (vindex, iindex) with | |
450 (Simple vi, Simple ii) -> string_of_int (vi + ii) | |
451 | (Simple 0, x) -> cstride_to_string x | |
452 | (x, Simple 0) -> cstride_to_string x | |
453 | _ -> (cstride_to_string vindex) ^ " + " ^ (cstride_to_string iindex) | |
454 in aref name index | |
455 | |
456 let real_of s = "c_re(" ^ s ^ ")" | |
457 let imag_of s = "c_im(" ^ s ^ ")" | |
458 | |
459 let flops_of f = | |
460 let (add, mul, fma) = count_flops f in | |
461 Printf.sprintf "{ %d, %d, %d, 0 }" add mul fma |