1/*
2 * Copyright (C) 2009 Apple Inc. All rights reserved.
3 * Copyright (C) 2009 University of Szeged
4 * All rights reserved.
5 * Copyright (C) 2010 MIPS Technologies, Inc. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
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.
15 *
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.
27 */
28
29#ifndef MIPSAssembler_h
30#define MIPSAssembler_h
31
32#if ENABLE(ASSEMBLER) && CPU(MIPS)
33
34#include "AssemblerBuffer.h"
35#include "JITCompilationEffort.h"
36#include <wtf/Assertions.h>
37#include <wtf/SegmentedVector.h>
38
39namespace JSC {
40
41typedef uint32_t MIPSWord;
42
43namespace MIPSRegisters {
44typedef enum {
45    r0 = 0,
46    r1,
47    r2,
48    r3,
49    r4,
50    r5,
51    r6,
52    r7,
53    r8,
54    r9,
55    r10,
56    r11,
57    r12,
58    r13,
59    r14,
60    r15,
61    r16,
62    r17,
63    r18,
64    r19,
65    r20,
66    r21,
67    r22,
68    r23,
69    r24,
70    r25,
71    r26,
72    r27,
73    r28,
74    r29,
75    r30,
76    r31,
77    zero = r0,
78    at = r1,
79    v0 = r2,
80    v1 = r3,
81    a0 = r4,
82    a1 = r5,
83    a2 = r6,
84    a3 = r7,
85    t0 = r8,
86    t1 = r9,
87    t2 = r10,
88    t3 = r11,
89    t4 = r12,
90    t5 = r13,
91    t6 = r14,
92    t7 = r15,
93    s0 = r16,
94    s1 = r17,
95    s2 = r18,
96    s3 = r19,
97    s4 = r20,
98    s5 = r21,
99    s6 = r22,
100    s7 = r23,
101    t8 = r24,
102    t9 = r25,
103    k0 = r26,
104    k1 = r27,
105    gp = r28,
106    sp = r29,
107    fp = r30,
108    ra = r31
109} RegisterID;
110
111typedef enum {
112    f0,
113    f1,
114    f2,
115    f3,
116    f4,
117    f5,
118    f6,
119    f7,
120    f8,
121    f9,
122    f10,
123    f11,
124    f12,
125    f13,
126    f14,
127    f15,
128    f16,
129    f17,
130    f18,
131    f19,
132    f20,
133    f21,
134    f22,
135    f23,
136    f24,
137    f25,
138    f26,
139    f27,
140    f28,
141    f29,
142    f30,
143    f31
144} FPRegisterID;
145
146} // namespace MIPSRegisters
147
148class MIPSAssembler {
149public:
150    typedef MIPSRegisters::RegisterID RegisterID;
151    typedef MIPSRegisters::FPRegisterID FPRegisterID;
152    typedef SegmentedVector<AssemblerLabel, 64> Jumps;
153
154    static RegisterID firstRegister() { return MIPSRegisters::r0; }
155    static RegisterID lastRegister() { return MIPSRegisters::r31; }
156
157    static FPRegisterID firstFPRegister() { return MIPSRegisters::f0; }
158    static FPRegisterID lastFPRegister() { return MIPSRegisters::f31; }
159
160    MIPSAssembler()
161        : m_indexOfLastWatchpoint(INT_MIN)
162        , m_indexOfTailOfLastWatchpoint(INT_MIN)
163    {
164    }
165
166    AssemblerBuffer& buffer() { return m_buffer; }
167
168    // MIPS instruction opcode field position
169    enum {
170        OP_SH_RD = 11,
171        OP_SH_RT = 16,
172        OP_SH_RS = 21,
173        OP_SH_SHAMT = 6,
174        OP_SH_CODE = 16,
175        OP_SH_FD = 6,
176        OP_SH_FS = 11,
177        OP_SH_FT = 16
178    };
179
180    void emitInst(MIPSWord op)
181    {
182        void* oldBase = m_buffer.data();
183
184        m_buffer.putInt(op);
185
186        void* newBase = m_buffer.data();
187        if (oldBase != newBase)
188            relocateJumps(oldBase, newBase);
189    }
190
191    void nop()
192    {
193        emitInst(0x00000000);
194    }
195
196    void sync()
197    {
198        emitInst(0x0000000f);
199    }
200
201    /* Need to insert one load data delay nop for mips1.  */
202    void loadDelayNop()
203    {
204#if WTF_MIPS_ISA(1)
205        nop();
206#endif
207    }
208
209    /* Need to insert one coprocessor access delay nop for mips1.  */
210    void copDelayNop()
211    {
212#if WTF_MIPS_ISA(1)
213        nop();
214#endif
215    }
216
217    void move(RegisterID rd, RegisterID rs)
218    {
219        /* addu */
220        emitInst(0x00000021 | (rd << OP_SH_RD) | (rs << OP_SH_RS));
221    }
222
223    /* Set an immediate value to a register.  This may generate 1 or 2
224       instructions.  */
225    void li(RegisterID dest, int imm)
226    {
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);
231        else {
232            lui(dest, imm >> 16);
233            if (imm & 0xffff)
234                ori(dest, dest, imm);
235        }
236    }
237
238    void lui(RegisterID rt, int imm)
239    {
240        emitInst(0x3c000000 | (rt << OP_SH_RT) | (imm & 0xffff));
241    }
242
243    void addiu(RegisterID rt, RegisterID rs, int imm)
244    {
245        emitInst(0x24000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) | (imm & 0xffff));
246    }
247
248    void addu(RegisterID rd, RegisterID rs, RegisterID rt)
249    {
250        emitInst(0x00000021 | (rd << OP_SH_RD) | (rs << OP_SH_RS) | (rt << OP_SH_RT));
251    }
252
253    void subu(RegisterID rd, RegisterID rs, RegisterID rt)
254    {
255        emitInst(0x00000023 | (rd << OP_SH_RD) | (rs << OP_SH_RS) | (rt << OP_SH_RT));
256    }
257
258    void mult(RegisterID rs, RegisterID rt)
259    {
260        emitInst(0x00000018 | (rs << OP_SH_RS) | (rt << OP_SH_RT));
261    }
262
263    void div(RegisterID rs, RegisterID rt)
264    {
265        emitInst(0x0000001a | (rs << OP_SH_RS) | (rt << OP_SH_RT));
266    }
267
268    void mfhi(RegisterID rd)
269    {
270        emitInst(0x00000010 | (rd << OP_SH_RD));
271    }
272
273    void mflo(RegisterID rd)
274    {
275        emitInst(0x00000012 | (rd << OP_SH_RD));
276    }
277
278    void mul(RegisterID rd, RegisterID rs, RegisterID rt)
279    {
280#if WTF_MIPS_ISA_AT_LEAST(32)
281        emitInst(0x70000002 | (rd << OP_SH_RD) | (rs << OP_SH_RS) | (rt << OP_SH_RT));
282#else
283        mult(rs, rt);
284        mflo(rd);
285#endif
286    }
287
288    void andInsn(RegisterID rd, RegisterID rs, RegisterID rt)
289    {
290        emitInst(0x00000024 | (rd << OP_SH_RD) | (rs << OP_SH_RS) | (rt << OP_SH_RT));
291    }
292
293    void andi(RegisterID rt, RegisterID rs, int imm)
294    {
295        emitInst(0x30000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) | (imm & 0xffff));
296    }
297
298    void nor(RegisterID rd, RegisterID rs, RegisterID rt)
299    {
300        emitInst(0x00000027 | (rd << OP_SH_RD) | (rs << OP_SH_RS) | (rt << OP_SH_RT));
301    }
302
303    void orInsn(RegisterID rd, RegisterID rs, RegisterID rt)
304    {
305        emitInst(0x00000025 | (rd << OP_SH_RD) | (rs << OP_SH_RS) | (rt << OP_SH_RT));
306    }
307
308    void ori(RegisterID rt, RegisterID rs, int imm)
309    {
310        emitInst(0x34000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) | (imm & 0xffff));
311    }
312
313    void xorInsn(RegisterID rd, RegisterID rs, RegisterID rt)
314    {
315        emitInst(0x00000026 | (rd << OP_SH_RD) | (rs << OP_SH_RS) | (rt << OP_SH_RT));
316    }
317
318    void xori(RegisterID rt, RegisterID rs, int imm)
319    {
320        emitInst(0x38000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) | (imm & 0xffff));
321    }
322
323    void slt(RegisterID rd, RegisterID rs, RegisterID rt)
324    {
325        emitInst(0x0000002a | (rd << OP_SH_RD) | (rs << OP_SH_RS) | (rt << OP_SH_RT));
326    }
327
328    void sltu(RegisterID rd, RegisterID rs, RegisterID rt)
329    {
330        emitInst(0x0000002b | (rd << OP_SH_RD) | (rs << OP_SH_RS) | (rt << OP_SH_RT));
331    }
332
333    void sltiu(RegisterID rt, RegisterID rs, int imm)
334    {
335        emitInst(0x2c000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) | (imm & 0xffff));
336    }
337
338    void sll(RegisterID rd, RegisterID rt, int shamt)
339    {
340        emitInst(0x00000000 | (rd << OP_SH_RD) | (rt << OP_SH_RT) | ((shamt & 0x1f) << OP_SH_SHAMT));
341    }
342
343    void sllv(RegisterID rd, RegisterID rt, RegisterID rs)
344    {
345        emitInst(0x00000004 | (rd << OP_SH_RD) | (rt << OP_SH_RT) | (rs << OP_SH_RS));
346    }
347
348    void sra(RegisterID rd, RegisterID rt, int shamt)
349    {
350        emitInst(0x00000003 | (rd << OP_SH_RD) | (rt << OP_SH_RT) | ((shamt & 0x1f) << OP_SH_SHAMT));
351    }
352
353    void srav(RegisterID rd, RegisterID rt, RegisterID rs)
354    {
355        emitInst(0x00000007 | (rd << OP_SH_RD) | (rt << OP_SH_RT) | (rs << OP_SH_RS));
356    }
357
358    void srl(RegisterID rd, RegisterID rt, int shamt)
359    {
360        emitInst(0x00000002 | (rd << OP_SH_RD) | (rt << OP_SH_RT) | ((shamt & 0x1f) << OP_SH_SHAMT));
361    }
362
363    void srlv(RegisterID rd, RegisterID rt, RegisterID rs)
364    {
365        emitInst(0x00000006 | (rd << OP_SH_RD) | (rt << OP_SH_RT) | (rs << OP_SH_RS));
366    }
367
368    void lb(RegisterID rt, RegisterID rs, int offset)
369    {
370        emitInst(0x80000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) | (offset & 0xffff));
371        loadDelayNop();
372    }
373
374    void lbu(RegisterID rt, RegisterID rs, int offset)
375    {
376        emitInst(0x90000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) | (offset & 0xffff));
377        loadDelayNop();
378    }
379
380    void lw(RegisterID rt, RegisterID rs, int offset)
381    {
382        emitInst(0x8c000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) | (offset & 0xffff));
383        loadDelayNop();
384    }
385
386    void lwl(RegisterID rt, RegisterID rs, int offset)
387    {
388        emitInst(0x88000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) | (offset & 0xffff));
389        loadDelayNop();
390    }
391
392    void lwr(RegisterID rt, RegisterID rs, int offset)
393    {
394        emitInst(0x98000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) | (offset & 0xffff));
395        loadDelayNop();
396    }
397
398    void lh(RegisterID rt, RegisterID rs, int offset)
399    {
400        emitInst(0x84000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) | (offset & 0xffff));
401        loadDelayNop();
402    }
403
404    void lhu(RegisterID rt, RegisterID rs, int offset)
405    {
406        emitInst(0x94000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) | (offset & 0xffff));
407        loadDelayNop();
408    }
409
410    void sb(RegisterID rt, RegisterID rs, int offset)
411    {
412        emitInst(0xa0000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) | (offset & 0xffff));
413    }
414
415    void sh(RegisterID rt, RegisterID rs, int offset)
416    {
417        emitInst(0xa4000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) | (offset & 0xffff));
418    }
419
420    void sw(RegisterID rt, RegisterID rs, int offset)
421    {
422        emitInst(0xac000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) | (offset & 0xffff));
423    }
424
425    void jr(RegisterID rs)
426    {
427        emitInst(0x00000008 | (rs << OP_SH_RS));
428    }
429
430    void jalr(RegisterID rs)
431    {
432        emitInst(0x0000f809 | (rs << OP_SH_RS));
433    }
434
435    void jal()
436    {
437        emitInst(0x0c000000);
438    }
439
440    void bkpt()
441    {
442        int value = 512; /* BRK_BUG */
443        emitInst(0x0000000d | ((value & 0x3ff) << OP_SH_CODE));
444    }
445
446    void bgez(RegisterID rs, int imm)
447    {
448        emitInst(0x04010000 | (rs << OP_SH_RS) | (imm & 0xffff));
449    }
450
451    void bltz(RegisterID rs, int imm)
452    {
453        emitInst(0x04000000 | (rs << OP_SH_RS) | (imm & 0xffff));
454    }
455
456    void beq(RegisterID rs, RegisterID rt, int imm)
457    {
458        emitInst(0x10000000 | (rs << OP_SH_RS) | (rt << OP_SH_RT) | (imm & 0xffff));
459    }
460
461    void bne(RegisterID rs, RegisterID rt, int imm)
462    {
463        emitInst(0x14000000 | (rs << OP_SH_RS) | (rt << OP_SH_RT) | (imm & 0xffff));
464    }
465
466    void bc1t()
467    {
468        emitInst(0x45010000);
469    }
470
471    void bc1f()
472    {
473        emitInst(0x45000000);
474    }
475
476    void appendJump()
477    {
478        m_jumps.append(m_buffer.label());
479    }
480
481    void addd(FPRegisterID fd, FPRegisterID fs, FPRegisterID ft)
482    {
483        emitInst(0x46200000 | (fd << OP_SH_FD) | (fs << OP_SH_FS) | (ft << OP_SH_FT));
484    }
485
486    void subd(FPRegisterID fd, FPRegisterID fs, FPRegisterID ft)
487    {
488        emitInst(0x46200001 | (fd << OP_SH_FD) | (fs << OP_SH_FS) | (ft << OP_SH_FT));
489    }
490
491    void muld(FPRegisterID fd, FPRegisterID fs, FPRegisterID ft)
492    {
493        emitInst(0x46200002 | (fd << OP_SH_FD) | (fs << OP_SH_FS) | (ft << OP_SH_FT));
494    }
495
496    void divd(FPRegisterID fd, FPRegisterID fs, FPRegisterID ft)
497    {
498        emitInst(0x46200003 | (fd << OP_SH_FD) | (fs << OP_SH_FS) | (ft << OP_SH_FT));
499    }
500
501    void lwc1(FPRegisterID ft, RegisterID rs, int offset)
502    {
503        emitInst(0xc4000000 | (ft << OP_SH_FT) | (rs << OP_SH_RS) | (offset & 0xffff));
504        copDelayNop();
505    }
506
507    void ldc1(FPRegisterID ft, RegisterID rs, int offset)
508    {
509        emitInst(0xd4000000 | (ft << OP_SH_FT) | (rs << OP_SH_RS) | (offset & 0xffff));
510    }
511
512    void swc1(FPRegisterID ft, RegisterID rs, int offset)
513    {
514        emitInst(0xe4000000 | (ft << OP_SH_FT) | (rs << OP_SH_RS) | (offset & 0xffff));
515    }
516
517    void sdc1(FPRegisterID ft, RegisterID rs, int offset)
518    {
519        emitInst(0xf4000000 | (ft << OP_SH_FT) | (rs << OP_SH_RS) | (offset & 0xffff));
520    }
521
522    void mtc1(RegisterID rt, FPRegisterID fs)
523    {
524        emitInst(0x44800000 | (fs << OP_SH_FS) | (rt << OP_SH_RT));
525        copDelayNop();
526    }
527
528    void mthc1(RegisterID rt, FPRegisterID fs)
529    {
530        emitInst(0x44e00000 | (fs << OP_SH_FS) | (rt << OP_SH_RT));
531        copDelayNop();
532    }
533
534    void mfc1(RegisterID rt, FPRegisterID fs)
535    {
536        emitInst(0x44000000 | (fs << OP_SH_FS) | (rt << OP_SH_RT));
537        copDelayNop();
538    }
539
540    void sqrtd(FPRegisterID fd, FPRegisterID fs)
541    {
542        emitInst(0x46200004 | (fd << OP_SH_FD) | (fs << OP_SH_FS));
543    }
544
545    void movd(FPRegisterID fd, FPRegisterID fs)
546    {
547        emitInst(0x46200006 | (fd << OP_SH_FD) | (fs << OP_SH_FS));
548    }
549
550    void negd(FPRegisterID fd, FPRegisterID fs)
551    {
552        emitInst(0x46200007 | (fd << OP_SH_FD) | (fs << OP_SH_FS));
553    }
554
555    void truncwd(FPRegisterID fd, FPRegisterID fs)
556    {
557        emitInst(0x4620000d | (fd << OP_SH_FD) | (fs << OP_SH_FS));
558    }
559
560    void cvtdw(FPRegisterID fd, FPRegisterID fs)
561    {
562        emitInst(0x46800021 | (fd << OP_SH_FD) | (fs << OP_SH_FS));
563    }
564
565    void cvtds(FPRegisterID fd, FPRegisterID fs)
566    {
567        emitInst(0x46000021 | (fd << OP_SH_FD) | (fs << OP_SH_FS));
568    }
569
570    void cvtwd(FPRegisterID fd, FPRegisterID fs)
571    {
572        emitInst(0x46200024 | (fd << OP_SH_FD) | (fs << OP_SH_FS));
573    }
574
575    void cvtsd(FPRegisterID fd, FPRegisterID fs)
576    {
577        emitInst(0x46200020 | (fd << OP_SH_FD) | (fs << OP_SH_FS));
578    }
579
580    void ceqd(FPRegisterID fs, FPRegisterID ft)
581    {
582        emitInst(0x46200032 | (fs << OP_SH_FS) | (ft << OP_SH_FT));
583        copDelayNop();
584    }
585
586    void cngtd(FPRegisterID fs, FPRegisterID ft)
587    {
588        emitInst(0x4620003f | (fs << OP_SH_FS) | (ft << OP_SH_FT));
589        copDelayNop();
590    }
591
592    void cnged(FPRegisterID fs, FPRegisterID ft)
593    {
594        emitInst(0x4620003d | (fs << OP_SH_FS) | (ft << OP_SH_FT));
595        copDelayNop();
596    }
597
598    void cltd(FPRegisterID fs, FPRegisterID ft)
599    {
600        emitInst(0x4620003c | (fs << OP_SH_FS) | (ft << OP_SH_FT));
601        copDelayNop();
602    }
603
604    void cled(FPRegisterID fs, FPRegisterID ft)
605    {
606        emitInst(0x4620003e | (fs << OP_SH_FS) | (ft << OP_SH_FT));
607        copDelayNop();
608    }
609
610    void cueqd(FPRegisterID fs, FPRegisterID ft)
611    {
612        emitInst(0x46200033 | (fs << OP_SH_FS) | (ft << OP_SH_FT));
613        copDelayNop();
614    }
615
616    void coled(FPRegisterID fs, FPRegisterID ft)
617    {
618        emitInst(0x46200036 | (fs << OP_SH_FS) | (ft << OP_SH_FT));
619        copDelayNop();
620    }
621
622    void coltd(FPRegisterID fs, FPRegisterID ft)
623    {
624        emitInst(0x46200034 | (fs << OP_SH_FS) | (ft << OP_SH_FT));
625        copDelayNop();
626    }
627
628    void culed(FPRegisterID fs, FPRegisterID ft)
629    {
630        emitInst(0x46200037 | (fs << OP_SH_FS) | (ft << OP_SH_FT));
631        copDelayNop();
632    }
633
634    void cultd(FPRegisterID fs, FPRegisterID ft)
635    {
636        emitInst(0x46200035 | (fs << OP_SH_FS) | (ft << OP_SH_FT));
637        copDelayNop();
638    }
639
640    // General helpers
641
642    AssemblerLabel labelIgnoringWatchpoints()
643    {
644        return m_buffer.label();
645    }
646
647    AssemblerLabel labelForWatchpoint()
648    {
649        AssemblerLabel result = m_buffer.label();
650        if (static_cast<int>(result.m_offset) != m_indexOfLastWatchpoint)
651            result = label();
652        m_indexOfLastWatchpoint = result.m_offset;
653        m_indexOfTailOfLastWatchpoint = result.m_offset + maxJumpReplacementSize();
654        return result;
655    }
656
657    AssemblerLabel label()
658    {
659        AssemblerLabel result = m_buffer.label();
660        while (UNLIKELY(static_cast<int>(result.m_offset) < m_indexOfTailOfLastWatchpoint)) {
661            nop();
662            result = m_buffer.label();
663        }
664        return result;
665    }
666
667    AssemblerLabel align(int alignment)
668    {
669        while (!m_buffer.isAligned(alignment))
670            bkpt();
671
672        return label();
673    }
674
675    static void* getRelocatedAddress(void* code, AssemblerLabel label)
676    {
677        return reinterpret_cast<void*>(reinterpret_cast<char*>(code) + label.m_offset);
678    }
679
680    static int getDifferenceBetweenLabels(AssemblerLabel a, AssemblerLabel b)
681    {
682        return b.m_offset - a.m_offset;
683    }
684
685    // Assembler admin methods:
686
687    size_t codeSize() const
688    {
689        return m_buffer.codeSize();
690    }
691
692    unsigned debugOffset() { return m_buffer.debugOffset(); }
693
694    // Assembly helpers for moving data between fp and registers.
695    void vmov(RegisterID rd1, RegisterID rd2, FPRegisterID rn)
696    {
697#if WTF_MIPS_ISA_REV(2) && WTF_MIPS_FP64
698        mfc1(rd1, rn);
699        mfhc1(rd2, rn);
700#else
701        mfc1(rd1, rn);
702        mfc1(rd2, FPRegisterID(rn + 1));
703#endif
704    }
705
706    void vmov(FPRegisterID rd, RegisterID rn1, RegisterID rn2)
707    {
708#if WTF_MIPS_ISA_REV(2) && WTF_MIPS_FP64
709        mtc1(rn1, rd);
710        mthc1(rn2, rd);
711#else
712        mtc1(rn1, rd);
713        mtc1(rn2, FPRegisterID(rd + 1));
714#endif
715    }
716
717    static unsigned getCallReturnOffset(AssemblerLabel call)
718    {
719        // The return address is after a call and a delay slot instruction
720        return call.m_offset;
721    }
722
723    // Linking & patching:
724    //
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.
730
731    static size_t linkDirectJump(void* code, void* to)
732    {
733        MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(code));
734        size_t ops = 0;
735        int32_t slotAddr = reinterpret_cast<int>(insn) + 4;
736        int32_t toAddr = reinterpret_cast<int>(to);
737
738        if ((slotAddr & 0xf0000000) != (toAddr & 0xf0000000)) {
739            // lui
740            *insn = 0x3c000000 | (MIPSRegisters::t9 << OP_SH_RT) | ((toAddr >> 16) & 0xffff);
741            ++insn;
742            // ori
743            *insn = 0x34000000 | (MIPSRegisters::t9 << OP_SH_RT) | (MIPSRegisters::t9 << OP_SH_RS) | (toAddr & 0xffff);
744            ++insn;
745            // jr
746            *insn = 0x00000008 | (MIPSRegisters::t9 << OP_SH_RS);
747            ++insn;
748            ops = 4 * sizeof(MIPSWord);
749        } else {
750            // j
751            *insn = 0x08000000 | ((toAddr & 0x0fffffff) >> 2);
752            ++insn;
753            ops = 2 * sizeof(MIPSWord);
754        }
755        // nop
756        *insn = 0x00000000;
757        return ops;
758    }
759
760    void linkJump(AssemblerLabel from, AssemblerLabel to)
761    {
762        ASSERT(to.isSet());
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);
766
767        ASSERT(!(*(insn - 1)) && !(*(insn - 2)) && !(*(insn - 3)) && !(*(insn - 5)));
768        insn = insn - 6;
769        linkWithOffset(insn, toPos);
770    }
771
772    static void linkJump(void* code, AssemblerLabel from, void* to)
773    {
774        ASSERT(from.isSet());
775        MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(code) + from.m_offset);
776
777        ASSERT(!(*(insn - 1)) && !(*(insn - 2)) && !(*(insn - 3)) && !(*(insn - 5)));
778        insn = insn - 6;
779        linkWithOffset(insn, to);
780    }
781
782    static void linkCall(void* code, AssemblerLabel from, void* to)
783    {
784        MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(code) + from.m_offset);
785        linkCallInternal(insn, to);
786    }
787
788    static void linkPointer(void* code, AssemblerLabel from, void* to)
789    {
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);
793        insn++;
794        ASSERT((*insn & 0xfc000000) == 0x34000000); // ori
795        *insn = (*insn & 0xffff0000) | (reinterpret_cast<intptr_t>(to) & 0xffff);
796    }
797
798    static void relinkJump(void* from, void* to)
799    {
800        MIPSWord* insn = reinterpret_cast<MIPSWord*>(from);
801
802        ASSERT(!(*(insn - 1)) && !(*(insn - 5)));
803        insn = insn - 6;
804        int flushSize = linkWithOffset(insn, to);
805
806        cacheFlush(insn, flushSize);
807    }
808
809    static void relinkCall(void* from, void* to)
810    {
811        void* start;
812        int size = linkCallInternal(from, to);
813        if (size == sizeof(MIPSWord))
814            start = reinterpret_cast<void*>(reinterpret_cast<intptr_t>(from) - 2 * sizeof(MIPSWord));
815        else
816            start = reinterpret_cast<void*>(reinterpret_cast<intptr_t>(from) - 4 * sizeof(MIPSWord));
817
818        cacheFlush(start, size);
819    }
820
821    static void repatchInt32(void* from, int32_t to)
822    {
823        MIPSWord* insn = reinterpret_cast<MIPSWord*>(from);
824        ASSERT((*insn & 0xffe00000) == 0x3c000000); // lui
825        *insn = (*insn & 0xffff0000) | ((to >> 16) & 0xffff);
826        insn++;
827        ASSERT((*insn & 0xfc000000) == 0x34000000); // ori
828        *insn = (*insn & 0xffff0000) | (to & 0xffff);
829        insn--;
830        cacheFlush(insn, 2 * sizeof(MIPSWord));
831    }
832
833    static int32_t readInt32(void* from)
834    {
835        MIPSWord* insn = reinterpret_cast<MIPSWord*>(from);
836        ASSERT((*insn & 0xffe00000) == 0x3c000000); // lui
837        int32_t result = (*insn & 0x0000ffff) << 16;
838        insn++;
839        ASSERT((*insn & 0xfc000000) == 0x34000000); // ori
840        result |= *insn & 0x0000ffff;
841        return result;
842    }
843
844    static void repatchCompact(void* where, int32_t value)
845    {
846        repatchInt32(where, value);
847    }
848
849    static void repatchPointer(void* from, void* to)
850    {
851        repatchInt32(from, reinterpret_cast<int32_t>(to));
852    }
853
854    static void* readPointer(void* from)
855    {
856        return reinterpret_cast<void*>(readInt32(from));
857    }
858
859    static void* readCallTarget(void* from)
860    {
861        MIPSWord* insn = reinterpret_cast<MIPSWord*>(from);
862        insn -= 4;
863        ASSERT((*insn & 0xffe00000) == 0x3c000000); // lui
864        int32_t result = (*insn & 0x0000ffff) << 16;
865        insn++;
866        ASSERT((*insn & 0xfc000000) == 0x34000000); // ori
867        result |= *insn & 0x0000ffff;
868        return reinterpret_cast<void*>(result);
869    }
870
871    static void cacheFlush(void* code, size_t size)
872    {
873        intptr_t end = reinterpret_cast<intptr_t>(code) + size;
874        __builtin___clear_cache(reinterpret_cast<char*>(code), reinterpret_cast<char*>(end));
875    }
876
877    static ptrdiff_t maxJumpReplacementSize()
878    {
879        return sizeof(MIPSWord) * 4;
880    }
881
882    static void revertJumpToMove(void* instructionStart, RegisterID rt, int imm)
883    {
884        MIPSWord* insn = static_cast<MIPSWord*>(instructionStart);
885        size_t codeSize = 2 * sizeof(MIPSWord);
886
887        // lui
888        *insn = 0x3c000000 | (rt << OP_SH_RT) | ((imm >> 16) & 0xffff);
889        ++insn;
890        // ori
891        *insn = 0x34000000 | (rt << OP_SH_RS) | (rt << OP_SH_RT) | (imm & 0xffff);
892        ++insn;
893        // if jr $t9
894        if (*insn == 0x03200008) {
895            *insn = 0x00000000;
896            codeSize += sizeof(MIPSWord);
897        }
898        cacheFlush(insn, codeSize);
899    }
900
901    static void replaceWithJump(void* instructionStart, void* to)
902    {
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);
907    }
908
909    static void replaceWithLoad(void* instructionStart)
910    {
911        MIPSWord* insn = reinterpret_cast<MIPSWord*>(instructionStart);
912        ASSERT((*insn & 0xffe00000) == 0x3c000000); // lui
913        insn++;
914        ASSERT((*insn & 0xfc0007ff) == 0x00000021); // addu
915        insn++;
916        *insn = 0x8c000000 | ((*insn) & 0x3ffffff); // lw
917        cacheFlush(insn, 4);
918    }
919
920    static void replaceWithAddressComputation(void* instructionStart)
921    {
922        MIPSWord* insn = reinterpret_cast<MIPSWord*>(instructionStart);
923        ASSERT((*insn & 0xffe00000) == 0x3c000000); // lui
924        insn++;
925        ASSERT((*insn & 0xfc0007ff) == 0x00000021); // addu
926        insn++;
927        *insn = 0x24000000 | ((*insn) & 0x3ffffff); // addiu
928        cacheFlush(insn, 4);
929    }
930
931    /* Update each jump in the buffer of newBase.  */
932    void relocateJumps(void* oldBase, void* newBase)
933    {
934        // Check each jump
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);
938            insn = insn + 2;
939            // Need to make sure we have 5 valid instructions after pos
940            if ((unsigned)pos >= m_buffer.codeSize() - 5 * sizeof(MIPSWord))
941                continue;
942
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);
952                else {
953                    /* lui */
954                    *insn = 0x3c000000 | (MIPSRegisters::t9 << OP_SH_RT) | ((newTargetAddress >> 16) & 0xffff);
955                    /* ori */
956                    *(insn + 1) = 0x34000000 | (MIPSRegisters::t9 << OP_SH_RT) | (MIPSRegisters::t9 << OP_SH_RS) | (newTargetAddress & 0xffff);
957                    /* jr */
958                    *(insn + 2) = 0x00000008 | (MIPSRegisters::t9 << OP_SH_RS);
959                }
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;
965                /* lui */
966                *insn = 0x3c000000 | (MIPSRegisters::t9 << OP_SH_RT) | ((newTargetAddress >> 16) & 0xffff);
967                /* ori */
968                *(insn + 1) = 0x34000000 | (MIPSRegisters::t9 << OP_SH_RT) | (MIPSRegisters::t9 << OP_SH_RS) | (newTargetAddress & 0xffff);
969            }
970        }
971    }
972
973private:
974    static int linkWithOffset(MIPSWord* insn, void* to)
975    {
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;
981
982        if (diff < -32768 || diff > 32767 || *(insn + 2) != 0x10000003) {
983            /*
984                Convert the sequence:
985                  beq $2, $3, target
986                  nop
987                  b 1f
988                  nop
989                  nop
990                  nop
991                1:
992
993                to the new sequence if possible:
994                  bne $2, $3, 1f
995                  nop
996                  j    target
997                  nop
998                  nop
999                  nop
1000                1:
1001
1002                OR to the new sequence:
1003                  bne $2, $3, 1f
1004                  nop
1005                  lui $25, target >> 16
1006                  ori $25, $25, target & 0xffff
1007                  jr $25
1008                  nop
1009                1:
1010
1011                Note: beq/bne/bc1t/bc1f are converted to bne/beq/bc1f/bc1t.
1012            */
1013
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
1023                else
1024                    ASSERT(0);
1025            }
1026
1027            insn = insn + 2;
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);
1031                *(insn + 1) = 0;
1032                return 4 * sizeof(MIPSWord);
1033            }
1034
1035            intptr_t newTargetAddress = reinterpret_cast<intptr_t>(to);
1036            /* lui */
1037            *insn = 0x3c000000 | (MIPSRegisters::t9 << OP_SH_RT) | ((newTargetAddress >> 16) & 0xffff);
1038            /* ori */
1039            *(insn + 1) = 0x34000000 | (MIPSRegisters::t9 << OP_SH_RT) | (MIPSRegisters::t9 << OP_SH_RS) | (newTargetAddress & 0xffff);
1040            /* jr */
1041            *(insn + 2) = 0x00000008 | (MIPSRegisters::t9 << OP_SH_RS);
1042            return 5 * sizeof(MIPSWord);
1043        }
1044
1045        *insn = (*insn & 0xffff0000) | (diff & 0xffff);
1046        return sizeof(MIPSWord);
1047    }
1048
1049    static int linkCallInternal(void* from, void* to)
1050    {
1051        MIPSWord* insn = reinterpret_cast<MIPSWord*>(from);
1052        insn = insn - 4;
1053
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);
1059            }
1060
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);
1065            /* jalr $25 */
1066            *(insn + 2) = 0x0000f809 | (MIPSRegisters::t9 << OP_SH_RS);
1067            return 3 * sizeof(MIPSWord);
1068        }
1069
1070        ASSERT((*insn & 0xffe00000) == 0x3c000000); // lui
1071        ASSERT((*(insn + 1) & 0xfc000000) == 0x34000000); // ori
1072
1073        /* lui */
1074        *insn = (*insn & 0xffff0000) | ((reinterpret_cast<intptr_t>(to) >> 16) & 0xffff);
1075        /* ori */
1076        *(insn + 1) = (*(insn + 1) & 0xffff0000) | (reinterpret_cast<intptr_t>(to) & 0xffff);
1077        return 2 * sizeof(MIPSWord);
1078    }
1079
1080    AssemblerBuffer m_buffer;
1081    Jumps m_jumps;
1082    int m_indexOfLastWatchpoint;
1083    int m_indexOfTailOfLastWatchpoint;
1084};
1085
1086} // namespace JSC
1087
1088#endif // ENABLE(ASSEMBLER) && CPU(MIPS)
1089
1090#endif // MIPSAssembler_h
1091