1 # Copyright (C) 2012, 2014 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.
38 raise "bad value for $activeBackend: #{$activeBackend}"
53 raise "bad value for $activeBackend: #{$activeBackend}"
58 ENV['OS'] == 'Windows_NT'
74 isIntelSyntax
? name
: "%" + name
77 def offsetRegister(off
, register
)
78 isIntelSyntax
? "[#{off} + #{register}]" : "#{off}(#{register})"
82 isIntelSyntax ? "" : "*"
85 def orderOperands(opA, opB)
86 isIntelSyntax ? "#{opB}, #{opA}" : "#{opA}, #{opB}"
90 isIntelSyntax ? "#{c}" : "$
#{c}"
93 def getSizeString(kind)
107 size
= isX64
? "qword" : "dword"
113 raise "Invalid kind #{kind}"
116 return size +
" " +
"ptr" +
" ";
119 class SpecialRegister
< NoChildren
121 raise unless @name =~
/^r/
125 register(@name +
"w")
127 register(@name +
"d")
136 def x86CallOperand(kind
)
137 # Call operands are not allowed to be partial registers.
138 "#{callPrefix}#{x86Operand(:quad)}"
142 X64_SCRATCH_REGISTER
= SpecialRegister
.new("r11")
145 def supports8BitOnX86
147 when "t0", "a0", "r0", "t1", "a1", "r1", "t2", "t3", "t4", "t5"
149 when "cfr", "ttnr", "tmr"
160 when "t0", "a0", "r0"
169 isX64
? register("rax") : register("eax")
171 isX64
? register("rax") : raise
173 raise "Invalid kind #{kind} for name #{name}"
175 when "t1", "a1", "r1"
184 isX64
? register("rdx") : register("edx")
186 isX64
? register("rdx") : raise
199 isX64
? register("rcx") : register("ecx")
201 isX64
? register("rcx") : raise
214 isX64
? register("rbx") : register("ebx")
216 isX64
? register("rbx") : raise
229 isX64
? register("rdi") : register("edi")
231 isX64
? register("rdi") : raise
270 isX64
? register("rsp") : register("esp")
272 isX64
? register("rsp") : raise
285 isX64
? register("rsi") : register("esi")
287 isX64
? register("rsi") : raise
290 raise "Cannot use #{name} in 32-bit X86 at #{codeOriginString}" unless isX64
302 raise "Cannot use #{name} in 32-bit X86 at #{codeOriginString}" unless isX64
314 raise "Cannot use #{name} in 32-bit X86 at #{codeOriginString}" unless isX64
326 raise "Cannot use #{name} in 32-bit X86 at #{codeOriginString}" unless isX64
338 raise "Bad register #{name} for X86 at #{codeOriginString}"
341 def x86CallOperand(kind
)
342 isX64
? "#{callPrefix}#{x86Operand(:quad)}" : "#{callPrefix}#{x86Operand(:ptr)}"
348 raise unless kind
== :double
351 when "ft0", "fa0", "fr"
364 raise "Bad register #{name} for X86 at #{codeOriginString}"
367 def x87DefaultStackPosition
373 when "ft2", "ft3", "ft4", "ft5"
374 raise "Unimplemented register #{name} for X86 at #{codeOriginString}"
376 raise "Bad register #{name} for X86 at #{codeOriginString}"
379 def x87Operand(offset
)
381 raise unless offset
== 0 or offset
== 1
382 "#{register("st")}(#{x87DefaultStackPosition + offset})"
384 def x86CallOperand(kind
)
385 "#{callPrefix}#{x86Operand(kind)}"
390 def validX86Immediate
?
392 value
>= -0x80000000 and value
<= 0x7fffffff
400 def x86CallOperand(kind
)
406 def supports8BitOnX86
410 def x86AddressOperand(addressKind
)
411 "#{offsetRegister(offset.value, base.x86Operand(addressKind))}"
414 "#{getSizeString(kind)}#{x86AddressOperand(:ptr)}"
416 def x86CallOperand(kind
)
417 "#{callPrefix}#{x86Operand(kind)}"
422 def supports8BitOnX86
426 def x86AddressOperand(addressKind
)
428 "#{offset.value}(#{base.x86Operand(addressKind)}, #{index.x86Operand(addressKind)}, #{scale})"
430 "#{getSizeString(addressKind)}[#{offset.value} + #{base.x86Operand(addressKind)} +
#{index.x86Operand(addressKind)} * #{scale}]"
436 x86AddressOperand(:ptr)
438 "#{getSizeString(kind)}[#{offset.value} + #{base.x86Operand(:ptr)} +
#{index.x86Operand(:ptr)} * #{scale}]"
442 def x86CallOperand(kind)
443 "#{callPrefix}#{x86Operand(kind)}"
447 class AbsoluteAddress
448 def supports8BitOnX86
452 def x86AddressOperand(addressKind)
460 def x86CallOperand(kind)
461 "#{callPrefix}#{address.value}"
466 def x86CallOperand(kind)
471 class LocalLabelReference
475 def x86CallOperand(kind)
481 def getModifiedListX86_64
487 if node.is_a? Instruction
488 unless node.opcode == "move
"
490 newOperands = node.operands.map {
492 if operand.immediate? and not operand.validX86Immediate?
494 raise "Attempt to use scratch register twice at
#{operand.codeOriginString}"
496 newList << Instruction.new(operand.codeOrigin, "move
", [operand, X64_SCRATCH_REGISTER])
503 newNode = Instruction.new(node.codeOrigin, node.opcode, newOperands, node.annotation)
506 unless node.is_a? Label or
507 node.is_a? LocalLabel or
509 raise "Unexpected
#{node.inspect} at
#{node.codeOrigin}"
519 def getModifiedListX86_64_WIN
520 getModifiedListX86_64
525 @@floatingPointCompareImplicitOperand = isIntelSyntax ? "st(0), " : ""
527 def x86Operands(*kinds)
528 raise unless kinds.size == operands.size
532 i = isIntelSyntax ? (kinds.size - idx - 1) : idx
533 result << operands[i].x86Operand(kinds[i])
555 not useX87 ? "sd
" : raise
580 def handleX86OpWithNumOperands(opcode, kind, numOperands)
582 if operands[0] == operands[2]
583 $asm.puts "#{opcode} #{orderOperands(operands[1].x86Operand(kind), operands[2].x86Operand(kind))}"
584 elsif operands[1] == operands[2]
585 $asm.puts "#{opcode} #{orderOperands(operands[0].x86Operand(kind), operands[2].x86Operand(kind))}"
587 $asm.puts "mov
#{x86Suffix(kind)} #{orderOperands(operands[0].x86Operand(kind), operands[2].x86Operand(kind))}"
588 $asm.puts "#{opcode} #{orderOperands(operands[1].x86Operand(kind), operands[2].x86Operand(kind))}"
591 $asm.puts "#{opcode} #{orderOperands(operands[0].x86Operand(kind), operands[1].x86Operand(kind))}"
595 def handleX86Op(opcode, kind)
596 handleX86OpWithNumOperands(opcode, kind, operands.size)
599 def handleX86Shift(opcode, kind)
600 if operands[0].is_a? Immediate or operands[0] == RegisterID.forName(nil, "t2
")
601 $asm.puts "#{opcode} #{orderOperands(operands[0].x86Operand(:byte), operands[1].x86Operand(kind))}"
603 cx = RegisterID.forName(nil, "t2
")
604 $asm.puts "xchg
#{x86Suffix(:ptr)} #{operands[0].x86Operand(:ptr)}, #{cx.x86Operand(:ptr)}"
605 $asm.puts "#{opcode} #{orderOperands(register("cl"), operands[1].x86Operand(kind))}"
606 $asm.puts "xchg
#{x86Suffix(:ptr)} #{operands[0].x86Operand(:ptr)}, #{cx.x86Operand(:ptr)}"
610 def handleX86DoubleBranch(branchOpcode, mode)
612 handleX87Compare(mode)
616 $asm.puts "ucomisd
#{orderOperands(operands[1].x86Operand(:double), operands[0].x86Operand(:double))}"
618 $asm.puts "ucomisd
#{orderOperands(operands[0].x86Operand(:double), operands[1].x86Operand(:double))}"
623 $asm.puts "#{branchOpcode} #{operands[2].asmLabel}"
626 def handleX86IntCompare(opcodeSuffix, kind)
627 if operands[0].is_a? Immediate and operands[0].value == 0 and operands[1].is_a? RegisterID and (opcodeSuffix == "e
" or opcodeSuffix == "ne
")
628 $asm.puts "test
#{x86Suffix(kind)} #{orderOperands(operands[1].x86Operand(kind), operands[1].x86Operand(kind))}"
629 elsif operands[1].is_a? Immediate and operands[1].value == 0 and operands[0].is_a? RegisterID and (opcodeSuffix == "e
" or opcodeSuffix == "ne
")
630 $asm.puts "test
#{x86Suffix(kind)} #{orderOperands(operands[0].x86Operand(kind), operands[0].x86Operand(kind))}"
632 $asm.puts "cmp
#{x86Suffix(kind)} #{orderOperands(operands[1].x86Operand(kind), operands[0].x86Operand(kind))}"
636 def handleX86IntBranch(branchOpcode, kind)
637 handleX86IntCompare(branchOpcode[1..-1], kind)
638 $asm.puts "#{branchOpcode} #{operands[2].asmLabel}"
641 def handleX86Set(setOpcode, operand)
642 if operand.supports8BitOnX86
643 $asm.puts "#{setOpcode} #{operand.x86Operand(:byte)}"
645 $asm.puts
"movzbl #{orderOperands(operand.x86Operand(:byte), operand.x86Operand(:int))}"
647 $asm.puts
"movzx #{orderOperands(operand.x86Operand(:byte), operand.x86Operand(:int))}"
650 ax
= RegisterID
.new(nil, "t0")
651 $asm.puts
"xchg#{x86Suffix(:ptr)} #{operand.x86Operand(:ptr)}, #{ax.x86Operand(:ptr)}"
652 $asm.puts
"#{setOpcode} %al"
653 $asm.puts
"movzbl %al, %eax"
654 $asm.puts
"xchg#{x86Suffix(:ptr)} #{operand.x86Operand(:ptr)}, #{ax.x86Operand(:ptr)}"
658 def handleX86IntCompareSet(setOpcode
, kind
)
659 handleX86IntCompare(setOpcode
[3..-1], kind
)
660 handleX86Set(setOpcode
, operands
[2])
663 def handleX86Test(kind
)
667 mask
= Immediate
.new(codeOrigin
, -1)
671 raise "Expected 2 or 3 operands, but got #{operands.size} at #{codeOriginString}"
674 if mask
.is_a
? Immediate
and mask
.value
== -1
675 if value
.is_a
? RegisterID
676 $asm.puts
"test#{x86Suffix(kind)} #{value.x86Operand(kind)}, #{value.x86Operand(kind)}"
678 $asm.puts
"cmp#{x86Suffix(kind)} #{orderOperands(const(0), value.x86Operand(kind))}"
681 $asm.puts
"test#{x86Suffix(kind)} #{orderOperands(mask.x86Operand(kind), value.x86Operand(kind))}"
685 def handleX86BranchTest(branchOpcode
, kind
)
687 $asm.puts
"#{branchOpcode} #{operands.last.asmLabel}"
690 def handleX86SetTest(setOpcode
, kind
)
692 handleX86Set(setOpcode
, operands
.last
)
695 def handleX86OpBranch(opcode
, branchOpcode
, kind
)
696 handleX86OpWithNumOperands(opcode
, kind
, operands
.size
- 1)
699 jumpTarget
= operands
[3]
701 jumpTarget
= operands
[2]
705 $asm.puts
"#{branchOpcode} #{jumpTarget.asmLabel}"
708 def handleX86SubBranch(branchOpcode
, kind
)
709 if operands
.size
== 4 and operands
[1] == operands
[2]
710 $asm.puts
"neg#{x86Suffix(kind)} #{operands[2].x86Operand(kind)}"
711 $asm.puts
"add#{x86Suffix(kind)} #{orderOperands(operands[0].x86Operand(kind), operands[2].x86Operand(kind))}"
713 handleX86OpWithNumOperands("sub#{x86Suffix(kind)}", kind
, operands
.size
- 1)
717 jumpTarget
= operands
[3]
719 jumpTarget
= operands
[2]
723 $asm.puts
"#{branchOpcode} #{jumpTarget.asmLabel}"
726 def handleX86Add(kind
)
727 if operands
.size
== 3 and operands
[1] == operands
[2]
728 unless Immediate
.new(nil, 0) == operands
[0]
729 $asm.puts
"add#{x86Suffix(kind)} #{orderOperands(operands[0].x86Operand(kind), operands[2].x86Operand(kind))}"
731 elsif operands
.size
== 3 and operands
[0].is_a
? Immediate
732 raise unless operands
[1].is_a
? RegisterID
733 raise unless operands
[2].is_a
? RegisterID
734 if operands
[0].value
== 0
735 unless operands
[1] == operands
[2]
736 $asm.puts
"mov#{x86Suffix(kind)} #{orderOperands(operands[1].x86Operand(kind), operands[2].x86Operand(kind))}"
739 $asm.puts
"lea#{x86Suffix(kind)} #{orderOperands(offsetRegister(operands[0].value, operands[1].x86Operand(kind)), operands[2].x86Operand(kind))}"
741 elsif operands
.size
== 3 and operands
[0].is_a
? RegisterID
742 raise unless operands
[1].is_a
? RegisterID
743 raise unless operands
[2].is_a
? RegisterID
744 if operands
[0] == operands
[2]
745 $asm.puts
"add#{x86Suffix(kind)} #{orderOperands(operands[1].x86Operand(kind), operands[2].x86Operand(kind))}"
748 $asm.puts
"lea#{x86Suffix(kind)} (#{operands[0].x86Operand(kind)}, #{operands[1].x86Operand(kind)}), #{operands[2].x86Operand(kind)}"
750 $asm.puts
"lea#{x86Suffix(kind)} #{operands[2].x86Operand(kind)}, [#{operands[0].x86Operand(kind)} + #{operands[1].x86Operand(kind)}]"
754 unless Immediate.new(nil, 0) == operands[0]
755 $asm.puts "add
#{x86Suffix(kind)} #{x86Operands(kind, kind)}"
760 def handleX86Sub(kind)
761 if operands.size == 3 and operands[1] == operands[2]
762 $asm.puts "neg
#{x86Suffix(kind)} #{operands[2].x86Operand(kind)}"
763 $asm.puts "add
#{x86Suffix(kind)} #{orderOperands(operands[0].x86Operand(kind), operands[2].x86Operand(kind))}"
765 handleX86Op("sub
#{x86Suffix(kind)}", kind)
769 def handleX86Mul(kind)
770 if operands.size == 3 and operands[0].is_a? Immediate
771 $asm.puts "imul
#{x86Suffix(kind)} #{x86Operands(kind, kind, kind)}"
773 # FIXME: could do some peephole in case the left operand is immediate and it's
775 handleX86Op("imul
#{x86Suffix(kind)}", kind)
780 sp = RegisterID.new(nil, "sp
")
781 opA = offsetRegister(operands[0].value * x86Bytes(:ptr), sp.x86Operand(:ptr))
782 opB = operands[1].x86Operand(:ptr)
783 $asm.puts "mov
#{x86Suffix(:ptr)} #{orderOperands(opA, opB)}"
787 sp = RegisterID.new(nil, "sp
")
788 opA = operands[0].x86Operand(:ptr)
789 opB = offsetRegister(operands[1].value * x86Bytes(:ptr), sp.x86Operand(:ptr))
790 $asm.puts "mov
#{x86Suffix(:ptr)} #{orderOperands(opA, opB)}"
794 if Immediate.new(nil, 0) == operands[0] and operands[1].is_a? RegisterID
796 $asm.puts "xor
#{x86Suffix(:quad)} #{operands[1].x86Operand(:quad)}, #{operands[1].x86Operand(:quad)}"
798 $asm.puts "xor
#{x86Suffix(:ptr)} #{operands[1].x86Operand(:ptr)}, #{operands[1].x86Operand(:ptr)}"
800 elsif operands[0] != operands
[1]
802 $asm.puts
"mov#{x86Suffix(:quad)} #{x86Operands(:quad, :quad)}"
804 $asm.puts
"mov#{x86Suffix(:ptr)} #{x86Operands(:ptr, :ptr)}"
809 def handleX87Compare(mode
)
812 if (operands
[0].x87DefaultStackPosition
== 0)
813 $asm.puts
"fucomi #{@@floatingPointCompareImplicitOperand}#{operands[1].x87Operand(0)}"
815 $asm.puts
"fld #{operands[0].x87Operand(0)}"
816 $asm.puts
"fucomip #{@@floatingPointCompareImplicitOperand}#{operands[1].x87Operand(1)}"
819 if (operands
[1].x87DefaultStackPosition
== 0)
820 $asm.puts
"fucomi #{@@floatingPointCompareImplicitOperand}#{operands[0].x87Operand(0)}"
822 $asm.puts
"fld #{operands[1].x87Operand(0)}"
823 $asm.puts
"fucomip #{@@floatingPointCompareImplicitOperand}#{operands[0].x87Operand(1)}"
830 def handleX87BinOp(opcode
, opcodereverse
)
831 if (operands
[1].x87DefaultStackPosition
== 0)
832 $asm.puts
"#{opcode} #{orderOperands(operands[0].x87Operand(0), register("st"))}"
833 elsif (operands
[0].x87DefaultStackPosition
== 0)
835 $asm.puts
"#{opcodereverse} #{register("st")}, #{operands[1].x87Operand(0)}"
837 $asm.puts
"#{opcode} #{operands[1].x87Operand(0)}, #{register("st")}"
840 $asm.puts
"fld #{operands[0].x87Operand(0)}"
841 $asm.puts
"#{opcodereverse}p #{orderOperands(register("st"), operands[1].x87Operand(1))}"
846 raise unless $activeBackend == "X86"
851 raise unless $activeBackend == "X86_WIN"
856 raise unless $activeBackend == "X86_64"
861 raise unless $activeBackend == "X86_64_WIN"
866 $asm.codeOrigin codeOriginString
if $enableCodeOriginComments
867 $asm.annotation annotation
if $enableInstrAnnotations
877 handleX86Op("and#{x86Suffix(:int)}", :int)
879 handleX86Op("and#{x86Suffix(:ptr)}", :ptr)
881 handleX86Op("and#{x86Suffix(:quad)}", :quad)
883 handleX86Shift("sal#{x86Suffix(:int)}", :int)
885 handleX86Shift("sal#{x86Suffix(:ptr)}", :ptr)
887 handleX86Shift("sal#{x86Suffix(:quad)}", :quad)
895 $asm.puts
"neg#{x86Suffix(:int)} #{x86Operands(:int)}"
897 $asm.puts
"neg#{x86Suffix(:ptr)} #{x86Operands(:ptr)}"
899 $asm.puts
"neg#{x86Suffix(:quad)} #{x86Operands(:quad)}"
901 $asm.puts
"not#{x86Suffix(:int)} #{x86Operands(:int)}"
903 handleX86Op("or#{x86Suffix(:int)}", :int)
905 handleX86Op("or#{x86Suffix(:ptr)}", :ptr)
907 handleX86Op("or#{x86Suffix(:quad)}", :quad)
909 handleX86Shift("sar#{x86Suffix(:int)}", :int)
911 handleX86Shift("sar#{x86Suffix(:ptr)}", :ptr)
913 handleX86Shift("sar#{x86Suffix(:quad)}", :quad)
915 handleX86Shift("shr#{x86Suffix(:int)}", :int)
917 handleX86Shift("shr#{x86Suffix(:ptr)}", :ptr)
919 handleX86Shift("shr#{x86Suffix(:quad)}", :quad)
927 handleX86Op("xor#{x86Suffix(:int)}", :int)
929 handleX86Op("xor#{x86Suffix(:ptr)}", :ptr)
931 handleX86Op("xor#{x86Suffix(:quad)}", :quad)
932 when "loadi", "storei"
933 $asm.puts
"mov#{x86Suffix(:int)} #{x86Operands(:int, :int)}"
937 $asm.puts
"movslq #{x86Operands(:int, :quad)}"
939 $asm.puts
"movsxd #{x86Operands(:int, :quad)}"
942 $asm.puts
"mov#{x86Suffix(:int)} #{x86Operands(:int, :int)}"
944 when "loadp", "storep"
945 $asm.puts
"mov#{x86Suffix(:ptr)} #{x86Operands(:ptr, :ptr)}"
946 when "loadq", "storeq"
947 $asm.puts
"mov#{x86Suffix(:quad)} #{x86Operands(:quad, :quad)}"
950 $asm.puts
"movzbl #{orderOperands(operands[0].x86Operand(:byte), operands[1].x86Operand(:int))}"
952 $asm.puts
"movzx #{orderOperands(operands[0].x86Operand(:byte), operands[1].x86Operand(:int))}"
955 $asm.puts
"movsbl #{operands[0].x86Operand(:byte)}, #{operands[1].x86Operand(:int)}"
958 $asm.puts
"movzwl #{orderOperands(operands[0].x86Operand(:half), operands[1].x86Operand(:int))}"
960 $asm.puts
"movzx #{orderOperands(operands[0].x86Operand(:half), operands[1].x86Operand(:int))}"
963 $asm.puts
"movswl #{operands[0].x86Operand(:half)}, #{operands[1].x86Operand(:int)}"
965 $asm.puts
"mov#{x86Suffix(:byte)} #{x86Operands(:byte, :byte)}"
969 $asm.puts
"fldl #{operands[0].x86Operand(:double)}"
971 $asm.puts
"fld #{operands[0].x86Operand(:double)}"
973 $asm.puts
"fstp #{operands[1].x87Operand(1)}"
975 $asm.puts
"movsd #{x86Operands(:double, :double)}"
979 if (operands
[0].x87DefaultStackPosition
== 0)
980 $asm.puts
"fst #{operands[1].x87Operand(0)}"
982 $asm.puts
"fld #{operands[0].x87Operand(0)}"
983 $asm.puts
"fstp #{operands[1].x87Operand(1)}"
986 $asm.puts
"movsd #{x86Operands(:double, :double)}"
990 if (operands
[0].x87DefaultStackPosition
== 0)
991 $asm.puts
"fst#{x86Suffix(:int)} #{operands[1].x86Operand(:double)}"
993 $asm.puts
"fld #{operands[0].x87Operand(0)}"
995 $asm.puts
"fstpl #{operands[1].x86Operand(:double)}"
997 $asm.puts
"fstp #{operands[1].x86Operand(:double)}"
1001 $asm.puts
"movsd #{x86Operands(:double, :double)}"
1005 handleX87BinOp("fadd", "fadd")
1007 $asm.puts
"addsd #{x86Operands(:double, :double)}"
1011 handleX87BinOp("fmul", "fmul")
1013 $asm.puts
"mulsd #{x86Operands(:double, :double)}"
1017 handleX87BinOp("fsub", "fsubr")
1019 $asm.puts
"subsd #{x86Operands(:double, :double)}"
1023 handleX87BinOp("fdiv", "fdivr")
1025 $asm.puts
"divsd #{x86Operands(:double, :double)}"
1029 $asm.puts
"fld #{operands[0].x87Operand(0)}"
1031 $asm.puts
"fstp #{operands[1].x87Operand(1)}"
1033 $asm.puts
"sqrtsd #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:double)}"
1037 sp
= RegisterID
.new(nil, "sp")
1038 $asm.puts
"mov#{x86Suffix(:int)} #{orderOperands(operands[0].x86Operand(:int), offsetRegister(-4, sp.x86Operand(:ptr)))}"
1039 $asm.puts
"fild#{x86Suffix(:ptr)} #{getSizeString(:ptr)}#{offsetRegister(-4, sp.x86Operand(:ptr))}"
1040 $asm.puts
"fstp #{operands[1].x87Operand(1)}"
1042 $asm.puts
"cvtsi2sd #{orderOperands(operands[0].x86Operand(:int), operands[1].x86Operand(:double))}"
1046 handleX87Compare(:normal)
1048 $asm.puts
"ucomisd #{orderOperands(operands[0].x86Operand(:double), operands[1].x86Operand(:double))}"
1050 if operands
[0] == operands
[1]
1051 # This is just a jump ordered, which is a jnp.
1052 $asm.puts
"jnp #{operands[2].asmLabel}"
1054 isUnordered
= LocalLabel
.unique("bdeq")
1055 $asm.puts
"jp #{LabelReference.new(codeOrigin, isUnordered).asmLabel}"
1056 $asm.puts
"je #{LabelReference.new(codeOrigin, operands[2]).asmLabel}"
1057 isUnordered
.lower("X86")
1060 handleX86DoubleBranch("jne", :normal)
1062 handleX86DoubleBranch("ja", :normal)
1064 handleX86DoubleBranch("jae", :normal)
1066 handleX86DoubleBranch("ja", :reverse)
1068 handleX86DoubleBranch("jae", :reverse)
1070 handleX86DoubleBranch("je", :normal)
1073 handleX87Compare(:normal)
1075 $asm.puts
"ucomisd #{orderOperands(operands[0].x86Operand(:double), operands[1].x86Operand(:double))}"
1077 if operands
[0] == operands
[1]
1078 # This is just a jump unordered, which is a jp.
1079 $asm.puts
"jp #{operands[2].asmLabel}"
1081 isUnordered
= LocalLabel
.unique("bdnequn")
1082 isEqual
= LocalLabel
.unique("bdnequn")
1083 $asm.puts
"jp #{LabelReference.new(codeOrigin, isUnordered).asmLabel}"
1084 $asm.puts
"je #{LabelReference.new(codeOrigin, isEqual).asmLabel}"
1085 isUnordered
.lower("X86")
1086 $asm.puts
"jmp #{operands[2].asmLabel}"
1087 isEqual
.lower("X86")
1090 handleX86DoubleBranch("jb", :reverse)
1092 handleX86DoubleBranch("jbe", :reverse)
1094 handleX86DoubleBranch("jb", :normal)
1096 handleX86DoubleBranch("jbe", :normal)
1098 # FIXME: unused and unimplemented for x87
1100 $asm.puts
"cvttsd2si #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:int)}"
1101 $asm.puts
"cmpl $0x80000000 #{operands[1].x86Operand(:int)}"
1102 $asm.puts
"je #{operands[2].asmLabel}"
1104 # FIXME: unused and unimplemented for x87
1106 $asm.puts
"cvttsd2si #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:int)}"
1109 sp
= RegisterID
.new(nil, "sp")
1110 if (operands
[0].x87DefaultStackPosition
== 0)
1111 $asm.puts
"fistl -4(#{sp.x86Operand(:ptr)})"
1113 $asm.puts
"fld #{operands[0].x87Operand(0)}"
1114 $asm.puts
"fistp#{x86Suffix(:ptr)} #{getSizeString(:ptr)}#{offsetRegister(-4, sp.x86Operand(:ptr))}"
1116 $asm.puts
"mov#{x86Suffix(:int)} #{orderOperands(offsetRegister(-4, sp.x86Operand(:ptr)), operands[1].x86Operand(:int))}"
1117 $asm.puts
"test#{x86Suffix(:int)} #{operands[1].x86Operand(:int)}, #{operands[1].x86Operand(:int)}"
1118 $asm.puts
"je #{operands[2].asmLabel}"
1119 $asm.puts
"fild#{x86Suffix(:int)} #{getSizeString(:int)}#{offsetRegister(-4, sp.x86Operand(:ptr))}"
1120 $asm.puts
"fucomip #{@@floatingPointCompareImplicitOperand}#{operands[0].x87Operand(1)}"
1121 $asm.puts
"jp #{operands[2].asmLabel}"
1122 $asm.puts
"jne #{operands[2].asmLabel}"
1124 $asm.puts
"cvttsd2si #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:int)}"
1125 $asm.puts
"test#{x86Suffix(:int)} #{operands[1].x86Operand(:int)}, #{operands[1].x86Operand(:int)}"
1126 $asm.puts
"je #{operands[2].asmLabel}"
1127 $asm.puts
"cvtsi2sd #{operands[1].x86Operand(:int)}, %xmm7"
1128 $asm.puts
"ucomisd #{operands[0].x86Operand(:double)}, %xmm7"
1129 $asm.puts
"jp #{operands[2].asmLabel}"
1130 $asm.puts
"jne #{operands[2].asmLabel}"
1135 $asm.puts
"fstp #{operands[0].x87Operand(1)}"
1137 $asm.puts
"xorpd #{operands[0].x86Operand(:double)}, #{operands[0].x86Operand(:double)}"
1142 $asm.puts
"pop #{op.x86Operand(:ptr)}"
1147 $asm.puts
"push #{op.x86Operand(:ptr)}"
1153 $asm.puts
"movslq #{operands[0].x86Operand(:int)}, #{operands[1].x86Operand(:quad)}"
1155 $asm.puts
"movsxd #{orderOperands(operands[0].x86Operand(:int), operands[1].x86Operand(:quad))}"
1158 $asm.puts
"mov#{x86Suffix(:int)} #{orderOperands(operands[0].x86Operand(:int), operands[1].x86Operand(:int))}"
1162 handleX86IntBranch("je", :int)
1164 handleX86IntBranch("je", :ptr)
1166 handleX86IntBranch("je", :quad)
1168 handleX86IntBranch("jne", :int)
1170 handleX86IntBranch("jne", :ptr)
1172 handleX86IntBranch("jne", :quad)
1174 handleX86IntBranch("ja", :int)
1176 handleX86IntBranch("ja", :ptr)
1178 handleX86IntBranch("ja", :quad)
1180 handleX86IntBranch("jae", :int)
1182 handleX86IntBranch("jae", :ptr)
1184 handleX86IntBranch("jae", :quad)
1186 handleX86IntBranch("jb", :int)
1188 handleX86IntBranch("jb", :ptr)
1190 handleX86IntBranch("jb", :quad)
1192 handleX86IntBranch("jbe", :int)
1194 handleX86IntBranch("jbe", :ptr)
1196 handleX86IntBranch("jbe", :quad)
1198 handleX86IntBranch("jg", :int)
1200 handleX86IntBranch("jg", :ptr)
1202 handleX86IntBranch("jg", :quad)
1204 handleX86IntBranch("jge", :int)
1206 handleX86IntBranch("jge", :ptr)
1208 handleX86IntBranch("jge", :quad)
1210 handleX86IntBranch("jl", :int)
1212 handleX86IntBranch("jl", :ptr)
1214 handleX86IntBranch("jl", :quad)
1216 handleX86IntBranch("jle", :int)
1218 handleX86IntBranch("jle", :ptr)
1220 handleX86IntBranch("jle", :quad)
1222 handleX86IntBranch("je", :byte)
1224 handleX86IntBranch("jne", :byte)
1226 handleX86IntBranch("ja", :byte)
1228 handleX86IntBranch("jae", :byte)
1230 handleX86IntBranch("jb", :byte)
1232 handleX86IntBranch("jbe", :byte)
1234 handleX86IntBranch("jg", :byte)
1236 handleX86IntBranch("jge", :byte)
1238 handleX86IntBranch("jl", :byte)
1240 handleX86IntBranch("jlteq", :byte)
1242 handleX86BranchTest("js", :int)
1244 handleX86BranchTest("js", :ptr)
1246 handleX86BranchTest("js", :quad)
1248 handleX86BranchTest("jz", :int)
1250 handleX86BranchTest("jz", :ptr)
1252 handleX86BranchTest("jz", :quad)
1254 handleX86BranchTest("jnz", :int)
1256 handleX86BranchTest("jnz", :ptr)
1258 handleX86BranchTest("jnz", :quad)
1260 handleX86BranchTest("js", :byte)
1262 handleX86BranchTest("jz", :byte)
1264 handleX86BranchTest("jnz", :byte)
1266 $asm.puts
"jmp #{operands[0].x86CallOperand(:ptr)}"
1268 handleX86OpBranch("add#{x86Suffix(:int)}", "jo", :int)
1270 handleX86OpBranch("add#{x86Suffix(:ptr)}", "jo", :ptr)
1272 handleX86OpBranch("add#{x86Suffix(:quad)}", "jo", :quad)
1274 handleX86OpBranch("add#{x86Suffix(:int)}", "js", :int)
1276 handleX86OpBranch("add#{x86Suffix(:ptr)}", "js", :ptr)
1278 handleX86OpBranch("add#{x86Suffix(:quad)}", "js", :quad)
1280 handleX86OpBranch("add#{x86Suffix(:int)}", "jz", :int)
1282 handleX86OpBranch("add#{x86Suffix(:ptr)}", "jz", :ptr)
1284 handleX86OpBranch("add#{x86Suffix(:quad)}", "jz", :quad)
1286 handleX86OpBranch("add#{x86Suffix(:int)}", "jnz", :int)
1288 handleX86OpBranch("add#{x86Suffix(:ptr)}", "jnz", :ptr)
1290 handleX86OpBranch("add#{x86Suffix(:quad)}", "jnz", :quad)
1292 handleX86SubBranch("jo", :int)
1294 handleX86SubBranch("js", :int)
1296 handleX86SubBranch("jz", :int)
1298 handleX86SubBranch("jnz", :int)
1300 handleX86OpBranch("imul#{x86Suffix(:int)}", "jo", :int)
1302 handleX86OpBranch("imul#{x86Suffix(:int)}", "js", :int)
1304 handleX86OpBranch("imul#{x86Suffix(:int)}", "jz", :int)
1306 handleX86OpBranch("imul#{x86Suffix(:int)}", "jnz", :int)
1308 handleX86OpBranch("orl", "jo", :int)
1310 handleX86OpBranch("orl", "js", :int)
1312 handleX86OpBranch("orl", "jz", :int)
1314 handleX86OpBranch("orl", "jnz", :int)
1316 $asm.puts
"int #{const(3)}"
1321 $asm.puts
"ffree #{register("st")}(#{offset})"
1324 op
= operands
[0].x86CallOperand(:ptr)
1325 if operands
[0].is_a
? LabelReference
1328 $asm.puts
"call #{op}"
1332 handleX86IntCompareSet("sete", :int)
1334 handleX86IntCompareSet("sete", :byte)
1336 handleX86IntCompareSet("sete", :ptr)
1338 handleX86IntCompareSet("sete", :quad)
1340 handleX86IntCompareSet("setne", :int)
1342 handleX86IntCompareSet("setne", :byte)
1344 handleX86IntCompareSet("setne", :ptr)
1346 handleX86IntCompareSet("setne", :quad)
1348 handleX86IntCompareSet("seta", :int)
1350 handleX86IntCompareSet("seta", :byte)
1352 handleX86IntCompareSet("seta", :ptr)
1354 handleX86IntCompareSet("seta", :quad)
1356 handleX86IntCompareSet("setae", :int)
1358 handleX86IntCompareSet("setae", :byte)
1360 handleX86IntCompareSet("setae", :ptr)
1362 handleX86IntCompareSet("setae", :quad)
1364 handleX86IntCompareSet("setb", :int)
1366 handleX86IntCompareSet("setb", :byte)
1368 handleX86IntCompareSet("setb", :ptr)
1370 handleX86IntCompareSet("setb", :quad)
1372 handleX86IntCompareSet("setbe", :int)
1374 handleX86IntCompareSet("setbe", :byte)
1376 handleX86IntCompareSet("setbe", :ptr)
1378 handleX86IntCompareSet("setbe", :quad)
1380 handleX86IntCompareSet("setg", :int)
1382 handleX86IntCompareSet("setg", :byte)
1384 handleX86IntCompareSet("setg", :ptr)
1386 handleX86IntCompareSet("setg", :quad)
1388 handleX86IntCompareSet("setge", :int)
1390 handleX86IntCompareSet("setge", :byte)
1392 handleX86IntCompareSet("setge", :ptr)
1394 handleX86IntCompareSet("setge", :quad)
1396 handleX86IntCompareSet("setl", :int)
1398 handleX86IntCompareSet("setl", :byte)
1400 handleX86IntCompareSet("setl", :ptr)
1402 handleX86IntCompareSet("setl", :quad)
1404 handleX86IntCompareSet("setle", :int)
1406 handleX86IntCompareSet("setle", :byte)
1408 handleX86IntCompareSet("setle", :ptr)
1410 handleX86IntCompareSet("setle", :quad)
1412 handleX86SetTest("sets", :int)
1414 handleX86SetTest("setz", :int)
1416 handleX86SetTest("setnz", :int)
1418 handleX86SetTest("sets", :ptr)
1420 handleX86SetTest("setz", :ptr)
1422 handleX86SetTest("setnz", :ptr)
1424 handleX86SetTest("sets", :quad)
1426 handleX86SetTest("setz", :quad)
1428 handleX86SetTest("setnz", :quad)
1430 handleX86SetTest("sets", :byte)
1432 handleX86SetTest("setz", :byte)
1434 handleX86SetTest("setnz", :byte)
1442 $asm.puts
"idiv#{x86Suffix(:int)} #{operands[0].x86Operand(:int)}"
1445 sp
= RegisterID
.new(nil, "sp")
1446 $asm.puts
"mov#{x86Suffix(:int)} #{orderOperands(operands[0].x86Operand(:int), offsetRegister(-8, sp.x86Operand(:ptr)))}"
1447 $asm.puts
"mov#{x86Suffix(:int)} #{orderOperands(operands[1].x86Operand(:int), offsetRegister(-4, sp.x86Operand(:ptr)))}"
1448 $asm.puts
"fld#{x86Suffix(:ptr)} #{getSizeString(:double)}#{offsetRegister(-8, sp.x86Operand(:ptr))}"
1449 $asm.puts
"fstp #{operands[2].x87Operand(1)}"
1451 $asm.puts
"movd #{operands[0].x86Operand(:int)}, #{operands[2].x86Operand(:double)}"
1452 $asm.puts
"movd #{operands[1].x86Operand(:int)}, %xmm7"
1453 $asm.puts
"psllq $32, %xmm7"
1454 $asm.puts
"por %xmm7, #{operands[2].x86Operand(:double)}"
1458 sp
= RegisterID
.new(nil, "sp")
1459 if (operands
[0].x87DefaultStackPosition
== 0)
1460 $asm.puts
"fst#{x86Suffix(:ptr)} #{getSizeString(:double)}#{offsetRegister(-8, sp.x86Operand(:ptr))}"
1462 $asm.puts
"fld #{operands[0].x87Operand(0)}"
1463 $asm.puts
"fstpl -8(#{sp.x86Operand(:ptr)})"
1465 $asm.puts
"mov#{x86Suffix(:int)} #{orderOperands(offsetRegister(-8, sp.x86Operand(:ptr)), operands[1].x86Operand(:int))}"
1466 $asm.puts
"mov#{x86Suffix(:int)} #{orderOperands(offsetRegister(-4, sp.x86Operand(:ptr)), operands[2].x86Operand(:int))}"
1468 $asm.puts
"movd #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:int)}"
1469 $asm.puts
"movsd #{operands[0].x86Operand(:double)}, %xmm7"
1470 $asm.puts
"psrlq $32, %xmm7"
1471 $asm.puts
"movd %xmm7, #{operands[2].x86Operand(:int)}"
1475 sp
= RegisterID
.new(nil, "sp")
1476 $asm.puts
"movq #{operands[0].x86Operand(:quad)}, -8(#{sp.x86Operand(:ptr)})"
1477 $asm.puts
"fldl -8(#{sp.x86Operand(:ptr)})"
1478 $asm.puts
"fstp #{operands[1].x87Operand(1)}"
1481 $asm.puts
"movq #{operands[0].x86Operand(:quad)}, #{operands[1].x86Operand(:double)}"
1483 # MASM does not accept register operands with movq.
1484 # Debugging shows that movd actually moves a qword when using MASM.
1485 $asm.puts
"movd #{operands[1].x86Operand(:double)}, #{operands[0].x86Operand(:quad)}"
1490 sp
= RegisterID
.new(nil, "sp")
1491 if (operands
[0].x87DefaultStackPosition
== 0)
1492 $asm.puts
"fst#{x86Suffix(:int)} #{getSizeString(:int)}#{offsetRegister(-8, sp.x86Operand(:ptr))}"
1494 $asm.puts
"fld #{operands[0].x87Operand(0)}"
1495 $asm.puts
"fstpl -8(#{sp.x86Operand(:ptr)})"
1497 $asm.puts
"movq -8(#{sp.x86Operand(:ptr)}), #{operands[1].x86Operand(:quad)}"
1500 $asm.puts
"movq #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:quad)}"
1502 # MASM does not accept register operands with movq.
1503 # Debugging shows that movd actually moves a qword when using MASM.
1504 $asm.puts
"movd #{operands[1].x86Operand(:quad)}, #{operands[0].x86Operand(:double)}"
1508 $asm.puts
"jo #{operands[0].asmLabel}"
1510 $asm.puts
"js #{operands[0].asmLabel}"
1512 $asm.puts
"jz #{operands[0].asmLabel}"
1514 $asm.puts
"jnz #{operands[0].asmLabel}"
1516 $asm.puts
"lea#{x86Suffix(:int)} #{orderOperands(operands[0].x86AddressOperand(:int), operands[1].x86Operand(:int))}"
1518 $asm.puts
"lea#{x86Suffix(:ptr)} #{orderOperands(operands[0].x86AddressOperand(:ptr), operands[1].x86Operand(:ptr))}"