Chris@10
|
1 (*
|
Chris@10
|
2 * Copyright (c) 1997-1999 Massachusetts Institute of Technology
|
Chris@10
|
3 * Copyright (c) 2003, 2007-11 Matteo Frigo
|
Chris@10
|
4 * Copyright (c) 2003, 2007-11 Massachusetts Institute of Technology
|
Chris@10
|
5 *
|
Chris@10
|
6 * This program is free software; you can redistribute it and/or modify
|
Chris@10
|
7 * it under the terms of the GNU General Public License as published by
|
Chris@10
|
8 * the Free Software Foundation; either version 2 of the License, or
|
Chris@10
|
9 * (at your option) any later version.
|
Chris@10
|
10 *
|
Chris@10
|
11 * This program is distributed in the hope that it will be useful,
|
Chris@10
|
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
Chris@10
|
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
Chris@10
|
14 * GNU General Public License for more details.
|
Chris@10
|
15 *
|
Chris@10
|
16 * You should have received a copy of the GNU General Public License
|
Chris@10
|
17 * along with this program; if not, write to the Free Software
|
Chris@10
|
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
Chris@10
|
19 *
|
Chris@10
|
20 *)
|
Chris@10
|
21
|
Chris@10
|
22 (* policies for loading/computing twiddle factors *)
|
Chris@10
|
23 open Complex
|
Chris@10
|
24 open Util
|
Chris@10
|
25
|
Chris@10
|
26 type twop = TW_FULL | TW_CEXP | TW_NEXT
|
Chris@10
|
27
|
Chris@10
|
28 let optostring = function
|
Chris@10
|
29 | TW_CEXP -> "TW_CEXP"
|
Chris@10
|
30 | TW_NEXT -> "TW_NEXT"
|
Chris@10
|
31 | TW_FULL -> "TW_FULL"
|
Chris@10
|
32
|
Chris@10
|
33 type twinstr = (twop * int * int)
|
Chris@10
|
34
|
Chris@10
|
35 let rec unroll_twfull l = match l with
|
Chris@10
|
36 | [] -> []
|
Chris@10
|
37 | (TW_FULL, v, n) :: b ->
|
Chris@10
|
38 (forall [] cons 1 n (fun i -> (TW_CEXP, v, i)))
|
Chris@10
|
39 @ unroll_twfull b
|
Chris@10
|
40 | a :: b -> a :: unroll_twfull b
|
Chris@10
|
41
|
Chris@10
|
42 let twinstr_to_c_string l =
|
Chris@10
|
43 let one (op, a, b) = Printf.sprintf "{ %s, %d, %d }" (optostring op) a b
|
Chris@10
|
44 in let rec loop first = function
|
Chris@10
|
45 | [] -> ""
|
Chris@10
|
46 | a :: b -> (if first then "\n" else ",\n") ^ (one a) ^ (loop false b)
|
Chris@10
|
47 in "{" ^ (loop true l) ^ "}"
|
Chris@10
|
48
|
Chris@10
|
49 let twinstr_to_simd_string vl l =
|
Chris@10
|
50 let one sep = function
|
Chris@10
|
51 | (TW_NEXT, 1, 0) -> sep ^ "{TW_NEXT, " ^ vl ^ ", 0}"
|
Chris@10
|
52 | (TW_NEXT, _, _) -> failwith "twinstr_to_simd_string"
|
Chris@10
|
53 | (TW_CEXP, v, b) -> sep ^ (Printf.sprintf "VTW(%d,%d)" v b)
|
Chris@10
|
54 | _ -> failwith "twinstr_to_simd_string"
|
Chris@10
|
55 in let rec loop first = function
|
Chris@10
|
56 | [] -> ""
|
Chris@10
|
57 | a :: b -> (one (if first then "\n" else ",\n") a) ^ (loop false b)
|
Chris@10
|
58 in "{" ^ (loop true (unroll_twfull l)) ^ "}"
|
Chris@10
|
59
|
Chris@10
|
60 let rec pow m n =
|
Chris@10
|
61 if (n = 0) then 1
|
Chris@10
|
62 else m * pow m (n - 1)
|
Chris@10
|
63
|
Chris@10
|
64 let rec is_pow m n =
|
Chris@10
|
65 n = 1 || ((n mod m) = 0 && is_pow m (n / m))
|
Chris@10
|
66
|
Chris@10
|
67 let rec log m n = if n = 1 then 0 else 1 + log m (n / m)
|
Chris@10
|
68
|
Chris@10
|
69 let rec largest_power_smaller_than m i =
|
Chris@10
|
70 if (is_pow m i) then i
|
Chris@10
|
71 else largest_power_smaller_than m (i - 1)
|
Chris@10
|
72
|
Chris@10
|
73 let rec smallest_power_larger_than m i =
|
Chris@10
|
74 if (is_pow m i) then i
|
Chris@10
|
75 else smallest_power_larger_than m (i + 1)
|
Chris@10
|
76
|
Chris@10
|
77 let rec_array n f =
|
Chris@10
|
78 let g = ref (fun i -> Complex.zero) in
|
Chris@10
|
79 let a = Array.init n (fun i -> lazy (!g i)) in
|
Chris@10
|
80 let h i = f (fun i -> Lazy.force a.(i)) i in
|
Chris@10
|
81 begin
|
Chris@10
|
82 g := h;
|
Chris@10
|
83 h
|
Chris@10
|
84 end
|
Chris@10
|
85
|
Chris@10
|
86
|
Chris@10
|
87 let ctimes use_complex_arith a b =
|
Chris@10
|
88 if use_complex_arith then
|
Chris@10
|
89 Complex.ctimes a b
|
Chris@10
|
90 else
|
Chris@10
|
91 Complex.times a b
|
Chris@10
|
92
|
Chris@10
|
93 let ctimesj use_complex_arith a b =
|
Chris@10
|
94 if use_complex_arith then
|
Chris@10
|
95 Complex.ctimesj a b
|
Chris@10
|
96 else
|
Chris@10
|
97 Complex.times (Complex.conj a) b
|
Chris@10
|
98
|
Chris@10
|
99 let make_bytwiddle sign use_complex_arith g f i =
|
Chris@10
|
100 if i = 0 then
|
Chris@10
|
101 f i
|
Chris@10
|
102 else if sign = 1 then
|
Chris@10
|
103 ctimes use_complex_arith (g i) (f i)
|
Chris@10
|
104 else
|
Chris@10
|
105 ctimesj use_complex_arith (g i) (f i)
|
Chris@10
|
106
|
Chris@10
|
107 (* various policies for computing/loading twiddle factors *)
|
Chris@10
|
108
|
Chris@10
|
109 let twiddle_policy_load_all v use_complex_arith =
|
Chris@10
|
110 let bytwiddle n sign w f =
|
Chris@10
|
111 make_bytwiddle sign use_complex_arith (fun i -> w (i - 1)) f
|
Chris@10
|
112 and twidlen n = 2 * (n - 1)
|
Chris@10
|
113 and twdesc r = [(TW_FULL, v, r);(TW_NEXT, 1, 0)]
|
Chris@10
|
114 in bytwiddle, twidlen, twdesc
|
Chris@10
|
115
|
Chris@10
|
116 (*
|
Chris@10
|
117 * if i is a power of two, then load w (log i)
|
Chris@10
|
118 * else let x = largest power of 2 less than i in
|
Chris@10
|
119 * let y = i - x in
|
Chris@10
|
120 * compute w^{x+y} = w^x * w^y
|
Chris@10
|
121 *)
|
Chris@10
|
122 let twiddle_policy_log2 v use_complex_arith =
|
Chris@10
|
123 let bytwiddle n sign w f =
|
Chris@10
|
124 let g = rec_array n (fun self i ->
|
Chris@10
|
125 if i = 0 then Complex.one
|
Chris@10
|
126 else if is_pow 2 i then w (log 2 i)
|
Chris@10
|
127 else let x = largest_power_smaller_than 2 i in
|
Chris@10
|
128 let y = i - x in
|
Chris@10
|
129 ctimes use_complex_arith (self x) (self y))
|
Chris@10
|
130 in make_bytwiddle sign use_complex_arith g f
|
Chris@10
|
131 and twidlen n = 2 * (log 2 (largest_power_smaller_than 2 (2 * n - 1)))
|
Chris@10
|
132 and twdesc n =
|
Chris@10
|
133 (List.flatten
|
Chris@10
|
134 (List.map
|
Chris@10
|
135 (fun i ->
|
Chris@10
|
136 if i > 0 && is_pow 2 i then
|
Chris@10
|
137 [TW_CEXP, v, i]
|
Chris@10
|
138 else
|
Chris@10
|
139 [])
|
Chris@10
|
140 (iota n)))
|
Chris@10
|
141 @ [(TW_NEXT, 1, 0)]
|
Chris@10
|
142 in bytwiddle, twidlen, twdesc
|
Chris@10
|
143
|
Chris@10
|
144 let twiddle_policy_log3 v use_complex_arith =
|
Chris@10
|
145 let rec terms_needed i pi s n =
|
Chris@10
|
146 if (s >= n - 1) then i
|
Chris@10
|
147 else terms_needed (i + 1) (3 * pi) (s + pi) n
|
Chris@10
|
148 in
|
Chris@10
|
149 let rec bytwiddle n sign w f =
|
Chris@10
|
150 let nterms = terms_needed 0 1 0 n in
|
Chris@10
|
151 let maxterm = pow 3 (nterms - 1) in
|
Chris@10
|
152 let g = rec_array (3 * n) (fun self i ->
|
Chris@10
|
153 if i = 0 then Complex.one
|
Chris@10
|
154 else if is_pow 3 i then w (log 3 i)
|
Chris@10
|
155 else if i = (n - 1) && maxterm >= n then
|
Chris@10
|
156 w (nterms - 1)
|
Chris@10
|
157 else let x = smallest_power_larger_than 3 i in
|
Chris@10
|
158 if (i + i >= x) then
|
Chris@10
|
159 let x = min x (n - 1) in
|
Chris@10
|
160 ctimesj use_complex_arith (self (x - i)) (self x)
|
Chris@10
|
161 else let x = largest_power_smaller_than 3 i in
|
Chris@10
|
162 ctimes use_complex_arith (self (i - x)) (self x))
|
Chris@10
|
163 in make_bytwiddle sign use_complex_arith g f
|
Chris@10
|
164 and twidlen n = 2 * (terms_needed 0 1 0 n)
|
Chris@10
|
165 and twdesc n =
|
Chris@10
|
166 (List.map
|
Chris@10
|
167 (fun i ->
|
Chris@10
|
168 let x = min (pow 3 i) (n - 1) in
|
Chris@10
|
169 TW_CEXP, v, x)
|
Chris@10
|
170 (iota ((twidlen n) / 2)))
|
Chris@10
|
171 @ [(TW_NEXT, 1, 0)]
|
Chris@10
|
172 in bytwiddle, twidlen, twdesc
|
Chris@10
|
173
|
Chris@10
|
174 let current_twiddle_policy = ref twiddle_policy_load_all
|
Chris@10
|
175
|
Chris@10
|
176 let twiddle_policy use_complex_arith =
|
Chris@10
|
177 !current_twiddle_policy use_complex_arith
|
Chris@10
|
178
|
Chris@10
|
179 let set_policy x = Arg.Unit (fun () -> current_twiddle_policy := x)
|
Chris@10
|
180 let set_policy_int x = Arg.Int (fun i -> current_twiddle_policy := x i)
|
Chris@10
|
181
|
Chris@10
|
182 let undocumented = " Undocumented twiddle policy"
|
Chris@10
|
183
|
Chris@10
|
184 let speclist = [
|
Chris@10
|
185 "-twiddle-load-all", set_policy twiddle_policy_load_all, undocumented;
|
Chris@10
|
186 "-twiddle-log2", set_policy twiddle_policy_log2, undocumented;
|
Chris@10
|
187 "-twiddle-log3", set_policy twiddle_policy_log3, undocumented;
|
Chris@10
|
188 ]
|