]> git.saurik.com Git - apple/javascriptcore.git/blob - assembler/SH4Assembler.h
JavaScriptCore-7600.1.4.9.tar.gz
[apple/javascriptcore.git] / assembler / SH4Assembler.h
1 /*
2 * Copyright (C) 2013 Cisco Systems, Inc. All rights reserved.
3 * Copyright (C) 2009-2011 STMicroelectronics. All rights reserved.
4 * Copyright (C) 2008 Apple Inc. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
16 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
19 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
23 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 #ifndef SH4Assembler_h
29 #define SH4Assembler_h
30
31 #if ENABLE(ASSEMBLER) && CPU(SH4)
32
33 #include "AssemblerBuffer.h"
34 #include "AssemblerBufferWithConstantPool.h"
35 #include "JITCompilationEffort.h"
36 #include <limits.h>
37 #include <stdarg.h>
38 #include <stdint.h>
39 #include <stdio.h>
40 #include <wtf/Assertions.h>
41 #include <wtf/DataLog.h>
42 #include <wtf/Vector.h>
43
44 #ifndef NDEBUG
45 #define SH4_ASSEMBLER_TRACING
46 #endif
47
48 namespace JSC {
49 typedef uint16_t SH4Word;
50
51 enum {
52 INVALID_OPCODE = 0xffff,
53 ADD_OPCODE = 0x300c,
54 ADDIMM_OPCODE = 0x7000,
55 ADDC_OPCODE = 0x300e,
56 ADDV_OPCODE = 0x300f,
57 AND_OPCODE = 0x2009,
58 ANDIMM_OPCODE = 0xc900,
59 DIV0_OPCODE = 0x2007,
60 DIV1_OPCODE = 0x3004,
61 BF_OPCODE = 0x8b00,
62 BFS_OPCODE = 0x8f00,
63 BRA_OPCODE = 0xa000,
64 BRAF_OPCODE = 0x0023,
65 NOP_OPCODE = 0x0009,
66 BSR_OPCODE = 0xb000,
67 RTS_OPCODE = 0x000b,
68 BT_OPCODE = 0x8900,
69 BTS_OPCODE = 0x8d00,
70 BSRF_OPCODE = 0x0003,
71 BRK_OPCODE = 0x003b,
72 FTRC_OPCODE = 0xf03d,
73 CMPEQ_OPCODE = 0x3000,
74 CMPEQIMM_OPCODE = 0x8800,
75 CMPGE_OPCODE = 0x3003,
76 CMPGT_OPCODE = 0x3007,
77 CMPHI_OPCODE = 0x3006,
78 CMPHS_OPCODE = 0x3002,
79 CMPPL_OPCODE = 0x4015,
80 CMPPZ_OPCODE = 0x4011,
81 CMPSTR_OPCODE = 0x200c,
82 DT_OPCODE = 0x4010,
83 FCMPEQ_OPCODE = 0xf004,
84 FCMPGT_OPCODE = 0xf005,
85 FMOV_OPCODE = 0xf00c,
86 FADD_OPCODE = 0xf000,
87 FMUL_OPCODE = 0xf002,
88 FSUB_OPCODE = 0xf001,
89 FDIV_OPCODE = 0xf003,
90 FNEG_OPCODE = 0xf04d,
91 JMP_OPCODE = 0x402b,
92 JSR_OPCODE = 0x400b,
93 LDSPR_OPCODE = 0x402a,
94 LDSLPR_OPCODE = 0x4026,
95 MOV_OPCODE = 0x6003,
96 MOVIMM_OPCODE = 0xe000,
97 MOVB_WRITE_RN_OPCODE = 0x2000,
98 MOVB_WRITE_RNDEC_OPCODE = 0x2004,
99 MOVB_WRITE_R0RN_OPCODE = 0x0004,
100 MOVB_WRITE_OFFGBR_OPCODE = 0xc000,
101 MOVB_WRITE_OFFRN_OPCODE = 0x8000,
102 MOVB_READ_RM_OPCODE = 0x6000,
103 MOVB_READ_RMINC_OPCODE = 0x6004,
104 MOVB_READ_R0RM_OPCODE = 0x000c,
105 MOVB_READ_OFFGBR_OPCODE = 0xc400,
106 MOVB_READ_OFFRM_OPCODE = 0x8400,
107 MOVL_WRITE_RN_OPCODE = 0x2002,
108 MOVL_WRITE_RNDEC_OPCODE = 0x2006,
109 MOVL_WRITE_R0RN_OPCODE = 0x0006,
110 MOVL_WRITE_OFFGBR_OPCODE = 0xc200,
111 MOVL_WRITE_OFFRN_OPCODE = 0x1000,
112 MOVL_READ_RM_OPCODE = 0x6002,
113 MOVL_READ_RMINC_OPCODE = 0x6006,
114 MOVL_READ_R0RM_OPCODE = 0x000e,
115 MOVL_READ_OFFGBR_OPCODE = 0xc600,
116 MOVL_READ_OFFPC_OPCODE = 0xd000,
117 MOVL_READ_OFFRM_OPCODE = 0x5000,
118 MOVW_WRITE_RN_OPCODE = 0x2001,
119 MOVW_WRITE_R0RN_OPCODE = 0x0005,
120 MOVW_READ_RM_OPCODE = 0x6001,
121 MOVW_READ_RMINC_OPCODE = 0x6005,
122 MOVW_READ_R0RM_OPCODE = 0x000d,
123 MOVW_READ_OFFRM_OPCODE = 0x8500,
124 MOVW_READ_OFFPC_OPCODE = 0x9000,
125 MOVA_READ_OFFPC_OPCODE = 0xc700,
126 MOVT_OPCODE = 0x0029,
127 MULL_OPCODE = 0x0007,
128 DMULL_L_OPCODE = 0x3005,
129 STSMACL_OPCODE = 0x001a,
130 STSMACH_OPCODE = 0x000a,
131 DMULSL_OPCODE = 0x300d,
132 NEG_OPCODE = 0x600b,
133 NEGC_OPCODE = 0x600a,
134 NOT_OPCODE = 0x6007,
135 OR_OPCODE = 0x200b,
136 ORIMM_OPCODE = 0xcb00,
137 ORBIMM_OPCODE = 0xcf00,
138 SETS_OPCODE = 0x0058,
139 SETT_OPCODE = 0x0018,
140 SHAD_OPCODE = 0x400c,
141 SHAL_OPCODE = 0x4020,
142 SHAR_OPCODE = 0x4021,
143 SHLD_OPCODE = 0x400d,
144 SHLL_OPCODE = 0x4000,
145 SHLL2_OPCODE = 0x4008,
146 SHLL8_OPCODE = 0x4018,
147 SHLL16_OPCODE = 0x4028,
148 SHLR_OPCODE = 0x4001,
149 SHLR2_OPCODE = 0x4009,
150 SHLR8_OPCODE = 0x4019,
151 SHLR16_OPCODE = 0x4029,
152 STSPR_OPCODE = 0x002a,
153 STSLPR_OPCODE = 0x4022,
154 FLOAT_OPCODE = 0xf02d,
155 SUB_OPCODE = 0x3008,
156 SUBC_OPCODE = 0x300a,
157 SUBV_OPCODE = 0x300b,
158 TST_OPCODE = 0x2008,
159 TSTIMM_OPCODE = 0xc800,
160 TSTB_OPCODE = 0xcc00,
161 EXTUB_OPCODE = 0x600c,
162 EXTUW_OPCODE = 0x600d,
163 XOR_OPCODE = 0x200a,
164 XORIMM_OPCODE = 0xca00,
165 XORB_OPCODE = 0xce00,
166 FMOVS_READ_RM_INC_OPCODE = 0xf009,
167 FMOVS_READ_RM_OPCODE = 0xf008,
168 FMOVS_READ_R0RM_OPCODE = 0xf006,
169 FMOVS_WRITE_RN_OPCODE = 0xf00a,
170 FMOVS_WRITE_RN_DEC_OPCODE = 0xf00b,
171 FMOVS_WRITE_R0RN_OPCODE = 0xf007,
172 FCNVDS_DRM_FPUL_OPCODE = 0xf0bd,
173 FCNVSD_FPUL_DRN_OPCODE = 0xf0ad,
174 LDS_RM_FPUL_OPCODE = 0x405a,
175 FLDS_FRM_FPUL_OPCODE = 0xf01d,
176 STS_FPUL_RN_OPCODE = 0x005a,
177 FSTS_FPUL_FRN_OPCODE = 0xF00d,
178 LDSFPSCR_OPCODE = 0x406a,
179 STSFPSCR_OPCODE = 0x006a,
180 LDSRMFPUL_OPCODE = 0x405a,
181 FSTSFPULFRN_OPCODE = 0xf00d,
182 FABS_OPCODE = 0xf05d,
183 FSQRT_OPCODE = 0xf06d,
184 FSCHG_OPCODE = 0xf3fd,
185 CLRT_OPCODE = 8,
186 SYNCO_OPCODE = 0x00ab,
187 };
188
189 namespace SH4Registers {
190 typedef enum {
191 r0,
192 r1,
193 r2,
194 r3,
195 r4,
196 r5,
197 r6,
198 r7,
199 r8,
200 r9,
201 r10,
202 r11,
203 r12,
204 r13,
205 r14, fp = r14,
206 r15, sp = r15,
207 pc,
208 pr,
209 } RegisterID;
210
211 typedef enum {
212 fr0, dr0 = fr0,
213 fr1,
214 fr2, dr2 = fr2,
215 fr3,
216 fr4, dr4 = fr4,
217 fr5,
218 fr6, dr6 = fr6,
219 fr7,
220 fr8, dr8 = fr8,
221 fr9,
222 fr10, dr10 = fr10,
223 fr11,
224 fr12, dr12 = fr12,
225 fr13,
226 fr14, dr14 = fr14,
227 fr15,
228 } FPRegisterID;
229 }
230
231 inline uint16_t getOpcodeGroup1(uint16_t opc, int rm, int rn)
232 {
233 return (opc | ((rm & 0xf) << 8) | ((rn & 0xf) << 4));
234 }
235
236 inline uint16_t getOpcodeGroup2(uint16_t opc, int rm)
237 {
238 return (opc | ((rm & 0xf) << 8));
239 }
240
241 inline uint16_t getOpcodeGroup3(uint16_t opc, int rm, int rn)
242 {
243 return (opc | ((rm & 0xf) << 8) | (rn & 0xff));
244 }
245
246 inline uint16_t getOpcodeGroup4(uint16_t opc, int rm, int rn, int offset)
247 {
248 return (opc | ((rm & 0xf) << 8) | ((rn & 0xf) << 4) | (offset & 0xf));
249 }
250
251 inline uint16_t getOpcodeGroup5(uint16_t opc, int rm)
252 {
253 return (opc | (rm & 0xff));
254 }
255
256 inline uint16_t getOpcodeGroup6(uint16_t opc, int rm)
257 {
258 return (opc | (rm & 0xfff));
259 }
260
261 inline uint16_t getOpcodeGroup7(uint16_t opc, int rm)
262 {
263 return (opc | ((rm & 0x7) << 9));
264 }
265
266 inline uint16_t getOpcodeGroup8(uint16_t opc, int rm, int rn)
267 {
268 return (opc | ((rm & 0x7) << 9) | ((rn & 0x7) << 5));
269 }
270
271 inline uint16_t getOpcodeGroup9(uint16_t opc, int rm, int rn)
272 {
273 return (opc | ((rm & 0xf) << 8) | ((rn & 0x7) << 5));
274 }
275
276 inline uint16_t getOpcodeGroup10(uint16_t opc, int rm, int rn)
277 {
278 return (opc | ((rm & 0x7) << 9) | ((rn & 0xf) << 4));
279 }
280
281 inline uint16_t getOpcodeGroup11(uint16_t opc, int rm, int rn)
282 {
283 return (opc | ((rm & 0xf) << 4) | (rn & 0xf));
284 }
285
286 inline uint16_t getRn(uint16_t x)
287 {
288 return ((x & 0xf00) >> 8);
289 }
290
291 inline uint16_t getRm(uint16_t x)
292 {
293 return ((x & 0xf0) >> 4);
294 }
295
296 inline uint16_t getDisp(uint16_t x)
297 {
298 return (x & 0xf);
299 }
300
301 inline uint16_t getImm8(uint16_t x)
302 {
303 return (x & 0xff);
304 }
305
306 inline uint16_t getImm12(uint16_t x)
307 {
308 return (x & 0xfff);
309 }
310
311 inline uint16_t getDRn(uint16_t x)
312 {
313 return ((x & 0xe00) >> 9);
314 }
315
316 inline uint16_t getDRm(uint16_t x)
317 {
318 return ((x & 0xe0) >> 5);
319 }
320
321 class SH4Assembler {
322 public:
323 typedef SH4Registers::RegisterID RegisterID;
324 typedef SH4Registers::FPRegisterID FPRegisterID;
325 typedef AssemblerBufferWithConstantPool<512, 4, 2, SH4Assembler> SH4Buffer;
326 static const RegisterID scratchReg1 = SH4Registers::r3;
327 static const RegisterID scratchReg2 = SH4Registers::r11;
328 static const uint32_t maxInstructionSize = 16;
329
330 static RegisterID firstRegister() { return SH4Registers::r0; }
331 static RegisterID lastRegister() { return SH4Registers::r15; }
332
333 static FPRegisterID firstFPRegister() { return SH4Registers::dr0; }
334 static FPRegisterID lastFPRegister() { return SH4Registers::dr14; }
335
336 enum {
337 padForAlign8 = 0x00,
338 padForAlign16 = 0x0009,
339 padForAlign32 = 0x00090009,
340 };
341
342 enum JumpType {
343 JumpFar,
344 JumpNear
345 };
346
347 SH4Assembler()
348 : m_claimscratchReg(0x0)
349 , m_indexOfLastWatchpoint(INT_MIN)
350 , m_indexOfTailOfLastWatchpoint(INT_MIN)
351 {
352 }
353
354 SH4Buffer& buffer() { return m_buffer; }
355
356 // SH4 condition codes
357 typedef enum {
358 EQ = 0x0, // Equal
359 NE = 0x1, // Not Equal
360 HS = 0x2, // Unsigned Greater Than equal
361 HI = 0x3, // Unsigned Greater Than
362 LS = 0x4, // Unsigned Lower or Same
363 LI = 0x5, // Unsigned Lower
364 GE = 0x6, // Greater or Equal
365 LT = 0x7, // Less Than
366 GT = 0x8, // Greater Than
367 LE = 0x9, // Less or Equal
368 OF = 0xa, // OverFlow
369 SI = 0xb, // Signed
370 NS = 0xc, // Not Signed
371 EQU= 0xd, // Equal or unordered(NaN)
372 NEU= 0xe,
373 GTU= 0xf,
374 GEU= 0x10,
375 LTU= 0x11,
376 LEU= 0x12,
377 } Condition;
378
379 // Opaque label types
380 public:
381 bool isImmediate(int constant)
382 {
383 return ((constant <= 127) && (constant >= -128));
384 }
385
386 RegisterID claimScratch()
387 {
388 ASSERT((m_claimscratchReg != 0x3));
389
390 if (!(m_claimscratchReg & 0x1)) {
391 m_claimscratchReg = (m_claimscratchReg | 0x1);
392 return scratchReg1;
393 }
394
395 m_claimscratchReg = (m_claimscratchReg | 0x2);
396 return scratchReg2;
397 }
398
399 void releaseScratch(RegisterID scratchR)
400 {
401 if (scratchR == scratchReg1)
402 m_claimscratchReg = (m_claimscratchReg & 0x2);
403 else
404 m_claimscratchReg = (m_claimscratchReg & 0x1);
405 }
406
407 // Stack operations
408
409 void pushReg(RegisterID reg)
410 {
411 if (reg == SH4Registers::pr) {
412 oneShortOp(getOpcodeGroup2(STSLPR_OPCODE, SH4Registers::sp));
413 return;
414 }
415
416 oneShortOp(getOpcodeGroup1(MOVL_WRITE_RNDEC_OPCODE, SH4Registers::sp, reg));
417 }
418
419 void popReg(RegisterID reg)
420 {
421 if (reg == SH4Registers::pr) {
422 oneShortOp(getOpcodeGroup2(LDSLPR_OPCODE, SH4Registers::sp));
423 return;
424 }
425
426 oneShortOp(getOpcodeGroup1(MOVL_READ_RMINC_OPCODE, reg, SH4Registers::sp));
427 }
428
429 void movt(RegisterID dst)
430 {
431 uint16_t opc = getOpcodeGroup2(MOVT_OPCODE, dst);
432 oneShortOp(opc);
433 }
434
435 // Arithmetic operations
436
437 void addlRegReg(RegisterID src, RegisterID dst)
438 {
439 uint16_t opc = getOpcodeGroup1(ADD_OPCODE, dst, src);
440 oneShortOp(opc);
441 }
442
443 void addclRegReg(RegisterID src, RegisterID dst)
444 {
445 uint16_t opc = getOpcodeGroup1(ADDC_OPCODE, dst, src);
446 oneShortOp(opc);
447 }
448
449 void addvlRegReg(RegisterID src, RegisterID dst)
450 {
451 uint16_t opc = getOpcodeGroup1(ADDV_OPCODE, dst, src);
452 oneShortOp(opc);
453 }
454
455 void addlImm8r(int imm8, RegisterID dst)
456 {
457 ASSERT((imm8 <= 127) && (imm8 >= -128));
458
459 uint16_t opc = getOpcodeGroup3(ADDIMM_OPCODE, dst, imm8);
460 oneShortOp(opc);
461 }
462
463 void andlRegReg(RegisterID src, RegisterID dst)
464 {
465 uint16_t opc = getOpcodeGroup1(AND_OPCODE, dst, src);
466 oneShortOp(opc);
467 }
468
469 void andlImm8r(int imm8, RegisterID dst)
470 {
471 ASSERT((imm8 <= 255) && (imm8 >= 0));
472 ASSERT_UNUSED(dst, dst == SH4Registers::r0);
473
474 uint16_t opc = getOpcodeGroup5(ANDIMM_OPCODE, imm8);
475 oneShortOp(opc);
476 }
477
478 void div1lRegReg(RegisterID src, RegisterID dst)
479 {
480 uint16_t opc = getOpcodeGroup1(DIV1_OPCODE, dst, src);
481 oneShortOp(opc);
482 }
483
484 void div0lRegReg(RegisterID src, RegisterID dst)
485 {
486 uint16_t opc = getOpcodeGroup1(DIV0_OPCODE, dst, src);
487 oneShortOp(opc);
488 }
489
490 void notlReg(RegisterID src, RegisterID dst)
491 {
492 uint16_t opc = getOpcodeGroup1(NOT_OPCODE, dst, src);
493 oneShortOp(opc);
494 }
495
496 void orlRegReg(RegisterID src, RegisterID dst)
497 {
498 uint16_t opc = getOpcodeGroup1(OR_OPCODE, dst, src);
499 oneShortOp(opc);
500 }
501
502 void orlImm8r(int imm8, RegisterID dst)
503 {
504 ASSERT((imm8 <= 255) && (imm8 >= 0));
505 ASSERT_UNUSED(dst, dst == SH4Registers::r0);
506
507 uint16_t opc = getOpcodeGroup5(ORIMM_OPCODE, imm8);
508 oneShortOp(opc);
509 }
510
511 void sublRegReg(RegisterID src, RegisterID dst)
512 {
513 uint16_t opc = getOpcodeGroup1(SUB_OPCODE, dst, src);
514 oneShortOp(opc);
515 }
516
517 void subvlRegReg(RegisterID src, RegisterID dst)
518 {
519 uint16_t opc = getOpcodeGroup1(SUBV_OPCODE, dst, src);
520 oneShortOp(opc);
521 }
522
523 void xorlRegReg(RegisterID src, RegisterID dst)
524 {
525 uint16_t opc = getOpcodeGroup1(XOR_OPCODE, dst, src);
526 oneShortOp(opc);
527 }
528
529 void xorlImm8r(int imm8, RegisterID dst)
530 {
531 ASSERT((imm8 <= 255) && (imm8 >= 0));
532 ASSERT_UNUSED(dst, dst == SH4Registers::r0);
533
534 uint16_t opc = getOpcodeGroup5(XORIMM_OPCODE, imm8);
535 oneShortOp(opc);
536 }
537
538 void shllImm8r(int imm, RegisterID dst)
539 {
540 switch (imm) {
541 case 1:
542 oneShortOp(getOpcodeGroup2(SHLL_OPCODE, dst));
543 break;
544 case 2:
545 oneShortOp(getOpcodeGroup2(SHLL2_OPCODE, dst));
546 break;
547 case 8:
548 oneShortOp(getOpcodeGroup2(SHLL8_OPCODE, dst));
549 break;
550 case 16:
551 oneShortOp(getOpcodeGroup2(SHLL16_OPCODE, dst));
552 break;
553 default:
554 RELEASE_ASSERT_NOT_REACHED();
555 }
556 }
557
558 void neg(RegisterID dst, RegisterID src)
559 {
560 uint16_t opc = getOpcodeGroup1(NEG_OPCODE, dst, src);
561 oneShortOp(opc);
562 }
563
564 void shldRegReg(RegisterID dst, RegisterID rShift)
565 {
566 oneShortOp(getOpcodeGroup1(SHLD_OPCODE, dst, rShift));
567 }
568
569 void shadRegReg(RegisterID dst, RegisterID rShift)
570 {
571 oneShortOp(getOpcodeGroup1(SHAD_OPCODE, dst, rShift));
572 }
573
574 void shlrImm8r(int imm, RegisterID dst)
575 {
576 switch (imm) {
577 case 1:
578 oneShortOp(getOpcodeGroup2(SHLR_OPCODE, dst));
579 break;
580 case 2:
581 oneShortOp(getOpcodeGroup2(SHLR2_OPCODE, dst));
582 break;
583 case 8:
584 oneShortOp(getOpcodeGroup2(SHLR8_OPCODE, dst));
585 break;
586 case 16:
587 oneShortOp(getOpcodeGroup2(SHLR16_OPCODE, dst));
588 break;
589 default:
590 RELEASE_ASSERT_NOT_REACHED();
591 }
592 }
593
594 void shalImm8r(int imm, RegisterID dst)
595 {
596 switch (imm) {
597 case 1:
598 oneShortOp(getOpcodeGroup2(SHAL_OPCODE, dst));
599 break;
600 default:
601 RELEASE_ASSERT_NOT_REACHED();
602 }
603 }
604
605 void sharImm8r(int imm, RegisterID dst)
606 {
607 switch (imm) {
608 case 1:
609 oneShortOp(getOpcodeGroup2(SHAR_OPCODE, dst));
610 break;
611 default:
612 RELEASE_ASSERT_NOT_REACHED();
613 }
614 }
615
616 void imullRegReg(RegisterID src, RegisterID dst)
617 {
618 uint16_t opc = getOpcodeGroup1(MULL_OPCODE, dst, src);
619 oneShortOp(opc);
620 }
621
622 void dmullRegReg(RegisterID src, RegisterID dst)
623 {
624 uint16_t opc = getOpcodeGroup1(DMULL_L_OPCODE, dst, src);
625 oneShortOp(opc);
626 }
627
628 void dmulslRegReg(RegisterID src, RegisterID dst)
629 {
630 uint16_t opc = getOpcodeGroup1(DMULSL_OPCODE, dst, src);
631 oneShortOp(opc);
632 }
633
634 void stsmacl(RegisterID reg)
635 {
636 uint16_t opc = getOpcodeGroup2(STSMACL_OPCODE, reg);
637 oneShortOp(opc);
638 }
639
640 void stsmach(RegisterID reg)
641 {
642 uint16_t opc = getOpcodeGroup2(STSMACH_OPCODE, reg);
643 oneShortOp(opc);
644 }
645
646 // Comparisons
647
648 void cmplRegReg(RegisterID left, RegisterID right, Condition cond)
649 {
650 switch (cond) {
651 case NE:
652 oneShortOp(getOpcodeGroup1(CMPEQ_OPCODE, right, left));
653 break;
654 case GT:
655 oneShortOp(getOpcodeGroup1(CMPGT_OPCODE, right, left));
656 break;
657 case EQ:
658 oneShortOp(getOpcodeGroup1(CMPEQ_OPCODE, right, left));
659 break;
660 case GE:
661 oneShortOp(getOpcodeGroup1(CMPGE_OPCODE, right, left));
662 break;
663 case HS:
664 oneShortOp(getOpcodeGroup1(CMPHS_OPCODE, right, left));
665 break;
666 case HI:
667 oneShortOp(getOpcodeGroup1(CMPHI_OPCODE, right, left));
668 break;
669 case LI:
670 oneShortOp(getOpcodeGroup1(CMPHI_OPCODE, left, right));
671 break;
672 case LS:
673 oneShortOp(getOpcodeGroup1(CMPHS_OPCODE, left, right));
674 break;
675 case LE:
676 oneShortOp(getOpcodeGroup1(CMPGE_OPCODE, left, right));
677 break;
678 case LT:
679 oneShortOp(getOpcodeGroup1(CMPGT_OPCODE, left, right));
680 break;
681 default:
682 RELEASE_ASSERT_NOT_REACHED();
683 }
684 }
685
686 void cmppl(RegisterID reg)
687 {
688 uint16_t opc = getOpcodeGroup2(CMPPL_OPCODE, reg);
689 oneShortOp(opc);
690 }
691
692 void cmppz(RegisterID reg)
693 {
694 uint16_t opc = getOpcodeGroup2(CMPPZ_OPCODE, reg);
695 oneShortOp(opc);
696 }
697
698 void cmpEqImmR0(int imm, RegisterID dst)
699 {
700 ASSERT_UNUSED(dst, dst == SH4Registers::r0);
701 uint16_t opc = getOpcodeGroup5(CMPEQIMM_OPCODE, imm);
702 oneShortOp(opc);
703 }
704
705 void testlRegReg(RegisterID src, RegisterID dst)
706 {
707 uint16_t opc = getOpcodeGroup1(TST_OPCODE, dst, src);
708 oneShortOp(opc);
709 }
710
711 void testlImm8r(int imm, RegisterID dst)
712 {
713 ASSERT((imm <= 255) && (imm >= 0));
714 ASSERT_UNUSED(dst, dst == SH4Registers::r0);
715
716 uint16_t opc = getOpcodeGroup5(TSTIMM_OPCODE, imm);
717 oneShortOp(opc);
718 }
719
720 void nop()
721 {
722 oneShortOp(NOP_OPCODE, false);
723 }
724
725 void synco()
726 {
727 oneShortOp(SYNCO_OPCODE);
728 }
729
730 void sett()
731 {
732 oneShortOp(SETT_OPCODE);
733 }
734
735 void clrt()
736 {
737 oneShortOp(CLRT_OPCODE);
738 }
739
740 void fschg()
741 {
742 oneShortOp(FSCHG_OPCODE);
743 }
744
745 void bkpt()
746 {
747 oneShortOp(BRK_OPCODE, false);
748 }
749
750 void branch(uint16_t opc, int label)
751 {
752 switch (opc) {
753 case BT_OPCODE:
754 ASSERT((label <= 127) && (label >= -128));
755 oneShortOp(getOpcodeGroup5(BT_OPCODE, label));
756 break;
757 case BRA_OPCODE:
758 ASSERT((label <= 2047) && (label >= -2048));
759 oneShortOp(getOpcodeGroup6(BRA_OPCODE, label));
760 break;
761 case BF_OPCODE:
762 ASSERT((label <= 127) && (label >= -128));
763 oneShortOp(getOpcodeGroup5(BF_OPCODE, label));
764 break;
765 default:
766 RELEASE_ASSERT_NOT_REACHED();
767 }
768 }
769
770 void branch(uint16_t opc, RegisterID reg)
771 {
772 switch (opc) {
773 case BRAF_OPCODE:
774 oneShortOp(getOpcodeGroup2(BRAF_OPCODE, reg));
775 break;
776 case JMP_OPCODE:
777 oneShortOp(getOpcodeGroup2(JMP_OPCODE, reg));
778 break;
779 case JSR_OPCODE:
780 oneShortOp(getOpcodeGroup2(JSR_OPCODE, reg));
781 break;
782 case BSRF_OPCODE:
783 oneShortOp(getOpcodeGroup2(BSRF_OPCODE, reg));
784 break;
785 default:
786 RELEASE_ASSERT_NOT_REACHED();
787 }
788 }
789
790 void ldspr(RegisterID reg)
791 {
792 uint16_t opc = getOpcodeGroup2(LDSPR_OPCODE, reg);
793 oneShortOp(opc);
794 }
795
796 void stspr(RegisterID reg)
797 {
798 uint16_t opc = getOpcodeGroup2(STSPR_OPCODE, reg);
799 oneShortOp(opc);
800 }
801
802 void extub(RegisterID src, RegisterID dst)
803 {
804 uint16_t opc = getOpcodeGroup1(EXTUB_OPCODE, dst, src);
805 oneShortOp(opc);
806 }
807
808 void extuw(RegisterID src, RegisterID dst)
809 {
810 uint16_t opc = getOpcodeGroup1(EXTUW_OPCODE, dst, src);
811 oneShortOp(opc);
812 }
813
814 // float operations
815
816 void ldsrmfpul(RegisterID src)
817 {
818 uint16_t opc = getOpcodeGroup2(LDS_RM_FPUL_OPCODE, src);
819 oneShortOp(opc);
820 }
821
822 void fneg(FPRegisterID dst)
823 {
824 uint16_t opc = getOpcodeGroup2(FNEG_OPCODE, dst);
825 oneShortOp(opc, true, false);
826 }
827
828 void fsqrt(FPRegisterID dst)
829 {
830 uint16_t opc = getOpcodeGroup2(FSQRT_OPCODE, dst);
831 oneShortOp(opc, true, false);
832 }
833
834 void stsfpulReg(RegisterID src)
835 {
836 uint16_t opc = getOpcodeGroup2(STS_FPUL_RN_OPCODE, src);
837 oneShortOp(opc);
838 }
839
840 void floatfpulfrn(FPRegisterID src)
841 {
842 uint16_t opc = getOpcodeGroup2(FLOAT_OPCODE, src);
843 oneShortOp(opc, true, false);
844 }
845
846 void fmull(FPRegisterID src, FPRegisterID dst)
847 {
848 uint16_t opc = getOpcodeGroup1(FMUL_OPCODE, dst, src);
849 oneShortOp(opc, true, false);
850 }
851
852 void fmovsRegReg(FPRegisterID src, FPRegisterID dst)
853 {
854 uint16_t opc = getOpcodeGroup1(FMOV_OPCODE, dst, src);
855 oneShortOp(opc, true, false);
856 }
857
858 void fmovsReadrm(RegisterID src, FPRegisterID dst)
859 {
860 uint16_t opc = getOpcodeGroup1(FMOVS_READ_RM_OPCODE, dst, src);
861 oneShortOp(opc, true, false);
862 }
863
864 void fmovsWriterm(FPRegisterID src, RegisterID dst)
865 {
866 uint16_t opc = getOpcodeGroup1(FMOVS_WRITE_RN_OPCODE, dst, src);
867 oneShortOp(opc, true, false);
868 }
869
870 void fmovsWriter0r(FPRegisterID src, RegisterID dst)
871 {
872 uint16_t opc = getOpcodeGroup1(FMOVS_WRITE_R0RN_OPCODE, dst, src);
873 oneShortOp(opc, true, false);
874 }
875
876 void fmovsReadr0r(RegisterID src, FPRegisterID dst)
877 {
878 uint16_t opc = getOpcodeGroup1(FMOVS_READ_R0RM_OPCODE, dst, src);
879 oneShortOp(opc, true, false);
880 }
881
882 void fmovsReadrminc(RegisterID src, FPRegisterID dst)
883 {
884 uint16_t opc = getOpcodeGroup1(FMOVS_READ_RM_INC_OPCODE, dst, src);
885 oneShortOp(opc, true, false);
886 }
887
888 void fmovsWriterndec(FPRegisterID src, RegisterID dst)
889 {
890 uint16_t opc = getOpcodeGroup1(FMOVS_WRITE_RN_DEC_OPCODE, dst, src);
891 oneShortOp(opc, true, false);
892 }
893
894 void ftrcRegfpul(FPRegisterID src)
895 {
896 uint16_t opc = getOpcodeGroup2(FTRC_OPCODE, src);
897 oneShortOp(opc, true, false);
898 }
899
900 void fldsfpul(FPRegisterID src)
901 {
902 uint16_t opc = getOpcodeGroup2(FLDS_FRM_FPUL_OPCODE, src);
903 oneShortOp(opc);
904 }
905
906 void fstsfpul(FPRegisterID src)
907 {
908 uint16_t opc = getOpcodeGroup2(FSTS_FPUL_FRN_OPCODE, src);
909 oneShortOp(opc);
910 }
911
912 void ldsfpscr(RegisterID reg)
913 {
914 uint16_t opc = getOpcodeGroup2(LDSFPSCR_OPCODE, reg);
915 oneShortOp(opc);
916 }
917
918 void stsfpscr(RegisterID reg)
919 {
920 uint16_t opc = getOpcodeGroup2(STSFPSCR_OPCODE, reg);
921 oneShortOp(opc);
922 }
923
924 // double operations
925
926 void dcnvds(FPRegisterID src)
927 {
928 uint16_t opc = getOpcodeGroup7(FCNVDS_DRM_FPUL_OPCODE, src >> 1);
929 oneShortOp(opc);
930 }
931
932 void dcnvsd(FPRegisterID dst)
933 {
934 uint16_t opc = getOpcodeGroup7(FCNVSD_FPUL_DRN_OPCODE, dst >> 1);
935 oneShortOp(opc);
936 }
937
938 void dcmppeq(FPRegisterID src, FPRegisterID dst)
939 {
940 uint16_t opc = getOpcodeGroup8(FCMPEQ_OPCODE, dst >> 1, src >> 1);
941 oneShortOp(opc);
942 }
943
944 void dcmppgt(FPRegisterID src, FPRegisterID dst)
945 {
946 uint16_t opc = getOpcodeGroup8(FCMPGT_OPCODE, dst >> 1, src >> 1);
947 oneShortOp(opc);
948 }
949
950 void dmulRegReg(FPRegisterID src, FPRegisterID dst)
951 {
952 uint16_t opc = getOpcodeGroup8(FMUL_OPCODE, dst >> 1, src >> 1);
953 oneShortOp(opc);
954 }
955
956 void dsubRegReg(FPRegisterID src, FPRegisterID dst)
957 {
958 uint16_t opc = getOpcodeGroup8(FSUB_OPCODE, dst >> 1, src >> 1);
959 oneShortOp(opc);
960 }
961
962 void daddRegReg(FPRegisterID src, FPRegisterID dst)
963 {
964 uint16_t opc = getOpcodeGroup8(FADD_OPCODE, dst >> 1, src >> 1);
965 oneShortOp(opc);
966 }
967
968 void dmovRegReg(FPRegisterID src, FPRegisterID dst)
969 {
970 uint16_t opc = getOpcodeGroup8(FMOV_OPCODE, dst >> 1, src >> 1);
971 oneShortOp(opc);
972 }
973
974 void ddivRegReg(FPRegisterID src, FPRegisterID dst)
975 {
976 uint16_t opc = getOpcodeGroup8(FDIV_OPCODE, dst >> 1, src >> 1);
977 oneShortOp(opc);
978 }
979
980 void dabs(FPRegisterID dst)
981 {
982 uint16_t opc = getOpcodeGroup7(FABS_OPCODE, dst >> 1);
983 oneShortOp(opc);
984 }
985
986 void dsqrt(FPRegisterID dst)
987 {
988 uint16_t opc = getOpcodeGroup7(FSQRT_OPCODE, dst >> 1);
989 oneShortOp(opc);
990 }
991
992 void dneg(FPRegisterID dst)
993 {
994 uint16_t opc = getOpcodeGroup7(FNEG_OPCODE, dst >> 1);
995 oneShortOp(opc);
996 }
997
998 void fmovReadrm(RegisterID src, FPRegisterID dst)
999 {
1000 uint16_t opc = getOpcodeGroup10(FMOVS_READ_RM_OPCODE, dst >> 1, src);
1001 oneShortOp(opc);
1002 }
1003
1004 void fmovWriterm(FPRegisterID src, RegisterID dst)
1005 {
1006 uint16_t opc = getOpcodeGroup9(FMOVS_WRITE_RN_OPCODE, dst, src >> 1);
1007 oneShortOp(opc);
1008 }
1009
1010 void fmovWriter0r(FPRegisterID src, RegisterID dst)
1011 {
1012 uint16_t opc = getOpcodeGroup9(FMOVS_WRITE_R0RN_OPCODE, dst, src >> 1);
1013 oneShortOp(opc);
1014 }
1015
1016 void fmovReadr0r(RegisterID src, FPRegisterID dst)
1017 {
1018 uint16_t opc = getOpcodeGroup10(FMOVS_READ_R0RM_OPCODE, dst >> 1, src);
1019 oneShortOp(opc);
1020 }
1021
1022 void fmovReadrminc(RegisterID src, FPRegisterID dst)
1023 {
1024 uint16_t opc = getOpcodeGroup10(FMOVS_READ_RM_INC_OPCODE, dst >> 1, src);
1025 oneShortOp(opc);
1026 }
1027
1028 void fmovWriterndec(FPRegisterID src, RegisterID dst)
1029 {
1030 uint16_t opc = getOpcodeGroup9(FMOVS_WRITE_RN_DEC_OPCODE, dst, src >> 1);
1031 oneShortOp(opc);
1032 }
1033
1034 void floatfpulDreg(FPRegisterID src)
1035 {
1036 uint16_t opc = getOpcodeGroup7(FLOAT_OPCODE, src >> 1);
1037 oneShortOp(opc);
1038 }
1039
1040 void ftrcdrmfpul(FPRegisterID src)
1041 {
1042 uint16_t opc = getOpcodeGroup7(FTRC_OPCODE, src >> 1);
1043 oneShortOp(opc);
1044 }
1045
1046 // Various move ops
1047
1048 void movImm8(int imm8, RegisterID dst)
1049 {
1050 ASSERT((imm8 <= 127) && (imm8 >= -128));
1051
1052 uint16_t opc = getOpcodeGroup3(MOVIMM_OPCODE, dst, imm8);
1053 oneShortOp(opc);
1054 }
1055
1056 void movlRegReg(RegisterID src, RegisterID dst)
1057 {
1058 uint16_t opc = getOpcodeGroup1(MOV_OPCODE, dst, src);
1059 oneShortOp(opc);
1060 }
1061
1062 void movwRegMem(RegisterID src, RegisterID dst)
1063 {
1064 uint16_t opc = getOpcodeGroup1(MOVW_WRITE_RN_OPCODE, dst, src);
1065 oneShortOp(opc);
1066 }
1067
1068 void movwMemReg(RegisterID src, RegisterID dst)
1069 {
1070 uint16_t opc = getOpcodeGroup1(MOVW_READ_RM_OPCODE, dst, src);
1071 oneShortOp(opc);
1072 }
1073
1074 void movwMemRegIn(RegisterID base, RegisterID dst)
1075 {
1076 uint16_t opc = getOpcodeGroup1(MOVW_READ_RMINC_OPCODE, dst, base);
1077 oneShortOp(opc);
1078 }
1079
1080 void movwPCReg(int offset, RegisterID base, RegisterID dst)
1081 {
1082 ASSERT_UNUSED(base, base == SH4Registers::pc);
1083 ASSERT((offset <= 255) && (offset >= 0));
1084
1085 uint16_t opc = getOpcodeGroup3(MOVW_READ_OFFPC_OPCODE, dst, offset);
1086 oneShortOp(opc);
1087 }
1088
1089 void movwMemReg(int offset, RegisterID base, RegisterID dst)
1090 {
1091 ASSERT_UNUSED(dst, dst == SH4Registers::r0);
1092
1093 uint16_t opc = getOpcodeGroup11(MOVW_READ_OFFRM_OPCODE, base, offset);
1094 oneShortOp(opc);
1095 }
1096
1097 void movwR0mr(RegisterID src, RegisterID dst)
1098 {
1099 uint16_t opc = getOpcodeGroup1(MOVW_READ_R0RM_OPCODE, dst, src);
1100 oneShortOp(opc);
1101 }
1102
1103 void movwRegMemr0(RegisterID src, RegisterID dst)
1104 {
1105 uint16_t opc = getOpcodeGroup1(MOVW_WRITE_R0RN_OPCODE, dst, src);
1106 oneShortOp(opc);
1107 }
1108
1109 void movlRegMem(RegisterID src, int offset, RegisterID base)
1110 {
1111 ASSERT((offset <= 15) && (offset >= 0));
1112
1113 if (!offset) {
1114 oneShortOp(getOpcodeGroup1(MOVL_WRITE_RN_OPCODE, base, src));
1115 return;
1116 }
1117
1118 oneShortOp(getOpcodeGroup4(MOVL_WRITE_OFFRN_OPCODE, base, src, offset));
1119 }
1120
1121 void movlRegMem(RegisterID src, RegisterID base)
1122 {
1123 uint16_t opc = getOpcodeGroup1(MOVL_WRITE_RN_OPCODE, base, src);
1124 oneShortOp(opc);
1125 }
1126
1127 void movlMemReg(int offset, RegisterID base, RegisterID dst)
1128 {
1129 if (base == SH4Registers::pc) {
1130 ASSERT((offset <= 255) && (offset >= 0));
1131 oneShortOp(getOpcodeGroup3(MOVL_READ_OFFPC_OPCODE, dst, offset));
1132 return;
1133 }
1134
1135 ASSERT((offset <= 15) && (offset >= 0));
1136 if (!offset) {
1137 oneShortOp(getOpcodeGroup1(MOVL_READ_RM_OPCODE, dst, base));
1138 return;
1139 }
1140
1141 oneShortOp(getOpcodeGroup4(MOVL_READ_OFFRM_OPCODE, dst, base, offset));
1142 }
1143
1144 void movlMemRegCompact(int offset, RegisterID base, RegisterID dst)
1145 {
1146 oneShortOp(getOpcodeGroup4(MOVL_READ_OFFRM_OPCODE, dst, base, offset));
1147 }
1148
1149 void movbRegMem(RegisterID src, RegisterID base)
1150 {
1151 uint16_t opc = getOpcodeGroup1(MOVB_WRITE_RN_OPCODE, base, src);
1152 oneShortOp(opc);
1153 }
1154
1155 void movbMemReg(int offset, RegisterID base, RegisterID dst)
1156 {
1157 ASSERT_UNUSED(dst, dst == SH4Registers::r0);
1158
1159 uint16_t opc = getOpcodeGroup11(MOVB_READ_OFFRM_OPCODE, base, offset);
1160 oneShortOp(opc);
1161 }
1162
1163 void movbR0mr(RegisterID src, RegisterID dst)
1164 {
1165 uint16_t opc = getOpcodeGroup1(MOVB_READ_R0RM_OPCODE, dst, src);
1166 oneShortOp(opc);
1167 }
1168
1169 void movbMemReg(RegisterID src, RegisterID dst)
1170 {
1171 uint16_t opc = getOpcodeGroup1(MOVB_READ_RM_OPCODE, dst, src);
1172 oneShortOp(opc);
1173 }
1174
1175 void movbMemRegIn(RegisterID base, RegisterID dst)
1176 {
1177 uint16_t opc = getOpcodeGroup1(MOVB_READ_RMINC_OPCODE, dst, base);
1178 oneShortOp(opc);
1179 }
1180
1181 void movbRegMemr0(RegisterID src, RegisterID dst)
1182 {
1183 uint16_t opc = getOpcodeGroup1(MOVB_WRITE_R0RN_OPCODE, dst, src);
1184 oneShortOp(opc);
1185 }
1186
1187 void movlMemReg(RegisterID base, RegisterID dst)
1188 {
1189 uint16_t opc = getOpcodeGroup1(MOVL_READ_RM_OPCODE, dst, base);
1190 oneShortOp(opc);
1191 }
1192
1193 void movlMemRegIn(RegisterID base, RegisterID dst)
1194 {
1195 uint16_t opc = getOpcodeGroup1(MOVL_READ_RMINC_OPCODE, dst, base);
1196 oneShortOp(opc);
1197 }
1198
1199 void movlR0mr(RegisterID src, RegisterID dst)
1200 {
1201 uint16_t opc = getOpcodeGroup1(MOVL_READ_R0RM_OPCODE, dst, src);
1202 oneShortOp(opc);
1203 }
1204
1205 void movlRegMemr0(RegisterID src, RegisterID dst)
1206 {
1207 uint16_t opc = getOpcodeGroup1(MOVL_WRITE_R0RN_OPCODE, dst, src);
1208 oneShortOp(opc);
1209 }
1210
1211 void loadConstant(uint32_t constant, RegisterID dst)
1212 {
1213 if (((int)constant <= 0x7f) && ((int)constant >= -0x80)) {
1214 movImm8(constant, dst);
1215 return;
1216 }
1217
1218 uint16_t opc = getOpcodeGroup3(MOVIMM_OPCODE, dst, 0);
1219
1220 m_buffer.ensureSpace(maxInstructionSize, sizeof(uint32_t));
1221 printInstr(getOpcodeGroup3(MOVIMM_OPCODE, dst, constant), m_buffer.codeSize());
1222 m_buffer.putShortWithConstantInt(opc, constant, true);
1223 }
1224
1225 void loadConstantUnReusable(uint32_t constant, RegisterID dst, bool ensureSpace = false)
1226 {
1227 uint16_t opc = getOpcodeGroup3(MOVIMM_OPCODE, dst, 0);
1228
1229 if (ensureSpace)
1230 m_buffer.ensureSpace(maxInstructionSize, sizeof(uint32_t));
1231
1232 printInstr(getOpcodeGroup3(MOVIMM_OPCODE, dst, constant), m_buffer.codeSize());
1233 m_buffer.putShortWithConstantInt(opc, constant);
1234 }
1235
1236 // Flow control
1237
1238 AssemblerLabel call()
1239 {
1240 RegisterID scr = claimScratch();
1241 m_buffer.ensureSpace(maxInstructionSize + 4, sizeof(uint32_t));
1242 loadConstantUnReusable(0x0, scr);
1243 branch(JSR_OPCODE, scr);
1244 nop();
1245 releaseScratch(scr);
1246 return m_buffer.label();
1247 }
1248
1249 AssemblerLabel call(RegisterID dst)
1250 {
1251 m_buffer.ensureSpace(maxInstructionSize + 2);
1252 branch(JSR_OPCODE, dst);
1253 nop();
1254 return m_buffer.label();
1255 }
1256
1257 AssemblerLabel jmp()
1258 {
1259 RegisterID scr = claimScratch();
1260 m_buffer.ensureSpace(maxInstructionSize + 4, sizeof(uint32_t));
1261 loadConstantUnReusable(0x0, scr);
1262 branch(BRAF_OPCODE, scr);
1263 nop();
1264 releaseScratch(scr);
1265 return m_buffer.label();
1266 }
1267
1268 AssemblerLabel extraInstrForBranch(RegisterID dst)
1269 {
1270 loadConstantUnReusable(0x0, dst);
1271 branch(BRAF_OPCODE, dst);
1272 nop();
1273 return m_buffer.label();
1274 }
1275
1276 AssemblerLabel jmp(RegisterID dst)
1277 {
1278 jmpReg(dst);
1279 return m_buffer.label();
1280 }
1281
1282 void jmpReg(RegisterID dst)
1283 {
1284 m_buffer.ensureSpace(maxInstructionSize + 2);
1285 branch(JMP_OPCODE, dst);
1286 nop();
1287 }
1288
1289 AssemblerLabel jne()
1290 {
1291 branch(BF_OPCODE, 0);
1292 return m_buffer.label();
1293 }
1294
1295 AssemblerLabel je()
1296 {
1297 branch(BT_OPCODE, 0);
1298 return m_buffer.label();
1299 }
1300
1301 AssemblerLabel bra()
1302 {
1303 branch(BRA_OPCODE, 0);
1304 return m_buffer.label();
1305 }
1306
1307 void ret()
1308 {
1309 m_buffer.ensureSpace(maxInstructionSize + 2);
1310 oneShortOp(RTS_OPCODE, false);
1311 }
1312
1313 AssemblerLabel labelIgnoringWatchpoints()
1314 {
1315 m_buffer.ensureSpaceForAnyInstruction();
1316 return m_buffer.label();
1317 }
1318
1319 AssemblerLabel labelForWatchpoint()
1320 {
1321 m_buffer.ensureSpaceForAnyInstruction();
1322 AssemblerLabel result = m_buffer.label();
1323 if (static_cast<int>(result.m_offset) != m_indexOfLastWatchpoint)
1324 result = label();
1325 m_indexOfLastWatchpoint = result.m_offset;
1326 m_indexOfTailOfLastWatchpoint = result.m_offset + maxJumpReplacementSize();
1327 return result;
1328 }
1329
1330 AssemblerLabel label()
1331 {
1332 AssemblerLabel result = labelIgnoringWatchpoints();
1333 while (UNLIKELY(static_cast<int>(result.m_offset) < m_indexOfTailOfLastWatchpoint)) {
1334 nop();
1335 result = labelIgnoringWatchpoints();
1336 }
1337 return result;
1338 }
1339
1340 int sizeOfConstantPool()
1341 {
1342 return m_buffer.sizeOfConstantPool();
1343 }
1344
1345 AssemblerLabel align(int alignment)
1346 {
1347 m_buffer.ensureSpace(maxInstructionSize + 2);
1348 while (!m_buffer.isAligned(alignment)) {
1349 nop();
1350 m_buffer.ensureSpace(maxInstructionSize + 2);
1351 }
1352 return label();
1353 }
1354
1355 static void changePCrelativeAddress(int offset, uint16_t* instructionPtr, uint32_t newAddress)
1356 {
1357 ASSERT((instructionPtr[0] & 0xf000) == MOVL_READ_OFFPC_OPCODE);
1358 uint32_t address = (offset << 2) + ((reinterpret_cast<uint32_t>(instructionPtr) + 4) &(~0x3));
1359 *reinterpret_cast<uint32_t*>(address) = newAddress;
1360 }
1361
1362 static uint32_t readPCrelativeAddress(int offset, uint16_t* instructionPtr)
1363 {
1364 ASSERT((instructionPtr[0] & 0xf000) == MOVL_READ_OFFPC_OPCODE);
1365 uint32_t address = (offset << 2) + ((reinterpret_cast<uint32_t>(instructionPtr) + 4) &(~0x3));
1366 return *reinterpret_cast<uint32_t*>(address);
1367 }
1368
1369 static uint16_t* getInstructionPtr(void* code, int offset)
1370 {
1371 return reinterpret_cast<uint16_t*> (reinterpret_cast<uint32_t>(code) + offset);
1372 }
1373
1374 static void linkJump(void* code, AssemblerLabel from, void* to)
1375 {
1376 ASSERT(from.isSet());
1377
1378 uint16_t* instructionPtr = getInstructionPtr(code, from.m_offset) - 3;
1379 int offsetBits = (reinterpret_cast<uint32_t>(to) - reinterpret_cast<uint32_t>(code)) - from.m_offset;
1380
1381 /* MOV #imm, reg => LDR reg
1382 braf @reg braf @reg
1383 nop nop
1384 */
1385 ASSERT((instructionPtr[0] & 0xf000) == MOVL_READ_OFFPC_OPCODE);
1386 ASSERT((instructionPtr[1] & 0xf0ff) == BRAF_OPCODE);
1387 changePCrelativeAddress((*instructionPtr & 0xff), instructionPtr, offsetBits);
1388 printInstr(*instructionPtr, from.m_offset + 2);
1389 }
1390
1391 static void linkCall(void* code, AssemblerLabel from, void* to)
1392 {
1393 uint16_t* instructionPtr = getInstructionPtr(code, from.m_offset);
1394 instructionPtr -= 3;
1395 ASSERT((instructionPtr[0] & 0xf000) == MOVL_READ_OFFPC_OPCODE);
1396 changePCrelativeAddress((*instructionPtr & 0xff), instructionPtr, reinterpret_cast<uint32_t>(to));
1397 }
1398
1399 static void linkPointer(void* code, AssemblerLabel where, void* value)
1400 {
1401 uint16_t* instructionPtr = getInstructionPtr(code, where.m_offset);
1402 ASSERT((instructionPtr[0] & 0xf000) == MOVL_READ_OFFPC_OPCODE);
1403 changePCrelativeAddress((*instructionPtr & 0xff), instructionPtr, reinterpret_cast<uint32_t>(value));
1404 }
1405
1406 static unsigned getCallReturnOffset(AssemblerLabel call)
1407 {
1408 ASSERT(call.isSet());
1409 return call.m_offset;
1410 }
1411
1412 static uint32_t* getLdrImmAddressOnPool(SH4Word* insn, uint32_t* constPool)
1413 {
1414 return (constPool + (*insn & 0xff));
1415 }
1416
1417 static SH4Word patchConstantPoolLoad(SH4Word load, int value)
1418 {
1419 return ((load & ~0xff) | value);
1420 }
1421
1422 static SH4Buffer::TwoShorts placeConstantPoolBarrier(int offset)
1423 {
1424 ASSERT(((offset >> 1) <= 2047) && ((offset >> 1) >= -2048));
1425
1426 SH4Buffer::TwoShorts m_barrier;
1427 m_barrier.high = (BRA_OPCODE | (offset >> 1));
1428 m_barrier.low = NOP_OPCODE;
1429 printInstr(((BRA_OPCODE | (offset >> 1))), 0);
1430 printInstr(NOP_OPCODE, 0);
1431 return m_barrier;
1432 }
1433
1434 static void patchConstantPoolLoad(void* loadAddr, void* constPoolAddr)
1435 {
1436 SH4Word* instructionPtr = reinterpret_cast<SH4Word*>(loadAddr);
1437 SH4Word instruction = *instructionPtr;
1438 SH4Word index = instruction & 0xff;
1439
1440 if ((instruction & 0xf000) != MOVIMM_OPCODE)
1441 return;
1442
1443 ASSERT((((reinterpret_cast<uint32_t>(constPoolAddr) - reinterpret_cast<uint32_t>(loadAddr)) + index * 4)) < 1024);
1444
1445 int offset = reinterpret_cast<uint32_t>(constPoolAddr) + (index * 4) - ((reinterpret_cast<uint32_t>(instructionPtr) & ~0x03) + 4);
1446 instruction &= 0x0f00;
1447 instruction |= 0xd000;
1448 offset &= 0x03ff;
1449 instruction |= (offset >> 2);
1450 *instructionPtr = instruction;
1451 printInstr(instruction, reinterpret_cast<uint32_t>(loadAddr));
1452 }
1453
1454 static void repatchPointer(void* where, void* value)
1455 {
1456 patchPointer(where, value);
1457 }
1458
1459 static void* readPointer(void* code)
1460 {
1461 return reinterpret_cast<void*>(readInt32(code));
1462 }
1463
1464 static void repatchInt32(void* where, int32_t value)
1465 {
1466 uint16_t* instructionPtr = reinterpret_cast<uint16_t*>(where);
1467 ASSERT((instructionPtr[0] & 0xf000) == MOVL_READ_OFFPC_OPCODE);
1468 changePCrelativeAddress((*instructionPtr & 0xff), instructionPtr, value);
1469 }
1470
1471 static void repatchCompact(void* where, int32_t value)
1472 {
1473 uint16_t* instructionPtr = reinterpret_cast<uint16_t*>(where);
1474 ASSERT(value >= 0);
1475 ASSERT(value <= 60);
1476
1477 // Handle the uncommon case where a flushConstantPool occured in movlMemRegCompact.
1478 if ((instructionPtr[0] & 0xf000) == BRA_OPCODE)
1479 instructionPtr += (instructionPtr[0] & 0x0fff) + 2;
1480
1481 ASSERT((instructionPtr[0] & 0xf000) == MOVL_READ_OFFRM_OPCODE);
1482 instructionPtr[0] = (instructionPtr[0] & 0xfff0) | (value >> 2);
1483 cacheFlush(instructionPtr, sizeof(uint16_t));
1484 }
1485
1486 static void relinkCall(void* from, void* to)
1487 {
1488 uint16_t* instructionPtr = reinterpret_cast<uint16_t*>(from);
1489 instructionPtr -= 3;
1490 ASSERT((instructionPtr[0] & 0xf000) == MOVL_READ_OFFPC_OPCODE);
1491 changePCrelativeAddress((*instructionPtr & 0xff), instructionPtr, reinterpret_cast<uint32_t>(to));
1492 }
1493
1494 static void relinkJump(void* from, void* to)
1495 {
1496 uint16_t* instructionPtr = reinterpret_cast<uint16_t*> (from);
1497 instructionPtr -= 3;
1498 ASSERT((instructionPtr[0] & 0xf000) == MOVL_READ_OFFPC_OPCODE);
1499 ASSERT((instructionPtr[1] & 0xf0ff) == BRAF_OPCODE);
1500 changePCrelativeAddress((*instructionPtr & 0xff), instructionPtr, reinterpret_cast<uint32_t>(to) - reinterpret_cast<uint32_t>(from));
1501 }
1502
1503 // Linking & patching
1504
1505 static ptrdiff_t maxJumpReplacementSize()
1506 {
1507 return sizeof(SH4Word) * 6;
1508 }
1509
1510 static void replaceWithJump(void *instructionStart, void *to)
1511 {
1512 SH4Word* instruction = reinterpret_cast<SH4Word*>(instructionStart);
1513 intptr_t difference = reinterpret_cast<intptr_t>(to) - (reinterpret_cast<intptr_t>(instruction) + 3 * sizeof(SH4Word));
1514
1515 if ((instruction[0] & 0xf000) == MOVL_READ_OFFPC_OPCODE) {
1516 // We have an entry in constant pool and we potentially replace a branchPtrWithPatch, so let's backup what would be the
1517 // condition (CMP/xx and Bx opcodes) for later use in revertJumpReplacementToBranchPtrWithPatch before putting the jump.
1518 instruction[4] = instruction[1];
1519 instruction[5] = instruction[2];
1520 instruction[1] = (BRAF_OPCODE | (instruction[0] & 0x0f00));
1521 instruction[2] = NOP_OPCODE;
1522 cacheFlush(&instruction[1], 2 * sizeof(SH4Word));
1523 } else {
1524 instruction[0] = getOpcodeGroup3(MOVL_READ_OFFPC_OPCODE, SH4Registers::r13, 1);
1525 instruction[1] = getOpcodeGroup2(BRAF_OPCODE, SH4Registers::r13);
1526 instruction[2] = NOP_OPCODE;
1527 cacheFlush(instruction, 3 * sizeof(SH4Word));
1528 }
1529
1530 changePCrelativeAddress(instruction[0] & 0x00ff, instruction, difference);
1531 }
1532
1533 static void revertJumpReplacementToBranchPtrWithPatch(void* instructionStart, RegisterID rd, int imm)
1534 {
1535 SH4Word *insn = reinterpret_cast<SH4Word*>(instructionStart);
1536 ASSERT((insn[0] & 0xf000) == MOVL_READ_OFFPC_OPCODE);
1537 ASSERT((insn[0] & 0x00ff) != 1);
1538
1539 insn[0] = getOpcodeGroup3(MOVL_READ_OFFPC_OPCODE, SH4Registers::r13, insn[0] & 0x00ff);
1540 if ((insn[1] & 0xf0ff) == BRAF_OPCODE) {
1541 insn[1] = (insn[4] & 0xf00f) | (rd << 8) | (SH4Registers::r13 << 4); // Restore CMP/xx opcode.
1542 insn[2] = insn[5];
1543 ASSERT(((insn[2] & 0xff00) == BT_OPCODE) || ((insn[2] & 0xff00) == BF_OPCODE));
1544 ASSERT((insn[3] & 0xf000) == MOVL_READ_OFFPC_OPCODE);
1545 insn[4] = (BRAF_OPCODE | (insn[3] & 0x0f00));
1546 insn[5] = NOP_OPCODE;
1547 cacheFlush(insn, 6 * sizeof(SH4Word));
1548 } else {
1549 // The branchPtrWithPatch has already been restored, so we just patch the immediate value and ASSERT all is as expected.
1550 ASSERT((insn[1] & 0xf000) == 0x3000);
1551 insn[1] = (insn[1] & 0xf00f) | (rd << 8) | (SH4Registers::r13 << 4);
1552 cacheFlush(insn, 2 * sizeof(SH4Word));
1553 ASSERT(((insn[2] & 0xff00) == BT_OPCODE) || ((insn[2] & 0xff00) == BF_OPCODE));
1554 ASSERT((insn[3] & 0xf000) == MOVL_READ_OFFPC_OPCODE);
1555 ASSERT(insn[5] == NOP_OPCODE);
1556 }
1557
1558 changePCrelativeAddress(insn[0] & 0x00ff, insn, imm);
1559 }
1560
1561 void linkJump(AssemblerLabel from, AssemblerLabel to, JumpType type = JumpFar)
1562 {
1563 ASSERT(to.isSet());
1564 ASSERT(from.isSet());
1565
1566 uint16_t* instructionPtr = getInstructionPtr(data(), from.m_offset) - 1;
1567 int offsetBits = (to.m_offset - from.m_offset);
1568
1569 if (type == JumpNear) {
1570 uint16_t instruction = instructionPtr[0];
1571 int offset = (offsetBits - 2);
1572 ASSERT((((instruction == BT_OPCODE) || (instruction == BF_OPCODE)) && (offset >= -256) && (offset <= 254))
1573 || ((instruction == BRA_OPCODE) && (offset >= -4096) && (offset <= 4094)));
1574 *instructionPtr++ = instruction | (offset >> 1);
1575 printInstr(*instructionPtr, from.m_offset + 2);
1576 return;
1577 }
1578
1579 /* MOV # imm, reg => LDR reg
1580 braf @reg braf @reg
1581 nop nop
1582 */
1583 instructionPtr -= 2;
1584 ASSERT((instructionPtr[1] & 0xf0ff) == BRAF_OPCODE);
1585
1586 if ((instructionPtr[0] & 0xf000) == MOVIMM_OPCODE) {
1587 uint32_t* addr = getLdrImmAddressOnPool(instructionPtr, m_buffer.poolAddress());
1588 *addr = offsetBits;
1589 printInstr(*instructionPtr, from.m_offset + 2);
1590 return;
1591 }
1592
1593 ASSERT((instructionPtr[0] & 0xf000) == MOVL_READ_OFFPC_OPCODE);
1594 changePCrelativeAddress((*instructionPtr & 0xff), instructionPtr, offsetBits);
1595 printInstr(*instructionPtr, from.m_offset + 2);
1596 }
1597
1598 static void* getRelocatedAddress(void* code, AssemblerLabel label)
1599 {
1600 return reinterpret_cast<void*>(reinterpret_cast<char*>(code) + label.m_offset);
1601 }
1602
1603 static int getDifferenceBetweenLabels(AssemblerLabel a, AssemblerLabel b)
1604 {
1605 return b.m_offset - a.m_offset;
1606 }
1607
1608 static void patchPointer(void* code, AssemblerLabel where, void* value)
1609 {
1610 patchPointer(reinterpret_cast<uint32_t*>(code) + where.m_offset, value);
1611 }
1612
1613 static void patchPointer(void* code, void* value)
1614 {
1615 patchInt32(code, reinterpret_cast<uint32_t>(value));
1616 }
1617
1618 static void patchInt32(void* code, uint32_t value)
1619 {
1620 changePCrelativeAddress((*(reinterpret_cast<uint16_t*>(code)) & 0xff), reinterpret_cast<uint16_t*>(code), value);
1621 }
1622
1623 static uint32_t readInt32(void* code)
1624 {
1625 return readPCrelativeAddress((*(reinterpret_cast<uint16_t*>(code)) & 0xff), reinterpret_cast<uint16_t*>(code));
1626 }
1627
1628 static void* readCallTarget(void* from)
1629 {
1630 uint16_t* instructionPtr = static_cast<uint16_t*>(from);
1631 instructionPtr -= 3;
1632 return reinterpret_cast<void*>(readPCrelativeAddress((*instructionPtr & 0xff), instructionPtr));
1633 }
1634
1635 static void cacheFlush(void* code, size_t size)
1636 {
1637 #if OS(LINUX)
1638 // Flush each page separately, otherwise the whole flush will fail if an uncommited page is in the area.
1639 unsigned currentPage = reinterpret_cast<unsigned>(code) & ~(pageSize() - 1);
1640 unsigned lastPage = (reinterpret_cast<unsigned>(code) + size - 1) & ~(pageSize() - 1);
1641 do {
1642 #if defined CACHEFLUSH_D_L2
1643 syscall(__NR_cacheflush, currentPage, pageSize(), CACHEFLUSH_D_WB | CACHEFLUSH_I | CACHEFLUSH_D_L2);
1644 #else
1645 syscall(__NR_cacheflush, currentPage, pageSize(), CACHEFLUSH_D_WB | CACHEFLUSH_I);
1646 #endif
1647 currentPage += pageSize();
1648 } while (lastPage >= currentPage);
1649 #else
1650 #error "The cacheFlush support is missing on this platform."
1651 #endif
1652 }
1653
1654 void prefix(uint16_t pre)
1655 {
1656 m_buffer.putByte(pre);
1657 }
1658
1659 void oneShortOp(uint16_t opcode, bool checksize = true, bool isDouble = true)
1660 {
1661 printInstr(opcode, m_buffer.codeSize(), isDouble);
1662 if (checksize)
1663 m_buffer.ensureSpace(maxInstructionSize);
1664 m_buffer.putShortUnchecked(opcode);
1665 }
1666
1667 void ensureSpace(int space)
1668 {
1669 m_buffer.ensureSpace(space);
1670 }
1671
1672 void ensureSpace(int insnSpace, int constSpace)
1673 {
1674 m_buffer.ensureSpace(insnSpace, constSpace);
1675 }
1676
1677 // Administrative methods
1678
1679 void* data() const { return m_buffer.data(); }
1680 size_t codeSize() const { return m_buffer.codeSize(); }
1681
1682 unsigned debugOffset() { return m_buffer.debugOffset(); }
1683
1684 #ifdef SH4_ASSEMBLER_TRACING
1685 static void printInstr(uint16_t opc, unsigned size, bool isdoubleInst = true)
1686 {
1687 if (!getenv("JavaScriptCoreDumpJIT"))
1688 return;
1689
1690 const char *format = 0;
1691 printfStdoutInstr("offset: 0x%8.8x\t", size);
1692 switch (opc) {
1693 case BRK_OPCODE:
1694 format = " BRK\n";
1695 break;
1696 case NOP_OPCODE:
1697 format = " NOP\n";
1698 break;
1699 case RTS_OPCODE:
1700 format =" *RTS\n";
1701 break;
1702 case SETS_OPCODE:
1703 format = " SETS\n";
1704 break;
1705 case SETT_OPCODE:
1706 format = " SETT\n";
1707 break;
1708 case CLRT_OPCODE:
1709 format = " CLRT\n";
1710 break;
1711 case FSCHG_OPCODE:
1712 format = " FSCHG\n";
1713 break;
1714 }
1715 if (format) {
1716 printfStdoutInstr(format);
1717 return;
1718 }
1719 switch (opc & 0xf0ff) {
1720 case BRAF_OPCODE:
1721 format = " *BRAF R%d\n";
1722 break;
1723 case DT_OPCODE:
1724 format = " DT R%d\n";
1725 break;
1726 case CMPPL_OPCODE:
1727 format = " CMP/PL R%d\n";
1728 break;
1729 case CMPPZ_OPCODE:
1730 format = " CMP/PZ R%d\n";
1731 break;
1732 case JMP_OPCODE:
1733 format = " *JMP @R%d\n";
1734 break;
1735 case JSR_OPCODE:
1736 format = " *JSR @R%d\n";
1737 break;
1738 case LDSPR_OPCODE:
1739 format = " LDS R%d, PR\n";
1740 break;
1741 case LDSLPR_OPCODE:
1742 format = " LDS.L @R%d+, PR\n";
1743 break;
1744 case MOVT_OPCODE:
1745 format = " MOVT R%d\n";
1746 break;
1747 case SHAL_OPCODE:
1748 format = " SHAL R%d\n";
1749 break;
1750 case SHAR_OPCODE:
1751 format = " SHAR R%d\n";
1752 break;
1753 case SHLL_OPCODE:
1754 format = " SHLL R%d\n";
1755 break;
1756 case SHLL2_OPCODE:
1757 format = " SHLL2 R%d\n";
1758 break;
1759 case SHLL8_OPCODE:
1760 format = " SHLL8 R%d\n";
1761 break;
1762 case SHLL16_OPCODE:
1763 format = " SHLL16 R%d\n";
1764 break;
1765 case SHLR_OPCODE:
1766 format = " SHLR R%d\n";
1767 break;
1768 case SHLR2_OPCODE:
1769 format = " SHLR2 R%d\n";
1770 break;
1771 case SHLR8_OPCODE:
1772 format = " SHLR8 R%d\n";
1773 break;
1774 case SHLR16_OPCODE:
1775 format = " SHLR16 R%d\n";
1776 break;
1777 case STSPR_OPCODE:
1778 format = " STS PR, R%d\n";
1779 break;
1780 case STSLPR_OPCODE:
1781 format = " STS.L PR, @-R%d\n";
1782 break;
1783 case LDS_RM_FPUL_OPCODE:
1784 format = " LDS R%d, FPUL\n";
1785 break;
1786 case STS_FPUL_RN_OPCODE:
1787 format = " STS FPUL, R%d \n";
1788 break;
1789 case FLDS_FRM_FPUL_OPCODE:
1790 format = " FLDS FR%d, FPUL\n";
1791 break;
1792 case FSTS_FPUL_FRN_OPCODE:
1793 format = " FSTS FPUL, R%d \n";
1794 break;
1795 case LDSFPSCR_OPCODE:
1796 format = " LDS R%d, FPSCR \n";
1797 break;
1798 case STSFPSCR_OPCODE:
1799 format = " STS FPSCR, R%d \n";
1800 break;
1801 case STSMACL_OPCODE:
1802 format = " STS MACL, R%d \n";
1803 break;
1804 case STSMACH_OPCODE:
1805 format = " STS MACH, R%d \n";
1806 break;
1807 case BSRF_OPCODE:
1808 format = " *BSRF R%d";
1809 break;
1810 case FTRC_OPCODE:
1811 format = " FTRC FR%d, FPUL\n";
1812 break;
1813 }
1814 if (format) {
1815 printfStdoutInstr(format, getRn(opc));
1816 return;
1817 }
1818 switch (opc & 0xf0ff) {
1819 case FNEG_OPCODE:
1820 format = " FNEG DR%d\n";
1821 break;
1822 case FLOAT_OPCODE:
1823 format = " FLOAT DR%d\n";
1824 break;
1825 case FTRC_OPCODE:
1826 format = " FTRC FR%d, FPUL\n";
1827 break;
1828 case FABS_OPCODE:
1829 format = " FABS FR%d\n";
1830 break;
1831 case FSQRT_OPCODE:
1832 format = " FSQRT FR%d\n";
1833 break;
1834 case FCNVDS_DRM_FPUL_OPCODE:
1835 format = " FCNVDS FR%d, FPUL\n";
1836 break;
1837 case FCNVSD_FPUL_DRN_OPCODE:
1838 format = " FCNVSD FPUL, FR%d\n";
1839 break;
1840 }
1841 if (format) {
1842 if (isdoubleInst)
1843 printfStdoutInstr(format, getDRn(opc) << 1);
1844 else
1845 printfStdoutInstr(format, getRn(opc));
1846 return;
1847 }
1848 switch (opc & 0xf00f) {
1849 case ADD_OPCODE:
1850 format = " ADD R%d, R%d\n";
1851 break;
1852 case ADDC_OPCODE:
1853 format = " ADDC R%d, R%d\n";
1854 break;
1855 case ADDV_OPCODE:
1856 format = " ADDV R%d, R%d\n";
1857 break;
1858 case AND_OPCODE:
1859 format = " AND R%d, R%d\n";
1860 break;
1861 case DIV1_OPCODE:
1862 format = " DIV1 R%d, R%d\n";
1863 break;
1864 case CMPEQ_OPCODE:
1865 format = " CMP/EQ R%d, R%d\n";
1866 break;
1867 case CMPGE_OPCODE:
1868 format = " CMP/GE R%d, R%d\n";
1869 break;
1870 case CMPGT_OPCODE:
1871 format = " CMP/GT R%d, R%d\n";
1872 break;
1873 case CMPHI_OPCODE:
1874 format = " CMP/HI R%d, R%d\n";
1875 break;
1876 case CMPHS_OPCODE:
1877 format = " CMP/HS R%d, R%d\n";
1878 break;
1879 case MOV_OPCODE:
1880 format = " MOV R%d, R%d\n";
1881 break;
1882 case MOVB_WRITE_RN_OPCODE:
1883 format = " MOV.B R%d, @R%d\n";
1884 break;
1885 case MOVB_WRITE_RNDEC_OPCODE:
1886 format = " MOV.B R%d, @-R%d\n";
1887 break;
1888 case MOVB_WRITE_R0RN_OPCODE:
1889 format = " MOV.B R%d, @(R0, R%d)\n";
1890 break;
1891 case MOVB_READ_RM_OPCODE:
1892 format = " MOV.B @R%d, R%d\n";
1893 break;
1894 case MOVB_READ_RMINC_OPCODE:
1895 format = " MOV.B @R%d+, R%d\n";
1896 break;
1897 case MOVB_READ_R0RM_OPCODE:
1898 format = " MOV.B @(R0, R%d), R%d\n";
1899 break;
1900 case MOVL_WRITE_RN_OPCODE:
1901 format = " MOV.L R%d, @R%d\n";
1902 break;
1903 case MOVL_WRITE_RNDEC_OPCODE:
1904 format = " MOV.L R%d, @-R%d\n";
1905 break;
1906 case MOVL_WRITE_R0RN_OPCODE:
1907 format = " MOV.L R%d, @(R0, R%d)\n";
1908 break;
1909 case MOVL_READ_RM_OPCODE:
1910 format = " MOV.L @R%d, R%d\n";
1911 break;
1912 case MOVL_READ_RMINC_OPCODE:
1913 format = " MOV.L @R%d+, R%d\n";
1914 break;
1915 case MOVL_READ_R0RM_OPCODE:
1916 format = " MOV.L @(R0, R%d), R%d\n";
1917 break;
1918 case MULL_OPCODE:
1919 format = " MUL.L R%d, R%d\n";
1920 break;
1921 case DMULL_L_OPCODE:
1922 format = " DMULU.L R%d, R%d\n";
1923 break;
1924 case DMULSL_OPCODE:
1925 format = " DMULS.L R%d, R%d\n";
1926 break;
1927 case NEG_OPCODE:
1928 format = " NEG R%d, R%d\n";
1929 break;
1930 case NEGC_OPCODE:
1931 format = " NEGC R%d, R%d\n";
1932 break;
1933 case NOT_OPCODE:
1934 format = " NOT R%d, R%d\n";
1935 break;
1936 case OR_OPCODE:
1937 format = " OR R%d, R%d\n";
1938 break;
1939 case SHAD_OPCODE:
1940 format = " SHAD R%d, R%d\n";
1941 break;
1942 case SHLD_OPCODE:
1943 format = " SHLD R%d, R%d\n";
1944 break;
1945 case SUB_OPCODE:
1946 format = " SUB R%d, R%d\n";
1947 break;
1948 case SUBC_OPCODE:
1949 format = " SUBC R%d, R%d\n";
1950 break;
1951 case SUBV_OPCODE:
1952 format = " SUBV R%d, R%d\n";
1953 break;
1954 case TST_OPCODE:
1955 format = " TST R%d, R%d\n";
1956 break;
1957 case XOR_OPCODE:
1958 format = " XOR R%d, R%d\n";break;
1959 case MOVW_WRITE_RN_OPCODE:
1960 format = " MOV.W R%d, @R%d\n";
1961 break;
1962 case MOVW_READ_RM_OPCODE:
1963 format = " MOV.W @R%d, R%d\n";
1964 break;
1965 case MOVW_READ_RMINC_OPCODE:
1966 format = " MOV.W @R%d+, R%d\n";
1967 break;
1968 case MOVW_READ_R0RM_OPCODE:
1969 format = " MOV.W @(R0, R%d), R%d\n";
1970 break;
1971 case MOVW_WRITE_R0RN_OPCODE:
1972 format = " MOV.W R%d, @(R0, R%d)\n";
1973 break;
1974 case EXTUB_OPCODE:
1975 format = " EXTU.B R%d, R%d\n";
1976 break;
1977 case EXTUW_OPCODE:
1978 format = " EXTU.W R%d, R%d\n";
1979 break;
1980 }
1981 if (format) {
1982 printfStdoutInstr(format, getRm(opc), getRn(opc));
1983 return;
1984 }
1985 switch (opc & 0xf00f) {
1986 case FSUB_OPCODE:
1987 format = " FSUB FR%d, FR%d\n";
1988 break;
1989 case FADD_OPCODE:
1990 format = " FADD FR%d, FR%d\n";
1991 break;
1992 case FDIV_OPCODE:
1993 format = " FDIV FR%d, FR%d\n";
1994 break;
1995 case FMUL_OPCODE:
1996 format = " DMULL FR%d, FR%d\n";
1997 break;
1998 case FMOV_OPCODE:
1999 format = " FMOV FR%d, FR%d\n";
2000 break;
2001 case FCMPEQ_OPCODE:
2002 format = " FCMP/EQ FR%d, FR%d\n";
2003 break;
2004 case FCMPGT_OPCODE:
2005 format = " FCMP/GT FR%d, FR%d\n";
2006 break;
2007 }
2008 if (format) {
2009 if (isdoubleInst)
2010 printfStdoutInstr(format, getDRm(opc) << 1, getDRn(opc) << 1);
2011 else
2012 printfStdoutInstr(format, getRm(opc), getRn(opc));
2013 return;
2014 }
2015 switch (opc & 0xf00f) {
2016 case FMOVS_WRITE_RN_DEC_OPCODE:
2017 format = " %s FR%d, @-R%d\n";
2018 break;
2019 case FMOVS_WRITE_RN_OPCODE:
2020 format = " %s FR%d, @R%d\n";
2021 break;
2022 case FMOVS_WRITE_R0RN_OPCODE:
2023 format = " %s FR%d, @(R0, R%d)\n";
2024 break;
2025 }
2026 if (format) {
2027 if (isdoubleInst)
2028 printfStdoutInstr(format, "FMOV", getDRm(opc) << 1, getDRn(opc));
2029 else
2030 printfStdoutInstr(format, "FMOV.S", getRm(opc), getRn(opc));
2031 return;
2032 }
2033 switch (opc & 0xf00f) {
2034 case FMOVS_READ_RM_OPCODE:
2035 format = " %s @R%d, FR%d\n";
2036 break;
2037 case FMOVS_READ_RM_INC_OPCODE:
2038 format = " %s @R%d+, FR%d\n";
2039 break;
2040 case FMOVS_READ_R0RM_OPCODE:
2041 format = " %s @(R0, R%d), FR%d\n";
2042 break;
2043 }
2044 if (format) {
2045 if (isdoubleInst)
2046 printfStdoutInstr(format, "FMOV", getDRm(opc), getDRn(opc) << 1);
2047 else
2048 printfStdoutInstr(format, "FMOV.S", getRm(opc), getRn(opc));
2049 return;
2050 }
2051 switch (opc & 0xff00) {
2052 case BF_OPCODE:
2053 format = " BF %d\n";
2054 break;
2055 case BFS_OPCODE:
2056 format = " *BF/S %d\n";
2057 break;
2058 case ANDIMM_OPCODE:
2059 format = " AND #%d, R0\n";
2060 break;
2061 case BT_OPCODE:
2062 format = " BT %d\n";
2063 break;
2064 case BTS_OPCODE:
2065 format = " *BT/S %d\n";
2066 break;
2067 case CMPEQIMM_OPCODE:
2068 format = " CMP/EQ #%d, R0\n";
2069 break;
2070 case MOVB_WRITE_OFFGBR_OPCODE:
2071 format = " MOV.B R0, @(%d, GBR)\n";
2072 break;
2073 case MOVB_READ_OFFGBR_OPCODE:
2074 format = " MOV.B @(%d, GBR), R0\n";
2075 break;
2076 case MOVL_WRITE_OFFGBR_OPCODE:
2077 format = " MOV.L R0, @(%d, GBR)\n";
2078 break;
2079 case MOVL_READ_OFFGBR_OPCODE:
2080 format = " MOV.L @(%d, GBR), R0\n";
2081 break;
2082 case MOVA_READ_OFFPC_OPCODE:
2083 format = " MOVA @(%d, PC), R0\n";
2084 break;
2085 case ORIMM_OPCODE:
2086 format = " OR #%d, R0\n";
2087 break;
2088 case ORBIMM_OPCODE:
2089 format = " OR.B #%d, @(R0, GBR)\n";
2090 break;
2091 case TSTIMM_OPCODE:
2092 format = " TST #%d, R0\n";
2093 break;
2094 case TSTB_OPCODE:
2095 format = " TST.B %d, @(R0, GBR)\n";
2096 break;
2097 case XORIMM_OPCODE:
2098 format = " XOR #%d, R0\n";
2099 break;
2100 case XORB_OPCODE:
2101 format = " XOR.B %d, @(R0, GBR)\n";
2102 break;
2103 }
2104 if (format) {
2105 printfStdoutInstr(format, getImm8(opc));
2106 return;
2107 }
2108 switch (opc & 0xff00) {
2109 case MOVB_WRITE_OFFRN_OPCODE:
2110 format = " MOV.B R0, @(%d, R%d)\n";
2111 break;
2112 case MOVB_READ_OFFRM_OPCODE:
2113 format = " MOV.B @(%d, R%d), R0\n";
2114 break;
2115 }
2116 if (format) {
2117 printfStdoutInstr(format, getDisp(opc), getRm(opc));
2118 return;
2119 }
2120 switch (opc & 0xf000) {
2121 case BRA_OPCODE:
2122 format = " *BRA %d\n";
2123 break;
2124 case BSR_OPCODE:
2125 format = " *BSR %d\n";
2126 break;
2127 }
2128 if (format) {
2129 printfStdoutInstr(format, getImm12(opc));
2130 return;
2131 }
2132 switch (opc & 0xf000) {
2133 case MOVL_READ_OFFPC_OPCODE:
2134 format = " MOV.L @(%d, PC), R%d\n";
2135 break;
2136 case ADDIMM_OPCODE:
2137 format = " ADD #%d, R%d\n";
2138 break;
2139 case MOVIMM_OPCODE:
2140 format = " MOV #%d, R%d\n";
2141 break;
2142 case MOVW_READ_OFFPC_OPCODE:
2143 format = " MOV.W @(%d, PC), R%d\n";
2144 break;
2145 }
2146 if (format) {
2147 printfStdoutInstr(format, getImm8(opc), getRn(opc));
2148 return;
2149 }
2150 switch (opc & 0xf000) {
2151 case MOVL_WRITE_OFFRN_OPCODE:
2152 format = " MOV.L R%d, @(%d, R%d)\n";
2153 printfStdoutInstr(format, getRm(opc), getDisp(opc), getRn(opc));
2154 break;
2155 case MOVL_READ_OFFRM_OPCODE:
2156 format = " MOV.L @(%d, R%d), R%d\n";
2157 printfStdoutInstr(format, getDisp(opc), getRm(opc), getRn(opc));
2158 break;
2159 }
2160 }
2161
2162 static void printfStdoutInstr(const char* format, ...)
2163 {
2164 if (getenv("JavaScriptCoreDumpJIT")) {
2165 va_list args;
2166 va_start(args, format);
2167 vprintfStdoutInstr(format, args);
2168 va_end(args);
2169 }
2170 }
2171
2172 static void vprintfStdoutInstr(const char* format, va_list args)
2173 {
2174 if (getenv("JavaScriptCoreDumpJIT"))
2175 WTF::dataLogFV(format, args);
2176 }
2177
2178 static void printBlockInstr(uint16_t* first, unsigned offset, int nbInstr)
2179 {
2180 printfStdoutInstr(">> repatch instructions after link\n");
2181 for (int i = 0; i <= nbInstr; i++)
2182 printInstr(*(first + i), offset + i);
2183 printfStdoutInstr(">> end repatch\n");
2184 }
2185 #else
2186 static void printInstr(uint16_t, unsigned, bool = true) { };
2187 static void printBlockInstr(uint16_t*, unsigned, int) { };
2188 #endif
2189
2190 static void replaceWithLoad(void* instructionStart)
2191 {
2192 SH4Word* insPtr = reinterpret_cast<SH4Word*>(instructionStart);
2193
2194 insPtr += 2; // skip MOV and ADD opcodes
2195
2196 if (((*insPtr) & 0xf00f) != MOVL_READ_RM_OPCODE) {
2197 *insPtr = MOVL_READ_RM_OPCODE | (*insPtr & 0x0ff0);
2198 cacheFlush(insPtr, sizeof(SH4Word));
2199 }
2200 }
2201
2202 static void replaceWithAddressComputation(void* instructionStart)
2203 {
2204 SH4Word* insPtr = reinterpret_cast<SH4Word*>(instructionStart);
2205
2206 insPtr += 2; // skip MOV and ADD opcodes
2207
2208 if (((*insPtr) & 0xf00f) != MOV_OPCODE) {
2209 *insPtr = MOV_OPCODE | (*insPtr & 0x0ff0);
2210 cacheFlush(insPtr, sizeof(SH4Word));
2211 }
2212 }
2213
2214 private:
2215 SH4Buffer m_buffer;
2216 int m_claimscratchReg;
2217 int m_indexOfLastWatchpoint;
2218 int m_indexOfTailOfLastWatchpoint;
2219 };
2220
2221 } // namespace JSC
2222
2223 #endif // ENABLE(ASSEMBLER) && CPU(SH4)
2224
2225 #endif // SH4Assembler_h