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