1 (* Copyright (C) 1999-2008 Henry Cejtin, Matthew Fluet, Suresh
2 * Jagannathan, and Stephen Weeks.
3 * Copyright (C) 1997-2000 NEC Research Institute.
5 * MLton is released under a BSD-style license.
6 * See the file MLton-LICENSE for details.
9 functor x86MLton (S: X86_MLTON_STRUCTS): X86_MLTON =
18 structure CFunction = CFunction
19 structure RealSize = RealSize
21 structure WordSize = WordSize
22 datatype z = datatype RealSize.t
23 datatype z = datatype WordSize.prim
26 type transInfo = {addData : x86.Assembly.t list -> unit,
27 frameInfoToX86: (x86MLtonBasic.Machine.FrameInfo.t
29 live: x86.Label.t -> x86.Operand.t list,
30 liveInfo: x86Liveness.LiveInfo.t}
32 fun implementsPrim (p: 'a Prim.t) =
34 datatype z = datatype RealSize.t
35 datatype z = datatype WordSize.prim
37 case WordSize.prim s of
42 datatype z = datatype Prim.Name.t
46 | CPointer_diff => true
47 | CPointer_equal => true
48 | CPointer_fromWord => true
50 | CPointer_sub => true
51 | CPointer_toWord => true
52 | FFI_Symbol _ => true
53 | Real_Math_acos _ => true
54 | Real_Math_asin _ => true
55 | Real_Math_atan _ => true
56 | Real_Math_atan2 _ => true
57 | Real_Math_cos _ => true
58 | Real_Math_exp _ => true
59 | Real_Math_ln _ => true
60 | Real_Math_log10 _ => true
61 | Real_Math_sin _ => true
62 | Real_Math_sqrt _ => true
63 | Real_Math_tan _ => true
66 | Real_castToWord _ => false (* !! *)
68 | Real_equal _ => true
69 | Real_ldexp _ => true
73 | Real_muladd _ => true
74 | Real_mulsub _ => true
76 | Real_qequal _ => true
77 | Real_rndToReal _ => true
78 | Real_rndToWord (_, s2, {signed}) => signed andalso w32168 s2
79 | Real_round _ => true
81 | Thread_returnToC => false
83 | Word_addCheck _ => true
85 | Word_castToReal _ => false (* !! *)
86 | Word_equal s => w32168 s
87 | Word_extdToWord (s1, s2, _) => w32168 s1 andalso w32168 s2
88 | Word_lshift s => w32168 s
89 | Word_lt (s, _) => w32168 s
90 | Word_mul (s, _) => w32168 s
91 | Word_mulCheck (s, _) => w32168 s
93 | Word_negCheck _ => true
96 | Word_quot (s, _) => w32168 s
97 | Word_rem (s, _) => w32168 s
98 | Word_rndToReal (s1, _, {signed}) => signed andalso w32168 s1
99 | Word_rol s => w32168 s
100 | Word_ror s => w32168 s
101 | Word_rshift (s, _) => w32168 s
103 | Word_subCheck _ => true
104 | Word_xorb _ => true
108 val implementsPrim: Machine.Type.t Prim.t -> bool =
110 ("x86MLton.implementsPrim", Prim.layout, Bool.layout)
113 fun prim {prim : RepType.t Prim.t,
114 args : (Operand.t * Size.t) vector,
115 dsts : (Operand.t * Size.t) vector,
116 transInfo = {addData, ...} : transInfo}
118 val primName = Prim.toString prim
119 datatype z = datatype Prim.Name.t
122 = Vector.sub (dsts, 0)
123 handle _ => Error.bug "x86MLton.prim: getDst1"
125 = (Vector.sub (dsts, 0), Vector.sub (dsts, 1))
126 handle _ => Error.bug "x86MLton.prim: getDst2"
128 = Vector.sub (args, 0)
129 handle _ => Error.bug "x86MLton.prim: getSrc1"
131 = (Vector.sub (args, 0), Vector.sub (args, 1))
132 handle _ => Error.bug "x86MLton.prim: getSrc2"
134 = (Vector.sub (args, 0), Vector.sub (args, 1), Vector.sub (args, 2))
135 handle _ => Error.bug "x86MLton.prim: getSrc3"
137 = (Vector.sub (args, 0), Vector.sub (args, 1),
138 Vector.sub (args, 2), Vector.sub (args, 3))
139 handle _ => Error.bug "x86MLton.prim: getSrc4"
143 val (dst,dstsize) = getDst1 ()
144 val (src,srcsize) = getSrc1 ()
147 ("x86MLton.prim: mov, dstsize/srcsize",
148 fn () => srcsize = dstsize)
154 = [Assembly.instruction_mov
163 val (dst,dstsize) = getDst1 ()
164 val (src,srcsize) = getSrc1 ()
167 ("x86MLton.prim: movx, dstsize/srcsize",
168 fn () => Size.lt(srcsize,dstsize))
174 = [Assembly.instruction_movx
185 val (dst,dstsize) = getDst1 ()
186 val (src,srcsize) = getSrc1 ()
189 ("x86MLton.prim: xvom, dstsize/srcsize",
190 fn () => Size.lt(dstsize,srcsize))
196 = [Assembly.instruction_xvom
206 val ((src1,src1size),
207 (src2,src2size)) = getSrc2 ()
208 val (dst,dstsize) = getDst1 ()
211 ("x86MLton.prim: binal, dstsize/src1size/src2size",
212 fn () => src1size = dstsize andalso
215 (* Reverse src1/src2 when src1 and src2 are temporaries
216 * and the oper is commutative.
219 = if (oper = Instruction.ADD)
221 (oper = Instruction.ADC)
223 (oper = Instruction.AND)
225 (oper = Instruction.OR)
227 (oper = Instruction.XOR)
228 then case (Operand.deMemloc src1, Operand.deMemloc src2)
229 of (SOME memloc_src1, SOME memloc_src2)
230 => if x86Liveness.track memloc_src1
232 x86Liveness.track memloc_src2
242 = [Assembly.instruction_mov
246 Assembly.instruction_binal
254 fun binal64 (oper1, oper2)
256 val ((src1,src1size),
259 (src4,src4size)) = getSrc4 ()
260 val ((dst1,dst1size),
261 (dst2,dst2size)) = getDst2 ()
264 ("x86MLton.prim: binal64, dst1size/dst2size/src1size/src2size/src3size/src4size",
265 fn () => src1size = dst1size andalso
266 src3size = dst1size andalso
267 src2size = dst2size andalso
268 src4size = dst2size andalso
271 if List.exists ([src2,src3,src4], fn src =>
272 Operand.mayAlias (dst1, src))
273 then wordTemp1ContentsOperand dst1size
276 if List.exists ([src3,src4], fn src =>
277 Operand.mayAlias (dst2, src))
278 then wordTemp1ContentsOperand dst2size
285 = [Assembly.instruction_mov
289 Assembly.instruction_mov
293 Assembly.instruction_binal
298 Assembly.instruction_binal
303 Assembly.instruction_mov
307 Assembly.instruction_mov
316 val ((src1,src1size),
317 (src2,src2size)) = getSrc2 ()
318 val (dst,dstsize) = getDst1 ()
321 ("x86MLton.prim: pmd, dstsize/src1size/src2size",
322 fn () => src1size = dstsize andalso
325 (* Reverse src1/src2 when src1 and src2 are temporaries
326 * and the oper is commutative.
329 = if (oper = Instruction.IMUL)
331 (oper = Instruction.MUL)
332 then case (Operand.deMemloc src1, Operand.deMemloc src2)
333 of (SOME memloc_src1, SOME memloc_src2)
334 => if x86Liveness.track memloc_src1
336 x86Liveness.track memloc_src2
346 = [Assembly.instruction_mov
350 Assembly.instruction_pmd
360 val ((src1,src1size),
361 (src2,src2size)) = getSrc2 ()
362 val (dst,dstsize) = getDst1 ()
365 ("x86MLton.prim: imul2, dstsize/src1size/src2size",
366 fn () => src1size = dstsize andalso
369 (* Reverse src1/src2 when src1 and src2 are temporaries
370 * and the oper is commutative.
373 = case (Operand.deMemloc src1, Operand.deMemloc src2)
374 of (SOME memloc_src1, SOME memloc_src2)
375 => if x86Liveness.track memloc_src1
377 x86Liveness.track memloc_src2
386 = [Assembly.instruction_mov
390 Assembly.instruction_imul2
399 val (src,srcsize) = getSrc1 ()
400 val (dst,dstsize) = getDst1 ()
403 ("x86MLton.prim: unal, dstsize/srcsize",
404 fn () => srcsize = dstsize)
410 = [Assembly.instruction_mov
414 Assembly.instruction_unal
421 fun unal64 (oper, mk)
423 val ((src1,src1size),(src2,src2size)) = getSrc2 ()
424 val ((dst1,dst1size),(dst2,dst2size)) = getDst2 ()
427 ("x86MLton.prim: unal64, dst1size/dst2size/src1size/src2size",
428 fn () => src1size = dst1size andalso
429 src2size = dst2size andalso
432 if List.exists ([src2], fn src =>
433 Operand.mayAlias (dst1, src))
434 then wordTemp1ContentsOperand dst1size
441 = [Assembly.instruction_mov
445 Assembly.instruction_mov
449 Assembly.instruction_mov
453 Assembly.instruction_unal
457 (mk (dst2,dst2size)) @
458 [Assembly.instruction_unal
467 val (dst,dstsize) = getDst1 ()
468 val ((src1,src1size),
469 (src2,src2size)) = getSrc2 ()
472 ("x86MLton.prim: sral, dstsize/src1size",
473 fn () => src1size = dstsize)
476 ("x86MLton.prim: sral, src2size",
477 fn () => src2size = wordSize)
483 = [Assembly.instruction_mov
487 Assembly.instruction_sral
497 val (dst,dstsize) = getDst1 ()
498 val ((src1,src1size),
499 (src2,src2size)) = getSrc2 ()
502 ("x86MLton.prim: cmp, src1size/src2size",
503 fn () => src1size = src2size)
505 (* Can't have an immediate in src1 position,
506 * so reverse the srcs and reverse the condition.
508 * This won't fix an immediate in both positions.
509 * Either constant folding eliminated it
510 * or the register allocator will raise an error.
512 case Operand.deImmediate src1
513 of SOME _ => AppendList.fromList
517 = [Assembly.instruction_cmp
521 Assembly.instruction_setcc
522 {condition = Instruction.condition_reverse condition,
526 | NONE => AppendList.fromList
530 = [Assembly.instruction_cmp
534 Assembly.instruction_setcc
535 {condition = condition,
543 val (dst,dstsize) = getDst1 ()
544 val ((src1,src1size),
545 (src2,src2size)) = getSrc2 ()
548 ("x86MLton.prim: fbina, dstsize/src1size/src2size",
549 fn () => src1size = dstsize andalso
552 (* Reverse src1/src2 when src1 and src2 are temporaries.
555 = case (Operand.deMemloc src1, Operand.deMemloc src2)
556 of (SOME memloc_src1, SOME memloc_src2)
557 => if x86Liveness.track memloc_src1
559 x86Liveness.track memloc_src2
560 then (Instruction.fbina_reverse oper,src2,src1)
561 else (oper,src1,src2)
562 | _ => (oper,src1,src2)
568 = [Assembly.instruction_pfmov
572 Assembly.instruction_pfbina
582 val (dst,dstsize) = getDst1 ()
583 val ((src1,src1size),
585 (src3,src3size)) = getSrc3 ()
588 ("x86MLton.prim: fbina_fmul, dstsize/src1size/src2size/src3size",
589 fn () => src1size = dstsize andalso
590 src2size = dstsize andalso
597 = [Assembly.instruction_pfmov
601 Assembly.instruction_pfbina
602 {oper = Instruction.FMUL,
606 Assembly.instruction_pfbina
616 val (dst,dstsize) = getDst1 ()
617 val (src,srcsize) = getSrc1 ()
620 ("x86MLton.prim: funa, dstsize/srcsize",
621 fn () => srcsize = dstsize)
627 = [Assembly.instruction_pfmov
631 Assembly.instruction_pfuna
640 val (dst,dstsize) = getDst1 ()
641 val (src,srcsize) = getSrc1 ()
644 ("x86MLton.prim: flogarithm, dstsize/srcsize",
645 fn () => srcsize = dstsize)
651 = [Assembly.instruction_pfldc
655 Assembly.instruction_pfbinasp
656 {oper = Instruction.FYL2X,
665 = if !Control.Native.commented > 0
667 val comment = primName
673 = [x86.Assembly.comment
674 ("begin prim: " ^ comment)],
680 = [x86.Assembly.comment
681 ("end prim: " ^ comment)],
684 else (AppendList.empty,AppendList.empty)
685 fun bitop (size, i) =
686 case WordSize.prim size of
690 | W64 => binal64 (i, i)
691 fun compare (size, {signed}, s, u) =
693 val f = if signed then s else u
695 case WordSize.prim size of
699 | W64 => Error.bug "x86MLton.prim: compare, W64"
701 fun shift (size, i) =
702 case WordSize.prim size of
706 | W64 => Error.bug "x86MLton.prim: shift, W64"
710 (case Prim.name prim of
711 CPointer_add => binal Instruction.ADD
712 | CPointer_diff => binal Instruction.SUB
713 | CPointer_equal => cmp Instruction.E
714 | CPointer_fromWord => mov ()
715 | CPointer_lt => cmp Instruction.B
716 | CPointer_sub => binal Instruction.SUB
717 | CPointer_toWord => mov ()
718 | FFI_Symbol {name, symbolScope, ...}
720 datatype z = datatype CFunction.SymbolScope.t
721 datatype z = datatype Control.Format.t
722 datatype z = datatype MLton.Platform.OS.t
724 val (dst, dstsize) = getDst1 ()
726 val label = fn () => Label.fromString name
728 (* how to access an imported label's address *)
729 (* windows coff will add another leading _ to label *)
730 val coff = fn () => Label.fromString ("_imp__" ^ name)
734 Label.newString (concat ["L_", name, "_non_lazy_ptr"])
737 [Assembly.pseudoop_non_lazy_symbol_pointer (),
738 Assembly.label label,
739 Assembly.pseudoop_indirect_symbol (Label.fromString name),
740 Assembly.pseudoop_long [Immediate.zero]]
744 val elf = fn () => Label.fromString (name ^ "@GOT")
746 val importLabel = fn () =>
747 case !Control.Target.os of
753 val direct = fn () =>
758 [Assembly.instruction_lea
760 src = Operand.memloc_label (label ()),
764 val indirect = fn () =>
769 [Assembly.instruction_mov
771 src = Operand.memloc_label (importLabel ()),
777 !Control.positionIndependent) of
778 (* Even private PIC symbols on darwin need indirection. *)
779 (Private, Darwin, true) => indirect ()
780 (* As long as the symbol is private (thus it is not
781 * exported to code outside this text segment), then
782 * use normal addressing. If PIC is needed, then the
783 * memloc_label is updated to relative access in the
784 * allocate-registers pass.
786 | (Private, _, _) => direct ()
787 (* On darwin, even executables use the defintion address.
788 * Therefore we don't need to do indirection.
790 | (Public, Darwin, _) => direct ()
791 (* On ELF, a public symbol must be accessed via
792 * the GOT. This is because the final value may not be
793 * in this text segment. If the executable uses it, then
794 * the unique C address resides in the executable's
795 * text segment. The loader does this by creating a PLT
796 * proxy or copying values to the executable text segment.
797 * When linking an executable, ELF uses a special trick
798 * to "simplify" the code. All exported functions and
799 * symbols have pointers that correspond to the
800 * executable. Function pointers point to the
801 * automatically created PLT entry in the executable.
802 * Variables are copied/relocated into the executable bss.
804 * This means that direct access is fine for executable
805 * and archive formats. (It also means direct access is
806 * NOT fine for a library, even if it defines the symbol)
809 | (Public, _, true) => indirect ()
810 | (Public, _, false) => direct ()
811 (* On darwin, the address is the point of definition. So
812 * indirection is needed. We also need to make a stub!
814 | (External, Darwin, _) => indirect ()
815 (* On windows, the address is the point of definition. So
816 * we must always use an indirect lookup to the symbols
817 * windows rewrites (__imp__name) in our segment.
819 | (External, MinGW, _) => indirect ()
820 | (External, Cygwin, _) => indirect ()
821 (* When compiling ELF to a library, we access external
822 * symbols via some address that is updated by the loader.
823 * That address resides within our data segment, and can
824 * be easily referenced using RBX-relative addressing.
825 * This trick is used on every platform MLton supports.
826 * ELF rewrites symbols of form name@GOT.
828 | (External, _, true) => indirect ()
829 | (External, _, false) => direct ()
833 val (dst,dstsize) = getDst1 ()
834 val (src,srcsize) = getSrc1 ()
837 ("x86MLton.prim: Real_Math_acos, dstsize/srcsize",
838 fn () => srcsize = dstsize)
839 val realTemp1ContentsOperand = realTemp1ContentsOperand srcsize
840 val realTemp2ContentsOperand = realTemp2ContentsOperand srcsize
841 val realTemp3ContentsOperand = realTemp3ContentsOperand srcsize
847 = [Assembly.instruction_pfmov
848 {dst = realTemp1ContentsOperand,
851 Assembly.instruction_pfmov
852 {dst = realTemp2ContentsOperand,
853 src = realTemp1ContentsOperand,
855 Assembly.instruction_pfbina
856 {oper = Instruction.FMUL,
857 dst = realTemp2ContentsOperand,
858 src = realTemp2ContentsOperand,
860 Assembly.instruction_pfldc
861 {oper = Instruction.ONE,
862 dst = realTemp3ContentsOperand,
864 Assembly.instruction_pfbina
865 {oper = Instruction.FSUB,
866 dst = realTemp3ContentsOperand,
867 src = realTemp2ContentsOperand,
869 Assembly.instruction_pfuna
870 {oper = Instruction.FSQRT,
871 dst = realTemp3ContentsOperand,
873 Assembly.instruction_pfmov
875 src = realTemp3ContentsOperand,
877 Assembly.instruction_pfbinasp
878 {oper = Instruction.FPATAN,
879 src = realTemp1ContentsOperand,
886 val (dst,dstsize) = getDst1 ()
887 val (src,srcsize) = getSrc1 ()
890 ("x86MLton.prim: Real_Math_asin, dstsize/srcsize",
891 fn () => srcsize = dstsize)
892 val realTemp1ContentsOperand = realTemp1ContentsOperand srcsize
893 val realTemp2ContentsOperand = realTemp2ContentsOperand srcsize
899 = [Assembly.instruction_pfmov
903 Assembly.instruction_pfmov
904 {dst = realTemp1ContentsOperand,
907 Assembly.instruction_pfbina
908 {oper = Instruction.FMUL,
909 dst = realTemp1ContentsOperand,
910 src = realTemp1ContentsOperand,
912 Assembly.instruction_pfldc
913 {oper = Instruction.ONE,
914 dst = realTemp2ContentsOperand,
916 Assembly.instruction_pfbina
917 {oper = Instruction.FSUB,
918 dst = realTemp2ContentsOperand,
919 src = realTemp1ContentsOperand,
921 Assembly.instruction_pfuna
922 {oper = Instruction.FSQRT,
923 dst = realTemp2ContentsOperand,
925 Assembly.instruction_pfbinasp
926 {oper = Instruction.FPATAN,
927 src = realTemp2ContentsOperand,
934 val (dst,dstsize) = getDst1 ()
935 val (src,srcsize) = getSrc1 ()
938 ("x86MLton.prim: Real_Math_atan, dstsize/srcsize",
939 fn () => srcsize = dstsize)
940 val realTemp1ContentsOperand = realTemp1ContentsOperand srcsize
946 = [Assembly.instruction_pfmov
950 Assembly.instruction_pfldc
951 {oper = Instruction.ONE,
952 dst = realTemp1ContentsOperand,
954 Assembly.instruction_pfbinasp
955 {oper = Instruction.FPATAN,
956 src = realTemp1ContentsOperand,
963 val (dst,dstsize) = getDst1 ()
964 val ((src1,src1size),
965 (src2,src2size))= getSrc2 ()
968 ("x86MLton.prim: Real_Math_atan2, dstsize/src1size/src2size",
969 fn () => src1size = dstsize andalso
976 = [Assembly.instruction_pfmov
980 Assembly.instruction_pfbinasp
981 {oper = Instruction.FPATAN,
987 | Real_Math_cos _ => funa Instruction.FCOS
990 val (dst,dstsize) = getDst1 ()
991 val (src,srcsize) = getSrc1 ()
994 ("x86MLton.prim: Real_Math_exp, dstsize/srcsize",
995 fn () => srcsize = dstsize)
996 val realTemp1ContentsOperand = realTemp1ContentsOperand srcsize
997 val realTemp2ContentsOperand = realTemp2ContentsOperand srcsize
1003 = [Assembly.instruction_pfldc
1004 {oper = Instruction.L2E,
1007 Assembly.instruction_pfbina
1008 {oper = Instruction.FMUL,
1012 Assembly.instruction_pfmov
1014 dst = realTemp1ContentsOperand,
1016 Assembly.instruction_pfuna
1017 {oper = Instruction.FRNDINT,
1018 dst = realTemp1ContentsOperand,
1020 Assembly.instruction_pfbina
1021 {oper = Instruction.FSUB,
1022 src = realTemp1ContentsOperand,
1025 Assembly.instruction_pfuna
1026 {oper = Instruction.F2XM1,
1029 Assembly.instruction_pfldc
1030 {oper = Instruction.ONE,
1031 dst = realTemp2ContentsOperand,
1033 Assembly.instruction_pfbina
1034 {oper = Instruction.FADD,
1035 src = realTemp2ContentsOperand,
1038 Assembly.instruction_pfbinas
1039 {oper = Instruction.FSCALE,
1040 src = realTemp1ContentsOperand,
1045 | Real_Math_ln _ => flogarithm Instruction.LN2
1046 | Real_Math_log10 _ => flogarithm Instruction.LG2
1047 | Real_Math_sin _ => funa Instruction.FSIN
1048 | Real_Math_sqrt _ => funa Instruction.FSQRT
1051 val (dst,dstsize) = getDst1 ()
1052 val (src,srcsize) = getSrc1 ()
1055 ("x86MLton.prim: Real_Math_tan, dstsize/srcsize",
1056 fn () => srcsize = dstsize)
1062 = [Assembly.instruction_pfmov
1066 Assembly.instruction_pfptan
1071 | Real_mul _ => fbina Instruction.FMUL
1072 | Real_muladd _ => fbina_fmul Instruction.FADD
1073 | Real_mulsub _ => fbina_fmul Instruction.FSUB
1074 | Real_add _ => fbina Instruction.FADD
1075 | Real_sub _ => fbina Instruction.FSUB
1076 | Real_div _ => fbina Instruction.FDIV
1079 val (dst,dstsize) = getDst1 ()
1080 val ((src1,src1size),
1081 (src2,src2size))= getSrc2 ()
1084 ("x86MLton.prim: Real_lt, src1size/src2size",
1085 fn () => src1size = src2size)
1091 = [Assembly.instruction_pfcom
1095 Assembly.instruction_fstsw
1096 {dst = fpswTempContentsOperand,
1098 Assembly.instruction_test
1099 {src1 = fpswTempContentsOperand,
1100 src2 = Operand.immediate_int' (0x4500, WordSize.word16),
1102 Assembly.instruction_setcc
1103 {condition = Instruction.Z,
1110 val (dst,dstsize) = getDst1 ()
1111 val ((src1,src1size),
1112 (src2,src2size))= getSrc2 ()
1115 ("x86MLton.prim: Real_le, src1size/src2size",
1116 fn () => src1size = src2size)
1122 = [Assembly.instruction_pfcom
1126 Assembly.instruction_fstsw
1127 {dst = fpswTempContentsOperand,
1129 Assembly.instruction_test
1130 {src1 = fpswTempContentsOperand,
1131 src2 = Operand.immediate_int' (0x500, WordSize.word16),
1133 Assembly.instruction_setcc
1134 {condition = Instruction.Z,
1141 val (dst,dstsize) = getDst1 ()
1142 val ((src1,src1size),
1143 (src2,src2size))= getSrc2 ()
1146 ("x86MLton.prim: Real_equal, src1size/src2size",
1147 fn () => src1size = src2size)
1153 = [Assembly.instruction_pfucom
1157 Assembly.instruction_fstsw
1158 {dst = fpswTempContentsOperand,
1160 Assembly.instruction_binal
1161 {oper = Instruction.AND,
1162 dst = fpswTempContentsOperand,
1163 src = Operand.immediate_int' (0x4500, WordSize.word16),
1165 Assembly.instruction_cmp
1166 {src1 = fpswTempContentsOperand,
1167 src2 = Operand.immediate_int' (0x4000, WordSize.word16),
1169 Assembly.instruction_setcc
1170 {condition = Instruction.E,
1177 val (dst,dstsize) = getDst1 ()
1178 val ((src1,src1size),
1179 (src2,src2size))= getSrc2 ()
1182 ("x86MLton.prim: Real_qequal, src1size/src2size",
1183 fn () => src1size = src2size)
1189 = [Assembly.instruction_pfucom
1193 Assembly.instruction_fstsw
1194 {dst = fpswTempContentsOperand,
1196 Assembly.instruction_test
1197 {src1 = fpswTempContentsOperand,
1198 src2 = Operand.immediate_int' (0x4400, WordSize.word16),
1200 Assembly.instruction_setcc
1201 {condition = Instruction.NE,
1206 | Real_abs _ => funa Instruction.FABS
1207 | Real_rndToReal (s, s')
1209 val (dst,dstsize) = getDst1 ()
1210 val (src,srcsize) = getSrc1 ()
1216 = [Assembly.instruction_pfmov
1226 = [Assembly.instruction_pfmovx
1230 dstsize = dstsize}],
1237 = [Assembly.instruction_pfxvom
1241 dstsize = dstsize}],
1245 (R64, R64) => mov ()
1246 | (R64, R32) => xvom ()
1247 | (R32, R64) => movx ()
1248 | (R32, R32) => mov ()
1250 | Real_rndToWord (s, s', _)
1254 val (dst,dstsize) = getDst1 ()
1255 val (src,srcsize) = getSrc1 ()
1261 = [Assembly.instruction_pfmovti
1265 dstsize = dstsize}],
1270 val (dst,dstsize) = getDst1 ()
1271 val (src,srcsize) = getSrc1 ()
1273 (fildTempContentsOperand, Size.WORD)
1279 = [Assembly.instruction_pfmovti
1284 Assembly.instruction_xvom
1288 srcsize = tmpsize}],
1292 case (s, WordSize.prim s') of
1293 (R64, W64) => Error.bug "x86MLton.prim: Real_toWord, W64"
1294 | (R64, W32) => default ()
1295 | (R64, W16) => default ()
1296 | (R64, W8) => default' ()
1297 | (R32, W64) => Error.bug "x86MLton.prim: Real_toWord, W64"
1298 | (R32, W32) => default ()
1299 | (R32, W16) => default ()
1300 | (R32, W8) => default' ()
1304 val (dst,dstsize) = getDst1 ()
1305 val ((src1,src1size),
1306 (src2,src2size)) = getSrc2 ()
1309 ("x86MLton.prim: Real_ldexp, dstsize/src1size",
1310 fn () => src1size = dstsize)
1313 ("x86MLton.prim: Real_ldexp, src2size",
1314 fn () => src2size = Size.LONG)
1315 val realTemp1ContentsOperand = realTemp1ContentsOperand src1size
1321 = [Assembly.instruction_pfmovfi
1322 {dst = realTemp1ContentsOperand,
1326 Assembly.instruction_pfmov
1330 Assembly.instruction_pfbinas
1331 {oper = Instruction.FSCALE,
1333 src = realTemp1ContentsOperand,
1337 | Real_neg _ => funa Instruction.FCHS
1338 | Real_round _ => funa Instruction.FRNDINT
1340 (case WordSize.prim s of
1341 W8 => binal Instruction.ADD
1342 | W16 => binal Instruction.ADD
1343 | W32 => binal Instruction.ADD
1344 | W64 => binal64 (Instruction.ADD, Instruction.ADC))
1345 | Word_andb s => bitop (s, Instruction.AND)
1346 | Word_equal _ => cmp Instruction.E
1347 | Word_lshift s => shift (s, Instruction.SHL)
1348 | Word_lt (s, sg) => compare (s, sg, Instruction.L, Instruction.B)
1349 | Word_mul (s, {signed}) =>
1350 (case WordSize.prim s of
1351 W8 => pmd (if signed
1352 then Instruction.IMUL
1353 else Instruction.MUL)
1356 | W64 => Error.bug "x86MLton.prim: Word_mul, W64")
1358 (case WordSize.prim s of
1359 W8 => unal Instruction.NEG
1360 | W16 => unal Instruction.NEG
1361 | W32 => unal Instruction.NEG
1362 | W64 => unal64 (Instruction.NEG,
1363 fn (dst,dstsize) => [Assembly.instruction_binal
1365 oper = Instruction.ADC,
1366 src = Operand.immediate_zero,
1369 (case WordSize.prim s of
1370 W8 => unal Instruction.NOT
1371 | W16 => unal Instruction.NOT
1372 | W32 => unal Instruction.NOT
1373 | W64 => unal64 (Instruction.NOT, fn _ => []))
1374 | Word_orb s => bitop (s, Instruction.OR)
1375 | Word_quot (_, {signed}) =>
1376 pmd (if signed then Instruction.IDIV else Instruction.DIV)
1377 | Word_rem (_, {signed}) =>
1378 pmd (if signed then Instruction.IMOD else Instruction.MOD)
1379 | Word_rol s => shift (s, Instruction.ROL)
1380 | Word_ror s => shift (s, Instruction.ROR)
1381 | Word_rshift (s, {signed}) =>
1382 shift (s, if signed then Instruction.SAR else Instruction.SHR)
1384 (case WordSize.prim s of
1385 W8 => binal Instruction.SUB
1386 | W16 => binal Instruction.SUB
1387 | W32 => binal Instruction.SUB
1388 | W64 => binal64 (Instruction.SUB, Instruction.SBB))
1389 | Word_rndToReal (s, s', _)
1393 val (dst,dstsize) = getDst1 ()
1394 val (src,srcsize) = getSrc1 ()
1400 = [Assembly.instruction_pfmovfi
1404 dstsize = dstsize}],
1409 val (dst,dstsize) = getDst1 ()
1410 val (src,srcsize) = getSrc1 ()
1412 (fildTempContentsOperand, Size.WORD)
1418 = [Assembly.instruction_movx
1419 {oper = Instruction.MOVSX,
1424 Assembly.instruction_pfmovfi
1428 dstsize = dstsize}],
1432 case (WordSize.prim s, s') of
1433 (W32, R64) => default ()
1434 | (W32, R32) => default ()
1435 | (W16, R64) => default ()
1436 | (W16, R32) => default ()
1437 | (W8, R64) => default' ()
1438 | (W8, R32) => default' ()
1439 | _ => Error.bug "x86MLton.prim: Word_toReal, W64"
1441 | Word_extdToWord (s, s', {signed}) =>
1443 val b = WordSize.bits s
1444 val b' = WordSize.bits s'
1447 then movx (if signed
1448 then Instruction.MOVSX
1449 else Instruction.MOVZX)
1450 else if Bits.equals (b, b')
1454 | Word_xorb s => bitop (s, Instruction.XOR)
1455 | _ => Error.bug ("x86MLton.prim: strange Prim.Name.t: " ^ primName)),
1459 fun ccall {args: (x86.Operand.t * x86.Size.t) vector,
1462 return: x86.Label.t option,
1463 transInfo = {...}: transInfo}
1465 val CFunction.T {convention, target, ...} = func
1467 = if !Control.Native.commented > 0
1468 then AppendList.single
1472 [x86.Assembly.comment
1475 CFunction.Convention.toString convention,
1477 CFunction.Target.toString target])],
1479 else AppendList.empty
1487 transfer = SOME (Transfer.ccall
1488 {args = Vector.toList args,
1489 frameInfo = frameInfo,
1491 return = return})})]
1494 fun creturn {dsts: (x86.Operand.t * x86.Size.t) vector,
1495 frameInfo: x86.FrameInfo.t option,
1496 func: RepType.t CFunction.t,
1498 transInfo = {live, liveInfo, ...}: transInfo}
1500 val CFunction.T {convention, target, ...} = func
1503 val _ = x86Liveness.LiveInfo.setLiveOperands
1504 (liveInfo, label, live label)
1508 {entry = SOME (Entry.creturn {dsts = dsts,
1509 frameInfo = frameInfo,
1516 = if !Control.Native.commented > 0
1517 then AppendList.single
1521 [x86.Assembly.comment
1524 CFunction.Convention.toString convention,
1526 CFunction.Target.toString target])],
1528 else AppendList.empty
1530 AppendList.appends [default (), comment_end]
1533 fun arith {prim : RepType.t Prim.t,
1534 args : (Operand.t * Size.t) vector,
1535 dsts : (Operand.t * Size.t) vector,
1538 transInfo = {live, liveInfo, ...} : transInfo}
1540 val primName = Prim.toString prim
1541 datatype z = datatype Prim.Name.t
1544 = Vector.sub (dsts, 0)
1545 handle _ => Error.bug "x86MLton.arith: getDst1"
1547 = (Vector.sub (dsts, 0), Vector.sub (dsts, 1))
1548 handle _ => Error.bug "x86MLton.arith: getDst2"
1550 = Vector.sub (args, 0)
1551 handle _ => Error.bug "x86MLton.arith: getSrc1"
1553 = (Vector.sub (args, 0), Vector.sub (args, 1))
1554 handle _ => Error.bug "x86MLton.arith: getSrc2"
1556 = (Vector.sub (args, 0), Vector.sub (args, 1),
1557 Vector.sub (args, 2), Vector.sub (args, 3))
1558 handle _ => Error.bug "x86MLton.arith: getSrc4"
1560 fun check (statements, condition)
1564 statements = statements,
1565 transfer = SOME (x86.Transfer.iff
1566 {condition = condition,
1568 falsee = success})})
1569 fun binal (oper: x86.Instruction.binal, condition)
1571 val (dst, dstsize) = getDst1 ()
1572 val ((src1, src1size), (src2, src2size)) = getSrc2 ()
1573 val _ = Assert.assert
1574 ("x86MLton.arith: binal, dstsize/src1size/src2size",
1575 fn () => src1size = dstsize andalso src2size = dstsize)
1576 (* Reverse src1/src2 when src1 and src2 are
1577 * temporaries and the oper is commutative.
1580 = if (oper = x86.Instruction.ADD)
1581 then case (x86.Operand.deMemloc src1,
1582 x86.Operand.deMemloc src2)
1583 of (SOME memloc_src1, SOME memloc_src2)
1584 => if x86Liveness.track memloc_src1
1586 x86Liveness.track memloc_src2
1592 check ([Assembly.instruction_mov
1596 Assembly.instruction_binal
1603 fun binal64 (oper1: x86.Instruction.binal,
1604 oper2: x86.Instruction.binal,
1607 val ((dst1, dst1size), (dst2, dst2size)) = getDst2 ()
1608 val ((src1, src1size), (src2, src2size),
1609 (src3, src3size), (src4, src4size)) = getSrc4 ()
1610 val _ = Assert.assert
1611 ("x86MLton.arith: binal64, dst1size/dst2size/src1size/src2size/src3size/src4size",
1612 fn () => src1size = dst1size andalso src3size = dst1size andalso
1613 src2size = dst2size andalso src4size = dst2size andalso
1614 dst1size = dst2size)
1616 if List.exists ([src2,src3,src4], fn src =>
1617 Operand.mayAlias (dst1, src))
1618 then wordTemp1ContentsOperand dst1size
1621 if List.exists ([src3,src4], fn src =>
1622 Operand.mayAlias (dst2, src))
1623 then wordTemp1ContentsOperand dst2size
1626 check ([Assembly.instruction_mov
1630 Assembly.instruction_mov
1634 Assembly.instruction_binal
1639 Assembly.instruction_binal
1644 Assembly.instruction_mov
1648 Assembly.instruction_mov
1654 fun pmd (oper: x86.Instruction.md, condition)
1656 val (dst, dstsize) = getDst1 ()
1657 val ((src1, src1size), (src2, src2size)) = getSrc2 ()
1658 val _ = Assert.assert
1659 ("x86MLton.arith: pmd, dstsize/src1size/src2size",
1660 fn () => src1size = dstsize andalso src2size = dstsize)
1661 (* Reverse src1/src2 when src1 and src2 are
1662 * temporaries and the oper is commutative.
1665 = if oper = x86.Instruction.MUL
1666 then case (x86.Operand.deMemloc src1,
1667 x86.Operand.deMemloc src2)
1668 of (SOME memloc_src1, SOME memloc_src2)
1669 => if x86Liveness.track memloc_src1
1671 x86Liveness.track memloc_src2
1677 check ([Assembly.instruction_mov
1681 Assembly.instruction_pmd
1688 fun unal (oper: x86.Instruction.unal, condition)
1690 val (dst, dstsize) = getDst1 ()
1691 val (src1, src1size) = getSrc1 ()
1692 val _ = Assert.assert
1693 ("x86MLton.arith: unal, dstsize/src1size",
1694 fn () => src1size = dstsize)
1696 check ([Assembly.instruction_mov
1700 Assembly.instruction_unal
1709 val ((dst1, dst1size), (dst2, dst2size)) = getDst2 ()
1710 val ((src1, src1size), (src2, src2size)) = getSrc2 ()
1711 val _ = Assert.assert
1712 ("x86MLton.arith: neg64, dst1size/dst2size/src1size/src2size",
1713 fn () => src1size = dst1size andalso
1714 src2size = dst2size andalso
1715 dst1size = dst2size)
1717 if List.exists ([src2], fn src =>
1718 Operand.mayAlias (dst1, src))
1719 then wordTemp1ContentsOperand dst1size
1721 val loZ = Label.newString "loZ"
1722 val _ = x86Liveness.LiveInfo.setLiveOperands
1723 (liveInfo, loZ, dst2::((live success) @ (live overflow)))
1724 val loNZ = Label.newString "loNZ"
1725 val _ = x86Liveness.LiveInfo.setLiveOperands
1726 (liveInfo, loNZ, dst2::(live success))
1731 statements = [Assembly.instruction_mov
1735 Assembly.instruction_mov
1739 Assembly.instruction_mov
1743 Assembly.instruction_unal
1744 {oper = x86.Instruction.NEG,
1747 transfer = SOME (x86.Transfer.iff
1748 {condition = x86.Instruction.Z,
1752 {entry = SOME (x86.Entry.jump {label = loNZ}),
1753 statements = [Assembly.instruction_unal
1755 oper = Instruction.INC,
1757 Assembly.instruction_unal
1758 {oper = x86.Instruction.NEG,
1761 transfer = SOME (x86.Transfer.goto {target = success})},
1763 {entry = SOME (x86.Entry.jump {label = loZ}),
1764 statements = [Assembly.instruction_unal
1765 {oper = x86.Instruction.NEG,
1768 transfer = SOME (x86.Transfer.iff
1769 {condition = x86.Instruction.O,
1771 falsee = success})}]
1776 val (dst, dstsize) = getDst1 ()
1777 val ((src1, src1size), (src2, src2size)) = getSrc2 ()
1778 val _ = Assert.assert
1779 ("x86MLton.arith: imul2, dstsize/src1size/src2size",
1780 fn () => src1size = dstsize andalso src2size = dstsize)
1781 (* Reverse src1/src2 when src1 and src2 are
1782 * temporaries and the oper is commutative.
1785 = case (x86.Operand.deMemloc src1,
1786 x86.Operand.deMemloc src2)
1787 of (SOME memloc_src1, SOME memloc_src2)
1788 => if x86Liveness.track memloc_src1
1790 x86Liveness.track memloc_src2
1795 check ([Assembly.instruction_mov
1799 Assembly.instruction_imul2
1806 val (comment_begin,_)
1807 = if !Control.Native.commented > 0
1809 val comment = primName
1815 = [x86.Assembly.comment
1816 ("begin arith: " ^ comment)],
1822 = [x86.Assembly.comment
1823 ("end arith: " ^ comment)],
1826 else (AppendList.empty,AppendList.empty)
1828 if signed then x86.Instruction.O else x86.Instruction.C
1832 (case Prim.name prim of
1833 Word_addCheck (s, sg) =>
1837 case WordSize.prim s of
1838 W8 => binal (x86.Instruction.ADD, flag)
1839 | W16 => binal (x86.Instruction.ADD, flag)
1840 | W32 => binal (x86.Instruction.ADD, flag)
1841 | W64 => binal64 (x86.Instruction.ADD, x86.Instruction.ADC, flag)
1843 | Word_mulCheck (s, {signed}) =>
1848 (case WordSize.prim s of
1849 W8 => pmd (x86.Instruction.IMUL, x86.Instruction.O)
1850 | W16 => imul2 x86.Instruction.O
1851 | W32 => imul2 x86.Instruction.O
1852 | W64 => Error.bug "x86MLton.arith: Word_mulCheck, W64")
1854 (case WordSize.prim s of
1855 W8 => pmd (x86.Instruction.MUL, x86.Instruction.C)
1856 | W16 => pmd (x86.Instruction.MUL, x86.Instruction.C)
1857 | W32 => pmd (x86.Instruction.MUL, x86.Instruction.C)
1858 | W64 => Error.bug "x86MLton.arith: Word_mulCheck, W64")
1860 | Word_negCheck s =>
1861 (case WordSize.prim s of
1862 W8 => unal (x86.Instruction.NEG, x86.Instruction.O)
1863 | W16 => unal (x86.Instruction.NEG, x86.Instruction.O)
1864 | W32 => unal (x86.Instruction.NEG, x86.Instruction.O)
1866 | Word_subCheck (s, sg) =>
1870 case WordSize.prim s of
1871 W8 => binal (x86.Instruction.SUB, flag)
1872 | W16 => binal (x86.Instruction.SUB, flag)
1873 | W32 => binal (x86.Instruction.SUB, flag)
1874 | W64 => binal64 (x86.Instruction.SUB, x86.Instruction.SBB, flag)
1876 | _ => Error.bug ("x86MLton.arith: strange Prim.Name.t: " ^ primName))]