258 lines
		
	
	
		
			7.5 KiB
		
	
	
	
		
			OCaml
		
	
	
	
	
	
		
		
			
		
	
	
			258 lines
		
	
	
		
			7.5 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 | ||
|  |  * | ||
|  |  *) | ||
|  | 
 | ||
|  | (* generation of trigonometric transforms *) | ||
|  | 
 | ||
|  | open Util | ||
|  | open Genutil | ||
|  | open C | ||
|  | 
 | ||
|  | 
 | ||
|  | let usage = "Usage: " ^ Sys.argv.(0) ^ " -n <number>" | ||
|  | 
 | ||
|  | let uistride = ref Stride_variable | ||
|  | let uostride = ref Stride_variable | ||
|  | let uivstride = ref Stride_variable | ||
|  | let uovstride = ref Stride_variable | ||
|  | let normalization = ref 1 | ||
|  | 
 | ||
|  | type mode = | ||
|  |   | MDCT | ||
|  |   | MDCT_MP3 | ||
|  |   | MDCT_VORBIS | ||
|  |   | MDCT_WINDOW | ||
|  |   | MDCT_WINDOW_SYM | ||
|  |   | IMDCT | ||
|  |   | IMDCT_MP3 | ||
|  |   | IMDCT_VORBIS | ||
|  |   | IMDCT_WINDOW | ||
|  |   | IMDCT_WINDOW_SYM | ||
|  |   | NONE | ||
|  | 
 | ||
|  | let mode = ref NONE | ||
|  | 
 | ||
|  | let speclist = [ | ||
|  |   "-with-istride", | ||
|  |   Arg.String(fun x -> uistride := arg_to_stride x), | ||
|  |   " specialize for given input stride"; | ||
|  | 
 | ||
|  |   "-with-ostride", | ||
|  |   Arg.String(fun x -> uostride := arg_to_stride x), | ||
|  |   " specialize for given output stride"; | ||
|  | 
 | ||
|  |   "-with-ivstride", | ||
|  |   Arg.String(fun x -> uivstride := arg_to_stride x), | ||
|  |   " specialize for given input vector stride"; | ||
|  | 
 | ||
|  |   "-with-ovstride", | ||
|  |   Arg.String(fun x -> uovstride := arg_to_stride x), | ||
|  |   " specialize for given output vector stride"; | ||
|  | 
 | ||
|  |   "-normalization", | ||
|  |   Arg.String(fun x -> normalization := int_of_string x), | ||
|  |   " normalization integer to divide by"; | ||
|  | 
 | ||
|  |   "-mdct", | ||
|  |   Arg.Unit(fun () -> mode := MDCT), | ||
|  |   " generate an MDCT codelet"; | ||
|  | 
 | ||
|  |   "-mdct-mp3", | ||
|  |   Arg.Unit(fun () -> mode := MDCT_MP3), | ||
|  |   " generate an MDCT codelet with MP3 windowing"; | ||
|  | 
 | ||
|  |   "-mdct-window", | ||
|  |   Arg.Unit(fun () -> mode := MDCT_WINDOW), | ||
|  |   " generate an MDCT codelet with window array"; | ||
|  | 
 | ||
|  |   "-mdct-window-sym", | ||
|  |   Arg.Unit(fun () -> mode := MDCT_WINDOW_SYM), | ||
|  |   " generate an MDCT codelet with symmetric window array"; | ||
|  | 
 | ||
|  |   "-imdct", | ||
|  |   Arg.Unit(fun () -> mode := IMDCT), | ||
|  |   " generate an IMDCT codelet"; | ||
|  | 
 | ||
|  |   "-imdct-mp3", | ||
|  |   Arg.Unit(fun () -> mode := IMDCT_MP3), | ||
|  |   " generate an IMDCT codelet with MP3 windowing"; | ||
|  | 
 | ||
|  |   "-imdct-window", | ||
|  |   Arg.Unit(fun () -> mode := IMDCT_WINDOW), | ||
|  |   " generate an IMDCT codelet with window array"; | ||
|  | 
 | ||
|  |   "-imdct-window-sym", | ||
|  |   Arg.Unit(fun () -> mode := IMDCT_WINDOW_SYM), | ||
|  |   " generate an IMDCT codelet with symmetric window array"; | ||
|  | ] | ||
|  | 
 | ||
|  | let unity_window n i = Complex.one | ||
|  | 
 | ||
|  | (* MP3 window(k) = sin(pi/(2n) * (k + 1/2)) *) | ||
|  | let mp3_window n k =  | ||
|  |   Complex.imag (Complex.exp (8 * n) (2*k + 1)) | ||
|  | 
 | ||
|  | (* Vorbis window(k) = sin(pi/2 * (mp3_window(k))^2)
 | ||
|  |     ... this is transcendental, though, so we can't do it with our | ||
|  |         current Complex.exp function *) | ||
|  | 
 | ||
|  | let window_array n w = | ||
|  |     array n (fun i -> | ||
|  |       let stride = C.SInteger 1 | ||
|  |       and klass = Unique.make () in | ||
|  |       let refr = C.array_subscript w stride i in | ||
|  |       let kr = Variable.make_constant klass refr in | ||
|  |       load_r (kr, kr)) | ||
|  | 
 | ||
|  | let load_window w n i = w i | ||
|  | let load_window_sym w n i = w (if (i < n) then i else (2*n - 1 - i)) | ||
|  | 
 | ||
|  | (* fixme: use same locations for input and output so that it works in-place? *) | ||
|  | 
 | ||
|  | (* Note: only correct for even n! *) | ||
|  | let load_array_mdct window n rarr iarr locations = | ||
|  |   let twon = 2 * n in | ||
|  |   let arr = load_array_c twon  | ||
|  |       (locative_array_c twon rarr iarr locations "BUG") in | ||
|  |   let arrw = fun i -> Complex.times (window n i) (arr i) in | ||
|  |   array n | ||
|  |     ((Complex.times Complex.half) @@ | ||
|  |      (fun i -> | ||
|  |        if (i < n/2) then | ||
|  | 	 Complex.uminus (Complex.plus [arrw (i + n + n/2);  | ||
|  | 				       arrw (n + n/2 - 1 - i)]) | ||
|  |        else | ||
|  | 	 Complex.plus [arrw (i - n/2);  | ||
|  | 		       Complex.uminus (arrw (n + n/2 - 1 - i))])) | ||
|  | 
 | ||
|  | let store_array_mdct window n rarr iarr locations arr = | ||
|  |   store_array_r n (locative_array_c n rarr iarr locations "BUG") arr | ||
|  | 
 | ||
|  | let load_array_imdct window n rarr iarr locations = | ||
|  |   load_array_c n (locative_array_c n rarr iarr locations "BUG") | ||
|  | 
 | ||
|  | let store_array_imdct window n rarr iarr locations arr = | ||
|  |   let n2 = n/2 in | ||
|  |   let threen2 = 3*n2 in | ||
|  |   let arr2 = fun i -> | ||
|  |     if (i < n2) then | ||
|  |       arr (i + n2) | ||
|  |     else if (i < threen2) then | ||
|  |       Complex.uminus (arr (threen2 - 1 - i)) | ||
|  |     else | ||
|  |       Complex.uminus (arr (i - threen2)) | ||
|  |   in | ||
|  |   let arr2w = fun i -> Complex.times (window n i) (arr2 i) in | ||
|  |   let twon = 2 * n in | ||
|  |   store_array_r twon (locative_array_c twon rarr iarr locations "BUG") arr2w | ||
|  | 
 | ||
|  | let window_param = function | ||
|  |     MDCT_WINDOW -> true | ||
|  |   | MDCT_WINDOW_SYM -> true | ||
|  |   | IMDCT_WINDOW -> true | ||
|  |   | IMDCT_WINDOW_SYM -> true | ||
|  |   | _ -> false | ||
|  | 
 | ||
|  | let generate n mode = | ||
|  |   let iarray = "I" | ||
|  |   and oarray = "O" | ||
|  |   and istride = "istride" | ||
|  |   and ostride = "ostride"  | ||
|  |   and window = "W"  | ||
|  |   and name = !Magic.codelet_name in | ||
|  | 
 | ||
|  |   let vistride = either_stride (!uistride) (C.SVar istride) | ||
|  |   and vostride = either_stride (!uostride) (C.SVar ostride) | ||
|  |   in | ||
|  | 
 | ||
|  |   let sivs = stride_to_string "ovs" !uovstride in | ||
|  |   let sovs = stride_to_string "ivs" !uivstride in | ||
|  | 
 | ||
|  |   let (transform, load_input, store_output) = match mode with | ||
|  |   | MDCT -> Trig.dctIV, load_array_mdct unity_window, | ||
|  |       store_array_mdct unity_window | ||
|  |   | MDCT_MP3 -> Trig.dctIV, load_array_mdct mp3_window, | ||
|  |       store_array_mdct unity_window | ||
|  |   | MDCT_WINDOW -> Trig.dctIV, load_array_mdct | ||
|  | 	(load_window (window_array (2 * n) window)), | ||
|  |       store_array_mdct unity_window | ||
|  |   | MDCT_WINDOW_SYM -> Trig.dctIV, load_array_mdct | ||
|  | 	(load_window_sym (window_array n window)), | ||
|  |       store_array_mdct unity_window | ||
|  |   | IMDCT -> Trig.dctIV, load_array_imdct unity_window, | ||
|  |       store_array_imdct unity_window | ||
|  |   | IMDCT_MP3 -> Trig.dctIV, load_array_imdct unity_window, | ||
|  |       store_array_imdct mp3_window | ||
|  |   | IMDCT_WINDOW -> Trig.dctIV, load_array_imdct unity_window, | ||
|  |       store_array_imdct (load_window (window_array (2 * n) window)) | ||
|  |   | IMDCT_WINDOW_SYM -> Trig.dctIV, load_array_imdct unity_window, | ||
|  |       store_array_imdct (load_window_sym (window_array n window)) | ||
|  |   | _ -> failwith "must specify transform kind" | ||
|  |   in | ||
|  |      | ||
|  |   let locations = unique_array_c (2*n) in | ||
|  |   let input =  | ||
|  |     load_input n | ||
|  |       (C.array_subscript iarray vistride) | ||
|  |       (C.array_subscript "BUG" vistride) | ||
|  |       locations | ||
|  |   in | ||
|  |   let output = (Complex.times (Complex.inverse_int !normalization))  | ||
|  |     @@ (transform n input) in | ||
|  |   let odag = | ||
|  |     store_output n | ||
|  |       (C.array_subscript oarray vostride) | ||
|  |       (C.array_subscript "BUG" vostride) | ||
|  |       locations  | ||
|  |       output | ||
|  |   in | ||
|  |   let annot = standard_optimizer odag in | ||
|  | 
 | ||
|  |   let tree = | ||
|  |     Fcn ("void", name, | ||
|  | 	 ([Decl (C.constrealtypep, iarray); | ||
|  | 	   Decl (C.realtypep, oarray)] | ||
|  | 	  @ (if stride_fixed !uistride then []  | ||
|  |                else [Decl (C.stridetype, istride)]) | ||
|  | 	  @ (if stride_fixed !uostride then []  | ||
|  | 	       else [Decl (C.stridetype, ostride)]) | ||
|  | 	  @ (choose_simd [] | ||
|  | 	       (if stride_fixed !uivstride then [] else  | ||
|  | 	       [Decl ("int", sivs)])) | ||
|  | 	  @ (choose_simd [] | ||
|  | 	       (if stride_fixed !uovstride then [] else  | ||
|  | 	       [Decl ("int", sovs)])) | ||
|  | 	  @ (if (not (window_param mode)) then []  | ||
|  | 	       else [Decl (C.constrealtypep, window)]) | ||
|  | 	 ), | ||
|  | 	 finalize_fcn (Asch annot)) | ||
|  | 
 | ||
|  |   in | ||
|  |   (unparse tree) ^ "\n" | ||
|  | 
 | ||
|  | 
 | ||
|  | let main () = | ||
|  |   begin | ||
|  |     parse speclist usage; | ||
|  |     print_string (generate (check_size ()) !mode); | ||
|  |   end | ||
|  | 
 | ||
|  | let _ = main() |