2 * Copyright (C) 2008 Apple Inc. All rights reserved.
3 * Copyright (C) 2010 MIPS Technologies, Inc. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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.
27 #ifndef MacroAssemblerMIPS_h
28 #define MacroAssemblerMIPS_h
30 #if ENABLE(ASSEMBLER) && CPU(MIPS)
32 #include "MIPSAssembler.h"
33 #include "AbstractMacroAssembler.h"
37 class MacroAssemblerMIPS : public AbstractMacroAssembler<MIPSAssembler> {
39 typedef MIPSRegisters::FPRegisterID FPRegisterID;
46 static const Scale ScalePtr = TimesFour;
48 // For storing immediate number
49 static const RegisterID immTempRegister = MIPSRegisters::t0;
50 // For storing data loaded from the memory
51 static const RegisterID dataTempRegister = MIPSRegisters::t1;
52 // For storing address base
53 static const RegisterID addrTempRegister = MIPSRegisters::t2;
54 // For storing compare result
55 static const RegisterID cmpTempRegister = MIPSRegisters::t3;
58 static const FPRegisterID fpTempRegister = MIPSRegisters::f16;
60 static const int MaximumCompactPtrAlignedAddressOffset = 0x7FFFFFFF;
62 enum RelationalCondition {
75 enum ResultCondition {
82 enum DoubleCondition {
86 DoubleGreaterThanOrEqual,
88 DoubleLessThanOrEqual,
89 DoubleEqualOrUnordered,
90 DoubleNotEqualOrUnordered,
91 DoubleGreaterThanOrUnordered,
92 DoubleGreaterThanOrEqualOrUnordered,
93 DoubleLessThanOrUnordered,
94 DoubleLessThanOrEqualOrUnordered
97 static const RegisterID stackPointerRegister = MIPSRegisters::sp;
98 static const RegisterID returnAddressRegister = MIPSRegisters::ra;
100 // Integer arithmetic operations:
102 // Operations are typically two operand - operation(source, srcDst)
103 // For many operations the source may be an TrustedImm32, the srcDst operand
104 // may often be a memory location (explictly described using an Address
107 void add32(RegisterID src, RegisterID dest)
109 m_assembler.addu(dest, dest, src);
112 void add32(TrustedImm32 imm, RegisterID dest)
114 add32(imm, dest, dest);
117 void add32(TrustedImm32 imm, RegisterID src, RegisterID dest)
119 if (!imm.m_isPointer && imm.m_value >= -32768 && imm.m_value <= 32767
124 m_assembler.addiu(dest, src, imm.m_value);
128 addu dest, src, immTemp
130 move(imm, immTempRegister);
131 m_assembler.addu(dest, src, immTempRegister);
135 void add32(TrustedImm32 imm, Address address)
137 if (address.offset >= -32768 && address.offset <= 32767
140 lw dataTemp, offset(base)
142 addu dataTemp, dataTemp, immTemp
143 sw dataTemp, offset(base)
145 m_assembler.lw(dataTempRegister, address.base, address.offset);
147 && imm.m_value >= -32768 && imm.m_value <= 32767
149 m_assembler.addiu(dataTempRegister, dataTempRegister,
152 move(imm, immTempRegister);
153 m_assembler.addu(dataTempRegister, dataTempRegister,
156 m_assembler.sw(dataTempRegister, address.base, address.offset);
159 lui addrTemp, (offset + 0x8000) >> 16
160 addu addrTemp, addrTemp, base
161 lw dataTemp, (offset & 0xffff)(addrTemp)
163 addu dataTemp, dataTemp, immTemp
164 sw dataTemp, (offset & 0xffff)(addrTemp)
166 m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16);
167 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
168 m_assembler.lw(dataTempRegister, addrTempRegister, address.offset);
170 if (imm.m_value >= -32768 && imm.m_value <= 32767 && !m_fixedWidth)
171 m_assembler.addiu(dataTempRegister, dataTempRegister,
174 move(imm, immTempRegister);
175 m_assembler.addu(dataTempRegister, dataTempRegister,
178 m_assembler.sw(dataTempRegister, addrTempRegister, address.offset);
182 void add32(Address src, RegisterID dest)
184 load32(src, dataTempRegister);
185 add32(dataTempRegister, dest);
188 void add32(RegisterID src, Address dest)
190 if (dest.offset >= -32768 && dest.offset <= 32767 && !m_fixedWidth) {
192 lw dataTemp, offset(base)
193 addu dataTemp, dataTemp, src
194 sw dataTemp, offset(base)
196 m_assembler.lw(dataTempRegister, dest.base, dest.offset);
197 m_assembler.addu(dataTempRegister, dataTempRegister, src);
198 m_assembler.sw(dataTempRegister, dest.base, dest.offset);
201 lui addrTemp, (offset + 0x8000) >> 16
202 addu addrTemp, addrTemp, base
203 lw dataTemp, (offset & 0xffff)(addrTemp)
204 addu dataTemp, dataTemp, src
205 sw dataTemp, (offset & 0xffff)(addrTemp)
207 m_assembler.lui(addrTempRegister, (dest.offset + 0x8000) >> 16);
208 m_assembler.addu(addrTempRegister, addrTempRegister, dest.base);
209 m_assembler.lw(dataTempRegister, addrTempRegister, dest.offset);
210 m_assembler.addu(dataTempRegister, dataTempRegister, src);
211 m_assembler.sw(dataTempRegister, addrTempRegister, dest.offset);
215 void add32(TrustedImm32 imm, AbsoluteAddress address)
220 lw dataTemp, 0(addrTemp)
221 addu dataTemp, dataTemp, immTemp
222 sw dataTemp, 0(addrTemp)
224 move(TrustedImmPtr(address.m_ptr), addrTempRegister);
225 m_assembler.lw(dataTempRegister, addrTempRegister, 0);
226 if (!imm.m_isPointer && imm.m_value >= -32768 && imm.m_value <= 32767
228 m_assembler.addiu(dataTempRegister, dataTempRegister, imm.m_value);
230 move(imm, immTempRegister);
231 m_assembler.addu(dataTempRegister, dataTempRegister, immTempRegister);
233 m_assembler.sw(dataTempRegister, addrTempRegister, 0);
236 void and32(RegisterID src, RegisterID dest)
238 m_assembler.andInsn(dest, dest, src);
241 void and32(TrustedImm32 imm, RegisterID dest)
243 if (!imm.m_isPointer && !imm.m_value && !m_fixedWidth)
244 move(MIPSRegisters::zero, dest);
245 else if (!imm.m_isPointer && imm.m_value > 0 && imm.m_value < 65535
247 m_assembler.andi(dest, dest, imm.m_value);
251 and dest, dest, immTemp
253 move(imm, immTempRegister);
254 m_assembler.andInsn(dest, dest, immTempRegister);
258 void lshift32(TrustedImm32 imm, RegisterID dest)
260 m_assembler.sll(dest, dest, imm.m_value);
263 void lshift32(RegisterID shiftAmount, RegisterID dest)
265 m_assembler.sllv(dest, dest, shiftAmount);
268 void mul32(RegisterID src, RegisterID dest)
270 m_assembler.mul(dest, dest, src);
273 void mul32(TrustedImm32 imm, RegisterID src, RegisterID dest)
275 if (!imm.m_isPointer && !imm.m_value && !m_fixedWidth)
276 move(MIPSRegisters::zero, dest);
277 else if (!imm.m_isPointer && imm.m_value == 1 && !m_fixedWidth)
282 mul dest, src, dataTemp
284 move(imm, dataTempRegister);
285 m_assembler.mul(dest, src, dataTempRegister);
289 void neg32(RegisterID srcDest)
291 m_assembler.subu(srcDest, MIPSRegisters::zero, srcDest);
294 void not32(RegisterID srcDest)
296 m_assembler.nor(srcDest, srcDest, MIPSRegisters::zero);
299 void or32(RegisterID src, RegisterID dest)
301 m_assembler.orInsn(dest, dest, src);
304 void or32(RegisterID op1, RegisterID op2, RegisterID dest)
306 m_assembler.orInsn(dest, op1, op2);
309 void or32(TrustedImm32 imm, RegisterID dest)
311 if (!imm.m_isPointer && !imm.m_value && !m_fixedWidth)
314 if (!imm.m_isPointer && imm.m_value > 0 && imm.m_value < 65535
316 m_assembler.ori(dest, dest, imm.m_value);
322 or dest, dest, dataTemp
324 move(imm, dataTempRegister);
325 m_assembler.orInsn(dest, dest, dataTempRegister);
328 void rshift32(RegisterID shiftAmount, RegisterID dest)
330 m_assembler.srav(dest, dest, shiftAmount);
333 void rshift32(TrustedImm32 imm, RegisterID dest)
335 m_assembler.sra(dest, dest, imm.m_value);
338 void rshift32(RegisterID src, TrustedImm32 imm, RegisterID dest)
340 m_assembler.sra(dest, src, imm.m_value);
343 void urshift32(RegisterID shiftAmount, RegisterID dest)
345 m_assembler.srlv(dest, dest, shiftAmount);
348 void urshift32(TrustedImm32 imm, RegisterID dest)
350 m_assembler.srl(dest, dest, imm.m_value);
353 void sub32(RegisterID src, RegisterID dest)
355 m_assembler.subu(dest, dest, src);
358 void sub32(TrustedImm32 imm, RegisterID dest)
360 if (!imm.m_isPointer && imm.m_value >= -32767 && imm.m_value <= 32768
365 m_assembler.addiu(dest, dest, -imm.m_value);
369 subu dest, src, immTemp
371 move(imm, immTempRegister);
372 m_assembler.subu(dest, dest, immTempRegister);
376 void sub32(TrustedImm32 imm, Address address)
378 if (address.offset >= -32768 && address.offset <= 32767
381 lw dataTemp, offset(base)
383 subu dataTemp, dataTemp, immTemp
384 sw dataTemp, offset(base)
386 m_assembler.lw(dataTempRegister, address.base, address.offset);
388 && imm.m_value >= -32767 && imm.m_value <= 32768
390 m_assembler.addiu(dataTempRegister, dataTempRegister,
393 move(imm, immTempRegister);
394 m_assembler.subu(dataTempRegister, dataTempRegister,
397 m_assembler.sw(dataTempRegister, address.base, address.offset);
400 lui addrTemp, (offset + 0x8000) >> 16
401 addu addrTemp, addrTemp, base
402 lw dataTemp, (offset & 0xffff)(addrTemp)
404 subu dataTemp, dataTemp, immTemp
405 sw dataTemp, (offset & 0xffff)(addrTemp)
407 m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16);
408 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
409 m_assembler.lw(dataTempRegister, addrTempRegister, address.offset);
412 && imm.m_value >= -32767 && imm.m_value <= 32768
414 m_assembler.addiu(dataTempRegister, dataTempRegister,
417 move(imm, immTempRegister);
418 m_assembler.subu(dataTempRegister, dataTempRegister,
421 m_assembler.sw(dataTempRegister, addrTempRegister, address.offset);
425 void sub32(Address src, RegisterID dest)
427 load32(src, dataTempRegister);
428 sub32(dataTempRegister, dest);
431 void sub32(TrustedImm32 imm, AbsoluteAddress address)
436 lw dataTemp, 0(addrTemp)
437 subu dataTemp, dataTemp, immTemp
438 sw dataTemp, 0(addrTemp)
440 move(TrustedImmPtr(address.m_ptr), addrTempRegister);
441 m_assembler.lw(dataTempRegister, addrTempRegister, 0);
443 if (!imm.m_isPointer && imm.m_value >= -32767 && imm.m_value <= 32768
445 m_assembler.addiu(dataTempRegister, dataTempRegister,
448 move(imm, immTempRegister);
449 m_assembler.subu(dataTempRegister, dataTempRegister, immTempRegister);
451 m_assembler.sw(dataTempRegister, addrTempRegister, 0);
454 void xor32(RegisterID src, RegisterID dest)
456 m_assembler.xorInsn(dest, dest, src);
459 void xor32(TrustedImm32 imm, RegisterID dest)
463 xor dest, dest, immTemp
465 move(imm, immTempRegister);
466 m_assembler.xorInsn(dest, dest, immTempRegister);
469 void sqrtDouble(FPRegisterID src, FPRegisterID dst)
471 m_assembler.sqrtd(dst, src);
474 void absDouble(FPRegisterID, FPRegisterID)
476 ASSERT_NOT_REACHED();
479 // Memory access operations:
481 // Loads are of the form load(address, destination) and stores of the form
482 // store(source, address). The source for a store may be an TrustedImm32. Address
483 // operand objects to loads and store will be implicitly constructed if a
484 // register is passed.
486 /* Need to use zero-extened load byte for load8. */
487 void load8(ImplicitAddress address, RegisterID dest)
489 if (address.offset >= -32768 && address.offset <= 32767
491 m_assembler.lbu(dest, address.base, address.offset);
494 lui addrTemp, (offset + 0x8000) >> 16
495 addu addrTemp, addrTemp, base
496 lbu dest, (offset & 0xffff)(addrTemp)
498 m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16);
499 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
500 m_assembler.lbu(dest, addrTempRegister, address.offset);
504 void load8(BaseIndex address, RegisterID dest)
506 if (address.offset >= -32768 && address.offset <= 32767
509 sll addrTemp, address.index, address.scale
510 addu addrTemp, addrTemp, address.base
511 lbu dest, address.offset(addrTemp)
513 m_assembler.sll(addrTempRegister, address.index, address.scale);
514 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
515 m_assembler.lbu(dest, addrTempRegister, address.offset);
518 sll addrTemp, address.index, address.scale
519 addu addrTemp, addrTemp, address.base
520 lui immTemp, (address.offset + 0x8000) >> 16
521 addu addrTemp, addrTemp, immTemp
522 lbu dest, (address.offset & 0xffff)(at)
524 m_assembler.sll(addrTempRegister, address.index, address.scale);
525 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
526 m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16);
527 m_assembler.addu(addrTempRegister, addrTempRegister,
529 m_assembler.lbu(dest, addrTempRegister, address.offset);
533 void load32(ImplicitAddress address, RegisterID dest)
535 if (address.offset >= -32768 && address.offset <= 32767
537 m_assembler.lw(dest, address.base, address.offset);
540 lui addrTemp, (offset + 0x8000) >> 16
541 addu addrTemp, addrTemp, base
542 lw dest, (offset & 0xffff)(addrTemp)
544 m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16);
545 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
546 m_assembler.lw(dest, addrTempRegister, address.offset);
550 void load32(BaseIndex address, RegisterID dest)
552 if (address.offset >= -32768 && address.offset <= 32767
555 sll addrTemp, address.index, address.scale
556 addu addrTemp, addrTemp, address.base
557 lw dest, address.offset(addrTemp)
559 m_assembler.sll(addrTempRegister, address.index, address.scale);
560 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
561 m_assembler.lw(dest, addrTempRegister, address.offset);
564 sll addrTemp, address.index, address.scale
565 addu addrTemp, addrTemp, address.base
566 lui immTemp, (address.offset + 0x8000) >> 16
567 addu addrTemp, addrTemp, immTemp
568 lw dest, (address.offset & 0xffff)(at)
570 m_assembler.sll(addrTempRegister, address.index, address.scale);
571 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
572 m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16);
573 m_assembler.addu(addrTempRegister, addrTempRegister,
575 m_assembler.lw(dest, addrTempRegister, address.offset);
579 void load32WithUnalignedHalfWords(BaseIndex address, RegisterID dest)
581 if (address.offset >= -32768 && address.offset <= 32764
584 sll addrTemp, address.index, address.scale
585 addu addrTemp, addrTemp, address.base
587 lwl dest, address.offset(addrTemp)
588 lwr dest, address.offset+3(addrTemp)
590 lwl dest, address.offset+3(addrTemp)
591 lwr dest, address.offset(addrTemp)
593 m_assembler.sll(addrTempRegister, address.index, address.scale);
594 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
596 m_assembler.lwl(dest, addrTempRegister, address.offset);
597 m_assembler.lwr(dest, addrTempRegister, address.offset + 3);
599 m_assembler.lwl(dest, addrTempRegister, address.offset + 3);
600 m_assembler.lwr(dest, addrTempRegister, address.offset);
605 sll addrTemp, address.index, address.scale
606 addu addrTemp, addrTemp, address.base
607 lui immTemp, address.offset >> 16
608 ori immTemp, immTemp, address.offset & 0xffff
609 addu addrTemp, addrTemp, immTemp
617 m_assembler.sll(addrTempRegister, address.index, address.scale);
618 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
619 m_assembler.lui(immTempRegister, address.offset >> 16);
620 m_assembler.ori(immTempRegister, immTempRegister, address.offset);
621 m_assembler.addu(addrTempRegister, addrTempRegister,
624 m_assembler.lwl(dest, addrTempRegister, 0);
625 m_assembler.lwr(dest, addrTempRegister, 3);
627 m_assembler.lwl(dest, addrTempRegister, 3);
628 m_assembler.lwr(dest, addrTempRegister, 0);
633 void load32(const void* address, RegisterID dest)
639 move(TrustedImmPtr(address), addrTempRegister);
640 m_assembler.lw(dest, addrTempRegister, 0);
643 DataLabel32 load32WithAddressOffsetPatch(Address address, RegisterID dest)
647 lui addrTemp, address.offset >> 16
648 ori addrTemp, addrTemp, address.offset & 0xffff
649 addu addrTemp, addrTemp, address.base
652 DataLabel32 dataLabel(this);
653 move(TrustedImm32(address.offset), addrTempRegister);
654 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
655 m_assembler.lw(dest, addrTempRegister, 0);
656 m_fixedWidth = false;
660 DataLabelCompact load32WithCompactAddressOffsetPatch(Address address, RegisterID dest)
662 DataLabelCompact dataLabel(this);
663 load32WithAddressOffsetPatch(address, dest);
667 /* Need to use zero-extened load half-word for load16. */
668 void load16(ImplicitAddress address, RegisterID dest)
670 if (address.offset >= -32768 && address.offset <= 32767
672 m_assembler.lhu(dest, address.base, address.offset);
675 lui addrTemp, (offset + 0x8000) >> 16
676 addu addrTemp, addrTemp, base
677 lhu dest, (offset & 0xffff)(addrTemp)
679 m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16);
680 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
681 m_assembler.lhu(dest, addrTempRegister, address.offset);
685 /* Need to use zero-extened load half-word for load16. */
686 void load16(BaseIndex address, RegisterID dest)
688 if (address.offset >= -32768 && address.offset <= 32767
691 sll addrTemp, address.index, address.scale
692 addu addrTemp, addrTemp, address.base
693 lhu dest, address.offset(addrTemp)
695 m_assembler.sll(addrTempRegister, address.index, address.scale);
696 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
697 m_assembler.lhu(dest, addrTempRegister, address.offset);
700 sll addrTemp, address.index, address.scale
701 addu addrTemp, addrTemp, address.base
702 lui immTemp, (address.offset + 0x8000) >> 16
703 addu addrTemp, addrTemp, immTemp
704 lhu dest, (address.offset & 0xffff)(addrTemp)
706 m_assembler.sll(addrTempRegister, address.index, address.scale);
707 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
708 m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16);
709 m_assembler.addu(addrTempRegister, addrTempRegister,
711 m_assembler.lhu(dest, addrTempRegister, address.offset);
715 DataLabel32 store32WithAddressOffsetPatch(RegisterID src, Address address)
719 lui addrTemp, address.offset >> 16
720 ori addrTemp, addrTemp, address.offset & 0xffff
721 addu addrTemp, addrTemp, address.base
724 DataLabel32 dataLabel(this);
725 move(TrustedImm32(address.offset), addrTempRegister);
726 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
727 m_assembler.sw(src, addrTempRegister, 0);
728 m_fixedWidth = false;
732 void store32(RegisterID src, ImplicitAddress address)
734 if (address.offset >= -32768 && address.offset <= 32767
736 m_assembler.sw(src, address.base, address.offset);
739 lui addrTemp, (offset + 0x8000) >> 16
740 addu addrTemp, addrTemp, base
741 sw src, (offset & 0xffff)(addrTemp)
743 m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16);
744 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
745 m_assembler.sw(src, addrTempRegister, address.offset);
749 void store32(RegisterID src, BaseIndex address)
751 if (address.offset >= -32768 && address.offset <= 32767
754 sll addrTemp, address.index, address.scale
755 addu addrTemp, addrTemp, address.base
756 sw src, address.offset(addrTemp)
758 m_assembler.sll(addrTempRegister, address.index, address.scale);
759 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
760 m_assembler.sw(src, addrTempRegister, address.offset);
763 sll addrTemp, address.index, address.scale
764 addu addrTemp, addrTemp, address.base
765 lui immTemp, (address.offset + 0x8000) >> 16
766 addu addrTemp, addrTemp, immTemp
767 sw src, (address.offset & 0xffff)(at)
769 m_assembler.sll(addrTempRegister, address.index, address.scale);
770 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
771 m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16);
772 m_assembler.addu(addrTempRegister, addrTempRegister,
774 m_assembler.sw(src, addrTempRegister, address.offset);
778 void store32(TrustedImm32 imm, ImplicitAddress address)
780 if (address.offset >= -32768 && address.offset <= 32767
782 if (!imm.m_isPointer && !imm.m_value)
783 m_assembler.sw(MIPSRegisters::zero, address.base,
786 move(imm, immTempRegister);
787 m_assembler.sw(immTempRegister, address.base, address.offset);
791 lui addrTemp, (offset + 0x8000) >> 16
792 addu addrTemp, addrTemp, base
793 sw immTemp, (offset & 0xffff)(addrTemp)
795 m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16);
796 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
797 if (!imm.m_isPointer && !imm.m_value && !m_fixedWidth)
798 m_assembler.sw(MIPSRegisters::zero, addrTempRegister,
801 move(imm, immTempRegister);
802 m_assembler.sw(immTempRegister, addrTempRegister,
808 void store32(RegisterID src, const void* address)
814 move(TrustedImmPtr(address), addrTempRegister);
815 m_assembler.sw(src, addrTempRegister, 0);
818 void store32(TrustedImm32 imm, const void* address)
825 if (!imm.m_isPointer && !imm.m_value && !m_fixedWidth) {
826 move(TrustedImmPtr(address), addrTempRegister);
827 m_assembler.sw(MIPSRegisters::zero, addrTempRegister, 0);
829 move(imm, immTempRegister);
830 move(TrustedImmPtr(address), addrTempRegister);
831 m_assembler.sw(immTempRegister, addrTempRegister, 0);
835 // Floating-point operations:
837 static bool supportsFloatingPoint()
839 #if WTF_MIPS_DOUBLE_FLOAT
846 static bool supportsFloatingPointTruncate()
848 #if WTF_MIPS_DOUBLE_FLOAT && WTF_MIPS_ISA_AT_LEAST(2)
855 static bool supportsFloatingPointSqrt()
857 #if WTF_MIPS_DOUBLE_FLOAT && WTF_MIPS_ISA_AT_LEAST(2)
863 static bool supportsFloatingPointAbs() { return false; }
865 // Stack manipulation operations:
867 // The ABI is assumed to provide a stack abstraction to memory,
868 // containing machine word sized units of data. Push and pop
869 // operations add and remove a single register sized unit of data
870 // to or from the stack. Peek and poke operations read or write
871 // values on the stack, without moving the current stack position.
873 void pop(RegisterID dest)
875 m_assembler.lw(dest, MIPSRegisters::sp, 0);
876 m_assembler.addiu(MIPSRegisters::sp, MIPSRegisters::sp, 4);
879 void push(RegisterID src)
881 m_assembler.addiu(MIPSRegisters::sp, MIPSRegisters::sp, -4);
882 m_assembler.sw(src, MIPSRegisters::sp, 0);
885 void push(Address address)
887 load32(address, dataTempRegister);
888 push(dataTempRegister);
891 void push(TrustedImm32 imm)
893 move(imm, immTempRegister);
894 push(immTempRegister);
897 // Register move operations:
899 // Move values in registers.
901 void move(TrustedImm32 imm, RegisterID dest)
903 if (!imm.m_isPointer && !imm.m_value && !m_fixedWidth)
904 move(MIPSRegisters::zero, dest);
905 else if (imm.m_isPointer || m_fixedWidth) {
906 m_assembler.lui(dest, imm.m_value >> 16);
907 m_assembler.ori(dest, dest, imm.m_value);
909 m_assembler.li(dest, imm.m_value);
912 void move(RegisterID src, RegisterID dest)
914 if (src != dest || m_fixedWidth)
915 m_assembler.move(dest, src);
918 void move(TrustedImmPtr imm, RegisterID dest)
920 move(TrustedImm32(imm), dest);
923 void swap(RegisterID reg1, RegisterID reg2)
925 move(reg1, immTempRegister);
927 move(immTempRegister, reg2);
930 void signExtend32ToPtr(RegisterID src, RegisterID dest)
932 if (src != dest || m_fixedWidth)
936 void zeroExtend32ToPtr(RegisterID src, RegisterID dest)
938 if (src != dest || m_fixedWidth)
942 // Forwards / external control flow operations:
944 // This set of jump and conditional branch operations return a Jump
945 // object which may linked at a later point, allow forwards jump,
946 // or jumps that will require external linkage (after the code has been
949 // For branches, signed <, >, <= and >= are denoted as l, g, le, and ge
950 // respecitvely, for unsigned comparisons the names b, a, be, and ae are
951 // used (representing the names 'below' and 'above').
953 // Operands to the comparision are provided in the expected order, e.g.
954 // jle32(reg1, TrustedImm32(5)) will branch if the value held in reg1, when
955 // treated as a signed 32bit value, is less than or equal to 5.
957 // jz and jnz test whether the first operand is equal to zero, and take
958 // an optional second operand of a mask under which to perform the test.
960 Jump branch8(RelationalCondition cond, Address left, TrustedImm32 right)
962 // Make sure the immediate value is unsigned 8 bits.
963 ASSERT(!(right.m_value & 0xFFFFFF00));
964 load8(left, dataTempRegister);
965 move(right, immTempRegister);
966 return branch32(cond, dataTempRegister, immTempRegister);
969 Jump branch8(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
971 ASSERT(!(right.m_value & 0xFFFFFF00));
972 load8(left, dataTempRegister);
973 // Be careful that the previous load8() uses immTempRegister.
974 // So, we need to put move() after load8().
975 move(right, immTempRegister);
976 return branch32(cond, dataTempRegister, immTempRegister);
979 Jump branch32(RelationalCondition cond, RegisterID left, RegisterID right)
982 return branchEqual(left, right);
983 if (cond == NotEqual)
984 return branchNotEqual(left, right);
986 m_assembler.sltu(cmpTempRegister, right, left);
987 return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
989 if (cond == AboveOrEqual) {
990 m_assembler.sltu(cmpTempRegister, left, right);
991 return branchEqual(cmpTempRegister, MIPSRegisters::zero);
994 m_assembler.sltu(cmpTempRegister, left, right);
995 return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
997 if (cond == BelowOrEqual) {
998 m_assembler.sltu(cmpTempRegister, right, left);
999 return branchEqual(cmpTempRegister, MIPSRegisters::zero);
1001 if (cond == GreaterThan) {
1002 m_assembler.slt(cmpTempRegister, right, left);
1003 return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
1005 if (cond == GreaterThanOrEqual) {
1006 m_assembler.slt(cmpTempRegister, left, right);
1007 return branchEqual(cmpTempRegister, MIPSRegisters::zero);
1009 if (cond == LessThan) {
1010 m_assembler.slt(cmpTempRegister, left, right);
1011 return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
1013 if (cond == LessThanOrEqual) {
1014 m_assembler.slt(cmpTempRegister, right, left);
1015 return branchEqual(cmpTempRegister, MIPSRegisters::zero);
1022 Jump branch32(RelationalCondition cond, RegisterID left, TrustedImm32 right)
1024 move(right, immTempRegister);
1025 return branch32(cond, left, immTempRegister);
1028 Jump branch32(RelationalCondition cond, RegisterID left, Address right)
1030 load32(right, dataTempRegister);
1031 return branch32(cond, left, dataTempRegister);
1034 Jump branch32(RelationalCondition cond, Address left, RegisterID right)
1036 load32(left, dataTempRegister);
1037 return branch32(cond, dataTempRegister, right);
1040 Jump branch32(RelationalCondition cond, Address left, TrustedImm32 right)
1042 load32(left, dataTempRegister);
1043 move(right, immTempRegister);
1044 return branch32(cond, dataTempRegister, immTempRegister);
1047 Jump branch32(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
1049 load32(left, dataTempRegister);
1050 // Be careful that the previous load32() uses immTempRegister.
1051 // So, we need to put move() after load32().
1052 move(right, immTempRegister);
1053 return branch32(cond, dataTempRegister, immTempRegister);
1056 Jump branch32WithUnalignedHalfWords(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
1058 load32WithUnalignedHalfWords(left, dataTempRegister);
1059 // Be careful that the previous load32WithUnalignedHalfWords()
1060 // uses immTempRegister.
1061 // So, we need to put move() after load32WithUnalignedHalfWords().
1062 move(right, immTempRegister);
1063 return branch32(cond, dataTempRegister, immTempRegister);
1066 Jump branch32(RelationalCondition cond, AbsoluteAddress left, RegisterID right)
1068 load32(left.m_ptr, dataTempRegister);
1069 return branch32(cond, dataTempRegister, right);
1072 Jump branch32(RelationalCondition cond, AbsoluteAddress left, TrustedImm32 right)
1074 load32(left.m_ptr, dataTempRegister);
1075 move(right, immTempRegister);
1076 return branch32(cond, dataTempRegister, immTempRegister);
1079 Jump branchTest32(ResultCondition cond, RegisterID reg, RegisterID mask)
1081 ASSERT((cond == Zero) || (cond == NonZero));
1082 m_assembler.andInsn(cmpTempRegister, reg, mask);
1084 return branchEqual(cmpTempRegister, MIPSRegisters::zero);
1085 return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
1088 Jump branchTest32(ResultCondition cond, RegisterID reg, TrustedImm32 mask = TrustedImm32(-1))
1090 ASSERT((cond == Zero) || (cond == NonZero));
1091 if (mask.m_value == -1 && !m_fixedWidth) {
1093 return branchEqual(reg, MIPSRegisters::zero);
1094 return branchNotEqual(reg, MIPSRegisters::zero);
1096 move(mask, immTempRegister);
1097 return branchTest32(cond, reg, immTempRegister);
1100 Jump branchTest32(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
1102 load32(address, dataTempRegister);
1103 return branchTest32(cond, dataTempRegister, mask);
1106 Jump branchTest32(ResultCondition cond, BaseIndex address, TrustedImm32 mask = TrustedImm32(-1))
1108 load32(address, dataTempRegister);
1109 return branchTest32(cond, dataTempRegister, mask);
1112 Jump branchTest8(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
1114 load8(address, dataTempRegister);
1115 return branchTest32(cond, dataTempRegister, mask);
1120 return branchEqual(MIPSRegisters::zero, MIPSRegisters::zero);
1123 void jump(RegisterID target)
1125 m_assembler.jr(target);
1129 void jump(Address address)
1131 m_fixedWidth = true;
1132 load32(address, MIPSRegisters::t9);
1133 m_assembler.jr(MIPSRegisters::t9);
1135 m_fixedWidth = false;
1138 // Arithmetic control flow operations:
1140 // This set of conditional branch operations branch based
1141 // on the result of an arithmetic operation. The operation
1142 // is performed as normal, storing the result.
1144 // * jz operations branch if the result is zero.
1145 // * jo operations branch if the (signed) arithmetic
1146 // operation caused an overflow to occur.
1148 Jump branchAdd32(ResultCondition cond, RegisterID src, RegisterID dest)
1150 ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
1151 if (cond == Overflow) {
1154 xor cmpTemp, dataTemp, src
1155 bltz cmpTemp, No_overflow # diff sign bit -> no overflow
1156 addu dest, dataTemp, src
1157 xor cmpTemp, dest, dataTemp
1158 bgez cmpTemp, No_overflow # same sign big -> no overflow
1168 move(dest, dataTempRegister);
1169 m_assembler.xorInsn(cmpTempRegister, dataTempRegister, src);
1170 m_assembler.bltz(cmpTempRegister, 10);
1171 m_assembler.addu(dest, dataTempRegister, src);
1172 m_assembler.xorInsn(cmpTempRegister, dest, dataTempRegister);
1173 m_assembler.bgez(cmpTempRegister, 7);
1177 if (cond == Signed) {
1179 // Check if dest is negative.
1180 m_assembler.slt(cmpTempRegister, dest, MIPSRegisters::zero);
1181 return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
1185 return branchEqual(dest, MIPSRegisters::zero);
1187 if (cond == NonZero) {
1189 return branchNotEqual(dest, MIPSRegisters::zero);
1195 Jump branchAdd32(ResultCondition cond, TrustedImm32 imm, RegisterID dest)
1197 move(imm, immTempRegister);
1198 return branchAdd32(cond, immTempRegister, dest);
1201 Jump branchMul32(ResultCondition cond, RegisterID src, RegisterID dest)
1203 ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
1204 if (cond == Overflow) {
1209 sra addrTemp, dest, 31
1210 beq dataTemp, addrTemp, No_overflow # all sign bits (bit 63 to bit 31) are the same -> no overflow
1220 m_assembler.mult(src, dest);
1221 m_assembler.mfhi(dataTempRegister);
1222 m_assembler.mflo(dest);
1223 m_assembler.sra(addrTempRegister, dest, 31);
1224 m_assembler.beq(dataTempRegister, addrTempRegister, 7);
1228 if (cond == Signed) {
1230 // Check if dest is negative.
1231 m_assembler.slt(cmpTempRegister, dest, MIPSRegisters::zero);
1232 return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
1236 return branchEqual(dest, MIPSRegisters::zero);
1238 if (cond == NonZero) {
1240 return branchNotEqual(dest, MIPSRegisters::zero);
1246 Jump branchMul32(ResultCondition cond, TrustedImm32 imm, RegisterID src, RegisterID dest)
1248 move(imm, immTempRegister);
1250 return branchMul32(cond, immTempRegister, dest);
1253 Jump branchSub32(ResultCondition cond, RegisterID src, RegisterID dest)
1255 ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
1256 if (cond == Overflow) {
1259 xor cmpTemp, dataTemp, src
1260 bgez cmpTemp, No_overflow # same sign bit -> no overflow
1261 subu dest, dataTemp, src
1262 xor cmpTemp, dest, dataTemp
1263 bgez cmpTemp, No_overflow # same sign bit -> no overflow
1273 move(dest, dataTempRegister);
1274 m_assembler.xorInsn(cmpTempRegister, dataTempRegister, src);
1275 m_assembler.bgez(cmpTempRegister, 10);
1276 m_assembler.subu(dest, dataTempRegister, src);
1277 m_assembler.xorInsn(cmpTempRegister, dest, dataTempRegister);
1278 m_assembler.bgez(cmpTempRegister, 7);
1282 if (cond == Signed) {
1284 // Check if dest is negative.
1285 m_assembler.slt(cmpTempRegister, dest, MIPSRegisters::zero);
1286 return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
1290 return branchEqual(dest, MIPSRegisters::zero);
1292 if (cond == NonZero) {
1294 return branchNotEqual(dest, MIPSRegisters::zero);
1300 Jump branchSub32(ResultCondition cond, TrustedImm32 imm, RegisterID dest)
1302 move(imm, immTempRegister);
1303 return branchSub32(cond, immTempRegister, dest);
1306 Jump branchOr32(ResultCondition cond, RegisterID src, RegisterID dest)
1308 ASSERT((cond == Signed) || (cond == Zero) || (cond == NonZero));
1309 if (cond == Signed) {
1311 // Check if dest is negative.
1312 m_assembler.slt(cmpTempRegister, dest, MIPSRegisters::zero);
1313 return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
1317 return branchEqual(dest, MIPSRegisters::zero);
1319 if (cond == NonZero) {
1321 return branchNotEqual(dest, MIPSRegisters::zero);
1327 // Miscellaneous operations:
1336 /* We need two words for relaxation. */
1341 return Call(m_assembler.label(), Call::LinkableNear);
1346 m_assembler.lui(MIPSRegisters::t9, 0);
1347 m_assembler.ori(MIPSRegisters::t9, MIPSRegisters::t9, 0);
1348 m_assembler.jalr(MIPSRegisters::t9);
1350 return Call(m_assembler.label(), Call::Linkable);
1353 Call call(RegisterID target)
1355 m_assembler.jalr(target);
1357 return Call(m_assembler.label(), Call::None);
1360 Call call(Address address)
1362 m_fixedWidth = true;
1363 load32(address, MIPSRegisters::t9);
1364 m_assembler.jalr(MIPSRegisters::t9);
1366 m_fixedWidth = false;
1367 return Call(m_assembler.label(), Call::None);
1372 m_assembler.jr(MIPSRegisters::ra);
1376 void compare32(RelationalCondition cond, RegisterID left, RegisterID right, RegisterID dest)
1378 if (cond == Equal) {
1379 m_assembler.xorInsn(dest, left, right);
1380 m_assembler.sltiu(dest, dest, 1);
1381 } else if (cond == NotEqual) {
1382 m_assembler.xorInsn(dest, left, right);
1383 m_assembler.sltu(dest, MIPSRegisters::zero, dest);
1384 } else if (cond == Above)
1385 m_assembler.sltu(dest, right, left);
1386 else if (cond == AboveOrEqual) {
1387 m_assembler.sltu(dest, left, right);
1388 m_assembler.xori(dest, dest, 1);
1389 } else if (cond == Below)
1390 m_assembler.sltu(dest, left, right);
1391 else if (cond == BelowOrEqual) {
1392 m_assembler.sltu(dest, right, left);
1393 m_assembler.xori(dest, dest, 1);
1394 } else if (cond == GreaterThan)
1395 m_assembler.slt(dest, right, left);
1396 else if (cond == GreaterThanOrEqual) {
1397 m_assembler.slt(dest, left, right);
1398 m_assembler.xori(dest, dest, 1);
1399 } else if (cond == LessThan)
1400 m_assembler.slt(dest, left, right);
1401 else if (cond == LessThanOrEqual) {
1402 m_assembler.slt(dest, right, left);
1403 m_assembler.xori(dest, dest, 1);
1407 void compare32(RelationalCondition cond, RegisterID left, TrustedImm32 right, RegisterID dest)
1409 move(right, immTempRegister);
1410 compare32(cond, left, immTempRegister, dest);
1413 void test8(ResultCondition cond, Address address, TrustedImm32 mask, RegisterID dest)
1415 ASSERT((cond == Zero) || (cond == NonZero));
1416 load8(address, dataTempRegister);
1417 if (mask.m_value == -1 && !m_fixedWidth) {
1419 m_assembler.sltiu(dest, dataTempRegister, 1);
1421 m_assembler.sltu(dest, MIPSRegisters::zero, dataTempRegister);
1423 move(mask, immTempRegister);
1424 m_assembler.andInsn(cmpTempRegister, dataTempRegister,
1427 m_assembler.sltiu(dest, cmpTempRegister, 1);
1429 m_assembler.sltu(dest, MIPSRegisters::zero, cmpTempRegister);
1433 void test32(ResultCondition cond, Address address, TrustedImm32 mask, RegisterID dest)
1435 ASSERT((cond == Zero) || (cond == NonZero));
1436 load32(address, dataTempRegister);
1437 if (mask.m_value == -1 && !m_fixedWidth) {
1439 m_assembler.sltiu(dest, dataTempRegister, 1);
1441 m_assembler.sltu(dest, MIPSRegisters::zero, dataTempRegister);
1443 move(mask, immTempRegister);
1444 m_assembler.andInsn(cmpTempRegister, dataTempRegister,
1447 m_assembler.sltiu(dest, cmpTempRegister, 1);
1449 m_assembler.sltu(dest, MIPSRegisters::zero, cmpTempRegister);
1453 DataLabel32 moveWithPatch(TrustedImm32 imm, RegisterID dest)
1455 m_fixedWidth = true;
1456 DataLabel32 label(this);
1458 m_fixedWidth = false;
1462 DataLabelPtr moveWithPatch(TrustedImmPtr initialValue, RegisterID dest)
1464 m_fixedWidth = true;
1465 DataLabelPtr label(this);
1466 move(initialValue, dest);
1467 m_fixedWidth = false;
1471 Jump branchPtrWithPatch(RelationalCondition cond, RegisterID left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
1473 m_fixedWidth = true;
1474 dataLabel = moveWithPatch(initialRightValue, immTempRegister);
1475 Jump temp = branch32(cond, left, immTempRegister);
1476 m_fixedWidth = false;
1480 Jump branchPtrWithPatch(RelationalCondition cond, Address left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
1482 m_fixedWidth = true;
1483 load32(left, dataTempRegister);
1484 dataLabel = moveWithPatch(initialRightValue, immTempRegister);
1485 Jump temp = branch32(cond, dataTempRegister, immTempRegister);
1486 m_fixedWidth = false;
1490 DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address)
1492 m_fixedWidth = true;
1493 DataLabelPtr dataLabel = moveWithPatch(initialValue, dataTempRegister);
1494 store32(dataTempRegister, address);
1495 m_fixedWidth = false;
1499 DataLabelPtr storePtrWithPatch(ImplicitAddress address)
1501 return storePtrWithPatch(TrustedImmPtr(0), address);
1504 Call tailRecursiveCall()
1506 // Like a normal call, but don't update the returned address register
1507 m_fixedWidth = true;
1508 move(TrustedImm32(0), MIPSRegisters::t9);
1509 m_assembler.jr(MIPSRegisters::t9);
1511 m_fixedWidth = false;
1512 return Call(m_assembler.label(), Call::Linkable);
1515 Call makeTailRecursiveCall(Jump oldJump)
1518 return tailRecursiveCall();
1521 void loadDouble(ImplicitAddress address, FPRegisterID dest)
1525 li addrTemp, address.offset
1526 addu addrTemp, addrTemp, base
1527 lwc1 dest, 0(addrTemp)
1528 lwc1 dest+1, 4(addrTemp)
1530 move(TrustedImm32(address.offset), addrTempRegister);
1531 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
1532 m_assembler.lwc1(dest, addrTempRegister, 0);
1533 m_assembler.lwc1(FPRegisterID(dest + 1), addrTempRegister, 4);
1535 if (address.offset >= -32768 && address.offset <= 32767
1537 m_assembler.ldc1(dest, address.base, address.offset);
1540 lui addrTemp, (offset + 0x8000) >> 16
1541 addu addrTemp, addrTemp, base
1542 ldc1 dest, (offset & 0xffff)(addrTemp)
1544 m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16);
1545 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
1546 m_assembler.ldc1(dest, addrTempRegister, address.offset);
1551 void loadDouble(const void* address, FPRegisterID dest)
1555 li addrTemp, address
1556 lwc1 dest, 0(addrTemp)
1557 lwc1 dest+1, 4(addrTemp)
1559 move(TrustedImmPtr(address), addrTempRegister);
1560 m_assembler.lwc1(dest, addrTempRegister, 0);
1561 m_assembler.lwc1(FPRegisterID(dest + 1), addrTempRegister, 4);
1564 li addrTemp, address
1565 ldc1 dest, 0(addrTemp)
1567 move(TrustedImmPtr(address), addrTempRegister);
1568 m_assembler.ldc1(dest, addrTempRegister, 0);
1573 void storeDouble(FPRegisterID src, ImplicitAddress address)
1577 li addrTemp, address.offset
1578 addu addrTemp, addrTemp, base
1579 swc1 dest, 0(addrTemp)
1580 swc1 dest+1, 4(addrTemp)
1582 move(TrustedImm32(address.offset), addrTempRegister);
1583 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
1584 m_assembler.swc1(src, addrTempRegister, 0);
1585 m_assembler.swc1(FPRegisterID(src + 1), addrTempRegister, 4);
1587 if (address.offset >= -32768 && address.offset <= 32767
1589 m_assembler.sdc1(src, address.base, address.offset);
1592 lui addrTemp, (offset + 0x8000) >> 16
1593 addu addrTemp, addrTemp, base
1594 sdc1 src, (offset & 0xffff)(addrTemp)
1596 m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16);
1597 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
1598 m_assembler.sdc1(src, addrTempRegister, address.offset);
1603 void addDouble(FPRegisterID src, FPRegisterID dest)
1605 m_assembler.addd(dest, dest, src);
1608 void addDouble(Address src, FPRegisterID dest)
1610 loadDouble(src, fpTempRegister);
1611 m_assembler.addd(dest, dest, fpTempRegister);
1614 void subDouble(FPRegisterID src, FPRegisterID dest)
1616 m_assembler.subd(dest, dest, src);
1619 void subDouble(Address src, FPRegisterID dest)
1621 loadDouble(src, fpTempRegister);
1622 m_assembler.subd(dest, dest, fpTempRegister);
1625 void mulDouble(FPRegisterID src, FPRegisterID dest)
1627 m_assembler.muld(dest, dest, src);
1630 void mulDouble(Address src, FPRegisterID dest)
1632 loadDouble(src, fpTempRegister);
1633 m_assembler.muld(dest, dest, fpTempRegister);
1636 void divDouble(FPRegisterID src, FPRegisterID dest)
1638 m_assembler.divd(dest, dest, src);
1641 void convertInt32ToDouble(RegisterID src, FPRegisterID dest)
1643 m_assembler.mtc1(src, fpTempRegister);
1644 m_assembler.cvtdw(dest, fpTempRegister);
1647 void convertInt32ToDouble(Address src, FPRegisterID dest)
1649 load32(src, dataTempRegister);
1650 m_assembler.mtc1(dataTempRegister, fpTempRegister);
1651 m_assembler.cvtdw(dest, fpTempRegister);
1654 void convertInt32ToDouble(AbsoluteAddress src, FPRegisterID dest)
1656 load32(src.m_ptr, dataTempRegister);
1657 m_assembler.mtc1(dataTempRegister, fpTempRegister);
1658 m_assembler.cvtdw(dest, fpTempRegister);
1661 void insertRelaxationWords()
1663 /* We need four words for relaxation. */
1664 m_assembler.beq(MIPSRegisters::zero, MIPSRegisters::zero, 3); // Jump over nops;
1672 m_assembler.appendJump();
1675 insertRelaxationWords();
1676 return Jump(m_assembler.label());
1681 m_assembler.appendJump();
1684 insertRelaxationWords();
1685 return Jump(m_assembler.label());
1688 Jump branchEqual(RegisterID rs, RegisterID rt)
1690 m_assembler.appendJump();
1691 m_assembler.beq(rs, rt, 0);
1693 insertRelaxationWords();
1694 return Jump(m_assembler.label());
1697 Jump branchNotEqual(RegisterID rs, RegisterID rt)
1699 m_assembler.appendJump();
1700 m_assembler.bne(rs, rt, 0);
1702 insertRelaxationWords();
1703 return Jump(m_assembler.label());
1706 Jump branchDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right)
1708 if (cond == DoubleEqual) {
1709 m_assembler.ceqd(left, right);
1710 return branchTrue();
1712 if (cond == DoubleNotEqual) {
1713 m_assembler.cueqd(left, right);
1714 return branchFalse(); // false
1716 if (cond == DoubleGreaterThan) {
1717 m_assembler.cngtd(left, right);
1718 return branchFalse(); // false
1720 if (cond == DoubleGreaterThanOrEqual) {
1721 m_assembler.cnged(left, right);
1722 return branchFalse(); // false
1724 if (cond == DoubleLessThan) {
1725 m_assembler.cltd(left, right);
1726 return branchTrue();
1728 if (cond == DoubleLessThanOrEqual) {
1729 m_assembler.cled(left, right);
1730 return branchTrue();
1732 if (cond == DoubleEqualOrUnordered) {
1733 m_assembler.cueqd(left, right);
1734 return branchTrue();
1736 if (cond == DoubleNotEqualOrUnordered) {
1737 m_assembler.ceqd(left, right);
1738 return branchFalse(); // false
1740 if (cond == DoubleGreaterThanOrUnordered) {
1741 m_assembler.coled(left, right);
1742 return branchFalse(); // false
1744 if (cond == DoubleGreaterThanOrEqualOrUnordered) {
1745 m_assembler.coltd(left, right);
1746 return branchFalse(); // false
1748 if (cond == DoubleLessThanOrUnordered) {
1749 m_assembler.cultd(left, right);
1750 return branchTrue();
1752 if (cond == DoubleLessThanOrEqualOrUnordered) {
1753 m_assembler.culed(left, right);
1754 return branchTrue();
1761 // Truncates 'src' to an integer, and places the resulting 'dest'.
1762 // If the result is not representable as a 32 bit value, branch.
1763 // May also branch for some values that are representable in 32 bits
1764 // (specifically, in this case, INT_MAX 0x7fffffff).
1765 Jump branchTruncateDoubleToInt32(FPRegisterID src, RegisterID dest)
1767 m_assembler.truncwd(fpTempRegister, src);
1768 m_assembler.mfc1(dest, fpTempRegister);
1769 return branch32(Equal, dest, TrustedImm32(0x7fffffff));
1772 // Convert 'src' to an integer, and places the resulting 'dest'.
1773 // If the result is not representable as a 32 bit value, branch.
1774 // May also branch for some values that are representable in 32 bits
1775 // (specifically, in this case, 0).
1776 void branchConvertDoubleToInt32(FPRegisterID src, RegisterID dest, JumpList& failureCases, FPRegisterID fpTemp)
1778 m_assembler.cvtwd(fpTempRegister, src);
1779 m_assembler.mfc1(dest, fpTempRegister);
1781 // If the result is zero, it might have been -0.0, and the double comparison won't catch this!
1782 failureCases.append(branch32(Equal, dest, MIPSRegisters::zero));
1784 // Convert the integer result back to float & compare to the original value - if not equal or unordered (NaN) then jump.
1785 convertInt32ToDouble(dest, fpTemp);
1786 failureCases.append(branchDouble(DoubleNotEqualOrUnordered, fpTemp, src));
1789 Jump branchDoubleNonZero(FPRegisterID reg, FPRegisterID scratch)
1791 #if WTF_MIPS_ISA_REV(2) && WTF_MIPS_FP64
1792 m_assembler.mtc1(MIPSRegisters::zero, scratch);
1793 m_assembler.mthc1(MIPSRegisters::zero, scratch);
1795 m_assembler.mtc1(MIPSRegisters::zero, scratch);
1796 m_assembler.mtc1(MIPSRegisters::zero, FPRegisterID(scratch + 1));
1798 return branchDouble(DoubleNotEqual, reg, scratch);
1801 Jump branchDoubleZeroOrNaN(FPRegisterID reg, FPRegisterID scratch)
1803 #if WTF_MIPS_ISA_REV(2) && WTF_MIPS_FP64
1804 m_assembler.mtc1(MIPSRegisters::zero, scratch);
1805 m_assembler.mthc1(MIPSRegisters::zero, scratch);
1807 m_assembler.mtc1(MIPSRegisters::zero, scratch);
1808 m_assembler.mtc1(MIPSRegisters::zero, FPRegisterID(scratch + 1));
1810 return branchDouble(DoubleEqualOrUnordered, reg, scratch);
1819 // If m_fixedWidth is true, we will generate a fixed number of instructions.
1820 // Otherwise, we can emit any number of instructions.
1823 friend class LinkBuffer;
1824 friend class RepatchBuffer;
1826 static void linkCall(void* code, Call call, FunctionPtr function)
1828 MIPSAssembler::linkCall(code, call.m_label, function.value());
1831 static void repatchCall(CodeLocationCall call, CodeLocationLabel destination)
1833 MIPSAssembler::relinkCall(call.dataLocation(), destination.executableAddress());
1836 static void repatchCall(CodeLocationCall call, FunctionPtr destination)
1838 MIPSAssembler::relinkCall(call.dataLocation(), destination.executableAddress());
1845 #endif // ENABLE(ASSEMBLER) && CPU(MIPS)
1847 #endif // MacroAssemblerMIPS_h