annotate src/fftw-3.3.3/genfft/schedule.ml @ 83:ae30d91d2ffe

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