1 (* Copyright (C) 2009,2016-2017 Matthew Fluet.
2 * Copyright (C) 1999-2008 Henry Cejtin, Matthew Fluet, Suresh
3 * Jagannathan, and Stephen Weeks.
4 * Copyright (C) 1997-2000 NEC Research Institute.
6 * MLton is released under a BSD-style license.
7 * See the file MLton-LICENSE for details.
10 functor Rssa (S: RSSA_STRUCTS): RSSA =
18 structure ApplyArg = ApplyArg
19 structure ApplyResult = ApplyResult
24 structure CFunction = CFunction
25 structure GCField = GCField
28 fun constrain (ty: Type.t): Layout.t =
33 then seq [str ": ", Type.layout ty]
40 ArrayOffset of {base: t,
52 | ObjptrTycon of ObjptrTycon.t
53 | Runtime of GCField.t
57 val null = Const Const.null
59 val word = Const o Const.word
61 fun zero s = word (WordX.fromIntInf (0, s))
64 word (WordX.fromIntInf (if b then 1 else 0, WordSize.bool))
67 fn ArrayOffset {ty, ...} => ty
71 datatype z = datatype Const.t
74 IntInf _ => Type.intInf ()
75 | Null => Type.cpointer ()
76 | Real r => Type.real (RealX.size r)
77 | Word w => Type.ofWordX w
78 | WordVector v => Type.ofWordXVector v
80 | EnsuresBytesFree => Type.csize ()
81 | GCState => Type.gcState ()
82 | Offset {ty, ...} => ty
83 | ObjptrTycon _ => Type.objptrHeader ()
84 | Runtime z => Type.ofGCField z
87 fun layout (z: t): Layout.t =
92 ArrayOffset {base, index, offset, scale, ty} =>
93 seq [str (concat ["X", Type.name ty, " "]),
94 tuple [layout base, layout index, Scale.layout scale,
97 seq [str "Cast ", tuple [layout z, Type.layout ty]]
98 | Const c => seq [Const.layout c, constrain (ty z)]
99 | EnsuresBytesFree => str "<EnsuresBytesFree>"
100 | GCState => str "<GCState>"
101 | Offset {base, offset, ty} =>
102 seq [str (concat ["O", Type.name ty, " "]),
103 tuple [layout base, Bytes.layout offset],
105 | ObjptrTycon opt => ObjptrTycon.layout opt
106 | Runtime r => GCField.layout r
107 | Var {var, ...} => Var.layout var
110 fun cast (z: t, t: Type.t): t =
111 if Type.equals (t, ty z)
115 val cast = Trace.trace2 ("Rssa.Operand.cast", layout, Type.layout, layout) cast
118 fn ArrayOffset _ => true
119 | Cast (z, _) => isLocation z
125 fun 'a foldVars (z: t, a: 'a, f: Var.t * 'a -> 'a): 'a =
127 ArrayOffset {base, index, ...} =>
128 foldVars (index, foldVars (base, a, f), f)
129 | Cast (z, _) => foldVars (z, a, f)
130 | Offset {base, ...} => foldVars (base, a, f)
131 | Var {var, ...} => f (var, a)
134 fun replaceVar (z: t, f: Var.t -> t): t =
138 ArrayOffset {base, index, offset, scale, ty} =>
139 ArrayOffset {base = loop base,
144 | Cast (t, ty) => Cast (loop t, ty)
145 | Offset {base, offset, ty} =>
146 Offset {base = loop base,
149 | Var {var, ...} => f var
160 structure S = Switch (open S
161 structure Type = Type
162 structure Use = Operand)
167 fun replaceVar (T {cases, default, size, test}, f) =
171 test = Operand.replaceVar (test, f)}
174 structure Statement =
177 Bind of {dst: Var.t * Type.t,
180 | Move of {dst: Operand.t,
182 | Object of {dst: Var.t * Type.t,
185 | PrimApp of {args: Operand.t vector,
186 dst: (Var.t * Type.t) option,
188 | Profile of ProfileExp.t
189 | ProfileLabel of ProfileLabel.t
192 | SetHandler of Label.t
195 fun 'a foldDefUse (s, a: 'a, {def: Var.t * Type.t * 'a -> 'a,
196 use: Var.t * 'a -> 'a}): 'a =
198 fun useOperand (z: Operand.t, a) = Operand.foldVars (z, a, use)
201 Bind {dst = (x, t), src, ...} => def (x, t, useOperand (src, a))
202 | Move {dst, src} => useOperand (src, useOperand (dst, a))
203 | Object {dst = (dst, ty), ...} => def (dst, ty, a)
204 | PrimApp {dst, args, ...} =>
206 Option.fold (dst, a, fn ((x, t), a) =>
210 | ProfileLabel _ => a
211 | SetExnStackLocal => a
212 | SetExnStackSlot => a
214 | SetSlotExnStack => a
217 fun foreachDefUse (s: t, {def, use}) =
218 foldDefUse (s, (), {def = fn (x, t, ()) => def (x, t),
221 fun 'a foldDef (s: t, a: 'a, f: Var.t * Type.t * 'a -> 'a): 'a =
222 foldDefUse (s, a, {def = f, use = #2})
224 fun foreachDef (s:t , f: Var.t * Type.t -> unit) =
225 foldDef (s, (), fn (x, t, ()) => f (x, t))
227 fun 'a foldUse (s: t, a: 'a, f: Var.t * 'a -> 'a) =
228 foldDefUse (s, a, {def = #3, use = f})
230 fun foreachUse (s, f) = foldUse (s, (), f o #1)
232 fun replaceUses (s: t, f: Var.t -> Operand.t): t =
234 fun oper (z: Operand.t): Operand.t =
235 Operand.replaceVar (z, f)
238 Bind {dst, isMutable, src} =>
240 isMutable = isMutable,
242 | Move {dst, src} => Move {dst = oper dst, src = oper src}
244 | PrimApp {args, dst, prim} =>
245 PrimApp {args = Vector.map (args, oper),
249 | ProfileLabel _ => s
250 | SetExnStackLocal => s
251 | SetExnStackSlot => s
253 | SetSlotExnStack => s
260 fn Bind {dst = (x, t), src, ...} =>
262 [seq [Var.layout x, constrain t],
263 indent (seq [str "= ", Operand.layout src], 2)]
267 indent (seq [str ":= ", Operand.layout src], 2)]
268 | Object {dst = (dst, ty), header, size} =>
270 [seq [Var.layout dst, constrain ty],
271 indent (seq [str "= Object ",
272 record [("header", seq [str "0x", Word.layout header]),
273 ("size", Bytes.layout size)]],
275 | PrimApp {dst, prim, args, ...} =>
278 NONE => seq [str "_", constrain (Type.unit)]
279 | SOME (x, t) => seq [Var.layout x, constrain t],
280 indent (seq [str "= ", Prim.layout prim, str " ",
281 Vector.layout Operand.layout args],
283 | Profile e => ProfileExp.layout e
285 seq [str "ProfileLabel ", ProfileLabel.layout p]
286 | SetExnStackLocal => str "SetExnStackLocal"
287 | SetExnStackSlot => str "SetExnStackSlot "
288 | SetHandler l => seq [str "SetHandler ", Label.layout l]
289 | SetSlotExnStack => str "SetSlotExnStack "
292 val toString = Layout.toString o layout
295 foreachDef (s, Var.clear o #1)
297 fun resize (src: Operand.t, dstTy: Type.t): Operand.t * t list =
299 val srcTy = Operand.ty src
301 val (src, srcTy, ssSrc, dstTy, finishDst) =
302 case (Type.deReal srcTy, Type.deReal dstTy) of
304 (src, srcTy, [], dstTy, fn dst => (dst, []))
307 val ws = WordSize.fromBits (RealSize.bits rs)
308 val tmp = Var.newNoname ()
309 val tmpTy = Type.word ws
311 (Operand.Var {ty = tmpTy, var = tmp},
313 [PrimApp {args = Vector.new1 src,
314 dst = SOME (tmp, tmpTy),
315 prim = Prim.realCastToWord (rs, ws)}],
316 dstTy, fn dst => (dst, []))
320 val ws = WordSize.fromBits (RealSize.bits rs)
321 val tmp = Var.newNoname ()
322 val tmpTy = Type.real rs
327 (Operand.Var {ty = tmpTy, var = tmp},
328 [PrimApp {args = Vector.new1 dst,
329 dst = SOME (tmp, tmpTy),
330 prim = Prim.wordCastToReal (ws, rs)}]))
332 | (SOME _, SOME _) =>
333 (src, srcTy, [], dstTy, fn dst => (dst, []))
335 val srcW = Type.width srcTy
336 val dstW = Type.width dstTy
339 if Bits.equals (srcW, dstW)
340 then (Operand.cast (src, dstTy), [])
342 val tmp = Var.newNoname ()
345 (Operand.Var {ty = tmpTy, var = tmp},
346 [PrimApp {args = Vector.new1 src,
347 dst = SOME (tmp, tmpTy),
348 prim = (Prim.wordExtdToWord
349 (WordSize.fromBits srcW,
350 WordSize.fromBits dstW,
351 {signed = false}))}])
354 val (dst, ssDst) = finishDst dst
356 (dst, ssSrc @ ssConv @ ssDst)
360 datatype z = datatype Statement.t
365 Arith of {args: Operand.t vector,
371 | CCall of {args: Operand.t vector,
372 func: Type.t CFunction.t,
373 return: Label.t option}
374 | Call of {args: Operand.t vector,
377 | Goto of {args: Operand.t vector,
379 | Raise of Operand.t vector
380 | Return of Operand.t vector
388 Arith {args, dst, overflow, prim, success, ty} =>
390 record [("args", Vector.layout Operand.layout args),
391 ("dst", Var.layout dst),
392 ("overflow", Label.layout overflow),
393 ("prim", Prim.layout prim),
394 ("success", Label.layout success),
395 ("ty", Type.layout ty)]]
396 | CCall {args, func, return} =>
398 record [("args", Vector.layout Operand.layout args),
399 ("func", CFunction.layout (func, Type.layout)),
400 ("return", Option.layout Label.layout return)]]
401 | Call {args, func, return} =>
402 seq [Func.layout func, str " ",
403 Vector.layout Operand.layout args,
404 str " ", Return.layout return]
405 | Goto {dst, args} =>
406 seq [Label.layout dst, str " ",
407 Vector.layout Operand.layout args]
408 | Raise xs => seq [str "raise ", Vector.layout Operand.layout xs]
409 | Return xs => seq [str "return ", Vector.layout Operand.layout xs]
410 | Switch s => Switch.layout s
414 CCall {args = (Vector.new1
416 (Const.string "control shouldn't reach here"))),
417 func = Type.BuiltInCFunction.bug (),
420 fun foreachFunc (t, f : Func.t -> unit) : unit =
422 Call {func, ...} => f func
425 fun 'a foldDefLabelUse (t, a: 'a,
426 {def: Var.t * Type.t * 'a -> 'a,
427 label: Label.t * 'a -> 'a,
428 use: Var.t * 'a -> 'a}): 'a =
430 fun useOperand (z, a) = Operand.foldVars (z, a, use)
431 fun useOperands (zs: Operand.t vector, a) =
432 Vector.fold (zs, a, useOperand)
435 Arith {args, dst, overflow, success, ty, ...} =>
437 val a = label (overflow, a)
438 val a = label (success, a)
439 val a = def (dst, ty, a)
440 val a = useOperands (args, a)
444 | CCall {args, return, ...} =>
448 | SOME l => label (l, a))
449 | Call {args, return, ...} =>
450 useOperands (args, Return.foldLabel (return, a, label))
451 | Goto {args, dst, ...} => label (dst, useOperands (args, a))
452 | Raise zs => useOperands (zs, a)
453 | Return zs => useOperands (zs, a)
454 | Switch s => Switch.foldLabelUse (s, a, {label = label,
458 fun foreachDefLabelUse (t, {def, label, use}) =
459 foldDefLabelUse (t, (), {def = fn (x, t, ()) => def (x, t),
463 fun foldLabel (t, a, f) = foldDefLabelUse (t, a, {def = #3,
467 fun foreachLabel (t, f) = foldLabel (t, (), f o #1)
469 fun foldDef (t, a, f) = foldDefLabelUse (t, a, {def = f,
473 fun foreachDef (t, f) =
474 foldDef (t, (), fn (x, t, ()) => f (x, t))
476 fun foldUse (t, a, f) = foldDefLabelUse (t, a, {def = #3,
480 fun foreachUse (t, f) = foldUse (t, (), f o #1)
482 fun clear (t: t): unit =
483 foreachDef (t, Var.clear o #1)
486 fun make i = WordX.fromIntInf (i, WordSize.bool)
488 fun ifBool (test, {falsee, truee}) =
490 {cases = Vector.new2 ((make 0, falsee), (make 1, truee)),
492 size = WordSize.bool,
494 fun ifZero (test, {falsee, truee}) =
496 {cases = Vector.new1 (make 0, truee),
497 default = SOME falsee,
498 size = WordSize.bool,
502 fun replaceUses (t: t, f: Var.t -> Operand.t): t =
504 fun oper z = Operand.replaceVar (z, f)
505 fun opers zs = Vector.map (zs, oper)
508 Arith {args, dst, overflow, prim, success, ty} =>
509 Arith {args = opers args,
515 | CCall {args, func, return} =>
516 CCall {args = opers args,
519 | Call {args, func, return} =>
520 Call {args = opers args,
523 | Goto {args, dst} =>
524 Goto {args = opers args,
526 | Raise zs => Raise (opers zs)
527 | Return zs => Return (opers zs)
528 | Switch s => Switch (Switch.replaceVar (s, f))
535 Cont of {handler: Handler.t}
536 | CReturn of {func: Type.t CFunction.t}
547 record [("handler", Handler.layout handler)]]
550 record [("func", CFunction.layout (func, Type.layout))]]
551 | Handler => str "Handler"
555 datatype frameStyle = None | OffsetsAndSize | SizeOnly
556 fun frameStyle (k: t): frameStyle =
558 Cont _ => OffsetsAndSize
559 | CReturn {func, ...} =>
560 if CFunction.mayGC func
562 else if !Control.profile = Control.ProfileNone
565 | Handler => SizeOnly
572 fun layoutFormals (xts: (Var.t * Type.t) vector) =
573 Vector.layout (fn (x, t) =>
575 if !Control.showTypes
576 then seq [str ": ", Type.layout t]
584 T of {args: (Var.t * Type.t) vector,
587 statements: Statement.t vector,
588 transfer: Transfer.t}
591 fun make f (T r) = f r
593 val kind = make #kind
594 val label = make #label
597 fun clear (T {args, label, statements, transfer, ...}) =
598 (Vector.foreach (args, Var.clear o #1)
600 ; Vector.foreach (statements, Statement.clear)
601 ; Transfer.clear transfer)
603 fun layout (T {args, kind, label, statements, transfer, ...}) =
607 align [seq [Label.layout label, str " ",
608 Vector.layout (fn (x, t) =>
609 if !Control.showTypes
610 then seq [Var.layout x, str ": ",
612 else Var.layout x) args,
613 str " ", Kind.layout kind, str " = "],
616 (Vector.toListMap (statements, Statement.layout)),
617 Transfer.layout transfer],
621 fun foreachDef (T {args, statements, transfer, ...}, f) =
622 (Vector.foreach (args, f)
623 ; Vector.foreach (statements, fn s => Statement.foreachDef (s, f))
624 ; Transfer.foreachDef (transfer, f))
626 fun foreachUse (T {statements, transfer, ...}, f) =
627 (Vector.foreach (statements, fn s => Statement.foreachUse (s, f))
628 ; Transfer.foreachUse (transfer, f))
633 datatype t = T of {args: (Var.t * Type.t) vector,
634 blocks: Block.t vector,
636 raises: Type.t vector option,
637 returns: Type.t vector option,
641 fun make f (T r) = f r
643 val blocks = make #blocks
644 val name = make #name
650 fun clear (T {name, args, blocks, ...}) =
652 ; Vector.foreach (args, Var.clear o #1)
653 ; Vector.foreach (blocks, Block.clear))
655 fun layoutHeader (T {args, name, raises, returns, start, ...}): Layout.t =
659 seq [str "fun ", Func.layout name,
660 str " ", layoutFormals args,
661 if !Control.showTypes
665 (Vector.layout Type.layout) raises),
668 (Vector.layout Type.layout) returns)]]
670 str " = ", Label.layout start, str " ()"]
673 fun layouts (f as T {blocks, ...}, output) =
674 (output (layoutHeader f)
675 ; Vector.foreach (blocks, fn b =>
676 output (Layout.indent (Block.layout b, 2))))
678 fun layout (f as T {blocks, ...}) =
682 align [layoutHeader f,
683 indent (align (Vector.toListMap (blocks, Block.layout)), 2)]
686 fun foreachDef (T {args, blocks, ...}, f) =
687 (Vector.foreach (args, f)
688 ; (Vector.foreach (blocks, fn b => Block.foreachDef (b, f))))
690 fun foreachUse (T {blocks, ...}, f) =
691 Vector.foreach (blocks, fn b => Block.foreachUse (b, f))
693 fun dfs (T {blocks, start, ...}, v) =
695 val numBlocks = Vector.length blocks
696 val {get = labelIndex, set = setLabelIndex, rem, ...} =
697 Property.getSetOnce (Label.plist,
698 Property.initRaise ("index", Label.layout))
699 val _ = Vector.foreachi (blocks, fn (i, Block.T {label, ...}) =>
700 setLabelIndex (label, i))
701 val visited = Array.array (numBlocks, false)
702 fun visit (l: Label.t): unit =
706 if Array.sub (visited, i)
710 val _ = Array.update (visited, i, true)
711 val b as Block.T {transfer, ...} =
712 Vector.sub (blocks, i)
714 val _ = Transfer.foreachLabel (transfer, visit)
721 val _ = Vector.foreach (blocks, rem o Block.label)
726 structure Graph = DirectedGraph
727 structure Node = Graph.Node
729 fun dominatorTree (T {blocks, start, ...}): Block.t Tree.t =
733 fun newNode () = Graph.newNode g
734 val {get = labelNode, ...} =
736 (Label.plist, Property.initFun (fn _ => newNode ()))
737 val {get = nodeInfo: unit Node.t -> {block: Block.t},
738 set = setNodeInfo, ...} =
740 (Node.plist, Property.initRaise ("info", Node.layout))
743 (blocks, fn b as Block.T {label, ...}=>
744 setNodeInfo (labelNode label, {block = b}))
747 (blocks, fn Block.T {label, transfer, ...} =>
749 val from = labelNode label
751 Transfer.foreachLabel
753 (ignore o Graph.addEdge)
754 (g, {from = from, to = labelNode to}))
759 Graph.dominatorTree (g, {root = labelNode start,
760 nodeValue = #block o nodeInfo})
763 fun dropProfile (f: t): t =
765 val {args, blocks, name, raises, returns, start} = dest f
768 (blocks, fn Block.T {args, kind, label, statements, transfer} =>
769 Block.T {args = args,
772 statements = Vector.keepAll
774 fn Statement.Profile _ => false
775 | Statement.ProfileLabel _ => false
777 transfer = transfer})
787 fun shrink (f: t): t =
789 val {args, blocks, name, raises, returns, start} = dest f
790 val {get = labelInfo, rem, set = setLabelInfo, ...} =
792 (Label.plist, Property.initRaise ("info", Label.layout))
795 (blocks, fn block as Block.T {label, ...} =>
796 setLabelInfo (label, {block = block,
798 occurrences = ref 0}))
799 fun visitLabel l = Int.inc (#occurrences (labelInfo l))
800 val () = visitLabel start
802 Vector.foreach (blocks, fn Block.T {transfer, ...} =>
803 Transfer.foreachLabel (transfer, visitLabel))
804 datatype z = datatype Statement.t
805 datatype z = datatype Transfer.t
808 (blocks, fn Block.T {transfer, ...} =>
812 val {inline, occurrences, ...} = labelInfo dst
819 fun expand (ss: Statement.t vector list, t: Transfer.t)
820 : Statement.t vector * Transfer.t =
822 fun done () = (Vector.concat (rev ss), t)
827 val {block, inline, ...} = labelInfo dst
833 val Block.T {args = formals, statements,
838 (formals, args, fn (dst, src) =>
843 expand (statements :: binds :: ss, transfer)
852 fn (Block.T {args, kind, label, statements, transfer}, ac) =>
854 val {inline, ...} = labelInfo label
860 val (statements, transfer) =
861 expand ([statements], transfer)
863 Block.T {args = args,
866 statements = statements,
867 transfer = transfer} :: ac
870 val () = Vector.foreach (blocks, rem o Block.label)
884 T of {functions: Function.t list,
885 handlesSignals: bool,
887 objectTypes: ObjectType.t vector}
889 fun clear (T {functions, main, ...}) =
890 (List.foreach (functions, Function.clear)
891 ; Function.clear main)
893 fun layouts (T {functions, main, objectTypes, ...},
894 output': Layout.t -> unit): unit =
899 output (str "\nObjectTypes:")
900 ; Vector.foreachi (objectTypes, fn (i, ty) =>
901 output (seq [str "opt_", Int.layout i,
902 str " = ", ObjectType.layout ty]))
903 ; output (str "\nMain:")
904 ; Function.layouts (main, output)
905 ; output (str "\nFunctions:")
906 ; List.foreach (functions, fn f => Function.layouts (f, output))
909 fun layoutStats (T {functions, main, objectTypes, ...}) =
911 val numStatements = ref 0
912 val numBlocks = ref 0
915 (main::functions, fn f =>
917 val {blocks, ...} = Function.dest f
920 (blocks, fn Block.T {statements, ...} =>
922 ; numStatements := !numStatements + Vector.length statements))
924 val numFunctions = 1 + List.length functions
925 val numObjectTypes = Vector.length objectTypes
929 [seq [str "num functions in program = ", Int.layout numFunctions],
930 seq [str "num blocks in program = ", Int.layout (!numBlocks)],
931 seq [str "num statements in program = ", Int.layout (!numStatements)],
932 seq [str "num object types in program = ", Int.layout (numObjectTypes)]]
935 fun dropProfile (T {functions, handlesSignals, main, objectTypes}) =
936 (Control.profile := Control.ProfileNone
937 ; T {functions = List.map (functions, Function.dropProfile),
938 handlesSignals = handlesSignals,
939 main = Function.dropProfile main,
940 objectTypes = objectTypes})
941 (* quell unused warning *)
946 val T {functions, main, ...} = p
947 val functions = Vector.fromList (main::functions)
948 val numFunctions = Vector.length functions
949 val {get = funcIndex, set = setFuncIndex, rem, ...} =
950 Property.getSetOnce (Func.plist,
951 Property.initRaise ("index", Func.layout))
952 val _ = Vector.foreachi (functions, fn (i, f) =>
953 setFuncIndex (#name (Function.dest f), i))
954 val visited = Array.array (numFunctions, false)
955 fun visit (f: Func.t): unit =
959 if Array.sub (visited, i)
963 val _ = Array.update (visited, i, true)
964 val f = Vector.sub (functions, i)
967 (f, fn Block.T {transfer, ...} =>
968 (Transfer.foreachFunc (transfer, visit)
975 val _ = visit (Function.name main)
976 val _ = Vector.foreach (functions, rem o Function.name)
981 fun orderFunctions (p as T {handlesSignals, objectTypes, ...}) =
983 val functions = ref []
988 val {args, name, raises, returns, start, ...} =
994 (List.push (blocks, b)
996 val f = Function.new {args = args,
997 blocks = Vector.fromListRev (!blocks),
1003 List.push (functions, f)
1006 val (main, functions) =
1007 case List.rev (!functions) of
1008 main::functions => (main, functions)
1009 | _ => Error.bug "Rssa.orderFunctions: main/functions"
1011 T {functions = functions,
1012 handlesSignals = handlesSignals,
1014 objectTypes = objectTypes}
1017 fun copyProp (T {functions, handlesSignals, main, objectTypes, ...}): t =
1019 val tracePrimApply =
1021 ("Rssa.copyProp.primApply",
1023 List.layout (ApplyArg.layout (Var.layout o #var)),
1025 ApplyResult.layout (Var.layout o #var))
1026 val {get = replaceVar: Var.t -> Operand.t,
1027 set = setReplaceVar, ...} =
1029 (Var.plist, Property.initRaise ("replacement", Var.layout))
1030 fun dontReplace (x: Var.t, t: Type.t): unit =
1031 setReplaceVar (x, Operand.Var {var = x, ty = t})
1032 val setReplaceVar = fn (x: Var.t, t: Type.t, z: Operand.t) =>
1035 if Type.equals (Operand.ty z, t)
1037 else Operand.Cast (z, t)
1039 setReplaceVar (x, z)
1041 fun loopStatement (s: Statement.t): Statement.t option =
1043 val s = Statement.replaceUses (s, replaceVar)
1045 (Statement.foreachDef (s, dontReplace)
1049 Bind {dst = (dst, dstTy), isMutable, src} =>
1054 datatype z = datatype Operand.t
1057 Cast (src, _) => getSrc src
1058 | Const _ => SOME src
1065 (setReplaceVar (dst, dstTy, src)
1068 | PrimApp {args, dst, prim} =>
1070 fun replace (z: Operand.t): Statement.t option =
1071 (Option.app (dst, fn (x, t) =>
1072 setReplaceVar (x, t, z))
1074 datatype z = datatype Operand.t
1077 Cast (arg, _) => getArg arg
1078 | Const c => SOME (ApplyArg.Const c)
1079 | Var x => SOME (ApplyArg.Var x)
1081 val applyArgs = Vector.keepAllMap (args, getArg)
1082 datatype z = datatype ApplyResult.t
1084 if Vector.length args <> Vector.length applyArgs
1087 case (tracePrimApply
1089 (prim, Vector.toList applyArgs,
1090 fn ({var = x, ...}, {var = y, ...}) =>
1091 Var.equals (x, y))) of
1092 Apply (prim, args) =>
1095 Vector.fromListMap (args, Operand.Var)
1096 val () = Option.app (dst, dontReplace)
1098 SOME (PrimApp {args = args,
1102 | Bool b => replace (Operand.bool b)
1103 | Const c => replace (Operand.Const c)
1104 | Overflow => keep ()
1105 | Unknown => keep ()
1106 | Var x => replace (Operand.Var x)
1110 fun loopTransfer t =
1111 (Transfer.foreachDef (t, dontReplace)
1112 ; Transfer.replaceUses (t, replaceVar))
1113 fun loopFormals args = Vector.foreach (args, dontReplace)
1114 fun loopFunction (f: Function.t): Function.t =
1116 val {args, name, raises, returns, start, ...} =
1118 val () = loopFormals args
1122 (f, fn Block.T {args, kind, label, statements, transfer} =>
1124 val () = loopFormals args
1126 Vector.keepAllMap (statements, loopStatement)
1127 val transfer = loopTransfer transfer
1130 (blocks, Block.T {args = args,
1133 statements = statements,
1134 transfer = transfer})
1138 val blocks = Vector.fromList (!blocks)
1140 Function.new {args = args,
1147 (* Must process main first, because it defines globals that are
1148 * used in other functions.
1150 val main = loopFunction main
1151 val functions = List.revMap (functions, loopFunction)
1153 T {functions = functions,
1154 handlesSignals = handlesSignals,
1156 objectTypes = objectTypes}
1159 fun shrink (T {functions, handlesSignals, main, objectTypes}) =
1162 T {functions = List.revMap (functions, Function.shrink),
1163 handlesSignals = handlesSignals,
1164 main = Function.shrink main,
1165 objectTypes = objectTypes}
1172 structure ExnStack =
1176 datatype t = Caller | Me
1178 val equals: t * t -> bool = op =
1181 fn Caller => "Caller"
1184 val layout = Layout.str o toString
1187 structure L = FlatLattice (structure Point = ZPoint)
1189 structure Point = ZPoint
1191 val me = point Point.Me
1194 structure HandlerLat = FlatLattice (structure Point = Label)
1196 structure HandlerInfo =
1198 datatype t = T of {block: Block.t,
1200 handler: HandlerLat.t,
1204 fun new (b: Block.t): t =
1206 global = ExnStack.new (),
1207 handler = HandlerLat.new (),
1208 slot = ExnStack.new (),
1209 visited = ref false}
1211 fun layout (T {global, handler, slot, ...}) =
1212 Layout.record [("global", ExnStack.layout global),
1213 ("slot", ExnStack.layout slot),
1214 ("handler", HandlerLat.layout handler)]
1218 Trace.trace ("Rssa.checkHandlers.goto", Label.layout, Unit.layout)
1220 fun checkHandlers (T {functions, ...}) =
1223 fun checkFunction (f: Function.t): unit =
1225 val {name, start, blocks, ...} = Function.dest f
1226 val {get = labelInfo: Label.t -> HandlerInfo.t,
1228 set = setLabelInfo} =
1230 (Label.plist, Property.initRaise ("info", Label.layout))
1234 setLabelInfo (Block.label b, HandlerInfo.new b))
1235 (* Do a DFS of the control-flow graph. *)
1236 fun visitLabel l = visitInfo (labelInfo l)
1238 (hi as HandlerInfo.T {block, global, handler, slot,
1239 visited, ...}): unit =
1244 val _ = visited := true
1245 val Block.T {label, statements, transfer, ...} = block
1253 (seq [str "visiting ",
1254 Label.layout label],
1258 datatype z = datatype Statement.t
1259 val {global, handler, slot} =
1262 {global = global, handler = handler, slot = slot},
1263 fn (s, {global, handler, slot}) =>
1265 SetExnStackLocal => {global = ExnStack.me,
1268 | SetExnStackSlot => {global = slot,
1271 | SetSlotExnStack => {global = global,
1274 | SetHandler l => {global = global,
1275 handler = HandlerLat.point l,
1277 | _ => {global = global,
1282 (Control.Silent, fn () =>
1285 [str "before: ", HandlerInfo.layout hi,
1286 str "block: ", Block.layout block,
1289 [("global", ExnStack.layout global),
1290 ("slot", ExnStack.layout slot),
1292 HandlerLat.layout handler)]],
1294 (fn Block.T {label, ...} =>
1295 seq [Label.layout label,
1297 HandlerInfo.layout (labelInfo label)])
1300 ; Error.bug (concat ["Rssa.checkHandlers: handler mismatch at ", msg]))
1301 fun assert (msg, f) =
1305 fun goto (l: Label.t): unit =
1307 val HandlerInfo.T {global = g, handler = h,
1312 ExnStack.<= (global, g)
1313 andalso ExnStack.<= (slot, s)
1314 andalso HandlerLat.<= (handler, h))
1318 val goto = traceGoto goto
1322 (global, ExnStack.Point.Caller))
1323 datatype z = datatype Transfer.t
1326 Arith {overflow, success, ...} =>
1327 (goto overflow; goto success)
1328 | CCall {return, ...} => Option.app (return, goto)
1329 | Call {return, ...} =>
1333 datatype z = datatype Return.t
1337 | NonTail {handler = h, ...} =>
1341 (global, ExnStack.Point.Caller)
1342 | Handler.Dead => true
1343 | Handler.Handle l =>
1350 HandlerLat.forcePoint
1358 | Goto {dst, ...} => goto dst
1359 | Raise _ => tail "raise"
1360 | Return _ => tail "return"
1361 | Switch s => Switch.foreachLabel (s, goto)
1363 val info as HandlerInfo.T {global, ...} = labelInfo start
1364 val _ = ExnStack.forcePoint (global, ExnStack.Point.Caller)
1365 val _ = visitInfo info
1372 display (seq [str "checkHandlers ",
1376 (blocks, fn Block.T {label, ...} =>
1378 [Label.layout label,
1380 HandlerInfo.layout (labelInfo label)]))
1384 val _ = Vector.foreach (blocks, fn b =>
1385 remLabelInfo (Block.label b))
1389 val _ = List.foreach (functions, checkFunction)
1394 fun checkScopes (program as T {functions, main, ...}): unit =
1401 fun make (layout, plist) =
1403 val {get, set, ...} =
1404 Property.getSet (plist, Property.initConst Undefined)
1405 fun bind (x, isGlobal) =
1409 set (x, if isGlobal then Global else InScope)
1410 | _ => Error.bug ("Rssa.checkScopes: duplicate definition of "
1411 ^ (Layout.toString (layout x)))
1416 | _ => Error.bug (concat
1417 ["Rssa.checkScopes: reference to ",
1418 Layout.toString (layout x),
1423 | _ => set (x, Defined)
1424 in (bind, reference, unbind)
1426 val (bindVar, getVar, unbindVar) = make (Var.layout, Var.plist)
1429 ("Rssa.bindVar", Var.layout, Bool.layout, Unit.layout)
1432 Trace.trace ("Rssa.getVar", Var.layout, Unit.layout) getVar
1434 Trace.trace ("Rssa.unbindVar", Var.layout, Unit.layout) unbindVar
1435 val (bindFunc, _, _) = make (Func.layout, Func.plist)
1436 val bindFunc = fn f => bindFunc (f, false)
1437 val (bindLabel, getLabel, unbindLabel) =
1438 make (Label.layout, Label.plist)
1439 val bindLabel = fn l => bindLabel (l, false)
1440 fun loopFunc (f: Function.t, isMain: bool): unit =
1442 val bindVar = fn x => bindVar (x, isMain)
1443 val {args, blocks, ...} = Function.dest f
1444 val _ = Vector.foreach (args, bindVar o #1)
1445 val _ = Vector.foreach (blocks, bindLabel o Block.label)
1448 (blocks, fn Block.T {transfer, ...} =>
1449 Transfer.foreachLabel (transfer, getLabel))
1450 (* Descend the dominator tree, verifying that variable
1451 * definitions dominate variable uses.
1455 (Function.dominatorTree f,
1456 fn Block.T {args, statements, transfer, ...} =>
1458 val _ = Vector.foreach (args, bindVar o #1)
1461 (statements, fn s =>
1462 (Statement.foreachUse (s, getVar)
1463 ; Statement.foreachDef (s, bindVar o #1)))
1464 val _ = Transfer.foreachUse (transfer, getVar)
1465 val _ = Transfer.foreachDef (transfer, bindVar o #1)
1474 (statements, fn s =>
1475 Statement.foreachDef (s, unbindVar o #1))
1477 Transfer.foreachDef (transfer, unbindVar o #1)
1478 val _ = Vector.foreach (args, unbindVar o #1)
1483 val _ = Vector.foreach (blocks, unbindLabel o Block.label)
1484 val _ = Vector.foreach (args, unbindVar o #1)
1488 val _ = List.foreach (functions, bindFunc o Function.name)
1489 val _ = loopFunc (main, true)
1490 val _ = List.foreach (functions, fn f => loopFunc (f, false))
1491 val _ = clear program
1495 fun typeCheck (p as T {functions, main, objectTypes, ...}) =
1499 (objectTypes, fn ty =>
1500 Err.check ("objectType",
1501 fn () => ObjectType.isOk ty,
1502 fn () => ObjectType.layout ty))
1503 fun tyconTy (opt: ObjptrTycon.t): ObjectType.t =
1504 Vector.sub (objectTypes, ObjptrTycon.index opt)
1505 val () = checkScopes p
1506 val {get = labelBlock: Label.t -> Block.t,
1507 set = setLabelBlock, ...} =
1508 Property.getSetOnce (Label.plist,
1509 Property.initRaise ("block", Label.layout))
1510 val {get = funcInfo, set = setFuncInfo, ...} =
1511 Property.getSetOnce (Func.plist,
1512 Property.initRaise ("info", Func.layout))
1513 val {get = varType: Var.t -> Type.t, set = setVarType, ...} =
1514 Property.getSetOnce (Var.plist,
1515 Property.initRaise ("type", Var.layout))
1517 Trace.trace2 ("Rssa.setVarType", Var.layout, Type.layout,
1520 fun checkOperand (x: Operand.t): unit =
1522 datatype z = datatype Operand.t
1525 ArrayOffset {base, index, offset, scale, ty} =>
1527 ; checkOperand index
1528 ; Type.arrayOffsetIsOk {base = Operand.ty base,
1529 index = Operand.ty index,
1536 ; Type.castIsOk {from = Operand.ty z,
1540 | EnsuresBytesFree => true
1542 | Offset {base, offset, ty} =>
1543 Type.offsetIsOk {base = Operand.ty base,
1547 | ObjptrTycon _ => true
1549 | Var {ty, var} => Type.isSubtype (varType var, ty)
1551 Err.check ("operand", ok, fn () => Operand.layout x)
1554 Trace.trace ("Rssa.checkOperand", Operand.layout, Unit.layout)
1556 fun checkOperands v = Vector.foreach (v, checkOperand)
1557 fun check' (x, name, isOk, layout) =
1558 Err.check (name, fn () => isOk x, fn () => layout x)
1559 val labelKind = Block.kind o labelBlock
1560 fun statementOk (s: Statement.t): bool =
1562 datatype z = datatype Statement.t
1565 Bind {src, dst = (_, dstTy), ...} =>
1567 ; Type.isSubtype (Operand.ty src, dstTy))
1568 | Move {dst, src} =>
1571 ; (Type.isSubtype (Operand.ty src, Operand.ty dst)
1572 andalso Operand.isLocation dst))
1573 | Object {dst = (_, ty), header, size} =>
1576 ObjptrTycon.fromIndex
1577 (Runtime.headerToTypeIndex header)
1579 Type.isSubtype (Type.objptr tycon, ty)
1585 {alignment = (case !Control.align of
1586 Control.Align4 => Bytes.inWord32
1587 | Control.Align8 => Bytes.inWord64)}))
1589 (case tyconTy tycon of
1590 ObjectType.Normal {ty, ...} =>
1592 (size, Bytes.+ (Runtime.normalMetaDataSize (),
1596 | PrimApp {args, dst, prim} =>
1597 (Vector.foreach (args, checkOperand)
1598 ; (Type.checkPrimApp
1599 {args = Vector.map (args, Operand.ty),
1601 result = Option.map (dst, #2)}))
1603 | ProfileLabel _ => true
1604 | SetExnStackLocal => true
1605 | SetExnStackSlot => true
1607 (case labelKind l of
1608 Kind.Handler => true
1610 | SetSlotExnStack => true
1613 Trace.trace ("Rssa.statementOk",
1617 fun gotoOk {args: Type.t vector,
1618 dst: Label.t}: bool =
1620 val Block.T {args = formals, kind, ...} = labelBlock dst
1622 Vector.equals (args, formals, fn (t, (_, t')) =>
1623 Type.isSubtype (t, t'))
1624 andalso (case kind of
1628 fun labelIsNullaryJump l = gotoOk {dst = l, args = Vector.new0 ()}
1629 fun tailIsOk (caller: Type.t vector option,
1630 callee: Type.t vector option): bool =
1631 case (caller, callee) of
1633 | (SOME caller, SOME callee) =>
1634 Vector.equals (callee, caller, Type.isSubtype)
1636 fun nonTailIsOk (formals: (Var.t * Type.t) vector,
1637 returns: Type.t vector option): bool =
1641 Vector.equals (formals, ts, fn ((_, t), t') =>
1642 Type.isSubtype (t', t))
1643 fun callIsOk {args, func, raises, return, returns} =
1645 val Function.T {args = formals,
1647 returns = returns', ...} =
1651 Vector.equals (args, formals, fn (z, (_, t)) =>
1652 Type.isSubtype (Operand.ty z, t))
1656 Option.isNone raises'
1657 andalso Option.isNone returns'
1658 | Return.NonTail {cont, handler} =>
1660 val Block.T {args = cArgs, kind = cKind, ...} =
1663 nonTailIsOk (cArgs, returns')
1666 Kind.Cont {handler = h} =>
1667 Handler.equals (handler, h)
1671 tailIsOk (raises, raises')
1672 | Handler.Dead => true
1673 | Handler.Handle l =>
1675 val Block.T {args = hArgs,
1676 kind = hKind, ...} =
1679 nonTailIsOk (hArgs, raises')
1682 Kind.Handler => true
1688 tailIsOk (raises, raises')
1689 andalso tailIsOk (returns, returns'))
1692 fun checkFunction (Function.T {args, blocks, raises, returns, start,
1695 val _ = Vector.foreach (args, setVarType)
1698 (blocks, fn b as Block.T {args, label, statements,
1700 (setLabelBlock (label, b)
1701 ; Vector.foreach (args, setVarType)
1702 ; Vector.foreach (statements, fn s =>
1703 Statement.foreachDef
1705 ; Transfer.foreachDef (transfer, setVarType)))
1706 val _ = labelIsNullaryJump start
1707 fun transferOk (t: Transfer.t): bool =
1709 datatype z = datatype Transfer.t
1712 Arith {args, overflow, prim, success, ty, ...} =>
1714 val _ = checkOperands args
1716 Prim.mayOverflow prim
1717 andalso labelIsNullaryJump overflow
1718 andalso labelIsNullaryJump success
1721 {args = Vector.map (args, Operand.ty),
1725 | CCall {args, func, return} =>
1727 val _ = checkOperands args
1729 CFunction.isOk (func, {isUnit = Type.isUnit})
1731 Vector.equals (args, CFunction.args func,
1740 Kind.CReturn {func = f} =>
1741 CFunction.equals (func, f)
1744 | Call {args, func, return} =>
1746 val _ = checkOperands args
1748 callIsOk {args = args,
1754 | Goto {args, dst} =>
1756 ; gotoOk {args = Vector.map (args, Operand.ty),
1764 (zs, ts, fn (z, t) =>
1765 Type.isSubtype (Operand.ty z, t))))
1772 (zs, ts, fn (z, t) =>
1773 Type.isSubtype (Operand.ty z, t))))
1775 Switch.isOk (s, {checkUse = checkOperand,
1776 labelIsOk = labelIsNullaryJump})
1779 Trace.trace ("Rssa.transferOk",
1783 fun blockOk (Block.T {args, kind, statements, transfer, ...})
1786 fun kindOk (k: Kind.t): bool =
1788 datatype z = datatype Kind.t
1794 val return = CFunction.return func
1796 0 = Vector.length args
1798 (1 = Vector.length args
1802 #2 (Vector.first args)
1804 Type.isSubtype (return, expects)
1806 CType.equals (Type.toCType return,
1807 Type.toCType expects)
1813 val _ = check' (kind, "kind", kindOk, Kind.layout)
1816 (statements, fn s =>
1817 check' (s, "statement", statementOk,
1819 val _ = check' (transfer, "transfer", transferOk,
1825 Trace.trace ("Rssa.blockOk",
1833 check' (b, "block", blockOk, Block.layout))
1839 (functions, fn f as Function.T {name, ...} =>
1840 setFuncInfo (name, f))
1841 val _ = checkFunction main
1842 val _ = List.foreach (functions, checkFunction)
1845 (main, "main function",
1848 val {args, ...} = Function.dest f
1856 end handle Err.E e => (Layout.outputl (Err.layout e, Out.error)
1857 ; Error.bug "Rssa.typeCheck")