|  | # Copyright (C) 2012-2018 Apple Inc. All rights reserved. | 
|  | # Copyright (C) 2013 Digia Plc. and/or its subsidiary(-ies) | 
|  | # | 
|  | # 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" | 
|  |  | 
|  | # GPR conventions, to match the baseline JIT: | 
|  | # | 
|  | # | 
|  | # On x86-32 bits (windows and non-windows) | 
|  | # a0, a1, a2, a3 are only there for ease-of-use of offlineasm; they are not | 
|  | # actually considered as such by the ABI and we need to push/pop our arguments | 
|  | # on the stack. a0 and a1 are ecx and edx to follow fastcall. | 
|  | # | 
|  | # eax => t0, a2, r0 | 
|  | # edx => t1, a1, r1 | 
|  | # ecx => t2, a0 | 
|  | # ebx => t3, a3     (callee-save) | 
|  | # esi => t4         (callee-save) | 
|  | # edi => t5         (callee-save) | 
|  | # ebp => cfr | 
|  | # esp => sp | 
|  | # | 
|  | # On x86-64 non-windows | 
|  | # | 
|  | # rax => t0,     r0 | 
|  | # rdi =>     a0 | 
|  | # rsi => t1, a1 | 
|  | # rdx => t2, a2, r1 | 
|  | # rcx => t3, a3 | 
|  | #  r8 => t4 | 
|  | #  r9 => t5 | 
|  | # r10 => t6 | 
|  | # rbx =>             csr0 (callee-save, wasmInstance) | 
|  | # r12 =>             csr1 (callee-save, metadataTable) | 
|  | # r13 =>             csr2 (callee-save, PB) | 
|  | # r14 =>             csr3 (callee-save, tagTypeNumber) | 
|  | # r15 =>             csr4 (callee-save, tagMask) | 
|  | # rsp => sp | 
|  | # rbp => cfr | 
|  | # r11 =>                  (scratch) | 
|  | # | 
|  | # On x86-64 windows | 
|  | # Arguments need to be push/pop'd on the stack in addition to being stored in | 
|  | # the registers. Also, >8 return types are returned in a weird way. | 
|  | # | 
|  | # rax => t0,     r0 | 
|  | # rcx => t5, a0 | 
|  | # rdx => t1, a1, r1 | 
|  | #  r8 => t2, a2 | 
|  | #  r9 => t3, a3 | 
|  | # r10 => t4 | 
|  | # rbx =>             csr0 (callee-save, PB, unused in baseline) | 
|  | # rsi =>             csr1 (callee-save) | 
|  | # rdi =>             csr2 (callee-save) | 
|  | # r12 =>             csr3 (callee-save) | 
|  | # r13 =>             csr4 (callee-save) | 
|  | # r14 =>             csr5 (callee-save, numberTag) | 
|  | # r15 =>             csr6 (callee-save, notCellMask) | 
|  | # rsp => sp | 
|  | # rbp => cfr | 
|  | # r11 =>                  (scratch) | 
|  |  | 
|  | def isX64 | 
|  | case $activeBackend | 
|  | when "X86" | 
|  | false | 
|  | when "X86_WIN" | 
|  | false | 
|  | when "X86_64" | 
|  | true | 
|  | when "X86_64_WIN" | 
|  | true | 
|  | else | 
|  | raise "bad value for $activeBackend: #{$activeBackend}" | 
|  | end | 
|  | end | 
|  |  | 
|  | def isWin | 
|  | case $activeBackend | 
|  | when "X86" | 
|  | false | 
|  | when "X86_WIN" | 
|  | true | 
|  | when "X86_64" | 
|  | false | 
|  | when "X86_64_WIN" | 
|  | true | 
|  | else | 
|  | raise "bad value for $activeBackend: #{$activeBackend}" | 
|  | end | 
|  | end | 
|  |  | 
|  | def isMSVC | 
|  | $options.has_key?(:assembler) && $options[:assembler] == "MASM" | 
|  | end | 
|  |  | 
|  | def isIntelSyntax | 
|  | $options.has_key?(:assembler) && $options[:assembler] == "MASM" | 
|  | end | 
|  |  | 
|  | def register(name) | 
|  | isIntelSyntax ? name : "%" + name | 
|  | end | 
|  |  | 
|  | def offsetRegister(off, register) | 
|  | isIntelSyntax ? "[#{off} + #{register}]" : "#{off}(#{register})" | 
|  | end | 
|  |  | 
|  | def callPrefix | 
|  | isIntelSyntax ? "" : "*" | 
|  | end | 
|  |  | 
|  | def orderOperands(*operands) | 
|  | (isIntelSyntax ? operands.reverse : operands).join(", ") | 
|  | end | 
|  |  | 
|  | def const(c) | 
|  | isIntelSyntax ? "#{c}" : "$#{c}" | 
|  | end | 
|  |  | 
|  | def getSizeString(kind) | 
|  | if !isIntelSyntax | 
|  | return "" | 
|  | end | 
|  |  | 
|  | size = "" | 
|  | case kind | 
|  | when :byte | 
|  | size = "byte" | 
|  | when :half | 
|  | size = "word" | 
|  | when :int | 
|  | size = "dword" | 
|  | when :ptr | 
|  | size =  isX64 ? "qword" : "dword" | 
|  | when :float | 
|  | size = "dword" | 
|  | when :double | 
|  | size = "qword" | 
|  | when :quad | 
|  | size = "qword" | 
|  | else | 
|  | raise "Invalid kind #{kind}" | 
|  | end | 
|  |  | 
|  | return size + " " + "ptr" + " "; | 
|  | end | 
|  |  | 
|  | class SpecialRegister < NoChildren | 
|  | def x86Operand(kind) | 
|  | raise unless @name =~ /^r/ | 
|  | raise unless isX64 | 
|  | case kind | 
|  | when :half | 
|  | register(@name + "w") | 
|  | when :int | 
|  | register(@name + "d") | 
|  | when :ptr | 
|  | register(@name) | 
|  | when :quad | 
|  | register(@name) | 
|  | else | 
|  | raise codeOriginString | 
|  | end | 
|  | end | 
|  | def x86CallOperand(kind) | 
|  | # Call operands are not allowed to be partial registers. | 
|  | "#{callPrefix}#{x86Operand(:quad)}" | 
|  | end | 
|  | end | 
|  |  | 
|  | X64_SCRATCH_REGISTER = SpecialRegister.new("r11") | 
|  |  | 
|  | def x86GPRName(name, kind) | 
|  | case name | 
|  | when "eax", "ebx", "ecx", "edx" | 
|  | name8 = name[1] + 'l' | 
|  | name16 = name[1..2] | 
|  | when "esi", "edi", "ebp", "esp" | 
|  | name16 = name[1..2] | 
|  | name8 = name16 + 'l' | 
|  | when "rax", "rbx", "rcx", "rdx" | 
|  | raise "bad GPR name #{name} in 32-bit X86" unless isX64 | 
|  | name8 = name[1] + 'l' | 
|  | name16 = name[1..2] | 
|  | when "r8", "r9", "r10", "r12", "r13", "r14", "r15" | 
|  | raise "bad GPR name #{name} in 32-bit X86" unless isX64 | 
|  | case kind | 
|  | when :half | 
|  | return register(name + "w") | 
|  | when :int | 
|  | return register(name + "d") | 
|  | when :ptr | 
|  | return register(name) | 
|  | when :quad | 
|  | return register(name) | 
|  | end | 
|  | else | 
|  | raise "bad GPR name #{name}" | 
|  | end | 
|  | case kind | 
|  | when :byte | 
|  | register(name8) | 
|  | when :half | 
|  | register(name16) | 
|  | when :int | 
|  | register("e" + name16) | 
|  | when :ptr | 
|  | register((isX64 ? "r" : "e") + name16) | 
|  | when :quad | 
|  | isX64 ? register("r" + name16) : raise | 
|  | else | 
|  | raise "invalid kind #{kind} for GPR #{name} in X86" | 
|  | end | 
|  | end | 
|  |  | 
|  | class Node | 
|  | def x86LoadOperand(type, dst) | 
|  | x86Operand(type) | 
|  | end | 
|  | end | 
|  |  | 
|  | class RegisterID | 
|  | def supports8BitOnX86 | 
|  | case x86GPR | 
|  | when "eax", "ebx", "ecx", "edx", "edi", "esi", "ebp", "esp" | 
|  | true | 
|  | when "r8", "r9", "r10", "r12", "r13", "r14", "r15" | 
|  | false | 
|  | else | 
|  | raise | 
|  | end | 
|  | end | 
|  |  | 
|  | def x86GPR | 
|  | if isX64 | 
|  | case name | 
|  | when "t0", "r0", "ws0" | 
|  | "eax" | 
|  | when "r1" | 
|  | "edx" # t1 = a1 when isWin, t2 = a2 otherwise | 
|  | when "a0", "wa0" | 
|  | isWin ? "ecx" : "edi" | 
|  | when "t1", "a1", "wa1" | 
|  | isWin ? "edx" : "esi" | 
|  | when "t2", "a2", "wa2" | 
|  | isWin ? "r8" : "edx" | 
|  | when "t3", "a3", "wa3" | 
|  | isWin ? "r9" : "ecx" | 
|  | when "t4", "wa4" | 
|  | isWin ? "r10" : "r8" | 
|  | when "t5", "wa5" | 
|  | isWin ? "ecx" : "r9" | 
|  | when "t6", "ws1" | 
|  | raise "cannot use register #{name} on X86-64 Windows" if isWin | 
|  | "r10" | 
|  | when "csr0" | 
|  | "ebx" | 
|  | when "csr1" | 
|  | isWin ? "esi" : "r12" | 
|  | when "csr2" | 
|  | isWin ? "edi" : "r13" | 
|  | when "csr3" | 
|  | isWin ? "r12" : "r14" | 
|  | when "csr4" | 
|  | isWin ? "r13" : "r15" | 
|  | when "csr5" | 
|  | raise "cannot use register #{name} on X86-64" unless isWin | 
|  | "r14" | 
|  | when "csr6" | 
|  | raise "cannot use register #{name} on X86-64" unless isWin | 
|  | "r15" | 
|  | when "cfr" | 
|  | "ebp" | 
|  | when "sp" | 
|  | "esp" | 
|  | else | 
|  | raise "cannot use register #{name} on X86" | 
|  | end | 
|  | else | 
|  | case name | 
|  | when "t0", "r0", "a2" | 
|  | "eax" | 
|  | when "t1", "r1", "a1" | 
|  | "edx" | 
|  | when "t2", "a0" | 
|  | "ecx" | 
|  | when "t3", "a3" | 
|  | "ebx" | 
|  | when "t4" | 
|  | "esi" | 
|  | when "t5" | 
|  | "edi" | 
|  | when "cfr" | 
|  | "ebp" | 
|  | when "sp" | 
|  | "esp" | 
|  | end | 
|  | end | 
|  | end | 
|  |  | 
|  | def x86Operand(kind) | 
|  | x86GPRName(x86GPR, kind) | 
|  | end | 
|  |  | 
|  | def x86CallOperand(kind) | 
|  | "#{callPrefix}#{x86Operand(:ptr)}" | 
|  | end | 
|  | end | 
|  |  | 
|  | class FPRegisterID | 
|  | def x86Operand(kind) | 
|  | raise unless [:float, :double].include? kind | 
|  | case name | 
|  | when "ft0", "fa0", "fr", "wfa0" | 
|  | register("xmm0") | 
|  | when "ft1", "fa1", "wfa1" | 
|  | register("xmm1") | 
|  | when "ft2", "fa2", "wfa2" | 
|  | register("xmm2") | 
|  | when "ft3", "fa3", "wfa3" | 
|  | register("xmm3") | 
|  | when "ft4", "wfa4" | 
|  | register("xmm4") | 
|  | when "ft5", "wfa5" | 
|  | register("xmm5") | 
|  | when "wfa6" | 
|  | register("xmm6") | 
|  | when "wfa7" | 
|  | register("xmm7") | 
|  | else | 
|  | raise "Bad register #{name} for X86 at #{codeOriginString}" | 
|  | end | 
|  | end | 
|  | def x86CallOperand(kind) | 
|  | "#{callPrefix}#{x86Operand(kind)}" | 
|  | end | 
|  | end | 
|  |  | 
|  | class Immediate | 
|  | def validX86Immediate? | 
|  | if isX64 | 
|  | value >= -0x80000000 and value <= 0x7fffffff | 
|  | else | 
|  | true | 
|  | end | 
|  | end | 
|  | def x86Operand(kind) | 
|  | "#{const(value)}" | 
|  | end | 
|  | def x86CallOperand(kind) | 
|  | "#{value}" | 
|  | end | 
|  | end | 
|  |  | 
|  | class Address | 
|  | def supports8BitOnX86 | 
|  | true | 
|  | end | 
|  |  | 
|  | def x86AddressOperand(addressKind) | 
|  | "#{offsetRegister(offset.value, base.x86Operand(addressKind))}" | 
|  | end | 
|  | def x86Operand(kind) | 
|  | "#{getSizeString(kind)}#{x86AddressOperand(:ptr)}" | 
|  | end | 
|  | def x86CallOperand(kind) | 
|  | "#{callPrefix}#{x86Operand(kind)}" | 
|  | end | 
|  | end | 
|  |  | 
|  | class BaseIndex | 
|  | def supports8BitOnX86 | 
|  | true | 
|  | end | 
|  |  | 
|  | def x86AddressOperand(addressKind) | 
|  | if !isIntelSyntax | 
|  | "#{offset.value}(#{base.x86Operand(addressKind)}, #{index.x86Operand(addressKind)}, #{scaleValue})" | 
|  | else | 
|  | "#{getSizeString(addressKind)}[#{offset.value} + #{base.x86Operand(addressKind)} + #{index.x86Operand(addressKind)} * #{scaleValue}]" | 
|  | end | 
|  | end | 
|  |  | 
|  | def x86Operand(kind) | 
|  | if !isIntelSyntax | 
|  | x86AddressOperand(:ptr) | 
|  | else | 
|  | "#{getSizeString(kind)}[#{offset.value} + #{base.x86Operand(:ptr)} + #{index.x86Operand(:ptr)} * #{scaleValue}]" | 
|  | end | 
|  | end | 
|  |  | 
|  | def x86CallOperand(kind) | 
|  | "#{callPrefix}#{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) | 
|  | "#{callPrefix}#{address.value}" | 
|  | end | 
|  | end | 
|  |  | 
|  | class LabelReference | 
|  | def x86CallOperand(kind) | 
|  | asmLabel | 
|  | end | 
|  | def x86LoadOperand(kind, dst) | 
|  | # FIXME: Implement this on platforms that aren't Mach-O. | 
|  | # https://bugs.webkit.org/show_bug.cgi?id=175104 | 
|  | used | 
|  | if !isIntelSyntax | 
|  | $asm.puts "movq #{asmLabel}@GOTPCREL(%rip), #{dst.x86Operand(:ptr)}" | 
|  | else | 
|  | $asm.puts "lea #{dst.x86Operand(:ptr)}, #{asmLabel}" | 
|  | end | 
|  | "#{offset}(#{dst.x86Operand(kind)})" | 
|  | end | 
|  | end | 
|  |  | 
|  | class LocalLabelReference | 
|  | def x86Operand(kind) | 
|  | asmLabel | 
|  | end | 
|  | 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 | 
|  | def getModifiedListX86_64_WIN | 
|  | getModifiedListX86_64 | 
|  | end | 
|  | end | 
|  |  | 
|  | class Instruction | 
|  |  | 
|  | def x86Operands(*kinds) | 
|  | raise "Expected size of kinds to be #{operands.size}, but it was #{kinds.size}" unless kinds.size == operands.size | 
|  | result = [] | 
|  | kinds.size.times { | 
|  | | idx | | 
|  | i = isIntelSyntax ? (kinds.size - idx - 1) : idx | 
|  | result << operands[i].x86Operand(kinds[i]) | 
|  | } | 
|  | result.join(", ") | 
|  | end | 
|  |  | 
|  | def x86LoadOperands(srcKind, dstKind) | 
|  | orderOperands(operands[0].x86LoadOperand(srcKind, operands[1]), operands[1].x86Operand(dstKind)) | 
|  | end | 
|  |  | 
|  | def x86Suffix(kind) | 
|  | if isIntelSyntax and not [:float, :double].include? kind | 
|  | return "" | 
|  | end | 
|  |  | 
|  | case kind | 
|  | when :byte | 
|  | "b" | 
|  | when :half | 
|  | "w" | 
|  | when :int | 
|  | "l" | 
|  | when :ptr | 
|  | isX64 ? "q" : "l" | 
|  | when :quad | 
|  | isX64 ? "q" : raise | 
|  | when :float | 
|  | "ss" | 
|  | 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 :float | 
|  | 4 | 
|  | when :double | 
|  | 8 | 
|  | else | 
|  | raise | 
|  | end | 
|  | end | 
|  |  | 
|  | def emitX86Lea(src, dst, kind) | 
|  | if src.is_a? LabelReference | 
|  | src.used | 
|  | if !isIntelSyntax | 
|  | $asm.puts "movq #{src.asmLabel}@GOTPCREL(%rip), #{dst.x86Operand(:ptr)}" | 
|  | else | 
|  | $asm.puts "lea #{dst.x86Operand(:ptr)}, #{src.asmLabel}" | 
|  | end | 
|  | else | 
|  | $asm.puts "lea#{x86Suffix(kind)} #{orderOperands(src.x86AddressOperand(kind), dst.x86Operand(kind))}" | 
|  | end | 
|  | end | 
|  |  | 
|  | def getImplicitOperandString | 
|  | isIntelSyntax ? "st(0), " : "" | 
|  | end | 
|  |  | 
|  | def handleX86OpWithNumOperands(opcode, kind, numOperands) | 
|  | if numOperands == 3 | 
|  | if operands[0] == operands[2] | 
|  | $asm.puts "#{opcode} #{orderOperands(operands[1].x86Operand(kind), operands[2].x86Operand(kind))}" | 
|  | elsif operands[1] == operands[2] | 
|  | $asm.puts "#{opcode} #{orderOperands(operands[0].x86Operand(kind), operands[2].x86Operand(kind))}" | 
|  | else | 
|  | $asm.puts "mov#{x86Suffix(kind)} #{orderOperands(operands[0].x86Operand(kind), operands[2].x86Operand(kind))}" | 
|  | $asm.puts "#{opcode} #{orderOperands(operands[1].x86Operand(kind), operands[2].x86Operand(kind))}" | 
|  | end | 
|  | else | 
|  | $asm.puts "#{opcode} #{orderOperands(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].x86GPR == "ecx" | 
|  | $asm.puts "#{opcode} #{orderOperands(operands[0].x86Operand(:byte), operands[1].x86Operand(kind))}" | 
|  | else | 
|  | $asm.puts "xchg#{x86Suffix(:ptr)} #{operands[0].x86Operand(:ptr)}, #{x86GPRName("ecx", :ptr)}" | 
|  | $asm.puts "#{opcode} #{orderOperands(register("cl"), operands[1].x86Operand(kind))}" | 
|  | $asm.puts "xchg#{x86Suffix(:ptr)} #{operands[0].x86Operand(:ptr)}, #{x86GPRName("ecx", :ptr)}" | 
|  | end | 
|  | end | 
|  |  | 
|  | def handleX86FPBranch(kind, branchOpcode, mode) | 
|  | case mode | 
|  | when :normal | 
|  | $asm.puts "ucomi#{x86Suffix(kind)} #{orderOperands(operands[1].x86Operand(:double), operands[0].x86Operand(:double))}" | 
|  | when :reverse | 
|  | $asm.puts "ucomi#{x86Suffix(kind)} #{orderOperands(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)} #{orderOperands(operands[1].x86Operand(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)}  #{orderOperands(operands[0].x86Operand(kind), operands[0].x86Operand(kind))}" | 
|  | else | 
|  | $asm.puts "cmp#{x86Suffix(kind)} #{orderOperands(operands[1].x86Operand(kind), operands[0].x86Operand(kind))}" | 
|  | end | 
|  | 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)} #{orderOperands(operands[1].x86Operand(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)}  #{orderOperands(operands[0].x86Operand(kind), operands[0].x86Operand(kind))}" | 
|  | else | 
|  | $asm.puts "cmp#{x86Suffix(kind)} #{orderOperands(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)}" | 
|  | if !isIntelSyntax | 
|  | $asm.puts "movzbl #{orderOperands(operand.x86Operand(:byte), operand.x86Operand(:int))}" | 
|  | else | 
|  | $asm.puts "movzx #{orderOperands(operand.x86Operand(:byte), operand.x86Operand(:int))}" | 
|  | end | 
|  | else | 
|  | ax = RegisterID.new(nil, "r0") | 
|  | $asm.puts "xchg#{x86Suffix(:ptr)} #{operand.x86Operand(:ptr)}, #{ax.x86Operand(:ptr)}" | 
|  | $asm.puts "#{setOpcode} #{ax.x86Operand(:byte)}" | 
|  | if !isIntelSyntax | 
|  | $asm.puts "movzbl #{ax.x86Operand(:byte)}, #{ax.x86Operand(:int)}" | 
|  | else | 
|  | $asm.puts "movzx #{ax.x86Operand(:int)}, #{ax.x86Operand(:byte)}" | 
|  | end | 
|  | $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 handleX86FPCompareSet(kind, setOpcode, order = :normal) | 
|  | is_special = setOpcode.is_a? Symbol | 
|  | left = operands[0] | 
|  | right = operands[1] | 
|  | target = operands[2] | 
|  |  | 
|  | compare = lambda do |lhs, rhs| | 
|  | $asm.puts "ucomi#{x86Suffix(kind)} #{orderOperands(lhs.x86Operand(:double), rhs.x86Operand(:double))}" | 
|  | end | 
|  |  | 
|  | if is_special | 
|  | case setOpcode | 
|  | when :eq | 
|  | if left == right | 
|  | compare.call(right, left) | 
|  | handleX86Set("setnp", operands[2]) | 
|  | return | 
|  | end | 
|  |  | 
|  | isUnordered = LocalLabel.unique("isUnordered") | 
|  | $asm.puts "movq $0, #{target.x86Operand(:quad)}" | 
|  | compare.call(right, left) | 
|  | $asm.puts "jp #{LocalLabelReference.new(codeOrigin, isUnordered).asmLabel}" | 
|  | handleX86Set("sete", target) | 
|  | isUnordered.lower($activeBackend) | 
|  | return | 
|  | when :nequn | 
|  | if left == right | 
|  | compare.call(right, left) | 
|  | handleX86Set("setp", target) | 
|  | return | 
|  | end | 
|  |  | 
|  | isUnordered = LocalLabel.unique("isUnordered") | 
|  | $asm.puts "movq $1, #{target.x86Operand(:quad)}" | 
|  | compare.call(right, left); | 
|  | $asm.puts "jp #{LocalLabelReference.new(codeOrigin, isUnordered).asmLabel}" | 
|  | handleX86Set("setne", target) | 
|  | isUnordered.lower($activeBackend) | 
|  | return | 
|  | else | 
|  | raise "Uhandled special opcode: #{setOpcode}" | 
|  | end | 
|  | end | 
|  |  | 
|  | if order == :normal | 
|  | compare.call(right, left) | 
|  | else | 
|  | compare.call(left, right) | 
|  | end | 
|  | handleX86Set(setOpcode, target) | 
|  | 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)} #{orderOperands(const(0), value.x86Operand(kind))}" | 
|  | end | 
|  | else | 
|  | $asm.puts "test#{x86Suffix(kind)} #{orderOperands(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)} #{orderOperands(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)} #{orderOperands(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 | 
|  | if operands[1] != operands[2] | 
|  | $asm.puts "mov#{x86Suffix(kind)} #{orderOperands(operands[1].x86Operand(kind), operands[2].x86Operand(kind))}" | 
|  | end | 
|  | else | 
|  | $asm.puts "lea#{x86Suffix(kind)} #{orderOperands(offsetRegister(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)} #{orderOperands(operands[1].x86Operand(kind), operands[2].x86Operand(kind))}" | 
|  | else | 
|  | if !isIntelSyntax | 
|  | $asm.puts "lea#{x86Suffix(kind)} (#{operands[0].x86Operand(kind)}, #{operands[1].x86Operand(kind)}), #{operands[2].x86Operand(kind)}" | 
|  | else | 
|  | $asm.puts "lea#{x86Suffix(kind)} #{operands[2].x86Operand(kind)}, [#{operands[0].x86Operand(kind)} + #{operands[1].x86Operand(kind)}]" | 
|  | end | 
|  | 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 | 
|  | if Immediate.new(nil, 0) == operands[1] | 
|  | raise unless operands[0].is_a? RegisterID | 
|  | raise unless operands[2].is_a? RegisterID | 
|  | if operands[0] != operands[2] | 
|  | $asm.puts "mov#{x86Suffix(kind)} #{orderOperands(operands[0].x86Operand(kind), operands[2].x86Operand(kind))}" | 
|  | end | 
|  | return | 
|  | end | 
|  | if operands[1] == operands[2] | 
|  | $asm.puts "neg#{x86Suffix(kind)} #{operands[2].x86Operand(kind)}" | 
|  | if Immediate.new(nil, 0) != operands[0] | 
|  | $asm.puts "add#{x86Suffix(kind)} #{orderOperands(operands[0].x86Operand(kind), operands[2].x86Operand(kind))}" | 
|  | end | 
|  | return | 
|  | end | 
|  | end | 
|  |  | 
|  | if operands.size == 2 | 
|  | if Immediate.new(nil, 0) == operands[0] | 
|  | return | 
|  | end | 
|  | end | 
|  |  | 
|  | handleX86Op("sub#{x86Suffix(kind)}", kind) | 
|  | end | 
|  |  | 
|  | def handleX86Mul(kind) | 
|  | if operands.size == 3 and operands[0].is_a? Immediate | 
|  | $asm.puts "imul#{x86Suffix(kind)} #{x86Operands(kind, kind, kind)}" | 
|  | return | 
|  | end | 
|  |  | 
|  | if operands.size == 2 and operands[0].is_a? Immediate | 
|  | imm = operands[0].value | 
|  | if imm > 0 and isPowerOfTwo(imm) | 
|  | $asm.puts "sal#{x86Suffix(kind)} #{orderOperands(Immediate.new(nil, Math.log2(imm).to_i).x86Operand(kind), operands[1].x86Operand(kind))}" | 
|  | return | 
|  | end | 
|  | end | 
|  |  | 
|  | handleX86Op("imul#{x86Suffix(kind)}", kind) | 
|  | end | 
|  |  | 
|  | def handleX86AddFP(kind) | 
|  | if operands.size == 2 | 
|  | $asm.puts "add#{x86Suffix(kind)} #{orderOperands(operands[0].x86Operand(kind), operands[1].x86Operand(kind))}" | 
|  | elsif operands.size == 3 | 
|  | $asm.puts "vadd#{x86Suffix(kind)} #{orderOperands(operands[1].x86Operand(kind), operands[0].x86Operand(kind), operands[2].x86Operand(kind))}" | 
|  | else | 
|  | raise "Unexpected number of operands for floating point addition: #{operands.size}" | 
|  | end | 
|  | end | 
|  |  | 
|  | def handleX86SubFP(kind) | 
|  | if operands.size == 2 | 
|  | $asm.puts "sub#{x86Suffix(kind)} #{orderOperands(operands[0].x86Operand(kind), operands[1].x86Operand(kind))}" | 
|  | elsif operands.size == 3 | 
|  | $asm.puts "vsub#{x86Suffix(kind)} #{orderOperands(operands[1].x86Operand(kind), operands[0].x86Operand(kind), operands[2].x86Operand(kind))}" | 
|  | else | 
|  | raise "Unexpected number of operands for floating point addition: #{operands.size}" | 
|  | end | 
|  | end | 
|  |  | 
|  | def handleX86MulFP(kind) | 
|  | if operands.size == 2 | 
|  | $asm.puts "mul#{x86Suffix(kind)} #{orderOperands(operands[0].x86Operand(kind), operands[1].x86Operand(kind))}" | 
|  | elsif operands.size == 3 | 
|  | $asm.puts "vmul#{x86Suffix(kind)} #{orderOperands(operands[1].x86Operand(kind), operands[0].x86Operand(kind), operands[2].x86Operand(kind))}" | 
|  | else | 
|  | raise "Unexpected number of operands for floating point addition: #{operands.size}" | 
|  | end | 
|  | end | 
|  |  | 
|  | def handleX86DivFP(kind) | 
|  | if operands.size == 2 | 
|  | $asm.puts "div#{x86Suffix(kind)} #{orderOperands(operands[0].x86Operand(kind), operands[1].x86Operand(kind))}" | 
|  | elsif operands.size == 3 | 
|  | $asm.puts "vdiv#{x86Suffix(kind)} #{orderOperands(operands[1].x86Operand(kind), operands[0].x86Operand(kind), operands[2].x86Operand(kind))}" | 
|  | else | 
|  | raise "Unexpected number of operands for floating point addition: #{operands.size}" | 
|  | end | 
|  | end | 
|  |  | 
|  | def handleX86Peek() | 
|  | sp = RegisterID.new(nil, "sp") | 
|  | opA = offsetRegister(operands[0].value * x86Bytes(:ptr), sp.x86Operand(:ptr)) | 
|  | opB = operands[1].x86Operand(:ptr) | 
|  | $asm.puts "mov#{x86Suffix(:ptr)} #{orderOperands(opA, opB)}" | 
|  | end | 
|  |  | 
|  | def handleX86Poke() | 
|  | sp = RegisterID.new(nil, "sp") | 
|  | opA = operands[0].x86Operand(:ptr) | 
|  | opB = offsetRegister(operands[1].value * x86Bytes(:ptr), sp.x86Operand(:ptr)) | 
|  | $asm.puts "mov#{x86Suffix(:ptr)} #{orderOperands(opA, opB)}" | 
|  | 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 countLeadingZeros(kind) | 
|  | target = operands[1] | 
|  | srcIsNonZero = LocalLabel.unique("srcIsNonZero") | 
|  | skipNonZeroCase = LocalLabel.unique("skipNonZeroCase") | 
|  | zeroValue = Immediate.new(codeOrigin, x86Bytes(kind) * 8) | 
|  | xorValue = Immediate.new(codeOrigin, kind == :quad ? 0x3f : 0x1f) | 
|  | xor = kind == :quad ? "xorq" : "xori" | 
|  |  | 
|  | $asm.puts "bsr#{x86Suffix(kind)} #{x86Operands(kind, kind)}" | 
|  |  | 
|  | Sequence.new(codeOrigin, [ | 
|  | Instruction.new(codeOrigin, "bnz", [LocalLabelReference.new(codeOrigin, srcIsNonZero)]), | 
|  | Instruction.new(codeOrigin, "move", [zeroValue, target]), | 
|  | Instruction.new(codeOrigin, "jmp", [LocalLabelReference.new(codeOrigin, skipNonZeroCase)]), | 
|  |  | 
|  | srcIsNonZero, | 
|  | Instruction.new(codeOrigin, xor, [xorValue, target]), | 
|  |  | 
|  | skipNonZeroCase, | 
|  | ]).lower($activeBackend) | 
|  | end | 
|  |  | 
|  | def countTrailingZeros(kind) | 
|  | target = operands[1] | 
|  | srcIsNonZero = LocalLabel.unique("srcIsNonZero") | 
|  | zeroValue = Immediate.new(codeOrigin, x86Bytes(kind) * 8) | 
|  |  | 
|  | $asm.puts "bsf#{x86Suffix(kind)} #{x86Operands(kind, kind)}" | 
|  |  | 
|  | Sequence.new(codeOrigin, [ | 
|  | Instruction.new(codeOrigin, "bnz", [LocalLabelReference.new(codeOrigin, srcIsNonZero)]), | 
|  | Instruction.new(codeOrigin, "move", [zeroValue, target]), | 
|  | srcIsNonZero, | 
|  | ]).lower($activeBackend) | 
|  | end | 
|  |  | 
|  | def truncateFloatingPointToQuad(kind) | 
|  | src = operands[0] | 
|  | dst = operands[1] | 
|  | slow = LocalLabel.unique("slow") | 
|  | done = LocalLabel.unique("done") | 
|  | gprScratch = X64_SCRATCH_REGISTER | 
|  | fprScratch = FPRegisterID.forName(codeOrigin, "wfa7") | 
|  | int64SignBit = Immediate.new(codeOrigin, 0x8000000000000000) | 
|  | case kind | 
|  | when :float | 
|  | int64Min = Immediate.new(codeOrigin, 0xdf000000) | 
|  | negInt64Min = Immediate.new(codeOrigin, 0x5f000000) | 
|  | integerSuffix = "i" | 
|  | floatingSuffix = "f" | 
|  | when :double | 
|  | int64Min = Immediate.new(codeOrigin, 0xc3e0000000000000) | 
|  | negInt64Min = Immediate.new(codeOrigin, 0x43e0000000000000) | 
|  | integerSuffix = "q" | 
|  | floatingSuffix = "d" | 
|  | else | 
|  | raise | 
|  | end | 
|  |  | 
|  | Sequence.new(codeOrigin, [ | 
|  | Instruction.new(codeOrigin, "move", [negInt64Min, gprScratch]), | 
|  | Instruction.new(codeOrigin, "f#{integerSuffix}2#{floatingSuffix}", [gprScratch, fprScratch]), | 
|  | Instruction.new(codeOrigin, "b#{floatingSuffix}gteq", [src, fprScratch, LocalLabelReference.new(codeOrigin, slow)]), | 
|  | Instruction.new(codeOrigin, "truncate#{floatingSuffix}2qs", [src, dst]), | 
|  | Instruction.new(codeOrigin, "jmp", [LocalLabelReference.new(codeOrigin, done)]), | 
|  |  | 
|  | slow, | 
|  | Instruction.new(codeOrigin, "move", [int64Min, gprScratch]), | 
|  | Instruction.new(codeOrigin, "f#{integerSuffix}2#{floatingSuffix}", [gprScratch, fprScratch]), | 
|  | Instruction.new(codeOrigin, "add#{floatingSuffix}", [src, fprScratch]), | 
|  | Instruction.new(codeOrigin, "truncate#{floatingSuffix}2qs", [fprScratch, dst]), | 
|  | Instruction.new(codeOrigin, "move", [int64SignBit, gprScratch]), | 
|  | Instruction.new(codeOrigin, "orq", [gprScratch, dst]), | 
|  |  | 
|  | done, | 
|  | ]).lower($activeBackend) | 
|  | end | 
|  |  | 
|  | def convertQuadToFloatingPoint(kind) | 
|  | src = operands[0] | 
|  | scratch1 = operands[1] | 
|  | dst = operands[2] | 
|  | slow = LocalLabel.unique("slow") | 
|  | done = LocalLabel.unique("done") | 
|  | scratch2 = X64_SCRATCH_REGISTER | 
|  | one = Immediate.new(codeOrigin, 0x1) | 
|  |  | 
|  | case kind | 
|  | when :float | 
|  | floatingSuffix = "f" | 
|  | when :double | 
|  | floatingSuffix = "d" | 
|  | else | 
|  | raise | 
|  | end | 
|  |  | 
|  | Sequence.new(codeOrigin, [ | 
|  | Instruction.new(codeOrigin, "btqs", [src, LocalLabelReference.new(codeOrigin, slow)]), | 
|  | Instruction.new(codeOrigin, "cq2#{floatingSuffix}s", [src, dst]), | 
|  | Instruction.new(codeOrigin, "jmp", [LocalLabelReference.new(codeOrigin, done)]), | 
|  |  | 
|  | slow, | 
|  | Instruction.new(codeOrigin, "move", [src, scratch1]), | 
|  | Instruction.new(codeOrigin, "move", [src, scratch2]), | 
|  | Instruction.new(codeOrigin, "urshiftq", [one, scratch1]), | 
|  | Instruction.new(codeOrigin, "andq", [one, scratch2]), | 
|  | Instruction.new(codeOrigin, "orq", [scratch1, scratch2]), | 
|  | Instruction.new(codeOrigin, "cq2#{floatingSuffix}s", [scratch2, dst]), | 
|  | Instruction.new(codeOrigin, "add#{floatingSuffix}", [dst, dst]), | 
|  |  | 
|  | done, | 
|  | ]).lower($activeBackend) | 
|  | end | 
|  |  | 
|  | def lowerX86 | 
|  | raise unless $activeBackend == "X86" | 
|  | lowerX86Common | 
|  | end | 
|  |  | 
|  | def lowerX86_WIN | 
|  | raise unless $activeBackend == "X86_WIN" | 
|  | lowerX86Common | 
|  | end | 
|  |  | 
|  | def lowerX86_64 | 
|  | raise unless $activeBackend == "X86_64" | 
|  | lowerX86Common | 
|  | end | 
|  |  | 
|  | def lowerX86_64_WIN | 
|  | raise unless $activeBackend == "X86_64_WIN" | 
|  | lowerX86Common | 
|  | end | 
|  |  | 
|  | def lowerX86Common | 
|  | case opcode | 
|  | when "addi" | 
|  | handleX86Add(:int) | 
|  | when "addp" | 
|  | handleX86Add(:ptr) | 
|  | when "addq" | 
|  | handleX86Add(:quad) | 
|  | when "andi" | 
|  | handleX86Op("and#{x86Suffix(:int)}", :int) | 
|  | when "andp" | 
|  | handleX86Op("and#{x86Suffix(:ptr)}", :ptr) | 
|  | when "andq" | 
|  | handleX86Op("and#{x86Suffix(:quad)}", :quad) | 
|  | when "andf" | 
|  | handleX86Op("andps", :float) | 
|  | when "andd" | 
|  | handleX86Op("andpd", :double) | 
|  | when "lshifti" | 
|  | handleX86Shift("sal#{x86Suffix(:int)}", :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 "neg#{x86Suffix(:int)} #{x86Operands(:int)}" | 
|  | when "negp" | 
|  | $asm.puts "neg#{x86Suffix(:ptr)} #{x86Operands(:ptr)}" | 
|  | when "negq" | 
|  | $asm.puts "neg#{x86Suffix(:quad)} #{x86Operands(:quad)}" | 
|  | when "noti" | 
|  | $asm.puts "not#{x86Suffix(:int)} #{x86Operands(:int)}" | 
|  | when "ori" | 
|  | handleX86Op("or#{x86Suffix(:int)}", :int) | 
|  | when "orp" | 
|  | handleX86Op("or#{x86Suffix(:ptr)}", :ptr) | 
|  | when "orq" | 
|  | handleX86Op("or#{x86Suffix(:quad)}", :quad) | 
|  | when "orf" | 
|  | handleX86Op("orps", :float) | 
|  | when "ord" | 
|  | handleX86Op("orpd", :double) | 
|  | when "orh" | 
|  | handleX86Op("or#{x86Suffix(:half)}", :half) | 
|  | when "rshifti" | 
|  | handleX86Shift("sar#{x86Suffix(:int)}", :int) | 
|  | when "rshiftp" | 
|  | handleX86Shift("sar#{x86Suffix(:ptr)}", :ptr) | 
|  | when "rshiftq" | 
|  | handleX86Shift("sar#{x86Suffix(:quad)}", :quad) | 
|  | when "urshifti" | 
|  | handleX86Shift("shr#{x86Suffix(:int)}", :int) | 
|  | when "urshiftp" | 
|  | handleX86Shift("shr#{x86Suffix(:ptr)}", :ptr) | 
|  | when "urshiftq" | 
|  | handleX86Shift("shr#{x86Suffix(:quad)}", :quad) | 
|  | when "rrotatei" | 
|  | handleX86Shift("ror#{x86Suffix(:int)}", :int) | 
|  | when "rrotateq" | 
|  | handleX86Shift("ror#{x86Suffix(:quad)}", :quad) | 
|  | when "lrotatei" | 
|  | handleX86Shift("rol#{x86Suffix(:int)}", :int) | 
|  | when "lrotateq" | 
|  | handleX86Shift("rol#{x86Suffix(:quad)}", :quad) | 
|  | when "subi" | 
|  | handleX86Sub(:int) | 
|  | when "subp" | 
|  | handleX86Sub(:ptr) | 
|  | when "subq" | 
|  | handleX86Sub(:quad) | 
|  | when "xori" | 
|  | handleX86Op("xor#{x86Suffix(:int)}", :int) | 
|  | when "xorp" | 
|  | handleX86Op("xor#{x86Suffix(:ptr)}", :ptr) | 
|  | when "xorq" | 
|  | handleX86Op("xor#{x86Suffix(:quad)}", :quad) | 
|  | when "leap" | 
|  | emitX86Lea(operands[0], operands[1], :ptr) | 
|  | when "loadi" | 
|  | $asm.puts "mov#{x86Suffix(:int)} #{x86LoadOperands(:int, :int)}" | 
|  | when "storei" | 
|  | $asm.puts "mov#{x86Suffix(:int)} #{x86Operands(:int, :int)}" | 
|  | when "loadis" | 
|  | if isX64 | 
|  | if !isIntelSyntax | 
|  | $asm.puts "movslq #{x86LoadOperands(:int, :quad)}" | 
|  | else | 
|  | $asm.puts "movsxd #{x86LoadOperands(:int, :quad)}" | 
|  | end | 
|  | else | 
|  | $asm.puts "mov#{x86Suffix(:int)} #{x86LoadOperands(:int, :int)}" | 
|  | end | 
|  | when "loadp" | 
|  | $asm.puts "mov#{x86Suffix(:ptr)} #{x86LoadOperands(:ptr, :ptr)}" | 
|  | when "storep" | 
|  | $asm.puts "mov#{x86Suffix(:ptr)} #{x86Operands(:ptr, :ptr)}" | 
|  | when "loadq" | 
|  | $asm.puts "mov#{x86Suffix(:quad)} #{x86LoadOperands(:quad, :quad)}" | 
|  | when "storeq" | 
|  | $asm.puts "mov#{x86Suffix(:quad)} #{x86Operands(:quad, :quad)}" | 
|  | when "loadb" | 
|  | if !isIntelSyntax | 
|  | $asm.puts "movzbl #{x86LoadOperands(:byte, :int)}" | 
|  | else | 
|  | $asm.puts "movzx #{x86LoadOperands(:byte, :int)}" | 
|  | end | 
|  | when "loadbsi" | 
|  | if !isIntelSyntax | 
|  | $asm.puts "movsbl #{x86LoadOperands(:byte, :int)}" | 
|  | else | 
|  | $asm.puts "movsx #{x86LoadOperands(:byte, :int)}" | 
|  | end | 
|  | when "loadbsq" | 
|  | if !isIntelSyntax | 
|  | $asm.puts "movsbq #{x86LoadOperands(:byte, :quad)}" | 
|  | else | 
|  | $asm.puts "movsx #{x86LoadOperands(:byte, :quad)}" | 
|  | end | 
|  | when "loadh" | 
|  | if !isIntelSyntax | 
|  | $asm.puts "movzwl #{x86LoadOperands(:half, :int)}" | 
|  | else | 
|  | $asm.puts "movzx #{x86LoadOperands(:half, :int)}" | 
|  | end | 
|  | when "loadhsi" | 
|  | if !isIntelSyntax | 
|  | $asm.puts "movswl #{x86LoadOperands(:half, :int)}" | 
|  | else | 
|  | $asm.puts "movsx #{x86LoadOperands(:half, :int)}" | 
|  | end | 
|  | when "loadhsq" | 
|  | if !isIntelSyntax | 
|  | $asm.puts "movswq #{x86LoadOperands(:half, :quad)}" | 
|  | else | 
|  | $asm.puts "movsx #{x86LoadOperands(:half, :quad)}" | 
|  | end | 
|  | when "storeb" | 
|  | $asm.puts "mov#{x86Suffix(:byte)} #{x86Operands(:byte, :byte)}" | 
|  | when "storeh" | 
|  | $asm.puts "mov#{x86Suffix(:half)} #{x86Operands(:half, :half)}" | 
|  | when "loadf" | 
|  | $asm.puts "movss #{x86Operands(:float, :float)}" | 
|  | when "loadd" | 
|  | $asm.puts "movsd #{x86Operands(:double, :double)}" | 
|  | when "moved" | 
|  | $asm.puts "movsd #{x86Operands(:double, :double)}" | 
|  | when "storef" | 
|  | $asm.puts "movss #{x86Operands(:float, :float)}" | 
|  | when "stored" | 
|  | $asm.puts "movsd #{x86Operands(:double, :double)}" | 
|  | when "addf" | 
|  | handleX86AddFP(:float) | 
|  | when "addd" | 
|  | handleX86AddFP(:double) | 
|  | when "mulf" | 
|  | handleX86MulFP(:float) | 
|  | when "muld" | 
|  | handleX86MulFP(:double) | 
|  | when "subf" | 
|  | handleX86SubFP(:float) | 
|  | when "subd" | 
|  | handleX86SubFP(:double) | 
|  | when "divf" | 
|  | handleX86DivFP(:float) | 
|  | when "divd" | 
|  | handleX86DivFP(:double) | 
|  | when "sqrtf" | 
|  | $asm.puts "sqrtss #{operands[0].x86Operand(:float)}, #{operands[1].x86Operand(:float)}" | 
|  | when "sqrtd" | 
|  | $asm.puts "sqrtsd #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:double)}" | 
|  | when "roundf" | 
|  | $asm.puts "roundss $0, #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:double)}" | 
|  | when "roundd" | 
|  | $asm.puts "roundsd $0, #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:double)}" | 
|  | when "floorf" | 
|  | $asm.puts "roundss $1, #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:double)}" | 
|  | when "floord" | 
|  | $asm.puts "roundsd $1, #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:double)}" | 
|  | when "ceilf" | 
|  | $asm.puts "roundss $2, #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:double)}" | 
|  | when "ceild" | 
|  | $asm.puts "roundsd $2, #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:double)}" | 
|  | when "truncatef" | 
|  | $asm.puts "roundss $3, #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:double)}" | 
|  | when "truncated" | 
|  | $asm.puts "roundsd $3, #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:double)}" | 
|  | when "truncatef2i" | 
|  | $asm.puts "cvttss2si #{operands[0].x86Operand(:float)}, #{operands[1].x86Operand(:quad)}" | 
|  | when "truncated2i" | 
|  | $asm.puts "cvttsd2si #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:quad)}" | 
|  | when "truncatef2q" | 
|  | truncateFloatingPointToQuad(:float) | 
|  | when "truncated2q" | 
|  | truncateFloatingPointToQuad(:double) | 
|  | when "truncatef2is" | 
|  | $asm.puts "cvttss2si #{operands[0].x86Operand(:float)}, #{operands[1].x86Operand(:int)}" | 
|  | when "truncatef2qs" | 
|  | $asm.puts "cvttss2si #{operands[0].x86Operand(:float)}, #{operands[1].x86Operand(:quad)}" | 
|  | when "truncated2is" | 
|  | $asm.puts "cvttsd2si #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:int)}" | 
|  | when "truncated2qs" | 
|  | $asm.puts "cvttsd2si #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:quad)}" | 
|  | when "ci2d" | 
|  | $asm.puts "cvtsi2sd #{orderOperands(operands[0].x86Operand(:quad), operands[1].x86Operand(:double))}" | 
|  | when "ci2ds" | 
|  | $asm.puts "cvtsi2sd #{orderOperands(operands[0].x86Operand(:int), operands[1].x86Operand(:double))}" | 
|  | when "ci2fs" | 
|  | $asm.puts "cvtsi2ss #{orderOperands(operands[0].x86Operand(:int), operands[1].x86Operand(:float))}" | 
|  | when "ci2f" | 
|  | $asm.puts "cvtsi2ss #{orderOperands(operands[0].x86Operand(:quad), operands[1].x86Operand(:float))}" | 
|  | when "cq2f" | 
|  | convertQuadToFloatingPoint(:float) | 
|  | when "cq2d" | 
|  | convertQuadToFloatingPoint(:double) | 
|  | when "cq2fs" | 
|  | $asm.puts "cvtsi2ssq #{orderOperands(operands[0].x86Operand(:quad), operands[1].x86Operand(:float))}" | 
|  | when "cq2ds" | 
|  | $asm.puts "cvtsi2sdq #{orderOperands(operands[0].x86Operand(:quad), operands[1].x86Operand(:double))}" | 
|  | when "cd2f" | 
|  | $asm.puts "cvtsd2ss #{x86Operands(:double, :float)}" | 
|  | when "cf2d" | 
|  | $asm.puts "cvtss2sd #{x86Operands(:float, :double)}" | 
|  | when "bdeq" | 
|  | $asm.puts "ucomisd #{orderOperands(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 #{LocalLabelReference.new(codeOrigin, isUnordered).asmLabel}" | 
|  | $asm.puts "je #{LocalLabelReference.new(codeOrigin, operands[2]).asmLabel}" | 
|  | isUnordered.lower($activeBackend) | 
|  | end | 
|  | when "bdneq" | 
|  | handleX86FPBranch(:double, "jne", :normal) | 
|  | when "bdgt" | 
|  | handleX86FPBranch(:double, "ja", :normal) | 
|  | when "bdgteq" | 
|  | handleX86FPBranch(:double, "jae", :normal) | 
|  | when "bdlt" | 
|  | handleX86FPBranch(:double, "ja", :reverse) | 
|  | when "bdlteq" | 
|  | handleX86FPBranch(:double, "jae", :reverse) | 
|  | when "bdequn" | 
|  | handleX86FPBranch(:double, "je", :normal) | 
|  | when "bdnequn" | 
|  | $asm.puts "ucomisd #{orderOperands(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 #{LocalLabelReference.new(codeOrigin, isUnordered).asmLabel}" | 
|  | $asm.puts "je #{LocalLabelReference.new(codeOrigin, isEqual).asmLabel}" | 
|  | isUnordered.lower($activeBackend) | 
|  | $asm.puts "jmp #{operands[2].asmLabel}" | 
|  | isEqual.lower($activeBackend) | 
|  | end | 
|  | when "bdgtun" | 
|  | handleX86FPBranch(:double, "jb", :reverse) | 
|  | when "bdgtequn" | 
|  | handleX86FPBranch(:double, "jbe", :reverse) | 
|  | when "bdltun" | 
|  | handleX86FPBranch(:double, "jb", :normal) | 
|  | when "bdltequn" | 
|  | handleX86FPBranch(:double, "jbe", :normal) | 
|  | when "bfeq" | 
|  | $asm.puts "ucomiss #{orderOperands(operands[0].x86Operand(:float), operands[1].x86Operand(:float))}" | 
|  | 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("bfeq") | 
|  | $asm.puts "jp #{LocalLabelReference.new(codeOrigin, isUnordered).asmLabel}" | 
|  | $asm.puts "je #{LocalLabelReference.new(codeOrigin, operands[2]).asmLabel}" | 
|  | isUnordered.lower($activeBackend) | 
|  | end | 
|  | when "bfgt" | 
|  | handleX86FPBranch(:float, "ja", :normal) | 
|  | when "bfgteq" | 
|  | handleX86FPBranch(:float, "jae", :normal) | 
|  | when "bflt" | 
|  | handleX86FPBranch(:float, "ja", :reverse) | 
|  | when "bfgtun" | 
|  | handleX86FPBranch(:float, "jb", :reverse) | 
|  | when "bfgtequn" | 
|  | handleX86FPBranch(:float, "jbe", :reverse) | 
|  | when "bfltun" | 
|  | handleX86FPBranch(:float, "jb", :normal) | 
|  | when "bfltequn" | 
|  | handleX86FPBranch(:float, "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 "test#{x86Suffix(:int)} #{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" | 
|  | operands.each { | 
|  | | op | | 
|  | $asm.puts "pop #{op.x86Operand(:ptr)}" | 
|  | } | 
|  | when "push" | 
|  | operands.each { | 
|  | | op | | 
|  | $asm.puts "push #{op.x86Operand(:ptr)}" | 
|  | } | 
|  | when "move" | 
|  | handleMove | 
|  | when "sxi2q" | 
|  | if !isIntelSyntax | 
|  | $asm.puts "movslq #{operands[0].x86Operand(:int)}, #{operands[1].x86Operand(:quad)}" | 
|  | else | 
|  | $asm.puts "movsxd #{orderOperands(operands[0].x86Operand(:int), operands[1].x86Operand(:quad))}" | 
|  | end | 
|  | when "zxi2q" | 
|  | $asm.puts "mov#{x86Suffix(:int)} #{orderOperands(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("add#{x86Suffix(:int)}", "jo", :int) | 
|  | when "baddpo" | 
|  | handleX86OpBranch("add#{x86Suffix(:ptr)}", "jo", :ptr) | 
|  | when "baddqo" | 
|  | handleX86OpBranch("add#{x86Suffix(:quad)}", "jo", :quad) | 
|  | when "baddis" | 
|  | handleX86OpBranch("add#{x86Suffix(:int)}", "js", :int) | 
|  | when "baddps" | 
|  | handleX86OpBranch("add#{x86Suffix(:ptr)}", "js", :ptr) | 
|  | when "baddqs" | 
|  | handleX86OpBranch("add#{x86Suffix(:quad)}", "js", :quad) | 
|  | when "baddiz" | 
|  | handleX86OpBranch("add#{x86Suffix(:int)}", "jz", :int) | 
|  | when "baddpz" | 
|  | handleX86OpBranch("add#{x86Suffix(:ptr)}", "jz", :ptr) | 
|  | when "baddqz" | 
|  | handleX86OpBranch("add#{x86Suffix(:quad)}", "jz", :quad) | 
|  | when "baddinz" | 
|  | handleX86OpBranch("add#{x86Suffix(:int)}", "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("imul#{x86Suffix(:int)}", "jo", :int) | 
|  | when "bmulis" | 
|  | handleX86OpBranch("imul#{x86Suffix(:int)}", "js", :int) | 
|  | when "bmuliz" | 
|  | handleX86OpBranch("imul#{x86Suffix(:int)}", "jz", :int) | 
|  | when "bmulinz" | 
|  | handleX86OpBranch("imul#{x86Suffix(:int)}", "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 #{const(3)}" | 
|  | when "call" | 
|  | op = operands[0].x86CallOperand(:ptr) | 
|  | if operands[0].is_a? LabelReference | 
|  | operands[0].used | 
|  | end | 
|  | $asm.puts "call #{op}" | 
|  | 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 "cfeq" | 
|  | handleX86FPCompareSet(:float, :eq) | 
|  | when "cdeq" | 
|  | handleX86FPCompareSet(:double, :eq) | 
|  | when "cfneq" | 
|  | handleX86FPCompareSet(:float, "setne") | 
|  | when "cdneq" | 
|  | handleX86FPCompareSet(:double, "setne") | 
|  | when "cfnequn" | 
|  | handleX86FPCompareSet(:float, :nequn) | 
|  | when "cdnequn" | 
|  | handleX86FPCompareSet(:double, :nequn) | 
|  | when "cfgt" | 
|  | handleX86FPCompareSet(:float, "seta") | 
|  | when "cdgt" | 
|  | handleX86FPCompareSet(:double, "seta") | 
|  | when "cfgteq" | 
|  | handleX86FPCompareSet(:float, "setae") | 
|  | when "cdgteq" | 
|  | handleX86FPCompareSet(:double, "setae") | 
|  | when "cflt" | 
|  | handleX86FPCompareSet(:float, "seta", :reverse) | 
|  | when "cdlt" | 
|  | handleX86FPCompareSet(:double, "seta", :reverse) | 
|  | when "cflteq" | 
|  | handleX86FPCompareSet(:float, "setae", :reverse) | 
|  | when "cdlteq" | 
|  | handleX86FPCompareSet(:double, "setae", :reverse) | 
|  | 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" | 
|  | handleX86Peek() | 
|  | when "poke" | 
|  | handleX86Poke() | 
|  | when "cdqi" | 
|  | $asm.puts "cdq" | 
|  | when "cqoq" | 
|  | $asm.puts "cqo" | 
|  | when "idivi" | 
|  | $asm.puts "idiv#{x86Suffix(:int)} #{operands[0].x86Operand(:int)}" | 
|  | when "udivi" | 
|  | $asm.puts "div#{x86Suffix(:int)} #{operands[0].x86Operand(:int)}" | 
|  | when "idivq" | 
|  | $asm.puts "idiv#{x86Suffix(:quad)} #{operands[0].x86Operand(:quad)}" | 
|  | when "udivq" | 
|  | $asm.puts "div#{x86Suffix(:quad)} #{operands[0].x86Operand(:quad)}" | 
|  | when "popcnti" | 
|  | $asm.puts "popcnt#{x86Suffix(:int)} #{x86Operands(:int, :int)}" | 
|  | when "popcntq" | 
|  | $asm.puts "popcnt#{x86Suffix(:quad)} #{x86Operands(:quad, :quad)}" | 
|  | when "tzcnti" | 
|  | countTrailingZeros(:int) | 
|  | when "tzcntq" | 
|  | countTrailingZeros(:quad) | 
|  | when "lzcnti" | 
|  | countLeadingZeros(:int) | 
|  | when "lzcntq" | 
|  | countLeadingZeros(:quad) | 
|  | 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" | 
|  | if !isIntelSyntax | 
|  | $asm.puts "movq #{operands[0].x86Operand(:quad)}, #{operands[1].x86Operand(:double)}" | 
|  | else | 
|  | # MASM does not accept register operands with movq. | 
|  | # Debugging shows that movd actually moves a qword when using MASM. | 
|  | $asm.puts "movd #{operands[1].x86Operand(:double)}, #{operands[0].x86Operand(:quad)}" | 
|  | end | 
|  | when "fd2q" | 
|  | if !isIntelSyntax | 
|  | $asm.puts "movq #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:quad)}" | 
|  | else | 
|  | # MASM does not accept register operands with movq. | 
|  | # Debugging shows that movd actually moves a qword when using MASM. | 
|  | $asm.puts "movd #{operands[1].x86Operand(:quad)}, #{operands[0].x86Operand(:double)}" | 
|  | end | 
|  | when "fi2f" | 
|  | $asm.puts "movd #{x86Operands(:int, :float)}" | 
|  | when "ff2i" | 
|  | $asm.puts "movd #{x86Operands(:float, :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" | 
|  | $asm.puts "lea#{x86Suffix(:int)} #{orderOperands(operands[0].x86AddressOperand(:int), operands[1].x86Operand(:int))}" | 
|  | when "leap" | 
|  | $asm.puts "lea#{x86Suffix(:ptr)} #{orderOperands(operands[0].x86AddressOperand(:ptr), operands[1].x86Operand(:ptr))}" | 
|  | when "memfence" | 
|  | sp = RegisterID.new(nil, "sp") | 
|  | if isIntelSyntax | 
|  | $asm.puts "mfence" | 
|  | else | 
|  | $asm.puts "lock; orl $0, (#{sp.x86Operand(:ptr)})" | 
|  | end | 
|  | when "absf" | 
|  | $asm.puts "movl #{orderOperands("$0x80000000", X64_SCRATCH_REGISTER.x86Operand(:int))}" | 
|  | $asm.puts "movd #{orderOperands(X64_SCRATCH_REGISTER.x86Operand(:int), operands[1].x86Operand(:float))}" | 
|  | $asm.puts "andnps #{orderOperands(operands[0].x86Operand(:float), operands[1].x86Operand(:float))}" | 
|  | when "absd" | 
|  | $asm.puts "movq #{orderOperands("$0x8000000000000000", X64_SCRATCH_REGISTER.x86Operand(:quad))}" | 
|  | $asm.puts "movd #{orderOperands(X64_SCRATCH_REGISTER.x86Operand(:quad), operands[1].x86Operand(:double))}" | 
|  | $asm.puts "andnps #{orderOperands(operands[0].x86Operand(:double), operands[1].x86Operand(:double))}" | 
|  | when "negf" | 
|  | $asm.puts "movl #{orderOperands("$0x80000000", X64_SCRATCH_REGISTER.x86Operand(:int))}" | 
|  | $asm.puts "movd #{orderOperands(X64_SCRATCH_REGISTER.x86Operand(:int), operands[1].x86Operand(:float))}" | 
|  | $asm.puts "xorps #{orderOperands(operands[0].x86Operand(:float), operands[1].x86Operand(:float))}" | 
|  | when "negd" | 
|  | $asm.puts "movq #{orderOperands("$0x8000000000000000", X64_SCRATCH_REGISTER.x86Operand(:quad))}" | 
|  | $asm.puts "movd #{orderOperands(X64_SCRATCH_REGISTER.x86Operand(:quad), operands[1].x86Operand(:double))}" | 
|  | $asm.puts "xorpd #{orderOperands(operands[0].x86Operand(:double), operands[1].x86Operand(:double))}" | 
|  | when "tls_loadp" | 
|  | raise "tls_loadp is only supported on x64" unless isX64 | 
|  | if operands[0].immediate? | 
|  | mem = "%gs:#{operands[0].value * 8}" | 
|  | else | 
|  | mem = BaseIndex.new(codeOrigin, nil, operands[0], 8, "%gs:").x86AddressOperand(:quad) | 
|  | end | 
|  | $asm.puts "movq #{orderOperands(mem, operands[1].x86Operand(:quad))}" | 
|  | when "tls_loadp" | 
|  | raise "tls_loadp is only supported on x64" unless isX64 | 
|  | if operands[0].immediate? | 
|  | mem = "%gs:#{operands[0].value * x86Bytes(:ptr)}" | 
|  | else | 
|  | mem = BaseIndex.new(codeOrigin, nil, operands[0], x86Bytes(:ptr), "%gs:").x86AddressOperand(:quad) | 
|  | end | 
|  | $asm.puts "mov#{x86Suffix(:ptr)} #{orderOperands(mem, operands[1].x86Operand(:quad))}" | 
|  | when "tls_storep" | 
|  | raise "tls_loadp is only supported on x64" unless isX64 | 
|  | if operands[1].immediate? | 
|  | mem = "%gs:#{operands[1].value * x86Bytes(:ptr)}" | 
|  | else | 
|  | mem = BaseIndex.new(codeOrigin, nil, operands[1], x86Bytes(:ptr), "%gs:").x86AddressOperand(:ptr) | 
|  | end | 
|  | $asm.puts "mov#{x86Suffix(:ptr)} #{orderOperands(operands[0].x86Operand(:ptr), mem)}" | 
|  | else | 
|  | lowerDefault | 
|  | end | 
|  | end | 
|  | end | 
|  |  |