1 (* Copyright (C) 2009,2017 Matthew Fluet.
2 * Copyright (C) 2004-2008 Henry Cejtin, Matthew Fluet, Suresh
3 * Jagannathan, and Stephen Weeks.
5 * MLton is released under a BSD-style license.
6 * See the file MLton-LICENSE for details.
9 functor DeepFlatten (S: SSA2_TRANSFORM_STRUCTS): SSA2_TRANSFORM =
14 datatype z = datatype Exp.t
15 datatype z = datatype Statement.t
16 datatype z = datatype Transfer.t
18 structure Tree = Tree (structure Seq = Prod)
22 datatype t = datatype Tree.t
26 | NotFlat of {ty: Type.t,
31 fun layout (t: t): Layout.t =
38 | NotFlat {ty, var} =>
40 record [("ty", Type.layout ty),
41 ("var", Option.layout Var.layout var)]]
44 val isFlat: t -> bool =
55 val labelRoot: t * Var.t -> t =
56 fn (t as T (info, ts), x) =>
59 | NotFlat {ty, ...} => T (NotFlat {ty = ty, var = SOME x}, ts)
61 val fromTypeTree: TypeTree.t -> t = fn t => t
63 val foldRoots: t * 'a * (Var.t * 'a -> 'a) -> 'a =
66 fun loop (T (info, children), a: 'a): 'a =
68 Flat => Prod.fold (children, a, loop)
69 | NotFlat {var, ...} =>
71 NONE => Error.bug "DeepFlatten.VarTree.foldRoots"
77 fun foreachRoot (t, f) = foldRoots (t, (), f o #1)
79 val rootsOnto: t * Var.t list -> Var.t list =
81 List.appendRev (foldRoots (t, [], op ::), ac)
83 val rec dropVars: t -> t =
89 | NotFlat {ty, ...} => NotFlat {ty = ty, var = NONE}
91 T (info, Prod.map (ts, dropVars))
94 fun fillInRoots (t: t, {base: Var.t Base.t, offset: int})
95 : t * Statement.t list =
97 fun loop (t as T (info, ts), offset, ac) =
101 val (ts, (offset, ac)) =
103 (Prod.dest ts, (offset, ac),
104 fn ({elt = t, isMutable}, (offset, ac)) =>
106 val (t, offset, ac) = loop (t, offset, ac)
108 ({elt = t, isMutable = isMutable},
112 (T (Flat, Prod.make ts), offset, ac)
114 | NotFlat {ty, var} =>
120 val var = Var.newNoname ()
122 (T (NotFlat {ty = ty, var = SOME var}, ts),
124 {exp = Select {base = base,
127 var = SOME var} :: ac)
133 val (t, _, ac) = loop (t, offset, [])
139 Trace.trace2 ("DeepFlatten.VarTree.fillInRoots",
142 Layout.record [("base", Base.layout (base, Var.layout)),
143 ("offset", Int.layout offset)],
144 Layout.tuple2 (layout, List.layout Statement.layout))
148 fun flatten {base: Var.t Base.t option,
151 to: TypeTree.t}: {offset: int} * VarTree.t * Statement.t list =
153 val Tree.T (from, fs) = from
157 if TypeTree.isFlat to
158 then flattensAt {base = base,
161 tos = Tree.children to}
162 else Error.bug "DeepFlatten.flatten: cannot flatten from Flat to NotFlat"
163 | VarTree.NotFlat {ty, var} =>
171 NONE => Error.bug "DeepFlatten.flatten: flatten missing base"
173 val result = Var.newNoname ()
176 [Bind {exp = Select {base = base,
181 | SOME var => (var, [])
183 if TypeTree.isFlat to
187 flattensAt {base = SOME (Base.Object var),
190 tos = Tree.children to}
194 else (Tree.T (VarTree.NotFlat {ty = ty, var = SOME var},
198 ({offset = 1 + offset}, r, ss)
201 and flattensAt {base: Var.t Base.t option,
202 froms: VarTree.t Prod.t,
204 tos: TypeTree.t Prod.t} =
206 val (ts, (off, ss)) =
208 (Prod.dest froms, Prod.dest tos, ({offset = offset}, []),
209 fn ({elt = f, isMutable}, {elt = t, ...}, ({offset}, ss)) =>
213 then Error.bug "DeepFlatten.flattensAt: mutable"
215 val ({offset}, t, ss') =
216 flatten {base = base,
221 ({elt = t, isMutable = false},
222 ({offset = offset}, ss' @ ss))
225 (off, Tree.T (VarTree.Flat, Prod.make ts), ss)
228 fun coerceTree {from: VarTree.t, to: TypeTree.t}: VarTree.t * Statement.t list =
231 flatten {base = NONE,
243 Trace.trace ("DeepFlatten.coerceTree",
245 record [("from", VarTree.layout from),
246 ("to", TypeTree.layout to)],
248 tuple [VarTree.layout vt,
249 List.layout Statement.layout ss])
255 datatype t = Flat | NotFlat
257 val toString: t -> string =
259 | NotFlat => "NotFlat"
261 val layout = Layout.str o toString
264 datatype z = datatype Flat.t
270 | Object of object Equatable.t
272 withtype object = {args: t Prod.t,
273 coercedFrom: t AppendList.t ref,
275 finalOffsets: int vector option ref,
276 finalTree: TypeTree.t option ref,
277 finalType: Type.t option ref,
278 finalTypes: Type.t Prod.t option ref,
281 fun layout (v: t): Layout.t =
286 Ground t => Type.layout t
289 (e, fn {args, con, flat, ...} =>
291 record [("args", Prod.layout (args, layout)),
292 ("con", ObjectCon.layout con),
293 ("flat", Flat.layout (! flat))]])
294 | Weak {arg, ...} => seq [str "Weak ", layout arg]
300 Trace.trace ("DeepFlatten.Value.coerce",
302 Layout.record [("from", layout from),
307 Trace.trace2 ("DeepFlatten.Value.unify", layout, layout, Unit.layout)
309 val rec unify: t * t -> unit =
314 (Ground _, Ground _) => ()
315 | (Object e, Object e') =>
317 val callDont = ref false
321 fn (z as {args = a, coercedFrom = c, flat = f, ...},
322 z' as {args = a', coercedFrom = c', flat = f', ...}) =>
324 val () = unifyProd (a, a')
328 (c := AppendList.append (!c', !c); z)
330 (callDont := true; z)
332 (callDont := true; z')
333 | (NotFlat, NotFlat) => z
340 | (Weak {arg = a, ...}, Weak {arg = a', ...}) =>
342 | _ => Error.bug "DeepFlatten.unify: strange") arg
346 (Prod.dest p, Prod.dest p',
347 fn ({elt = e, ...}, {elt = e', ...}) => unify (e, e'))
348 and dontFlatten: t -> unit =
353 val {coercedFrom, flat, ...} = Equatable.value e
358 val () = flat := NotFlat
359 val from = !coercedFrom
360 val () = coercedFrom := AppendList.empty
362 AppendList.foreach (from, fn v' => unify (v, v'))
369 fn arg as {from, to} =>
373 (Ground _, Ground _) => ()
374 | (Object e, Object e') =>
375 if Equatable.equals (e, e')
378 Equatable.whenComputed
379 (e', fn {args = a', coercedFrom = c', flat = f', ...} =>
381 val {args = a, con, ...} = Equatable.value e
383 if Prod.someIsMutable a orelse ObjectCon.isVector con
384 then unify (from, to)
387 Flat => (AppendList.push (c', from)
388 ; coerceProd {from = a, to = a'})
389 | NotFlat => unify (from, to)
391 | (Weak _, Weak _) => unify (from, to)
392 | _ => Error.bug "DeepFlatten.coerce: strange") arg
394 fn {from = p, to = p'} =>
396 (Prod.dest p, Prod.dest p', fn ({elt = e, ...}, {elt = e', ...}) =>
397 coerce {from = e, to = e'})
399 fun mayFlatten {args, con}: bool =
400 (* Don't flatten constructors, since they are part of a sum type.
401 * Don't flatten unit.
402 * Don't flatten vectors (of course their components can be
404 * Don't flatten objects with mutable fields, since sharing must be
407 not (Prod.isEmpty args)
408 andalso Prod.allAreImmutable args
410 ObjectCon.Con _ => false
411 | ObjectCon.Tuple => true
412 | ObjectCon.Vector => false)
414 fun objectFields {args, con} =
416 (* Don't flatten object components that are immutable fields. Those
417 * have already had a chance to be flattened by other passes.
421 ObjectCon.Con _ => true
422 | ObjectCon.Tuple => true
423 | ObjectCon.Vector => false)
424 then Vector.foreach (Prod.dest args, fn {elt, isMutable} =>
427 else dontFlatten elt)
430 if mayFlatten {args = args, con = con}
435 coercedFrom = ref AppendList.empty,
437 finalOffsets = ref NONE,
438 finalTree = ref NONE,
439 finalType = ref NONE,
440 finalTypes = ref NONE,
445 Object (Equatable.delay (fn () => objectFields (f ())))
447 val tuple: t Prod.t -> t =
449 Object (Equatable.new (objectFields {args = vs, con = ObjectCon.Tuple}))
452 Trace.trace ("DeepFlatten.Value.tuple",
453 fn p => Prod.layout (p, layout),
457 fun weak (arg: t) = Weak {arg = arg}
459 val deObject: t -> object option =
462 Object e => SOME (Equatable.value e)
466 Trace.trace ("DeepFlatten.Value.finalType", layout, Type.layout)
467 val traceFinalTypes =
468 Trace.trace ("DeepFlatten.Value.finalTypes",
470 fn p => Prod.layout (p, Type.layout))
472 fun finalTree (v: t): TypeTree.t =
474 fun notFlat (): TypeTree.info =
475 TypeTree.NotFlat {ty = finalType v, var = NONE}
478 NONE => Tree.T (notFlat (), Prod.empty ())
479 | SOME {args, finalTree = r, flat, ...} =>
485 Flat => TypeTree.Flat
486 | NotFlat => notFlat ()
488 Tree.T (info, Prod.map (args, finalTree))
491 and finalType arg: Type.t =
498 val {finalType = r, ...} = Equatable.value e
500 Ref.memoize (r, fn () => Prod.elt (finalTypes v, 0))
502 | Weak {arg, ...} => Type.weak (finalType arg)) arg
503 and finalTypes arg: Type.t Prod.t =
508 Prod.make (Vector.new1 {elt = finalType v,
510 | SOME {args, con, finalTypes, flat, ...} =>
512 (finalTypes, fn () =>
514 val args = prodFinalTypes args
521 {elt = Type.object {args = args, con = con},
524 and prodFinalTypes (p: t Prod.t): Type.t Prod.t =
528 (Prod.dest p, [], fn ({elt, isMutable = i}, ac) =>
530 (Prod.dest (finalTypes elt), ac, fn ({elt, isMutable = i'}, ac) =>
531 {elt = elt, isMutable = i orelse i'} :: ac))))
536 type t = Value.object
538 fun select ({args, ...}: t, offset): Value.t =
539 Prod.elt (args, offset)
541 fun finalOffsets ({args, finalOffsets = r, ...}: t): int vector =
546 (args, (0, []), fn (elt, (offset, offsets)) =>
547 (offset + Prod.length (Value.finalTypes elt),
548 offset :: offsets)))))
550 fun finalOffset (object, offset) =
551 Vector.sub (finalOffsets object, offset)
554 fun transform2 (program as Program.T {datatypes, functions, globals, main}) =
556 val {get = conValue: Con.t -> Value.t option ref, ...} =
557 Property.get (Con.plist, Property.initFun (fn _ => ref NONE))
559 Trace.trace ("DeepFlatten.conValue",
560 Con.layout, Ref.layout (Option.layout Value.layout))
565 val traceMakeTypeValue =
566 Trace.trace ("DeepFlatten.makeTypeValue",
573 fun needToMakeProd p =
574 Vector.exists (Prod.dest p, fn {elt, ...} =>
578 fun makeProd p = Prod.map (p, makeValue)
579 val {get = makeTypeValue: Type.t -> Value.t make, ...} =
584 (fn (t, makeTypeValue) =>
586 fun const () = Const (Value.ground t)
587 datatype z = datatype Type.dest
590 Object {args, con} =>
592 val args = Prod.map (args, makeTypeValue)
594 if needToMakeProd args
595 orelse Value.mayFlatten {args = args, con = con}
599 Value.object (fn () => {args = makeProd args,
602 datatype z = datatype ObjectCon.t
607 (conValue c, fn () =>
608 makeValue (doit ())))
613 (case makeTypeValue t of
615 | Make f => Make (fn () => Value.weak (f ())))
618 fun typeValue (t: Type.t): Value.t =
619 makeValue (makeTypeValue t)
621 Trace.trace ("DeepFlatten.typeValue", Type.layout, Value.layout)
623 val (coerce, coerceProd) = (Value.coerce, Value.coerceProd)
624 fun inject {sum, variant = _} = typeValue (Type.datatypee sum)
625 fun object {args, con, resultType} =
627 val m = makeTypeValue resultType
633 | Make _ => Value.tuple args)
639 case Value.deObject v of
641 | SOME {args = args', ...} =>
642 coerceProd {from = args, to = args'}
646 | _ => Error.bug "DeepFlatten.object: strange con value")
650 ("DeepFlatten.object",
651 fn {args, con, ...} =>
652 Layout.record [("args", Prod.layout (args, Value.layout)),
653 ("con", Option.layout Con.layout con)],
656 val deWeak : Value.t -> Value.t =
660 typeValue (case Type.dest t of
662 | _ => Error.bug "DeepFlatten.primApp: deWeak")
663 | Value.Weak {arg, ...} => arg
664 | _ => Error.bug "DeepFlatten.primApp: Value.deWeak"
665 fun primApp {args, prim, resultVar = _, resultType} =
668 case makeTypeValue resultType of
670 | Make _ => Value.weak v
671 fun arg i = Vector.sub (args, i)
672 fun result () = typeValue resultType
673 datatype z = datatype Prim.Name.t
675 (Vector.foreach (args, Value.dontFlatten)
678 (Value.unify (arg 0, arg 1)
679 ; Value.dontFlatten (arg 0)
682 case Prim.name prim of
687 case (Value.deObject (arg 0), Value.deObject res) of
689 | (SOME {args = a, ...}, SOME {args = a', ...}) =>
691 (Prod.dest a, Prod.dest a',
692 fn ({elt = v, ...}, {elt = v', ...}) =>
694 | _ => Error.bug "DeepFlatten.primApp: Array_toArray"
702 case (Value.deObject (arg 0), Value.deObject res) of
704 | (SOME {args = a, ...}, SOME {args = a', ...}) =>
706 (Prod.dest a, Prod.dest a',
707 fn ({elt = v, ...}, {elt = v', ...}) =>
709 | _ => Error.bug "DeepFlatten.primApp: Array_toVector"
714 (* Some imports, like Real64.modf, take ref cells that can not
718 | MLton_eq => equal ()
719 | MLton_equal => equal ()
720 | MLton_size => dontFlatten ()
721 | MLton_share => dontFlatten ()
722 | Weak_get => deWeak (arg 0)
725 in (Value.dontFlatten a; weak a)
731 Base.Object obj => obj
732 | Base.VectorSub {vector, ...} => vector
733 fun select {base, offset} =
735 datatype z = datatype Value.t
740 Type.Object {args, ...} =>
741 typeValue (Prod.elt (args, offset))
742 | _ => Error.bug "DeepFlatten.select: Ground")
743 | Object e => Object.select (Equatable.value e, offset)
744 | _ => Error.bug "DeepFlatten.select:"
746 fun update {base, offset, value} =
747 coerce {from = value,
748 to = select {base = base, offset = offset}}
749 fun const c = typeValue (Type.ofConst c)
750 val {func, value = varValue, ...} =
751 analyze {base = base,
755 filterWord = fn _ => (),
756 fromType = typeValue,
758 layout = Value.layout,
762 select = fn {base, offset, ...} => select {base = base,
765 useFromTypeOnBinds = false}
766 (* Don't flatten outermost part of formal parameters. *)
767 fun dontFlattenFormals (xts: (Var.t * Type.t) vector): unit =
768 Vector.foreach (xts, fn (x, _) => Value.dontFlatten (varValue x))
773 val {args, blocks, ...} = Function.dest f
774 val () = dontFlattenFormals args
775 val () = Vector.foreach (blocks, fn Block.T {args, ...} =>
776 dontFlattenFormals args)
787 (datatypes, fn Datatype.T {cons, ...} =>
789 (cons, fn {con, ...} =>
790 display (Option.layout Value.layout (! (conValue con)))))
793 (program, fn (x, _) =>
795 (seq [Var.layout x, str " ", Value.layout (varValue x)]))
799 (* Transform the program. *)
802 (datatypes, fn Datatype.T {cons, tycon} =>
806 (cons, fn {con, args} =>
809 case ! (conValue con) of
812 case Type.dest (Value.finalType v) of
813 Type.Object {args, ...} => args
814 | _ => Error.bug "DeepFlatten.datatypes: strange con"
816 {args = args, con = con}
819 Datatype.T {cons = cons, tycon = tycon}
821 val valueType = Value.finalType
822 fun valuesTypes vs = Vector.map (vs, Value.finalType)
823 val {get = varTree: Var.t -> VarTree.t, set = setVarTree, ...} =
824 Property.getSetOnce (Var.plist,
825 Property.initRaise ("tree", Var.layout))
827 Trace.trace2 ("DeepFlatten.setVarTree",
828 Var.layout, VarTree.layout, Unit.layout)
830 fun simpleVarTree (x: Var.t): unit =
832 (x, VarTree.labelRoot (VarTree.fromTypeTree
833 (Value.finalTree (varValue x)),
835 fun transformFormals xts =
836 Vector.map (xts, fn (x, _) =>
838 val () = simpleVarTree x
840 (x, Value.finalType (varValue x))
842 fun replaceVar (x: Var.t): Var.t =
844 fun bug () = Error.bug (concat ["DeepFlatten.replaceVar ", Var.toString x])
845 val Tree.T (info, _) = varTree x
848 VarTree.Flat => bug ()
849 | VarTree.NotFlat {var, ...} =>
854 fun transformBind {exp, ty, var}: Statement.t list =
856 fun simpleTree () = Option.app (var, simpleVarTree)
857 fun doit (e: Exp.t) =
862 | SOME var => valueType (varValue var)
864 [Bind {exp = e, ty = ty, var = var}]
868 ; doit (Exp.replaceVar (exp, replaceVar)))
872 Exp.Const _ => simple ()
873 | Inject _ => simple ()
874 | Object {args, con} =>
881 case Value.deObject v of
883 | SOME {args = expects, flat, ...} =>
887 (args, Prod.dest expects,
888 fn (arg, {elt, isMutable}) =>
893 to = Value.finalTree elt}
896 isMutable = isMutable},
899 val vts = Vector.map (z, #1)
906 Flat => (set VarTree.Flat; none ())
909 val ty = Value.finalType v
918 fn ({elt = vt, ...}, ac) =>
919 VarTree.rootsOnto (vt, ac)))
922 {exp = Object {args = args,
929 fn ((_, ss), ac) => ss @ ac)
933 | PrimApp _ => simple ()
934 | Select {base, offset} =>
939 val baseVar = Base.object base
941 case Value.deObject (varValue baseVar) of
945 val Tree.T (info, children) =
947 val {elt = child, isMutable} =
948 Prod.sub (children, offset)
951 VarTree.Flat => (child, [])
952 | VarTree.NotFlat _ =>
955 (* Don't simplify a select out
956 * of a mutable field.
957 * Something may have mutated
961 then VarTree.dropVars child
966 {base = Base.map (base, replaceVar),
967 offset = (Object.finalOffset
970 val () = setVarTree (var, child)
976 (Option.app (var, fn y => setVarTree (y, varTree x))
979 fun transformStatement (s: Statement.t): Statement.t list =
981 fun simple () = [Statement.replaceUses (s, replaceVar)]
984 Bind b => transformBind b
985 | Profile _ => simple ()
986 | Update {base, offset, value} =>
991 | Base.VectorSub {vector = x, ...} => x
993 case Value.deObject (varValue baseVar) of
999 Value.finalTree (Object.select (object, offset))
1000 val offset = Object.finalOffset (object, offset)
1001 val base = Base.map (base, replaceVar)
1003 if not (TypeTree.isFlat child)
1004 then [Update {base = base,
1006 value = replaceVar value}]
1010 coerceTree {from = varTree value,
1012 val () = ss := ss' @ (!ss)
1020 val () = r := 1 + !r
1023 Update {base = base,
1035 val transformStatement =
1036 Trace.trace ("DeepFlatten.transformStatement",
1038 List.layout Statement.layout)
1040 fun transformStatements ss =
1042 (Vector.map (ss, Vector.fromList o transformStatement))
1043 fun transformTransfer t = Transfer.replaceVar (t, replaceVar)
1044 val transformTransfer =
1045 Trace.trace ("DeepFlatten.transformTransfer",
1046 Transfer.layout, Transfer.layout)
1048 fun transformBlock (Block.T {args, label, statements, transfer}) =
1049 Block.T {args = transformFormals args,
1051 statements = transformStatements statements,
1052 transfer = transformTransfer transfer}
1053 fun transformFunction (f: Function.t): Function.t =
1055 val {args, mayInline, name, start, ...} = Function.dest f
1056 val {raises, returns, ...} = func name
1057 val args = transformFormals args
1058 val raises = Option.map (raises, valuesTypes)
1059 val returns = Option.map (returns, valuesTypes)
1062 Function.dfs (f, fn b =>
1063 (List.push (blocks, transformBlock b)
1066 Function.new {args = args,
1067 blocks = Vector.fromList (!blocks),
1068 mayInline = mayInline,
1074 val globals = transformStatements globals
1075 val functions = List.revMap (functions, transformFunction)
1077 Program.T {datatypes = datatypes,
1078 functions = functions,
1081 val () = Program.clear program