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