diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
commit | 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch) | |
tree | 46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/JavaScriptCore/offlineasm/sh4.rb | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Source/JavaScriptCore/offlineasm/sh4.rb')
-rw-r--r-- | Source/JavaScriptCore/offlineasm/sh4.rb | 1072 |
1 files changed, 0 insertions, 1072 deletions
diff --git a/Source/JavaScriptCore/offlineasm/sh4.rb b/Source/JavaScriptCore/offlineasm/sh4.rb deleted file mode 100644 index a804b29cc..000000000 --- a/Source/JavaScriptCore/offlineasm/sh4.rb +++ /dev/null @@ -1,1072 +0,0 @@ -# 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 "t0" - "r0" - when "t1" - "r1" - when "t2" - "r2" - when "t3" - "r10" - when "t4", "a0" - "r4" - when "t5", "a1" - "r5" - when "t6", "a2" - "r6" - when "t7", "a3" - "r7" - when "t8" - "r8" - when "t9" - "r9" - 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 - -class ConstPool < Node - attr_reader :size - attr_reader :entries - - def initialize(codeOrigin, entries, size) - super(codeOrigin) - raise "Invalid size #{size} for ConstPool" unless size == 16 or size == 32 - @size = size - @entries = entries - end - - def dump - "#{size}: #{entries}" - end - - def address? - false - end - - def label? - false - end - - def immediate? - false - end - - def register? - false - end - - def lowerSH4 - if size == 16 - $asm.puts ".balign 2" - else - $asm.puts ".balign 4" - end - entries.map { - |e| - e.label.lower("SH4") - if e.size == 16 - $asm.puts ".word #{e.value}" - else - $asm.puts ".long #{e.value}" - end - } - end -end - -class ConstPoolEntry < Node - attr_reader :size - attr_reader :value - attr_reader :label - attr_reader :labelref - - def initialize(codeOrigin, value, size) - super(codeOrigin) - raise "Invalid size #{size} for ConstPoolEntry" unless size == 16 or size == 32 - @size = size - @value = value - @label = LocalLabel.unique("constpool#{size}") - @labelref = LocalLabelReference.new(codeOrigin, label) - end - - def dump - "#{value} (#{size} @ #{label})" - end - - def ==(other) - other.is_a? ConstPoolEntry and other.value == @value - end - - def address? - false - end - - def label? - false - end - - def immediate? - false - end - - def register? - false - 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 - operands = node.operands - newOperands = [] - operands.each { - | operand | - if operand.is_a? LabelReference - tmp = Tmp.new(operand.codeOrigin, :gpr) - newList << Instruction.new(operand.codeOrigin, "move", [operand, tmp]) - newOperands << tmp - else - newOperands << operand - end - } - newList << Instruction.new(node.codeOrigin, node.opcode, newOperands, node.annotation) - else - newList << node - end - } - newList -end - - -# -# Lowering of misplaced special registers for SH4. For example: -# -# storep pr, foo -# -# becomes: -# -# stspr tmp -# storep tmp, foo -# - -def sh4LowerMisplacedSpecialRegisters(list) - newList = [] - list.each { - | node | - if node.is_a? Instruction - case node.opcode - when "move" - if node.operands[0].is_a? RegisterID and node.operands[0].sh4Operand == "pr" - newList << Instruction.new(codeOrigin, "stspr", [node.operands[1]]) - elsif node.operands[1].is_a? RegisterID and node.operands[1].sh4Operand == "pr" - newList << Instruction.new(codeOrigin, "ldspr", [node.operands[0]]) - else - newList << node - end - when "loadi", "loadis", "loadp" - if node.operands[1].is_a? RegisterID and node.operands[1].sh4Operand == "pr" - tmp = Tmp.new(codeOrigin, :gpr) - newList << Instruction.new(codeOrigin, node.opcode, [node.operands[0], tmp]) - newList << Instruction.new(codeOrigin, "ldspr", [tmp]) - else - newList << node - end - when "storei", "storep" - if node.operands[0].is_a? RegisterID and node.operands[0].sh4Operand == "pr" - tmp = Tmp.new(codeOrigin, :gpr) - newList << Instruction.new(codeOrigin, "stspr", [tmp]) - newList << Instruction.new(codeOrigin, node.opcode, [tmp, node.operands[1]]) - else - newList << node - end - else - newList << node - end - else - newList << node - end - } - newList -end - - -# -# Group immediate values outside -128..127 range into constant pools for SH4. -# These constant pools will be placed behind non-return opcodes jmp and ret, for example: -# -# move 1024, foo -# ... -# ret -# -# becomes: -# -# move [label], foo -# ... -# ret -# label: 1024 -# - -def sh4LowerConstPool(list) - newList = [] - currentPool16 = [] - currentPool32 = [] - list.each { - | node | - if node.is_a? Instruction - case node.opcode - when "jmp", "ret" - newList << node - if not currentPool16.empty? - newList << ConstPool.new(codeOrigin, currentPool16, 16) - currentPool16 = [] - end - if not currentPool32.empty? - newList << ConstPool.new(codeOrigin, currentPool32, 32) - currentPool32 = [] - end - when "move" - if node.operands[0].is_a? Immediate and not (-128..127).include? node.operands[0].value - poolEntry = nil - if (-32768..32767).include? node.operands[0].value - currentPool16.each { |e| - if e.value == node.operands[0].value - poolEntry = e - end - } - if !poolEntry - poolEntry = ConstPoolEntry.new(codeOrigin, node.operands[0].value, 16) - currentPool16 << poolEntry - end - else - currentPool32.each { |e| - if e.value == node.operands[0].value - poolEntry = e - end - } - if !poolEntry - poolEntry = ConstPoolEntry.new(codeOrigin, node.operands[0].value, 32) - currentPool32 << poolEntry - end - end - newList << Instruction.new(codeOrigin, "move", [poolEntry, node.operands[1]]) - elsif node.operands[0].is_a? LabelReference - poolEntry = nil - currentPool32.each { |e| - if e.value == node.operands[0].asmLabel - poolEntry = e - end - } - if !poolEntry - poolEntry = ConstPoolEntry.new(codeOrigin, node.operands[0].asmLabel, 32) - currentPool32 << poolEntry - end - newList << Instruction.new(codeOrigin, "move", [poolEntry, node.operands[1]]) - else - newList << node - end - else - newList << node - end - else - newList << node - end - } - if not currentPool16.empty? - newList << ConstPool.new(codeOrigin, currentPool16, 16) - end - if not currentPool32.empty? - newList << ConstPool.new(codeOrigin, currentPool32, 32) - end - newList -end - - -# -# Lowering of argument setup for SH4. -# This phase avoids argument register trampling. For example, if a0 == t4: -# -# setargs t1, t4 -# -# becomes: -# -# move t4, a1 -# move t1, a0 -# - -def sh4LowerArgumentSetup(list) - a0 = RegisterID.forName(codeOrigin, "a0") - a1 = RegisterID.forName(codeOrigin, "a1") - a2 = RegisterID.forName(codeOrigin, "a2") - a3 = RegisterID.forName(codeOrigin, "a3") - newList = [] - list.each { - | node | - if node.is_a? Instruction - case node.opcode - when "setargs" - if node.operands.size == 2 - if node.operands[1].sh4Operand != a0.sh4Operand - newList << Instruction.new(codeOrigin, "move", [node.operands[0], a0]) - newList << Instruction.new(codeOrigin, "move", [node.operands[1], a1]) - elsif node.operands[0].sh4Operand != a1.sh4Operand - newList << Instruction.new(codeOrigin, "move", [node.operands[1], a1]) - newList << Instruction.new(codeOrigin, "move", [node.operands[0], a0]) - else - # As (operands[0] == a1) and (operands[1] == a0), we just need to swap a0 and a1. - newList << Instruction.new(codeOrigin, "xori", [a0, a1]) - newList << Instruction.new(codeOrigin, "xori", [a1, a0]) - newList << Instruction.new(codeOrigin, "xori", [a0, a1]) - end - elsif node.operands.size == 4 - # FIXME: We just raise an error if something is likely to go wrong for now. - # It would be better to implement a recovering algorithm. - if (node.operands[0].sh4Operand == a1.sh4Operand) or - (node.operands[0].sh4Operand == a2.sh4Operand) or - (node.operands[0].sh4Operand == a3.sh4Operand) or - (node.operands[1].sh4Operand == a0.sh4Operand) or - (node.operands[1].sh4Operand == a2.sh4Operand) or - (node.operands[1].sh4Operand == a3.sh4Operand) or - (node.operands[2].sh4Operand == a0.sh4Operand) or - (node.operands[2].sh4Operand == a1.sh4Operand) or - (node.operands[2].sh4Operand == a3.sh4Operand) or - (node.operands[3].sh4Operand == a0.sh4Operand) or - (node.operands[3].sh4Operand == a1.sh4Operand) or - (node.operands[3].sh4Operand == a2.sh4Operand) - raise "Potential argument register trampling detected." - end - - newList << Instruction.new(codeOrigin, "move", [node.operands[0], a0]) - newList << Instruction.new(codeOrigin, "move", [node.operands[1], a1]) - newList << Instruction.new(codeOrigin, "move", [node.operands[2], a2]) - newList << Instruction.new(codeOrigin, "move", [node.operands[3], a3]) - else - raise "Invalid operands number (#{node.operands.size}) for setargs" - 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 = riscLowerMisplacedAddresses(result) - result = sh4LowerMisplacedLabels(result) - result = sh4LowerMisplacedSpecialRegisters(result) - - result = assignRegistersToTemporaries(result, :gpr, SH4_TMP_GPRS) - result = assignRegistersToTemporaries(result, :gpr, SH4_TMP_FPRS) - - result = sh4LowerConstPool(result) - result = sh4LowerArgumentSetup(result) - - return result - end -end - -def sh4Operands(operands) - operands.map{|v| v.sh4Operand}.join(", ") -end - -def emitSH4Branch(sh4opcode, operand) - raise "Invalid operand #{operand}" unless operand.is_a? RegisterID or operand.is_a? SpecialRegister - $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(dest, neg) - outlabel = LocalLabel.unique("branchIfT") - sh4opcode = neg ? "bt" : "bf" - $asm.puts "#{sh4opcode} #{LocalLabelReference.new(codeOrigin, outlabel).asmLabel}" - if dest.is_a? LocalLabelReference - $asm.puts "bra #{dest.asmLabel}" - $asm.puts "nop" - else - emitSH4Branch("jmp", dest) - 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" - if operands.size == 3 - if operands[1].sh4Operand == operands[2].sh4Operand - $asm.puts "neg #{sh4Operands([operands[2], operands[2]])}" - $asm.puts "add #{sh4Operands([operands[0], operands[2]])}" - else - $asm.puts "mov #{sh4Operands([operands[0], operands[2]])}" - $asm.puts "sub #{sh4Operands([operands[1], operands[2]])}" - end - else - 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 - 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 "bibeq", "bpbeq" - emitSH4CondBranch("hi", true, 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 "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 "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? ConstPoolEntry - if operands[0].size == 16 - $asm.puts "mov.w #{operands[0].labelref.asmLabel}, #{operands[1].sh4Operand}" - else - $asm.puts "mov.l #{operands[0].labelref.asmLabel}, #{operands[1].sh4Operand}" - end - elsif operands[0].sh4Operand != operands[1].sh4Operand - $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 "memfence" - $asm.puts "synco" - when "popCalleeSaves" - $asm.puts "mov.l @r15+, r8" - $asm.puts "mov.l @r15+, r9" - $asm.puts "mov.l @r15+, r10" - $asm.puts "mov.l @r15+, r11" - $asm.puts "mov.l @r15+, r13" - $asm.puts "lds.l @r15+, pr" - $asm.puts "mov.l @r15+, r14" - when "pushCalleeSaves" - $asm.puts "mov.l r14, @-r15" - $asm.puts "sts.l pr, @-r15" - $asm.puts "mov.l r13, @-r15" - $asm.puts "mov.l r11, @-r15" - $asm.puts "mov.l r10, @-r15" - $asm.puts "mov.l r9, @-r15" - $asm.puts "mov.l r8, @-r15" - when "break" - # This special opcode always generates an illegal instruction exception. - $asm.puts ".word 0xfffd" - else - lowerDefault - end - end -end - |