Chris@42: (* Chris@42: * Copyright (c) 1997-1999 Massachusetts Institute of Technology Chris@42: * Copyright (c) 2003, 2007-14 Matteo Frigo Chris@42: * Copyright (c) 2003, 2007-14 Massachusetts Institute of Technology Chris@42: * Chris@42: * This program is free software; you can redistribute it and/or modify Chris@42: * it under the terms of the GNU General Public License as published by Chris@42: * the Free Software Foundation; either version 2 of the License, or Chris@42: * (at your option) any later version. Chris@42: * Chris@42: * This program is distributed in the hope that it will be useful, Chris@42: * but WITHOUT ANY WARRANTY; without even the implied warranty of Chris@42: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Chris@42: * GNU General Public License for more details. Chris@42: * Chris@42: * You should have received a copy of the GNU General Public License Chris@42: * along with this program; if not, write to the Free Software Chris@42: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Chris@42: * Chris@42: *) Chris@42: Chris@42: (* generation of trigonometric transforms *) Chris@42: Chris@42: open Util Chris@42: open Genutil Chris@42: open C Chris@42: Chris@42: Chris@42: let usage = "Usage: " ^ Sys.argv.(0) ^ " -n " Chris@42: Chris@42: let uistride = ref Stride_variable Chris@42: let uostride = ref Stride_variable Chris@42: let uivstride = ref Stride_variable Chris@42: let uovstride = ref Stride_variable Chris@42: let normalization = ref 1 Chris@42: Chris@42: type mode = Chris@42: | MDCT Chris@42: | MDCT_MP3 Chris@42: | MDCT_VORBIS Chris@42: | MDCT_WINDOW Chris@42: | MDCT_WINDOW_SYM Chris@42: | IMDCT Chris@42: | IMDCT_MP3 Chris@42: | IMDCT_VORBIS Chris@42: | IMDCT_WINDOW Chris@42: | IMDCT_WINDOW_SYM Chris@42: | NONE Chris@42: Chris@42: let mode = ref NONE Chris@42: Chris@42: let speclist = [ Chris@42: "-with-istride", Chris@42: Arg.String(fun x -> uistride := arg_to_stride x), Chris@42: " specialize for given input stride"; Chris@42: Chris@42: "-with-ostride", Chris@42: Arg.String(fun x -> uostride := arg_to_stride x), Chris@42: " specialize for given output stride"; Chris@42: Chris@42: "-with-ivstride", Chris@42: Arg.String(fun x -> uivstride := arg_to_stride x), Chris@42: " specialize for given input vector stride"; Chris@42: Chris@42: "-with-ovstride", Chris@42: Arg.String(fun x -> uovstride := arg_to_stride x), Chris@42: " specialize for given output vector stride"; Chris@42: Chris@42: "-normalization", Chris@42: Arg.String(fun x -> normalization := int_of_string x), Chris@42: " normalization integer to divide by"; Chris@42: Chris@42: "-mdct", Chris@42: Arg.Unit(fun () -> mode := MDCT), Chris@42: " generate an MDCT codelet"; Chris@42: Chris@42: "-mdct-mp3", Chris@42: Arg.Unit(fun () -> mode := MDCT_MP3), Chris@42: " generate an MDCT codelet with MP3 windowing"; Chris@42: Chris@42: "-mdct-window", Chris@42: Arg.Unit(fun () -> mode := MDCT_WINDOW), Chris@42: " generate an MDCT codelet with window array"; Chris@42: Chris@42: "-mdct-window-sym", Chris@42: Arg.Unit(fun () -> mode := MDCT_WINDOW_SYM), Chris@42: " generate an MDCT codelet with symmetric window array"; Chris@42: Chris@42: "-imdct", Chris@42: Arg.Unit(fun () -> mode := IMDCT), Chris@42: " generate an IMDCT codelet"; Chris@42: Chris@42: "-imdct-mp3", Chris@42: Arg.Unit(fun () -> mode := IMDCT_MP3), Chris@42: " generate an IMDCT codelet with MP3 windowing"; Chris@42: Chris@42: "-imdct-window", Chris@42: Arg.Unit(fun () -> mode := IMDCT_WINDOW), Chris@42: " generate an IMDCT codelet with window array"; Chris@42: Chris@42: "-imdct-window-sym", Chris@42: Arg.Unit(fun () -> mode := IMDCT_WINDOW_SYM), Chris@42: " generate an IMDCT codelet with symmetric window array"; Chris@42: ] Chris@42: Chris@42: let unity_window n i = Complex.one Chris@42: Chris@42: (* MP3 window(k) = sin(pi/(2n) * (k + 1/2)) *) Chris@42: let mp3_window n k = Chris@42: Complex.imag (Complex.exp (8 * n) (2*k + 1)) Chris@42: Chris@42: (* Vorbis window(k) = sin(pi/2 * (mp3_window(k))^2) Chris@42: ... this is transcendental, though, so we can't do it with our Chris@42: current Complex.exp function *) Chris@42: Chris@42: let window_array n w = Chris@42: array n (fun i -> Chris@42: let stride = C.SInteger 1 Chris@42: and klass = Unique.make () in Chris@42: let refr = C.array_subscript w stride i in Chris@42: let kr = Variable.make_constant klass refr in Chris@42: load_r (kr, kr)) Chris@42: Chris@42: let load_window w n i = w i Chris@42: let load_window_sym w n i = w (if (i < n) then i else (2*n - 1 - i)) Chris@42: Chris@42: (* fixme: use same locations for input and output so that it works in-place? *) Chris@42: Chris@42: (* Note: only correct for even n! *) Chris@42: let load_array_mdct window n rarr iarr locations = Chris@42: let twon = 2 * n in Chris@42: let arr = load_array_c twon Chris@42: (locative_array_c twon rarr iarr locations "BUG") in Chris@42: let arrw = fun i -> Complex.times (window n i) (arr i) in Chris@42: array n Chris@42: ((Complex.times Complex.half) @@ Chris@42: (fun i -> Chris@42: if (i < n/2) then Chris@42: Complex.uminus (Complex.plus [arrw (i + n + n/2); Chris@42: arrw (n + n/2 - 1 - i)]) Chris@42: else Chris@42: Complex.plus [arrw (i - n/2); Chris@42: Complex.uminus (arrw (n + n/2 - 1 - i))])) Chris@42: Chris@42: let store_array_mdct window n rarr iarr locations arr = Chris@42: store_array_r n (locative_array_c n rarr iarr locations "BUG") arr Chris@42: Chris@42: let load_array_imdct window n rarr iarr locations = Chris@42: load_array_c n (locative_array_c n rarr iarr locations "BUG") Chris@42: Chris@42: let store_array_imdct window n rarr iarr locations arr = Chris@42: let n2 = n/2 in Chris@42: let threen2 = 3*n2 in Chris@42: let arr2 = fun i -> Chris@42: if (i < n2) then Chris@42: arr (i + n2) Chris@42: else if (i < threen2) then Chris@42: Complex.uminus (arr (threen2 - 1 - i)) Chris@42: else Chris@42: Complex.uminus (arr (i - threen2)) Chris@42: in Chris@42: let arr2w = fun i -> Complex.times (window n i) (arr2 i) in Chris@42: let twon = 2 * n in Chris@42: store_array_r twon (locative_array_c twon rarr iarr locations "BUG") arr2w Chris@42: Chris@42: let window_param = function Chris@42: MDCT_WINDOW -> true Chris@42: | MDCT_WINDOW_SYM -> true Chris@42: | IMDCT_WINDOW -> true Chris@42: | IMDCT_WINDOW_SYM -> true Chris@42: | _ -> false Chris@42: Chris@42: let generate n mode = Chris@42: let iarray = "I" Chris@42: and oarray = "O" Chris@42: and istride = "istride" Chris@42: and ostride = "ostride" Chris@42: and window = "W" Chris@42: and name = !Magic.codelet_name in Chris@42: Chris@42: let vistride = either_stride (!uistride) (C.SVar istride) Chris@42: and vostride = either_stride (!uostride) (C.SVar ostride) Chris@42: in Chris@42: Chris@42: let sivs = stride_to_string "ovs" !uovstride in Chris@42: let sovs = stride_to_string "ivs" !uivstride in Chris@42: Chris@42: let (transform, load_input, store_output) = match mode with Chris@42: | MDCT -> Trig.dctIV, load_array_mdct unity_window, Chris@42: store_array_mdct unity_window Chris@42: | MDCT_MP3 -> Trig.dctIV, load_array_mdct mp3_window, Chris@42: store_array_mdct unity_window Chris@42: | MDCT_WINDOW -> Trig.dctIV, load_array_mdct Chris@42: (load_window (window_array (2 * n) window)), Chris@42: store_array_mdct unity_window Chris@42: | MDCT_WINDOW_SYM -> Trig.dctIV, load_array_mdct Chris@42: (load_window_sym (window_array n window)), Chris@42: store_array_mdct unity_window Chris@42: | IMDCT -> Trig.dctIV, load_array_imdct unity_window, Chris@42: store_array_imdct unity_window Chris@42: | IMDCT_MP3 -> Trig.dctIV, load_array_imdct unity_window, Chris@42: store_array_imdct mp3_window Chris@42: | IMDCT_WINDOW -> Trig.dctIV, load_array_imdct unity_window, Chris@42: store_array_imdct (load_window (window_array (2 * n) window)) Chris@42: | IMDCT_WINDOW_SYM -> Trig.dctIV, load_array_imdct unity_window, Chris@42: store_array_imdct (load_window_sym (window_array n window)) Chris@42: | _ -> failwith "must specify transform kind" Chris@42: in Chris@42: Chris@42: let locations = unique_array_c (2*n) in Chris@42: let input = Chris@42: load_input n Chris@42: (C.array_subscript iarray vistride) Chris@42: (C.array_subscript "BUG" vistride) Chris@42: locations Chris@42: in Chris@42: let output = (Complex.times (Complex.inverse_int !normalization)) Chris@42: @@ (transform n input) in Chris@42: let odag = Chris@42: store_output n Chris@42: (C.array_subscript oarray vostride) Chris@42: (C.array_subscript "BUG" vostride) Chris@42: locations Chris@42: output Chris@42: in Chris@42: let annot = standard_optimizer odag in Chris@42: Chris@42: let tree = Chris@42: Fcn ("void", name, Chris@42: ([Decl (C.constrealtypep, iarray); Chris@42: Decl (C.realtypep, oarray)] Chris@42: @ (if stride_fixed !uistride then [] Chris@42: else [Decl (C.stridetype, istride)]) Chris@42: @ (if stride_fixed !uostride then [] Chris@42: else [Decl (C.stridetype, ostride)]) Chris@42: @ (choose_simd [] Chris@42: (if stride_fixed !uivstride then [] else Chris@42: [Decl ("int", sivs)])) Chris@42: @ (choose_simd [] Chris@42: (if stride_fixed !uovstride then [] else Chris@42: [Decl ("int", sovs)])) Chris@42: @ (if (not (window_param mode)) then [] Chris@42: else [Decl (C.constrealtypep, window)]) Chris@42: ), Chris@42: finalize_fcn (Asch annot)) Chris@42: Chris@42: in Chris@42: (unparse tree) ^ "\n" Chris@42: Chris@42: Chris@42: let main () = Chris@42: begin Chris@42: parse speclist usage; Chris@42: print_string (generate (check_size ()) !mode); Chris@42: end Chris@42: Chris@42: let _ = main()