source: webkit/trunk/Source/JavaScriptCore/offlineasm/mips.rb

Last change on this file was 284341, checked in by [email protected], 4 years ago

Make LLIntAssembly.h more readable.
https://bugs.webkit.org/show_bug.cgi?id=231876

Reviewed by Yusuki Suzuki.

In this patch, I did the following:

  1. Changed CodeOrigin to only dump the filename, and not the full path.
  1. Deferred printing the ".loc" metadata in $asm.debugAnnotation till we format the line to dump in $asm.formatDump. This enabled the ".loc" metadata to be dumped on the same line as the asm instruction.
  1. Changed $asm.codeOrigin to not dump multiple codeOrigin comments. The only times when there appears to be "multiple" codeOrigins for any given instruction is if the instruction before it was elided, thereby leaving the elided instruction's codeOrigin to be mis-attributed to the subsequent instruction.
  1. Moved the MIPS Assembler.putStr method to asm.rb. This method was already commonly used in arm.rb and arm64.rb previously. Hence, it belongs in common code.

Also enhanced it to support indenting by the column width of ".loc" debug
annotations if $enableDebugAnnotations is true. This keeps the ".loc" column
on the left clear of other content, thereby making it easy to visually filter
out that column when scanning through the generated asm code.

  1. Changed some code that called outp.puts directly to call $asm.putStr instead. This yields the nice alignment for easy visual filtering described in (4).
  1. Changed $preferredCommentStartColumn to be at column 40 to make the generated asm code more compact. However, if the backend is the C_LOOP, then change it back to 60 because C_LOOP code is more verbose and need the extra space.

Demo time:
Before this patch, LLIntAssembly.h looks like this:
`
#if !OFFLINE_ASM_X86 && !OFFLINE_ASM_X86_WIN && !OFFLINE_ASM_X86_64 && !OFFLINE_ASM_X86_64_WIN && !OFFLINE_ASM_ARMv7 && !OFFLINE_ASM_ARM64 && OFFLINE_ASM_ARM64E && !OFFLINE_ASM_MIPS && !OFFLINE_ASM_RISCV64 && !OFFLINE_ASM_C_LOOP && !OFFLINE_ASM_C_LOOP_WIN && !OFFLINE_ASM_ARMv7k && !OFFLINE_ASM_ARMv7s && OFFLINE_ASM_JSVALUE64 && !OFFLINE_ASM_BIGINT32 && OFFLINE_ASM_GIGACAGE_ENABLED && !OFFLINE_ASM_ASSERT_ENABLED && !OFFLINE_ASM_TRACING && OFFLINE_ASM_ADDRESS64 && OFFLINE_ASM_JIT && OFFLINE_ASM_WEBASSEMBLY && OFFLINE_ASM_HAVE_FAST_TLS && OFFLINE_ASM_WEBASSEMBLY_B3JIT
OFFLINE_ASM_BEGIN
OFFLINE_ASM_GLOBAL_LABEL(llintPCRangeStart)
".file 1 \"/Users/mlam/ws1/OpenSource/Source/JavaScriptCore/llint/LowLevelInterpreter.asm\"\n"
".file 2 \"/Users/mlam/ws1/OpenSource/WebKitBuild/Release/DerivedSources/JavaScriptCore/InitBytecodes.asm\"\n"
".file 3 \"/Users/mlam/ws1/OpenSource/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm\"\n"
".file 4 \"/Users/mlam/ws1/OpenSource/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm\"\n"
".file 5 \"/Users/mlam/ws1/OpenSource/WebKitBuild/Release/DerivedSources/JavaScriptCore/InitWasm.asm\"\n"
".file 6 \"/Users/mlam/ws1/OpenSource/Source/JavaScriptCore/llint/WebAssembly.asm\"\n"
".file 7 \"/Users/mlam/ws1/OpenSource/WebKitBuild/Release/usr/local/include/WebKitAdditions/LowLevelInterpreterAdditions.asm\"\n"
".loc 1 1672\n"

"\tbrk #0xc471\n" JavaScriptCore/llint/LowLevelInterpreter.asm:1672

".loc 1 1681\n"

OFFLINE_ASM_GLOBAL_LABEL(vmEntryToJavaScript)
".loc 1 1066\n"

"\tpacibsp\n" JavaScriptCore/llint/LowLevelInterpreter.asm:1066

".loc 1 1070\n"

"\tstp x29, x30, [sp, #-16]!\n" JavaScriptCore/llint/LowLevelInterpreter.asm:1070

".loc 1 1075\n"

"\tmov x29, sp\n" JavaScriptCore/llint/LowLevelInterpreter.asm:1075

".loc 1 1090\n"

"\tsub sp, x29, #176\n" JavaScriptCore/llint/LowLevelInterpreter.asm:1090

".loc 3 169\n"

"\tmovz x13, #48040, lsl #0\n" JavaScriptCore/llint/LowLevelInterpreter64.asm:169

".loc 3 169\n"

"\tadd x17, x1, x13, lsl #0\n" JavaScriptCore/llint/LowLevelInterpreter64.asm:169

".loc 3 169\n"

"\tldr w4, [x17, #0]\n" JavaScriptCore/llint/LowLevelInterpreter64.asm:169

".loc 3 170\n"

"\tcbnz w4, " LOCAL_LABEL_STRING(_offlineasm_doVMEntrycheckVMEntryPermission) "\n" JavaScriptCore/llint/LowLevelInterpreter64.asm:170

".loc 3 172\n"

"\tstr x1, [sp, #0]\n" JavaScriptCore/llint/LowLevelInterpreter64.asm:172

...

".loc 3 309\n"

"\tmov x3, x0\n" JavaScriptCore/llint/LowLevelInterpreter64.asm:309

".loc 1 1\n"
#if OS(DARWIN)

"\tL_offlineasm_loh_adrp_1:\n" JavaScriptCore/llint/LowLevelInterpreter.asm:1
"\tadrp x2, " LOCAL_REFERENCE(g_config) "@GOTPAGE\n"
"\tL_offlineasm_loh_ldr_1:\n"
"\tldr x2, [x2, " LOCAL_REFERENCE(g_config) "@GOTPAGEOFF]\n"

#elif OS(LINUX)

"\tadrp x2, :got:" LOCAL_REFERENCE(g_config) "\n"
"\tldr x2, [x2, :got_lo12:" LOCAL_REFERENCE(g_config) "]\n"

#else
#error Missing globaladdr implementation
#endif
".loc 1 1\n"

"\tadd x2, x2, #3072\n" JavaScriptCore/llint/LowLevelInterpreter.asm:1

`

After this patch, LLIntAssembly.h looks like this:
`
#if !OFFLINE_ASM_X86 && !OFFLINE_ASM_X86_WIN && !OFFLINE_ASM_X86_64 && !OFFLINE_ASM_X86_64_WIN && !OFFLINE_ASM_ARMv7 && !OFFLINE_ASM_ARM64 && OFFLINE_ASM_ARM64E && !OFFLINE_ASM_MIPS && !OFFLINE_ASM_RISCV64 && !OFFLINE_ASM_C_LOOP && !OFFLINE_ASM_C_LOOP_WIN && !OFFLINE_ASM_ARMv7k && !OFFLINE_ASM_ARMv7s && OFFLINE_ASM_JSVALUE64 && !OFFLINE_ASM_BIGINT32 && OFFLINE_ASM_GIGACAGE_ENABLED && !OFFLINE_ASM_ASSERT_ENABLED && !OFFLINE_ASM_TRACING && OFFLINE_ASM_ADDRESS64 && OFFLINE_ASM_JIT && OFFLINE_ASM_WEBASSEMBLY && OFFLINE_ASM_HAVE_FAST_TLS && OFFLINE_ASM_WEBASSEMBLY_B3JIT

OFFLINE_ASM_BEGIN
OFFLINE_ASM_GLOBAL_LABEL(llintPCRangeStart)
".file 1 \"/Users/mlam/ws1/OpenSource/Source/JavaScriptCore/llint/LowLevelInterpreter.asm\"\n"
".file 2 \"/Users/mlam/ws1/OpenSource/WebKitBuild/Release/DerivedSources/JavaScriptCore/InitBytecodes.asm\"\n"
".file 3 \"/Users/mlam/ws1/OpenSource/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm\"\n"
".file 4 \"/Users/mlam/ws1/OpenSource/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm\"\n"
".file 5 \"/Users/mlam/ws1/OpenSource/WebKitBuild/Release/DerivedSources/JavaScriptCore/InitWasm.asm\"\n"
".file 6 \"/Users/mlam/ws1/OpenSource/Source/JavaScriptCore/llint/WebAssembly.asm\"\n"
".file 7 \"/Users/mlam/ws1/OpenSource/WebKitBuild/Release/usr/local/include/WebKitAdditions/LowLevelInterpreterAdditions.asm\"\n"

".loc 1 1672\n" "brk #0xc471 \n" LowLevelInterpreter.asm:1672

".loc 1 1681\n" OFFLINE_ASM_GLOBAL_LABEL(vmEntryToJavaScript)
".loc 1 1066\n" "pacibsp \n" LowLevelInterpreter.asm:1066
".loc 1 1070\n" "stp x29, x30, [sp, #-16]! \n"
LowLevelInterpreter.asm:1070
".loc 1 1075\n" "mov x29, sp \n" LowLevelInterpreter.asm:1075
".loc 1 1090\n" "sub sp, x29, #176 \n"
LowLevelInterpreter.asm:1090
".loc 3 169\n" "movz x13, #48040, lsl #0 \n" LowLevelInterpreter64.asm:169

"add x17, x1, x13, lsl #0 \n"
"ldr w4, [x17, #0] \n"

".loc 3 170\n" "cbnz w4, " LOCAL_LABEL_STRING(_offlineasm_doVMEntrycheckVMEntryPermission) " \n" LowLevelInterpreter64.asm:170
".loc 3 172\n" "str x1, [sp, #0] \n"
LowLevelInterpreter64.asm:172

...

".loc 3 309\n" "mov x3, x0 \n" LowLevelInterpreter64.asm:309

#if OS(DARWIN)

".loc 1 1\n" "L_offlineasm_loh_adrp_1: \n" LowLevelInterpreter.asm:1

"adrp x2, " LOCAL_REFERENCE(g_config) "@GOTPAGE \n"
"L_offlineasm_loh_ldr_1: \n"
"ldr x2, [x2, " LOCAL_REFERENCE(g_config) "@GOTPAGEOFF] \n"

#elif OS(LINUX)

"adrp x2, :got:" LOCAL_REFERENCE(g_config) " \n"
"ldr x2, [x2, :got_lo12:" LOCAL_REFERENCE(g_config) "] \n"

#else
#error Missing globaladdr implementation
#endif

".loc 1 1\n" "add x2, x2, #3072 \n"
`

  • offlineasm/asm.rb:
  • offlineasm/cloop.rb:
  • offlineasm/config.rb:
  • offlineasm/mips.rb:
  • offlineasm/parser.rb:
File size: 39.7 KB
Line 
1# Copyright (C) 2012-2021 Apple Inc. All rights reserved.
2# Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved.
3#
4# Redistribution and use in source and binary forms, with or without
5# modification, are permitted provided that the following conditions
6# are met:
7# 1. Redistributions of source code must retain the above copyright
8# notice, this list of conditions and the following disclaimer.
9# 2. Redistributions in binary form must reproduce the above copyright
10# notice, this list of conditions and the following disclaimer in the
11# documentation and/or other materials provided with the distribution.
12#
13# THIS SOFTWARE IS PROVIDED BY MIPS TECHNOLOGIES, INC. ``AS IS'' AND ANY
14# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MIPS TECHNOLOGIES, INC. OR
17# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24
25require 'risc'
26
27# GPR conventions, to match the baseline JIT
28#
29# $a0 => a0, t7
30# $a1 => a1, t8
31# $a2 => a2, t9
32# $a3 => a3, t10
33# $v0 => t0, r0
34# $v1 => t1, r1
35# $t0 => (scratch)
36# $t1 => (scratch)
37# $t2 => t2
38# $t3 => t3
39# $t4 => t4
40# $t5 => t5
41# $t6 => t6
42# $t7 => (scratch)
43# $t8 => (scratch)
44# $t9 => (stores the callee of a call opcode)
45# $gp => (globals)
46# $s0 => csr0 (callee-save, metadataTable)
47# $s1 => csr1 (callee-save, PB)
48# $s4 => (callee-save used to preserve $gp across calls)
49# $ra => lr
50# $sp => sp
51# $fp => cfr
52#
53# FPR conventions, to match the baseline JIT
54# We don't have fa2 or fa3!
55# $f0 => ft0, fr
56# $f2 => ft1
57# $f4 => ft2
58# $f6 => ft3
59# $f8 => ft4
60# $f10 => ft5
61# $f12 => fa0
62# $f14 => fa1
63# $f16 => (scratch)
64# $f18 => (scratch)
65
66class Node
67 def mipsSingleHi
68 doubleOperand = mipsOperand
69 raise "Bogus register name #{doubleOperand}" unless doubleOperand =~ /^\$f/
70 "$f" + ($~.post_match.to_i + 1).to_s
71 end
72 def mipsSingleLo
73 doubleOperand = mipsOperand
74 raise "Bogus register name #{doubleOperand}" unless doubleOperand =~ /^\$f/
75 doubleOperand
76 end
77end
78
79class SpecialRegister < NoChildren
80 def mipsOperand
81 @name
82 end
83
84 def dump
85 @name
86 end
87
88 def register?
89 true
90 end
91end
92
93MIPS_TEMP_GPRS = [SpecialRegister.new("$t0"), SpecialRegister.new("$t1"), SpecialRegister.new("$t7"), SpecialRegister.new("$t8")]
94MIPS_ZERO_REG = SpecialRegister.new("$zero")
95MIPS_GP_REG = SpecialRegister.new("$gp")
96MIPS_GPSAVE_REG = SpecialRegister.new("$s4")
97MIPS_CALL_REG = SpecialRegister.new("$t9")
98MIPS_RETURN_ADDRESS_REG = SpecialRegister.new("$ra")
99MIPS_TEMP_FPRS = [SpecialRegister.new("$f16")]
100MIPS_SCRATCH_FPR = SpecialRegister.new("$f18")
101
102def mipsMoveImmediate(value, register)
103 if value == 0
104 $asm.puts "add #{register.mipsOperand}, $zero, $zero"
105 else
106 $asm.puts "li #{register.mipsOperand}, #{value}"
107 end
108end
109
110class RegisterID
111 def mipsOperand
112 case name
113 when "a0", "t7"
114 "$a0"
115 when "a1", "t8"
116 "$a1"
117 when "a2", "t9"
118 "$a2"
119 when "a3", "t10"
120 "$a3"
121 when "t0", "r0"
122 "$v0"
123 when "t1", "r1"
124 "$v1"
125 when "t2"
126 "$t2"
127 when "t3"
128 "$t3"
129 when "t4"
130 "$t4"
131 when "t5"
132 "$t5"
133 when "cfr"
134 "$fp"
135 when "csr0"
136 "$s0"
137 when "csr1"
138 "$s1"
139 when "lr"
140 "$ra"
141 when "sp"
142 "$sp"
143 else
144 raise "Bad register #{name} for MIPS at #{codeOriginString}"
145 end
146 end
147end
148
149class FPRegisterID
150 def mipsOperand
151 case name
152 when "ft0", "fr"
153 "$f0"
154 when "ft1"
155 "$f2"
156 when "ft2"
157 "$f4"
158 when "ft3"
159 "$f6"
160 when "ft4"
161 "$f8"
162 when "ft5"
163 "$f10"
164 when "fa0"
165 "$f12"
166 when "fa1"
167 "$f14"
168 else
169 raise "Bad register #{name} for MIPS at #{codeOriginString}"
170 end
171 end
172end
173
174class Immediate
175 def mipsOperand
176 raise "Invalid immediate #{value} at #{codeOriginString}" if value < -0x7fff or value > 0xffff
177 "#{value}"
178 end
179end
180
181class Address
182 def mipsOperand
183 raise "Bad offset at #{codeOriginString}" if offset.value < -0x7fff or offset.value > 0x7fff
184 "#{offset.value}(#{base.mipsOperand})"
185 end
186end
187
188class AbsoluteAddress
189 def mipsOperand
190 raise "Unconverted absolute address at #{codeOriginString}"
191 end
192end
193
194#
195# Negate condition of branches to labels.
196#
197
198class Instruction
199 def mipsNegateCondition(list)
200 /^(b(add|sub|or|mul|t)?)([ipb])/.match(opcode)
201 case $~.post_match
202 when "eq"
203 op = "neq"
204 when "neq"
205 op = "eq"
206 when "z"
207 op = "nz"
208 when "nz"
209 op = "z"
210 when "gt"
211 op = "lteq"
212 when "gteq"
213 op = "lt"
214 when "lt"
215 op = "gteq"
216 when "lteq"
217 op = "gt"
218 when "a"
219 op = "beq"
220 when "b"
221 op = "aeq"
222 when "aeq"
223 op = "b"
224 when "beq"
225 op = "a"
226 else
227 raise "Can't negate #{opcode} branch."
228 end
229 noBranch = LocalLabel.unique("nobranch")
230 noBranchRef = LocalLabelReference.new(codeOrigin, noBranch)
231 toRef = operands[-1]
232 list << Instruction.new(codeOrigin, "#{$1}#{$3}#{op}", operands[0..-2].push(noBranchRef), annotation)
233 list << Instruction.new(codeOrigin, "la", [toRef, MIPS_CALL_REG])
234 list << Instruction.new(codeOrigin, "jmp", [MIPS_CALL_REG])
235 list << noBranch
236 end
237end
238
239def mipsLowerFarBranchOps(list)
240 newList = []
241 list.each {
242 | node |
243 if node.is_a? Instruction
244 annotation = node.annotation
245 case node.opcode
246 when /^b(add|sub|or|mul|t)?([ipb])/
247 if node.operands[-1].is_a? LabelReference
248 node.mipsNegateCondition(newList)
249 next
250 end
251 end
252 end
253 newList << node
254 }
255 newList
256end
257
258#
259# Lower 'and' masked branches
260#
261
262def lowerMIPSCondBranch(list, condOp, node)
263 if node.operands.size == 2
264 list << Instruction.new(node.codeOrigin,
265 condOp,
266 [node.operands[0], MIPS_ZERO_REG, node.operands[-1]],
267 node.annotation)
268 elsif node.operands.size == 3
269 tl = condOp[-1, 1]
270 tmp = Tmp.new(node.codeOrigin, :gpr)
271 list << Instruction.new(node.codeOrigin,
272 "and" + tl,
273 [node.operands[0], node.operands[1], tmp],
274 node.annotation)
275 list << Instruction.new(node.codeOrigin,
276 condOp,
277 [tmp, MIPS_ZERO_REG, node.operands[-1]])
278 else
279 raise "Expected 2 or 3 operands but got #{node.operands.size} at #{node.codeOriginString}"
280 end
281end
282
283#
284# Lowering of branch ops. For example:
285#
286# baddiz foo, bar, baz
287#
288# will become:
289#
290# addi foo, bar
291# bz baz
292#
293
294def mipsLowerSimpleBranchOps(list)
295 newList = []
296 list.each {
297 | node |
298 if node.is_a? Instruction
299 annotation = node.annotation
300 case node.opcode
301 when /^b(addi|subi|ori|addp)/
302 op = $1
303 bc = $~.post_match
304 branch = "b" + bc
305
306 case op
307 when "addi", "addp"
308 op = "addi"
309 when "subi"
310 op = "subi"
311 when "ori"
312 op = "ori"
313 end
314
315 if bc == "o"
316 case op
317 when "addi"
318 # addu $s0, $s1, $s2
319 # xor $t0, $s1, $s2
320 # blt $t0, $zero, no overflow
321 # xor $t0, $s0, $s1
322 # blt $t0, $zero, overflow
323 # no overflow:
324 #
325 tr = Tmp.new(node.codeOrigin, :gpr)
326 tmp = Tmp.new(node.codeOrigin, :gpr)
327 noFlow = LocalLabel.unique("noflow")
328 noFlowRef = LocalLabelReference.new(node.codeOrigin, noFlow)
329 newList << Instruction.new(node.codeOrigin, op, [node.operands[0], node.operands[1], tr], annotation)
330 newList << Instruction.new(node.codeOrigin, "xori", [node.operands[0], node.operands[1], tmp])
331 newList << Instruction.new(node.codeOrigin, "bilt", [tmp, MIPS_ZERO_REG, noFlowRef])
332 newList << Instruction.new(node.codeOrigin, "xori", [tr, node.operands[0], tmp])
333 newList << Instruction.new(node.codeOrigin, "bilt", [tmp, MIPS_ZERO_REG, node.operands[2]])
334 newList << noFlow
335 newList << Instruction.new(node.codeOrigin, "move", [tr, node.operands[1]])
336 when "subi"
337 # subu $s0, $s1, $s2
338 # xor $t0, $s1, $s2
339 # bge $t0, $zero, no overflow
340 # xor $t0, $s0, $s1
341 # blt $t0, $zero, overflow
342 # no overflow:
343 #
344 tr = Tmp.new(node.codeOrigin, :gpr)
345 tmp = Tmp.new(node.codeOrigin, :gpr)
346 noFlow = LocalLabel.unique("noflow")
347 noFlowRef = LocalLabelReference.new(node.codeOrigin, noFlow)
348 newList << Instruction.new(node.codeOrigin, op, [node.operands[1], node.operands[0], tr], annotation)
349 newList << Instruction.new(node.codeOrigin, "xori", [node.operands[1], node.operands[0], tmp])
350 newList << Instruction.new(node.codeOrigin, "bigteq", [tmp, MIPS_ZERO_REG, noFlowRef])
351 newList << Instruction.new(node.codeOrigin, "xori", [tr, node.operands[1], tmp])
352 newList << Instruction.new(node.codeOrigin, "bilt", [tmp, MIPS_ZERO_REG, node.operands[2]])
353 newList << noFlow
354 newList << Instruction.new(node.codeOrigin, "move", [tr, node.operands[1]])
355 when "ori"
356 # no ovwerflow at ori
357 newList << Instruction.new(node.codeOrigin, op, node.operands[0..1], annotation)
358 end
359 else
360 if node.operands[1].is_a? Address
361 addr = node.operands[1]
362 tr = Tmp.new(node.codeOrigin, :gpr)
363 newList << Instruction.new(node.codeOrigin, "loadp", [addr, tr], annotation)
364 newList << Instruction.new(node.codeOrigin, op, [node.operands[0], tr])
365 newList << Instruction.new(node.codeOrigin, "storep", [tr, addr])
366 else
367 tr = node.operands[1]
368 newList << Instruction.new(node.codeOrigin, op, node.operands[0..-2], annotation)
369 end
370 newList << Instruction.new(node.codeOrigin, branch, [tr, MIPS_ZERO_REG, node.operands[-1]])
371 end
372 when "bia", "bpa", "bba"
373 tmp = Tmp.new(node.codeOrigin, :gpr)
374 comp = node.opcode[1] == ?b ? "sltub" : "sltu"
375 newList << Instruction.new(node.codeOrigin, comp, [tmp, node.operands[1], node.operands[0]], annotation)
376 newList << Instruction.new(node.codeOrigin, "bnz", [tmp, MIPS_ZERO_REG, node.operands[2]])
377 when "biaeq", "bpaeq", "bbaeq"
378 tmp = Tmp.new(node.codeOrigin, :gpr)
379 comp = node.opcode[1] == ?b ? "sltub" : "sltu"
380 newList << Instruction.new(node.codeOrigin, comp, [tmp, node.operands[0], node.operands[1]], annotation)
381 newList << Instruction.new(node.codeOrigin, "bz", [tmp, MIPS_ZERO_REG, node.operands[2]])
382 when "bib", "bpb", "bbb"
383 tmp = Tmp.new(node.codeOrigin, :gpr)
384 comp = node.opcode[1] == ?b ? "sltub" : "sltu"
385 newList << Instruction.new(node.codeOrigin, comp, [tmp, node.operands[0], node.operands[1]], annotation)
386 newList << Instruction.new(node.codeOrigin, "bnz", [tmp, MIPS_ZERO_REG, node.operands[2]])
387 when "bibeq", "bpbeq", "bbbeq"
388 tmp = Tmp.new(node.codeOrigin, :gpr)
389 comp = node.opcode[1] == ?b ? "sltub" : "sltu"
390 newList << Instruction.new(node.codeOrigin, comp, [tmp, node.operands[1], node.operands[0]], annotation)
391 newList << Instruction.new(node.codeOrigin, "bz", [tmp, MIPS_ZERO_REG, node.operands[2]])
392 when /^bt(i|p|b)/
393 lowerMIPSCondBranch(newList, "b" + $~.post_match + $1, node)
394 else
395 newList << node
396 end
397 else
398 newList << node
399 end
400 }
401 newList
402end
403
404#
405# Specialization of lowering of malformed BaseIndex addresses.
406#
407
408class Node
409 def mipsLowerMalformedAddressesRecurse(list)
410 mapChildren {
411 | subNode |
412 subNode.mipsLowerMalformedAddressesRecurse(list)
413 }
414 end
415
416 def mipsLowerShiftedAddressesRecurse(list, isFirst, tmp)
417 mapChildren {
418 | subNode |
419 subNode.mipsLowerShiftedAddressesRecurse(list, isFirst, tmp)
420 }
421 end
422end
423
424class BaseIndex
425 def mipsLowerMalformedAddressesRecurse(list)
426 tmp = Tmp.new(codeOrigin, :gpr)
427 if scaleShift == 0
428 list << Instruction.new(codeOrigin, "addp", [base, index, tmp])
429 Address.new(codeOrigin, tmp, Immediate.new(codeOrigin, offset.value));
430 end
431 end
432
433 def mipsLowerShiftedAddressesRecurse(list, isFirst, tmp)
434 if isFirst
435 list << Instruction.new(codeOrigin, "lshifti", [index, Immediate.new(codeOrigin, scaleShift), tmp]);
436 list << Instruction.new(codeOrigin, "addp", [base, tmp])
437 end
438 Address.new(codeOrigin, tmp, Immediate.new(codeOrigin, offset.value));
439 end
440end
441
442#
443# Lowering of BaseIndex addresses with optimization for MIPS.
444#
445# offline asm instruction pair:
446# loadi 4[cfr, t0, 8], t2
447# loadi 0[cfr, t0, 8], t0
448#
449# lowered instructions:
450# lshifti t0, 3, tmp
451# addp cfr, tmp
452# loadi 4[tmp], t2
453# loadi 0[tmp], t0
454#
455
456def mipsHasShiftedBaseIndexAddress(instruction)
457 instruction.operands.each_with_index {
458 | operand, index |
459 if operand.is_a? BaseIndex and operand.scaleShift != 0
460 return index
461 end
462 }
463 -1
464end
465
466def mipsScaleOfBaseIndexMatches(baseIndex0, baseIndex1)
467 baseIndex0.base == baseIndex1.base and
468 baseIndex0.index == baseIndex1.index and
469 baseIndex0.scale == baseIndex1.scale
470end
471
472def mipsLowerBaseIndexAddresses(list)
473 newList = [ list[0] ]
474 tmp = nil
475 list.each_cons(2) {
476 | nodes |
477 if nodes[1].is_a? Instruction
478 ind = mipsHasShiftedBaseIndexAddress(nodes[1])
479 if ind != -1
480 if nodes[0].is_a? Instruction and
481 nodes[0].opcode == nodes[1].opcode and
482 ind == mipsHasShiftedBaseIndexAddress(nodes[0]) and
483 mipsScaleOfBaseIndexMatches(nodes[0].operands[ind], nodes[1].operands[ind])
484
485 newList << nodes[1].mipsLowerShiftedAddressesRecurse(newList, false, tmp)
486 else
487 tmp = Tmp.new(codeOrigin, :gpr)
488 newList << nodes[1].mipsLowerShiftedAddressesRecurse(newList, true, tmp)
489 end
490 else
491 newList << nodes[1].mipsLowerMalformedAddressesRecurse(newList)
492 end
493 else
494 newList << nodes[1]
495 end
496 }
497 newList
498end
499
500#
501# Lowering of misplaced immediates of MIPS specific instructions. For example:
502#
503# sltu reg, 4, 2
504#
505# will become:
506#
507# move 4, tmp
508# sltu reg, tmp, 2
509#
510
511def mipsLowerMisplacedImmediates(list)
512 newList = []
513 list.each {
514 | node |
515 if node.is_a? Instruction
516 case node.opcode
517 when "slt", "sltu", "sltb", "sltub"
518 if node.operands[1].is_a? Immediate
519 tmp = Tmp.new(node.codeOrigin, :gpr)
520 newList << Instruction.new(node.codeOrigin, "move", [node.operands[1], tmp], node.annotation)
521 newList << Instruction.new(node.codeOrigin, node.opcode,
522 [node.operands[0], tmp, node.operands[2]],
523 node.annotation)
524 else
525 newList << node
526 end
527 when /^(addi|subi)/
528 newList << node.riscLowerMalformedImmediatesRecurse(newList, -0x7fff..0x7fff)
529 when "andi", "andp", "ori", "orp", "orh", "xori", "xorp"
530 newList << node.riscLowerMalformedImmediatesRecurse(newList, 0..0xffff)
531 else
532 newList << node
533 end
534 else
535 newList << node
536 end
537 }
538 newList
539end
540
541#
542# Specialization of lowering of misplaced addresses.
543#
544
545class LocalLabelReference
546 def register?
547 false
548 end
549end
550
551class Instruction
552 # Replace operands with a single register operand.
553 # Note: in contrast to the risc version, this method drops all other operands.
554 def mipsCloneWithOperandLowered(preList, postList, operandIndex, needRestore)
555 operand = self.operands[operandIndex]
556 tmp = MIPS_CALL_REG
557 if operand.address?
558 preList << Instruction.new(self.codeOrigin, "loadp", [operand, MIPS_CALL_REG])
559 elsif operand.is_a? LabelReference
560 preList << Instruction.new(self.codeOrigin, "la", [operand, MIPS_CALL_REG])
561 elsif operand.register? and operand != MIPS_CALL_REG
562 preList << Instruction.new(self.codeOrigin, "move", [operand, MIPS_CALL_REG])
563 else
564 needRestore = false
565 tmp = operand
566 end
567 if needRestore
568 postList << Instruction.new(self.codeOrigin, "move", [MIPS_GPSAVE_REG, MIPS_GP_REG])
569 end
570 cloneWithNewOperands([tmp])
571 end
572end
573
574def mipsLowerMisplacedAddresses(list)
575 newList = []
576 list.each {
577 | node |
578 if node.is_a? Instruction
579 postInstructions = []
580 annotation = node.annotation
581 case node.opcode
582 when "jmp"
583 newList << node.mipsCloneWithOperandLowered(newList, [], 0, false)
584 when "call"
585 newList << node.mipsCloneWithOperandLowered(newList, postInstructions, 0, true)
586 when "slt", "sltu"
587 newList << node.riscCloneWithOperandsLowered(newList, [], "i")
588 when "sltub", "sltb"
589 newList << node.riscCloneWithOperandsLowered(newList, [], "b")
590 when "andb"
591 newList << Instruction.new(node.codeOrigin,
592 "andi",
593 riscLowerOperandsToRegisters(node, newList, [], "b"),
594 node.annotation)
595 when /^(bz|bnz|bs|bo)/
596 tl = $~.post_match == "" ? "i" : $~.post_match
597 newList << node.riscCloneWithOperandsLowered(newList, [], tl)
598 else
599 newList << node
600 end
601 newList += postInstructions
602 else
603 newList << node
604 end
605 }
606 newList
607end
608
609#
610# Lowering compares and tests.
611#
612
613def mipsLowerCompareTemplate(list, node, opCmp, opMov)
614 tmp0 = Tmp.new(node.codeOrigin, :gpr)
615 tmp1 = Tmp.new(node.codeOrigin, :gpr)
616 list << Instruction.new(node.codeOrigin, "move", [Immediate.new(nil, 0), node.operands[2]])
617 list << Instruction.new(node.codeOrigin, opCmp, [node.operands[1], node.operands[0], tmp0])
618 list << Instruction.new(node.codeOrigin, "move", [Immediate.new(nil, 1), tmp1])
619 list << Instruction.new(node.codeOrigin, opMov, [node.operands[2], tmp1, tmp0])
620end
621
622def mipsLowerCompares(list)
623 newList = []
624 list.each {
625 | node |
626 if node.is_a? Instruction
627 case node.opcode
628 when "cieq", "cpeq", "cbeq"
629 mipsLowerCompareTemplate(newList, node, "subp", "movz")
630 when "cineq", "cpneq", "cbneq"
631 mipsLowerCompareTemplate(newList, node, "subp", "movn")
632 when "tiz", "tbz", "tpz"
633 mipsLowerCompareTemplate(newList, node, "andp", "movz")
634 when "tinz", "tbnz", "tpnz"
635 mipsLowerCompareTemplate(newList, node, "andp", "movn")
636 when "tio", "tbo", "tpo"
637 tmp = Tmp.new(node.codeOrigin, :gpr)
638 list << Instruction.new(node.codeOrigin, "andp", [node.operands[1], node.operands[0], tmp])
639 list << Instruction.new(node.codeOrigin, "slt", [node.operands[2], MIPS_ZERO_REG, tmp])
640 when "tis", "tbs", "tps"
641 tmp = Tmp.new(node.codeOrigin, :gpr)
642 list << Instruction.new(node.codeOrigin, "andp", [node.operands[1], node.operands[0], tmp])
643 list << Instruction.new(node.codeOrigin, "slt", [node.operands[2], tmp, MIPS_ZERO_REG])
644 else
645 newList << node
646 end
647 else
648 newList << node
649 end
650 }
651 newList
652end
653
654#
655# Lea support.
656#
657
658class Address
659 def mipsEmitLea(destination)
660 if destination == base
661 $asm.puts "addiu #{destination.mipsOperand}, #{offset.value}"
662 else
663 $asm.puts "addiu #{destination.mipsOperand}, #{base.mipsOperand}, #{offset.value}"
664 end
665 end
666end
667
668#
669# Add PIC compatible header code to all the LLInt rutins.
670#
671
672def mipsAddPICCode(list)
673 myList = []
674 list.each {
675 | node |
676 myList << node
677 if node.is_a? Label
678 myList << Instruction.new(node.codeOrigin, "pichdr", [MIPS_CALL_REG])
679 end
680 }
681 myList
682end
683
684#
685# Actual lowering code follows.
686#
687
688class Sequence
689 def getModifiedListMIPS
690 result = @list
691
692 # Verify that we will only see instructions and labels.
693 result.each {
694 | node |
695 unless node.is_a? Instruction or
696 node.is_a? Label or
697 node.is_a? LocalLabel or
698 node.is_a? Skip
699 raise "Unexpected #{node.inspect} at #{node.codeOrigin}"
700 end
701 }
702
703 result = mipsAddPICCode(result)
704 result = mipsLowerFarBranchOps(result)
705 result = mipsLowerSimpleBranchOps(result)
706 result = riscLowerSimpleBranchOps(result)
707 result = riscLowerHardBranchOps(result)
708 result = riscLowerShiftOps(result)
709 result = mipsLowerBaseIndexAddresses(result)
710 result = riscLowerMalformedAddresses(result) {
711 | node, address |
712 if address.is_a? Address
713 (-0x7fff..0x7fff).include? address.offset.value
714 else
715 false
716 end
717 }
718 result = riscLowerMalformedAddressesDouble(result)
719 result = riscLowerMisplacedImmediates(result, ["storeb", "storei", "storep"])
720 result = mipsLowerMisplacedImmediates(result)
721 result = riscLowerMalformedImmediates(result, -0x7fff..0x7fff, -0x7fff..0x7fff)
722 result = mipsLowerMisplacedAddresses(result)
723 result = riscLowerMisplacedAddresses(result)
724 result = riscLowerRegisterReuse(result)
725 result = mipsLowerCompares(result)
726 result = assignRegistersToTemporaries(result, :gpr, MIPS_TEMP_GPRS)
727 result = assignRegistersToTemporaries(result, :fpr, MIPS_TEMP_FPRS)
728
729 return result
730 end
731end
732
733def mipsOperands(operands)
734 operands.map{|v| v.mipsOperand}.join(", ")
735end
736
737def mipsFlippedOperands(operands)
738 mipsOperands([operands[-1]] + operands[0..-2])
739end
740
741def getMIPSOpcode(opcode, suffix)
742
743end
744
745def emitMIPSCompact(opcode, opcodei, operands)
746 postfix = ""
747 if opcode == "sub"
748 if operands[0].is_a? Immediate
749 opcode = "add"
750 operands[0] = Immediate.new(operands[0].codeOrigin, -1 * operands[0].value)
751 elsif operands[1].is_a? Immediate
752 opcode = "add"
753 operands[1] = Immediate.new(operands[1].codeOrigin, -1 * operands[1].value)
754 end
755 postfix = "u"
756 elsif opcode == "add"
757 postfix = "u"
758 end
759 if operands.size == 3
760 if operands[0].is_a? Immediate
761 $asm.puts "#{opcode}i#{postfix} #{operands[2].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].value}"
762 elsif operands[1].is_a? Immediate
763 $asm.puts "#{opcode}i#{postfix} #{operands[2].mipsOperand}, #{operands[0].mipsOperand}, #{operands[1].value}"
764 else
765 $asm.puts "#{opcode}#{postfix} #{mipsFlippedOperands(operands)}"
766 end
767 else
768 raise unless operands.size == 2
769 raise unless operands[1].register?
770 if operands[0].is_a? Immediate
771 $asm.puts "#{opcode}i#{postfix} #{operands[1].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}"
772 else
773 $asm.puts "#{opcode}#{postfix} #{operands[1].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}"
774 end
775 end
776end
777
778def emitMIPSShiftCompact(opcode, operands)
779 if operands.size == 3
780 if (operands[1].is_a? Immediate)
781 $asm.puts "#{opcode} #{operands[2].mipsOperand}, #{operands[0].mipsOperand}, #{operands[1].value}"
782 else
783 $asm.puts "#{opcode}v #{mipsFlippedOperands(operands)}"
784 end
785 else
786 raise unless operands.size == 2
787 if operands[0].register?
788 $asm.puts "#{opcode}v #{operands[1].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}"
789 else
790 $asm.puts "#{opcode} #{operands[1].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].value}"
791 end
792 end
793end
794
795def emitMIPS(opcode, operands)
796 if operands.size == 3
797 $asm.puts "#{opcode} #{mipsFlippedOperands(operands)}"
798 else
799 raise unless operands.size == 2
800 $asm.puts "#{opcode} #{operands[1].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}"
801 end
802end
803
804def emitMIPSDoubleCompare(branchOpcode, neg, operands)
805 mipsMoveImmediate(1, operands[2])
806 $asm.puts "c.#{branchOpcode}.d $fcc0, #{mipsOperands(operands[0..1])}"
807 if (!neg)
808 $asm.puts "movf #{operands[2].mipsOperand}, $zero, $fcc0"
809 else
810 $asm.puts "movt #{operands[2].mipsOperand}, $zero, $fcc0"
811 end
812end
813
814def emitMIPSDoubleBranch(branchOpcode, neg, operands)
815 $asm.puts "c.#{branchOpcode}.d #{mipsOperands(operands[0..1])}"
816 if (!neg)
817 $asm.puts "bc1t #{operands[2].asmLabel}"
818 else
819 $asm.puts "bc1f #{operands[2].asmLabel}"
820 end
821end
822
823def emitMIPSJumpOrCall(opcode, operand)
824 if operand.label?
825 raise "Direct call/jump to a not local label." unless operand.is_a? LocalLabelReference
826 $asm.puts "#{opcode} #{operand.asmLabel}"
827 else
828 raise "Invalid call/jump register." unless operand == MIPS_CALL_REG
829 $asm.puts "#{opcode}r #{MIPS_CALL_REG.mipsOperand}"
830 end
831end
832
833class Instruction
834 def lowerMIPS
835 case opcode
836 when "addi", "addp", "addis"
837 if operands.size == 3 and operands[0].is_a? Immediate
838 raise unless operands[1].register?
839 raise unless operands[2].register?
840 if operands[0].value == 0 #and suffix.empty?
841 unless operands[1] == operands[2]
842 $asm.puts "move #{operands[2].mipsOperand}, #{operands[1].mipsOperand}"
843 end
844 else
845 $asm.puts "addiu #{operands[2].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}"
846 end
847 elsif operands.size == 3 and operands[0].register?
848 raise unless operands[1].register?
849 raise unless operands[2].register?
850 $asm.puts "addu #{mipsFlippedOperands(operands)}"
851 else
852 if operands[0].is_a? Immediate
853 unless Immediate.new(nil, 0) == operands[0]
854 $asm.puts "addiu #{operands[1].mipsOperand}, #{mipsFlippedOperands(operands)}"
855 end
856 else
857 $asm.puts "addu #{operands[1].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}"
858 end
859 end
860 when "andi", "andp"
861 emitMIPSCompact("and", "and", operands)
862 when "ori", "orp", "orh"
863 emitMIPSCompact("or", "orr", operands)
864 when "oris"
865 emitMIPSCompact("or", "orrs", operands)
866 when "xori", "xorp"
867 emitMIPSCompact("xor", "eor", operands)
868 when "lshifti", "lshiftp"
869 emitMIPSShiftCompact("sll", operands)
870 when "rshifti", "rshiftp"
871 emitMIPSShiftCompact("sra", operands)
872 when "urshifti", "urshiftp"
873 emitMIPSShiftCompact("srl", operands)
874 when "muli", "mulp"
875 emitMIPS("mul", operands)
876 when "subi", "subp", "subis"
877 emitMIPSCompact("sub", "subs", operands)
878 when "negi", "negp"
879 $asm.puts "negu #{operands[0].mipsOperand}, #{operands[0].mipsOperand}"
880 when "noti"
881 $asm.puts "nor #{operands[0].mipsOperand}, #{operands[0].mipsOperand}, $zero"
882 when "loadi", "loadis", "loadp"
883 $asm.puts "lw #{mipsFlippedOperands(operands)}"
884 when "storei", "storep"
885 $asm.puts "sw #{mipsOperands(operands)}"
886 when "loadb"
887 $asm.puts "lbu #{mipsFlippedOperands(operands)}"
888 when "loadbsi"
889 $asm.puts "lb #{mipsFlippedOperands(operands)}"
890 when "storeb"
891 $asm.puts "sb #{mipsOperands(operands)}"
892 when "loadh"
893 $asm.puts "lhu #{mipsFlippedOperands(operands)}"
894 when "loadhsi"
895 $asm.puts "lh #{mipsFlippedOperands(operands)}"
896 when "storeh"
897 $asm.puts "sh #{mipsOperands(operands)}"
898 when "loadd"
899 $asm.puts "ldc1 #{mipsFlippedOperands(operands)}"
900 when "stored"
901 $asm.puts "sdc1 #{mipsOperands(operands)}"
902 when "la"
903 $asm.puts "la #{operands[1].mipsOperand}, #{operands[0].asmLabel}"
904 when "addd"
905 emitMIPS("add.d", operands)
906 when "divd"
907 emitMIPS("div.d", operands)
908 when "subd"
909 emitMIPS("sub.d", operands)
910 when "muld"
911 emitMIPS("mul.d", operands)
912 when "sqrtd"
913 $asm.puts "sqrt.d #{mipsFlippedOperands(operands)}"
914 when "ci2ds"
915 raise "invalid ops of #{self.inspect} at #{codeOriginString}" unless operands[1].is_a? FPRegisterID and operands[0].register?
916 $asm.puts "mtc1 #{operands[0].mipsOperand}, #{operands[1].mipsOperand}"
917 $asm.puts "cvt.d.w #{operands[1].mipsOperand}, #{operands[1].mipsOperand}"
918 when "bdeq"
919 emitMIPSDoubleBranch("eq", false, operands)
920 when "bdneq"
921 emitMIPSDoubleBranch("ueq", true, operands)
922 when "bdgt"
923 emitMIPSDoubleBranch("ule", true, operands)
924 when "bdgteq"
925 emitMIPSDoubleBranch("ult", true, operands)
926 when "bdlt"
927 emitMIPSDoubleBranch("olt", false, operands)
928 when "bdlteq"
929 emitMIPSDoubleBranch("ole", false, operands)
930 when "bdequn"
931 emitMIPSDoubleBranch("ueq", false, operands)
932 when "bdnequn"
933 emitMIPSDoubleBranch("eq", true, operands)
934 when "bdgtun"
935 emitMIPSDoubleBranch("ole", true, operands)
936 when "bdgtequn"
937 emitMIPSDoubleBranch("olt", true, operands)
938 when "bdltun"
939 emitMIPSDoubleBranch("ult", false, operands)
940 when "bdltequn"
941 emitMIPSDoubleBranch("ule", false, operands)
942 when "btd2i"
943 # FIXME: may be a good idea to just get rid of this instruction, since the interpreter
944 # currently does not use it.
945 raise "MIPS does not support this opcode yet, #{codeOrigin}"
946 when "td2i"
947 $asm.puts "cvt.w.d #{MIPS_SCRATCH_FPR.mipsSingleLo}, #{operands[0].mipsOperand}"
948 $asm.puts "mfc1 #{operands[1].mipsOperand}, #{MIPS_SCRATCH_FPR.mipsSingleLo}"
949 when "bcd2i"
950 $asm.puts "cvt.w.d #{MIPS_SCRATCH_FPR.mipsSingleLo}, #{operands[0].mipsOperand}"
951 $asm.puts "mfc1 #{operands[1].mipsOperand}, #{MIPS_SCRATCH_FPR.mipsSingleLo}"
952 $asm.puts "cvt.d.w #{MIPS_SCRATCH_FPR.mipsOperand}, #{MIPS_SCRATCH_FPR.mipsSingleLo}"
953 emitMIPSDoubleBranch("eq", true, [MIPS_SCRATCH_FPR, operands[0], operands[2]])
954 $asm.puts "beq #{operands[1].mipsOperand}, $zero, #{operands[2].asmLabel}"
955 when "movdz"
956 # FIXME: either support this or remove it.
957 raise "MIPS does not support this opcode yet, #{codeOrigin}"
958 when "pop"
959 operands.each {
960 | op |
961 $asm.puts "lw #{op.mipsOperand}, 0($sp)"
962 $asm.puts "addiu $sp, $sp, 4"
963 }
964 when "push"
965 operands.each {
966 | op |
967 $asm.puts "addiu $sp, $sp, -4"
968 $asm.puts "sw #{op.mipsOperand}, 0($sp)"
969 }
970 when "move", "sxi2p", "zxi2p"
971 if operands[0].is_a? Immediate
972 mipsMoveImmediate(operands[0].value, operands[1])
973 else
974 $asm.puts "move #{mipsFlippedOperands(operands)}"
975 end
976 when "nop"
977 $asm.puts "nop"
978 when "bieq", "bpeq", "bbeq"
979 $asm.puts "beq #{mipsOperands(operands[0..1])}, #{operands[2].asmLabel}"
980 when "bineq", "bpneq", "bbneq"
981 $asm.puts "bne #{mipsOperands(operands[0..1])}, #{operands[2].asmLabel}"
982 when "bigt", "bpgt", "bbgt"
983 $asm.puts "bgt #{mipsOperands(operands[0..1])}, #{operands[2].asmLabel}"
984 when "bigteq", "bpgteq", "bbgteq"
985 $asm.puts "bge #{mipsOperands(operands[0..1])}, #{operands[2].asmLabel}"
986 when "bilt", "bplt", "bblt"
987 $asm.puts "blt #{mipsOperands(operands[0..1])}, #{operands[2].asmLabel}"
988 when "bilteq", "bplteq", "bblteq"
989 $asm.puts "ble #{mipsOperands(operands[0..1])}, #{operands[2].asmLabel}"
990 when "jmp"
991 emitMIPSJumpOrCall("j", operands[0])
992 when "call"
993 emitMIPSJumpOrCall("jal", operands[0])
994 when "break"
995 $asm.puts "break"
996 when "ret"
997 $asm.puts "jr $ra"
998 when "cia", "cpa", "cba"
999 $asm.puts "sltu #{operands[2].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}"
1000 when "ciaeq", "cpaeq", "cbaeq"
1001 $asm.puts "sltu #{operands[2].mipsOperand}, #{operands[0].mipsOperand}, #{operands[1].mipsOperand}"
1002 $asm.puts "xori #{operands[2].mipsOperand}, 1"
1003 when "cib", "cpb", "cbb"
1004 $asm.puts "sltu #{operands[2].mipsOperand}, #{operands[0].mipsOperand}, #{operands[1].mipsOperand}"
1005 when "cibeq", "cpbeq", "cbbeq"
1006 $asm.puts "sltu #{operands[2].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}"
1007 $asm.puts "xori #{operands[2].mipsOperand}, 1"
1008 when "cigt", "cpgt", "cbgt"
1009 $asm.puts "slt #{operands[2].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}"
1010 when "cigteq", "cpgteq", "cbgteq"
1011 $asm.puts "slt #{operands[2].mipsOperand}, #{operands[0].mipsOperand}, #{operands[1].mipsOperand}"
1012 $asm.puts "xori #{operands[2].mipsOperand}, 1"
1013 when "cilt", "cplt", "cblt"
1014 $asm.puts "slt #{operands[2].mipsOperand}, #{operands[0].mipsOperand}, #{operands[1].mipsOperand}"
1015 when "cilteq", "cplteq", "cblteq"
1016 $asm.puts "slt #{operands[2].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}"
1017 $asm.puts "xori #{operands[2].mipsOperand}, 1"
1018 when "cdgt"
1019 emitMIPSDoubleCompare("ule", true, operands)
1020 when "cdgteq"
1021 emitMIPSDoubleCompare("ult", true, operands)
1022 when "cdlt"
1023 emitMIPSDoubleCompare("olt", false, operands)
1024 when "cdlteq"
1025 emitMIPSDoubleCompare("ole", false, operands)
1026 when "peek"
1027 $asm.puts "lw #{operands[1].mipsOperand}, #{operands[0].value * 4}($sp)"
1028 when "poke"
1029 $asm.puts "sw #{operands[1].mipsOperand}, #{operands[0].value * 4}($sp)"
1030 when "fii2d"
1031 $asm.puts "mtc1 #{operands[0].mipsOperand}, #{operands[2].mipsSingleLo}"
1032 $asm.putStr("#if WTF_MIPS_ISA_REV_AT_LEAST(2)")
1033 $asm.puts "mthc1 #{operands[1].mipsOperand}, #{operands[2].mipsSingleLo}"
1034 $asm.putStr("#else")
1035 $asm.puts "mtc1 #{operands[1].mipsOperand}, #{operands[2].mipsSingleHi}"
1036 $asm.putStr("#endif")
1037 when "fd2ii"
1038 $asm.puts "mfc1 #{operands[1].mipsOperand}, #{operands[0].mipsSingleLo}"
1039 $asm.putStr("#if WTF_MIPS_ISA_REV_AT_LEAST(2)")
1040 $asm.puts "mfhc1 #{operands[2].mipsOperand}, #{operands[0].mipsSingleLo}"
1041 $asm.putStr("#else")
1042 $asm.puts "mfc1 #{operands[2].mipsOperand}, #{operands[0].mipsSingleHi}"
1043 $asm.putStr("#endif")
1044 when /^bo/
1045 $asm.puts "bgt #{operands[0].mipsOperand}, #{operands[1].mipsOperand}, #{operands[2].asmLabel}"
1046 when /^bs/
1047 $asm.puts "blt #{operands[0].mipsOperand}, #{operands[1].mipsOperand}, #{operands[2].asmLabel}"
1048 when /^bz/
1049 $asm.puts "beq #{operands[0].mipsOperand}, #{operands[1].mipsOperand}, #{operands[2].asmLabel}"
1050 when /^bnz/
1051 $asm.puts "bne #{operands[0].mipsOperand}, #{operands[1].mipsOperand}, #{operands[2].asmLabel}"
1052 when "leai", "leap"
1053 if operands[0].is_a? LabelReference
1054 labelRef = operands[0]
1055 $asm.puts "lw #{operands[1].mipsOperand}, %got(#{labelRef.asmLabel})($gp)"
1056 if labelRef.offset > 0
1057 $asm.puts "addu #{operands[1].mipsOperand}, #{operands[1].mipsOperand}, #{labelRef.offset}"
1058 end
1059 else
1060 operands[0].mipsEmitLea(operands[1])
1061 end
1062
1063 when "smulli"
1064 raise "Wrong number of arguments to smull in #{self.inspect} at #{codeOriginString}" unless operands.length == 4
1065 $asm.puts "mult #{operands[0].mipsOperand}, #{operands[1].mipsOperand}"
1066 $asm.puts "mflo #{operands[2].mipsOperand}"
1067 $asm.puts "mfhi #{operands[3].mipsOperand}"
1068 when "movz"
1069 $asm.puts "movz #{operands[0].mipsOperand}, #{operands[1].mipsOperand}, #{operands[2].mipsOperand}"
1070 when "movn"
1071 $asm.puts "movn #{operands[0].mipsOperand}, #{operands[1].mipsOperand}, #{operands[2].mipsOperand}"
1072 when "setcallreg"
1073 $asm.puts "move #{MIPS_CALL_REG.mipsOperand}, #{operands[0].mipsOperand}"
1074 when "slt", "sltb"
1075 $asm.puts "slt #{operands[0].mipsOperand}, #{operands[1].mipsOperand}, #{operands[2].mipsOperand}"
1076 when "sltu", "sltub"
1077 $asm.puts "sltu #{operands[0].mipsOperand}, #{operands[1].mipsOperand}, #{operands[2].mipsOperand}"
1078 when "pichdr"
1079 $asm.putStr("OFFLINE_ASM_CPLOAD(#{operands[0].mipsOperand})")
1080 when "memfence"
1081 $asm.puts "sync"
1082 else
1083 lowerDefault
1084 end
1085 end
1086end
Note: See TracBrowser for help on using the repository browser.