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