blob: f78b43912a252893eb3f86d461bc56b7f88a16cc [file] [log] [blame]
# Copyright (C) 2012 Apple Inc. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
# THE POSSIBILITY OF SUCH DAMAGE.
require "config"
def isX64
case $activeBackend
when "X86"
false
when "X86_64"
true
else
raise "bad value for $activeBackend: #{$activeBackend}"
end
end
class SpecialRegister < NoChildren
def x86Operand(kind)
raise unless @name =~ /^r/
raise unless isX64
case kind
when :half
"%" + @name + "w"
when :int
"%" + @name + "d"
when :ptr
"%" + @name
when :quad
"%" + @name
else
raise
end
end
def x86CallOperand(kind)
# Call operands are not allowed to be partial registers.
"*#{x86Operand(:quad)}"
end
end
X64_SCRATCH_REGISTER = SpecialRegister.new("r11")
class RegisterID
def supports8BitOnX86
case name
when "t0", "a0", "r0", "t1", "a1", "r1", "t2", "t3"
true
when "cfr", "ttnr", "tmr"
false
when "t4", "t5"
isX64
else
raise
end
end
def x86Operand(kind)
case name
when "t0", "a0", "r0"
case kind
when :byte
"%al"
when :half
"%ax"
when :int
"%eax"
when :ptr
isX64 ? "%rax" : "%eax"
when :quad
isX64 ? "%rax" : raise
else
raise
end
when "t1", "a1", "r1"
case kind
when :byte
"%dl"
when :half
"%dx"
when :int
"%edx"
when :ptr
isX64 ? "%rdx" : "%edx"
when :quad
isX64 ? "%rdx" : raise
else
raise
end
when "t2"
case kind
when :byte
"%cl"
when :half
"%cx"
when :int
"%ecx"
when :ptr
isX64 ? "%rcx" : "%ecx"
when :quad
isX64 ? "%rcx" : raise
else
raise
end
when "t3"
case kind
when :byte
"%bl"
when :half
"%bx"
when :int
"%ebx"
when :ptr
isX64 ? "%rbx" : "%ebx"
when :quad
isX64 ? "%rbx" : raise
else
raise
end
when "t4"
case kind
when :byte
"%sil"
when :half
"%si"
when :int
"%esi"
when :ptr
isX64 ? "%rsi" : "%esi"
when :quad
isX64 ? "%rsi" : raise
else
raise
end
when "cfr"
if isX64
case kind
when :half
"%r13w"
when :int
"%r13d"
when :ptr
"%r13"
when :quad
"%r13"
else
raise
end
else
case kind
when :byte
"%dil"
when :half
"%di"
when :int
"%edi"
when :ptr
"%edi"
else
raise
end
end
when "sp"
case kind
when :byte
"%spl"
when :half
"%sp"
when :int
"%esp"
when :ptr
isX64 ? "%rsp" : "%esp"
when :quad
isX64 ? "%rsp" : raise
else
raise
end
when "t5"
raise "Cannot use #{name} in 32-bit X86 at #{codeOriginString}" unless isX64
case kind
when :byte
"%dil"
when :half
"%di"
when :int
"%edi"
when :ptr
"%rdi"
when :quad
"%rdi"
end
when "t6"
raise "Cannot use #{name} in 32-bit X86 at #{codeOriginString}" unless isX64
case kind
when :half
"%r10w"
when :int
"%r10d"
when :ptr
"%r10"
when :quad
"%r10"
end
when "csr1"
raise "Cannot use #{name} in 32-bit X86 at #{codeOriginString}" unless isX64
case kind
when :half
"%r14w"
when :int
"%r14d"
when :ptr
"%r14"
when :quad
"%r14"
end
when "csr2"
raise "Cannot use #{name} in 32-bit X86 at #{codeOriginString}" unless isX64
case kind
when :half
"%r15w"
when :int
"%r15d"
when :ptr
"%r15"
when :quad
"%r15"
end
else
raise "Bad register #{name} for X86 at #{codeOriginString}"
end
end
def x86CallOperand(kind)
isX64 ? "*#{x86Operand(:quad)}" : "*#{x86Operand(:ptr)}"
end
end
class FPRegisterID
def x86Operand(kind)
raise unless kind == :double
case name
when "ft0", "fa0", "fr"
"%xmm0"
when "ft1", "fa1"
"%xmm1"
when "ft2", "fa2"
"%xmm2"
when "ft3", "fa3"
"%xmm3"
when "ft4"
"%xmm4"
when "ft5"
"%xmm5"
else
raise "Bad register #{name} for X86 at #{codeOriginString}"
end
end
def x86CallOperand(kind)
"*#{x86Operand(kind)}"
end
end
class Immediate
def validX86Immediate?
if isX64
value >= -0x80000000 and value <= 0x7fffffff
else
true
end
end
def x86Operand(kind)
"$#{value}"
end
def x86CallOperand(kind)
"#{value}"
end
end
class Address
def supports8BitOnX86
true
end
def x86AddressOperand(addressKind)
"#{offset.value}(#{base.x86Operand(addressKind)})"
end
def x86Operand(kind)
x86AddressOperand(:ptr)
end
def x86CallOperand(kind)
"*#{x86Operand(kind)}"
end
end
class BaseIndex
def supports8BitOnX86
true
end
def x86AddressOperand(addressKind)
"#{offset.value}(#{base.x86Operand(addressKind)}, #{index.x86Operand(addressKind)}, #{scale})"
end
def x86Operand(kind)
x86AddressOperand(:ptr)
end
def x86CallOperand(kind)
"*#{x86Operand(kind)}"
end
end
class AbsoluteAddress
def supports8BitOnX86
true
end
def x86AddressOperand(addressKind)
"#{address.value}"
end
def x86Operand(kind)
"#{address.value}"
end
def x86CallOperand(kind)
"*#{address.value}"
end
end
class LabelReference
def x86CallOperand(kind)
asmLabel
end
end
class LocalLabelReference
def x86CallOperand(kind)
asmLabel
end
end
class Sequence
def getModifiedListX86_64
newList = []
@list.each {
| node |
newNode = node
if node.is_a? Instruction
unless node.opcode == "move"
usedScratch = false
newOperands = node.operands.map {
| operand |
if operand.immediate? and not operand.validX86Immediate?
if usedScratch
raise "Attempt to use scratch register twice at #{operand.codeOriginString}"
end
newList << Instruction.new(operand.codeOrigin, "move", [operand, X64_SCRATCH_REGISTER])
usedScratch = true
X64_SCRATCH_REGISTER
else
operand
end
}
newNode = Instruction.new(node.codeOrigin, node.opcode, newOperands, node.annotation)
end
else
unless node.is_a? Label or
node.is_a? LocalLabel or
node.is_a? Skip
raise "Unexpected #{node.inspect} at #{node.codeOrigin}"
end
end
if newNode
newList << newNode
end
}
return newList
end
end
class Instruction
def x86Operands(*kinds)
raise unless kinds.size == operands.size
result = []
kinds.size.times {
| idx |
result << operands[idx].x86Operand(kinds[idx])
}
result.join(", ")
end
def x86Suffix(kind)
case kind
when :byte
"b"
when :half
"w"
when :int
"l"
when :ptr
isX64 ? "q" : "l"
when :quad
isX64 ? "q" : raise
when :double
"sd"
else
raise
end
end
def x86Bytes(kind)
case kind
when :byte
1
when :half
2
when :int
4
when :ptr
isX64 ? 8 : 4
when :quad
isX64 ? 8 : raise
when :double
8
else
raise
end
end
def handleX86OpWithNumOperands(opcode, kind, numOperands)
if numOperands == 3
if operands[0] == operands[2]
$asm.puts "#{opcode} #{operands[1].x86Operand(kind)}, #{operands[2].x86Operand(kind)}"
elsif operands[1] == operands[2]
$asm.puts "#{opcode} #{operands[0].x86Operand(kind)}, #{operands[2].x86Operand(kind)}"
else
$asm.puts "mov#{x86Suffix(kind)} #{operands[0].x86Operand(kind)}, #{operands[2].x86Operand(kind)}"
$asm.puts "#{opcode} #{operands[1].x86Operand(kind)}, #{operands[2].x86Operand(kind)}"
end
else
$asm.puts "#{opcode} #{operands[0].x86Operand(kind)}, #{operands[1].x86Operand(kind)}"
end
end
def handleX86Op(opcode, kind)
handleX86OpWithNumOperands(opcode, kind, operands.size)
end
def handleX86Shift(opcode, kind)
if operands[0].is_a? Immediate or operands[0] == RegisterID.forName(nil, "t2")
$asm.puts "#{opcode} #{operands[0].x86Operand(:byte)}, #{operands[1].x86Operand(kind)}"
else
cx = RegisterID.forName(nil, "t2")
$asm.puts "xchg#{x86Suffix(:ptr)} #{operands[0].x86Operand(:ptr)}, #{cx.x86Operand(:ptr)}"
$asm.puts "#{opcode} %cl, #{operands[1].x86Operand(kind)}"
$asm.puts "xchg#{x86Suffix(:ptr)} #{operands[0].x86Operand(:ptr)}, #{cx.x86Operand(:ptr)}"
end
end
def handleX86DoubleBranch(branchOpcode, mode)
case mode
when :normal
$asm.puts "ucomisd #{operands[1].x86Operand(:double)}, #{operands[0].x86Operand(:double)}"
when :reverse
$asm.puts "ucomisd #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:double)}"
else
raise mode.inspect
end
$asm.puts "#{branchOpcode} #{operands[2].asmLabel}"
end
def handleX86IntCompare(opcodeSuffix, kind)
if operands[0].is_a? Immediate and operands[0].value == 0 and operands[1].is_a? RegisterID and (opcodeSuffix == "e" or opcodeSuffix == "ne")
$asm.puts "test#{x86Suffix(kind)} #{operands[1].x86Operand(kind)}"
elsif operands[1].is_a? Immediate and operands[1].value == 0 and operands[0].is_a? RegisterID and (opcodeSuffix == "e" or opcodeSuffix == "ne")
$asm.puts "test#{x86Suffix(kind)} #{operands[0].x86Operand(kind)}"
else
$asm.puts "cmp#{x86Suffix(kind)} #{operands[1].x86Operand(kind)}, #{operands[0].x86Operand(kind)}"
end
end
def handleX86IntBranch(branchOpcode, kind)
handleX86IntCompare(branchOpcode[1..-1], kind)
$asm.puts "#{branchOpcode} #{operands[2].asmLabel}"
end
def handleX86Set(setOpcode, operand)
if operand.supports8BitOnX86
$asm.puts "#{setOpcode} #{operand.x86Operand(:byte)}"
$asm.puts "movzbl #{operand.x86Operand(:byte)}, #{operand.x86Operand(:int)}"
else
ax = RegisterID.new(nil, "t0")
$asm.puts "xchg#{x86Suffix(:ptr)} #{operand.x86Operand(:ptr)}, #{ax.x86Operand(:ptr)}"
$asm.puts "#{setOpcode} %al"
$asm.puts "movzbl %al, %eax"
$asm.puts "xchg#{x86Suffix(:ptr)} #{operand.x86Operand(:ptr)}, #{ax.x86Operand(:ptr)}"
end
end
def handleX86IntCompareSet(setOpcode, kind)
handleX86IntCompare(setOpcode[3..-1], kind)
handleX86Set(setOpcode, operands[2])
end
def handleX86Test(kind)
value = operands[0]
case operands.size
when 2
mask = Immediate.new(codeOrigin, -1)
when 3
mask = operands[1]
else
raise "Expected 2 or 3 operands, but got #{operands.size} at #{codeOriginString}"
end
if mask.is_a? Immediate and mask.value == -1
if value.is_a? RegisterID
$asm.puts "test#{x86Suffix(kind)} #{value.x86Operand(kind)}, #{value.x86Operand(kind)}"
else
$asm.puts "cmp#{x86Suffix(kind)} $0, #{value.x86Operand(kind)}"
end
else
$asm.puts "test#{x86Suffix(kind)} #{mask.x86Operand(kind)}, #{value.x86Operand(kind)}"
end
end
def handleX86BranchTest(branchOpcode, kind)
handleX86Test(kind)
$asm.puts "#{branchOpcode} #{operands.last.asmLabel}"
end
def handleX86SetTest(setOpcode, kind)
handleX86Test(kind)
handleX86Set(setOpcode, operands.last)
end
def handleX86OpBranch(opcode, branchOpcode, kind)
handleX86OpWithNumOperands(opcode, kind, operands.size - 1)
case operands.size
when 4
jumpTarget = operands[3]
when 3
jumpTarget = operands[2]
else
raise self.inspect
end
$asm.puts "#{branchOpcode} #{jumpTarget.asmLabel}"
end
def handleX86SubBranch(branchOpcode, kind)
if operands.size == 4 and operands[1] == operands[2]
$asm.puts "neg#{x86Suffix(kind)} #{operands[2].x86Operand(kind)}"
$asm.puts "add#{x86Suffix(kind)} #{operands[0].x86Operand(kind)}, #{operands[2].x86Operand(kind)}"
else
handleX86OpWithNumOperands("sub#{x86Suffix(kind)}", kind, operands.size - 1)
end
case operands.size
when 4
jumpTarget = operands[3]
when 3
jumpTarget = operands[2]
else
raise self.inspect
end
$asm.puts "#{branchOpcode} #{jumpTarget.asmLabel}"
end
def handleX86Add(kind)
if operands.size == 3 and operands[1] == operands[2]
unless Immediate.new(nil, 0) == operands[0]
$asm.puts "add#{x86Suffix(kind)} #{operands[0].x86Operand(kind)}, #{operands[2].x86Operand(kind)}"
end
elsif operands.size == 3 and operands[0].is_a? Immediate
raise unless operands[1].is_a? RegisterID
raise unless operands[2].is_a? RegisterID
if operands[0].value == 0
unless operands[1] == operands[2]
$asm.puts "mov#{x86Suffix(kind)} #{operands[1].x86Operand(kind)}, #{operands[2].x86Operand(kind)}"
end
else
$asm.puts "lea#{x86Suffix(kind)} #{operands[0].value}(#{operands[1].x86Operand(kind)}), #{operands[2].x86Operand(kind)}"
end
elsif operands.size == 3 and operands[0].is_a? RegisterID
raise unless operands[1].is_a? RegisterID
raise unless operands[2].is_a? RegisterID
if operands[0] == operands[2]
$asm.puts "add#{x86Suffix(kind)} #{operands[1].x86Operand(kind)}, #{operands[2].x86Operand(kind)}"
else
$asm.puts "lea#{x86Suffix(kind)} (#{operands[0].x86Operand(kind)}, #{operands[1].x86Operand(kind)}), #{operands[2].x86Operand(kind)}"
end
else
unless Immediate.new(nil, 0) == operands[0]
$asm.puts "add#{x86Suffix(kind)} #{x86Operands(kind, kind)}"
end
end
end
def handleX86Sub(kind)
if operands.size == 3 and operands[1] == operands[2]
$asm.puts "neg#{x86Suffix(kind)} #{operands[2].x86Operand(kind)}"
$asm.puts "add#{x86Suffix(kind)} #{operands[0].x86Operand(kind)}, #{operands[2].x86Operand(kind)}"
else
handleX86Op("sub#{x86Suffix(kind)}", kind)
end
end
def handleX86Mul(kind)
if operands.size == 3 and operands[0].is_a? Immediate
$asm.puts "imul#{x86Suffix(kind)} #{x86Operands(kind, kind, kind)}"
else
# FIXME: could do some peephole in case the left operand is immediate and it's
# a power of two.
handleX86Op("imul#{x86Suffix(kind)}", kind)
end
end
def handleMove
if Immediate.new(nil, 0) == operands[0] and operands[1].is_a? RegisterID
if isX64
$asm.puts "xor#{x86Suffix(:quad)} #{operands[1].x86Operand(:quad)}, #{operands[1].x86Operand(:quad)}"
else
$asm.puts "xor#{x86Suffix(:ptr)} #{operands[1].x86Operand(:ptr)}, #{operands[1].x86Operand(:ptr)}"
end
elsif operands[0] != operands[1]
if isX64
$asm.puts "mov#{x86Suffix(:quad)} #{x86Operands(:quad, :quad)}"
else
$asm.puts "mov#{x86Suffix(:ptr)} #{x86Operands(:ptr, :ptr)}"
end
end
end
def lowerX86
raise unless $activeBackend == "X86"
lowerX86Common
end
def lowerX86_64
raise unless $activeBackend == "X86_64"
lowerX86Common
end
def lowerX86Common
$asm.codeOrigin codeOriginString if $enableCodeOriginComments
$asm.annotation annotation if $enableInstrAnnotations
case opcode
when "addi"
handleX86Add(:int)
when "addp"
handleX86Add(:ptr)
when "addq"
handleX86Add(:quad)
when "andi"
handleX86Op("andl", :int)
when "andp"
handleX86Op("and#{x86Suffix(:ptr)}", :ptr)
when "andq"
handleX86Op("and#{x86Suffix(:quad)}", :quad)
when "lshifti"
handleX86Shift("sall", :int)
when "lshiftp"
handleX86Shift("sal#{x86Suffix(:ptr)}", :ptr)
when "lshiftq"
handleX86Shift("sal#{x86Suffix(:quad)}", :quad)
when "muli"
handleX86Mul(:int)
when "mulp"
handleX86Mul(:ptr)
when "mulq"
handleX86Mul(:quad)
when "negi"
$asm.puts "negl #{x86Operands(:int)}"
when "negp"
$asm.puts "neg#{x86Suffix(:ptr)} #{x86Operands(:ptr)}"
when "negq"
$asm.puts "neg#{x86Suffix(:quad)} #{x86Operands(:quad)}"
when "noti"
$asm.puts "notl #{x86Operands(:int)}"
when "ori"
handleX86Op("orl", :int)
when "orp"
handleX86Op("or#{x86Suffix(:ptr)}", :ptr)
when "orq"
handleX86Op("or#{x86Suffix(:quad)}", :quad)
when "rshifti"
handleX86Shift("sarl", :int)
when "rshiftp"
handleX86Shift("sar#{x86Suffix(:ptr)}", :ptr)
when "rshiftq"
handleX86Shift("sar#{x86Suffix(:quad)}", :quad)
when "urshifti"
handleX86Shift("shrl", :int)
when "urshiftp"
handleX86Shift("shr#{x86Suffix(:ptr)}", :ptr)
when "urshiftq"
handleX86Shift("shr#{x86Suffix(:quad)}", :quad)
when "subi"
handleX86Sub(:int)
when "subp"
handleX86Sub(:ptr)
when "subq"
handleX86Sub(:quad)
when "xori"
handleX86Op("xorl", :int)
when "xorp"
handleX86Op("xor#{x86Suffix(:ptr)}", :ptr)
when "xorq"
handleX86Op("xor#{x86Suffix(:quad)}", :quad)
when "loadi", "storei"
$asm.puts "movl #{x86Operands(:int, :int)}"
when "loadis"
if isX64
$asm.puts "movslq #{x86Operands(:int, :quad)}"
else
$asm.puts "movl #{x86Operands(:int, :int)}"
end
when "loadp", "storep"
$asm.puts "mov#{x86Suffix(:ptr)} #{x86Operands(:ptr, :ptr)}"
when "loadq", "storeq"
$asm.puts "mov#{x86Suffix(:quad)} #{x86Operands(:quad, :quad)}"
when "loadb"
$asm.puts "movzbl #{operands[0].x86Operand(:byte)}, #{operands[1].x86Operand(:int)}"
when "loadbs"
$asm.puts "movsbl #{operands[0].x86Operand(:byte)}, #{operands[1].x86Operand(:int)}"
when "loadh"
$asm.puts "movzwl #{operands[0].x86Operand(:half)}, #{operands[1].x86Operand(:int)}"
when "loadhs"
$asm.puts "movswl #{operands[0].x86Operand(:half)}, #{operands[1].x86Operand(:int)}"
when "storeb"
$asm.puts "movb #{x86Operands(:byte, :byte)}"
when "loadd", "moved", "stored"
$asm.puts "movsd #{x86Operands(:double, :double)}"
when "addd"
$asm.puts "addsd #{x86Operands(:double, :double)}"
when "divd"
$asm.puts "divsd #{x86Operands(:double, :double)}"
when "subd"
$asm.puts "subsd #{x86Operands(:double, :double)}"
when "muld"
$asm.puts "mulsd #{x86Operands(:double, :double)}"
when "sqrtd"
$asm.puts "sqrtsd #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:double)}"
when "ci2d"
$asm.puts "cvtsi2sd #{operands[0].x86Operand(:int)}, #{operands[1].x86Operand(:double)}"
when "bdeq"
$asm.puts "ucomisd #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:double)}"
if operands[0] == operands[1]
# This is just a jump ordered, which is a jnp.
$asm.puts "jnp #{operands[2].asmLabel}"
else
isUnordered = LocalLabel.unique("bdeq")
$asm.puts "jp #{LabelReference.new(codeOrigin, isUnordered).asmLabel}"
$asm.puts "je #{LabelReference.new(codeOrigin, operands[2]).asmLabel}"
isUnordered.lower("X86")
end
when "bdneq"
handleX86DoubleBranch("jne", :normal)
when "bdgt"
handleX86DoubleBranch("ja", :normal)
when "bdgteq"
handleX86DoubleBranch("jae", :normal)
when "bdlt"
handleX86DoubleBranch("ja", :reverse)
when "bdlteq"
handleX86DoubleBranch("jae", :reverse)
when "bdequn"
handleX86DoubleBranch("je", :normal)
when "bdnequn"
$asm.puts "ucomisd #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:double)}"
if operands[0] == operands[1]
# This is just a jump unordered, which is a jp.
$asm.puts "jp #{operands[2].asmLabel}"
else
isUnordered = LocalLabel.unique("bdnequn")
isEqual = LocalLabel.unique("bdnequn")
$asm.puts "jp #{LabelReference.new(codeOrigin, isUnordered).asmLabel}"
$asm.puts "je #{LabelReference.new(codeOrigin, isEqual).asmLabel}"
isUnordered.lower("X86")
$asm.puts "jmp #{operands[2].asmLabel}"
isEqual.lower("X86")
end
when "bdgtun"
handleX86DoubleBranch("jb", :reverse)
when "bdgtequn"
handleX86DoubleBranch("jbe", :reverse)
when "bdltun"
handleX86DoubleBranch("jb", :normal)
when "bdltequn"
handleX86DoubleBranch("jbe", :normal)
when "btd2i"
$asm.puts "cvttsd2si #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:int)}"
$asm.puts "cmpl $0x80000000 #{operands[1].x86Operand(:int)}"
$asm.puts "je #{operands[2].asmLabel}"
when "td2i"
$asm.puts "cvttsd2si #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:int)}"
when "bcd2i"
$asm.puts "cvttsd2si #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:int)}"
$asm.puts "testl #{operands[1].x86Operand(:int)}, #{operands[1].x86Operand(:int)}"
$asm.puts "je #{operands[2].asmLabel}"
$asm.puts "cvtsi2sd #{operands[1].x86Operand(:int)}, %xmm7"
$asm.puts "ucomisd #{operands[0].x86Operand(:double)}, %xmm7"
$asm.puts "jp #{operands[2].asmLabel}"
$asm.puts "jne #{operands[2].asmLabel}"
when "movdz"
$asm.puts "xorpd #{operands[0].x86Operand(:double)}, #{operands[0].x86Operand(:double)}"
when "pop"
$asm.puts "pop #{operands[0].x86Operand(:ptr)}"
when "push"
$asm.puts "push #{operands[0].x86Operand(:ptr)}"
when "move"
handleMove
when "sxi2q"
$asm.puts "movslq #{operands[0].x86Operand(:int)}, #{operands[1].x86Operand(:quad)}"
when "zxi2q"
$asm.puts "movl #{operands[0].x86Operand(:int)}, #{operands[1].x86Operand(:int)}"
when "nop"
$asm.puts "nop"
when "bieq"
handleX86IntBranch("je", :int)
when "bpeq"
handleX86IntBranch("je", :ptr)
when "bqeq"
handleX86IntBranch("je", :quad)
when "bineq"
handleX86IntBranch("jne", :int)
when "bpneq"
handleX86IntBranch("jne", :ptr)
when "bqneq"
handleX86IntBranch("jne", :quad)
when "bia"
handleX86IntBranch("ja", :int)
when "bpa"
handleX86IntBranch("ja", :ptr)
when "bqa"
handleX86IntBranch("ja", :quad)
when "biaeq"
handleX86IntBranch("jae", :int)
when "bpaeq"
handleX86IntBranch("jae", :ptr)
when "bqaeq"
handleX86IntBranch("jae", :quad)
when "bib"
handleX86IntBranch("jb", :int)
when "bpb"
handleX86IntBranch("jb", :ptr)
when "bqb"
handleX86IntBranch("jb", :quad)
when "bibeq"
handleX86IntBranch("jbe", :int)
when "bpbeq"
handleX86IntBranch("jbe", :ptr)
when "bqbeq"
handleX86IntBranch("jbe", :quad)
when "bigt"
handleX86IntBranch("jg", :int)
when "bpgt"
handleX86IntBranch("jg", :ptr)
when "bqgt"
handleX86IntBranch("jg", :quad)
when "bigteq"
handleX86IntBranch("jge", :int)
when "bpgteq"
handleX86IntBranch("jge", :ptr)
when "bqgteq"
handleX86IntBranch("jge", :quad)
when "bilt"
handleX86IntBranch("jl", :int)
when "bplt"
handleX86IntBranch("jl", :ptr)
when "bqlt"
handleX86IntBranch("jl", :quad)
when "bilteq"
handleX86IntBranch("jle", :int)
when "bplteq"
handleX86IntBranch("jle", :ptr)
when "bqlteq"
handleX86IntBranch("jle", :quad)
when "bbeq"
handleX86IntBranch("je", :byte)
when "bbneq"
handleX86IntBranch("jne", :byte)
when "bba"
handleX86IntBranch("ja", :byte)
when "bbaeq"
handleX86IntBranch("jae", :byte)
when "bbb"
handleX86IntBranch("jb", :byte)
when "bbbeq"
handleX86IntBranch("jbe", :byte)
when "bbgt"
handleX86IntBranch("jg", :byte)
when "bbgteq"
handleX86IntBranch("jge", :byte)
when "bblt"
handleX86IntBranch("jl", :byte)
when "bblteq"
handleX86IntBranch("jlteq", :byte)
when "btis"
handleX86BranchTest("js", :int)
when "btps"
handleX86BranchTest("js", :ptr)
when "btqs"
handleX86BranchTest("js", :quad)
when "btiz"
handleX86BranchTest("jz", :int)
when "btpz"
handleX86BranchTest("jz", :ptr)
when "btqz"
handleX86BranchTest("jz", :quad)
when "btinz"
handleX86BranchTest("jnz", :int)
when "btpnz"
handleX86BranchTest("jnz", :ptr)
when "btqnz"
handleX86BranchTest("jnz", :quad)
when "btbs"
handleX86BranchTest("js", :byte)
when "btbz"
handleX86BranchTest("jz", :byte)
when "btbnz"
handleX86BranchTest("jnz", :byte)
when "jmp"
$asm.puts "jmp #{operands[0].x86CallOperand(:ptr)}"
when "baddio"
handleX86OpBranch("addl", "jo", :int)
when "baddpo"
handleX86OpBranch("add#{x86Suffix(:ptr)}", "jo", :ptr)
when "baddqo"
handleX86OpBranch("add#{x86Suffix(:quad)}", "jo", :quad)
when "baddis"
handleX86OpBranch("addl", "js", :int)
when "baddps"
handleX86OpBranch("add#{x86Suffix(:ptr)}", "js", :ptr)
when "baddqs"
handleX86OpBranch("add#{x86Suffix(:quad)}", "js", :quad)
when "baddiz"
handleX86OpBranch("addl", "jz", :int)
when "baddpz"
handleX86OpBranch("add#{x86Suffix(:ptr)}", "jz", :ptr)
when "baddqz"
handleX86OpBranch("add#{x86Suffix(:quad)}", "jz", :quad)
when "baddinz"
handleX86OpBranch("addl", "jnz", :int)
when "baddpnz"
handleX86OpBranch("add#{x86Suffix(:ptr)}", "jnz", :ptr)
when "baddqnz"
handleX86OpBranch("add#{x86Suffix(:quad)}", "jnz", :quad)
when "bsubio"
handleX86SubBranch("jo", :int)
when "bsubis"
handleX86SubBranch("js", :int)
when "bsubiz"
handleX86SubBranch("jz", :int)
when "bsubinz"
handleX86SubBranch("jnz", :int)
when "bmulio"
handleX86OpBranch("imull", "jo", :int)
when "bmulis"
handleX86OpBranch("imull", "js", :int)
when "bmuliz"
handleX86OpBranch("imull", "jz", :int)
when "bmulinz"
handleX86OpBranch("imull", "jnz", :int)
when "borio"
handleX86OpBranch("orl", "jo", :int)
when "boris"
handleX86OpBranch("orl", "js", :int)
when "boriz"
handleX86OpBranch("orl", "jz", :int)
when "borinz"
handleX86OpBranch("orl", "jnz", :int)
when "break"
$asm.puts "int $3"
when "call"
$asm.puts "call #{operands[0].x86CallOperand(:ptr)}"
when "ret"
$asm.puts "ret"
when "cieq"
handleX86IntCompareSet("sete", :int)
when "cbeq"
handleX86IntCompareSet("sete", :byte)
when "cpeq"
handleX86IntCompareSet("sete", :ptr)
when "cqeq"
handleX86IntCompareSet("sete", :quad)
when "cineq"
handleX86IntCompareSet("setne", :int)
when "cbneq"
handleX86IntCompareSet("setne", :byte)
when "cpneq"
handleX86IntCompareSet("setne", :ptr)
when "cqneq"
handleX86IntCompareSet("setne", :quad)
when "cia"
handleX86IntCompareSet("seta", :int)
when "cba"
handleX86IntCompareSet("seta", :byte)
when "cpa"
handleX86IntCompareSet("seta", :ptr)
when "cqa"
handleX86IntCompareSet("seta", :quad)
when "ciaeq"
handleX86IntCompareSet("setae", :int)
when "cbaeq"
handleX86IntCompareSet("setae", :byte)
when "cpaeq"
handleX86IntCompareSet("setae", :ptr)
when "cqaeq"
handleX86IntCompareSet("setae", :quad)
when "cib"
handleX86IntCompareSet("setb", :int)
when "cbb"
handleX86IntCompareSet("setb", :byte)
when "cpb"
handleX86IntCompareSet("setb", :ptr)
when "cqb"
handleX86IntCompareSet("setb", :quad)
when "cibeq"
handleX86IntCompareSet("setbe", :int)
when "cbbeq"
handleX86IntCompareSet("setbe", :byte)
when "cpbeq"
handleX86IntCompareSet("setbe", :ptr)
when "cqbeq"
handleX86IntCompareSet("setbe", :quad)
when "cigt"
handleX86IntCompareSet("setg", :int)
when "cbgt"
handleX86IntCompareSet("setg", :byte)
when "cpgt"
handleX86IntCompareSet("setg", :ptr)
when "cqgt"
handleX86IntCompareSet("setg", :quad)
when "cigteq"
handleX86IntCompareSet("setge", :int)
when "cbgteq"
handleX86IntCompareSet("setge", :byte)
when "cpgteq"
handleX86IntCompareSet("setge", :ptr)
when "cqgteq"
handleX86IntCompareSet("setge", :quad)
when "cilt"
handleX86IntCompareSet("setl", :int)
when "cblt"
handleX86IntCompareSet("setl", :byte)
when "cplt"
handleX86IntCompareSet("setl", :ptr)
when "cqlt"
handleX86IntCompareSet("setl", :quad)
when "cilteq"
handleX86IntCompareSet("setle", :int)
when "cblteq"
handleX86IntCompareSet("setle", :byte)
when "cplteq"
handleX86IntCompareSet("setle", :ptr)
when "cqlteq"
handleX86IntCompareSet("setle", :quad)
when "tis"
handleX86SetTest("sets", :int)
when "tiz"
handleX86SetTest("setz", :int)
when "tinz"
handleX86SetTest("setnz", :int)
when "tps"
handleX86SetTest("sets", :ptr)
when "tpz"
handleX86SetTest("setz", :ptr)
when "tpnz"
handleX86SetTest("setnz", :ptr)
when "tqs"
handleX86SetTest("sets", :quad)
when "tqz"
handleX86SetTest("setz", :quad)
when "tqnz"
handleX86SetTest("setnz", :quad)
when "tbs"
handleX86SetTest("sets", :byte)
when "tbz"
handleX86SetTest("setz", :byte)
when "tbnz"
handleX86SetTest("setnz", :byte)
when "peek"
sp = RegisterID.new(nil, "sp")
$asm.puts "mov#{x86Suffix(:ptr)} #{operands[0].value * x86Bytes(:ptr)}(#{sp.x86Operand(:ptr)}), #{operands[1].x86Operand(:ptr)}"
when "peekq"
sp = RegisterID.new(nil, "sp")
$asm.puts "mov#{x86Suffix(:quad)} #{operands[0].value * x86Bytes(:quad)}(#{sp.x86Operand(:ptr)}), #{operands[1].x86Operand(:quad)}"
when "poke"
sp = RegisterID.new(nil, "sp")
$asm.puts "mov#{x86Suffix(:ptr)} #{operands[0].x86Operand(:ptr)}, #{operands[1].value * x86Bytes(:ptr)}(#{sp.x86Operand(:ptr)})"
when "pokeq"
sp = RegisterID.new(nil, "sp")
$asm.puts "mov#{x86Suffix(:quad)} #{operands[0].x86Operand(:quad)}, #{operands[1].value * x86Bytes(:quad)}(#{sp.x86Operand(:ptr)})"
when "cdqi"
$asm.puts "cdq"
when "idivi"
$asm.puts "idivl #{operands[0].x86Operand(:int)}"
when "fii2d"
$asm.puts "movd #{operands[0].x86Operand(:int)}, #{operands[2].x86Operand(:double)}"
$asm.puts "movd #{operands[1].x86Operand(:int)}, %xmm7"
$asm.puts "psllq $32, %xmm7"
$asm.puts "por %xmm7, #{operands[2].x86Operand(:double)}"
when "fd2ii"
$asm.puts "movd #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:int)}"
$asm.puts "movsd #{operands[0].x86Operand(:double)}, %xmm7"
$asm.puts "psrlq $32, %xmm7"
$asm.puts "movd %xmm7, #{operands[2].x86Operand(:int)}"
when "fq2d"
$asm.puts "movd #{operands[0].x86Operand(:quad)}, #{operands[1].x86Operand(:double)}"
when "fd2q"
$asm.puts "movd #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:quad)}"
when "bo"
$asm.puts "jo #{operands[0].asmLabel}"
when "bs"
$asm.puts "js #{operands[0].asmLabel}"
when "bz"
$asm.puts "jz #{operands[0].asmLabel}"
when "bnz"
$asm.puts "jnz #{operands[0].asmLabel}"
when "leai"
$asm.puts "leal #{operands[0].x86AddressOperand(:int)}, #{operands[1].x86Operand(:int)}"
when "leap"
$asm.puts "lea#{x86Suffix(:ptr)} #{operands[0].x86AddressOperand(:ptr)}, #{operands[1].x86Operand(:ptr)}"
else
lowerDefault
end
end
end