]> git.saurik.com Git - apple/javascriptcore.git/blob - assembler/MacroAssemblerMIPS.h
JavaScriptCore-1218.0.1.tar.gz
[apple/javascriptcore.git] / assembler / MacroAssemblerMIPS.h
1 /*
2 * Copyright (C) 2008 Apple Inc. All rights reserved.
3 * Copyright (C) 2010 MIPS Technologies, Inc. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY MIPS TECHNOLOGIES, INC. ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MIPS TECHNOLOGIES, INC. OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27 #ifndef MacroAssemblerMIPS_h
28 #define MacroAssemblerMIPS_h
29
30 #if ENABLE(ASSEMBLER) && CPU(MIPS)
31
32 #include "AbstractMacroAssembler.h"
33 #include "MIPSAssembler.h"
34
35 namespace JSC {
36
37 class MacroAssemblerMIPS : public AbstractMacroAssembler<MIPSAssembler> {
38 public:
39 typedef MIPSRegisters::FPRegisterID FPRegisterID;
40
41 MacroAssemblerMIPS()
42 : m_fixedWidth(false)
43 {
44 }
45
46 static bool isCompactPtrAlignedAddressOffset(ptrdiff_t value)
47 {
48 return value >= -2147483647 - 1 && value <= 2147483647;
49 }
50
51 static const Scale ScalePtr = TimesFour;
52
53 // For storing immediate number
54 static const RegisterID immTempRegister = MIPSRegisters::t0;
55 // For storing data loaded from the memory
56 static const RegisterID dataTempRegister = MIPSRegisters::t1;
57 // For storing address base
58 static const RegisterID addrTempRegister = MIPSRegisters::t2;
59 // For storing compare result
60 static const RegisterID cmpTempRegister = MIPSRegisters::t3;
61
62 // FP temp register
63 static const FPRegisterID fpTempRegister = MIPSRegisters::f16;
64
65 static const int MaximumCompactPtrAlignedAddressOffset = 0x7FFFFFFF;
66
67 enum RelationalCondition {
68 Equal,
69 NotEqual,
70 Above,
71 AboveOrEqual,
72 Below,
73 BelowOrEqual,
74 GreaterThan,
75 GreaterThanOrEqual,
76 LessThan,
77 LessThanOrEqual
78 };
79
80 enum ResultCondition {
81 Overflow,
82 Signed,
83 PositiveOrZero,
84 Zero,
85 NonZero
86 };
87
88 enum DoubleCondition {
89 DoubleEqual,
90 DoubleNotEqual,
91 DoubleGreaterThan,
92 DoubleGreaterThanOrEqual,
93 DoubleLessThan,
94 DoubleLessThanOrEqual,
95 DoubleEqualOrUnordered,
96 DoubleNotEqualOrUnordered,
97 DoubleGreaterThanOrUnordered,
98 DoubleGreaterThanOrEqualOrUnordered,
99 DoubleLessThanOrUnordered,
100 DoubleLessThanOrEqualOrUnordered
101 };
102
103 static const RegisterID stackPointerRegister = MIPSRegisters::sp;
104 static const RegisterID returnAddressRegister = MIPSRegisters::ra;
105
106 // Integer arithmetic operations:
107 //
108 // Operations are typically two operand - operation(source, srcDst)
109 // For many operations the source may be an TrustedImm32, the srcDst operand
110 // may often be a memory location (explictly described using an Address
111 // object).
112
113 void add32(RegisterID src, RegisterID dest)
114 {
115 m_assembler.addu(dest, dest, src);
116 }
117
118 void add32(RegisterID op1, RegisterID op2, RegisterID dest)
119 {
120 m_assembler.addu(dest, op1, op2);
121 }
122
123 void add32(TrustedImm32 imm, RegisterID dest)
124 {
125 add32(imm, dest, dest);
126 }
127
128 void add32(TrustedImm32 imm, RegisterID src, RegisterID dest)
129 {
130 if (imm.m_value >= -32768 && imm.m_value <= 32767
131 && !m_fixedWidth) {
132 /*
133 addiu dest, src, imm
134 */
135 m_assembler.addiu(dest, src, imm.m_value);
136 } else {
137 /*
138 li immTemp, imm
139 addu dest, src, immTemp
140 */
141 move(imm, immTempRegister);
142 m_assembler.addu(dest, src, immTempRegister);
143 }
144 }
145
146 void add32(RegisterID src, TrustedImm32 imm, RegisterID dest)
147 {
148 add32(imm, src, dest);
149 }
150
151 void add32(TrustedImm32 imm, Address address)
152 {
153 if (address.offset >= -32768 && address.offset <= 32767
154 && !m_fixedWidth) {
155 /*
156 lw dataTemp, offset(base)
157 li immTemp, imm
158 addu dataTemp, dataTemp, immTemp
159 sw dataTemp, offset(base)
160 */
161 m_assembler.lw(dataTempRegister, address.base, address.offset);
162 if (imm.m_value >= -32768 && imm.m_value <= 32767
163 && !m_fixedWidth)
164 m_assembler.addiu(dataTempRegister, dataTempRegister, imm.m_value);
165 else {
166 move(imm, immTempRegister);
167 m_assembler.addu(dataTempRegister, dataTempRegister, immTempRegister);
168 }
169 m_assembler.sw(dataTempRegister, address.base, address.offset);
170 } else {
171 /*
172 lui addrTemp, (offset + 0x8000) >> 16
173 addu addrTemp, addrTemp, base
174 lw dataTemp, (offset & 0xffff)(addrTemp)
175 li immtemp, imm
176 addu dataTemp, dataTemp, immTemp
177 sw dataTemp, (offset & 0xffff)(addrTemp)
178 */
179 m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16);
180 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
181 m_assembler.lw(dataTempRegister, addrTempRegister, address.offset);
182
183 if (imm.m_value >= -32768 && imm.m_value <= 32767 && !m_fixedWidth)
184 m_assembler.addiu(dataTempRegister, dataTempRegister, imm.m_value);
185 else {
186 move(imm, immTempRegister);
187 m_assembler.addu(dataTempRegister, dataTempRegister, immTempRegister);
188 }
189 m_assembler.sw(dataTempRegister, addrTempRegister, address.offset);
190 }
191 }
192
193 void add32(Address src, RegisterID dest)
194 {
195 load32(src, dataTempRegister);
196 add32(dataTempRegister, dest);
197 }
198
199 void add32(AbsoluteAddress src, RegisterID dest)
200 {
201 load32(src.m_ptr, dataTempRegister);
202 add32(dataTempRegister, dest);
203 }
204
205 void add32(RegisterID src, Address dest)
206 {
207 if (dest.offset >= -32768 && dest.offset <= 32767 && !m_fixedWidth) {
208 /*
209 lw dataTemp, offset(base)
210 addu dataTemp, dataTemp, src
211 sw dataTemp, offset(base)
212 */
213 m_assembler.lw(dataTempRegister, dest.base, dest.offset);
214 m_assembler.addu(dataTempRegister, dataTempRegister, src);
215 m_assembler.sw(dataTempRegister, dest.base, dest.offset);
216 } else {
217 /*
218 lui addrTemp, (offset + 0x8000) >> 16
219 addu addrTemp, addrTemp, base
220 lw dataTemp, (offset & 0xffff)(addrTemp)
221 addu dataTemp, dataTemp, src
222 sw dataTemp, (offset & 0xffff)(addrTemp)
223 */
224 m_assembler.lui(addrTempRegister, (dest.offset + 0x8000) >> 16);
225 m_assembler.addu(addrTempRegister, addrTempRegister, dest.base);
226 m_assembler.lw(dataTempRegister, addrTempRegister, dest.offset);
227 m_assembler.addu(dataTempRegister, dataTempRegister, src);
228 m_assembler.sw(dataTempRegister, addrTempRegister, dest.offset);
229 }
230 }
231
232 void add32(TrustedImm32 imm, AbsoluteAddress address)
233 {
234 /*
235 li addrTemp, address
236 li immTemp, imm
237 lw cmpTemp, 0(addrTemp)
238 addu dataTemp, cmpTemp, immTemp
239 sw dataTemp, 0(addrTemp)
240 */
241 move(TrustedImmPtr(address.m_ptr), addrTempRegister);
242 m_assembler.lw(cmpTempRegister, addrTempRegister, 0);
243 if (imm.m_value >= -32768 && imm.m_value <= 32767 && !m_fixedWidth)
244 m_assembler.addiu(dataTempRegister, cmpTempRegister, imm.m_value);
245 else {
246 move(imm, immTempRegister);
247 m_assembler.addu(dataTempRegister, cmpTempRegister, immTempRegister);
248 }
249 m_assembler.sw(dataTempRegister, addrTempRegister, 0);
250 }
251
252 void add64(TrustedImm32 imm, AbsoluteAddress address)
253 {
254 /*
255 add32(imm, address)
256 sltu immTemp, dataTemp, cmpTemp # set carry-in bit
257 lw dataTemp, 4(addrTemp)
258 addiu dataTemp, imm.m_value >> 31 ? -1 : 0
259 addu dataTemp, dataTemp, immTemp
260 sw dataTemp, 4(addrTemp)
261 */
262 add32(imm, address);
263 m_assembler.sltu(immTempRegister, dataTempRegister, cmpTempRegister);
264 m_assembler.lw(dataTempRegister, addrTempRegister, 4);
265 if (imm.m_value >> 31)
266 m_assembler.addiu(dataTempRegister, dataTempRegister, -1);
267 m_assembler.addu(dataTempRegister, dataTempRegister, immTempRegister);
268 m_assembler.sw(dataTempRegister, addrTempRegister, 4);
269 }
270
271 void and32(Address src, RegisterID dest)
272 {
273 load32(src, dataTempRegister);
274 and32(dataTempRegister, dest);
275 }
276
277 void and32(RegisterID src, RegisterID dest)
278 {
279 m_assembler.andInsn(dest, dest, src);
280 }
281
282 void and32(RegisterID op1, RegisterID op2, RegisterID dest)
283 {
284 m_assembler.andInsn(dest, op1, op2);
285 }
286
287 void and32(TrustedImm32 imm, RegisterID dest)
288 {
289 if (!imm.m_value && !m_fixedWidth)
290 move(MIPSRegisters::zero, dest);
291 else if (imm.m_value > 0 && imm.m_value < 65535 && !m_fixedWidth)
292 m_assembler.andi(dest, dest, imm.m_value);
293 else {
294 /*
295 li immTemp, imm
296 and dest, dest, immTemp
297 */
298 move(imm, immTempRegister);
299 m_assembler.andInsn(dest, dest, immTempRegister);
300 }
301 }
302
303 void and32(TrustedImm32 imm, RegisterID src, RegisterID dest)
304 {
305 if (!imm.m_value && !m_fixedWidth)
306 move(MIPSRegisters::zero, dest);
307 else if (imm.m_value > 0 && imm.m_value < 65535 && !m_fixedWidth)
308 m_assembler.andi(dest, src, imm.m_value);
309 else {
310 move(imm, immTempRegister);
311 m_assembler.andInsn(dest, src, immTempRegister);
312 }
313 }
314
315 void lshift32(RegisterID shiftAmount, RegisterID dest)
316 {
317 m_assembler.sllv(dest, dest, shiftAmount);
318 }
319
320 void lshift32(RegisterID src, RegisterID shiftAmount, RegisterID dest)
321 {
322 m_assembler.sllv(dest, src, shiftAmount);
323 }
324
325 void lshift32(TrustedImm32 imm, RegisterID dest)
326 {
327 move(imm, immTempRegister);
328 m_assembler.sllv(dest, dest, immTempRegister);
329 }
330
331 void lshift32(RegisterID src, TrustedImm32 imm, RegisterID dest)
332 {
333 move(imm, immTempRegister);
334 m_assembler.sllv(dest, src, immTempRegister);
335 }
336
337 void mul32(RegisterID src, RegisterID dest)
338 {
339 m_assembler.mul(dest, dest, src);
340 }
341
342 void mul32(RegisterID op1, RegisterID op2, RegisterID dest)
343 {
344 m_assembler.mul(dest, op1, op2);
345 }
346
347 void mul32(TrustedImm32 imm, RegisterID src, RegisterID dest)
348 {
349 if (!imm.m_value && !m_fixedWidth)
350 move(MIPSRegisters::zero, dest);
351 else if (imm.m_value == 1 && !m_fixedWidth)
352 move(src, dest);
353 else {
354 /*
355 li dataTemp, imm
356 mul dest, src, dataTemp
357 */
358 move(imm, dataTempRegister);
359 m_assembler.mul(dest, src, dataTempRegister);
360 }
361 }
362
363 void neg32(RegisterID srcDest)
364 {
365 m_assembler.subu(srcDest, MIPSRegisters::zero, srcDest);
366 }
367
368 void or32(RegisterID src, RegisterID dest)
369 {
370 m_assembler.orInsn(dest, dest, src);
371 }
372
373 void or32(RegisterID op1, RegisterID op2, RegisterID dest)
374 {
375 m_assembler.orInsn(dest, op1, op2);
376 }
377
378 void or32(TrustedImm32 imm, RegisterID dest)
379 {
380 if (!imm.m_value && !m_fixedWidth)
381 return;
382
383 if (imm.m_value > 0 && imm.m_value < 65535
384 && !m_fixedWidth) {
385 m_assembler.ori(dest, dest, imm.m_value);
386 return;
387 }
388
389 /*
390 li dataTemp, imm
391 or dest, dest, dataTemp
392 */
393 move(imm, dataTempRegister);
394 m_assembler.orInsn(dest, dest, dataTempRegister);
395 }
396
397 void or32(TrustedImm32 imm, RegisterID src, RegisterID dest)
398 {
399 if (!imm.m_value && !m_fixedWidth)
400 return;
401
402 if (imm.m_value > 0 && imm.m_value < 65535 && !m_fixedWidth) {
403 m_assembler.ori(dest, src, imm.m_value);
404 return;
405 }
406
407 /*
408 li dataTemp, imm
409 or dest, src, dataTemp
410 */
411 move(imm, dataTempRegister);
412 m_assembler.orInsn(dest, src, dataTempRegister);
413 }
414
415 void or32(RegisterID src, AbsoluteAddress dest)
416 {
417 load32(dest.m_ptr, dataTempRegister);
418 m_assembler.orInsn(dataTempRegister, dataTempRegister, src);
419 store32(dataTempRegister, dest.m_ptr);
420 }
421
422 void rshift32(RegisterID shiftAmount, RegisterID dest)
423 {
424 m_assembler.srav(dest, dest, shiftAmount);
425 }
426
427 void rshift32(RegisterID src, RegisterID shiftAmount, RegisterID dest)
428 {
429 m_assembler.srav(dest, src, shiftAmount);
430 }
431
432 void rshift32(TrustedImm32 imm, RegisterID dest)
433 {
434 m_assembler.sra(dest, dest, imm.m_value);
435 }
436
437 void rshift32(RegisterID src, TrustedImm32 imm, RegisterID dest)
438 {
439 m_assembler.sra(dest, src, imm.m_value);
440 }
441
442 void urshift32(RegisterID shiftAmount, RegisterID dest)
443 {
444 m_assembler.srlv(dest, dest, shiftAmount);
445 }
446
447 void urshift32(RegisterID src, RegisterID shiftAmount, RegisterID dest)
448 {
449 m_assembler.srlv(dest, src, shiftAmount);
450 }
451
452 void urshift32(TrustedImm32 imm, RegisterID dest)
453 {
454 m_assembler.srl(dest, dest, imm.m_value);
455 }
456
457 void urshift32(RegisterID src, TrustedImm32 imm, RegisterID dest)
458 {
459 m_assembler.srl(dest, src, imm.m_value);
460 }
461
462 void sub32(RegisterID src, RegisterID dest)
463 {
464 m_assembler.subu(dest, dest, src);
465 }
466
467 void sub32(RegisterID op1, RegisterID op2, RegisterID dest)
468 {
469 m_assembler.subu(dest, op1, op2);
470 }
471
472 void sub32(TrustedImm32 imm, RegisterID dest)
473 {
474 if (imm.m_value >= -32767 && imm.m_value <= 32768
475 && !m_fixedWidth) {
476 /*
477 addiu dest, src, imm
478 */
479 m_assembler.addiu(dest, dest, -imm.m_value);
480 } else {
481 /*
482 li immTemp, imm
483 subu dest, src, immTemp
484 */
485 move(imm, immTempRegister);
486 m_assembler.subu(dest, dest, immTempRegister);
487 }
488 }
489
490 void sub32(RegisterID src, TrustedImm32 imm, RegisterID dest)
491 {
492 if (imm.m_value >= -32767 && imm.m_value <= 32768
493 && !m_fixedWidth) {
494 /*
495 addiu dest, src, imm
496 */
497 m_assembler.addiu(dest, src, -imm.m_value);
498 } else {
499 /*
500 li immTemp, imm
501 subu dest, src, immTemp
502 */
503 move(imm, immTempRegister);
504 m_assembler.subu(dest, src, immTempRegister);
505 }
506 }
507
508 void sub32(TrustedImm32 imm, Address address)
509 {
510 if (address.offset >= -32768 && address.offset <= 32767
511 && !m_fixedWidth) {
512 /*
513 lw dataTemp, offset(base)
514 li immTemp, imm
515 subu dataTemp, dataTemp, immTemp
516 sw dataTemp, offset(base)
517 */
518 m_assembler.lw(dataTempRegister, address.base, address.offset);
519 if (imm.m_value >= -32767 && imm.m_value <= 32768 && !m_fixedWidth)
520 m_assembler.addiu(dataTempRegister, dataTempRegister, -imm.m_value);
521 else {
522 move(imm, immTempRegister);
523 m_assembler.subu(dataTempRegister, dataTempRegister, immTempRegister);
524 }
525 m_assembler.sw(dataTempRegister, address.base, address.offset);
526 } else {
527 /*
528 lui addrTemp, (offset + 0x8000) >> 16
529 addu addrTemp, addrTemp, base
530 lw dataTemp, (offset & 0xffff)(addrTemp)
531 li immtemp, imm
532 subu dataTemp, dataTemp, immTemp
533 sw dataTemp, (offset & 0xffff)(addrTemp)
534 */
535 m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16);
536 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
537 m_assembler.lw(dataTempRegister, addrTempRegister, address.offset);
538
539 if (imm.m_value >= -32767 && imm.m_value <= 32768
540 && !m_fixedWidth)
541 m_assembler.addiu(dataTempRegister, dataTempRegister, -imm.m_value);
542 else {
543 move(imm, immTempRegister);
544 m_assembler.subu(dataTempRegister, dataTempRegister, immTempRegister);
545 }
546 m_assembler.sw(dataTempRegister, addrTempRegister, address.offset);
547 }
548 }
549
550 void sub32(Address src, RegisterID dest)
551 {
552 load32(src, dataTempRegister);
553 sub32(dataTempRegister, dest);
554 }
555
556 void sub32(TrustedImm32 imm, AbsoluteAddress address)
557 {
558 /*
559 li addrTemp, address
560 li immTemp, imm
561 lw dataTemp, 0(addrTemp)
562 subu dataTemp, dataTemp, immTemp
563 sw dataTemp, 0(addrTemp)
564 */
565 move(TrustedImmPtr(address.m_ptr), addrTempRegister);
566 m_assembler.lw(dataTempRegister, addrTempRegister, 0);
567
568 if (imm.m_value >= -32767 && imm.m_value <= 32768 && !m_fixedWidth)
569 m_assembler.addiu(dataTempRegister, dataTempRegister, -imm.m_value);
570 else {
571 move(imm, immTempRegister);
572 m_assembler.subu(dataTempRegister, dataTempRegister, immTempRegister);
573 }
574 m_assembler.sw(dataTempRegister, addrTempRegister, 0);
575 }
576
577 void xor32(RegisterID src, RegisterID dest)
578 {
579 m_assembler.xorInsn(dest, dest, src);
580 }
581
582 void xor32(RegisterID op1, RegisterID op2, RegisterID dest)
583 {
584 m_assembler.xorInsn(dest, op1, op2);
585 }
586
587 void xor32(TrustedImm32 imm, RegisterID dest)
588 {
589 if (imm.m_value == -1) {
590 m_assembler.nor(dest, dest, MIPSRegisters::zero);
591 return;
592 }
593
594 /*
595 li immTemp, imm
596 xor dest, dest, immTemp
597 */
598 move(imm, immTempRegister);
599 m_assembler.xorInsn(dest, dest, immTempRegister);
600 }
601
602 void xor32(TrustedImm32 imm, RegisterID src, RegisterID dest)
603 {
604 if (imm.m_value == -1) {
605 m_assembler.nor(dest, src, MIPSRegisters::zero);
606 return;
607 }
608
609 /*
610 li immTemp, imm
611 xor dest, dest, immTemp
612 */
613 move(imm, immTempRegister);
614 m_assembler.xorInsn(dest, src, immTempRegister);
615 }
616
617 void sqrtDouble(FPRegisterID src, FPRegisterID dst)
618 {
619 m_assembler.sqrtd(dst, src);
620 }
621
622 void absDouble(FPRegisterID, FPRegisterID)
623 {
624 RELEASE_ASSERT_NOT_REACHED();
625 }
626
627 ConvertibleLoadLabel convertibleLoadPtr(Address address, RegisterID dest)
628 {
629 ConvertibleLoadLabel result(this);
630 /*
631 lui addrTemp, (offset + 0x8000) >> 16
632 addu addrTemp, addrTemp, base
633 lw dest, (offset & 0xffff)(addrTemp)
634 */
635 m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16);
636 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
637 m_assembler.lw(dest, addrTempRegister, address.offset);
638 return result;
639 }
640
641 // Memory access operations:
642 //
643 // Loads are of the form load(address, destination) and stores of the form
644 // store(source, address). The source for a store may be an TrustedImm32. Address
645 // operand objects to loads and store will be implicitly constructed if a
646 // register is passed.
647
648 /* Need to use zero-extened load byte for load8. */
649 void load8(ImplicitAddress address, RegisterID dest)
650 {
651 if (address.offset >= -32768 && address.offset <= 32767
652 && !m_fixedWidth)
653 m_assembler.lbu(dest, address.base, address.offset);
654 else {
655 /*
656 lui addrTemp, (offset + 0x8000) >> 16
657 addu addrTemp, addrTemp, base
658 lbu dest, (offset & 0xffff)(addrTemp)
659 */
660 m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16);
661 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
662 m_assembler.lbu(dest, addrTempRegister, address.offset);
663 }
664 }
665
666 void load8(BaseIndex address, RegisterID dest)
667 {
668 if (address.offset >= -32768 && address.offset <= 32767
669 && !m_fixedWidth) {
670 /*
671 sll addrTemp, address.index, address.scale
672 addu addrTemp, addrTemp, address.base
673 lbu dest, address.offset(addrTemp)
674 */
675 m_assembler.sll(addrTempRegister, address.index, address.scale);
676 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
677 m_assembler.lbu(dest, addrTempRegister, address.offset);
678 } else {
679 /*
680 sll addrTemp, address.index, address.scale
681 addu addrTemp, addrTemp, address.base
682 lui immTemp, (address.offset + 0x8000) >> 16
683 addu addrTemp, addrTemp, immTemp
684 lbu dest, (address.offset & 0xffff)(at)
685 */
686 m_assembler.sll(addrTempRegister, address.index, address.scale);
687 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
688 m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16);
689 m_assembler.addu(addrTempRegister, addrTempRegister, immTempRegister);
690 m_assembler.lbu(dest, addrTempRegister, address.offset);
691 }
692 }
693
694 void load8Signed(BaseIndex address, RegisterID dest)
695 {
696 if (address.offset >= -32768 && address.offset <= 32767
697 && !m_fixedWidth) {
698 /*
699 sll addrTemp, address.index, address.scale
700 addu addrTemp, addrTemp, address.base
701 lb dest, address.offset(addrTemp)
702 */
703 m_assembler.sll(addrTempRegister, address.index, address.scale);
704 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
705 m_assembler.lb(dest, addrTempRegister, address.offset);
706 } else {
707 /*
708 sll addrTemp, address.index, address.scale
709 addu addrTemp, addrTemp, address.base
710 lui immTemp, (address.offset + 0x8000) >> 16
711 addu addrTemp, addrTemp, immTemp
712 lb dest, (address.offset & 0xffff)(at)
713 */
714 m_assembler.sll(addrTempRegister, address.index, address.scale);
715 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
716 m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16);
717 m_assembler.addu(addrTempRegister, addrTempRegister, immTempRegister);
718 m_assembler.lb(dest, addrTempRegister, address.offset);
719 }
720 }
721
722 void load32(ImplicitAddress address, RegisterID dest)
723 {
724 if (address.offset >= -32768 && address.offset <= 32767
725 && !m_fixedWidth)
726 m_assembler.lw(dest, address.base, address.offset);
727 else {
728 /*
729 lui addrTemp, (offset + 0x8000) >> 16
730 addu addrTemp, addrTemp, base
731 lw dest, (offset & 0xffff)(addrTemp)
732 */
733 m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16);
734 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
735 m_assembler.lw(dest, addrTempRegister, address.offset);
736 }
737 }
738
739 void load32(BaseIndex address, RegisterID dest)
740 {
741 if (address.offset >= -32768 && address.offset <= 32767
742 && !m_fixedWidth) {
743 /*
744 sll addrTemp, address.index, address.scale
745 addu addrTemp, addrTemp, address.base
746 lw dest, address.offset(addrTemp)
747 */
748 m_assembler.sll(addrTempRegister, address.index, address.scale);
749 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
750 m_assembler.lw(dest, addrTempRegister, address.offset);
751 } else {
752 /*
753 sll addrTemp, address.index, address.scale
754 addu addrTemp, addrTemp, address.base
755 lui immTemp, (address.offset + 0x8000) >> 16
756 addu addrTemp, addrTemp, immTemp
757 lw dest, (address.offset & 0xffff)(at)
758 */
759 m_assembler.sll(addrTempRegister, address.index, address.scale);
760 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
761 m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16);
762 m_assembler.addu(addrTempRegister, addrTempRegister, immTempRegister);
763 m_assembler.lw(dest, addrTempRegister, address.offset);
764 }
765 }
766
767 void load16Unaligned(BaseIndex address, RegisterID dest)
768 {
769 load16(address, dest);
770 }
771
772 void load32WithUnalignedHalfWords(BaseIndex address, RegisterID dest)
773 {
774 if (address.offset >= -32768 && address.offset <= 32764
775 && !m_fixedWidth) {
776 /*
777 sll addrTemp, address.index, address.scale
778 addu addrTemp, addrTemp, address.base
779 (Big-Endian)
780 lwl dest, address.offset(addrTemp)
781 lwr dest, address.offset+3(addrTemp)
782 (Little-Endian)
783 lwl dest, address.offset+3(addrTemp)
784 lwr dest, address.offset(addrTemp)
785 */
786 m_assembler.sll(addrTempRegister, address.index, address.scale);
787 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
788 #if CPU(BIG_ENDIAN)
789 m_assembler.lwl(dest, addrTempRegister, address.offset);
790 m_assembler.lwr(dest, addrTempRegister, address.offset + 3);
791 #else
792 m_assembler.lwl(dest, addrTempRegister, address.offset + 3);
793 m_assembler.lwr(dest, addrTempRegister, address.offset);
794
795 #endif
796 } else {
797 /*
798 sll addrTemp, address.index, address.scale
799 addu addrTemp, addrTemp, address.base
800 lui immTemp, address.offset >> 16
801 ori immTemp, immTemp, address.offset & 0xffff
802 addu addrTemp, addrTemp, immTemp
803 (Big-Endian)
804 lw dest, 0(at)
805 lw dest, 3(at)
806 (Little-Endian)
807 lw dest, 3(at)
808 lw dest, 0(at)
809 */
810 m_assembler.sll(addrTempRegister, address.index, address.scale);
811 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
812 m_assembler.lui(immTempRegister, address.offset >> 16);
813 m_assembler.ori(immTempRegister, immTempRegister, address.offset);
814 m_assembler.addu(addrTempRegister, addrTempRegister, immTempRegister);
815 #if CPU(BIG_ENDIAN)
816 m_assembler.lwl(dest, addrTempRegister, 0);
817 m_assembler.lwr(dest, addrTempRegister, 3);
818 #else
819 m_assembler.lwl(dest, addrTempRegister, 3);
820 m_assembler.lwr(dest, addrTempRegister, 0);
821 #endif
822 }
823 }
824
825 void load32(const void* address, RegisterID dest)
826 {
827 /*
828 li addrTemp, address
829 lw dest, 0(addrTemp)
830 */
831 move(TrustedImmPtr(address), addrTempRegister);
832 m_assembler.lw(dest, addrTempRegister, 0);
833 }
834
835 DataLabel32 load32WithAddressOffsetPatch(Address address, RegisterID dest)
836 {
837 m_fixedWidth = true;
838 /*
839 lui addrTemp, address.offset >> 16
840 ori addrTemp, addrTemp, address.offset & 0xffff
841 addu addrTemp, addrTemp, address.base
842 lw dest, 0(addrTemp)
843 */
844 DataLabel32 dataLabel(this);
845 move(TrustedImm32(address.offset), addrTempRegister);
846 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
847 m_assembler.lw(dest, addrTempRegister, 0);
848 m_fixedWidth = false;
849 return dataLabel;
850 }
851
852 DataLabelCompact load32WithCompactAddressOffsetPatch(Address address, RegisterID dest)
853 {
854 DataLabelCompact dataLabel(this);
855 load32WithAddressOffsetPatch(address, dest);
856 return dataLabel;
857 }
858
859 /* Need to use zero-extened load half-word for load16. */
860 void load16(ImplicitAddress address, RegisterID dest)
861 {
862 if (address.offset >= -32768 && address.offset <= 32767
863 && !m_fixedWidth)
864 m_assembler.lhu(dest, address.base, address.offset);
865 else {
866 /*
867 lui addrTemp, (offset + 0x8000) >> 16
868 addu addrTemp, addrTemp, base
869 lhu dest, (offset & 0xffff)(addrTemp)
870 */
871 m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16);
872 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
873 m_assembler.lhu(dest, addrTempRegister, address.offset);
874 }
875 }
876
877 /* Need to use zero-extened load half-word for load16. */
878 void load16(BaseIndex address, RegisterID dest)
879 {
880 if (address.offset >= -32768 && address.offset <= 32767
881 && !m_fixedWidth) {
882 /*
883 sll addrTemp, address.index, address.scale
884 addu addrTemp, addrTemp, address.base
885 lhu dest, address.offset(addrTemp)
886 */
887 m_assembler.sll(addrTempRegister, address.index, address.scale);
888 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
889 m_assembler.lhu(dest, addrTempRegister, address.offset);
890 } else {
891 /*
892 sll addrTemp, address.index, address.scale
893 addu addrTemp, addrTemp, address.base
894 lui immTemp, (address.offset + 0x8000) >> 16
895 addu addrTemp, addrTemp, immTemp
896 lhu dest, (address.offset & 0xffff)(addrTemp)
897 */
898 m_assembler.sll(addrTempRegister, address.index, address.scale);
899 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
900 m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16);
901 m_assembler.addu(addrTempRegister, addrTempRegister, immTempRegister);
902 m_assembler.lhu(dest, addrTempRegister, address.offset);
903 }
904 }
905
906 void load16Signed(BaseIndex address, RegisterID dest)
907 {
908 if (address.offset >= -32768 && address.offset <= 32767
909 && !m_fixedWidth) {
910 /*
911 sll addrTemp, address.index, address.scale
912 addu addrTemp, addrTemp, address.base
913 lh dest, address.offset(addrTemp)
914 */
915 m_assembler.sll(addrTempRegister, address.index, address.scale);
916 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
917 m_assembler.lh(dest, addrTempRegister, address.offset);
918 } else {
919 /*
920 sll addrTemp, address.index, address.scale
921 addu addrTemp, addrTemp, address.base
922 lui immTemp, (address.offset + 0x8000) >> 16
923 addu addrTemp, addrTemp, immTemp
924 lh dest, (address.offset & 0xffff)(addrTemp)
925 */
926 m_assembler.sll(addrTempRegister, address.index, address.scale);
927 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
928 m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16);
929 m_assembler.addu(addrTempRegister, addrTempRegister, immTempRegister);
930 m_assembler.lh(dest, addrTempRegister, address.offset);
931 }
932 }
933
934 DataLabel32 store32WithAddressOffsetPatch(RegisterID src, Address address)
935 {
936 m_fixedWidth = true;
937 /*
938 lui addrTemp, address.offset >> 16
939 ori addrTemp, addrTemp, address.offset & 0xffff
940 addu addrTemp, addrTemp, address.base
941 sw src, 0(addrTemp)
942 */
943 DataLabel32 dataLabel(this);
944 move(TrustedImm32(address.offset), addrTempRegister);
945 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
946 m_assembler.sw(src, addrTempRegister, 0);
947 m_fixedWidth = false;
948 return dataLabel;
949 }
950
951 void store8(RegisterID src, BaseIndex address)
952 {
953 if (address.offset >= -32768 && address.offset <= 32767
954 && !m_fixedWidth) {
955 /*
956 sll addrTemp, address.index, address.scale
957 addu addrTemp, addrTemp, address.base
958 sb src, address.offset(addrTemp)
959 */
960 m_assembler.sll(addrTempRegister, address.index, address.scale);
961 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
962 m_assembler.sb(src, addrTempRegister, address.offset);
963 } else {
964 /*
965 sll addrTemp, address.index, address.scale
966 addu addrTemp, addrTemp, address.base
967 lui immTemp, (address.offset + 0x8000) >> 16
968 addu addrTemp, addrTemp, immTemp
969 sb src, (address.offset & 0xffff)(at)
970 */
971 m_assembler.sll(addrTempRegister, address.index, address.scale);
972 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
973 m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16);
974 m_assembler.addu(addrTempRegister, addrTempRegister, immTempRegister);
975 m_assembler.sb(src, addrTempRegister, address.offset);
976 }
977 }
978
979 void store8(TrustedImm32 imm, void* address)
980 {
981 /*
982 li immTemp, imm
983 li addrTemp, address
984 sb src, 0(addrTemp)
985 */
986 if (!imm.m_value && !m_fixedWidth) {
987 move(TrustedImmPtr(address), addrTempRegister);
988 m_assembler.sb(MIPSRegisters::zero, addrTempRegister, 0);
989 } else {
990 move(imm, immTempRegister);
991 move(TrustedImmPtr(address), addrTempRegister);
992 m_assembler.sb(immTempRegister, addrTempRegister, 0);
993 }
994 }
995
996 void store16(RegisterID src, BaseIndex address)
997 {
998 if (address.offset >= -32768 && address.offset <= 32767
999 && !m_fixedWidth) {
1000 /*
1001 sll addrTemp, address.index, address.scale
1002 addu addrTemp, addrTemp, address.base
1003 sh src, address.offset(addrTemp)
1004 */
1005 m_assembler.sll(addrTempRegister, address.index, address.scale);
1006 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
1007 m_assembler.sh(src, addrTempRegister, address.offset);
1008 } else {
1009 /*
1010 sll addrTemp, address.index, address.scale
1011 addu addrTemp, addrTemp, address.base
1012 lui immTemp, (address.offset + 0x8000) >> 16
1013 addu addrTemp, addrTemp, immTemp
1014 sh src, (address.offset & 0xffff)(at)
1015 */
1016 m_assembler.sll(addrTempRegister, address.index, address.scale);
1017 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
1018 m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16);
1019 m_assembler.addu(addrTempRegister, addrTempRegister, immTempRegister);
1020 m_assembler.sh(src, addrTempRegister, address.offset);
1021 }
1022 }
1023
1024 void store32(RegisterID src, ImplicitAddress address)
1025 {
1026 if (address.offset >= -32768 && address.offset <= 32767
1027 && !m_fixedWidth)
1028 m_assembler.sw(src, address.base, address.offset);
1029 else {
1030 /*
1031 lui addrTemp, (offset + 0x8000) >> 16
1032 addu addrTemp, addrTemp, base
1033 sw src, (offset & 0xffff)(addrTemp)
1034 */
1035 m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16);
1036 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
1037 m_assembler.sw(src, addrTempRegister, address.offset);
1038 }
1039 }
1040
1041 void store32(RegisterID src, BaseIndex address)
1042 {
1043 if (address.offset >= -32768 && address.offset <= 32767
1044 && !m_fixedWidth) {
1045 /*
1046 sll addrTemp, address.index, address.scale
1047 addu addrTemp, addrTemp, address.base
1048 sw src, address.offset(addrTemp)
1049 */
1050 m_assembler.sll(addrTempRegister, address.index, address.scale);
1051 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
1052 m_assembler.sw(src, addrTempRegister, address.offset);
1053 } else {
1054 /*
1055 sll addrTemp, address.index, address.scale
1056 addu addrTemp, addrTemp, address.base
1057 lui immTemp, (address.offset + 0x8000) >> 16
1058 addu addrTemp, addrTemp, immTemp
1059 sw src, (address.offset & 0xffff)(at)
1060 */
1061 m_assembler.sll(addrTempRegister, address.index, address.scale);
1062 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
1063 m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16);
1064 m_assembler.addu(addrTempRegister, addrTempRegister, immTempRegister);
1065 m_assembler.sw(src, addrTempRegister, address.offset);
1066 }
1067 }
1068
1069 void store32(TrustedImm32 imm, ImplicitAddress address)
1070 {
1071 if (address.offset >= -32768 && address.offset <= 32767
1072 && !m_fixedWidth) {
1073 if (!imm.m_value)
1074 m_assembler.sw(MIPSRegisters::zero, address.base, address.offset);
1075 else {
1076 move(imm, immTempRegister);
1077 m_assembler.sw(immTempRegister, address.base, address.offset);
1078 }
1079 } else {
1080 /*
1081 lui addrTemp, (offset + 0x8000) >> 16
1082 addu addrTemp, addrTemp, base
1083 sw immTemp, (offset & 0xffff)(addrTemp)
1084 */
1085 m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16);
1086 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
1087 if (!imm.m_value && !m_fixedWidth)
1088 m_assembler.sw(MIPSRegisters::zero, addrTempRegister, address.offset);
1089 else {
1090 move(imm, immTempRegister);
1091 m_assembler.sw(immTempRegister, addrTempRegister, address.offset);
1092 }
1093 }
1094 }
1095
1096 void store32(TrustedImm32 imm, BaseIndex address)
1097 {
1098 if (address.offset >= -32768 && address.offset <= 32767 && !m_fixedWidth) {
1099 /*
1100 sll addrTemp, address.index, address.scale
1101 addu addrTemp, addrTemp, address.base
1102 sw src, address.offset(addrTemp)
1103 */
1104 m_assembler.sll(addrTempRegister, address.index, address.scale);
1105 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
1106 if (!imm.m_value)
1107 m_assembler.sw(MIPSRegisters::zero, addrTempRegister, address.offset);
1108 else {
1109 move(imm, immTempRegister);
1110 m_assembler.sw(immTempRegister, addrTempRegister, address.offset);
1111 }
1112 } else {
1113 /*
1114 sll addrTemp, address.index, address.scale
1115 addu addrTemp, addrTemp, address.base
1116 lui immTemp, (address.offset + 0x8000) >> 16
1117 addu addrTemp, addrTemp, immTemp
1118 sw src, (address.offset & 0xffff)(at)
1119 */
1120 m_assembler.sll(addrTempRegister, address.index, address.scale);
1121 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
1122 m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16);
1123 m_assembler.addu(addrTempRegister, addrTempRegister, immTempRegister);
1124 if (!imm.m_value && !m_fixedWidth)
1125 m_assembler.sw(MIPSRegisters::zero, addrTempRegister, address.offset);
1126 else {
1127 move(imm, immTempRegister);
1128 m_assembler.sw(immTempRegister, addrTempRegister, address.offset);
1129 }
1130 }
1131 }
1132
1133
1134 void store32(RegisterID src, const void* address)
1135 {
1136 /*
1137 li addrTemp, address
1138 sw src, 0(addrTemp)
1139 */
1140 move(TrustedImmPtr(address), addrTempRegister);
1141 m_assembler.sw(src, addrTempRegister, 0);
1142 }
1143
1144 void store32(TrustedImm32 imm, const void* address)
1145 {
1146 /*
1147 li immTemp, imm
1148 li addrTemp, address
1149 sw src, 0(addrTemp)
1150 */
1151 if (!imm.m_value && !m_fixedWidth) {
1152 move(TrustedImmPtr(address), addrTempRegister);
1153 m_assembler.sw(MIPSRegisters::zero, addrTempRegister, 0);
1154 } else {
1155 move(imm, immTempRegister);
1156 move(TrustedImmPtr(address), addrTempRegister);
1157 m_assembler.sw(immTempRegister, addrTempRegister, 0);
1158 }
1159 }
1160
1161 // Floating-point operations:
1162
1163 static bool supportsFloatingPoint()
1164 {
1165 #if WTF_MIPS_DOUBLE_FLOAT
1166 return true;
1167 #else
1168 return false;
1169 #endif
1170 }
1171
1172 static bool supportsFloatingPointTruncate()
1173 {
1174 #if WTF_MIPS_DOUBLE_FLOAT && WTF_MIPS_ISA_AT_LEAST(2)
1175 return true;
1176 #else
1177 return false;
1178 #endif
1179 }
1180
1181 static bool supportsFloatingPointSqrt()
1182 {
1183 #if WTF_MIPS_DOUBLE_FLOAT && WTF_MIPS_ISA_AT_LEAST(2)
1184 return true;
1185 #else
1186 return false;
1187 #endif
1188 }
1189 static bool supportsFloatingPointAbs() { return false; }
1190
1191 // Stack manipulation operations:
1192 //
1193 // The ABI is assumed to provide a stack abstraction to memory,
1194 // containing machine word sized units of data. Push and pop
1195 // operations add and remove a single register sized unit of data
1196 // to or from the stack. Peek and poke operations read or write
1197 // values on the stack, without moving the current stack position.
1198
1199 void pop(RegisterID dest)
1200 {
1201 m_assembler.lw(dest, MIPSRegisters::sp, 0);
1202 m_assembler.addiu(MIPSRegisters::sp, MIPSRegisters::sp, 4);
1203 }
1204
1205 void push(RegisterID src)
1206 {
1207 m_assembler.addiu(MIPSRegisters::sp, MIPSRegisters::sp, -4);
1208 m_assembler.sw(src, MIPSRegisters::sp, 0);
1209 }
1210
1211 void push(Address address)
1212 {
1213 load32(address, dataTempRegister);
1214 push(dataTempRegister);
1215 }
1216
1217 void push(TrustedImm32 imm)
1218 {
1219 move(imm, immTempRegister);
1220 push(immTempRegister);
1221 }
1222
1223 // Register move operations:
1224 //
1225 // Move values in registers.
1226
1227 void move(TrustedImm32 imm, RegisterID dest)
1228 {
1229 if (!imm.m_value && !m_fixedWidth)
1230 move(MIPSRegisters::zero, dest);
1231 else if (m_fixedWidth) {
1232 m_assembler.lui(dest, imm.m_value >> 16);
1233 m_assembler.ori(dest, dest, imm.m_value);
1234 } else
1235 m_assembler.li(dest, imm.m_value);
1236 }
1237
1238 void move(RegisterID src, RegisterID dest)
1239 {
1240 if (src != dest || m_fixedWidth)
1241 m_assembler.move(dest, src);
1242 }
1243
1244 void move(TrustedImmPtr imm, RegisterID dest)
1245 {
1246 move(TrustedImm32(imm), dest);
1247 }
1248
1249 void swap(RegisterID reg1, RegisterID reg2)
1250 {
1251 move(reg1, immTempRegister);
1252 move(reg2, reg1);
1253 move(immTempRegister, reg2);
1254 }
1255
1256 void signExtend32ToPtr(RegisterID src, RegisterID dest)
1257 {
1258 if (src != dest || m_fixedWidth)
1259 move(src, dest);
1260 }
1261
1262 void zeroExtend32ToPtr(RegisterID src, RegisterID dest)
1263 {
1264 if (src != dest || m_fixedWidth)
1265 move(src, dest);
1266 }
1267
1268 // Forwards / external control flow operations:
1269 //
1270 // This set of jump and conditional branch operations return a Jump
1271 // object which may linked at a later point, allow forwards jump,
1272 // or jumps that will require external linkage (after the code has been
1273 // relocated).
1274 //
1275 // For branches, signed <, >, <= and >= are denoted as l, g, le, and ge
1276 // respecitvely, for unsigned comparisons the names b, a, be, and ae are
1277 // used (representing the names 'below' and 'above').
1278 //
1279 // Operands to the comparision are provided in the expected order, e.g.
1280 // jle32(reg1, TrustedImm32(5)) will branch if the value held in reg1, when
1281 // treated as a signed 32bit value, is less than or equal to 5.
1282 //
1283 // jz and jnz test whether the first operand is equal to zero, and take
1284 // an optional second operand of a mask under which to perform the test.
1285
1286 Jump branch8(RelationalCondition cond, Address left, TrustedImm32 right)
1287 {
1288 // Make sure the immediate value is unsigned 8 bits.
1289 ASSERT(!(right.m_value & 0xFFFFFF00));
1290 load8(left, dataTempRegister);
1291 move(right, immTempRegister);
1292 return branch32(cond, dataTempRegister, immTempRegister);
1293 }
1294
1295 void compare8(RelationalCondition cond, Address left, TrustedImm32 right, RegisterID dest)
1296 {
1297 // Make sure the immediate value is unsigned 8 bits.
1298 ASSERT(!(right.m_value & 0xFFFFFF00));
1299 load8(left, dataTempRegister);
1300 move(right, immTempRegister);
1301 compare32(cond, dataTempRegister, immTempRegister, dest);
1302 }
1303
1304 Jump branch8(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
1305 {
1306 ASSERT(!(right.m_value & 0xFFFFFF00));
1307 load8(left, dataTempRegister);
1308 // Be careful that the previous load8() uses immTempRegister.
1309 // So, we need to put move() after load8().
1310 move(right, immTempRegister);
1311 return branch32(cond, dataTempRegister, immTempRegister);
1312 }
1313
1314 Jump branch32(RelationalCondition cond, RegisterID left, RegisterID right)
1315 {
1316 if (cond == Equal)
1317 return branchEqual(left, right);
1318 if (cond == NotEqual)
1319 return branchNotEqual(left, right);
1320 if (cond == Above) {
1321 m_assembler.sltu(cmpTempRegister, right, left);
1322 return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
1323 }
1324 if (cond == AboveOrEqual) {
1325 m_assembler.sltu(cmpTempRegister, left, right);
1326 return branchEqual(cmpTempRegister, MIPSRegisters::zero);
1327 }
1328 if (cond == Below) {
1329 m_assembler.sltu(cmpTempRegister, left, right);
1330 return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
1331 }
1332 if (cond == BelowOrEqual) {
1333 m_assembler.sltu(cmpTempRegister, right, left);
1334 return branchEqual(cmpTempRegister, MIPSRegisters::zero);
1335 }
1336 if (cond == GreaterThan) {
1337 m_assembler.slt(cmpTempRegister, right, left);
1338 return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
1339 }
1340 if (cond == GreaterThanOrEqual) {
1341 m_assembler.slt(cmpTempRegister, left, right);
1342 return branchEqual(cmpTempRegister, MIPSRegisters::zero);
1343 }
1344 if (cond == LessThan) {
1345 m_assembler.slt(cmpTempRegister, left, right);
1346 return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
1347 }
1348 if (cond == LessThanOrEqual) {
1349 m_assembler.slt(cmpTempRegister, right, left);
1350 return branchEqual(cmpTempRegister, MIPSRegisters::zero);
1351 }
1352 ASSERT(0);
1353
1354 return Jump();
1355 }
1356
1357 Jump branch32(RelationalCondition cond, RegisterID left, TrustedImm32 right)
1358 {
1359 move(right, immTempRegister);
1360 return branch32(cond, left, immTempRegister);
1361 }
1362
1363 Jump branch32(RelationalCondition cond, RegisterID left, Address right)
1364 {
1365 load32(right, dataTempRegister);
1366 return branch32(cond, left, dataTempRegister);
1367 }
1368
1369 Jump branch32(RelationalCondition cond, Address left, RegisterID right)
1370 {
1371 load32(left, dataTempRegister);
1372 return branch32(cond, dataTempRegister, right);
1373 }
1374
1375 Jump branch32(RelationalCondition cond, Address left, TrustedImm32 right)
1376 {
1377 load32(left, dataTempRegister);
1378 move(right, immTempRegister);
1379 return branch32(cond, dataTempRegister, immTempRegister);
1380 }
1381
1382 Jump branch32(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
1383 {
1384 load32(left, dataTempRegister);
1385 // Be careful that the previous load32() uses immTempRegister.
1386 // So, we need to put move() after load32().
1387 move(right, immTempRegister);
1388 return branch32(cond, dataTempRegister, immTempRegister);
1389 }
1390
1391 Jump branch32WithUnalignedHalfWords(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
1392 {
1393 load32WithUnalignedHalfWords(left, dataTempRegister);
1394 // Be careful that the previous load32WithUnalignedHalfWords()
1395 // uses immTempRegister.
1396 // So, we need to put move() after load32WithUnalignedHalfWords().
1397 move(right, immTempRegister);
1398 return branch32(cond, dataTempRegister, immTempRegister);
1399 }
1400
1401 Jump branch32(RelationalCondition cond, AbsoluteAddress left, RegisterID right)
1402 {
1403 load32(left.m_ptr, dataTempRegister);
1404 return branch32(cond, dataTempRegister, right);
1405 }
1406
1407 Jump branch32(RelationalCondition cond, AbsoluteAddress left, TrustedImm32 right)
1408 {
1409 load32(left.m_ptr, dataTempRegister);
1410 move(right, immTempRegister);
1411 return branch32(cond, dataTempRegister, immTempRegister);
1412 }
1413
1414 Jump branchTest32(ResultCondition cond, RegisterID reg, RegisterID mask)
1415 {
1416 ASSERT((cond == Zero) || (cond == NonZero));
1417 m_assembler.andInsn(cmpTempRegister, reg, mask);
1418 if (cond == Zero)
1419 return branchEqual(cmpTempRegister, MIPSRegisters::zero);
1420 return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
1421 }
1422
1423 Jump branchTest32(ResultCondition cond, RegisterID reg, TrustedImm32 mask = TrustedImm32(-1))
1424 {
1425 ASSERT((cond == Zero) || (cond == NonZero));
1426 if (mask.m_value == -1 && !m_fixedWidth) {
1427 if (cond == Zero)
1428 return branchEqual(reg, MIPSRegisters::zero);
1429 return branchNotEqual(reg, MIPSRegisters::zero);
1430 }
1431 move(mask, immTempRegister);
1432 return branchTest32(cond, reg, immTempRegister);
1433 }
1434
1435 Jump branchTest32(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
1436 {
1437 load32(address, dataTempRegister);
1438 return branchTest32(cond, dataTempRegister, mask);
1439 }
1440
1441 Jump branchTest32(ResultCondition cond, BaseIndex address, TrustedImm32 mask = TrustedImm32(-1))
1442 {
1443 load32(address, dataTempRegister);
1444 return branchTest32(cond, dataTempRegister, mask);
1445 }
1446
1447 Jump branchTest8(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
1448 {
1449 load8(address, dataTempRegister);
1450 return branchTest32(cond, dataTempRegister, mask);
1451 }
1452
1453 Jump branchTest8(ResultCondition cond, AbsoluteAddress address, TrustedImm32 mask = TrustedImm32(-1))
1454 {
1455 move(TrustedImmPtr(address.m_ptr), dataTempRegister);
1456 load8(Address(dataTempRegister), dataTempRegister);
1457 return branchTest32(cond, dataTempRegister, mask);
1458 }
1459
1460 Jump jump()
1461 {
1462 return branchEqual(MIPSRegisters::zero, MIPSRegisters::zero);
1463 }
1464
1465 void jump(RegisterID target)
1466 {
1467 move(target, MIPSRegisters::t9);
1468 m_assembler.jr(MIPSRegisters::t9);
1469 m_assembler.nop();
1470 }
1471
1472 void jump(Address address)
1473 {
1474 m_fixedWidth = true;
1475 load32(address, MIPSRegisters::t9);
1476 m_assembler.jr(MIPSRegisters::t9);
1477 m_assembler.nop();
1478 m_fixedWidth = false;
1479 }
1480
1481 void jump(AbsoluteAddress address)
1482 {
1483 m_fixedWidth = true;
1484 load32(address.m_ptr, MIPSRegisters::t9);
1485 m_assembler.jr(MIPSRegisters::t9);
1486 m_assembler.nop();
1487 m_fixedWidth = false;
1488 }
1489
1490 void moveDoubleToInts(FPRegisterID src, RegisterID dest1, RegisterID dest2)
1491 {
1492 m_assembler.vmov(dest1, dest2, src);
1493 }
1494
1495 void moveIntsToDouble(RegisterID src1, RegisterID src2, FPRegisterID dest, FPRegisterID scratch)
1496 {
1497 UNUSED_PARAM(scratch);
1498 m_assembler.vmov(dest, src1, src2);
1499 }
1500
1501 // Arithmetic control flow operations:
1502 //
1503 // This set of conditional branch operations branch based
1504 // on the result of an arithmetic operation. The operation
1505 // is performed as normal, storing the result.
1506 //
1507 // * jz operations branch if the result is zero.
1508 // * jo operations branch if the (signed) arithmetic
1509 // operation caused an overflow to occur.
1510
1511 Jump branchAdd32(ResultCondition cond, RegisterID src, RegisterID dest)
1512 {
1513 ASSERT((cond == Overflow) || (cond == Signed) || (cond == PositiveOrZero) || (cond == Zero) || (cond == NonZero));
1514 if (cond == Overflow) {
1515 /*
1516 move dest, dataTemp
1517 xor cmpTemp, dataTemp, src
1518 bltz cmpTemp, No_overflow # diff sign bit -> no overflow
1519 addu dest, dataTemp, src
1520 xor cmpTemp, dest, dataTemp
1521 bgez cmpTemp, No_overflow # same sign big -> no overflow
1522 nop
1523 b Overflow
1524 nop
1525 nop
1526 nop
1527 nop
1528 nop
1529 No_overflow:
1530 */
1531 move(dest, dataTempRegister);
1532 m_assembler.xorInsn(cmpTempRegister, dataTempRegister, src);
1533 m_assembler.bltz(cmpTempRegister, 10);
1534 m_assembler.addu(dest, dataTempRegister, src);
1535 m_assembler.xorInsn(cmpTempRegister, dest, dataTempRegister);
1536 m_assembler.bgez(cmpTempRegister, 7);
1537 m_assembler.nop();
1538 return jump();
1539 }
1540 if (cond == Signed) {
1541 add32(src, dest);
1542 // Check if dest is negative.
1543 m_assembler.slt(cmpTempRegister, dest, MIPSRegisters::zero);
1544 return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
1545 }
1546 if (cond == PositiveOrZero) {
1547 add32(src, dest);
1548 // Check if dest is not negative.
1549 m_assembler.slt(cmpTempRegister, dest, MIPSRegisters::zero);
1550 return branchEqual(cmpTempRegister, MIPSRegisters::zero);
1551 }
1552 if (cond == Zero) {
1553 add32(src, dest);
1554 return branchEqual(dest, MIPSRegisters::zero);
1555 }
1556 if (cond == NonZero) {
1557 add32(src, dest);
1558 return branchNotEqual(dest, MIPSRegisters::zero);
1559 }
1560 ASSERT(0);
1561 return Jump();
1562 }
1563
1564 Jump branchAdd32(ResultCondition cond, RegisterID op1, RegisterID op2, RegisterID dest)
1565 {
1566 ASSERT((cond == Overflow) || (cond == Signed) || (cond == PositiveOrZero) || (cond == Zero) || (cond == NonZero));
1567 if (cond == Overflow) {
1568 /*
1569 move dataTemp, op1
1570 xor cmpTemp, dataTemp, op2
1571 bltz cmpTemp, No_overflow # diff sign bit -> no overflow
1572 addu dest, dataTemp, op2
1573 xor cmpTemp, dest, dataTemp
1574 bgez cmpTemp, No_overflow # same sign big -> no overflow
1575 nop
1576 b Overflow
1577 nop
1578 nop
1579 nop
1580 nop
1581 nop
1582 No_overflow:
1583 */
1584 move(op1, dataTempRegister);
1585 m_assembler.xorInsn(cmpTempRegister, dataTempRegister, op2);
1586 m_assembler.bltz(cmpTempRegister, 10);
1587 m_assembler.addu(dest, dataTempRegister, op2);
1588 m_assembler.xorInsn(cmpTempRegister, dest, dataTempRegister);
1589 m_assembler.bgez(cmpTempRegister, 7);
1590 m_assembler.nop();
1591 return jump();
1592 }
1593 if (cond == Signed) {
1594 add32(op1, op2, dest);
1595 // Check if dest is negative.
1596 m_assembler.slt(cmpTempRegister, dest, MIPSRegisters::zero);
1597 return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
1598 }
1599 if (cond == PositiveOrZero) {
1600 add32(op1, op2, dest);
1601 // Check if dest is not negative.
1602 m_assembler.slt(cmpTempRegister, dest, MIPSRegisters::zero);
1603 return branchEqual(cmpTempRegister, MIPSRegisters::zero);
1604 }
1605 if (cond == Zero) {
1606 add32(op1, op2, dest);
1607 return branchEqual(dest, MIPSRegisters::zero);
1608 }
1609 if (cond == NonZero) {
1610 add32(op1, op2, dest);
1611 return branchNotEqual(dest, MIPSRegisters::zero);
1612 }
1613 ASSERT(0);
1614 return Jump();
1615 }
1616
1617 Jump branchAdd32(ResultCondition cond, TrustedImm32 imm, RegisterID dest)
1618 {
1619 move(imm, immTempRegister);
1620 return branchAdd32(cond, immTempRegister, dest);
1621 }
1622
1623 Jump branchAdd32(ResultCondition cond, RegisterID src, TrustedImm32 imm, RegisterID dest)
1624 {
1625 move(imm, immTempRegister);
1626 move(src, dest);
1627 return branchAdd32(cond, immTempRegister, dest);
1628 }
1629
1630 Jump branchAdd32(ResultCondition cond, TrustedImm32 imm, AbsoluteAddress dest)
1631 {
1632 ASSERT((cond == Overflow) || (cond == Signed) || (cond == PositiveOrZero) || (cond == Zero) || (cond == NonZero));
1633 if (cond == Overflow) {
1634 /*
1635 move dataTemp, dest
1636 xori cmpTemp, dataTemp, imm
1637 bltz cmpTemp, No_overflow # diff sign bit -> no overflow
1638 addiu dataTemp, dataTemp, imm
1639 move dest, dataTemp
1640 xori cmpTemp, dataTemp, imm
1641 bgez cmpTemp, No_overflow # same sign big -> no overflow
1642 nop
1643 b Overflow
1644 nop
1645 nop
1646 nop
1647 nop
1648 nop
1649 No_overflow:
1650 */
1651 if (imm.m_value >= -32768 && imm.m_value <= 32767 && !m_fixedWidth) {
1652 load32(dest.m_ptr, dataTempRegister);
1653 m_assembler.xori(cmpTempRegister, dataTempRegister, imm.m_value);
1654 m_assembler.bltz(cmpTempRegister, 10);
1655 m_assembler.addiu(dataTempRegister, dataTempRegister, imm.m_value);
1656 store32(dataTempRegister, dest.m_ptr);
1657 m_assembler.xori(cmpTempRegister, dataTempRegister, imm.m_value);
1658 m_assembler.bgez(cmpTempRegister, 7);
1659 m_assembler.nop();
1660 } else {
1661 load32(dest.m_ptr, dataTempRegister);
1662 move(imm, immTempRegister);
1663 m_assembler.xorInsn(cmpTempRegister, dataTempRegister, immTempRegister);
1664 m_assembler.bltz(cmpTempRegister, 10);
1665 m_assembler.addiu(dataTempRegister, dataTempRegister, immTempRegister);
1666 store32(dataTempRegister, dest.m_ptr);
1667 m_assembler.xori(cmpTempRegister, dataTempRegister, immTempRegister);
1668 m_assembler.bgez(cmpTempRegister, 7);
1669 m_assembler.nop();
1670 }
1671 return jump();
1672 }
1673 move(imm, immTempRegister);
1674 load32(dest.m_ptr, dataTempRegister);
1675 add32(immTempRegister, dataTempRegister);
1676 store32(dataTempRegister, dest.m_ptr);
1677 if (cond == Signed) {
1678 // Check if dest is negative.
1679 m_assembler.slt(cmpTempRegister, dataTempRegister, MIPSRegisters::zero);
1680 return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
1681 }
1682 if (cond == PositiveOrZero) {
1683 // Check if dest is not negative.
1684 m_assembler.slt(cmpTempRegister, dataTempRegister, MIPSRegisters::zero);
1685 return branchEqual(cmpTempRegister, MIPSRegisters::zero);
1686 }
1687 if (cond == Zero)
1688 return branchEqual(dataTempRegister, MIPSRegisters::zero);
1689 if (cond == NonZero)
1690 return branchNotEqual(dataTempRegister, MIPSRegisters::zero);
1691 ASSERT(0);
1692 return Jump();
1693 }
1694
1695 Jump branchMul32(ResultCondition cond, RegisterID src1, RegisterID src2, RegisterID dest)
1696 {
1697 ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
1698 if (cond == Overflow) {
1699 /*
1700 mult src, dest
1701 mfhi dataTemp
1702 mflo dest
1703 sra addrTemp, dest, 31
1704 beq dataTemp, addrTemp, No_overflow # all sign bits (bit 63 to bit 31) are the same -> no overflow
1705 nop
1706 b Overflow
1707 nop
1708 nop
1709 nop
1710 nop
1711 nop
1712 No_overflow:
1713 */
1714 m_assembler.mult(src1, src2);
1715 m_assembler.mfhi(dataTempRegister);
1716 m_assembler.mflo(dest);
1717 m_assembler.sra(addrTempRegister, dest, 31);
1718 m_assembler.beq(dataTempRegister, addrTempRegister, 7);
1719 m_assembler.nop();
1720 return jump();
1721 }
1722 if (cond == Signed) {
1723 mul32(src1, src2, dest);
1724 // Check if dest is negative.
1725 m_assembler.slt(cmpTempRegister, dest, MIPSRegisters::zero);
1726 return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
1727 }
1728 if (cond == Zero) {
1729 mul32(src1, src2, dest);
1730 return branchEqual(dest, MIPSRegisters::zero);
1731 }
1732 if (cond == NonZero) {
1733 mul32(src1, src2, dest);
1734 return branchNotEqual(dest, MIPSRegisters::zero);
1735 }
1736 ASSERT(0);
1737 return Jump();
1738 }
1739
1740 Jump branchMul32(ResultCondition cond, RegisterID src, RegisterID dest)
1741 {
1742 ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
1743 if (cond == Overflow) {
1744 /*
1745 mult src, dest
1746 mfhi dataTemp
1747 mflo dest
1748 sra addrTemp, dest, 31
1749 beq dataTemp, addrTemp, No_overflow # all sign bits (bit 63 to bit 31) are the same -> no overflow
1750 nop
1751 b Overflow
1752 nop
1753 nop
1754 nop
1755 nop
1756 nop
1757 No_overflow:
1758 */
1759 m_assembler.mult(src, dest);
1760 m_assembler.mfhi(dataTempRegister);
1761 m_assembler.mflo(dest);
1762 m_assembler.sra(addrTempRegister, dest, 31);
1763 m_assembler.beq(dataTempRegister, addrTempRegister, 7);
1764 m_assembler.nop();
1765 return jump();
1766 }
1767 if (cond == Signed) {
1768 mul32(src, dest);
1769 // Check if dest is negative.
1770 m_assembler.slt(cmpTempRegister, dest, MIPSRegisters::zero);
1771 return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
1772 }
1773 if (cond == Zero) {
1774 mul32(src, dest);
1775 return branchEqual(dest, MIPSRegisters::zero);
1776 }
1777 if (cond == NonZero) {
1778 mul32(src, dest);
1779 return branchNotEqual(dest, MIPSRegisters::zero);
1780 }
1781 ASSERT(0);
1782 return Jump();
1783 }
1784
1785 Jump branchMul32(ResultCondition cond, TrustedImm32 imm, RegisterID src, RegisterID dest)
1786 {
1787 move(imm, immTempRegister);
1788 return branchMul32(cond, immTempRegister, src, dest);
1789 }
1790
1791 Jump branchSub32(ResultCondition cond, RegisterID src, RegisterID dest)
1792 {
1793 ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
1794 if (cond == Overflow) {
1795 /*
1796 move dest, dataTemp
1797 xor cmpTemp, dataTemp, src
1798 bgez cmpTemp, No_overflow # same sign bit -> no overflow
1799 subu dest, dataTemp, src
1800 xor cmpTemp, dest, dataTemp
1801 bgez cmpTemp, No_overflow # same sign bit -> no overflow
1802 nop
1803 b Overflow
1804 nop
1805 nop
1806 nop
1807 nop
1808 nop
1809 No_overflow:
1810 */
1811 move(dest, dataTempRegister);
1812 m_assembler.xorInsn(cmpTempRegister, dataTempRegister, src);
1813 m_assembler.bgez(cmpTempRegister, 10);
1814 m_assembler.subu(dest, dataTempRegister, src);
1815 m_assembler.xorInsn(cmpTempRegister, dest, dataTempRegister);
1816 m_assembler.bgez(cmpTempRegister, 7);
1817 m_assembler.nop();
1818 return jump();
1819 }
1820 if (cond == Signed) {
1821 sub32(src, dest);
1822 // Check if dest is negative.
1823 m_assembler.slt(cmpTempRegister, dest, MIPSRegisters::zero);
1824 return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
1825 }
1826 if (cond == Zero) {
1827 sub32(src, dest);
1828 return branchEqual(dest, MIPSRegisters::zero);
1829 }
1830 if (cond == NonZero) {
1831 sub32(src, dest);
1832 return branchNotEqual(dest, MIPSRegisters::zero);
1833 }
1834 ASSERT(0);
1835 return Jump();
1836 }
1837
1838 Jump branchSub32(ResultCondition cond, TrustedImm32 imm, RegisterID dest)
1839 {
1840 move(imm, immTempRegister);
1841 return branchSub32(cond, immTempRegister, dest);
1842 }
1843
1844 Jump branchSub32(ResultCondition cond, RegisterID src, TrustedImm32 imm, RegisterID dest)
1845 {
1846 move(imm, immTempRegister);
1847 return branchSub32(cond, src, immTempRegister, dest);
1848 }
1849
1850 Jump branchSub32(ResultCondition cond, RegisterID op1, RegisterID op2, RegisterID dest)
1851 {
1852 ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
1853 if (cond == Overflow) {
1854 /*
1855 move dataTemp, op1
1856 xor cmpTemp, dataTemp, op2
1857 bgez cmpTemp, No_overflow # same sign bit -> no overflow
1858 subu dest, dataTemp, op2
1859 xor cmpTemp, dest, dataTemp
1860 bgez cmpTemp, No_overflow # same sign bit -> no overflow
1861 nop
1862 b Overflow
1863 nop
1864 nop
1865 nop
1866 nop
1867 nop
1868 No_overflow:
1869 */
1870 move(op1, dataTempRegister);
1871 m_assembler.xorInsn(cmpTempRegister, dataTempRegister, op2);
1872 m_assembler.bgez(cmpTempRegister, 10);
1873 m_assembler.subu(dest, dataTempRegister, op2);
1874 m_assembler.xorInsn(cmpTempRegister, dest, dataTempRegister);
1875 m_assembler.bgez(cmpTempRegister, 7);
1876 m_assembler.nop();
1877 return jump();
1878 }
1879 if (cond == Signed) {
1880 sub32(op1, op2, dest);
1881 // Check if dest is negative.
1882 m_assembler.slt(cmpTempRegister, dest, MIPSRegisters::zero);
1883 return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
1884 }
1885 if (cond == Zero) {
1886 sub32(op1, op2, dest);
1887 return branchEqual(dest, MIPSRegisters::zero);
1888 }
1889 if (cond == NonZero) {
1890 sub32(op1, op2, dest);
1891 return branchNotEqual(dest, MIPSRegisters::zero);
1892 }
1893 ASSERT(0);
1894 return Jump();
1895 }
1896
1897 Jump branchNeg32(ResultCondition cond, RegisterID srcDest)
1898 {
1899 m_assembler.li(dataTempRegister, -1);
1900 return branchMul32(cond, dataTempRegister, srcDest);
1901 }
1902
1903 Jump branchOr32(ResultCondition cond, RegisterID src, RegisterID dest)
1904 {
1905 ASSERT((cond == Signed) || (cond == Zero) || (cond == NonZero));
1906 if (cond == Signed) {
1907 or32(src, dest);
1908 // Check if dest is negative.
1909 m_assembler.slt(cmpTempRegister, dest, MIPSRegisters::zero);
1910 return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
1911 }
1912 if (cond == Zero) {
1913 or32(src, dest);
1914 return branchEqual(dest, MIPSRegisters::zero);
1915 }
1916 if (cond == NonZero) {
1917 or32(src, dest);
1918 return branchNotEqual(dest, MIPSRegisters::zero);
1919 }
1920 ASSERT(0);
1921 return Jump();
1922 }
1923
1924 // Miscellaneous operations:
1925
1926 void breakpoint()
1927 {
1928 m_assembler.bkpt();
1929 }
1930
1931 Call nearCall()
1932 {
1933 /* We need two words for relaxation. */
1934 m_assembler.nop();
1935 m_assembler.nop();
1936 m_assembler.jal();
1937 m_assembler.nop();
1938 return Call(m_assembler.label(), Call::LinkableNear);
1939 }
1940
1941 Call call()
1942 {
1943 m_assembler.lui(MIPSRegisters::t9, 0);
1944 m_assembler.ori(MIPSRegisters::t9, MIPSRegisters::t9, 0);
1945 m_assembler.jalr(MIPSRegisters::t9);
1946 m_assembler.nop();
1947 return Call(m_assembler.label(), Call::Linkable);
1948 }
1949
1950 Call call(RegisterID target)
1951 {
1952 move(target, MIPSRegisters::t9);
1953 m_assembler.jalr(MIPSRegisters::t9);
1954 m_assembler.nop();
1955 return Call(m_assembler.label(), Call::None);
1956 }
1957
1958 Call call(Address address)
1959 {
1960 m_fixedWidth = true;
1961 load32(address, MIPSRegisters::t9);
1962 m_assembler.jalr(MIPSRegisters::t9);
1963 m_assembler.nop();
1964 m_fixedWidth = false;
1965 return Call(m_assembler.label(), Call::None);
1966 }
1967
1968 void ret()
1969 {
1970 m_assembler.jr(MIPSRegisters::ra);
1971 m_assembler.nop();
1972 }
1973
1974 void compare32(RelationalCondition cond, RegisterID left, RegisterID right, RegisterID dest)
1975 {
1976 if (cond == Equal) {
1977 m_assembler.xorInsn(dest, left, right);
1978 m_assembler.sltiu(dest, dest, 1);
1979 } else if (cond == NotEqual) {
1980 m_assembler.xorInsn(dest, left, right);
1981 m_assembler.sltu(dest, MIPSRegisters::zero, dest);
1982 } else if (cond == Above)
1983 m_assembler.sltu(dest, right, left);
1984 else if (cond == AboveOrEqual) {
1985 m_assembler.sltu(dest, left, right);
1986 m_assembler.xori(dest, dest, 1);
1987 } else if (cond == Below)
1988 m_assembler.sltu(dest, left, right);
1989 else if (cond == BelowOrEqual) {
1990 m_assembler.sltu(dest, right, left);
1991 m_assembler.xori(dest, dest, 1);
1992 } else if (cond == GreaterThan)
1993 m_assembler.slt(dest, right, left);
1994 else if (cond == GreaterThanOrEqual) {
1995 m_assembler.slt(dest, left, right);
1996 m_assembler.xori(dest, dest, 1);
1997 } else if (cond == LessThan)
1998 m_assembler.slt(dest, left, right);
1999 else if (cond == LessThanOrEqual) {
2000 m_assembler.slt(dest, right, left);
2001 m_assembler.xori(dest, dest, 1);
2002 }
2003 }
2004
2005 void compare32(RelationalCondition cond, RegisterID left, TrustedImm32 right, RegisterID dest)
2006 {
2007 move(right, immTempRegister);
2008 compare32(cond, left, immTempRegister, dest);
2009 }
2010
2011 void test8(ResultCondition cond, Address address, TrustedImm32 mask, RegisterID dest)
2012 {
2013 ASSERT((cond == Zero) || (cond == NonZero));
2014 load8(address, dataTempRegister);
2015 if (mask.m_value == -1 && !m_fixedWidth) {
2016 if (cond == Zero)
2017 m_assembler.sltiu(dest, dataTempRegister, 1);
2018 else
2019 m_assembler.sltu(dest, MIPSRegisters::zero, dataTempRegister);
2020 } else {
2021 move(mask, immTempRegister);
2022 m_assembler.andInsn(cmpTempRegister, dataTempRegister, immTempRegister);
2023 if (cond == Zero)
2024 m_assembler.sltiu(dest, cmpTempRegister, 1);
2025 else
2026 m_assembler.sltu(dest, MIPSRegisters::zero, cmpTempRegister);
2027 }
2028 }
2029
2030 void test32(ResultCondition cond, Address address, TrustedImm32 mask, RegisterID dest)
2031 {
2032 ASSERT((cond == Zero) || (cond == NonZero));
2033 load32(address, dataTempRegister);
2034 if (mask.m_value == -1 && !m_fixedWidth) {
2035 if (cond == Zero)
2036 m_assembler.sltiu(dest, dataTempRegister, 1);
2037 else
2038 m_assembler.sltu(dest, MIPSRegisters::zero, dataTempRegister);
2039 } else {
2040 move(mask, immTempRegister);
2041 m_assembler.andInsn(cmpTempRegister, dataTempRegister, immTempRegister);
2042 if (cond == Zero)
2043 m_assembler.sltiu(dest, cmpTempRegister, 1);
2044 else
2045 m_assembler.sltu(dest, MIPSRegisters::zero, cmpTempRegister);
2046 }
2047 }
2048
2049 DataLabel32 moveWithPatch(TrustedImm32 imm, RegisterID dest)
2050 {
2051 m_fixedWidth = true;
2052 DataLabel32 label(this);
2053 move(imm, dest);
2054 m_fixedWidth = false;
2055 return label;
2056 }
2057
2058 DataLabelPtr moveWithPatch(TrustedImmPtr initialValue, RegisterID dest)
2059 {
2060 m_fixedWidth = true;
2061 DataLabelPtr label(this);
2062 move(initialValue, dest);
2063 m_fixedWidth = false;
2064 return label;
2065 }
2066
2067 Jump branchPtrWithPatch(RelationalCondition cond, RegisterID left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
2068 {
2069 m_fixedWidth = true;
2070 dataLabel = moveWithPatch(initialRightValue, immTempRegister);
2071 Jump temp = branch32(cond, left, immTempRegister);
2072 m_fixedWidth = false;
2073 return temp;
2074 }
2075
2076 Jump branchPtrWithPatch(RelationalCondition cond, Address left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
2077 {
2078 m_fixedWidth = true;
2079 load32(left, dataTempRegister);
2080 dataLabel = moveWithPatch(initialRightValue, immTempRegister);
2081 Jump temp = branch32(cond, dataTempRegister, immTempRegister);
2082 m_fixedWidth = false;
2083 return temp;
2084 }
2085
2086 DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address)
2087 {
2088 m_fixedWidth = true;
2089 DataLabelPtr dataLabel = moveWithPatch(initialValue, dataTempRegister);
2090 store32(dataTempRegister, address);
2091 m_fixedWidth = false;
2092 return dataLabel;
2093 }
2094
2095 DataLabelPtr storePtrWithPatch(ImplicitAddress address)
2096 {
2097 return storePtrWithPatch(TrustedImmPtr(0), address);
2098 }
2099
2100 Call tailRecursiveCall()
2101 {
2102 // Like a normal call, but don't update the returned address register
2103 m_fixedWidth = true;
2104 move(TrustedImm32(0), MIPSRegisters::t9);
2105 m_assembler.jr(MIPSRegisters::t9);
2106 m_assembler.nop();
2107 m_fixedWidth = false;
2108 return Call(m_assembler.label(), Call::Linkable);
2109 }
2110
2111 Call makeTailRecursiveCall(Jump oldJump)
2112 {
2113 oldJump.link(this);
2114 return tailRecursiveCall();
2115 }
2116
2117 void loadFloat(BaseIndex address, FPRegisterID dest)
2118 {
2119 if (address.offset >= -32768 && address.offset <= 32767
2120 && !m_fixedWidth) {
2121 /*
2122 sll addrTemp, address.index, address.scale
2123 addu addrTemp, addrTemp, address.base
2124 lwc1 dest, address.offset(addrTemp)
2125 */
2126 m_assembler.sll(addrTempRegister, address.index, address.scale);
2127 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
2128 m_assembler.lwc1(dest, addrTempRegister, address.offset);
2129 } else {
2130 /*
2131 sll addrTemp, address.index, address.scale
2132 addu addrTemp, addrTemp, address.base
2133 lui immTemp, (address.offset + 0x8000) >> 16
2134 addu addrTemp, addrTemp, immTemp
2135 lwc1 dest, (address.offset & 0xffff)(at)
2136 */
2137 m_assembler.sll(addrTempRegister, address.index, address.scale);
2138 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
2139 m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16);
2140 m_assembler.addu(addrTempRegister, addrTempRegister, immTempRegister);
2141 m_assembler.lwc1(dest, addrTempRegister, address.offset);
2142 }
2143 }
2144
2145 void loadDouble(ImplicitAddress address, FPRegisterID dest)
2146 {
2147 #if WTF_MIPS_ISA(1)
2148 /*
2149 li addrTemp, address.offset
2150 addu addrTemp, addrTemp, base
2151 lwc1 dest, 0(addrTemp)
2152 lwc1 dest+1, 4(addrTemp)
2153 */
2154 move(TrustedImm32(address.offset), addrTempRegister);
2155 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
2156 m_assembler.lwc1(dest, addrTempRegister, 0);
2157 m_assembler.lwc1(FPRegisterID(dest + 1), addrTempRegister, 4);
2158 #else
2159 if (address.offset >= -32768 && address.offset <= 32767
2160 && !m_fixedWidth) {
2161 m_assembler.ldc1(dest, address.base, address.offset);
2162 } else {
2163 /*
2164 lui addrTemp, (offset + 0x8000) >> 16
2165 addu addrTemp, addrTemp, base
2166 ldc1 dest, (offset & 0xffff)(addrTemp)
2167 */
2168 m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16);
2169 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
2170 m_assembler.ldc1(dest, addrTempRegister, address.offset);
2171 }
2172 #endif
2173 }
2174
2175 void loadDouble(BaseIndex address, FPRegisterID dest)
2176 {
2177 #if WTF_MIPS_ISA(1)
2178 if (address.offset >= -32768 && address.offset <= 32767
2179 && !m_fixedWidth) {
2180 /*
2181 sll addrTemp, address.index, address.scale
2182 addu addrTemp, addrTemp, address.base
2183 lwc1 dest, address.offset(addrTemp)
2184 lwc1 dest+1, (address.offset+4)(addrTemp)
2185 */
2186 m_assembler.sll(addrTempRegister, address.index, address.scale);
2187 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
2188 m_assembler.lwc1(dest, addrTempRegister, address.offset);
2189 m_assembler.lwc1(FPRegisterID(dest + 1), addrTempRegister, address.offset + 4);
2190 } else {
2191 /*
2192 sll addrTemp, address.index, address.scale
2193 addu addrTemp, addrTemp, address.base
2194 lui immTemp, (address.offset + 0x8000) >> 16
2195 addu addrTemp, addrTemp, immTemp
2196 lwc1 dest, (address.offset & 0xffff)(at)
2197 lwc1 dest+1, (address.offset & 0xffff + 4)(at)
2198 */
2199 m_assembler.sll(addrTempRegister, address.index, address.scale);
2200 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
2201 m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16);
2202 m_assembler.addu(addrTempRegister, addrTempRegister, immTempRegister);
2203 m_assembler.lwc1(dest, addrTempRegister, address.offset);
2204 m_assembler.lwc1(FPRegisterID(dest + 1), addrTempRegister, address.offset + 4);
2205 }
2206 #else
2207 if (address.offset >= -32768 && address.offset <= 32767
2208 && !m_fixedWidth) {
2209 /*
2210 sll addrTemp, address.index, address.scale
2211 addu addrTemp, addrTemp, address.base
2212 ldc1 dest, address.offset(addrTemp)
2213 */
2214 m_assembler.sll(addrTempRegister, address.index, address.scale);
2215 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
2216 m_assembler.ldc1(dest, addrTempRegister, address.offset);
2217 } else {
2218 /*
2219 sll addrTemp, address.index, address.scale
2220 addu addrTemp, addrTemp, address.base
2221 lui immTemp, (address.offset + 0x8000) >> 16
2222 addu addrTemp, addrTemp, immTemp
2223 ldc1 dest, (address.offset & 0xffff)(at)
2224 */
2225 m_assembler.sll(addrTempRegister, address.index, address.scale);
2226 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
2227 m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16);
2228 m_assembler.addu(addrTempRegister, addrTempRegister, immTempRegister);
2229 m_assembler.ldc1(dest, addrTempRegister, address.offset);
2230 }
2231 #endif
2232 }
2233
2234 void loadDouble(const void* address, FPRegisterID dest)
2235 {
2236 #if WTF_MIPS_ISA(1)
2237 /*
2238 li addrTemp, address
2239 lwc1 dest, 0(addrTemp)
2240 lwc1 dest+1, 4(addrTemp)
2241 */
2242 move(TrustedImmPtr(address), addrTempRegister);
2243 m_assembler.lwc1(dest, addrTempRegister, 0);
2244 m_assembler.lwc1(FPRegisterID(dest + 1), addrTempRegister, 4);
2245 #else
2246 /*
2247 li addrTemp, address
2248 ldc1 dest, 0(addrTemp)
2249 */
2250 move(TrustedImmPtr(address), addrTempRegister);
2251 m_assembler.ldc1(dest, addrTempRegister, 0);
2252 #endif
2253 }
2254
2255 void storeFloat(FPRegisterID src, BaseIndex address)
2256 {
2257 if (address.offset >= -32768 && address.offset <= 32767
2258 && !m_fixedWidth) {
2259 /*
2260 sll addrTemp, address.index, address.scale
2261 addu addrTemp, addrTemp, address.base
2262 swc1 src, address.offset(addrTemp)
2263 */
2264 m_assembler.sll(addrTempRegister, address.index, address.scale);
2265 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
2266 m_assembler.swc1(src, addrTempRegister, address.offset);
2267 } else {
2268 /*
2269 sll addrTemp, address.index, address.scale
2270 addu addrTemp, addrTemp, address.base
2271 lui immTemp, (address.offset + 0x8000) >> 16
2272 addu addrTemp, addrTemp, immTemp
2273 swc1 src, (address.offset & 0xffff)(at)
2274 */
2275 m_assembler.sll(addrTempRegister, address.index, address.scale);
2276 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
2277 m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16);
2278 m_assembler.addu(addrTempRegister, addrTempRegister, immTempRegister);
2279 m_assembler.swc1(src, addrTempRegister, address.offset);
2280 }
2281 }
2282
2283 void storeDouble(FPRegisterID src, ImplicitAddress address)
2284 {
2285 #if WTF_MIPS_ISA(1)
2286 /*
2287 li addrTemp, address.offset
2288 addu addrTemp, addrTemp, base
2289 swc1 dest, 0(addrTemp)
2290 swc1 dest+1, 4(addrTemp)
2291 */
2292 move(TrustedImm32(address.offset), addrTempRegister);
2293 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
2294 m_assembler.swc1(src, addrTempRegister, 0);
2295 m_assembler.swc1(FPRegisterID(src + 1), addrTempRegister, 4);
2296 #else
2297 if (address.offset >= -32768 && address.offset <= 32767
2298 && !m_fixedWidth)
2299 m_assembler.sdc1(src, address.base, address.offset);
2300 else {
2301 /*
2302 lui addrTemp, (offset + 0x8000) >> 16
2303 addu addrTemp, addrTemp, base
2304 sdc1 src, (offset & 0xffff)(addrTemp)
2305 */
2306 m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16);
2307 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
2308 m_assembler.sdc1(src, addrTempRegister, address.offset);
2309 }
2310 #endif
2311 }
2312
2313 void storeDouble(FPRegisterID src, BaseIndex address)
2314 {
2315 #if WTF_MIPS_ISA(1)
2316 if (address.offset >= -32768 && address.offset <= 32767
2317 && !m_fixedWidth) {
2318 /*
2319 sll addrTemp, address.index, address.scale
2320 addu addrTemp, addrTemp, address.base
2321 swc1 src, address.offset(addrTemp)
2322 swc1 src+1, (address.offset + 4)(addrTemp)
2323 */
2324 m_assembler.sll(addrTempRegister, address.index, address.scale);
2325 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
2326 m_assembler.swc1(src, addrTempRegister, address.offset);
2327 m_assembler.swc1(FPRegisterID(src + 1), addrTempRegister, address.offset + 4);
2328 } else {
2329 /*
2330 sll addrTemp, address.index, address.scale
2331 addu addrTemp, addrTemp, address.base
2332 lui immTemp, (address.offset + 0x8000) >> 16
2333 addu addrTemp, addrTemp, immTemp
2334 swc1 src, (address.offset & 0xffff)(at)
2335 swc1 src+1, (address.offset & 0xffff + 4)(at)
2336 */
2337 m_assembler.sll(addrTempRegister, address.index, address.scale);
2338 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
2339 m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16);
2340 m_assembler.addu(addrTempRegister, addrTempRegister, immTempRegister);
2341 m_assembler.swc1(src, addrTempRegister, address.offset);
2342 m_assembler.swc1(FPRegisterID(src + 1), addrTempRegister, address.offset + 4);
2343 }
2344 #else
2345 if (address.offset >= -32768 && address.offset <= 32767
2346 && !m_fixedWidth) {
2347 /*
2348 sll addrTemp, address.index, address.scale
2349 addu addrTemp, addrTemp, address.base
2350 sdc1 src, address.offset(addrTemp)
2351 */
2352 m_assembler.sll(addrTempRegister, address.index, address.scale);
2353 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
2354 m_assembler.sdc1(src, addrTempRegister, address.offset);
2355 } else {
2356 /*
2357 sll addrTemp, address.index, address.scale
2358 addu addrTemp, addrTemp, address.base
2359 lui immTemp, (address.offset + 0x8000) >> 16
2360 addu addrTemp, addrTemp, immTemp
2361 sdc1 src, (address.offset & 0xffff)(at)
2362 */
2363 m_assembler.sll(addrTempRegister, address.index, address.scale);
2364 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
2365 m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16);
2366 m_assembler.addu(addrTempRegister, addrTempRegister, immTempRegister);
2367 m_assembler.sdc1(src, addrTempRegister, address.offset);
2368 }
2369 #endif
2370 }
2371
2372 void storeDouble(FPRegisterID src, const void* address)
2373 {
2374 #if WTF_MIPS_ISA(1)
2375 move(TrustedImmPtr(address), addrTempRegister);
2376 m_assembler.swc1(src, addrTempRegister, 0);
2377 m_assembler.swc1(FPRegisterID(src + 1), addrTempRegister, 4);
2378 #else
2379 move(TrustedImmPtr(address), addrTempRegister);
2380 m_assembler.sdc1(src, addrTempRegister, 0);
2381 #endif
2382 }
2383
2384 void moveDouble(FPRegisterID src, FPRegisterID dest)
2385 {
2386 if (src != dest || m_fixedWidth)
2387 m_assembler.movd(dest, src);
2388 }
2389
2390 void swapDouble(FPRegisterID fr1, FPRegisterID fr2)
2391 {
2392 moveDouble(fr1, fpTempRegister);
2393 moveDouble(fr2, fr1);
2394 moveDouble(fpTempRegister, fr2);
2395 }
2396
2397 void addDouble(FPRegisterID src, FPRegisterID dest)
2398 {
2399 m_assembler.addd(dest, dest, src);
2400 }
2401
2402 void addDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
2403 {
2404 m_assembler.addd(dest, op1, op2);
2405 }
2406
2407 void addDouble(Address src, FPRegisterID dest)
2408 {
2409 loadDouble(src, fpTempRegister);
2410 m_assembler.addd(dest, dest, fpTempRegister);
2411 }
2412
2413 void addDouble(AbsoluteAddress address, FPRegisterID dest)
2414 {
2415 loadDouble(address.m_ptr, fpTempRegister);
2416 m_assembler.addd(dest, dest, fpTempRegister);
2417 }
2418
2419 void subDouble(FPRegisterID src, FPRegisterID dest)
2420 {
2421 m_assembler.subd(dest, dest, src);
2422 }
2423
2424 void subDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
2425 {
2426 m_assembler.subd(dest, op1, op2);
2427 }
2428
2429 void subDouble(Address src, FPRegisterID dest)
2430 {
2431 loadDouble(src, fpTempRegister);
2432 m_assembler.subd(dest, dest, fpTempRegister);
2433 }
2434
2435 void mulDouble(FPRegisterID src, FPRegisterID dest)
2436 {
2437 m_assembler.muld(dest, dest, src);
2438 }
2439
2440 void mulDouble(Address src, FPRegisterID dest)
2441 {
2442 loadDouble(src, fpTempRegister);
2443 m_assembler.muld(dest, dest, fpTempRegister);
2444 }
2445
2446 void mulDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
2447 {
2448 m_assembler.muld(dest, op1, op2);
2449 }
2450
2451 void divDouble(FPRegisterID src, FPRegisterID dest)
2452 {
2453 m_assembler.divd(dest, dest, src);
2454 }
2455
2456 void divDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
2457 {
2458 m_assembler.divd(dest, op1, op2);
2459 }
2460
2461 void divDouble(Address src, FPRegisterID dest)
2462 {
2463 loadDouble(src, fpTempRegister);
2464 m_assembler.divd(dest, dest, fpTempRegister);
2465 }
2466
2467 void negateDouble(FPRegisterID src, FPRegisterID dest)
2468 {
2469 m_assembler.negd(dest, src);
2470 }
2471
2472 void convertInt32ToDouble(RegisterID src, FPRegisterID dest)
2473 {
2474 m_assembler.mtc1(src, fpTempRegister);
2475 m_assembler.cvtdw(dest, fpTempRegister);
2476 }
2477
2478 void convertInt32ToDouble(Address src, FPRegisterID dest)
2479 {
2480 load32(src, dataTempRegister);
2481 m_assembler.mtc1(dataTempRegister, fpTempRegister);
2482 m_assembler.cvtdw(dest, fpTempRegister);
2483 }
2484
2485 void convertInt32ToDouble(AbsoluteAddress src, FPRegisterID dest)
2486 {
2487 load32(src.m_ptr, dataTempRegister);
2488 m_assembler.mtc1(dataTempRegister, fpTempRegister);
2489 m_assembler.cvtdw(dest, fpTempRegister);
2490 }
2491
2492 void convertFloatToDouble(FPRegisterID src, FPRegisterID dst)
2493 {
2494 m_assembler.cvtds(dst, src);
2495 }
2496
2497 void convertDoubleToFloat(FPRegisterID src, FPRegisterID dst)
2498 {
2499 m_assembler.cvtsd(dst, src);
2500 }
2501
2502 void insertRelaxationWords()
2503 {
2504 /* We need four words for relaxation. */
2505 m_assembler.beq(MIPSRegisters::zero, MIPSRegisters::zero, 3); // Jump over nops;
2506 m_assembler.nop();
2507 m_assembler.nop();
2508 m_assembler.nop();
2509 }
2510
2511 Jump branchTrue()
2512 {
2513 m_assembler.appendJump();
2514 m_assembler.bc1t();
2515 m_assembler.nop();
2516 insertRelaxationWords();
2517 return Jump(m_assembler.label());
2518 }
2519
2520 Jump branchFalse()
2521 {
2522 m_assembler.appendJump();
2523 m_assembler.bc1f();
2524 m_assembler.nop();
2525 insertRelaxationWords();
2526 return Jump(m_assembler.label());
2527 }
2528
2529 Jump branchEqual(RegisterID rs, RegisterID rt)
2530 {
2531 m_assembler.nop();
2532 m_assembler.nop();
2533 m_assembler.appendJump();
2534 m_assembler.beq(rs, rt, 0);
2535 m_assembler.nop();
2536 insertRelaxationWords();
2537 return Jump(m_assembler.label());
2538 }
2539
2540 Jump branchNotEqual(RegisterID rs, RegisterID rt)
2541 {
2542 m_assembler.nop();
2543 m_assembler.nop();
2544 m_assembler.appendJump();
2545 m_assembler.bne(rs, rt, 0);
2546 m_assembler.nop();
2547 insertRelaxationWords();
2548 return Jump(m_assembler.label());
2549 }
2550
2551 Jump branchDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right)
2552 {
2553 if (cond == DoubleEqual) {
2554 m_assembler.ceqd(left, right);
2555 return branchTrue();
2556 }
2557 if (cond == DoubleNotEqual) {
2558 m_assembler.cueqd(left, right);
2559 return branchFalse(); // false
2560 }
2561 if (cond == DoubleGreaterThan) {
2562 m_assembler.cngtd(left, right);
2563 return branchFalse(); // false
2564 }
2565 if (cond == DoubleGreaterThanOrEqual) {
2566 m_assembler.cnged(left, right);
2567 return branchFalse(); // false
2568 }
2569 if (cond == DoubleLessThan) {
2570 m_assembler.cltd(left, right);
2571 return branchTrue();
2572 }
2573 if (cond == DoubleLessThanOrEqual) {
2574 m_assembler.cled(left, right);
2575 return branchTrue();
2576 }
2577 if (cond == DoubleEqualOrUnordered) {
2578 m_assembler.cueqd(left, right);
2579 return branchTrue();
2580 }
2581 if (cond == DoubleNotEqualOrUnordered) {
2582 m_assembler.ceqd(left, right);
2583 return branchFalse(); // false
2584 }
2585 if (cond == DoubleGreaterThanOrUnordered) {
2586 m_assembler.coled(left, right);
2587 return branchFalse(); // false
2588 }
2589 if (cond == DoubleGreaterThanOrEqualOrUnordered) {
2590 m_assembler.coltd(left, right);
2591 return branchFalse(); // false
2592 }
2593 if (cond == DoubleLessThanOrUnordered) {
2594 m_assembler.cultd(left, right);
2595 return branchTrue();
2596 }
2597 if (cond == DoubleLessThanOrEqualOrUnordered) {
2598 m_assembler.culed(left, right);
2599 return branchTrue();
2600 }
2601 ASSERT(0);
2602
2603 return Jump();
2604 }
2605
2606 // Truncates 'src' to an integer, and places the resulting 'dest'.
2607 // If the result is not representable as a 32 bit value, branch.
2608 // May also branch for some values that are representable in 32 bits
2609 // (specifically, in this case, INT_MAX 0x7fffffff).
2610 enum BranchTruncateType { BranchIfTruncateFailed, BranchIfTruncateSuccessful };
2611 Jump branchTruncateDoubleToInt32(FPRegisterID src, RegisterID dest, BranchTruncateType branchType = BranchIfTruncateFailed)
2612 {
2613 m_assembler.truncwd(fpTempRegister, src);
2614 m_assembler.mfc1(dest, fpTempRegister);
2615 return branch32(branchType == BranchIfTruncateFailed ? Equal : NotEqual, dest, TrustedImm32(0x7fffffff));
2616 }
2617
2618 Jump branchTruncateDoubleToUint32(FPRegisterID src, RegisterID dest, BranchTruncateType branchType = BranchIfTruncateFailed)
2619 {
2620 m_assembler.truncwd(fpTempRegister, src);
2621 m_assembler.mfc1(dest, fpTempRegister);
2622 return branch32(branchType == BranchIfTruncateFailed ? Equal : NotEqual, dest, TrustedImm32(0));
2623 }
2624
2625 // Result is undefined if the value is outside of the integer range.
2626 void truncateDoubleToInt32(FPRegisterID src, RegisterID dest)
2627 {
2628 m_assembler.truncwd(fpTempRegister, src);
2629 m_assembler.mfc1(dest, fpTempRegister);
2630 }
2631
2632 // Result is undefined if src > 2^31
2633 void truncateDoubleToUint32(FPRegisterID src, RegisterID dest)
2634 {
2635 m_assembler.truncwd(fpTempRegister, src);
2636 m_assembler.mfc1(dest, fpTempRegister);
2637 }
2638
2639 // Convert 'src' to an integer, and places the resulting 'dest'.
2640 // If the result is not representable as a 32 bit value, branch.
2641 // May also branch for some values that are representable in 32 bits
2642 // (specifically, in this case, 0).
2643 void branchConvertDoubleToInt32(FPRegisterID src, RegisterID dest, JumpList& failureCases, FPRegisterID fpTemp, bool negZeroCheck = true)
2644 {
2645 m_assembler.cvtwd(fpTempRegister, src);
2646 m_assembler.mfc1(dest, fpTempRegister);
2647
2648 // If the result is zero, it might have been -0.0, and the double comparison won't catch this!
2649 if (negZeroCheck)
2650 failureCases.append(branch32(Equal, dest, MIPSRegisters::zero));
2651
2652 // Convert the integer result back to float & compare to the original value - if not equal or unordered (NaN) then jump.
2653 convertInt32ToDouble(dest, fpTemp);
2654 failureCases.append(branchDouble(DoubleNotEqualOrUnordered, fpTemp, src));
2655 }
2656
2657 Jump branchDoubleNonZero(FPRegisterID reg, FPRegisterID scratch)
2658 {
2659 m_assembler.vmov(scratch, MIPSRegisters::zero, MIPSRegisters::zero);
2660 return branchDouble(DoubleNotEqual, reg, scratch);
2661 }
2662
2663 Jump branchDoubleZeroOrNaN(FPRegisterID reg, FPRegisterID scratch)
2664 {
2665 m_assembler.vmov(scratch, MIPSRegisters::zero, MIPSRegisters::zero);
2666 return branchDouble(DoubleEqualOrUnordered, reg, scratch);
2667 }
2668
2669 // Invert a relational condition, e.g. == becomes !=, < becomes >=, etc.
2670 static RelationalCondition invert(RelationalCondition cond)
2671 {
2672 RelationalCondition r;
2673 if (cond == Equal)
2674 r = NotEqual;
2675 else if (cond == NotEqual)
2676 r = Equal;
2677 else if (cond == Above)
2678 r = BelowOrEqual;
2679 else if (cond == AboveOrEqual)
2680 r = Below;
2681 else if (cond == Below)
2682 r = AboveOrEqual;
2683 else if (cond == BelowOrEqual)
2684 r = Above;
2685 else if (cond == GreaterThan)
2686 r = LessThanOrEqual;
2687 else if (cond == GreaterThanOrEqual)
2688 r = LessThan;
2689 else if (cond == LessThan)
2690 r = GreaterThanOrEqual;
2691 else if (cond == LessThanOrEqual)
2692 r = GreaterThan;
2693 return r;
2694 }
2695
2696 void nop()
2697 {
2698 m_assembler.nop();
2699 }
2700
2701 static FunctionPtr readCallTarget(CodeLocationCall call)
2702 {
2703 return FunctionPtr(reinterpret_cast<void(*)()>(MIPSAssembler::readCallTarget(call.dataLocation())));
2704 }
2705
2706 static void replaceWithJump(CodeLocationLabel instructionStart, CodeLocationLabel destination)
2707 {
2708 MIPSAssembler::replaceWithJump(instructionStart.dataLocation(), destination.dataLocation());
2709 }
2710
2711 static ptrdiff_t maxJumpReplacementSize()
2712 {
2713 MIPSAssembler::maxJumpReplacementSize();
2714 return 0;
2715 }
2716
2717 static bool canJumpReplacePatchableBranchPtrWithPatch() { return false; }
2718
2719 static CodeLocationLabel startOfBranchPtrWithPatchOnRegister(CodeLocationDataLabelPtr label)
2720 {
2721 return label.labelAtOffset(0);
2722 }
2723
2724 static void revertJumpReplacementToBranchPtrWithPatch(CodeLocationLabel instructionStart, RegisterID, void* initialValue)
2725 {
2726 MIPSAssembler::revertJumpToMove(instructionStart.dataLocation(), immTempRegister, reinterpret_cast<int>(initialValue) & 0xffff);
2727 }
2728
2729 static CodeLocationLabel startOfPatchableBranchPtrWithPatchOnAddress(CodeLocationDataLabelPtr)
2730 {
2731 UNREACHABLE_FOR_PLATFORM();
2732 return CodeLocationLabel();
2733 }
2734
2735 static void revertJumpReplacementToPatchableBranchPtrWithPatch(CodeLocationLabel instructionStart, Address, void* initialValue)
2736 {
2737 UNREACHABLE_FOR_PLATFORM();
2738 }
2739
2740
2741 private:
2742 // If m_fixedWidth is true, we will generate a fixed number of instructions.
2743 // Otherwise, we can emit any number of instructions.
2744 bool m_fixedWidth;
2745
2746 friend class LinkBuffer;
2747 friend class RepatchBuffer;
2748
2749 static void linkCall(void* code, Call call, FunctionPtr function)
2750 {
2751 MIPSAssembler::linkCall(code, call.m_label, function.value());
2752 }
2753
2754 static void repatchCall(CodeLocationCall call, CodeLocationLabel destination)
2755 {
2756 MIPSAssembler::relinkCall(call.dataLocation(), destination.executableAddress());
2757 }
2758
2759 static void repatchCall(CodeLocationCall call, FunctionPtr destination)
2760 {
2761 MIPSAssembler::relinkCall(call.dataLocation(), destination.executableAddress());
2762 }
2763
2764 };
2765
2766 }
2767
2768 #endif // ENABLE(ASSEMBLER) && CPU(MIPS)
2769
2770 #endif // MacroAssemblerMIPS_h