summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/offlineasm
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@digia.com>2013-09-13 12:51:20 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-09-19 20:50:05 +0200
commitd441d6f39bb846989d95bcf5caf387b42414718d (patch)
treee367e64a75991c554930278175d403c072de6bb8 /Source/JavaScriptCore/offlineasm
parent0060b2994c07842f4c59de64b5e3e430525c4b90 (diff)
downloadqtwebkit-d441d6f39bb846989d95bcf5caf387b42414718d.tar.gz
Import Qt5x2 branch of QtWebkit for Qt 5.2
Importing a new snapshot of webkit. Change-Id: I2d01ad12cdc8af8cb015387641120a9d7ea5f10c Reviewed-by: Allan Sandfeld Jensen <allan.jensen@digia.com>
Diffstat (limited to 'Source/JavaScriptCore/offlineasm')
-rw-r--r--Source/JavaScriptCore/offlineasm/arm.rb587
-rw-r--r--Source/JavaScriptCore/offlineasm/armv7.rb531
-rw-r--r--Source/JavaScriptCore/offlineasm/ast.rb12
-rw-r--r--Source/JavaScriptCore/offlineasm/backends.rb9
-rw-r--r--Source/JavaScriptCore/offlineasm/cloop.rb58
-rw-r--r--Source/JavaScriptCore/offlineasm/instructions.rb19
-rw-r--r--Source/JavaScriptCore/offlineasm/mips.rb2
-rw-r--r--Source/JavaScriptCore/offlineasm/parser.rb7
-rw-r--r--Source/JavaScriptCore/offlineasm/risc.rb9
-rw-r--r--Source/JavaScriptCore/offlineasm/sh4.rb778
-rw-r--r--Source/JavaScriptCore/offlineasm/x86.rb276
11 files changed, 1678 insertions, 610 deletions
diff --git a/Source/JavaScriptCore/offlineasm/arm.rb b/Source/JavaScriptCore/offlineasm/arm.rb
new file mode 100644
index 000000000..498333ba2
--- /dev/null
+++ b/Source/JavaScriptCore/offlineasm/arm.rb
@@ -0,0 +1,587 @@
+# Copyright (C) 2011, 2012 Apple Inc. All rights reserved.
+# Copyright (C) 2013 University of Szeged. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+# THE POSSIBILITY OF SUCH DAMAGE.
+
+require "config"
+require "ast"
+require "opt"
+require "risc"
+
+def isARMv7
+ case $activeBackend
+ when "ARMv7"
+ true
+ when "ARMv7_TRADITIONAL", "ARM"
+ false
+ else
+ raise "bad value for $activeBackend: #{$activeBackend}"
+ end
+end
+
+def isARMv7Traditional
+ case $activeBackend
+ when "ARMv7_TRADITIONAL"
+ true
+ when "ARMv7", "ARM"
+ false
+ else
+ raise "bad value for $activeBackend: #{$activeBackend}"
+ end
+end
+
+class Node
+ def armSingle
+ doubleOperand = armOperand
+ raise "Bogus register name #{doubleOperand}" unless doubleOperand =~ /^d/
+ "s" + ($~.post_match.to_i * 2).to_s
+ end
+end
+
+class SpecialRegister
+ def armOperand
+ @name
+ end
+end
+
+ARM_EXTRA_GPRS = [SpecialRegister.new("r9"), SpecialRegister.new("r8"), SpecialRegister.new("r3")]
+ARM_EXTRA_FPRS = [SpecialRegister.new("d7")]
+ARM_SCRATCH_FPR = SpecialRegister.new("d6")
+
+def armMoveImmediate(value, register)
+ # Currently we only handle the simple cases, and fall back to mov/movt for the complex ones.
+ if value >= 0 && value < 256
+ $asm.puts "mov #{register.armOperand}, \##{value}"
+ elsif (~value) >= 0 && (~value) < 256
+ $asm.puts "mvn #{register.armOperand}, \##{~value}"
+ elsif isARMv7 or isARMv7Traditional
+ $asm.puts "movw #{register.armOperand}, \##{value & 0xffff}"
+ if (value & 0xffff0000) != 0
+ $asm.puts "movt #{register.armOperand}, \##{(value >> 16) & 0xffff}"
+ end
+ else
+ $asm.puts "ldr #{register.armOperand}, =#{value}"
+ end
+end
+
+class RegisterID
+ def armOperand
+ case name
+ when "t0", "a0", "r0"
+ "r0"
+ when "t1", "a1", "r1"
+ "r1"
+ when "t2", "a2"
+ "r2"
+ when "a3"
+ "r3"
+ when "t3"
+ "r4"
+ when "t4"
+ "r10"
+ when "cfr"
+ "r5"
+ when "lr"
+ "lr"
+ when "sp"
+ "sp"
+ else
+ raise "Bad register #{name} for ARM at #{codeOriginString}"
+ end
+ end
+end
+
+class FPRegisterID
+ def armOperand
+ case name
+ when "ft0", "fr"
+ "d0"
+ when "ft1"
+ "d1"
+ when "ft2"
+ "d2"
+ when "ft3"
+ "d3"
+ when "ft4"
+ "d4"
+ when "ft5"
+ "d5"
+ else
+ raise "Bad register #{name} for ARM at #{codeOriginString}"
+ end
+ end
+end
+
+class Immediate
+ def armOperand
+ raise "Invalid immediate #{value} at #{codeOriginString}" if value < 0 or value > 255
+ "\##{value}"
+ end
+end
+
+class Address
+ def armOperand
+ raise "Bad offset at #{codeOriginString}" if offset.value < -0xff or offset.value > 0xfff
+ "[#{base.armOperand}, \##{offset.value}]"
+ end
+end
+
+class BaseIndex
+ def armOperand
+ raise "Bad offset at #{codeOriginString}" if offset.value != 0
+ "[#{base.armOperand}, #{index.armOperand}, lsl \##{scaleShift}]"
+ end
+end
+
+class AbsoluteAddress
+ def armOperand
+ raise "Unconverted absolute address at #{codeOriginString}"
+ end
+end
+
+#
+# Lea support.
+#
+
+class Address
+ def armEmitLea(destination)
+ if destination == base
+ $asm.puts "adds #{destination.armOperand}, \##{offset.value}"
+ else
+ $asm.puts "adds #{destination.armOperand}, #{base.armOperand}, \##{offset.value}"
+ end
+ end
+end
+
+class BaseIndex
+ def armEmitLea(destination)
+ raise "Malformed BaseIndex, offset should be zero at #{codeOriginString}" unless offset.value == 0
+ $asm.puts "add #{destination.armOperand}, #{base.armOperand}, #{index.armOperand}, lsl \##{scaleShift}"
+ end
+end
+
+# FIXME: we could support AbsoluteAddress for lea, but we don't.
+
+#
+# Actual lowering code follows.
+#
+
+class Sequence
+ def getModifiedListARM
+ raise unless $activeBackend == "ARM"
+ getModifiedListARMCommon
+ end
+
+ def getModifiedListARMv7
+ raise unless $activeBackend == "ARMv7"
+ getModifiedListARMCommon
+ end
+
+ def getModifiedListARMv7_TRADITIONAL
+ raise unless $activeBackend == "ARMv7_TRADITIONAL"
+ getModifiedListARMCommon
+ end
+
+ def getModifiedListARMCommon
+ result = @list
+ result = riscLowerSimpleBranchOps(result)
+ result = riscLowerHardBranchOps(result)
+ result = riscLowerShiftOps(result)
+ result = riscLowerMalformedAddresses(result) {
+ | node, address |
+ if address.is_a? BaseIndex
+ address.offset.value == 0
+ elsif address.is_a? Address
+ (-0xff..0xfff).include? address.offset.value
+ else
+ false
+ end
+ }
+ result = riscLowerMalformedAddressesDouble(result)
+ result = riscLowerMisplacedImmediates(result, ["storeb", "storei", "storep"])
+ result = riscLowerMalformedImmediates(result, 0..0xff)
+ result = riscLowerMisplacedAddresses(result)
+ result = riscLowerRegisterReuse(result)
+ result = assignRegistersToTemporaries(result, :gpr, ARM_EXTRA_GPRS)
+ result = assignRegistersToTemporaries(result, :fpr, ARM_EXTRA_FPRS)
+ return result
+ end
+end
+
+def armOperands(operands)
+ operands.map{|v| v.armOperand}.join(", ")
+end
+
+def armFlippedOperands(operands)
+ armOperands([operands[-1]] + operands[0..-2])
+end
+
+def emitArmCompact(opcode2, opcode3, operands)
+ if operands.size == 3
+ $asm.puts "#{opcode3} #{armFlippedOperands(operands)}"
+ else
+ raise unless operands.size == 2
+ raise unless operands[1].register?
+ if operands[0].immediate?
+ $asm.puts "#{opcode3} #{operands[1].armOperand}, #{operands[1].armOperand}, #{operands[0].armOperand}"
+ else
+ $asm.puts "#{opcode2} #{armFlippedOperands(operands)}"
+ end
+ end
+end
+
+def emitArm(opcode, operands)
+ if operands.size == 3
+ $asm.puts "#{opcode} #{armFlippedOperands(operands)}"
+ else
+ raise unless operands.size == 2
+ $asm.puts "#{opcode} #{operands[1].armOperand}, #{operands[1].armOperand}, #{operands[0].armOperand}"
+ end
+end
+
+def emitArmDoubleBranch(branchOpcode, operands)
+ $asm.puts "vcmpe.f64 #{armOperands(operands[0..1])}"
+ $asm.puts "vmrs apsr_nzcv, fpscr"
+ $asm.puts "#{branchOpcode} #{operands[2].asmLabel}"
+end
+
+def emitArmTest(operands)
+ 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.immediate? and mask.value == -1
+ $asm.puts "tst #{value.armOperand}, #{value.armOperand}"
+ else
+ $asm.puts "tst #{value.armOperand}, #{mask.armOperand}"
+ end
+end
+
+def emitArmCompare(operands, code)
+ $asm.puts "movs #{operands[2].armOperand}, \#0"
+ $asm.puts "cmp #{operands[0].armOperand}, #{operands[1].armOperand}"
+ $asm.puts "it #{code}"
+ $asm.puts "mov#{code} #{operands[2].armOperand}, \#1"
+end
+
+def emitArmTestSet(operands, code)
+ $asm.puts "movs #{operands[-1].armOperand}, \#0"
+ emitArmTest(operands)
+ $asm.puts "it #{code}"
+ $asm.puts "mov#{code} #{operands[-1].armOperand}, \#1"
+end
+
+class Instruction
+ def lowerARM
+ raise unless $activeBackend == "ARM"
+ lowerARMCommon
+ end
+
+ def lowerARMv7
+ raise unless $activeBackend == "ARMv7"
+ lowerARMCommon
+ end
+
+ def lowerARMv7_TRADITIONAL
+ raise unless $activeBackend == "ARMv7_TRADITIONAL"
+ lowerARMCommon
+ end
+
+ def lowerARMCommon
+ $asm.codeOrigin codeOriginString if $enableCodeOriginComments
+ $asm.annotation annotation if $enableInstrAnnotations
+
+ case opcode
+ when "addi", "addp", "addis", "addps"
+ if opcode == "addis" or opcode == "addps"
+ suffix = "s"
+ else
+ suffix = ""
+ end
+ if operands.size == 3 and operands[0].immediate?
+ raise unless operands[1].register?
+ raise unless operands[2].register?
+ if operands[0].value == 0 and suffix.empty?
+ unless operands[1] == operands[2]
+ $asm.puts "mov #{operands[2].armOperand}, #{operands[1].armOperand}"
+ end
+ else
+ $asm.puts "adds #{operands[2].armOperand}, #{operands[1].armOperand}, #{operands[0].armOperand}"
+ end
+ elsif operands.size == 3 and operands[0].immediate?
+ raise unless operands[1].register?
+ raise unless operands[2].register?
+ $asm.puts "adds #{armFlippedOperands(operands)}"
+ else
+ if operands[0].immediate?
+ unless Immediate.new(nil, 0) == operands[0]
+ $asm.puts "adds #{armFlippedOperands(operands)}"
+ end
+ else
+ $asm.puts "add#{suffix} #{armFlippedOperands(operands)}"
+ end
+ end
+ when "andi", "andp"
+ emitArmCompact("ands", "and", operands)
+ when "ori", "orp"
+ emitArmCompact("orrs", "orr", operands)
+ when "oris"
+ emitArmCompact("orrs", "orrs", operands)
+ when "xori", "xorp"
+ emitArmCompact("eors", "eor", operands)
+ when "lshifti", "lshiftp"
+ emitArmCompact("lsls", "lsls", operands)
+ when "rshifti", "rshiftp"
+ emitArmCompact("asrs", "asrs", operands)
+ when "urshifti", "urshiftp"
+ emitArmCompact("lsrs", "lsrs", operands)
+ when "muli", "mulp"
+ emitArm("mul", operands)
+ when "subi", "subp", "subis"
+ emitArmCompact("subs", "subs", operands)
+ when "negi", "negp"
+ $asm.puts "rsbs #{operands[0].armOperand}, #{operands[0].armOperand}, \#0"
+ when "noti"
+ $asm.puts "mvns #{operands[0].armOperand}, #{operands[0].armOperand}"
+ when "loadi", "loadis", "loadp"
+ $asm.puts "ldr #{armFlippedOperands(operands)}"
+ when "storei", "storep"
+ $asm.puts "str #{armOperands(operands)}"
+ when "loadb"
+ $asm.puts "ldrb #{armFlippedOperands(operands)}"
+ when "loadbs"
+ $asm.puts "ldrsb.w #{armFlippedOperands(operands)}"
+ when "storeb"
+ $asm.puts "strb #{armOperands(operands)}"
+ when "loadh"
+ $asm.puts "ldrh #{armFlippedOperands(operands)}"
+ when "loadhs"
+ $asm.puts "ldrsh.w #{armFlippedOperands(operands)}"
+ when "storeh"
+ $asm.puts "strh #{armOperands(operands)}"
+ when "loadd"
+ $asm.puts "vldr.64 #{armFlippedOperands(operands)}"
+ when "stored"
+ $asm.puts "vstr.64 #{armOperands(operands)}"
+ when "addd"
+ emitArm("vadd.f64", operands)
+ when "divd"
+ emitArm("vdiv.f64", operands)
+ when "subd"
+ emitArm("vsub.f64", operands)
+ when "muld"
+ emitArm("vmul.f64", operands)
+ when "sqrtd"
+ $asm.puts "vsqrt.f64 #{armFlippedOperands(operands)}"
+ when "ci2d"
+ $asm.puts "vmov #{operands[1].armSingle}, #{operands[0].armOperand}"
+ $asm.puts "vcvt.f64.s32 #{operands[1].armOperand}, #{operands[1].armSingle}"
+ when "bdeq"
+ emitArmDoubleBranch("beq", operands)
+ when "bdneq"
+ $asm.puts "vcmpe.f64 #{armOperands(operands[0..1])}"
+ $asm.puts "vmrs apsr_nzcv, fpscr"
+ isUnordered = LocalLabel.unique("bdneq")
+ $asm.puts "bvs #{LocalLabelReference.new(codeOrigin, isUnordered).asmLabel}"
+ $asm.puts "bne #{operands[2].asmLabel}"
+ isUnordered.lower("ARM")
+ when "bdgt"
+ emitArmDoubleBranch("bgt", operands)
+ when "bdgteq"
+ emitArmDoubleBranch("bge", operands)
+ when "bdlt"
+ emitArmDoubleBranch("bmi", operands)
+ when "bdlteq"
+ emitArmDoubleBranch("bls", operands)
+ when "bdequn"
+ $asm.puts "vcmpe.f64 #{armOperands(operands[0..1])}"
+ $asm.puts "vmrs apsr_nzcv, fpscr"
+ $asm.puts "bvs #{operands[2].asmLabel}"
+ $asm.puts "beq #{operands[2].asmLabel}"
+ when "bdnequn"
+ emitArmDoubleBranch("bne", operands)
+ when "bdgtun"
+ emitArmDoubleBranch("bhi", operands)
+ when "bdgtequn"
+ emitArmDoubleBranch("bpl", operands)
+ when "bdltun"
+ emitArmDoubleBranch("blt", operands)
+ when "bdltequn"
+ emitArmDoubleBranch("ble", operands)
+ when "btd2i"
+ # FIXME: may be a good idea to just get rid of this instruction, since the interpreter
+ # currently does not use it.
+ raise "ARM does not support this opcode yet, #{codeOrigin}"
+ when "td2i"
+ $asm.puts "vcvt.s32.f64 #{ARM_SCRATCH_FPR.armSingle}, #{operands[0].armOperand}"
+ $asm.puts "vmov #{operands[1].armOperand}, #{ARM_SCRATCH_FPR.armSingle}"
+ when "bcd2i"
+ $asm.puts "vcvt.s32.f64 #{ARM_SCRATCH_FPR.armSingle}, #{operands[0].armOperand}"
+ $asm.puts "vmov #{operands[1].armOperand}, #{ARM_SCRATCH_FPR.armSingle}"
+ $asm.puts "vcvt.f64.s32 #{ARM_SCRATCH_FPR.armOperand}, #{ARM_SCRATCH_FPR.armSingle}"
+ emitArmDoubleBranch("bne", [ARM_SCRATCH_FPR, operands[0], operands[2]])
+ $asm.puts "tst #{operands[1].armOperand}, #{operands[1].armOperand}"
+ $asm.puts "beq #{operands[2].asmLabel}"
+ when "movdz"
+ # FIXME: either support this or remove it.
+ raise "ARM does not support this opcode yet, #{codeOrigin}"
+ when "pop"
+ $asm.puts "pop #{operands[0].armOperand}"
+ when "push"
+ $asm.puts "push #{operands[0].armOperand}"
+ when "move"
+ if operands[0].immediate?
+ armMoveImmediate(operands[0].value, operands[1])
+ else
+ $asm.puts "mov #{armFlippedOperands(operands)}"
+ end
+ when "nop"
+ $asm.puts "nop"
+ when "bieq", "bpeq", "bbeq"
+ if Immediate.new(nil, 0) == operands[0]
+ $asm.puts "tst #{operands[1].armOperand}, #{operands[1].armOperand}"
+ elsif Immediate.new(nil, 0) == operands[1]
+ $asm.puts "tst #{operands[0].armOperand}, #{operands[0].armOperand}"
+ else
+ $asm.puts "cmp #{armOperands(operands[0..1])}"
+ end
+ $asm.puts "beq #{operands[2].asmLabel}"
+ when "bineq", "bpneq", "bbneq"
+ if Immediate.new(nil, 0) == operands[0]
+ $asm.puts "tst #{operands[1].armOperand}, #{operands[1].armOperand}"
+ elsif Immediate.new(nil, 0) == operands[1]
+ $asm.puts "tst #{operands[0].armOperand}, #{operands[0].armOperand}"
+ else
+ $asm.puts "cmp #{armOperands(operands[0..1])}"
+ end
+ $asm.puts "bne #{operands[2].asmLabel}"
+ when "bia", "bpa", "bba"
+ $asm.puts "cmp #{armOperands(operands[0..1])}"
+ $asm.puts "bhi #{operands[2].asmLabel}"
+ when "biaeq", "bpaeq", "bbaeq"
+ $asm.puts "cmp #{armOperands(operands[0..1])}"
+ $asm.puts "bhs #{operands[2].asmLabel}"
+ when "bib", "bpb", "bbb"
+ $asm.puts "cmp #{armOperands(operands[0..1])}"
+ $asm.puts "blo #{operands[2].asmLabel}"
+ when "bibeq", "bpbeq", "bbbeq"
+ $asm.puts "cmp #{armOperands(operands[0..1])}"
+ $asm.puts "bls #{operands[2].asmLabel}"
+ when "bigt", "bpgt", "bbgt"
+ $asm.puts "cmp #{armOperands(operands[0..1])}"
+ $asm.puts "bgt #{operands[2].asmLabel}"
+ when "bigteq", "bpgteq", "bbgteq"
+ $asm.puts "cmp #{armOperands(operands[0..1])}"
+ $asm.puts "bge #{operands[2].asmLabel}"
+ when "bilt", "bplt", "bblt"
+ $asm.puts "cmp #{armOperands(operands[0..1])}"
+ $asm.puts "blt #{operands[2].asmLabel}"
+ when "bilteq", "bplteq", "bblteq"
+ $asm.puts "cmp #{armOperands(operands[0..1])}"
+ $asm.puts "ble #{operands[2].asmLabel}"
+ when "btiz", "btpz", "btbz"
+ emitArmTest(operands)
+ $asm.puts "beq #{operands[-1].asmLabel}"
+ when "btinz", "btpnz", "btbnz"
+ emitArmTest(operands)
+ $asm.puts "bne #{operands[-1].asmLabel}"
+ when "btis", "btps", "btbs"
+ emitArmTest(operands)
+ $asm.puts "bmi #{operands[-1].asmLabel}"
+ when "jmp"
+ if operands[0].label?
+ $asm.puts "b #{operands[0].asmLabel}"
+ else
+ $asm.puts "mov pc, #{operands[0].armOperand}"
+ end
+ if not isARMv7 and not isARMv7Traditional
+ $asm.puts ".ltorg"
+ end
+ when "call"
+ if operands[0].label?
+ $asm.puts "blx #{operands[0].asmLabel}"
+ else
+ $asm.puts "blx #{operands[0].armOperand}"
+ end
+ when "break"
+ $asm.puts "bkpt #0"
+ when "ret"
+ $asm.puts "bx lr"
+ when "cieq", "cpeq", "cbeq"
+ emitArmCompare(operands, "eq")
+ when "cineq", "cpneq", "cbneq"
+ emitArmCompare(operands, "ne")
+ when "cia", "cpa", "cba"
+ emitArmCompare(operands, "hi")
+ when "ciaeq", "cpaeq", "cbaeq"
+ emitArmCompare(operands, "hs")
+ when "cib", "cpb", "cbb"
+ emitArmCompare(operands, "lo")
+ when "cibeq", "cpbeq", "cbbeq"
+ emitArmCompare(operands, "ls")
+ when "cigt", "cpgt", "cbgt"
+ emitArmCompare(operands, "gt")
+ when "cigteq", "cpgteq", "cbgteq"
+ emitArmCompare(operands, "ge")
+ when "cilt", "cplt", "cblt"
+ emitArmCompare(operands, "lt")
+ when "cilteq", "cplteq", "cblteq"
+ emitArmCompare(operands, "le")
+ when "tis", "tbs", "tps"
+ emitArmTestSet(operands, "mi")
+ when "tiz", "tbz", "tpz"
+ emitArmTestSet(operands, "eq")
+ when "tinz", "tbnz", "tpnz"
+ emitArmTestSet(operands, "ne")
+ when "peek"
+ $asm.puts "ldr #{operands[1].armOperand}, [sp, \##{operands[0].value * 4}]"
+ when "poke"
+ $asm.puts "str #{operands[1].armOperand}, [sp, \##{operands[0].value * 4}]"
+ when "fii2d"
+ $asm.puts "vmov #{operands[2].armOperand}, #{operands[0].armOperand}, #{operands[1].armOperand}"
+ when "fd2ii"
+ $asm.puts "vmov #{operands[1].armOperand}, #{operands[2].armOperand}, #{operands[0].armOperand}"
+ when "bo"
+ $asm.puts "bvs #{operands[0].asmLabel}"
+ when "bs"
+ $asm.puts "bmi #{operands[0].asmLabel}"
+ when "bz"
+ $asm.puts "beq #{operands[0].asmLabel}"
+ when "bnz"
+ $asm.puts "bne #{operands[0].asmLabel}"
+ when "leai", "leap"
+ operands[0].armEmitLea(operands[1])
+ when "smulli"
+ raise "Wrong number of arguments to smull in #{self.inspect} at #{codeOriginString}" unless operands.length == 4
+ $asm.puts "smull #{operands[2].armOperand}, #{operands[3].armOperand}, #{operands[0].armOperand}, #{operands[1].armOperand}"
+ else
+ lowerDefault
+ end
+ end
+end
+
diff --git a/Source/JavaScriptCore/offlineasm/armv7.rb b/Source/JavaScriptCore/offlineasm/armv7.rb
deleted file mode 100644
index 078be8c0f..000000000
--- a/Source/JavaScriptCore/offlineasm/armv7.rb
+++ /dev/null
@@ -1,531 +0,0 @@
-# Copyright (C) 2011, 2012 Apple Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-# 1. Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright
-# notice, this list of conditions and the following disclaimer in the
-# documentation and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
-# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
-# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
-# THE POSSIBILITY OF SUCH DAMAGE.
-
-require "config"
-require "ast"
-require "opt"
-require "risc"
-
-class Node
- def armV7Single
- doubleOperand = armV7Operand
- raise "Bogus register name #{doubleOperand}" unless doubleOperand =~ /^d/
- "s" + ($~.post_match.to_i * 2).to_s
- end
-end
-
-class SpecialRegister
- def armV7Operand
- @name
- end
-end
-
-ARMv7_EXTRA_GPRS = [SpecialRegister.new("r9"), SpecialRegister.new("r8"), SpecialRegister.new("r3")]
-ARMv7_EXTRA_FPRS = [SpecialRegister.new("d7")]
-ARMv7_SCRATCH_FPR = SpecialRegister.new("d8")
-
-def armV7MoveImmediate(value, register)
- # Currently we only handle the simple cases, and fall back to mov/movt for the complex ones.
- if value >= 0 && value < 256
- $asm.puts "movw #{register.armV7Operand}, \##{value}"
- elsif (~value) >= 0 && (~value) < 256
- $asm.puts "mvn #{register.armV7Operand}, \##{~value}"
- else
- $asm.puts "movw #{register.armV7Operand}, \##{value & 0xffff}"
- if (value & 0xffff0000) != 0
- $asm.puts "movt #{register.armV7Operand}, \##{(value >> 16) & 0xffff}"
- end
- end
-end
-
-class RegisterID
- def armV7Operand
- case name
- when "t0", "a0", "r0"
- "r0"
- when "t1", "a1", "r1"
- "r1"
- when "t2", "a2"
- "r2"
- when "a3"
- "r3"
- when "t3"
- "r4"
- when "t4"
- "r10"
- when "cfr"
- "r5"
- when "lr"
- "lr"
- when "sp"
- "sp"
- else
- raise "Bad register #{name} for ARMv7 at #{codeOriginString}"
- end
- end
-end
-
-class FPRegisterID
- def armV7Operand
- case name
- when "ft0", "fr"
- "d0"
- when "ft1"
- "d1"
- when "ft2"
- "d2"
- when "ft3"
- "d3"
- when "ft4"
- "d4"
- when "ft5"
- "d5"
- else
- raise "Bad register #{name} for ARMv7 at #{codeOriginString}"
- end
- end
-end
-
-class Immediate
- def armV7Operand
- raise "Invalid immediate #{value} at #{codeOriginString}" if value < 0 or value > 255
- "\##{value}"
- end
-end
-
-class Address
- def armV7Operand
- raise "Bad offset at #{codeOriginString}" if offset.value < -0xff or offset.value > 0xfff
- "[#{base.armV7Operand}, \##{offset.value}]"
- end
-end
-
-class BaseIndex
- def armV7Operand
- raise "Bad offset at #{codeOriginString}" if offset.value != 0
- "[#{base.armV7Operand}, #{index.armV7Operand}, lsl \##{scaleShift}]"
- end
-end
-
-class AbsoluteAddress
- def armV7Operand
- raise "Unconverted absolute address at #{codeOriginString}"
- end
-end
-
-#
-# Lea support.
-#
-
-class Address
- def armV7EmitLea(destination)
- if destination == base
- $asm.puts "adds #{destination.armV7Operand}, \##{offset.value}"
- else
- $asm.puts "adds #{destination.armV7Operand}, #{base.armV7Operand}, \##{offset.value}"
- end
- end
-end
-
-class BaseIndex
- def armV7EmitLea(destination)
- raise "Malformed BaseIndex, offset should be zero at #{codeOriginString}" unless offset.value == 0
- $asm.puts "add.w #{destination.armV7Operand}, #{base.armV7Operand}, #{index.armV7Operand}, lsl \##{scaleShift}"
- end
-end
-
-# FIXME: we could support AbsoluteAddress for lea, but we don't.
-
-#
-# Actual lowering code follows.
-#
-
-class Sequence
- def getModifiedListARMv7
- result = @list
- result = riscLowerSimpleBranchOps(result)
- result = riscLowerHardBranchOps(result)
- result = riscLowerShiftOps(result)
- result = riscLowerMalformedAddresses(result) {
- | node, address |
- if address.is_a? BaseIndex
- address.offset.value == 0
- elsif address.is_a? Address
- (-0xff..0xfff).include? address.offset.value
- else
- false
- end
- }
- result = riscLowerMalformedAddressesDouble(result)
- result = riscLowerMisplacedImmediates(result)
- result = riscLowerMalformedImmediates(result, 0..0xff)
- result = riscLowerMisplacedAddresses(result)
- result = riscLowerRegisterReuse(result)
- result = assignRegistersToTemporaries(result, :gpr, ARMv7_EXTRA_GPRS)
- result = assignRegistersToTemporaries(result, :fpr, ARMv7_EXTRA_FPRS)
- return result
- end
-end
-
-def armV7Operands(operands)
- operands.map{|v| v.armV7Operand}.join(", ")
-end
-
-def armV7FlippedOperands(operands)
- armV7Operands([operands[-1]] + operands[0..-2])
-end
-
-def emitArmV7Compact(opcode2, opcode3, operands)
- if operands.size == 3
- $asm.puts "#{opcode3} #{armV7FlippedOperands(operands)}"
- else
- raise unless operands.size == 2
- raise unless operands[1].register?
- if operands[0].is_a? Immediate
- $asm.puts "#{opcode3} #{operands[1].armV7Operand}, #{operands[1].armV7Operand}, #{operands[0].armV7Operand}"
- else
- $asm.puts "#{opcode2} #{armV7FlippedOperands(operands)}"
- end
- end
-end
-
-def emitArmV7(opcode, operands)
- if operands.size == 3
- $asm.puts "#{opcode} #{armV7FlippedOperands(operands)}"
- else
- raise unless operands.size == 2
- $asm.puts "#{opcode} #{operands[1].armV7Operand}, #{operands[1].armV7Operand}, #{operands[0].armV7Operand}"
- end
-end
-
-def emitArmV7DoubleBranch(branchOpcode, operands)
- $asm.puts "vcmpe.f64 #{armV7Operands(operands[0..1])}"
- $asm.puts "vmrs apsr_nzcv, fpscr"
- $asm.puts "#{branchOpcode} #{operands[2].asmLabel}"
-end
-
-def emitArmV7Test(operands)
- 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
- $asm.puts "tst #{value.armV7Operand}, #{value.armV7Operand}"
- elsif mask.is_a? Immediate
- $asm.puts "tst.w #{value.armV7Operand}, #{mask.armV7Operand}"
- else
- $asm.puts "tst #{value.armV7Operand}, #{mask.armV7Operand}"
- end
-end
-
-def emitArmV7Compare(operands, code)
- $asm.puts "movs #{operands[2].armV7Operand}, \#0"
- $asm.puts "cmp #{operands[0].armV7Operand}, #{operands[1].armV7Operand}"
- $asm.puts "it #{code}"
- $asm.puts "mov#{code} #{operands[2].armV7Operand}, \#1"
-end
-
-def emitArmV7TestSet(operands, code)
- $asm.puts "movs #{operands[-1].armV7Operand}, \#0"
- emitArmV7Test(operands)
- $asm.puts "it #{code}"
- $asm.puts "mov#{code} #{operands[-1].armV7Operand}, \#1"
-end
-
-class Instruction
- def lowerARMv7
- $asm.codeOrigin codeOriginString if $enableCodeOriginComments
- $asm.annotation annotation if $enableInstrAnnotations
-
- case opcode
- when "addi", "addp", "addis", "addps"
- if opcode == "addis" or opcode == "addps"
- suffix = "s"
- else
- suffix = ""
- end
- if operands.size == 3 and operands[0].is_a? Immediate
- raise unless operands[1].is_a? RegisterID
- raise unless operands[2].is_a? RegisterID
- if operands[0].value == 0 and suffix.empty?
- unless operands[1] == operands[2]
- $asm.puts "mov #{operands[2].armV7Operand}, #{operands[1].armV7Operand}"
- end
- else
- $asm.puts "adds #{operands[2].armV7Operand}, #{operands[1].armV7Operand}, #{operands[0].armV7Operand}"
- end
- elsif operands.size == 3 and operands[0].is_a? RegisterID
- raise unless operands[1].is_a? RegisterID
- raise unless operands[2].is_a? RegisterID
- $asm.puts "adds #{armV7FlippedOperands(operands)}"
- else
- if operands[0].is_a? Immediate
- unless Immediate.new(nil, 0) == operands[0]
- $asm.puts "adds #{armV7FlippedOperands(operands)}"
- end
- else
- $asm.puts "add#{suffix} #{armV7FlippedOperands(operands)}"
- end
- end
- when "andi", "andp"
- emitArmV7Compact("ands", "and", operands)
- when "ori", "orp"
- emitArmV7Compact("orrs", "orr", operands)
- when "oris"
- emitArmV7Compact("orrs", "orrs", operands)
- when "xori", "xorp"
- emitArmV7Compact("eors", "eor", operands)
- when "lshifti", "lshiftp"
- emitArmV7Compact("lsls", "lsls", operands)
- when "rshifti", "rshiftp"
- emitArmV7Compact("asrs", "asrs", operands)
- when "urshifti", "urshiftp"
- emitArmV7Compact("lsrs", "lsrs", operands)
- when "muli", "mulp"
- emitArmV7("mul", operands)
- when "subi", "subp", "subis"
- emitArmV7Compact("subs", "subs", operands)
- when "negi", "negp"
- $asm.puts "rsbs #{operands[0].armV7Operand}, #{operands[0].armV7Operand}, \#0"
- when "noti"
- $asm.puts "mvns #{operands[0].armV7Operand}, #{operands[0].armV7Operand}"
- when "loadi", "loadis", "loadp"
- $asm.puts "ldr #{armV7FlippedOperands(operands)}"
- when "storei", "storep"
- $asm.puts "str #{armV7Operands(operands)}"
- when "loadb"
- $asm.puts "ldrb #{armV7FlippedOperands(operands)}"
- when "loadbs"
- $asm.puts "ldrsb.w #{armV7FlippedOperands(operands)}"
- when "storeb"
- $asm.puts "strb #{armV7Operands(operands)}"
- when "loadh"
- $asm.puts "ldrh #{armV7FlippedOperands(operands)}"
- when "loadhs"
- $asm.puts "ldrsh.w #{armV7FlippedOperands(operands)}"
- when "storeh"
- $asm.puts "strh #{armV7Operands(operands)}"
- when "loadd"
- $asm.puts "vldr.64 #{armV7FlippedOperands(operands)}"
- when "stored"
- $asm.puts "vstr.64 #{armV7Operands(operands)}"
- when "addd"
- emitArmV7("vadd.f64", operands)
- when "divd"
- emitArmV7("vdiv.f64", operands)
- when "subd"
- emitArmV7("vsub.f64", operands)
- when "muld"
- emitArmV7("vmul.f64", operands)
- when "sqrtd"
- $asm.puts "vsqrt.f64 #{armV7FlippedOperands(operands)}"
- when "ci2d"
- $asm.puts "vmov #{operands[1].armV7Single}, #{operands[0].armV7Operand}"
- $asm.puts "vcvt.f64.s32 #{operands[1].armV7Operand}, #{operands[1].armV7Single}"
- when "bdeq"
- emitArmV7DoubleBranch("beq", operands)
- when "bdneq"
- $asm.puts "vcmpe.f64 #{armV7Operands(operands[0..1])}"
- $asm.puts "vmrs apsr_nzcv, fpscr"
- isUnordered = LocalLabel.unique("bdneq")
- $asm.puts "bvs #{LocalLabelReference.new(codeOrigin, isUnordered).asmLabel}"
- $asm.puts "bne #{operands[2].asmLabel}"
- isUnordered.lower("ARMv7")
- when "bdgt"
- emitArmV7DoubleBranch("bgt", operands)
- when "bdgteq"
- emitArmV7DoubleBranch("bge", operands)
- when "bdlt"
- emitArmV7DoubleBranch("bmi", operands)
- when "bdlteq"
- emitArmV7DoubleBranch("bls", operands)
- when "bdequn"
- $asm.puts "vcmpe.f64 #{armV7Operands(operands[0..1])}"
- $asm.puts "vmrs apsr_nzcv, fpscr"
- $asm.puts "bvs #{operands[2].asmLabel}"
- $asm.puts "beq #{operands[2].asmLabel}"
- when "bdnequn"
- emitArmV7DoubleBranch("bne", operands)
- when "bdgtun"
- emitArmV7DoubleBranch("bhi", operands)
- when "bdgtequn"
- emitArmV7DoubleBranch("bpl", operands)
- when "bdltun"
- emitArmV7DoubleBranch("blt", operands)
- when "bdltequn"
- emitArmV7DoubleBranch("ble", operands)
- when "btd2i"
- # FIXME: may be a good idea to just get rid of this instruction, since the interpreter
- # currently does not use it.
- raise "ARMv7 does not support this opcode yet, #{codeOrigin}"
- when "td2i"
- $asm.puts "vcvt.s32.f64 #{ARMv7_SCRATCH_FPR.armV7Single}, #{operands[0].armV7Operand}"
- $asm.puts "vmov #{operands[1].armV7Operand}, #{ARMv7_SCRATCH_FPR.armV7Single}"
- when "bcd2i"
- $asm.puts "vcvt.s32.f64 #{ARMv7_SCRATCH_FPR.armV7Single}, #{operands[0].armV7Operand}"
- $asm.puts "vmov #{operands[1].armV7Operand}, #{ARMv7_SCRATCH_FPR.armV7Single}"
- $asm.puts "vcvt.f64.s32 #{ARMv7_SCRATCH_FPR.armV7Operand}, #{ARMv7_SCRATCH_FPR.armV7Single}"
- emitArmV7DoubleBranch("bne", [ARMv7_SCRATCH_FPR, operands[0], operands[2]])
- $asm.puts "tst #{operands[1].armV7Operand}, #{operands[1].armV7Operand}"
- $asm.puts "beq #{operands[2].asmLabel}"
- when "movdz"
- # FIXME: either support this or remove it.
- raise "ARMv7 does not support this opcode yet, #{codeOrigin}"
- when "pop"
- $asm.puts "pop #{operands[0].armV7Operand}"
- when "push"
- $asm.puts "push #{operands[0].armV7Operand}"
- when "move"
- if operands[0].is_a? Immediate
- armV7MoveImmediate(operands[0].value, operands[1])
- else
- $asm.puts "mov #{armV7FlippedOperands(operands)}"
- end
- when "nop"
- $asm.puts "nop"
- when "bieq", "bpeq", "bbeq"
- if Immediate.new(nil, 0) == operands[0]
- $asm.puts "tst #{operands[1].armV7Operand}, #{operands[1].armV7Operand}"
- elsif Immediate.new(nil, 0) == operands[1]
- $asm.puts "tst #{operands[0].armV7Operand}, #{operands[0].armV7Operand}"
- else
- $asm.puts "cmp #{armV7Operands(operands[0..1])}"
- end
- $asm.puts "beq #{operands[2].asmLabel}"
- when "bineq", "bpneq", "bbneq"
- if Immediate.new(nil, 0) == operands[0]
- $asm.puts "tst #{operands[1].armV7Operand}, #{operands[1].armV7Operand}"
- elsif Immediate.new(nil, 0) == operands[1]
- $asm.puts "tst #{operands[0].armV7Operand}, #{operands[0].armV7Operand}"
- else
- $asm.puts "cmp #{armV7Operands(operands[0..1])}"
- end
- $asm.puts "bne #{operands[2].asmLabel}"
- when "bia", "bpa", "bba"
- $asm.puts "cmp #{armV7Operands(operands[0..1])}"
- $asm.puts "bhi #{operands[2].asmLabel}"
- when "biaeq", "bpaeq", "bbaeq"
- $asm.puts "cmp #{armV7Operands(operands[0..1])}"
- $asm.puts "bhs #{operands[2].asmLabel}"
- when "bib", "bpb", "bbb"
- $asm.puts "cmp #{armV7Operands(operands[0..1])}"
- $asm.puts "blo #{operands[2].asmLabel}"
- when "bibeq", "bpbeq", "bbbeq"
- $asm.puts "cmp #{armV7Operands(operands[0..1])}"
- $asm.puts "bls #{operands[2].asmLabel}"
- when "bigt", "bpgt", "bbgt"
- $asm.puts "cmp #{armV7Operands(operands[0..1])}"
- $asm.puts "bgt #{operands[2].asmLabel}"
- when "bigteq", "bpgteq", "bbgteq"
- $asm.puts "cmp #{armV7Operands(operands[0..1])}"
- $asm.puts "bge #{operands[2].asmLabel}"
- when "bilt", "bplt", "bblt"
- $asm.puts "cmp #{armV7Operands(operands[0..1])}"
- $asm.puts "blt #{operands[2].asmLabel}"
- when "bilteq", "bplteq", "bblteq"
- $asm.puts "cmp #{armV7Operands(operands[0..1])}"
- $asm.puts "ble #{operands[2].asmLabel}"
- when "btiz", "btpz", "btbz"
- emitArmV7Test(operands)
- $asm.puts "beq #{operands[-1].asmLabel}"
- when "btinz", "btpnz", "btbnz"
- emitArmV7Test(operands)
- $asm.puts "bne #{operands[-1].asmLabel}"
- when "btis", "btps", "btbs"
- emitArmV7Test(operands)
- $asm.puts "bmi #{operands[-1].asmLabel}"
- when "jmp"
- if operands[0].label?
- $asm.puts "b #{operands[0].asmLabel}"
- else
- $asm.puts "mov pc, #{operands[0].armV7Operand}"
- end
- when "call"
- if operands[0].label?
- $asm.puts "blx #{operands[0].asmLabel}"
- else
- $asm.puts "blx #{operands[0].armV7Operand}"
- end
- when "break"
- $asm.puts "bkpt #0"
- when "ret"
- $asm.puts "bx lr"
- when "cieq", "cpeq", "cbeq"
- emitArmV7Compare(operands, "eq")
- when "cineq", "cpneq", "cbneq"
- emitArmV7Compare(operands, "ne")
- when "cia", "cpa", "cba"
- emitArmV7Compare(operands, "hi")
- when "ciaeq", "cpaeq", "cbaeq"
- emitArmV7Compare(operands, "hs")
- when "cib", "cpb", "cbb"
- emitArmV7Compare(operands, "lo")
- when "cibeq", "cpbeq", "cbbeq"
- emitArmV7Compare(operands, "ls")
- when "cigt", "cpgt", "cbgt"
- emitArmV7Compare(operands, "gt")
- when "cigteq", "cpgteq", "cbgteq"
- emitArmV7Compare(operands, "ge")
- when "cilt", "cplt", "cblt"
- emitArmV7Compare(operands, "lt")
- when "cilteq", "cplteq", "cblteq"
- emitArmV7Compare(operands, "le")
- when "tis", "tbs", "tps"
- emitArmV7TestSet(operands, "mi")
- when "tiz", "tbz", "tpz"
- emitArmV7TestSet(operands, "eq")
- when "tinz", "tbnz", "tpnz"
- emitArmV7TestSet(operands, "ne")
- when "peek"
- $asm.puts "ldr #{operands[1].armV7Operand}, [sp, \##{operands[0].value * 4}]"
- when "poke"
- $asm.puts "str #{operands[1].armV7Operand}, [sp, \##{operands[0].value * 4}]"
- when "fii2d"
- $asm.puts "vmov #{operands[2].armV7Operand}, #{operands[0].armV7Operand}, #{operands[1].armV7Operand}"
- when "fd2ii"
- $asm.puts "vmov #{operands[1].armV7Operand}, #{operands[2].armV7Operand}, #{operands[0].armV7Operand}"
- when "bo"
- $asm.puts "bvs #{operands[0].asmLabel}"
- when "bs"
- $asm.puts "bmi #{operands[0].asmLabel}"
- when "bz"
- $asm.puts "beq #{operands[0].asmLabel}"
- when "bnz"
- $asm.puts "bne #{operands[0].asmLabel}"
- when "leai", "leap"
- operands[0].armV7EmitLea(operands[1])
- when "smulli"
- raise "Wrong number of arguments to smull in #{self.inspect} at #{codeOriginString}" unless operands.length == 4
- $asm.puts "smull #{operands[2].armV7Operand}, #{operands[3].armV7Operand}, #{operands[0].armV7Operand}, #{operands[1].armV7Operand}"
- else
- lowerDefault
- end
- end
-end
-
diff --git a/Source/JavaScriptCore/offlineasm/ast.rb b/Source/JavaScriptCore/offlineasm/ast.rb
index 4f0c3fd88..74bccff56 100644
--- a/Source/JavaScriptCore/offlineasm/ast.rb
+++ b/Source/JavaScriptCore/offlineasm/ast.rb
@@ -671,6 +671,10 @@ class Address < Node
raise "Bad offset for address #{offset.inspect} at #{codeOriginString}" unless offset.is_a? Variable or offset.immediate?
end
+ def withOffset(extraOffset)
+ Address.new(codeOrigin, @base, Immediate.new(codeOrigin, @offset.value + extraOffset))
+ end
+
def children
[@base, @offset]
end
@@ -727,6 +731,10 @@ class BaseIndex < Node
end
end
+ def withOffset(extraOffset)
+ BaseIndex.new(codeOrigin, @base, @index, @scale, Immediate.new(codeOrigin, @offset.value + extraOffset))
+ end
+
def children
[@base, @index, @offset]
end
@@ -764,6 +772,10 @@ class AbsoluteAddress < NoChildren
@address = address
end
+ def withOffset(extraOffset)
+ AbsoluteAddress.new(codeOrigin, Immediate.new(codeOrigin, @address.value + extraOffset))
+ end
+
def dump
"#{address.dump}[]"
end
diff --git a/Source/JavaScriptCore/offlineasm/backends.rb b/Source/JavaScriptCore/offlineasm/backends.rb
index ef9358c0b..902a764af 100644
--- a/Source/JavaScriptCore/offlineasm/backends.rb
+++ b/Source/JavaScriptCore/offlineasm/backends.rb
@@ -22,18 +22,22 @@
# THE POSSIBILITY OF SUCH DAMAGE.
require "config"
-require "armv7"
+require "arm"
require "ast"
require "x86"
require "mips"
+require "sh4"
require "cloop"
BACKENDS =
[
"X86",
"X86_64",
+ "ARM",
"ARMv7",
+ "ARMv7_TRADITIONAL",
"MIPS",
+ "SH4",
"C_LOOP"
]
@@ -46,8 +50,11 @@ WORKING_BACKENDS =
[
"X86",
"X86_64",
+ "ARM",
"ARMv7",
+ "ARMv7_TRADITIONAL",
"MIPS",
+ "SH4",
"C_LOOP"
]
diff --git a/Source/JavaScriptCore/offlineasm/cloop.rb b/Source/JavaScriptCore/offlineasm/cloop.rb
index 8d0838ebd..6f35b2ffd 100644
--- a/Source/JavaScriptCore/offlineasm/cloop.rb
+++ b/Source/JavaScriptCore/offlineasm/cloop.rb
@@ -55,7 +55,7 @@ end
class SpecialRegister < NoChildren
- def dump
+ def clDump
@name
end
def clValue(type=:int)
@@ -63,10 +63,10 @@ class SpecialRegister < NoChildren
end
end
-C_LOOP_SCRATCH_FPR = SpecialRegister.new("d8")
+C_LOOP_SCRATCH_FPR = SpecialRegister.new("d6")
class RegisterID
- def dump
+ def clDump
case name
when "t0"
"t0"
@@ -95,12 +95,12 @@ class RegisterID
end
end
def clValue(type=:int)
- dump + cloopMapType(type)
+ clDump + cloopMapType(type)
end
end
class FPRegisterID
- def dump
+ def clDump
case name
when "ft0", "fr"
"d0"
@@ -119,12 +119,12 @@ class FPRegisterID
end
end
def clValue(type=:int)
- dump + cloopMapType(type)
+ clDump + cloopMapType(type)
end
end
class Immediate
- def dump
+ def clDump
"#{value}"
end
def clValue(type=:int)
@@ -156,8 +156,8 @@ class Immediate
end
class Address
- def dump
- "[#{base.dump}, #{offset.value}]"
+ def clDump
+ "[#{base.clDump}, #{offset.value}]"
end
def clValue(type=:int)
case type
@@ -178,7 +178,7 @@ class Address
def pointerExpr
if base.is_a? RegisterID and base.name == "sp"
offsetValue = "#{offset.value}"
- "(ASSERT(#{offsetValue} == offsetof(JITStackFrame, globalData)), &sp->globalData)"
+ "(ASSERT(#{offsetValue} == offsetof(JITStackFrame, vm)), &sp->vm)"
elsif offset.value == 0
"#{base.clValue(:int8Ptr)}"
elsif offset.value > 0
@@ -229,8 +229,8 @@ class Address
end
class BaseIndex
- def dump
- "[#{base.dump}, #{offset.dump}, #{index.dump} << #{scaleShift}]"
+ def clDump
+ "[#{base.clDump}, #{offset.clDump}, #{index.clDump} << #{scaleShift}]"
end
def clValue(type=:int)
case type
@@ -250,7 +250,7 @@ class BaseIndex
def pointerExpr
if base.is_a? RegisterID and base.name == "sp"
offsetValue = "(#{index.clValue} << #{scaleShift}) + #{offset.clValue})"
- "(ASSERT(#{offsetValue} == offsetof(JITStackFrame, globalData)), &sp->globalData)"
+ "(ASSERT(#{offsetValue} == offsetof(JITStackFrame, vm)), &sp->vm)"
else
"#{base.clValue(:int8Ptr)} + (#{index.clValue} << #{scaleShift}) + #{offset.clValue}"
end
@@ -294,11 +294,11 @@ class BaseIndex
end
class AbsoluteAddress
- def dump
+ def clDump
"#{codeOriginString}"
end
def clValue
- dump
+ clDump
end
end
@@ -348,7 +348,7 @@ class Sequence
end
def clOperands(operands)
- operands.map{|v| v.dump}.join(", ")
+ operands.map{|v| v.clDump}.join(", ")
end
@@ -358,14 +358,14 @@ def cloopEmitOperation(operands, type, operator)
if operands.size == 3
$asm.putc "#{operands[2].clValue(type)} = #{operands[1].clValue(type)} #{operator} #{operands[0].clValue(type)};"
if operands[2].is_a? RegisterID and (type == :int32 or type == :uint32)
- $asm.putc "#{operands[2].dump}.clearHighWord();" # Just clear it. It does nothing on the 32-bit port.
+ $asm.putc "#{operands[2].clDump}.clearHighWord();" # Just clear it. It does nothing on the 32-bit port.
end
else
raise unless operands.size == 2
raise unless not operands[1].is_a? Immediate
$asm.putc "#{operands[1].clValue(type)} = #{operands[1].clValue(type)} #{operator} #{operands[0].clValue(type)};"
if operands[1].is_a? RegisterID and (type == :int32 or type == :uint32)
- $asm.putc "#{operands[1].dump}.clearHighWord();" # Just clear it. It does nothing on the 32-bit port.
+ $asm.putc "#{operands[1].clDump}.clearHighWord();" # Just clear it. It does nothing on the 32-bit port.
end
end
end
@@ -375,14 +375,14 @@ def cloopEmitShiftOperation(operands, type, operator)
if operands.size == 3
$asm.putc "#{operands[2].clValue(type)} = #{operands[1].clValue(type)} #{operator} (#{operands[0].clValue(:int)} & 0x1f);"
if operands[2].is_a? RegisterID and (type == :int32 or type == :uint32)
- $asm.putc "#{operands[2].dump}.clearHighWord();" # Just clear it. It does nothing on the 32-bit port.
+ $asm.putc "#{operands[2].clDump}.clearHighWord();" # Just clear it. It does nothing on the 32-bit port.
end
else
raise unless operands.size == 2
raise unless not operands[1].is_a? Immediate
$asm.putc "#{operands[1].clValue(type)} = #{operands[1].clValue(type)} #{operator} (#{operands[0].clValue(:int)} & 0x1f);"
if operands[1].is_a? RegisterID and (type == :int32 or type == :uint32)
- $asm.putc "#{operands[1].dump}.clearHighWord();" # Just clear it. It does nothing on the 32-bit port.
+ $asm.putc "#{operands[1].clDump}.clearHighWord();" # Just clear it. It does nothing on the 32-bit port.
end
end
end
@@ -393,12 +393,12 @@ def cloopEmitUnaryOperation(operands, type, operator)
raise unless not operands[0].is_a? Immediate
$asm.putc "#{operands[0].clValue(type)} = #{operator}#{operands[0].clValue(type)};"
if operands[0].is_a? RegisterID and (type == :int32 or type == :uint32)
- $asm.putc "#{operands[0].dump}.clearHighWord();" # Just clear it. It does nothing on the 32-bit port.
+ $asm.putc "#{operands[0].clDump}.clearHighWord();" # Just clear it. It does nothing on the 32-bit port.
end
end
def cloopEmitCompareDoubleWithNaNCheckAndBranch(operands, condition)
- $asm.putc "if (isnan(#{operands[0].clValue(:double)}) || isnan(#{operands[1].clValue(:double)})"
+ $asm.putc "if (std::isnan(#{operands[0].clValue(:double)}) || isnan(#{operands[1].clValue(:double)})"
$asm.putc " || (#{operands[0].clValue(:double)} #{condition} #{operands[1].clValue(:double)}))"
$asm.putc " goto #{operands[2].cLabel};"
end
@@ -465,9 +465,9 @@ def cloopEmitOpAndBranch(operands, operator, type, conditionTest)
$asm.putc "{"
$asm.putc " #{tempType} temp = #{op2} #{operator} #{op1};"
+ $asm.putc " #{op2} = temp;"
$asm.putc " if (temp #{conditionTest})"
$asm.putc " goto #{operands[2].cLabel};"
- $asm.putc " #{op2} = temp;"
$asm.putc "}"
end
@@ -533,10 +533,10 @@ def cloopEmitOpAndBranchIfOverflow(operands, operator, type)
raise "Unimplemented opeartor"
end
- $asm.putc " if #{overflowTest} {"
- $asm.putc " goto #{operands[2].cLabel};"
- $asm.putc " }"
+ $asm.putc " bool didOverflow = #{overflowTest};"
$asm.putc " #{operands[1].clValue(type)} = #{operands[1].clValue(type)} #{operator} #{operands[0].clValue(type)};"
+ $asm.putc " if (didOverflow)"
+ $asm.putc " goto #{operands[2].cLabel};"
$asm.putc "}"
end
@@ -703,16 +703,16 @@ class Instruction
when "td2i"
$asm.putc "#{operands[1].clValue(:int)} = #{operands[0].clValue(:double)};"
- $asm.putc "#{operands[1].dump}.clearHighWord();"
+ $asm.putc "#{operands[1].clDump}.clearHighWord();"
when "bcd2i" # operands: srcDbl dstInt slowPath
$asm.putc "{"
$asm.putc " double d = #{operands[0].clValue(:double)};"
$asm.putc " const int32_t asInt32 = int32_t(d);"
- $asm.putc " if (asInt32 != d || (!asInt32 && signbit(d))) // true for -0.0"
+ $asm.putc " if (asInt32 != d || (!asInt32 && std::signbit(d))) // true for -0.0"
$asm.putc " goto #{operands[2].cLabel};"
$asm.putc " #{operands[1].clValue} = asInt32;"
- $asm.putc " #{operands[1].dump}.clearHighWord();"
+ $asm.putc " #{operands[1].clDump}.clearHighWord();"
$asm.putc "}"
when "move"
diff --git a/Source/JavaScriptCore/offlineasm/instructions.rb b/Source/JavaScriptCore/offlineasm/instructions.rb
index 4e70625c2..eb394afab 100644
--- a/Source/JavaScriptCore/offlineasm/instructions.rb
+++ b/Source/JavaScriptCore/offlineasm/instructions.rb
@@ -257,7 +257,7 @@ X86_INSTRUCTIONS =
"idivi"
]
-ARMv7_INSTRUCTIONS =
+ARM_INSTRUCTIONS =
[
"smulli",
"addis",
@@ -275,6 +275,21 @@ MIPS_INSTRUCTIONS =
"pichdrra"
]
+SH4_INSTRUCTIONS =
+ [
+ "shllx",
+ "shlrx",
+ "shld",
+ "shad",
+ "bdnan",
+ "loaddReversedAndIncrementAddress",
+ "storedReversedAndDecrementAddress",
+ "ldspr",
+ "stspr",
+ "callf",
+ "jmpf"
+ ]
+
CXX_INSTRUCTIONS =
[
"cloopCrash", # no operands
@@ -291,7 +306,7 @@ CXX_INSTRUCTIONS =
"cloopDo", # no operands
]
-INSTRUCTIONS = MACRO_INSTRUCTIONS + X86_INSTRUCTIONS + ARMv7_INSTRUCTIONS + MIPS_INSTRUCTIONS + CXX_INSTRUCTIONS
+INSTRUCTIONS = MACRO_INSTRUCTIONS + X86_INSTRUCTIONS + ARM_INSTRUCTIONS + MIPS_INSTRUCTIONS + SH4_INSTRUCTIONS + CXX_INSTRUCTIONS
INSTRUCTION_PATTERN = Regexp.new('\\A((' + INSTRUCTIONS.join(')|(') + '))\\Z')
diff --git a/Source/JavaScriptCore/offlineasm/mips.rb b/Source/JavaScriptCore/offlineasm/mips.rb
index c6daa3c7d..3ec7022ee 100644
--- a/Source/JavaScriptCore/offlineasm/mips.rb
+++ b/Source/JavaScriptCore/offlineasm/mips.rb
@@ -566,7 +566,7 @@ class Sequence
end
}
result = riscLowerMalformedAddressesDouble(result)
- result = riscLowerMisplacedImmediates(result)
+ result = riscLowerMisplacedImmediates(result, ["storeb", "storei", "storep"])
result = mipsLowerMisplacedImmediates(result)
result = riscLowerMalformedImmediates(result, -0xffff..0xffff)
result = mipsLowerMisplacedAddresses(result)
diff --git a/Source/JavaScriptCore/offlineasm/parser.rb b/Source/JavaScriptCore/offlineasm/parser.rb
index 76eea522f..3b9c67bed 100644
--- a/Source/JavaScriptCore/offlineasm/parser.rb
+++ b/Source/JavaScriptCore/offlineasm/parser.rb
@@ -114,7 +114,7 @@ def lex(str, fileName)
end
result << Token.new(CodeOrigin.new(fileName, lineNumber), $&)
lineNumber += 1
- when /\A[a-zA-Z]([a-zA-Z0-9_]*)/
+ when /\A[a-zA-Z]([a-zA-Z0-9_.]*)/
result << Token.new(CodeOrigin.new(fileName, lineNumber), $&)
when /\A\.([a-zA-Z0-9_]*)/
result << Token.new(CodeOrigin.new(fileName, lineNumber), $&)
@@ -163,7 +163,7 @@ def isKeyword(token)
end
def isIdentifier(token)
- token =~ /\A[a-zA-Z]([a-zA-Z0-9_]*)\Z/ and not isKeyword(token)
+ token =~ /\A[a-zA-Z]([a-zA-Z0-9_.]*)\Z/ and not isKeyword(token)
end
def isLabel(token)
@@ -223,8 +223,9 @@ class Parser
def parsePredicateAtom
if @tokens[@idx] == "not"
+ codeOrigin = @tokens[@idx].codeOrigin
@idx += 1
- parsePredicateAtom
+ Not.new(codeOrigin, parsePredicateAtom)
elsif @tokens[@idx] == "("
@idx += 1
skipNewLine
diff --git a/Source/JavaScriptCore/offlineasm/risc.rb b/Source/JavaScriptCore/offlineasm/risc.rb
index 7408253af..1696a0c5c 100644
--- a/Source/JavaScriptCore/offlineasm/risc.rb
+++ b/Source/JavaScriptCore/offlineasm/risc.rb
@@ -172,7 +172,7 @@ end
# end
# }
#
-# See armv7.rb for a different example, in which we lower all BaseIndex addresses
+# See arm.rb for a different example, in which we lower all BaseIndex addresses
# that have non-zero offset, all Address addresses that have large offsets, and
# all other addresses (like AbsoluteAddress).
#
@@ -272,7 +272,7 @@ def riscLowerMalformedAddressesDouble(list)
end
#
-# Lowering of misplaced immediates. For example:
+# Lowering of misplaced immediates for opcodes in opcodeList. For example, if storei is in opcodeList:
#
# storei 0, [foo]
#
@@ -282,13 +282,12 @@ end
# storei tmp, [foo]
#
-def riscLowerMisplacedImmediates(list)
+def riscLowerMisplacedImmediates(list, opcodeList)
newList = []
list.each {
| node |
if node.is_a? Instruction
- case node.opcode
- when "storeb", "storei", "storep"
+ if opcodeList.include? node.opcode
operands = node.operands
newOperands = []
operands.each {
diff --git a/Source/JavaScriptCore/offlineasm/sh4.rb b/Source/JavaScriptCore/offlineasm/sh4.rb
new file mode 100644
index 000000000..57223c826
--- /dev/null
+++ b/Source/JavaScriptCore/offlineasm/sh4.rb
@@ -0,0 +1,778 @@
+# Copyright (C) 2013 Apple Inc. All rights reserved.
+# Copyright (C) 2013 Cisco Systems, Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY CISCO SYSTEMS, INC. ``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 CISCO SYSTEMS, 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 'risc'
+
+class Node
+ def sh4SingleHi
+ doubleOperand = sh4Operand
+ raise "Bogus register name #{doubleOperand}" unless doubleOperand =~ /^dr/
+ "fr" + ($~.post_match.to_i).to_s
+ end
+ def sh4SingleLo
+ doubleOperand = sh4Operand
+ raise "Bogus register name #{doubleOperand}" unless doubleOperand =~ /^dr/
+ "fr" + ($~.post_match.to_i + 1).to_s
+ end
+end
+
+class SpecialRegister < NoChildren
+ def sh4Operand
+ @name
+ end
+
+ def dump
+ @name
+ end
+
+ def register?
+ true
+ end
+end
+
+SH4_TMP_GPRS = [ SpecialRegister.new("r3"), SpecialRegister.new("r11"), SpecialRegister.new("r13") ]
+SH4_TMP_FPRS = [ SpecialRegister.new("dr10") ]
+
+class RegisterID
+ def sh4Operand
+ case name
+ when "a0"
+ "r4"
+ when "a1"
+ "r5"
+ when "t0"
+ "r0"
+ when "t1"
+ "r1"
+ when "t2"
+ "r2"
+ when "t3"
+ "r10"
+ when "t4"
+ "r6"
+ when "cfr"
+ "r14"
+ when "sp"
+ "r15"
+ when "lr"
+ "pr"
+ else
+ raise "Bad register #{name} for SH4 at #{codeOriginString}"
+ end
+ end
+end
+
+class FPRegisterID
+ def sh4Operand
+ case name
+ when "ft0", "fr"
+ "dr0"
+ when "ft1"
+ "dr2"
+ when "ft2"
+ "dr4"
+ when "ft3"
+ "dr6"
+ when "ft4"
+ "dr8"
+ when "fa0"
+ "dr12"
+ else
+ raise "Bad register #{name} for SH4 at #{codeOriginString}"
+ end
+ end
+end
+
+class Immediate
+ def sh4Operand
+ raise "Invalid immediate #{value} at #{codeOriginString}" if value < -128 or value > 127
+ "##{value}"
+ end
+end
+
+class Address
+ def sh4Operand
+ raise "Bad offset #{offset.value} at #{codeOriginString}" if offset.value < 0 or offset.value > 60
+ if offset.value == 0
+ "@#{base.sh4Operand}"
+ else
+ "@(#{offset.value}, #{base.sh4Operand})"
+ end
+ end
+
+ def sh4OperandPostInc
+ raise "Bad offset #{offset.value} for post inc at #{codeOriginString}" unless offset.value == 0
+ "@#{base.sh4Operand}+"
+ end
+
+ def sh4OperandPreDec
+ raise "Bad offset #{offset.value} for pre dec at #{codeOriginString}" unless offset.value == 0
+ "@-#{base.sh4Operand}"
+ end
+end
+
+class BaseIndex
+ def sh4Operand
+ raise "Unconverted base index at #{codeOriginString}"
+ end
+end
+
+class AbsoluteAddress
+ def sh4Operand
+ raise "Unconverted absolute address at #{codeOriginString}"
+ end
+end
+
+
+#
+# Lowering of shift ops for SH4. For example:
+#
+# rshifti foo, bar
+#
+# becomes:
+#
+# negi foo, tmp
+# shad tmp, bar
+#
+
+def sh4LowerShiftOps(list)
+ newList = []
+ list.each {
+ | node |
+ if node.is_a? Instruction
+ case node.opcode
+ when "ulshifti", "ulshiftp", "urshifti", "urshiftp", "lshifti", "lshiftp", "rshifti", "rshiftp"
+ if node.opcode[0, 1] == "u"
+ type = "l"
+ direction = node.opcode[1, 1]
+ else
+ type = "a"
+ direction = node.opcode[0, 1]
+ end
+ if node.operands[0].is_a? Immediate
+ maskedImm = Immediate.new(node.operands[0].codeOrigin, node.operands[0].value & 31)
+ if maskedImm.value == 0
+ # There is nothing to do here.
+ elsif maskedImm.value == 1 or (type == "l" and [2, 8, 16].include? maskedImm.value)
+ newList << Instruction.new(node.codeOrigin, "sh#{type}#{direction}x", [maskedImm, node.operands[1]])
+ else
+ tmp = Tmp.new(node.codeOrigin, :gpr)
+ if direction == "l"
+ newList << Instruction.new(node.codeOrigin, "move", [maskedImm, tmp])
+ else
+ newList << Instruction.new(node.codeOrigin, "move", [Immediate.new(node.operands[0].codeOrigin, -1 * maskedImm.value), tmp])
+ end
+ newList << Instruction.new(node.codeOrigin, "sh#{type}d", [tmp, node.operands[1]])
+ end
+ else
+ tmp = Tmp.new(node.codeOrigin, :gpr)
+ newList << Instruction.new(node.codeOrigin, "move", [Immediate.new(node.operands[0].codeOrigin, 31), tmp])
+ newList << Instruction.new(node.codeOrigin, "andi", [node.operands[0], tmp])
+ if direction == "r"
+ newList << Instruction.new(node.codeOrigin, "negi", [tmp, tmp])
+ end
+ newList << Instruction.new(node.codeOrigin, "sh#{type}d", [tmp, node.operands[1]])
+ end
+ else
+ newList << node
+ end
+ else
+ newList << node
+ end
+ }
+ newList
+end
+
+
+#
+# Lowering of simple branch ops for SH4. For example:
+#
+# baddis foo, bar, baz
+#
+# will become:
+#
+# addi foo, bar
+# bs bar, baz
+#
+
+def sh4LowerSimpleBranchOps(list)
+ newList = []
+ list.each {
+ | node |
+ if node.is_a? Instruction
+ annotation = node.annotation
+ case node.opcode
+ when /^b(addi|subi|ori|addp)/
+ op = $1
+ bc = $~.post_match
+
+ case op
+ when "addi", "addp"
+ op = "addi"
+ when "subi", "subp"
+ op = "subi"
+ when "ori", "orp"
+ op = "ori"
+ end
+
+ if bc == "s"
+ raise "Invalid operands number (#{node.operands.size})" unless node.operands.size == 3
+ if node.operands[1].is_a? RegisterID or node.operands[1].is_a? SpecialRegister
+ newList << Instruction.new(node.codeOrigin, op, node.operands[0..1])
+ newList << Instruction.new(node.codeOrigin, "bs", node.operands[1..2])
+ else
+ tmpVal = Tmp.new(node.codeOrigin, :gpr)
+ tmpPtr = Tmp.new(node.codeOrigin, :gpr)
+ addr = Address.new(node.codeOrigin, tmpPtr, Immediate.new(node.codeOrigin, 0))
+ newList << Instruction.new(node.codeOrigin, "leap", [node.operands[1], tmpPtr])
+ newList << Instruction.new(node.codeOrigin, "loadi", [addr, tmpVal])
+ newList << Instruction.new(node.codeOrigin, op, [node.operands[0], tmpVal])
+ newList << Instruction.new(node.codeOrigin, "storei", [tmpVal, addr])
+ newList << Instruction.new(node.codeOrigin, "bs", [tmpVal, node.operands[2]])
+ end
+ elsif bc == "nz"
+ raise "Invalid operands number (#{node.operands.size})" unless node.operands.size == 3
+ newList << Instruction.new(node.codeOrigin, op, node.operands[0..1])
+ newList << Instruction.new(node.codeOrigin, "btinz", node.operands[1..2])
+ else
+ newList << node
+ end
+ when "bmulio", "bmulpo"
+ raise "Invalid operands number (#{node.operands.size})" unless node.operands.size == 3
+ tmp1 = Tmp.new(node.codeOrigin, :gpr)
+ tmp2 = Tmp.new(node.codeOrigin, :gpr)
+ newList << Instruction.new(node.codeOrigin, node.opcode, [tmp1, tmp2].concat(node.operands))
+ else
+ newList << node
+ end
+ else
+ newList << node
+ end
+ }
+ newList
+end
+
+
+#
+# Lowering of double accesses for SH4. For example:
+#
+# loadd [foo, bar, 8], baz
+#
+# becomes:
+#
+# leap [foo, bar, 8], tmp
+# loaddReversedAndIncrementAddress [tmp], baz
+#
+
+def sh4LowerDoubleAccesses(list)
+ newList = []
+ list.each {
+ | node |
+ if node.is_a? Instruction
+ case node.opcode
+ when "loadd"
+ tmp = Tmp.new(codeOrigin, :gpr)
+ addr = Address.new(codeOrigin, tmp, Immediate.new(codeOrigin, 0))
+ newList << Instruction.new(codeOrigin, "leap", [node.operands[0], tmp])
+ newList << Instruction.new(node.codeOrigin, "loaddReversedAndIncrementAddress", [addr, node.operands[1]], node.annotation)
+ when "stored"
+ tmp = Tmp.new(codeOrigin, :gpr)
+ addr = Address.new(codeOrigin, tmp, Immediate.new(codeOrigin, 0))
+ newList << Instruction.new(codeOrigin, "leap", [node.operands[1].withOffset(8), tmp])
+ newList << Instruction.new(node.codeOrigin, "storedReversedAndDecrementAddress", [node.operands[0], addr], node.annotation)
+ else
+ newList << node
+ end
+ else
+ newList << node
+ end
+ }
+ newList
+end
+
+
+#
+# Lowering of double specials for SH4.
+#
+
+def sh4LowerDoubleSpecials(list)
+ newList = []
+ list.each {
+ | node |
+ if node.is_a? Instruction
+ case node.opcode
+ when "bdltun", "bdgtun"
+ # Handle specific floating point unordered opcodes.
+ newList << Instruction.new(codeOrigin, "bdnan", [node.operands[0], node.operands[2]])
+ newList << Instruction.new(codeOrigin, "bdnan", [node.operands[1], node.operands[2]])
+ newList << Instruction.new(codeOrigin, node.opcode[0..-3], node.operands)
+ when "bdnequn", "bdgtequn", "bdltequn"
+ newList << Instruction.new(codeOrigin, node.opcode[0..-3], node.operands)
+ when "bdneq", "bdgteq", "bdlteq"
+ # Handle specific floating point ordered opcodes.
+ outlabel = LocalLabel.unique("out_#{node.opcode}")
+ outref = LocalLabelReference.new(codeOrigin, outlabel)
+ newList << Instruction.new(codeOrigin, "bdnan", [node.operands[0], outref])
+ newList << Instruction.new(codeOrigin, "bdnan", [node.operands[1], outref])
+ newList << Instruction.new(codeOrigin, node.opcode, node.operands)
+ newList << outlabel
+ else
+ newList << node
+ end
+ else
+ newList << node
+ end
+ }
+ newList
+end
+
+
+#
+# Lowering of misplaced labels for SH4.
+#
+
+def sh4LowerMisplacedLabels(list)
+ newList = []
+ list.each {
+ | node |
+ if node.is_a? Instruction
+ case node.opcode
+ when "jmp"
+ if node.operands[0].is_a? LabelReference
+ tmp = Tmp.new(codeOrigin, :gpr)
+ newList << Instruction.new(codeOrigin, "jmpf", [tmp, node.operands[0]])
+ else
+ newList << node
+ end
+ when "call"
+ if node.operands[0].is_a? LabelReference
+ tmp1 = Tmp.new(codeOrigin, :gpr)
+ tmp2 = Tmp.new(codeOrigin, :gpr)
+ newList << Instruction.new(codeOrigin, "callf", [tmp1, tmp2, node.operands[0]])
+ else
+ newList << node
+ end
+ else
+ newList << node
+ end
+ else
+ newList << node
+ end
+ }
+ newList
+end
+
+
+class Sequence
+ def getModifiedListSH4
+ result = @list
+
+ # Verify that we will only see instructions and labels.
+ result.each {
+ | node |
+ unless node.is_a? Instruction or
+ node.is_a? Label or
+ node.is_a? LocalLabel or
+ node.is_a? Skip
+ raise "Unexpected #{node.inspect} at #{node.codeOrigin}"
+ end
+ }
+
+ result = sh4LowerShiftOps(result)
+ result = sh4LowerSimpleBranchOps(result)
+ result = riscLowerMalformedAddresses(result) {
+ | node, address |
+ if address.is_a? Address
+ case node.opcode
+ when "btbz", "btbnz", "cbeq", "bbeq", "bbneq", "bbb", "loadb", "storeb"
+ (0..15).include? address.offset.value and
+ ((node.operands[0].is_a? RegisterID and node.operands[0].sh4Operand == "r0") or
+ (node.operands[1].is_a? RegisterID and node.operands[1].sh4Operand == "r0"))
+ when "loadh"
+ (0..30).include? address.offset.value and
+ ((node.operands[0].is_a? RegisterID and node.operands[0].sh4Operand == "r0") or
+ (node.operands[1].is_a? RegisterID and node.operands[1].sh4Operand == "r0"))
+ else
+ (0..60).include? address.offset.value
+ end
+ else
+ false
+ end
+ }
+ result = sh4LowerDoubleAccesses(result)
+ result = sh4LowerDoubleSpecials(result)
+ result = riscLowerMisplacedImmediates(result, ["storeb", "storei", "storep", "muli", "mulp", "andi", "ori", "xori",
+ "cbeq", "cieq", "cpeq", "cineq", "cpneq", "cib", "baddio", "bsubio", "bmulio", "baddis",
+ "bbeq", "bbneq", "bbb", "bieq", "bpeq", "bineq", "bpneq", "bia", "bpa", "biaeq", "bpaeq", "bib", "bpb",
+ "bigteq", "bpgteq", "bilt", "bplt", "bigt", "bpgt", "bilteq", "bplteq", "btiz", "btpz", "btinz", "btpnz", "btbz", "btbnz"])
+ result = riscLowerMalformedImmediates(result, -128..127)
+ result = sh4LowerMisplacedLabels(result)
+ result = riscLowerMisplacedAddresses(result)
+
+ result = assignRegistersToTemporaries(result, :gpr, SH4_TMP_GPRS)
+ result = assignRegistersToTemporaries(result, :gpr, SH4_TMP_FPRS)
+
+ return result
+ end
+end
+
+def sh4Operands(operands)
+ operands.map{|v| v.sh4Operand}.join(", ")
+end
+
+def emitSH4Load32AndJump(constant, scratch)
+ $asm.puts "mov.l 2f, #{scratch.sh4Operand}"
+ $asm.puts "braf #{scratch.sh4Operand}"
+ $asm.puts "nop"
+ $asm.puts "1: .balign 4"
+ $asm.puts "2: .long #{constant}-1b"
+end
+
+def emitSH4LoadImm(operands)
+ if operands[0].value == 0x40000000
+ # FirstConstantRegisterIndex const is often used (0x40000000).
+ # It's more efficient to "build" the value with 3 opcodes without branch.
+ $asm.puts "mov #64, #{operands[1].sh4Operand}"
+ $asm.puts "shll16 #{operands[1].sh4Operand}"
+ $asm.puts "shll8 #{operands[1].sh4Operand}"
+ elsif (-128..127).include? operands[0].value
+ $asm.puts "mov #{sh4Operands(operands)}"
+ elsif (-32768..32767).include? operands[0].value
+ constlabel = LocalLabel.unique("loadconstant")
+ $asm.puts "mov.w @(6, PC), #{operands[1].sh4Operand}"
+ $asm.puts "bra #{LocalLabelReference.new(codeOrigin, constlabel).asmLabel}"
+ $asm.puts "nop"
+ $asm.puts ".word #{operands[0].value}"
+ constlabel.lower("SH4")
+ else
+ outlabel = LocalLabel.unique("load32out")
+ constlabel = LocalLabel.unique("load32const")
+ $asm.puts "mov.l #{LocalLabelReference.new(codeOrigin, constlabel).asmLabel}, #{operands[1].sh4Operand}"
+ $asm.puts "bra #{LocalLabelReference.new(codeOrigin, outlabel).asmLabel}"
+ $asm.puts "nop"
+ $asm.puts ".balign 4"
+ constlabel.lower("SH4")
+ $asm.puts ".long #{operands[0].value}"
+ outlabel.lower("SH4")
+ end
+end
+
+def emitSH4Branch(sh4opcode, operand)
+ $asm.puts "#{sh4opcode} @#{operand.sh4Operand}"
+ $asm.puts "nop"
+end
+
+def emitSH4ShiftImm(val, operand, direction)
+ tmp = val
+ while tmp > 0
+ if tmp >= 16
+ $asm.puts "shl#{direction}16 #{operand.sh4Operand}"
+ tmp -= 16
+ elsif tmp >= 8
+ $asm.puts "shl#{direction}8 #{operand.sh4Operand}"
+ tmp -= 8
+ elsif tmp >= 2
+ $asm.puts "shl#{direction}2 #{operand.sh4Operand}"
+ tmp -= 2
+ else
+ $asm.puts "shl#{direction} #{operand.sh4Operand}"
+ tmp -= 1
+ end
+ end
+end
+
+def emitSH4BranchIfT(label, neg)
+ outlabel = LocalLabel.unique("branchIfT")
+ sh4opcode = neg ? "bt" : "bf"
+ $asm.puts "#{sh4opcode} #{LocalLabelReference.new(codeOrigin, outlabel).asmLabel}"
+ if label.is_a? LocalLabelReference
+ $asm.puts "bra #{label.asmLabel}"
+ $asm.puts "nop"
+ else
+ emitSH4Load32AndJump(label.asmLabel, SH4_TMP_GPRS[0])
+ end
+ outlabel.lower("SH4")
+end
+
+def emitSH4IntCompare(cmpOpcode, operands)
+ $asm.puts "cmp/#{cmpOpcode} #{sh4Operands([operands[1], operands[0]])}"
+end
+
+def emitSH4CondBranch(cmpOpcode, neg, operands)
+ emitSH4IntCompare(cmpOpcode, operands)
+ emitSH4BranchIfT(operands[2], neg)
+end
+
+def emitSH4CompareSet(cmpOpcode, neg, operands)
+ emitSH4IntCompare(cmpOpcode, operands)
+ if !neg
+ $asm.puts "movt #{operands[2].sh4Operand}"
+ else
+ outlabel = LocalLabel.unique("compareSet")
+ $asm.puts "mov #0, #{operands[2].sh4Operand}"
+ $asm.puts "bt #{LocalLabelReference.new(codeOrigin, outlabel).asmLabel}"
+ $asm.puts "mov #1, #{operands[2].sh4Operand}"
+ outlabel.lower("SH4")
+ end
+end
+
+def emitSH4BranchIfNaN(operands)
+ raise "Invalid operands number (#{operands.size})" unless operands.size == 2
+ $asm.puts "fcmp/eq #{sh4Operands([operands[0], operands[0]])}"
+ $asm.puts "bf #{operands[1].asmLabel}"
+end
+
+def emitSH4DoubleCondBranch(cmpOpcode, neg, operands)
+ if cmpOpcode == "lt"
+ $asm.puts "fcmp/gt #{sh4Operands([operands[0], operands[1]])}"
+ else
+ $asm.puts "fcmp/#{cmpOpcode} #{sh4Operands([operands[1], operands[0]])}"
+ end
+ emitSH4BranchIfT(operands[2], neg)
+end
+
+class Instruction
+ def lowerSH4
+ $asm.comment codeOriginString
+ case opcode
+ when "addi", "addp"
+ if operands.size == 3
+ if operands[0].sh4Operand == operands[2].sh4Operand
+ $asm.puts "add #{sh4Operands([operands[1], operands[2]])}"
+ elsif operands[1].sh4Operand == operands[2].sh4Operand
+ $asm.puts "add #{sh4Operands([operands[0], operands[2]])}"
+ else
+ $asm.puts "mov #{sh4Operands([operands[0], operands[2]])}"
+ $asm.puts "add #{sh4Operands([operands[1], operands[2]])}"
+ end
+ else
+ $asm.puts "add #{sh4Operands(operands)}"
+ end
+ when "subi", "subp"
+ raise "#{opcode} with #{operands.size} operands is not handled yet" unless operands.size == 2
+ if operands[0].is_a? Immediate
+ $asm.puts "add #{sh4Operands([Immediate.new(codeOrigin, -1 * operands[0].value), operands[1]])}"
+ else
+ $asm.puts "sub #{sh4Operands(operands)}"
+ end
+ when "muli", "mulp"
+ $asm.puts "mul.l #{sh4Operands(operands[0..1])}"
+ $asm.puts "sts macl, #{operands[-1].sh4Operand}"
+ when "negi", "negp"
+ if operands.size == 2
+ $asm.puts "neg #{sh4Operands(operands)}"
+ else
+ $asm.puts "neg #{sh4Operands([operands[0], operands[0]])}"
+ end
+ when "andi", "andp", "ori", "orp", "xori", "xorp"
+ raise "#{opcode} with #{operands.size} operands is not handled yet" unless operands.size == 2
+ sh4opcode = opcode[0..-2]
+ $asm.puts "#{sh4opcode} #{sh4Operands(operands)}"
+ when "shllx", "shlrx"
+ raise "Unhandled parameters for opcode #{opcode}" unless operands[0].is_a? Immediate
+ if operands[0].value == 1
+ $asm.puts "shl#{opcode[3, 1]} #{operands[1].sh4Operand}"
+ else
+ $asm.puts "shl#{opcode[3, 1]}#{operands[0].value} #{operands[1].sh4Operand}"
+ end
+ when "shld", "shad"
+ $asm.puts "#{opcode} #{sh4Operands(operands)}"
+ when "loaddReversedAndIncrementAddress"
+ # As we are little endian, we don't use "fmov @Rm, DRn" here.
+ $asm.puts "fmov.s #{operands[0].sh4OperandPostInc}, #{operands[1].sh4SingleLo}"
+ $asm.puts "fmov.s #{operands[0].sh4OperandPostInc}, #{operands[1].sh4SingleHi}"
+ when "storedReversedAndDecrementAddress"
+ # As we are little endian, we don't use "fmov DRm, @Rn" here.
+ $asm.puts "fmov.s #{operands[0].sh4SingleHi}, #{operands[1].sh4OperandPreDec}"
+ $asm.puts "fmov.s #{operands[0].sh4SingleLo}, #{operands[1].sh4OperandPreDec}"
+ when "ci2d"
+ $asm.puts "lds #{operands[0].sh4Operand}, fpul"
+ $asm.puts "float fpul, #{operands[1].sh4Operand}"
+ when "fii2d"
+ $asm.puts "lds #{operands[0].sh4Operand}, fpul"
+ $asm.puts "fsts fpul, #{operands[2].sh4SingleLo}"
+ $asm.puts "lds #{operands[1].sh4Operand}, fpul"
+ $asm.puts "fsts fpul, #{operands[2].sh4SingleHi}"
+ when "fd2ii"
+ $asm.puts "flds #{operands[0].sh4SingleLo}, fpul"
+ $asm.puts "sts fpul, #{operands[1].sh4Operand}"
+ $asm.puts "flds #{operands[0].sh4SingleHi}, fpul"
+ $asm.puts "sts fpul, #{operands[2].sh4Operand}"
+ when "addd", "subd", "muld", "divd"
+ sh4opcode = opcode[0..-2]
+ $asm.puts "f#{sh4opcode} #{sh4Operands(operands)}"
+ when "bcd2i"
+ $asm.puts "ftrc #{operands[0].sh4Operand}, fpul"
+ $asm.puts "sts fpul, #{operands[1].sh4Operand}"
+ $asm.puts "float fpul, #{SH4_TMP_FPRS[0].sh4Operand}"
+ $asm.puts "fcmp/eq #{sh4Operands([operands[0], SH4_TMP_FPRS[0]])}"
+ $asm.puts "bf #{operands[2].asmLabel}"
+ $asm.puts "tst #{sh4Operands([operands[1], operands[1]])}"
+ $asm.puts "bt #{operands[2].asmLabel}"
+ when "bdnan"
+ emitSH4BranchIfNaN(operands)
+ when "bdneq"
+ emitSH4DoubleCondBranch("eq", true, operands)
+ when "bdgteq"
+ emitSH4DoubleCondBranch("lt", true, operands)
+ when "bdlt"
+ emitSH4DoubleCondBranch("lt", false, operands)
+ when "bdlteq"
+ emitSH4DoubleCondBranch("gt", true, operands)
+ when "bdgt"
+ emitSH4DoubleCondBranch("gt", false, operands)
+ when "baddio", "baddpo", "bsubio", "bsubpo"
+ raise "#{opcode} with #{operands.size} operands is not handled yet" unless operands.size == 3
+ $asm.puts "#{opcode[1, 3]}v #{sh4Operands([operands[0], operands[1]])}"
+ $asm.puts "bt #{operands[2].asmLabel}"
+ when "bmulio", "bmulpo"
+ raise "Invalid operands number (#{operands.size})" unless operands.size == 5
+ $asm.puts "dmuls.l #{sh4Operands([operands[2], operands[3]])}"
+ $asm.puts "sts macl, #{operands[3].sh4Operand}"
+ $asm.puts "cmp/pz #{operands[3].sh4Operand}"
+ $asm.puts "movt #{operands[1].sh4Operand}"
+ $asm.puts "add #-1, #{operands[1].sh4Operand}"
+ $asm.puts "sts mach, #{operands[0].sh4Operand}"
+ $asm.puts "cmp/eq #{sh4Operands([operands[0], operands[1]])}"
+ $asm.puts "bf #{operands[4].asmLabel}"
+ when "btiz", "btpz", "btbz", "btinz", "btpnz", "btbnz"
+ if operands.size == 3
+ $asm.puts "tst #{sh4Operands([operands[0], operands[1]])}"
+ else
+ if operands[0].sh4Operand == "r0"
+ $asm.puts "cmp/eq #0, r0"
+ else
+ $asm.puts "tst #{sh4Operands([operands[0], operands[0]])}"
+ end
+ end
+ emitSH4BranchIfT(operands[-1], (opcode[-2, 2] == "nz"))
+ when "cieq", "cpeq", "cbeq"
+ emitSH4CompareSet("eq", false, operands)
+ when "cineq", "cpneq", "cbneq"
+ emitSH4CompareSet("eq", true, operands)
+ when "cib", "cpb", "cbb"
+ emitSH4CompareSet("hs", true, operands)
+ when "bieq", "bpeq", "bbeq"
+ emitSH4CondBranch("eq", false, operands)
+ when "bineq", "bpneq", "bbneq"
+ emitSH4CondBranch("eq", true, operands)
+ when "bib", "bpb", "bbb"
+ emitSH4CondBranch("hs", true, operands)
+ when "bia", "bpa", "bba"
+ emitSH4CondBranch("hi", false, operands)
+ when "biaeq", "bpaeq"
+ emitSH4CondBranch("hs", false, operands)
+ when "bigteq", "bpgteq", "bbgteq"
+ emitSH4CondBranch("ge", false, operands)
+ when "bilt", "bplt", "bblt"
+ emitSH4CondBranch("ge", true, operands)
+ when "bigt", "bpgt", "bbgt"
+ emitSH4CondBranch("gt", false, operands)
+ when "bilteq", "bplteq", "bblteq"
+ emitSH4CondBranch("gt", true, operands)
+ when "bs"
+ $asm.puts "cmp/pz #{operands[0].sh4Operand}"
+ $asm.puts "bf #{operands[1].asmLabel}"
+ when "call"
+ if operands[0].is_a? LocalLabelReference
+ $asm.puts "bsr #{operands[0].asmLabel}"
+ $asm.puts "nop"
+ elsif operands[0].is_a? RegisterID or operands[0].is_a? SpecialRegister
+ emitSH4Branch("jsr", operands[0])
+ else
+ raise "Unhandled parameters for opcode #{opcode} at #{codeOriginString}"
+ end
+ when "callf"
+ $asm.puts ".balign 4"
+ $asm.puts "mov r0, #{operands[0].sh4Operand}"
+ $asm.puts "mova @(14, PC), r0"
+ $asm.puts "lds r0, pr"
+ $asm.puts "mov.l @(6, PC), #{operands[1].sh4Operand}"
+ $asm.puts "braf #{operands[1].sh4Operand}"
+ $asm.puts "mov #{operands[0].sh4Operand}, r0"
+ $asm.puts ".long #{operands[2].asmLabel}-."
+ when "jmp"
+ if operands[0].is_a? LocalLabelReference
+ $asm.puts "bra #{operands[0].asmLabel}"
+ $asm.puts "nop"
+ elsif operands[0].is_a? RegisterID or operands[0].is_a? SpecialRegister
+ emitSH4Branch("jmp", operands[0])
+ else
+ raise "Unhandled parameters for opcode #{opcode} at #{codeOriginString}"
+ end
+ when "jmpf"
+ emitSH4Load32AndJump(operands[1].asmLabel, operands[0])
+ when "ret"
+ $asm.puts "rts"
+ $asm.puts "nop"
+ when "loadb"
+ $asm.puts "mov.b #{sh4Operands(operands)}"
+ $asm.puts "extu.b #{sh4Operands([operands[1], operands[1]])}"
+ when "storeb"
+ $asm.puts "mov.b #{sh4Operands(operands)}"
+ when "loadh"
+ $asm.puts "mov.w #{sh4Operands(operands)}"
+ $asm.puts "extu.w #{sh4Operands([operands[1], operands[1]])}"
+ when "loadi", "loadis", "loadp", "storei", "storep"
+ $asm.puts "mov.l #{sh4Operands(operands)}"
+ when "move"
+ if operands[0].is_a? Immediate
+ emitSH4LoadImm(operands)
+ else
+ $asm.puts "mov #{sh4Operands(operands)}"
+ end
+ when "leap"
+ if operands[0].is_a? BaseIndex
+ biop = operands[0]
+ $asm.puts "mov #{sh4Operands([biop.index, operands[1]])}"
+ if biop.scaleShift > 0
+ emitSH4ShiftImm(biop.scaleShift, operands[1], "l")
+ end
+ $asm.puts "add #{sh4Operands([biop.base, operands[1]])}"
+ if biop.offset.value != 0
+ $asm.puts "add #{sh4Operands([biop.offset, operands[1]])}"
+ end
+ elsif operands[0].is_a? Address
+ if operands[0].base != operands[1]
+ $asm.puts "mov #{sh4Operands([operands[0].base, operands[1]])}"
+ end
+ if operands[0].offset.value != 0
+ $asm.puts "add #{sh4Operands([operands[0].offset, operands[1]])}"
+ end
+ else
+ raise "Unhandled parameters for opcode #{opcode} at #{codeOriginString}"
+ end
+ when "ldspr"
+ $asm.puts "lds #{sh4Operands(operands)}, pr"
+ when "stspr"
+ $asm.puts "sts pr, #{sh4Operands(operands)}"
+ when "break"
+ # This special opcode always generates an illegal instruction exception.
+ $asm.puts ".word 0xfffd"
+ else
+ raise "Unhandled opcode #{opcode} at #{codeOriginString}"
+ end
+ end
+end
+
diff --git a/Source/JavaScriptCore/offlineasm/x86.rb b/Source/JavaScriptCore/offlineasm/x86.rb
index f78b43912..5e040ba76 100644
--- a/Source/JavaScriptCore/offlineasm/x86.rb
+++ b/Source/JavaScriptCore/offlineasm/x86.rb
@@ -1,4 +1,5 @@
# Copyright (C) 2012 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
@@ -34,6 +35,17 @@ def isX64
end
end
+def useX87
+ case $activeBackend
+ when "X86"
+ true
+ when "X86_64"
+ false
+ else
+ raise "bad value for $activeBackend: #{$activeBackend}"
+ end
+end
+
class SpecialRegister < NoChildren
def x86Operand(kind)
raise unless @name =~ /^r/
@@ -255,6 +267,7 @@ end
class FPRegisterID
def x86Operand(kind)
raise unless kind == :double
+ raise if useX87
case name
when "ft0", "fa0", "fr"
"%xmm0"
@@ -272,6 +285,23 @@ class FPRegisterID
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
+ "%st(#{x87DefaultStackPosition + offset})"
+ end
def x86CallOperand(kind)
"*#{x86Operand(kind)}"
end
@@ -422,7 +452,7 @@ class Instruction
when :quad
isX64 ? "q" : raise
when :double
- "sd"
+ not useX87 ? "sd" : raise
else
raise
end
@@ -478,13 +508,17 @@ class Instruction
end
def handleX86DoubleBranch(branchOpcode, mode)
- case mode
- when :normal
- $asm.puts "ucomisd #{operands[1].x86Operand(:double)}, #{operands[0].x86Operand(:double)}"
- when :reverse
- $asm.puts "ucomisd #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:double)}"
+ if useX87
+ handleX87Compare(mode)
else
- raise mode.inspect
+ case mode
+ when :normal
+ $asm.puts "ucomisd #{operands[1].x86Operand(:double)}, #{operands[0].x86Operand(:double)}"
+ when :reverse
+ $asm.puts "ucomisd #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:double)}"
+ else
+ raise mode.inspect
+ end
end
$asm.puts "#{branchOpcode} #{operands[2].asmLabel}"
end
@@ -584,7 +618,7 @@ class Instruction
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]
@@ -650,6 +684,38 @@ class Instruction
end
end
+ def handleX87Compare(mode)
+ case mode
+ when :normal
+ if (operands[0].x87DefaultStackPosition == 0)
+ $asm.puts "fucomi #{operands[1].x87Operand(0)}"
+ else
+ $asm.puts "fld #{operands[0].x87Operand(0)}"
+ $asm.puts "fucomip #{operands[1].x87Operand(1)}"
+ end
+ when :reverse
+ if (operands[1].x87DefaultStackPosition == 0)
+ $asm.puts "fucomi #{operands[0].x87Operand(0)}"
+ else
+ $asm.puts "fld #{operands[1].x87Operand(0)}"
+ $asm.puts "fucomip #{operands[0].x87Operand(1)}"
+ end
+ else
+ raise mode.inspect
+ end
+ end
+
+ def handleX87BinOp(opcode, opcodereverse)
+ if (operands[1].x87DefaultStackPosition == 0)
+ $asm.puts "#{opcode} #{operands[0].x87Operand(0)}, %st"
+ elsif (operands[0].x87DefaultStackPosition == 0)
+ $asm.puts "#{opcodereverse} %st, #{operands[1].x87Operand(0)}"
+ else
+ $asm.puts "fld #{operands[0].x87Operand(0)}"
+ $asm.puts "#{opcodereverse}p %st, #{operands[1].x87Operand(1)}"
+ end
+ end
+
def lowerX86
raise unless $activeBackend == "X86"
lowerX86Common
@@ -749,22 +815,82 @@ class Instruction
$asm.puts "movswl #{operands[0].x86Operand(:half)}, #{operands[1].x86Operand(:int)}"
when "storeb"
$asm.puts "movb #{x86Operands(:byte, :byte)}"
- when "loadd", "moved", "stored"
- $asm.puts "movsd #{x86Operands(:double, :double)}"
+ when "loadd"
+ if useX87
+ $asm.puts "fldl #{operands[0].x86Operand(:double)}"
+ $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 "fstl #{operands[1].x86Operand(:double)}"
+ else
+ $asm.puts "fld #{operands[0].x87Operand(0)}"
+ $asm.puts "fstpl #{operands[1].x86Operand(:double)}"
+ end
+ else
+ $asm.puts "movsd #{x86Operands(:double, :double)}"
+ end
when "addd"
- $asm.puts "addsd #{x86Operands(:double, :double)}"
- when "divd"
- $asm.puts "divsd #{x86Operands(:double, :double)}"
- when "subd"
- $asm.puts "subsd #{x86Operands(:double, :double)}"
+ if useX87
+ handleX87BinOp("fadd", "fadd")
+ else
+ $asm.puts "addsd #{x86Operands(:double, :double)}"
+ end
when "muld"
- $asm.puts "mulsd #{x86Operands(:double, :double)}"
+ 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"
- $asm.puts "sqrtsd #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:double)}"
+ 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"
- $asm.puts "cvtsi2sd #{operands[0].x86Operand(:int)}, #{operands[1].x86Operand(:double)}"
+ if useX87
+ sp = RegisterID.new(nil, "sp")
+ $asm.puts "movl #{operands[0].x86Operand(:int)}, -4(#{sp.x86Operand(:ptr)})"
+ $asm.puts "fildl -4(#{sp.x86Operand(:ptr)})"
+ $asm.puts "fstp #{operands[1].x87Operand(1)}"
+ else
+ $asm.puts "cvtsi2sd #{operands[0].x86Operand(:int)}, #{operands[1].x86Operand(:double)}"
+ end
when "bdeq"
- $asm.puts "ucomisd #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:double)}"
+ if useX87
+ handleX87Compare(:normal)
+ else
+ $asm.puts "ucomisd #{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}"
@@ -787,7 +913,11 @@ class Instruction
when "bdequn"
handleX86DoubleBranch("je", :normal)
when "bdnequn"
- $asm.puts "ucomisd #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:double)}"
+ if useX87
+ handleX87Compare(:normal)
+ else
+ $asm.puts "ucomisd #{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}"
@@ -809,21 +939,47 @@ class Instruction
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"
- $asm.puts "cvttsd2si #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:int)}"
- $asm.puts "testl #{operands[1].x86Operand(:int)}, #{operands[1].x86Operand(:int)}"
- $asm.puts "je #{operands[2].asmLabel}"
- $asm.puts "cvtsi2sd #{operands[1].x86Operand(:int)}, %xmm7"
- $asm.puts "ucomisd #{operands[0].x86Operand(:double)}, %xmm7"
- $asm.puts "jp #{operands[2].asmLabel}"
- $asm.puts "jne #{operands[2].asmLabel}"
+ 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 "fistpl -4(#{sp.x86Operand(:ptr)})"
+ end
+ $asm.puts "movl -4(#{sp.x86Operand(:ptr)}), #{operands[1].x86Operand(:int)}"
+ $asm.puts "testl #{operands[1].x86Operand(:int)}, #{operands[1].x86Operand(:int)}"
+ $asm.puts "je #{operands[2].asmLabel}"
+ $asm.puts "fildl -4(#{sp.x86Operand(:ptr)})"
+ $asm.puts "fucomip #{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 "testl #{operands[1].x86Operand(:int)}, #{operands[1].x86Operand(:int)}"
+ $asm.puts "je #{operands[2].asmLabel}"
+ $asm.puts "cvtsi2sd #{operands[1].x86Operand(:int)}, %xmm7"
+ $asm.puts "ucomisd #{operands[0].x86Operand(:double)}, %xmm7"
+ $asm.puts "jp #{operands[2].asmLabel}"
+ $asm.puts "jne #{operands[2].asmLabel}"
+ end
when "movdz"
- $asm.puts "xorpd #{operands[0].x86Operand(:double)}, #{operands[0].x86Operand(:double)}"
+ 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"
$asm.puts "pop #{operands[0].x86Operand(:ptr)}"
when "push"
@@ -993,6 +1149,12 @@ class Instruction
when "break"
$asm.puts "int $3"
when "call"
+ if useX87
+ 2.times {
+ | offset |
+ $asm.puts "ffree %st(#{offset})"
+ }
+ end
$asm.puts "call #{operands[0].x86CallOperand(:ptr)}"
when "ret"
$asm.puts "ret"
@@ -1117,19 +1279,57 @@ class Instruction
when "idivi"
$asm.puts "idivl #{operands[0].x86Operand(:int)}"
when "fii2d"
- $asm.puts "movd #{operands[0].x86Operand(:int)}, #{operands[2].x86Operand(:double)}"
- $asm.puts "movd #{operands[1].x86Operand(:int)}, %xmm7"
- $asm.puts "psllq $32, %xmm7"
- $asm.puts "por %xmm7, #{operands[2].x86Operand(:double)}"
+ if useX87
+ sp = RegisterID.new(nil, "sp")
+ $asm.puts "movl #{operands[0].x86Operand(:int)}, -8(#{sp.x86Operand(:ptr)})"
+ $asm.puts "movl #{operands[1].x86Operand(:int)}, -4(#{sp.x86Operand(:ptr)})"
+ $asm.puts "fldl -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"
- $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)}"
+ if useX87
+ sp = RegisterID.new(nil, "sp")
+ if (operands[0].x87DefaultStackPosition == 0)
+ $asm.puts "fstl -8(#{sp.x86Operand(:ptr)})"
+ else
+ $asm.puts "fld #{operands[0].x87Operand(0)}"
+ $asm.puts "fstpl -8(#{sp.x86Operand(:ptr)})"
+ end
+ $asm.puts "movl -8(#{sp.x86Operand(:ptr)}), #{operands[1].x86Operand(:int)}"
+ $asm.puts "movl -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"
- $asm.puts "movd #{operands[0].x86Operand(:quad)}, #{operands[1].x86Operand(:double)}"
+ 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
+ $asm.puts "movq #{operands[0].x86Operand(:quad)}, #{operands[1].x86Operand(:double)}"
+ end
when "fd2q"
- $asm.puts "movd #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:quad)}"
+ if useX87
+ sp = RegisterID.new(nil, "sp")
+ if (operands[0].x87DefaultStackPosition == 0)
+ $asm.puts "fstl -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
+ $asm.puts "movq #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:quad)}"
+ end
when "bo"
$asm.puts "jo #{operands[0].asmLabel}"
when "bs"