]>
git.saurik.com Git - apple/javascriptcore.git/blob - offlineasm/mips.rb
686f58f164f0fc6bc166f6614bc971cde12d1b99
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}"
97 when "t4" # PC reg in llint
114 raise "Bad register #{name} for MIPS at #{codeOriginString}"
139 raise "Bad register #{name} for MIPS at #{codeOriginString}"
146 raise "Invalid immediate #{value} at #{codeOriginString}" if value
< -0x7fff or value
> 0xffff
153 raise "Bad offset at #{codeOriginString}" if offset
.value
< -0x7fff or offset
.value
> 0x7fff
154 "#{offset.value}(#{base.mipsOperand})"
158 class AbsoluteAddress
160 raise "Unconverted absolute address at #{codeOriginString}"
165 # Lower 'and' masked branches
168 def lowerMIPSCondBranch(list
, condOp
, node
)
169 if node
.operands
.size
== 2
170 list
<< Instruction
.new(node
.codeOrigin
,
172 [node
.operands
[0], MIPS_ZERO_REG
, node
.operands
[-1]],
174 elsif node
.operands
.size
== 3
175 tmp
= Tmp
.new(node
.codeOrigin
, :gpr)
176 list
<< Instruction
.new(node
.codeOrigin
,
178 [node
.operands
[0], node
.operands
[1], tmp
],
180 list
<< Instruction
.new(node
.codeOrigin
,
182 [tmp
, MIPS_ZERO_REG
, node
.operands
[-1]])
184 raise "Expected 2 or 3 operands but got #{node.operands.size} at #{node.codeOriginString}"
189 # Lowering of branch ops. For example:
191 # baddiz foo, bar, baz
199 def mipsLowerSimpleBranchOps(list
)
203 if node
.is_a
? Instruction
204 annotation
= node
.annotation
206 when /^b(addi|subi|ori|addp)/
225 # blt $t0, $zero, no overflow
227 # blt $t0, $zero, overflow
230 tr
= Tmp
.new(node
.codeOrigin
, :gpr)
231 tmp
= Tmp
.new(node
.codeOrigin
, :gpr)
232 noFlow
= LocalLabel
.unique("noflow")
233 noFlowRef
= LocalLabelReference
.new(node
.codeOrigin
, noFlow
)
234 newList
<< Instruction
.new(node
.codeOrigin
, op
, [node
.operands
[0], node
.operands
[1], tr
], annotation
)
235 newList
<< Instruction
.new(node
.codeOrigin
, "xori", [node
.operands
[0], node
.operands
[1], tmp
])
236 newList
<< Instruction
.new(node
.codeOrigin
, "bilt", [tmp
, MIPS_ZERO_REG
, noFlowRef
])
237 newList
<< Instruction
.new(node
.codeOrigin
, "xori", [tr
, node
.operands
[0], tmp
])
238 newList
<< Instruction
.new(node
.codeOrigin
, "bilt", [tmp
, MIPS_ZERO_REG
, node
.operands
[2]])
240 newList
<< Instruction
.new(node
.codeOrigin
, "move", [tr
, node
.operands
[1]])
244 # bge $t0, $zero, no overflow
246 # blt $t0, $zero, overflow
249 tr
= Tmp
.new(node
.codeOrigin
, :gpr)
250 tmp
= Tmp
.new(node
.codeOrigin
, :gpr)
251 noFlow
= LocalLabel
.unique("noflow")
252 noFlowRef
= LocalLabelReference
.new(node
.codeOrigin
, noFlow
)
253 newList
<< Instruction
.new(node
.codeOrigin
, op
, [node
.operands
[1], node
.operands
[0], tr
], annotation
)
254 newList
<< Instruction
.new(node
.codeOrigin
, "xori", [node
.operands
[1], node
.operands
[0], tmp
])
255 newList
<< Instruction
.new(node
.codeOrigin
, "bigteq", [tmp
, MIPS_ZERO_REG
, noFlowRef
])
256 newList
<< Instruction
.new(node
.codeOrigin
, "xori", [tr
, node
.operands
[1], tmp
])
257 newList
<< Instruction
.new(node
.codeOrigin
, "bilt", [tmp
, MIPS_ZERO_REG
, node
.operands
[2]])
259 newList
<< Instruction
.new(node
.codeOrigin
, "move", [tr
, node
.operands
[1]])
261 # no ovwerflow at ori
262 newList
<< Instruction
.new(node
.codeOrigin
, op
, node
.operands
[0..1], annotation
)
265 if node
.operands
[1].is_a
? Address
266 addr
= node
.operands
[1]
267 tr
= Tmp
.new(node
.codeOrigin
, :gpr)
268 newList
<< Instruction
.new(node
.codeOrigin
, "loadp", [addr
, tr
], annotation
)
269 newList
<< Instruction
.new(node
.codeOrigin
, op
, [node
.operands
[0], tr
])
270 newList
<< Instruction
.new(node
.codeOrigin
, "storep", [tr
, addr
])
272 tr
= node
.operands
[1]
273 newList
<< Instruction
.new(node
.codeOrigin
, op
, node
.operands
[0..-2], annotation
)
275 newList
<< Instruction
.new(node
.codeOrigin
, branch
, [tr
, MIPS_ZERO_REG
, node
.operands
[-1]])
277 when "bia", "bpa", "bba"
278 tmp
= Tmp
.new(node
.codeOrigin
, :gpr)
279 comp
= node
.opcode
[1] == ?b
? "sltub" : "sltu"
280 newList
<< Instruction
.new(node
.codeOrigin
, comp
, [tmp
, node
.operands
[1], node
.operands
[0]], annotation
)
281 newList
<< Instruction
.new(node
.codeOrigin
, "bnz", [tmp
, MIPS_ZERO_REG
, node
.operands
[2]])
282 when "biaeq", "bpaeq", "bbaeq"
283 tmp
= Tmp
.new(node
.codeOrigin
, :gpr)
284 comp
= node
.opcode
[1] == ?b
? "sltub" : "sltu"
285 newList
<< Instruction
.new(node
.codeOrigin
, comp
, [tmp
, node
.operands
[0], node
.operands
[1]], annotation
)
286 newList
<< Instruction
.new(node
.codeOrigin
, "bz", [tmp
, MIPS_ZERO_REG
, node
.operands
[2]])
287 when "bib", "bpb", "bbb"
288 tmp
= Tmp
.new(node
.codeOrigin
, :gpr)
289 comp
= node
.opcode
[1] == ?b
? "sltub" : "sltu"
290 newList
<< Instruction
.new(node
.codeOrigin
, comp
, [tmp
, node
.operands
[0], node
.operands
[1]], annotation
)
291 newList
<< Instruction
.new(node
.codeOrigin
, "bnz", [tmp
, MIPS_ZERO_REG
, node
.operands
[2]])
292 when "bibeq", "bpbeq", "bbbeq"
293 tmp
= Tmp
.new(node
.codeOrigin
, :gpr)
294 comp
= node
.opcode
[1] == ?b
? "sltub" : "sltu"
295 newList
<< Instruction
.new(node
.codeOrigin
, comp
, [tmp
, node
.operands
[1], node
.operands
[0]], annotation
)
296 newList
<< Instruction
.new(node
.codeOrigin
, "bz", [tmp
, MIPS_ZERO_REG
, node
.operands
[2]])
298 lowerMIPSCondBranch(newList
, "b" + $~
.post_match +
$1, node
)
310 # Specialization of lowering of malformed BaseIndex addresses.
314 def mipsLowerMalformedAddressesRecurse(list
)
317 subNode
.mipsLowerMalformedAddressesRecurse(list
)
321 def mipsLowerShiftedAddressesRecurse(list
, isFirst
, tmp
)
324 subNode
.mipsLowerShiftedAddressesRecurse(list
, isFirst
, tmp
)
330 def mipsLowerMalformedAddressesRecurse(list
)
331 tmp
= Tmp
.new(codeOrigin
, :gpr)
333 list
<< Instruction
.new(codeOrigin
, "addp", [base
, index
, tmp
])
334 Address
.new(codeOrigin
, tmp
, Immediate
.new(codeOrigin
, offset
.value
));
338 def mipsLowerShiftedAddressesRecurse(list
, isFirst
, tmp
)
340 list
<< Instruction
.new(codeOrigin
, "lshifti", [index
, Immediate
.new(codeOrigin
, scaleShift
), tmp
]);
341 list
<< Instruction
.new(codeOrigin
, "addp", [base
, tmp
])
343 Address
.new(codeOrigin
, tmp
, Immediate
.new(codeOrigin
, offset
.value
));
348 # Lowering of BaseIndex addresses with optimization for MIPS.
350 # offline asm instruction pair:
351 # loadi 4[cfr, t0, 8], t2
352 # loadi 0[cfr, t0, 8], t0
354 # lowered instructions:
361 def mipsHasShiftedBaseIndexAddress(instruction
)
362 instruction
.operands
.each_with_index
{
364 if operand
.is_a
? BaseIndex
and operand
.scaleShift !
= 0
371 def mipsScaleOfBaseIndexMatches(baseIndex0
, baseIndex1
)
372 baseIndex0
.base
== baseIndex1
.base
and
373 baseIndex0
.index
== baseIndex1
.index
and
374 baseIndex0
.scale
== baseIndex1
.scale
377 def mipsLowerBaseIndexAddresses(list
)
378 newList
= [ list
[0] ]
382 if nodes
[1].is_a
? Instruction
383 ind
= mipsHasShiftedBaseIndexAddress(nodes
[1])
385 if nodes
[0].is_a
? Instruction
and
386 nodes
[0].opcode
== nodes
[1].opcode
and
387 ind
== mipsHasShiftedBaseIndexAddress(nodes
[0]) and
388 mipsScaleOfBaseIndexMatches(nodes
[0].operands
[ind
], nodes
[1].operands
[ind
])
390 newList
<< nodes
[1].mipsLowerShiftedAddressesRecurse(newList
, false, tmp
)
392 tmp
= Tmp
.new(codeOrigin
, :gpr)
393 newList
<< nodes
[1].mipsLowerShiftedAddressesRecurse(newList
, true, tmp
)
396 newList
<< nodes
[1].mipsLowerMalformedAddressesRecurse(newList
)
406 # Lowering of misplaced immediates of MIPS specific instructions. For example:
416 def mipsLowerMisplacedImmediates(list
)
420 if node
.is_a
? Instruction
422 when "slt", "sltu", "sltb", "sltub"
423 if node
.operands
[1].is_a
? Immediate
424 tmp
= Tmp
.new(node
.codeOrigin
, :gpr)
425 newList
<< Instruction
.new(node
.codeOrigin
, "move", [node
.operands
[1], tmp
], node
.annotation
)
426 newList
<< Instruction
.new(node
.codeOrigin
, node
.opcode
,
427 [node
.operands
[0], tmp
, node
.operands
[2]],
433 newList
<< node
.riscLowerMalformedImmediatesRecurse(newList
, -0x7fff..0x7fff
)
445 # Specialization of lowering of misplaced addresses.
448 def mipsLowerMisplacedAddresses(list
)
452 if node
.is_a
? Instruction
453 postInstructions
= []
454 annotation
= node
.annotation
457 if node
.operands
[0].address
?
458 newList
<< Instruction
.new(node
.operands
[0].codeOrigin
, "loadi", [node
.operands
[0], MIPS_JUMP_REG
])
459 newList
<< Instruction
.new(node
.codeOrigin
, node
.opcode
, [MIPS_JUMP_REG
])
461 newList
<< Instruction
.new(node
.codeOrigin
,
463 [riscAsRegister(newList
, postInstructions
, node
.operands
[0], "p", false)])
468 if node
.operands
[0].address
?
469 newList
<< Instruction
.new(node
.operands
[0].codeOrigin
, "loadp", [node
.operands
[0], MIPS_CALL_REG
])
471 elsif node
.operands
[0].is_a
? LabelReference
472 tmp
= node
.operands
[0]
474 elsif node
.operands
[0].register
?
475 newList
<< Instruction
.new(node
.operands
[0].codeOrigin
, "move", [node
.operands
[0], MIPS_CALL_REG
])
478 tmp
= node
.operands
[0]
480 newList
<< Instruction
.new(node
.codeOrigin
, node
.opcode
, [tmp
])
482 newList
<< Instruction
.new(node
.codeOrigin
, "move", [MIPS_GPSAVE_REG
, MIPS_GP_REG
])
485 newList
<< Instruction
.new(node
.codeOrigin
,
487 riscAsRegisters(newList
, [], node
.operands
, "i"))
489 newList
<< Instruction
.new(node
.codeOrigin
,
491 riscAsRegisters(newList
, [], node
.operands
, "b"))
492 when /^(bz|bnz|bs|bo)/
493 tl
= $~
.post_match
== "" ? "i" : $~
.post_match
494 newList
<< Instruction
.new(node
.codeOrigin
,
496 riscAsRegisters(newList
, [], node
.operands
, tl
))
500 newList +
= postInstructions
509 # Lowering compares and tests.
512 def mipsLowerCompareTemplate(list
, node
, opCmp
, opMov
)
513 tmp0
= Tmp
.new(node
.codeOrigin
, :gpr)
514 tmp1
= Tmp
.new(node
.codeOrigin
, :gpr)
515 list
<< Instruction
.new(node
.codeOrigin
, "move", [Immediate
.new(nil, 0), node
.operands
[2]])
516 list
<< Instruction
.new(node
.codeOrigin
, opCmp
, [node
.operands
[1], node
.operands
[0], tmp0
])
517 list
<< Instruction
.new(node
.codeOrigin
, "move", [Immediate
.new(nil, 1), tmp1
])
518 list
<< Instruction
.new(node
.codeOrigin
, opMov
, [node
.operands
[2], tmp1
, tmp0
])
521 def mipsLowerCompares(list
)
525 if node
.is_a
? Instruction
527 when "cieq", "cpeq", "cbeq"
528 mipsLowerCompareTemplate(newList
, node
, "subp", "movz")
529 when "cineq", "cpneq", "cbneq"
530 mipsLowerCompareTemplate(newList
, node
, "subp", "movn")
531 when "tiz", "tbz", "tpz"
532 mipsLowerCompareTemplate(newList
, node
, "andp", "movz")
533 when "tinz", "tbnz", "tpnz"
534 mipsLowerCompareTemplate(newList
, node
, "andp", "movn")
535 when "tio", "tbo", "tpo"
536 tmp
= Tmp
.new(node
.codeOrigin
, :gpr)
537 list
<< Instruction
.new(node
.codeOrigin
, "andp", [node
.operands
[1], node
.operands
[0], tmp
])
538 list
<< Instruction
.new(node
.codeOrigin
, "slt", [node
.operands
[2], MIPS_ZERO_REG
, tmp
])
539 when "tis", "tbs", "tps"
540 tmp
= Tmp
.new(node
.codeOrigin
, :gpr)
541 list
<< Instruction
.new(node
.codeOrigin
, "andp", [node
.operands
[1], node
.operands
[0], tmp
])
542 list
<< Instruction
.new(node
.codeOrigin
, "slt", [node
.operands
[2], tmp
, MIPS_ZERO_REG
])
558 def mipsEmitLea(destination
)
559 if destination
== base
560 $asm.puts
"addiu #{destination.mipsOperand}, #{offset.value}"
562 $asm.puts
"addiu #{destination.mipsOperand}, #{base.mipsOperand}, #{offset.value}"
568 # Add PIC compatible header code to prologue/entry rutins.
571 def mipsAddPICCode(list
)
577 if /_prologue$/.match(node
.name
) || /^_llint_function_/.match(node
.name
)
578 # Functions called from trampoline/JIT codes.
579 myList
<< Instruction
.new(node
.codeOrigin
, "pichdr", [])
580 elsif /_llint_op_catch/.match(node
.name
)
581 # Exception cactcher entry point function.
582 myList
<< Instruction
.new(node
.codeOrigin
, "pichdrra", [])
590 # Actual lowering code follows.
594 def getModifiedListMIPS
597 # Verify that we will only see instructions and labels.
600 unless node
.is_a
? Instruction
or
602 node
.is_a
? LocalLabel
or
604 raise "Unexpected #{node.inspect} at #{node.codeOrigin}"
608 result
= mipsAddPICCode(result
)
609 result
= mipsLowerSimpleBranchOps(result
)
610 result
= riscLowerSimpleBranchOps(result
)
611 result
= riscLowerHardBranchOps(result
)
612 result
= riscLowerShiftOps(result
)
613 result
= mipsLowerBaseIndexAddresses(result
)
614 result
= riscLowerMalformedAddresses(result
) {
616 if address
.is_a
? Address
617 (-0xffff..0xffff
).include? address
.offset
.value
622 result
= riscLowerMalformedAddressesDouble(result
)
623 result
= riscLowerMisplacedImmediates(result
, ["storeb", "storei", "storep"])
624 result
= mipsLowerMisplacedImmediates(result
)
625 result
= riscLowerMalformedImmediates(result
, -0xffff..0xffff
)
626 result
= mipsLowerMisplacedAddresses(result
)
627 result
= riscLowerMisplacedAddresses(result
)
628 result
= riscLowerRegisterReuse(result
)
629 result
= mipsLowerCompares(result
)
630 result
= assignRegistersToTemporaries(result
, :gpr, MIPS_TEMP_GPRS
)
631 result
= assignRegistersToTemporaries(result
, :fpr, MIPS_TEMP_FPRS
)
637 def mipsOperands(operands
)
638 operands
.map
{|v
| v
.mipsOperand
}.join(", ")
641 def mipsFlippedOperands(operands
)
642 mipsOperands([operands
[-1]] + operands
[0..-2])
645 def getMIPSOpcode(opcode
, suffix
)
649 def emitMIPSCompact(opcode
, opcodei
, operands
)
652 if operands
[0].is_a
? Immediate
654 operands
[0] = Immediate
.new(operands
[0].codeOrigin
, -1 * operands
[0].value
)
655 elsif operands
[1].is_a
? Immediate
657 operands
[1] = Immediate
.new(operands
[1].codeOrigin
, -1 * operands
[1].value
)
660 elsif opcode
== "add"
663 if operands
.size
== 3
664 if operands
[0].is_a
? Immediate
665 $asm.puts
"#{opcode}i#{postfix} #{operands[2].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].value}"
666 elsif operands
[1].is_a
? Immediate
667 $asm.puts
"#{opcode}i#{postfix} #{operands[2].mipsOperand}, #{operands[0].mipsOperand}, #{operands[1].value}"
669 $asm.puts
"#{opcode}#{postfix} #{mipsFlippedOperands(operands)}"
672 raise unless operands
.size
== 2
673 raise unless operands
[1].register
?
674 if operands
[0].is_a
? Immediate
675 $asm.puts
"#{opcode}i#{postfix} #{operands[1].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}"
677 $asm.puts
"#{opcode}#{postfix} #{operands[1].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}"
682 def emitMIPSShiftCompact(opcode
, operands
)
683 if operands
.size
== 3
684 if (operands
[1].is_a
? Immediate
)
685 $asm.puts
"#{opcode} #{operands[2].mipsOperand}, #{operands[0].mipsOperand}, #{operands[1].value}"
687 $asm.puts
"#{opcode}v #{mipsFlippedOperands(operands)}"
690 raise unless operands
.size
== 2
691 if operands
[0].register
?
692 $asm.puts
"#{opcode}v #{operands[1].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}"
694 $asm.puts
"#{opcode} #{operands[1].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].value}"
699 def emitMIPS(opcode
, operands
)
700 if operands
.size
== 3
701 $asm.puts
"#{opcode} #{mipsFlippedOperands(operands)}"
703 raise unless operands
.size
== 2
704 $asm.puts
"#{opcode} #{operands[1].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}"
708 def emitMIPSDoubleBranch(branchOpcode
, neg
, operands
)
709 $asm.puts
"c.#{branchOpcode}.d #{mipsOperands(operands[0..1])}"
711 $asm.puts
"bc1t #{operands[2].asmLabel}"
713 $asm.puts
"bc1f #{operands[2].asmLabel}"
719 $asm.comment codeOriginString
721 when "addi", "addp", "addis"
722 if operands
.size
== 3 and operands
[0].is_a
? Immediate
723 raise unless operands
[1].register
?
724 raise unless operands
[2].register
?
725 if operands
[0].value
== 0 #and suffix.empty?
726 unless operands
[1] == operands
[2]
727 $asm.puts
"move #{operands[2].mipsOperand}, #{operands[1].mipsOperand}"
730 $asm.puts
"addiu #{operands[2].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}"
732 elsif operands
.size
== 3 and operands
[0].register
?
733 raise unless operands
[1].register
?
734 raise unless operands
[2].register
?
735 $asm.puts
"addu #{mipsFlippedOperands(operands)}"
737 if operands
[0].is_a
? Immediate
738 unless Immediate
.new(nil, 0) == operands
[0]
739 $asm.puts
"addiu #{operands[1].mipsOperand}, #{mipsFlippedOperands(operands)}"
742 $asm.puts
"addu #{operands[1].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}"
746 emitMIPSCompact("and", "and", operands
)
748 emitMIPSCompact("or", "orr", operands
)
750 emitMIPSCompact("or", "orrs", operands
)
752 emitMIPSCompact("xor", "eor", operands
)
753 when "lshifti", "lshiftp"
754 emitMIPSShiftCompact("sll", operands
)
755 when "rshifti", "rshiftp"
756 emitMIPSShiftCompact("sra", operands
)
757 when "urshifti", "urshiftp"
758 emitMIPSShiftCompact("srl", operands
)
760 emitMIPS("mul", operands
)
761 when "subi", "subp", "subis"
762 emitMIPSCompact("sub", "subs", operands
)
764 $asm.puts
"negu #{operands[0].mipsOperand}, #{operands[0].mipsOperand}"
766 $asm.puts
"nor #{operands[0].mipsOperand}, #{operands[0].mipsOperand}, $zero"
767 when "loadi", "loadis", "loadp"
768 $asm.puts
"lw #{mipsFlippedOperands(operands)}"
769 when "storei", "storep"
770 $asm.puts
"sw #{mipsOperands(operands)}"
772 $asm.puts
"lbu #{mipsFlippedOperands(operands)}"
774 $asm.puts
"lb #{mipsFlippedOperands(operands)}"
776 $asm.puts
"sb #{mipsOperands(operands)}"
778 $asm.puts
"lhu #{mipsFlippedOperands(operands)}"
780 $asm.puts
"lh #{mipsFlippedOperands(operands)}"
782 $asm.puts
"shv #{mipsOperands(operands)}"
784 $asm.puts
"ldc1 #{mipsFlippedOperands(operands)}"
786 $asm.puts
"sdc1 #{mipsOperands(operands)}"
788 emitMIPS("add.d", operands
)
790 emitMIPS("div.d", operands
)
792 emitMIPS("sub.d", operands
)
794 emitMIPS("mul.d", operands
)
796 $asm.puts
"sqrt.d #{mipsFlippedOperands(operands)}"
798 raise "invalid ops of #{self.inspect} at #{codeOriginString}" unless operands
[1].is_a
? FPRegisterID
and operands
[0].register
?
799 $asm.puts
"mtc1 #{operands[0].mipsOperand}, #{operands[1].mipsOperand}"
800 $asm.puts
"cvt.d.w #{operands[1].mipsOperand}, #{operands[1].mipsOperand}"
802 emitMIPSDoubleBranch("eq", false, operands
)
804 emitMIPSDoubleBranch("ueq", true, operands
)
806 emitMIPSDoubleBranch("ule", true, operands
)
808 emitMIPSDoubleBranch("ult", true, operands
)
810 emitMIPSDoubleBranch("olt", false, operands
)
812 emitMIPSDoubleBranch("ole", false, operands
)
814 emitMIPSDoubleBranch("ueq", false, operands
)
816 emitMIPSDoubleBranch("eq", true, operands
)
818 emitMIPSDoubleBranch("ole", true, operands
)
820 emitMIPSDoubleBranch("olt", true, operands
)
822 emitMIPSDoubleBranch("ult", false, operands
)
824 emitMIPSDoubleBranch("ule", false, operands
)
826 # FIXME: may be a good idea to just get rid of this instruction, since the interpreter
827 # currently does not use it.
828 raise "MIPS does not support this opcode yet, #{codeOrigin}"
830 $asm.puts
"cvt.w.d #{MIPS_SCRATCH_FPR.mipsSingleLo}, #{operands[0].mipsOperand}"
831 $asm.puts
"mfc1 #{operands[1].mipsOperand}, #{MIPS_SCRATCH_FPR.mipsSingleLo}"
833 $asm.puts
"cvt.w.d #{MIPS_SCRATCH_FPR.mipsSingleLo}, #{operands[0].mipsOperand}"
834 $asm.puts
"mfc1 #{operands[1].mipsOperand}, #{MIPS_SCRATCH_FPR.mipsSingleLo}"
835 $asm.puts
"cvt.d.w #{MIPS_SCRATCH_FPR.mipsOperand}, #{MIPS_SCRATCH_FPR.mipsSingleLo}"
836 emitMIPSDoubleBranch("eq", true, [MIPS_SCRATCH_FPR
, operands
[0], operands
[2]])
837 $asm.puts
"beq #{operands[1].mipsOperand}, $zero, #{operands[2].asmLabel}"
839 # FIXME: either support this or remove it.
840 raise "MIPS does not support this opcode yet, #{codeOrigin}"
844 $asm.puts
"lw #{op.mipsOperand}, 0($sp)"
845 $asm.puts
"addiu $sp, $sp, 4"
850 $asm.puts
"addiu $sp, $sp, -4"
851 $asm.puts
"sw #{op.mipsOperand}, 0($sp)"
853 when "popCalleeSaves"
854 $asm.puts
"lw $16, 0($sp)"
855 $asm.puts
"lw $17, 4($sp)"
856 $asm.puts
"lw $18, 8($sp)"
857 $asm.puts
"lw $19, 12($sp)"
858 $asm.puts
"lw $20, 16($sp)"
859 $asm.puts
"addiu $sp, $sp, 20"
860 when "pushCalleeSaves"
861 $asm.puts
"addiu $sp, $sp, -20"
862 $asm.puts
"sw $20, 16($sp)"
863 $asm.puts
"sw $19, 12($sp)"
864 $asm.puts
"sw $18, 8($sp)"
865 $asm.puts
"sw $17, 4($sp)"
866 $asm.puts
"sw $16, 0($sp)"
867 when "move", "sxi2p", "zxi2p"
868 if operands
[0].is_a
? Immediate
869 mipsMoveImmediate(operands
[0].value
, operands
[1])
871 $asm.puts
"move #{mipsFlippedOperands(operands)}"
875 when "bieq", "bpeq", "bbeq"
876 $asm.puts
"beq #{mipsOperands(operands[0..1])}, #{operands[2].asmLabel}"
877 when "bineq", "bpneq", "bbneq"
878 $asm.puts
"bne #{mipsOperands(operands[0..1])}, #{operands[2].asmLabel}"
879 when "bigt", "bpgt", "bbgt"
880 $asm.puts
"bgt #{mipsOperands(operands[0..1])}, #{operands[2].asmLabel}"
881 when "bigteq", "bpgteq", "bbgteq"
882 $asm.puts
"bge #{mipsOperands(operands[0..1])}, #{operands[2].asmLabel}"
883 when "bilt", "bplt", "bblt"
884 $asm.puts
"blt #{mipsOperands(operands[0..1])}, #{operands[2].asmLabel}"
885 when "bilteq", "bplteq", "bblteq"
886 $asm.puts
"ble #{mipsOperands(operands[0..1])}, #{operands[2].asmLabel}"
888 if operands
[0].label
?
889 $asm.puts
"j #{operands[0].asmLabel}"
891 $asm.puts
"jr #{operands[0].mipsOperand}"
894 if operands
[0].label
?
895 $asm.puts
"jal #{operands[0].asmLabel}"
897 $asm.puts
"jalr #{operands[0].mipsOperand}"
903 when "cia", "cpa", "cba"
904 $asm.puts
"sltu #{operands[2].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}"
905 when "ciaeq", "cpaeq", "cbaeq"
906 $asm.puts
"sltu #{operands[2].mipsOperand}, #{operands[0].mipsOperand}, #{operands[1].mipsOperand}"
907 $asm.puts
"xori #{operands[2].mipsOperand}, 1"
908 when "cib", "cpb", "cbb"
909 $asm.puts
"sltu #{operands[2].mipsOperand}, #{operands[0].mipsOperand}, #{operands[1].mipsOperand}"
910 when "cibeq", "cpbeq", "cbbeq"
911 $asm.puts
"sltu #{operands[2].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}"
912 $asm.puts
"xori #{operands[2].mipsOperand}, 1"
913 when "cigt", "cpgt", "cbgt"
914 $asm.puts
"slt #{operands[2].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}"
915 when "cigteq", "cpgteq", "cbgteq"
916 $asm.puts
"slt #{operands[2].mipsOperand}, #{operands[0].mipsOperand}, #{operands[1].mipsOperand}"
917 $asm.puts
"xori #{operands[2].mipsOperand}, 1"
918 when "cilt", "cplt", "cblt"
919 $asm.puts
"slt #{operands[2].mipsOperand}, #{operands[0].mipsOperand}, #{operands[1].mipsOperand}"
920 when "cilteq", "cplteq", "cblteq"
921 $asm.puts
"slt #{operands[2].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}"
922 $asm.puts
"xori #{operands[2].mipsOperand}, 1"
924 $asm.puts
"lw #{operands[1].mipsOperand}, #{operands[0].value * 4}($sp)"
926 $asm.puts
"sw #{operands[1].mipsOperand}, #{operands[0].value * 4}($sp)"
928 $asm.puts
"mtc1 #{operands[0].mipsOperand}, #{operands[2].mipsSingleLo}"
929 $asm.puts
"mtc1 #{operands[1].mipsOperand}, #{operands[2].mipsSingleHi}"
931 $asm.puts
"mfc1 #{operands[1].mipsOperand}, #{operands[0].mipsSingleLo}"
932 $asm.puts
"mfc1 #{operands[2].mipsOperand}, #{operands[0].mipsSingleHi}"
934 $asm.puts
"bgt #{operands[0].mipsOperand}, #{operands[1].mipsOperand}, #{operands[2].asmLabel}"
936 $asm.puts
"blt #{operands[0].mipsOperand}, #{operands[1].mipsOperand}, #{operands[2].asmLabel}"
938 $asm.puts
"beq #{operands[0].mipsOperand}, #{operands[1].mipsOperand}, #{operands[2].asmLabel}"
940 $asm.puts
"bne #{operands[0].mipsOperand}, #{operands[1].mipsOperand}, #{operands[2].asmLabel}"
942 operands
[0].mipsEmitLea(operands
[1])
944 raise "Wrong number of arguments to smull in #{self.inspect} at #{codeOriginString}" unless operands
.length
== 4
945 $asm.puts
"mult #{operands[0].mipsOperand}, #{operands[1].mipsOperand}"
946 $asm.puts
"mflo #{operands[2].mipsOperand}"
947 $asm.puts
"mfhi #{operands[3].mipsOperand}"
949 $asm.puts
"movz #{operands[0].mipsOperand}, #{operands[1].mipsOperand}, #{operands[2].mipsOperand}"
951 $asm.puts
"movn #{operands[0].mipsOperand}, #{operands[1].mipsOperand}, #{operands[2].mipsOperand}"
953 $asm.puts
"slt #{operands[0].mipsOperand}, #{operands[1].mipsOperand}, #{operands[2].mipsOperand}"
955 $asm.puts
"sltu #{operands[0].mipsOperand}, #{operands[1].mipsOperand}, #{operands[2].mipsOperand}"
957 $asm.putStr("OFFLINE_ASM_CPLOAD($25)")
958 $asm.puts
"move $s4, $gp"
960 $asm.putStr("OFFLINE_ASM_CPLOAD($31)")
961 $asm.puts
"move $s4, $gp"