1 (* Copyright (C) 2009,2011,2017 Matthew Fluet.
2 * Copyright (C) 1999-2006 Henry Cejtin, Matthew Fluet, Suresh
3 * Jagannathan, and Stephen Weeks.
4 * Copyright (C) 1997-2000 NEC Research Institute.
6 * MLton is released under a BSD-style license.
7 * See the file MLton-LICENSE for details.
10 functor CommonSubexp (S: SSA_TRANSFORM_STRUCTS): SSA_TRANSFORM =
17 fun transform (Program.T {globals, datatypes, functions, main}) =
19 (* Keep track of control-flow specific cse's,
20 * arguments, and in-degree of blocks.
22 val {get = labelInfo: Label.t -> {add: (Var.t * Exp.t) list ref,
23 args: (Var.t * Type.t) vector,
25 set = setLabelInfo, ...} =
26 Property.getSetOnce (Label.plist,
27 Property.initRaise ("info", Label.layout))
28 (* Keep track of a total ordering on variables. *)
29 val {get = varIndex : Var.t -> int, set = setVarIndex, ...} =
30 Property.getSetOnce (Var.plist,
31 Property.initRaise ("varIndex", Var.layout))
36 fn x => setVarIndex (x, Counter.next c)
38 (* Keep track of variables used as overflow variables. *)
39 val {get = overflowVar: Var.t -> bool, set = setOverflowVar, ...} =
40 Property.getSetOnce (Var.plist, Property.initConst false)
41 (* Keep track of the replacements of variables. *)
42 val {get = replace: Var.t -> Var.t option, set = setReplace, ...} =
43 Property.getSetOnce (Var.plist, Property.initConst NONE)
44 (* Keep track of the variable that holds the length of arrays (and
45 * vectors and strings).
47 val {get = getLength: Var.t -> Var.t option, set = setLength, ...} =
48 Property.getSetOnce (Var.plist, Property.initConst NONE)
53 fun canonVars xs = Vector.map (xs, canonVar)
54 (* Canonicalize an Exp.
55 * Replace vars with their replacements.
56 * Put commutative arguments in canonical order.
58 fun canon (e: Exp.t): Exp.t =
61 ConApp {con = con, args = canonVars args}
63 | PrimApp {prim, targs, args} =>
69 val args = canonVars args
70 fun arg i = Vector.sub (args, i)
76 if varIndex a0 >= varIndex a1
80 datatype z = datatype Prim.Name.t
82 if Prim.isCommutative prim
83 then doit (Vector.new2 (canon2 ()))
85 if (case Prim.name prim of
95 val (a0, a1) = canon2 ()
96 in doit (Vector.new3 (a0, a1, arg 2))
100 | Select {tuple, offset} => Select {tuple = canonVar tuple,
102 | Tuple xs => Tuple (canonVars xs)
103 | Var x => Var (canonVar x)
106 (* Keep a hash table of canonicalized Exps that are in scope. *)
107 val table: {hash: word, exp: Exp.t, var: Var.t} HashSet.t =
108 HashSet.new {hash = #hash}
109 fun lookup (var, exp, hash) =
110 HashSet.lookupOrInsert
112 fn {exp = exp', ...} => Exp.equals (exp, exp'),
117 (* All of the globals are in scope, and never go out of scope. *)
118 (* The hash-cons'ing of globals in ConstantPropagation ensures
119 * that each global is unique.
123 (globals, fn Statement.T {var, exp, ...} =>
126 val () = setVarIndex var
128 val _ = lookup (var, exp, Exp.hash exp)
136 fun loop (Tree.T (Block.T {args, label,
137 statements, transfer},
145 display (seq [Label.layout label, str ": ", str s])
147 val _ = diag "started"
149 val {add, ...} = labelInfo label
150 val _ = Control.diagnostics
154 display (seq [str "add: ",
155 List.layout (fn (var,exp) =>
158 Exp.layout exp]) (!add)])
161 (!add, fn (var, exp) =>
163 val hash = Exp.hash exp
164 val elem as {var = var', ...} = lookup (var, exp, hash)
165 val _ = if Var.equals(var, var')
166 then List.push (remove, elem)
175 (args, fn (var, _) => setVarIndex var)
179 fn Statement.T {var, ty, exp} =>
182 fun keep () = SOME (Statement.T {var = var,
190 val _ = setVarIndex var
192 (setReplace (var, SOME var'); NONE)
195 val hash = Exp.hash exp
196 val elem as {var = var', ...} =
197 lookup (var, exp, hash)
199 if Var.equals(var, var')
200 then (List.push (remove, elem)
206 PrimApp ({args, prim, ...}) =>
208 fun arg () = Vector.first args
209 fun knownLength var' =
211 val _ = setLength (var, SOME var')
216 case getLength (arg ()) of
218 | SOME var' => knownLength var'
220 case getLength (arg ()) of
222 | SOME var' => replace var'
223 datatype z = datatype Prim.Name.t
225 case Prim.name prim of
226 Array_alloc _ => knownLength (arg ())
227 | Array_length => length ()
228 | Array_toArray => conv ()
229 | Array_toVector => conv ()
230 | Vector_length => length ()
231 | _ => if Prim.isFunctional prim
238 val _ = diag "statements"
239 val transfer = Transfer.replaceVar (transfer, canonVar)
242 Arith {prim, args, overflow, success, ...} =>
244 val {args = succArgs,
246 add = succAdd, ...} =
248 val {inDeg = overInDeg,
249 add = overAdd, ...} =
251 val exp = canon (PrimApp {prim = prim,
252 targs = Vector.new0 (),
254 val hash = Exp.hash exp
258 fn {exp = exp', ...} => Exp.equals (exp, exp')) of
261 then Goto {dst = overflow,
262 args = Vector.new0 ()}
263 else (if !succInDeg = 1
266 Vector.first succArgs
268 setReplace (var', SOME var)
271 ; Goto {dst = success,
272 args = Vector.new1 var})
273 | NONE => (if !succInDeg = 1
276 Vector.first succArgs
279 (succAdd, (var, exp))
284 val var = Var.newNoname ()
285 val _ = setOverflowVar (var, true)
288 (overAdd, (var, exp))
293 | Goto {dst, args} =>
295 val {args = args', inDeg, ...} = labelInfo dst
298 then (Vector.foreach2
299 (args, args', fn (var, (var', _)) =>
300 setReplace (var', SOME var))
305 val _ = diag "transfer"
306 val block = Block.T {args = args,
308 statements = statements,
310 val _ = List.push (blocks, block)
311 val _ = Vector.foreach (children, loop)
312 val _ = diag "children"
313 val _ = Control.diagnostics
317 display (seq [str "remove: ",
318 List.layout (fn {var,exp,...} =>
321 Exp.layout exp]) (!remove)])
324 (!remove, fn {var, hash, ...} =>
326 (table, hash, fn {var = var', ...} =>
327 Var.equals (var, var')))
328 val _ = diag "removed"
337 display (seq [str "starting loop"])
345 display (seq [str "finished loop"])
348 Vector.fromList (!blocks)
350 val shrink = shrinkFunction {globals = globals}
355 val {args, blocks, mayInline, name, raises, returns, start} =
359 (args, fn (var, _) => setVarIndex var)
362 (blocks, fn Block.T {label, args, ...} =>
363 (setLabelInfo (label, {add = ref [],
368 (blocks, fn Block.T {transfer, ...} =>
369 Transfer.foreachLabel (transfer, fn label' =>
370 Int.inc (#inDeg (labelInfo label'))))
371 val blocks = doitTree (Function.dominatorTree f)
373 shrink (Function.new {args = args,
375 mayInline = mayInline,
382 Program.T {datatypes = datatypes,
384 functions = functions,
386 val _ = Program.clearTop program