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 bool isCompactPtrAlignedAddressOffset(ptrdiff_t value)
48 return value >= -2147483647 - 1 && value <= 2147483647;
51 static const Scale ScalePtr = TimesFour;
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;
63 static const FPRegisterID fpTempRegister = MIPSRegisters::f16;
65 static const int MaximumCompactPtrAlignedAddressOffset = 0x7FFFFFFF;
67 enum RelationalCondition {
80 enum ResultCondition {
87 enum DoubleCondition {
91 DoubleGreaterThanOrEqual,
93 DoubleLessThanOrEqual,
94 DoubleEqualOrUnordered,
95 DoubleNotEqualOrUnordered,
96 DoubleGreaterThanOrUnordered,
97 DoubleGreaterThanOrEqualOrUnordered,
98 DoubleLessThanOrUnordered,
99 DoubleLessThanOrEqualOrUnordered
102 static const RegisterID stackPointerRegister = MIPSRegisters::sp;
103 static const RegisterID returnAddressRegister = MIPSRegisters::ra;
105 // Integer arithmetic operations:
107 // Operations are typically two operand - operation(source, srcDst)
108 // For many operations the source may be an TrustedImm32, the srcDst operand
109 // may often be a memory location (explictly described using an Address
112 void add32(RegisterID src, RegisterID dest)
114 m_assembler.addu(dest, dest, src);
117 void add32(TrustedImm32 imm, RegisterID dest)
119 add32(imm, dest, dest);
122 void add32(TrustedImm32 imm, RegisterID src, RegisterID dest)
124 if (imm.m_value >= -32768 && imm.m_value <= 32767
129 m_assembler.addiu(dest, src, imm.m_value);
133 addu dest, src, immTemp
135 move(imm, immTempRegister);
136 m_assembler.addu(dest, src, immTempRegister);
140 void add32(RegisterID src, TrustedImm32 imm, RegisterID dest)
142 add32(imm, src, dest);
145 void add32(TrustedImm32 imm, Address address)
147 if (address.offset >= -32768 && address.offset <= 32767
150 lw dataTemp, offset(base)
152 addu dataTemp, dataTemp, immTemp
153 sw dataTemp, offset(base)
155 m_assembler.lw(dataTempRegister, address.base, address.offset);
156 if (imm.m_value >= -32768 && imm.m_value <= 32767
158 m_assembler.addiu(dataTempRegister, dataTempRegister,
161 move(imm, immTempRegister);
162 m_assembler.addu(dataTempRegister, dataTempRegister,
165 m_assembler.sw(dataTempRegister, address.base, address.offset);
168 lui addrTemp, (offset + 0x8000) >> 16
169 addu addrTemp, addrTemp, base
170 lw dataTemp, (offset & 0xffff)(addrTemp)
172 addu dataTemp, dataTemp, immTemp
173 sw dataTemp, (offset & 0xffff)(addrTemp)
175 m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16);
176 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
177 m_assembler.lw(dataTempRegister, addrTempRegister, address.offset);
179 if (imm.m_value >= -32768 && imm.m_value <= 32767 && !m_fixedWidth)
180 m_assembler.addiu(dataTempRegister, dataTempRegister,
183 move(imm, immTempRegister);
184 m_assembler.addu(dataTempRegister, dataTempRegister,
187 m_assembler.sw(dataTempRegister, addrTempRegister, address.offset);
191 void add32(Address src, RegisterID dest)
193 load32(src, dataTempRegister);
194 add32(dataTempRegister, dest);
197 void add32(AbsoluteAddress src, RegisterID dest)
199 load32(src.m_ptr, dataTempRegister);
200 add32(dataTempRegister, dest);
203 void add32(RegisterID src, Address dest)
205 if (dest.offset >= -32768 && dest.offset <= 32767 && !m_fixedWidth) {
207 lw dataTemp, offset(base)
208 addu dataTemp, dataTemp, src
209 sw dataTemp, offset(base)
211 m_assembler.lw(dataTempRegister, dest.base, dest.offset);
212 m_assembler.addu(dataTempRegister, dataTempRegister, src);
213 m_assembler.sw(dataTempRegister, dest.base, dest.offset);
216 lui addrTemp, (offset + 0x8000) >> 16
217 addu addrTemp, addrTemp, base
218 lw dataTemp, (offset & 0xffff)(addrTemp)
219 addu dataTemp, dataTemp, src
220 sw dataTemp, (offset & 0xffff)(addrTemp)
222 m_assembler.lui(addrTempRegister, (dest.offset + 0x8000) >> 16);
223 m_assembler.addu(addrTempRegister, addrTempRegister, dest.base);
224 m_assembler.lw(dataTempRegister, addrTempRegister, dest.offset);
225 m_assembler.addu(dataTempRegister, dataTempRegister, src);
226 m_assembler.sw(dataTempRegister, addrTempRegister, dest.offset);
230 void add32(TrustedImm32 imm, AbsoluteAddress address)
235 lw dataTemp, 0(addrTemp)
236 addu dataTemp, dataTemp, immTemp
237 sw dataTemp, 0(addrTemp)
239 move(TrustedImmPtr(address.m_ptr), addrTempRegister);
240 m_assembler.lw(dataTempRegister, addrTempRegister, 0);
241 if (imm.m_value >= -32768 && imm.m_value <= 32767
243 m_assembler.addiu(dataTempRegister, dataTempRegister, imm.m_value);
245 move(imm, immTempRegister);
246 m_assembler.addu(dataTempRegister, dataTempRegister, immTempRegister);
248 m_assembler.sw(dataTempRegister, addrTempRegister, 0);
251 void and32(RegisterID src, RegisterID dest)
253 m_assembler.andInsn(dest, dest, src);
256 void and32(TrustedImm32 imm, RegisterID dest)
258 if (!imm.m_value && !m_fixedWidth)
259 move(MIPSRegisters::zero, dest);
260 else if (imm.m_value > 0 && imm.m_value < 65535
262 m_assembler.andi(dest, dest, imm.m_value);
266 and dest, dest, immTemp
268 move(imm, immTempRegister);
269 m_assembler.andInsn(dest, dest, immTempRegister);
273 void lshift32(TrustedImm32 imm, RegisterID dest)
275 m_assembler.sll(dest, dest, imm.m_value);
278 void lshift32(RegisterID shiftAmount, RegisterID dest)
280 m_assembler.sllv(dest, dest, shiftAmount);
283 void mul32(RegisterID src, RegisterID dest)
285 m_assembler.mul(dest, dest, src);
288 void mul32(TrustedImm32 imm, RegisterID src, RegisterID dest)
290 if (!imm.m_value && !m_fixedWidth)
291 move(MIPSRegisters::zero, dest);
292 else if (imm.m_value == 1 && !m_fixedWidth)
297 mul dest, src, dataTemp
299 move(imm, dataTempRegister);
300 m_assembler.mul(dest, src, dataTempRegister);
304 void neg32(RegisterID srcDest)
306 m_assembler.subu(srcDest, MIPSRegisters::zero, srcDest);
309 void or32(RegisterID src, RegisterID dest)
311 m_assembler.orInsn(dest, dest, src);
314 void or32(RegisterID op1, RegisterID op2, RegisterID dest)
316 m_assembler.orInsn(dest, op1, op2);
319 void or32(TrustedImm32 imm, RegisterID dest)
321 if (!imm.m_value && !m_fixedWidth)
324 if (imm.m_value > 0 && imm.m_value < 65535
326 m_assembler.ori(dest, dest, imm.m_value);
332 or dest, dest, dataTemp
334 move(imm, dataTempRegister);
335 m_assembler.orInsn(dest, dest, dataTempRegister);
338 void rshift32(RegisterID shiftAmount, RegisterID dest)
340 m_assembler.srav(dest, dest, shiftAmount);
343 void rshift32(TrustedImm32 imm, RegisterID dest)
345 m_assembler.sra(dest, dest, imm.m_value);
348 void rshift32(RegisterID src, TrustedImm32 imm, RegisterID dest)
350 m_assembler.sra(dest, src, imm.m_value);
353 void urshift32(RegisterID shiftAmount, RegisterID dest)
355 m_assembler.srlv(dest, dest, shiftAmount);
358 void urshift32(TrustedImm32 imm, RegisterID dest)
360 m_assembler.srl(dest, dest, imm.m_value);
363 void sub32(RegisterID src, RegisterID dest)
365 m_assembler.subu(dest, dest, src);
368 void sub32(TrustedImm32 imm, RegisterID dest)
370 if (imm.m_value >= -32767 && imm.m_value <= 32768
375 m_assembler.addiu(dest, dest, -imm.m_value);
379 subu dest, src, immTemp
381 move(imm, immTempRegister);
382 m_assembler.subu(dest, dest, immTempRegister);
386 void sub32(RegisterID src, TrustedImm32 imm, RegisterID dest)
388 if (imm.m_value >= -32767 && imm.m_value <= 32768
393 m_assembler.addiu(dest, src, -imm.m_value);
397 subu dest, src, immTemp
399 move(imm, immTempRegister);
400 m_assembler.subu(dest, src, immTempRegister);
404 void sub32(TrustedImm32 imm, Address address)
406 if (address.offset >= -32768 && address.offset <= 32767
409 lw dataTemp, offset(base)
411 subu dataTemp, dataTemp, immTemp
412 sw dataTemp, offset(base)
414 m_assembler.lw(dataTempRegister, address.base, address.offset);
415 if (imm.m_value >= -32767 && imm.m_value <= 32768
417 m_assembler.addiu(dataTempRegister, dataTempRegister,
420 move(imm, immTempRegister);
421 m_assembler.subu(dataTempRegister, dataTempRegister,
424 m_assembler.sw(dataTempRegister, address.base, address.offset);
427 lui addrTemp, (offset + 0x8000) >> 16
428 addu addrTemp, addrTemp, base
429 lw dataTemp, (offset & 0xffff)(addrTemp)
431 subu dataTemp, dataTemp, immTemp
432 sw dataTemp, (offset & 0xffff)(addrTemp)
434 m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16);
435 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
436 m_assembler.lw(dataTempRegister, addrTempRegister, address.offset);
438 if (imm.m_value >= -32767 && imm.m_value <= 32768
440 m_assembler.addiu(dataTempRegister, dataTempRegister,
443 move(imm, immTempRegister);
444 m_assembler.subu(dataTempRegister, dataTempRegister,
447 m_assembler.sw(dataTempRegister, addrTempRegister, address.offset);
451 void sub32(Address src, RegisterID dest)
453 load32(src, dataTempRegister);
454 sub32(dataTempRegister, dest);
457 void sub32(TrustedImm32 imm, AbsoluteAddress address)
462 lw dataTemp, 0(addrTemp)
463 subu dataTemp, dataTemp, immTemp
464 sw dataTemp, 0(addrTemp)
466 move(TrustedImmPtr(address.m_ptr), addrTempRegister);
467 m_assembler.lw(dataTempRegister, addrTempRegister, 0);
469 if (imm.m_value >= -32767 && imm.m_value <= 32768
471 m_assembler.addiu(dataTempRegister, dataTempRegister,
474 move(imm, immTempRegister);
475 m_assembler.subu(dataTempRegister, dataTempRegister, immTempRegister);
477 m_assembler.sw(dataTempRegister, addrTempRegister, 0);
480 void xor32(RegisterID src, RegisterID dest)
482 m_assembler.xorInsn(dest, dest, src);
485 void xor32(TrustedImm32 imm, RegisterID dest)
487 if (imm.m_value == -1) {
488 m_assembler.nor(dest, dest, MIPSRegisters::zero);
494 xor dest, dest, immTemp
496 move(imm, immTempRegister);
497 m_assembler.xorInsn(dest, dest, immTempRegister);
500 void sqrtDouble(FPRegisterID src, FPRegisterID dst)
502 m_assembler.sqrtd(dst, src);
505 void absDouble(FPRegisterID, FPRegisterID)
507 ASSERT_NOT_REACHED();
510 ConvertibleLoadLabel convertibleLoadPtr(Address address, RegisterID dest)
512 ConvertibleLoadLabel result(this);
514 lui addrTemp, (offset + 0x8000) >> 16
515 addu addrTemp, addrTemp, base
516 lw dest, (offset & 0xffff)(addrTemp)
518 m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16);
519 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
520 m_assembler.lw(dest, addrTempRegister, address.offset);
524 // Memory access operations:
526 // Loads are of the form load(address, destination) and stores of the form
527 // store(source, address). The source for a store may be an TrustedImm32. Address
528 // operand objects to loads and store will be implicitly constructed if a
529 // register is passed.
531 /* Need to use zero-extened load byte for load8. */
532 void load8(ImplicitAddress address, RegisterID dest)
534 if (address.offset >= -32768 && address.offset <= 32767
536 m_assembler.lbu(dest, address.base, address.offset);
539 lui addrTemp, (offset + 0x8000) >> 16
540 addu addrTemp, addrTemp, base
541 lbu dest, (offset & 0xffff)(addrTemp)
543 m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16);
544 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
545 m_assembler.lbu(dest, addrTempRegister, address.offset);
549 void load8(BaseIndex address, RegisterID dest)
551 if (address.offset >= -32768 && address.offset <= 32767
554 sll addrTemp, address.index, address.scale
555 addu addrTemp, addrTemp, address.base
556 lbu dest, address.offset(addrTemp)
558 m_assembler.sll(addrTempRegister, address.index, address.scale);
559 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
560 m_assembler.lbu(dest, addrTempRegister, address.offset);
563 sll addrTemp, address.index, address.scale
564 addu addrTemp, addrTemp, address.base
565 lui immTemp, (address.offset + 0x8000) >> 16
566 addu addrTemp, addrTemp, immTemp
567 lbu dest, (address.offset & 0xffff)(at)
569 m_assembler.sll(addrTempRegister, address.index, address.scale);
570 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
571 m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16);
572 m_assembler.addu(addrTempRegister, addrTempRegister,
574 m_assembler.lbu(dest, addrTempRegister, address.offset);
578 void load32(ImplicitAddress address, RegisterID dest)
580 if (address.offset >= -32768 && address.offset <= 32767
582 m_assembler.lw(dest, address.base, address.offset);
585 lui addrTemp, (offset + 0x8000) >> 16
586 addu addrTemp, addrTemp, base
587 lw dest, (offset & 0xffff)(addrTemp)
589 m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16);
590 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
591 m_assembler.lw(dest, addrTempRegister, address.offset);
595 void load32(BaseIndex address, RegisterID dest)
597 if (address.offset >= -32768 && address.offset <= 32767
600 sll addrTemp, address.index, address.scale
601 addu addrTemp, addrTemp, address.base
602 lw dest, address.offset(addrTemp)
604 m_assembler.sll(addrTempRegister, address.index, address.scale);
605 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
606 m_assembler.lw(dest, addrTempRegister, address.offset);
609 sll addrTemp, address.index, address.scale
610 addu addrTemp, addrTemp, address.base
611 lui immTemp, (address.offset + 0x8000) >> 16
612 addu addrTemp, addrTemp, immTemp
613 lw dest, (address.offset & 0xffff)(at)
615 m_assembler.sll(addrTempRegister, address.index, address.scale);
616 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
617 m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16);
618 m_assembler.addu(addrTempRegister, addrTempRegister,
620 m_assembler.lw(dest, addrTempRegister, address.offset);
624 void load16Unaligned(BaseIndex address, RegisterID dest)
626 load16(address, dest);
629 void load32WithUnalignedHalfWords(BaseIndex address, RegisterID dest)
631 if (address.offset >= -32768 && address.offset <= 32764
634 sll addrTemp, address.index, address.scale
635 addu addrTemp, addrTemp, address.base
637 lwl dest, address.offset(addrTemp)
638 lwr dest, address.offset+3(addrTemp)
640 lwl dest, address.offset+3(addrTemp)
641 lwr dest, address.offset(addrTemp)
643 m_assembler.sll(addrTempRegister, address.index, address.scale);
644 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
646 m_assembler.lwl(dest, addrTempRegister, address.offset);
647 m_assembler.lwr(dest, addrTempRegister, address.offset + 3);
649 m_assembler.lwl(dest, addrTempRegister, address.offset + 3);
650 m_assembler.lwr(dest, addrTempRegister, address.offset);
655 sll addrTemp, address.index, address.scale
656 addu addrTemp, addrTemp, address.base
657 lui immTemp, address.offset >> 16
658 ori immTemp, immTemp, address.offset & 0xffff
659 addu addrTemp, addrTemp, immTemp
667 m_assembler.sll(addrTempRegister, address.index, address.scale);
668 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
669 m_assembler.lui(immTempRegister, address.offset >> 16);
670 m_assembler.ori(immTempRegister, immTempRegister, address.offset);
671 m_assembler.addu(addrTempRegister, addrTempRegister,
674 m_assembler.lwl(dest, addrTempRegister, 0);
675 m_assembler.lwr(dest, addrTempRegister, 3);
677 m_assembler.lwl(dest, addrTempRegister, 3);
678 m_assembler.lwr(dest, addrTempRegister, 0);
683 void load32(const void* address, RegisterID dest)
689 move(TrustedImmPtr(address), addrTempRegister);
690 m_assembler.lw(dest, addrTempRegister, 0);
693 DataLabel32 load32WithAddressOffsetPatch(Address address, RegisterID dest)
697 lui addrTemp, address.offset >> 16
698 ori addrTemp, addrTemp, address.offset & 0xffff
699 addu addrTemp, addrTemp, address.base
702 DataLabel32 dataLabel(this);
703 move(TrustedImm32(address.offset), addrTempRegister);
704 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
705 m_assembler.lw(dest, addrTempRegister, 0);
706 m_fixedWidth = false;
710 DataLabelCompact load32WithCompactAddressOffsetPatch(Address address, RegisterID dest)
712 DataLabelCompact dataLabel(this);
713 load32WithAddressOffsetPatch(address, dest);
717 /* Need to use zero-extened load half-word for load16. */
718 void load16(ImplicitAddress address, RegisterID dest)
720 if (address.offset >= -32768 && address.offset <= 32767
722 m_assembler.lhu(dest, address.base, address.offset);
725 lui addrTemp, (offset + 0x8000) >> 16
726 addu addrTemp, addrTemp, base
727 lhu dest, (offset & 0xffff)(addrTemp)
729 m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16);
730 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
731 m_assembler.lhu(dest, addrTempRegister, address.offset);
735 /* Need to use zero-extened load half-word for load16. */
736 void load16(BaseIndex address, RegisterID dest)
738 if (address.offset >= -32768 && address.offset <= 32767
741 sll addrTemp, address.index, address.scale
742 addu addrTemp, addrTemp, address.base
743 lhu dest, address.offset(addrTemp)
745 m_assembler.sll(addrTempRegister, address.index, address.scale);
746 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
747 m_assembler.lhu(dest, addrTempRegister, address.offset);
750 sll addrTemp, address.index, address.scale
751 addu addrTemp, addrTemp, address.base
752 lui immTemp, (address.offset + 0x8000) >> 16
753 addu addrTemp, addrTemp, immTemp
754 lhu dest, (address.offset & 0xffff)(addrTemp)
756 m_assembler.sll(addrTempRegister, address.index, address.scale);
757 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
758 m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16);
759 m_assembler.addu(addrTempRegister, addrTempRegister,
761 m_assembler.lhu(dest, addrTempRegister, address.offset);
765 DataLabel32 store32WithAddressOffsetPatch(RegisterID src, Address address)
769 lui addrTemp, address.offset >> 16
770 ori addrTemp, addrTemp, address.offset & 0xffff
771 addu addrTemp, addrTemp, address.base
774 DataLabel32 dataLabel(this);
775 move(TrustedImm32(address.offset), addrTempRegister);
776 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
777 m_assembler.sw(src, addrTempRegister, 0);
778 m_fixedWidth = false;
782 void store32(RegisterID src, ImplicitAddress address)
784 if (address.offset >= -32768 && address.offset <= 32767
786 m_assembler.sw(src, address.base, address.offset);
789 lui addrTemp, (offset + 0x8000) >> 16
790 addu addrTemp, addrTemp, base
791 sw src, (offset & 0xffff)(addrTemp)
793 m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16);
794 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
795 m_assembler.sw(src, addrTempRegister, address.offset);
799 void store32(RegisterID src, BaseIndex address)
801 if (address.offset >= -32768 && address.offset <= 32767
804 sll addrTemp, address.index, address.scale
805 addu addrTemp, addrTemp, address.base
806 sw src, address.offset(addrTemp)
808 m_assembler.sll(addrTempRegister, address.index, address.scale);
809 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
810 m_assembler.sw(src, addrTempRegister, address.offset);
813 sll addrTemp, address.index, address.scale
814 addu addrTemp, addrTemp, address.base
815 lui immTemp, (address.offset + 0x8000) >> 16
816 addu addrTemp, addrTemp, immTemp
817 sw src, (address.offset & 0xffff)(at)
819 m_assembler.sll(addrTempRegister, address.index, address.scale);
820 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
821 m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16);
822 m_assembler.addu(addrTempRegister, addrTempRegister,
824 m_assembler.sw(src, addrTempRegister, address.offset);
828 void store32(TrustedImm32 imm, ImplicitAddress address)
830 if (address.offset >= -32768 && address.offset <= 32767
833 m_assembler.sw(MIPSRegisters::zero, address.base,
836 move(imm, immTempRegister);
837 m_assembler.sw(immTempRegister, address.base, address.offset);
841 lui addrTemp, (offset + 0x8000) >> 16
842 addu addrTemp, addrTemp, base
843 sw immTemp, (offset & 0xffff)(addrTemp)
845 m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16);
846 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
847 if (!imm.m_value && !m_fixedWidth)
848 m_assembler.sw(MIPSRegisters::zero, addrTempRegister,
851 move(imm, immTempRegister);
852 m_assembler.sw(immTempRegister, addrTempRegister,
858 void store32(RegisterID src, const void* address)
864 move(TrustedImmPtr(address), addrTempRegister);
865 m_assembler.sw(src, addrTempRegister, 0);
868 void store32(TrustedImm32 imm, const void* address)
875 if (!imm.m_value && !m_fixedWidth) {
876 move(TrustedImmPtr(address), addrTempRegister);
877 m_assembler.sw(MIPSRegisters::zero, addrTempRegister, 0);
879 move(imm, immTempRegister);
880 move(TrustedImmPtr(address), addrTempRegister);
881 m_assembler.sw(immTempRegister, addrTempRegister, 0);
885 // Floating-point operations:
887 static bool supportsFloatingPoint()
889 #if WTF_MIPS_DOUBLE_FLOAT
896 static bool supportsFloatingPointTruncate()
898 #if WTF_MIPS_DOUBLE_FLOAT && WTF_MIPS_ISA_AT_LEAST(2)
905 static bool supportsFloatingPointSqrt()
907 #if WTF_MIPS_DOUBLE_FLOAT && WTF_MIPS_ISA_AT_LEAST(2)
913 static bool supportsFloatingPointAbs() { return false; }
915 // Stack manipulation operations:
917 // The ABI is assumed to provide a stack abstraction to memory,
918 // containing machine word sized units of data. Push and pop
919 // operations add and remove a single register sized unit of data
920 // to or from the stack. Peek and poke operations read or write
921 // values on the stack, without moving the current stack position.
923 void pop(RegisterID dest)
925 m_assembler.lw(dest, MIPSRegisters::sp, 0);
926 m_assembler.addiu(MIPSRegisters::sp, MIPSRegisters::sp, 4);
929 void push(RegisterID src)
931 m_assembler.addiu(MIPSRegisters::sp, MIPSRegisters::sp, -4);
932 m_assembler.sw(src, MIPSRegisters::sp, 0);
935 void push(Address address)
937 load32(address, dataTempRegister);
938 push(dataTempRegister);
941 void push(TrustedImm32 imm)
943 move(imm, immTempRegister);
944 push(immTempRegister);
947 // Register move operations:
949 // Move values in registers.
951 void move(TrustedImm32 imm, RegisterID dest)
953 if (!imm.m_value && !m_fixedWidth)
954 move(MIPSRegisters::zero, dest);
955 else if (m_fixedWidth) {
956 m_assembler.lui(dest, imm.m_value >> 16);
957 m_assembler.ori(dest, dest, imm.m_value);
959 m_assembler.li(dest, imm.m_value);
962 void move(RegisterID src, RegisterID dest)
964 if (src != dest || m_fixedWidth)
965 m_assembler.move(dest, src);
968 void move(TrustedImmPtr imm, RegisterID dest)
970 move(TrustedImm32(imm), dest);
973 void swap(RegisterID reg1, RegisterID reg2)
975 move(reg1, immTempRegister);
977 move(immTempRegister, reg2);
980 void signExtend32ToPtr(RegisterID src, RegisterID dest)
982 if (src != dest || m_fixedWidth)
986 void zeroExtend32ToPtr(RegisterID src, RegisterID dest)
988 if (src != dest || m_fixedWidth)
992 // Forwards / external control flow operations:
994 // This set of jump and conditional branch operations return a Jump
995 // object which may linked at a later point, allow forwards jump,
996 // or jumps that will require external linkage (after the code has been
999 // For branches, signed <, >, <= and >= are denoted as l, g, le, and ge
1000 // respecitvely, for unsigned comparisons the names b, a, be, and ae are
1001 // used (representing the names 'below' and 'above').
1003 // Operands to the comparision are provided in the expected order, e.g.
1004 // jle32(reg1, TrustedImm32(5)) will branch if the value held in reg1, when
1005 // treated as a signed 32bit value, is less than or equal to 5.
1007 // jz and jnz test whether the first operand is equal to zero, and take
1008 // an optional second operand of a mask under which to perform the test.
1010 Jump branch8(RelationalCondition cond, Address left, TrustedImm32 right)
1012 // Make sure the immediate value is unsigned 8 bits.
1013 ASSERT(!(right.m_value & 0xFFFFFF00));
1014 load8(left, dataTempRegister);
1015 move(right, immTempRegister);
1016 return branch32(cond, dataTempRegister, immTempRegister);
1019 void compare8(RelationalCondition cond, Address left, TrustedImm32 right, RegisterID dest)
1021 // Make sure the immediate value is unsigned 8 bits.
1022 ASSERT(!(right.m_value & 0xFFFFFF00));
1023 load8(left, dataTempRegister);
1024 move(right, immTempRegister);
1025 compare32(cond, dataTempRegister, immTempRegister, dest);
1028 Jump branch8(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
1030 ASSERT(!(right.m_value & 0xFFFFFF00));
1031 load8(left, dataTempRegister);
1032 // Be careful that the previous load8() uses immTempRegister.
1033 // So, we need to put move() after load8().
1034 move(right, immTempRegister);
1035 return branch32(cond, dataTempRegister, immTempRegister);
1038 Jump branch32(RelationalCondition cond, RegisterID left, RegisterID right)
1041 return branchEqual(left, right);
1042 if (cond == NotEqual)
1043 return branchNotEqual(left, right);
1044 if (cond == Above) {
1045 m_assembler.sltu(cmpTempRegister, right, left);
1046 return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
1048 if (cond == AboveOrEqual) {
1049 m_assembler.sltu(cmpTempRegister, left, right);
1050 return branchEqual(cmpTempRegister, MIPSRegisters::zero);
1052 if (cond == Below) {
1053 m_assembler.sltu(cmpTempRegister, left, right);
1054 return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
1056 if (cond == BelowOrEqual) {
1057 m_assembler.sltu(cmpTempRegister, right, left);
1058 return branchEqual(cmpTempRegister, MIPSRegisters::zero);
1060 if (cond == GreaterThan) {
1061 m_assembler.slt(cmpTempRegister, right, left);
1062 return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
1064 if (cond == GreaterThanOrEqual) {
1065 m_assembler.slt(cmpTempRegister, left, right);
1066 return branchEqual(cmpTempRegister, MIPSRegisters::zero);
1068 if (cond == LessThan) {
1069 m_assembler.slt(cmpTempRegister, left, right);
1070 return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
1072 if (cond == LessThanOrEqual) {
1073 m_assembler.slt(cmpTempRegister, right, left);
1074 return branchEqual(cmpTempRegister, MIPSRegisters::zero);
1081 Jump branch32(RelationalCondition cond, RegisterID left, TrustedImm32 right)
1083 move(right, immTempRegister);
1084 return branch32(cond, left, immTempRegister);
1087 Jump branch32(RelationalCondition cond, RegisterID left, Address right)
1089 load32(right, dataTempRegister);
1090 return branch32(cond, left, dataTempRegister);
1093 Jump branch32(RelationalCondition cond, Address left, RegisterID right)
1095 load32(left, dataTempRegister);
1096 return branch32(cond, dataTempRegister, right);
1099 Jump branch32(RelationalCondition cond, Address left, TrustedImm32 right)
1101 load32(left, dataTempRegister);
1102 move(right, immTempRegister);
1103 return branch32(cond, dataTempRegister, immTempRegister);
1106 Jump branch32(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
1108 load32(left, dataTempRegister);
1109 // Be careful that the previous load32() uses immTempRegister.
1110 // So, we need to put move() after load32().
1111 move(right, immTempRegister);
1112 return branch32(cond, dataTempRegister, immTempRegister);
1115 Jump branch32WithUnalignedHalfWords(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
1117 load32WithUnalignedHalfWords(left, dataTempRegister);
1118 // Be careful that the previous load32WithUnalignedHalfWords()
1119 // uses immTempRegister.
1120 // So, we need to put move() after load32WithUnalignedHalfWords().
1121 move(right, immTempRegister);
1122 return branch32(cond, dataTempRegister, immTempRegister);
1125 Jump branch32(RelationalCondition cond, AbsoluteAddress left, RegisterID right)
1127 load32(left.m_ptr, dataTempRegister);
1128 return branch32(cond, dataTempRegister, right);
1131 Jump branch32(RelationalCondition cond, AbsoluteAddress left, TrustedImm32 right)
1133 load32(left.m_ptr, dataTempRegister);
1134 move(right, immTempRegister);
1135 return branch32(cond, dataTempRegister, immTempRegister);
1138 Jump branchTest32(ResultCondition cond, RegisterID reg, RegisterID mask)
1140 ASSERT((cond == Zero) || (cond == NonZero));
1141 m_assembler.andInsn(cmpTempRegister, reg, mask);
1143 return branchEqual(cmpTempRegister, MIPSRegisters::zero);
1144 return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
1147 Jump branchTest32(ResultCondition cond, RegisterID reg, TrustedImm32 mask = TrustedImm32(-1))
1149 ASSERT((cond == Zero) || (cond == NonZero));
1150 if (mask.m_value == -1 && !m_fixedWidth) {
1152 return branchEqual(reg, MIPSRegisters::zero);
1153 return branchNotEqual(reg, MIPSRegisters::zero);
1155 move(mask, immTempRegister);
1156 return branchTest32(cond, reg, immTempRegister);
1159 Jump branchTest32(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
1161 load32(address, dataTempRegister);
1162 return branchTest32(cond, dataTempRegister, mask);
1165 Jump branchTest32(ResultCondition cond, BaseIndex address, TrustedImm32 mask = TrustedImm32(-1))
1167 load32(address, dataTempRegister);
1168 return branchTest32(cond, dataTempRegister, mask);
1171 Jump branchTest8(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
1173 load8(address, dataTempRegister);
1174 return branchTest32(cond, dataTempRegister, mask);
1177 Jump branchTest8(ResultCondition cond, AbsoluteAddress address, TrustedImm32 mask = TrustedImm32(-1))
1179 move(TrustedImmPtr(address.m_ptr), dataTempRegister);
1180 load8(Address(dataTempRegister), dataTempRegister);
1181 return branchTest32(cond, dataTempRegister, mask);
1186 return branchEqual(MIPSRegisters::zero, MIPSRegisters::zero);
1189 void jump(RegisterID target)
1191 m_assembler.jr(target);
1195 void jump(Address address)
1197 m_fixedWidth = true;
1198 load32(address, MIPSRegisters::t9);
1199 m_assembler.jr(MIPSRegisters::t9);
1201 m_fixedWidth = false;
1204 // Arithmetic control flow operations:
1206 // This set of conditional branch operations branch based
1207 // on the result of an arithmetic operation. The operation
1208 // is performed as normal, storing the result.
1210 // * jz operations branch if the result is zero.
1211 // * jo operations branch if the (signed) arithmetic
1212 // operation caused an overflow to occur.
1214 Jump branchAdd32(ResultCondition cond, RegisterID src, RegisterID dest)
1216 ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
1217 if (cond == Overflow) {
1220 xor cmpTemp, dataTemp, src
1221 bltz cmpTemp, No_overflow # diff sign bit -> no overflow
1222 addu dest, dataTemp, src
1223 xor cmpTemp, dest, dataTemp
1224 bgez cmpTemp, No_overflow # same sign big -> no overflow
1234 move(dest, dataTempRegister);
1235 m_assembler.xorInsn(cmpTempRegister, dataTempRegister, src);
1236 m_assembler.bltz(cmpTempRegister, 10);
1237 m_assembler.addu(dest, dataTempRegister, src);
1238 m_assembler.xorInsn(cmpTempRegister, dest, dataTempRegister);
1239 m_assembler.bgez(cmpTempRegister, 7);
1243 if (cond == Signed) {
1245 // Check if dest is negative.
1246 m_assembler.slt(cmpTempRegister, dest, MIPSRegisters::zero);
1247 return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
1251 return branchEqual(dest, MIPSRegisters::zero);
1253 if (cond == NonZero) {
1255 return branchNotEqual(dest, MIPSRegisters::zero);
1261 Jump branchAdd32(ResultCondition cond, TrustedImm32 imm, RegisterID dest)
1263 move(imm, immTempRegister);
1264 return branchAdd32(cond, immTempRegister, dest);
1267 Jump branchAdd32(ResultCondition cond, RegisterID src, TrustedImm32 imm, RegisterID dest)
1269 move(imm, immTempRegister);
1271 return branchAdd32(cond, immTempRegister, dest);
1274 Jump branchMul32(ResultCondition cond, RegisterID src, RegisterID dest)
1276 ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
1277 if (cond == Overflow) {
1282 sra addrTemp, dest, 31
1283 beq dataTemp, addrTemp, No_overflow # all sign bits (bit 63 to bit 31) are the same -> no overflow
1293 m_assembler.mult(src, dest);
1294 m_assembler.mfhi(dataTempRegister);
1295 m_assembler.mflo(dest);
1296 m_assembler.sra(addrTempRegister, dest, 31);
1297 m_assembler.beq(dataTempRegister, addrTempRegister, 7);
1301 if (cond == Signed) {
1303 // Check if dest is negative.
1304 m_assembler.slt(cmpTempRegister, dest, MIPSRegisters::zero);
1305 return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
1309 return branchEqual(dest, MIPSRegisters::zero);
1311 if (cond == NonZero) {
1313 return branchNotEqual(dest, MIPSRegisters::zero);
1319 Jump branchMul32(ResultCondition cond, TrustedImm32 imm, RegisterID src, RegisterID dest)
1321 move(imm, immTempRegister);
1323 return branchMul32(cond, immTempRegister, dest);
1326 Jump branchSub32(ResultCondition cond, RegisterID src, RegisterID dest)
1328 ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
1329 if (cond == Overflow) {
1332 xor cmpTemp, dataTemp, src
1333 bgez cmpTemp, No_overflow # same sign bit -> no overflow
1334 subu dest, dataTemp, src
1335 xor cmpTemp, dest, dataTemp
1336 bgez cmpTemp, No_overflow # same sign bit -> no overflow
1346 move(dest, dataTempRegister);
1347 m_assembler.xorInsn(cmpTempRegister, dataTempRegister, src);
1348 m_assembler.bgez(cmpTempRegister, 10);
1349 m_assembler.subu(dest, dataTempRegister, src);
1350 m_assembler.xorInsn(cmpTempRegister, dest, dataTempRegister);
1351 m_assembler.bgez(cmpTempRegister, 7);
1355 if (cond == Signed) {
1357 // Check if dest is negative.
1358 m_assembler.slt(cmpTempRegister, dest, MIPSRegisters::zero);
1359 return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
1363 return branchEqual(dest, MIPSRegisters::zero);
1365 if (cond == NonZero) {
1367 return branchNotEqual(dest, MIPSRegisters::zero);
1373 Jump branchSub32(ResultCondition cond, TrustedImm32 imm, RegisterID dest)
1375 move(imm, immTempRegister);
1376 return branchSub32(cond, immTempRegister, dest);
1379 Jump branchSub32(ResultCondition cond, RegisterID src, TrustedImm32 imm, RegisterID dest)
1381 move(imm, immTempRegister);
1383 return branchSub32(cond, immTempRegister, dest);
1386 Jump branchOr32(ResultCondition cond, RegisterID src, RegisterID dest)
1388 ASSERT((cond == Signed) || (cond == Zero) || (cond == NonZero));
1389 if (cond == Signed) {
1391 // Check if dest is negative.
1392 m_assembler.slt(cmpTempRegister, dest, MIPSRegisters::zero);
1393 return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
1397 return branchEqual(dest, MIPSRegisters::zero);
1399 if (cond == NonZero) {
1401 return branchNotEqual(dest, MIPSRegisters::zero);
1407 // Miscellaneous operations:
1416 /* We need two words for relaxation. */
1421 return Call(m_assembler.label(), Call::LinkableNear);
1426 m_assembler.lui(MIPSRegisters::t9, 0);
1427 m_assembler.ori(MIPSRegisters::t9, MIPSRegisters::t9, 0);
1428 m_assembler.jalr(MIPSRegisters::t9);
1430 return Call(m_assembler.label(), Call::Linkable);
1433 Call call(RegisterID target)
1435 m_assembler.jalr(target);
1437 return Call(m_assembler.label(), Call::None);
1440 Call call(Address address)
1442 m_fixedWidth = true;
1443 load32(address, MIPSRegisters::t9);
1444 m_assembler.jalr(MIPSRegisters::t9);
1446 m_fixedWidth = false;
1447 return Call(m_assembler.label(), Call::None);
1452 m_assembler.jr(MIPSRegisters::ra);
1456 void compare32(RelationalCondition cond, RegisterID left, RegisterID right, RegisterID dest)
1458 if (cond == Equal) {
1459 m_assembler.xorInsn(dest, left, right);
1460 m_assembler.sltiu(dest, dest, 1);
1461 } else if (cond == NotEqual) {
1462 m_assembler.xorInsn(dest, left, right);
1463 m_assembler.sltu(dest, MIPSRegisters::zero, dest);
1464 } else if (cond == Above)
1465 m_assembler.sltu(dest, right, left);
1466 else if (cond == AboveOrEqual) {
1467 m_assembler.sltu(dest, left, right);
1468 m_assembler.xori(dest, dest, 1);
1469 } else if (cond == Below)
1470 m_assembler.sltu(dest, left, right);
1471 else if (cond == BelowOrEqual) {
1472 m_assembler.sltu(dest, right, left);
1473 m_assembler.xori(dest, dest, 1);
1474 } else if (cond == GreaterThan)
1475 m_assembler.slt(dest, right, left);
1476 else if (cond == GreaterThanOrEqual) {
1477 m_assembler.slt(dest, left, right);
1478 m_assembler.xori(dest, dest, 1);
1479 } else if (cond == LessThan)
1480 m_assembler.slt(dest, left, right);
1481 else if (cond == LessThanOrEqual) {
1482 m_assembler.slt(dest, right, left);
1483 m_assembler.xori(dest, dest, 1);
1487 void compare32(RelationalCondition cond, RegisterID left, TrustedImm32 right, RegisterID dest)
1489 move(right, immTempRegister);
1490 compare32(cond, left, immTempRegister, dest);
1493 void test8(ResultCondition cond, Address address, TrustedImm32 mask, RegisterID dest)
1495 ASSERT((cond == Zero) || (cond == NonZero));
1496 load8(address, dataTempRegister);
1497 if (mask.m_value == -1 && !m_fixedWidth) {
1499 m_assembler.sltiu(dest, dataTempRegister, 1);
1501 m_assembler.sltu(dest, MIPSRegisters::zero, dataTempRegister);
1503 move(mask, immTempRegister);
1504 m_assembler.andInsn(cmpTempRegister, dataTempRegister,
1507 m_assembler.sltiu(dest, cmpTempRegister, 1);
1509 m_assembler.sltu(dest, MIPSRegisters::zero, cmpTempRegister);
1513 void test32(ResultCondition cond, Address address, TrustedImm32 mask, RegisterID dest)
1515 ASSERT((cond == Zero) || (cond == NonZero));
1516 load32(address, dataTempRegister);
1517 if (mask.m_value == -1 && !m_fixedWidth) {
1519 m_assembler.sltiu(dest, dataTempRegister, 1);
1521 m_assembler.sltu(dest, MIPSRegisters::zero, dataTempRegister);
1523 move(mask, immTempRegister);
1524 m_assembler.andInsn(cmpTempRegister, dataTempRegister,
1527 m_assembler.sltiu(dest, cmpTempRegister, 1);
1529 m_assembler.sltu(dest, MIPSRegisters::zero, cmpTempRegister);
1533 DataLabel32 moveWithPatch(TrustedImm32 imm, RegisterID dest)
1535 m_fixedWidth = true;
1536 DataLabel32 label(this);
1538 m_fixedWidth = false;
1542 DataLabelPtr moveWithPatch(TrustedImmPtr initialValue, RegisterID dest)
1544 m_fixedWidth = true;
1545 DataLabelPtr label(this);
1546 move(initialValue, dest);
1547 m_fixedWidth = false;
1551 Jump branchPtrWithPatch(RelationalCondition cond, RegisterID left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
1553 m_fixedWidth = true;
1554 dataLabel = moveWithPatch(initialRightValue, immTempRegister);
1555 Jump temp = branch32(cond, left, immTempRegister);
1556 m_fixedWidth = false;
1560 Jump branchPtrWithPatch(RelationalCondition cond, Address left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
1562 m_fixedWidth = true;
1563 load32(left, dataTempRegister);
1564 dataLabel = moveWithPatch(initialRightValue, immTempRegister);
1565 Jump temp = branch32(cond, dataTempRegister, immTempRegister);
1566 m_fixedWidth = false;
1570 DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address)
1572 m_fixedWidth = true;
1573 DataLabelPtr dataLabel = moveWithPatch(initialValue, dataTempRegister);
1574 store32(dataTempRegister, address);
1575 m_fixedWidth = false;
1579 DataLabelPtr storePtrWithPatch(ImplicitAddress address)
1581 return storePtrWithPatch(TrustedImmPtr(0), address);
1584 Call tailRecursiveCall()
1586 // Like a normal call, but don't update the returned address register
1587 m_fixedWidth = true;
1588 move(TrustedImm32(0), MIPSRegisters::t9);
1589 m_assembler.jr(MIPSRegisters::t9);
1591 m_fixedWidth = false;
1592 return Call(m_assembler.label(), Call::Linkable);
1595 Call makeTailRecursiveCall(Jump oldJump)
1598 return tailRecursiveCall();
1601 void loadDouble(ImplicitAddress address, FPRegisterID dest)
1605 li addrTemp, address.offset
1606 addu addrTemp, addrTemp, base
1607 lwc1 dest, 0(addrTemp)
1608 lwc1 dest+1, 4(addrTemp)
1610 move(TrustedImm32(address.offset), addrTempRegister);
1611 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
1612 m_assembler.lwc1(dest, addrTempRegister, 0);
1613 m_assembler.lwc1(FPRegisterID(dest + 1), addrTempRegister, 4);
1615 if (address.offset >= -32768 && address.offset <= 32767
1617 m_assembler.ldc1(dest, address.base, address.offset);
1620 lui addrTemp, (offset + 0x8000) >> 16
1621 addu addrTemp, addrTemp, base
1622 ldc1 dest, (offset & 0xffff)(addrTemp)
1624 m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16);
1625 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
1626 m_assembler.ldc1(dest, addrTempRegister, address.offset);
1631 void loadDouble(const void* address, FPRegisterID dest)
1635 li addrTemp, address
1636 lwc1 dest, 0(addrTemp)
1637 lwc1 dest+1, 4(addrTemp)
1639 move(TrustedImmPtr(address), addrTempRegister);
1640 m_assembler.lwc1(dest, addrTempRegister, 0);
1641 m_assembler.lwc1(FPRegisterID(dest + 1), addrTempRegister, 4);
1644 li addrTemp, address
1645 ldc1 dest, 0(addrTemp)
1647 move(TrustedImmPtr(address), addrTempRegister);
1648 m_assembler.ldc1(dest, addrTempRegister, 0);
1653 void storeDouble(FPRegisterID src, ImplicitAddress address)
1657 li addrTemp, address.offset
1658 addu addrTemp, addrTemp, base
1659 swc1 dest, 0(addrTemp)
1660 swc1 dest+1, 4(addrTemp)
1662 move(TrustedImm32(address.offset), addrTempRegister);
1663 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
1664 m_assembler.swc1(src, addrTempRegister, 0);
1665 m_assembler.swc1(FPRegisterID(src + 1), addrTempRegister, 4);
1667 if (address.offset >= -32768 && address.offset <= 32767
1669 m_assembler.sdc1(src, address.base, address.offset);
1672 lui addrTemp, (offset + 0x8000) >> 16
1673 addu addrTemp, addrTemp, base
1674 sdc1 src, (offset & 0xffff)(addrTemp)
1676 m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16);
1677 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
1678 m_assembler.sdc1(src, addrTempRegister, address.offset);
1683 void addDouble(FPRegisterID src, FPRegisterID dest)
1685 m_assembler.addd(dest, dest, src);
1688 void addDouble(Address src, FPRegisterID dest)
1690 loadDouble(src, fpTempRegister);
1691 m_assembler.addd(dest, dest, fpTempRegister);
1694 void subDouble(FPRegisterID src, FPRegisterID dest)
1696 m_assembler.subd(dest, dest, src);
1699 void subDouble(Address src, FPRegisterID dest)
1701 loadDouble(src, fpTempRegister);
1702 m_assembler.subd(dest, dest, fpTempRegister);
1705 void mulDouble(FPRegisterID src, FPRegisterID dest)
1707 m_assembler.muld(dest, dest, src);
1710 void mulDouble(Address src, FPRegisterID dest)
1712 loadDouble(src, fpTempRegister);
1713 m_assembler.muld(dest, dest, fpTempRegister);
1716 void divDouble(FPRegisterID src, FPRegisterID dest)
1718 m_assembler.divd(dest, dest, src);
1721 void convertInt32ToDouble(RegisterID src, FPRegisterID dest)
1723 m_assembler.mtc1(src, fpTempRegister);
1724 m_assembler.cvtdw(dest, fpTempRegister);
1727 void convertInt32ToDouble(Address src, FPRegisterID dest)
1729 load32(src, dataTempRegister);
1730 m_assembler.mtc1(dataTempRegister, fpTempRegister);
1731 m_assembler.cvtdw(dest, fpTempRegister);
1734 void convertInt32ToDouble(AbsoluteAddress src, FPRegisterID dest)
1736 load32(src.m_ptr, dataTempRegister);
1737 m_assembler.mtc1(dataTempRegister, fpTempRegister);
1738 m_assembler.cvtdw(dest, fpTempRegister);
1741 void insertRelaxationWords()
1743 /* We need four words for relaxation. */
1744 m_assembler.beq(MIPSRegisters::zero, MIPSRegisters::zero, 3); // Jump over nops;
1752 m_assembler.appendJump();
1755 insertRelaxationWords();
1756 return Jump(m_assembler.label());
1761 m_assembler.appendJump();
1764 insertRelaxationWords();
1765 return Jump(m_assembler.label());
1768 Jump branchEqual(RegisterID rs, RegisterID rt)
1770 m_assembler.appendJump();
1771 m_assembler.beq(rs, rt, 0);
1773 insertRelaxationWords();
1774 return Jump(m_assembler.label());
1777 Jump branchNotEqual(RegisterID rs, RegisterID rt)
1779 m_assembler.appendJump();
1780 m_assembler.bne(rs, rt, 0);
1782 insertRelaxationWords();
1783 return Jump(m_assembler.label());
1786 Jump branchDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right)
1788 if (cond == DoubleEqual) {
1789 m_assembler.ceqd(left, right);
1790 return branchTrue();
1792 if (cond == DoubleNotEqual) {
1793 m_assembler.cueqd(left, right);
1794 return branchFalse(); // false
1796 if (cond == DoubleGreaterThan) {
1797 m_assembler.cngtd(left, right);
1798 return branchFalse(); // false
1800 if (cond == DoubleGreaterThanOrEqual) {
1801 m_assembler.cnged(left, right);
1802 return branchFalse(); // false
1804 if (cond == DoubleLessThan) {
1805 m_assembler.cltd(left, right);
1806 return branchTrue();
1808 if (cond == DoubleLessThanOrEqual) {
1809 m_assembler.cled(left, right);
1810 return branchTrue();
1812 if (cond == DoubleEqualOrUnordered) {
1813 m_assembler.cueqd(left, right);
1814 return branchTrue();
1816 if (cond == DoubleNotEqualOrUnordered) {
1817 m_assembler.ceqd(left, right);
1818 return branchFalse(); // false
1820 if (cond == DoubleGreaterThanOrUnordered) {
1821 m_assembler.coled(left, right);
1822 return branchFalse(); // false
1824 if (cond == DoubleGreaterThanOrEqualOrUnordered) {
1825 m_assembler.coltd(left, right);
1826 return branchFalse(); // false
1828 if (cond == DoubleLessThanOrUnordered) {
1829 m_assembler.cultd(left, right);
1830 return branchTrue();
1832 if (cond == DoubleLessThanOrEqualOrUnordered) {
1833 m_assembler.culed(left, right);
1834 return branchTrue();
1841 // Truncates 'src' to an integer, and places the resulting 'dest'.
1842 // If the result is not representable as a 32 bit value, branch.
1843 // May also branch for some values that are representable in 32 bits
1844 // (specifically, in this case, INT_MAX 0x7fffffff).
1845 Jump branchTruncateDoubleToInt32(FPRegisterID src, RegisterID dest)
1847 m_assembler.truncwd(fpTempRegister, src);
1848 m_assembler.mfc1(dest, fpTempRegister);
1849 return branch32(Equal, dest, TrustedImm32(0x7fffffff));
1852 // Convert 'src' to an integer, and places the resulting 'dest'.
1853 // If the result is not representable as a 32 bit value, branch.
1854 // May also branch for some values that are representable in 32 bits
1855 // (specifically, in this case, 0).
1856 void branchConvertDoubleToInt32(FPRegisterID src, RegisterID dest, JumpList& failureCases, FPRegisterID fpTemp, bool negZeroCheck = true)
1858 m_assembler.cvtwd(fpTempRegister, src);
1859 m_assembler.mfc1(dest, fpTempRegister);
1861 // If the result is zero, it might have been -0.0, and the double comparison won't catch this!
1863 failureCases.append(branch32(Equal, dest, MIPSRegisters::zero));
1865 // Convert the integer result back to float & compare to the original value - if not equal or unordered (NaN) then jump.
1866 convertInt32ToDouble(dest, fpTemp);
1867 failureCases.append(branchDouble(DoubleNotEqualOrUnordered, fpTemp, src));
1870 Jump branchDoubleNonZero(FPRegisterID reg, FPRegisterID scratch)
1872 #if WTF_MIPS_ISA_REV(2) && WTF_MIPS_FP64
1873 m_assembler.mtc1(MIPSRegisters::zero, scratch);
1874 m_assembler.mthc1(MIPSRegisters::zero, scratch);
1876 m_assembler.mtc1(MIPSRegisters::zero, scratch);
1877 m_assembler.mtc1(MIPSRegisters::zero, FPRegisterID(scratch + 1));
1879 return branchDouble(DoubleNotEqual, reg, scratch);
1882 Jump branchDoubleZeroOrNaN(FPRegisterID reg, FPRegisterID scratch)
1884 #if WTF_MIPS_ISA_REV(2) && WTF_MIPS_FP64
1885 m_assembler.mtc1(MIPSRegisters::zero, scratch);
1886 m_assembler.mthc1(MIPSRegisters::zero, scratch);
1888 m_assembler.mtc1(MIPSRegisters::zero, scratch);
1889 m_assembler.mtc1(MIPSRegisters::zero, FPRegisterID(scratch + 1));
1891 return branchDouble(DoubleEqualOrUnordered, reg, scratch);
1899 static FunctionPtr readCallTarget(CodeLocationCall call)
1901 return FunctionPtr(reinterpret_cast<void(*)()>(MIPSAssembler::readCallTarget(call.dataLocation())));
1904 static void replaceWithJump(CodeLocationLabel instructionStart, CodeLocationLabel destination)
1906 ASSERT_NOT_REACHED();
1909 static ptrdiff_t maxJumpReplacementSize()
1911 ASSERT_NOT_REACHED();
1916 // If m_fixedWidth is true, we will generate a fixed number of instructions.
1917 // Otherwise, we can emit any number of instructions.
1920 friend class LinkBuffer;
1921 friend class RepatchBuffer;
1923 static void linkCall(void* code, Call call, FunctionPtr function)
1925 MIPSAssembler::linkCall(code, call.m_label, function.value());
1928 static void repatchCall(CodeLocationCall call, CodeLocationLabel destination)
1930 MIPSAssembler::relinkCall(call.dataLocation(), destination.executableAddress());
1933 static void repatchCall(CodeLocationCall call, FunctionPtr destination)
1935 MIPSAssembler::relinkCall(call.dataLocation(), destination.executableAddress());
1942 #endif // ENABLE(ASSEMBLER) && CPU(MIPS)
1944 #endif // MacroAssemblerMIPS_h