329 lines
		
	
	
		
			8.7 KiB
		
	
	
	
		
			OCaml
		
	
	
	
	
	
			
		
		
	
	
			329 lines
		
	
	
		
			8.7 KiB
		
	
	
	
		
			OCaml
		
	
	
	
	
	
| (*
 | |
|  * 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 <n>";
 | |
|   "-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))
 | 
