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 labelIgnoringWatchpoints()
621 return m_buffer.label();
624 AssemblerLabel label()
626 return m_buffer.label();
629 AssemblerLabel align(int alignment)
631 while (!m_buffer.isAligned(alignment))
637 static void* getRelocatedAddress(void* code, AssemblerLabel label)
639 return reinterpret_cast<void*>(reinterpret_cast<char*>(code) + label.m_offset);
642 static int getDifferenceBetweenLabels(AssemblerLabel a, AssemblerLabel b)
644 return b.m_offset - a.m_offset;
647 // Assembler admin methods:
649 size_t codeSize() const
651 return m_buffer.codeSize();
654 PassRefPtr<ExecutableMemoryHandle> executableCopy(JSGlobalData& globalData, void* ownerUID, JITCompilationEffort effort)
656 RefPtr<ExecutableMemoryHandle> result = m_buffer.executableCopy(globalData, ownerUID, effort);
660 relocateJumps(m_buffer.data(), result->start());
661 return result.release();
664 unsigned debugOffset() { return m_buffer.debugOffset(); }
666 static unsigned getCallReturnOffset(AssemblerLabel call)
668 // The return address is after a call and a delay slot instruction
669 return call.m_offset;
672 // Linking & patching:
674 // 'link' and 'patch' methods are for use on unprotected code - such as the code
675 // within the AssemblerBuffer, and code being patched by the patch buffer. Once
676 // code has been finalized it is (platform support permitting) within a non-
677 // writable region of memory; to modify the code in an execute-only execuable
678 // pool the 'repatch' and 'relink' methods should be used.
680 void linkJump(AssemblerLabel from, AssemblerLabel to)
683 ASSERT(from.isSet());
684 MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(m_buffer.data()) + from.m_offset);
685 MIPSWord* toPos = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(m_buffer.data()) + to.m_offset);
687 ASSERT(!(*(insn - 1)) && !(*(insn - 2)) && !(*(insn - 3)) && !(*(insn - 5)));
689 linkWithOffset(insn, toPos);
692 static void linkJump(void* code, AssemblerLabel from, void* to)
694 ASSERT(from.isSet());
695 MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(code) + from.m_offset);
697 ASSERT(!(*(insn - 1)) && !(*(insn - 2)) && !(*(insn - 3)) && !(*(insn - 5)));
699 linkWithOffset(insn, to);
702 static void linkCall(void* code, AssemblerLabel from, void* to)
704 MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(code) + from.m_offset);
705 linkCallInternal(insn, to);
708 static void linkPointer(void* code, AssemblerLabel from, void* to)
710 MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(code) + from.m_offset);
711 ASSERT((*insn & 0xffe00000) == 0x3c000000); // lui
712 *insn = (*insn & 0xffff0000) | ((reinterpret_cast<intptr_t>(to) >> 16) & 0xffff);
714 ASSERT((*insn & 0xfc000000) == 0x34000000); // ori
715 *insn = (*insn & 0xffff0000) | (reinterpret_cast<intptr_t>(to) & 0xffff);
718 static void relinkJump(void* from, void* to)
720 MIPSWord* insn = reinterpret_cast<MIPSWord*>(from);
722 ASSERT(!(*(insn - 1)) && !(*(insn - 5)));
724 int flushSize = linkWithOffset(insn, to);
726 cacheFlush(insn, flushSize);
729 static void relinkCall(void* from, void* to)
732 int size = linkCallInternal(from, to);
733 if (size == sizeof(MIPSWord))
734 start = reinterpret_cast<void*>(reinterpret_cast<intptr_t>(from) - 2 * sizeof(MIPSWord));
736 start = reinterpret_cast<void*>(reinterpret_cast<intptr_t>(from) - 4 * sizeof(MIPSWord));
738 cacheFlush(start, size);
741 static void repatchInt32(void* from, int32_t to)
743 MIPSWord* insn = reinterpret_cast<MIPSWord*>(from);
744 ASSERT((*insn & 0xffe00000) == 0x3c000000); // lui
745 *insn = (*insn & 0xffff0000) | ((to >> 16) & 0xffff);
747 ASSERT((*insn & 0xfc000000) == 0x34000000); // ori
748 *insn = (*insn & 0xffff0000) | (to & 0xffff);
750 cacheFlush(insn, 2 * sizeof(MIPSWord));
753 static int32_t readInt32(void* from)
755 MIPSWord* insn = reinterpret_cast<MIPSWord*>(from);
756 ASSERT((*insn & 0xffe00000) == 0x3c000000); // lui
757 int32_t result = (*insn & 0x0000ffff) << 16;
759 ASSERT((*insn & 0xfc000000) == 0x34000000); // ori
760 result |= *insn & 0x0000ffff;
764 static void repatchCompact(void* where, int32_t value)
766 repatchInt32(where, value);
769 static void repatchPointer(void* from, void* to)
771 repatchInt32(from, reinterpret_cast<int32_t>(to));
774 static void* readPointer(void* from)
776 return reinterpret_cast<void*>(readInt32(from));
779 static void* readCallTarget(void* from)
781 MIPSWord* insn = reinterpret_cast<MIPSWord*>(from);
783 ASSERT((*insn & 0xffe00000) == 0x3c000000); // lui
784 int32_t result = (*insn & 0x0000ffff) << 16;
786 ASSERT((*insn & 0xfc000000) == 0x34000000); // ori
787 result |= *insn & 0x0000ffff;
788 return reinterpret_cast<void*>(result);
791 static void cacheFlush(void* code, size_t size)
793 #if GCC_VERSION_AT_LEAST(4, 3, 0)
794 #if WTF_MIPS_ISA_REV(2) && !GCC_VERSION_AT_LEAST(4, 4, 3)
796 asm("rdhwr %0, $1" : "=r" (lineSize));
798 // Modify "start" and "end" to avoid GCC 4.3.0-4.4.2 bug in
799 // mips_expand_synci_loop that may execute synci one more time.
800 // "start" points to the fisrt byte of the cache line.
801 // "end" points to the last byte of the line before the last cache line.
802 // Because size is always a multiple of 4, this is safe to set
803 // "end" to the last byte.
805 intptr_t start = reinterpret_cast<intptr_t>(code) & (-lineSize);
806 intptr_t end = ((reinterpret_cast<intptr_t>(code) + size - 1) & (-lineSize)) - 1;
807 __builtin___clear_cache(reinterpret_cast<char*>(start), reinterpret_cast<char*>(end));
809 intptr_t end = reinterpret_cast<intptr_t>(code) + size;
810 __builtin___clear_cache(reinterpret_cast<char*>(code), reinterpret_cast<char*>(end));
813 _flush_cache(reinterpret_cast<char*>(code), size, BCACHE);
817 static void replaceWithLoad(void* instructionStart)
819 MIPSWord* insn = reinterpret_cast<MIPSWord*>(instructionStart);
820 ASSERT((*insn & 0xffe00000) == 0x3c000000); // lui
822 ASSERT((*insn & 0xfc0007ff) == 0x00000021); // addu
824 *insn = 0x8c000000 | ((*insn) & 0x3ffffff); // lw
828 static void replaceWithAddressComputation(void* instructionStart)
830 MIPSWord* insn = reinterpret_cast<MIPSWord*>(instructionStart);
831 ASSERT((*insn & 0xffe00000) == 0x3c000000); // lui
833 ASSERT((*insn & 0xfc0007ff) == 0x00000021); // addu
835 *insn = 0x24000000 | ((*insn) & 0x3ffffff); // addiu
840 /* Update each jump in the buffer of newBase. */
841 void relocateJumps(void* oldBase, void* newBase)
844 for (Jumps::Iterator iter = m_jumps.begin(); iter != m_jumps.end(); ++iter) {
845 int pos = iter->m_offset;
846 MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(newBase) + pos);
848 // Need to make sure we have 5 valid instructions after pos
849 if ((unsigned int)pos >= m_buffer.codeSize() - 5 * sizeof(MIPSWord))
852 if ((*insn & 0xfc000000) == 0x08000000) { // j
853 int offset = *insn & 0x03ffffff;
854 int oldInsnAddress = (int)insn - (int)newBase + (int)oldBase;
855 int topFourBits = (oldInsnAddress + 4) >> 28;
856 int oldTargetAddress = (topFourBits << 28) | (offset << 2);
857 int newTargetAddress = oldTargetAddress - (int)oldBase + (int)newBase;
858 int newInsnAddress = (int)insn;
859 if (((newInsnAddress + 4) >> 28) == (newTargetAddress >> 28))
860 *insn = 0x08000000 | ((newTargetAddress >> 2) & 0x3ffffff);
863 *insn = 0x3c000000 | (MIPSRegisters::t9 << OP_SH_RT) | ((newTargetAddress >> 16) & 0xffff);
865 *(insn + 1) = 0x34000000 | (MIPSRegisters::t9 << OP_SH_RT) | (MIPSRegisters::t9 << OP_SH_RS) | (newTargetAddress & 0xffff);
867 *(insn + 2) = 0x00000008 | (MIPSRegisters::t9 << OP_SH_RS);
869 } else if ((*insn & 0xffe00000) == 0x3c000000) { // lui
870 int high = (*insn & 0xffff) << 16;
871 int low = *(insn + 1) & 0xffff;
872 int oldTargetAddress = high | low;
873 int newTargetAddress = oldTargetAddress - (int)oldBase + (int)newBase;
875 *insn = 0x3c000000 | (MIPSRegisters::t9 << OP_SH_RT) | ((newTargetAddress >> 16) & 0xffff);
877 *(insn + 1) = 0x34000000 | (MIPSRegisters::t9 << OP_SH_RT) | (MIPSRegisters::t9 << OP_SH_RS) | (newTargetAddress & 0xffff);
882 static int linkWithOffset(MIPSWord* insn, void* to)
884 ASSERT((*insn & 0xfc000000) == 0x10000000 // beq
885 || (*insn & 0xfc000000) == 0x14000000 // bne
886 || (*insn & 0xffff0000) == 0x45010000 // bc1t
887 || (*insn & 0xffff0000) == 0x45000000); // bc1f
888 intptr_t diff = (reinterpret_cast<intptr_t>(to)
889 - reinterpret_cast<intptr_t>(insn) - 4) >> 2;
891 if (diff < -32768 || diff > 32767 || *(insn + 2) != 0x10000003) {
893 Convert the sequence:
902 to the new sequence if possible:
911 OR to the new sequence:
914 lui $25, target >> 16
915 ori $25, $25, target & 0xffff
920 Note: beq/bne/bc1t/bc1f are converted to bne/beq/bc1f/bc1t.
923 if (*(insn + 2) == 0x10000003) {
924 if ((*insn & 0xfc000000) == 0x10000000) // beq
925 *insn = (*insn & 0x03ff0000) | 0x14000005; // bne
926 else if ((*insn & 0xfc000000) == 0x14000000) // bne
927 *insn = (*insn & 0x03ff0000) | 0x10000005; // beq
928 else if ((*insn & 0xffff0000) == 0x45010000) // bc1t
929 *insn = 0x45000005; // bc1f
930 else if ((*insn & 0xffff0000) == 0x45000000) // bc1f
931 *insn = 0x45010005; // bc1t
937 if ((reinterpret_cast<intptr_t>(insn) + 4) >> 28
938 == reinterpret_cast<intptr_t>(to) >> 28) {
939 *insn = 0x08000000 | ((reinterpret_cast<intptr_t>(to) >> 2) & 0x3ffffff);
941 return 4 * sizeof(MIPSWord);
944 intptr_t newTargetAddress = reinterpret_cast<intptr_t>(to);
946 *insn = 0x3c000000 | (MIPSRegisters::t9 << OP_SH_RT) | ((newTargetAddress >> 16) & 0xffff);
948 *(insn + 1) = 0x34000000 | (MIPSRegisters::t9 << OP_SH_RT) | (MIPSRegisters::t9 << OP_SH_RS) | (newTargetAddress & 0xffff);
950 *(insn + 2) = 0x00000008 | (MIPSRegisters::t9 << OP_SH_RS);
951 return 5 * sizeof(MIPSWord);
954 *insn = (*insn & 0xffff0000) | (diff & 0xffff);
955 return sizeof(MIPSWord);
958 static int linkCallInternal(void* from, void* to)
960 MIPSWord* insn = reinterpret_cast<MIPSWord*>(from);
963 if ((*(insn + 2) & 0xfc000000) == 0x0c000000) { // jal
964 if ((reinterpret_cast<intptr_t>(from) - 4) >> 28
965 == reinterpret_cast<intptr_t>(to) >> 28) {
966 *(insn + 2) = 0x0c000000 | ((reinterpret_cast<intptr_t>(to) >> 2) & 0x3ffffff);
967 return sizeof(MIPSWord);
970 /* lui $25, (to >> 16) & 0xffff */
971 *insn = 0x3c000000 | (MIPSRegisters::t9 << OP_SH_RT) | ((reinterpret_cast<intptr_t>(to) >> 16) & 0xffff);
972 /* ori $25, $25, to & 0xffff */
973 *(insn + 1) = 0x34000000 | (MIPSRegisters::t9 << OP_SH_RT) | (MIPSRegisters::t9 << OP_SH_RS) | (reinterpret_cast<intptr_t>(to) & 0xffff);
975 *(insn + 2) = 0x0000f809 | (MIPSRegisters::t9 << OP_SH_RS);
976 return 3 * sizeof(MIPSWord);
979 ASSERT((*insn & 0xffe00000) == 0x3c000000); // lui
980 ASSERT((*(insn + 1) & 0xfc000000) == 0x34000000); // ori
983 *insn = (*insn & 0xffff0000) | ((reinterpret_cast<intptr_t>(to) >> 16) & 0xffff);
985 *(insn + 1) = (*(insn + 1) & 0xffff0000) | (reinterpret_cast<intptr_t>(to) & 0xffff);
986 return 2 * sizeof(MIPSWord);
989 AssemblerBuffer m_buffer;
995 #endif // ENABLE(ASSEMBLER) && CPU(MIPS)
997 #endif // MIPSAssembler_h