]> git.saurik.com Git - apple/javascriptcore.git/blame - offlineasm/mips.rb
JavaScriptCore-7601.1.46.3.tar.gz
[apple/javascriptcore.git] / offlineasm / mips.rb
CommitLineData
93a37866
A
1# Copyright (C) 2012 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
27class Assembler
28 def putStr(str)
29 @outp.puts str
30 end
31end
32
33class Node
34 def mipsSingleHi
35 doubleOperand = mipsOperand
36 raise "Bogus register name #{doubleOperand}" unless doubleOperand =~ /^\$f/
37 "$f" + ($~.post_match.to_i + 1).to_s
38 end
39 def mipsSingleLo
40 doubleOperand = mipsOperand
41 raise "Bogus register name #{doubleOperand}" unless doubleOperand =~ /^\$f/
42 doubleOperand
43 end
44end
45
46class SpecialRegister < NoChildren
47 def mipsOperand
48 @name
49 end
50
51 def dump
52 @name
53 end
54
55 def register?
56 true
57 end
58end
59
60MIPS_TEMP_GPRS = [SpecialRegister.new("$t5"), SpecialRegister.new("$t6"), SpecialRegister.new("$t7"),
61 SpecialRegister.new("$t8")]
62MIPS_ZERO_REG = SpecialRegister.new("$zero")
63MIPS_GP_REG = SpecialRegister.new("$gp")
64MIPS_GPSAVE_REG = SpecialRegister.new("$s4")
93a37866
A
65MIPS_CALL_REG = SpecialRegister.new("$t9")
66MIPS_TEMP_FPRS = [SpecialRegister.new("$f16")]
67MIPS_SCRATCH_FPR = SpecialRegister.new("$f18")
68
69def mipsMoveImmediate(value, register)
70 if value == 0
71 $asm.puts "add #{register.mipsOperand}, $zero, $zero"
72 else
73 $asm.puts "li #{register.mipsOperand}, #{value}"
74 end
75end
76
77class RegisterID
78 def mipsOperand
79 case name
80 when "a0"
81 "$a0"
82 when "a1"
83 "$a1"
81345200
A
84 when "a2"
85 "$a2"
86 when "a3"
87 "$a3"
93a37866
A
88 when "r0", "t0"
89 "$v0"
90 when "r1", "t1"
91 "$v1"
92 when "t2"
93 "$t2"
94 when "t3"
95 "$s3"
96 when "t4" # PC reg in llint
97 "$s2"
98 when "t5"
99 "$t5"
100 when "t6"
101 "$t6"
102 when "t7"
103 "$t7"
104 when "t8"
105 "$t8"
106 when "cfr"
81345200 107 "$fp"
93a37866
A
108 when "lr"
109 "$ra"
110 when "sp"
111 "$sp"
112 else
113 raise "Bad register #{name} for MIPS at #{codeOriginString}"
114 end
115 end
116end
117
118class FPRegisterID
119 def mipsOperand
120 case name
121 when "ft0", "fr"
122 "$f0"
123 when "ft1"
124 "$f2"
125 when "ft2"
126 "$f4"
127 when "ft3"
128 "$f6"
129 when "ft4"
130 "$f8"
131 when "ft5"
132 "$f10"
133 when "fa0"
134 "$f12"
135 when "fa1"
136 "$f14"
137 else
138 raise "Bad register #{name} for MIPS at #{codeOriginString}"
139 end
140 end
141end
142
143class Immediate
144 def mipsOperand
81345200 145 raise "Invalid immediate #{value} at #{codeOriginString}" if value < -0x7fff or value > 0xffff
93a37866
A
146 "#{value}"
147 end
148end
149
150class Address
151 def mipsOperand
152 raise "Bad offset at #{codeOriginString}" if offset.value < -0x7fff or offset.value > 0x7fff
153 "#{offset.value}(#{base.mipsOperand})"
154 end
155end
156
157class AbsoluteAddress
158 def mipsOperand
159 raise "Unconverted absolute address at #{codeOriginString}"
160 end
161end
162
ed1e77d3
A
163#
164# Negate condition of branches to labels.
165#
166
167class Instruction
168 def mipsNegateCondition(list)
169 /^(b(add|sub|or|mul|t)?)([ipb])/.match(opcode)
170 case $~.post_match
171 when "eq"
172 op = "neq"
173 when "neq"
174 op = "eq"
175 when "z"
176 op = "nz"
177 when "nz"
178 op = "z"
179 when "gt"
180 op = "lteq"
181 when "gteq"
182 op = "lt"
183 when "lt"
184 op = "gteq"
185 when "lteq"
186 op = "gt"
187 when "a"
188 op = "beq"
189 when "b"
190 op = "aeq"
191 when "aeq"
192 op = "b"
193 when "beq"
194 op = "a"
195 else
196 raise "Can't negate #{opcode} branch."
197 end
198 noBranch = LocalLabel.unique("nobranch")
199 noBranchRef = LocalLabelReference.new(codeOrigin, noBranch)
200 toRef = operands[-1]
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])
204 list << noBranch
205 end
206end
207
208def mipsLowerFarBranchOps(list)
209 newList = []
210 list.each {
211 | node |
212 if node.is_a? Instruction
213 annotation = node.annotation
214 case node.opcode
215 when /^b(add|sub|or|mul|t)?([ipb])/
216 if node.operands[-1].is_a? LabelReference
217 node.mipsNegateCondition(newList)
218 next
219 end
220 end
221 end
222 newList << node
223 }
224 newList
225end
226
93a37866
A
227#
228# Lower 'and' masked branches
229#
230
231def lowerMIPSCondBranch(list, condOp, node)
232 if node.operands.size == 2
233 list << Instruction.new(node.codeOrigin,
234 condOp,
235 [node.operands[0], MIPS_ZERO_REG, node.operands[-1]],
236 node.annotation)
237 elsif node.operands.size == 3
238 tmp = Tmp.new(node.codeOrigin, :gpr)
239 list << Instruction.new(node.codeOrigin,
240 "andi",
241 [node.operands[0], node.operands[1], tmp],
242 node.annotation)
243 list << Instruction.new(node.codeOrigin,
244 condOp,
245 [tmp, MIPS_ZERO_REG, node.operands[-1]])
246 else
247 raise "Expected 2 or 3 operands but got #{node.operands.size} at #{node.codeOriginString}"
248 end
249end
250
251#
252# Lowering of branch ops. For example:
253#
254# baddiz foo, bar, baz
255#
256# will become:
257#
258# addi foo, bar
259# bz baz
260#
261
262def mipsLowerSimpleBranchOps(list)
263 newList = []
264 list.each {
265 | node |
266 if node.is_a? Instruction
267 annotation = node.annotation
268 case node.opcode
269 when /^b(addi|subi|ori|addp)/
270 op = $1
271 bc = $~.post_match
272 branch = "b" + bc
273
274 case op
275 when "addi", "addp"
276 op = "addi"
277 when "subi"
278 op = "subi"
279 when "ori"
280 op = "ori"
281 end
282
283 if bc == "o"
284 case op
285 when "addi"
286 # addu $s0, $s1, $s2
287 # xor $t0, $s1, $s2
288 # blt $t0, $zero, no overflow
289 # xor $t0, $s0, $s1
290 # blt $t0, $zero, overflow
291 # no overflow:
292 #
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]])
302 newList << noFlow
303 newList << Instruction.new(node.codeOrigin, "move", [tr, node.operands[1]])
304 when "subi"
305 # subu $s0, $s1, $s2
306 # xor $t0, $s1, $s2
307 # bge $t0, $zero, no overflow
308 # xor $t0, $s0, $s1
309 # blt $t0, $zero, overflow
310 # no overflow:
311 #
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]])
321 newList << noFlow
322 newList << Instruction.new(node.codeOrigin, "move", [tr, node.operands[1]])
323 when "ori"
324 # no ovwerflow at ori
325 newList << Instruction.new(node.codeOrigin, op, node.operands[0..1], annotation)
326 end
327 else
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])
334 else
335 tr = node.operands[1]
336 newList << Instruction.new(node.codeOrigin, op, node.operands[0..-2], annotation)
337 end
338 newList << Instruction.new(node.codeOrigin, branch, [tr, MIPS_ZERO_REG, node.operands[-1]])
339 end
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]])
360 when /^bt(i|p|b)/
361 lowerMIPSCondBranch(newList, "b" + $~.post_match + $1, node)
362 else
363 newList << node
364 end
365 else
366 newList << node
367 end
368 }
369 newList
370end
371
372#
373# Specialization of lowering of malformed BaseIndex addresses.
374#
375
376class Node
81345200 377 def mipsLowerMalformedAddressesRecurse(list)
93a37866
A
378 mapChildren {
379 | subNode |
81345200 380 subNode.mipsLowerMalformedAddressesRecurse(list)
93a37866
A
381 }
382 end
93a37866 383
81345200
A
384 def mipsLowerShiftedAddressesRecurse(list, isFirst, tmp)
385 mapChildren {
386 | subNode |
387 subNode.mipsLowerShiftedAddressesRecurse(list, isFirst, tmp)
388 }
93a37866
A
389 end
390end
391
392class BaseIndex
81345200
A
393 def mipsLowerMalformedAddressesRecurse(list)
394 tmp = Tmp.new(codeOrigin, :gpr)
93a37866 395 if scaleShift == 0
81345200
A
396 list << Instruction.new(codeOrigin, "addp", [base, index, tmp])
397 Address.new(codeOrigin, tmp, Immediate.new(codeOrigin, offset.value));
93a37866
A
398 end
399 end
93a37866 400
81345200
A
401 def mipsLowerShiftedAddressesRecurse(list, isFirst, tmp)
402 if isFirst
403 list << Instruction.new(codeOrigin, "lshifti", [index, Immediate.new(codeOrigin, scaleShift), tmp]);
404 list << Instruction.new(codeOrigin, "addp", [base, tmp])
405 end
406 Address.new(codeOrigin, tmp, Immediate.new(codeOrigin, offset.value));
93a37866
A
407 end
408end
409
81345200
A
410#
411# Lowering of BaseIndex addresses with optimization for MIPS.
412#
413# offline asm instruction pair:
414# loadi 4[cfr, t0, 8], t2
415# loadi 0[cfr, t0, 8], t0
416#
417# lowered instructions:
418# lshifti t0, 3, tmp
419# addp cfr, tmp
420# loadi 4[tmp], t2
421# loadi 0[tmp], t0
422#
423
424def mipsHasShiftedBaseIndexAddress(instruction)
425 instruction.operands.each_with_index {
426 | operand, index |
427 if operand.is_a? BaseIndex and operand.scaleShift != 0
428 return index
429 end
430 }
431 -1
432end
433
434def mipsScaleOfBaseIndexMatches(baseIndex0, baseIndex1)
435 baseIndex0.base == baseIndex1.base and
436 baseIndex0.index == baseIndex1.index and
437 baseIndex0.scale == baseIndex1.scale
438end
439
440def mipsLowerBaseIndexAddresses(list)
441 newList = [ list[0] ]
442 tmp = nil
443 list.each_cons(2) {
444 | nodes |
445 if nodes[1].is_a? Instruction
446 ind = mipsHasShiftedBaseIndexAddress(nodes[1])
447 if ind != -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])
452
453 newList << nodes[1].mipsLowerShiftedAddressesRecurse(newList, false, tmp)
454 else
455 tmp = Tmp.new(codeOrigin, :gpr)
456 newList << nodes[1].mipsLowerShiftedAddressesRecurse(newList, true, tmp)
457 end
458 else
459 newList << nodes[1].mipsLowerMalformedAddressesRecurse(newList)
460 end
461 else
462 newList << nodes[1]
463 end
93a37866
A
464 }
465 newList
466end
467
468#
469# Lowering of misplaced immediates of MIPS specific instructions. For example:
470#
471# sltu reg, 4, 2
472#
473# will become:
474#
475# move 4, tmp
476# sltu reg, tmp, 2
477#
478
479def mipsLowerMisplacedImmediates(list)
480 newList = []
481 list.each {
482 | node |
483 if node.is_a? Instruction
484 case node.opcode
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]],
491 node.annotation)
492 else
493 newList << node
494 end
81345200
A
495 when /^(addi|subi)/
496 newList << node.riscLowerMalformedImmediatesRecurse(newList, -0x7fff..0x7fff)
93a37866
A
497 else
498 newList << node
499 end
500 else
501 newList << node
502 end
503 }
504 newList
505end
506
507#
508# Specialization of lowering of misplaced addresses.
509#
510
ed1e77d3
A
511class LocalLabelReference
512 def register?
513 false
514 end
515end
516
517def mipsAsRegister(preList, postList, operand, needRestore)
518 tmp = MIPS_CALL_REG
519 if operand.address?
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])
525 else
526 needRestore = false
527 tmp = operand
528 end
529 if needRestore
530 postList << Instruction.new(operand.codeOrigin, "move", [MIPS_GPSAVE_REG, MIPS_GP_REG])
531 end
532 tmp
533end
534
93a37866
A
535def mipsLowerMisplacedAddresses(list)
536 newList = []
537 list.each {
538 | node |
539 if node.is_a? Instruction
540 postInstructions = []
541 annotation = node.annotation
542 case node.opcode
543 when "jmp"
ed1e77d3
A
544 newList << Instruction.new(node.codeOrigin,
545 node.opcode,
546 [mipsAsRegister(newList, [], node.operands[0], false)])
93a37866 547 when "call"
ed1e77d3
A
548 newList << Instruction.new(node.codeOrigin,
549 node.opcode,
550 [mipsAsRegister(newList, postInstructions, node.operands[0], true)])
93a37866
A
551 when "slt", "sltu"
552 newList << Instruction.new(node.codeOrigin,
553 node.opcode,
554 riscAsRegisters(newList, [], node.operands, "i"))
555 when "sltub", "sltb"
556 newList << Instruction.new(node.codeOrigin,
557 node.opcode,
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,
562 node.opcode,
563 riscAsRegisters(newList, [], node.operands, tl))
564 else
565 newList << node
566 end
567 newList += postInstructions
568 else
569 newList << node
570 end
571 }
572 newList
573end
574
575#
576# Lowering compares and tests.
577#
578
579def 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])
586end
587
588def mipsLowerCompares(list)
589 newList = []
590 list.each {
591 | node |
592 if node.is_a? Instruction
593 case node.opcode
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])
610 else
611 newList << node
612 end
613 else
614 newList << node
615 end
616 }
617 newList
618end
619
620#
621# Lea support.
622#
623
624class Address
625 def mipsEmitLea(destination)
626 if destination == base
627 $asm.puts "addiu #{destination.mipsOperand}, #{offset.value}"
628 else
629 $asm.puts "addiu #{destination.mipsOperand}, #{base.mipsOperand}, #{offset.value}"
630 end
631 end
632end
633
634#
ed1e77d3 635# Add PIC compatible header code to all the LLInt rutins.
93a37866
A
636#
637
638def mipsAddPICCode(list)
639 myList = []
640 list.each {
641 | node |
642 myList << node
643 if node.is_a? Label
ed1e77d3 644 myList << Instruction.new(node.codeOrigin, "pichdr", [])
93a37866
A
645 end
646 }
647 myList
648end
649
650#
651# Actual lowering code follows.
652#
653
654class Sequence
655 def getModifiedListMIPS
656 result = @list
657
658 # Verify that we will only see instructions and labels.
659 result.each {
660 | node |
661 unless node.is_a? Instruction or
662 node.is_a? Label or
663 node.is_a? LocalLabel or
664 node.is_a? Skip
665 raise "Unexpected #{node.inspect} at #{node.codeOrigin}"
666 end
667 }
668
669 result = mipsAddPICCode(result)
ed1e77d3 670 result = mipsLowerFarBranchOps(result)
93a37866
A
671 result = mipsLowerSimpleBranchOps(result)
672 result = riscLowerSimpleBranchOps(result)
673 result = riscLowerHardBranchOps(result)
674 result = riscLowerShiftOps(result)
81345200
A
675 result = mipsLowerBaseIndexAddresses(result)
676 result = riscLowerMalformedAddresses(result) {
93a37866
A
677 | node, address |
678 if address.is_a? Address
679 (-0xffff..0xffff).include? address.offset.value
680 else
681 false
682 end
683 }
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)
694
695 return result
696 end
697end
698
699def mipsOperands(operands)
700 operands.map{|v| v.mipsOperand}.join(", ")
701end
702
703def mipsFlippedOperands(operands)
704 mipsOperands([operands[-1]] + operands[0..-2])
705end
706
707def getMIPSOpcode(opcode, suffix)
708
709end
710
711def emitMIPSCompact(opcode, opcodei, operands)
712 postfix = ""
713 if opcode == "sub"
714 if operands[0].is_a? Immediate
715 opcode = "add"
716 operands[0] = Immediate.new(operands[0].codeOrigin, -1 * operands[0].value)
717 elsif operands[1].is_a? Immediate
718 opcode = "add"
719 operands[1] = Immediate.new(operands[1].codeOrigin, -1 * operands[1].value)
720 end
721 postfix = "u"
722 elsif opcode == "add"
723 postfix = "u"
724 end
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}"
730 else
731 $asm.puts "#{opcode}#{postfix} #{mipsFlippedOperands(operands)}"
732 end
733 else
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}"
738 else
739 $asm.puts "#{opcode}#{postfix} #{operands[1].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}"
740 end
741 end
742end
743
744def 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}"
748 else
749 $asm.puts "#{opcode}v #{mipsFlippedOperands(operands)}"
750 end
751 else
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}"
755 else
756 $asm.puts "#{opcode} #{operands[1].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].value}"
757 end
758 end
759end
760
761def emitMIPS(opcode, operands)
762 if operands.size == 3
763 $asm.puts "#{opcode} #{mipsFlippedOperands(operands)}"
764 else
765 raise unless operands.size == 2
766 $asm.puts "#{opcode} #{operands[1].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}"
767 end
768end
769
770def emitMIPSDoubleBranch(branchOpcode, neg, operands)
771 $asm.puts "c.#{branchOpcode}.d #{mipsOperands(operands[0..1])}"
772 if (!neg)
773 $asm.puts "bc1t #{operands[2].asmLabel}"
774 else
775 $asm.puts "bc1f #{operands[2].asmLabel}"
776 end
777end
778
ed1e77d3
A
779def emitMIPSJumpOrCall(opcode, operand)
780 if operand.label?
781 raise "Direct call/jump to a not local label." unless operand.is_a? LocalLabelReference
782 $asm.puts "#{opcode} #{operand.asmLabel}"
783 else
784 raise "Invalid call/jump register." unless operand == MIPS_CALL_REG
785 $asm.puts "#{opcode}r #{MIPS_CALL_REG.mipsOperand}"
786 end
787end
788
93a37866
A
789class Instruction
790 def lowerMIPS
791 $asm.comment codeOriginString
792 case opcode
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}"
800 end
801 else
802 $asm.puts "addiu #{operands[2].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}"
803 end
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)}"
808 else
809 if operands[0].is_a? Immediate
810 unless Immediate.new(nil, 0) == operands[0]
811 $asm.puts "addiu #{operands[1].mipsOperand}, #{mipsFlippedOperands(operands)}"
812 end
813 else
814 $asm.puts "addu #{operands[1].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}"
815 end
816 end
817 when "andi", "andp"
818 emitMIPSCompact("and", "and", operands)
819 when "ori", "orp"
820 emitMIPSCompact("or", "orr", operands)
821 when "oris"
822 emitMIPSCompact("or", "orrs", operands)
823 when "xori", "xorp"
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)
831 when "muli", "mulp"
832 emitMIPS("mul", operands)
833 when "subi", "subp", "subis"
834 emitMIPSCompact("sub", "subs", operands)
835 when "negi", "negp"
836 $asm.puts "negu #{operands[0].mipsOperand}, #{operands[0].mipsOperand}"
837 when "noti"
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)}"
843 when "loadb"
844 $asm.puts "lbu #{mipsFlippedOperands(operands)}"
845 when "loadbs"
846 $asm.puts "lb #{mipsFlippedOperands(operands)}"
847 when "storeb"
848 $asm.puts "sb #{mipsOperands(operands)}"
849 when "loadh"
850 $asm.puts "lhu #{mipsFlippedOperands(operands)}"
851 when "loadhs"
852 $asm.puts "lh #{mipsFlippedOperands(operands)}"
853 when "storeh"
854 $asm.puts "shv #{mipsOperands(operands)}"
855 when "loadd"
856 $asm.puts "ldc1 #{mipsFlippedOperands(operands)}"
857 when "stored"
858 $asm.puts "sdc1 #{mipsOperands(operands)}"
ed1e77d3
A
859 when "la"
860 $asm.puts "la #{operands[1].mipsOperand}, #{operands[0].asmLabel}"
93a37866
A
861 when "addd"
862 emitMIPS("add.d", operands)
863 when "divd"
864 emitMIPS("div.d", operands)
865 when "subd"
866 emitMIPS("sub.d", operands)
867 when "muld"
868 emitMIPS("mul.d", operands)
869 when "sqrtd"
870 $asm.puts "sqrt.d #{mipsFlippedOperands(operands)}"
871 when "ci2d"
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}"
875 when "bdeq"
876 emitMIPSDoubleBranch("eq", false, operands)
877 when "bdneq"
878 emitMIPSDoubleBranch("ueq", true, operands)
879 when "bdgt"
880 emitMIPSDoubleBranch("ule", true, operands)
881 when "bdgteq"
882 emitMIPSDoubleBranch("ult", true, operands)
883 when "bdlt"
884 emitMIPSDoubleBranch("olt", false, operands)
885 when "bdlteq"
886 emitMIPSDoubleBranch("ole", false, operands)
887 when "bdequn"
888 emitMIPSDoubleBranch("ueq", false, operands)
889 when "bdnequn"
890 emitMIPSDoubleBranch("eq", true, operands)
891 when "bdgtun"
892 emitMIPSDoubleBranch("ole", true, operands)
893 when "bdgtequn"
894 emitMIPSDoubleBranch("olt", true, operands)
895 when "bdltun"
896 emitMIPSDoubleBranch("ult", false, operands)
897 when "bdltequn"
898 emitMIPSDoubleBranch("ule", false, operands)
899 when "btd2i"
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}"
903 when "td2i"
904 $asm.puts "cvt.w.d #{MIPS_SCRATCH_FPR.mipsSingleLo}, #{operands[0].mipsOperand}"
905 $asm.puts "mfc1 #{operands[1].mipsOperand}, #{MIPS_SCRATCH_FPR.mipsSingleLo}"
906 when "bcd2i"
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}"
912 when "movdz"
913 # FIXME: either support this or remove it.
914 raise "MIPS does not support this opcode yet, #{codeOrigin}"
915 when "pop"
81345200
A
916 operands.each {
917 | op |
918 $asm.puts "lw #{op.mipsOperand}, 0($sp)"
919 $asm.puts "addiu $sp, $sp, 4"
920 }
93a37866 921 when "push"
81345200
A
922 operands.each {
923 | op |
924 $asm.puts "addiu $sp, $sp, -4"
925 $asm.puts "sw #{op.mipsOperand}, 0($sp)"
926 }
93a37866
A
927 when "move", "sxi2p", "zxi2p"
928 if operands[0].is_a? Immediate
929 mipsMoveImmediate(operands[0].value, operands[1])
930 else
931 $asm.puts "move #{mipsFlippedOperands(operands)}"
932 end
933 when "nop"
934 $asm.puts "nop"
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}"
947 when "jmp"
ed1e77d3 948 emitMIPSJumpOrCall("j", operands[0])
93a37866 949 when "call"
ed1e77d3 950 emitMIPSJumpOrCall("jal", operands[0])
93a37866
A
951 when "break"
952 $asm.puts "break"
953 when "ret"
954 $asm.puts "jr $ra"
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"
975 when "peek"
976 $asm.puts "lw #{operands[1].mipsOperand}, #{operands[0].value * 4}($sp)"
977 when "poke"
978 $asm.puts "sw #{operands[1].mipsOperand}, #{operands[0].value * 4}($sp)"
979 when "fii2d"
980 $asm.puts "mtc1 #{operands[0].mipsOperand}, #{operands[2].mipsSingleLo}"
981 $asm.puts "mtc1 #{operands[1].mipsOperand}, #{operands[2].mipsSingleHi}"
982 when "fd2ii"
983 $asm.puts "mfc1 #{operands[1].mipsOperand}, #{operands[0].mipsSingleLo}"
984 $asm.puts "mfc1 #{operands[2].mipsOperand}, #{operands[0].mipsSingleHi}"
985 when /^bo/
986 $asm.puts "bgt #{operands[0].mipsOperand}, #{operands[1].mipsOperand}, #{operands[2].asmLabel}"
987 when /^bs/
988 $asm.puts "blt #{operands[0].mipsOperand}, #{operands[1].mipsOperand}, #{operands[2].asmLabel}"
989 when /^bz/
990 $asm.puts "beq #{operands[0].mipsOperand}, #{operands[1].mipsOperand}, #{operands[2].asmLabel}"
991 when /^bnz/
992 $asm.puts "bne #{operands[0].mipsOperand}, #{operands[1].mipsOperand}, #{operands[2].asmLabel}"
993 when "leai", "leap"
994 operands[0].mipsEmitLea(operands[1])
995 when "smulli"
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}"
1000 when "movz"
1001 $asm.puts "movz #{operands[0].mipsOperand}, #{operands[1].mipsOperand}, #{operands[2].mipsOperand}"
1002 when "movn"
1003 $asm.puts "movn #{operands[0].mipsOperand}, #{operands[1].mipsOperand}, #{operands[2].mipsOperand}"
1004 when "slt", "sltb"
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}"
1008 when "pichdr"
ed1e77d3
A
1009 $asm.putStr("OFFLINE_ASM_CPLOAD(#{MIPS_CALL_REG.mipsOperand})")
1010 $asm.puts "move #{MIPS_GPSAVE_REG.mipsOperand}, #{MIPS_GP_REG.mipsOperand}"
81345200
A
1011 when "memfence"
1012 $asm.puts "sync"
93a37866 1013 else
81345200 1014 lowerDefault
93a37866
A
1015 end
1016 end
1017end