forked from FFTW/fftw3
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathvScheduler.ml
166 lines (138 loc) · 5.32 KB
/
vScheduler.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
(*
* Copyright (c) 1997-1999 Massachusetts Institute of Technology
* Copyright (c) 2000-2001 Stefan Kral
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. *)
(* In the standard distribution of FFTW 2.1.3 there is a module called
'Schedule'. This module ('Vschedule') only slightly differs from
Schedule. It has been adapted to deal with structures defined in
module VSimdBasics. *)
open VDag
open VSimdBasics
(*************************************************
* Dag scheduler
*************************************************)
let to_assignment node = node.instruction
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 node_is_reachable node = (node.label < infinity)
let node_has_no_predecessors node = (Util.null node.predecessors)
let node_has_no_successors node = (Util.null node.successors)
let cc dag inputs =
begin
assert (inputs <> []);
VDag.for_all dag (fun node -> node.label <- infinity);
bfs dag (List.hd inputs) 0;
let (reachable,unreachable) =
List.partition node_is_reachable (VDag.to_list dag)
in (List.map to_assignment reachable, List.map to_assignment unreachable)
end
let rec connected_components alist =
let dag = makedag alist in
let inputs = List.filter node_has_no_predecessors (VDag.to_list dag) in
match cc dag inputs with
| a, [] -> [a]
| a, b -> a :: connected_components b
let loads_twiddle node =
node.predecessors = [] &&
(match VSimdInstrOperandSet.elements node.input_variables with
| [x] -> vsimdinstroperand_is_twiddle x
| _ -> false)
let partition alist =
let dag = makedag alist in
let dag' = VDag.to_list dag in
let inputs = List.filter node_has_no_predecessors dag'
and outputs = List.filter node_has_no_successors dag'
and special_inputs = List.filter loads_twiddle dag' in
begin
VDag.for_all dag (fun node -> node.color <- BLACK);
List.iter (set_color RED) inputs;
(* The special inputs are input that read a twiddle factor. They
can end up either in the blue or in the red part. If a red
node needs a special input, the special input becomes red. If
all successors of a special input are blue, it becomes blue.
Outputs are always blue.
As a consequence, however, the final partition might be
composed only of blue nodes (which is incorrect). In this case
we manually reset all inputs (whether special or not) to be red. *)
List.iter (set_color YELLOW) special_inputs;
List.iter (set_color BLUE) outputs;
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
List.iter (fun node ->
begin
set_color RED node;
List.iter (set_color RED) node.predecessors;
end) i;
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
List.iter (set_color BLUE) o;
loopi false;
end
(* among the magic parameters, this is the most obscure *)
in if !Magic.loopo then
loopo false
else
loopi false;
(* fix the partition if it is incorrect *)
if not (List.exists (has_color RED) dag') then
List.iter (set_color RED) inputs;
return
((List.map to_assignment (List.filter (has_color RED) dag')),
(List.map to_assignment (List.filter (has_color BLUE) dag')))
end
type vschedule =
| VDone
| VInstr of vsimdinstr
| VSeq of vschedule * vschedule
| VPar of vschedule list
let schedule =
let rec schedule_alist = function
| [] -> VDone
| [a] -> VInstr a
| alist ->
match connected_components alist with
| [a] -> schedule_connected a
| l -> VPar (List.map schedule_alist l)
and schedule_connected alist =
let (a,b) = partition alist in VSeq(schedule_alist a,schedule_alist b)
in schedule_alist