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)) |