]> git.saurik.com Git - apple/javascriptcore.git/blame - assembler/MIPSAssembler.h
JavaScriptCore-7601.1.46.3.tar.gz
[apple/javascriptcore.git] / assembler / MIPSAssembler.h
CommitLineData
4e4e5a6f
A
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"
6fe7ccc8 35#include "JITCompilationEffort.h"
4e4e5a6f
A
36#include <wtf/Assertions.h>
37#include <wtf/SegmentedVector.h>
38
39namespace JSC {
40
41typedef uint32_t MIPSWord;
42
43namespace MIPSRegisters {
44typedef enum {
45 r0 = 0,
46 r1,
47 r2,
48 r3,
49 r4,
50 r5,
51 r6,
52 r7,
53 r8,
54 r9,
55 r10,
56 r11,
57 r12,
58 r13,
59 r14,
60 r15,
61 r16,
62 r17,
63 r18,
64 r19,
65 r20,
66 r21,
67 r22,
68 r23,
69 r24,
70 r25,
71 r26,
72 r27,
73 r28,
74 r29,
75 r30,
76 r31,
77 zero = r0,
78 at = r1,
79 v0 = r2,
80 v1 = r3,
81 a0 = r4,
82 a1 = r5,
83 a2 = r6,
84 a3 = r7,
85 t0 = r8,
86 t1 = r9,
87 t2 = r10,
88 t3 = r11,
89 t4 = r12,
90 t5 = r13,
91 t6 = r14,
92 t7 = r15,
93 s0 = r16,
94 s1 = r17,
95 s2 = r18,
96 s3 = r19,
97 s4 = r20,
98 s5 = r21,
99 s6 = r22,
100 s7 = r23,
101 t8 = r24,
102 t9 = r25,
103 k0 = r26,
104 k1 = r27,
105 gp = r28,
106 sp = r29,
107 fp = r30,
108 ra = r31
109} RegisterID;
110
111typedef enum {
112 f0,
113 f1,
114 f2,
115 f3,
116 f4,
117 f5,
118 f6,
119 f7,
120 f8,
121 f9,
122 f10,
123 f11,
124 f12,
125 f13,
126 f14,
127 f15,
128 f16,
129 f17,
130 f18,
131 f19,
132 f20,
133 f21,
134 f22,
135 f23,
136 f24,
137 f25,
138 f26,
139 f27,
140 f28,
141 f29,
142 f30,
143 f31
144} FPRegisterID;
145
146} // namespace MIPSRegisters
147
148class MIPSAssembler {
149public:
150 typedef MIPSRegisters::RegisterID RegisterID;
151 typedef MIPSRegisters::FPRegisterID FPRegisterID;
14957cd0 152 typedef SegmentedVector<AssemblerLabel, 64> Jumps;
4e4e5a6f 153
81345200
A
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
4e4e5a6f 160 MIPSAssembler()
93a37866
A
161 : m_indexOfLastWatchpoint(INT_MIN)
162 , m_indexOfTailOfLastWatchpoint(INT_MIN)
4e4e5a6f
A
163 {
164 }
165
81345200
A
166 AssemblerBuffer& buffer() { return m_buffer; }
167
4e4e5a6f
A
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
4e4e5a6f
A
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
81345200
A
196 void sync()
197 {
198 emitInst(0x0000000f);
199 }
200
4e4e5a6f
A
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 {
93a37866 245 emitInst(0x24000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) | (imm & 0xffff));
4e4e5a6f
A
246 }
247
248 void addu(RegisterID rd, RegisterID rs, RegisterID rt)
249 {
93a37866 250 emitInst(0x00000021 | (rd << OP_SH_RD) | (rs << OP_SH_RS) | (rt << OP_SH_RT));
4e4e5a6f
A
251 }
252
253 void subu(RegisterID rd, RegisterID rs, RegisterID rt)
254 {
93a37866 255 emitInst(0x00000023 | (rd << OP_SH_RD) | (rs << OP_SH_RS) | (rt << OP_SH_RT));
4e4e5a6f
A
256 }
257
258 void mult(RegisterID rs, RegisterID rt)
259 {
260 emitInst(0x00000018 | (rs << OP_SH_RS) | (rt << OP_SH_RT));
261 }
262
14957cd0
A
263 void div(RegisterID rs, RegisterID rt)
264 {
265 emitInst(0x0000001a | (rs << OP_SH_RS) | (rt << OP_SH_RT));
266 }
267
4e4e5a6f
A
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)
93a37866 281 emitInst(0x70000002 | (rd << OP_SH_RD) | (rs << OP_SH_RS) | (rt << OP_SH_RT));
4e4e5a6f
A
282#else
283 mult(rs, rt);
284 mflo(rd);
285#endif
286 }
287
288 void andInsn(RegisterID rd, RegisterID rs, RegisterID rt)
289 {
93a37866 290 emitInst(0x00000024 | (rd << OP_SH_RD) | (rs << OP_SH_RS) | (rt << OP_SH_RT));
4e4e5a6f
A
291 }
292
293 void andi(RegisterID rt, RegisterID rs, int imm)
294 {
93a37866 295 emitInst(0x30000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) | (imm & 0xffff));
4e4e5a6f
A
296 }
297
298 void nor(RegisterID rd, RegisterID rs, RegisterID rt)
299 {
93a37866 300 emitInst(0x00000027 | (rd << OP_SH_RD) | (rs << OP_SH_RS) | (rt << OP_SH_RT));
4e4e5a6f
A
301 }
302
303 void orInsn(RegisterID rd, RegisterID rs, RegisterID rt)
304 {
93a37866 305 emitInst(0x00000025 | (rd << OP_SH_RD) | (rs << OP_SH_RS) | (rt << OP_SH_RT));
4e4e5a6f
A
306 }
307
308 void ori(RegisterID rt, RegisterID rs, int imm)
309 {
93a37866 310 emitInst(0x34000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) | (imm & 0xffff));
4e4e5a6f
A
311 }
312
313 void xorInsn(RegisterID rd, RegisterID rs, RegisterID rt)
314 {
93a37866 315 emitInst(0x00000026 | (rd << OP_SH_RD) | (rs << OP_SH_RS) | (rt << OP_SH_RT));
4e4e5a6f
A
316 }
317
318 void xori(RegisterID rt, RegisterID rs, int imm)
319 {
93a37866 320 emitInst(0x38000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) | (imm & 0xffff));
4e4e5a6f
A
321 }
322
323 void slt(RegisterID rd, RegisterID rs, RegisterID rt)
324 {
93a37866 325 emitInst(0x0000002a | (rd << OP_SH_RD) | (rs << OP_SH_RS) | (rt << OP_SH_RT));
4e4e5a6f
A
326 }
327
328 void sltu(RegisterID rd, RegisterID rs, RegisterID rt)
329 {
93a37866 330 emitInst(0x0000002b | (rd << OP_SH_RD) | (rs << OP_SH_RS) | (rt << OP_SH_RT));
4e4e5a6f
A
331 }
332
333 void sltiu(RegisterID rt, RegisterID rs, int imm)
334 {
93a37866 335 emitInst(0x2c000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) | (imm & 0xffff));
4e4e5a6f
A
336 }
337
338 void sll(RegisterID rd, RegisterID rt, int shamt)
339 {
93a37866 340 emitInst(0x00000000 | (rd << OP_SH_RD) | (rt << OP_SH_RT) | ((shamt & 0x1f) << OP_SH_SHAMT));
4e4e5a6f
A
341 }
342
93a37866 343 void sllv(RegisterID rd, RegisterID rt, RegisterID rs)
4e4e5a6f 344 {
93a37866 345 emitInst(0x00000004 | (rd << OP_SH_RD) | (rt << OP_SH_RT) | (rs << OP_SH_RS));
4e4e5a6f
A
346 }
347
348 void sra(RegisterID rd, RegisterID rt, int shamt)
349 {
93a37866 350 emitInst(0x00000003 | (rd << OP_SH_RD) | (rt << OP_SH_RT) | ((shamt & 0x1f) << OP_SH_SHAMT));
4e4e5a6f
A
351 }
352
353 void srav(RegisterID rd, RegisterID rt, RegisterID rs)
354 {
93a37866 355 emitInst(0x00000007 | (rd << OP_SH_RD) | (rt << OP_SH_RT) | (rs << OP_SH_RS));
4e4e5a6f
A
356 }
357
14957cd0
A
358 void srl(RegisterID rd, RegisterID rt, int shamt)
359 {
93a37866 360 emitInst(0x00000002 | (rd << OP_SH_RD) | (rt << OP_SH_RT) | ((shamt & 0x1f) << OP_SH_SHAMT));
14957cd0
A
361 }
362
363 void srlv(RegisterID rd, RegisterID rt, RegisterID rs)
364 {
93a37866
A
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();
14957cd0
A
372 }
373
4e4e5a6f
A
374 void lbu(RegisterID rt, RegisterID rs, int offset)
375 {
93a37866 376 emitInst(0x90000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) | (offset & 0xffff));
4e4e5a6f
A
377 loadDelayNop();
378 }
379
380 void lw(RegisterID rt, RegisterID rs, int offset)
381 {
93a37866 382 emitInst(0x8c000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) | (offset & 0xffff));
4e4e5a6f
A
383 loadDelayNop();
384 }
385
386 void lwl(RegisterID rt, RegisterID rs, int offset)
387 {
93a37866 388 emitInst(0x88000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) | (offset & 0xffff));
4e4e5a6f
A
389 loadDelayNop();
390 }
391
392 void lwr(RegisterID rt, RegisterID rs, int offset)
393 {
93a37866
A
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));
4e4e5a6f
A
401 loadDelayNop();
402 }
403
404 void lhu(RegisterID rt, RegisterID rs, int offset)
405 {
93a37866 406 emitInst(0x94000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) | (offset & 0xffff));
4e4e5a6f
A
407 loadDelayNop();
408 }
409
93a37866
A
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
4e4e5a6f
A
420 void sw(RegisterID rt, RegisterID rs, int offset)
421 {
93a37866 422 emitInst(0xac000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) | (offset & 0xffff));
4e4e5a6f
A
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
4e4e5a6f
A
476 void appendJump()
477 {
14957cd0 478 m_jumps.append(m_buffer.label());
4e4e5a6f
A
479 }
480
481 void addd(FPRegisterID fd, FPRegisterID fs, FPRegisterID ft)
482 {
93a37866 483 emitInst(0x46200000 | (fd << OP_SH_FD) | (fs << OP_SH_FS) | (ft << OP_SH_FT));
4e4e5a6f
A
484 }
485
486 void subd(FPRegisterID fd, FPRegisterID fs, FPRegisterID ft)
487 {
93a37866 488 emitInst(0x46200001 | (fd << OP_SH_FD) | (fs << OP_SH_FS) | (ft << OP_SH_FT));
4e4e5a6f
A
489 }
490
491 void muld(FPRegisterID fd, FPRegisterID fs, FPRegisterID ft)
492 {
93a37866 493 emitInst(0x46200002 | (fd << OP_SH_FD) | (fs << OP_SH_FS) | (ft << OP_SH_FT));
4e4e5a6f
A
494 }
495
14957cd0
A
496 void divd(FPRegisterID fd, FPRegisterID fs, FPRegisterID ft)
497 {
93a37866 498 emitInst(0x46200003 | (fd << OP_SH_FD) | (fs << OP_SH_FS) | (ft << OP_SH_FT));
14957cd0
A
499 }
500
4e4e5a6f
A
501 void lwc1(FPRegisterID ft, RegisterID rs, int offset)
502 {
93a37866 503 emitInst(0xc4000000 | (ft << OP_SH_FT) | (rs << OP_SH_RS) | (offset & 0xffff));
4e4e5a6f
A
504 copDelayNop();
505 }
506
507 void ldc1(FPRegisterID ft, RegisterID rs, int offset)
508 {
93a37866 509 emitInst(0xd4000000 | (ft << OP_SH_FT) | (rs << OP_SH_RS) | (offset & 0xffff));
4e4e5a6f
A
510 }
511
512 void swc1(FPRegisterID ft, RegisterID rs, int offset)
513 {
93a37866 514 emitInst(0xe4000000 | (ft << OP_SH_FT) | (rs << OP_SH_RS) | (offset & 0xffff));
4e4e5a6f
A
515 }
516
517 void sdc1(FPRegisterID ft, RegisterID rs, int offset)
518 {
93a37866 519 emitInst(0xf4000000 | (ft << OP_SH_FT) | (rs << OP_SH_RS) | (offset & 0xffff));
4e4e5a6f
A
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
14957cd0
A
528 void mthc1(RegisterID rt, FPRegisterID fs)
529 {
530 emitInst(0x44e00000 | (fs << OP_SH_FS) | (rt << OP_SH_RT));
531 copDelayNop();
532 }
533
4e4e5a6f
A
534 void mfc1(RegisterID rt, FPRegisterID fs)
535 {
536 emitInst(0x44000000 | (fs << OP_SH_FS) | (rt << OP_SH_RT));
537 copDelayNop();
538 }
539
14957cd0
A
540 void sqrtd(FPRegisterID fd, FPRegisterID fs)
541 {
542 emitInst(0x46200004 | (fd << OP_SH_FD) | (fs << OP_SH_FS));
543 }
544
93a37866
A
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
4e4e5a6f
A
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
93a37866
A
565 void cvtds(FPRegisterID fd, FPRegisterID fs)
566 {
567 emitInst(0x46000021 | (fd << OP_SH_FD) | (fs << OP_SH_FS));
568 }
569
14957cd0
A
570 void cvtwd(FPRegisterID fd, FPRegisterID fs)
571 {
572 emitInst(0x46200024 | (fd << OP_SH_FD) | (fs << OP_SH_FS));
573 }
574
93a37866
A
575 void cvtsd(FPRegisterID fd, FPRegisterID fs)
576 {
577 emitInst(0x46200020 | (fd << OP_SH_FD) | (fs << OP_SH_FS));
578 }
579
4e4e5a6f
A
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
93a37866 642 AssemblerLabel labelIgnoringWatchpoints()
4e4e5a6f 643 {
14957cd0 644 return m_buffer.label();
4e4e5a6f
A
645 }
646
93a37866
A
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
14957cd0 667 AssemblerLabel align(int alignment)
4e4e5a6f
A
668 {
669 while (!m_buffer.isAligned(alignment))
670 bkpt();
671
672 return label();
673 }
674
14957cd0 675 static void* getRelocatedAddress(void* code, AssemblerLabel label)
4e4e5a6f 676 {
14957cd0 677 return reinterpret_cast<void*>(reinterpret_cast<char*>(code) + label.m_offset);
4e4e5a6f
A
678 }
679
14957cd0 680 static int getDifferenceBetweenLabels(AssemblerLabel a, AssemblerLabel b)
4e4e5a6f 681 {
14957cd0 682 return b.m_offset - a.m_offset;
4e4e5a6f
A
683 }
684
685 // Assembler admin methods:
686
14957cd0 687 size_t codeSize() const
4e4e5a6f 688 {
14957cd0 689 return m_buffer.codeSize();
4e4e5a6f
A
690 }
691
14957cd0 692 unsigned debugOffset() { return m_buffer.debugOffset(); }
14957cd0 693
93a37866
A
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
14957cd0 717 static unsigned getCallReturnOffset(AssemblerLabel call)
4e4e5a6f
A
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
93a37866 726 // within the AssemblerBuffer, and code being patched by the patch buffer. Once
4e4e5a6f
A
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
93a37866
A
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
14957cd0 760 void linkJump(AssemblerLabel from, AssemblerLabel to)
4e4e5a6f 761 {
14957cd0
A
762 ASSERT(to.isSet());
763 ASSERT(from.isSet());
4e4e5a6f
A
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
14957cd0 772 static void linkJump(void* code, AssemblerLabel from, void* to)
4e4e5a6f 773 {
14957cd0 774 ASSERT(from.isSet());
4e4e5a6f
A
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
14957cd0 782 static void linkCall(void* code, AssemblerLabel from, void* to)
4e4e5a6f
A
783 {
784 MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(code) + from.m_offset);
785 linkCallInternal(insn, to);
786 }
787
14957cd0 788 static void linkPointer(void* code, AssemblerLabel from, void* to)
4e4e5a6f
A
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
6fe7ccc8 806 cacheFlush(insn, flushSize);
4e4e5a6f
A
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
6fe7ccc8 818 cacheFlush(start, size);
4e4e5a6f
A
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--;
6fe7ccc8 830 cacheFlush(insn, 2 * sizeof(MIPSWord));
4e4e5a6f
A
831 }
832
14957cd0
A
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
6fe7ccc8
A
840 result |= *insn & 0x0000ffff;
841 return result;
14957cd0
A
842 }
843
844 static void repatchCompact(void* where, int32_t value)
845 {
846 repatchInt32(where, value);
847 }
848
4e4e5a6f
A
849 static void repatchPointer(void* from, void* to)
850 {
851 repatchInt32(from, reinterpret_cast<int32_t>(to));
852 }
853
14957cd0 854 static void* readPointer(void* from)
4e4e5a6f 855 {
6fe7ccc8
A
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 {
6fe7ccc8
A
873 intptr_t end = reinterpret_cast<intptr_t>(code) + size;
874 __builtin___clear_cache(reinterpret_cast<char*>(code), reinterpret_cast<char*>(end));
4e4e5a6f
A
875 }
876
93a37866
A
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
4e4e5a6f
A
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) {
14957cd0 936 int pos = iter->m_offset;
4e4e5a6f
A
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
93a37866 940 if ((unsigned)pos >= m_buffer.codeSize() - 5 * sizeof(MIPSWord))
4e4e5a6f
A
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
81345200 973private:
4e4e5a6f
A
974 static int linkWithOffset(MIPSWord* insn, void* to)
975 {
976 ASSERT((*insn & 0xfc000000) == 0x10000000 // beq
93a37866
A
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;
4e4e5a6f
A
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;
93a37866
A
1082 int m_indexOfLastWatchpoint;
1083 int m_indexOfTailOfLastWatchpoint;
4e4e5a6f
A
1084};
1085
1086} // namespace JSC
1087
1088#endif // ENABLE(ASSEMBLER) && CPU(MIPS)
1089
1090#endif // MIPSAssembler_h