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
;
155 : m_indexOfLastWatchpoint(INT_MIN
)
156 , m_indexOfTailOfLastWatchpoint(INT_MIN
)
160 // MIPS instruction opcode field position
172 void emitInst(MIPSWord op
)
174 void* oldBase
= m_buffer
.data();
178 void* newBase
= m_buffer
.data();
179 if (oldBase
!= newBase
)
180 relocateJumps(oldBase
, newBase
);
185 emitInst(0x00000000);
188 /* Need to insert one load data delay nop for mips1. */
196 /* Need to insert one coprocessor access delay nop for mips1. */
204 void move(RegisterID rd
, RegisterID rs
)
207 emitInst(0x00000021 | (rd
<< OP_SH_RD
) | (rs
<< OP_SH_RS
));
210 /* Set an immediate value to a register. This may generate 1 or 2
212 void li(RegisterID dest
, int imm
)
214 if (imm
>= -32768 && imm
<= 32767)
215 addiu(dest
, MIPSRegisters::zero
, imm
);
216 else if (imm
>= 0 && imm
< 65536)
217 ori(dest
, MIPSRegisters::zero
, imm
);
219 lui(dest
, imm
>> 16);
221 ori(dest
, dest
, imm
);
225 void lui(RegisterID rt
, int imm
)
227 emitInst(0x3c000000 | (rt
<< OP_SH_RT
) | (imm
& 0xffff));
230 void addiu(RegisterID rt
, RegisterID rs
, int imm
)
232 emitInst(0x24000000 | (rt
<< OP_SH_RT
) | (rs
<< OP_SH_RS
) | (imm
& 0xffff));
235 void addu(RegisterID rd
, RegisterID rs
, RegisterID rt
)
237 emitInst(0x00000021 | (rd
<< OP_SH_RD
) | (rs
<< OP_SH_RS
) | (rt
<< OP_SH_RT
));
240 void subu(RegisterID rd
, RegisterID rs
, RegisterID rt
)
242 emitInst(0x00000023 | (rd
<< OP_SH_RD
) | (rs
<< OP_SH_RS
) | (rt
<< OP_SH_RT
));
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
) | (rt
<< OP_SH_RT
));
275 void andInsn(RegisterID rd
, RegisterID rs
, RegisterID rt
)
277 emitInst(0x00000024 | (rd
<< OP_SH_RD
) | (rs
<< OP_SH_RS
) | (rt
<< OP_SH_RT
));
280 void andi(RegisterID rt
, RegisterID rs
, int imm
)
282 emitInst(0x30000000 | (rt
<< OP_SH_RT
) | (rs
<< OP_SH_RS
) | (imm
& 0xffff));
285 void nor(RegisterID rd
, RegisterID rs
, RegisterID rt
)
287 emitInst(0x00000027 | (rd
<< OP_SH_RD
) | (rs
<< OP_SH_RS
) | (rt
<< OP_SH_RT
));
290 void orInsn(RegisterID rd
, RegisterID rs
, RegisterID rt
)
292 emitInst(0x00000025 | (rd
<< OP_SH_RD
) | (rs
<< OP_SH_RS
) | (rt
<< OP_SH_RT
));
295 void ori(RegisterID rt
, RegisterID rs
, int imm
)
297 emitInst(0x34000000 | (rt
<< OP_SH_RT
) | (rs
<< OP_SH_RS
) | (imm
& 0xffff));
300 void xorInsn(RegisterID rd
, RegisterID rs
, RegisterID rt
)
302 emitInst(0x00000026 | (rd
<< OP_SH_RD
) | (rs
<< OP_SH_RS
) | (rt
<< OP_SH_RT
));
305 void xori(RegisterID rt
, RegisterID rs
, int imm
)
307 emitInst(0x38000000 | (rt
<< OP_SH_RT
) | (rs
<< OP_SH_RS
) | (imm
& 0xffff));
310 void slt(RegisterID rd
, RegisterID rs
, RegisterID rt
)
312 emitInst(0x0000002a | (rd
<< OP_SH_RD
) | (rs
<< OP_SH_RS
) | (rt
<< OP_SH_RT
));
315 void sltu(RegisterID rd
, RegisterID rs
, RegisterID rt
)
317 emitInst(0x0000002b | (rd
<< OP_SH_RD
) | (rs
<< OP_SH_RS
) | (rt
<< OP_SH_RT
));
320 void sltiu(RegisterID rt
, RegisterID rs
, int imm
)
322 emitInst(0x2c000000 | (rt
<< OP_SH_RT
) | (rs
<< OP_SH_RS
) | (imm
& 0xffff));
325 void sll(RegisterID rd
, RegisterID rt
, int shamt
)
327 emitInst(0x00000000 | (rd
<< OP_SH_RD
) | (rt
<< OP_SH_RT
) | ((shamt
& 0x1f) << OP_SH_SHAMT
));
330 void sllv(RegisterID rd
, RegisterID rt
, RegisterID rs
)
332 emitInst(0x00000004 | (rd
<< OP_SH_RD
) | (rt
<< OP_SH_RT
) | (rs
<< OP_SH_RS
));
335 void sra(RegisterID rd
, RegisterID rt
, int shamt
)
337 emitInst(0x00000003 | (rd
<< OP_SH_RD
) | (rt
<< OP_SH_RT
) | ((shamt
& 0x1f) << OP_SH_SHAMT
));
340 void srav(RegisterID rd
, RegisterID rt
, RegisterID rs
)
342 emitInst(0x00000007 | (rd
<< OP_SH_RD
) | (rt
<< OP_SH_RT
) | (rs
<< OP_SH_RS
));
345 void srl(RegisterID rd
, RegisterID rt
, int shamt
)
347 emitInst(0x00000002 | (rd
<< OP_SH_RD
) | (rt
<< OP_SH_RT
) | ((shamt
& 0x1f) << OP_SH_SHAMT
));
350 void srlv(RegisterID rd
, RegisterID rt
, RegisterID rs
)
352 emitInst(0x00000006 | (rd
<< OP_SH_RD
) | (rt
<< OP_SH_RT
) | (rs
<< OP_SH_RS
));
355 void lb(RegisterID rt
, RegisterID rs
, int offset
)
357 emitInst(0x80000000 | (rt
<< OP_SH_RT
) | (rs
<< OP_SH_RS
) | (offset
& 0xffff));
361 void lbu(RegisterID rt
, RegisterID rs
, int offset
)
363 emitInst(0x90000000 | (rt
<< OP_SH_RT
) | (rs
<< OP_SH_RS
) | (offset
& 0xffff));
367 void lw(RegisterID rt
, RegisterID rs
, int offset
)
369 emitInst(0x8c000000 | (rt
<< OP_SH_RT
) | (rs
<< OP_SH_RS
) | (offset
& 0xffff));
373 void lwl(RegisterID rt
, RegisterID rs
, int offset
)
375 emitInst(0x88000000 | (rt
<< OP_SH_RT
) | (rs
<< OP_SH_RS
) | (offset
& 0xffff));
379 void lwr(RegisterID rt
, RegisterID rs
, int offset
)
381 emitInst(0x98000000 | (rt
<< OP_SH_RT
) | (rs
<< OP_SH_RS
) | (offset
& 0xffff));
385 void lh(RegisterID rt
, RegisterID rs
, int offset
)
387 emitInst(0x84000000 | (rt
<< OP_SH_RT
) | (rs
<< OP_SH_RS
) | (offset
& 0xffff));
391 void lhu(RegisterID rt
, RegisterID rs
, int offset
)
393 emitInst(0x94000000 | (rt
<< OP_SH_RT
) | (rs
<< OP_SH_RS
) | (offset
& 0xffff));
397 void sb(RegisterID rt
, RegisterID rs
, int offset
)
399 emitInst(0xa0000000 | (rt
<< OP_SH_RT
) | (rs
<< OP_SH_RS
) | (offset
& 0xffff));
402 void sh(RegisterID rt
, RegisterID rs
, int offset
)
404 emitInst(0xa4000000 | (rt
<< OP_SH_RT
) | (rs
<< OP_SH_RS
) | (offset
& 0xffff));
407 void sw(RegisterID rt
, RegisterID rs
, int offset
)
409 emitInst(0xac000000 | (rt
<< OP_SH_RT
) | (rs
<< OP_SH_RS
) | (offset
& 0xffff));
412 void jr(RegisterID rs
)
414 emitInst(0x00000008 | (rs
<< OP_SH_RS
));
417 void jalr(RegisterID rs
)
419 emitInst(0x0000f809 | (rs
<< OP_SH_RS
));
424 emitInst(0x0c000000);
429 int value
= 512; /* BRK_BUG */
430 emitInst(0x0000000d | ((value
& 0x3ff) << OP_SH_CODE
));
433 void bgez(RegisterID rs
, int imm
)
435 emitInst(0x04010000 | (rs
<< OP_SH_RS
) | (imm
& 0xffff));
438 void bltz(RegisterID rs
, int imm
)
440 emitInst(0x04000000 | (rs
<< OP_SH_RS
) | (imm
& 0xffff));
443 void beq(RegisterID rs
, RegisterID rt
, int imm
)
445 emitInst(0x10000000 | (rs
<< OP_SH_RS
) | (rt
<< OP_SH_RT
) | (imm
& 0xffff));
448 void bne(RegisterID rs
, RegisterID rt
, int imm
)
450 emitInst(0x14000000 | (rs
<< OP_SH_RS
) | (rt
<< OP_SH_RT
) | (imm
& 0xffff));
455 emitInst(0x45010000);
460 emitInst(0x45000000);
465 m_jumps
.append(m_buffer
.label());
468 void addd(FPRegisterID fd
, FPRegisterID fs
, FPRegisterID ft
)
470 emitInst(0x46200000 | (fd
<< OP_SH_FD
) | (fs
<< OP_SH_FS
) | (ft
<< OP_SH_FT
));
473 void subd(FPRegisterID fd
, FPRegisterID fs
, FPRegisterID ft
)
475 emitInst(0x46200001 | (fd
<< OP_SH_FD
) | (fs
<< OP_SH_FS
) | (ft
<< OP_SH_FT
));
478 void muld(FPRegisterID fd
, FPRegisterID fs
, FPRegisterID ft
)
480 emitInst(0x46200002 | (fd
<< OP_SH_FD
) | (fs
<< OP_SH_FS
) | (ft
<< OP_SH_FT
));
483 void divd(FPRegisterID fd
, FPRegisterID fs
, FPRegisterID ft
)
485 emitInst(0x46200003 | (fd
<< OP_SH_FD
) | (fs
<< OP_SH_FS
) | (ft
<< OP_SH_FT
));
488 void lwc1(FPRegisterID ft
, RegisterID rs
, int offset
)
490 emitInst(0xc4000000 | (ft
<< OP_SH_FT
) | (rs
<< OP_SH_RS
) | (offset
& 0xffff));
494 void ldc1(FPRegisterID ft
, RegisterID rs
, int offset
)
496 emitInst(0xd4000000 | (ft
<< OP_SH_FT
) | (rs
<< OP_SH_RS
) | (offset
& 0xffff));
499 void swc1(FPRegisterID ft
, RegisterID rs
, int offset
)
501 emitInst(0xe4000000 | (ft
<< OP_SH_FT
) | (rs
<< OP_SH_RS
) | (offset
& 0xffff));
504 void sdc1(FPRegisterID ft
, RegisterID rs
, int offset
)
506 emitInst(0xf4000000 | (ft
<< OP_SH_FT
) | (rs
<< OP_SH_RS
) | (offset
& 0xffff));
509 void mtc1(RegisterID rt
, FPRegisterID fs
)
511 emitInst(0x44800000 | (fs
<< OP_SH_FS
) | (rt
<< OP_SH_RT
));
515 void mthc1(RegisterID rt
, FPRegisterID fs
)
517 emitInst(0x44e00000 | (fs
<< OP_SH_FS
) | (rt
<< OP_SH_RT
));
521 void mfc1(RegisterID rt
, FPRegisterID fs
)
523 emitInst(0x44000000 | (fs
<< OP_SH_FS
) | (rt
<< OP_SH_RT
));
527 void sqrtd(FPRegisterID fd
, FPRegisterID fs
)
529 emitInst(0x46200004 | (fd
<< OP_SH_FD
) | (fs
<< OP_SH_FS
));
532 void movd(FPRegisterID fd
, FPRegisterID fs
)
534 emitInst(0x46200006 | (fd
<< OP_SH_FD
) | (fs
<< OP_SH_FS
));
537 void negd(FPRegisterID fd
, FPRegisterID fs
)
539 emitInst(0x46200007 | (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 cvtds(FPRegisterID fd
, FPRegisterID fs
)
554 emitInst(0x46000021 | (fd
<< OP_SH_FD
) | (fs
<< OP_SH_FS
));
557 void cvtwd(FPRegisterID fd
, FPRegisterID fs
)
559 emitInst(0x46200024 | (fd
<< OP_SH_FD
) | (fs
<< OP_SH_FS
));
562 void cvtsd(FPRegisterID fd
, FPRegisterID fs
)
564 emitInst(0x46200020 | (fd
<< OP_SH_FD
) | (fs
<< OP_SH_FS
));
567 void ceqd(FPRegisterID fs
, FPRegisterID ft
)
569 emitInst(0x46200032 | (fs
<< OP_SH_FS
) | (ft
<< OP_SH_FT
));
573 void cngtd(FPRegisterID fs
, FPRegisterID ft
)
575 emitInst(0x4620003f | (fs
<< OP_SH_FS
) | (ft
<< OP_SH_FT
));
579 void cnged(FPRegisterID fs
, FPRegisterID ft
)
581 emitInst(0x4620003d | (fs
<< OP_SH_FS
) | (ft
<< OP_SH_FT
));
585 void cltd(FPRegisterID fs
, FPRegisterID ft
)
587 emitInst(0x4620003c | (fs
<< OP_SH_FS
) | (ft
<< OP_SH_FT
));
591 void cled(FPRegisterID fs
, FPRegisterID ft
)
593 emitInst(0x4620003e | (fs
<< OP_SH_FS
) | (ft
<< OP_SH_FT
));
597 void cueqd(FPRegisterID fs
, FPRegisterID ft
)
599 emitInst(0x46200033 | (fs
<< OP_SH_FS
) | (ft
<< OP_SH_FT
));
603 void coled(FPRegisterID fs
, FPRegisterID ft
)
605 emitInst(0x46200036 | (fs
<< OP_SH_FS
) | (ft
<< OP_SH_FT
));
609 void coltd(FPRegisterID fs
, FPRegisterID ft
)
611 emitInst(0x46200034 | (fs
<< OP_SH_FS
) | (ft
<< OP_SH_FT
));
615 void culed(FPRegisterID fs
, FPRegisterID ft
)
617 emitInst(0x46200037 | (fs
<< OP_SH_FS
) | (ft
<< OP_SH_FT
));
621 void cultd(FPRegisterID fs
, FPRegisterID ft
)
623 emitInst(0x46200035 | (fs
<< OP_SH_FS
) | (ft
<< OP_SH_FT
));
629 AssemblerLabel
labelIgnoringWatchpoints()
631 return m_buffer
.label();
634 AssemblerLabel
labelForWatchpoint()
636 AssemblerLabel result
= m_buffer
.label();
637 if (static_cast<int>(result
.m_offset
) != m_indexOfLastWatchpoint
)
639 m_indexOfLastWatchpoint
= result
.m_offset
;
640 m_indexOfTailOfLastWatchpoint
= result
.m_offset
+ maxJumpReplacementSize();
644 AssemblerLabel
label()
646 AssemblerLabel result
= m_buffer
.label();
647 while (UNLIKELY(static_cast<int>(result
.m_offset
) < m_indexOfTailOfLastWatchpoint
)) {
649 result
= m_buffer
.label();
654 AssemblerLabel
align(int alignment
)
656 while (!m_buffer
.isAligned(alignment
))
662 static void* getRelocatedAddress(void* code
, AssemblerLabel label
)
664 return reinterpret_cast<void*>(reinterpret_cast<char*>(code
) + label
.m_offset
);
667 static int getDifferenceBetweenLabels(AssemblerLabel a
, AssemblerLabel b
)
669 return b
.m_offset
- a
.m_offset
;
672 // Assembler admin methods:
674 size_t codeSize() const
676 return m_buffer
.codeSize();
679 PassRefPtr
<ExecutableMemoryHandle
> executableCopy(VM
& vm
, void* ownerUID
, JITCompilationEffort effort
)
681 RefPtr
<ExecutableMemoryHandle
> result
= m_buffer
.executableCopy(vm
, ownerUID
, effort
);
685 relocateJumps(m_buffer
.data(), result
->start());
686 return result
.release();
689 unsigned debugOffset() { return m_buffer
.debugOffset(); }
691 // Assembly helpers for moving data between fp and registers.
692 void vmov(RegisterID rd1
, RegisterID rd2
, FPRegisterID rn
)
694 #if WTF_MIPS_ISA_REV(2) && WTF_MIPS_FP64
699 mfc1(rd2
, FPRegisterID(rn
+ 1));
703 void vmov(FPRegisterID rd
, RegisterID rn1
, RegisterID rn2
)
705 #if WTF_MIPS_ISA_REV(2) && WTF_MIPS_FP64
710 mtc1(rn2
, FPRegisterID(rd
+ 1));
714 static unsigned getCallReturnOffset(AssemblerLabel call
)
716 // The return address is after a call and a delay slot instruction
717 return call
.m_offset
;
720 // Linking & patching:
722 // 'link' and 'patch' methods are for use on unprotected code - such as the code
723 // within the AssemblerBuffer, and code being patched by the patch buffer. Once
724 // code has been finalized it is (platform support permitting) within a non-
725 // writable region of memory; to modify the code in an execute-only execuable
726 // pool the 'repatch' and 'relink' methods should be used.
728 static size_t linkDirectJump(void* code
, void* to
)
730 MIPSWord
* insn
= reinterpret_cast<MIPSWord
*>(reinterpret_cast<intptr_t>(code
));
732 int32_t slotAddr
= reinterpret_cast<int>(insn
) + 4;
733 int32_t toAddr
= reinterpret_cast<int>(to
);
735 if ((slotAddr
& 0xf0000000) != (toAddr
& 0xf0000000)) {
737 *insn
= 0x3c000000 | (MIPSRegisters::t9
<< OP_SH_RT
) | ((toAddr
>> 16) & 0xffff);
740 *insn
= 0x34000000 | (MIPSRegisters::t9
<< OP_SH_RT
) | (MIPSRegisters::t9
<< OP_SH_RS
) | (toAddr
& 0xffff);
743 *insn
= 0x00000008 | (MIPSRegisters::t9
<< OP_SH_RS
);
745 ops
= 4 * sizeof(MIPSWord
);
748 *insn
= 0x08000000 | ((toAddr
& 0x0fffffff) >> 2);
750 ops
= 2 * sizeof(MIPSWord
);
757 void linkJump(AssemblerLabel from
, AssemblerLabel to
)
760 ASSERT(from
.isSet());
761 MIPSWord
* insn
= reinterpret_cast<MIPSWord
*>(reinterpret_cast<intptr_t>(m_buffer
.data()) + from
.m_offset
);
762 MIPSWord
* toPos
= reinterpret_cast<MIPSWord
*>(reinterpret_cast<intptr_t>(m_buffer
.data()) + to
.m_offset
);
764 ASSERT(!(*(insn
- 1)) && !(*(insn
- 2)) && !(*(insn
- 3)) && !(*(insn
- 5)));
766 linkWithOffset(insn
, toPos
);
769 static void linkJump(void* code
, AssemblerLabel from
, void* to
)
771 ASSERT(from
.isSet());
772 MIPSWord
* insn
= reinterpret_cast<MIPSWord
*>(reinterpret_cast<intptr_t>(code
) + from
.m_offset
);
774 ASSERT(!(*(insn
- 1)) && !(*(insn
- 2)) && !(*(insn
- 3)) && !(*(insn
- 5)));
776 linkWithOffset(insn
, to
);
779 static void linkCall(void* code
, AssemblerLabel from
, void* to
)
781 MIPSWord
* insn
= reinterpret_cast<MIPSWord
*>(reinterpret_cast<intptr_t>(code
) + from
.m_offset
);
782 linkCallInternal(insn
, to
);
785 static void linkPointer(void* code
, AssemblerLabel from
, void* to
)
787 MIPSWord
* insn
= reinterpret_cast<MIPSWord
*>(reinterpret_cast<intptr_t>(code
) + from
.m_offset
);
788 ASSERT((*insn
& 0xffe00000) == 0x3c000000); // lui
789 *insn
= (*insn
& 0xffff0000) | ((reinterpret_cast<intptr_t>(to
) >> 16) & 0xffff);
791 ASSERT((*insn
& 0xfc000000) == 0x34000000); // ori
792 *insn
= (*insn
& 0xffff0000) | (reinterpret_cast<intptr_t>(to
) & 0xffff);
795 static void relinkJump(void* from
, void* to
)
797 MIPSWord
* insn
= reinterpret_cast<MIPSWord
*>(from
);
799 ASSERT(!(*(insn
- 1)) && !(*(insn
- 5)));
801 int flushSize
= linkWithOffset(insn
, to
);
803 cacheFlush(insn
, flushSize
);
806 static void relinkCall(void* from
, void* to
)
809 int size
= linkCallInternal(from
, to
);
810 if (size
== sizeof(MIPSWord
))
811 start
= reinterpret_cast<void*>(reinterpret_cast<intptr_t>(from
) - 2 * sizeof(MIPSWord
));
813 start
= reinterpret_cast<void*>(reinterpret_cast<intptr_t>(from
) - 4 * sizeof(MIPSWord
));
815 cacheFlush(start
, size
);
818 static void repatchInt32(void* from
, int32_t to
)
820 MIPSWord
* insn
= reinterpret_cast<MIPSWord
*>(from
);
821 ASSERT((*insn
& 0xffe00000) == 0x3c000000); // lui
822 *insn
= (*insn
& 0xffff0000) | ((to
>> 16) & 0xffff);
824 ASSERT((*insn
& 0xfc000000) == 0x34000000); // ori
825 *insn
= (*insn
& 0xffff0000) | (to
& 0xffff);
827 cacheFlush(insn
, 2 * sizeof(MIPSWord
));
830 static int32_t readInt32(void* from
)
832 MIPSWord
* insn
= reinterpret_cast<MIPSWord
*>(from
);
833 ASSERT((*insn
& 0xffe00000) == 0x3c000000); // lui
834 int32_t result
= (*insn
& 0x0000ffff) << 16;
836 ASSERT((*insn
& 0xfc000000) == 0x34000000); // ori
837 result
|= *insn
& 0x0000ffff;
841 static void repatchCompact(void* where
, int32_t value
)
843 repatchInt32(where
, value
);
846 static void repatchPointer(void* from
, void* to
)
848 repatchInt32(from
, reinterpret_cast<int32_t>(to
));
851 static void* readPointer(void* from
)
853 return reinterpret_cast<void*>(readInt32(from
));
856 static void* readCallTarget(void* from
)
858 MIPSWord
* insn
= reinterpret_cast<MIPSWord
*>(from
);
860 ASSERT((*insn
& 0xffe00000) == 0x3c000000); // lui
861 int32_t result
= (*insn
& 0x0000ffff) << 16;
863 ASSERT((*insn
& 0xfc000000) == 0x34000000); // ori
864 result
|= *insn
& 0x0000ffff;
865 return reinterpret_cast<void*>(result
);
868 static void cacheFlush(void* code
, size_t size
)
870 #if GCC_VERSION_AT_LEAST(4, 3, 0)
871 #if WTF_MIPS_ISA_REV(2) && !GCC_VERSION_AT_LEAST(4, 4, 3)
873 asm("rdhwr %0, $1" : "=r" (lineSize
));
875 // Modify "start" and "end" to avoid GCC 4.3.0-4.4.2 bug in
876 // mips_expand_synci_loop that may execute synci one more time.
877 // "start" points to the fisrt byte of the cache line.
878 // "end" points to the last byte of the line before the last cache line.
879 // Because size is always a multiple of 4, this is safe to set
880 // "end" to the last byte.
882 intptr_t start
= reinterpret_cast<intptr_t>(code
) & (-lineSize
);
883 intptr_t end
= ((reinterpret_cast<intptr_t>(code
) + size
- 1) & (-lineSize
)) - 1;
884 __builtin___clear_cache(reinterpret_cast<char*>(start
), reinterpret_cast<char*>(end
));
886 intptr_t end
= reinterpret_cast<intptr_t>(code
) + size
;
887 __builtin___clear_cache(reinterpret_cast<char*>(code
), reinterpret_cast<char*>(end
));
890 _flush_cache(reinterpret_cast<char*>(code
), size
, BCACHE
);
894 static ptrdiff_t maxJumpReplacementSize()
896 return sizeof(MIPSWord
) * 4;
899 static void revertJumpToMove(void* instructionStart
, RegisterID rt
, int imm
)
901 MIPSWord
* insn
= static_cast<MIPSWord
*>(instructionStart
);
902 size_t codeSize
= 2 * sizeof(MIPSWord
);
905 *insn
= 0x3c000000 | (rt
<< OP_SH_RT
) | ((imm
>> 16) & 0xffff);
908 *insn
= 0x34000000 | (rt
<< OP_SH_RS
) | (rt
<< OP_SH_RT
) | (imm
& 0xffff);
911 if (*insn
== 0x03200008) {
913 codeSize
+= sizeof(MIPSWord
);
915 cacheFlush(insn
, codeSize
);
918 static void replaceWithJump(void* instructionStart
, void* to
)
920 ASSERT(!(bitwise_cast
<uintptr_t>(instructionStart
) & 3));
921 ASSERT(!(bitwise_cast
<uintptr_t>(to
) & 3));
922 size_t ops
= linkDirectJump(instructionStart
, to
);
923 cacheFlush(instructionStart
, ops
);
926 static void replaceWithLoad(void* instructionStart
)
928 MIPSWord
* insn
= reinterpret_cast<MIPSWord
*>(instructionStart
);
929 ASSERT((*insn
& 0xffe00000) == 0x3c000000); // lui
931 ASSERT((*insn
& 0xfc0007ff) == 0x00000021); // addu
933 *insn
= 0x8c000000 | ((*insn
) & 0x3ffffff); // lw
937 static void replaceWithAddressComputation(void* instructionStart
)
939 MIPSWord
* insn
= reinterpret_cast<MIPSWord
*>(instructionStart
);
940 ASSERT((*insn
& 0xffe00000) == 0x3c000000); // lui
942 ASSERT((*insn
& 0xfc0007ff) == 0x00000021); // addu
944 *insn
= 0x24000000 | ((*insn
) & 0x3ffffff); // addiu
949 /* Update each jump in the buffer of newBase. */
950 void relocateJumps(void* oldBase
, void* newBase
)
953 for (Jumps::Iterator iter
= m_jumps
.begin(); iter
!= m_jumps
.end(); ++iter
) {
954 int pos
= iter
->m_offset
;
955 MIPSWord
* insn
= reinterpret_cast<MIPSWord
*>(reinterpret_cast<intptr_t>(newBase
) + pos
);
957 // Need to make sure we have 5 valid instructions after pos
958 if ((unsigned)pos
>= m_buffer
.codeSize() - 5 * sizeof(MIPSWord
))
961 if ((*insn
& 0xfc000000) == 0x08000000) { // j
962 int offset
= *insn
& 0x03ffffff;
963 int oldInsnAddress
= (int)insn
- (int)newBase
+ (int)oldBase
;
964 int topFourBits
= (oldInsnAddress
+ 4) >> 28;
965 int oldTargetAddress
= (topFourBits
<< 28) | (offset
<< 2);
966 int newTargetAddress
= oldTargetAddress
- (int)oldBase
+ (int)newBase
;
967 int newInsnAddress
= (int)insn
;
968 if (((newInsnAddress
+ 4) >> 28) == (newTargetAddress
>> 28))
969 *insn
= 0x08000000 | ((newTargetAddress
>> 2) & 0x3ffffff);
972 *insn
= 0x3c000000 | (MIPSRegisters::t9
<< OP_SH_RT
) | ((newTargetAddress
>> 16) & 0xffff);
974 *(insn
+ 1) = 0x34000000 | (MIPSRegisters::t9
<< OP_SH_RT
) | (MIPSRegisters::t9
<< OP_SH_RS
) | (newTargetAddress
& 0xffff);
976 *(insn
+ 2) = 0x00000008 | (MIPSRegisters::t9
<< OP_SH_RS
);
978 } else if ((*insn
& 0xffe00000) == 0x3c000000) { // lui
979 int high
= (*insn
& 0xffff) << 16;
980 int low
= *(insn
+ 1) & 0xffff;
981 int oldTargetAddress
= high
| low
;
982 int newTargetAddress
= oldTargetAddress
- (int)oldBase
+ (int)newBase
;
984 *insn
= 0x3c000000 | (MIPSRegisters::t9
<< OP_SH_RT
) | ((newTargetAddress
>> 16) & 0xffff);
986 *(insn
+ 1) = 0x34000000 | (MIPSRegisters::t9
<< OP_SH_RT
) | (MIPSRegisters::t9
<< OP_SH_RS
) | (newTargetAddress
& 0xffff);
991 static int linkWithOffset(MIPSWord
* insn
, void* to
)
993 ASSERT((*insn
& 0xfc000000) == 0x10000000 // beq
994 || (*insn
& 0xfc000000) == 0x14000000 // bne
995 || (*insn
& 0xffff0000) == 0x45010000 // bc1t
996 || (*insn
& 0xffff0000) == 0x45000000); // bc1f
997 intptr_t diff
= (reinterpret_cast<intptr_t>(to
) - reinterpret_cast<intptr_t>(insn
) - 4) >> 2;
999 if (diff
< -32768 || diff
> 32767 || *(insn
+ 2) != 0x10000003) {
1001 Convert the sequence:
1010 to the new sequence if possible:
1019 OR to the new sequence:
1022 lui $25, target >> 16
1023 ori $25, $25, target & 0xffff
1028 Note: beq/bne/bc1t/bc1f are converted to bne/beq/bc1f/bc1t.
1031 if (*(insn
+ 2) == 0x10000003) {
1032 if ((*insn
& 0xfc000000) == 0x10000000) // beq
1033 *insn
= (*insn
& 0x03ff0000) | 0x14000005; // bne
1034 else if ((*insn
& 0xfc000000) == 0x14000000) // bne
1035 *insn
= (*insn
& 0x03ff0000) | 0x10000005; // beq
1036 else if ((*insn
& 0xffff0000) == 0x45010000) // bc1t
1037 *insn
= 0x45000005; // bc1f
1038 else if ((*insn
& 0xffff0000) == 0x45000000) // bc1f
1039 *insn
= 0x45010005; // bc1t
1045 if ((reinterpret_cast<intptr_t>(insn
) + 4) >> 28
1046 == reinterpret_cast<intptr_t>(to
) >> 28) {
1047 *insn
= 0x08000000 | ((reinterpret_cast<intptr_t>(to
) >> 2) & 0x3ffffff);
1049 return 4 * sizeof(MIPSWord
);
1052 intptr_t newTargetAddress
= reinterpret_cast<intptr_t>(to
);
1054 *insn
= 0x3c000000 | (MIPSRegisters::t9
<< OP_SH_RT
) | ((newTargetAddress
>> 16) & 0xffff);
1056 *(insn
+ 1) = 0x34000000 | (MIPSRegisters::t9
<< OP_SH_RT
) | (MIPSRegisters::t9
<< OP_SH_RS
) | (newTargetAddress
& 0xffff);
1058 *(insn
+ 2) = 0x00000008 | (MIPSRegisters::t9
<< OP_SH_RS
);
1059 return 5 * sizeof(MIPSWord
);
1062 *insn
= (*insn
& 0xffff0000) | (diff
& 0xffff);
1063 return sizeof(MIPSWord
);
1066 static int linkCallInternal(void* from
, void* to
)
1068 MIPSWord
* insn
= reinterpret_cast<MIPSWord
*>(from
);
1071 if ((*(insn
+ 2) & 0xfc000000) == 0x0c000000) { // jal
1072 if ((reinterpret_cast<intptr_t>(from
) - 4) >> 28
1073 == reinterpret_cast<intptr_t>(to
) >> 28) {
1074 *(insn
+ 2) = 0x0c000000 | ((reinterpret_cast<intptr_t>(to
) >> 2) & 0x3ffffff);
1075 return sizeof(MIPSWord
);
1078 /* lui $25, (to >> 16) & 0xffff */
1079 *insn
= 0x3c000000 | (MIPSRegisters::t9
<< OP_SH_RT
) | ((reinterpret_cast<intptr_t>(to
) >> 16) & 0xffff);
1080 /* ori $25, $25, to & 0xffff */
1081 *(insn
+ 1) = 0x34000000 | (MIPSRegisters::t9
<< OP_SH_RT
) | (MIPSRegisters::t9
<< OP_SH_RS
) | (reinterpret_cast<intptr_t>(to
) & 0xffff);
1083 *(insn
+ 2) = 0x0000f809 | (MIPSRegisters::t9
<< OP_SH_RS
);
1084 return 3 * sizeof(MIPSWord
);
1087 ASSERT((*insn
& 0xffe00000) == 0x3c000000); // lui
1088 ASSERT((*(insn
+ 1) & 0xfc000000) == 0x34000000); // ori
1091 *insn
= (*insn
& 0xffff0000) | ((reinterpret_cast<intptr_t>(to
) >> 16) & 0xffff);
1093 *(insn
+ 1) = (*(insn
+ 1) & 0xffff0000) | (reinterpret_cast<intptr_t>(to
) & 0xffff);
1094 return 2 * sizeof(MIPSWord
);
1097 AssemblerBuffer m_buffer
;
1099 int m_indexOfLastWatchpoint
;
1100 int m_indexOfTailOfLastWatchpoint
;
1105 #endif // ENABLE(ASSEMBLER) && CPU(MIPS)
1107 #endif // MIPSAssembler_h