summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore
diff options
context:
space:
mode:
Diffstat (limited to 'Source/JavaScriptCore')
-rw-r--r--Source/JavaScriptCore/offlineasm/instructions.rb4
-rw-r--r--Source/JavaScriptCore/offlineasm/sh4.rb272
2 files changed, 206 insertions, 70 deletions
diff --git a/Source/JavaScriptCore/offlineasm/instructions.rb b/Source/JavaScriptCore/offlineasm/instructions.rb
index eb394afab..45fdb0ffc 100644
--- a/Source/JavaScriptCore/offlineasm/instructions.rb
+++ b/Source/JavaScriptCore/offlineasm/instructions.rb
@@ -285,9 +285,7 @@ SH4_INSTRUCTIONS =
"loaddReversedAndIncrementAddress",
"storedReversedAndDecrementAddress",
"ldspr",
- "stspr",
- "callf",
- "jmpf"
+ "stspr"
]
CXX_INSTRUCTIONS =
diff --git a/Source/JavaScriptCore/offlineasm/sh4.rb b/Source/JavaScriptCore/offlineasm/sh4.rb
index 57223c826..5721baee7 100644
--- a/Source/JavaScriptCore/offlineasm/sh4.rb
+++ b/Source/JavaScriptCore/offlineasm/sh4.rb
@@ -144,6 +144,95 @@ class AbsoluteAddress
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:
@@ -358,18 +447,96 @@ def sh4LowerMisplacedLabels(list)
| node |
if node.is_a? Instruction
case node.opcode
- when "jmp"
+ when "jmp", "call"
if node.operands[0].is_a? LabelReference
tmp = Tmp.new(codeOrigin, :gpr)
- newList << Instruction.new(codeOrigin, "jmpf", [tmp, node.operands[0]])
+ newList << Instruction.new(codeOrigin, "move", [node.operands[0], tmp])
+ newList << Instruction.new(codeOrigin, node.opcode, [tmp])
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
+ }
+ 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
@@ -380,6 +547,12 @@ def sh4LowerMisplacedLabels(list)
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
@@ -433,6 +606,8 @@ class Sequence
result = assignRegistersToTemporaries(result, :gpr, SH4_TMP_GPRS)
result = assignRegistersToTemporaries(result, :gpr, SH4_TMP_FPRS)
+ result = sh4LowerConstPool(result)
+
return result
end
end
@@ -441,43 +616,6 @@ 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"
@@ -506,12 +644,8 @@ 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
+ $asm.puts "bra #{label.asmLabel}"
+ $asm.puts "nop"
outlabel.lower("SH4")
end
@@ -570,11 +704,20 @@ class Instruction
$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]])}"
+ 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
- $asm.puts "sub #{sh4Operands(operands)}"
+ 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])}"
@@ -681,6 +824,8 @@ class Instruction
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"
@@ -703,15 +848,6 @@ class Instruction
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}"
@@ -721,8 +857,6 @@ class Instruction
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"
@@ -737,8 +871,12 @@ class Instruction
when "loadi", "loadis", "loadp", "storei", "storep"
$asm.puts "mov.l #{sh4Operands(operands)}"
when "move"
- if operands[0].is_a? Immediate
- emitSH4LoadImm(operands)
+ 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
else
$asm.puts "mov #{sh4Operands(operands)}"
end