| # Copyright (C) 2011 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. |
| |
| class RegisterID |
| def supports8BitOnX86 |
| case name |
| when "t0", "a0", "r0", "t1", "a1", "r1", "t2", "t3" |
| true |
| when "t4", "cfr" |
| false |
| else |
| raise |
| end |
| end |
| |
| def x86Operand(kind) |
| case name |
| when "t0", "a0", "r0" |
| case kind |
| when :byte |
| "%al" |
| when :half |
| "%ax" |
| when :int |
| "%eax" |
| else |
| raise |
| end |
| when "t1", "a1", "r1" |
| case kind |
| when :byte |
| "%dl" |
| when :half |
| "%dx" |
| when :int |
| "%edx" |
| else |
| raise |
| end |
| when "t2" |
| case kind |
| when :byte |
| "%cl" |
| when :half |
| "%cx" |
| when :int |
| "%ecx" |
| else |
| raise |
| end |
| when "t3" |
| case kind |
| when :byte |
| "%bl" |
| when :half |
| "%bx" |
| when :int |
| "%ebx" |
| else |
| raise |
| end |
| when "t4" |
| case kind |
| when :byte |
| "%sil" |
| when :half |
| "%si" |
| when :int |
| "%esi" |
| else |
| raise |
| end |
| when "cfr" |
| case kind |
| when :byte |
| "%dil" |
| when :half |
| "%di" |
| when :int |
| "%edi" |
| else |
| raise |
| end |
| when "sp" |
| case kind |
| when :byte |
| "%spl" |
| when :half |
| "%sp" |
| when :int |
| "%esp" |
| else |
| raise |
| end |
| else |
| raise "Bad register #{name} for X86 at #{codeOriginString}" |
| end |
| end |
| def x86CallOperand(kind) |
| "*#{x86Operand(kind)}" |
| 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 x86Operand(kind) |
| "$#{value}" |
| end |
| def x86CallOperand(kind) |
| "#{value}" |
| end |
| end |
| |
| class Address |
| def supports8BitOnX86 |
| true |
| end |
| |
| def x86Operand(kind) |
| "#{offset.value}(#{base.x86Operand(:int)})" |
| end |
| def x86CallOperand(kind) |
| "*#{x86Operand(kind)}" |
| end |
| end |
| |
| class BaseIndex |
| def supports8BitOnX86 |
| true |
| end |
| |
| def x86Operand(kind) |
| "#{offset.value}(#{base.x86Operand(:int)}, #{index.x86Operand(:int)}, #{scale})" |
| end |
| |
| def x86CallOperand(kind) |
| "*#{x86operand(kind)}" |
| end |
| end |
| |
| class AbsoluteAddress |
| def supports8BitOnX86 |
| true |
| 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 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 :double |
| "sd" |
| 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 |
| $asm.puts "xchgl #{operands[0].x86Operand(:int)}, %ecx" |
| $asm.puts "#{opcode} %cl, #{operands[1].x86Operand(kind)}" |
| $asm.puts "xchgl #{operands[0].x86Operand(:int)}, %ecx" |
| 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 |
| $asm.puts "xchgl #{operand.x86Operand(:int)}, %eax" |
| $asm.puts "#{setOpcode} %al" |
| $asm.puts "movzbl %al, %eax" |
| $asm.puts "xchgl #{operand.x86Operand(:int)}, %eax" |
| 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 "negl #{operands[2].x86Operand(:int)}" |
| $asm.puts "addl #{operands[0].x86Operand(:int)}, #{operands[2].x86Operand(:int)}" |
| 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 lowerX86 |
| $asm.comment codeOriginString |
| case opcode |
| when "addi", "addp" |
| if 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 "movl #{operands[1].x86Operand(:int)}, #{operands[2].x86Operand(:int)}" |
| end |
| else |
| $asm.puts "leal #{operands[0].value}(#{operands[1].x86Operand(:int)}), #{operands[2].x86Operand(:int)}" |
| 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 |
| $asm.puts "leal (#{operands[0].x86Operand(:int)}, #{operands[1].x86Operand(:int)}), #{operands[2].x86Operand(:int)}" |
| else |
| unless Immediate.new(nil, 0) == operands[0] |
| $asm.puts "addl #{x86Operands(:int, :int)}" |
| end |
| end |
| when "andi", "andp" |
| handleX86Op("andl", :int) |
| when "lshifti" |
| handleX86Shift("sall", :int) |
| when "muli" |
| if operands.size == 3 and operands[0].is_a? Immediate |
| $asm.puts "imull #{x86Operands(:int, :int, :int)}" |
| else |
| # FIXME: could do some peephole in case the left operand is immediate and it's |
| # a power of two. |
| handleX86Op("imull", :int) |
| end |
| when "negi" |
| $asm.puts "negl #{x86Operands(:int)}" |
| when "noti" |
| $asm.puts "notl #{x86Operands(:int)}" |
| when "ori", "orp" |
| handleX86Op("orl", :int) |
| when "rshifti" |
| handleX86Shift("sarl", :int) |
| when "urshifti" |
| handleX86Shift("shrl", :int) |
| when "subi", "subp" |
| if operands.size == 3 and operands[1] == operands[2] |
| $asm.puts "negl #{operands[2].x86Operand(:int)}" |
| $asm.puts "addl #{operands[0].x86Operand(:int)}, #{operands[2].x86Operand(:int)}" |
| else |
| handleX86Op("subl", :int) |
| end |
| when "xori", "xorp" |
| handleX86Op("xorl", :int) |
| when "loadi", "storei", "loadp", "storep" |
| $asm.puts "movl #{x86Operands(:int, :int)}" |
| 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" |
| isUnordered = LocalLabel.unique("bdeq") |
| $asm.puts "ucomisd #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:double)}" |
| $asm.puts "jp #{LabelReference.new(codeOrigin, isUnordered).asmLabel}" |
| $asm.puts "je #{LabelReference.new(codeOrigin, operands[2]).asmLabel}" |
| isUnordered.lower("X86") |
| 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" |
| isUnordered = LocalLabel.unique("bdnequn") |
| isEqual = LocalLabel.unique("bdnequn") |
| $asm.puts "ucomisd #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:double)}" |
| $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") |
| 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(:int)}" |
| when "push" |
| $asm.puts "push #{operands[0].x86Operand(:int)}" |
| when "move", "sxi2p", "zxi2p" |
| if Immediate.new(nil, 0) == operands[0] and operands[1].is_a? RegisterID |
| $asm.puts "xorl #{operands[1].x86Operand(:int)}, #{operands[1].x86Operand(:int)}" |
| elsif operands[0] != operands[1] |
| $asm.puts "movl #{x86Operands(:int, :int)}" |
| end |
| when "nop" |
| $asm.puts "nop" |
| when "bieq", "bpeq" |
| handleX86IntBranch("je", :int) |
| when "bineq", "bpneq" |
| handleX86IntBranch("jne", :int) |
| when "bia", "bpa" |
| handleX86IntBranch("ja", :int) |
| when "biaeq", "bpaeq" |
| handleX86IntBranch("jae", :int) |
| when "bib", "bpb" |
| handleX86IntBranch("jb", :int) |
| when "bibeq", "bpbeq" |
| handleX86IntBranch("jbe", :int) |
| when "bigt", "bpgt" |
| handleX86IntBranch("jg", :int) |
| when "bigteq", "bpgteq" |
| handleX86IntBranch("jge", :int) |
| when "bilt", "bplt" |
| handleX86IntBranch("jl", :int) |
| when "bilteq", "bplteq" |
| handleX86IntBranch("jle", :int) |
| 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 "btio", "btpo" |
| handleX86BranchTest("jo", :int) |
| when "btis", "btps" |
| handleX86BranchTest("js", :int) |
| when "btiz", "btpz" |
| handleX86BranchTest("jz", :int) |
| when "btinz", "btpnz" |
| handleX86BranchTest("jnz", :int) |
| when "btbo" |
| handleX86BranchTest("jo", :byte) |
| when "btbs" |
| handleX86BranchTest("js", :byte) |
| when "btbz" |
| handleX86BranchTest("jz", :byte) |
| when "btbnz" |
| handleX86BranchTest("jnz", :byte) |
| when "jmp" |
| $asm.puts "jmp #{operands[0].x86CallOperand(:int)}" |
| when "baddio", "baddpo" |
| handleX86OpBranch("addl", "jo", :int) |
| when "baddis", "baddps" |
| handleX86OpBranch("addl", "js", :int) |
| when "baddiz", "baddpz" |
| handleX86OpBranch("addl", "jz", :int) |
| when "baddinz", "baddpnz" |
| handleX86OpBranch("addl", "jnz", :int) |
| 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(:int)}" |
| when "ret" |
| $asm.puts "ret" |
| when "cieq", "cpeq" |
| handleX86IntCompareSet("sete", :int) |
| when "cineq", "cpneq" |
| handleX86IntCompareSet("setne", :int) |
| when "cia", "cpa" |
| handleX86IntCompareSet("seta", :int) |
| when "ciaeq", "cpaeq" |
| handleX86IntCompareSet("setae", :int) |
| when "cib", "cpb" |
| handleX86IntCompareSet("setb", :int) |
| when "cibeq", "cpbeq" |
| handleX86IntCompareSet("setbe", :int) |
| when "cigt", "cpgt" |
| handleX86IntCompareSet("setg", :int) |
| when "cigteq", "cpgteq" |
| handleX86IntCompareSet("setge", :int) |
| when "cilt", "cplt" |
| handleX86IntCompareSet("setl", :int) |
| when "cilteq", "cplteq" |
| handleX86IntCompareSet("setle", :int) |
| when "tio" |
| handleX86SetTest("seto", :int) |
| when "tis" |
| handleX86SetTest("sets", :int) |
| when "tiz" |
| handleX86SetTest("setz", :int) |
| when "tinz" |
| handleX86SetTest("setnz", :int) |
| when "tbo" |
| handleX86SetTest("seto", :byte) |
| when "tbs" |
| handleX86SetTest("sets", :byte) |
| when "tbz" |
| handleX86SetTest("setz", :byte) |
| when "tbnz" |
| handleX86SetTest("setnz", :byte) |
| when "peek" |
| $asm.puts "movl #{operands[0].value * 4}(%esp), #{operands[1].x86Operand(:int)}" |
| when "poke" |
| $asm.puts "movl #{operands[0].x86Operand(:int)}, #{operands[1].value * 4}(%esp)" |
| 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 "movsd %xmm7, #{operands[2].x86Operand(:int)}" |
| 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", "leap" |
| $asm.puts "leal #{operands[0].x86Operand(:int)}, #{operands[1].x86Operand(:int)}" |
| else |
| raise "Bad opcode: #{opcode}" |
| end |
| end |
| end |
| |