• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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<int, 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 
169     class JmpSrc {
170         friend class MIPSAssembler;
171     public:
JmpSrc()172         JmpSrc()
173             : m_offset(-1)
174         {
175         }
176 
177     private:
JmpSrc(int offset)178         JmpSrc(int offset)
179             : m_offset(offset)
180         {
181         }
182 
183         int m_offset;
184     };
185 
186     class JmpDst {
187         friend class MIPSAssembler;
188     public:
JmpDst()189         JmpDst()
190             : m_offset(-1)
191             , m_used(false)
192         {
193         }
194 
isUsed()195         bool isUsed() const { return m_used; }
isSet()196         bool isSet() const { return (m_offset != -1); }
used()197         void used() { m_used = true; }
198     private:
JmpDst(int offset)199         JmpDst(int offset)
200             : m_offset(offset)
201             , m_used(false)
202         {
203             ASSERT(m_offset == offset);
204         }
205 
206         int m_offset : 31;
207         int m_used : 1;
208     };
209 
emitInst(MIPSWord op)210     void emitInst(MIPSWord op)
211     {
212         void* oldBase = m_buffer.data();
213 
214         m_buffer.putInt(op);
215 
216         void* newBase = m_buffer.data();
217         if (oldBase != newBase)
218             relocateJumps(oldBase, newBase);
219     }
220 
nop()221     void nop()
222     {
223         emitInst(0x00000000);
224     }
225 
226     /* Need to insert one load data delay nop for mips1.  */
loadDelayNop()227     void loadDelayNop()
228     {
229 #if WTF_MIPS_ISA(1)
230         nop();
231 #endif
232     }
233 
234     /* Need to insert one coprocessor access delay nop for mips1.  */
copDelayNop()235     void copDelayNop()
236     {
237 #if WTF_MIPS_ISA(1)
238         nop();
239 #endif
240     }
241 
move(RegisterID rd,RegisterID rs)242     void move(RegisterID rd, RegisterID rs)
243     {
244         /* addu */
245         emitInst(0x00000021 | (rd << OP_SH_RD) | (rs << OP_SH_RS));
246     }
247 
248     /* Set an immediate value to a register.  This may generate 1 or 2
249        instructions.  */
li(RegisterID dest,int imm)250     void li(RegisterID dest, int imm)
251     {
252         if (imm >= -32768 && imm <= 32767)
253             addiu(dest, MIPSRegisters::zero, imm);
254         else if (imm >= 0 && imm < 65536)
255             ori(dest, MIPSRegisters::zero, imm);
256         else {
257             lui(dest, imm >> 16);
258             if (imm & 0xffff)
259                 ori(dest, dest, imm);
260         }
261     }
262 
lui(RegisterID rt,int imm)263     void lui(RegisterID rt, int imm)
264     {
265         emitInst(0x3c000000 | (rt << OP_SH_RT) | (imm & 0xffff));
266     }
267 
addiu(RegisterID rt,RegisterID rs,int imm)268     void addiu(RegisterID rt, RegisterID rs, int imm)
269     {
270         emitInst(0x24000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
271                  | (imm & 0xffff));
272     }
273 
addu(RegisterID rd,RegisterID rs,RegisterID rt)274     void addu(RegisterID rd, RegisterID rs, RegisterID rt)
275     {
276         emitInst(0x00000021 | (rd << OP_SH_RD) | (rs << OP_SH_RS)
277                  | (rt << OP_SH_RT));
278     }
279 
subu(RegisterID rd,RegisterID rs,RegisterID rt)280     void subu(RegisterID rd, RegisterID rs, RegisterID rt)
281     {
282         emitInst(0x00000023 | (rd << OP_SH_RD) | (rs << OP_SH_RS)
283                  | (rt << OP_SH_RT));
284     }
285 
mult(RegisterID rs,RegisterID rt)286     void mult(RegisterID rs, RegisterID rt)
287     {
288         emitInst(0x00000018 | (rs << OP_SH_RS) | (rt << OP_SH_RT));
289     }
290 
div(RegisterID rs,RegisterID rt)291     void div(RegisterID rs, RegisterID rt)
292     {
293         emitInst(0x0000001a | (rs << OP_SH_RS) | (rt << OP_SH_RT));
294     }
295 
mfhi(RegisterID rd)296     void mfhi(RegisterID rd)
297     {
298         emitInst(0x00000010 | (rd << OP_SH_RD));
299     }
300 
mflo(RegisterID rd)301     void mflo(RegisterID rd)
302     {
303         emitInst(0x00000012 | (rd << OP_SH_RD));
304     }
305 
mul(RegisterID rd,RegisterID rs,RegisterID rt)306     void mul(RegisterID rd, RegisterID rs, RegisterID rt)
307     {
308 #if WTF_MIPS_ISA_AT_LEAST(32)
309         emitInst(0x70000002 | (rd << OP_SH_RD) | (rs << OP_SH_RS)
310                  | (rt << OP_SH_RT));
311 #else
312         mult(rs, rt);
313         mflo(rd);
314 #endif
315     }
316 
andInsn(RegisterID rd,RegisterID rs,RegisterID rt)317     void andInsn(RegisterID rd, RegisterID rs, RegisterID rt)
318     {
319         emitInst(0x00000024 | (rd << OP_SH_RD) | (rs << OP_SH_RS)
320                  | (rt << OP_SH_RT));
321     }
322 
andi(RegisterID rt,RegisterID rs,int imm)323     void andi(RegisterID rt, RegisterID rs, int imm)
324     {
325         emitInst(0x30000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
326                  | (imm & 0xffff));
327     }
328 
nor(RegisterID rd,RegisterID rs,RegisterID rt)329     void nor(RegisterID rd, RegisterID rs, RegisterID rt)
330     {
331         emitInst(0x00000027 | (rd << OP_SH_RD) | (rs << OP_SH_RS)
332                  | (rt << OP_SH_RT));
333     }
334 
orInsn(RegisterID rd,RegisterID rs,RegisterID rt)335     void orInsn(RegisterID rd, RegisterID rs, RegisterID rt)
336     {
337         emitInst(0x00000025 | (rd << OP_SH_RD) | (rs << OP_SH_RS)
338                  | (rt << OP_SH_RT));
339     }
340 
ori(RegisterID rt,RegisterID rs,int imm)341     void ori(RegisterID rt, RegisterID rs, int imm)
342     {
343         emitInst(0x34000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
344                  | (imm & 0xffff));
345     }
346 
xorInsn(RegisterID rd,RegisterID rs,RegisterID rt)347     void xorInsn(RegisterID rd, RegisterID rs, RegisterID rt)
348     {
349         emitInst(0x00000026 | (rd << OP_SH_RD) | (rs << OP_SH_RS)
350                  | (rt << OP_SH_RT));
351     }
352 
xori(RegisterID rt,RegisterID rs,int imm)353     void xori(RegisterID rt, RegisterID rs, int imm)
354     {
355         emitInst(0x38000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
356                  | (imm & 0xffff));
357     }
358 
slt(RegisterID rd,RegisterID rs,RegisterID rt)359     void slt(RegisterID rd, RegisterID rs, RegisterID rt)
360     {
361         emitInst(0x0000002a | (rd << OP_SH_RD) | (rs << OP_SH_RS)
362                  | (rt << OP_SH_RT));
363     }
364 
sltu(RegisterID rd,RegisterID rs,RegisterID rt)365     void sltu(RegisterID rd, RegisterID rs, RegisterID rt)
366     {
367         emitInst(0x0000002b | (rd << OP_SH_RD) | (rs << OP_SH_RS)
368                  | (rt << OP_SH_RT));
369     }
370 
sltiu(RegisterID rt,RegisterID rs,int imm)371     void sltiu(RegisterID rt, RegisterID rs, int imm)
372     {
373         emitInst(0x2c000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
374                  | (imm & 0xffff));
375     }
376 
sll(RegisterID rd,RegisterID rt,int shamt)377     void sll(RegisterID rd, RegisterID rt, int shamt)
378     {
379         emitInst(0x00000000 | (rd << OP_SH_RD) | (rt << OP_SH_RT)
380                  | ((shamt & 0x1f) << OP_SH_SHAMT));
381     }
382 
sllv(RegisterID rd,RegisterID rt,int rs)383     void sllv(RegisterID rd, RegisterID rt, int rs)
384     {
385         emitInst(0x00000004 | (rd << OP_SH_RD) | (rt << OP_SH_RT)
386                  | (rs << OP_SH_RS));
387     }
388 
sra(RegisterID rd,RegisterID rt,int shamt)389     void sra(RegisterID rd, RegisterID rt, int shamt)
390     {
391         emitInst(0x00000003 | (rd << OP_SH_RD) | (rt << OP_SH_RT)
392                  | ((shamt & 0x1f) << OP_SH_SHAMT));
393     }
394 
srav(RegisterID rd,RegisterID rt,RegisterID rs)395     void srav(RegisterID rd, RegisterID rt, RegisterID rs)
396     {
397         emitInst(0x00000007 | (rd << OP_SH_RD) | (rt << OP_SH_RT)
398                  | (rs << OP_SH_RS));
399     }
400 
srl(RegisterID rd,RegisterID rt,int shamt)401     void srl(RegisterID rd, RegisterID rt, int shamt)
402     {
403         emitInst(0x00000002 | (rd << OP_SH_RD) | (rt << OP_SH_RT)
404                  | ((shamt & 0x1f) << OP_SH_SHAMT));
405     }
406 
srlv(RegisterID rd,RegisterID rt,RegisterID rs)407     void srlv(RegisterID rd, RegisterID rt, RegisterID rs)
408     {
409         emitInst(0x00000006 | (rd << OP_SH_RD) | (rt << OP_SH_RT)
410                  | (rs << OP_SH_RS));
411     }
412 
lbu(RegisterID rt,RegisterID rs,int offset)413     void lbu(RegisterID rt, RegisterID rs, int offset)
414     {
415         emitInst(0x90000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
416                  | (offset & 0xffff));
417         loadDelayNop();
418     }
419 
lw(RegisterID rt,RegisterID rs,int offset)420     void lw(RegisterID rt, RegisterID rs, int offset)
421     {
422         emitInst(0x8c000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
423                  | (offset & 0xffff));
424         loadDelayNop();
425     }
426 
lwl(RegisterID rt,RegisterID rs,int offset)427     void lwl(RegisterID rt, RegisterID rs, int offset)
428     {
429         emitInst(0x88000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
430                  | (offset & 0xffff));
431         loadDelayNop();
432     }
433 
lwr(RegisterID rt,RegisterID rs,int offset)434     void lwr(RegisterID rt, RegisterID rs, int offset)
435     {
436         emitInst(0x98000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
437                  | (offset & 0xffff));
438         loadDelayNop();
439     }
440 
lhu(RegisterID rt,RegisterID rs,int offset)441     void lhu(RegisterID rt, RegisterID rs, int offset)
442     {
443         emitInst(0x94000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
444                  | (offset & 0xffff));
445         loadDelayNop();
446     }
447 
sw(RegisterID rt,RegisterID rs,int offset)448     void sw(RegisterID rt, RegisterID rs, int offset)
449     {
450         emitInst(0xac000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
451                  | (offset & 0xffff));
452     }
453 
jr(RegisterID rs)454     void jr(RegisterID rs)
455     {
456         emitInst(0x00000008 | (rs << OP_SH_RS));
457     }
458 
jalr(RegisterID rs)459     void jalr(RegisterID rs)
460     {
461         emitInst(0x0000f809 | (rs << OP_SH_RS));
462     }
463 
jal()464     void jal()
465     {
466         emitInst(0x0c000000);
467     }
468 
bkpt()469     void bkpt()
470     {
471         int value = 512; /* BRK_BUG */
472         emitInst(0x0000000d | ((value & 0x3ff) << OP_SH_CODE));
473     }
474 
bgez(RegisterID rs,int imm)475     void bgez(RegisterID rs, int imm)
476     {
477         emitInst(0x04010000 | (rs << OP_SH_RS) | (imm & 0xffff));
478     }
479 
bltz(RegisterID rs,int imm)480     void bltz(RegisterID rs, int imm)
481     {
482         emitInst(0x04000000 | (rs << OP_SH_RS) | (imm & 0xffff));
483     }
484 
beq(RegisterID rs,RegisterID rt,int imm)485     void beq(RegisterID rs, RegisterID rt, int imm)
486     {
487         emitInst(0x10000000 | (rs << OP_SH_RS) | (rt << OP_SH_RT) | (imm & 0xffff));
488     }
489 
bne(RegisterID rs,RegisterID rt,int imm)490     void bne(RegisterID rs, RegisterID rt, int imm)
491     {
492         emitInst(0x14000000 | (rs << OP_SH_RS) | (rt << OP_SH_RT) | (imm & 0xffff));
493     }
494 
bc1t()495     void bc1t()
496     {
497         emitInst(0x45010000);
498     }
499 
bc1f()500     void bc1f()
501     {
502         emitInst(0x45000000);
503     }
504 
newJmpSrc()505     JmpSrc newJmpSrc()
506     {
507         return JmpSrc(m_buffer.size());
508     }
509 
appendJump()510     void appendJump()
511     {
512         m_jumps.append(m_buffer.size());
513     }
514 
addd(FPRegisterID fd,FPRegisterID fs,FPRegisterID ft)515     void addd(FPRegisterID fd, FPRegisterID fs, FPRegisterID ft)
516     {
517         emitInst(0x46200000 | (fd << OP_SH_FD) | (fs << OP_SH_FS)
518                  | (ft << OP_SH_FT));
519     }
520 
subd(FPRegisterID fd,FPRegisterID fs,FPRegisterID ft)521     void subd(FPRegisterID fd, FPRegisterID fs, FPRegisterID ft)
522     {
523         emitInst(0x46200001 | (fd << OP_SH_FD) | (fs << OP_SH_FS)
524                  | (ft << OP_SH_FT));
525     }
526 
muld(FPRegisterID fd,FPRegisterID fs,FPRegisterID ft)527     void muld(FPRegisterID fd, FPRegisterID fs, FPRegisterID ft)
528     {
529         emitInst(0x46200002 | (fd << OP_SH_FD) | (fs << OP_SH_FS)
530                  | (ft << OP_SH_FT));
531     }
532 
divd(FPRegisterID fd,FPRegisterID fs,FPRegisterID ft)533     void divd(FPRegisterID fd, FPRegisterID fs, FPRegisterID ft)
534     {
535         emitInst(0x46200003 | (fd << OP_SH_FD) | (fs << OP_SH_FS)
536                  | (ft << OP_SH_FT));
537     }
538 
lwc1(FPRegisterID ft,RegisterID rs,int offset)539     void lwc1(FPRegisterID ft, RegisterID rs, int offset)
540     {
541         emitInst(0xc4000000 | (ft << OP_SH_FT) | (rs << OP_SH_RS)
542                  | (offset & 0xffff));
543         copDelayNop();
544     }
545 
ldc1(FPRegisterID ft,RegisterID rs,int offset)546     void ldc1(FPRegisterID ft, RegisterID rs, int offset)
547     {
548         emitInst(0xd4000000 | (ft << OP_SH_FT) | (rs << OP_SH_RS)
549                  | (offset & 0xffff));
550     }
551 
swc1(FPRegisterID ft,RegisterID rs,int offset)552     void swc1(FPRegisterID ft, RegisterID rs, int offset)
553     {
554         emitInst(0xe4000000 | (ft << OP_SH_FT) | (rs << OP_SH_RS)
555                  | (offset & 0xffff));
556     }
557 
sdc1(FPRegisterID ft,RegisterID rs,int offset)558     void sdc1(FPRegisterID ft, RegisterID rs, int offset)
559     {
560         emitInst(0xf4000000 | (ft << OP_SH_FT) | (rs << OP_SH_RS)
561                  | (offset & 0xffff));
562     }
563 
mtc1(RegisterID rt,FPRegisterID fs)564     void mtc1(RegisterID rt, FPRegisterID fs)
565     {
566         emitInst(0x44800000 | (fs << OP_SH_FS) | (rt << OP_SH_RT));
567         copDelayNop();
568     }
569 
mthc1(RegisterID rt,FPRegisterID fs)570     void mthc1(RegisterID rt, FPRegisterID fs)
571     {
572         emitInst(0x44e00000 | (fs << OP_SH_FS) | (rt << OP_SH_RT));
573         copDelayNop();
574     }
575 
mfc1(RegisterID rt,FPRegisterID fs)576     void mfc1(RegisterID rt, FPRegisterID fs)
577     {
578         emitInst(0x44000000 | (fs << OP_SH_FS) | (rt << OP_SH_RT));
579         copDelayNop();
580     }
581 
sqrtd(FPRegisterID fd,FPRegisterID fs)582     void sqrtd(FPRegisterID fd, FPRegisterID fs)
583     {
584         emitInst(0x46200004 | (fd << OP_SH_FD) | (fs << OP_SH_FS));
585     }
586 
truncwd(FPRegisterID fd,FPRegisterID fs)587     void truncwd(FPRegisterID fd, FPRegisterID fs)
588     {
589         emitInst(0x4620000d | (fd << OP_SH_FD) | (fs << OP_SH_FS));
590     }
591 
cvtdw(FPRegisterID fd,FPRegisterID fs)592     void cvtdw(FPRegisterID fd, FPRegisterID fs)
593     {
594         emitInst(0x46800021 | (fd << OP_SH_FD) | (fs << OP_SH_FS));
595     }
596 
cvtwd(FPRegisterID fd,FPRegisterID fs)597     void cvtwd(FPRegisterID fd, FPRegisterID fs)
598     {
599         emitInst(0x46200024 | (fd << OP_SH_FD) | (fs << OP_SH_FS));
600     }
601 
ceqd(FPRegisterID fs,FPRegisterID ft)602     void ceqd(FPRegisterID fs, FPRegisterID ft)
603     {
604         emitInst(0x46200032 | (fs << OP_SH_FS) | (ft << OP_SH_FT));
605         copDelayNop();
606     }
607 
cngtd(FPRegisterID fs,FPRegisterID ft)608     void cngtd(FPRegisterID fs, FPRegisterID ft)
609     {
610         emitInst(0x4620003f | (fs << OP_SH_FS) | (ft << OP_SH_FT));
611         copDelayNop();
612     }
613 
cnged(FPRegisterID fs,FPRegisterID ft)614     void cnged(FPRegisterID fs, FPRegisterID ft)
615     {
616         emitInst(0x4620003d | (fs << OP_SH_FS) | (ft << OP_SH_FT));
617         copDelayNop();
618     }
619 
cltd(FPRegisterID fs,FPRegisterID ft)620     void cltd(FPRegisterID fs, FPRegisterID ft)
621     {
622         emitInst(0x4620003c | (fs << OP_SH_FS) | (ft << OP_SH_FT));
623         copDelayNop();
624     }
625 
cled(FPRegisterID fs,FPRegisterID ft)626     void cled(FPRegisterID fs, FPRegisterID ft)
627     {
628         emitInst(0x4620003e | (fs << OP_SH_FS) | (ft << OP_SH_FT));
629         copDelayNop();
630     }
631 
cueqd(FPRegisterID fs,FPRegisterID ft)632     void cueqd(FPRegisterID fs, FPRegisterID ft)
633     {
634         emitInst(0x46200033 | (fs << OP_SH_FS) | (ft << OP_SH_FT));
635         copDelayNop();
636     }
637 
coled(FPRegisterID fs,FPRegisterID ft)638     void coled(FPRegisterID fs, FPRegisterID ft)
639     {
640         emitInst(0x46200036 | (fs << OP_SH_FS) | (ft << OP_SH_FT));
641         copDelayNop();
642     }
643 
coltd(FPRegisterID fs,FPRegisterID ft)644     void coltd(FPRegisterID fs, FPRegisterID ft)
645     {
646         emitInst(0x46200034 | (fs << OP_SH_FS) | (ft << OP_SH_FT));
647         copDelayNop();
648     }
649 
culed(FPRegisterID fs,FPRegisterID ft)650     void culed(FPRegisterID fs, FPRegisterID ft)
651     {
652         emitInst(0x46200037 | (fs << OP_SH_FS) | (ft << OP_SH_FT));
653         copDelayNop();
654     }
655 
cultd(FPRegisterID fs,FPRegisterID ft)656     void cultd(FPRegisterID fs, FPRegisterID ft)
657     {
658         emitInst(0x46200035 | (fs << OP_SH_FS) | (ft << OP_SH_FT));
659         copDelayNop();
660     }
661 
662     // General helpers
663 
label()664     JmpDst label()
665     {
666         return JmpDst(m_buffer.size());
667     }
668 
align(int alignment)669     JmpDst align(int alignment)
670     {
671         while (!m_buffer.isAligned(alignment))
672             bkpt();
673 
674         return label();
675     }
676 
getRelocatedAddress(void * code,JmpSrc jump)677     static void* getRelocatedAddress(void* code, JmpSrc jump)
678     {
679         ASSERT(jump.m_offset != -1);
680         void* b = reinterpret_cast<void*>((reinterpret_cast<intptr_t>(code)) + jump.m_offset);
681         return b;
682     }
683 
getRelocatedAddress(void * code,JmpDst label)684     static void* getRelocatedAddress(void* code, JmpDst label)
685     {
686         void* b = reinterpret_cast<void*>((reinterpret_cast<intptr_t>(code)) + label.m_offset);
687         return b;
688     }
689 
getDifferenceBetweenLabels(JmpDst from,JmpDst to)690     static int getDifferenceBetweenLabels(JmpDst from, JmpDst to)
691     {
692         return to.m_offset - from.m_offset;
693     }
694 
getDifferenceBetweenLabels(JmpDst from,JmpSrc to)695     static int getDifferenceBetweenLabels(JmpDst from, JmpSrc to)
696     {
697         return to.m_offset - from.m_offset;
698     }
699 
getDifferenceBetweenLabels(JmpSrc from,JmpDst to)700     static int getDifferenceBetweenLabels(JmpSrc from, JmpDst to)
701     {
702         return to.m_offset - from.m_offset;
703     }
704 
705     // Assembler admin methods:
706 
size()707     size_t size() const
708     {
709         return m_buffer.size();
710     }
711 
executableCopy(ExecutablePool * allocator)712     void* executableCopy(ExecutablePool* allocator)
713     {
714         void *result = m_buffer.executableCopy(allocator);
715         if (!result)
716             return 0;
717 
718         relocateJumps(m_buffer.data(), result);
719         return result;
720     }
721 
722 #ifndef NDEBUG
debugOffset()723     unsigned debugOffset() { return m_formatter.debugOffset(); }
724 #endif
725 
getCallReturnOffset(JmpSrc call)726     static unsigned getCallReturnOffset(JmpSrc call)
727     {
728         // The return address is after a call and a delay slot instruction
729         return call.m_offset;
730     }
731 
732     // Linking & patching:
733     //
734     // 'link' and 'patch' methods are for use on unprotected code - such as the code
735     // within the AssemblerBuffer, and code being patched by the patch buffer.  Once
736     // code has been finalized it is (platform support permitting) within a non-
737     // writable region of memory; to modify the code in an execute-only execuable
738     // pool the 'repatch' and 'relink' methods should be used.
739 
linkJump(JmpSrc from,JmpDst to)740     void linkJump(JmpSrc from, JmpDst to)
741     {
742         ASSERT(to.m_offset != -1);
743         ASSERT(from.m_offset != -1);
744         MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(m_buffer.data()) + from.m_offset);
745         MIPSWord* toPos = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(m_buffer.data()) + to.m_offset);
746 
747         ASSERT(!(*(insn - 1)) && !(*(insn - 2)) && !(*(insn - 3)) && !(*(insn - 5)));
748         insn = insn - 6;
749         linkWithOffset(insn, toPos);
750     }
751 
linkJump(void * code,JmpSrc from,void * to)752     static void linkJump(void* code, JmpSrc from, void* to)
753     {
754         ASSERT(from.m_offset != -1);
755         MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(code) + from.m_offset);
756 
757         ASSERT(!(*(insn - 1)) && !(*(insn - 2)) && !(*(insn - 3)) && !(*(insn - 5)));
758         insn = insn - 6;
759         linkWithOffset(insn, to);
760     }
761 
linkCall(void * code,JmpSrc from,void * to)762     static void linkCall(void* code, JmpSrc from, void* to)
763     {
764         MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(code) + from.m_offset);
765         linkCallInternal(insn, to);
766     }
767 
linkPointer(void * code,JmpDst from,void * to)768     static void linkPointer(void* code, JmpDst from, void* to)
769     {
770         MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(code) + from.m_offset);
771         ASSERT((*insn & 0xffe00000) == 0x3c000000); // lui
772         *insn = (*insn & 0xffff0000) | ((reinterpret_cast<intptr_t>(to) >> 16) & 0xffff);
773         insn++;
774         ASSERT((*insn & 0xfc000000) == 0x34000000); // ori
775         *insn = (*insn & 0xffff0000) | (reinterpret_cast<intptr_t>(to) & 0xffff);
776     }
777 
relinkJump(void * from,void * to)778     static void relinkJump(void* from, void* to)
779     {
780         MIPSWord* insn = reinterpret_cast<MIPSWord*>(from);
781 
782         ASSERT(!(*(insn - 1)) && !(*(insn - 5)));
783         insn = insn - 6;
784         int flushSize = linkWithOffset(insn, to);
785 
786         ExecutableAllocator::cacheFlush(insn, flushSize);
787     }
788 
relinkCall(void * from,void * to)789     static void relinkCall(void* from, void* to)
790     {
791         void* start;
792         int size = linkCallInternal(from, to);
793         if (size == sizeof(MIPSWord))
794             start = reinterpret_cast<void*>(reinterpret_cast<intptr_t>(from) - 2 * sizeof(MIPSWord));
795         else
796             start = reinterpret_cast<void*>(reinterpret_cast<intptr_t>(from) - 4 * sizeof(MIPSWord));
797 
798         ExecutableAllocator::cacheFlush(start, size);
799     }
800 
repatchInt32(void * from,int32_t to)801     static void repatchInt32(void* from, int32_t to)
802     {
803         MIPSWord* insn = reinterpret_cast<MIPSWord*>(from);
804         ASSERT((*insn & 0xffe00000) == 0x3c000000); // lui
805         *insn = (*insn & 0xffff0000) | ((to >> 16) & 0xffff);
806         insn++;
807         ASSERT((*insn & 0xfc000000) == 0x34000000); // ori
808         *insn = (*insn & 0xffff0000) | (to & 0xffff);
809         insn--;
810         ExecutableAllocator::cacheFlush(insn, 2 * sizeof(MIPSWord));
811     }
812 
repatchPointer(void * from,void * to)813     static void repatchPointer(void* from, void* to)
814     {
815         repatchInt32(from, reinterpret_cast<int32_t>(to));
816     }
817 
818 private:
819     /* Update each jump in the buffer of newBase.  */
relocateJumps(void * oldBase,void * newBase)820     void relocateJumps(void* oldBase, void* newBase)
821     {
822         // Check each jump
823         for (Jumps::Iterator iter = m_jumps.begin(); iter != m_jumps.end(); ++iter) {
824             int pos = *iter;
825             MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(newBase) + pos);
826             insn = insn + 2;
827             // Need to make sure we have 5 valid instructions after pos
828             if ((unsigned int)pos >= m_buffer.size() - 5 * sizeof(MIPSWord))
829                 continue;
830 
831             if ((*insn & 0xfc000000) == 0x08000000) { // j
832                 int offset = *insn & 0x03ffffff;
833                 int oldInsnAddress = (int)insn - (int)newBase + (int)oldBase;
834                 int topFourBits = (oldInsnAddress + 4) >> 28;
835                 int oldTargetAddress = (topFourBits << 28) | (offset << 2);
836                 int newTargetAddress = oldTargetAddress - (int)oldBase + (int)newBase;
837                 int newInsnAddress = (int)insn;
838                 if (((newInsnAddress + 4) >> 28) == (newTargetAddress >> 28))
839                     *insn = 0x08000000 | ((newTargetAddress >> 2) & 0x3ffffff);
840                 else {
841                     /* lui */
842                     *insn = 0x3c000000 | (MIPSRegisters::t9 << OP_SH_RT) | ((newTargetAddress >> 16) & 0xffff);
843                     /* ori */
844                     *(insn + 1) = 0x34000000 | (MIPSRegisters::t9 << OP_SH_RT) | (MIPSRegisters::t9 << OP_SH_RS) | (newTargetAddress & 0xffff);
845                     /* jr */
846                     *(insn + 2) = 0x00000008 | (MIPSRegisters::t9 << OP_SH_RS);
847                 }
848             } else if ((*insn & 0xffe00000) == 0x3c000000) { // lui
849                 int high = (*insn & 0xffff) << 16;
850                 int low = *(insn + 1) & 0xffff;
851                 int oldTargetAddress = high | low;
852                 int newTargetAddress = oldTargetAddress - (int)oldBase + (int)newBase;
853                 /* lui */
854                 *insn = 0x3c000000 | (MIPSRegisters::t9 << OP_SH_RT) | ((newTargetAddress >> 16) & 0xffff);
855                 /* ori */
856                 *(insn + 1) = 0x34000000 | (MIPSRegisters::t9 << OP_SH_RT) | (MIPSRegisters::t9 << OP_SH_RS) | (newTargetAddress & 0xffff);
857             }
858         }
859     }
860 
linkWithOffset(MIPSWord * insn,void * to)861     static int linkWithOffset(MIPSWord* insn, void* to)
862     {
863         ASSERT((*insn & 0xfc000000) == 0x10000000 // beq
864                || (*insn & 0xfc000000) == 0x14000000 // bne
865                || (*insn & 0xffff0000) == 0x45010000 // bc1t
866                || (*insn & 0xffff0000) == 0x45000000); // bc1f
867         intptr_t diff = (reinterpret_cast<intptr_t>(to)
868                          - reinterpret_cast<intptr_t>(insn) - 4) >> 2;
869 
870         if (diff < -32768 || diff > 32767 || *(insn + 2) != 0x10000003) {
871             /*
872                 Convert the sequence:
873                   beq $2, $3, target
874                   nop
875                   b 1f
876                   nop
877                   nop
878                   nop
879                 1:
880 
881                 to the new sequence if possible:
882                   bne $2, $3, 1f
883                   nop
884                   j    target
885                   nop
886                   nop
887                   nop
888                 1:
889 
890                 OR to the new sequence:
891                   bne $2, $3, 1f
892                   nop
893                   lui $25, target >> 16
894                   ori $25, $25, target & 0xffff
895                   jr $25
896                   nop
897                 1:
898 
899                 Note: beq/bne/bc1t/bc1f are converted to bne/beq/bc1f/bc1t.
900             */
901 
902             if (*(insn + 2) == 0x10000003) {
903                 if ((*insn & 0xfc000000) == 0x10000000) // beq
904                     *insn = (*insn & 0x03ff0000) | 0x14000005; // bne
905                 else if ((*insn & 0xfc000000) == 0x14000000) // bne
906                     *insn = (*insn & 0x03ff0000) | 0x10000005; // beq
907                 else if ((*insn & 0xffff0000) == 0x45010000) // bc1t
908                     *insn = 0x45000005; // bc1f
909                 else if ((*insn & 0xffff0000) == 0x45000000) // bc1f
910                     *insn = 0x45010005; // bc1t
911                 else
912                     ASSERT(0);
913             }
914 
915             insn = insn + 2;
916             if ((reinterpret_cast<intptr_t>(insn) + 4) >> 28
917                 == reinterpret_cast<intptr_t>(to) >> 28) {
918                 *insn = 0x08000000 | ((reinterpret_cast<intptr_t>(to) >> 2) & 0x3ffffff);
919                 *(insn + 1) = 0;
920                 return 4 * sizeof(MIPSWord);
921             }
922 
923             intptr_t newTargetAddress = reinterpret_cast<intptr_t>(to);
924             /* lui */
925             *insn = 0x3c000000 | (MIPSRegisters::t9 << OP_SH_RT) | ((newTargetAddress >> 16) & 0xffff);
926             /* ori */
927             *(insn + 1) = 0x34000000 | (MIPSRegisters::t9 << OP_SH_RT) | (MIPSRegisters::t9 << OP_SH_RS) | (newTargetAddress & 0xffff);
928             /* jr */
929             *(insn + 2) = 0x00000008 | (MIPSRegisters::t9 << OP_SH_RS);
930             return 5 * sizeof(MIPSWord);
931         }
932 
933         *insn = (*insn & 0xffff0000) | (diff & 0xffff);
934         return sizeof(MIPSWord);
935     }
936 
linkCallInternal(void * from,void * to)937     static int linkCallInternal(void* from, void* to)
938     {
939         MIPSWord* insn = reinterpret_cast<MIPSWord*>(from);
940         insn = insn - 4;
941 
942         if ((*(insn + 2) & 0xfc000000) == 0x0c000000) { // jal
943             if ((reinterpret_cast<intptr_t>(from) - 4) >> 28
944                 == reinterpret_cast<intptr_t>(to) >> 28) {
945                 *(insn + 2) = 0x0c000000 | ((reinterpret_cast<intptr_t>(to) >> 2) & 0x3ffffff);
946                 return sizeof(MIPSWord);
947             }
948 
949             /* lui $25, (to >> 16) & 0xffff */
950             *insn = 0x3c000000 | (MIPSRegisters::t9 << OP_SH_RT) | ((reinterpret_cast<intptr_t>(to) >> 16) & 0xffff);
951             /* ori $25, $25, to & 0xffff */
952             *(insn + 1) = 0x34000000 | (MIPSRegisters::t9 << OP_SH_RT) | (MIPSRegisters::t9 << OP_SH_RS) | (reinterpret_cast<intptr_t>(to) & 0xffff);
953             /* jalr $25 */
954             *(insn + 2) = 0x0000f809 | (MIPSRegisters::t9 << OP_SH_RS);
955             return 3 * sizeof(MIPSWord);
956         }
957 
958         ASSERT((*insn & 0xffe00000) == 0x3c000000); // lui
959         ASSERT((*(insn + 1) & 0xfc000000) == 0x34000000); // ori
960 
961         /* lui */
962         *insn = (*insn & 0xffff0000) | ((reinterpret_cast<intptr_t>(to) >> 16) & 0xffff);
963         /* ori */
964         *(insn + 1) = (*(insn + 1) & 0xffff0000) | (reinterpret_cast<intptr_t>(to) & 0xffff);
965         return 2 * sizeof(MIPSWord);
966     }
967 
968     AssemblerBuffer m_buffer;
969     Jumps m_jumps;
970 };
971 
972 } // namespace JSC
973 
974 #endif // ENABLE(ASSEMBLER) && CPU(MIPS)
975 
976 #endif // MIPSAssembler_h
977