]>
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_CALL_REG
= SpecialRegister
.new("$t9")
66 MIPS_TEMP_FPRS
= [SpecialRegister
.new("$f16")]
67 MIPS_SCRATCH_FPR
= SpecialRegister
.new("$f18")
69 def mipsMoveImmediate(value
, register
)
71 $asm.puts
"add #{register.mipsOperand}, $zero, $zero"
73 $asm.puts
"li #{register.mipsOperand}, #{value}"
96 when "t4" # PC reg in llint
113 raise "Bad register #{name} for MIPS at #{codeOriginString}"
138 raise "Bad register #{name} for MIPS at #{codeOriginString}"
145 raise "Invalid immediate #{value} at #{codeOriginString}" if value
< -0x7fff or value
> 0xffff
152 raise "Bad offset at #{codeOriginString}" if offset
.value
< -0x7fff or offset
.value
> 0x7fff
153 "#{offset.value}(#{base.mipsOperand})"
157 class AbsoluteAddress
159 raise "Unconverted absolute address at #{codeOriginString}"
164 # Negate condition of branches to labels.
168 def mipsNegateCondition(list
)
169 /^(b(add|sub|or|mul|t)?)([ipb])/.match(opcode
)
196 raise "Can't negate #{opcode} branch."
198 noBranch
= LocalLabel
.unique("nobranch")
199 noBranchRef
= LocalLabelReference
.new(codeOrigin
, noBranch
)
201 list
<< Instruction
.new(codeOrigin
, "#{$1}#{$3}#{op}", operands
[0..-2].push(noBranchRef
), annotation
)
202 list
<< Instruction
.new(codeOrigin
, "la", [toRef
, MIPS_CALL_REG
])
203 list
<< Instruction
.new(codeOrigin
, "jmp", [MIPS_CALL_REG
])
208 def mipsLowerFarBranchOps(list
)
212 if node
.is_a
? Instruction
213 annotation
= node
.annotation
215 when /^b(add|sub|or|mul|t)?([ipb])/
216 if node
.operands
[-1].is_a
? LabelReference
217 node
.mipsNegateCondition(newList
)
228 # Lower 'and' masked branches
231 def lowerMIPSCondBranch(list
, condOp
, node
)
232 if node
.operands
.size
== 2
233 list
<< Instruction
.new(node
.codeOrigin
,
235 [node
.operands
[0], MIPS_ZERO_REG
, node
.operands
[-1]],
237 elsif node
.operands
.size
== 3
238 tmp
= Tmp
.new(node
.codeOrigin
, :gpr)
239 list
<< Instruction
.new(node
.codeOrigin
,
241 [node
.operands
[0], node
.operands
[1], tmp
],
243 list
<< Instruction
.new(node
.codeOrigin
,
245 [tmp
, MIPS_ZERO_REG
, node
.operands
[-1]])
247 raise "Expected 2 or 3 operands but got #{node.operands.size} at #{node.codeOriginString}"
252 # Lowering of branch ops. For example:
254 # baddiz foo, bar, baz
262 def mipsLowerSimpleBranchOps(list
)
266 if node
.is_a
? Instruction
267 annotation
= node
.annotation
269 when /^b(addi|subi|ori|addp)/
288 # blt $t0, $zero, no overflow
290 # blt $t0, $zero, overflow
293 tr
= Tmp
.new(node
.codeOrigin
, :gpr)
294 tmp
= Tmp
.new(node
.codeOrigin
, :gpr)
295 noFlow
= LocalLabel
.unique("noflow")
296 noFlowRef
= LocalLabelReference
.new(node
.codeOrigin
, noFlow
)
297 newList
<< Instruction
.new(node
.codeOrigin
, op
, [node
.operands
[0], node
.operands
[1], tr
], annotation
)
298 newList
<< Instruction
.new(node
.codeOrigin
, "xori", [node
.operands
[0], node
.operands
[1], tmp
])
299 newList
<< Instruction
.new(node
.codeOrigin
, "bilt", [tmp
, MIPS_ZERO_REG
, noFlowRef
])
300 newList
<< Instruction
.new(node
.codeOrigin
, "xori", [tr
, node
.operands
[0], tmp
])
301 newList
<< Instruction
.new(node
.codeOrigin
, "bilt", [tmp
, MIPS_ZERO_REG
, node
.operands
[2]])
303 newList
<< Instruction
.new(node
.codeOrigin
, "move", [tr
, node
.operands
[1]])
307 # bge $t0, $zero, no overflow
309 # blt $t0, $zero, overflow
312 tr
= Tmp
.new(node
.codeOrigin
, :gpr)
313 tmp
= Tmp
.new(node
.codeOrigin
, :gpr)
314 noFlow
= LocalLabel
.unique("noflow")
315 noFlowRef
= LocalLabelReference
.new(node
.codeOrigin
, noFlow
)
316 newList
<< Instruction
.new(node
.codeOrigin
, op
, [node
.operands
[1], node
.operands
[0], tr
], annotation
)
317 newList
<< Instruction
.new(node
.codeOrigin
, "xori", [node
.operands
[1], node
.operands
[0], tmp
])
318 newList
<< Instruction
.new(node
.codeOrigin
, "bigteq", [tmp
, MIPS_ZERO_REG
, noFlowRef
])
319 newList
<< Instruction
.new(node
.codeOrigin
, "xori", [tr
, node
.operands
[1], tmp
])
320 newList
<< Instruction
.new(node
.codeOrigin
, "bilt", [tmp
, MIPS_ZERO_REG
, node
.operands
[2]])
322 newList
<< Instruction
.new(node
.codeOrigin
, "move", [tr
, node
.operands
[1]])
324 # no ovwerflow at ori
325 newList
<< Instruction
.new(node
.codeOrigin
, op
, node
.operands
[0..1], annotation
)
328 if node
.operands
[1].is_a
? Address
329 addr
= node
.operands
[1]
330 tr
= Tmp
.new(node
.codeOrigin
, :gpr)
331 newList
<< Instruction
.new(node
.codeOrigin
, "loadp", [addr
, tr
], annotation
)
332 newList
<< Instruction
.new(node
.codeOrigin
, op
, [node
.operands
[0], tr
])
333 newList
<< Instruction
.new(node
.codeOrigin
, "storep", [tr
, addr
])
335 tr
= node
.operands
[1]
336 newList
<< Instruction
.new(node
.codeOrigin
, op
, node
.operands
[0..-2], annotation
)
338 newList
<< Instruction
.new(node
.codeOrigin
, branch
, [tr
, MIPS_ZERO_REG
, node
.operands
[-1]])
340 when "bia", "bpa", "bba"
341 tmp
= Tmp
.new(node
.codeOrigin
, :gpr)
342 comp
= node
.opcode
[1] == ?b
? "sltub" : "sltu"
343 newList
<< Instruction
.new(node
.codeOrigin
, comp
, [tmp
, node
.operands
[1], node
.operands
[0]], annotation
)
344 newList
<< Instruction
.new(node
.codeOrigin
, "bnz", [tmp
, MIPS_ZERO_REG
, node
.operands
[2]])
345 when "biaeq", "bpaeq", "bbaeq"
346 tmp
= Tmp
.new(node
.codeOrigin
, :gpr)
347 comp
= node
.opcode
[1] == ?b
? "sltub" : "sltu"
348 newList
<< Instruction
.new(node
.codeOrigin
, comp
, [tmp
, node
.operands
[0], node
.operands
[1]], annotation
)
349 newList
<< Instruction
.new(node
.codeOrigin
, "bz", [tmp
, MIPS_ZERO_REG
, node
.operands
[2]])
350 when "bib", "bpb", "bbb"
351 tmp
= Tmp
.new(node
.codeOrigin
, :gpr)
352 comp
= node
.opcode
[1] == ?b
? "sltub" : "sltu"
353 newList
<< Instruction
.new(node
.codeOrigin
, comp
, [tmp
, node
.operands
[0], node
.operands
[1]], annotation
)
354 newList
<< Instruction
.new(node
.codeOrigin
, "bnz", [tmp
, MIPS_ZERO_REG
, node
.operands
[2]])
355 when "bibeq", "bpbeq", "bbbeq"
356 tmp
= Tmp
.new(node
.codeOrigin
, :gpr)
357 comp
= node
.opcode
[1] == ?b
? "sltub" : "sltu"
358 newList
<< Instruction
.new(node
.codeOrigin
, comp
, [tmp
, node
.operands
[1], node
.operands
[0]], annotation
)
359 newList
<< Instruction
.new(node
.codeOrigin
, "bz", [tmp
, MIPS_ZERO_REG
, node
.operands
[2]])
361 lowerMIPSCondBranch(newList
, "b" + $~
.post_match +
$1, node
)
373 # Specialization of lowering of malformed BaseIndex addresses.
377 def mipsLowerMalformedAddressesRecurse(list
)
380 subNode
.mipsLowerMalformedAddressesRecurse(list
)
384 def mipsLowerShiftedAddressesRecurse(list
, isFirst
, tmp
)
387 subNode
.mipsLowerShiftedAddressesRecurse(list
, isFirst
, tmp
)
393 def mipsLowerMalformedAddressesRecurse(list
)
394 tmp
= Tmp
.new(codeOrigin
, :gpr)
396 list
<< Instruction
.new(codeOrigin
, "addp", [base
, index
, tmp
])
397 Address
.new(codeOrigin
, tmp
, Immediate
.new(codeOrigin
, offset
.value
));
401 def mipsLowerShiftedAddressesRecurse(list
, isFirst
, tmp
)
403 list
<< Instruction
.new(codeOrigin
, "lshifti", [index
, Immediate
.new(codeOrigin
, scaleShift
), tmp
]);
404 list
<< Instruction
.new(codeOrigin
, "addp", [base
, tmp
])
406 Address
.new(codeOrigin
, tmp
, Immediate
.new(codeOrigin
, offset
.value
));
411 # Lowering of BaseIndex addresses with optimization for MIPS.
413 # offline asm instruction pair:
414 # loadi 4[cfr, t0, 8], t2
415 # loadi 0[cfr, t0, 8], t0
417 # lowered instructions:
424 def mipsHasShiftedBaseIndexAddress(instruction
)
425 instruction
.operands
.each_with_index
{
427 if operand
.is_a
? BaseIndex
and operand
.scaleShift !
= 0
434 def mipsScaleOfBaseIndexMatches(baseIndex0
, baseIndex1
)
435 baseIndex0
.base
== baseIndex1
.base
and
436 baseIndex0
.index
== baseIndex1
.index
and
437 baseIndex0
.scale
== baseIndex1
.scale
440 def mipsLowerBaseIndexAddresses(list
)
441 newList
= [ list
[0] ]
445 if nodes
[1].is_a
? Instruction
446 ind
= mipsHasShiftedBaseIndexAddress(nodes
[1])
448 if nodes
[0].is_a
? Instruction
and
449 nodes
[0].opcode
== nodes
[1].opcode
and
450 ind
== mipsHasShiftedBaseIndexAddress(nodes
[0]) and
451 mipsScaleOfBaseIndexMatches(nodes
[0].operands
[ind
], nodes
[1].operands
[ind
])
453 newList
<< nodes
[1].mipsLowerShiftedAddressesRecurse(newList
, false, tmp
)
455 tmp
= Tmp
.new(codeOrigin
, :gpr)
456 newList
<< nodes
[1].mipsLowerShiftedAddressesRecurse(newList
, true, tmp
)
459 newList
<< nodes
[1].mipsLowerMalformedAddressesRecurse(newList
)
469 # Lowering of misplaced immediates of MIPS specific instructions. For example:
479 def mipsLowerMisplacedImmediates(list
)
483 if node
.is_a
? Instruction
485 when "slt", "sltu", "sltb", "sltub"
486 if node
.operands
[1].is_a
? Immediate
487 tmp
= Tmp
.new(node
.codeOrigin
, :gpr)
488 newList
<< Instruction
.new(node
.codeOrigin
, "move", [node
.operands
[1], tmp
], node
.annotation
)
489 newList
<< Instruction
.new(node
.codeOrigin
, node
.opcode
,
490 [node
.operands
[0], tmp
, node
.operands
[2]],
496 newList
<< node
.riscLowerMalformedImmediatesRecurse(newList
, -0x7fff..0x7fff
)
508 # Specialization of lowering of misplaced addresses.
511 class LocalLabelReference
517 def mipsAsRegister(preList
, postList
, operand
, needRestore
)
520 preList
<< Instruction
.new(operand
.codeOrigin
, "loadp", [operand
, MIPS_CALL_REG
])
521 elsif operand
.is_a
? LabelReference
522 preList
<< Instruction
.new(operand
.codeOrigin
, "la", [operand
, MIPS_CALL_REG
])
523 elsif operand
.register
? and operand !
= MIPS_CALL_REG
524 preList
<< Instruction
.new(operand
.codeOrigin
, "move", [operand
, MIPS_CALL_REG
])
530 postList
<< Instruction
.new(operand
.codeOrigin
, "move", [MIPS_GPSAVE_REG
, MIPS_GP_REG
])
535 def mipsLowerMisplacedAddresses(list
)
539 if node
.is_a
? Instruction
540 postInstructions
= []
541 annotation
= node
.annotation
544 newList
<< Instruction
.new(node
.codeOrigin
,
546 [mipsAsRegister(newList
, [], node
.operands
[0], false)])
548 newList
<< Instruction
.new(node
.codeOrigin
,
550 [mipsAsRegister(newList
, postInstructions
, node
.operands
[0], true)])
552 newList
<< Instruction
.new(node
.codeOrigin
,
554 riscAsRegisters(newList
, [], node
.operands
, "i"))
556 newList
<< Instruction
.new(node
.codeOrigin
,
558 riscAsRegisters(newList
, [], node
.operands
, "b"))
559 when /^(bz|bnz|bs|bo)/
560 tl
= $~
.post_match
== "" ? "i" : $~
.post_match
561 newList
<< Instruction
.new(node
.codeOrigin
,
563 riscAsRegisters(newList
, [], node
.operands
, tl
))
567 newList +
= postInstructions
576 # Lowering compares and tests.
579 def mipsLowerCompareTemplate(list
, node
, opCmp
, opMov
)
580 tmp0
= Tmp
.new(node
.codeOrigin
, :gpr)
581 tmp1
= Tmp
.new(node
.codeOrigin
, :gpr)
582 list
<< Instruction
.new(node
.codeOrigin
, "move", [Immediate
.new(nil, 0), node
.operands
[2]])
583 list
<< Instruction
.new(node
.codeOrigin
, opCmp
, [node
.operands
[1], node
.operands
[0], tmp0
])
584 list
<< Instruction
.new(node
.codeOrigin
, "move", [Immediate
.new(nil, 1), tmp1
])
585 list
<< Instruction
.new(node
.codeOrigin
, opMov
, [node
.operands
[2], tmp1
, tmp0
])
588 def mipsLowerCompares(list
)
592 if node
.is_a
? Instruction
594 when "cieq", "cpeq", "cbeq"
595 mipsLowerCompareTemplate(newList
, node
, "subp", "movz")
596 when "cineq", "cpneq", "cbneq"
597 mipsLowerCompareTemplate(newList
, node
, "subp", "movn")
598 when "tiz", "tbz", "tpz"
599 mipsLowerCompareTemplate(newList
, node
, "andp", "movz")
600 when "tinz", "tbnz", "tpnz"
601 mipsLowerCompareTemplate(newList
, node
, "andp", "movn")
602 when "tio", "tbo", "tpo"
603 tmp
= Tmp
.new(node
.codeOrigin
, :gpr)
604 list
<< Instruction
.new(node
.codeOrigin
, "andp", [node
.operands
[1], node
.operands
[0], tmp
])
605 list
<< Instruction
.new(node
.codeOrigin
, "slt", [node
.operands
[2], MIPS_ZERO_REG
, tmp
])
606 when "tis", "tbs", "tps"
607 tmp
= Tmp
.new(node
.codeOrigin
, :gpr)
608 list
<< Instruction
.new(node
.codeOrigin
, "andp", [node
.operands
[1], node
.operands
[0], tmp
])
609 list
<< Instruction
.new(node
.codeOrigin
, "slt", [node
.operands
[2], tmp
, MIPS_ZERO_REG
])
625 def mipsEmitLea(destination
)
626 if destination
== base
627 $asm.puts
"addiu #{destination.mipsOperand}, #{offset.value}"
629 $asm.puts
"addiu #{destination.mipsOperand}, #{base.mipsOperand}, #{offset.value}"
635 # Add PIC compatible header code to all the LLInt rutins.
638 def mipsAddPICCode(list
)
644 myList
<< Instruction
.new(node
.codeOrigin
, "pichdr", [])
651 # Actual lowering code follows.
655 def getModifiedListMIPS
658 # Verify that we will only see instructions and labels.
661 unless node
.is_a
? Instruction
or
663 node
.is_a
? LocalLabel
or
665 raise "Unexpected #{node.inspect} at #{node.codeOrigin}"
669 result
= mipsAddPICCode(result
)
670 result
= mipsLowerFarBranchOps(result
)
671 result
= mipsLowerSimpleBranchOps(result
)
672 result
= riscLowerSimpleBranchOps(result
)
673 result
= riscLowerHardBranchOps(result
)
674 result
= riscLowerShiftOps(result
)
675 result
= mipsLowerBaseIndexAddresses(result
)
676 result
= riscLowerMalformedAddresses(result
) {
678 if address
.is_a
? Address
679 (-0xffff..0xffff
).include? address
.offset
.value
684 result
= riscLowerMalformedAddressesDouble(result
)
685 result
= riscLowerMisplacedImmediates(result
, ["storeb", "storei", "storep"])
686 result
= mipsLowerMisplacedImmediates(result
)
687 result
= riscLowerMalformedImmediates(result
, -0xffff..0xffff
)
688 result
= mipsLowerMisplacedAddresses(result
)
689 result
= riscLowerMisplacedAddresses(result
)
690 result
= riscLowerRegisterReuse(result
)
691 result
= mipsLowerCompares(result
)
692 result
= assignRegistersToTemporaries(result
, :gpr, MIPS_TEMP_GPRS
)
693 result
= assignRegistersToTemporaries(result
, :fpr, MIPS_TEMP_FPRS
)
699 def mipsOperands(operands
)
700 operands
.map
{|v
| v
.mipsOperand
}.join(", ")
703 def mipsFlippedOperands(operands
)
704 mipsOperands([operands
[-1]] + operands
[0..-2])
707 def getMIPSOpcode(opcode
, suffix
)
711 def emitMIPSCompact(opcode
, opcodei
, operands
)
714 if operands
[0].is_a
? Immediate
716 operands
[0] = Immediate
.new(operands
[0].codeOrigin
, -1 * operands
[0].value
)
717 elsif operands
[1].is_a
? Immediate
719 operands
[1] = Immediate
.new(operands
[1].codeOrigin
, -1 * operands
[1].value
)
722 elsif opcode
== "add"
725 if operands
.size
== 3
726 if operands
[0].is_a
? Immediate
727 $asm.puts
"#{opcode}i#{postfix} #{operands[2].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].value}"
728 elsif operands
[1].is_a
? Immediate
729 $asm.puts
"#{opcode}i#{postfix} #{operands[2].mipsOperand}, #{operands[0].mipsOperand}, #{operands[1].value}"
731 $asm.puts
"#{opcode}#{postfix} #{mipsFlippedOperands(operands)}"
734 raise unless operands
.size
== 2
735 raise unless operands
[1].register
?
736 if operands
[0].is_a
? Immediate
737 $asm.puts
"#{opcode}i#{postfix} #{operands[1].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}"
739 $asm.puts
"#{opcode}#{postfix} #{operands[1].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}"
744 def emitMIPSShiftCompact(opcode
, operands
)
745 if operands
.size
== 3
746 if (operands
[1].is_a
? Immediate
)
747 $asm.puts
"#{opcode} #{operands[2].mipsOperand}, #{operands[0].mipsOperand}, #{operands[1].value}"
749 $asm.puts
"#{opcode}v #{mipsFlippedOperands(operands)}"
752 raise unless operands
.size
== 2
753 if operands
[0].register
?
754 $asm.puts
"#{opcode}v #{operands[1].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}"
756 $asm.puts
"#{opcode} #{operands[1].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].value}"
761 def emitMIPS(opcode
, operands
)
762 if operands
.size
== 3
763 $asm.puts
"#{opcode} #{mipsFlippedOperands(operands)}"
765 raise unless operands
.size
== 2
766 $asm.puts
"#{opcode} #{operands[1].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}"
770 def emitMIPSDoubleBranch(branchOpcode
, neg
, operands
)
771 $asm.puts
"c.#{branchOpcode}.d #{mipsOperands(operands[0..1])}"
773 $asm.puts
"bc1t #{operands[2].asmLabel}"
775 $asm.puts
"bc1f #{operands[2].asmLabel}"
779 def emitMIPSJumpOrCall(opcode
, operand
)
781 raise "Direct call/jump to a not local label." unless operand
.is_a
? LocalLabelReference
782 $asm.puts
"#{opcode} #{operand.asmLabel}"
784 raise "Invalid call/jump register." unless operand
== MIPS_CALL_REG
785 $asm.puts
"#{opcode}r #{MIPS_CALL_REG.mipsOperand}"
791 $asm.comment codeOriginString
793 when "addi", "addp", "addis"
794 if operands
.size
== 3 and operands
[0].is_a
? Immediate
795 raise unless operands
[1].register
?
796 raise unless operands
[2].register
?
797 if operands
[0].value
== 0 #and suffix.empty?
798 unless operands
[1] == operands
[2]
799 $asm.puts
"move #{operands[2].mipsOperand}, #{operands[1].mipsOperand}"
802 $asm.puts
"addiu #{operands[2].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}"
804 elsif operands
.size
== 3 and operands
[0].register
?
805 raise unless operands
[1].register
?
806 raise unless operands
[2].register
?
807 $asm.puts
"addu #{mipsFlippedOperands(operands)}"
809 if operands
[0].is_a
? Immediate
810 unless Immediate
.new(nil, 0) == operands
[0]
811 $asm.puts
"addiu #{operands[1].mipsOperand}, #{mipsFlippedOperands(operands)}"
814 $asm.puts
"addu #{operands[1].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}"
818 emitMIPSCompact("and", "and", operands
)
820 emitMIPSCompact("or", "orr", operands
)
822 emitMIPSCompact("or", "orrs", operands
)
824 emitMIPSCompact("xor", "eor", operands
)
825 when "lshifti", "lshiftp"
826 emitMIPSShiftCompact("sll", operands
)
827 when "rshifti", "rshiftp"
828 emitMIPSShiftCompact("sra", operands
)
829 when "urshifti", "urshiftp"
830 emitMIPSShiftCompact("srl", operands
)
832 emitMIPS("mul", operands
)
833 when "subi", "subp", "subis"
834 emitMIPSCompact("sub", "subs", operands
)
836 $asm.puts
"negu #{operands[0].mipsOperand}, #{operands[0].mipsOperand}"
838 $asm.puts
"nor #{operands[0].mipsOperand}, #{operands[0].mipsOperand}, $zero"
839 when "loadi", "loadis", "loadp"
840 $asm.puts
"lw #{mipsFlippedOperands(operands)}"
841 when "storei", "storep"
842 $asm.puts
"sw #{mipsOperands(operands)}"
844 $asm.puts
"lbu #{mipsFlippedOperands(operands)}"
846 $asm.puts
"lb #{mipsFlippedOperands(operands)}"
848 $asm.puts
"sb #{mipsOperands(operands)}"
850 $asm.puts
"lhu #{mipsFlippedOperands(operands)}"
852 $asm.puts
"lh #{mipsFlippedOperands(operands)}"
854 $asm.puts
"shv #{mipsOperands(operands)}"
856 $asm.puts
"ldc1 #{mipsFlippedOperands(operands)}"
858 $asm.puts
"sdc1 #{mipsOperands(operands)}"
860 $asm.puts
"la #{operands[1].mipsOperand}, #{operands[0].asmLabel}"
862 emitMIPS("add.d", operands
)
864 emitMIPS("div.d", operands
)
866 emitMIPS("sub.d", operands
)
868 emitMIPS("mul.d", operands
)
870 $asm.puts
"sqrt.d #{mipsFlippedOperands(operands)}"
872 raise "invalid ops of #{self.inspect} at #{codeOriginString}" unless operands
[1].is_a
? FPRegisterID
and operands
[0].register
?
873 $asm.puts
"mtc1 #{operands[0].mipsOperand}, #{operands[1].mipsOperand}"
874 $asm.puts
"cvt.d.w #{operands[1].mipsOperand}, #{operands[1].mipsOperand}"
876 emitMIPSDoubleBranch("eq", false, operands
)
878 emitMIPSDoubleBranch("ueq", true, operands
)
880 emitMIPSDoubleBranch("ule", true, operands
)
882 emitMIPSDoubleBranch("ult", true, operands
)
884 emitMIPSDoubleBranch("olt", false, operands
)
886 emitMIPSDoubleBranch("ole", false, operands
)
888 emitMIPSDoubleBranch("ueq", false, operands
)
890 emitMIPSDoubleBranch("eq", true, operands
)
892 emitMIPSDoubleBranch("ole", true, operands
)
894 emitMIPSDoubleBranch("olt", true, operands
)
896 emitMIPSDoubleBranch("ult", false, operands
)
898 emitMIPSDoubleBranch("ule", false, operands
)
900 # FIXME: may be a good idea to just get rid of this instruction, since the interpreter
901 # currently does not use it.
902 raise "MIPS does not support this opcode yet, #{codeOrigin}"
904 $asm.puts
"cvt.w.d #{MIPS_SCRATCH_FPR.mipsSingleLo}, #{operands[0].mipsOperand}"
905 $asm.puts
"mfc1 #{operands[1].mipsOperand}, #{MIPS_SCRATCH_FPR.mipsSingleLo}"
907 $asm.puts
"cvt.w.d #{MIPS_SCRATCH_FPR.mipsSingleLo}, #{operands[0].mipsOperand}"
908 $asm.puts
"mfc1 #{operands[1].mipsOperand}, #{MIPS_SCRATCH_FPR.mipsSingleLo}"
909 $asm.puts
"cvt.d.w #{MIPS_SCRATCH_FPR.mipsOperand}, #{MIPS_SCRATCH_FPR.mipsSingleLo}"
910 emitMIPSDoubleBranch("eq", true, [MIPS_SCRATCH_FPR
, operands
[0], operands
[2]])
911 $asm.puts
"beq #{operands[1].mipsOperand}, $zero, #{operands[2].asmLabel}"
913 # FIXME: either support this or remove it.
914 raise "MIPS does not support this opcode yet, #{codeOrigin}"
918 $asm.puts
"lw #{op.mipsOperand}, 0($sp)"
919 $asm.puts
"addiu $sp, $sp, 4"
924 $asm.puts
"addiu $sp, $sp, -4"
925 $asm.puts
"sw #{op.mipsOperand}, 0($sp)"
927 when "move", "sxi2p", "zxi2p"
928 if operands
[0].is_a
? Immediate
929 mipsMoveImmediate(operands
[0].value
, operands
[1])
931 $asm.puts
"move #{mipsFlippedOperands(operands)}"
935 when "bieq", "bpeq", "bbeq"
936 $asm.puts
"beq #{mipsOperands(operands[0..1])}, #{operands[2].asmLabel}"
937 when "bineq", "bpneq", "bbneq"
938 $asm.puts
"bne #{mipsOperands(operands[0..1])}, #{operands[2].asmLabel}"
939 when "bigt", "bpgt", "bbgt"
940 $asm.puts
"bgt #{mipsOperands(operands[0..1])}, #{operands[2].asmLabel}"
941 when "bigteq", "bpgteq", "bbgteq"
942 $asm.puts
"bge #{mipsOperands(operands[0..1])}, #{operands[2].asmLabel}"
943 when "bilt", "bplt", "bblt"
944 $asm.puts
"blt #{mipsOperands(operands[0..1])}, #{operands[2].asmLabel}"
945 when "bilteq", "bplteq", "bblteq"
946 $asm.puts
"ble #{mipsOperands(operands[0..1])}, #{operands[2].asmLabel}"
948 emitMIPSJumpOrCall("j", operands
[0])
950 emitMIPSJumpOrCall("jal", operands
[0])
955 when "cia", "cpa", "cba"
956 $asm.puts
"sltu #{operands[2].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}"
957 when "ciaeq", "cpaeq", "cbaeq"
958 $asm.puts
"sltu #{operands[2].mipsOperand}, #{operands[0].mipsOperand}, #{operands[1].mipsOperand}"
959 $asm.puts
"xori #{operands[2].mipsOperand}, 1"
960 when "cib", "cpb", "cbb"
961 $asm.puts
"sltu #{operands[2].mipsOperand}, #{operands[0].mipsOperand}, #{operands[1].mipsOperand}"
962 when "cibeq", "cpbeq", "cbbeq"
963 $asm.puts
"sltu #{operands[2].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}"
964 $asm.puts
"xori #{operands[2].mipsOperand}, 1"
965 when "cigt", "cpgt", "cbgt"
966 $asm.puts
"slt #{operands[2].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}"
967 when "cigteq", "cpgteq", "cbgteq"
968 $asm.puts
"slt #{operands[2].mipsOperand}, #{operands[0].mipsOperand}, #{operands[1].mipsOperand}"
969 $asm.puts
"xori #{operands[2].mipsOperand}, 1"
970 when "cilt", "cplt", "cblt"
971 $asm.puts
"slt #{operands[2].mipsOperand}, #{operands[0].mipsOperand}, #{operands[1].mipsOperand}"
972 when "cilteq", "cplteq", "cblteq"
973 $asm.puts
"slt #{operands[2].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}"
974 $asm.puts
"xori #{operands[2].mipsOperand}, 1"
976 $asm.puts
"lw #{operands[1].mipsOperand}, #{operands[0].value * 4}($sp)"
978 $asm.puts
"sw #{operands[1].mipsOperand}, #{operands[0].value * 4}($sp)"
980 $asm.puts
"mtc1 #{operands[0].mipsOperand}, #{operands[2].mipsSingleLo}"
981 $asm.puts
"mtc1 #{operands[1].mipsOperand}, #{operands[2].mipsSingleHi}"
983 $asm.puts
"mfc1 #{operands[1].mipsOperand}, #{operands[0].mipsSingleLo}"
984 $asm.puts
"mfc1 #{operands[2].mipsOperand}, #{operands[0].mipsSingleHi}"
986 $asm.puts
"bgt #{operands[0].mipsOperand}, #{operands[1].mipsOperand}, #{operands[2].asmLabel}"
988 $asm.puts
"blt #{operands[0].mipsOperand}, #{operands[1].mipsOperand}, #{operands[2].asmLabel}"
990 $asm.puts
"beq #{operands[0].mipsOperand}, #{operands[1].mipsOperand}, #{operands[2].asmLabel}"
992 $asm.puts
"bne #{operands[0].mipsOperand}, #{operands[1].mipsOperand}, #{operands[2].asmLabel}"
994 operands
[0].mipsEmitLea(operands
[1])
996 raise "Wrong number of arguments to smull in #{self.inspect} at #{codeOriginString}" unless operands
.length
== 4
997 $asm.puts
"mult #{operands[0].mipsOperand}, #{operands[1].mipsOperand}"
998 $asm.puts
"mflo #{operands[2].mipsOperand}"
999 $asm.puts
"mfhi #{operands[3].mipsOperand}"
1001 $asm.puts
"movz #{operands[0].mipsOperand}, #{operands[1].mipsOperand}, #{operands[2].mipsOperand}"
1003 $asm.puts
"movn #{operands[0].mipsOperand}, #{operands[1].mipsOperand}, #{operands[2].mipsOperand}"
1005 $asm.puts
"slt #{operands[0].mipsOperand}, #{operands[1].mipsOperand}, #{operands[2].mipsOperand}"
1006 when "sltu", "sltub"
1007 $asm.puts
"sltu #{operands[0].mipsOperand}, #{operands[1].mipsOperand}, #{operands[2].mipsOperand}"
1009 $asm.putStr("OFFLINE_ASM_CPLOAD(#{MIPS_CALL_REG.mipsOperand})")
1010 $asm.puts
"move #{MIPS_GPSAVE_REG.mipsOperand}, #{MIPS_GP_REG.mipsOperand}"