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