diff options
author | Allan Sandfeld Jensen <allan.jensen@digia.com> | 2013-09-13 12:51:20 +0200 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2013-09-19 20:50:05 +0200 |
commit | d441d6f39bb846989d95bcf5caf387b42414718d (patch) | |
tree | e367e64a75991c554930278175d403c072de6bb8 /Source/JavaScriptCore/offlineasm | |
parent | 0060b2994c07842f4c59de64b5e3e430525c4b90 (diff) | |
download | qtwebkit-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.rb | 587 | ||||
-rw-r--r-- | Source/JavaScriptCore/offlineasm/armv7.rb | 531 | ||||
-rw-r--r-- | Source/JavaScriptCore/offlineasm/ast.rb | 12 | ||||
-rw-r--r-- | Source/JavaScriptCore/offlineasm/backends.rb | 9 | ||||
-rw-r--r-- | Source/JavaScriptCore/offlineasm/cloop.rb | 58 | ||||
-rw-r--r-- | Source/JavaScriptCore/offlineasm/instructions.rb | 19 | ||||
-rw-r--r-- | Source/JavaScriptCore/offlineasm/mips.rb | 2 | ||||
-rw-r--r-- | Source/JavaScriptCore/offlineasm/parser.rb | 7 | ||||
-rw-r--r-- | Source/JavaScriptCore/offlineasm/risc.rb | 9 | ||||
-rw-r--r-- | Source/JavaScriptCore/offlineasm/sh4.rb | 778 | ||||
-rw-r--r-- | Source/JavaScriptCore/offlineasm/x86.rb | 276 |
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" |