1 (* Copyright (C) 2009 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 x86GenerateTransfers(S: X86_GENERATE_TRANSFERS_STRUCTS): X86_GENERATE_TRANSFERS =
24 structure CFunction = CFunction
27 val ones : int * WordSize.t -> WordX.t
28 = fn (i, ws) => (WordX.notb o WordX.lshift)
30 WordX.fromIntInf (IntInf.fromInt i, ws))
32 val tracerTop = x86.tracerTop
34 structure x86LiveTransfers
35 = x86LiveTransfers(structure x86 = x86
36 structure x86Liveness = x86Liveness
37 structure x86JumpInfo = x86JumpInfo
38 structure x86LoopInfo = x86LoopInfo)
40 val pointerSize = x86MLton.pointerSize
41 val wordSize = x86MLton.wordSize
65 {frontierReg = Register.esp,
66 stackTopReg = Register.ebp,
67 transferRegs = fn Entry.Jump _ => transferRegs
68 | Entry.CReturn _ => Register.eax::Register.al::transferRegs
96 {frontierReg = Register.edi,
97 stackTopReg = Register.ebp,
98 transferRegs = fn Entry.Jump _ => transferRegs
99 | Entry.CReturn _ => Register.eax::Register.al::transferRegs
127 {frontierReg = Register.esp,
128 stackTopReg = Register.ebp,
129 transferRegs = fn Entry.Jump _ => transferRegs
130 | Entry.CReturn _ => Register.eax::Register.al::transferRegs
134 val transferFltRegs : Entry.t -> Int.t = fn Entry.Jump _ => 6
135 | Entry.CReturn _ => 6
138 val indexReg = x86.Register.eax
140 val stackTop = x86MLton.gcState_stackTopContents
141 val frontier = x86MLton.gcState_frontierContents
143 datatype gef = GEF of {generate : gef ->
147 Assembly.t AppendList.t,
150 transfer : Transfer.t} ->
151 Assembly.t AppendList.t,
155 Assembly.t AppendList.t}
157 fun generateTransfers {chunk as Chunk.T {data, blocks, ...},
159 newProfileLabel: x86.ProfileLabel.t -> x86.ProfileLabel.t,
160 liveInfo : x86Liveness.LiveInfo.t,
161 jumpInfo : x86JumpInfo.t,
165 val {frontierReg, stackTopReg, transferRegs} =
171 val allClasses = !x86MLton.Classes.allClasses
172 val livenessClasses = !x86MLton.Classes.livenessClasses
173 val livenessClasses = ClassSet.add(livenessClasses,
174 x86MLton.Classes.StaticNonTemp)
175 val nonlivenessClasses = ClassSet.-(allClasses, livenessClasses)
176 val holdClasses = !x86MLton.Classes.holdClasses
177 val farflushClasses = ClassSet.-(nonlivenessClasses, holdClasses)
178 val nearflushClasses = ClassSet.-(nonlivenessClasses, holdClasses)
179 val runtimeClasses = !x86MLton.Classes.runtimeClasses
180 val cstaticClasses = !x86MLton.Classes.cstaticClasses
181 val heapClasses = !x86MLton.Classes.heapClasses
182 val ccallflushClasses = ClassSet.+(cstaticClasses, heapClasses)
184 fun removeHoldMemLocs memlocs
187 fn m => not (ClassSet.contains(holdClasses, MemLoc.class m)))
189 val stackAssume = {register = stackTopReg,
190 memloc = stackTop (),
194 val frontierAssume = {register = frontierReg,
195 memloc = frontier (),
199 val cStackAssume = {register = Register.esp,
200 memloc = x86MLton.c_stackPContents,
201 weight = 2048, (* ??? *)
204 val picUsesEbxAssume = {register = Register.ebx,
205 memloc = x86MLton.globalOffsetTableContents,
206 weight = 2048, (* ??? *)
212 val l = frontierAssume :: stackAssume :: l
213 val l = if reserveEsp then cStackAssume :: l else l
214 val l = if picUsesEbx then picUsesEbxAssume :: l else l
216 Assembly.directive_assume {assumes = l }
219 fun runtimeTransfer live setup trans
222 (Assembly.directive_force
223 {commit_memlocs = removeHoldMemLocs live,
224 commit_classes = ClassSet.empty,
225 remove_memlocs = MemLocSet.empty,
226 remove_classes = ClassSet.empty,
227 dead_memlocs = MemLocSet.empty,
228 dead_classes = ClassSet.empty}),
231 [(Assembly.directive_clearflt ()),
232 (Assembly.directive_force
233 {commit_memlocs = MemLocSet.empty,
234 commit_classes = farflushClasses,
235 remove_memlocs = MemLocSet.empty,
236 remove_classes = ClassSet.empty,
237 dead_memlocs = MemLocSet.empty,
238 dead_classes = ClassSet.empty})],
241 fun farEntry l = AppendList.cons (blockAssumes [], l)
243 fun farTransfer live setup trans
246 (Assembly.directive_force
247 {commit_memlocs = removeHoldMemLocs live,
248 commit_classes = ClassSet.empty,
249 remove_memlocs = MemLocSet.empty,
250 remove_classes = ClassSet.empty,
251 dead_memlocs = MemLocSet.empty,
252 dead_classes = ClassSet.empty}),
255 [(Assembly.directive_cache
256 {caches = [{register = stackTopReg,
257 memloc = stackTop (),
259 {register = frontierReg,
260 memloc = frontier (),
262 (Assembly.directive_clearflt ()),
263 (Assembly.directive_force
264 {commit_memlocs = MemLocSet.empty,
265 commit_classes = farflushClasses,
266 remove_memlocs = MemLocSet.empty,
267 remove_classes = ClassSet.empty,
268 dead_memlocs = MemLocSet.empty,
269 dead_classes = ClassSet.empty})],
272 val profileStackTopCommit' =
273 x86.Assembly.directive_force
274 {commit_memlocs = MemLocSet.singleton (stackTop ()),
275 commit_classes = ClassSet.empty,
276 remove_memlocs = MemLocSet.empty,
277 remove_classes = ClassSet.empty,
278 dead_memlocs = MemLocSet.empty,
279 dead_classes = ClassSet.empty}
280 val profileStackTopCommit =
281 if !Control.profile <> Control.ProfileNone
282 then AppendList.single profileStackTopCommit'
283 else AppendList.empty
287 ("x86GenerateTransfers.verifyLiveInfo",
288 fn () => x86Liveness.LiveInfo.verifyLiveInfo {chunk = chunk,
289 liveInfo = liveInfo})
292 ("x86GenerateTransfers.verifyJumpInfo",
293 fn () => x86JumpInfo.verifyJumpInfo {chunk = chunk,
294 jumpInfo = jumpInfo})
298 ("x86GenerateTransfers.verifyEntryTransfer",
299 fn () => x86EntryTransfer.verifyEntryTransfer {chunk = chunk})
302 val {get: Label.t -> {block:Block.t},
305 = Property.destGetSetOnce
306 (Label.plist, Property.initRaise ("gotoInfo", Label.layout))
311 fn (block as Block.T {entry, ...}, labels)
313 val label = Entry.label entry
315 set(label, {block = block}) ;
323 (labels, ([], false),
324 fn (label, (labels, b))
325 => case x86JumpInfo.getNear (jumpInfo, label)
326 of x86JumpInfo.Count 0
328 val {block = Block.T {transfer, ...}}
332 (Transfer.nearTargets transfer,
334 => x86JumpInfo.decNear (jumpInfo, label));
337 | _ => (label::labels, b))
341 else List.map (labels, #block o get)
343 val blocks = loop labels
347 val chunk = Chunk.T {data = data, blocks = blocks}
351 = x86LoopInfo.createLoopInfo {chunk = chunk, farLoops = false}
353 = fn label => isLoopHeader(loopInfo, label)
357 = x86LiveTransfers.computeLiveTransfers
359 transferRegs = transferRegs,
360 transferFltRegs = transferFltRegs,
365 val getLiveRegsTransfers
366 = #1 o x86LiveTransfers.getLiveTransfers
367 val getLiveFltRegsTransfers
368 = #2 o x86LiveTransfers.getLiveTransfers
370 val {get = getLayoutInfo : Label.t -> Block.t option,
372 destroy = destLayoutInfo}
373 = Property.destGetSet(Label.plist,
374 Property.initRaise ("layoutInfo", Label.layout))
378 fn block as Block.T {entry, ...}
380 val label = Entry.label entry
382 setLayoutInfo(label, SOME block)
385 val {get = getProfileLabel : Label.t -> ProfileLabel.t option,
386 set = setProfileLabel,
387 destroy = destProfileLabel}
388 = Property.destGetSetOnce
390 Property.initRaise ("profileLabel", Label.layout))
394 fn Block.T {entry, profileLabel, ...}
396 val label = Entry.label entry
398 setProfileLabel(label, profileLabel)
403 val queue = ref (Queue.empty ())
405 fun enque x = queue := Queue.enque(!queue, x)
406 fun push x = stack := x::(!stack)
408 fun deque () = (case (!stack)
409 of [] => (case Queue.deque(!queue)
411 | SOME(queue', x) => (queue := queue';
413 | x::stack' => (stack := stack';
417 fun pushCompensationBlock {label, id}
419 val label' = Label.new label
420 val live = getLive(liveInfo, label)
421 val profileLabel = getProfileLabel label
422 val profileLabel' = Option.map (profileLabel, newProfileLabel)
424 = Block.T {entry = Entry.jump {label = label'},
425 profileLabel = profileLabel',
427 = (Assembly.directive_restoreregalloc
428 {live = MemLocSet.add
430 (LiveSet.toMemLocSet live,
435 transfer = Transfer.goto {target = label}}
437 setLive(liveInfo, label', live);
438 setProfileLabel(label', profileLabel');
439 incNear(jumpInfo, label');
440 Assert.assert("x86GenerateTransfers.pushCompensationBlock",
441 fn () => getNear(jumpInfo, label') = Count 1);
442 x86LiveTransfers.setLiveTransfersEmpty(liveTransfers, label');
443 setLayoutInfo(label', SOME block);
448 val c_stackP = x86MLton.c_stackPContentsOperand
452 then AppendList.empty
455 ((* explicit cache in case there are no args *)
456 Assembly.directive_cache
457 {caches = [{register = Register.esp,
458 memloc = valOf (Operand.deMemloc c_stackP),
461 fun unreserveEsp () =
463 then AppendList.empty
464 else AppendList.single (Assembly.directive_unreserve
465 {registers = [Register.esp]})
468 val set: (word * String.t * Label.t) HashSet.t =
469 HashSet.new {hash = #1}
471 fun makeDarwinSymbolStubLabel name =
473 val hash = String.hash name
475 (#3 o HashSet.lookupOrInsert)
477 fn (hash', name', _) =>
478 hash = hash' andalso name = name',
481 Label.newString (concat ["L_", name, "_stub"])))
484 fun makeDarwinSymbolStubs () =
486 (set, [], fn ((_, name, label), assembly) =>
487 (Assembly.pseudoop_symbol_stub ()) ::
488 (Assembly.label label) ::
489 (Assembly.pseudoop_indirect_symbol (Label.fromString name)) ::
490 (Assembly.instruction_hlt ()) ::
491 (Assembly.instruction_hlt ()) ::
492 (Assembly.instruction_hlt ()) ::
493 (Assembly.instruction_hlt ()) ::
494 (Assembly.instruction_hlt ()) ::
498 datatype z = datatype Entry.t
499 datatype z = datatype Transfer.t
500 fun generateAll (gef as GEF {effect,...})
501 {label, falling, unique} :
502 Assembly.t AppendList.t
503 = (case getLayoutInfo label
504 of NONE => AppendList.empty
505 | SOME (Block.T {entry, profileLabel, statements, transfer})
507 val _ = setLayoutInfo(label, NONE)
509 val isLoopHeader = fn _ => false
514 if isLoopHeader label handle _ => false
517 (Assembly.pseudoop_p2align
520 SOME (Immediate.int 7)))
522 then AppendList.empty
525 (Assembly.pseudoop_p2align
530 if falling andalso unique
531 then AppendList.empty
533 (* near entry & live transfer assumptions *)
537 (getLiveRegsTransfers
538 (liveTransfers, label),
539 fn (memloc,register,sync)
540 => {register = register,
545 (Assembly.directive_fltassume
548 (getLiveFltRegsTransfers
549 (liveTransfers, label),
558 (Assembly.label label),
560 (ProfileLabel.toAssemblyOpt profileLabel),
567 | CReturn {dsts, frameInfo, func, label}
570 if Vector.isEmpty dsts
571 then AppendList.empty
576 (Operand.cReturnTemps
577 (CFunction.return func),
580 (AppendList.fromList o Vector.fold2)
581 (dsts, srcs, [], fn ((dst,dstsize),src,stmts) =>
582 case Size.class dstsize of
584 (x86.Assembly.instruction_mov
586 src = Operand.memloc src,
587 size = dstsize})::stmts
589 (x86.Assembly.instruction_pfmov
591 src = Operand.memloc src,
592 size = dstsize})::stmts
593 | _ => Error.bug "x86GenerateTransfers.generateAll: CReturn")
599 val FrameInfo.T {size, frameLayoutsIndex}
605 = x86MLton.gcState_stackTopContentsOperand ()
607 = x86.Operand.immediate_int (~ size)
610 ((* stackTop += bytes *)
611 x86.Assembly.instruction_binal
612 {oper = x86.Instruction.ADD,
616 profileStackTopCommit)
623 [Assembly.pseudoop_p2align
624 (Immediate.int 4, NONE, NONE),
625 Assembly.pseudoop_long
626 [Immediate.int frameLayoutsIndex],
627 Assembly.label label],
629 (ProfileLabel.toAssemblyOpt profileLabel),
630 if CFunction.maySwitchThreads func
631 then (* entry from far assumptions *)
633 else (* near entry & live transfer assumptions *)
638 (getLiveRegsTransfers
639 (liveTransfers, label),
640 fn (memloc,register,sync)
641 => {register = register,
646 (Assembly.directive_fltassume
649 (getLiveFltRegsTransfers
650 (liveTransfers, label),
658 AppendList.append (near label, getReturn ())
661 => AppendList.appends
663 [Assembly.pseudoop_p2align
664 (Immediate.int 4, NONE, NONE),
665 Assembly.pseudoop_global label,
666 Assembly.pseudoop_hidden label,
667 Assembly.label label],
669 (ProfileLabel.toAssemblyOpt profileLabel),
670 (* entry from far assumptions *)
671 (farEntry AppendList.empty)]
673 frameInfo = FrameInfo.T {size,
679 [Assembly.pseudoop_p2align
680 (Immediate.int 4, NONE, NONE),
681 Assembly.pseudoop_long
682 [Immediate.int frameLayoutsIndex],
683 Assembly.label label],
685 (ProfileLabel.toAssemblyOpt profileLabel),
686 (* entry from far assumptions *)
690 = x86MLton.gcState_stackTopContentsOperand ()
692 = x86.Operand.immediate_int (~ size)
695 ((* stackTop += bytes *)
696 x86.Assembly.instruction_binal
697 {oper = x86.Instruction.ADD,
701 profileStackTopCommit)
703 | Handler {frameInfo = (FrameInfo.T
704 {frameLayoutsIndex, size}),
707 => AppendList.appends
709 [Assembly.pseudoop_p2align
710 (Immediate.int 4, NONE, NONE),
711 Assembly.pseudoop_long
712 [Immediate.int frameLayoutsIndex],
713 Assembly.label label],
715 (ProfileLabel.toAssemblyOpt profileLabel),
716 (* entry from far assumptions *)
720 = x86MLton.gcState_stackTopContentsOperand ()
722 = x86.Operand.immediate_int (~ size)
725 ((* stackTop += bytes *)
726 x86.Assembly.instruction_binal
727 {oper = x86.Instruction.ADD,
731 profileStackTopCommit)
735 [if !Control.Native.commented > 1
736 then AppendList.single
737 (Assembly.comment (Entry.toString entry))
738 else AppendList.empty,
739 if !Control.Native.commented > 2
740 then AppendList.single
743 (getLive(liveInfo, label),
747 MemLoc.toString memloc,
749 else AppendList.empty,
757 (livenessTransfer {transfer = transfer,
758 liveInfo = liveInfo})),
759 fn (assembly,(statements,live))
761 val Liveness.T {liveIn,dead, ...}
762 = livenessAssembly {assembly = assembly,
765 (if LiveSet.isEmpty dead
766 then assembly::statements
768 (Assembly.directive_force
769 {commit_memlocs = MemLocSet.empty,
770 commit_classes = ClassSet.empty,
771 remove_memlocs = MemLocSet.empty,
772 remove_classes = ClassSet.empty,
773 dead_memlocs = LiveSet.toMemLocSet dead,
774 dead_classes = ClassSet.empty})::
779 val statements = AppendList.fromList statements
781 val transfer = effect gef {label = label,
790 and effectDefault (gef as GEF {fall,...})
791 {label, transfer} : Assembly.t AppendList.t
793 (if !Control.Native.commented > 1
794 then AppendList.single
796 (Transfer.toString transfer))
797 else AppendList.empty,
802 live = getLive(liveInfo, target)}
803 | Iff {condition, truee, falsee}
806 = Instruction.condition_negate condition
809 = getLive(liveInfo, truee)
810 val truee_live_length
811 = LiveSet.size truee_live
814 = getLive(liveInfo, falsee)
815 val falsee_live_length
816 = LiveSet.size falsee_live
820 val id = Directive.Id.new ()
822 = pushCompensationBlock {label = falsee,
827 [Assembly.directive_force
828 {commit_memlocs = MemLocSet.empty,
829 commit_classes = nearflushClasses,
830 remove_memlocs = MemLocSet.empty,
831 remove_classes = ClassSet.empty,
832 dead_memlocs = MemLocSet.empty,
833 dead_classes = ClassSet.empty},
834 Assembly.instruction_jcc
835 {condition = condition_neg,
836 target = Operand.label falsee'},
837 Assembly.directive_saveregalloc
838 {live = MemLocSet.add
840 (LiveSet.toMemLocSet falsee_live,
851 val id = Directive.Id.new ()
852 val truee' = pushCompensationBlock {label = truee,
857 [Assembly.directive_force
858 {commit_memlocs = MemLocSet.empty,
859 commit_classes = nearflushClasses,
860 remove_memlocs = MemLocSet.empty,
861 remove_classes = ClassSet.empty,
862 dead_memlocs = MemLocSet.empty,
863 dead_classes = ClassSet.empty},
864 Assembly.instruction_jcc
865 {condition = condition,
866 target = Operand.label truee'},
867 Assembly.directive_saveregalloc
868 {live = MemLocSet.add
870 (LiveSet.toMemLocSet truee_live,
876 live = falsee_live}))
879 case (getLayoutInfo truee,
880 getLayoutInfo falsee)
881 of (NONE, SOME _) => fall_falsee ()
882 | (SOME _, NONE) => fall_truee ()
886 = if truee_live_length <= falsee_live_length
891 = case (getNear(jumpInfo, truee),
892 getNear(jumpInfo, falsee))
893 of (Count 1, Count 1) => default' ()
894 | (Count 1, _) => fall_truee ()
895 | (_, Count 1) => fall_falsee ()
898 case (getLoopDistance(loopInfo, label, truee),
899 getLoopDistance(loopInfo, label, falsee))
900 of (NONE, NONE) => default ()
901 | (SOME _, NONE) => fall_truee ()
902 | (NONE, SOME _) => fall_falsee ()
903 | (SOME dtruee, SOME dfalsee)
904 => (case Int.compare(dtruee, dfalsee)
905 of EQUAL => default ()
906 | LESS => fall_falsee ()
907 | GREATER => fall_truee ())
910 | Switch {test, cases, default}
912 val Liveness.T {dead, ...}
913 = livenessTransfer {transfer = transfer,
917 = case Operand.size test
922 = getLive(liveInfo, default)
925 = Transfer.Cases.mapToList
930 = getLive(liveInfo, target)
931 val id = Directive.Id.new ()
932 val target' = pushCompensationBlock
937 [Assembly.instruction_cmp
939 src2 = Operand.immediate_word k,
941 Assembly.instruction_jcc
942 {condition = Instruction.E,
943 target = Operand.label target'},
944 Assembly.directive_saveregalloc
945 {live = MemLocSet.add
947 (LiveSet.toMemLocSet target_live,
955 (Assembly.directive_force
956 {commit_memlocs = MemLocSet.empty,
957 commit_classes = nearflushClasses,
958 remove_memlocs = MemLocSet.empty,
959 remove_classes = ClassSet.empty,
960 dead_memlocs = MemLocSet.empty,
961 dead_classes = ClassSet.empty}),
962 AppendList.appends cases,
963 if LiveSet.isEmpty dead
964 then AppendList.empty
965 else AppendList.single
966 (Assembly.directive_force
967 {commit_memlocs = MemLocSet.empty,
968 commit_classes = ClassSet.empty,
969 remove_memlocs = MemLocSet.empty,
970 remove_classes = ClassSet.empty,
971 dead_memlocs = LiveSet.toMemLocSet dead,
972 dead_classes = ClassSet.empty}),
975 live = default_live})]
977 | Tail {target, live}
978 => (* flushing at far transfer *)
982 (Assembly.instruction_jmp
983 {target = Operand.label target,
985 | NonTail {target, live, return, handler, size}
989 of SOME handler => enque handler
993 = x86MLton.stackTopTempContentsOperand ()
994 val stackTopTempMinusWordDeref'
995 = x86MLton.stackTopTempMinusWordDeref ()
996 val stackTopTempMinusWordDeref
997 = x86MLton.stackTopTempMinusWordDerefOperand ()
999 = x86MLton.gcState_stackTopContentsOperand ()
1000 val stackTopMinusWordDeref'
1001 = x86MLton.gcState_stackTopMinusWordDeref ()
1002 val stackTopMinusWordDeref
1003 = x86MLton.gcState_stackTopMinusWordDerefOperand ()
1005 = x86.Operand.immediate_int size
1007 val liveReturn = x86Liveness.LiveInfo.getLive(liveInfo, return)
1011 => x86Liveness.LiveInfo.getLive(liveInfo, handler)
1012 | _ => LiveSet.empty
1013 val live = MemLocSet.unions [live,
1014 LiveSet.toMemLocSet liveReturn,
1015 LiveSet.toMemLocSet liveHandler]
1017 (* flushing at far transfer *)
1019 (if !Control.profile <> Control.ProfileNone
1020 then (AppendList.fromList
1021 [(* stackTopTemp = stackTop + bytes *)
1022 x86.Assembly.instruction_mov
1023 {dst = stackTopTemp,
1025 size = pointerSize},
1026 x86.Assembly.instruction_binal
1027 {oper = x86.Instruction.ADD,
1030 size = pointerSize},
1031 (* *(stackTopTemp - WORD_SIZE) = return *)
1032 x86.Assembly.instruction_mov
1033 {dst = stackTopTempMinusWordDeref,
1034 src = Operand.immediate_label return,
1035 size = pointerSize},
1036 x86.Assembly.directive_force
1037 {commit_memlocs = MemLocSet.singleton stackTopTempMinusWordDeref',
1038 commit_classes = ClassSet.empty,
1039 remove_memlocs = MemLocSet.empty,
1040 remove_classes = ClassSet.empty,
1041 dead_memlocs = MemLocSet.empty,
1042 dead_classes = ClassSet.empty},
1043 (* stackTop = stackTopTemp *)
1044 x86.Assembly.instruction_mov
1047 size = pointerSize},
1048 profileStackTopCommit'])
1049 else (AppendList.fromList
1050 [(* stackTop += bytes *)
1051 x86.Assembly.instruction_binal
1052 {oper = x86.Instruction.ADD,
1055 size = pointerSize},
1056 (* *(stackTop - WORD_SIZE) = return *)
1057 x86.Assembly.instruction_mov
1058 {dst = stackTopMinusWordDeref,
1059 src = Operand.immediate_label return,
1060 size = pointerSize},
1061 x86.Assembly.directive_force
1062 {commit_memlocs = MemLocSet.singleton stackTopMinusWordDeref',
1063 commit_classes = ClassSet.empty,
1064 remove_memlocs = MemLocSet.empty,
1065 remove_classes = ClassSet.empty,
1066 dead_memlocs = MemLocSet.empty,
1067 dead_classes = ClassSet.empty}]))
1069 (Assembly.instruction_jmp
1070 {target = Operand.label target,
1071 absolute = false})))
1075 val stackTopMinusWordDeref
1076 = x86MLton.gcState_stackTopMinusWordDerefOperand ()
1078 (* flushing at far transfer *)
1082 (* jmp *(stackTop - WORD_SIZE) *)
1083 (x86.Assembly.instruction_jmp
1084 {target = stackTopMinusWordDeref,
1090 = x86MLton.gcState_exnStackContentsOperand ()
1092 = x86MLton.stackTopTempContentsOperand ()
1094 = x86MLton.gcState_stackTopContentsOperand ()
1096 = x86MLton.gcState_stackBottomContentsOperand ()
1098 (* flushing at far transfer *)
1100 (if !Control.profile <> Control.ProfileNone
1101 then (AppendList.fromList
1102 [(* stackTopTemp = stackBottom + exnStack *)
1103 x86.Assembly.instruction_mov
1104 {dst = stackTopTemp,
1106 size = pointerSize},
1107 x86.Assembly.instruction_binal
1108 {oper = x86.Instruction.ADD,
1111 size = pointerSize},
1112 (* stackTop = stackTopTemp *)
1113 x86.Assembly.instruction_mov
1116 size = pointerSize},
1117 profileStackTopCommit'])
1118 else (AppendList.fromList
1119 [(* stackTop = stackBottom + exnStack *)
1120 x86.Assembly.instruction_mov
1123 size = pointerSize},
1124 x86.Assembly.instruction_binal
1125 {oper = x86.Instruction.ADD,
1128 size = pointerSize}]))
1130 (* jmp *(stackTop - WORD_SIZE) *)
1131 (x86.Assembly.instruction_jmp
1132 {target = x86MLton.gcState_stackTopMinusWordDerefOperand (),
1135 | CCall {args, frameInfo, func, return}
1137 datatype z = datatype CFunction.Convention.t
1138 datatype z = datatype CFunction.SymbolScope.t
1139 datatype z = datatype CFunction.Target.t
1140 val CFunction.T {convention,
1144 val stackTopMinusWordDeref
1145 = x86MLton.gcState_stackTopMinusWordDerefOperand ()
1146 val Liveness.T {dead, ...}
1147 = livenessTransfer {transfer = transfer,
1148 liveInfo = liveInfo}
1149 val c_stackP = x86MLton.c_stackPContentsOperand
1150 val c_stackPDerefFloat = x86MLton.c_stackPDerefFloatOperand
1151 val c_stackPDerefDouble = x86MLton.c_stackPDerefDoubleOperand
1152 val applyFFTempFun = x86MLton.applyFFTempFunContentsOperand
1153 val applyFFTempArg = x86MLton.applyFFTempArgContentsOperand
1154 val (fptrArg, args) =
1156 Direct _ => (AppendList.empty, args)
1159 val (fptrArg, args) =
1161 fptrArg::args => (fptrArg, args)
1162 | _ => Error.bug "x86GenerateTransfers.generateAll: CCall"
1165 (Assembly.instruction_mov
1167 dst = applyFFTempFun,
1168 size = #2 fptrArg}),
1171 val (pushArgs, size_args)
1173 (args, (AppendList.empty, 0),
1174 fn ((arg, size), (assembly_args, size_args)) =>
1176 val (assembly_arg, size_arg) =
1177 if Size.eq (size, Size.DBLE)
1178 then (AppendList.fromList
1179 [Assembly.instruction_binal
1180 {oper = Instruction.SUB,
1182 src = Operand.immediate_int 8,
1183 size = pointerSize},
1184 Assembly.instruction_pfmov
1186 dst = c_stackPDerefDouble,
1189 else if Size.eq (size, Size.SNGL)
1190 then (AppendList.fromList
1191 [Assembly.instruction_binal
1192 {oper = Instruction.SUB,
1194 src = Operand.immediate_int 4,
1195 size = pointerSize},
1196 Assembly.instruction_pfmov
1198 dst = c_stackPDerefFloat,
1201 else if Size.eq (size, Size.BYTE)
1202 orelse Size.eq (size, Size.WORD)
1203 then (AppendList.fromList
1204 [Assembly.instruction_movx
1205 {oper = Instruction.MOVZX,
1206 dst = applyFFTempArg,
1210 Assembly.instruction_ppush
1211 {src = applyFFTempArg,
1214 Size.toBytes wordSize)
1215 else (AppendList.single
1216 (Assembly.instruction_ppush
1222 (AppendList.append (assembly_arg, assembly_args),
1223 size_arg + size_args)
1225 val (pushArgs, aligned_size_args) =
1227 val space = 16 - (size_args mod 16)
1230 then (pushArgs, size_args)
1231 else (AppendList.append
1233 (Assembly.instruction_binal
1234 {oper = Instruction.SUB,
1236 src = Operand.immediate_int space,
1237 size = pointerSize}),
1243 SOME (FrameInfo.T {size, ...}) =>
1244 (* Entering runtime *)
1246 val return = valOf return
1247 val _ = enque return
1250 = x86MLton.stackTopTempContentsOperand ()
1251 val stackTopTempMinusWordDeref'
1252 = x86MLton.stackTopTempMinusWordDeref ()
1253 val stackTopTempMinusWordDeref
1254 = x86MLton.stackTopTempMinusWordDerefOperand ()
1256 = x86MLton.gcState_stackTopContentsOperand ()
1257 val stackTopMinusWordDeref'
1258 = x86MLton.gcState_stackTopMinusWordDeref ()
1259 val stackTopMinusWordDeref
1260 = x86MLton.gcState_stackTopMinusWordDerefOperand ()
1261 val bytes = x86.Operand.immediate_int size
1264 x86Liveness.LiveInfo.getLive(liveInfo, return)
1265 val {defs, ...} = Transfer.uses_defs_kills transfer
1271 case Operand.deMemloc oper of
1272 SOME memloc => LiveSet.remove (live, memloc)
1275 (runtimeTransfer (LiveSet.toMemLocSet live)
1276 (if !Control.profile <> Control.ProfileNone
1277 then (AppendList.fromList
1278 [(* stackTopTemp = stackTop + bytes *)
1279 x86.Assembly.instruction_mov
1280 {dst = stackTopTemp,
1282 size = pointerSize},
1283 x86.Assembly.instruction_binal
1284 {oper = x86.Instruction.ADD,
1287 size = pointerSize},
1288 (* *(stackTopTemp - WORD_SIZE) = return *)
1289 x86.Assembly.instruction_mov
1290 {dst = stackTopTempMinusWordDeref,
1291 src = Operand.immediate_label return,
1292 size = pointerSize},
1293 x86.Assembly.directive_force
1294 {commit_memlocs = MemLocSet.singleton stackTopTempMinusWordDeref',
1295 commit_classes = ClassSet.empty,
1296 remove_memlocs = MemLocSet.empty,
1297 remove_classes = ClassSet.empty,
1298 dead_memlocs = MemLocSet.empty,
1299 dead_classes = ClassSet.empty},
1300 (* stackTop = stackTopTemp *)
1301 x86.Assembly.instruction_mov
1304 size = pointerSize},
1305 profileStackTopCommit'])
1306 else (AppendList.fromList
1307 [(* stackTop += bytes *)
1308 x86.Assembly.instruction_binal
1309 {oper = x86.Instruction.ADD,
1312 size = pointerSize},
1313 (* *(stackTop - WORD_SIZE) = return *)
1314 x86.Assembly.instruction_mov
1315 {dst = stackTopMinusWordDeref,
1316 src = Operand.immediate_label return,
1317 size = pointerSize},
1318 x86.Assembly.directive_force
1319 {commit_memlocs = MemLocSet.singleton stackTopMinusWordDeref',
1320 commit_classes = ClassSet.empty,
1321 remove_memlocs = MemLocSet.empty,
1322 remove_classes = ClassSet.empty,
1323 dead_memlocs = MemLocSet.empty,
1324 dead_classes = ClassSet.empty}]))
1326 (Assembly.directive_force
1327 {commit_memlocs = LiveSet.toMemLocSet live,
1328 commit_classes = runtimeClasses,
1329 remove_memlocs = MemLocSet.empty,
1330 remove_classes = ClassSet.empty,
1331 dead_memlocs = MemLocSet.empty,
1332 dead_classes = ClassSet.empty})))
1336 (Assembly.directive_force
1337 {commit_memlocs = let
1338 val s = MemLocSet.empty
1339 val s = if CFunction.modifiesFrontier func
1343 val s = if CFunction.readsStackTop func
1350 commit_classes = ccallflushClasses,
1351 remove_memlocs = MemLocSet.empty,
1352 remove_classes = ClassSet.empty,
1353 dead_memlocs = LiveSet.toMemLocSet dead,
1354 dead_classes = ClassSet.empty})
1359 datatype z = datatype MLton.Platform.OS.t
1360 datatype z = datatype Control.Format.t
1365 | Stdcall => concat [name, "@", Int.toString size_args]
1367 val label = fn () => Label.fromString name
1369 (* how to access imported functions: *)
1370 (* Windows rewrites the symbol __imp__name *)
1371 val coff = fn () => Label.fromString ("_imp__" ^ name)
1372 val macho = fn () => makeDarwinSymbolStubLabel name
1373 val elf = fn () => Label.fromString (name ^ "@PLT")
1375 val importLabel = fn () =>
1376 case !Control.Target.os of
1378 | Darwin => macho ()
1382 val direct = fn () =>
1384 [Assembly.directive_ccall (),
1385 Assembly.instruction_call
1386 {target = Operand.label (label ()),
1391 [Assembly.directive_ccall (),
1392 Assembly.instruction_call
1393 {target = Operand.label (importLabel ()),
1396 val indirect = fn () =>
1398 [Assembly.directive_ccall (),
1399 Assembly.instruction_call
1400 {target = Operand.memloc_label (importLabel ()),
1405 !Control.positionIndependent) of
1406 (* Private functions can be easily reached
1407 * with a direct (eip-relative) call.
1409 (Private, _, _) => direct ()
1410 (* Call at the point of definition. *)
1411 | (Public, MinGW, _) => direct ()
1412 | (Public, Cygwin, _) => direct ()
1413 | (Public, Darwin, _) => direct ()
1414 (* ELF requires PLT even for public fns. *)
1415 | (Public, _, true) => plt ()
1416 | (Public, _, false) => direct ()
1417 (* Windows always does indirect calls to
1418 * imported functions. The importLabel has
1419 * the function address written to it.
1421 | (External, MinGW, _) => indirect ()
1422 | (External, Cygwin, _) => indirect ()
1423 (* Darwin needs to generate special stubs
1424 * that are filled in by the dynamic linker.
1425 * This is needed even for non-PIC.
1427 | (External, Darwin, _) => plt ()
1428 (* ELF systems create procedure lookup
1429 * tables (PLT) which proxy the call to
1430 * libraries. The PLT does not contain an
1431 * address, but instead a stub function.
1433 | (External, _, true) => plt ()
1434 | (External, _, false) => direct ()
1438 [Assembly.directive_ccall (),
1439 Assembly.instruction_call
1440 {target = applyFFTempFun,
1443 = if isSome frameInfo
1444 then AppendList.single
1445 (Assembly.directive_force
1446 {commit_memlocs = MemLocSet.empty,
1447 commit_classes = ClassSet.empty,
1448 remove_memlocs = MemLocSet.empty,
1449 remove_classes = ClassSet.empty,
1450 dead_memlocs = MemLocSet.empty,
1451 dead_classes = runtimeClasses})
1452 else AppendList.single
1453 (Assembly.directive_force
1454 {commit_memlocs = MemLocSet.empty,
1455 commit_classes = ClassSet.empty,
1456 remove_memlocs = MemLocSet.empty,
1457 remove_classes = ClassSet.empty,
1459 val s = MemLocSet.empty
1460 val s = if CFunction.modifiesFrontier func
1464 val s = if CFunction.writesStackTop func
1471 dead_classes = ccallflushClasses})
1474 (Assembly.directive_return
1475 {returns = Operand.cReturnTemps returnTy})
1477 if aligned_size_args > 0
1478 andalso convention = CFunction.Convention.Cdecl
1479 then (AppendList.single
1480 (Assembly.instruction_binal
1481 {oper = Instruction.ADD,
1483 src = Operand.immediate_int aligned_size_args,
1484 size = pointerSize}))
1485 else AppendList.empty
1487 = if CFunction.maySwitchThreads func
1488 then (* Returning from runtime *)
1489 (farTransfer MemLocSet.empty
1492 (* jmp *(stackTop - WORD_SIZE) *)
1493 (x86.Assembly.instruction_jmp
1494 {target = stackTopMinusWordDeref,
1497 of NONE => AppendList.empty
1498 | SOME l => (if isSome frameInfo
1499 then (* Don't need to trampoline,
1500 * since didn't switch threads,
1501 * but can't fall because
1502 * frame layout data is prefixed
1503 * to l's code; use fallNone
1504 * to force a jmp with near
1511 live = getLive (liveInfo, l)}
1526 and effectJumpTable (gef as GEF {...})
1527 {label, transfer} : Assembly.t AppendList.t
1529 of Switch {test, cases, default}
1532 case Operand.size test of
1533 SOME Size.BYTE => WordSize.word8
1534 | SOME Size.WORD => WordSize.word16
1535 | SOME Size.LONG => WordSize.word32
1536 | _ => Error.bug "x86GenerateTransfers.effectJumpTable: Switch"
1538 val zero = WordX.zero ws
1539 val one = WordX.one ws
1540 val two = WordX.add (one, one)
1541 fun even w = WordX.isZero (WordX.mod (w, two, {signed = false}))
1542 fun incFn w = WordX.add (w, one)
1543 fun decFn w = WordX.sub (w, one)
1544 fun halfFn w = WordX.div (w, two, {signed = false})
1545 fun ltFn (w1, w2) = WordX.lt (w1, w2, {signed = false})
1546 val min = WordX.min (ws, {signed = false})
1547 fun minFn (w1, w2) = if WordX.lt (w1, w2, {signed = false})
1550 val max = WordX.max (ws, {signed = false})
1551 fun maxFn (w1, w2) = if WordX.gt (w1, w2, {signed = false})
1554 fun range (w1, w2) = WordX.sub (w2, w1)
1556 val Liveness.T {dead, ...}
1557 = livenessTransfer {transfer = transfer,
1558 liveInfo = liveInfo}
1564 val (minK,maxK,length,
1579 allEven andalso isEven,
1580 allOdd andalso not isEven)
1583 if length > 1 andalso
1584 (allEven orelse allOdd)
1596 minK'', maxK'', length'',
1600 val shift' = 1 + shift''
1603 (WordX.lshift(mask'', WordX.one WordSize.word32),
1605 then WordX.one WordSize.word32
1606 else WordX.zero WordSize.word32)
1609 minK'', maxK'', length'',
1614 0, WordX.zero WordSize.word32)
1620 fun doitTable(cases,
1621 minK, _, rangeK, shift, mask)
1623 val jump_table_label
1624 = Label.newString "jumpTable"
1626 val idT = Directive.Id.new ()
1631 val _ = incNear(jumpInfo, default)
1633 pushCompensationBlock
1640 | (cases as (i,target)::cases',j)
1641 => if WordX.equals (i, j)
1644 = pushCompensationBlock
1648 (Immediate.label target')::
1649 (filler(cases', incFn j))
1651 else (Immediate.label
1652 (Promise.force defaultT))::
1653 (filler(cases, incFn j))
1655 val jump_table = filler (cases, minK)
1657 val idD = Directive.Id.new ()
1658 val defaultD = pushCompensationBlock
1662 val default_live = getLive(liveInfo, default)
1667 fn ((_,target), live)
1668 => LiveSet.+(live, getLive(liveInfo, target)))
1672 {base = Immediate.label (Label.fromString "indexTemp"),
1673 index = Immediate.zero,
1676 class = MemLoc.Class.Temp}
1679 {base = Immediate.label (Label.fromString "checkTemp"),
1680 index = Immediate.zero,
1683 class = MemLoc.Class.Temp}
1686 {base = Immediate.label jump_table_label,
1690 class = MemLoc.Class.Code}
1693 = case Operand.size test
1694 of SOME size => size
1696 val indexTemp' = indexTemp
1697 val indexTemp = Operand.memloc indexTemp
1698 val checkTemp' = checkTemp
1699 val checkTemp = Operand.memloc checkTemp
1700 val address = Operand.memloc address
1703 [if Size.lt(size, Size.LONG)
1704 then AppendList.single
1705 (Assembly.instruction_movx
1706 {oper = Instruction.MOVZX,
1710 dstsize = Size.LONG})
1711 else AppendList.single
1712 (Assembly.instruction_mov
1716 if LiveSet.isEmpty dead
1717 then AppendList.empty
1718 else AppendList.single
1719 (Assembly.directive_force
1720 {commit_memlocs = MemLocSet.empty,
1721 commit_classes = ClassSet.empty,
1722 remove_memlocs = MemLocSet.empty,
1723 remove_classes = ClassSet.empty,
1724 dead_memlocs = LiveSet.toMemLocSet dead,
1725 dead_classes = ClassSet.empty}),
1728 val idC = Directive.Id.new ()
1729 val defaultC = pushCompensationBlock
1732 val _ = incNear(jumpInfo, default)
1735 [AppendList.fromList
1736 [Assembly.instruction_mov
1740 Assembly.instruction_binal
1741 {oper = Instruction.AND,
1742 src = Operand.immediate_word
1743 (ones (shift, WordSize.word32)),
1746 if WordX.isZero mask
1747 then AppendList.empty
1748 else AppendList.single
1749 (Assembly.instruction_binal
1750 {oper = Instruction.SUB,
1751 src = Operand.immediate_word mask,
1755 [Assembly.directive_force
1756 {commit_memlocs = MemLocSet.empty,
1757 commit_classes = nearflushClasses,
1758 remove_memlocs = MemLocSet.empty,
1759 remove_classes = ClassSet.empty,
1760 dead_memlocs = MemLocSet.singleton checkTemp',
1761 dead_classes = ClassSet.empty},
1762 Assembly.instruction_jcc
1763 {condition = Instruction.NZ,
1764 target = Operand.label defaultC},
1765 Assembly.directive_saveregalloc
1767 live = MemLocSet.add
1769 (LiveSet.toMemLocSet default_live,
1772 Assembly.instruction_sral
1773 {oper = Instruction.SAR,
1774 count = Operand.immediate_int shift,
1778 else AppendList.empty,
1779 if WordX.equals (minK, zero)
1780 then AppendList.empty
1781 else AppendList.single
1782 (Assembly.instruction_binal
1783 {oper = Instruction.SUB,
1784 src = Operand.immediate_word minK,
1788 [Assembly.directive_force
1789 {commit_memlocs = MemLocSet.empty,
1790 commit_classes = nearflushClasses,
1791 remove_memlocs = MemLocSet.empty,
1792 remove_classes = ClassSet.empty,
1793 dead_memlocs = MemLocSet.empty,
1794 dead_classes = ClassSet.empty},
1795 Assembly.directive_cache
1796 {caches = [{register = indexReg,
1797 memloc = indexTemp',
1799 Assembly.instruction_cmp
1801 src2 = Operand.immediate_word rangeK,
1803 Assembly.instruction_jcc
1804 {condition = Instruction.A,
1805 target = Operand.label defaultD},
1806 Assembly.directive_saveregalloc
1808 live = MemLocSet.add
1810 (LiveSet.toMemLocSet default_live,
1813 Assembly.instruction_jmp
1816 Assembly.directive_saveregalloc
1818 live = MemLocSet.add
1820 (LiveSet.toMemLocSet live,
1823 Assembly.directive_force
1824 {commit_memlocs = MemLocSet.empty,
1825 commit_classes = ClassSet.empty,
1826 remove_memlocs = MemLocSet.empty,
1827 remove_classes = ClassSet.empty,
1828 dead_memlocs = MemLocSet.singleton indexTemp',
1829 dead_classes = ClassSet.empty}],
1831 [Assembly.pseudoop_data (),
1832 Assembly.pseudoop_p2align
1833 (Immediate.int 4, NONE, NONE),
1834 Assembly.label jump_table_label,
1835 Assembly.pseudoop_long jump_table,
1836 Assembly.pseudoop_text ()]]
1851 WordX.lt (WordX.div(rangeK,two,{signed=false}),
1852 WordX.fromIntInf (IntInf.fromInt length, ws),
1856 = List.insertionSort
1865 else effectDefault gef
1867 transfer = transfer}
1871 of Transfer.Cases.Word cases
1874 | _ => effectDefault gef
1876 transfer = transfer}
1878 and fallNone (GEF {...})
1879 {label, live} : Assembly.t AppendList.t
1881 val liveRegsTransfer = getLiveRegsTransfers
1882 (liveTransfers, label)
1883 val liveFltRegsTransfer = getLiveFltRegsTransfers
1884 (liveTransfers, label)
1890 fn ((memloc,_,_),live)
1891 => LiveSet.remove(live,memloc))
1894 (liveFltRegsTransfer,
1896 fn ((memloc,_),live)
1897 => LiveSet.remove(live,memloc))
1900 = AppendList.fromList
1901 ((* flushing at near transfer *)
1902 (Assembly.directive_cache
1903 {caches = [{register = stackTopReg,
1904 memloc = stackTop (),
1906 {register = frontierReg,
1907 memloc = frontier (),
1908 reserve = true}]})::
1909 (Assembly.directive_fltcache
1912 (liveFltRegsTransfer,
1914 => {memloc = memloc})})::
1915 (Assembly.directive_cache
1919 fn (temp,register,_)
1920 => {register = register,
1922 reserve = true})})::
1923 (Assembly.directive_force
1924 {commit_memlocs = LiveSet.toMemLocSet live,
1925 commit_classes = nearflushClasses,
1926 remove_memlocs = MemLocSet.empty,
1927 remove_classes = ClassSet.empty,
1928 dead_memlocs = MemLocSet.empty,
1929 dead_classes = ClassSet.empty})::
1930 (Assembly.instruction_jmp
1931 {target = Operand.label label,
1932 absolute = false})::
1933 (Assembly.directive_unreserve
1943 case getLayoutInfo label
1946 | SOME (Block.T {...})
1951 and fallDefault (gef as GEF {generate,...})
1952 {label, live} : Assembly.t AppendList.t
1954 datatype z = datatype x86JumpInfo.status
1955 val liveRegsTransfer = getLiveRegsTransfers
1956 (liveTransfers, label)
1957 val liveFltRegsTransfer = getLiveFltRegsTransfers
1958 (liveTransfers, label)
1964 fn ((memloc,_,_),live)
1965 => LiveSet.remove(live,memloc))
1968 (liveFltRegsTransfer,
1970 fn ((memloc,_),live)
1971 => LiveSet.remove(live,memloc))
1974 = AppendList.appends
1975 [AppendList.fromList
1976 [(* flushing at near transfer *)
1977 (Assembly.directive_cache
1978 {caches = [{register = stackTopReg,
1979 memloc = stackTop (),
1981 {register = frontierReg,
1982 memloc = frontier (),
1984 (Assembly.directive_fltcache
1987 (liveFltRegsTransfer,
1989 => {memloc = memloc})}),
1990 (Assembly.directive_cache
1994 fn (temp,register,_)
1995 => {register = register,
1998 (Assembly.directive_force
1999 {commit_memlocs = LiveSet.toMemLocSet live,
2000 commit_classes = nearflushClasses,
2001 remove_memlocs = MemLocSet.empty,
2002 remove_classes = ClassSet.empty,
2003 dead_memlocs = MemLocSet.empty,
2004 dead_classes = ClassSet.empty})],
2006 then AppendList.single
2007 (Assembly.instruction_jmp
2008 {target = Operand.label label,
2010 else AppendList.empty,
2012 (Assembly.directive_unreserve
2021 case getLayoutInfo label
2024 | SOME (Block.T {...})
2025 => (case getNear(jumpInfo, label)
2031 | _ => AppendList.append
2034 (Assembly.directive_reset (),
2041 fun make {generate, effect, fall}
2042 = generate (GEF {generate = generate,
2048 of 0 => make {generate = generateAll,
2049 effect = effectDefault,
2051 | _ => make {generate = generateAll,
2052 effect = effectJumpTable,
2055 val _ = List.foreach
2057 fn Block.T {entry, ...}
2059 of Func {label, ...} => enque label
2061 fun doit () : Assembly.t list list
2065 => (case AppendList.toList (generate {label = label,
2069 | block => block::(doit ())))
2070 val assembly = doit ()
2071 val symbol_stubs = makeDarwinSymbolStubs ()
2072 val _ = destLayoutInfo ()
2073 val _ = destProfileLabel ()
2075 val assembly = [Assembly.pseudoop_text ()]::assembly
2077 if List.isEmpty symbol_stubs
2079 else symbol_stubs :: assembly
2081 if List.isEmpty data
2088 val (generateTransfers, generateTransfers_msg)
2093 fun generateTransfers_totals ()
2094 = (generateTransfers_msg ();
2096 x86Liveness.LiveInfo.verifyLiveInfo_msg ();
2097 x86JumpInfo.verifyJumpInfo_msg ();
2098 x86EntryTransfer.verifyEntryTransfer_msg ();
2099 x86LoopInfo.createLoopInfo_msg ();
2100 x86LiveTransfers.computeLiveTransfers_totals ();
2101 Control.unindent ())