]>
Commit | Line | Data |
---|---|---|
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 | ||
25 | require 'risc' | |
26 | ||
27 | class Assembler | |
28 | def putStr(str) | |
29 | @outp.puts str | |
30 | end | |
31 | end | |
32 | ||
33 | class 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 | |
44 | end | |
45 | ||
46 | class 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 | |
58 | end | |
59 | ||
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") | |
93a37866 A |
65 | MIPS_CALL_REG = SpecialRegister.new("$t9") |
66 | MIPS_TEMP_FPRS = [SpecialRegister.new("$f16")] | |
67 | MIPS_SCRATCH_FPR = SpecialRegister.new("$f18") | |
68 | ||
69 | def 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 | |
75 | end | |
76 | ||
77 | class 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 | |
116 | end | |
117 | ||
118 | class 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 | |
141 | end | |
142 | ||
143 | class Immediate | |
144 | def mipsOperand | |
81345200 | 145 | raise "Invalid immediate #{value} at #{codeOriginString}" if value < -0x7fff or value > 0xffff |
93a37866 A |
146 | "#{value}" |
147 | end | |
148 | end | |
149 | ||
150 | class 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 | |
155 | end | |
156 | ||
157 | class AbsoluteAddress | |
158 | def mipsOperand | |
159 | raise "Unconverted absolute address at #{codeOriginString}" | |
160 | end | |
161 | end | |
162 | ||
ed1e77d3 A |
163 | # |
164 | # Negate condition of branches to labels. | |
165 | # | |
166 | ||
167 | class 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 | |
206 | end | |
207 | ||
208 | def 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 | |
225 | end | |
226 | ||
93a37866 A |
227 | # |
228 | # Lower 'and' masked branches | |
229 | # | |
230 | ||
231 | def 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 | |
249 | end | |
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 | ||
262 | def 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 | |
370 | end | |
371 | ||
372 | # | |
373 | # Specialization of lowering of malformed BaseIndex addresses. | |
374 | # | |
375 | ||
376 | class 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 |
390 | end | |
391 | ||
392 | class 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 |
408 | end | |
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 | ||
424 | def 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 | |
432 | end | |
433 | ||
434 | def mipsScaleOfBaseIndexMatches(baseIndex0, baseIndex1) | |
435 | baseIndex0.base == baseIndex1.base and | |
436 | baseIndex0.index == baseIndex1.index and | |
437 | baseIndex0.scale == baseIndex1.scale | |
438 | end | |
439 | ||
440 | def 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 | |
466 | end | |
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 | ||
479 | def 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 | |
505 | end | |
506 | ||
507 | # | |
508 | # Specialization of lowering of misplaced addresses. | |
509 | # | |
510 | ||
ed1e77d3 A |
511 | class LocalLabelReference |
512 | def register? | |
513 | false | |
514 | end | |
515 | end | |
516 | ||
517 | def 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 | |
533 | end | |
534 | ||
93a37866 A |
535 | def 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 | |
573 | end | |
574 | ||
575 | # | |
576 | # Lowering compares and tests. | |
577 | # | |
578 | ||
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]) | |
586 | end | |
587 | ||
588 | def 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 | |
618 | end | |
619 | ||
620 | # | |
621 | # Lea support. | |
622 | # | |
623 | ||
624 | class 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 | |
632 | end | |
633 | ||
634 | # | |
ed1e77d3 | 635 | # Add PIC compatible header code to all the LLInt rutins. |
93a37866 A |
636 | # |
637 | ||
638 | def 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 | |
648 | end | |
649 | ||
650 | # | |
651 | # Actual lowering code follows. | |
652 | # | |
653 | ||
654 | class 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 | |
697 | end | |
698 | ||
699 | def mipsOperands(operands) | |
700 | operands.map{|v| v.mipsOperand}.join(", ") | |
701 | end | |
702 | ||
703 | def mipsFlippedOperands(operands) | |
704 | mipsOperands([operands[-1]] + operands[0..-2]) | |
705 | end | |
706 | ||
707 | def getMIPSOpcode(opcode, suffix) | |
708 | ||
709 | end | |
710 | ||
711 | def 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 | |
742 | end | |
743 | ||
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}" | |
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 | |
759 | end | |
760 | ||
761 | def 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 | |
768 | end | |
769 | ||
770 | def 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 | |
777 | end | |
778 | ||
ed1e77d3 A |
779 | def 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 | |
787 | end | |
788 | ||
93a37866 A |
789 | class 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 | |
1017 | end |