(* * Copyright (c) 1997-1999 Massachusetts Institute of Technology * Copyright (c) 2003, 2007-14 Matteo Frigo * Copyright (c) 2003, 2007-14 Massachusetts Institute of Technology * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * *) (* utilities common to all generators *) open Util let choose_simd a b = if !Simdmagic.simd_mode then b else a let unique_array n = array n (fun _ -> Unique.make ()) let unique_array_c n = array n (fun _ -> (Unique.make (), Unique.make ())) let unique_v_array_c veclen n = array veclen (fun _ -> unique_array_c n) let locative_array_c n rarr iarr loc vs = array n (fun i -> let klass = Unique.make () in let (rloc, iloc) = loc i in (Variable.make_locative rloc klass rarr i vs, Variable.make_locative iloc klass iarr i vs)) let locative_v_array_c veclen n rarr iarr loc vs = array veclen (fun v -> array n (fun i -> let klass = Unique.make () in let (rloc, iloc) = loc v i in (Variable.make_locative rloc klass (rarr v) i vs, Variable.make_locative iloc klass (iarr v) i vs))) let temporary_array n = array n (fun i -> Variable.make_temporary ()) let temporary_array_c n = let tmpr = temporary_array n and tmpi = temporary_array n in array n (fun i -> (tmpr i, tmpi i)) let temporary_v_array_c veclen n = array veclen (fun v -> temporary_array_c n) let temporary_array_c n = let tmpr = temporary_array n and tmpi = temporary_array n in array n (fun i -> (tmpr i, tmpi i)) let load_c (vr, vi) = Complex.make (Expr.Load vr, Expr.Load vi) let load_r (vr, vi) = Complex.make (Expr.Load vr, Expr.Num (Number.zero)) let twiddle_array nt w = array (nt/2) (fun i -> let stride = choose_simd (C.SInteger 1) (C.SConst "TWVL") and klass = Unique.make () in let (refr, refi) = (C.array_subscript w stride (2 * i), C.array_subscript w stride (2 * i + 1)) in let (kr, ki) = (Variable.make_constant klass refr, Variable.make_constant klass refi) in load_c (kr, ki)) let load_array_c n var = array n (fun i -> load_c (var i)) let load_array_r n var = array n (fun i -> load_r (var i)) let load_array_hc n var = array n (fun i -> if (i < n - i) then load_c (var i) else if (i > n - i) then Complex.times Complex.i (load_c (var (n - i))) else load_r (var i)) let load_v_array_c veclen n var = array veclen (fun v -> load_array_c n (var v)) let store_c (vr, vi) x = [Complex.store_real vr x; Complex.store_imag vi x] let store_r (vr, vi) x = Complex.store_real vr x let store_i (vr, vi) x = Complex.store_imag vi x let assign_array_c n dst src = List.flatten (rmap (iota n) (fun i -> let (ar, ai) = Complex.assign (dst i) (src i) in [ar; ai])) let assign_v_array_c veclen n dst src = List.flatten (rmap (iota veclen) (fun v -> assign_array_c n (dst v) (src v))) let vassign_v_array_c veclen n dst src = List.flatten (rmap (iota n) (fun i -> List.flatten (rmap (iota veclen) (fun v -> let (ar, ai) = Complex.assign (dst v i) (src v i) in [ar; ai])))) let store_array_r n dst src = rmap (iota n) (fun i -> store_r (dst i) (src i)) let store_array_c n dst src = List.flatten (rmap (iota n) (fun i -> store_c (dst i) (src i))) let store_array_hc n dst src = List.flatten (rmap (iota n) (fun i -> if (i < n - i) then store_c (dst i) (src i) else if (i > n - i) then [] else [store_r (dst i) (Complex.real (src i))])) let store_v_array_c veclen n dst src = List.flatten (rmap (iota veclen) (fun v -> store_array_c n (dst v) (src v))) let elementwise f n a = array n (fun i -> f (a i)) let conj_array_c = elementwise Complex.conj let real_array_c = elementwise Complex.real let imag_array_c = elementwise Complex.imag let elementwise_v f veclen n a = array veclen (fun v -> array n (fun i -> f (a v i))) let conj_v_array_c = elementwise_v Complex.conj let real_v_array_c = elementwise_v Complex.real let imag_v_array_c = elementwise_v Complex.imag let transpose f i j = f j i let symmetrize f i j = if i <= j then f i j else f j i (* utilities for command-line parsing *) let standard_arg_parse_fail _ = failwith "too many arguments" let dump_dag alist = let fnam = !Magic.dag_dump_file in if (String.length fnam > 0) then let ochan = open_out fnam in begin To_alist.dump (output_string ochan) alist; close_out ochan; end let dump_alist alist = let fnam = !Magic.alist_dump_file in if (String.length fnam > 0) then let ochan = open_out fnam in begin Expr.dump (output_string ochan) alist; close_out ochan; end let dump_asched asched = let fnam = !Magic.asched_dump_file in if (String.length fnam > 0) then let ochan = open_out fnam in begin Annotate.dump (output_string ochan) asched; close_out ochan; end (* utilities for optimization *) let standard_scheduler dag = let optim = Algsimp.algsimp dag in let alist = To_alist.to_assignments optim in let _ = dump_alist alist in let _ = dump_dag alist in if !Magic.precompute_twiddles then Schedule.isolate_precomputations_and_schedule alist else Schedule.schedule alist let standard_optimizer dag = let sched = standard_scheduler dag in let annot = Annotate.annotate [] sched in let _ = dump_asched annot in annot let size = ref None let sign = ref (-1) let speclist = [ "-n", Arg.Int(fun i -> size := Some i), " generate a codelet of size "; "-sign", Arg.Int(fun i -> if (i > 0) then sign := 1 else sign := (-1)), " sign of transform"; ] let check_size () = match !size with | Some i -> i | None -> failwith "must specify -n" let expand_name name = if name = "" then "noname" else name let declare_register_fcn name = if name = "" then "void NAME(planner *p)\n" else "void " ^ (choose_simd "X" "XSIMD") ^ "(codelet_" ^ name ^ ")(planner *p)\n" let stringify name = if name = "" then "STRINGIZE(NAME)" else choose_simd ("\"" ^ name ^ "\"") ("XSIMD_STRING(\"" ^ name ^ "\")") let parse user_speclist usage = Arg.parse (user_speclist @ speclist @ Magic.speclist @ Simdmagic.speclist) standard_arg_parse_fail usage let rec list_to_c = function [] -> "" | [a] -> (string_of_int a) | a :: b -> (string_of_int a) ^ ", " ^ (list_to_c b) let rec list_to_comma = function | [a; b] -> C.Comma (a, b) | a :: b -> C.Comma (a, list_to_comma b) | _ -> failwith "list_to_comma" type stride = Stride_variable | Fixed_int of int | Fixed_string of string let either_stride a b = match a with Fixed_int x -> C.SInteger x | Fixed_string x -> C.SConst x | _ -> b let stride_fixed = function Stride_variable -> false | _ -> true let arg_to_stride s = try Fixed_int (int_of_string s) with Failure "int_of_string" -> Fixed_string s let stride_to_solverparm = function Stride_variable -> "0" | Fixed_int x -> string_of_int x | Fixed_string x -> x let stride_to_string s = function Stride_variable -> s | Fixed_int x -> string_of_int x | Fixed_string x -> x (* output the command line *) let cmdline () = List.fold_right (fun a b -> a ^ " " ^ b) (Array.to_list Sys.argv) "" let unparse tree = "/* Generated by: " ^ (cmdline ()) ^ "*/\n\n" ^ (C.print_cost tree) ^ (if String.length !Magic.inklude > 0 then (Printf.sprintf "#include \"%s\"\n\n" !Magic.inklude) else "") ^ (if !Simdmagic.simd_mode then Simd.unparse_function tree else C.unparse_function tree) let finalize_fcn ast = let mergedecls = function C.Block (d1, [C.Block (d2, s)]) -> C.Block (d1 @ d2, s) | x -> x and extract_constants = if !Simdmagic.simd_mode then Simd.extract_constants else C.extract_constants in mergedecls (C.Block (extract_constants ast, [ast; C.Simd_leavefun])) let twinstr_to_string vl x = if !Simdmagic.simd_mode then Twiddle.twinstr_to_simd_string vl x else Twiddle.twinstr_to_c_string x let make_volatile_stride n x = C.CCall ("MAKE_VOLATILE_STRIDE", C.Comma((C.Integer n), x))