]>
git.saurik.com Git - apple/javascriptcore.git/blob - offlineasm/mips.rb
1 # Copyright (C) 2012 Apple Inc. All rights reserved.
2 # Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved.
4 # Redistribution and use in source and binary forms, with or without
5 # modification, are permitted provided that the following conditions
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.
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.
35 doubleOperand
= mipsOperand
36 raise "Bogus register name #{doubleOperand}" unless doubleOperand
=~
/^\$f/
37 "$f" +
($~
.post_match
.to_i +
1).to_s
40 doubleOperand
= mipsOperand
41 raise "Bogus register name #{doubleOperand}" unless doubleOperand
=~
/^\$f/
46 class SpecialRegister
< NoChildren
60 MIPS_TEMP_GPRS
= [SpecialRegister
.new("$t5"), SpecialRegister
.new("$t6"), SpecialRegister
.new("$t7"),
61 SpecialRegister
.new("$t8")]
62 MIPS_ZERO_REG
= SpecialRegister
.new("$zero")
63 MIPS_GP_REG
= SpecialRegister
.new("$gp")
64 MIPS_GPSAVE_REG
= SpecialRegister
.new("$s4")
65 MIPS_JUMP_REG
= SpecialRegister
.new("$ra")
66 MIPS_CALL_REG
= SpecialRegister
.new("$t9")
67 MIPS_TEMP_FPRS
= [SpecialRegister
.new("$f16")]
68 MIPS_SCRATCH_FPR
= SpecialRegister
.new("$f18")
70 def mipsMoveImmediate(value
, register
)
72 $asm.puts
"add #{register.mipsOperand}, $zero, $zero"
74 $asm.puts
"li #{register.mipsOperand}, #{value}"
93 when "t4" # PC reg in llint
110 raise "Bad register #{name} for MIPS at #{codeOriginString}"
135 raise "Bad register #{name} for MIPS at #{codeOriginString}"
142 raise "Invalid immediate #{value} at #{codeOriginString}" if value
< -0x7fff or value
> 0x7fff
149 raise "Bad offset at #{codeOriginString}" if offset
.value
< -0x7fff or offset
.value
> 0x7fff
150 "#{offset.value}(#{base.mipsOperand})"
154 class AbsoluteAddress
156 raise "Unconverted absolute address at #{codeOriginString}"
161 # Lower 'and' masked branches
164 def lowerMIPSCondBranch(list
, condOp
, node
)
165 if node
.operands
.size
== 2
166 list
<< Instruction
.new(node
.codeOrigin
,
168 [node
.operands
[0], MIPS_ZERO_REG
, node
.operands
[-1]],
170 elsif node
.operands
.size
== 3
171 tmp
= Tmp
.new(node
.codeOrigin
, :gpr)
172 list
<< Instruction
.new(node
.codeOrigin
,
174 [node
.operands
[0], node
.operands
[1], tmp
],
176 list
<< Instruction
.new(node
.codeOrigin
,
178 [tmp
, MIPS_ZERO_REG
, node
.operands
[-1]])
180 raise "Expected 2 or 3 operands but got #{node.operands.size} at #{node.codeOriginString}"
185 # Lowering of branch ops. For example:
187 # baddiz foo, bar, baz
195 def mipsLowerSimpleBranchOps(list
)
199 if node
.is_a
? Instruction
200 annotation
= node
.annotation
202 when /^b(addi|subi|ori|addp)/
221 # blt $t0, $zero, no overflow
223 # blt $t0, $zero, overflow
226 tr
= Tmp
.new(node
.codeOrigin
, :gpr)
227 tmp
= Tmp
.new(node
.codeOrigin
, :gpr)
228 noFlow
= LocalLabel
.unique("noflow")
229 noFlowRef
= LocalLabelReference
.new(node
.codeOrigin
, noFlow
)
230 newList
<< Instruction
.new(node
.codeOrigin
, op
, [node
.operands
[0], node
.operands
[1], tr
], annotation
)
231 newList
<< Instruction
.new(node
.codeOrigin
, "xori", [node
.operands
[0], node
.operands
[1], tmp
])
232 newList
<< Instruction
.new(node
.codeOrigin
, "bilt", [tmp
, MIPS_ZERO_REG
, noFlowRef
])
233 newList
<< Instruction
.new(node
.codeOrigin
, "xori", [tr
, node
.operands
[0], tmp
])
234 newList
<< Instruction
.new(node
.codeOrigin
, "bilt", [tmp
, MIPS_ZERO_REG
, node
.operands
[2]])
236 newList
<< Instruction
.new(node
.codeOrigin
, "move", [tr
, node
.operands
[1]])
240 # bge $t0, $zero, no overflow
242 # blt $t0, $zero, overflow
245 tr
= Tmp
.new(node
.codeOrigin
, :gpr)
246 tmp
= Tmp
.new(node
.codeOrigin
, :gpr)
247 noFlow
= LocalLabel
.unique("noflow")
248 noFlowRef
= LocalLabelReference
.new(node
.codeOrigin
, noFlow
)
249 newList
<< Instruction
.new(node
.codeOrigin
, op
, [node
.operands
[1], node
.operands
[0], tr
], annotation
)
250 newList
<< Instruction
.new(node
.codeOrigin
, "xori", [node
.operands
[1], node
.operands
[0], tmp
])
251 newList
<< Instruction
.new(node
.codeOrigin
, "bigteq", [tmp
, MIPS_ZERO_REG
, noFlowRef
])
252 newList
<< Instruction
.new(node
.codeOrigin
, "xori", [tr
, node
.operands
[1], tmp
])
253 newList
<< Instruction
.new(node
.codeOrigin
, "bilt", [tmp
, MIPS_ZERO_REG
, node
.operands
[2]])
255 newList
<< Instruction
.new(node
.codeOrigin
, "move", [tr
, node
.operands
[1]])
257 # no ovwerflow at ori
258 newList
<< Instruction
.new(node
.codeOrigin
, op
, node
.operands
[0..1], annotation
)
261 if node
.operands
[1].is_a
? Address
262 addr
= node
.operands
[1]
263 tr
= Tmp
.new(node
.codeOrigin
, :gpr)
264 newList
<< Instruction
.new(node
.codeOrigin
, "loadp", [addr
, tr
], annotation
)
265 newList
<< Instruction
.new(node
.codeOrigin
, op
, [node
.operands
[0], tr
])
266 newList
<< Instruction
.new(node
.codeOrigin
, "storep", [tr
, addr
])
268 tr
= node
.operands
[1]
269 newList
<< Instruction
.new(node
.codeOrigin
, op
, node
.operands
[0..-2], annotation
)
271 newList
<< Instruction
.new(node
.codeOrigin
, branch
, [tr
, MIPS_ZERO_REG
, node
.operands
[-1]])
273 when "bia", "bpa", "bba"
274 tmp
= Tmp
.new(node
.codeOrigin
, :gpr)
275 comp
= node
.opcode
[1] == ?b
? "sltub" : "sltu"
276 newList
<< Instruction
.new(node
.codeOrigin
, comp
, [tmp
, node
.operands
[1], node
.operands
[0]], annotation
)
277 newList
<< Instruction
.new(node
.codeOrigin
, "bnz", [tmp
, MIPS_ZERO_REG
, node
.operands
[2]])
278 when "biaeq", "bpaeq", "bbaeq"
279 tmp
= Tmp
.new(node
.codeOrigin
, :gpr)
280 comp
= node
.opcode
[1] == ?b
? "sltub" : "sltu"
281 newList
<< Instruction
.new(node
.codeOrigin
, comp
, [tmp
, node
.operands
[0], node
.operands
[1]], annotation
)
282 newList
<< Instruction
.new(node
.codeOrigin
, "bz", [tmp
, MIPS_ZERO_REG
, node
.operands
[2]])
283 when "bib", "bpb", "bbb"
284 tmp
= Tmp
.new(node
.codeOrigin
, :gpr)
285 comp
= node
.opcode
[1] == ?b
? "sltub" : "sltu"
286 newList
<< Instruction
.new(node
.codeOrigin
, comp
, [tmp
, node
.operands
[0], node
.operands
[1]], annotation
)
287 newList
<< Instruction
.new(node
.codeOrigin
, "bnz", [tmp
, MIPS_ZERO_REG
, node
.operands
[2]])
288 when "bibeq", "bpbeq", "bbbeq"
289 tmp
= Tmp
.new(node
.codeOrigin
, :gpr)
290 comp
= node
.opcode
[1] == ?b
? "sltub" : "sltu"
291 newList
<< Instruction
.new(node
.codeOrigin
, comp
, [tmp
, node
.operands
[1], node
.operands
[0]], annotation
)
292 newList
<< Instruction
.new(node
.codeOrigin
, "bz", [tmp
, MIPS_ZERO_REG
, node
.operands
[2]])
294 lowerMIPSCondBranch(newList
, "b" + $~
.post_match +
$1, node
)
306 # Specialization of lowering of malformed BaseIndex addresses.
310 def mipsLowerMalformedAddressesRecurse(list
, topLevelNode
, &block
)
313 subNode
.mipsLowerMalformedAddressesRecurse(list
, topLevelNode
, &block
)
319 def mipsLowerMalformedAddressesRecurse(list
, node
, &block
)
320 riscLowerMalformedAddressesRecurse(list
, node
, &block
)
325 def mipsLowerMalformedAddressesRecurse(list
, node
, &block
)
327 tmp0
= Tmp
.new(codeOrigin
, :gpr)
328 list
<< Instruction
.new(codeOrigin
, "addp", [base
, index
, tmp0
])
329 Address
.new(codeOrigin
, tmp0
, Immediate
.new(codeOrigin
, offset
.value
));
331 tmp0
= Tmp
.new(codeOrigin
, :gpr)
332 list
<< Instruction
.new(codeOrigin
, "lshifti", [index
, Immediate
.new(codeOrigin
, scaleShift
), tmp0
]);
333 list
<< Instruction
.new(codeOrigin
, "addp", [base
, tmp0
])
334 Address
.new(codeOrigin
, tmp0
, Immediate
.new(codeOrigin
, offset
.value
));
339 class AbsoluteAddress
340 def mipsLowerMalformedAddressesRecurse(list
, node
, &block
)
341 riscLowerMalformedAddressesRecurse(list
, node
, &block
)
345 def mipsLowerMalformedAddresses(list
, &block
)
349 newList
<< node
.mipsLowerMalformedAddressesRecurse(newList
, node
, &block
)
355 # Lowering of misplaced immediates of MIPS specific instructions. For example:
365 def mipsLowerMisplacedImmediates(list
)
369 if node
.is_a
? Instruction
371 when "slt", "sltu", "sltb", "sltub"
372 if node
.operands
[1].is_a
? Immediate
373 tmp
= Tmp
.new(node
.codeOrigin
, :gpr)
374 newList
<< Instruction
.new(node
.codeOrigin
, "move", [node
.operands
[1], tmp
], node
.annotation
)
375 newList
<< Instruction
.new(node
.codeOrigin
, node
.opcode
,
376 [node
.operands
[0], tmp
, node
.operands
[2]],
392 # Specialization of lowering of misplaced addresses.
395 def mipsLowerMisplacedAddresses(list
)
399 if node
.is_a
? Instruction
400 postInstructions
= []
401 annotation
= node
.annotation
404 if node
.operands
[0].address
?
405 newList
<< Instruction
.new(node
.operands
[0].codeOrigin
, "loadi", [node
.operands
[0], MIPS_JUMP_REG
])
406 newList
<< Instruction
.new(node
.codeOrigin
, node
.opcode
, [MIPS_JUMP_REG
])
408 newList
<< Instruction
.new(node
.codeOrigin
,
410 [riscAsRegister(newList
, postInstructions
, node
.operands
[0], "p", false)])
415 if node
.operands
[0].address
?
416 newList
<< Instruction
.new(node
.operands
[0].codeOrigin
, "loadp", [node
.operands
[0], MIPS_CALL_REG
])
418 elsif node
.operands
[0].is_a
? LabelReference
419 tmp
= node
.operands
[0]
421 elsif node
.operands
[0].register
?
422 newList
<< Instruction
.new(node
.operands
[0].codeOrigin
, "move", [node
.operands
[0], MIPS_CALL_REG
])
425 tmp
= node
.operands
[0]
427 newList
<< Instruction
.new(node
.codeOrigin
, node
.opcode
, [tmp
])
429 newList
<< Instruction
.new(node
.codeOrigin
, "move", [MIPS_GPSAVE_REG
, MIPS_GP_REG
])
432 newList
<< Instruction
.new(node
.codeOrigin
,
434 riscAsRegisters(newList
, [], node
.operands
, "i"))
436 newList
<< Instruction
.new(node
.codeOrigin
,
438 riscAsRegisters(newList
, [], node
.operands
, "b"))
439 when /^(bz|bnz|bs|bo)/
440 tl
= $~
.post_match
== "" ? "i" : $~
.post_match
441 newList
<< Instruction
.new(node
.codeOrigin
,
443 riscAsRegisters(newList
, [], node
.operands
, tl
))
447 newList +
= postInstructions
456 # Lowering compares and tests.
459 def mipsLowerCompareTemplate(list
, node
, opCmp
, opMov
)
460 tmp0
= Tmp
.new(node
.codeOrigin
, :gpr)
461 tmp1
= Tmp
.new(node
.codeOrigin
, :gpr)
462 list
<< Instruction
.new(node
.codeOrigin
, "move", [Immediate
.new(nil, 0), node
.operands
[2]])
463 list
<< Instruction
.new(node
.codeOrigin
, opCmp
, [node
.operands
[1], node
.operands
[0], tmp0
])
464 list
<< Instruction
.new(node
.codeOrigin
, "move", [Immediate
.new(nil, 1), tmp1
])
465 list
<< Instruction
.new(node
.codeOrigin
, opMov
, [node
.operands
[2], tmp1
, tmp0
])
468 def mipsLowerCompares(list
)
472 if node
.is_a
? Instruction
474 when "cieq", "cpeq", "cbeq"
475 mipsLowerCompareTemplate(newList
, node
, "subp", "movz")
476 when "cineq", "cpneq", "cbneq"
477 mipsLowerCompareTemplate(newList
, node
, "subp", "movn")
478 when "tiz", "tbz", "tpz"
479 mipsLowerCompareTemplate(newList
, node
, "andp", "movz")
480 when "tinz", "tbnz", "tpnz"
481 mipsLowerCompareTemplate(newList
, node
, "andp", "movn")
482 when "tio", "tbo", "tpo"
483 tmp
= Tmp
.new(node
.codeOrigin
, :gpr)
484 list
<< Instruction
.new(node
.codeOrigin
, "andp", [node
.operands
[1], node
.operands
[0], tmp
])
485 list
<< Instruction
.new(node
.codeOrigin
, "slt", [node
.operands
[2], MIPS_ZERO_REG
, tmp
])
486 when "tis", "tbs", "tps"
487 tmp
= Tmp
.new(node
.codeOrigin
, :gpr)
488 list
<< Instruction
.new(node
.codeOrigin
, "andp", [node
.operands
[1], node
.operands
[0], tmp
])
489 list
<< Instruction
.new(node
.codeOrigin
, "slt", [node
.operands
[2], tmp
, MIPS_ZERO_REG
])
505 def mipsEmitLea(destination
)
506 if destination
== base
507 $asm.puts
"addiu #{destination.mipsOperand}, #{offset.value}"
509 $asm.puts
"addiu #{destination.mipsOperand}, #{base.mipsOperand}, #{offset.value}"
515 # Add PIC compatible header code to prologue/entry rutins.
518 def mipsAddPICCode(list
)
524 if /_prologue$/.match(node
.name
) || /^_llint_function_/.match(node
.name
)
525 # Functions called from trampoline/JIT codes.
526 myList
<< Instruction
.new(node
.codeOrigin
, "pichdr", [])
527 elsif /_llint_op_catch/.match(node
.name
)
528 # Exception cactcher entry point function.
529 myList
<< Instruction
.new(node
.codeOrigin
, "pichdrra", [])
537 # Actual lowering code follows.
541 def getModifiedListMIPS
544 # Verify that we will only see instructions and labels.
547 unless node
.is_a
? Instruction
or
549 node
.is_a
? LocalLabel
or
551 raise "Unexpected #{node.inspect} at #{node.codeOrigin}"
555 result
= mipsAddPICCode(result
)
556 result
= mipsLowerSimpleBranchOps(result
)
557 result
= riscLowerSimpleBranchOps(result
)
558 result
= riscLowerHardBranchOps(result
)
559 result
= riscLowerShiftOps(result
)
560 result
= mipsLowerMalformedAddresses(result
) {
562 if address
.is_a
? Address
563 (-0xffff..0xffff
).include? address
.offset
.value
568 result
= riscLowerMalformedAddressesDouble(result
)
569 result
= riscLowerMisplacedImmediates(result
, ["storeb", "storei", "storep"])
570 result
= mipsLowerMisplacedImmediates(result
)
571 result
= riscLowerMalformedImmediates(result
, -0xffff..0xffff
)
572 result
= mipsLowerMisplacedAddresses(result
)
573 result
= riscLowerMisplacedAddresses(result
)
574 result
= riscLowerRegisterReuse(result
)
575 result
= mipsLowerCompares(result
)
576 result
= assignRegistersToTemporaries(result
, :gpr, MIPS_TEMP_GPRS
)
577 result
= assignRegistersToTemporaries(result
, :fpr, MIPS_TEMP_FPRS
)
583 def mipsOperands(operands
)
584 operands
.map
{|v
| v
.mipsOperand
}.join(", ")
587 def mipsFlippedOperands(operands
)
588 mipsOperands([operands
[-1]] + operands
[0..-2])
591 def getMIPSOpcode(opcode
, suffix
)
595 def emitMIPSCompact(opcode
, opcodei
, operands
)
598 if operands
[0].is_a
? Immediate
600 operands
[0] = Immediate
.new(operands
[0].codeOrigin
, -1 * operands
[0].value
)
601 elsif operands
[1].is_a
? Immediate
603 operands
[1] = Immediate
.new(operands
[1].codeOrigin
, -1 * operands
[1].value
)
606 elsif opcode
== "add"
609 if operands
.size
== 3
610 if operands
[0].is_a
? Immediate
611 $asm.puts
"#{opcode}i#{postfix} #{operands[2].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].value}"
612 elsif operands
[1].is_a
? Immediate
613 $asm.puts
"#{opcode}i#{postfix} #{operands[2].mipsOperand}, #{operands[0].mipsOperand}, #{operands[1].value}"
615 $asm.puts
"#{opcode}#{postfix} #{mipsFlippedOperands(operands)}"
618 raise unless operands
.size
== 2
619 raise unless operands
[1].register
?
620 if operands
[0].is_a
? Immediate
621 $asm.puts
"#{opcode}i#{postfix} #{operands[1].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}"
623 $asm.puts
"#{opcode}#{postfix} #{operands[1].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}"
628 def emitMIPSShiftCompact(opcode
, operands
)
629 if operands
.size
== 3
630 if (operands
[1].is_a
? Immediate
)
631 $asm.puts
"#{opcode} #{operands[2].mipsOperand}, #{operands[0].mipsOperand}, #{operands[1].value}"
633 $asm.puts
"#{opcode}v #{mipsFlippedOperands(operands)}"
636 raise unless operands
.size
== 2
637 if operands
[0].register
?
638 $asm.puts
"#{opcode}v #{operands[1].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}"
640 $asm.puts
"#{opcode} #{operands[1].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].value}"
645 def emitMIPS(opcode
, operands
)
646 if operands
.size
== 3
647 $asm.puts
"#{opcode} #{mipsFlippedOperands(operands)}"
649 raise unless operands
.size
== 2
650 $asm.puts
"#{opcode} #{operands[1].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}"
654 def emitMIPSDoubleBranch(branchOpcode
, neg
, operands
)
655 $asm.puts
"c.#{branchOpcode}.d #{mipsOperands(operands[0..1])}"
657 $asm.puts
"bc1t #{operands[2].asmLabel}"
659 $asm.puts
"bc1f #{operands[2].asmLabel}"
665 $asm.comment codeOriginString
667 when "addi", "addp", "addis"
668 if operands
.size
== 3 and operands
[0].is_a
? Immediate
669 raise unless operands
[1].register
?
670 raise unless operands
[2].register
?
671 if operands
[0].value
== 0 #and suffix.empty?
672 unless operands
[1] == operands
[2]
673 $asm.puts
"move #{operands[2].mipsOperand}, #{operands[1].mipsOperand}"
676 $asm.puts
"addiu #{operands[2].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}"
678 elsif operands
.size
== 3 and operands
[0].register
?
679 raise unless operands
[1].register
?
680 raise unless operands
[2].register
?
681 $asm.puts
"addu #{mipsFlippedOperands(operands)}"
683 if operands
[0].is_a
? Immediate
684 unless Immediate
.new(nil, 0) == operands
[0]
685 $asm.puts
"addiu #{operands[1].mipsOperand}, #{mipsFlippedOperands(operands)}"
688 $asm.puts
"addu #{operands[1].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}"
692 emitMIPSCompact("and", "and", operands
)
694 emitMIPSCompact("or", "orr", operands
)
696 emitMIPSCompact("or", "orrs", operands
)
698 emitMIPSCompact("xor", "eor", operands
)
699 when "lshifti", "lshiftp"
700 emitMIPSShiftCompact("sll", operands
)
701 when "rshifti", "rshiftp"
702 emitMIPSShiftCompact("sra", operands
)
703 when "urshifti", "urshiftp"
704 emitMIPSShiftCompact("srl", operands
)
706 emitMIPS("mul", operands
)
707 when "subi", "subp", "subis"
708 emitMIPSCompact("sub", "subs", operands
)
710 $asm.puts
"negu #{operands[0].mipsOperand}, #{operands[0].mipsOperand}"
712 $asm.puts
"nor #{operands[0].mipsOperand}, #{operands[0].mipsOperand}, $zero"
713 when "loadi", "loadis", "loadp"
714 $asm.puts
"lw #{mipsFlippedOperands(operands)}"
715 when "storei", "storep"
716 $asm.puts
"sw #{mipsOperands(operands)}"
718 $asm.puts
"lbu #{mipsFlippedOperands(operands)}"
720 $asm.puts
"lb #{mipsFlippedOperands(operands)}"
722 $asm.puts
"sb #{mipsOperands(operands)}"
724 $asm.puts
"lhu #{mipsFlippedOperands(operands)}"
726 $asm.puts
"lh #{mipsFlippedOperands(operands)}"
728 $asm.puts
"shv #{mipsOperands(operands)}"
730 $asm.puts
"ldc1 #{mipsFlippedOperands(operands)}"
732 $asm.puts
"sdc1 #{mipsOperands(operands)}"
734 emitMIPS("add.d", operands
)
736 emitMIPS("div.d", operands
)
738 emitMIPS("sub.d", operands
)
740 emitMIPS("mul.d", operands
)
742 $asm.puts
"sqrt.d #{mipsFlippedOperands(operands)}"
744 raise "invalid ops of #{self.inspect} at #{codeOriginString}" unless operands
[1].is_a
? FPRegisterID
and operands
[0].register
?
745 $asm.puts
"mtc1 #{operands[0].mipsOperand}, #{operands[1].mipsOperand}"
746 $asm.puts
"cvt.d.w #{operands[1].mipsOperand}, #{operands[1].mipsOperand}"
748 emitMIPSDoubleBranch("eq", false, operands
)
750 emitMIPSDoubleBranch("ueq", true, operands
)
752 emitMIPSDoubleBranch("ule", true, operands
)
754 emitMIPSDoubleBranch("ult", true, operands
)
756 emitMIPSDoubleBranch("olt", false, operands
)
758 emitMIPSDoubleBranch("ole", false, operands
)
760 emitMIPSDoubleBranch("ueq", false, operands
)
762 emitMIPSDoubleBranch("eq", true, operands
)
764 emitMIPSDoubleBranch("ole", true, operands
)
766 emitMIPSDoubleBranch("olt", true, operands
)
768 emitMIPSDoubleBranch("ult", false, operands
)
770 emitMIPSDoubleBranch("ule", false, operands
)
772 # FIXME: may be a good idea to just get rid of this instruction, since the interpreter
773 # currently does not use it.
774 raise "MIPS does not support this opcode yet, #{codeOrigin}"
776 $asm.puts
"cvt.w.d #{MIPS_SCRATCH_FPR.mipsSingleLo}, #{operands[0].mipsOperand}"
777 $asm.puts
"mfc1 #{operands[1].mipsOperand}, #{MIPS_SCRATCH_FPR.mipsSingleLo}"
779 $asm.puts
"cvt.w.d #{MIPS_SCRATCH_FPR.mipsSingleLo}, #{operands[0].mipsOperand}"
780 $asm.puts
"mfc1 #{operands[1].mipsOperand}, #{MIPS_SCRATCH_FPR.mipsSingleLo}"
781 $asm.puts
"cvt.d.w #{MIPS_SCRATCH_FPR.mipsOperand}, #{MIPS_SCRATCH_FPR.mipsSingleLo}"
782 emitMIPSDoubleBranch("eq", true, [MIPS_SCRATCH_FPR
, operands
[0], operands
[2]])
783 $asm.puts
"beq #{operands[1].mipsOperand}, $zero, #{operands[2].asmLabel}"
785 # FIXME: either support this or remove it.
786 raise "MIPS does not support this opcode yet, #{codeOrigin}"
788 $asm.puts
"lw #{operands[0].mipsOperand}, 0($sp)"
789 $asm.puts
"addiu $sp, $sp, 4"
791 $asm.puts
"addiu $sp, $sp, -4"
792 $asm.puts
"sw #{operands[0].mipsOperand}, 0($sp)"
793 when "move", "sxi2p", "zxi2p"
794 if operands
[0].is_a
? Immediate
795 mipsMoveImmediate(operands
[0].value
, operands
[1])
797 $asm.puts
"move #{mipsFlippedOperands(operands)}"
801 when "bieq", "bpeq", "bbeq"
802 $asm.puts
"beq #{mipsOperands(operands[0..1])}, #{operands[2].asmLabel}"
803 when "bineq", "bpneq", "bbneq"
804 $asm.puts
"bne #{mipsOperands(operands[0..1])}, #{operands[2].asmLabel}"
805 when "bigt", "bpgt", "bbgt"
806 $asm.puts
"bgt #{mipsOperands(operands[0..1])}, #{operands[2].asmLabel}"
807 when "bigteq", "bpgteq", "bbgteq"
808 $asm.puts
"bge #{mipsOperands(operands[0..1])}, #{operands[2].asmLabel}"
809 when "bilt", "bplt", "bblt"
810 $asm.puts
"blt #{mipsOperands(operands[0..1])}, #{operands[2].asmLabel}"
811 when "bilteq", "bplteq", "bblteq"
812 $asm.puts
"ble #{mipsOperands(operands[0..1])}, #{operands[2].asmLabel}"
814 if operands
[0].label
?
815 $asm.puts
"j #{operands[0].asmLabel}"
817 $asm.puts
"jr #{operands[0].mipsOperand}"
820 if operands
[0].label
?
821 $asm.puts
"jal #{operands[0].asmLabel}"
823 $asm.puts
"jalr #{operands[0].mipsOperand}"
829 when "cia", "cpa", "cba"
830 $asm.puts
"sltu #{operands[2].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}"
831 when "ciaeq", "cpaeq", "cbaeq"
832 $asm.puts
"sltu #{operands[2].mipsOperand}, #{operands[0].mipsOperand}, #{operands[1].mipsOperand}"
833 $asm.puts
"xori #{operands[2].mipsOperand}, 1"
834 when "cib", "cpb", "cbb"
835 $asm.puts
"sltu #{operands[2].mipsOperand}, #{operands[0].mipsOperand}, #{operands[1].mipsOperand}"
836 when "cibeq", "cpbeq", "cbbeq"
837 $asm.puts
"sltu #{operands[2].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}"
838 $asm.puts
"xori #{operands[2].mipsOperand}, 1"
839 when "cigt", "cpgt", "cbgt"
840 $asm.puts
"slt #{operands[2].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}"
841 when "cigteq", "cpgteq", "cbgteq"
842 $asm.puts
"slt #{operands[2].mipsOperand}, #{operands[0].mipsOperand}, #{operands[1].mipsOperand}"
843 $asm.puts
"xori #{operands[2].mipsOperand}, 1"
844 when "cilt", "cplt", "cblt"
845 $asm.puts
"slt #{operands[2].mipsOperand}, #{operands[0].mipsOperand}, #{operands[1].mipsOperand}"
846 when "cilteq", "cplteq", "cblteq"
847 $asm.puts
"slt #{operands[2].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}"
848 $asm.puts
"xori #{operands[2].mipsOperand}, 1"
850 $asm.puts
"lw #{operands[1].mipsOperand}, #{operands[0].value * 4}($sp)"
852 $asm.puts
"sw #{operands[1].mipsOperand}, #{operands[0].value * 4}($sp)"
854 $asm.puts
"mtc1 #{operands[0].mipsOperand}, #{operands[2].mipsSingleLo}"
855 $asm.puts
"mtc1 #{operands[1].mipsOperand}, #{operands[2].mipsSingleHi}"
857 $asm.puts
"mfc1 #{operands[1].mipsOperand}, #{operands[0].mipsSingleLo}"
858 $asm.puts
"mfc1 #{operands[2].mipsOperand}, #{operands[0].mipsSingleHi}"
860 $asm.puts
"bgt #{operands[0].mipsOperand}, #{operands[1].mipsOperand}, #{operands[2].asmLabel}"
862 $asm.puts
"blt #{operands[0].mipsOperand}, #{operands[1].mipsOperand}, #{operands[2].asmLabel}"
864 $asm.puts
"beq #{operands[0].mipsOperand}, #{operands[1].mipsOperand}, #{operands[2].asmLabel}"
866 $asm.puts
"bne #{operands[0].mipsOperand}, #{operands[1].mipsOperand}, #{operands[2].asmLabel}"
868 operands
[0].mipsEmitLea(operands
[1])
870 raise "Wrong number of arguments to smull in #{self.inspect} at #{codeOriginString}" unless operands
.length
== 4
871 $asm.puts
"mult #{operands[0].mipsOperand}, #{operands[1].mipsOperand}"
872 $asm.puts
"mflo #{operands[2].mipsOperand}"
873 $asm.puts
"mfhi #{operands[3].mipsOperand}"
875 $asm.puts
"movz #{operands[0].mipsOperand}, #{operands[1].mipsOperand}, #{operands[2].mipsOperand}"
877 $asm.puts
"movn #{operands[0].mipsOperand}, #{operands[1].mipsOperand}, #{operands[2].mipsOperand}"
879 $asm.puts
"slt #{operands[0].mipsOperand}, #{operands[1].mipsOperand}, #{operands[2].mipsOperand}"
881 $asm.puts
"sltu #{operands[0].mipsOperand}, #{operands[1].mipsOperand}, #{operands[2].mipsOperand}"
883 $asm.putStr("OFFLINE_ASM_CPLOAD($25)")
884 $asm.puts
"move $s4, $gp"
886 $asm.putStr("OFFLINE_ASM_CPLOAD($31)")
887 $asm.puts
"move $s4, $gp"
889 raise "Unhandled opcode #{opcode} at #{codeOriginString}"