summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/offlineasm
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@digia.com>2012-10-22 15:40:17 +0200
committerSimon Hausmann <simon.hausmann@digia.com>2012-10-22 15:40:17 +0200
commit43a42f108af6bcbd91f2672731c3047c26213af1 (patch)
tree7fa092e5f5d873c72f2486a70e26be26f7a38bec /Source/JavaScriptCore/offlineasm
parentd9cf437c840c6eb7417bdd97e6c40979255d3158 (diff)
downloadqtwebkit-43a42f108af6bcbd91f2672731c3047c26213af1.tar.gz
Imported WebKit commit 302e7806bff028bd1167a1ec7c86a1ee00ecfb49 (http://svn.webkit.org/repository/webkit/trunk@132067)
New snapshot that fixes build without QtWidgets
Diffstat (limited to 'Source/JavaScriptCore/offlineasm')
-rw-r--r--Source/JavaScriptCore/offlineasm/armv7.rb535
-rw-r--r--Source/JavaScriptCore/offlineasm/risc.rb555
2 files changed, 581 insertions, 509 deletions
diff --git a/Source/JavaScriptCore/offlineasm/armv7.rb b/Source/JavaScriptCore/offlineasm/armv7.rb
index 07543574e..ab0496f71 100644
--- a/Source/JavaScriptCore/offlineasm/armv7.rb
+++ b/Source/JavaScriptCore/offlineasm/armv7.rb
@@ -1,4 +1,4 @@
-# Copyright (C) 2011 Apple Inc. All rights reserved.
+# 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
@@ -24,6 +24,7 @@
require "config"
require "ast"
require "opt"
+require "risc"
class Node
def armV7Single
@@ -33,7 +34,7 @@ class Node
end
end
-class SpecialRegister < NoChildren
+class SpecialRegister
def armV7Operand
@name
end
@@ -133,487 +134,6 @@ class AbsoluteAddress
end
#
-# Lowering of branch ops. For example:
-#
-# baddiz foo, bar, baz
-#
-# will become:
-#
-# addi foo, bar
-# bz baz
-#
-
-def armV7LowerBranchOps(list)
- newList = []
- list.each {
- | node |
- if node.is_a? Instruction
- annotation = node.annotation
- case node.opcode
- when /^b(addi|subi|ori|addp)/
- op = $1
- branch = "b" + $~.post_match
-
- case op
- when "addi", "addp"
- op = "addis"
- when "subi"
- op = "subis"
- when "ori"
- op = "oris"
- end
-
- newList << Instruction.new(node.codeOrigin, op, node.operands[0..-2], annotation)
- newList << Instruction.new(node.codeOrigin, branch, [node.operands[-1]])
- when "bmulio"
- tmp1 = Tmp.new(node.codeOrigin, :gpr)
- tmp2 = Tmp.new(node.codeOrigin, :gpr)
- newList << Instruction.new(node.codeOrigin, "smulli", [node.operands[0], node.operands[1], node.operands[1], tmp1], annotation)
- newList << Instruction.new(node.codeOrigin, "rshifti", [node.operands[-2], Immediate.new(node.codeOrigin, 31), tmp2])
- newList << Instruction.new(node.codeOrigin, "bineq", [tmp1, tmp2, node.operands[-1]])
- when /^bmuli/
- condition = $~.post_match
- newList << Instruction.new(node.codeOrigin, "muli", node.operands[0..-2], annotation)
- newList << Instruction.new(node.codeOrigin, "bti" + condition, [node.operands[-2], node.operands[-1]])
- else
- newList << node
- end
- else
- newList << node
- end
- }
- newList
-end
-
-#
-# Lowering of shift ops. For example:
-#
-# lshifti foo, bar
-#
-# will become:
-#
-# andi foo, 31, tmp
-# lshifti tmp, bar
-#
-
-def armV7SanitizeShift(operand, list)
- return operand if operand.immediate?
-
- tmp = Tmp.new(operand.codeOrigin, :gpr)
- list << Instruction.new(operand.codeOrigin, "andi", [operand, Immediate.new(operand.codeOrigin, 31), tmp])
- tmp
-end
-
-def armV7LowerShiftOps(list)
- newList = []
- list.each {
- | node |
- if node.is_a? Instruction
- case node.opcode
- when "lshifti", "rshifti", "urshifti", "lshiftp", "rshiftp", "urshiftp"
- if node.operands.size == 2
- newList << Instruction.new(node.codeOrigin, node.opcode, [armV7SanitizeShift(node.operands[0], newList), node.operands[1]], node.annotation)
- else
- newList << Instruction.new(node.codeOrigin, node.opcode, [node.operands[0], armV7SanitizeShift(node.operands[1], newList), node.operands[2]], node.annotation)
- raise "Wrong number of operands for shift at #{node.codeOriginString}" unless node.operands.size == 3
- end
- else
- newList << node
- end
- else
- newList << node
- end
- }
- newList
-end
-
-#
-# Lowering of malformed addresses. For example:
-#
-# loadp 10000[foo], bar
-#
-# will become:
-#
-# move 10000, tmp
-# addp foo, tmp
-# loadp 0[tmp], bar
-#
-
-class Node
- def armV7LowerMalformedAddressesRecurse(list)
- mapChildren {
- | node |
- node.armV7LowerMalformedAddressesRecurse(list)
- }
- end
-end
-
-class Address
- def armV7LowerMalformedAddressesRecurse(list)
- if offset.value < -0xff or offset.value > 0xfff
- tmp = Tmp.new(codeOrigin, :gpr)
- list << Instruction.new(codeOrigin, "move", [offset, tmp])
- list << Instruction.new(codeOrigin, "addp", [base, tmp])
- Address.new(codeOrigin, tmp, Immediate.new(codeOrigin, 0))
- else
- self
- end
- end
-end
-
-class BaseIndex
- def armV7LowerMalformedAddressesRecurse(list)
- if offset.value != 0
- tmp = Tmp.new(codeOrigin, :gpr)
- list << Instruction.new(codeOrigin, "move", [offset, tmp])
- list << Instruction.new(codeOrigin, "addp", [base, tmp])
- BaseIndex.new(codeOrigin, tmp, index, scale, Immediate.new(codeOrigin, 0))
- else
- self
- end
- end
-end
-
-class AbsoluteAddress
- def armV7LowerMalformedAddressesRecurse(list)
- tmp = Tmp.new(codeOrigin, :gpr)
- list << Instruction.new(codeOrigin, "move", [address, tmp])
- Address.new(codeOrigin, tmp, Immediate.new(codeOrigin, 0))
- end
-end
-
-def armV7LowerMalformedAddresses(list)
- newList = []
- list.each {
- | node |
- newList << node.armV7LowerMalformedAddressesRecurse(newList)
- }
- newList
-end
-
-#
-# Lowering of malformed addresses in double loads and stores. For example:
-#
-# loadd [foo, bar, 8], baz
-#
-# becomes:
-#
-# leap [foo, bar, 8], tmp
-# loadd [tmp], baz
-#
-
-class Node
- def armV7DoubleAddress(list)
- self
- end
-end
-
-class BaseIndex
- def armV7DoubleAddress(list)
- tmp = Tmp.new(codeOrigin, :gpr)
- list << Instruction.new(codeOrigin, "leap", [self, tmp])
- Address.new(codeOrigin, tmp, Immediate.new(codeOrigin, 0))
- end
-end
-
-def armV7LowerMalformedAddressesDouble(list)
- newList = []
- list.each {
- | node |
- if node.is_a? Instruction
- case node.opcode
- when "loadd"
- newList << Instruction.new(node.codeOrigin, "loadd", [node.operands[0].armV7DoubleAddress(newList), node.operands[1]], node.annotation)
- when "stored"
- newList << Instruction.new(node.codeOrigin, "stored", [node.operands[0], node.operands[1].armV7DoubleAddress(newList)], node.annotation)
- else
- newList << node
- end
- else
- newList << node
- end
- }
- newList
-end
-
-#
-# Lowering of misplaced immediates. For example:
-#
-# storei 0, [foo]
-#
-# will become:
-#
-# move 0, tmp
-# storei tmp, [foo]
-#
-
-def armV7LowerMisplacedImmediates(list)
- newList = []
- list.each {
- | node |
- if node.is_a? Instruction
- case node.opcode
- when "storeb", "storei", "storep"
- operands = node.operands
- newOperands = []
- operands.each {
- | operand |
- if operand.is_a? Immediate
- 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
- else
- newList << node
- end
- }
- newList
-end
-
-#
-# Lowering of malformed immediates except when used in a "move" instruction.
-# For example:
-#
-# addp 642641, foo
-#
-# will become:
-#
-# move 642641, tmp
-# addp tmp, foo
-#
-
-class Node
- def armV7LowerMalformedImmediatesRecurse(list)
- mapChildren {
- | node |
- node.armV7LowerMalformedImmediatesRecurse(list)
- }
- end
-end
-
-class Address
- def armV7LowerMalformedImmediatesRecurse(list)
- self
- end
-end
-
-class BaseIndex
- def armV7LowerMalformedImmediatesRecurse(list)
- self
- end
-end
-
-class AbsoluteAddress
- def armV7LowerMalformedImmediatesRecurse(list)
- self
- end
-end
-
-class Immediate
- def armV7LowerMalformedImmediatesRecurse(list)
- if value < 0 or value > 255
- tmp = Tmp.new(codeOrigin, :gpr)
- list << Instruction.new(codeOrigin, "move", [self, tmp])
- tmp
- else
- self
- end
- end
-end
-
-def armV7LowerMalformedImmediates(list)
- newList = []
- list.each {
- | node |
- if node.is_a? Instruction
- annotation = node.annotation
- case node.opcode
- when "move"
- newList << node
- when "addi", "addp", "addis", "subi", "subp", "subis"
- if node.operands[0].is_a? Immediate and
- node.operands[0].value < 0 and
- node.operands[0].value >= 255 and
- node.operands.size == 2
- if node.opcode =~ /add/
- newOpcode = "sub" + node.opcode[-1..-1]
- else
- newOpcode = "add" + node.opcode[-1..-1]
- end
- newList << Instruction.new(node.codeOrigin, newOpcode,
- [Immediate.new(-node.operands[0].value)] + node.operands[1..-1],
- annotation)
- else
- newList << node.armV7LowerMalformedImmediatesRecurse(newList)
- end
- when "muli", "mulp"
- if node.operands[0].is_a? Immediate
- tmp = Tmp.new(codeOrigin, :gpr)
- newList << Instruction.new(node.codeOrigin, "move", [node.operands[0], tmp], annotation)
- newList << Instruction.new(node.codeOrigin, "muli", [tmp] + node.operands[1..-1])
- else
- newList << node.armV7LowerMalformedImmediatesRecurse(newList)
- end
- else
- newList << node.armV7LowerMalformedImmediatesRecurse(newList)
- end
- else
- newList << node
- end
- }
- newList
-end
-
-#
-# Lowering of misplaced addresses. For example:
-#
-# addi foo, [bar]
-#
-# will become:
-#
-# loadi [bar], tmp
-# addi foo, tmp
-# storei tmp, [bar]
-#
-# Another example:
-#
-# addi [foo], bar
-#
-# will become:
-#
-# loadi [foo], tmp
-# addi tmp, bar
-#
-
-def armV7AsRegister(preList, postList, operand, suffix, needStore)
- return operand unless operand.address?
-
- tmp = Tmp.new(operand.codeOrigin, if suffix == "d" then :fpr else :gpr end)
- preList << Instruction.new(operand.codeOrigin, "load" + suffix, [operand, tmp])
- if needStore
- postList << Instruction.new(operand.codeOrigin, "store" + suffix, [tmp, operand])
- end
- tmp
-end
-
-def armV7AsRegisters(preList, postList, operands, suffix)
- newOperands = []
- operands.each_with_index {
- | operand, index |
- newOperands << armV7AsRegister(preList, postList, operand, suffix, index == operands.size - 1)
- }
- newOperands
-end
-
-def armV7LowerMisplacedAddresses(list)
- newList = []
- list.each {
- | node |
- if node.is_a? Instruction
- postInstructions = []
- annotation = node.annotation
- case node.opcode
- when "addi", "addp", "addis", "andi", "andp", "lshifti", "lshiftp", "muli", "mulp", "negi",
- "negp", "noti", "ori", "oris", "orp", "rshifti", "urshifti", "rshiftp", "urshiftp", "subi",
- "subp", "subis", "xori", "xorp", /^bi/, /^bp/, /^bti/, /^btp/, /^ci/, /^cp/, /^ti/
- newList << Instruction.new(node.codeOrigin,
- node.opcode,
- armV7AsRegisters(newList, postInstructions, node.operands, "i"),
- annotation)
- when "bbeq", "bbneq", "bba", "bbaeq", "bbb", "bbbeq", "btbz", "btbnz", "tbz", "tbnz",
- "cbeq", "cbneq", "cba", "cbaeq", "cbb", "cbbeq"
- newList << Instruction.new(node.codeOrigin,
- node.opcode,
- armV7AsRegisters(newList, postInstructions, node.operands, "b"),
- annotation)
- when "bbgt", "bbgteq", "bblt", "bblteq", "btbs", "tbs", "cbgt", "cbgteq", "cblt", "cblteq"
- newList << Instruction.new(node.codeOrigin,
- node.opcode,
- armV7AsRegisters(newList, postInstructions, node.operands, "bs"),
- annotation)
- when "addd", "divd", "subd", "muld", "sqrtd", /^bd/
- newList << Instruction.new(node.codeOrigin,
- node.opcode,
- armV7AsRegisters(newList, postInstructions, node.operands, "d"),
- annotation)
- when "jmp", "call"
- newList << Instruction.new(node.codeOrigin,
- node.opcode,
- [armV7AsRegister(newList, postInstructions, node.operands[0], "p", false)],
- annotation)
- else
- newList << node
- end
- newList += postInstructions
- else
- newList << node
- end
- }
- newList
-end
-
-#
-# Lowering of register reuse in compare instructions. For example:
-#
-# cieq t0, t1, t0
-#
-# will become:
-#
-# mov tmp, t0
-# cieq tmp, t1, t0
-#
-
-def armV7LowerRegisterReuse(list)
- newList = []
- list.each {
- | node |
- if node.is_a? Instruction
- annotation = node.annotation
- case node.opcode
- when "cieq", "cineq", "cia", "ciaeq", "cib", "cibeq", "cigt", "cigteq", "cilt", "cilteq",
- "cpeq", "cpneq", "cpa", "cpaeq", "cpb", "cpbeq", "cpgt", "cpgteq", "cplt", "cplteq",
- "tis", "tiz", "tinz", "tbs", "tbz", "tbnz", "tps", "tpz", "tpnz", "cbeq", "cbneq",
- "cba", "cbaeq", "cbb", "cbbeq", "cbgt", "cbgteq", "cblt", "cblteq"
- if node.operands.size == 2
- if node.operands[0] == node.operands[1]
- tmp = Tmp.new(node.codeOrigin, :gpr)
- newList << Instruction.new(node.codeOrigin, "move", [node.operands[0], tmp], annotation)
- newList << Instruction.new(node.codeOrigin, node.opcode, [tmp, node.operands[1]])
- else
- newList << node
- end
- else
- raise "Wrong number of arguments at #{node.codeOriginString}" unless node.operands.size == 3
- if node.operands[0] == node.operands[2]
- tmp = Tmp.new(node.codeOrigin, :gpr)
- newList << Instruction.new(node.codeOrigin, "move", [node.operands[0], tmp], annotation)
- newList << Instruction.new(node.codeOrigin, node.opcode, [tmp, node.operands[1], node.operands[2]])
- elsif node.operands[1] == node.operands[2]
- tmp = Tmp.new(node.codeOrigin, :gpr)
- newList << Instruction.new(node.codeOrigin, "move", [node.operands[1], tmp], annotation)
- newList << Instruction.new(node.codeOrigin, node.opcode, [node.operands[0], tmp, node.operands[2]])
- else
- newList << node
- end
- end
- else
- newList << node
- end
- else
- newList << node
- end
- }
- newList
-end
-
-#
# Lea support.
#
@@ -642,31 +162,28 @@ end
class Sequence
def getModifiedListARMv7
- myList = @list
-
- # Verify that we will only see instructions and labels.
- myList.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}"
+ 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
}
-
- myList = armV7LowerBranchOps(myList)
- myList = armV7LowerShiftOps(myList)
- myList = armV7LowerMalformedAddresses(myList)
- myList = armV7LowerMalformedAddressesDouble(myList)
- myList = armV7LowerMisplacedImmediates(myList)
- myList = armV7LowerMalformedImmediates(myList)
- myList = armV7LowerMisplacedAddresses(myList)
- myList = armV7LowerRegisterReuse(myList)
- myList = assignRegistersToTemporaries(myList, :gpr, ARMv7_EXTRA_GPRS)
- myList = assignRegistersToTemporaries(myList, :fpr, ARMv7_EXTRA_FPRS)
-
- return myList
+ 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
@@ -747,8 +264,8 @@ class Instruction
$asm.annotation annotation if $enableInstrAnnotations
case opcode
- when "addi", "addp", "addis"
- if opcode == "addis"
+ when "addi", "addp", "addis", "addps"
+ if opcode == "addis" or opcode == "addps"
suffix = "s"
else
suffix = ""
@@ -837,7 +354,7 @@ class Instruction
$asm.puts "vcmpe.f64 #{armV7Operands(operands[0..1])}"
$asm.puts "vmrs apsr_nzcv, fpscr"
isUnordered = LocalLabel.unique("bdneq")
- $asm.puts "bvs #{LabelReference.new(codeOrigin, isUnordered).asmLabel}"
+ $asm.puts "bvs #{LocalLabelReference.new(codeOrigin, isUnordered).asmLabel}"
$asm.puts "bne #{operands[2].asmLabel}"
isUnordered.lower("ARMv7")
when "bdgt"
diff --git a/Source/JavaScriptCore/offlineasm/risc.rb b/Source/JavaScriptCore/offlineasm/risc.rb
new file mode 100644
index 000000000..44b4dbd71
--- /dev/null
+++ b/Source/JavaScriptCore/offlineasm/risc.rb
@@ -0,0 +1,555 @@
+# 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'
+
+# This file contains utilities that are useful for implementing a backend
+# for RISC-like processors (ARM, MIPS, etc).
+
+#
+# Lowering of simple branch ops. For example:
+#
+# baddiz foo, bar, baz
+#
+# will become:
+#
+# addi foo, bar
+# bz baz
+#
+
+def riscLowerSimpleBranchOps(list)
+ newList = []
+ list.each {
+ | node |
+ if node.is_a? Instruction
+ annotation = node.annotation
+ case node.opcode
+ when /^b(addi|subi|ori|addp)/
+ op = $1
+ branch = "b" + $~.post_match
+
+ case op
+ when "addi"
+ op = "addis"
+ when "addp"
+ op = "addps"
+ when "subi"
+ op = "subis"
+ when "ori"
+ op = "oris"
+ end
+
+ newList << Instruction.new(node.codeOrigin, op, node.operands[0..-2], annotation)
+ newList << Instruction.new(node.codeOrigin, branch, [node.operands[-1]])
+ when 'bmulis', 'bmulz', 'bmulnz'
+ condition = $~.post_match
+ newList << Instruction.new(node.codeOrigin, "muli", node.operands[0..-2], annotation)
+ newList << Instruction.new(node.codeOrigin, "bti" + condition, [node.operands[-2], node.operands[-1]])
+ else
+ newList << node
+ end
+ else
+ newList << node
+ end
+ }
+ newList
+end
+
+#
+# Lowing of complex branch ops. For example:
+#
+# bmulio foo, bar, baz
+#
+# becomes:
+#
+# smulli foo, bar, bar, tmp1
+# rshifti bar, 31, tmp2
+# bineq tmp1, tmp2, baz
+#
+
+def riscLowerHardBranchOps(list)
+ newList = []
+ list.each {
+ | node |
+ if node.is_a? Instruction and node.opcode == "bmulio"
+ tmp1 = Tmp.new(node.codeOrigin, :gpr)
+ tmp2 = Tmp.new(node.codeOrigin, :gpr)
+ newList << Instruction.new(node.codeOrigin, "smulli", [node.operands[0], node.operands[1], node.operands[1], tmp1], node.annotation)
+ newList << Instruction.new(node.codeOrigin, "rshifti", [node.operands[-2], Immediate.new(node.codeOrigin, 31), tmp2])
+ newList << Instruction.new(node.codeOrigin, "bineq", [tmp1, tmp2, node.operands[-1]])
+ else
+ newList << node
+ end
+ }
+ newList
+end
+
+#
+# Lowering of shift ops. For example:
+#
+# lshifti foo, bar
+#
+# will become:
+#
+# andi foo, 31, tmp
+# lshifti tmp, bar
+#
+
+def riscSanitizeShift(operand, list)
+ return operand if operand.immediate?
+
+ tmp = Tmp.new(operand.codeOrigin, :gpr)
+ list << Instruction.new(operand.codeOrigin, "andi", [operand, Immediate.new(operand.codeOrigin, 31), tmp])
+ tmp
+end
+
+def riscLowerShiftOps(list)
+ newList = []
+ list.each {
+ | node |
+ if node.is_a? Instruction
+ case node.opcode
+ when "lshifti", "rshifti", "urshifti", "lshiftp", "rshiftp", "urshiftp"
+ if node.operands.size == 2
+ newList << Instruction.new(node.codeOrigin, node.opcode, [riscSanitizeShift(node.operands[0], newList), node.operands[1]], node.annotation)
+ else
+ newList << Instruction.new(node.codeOrigin, node.opcode, [node.operands[0], riscSanitizeShift(node.operands[1], newList), node.operands[2]], node.annotation)
+ raise "Wrong number of operands for shift at #{node.codeOriginString}" unless node.operands.size == 3
+ end
+ else
+ newList << node
+ end
+ else
+ newList << node
+ end
+ }
+ newList
+end
+
+#
+# Lowering of malformed addresses. For example:
+#
+# loadp 10000[foo], bar
+#
+# will become:
+#
+# move 10000, tmp
+# addp foo, tmp
+# loadp 0[tmp], bar
+#
+# Note that you use this lowering phase by passing it a block that returns true
+# if you don't want to lower the address, or false if you do. For example to get
+# the effect of the example above, the block would have to say something like:
+#
+# riscLowerMalformedAddresses(thingy) {
+# | node, address |
+# if address.is_a? Address
+# address.offset.value > 1000
+# else
+# true # don't lower anything else, in this example
+# end
+# }
+#
+# See armv7.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).
+#
+
+class Node
+ def riscLowerMalformedAddressesRecurse(list, topLevelNode, &block)
+ mapChildren {
+ | subNode |
+ subNode.riscLowerMalformedAddressesRecurse(list, topLevelNode, &block)
+ }
+ end
+end
+
+class Address
+ def riscLowerMalformedAddressesRecurse(list, node)
+ return self if yield node, self
+
+ tmp = Tmp.new(codeOrigin, :gpr)
+ list << Instruction.new(codeOrigin, "move", [offset, tmp])
+ list << Instruction.new(codeOrigin, "addp", [base, tmp])
+ Address.new(codeOrigin, tmp, Immediate.new(codeOrigin, 0))
+ end
+end
+
+class BaseIndex
+ def riscLowerMalformedAddressesRecurse(list, node, &block)
+ return self if yield node, self
+
+ tmp = Tmp.new(codeOrigin, :gpr)
+ list << Instruction.new(codeOrigin, "leap", [BaseIndex.new(codeOrigin, base, index, scale, Immediate.new(codeOrigin, 0)), tmp])
+ Address.new(codeOrigin, tmp, offset).riscLowerMalformedAddressesRecurse(list, node, &block)
+ end
+end
+
+class AbsoluteAddress
+ def riscLowerMalformedAddressesRecurse(list, node)
+ return self if yield node, self
+
+ tmp = Tmp.new(codeOrigin, :gpr)
+ list << Instruction.new(codeOrigin, "move", [address, tmp])
+ Address.new(codeOrigin, tmp, Immediate.new(codeOrigin, 0))
+ end
+end
+
+def riscLowerMalformedAddresses(list, &block)
+ newList = []
+ list.each {
+ | node |
+ newList << node.riscLowerMalformedAddressesRecurse(newList, node, &block)
+ }
+ newList
+end
+
+#
+# Lowering of malformed addresses in double loads and stores. For example:
+#
+# loadd [foo, bar, 8], baz
+#
+# becomes:
+#
+# leap [foo, bar, 8], tmp
+# loadd [tmp], baz
+#
+
+class Node
+ def riscDoubleAddress(list)
+ self
+ end
+end
+
+class BaseIndex
+ def riscDoubleAddress(list)
+ tmp = Tmp.new(codeOrigin, :gpr)
+ list << Instruction.new(codeOrigin, "leap", [self, tmp])
+ Address.new(codeOrigin, tmp, Immediate.new(codeOrigin, 0))
+ end
+end
+
+def riscLowerMalformedAddressesDouble(list)
+ newList = []
+ list.each {
+ | node |
+ if node.is_a? Instruction
+ case node.opcode
+ when "loadd"
+ newList << Instruction.new(node.codeOrigin, "loadd", [node.operands[0].riscDoubleAddress(newList), node.operands[1]], node.annotation)
+ when "stored"
+ newList << Instruction.new(node.codeOrigin, "stored", [node.operands[0], node.operands[1].riscDoubleAddress(newList)], node.annotation)
+ else
+ newList << node
+ end
+ else
+ newList << node
+ end
+ }
+ newList
+end
+
+#
+# Lowering of misplaced immediates. For example:
+#
+# storei 0, [foo]
+#
+# will become:
+#
+# move 0, tmp
+# storei tmp, [foo]
+#
+
+def riscLowerMisplacedImmediates(list)
+ newList = []
+ list.each {
+ | node |
+ if node.is_a? Instruction
+ case node.opcode
+ when "storeb", "storei", "storep"
+ operands = node.operands
+ newOperands = []
+ operands.each {
+ | operand |
+ if operand.is_a? Immediate
+ 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
+ else
+ newList << node
+ end
+ }
+ newList
+end
+
+#
+# Lowering of malformed immediates except when used in a "move" instruction.
+# For example:
+#
+# addp 642641, foo
+#
+# will become:
+#
+# move 642641, tmp
+# addp tmp, foo
+#
+
+class Node
+ def riscLowerMalformedImmediatesRecurse(list, validImmediates)
+ mapChildren {
+ | node |
+ node.riscLowerMalformedImmediatesRecurse(list, validImmediates)
+ }
+ end
+end
+
+class Address
+ def riscLowerMalformedImmediatesRecurse(list, validImmediates)
+ self
+ end
+end
+
+class BaseIndex
+ def riscLowerMalformedImmediatesRecurse(list, validImmediates)
+ self
+ end
+end
+
+class AbsoluteAddress
+ def riscLowerMalformedImmediatesRecurse(list, validImmediates)
+ self
+ end
+end
+
+class Immediate
+ def riscLowerMalformedImmediatesRecurse(list, validImmediates)
+ unless validImmediates.include? value
+ tmp = Tmp.new(codeOrigin, :gpr)
+ list << Instruction.new(codeOrigin, "move", [self, tmp])
+ tmp
+ else
+ self
+ end
+ end
+end
+
+def riscLowerMalformedImmediates(list, validImmediates)
+ newList = []
+ list.each {
+ | node |
+ if node.is_a? Instruction
+ annotation = node.annotation
+ case node.opcode
+ when "move"
+ newList << node
+ when "addi", "addp", "addis", "subi", "subp", "subis"
+ if node.operands[0].is_a? Immediate and
+ (not validImmediates.include? node.operands[0].value) and
+ validImmediates.include? -node.operands[0].value
+ node.operands.size == 2
+ if node.opcode =~ /add/
+ newOpcode = "sub" + $~.post_match
+ else
+ newOpcode = "add" + $~.post_match
+ end
+ newList << Instruction.new(node.codeOrigin, newOpcode,
+ [Immediate.new(node.codeOrigin, -node.operands[0].value)] + node.operands[1..-1],
+ annotation)
+ else
+ newList << node.riscLowerMalformedImmediatesRecurse(newList, validImmediates)
+ end
+ when "muli", "mulp"
+ if node.operands[0].is_a? Immediate
+ tmp = Tmp.new(codeOrigin, :gpr)
+ newList << Instruction.new(node.codeOrigin, "move", [node.operands[0], tmp], annotation)
+ newList << Instruction.new(node.codeOrigin, node.opcode, [tmp] + node.operands[1..-1])
+ else
+ newList << node.riscLowerMalformedImmediatesRecurse(newList, validImmediates)
+ end
+ else
+ newList << node.riscLowerMalformedImmediatesRecurse(newList, validImmediates)
+ end
+ else
+ newList << node
+ end
+ }
+ newList
+end
+
+#
+# Lowering of misplaced addresses. For example:
+#
+# addi foo, [bar]
+#
+# will become:
+#
+# loadi [bar], tmp
+# addi foo, tmp
+# storei tmp, [bar]
+#
+# Another example:
+#
+# addi [foo], bar
+#
+# will become:
+#
+# loadi [foo], tmp
+# addi tmp, bar
+#
+
+def riscAsRegister(preList, postList, operand, suffix, needStore)
+ return operand unless operand.address?
+
+ tmp = Tmp.new(operand.codeOrigin, if suffix == "d" then :fpr else :gpr end)
+ preList << Instruction.new(operand.codeOrigin, "load" + suffix, [operand, tmp])
+ if needStore
+ postList << Instruction.new(operand.codeOrigin, "store" + suffix, [tmp, operand])
+ end
+ tmp
+end
+
+def riscAsRegisters(preList, postList, operands, suffix)
+ newOperands = []
+ operands.each_with_index {
+ | operand, index |
+ newOperands << riscAsRegister(preList, postList, operand, suffix, index == operands.size - 1)
+ }
+ newOperands
+end
+
+def riscLowerMisplacedAddresses(list)
+ newList = []
+ list.each {
+ | node |
+ if node.is_a? Instruction
+ postInstructions = []
+ annotation = node.annotation
+ case node.opcode
+ when "addi", "addis", "andi", "lshifti", "muli", "negi", "noti", "ori", "oris",
+ "rshifti", "urshifti", "subi", "subis", "xori", /^bi/, /^bti/, /^ci/, /^ti/
+ newList << Instruction.new(node.codeOrigin,
+ node.opcode,
+ riscAsRegisters(newList, postInstructions, node.operands, "i"),
+ annotation)
+ when "addp", "andp", "lshiftp", "mulp", "negp", "orp", "rshiftp", "urshiftp",
+ "subp", "xorp", /^bp/, /^btp/, /^cp/
+ newList << Instruction.new(node.codeOrigin,
+ node.opcode,
+ riscAsRegisters(newList, postInstructions, node.operands, "p"),
+ annotation)
+ when "bbeq", "bbneq", "bba", "bbaeq", "bbb", "bbbeq", "btbz", "btbnz", "tbz", "tbnz",
+ "cbeq", "cbneq", "cba", "cbaeq", "cbb", "cbbeq"
+ newList << Instruction.new(node.codeOrigin,
+ node.opcode,
+ riscAsRegisters(newList, postInstructions, node.operands, "b"),
+ annotation)
+ when "bbgt", "bbgteq", "bblt", "bblteq", "btbs", "tbs", "cbgt", "cbgteq", "cblt", "cblteq"
+ newList << Instruction.new(node.codeOrigin,
+ node.opcode,
+ riscAsRegisters(newList, postInstructions, node.operands, "bs"),
+ annotation)
+ when "addd", "divd", "subd", "muld", "sqrtd", /^bd/
+ newList << Instruction.new(node.codeOrigin,
+ node.opcode,
+ riscAsRegisters(newList, postInstructions, node.operands, "d"),
+ annotation)
+ when "jmp", "call"
+ newList << Instruction.new(node.codeOrigin,
+ node.opcode,
+ [riscAsRegister(newList, postInstructions, node.operands[0], "p", false)],
+ annotation)
+ else
+ newList << node
+ end
+ newList += postInstructions
+ else
+ newList << node
+ end
+ }
+ newList
+end
+
+#
+# Lowering of register reuse in compare instructions. For example:
+#
+# cieq t0, t1, t0
+#
+# will become:
+#
+# mov tmp, t0
+# cieq tmp, t1, t0
+#
+
+def riscLowerRegisterReuse(list)
+ newList = []
+ list.each {
+ | node |
+ if node.is_a? Instruction
+ annotation = node.annotation
+ case node.opcode
+ when "cieq", "cineq", "cia", "ciaeq", "cib", "cibeq", "cigt", "cigteq", "cilt", "cilteq",
+ "cpeq", "cpneq", "cpa", "cpaeq", "cpb", "cpbeq", "cpgt", "cpgteq", "cplt", "cplteq",
+ "tis", "tiz", "tinz", "tbs", "tbz", "tbnz", "tps", "tpz", "tpnz", "cbeq", "cbneq",
+ "cba", "cbaeq", "cbb", "cbbeq", "cbgt", "cbgteq", "cblt", "cblteq"
+ if node.operands.size == 2
+ if node.operands[0] == node.operands[1]
+ tmp = Tmp.new(node.codeOrigin, :gpr)
+ newList << Instruction.new(node.codeOrigin, "move", [node.operands[0], tmp], annotation)
+ newList << Instruction.new(node.codeOrigin, node.opcode, [tmp, node.operands[1]])
+ else
+ newList << node
+ end
+ else
+ raise "Wrong number of arguments at #{node.codeOriginString}" unless node.operands.size == 3
+ if node.operands[0] == node.operands[2]
+ tmp = Tmp.new(node.codeOrigin, :gpr)
+ newList << Instruction.new(node.codeOrigin, "move", [node.operands[0], tmp], annotation)
+ newList << Instruction.new(node.codeOrigin, node.opcode, [tmp, node.operands[1], node.operands[2]])
+ elsif node.operands[1] == node.operands[2]
+ tmp = Tmp.new(node.codeOrigin, :gpr)
+ newList << Instruction.new(node.codeOrigin, "move", [node.operands[1], tmp], annotation)
+ newList << Instruction.new(node.codeOrigin, node.opcode, [node.operands[0], tmp, node.operands[2]])
+ else
+ newList << node
+ end
+ end
+ else
+ newList << node
+ end
+ else
+ newList << node
+ end
+ }
+ newList
+end
+