| # Copyright (C) 2012, 2014 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" |
| |
| 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 useX87 |
| case $activeBackend |
| when "X86" |
| true |
| when "X86_WIN" |
| true |
| when "X86_64" |
| false |
| when "X86_64_WIN" |
| false |
| else |
| raise "bad value for $activeBackend: #{$activeBackend}" |
| end |
| end |
| |
| def isWindows |
| ENV['OS'] == 'Windows_NT' |
| end |
| |
| def isGCC |
| !isWindows |
| end |
| |
| def isMSVC |
| isWindows |
| end |
| |
| def isIntelSyntax |
| isWindows |
| end |
| |
| def register(name) |
| isIntelSyntax ? name : "%" + name |
| end |
| |
| def offsetRegister(off, register) |
| isIntelSyntax ? "[#{off} + #{register}]" : "#{off}(#{register})" |
| end |
| |
| def callPrefix |
| isIntelSyntax ? "" : "*" |
| end |
| |
| def orderOperands(opA, opB) |
| isIntelSyntax ? "#{opB}, #{opA}" : "#{opA}, #{opB}" |
| 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 :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 |
| 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") |
| |
| class RegisterID |
| def supports8BitOnX86 |
| case name |
| when "t0", "a0", "r0", "t1", "a1", "r1", "t2", "t3", "t4", "t5" |
| true |
| when "cfr", "ttnr", "tmr" |
| false |
| when "t6" |
| isX64 |
| else |
| raise |
| end |
| end |
| |
| def x86Operand(kind) |
| case name |
| when "t0", "a0", "r0" |
| case kind |
| when :byte |
| register("al") |
| when :half |
| register("ax") |
| when :int |
| register("eax") |
| when :ptr |
| isX64 ? register("rax") : register("eax") |
| when :quad |
| isX64 ? register("rax") : raise |
| else |
| raise "Invalid kind #{kind} for name #{name}" |
| end |
| when "t1", "a1", "r1" |
| case kind |
| when :byte |
| register("dl") |
| when :half |
| register("dx") |
| when :int |
| register("edx") |
| when :ptr |
| isX64 ? register("rdx") : register("edx") |
| when :quad |
| isX64 ? register("rdx") : raise |
| else |
| raise |
| end |
| when "t2" |
| case kind |
| when :byte |
| register("cl") |
| when :half |
| register("cx") |
| when :int |
| register("ecx") |
| when :ptr |
| isX64 ? register("rcx") : register("ecx") |
| when :quad |
| isX64 ? register("rcx") : raise |
| else |
| raise |
| end |
| when "t3" |
| case kind |
| when :byte |
| register("bl") |
| when :half |
| register("bx") |
| when :int |
| register("ebx") |
| when :ptr |
| isX64 ? register("rbx") : register("ebx") |
| when :quad |
| isX64 ? register("rbx") : raise |
| else |
| raise |
| end |
| when "t4" |
| case kind |
| when :byte |
| register("dil") |
| when :half |
| register("di") |
| when :int |
| register("edi") |
| when :ptr |
| isX64 ? register("rdi") : register("edi") |
| when :quad |
| isX64 ? register("rdi") : raise |
| else |
| raise |
| end |
| when "cfr" |
| if isX64 |
| case kind |
| when :half |
| register("bp") |
| when :int |
| register("ebp") |
| when :ptr |
| register("rbp") |
| when :quad |
| register("rbp") |
| else |
| raise |
| end |
| else |
| case kind |
| when :half |
| register("bp") |
| when :int |
| register("ebp") |
| when :ptr |
| register("ebp") |
| else |
| raise |
| end |
| end |
| when "sp" |
| case kind |
| when :byte |
| register("spl") |
| when :half |
| register("sp") |
| when :int |
| register("esp") |
| when :ptr |
| isX64 ? register("rsp") : register("esp") |
| when :quad |
| isX64 ? register("rsp") : raise |
| else |
| raise |
| end |
| when "t5" |
| case kind |
| when :byte |
| register("sil") |
| when :half |
| register("si") |
| when :int |
| register("esi") |
| when :ptr |
| isX64 ? register("rsi") : register("esi") |
| when :quad |
| isX64 ? register("rsi") : raise |
| end |
| when "t6" |
| raise "Cannot use #{name} in 32-bit X86 at #{codeOriginString}" unless isX64 |
| case kind |
| when :half |
| register("r8w") |
| when :int |
| register("r8d") |
| when :ptr |
| register("r8") |
| when :quad |
| register("r8") |
| end |
| when "t7" |
| raise "Cannot use #{name} in 32-bit X86 at #{codeOriginString}" unless isX64 |
| case kind |
| when :half |
| register("r9w") |
| when :int |
| register("r9d") |
| when :ptr |
| register("r9") |
| when :quad |
| register("r9") |
| end |
| when "csr1" |
| raise "Cannot use #{name} in 32-bit X86 at #{codeOriginString}" unless isX64 |
| case kind |
| when :half |
| register("r14w") |
| when :int |
| register("r14d") |
| when :ptr |
| register("r14") |
| when :quad |
| register("r14") |
| end |
| when "csr2" |
| raise "Cannot use #{name} in 32-bit X86 at #{codeOriginString}" unless isX64 |
| case kind |
| when :half |
| register("r15w") |
| when :int |
| register("r15d") |
| when :ptr |
| register("r15") |
| when :quad |
| register("r15") |
| end |
| else |
| raise "Bad register #{name} for X86 at #{codeOriginString}" |
| end |
| end |
| def x86CallOperand(kind) |
| isX64 ? "#{callPrefix}#{x86Operand(:quad)}" : "#{callPrefix}#{x86Operand(:ptr)}" |
| end |
| end |
| |
| class FPRegisterID |
| def x86Operand(kind) |
| raise unless kind == :double |
| raise if useX87 |
| case name |
| when "ft0", "fa0", "fr" |
| register("xmm0") |
| when "ft1", "fa1" |
| register("xmm1") |
| when "ft2", "fa2" |
| register("xmm2") |
| when "ft3", "fa3" |
| register("xmm3") |
| when "ft4" |
| register("xmm4") |
| when "ft5" |
| register("xmm5") |
| else |
| raise "Bad register #{name} for X86 at #{codeOriginString}" |
| end |
| end |
| def x87DefaultStackPosition |
| case name |
| when "ft0", "fr" |
| 0 |
| when "ft1" |
| 1 |
| when "ft2", "ft3", "ft4", "ft5" |
| raise "Unimplemented register #{name} for X86 at #{codeOriginString}" |
| else |
| raise "Bad register #{name} for X86 at #{codeOriginString}" |
| end |
| end |
| def x87Operand(offset) |
| raise unless useX87 |
| raise unless offset == 0 or offset == 1 |
| "#{register("st")}(#{x87DefaultStackPosition + offset})" |
| 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)}, #{scale})" |
| else |
| "#{getSizeString(addressKind)}[#{offset.value} + #{base.x86Operand(addressKind)} + #{index.x86Operand(addressKind)} * #{scale}]" |
| end |
| end |
| |
| def x86Operand(kind) |
| if !isIntelSyntax |
| x86AddressOperand(:ptr) |
| else |
| "#{getSizeString(kind)}[#{offset.value} + #{base.x86Operand(:ptr)} + #{index.x86Operand(:ptr)} * #{scale}]" |
| 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 |
| 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 |
| @@floatingPointCompareImplicitOperand = isIntelSyntax ? "st(0), " : "" |
| |
| def x86Operands(*kinds) |
| raise 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 x86Suffix(kind) |
| if isIntelSyntax |
| return "" |
| end |
| |
| case kind |
| when :byte |
| "b" |
| when :half |
| "w" |
| when :int |
| "l" |
| when :ptr |
| isX64 ? "q" : "l" |
| when :quad |
| isX64 ? "q" : raise |
| when :double |
| not useX87 ? "sd" : raise |
| 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} #{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] == RegisterID.forName(nil, "t2") |
| $asm.puts "#{opcode} #{orderOperands(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} #{orderOperands(register("cl"), operands[1].x86Operand(kind))}" |
| $asm.puts "xchg#{x86Suffix(:ptr)} #{operands[0].x86Operand(:ptr)}, #{cx.x86Operand(:ptr)}" |
| end |
| end |
| |
| def handleX86DoubleBranch(branchOpcode, mode) |
| if useX87 |
| handleX87Compare(mode) |
| else |
| case mode |
| when :normal |
| $asm.puts "ucomisd #{orderOperands(operands[1].x86Operand(:double), operands[0].x86Operand(:double))}" |
| when :reverse |
| $asm.puts "ucomisd #{orderOperands(operands[0].x86Operand(:double), operands[1].x86Operand(:double))}" |
| else |
| raise mode.inspect |
| end |
| 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 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, "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)} #{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 |
| unless 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 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 |
| 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 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 handleX87Compare(mode) |
| case mode |
| when :normal |
| if (operands[0].x87DefaultStackPosition == 0) |
| $asm.puts "fucomi #{@@floatingPointCompareImplicitOperand}#{operands[1].x87Operand(0)}" |
| else |
| $asm.puts "fld #{operands[0].x87Operand(0)}" |
| $asm.puts "fucomip #{@@floatingPointCompareImplicitOperand}#{operands[1].x87Operand(1)}" |
| end |
| when :reverse |
| if (operands[1].x87DefaultStackPosition == 0) |
| $asm.puts "fucomi #{@@floatingPointCompareImplicitOperand}#{operands[0].x87Operand(0)}" |
| else |
| $asm.puts "fld #{operands[1].x87Operand(0)}" |
| $asm.puts "fucomip #{@@floatingPointCompareImplicitOperand}#{operands[0].x87Operand(1)}" |
| end |
| else |
| raise mode.inspect |
| end |
| end |
| |
| def handleX87BinOp(opcode, opcodereverse) |
| if (operands[1].x87DefaultStackPosition == 0) |
| $asm.puts "#{opcode} #{orderOperands(operands[0].x87Operand(0), register("st"))}" |
| elsif (operands[0].x87DefaultStackPosition == 0) |
| if !isIntelSyntax |
| $asm.puts "#{opcodereverse} #{register("st")}, #{operands[1].x87Operand(0)}" |
| else |
| $asm.puts "#{opcode} #{operands[1].x87Operand(0)}, #{register("st")}" |
| end |
| else |
| $asm.puts "fld #{operands[0].x87Operand(0)}" |
| $asm.puts "#{opcodereverse}p #{orderOperands(register("st"), operands[1].x87Operand(1))}" |
| end |
| 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 |
| $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("and#{x86Suffix(:int)}", :int) |
| when "andp" |
| handleX86Op("and#{x86Suffix(:ptr)}", :ptr) |
| when "andq" |
| handleX86Op("and#{x86Suffix(:quad)}", :quad) |
| 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 "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 "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 "loadi", "storei" |
| $asm.puts "mov#{x86Suffix(:int)} #{x86Operands(:int, :int)}" |
| when "loadis" |
| if isX64 |
| if !isIntelSyntax |
| $asm.puts "movslq #{x86Operands(:int, :quad)}" |
| else |
| $asm.puts "movsxd #{x86Operands(:int, :quad)}" |
| end |
| else |
| $asm.puts "mov#{x86Suffix(:int)} #{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" |
| if !isIntelSyntax |
| $asm.puts "movzbl #{orderOperands(operands[0].x86Operand(:byte), operands[1].x86Operand(:int))}" |
| else |
| $asm.puts "movzx #{orderOperands(operands[0].x86Operand(:byte), operands[1].x86Operand(:int))}" |
| end |
| when "loadbs" |
| $asm.puts "movsbl #{operands[0].x86Operand(:byte)}, #{operands[1].x86Operand(:int)}" |
| when "loadh" |
| if !isIntelSyntax |
| $asm.puts "movzwl #{orderOperands(operands[0].x86Operand(:half), operands[1].x86Operand(:int))}" |
| else |
| $asm.puts "movzx #{orderOperands(operands[0].x86Operand(:half), operands[1].x86Operand(:int))}" |
| end |
| when "loadhs" |
| $asm.puts "movswl #{operands[0].x86Operand(:half)}, #{operands[1].x86Operand(:int)}" |
| when "storeb" |
| $asm.puts "mov#{x86Suffix(:byte)} #{x86Operands(:byte, :byte)}" |
| when "loadd" |
| if useX87 |
| if !isIntelSyntax |
| $asm.puts "fldl #{operands[0].x86Operand(:double)}" |
| else |
| $asm.puts "fld #{operands[0].x86Operand(:double)}" |
| end |
| $asm.puts "fstp #{operands[1].x87Operand(1)}" |
| else |
| $asm.puts "movsd #{x86Operands(:double, :double)}" |
| end |
| when "moved" |
| if useX87 |
| if (operands[0].x87DefaultStackPosition == 0) |
| $asm.puts "fst #{operands[1].x87Operand(0)}" |
| else |
| $asm.puts "fld #{operands[0].x87Operand(0)}" |
| $asm.puts "fstp #{operands[1].x87Operand(1)}" |
| end |
| else |
| $asm.puts "movsd #{x86Operands(:double, :double)}" |
| end |
| when "stored" |
| if useX87 |
| if (operands[0].x87DefaultStackPosition == 0) |
| $asm.puts "fst#{x86Suffix(:int)} #{operands[1].x86Operand(:double)}" |
| else |
| $asm.puts "fld #{operands[0].x87Operand(0)}" |
| if !isIntelSyntax |
| $asm.puts "fstpl #{operands[1].x86Operand(:double)}" |
| else |
| $asm.puts "fstp #{operands[1].x86Operand(:double)}" |
| end |
| end |
| else |
| $asm.puts "movsd #{x86Operands(:double, :double)}" |
| end |
| when "addd" |
| if useX87 |
| handleX87BinOp("fadd", "fadd") |
| else |
| $asm.puts "addsd #{x86Operands(:double, :double)}" |
| end |
| when "muld" |
| if useX87 |
| handleX87BinOp("fmul", "fmul") |
| else |
| $asm.puts "mulsd #{x86Operands(:double, :double)}" |
| end |
| when "subd" |
| if useX87 |
| handleX87BinOp("fsub", "fsubr") |
| else |
| $asm.puts "subsd #{x86Operands(:double, :double)}" |
| end |
| when "divd" |
| if useX87 |
| handleX87BinOp("fdiv", "fdivr") |
| else |
| $asm.puts "divsd #{x86Operands(:double, :double)}" |
| end |
| when "sqrtd" |
| if useX87 |
| $asm.puts "fld #{operands[0].x87Operand(0)}" |
| $asm.puts "fsqrtl" |
| $asm.puts "fstp #{operands[1].x87Operand(1)}" |
| else |
| $asm.puts "sqrtsd #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:double)}" |
| end |
| when "ci2d" |
| if useX87 |
| sp = RegisterID.new(nil, "sp") |
| $asm.puts "mov#{x86Suffix(:int)} #{orderOperands(operands[0].x86Operand(:int), offsetRegister(-4, sp.x86Operand(:ptr)))}" |
| $asm.puts "fild#{x86Suffix(:ptr)} #{getSizeString(:ptr)}#{offsetRegister(-4, sp.x86Operand(:ptr))}" |
| $asm.puts "fstp #{operands[1].x87Operand(1)}" |
| else |
| $asm.puts "cvtsi2sd #{orderOperands(operands[0].x86Operand(:int), operands[1].x86Operand(:double))}" |
| end |
| when "bdeq" |
| if useX87 |
| handleX87Compare(:normal) |
| else |
| $asm.puts "ucomisd #{orderOperands(operands[0].x86Operand(:double), operands[1].x86Operand(:double))}" |
| end |
| 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" |
| if useX87 |
| handleX87Compare(:normal) |
| else |
| $asm.puts "ucomisd #{orderOperands(operands[0].x86Operand(:double), operands[1].x86Operand(:double))}" |
| end |
| 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" |
| # FIXME: unused and unimplemented for x87 |
| raise if useX87 |
| $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" |
| # FIXME: unused and unimplemented for x87 |
| raise if useX87 |
| $asm.puts "cvttsd2si #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:int)}" |
| when "bcd2i" |
| if useX87 |
| sp = RegisterID.new(nil, "sp") |
| if (operands[0].x87DefaultStackPosition == 0) |
| $asm.puts "fistl -4(#{sp.x86Operand(:ptr)})" |
| else |
| $asm.puts "fld #{operands[0].x87Operand(0)}" |
| $asm.puts "fistp#{x86Suffix(:ptr)} #{getSizeString(:ptr)}#{offsetRegister(-4, sp.x86Operand(:ptr))}" |
| end |
| $asm.puts "mov#{x86Suffix(:int)} #{orderOperands(offsetRegister(-4, sp.x86Operand(:ptr)), 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 "fild#{x86Suffix(:int)} #{getSizeString(:int)}#{offsetRegister(-4, sp.x86Operand(:ptr))}" |
| $asm.puts "fucomip #{@@floatingPointCompareImplicitOperand}#{operands[0].x87Operand(1)}" |
| $asm.puts "jp #{operands[2].asmLabel}" |
| $asm.puts "jne #{operands[2].asmLabel}" |
| else |
| $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}" |
| end |
| when "movdz" |
| if useX87 |
| $asm.puts "fldzl" |
| $asm.puts "fstp #{operands[0].x87Operand(1)}" |
| else |
| $asm.puts "xorpd #{operands[0].x86Operand(:double)}, #{operands[0].x86Operand(:double)}" |
| end |
| 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" |
| if useX87 |
| 2.times { |
| | offset | |
| $asm.puts "ffree #{register("st")}(#{offset})" |
| } |
| end |
| 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 "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 "idivi" |
| $asm.puts "idiv#{x86Suffix(:int)} #{operands[0].x86Operand(:int)}" |
| when "fii2d" |
| if useX87 |
| sp = RegisterID.new(nil, "sp") |
| $asm.puts "mov#{x86Suffix(:int)} #{orderOperands(operands[0].x86Operand(:int), offsetRegister(-8, sp.x86Operand(:ptr)))}" |
| $asm.puts "mov#{x86Suffix(:int)} #{orderOperands(operands[1].x86Operand(:int), offsetRegister(-4, sp.x86Operand(:ptr)))}" |
| $asm.puts "fld#{x86Suffix(:ptr)} #{getSizeString(:double)}#{offsetRegister(-8, sp.x86Operand(:ptr))}" |
| $asm.puts "fstp #{operands[2].x87Operand(1)}" |
| else |
| $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)}" |
| end |
| when "fd2ii" |
| if useX87 |
| sp = RegisterID.new(nil, "sp") |
| if (operands[0].x87DefaultStackPosition == 0) |
| $asm.puts "fst#{x86Suffix(:ptr)} #{getSizeString(:double)}#{offsetRegister(-8, sp.x86Operand(:ptr))}" |
| else |
| $asm.puts "fld #{operands[0].x87Operand(0)}" |
| $asm.puts "fstpl -8(#{sp.x86Operand(:ptr)})" |
| end |
| $asm.puts "mov#{x86Suffix(:int)} #{orderOperands(offsetRegister(-8, sp.x86Operand(:ptr)), operands[1].x86Operand(:int))}" |
| $asm.puts "mov#{x86Suffix(:int)} #{orderOperands(offsetRegister(-4, sp.x86Operand(:ptr)), operands[2].x86Operand(:int))}" |
| else |
| $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)}" |
| end |
| when "fq2d" |
| if useX87 |
| sp = RegisterID.new(nil, "sp") |
| $asm.puts "movq #{operands[0].x86Operand(:quad)}, -8(#{sp.x86Operand(:ptr)})" |
| $asm.puts "fldl -8(#{sp.x86Operand(:ptr)})" |
| $asm.puts "fstp #{operands[1].x87Operand(1)}" |
| else |
| 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 |
| end |
| when "fd2q" |
| if useX87 |
| sp = RegisterID.new(nil, "sp") |
| if (operands[0].x87DefaultStackPosition == 0) |
| $asm.puts "fst#{x86Suffix(:int)} #{getSizeString(:int)}#{offsetRegister(-8, sp.x86Operand(:ptr))}" |
| else |
| $asm.puts "fld #{operands[0].x87Operand(0)}" |
| $asm.puts "fstpl -8(#{sp.x86Operand(:ptr)})" |
| end |
| $asm.puts "movq -8(#{sp.x86Operand(:ptr)}), #{operands[1].x86Operand(:quad)}" |
| else |
| 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 |
| end |
| 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" |
| $asm.puts "mfence" |
| else |
| lowerDefault |
| end |
| end |
| end |
| |