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