Import Debian changes 20180207-1
[hcoop/debian/mlton.git] / mlton / ssa / ref-flatten.fun
CommitLineData
7f918cf1
CE
1(* Copyright (C) 2009,2017 Matthew Fluet.
2 * Copyright (C) 2004-2008 Henry Cejtin, Matthew Fluet, Suresh
3 * Jagannathan, and Stephen Weeks.
4 *
5 * MLton is released under a BSD-style license.
6 * See the file MLton-LICENSE for details.
7 *)
8
9functor RefFlatten (S: SSA2_TRANSFORM_STRUCTS): SSA2_TRANSFORM =
10struct
11
12open S
13
14structure Graph = DirectedGraph
15structure Node = Graph.Node
16
17datatype z = datatype Exp.t
18datatype z = datatype Statement.t
19datatype z = datatype Transfer.t
20
21structure Finish =
22 struct
23 datatype t = T of {flat: Type.t Prod.t option,
24 ty: Type.t}
25
26 val _: t -> Layout.t =
27 fn T {flat, ty} =>
28 let
29 open Layout
30 in
31 record [("flat",
32 Option.layout (fn p => Prod.layout (p, Type.layout)) flat),
33 ("ty", Type.layout ty)]
34 end
35 end
36
37structure Value =
38 struct
39 datatype t =
40 GroundV of Type.t
41 | Complex of computed Equatable.t
42 and computed =
43 ObjectC of object
44 | WeakC of {arg: t,
45 finalType: Type.t option ref,
46 originalType: Type.t}
47 and object =
48 Obj of {args: t Prod.t,
49 con: ObjectCon.t,
50 finalComponents: Type.t Prod.t option ref,
51 finalOffsets: int vector option ref,
52 finalType: Type.t option ref,
53 flat: flat ref,
54 originalType: Type.t}
55 and flat =
56 NotFlat
57 | Offset of {object: object,
58 offset: int}
59 | Unknown
60
61 fun delay (f: unit -> computed): t = Complex (Equatable.delay f)
62
63 datatype value =
64 Ground of Type.t
65 | Object of object
66 | Weak of {arg: t,
67 finalType: Type.t option ref,
68 originalType: Type.t}
69
70 val value: t -> value =
71 fn GroundV t => Ground t
72 | Complex e =>
73 case Equatable.value e of
74 ObjectC obj => Object obj
75 | WeakC w => Weak w
76
77 local
78 open Layout
79 in
80 fun layout v: Layout.t =
81 case v of
82 GroundV t => Type.layout t
83 | Complex e =>
84 Equatable.layout
85 (e,
86 fn ObjectC ob => layoutObject ob
87 | WeakC {arg, ...} => seq [str "Weak ", layout arg])
88 and layoutFlat (f: flat): Layout.t =
89 case f of
90 NotFlat => str "NotFlat"
91 | Offset {offset, ...} =>
92 seq [str "Offset ",
93 record [("offset", Int.layout offset)]]
94 | Unknown => str "Unknown"
95 and layoutObject (Obj {args, con, flat, ...}) =
96 seq [str "Object ",
97 record [("args", Prod.layout (args, layout)),
98 ("con", ObjectCon.layout con),
99 ("flat", layoutFlat (! flat))]]
100 end
101
102 fun originalType (v: t) =
103 case value v of
104 Ground t => t
105 | Object (Obj {originalType = t, ...}) => t
106 | Weak {originalType = t, ...} => t
107 end
108
109structure Flat =
110 struct
111 datatype t = datatype Value.flat
112 end
113
114structure Object =
115 struct
116 datatype t = datatype Value.object
117
118 val layout = Value.layoutObject
119
120 fun equals (Obj {flat = f, ...}, Obj {flat = f', ...}) = f = f'
121
122 val select: t * int -> Value.t =
123 fn (Obj {args, ...}, offset) =>
124 Prod.elt (args, offset)
125 end
126
127datatype z = datatype Object.t
128
129structure Value =
130 struct
131 open Value
132
133 val ground = GroundV
134
135 val deObject: t -> Object.t option =
136 fn v =>
137 case value v of
138 Object ob => SOME ob
139 | _ => NONE
140
141 fun deFlat {inner: t, outer: Object.t}: Object.t option =
142 case value inner of
143 Object (z as Obj {flat, ...}) =>
144 (case ! flat of
145 Flat.Offset {object, ...} =>
146 if Object.equals (object, outer) then SOME z else NONE
147 | _ => NONE)
148 | _ => NONE
149
150 fun dontFlatten (v: t): unit =
151 case value v of
152 Object (Obj {flat, ...}) => flat := NotFlat
153 | _ => ()
154
155 fun isUnit v =
156 case v of
157 GroundV t => Type.isUnit t
158 | _ => false
159
160 fun objectC {args: t Prod.t, con: ObjectCon.t, originalType}
161 : computed =
162 let
163 (* Only may flatten objects with mutable fields, and where the field
164 * isn't unit. Flattening a unit field could lead to a problem
165 * because the containing object might be otherwise immutable, and
166 * hence the unit ref would lose its identity. We can fix this
167 * once objects have a notion of identity independent of mutability.
168 *)
169 val flat =
170 ref
171 (if Vector.exists (Prod.dest args, fn {elt, isMutable} =>
172 isMutable andalso not (isUnit elt))
173 andalso not (ObjectCon.isVector con)
174 then Unknown
175 else NotFlat)
176 in
177 ObjectC (Obj {args = args,
178 con = con,
179 finalComponents = ref NONE,
180 finalOffsets = ref NONE,
181 finalType = ref NONE,
182 flat = flat,
183 originalType = originalType})
184 end
185
186 val computed: computed -> t =
187 fn c => Complex (Equatable.new c)
188
189 fun weakC (a: t): computed =
190 WeakC {arg = a,
191 finalType = ref NONE,
192 originalType = Type.weak (originalType a)}
193
194 val weak = computed o weakC
195
196 fun tuple (args: t Prod.t, originalType: Type.t): t =
197 computed (objectC {args = args,
198 con = ObjectCon.Tuple,
199 originalType = originalType})
200
201 val tuple =
202 Trace.trace ("RefFlatten.Value.tuple", fn (p, _) => Prod.layout (p, layout),
203 layout)
204 tuple
205
206 val rec unify: t * t -> unit =
207 fn z =>
208 case z of
209 (GroundV t, GroundV t') =>
210 if Type.equals (t, t') then ()
211 else Error.bug "RefFlatten.Value.unify: unequal Grounds"
212 | (Complex e, Complex e') =>
213 Equatable.equate
214 (e, e', fn (c, c') =>
215 case (c, c') of
216 (ObjectC (Obj {args = a, flat = f, ...}),
217 ObjectC (Obj {args = a', flat = f', ...})) =>
218 let
219 val () = unifyProd (a, a')
220 val () =
221 case (!f, !f') of
222 (_, NotFlat) => f := NotFlat
223 | (NotFlat, _) => f' := NotFlat
224 | (Offset _, _) =>
225 Error.bug "RefFlatten.Value.unify: Offset"
226 | (_, Offset _) =>
227 Error.bug "RefFlatten.Value.unify: Offset"
228 | _ => ()
229 in
230 c
231 end
232 | (WeakC {arg = a, ...}, WeakC {arg = a', ...}) =>
233 (unify (a, a'); c)
234 | _ => Error.bug "RefFlatten.Value.unify: strange Complex")
235 | _ => Error.bug "RefFlatten.Value.unify: Complex with Ground"
236 and unifyProd =
237 fn (p, p') =>
238 Vector.foreach2
239 (Prod.dest p, Prod.dest p',
240 fn ({elt = e, ...}, {elt = e', ...}) => unify (e, e'))
241
242 fun coerce {from, to} = unify (from, to)
243
244 val coerce =
245 Trace.trace ("RefFlatten.Value.coerce",
246 fn {from, to} =>
247 Layout.record [("from", layout from),
248 ("to", layout to)],
249 Unit.layout)
250 coerce
251 end
252
253structure Size = TwoPointLattice (val bottom = "small"
254 val top = "large")
255
256structure VarInfo =
257 struct
258 datatype useStatus =
259 InTuple of {object: Object.t,
260 objectVar: Var.t,
261 offset: int}
262 | Unused
263
264 datatype t =
265 Flattenable of {components: Var.t vector,
266 defBlock: Label.t,
267 useStatus: useStatus ref}
268 | Unflattenable
269
270 fun layout (i: t): Layout.t =
271 let
272 open Layout
273 in
274 case i of
275 Flattenable {components, defBlock, useStatus} =>
276 seq [str "Flattenable ",
277 record [("components",
278 Vector.layout Var.layout components),
279 ("defBlock", Label.layout defBlock),
280 ("useStatus",
281 (case !useStatus of
282 InTuple {object, objectVar, offset} =>
283 seq [str "InTuple ",
284 record [("object",
285 Object.layout object),
286 ("objectVar",
287 Var.layout objectVar),
288 ("offset",
289 Int.layout offset)]]
290 | Unused => str "Unused"))]]
291 | Unflattenable => str "Unflattenable"
292 end
293 end
294
295fun transform2 (program as Program.T {datatypes, functions, globals, main}) =
296 let
297 val {get = conValue: Con.t -> Value.t option ref, ...} =
298 Property.get (Con.plist, Property.initFun (fn _ => ref NONE))
299 val conValue =
300 Trace.trace ("RefFlatten.conValue",
301 Con.layout, Ref.layout (Option.layout Value.layout))
302 conValue
303 datatype 'a make =
304 Const of 'a
305 | Make of unit -> 'a
306 fun needToMakeProd p =
307 Vector.exists (Prod.dest p, fn {elt, ...} =>
308 case elt of
309 Const _ => false
310 | Make _ => true)
311 fun makeProd p =
312 Prod.map (p, fn m =>
313 case m of
314 Const v => v
315 | Make f => f ())
316 val {get = makeTypeValue: Type.t -> Value.t make, ...} =
317 Property.get
318 (Type.plist,
319 Property.initRec
320 (fn (t, makeTypeValue) =>
321 let
322 fun const () = Const (Value.ground t)
323 datatype z = datatype Type.dest
324 in
325 case Type.dest t of
326 Object {args, con} =>
327 let
328 fun doit () =
329 let
330 val args = Prod.map (args, makeTypeValue)
331 val mayFlatten =
332 Vector.exists (Prod.dest args, #isMutable)
333 andalso not (ObjectCon.isVector con)
334 in
335 if mayFlatten orelse needToMakeProd args
336 then Make (fn () =>
337 Value.delay
338 (fn () =>
339 Value.objectC {args = makeProd args,
340 con = con,
341 originalType = t}))
342 else const ()
343 end
344 datatype z = datatype ObjectCon.t
345 in
346 case con of
347 Con c =>
348 Const
349 (Ref.memoize
350 (conValue c, fn () =>
351 case doit () of
352 Const v => v
353 | Make f =>
354 let
355 val v = f ()
356 (* Constructors can never be
357 * flattened into other objects.
358 *)
359 val () = Value.dontFlatten v
360 in
361 v
362 end))
363 | Tuple => doit ()
364 | Vector => doit ()
365 end
366 | Weak t =>
367 (case makeTypeValue t of
368 Const _ => const ()
369 | Make f =>
370 Make (fn () =>
371 Value.delay (fn () => Value.weakC (f ()))))
372 | _ => const ()
373 end))
374 fun typeValue (t: Type.t): Value.t =
375 case makeTypeValue t of
376 Const v => v
377 | Make f => f ()
378 val typeValue =
379 Trace.trace ("RefFlatten.typeValue", Type.layout, Value.layout) typeValue
380 val coerce = Value.coerce
381 fun inject {sum, variant = _} = typeValue (Type.datatypee sum)
382 fun object {args, con, resultType} =
383 let
384 val m = makeTypeValue resultType
385 in
386 case con of
387 NONE =>
388 (case m of
389 Const v => v
390 | Make _ => Value.tuple (args, resultType))
391 | SOME _ =>
392 (case m of
393 Const v =>
394 let
395 val () =
396 case Value.deObject v of
397 NONE => ()
398 | SOME (Obj {args = args', ...}) =>
399 Vector.foreach2
400 (Prod.dest args, Prod.dest args',
401 fn ({elt = a, ...}, {elt = a', ...}) =>
402 coerce {from = a, to = a'})
403 in
404 v
405 end
406 | _ => Error.bug "RefFlatten.object: strange con value")
407 end
408 val object =
409 Trace.trace
410 ("RefFlatten.object",
411 fn {args, con, ...} =>
412 Layout.record [("args", Prod.layout (args, Value.layout)),
413 ("con", Option.layout Con.layout con)],
414 Value.layout)
415 object
416 val deWeak: Value.t -> Value.t =
417 fn v =>
418 case Value.value v of
419 Value.Ground t =>
420 typeValue (case Type.dest t of
421 Type.Weak t => t
422 | _ => Error.bug "RefFlatten.deWeak")
423 | Value.Weak {arg, ...} => arg
424 | _ => Error.bug "RefFlatten.deWeak"
425 fun primApp {args, prim, resultVar = _, resultType} =
426 let
427 fun weak v =
428 case makeTypeValue resultType of
429 Const v => v
430 | Make _ => Value.weak v
431 fun arg i = Vector.sub (args, i)
432 fun result () = typeValue resultType
433 datatype z = datatype Prim.Name.t
434 fun dontFlatten () =
435 (Vector.foreach (args, Value.dontFlatten)
436 ; result ())
437 fun equal () =
438 (Value.unify (arg 0, arg 1)
439 ; result ())
440 in
441 case Prim.name prim of
442 Array_toArray =>
443 let
444 val res = result ()
445 datatype z = datatype Value.value
446 val () =
447 case (Value.value (arg 0), Value.value res) of
448 (Ground _, Ground _) => ()
449 | (Object (Obj {args = a, ...}),
450 Object (Obj {args = a', ...})) =>
451 Vector.foreach2
452 (Prod.dest a, Prod.dest a',
453 fn ({elt = v, ...}, {elt = v', ...}) =>
454 Value.unify (v, v'))
455 | _ => Error.bug "RefFlatten.primApp: Array_toArray"
456 in
457 res
458 end
459 | Array_toVector =>
460 let
461 val res = result ()
462 datatype z = datatype Value.value
463 val () =
464 case (Value.value (arg 0), Value.value res) of
465 (Ground _, Ground _) => ()
466 | (Object (Obj {args = a, ...}),
467 Object (Obj {args = a', ...})) =>
468 Vector.foreach2
469 (Prod.dest a, Prod.dest a',
470 fn ({elt = v, ...}, {elt = v', ...}) =>
471 Value.unify (v, v'))
472 | _ => Error.bug "RefFlatten.primApp: Array_toVector"
473 in
474 res
475 end
476 | FFI _ =>
477 (* Some imports, like Real64.modf, take ref cells that can not
478 * be flattened.
479 *)
480 dontFlatten ()
481 | MLton_eq => equal ()
482 | MLton_equal => equal ()
483 | MLton_size => dontFlatten ()
484 | MLton_share => dontFlatten ()
485 | Weak_get => deWeak (arg 0)
486 | Weak_new =>
487 let val a = arg 0
488 in (Value.dontFlatten a; weak a)
489 end
490 | _ => result ()
491 end
492 fun base b =
493 case b of
494 Base.Object obj => obj
495 | Base.VectorSub {vector, ...} => vector
496 fun select {base, offset} =
497 let
498 datatype z = datatype Value.value
499 in
500 case Value.value base of
501 Ground t =>
502 (case Type.dest t of
503 Type.Object {args, ...} =>
504 typeValue (Prod.elt (args, offset))
505 | _ => Error.bug "RefFlatten.select: Ground")
506 | Object ob => Object.select (ob, offset)
507 | _ => Error.bug "RefFlatten.select"
508 end
509 fun update {base, offset, value} =
510 (coerce {from = value,
511 to = select {base = base, offset = offset}}
512 (* Don't flatten the component of the update,
513 * else sharing will be broken.
514 *)
515 ; Value.dontFlatten value)
516 fun const c = typeValue (Type.ofConst c)
517 val {func, value = varValue, ...} =
518 analyze {base = base,
519 coerce = coerce,
520 const = const,
521 filter = fn _ => (),
522 filterWord = fn _ => (),
523 fromType = typeValue,
524 inject = inject,
525 layout = Value.layout,
526 object = object,
527 primApp = primApp,
528 program = program,
529 select = fn {base, offset, ...} => select {base = base,
530 offset = offset},
531 update = update,
532 useFromTypeOnBinds = false}
533 val varObject = Value.deObject o varValue
534 (* Mark a variable as Flattenable if all its uses are contained in a single
535 * basic block, there is a single use in an object construction, and
536 * all other uses follow the object construction.
537 *
538 * ...
539 * r: (t ref) = (t)
540 * ... <no uses of r> ...
541 * x: (... * (t ref) * ...) = (..., r, ...)
542 * ... <other assignments to r> ...
543 *
544 *)
545 datatype z = datatype VarInfo.t
546 datatype z = datatype VarInfo.useStatus
547 val {get = varInfo: Var.t -> VarInfo.t ref, ...} =
548 Property.get (Var.plist,
549 Property.initFun (fn _ => ref VarInfo.Unflattenable))
550 val varInfo =
551 Trace.trace ("RefFlatten.varInfo",
552 Var.layout, Ref.layout VarInfo.layout)
553 varInfo
554 fun use x = varInfo x := Unflattenable
555 val use = Trace.trace ("RefFlatten.use", Var.layout, Unit.layout) use
556 fun uses xs = Vector.foreach (xs, use)
557 fun loopStatement (s: Statement.t, current: Label.t): unit =
558 case s of
559 Bind {exp = Exp.Object {args, ...}, var, ...} =>
560 (case var of
561 NONE => uses args
562 | SOME var =>
563 case Value.deObject (varValue var) of
564 NONE => uses args
565 | SOME object =>
566 let
567 val () =
568 varInfo var
569 := Flattenable {components = args,
570 defBlock = current,
571 useStatus = ref Unused}
572 in
573 Vector.foreachi
574 (args, fn (offset, x) =>
575 let
576 val r = varInfo x
577 in
578 case !r of
579 Flattenable {defBlock, useStatus, ...} =>
580 (if Label.equals (current, defBlock)
581 andalso (case !useStatus of
582 InTuple _ => false
583 | Unused => true)
584 then (useStatus
585 := (InTuple
586 {object = object,
587 objectVar = var,
588 offset = offset}))
589 else r := Unflattenable)
590 | Unflattenable => ()
591 end)
592 end)
593 | Statement.Update {base, value, ...} =>
594 (use value
595 ; (case base of
596 Base.Object r =>
597 let
598 val i = varInfo r
599 in
600 case ! i of
601 Flattenable {defBlock, useStatus, ...} =>
602 if Label.equals (current, defBlock)
603 andalso (case !useStatus of
604 InTuple _ => true
605 | Unused => false)
606 then ()
607 else i := Unflattenable
608 | Unflattenable => ()
609 end
610 | Base.VectorSub _ => ()))
611 | _ => Statement.foreachUse (s, use)
612 val loopStatement =
613 Trace.trace2
614 ("RefFlatten.loopStatement", Statement.layout, Label.layout,
615 Unit.layout)
616 loopStatement
617 fun loopStatements (ss, label) =
618 Vector.foreach (ss, fn s => loopStatement (s, label))
619 fun loopTransfer t = Transfer.foreachVar (t, use)
620 val globalLabel = Label.newNoname ()
621 val () = loopStatements (globals, globalLabel)
622 val () =
623 List.foreach
624 (functions, fn f =>
625 Function.dfs
626 (f, fn Block.T {label, statements, transfer, ...} =>
627 (loopStatements (statements, label)
628 ; loopTransfer transfer
629 ; fn () => ())))
630 fun foreachObject (f): unit =
631 let
632 fun loopStatement s =
633 case s of
634 Bind {exp = Exp.Object {args, ...}, var, ...} =>
635 Option.app
636 (var, fn var =>
637 case Value.value (varValue var) of
638 Value.Ground _ => ()
639 | Value.Object obj => f (var, args, obj)
640 | _ =>
641 Error.bug
642 "RefFlatten.foreachObject: Object with strange value")
643 | _ => ()
644 val () = Vector.foreach (globals, loopStatement)
645 val () =
646 List.foreach
647 (functions, fn f =>
648 let
649 val {blocks, ...} = Function.dest f
650 in
651 Vector.foreach
652 (blocks, fn Block.T {statements, ...} =>
653 Vector.foreach (statements, loopStatement))
654 end)
655 in
656 ()
657 end
658 (* Try to flatten each ref. *)
659 val () =
660 foreachObject
661 (fn (var, _, Obj {flat, ...}) =>
662 let
663 datatype z = datatype Flat.t
664 fun notFlat () = flat := NotFlat
665 val () =
666 case ! (varInfo var) of
667 Flattenable {useStatus, ...} =>
668 (case !useStatus of
669 InTuple {object = obj', offset = i', ...} =>
670 (case ! flat of
671 NotFlat => ()
672 | Offset {object = obj'', offset = i''} =>
673 if i' = i'' andalso Object.equals (obj', obj'')
674 then ()
675 else notFlat ()
676 | Unknown => flat := Offset {object = obj',
677 offset = i'})
678 | Unused => notFlat ())
679 | Unflattenable => notFlat ()
680 in
681 ()
682 end)
683 val () =
684 foreachObject
685 (fn (_, args, obj) =>
686 let
687 datatype z = datatype Flat.t
688 (* Check that all arguments that are represented by flattening them
689 * into the object are available as an explicit allocation.
690 *)
691 val () =
692 Vector.foreach
693 (args, fn a =>
694 case Value.deFlat {inner = varValue a, outer = obj} of
695 NONE => ()
696 | SOME (Obj {flat, ...}) =>
697 case ! (varInfo a) of
698 Flattenable _ => ()
699 | Unflattenable =>
700 flat := NotFlat)
701 in
702 ()
703 end)
704 (*
705 * The following code disables flattening of some refs to ensure
706 * space safety. Flattening a ref into an object that has
707 * another component that contains a value of unbounded size (a
708 * large object) could keep the large object alive beyond where
709 * it should be. So, we first use a simple fixed point to
710 * figure out which types have values of unbounded size. Then,
711 * for each reference to a mutable object, if we are trying to
712 * flatten it into an object that has another component with a
713 * large value and the container is not live in this block (we
714 * approximate liveness), then don't allow the flattening to
715 * happen.
716 *
717 * Vectors may be objects of unbounded size.
718 * Weak pointers may not be objects of unbounded size; weak
719 * pointers do not keep pointed-to object live.
720 * Instances of recursive datatypes may be objects of unbounded
721 * size.
722 *)
723 val {get = tyconSize: Tycon.t -> Size.t, ...} =
724 Property.get (Tycon.plist, Property.initFun (fn _ => Size.new ()))
725 (* Force (mutually) recursive datatypes to top. *)
726 val {get = nodeTycon: unit Node.t -> Tycon.t,
727 set = setNodeTycon, ...} =
728 Property.getSetOnce
729 (Node.plist, Property.initRaise ("nodeTycon", Node.layout))
730 val {get = tyconNode: Tycon.t -> unit Node.t,
731 set = setTyconNode, ...} =
732 Property.getSetOnce
733 (Tycon.plist, Property.initRaise ("tyconNode", Tycon.layout))
734 val graph = Graph.new ()
735 val () =
736 Vector.foreach
737 (datatypes, fn Datatype.T {tycon, ...} =>
738 let
739 val node = Graph.newNode graph
740 val () = setTyconNode (tycon, node)
741 val () = setNodeTycon (node, tycon)
742 in
743 ()
744 end)
745 val () =
746 Vector.foreach
747 (datatypes, fn Datatype.T {cons, tycon} =>
748 let
749 val n = tyconNode tycon
750 datatype z = datatype Type.dest
751 val {get = dependsOn, destroy = destroyDependsOn} =
752 Property.destGet
753 (Type.plist,
754 Property.initRec
755 (fn (t, dependsOn) =>
756 case Type.dest t of
757 Datatype tc =>
758 (ignore o Graph.addEdge)
759 (graph, {from = n, to = tyconNode tc})
760 | Object {args, ...} =>
761 Prod.foreach (args, dependsOn)
762 | _ => ()))
763 val () = Vector.foreach (cons, fn {args, ...} =>
764 Prod.foreach (args, dependsOn))
765 val () = destroyDependsOn ()
766 in
767 ()
768 end)
769 val () =
770 List.foreach
771 (Graph.stronglyConnectedComponents graph, fn ns =>
772 let
773 fun doit () =
774 List.foreach
775 (ns, fn n =>
776 Size.makeTop (tyconSize (nodeTycon n)))
777 in
778 case ns of
779 [n] => if Node.hasEdge {from = n, to = n}
780 then doit ()
781 else ()
782 | _ => doit ()
783 end)
784 val {get = typeSize: Type.t -> Size.t, ...} =
785 Property.get (Type.plist,
786 Property.initRec
787 (fn (t, typeSize) =>
788 let
789 val s = Size.new ()
790 fun dependsOn (t: Type.t): unit =
791 Size.<= (typeSize t, s)
792 datatype z = datatype Type.dest
793 val () =
794 case Type.dest t of
795 CPointer => ()
796 | Datatype tc => Size.<= (tyconSize tc, s)
797 | IntInf => Size.makeTop s
798 | Object {args, con, ...} =>
799 if ObjectCon.isVector con
800 then Size.makeTop s
801 else Prod.foreach (args, dependsOn)
802 | Real _ => ()
803 | Thread => Size.makeTop s
804 | Weak _ => ()
805 | Word _ => ()
806 in
807 s
808 end))
809 val () =
810 Vector.foreach
811 (datatypes, fn Datatype.T {cons, tycon} =>
812 let
813 val s = tyconSize tycon
814 fun dependsOn (t: Type.t): unit = Size.<= (typeSize t, s)
815 val () = Vector.foreach (cons, fn {args, ...} =>
816 Prod.foreach (args, dependsOn))
817 in
818 ()
819 end)
820 fun typeIsLarge (t: Type.t): bool =
821 Size.isTop (typeSize t)
822 fun objectHasAnotherLarge (Object.Obj {args, ...}, {offset: int}) =
823 Vector.existsi (Prod.dest args, fn (i, {elt, ...}) =>
824 i <> offset
825 andalso typeIsLarge (Value.originalType elt))
826 val () =
827 List.foreach
828 (functions, fn f =>
829 let
830 val {blocks, ...} = Function.dest f
831 in
832 Vector.foreach
833 (blocks, fn Block.T {statements, transfer, ...} =>
834 let
835 fun containerIsLive (x: Var.t) =
836 Vector.exists
837 (statements, fn s =>
838 case s of
839 Bind {exp, var = SOME x', ...} =>
840 Var.equals (x, x')
841 andalso (case exp of
842 Exp.Select _ => true
843 | _ => false)
844 | _ => false)
845 fun use (x: Var.t) =
846 case Value.value (varValue x) of
847 Value.Object (Obj {flat, ...}) =>
848 (case !flat of
849 Flat.Offset {object, offset} =>
850 if objectHasAnotherLarge (object,
851 {offset = offset})
852 andalso not (containerIsLive x)
853 then flat := Flat.NotFlat
854 else ()
855 | _ => ())
856 | _ => ()
857 val () = Vector.foreach (statements, fn s =>
858 Statement.foreachUse (s, use))
859 val () = Transfer.foreachVar (transfer, use)
860 in
861 ()
862 end)
863 end)
864 (* Mark varInfo as Unflattenable if varValue is. This done after all the
865 * other parts of the analysis so that varInfo is consistent with the
866 * varValue.
867 *)
868 val () =
869 Program.foreachVar
870 (program, fn (x, _) =>
871 let
872 val r = varInfo x
873 in
874 case !r of
875 Flattenable _ =>
876 (case Value.deObject (varValue x) of
877 NONE => ()
878 | SOME (Obj {flat, ...}) =>
879 (case !flat of
880 Flat.NotFlat => r := Unflattenable
881 | _ => ()))
882 | Unflattenable => ()
883 end)
884 val () =
885 Control.diagnostics
886 (fn display =>
887 let
888 open Layout
889 val () =
890 Vector.foreach
891 (datatypes, fn Datatype.T {cons, ...} =>
892 Vector.foreach
893 (cons, fn {con, ...} =>
894 display (Option.layout Value.layout (! (conValue con)))))
895 val () =
896 Program.foreachVar
897 (program, fn (x, _) =>
898 display
899 (seq [Var.layout x, str " ",
900 record [("value", Value.layout (varValue x)),
901 ("varInfo", VarInfo.layout (! (varInfo x)))]]))
902 in
903 ()
904 end)
905 (* Conversion from values to types. *)
906 datatype z = datatype Finish.t
907 val traceValueType =
908 Trace.trace ("RefFlatten.valueType", Value.layout, Type.layout)
909 fun valueType arg: Type.t =
910 traceValueType
911 (fn (v: Value.t) =>
912 let
913 datatype z = datatype Value.value
914 in
915 case Value.value v of
916 Ground t => t
917 | Object z => objectType z
918 | Weak {arg, finalType, ...} =>
919 Ref.memoize (finalType, fn () => Type.weak (valueType arg))
920 end) arg
921 and objectFinalComponents (obj as Obj {args, finalComponents, ...}) =
922 Ref.memoize
923 (finalComponents, fn () =>
924 Prod.make
925 (Vector.fromList
926 (Vector.foldr
927 (Prod.dest args, [], fn ({elt, isMutable = i}, ac) =>
928 case Value.deFlat {inner = elt, outer = obj} of
929 NONE => {elt = valueType elt, isMutable = i} :: ac
930 | SOME z =>
931 Vector.foldr
932 (Prod.dest (objectFinalComponents z), ac,
933 fn ({elt, isMutable = i'}, ac) =>
934 {elt = elt, isMutable = i orelse i'} :: ac)))))
935 and objectFinalOffsets (z as Obj {args, finalOffsets, flat, ...}) =
936 Ref.memoize
937 (finalOffsets, fn () =>
938 let
939 val initial =
940 case ! flat of
941 Flat.Offset {object, offset} => objectOffset (object, offset)
942 | _ => 0
943 val (_, offsets) =
944 Vector.fold
945 (Prod.dest args, (initial, []), fn ({elt, ...}, (offset, ac)) =>
946 let
947 val width =
948 case Value.deFlat {inner = elt, outer = z} of
949 NONE => 1
950 | SOME z => Prod.length (objectFinalComponents z)
951 in
952 (offset + width, offset :: ac)
953 end)
954 in
955 Vector.fromListRev offsets
956 end)
957 and objectOffset (z: Object.t, offset: int): int =
958 Vector.sub (objectFinalOffsets z, offset)
959 and objectType (z as Obj {con, finalType, flat, ...}): Type.t =
960 Ref.memoize
961 (finalType, fn () =>
962 case ! flat of
963 Flat.Offset {object, ...} => objectType object
964 | _ => Type.object {args = objectFinalComponents z,
965 con = con})
966 (* Transform the program. *)
967 fun transformFormals (xts: (Var.t * Type.t) vector)
968 : (Var.t * Type.t) vector =
969 Vector.map (xts, fn (x, _) => (x, valueType (varValue x)))
970 val extraSelects: Statement.t list ref = ref []
971 fun flattenValues (object: Var.t,
972 obj as Obj {args, ...},
973 ac: Var.t list): Var.t list =
974 Vector.foldri
975 (Prod.dest args, ac, fn (i, {elt, ...}, ac) =>
976 case Value.deFlat {inner = elt, outer = obj} of
977 NONE =>
978 let
979 val var = Var.newNoname ()
980 val () =
981 List.push
982 (extraSelects,
983 Bind
984 {exp = Select {base = Base.Object object,
985 offset = objectOffset (obj, i)},
986 ty = valueType elt,
987 var = SOME var})
988 in
989 var :: ac
990 end
991 | SOME obj => flattenValues (object, obj, ac))
992 fun flattenArgs (xs: Var.t vector, outer: Object.t, ac): Var.t list =
993 Vector.foldr
994 (xs, ac, fn (x, ac) =>
995 let
996 val v = varValue x
997 in
998 case Value.deFlat {inner = v, outer = outer} of
999 NONE => x :: ac
1000 | SOME obj =>
1001 (case ! (varInfo x) of
1002 Flattenable {components, ...} =>
1003 flattenArgs (components, obj, ac)
1004 | Unflattenable => flattenValues (x, obj, ac))
1005 end)
1006 val flattenArgs =
1007 Trace.trace3 ("RefFlatten.flattenArgs",
1008 Vector.layout Var.layout,
1009 Object.layout,
1010 List.layout Var.layout,
1011 List.layout Var.layout)
1012 flattenArgs
1013 fun transformBind {exp, ty, var}: Statement.t vector =
1014 let
1015 fun make e =
1016 Vector.new1
1017 (Bind {exp = e,
1018 ty = (case var of
1019 NONE => ty
1020 | SOME var => valueType (varValue var)),
1021 var = var})
1022 fun none () = Vector.new0 ()
1023 in
1024 case exp of
1025 Exp.Object {args, con} =>
1026 (case var of
1027 NONE => none ()
1028 | SOME var =>
1029 (case varObject var of
1030 NONE => make exp
1031 | SOME (z as Obj {flat, ...}) =>
1032 case ! flat of
1033 Flat.Offset _ => none ()
1034 | _ =>
1035 let
1036 val args =
1037 Vector.fromList
1038 (flattenArgs (args, z, []))
1039 val extra = !extraSelects
1040 val () = extraSelects := []
1041 in
1042 Vector.concat
1043 [Vector.fromList extra,
1044 make (Exp.Object
1045 {args = args, con = con})]
1046 end))
1047 | PrimApp {args, prim} =>
1048 make (PrimApp {args = args, prim = prim})
1049 | Select {base, offset} =>
1050 (case var of
1051 NONE => none ()
1052 | SOME var =>
1053 (case base of
1054 Base.Object object =>
1055 (case varObject object of
1056 NONE => make exp
1057 | SOME obj =>
1058 make
1059 (if isSome (Value.deFlat
1060 {inner = varValue var,
1061 outer = obj})
1062 then Var object
1063 else (Select
1064 {base = base,
1065 offset = (objectOffset
1066 (obj, offset))})))
1067 | Base.VectorSub _ => make exp))
1068 | _ => make exp
1069 end
1070 fun transformStatement (s: Statement.t): Statement.t vector =
1071 case s of
1072 Bind b => transformBind b
1073 | Profile _ => Vector.new1 s
1074 | Update {base, offset, value} =>
1075 Vector.new1
1076 (case base of
1077 Base.Object object =>
1078 (case varObject object of
1079 NONE => s
1080 | SOME obj =>
1081 let
1082 val base =
1083 case ! (varInfo object) of
1084 Flattenable {useStatus, ...} =>
1085 (case ! useStatus of
1086 InTuple {objectVar, ...} =>
1087 Base.Object objectVar
1088 | _ => base)
1089 | Unflattenable => base
1090 in
1091 Update {base = base,
1092 offset = objectOffset (obj, offset),
1093 value = value}
1094 end)
1095 | Base.VectorSub _ => s)
1096 val transformStatement =
1097 Trace.trace ("RefFlatten.transformStatement",
1098 Statement.layout,
1099 Vector.layout Statement.layout)
1100 transformStatement
1101 fun transformStatements ss =
1102 Vector.concatV (Vector.map (ss, transformStatement))
1103 fun transformBlock (Block.T {args, label, statements, transfer}) =
1104 Block.T {args = transformFormals args,
1105 label = label,
1106 statements = transformStatements statements,
1107 transfer = transfer}
1108 fun valuesTypes vs = Vector.map (vs, valueType)
1109 val datatypes =
1110 Vector.map
1111 (datatypes, fn Datatype.T {cons, tycon} =>
1112 let
1113 val cons =
1114 Vector.map
1115 (cons, fn {con, args} =>
1116 let
1117 val args =
1118 case ! (conValue con) of
1119 NONE => args
1120 | SOME v =>
1121 case Type.dest (valueType v) of
1122 Type.Object {args, ...} => args
1123 | _ => Error.bug "RefFlatten.datatypes: strange con"
1124 in
1125 {args = args, con = con}
1126 end)
1127 in
1128 Datatype.T {cons = cons, tycon = tycon}
1129 end)
1130 fun transformFunction (f: Function.t): Function.t =
1131 let
1132 val {args, blocks, mayInline, name, start, ...} = Function.dest f
1133 val {raises, returns, ...} = func name
1134 val raises = Option.map (raises, valuesTypes)
1135 val returns = Option.map (returns, valuesTypes)
1136 in
1137 Function.new {args = transformFormals args,
1138 blocks = Vector.map (blocks, transformBlock),
1139 mayInline = mayInline,
1140 name = name,
1141 raises = raises,
1142 returns = returns,
1143 start = start}
1144 end
1145 val program =
1146 Program.T {datatypes = datatypes,
1147 functions = List.revMap (functions, transformFunction),
1148 globals = transformStatements globals,
1149 main = main}
1150 val () = Program.clear program
1151 in
1152 shrink program
1153 end
1154
1155end