/Source/JavaScriptCore/offlineasm/x86.rb
Ruby | 1832 lines | 1638 code | 105 blank | 89 comment | 139 complexity | af9b28b816fcf1430c8d6e558e84ea70 MD5 | raw file
Possible License(s): MPL-2.0, 0BSD, MPL-2.0-no-copyleft-exception, BSD-3-Clause, AGPL-1.0, MIT, GPL-2.0, GPL-3.0, Unlicense, BSD-2-Clause, LGPL-2.1, Apache-2.0
Large files files are truncated, but you can click here to view the full file
- # 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)}…
Large files files are truncated, but you can click here to view the full file