2 * Copyright (C) 2009 Apple Inc. All rights reserved.
3 * Copyright (C) 2009 University of Szeged
5 * Copyright (C) 2010 MIPS Technologies, Inc. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY MIPS TECHNOLOGIES, INC. ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MIPS TECHNOLOGIES, INC. OR
20 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
24 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #ifndef MIPSAssembler_h
30 #define MIPSAssembler_h
32 #if ENABLE(ASSEMBLER) && CPU(MIPS)
34 #include "AssemblerBuffer.h"
35 #include <wtf/Assertions.h>
36 #include <wtf/SegmentedVector.h>
40 typedef uint32_t MIPSWord
;
42 namespace MIPSRegisters
{
145 } // namespace MIPSRegisters
147 class MIPSAssembler
{
149 typedef MIPSRegisters::RegisterID RegisterID
;
150 typedef MIPSRegisters::FPRegisterID FPRegisterID
;
151 typedef SegmentedVector
<int, 64> Jumps
;
157 // MIPS instruction opcode field position
170 friend class MIPSAssembler
;
187 friend class MIPSAssembler
;
195 bool isUsed() const { return m_used
; }
196 void used() { m_used
= true; }
202 ASSERT(m_offset
== offset
);
209 void emitInst(MIPSWord op
)
211 void* oldBase
= m_buffer
.data();
215 void* newBase
= m_buffer
.data();
216 if (oldBase
!= newBase
)
217 relocateJumps(oldBase
, newBase
);
222 emitInst(0x00000000);
225 /* Need to insert one load data delay nop for mips1. */
233 /* Need to insert one coprocessor access delay nop for mips1. */
241 void move(RegisterID rd
, RegisterID rs
)
244 emitInst(0x00000021 | (rd
<< OP_SH_RD
) | (rs
<< OP_SH_RS
));
247 /* Set an immediate value to a register. This may generate 1 or 2
249 void li(RegisterID dest
, int imm
)
251 if (imm
>= -32768 && imm
<= 32767)
252 addiu(dest
, MIPSRegisters::zero
, imm
);
253 else if (imm
>= 0 && imm
< 65536)
254 ori(dest
, MIPSRegisters::zero
, imm
);
256 lui(dest
, imm
>> 16);
258 ori(dest
, dest
, imm
);
262 void lui(RegisterID rt
, int imm
)
264 emitInst(0x3c000000 | (rt
<< OP_SH_RT
) | (imm
& 0xffff));
267 void addiu(RegisterID rt
, RegisterID rs
, int imm
)
269 emitInst(0x24000000 | (rt
<< OP_SH_RT
) | (rs
<< OP_SH_RS
)
273 void addu(RegisterID rd
, RegisterID rs
, RegisterID rt
)
275 emitInst(0x00000021 | (rd
<< OP_SH_RD
) | (rs
<< OP_SH_RS
)
279 void subu(RegisterID rd
, RegisterID rs
, RegisterID rt
)
281 emitInst(0x00000023 | (rd
<< OP_SH_RD
) | (rs
<< OP_SH_RS
)
285 void mult(RegisterID rs
, RegisterID rt
)
287 emitInst(0x00000018 | (rs
<< OP_SH_RS
) | (rt
<< OP_SH_RT
));
290 void mfhi(RegisterID rd
)
292 emitInst(0x00000010 | (rd
<< OP_SH_RD
));
295 void mflo(RegisterID rd
)
297 emitInst(0x00000012 | (rd
<< OP_SH_RD
));
300 void mul(RegisterID rd
, RegisterID rs
, RegisterID rt
)
302 #if WTF_MIPS_ISA_AT_LEAST(32)
303 emitInst(0x70000002 | (rd
<< OP_SH_RD
) | (rs
<< OP_SH_RS
)
311 void andInsn(RegisterID rd
, RegisterID rs
, RegisterID rt
)
313 emitInst(0x00000024 | (rd
<< OP_SH_RD
) | (rs
<< OP_SH_RS
)
317 void andi(RegisterID rt
, RegisterID rs
, int imm
)
319 emitInst(0x30000000 | (rt
<< OP_SH_RT
) | (rs
<< OP_SH_RS
)
323 void nor(RegisterID rd
, RegisterID rs
, RegisterID rt
)
325 emitInst(0x00000027 | (rd
<< OP_SH_RD
) | (rs
<< OP_SH_RS
)
329 void orInsn(RegisterID rd
, RegisterID rs
, RegisterID rt
)
331 emitInst(0x00000025 | (rd
<< OP_SH_RD
) | (rs
<< OP_SH_RS
)
335 void ori(RegisterID rt
, RegisterID rs
, int imm
)
337 emitInst(0x34000000 | (rt
<< OP_SH_RT
) | (rs
<< OP_SH_RS
)
341 void xorInsn(RegisterID rd
, RegisterID rs
, RegisterID rt
)
343 emitInst(0x00000026 | (rd
<< OP_SH_RD
) | (rs
<< OP_SH_RS
)
347 void xori(RegisterID rt
, RegisterID rs
, int imm
)
349 emitInst(0x38000000 | (rt
<< OP_SH_RT
) | (rs
<< OP_SH_RS
)
353 void slt(RegisterID rd
, RegisterID rs
, RegisterID rt
)
355 emitInst(0x0000002a | (rd
<< OP_SH_RD
) | (rs
<< OP_SH_RS
)
359 void sltu(RegisterID rd
, RegisterID rs
, RegisterID rt
)
361 emitInst(0x0000002b | (rd
<< OP_SH_RD
) | (rs
<< OP_SH_RS
)
365 void sltiu(RegisterID rt
, RegisterID rs
, int imm
)
367 emitInst(0x2c000000 | (rt
<< OP_SH_RT
) | (rs
<< OP_SH_RS
)
371 void sll(RegisterID rd
, RegisterID rt
, int shamt
)
373 emitInst(0x00000000 | (rd
<< OP_SH_RD
) | (rt
<< OP_SH_RT
)
374 | ((shamt
& 0x1f) << OP_SH_SHAMT
));
377 void sllv(RegisterID rd
, RegisterID rt
, int rs
)
379 emitInst(0x00000004 | (rd
<< OP_SH_RD
) | (rt
<< OP_SH_RT
)
383 void sra(RegisterID rd
, RegisterID rt
, int shamt
)
385 emitInst(0x00000003 | (rd
<< OP_SH_RD
) | (rt
<< OP_SH_RT
)
386 | ((shamt
& 0x1f) << OP_SH_SHAMT
));
389 void srav(RegisterID rd
, RegisterID rt
, RegisterID rs
)
391 emitInst(0x00000007 | (rd
<< OP_SH_RD
) | (rt
<< OP_SH_RT
)
395 void lbu(RegisterID rt
, RegisterID rs
, int offset
)
397 emitInst(0x90000000 | (rt
<< OP_SH_RT
) | (rs
<< OP_SH_RS
)
398 | (offset
& 0xffff));
402 void lw(RegisterID rt
, RegisterID rs
, int offset
)
404 emitInst(0x8c000000 | (rt
<< OP_SH_RT
) | (rs
<< OP_SH_RS
)
405 | (offset
& 0xffff));
409 void lwl(RegisterID rt
, RegisterID rs
, int offset
)
411 emitInst(0x88000000 | (rt
<< OP_SH_RT
) | (rs
<< OP_SH_RS
)
412 | (offset
& 0xffff));
416 void lwr(RegisterID rt
, RegisterID rs
, int offset
)
418 emitInst(0x98000000 | (rt
<< OP_SH_RT
) | (rs
<< OP_SH_RS
)
419 | (offset
& 0xffff));
423 void lhu(RegisterID rt
, RegisterID rs
, int offset
)
425 emitInst(0x94000000 | (rt
<< OP_SH_RT
) | (rs
<< OP_SH_RS
)
426 | (offset
& 0xffff));
430 void sw(RegisterID rt
, RegisterID rs
, int offset
)
432 emitInst(0xac000000 | (rt
<< OP_SH_RT
) | (rs
<< OP_SH_RS
)
433 | (offset
& 0xffff));
436 void jr(RegisterID rs
)
438 emitInst(0x00000008 | (rs
<< OP_SH_RS
));
441 void jalr(RegisterID rs
)
443 emitInst(0x0000f809 | (rs
<< OP_SH_RS
));
448 emitInst(0x0c000000);
453 int value
= 512; /* BRK_BUG */
454 emitInst(0x0000000d | ((value
& 0x3ff) << OP_SH_CODE
));
457 void bgez(RegisterID rs
, int imm
)
459 emitInst(0x04010000 | (rs
<< OP_SH_RS
) | (imm
& 0xffff));
462 void bltz(RegisterID rs
, int imm
)
464 emitInst(0x04000000 | (rs
<< OP_SH_RS
) | (imm
& 0xffff));
467 void beq(RegisterID rs
, RegisterID rt
, int imm
)
469 emitInst(0x10000000 | (rs
<< OP_SH_RS
) | (rt
<< OP_SH_RT
) | (imm
& 0xffff));
472 void bne(RegisterID rs
, RegisterID rt
, int imm
)
474 emitInst(0x14000000 | (rs
<< OP_SH_RS
) | (rt
<< OP_SH_RT
) | (imm
& 0xffff));
479 emitInst(0x45010000);
484 emitInst(0x45000000);
489 return JmpSrc(m_buffer
.size());
494 m_jumps
.append(m_buffer
.size());
497 void addd(FPRegisterID fd
, FPRegisterID fs
, FPRegisterID ft
)
499 emitInst(0x46200000 | (fd
<< OP_SH_FD
) | (fs
<< OP_SH_FS
)
503 void subd(FPRegisterID fd
, FPRegisterID fs
, FPRegisterID ft
)
505 emitInst(0x46200001 | (fd
<< OP_SH_FD
) | (fs
<< OP_SH_FS
)
509 void muld(FPRegisterID fd
, FPRegisterID fs
, FPRegisterID ft
)
511 emitInst(0x46200002 | (fd
<< OP_SH_FD
) | (fs
<< OP_SH_FS
)
515 void lwc1(FPRegisterID ft
, RegisterID rs
, int offset
)
517 emitInst(0xc4000000 | (ft
<< OP_SH_FT
) | (rs
<< OP_SH_RS
)
518 | (offset
& 0xffff));
522 void ldc1(FPRegisterID ft
, RegisterID rs
, int offset
)
524 emitInst(0xd4000000 | (ft
<< OP_SH_FT
) | (rs
<< OP_SH_RS
)
525 | (offset
& 0xffff));
528 void swc1(FPRegisterID ft
, RegisterID rs
, int offset
)
530 emitInst(0xe4000000 | (ft
<< OP_SH_FT
) | (rs
<< OP_SH_RS
)
531 | (offset
& 0xffff));
534 void sdc1(FPRegisterID ft
, RegisterID rs
, int offset
)
536 emitInst(0xf4000000 | (ft
<< OP_SH_FT
) | (rs
<< OP_SH_RS
)
537 | (offset
& 0xffff));
540 void mtc1(RegisterID rt
, FPRegisterID fs
)
542 emitInst(0x44800000 | (fs
<< OP_SH_FS
) | (rt
<< OP_SH_RT
));
546 void mfc1(RegisterID rt
, FPRegisterID fs
)
548 emitInst(0x44000000 | (fs
<< OP_SH_FS
) | (rt
<< OP_SH_RT
));
552 void truncwd(FPRegisterID fd
, FPRegisterID fs
)
554 emitInst(0x4620000d | (fd
<< OP_SH_FD
) | (fs
<< OP_SH_FS
));
557 void cvtdw(FPRegisterID fd
, FPRegisterID fs
)
559 emitInst(0x46800021 | (fd
<< OP_SH_FD
) | (fs
<< OP_SH_FS
));
562 void ceqd(FPRegisterID fs
, FPRegisterID ft
)
564 emitInst(0x46200032 | (fs
<< OP_SH_FS
) | (ft
<< OP_SH_FT
));
568 void cngtd(FPRegisterID fs
, FPRegisterID ft
)
570 emitInst(0x4620003f | (fs
<< OP_SH_FS
) | (ft
<< OP_SH_FT
));
574 void cnged(FPRegisterID fs
, FPRegisterID ft
)
576 emitInst(0x4620003d | (fs
<< OP_SH_FS
) | (ft
<< OP_SH_FT
));
580 void cltd(FPRegisterID fs
, FPRegisterID ft
)
582 emitInst(0x4620003c | (fs
<< OP_SH_FS
) | (ft
<< OP_SH_FT
));
586 void cled(FPRegisterID fs
, FPRegisterID ft
)
588 emitInst(0x4620003e | (fs
<< OP_SH_FS
) | (ft
<< OP_SH_FT
));
592 void cueqd(FPRegisterID fs
, FPRegisterID ft
)
594 emitInst(0x46200033 | (fs
<< OP_SH_FS
) | (ft
<< OP_SH_FT
));
598 void coled(FPRegisterID fs
, FPRegisterID ft
)
600 emitInst(0x46200036 | (fs
<< OP_SH_FS
) | (ft
<< OP_SH_FT
));
604 void coltd(FPRegisterID fs
, FPRegisterID ft
)
606 emitInst(0x46200034 | (fs
<< OP_SH_FS
) | (ft
<< OP_SH_FT
));
610 void culed(FPRegisterID fs
, FPRegisterID ft
)
612 emitInst(0x46200037 | (fs
<< OP_SH_FS
) | (ft
<< OP_SH_FT
));
616 void cultd(FPRegisterID fs
, FPRegisterID ft
)
618 emitInst(0x46200035 | (fs
<< OP_SH_FS
) | (ft
<< OP_SH_FT
));
626 return JmpDst(m_buffer
.size());
629 JmpDst
align(int alignment
)
631 while (!m_buffer
.isAligned(alignment
))
637 static void* getRelocatedAddress(void* code
, JmpSrc jump
)
639 ASSERT(jump
.m_offset
!= -1);
640 void* b
= reinterpret_cast<void*>((reinterpret_cast<intptr_t>(code
)) + jump
.m_offset
);
644 static void* getRelocatedAddress(void* code
, JmpDst label
)
646 void* b
= reinterpret_cast<void*>((reinterpret_cast<intptr_t>(code
)) + label
.m_offset
);
650 static int getDifferenceBetweenLabels(JmpDst from
, JmpDst to
)
652 return to
.m_offset
- from
.m_offset
;
655 static int getDifferenceBetweenLabels(JmpDst from
, JmpSrc to
)
657 return to
.m_offset
- from
.m_offset
;
660 static int getDifferenceBetweenLabels(JmpSrc from
, JmpDst to
)
662 return to
.m_offset
- from
.m_offset
;
665 // Assembler admin methods:
669 return m_buffer
.size();
672 void* executableCopy(ExecutablePool
* allocator
)
674 void *result
= m_buffer
.executableCopy(allocator
);
678 relocateJumps(m_buffer
.data(), result
);
682 static unsigned getCallReturnOffset(JmpSrc call
)
684 // The return address is after a call and a delay slot instruction
685 return call
.m_offset
;
688 // Linking & patching:
690 // 'link' and 'patch' methods are for use on unprotected code - such as the code
691 // within the AssemblerBuffer, and code being patched by the patch buffer. Once
692 // code has been finalized it is (platform support permitting) within a non-
693 // writable region of memory; to modify the code in an execute-only execuable
694 // pool the 'repatch' and 'relink' methods should be used.
696 void linkJump(JmpSrc from
, JmpDst to
)
698 ASSERT(to
.m_offset
!= -1);
699 ASSERT(from
.m_offset
!= -1);
700 MIPSWord
* insn
= reinterpret_cast<MIPSWord
*>(reinterpret_cast<intptr_t>(m_buffer
.data()) + from
.m_offset
);
701 MIPSWord
* toPos
= reinterpret_cast<MIPSWord
*>(reinterpret_cast<intptr_t>(m_buffer
.data()) + to
.m_offset
);
703 ASSERT(!(*(insn
- 1)) && !(*(insn
- 2)) && !(*(insn
- 3)) && !(*(insn
- 5)));
705 linkWithOffset(insn
, toPos
);
708 static void linkJump(void* code
, JmpSrc from
, void* to
)
710 ASSERT(from
.m_offset
!= -1);
711 MIPSWord
* insn
= reinterpret_cast<MIPSWord
*>(reinterpret_cast<intptr_t>(code
) + from
.m_offset
);
713 ASSERT(!(*(insn
- 1)) && !(*(insn
- 2)) && !(*(insn
- 3)) && !(*(insn
- 5)));
715 linkWithOffset(insn
, to
);
718 static void linkCall(void* code
, JmpSrc from
, void* to
)
720 MIPSWord
* insn
= reinterpret_cast<MIPSWord
*>(reinterpret_cast<intptr_t>(code
) + from
.m_offset
);
721 linkCallInternal(insn
, to
);
724 static void linkPointer(void* code
, JmpDst from
, void* to
)
726 MIPSWord
* insn
= reinterpret_cast<MIPSWord
*>(reinterpret_cast<intptr_t>(code
) + from
.m_offset
);
727 ASSERT((*insn
& 0xffe00000) == 0x3c000000); // lui
728 *insn
= (*insn
& 0xffff0000) | ((reinterpret_cast<intptr_t>(to
) >> 16) & 0xffff);
730 ASSERT((*insn
& 0xfc000000) == 0x34000000); // ori
731 *insn
= (*insn
& 0xffff0000) | (reinterpret_cast<intptr_t>(to
) & 0xffff);
734 static void relinkJump(void* from
, void* to
)
736 MIPSWord
* insn
= reinterpret_cast<MIPSWord
*>(from
);
738 ASSERT(!(*(insn
- 1)) && !(*(insn
- 5)));
740 int flushSize
= linkWithOffset(insn
, to
);
742 ExecutableAllocator::cacheFlush(insn
, flushSize
);
745 static void relinkCall(void* from
, void* to
)
748 int size
= linkCallInternal(from
, to
);
749 if (size
== sizeof(MIPSWord
))
750 start
= reinterpret_cast<void*>(reinterpret_cast<intptr_t>(from
) - 2 * sizeof(MIPSWord
));
752 start
= reinterpret_cast<void*>(reinterpret_cast<intptr_t>(from
) - 4 * sizeof(MIPSWord
));
754 ExecutableAllocator::cacheFlush(start
, size
);
757 static void repatchInt32(void* from
, int32_t to
)
759 MIPSWord
* insn
= reinterpret_cast<MIPSWord
*>(from
);
760 ASSERT((*insn
& 0xffe00000) == 0x3c000000); // lui
761 *insn
= (*insn
& 0xffff0000) | ((to
>> 16) & 0xffff);
763 ASSERT((*insn
& 0xfc000000) == 0x34000000); // ori
764 *insn
= (*insn
& 0xffff0000) | (to
& 0xffff);
766 ExecutableAllocator::cacheFlush(insn
, 2 * sizeof(MIPSWord
));
769 static void repatchPointer(void* from
, void* to
)
771 repatchInt32(from
, reinterpret_cast<int32_t>(to
));
774 static void repatchLoadPtrToLEA(void* from
)
776 MIPSWord
* insn
= reinterpret_cast<MIPSWord
*>(from
);
778 ASSERT((*insn
& 0xfc000000) == 0x8c000000); // lw
780 *insn
= 0x24000000 | (*insn
& 0x03ffffff);
782 ExecutableAllocator::cacheFlush(insn
, sizeof(MIPSWord
));
787 /* Update each jump in the buffer of newBase. */
788 void relocateJumps(void* oldBase
, void* newBase
)
791 for (Jumps::Iterator iter
= m_jumps
.begin(); iter
!= m_jumps
.end(); ++iter
) {
793 MIPSWord
* insn
= reinterpret_cast<MIPSWord
*>(reinterpret_cast<intptr_t>(newBase
) + pos
);
795 // Need to make sure we have 5 valid instructions after pos
796 if ((unsigned int)pos
>= m_buffer
.size() - 5 * sizeof(MIPSWord
))
799 if ((*insn
& 0xfc000000) == 0x08000000) { // j
800 int offset
= *insn
& 0x03ffffff;
801 int oldInsnAddress
= (int)insn
- (int)newBase
+ (int)oldBase
;
802 int topFourBits
= (oldInsnAddress
+ 4) >> 28;
803 int oldTargetAddress
= (topFourBits
<< 28) | (offset
<< 2);
804 int newTargetAddress
= oldTargetAddress
- (int)oldBase
+ (int)newBase
;
805 int newInsnAddress
= (int)insn
;
806 if (((newInsnAddress
+ 4) >> 28) == (newTargetAddress
>> 28))
807 *insn
= 0x08000000 | ((newTargetAddress
>> 2) & 0x3ffffff);
810 *insn
= 0x3c000000 | (MIPSRegisters::t9
<< OP_SH_RT
) | ((newTargetAddress
>> 16) & 0xffff);
812 *(insn
+ 1) = 0x34000000 | (MIPSRegisters::t9
<< OP_SH_RT
) | (MIPSRegisters::t9
<< OP_SH_RS
) | (newTargetAddress
& 0xffff);
814 *(insn
+ 2) = 0x00000008 | (MIPSRegisters::t9
<< OP_SH_RS
);
816 } else if ((*insn
& 0xffe00000) == 0x3c000000) { // lui
817 int high
= (*insn
& 0xffff) << 16;
818 int low
= *(insn
+ 1) & 0xffff;
819 int oldTargetAddress
= high
| low
;
820 int newTargetAddress
= oldTargetAddress
- (int)oldBase
+ (int)newBase
;
822 *insn
= 0x3c000000 | (MIPSRegisters::t9
<< OP_SH_RT
) | ((newTargetAddress
>> 16) & 0xffff);
824 *(insn
+ 1) = 0x34000000 | (MIPSRegisters::t9
<< OP_SH_RT
) | (MIPSRegisters::t9
<< OP_SH_RS
) | (newTargetAddress
& 0xffff);
829 static int linkWithOffset(MIPSWord
* insn
, void* to
)
831 ASSERT((*insn
& 0xfc000000) == 0x10000000 // beq
832 || (*insn
& 0xfc000000) == 0x14000000 // bne
833 || (*insn
& 0xffff0000) == 0x45010000 // bc1t
834 || (*insn
& 0xffff0000) == 0x45000000); // bc1f
835 intptr_t diff
= (reinterpret_cast<intptr_t>(to
)
836 - reinterpret_cast<intptr_t>(insn
) - 4) >> 2;
838 if (diff
< -32768 || diff
> 32767 || *(insn
+ 2) != 0x10000003) {
840 Convert the sequence:
849 to the new sequence if possible:
858 OR to the new sequence:
861 lui $25, target >> 16
862 ori $25, $25, target & 0xffff
867 Note: beq/bne/bc1t/bc1f are converted to bne/beq/bc1f/bc1t.
870 if (*(insn
+ 2) == 0x10000003) {
871 if ((*insn
& 0xfc000000) == 0x10000000) // beq
872 *insn
= (*insn
& 0x03ff0000) | 0x14000005; // bne
873 else if ((*insn
& 0xfc000000) == 0x14000000) // bne
874 *insn
= (*insn
& 0x03ff0000) | 0x10000005; // beq
875 else if ((*insn
& 0xffff0000) == 0x45010000) // bc1t
876 *insn
= 0x45000005; // bc1f
877 else if ((*insn
& 0xffff0000) == 0x45000000) // bc1f
878 *insn
= 0x45010005; // bc1t
884 if ((reinterpret_cast<intptr_t>(insn
) + 4) >> 28
885 == reinterpret_cast<intptr_t>(to
) >> 28) {
886 *insn
= 0x08000000 | ((reinterpret_cast<intptr_t>(to
) >> 2) & 0x3ffffff);
888 return 4 * sizeof(MIPSWord
);
891 intptr_t newTargetAddress
= reinterpret_cast<intptr_t>(to
);
893 *insn
= 0x3c000000 | (MIPSRegisters::t9
<< OP_SH_RT
) | ((newTargetAddress
>> 16) & 0xffff);
895 *(insn
+ 1) = 0x34000000 | (MIPSRegisters::t9
<< OP_SH_RT
) | (MIPSRegisters::t9
<< OP_SH_RS
) | (newTargetAddress
& 0xffff);
897 *(insn
+ 2) = 0x00000008 | (MIPSRegisters::t9
<< OP_SH_RS
);
898 return 5 * sizeof(MIPSWord
);
901 *insn
= (*insn
& 0xffff0000) | (diff
& 0xffff);
902 return sizeof(MIPSWord
);
905 static int linkCallInternal(void* from
, void* to
)
907 MIPSWord
* insn
= reinterpret_cast<MIPSWord
*>(from
);
910 if ((*(insn
+ 2) & 0xfc000000) == 0x0c000000) { // jal
911 if ((reinterpret_cast<intptr_t>(from
) - 4) >> 28
912 == reinterpret_cast<intptr_t>(to
) >> 28) {
913 *(insn
+ 2) = 0x0c000000 | ((reinterpret_cast<intptr_t>(to
) >> 2) & 0x3ffffff);
914 return sizeof(MIPSWord
);
917 /* lui $25, (to >> 16) & 0xffff */
918 *insn
= 0x3c000000 | (MIPSRegisters::t9
<< OP_SH_RT
) | ((reinterpret_cast<intptr_t>(to
) >> 16) & 0xffff);
919 /* ori $25, $25, to & 0xffff */
920 *(insn
+ 1) = 0x34000000 | (MIPSRegisters::t9
<< OP_SH_RT
) | (MIPSRegisters::t9
<< OP_SH_RS
) | (reinterpret_cast<intptr_t>(to
) & 0xffff);
922 *(insn
+ 2) = 0x0000f809 | (MIPSRegisters::t9
<< OP_SH_RS
);
923 return 3 * sizeof(MIPSWord
);
926 ASSERT((*insn
& 0xffe00000) == 0x3c000000); // lui
927 ASSERT((*(insn
+ 1) & 0xfc000000) == 0x34000000); // ori
930 *insn
= (*insn
& 0xffff0000) | ((reinterpret_cast<intptr_t>(to
) >> 16) & 0xffff);
932 *(insn
+ 1) = (*(insn
+ 1) & 0xffff0000) | (reinterpret_cast<intptr_t>(to
) & 0xffff);
933 return 2 * sizeof(MIPSWord
);
936 AssemblerBuffer m_buffer
;
942 #endif // ENABLE(ASSEMBLER) && CPU(MIPS)
944 #endif // MIPSAssembler_h