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 x86Translate(S: X86_TRANSLATE_STRUCTS): X86_TRANSLATE =
15 val tracerTop = x86.tracerTop
17 fun argsToString(ss: string list): string
18 = "(" ^ (concat (List.separate(ss, ", "))) ^ ")"
20 structure Machine = x86MLton.Machine
25 structure Label = Label
27 structure Register = Register
28 structure Scale = Scale
29 structure StackOffset = StackOffset
31 structure WordSize = WordSize
32 structure WordX = WordX
35 datatype z = datatype WordSize.prim
41 fun toX86Operand (g: t) : (x86.Operand.t * x86.Size.t) vector =
43 val ty = Machine.Type.toCType (ty g)
48 then x86MLton.global_base ty
49 else x86MLton.globalObjptrNonRoot_base)
53 index = x86.Immediate.int index,
54 scale = x86.Scale.fromCType ty,
56 class = x86MLton.Classes.Globals}
57 val sizes = x86.Size.fromCType ty
59 (#1 o Vector.mapAndFold)
60 (sizes, 0, fn (size,offset) =>
61 (((x86.Operand.memloc o x86.MemLoc.shift)
63 disp = x86.Immediate.int offset,
64 scale = x86.Scale.One,
65 size = size}, size), offset + x86.Size.toBytes size))
73 fun get (f: ('a * 'b) -> 'c) (i: int) (v: ('a * 'b) vector) =
78 val rec toX86Operand : t -> (x86.Operand.t * x86.Size.t) vector =
79 fn ArrayOffset {base, index, offset, scale, ty}
81 val base = toX86Operand base
82 val _ = Assert.assert("x86Translate.Operand.toX86Operand: Array/base",
83 fn () => Vector.length base = 1)
84 val base = getOp0 base
85 val index = toX86Operand index
86 val _ = Assert.assert("x86Translate.Operand.toX86Operand: Array/index",
87 fn () => Vector.length index = 1)
88 val index = getOp0 index
91 Scale.One => x86.Scale.One
92 | Scale.Two => x86.Scale.Two
93 | Scale.Four => x86.Scale.Four
94 | Scale.Eight => x86.Scale.Eight
95 val ty = Type.toCType ty
97 case (x86.Operand.deMemloc base,
98 x86.Operand.deImmediate index,
99 x86.Operand.deMemloc index) of
100 (SOME base, SOME index, _) =>
105 size = x86.Size.BYTE,
106 class = x86MLton.Classes.Heap}
107 | (SOME base, _, SOME index) =>
112 size = x86.Size.BYTE,
113 class = x86MLton.Classes.Heap}
114 | _ => Error.bug (concat ["x86Translate.Operand.toX86Operand: ",
115 "strange Offset: base: ",
116 x86.Operand.toString base,
118 x86.Operand.toString index])
120 if Bytes.isZero offset
122 else x86.MemLoc.shift
124 disp = x86.Immediate.int (Bytes.toInt offset),
125 scale = x86.Scale.One,
126 size = x86.Size.BYTE}
127 val sizes = x86.Size.fromCType ty
129 (#1 o Vector.mapAndFold)
130 (sizes, 0, fn (size,offset) =>
131 (((x86.Operand.memloc o x86.MemLoc.shift)
133 disp = x86.Immediate.int offset,
134 scale = x86.Scale.One,
135 size = size}, size), offset + x86.Size.toBytes size))
137 | Cast (z, _) => toX86Operand z
138 | Contents {oper, ty} =>
140 val ty = Type.toCType ty
141 val base = toX86Operand oper
142 val _ = Assert.assert("x86Translate.Operand.toX86Operand: Contents/base",
143 fn () => Vector.length base = 1)
144 val base = getOp0 base
146 case x86.Operand.deMemloc base of
150 index = x86.Immediate.zero,
151 scale = x86.Scale.One,
152 size = x86.Size.BYTE,
153 class = x86MLton.Classes.Heap}
154 | _ => Error.bug (concat
155 ["x86Translate.Operand.toX86Operand: ",
156 "strange Contents: base: ",
157 x86.Operand.toString base])
158 val sizes = x86.Size.fromCType ty
160 (#1 o Vector.mapAndFold)
161 (sizes, 0, fn (size,offset) =>
162 (((x86.Operand.memloc o x86.MemLoc.shift)
164 disp = x86.Immediate.int offset,
165 scale = x86.Scale.One,
166 size = size}, size), offset + x86.Size.toBytes size))
170 val frontier = x86MLton.gcState_frontierContentsOperand ()
172 Vector.new1 (frontier, valOf (x86.Operand.size frontier))
175 Vector.new1 (x86.Operand.immediate_label x86MLton.gcState_label,
176 x86MLton.pointerSize)
177 | Global g => Global.toX86Operand g
179 Vector.new1 (x86.Operand.immediate_label l, x86MLton.pointerSize)
181 Vector.new1 (x86.Operand.immediate_zero, x86MLton.wordSize)
182 | Offset {base = GCState, offset, ty} =>
184 val offset = Bytes.toInt offset
185 val ty = Type.toCType ty
186 val offset = x86MLton.gcState_offset {offset = offset, ty = ty}
188 Vector.new1 (offset, valOf (x86.Operand.size offset))
190 | Offset {base, offset, ty} =>
192 val offset = Bytes.toInt offset
193 val ty = Type.toCType ty
194 val base = toX86Operand base
195 val _ = Assert.assert("x86Translate.Operand.toX86Operand: Offset/base",
196 fn () => Vector.length base = 1)
197 val base = getOp0 base
199 case x86.Operand.deMemloc base of
203 index = x86.Immediate.int offset,
204 scale = x86.Scale.One,
205 size = x86.Size.BYTE,
206 class = x86MLton.Classes.Heap}
207 | _ => Error.bug (concat ["x86Translate.Operand.toX86Operand: ",
208 "strange Offset: base: ",
209 x86.Operand.toString base])
210 val sizes = x86.Size.fromCType ty
212 (#1 o Vector.mapAndFold)
213 (sizes, 0, fn (size,offset) =>
214 (((x86.Operand.memloc o x86.MemLoc.shift)
216 disp = x86.Immediate.int offset,
217 scale = x86.Scale.One,
218 size = size}, size), offset + x86.Size.toBytes size))
220 | Real _ => Error.bug "x86Translate.Operand.toX86Operand: Real unimplemented"
223 val ty = Machine.Type.toCType (Register.ty r)
224 val index = Machine.Register.index r
225 val base = x86.Immediate.label (x86MLton.local_base ty)
229 index = x86.Immediate.int index,
230 scale = x86.Scale.fromCType ty,
231 size = x86.Size.BYTE,
232 class = x86MLton.Classes.Locals}
233 val sizes = x86.Size.fromCType ty
235 (#1 o Vector.mapAndFold)
236 (sizes, 0, fn (size,offset) =>
237 (((x86.Operand.memloc o x86.MemLoc.shift)
239 disp = x86.Immediate.int offset,
240 scale = x86.Scale.One,
241 size = size}, size), offset + x86.Size.toBytes size))
243 | StackOffset (StackOffset.T {offset, ty}) =>
245 val offset = Bytes.toInt offset
246 val ty = Type.toCType ty
249 {base = x86MLton.gcState_stackTopContents (),
250 index = x86.Immediate.int offset,
251 scale = x86.Scale.One,
252 size = x86.Size.BYTE,
253 class = x86MLton.Classes.Stack}
254 val sizes = x86.Size.fromCType ty
256 (#1 o Vector.mapAndFold)
257 (sizes, 0, fn (size,offset) =>
258 (((x86.Operand.memloc o x86.MemLoc.shift)
260 disp = x86.Immediate.int offset,
261 scale = x86.Scale.One,
262 size = size}, size), offset + x86.Size.toBytes size))
266 val stackTop = x86MLton.gcState_stackTopContentsOperand ()
268 Vector.new1 (stackTop, valOf (x86.Operand.size stackTop))
273 Vector.new1 (x86.Operand.immediate_word w, size)
275 case WordSize.prim (WordX.size w) of
276 W8 => single x86.Size.BYTE
277 | W16 => single x86.Size.WORD
278 | W32 => single x86.Size.LONG
281 val lo = WordX.resize (w, WordSize.word32)
282 val w = WordX.rshift (w,
283 WordX.fromIntInf (32, WordSize.word64),
285 val hi = WordX.resize (w, WordSize.word32)
288 ((x86.Operand.immediate_word lo, x86.Size.LONG),
289 (x86.Operand.immediate_word hi, x86.Size.LONG))
294 type transInfo = x86MLton.transInfo
298 structure Kind = Machine.Kind
300 fun toX86Blocks {label, kind,
301 transInfo as {frameInfoToX86, live, liveInfo,
304 x86Liveness.LiveInfo.setLiveOperands
305 (liveInfo, label, live label);
312 {entry = SOME (x86.Entry.jump {label = label}),
323 => case x86.Operand.deMemloc operand
324 of SOME memloc => x86.MemLocSet.add(args, memloc)
329 {entry = SOME (x86.Entry.func {label = label,
334 | Kind.Cont {args, frameInfo, ...}
336 val frameInfo = frameInfoToX86 frameInfo
339 (args, x86.MemLocSet.empty,
342 (Operand.toX86Operand (Live.toOperand operand), args,
343 fn ((operand,_),args) =>
344 case x86.Operand.deMemloc operand of
345 SOME memloc => x86.MemLocSet.add(args, memloc)
350 {entry = SOME (x86.Entry.cont {label = label,
352 frameInfo = frameInfo}),
356 | Kind.Handler {frameInfo, ...}
361 {entry = SOME (x86.Entry.handler
362 {frameInfo = frameInfoToX86 frameInfo,
364 live = x86.MemLocSet.empty}),
368 | Kind.CReturn {dst, frameInfo, func}
372 NONE => Vector.new0 ()
373 | SOME dst => Operand.toX86Operand (Live.toOperand dst)
377 frameInfo = Option.map (frameInfo, frameInfoToX86),
380 transInfo = transInfo}
384 structure Statement =
386 open Machine.Statement
388 fun comments statement
389 = if !Control.Native.commented > 0
391 val comment = (Layout.toString o layout) statement
396 statements = [x86.Assembly.comment
403 statements = [x86.Assembly.comment
408 else (AppendList.empty,AppendList.empty)
410 fun toX86Blocks {statement,
411 transInfo as {...} : transInfo}
418 comment_end) = comments statement
420 val dsts = Operand.toX86Operand dst
421 val srcs = Operand.toX86Operand src
422 (* Operand.toX86Operand returns multi-word
423 * operands in and they will be moved in order,
424 * so it suffices to check for aliasing between
425 * the first dst and second src.
428 if Vector.length srcs > 1
429 andalso x86.Operand.mayAlias
430 (#1 (Vector.sub (dsts, 0)),
431 #1 (Vector.sub (srcs, 1)))
432 then (Vector.rev dsts, Vector.rev srcs)
441 = (Vector.toList o Vector.map2)
442 (dsts,srcs,fn ((dst,_),(src,srcsize)) =>
444 case x86.Size.class srcsize
445 of x86.Size.INT => x86.Assembly.instruction_mov
449 | x86.Size.FLT => x86.Assembly.instruction_pfmov
453 | _ => Error.bug "x86Translate.Statement.toX86Blocks: Move"),
457 | PrimApp {dst, prim, args}
459 val (comment_begin, comment_end) = comments statement
460 val args = (Vector.concatV o Vector.map)
461 (args, Operand.toX86Operand)
464 NONE => Vector.new0 ()
465 | SOME dst => Operand.toX86Operand dst
469 (x86MLton.prim {prim = prim,
472 transInfo = transInfo}),
477 (x86.Block.mkProfileBlock'
483 open Machine.Transfer
490 transfer = SOME (x86.Transfer.goto
495 val (test,testsize) =
496 Vector.sub (Operand.toX86Operand test, 0)
498 if Label.equals(a, b)
499 then AppendList.single
503 transfer = SOME (x86.Transfer.goto {target = a})})
504 else AppendList.single
511 = [x86.Assembly.instruction_test
516 = SOME (x86.Transfer.iff
517 {condition = x86.Instruction.NZ,
522 fun cmp (test, k, a, b)
524 val (test,testsize) =
525 Vector.sub (Operand.toX86Operand test, 0)
527 if Label.equals(a, b)
528 then AppendList.single
532 transfer = SOME (x86.Transfer.goto {target = a})})
533 else AppendList.single
534 ((* if (test = k) goto a
540 = [x86.Assembly.instruction_cmp
542 src2 = x86.Operand.immediate k,
545 = SOME (x86.Transfer.iff
546 {condition = x86.Instruction.E,
551 fun switch(test, cases, default)
553 val test = Operand.toX86Operand test
554 val (test,_) = Vector.sub(test, 0)
560 transfer = SOME (x86.Transfer.switch
563 default = default})})
566 fun doSwitchWord (test, cases, default)
567 = (case (cases, default)
569 => Error.bug "x86Translate.Transfer.doSwitchWord"
570 | ([(_,l)], NONE) => goto l
571 | ([], SOME l) => goto l
572 | ([(w1,l1),(w2,l2)], NONE) =>
573 if WordX.isZero w1 andalso WordX.isOne w2
575 else if WordX.isZero w2 andalso WordX.isOne w1
577 else cmp(test,x86.Immediate.word w1,l1,l2)
578 | ([(k',l')], SOME l)
579 => cmp(test,x86.Immediate.word k',l',l)
580 | ((_,l)::cases, NONE)
581 => switch(test, x86.Transfer.Cases.word cases, l)
583 => switch(test, x86.Transfer.Cases.word cases, l))
585 fun comments transfer
586 = if !Control.Native.commented > 0
588 val comment = (Layout.toString o layout) transfer
593 statements = [x86.Assembly.comment comment],
596 else AppendList.empty
599 fun toX86Blocks {returns, transfer,
600 transInfo as {frameInfoToX86, ...}: transInfo}
602 of Arith {prim, args, dst, overflow, success, ...}
604 val args = (Vector.concatV o Vector.map)
605 (args, Operand.toX86Operand)
606 val dsts = Operand.toX86Operand dst
610 x86MLton.arith {prim = prim,
615 transInfo = transInfo})
617 | CCall {args, frameInfo, func, return}
619 val args = (Vector.concatV o Vector.map)
620 (args, Operand.toX86Operand)
624 x86MLton.ccall {args = args,
625 frameInfo = (Option.map
626 (frameInfo, frameInfoToX86)),
629 transInfo = transInfo})
639 = SOME (x86.Transfer.return
643 NONE => Error.bug "x86Translate.Transfer.toX86Blocsk: Return"
646 fn (operand, live) =>
648 (Operand.toX86Operand operand, live,
649 fn ((operand,_),live) =>
650 case x86.Operand.deMemloc operand of
651 SOME memloc => x86.MemLocSet.add(live, memloc)
652 | NONE => live))})}))
661 = SOME (x86.Transfer.raisee
665 (x86.MemLocSet.empty,
666 x86MLton.gcState_stackBottomContents ()),
667 x86MLton.gcState_exnStackContents ())})}))
668 | Switch (Machine.Switch.T {cases, default, test, ...})
671 doSwitchWord (test, Vector.toList cases, default))
673 => (AppendList.append
680 transfer = SOME (x86.Transfer.goto {target = label})})))
681 | Call {label, live, return, ...}
685 (live, x86.MemLocSet.empty, fn (operand, live) =>
687 (Operand.toX86Operand (Live.toOperand operand), live,
688 fn ((operand, _), live) =>
689 case x86.Operand.deMemloc operand of
691 | SOME memloc => x86.MemLocSet.add (live, memloc)))
692 val com = comments transfer
695 NONE => x86.Transfer.tail {target = label,
697 | SOME {return, handler, size} =>
698 x86.Transfer.nontail {target = label,
702 size = Bytes.toInt size}
707 (x86.Block.mkBlock' {entry = NONE,
709 transfer = SOME transfer}))
717 fun toX86Blocks {block = T {label,
724 transInfo as {...} : transInfo}
729 (Entry.toX86Blocks {label = label,
731 transInfo = transInfo},
735 = if !Control.Native.commented > 0
742 Operand.toString (Live.toOperand l)))]
744 [x86.Assembly.comment comment]
748 Vector.foldr(statements,
749 (Transfer.toX86Blocks
750 {returns = (Option.map
752 Vector.map (v, Live.toOperand))),
754 transInfo = transInfo}),
757 (Statement.toX86Blocks
758 {statement = statement,
759 transInfo = transInfo}, l)))
761 val pseudo_blocks = AppendList.toList pseudo_blocks
763 val blocks = x86.Block.compress pseudo_blocks
773 fun toX86Chunk {chunk = T {blocks, ...},
778 val addData = fn l => List.push (data, l)
779 val {get = live : Label.t -> x86.Operand.t list,
782 = Property.getSetOnce
783 (Label.plist, Property.initRaise ("live", Label.layout))
784 val _ = Vector.foreach
785 (blocks, fn Block.T {label, live, ...} =>
787 (Vector.toList o #1 o Vector.unzip o
788 Vector.concatV o Vector.map)
789 (live, Operand.toX86Operand o Live.toOperand)))
790 val transInfo = {addData = addData,
791 frameInfoToX86 = frameInfoToX86,
795 = List.concat (Vector.toListMap
800 transInfo = transInfo}))
801 val _ = Vector.foreach (blocks, fn Block.T {label, ...} =>
803 val data = List.concatRev (!data)
807 else (x86.Assembly.pseudoop_data())::data
809 x86.Chunk.T {data = data, blocks = x86Blocks}
813 fun translateChunk {chunk: x86MLton.Machine.Chunk.t,
815 liveInfo: x86Liveness.LiveInfo.t}:
817 = {chunk = Chunk.toX86Chunk {chunk = chunk,
818 frameInfoToX86 = frameInfoToX86,
819 liveInfo = liveInfo}}
821 val (translateChunk, translateChunk_msg)
826 fun translateChunk_totals ()
827 = (translateChunk_msg ();