]> git.saurik.com Git - apple/javascriptcore.git/blob - assembler/MIPSAssembler.h
JavaScriptCore-7600.1.4.13.1.tar.gz
[apple/javascriptcore.git] / assembler / MIPSAssembler.h
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
39 namespace JSC {
40
41 typedef uint32_t MIPSWord;
42
43 namespace MIPSRegisters {
44 typedef 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
111 typedef 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
148 class MIPSAssembler {
149 public:
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
973 private:
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