Commit | Line | Data |
---|---|---|
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 | ||
9 | functor RefFlatten (S: SSA2_TRANSFORM_STRUCTS): SSA2_TRANSFORM = | |
10 | struct | |
11 | ||
12 | open S | |
13 | ||
14 | structure Graph = DirectedGraph | |
15 | structure Node = Graph.Node | |
16 | ||
17 | datatype z = datatype Exp.t | |
18 | datatype z = datatype Statement.t | |
19 | datatype z = datatype Transfer.t | |
20 | ||
21 | structure 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 | ||
37 | structure 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 | ||
109 | structure Flat = | |
110 | struct | |
111 | datatype t = datatype Value.flat | |
112 | end | |
113 | ||
114 | structure 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 | ||
127 | datatype z = datatype Object.t | |
128 | ||
129 | structure 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 | ||
253 | structure Size = TwoPointLattice (val bottom = "small" | |
254 | val top = "large") | |
255 | ||
256 | structure 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 | ||
295 | fun 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 | ||
1155 | end |