comparison src/fftw-3.3.3/genfft/c.ml @ 95:89f5e221ed7b

Add FFTW3
author Chris Cannam <cannam@all-day-breakfast.com>
date Wed, 20 Mar 2013 15:35:50 +0000
parents
children
comparison
equal deleted inserted replaced
94:d278df1123f9 95:89f5e221ed7b
1 (*
2 * Copyright (c) 1997-1999 Massachusetts Institute of Technology
3 * Copyright (c) 2003, 2007-11 Matteo Frigo
4 * Copyright (c) 2003, 2007-11 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