1 (* Copyright (C) 2009,2013-2014,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 Backend (S: BACKEND_STRUCTS): BACKEND =
19 structure Global = Global
20 structure Label = Label
22 structure ObjptrTycon = ObjptrTycon
23 structure RealX = RealX
24 structure Register = Register
25 structure Runtime = Runtime
26 structure StackOffset = StackOffset
27 structure WordSize = WordSize
28 structure WordX = WordX
29 structure WordXVector = WordXVector
34 structure GCField = GCField
37 structure Rssa = Rssa (open Ssa Machine)
42 structure CType = CType
43 structure Const = Const
45 structure Function = Function
51 structure AllocateRegisters = AllocateRegisters (structure Machine = Machine
52 structure Rssa = Rssa)
53 structure Chunkify = Chunkify (Rssa)
54 structure ImplementHandlers = ImplementHandlers (structure Rssa = Rssa)
55 structure ImplementProfiling = ImplementProfiling (structure Machine = Machine
56 structure Rssa = Rssa)
57 structure LimitCheck = LimitCheck (structure Rssa = Rssa)
58 structure ParallelMove = ParallelMove ()
59 structure SignalCheck = SignalCheck(structure Rssa = Rssa)
60 structure SsaToRssa = SsaToRssa (structure Rssa = Rssa
63 structure VarOperand =
66 Allocate of {operand: M.Operand.t option ref}
67 | Const of M.Operand.t
74 Allocate {operand, ...} =>
77 Option.layout M.Operand.layout (!operand))]]
78 | Const oper => seq [str "Const ", M.Operand.layout oper]
81 val operand: t -> M.Operand.t =
82 fn Allocate {operand, ...} => valOf (!operand)
86 structure IntSet = UniqueSet (val cacheSize: int = 1
91 fun hash n = Word.fromInt n
96 datatype t = T of {blocks: M.Block.t list ref,
97 chunkLabel: M.ChunkLabel.t}
99 fun label (T {chunkLabel, ...}) = chunkLabel
103 chunkLabel = M.ChunkLabel.newNoname ()}
105 fun newBlock (T {blocks, ...}, z) =
106 List.push (blocks, M.Block.T z)
110 Trace.trace ("Backend.genBlock",
111 Label.layout o R.Block.label,
114 fun eliminateDeadCode (f: R.Function.t): R.Function.t =
116 val {args, blocks, name, returns, raises, start} = R.Function.dest f
117 val {get, rem, set, ...} =
118 Property.getSetOnce (Label.plist, Property.initConst false)
119 val get = Trace.trace ("Backend.labelIsReachable",
123 R.Function.dfs (f, fn R.Block.T {label, ...} =>
127 Vector.keepAll (blocks, fn R.Block.T {label, ...} =>
135 R.Function.new {args = args,
143 fun toMachine (program: Ssa.Program.t, codegen) =
145 fun pass (name, doit, program) =
146 Control.passTypeCheck {display = Control.Layouts Rssa.Program.layouts,
148 stats = R.Program.layoutStats,
151 thunk = fn () => doit program,
152 typeCheck = R.Program.typeCheck}
153 val program = pass ("toRssa", SsaToRssa.convert, (program, codegen))
157 fun pass' ({name, doit}, sel, p) =
163 suffix = "pre.rssa"},
164 Control.No, p, Control.Layouts Program.layouts)
167 Control.passTypeCheck
168 {display = Control.Layouts
170 Program.layouts (sel r, output)),
172 stats = Program.layoutStats o sel,
174 suffix = "post.rssa",
175 thunk = fn () => doit p,
176 typeCheck = Program.typeCheck o sel}
180 fun pass ({name, doit}, p) =
181 pass' ({name = name, doit = doit}, fn p => p, p)
182 fun maybePass ({name, doit, execute}, p) =
183 if List.foldr (!Control.executePasses, execute, fn ((re, new), old) =>
184 if Regexp.Compiled.matchesAll (re, name)
187 then pass ({name = name, doit = doit}, p)
188 else (Control.messageStr (Control.Pass, name ^ " skipped"); p)
189 val p = maybePass ({name = "rssaShrink1",
190 doit = Program.shrink,
192 val p = pass ({name = "insertLimitChecks",
193 doit = LimitCheck.transform}, p)
194 val p = pass ({name = "insertSignalChecks",
195 doit = SignalCheck.transform}, p)
196 val p = pass ({name = "implementHandlers",
197 doit = ImplementHandlers.transform}, p)
198 val p = maybePass ({name = "rssaShrink2",
199 doit = Program.shrink,
201 val () = Program.checkHandlers p
202 val (p, makeProfileInfo) =
203 pass' ({name = "implementProfiling",
204 doit = ImplementProfiling.doit},
206 val p = maybePass ({name = "rssaOrderFunctions",
207 doit = Program.orderFunctions,
212 val (program, makeProfileInfo) =
213 Control.passTypeCheck
214 {display = Control.Layouts (fn ((program, _), output) =>
215 Rssa.Program.layouts (program, output)),
216 name = "rssaSimplify",
217 stats = fn (program,_) => Rssa.Program.layoutStats program,
220 thunk = fn () => rssaSimplify program,
221 typeCheck = R.Program.typeCheck o #1}
227 then saveToFile ({suffix = "rssa"},
230 Layouts Rssa.Program.layouts)
235 {display = Control.Layouts Machine.Program.layouts,
237 stats = fn _ => Layout.empty,
242 val R.Program.T {functions, handlesSignals, main, objectTypes} = program
243 (* Chunk information *)
244 val {get = labelChunk, set = setLabelChunk, ...} =
245 Property.getSetOnce (Label.plist,
246 Property.initRaise ("labelChunk", Label.layout))
247 val {get = funcChunk: Func.t -> Chunk.t, set = setFuncChunk, ...} =
248 Property.getSetOnce (Func.plist,
249 Property.initRaise ("funcChunk", Func.layout))
254 val _ = List.push (chunks, c)
258 val handlers = ref []
259 (* Set funcChunk and labelChunk. *)
262 (Chunkify.chunkify program, fn {funcs, labels} =>
265 val _ = Vector.foreach (funcs, fn f => setFuncChunk (f, c))
266 val _ = Vector.foreach (labels, fn l => setLabelChunk (l, c))
272 val frameLabels = ref []
273 val frameLayouts = ref []
274 val frameLayoutsCounter = Counter.new 0
275 val _ = IntSet.reset ()
276 val table = HashSet.new {hash = Word.fromInt o #frameOffsetsIndex}
277 val frameOffsets: Bytes.t vector list ref = ref []
278 val frameOffsetsCounter = Counter.new 0
279 val {get = frameOffsetsIndex: IntSet.t -> int, ...} =
285 val _ = List.push (frameOffsets,
288 (IntSet.toList offsets, Bytes.fromInt),
291 Counter.next frameOffsetsCounter
294 fun allFrameInfo () =
296 (* Reverse lists because the index is from back of list. *)
297 val frameLabels = Vector.fromListRev (!frameLabels)
298 val frameLayouts = Vector.fromListRev (!frameLayouts)
299 val frameOffsets = Vector.fromListRev (!frameOffsets)
301 (frameLabels, frameLayouts, frameOffsets)
303 fun getFrameLayoutsIndex {isC: bool,
305 offsets: Bytes.t list,
306 size: Bytes.t}: int =
309 frameOffsetsIndex (IntSet.fromList
310 (List.map (offsets, Bytes.toInt)))
314 List.push (frameLayouts,
315 {frameOffsetsIndex = foi,
318 val _ = List.push (frameLabels, label)
320 Counter.next frameLayoutsCounter
323 (* We need to give each frame its own layout index in two cases.
324 * 1. If we are using the C codegen, in which case we want the
325 * indices in a chunk to be consecutive integers so that gcc
326 * will use a jump table.
327 * 2. If we are profiling, we want every frame to have a
328 * different index so that it can have its own profiling info.
329 * This will be created by the call to makeProfileInfo at the
330 * end of the backend.
332 if !Control.codegen = Control.CCodegen
333 orelse !Control.codegen = Control.LLVMCodegen
334 orelse !Control.profile <> Control.ProfileNone
338 (HashSet.lookupOrInsert
339 (table, Word.fromInt foi,
340 fn {frameOffsetsIndex = foi', isC = isC', size = s', ...} =>
343 andalso Bytes.equals (size, s'),
344 fn () => {frameLayoutsIndex = new (),
345 frameOffsetsIndex = foi,
350 val {get = frameInfo: Label.t -> M.FrameInfo.t option,
351 set = setFrameInfo, ...} =
352 Property.getSetOnce (Label.plist,
353 Property.initConst NONE)
355 Trace.trace2 ("Backend.setFrameInfo",
356 Label.layout, Option.layout M.FrameInfo.layout,
359 (* The global raise operands. *)
361 val table: (Type.t vector * M.Live.t vector) list ref = ref []
363 fun raiseOperands (ts: Type.t vector): M.Live.t vector =
364 case List.peek (!table, fn (ts', _) =>
365 Vector.equals (ts, ts', Type.equals)) of
369 Vector.map (ts, fn ty =>
371 (Global.new {isRoot = false,
373 val _ = List.push (table, (ts, gs))
379 val {get = varInfo: Var.t -> {operand: VarOperand.t,
381 set = setVarInfo, ...} =
382 Property.getSetOnce (Var.plist,
383 Property.initRaise ("Backend.info", Var.layout))
385 Trace.trace2 ("Backend.setVarInfo",
386 Var.layout, VarOperand.layout o #operand, Unit.layout)
389 Trace.trace ("Backend.varInfo",
392 Layout.record [("operand", VarOperand.layout operand)])
394 val varOperand: Var.t -> M.Operand.t =
395 VarOperand.operand o #operand o varInfo
396 (* Hash tables for uniquifying globals. *)
398 fun ('a, 'b) make (equals: 'a * 'a -> bool,
399 info: 'a -> string * Type.t * 'b) =
404 value: 'b} HashSet.t = HashSet.new {hash = #hash}
405 fun get (a: 'a): M.Operand.t =
407 val (string, ty, value) = info a
408 val hash = String.hash string
412 (HashSet.lookupOrInsert
414 fn {a = a', ...} => equals (a, a'),
417 global = M.Global.new {isRoot = true,
423 (set, [], fn ({global, value, ...}, ac) =>
424 (global, value) :: ac)
429 val (allReals, globalReal) =
431 fn r => (RealX.toString r,
432 Type.real (RealX.size r),
434 val (allVectors, globalVector) =
435 make (WordXVector.equals,
436 fn v => (WordXVector.toString v,
437 Type.ofWordXVector v,
440 fun bogusOp (t: Type.t): M.Operand.t =
441 case Type.deReal t of
446 (WordSize.fromBits (Type.width t)))
448 case Type.deWord t of
449 NONE => M.Operand.Cast (bogusWord, t)
450 | SOME _ => bogusWord
452 | SOME s => globalReal (RealX.zero s)
453 fun constOperand (c: Const.t): M.Operand.t =
455 datatype z = datatype Const.t
459 Error.bug "Backend.constOperand: IntInf"
460 | Null => M.Operand.Null
461 | Real r => globalReal r
462 | Word w => M.Operand.Word w
463 | WordVector v => globalVector v
465 fun parallelMove {chunk = _,
466 dsts: M.Operand.t vector,
467 srcs: M.Operand.t vector}: M.Statement.t vector =
470 Vector.fold2 (srcs, dsts, [],
471 fn (src, dst, ac) => {src = src, dst = dst} :: ac)
473 M.Operand.Register (Register.new (M.Operand.ty r, NONE))
477 equals = M.Operand.equals,
478 move = M.Statement.move,
480 interfere = M.Operand.interfere,
484 fun runtimeOp (field: GCField.t): M.Operand.t =
486 GCField.Frontier => M.Operand.Frontier
487 | GCField.StackTop => M.Operand.StackTop
489 M.Operand.Offset {base = M.Operand.GCState,
490 offset = GCField.offset field,
491 ty = Type.ofGCField field}
492 val exnStackOp = runtimeOp GCField.ExnStack
493 val stackBottomOp = runtimeOp GCField.StackBottom
494 val stackTopOp = runtimeOp GCField.StackTop
495 fun translateOperand (oper: R.Operand.t): M.Operand.t =
497 datatype z = datatype R.Operand.t
500 ArrayOffset {base, index, offset, scale, ty} =>
502 val base = translateOperand base
504 if M.Operand.isLocation base
505 then M.Operand.ArrayOffset {base = base,
506 index = translateOperand index,
512 | Cast (z, t) => M.Operand.Cast (translateOperand z, t)
513 | Const c => constOperand c
514 | EnsuresBytesFree =>
515 Error.bug "Backend.translateOperand: EnsuresBytesFree"
516 | GCState => M.Operand.GCState
517 | Offset {base, offset, ty} =>
519 val base = translateOperand base
521 if M.Operand.isLocation base
522 then M.Operand.Offset {base = base,
530 (Word.toIntInf (Runtime.typeIndexToHeader
531 (ObjptrTycon.index opt)),
532 WordSize.objptrHeader ()))
533 | Runtime f => runtimeOp f
534 | Var {var, ...} => varOperand var
536 fun translateOperands ops = Vector.map (ops, translateOperand)
537 fun genStatement (s: R.Statement.t,
538 handlerLinkOffset: {handler: Bytes.t,
539 link: Bytes.t} option)
540 : M.Statement.t vector =
542 fun handlerOffset () = #handler (valOf handlerLinkOffset)
543 fun linkOffset () = #link (valOf handlerLinkOffset)
544 datatype z = datatype R.Statement.t
547 Bind {dst = (var, _), src, ...} =>
549 (M.Statement.move {dst = varOperand var,
550 src = translateOperand src})
553 (M.Statement.move {dst = translateOperand dst,
554 src = translateOperand src})
555 | Object {dst, header, size} =>
556 M.Statement.object {dst = varOperand (#1 dst),
559 | PrimApp {dst, prim, args} =>
561 datatype z = datatype Prim.Name.t
563 case Prim.name prim of
564 MLton_touch => Vector.new0 ()
568 {args = translateOperands args,
569 dst = Option.map (dst, varOperand o #1),
572 | ProfileLabel s => Vector.new1 (M.Statement.ProfileLabel s)
573 | SetExnStackLocal =>
574 (* ExnStack = stackTop + (offset + LABEL_SIZE) - StackBottom; *)
578 (Register.new (Type.cpointer (), NONE))
581 (Register.new (Type.csize (), NONE))
591 (Bytes.+ (handlerOffset (), Runtime.labelSize ()))),
592 WordSize.cpointer ())))),
594 prim = Prim.cpointerAdd},
596 {args = Vector.new2 (tmp1, stackBottomOp),
598 prim = Prim.cpointerDiff},
601 src = M.Operand.Cast (tmp2, Type.exnStack ())})
604 (* ExnStack = *(uint* )(stackTop + offset); *)
608 src = M.Operand.stackOffset {offset = linkOffset (),
609 ty = Type.exnStack ()}})
613 {dst = M.Operand.stackOffset {offset = handlerOffset (),
615 src = M.Operand.Label h})
617 (* *(uint* )(stackTop + offset) = ExnStack; *)
620 {dst = M.Operand.stackOffset {offset = linkOffset (),
621 ty = Type.exnStack ()},
623 | _ => Error.bug (concat
624 ["Backend.genStatement: strange statement: ",
625 R.Statement.toString s])
628 Trace.trace ("Backend.genStatement",
629 R.Statement.layout o #1, Vector.layout M.Statement.layout)
631 val bugTransfer = fn () =>
635 (WordXVector.fromString
636 "backend thought control shouldn't reach here"))),
638 func = Type.BuiltInCFunction.bug (),
640 val {get = labelInfo: Label.t -> {args: (Var.t * Type.t) vector},
641 set = setLabelInfo, ...} =
643 (Label.plist, Property.initRaise ("labelInfo", Label.layout))
645 Trace.trace2 ("Backend.setLabelInfo",
646 Label.layout, Layout.ignore, Unit.layout)
648 fun callReturnStackOffsets (xs: 'a vector,
650 shift: Bytes.t): StackOffset.t vector =
651 #1 (Vector.mapAndFold
656 val offset = Type.align (ty, offset)
658 (StackOffset.T {offset = Bytes.+ (shift, offset), ty = ty},
659 Bytes.+ (offset, Type.bytes ty))
661 val operandLive: M.Operand.t -> M.Live.t =
662 valOf o M.Live.fromOperand
663 val operandsLive: M.Operand.t vector -> M.Live.t vector =
664 fn ops => Vector.map (ops, operandLive)
667 val {get: Var.t -> bool, set, rem, ...} =
670 Property.initRaise ("Backend.toMachine.isGlobal", Var.layout))
672 Function.foreachDef (main, fn (x, _) => set (x, false))
676 (Function.foreachUse (f, fn x => set (x, true))
677 ; Function.foreachDef (f, fn (x, _) => rem x)))
681 fun genFunc (f: Function.t, isMain: bool): unit =
683 val f = eliminateDeadCode f
684 val {args, blocks, name, raises, returns, start, ...} =
686 val raises = Option.map (raises, fn ts => raiseOperands ts)
688 Option.map (returns, fn ts =>
689 callReturnStackOffsets (ts, fn t => t, Bytes.zero))
690 val chunk = funcChunk name
691 fun labelArgOperands (l: R.Label.t): M.Operand.t vector =
692 Vector.map (#args (labelInfo l), varOperand o #1)
693 fun newVarInfo (x, ty: Type.t) =
696 if isMain andalso isGlobal x
711 VarOperand.Const (M.Operand.Global
712 (M.Global.new {isRoot = true,
715 else VarOperand.Allocate {operand = ref NONE}
717 setVarInfo (x, {operand = operand,
720 fun newVarInfos xts = Vector.foreach (xts, newVarInfo)
721 (* Set the constant operands, labelInfo, and varInfo. *)
722 val _ = newVarInfos args
725 (f, fn R.Block.T {args, label, statements, transfer, ...} =>
727 val _ = setLabelInfo (label, {args = args})
728 val _ = newVarInfos args
733 fun normal () = R.Statement.foreachDef (s, newVarInfo)
736 R.Statement.Bind {dst = (var, _), isMutable, src} =>
741 fun set (z: M.Operand.t,
742 casts: Type.t list) =
746 (casts, z, fn (t, z) =>
747 M.Operand.Cast (z, t))
750 (var, {operand = VarOperand.Const z,
751 ty = M.Operand.ty z})
753 fun loop (z: R.Operand.t, casts) =
755 R.Operand.Cast (z, t) =>
757 | R.Operand.Const c =>
758 set (constOperand c, casts)
759 | R.Operand.Var {var = var', ...} =>
760 (case #operand (varInfo var') of
761 VarOperand.Const z =>
763 | VarOperand.Allocate _ =>
771 val _ = R.Transfer.foreachDef (transfer, newVarInfo)
775 (* Allocate stack slots. *)
780 val {operand, ty, ...} = varInfo x
782 {operand = (case operand of
783 VarOperand.Allocate {operand, ...} =>
789 val {handlerLinkOffset, labelInfo = labelRegInfo, ...} =
791 fun formalsStackOffsets args =
792 callReturnStackOffsets (args, fn (_, ty) => ty, Bytes.zero)
794 AllocateRegisters.allocate {formalsStackOffsets = formalsStackOffsets,
799 (* Set the frameInfo for blocks in this function. *)
802 (blocks, fn R.Block.T {kind, label, ...} =>
804 fun doit (useOffsets: bool): unit =
806 val {liveNoFormals, size, ...} = labelRegInfo label
811 (liveNoFormals, [], fn (oper, ac) =>
813 M.Operand.StackOffset (StackOffset.T {offset, ty}) =>
822 R.Kind.CReturn _ => true
824 val frameLayoutsIndex =
825 getFrameLayoutsIndex {isC = isC,
833 {frameLayoutsIndex = frameLayoutsIndex}))
836 case R.Kind.frameStyle kind of
838 | R.Kind.OffsetsAndSize => doit true
839 | R.Kind.SizeOnly => doit false
841 (* ------------------------------------------------- *)
843 (* ------------------------------------------------- *)
844 fun genTransfer (t: R.Transfer.t, chunk: Chunk.t)
845 : M.Statement.t vector * M.Transfer.t =
847 fun simple t = (Vector.new0 (), t)
850 R.Transfer.Arith {args, dst, overflow, prim, success,
853 (M.Transfer.Arith {args = translateOperands args,
854 dst = varOperand dst,
858 | R.Transfer.CCall {args, func, return} =>
859 simple (M.Transfer.CCall
860 {args = translateOperands args,
861 frameInfo = (case return of
863 | SOME l => frameInfo l),
866 | R.Transfer.Call {func, args, return} =>
868 datatype z = datatype R.Return.t
869 val (contLive, frameSize, return) =
871 Dead => (Vector.new0 (), Bytes.zero, NONE)
872 | Tail => (Vector.new0 (), Bytes.zero, NONE)
873 | NonTail {cont, handler} =>
875 val {liveNoFormals, size, ...} =
877 datatype z = datatype R.Handler.t
891 callReturnStackOffsets
892 (args, R.Operand.ty, frameSize)
896 dsts = Vector.map (dsts, M.Operand.StackOffset),
897 srcs = translateOperands args}
899 Vector.concat [operandsLive contLive,
900 Vector.map (dsts, Live.StackOffset)]
902 M.Transfer.Call {label = funcToLabel func,
906 (setupArgs, transfer)
908 | R.Transfer.Goto {dst, args} =>
909 (parallelMove {srcs = translateOperands args,
910 dsts = labelArgOperands dst,
911 chunk = labelChunk dst},
913 | R.Transfer.Raise srcs =>
914 (M.Statement.moves {dsts = Vector.map (valOf raises,
916 srcs = translateOperands srcs},
918 | R.Transfer.Return xs =>
919 (parallelMove {chunk = chunk,
920 dsts = Vector.map (valOf returns,
921 M.Operand.StackOffset),
922 srcs = translateOperands xs},
924 | R.Transfer.Switch switch =>
926 val R.Switch.T {cases, default, size, test} =
930 (case (Vector.length cases, default) of
931 (0, NONE) => bugTransfer ()
933 M.Transfer.Goto (#2 (Vector.sub (cases, 0)))
934 | (0, SOME dst) => M.Transfer.Goto dst
941 test = translateOperand test}))
945 Trace.trace ("Backend.genTransfer",
946 R.Transfer.layout o #1,
947 Layout.tuple2 (Vector.layout M.Statement.layout,
950 fun genBlock (R.Block.T {args, kind, label, statements, transfer,
954 if Label.equals (label, start)
956 val live = #live (labelRegInfo start)
959 (returns, fn returns =>
960 Vector.map (returns, Live.StackOffset))
964 {label = funcToLabel name,
966 live = operandsLive live,
969 statements = Vector.new0 (),
970 transfer = M.Transfer.Goto start})
973 val {live, liveNoFormals, size, ...} = labelRegInfo label
974 val chunk = labelChunk label
977 (Vector.map (statements, fn s =>
978 genStatement (s, handlerLinkOffset)))
979 val (preTransfer, transfer) = genTransfer (transfer, chunk)
980 val (kind, live, pre) =
984 val srcs = callReturnStackOffsets (args, #2, size)
986 (M.Kind.Cont {args = Vector.map (srcs,
988 frameInfo = valOf (frameInfo label)},
992 dsts = Vector.map (args, varOperand o #1),
993 srcs = Vector.map (srcs, M.Operand.StackOffset)})
995 | R.Kind.CReturn {func, ...} =>
998 case Vector.length args of
1000 | 1 => SOME (operandLive
1002 (#1 (Vector.sub (args, 0)))))
1003 | _ => Error.bug "Backend.genBlock: CReturn"
1005 (M.Kind.CReturn {dst = dst,
1006 frameInfo = frameInfo label,
1015 (handlers, {chunkLabel = Chunk.label chunk,
1017 val dsts = Vector.map (args, varOperand o #1)
1019 raiseOperands (Vector.map (dsts, M.Operand.ty))
1022 {frameInfo = valOf (frameInfo label),
1027 srcs = Vector.map (handles, Live.toOperand)})
1029 | R.Kind.Jump => (M.Kind.Jump, live, Vector.new0 ())
1030 val (first, statements) =
1031 if !Control.profile = Control.ProfileTimeLabel
1033 case (if Vector.isEmpty statements
1035 else (case Vector.first statements of
1036 s as M.Statement.ProfileLabel _ =>
1041 (concat ["Backend.genBlock: ",
1042 "missing ProfileLabel in ",
1043 Label.toString label])
1046 Vector.dropPrefix (statements, 1))
1047 else (Vector.new0 (), statements)
1049 Vector.concat [first, pre, statements, preTransfer]
1051 Option.map (returns, fn returns =>
1052 Vector.map (returns, Live.StackOffset))
1054 Chunk.newBlock (chunk,
1057 live = operandsLive live,
1060 statements = statements,
1061 transfer = transfer})
1063 val genBlock = traceGenBlock genBlock
1064 val _ = Vector.foreach (blocks, genBlock)
1068 else Vector.foreach (blocks, R.Block.clear)
1073 Trace.trace2 ("Backend.genFunc",
1074 Func.layout o Function.name, Bool.layout, Unit.layout)
1076 (* Generate the main function first.
1077 * Need to do this in order to set globals.
1079 val _ = genFunc (main, true)
1080 val _ = List.foreach (functions, fn f => genFunc (f, false))
1081 val chunks = !chunks
1082 fun chunkToMachine (Chunk.T {chunkLabel, blocks}) =
1084 val blocks = Vector.fromList (!blocks)
1085 val regMax = CType.memo (fn _ => ref ~1)
1086 val regsNeedingIndex =
1088 (blocks, [], fn (b, ac) =>
1090 (b, ac, fn (z, ac) =>
1092 M.Operand.Register r =>
1093 (case Register.indexOpt r of
1097 val z = regMax (Type.toCType (Register.ty r))
1108 (regsNeedingIndex, fn r =>
1110 val z = regMax (Type.toCType (Register.ty r))
1113 val _ = Register.setIndex (r, i)
1118 Machine.Chunk.T {chunkLabel = chunkLabel,
1120 regMax = ! o regMax}
1122 val mainName = R.Function.name main
1123 val main = {chunkLabel = Chunk.label (funcChunk mainName),
1124 label = funcToLabel mainName}
1125 val chunks = List.revMap (chunks, chunkToMachine)
1126 (* The clear is necessary because properties have been attached to Funcs
1127 * and Labels, and they appear as labels in the resulting program.
1129 val _ = List.foreach (chunks, fn M.Chunk.T {blocks, ...} =>
1130 Vector.foreach (blocks, Label.clear o M.Block.label))
1131 val (frameLabels, frameLayouts, frameOffsets) = allFrameInfo ()
1132 val maxFrameSize: Bytes.t =
1134 (chunks, Bytes.zero, fn (M.Chunk.T {blocks, ...}, max) =>
1136 (blocks, max, fn (M.Block.T {kind, statements, transfer, ...}, max) =>
1138 fun doOperand (z: M.Operand.t, max: Bytes.t): Bytes.t =
1140 datatype z = datatype M.Operand.t
1143 ArrayOffset {base, index, ...} =>
1144 doOperand (base, doOperand (index, max))
1145 | Cast (z, _) => doOperand (z, max)
1146 | Contents {oper, ...} => doOperand (oper, max)
1147 | Offset {base, ...} => doOperand (base, max)
1148 | StackOffset (StackOffset.T {offset, ty}) =>
1149 Bytes.max (Bytes.+ (offset, Type.bytes ty), max)
1153 case M.Kind.frameInfoOpt kind of
1155 | SOME (M.FrameInfo.T {frameLayoutsIndex, ...}) =>
1158 #size (Vector.sub (frameLayouts, frameLayoutsIndex)))
1161 (statements, max, fn (s, max) =>
1162 M.Statement.foldOperands (s, max, doOperand))
1164 M.Transfer.foldOperands (transfer, max, doOperand)
1168 val maxFrameSize = Bytes.alignWord32 maxFrameSize
1169 val profileInfo = makeProfileInfo {frames = frameLabels}
1173 frameLayouts = frameLayouts,
1174 frameOffsets = frameOffsets,
1175 handlesSignals = handlesSignals,
1177 maxFrameSize = maxFrameSize,
1178 objectTypes = objectTypes,
1179 profileInfo = profileInfo,
1180 reals = allReals (),
1181 vectors = allVectors ()}
1185 fun pass' ({name, doit}, sel, p) =
1191 suffix = "pre.machine"},
1192 Control.No, p, Control.Layouts Program.layouts)
1195 Control.passTypeCheck
1196 {display = Control.Layouts
1198 Program.layouts (sel r, output)),
1200 stats = fn _ => Layout.empty,
1202 suffix = "post.machine",
1203 thunk = fn () => doit p,
1204 typeCheck = Program.typeCheck o sel}
1208 fun pass ({name, doit}, p) =
1209 pass' ({name = name, doit = doit}, fn p => p, p)
1210 fun maybePass ({name, doit, execute}, p) =
1211 if List.foldr (!Control.executePasses, execute, fn ((re, new), old) =>
1212 if Regexp.Compiled.matchesAll (re, name)
1215 then pass ({name = name, doit = doit}, p)
1216 else (Control.messageStr (Control.Pass, name ^ " skipped"); p)
1222 val a = Array.fromVector v
1223 val () = Array.shuffle a
1227 val Machine.Program.T
1228 {chunks, frameLayouts, frameOffsets,
1229 handlesSignals, main, maxFrameSize,
1230 objectTypes, profileInfo,
1232 val chunks = Vector.fromList chunks
1233 val chunks = shuffle chunks
1236 (chunks, fn Machine.Chunk.T {blocks, chunkLabel, regMax} =>
1238 {blocks = shuffle blocks,
1239 chunkLabel = chunkLabel,
1241 val chunks = Vector.toList chunks
1245 frameLayouts = frameLayouts,
1246 frameOffsets = frameOffsets,
1247 handlesSignals = handlesSignals,
1249 maxFrameSize = maxFrameSize,
1250 objectTypes = objectTypes,
1251 profileInfo = profileInfo,
1256 val program = maybePass ({name = "machineShuffle",
1258 execute = false}, program)