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 RefFlatten (S: SSA2_TRANSFORM_STRUCTS): SSA2_TRANSFORM =
14 structure Graph = DirectedGraph
15 structure Node = Graph.Node
17 datatype z = datatype Exp.t
18 datatype z = datatype Statement.t
19 datatype z = datatype Transfer.t
23 datatype t = T of {flat: Type.t Prod.t option,
26 val _: t -> Layout.t =
32 Option.layout (fn p => Prod.layout (p, Type.layout)) flat),
33 ("ty", Type.layout ty)]
41 | Complex of computed Equatable.t
45 finalType: Type.t option ref,
48 Obj of {args: t Prod.t,
50 finalComponents: Type.t Prod.t option ref,
51 finalOffsets: int vector option ref,
52 finalType: Type.t option ref,
57 | Offset of {object: object,
61 fun delay (f: unit -> computed): t = Complex (Equatable.delay f)
67 finalType: Type.t option ref,
70 val value: t -> value =
71 fn GroundV t => Ground t
73 case Equatable.value e of
74 ObjectC obj => Object obj
80 fun layout v: Layout.t =
82 GroundV t => Type.layout t
86 fn ObjectC ob => layoutObject ob
87 | WeakC {arg, ...} => seq [str "Weak ", layout arg])
88 and layoutFlat (f: flat): Layout.t =
90 NotFlat => str "NotFlat"
91 | Offset {offset, ...} =>
93 record [("offset", Int.layout offset)]]
94 | Unknown => str "Unknown"
95 and layoutObject (Obj {args, con, flat, ...}) =
97 record [("args", Prod.layout (args, layout)),
98 ("con", ObjectCon.layout con),
99 ("flat", layoutFlat (! flat))]]
102 fun originalType (v: t) =
105 | Object (Obj {originalType = t, ...}) => t
106 | Weak {originalType = t, ...} => t
111 datatype t = datatype Value.flat
116 datatype t = datatype Value.object
118 val layout = Value.layoutObject
120 fun equals (Obj {flat = f, ...}, Obj {flat = f', ...}) = f = f'
122 val select: t * int -> Value.t =
123 fn (Obj {args, ...}, offset) =>
124 Prod.elt (args, offset)
127 datatype z = datatype Object.t
135 val deObject: t -> Object.t option =
141 fun deFlat {inner: t, outer: Object.t}: Object.t option =
143 Object (z as Obj {flat, ...}) =>
145 Flat.Offset {object, ...} =>
146 if Object.equals (object, outer) then SOME z else NONE
150 fun dontFlatten (v: t): unit =
152 Object (Obj {flat, ...}) => flat := NotFlat
157 GroundV t => Type.isUnit t
160 fun objectC {args: t Prod.t, con: ObjectCon.t, originalType}
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.
171 (if Vector.exists (Prod.dest args, fn {elt, isMutable} =>
172 isMutable andalso not (isUnit elt))
173 andalso not (ObjectCon.isVector con)
177 ObjectC (Obj {args = args,
179 finalComponents = ref NONE,
180 finalOffsets = ref NONE,
181 finalType = ref NONE,
183 originalType = originalType})
186 val computed: computed -> t =
187 fn c => Complex (Equatable.new c)
189 fun weakC (a: t): computed =
191 finalType = ref NONE,
192 originalType = Type.weak (originalType a)}
194 val weak = computed o weakC
196 fun tuple (args: t Prod.t, originalType: Type.t): t =
197 computed (objectC {args = args,
198 con = ObjectCon.Tuple,
199 originalType = originalType})
202 Trace.trace ("RefFlatten.Value.tuple", fn (p, _) => Prod.layout (p, layout),
206 val rec unify: t * t -> unit =
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') =>
214 (e, e', fn (c, c') =>
216 (ObjectC (Obj {args = a, flat = f, ...}),
217 ObjectC (Obj {args = a', flat = f', ...})) =>
219 val () = unifyProd (a, a')
222 (_, NotFlat) => f := NotFlat
223 | (NotFlat, _) => f' := NotFlat
225 Error.bug "RefFlatten.Value.unify: Offset"
227 Error.bug "RefFlatten.Value.unify: Offset"
232 | (WeakC {arg = a, ...}, WeakC {arg = a', ...}) =>
234 | _ => Error.bug "RefFlatten.Value.unify: strange Complex")
235 | _ => Error.bug "RefFlatten.Value.unify: Complex with Ground"
239 (Prod.dest p, Prod.dest p',
240 fn ({elt = e, ...}, {elt = e', ...}) => unify (e, e'))
242 fun coerce {from, to} = unify (from, to)
245 Trace.trace ("RefFlatten.Value.coerce",
247 Layout.record [("from", layout from),
253 structure Size = TwoPointLattice (val bottom = "small"
259 InTuple of {object: Object.t,
265 Flattenable of {components: Var.t vector,
267 useStatus: useStatus ref}
270 fun layout (i: t): Layout.t =
275 Flattenable {components, defBlock, useStatus} =>
276 seq [str "Flattenable ",
277 record [("components",
278 Vector.layout Var.layout components),
279 ("defBlock", Label.layout defBlock),
282 InTuple {object, objectVar, offset} =>
285 Object.layout object),
287 Var.layout objectVar),
290 | Unused => str "Unused"))]]
291 | Unflattenable => str "Unflattenable"
295 fun transform2 (program as Program.T {datatypes, functions, globals, main}) =
297 val {get = conValue: Con.t -> Value.t option ref, ...} =
298 Property.get (Con.plist, Property.initFun (fn _ => ref NONE))
300 Trace.trace ("RefFlatten.conValue",
301 Con.layout, Ref.layout (Option.layout Value.layout))
306 fun needToMakeProd p =
307 Vector.exists (Prod.dest p, fn {elt, ...} =>
316 val {get = makeTypeValue: Type.t -> Value.t make, ...} =
320 (fn (t, makeTypeValue) =>
322 fun const () = Const (Value.ground t)
323 datatype z = datatype Type.dest
326 Object {args, con} =>
330 val args = Prod.map (args, makeTypeValue)
332 Vector.exists (Prod.dest args, #isMutable)
333 andalso not (ObjectCon.isVector con)
335 if mayFlatten orelse needToMakeProd args
339 Value.objectC {args = makeProd args,
344 datatype z = datatype ObjectCon.t
350 (conValue c, fn () =>
356 (* Constructors can never be
357 * flattened into other objects.
359 val () = Value.dontFlatten v
367 (case makeTypeValue t of
371 Value.delay (fn () => Value.weakC (f ()))))
374 fun typeValue (t: Type.t): Value.t =
375 case makeTypeValue t of
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} =
384 val m = makeTypeValue resultType
390 | Make _ => Value.tuple (args, resultType))
396 case Value.deObject v of
398 | SOME (Obj {args = args', ...}) =>
400 (Prod.dest args, Prod.dest args',
401 fn ({elt = a, ...}, {elt = a', ...}) =>
402 coerce {from = a, to = a'})
406 | _ => Error.bug "RefFlatten.object: strange con value")
410 ("RefFlatten.object",
411 fn {args, con, ...} =>
412 Layout.record [("args", Prod.layout (args, Value.layout)),
413 ("con", Option.layout Con.layout con)],
416 val deWeak: Value.t -> Value.t =
418 case Value.value v of
420 typeValue (case Type.dest t of
422 | _ => Error.bug "RefFlatten.deWeak")
423 | Value.Weak {arg, ...} => arg
424 | _ => Error.bug "RefFlatten.deWeak"
425 fun primApp {args, prim, resultVar = _, resultType} =
428 case makeTypeValue resultType of
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
435 (Vector.foreach (args, Value.dontFlatten)
438 (Value.unify (arg 0, arg 1)
441 case Prim.name prim of
445 datatype z = datatype Value.value
447 case (Value.value (arg 0), Value.value res) of
448 (Ground _, Ground _) => ()
449 | (Object (Obj {args = a, ...}),
450 Object (Obj {args = a', ...})) =>
452 (Prod.dest a, Prod.dest a',
453 fn ({elt = v, ...}, {elt = v', ...}) =>
455 | _ => Error.bug "RefFlatten.primApp: Array_toArray"
462 datatype z = datatype Value.value
464 case (Value.value (arg 0), Value.value res) of
465 (Ground _, Ground _) => ()
466 | (Object (Obj {args = a, ...}),
467 Object (Obj {args = a', ...})) =>
469 (Prod.dest a, Prod.dest a',
470 fn ({elt = v, ...}, {elt = v', ...}) =>
472 | _ => Error.bug "RefFlatten.primApp: Array_toVector"
477 (* Some imports, like Real64.modf, take ref cells that can not
481 | MLton_eq => equal ()
482 | MLton_equal => equal ()
483 | MLton_size => dontFlatten ()
484 | MLton_share => dontFlatten ()
485 | Weak_get => deWeak (arg 0)
488 in (Value.dontFlatten a; weak a)
494 Base.Object obj => obj
495 | Base.VectorSub {vector, ...} => vector
496 fun select {base, offset} =
498 datatype z = datatype Value.value
500 case Value.value base 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"
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.
515 ; Value.dontFlatten value)
516 fun const c = typeValue (Type.ofConst c)
517 val {func, value = varValue, ...} =
518 analyze {base = base,
522 filterWord = fn _ => (),
523 fromType = typeValue,
525 layout = Value.layout,
529 select = fn {base, offset, ...} => select {base = base,
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.
540 * ... <no uses of r> ...
541 * x: (... * (t ref) * ...) = (..., r, ...)
542 * ... <other assignments to r> ...
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))
551 Trace.trace ("RefFlatten.varInfo",
552 Var.layout, Ref.layout VarInfo.layout)
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 =
559 Bind {exp = Exp.Object {args, ...}, var, ...} =>
563 case Value.deObject (varValue var) of
569 := Flattenable {components = args,
571 useStatus = ref Unused}
574 (args, fn (offset, x) =>
579 Flattenable {defBlock, useStatus, ...} =>
580 (if Label.equals (current, defBlock)
581 andalso (case !useStatus of
589 else r := Unflattenable)
590 | Unflattenable => ()
593 | Statement.Update {base, value, ...} =>
601 Flattenable {defBlock, useStatus, ...} =>
602 if Label.equals (current, defBlock)
603 andalso (case !useStatus of
607 else i := Unflattenable
608 | Unflattenable => ()
610 | Base.VectorSub _ => ()))
611 | _ => Statement.foreachUse (s, use)
614 ("RefFlatten.loopStatement", Statement.layout, Label.layout,
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)
626 (f, fn Block.T {label, statements, transfer, ...} =>
627 (loopStatements (statements, label)
628 ; loopTransfer transfer
630 fun foreachObject (f): unit =
632 fun loopStatement s =
634 Bind {exp = Exp.Object {args, ...}, var, ...} =>
637 case Value.value (varValue var) of
639 | Value.Object obj => f (var, args, obj)
642 "RefFlatten.foreachObject: Object with strange value")
644 val () = Vector.foreach (globals, loopStatement)
649 val {blocks, ...} = Function.dest f
652 (blocks, fn Block.T {statements, ...} =>
653 Vector.foreach (statements, loopStatement))
658 (* Try to flatten each ref. *)
661 (fn (var, _, Obj {flat, ...}) =>
663 datatype z = datatype Flat.t
664 fun notFlat () = flat := NotFlat
666 case ! (varInfo var) of
667 Flattenable {useStatus, ...} =>
669 InTuple {object = obj', offset = i', ...} =>
672 | Offset {object = obj'', offset = i''} =>
673 if i' = i'' andalso Object.equals (obj', obj'')
676 | Unknown => flat := Offset {object = obj',
678 | Unused => notFlat ())
679 | Unflattenable => notFlat ()
685 (fn (_, args, obj) =>
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.
694 case Value.deFlat {inner = varValue a, outer = obj} of
696 | SOME (Obj {flat, ...}) =>
697 case ! (varInfo a) of
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
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
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, ...} =
729 (Node.plist, Property.initRaise ("nodeTycon", Node.layout))
730 val {get = tyconNode: Tycon.t -> unit Node.t,
731 set = setTyconNode, ...} =
733 (Tycon.plist, Property.initRaise ("tyconNode", Tycon.layout))
734 val graph = Graph.new ()
737 (datatypes, fn Datatype.T {tycon, ...} =>
739 val node = Graph.newNode graph
740 val () = setTyconNode (tycon, node)
741 val () = setNodeTycon (node, tycon)
747 (datatypes, fn Datatype.T {cons, tycon} =>
749 val n = tyconNode tycon
750 datatype z = datatype Type.dest
751 val {get = dependsOn, destroy = destroyDependsOn} =
755 (fn (t, dependsOn) =>
758 (ignore o Graph.addEdge)
759 (graph, {from = n, to = tyconNode tc})
760 | Object {args, ...} =>
761 Prod.foreach (args, dependsOn)
763 val () = Vector.foreach (cons, fn {args, ...} =>
764 Prod.foreach (args, dependsOn))
765 val () = destroyDependsOn ()
771 (Graph.stronglyConnectedComponents graph, fn ns =>
776 Size.makeTop (tyconSize (nodeTycon n)))
779 [n] => if Node.hasEdge {from = n, to = n}
784 val {get = typeSize: Type.t -> Size.t, ...} =
785 Property.get (Type.plist,
790 fun dependsOn (t: Type.t): unit =
791 Size.<= (typeSize t, s)
792 datatype z = datatype Type.dest
796 | Datatype tc => Size.<= (tyconSize tc, s)
797 | IntInf => Size.makeTop s
798 | Object {args, con, ...} =>
799 if ObjectCon.isVector con
801 else Prod.foreach (args, dependsOn)
803 | Thread => Size.makeTop s
811 (datatypes, fn Datatype.T {cons, tycon} =>
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))
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, ...}) =>
825 andalso typeIsLarge (Value.originalType elt))
830 val {blocks, ...} = Function.dest f
833 (blocks, fn Block.T {statements, transfer, ...} =>
835 fun containerIsLive (x: Var.t) =
839 Bind {exp, var = SOME x', ...} =>
846 case Value.value (varValue x) of
847 Value.Object (Obj {flat, ...}) =>
849 Flat.Offset {object, offset} =>
850 if objectHasAnotherLarge (object,
852 andalso not (containerIsLive x)
853 then flat := Flat.NotFlat
857 val () = Vector.foreach (statements, fn s =>
858 Statement.foreachUse (s, use))
859 val () = Transfer.foreachVar (transfer, use)
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
870 (program, fn (x, _) =>
876 (case Value.deObject (varValue x) of
878 | SOME (Obj {flat, ...}) =>
880 Flat.NotFlat => r := Unflattenable
882 | Unflattenable => ()
891 (datatypes, fn Datatype.T {cons, ...} =>
893 (cons, fn {con, ...} =>
894 display (Option.layout Value.layout (! (conValue con)))))
897 (program, fn (x, _) =>
899 (seq [Var.layout x, str " ",
900 record [("value", Value.layout (varValue x)),
901 ("varInfo", VarInfo.layout (! (varInfo x)))]]))
905 (* Conversion from values to types. *)
906 datatype z = datatype Finish.t
908 Trace.trace ("RefFlatten.valueType", Value.layout, Type.layout)
909 fun valueType arg: Type.t =
913 datatype z = datatype Value.value
915 case Value.value v of
917 | Object z => objectType z
918 | Weak {arg, finalType, ...} =>
919 Ref.memoize (finalType, fn () => Type.weak (valueType arg))
921 and objectFinalComponents (obj as Obj {args, finalComponents, ...}) =
923 (finalComponents, fn () =>
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
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, ...}) =
937 (finalOffsets, fn () =>
941 Flat.Offset {object, offset} => objectOffset (object, offset)
945 (Prod.dest args, (initial, []), fn ({elt, ...}, (offset, ac)) =>
948 case Value.deFlat {inner = elt, outer = z} of
950 | SOME z => Prod.length (objectFinalComponents z)
952 (offset + width, offset :: ac)
955 Vector.fromListRev offsets
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 =
963 Flat.Offset {object, ...} => objectType object
964 | _ => Type.object {args = objectFinalComponents z,
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 =
975 (Prod.dest args, ac, fn (i, {elt, ...}, ac) =>
976 case Value.deFlat {inner = elt, outer = obj} of
979 val var = Var.newNoname ()
984 {exp = Select {base = Base.Object object,
985 offset = objectOffset (obj, i)},
991 | SOME obj => flattenValues (object, obj, ac))
992 fun flattenArgs (xs: Var.t vector, outer: Object.t, ac): Var.t list =
994 (xs, ac, fn (x, ac) =>
998 case Value.deFlat {inner = v, outer = outer} of
1001 (case ! (varInfo x) of
1002 Flattenable {components, ...} =>
1003 flattenArgs (components, obj, ac)
1004 | Unflattenable => flattenValues (x, obj, ac))
1007 Trace.trace3 ("RefFlatten.flattenArgs",
1008 Vector.layout Var.layout,
1010 List.layout Var.layout,
1011 List.layout Var.layout)
1013 fun transformBind {exp, ty, var}: Statement.t vector =
1020 | SOME var => valueType (varValue var)),
1022 fun none () = Vector.new0 ()
1025 Exp.Object {args, con} =>
1029 (case varObject var of
1031 | SOME (z as Obj {flat, ...}) =>
1033 Flat.Offset _ => none ()
1038 (flattenArgs (args, z, []))
1039 val extra = !extraSelects
1040 val () = extraSelects := []
1043 [Vector.fromList extra,
1045 {args = args, con = con})]
1047 | PrimApp {args, prim} =>
1048 make (PrimApp {args = args, prim = prim})
1049 | Select {base, offset} =>
1054 Base.Object object =>
1055 (case varObject object of
1059 (if isSome (Value.deFlat
1060 {inner = varValue var,
1065 offset = (objectOffset
1067 | Base.VectorSub _ => make exp))
1070 fun transformStatement (s: Statement.t): Statement.t vector =
1072 Bind b => transformBind b
1073 | Profile _ => Vector.new1 s
1074 | Update {base, offset, value} =>
1077 Base.Object object =>
1078 (case varObject object of
1083 case ! (varInfo object) of
1084 Flattenable {useStatus, ...} =>
1085 (case ! useStatus of
1086 InTuple {objectVar, ...} =>
1087 Base.Object objectVar
1089 | Unflattenable => base
1091 Update {base = base,
1092 offset = objectOffset (obj, offset),
1095 | Base.VectorSub _ => s)
1096 val transformStatement =
1097 Trace.trace ("RefFlatten.transformStatement",
1099 Vector.layout Statement.layout)
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,
1106 statements = transformStatements statements,
1107 transfer = transfer}
1108 fun valuesTypes vs = Vector.map (vs, valueType)
1111 (datatypes, fn Datatype.T {cons, tycon} =>
1115 (cons, fn {con, args} =>
1118 case ! (conValue con) of
1121 case Type.dest (valueType v) of
1122 Type.Object {args, ...} => args
1123 | _ => Error.bug "RefFlatten.datatypes: strange con"
1125 {args = args, con = con}
1128 Datatype.T {cons = cons, tycon = tycon}
1130 fun transformFunction (f: Function.t): Function.t =
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)
1137 Function.new {args = transformFormals args,
1138 blocks = Vector.map (blocks, transformBlock),
1139 mayInline = mayInline,
1146 Program.T {datatypes = datatypes,
1147 functions = List.revMap (functions, transformFunction),
1148 globals = transformStatements globals,
1150 val () = Program.clear program