1 # Copyright (C) 2012 Apple Inc. All rights reserved.
2 # Copyright (C) 2013 Digia Plc. and/or its subsidiary(-ies)
4 # Redistribution and use in source and binary forms, with or without
5 # modification, are permitted provided that the following conditions
7 # 1. Redistributions of source code must retain the above copyright
8 # notice, this list of conditions and the following disclaimer.
9 # 2. Redistributions in binary form must reproduce the above copyright
10 # notice, this list of conditions and the following disclaimer in the
11 # documentation and/or other materials provided with the distribution.
13 # THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 # THE POSSIBILITY OF SUCH DAMAGE.
36 raise "bad value for $activeBackend: #{$activeBackend}"
49 raise "bad value for $activeBackend: #{$activeBackend}"
54 RUBY_PLATFORM =~ /cygwin/i
70 isIntelSyntax ? name : "%" + name
73 def offsetRegister(off, register)
74 isIntelSyntax ? "[#{off} + #{register}]" : "#{off}(#{register})"
78 isIntelSyntax ? "" : "*"
81 def orderOperands(opA, opB)
82 isIntelSyntax ? "#{opB}, #{opA}" : "#{opA}, #{opB}"
86 isIntelSyntax ? "#{c}" : "$#{c}"
89 def getSizeString(kind)
110 return size + " " + "ptr" + " ";
113 class SpecialRegister < NoChildren
115 raise unless @name =~ /^r/
130 def x86CallOperand(kind)
131 # Call operands are not allowed to be partial registers.
132 "#{callPrefix}#{x86Operand(:quad)}"
136 X64_SCRATCH_REGISTER = SpecialRegister.new("r11")
139 def supports8BitOnX86
141 when "t0", "a0", "r0", "t1", "a1", "r1", "t2", "t3", "t4", "t5"
143 when "cfr", "ttnr", "tmr"
154 when "t0", "a0", "r0"
163 isX64 ? register("rax") : register("eax")
165 isX64 ? register("rax") : raise
167 raise "Invalid kind #{kind} for name #{name}"
169 when "t1", "a1", "r1"
178 isX64 ? register("rdx") : register("edx")
180 isX64 ? register("rdx") : raise
193 isX64 ? register("rcx") : register("ecx")
195 isX64 ? register("rcx") : raise
208 isX64 ? register("rbx") : register("ebx")
210 isX64 ? register("rbx") : raise
223 isX64 ? register("rdi") : register("edi")
225 isX64 ? register("rdi") : raise
264 isX64 ? register("rsp") : register("esp")
266 isX64 ? register("rsp") : raise
279 isX64 ? register("rsi") : register("esi")
281 isX64 ? register("rsi") : raise
284 raise "Cannot use #{name} in 32-bit X86 at #{codeOriginString}" unless isX64
296 raise "Cannot use #{name} in 32-bit X86 at #{codeOriginString}" unless isX64
308 raise "Cannot use #{name} in 32-bit X86 at #{codeOriginString}" unless isX64
320 raise "Bad register #{name} for X86 at #{codeOriginString}"
323 def x86CallOperand(kind)
324 isX64 ? "#{callPrefix}#{x86Operand(:quad)}" : "#{callPrefix}#{x86Operand(:ptr)}"
330 raise unless kind == :double
333 when "ft0", "fa0", "fr"
346 raise "Bad register #{name} for X86 at #{codeOriginString}"
349 def x87DefaultStackPosition
355 when "ft2", "ft3", "ft4", "ft5"
356 raise "Unimplemented register #{name} for X86 at #{codeOriginString}"
358 raise "Bad register #{name} for X86 at #{codeOriginString}"
361 def x87Operand(offset)
363 raise unless offset == 0 or offset == 1
364 "#{register("st")}(#{x87DefaultStackPosition + offset})"
366 def x86CallOperand(kind)
367 "#{callPrefix}#{x86Operand(kind)}"
372 def validX86Immediate?
374 value >= -0x80000000 and value <= 0x7fffffff
382 def x86CallOperand(kind)
388 def supports8BitOnX86
392 def x86AddressOperand(addressKind)
393 "#{offsetRegister(offset.value, base.x86Operand(addressKind))}"
396 "#{getSizeString(kind)}#{x86AddressOperand(:ptr)}"
398 def x86CallOperand(kind)
399 "#{callPrefix}#{x86Operand(kind)}"
404 def supports8BitOnX86
408 def x86AddressOperand(addressKind)
410 "#{offset.value}(#{base.x86Operand(addressKind)}, #{index.x86Operand(addressKind)}, #{scale})"
412 "#{getSizeString(addressKind)}[#{offset.value} + #{base.x86Operand(addressKind)} + #{index.x86Operand(addressKind)} * #{scale}]"
418 x86AddressOperand(:ptr)
420 "#{getSizeString(kind)}[#{offset.value} + #{base.x86Operand(:ptr)} + #{index.x86Operand(:ptr)} * #{scale}]"
424 def x86CallOperand(kind)
425 "#{callPrefix}#{x86Operand(kind)}"
429 class AbsoluteAddress
430 def supports8BitOnX86
434 def x86AddressOperand(addressKind)
442 def x86CallOperand(kind)
443 "#{callPrefix}#{address.value}"
448 def x86CallOperand(kind)
453 class LocalLabelReference
454 def x86CallOperand(kind)
460 def getModifiedListX86_64
466 if node.is_a? Instruction
467 unless node.opcode == "move"
469 newOperands = node.operands.map {
471 if operand.immediate? and not operand.validX86Immediate?
473 raise "Attempt to use scratch register twice at #{operand.codeOriginString}"
475 newList << Instruction.new(operand.codeOrigin, "move", [operand, X64_SCRATCH_REGISTER])
482 newNode = Instruction.new(node.codeOrigin, node.opcode, newOperands, node.annotation)
485 unless node.is_a? Label or
486 node.is_a? LocalLabel or
488 raise "Unexpected #{node.inspect} at #{node.codeOrigin}"
501 @@floatingPointCompareImplicitOperand = isIntelSyntax ? "st(0), " : ""
502 @@exportedSymbols = Array.new
504 def x86Operands(*kinds)
505 raise unless kinds.size == operands.size
509 i = isIntelSyntax ? (kinds.size - idx - 1) : idx
510 result << operands[i].x86Operand(kinds[i])
532 not useX87 ? "sd" : raise
557 def handleX86OpWithNumOperands(opcode, kind, numOperands)
559 if operands[0] == operands[2]
560 $asm.puts "#{opcode} #{orderOperands(operands[1].x86Operand(kind), operands[2].x86Operand(kind))}"
561 elsif operands[1] == operands[2]
562 $asm.puts "#{opcode} #{orderOperands(operands[0].x86Operand(kind), operands[2].x86Operand(kind))}"
564 $asm.puts "mov#{x86Suffix(kind)} #{orderOperands(operands[0].x86Operand(kind), operands[2].x86Operand(kind))}"
565 $asm.puts "#{opcode} #{orderOperands(operands[1].x86Operand(kind), operands[2].x86Operand(kind))}"
568 $asm.puts "#{opcode} #{orderOperands(operands[0].x86Operand(kind), operands[1].x86Operand(kind))}"
572 def handleX86Op(opcode, kind)
573 handleX86OpWithNumOperands(opcode, kind, operands.size)
576 def handleX86Shift(opcode, kind)
577 if operands[0].is_a? Immediate or operands[0] == RegisterID.forName(nil, "t2")
578 $asm.puts "#{opcode} #{orderOperands(operands[0].x86Operand(:byte), operands[1].x86Operand(kind))}"
580 cx = RegisterID.forName(nil, "t2")
581 $asm.puts "xchg#{x86Suffix(:ptr)} #{operands[0].x86Operand(:ptr)}, #{cx.x86Operand(:ptr)}"
582 $asm.puts "#{opcode} #{orderOperands(register("cl"), operands[1].x86Operand(kind))}"
583 $asm.puts "xchg#{x86Suffix(:ptr)} #{operands[0].x86Operand(:ptr)}, #{cx.x86Operand(:ptr)}"
587 def handleX86DoubleBranch(branchOpcode, mode)
589 handleX87Compare(mode)
593 $asm.puts "ucomisd #{operands[1].x86Operand(:double)}, #{operands[0].x86Operand(:double)}"
595 $asm.puts "ucomisd #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:double)}"
600 $asm.puts "#{branchOpcode} #{operands[2].asmLabel}"
603 def handleX86IntCompare(opcodeSuffix, kind)
604 if operands[0].is_a? Immediate and operands[0].value == 0 and operands[1].is_a? RegisterID and (opcodeSuffix == "e" or opcodeSuffix == "ne")
605 $asm.puts "test#{x86Suffix(kind)} #{orderOperands(operands[1].x86Operand(kind), operands[1].x86Operand(kind))}"
606 elsif operands[1].is_a? Immediate and operands[1].value == 0 and operands[0].is_a? RegisterID and (opcodeSuffix == "e" or opcodeSuffix == "ne")
607 $asm.puts "test#{x86Suffix(kind)} #{orderOperands(operands[0].x86Operand(kind), operands[0].x86Operand(kind))}"
609 $asm.puts "cmp#{x86Suffix(kind)} #{orderOperands(operands[1].x86Operand(kind), operands[0].x86Operand(kind))}"
613 def handleX86IntBranch(branchOpcode, kind)
614 handleX86IntCompare(branchOpcode[1..-1], kind)
615 $asm.puts "#{branchOpcode} #{operands[2].asmLabel}"
618 def handleX86Set(setOpcode, operand)
619 if operand.supports8BitOnX86
620 $asm.puts "#{setOpcode} #{operand.x86Operand(:byte)}"
622 $asm.puts "movzbl #{orderOperands(operand.x86Operand(:byte), operand.x86Operand(:int))}"
624 $asm.puts "movzx #{orderOperands(operand.x86Operand(:byte), operand.x86Operand(:int))}"
627 ax = RegisterID.new(nil, "t0")
628 $asm.puts "xchg#{x86Suffix(:ptr)} #{operand.x86Operand(:ptr)}, #{ax.x86Operand(:ptr)}"
629 $asm.puts "#{setOpcode} %al"
630 $asm.puts "movzbl %al, %eax"
631 $asm.puts "xchg#{x86Suffix(:ptr)} #{operand.x86Operand(:ptr)}, #{ax.x86Operand(:ptr)}"
635 def handleX86IntCompareSet(setOpcode, kind)
636 handleX86IntCompare(setOpcode[3..-1], kind)
637 handleX86Set(setOpcode, operands[2])
640 def handleX86Test(kind)
644 mask = Immediate.new(codeOrigin, -1)
648 raise "Expected 2 or 3 operands, but got #{operands.size} at #{codeOriginString}"
651 if mask.is_a? Immediate and mask.value == -1
652 if value.is_a? RegisterID
653 $asm.puts "test#{x86Suffix(kind)} #{value.x86Operand(kind)}, #{value.x86Operand(kind)}"
655 $asm.puts "cmp#{x86Suffix(kind)} #{orderOperands(const(0), value.x86Operand(kind))}"
658 $asm.puts "test#{x86Suffix(kind)} #{orderOperands(mask.x86Operand(kind), value.x86Operand(kind))}"
662 def handleX86BranchTest(branchOpcode, kind)
664 $asm.puts "#{branchOpcode} #{operands.last.asmLabel}"
667 def handleX86SetTest(setOpcode, kind)
669 handleX86Set(setOpcode, operands.last)
672 def handleX86OpBranch(opcode, branchOpcode, kind)
673 handleX86OpWithNumOperands(opcode, kind, operands.size - 1)
676 jumpTarget = operands[3]
678 jumpTarget = operands[2]
682 $asm.puts "#{branchOpcode} #{jumpTarget.asmLabel}"
685 def handleX86SubBranch(branchOpcode, kind)
686 if operands.size == 4 and operands[1] == operands[2]
687 $asm.puts "neg#{x86Suffix(kind)} #{operands[2].x86Operand(kind)}"
688 $asm.puts "add#{x86Suffix(kind)} #{orderOperands(operands[0].x86Operand(kind), operands[2].x86Operand(kind))}"
690 handleX86OpWithNumOperands("sub#{x86Suffix(kind)}", kind, operands.size - 1)
694 jumpTarget = operands[3]
696 jumpTarget = operands[2]
700 $asm.puts "#{branchOpcode} #{jumpTarget.asmLabel}"
703 def handleX86Add(kind)
704 if operands.size == 3 and operands[1] == operands[2]
705 unless Immediate.new(nil, 0) == operands[0]
706 $asm.puts "add#{x86Suffix(kind)} #{orderOperands(operands[0].x86Operand(kind), operands[2].x86Operand(kind))}"
708 elsif operands.size == 3 and operands[0].is_a? Immediate
709 raise unless operands[1].is_a? RegisterID
710 raise unless operands[2].is_a? RegisterID
711 if operands[0].value == 0
712 unless operands[1] == operands[2]
713 $asm.puts "mov#{x86Suffix(kind)} #{orderOperands(operands[1].x86Operand(kind), operands[2].x86Operand(kind))}"
716 $asm.puts "lea#{x86Suffix(kind)} #{orderOperands(offsetRegister(operands[0].value, operands[1].x86Operand(kind)), operands[2].x86Operand(kind))}"
718 elsif operands.size == 3 and operands[0].is_a? RegisterID
719 raise unless operands[1].is_a? RegisterID
720 raise unless operands[2].is_a? RegisterID
721 if operands[0] == operands[2]
722 $asm.puts "add#{x86Suffix(kind)} #{orderOperands(operands[1].x86Operand(kind), operands[2].x86Operand(kind))}"
725 $asm.puts "lea#{x86Suffix(kind)} (#{operands[0].x86Operand(kind)}, #{operands[1].x86Operand(kind)}), #{operands[2].x86Operand(kind)}"
727 $asm.puts "lea#{x86Suffix(kind)} #{operands[2].x86Operand(kind)}, [#{operands[0].x86Operand(kind)} + #{operands[1].x86Operand(kind)}]"
731 unless Immediate.new(nil, 0) == operands[0]
732 $asm.puts "add#{x86Suffix(kind)} #{x86Operands(kind, kind)}"
737 def handleX86Sub(kind)
738 if operands.size == 3 and operands[1] == operands[2]
739 $asm.puts "neg#{x86Suffix(kind)} #{operands[2].x86Operand(kind)}"
740 $asm.puts "add#{x86Suffix(kind)} #{orderOperands(operands[0].x86Operand(kind), operands[2].x86Operand(kind))}"
742 handleX86Op("sub#{x86Suffix(kind)}", kind)
746 def handleX86Mul(kind)
747 if operands.size == 3 and operands[0].is_a? Immediate
748 $asm.puts "imul#{x86Suffix(kind)} #{x86Operands(kind, kind, kind)}"
750 # FIXME: could do some peephole in case the left operand is immediate and it's
752 handleX86Op("imul#{x86Suffix(kind)}", kind)
757 sp = RegisterID.new(nil, "sp")
758 opA = offsetRegister(operands[0].value * x86Bytes(:ptr), sp.x86Operand(:ptr))
759 opB = operands[1].x86Operand(:ptr)
760 $asm.puts "mov#{x86Suffix(:ptr)} #{orderOperands(opA, opB)}"
764 sp = RegisterID.new(nil, "sp")
765 opA = operands[0].x86Operand(:ptr)
766 opB = offsetRegister(operands[1].value * x86Bytes(:ptr), sp.x86Operand(:ptr))
767 $asm.puts "mov#{x86Suffix(:ptr)} #{orderOperands(opA, opB)}"
771 if Immediate.new(nil, 0) == operands[0] and operands[1].is_a? RegisterID
773 $asm.puts "xor#{x86Suffix(:quad)} #{operands[1].x86Operand(:quad)}, #{operands[1].x86Operand(:quad)}"
775 $asm.puts "xor#{x86Suffix(:ptr)} #{operands[1].x86Operand(:ptr)}, #{operands[1].x86Operand(:ptr)}"
777 elsif operands[0] != operands[1]
779 $asm.puts "mov#{x86Suffix(:quad)} #{x86Operands(:quad, :quad)}"
781 $asm.puts "mov#{x86Suffix(:ptr)} #{x86Operands(:ptr, :ptr)}"
786 def handleX87Compare(mode)
789 if (operands[0].x87DefaultStackPosition == 0)
790 $asm.puts "fucomi #{@@floatingPointCompareImplicitOperand}#{operands[1].x87Operand(0)}"
792 $asm.puts "fld #{operands[0].x87Operand(0)}"
793 $asm.puts "fucomip #{@@floatingPointCompareImplicitOperand}#{operands[1].x87Operand(1)}"
796 if (operands[1].x87DefaultStackPosition == 0)
797 $asm.puts "fucomi #{@@floatingPointCompareImplicitOperand}#{operands[0].x87Operand(0)}"
799 $asm.puts "fld #{operands[1].x87Operand(0)}"
800 $asm.puts "fucomip #{@@floatingPointCompareImplicitOperand}#{operands[0].x87Operand(1)}"
807 def handleX87BinOp(opcode, opcodereverse)
808 if (operands[1].x87DefaultStackPosition == 0)
809 $asm.puts "#{opcode} #{orderOperands(operands[0].x87Operand(0), register("st"))}"
810 elsif (operands[0].x87DefaultStackPosition == 0)
812 $asm.puts "#{opcodereverse} #{register("st")}, #{operands[1].x87Operand(0)}"
814 $asm.puts "#{opcode} #{operands[1].x87Operand(0)}, #{register("st")}"
817 $asm.puts "fld #{operands[0].x87Operand(0)}"
818 $asm.puts "#{opcodereverse}p #{orderOperands(register("st"), operands[1].x87Operand(1))}"
823 raise unless $activeBackend == "X86"
828 raise unless $activeBackend == "X86_WIN"
833 raise unless $activeBackend == "X86_64"
837 def writeSymbolToFile(symbol)
840 alreadyExported = @@exportedSymbols.include?(symbol)
843 @@exportedSymbols.push(symbol)
845 # Write symbols needed by MASM
846 File.open("#{File.basename($output.path)}.sym", "a") {
848 outp.puts "EXTERN #{symbol} : near"
854 $asm.codeOrigin codeOriginString if $enableCodeOriginComments
855 $asm.annotation annotation if $enableInstrAnnotations
865 handleX86Op("and#{x86Suffix(:int)}", :int)
867 handleX86Op("and#{x86Suffix(:ptr)}", :ptr)
869 handleX86Op("and#{x86Suffix(:quad)}", :quad)
871 handleX86Shift("sal#{x86Suffix(:int)}", :int)
873 handleX86Shift("sal#{x86Suffix(:ptr)}", :ptr)
875 handleX86Shift("sal#{x86Suffix(:quad)}", :quad)
883 $asm.puts "neg#{x86Suffix(:int)} #{x86Operands(:int)}"
885 $asm.puts "neg#{x86Suffix(:ptr)} #{x86Operands(:ptr)}"
887 $asm.puts "neg#{x86Suffix(:quad)} #{x86Operands(:quad)}"
889 $asm.puts "not#{x86Suffix(:int)} #{x86Operands(:int)}"
891 handleX86Op("or#{x86Suffix(:int)}", :int)
893 handleX86Op("or#{x86Suffix(:ptr)}", :ptr)
895 handleX86Op("or#{x86Suffix(:quad)}", :quad)
897 handleX86Shift("sar#{x86Suffix(:int)}", :int)
899 handleX86Shift("sar#{x86Suffix(:ptr)}", :ptr)
901 handleX86Shift("sar#{x86Suffix(:quad)}", :quad)
903 handleX86Shift("shr#{x86Suffix(:int)}", :int)
905 handleX86Shift("shr#{x86Suffix(:ptr)}", :ptr)
907 handleX86Shift("shr#{x86Suffix(:quad)}", :quad)
915 handleX86Op("xor#{x86Suffix(:int)}", :int)
917 handleX86Op("xor#{x86Suffix(:ptr)}", :ptr)
919 handleX86Op("xor#{x86Suffix(:quad)}", :quad)
920 when "loadi", "storei"
921 $asm.puts "mov#{x86Suffix(:int)} #{x86Operands(:int, :int)}"
924 $asm.puts "movslq #{x86Operands(:int, :quad)}"
926 $asm.puts "mov#{x86Suffix(:int)} #{x86Operands(:int, :int)}"
928 when "loadp", "storep"
929 $asm.puts "mov#{x86Suffix(:ptr)} #{x86Operands(:ptr, :ptr)}"
930 when "loadq", "storeq"
931 $asm.puts "mov#{x86Suffix(:quad)} #{x86Operands(:quad, :quad)}"
934 $asm.puts "movzbl #{orderOperands(operands[0].x86Operand(:byte), operands[1].x86Operand(:int))}"
936 $asm.puts "movzx #{orderOperands(operands[0].x86Operand(:byte), operands[1].x86Operand(:int))}"
939 $asm.puts "movsbl #{operands[0].x86Operand(:byte)}, #{operands[1].x86Operand(:int)}"
942 $asm.puts "movzwl #{orderOperands(operands[0].x86Operand(:half), operands[1].x86Operand(:int))}"
944 $asm.puts "movzx #{orderOperands(operands[0].x86Operand(:half), operands[1].x86Operand(:int))}"
947 $asm.puts "movswl #{operands[0].x86Operand(:half)}, #{operands[1].x86Operand(:int)}"
949 $asm.puts "mov#{x86Suffix(:byte)} #{x86Operands(:byte, :byte)}"
953 $asm.puts "fldl #{operands[0].x86Operand(:double)}"
955 $asm.puts "fld #{operands[0].x86Operand(:double)}"
957 $asm.puts "fstp #{operands[1].x87Operand(1)}"
959 $asm.puts "movsd #{x86Operands(:double, :double)}"
963 if (operands[0].x87DefaultStackPosition == 0)
964 $asm.puts "fst #{operands[1].x87Operand(0)}"
966 $asm.puts "fld #{operands[0].x87Operand(0)}"
967 $asm.puts "fstp #{operands[1].x87Operand(1)}"
970 $asm.puts "movsd #{x86Operands(:double, :double)}"
974 if (operands[0].x87DefaultStackPosition == 0)
975 $asm.puts "fst#{x86Suffix(:int)} #{operands[1].x86Operand(:double)}"
977 $asm.puts "fld #{operands[0].x87Operand(0)}"
979 $asm.puts "fstpl #{operands[1].x86Operand(:double)}"
981 $asm.puts "fstp #{operands[1].x86Operand(:double)}"
985 $asm.puts "movsd #{x86Operands(:double, :double)}"
989 handleX87BinOp("fadd", "fadd")
991 $asm.puts "addsd #{x86Operands(:double, :double)}"
995 handleX87BinOp("fmul", "fmul")
997 $asm.puts "mulsd #{x86Operands(:double, :double)}"
1001 handleX87BinOp("fsub", "fsubr")
1003 $asm.puts "subsd #{x86Operands(:double, :double)}"
1007 handleX87BinOp("fdiv", "fdivr")
1009 $asm.puts "divsd #{x86Operands(:double, :double)}"
1013 $asm.puts "fld #{operands[0].x87Operand(0)}"
1015 $asm.puts "fstp #{operands[1].x87Operand(1)}"
1017 $asm.puts "sqrtsd #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:double)}"
1021 sp = RegisterID.new(nil, "sp")
1022 $asm.puts "mov#{x86Suffix(:int)} #{orderOperands(operands[0].x86Operand(:int), offsetRegister(-4, sp.x86Operand(:ptr)))}"
1023 $asm.puts "fild#{x86Suffix(:ptr)} #{getSizeString(:ptr)}#{offsetRegister(-4, sp.x86Operand(:ptr))}"
1024 $asm.puts "fstp #{operands[1].x87Operand(1)}"
1026 $asm.puts "cvtsi2sd #{operands[0].x86Operand(:int)}, #{operands[1].x86Operand(:double)}"
1030 handleX87Compare(:normal)
1032 $asm.puts "ucomisd #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:double)}"
1034 if operands[0] == operands[1]
1035 # This is just a jump ordered, which is a jnp.
1036 $asm.puts "jnp #{operands[2].asmLabel}"
1038 isUnordered = LocalLabel.unique("bdeq")
1039 $asm.puts "jp #{LabelReference.new(codeOrigin, isUnordered).asmLabel}"
1040 $asm.puts "je #{LabelReference.new(codeOrigin, operands[2]).asmLabel}"
1041 isUnordered.lower("X86")
1044 handleX86DoubleBranch("jne", :normal)
1046 handleX86DoubleBranch("ja", :normal)
1048 handleX86DoubleBranch("jae", :normal)
1050 handleX86DoubleBranch("ja", :reverse)
1052 handleX86DoubleBranch("jae", :reverse)
1054 handleX86DoubleBranch("je", :normal)
1057 handleX87Compare(:normal)
1059 $asm.puts "ucomisd #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:double)}"
1061 if operands[0] == operands[1]
1062 # This is just a jump unordered, which is a jp.
1063 $asm.puts "jp #{operands[2].asmLabel}"
1065 isUnordered = LocalLabel.unique("bdnequn")
1066 isEqual = LocalLabel.unique("bdnequn")
1067 $asm.puts "jp #{LabelReference.new(codeOrigin, isUnordered).asmLabel}"
1068 $asm.puts "je #{LabelReference.new(codeOrigin, isEqual).asmLabel}"
1069 isUnordered.lower("X86")
1070 $asm.puts "jmp #{operands[2].asmLabel}"
1071 isEqual.lower("X86")
1074 handleX86DoubleBranch("jb", :reverse)
1076 handleX86DoubleBranch("jbe", :reverse)
1078 handleX86DoubleBranch("jb", :normal)
1080 handleX86DoubleBranch("jbe", :normal)
1082 # FIXME: unused and unimplemented for x87
1084 $asm.puts "cvttsd2si #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:int)}"
1085 $asm.puts "cmpl $0x80000000 #{operands[1].x86Operand(:int)}"
1086 $asm.puts "je #{operands[2].asmLabel}"
1088 # FIXME: unused and unimplemented for x87
1090 $asm.puts "cvttsd2si #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:int)}"
1093 sp = RegisterID.new(nil, "sp")
1094 if (operands[0].x87DefaultStackPosition == 0)
1095 $asm.puts "fistl -4(#{sp.x86Operand(:ptr)})"
1097 $asm.puts "fld #{operands[0].x87Operand(0)}"
1098 $asm.puts "fistp#{x86Suffix(:ptr)} #{getSizeString(:ptr)}#{offsetRegister(-4, sp.x86Operand(:ptr))}"
1100 $asm.puts "mov#{x86Suffix(:int)} #{orderOperands(offsetRegister(-4, sp.x86Operand(:ptr)), operands[1].x86Operand(:int))}"
1101 $asm.puts "test#{x86Suffix(:int)} #{operands[1].x86Operand(:int)}, #{operands[1].x86Operand(:int)}"
1102 $asm.puts "je #{operands[2].asmLabel}"
1103 $asm.puts "fild#{x86Suffix(:int)} #{getSizeString(:int)}#{offsetRegister(-4, sp.x86Operand(:ptr))}"
1104 $asm.puts "fucomip #{@@floatingPointCompareImplicitOperand}#{operands[0].x87Operand(1)}"
1105 $asm.puts "jp #{operands[2].asmLabel}"
1106 $asm.puts "jne #{operands[2].asmLabel}"
1108 $asm.puts "cvttsd2si #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:int)}"
1109 $asm.puts "test#{x86Suffix(:int)} #{operands[1].x86Operand(:int)}, #{operands[1].x86Operand(:int)}"
1110 $asm.puts "je #{operands[2].asmLabel}"
1111 $asm.puts "cvtsi2sd #{operands[1].x86Operand(:int)}, %xmm7"
1112 $asm.puts "ucomisd #{operands[0].x86Operand(:double)}, %xmm7"
1113 $asm.puts "jp #{operands[2].asmLabel}"
1114 $asm.puts "jne #{operands[2].asmLabel}"
1119 $asm.puts "fstp #{operands[0].x87Operand(1)}"
1121 $asm.puts "xorpd #{operands[0].x86Operand(:double)}, #{operands[0].x86Operand(:double)}"
1126 $asm.puts "pop #{op.x86Operand(:ptr)}"
1131 $asm.puts "push #{op.x86Operand(:ptr)}"
1133 when "popCalleeSaves"
1135 $asm.puts "pop %rbx"
1136 $asm.puts "pop %r15"
1137 $asm.puts "pop %r14"
1138 $asm.puts "pop %r13"
1139 $asm.puts "pop %r12"
1141 $asm.puts "pop " + register("ebx")
1142 $asm.puts "pop " + register("edi")
1143 $asm.puts "pop " + register("esi")
1145 when "pushCalleeSaves"
1147 $asm.puts "push %r12"
1148 $asm.puts "push %r13"
1149 $asm.puts "push %r14"
1150 $asm.puts "push %r15"
1151 $asm.puts "push %rbx"
1153 $asm.puts "push " + register("esi")
1154 $asm.puts "push " + register("edi")
1155 $asm.puts "push " + register("ebx")
1160 $asm.puts "movslq #{operands[0].x86Operand(:int)}, #{operands[1].x86Operand(:quad)}"
1162 $asm.puts "mov#{x86Suffix(:int)} #{orderOperands(operands[0].x86Operand(:int), operands[1].x86Operand(:int))}"
1166 handleX86IntBranch("je", :int)
1168 handleX86IntBranch("je", :ptr)
1170 handleX86IntBranch("je", :quad)
1172 handleX86IntBranch("jne", :int)
1174 handleX86IntBranch("jne", :ptr)
1176 handleX86IntBranch("jne", :quad)
1178 handleX86IntBranch("ja", :int)
1180 handleX86IntBranch("ja", :ptr)
1182 handleX86IntBranch("ja", :quad)
1184 handleX86IntBranch("jae", :int)
1186 handleX86IntBranch("jae", :ptr)
1188 handleX86IntBranch("jae", :quad)
1190 handleX86IntBranch("jb", :int)
1192 handleX86IntBranch("jb", :ptr)
1194 handleX86IntBranch("jb", :quad)
1196 handleX86IntBranch("jbe", :int)
1198 handleX86IntBranch("jbe", :ptr)
1200 handleX86IntBranch("jbe", :quad)
1202 handleX86IntBranch("jg", :int)
1204 handleX86IntBranch("jg", :ptr)
1206 handleX86IntBranch("jg", :quad)
1208 handleX86IntBranch("jge", :int)
1210 handleX86IntBranch("jge", :ptr)
1212 handleX86IntBranch("jge", :quad)
1214 handleX86IntBranch("jl", :int)
1216 handleX86IntBranch("jl", :ptr)
1218 handleX86IntBranch("jl", :quad)
1220 handleX86IntBranch("jle", :int)
1222 handleX86IntBranch("jle", :ptr)
1224 handleX86IntBranch("jle", :quad)
1226 handleX86IntBranch("je", :byte)
1228 handleX86IntBranch("jne", :byte)
1230 handleX86IntBranch("ja", :byte)
1232 handleX86IntBranch("jae", :byte)
1234 handleX86IntBranch("jb", :byte)
1236 handleX86IntBranch("jbe", :byte)
1238 handleX86IntBranch("jg", :byte)
1240 handleX86IntBranch("jge", :byte)
1242 handleX86IntBranch("jl", :byte)
1244 handleX86IntBranch("jlteq", :byte)
1246 handleX86BranchTest("js", :int)
1248 handleX86BranchTest("js", :ptr)
1250 handleX86BranchTest("js", :quad)
1252 handleX86BranchTest("jz", :int)
1254 handleX86BranchTest("jz", :ptr)
1256 handleX86BranchTest("jz", :quad)
1258 handleX86BranchTest("jnz", :int)
1260 handleX86BranchTest("jnz", :ptr)
1262 handleX86BranchTest("jnz", :quad)
1264 handleX86BranchTest("js", :byte)
1266 handleX86BranchTest("jz", :byte)
1268 handleX86BranchTest("jnz", :byte)
1270 $asm.puts "jmp #{operands[0].x86CallOperand(:ptr)}"
1272 handleX86OpBranch("add#{x86Suffix(:int)}", "jo", :int)
1274 handleX86OpBranch("add#{x86Suffix(:ptr)}", "jo", :ptr)
1276 handleX86OpBranch("add#{x86Suffix(:quad)}", "jo", :quad)
1278 handleX86OpBranch("add#{x86Suffix(:int)}", "js", :int)
1280 handleX86OpBranch("add#{x86Suffix(:ptr)}", "js", :ptr)
1282 handleX86OpBranch("add#{x86Suffix(:quad)}", "js", :quad)
1284 handleX86OpBranch("add#{x86Suffix(:int)}", "jz", :int)
1286 handleX86OpBranch("add#{x86Suffix(:ptr)}", "jz", :ptr)
1288 handleX86OpBranch("add#{x86Suffix(:quad)}", "jz", :quad)
1290 handleX86OpBranch("add#{x86Suffix(:int)}", "jnz", :int)
1292 handleX86OpBranch("add#{x86Suffix(:ptr)}", "jnz", :ptr)
1294 handleX86OpBranch("add#{x86Suffix(:quad)}", "jnz", :quad)
1296 handleX86SubBranch("jo", :int)
1298 handleX86SubBranch("js", :int)
1300 handleX86SubBranch("jz", :int)
1302 handleX86SubBranch("jnz", :int)
1304 handleX86OpBranch("imul#{x86Suffix(:int)}", "jo", :int)
1306 handleX86OpBranch("imul#{x86Suffix(:int)}", "js", :int)
1308 handleX86OpBranch("imul#{x86Suffix(:int)}", "jz", :int)
1310 handleX86OpBranch("imul#{x86Suffix(:int)}", "jnz", :int)
1312 handleX86OpBranch("orl", "jo", :int)
1314 handleX86OpBranch("orl", "js", :int)
1316 handleX86OpBranch("orl", "jz", :int)
1318 handleX86OpBranch("orl", "jnz", :int)
1320 $asm.puts "int #{const(3)}"
1325 $asm.puts "ffree #{register("st")}(#{offset})"
1328 op = operands[0].x86CallOperand(:ptr)
1329 if isMSVC && (operands[0].is_a? LabelReference)
1330 writeSymbolToFile(op)
1332 $asm.puts "call #{op}"
1336 handleX86IntCompareSet("sete", :int)
1338 handleX86IntCompareSet("sete", :byte)
1340 handleX86IntCompareSet("sete", :ptr)
1342 handleX86IntCompareSet("sete", :quad)
1344 handleX86IntCompareSet("setne", :int)
1346 handleX86IntCompareSet("setne", :byte)
1348 handleX86IntCompareSet("setne", :ptr)
1350 handleX86IntCompareSet("setne", :quad)
1352 handleX86IntCompareSet("seta", :int)
1354 handleX86IntCompareSet("seta", :byte)
1356 handleX86IntCompareSet("seta", :ptr)
1358 handleX86IntCompareSet("seta", :quad)
1360 handleX86IntCompareSet("setae", :int)
1362 handleX86IntCompareSet("setae", :byte)
1364 handleX86IntCompareSet("setae", :ptr)
1366 handleX86IntCompareSet("setae", :quad)
1368 handleX86IntCompareSet("setb", :int)
1370 handleX86IntCompareSet("setb", :byte)
1372 handleX86IntCompareSet("setb", :ptr)
1374 handleX86IntCompareSet("setb", :quad)
1376 handleX86IntCompareSet("setbe", :int)
1378 handleX86IntCompareSet("setbe", :byte)
1380 handleX86IntCompareSet("setbe", :ptr)
1382 handleX86IntCompareSet("setbe", :quad)
1384 handleX86IntCompareSet("setg", :int)
1386 handleX86IntCompareSet("setg", :byte)
1388 handleX86IntCompareSet("setg", :ptr)
1390 handleX86IntCompareSet("setg", :quad)
1392 handleX86IntCompareSet("setge", :int)
1394 handleX86IntCompareSet("setge", :byte)
1396 handleX86IntCompareSet("setge", :ptr)
1398 handleX86IntCompareSet("setge", :quad)
1400 handleX86IntCompareSet("setl", :int)
1402 handleX86IntCompareSet("setl", :byte)
1404 handleX86IntCompareSet("setl", :ptr)
1406 handleX86IntCompareSet("setl", :quad)
1408 handleX86IntCompareSet("setle", :int)
1410 handleX86IntCompareSet("setle", :byte)
1412 handleX86IntCompareSet("setle", :ptr)
1414 handleX86IntCompareSet("setle", :quad)
1416 handleX86SetTest("sets", :int)
1418 handleX86SetTest("setz", :int)
1420 handleX86SetTest("setnz", :int)
1422 handleX86SetTest("sets", :ptr)
1424 handleX86SetTest("setz", :ptr)
1426 handleX86SetTest("setnz", :ptr)
1428 handleX86SetTest("sets", :quad)
1430 handleX86SetTest("setz", :quad)
1432 handleX86SetTest("setnz", :quad)
1434 handleX86SetTest("sets", :byte)
1436 handleX86SetTest("setz", :byte)
1438 handleX86SetTest("setnz", :byte)
1446 $asm.puts "idivl #{operands[0].x86Operand(:int)}"
1449 sp = RegisterID.new(nil, "sp")
1450 $asm.puts "mov#{x86Suffix(:int)} #{orderOperands(operands[0].x86Operand(:int), offsetRegister(-8, sp.x86Operand(:ptr)))}"
1451 $asm.puts "mov#{x86Suffix(:int)} #{orderOperands(operands[1].x86Operand(:int), offsetRegister(-4, sp.x86Operand(:ptr)))}"
1452 $asm.puts "fld#{x86Suffix(:ptr)} #{getSizeString(:double)}#{offsetRegister(-8, sp.x86Operand(:ptr))}"
1453 $asm.puts "fstp #{operands[2].x87Operand(1)}"
1455 $asm.puts "movd #{operands[0].x86Operand(:int)}, #{operands[2].x86Operand(:double)}"
1456 $asm.puts "movd #{operands[1].x86Operand(:int)}, %xmm7"
1457 $asm.puts "psllq $32, %xmm7"
1458 $asm.puts "por %xmm7, #{operands[2].x86Operand(:double)}"
1462 sp = RegisterID.new(nil, "sp")
1463 if (operands[0].x87DefaultStackPosition == 0)
1464 $asm.puts "fst#{x86Suffix(:ptr)} #{getSizeString(:double)}#{offsetRegister(-8, sp.x86Operand(:ptr))}"
1466 $asm.puts "fld #{operands[0].x87Operand(0)}"
1467 $asm.puts "fstpl -8(#{sp.x86Operand(:ptr)})"
1469 $asm.puts "mov#{x86Suffix(:int)} #{orderOperands(offsetRegister(-8, sp.x86Operand(:ptr)), operands[1].x86Operand(:int))}"
1470 $asm.puts "mov#{x86Suffix(:int)} #{orderOperands(offsetRegister(-4, sp.x86Operand(:ptr)), operands[2].x86Operand(:int))}"
1472 $asm.puts "movd #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:int)}"
1473 $asm.puts "movsd #{operands[0].x86Operand(:double)}, %xmm7"
1474 $asm.puts "psrlq $32, %xmm7"
1475 $asm.puts "movd %xmm7, #{operands[2].x86Operand(:int)}"
1479 sp = RegisterID.new(nil, "sp")
1480 $asm.puts "movq #{operands[0].x86Operand(:quad)}, -8(#{sp.x86Operand(:ptr)})"
1481 $asm.puts "fldl -8(#{sp.x86Operand(:ptr)})"
1482 $asm.puts "fstp #{operands[1].x87Operand(1)}"
1484 $asm.puts "movq #{operands[0].x86Operand(:quad)}, #{operands[1].x86Operand(:double)}"
1488 sp = RegisterID.new(nil, "sp")
1489 if (operands[0].x87DefaultStackPosition == 0)
1490 $asm.puts "fst#{x86Suffix(:int)} #{getSizeString(:int)}#{offsetRegister(-8, sp.x86Operand(:ptr))}"
1492 $asm.puts "fld #{operands[0].x87Operand(0)}"
1493 $asm.puts "fstpl -8(#{sp.x86Operand(:ptr)})"
1495 $asm.puts "movq -8(#{sp.x86Operand(:ptr)}), #{operands[1].x86Operand(:quad)}"
1497 $asm.puts "movq #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:quad)}"
1500 $asm.puts "jo #{operands[0].asmLabel}"
1502 $asm.puts "js #{operands[0].asmLabel}"
1504 $asm.puts "jz #{operands[0].asmLabel}"
1506 $asm.puts "jnz #{operands[0].asmLabel}"
1508 $asm.puts "lea#{x86Suffix(:int)} #{orderOperands(operands[0].x86AddressOperand(:int), operands[1].x86Operand(:int))}"
1510 $asm.puts "lea#{x86Suffix(:ptr)} #{orderOperands(operands[0].x86AddressOperand(:ptr), operands[1].x86Operand(:ptr))}"