annotate src/fftw-3.3.3/genfft/annotate.ml @ 169:223a55898ab9 tip default

Add null config files
author Chris Cannam <cannam@all-day-breakfast.com>
date Mon, 02 Mar 2020 14:03:47 +0000
parents 89f5e221ed7b
children
rev   line source
cannam@95 1 (*
cannam@95 2 * Copyright (c) 1997-1999 Massachusetts Institute of Technology
cannam@95 3 * Copyright (c) 2003, 2007-11 Matteo Frigo
cannam@95 4 * Copyright (c) 2003, 2007-11 Massachusetts Institute of Technology
cannam@95 5 *
cannam@95 6 * This program is free software; you can redistribute it and/or modify
cannam@95 7 * it under the terms of the GNU General Public License as published by
cannam@95 8 * the Free Software Foundation; either version 2 of the License, or
cannam@95 9 * (at your option) any later version.
cannam@95 10 *
cannam@95 11 * This program is distributed in the hope that it will be useful,
cannam@95 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
cannam@95 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
cannam@95 14 * GNU General Public License for more details.
cannam@95 15 *
cannam@95 16 * You should have received a copy of the GNU General Public License
cannam@95 17 * along with this program; if not, write to the Free Software
cannam@95 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
cannam@95 19 *
cannam@95 20 *)
cannam@95 21
cannam@95 22 (* Here, we take a schedule (produced by schedule.ml) ordering a
cannam@95 23 sequence of instructions, and produce an annotated schedule. The
cannam@95 24 annotated schedule has the same ordering as the original schedule,
cannam@95 25 but is additionally partitioned into nested blocks of temporary
cannam@95 26 variables. The partitioning is computed via a heuristic algorithm.
cannam@95 27
cannam@95 28 The blocking allows the C code that we generate to consist of
cannam@95 29 nested blocks that help communicate variable lifetimes to the
cannam@95 30 compiler. *)
cannam@95 31
cannam@95 32 open Schedule
cannam@95 33 open Expr
cannam@95 34 open Variable
cannam@95 35
cannam@95 36 type annotated_schedule =
cannam@95 37 Annotate of variable list * variable list * variable list * int * aschedule
cannam@95 38 and aschedule =
cannam@95 39 ADone
cannam@95 40 | AInstr of assignment
cannam@95 41 | ASeq of (annotated_schedule * annotated_schedule)
cannam@95 42
cannam@95 43 let addelem a set = if not (List.memq a set) then a :: set else set
cannam@95 44 let union l =
cannam@95 45 let f x = addelem x (* let is source of polymorphism *)
cannam@95 46 in List.fold_right f l
cannam@95 47
cannam@95 48 (* set difference a - b *)
cannam@95 49 let diff a b = List.filter (fun x -> not (List.memq x b)) a
cannam@95 50
cannam@95 51 let rec minimize f = function
cannam@95 52 [] -> failwith "minimize"
cannam@95 53 | [n] -> n
cannam@95 54 | n :: rest ->
cannam@95 55 let x = minimize f rest in
cannam@95 56 if (f x) >= (f n) then n else x
cannam@95 57
cannam@95 58 (* find all variables used inside a scheduling unit *)
cannam@95 59 let rec find_block_vars = function
cannam@95 60 Done -> []
cannam@95 61 | (Instr (Assign (v, x))) -> v :: (find_vars x)
cannam@95 62 | Par a -> List.flatten (List.map find_block_vars a)
cannam@95 63 | Seq (a, b) -> (find_block_vars a) @ (find_block_vars b)
cannam@95 64
cannam@95 65 let uniq l =
cannam@95 66 List.fold_right (fun a b -> if List.memq a b then b else a :: b) l []
cannam@95 67
cannam@95 68 let has_related x = List.exists (Variable.same_class x)
cannam@95 69
cannam@95 70 let rec overlap a b = Util.count (fun y -> has_related y b) a
cannam@95 71
cannam@95 72 (* reorder a list of schedules so as to maximize overlap of variables *)
cannam@95 73 let reorder l =
cannam@95 74 let rec loop = function
cannam@95 75 [] -> []
cannam@95 76 | (a, va) :: b ->
cannam@95 77 let c =
cannam@95 78 List.map
cannam@95 79 (fun (a, x) -> ((a, x), (overlap va x, List.length x))) b in
cannam@95 80 let c' =
cannam@95 81 Sort.list
cannam@95 82 (fun (_, (a, la)) (_, (b, lb)) ->
cannam@95 83 la < lb or a > b)
cannam@95 84 c in
cannam@95 85 let b' = List.map (fun (a, _) -> a) c' in
cannam@95 86 a :: (loop b') in
cannam@95 87 let l' = List.map (fun x -> x, uniq (find_block_vars x)) l in
cannam@95 88 (* start with smallest block --- does this matter ? *)
cannam@95 89 match l' with
cannam@95 90 [] -> []
cannam@95 91 | _ ->
cannam@95 92 let m = minimize (fun (_, x) -> (List.length x)) l' in
cannam@95 93 let l'' = Util.remove m l' in
cannam@95 94 loop (m :: l'')
cannam@95 95
cannam@95 96 (* remove Par blocks *)
cannam@95 97 let rec linearize = function
cannam@95 98 | Seq (a, Done) -> linearize a
cannam@95 99 | Seq (Done, a) -> linearize a
cannam@95 100 | Seq (a, b) -> Seq (linearize a, linearize b)
cannam@95 101
cannam@95 102 (* try to balance nested Par blocks *)
cannam@95 103 | Par [a] -> linearize a
cannam@95 104 | Par l ->
cannam@95 105 let n2 = (List.length l) / 2 in
cannam@95 106 let rec loop n a b =
cannam@95 107 if n = 0 then
cannam@95 108 (List.rev b, a)
cannam@95 109 else
cannam@95 110 match a with
cannam@95 111 [] -> failwith "loop"
cannam@95 112 | x :: y -> loop (n - 1) y (x :: b)
cannam@95 113 in let (a, b) = loop n2 (reorder l) []
cannam@95 114 in linearize (Seq (Par a, Par b))
cannam@95 115
cannam@95 116 | x -> x
cannam@95 117
cannam@95 118 let subset a b =
cannam@95 119 List.for_all (fun x -> List.exists (fun y -> x == y) b) a
cannam@95 120
cannam@95 121 let use_same_vars (Assign (av, ax)) (Assign (bv, bx)) =
cannam@95 122 is_temporary av &&
cannam@95 123 is_temporary bv &&
cannam@95 124 (let va = Expr.find_vars ax and vb = Expr.find_vars bx in
cannam@95 125 subset va vb && subset vb va)
cannam@95 126
cannam@95 127 let store_to_same_class (Assign (av, ax)) (Assign (bv, bx)) =
cannam@95 128 is_locative av &&
cannam@95 129 is_locative bv &&
cannam@95 130 Variable.same_class av bv
cannam@95 131
cannam@95 132 let loads_from_same_class (Assign (av, ax)) (Assign (bv, bx)) =
cannam@95 133 match (ax, bx) with
cannam@95 134 | (Load a), (Load b) when
cannam@95 135 Variable.is_locative a && Variable.is_locative b
cannam@95 136 -> Variable.same_class a b
cannam@95 137 | _ -> false
cannam@95 138
cannam@95 139 (* extract instructions from schedule *)
cannam@95 140 let rec sched_to_ilist = function
cannam@95 141 | Done -> []
cannam@95 142 | Instr a -> [a]
cannam@95 143 | Seq (a, b) -> (sched_to_ilist a) @ (sched_to_ilist b)
cannam@95 144 | _ -> failwith "sched_to_ilist" (* Par blocks removed by linearize *)
cannam@95 145
cannam@95 146 let rec find_friends friendp insn friends foes = function
cannam@95 147 | [] -> (friends, foes)
cannam@95 148 | a :: b ->
cannam@95 149 if (a == insn) || (friendp a insn) then
cannam@95 150 find_friends friendp insn (a :: friends) foes b
cannam@95 151 else
cannam@95 152 find_friends friendp insn friends (a :: foes) b
cannam@95 153
cannam@95 154 (* schedule all instructions in the equivalence class determined
cannam@95 155 by friendp at the point where the last one
cannam@95 156 is executed *)
cannam@95 157 let rec delay_friends friendp sched =
cannam@95 158 let rec recur insns = function
cannam@95 159 | Done -> (Done, insns)
cannam@95 160 | Instr a ->
cannam@95 161 let (friends, foes) = find_friends friendp a [] [] insns in
cannam@95 162 (Schedule.sequentially friends), foes
cannam@95 163 | Seq (a, b) ->
cannam@95 164 let (b', insnsb) = recur insns b in
cannam@95 165 let (a', insnsa) = recur insnsb a in
cannam@95 166 (Seq (a', b')), insnsa
cannam@95 167 | _ -> failwith "delay_friends"
cannam@95 168 in match recur (sched_to_ilist sched) sched with
cannam@95 169 | (s, []) -> s (* assert that all insns have been used *)
cannam@95 170 | _ -> failwith "delay_friends"
cannam@95 171
cannam@95 172 (* schedule all instructions in the equivalence class determined
cannam@95 173 by friendp at the point where the first one
cannam@95 174 is executed *)
cannam@95 175 let rec anticipate_friends friendp sched =
cannam@95 176 let rec recur insns = function
cannam@95 177 | Done -> (Done, insns)
cannam@95 178 | Instr a ->
cannam@95 179 let (friends, foes) = find_friends friendp a [] [] insns in
cannam@95 180 (Schedule.sequentially friends), foes
cannam@95 181 | Seq (a, b) ->
cannam@95 182 let (a', insnsa) = recur insns a in
cannam@95 183 let (b', insnsb) = recur insnsa b in
cannam@95 184 (Seq (a', b')), insnsb
cannam@95 185 | _ -> failwith "anticipate_friends"
cannam@95 186 in match recur (sched_to_ilist sched) sched with
cannam@95 187 | (s, []) -> s (* assert that all insns have been used *)
cannam@95 188 | _ -> failwith "anticipate_friends"
cannam@95 189
cannam@95 190 let collect_buddy_stores buddy_list sched =
cannam@95 191 let rec recur sched delayed_stores = match sched with
cannam@95 192 | Done -> (sched, delayed_stores)
cannam@95 193 | Instr (Assign (v, x)) ->
cannam@95 194 begin
cannam@95 195 try
cannam@95 196 let buddies = List.find (List.memq v) buddy_list in
cannam@95 197 let tmp = Variable.make_temporary () in
cannam@95 198 let i = Seq(Instr (Assign (tmp, x)),
cannam@95 199 Instr (Assign (v, Times (NaN MULTI_A, Load tmp))))
cannam@95 200 and delayed_stores = (v, Load tmp) :: delayed_stores in
cannam@95 201 try
cannam@95 202 (Seq (i,
cannam@95 203 Instr (Assign
cannam@95 204 (List.hd buddies,
cannam@95 205 Times (NaN MULTI_B,
cannam@95 206 Plus (List.map
cannam@95 207 (fun buddy ->
cannam@95 208 List.assq buddy
cannam@95 209 delayed_stores)
cannam@95 210 buddies))) )))
cannam@95 211 , delayed_stores
cannam@95 212 with Not_found -> (i, delayed_stores)
cannam@95 213 with Not_found -> (sched, delayed_stores)
cannam@95 214 end
cannam@95 215 | Seq (a, b) ->
cannam@95 216 let (newa, delayed_stores) = recur a delayed_stores in
cannam@95 217 let (newb, delayed_stores) = recur b delayed_stores in
cannam@95 218 (Seq (newa, newb), delayed_stores)
cannam@95 219 | _ -> failwith "collect_buddy_stores"
cannam@95 220 in let (sched, _) = recur sched [] in
cannam@95 221 sched
cannam@95 222
cannam@95 223 let schedule_for_pipeline sched =
cannam@95 224 let update_readytimes t (Assign (v, _)) ready_times =
cannam@95 225 (v, (t + !Magic.pipeline_latency)) :: ready_times
cannam@95 226 and readyp t ready_times (Assign (_, x)) =
cannam@95 227 List.for_all
cannam@95 228 (fun var ->
cannam@95 229 try
cannam@95 230 (List.assq var ready_times) <= t
cannam@95 231 with Not_found -> false)
cannam@95 232 (List.filter Variable.is_temporary (Expr.find_vars x))
cannam@95 233 in
cannam@95 234 let rec recur sched t ready_times delayed_instructions =
cannam@95 235 let (ready, not_ready) =
cannam@95 236 List.partition (readyp t ready_times) delayed_instructions
cannam@95 237 in match ready with
cannam@95 238 | a :: b ->
cannam@95 239 let (sched, t, ready_times, delayed_instructions) =
cannam@95 240 recur sched (t+1) (update_readytimes t a ready_times)
cannam@95 241 (b @ not_ready)
cannam@95 242 in
cannam@95 243 (Seq (Instr a, sched)), t, ready_times, delayed_instructions
cannam@95 244 | _ -> (match sched with
cannam@95 245 | Done -> (sched, t, ready_times, delayed_instructions)
cannam@95 246 | Instr a ->
cannam@95 247 if (readyp t ready_times a) then
cannam@95 248 (sched, (t+1), (update_readytimes t a ready_times),
cannam@95 249 delayed_instructions)
cannam@95 250 else
cannam@95 251 (Done, t, ready_times, (a :: delayed_instructions))
cannam@95 252 | Seq (a, b) ->
cannam@95 253 let (a, t, ready_times, delayed_instructions) =
cannam@95 254 recur a t ready_times delayed_instructions
cannam@95 255 in
cannam@95 256 let (b, t, ready_times, delayed_instructions) =
cannam@95 257 recur b t ready_times delayed_instructions
cannam@95 258 in (Seq (a, b)), t, ready_times, delayed_instructions
cannam@95 259 | _ -> failwith "schedule_for_pipeline")
cannam@95 260 in let rec recur_until_done sched t ready_times delayed_instructions =
cannam@95 261 let (sched, t, ready_times, delayed_instructions) =
cannam@95 262 recur sched t ready_times delayed_instructions
cannam@95 263 in match delayed_instructions with
cannam@95 264 | [] -> sched
cannam@95 265 | _ ->
cannam@95 266 (Seq (sched,
cannam@95 267 (recur_until_done Done (t+1) ready_times
cannam@95 268 delayed_instructions)))
cannam@95 269 in recur_until_done sched 0 [] []
cannam@95 270
cannam@95 271 let rec rewrite_declarations force_declarations
cannam@95 272 (Annotate (_, _, declared, _, what)) =
cannam@95 273 let m = !Magic.number_of_variables in
cannam@95 274
cannam@95 275 let declare_it declared =
cannam@95 276 if (force_declarations or List.length declared >= m) then
cannam@95 277 ([], declared)
cannam@95 278 else
cannam@95 279 (declared, [])
cannam@95 280
cannam@95 281 in match what with
cannam@95 282 ADone -> Annotate ([], [], [], 0, what)
cannam@95 283 | AInstr i ->
cannam@95 284 let (u, d) = declare_it declared
cannam@95 285 in Annotate ([], u, d, 0, what)
cannam@95 286 | ASeq (a, b) ->
cannam@95 287 let ma = rewrite_declarations false a
cannam@95 288 and mb = rewrite_declarations false b
cannam@95 289 in let Annotate (_, ua, _, _, _) = ma
cannam@95 290 and Annotate (_, ub, _, _, _) = mb
cannam@95 291 in let (u, d) = declare_it (declared @ ua @ ub)
cannam@95 292 in Annotate ([], u, d, 0, ASeq (ma, mb))
cannam@95 293
cannam@95 294 let annotate list_of_buddy_stores schedule =
cannam@95 295 let rec analyze live_at_end = function
cannam@95 296 Done -> Annotate (live_at_end, [], [], 0, ADone)
cannam@95 297 | Instr i -> (match i with
cannam@95 298 Assign (v, x) ->
cannam@95 299 let vars = (find_vars x) in
cannam@95 300 Annotate (Util.remove v (union live_at_end vars), [v], [],
cannam@95 301 0, AInstr i))
cannam@95 302 | Seq (a, b) ->
cannam@95 303 let ab = analyze live_at_end b in
cannam@95 304 let Annotate (live_at_begin_b, defined_b, _, depth_a, _) = ab in
cannam@95 305 let aa = analyze live_at_begin_b a in
cannam@95 306 let Annotate (live_at_begin_a, defined_a, _, depth_b, _) = aa in
cannam@95 307 let defined = List.filter is_temporary (defined_a @ defined_b) in
cannam@95 308 let declarable = diff defined live_at_end in
cannam@95 309 let undeclarable = diff defined declarable
cannam@95 310 and maxdepth = max depth_a depth_b in
cannam@95 311 Annotate (live_at_begin_a, undeclarable, declarable,
cannam@95 312 List.length declarable + maxdepth,
cannam@95 313 ASeq (aa, ab))
cannam@95 314 | _ -> failwith "really_analyze"
cannam@95 315
cannam@95 316 in
cannam@95 317 let () = Util.info "begin annotate" in
cannam@95 318 let x = linearize schedule in
cannam@95 319
cannam@95 320 let x =
cannam@95 321 if (!Magic.schedule_for_pipeline && !Magic.pipeline_latency > 0) then
cannam@95 322 schedule_for_pipeline x
cannam@95 323 else
cannam@95 324 x
cannam@95 325 in
cannam@95 326
cannam@95 327 let x =
cannam@95 328 if !Magic.reorder_insns then
cannam@95 329 linearize(anticipate_friends use_same_vars x)
cannam@95 330 else
cannam@95 331 x
cannam@95 332 in
cannam@95 333
cannam@95 334 (* delay stores to the real and imaginary parts of the same number *)
cannam@95 335 let x =
cannam@95 336 if !Magic.reorder_stores then
cannam@95 337 linearize(delay_friends store_to_same_class x)
cannam@95 338 else
cannam@95 339 x
cannam@95 340 in
cannam@95 341
cannam@95 342 (* move loads of the real and imaginary parts of the same number *)
cannam@95 343 let x =
cannam@95 344 if !Magic.reorder_loads then
cannam@95 345 linearize(anticipate_friends loads_from_same_class x)
cannam@95 346 else
cannam@95 347 x
cannam@95 348 in
cannam@95 349
cannam@95 350 let x = collect_buddy_stores list_of_buddy_stores x in
cannam@95 351 let x = analyze [] x in
cannam@95 352 let res = rewrite_declarations true x in
cannam@95 353 let () = Util.info "end annotate" in
cannam@95 354 res
cannam@95 355
cannam@95 356 let rec dump print (Annotate (_, _, _, _, code)) =
cannam@95 357 dump_code print code
cannam@95 358 and dump_code print = function
cannam@95 359 | ADone -> ()
cannam@95 360 | AInstr x -> print ((assignment_to_string x) ^ "\n")
cannam@95 361 | ASeq (a, b) -> dump print a; dump print b