]> git.saurik.com Git - apple/javascriptcore.git/blob - assembler/MacroAssemblerMIPS.h
JavaScriptCore-7601.1.46.3.tar.gz
[apple/javascriptcore.git] / assembler / MacroAssemblerMIPS.h
1 /*
2 * Copyright (C) 2008, 2014 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, MacroAssemblerMIPS> {
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 load8SignedExtendTo32(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 load16SignedExtendTo32(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 Jump branch32WithPatch(RelationalCondition cond, Address left, DataLabel32& dataLabel, TrustedImm32 initialRightValue = TrustedImm32(0))
2124 {
2125 m_fixedWidth = true;
2126 load32(left, dataTempRegister);
2127 dataLabel = moveWithPatch(initialRightValue, immTempRegister);
2128 Jump temp = branch32(cond, dataTempRegister, immTempRegister);
2129 m_fixedWidth = false;
2130 return temp;
2131 }
2132
2133 DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address)
2134 {
2135 m_fixedWidth = true;
2136 DataLabelPtr dataLabel = moveWithPatch(initialValue, dataTempRegister);
2137 store32(dataTempRegister, address);
2138 m_fixedWidth = false;
2139 return dataLabel;
2140 }
2141
2142 DataLabelPtr storePtrWithPatch(ImplicitAddress address)
2143 {
2144 return storePtrWithPatch(TrustedImmPtr(0), address);
2145 }
2146
2147 Call tailRecursiveCall()
2148 {
2149 // Like a normal call, but don't update the returned address register
2150 m_fixedWidth = true;
2151 move(TrustedImm32(0), MIPSRegisters::t9);
2152 m_assembler.jr(MIPSRegisters::t9);
2153 m_assembler.nop();
2154 m_fixedWidth = false;
2155 return Call(m_assembler.label(), Call::Linkable);
2156 }
2157
2158 Call makeTailRecursiveCall(Jump oldJump)
2159 {
2160 oldJump.link(this);
2161 return tailRecursiveCall();
2162 }
2163
2164 void loadFloat(BaseIndex address, FPRegisterID dest)
2165 {
2166 if (address.offset >= -32768 && address.offset <= 32767
2167 && !m_fixedWidth) {
2168 /*
2169 sll addrTemp, address.index, address.scale
2170 addu addrTemp, addrTemp, address.base
2171 lwc1 dest, address.offset(addrTemp)
2172 */
2173 m_assembler.sll(addrTempRegister, address.index, address.scale);
2174 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
2175 m_assembler.lwc1(dest, addrTempRegister, address.offset);
2176 } else {
2177 /*
2178 sll addrTemp, address.index, address.scale
2179 addu addrTemp, addrTemp, address.base
2180 lui immTemp, (address.offset + 0x8000) >> 16
2181 addu addrTemp, addrTemp, immTemp
2182 lwc1 dest, (address.offset & 0xffff)(at)
2183 */
2184 m_assembler.sll(addrTempRegister, address.index, address.scale);
2185 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
2186 m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16);
2187 m_assembler.addu(addrTempRegister, addrTempRegister, immTempRegister);
2188 m_assembler.lwc1(dest, addrTempRegister, address.offset);
2189 }
2190 }
2191
2192 void loadDouble(ImplicitAddress address, FPRegisterID dest)
2193 {
2194 #if WTF_MIPS_ISA(1)
2195 /*
2196 li addrTemp, address.offset
2197 addu addrTemp, addrTemp, base
2198 lwc1 dest, 0(addrTemp)
2199 lwc1 dest+1, 4(addrTemp)
2200 */
2201 move(TrustedImm32(address.offset), addrTempRegister);
2202 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
2203 m_assembler.lwc1(dest, addrTempRegister, 0);
2204 m_assembler.lwc1(FPRegisterID(dest + 1), addrTempRegister, 4);
2205 #else
2206 if (address.offset >= -32768 && address.offset <= 32767
2207 && !m_fixedWidth) {
2208 m_assembler.ldc1(dest, address.base, address.offset);
2209 } else {
2210 /*
2211 lui addrTemp, (offset + 0x8000) >> 16
2212 addu addrTemp, addrTemp, base
2213 ldc1 dest, (offset & 0xffff)(addrTemp)
2214 */
2215 m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16);
2216 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
2217 m_assembler.ldc1(dest, addrTempRegister, address.offset);
2218 }
2219 #endif
2220 }
2221
2222 void loadDouble(BaseIndex address, FPRegisterID dest)
2223 {
2224 #if WTF_MIPS_ISA(1)
2225 if (address.offset >= -32768 && address.offset <= 32767
2226 && !m_fixedWidth) {
2227 /*
2228 sll addrTemp, address.index, address.scale
2229 addu addrTemp, addrTemp, address.base
2230 lwc1 dest, address.offset(addrTemp)
2231 lwc1 dest+1, (address.offset+4)(addrTemp)
2232 */
2233 m_assembler.sll(addrTempRegister, address.index, address.scale);
2234 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
2235 m_assembler.lwc1(dest, addrTempRegister, address.offset);
2236 m_assembler.lwc1(FPRegisterID(dest + 1), addrTempRegister, address.offset + 4);
2237 } else {
2238 /*
2239 sll addrTemp, address.index, address.scale
2240 addu addrTemp, addrTemp, address.base
2241 lui immTemp, (address.offset + 0x8000) >> 16
2242 addu addrTemp, addrTemp, immTemp
2243 lwc1 dest, (address.offset & 0xffff)(at)
2244 lwc1 dest+1, (address.offset & 0xffff + 4)(at)
2245 */
2246 m_assembler.sll(addrTempRegister, address.index, address.scale);
2247 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
2248 m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16);
2249 m_assembler.addu(addrTempRegister, addrTempRegister, immTempRegister);
2250 m_assembler.lwc1(dest, addrTempRegister, address.offset);
2251 m_assembler.lwc1(FPRegisterID(dest + 1), addrTempRegister, address.offset + 4);
2252 }
2253 #else
2254 if (address.offset >= -32768 && address.offset <= 32767
2255 && !m_fixedWidth) {
2256 /*
2257 sll addrTemp, address.index, address.scale
2258 addu addrTemp, addrTemp, address.base
2259 ldc1 dest, address.offset(addrTemp)
2260 */
2261 m_assembler.sll(addrTempRegister, address.index, address.scale);
2262 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
2263 m_assembler.ldc1(dest, addrTempRegister, address.offset);
2264 } else {
2265 /*
2266 sll addrTemp, address.index, address.scale
2267 addu addrTemp, addrTemp, address.base
2268 lui immTemp, (address.offset + 0x8000) >> 16
2269 addu addrTemp, addrTemp, immTemp
2270 ldc1 dest, (address.offset & 0xffff)(at)
2271 */
2272 m_assembler.sll(addrTempRegister, address.index, address.scale);
2273 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
2274 m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16);
2275 m_assembler.addu(addrTempRegister, addrTempRegister, immTempRegister);
2276 m_assembler.ldc1(dest, addrTempRegister, address.offset);
2277 }
2278 #endif
2279 }
2280
2281 void loadDouble(TrustedImmPtr address, FPRegisterID dest)
2282 {
2283 #if WTF_MIPS_ISA(1)
2284 /*
2285 li addrTemp, address
2286 lwc1 dest, 0(addrTemp)
2287 lwc1 dest+1, 4(addrTemp)
2288 */
2289 move(address, addrTempRegister);
2290 m_assembler.lwc1(dest, addrTempRegister, 0);
2291 m_assembler.lwc1(FPRegisterID(dest + 1), addrTempRegister, 4);
2292 #else
2293 /*
2294 li addrTemp, address
2295 ldc1 dest, 0(addrTemp)
2296 */
2297 move(address, addrTempRegister);
2298 m_assembler.ldc1(dest, addrTempRegister, 0);
2299 #endif
2300 }
2301
2302 void storeFloat(FPRegisterID src, BaseIndex address)
2303 {
2304 if (address.offset >= -32768 && address.offset <= 32767
2305 && !m_fixedWidth) {
2306 /*
2307 sll addrTemp, address.index, address.scale
2308 addu addrTemp, addrTemp, address.base
2309 swc1 src, address.offset(addrTemp)
2310 */
2311 m_assembler.sll(addrTempRegister, address.index, address.scale);
2312 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
2313 m_assembler.swc1(src, addrTempRegister, address.offset);
2314 } else {
2315 /*
2316 sll addrTemp, address.index, address.scale
2317 addu addrTemp, addrTemp, address.base
2318 lui immTemp, (address.offset + 0x8000) >> 16
2319 addu addrTemp, addrTemp, immTemp
2320 swc1 src, (address.offset & 0xffff)(at)
2321 */
2322 m_assembler.sll(addrTempRegister, address.index, address.scale);
2323 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
2324 m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16);
2325 m_assembler.addu(addrTempRegister, addrTempRegister, immTempRegister);
2326 m_assembler.swc1(src, addrTempRegister, address.offset);
2327 }
2328 }
2329
2330 void storeDouble(FPRegisterID src, ImplicitAddress address)
2331 {
2332 #if WTF_MIPS_ISA(1)
2333 /*
2334 li addrTemp, address.offset
2335 addu addrTemp, addrTemp, base
2336 swc1 dest, 0(addrTemp)
2337 swc1 dest+1, 4(addrTemp)
2338 */
2339 move(TrustedImm32(address.offset), addrTempRegister);
2340 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
2341 m_assembler.swc1(src, addrTempRegister, 0);
2342 m_assembler.swc1(FPRegisterID(src + 1), addrTempRegister, 4);
2343 #else
2344 if (address.offset >= -32768 && address.offset <= 32767
2345 && !m_fixedWidth)
2346 m_assembler.sdc1(src, address.base, address.offset);
2347 else {
2348 /*
2349 lui addrTemp, (offset + 0x8000) >> 16
2350 addu addrTemp, addrTemp, base
2351 sdc1 src, (offset & 0xffff)(addrTemp)
2352 */
2353 m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16);
2354 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
2355 m_assembler.sdc1(src, addrTempRegister, address.offset);
2356 }
2357 #endif
2358 }
2359
2360 void storeDouble(FPRegisterID src, BaseIndex address)
2361 {
2362 #if WTF_MIPS_ISA(1)
2363 if (address.offset >= -32768 && address.offset <= 32767
2364 && !m_fixedWidth) {
2365 /*
2366 sll addrTemp, address.index, address.scale
2367 addu addrTemp, addrTemp, address.base
2368 swc1 src, address.offset(addrTemp)
2369 swc1 src+1, (address.offset + 4)(addrTemp)
2370 */
2371 m_assembler.sll(addrTempRegister, address.index, address.scale);
2372 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
2373 m_assembler.swc1(src, addrTempRegister, address.offset);
2374 m_assembler.swc1(FPRegisterID(src + 1), addrTempRegister, address.offset + 4);
2375 } else {
2376 /*
2377 sll addrTemp, address.index, address.scale
2378 addu addrTemp, addrTemp, address.base
2379 lui immTemp, (address.offset + 0x8000) >> 16
2380 addu addrTemp, addrTemp, immTemp
2381 swc1 src, (address.offset & 0xffff)(at)
2382 swc1 src+1, (address.offset & 0xffff + 4)(at)
2383 */
2384 m_assembler.sll(addrTempRegister, address.index, address.scale);
2385 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
2386 m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16);
2387 m_assembler.addu(addrTempRegister, addrTempRegister, immTempRegister);
2388 m_assembler.swc1(src, addrTempRegister, address.offset);
2389 m_assembler.swc1(FPRegisterID(src + 1), addrTempRegister, address.offset + 4);
2390 }
2391 #else
2392 if (address.offset >= -32768 && address.offset <= 32767
2393 && !m_fixedWidth) {
2394 /*
2395 sll addrTemp, address.index, address.scale
2396 addu addrTemp, addrTemp, address.base
2397 sdc1 src, address.offset(addrTemp)
2398 */
2399 m_assembler.sll(addrTempRegister, address.index, address.scale);
2400 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
2401 m_assembler.sdc1(src, addrTempRegister, address.offset);
2402 } else {
2403 /*
2404 sll addrTemp, address.index, address.scale
2405 addu addrTemp, addrTemp, address.base
2406 lui immTemp, (address.offset + 0x8000) >> 16
2407 addu addrTemp, addrTemp, immTemp
2408 sdc1 src, (address.offset & 0xffff)(at)
2409 */
2410 m_assembler.sll(addrTempRegister, address.index, address.scale);
2411 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
2412 m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16);
2413 m_assembler.addu(addrTempRegister, addrTempRegister, immTempRegister);
2414 m_assembler.sdc1(src, addrTempRegister, address.offset);
2415 }
2416 #endif
2417 }
2418
2419 void storeDouble(FPRegisterID src, TrustedImmPtr address)
2420 {
2421 #if WTF_MIPS_ISA(1)
2422 move(address, addrTempRegister);
2423 m_assembler.swc1(src, addrTempRegister, 0);
2424 m_assembler.swc1(FPRegisterID(src + 1), addrTempRegister, 4);
2425 #else
2426 move(address, addrTempRegister);
2427 m_assembler.sdc1(src, addrTempRegister, 0);
2428 #endif
2429 }
2430
2431 void moveDouble(FPRegisterID src, FPRegisterID dest)
2432 {
2433 if (src != dest || m_fixedWidth)
2434 m_assembler.movd(dest, src);
2435 }
2436
2437 void swapDouble(FPRegisterID fr1, FPRegisterID fr2)
2438 {
2439 moveDouble(fr1, fpTempRegister);
2440 moveDouble(fr2, fr1);
2441 moveDouble(fpTempRegister, fr2);
2442 }
2443
2444 void addDouble(FPRegisterID src, FPRegisterID dest)
2445 {
2446 m_assembler.addd(dest, dest, src);
2447 }
2448
2449 void addDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
2450 {
2451 m_assembler.addd(dest, op1, op2);
2452 }
2453
2454 void addDouble(Address src, FPRegisterID dest)
2455 {
2456 loadDouble(src, fpTempRegister);
2457 m_assembler.addd(dest, dest, fpTempRegister);
2458 }
2459
2460 void addDouble(AbsoluteAddress address, FPRegisterID dest)
2461 {
2462 loadDouble(TrustedImmPtr(address.m_ptr), fpTempRegister);
2463 m_assembler.addd(dest, dest, fpTempRegister);
2464 }
2465
2466 void subDouble(FPRegisterID src, FPRegisterID dest)
2467 {
2468 m_assembler.subd(dest, dest, src);
2469 }
2470
2471 void subDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
2472 {
2473 m_assembler.subd(dest, op1, op2);
2474 }
2475
2476 void subDouble(Address src, FPRegisterID dest)
2477 {
2478 loadDouble(src, fpTempRegister);
2479 m_assembler.subd(dest, dest, fpTempRegister);
2480 }
2481
2482 void mulDouble(FPRegisterID src, FPRegisterID dest)
2483 {
2484 m_assembler.muld(dest, dest, src);
2485 }
2486
2487 void mulDouble(Address src, FPRegisterID dest)
2488 {
2489 loadDouble(src, fpTempRegister);
2490 m_assembler.muld(dest, dest, fpTempRegister);
2491 }
2492
2493 void mulDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
2494 {
2495 m_assembler.muld(dest, op1, op2);
2496 }
2497
2498 void divDouble(FPRegisterID src, FPRegisterID dest)
2499 {
2500 m_assembler.divd(dest, dest, src);
2501 }
2502
2503 void divDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
2504 {
2505 m_assembler.divd(dest, op1, op2);
2506 }
2507
2508 void divDouble(Address src, FPRegisterID dest)
2509 {
2510 loadDouble(src, fpTempRegister);
2511 m_assembler.divd(dest, dest, fpTempRegister);
2512 }
2513
2514 void negateDouble(FPRegisterID src, FPRegisterID dest)
2515 {
2516 m_assembler.negd(dest, src);
2517 }
2518
2519 void convertInt32ToDouble(RegisterID src, FPRegisterID dest)
2520 {
2521 m_assembler.mtc1(src, fpTempRegister);
2522 m_assembler.cvtdw(dest, fpTempRegister);
2523 }
2524
2525 void convertInt32ToDouble(Address src, FPRegisterID dest)
2526 {
2527 load32(src, dataTempRegister);
2528 m_assembler.mtc1(dataTempRegister, fpTempRegister);
2529 m_assembler.cvtdw(dest, fpTempRegister);
2530 }
2531
2532 void convertInt32ToDouble(AbsoluteAddress src, FPRegisterID dest)
2533 {
2534 load32(src.m_ptr, dataTempRegister);
2535 m_assembler.mtc1(dataTempRegister, fpTempRegister);
2536 m_assembler.cvtdw(dest, fpTempRegister);
2537 }
2538
2539 void convertFloatToDouble(FPRegisterID src, FPRegisterID dst)
2540 {
2541 m_assembler.cvtds(dst, src);
2542 }
2543
2544 void convertDoubleToFloat(FPRegisterID src, FPRegisterID dst)
2545 {
2546 m_assembler.cvtsd(dst, src);
2547 }
2548
2549 void insertRelaxationWords()
2550 {
2551 /* We need four words for relaxation. */
2552 m_assembler.beq(MIPSRegisters::zero, MIPSRegisters::zero, 3); // Jump over nops;
2553 m_assembler.nop();
2554 m_assembler.nop();
2555 m_assembler.nop();
2556 }
2557
2558 Jump branchTrue()
2559 {
2560 m_assembler.appendJump();
2561 m_assembler.bc1t();
2562 m_assembler.nop();
2563 insertRelaxationWords();
2564 return Jump(m_assembler.label());
2565 }
2566
2567 Jump branchFalse()
2568 {
2569 m_assembler.appendJump();
2570 m_assembler.bc1f();
2571 m_assembler.nop();
2572 insertRelaxationWords();
2573 return Jump(m_assembler.label());
2574 }
2575
2576 Jump branchEqual(RegisterID rs, RegisterID rt)
2577 {
2578 m_assembler.nop();
2579 m_assembler.nop();
2580 m_assembler.appendJump();
2581 m_assembler.beq(rs, rt, 0);
2582 m_assembler.nop();
2583 insertRelaxationWords();
2584 return Jump(m_assembler.label());
2585 }
2586
2587 Jump branchNotEqual(RegisterID rs, RegisterID rt)
2588 {
2589 m_assembler.nop();
2590 m_assembler.nop();
2591 m_assembler.appendJump();
2592 m_assembler.bne(rs, rt, 0);
2593 m_assembler.nop();
2594 insertRelaxationWords();
2595 return Jump(m_assembler.label());
2596 }
2597
2598 Jump branchDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right)
2599 {
2600 if (cond == DoubleEqual) {
2601 m_assembler.ceqd(left, right);
2602 return branchTrue();
2603 }
2604 if (cond == DoubleNotEqual) {
2605 m_assembler.cueqd(left, right);
2606 return branchFalse(); // false
2607 }
2608 if (cond == DoubleGreaterThan) {
2609 m_assembler.cngtd(left, right);
2610 return branchFalse(); // false
2611 }
2612 if (cond == DoubleGreaterThanOrEqual) {
2613 m_assembler.cnged(left, right);
2614 return branchFalse(); // false
2615 }
2616 if (cond == DoubleLessThan) {
2617 m_assembler.cltd(left, right);
2618 return branchTrue();
2619 }
2620 if (cond == DoubleLessThanOrEqual) {
2621 m_assembler.cled(left, right);
2622 return branchTrue();
2623 }
2624 if (cond == DoubleEqualOrUnordered) {
2625 m_assembler.cueqd(left, right);
2626 return branchTrue();
2627 }
2628 if (cond == DoubleNotEqualOrUnordered) {
2629 m_assembler.ceqd(left, right);
2630 return branchFalse(); // false
2631 }
2632 if (cond == DoubleGreaterThanOrUnordered) {
2633 m_assembler.coled(left, right);
2634 return branchFalse(); // false
2635 }
2636 if (cond == DoubleGreaterThanOrEqualOrUnordered) {
2637 m_assembler.coltd(left, right);
2638 return branchFalse(); // false
2639 }
2640 if (cond == DoubleLessThanOrUnordered) {
2641 m_assembler.cultd(left, right);
2642 return branchTrue();
2643 }
2644 if (cond == DoubleLessThanOrEqualOrUnordered) {
2645 m_assembler.culed(left, right);
2646 return branchTrue();
2647 }
2648 ASSERT(0);
2649
2650 return Jump();
2651 }
2652
2653 // Truncates 'src' to an integer, and places the resulting 'dest'.
2654 // If the result is not representable as a 32 bit value, branch.
2655 // May also branch for some values that are representable in 32 bits
2656 // (specifically, in this case, INT_MAX 0x7fffffff).
2657 enum BranchTruncateType { BranchIfTruncateFailed, BranchIfTruncateSuccessful };
2658 Jump branchTruncateDoubleToInt32(FPRegisterID src, RegisterID dest, BranchTruncateType branchType = BranchIfTruncateFailed)
2659 {
2660 m_assembler.truncwd(fpTempRegister, src);
2661 m_assembler.mfc1(dest, fpTempRegister);
2662 return branch32(branchType == BranchIfTruncateFailed ? Equal : NotEqual, dest, TrustedImm32(0x7fffffff));
2663 }
2664
2665 Jump branchTruncateDoubleToUint32(FPRegisterID src, RegisterID dest, BranchTruncateType branchType = BranchIfTruncateFailed)
2666 {
2667 m_assembler.truncwd(fpTempRegister, src);
2668 m_assembler.mfc1(dest, fpTempRegister);
2669 return branch32(branchType == BranchIfTruncateFailed ? Equal : NotEqual, dest, TrustedImm32(0));
2670 }
2671
2672 // Result is undefined if the value is outside of the integer range.
2673 void truncateDoubleToInt32(FPRegisterID src, RegisterID dest)
2674 {
2675 m_assembler.truncwd(fpTempRegister, src);
2676 m_assembler.mfc1(dest, fpTempRegister);
2677 }
2678
2679 // Result is undefined if src > 2^31
2680 void truncateDoubleToUint32(FPRegisterID src, RegisterID dest)
2681 {
2682 m_assembler.truncwd(fpTempRegister, src);
2683 m_assembler.mfc1(dest, fpTempRegister);
2684 }
2685
2686 // Convert 'src' to an integer, and places the resulting 'dest'.
2687 // If the result is not representable as a 32 bit value, branch.
2688 // May also branch for some values that are representable in 32 bits
2689 // (specifically, in this case, 0).
2690 void branchConvertDoubleToInt32(FPRegisterID src, RegisterID dest, JumpList& failureCases, FPRegisterID fpTemp, bool negZeroCheck = true)
2691 {
2692 m_assembler.cvtwd(fpTempRegister, src);
2693 m_assembler.mfc1(dest, fpTempRegister);
2694
2695 // If the result is zero, it might have been -0.0, and the double comparison won't catch this!
2696 if (negZeroCheck)
2697 failureCases.append(branch32(Equal, dest, MIPSRegisters::zero));
2698
2699 // Convert the integer result back to float & compare to the original value - if not equal or unordered (NaN) then jump.
2700 convertInt32ToDouble(dest, fpTemp);
2701 failureCases.append(branchDouble(DoubleNotEqualOrUnordered, fpTemp, src));
2702 }
2703
2704 Jump branchDoubleNonZero(FPRegisterID reg, FPRegisterID scratch)
2705 {
2706 m_assembler.vmov(scratch, MIPSRegisters::zero, MIPSRegisters::zero);
2707 return branchDouble(DoubleNotEqual, reg, scratch);
2708 }
2709
2710 Jump branchDoubleZeroOrNaN(FPRegisterID reg, FPRegisterID scratch)
2711 {
2712 m_assembler.vmov(scratch, MIPSRegisters::zero, MIPSRegisters::zero);
2713 return branchDouble(DoubleEqualOrUnordered, reg, scratch);
2714 }
2715
2716 // Invert a relational condition, e.g. == becomes !=, < becomes >=, etc.
2717 static RelationalCondition invert(RelationalCondition cond)
2718 {
2719 RelationalCondition r;
2720 if (cond == Equal)
2721 r = NotEqual;
2722 else if (cond == NotEqual)
2723 r = Equal;
2724 else if (cond == Above)
2725 r = BelowOrEqual;
2726 else if (cond == AboveOrEqual)
2727 r = Below;
2728 else if (cond == Below)
2729 r = AboveOrEqual;
2730 else if (cond == BelowOrEqual)
2731 r = Above;
2732 else if (cond == GreaterThan)
2733 r = LessThanOrEqual;
2734 else if (cond == GreaterThanOrEqual)
2735 r = LessThan;
2736 else if (cond == LessThan)
2737 r = GreaterThanOrEqual;
2738 else if (cond == LessThanOrEqual)
2739 r = GreaterThan;
2740 return r;
2741 }
2742
2743 void nop()
2744 {
2745 m_assembler.nop();
2746 }
2747
2748 void memoryFence()
2749 {
2750 m_assembler.sync();
2751 }
2752
2753 static FunctionPtr readCallTarget(CodeLocationCall call)
2754 {
2755 return FunctionPtr(reinterpret_cast<void(*)()>(MIPSAssembler::readCallTarget(call.dataLocation())));
2756 }
2757
2758 static void replaceWithJump(CodeLocationLabel instructionStart, CodeLocationLabel destination)
2759 {
2760 MIPSAssembler::replaceWithJump(instructionStart.dataLocation(), destination.dataLocation());
2761 }
2762
2763 static ptrdiff_t maxJumpReplacementSize()
2764 {
2765 MIPSAssembler::maxJumpReplacementSize();
2766 return 0;
2767 }
2768
2769 static bool canJumpReplacePatchableBranchPtrWithPatch() { return false; }
2770
2771 static CodeLocationLabel startOfBranchPtrWithPatchOnRegister(CodeLocationDataLabelPtr label)
2772 {
2773 return label.labelAtOffset(0);
2774 }
2775
2776 static void revertJumpReplacementToBranchPtrWithPatch(CodeLocationLabel instructionStart, RegisterID, void* initialValue)
2777 {
2778 MIPSAssembler::revertJumpToMove(instructionStart.dataLocation(), immTempRegister, reinterpret_cast<int>(initialValue) & 0xffff);
2779 }
2780
2781 static CodeLocationLabel startOfPatchableBranchPtrWithPatchOnAddress(CodeLocationDataLabelPtr)
2782 {
2783 UNREACHABLE_FOR_PLATFORM();
2784 return CodeLocationLabel();
2785 }
2786
2787 static void revertJumpReplacementToPatchableBranchPtrWithPatch(CodeLocationLabel, Address, void*)
2788 {
2789 UNREACHABLE_FOR_PLATFORM();
2790 }
2791
2792
2793 private:
2794 // If m_fixedWidth is true, we will generate a fixed number of instructions.
2795 // Otherwise, we can emit any number of instructions.
2796 bool m_fixedWidth;
2797
2798 friend class LinkBuffer;
2799 friend class RepatchBuffer;
2800
2801 static void linkCall(void* code, Call call, FunctionPtr function)
2802 {
2803 MIPSAssembler::linkCall(code, call.m_label, function.value());
2804 }
2805
2806 static void repatchCall(CodeLocationCall call, CodeLocationLabel destination)
2807 {
2808 MIPSAssembler::relinkCall(call.dataLocation(), destination.executableAddress());
2809 }
2810
2811 static void repatchCall(CodeLocationCall call, FunctionPtr destination)
2812 {
2813 MIPSAssembler::relinkCall(call.dataLocation(), destination.executableAddress());
2814 }
2815
2816 };
2817
2818 }
2819
2820 #endif // ENABLE(ASSEMBLER) && CPU(MIPS)
2821
2822 #endif // MacroAssemblerMIPS_h