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
;
154 static RegisterID
firstRegister() { return MIPSRegisters::r0
; }
155 static RegisterID
lastRegister() { return MIPSRegisters::r31
; }
157 static FPRegisterID
firstFPRegister() { return MIPSRegisters::f0
; }
158 static FPRegisterID
lastFPRegister() { return MIPSRegisters::f31
; }
161 : m_indexOfLastWatchpoint(INT_MIN
)
162 , m_indexOfTailOfLastWatchpoint(INT_MIN
)
166 AssemblerBuffer
& buffer() { return m_buffer
; }
168 // MIPS instruction opcode field position
180 void emitInst(MIPSWord op
)
182 void* oldBase
= m_buffer
.data();
186 void* newBase
= m_buffer
.data();
187 if (oldBase
!= newBase
)
188 relocateJumps(oldBase
, newBase
);
193 emitInst(0x00000000);
198 emitInst(0x0000000f);
201 /* Need to insert one load data delay nop for mips1. */
209 /* Need to insert one coprocessor access delay nop for mips1. */
217 void move(RegisterID rd
, RegisterID rs
)
220 emitInst(0x00000021 | (rd
<< OP_SH_RD
) | (rs
<< OP_SH_RS
));
223 /* Set an immediate value to a register. This may generate 1 or 2
225 void li(RegisterID dest
, int imm
)
227 if (imm
>= -32768 && imm
<= 32767)
228 addiu(dest
, MIPSRegisters::zero
, imm
);
229 else if (imm
>= 0 && imm
< 65536)
230 ori(dest
, MIPSRegisters::zero
, imm
);
232 lui(dest
, imm
>> 16);
234 ori(dest
, dest
, imm
);
238 void lui(RegisterID rt
, int imm
)
240 emitInst(0x3c000000 | (rt
<< OP_SH_RT
) | (imm
& 0xffff));
243 void addiu(RegisterID rt
, RegisterID rs
, int imm
)
245 emitInst(0x24000000 | (rt
<< OP_SH_RT
) | (rs
<< OP_SH_RS
) | (imm
& 0xffff));
248 void addu(RegisterID rd
, RegisterID rs
, RegisterID rt
)
250 emitInst(0x00000021 | (rd
<< OP_SH_RD
) | (rs
<< OP_SH_RS
) | (rt
<< OP_SH_RT
));
253 void subu(RegisterID rd
, RegisterID rs
, RegisterID rt
)
255 emitInst(0x00000023 | (rd
<< OP_SH_RD
) | (rs
<< OP_SH_RS
) | (rt
<< OP_SH_RT
));
258 void mult(RegisterID rs
, RegisterID rt
)
260 emitInst(0x00000018 | (rs
<< OP_SH_RS
) | (rt
<< OP_SH_RT
));
263 void div(RegisterID rs
, RegisterID rt
)
265 emitInst(0x0000001a | (rs
<< OP_SH_RS
) | (rt
<< OP_SH_RT
));
268 void mfhi(RegisterID rd
)
270 emitInst(0x00000010 | (rd
<< OP_SH_RD
));
273 void mflo(RegisterID rd
)
275 emitInst(0x00000012 | (rd
<< OP_SH_RD
));
278 void mul(RegisterID rd
, RegisterID rs
, RegisterID rt
)
280 #if WTF_MIPS_ISA_AT_LEAST(32)
281 emitInst(0x70000002 | (rd
<< OP_SH_RD
) | (rs
<< OP_SH_RS
) | (rt
<< OP_SH_RT
));
288 void andInsn(RegisterID rd
, RegisterID rs
, RegisterID rt
)
290 emitInst(0x00000024 | (rd
<< OP_SH_RD
) | (rs
<< OP_SH_RS
) | (rt
<< OP_SH_RT
));
293 void andi(RegisterID rt
, RegisterID rs
, int imm
)
295 emitInst(0x30000000 | (rt
<< OP_SH_RT
) | (rs
<< OP_SH_RS
) | (imm
& 0xffff));
298 void nor(RegisterID rd
, RegisterID rs
, RegisterID rt
)
300 emitInst(0x00000027 | (rd
<< OP_SH_RD
) | (rs
<< OP_SH_RS
) | (rt
<< OP_SH_RT
));
303 void orInsn(RegisterID rd
, RegisterID rs
, RegisterID rt
)
305 emitInst(0x00000025 | (rd
<< OP_SH_RD
) | (rs
<< OP_SH_RS
) | (rt
<< OP_SH_RT
));
308 void ori(RegisterID rt
, RegisterID rs
, int imm
)
310 emitInst(0x34000000 | (rt
<< OP_SH_RT
) | (rs
<< OP_SH_RS
) | (imm
& 0xffff));
313 void xorInsn(RegisterID rd
, RegisterID rs
, RegisterID rt
)
315 emitInst(0x00000026 | (rd
<< OP_SH_RD
) | (rs
<< OP_SH_RS
) | (rt
<< OP_SH_RT
));
318 void xori(RegisterID rt
, RegisterID rs
, int imm
)
320 emitInst(0x38000000 | (rt
<< OP_SH_RT
) | (rs
<< OP_SH_RS
) | (imm
& 0xffff));
323 void slt(RegisterID rd
, RegisterID rs
, RegisterID rt
)
325 emitInst(0x0000002a | (rd
<< OP_SH_RD
) | (rs
<< OP_SH_RS
) | (rt
<< OP_SH_RT
));
328 void sltu(RegisterID rd
, RegisterID rs
, RegisterID rt
)
330 emitInst(0x0000002b | (rd
<< OP_SH_RD
) | (rs
<< OP_SH_RS
) | (rt
<< OP_SH_RT
));
333 void sltiu(RegisterID rt
, RegisterID rs
, int imm
)
335 emitInst(0x2c000000 | (rt
<< OP_SH_RT
) | (rs
<< OP_SH_RS
) | (imm
& 0xffff));
338 void sll(RegisterID rd
, RegisterID rt
, int shamt
)
340 emitInst(0x00000000 | (rd
<< OP_SH_RD
) | (rt
<< OP_SH_RT
) | ((shamt
& 0x1f) << OP_SH_SHAMT
));
343 void sllv(RegisterID rd
, RegisterID rt
, RegisterID rs
)
345 emitInst(0x00000004 | (rd
<< OP_SH_RD
) | (rt
<< OP_SH_RT
) | (rs
<< OP_SH_RS
));
348 void sra(RegisterID rd
, RegisterID rt
, int shamt
)
350 emitInst(0x00000003 | (rd
<< OP_SH_RD
) | (rt
<< OP_SH_RT
) | ((shamt
& 0x1f) << OP_SH_SHAMT
));
353 void srav(RegisterID rd
, RegisterID rt
, RegisterID rs
)
355 emitInst(0x00000007 | (rd
<< OP_SH_RD
) | (rt
<< OP_SH_RT
) | (rs
<< OP_SH_RS
));
358 void srl(RegisterID rd
, RegisterID rt
, int shamt
)
360 emitInst(0x00000002 | (rd
<< OP_SH_RD
) | (rt
<< OP_SH_RT
) | ((shamt
& 0x1f) << OP_SH_SHAMT
));
363 void srlv(RegisterID rd
, RegisterID rt
, RegisterID rs
)
365 emitInst(0x00000006 | (rd
<< OP_SH_RD
) | (rt
<< OP_SH_RT
) | (rs
<< OP_SH_RS
));
368 void lb(RegisterID rt
, RegisterID rs
, int offset
)
370 emitInst(0x80000000 | (rt
<< OP_SH_RT
) | (rs
<< OP_SH_RS
) | (offset
& 0xffff));
374 void lbu(RegisterID rt
, RegisterID rs
, int offset
)
376 emitInst(0x90000000 | (rt
<< OP_SH_RT
) | (rs
<< OP_SH_RS
) | (offset
& 0xffff));
380 void lw(RegisterID rt
, RegisterID rs
, int offset
)
382 emitInst(0x8c000000 | (rt
<< OP_SH_RT
) | (rs
<< OP_SH_RS
) | (offset
& 0xffff));
386 void lwl(RegisterID rt
, RegisterID rs
, int offset
)
388 emitInst(0x88000000 | (rt
<< OP_SH_RT
) | (rs
<< OP_SH_RS
) | (offset
& 0xffff));
392 void lwr(RegisterID rt
, RegisterID rs
, int offset
)
394 emitInst(0x98000000 | (rt
<< OP_SH_RT
) | (rs
<< OP_SH_RS
) | (offset
& 0xffff));
398 void lh(RegisterID rt
, RegisterID rs
, int offset
)
400 emitInst(0x84000000 | (rt
<< OP_SH_RT
) | (rs
<< OP_SH_RS
) | (offset
& 0xffff));
404 void lhu(RegisterID rt
, RegisterID rs
, int offset
)
406 emitInst(0x94000000 | (rt
<< OP_SH_RT
) | (rs
<< OP_SH_RS
) | (offset
& 0xffff));
410 void sb(RegisterID rt
, RegisterID rs
, int offset
)
412 emitInst(0xa0000000 | (rt
<< OP_SH_RT
) | (rs
<< OP_SH_RS
) | (offset
& 0xffff));
415 void sh(RegisterID rt
, RegisterID rs
, int offset
)
417 emitInst(0xa4000000 | (rt
<< OP_SH_RT
) | (rs
<< OP_SH_RS
) | (offset
& 0xffff));
420 void sw(RegisterID rt
, RegisterID rs
, int offset
)
422 emitInst(0xac000000 | (rt
<< OP_SH_RT
) | (rs
<< OP_SH_RS
) | (offset
& 0xffff));
425 void jr(RegisterID rs
)
427 emitInst(0x00000008 | (rs
<< OP_SH_RS
));
430 void jalr(RegisterID rs
)
432 emitInst(0x0000f809 | (rs
<< OP_SH_RS
));
437 emitInst(0x0c000000);
442 int value
= 512; /* BRK_BUG */
443 emitInst(0x0000000d | ((value
& 0x3ff) << OP_SH_CODE
));
446 void bgez(RegisterID rs
, int imm
)
448 emitInst(0x04010000 | (rs
<< OP_SH_RS
) | (imm
& 0xffff));
451 void bltz(RegisterID rs
, int imm
)
453 emitInst(0x04000000 | (rs
<< OP_SH_RS
) | (imm
& 0xffff));
456 void beq(RegisterID rs
, RegisterID rt
, int imm
)
458 emitInst(0x10000000 | (rs
<< OP_SH_RS
) | (rt
<< OP_SH_RT
) | (imm
& 0xffff));
461 void bne(RegisterID rs
, RegisterID rt
, int imm
)
463 emitInst(0x14000000 | (rs
<< OP_SH_RS
) | (rt
<< OP_SH_RT
) | (imm
& 0xffff));
468 emitInst(0x45010000);
473 emitInst(0x45000000);
478 m_jumps
.append(m_buffer
.label());
481 void addd(FPRegisterID fd
, FPRegisterID fs
, FPRegisterID ft
)
483 emitInst(0x46200000 | (fd
<< OP_SH_FD
) | (fs
<< OP_SH_FS
) | (ft
<< OP_SH_FT
));
486 void subd(FPRegisterID fd
, FPRegisterID fs
, FPRegisterID ft
)
488 emitInst(0x46200001 | (fd
<< OP_SH_FD
) | (fs
<< OP_SH_FS
) | (ft
<< OP_SH_FT
));
491 void muld(FPRegisterID fd
, FPRegisterID fs
, FPRegisterID ft
)
493 emitInst(0x46200002 | (fd
<< OP_SH_FD
) | (fs
<< OP_SH_FS
) | (ft
<< OP_SH_FT
));
496 void divd(FPRegisterID fd
, FPRegisterID fs
, FPRegisterID ft
)
498 emitInst(0x46200003 | (fd
<< OP_SH_FD
) | (fs
<< OP_SH_FS
) | (ft
<< OP_SH_FT
));
501 void lwc1(FPRegisterID ft
, RegisterID rs
, int offset
)
503 emitInst(0xc4000000 | (ft
<< OP_SH_FT
) | (rs
<< OP_SH_RS
) | (offset
& 0xffff));
507 void ldc1(FPRegisterID ft
, RegisterID rs
, int offset
)
509 emitInst(0xd4000000 | (ft
<< OP_SH_FT
) | (rs
<< OP_SH_RS
) | (offset
& 0xffff));
512 void swc1(FPRegisterID ft
, RegisterID rs
, int offset
)
514 emitInst(0xe4000000 | (ft
<< OP_SH_FT
) | (rs
<< OP_SH_RS
) | (offset
& 0xffff));
517 void sdc1(FPRegisterID ft
, RegisterID rs
, int offset
)
519 emitInst(0xf4000000 | (ft
<< OP_SH_FT
) | (rs
<< OP_SH_RS
) | (offset
& 0xffff));
522 void mtc1(RegisterID rt
, FPRegisterID fs
)
524 emitInst(0x44800000 | (fs
<< OP_SH_FS
) | (rt
<< OP_SH_RT
));
528 void mthc1(RegisterID rt
, FPRegisterID fs
)
530 emitInst(0x44e00000 | (fs
<< OP_SH_FS
) | (rt
<< OP_SH_RT
));
534 void mfc1(RegisterID rt
, FPRegisterID fs
)
536 emitInst(0x44000000 | (fs
<< OP_SH_FS
) | (rt
<< OP_SH_RT
));
540 void sqrtd(FPRegisterID fd
, FPRegisterID fs
)
542 emitInst(0x46200004 | (fd
<< OP_SH_FD
) | (fs
<< OP_SH_FS
));
545 void movd(FPRegisterID fd
, FPRegisterID fs
)
547 emitInst(0x46200006 | (fd
<< OP_SH_FD
) | (fs
<< OP_SH_FS
));
550 void negd(FPRegisterID fd
, FPRegisterID fs
)
552 emitInst(0x46200007 | (fd
<< OP_SH_FD
) | (fs
<< OP_SH_FS
));
555 void truncwd(FPRegisterID fd
, FPRegisterID fs
)
557 emitInst(0x4620000d | (fd
<< OP_SH_FD
) | (fs
<< OP_SH_FS
));
560 void cvtdw(FPRegisterID fd
, FPRegisterID fs
)
562 emitInst(0x46800021 | (fd
<< OP_SH_FD
) | (fs
<< OP_SH_FS
));
565 void cvtds(FPRegisterID fd
, FPRegisterID fs
)
567 emitInst(0x46000021 | (fd
<< OP_SH_FD
) | (fs
<< OP_SH_FS
));
570 void cvtwd(FPRegisterID fd
, FPRegisterID fs
)
572 emitInst(0x46200024 | (fd
<< OP_SH_FD
) | (fs
<< OP_SH_FS
));
575 void cvtsd(FPRegisterID fd
, FPRegisterID fs
)
577 emitInst(0x46200020 | (fd
<< OP_SH_FD
) | (fs
<< OP_SH_FS
));
580 void ceqd(FPRegisterID fs
, FPRegisterID ft
)
582 emitInst(0x46200032 | (fs
<< OP_SH_FS
) | (ft
<< OP_SH_FT
));
586 void cngtd(FPRegisterID fs
, FPRegisterID ft
)
588 emitInst(0x4620003f | (fs
<< OP_SH_FS
) | (ft
<< OP_SH_FT
));
592 void cnged(FPRegisterID fs
, FPRegisterID ft
)
594 emitInst(0x4620003d | (fs
<< OP_SH_FS
) | (ft
<< OP_SH_FT
));
598 void cltd(FPRegisterID fs
, FPRegisterID ft
)
600 emitInst(0x4620003c | (fs
<< OP_SH_FS
) | (ft
<< OP_SH_FT
));
604 void cled(FPRegisterID fs
, FPRegisterID ft
)
606 emitInst(0x4620003e | (fs
<< OP_SH_FS
) | (ft
<< OP_SH_FT
));
610 void cueqd(FPRegisterID fs
, FPRegisterID ft
)
612 emitInst(0x46200033 | (fs
<< OP_SH_FS
) | (ft
<< OP_SH_FT
));
616 void coled(FPRegisterID fs
, FPRegisterID ft
)
618 emitInst(0x46200036 | (fs
<< OP_SH_FS
) | (ft
<< OP_SH_FT
));
622 void coltd(FPRegisterID fs
, FPRegisterID ft
)
624 emitInst(0x46200034 | (fs
<< OP_SH_FS
) | (ft
<< OP_SH_FT
));
628 void culed(FPRegisterID fs
, FPRegisterID ft
)
630 emitInst(0x46200037 | (fs
<< OP_SH_FS
) | (ft
<< OP_SH_FT
));
634 void cultd(FPRegisterID fs
, FPRegisterID ft
)
636 emitInst(0x46200035 | (fs
<< OP_SH_FS
) | (ft
<< OP_SH_FT
));
642 AssemblerLabel
labelIgnoringWatchpoints()
644 return m_buffer
.label();
647 AssemblerLabel
labelForWatchpoint()
649 AssemblerLabel result
= m_buffer
.label();
650 if (static_cast<int>(result
.m_offset
) != m_indexOfLastWatchpoint
)
652 m_indexOfLastWatchpoint
= result
.m_offset
;
653 m_indexOfTailOfLastWatchpoint
= result
.m_offset
+ maxJumpReplacementSize();
657 AssemblerLabel
label()
659 AssemblerLabel result
= m_buffer
.label();
660 while (UNLIKELY(static_cast<int>(result
.m_offset
) < m_indexOfTailOfLastWatchpoint
)) {
662 result
= m_buffer
.label();
667 AssemblerLabel
align(int alignment
)
669 while (!m_buffer
.isAligned(alignment
))
675 static void* getRelocatedAddress(void* code
, AssemblerLabel label
)
677 return reinterpret_cast<void*>(reinterpret_cast<char*>(code
) + label
.m_offset
);
680 static int getDifferenceBetweenLabels(AssemblerLabel a
, AssemblerLabel b
)
682 return b
.m_offset
- a
.m_offset
;
685 // Assembler admin methods:
687 size_t codeSize() const
689 return m_buffer
.codeSize();
692 unsigned debugOffset() { return m_buffer
.debugOffset(); }
694 // Assembly helpers for moving data between fp and registers.
695 void vmov(RegisterID rd1
, RegisterID rd2
, FPRegisterID rn
)
697 #if WTF_MIPS_ISA_REV(2) && WTF_MIPS_FP64
702 mfc1(rd2
, FPRegisterID(rn
+ 1));
706 void vmov(FPRegisterID rd
, RegisterID rn1
, RegisterID rn2
)
708 #if WTF_MIPS_ISA_REV(2) && WTF_MIPS_FP64
713 mtc1(rn2
, FPRegisterID(rd
+ 1));
717 static unsigned getCallReturnOffset(AssemblerLabel call
)
719 // The return address is after a call and a delay slot instruction
720 return call
.m_offset
;
723 // Linking & patching:
725 // 'link' and 'patch' methods are for use on unprotected code - such as the code
726 // within the AssemblerBuffer, and code being patched by the patch buffer. Once
727 // code has been finalized it is (platform support permitting) within a non-
728 // writable region of memory; to modify the code in an execute-only execuable
729 // pool the 'repatch' and 'relink' methods should be used.
731 static size_t linkDirectJump(void* code
, void* to
)
733 MIPSWord
* insn
= reinterpret_cast<MIPSWord
*>(reinterpret_cast<intptr_t>(code
));
735 int32_t slotAddr
= reinterpret_cast<int>(insn
) + 4;
736 int32_t toAddr
= reinterpret_cast<int>(to
);
738 if ((slotAddr
& 0xf0000000) != (toAddr
& 0xf0000000)) {
740 *insn
= 0x3c000000 | (MIPSRegisters::t9
<< OP_SH_RT
) | ((toAddr
>> 16) & 0xffff);
743 *insn
= 0x34000000 | (MIPSRegisters::t9
<< OP_SH_RT
) | (MIPSRegisters::t9
<< OP_SH_RS
) | (toAddr
& 0xffff);
746 *insn
= 0x00000008 | (MIPSRegisters::t9
<< OP_SH_RS
);
748 ops
= 4 * sizeof(MIPSWord
);
751 *insn
= 0x08000000 | ((toAddr
& 0x0fffffff) >> 2);
753 ops
= 2 * sizeof(MIPSWord
);
760 void linkJump(AssemblerLabel from
, AssemblerLabel to
)
763 ASSERT(from
.isSet());
764 MIPSWord
* insn
= reinterpret_cast<MIPSWord
*>(reinterpret_cast<intptr_t>(m_buffer
.data()) + from
.m_offset
);
765 MIPSWord
* toPos
= reinterpret_cast<MIPSWord
*>(reinterpret_cast<intptr_t>(m_buffer
.data()) + to
.m_offset
);
767 ASSERT(!(*(insn
- 1)) && !(*(insn
- 2)) && !(*(insn
- 3)) && !(*(insn
- 5)));
769 linkWithOffset(insn
, toPos
);
772 static void linkJump(void* code
, AssemblerLabel from
, void* to
)
774 ASSERT(from
.isSet());
775 MIPSWord
* insn
= reinterpret_cast<MIPSWord
*>(reinterpret_cast<intptr_t>(code
) + from
.m_offset
);
777 ASSERT(!(*(insn
- 1)) && !(*(insn
- 2)) && !(*(insn
- 3)) && !(*(insn
- 5)));
779 linkWithOffset(insn
, to
);
782 static void linkCall(void* code
, AssemblerLabel from
, void* to
)
784 MIPSWord
* insn
= reinterpret_cast<MIPSWord
*>(reinterpret_cast<intptr_t>(code
) + from
.m_offset
);
785 linkCallInternal(insn
, to
);
788 static void linkPointer(void* code
, AssemblerLabel from
, void* to
)
790 MIPSWord
* insn
= reinterpret_cast<MIPSWord
*>(reinterpret_cast<intptr_t>(code
) + from
.m_offset
);
791 ASSERT((*insn
& 0xffe00000) == 0x3c000000); // lui
792 *insn
= (*insn
& 0xffff0000) | ((reinterpret_cast<intptr_t>(to
) >> 16) & 0xffff);
794 ASSERT((*insn
& 0xfc000000) == 0x34000000); // ori
795 *insn
= (*insn
& 0xffff0000) | (reinterpret_cast<intptr_t>(to
) & 0xffff);
798 static void relinkJump(void* from
, void* to
)
800 MIPSWord
* insn
= reinterpret_cast<MIPSWord
*>(from
);
802 ASSERT(!(*(insn
- 1)) && !(*(insn
- 5)));
804 int flushSize
= linkWithOffset(insn
, to
);
806 cacheFlush(insn
, flushSize
);
809 static void relinkCall(void* from
, void* to
)
812 int size
= linkCallInternal(from
, to
);
813 if (size
== sizeof(MIPSWord
))
814 start
= reinterpret_cast<void*>(reinterpret_cast<intptr_t>(from
) - 2 * sizeof(MIPSWord
));
816 start
= reinterpret_cast<void*>(reinterpret_cast<intptr_t>(from
) - 4 * sizeof(MIPSWord
));
818 cacheFlush(start
, size
);
821 static void repatchInt32(void* from
, int32_t to
)
823 MIPSWord
* insn
= reinterpret_cast<MIPSWord
*>(from
);
824 ASSERT((*insn
& 0xffe00000) == 0x3c000000); // lui
825 *insn
= (*insn
& 0xffff0000) | ((to
>> 16) & 0xffff);
827 ASSERT((*insn
& 0xfc000000) == 0x34000000); // ori
828 *insn
= (*insn
& 0xffff0000) | (to
& 0xffff);
830 cacheFlush(insn
, 2 * sizeof(MIPSWord
));
833 static int32_t readInt32(void* from
)
835 MIPSWord
* insn
= reinterpret_cast<MIPSWord
*>(from
);
836 ASSERT((*insn
& 0xffe00000) == 0x3c000000); // lui
837 int32_t result
= (*insn
& 0x0000ffff) << 16;
839 ASSERT((*insn
& 0xfc000000) == 0x34000000); // ori
840 result
|= *insn
& 0x0000ffff;
844 static void repatchCompact(void* where
, int32_t value
)
846 repatchInt32(where
, value
);
849 static void repatchPointer(void* from
, void* to
)
851 repatchInt32(from
, reinterpret_cast<int32_t>(to
));
854 static void* readPointer(void* from
)
856 return reinterpret_cast<void*>(readInt32(from
));
859 static void* readCallTarget(void* from
)
861 MIPSWord
* insn
= reinterpret_cast<MIPSWord
*>(from
);
863 ASSERT((*insn
& 0xffe00000) == 0x3c000000); // lui
864 int32_t result
= (*insn
& 0x0000ffff) << 16;
866 ASSERT((*insn
& 0xfc000000) == 0x34000000); // ori
867 result
|= *insn
& 0x0000ffff;
868 return reinterpret_cast<void*>(result
);
871 static void cacheFlush(void* code
, size_t size
)
873 intptr_t end
= reinterpret_cast<intptr_t>(code
) + size
;
874 __builtin___clear_cache(reinterpret_cast<char*>(code
), reinterpret_cast<char*>(end
));
877 static ptrdiff_t maxJumpReplacementSize()
879 return sizeof(MIPSWord
) * 4;
882 static void revertJumpToMove(void* instructionStart
, RegisterID rt
, int imm
)
884 MIPSWord
* insn
= static_cast<MIPSWord
*>(instructionStart
);
885 size_t codeSize
= 2 * sizeof(MIPSWord
);
888 *insn
= 0x3c000000 | (rt
<< OP_SH_RT
) | ((imm
>> 16) & 0xffff);
891 *insn
= 0x34000000 | (rt
<< OP_SH_RS
) | (rt
<< OP_SH_RT
) | (imm
& 0xffff);
894 if (*insn
== 0x03200008) {
896 codeSize
+= sizeof(MIPSWord
);
898 cacheFlush(insn
, codeSize
);
901 static void replaceWithJump(void* instructionStart
, void* to
)
903 ASSERT(!(bitwise_cast
<uintptr_t>(instructionStart
) & 3));
904 ASSERT(!(bitwise_cast
<uintptr_t>(to
) & 3));
905 size_t ops
= linkDirectJump(instructionStart
, to
);
906 cacheFlush(instructionStart
, ops
);
909 static void replaceWithLoad(void* instructionStart
)
911 MIPSWord
* insn
= reinterpret_cast<MIPSWord
*>(instructionStart
);
912 ASSERT((*insn
& 0xffe00000) == 0x3c000000); // lui
914 ASSERT((*insn
& 0xfc0007ff) == 0x00000021); // addu
916 *insn
= 0x8c000000 | ((*insn
) & 0x3ffffff); // lw
920 static void replaceWithAddressComputation(void* instructionStart
)
922 MIPSWord
* insn
= reinterpret_cast<MIPSWord
*>(instructionStart
);
923 ASSERT((*insn
& 0xffe00000) == 0x3c000000); // lui
925 ASSERT((*insn
& 0xfc0007ff) == 0x00000021); // addu
927 *insn
= 0x24000000 | ((*insn
) & 0x3ffffff); // addiu
931 /* Update each jump in the buffer of newBase. */
932 void relocateJumps(void* oldBase
, void* newBase
)
935 for (Jumps::Iterator iter
= m_jumps
.begin(); iter
!= m_jumps
.end(); ++iter
) {
936 int pos
= iter
->m_offset
;
937 MIPSWord
* insn
= reinterpret_cast<MIPSWord
*>(reinterpret_cast<intptr_t>(newBase
) + pos
);
939 // Need to make sure we have 5 valid instructions after pos
940 if ((unsigned)pos
>= m_buffer
.codeSize() - 5 * sizeof(MIPSWord
))
943 if ((*insn
& 0xfc000000) == 0x08000000) { // j
944 int offset
= *insn
& 0x03ffffff;
945 int oldInsnAddress
= (int)insn
- (int)newBase
+ (int)oldBase
;
946 int topFourBits
= (oldInsnAddress
+ 4) >> 28;
947 int oldTargetAddress
= (topFourBits
<< 28) | (offset
<< 2);
948 int newTargetAddress
= oldTargetAddress
- (int)oldBase
+ (int)newBase
;
949 int newInsnAddress
= (int)insn
;
950 if (((newInsnAddress
+ 4) >> 28) == (newTargetAddress
>> 28))
951 *insn
= 0x08000000 | ((newTargetAddress
>> 2) & 0x3ffffff);
954 *insn
= 0x3c000000 | (MIPSRegisters::t9
<< OP_SH_RT
) | ((newTargetAddress
>> 16) & 0xffff);
956 *(insn
+ 1) = 0x34000000 | (MIPSRegisters::t9
<< OP_SH_RT
) | (MIPSRegisters::t9
<< OP_SH_RS
) | (newTargetAddress
& 0xffff);
958 *(insn
+ 2) = 0x00000008 | (MIPSRegisters::t9
<< OP_SH_RS
);
960 } else if ((*insn
& 0xffe00000) == 0x3c000000) { // lui
961 int high
= (*insn
& 0xffff) << 16;
962 int low
= *(insn
+ 1) & 0xffff;
963 int oldTargetAddress
= high
| low
;
964 int newTargetAddress
= oldTargetAddress
- (int)oldBase
+ (int)newBase
;
966 *insn
= 0x3c000000 | (MIPSRegisters::t9
<< OP_SH_RT
) | ((newTargetAddress
>> 16) & 0xffff);
968 *(insn
+ 1) = 0x34000000 | (MIPSRegisters::t9
<< OP_SH_RT
) | (MIPSRegisters::t9
<< OP_SH_RS
) | (newTargetAddress
& 0xffff);
974 static int linkWithOffset(MIPSWord
* insn
, void* to
)
976 ASSERT((*insn
& 0xfc000000) == 0x10000000 // beq
977 || (*insn
& 0xfc000000) == 0x14000000 // bne
978 || (*insn
& 0xffff0000) == 0x45010000 // bc1t
979 || (*insn
& 0xffff0000) == 0x45000000); // bc1f
980 intptr_t diff
= (reinterpret_cast<intptr_t>(to
) - reinterpret_cast<intptr_t>(insn
) - 4) >> 2;
982 if (diff
< -32768 || diff
> 32767 || *(insn
+ 2) != 0x10000003) {
984 Convert the sequence:
993 to the new sequence if possible:
1002 OR to the new sequence:
1005 lui $25, target >> 16
1006 ori $25, $25, target & 0xffff
1011 Note: beq/bne/bc1t/bc1f are converted to bne/beq/bc1f/bc1t.
1014 if (*(insn
+ 2) == 0x10000003) {
1015 if ((*insn
& 0xfc000000) == 0x10000000) // beq
1016 *insn
= (*insn
& 0x03ff0000) | 0x14000005; // bne
1017 else if ((*insn
& 0xfc000000) == 0x14000000) // bne
1018 *insn
= (*insn
& 0x03ff0000) | 0x10000005; // beq
1019 else if ((*insn
& 0xffff0000) == 0x45010000) // bc1t
1020 *insn
= 0x45000005; // bc1f
1021 else if ((*insn
& 0xffff0000) == 0x45000000) // bc1f
1022 *insn
= 0x45010005; // bc1t
1028 if ((reinterpret_cast<intptr_t>(insn
) + 4) >> 28
1029 == reinterpret_cast<intptr_t>(to
) >> 28) {
1030 *insn
= 0x08000000 | ((reinterpret_cast<intptr_t>(to
) >> 2) & 0x3ffffff);
1032 return 4 * sizeof(MIPSWord
);
1035 intptr_t newTargetAddress
= reinterpret_cast<intptr_t>(to
);
1037 *insn
= 0x3c000000 | (MIPSRegisters::t9
<< OP_SH_RT
) | ((newTargetAddress
>> 16) & 0xffff);
1039 *(insn
+ 1) = 0x34000000 | (MIPSRegisters::t9
<< OP_SH_RT
) | (MIPSRegisters::t9
<< OP_SH_RS
) | (newTargetAddress
& 0xffff);
1041 *(insn
+ 2) = 0x00000008 | (MIPSRegisters::t9
<< OP_SH_RS
);
1042 return 5 * sizeof(MIPSWord
);
1045 *insn
= (*insn
& 0xffff0000) | (diff
& 0xffff);
1046 return sizeof(MIPSWord
);
1049 static int linkCallInternal(void* from
, void* to
)
1051 MIPSWord
* insn
= reinterpret_cast<MIPSWord
*>(from
);
1054 if ((*(insn
+ 2) & 0xfc000000) == 0x0c000000) { // jal
1055 if ((reinterpret_cast<intptr_t>(from
) - 4) >> 28
1056 == reinterpret_cast<intptr_t>(to
) >> 28) {
1057 *(insn
+ 2) = 0x0c000000 | ((reinterpret_cast<intptr_t>(to
) >> 2) & 0x3ffffff);
1058 return sizeof(MIPSWord
);
1061 /* lui $25, (to >> 16) & 0xffff */
1062 *insn
= 0x3c000000 | (MIPSRegisters::t9
<< OP_SH_RT
) | ((reinterpret_cast<intptr_t>(to
) >> 16) & 0xffff);
1063 /* ori $25, $25, to & 0xffff */
1064 *(insn
+ 1) = 0x34000000 | (MIPSRegisters::t9
<< OP_SH_RT
) | (MIPSRegisters::t9
<< OP_SH_RS
) | (reinterpret_cast<intptr_t>(to
) & 0xffff);
1066 *(insn
+ 2) = 0x0000f809 | (MIPSRegisters::t9
<< OP_SH_RS
);
1067 return 3 * sizeof(MIPSWord
);
1070 ASSERT((*insn
& 0xffe00000) == 0x3c000000); // lui
1071 ASSERT((*(insn
+ 1) & 0xfc000000) == 0x34000000); // ori
1074 *insn
= (*insn
& 0xffff0000) | ((reinterpret_cast<intptr_t>(to
) >> 16) & 0xffff);
1076 *(insn
+ 1) = (*(insn
+ 1) & 0xffff0000) | (reinterpret_cast<intptr_t>(to
) & 0xffff);
1077 return 2 * sizeof(MIPSWord
);
1080 AssemblerBuffer m_buffer
;
1082 int m_indexOfLastWatchpoint
;
1083 int m_indexOfTailOfLastWatchpoint
;
1088 #endif // ENABLE(ASSEMBLER) && CPU(MIPS)
1090 #endif // MIPSAssembler_h