]> git.saurik.com Git - apple/javascriptcore.git/blame - assembler/MIPSAssembler.h
JavaScriptCore-1218.34.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
A
153
154 MIPSAssembler()
93a37866
A
155 : m_indexOfLastWatchpoint(INT_MIN)
156 , m_indexOfTailOfLastWatchpoint(INT_MIN)
4e4e5a6f
A
157 {
158 }
159
160 // MIPS instruction opcode field position
161 enum {
162 OP_SH_RD = 11,
163 OP_SH_RT = 16,
164 OP_SH_RS = 21,
165 OP_SH_SHAMT = 6,
166 OP_SH_CODE = 16,
167 OP_SH_FD = 6,
168 OP_SH_FS = 11,
169 OP_SH_FT = 16
170 };
171
4e4e5a6f
A
172 void emitInst(MIPSWord op)
173 {
174 void* oldBase = m_buffer.data();
175
176 m_buffer.putInt(op);
177
178 void* newBase = m_buffer.data();
179 if (oldBase != newBase)
180 relocateJumps(oldBase, newBase);
181 }
182
183 void nop()
184 {
185 emitInst(0x00000000);
186 }
187
188 /* Need to insert one load data delay nop for mips1. */
189 void loadDelayNop()
190 {
191#if WTF_MIPS_ISA(1)
192 nop();
193#endif
194 }
195
196 /* Need to insert one coprocessor access delay nop for mips1. */
197 void copDelayNop()
198 {
199#if WTF_MIPS_ISA(1)
200 nop();
201#endif
202 }
203
204 void move(RegisterID rd, RegisterID rs)
205 {
206 /* addu */
207 emitInst(0x00000021 | (rd << OP_SH_RD) | (rs << OP_SH_RS));
208 }
209
210 /* Set an immediate value to a register. This may generate 1 or 2
211 instructions. */
212 void li(RegisterID dest, int imm)
213 {
214 if (imm >= -32768 && imm <= 32767)
215 addiu(dest, MIPSRegisters::zero, imm);
216 else if (imm >= 0 && imm < 65536)
217 ori(dest, MIPSRegisters::zero, imm);
218 else {
219 lui(dest, imm >> 16);
220 if (imm & 0xffff)
221 ori(dest, dest, imm);
222 }
223 }
224
225 void lui(RegisterID rt, int imm)
226 {
227 emitInst(0x3c000000 | (rt << OP_SH_RT) | (imm & 0xffff));
228 }
229
230 void addiu(RegisterID rt, RegisterID rs, int imm)
231 {
93a37866 232 emitInst(0x24000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) | (imm & 0xffff));
4e4e5a6f
A
233 }
234
235 void addu(RegisterID rd, RegisterID rs, RegisterID rt)
236 {
93a37866 237 emitInst(0x00000021 | (rd << OP_SH_RD) | (rs << OP_SH_RS) | (rt << OP_SH_RT));
4e4e5a6f
A
238 }
239
240 void subu(RegisterID rd, RegisterID rs, RegisterID rt)
241 {
93a37866 242 emitInst(0x00000023 | (rd << OP_SH_RD) | (rs << OP_SH_RS) | (rt << OP_SH_RT));
4e4e5a6f
A
243 }
244
245 void mult(RegisterID rs, RegisterID rt)
246 {
247 emitInst(0x00000018 | (rs << OP_SH_RS) | (rt << OP_SH_RT));
248 }
249
14957cd0
A
250 void div(RegisterID rs, RegisterID rt)
251 {
252 emitInst(0x0000001a | (rs << OP_SH_RS) | (rt << OP_SH_RT));
253 }
254
4e4e5a6f
A
255 void mfhi(RegisterID rd)
256 {
257 emitInst(0x00000010 | (rd << OP_SH_RD));
258 }
259
260 void mflo(RegisterID rd)
261 {
262 emitInst(0x00000012 | (rd << OP_SH_RD));
263 }
264
265 void mul(RegisterID rd, RegisterID rs, RegisterID rt)
266 {
267#if WTF_MIPS_ISA_AT_LEAST(32)
93a37866 268 emitInst(0x70000002 | (rd << OP_SH_RD) | (rs << OP_SH_RS) | (rt << OP_SH_RT));
4e4e5a6f
A
269#else
270 mult(rs, rt);
271 mflo(rd);
272#endif
273 }
274
275 void andInsn(RegisterID rd, RegisterID rs, RegisterID rt)
276 {
93a37866 277 emitInst(0x00000024 | (rd << OP_SH_RD) | (rs << OP_SH_RS) | (rt << OP_SH_RT));
4e4e5a6f
A
278 }
279
280 void andi(RegisterID rt, RegisterID rs, int imm)
281 {
93a37866 282 emitInst(0x30000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) | (imm & 0xffff));
4e4e5a6f
A
283 }
284
285 void nor(RegisterID rd, RegisterID rs, RegisterID rt)
286 {
93a37866 287 emitInst(0x00000027 | (rd << OP_SH_RD) | (rs << OP_SH_RS) | (rt << OP_SH_RT));
4e4e5a6f
A
288 }
289
290 void orInsn(RegisterID rd, RegisterID rs, RegisterID rt)
291 {
93a37866 292 emitInst(0x00000025 | (rd << OP_SH_RD) | (rs << OP_SH_RS) | (rt << OP_SH_RT));
4e4e5a6f
A
293 }
294
295 void ori(RegisterID rt, RegisterID rs, int imm)
296 {
93a37866 297 emitInst(0x34000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) | (imm & 0xffff));
4e4e5a6f
A
298 }
299
300 void xorInsn(RegisterID rd, RegisterID rs, RegisterID rt)
301 {
93a37866 302 emitInst(0x00000026 | (rd << OP_SH_RD) | (rs << OP_SH_RS) | (rt << OP_SH_RT));
4e4e5a6f
A
303 }
304
305 void xori(RegisterID rt, RegisterID rs, int imm)
306 {
93a37866 307 emitInst(0x38000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) | (imm & 0xffff));
4e4e5a6f
A
308 }
309
310 void slt(RegisterID rd, RegisterID rs, RegisterID rt)
311 {
93a37866 312 emitInst(0x0000002a | (rd << OP_SH_RD) | (rs << OP_SH_RS) | (rt << OP_SH_RT));
4e4e5a6f
A
313 }
314
315 void sltu(RegisterID rd, RegisterID rs, RegisterID rt)
316 {
93a37866 317 emitInst(0x0000002b | (rd << OP_SH_RD) | (rs << OP_SH_RS) | (rt << OP_SH_RT));
4e4e5a6f
A
318 }
319
320 void sltiu(RegisterID rt, RegisterID rs, int imm)
321 {
93a37866 322 emitInst(0x2c000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) | (imm & 0xffff));
4e4e5a6f
A
323 }
324
325 void sll(RegisterID rd, RegisterID rt, int shamt)
326 {
93a37866 327 emitInst(0x00000000 | (rd << OP_SH_RD) | (rt << OP_SH_RT) | ((shamt & 0x1f) << OP_SH_SHAMT));
4e4e5a6f
A
328 }
329
93a37866 330 void sllv(RegisterID rd, RegisterID rt, RegisterID rs)
4e4e5a6f 331 {
93a37866 332 emitInst(0x00000004 | (rd << OP_SH_RD) | (rt << OP_SH_RT) | (rs << OP_SH_RS));
4e4e5a6f
A
333 }
334
335 void sra(RegisterID rd, RegisterID rt, int shamt)
336 {
93a37866 337 emitInst(0x00000003 | (rd << OP_SH_RD) | (rt << OP_SH_RT) | ((shamt & 0x1f) << OP_SH_SHAMT));
4e4e5a6f
A
338 }
339
340 void srav(RegisterID rd, RegisterID rt, RegisterID rs)
341 {
93a37866 342 emitInst(0x00000007 | (rd << OP_SH_RD) | (rt << OP_SH_RT) | (rs << OP_SH_RS));
4e4e5a6f
A
343 }
344
14957cd0
A
345 void srl(RegisterID rd, RegisterID rt, int shamt)
346 {
93a37866 347 emitInst(0x00000002 | (rd << OP_SH_RD) | (rt << OP_SH_RT) | ((shamt & 0x1f) << OP_SH_SHAMT));
14957cd0
A
348 }
349
350 void srlv(RegisterID rd, RegisterID rt, RegisterID rs)
351 {
93a37866
A
352 emitInst(0x00000006 | (rd << OP_SH_RD) | (rt << OP_SH_RT) | (rs << OP_SH_RS));
353 }
354
355 void lb(RegisterID rt, RegisterID rs, int offset)
356 {
357 emitInst(0x80000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) | (offset & 0xffff));
358 loadDelayNop();
14957cd0
A
359 }
360
4e4e5a6f
A
361 void lbu(RegisterID rt, RegisterID rs, int offset)
362 {
93a37866 363 emitInst(0x90000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) | (offset & 0xffff));
4e4e5a6f
A
364 loadDelayNop();
365 }
366
367 void lw(RegisterID rt, RegisterID rs, int offset)
368 {
93a37866 369 emitInst(0x8c000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) | (offset & 0xffff));
4e4e5a6f
A
370 loadDelayNop();
371 }
372
373 void lwl(RegisterID rt, RegisterID rs, int offset)
374 {
93a37866 375 emitInst(0x88000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) | (offset & 0xffff));
4e4e5a6f
A
376 loadDelayNop();
377 }
378
379 void lwr(RegisterID rt, RegisterID rs, int offset)
380 {
93a37866
A
381 emitInst(0x98000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) | (offset & 0xffff));
382 loadDelayNop();
383 }
384
385 void lh(RegisterID rt, RegisterID rs, int offset)
386 {
387 emitInst(0x84000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) | (offset & 0xffff));
4e4e5a6f
A
388 loadDelayNop();
389 }
390
391 void lhu(RegisterID rt, RegisterID rs, int offset)
392 {
93a37866 393 emitInst(0x94000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) | (offset & 0xffff));
4e4e5a6f
A
394 loadDelayNop();
395 }
396
93a37866
A
397 void sb(RegisterID rt, RegisterID rs, int offset)
398 {
399 emitInst(0xa0000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) | (offset & 0xffff));
400 }
401
402 void sh(RegisterID rt, RegisterID rs, int offset)
403 {
404 emitInst(0xa4000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) | (offset & 0xffff));
405 }
406
4e4e5a6f
A
407 void sw(RegisterID rt, RegisterID rs, int offset)
408 {
93a37866 409 emitInst(0xac000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) | (offset & 0xffff));
4e4e5a6f
A
410 }
411
412 void jr(RegisterID rs)
413 {
414 emitInst(0x00000008 | (rs << OP_SH_RS));
415 }
416
417 void jalr(RegisterID rs)
418 {
419 emitInst(0x0000f809 | (rs << OP_SH_RS));
420 }
421
422 void jal()
423 {
424 emitInst(0x0c000000);
425 }
426
427 void bkpt()
428 {
429 int value = 512; /* BRK_BUG */
430 emitInst(0x0000000d | ((value & 0x3ff) << OP_SH_CODE));
431 }
432
433 void bgez(RegisterID rs, int imm)
434 {
435 emitInst(0x04010000 | (rs << OP_SH_RS) | (imm & 0xffff));
436 }
437
438 void bltz(RegisterID rs, int imm)
439 {
440 emitInst(0x04000000 | (rs << OP_SH_RS) | (imm & 0xffff));
441 }
442
443 void beq(RegisterID rs, RegisterID rt, int imm)
444 {
445 emitInst(0x10000000 | (rs << OP_SH_RS) | (rt << OP_SH_RT) | (imm & 0xffff));
446 }
447
448 void bne(RegisterID rs, RegisterID rt, int imm)
449 {
450 emitInst(0x14000000 | (rs << OP_SH_RS) | (rt << OP_SH_RT) | (imm & 0xffff));
451 }
452
453 void bc1t()
454 {
455 emitInst(0x45010000);
456 }
457
458 void bc1f()
459 {
460 emitInst(0x45000000);
461 }
462
4e4e5a6f
A
463 void appendJump()
464 {
14957cd0 465 m_jumps.append(m_buffer.label());
4e4e5a6f
A
466 }
467
468 void addd(FPRegisterID fd, FPRegisterID fs, FPRegisterID ft)
469 {
93a37866 470 emitInst(0x46200000 | (fd << OP_SH_FD) | (fs << OP_SH_FS) | (ft << OP_SH_FT));
4e4e5a6f
A
471 }
472
473 void subd(FPRegisterID fd, FPRegisterID fs, FPRegisterID ft)
474 {
93a37866 475 emitInst(0x46200001 | (fd << OP_SH_FD) | (fs << OP_SH_FS) | (ft << OP_SH_FT));
4e4e5a6f
A
476 }
477
478 void muld(FPRegisterID fd, FPRegisterID fs, FPRegisterID ft)
479 {
93a37866 480 emitInst(0x46200002 | (fd << OP_SH_FD) | (fs << OP_SH_FS) | (ft << OP_SH_FT));
4e4e5a6f
A
481 }
482
14957cd0
A
483 void divd(FPRegisterID fd, FPRegisterID fs, FPRegisterID ft)
484 {
93a37866 485 emitInst(0x46200003 | (fd << OP_SH_FD) | (fs << OP_SH_FS) | (ft << OP_SH_FT));
14957cd0
A
486 }
487
4e4e5a6f
A
488 void lwc1(FPRegisterID ft, RegisterID rs, int offset)
489 {
93a37866 490 emitInst(0xc4000000 | (ft << OP_SH_FT) | (rs << OP_SH_RS) | (offset & 0xffff));
4e4e5a6f
A
491 copDelayNop();
492 }
493
494 void ldc1(FPRegisterID ft, RegisterID rs, int offset)
495 {
93a37866 496 emitInst(0xd4000000 | (ft << OP_SH_FT) | (rs << OP_SH_RS) | (offset & 0xffff));
4e4e5a6f
A
497 }
498
499 void swc1(FPRegisterID ft, RegisterID rs, int offset)
500 {
93a37866 501 emitInst(0xe4000000 | (ft << OP_SH_FT) | (rs << OP_SH_RS) | (offset & 0xffff));
4e4e5a6f
A
502 }
503
504 void sdc1(FPRegisterID ft, RegisterID rs, int offset)
505 {
93a37866 506 emitInst(0xf4000000 | (ft << OP_SH_FT) | (rs << OP_SH_RS) | (offset & 0xffff));
4e4e5a6f
A
507 }
508
509 void mtc1(RegisterID rt, FPRegisterID fs)
510 {
511 emitInst(0x44800000 | (fs << OP_SH_FS) | (rt << OP_SH_RT));
512 copDelayNop();
513 }
514
14957cd0
A
515 void mthc1(RegisterID rt, FPRegisterID fs)
516 {
517 emitInst(0x44e00000 | (fs << OP_SH_FS) | (rt << OP_SH_RT));
518 copDelayNop();
519 }
520
4e4e5a6f
A
521 void mfc1(RegisterID rt, FPRegisterID fs)
522 {
523 emitInst(0x44000000 | (fs << OP_SH_FS) | (rt << OP_SH_RT));
524 copDelayNop();
525 }
526
14957cd0
A
527 void sqrtd(FPRegisterID fd, FPRegisterID fs)
528 {
529 emitInst(0x46200004 | (fd << OP_SH_FD) | (fs << OP_SH_FS));
530 }
531
93a37866
A
532 void movd(FPRegisterID fd, FPRegisterID fs)
533 {
534 emitInst(0x46200006 | (fd << OP_SH_FD) | (fs << OP_SH_FS));
535 }
536
537 void negd(FPRegisterID fd, FPRegisterID fs)
538 {
539 emitInst(0x46200007 | (fd << OP_SH_FD) | (fs << OP_SH_FS));
540 }
541
4e4e5a6f
A
542 void truncwd(FPRegisterID fd, FPRegisterID fs)
543 {
544 emitInst(0x4620000d | (fd << OP_SH_FD) | (fs << OP_SH_FS));
545 }
546
547 void cvtdw(FPRegisterID fd, FPRegisterID fs)
548 {
549 emitInst(0x46800021 | (fd << OP_SH_FD) | (fs << OP_SH_FS));
550 }
551
93a37866
A
552 void cvtds(FPRegisterID fd, FPRegisterID fs)
553 {
554 emitInst(0x46000021 | (fd << OP_SH_FD) | (fs << OP_SH_FS));
555 }
556
14957cd0
A
557 void cvtwd(FPRegisterID fd, FPRegisterID fs)
558 {
559 emitInst(0x46200024 | (fd << OP_SH_FD) | (fs << OP_SH_FS));
560 }
561
93a37866
A
562 void cvtsd(FPRegisterID fd, FPRegisterID fs)
563 {
564 emitInst(0x46200020 | (fd << OP_SH_FD) | (fs << OP_SH_FS));
565 }
566
4e4e5a6f
A
567 void ceqd(FPRegisterID fs, FPRegisterID ft)
568 {
569 emitInst(0x46200032 | (fs << OP_SH_FS) | (ft << OP_SH_FT));
570 copDelayNop();
571 }
572
573 void cngtd(FPRegisterID fs, FPRegisterID ft)
574 {
575 emitInst(0x4620003f | (fs << OP_SH_FS) | (ft << OP_SH_FT));
576 copDelayNop();
577 }
578
579 void cnged(FPRegisterID fs, FPRegisterID ft)
580 {
581 emitInst(0x4620003d | (fs << OP_SH_FS) | (ft << OP_SH_FT));
582 copDelayNop();
583 }
584
585 void cltd(FPRegisterID fs, FPRegisterID ft)
586 {
587 emitInst(0x4620003c | (fs << OP_SH_FS) | (ft << OP_SH_FT));
588 copDelayNop();
589 }
590
591 void cled(FPRegisterID fs, FPRegisterID ft)
592 {
593 emitInst(0x4620003e | (fs << OP_SH_FS) | (ft << OP_SH_FT));
594 copDelayNop();
595 }
596
597 void cueqd(FPRegisterID fs, FPRegisterID ft)
598 {
599 emitInst(0x46200033 | (fs << OP_SH_FS) | (ft << OP_SH_FT));
600 copDelayNop();
601 }
602
603 void coled(FPRegisterID fs, FPRegisterID ft)
604 {
605 emitInst(0x46200036 | (fs << OP_SH_FS) | (ft << OP_SH_FT));
606 copDelayNop();
607 }
608
609 void coltd(FPRegisterID fs, FPRegisterID ft)
610 {
611 emitInst(0x46200034 | (fs << OP_SH_FS) | (ft << OP_SH_FT));
612 copDelayNop();
613 }
614
615 void culed(FPRegisterID fs, FPRegisterID ft)
616 {
617 emitInst(0x46200037 | (fs << OP_SH_FS) | (ft << OP_SH_FT));
618 copDelayNop();
619 }
620
621 void cultd(FPRegisterID fs, FPRegisterID ft)
622 {
623 emitInst(0x46200035 | (fs << OP_SH_FS) | (ft << OP_SH_FT));
624 copDelayNop();
625 }
626
627 // General helpers
628
93a37866 629 AssemblerLabel labelIgnoringWatchpoints()
4e4e5a6f 630 {
14957cd0 631 return m_buffer.label();
4e4e5a6f
A
632 }
633
93a37866
A
634 AssemblerLabel labelForWatchpoint()
635 {
636 AssemblerLabel result = m_buffer.label();
637 if (static_cast<int>(result.m_offset) != m_indexOfLastWatchpoint)
638 result = label();
639 m_indexOfLastWatchpoint = result.m_offset;
640 m_indexOfTailOfLastWatchpoint = result.m_offset + maxJumpReplacementSize();
641 return result;
642 }
643
644 AssemblerLabel label()
645 {
646 AssemblerLabel result = m_buffer.label();
647 while (UNLIKELY(static_cast<int>(result.m_offset) < m_indexOfTailOfLastWatchpoint)) {
648 nop();
649 result = m_buffer.label();
650 }
651 return result;
652 }
653
14957cd0 654 AssemblerLabel align(int alignment)
4e4e5a6f
A
655 {
656 while (!m_buffer.isAligned(alignment))
657 bkpt();
658
659 return label();
660 }
661
14957cd0 662 static void* getRelocatedAddress(void* code, AssemblerLabel label)
4e4e5a6f 663 {
14957cd0 664 return reinterpret_cast<void*>(reinterpret_cast<char*>(code) + label.m_offset);
4e4e5a6f
A
665 }
666
14957cd0 667 static int getDifferenceBetweenLabels(AssemblerLabel a, AssemblerLabel b)
4e4e5a6f 668 {
14957cd0 669 return b.m_offset - a.m_offset;
4e4e5a6f
A
670 }
671
672 // Assembler admin methods:
673
14957cd0 674 size_t codeSize() const
4e4e5a6f 675 {
14957cd0 676 return m_buffer.codeSize();
4e4e5a6f
A
677 }
678
93a37866 679 PassRefPtr<ExecutableMemoryHandle> executableCopy(VM& vm, void* ownerUID, JITCompilationEffort effort)
4e4e5a6f 680 {
93a37866 681 RefPtr<ExecutableMemoryHandle> result = m_buffer.executableCopy(vm, ownerUID, effort);
4e4e5a6f
A
682 if (!result)
683 return 0;
684
6fe7ccc8
A
685 relocateJumps(m_buffer.data(), result->start());
686 return result.release();
4e4e5a6f
A
687 }
688
14957cd0 689 unsigned debugOffset() { return m_buffer.debugOffset(); }
14957cd0 690
93a37866
A
691 // Assembly helpers for moving data between fp and registers.
692 void vmov(RegisterID rd1, RegisterID rd2, FPRegisterID rn)
693 {
694#if WTF_MIPS_ISA_REV(2) && WTF_MIPS_FP64
695 mfc1(rd1, rn);
696 mfhc1(rd2, rn);
697#else
698 mfc1(rd1, rn);
699 mfc1(rd2, FPRegisterID(rn + 1));
700#endif
701 }
702
703 void vmov(FPRegisterID rd, RegisterID rn1, RegisterID rn2)
704 {
705#if WTF_MIPS_ISA_REV(2) && WTF_MIPS_FP64
706 mtc1(rn1, rd);
707 mthc1(rn2, rd);
708#else
709 mtc1(rn1, rd);
710 mtc1(rn2, FPRegisterID(rd + 1));
711#endif
712 }
713
14957cd0 714 static unsigned getCallReturnOffset(AssemblerLabel call)
4e4e5a6f
A
715 {
716 // The return address is after a call and a delay slot instruction
717 return call.m_offset;
718 }
719
720 // Linking & patching:
721 //
722 // 'link' and 'patch' methods are for use on unprotected code - such as the code
93a37866 723 // within the AssemblerBuffer, and code being patched by the patch buffer. Once
4e4e5a6f
A
724 // code has been finalized it is (platform support permitting) within a non-
725 // writable region of memory; to modify the code in an execute-only execuable
726 // pool the 'repatch' and 'relink' methods should be used.
727
93a37866
A
728 static size_t linkDirectJump(void* code, void* to)
729 {
730 MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(code));
731 size_t ops = 0;
732 int32_t slotAddr = reinterpret_cast<int>(insn) + 4;
733 int32_t toAddr = reinterpret_cast<int>(to);
734
735 if ((slotAddr & 0xf0000000) != (toAddr & 0xf0000000)) {
736 // lui
737 *insn = 0x3c000000 | (MIPSRegisters::t9 << OP_SH_RT) | ((toAddr >> 16) & 0xffff);
738 ++insn;
739 // ori
740 *insn = 0x34000000 | (MIPSRegisters::t9 << OP_SH_RT) | (MIPSRegisters::t9 << OP_SH_RS) | (toAddr & 0xffff);
741 ++insn;
742 // jr
743 *insn = 0x00000008 | (MIPSRegisters::t9 << OP_SH_RS);
744 ++insn;
745 ops = 4 * sizeof(MIPSWord);
746 } else {
747 // j
748 *insn = 0x08000000 | ((toAddr & 0x0fffffff) >> 2);
749 ++insn;
750 ops = 2 * sizeof(MIPSWord);
751 }
752 // nop
753 *insn = 0x00000000;
754 return ops;
755 }
756
14957cd0 757 void linkJump(AssemblerLabel from, AssemblerLabel to)
4e4e5a6f 758 {
14957cd0
A
759 ASSERT(to.isSet());
760 ASSERT(from.isSet());
4e4e5a6f
A
761 MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(m_buffer.data()) + from.m_offset);
762 MIPSWord* toPos = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(m_buffer.data()) + to.m_offset);
763
764 ASSERT(!(*(insn - 1)) && !(*(insn - 2)) && !(*(insn - 3)) && !(*(insn - 5)));
765 insn = insn - 6;
766 linkWithOffset(insn, toPos);
767 }
768
14957cd0 769 static void linkJump(void* code, AssemblerLabel from, void* to)
4e4e5a6f 770 {
14957cd0 771 ASSERT(from.isSet());
4e4e5a6f
A
772 MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(code) + from.m_offset);
773
774 ASSERT(!(*(insn - 1)) && !(*(insn - 2)) && !(*(insn - 3)) && !(*(insn - 5)));
775 insn = insn - 6;
776 linkWithOffset(insn, to);
777 }
778
14957cd0 779 static void linkCall(void* code, AssemblerLabel from, void* to)
4e4e5a6f
A
780 {
781 MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(code) + from.m_offset);
782 linkCallInternal(insn, to);
783 }
784
14957cd0 785 static void linkPointer(void* code, AssemblerLabel from, void* to)
4e4e5a6f
A
786 {
787 MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(code) + from.m_offset);
788 ASSERT((*insn & 0xffe00000) == 0x3c000000); // lui
789 *insn = (*insn & 0xffff0000) | ((reinterpret_cast<intptr_t>(to) >> 16) & 0xffff);
790 insn++;
791 ASSERT((*insn & 0xfc000000) == 0x34000000); // ori
792 *insn = (*insn & 0xffff0000) | (reinterpret_cast<intptr_t>(to) & 0xffff);
793 }
794
795 static void relinkJump(void* from, void* to)
796 {
797 MIPSWord* insn = reinterpret_cast<MIPSWord*>(from);
798
799 ASSERT(!(*(insn - 1)) && !(*(insn - 5)));
800 insn = insn - 6;
801 int flushSize = linkWithOffset(insn, to);
802
6fe7ccc8 803 cacheFlush(insn, flushSize);
4e4e5a6f
A
804 }
805
806 static void relinkCall(void* from, void* to)
807 {
808 void* start;
809 int size = linkCallInternal(from, to);
810 if (size == sizeof(MIPSWord))
811 start = reinterpret_cast<void*>(reinterpret_cast<intptr_t>(from) - 2 * sizeof(MIPSWord));
812 else
813 start = reinterpret_cast<void*>(reinterpret_cast<intptr_t>(from) - 4 * sizeof(MIPSWord));
814
6fe7ccc8 815 cacheFlush(start, size);
4e4e5a6f
A
816 }
817
818 static void repatchInt32(void* from, int32_t to)
819 {
820 MIPSWord* insn = reinterpret_cast<MIPSWord*>(from);
821 ASSERT((*insn & 0xffe00000) == 0x3c000000); // lui
822 *insn = (*insn & 0xffff0000) | ((to >> 16) & 0xffff);
823 insn++;
824 ASSERT((*insn & 0xfc000000) == 0x34000000); // ori
825 *insn = (*insn & 0xffff0000) | (to & 0xffff);
826 insn--;
6fe7ccc8 827 cacheFlush(insn, 2 * sizeof(MIPSWord));
4e4e5a6f
A
828 }
829
14957cd0
A
830 static int32_t readInt32(void* from)
831 {
832 MIPSWord* insn = reinterpret_cast<MIPSWord*>(from);
833 ASSERT((*insn & 0xffe00000) == 0x3c000000); // lui
834 int32_t result = (*insn & 0x0000ffff) << 16;
835 insn++;
836 ASSERT((*insn & 0xfc000000) == 0x34000000); // ori
6fe7ccc8
A
837 result |= *insn & 0x0000ffff;
838 return result;
14957cd0
A
839 }
840
841 static void repatchCompact(void* where, int32_t value)
842 {
843 repatchInt32(where, value);
844 }
845
4e4e5a6f
A
846 static void repatchPointer(void* from, void* to)
847 {
848 repatchInt32(from, reinterpret_cast<int32_t>(to));
849 }
850
14957cd0 851 static void* readPointer(void* from)
4e4e5a6f 852 {
6fe7ccc8
A
853 return reinterpret_cast<void*>(readInt32(from));
854 }
855
856 static void* readCallTarget(void* from)
857 {
858 MIPSWord* insn = reinterpret_cast<MIPSWord*>(from);
859 insn -= 4;
860 ASSERT((*insn & 0xffe00000) == 0x3c000000); // lui
861 int32_t result = (*insn & 0x0000ffff) << 16;
862 insn++;
863 ASSERT((*insn & 0xfc000000) == 0x34000000); // ori
864 result |= *insn & 0x0000ffff;
865 return reinterpret_cast<void*>(result);
866 }
867
868 static void cacheFlush(void* code, size_t size)
869 {
870#if GCC_VERSION_AT_LEAST(4, 3, 0)
871#if WTF_MIPS_ISA_REV(2) && !GCC_VERSION_AT_LEAST(4, 4, 3)
872 int lineSize;
873 asm("rdhwr %0, $1" : "=r" (lineSize));
874 //
875 // Modify "start" and "end" to avoid GCC 4.3.0-4.4.2 bug in
876 // mips_expand_synci_loop that may execute synci one more time.
877 // "start" points to the fisrt byte of the cache line.
878 // "end" points to the last byte of the line before the last cache line.
879 // Because size is always a multiple of 4, this is safe to set
880 // "end" to the last byte.
881 //
882 intptr_t start = reinterpret_cast<intptr_t>(code) & (-lineSize);
883 intptr_t end = ((reinterpret_cast<intptr_t>(code) + size - 1) & (-lineSize)) - 1;
884 __builtin___clear_cache(reinterpret_cast<char*>(start), reinterpret_cast<char*>(end));
885#else
886 intptr_t end = reinterpret_cast<intptr_t>(code) + size;
887 __builtin___clear_cache(reinterpret_cast<char*>(code), reinterpret_cast<char*>(end));
888#endif
889#else
890 _flush_cache(reinterpret_cast<char*>(code), size, BCACHE);
891#endif
4e4e5a6f
A
892 }
893
93a37866
A
894 static ptrdiff_t maxJumpReplacementSize()
895 {
896 return sizeof(MIPSWord) * 4;
897 }
898
899 static void revertJumpToMove(void* instructionStart, RegisterID rt, int imm)
900 {
901 MIPSWord* insn = static_cast<MIPSWord*>(instructionStart);
902 size_t codeSize = 2 * sizeof(MIPSWord);
903
904 // lui
905 *insn = 0x3c000000 | (rt << OP_SH_RT) | ((imm >> 16) & 0xffff);
906 ++insn;
907 // ori
908 *insn = 0x34000000 | (rt << OP_SH_RS) | (rt << OP_SH_RT) | (imm & 0xffff);
909 ++insn;
910 // if jr $t9
911 if (*insn == 0x03200008) {
912 *insn = 0x00000000;
913 codeSize += sizeof(MIPSWord);
914 }
915 cacheFlush(insn, codeSize);
916 }
917
918 static void replaceWithJump(void* instructionStart, void* to)
919 {
920 ASSERT(!(bitwise_cast<uintptr_t>(instructionStart) & 3));
921 ASSERT(!(bitwise_cast<uintptr_t>(to) & 3));
922 size_t ops = linkDirectJump(instructionStart, to);
923 cacheFlush(instructionStart, ops);
924 }
925
926 static void replaceWithLoad(void* instructionStart)
927 {
928 MIPSWord* insn = reinterpret_cast<MIPSWord*>(instructionStart);
929 ASSERT((*insn & 0xffe00000) == 0x3c000000); // lui
930 insn++;
931 ASSERT((*insn & 0xfc0007ff) == 0x00000021); // addu
932 insn++;
933 *insn = 0x8c000000 | ((*insn) & 0x3ffffff); // lw
934 cacheFlush(insn, 4);
935 }
936
937 static void replaceWithAddressComputation(void* instructionStart)
938 {
939 MIPSWord* insn = reinterpret_cast<MIPSWord*>(instructionStart);
940 ASSERT((*insn & 0xffe00000) == 0x3c000000); // lui
941 insn++;
942 ASSERT((*insn & 0xfc0007ff) == 0x00000021); // addu
943 insn++;
944 *insn = 0x24000000 | ((*insn) & 0x3ffffff); // addiu
945 cacheFlush(insn, 4);
946 }
947
4e4e5a6f 948private:
4e4e5a6f
A
949 /* Update each jump in the buffer of newBase. */
950 void relocateJumps(void* oldBase, void* newBase)
951 {
952 // Check each jump
953 for (Jumps::Iterator iter = m_jumps.begin(); iter != m_jumps.end(); ++iter) {
14957cd0 954 int pos = iter->m_offset;
4e4e5a6f
A
955 MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(newBase) + pos);
956 insn = insn + 2;
957 // Need to make sure we have 5 valid instructions after pos
93a37866 958 if ((unsigned)pos >= m_buffer.codeSize() - 5 * sizeof(MIPSWord))
4e4e5a6f
A
959 continue;
960
961 if ((*insn & 0xfc000000) == 0x08000000) { // j
962 int offset = *insn & 0x03ffffff;
963 int oldInsnAddress = (int)insn - (int)newBase + (int)oldBase;
964 int topFourBits = (oldInsnAddress + 4) >> 28;
965 int oldTargetAddress = (topFourBits << 28) | (offset << 2);
966 int newTargetAddress = oldTargetAddress - (int)oldBase + (int)newBase;
967 int newInsnAddress = (int)insn;
968 if (((newInsnAddress + 4) >> 28) == (newTargetAddress >> 28))
969 *insn = 0x08000000 | ((newTargetAddress >> 2) & 0x3ffffff);
970 else {
971 /* lui */
972 *insn = 0x3c000000 | (MIPSRegisters::t9 << OP_SH_RT) | ((newTargetAddress >> 16) & 0xffff);
973 /* ori */
974 *(insn + 1) = 0x34000000 | (MIPSRegisters::t9 << OP_SH_RT) | (MIPSRegisters::t9 << OP_SH_RS) | (newTargetAddress & 0xffff);
975 /* jr */
976 *(insn + 2) = 0x00000008 | (MIPSRegisters::t9 << OP_SH_RS);
977 }
978 } else if ((*insn & 0xffe00000) == 0x3c000000) { // lui
979 int high = (*insn & 0xffff) << 16;
980 int low = *(insn + 1) & 0xffff;
981 int oldTargetAddress = high | low;
982 int newTargetAddress = oldTargetAddress - (int)oldBase + (int)newBase;
983 /* lui */
984 *insn = 0x3c000000 | (MIPSRegisters::t9 << OP_SH_RT) | ((newTargetAddress >> 16) & 0xffff);
985 /* ori */
986 *(insn + 1) = 0x34000000 | (MIPSRegisters::t9 << OP_SH_RT) | (MIPSRegisters::t9 << OP_SH_RS) | (newTargetAddress & 0xffff);
987 }
988 }
989 }
990
991 static int linkWithOffset(MIPSWord* insn, void* to)
992 {
993 ASSERT((*insn & 0xfc000000) == 0x10000000 // beq
93a37866
A
994 || (*insn & 0xfc000000) == 0x14000000 // bne
995 || (*insn & 0xffff0000) == 0x45010000 // bc1t
996 || (*insn & 0xffff0000) == 0x45000000); // bc1f
997 intptr_t diff = (reinterpret_cast<intptr_t>(to) - reinterpret_cast<intptr_t>(insn) - 4) >> 2;
4e4e5a6f
A
998
999 if (diff < -32768 || diff > 32767 || *(insn + 2) != 0x10000003) {
1000 /*
1001 Convert the sequence:
1002 beq $2, $3, target
1003 nop
1004 b 1f
1005 nop
1006 nop
1007 nop
1008 1:
1009
1010 to the new sequence if possible:
1011 bne $2, $3, 1f
1012 nop
1013 j target
1014 nop
1015 nop
1016 nop
1017 1:
1018
1019 OR to the new sequence:
1020 bne $2, $3, 1f
1021 nop
1022 lui $25, target >> 16
1023 ori $25, $25, target & 0xffff
1024 jr $25
1025 nop
1026 1:
1027
1028 Note: beq/bne/bc1t/bc1f are converted to bne/beq/bc1f/bc1t.
1029 */
1030
1031 if (*(insn + 2) == 0x10000003) {
1032 if ((*insn & 0xfc000000) == 0x10000000) // beq
1033 *insn = (*insn & 0x03ff0000) | 0x14000005; // bne
1034 else if ((*insn & 0xfc000000) == 0x14000000) // bne
1035 *insn = (*insn & 0x03ff0000) | 0x10000005; // beq
1036 else if ((*insn & 0xffff0000) == 0x45010000) // bc1t
1037 *insn = 0x45000005; // bc1f
1038 else if ((*insn & 0xffff0000) == 0x45000000) // bc1f
1039 *insn = 0x45010005; // bc1t
1040 else
1041 ASSERT(0);
1042 }
1043
1044 insn = insn + 2;
1045 if ((reinterpret_cast<intptr_t>(insn) + 4) >> 28
1046 == reinterpret_cast<intptr_t>(to) >> 28) {
1047 *insn = 0x08000000 | ((reinterpret_cast<intptr_t>(to) >> 2) & 0x3ffffff);
1048 *(insn + 1) = 0;
1049 return 4 * sizeof(MIPSWord);
1050 }
1051
1052 intptr_t newTargetAddress = reinterpret_cast<intptr_t>(to);
1053 /* lui */
1054 *insn = 0x3c000000 | (MIPSRegisters::t9 << OP_SH_RT) | ((newTargetAddress >> 16) & 0xffff);
1055 /* ori */
1056 *(insn + 1) = 0x34000000 | (MIPSRegisters::t9 << OP_SH_RT) | (MIPSRegisters::t9 << OP_SH_RS) | (newTargetAddress & 0xffff);
1057 /* jr */
1058 *(insn + 2) = 0x00000008 | (MIPSRegisters::t9 << OP_SH_RS);
1059 return 5 * sizeof(MIPSWord);
1060 }
1061
1062 *insn = (*insn & 0xffff0000) | (diff & 0xffff);
1063 return sizeof(MIPSWord);
1064 }
1065
1066 static int linkCallInternal(void* from, void* to)
1067 {
1068 MIPSWord* insn = reinterpret_cast<MIPSWord*>(from);
1069 insn = insn - 4;
1070
1071 if ((*(insn + 2) & 0xfc000000) == 0x0c000000) { // jal
1072 if ((reinterpret_cast<intptr_t>(from) - 4) >> 28
1073 == reinterpret_cast<intptr_t>(to) >> 28) {
1074 *(insn + 2) = 0x0c000000 | ((reinterpret_cast<intptr_t>(to) >> 2) & 0x3ffffff);
1075 return sizeof(MIPSWord);
1076 }
1077
1078 /* lui $25, (to >> 16) & 0xffff */
1079 *insn = 0x3c000000 | (MIPSRegisters::t9 << OP_SH_RT) | ((reinterpret_cast<intptr_t>(to) >> 16) & 0xffff);
1080 /* ori $25, $25, to & 0xffff */
1081 *(insn + 1) = 0x34000000 | (MIPSRegisters::t9 << OP_SH_RT) | (MIPSRegisters::t9 << OP_SH_RS) | (reinterpret_cast<intptr_t>(to) & 0xffff);
1082 /* jalr $25 */
1083 *(insn + 2) = 0x0000f809 | (MIPSRegisters::t9 << OP_SH_RS);
1084 return 3 * sizeof(MIPSWord);
1085 }
1086
1087 ASSERT((*insn & 0xffe00000) == 0x3c000000); // lui
1088 ASSERT((*(insn + 1) & 0xfc000000) == 0x34000000); // ori
1089
1090 /* lui */
1091 *insn = (*insn & 0xffff0000) | ((reinterpret_cast<intptr_t>(to) >> 16) & 0xffff);
1092 /* ori */
1093 *(insn + 1) = (*(insn + 1) & 0xffff0000) | (reinterpret_cast<intptr_t>(to) & 0xffff);
1094 return 2 * sizeof(MIPSWord);
1095 }
1096
1097 AssemblerBuffer m_buffer;
1098 Jumps m_jumps;
93a37866
A
1099 int m_indexOfLastWatchpoint;
1100 int m_indexOfTailOfLastWatchpoint;
4e4e5a6f
A
1101};
1102
1103} // namespace JSC
1104
1105#endif // ENABLE(ASSEMBLER) && CPU(MIPS)
1106
1107#endif // MIPSAssembler_h