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(TrustedImm32 imm, RegisterID dest)
306 if (!imm.m_isPointer && !imm.m_value && !m_fixedWidth)
309 if (!imm.m_isPointer && imm.m_value > 0 && imm.m_value < 65535
311 m_assembler.ori(dest, dest, imm.m_value);
317 or dest, dest, dataTemp
319 move(imm, dataTempRegister);
320 m_assembler.orInsn(dest, dest, dataTempRegister);
323 void rshift32(RegisterID shiftAmount, RegisterID dest)
325 m_assembler.srav(dest, dest, shiftAmount);
328 void rshift32(TrustedImm32 imm, RegisterID dest)
330 m_assembler.sra(dest, dest, imm.m_value);
333 void rshift32(RegisterID src, TrustedImm32 imm, RegisterID dest)
335 m_assembler.sra(dest, src, imm.m_value);
338 void urshift32(RegisterID shiftAmount, RegisterID dest)
340 m_assembler.srlv(dest, dest, shiftAmount);
343 void urshift32(TrustedImm32 imm, RegisterID dest)
345 m_assembler.srl(dest, dest, imm.m_value);
348 void sub32(RegisterID src, RegisterID dest)
350 m_assembler.subu(dest, dest, src);
353 void sub32(TrustedImm32 imm, RegisterID dest)
355 if (!imm.m_isPointer && imm.m_value >= -32767 && imm.m_value <= 32768
360 m_assembler.addiu(dest, dest, -imm.m_value);
364 subu dest, src, immTemp
366 move(imm, immTempRegister);
367 m_assembler.subu(dest, dest, immTempRegister);
371 void sub32(TrustedImm32 imm, Address address)
373 if (address.offset >= -32768 && address.offset <= 32767
376 lw dataTemp, offset(base)
378 subu dataTemp, dataTemp, immTemp
379 sw dataTemp, offset(base)
381 m_assembler.lw(dataTempRegister, address.base, address.offset);
383 && imm.m_value >= -32767 && imm.m_value <= 32768
385 m_assembler.addiu(dataTempRegister, dataTempRegister,
388 move(imm, immTempRegister);
389 m_assembler.subu(dataTempRegister, dataTempRegister,
392 m_assembler.sw(dataTempRegister, address.base, address.offset);
395 lui addrTemp, (offset + 0x8000) >> 16
396 addu addrTemp, addrTemp, base
397 lw dataTemp, (offset & 0xffff)(addrTemp)
399 subu dataTemp, dataTemp, immTemp
400 sw dataTemp, (offset & 0xffff)(addrTemp)
402 m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16);
403 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
404 m_assembler.lw(dataTempRegister, addrTempRegister, address.offset);
407 && imm.m_value >= -32767 && imm.m_value <= 32768
409 m_assembler.addiu(dataTempRegister, dataTempRegister,
412 move(imm, immTempRegister);
413 m_assembler.subu(dataTempRegister, dataTempRegister,
416 m_assembler.sw(dataTempRegister, addrTempRegister, address.offset);
420 void sub32(Address src, RegisterID dest)
422 load32(src, dataTempRegister);
423 sub32(dataTempRegister, dest);
426 void sub32(TrustedImm32 imm, AbsoluteAddress address)
431 lw dataTemp, 0(addrTemp)
432 subu dataTemp, dataTemp, immTemp
433 sw dataTemp, 0(addrTemp)
435 move(TrustedImmPtr(address.m_ptr), addrTempRegister);
436 m_assembler.lw(dataTempRegister, addrTempRegister, 0);
438 if (!imm.m_isPointer && imm.m_value >= -32767 && imm.m_value <= 32768
440 m_assembler.addiu(dataTempRegister, dataTempRegister,
443 move(imm, immTempRegister);
444 m_assembler.subu(dataTempRegister, dataTempRegister, immTempRegister);
446 m_assembler.sw(dataTempRegister, addrTempRegister, 0);
449 void xor32(RegisterID src, RegisterID dest)
451 m_assembler.xorInsn(dest, dest, src);
454 void xor32(TrustedImm32 imm, RegisterID dest)
458 xor dest, dest, immTemp
460 move(imm, immTempRegister);
461 m_assembler.xorInsn(dest, dest, immTempRegister);
464 void sqrtDouble(FPRegisterID src, FPRegisterID dst)
466 m_assembler.sqrtd(dst, src);
469 void andnotDouble(FPRegisterID, FPRegisterID)
471 ASSERT_NOT_REACHED();
474 // Memory access operations:
476 // Loads are of the form load(address, destination) and stores of the form
477 // store(source, address). The source for a store may be an TrustedImm32. Address
478 // operand objects to loads and store will be implicitly constructed if a
479 // register is passed.
481 /* Need to use zero-extened load byte for load8. */
482 void load8(ImplicitAddress address, RegisterID dest)
484 if (address.offset >= -32768 && address.offset <= 32767
486 m_assembler.lbu(dest, address.base, address.offset);
489 lui addrTemp, (offset + 0x8000) >> 16
490 addu addrTemp, addrTemp, base
491 lbu dest, (offset & 0xffff)(addrTemp)
493 m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16);
494 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
495 m_assembler.lbu(dest, addrTempRegister, address.offset);
499 void load8(BaseIndex address, RegisterID dest)
501 if (address.offset >= -32768 && address.offset <= 32767
504 sll addrTemp, address.index, address.scale
505 addu addrTemp, addrTemp, address.base
506 lbu dest, address.offset(addrTemp)
508 m_assembler.sll(addrTempRegister, address.index, address.scale);
509 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
510 m_assembler.lbu(dest, addrTempRegister, address.offset);
513 sll addrTemp, address.index, address.scale
514 addu addrTemp, addrTemp, address.base
515 lui immTemp, (address.offset + 0x8000) >> 16
516 addu addrTemp, addrTemp, immTemp
517 lbu dest, (address.offset & 0xffff)(at)
519 m_assembler.sll(addrTempRegister, address.index, address.scale);
520 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
521 m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16);
522 m_assembler.addu(addrTempRegister, addrTempRegister,
524 m_assembler.lbu(dest, addrTempRegister, address.offset);
528 void load32(ImplicitAddress address, RegisterID dest)
530 if (address.offset >= -32768 && address.offset <= 32767
532 m_assembler.lw(dest, address.base, address.offset);
535 lui addrTemp, (offset + 0x8000) >> 16
536 addu addrTemp, addrTemp, base
537 lw dest, (offset & 0xffff)(addrTemp)
539 m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16);
540 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
541 m_assembler.lw(dest, addrTempRegister, address.offset);
545 void load32(BaseIndex address, RegisterID dest)
547 if (address.offset >= -32768 && address.offset <= 32767
550 sll addrTemp, address.index, address.scale
551 addu addrTemp, addrTemp, address.base
552 lw dest, address.offset(addrTemp)
554 m_assembler.sll(addrTempRegister, address.index, address.scale);
555 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
556 m_assembler.lw(dest, addrTempRegister, address.offset);
559 sll addrTemp, address.index, address.scale
560 addu addrTemp, addrTemp, address.base
561 lui immTemp, (address.offset + 0x8000) >> 16
562 addu addrTemp, addrTemp, immTemp
563 lw dest, (address.offset & 0xffff)(at)
565 m_assembler.sll(addrTempRegister, address.index, address.scale);
566 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
567 m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16);
568 m_assembler.addu(addrTempRegister, addrTempRegister,
570 m_assembler.lw(dest, addrTempRegister, address.offset);
574 void load32WithUnalignedHalfWords(BaseIndex address, RegisterID dest)
576 if (address.offset >= -32768 && address.offset <= 32764
579 sll addrTemp, address.index, address.scale
580 addu addrTemp, addrTemp, address.base
582 lwl dest, address.offset(addrTemp)
583 lwr dest, address.offset+3(addrTemp)
585 lwl dest, address.offset+3(addrTemp)
586 lwr dest, address.offset(addrTemp)
588 m_assembler.sll(addrTempRegister, address.index, address.scale);
589 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
591 m_assembler.lwl(dest, addrTempRegister, address.offset);
592 m_assembler.lwr(dest, addrTempRegister, address.offset + 3);
594 m_assembler.lwl(dest, addrTempRegister, address.offset + 3);
595 m_assembler.lwr(dest, addrTempRegister, address.offset);
600 sll addrTemp, address.index, address.scale
601 addu addrTemp, addrTemp, address.base
602 lui immTemp, address.offset >> 16
603 ori immTemp, immTemp, address.offset & 0xffff
604 addu addrTemp, addrTemp, immTemp
612 m_assembler.sll(addrTempRegister, address.index, address.scale);
613 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
614 m_assembler.lui(immTempRegister, address.offset >> 16);
615 m_assembler.ori(immTempRegister, immTempRegister, address.offset);
616 m_assembler.addu(addrTempRegister, addrTempRegister,
619 m_assembler.lwl(dest, addrTempRegister, 0);
620 m_assembler.lwr(dest, addrTempRegister, 3);
622 m_assembler.lwl(dest, addrTempRegister, 3);
623 m_assembler.lwr(dest, addrTempRegister, 0);
628 void load32(const void* address, RegisterID dest)
634 move(TrustedImmPtr(address), addrTempRegister);
635 m_assembler.lw(dest, addrTempRegister, 0);
638 DataLabel32 load32WithAddressOffsetPatch(Address address, RegisterID dest)
642 lui addrTemp, address.offset >> 16
643 ori addrTemp, addrTemp, address.offset & 0xffff
644 addu addrTemp, addrTemp, address.base
647 DataLabel32 dataLabel(this);
648 move(TrustedImm32(address.offset), addrTempRegister);
649 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
650 m_assembler.lw(dest, addrTempRegister, 0);
651 m_fixedWidth = false;
655 DataLabelCompact load32WithCompactAddressOffsetPatch(Address address, RegisterID dest)
657 DataLabelCompact dataLabel(this);
658 load32WithAddressOffsetPatch(address, dest);
662 /* Need to use zero-extened load half-word for load16. */
663 void load16(ImplicitAddress address, RegisterID dest)
665 if (address.offset >= -32768 && address.offset <= 32767
667 m_assembler.lhu(dest, address.base, address.offset);
670 lui addrTemp, (offset + 0x8000) >> 16
671 addu addrTemp, addrTemp, base
672 lhu dest, (offset & 0xffff)(addrTemp)
674 m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16);
675 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
676 m_assembler.lhu(dest, addrTempRegister, address.offset);
680 /* Need to use zero-extened load half-word for load16. */
681 void load16(BaseIndex address, RegisterID dest)
683 if (address.offset >= -32768 && address.offset <= 32767
686 sll addrTemp, address.index, address.scale
687 addu addrTemp, addrTemp, address.base
688 lhu dest, address.offset(addrTemp)
690 m_assembler.sll(addrTempRegister, address.index, address.scale);
691 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
692 m_assembler.lhu(dest, addrTempRegister, address.offset);
695 sll addrTemp, address.index, address.scale
696 addu addrTemp, addrTemp, address.base
697 lui immTemp, (address.offset + 0x8000) >> 16
698 addu addrTemp, addrTemp, immTemp
699 lhu dest, (address.offset & 0xffff)(addrTemp)
701 m_assembler.sll(addrTempRegister, address.index, address.scale);
702 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
703 m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16);
704 m_assembler.addu(addrTempRegister, addrTempRegister,
706 m_assembler.lhu(dest, addrTempRegister, address.offset);
710 DataLabel32 store32WithAddressOffsetPatch(RegisterID src, Address address)
714 lui addrTemp, address.offset >> 16
715 ori addrTemp, addrTemp, address.offset & 0xffff
716 addu addrTemp, addrTemp, address.base
719 DataLabel32 dataLabel(this);
720 move(TrustedImm32(address.offset), addrTempRegister);
721 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
722 m_assembler.sw(src, addrTempRegister, 0);
723 m_fixedWidth = false;
727 void store32(RegisterID src, ImplicitAddress address)
729 if (address.offset >= -32768 && address.offset <= 32767
731 m_assembler.sw(src, address.base, address.offset);
734 lui addrTemp, (offset + 0x8000) >> 16
735 addu addrTemp, addrTemp, base
736 sw src, (offset & 0xffff)(addrTemp)
738 m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16);
739 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
740 m_assembler.sw(src, addrTempRegister, address.offset);
744 void store32(RegisterID src, BaseIndex address)
746 if (address.offset >= -32768 && address.offset <= 32767
749 sll addrTemp, address.index, address.scale
750 addu addrTemp, addrTemp, address.base
751 sw src, address.offset(addrTemp)
753 m_assembler.sll(addrTempRegister, address.index, address.scale);
754 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
755 m_assembler.sw(src, addrTempRegister, address.offset);
758 sll addrTemp, address.index, address.scale
759 addu addrTemp, addrTemp, address.base
760 lui immTemp, (address.offset + 0x8000) >> 16
761 addu addrTemp, addrTemp, immTemp
762 sw src, (address.offset & 0xffff)(at)
764 m_assembler.sll(addrTempRegister, address.index, address.scale);
765 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
766 m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16);
767 m_assembler.addu(addrTempRegister, addrTempRegister,
769 m_assembler.sw(src, addrTempRegister, address.offset);
773 void store32(TrustedImm32 imm, ImplicitAddress address)
775 if (address.offset >= -32768 && address.offset <= 32767
777 if (!imm.m_isPointer && !imm.m_value)
778 m_assembler.sw(MIPSRegisters::zero, address.base,
781 move(imm, immTempRegister);
782 m_assembler.sw(immTempRegister, address.base, address.offset);
786 lui addrTemp, (offset + 0x8000) >> 16
787 addu addrTemp, addrTemp, base
788 sw immTemp, (offset & 0xffff)(addrTemp)
790 m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16);
791 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
792 if (!imm.m_isPointer && !imm.m_value && !m_fixedWidth)
793 m_assembler.sw(MIPSRegisters::zero, addrTempRegister,
796 move(imm, immTempRegister);
797 m_assembler.sw(immTempRegister, addrTempRegister,
803 void store32(RegisterID src, const void* address)
809 move(TrustedImmPtr(address), addrTempRegister);
810 m_assembler.sw(src, addrTempRegister, 0);
813 void store32(TrustedImm32 imm, const void* address)
820 if (!imm.m_isPointer && !imm.m_value && !m_fixedWidth) {
821 move(TrustedImmPtr(address), addrTempRegister);
822 m_assembler.sw(MIPSRegisters::zero, addrTempRegister, 0);
824 move(imm, immTempRegister);
825 move(TrustedImmPtr(address), addrTempRegister);
826 m_assembler.sw(immTempRegister, addrTempRegister, 0);
830 // Floating-point operations:
832 bool supportsFloatingPoint() const
834 #if WTF_MIPS_DOUBLE_FLOAT
841 bool supportsFloatingPointTruncate() const
843 #if WTF_MIPS_DOUBLE_FLOAT && WTF_MIPS_ISA_AT_LEAST(2)
850 bool supportsFloatingPointSqrt() const
852 #if WTF_MIPS_DOUBLE_FLOAT && WTF_MIPS_ISA_AT_LEAST(2)
858 bool supportsDoubleBitops() const { return false; }
860 // Stack manipulation operations:
862 // The ABI is assumed to provide a stack abstraction to memory,
863 // containing machine word sized units of data. Push and pop
864 // operations add and remove a single register sized unit of data
865 // to or from the stack. Peek and poke operations read or write
866 // values on the stack, without moving the current stack position.
868 void pop(RegisterID dest)
870 m_assembler.lw(dest, MIPSRegisters::sp, 0);
871 m_assembler.addiu(MIPSRegisters::sp, MIPSRegisters::sp, 4);
874 void push(RegisterID src)
876 m_assembler.addiu(MIPSRegisters::sp, MIPSRegisters::sp, -4);
877 m_assembler.sw(src, MIPSRegisters::sp, 0);
880 void push(Address address)
882 load32(address, dataTempRegister);
883 push(dataTempRegister);
886 void push(TrustedImm32 imm)
888 move(imm, immTempRegister);
889 push(immTempRegister);
892 // Register move operations:
894 // Move values in registers.
896 void move(TrustedImm32 imm, RegisterID dest)
898 if (!imm.m_isPointer && !imm.m_value && !m_fixedWidth)
899 move(MIPSRegisters::zero, dest);
900 else if (imm.m_isPointer || m_fixedWidth) {
901 m_assembler.lui(dest, imm.m_value >> 16);
902 m_assembler.ori(dest, dest, imm.m_value);
904 m_assembler.li(dest, imm.m_value);
907 void move(RegisterID src, RegisterID dest)
909 if (src != dest || m_fixedWidth)
910 m_assembler.move(dest, src);
913 void move(TrustedImmPtr imm, RegisterID dest)
915 move(TrustedImm32(imm), dest);
918 void swap(RegisterID reg1, RegisterID reg2)
920 move(reg1, immTempRegister);
922 move(immTempRegister, reg2);
925 void signExtend32ToPtr(RegisterID src, RegisterID dest)
927 if (src != dest || m_fixedWidth)
931 void zeroExtend32ToPtr(RegisterID src, RegisterID dest)
933 if (src != dest || m_fixedWidth)
937 // Forwards / external control flow operations:
939 // This set of jump and conditional branch operations return a Jump
940 // object which may linked at a later point, allow forwards jump,
941 // or jumps that will require external linkage (after the code has been
944 // For branches, signed <, >, <= and >= are denoted as l, g, le, and ge
945 // respecitvely, for unsigned comparisons the names b, a, be, and ae are
946 // used (representing the names 'below' and 'above').
948 // Operands to the comparision are provided in the expected order, e.g.
949 // jle32(reg1, TrustedImm32(5)) will branch if the value held in reg1, when
950 // treated as a signed 32bit value, is less than or equal to 5.
952 // jz and jnz test whether the first operand is equal to zero, and take
953 // an optional second operand of a mask under which to perform the test.
955 Jump branch8(RelationalCondition cond, Address left, TrustedImm32 right)
957 // Make sure the immediate value is unsigned 8 bits.
958 ASSERT(!(right.m_value & 0xFFFFFF00));
959 load8(left, dataTempRegister);
960 move(right, immTempRegister);
961 return branch32(cond, dataTempRegister, immTempRegister);
964 Jump branch8(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
966 ASSERT(!(right.m_value & 0xFFFFFF00));
967 load8(left, dataTempRegister);
968 // Be careful that the previous load8() uses immTempRegister.
969 // So, we need to put move() after load8().
970 move(right, immTempRegister);
971 return branch32(cond, dataTempRegister, immTempRegister);
974 Jump branch32(RelationalCondition cond, RegisterID left, RegisterID right)
977 return branchEqual(left, right);
978 if (cond == NotEqual)
979 return branchNotEqual(left, right);
981 m_assembler.sltu(cmpTempRegister, right, left);
982 return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
984 if (cond == AboveOrEqual) {
985 m_assembler.sltu(cmpTempRegister, left, right);
986 return branchEqual(cmpTempRegister, MIPSRegisters::zero);
989 m_assembler.sltu(cmpTempRegister, left, right);
990 return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
992 if (cond == BelowOrEqual) {
993 m_assembler.sltu(cmpTempRegister, right, left);
994 return branchEqual(cmpTempRegister, MIPSRegisters::zero);
996 if (cond == GreaterThan) {
997 m_assembler.slt(cmpTempRegister, right, left);
998 return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
1000 if (cond == GreaterThanOrEqual) {
1001 m_assembler.slt(cmpTempRegister, left, right);
1002 return branchEqual(cmpTempRegister, MIPSRegisters::zero);
1004 if (cond == LessThan) {
1005 m_assembler.slt(cmpTempRegister, left, right);
1006 return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
1008 if (cond == LessThanOrEqual) {
1009 m_assembler.slt(cmpTempRegister, right, left);
1010 return branchEqual(cmpTempRegister, MIPSRegisters::zero);
1017 Jump branch32(RelationalCondition cond, RegisterID left, TrustedImm32 right)
1019 move(right, immTempRegister);
1020 return branch32(cond, left, immTempRegister);
1023 Jump branch32(RelationalCondition cond, RegisterID left, Address right)
1025 load32(right, dataTempRegister);
1026 return branch32(cond, left, dataTempRegister);
1029 Jump branch32(RelationalCondition cond, Address left, RegisterID right)
1031 load32(left, dataTempRegister);
1032 return branch32(cond, dataTempRegister, right);
1035 Jump branch32(RelationalCondition cond, Address left, TrustedImm32 right)
1037 load32(left, dataTempRegister);
1038 move(right, immTempRegister);
1039 return branch32(cond, dataTempRegister, immTempRegister);
1042 Jump branch32(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
1044 load32(left, dataTempRegister);
1045 // Be careful that the previous load32() uses immTempRegister.
1046 // So, we need to put move() after load32().
1047 move(right, immTempRegister);
1048 return branch32(cond, dataTempRegister, immTempRegister);
1051 Jump branch32WithUnalignedHalfWords(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
1053 load32WithUnalignedHalfWords(left, dataTempRegister);
1054 // Be careful that the previous load32WithUnalignedHalfWords()
1055 // uses immTempRegister.
1056 // So, we need to put move() after load32WithUnalignedHalfWords().
1057 move(right, immTempRegister);
1058 return branch32(cond, dataTempRegister, immTempRegister);
1061 Jump branch32(RelationalCondition cond, AbsoluteAddress left, RegisterID right)
1063 load32(left.m_ptr, dataTempRegister);
1064 return branch32(cond, dataTempRegister, right);
1067 Jump branch32(RelationalCondition cond, AbsoluteAddress left, TrustedImm32 right)
1069 load32(left.m_ptr, dataTempRegister);
1070 move(right, immTempRegister);
1071 return branch32(cond, dataTempRegister, immTempRegister);
1074 Jump branch16(RelationalCondition cond, RegisterID left, TrustedImm32 right)
1076 // Make sure the immediate value is unsigned 16 bits.
1077 ASSERT(!(right.m_value & 0xFFFF0000));
1078 m_assembler.andi(immTempRegister, left, 0xffff);
1079 return branch32(cond, immTempRegister, right);
1082 Jump branch16(RelationalCondition cond, BaseIndex left, RegisterID right)
1084 load16(left, dataTempRegister);
1085 return branch32(cond, dataTempRegister, right);
1088 Jump branch16(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
1090 ASSERT(!(right.m_value & 0xFFFF0000));
1091 load16(left, dataTempRegister);
1092 // Be careful that the previous load16() uses immTempRegister.
1093 // So, we need to put move() after load16().
1094 move(right, immTempRegister);
1095 return branch32(cond, dataTempRegister, immTempRegister);
1098 Jump branchTest32(ResultCondition cond, RegisterID reg, RegisterID mask)
1100 ASSERT((cond == Zero) || (cond == NonZero));
1101 m_assembler.andInsn(cmpTempRegister, reg, mask);
1103 return branchEqual(cmpTempRegister, MIPSRegisters::zero);
1104 return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
1107 Jump branchTest32(ResultCondition cond, RegisterID reg, TrustedImm32 mask = TrustedImm32(-1))
1109 ASSERT((cond == Zero) || (cond == NonZero));
1110 if (mask.m_value == -1 && !m_fixedWidth) {
1112 return branchEqual(reg, MIPSRegisters::zero);
1113 return branchNotEqual(reg, MIPSRegisters::zero);
1115 move(mask, immTempRegister);
1116 return branchTest32(cond, reg, immTempRegister);
1119 Jump branchTest32(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
1121 load32(address, dataTempRegister);
1122 return branchTest32(cond, dataTempRegister, mask);
1125 Jump branchTest32(ResultCondition cond, BaseIndex address, TrustedImm32 mask = TrustedImm32(-1))
1127 load32(address, dataTempRegister);
1128 return branchTest32(cond, dataTempRegister, mask);
1131 Jump branchTest8(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
1133 load8(address, dataTempRegister);
1134 return branchTest32(cond, dataTempRegister, mask);
1139 return branchEqual(MIPSRegisters::zero, MIPSRegisters::zero);
1142 void jump(RegisterID target)
1144 m_assembler.jr(target);
1148 void jump(Address address)
1150 m_fixedWidth = true;
1151 load32(address, MIPSRegisters::t9);
1152 m_assembler.jr(MIPSRegisters::t9);
1154 m_fixedWidth = false;
1157 // Arithmetic control flow operations:
1159 // This set of conditional branch operations branch based
1160 // on the result of an arithmetic operation. The operation
1161 // is performed as normal, storing the result.
1163 // * jz operations branch if the result is zero.
1164 // * jo operations branch if the (signed) arithmetic
1165 // operation caused an overflow to occur.
1167 Jump branchAdd32(ResultCondition cond, RegisterID src, RegisterID dest)
1169 ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
1170 if (cond == Overflow) {
1173 xor cmpTemp, dataTemp, src
1174 bltz cmpTemp, No_overflow # diff sign bit -> no overflow
1175 addu dest, dataTemp, src
1176 xor cmpTemp, dest, dataTemp
1177 bgez cmpTemp, No_overflow # same sign big -> no overflow
1187 move(dest, dataTempRegister);
1188 m_assembler.xorInsn(cmpTempRegister, dataTempRegister, src);
1189 m_assembler.bltz(cmpTempRegister, 10);
1190 m_assembler.addu(dest, dataTempRegister, src);
1191 m_assembler.xorInsn(cmpTempRegister, dest, dataTempRegister);
1192 m_assembler.bgez(cmpTempRegister, 7);
1196 if (cond == Signed) {
1198 // Check if dest is negative.
1199 m_assembler.slt(cmpTempRegister, dest, MIPSRegisters::zero);
1200 return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
1204 return branchEqual(dest, MIPSRegisters::zero);
1206 if (cond == NonZero) {
1208 return branchNotEqual(dest, MIPSRegisters::zero);
1214 Jump branchAdd32(ResultCondition cond, TrustedImm32 imm, RegisterID dest)
1216 move(imm, immTempRegister);
1217 return branchAdd32(cond, immTempRegister, dest);
1220 Jump branchMul32(ResultCondition cond, RegisterID src, RegisterID dest)
1222 ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
1223 if (cond == Overflow) {
1228 sra addrTemp, dest, 31
1229 beq dataTemp, addrTemp, No_overflow # all sign bits (bit 63 to bit 31) are the same -> no overflow
1239 m_assembler.mult(src, dest);
1240 m_assembler.mfhi(dataTempRegister);
1241 m_assembler.mflo(dest);
1242 m_assembler.sra(addrTempRegister, dest, 31);
1243 m_assembler.beq(dataTempRegister, addrTempRegister, 7);
1247 if (cond == Signed) {
1249 // Check if dest is negative.
1250 m_assembler.slt(cmpTempRegister, dest, MIPSRegisters::zero);
1251 return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
1255 return branchEqual(dest, MIPSRegisters::zero);
1257 if (cond == NonZero) {
1259 return branchNotEqual(dest, MIPSRegisters::zero);
1265 Jump branchMul32(ResultCondition cond, TrustedImm32 imm, RegisterID src, RegisterID dest)
1267 move(imm, immTempRegister);
1269 return branchMul32(cond, immTempRegister, dest);
1272 Jump branchSub32(ResultCondition cond, RegisterID src, RegisterID dest)
1274 ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
1275 if (cond == Overflow) {
1278 xor cmpTemp, dataTemp, src
1279 bgez cmpTemp, No_overflow # same sign bit -> no overflow
1280 subu dest, dataTemp, src
1281 xor cmpTemp, dest, dataTemp
1282 bgez cmpTemp, No_overflow # same sign bit -> no overflow
1292 move(dest, dataTempRegister);
1293 m_assembler.xorInsn(cmpTempRegister, dataTempRegister, src);
1294 m_assembler.bgez(cmpTempRegister, 10);
1295 m_assembler.subu(dest, dataTempRegister, src);
1296 m_assembler.xorInsn(cmpTempRegister, dest, dataTempRegister);
1297 m_assembler.bgez(cmpTempRegister, 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 branchSub32(ResultCondition cond, TrustedImm32 imm, RegisterID dest)
1321 move(imm, immTempRegister);
1322 return branchSub32(cond, immTempRegister, dest);
1325 Jump branchOr32(ResultCondition cond, RegisterID src, RegisterID dest)
1327 ASSERT((cond == Signed) || (cond == Zero) || (cond == NonZero));
1328 if (cond == Signed) {
1330 // Check if dest is negative.
1331 m_assembler.slt(cmpTempRegister, dest, MIPSRegisters::zero);
1332 return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
1336 return branchEqual(dest, MIPSRegisters::zero);
1338 if (cond == NonZero) {
1340 return branchNotEqual(dest, MIPSRegisters::zero);
1346 // Miscellaneous operations:
1355 /* We need two words for relaxation. */
1360 return Call(m_assembler.label(), Call::LinkableNear);
1365 m_assembler.lui(MIPSRegisters::t9, 0);
1366 m_assembler.ori(MIPSRegisters::t9, MIPSRegisters::t9, 0);
1367 m_assembler.jalr(MIPSRegisters::t9);
1369 return Call(m_assembler.label(), Call::Linkable);
1372 Call call(RegisterID target)
1374 m_assembler.jalr(target);
1376 return Call(m_assembler.label(), Call::None);
1379 Call call(Address address)
1381 m_fixedWidth = true;
1382 load32(address, MIPSRegisters::t9);
1383 m_assembler.jalr(MIPSRegisters::t9);
1385 m_fixedWidth = false;
1386 return Call(m_assembler.label(), Call::None);
1391 m_assembler.jr(MIPSRegisters::ra);
1395 void compare32(RelationalCondition cond, RegisterID left, RegisterID right, RegisterID dest)
1397 if (cond == Equal) {
1398 m_assembler.xorInsn(dest, left, right);
1399 m_assembler.sltiu(dest, dest, 1);
1400 } else if (cond == NotEqual) {
1401 m_assembler.xorInsn(dest, left, right);
1402 m_assembler.sltu(dest, MIPSRegisters::zero, dest);
1403 } else if (cond == Above)
1404 m_assembler.sltu(dest, right, left);
1405 else if (cond == AboveOrEqual) {
1406 m_assembler.sltu(dest, left, right);
1407 m_assembler.xori(dest, dest, 1);
1408 } else if (cond == Below)
1409 m_assembler.sltu(dest, left, right);
1410 else if (cond == BelowOrEqual) {
1411 m_assembler.sltu(dest, right, left);
1412 m_assembler.xori(dest, dest, 1);
1413 } else if (cond == GreaterThan)
1414 m_assembler.slt(dest, right, left);
1415 else if (cond == GreaterThanOrEqual) {
1416 m_assembler.slt(dest, left, right);
1417 m_assembler.xori(dest, dest, 1);
1418 } else if (cond == LessThan)
1419 m_assembler.slt(dest, left, right);
1420 else if (cond == LessThanOrEqual) {
1421 m_assembler.slt(dest, right, left);
1422 m_assembler.xori(dest, dest, 1);
1426 void compare32(RelationalCondition cond, RegisterID left, TrustedImm32 right, RegisterID dest)
1428 move(right, immTempRegister);
1429 compare32(cond, left, immTempRegister, dest);
1432 void test8(ResultCondition cond, Address address, TrustedImm32 mask, RegisterID dest)
1434 ASSERT((cond == Zero) || (cond == NonZero));
1435 load8(address, dataTempRegister);
1436 if (mask.m_value == -1 && !m_fixedWidth) {
1438 m_assembler.sltiu(dest, dataTempRegister, 1);
1440 m_assembler.sltu(dest, MIPSRegisters::zero, dataTempRegister);
1442 move(mask, immTempRegister);
1443 m_assembler.andInsn(cmpTempRegister, dataTempRegister,
1446 m_assembler.sltiu(dest, cmpTempRegister, 1);
1448 m_assembler.sltu(dest, MIPSRegisters::zero, cmpTempRegister);
1452 void test32(ResultCondition cond, Address address, TrustedImm32 mask, RegisterID dest)
1454 ASSERT((cond == Zero) || (cond == NonZero));
1455 load32(address, dataTempRegister);
1456 if (mask.m_value == -1 && !m_fixedWidth) {
1458 m_assembler.sltiu(dest, dataTempRegister, 1);
1460 m_assembler.sltu(dest, MIPSRegisters::zero, dataTempRegister);
1462 move(mask, immTempRegister);
1463 m_assembler.andInsn(cmpTempRegister, dataTempRegister,
1466 m_assembler.sltiu(dest, cmpTempRegister, 1);
1468 m_assembler.sltu(dest, MIPSRegisters::zero, cmpTempRegister);
1472 DataLabel32 moveWithPatch(TrustedImm32 imm, RegisterID dest)
1474 m_fixedWidth = true;
1475 DataLabel32 label(this);
1477 m_fixedWidth = false;
1481 DataLabelPtr moveWithPatch(TrustedImmPtr initialValue, RegisterID dest)
1483 m_fixedWidth = true;
1484 DataLabelPtr label(this);
1485 move(initialValue, dest);
1486 m_fixedWidth = false;
1490 Jump branchPtrWithPatch(RelationalCondition cond, RegisterID left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
1492 m_fixedWidth = true;
1493 dataLabel = moveWithPatch(initialRightValue, immTempRegister);
1494 Jump temp = branch32(cond, left, immTempRegister);
1495 m_fixedWidth = false;
1499 Jump branchPtrWithPatch(RelationalCondition cond, Address left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
1501 m_fixedWidth = true;
1502 load32(left, dataTempRegister);
1503 dataLabel = moveWithPatch(initialRightValue, immTempRegister);
1504 Jump temp = branch32(cond, dataTempRegister, immTempRegister);
1505 m_fixedWidth = false;
1509 DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address)
1511 m_fixedWidth = true;
1512 DataLabelPtr dataLabel = moveWithPatch(initialValue, dataTempRegister);
1513 store32(dataTempRegister, address);
1514 m_fixedWidth = false;
1518 DataLabelPtr storePtrWithPatch(ImplicitAddress address)
1520 return storePtrWithPatch(TrustedImmPtr(0), address);
1523 Call tailRecursiveCall()
1525 // Like a normal call, but don't update the returned address register
1526 m_fixedWidth = true;
1527 move(TrustedImm32(0), MIPSRegisters::t9);
1528 m_assembler.jr(MIPSRegisters::t9);
1530 m_fixedWidth = false;
1531 return Call(m_assembler.label(), Call::Linkable);
1534 Call makeTailRecursiveCall(Jump oldJump)
1537 return tailRecursiveCall();
1540 void loadDouble(ImplicitAddress address, FPRegisterID dest)
1544 li addrTemp, address.offset
1545 addu addrTemp, addrTemp, base
1546 lwc1 dest, 0(addrTemp)
1547 lwc1 dest+1, 4(addrTemp)
1549 move(TrustedImm32(address.offset), addrTempRegister);
1550 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
1551 m_assembler.lwc1(dest, addrTempRegister, 0);
1552 m_assembler.lwc1(FPRegisterID(dest + 1), addrTempRegister, 4);
1554 if (address.offset >= -32768 && address.offset <= 32767
1556 m_assembler.ldc1(dest, address.base, address.offset);
1559 lui addrTemp, (offset + 0x8000) >> 16
1560 addu addrTemp, addrTemp, base
1561 ldc1 dest, (offset & 0xffff)(addrTemp)
1563 m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16);
1564 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
1565 m_assembler.ldc1(dest, addrTempRegister, address.offset);
1570 void loadDouble(const void* address, FPRegisterID dest)
1574 li addrTemp, address
1575 lwc1 dest, 0(addrTemp)
1576 lwc1 dest+1, 4(addrTemp)
1578 move(TrustedImmPtr(address), addrTempRegister);
1579 m_assembler.lwc1(dest, addrTempRegister, 0);
1580 m_assembler.lwc1(FPRegisterID(dest + 1), addrTempRegister, 4);
1583 li addrTemp, address
1584 ldc1 dest, 0(addrTemp)
1586 move(TrustedImmPtr(address), addrTempRegister);
1587 m_assembler.ldc1(dest, addrTempRegister, 0);
1592 void storeDouble(FPRegisterID src, ImplicitAddress address)
1596 li addrTemp, address.offset
1597 addu addrTemp, addrTemp, base
1598 swc1 dest, 0(addrTemp)
1599 swc1 dest+1, 4(addrTemp)
1601 move(TrustedImm32(address.offset), addrTempRegister);
1602 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
1603 m_assembler.swc1(src, addrTempRegister, 0);
1604 m_assembler.swc1(FPRegisterID(src + 1), addrTempRegister, 4);
1606 if (address.offset >= -32768 && address.offset <= 32767
1608 m_assembler.sdc1(src, address.base, address.offset);
1611 lui addrTemp, (offset + 0x8000) >> 16
1612 addu addrTemp, addrTemp, base
1613 sdc1 src, (offset & 0xffff)(addrTemp)
1615 m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16);
1616 m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
1617 m_assembler.sdc1(src, addrTempRegister, address.offset);
1622 void addDouble(FPRegisterID src, FPRegisterID dest)
1624 m_assembler.addd(dest, dest, src);
1627 void addDouble(Address src, FPRegisterID dest)
1629 loadDouble(src, fpTempRegister);
1630 m_assembler.addd(dest, dest, fpTempRegister);
1633 void subDouble(FPRegisterID src, FPRegisterID dest)
1635 m_assembler.subd(dest, dest, src);
1638 void subDouble(Address src, FPRegisterID dest)
1640 loadDouble(src, fpTempRegister);
1641 m_assembler.subd(dest, dest, fpTempRegister);
1644 void mulDouble(FPRegisterID src, FPRegisterID dest)
1646 m_assembler.muld(dest, dest, src);
1649 void mulDouble(Address src, FPRegisterID dest)
1651 loadDouble(src, fpTempRegister);
1652 m_assembler.muld(dest, dest, fpTempRegister);
1655 void divDouble(FPRegisterID src, FPRegisterID dest)
1657 m_assembler.divd(dest, dest, src);
1660 void convertInt32ToDouble(RegisterID src, FPRegisterID dest)
1662 m_assembler.mtc1(src, fpTempRegister);
1663 m_assembler.cvtdw(dest, fpTempRegister);
1666 void convertInt32ToDouble(Address src, FPRegisterID dest)
1668 load32(src, dataTempRegister);
1669 m_assembler.mtc1(dataTempRegister, fpTempRegister);
1670 m_assembler.cvtdw(dest, fpTempRegister);
1673 void convertInt32ToDouble(AbsoluteAddress src, FPRegisterID dest)
1675 load32(src.m_ptr, dataTempRegister);
1676 m_assembler.mtc1(dataTempRegister, fpTempRegister);
1677 m_assembler.cvtdw(dest, fpTempRegister);
1680 void insertRelaxationWords()
1682 /* We need four words for relaxation. */
1683 m_assembler.beq(MIPSRegisters::zero, MIPSRegisters::zero, 3); // Jump over nops;
1691 m_assembler.appendJump();
1694 insertRelaxationWords();
1695 return Jump(m_assembler.label());
1700 m_assembler.appendJump();
1703 insertRelaxationWords();
1704 return Jump(m_assembler.label());
1707 Jump branchEqual(RegisterID rs, RegisterID rt)
1709 m_assembler.appendJump();
1710 m_assembler.beq(rs, rt, 0);
1712 insertRelaxationWords();
1713 return Jump(m_assembler.label());
1716 Jump branchNotEqual(RegisterID rs, RegisterID rt)
1718 m_assembler.appendJump();
1719 m_assembler.bne(rs, rt, 0);
1721 insertRelaxationWords();
1722 return Jump(m_assembler.label());
1725 Jump branchDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right)
1727 if (cond == DoubleEqual) {
1728 m_assembler.ceqd(left, right);
1729 return branchTrue();
1731 if (cond == DoubleNotEqual) {
1732 m_assembler.cueqd(left, right);
1733 return branchFalse(); // false
1735 if (cond == DoubleGreaterThan) {
1736 m_assembler.cngtd(left, right);
1737 return branchFalse(); // false
1739 if (cond == DoubleGreaterThanOrEqual) {
1740 m_assembler.cnged(left, right);
1741 return branchFalse(); // false
1743 if (cond == DoubleLessThan) {
1744 m_assembler.cltd(left, right);
1745 return branchTrue();
1747 if (cond == DoubleLessThanOrEqual) {
1748 m_assembler.cled(left, right);
1749 return branchTrue();
1751 if (cond == DoubleEqualOrUnordered) {
1752 m_assembler.cueqd(left, right);
1753 return branchTrue();
1755 if (cond == DoubleNotEqualOrUnordered) {
1756 m_assembler.ceqd(left, right);
1757 return branchFalse(); // false
1759 if (cond == DoubleGreaterThanOrUnordered) {
1760 m_assembler.coled(left, right);
1761 return branchFalse(); // false
1763 if (cond == DoubleGreaterThanOrEqualOrUnordered) {
1764 m_assembler.coltd(left, right);
1765 return branchFalse(); // false
1767 if (cond == DoubleLessThanOrUnordered) {
1768 m_assembler.cultd(left, right);
1769 return branchTrue();
1771 if (cond == DoubleLessThanOrEqualOrUnordered) {
1772 m_assembler.culed(left, right);
1773 return branchTrue();
1780 // Truncates 'src' to an integer, and places the resulting 'dest'.
1781 // If the result is not representable as a 32 bit value, branch.
1782 // May also branch for some values that are representable in 32 bits
1783 // (specifically, in this case, INT_MAX 0x7fffffff).
1784 Jump branchTruncateDoubleToInt32(FPRegisterID src, RegisterID dest)
1786 m_assembler.truncwd(fpTempRegister, src);
1787 m_assembler.mfc1(dest, fpTempRegister);
1788 return branch32(Equal, dest, TrustedImm32(0x7fffffff));
1791 // Convert 'src' to an integer, and places the resulting 'dest'.
1792 // If the result is not representable as a 32 bit value, branch.
1793 // May also branch for some values that are representable in 32 bits
1794 // (specifically, in this case, 0).
1795 void branchConvertDoubleToInt32(FPRegisterID src, RegisterID dest, JumpList& failureCases, FPRegisterID fpTemp)
1797 m_assembler.cvtwd(fpTempRegister, src);
1798 m_assembler.mfc1(dest, fpTempRegister);
1800 // If the result is zero, it might have been -0.0, and the double comparison won't catch this!
1801 failureCases.append(branch32(Equal, dest, MIPSRegisters::zero));
1803 // Convert the integer result back to float & compare to the original value - if not equal or unordered (NaN) then jump.
1804 convertInt32ToDouble(dest, fpTemp);
1805 failureCases.append(branchDouble(DoubleNotEqualOrUnordered, fpTemp, src));
1808 Jump branchDoubleNonZero(FPRegisterID reg, FPRegisterID scratch)
1810 #if WTF_MIPS_ISA_REV(2) && WTF_MIPS_FP64
1811 m_assembler.mtc1(MIPSRegisters::zero, scratch);
1812 m_assembler.mthc1(MIPSRegisters::zero, scratch);
1814 m_assembler.mtc1(MIPSRegisters::zero, scratch);
1815 m_assembler.mtc1(MIPSRegisters::zero, FPRegisterID(scratch + 1));
1817 return branchDouble(DoubleNotEqual, reg, scratch);
1820 Jump branchDoubleZeroOrNaN(FPRegisterID reg, FPRegisterID scratch)
1822 #if WTF_MIPS_ISA_REV(2) && WTF_MIPS_FP64
1823 m_assembler.mtc1(MIPSRegisters::zero, scratch);
1824 m_assembler.mthc1(MIPSRegisters::zero, scratch);
1826 m_assembler.mtc1(MIPSRegisters::zero, scratch);
1827 m_assembler.mtc1(MIPSRegisters::zero, FPRegisterID(scratch + 1));
1829 return branchDouble(DoubleEqualOrUnordered, reg, scratch);
1838 // If m_fixedWidth is true, we will generate a fixed number of instructions.
1839 // Otherwise, we can emit any number of instructions.
1842 friend class LinkBuffer;
1843 friend class RepatchBuffer;
1845 static void linkCall(void* code, Call call, FunctionPtr function)
1847 MIPSAssembler::linkCall(code, call.m_label, function.value());
1850 static void repatchCall(CodeLocationCall call, CodeLocationLabel destination)
1852 MIPSAssembler::relinkCall(call.dataLocation(), destination.executableAddress());
1855 static void repatchCall(CodeLocationCall call, FunctionPtr destination)
1857 MIPSAssembler::relinkCall(call.dataLocation(), destination.executableAddress());
1864 #endif // ENABLE(ASSEMBLER) && CPU(MIPS)
1866 #endif // MacroAssemblerMIPS_h