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 PassRefPtr<ExecutableMemoryHandle> executableCopy(JSGlobalData& globalData)
650 RefPtr<ExecutableMemoryHandle> result = m_buffer.executableCopy(globalData);
654 relocateJumps(m_buffer.data(), result->start());
655 return result.release();
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;
760 static void repatchCompact(void* where, int32_t value)
762 repatchInt32(where, value);
765 static void repatchPointer(void* from, void* to)
767 repatchInt32(from, reinterpret_cast<int32_t>(to));
770 static void* readPointer(void* from)
772 return reinterpret_cast<void*>(readInt32(from));
776 /* Update each jump in the buffer of newBase. */
777 void relocateJumps(void* oldBase, void* newBase)
780 for (Jumps::Iterator iter = m_jumps.begin(); iter != m_jumps.end(); ++iter) {
781 int pos = iter->m_offset;
782 MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(newBase) + pos);
784 // Need to make sure we have 5 valid instructions after pos
785 if ((unsigned int)pos >= m_buffer.codeSize() - 5 * sizeof(MIPSWord))
788 if ((*insn & 0xfc000000) == 0x08000000) { // j
789 int offset = *insn & 0x03ffffff;
790 int oldInsnAddress = (int)insn - (int)newBase + (int)oldBase;
791 int topFourBits = (oldInsnAddress + 4) >> 28;
792 int oldTargetAddress = (topFourBits << 28) | (offset << 2);
793 int newTargetAddress = oldTargetAddress - (int)oldBase + (int)newBase;
794 int newInsnAddress = (int)insn;
795 if (((newInsnAddress + 4) >> 28) == (newTargetAddress >> 28))
796 *insn = 0x08000000 | ((newTargetAddress >> 2) & 0x3ffffff);
799 *insn = 0x3c000000 | (MIPSRegisters::t9 << OP_SH_RT) | ((newTargetAddress >> 16) & 0xffff);
801 *(insn + 1) = 0x34000000 | (MIPSRegisters::t9 << OP_SH_RT) | (MIPSRegisters::t9 << OP_SH_RS) | (newTargetAddress & 0xffff);
803 *(insn + 2) = 0x00000008 | (MIPSRegisters::t9 << OP_SH_RS);
805 } else if ((*insn & 0xffe00000) == 0x3c000000) { // lui
806 int high = (*insn & 0xffff) << 16;
807 int low = *(insn + 1) & 0xffff;
808 int oldTargetAddress = high | low;
809 int newTargetAddress = oldTargetAddress - (int)oldBase + (int)newBase;
811 *insn = 0x3c000000 | (MIPSRegisters::t9 << OP_SH_RT) | ((newTargetAddress >> 16) & 0xffff);
813 *(insn + 1) = 0x34000000 | (MIPSRegisters::t9 << OP_SH_RT) | (MIPSRegisters::t9 << OP_SH_RS) | (newTargetAddress & 0xffff);
818 static int linkWithOffset(MIPSWord* insn, void* to)
820 ASSERT((*insn & 0xfc000000) == 0x10000000 // beq
821 || (*insn & 0xfc000000) == 0x14000000 // bne
822 || (*insn & 0xffff0000) == 0x45010000 // bc1t
823 || (*insn & 0xffff0000) == 0x45000000); // bc1f
824 intptr_t diff = (reinterpret_cast<intptr_t>(to)
825 - reinterpret_cast<intptr_t>(insn) - 4) >> 2;
827 if (diff < -32768 || diff > 32767 || *(insn + 2) != 0x10000003) {
829 Convert the sequence:
838 to the new sequence if possible:
847 OR to the new sequence:
850 lui $25, target >> 16
851 ori $25, $25, target & 0xffff
856 Note: beq/bne/bc1t/bc1f are converted to bne/beq/bc1f/bc1t.
859 if (*(insn + 2) == 0x10000003) {
860 if ((*insn & 0xfc000000) == 0x10000000) // beq
861 *insn = (*insn & 0x03ff0000) | 0x14000005; // bne
862 else if ((*insn & 0xfc000000) == 0x14000000) // bne
863 *insn = (*insn & 0x03ff0000) | 0x10000005; // beq
864 else if ((*insn & 0xffff0000) == 0x45010000) // bc1t
865 *insn = 0x45000005; // bc1f
866 else if ((*insn & 0xffff0000) == 0x45000000) // bc1f
867 *insn = 0x45010005; // bc1t
873 if ((reinterpret_cast<intptr_t>(insn) + 4) >> 28
874 == reinterpret_cast<intptr_t>(to) >> 28) {
875 *insn = 0x08000000 | ((reinterpret_cast<intptr_t>(to) >> 2) & 0x3ffffff);
877 return 4 * sizeof(MIPSWord);
880 intptr_t newTargetAddress = reinterpret_cast<intptr_t>(to);
882 *insn = 0x3c000000 | (MIPSRegisters::t9 << OP_SH_RT) | ((newTargetAddress >> 16) & 0xffff);
884 *(insn + 1) = 0x34000000 | (MIPSRegisters::t9 << OP_SH_RT) | (MIPSRegisters::t9 << OP_SH_RS) | (newTargetAddress & 0xffff);
886 *(insn + 2) = 0x00000008 | (MIPSRegisters::t9 << OP_SH_RS);
887 return 5 * sizeof(MIPSWord);
890 *insn = (*insn & 0xffff0000) | (diff & 0xffff);
891 return sizeof(MIPSWord);
894 static int linkCallInternal(void* from, void* to)
896 MIPSWord* insn = reinterpret_cast<MIPSWord*>(from);
899 if ((*(insn + 2) & 0xfc000000) == 0x0c000000) { // jal
900 if ((reinterpret_cast<intptr_t>(from) - 4) >> 28
901 == reinterpret_cast<intptr_t>(to) >> 28) {
902 *(insn + 2) = 0x0c000000 | ((reinterpret_cast<intptr_t>(to) >> 2) & 0x3ffffff);
903 return sizeof(MIPSWord);
906 /* lui $25, (to >> 16) & 0xffff */
907 *insn = 0x3c000000 | (MIPSRegisters::t9 << OP_SH_RT) | ((reinterpret_cast<intptr_t>(to) >> 16) & 0xffff);
908 /* ori $25, $25, to & 0xffff */
909 *(insn + 1) = 0x34000000 | (MIPSRegisters::t9 << OP_SH_RT) | (MIPSRegisters::t9 << OP_SH_RS) | (reinterpret_cast<intptr_t>(to) & 0xffff);
911 *(insn + 2) = 0x0000f809 | (MIPSRegisters::t9 << OP_SH_RS);
912 return 3 * sizeof(MIPSWord);
915 ASSERT((*insn & 0xffe00000) == 0x3c000000); // lui
916 ASSERT((*(insn + 1) & 0xfc000000) == 0x34000000); // ori
919 *insn = (*insn & 0xffff0000) | ((reinterpret_cast<intptr_t>(to) >> 16) & 0xffff);
921 *(insn + 1) = (*(insn + 1) & 0xffff0000) | (reinterpret_cast<intptr_t>(to) & 0xffff);
922 return 2 * sizeof(MIPSWord);
925 AssemblerBuffer m_buffer;
931 #endif // ENABLE(ASSEMBLER) && CPU(MIPS)
933 #endif // MIPSAssembler_h