comparison src/fftw-3.3.8/genfft/schedule.ml @ 167:bd3cc4d1df30

Add FFTW 3.3.8 source, and a Linux build
author Chris Cannam <cannam@all-day-breakfast.com>
date Tue, 19 Nov 2019 14:52:55 +0000
parents
children
comparison
equal deleted inserted replaced
166:cbd6d7e562c7 167:bd3cc4d1df30
1 (*
2 * Copyright (c) 1997-1999 Massachusetts Institute of Technology
3 * Copyright (c) 2003, 2007-14 Matteo Frigo
4 * Copyright (c) 2003, 2007-14 Massachusetts Institute of Technology
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 *
20 *)
21
22 (* This file contains the instruction scheduler, which finds an
23 efficient ordering for a given list of instructions.
24
25 The scheduler analyzes the DAG (directed acyclic graph) formed by
26 the instruction dependencies, and recursively partitions it. The
27 resulting schedule data structure expresses a "good" ordering
28 and structure for the computation.
29
30 The scheduler makes use of utilties in Dag and other packages to
31 manipulate the Dag and the instruction list. *)
32
33 open Dag
34 (*************************************************
35 * Dag scheduler
36 *************************************************)
37 let to_assignment node = (Expr.Assign (node.assigned, node.expression))
38 let makedag l = Dag.makedag
39 (List.map (function Expr.Assign (v, x) -> (v, x)) l)
40
41 let return x = x
42 let has_color c n = (n.color = c)
43 let set_color c n = (n.color <- c)
44 let has_either_color c1 c2 n = (n.color = c1 || n.color = c2)
45
46 let infinity = 100000
47
48 let cc dag inputs =
49 begin
50 Dag.for_all dag (fun node ->
51 node.label <- infinity);
52
53 (match inputs with
54 a :: _ -> bfs dag a 0
55 | _ -> failwith "connected");
56
57 return
58 ((List.map to_assignment (List.filter (fun n -> n.label < infinity)
59 (Dag.to_list dag))),
60 (List.map to_assignment (List.filter (fun n -> n.label == infinity)
61 (Dag.to_list dag))))
62 end
63
64 let rec connected_components alist =
65 let dag = makedag alist in
66 let inputs =
67 List.filter (fun node -> Util.null node.predecessors)
68 (Dag.to_list dag) in
69 match cc dag inputs with
70 (a, []) -> [a]
71 | (a, b) -> a :: connected_components b
72
73 let single_load node =
74 match (node.input_variables, node.predecessors) with
75 ([x], []) ->
76 Variable.is_constant x ||
77 (!Magic.locations_are_special && Variable.is_locative x)
78 | _ -> false
79
80 let loads_locative node =
81 match (node.input_variables, node.predecessors) with
82 | ([x], []) -> Variable.is_locative x
83 | _ -> false
84
85 let partition alist =
86 let dag = makedag alist in
87 let dag' = Dag.to_list dag in
88 let inputs =
89 List.filter (fun node -> Util.null node.predecessors) dag'
90 and outputs =
91 List.filter (fun node -> Util.null node.successors) dag'
92 and special_inputs = List.filter single_load dag' in
93 begin
94
95 let c = match !Magic.schedule_type with
96 | 1 -> RED; (* all nodes in the input partition *)
97 | -1 -> BLUE; (* all nodes in the output partition *)
98 | _ -> BLACK; (* node color determined by bisection algorithm *)
99 in Dag.for_all dag (fun node -> node.color <- c);
100
101 Util.for_list inputs (set_color RED);
102
103 (*
104 The special inputs are those input nodes that load a single
105 location or twiddle factor. Special inputs can end up either
106 in the blue or in the red part. These inputs are special
107 because they inherit a color from their neighbors: If a red
108 node needs a special input, the special input becomes red, but
109 if all successors of a special input are blue, the special
110 input becomes blue. Outputs are always blue, whether they be
111 special or not.
112
113 Because of the processing of special inputs, however, the final
114 partition might end up being composed only of blue nodes (which
115 is incorrect). In this case we manually reset all inputs
116 (whether special or not) to be red.
117 *)
118
119 Util.for_list special_inputs (set_color YELLOW);
120
121 Util.for_list outputs (set_color BLUE);
122
123 let rec loopi donep =
124 match (List.filter
125 (fun node -> (has_color BLACK node) &&
126 List.for_all (has_either_color RED YELLOW) node.predecessors)
127 dag') with
128 [] -> if (donep) then () else loopo true
129 | i ->
130 begin
131 Util.for_list i (fun node ->
132 begin
133 set_color RED node;
134 Util.for_list node.predecessors (set_color RED);
135 end);
136 loopo false;
137 end
138
139 and loopo donep =
140 match (List.filter
141 (fun node -> (has_either_color BLACK YELLOW node) &&
142 List.for_all (has_color BLUE) node.successors)
143 dag') with
144 [] -> if (donep) then () else loopi true
145 | o ->
146 begin
147 Util.for_list o (set_color BLUE);
148 loopi false;
149 end
150
151 in loopi false;
152
153 (* fix the partition if it is incorrect *)
154 if not (List.exists (has_color RED) dag') then
155 Util.for_list inputs (set_color RED);
156
157 return
158 ((List.map to_assignment (List.filter (has_color RED) dag')),
159 (List.map to_assignment (List.filter (has_color BLUE) dag')))
160 end
161
162 type schedule =
163 Done
164 | Instr of Expr.assignment
165 | Seq of (schedule * schedule)
166 | Par of schedule list
167
168
169
170 (* produce a sequential schedule determined by the user *)
171 let rec sequentially = function
172 [] -> Done
173 | a :: b -> Seq (Instr a, sequentially b)
174
175 let schedule =
176 let rec schedule_alist = function
177 | [] -> Done
178 | [a] -> Instr a
179 | alist -> match connected_components alist with
180 | ([a]) -> schedule_connected a
181 | l -> Par (List.map schedule_alist l)
182
183 and schedule_connected alist =
184 match partition alist with
185 | (a, b) -> Seq (schedule_alist a, schedule_alist b)
186
187 in fun x ->
188 let () = Util.info "begin schedule" in
189 let res = schedule_alist x in
190 let () = Util.info "end schedule" in
191 res
192
193
194 (* partition a dag into two parts:
195
196 1) the set of loads from locatives and their successors,
197 2) all other nodes
198
199 This step separates the ``body'' of the dag, which computes the
200 actual fft, from the ``precomputations'' part, which computes e.g.
201 twiddle factors.
202 *)
203 let partition_precomputations alist =
204 let dag = makedag alist in
205 let dag' = Dag.to_list dag in
206 let loads = List.filter loads_locative dag' in
207 begin
208
209 Dag.for_all dag (set_color BLUE);
210 Util.for_list loads (set_color RED);
211
212 let rec loop () =
213 match (List.filter
214 (fun node -> (has_color RED node) &&
215 List.exists (has_color BLUE) node.successors)
216 dag') with
217 [] -> ()
218 | i ->
219 begin
220 Util.for_list i
221 (fun node ->
222 Util.for_list node.successors (set_color RED));
223 loop ()
224 end
225
226 in loop ();
227
228 return
229 ((List.map to_assignment (List.filter (has_color BLUE) dag')),
230 (List.map to_assignment (List.filter (has_color RED) dag')))
231 end
232
233 let isolate_precomputations_and_schedule alist =
234 let (a, b) = partition_precomputations alist in
235 Seq (schedule a, schedule b)
236