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 "JITCompilationEffort.h"
36 #include <wtf/Assertions.h>
37 #include <wtf/SegmentedVector.h>
41 typedef uint32_t MIPSWord
;
43 namespace MIPSRegisters
{
146 } // namespace MIPSRegisters
148 class MIPSAssembler
{
150 typedef MIPSRegisters::RegisterID RegisterID
;
151 typedef MIPSRegisters::FPRegisterID FPRegisterID
;
152 typedef SegmentedVector
<AssemblerLabel
, 64> Jumps
;
158 // MIPS instruction opcode field position
170 void emitInst(MIPSWord op
)
172 void* oldBase
= m_buffer
.data();
176 void* newBase
= m_buffer
.data();
177 if (oldBase
!= newBase
)
178 relocateJumps(oldBase
, newBase
);
183 emitInst(0x00000000);
186 /* Need to insert one load data delay nop for mips1. */
194 /* Need to insert one coprocessor access delay nop for mips1. */
202 void move(RegisterID rd
, RegisterID rs
)
205 emitInst(0x00000021 | (rd
<< OP_SH_RD
) | (rs
<< OP_SH_RS
));
208 /* Set an immediate value to a register. This may generate 1 or 2
210 void li(RegisterID dest
, int imm
)
212 if (imm
>= -32768 && imm
<= 32767)
213 addiu(dest
, MIPSRegisters::zero
, imm
);
214 else if (imm
>= 0 && imm
< 65536)
215 ori(dest
, MIPSRegisters::zero
, imm
);
217 lui(dest
, imm
>> 16);
219 ori(dest
, dest
, imm
);
223 void lui(RegisterID rt
, int imm
)
225 emitInst(0x3c000000 | (rt
<< OP_SH_RT
) | (imm
& 0xffff));
228 void addiu(RegisterID rt
, RegisterID rs
, int imm
)
230 emitInst(0x24000000 | (rt
<< OP_SH_RT
) | (rs
<< OP_SH_RS
)
234 void addu(RegisterID rd
, RegisterID rs
, RegisterID rt
)
236 emitInst(0x00000021 | (rd
<< OP_SH_RD
) | (rs
<< OP_SH_RS
)
240 void subu(RegisterID rd
, RegisterID rs
, RegisterID rt
)
242 emitInst(0x00000023 | (rd
<< OP_SH_RD
) | (rs
<< OP_SH_RS
)
246 void mult(RegisterID rs
, RegisterID rt
)
248 emitInst(0x00000018 | (rs
<< OP_SH_RS
) | (rt
<< OP_SH_RT
));
251 void div(RegisterID rs
, RegisterID rt
)
253 emitInst(0x0000001a | (rs
<< OP_SH_RS
) | (rt
<< OP_SH_RT
));
256 void mfhi(RegisterID rd
)
258 emitInst(0x00000010 | (rd
<< OP_SH_RD
));
261 void mflo(RegisterID rd
)
263 emitInst(0x00000012 | (rd
<< OP_SH_RD
));
266 void mul(RegisterID rd
, RegisterID rs
, RegisterID rt
)
268 #if WTF_MIPS_ISA_AT_LEAST(32)
269 emitInst(0x70000002 | (rd
<< OP_SH_RD
) | (rs
<< OP_SH_RS
)
277 void andInsn(RegisterID rd
, RegisterID rs
, RegisterID rt
)
279 emitInst(0x00000024 | (rd
<< OP_SH_RD
) | (rs
<< OP_SH_RS
)
283 void andi(RegisterID rt
, RegisterID rs
, int imm
)
285 emitInst(0x30000000 | (rt
<< OP_SH_RT
) | (rs
<< OP_SH_RS
)
289 void nor(RegisterID rd
, RegisterID rs
, RegisterID rt
)
291 emitInst(0x00000027 | (rd
<< OP_SH_RD
) | (rs
<< OP_SH_RS
)
295 void orInsn(RegisterID rd
, RegisterID rs
, RegisterID rt
)
297 emitInst(0x00000025 | (rd
<< OP_SH_RD
) | (rs
<< OP_SH_RS
)
301 void ori(RegisterID rt
, RegisterID rs
, int imm
)
303 emitInst(0x34000000 | (rt
<< OP_SH_RT
) | (rs
<< OP_SH_RS
)
307 void xorInsn(RegisterID rd
, RegisterID rs
, RegisterID rt
)
309 emitInst(0x00000026 | (rd
<< OP_SH_RD
) | (rs
<< OP_SH_RS
)
313 void xori(RegisterID rt
, RegisterID rs
, int imm
)
315 emitInst(0x38000000 | (rt
<< OP_SH_RT
) | (rs
<< OP_SH_RS
)
319 void slt(RegisterID rd
, RegisterID rs
, RegisterID rt
)
321 emitInst(0x0000002a | (rd
<< OP_SH_RD
) | (rs
<< OP_SH_RS
)
325 void sltu(RegisterID rd
, RegisterID rs
, RegisterID rt
)
327 emitInst(0x0000002b | (rd
<< OP_SH_RD
) | (rs
<< OP_SH_RS
)
331 void sltiu(RegisterID rt
, RegisterID rs
, int imm
)
333 emitInst(0x2c000000 | (rt
<< OP_SH_RT
) | (rs
<< OP_SH_RS
)
337 void sll(RegisterID rd
, RegisterID rt
, int shamt
)
339 emitInst(0x00000000 | (rd
<< OP_SH_RD
) | (rt
<< OP_SH_RT
)
340 | ((shamt
& 0x1f) << OP_SH_SHAMT
));
343 void sllv(RegisterID rd
, RegisterID rt
, int rs
)
345 emitInst(0x00000004 | (rd
<< OP_SH_RD
) | (rt
<< OP_SH_RT
)
349 void sra(RegisterID rd
, RegisterID rt
, int shamt
)
351 emitInst(0x00000003 | (rd
<< OP_SH_RD
) | (rt
<< OP_SH_RT
)
352 | ((shamt
& 0x1f) << OP_SH_SHAMT
));
355 void srav(RegisterID rd
, RegisterID rt
, RegisterID rs
)
357 emitInst(0x00000007 | (rd
<< OP_SH_RD
) | (rt
<< OP_SH_RT
)
361 void srl(RegisterID rd
, RegisterID rt
, int shamt
)
363 emitInst(0x00000002 | (rd
<< OP_SH_RD
) | (rt
<< OP_SH_RT
)
364 | ((shamt
& 0x1f) << OP_SH_SHAMT
));
367 void srlv(RegisterID rd
, RegisterID rt
, RegisterID rs
)
369 emitInst(0x00000006 | (rd
<< OP_SH_RD
) | (rt
<< OP_SH_RT
)
373 void lbu(RegisterID rt
, RegisterID rs
, int offset
)
375 emitInst(0x90000000 | (rt
<< OP_SH_RT
) | (rs
<< OP_SH_RS
)
376 | (offset
& 0xffff));
380 void lw(RegisterID rt
, RegisterID rs
, int offset
)
382 emitInst(0x8c000000 | (rt
<< OP_SH_RT
) | (rs
<< OP_SH_RS
)
383 | (offset
& 0xffff));
387 void lwl(RegisterID rt
, RegisterID rs
, int offset
)
389 emitInst(0x88000000 | (rt
<< OP_SH_RT
) | (rs
<< OP_SH_RS
)
390 | (offset
& 0xffff));
394 void lwr(RegisterID rt
, RegisterID rs
, int offset
)
396 emitInst(0x98000000 | (rt
<< OP_SH_RT
) | (rs
<< OP_SH_RS
)
397 | (offset
& 0xffff));
401 void lhu(RegisterID rt
, RegisterID rs
, int offset
)
403 emitInst(0x94000000 | (rt
<< OP_SH_RT
) | (rs
<< OP_SH_RS
)
404 | (offset
& 0xffff));
408 void sw(RegisterID rt
, RegisterID rs
, int offset
)
410 emitInst(0xac000000 | (rt
<< OP_SH_RT
) | (rs
<< OP_SH_RS
)
411 | (offset
& 0xffff));
414 void jr(RegisterID rs
)
416 emitInst(0x00000008 | (rs
<< OP_SH_RS
));
419 void jalr(RegisterID rs
)
421 emitInst(0x0000f809 | (rs
<< OP_SH_RS
));
426 emitInst(0x0c000000);
431 int value
= 512; /* BRK_BUG */
432 emitInst(0x0000000d | ((value
& 0x3ff) << OP_SH_CODE
));
435 void bgez(RegisterID rs
, int imm
)
437 emitInst(0x04010000 | (rs
<< OP_SH_RS
) | (imm
& 0xffff));
440 void bltz(RegisterID rs
, int imm
)
442 emitInst(0x04000000 | (rs
<< OP_SH_RS
) | (imm
& 0xffff));
445 void beq(RegisterID rs
, RegisterID rt
, int imm
)
447 emitInst(0x10000000 | (rs
<< OP_SH_RS
) | (rt
<< OP_SH_RT
) | (imm
& 0xffff));
450 void bne(RegisterID rs
, RegisterID rt
, int imm
)
452 emitInst(0x14000000 | (rs
<< OP_SH_RS
) | (rt
<< OP_SH_RT
) | (imm
& 0xffff));
457 emitInst(0x45010000);
462 emitInst(0x45000000);
467 m_jumps
.append(m_buffer
.label());
470 void addd(FPRegisterID fd
, FPRegisterID fs
, FPRegisterID ft
)
472 emitInst(0x46200000 | (fd
<< OP_SH_FD
) | (fs
<< OP_SH_FS
)
476 void subd(FPRegisterID fd
, FPRegisterID fs
, FPRegisterID ft
)
478 emitInst(0x46200001 | (fd
<< OP_SH_FD
) | (fs
<< OP_SH_FS
)
482 void muld(FPRegisterID fd
, FPRegisterID fs
, FPRegisterID ft
)
484 emitInst(0x46200002 | (fd
<< OP_SH_FD
) | (fs
<< OP_SH_FS
)
488 void divd(FPRegisterID fd
, FPRegisterID fs
, FPRegisterID ft
)
490 emitInst(0x46200003 | (fd
<< OP_SH_FD
) | (fs
<< OP_SH_FS
)
494 void lwc1(FPRegisterID ft
, RegisterID rs
, int offset
)
496 emitInst(0xc4000000 | (ft
<< OP_SH_FT
) | (rs
<< OP_SH_RS
)
497 | (offset
& 0xffff));
501 void ldc1(FPRegisterID ft
, RegisterID rs
, int offset
)
503 emitInst(0xd4000000 | (ft
<< OP_SH_FT
) | (rs
<< OP_SH_RS
)
504 | (offset
& 0xffff));
507 void swc1(FPRegisterID ft
, RegisterID rs
, int offset
)
509 emitInst(0xe4000000 | (ft
<< OP_SH_FT
) | (rs
<< OP_SH_RS
)
510 | (offset
& 0xffff));
513 void sdc1(FPRegisterID ft
, RegisterID rs
, int offset
)
515 emitInst(0xf4000000 | (ft
<< OP_SH_FT
) | (rs
<< OP_SH_RS
)
516 | (offset
& 0xffff));
519 void mtc1(RegisterID rt
, FPRegisterID fs
)
521 emitInst(0x44800000 | (fs
<< OP_SH_FS
) | (rt
<< OP_SH_RT
));
525 void mthc1(RegisterID rt
, FPRegisterID fs
)
527 emitInst(0x44e00000 | (fs
<< OP_SH_FS
) | (rt
<< OP_SH_RT
));
531 void mfc1(RegisterID rt
, FPRegisterID fs
)
533 emitInst(0x44000000 | (fs
<< OP_SH_FS
) | (rt
<< OP_SH_RT
));
537 void sqrtd(FPRegisterID fd
, FPRegisterID fs
)
539 emitInst(0x46200004 | (fd
<< OP_SH_FD
) | (fs
<< OP_SH_FS
));
542 void truncwd(FPRegisterID fd
, FPRegisterID fs
)
544 emitInst(0x4620000d | (fd
<< OP_SH_FD
) | (fs
<< OP_SH_FS
));
547 void cvtdw(FPRegisterID fd
, FPRegisterID fs
)
549 emitInst(0x46800021 | (fd
<< OP_SH_FD
) | (fs
<< OP_SH_FS
));
552 void cvtwd(FPRegisterID fd
, FPRegisterID fs
)
554 emitInst(0x46200024 | (fd
<< OP_SH_FD
) | (fs
<< OP_SH_FS
));
557 void ceqd(FPRegisterID fs
, FPRegisterID ft
)
559 emitInst(0x46200032 | (fs
<< OP_SH_FS
) | (ft
<< OP_SH_FT
));
563 void cngtd(FPRegisterID fs
, FPRegisterID ft
)
565 emitInst(0x4620003f | (fs
<< OP_SH_FS
) | (ft
<< OP_SH_FT
));
569 void cnged(FPRegisterID fs
, FPRegisterID ft
)
571 emitInst(0x4620003d | (fs
<< OP_SH_FS
) | (ft
<< OP_SH_FT
));
575 void cltd(FPRegisterID fs
, FPRegisterID ft
)
577 emitInst(0x4620003c | (fs
<< OP_SH_FS
) | (ft
<< OP_SH_FT
));
581 void cled(FPRegisterID fs
, FPRegisterID ft
)
583 emitInst(0x4620003e | (fs
<< OP_SH_FS
) | (ft
<< OP_SH_FT
));
587 void cueqd(FPRegisterID fs
, FPRegisterID ft
)
589 emitInst(0x46200033 | (fs
<< OP_SH_FS
) | (ft
<< OP_SH_FT
));
593 void coled(FPRegisterID fs
, FPRegisterID ft
)
595 emitInst(0x46200036 | (fs
<< OP_SH_FS
) | (ft
<< OP_SH_FT
));
599 void coltd(FPRegisterID fs
, FPRegisterID ft
)
601 emitInst(0x46200034 | (fs
<< OP_SH_FS
) | (ft
<< OP_SH_FT
));
605 void culed(FPRegisterID fs
, FPRegisterID ft
)
607 emitInst(0x46200037 | (fs
<< OP_SH_FS
) | (ft
<< OP_SH_FT
));
611 void cultd(FPRegisterID fs
, FPRegisterID ft
)
613 emitInst(0x46200035 | (fs
<< OP_SH_FS
) | (ft
<< OP_SH_FT
));
619 AssemblerLabel
label()
621 return m_buffer
.label();
624 AssemblerLabel
align(int alignment
)
626 while (!m_buffer
.isAligned(alignment
))
632 static void* getRelocatedAddress(void* code
, AssemblerLabel label
)
634 return reinterpret_cast<void*>(reinterpret_cast<char*>(code
) + label
.m_offset
);
637 static int getDifferenceBetweenLabels(AssemblerLabel a
, AssemblerLabel b
)
639 return b
.m_offset
- a
.m_offset
;
642 // Assembler admin methods:
644 size_t codeSize() const
646 return m_buffer
.codeSize();
649 PassRefPtr
<ExecutableMemoryHandle
> executableCopy(JSGlobalData
& globalData
, void* ownerUID
, JITCompilationEffort effort
)
651 RefPtr
<ExecutableMemoryHandle
> result
= m_buffer
.executableCopy(globalData
, ownerUID
, effort
);
655 relocateJumps(m_buffer
.data(), result
->start());
656 return result
.release();
659 unsigned debugOffset() { return m_buffer
.debugOffset(); }
661 static unsigned getCallReturnOffset(AssemblerLabel call
)
663 // The return address is after a call and a delay slot instruction
664 return call
.m_offset
;
667 // Linking & patching:
669 // 'link' and 'patch' methods are for use on unprotected code - such as the code
670 // within the AssemblerBuffer, and code being patched by the patch buffer. Once
671 // code has been finalized it is (platform support permitting) within a non-
672 // writable region of memory; to modify the code in an execute-only execuable
673 // pool the 'repatch' and 'relink' methods should be used.
675 void linkJump(AssemblerLabel from
, AssemblerLabel to
)
678 ASSERT(from
.isSet());
679 MIPSWord
* insn
= reinterpret_cast<MIPSWord
*>(reinterpret_cast<intptr_t>(m_buffer
.data()) + from
.m_offset
);
680 MIPSWord
* toPos
= reinterpret_cast<MIPSWord
*>(reinterpret_cast<intptr_t>(m_buffer
.data()) + to
.m_offset
);
682 ASSERT(!(*(insn
- 1)) && !(*(insn
- 2)) && !(*(insn
- 3)) && !(*(insn
- 5)));
684 linkWithOffset(insn
, toPos
);
687 static void linkJump(void* code
, AssemblerLabel from
, void* to
)
689 ASSERT(from
.isSet());
690 MIPSWord
* insn
= reinterpret_cast<MIPSWord
*>(reinterpret_cast<intptr_t>(code
) + from
.m_offset
);
692 ASSERT(!(*(insn
- 1)) && !(*(insn
- 2)) && !(*(insn
- 3)) && !(*(insn
- 5)));
694 linkWithOffset(insn
, to
);
697 static void linkCall(void* code
, AssemblerLabel from
, void* to
)
699 MIPSWord
* insn
= reinterpret_cast<MIPSWord
*>(reinterpret_cast<intptr_t>(code
) + from
.m_offset
);
700 linkCallInternal(insn
, to
);
703 static void linkPointer(void* code
, AssemblerLabel from
, void* to
)
705 MIPSWord
* insn
= reinterpret_cast<MIPSWord
*>(reinterpret_cast<intptr_t>(code
) + from
.m_offset
);
706 ASSERT((*insn
& 0xffe00000) == 0x3c000000); // lui
707 *insn
= (*insn
& 0xffff0000) | ((reinterpret_cast<intptr_t>(to
) >> 16) & 0xffff);
709 ASSERT((*insn
& 0xfc000000) == 0x34000000); // ori
710 *insn
= (*insn
& 0xffff0000) | (reinterpret_cast<intptr_t>(to
) & 0xffff);
713 static void relinkJump(void* from
, void* to
)
715 MIPSWord
* insn
= reinterpret_cast<MIPSWord
*>(from
);
717 ASSERT(!(*(insn
- 1)) && !(*(insn
- 5)));
719 int flushSize
= linkWithOffset(insn
, to
);
721 cacheFlush(insn
, flushSize
);
724 static void relinkCall(void* from
, void* to
)
727 int size
= linkCallInternal(from
, to
);
728 if (size
== sizeof(MIPSWord
))
729 start
= reinterpret_cast<void*>(reinterpret_cast<intptr_t>(from
) - 2 * sizeof(MIPSWord
));
731 start
= reinterpret_cast<void*>(reinterpret_cast<intptr_t>(from
) - 4 * sizeof(MIPSWord
));
733 cacheFlush(start
, size
);
736 static void repatchInt32(void* from
, int32_t to
)
738 MIPSWord
* insn
= reinterpret_cast<MIPSWord
*>(from
);
739 ASSERT((*insn
& 0xffe00000) == 0x3c000000); // lui
740 *insn
= (*insn
& 0xffff0000) | ((to
>> 16) & 0xffff);
742 ASSERT((*insn
& 0xfc000000) == 0x34000000); // ori
743 *insn
= (*insn
& 0xffff0000) | (to
& 0xffff);
745 cacheFlush(insn
, 2 * sizeof(MIPSWord
));
748 static int32_t readInt32(void* from
)
750 MIPSWord
* insn
= reinterpret_cast<MIPSWord
*>(from
);
751 ASSERT((*insn
& 0xffe00000) == 0x3c000000); // lui
752 int32_t result
= (*insn
& 0x0000ffff) << 16;
754 ASSERT((*insn
& 0xfc000000) == 0x34000000); // ori
755 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 reinterpret_cast<void*>(readInt32(from
));
774 static void* readCallTarget(void* from
)
776 MIPSWord
* insn
= reinterpret_cast<MIPSWord
*>(from
);
778 ASSERT((*insn
& 0xffe00000) == 0x3c000000); // lui
779 int32_t result
= (*insn
& 0x0000ffff) << 16;
781 ASSERT((*insn
& 0xfc000000) == 0x34000000); // ori
782 result
|= *insn
& 0x0000ffff;
783 return reinterpret_cast<void*>(result
);
786 static void cacheFlush(void* code
, size_t size
)
788 #if GCC_VERSION_AT_LEAST(4, 3, 0)
789 #if WTF_MIPS_ISA_REV(2) && !GCC_VERSION_AT_LEAST(4, 4, 3)
791 asm("rdhwr %0, $1" : "=r" (lineSize
));
793 // Modify "start" and "end" to avoid GCC 4.3.0-4.4.2 bug in
794 // mips_expand_synci_loop that may execute synci one more time.
795 // "start" points to the fisrt byte of the cache line.
796 // "end" points to the last byte of the line before the last cache line.
797 // Because size is always a multiple of 4, this is safe to set
798 // "end" to the last byte.
800 intptr_t start
= reinterpret_cast<intptr_t>(code
) & (-lineSize
);
801 intptr_t end
= ((reinterpret_cast<intptr_t>(code
) + size
- 1) & (-lineSize
)) - 1;
802 __builtin___clear_cache(reinterpret_cast<char*>(start
), reinterpret_cast<char*>(end
));
804 intptr_t end
= reinterpret_cast<intptr_t>(code
) + size
;
805 __builtin___clear_cache(reinterpret_cast<char*>(code
), reinterpret_cast<char*>(end
));
808 _flush_cache(reinterpret_cast<char*>(code
), size
, BCACHE
);
813 /* Update each jump in the buffer of newBase. */
814 void relocateJumps(void* oldBase
, void* newBase
)
817 for (Jumps::Iterator iter
= m_jumps
.begin(); iter
!= m_jumps
.end(); ++iter
) {
818 int pos
= iter
->m_offset
;
819 MIPSWord
* insn
= reinterpret_cast<MIPSWord
*>(reinterpret_cast<intptr_t>(newBase
) + pos
);
821 // Need to make sure we have 5 valid instructions after pos
822 if ((unsigned int)pos
>= m_buffer
.codeSize() - 5 * sizeof(MIPSWord
))
825 if ((*insn
& 0xfc000000) == 0x08000000) { // j
826 int offset
= *insn
& 0x03ffffff;
827 int oldInsnAddress
= (int)insn
- (int)newBase
+ (int)oldBase
;
828 int topFourBits
= (oldInsnAddress
+ 4) >> 28;
829 int oldTargetAddress
= (topFourBits
<< 28) | (offset
<< 2);
830 int newTargetAddress
= oldTargetAddress
- (int)oldBase
+ (int)newBase
;
831 int newInsnAddress
= (int)insn
;
832 if (((newInsnAddress
+ 4) >> 28) == (newTargetAddress
>> 28))
833 *insn
= 0x08000000 | ((newTargetAddress
>> 2) & 0x3ffffff);
836 *insn
= 0x3c000000 | (MIPSRegisters::t9
<< OP_SH_RT
) | ((newTargetAddress
>> 16) & 0xffff);
838 *(insn
+ 1) = 0x34000000 | (MIPSRegisters::t9
<< OP_SH_RT
) | (MIPSRegisters::t9
<< OP_SH_RS
) | (newTargetAddress
& 0xffff);
840 *(insn
+ 2) = 0x00000008 | (MIPSRegisters::t9
<< OP_SH_RS
);
842 } else if ((*insn
& 0xffe00000) == 0x3c000000) { // lui
843 int high
= (*insn
& 0xffff) << 16;
844 int low
= *(insn
+ 1) & 0xffff;
845 int oldTargetAddress
= high
| low
;
846 int newTargetAddress
= oldTargetAddress
- (int)oldBase
+ (int)newBase
;
848 *insn
= 0x3c000000 | (MIPSRegisters::t9
<< OP_SH_RT
) | ((newTargetAddress
>> 16) & 0xffff);
850 *(insn
+ 1) = 0x34000000 | (MIPSRegisters::t9
<< OP_SH_RT
) | (MIPSRegisters::t9
<< OP_SH_RS
) | (newTargetAddress
& 0xffff);
855 static int linkWithOffset(MIPSWord
* insn
, void* to
)
857 ASSERT((*insn
& 0xfc000000) == 0x10000000 // beq
858 || (*insn
& 0xfc000000) == 0x14000000 // bne
859 || (*insn
& 0xffff0000) == 0x45010000 // bc1t
860 || (*insn
& 0xffff0000) == 0x45000000); // bc1f
861 intptr_t diff
= (reinterpret_cast<intptr_t>(to
)
862 - reinterpret_cast<intptr_t>(insn
) - 4) >> 2;
864 if (diff
< -32768 || diff
> 32767 || *(insn
+ 2) != 0x10000003) {
866 Convert the sequence:
875 to the new sequence if possible:
884 OR to the new sequence:
887 lui $25, target >> 16
888 ori $25, $25, target & 0xffff
893 Note: beq/bne/bc1t/bc1f are converted to bne/beq/bc1f/bc1t.
896 if (*(insn
+ 2) == 0x10000003) {
897 if ((*insn
& 0xfc000000) == 0x10000000) // beq
898 *insn
= (*insn
& 0x03ff0000) | 0x14000005; // bne
899 else if ((*insn
& 0xfc000000) == 0x14000000) // bne
900 *insn
= (*insn
& 0x03ff0000) | 0x10000005; // beq
901 else if ((*insn
& 0xffff0000) == 0x45010000) // bc1t
902 *insn
= 0x45000005; // bc1f
903 else if ((*insn
& 0xffff0000) == 0x45000000) // bc1f
904 *insn
= 0x45010005; // bc1t
910 if ((reinterpret_cast<intptr_t>(insn
) + 4) >> 28
911 == reinterpret_cast<intptr_t>(to
) >> 28) {
912 *insn
= 0x08000000 | ((reinterpret_cast<intptr_t>(to
) >> 2) & 0x3ffffff);
914 return 4 * sizeof(MIPSWord
);
917 intptr_t newTargetAddress
= reinterpret_cast<intptr_t>(to
);
919 *insn
= 0x3c000000 | (MIPSRegisters::t9
<< OP_SH_RT
) | ((newTargetAddress
>> 16) & 0xffff);
921 *(insn
+ 1) = 0x34000000 | (MIPSRegisters::t9
<< OP_SH_RT
) | (MIPSRegisters::t9
<< OP_SH_RS
) | (newTargetAddress
& 0xffff);
923 *(insn
+ 2) = 0x00000008 | (MIPSRegisters::t9
<< OP_SH_RS
);
924 return 5 * sizeof(MIPSWord
);
927 *insn
= (*insn
& 0xffff0000) | (diff
& 0xffff);
928 return sizeof(MIPSWord
);
931 static int linkCallInternal(void* from
, void* to
)
933 MIPSWord
* insn
= reinterpret_cast<MIPSWord
*>(from
);
936 if ((*(insn
+ 2) & 0xfc000000) == 0x0c000000) { // jal
937 if ((reinterpret_cast<intptr_t>(from
) - 4) >> 28
938 == reinterpret_cast<intptr_t>(to
) >> 28) {
939 *(insn
+ 2) = 0x0c000000 | ((reinterpret_cast<intptr_t>(to
) >> 2) & 0x3ffffff);
940 return sizeof(MIPSWord
);
943 /* lui $25, (to >> 16) & 0xffff */
944 *insn
= 0x3c000000 | (MIPSRegisters::t9
<< OP_SH_RT
) | ((reinterpret_cast<intptr_t>(to
) >> 16) & 0xffff);
945 /* ori $25, $25, to & 0xffff */
946 *(insn
+ 1) = 0x34000000 | (MIPSRegisters::t9
<< OP_SH_RT
) | (MIPSRegisters::t9
<< OP_SH_RS
) | (reinterpret_cast<intptr_t>(to
) & 0xffff);
948 *(insn
+ 2) = 0x0000f809 | (MIPSRegisters::t9
<< OP_SH_RS
);
949 return 3 * sizeof(MIPSWord
);
952 ASSERT((*insn
& 0xffe00000) == 0x3c000000); // lui
953 ASSERT((*(insn
+ 1) & 0xfc000000) == 0x34000000); // ori
956 *insn
= (*insn
& 0xffff0000) | ((reinterpret_cast<intptr_t>(to
) >> 16) & 0xffff);
958 *(insn
+ 1) = (*(insn
+ 1) & 0xffff0000) | (reinterpret_cast<intptr_t>(to
) & 0xffff);
959 return 2 * sizeof(MIPSWord
);
962 AssemblerBuffer m_buffer
;
968 #endif // ENABLE(ASSEMBLER) && CPU(MIPS)
970 #endif // MIPSAssembler_h