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
<AssemblerLabel
, 64> Jumps
;
157 // MIPS instruction opcode field position
169 void emitInst(MIPSWord op
)
171 void* oldBase
= m_buffer
.data();
175 void* newBase
= m_buffer
.data();
176 if (oldBase
!= newBase
)
177 relocateJumps(oldBase
, newBase
);
182 emitInst(0x00000000);
185 /* Need to insert one load data delay nop for mips1. */
193 /* Need to insert one coprocessor access delay nop for mips1. */
201 void move(RegisterID rd
, RegisterID rs
)
204 emitInst(0x00000021 | (rd
<< OP_SH_RD
) | (rs
<< OP_SH_RS
));
207 /* Set an immediate value to a register. This may generate 1 or 2
209 void li(RegisterID dest
, int imm
)
211 if (imm
>= -32768 && imm
<= 32767)
212 addiu(dest
, MIPSRegisters::zero
, imm
);
213 else if (imm
>= 0 && imm
< 65536)
214 ori(dest
, MIPSRegisters::zero
, imm
);
216 lui(dest
, imm
>> 16);
218 ori(dest
, dest
, imm
);
222 void lui(RegisterID rt
, int imm
)
224 emitInst(0x3c000000 | (rt
<< OP_SH_RT
) | (imm
& 0xffff));
227 void addiu(RegisterID rt
, RegisterID rs
, int imm
)
229 emitInst(0x24000000 | (rt
<< OP_SH_RT
) | (rs
<< OP_SH_RS
)
233 void addu(RegisterID rd
, RegisterID rs
, RegisterID rt
)
235 emitInst(0x00000021 | (rd
<< OP_SH_RD
) | (rs
<< OP_SH_RS
)
239 void subu(RegisterID rd
, RegisterID rs
, RegisterID rt
)
241 emitInst(0x00000023 | (rd
<< OP_SH_RD
) | (rs
<< OP_SH_RS
)
245 void mult(RegisterID rs
, RegisterID rt
)
247 emitInst(0x00000018 | (rs
<< OP_SH_RS
) | (rt
<< OP_SH_RT
));
250 void div(RegisterID rs
, RegisterID rt
)
252 emitInst(0x0000001a | (rs
<< OP_SH_RS
) | (rt
<< OP_SH_RT
));
255 void mfhi(RegisterID rd
)
257 emitInst(0x00000010 | (rd
<< OP_SH_RD
));
260 void mflo(RegisterID rd
)
262 emitInst(0x00000012 | (rd
<< OP_SH_RD
));
265 void mul(RegisterID rd
, RegisterID rs
, RegisterID rt
)
267 #if WTF_MIPS_ISA_AT_LEAST(32)
268 emitInst(0x70000002 | (rd
<< OP_SH_RD
) | (rs
<< OP_SH_RS
)
276 void andInsn(RegisterID rd
, RegisterID rs
, RegisterID rt
)
278 emitInst(0x00000024 | (rd
<< OP_SH_RD
) | (rs
<< OP_SH_RS
)
282 void andi(RegisterID rt
, RegisterID rs
, int imm
)
284 emitInst(0x30000000 | (rt
<< OP_SH_RT
) | (rs
<< OP_SH_RS
)
288 void nor(RegisterID rd
, RegisterID rs
, RegisterID rt
)
290 emitInst(0x00000027 | (rd
<< OP_SH_RD
) | (rs
<< OP_SH_RS
)
294 void orInsn(RegisterID rd
, RegisterID rs
, RegisterID rt
)
296 emitInst(0x00000025 | (rd
<< OP_SH_RD
) | (rs
<< OP_SH_RS
)
300 void ori(RegisterID rt
, RegisterID rs
, int imm
)
302 emitInst(0x34000000 | (rt
<< OP_SH_RT
) | (rs
<< OP_SH_RS
)
306 void xorInsn(RegisterID rd
, RegisterID rs
, RegisterID rt
)
308 emitInst(0x00000026 | (rd
<< OP_SH_RD
) | (rs
<< OP_SH_RS
)
312 void xori(RegisterID rt
, RegisterID rs
, int imm
)
314 emitInst(0x38000000 | (rt
<< OP_SH_RT
) | (rs
<< OP_SH_RS
)
318 void slt(RegisterID rd
, RegisterID rs
, RegisterID rt
)
320 emitInst(0x0000002a | (rd
<< OP_SH_RD
) | (rs
<< OP_SH_RS
)
324 void sltu(RegisterID rd
, RegisterID rs
, RegisterID rt
)
326 emitInst(0x0000002b | (rd
<< OP_SH_RD
) | (rs
<< OP_SH_RS
)
330 void sltiu(RegisterID rt
, RegisterID rs
, int imm
)
332 emitInst(0x2c000000 | (rt
<< OP_SH_RT
) | (rs
<< OP_SH_RS
)
336 void sll(RegisterID rd
, RegisterID rt
, int shamt
)
338 emitInst(0x00000000 | (rd
<< OP_SH_RD
) | (rt
<< OP_SH_RT
)
339 | ((shamt
& 0x1f) << OP_SH_SHAMT
));
342 void sllv(RegisterID rd
, RegisterID rt
, int rs
)
344 emitInst(0x00000004 | (rd
<< OP_SH_RD
) | (rt
<< OP_SH_RT
)
348 void sra(RegisterID rd
, RegisterID rt
, int shamt
)
350 emitInst(0x00000003 | (rd
<< OP_SH_RD
) | (rt
<< OP_SH_RT
)
351 | ((shamt
& 0x1f) << OP_SH_SHAMT
));
354 void srav(RegisterID rd
, RegisterID rt
, RegisterID rs
)
356 emitInst(0x00000007 | (rd
<< OP_SH_RD
) | (rt
<< OP_SH_RT
)
360 void srl(RegisterID rd
, RegisterID rt
, int shamt
)
362 emitInst(0x00000002 | (rd
<< OP_SH_RD
) | (rt
<< OP_SH_RT
)
363 | ((shamt
& 0x1f) << OP_SH_SHAMT
));
366 void srlv(RegisterID rd
, RegisterID rt
, RegisterID rs
)
368 emitInst(0x00000006 | (rd
<< OP_SH_RD
) | (rt
<< OP_SH_RT
)
372 void lbu(RegisterID rt
, RegisterID rs
, int offset
)
374 emitInst(0x90000000 | (rt
<< OP_SH_RT
) | (rs
<< OP_SH_RS
)
375 | (offset
& 0xffff));
379 void lw(RegisterID rt
, RegisterID rs
, int offset
)
381 emitInst(0x8c000000 | (rt
<< OP_SH_RT
) | (rs
<< OP_SH_RS
)
382 | (offset
& 0xffff));
386 void lwl(RegisterID rt
, RegisterID rs
, int offset
)
388 emitInst(0x88000000 | (rt
<< OP_SH_RT
) | (rs
<< OP_SH_RS
)
389 | (offset
& 0xffff));
393 void lwr(RegisterID rt
, RegisterID rs
, int offset
)
395 emitInst(0x98000000 | (rt
<< OP_SH_RT
) | (rs
<< OP_SH_RS
)
396 | (offset
& 0xffff));
400 void lhu(RegisterID rt
, RegisterID rs
, int offset
)
402 emitInst(0x94000000 | (rt
<< OP_SH_RT
) | (rs
<< OP_SH_RS
)
403 | (offset
& 0xffff));
407 void sw(RegisterID rt
, RegisterID rs
, int offset
)
409 emitInst(0xac000000 | (rt
<< OP_SH_RT
) | (rs
<< OP_SH_RS
)
410 | (offset
& 0xffff));
413 void jr(RegisterID rs
)
415 emitInst(0x00000008 | (rs
<< OP_SH_RS
));
418 void jalr(RegisterID rs
)
420 emitInst(0x0000f809 | (rs
<< OP_SH_RS
));
425 emitInst(0x0c000000);
430 int value
= 512; /* BRK_BUG */
431 emitInst(0x0000000d | ((value
& 0x3ff) << OP_SH_CODE
));
434 void bgez(RegisterID rs
, int imm
)
436 emitInst(0x04010000 | (rs
<< OP_SH_RS
) | (imm
& 0xffff));
439 void bltz(RegisterID rs
, int imm
)
441 emitInst(0x04000000 | (rs
<< OP_SH_RS
) | (imm
& 0xffff));
444 void beq(RegisterID rs
, RegisterID rt
, int imm
)
446 emitInst(0x10000000 | (rs
<< OP_SH_RS
) | (rt
<< OP_SH_RT
) | (imm
& 0xffff));
449 void bne(RegisterID rs
, RegisterID rt
, int imm
)
451 emitInst(0x14000000 | (rs
<< OP_SH_RS
) | (rt
<< OP_SH_RT
) | (imm
& 0xffff));
456 emitInst(0x45010000);
461 emitInst(0x45000000);
466 m_jumps
.append(m_buffer
.label());
469 void addd(FPRegisterID fd
, FPRegisterID fs
, FPRegisterID ft
)
471 emitInst(0x46200000 | (fd
<< OP_SH_FD
) | (fs
<< OP_SH_FS
)
475 void subd(FPRegisterID fd
, FPRegisterID fs
, FPRegisterID ft
)
477 emitInst(0x46200001 | (fd
<< OP_SH_FD
) | (fs
<< OP_SH_FS
)
481 void muld(FPRegisterID fd
, FPRegisterID fs
, FPRegisterID ft
)
483 emitInst(0x46200002 | (fd
<< OP_SH_FD
) | (fs
<< OP_SH_FS
)
487 void divd(FPRegisterID fd
, FPRegisterID fs
, FPRegisterID ft
)
489 emitInst(0x46200003 | (fd
<< OP_SH_FD
) | (fs
<< OP_SH_FS
)
493 void lwc1(FPRegisterID ft
, RegisterID rs
, int offset
)
495 emitInst(0xc4000000 | (ft
<< OP_SH_FT
) | (rs
<< OP_SH_RS
)
496 | (offset
& 0xffff));
500 void ldc1(FPRegisterID ft
, RegisterID rs
, int offset
)
502 emitInst(0xd4000000 | (ft
<< OP_SH_FT
) | (rs
<< OP_SH_RS
)
503 | (offset
& 0xffff));
506 void swc1(FPRegisterID ft
, RegisterID rs
, int offset
)
508 emitInst(0xe4000000 | (ft
<< OP_SH_FT
) | (rs
<< OP_SH_RS
)
509 | (offset
& 0xffff));
512 void sdc1(FPRegisterID ft
, RegisterID rs
, int offset
)
514 emitInst(0xf4000000 | (ft
<< OP_SH_FT
) | (rs
<< OP_SH_RS
)
515 | (offset
& 0xffff));
518 void mtc1(RegisterID rt
, FPRegisterID fs
)
520 emitInst(0x44800000 | (fs
<< OP_SH_FS
) | (rt
<< OP_SH_RT
));
524 void mthc1(RegisterID rt
, FPRegisterID fs
)
526 emitInst(0x44e00000 | (fs
<< OP_SH_FS
) | (rt
<< OP_SH_RT
));
530 void mfc1(RegisterID rt
, FPRegisterID fs
)
532 emitInst(0x44000000 | (fs
<< OP_SH_FS
) | (rt
<< OP_SH_RT
));
536 void sqrtd(FPRegisterID fd
, FPRegisterID fs
)
538 emitInst(0x46200004 | (fd
<< OP_SH_FD
) | (fs
<< OP_SH_FS
));
541 void truncwd(FPRegisterID fd
, FPRegisterID fs
)
543 emitInst(0x4620000d | (fd
<< OP_SH_FD
) | (fs
<< OP_SH_FS
));
546 void cvtdw(FPRegisterID fd
, FPRegisterID fs
)
548 emitInst(0x46800021 | (fd
<< OP_SH_FD
) | (fs
<< OP_SH_FS
));
551 void cvtwd(FPRegisterID fd
, FPRegisterID fs
)
553 emitInst(0x46200024 | (fd
<< OP_SH_FD
) | (fs
<< OP_SH_FS
));
556 void ceqd(FPRegisterID fs
, FPRegisterID ft
)
558 emitInst(0x46200032 | (fs
<< OP_SH_FS
) | (ft
<< OP_SH_FT
));
562 void cngtd(FPRegisterID fs
, FPRegisterID ft
)
564 emitInst(0x4620003f | (fs
<< OP_SH_FS
) | (ft
<< OP_SH_FT
));
568 void cnged(FPRegisterID fs
, FPRegisterID ft
)
570 emitInst(0x4620003d | (fs
<< OP_SH_FS
) | (ft
<< OP_SH_FT
));
574 void cltd(FPRegisterID fs
, FPRegisterID ft
)
576 emitInst(0x4620003c | (fs
<< OP_SH_FS
) | (ft
<< OP_SH_FT
));
580 void cled(FPRegisterID fs
, FPRegisterID ft
)
582 emitInst(0x4620003e | (fs
<< OP_SH_FS
) | (ft
<< OP_SH_FT
));
586 void cueqd(FPRegisterID fs
, FPRegisterID ft
)
588 emitInst(0x46200033 | (fs
<< OP_SH_FS
) | (ft
<< OP_SH_FT
));
592 void coled(FPRegisterID fs
, FPRegisterID ft
)
594 emitInst(0x46200036 | (fs
<< OP_SH_FS
) | (ft
<< OP_SH_FT
));
598 void coltd(FPRegisterID fs
, FPRegisterID ft
)
600 emitInst(0x46200034 | (fs
<< OP_SH_FS
) | (ft
<< OP_SH_FT
));
604 void culed(FPRegisterID fs
, FPRegisterID ft
)
606 emitInst(0x46200037 | (fs
<< OP_SH_FS
) | (ft
<< OP_SH_FT
));
610 void cultd(FPRegisterID fs
, FPRegisterID ft
)
612 emitInst(0x46200035 | (fs
<< OP_SH_FS
) | (ft
<< OP_SH_FT
));
618 AssemblerLabel
label()
620 return m_buffer
.label();
623 AssemblerLabel
align(int alignment
)
625 while (!m_buffer
.isAligned(alignment
))
631 static void* getRelocatedAddress(void* code
, AssemblerLabel label
)
633 return reinterpret_cast<void*>(reinterpret_cast<char*>(code
) + label
.m_offset
);
636 static int getDifferenceBetweenLabels(AssemblerLabel a
, AssemblerLabel b
)
638 return b
.m_offset
- a
.m_offset
;
641 // Assembler admin methods:
643 size_t codeSize() const
645 return m_buffer
.codeSize();
648 void* executableCopy(JSGlobalData
& globalData
, ExecutablePool
* allocator
)
650 void *result
= m_buffer
.executableCopy(globalData
, allocator
);
654 relocateJumps(m_buffer
.data(), result
);
659 unsigned debugOffset() { return m_buffer
.debugOffset(); }
662 static unsigned getCallReturnOffset(AssemblerLabel call
)
664 // The return address is after a call and a delay slot instruction
665 return call
.m_offset
;
668 // Linking & patching:
670 // 'link' and 'patch' methods are for use on unprotected code - such as the code
671 // within the AssemblerBuffer, and code being patched by the patch buffer. Once
672 // code has been finalized it is (platform support permitting) within a non-
673 // writable region of memory; to modify the code in an execute-only execuable
674 // pool the 'repatch' and 'relink' methods should be used.
676 void linkJump(AssemblerLabel from
, AssemblerLabel to
)
679 ASSERT(from
.isSet());
680 MIPSWord
* insn
= reinterpret_cast<MIPSWord
*>(reinterpret_cast<intptr_t>(m_buffer
.data()) + from
.m_offset
);
681 MIPSWord
* toPos
= reinterpret_cast<MIPSWord
*>(reinterpret_cast<intptr_t>(m_buffer
.data()) + to
.m_offset
);
683 ASSERT(!(*(insn
- 1)) && !(*(insn
- 2)) && !(*(insn
- 3)) && !(*(insn
- 5)));
685 linkWithOffset(insn
, toPos
);
688 static void linkJump(void* code
, AssemblerLabel from
, void* to
)
690 ASSERT(from
.isSet());
691 MIPSWord
* insn
= reinterpret_cast<MIPSWord
*>(reinterpret_cast<intptr_t>(code
) + from
.m_offset
);
693 ASSERT(!(*(insn
- 1)) && !(*(insn
- 2)) && !(*(insn
- 3)) && !(*(insn
- 5)));
695 linkWithOffset(insn
, to
);
698 static void linkCall(void* code
, AssemblerLabel from
, void* to
)
700 MIPSWord
* insn
= reinterpret_cast<MIPSWord
*>(reinterpret_cast<intptr_t>(code
) + from
.m_offset
);
701 linkCallInternal(insn
, to
);
704 static void linkPointer(void* code
, AssemblerLabel from
, void* to
)
706 MIPSWord
* insn
= reinterpret_cast<MIPSWord
*>(reinterpret_cast<intptr_t>(code
) + from
.m_offset
);
707 ASSERT((*insn
& 0xffe00000) == 0x3c000000); // lui
708 *insn
= (*insn
& 0xffff0000) | ((reinterpret_cast<intptr_t>(to
) >> 16) & 0xffff);
710 ASSERT((*insn
& 0xfc000000) == 0x34000000); // ori
711 *insn
= (*insn
& 0xffff0000) | (reinterpret_cast<intptr_t>(to
) & 0xffff);
714 static void relinkJump(void* from
, void* to
)
716 MIPSWord
* insn
= reinterpret_cast<MIPSWord
*>(from
);
718 ASSERT(!(*(insn
- 1)) && !(*(insn
- 5)));
720 int flushSize
= linkWithOffset(insn
, to
);
722 ExecutableAllocator::cacheFlush(insn
, flushSize
);
725 static void relinkCall(void* from
, void* to
)
728 int size
= linkCallInternal(from
, to
);
729 if (size
== sizeof(MIPSWord
))
730 start
= reinterpret_cast<void*>(reinterpret_cast<intptr_t>(from
) - 2 * sizeof(MIPSWord
));
732 start
= reinterpret_cast<void*>(reinterpret_cast<intptr_t>(from
) - 4 * sizeof(MIPSWord
));
734 ExecutableAllocator::cacheFlush(start
, size
);
737 static void repatchInt32(void* from
, int32_t to
)
739 MIPSWord
* insn
= reinterpret_cast<MIPSWord
*>(from
);
740 ASSERT((*insn
& 0xffe00000) == 0x3c000000); // lui
741 *insn
= (*insn
& 0xffff0000) | ((to
>> 16) & 0xffff);
743 ASSERT((*insn
& 0xfc000000) == 0x34000000); // ori
744 *insn
= (*insn
& 0xffff0000) | (to
& 0xffff);
746 ExecutableAllocator::cacheFlush(insn
, 2 * sizeof(MIPSWord
));
749 static int32_t readInt32(void* from
)
751 MIPSWord
* insn
= reinterpret_cast<MIPSWord
*>(from
);
752 ASSERT((*insn
& 0xffe00000) == 0x3c000000); // lui
753 int32_t result
= (*insn
& 0x0000ffff) << 16;
755 ASSERT((*insn
& 0xfc000000) == 0x34000000); // ori
756 result
|= *insn
& 0x0000ffff
759 static void repatchCompact(void* where
, int32_t value
)
761 repatchInt32(where
, value
);
764 static void repatchPointer(void* from
, void* to
)
766 repatchInt32(from
, reinterpret_cast<int32_t>(to
));
769 static void* readPointer(void* from
)
771 return static_cast<void*>(readInt32(from
));
775 /* Update each jump in the buffer of newBase. */
776 void relocateJumps(void* oldBase
, void* newBase
)
779 for (Jumps::Iterator iter
= m_jumps
.begin(); iter
!= m_jumps
.end(); ++iter
) {
780 int pos
= iter
->m_offset
;
781 MIPSWord
* insn
= reinterpret_cast<MIPSWord
*>(reinterpret_cast<intptr_t>(newBase
) + pos
);
783 // Need to make sure we have 5 valid instructions after pos
784 if ((unsigned int)pos
>= m_buffer
.codeSize() - 5 * sizeof(MIPSWord
))
787 if ((*insn
& 0xfc000000) == 0x08000000) { // j
788 int offset
= *insn
& 0x03ffffff;
789 int oldInsnAddress
= (int)insn
- (int)newBase
+ (int)oldBase
;
790 int topFourBits
= (oldInsnAddress
+ 4) >> 28;
791 int oldTargetAddress
= (topFourBits
<< 28) | (offset
<< 2);
792 int newTargetAddress
= oldTargetAddress
- (int)oldBase
+ (int)newBase
;
793 int newInsnAddress
= (int)insn
;
794 if (((newInsnAddress
+ 4) >> 28) == (newTargetAddress
>> 28))
795 *insn
= 0x08000000 | ((newTargetAddress
>> 2) & 0x3ffffff);
798 *insn
= 0x3c000000 | (MIPSRegisters::t9
<< OP_SH_RT
) | ((newTargetAddress
>> 16) & 0xffff);
800 *(insn
+ 1) = 0x34000000 | (MIPSRegisters::t9
<< OP_SH_RT
) | (MIPSRegisters::t9
<< OP_SH_RS
) | (newTargetAddress
& 0xffff);
802 *(insn
+ 2) = 0x00000008 | (MIPSRegisters::t9
<< OP_SH_RS
);
804 } else if ((*insn
& 0xffe00000) == 0x3c000000) { // lui
805 int high
= (*insn
& 0xffff) << 16;
806 int low
= *(insn
+ 1) & 0xffff;
807 int oldTargetAddress
= high
| low
;
808 int newTargetAddress
= oldTargetAddress
- (int)oldBase
+ (int)newBase
;
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);
817 static int linkWithOffset(MIPSWord
* insn
, void* to
)
819 ASSERT((*insn
& 0xfc000000) == 0x10000000 // beq
820 || (*insn
& 0xfc000000) == 0x14000000 // bne
821 || (*insn
& 0xffff0000) == 0x45010000 // bc1t
822 || (*insn
& 0xffff0000) == 0x45000000); // bc1f
823 intptr_t diff
= (reinterpret_cast<intptr_t>(to
)
824 - reinterpret_cast<intptr_t>(insn
) - 4) >> 2;
826 if (diff
< -32768 || diff
> 32767 || *(insn
+ 2) != 0x10000003) {
828 Convert the sequence:
837 to the new sequence if possible:
846 OR to the new sequence:
849 lui $25, target >> 16
850 ori $25, $25, target & 0xffff
855 Note: beq/bne/bc1t/bc1f are converted to bne/beq/bc1f/bc1t.
858 if (*(insn
+ 2) == 0x10000003) {
859 if ((*insn
& 0xfc000000) == 0x10000000) // beq
860 *insn
= (*insn
& 0x03ff0000) | 0x14000005; // bne
861 else if ((*insn
& 0xfc000000) == 0x14000000) // bne
862 *insn
= (*insn
& 0x03ff0000) | 0x10000005; // beq
863 else if ((*insn
& 0xffff0000) == 0x45010000) // bc1t
864 *insn
= 0x45000005; // bc1f
865 else if ((*insn
& 0xffff0000) == 0x45000000) // bc1f
866 *insn
= 0x45010005; // bc1t
872 if ((reinterpret_cast<intptr_t>(insn
) + 4) >> 28
873 == reinterpret_cast<intptr_t>(to
) >> 28) {
874 *insn
= 0x08000000 | ((reinterpret_cast<intptr_t>(to
) >> 2) & 0x3ffffff);
876 return 4 * sizeof(MIPSWord
);
879 intptr_t newTargetAddress
= reinterpret_cast<intptr_t>(to
);
881 *insn
= 0x3c000000 | (MIPSRegisters::t9
<< OP_SH_RT
) | ((newTargetAddress
>> 16) & 0xffff);
883 *(insn
+ 1) = 0x34000000 | (MIPSRegisters::t9
<< OP_SH_RT
) | (MIPSRegisters::t9
<< OP_SH_RS
) | (newTargetAddress
& 0xffff);
885 *(insn
+ 2) = 0x00000008 | (MIPSRegisters::t9
<< OP_SH_RS
);
886 return 5 * sizeof(MIPSWord
);
889 *insn
= (*insn
& 0xffff0000) | (diff
& 0xffff);
890 return sizeof(MIPSWord
);
893 static int linkCallInternal(void* from
, void* to
)
895 MIPSWord
* insn
= reinterpret_cast<MIPSWord
*>(from
);
898 if ((*(insn
+ 2) & 0xfc000000) == 0x0c000000) { // jal
899 if ((reinterpret_cast<intptr_t>(from
) - 4) >> 28
900 == reinterpret_cast<intptr_t>(to
) >> 28) {
901 *(insn
+ 2) = 0x0c000000 | ((reinterpret_cast<intptr_t>(to
) >> 2) & 0x3ffffff);
902 return sizeof(MIPSWord
);
905 /* lui $25, (to >> 16) & 0xffff */
906 *insn
= 0x3c000000 | (MIPSRegisters::t9
<< OP_SH_RT
) | ((reinterpret_cast<intptr_t>(to
) >> 16) & 0xffff);
907 /* ori $25, $25, to & 0xffff */
908 *(insn
+ 1) = 0x34000000 | (MIPSRegisters::t9
<< OP_SH_RT
) | (MIPSRegisters::t9
<< OP_SH_RS
) | (reinterpret_cast<intptr_t>(to
) & 0xffff);
910 *(insn
+ 2) = 0x0000f809 | (MIPSRegisters::t9
<< OP_SH_RS
);
911 return 3 * sizeof(MIPSWord
);
914 ASSERT((*insn
& 0xffe00000) == 0x3c000000); // lui
915 ASSERT((*(insn
+ 1) & 0xfc000000) == 0x34000000); // ori
918 *insn
= (*insn
& 0xffff0000) | ((reinterpret_cast<intptr_t>(to
) >> 16) & 0xffff);
920 *(insn
+ 1) = (*(insn
+ 1) & 0xffff0000) | (reinterpret_cast<intptr_t>(to
) & 0xffff);
921 return 2 * sizeof(MIPSWord
);
924 AssemblerBuffer m_buffer
;
930 #endif // ENABLE(ASSEMBLER) && CPU(MIPS)
932 #endif // MIPSAssembler_h