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.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
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.
28 #ifndef SH4Assembler_h
29 #define SH4Assembler_h
31 #if ENABLE(ASSEMBLER) && CPU(SH4)
33 #include "AssemblerBuffer.h"
34 #include "AssemblerBufferWithConstantPool.h"
35 #include "JITCompilationEffort.h"
40 #include <wtf/Assertions.h>
41 #include <wtf/DataLog.h>
42 #include <wtf/Vector.h>
45 #define SH4_ASSEMBLER_TRACING
49 typedef uint16_t SH4Word
;
52 INVALID_OPCODE
= 0xffff,
54 ADDIMM_OPCODE
= 0x7000,
58 ANDIMM_OPCODE
= 0xc900,
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,
83 FCMPEQ_OPCODE
= 0xf004,
84 FCMPGT_OPCODE
= 0xf005,
93 LDSPR_OPCODE
= 0x402a,
94 LDSLPR_OPCODE
= 0x4026,
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,
133 NEGC_OPCODE
= 0x600a,
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,
156 SUBC_OPCODE
= 0x300a,
157 SUBV_OPCODE
= 0x300b,
159 TSTIMM_OPCODE
= 0xc800,
160 TSTB_OPCODE
= 0xcc00,
161 EXTUB_OPCODE
= 0x600c,
162 EXTUW_OPCODE
= 0x600d,
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,
186 SYNCO_OPCODE
= 0x00ab,
189 namespace SH4Registers
{
231 inline uint16_t getOpcodeGroup1(uint16_t opc
, int rm
, int rn
)
233 return (opc
| ((rm
& 0xf) << 8) | ((rn
& 0xf) << 4));
236 inline uint16_t getOpcodeGroup2(uint16_t opc
, int rm
)
238 return (opc
| ((rm
& 0xf) << 8));
241 inline uint16_t getOpcodeGroup3(uint16_t opc
, int rm
, int rn
)
243 return (opc
| ((rm
& 0xf) << 8) | (rn
& 0xff));
246 inline uint16_t getOpcodeGroup4(uint16_t opc
, int rm
, int rn
, int offset
)
248 return (opc
| ((rm
& 0xf) << 8) | ((rn
& 0xf) << 4) | (offset
& 0xf));
251 inline uint16_t getOpcodeGroup5(uint16_t opc
, int rm
)
253 return (opc
| (rm
& 0xff));
256 inline uint16_t getOpcodeGroup6(uint16_t opc
, int rm
)
258 return (opc
| (rm
& 0xfff));
261 inline uint16_t getOpcodeGroup7(uint16_t opc
, int rm
)
263 return (opc
| ((rm
& 0x7) << 9));
266 inline uint16_t getOpcodeGroup8(uint16_t opc
, int rm
, int rn
)
268 return (opc
| ((rm
& 0x7) << 9) | ((rn
& 0x7) << 5));
271 inline uint16_t getOpcodeGroup9(uint16_t opc
, int rm
, int rn
)
273 return (opc
| ((rm
& 0xf) << 8) | ((rn
& 0x7) << 5));
276 inline uint16_t getOpcodeGroup10(uint16_t opc
, int rm
, int rn
)
278 return (opc
| ((rm
& 0x7) << 9) | ((rn
& 0xf) << 4));
281 inline uint16_t getOpcodeGroup11(uint16_t opc
, int rm
, int rn
)
283 return (opc
| ((rm
& 0xf) << 4) | (rn
& 0xf));
286 inline uint16_t getRn(uint16_t x
)
288 return ((x
& 0xf00) >> 8);
291 inline uint16_t getRm(uint16_t x
)
293 return ((x
& 0xf0) >> 4);
296 inline uint16_t getDisp(uint16_t x
)
301 inline uint16_t getImm8(uint16_t x
)
306 inline uint16_t getImm12(uint16_t x
)
311 inline uint16_t getDRn(uint16_t x
)
313 return ((x
& 0xe00) >> 9);
316 inline uint16_t getDRm(uint16_t x
)
318 return ((x
& 0xe0) >> 5);
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;
330 static RegisterID
firstRegister() { return SH4Registers::r0
; }
331 static RegisterID
lastRegister() { return SH4Registers::r15
; }
333 static FPRegisterID
firstFPRegister() { return SH4Registers::dr0
; }
334 static FPRegisterID
lastFPRegister() { return SH4Registers::dr14
; }
338 padForAlign16
= 0x0009,
339 padForAlign32
= 0x00090009,
348 : m_claimscratchReg(0x0)
349 , m_indexOfLastWatchpoint(INT_MIN
)
350 , m_indexOfTailOfLastWatchpoint(INT_MIN
)
354 SH4Buffer
& buffer() { return m_buffer
; }
356 // SH4 condition codes
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
370 NS
= 0xc, // Not Signed
371 EQU
= 0xd, // Equal or unordered(NaN)
379 // Opaque label types
381 bool isImmediate(int constant
)
383 return ((constant
<= 127) && (constant
>= -128));
386 RegisterID
claimScratch()
388 ASSERT((m_claimscratchReg
!= 0x3));
390 if (!(m_claimscratchReg
& 0x1)) {
391 m_claimscratchReg
= (m_claimscratchReg
| 0x1);
395 m_claimscratchReg
= (m_claimscratchReg
| 0x2);
399 void releaseScratch(RegisterID scratchR
)
401 if (scratchR
== scratchReg1
)
402 m_claimscratchReg
= (m_claimscratchReg
& 0x2);
404 m_claimscratchReg
= (m_claimscratchReg
& 0x1);
409 void pushReg(RegisterID reg
)
411 if (reg
== SH4Registers::pr
) {
412 oneShortOp(getOpcodeGroup2(STSLPR_OPCODE
, SH4Registers::sp
));
416 oneShortOp(getOpcodeGroup1(MOVL_WRITE_RNDEC_OPCODE
, SH4Registers::sp
, reg
));
419 void popReg(RegisterID reg
)
421 if (reg
== SH4Registers::pr
) {
422 oneShortOp(getOpcodeGroup2(LDSLPR_OPCODE
, SH4Registers::sp
));
426 oneShortOp(getOpcodeGroup1(MOVL_READ_RMINC_OPCODE
, reg
, SH4Registers::sp
));
429 void movt(RegisterID dst
)
431 uint16_t opc
= getOpcodeGroup2(MOVT_OPCODE
, dst
);
435 // Arithmetic operations
437 void addlRegReg(RegisterID src
, RegisterID dst
)
439 uint16_t opc
= getOpcodeGroup1(ADD_OPCODE
, dst
, src
);
443 void addclRegReg(RegisterID src
, RegisterID dst
)
445 uint16_t opc
= getOpcodeGroup1(ADDC_OPCODE
, dst
, src
);
449 void addvlRegReg(RegisterID src
, RegisterID dst
)
451 uint16_t opc
= getOpcodeGroup1(ADDV_OPCODE
, dst
, src
);
455 void addlImm8r(int imm8
, RegisterID dst
)
457 ASSERT((imm8
<= 127) && (imm8
>= -128));
459 uint16_t opc
= getOpcodeGroup3(ADDIMM_OPCODE
, dst
, imm8
);
463 void andlRegReg(RegisterID src
, RegisterID dst
)
465 uint16_t opc
= getOpcodeGroup1(AND_OPCODE
, dst
, src
);
469 void andlImm8r(int imm8
, RegisterID dst
)
471 ASSERT((imm8
<= 255) && (imm8
>= 0));
472 ASSERT_UNUSED(dst
, dst
== SH4Registers::r0
);
474 uint16_t opc
= getOpcodeGroup5(ANDIMM_OPCODE
, imm8
);
478 void div1lRegReg(RegisterID src
, RegisterID dst
)
480 uint16_t opc
= getOpcodeGroup1(DIV1_OPCODE
, dst
, src
);
484 void div0lRegReg(RegisterID src
, RegisterID dst
)
486 uint16_t opc
= getOpcodeGroup1(DIV0_OPCODE
, dst
, src
);
490 void notlReg(RegisterID src
, RegisterID dst
)
492 uint16_t opc
= getOpcodeGroup1(NOT_OPCODE
, dst
, src
);
496 void orlRegReg(RegisterID src
, RegisterID dst
)
498 uint16_t opc
= getOpcodeGroup1(OR_OPCODE
, dst
, src
);
502 void orlImm8r(int imm8
, RegisterID dst
)
504 ASSERT((imm8
<= 255) && (imm8
>= 0));
505 ASSERT_UNUSED(dst
, dst
== SH4Registers::r0
);
507 uint16_t opc
= getOpcodeGroup5(ORIMM_OPCODE
, imm8
);
511 void sublRegReg(RegisterID src
, RegisterID dst
)
513 uint16_t opc
= getOpcodeGroup1(SUB_OPCODE
, dst
, src
);
517 void subvlRegReg(RegisterID src
, RegisterID dst
)
519 uint16_t opc
= getOpcodeGroup1(SUBV_OPCODE
, dst
, src
);
523 void xorlRegReg(RegisterID src
, RegisterID dst
)
525 uint16_t opc
= getOpcodeGroup1(XOR_OPCODE
, dst
, src
);
529 void xorlImm8r(int imm8
, RegisterID dst
)
531 ASSERT((imm8
<= 255) && (imm8
>= 0));
532 ASSERT_UNUSED(dst
, dst
== SH4Registers::r0
);
534 uint16_t opc
= getOpcodeGroup5(XORIMM_OPCODE
, imm8
);
538 void shllImm8r(int imm
, RegisterID dst
)
542 oneShortOp(getOpcodeGroup2(SHLL_OPCODE
, dst
));
545 oneShortOp(getOpcodeGroup2(SHLL2_OPCODE
, dst
));
548 oneShortOp(getOpcodeGroup2(SHLL8_OPCODE
, dst
));
551 oneShortOp(getOpcodeGroup2(SHLL16_OPCODE
, dst
));
554 RELEASE_ASSERT_NOT_REACHED();
558 void neg(RegisterID dst
, RegisterID src
)
560 uint16_t opc
= getOpcodeGroup1(NEG_OPCODE
, dst
, src
);
564 void shldRegReg(RegisterID dst
, RegisterID rShift
)
566 oneShortOp(getOpcodeGroup1(SHLD_OPCODE
, dst
, rShift
));
569 void shadRegReg(RegisterID dst
, RegisterID rShift
)
571 oneShortOp(getOpcodeGroup1(SHAD_OPCODE
, dst
, rShift
));
574 void shlrImm8r(int imm
, RegisterID dst
)
578 oneShortOp(getOpcodeGroup2(SHLR_OPCODE
, dst
));
581 oneShortOp(getOpcodeGroup2(SHLR2_OPCODE
, dst
));
584 oneShortOp(getOpcodeGroup2(SHLR8_OPCODE
, dst
));
587 oneShortOp(getOpcodeGroup2(SHLR16_OPCODE
, dst
));
590 RELEASE_ASSERT_NOT_REACHED();
594 void shalImm8r(int imm
, RegisterID dst
)
598 oneShortOp(getOpcodeGroup2(SHAL_OPCODE
, dst
));
601 RELEASE_ASSERT_NOT_REACHED();
605 void sharImm8r(int imm
, RegisterID dst
)
609 oneShortOp(getOpcodeGroup2(SHAR_OPCODE
, dst
));
612 RELEASE_ASSERT_NOT_REACHED();
616 void imullRegReg(RegisterID src
, RegisterID dst
)
618 uint16_t opc
= getOpcodeGroup1(MULL_OPCODE
, dst
, src
);
622 void dmullRegReg(RegisterID src
, RegisterID dst
)
624 uint16_t opc
= getOpcodeGroup1(DMULL_L_OPCODE
, dst
, src
);
628 void dmulslRegReg(RegisterID src
, RegisterID dst
)
630 uint16_t opc
= getOpcodeGroup1(DMULSL_OPCODE
, dst
, src
);
634 void stsmacl(RegisterID reg
)
636 uint16_t opc
= getOpcodeGroup2(STSMACL_OPCODE
, reg
);
640 void stsmach(RegisterID reg
)
642 uint16_t opc
= getOpcodeGroup2(STSMACH_OPCODE
, reg
);
648 void cmplRegReg(RegisterID left
, RegisterID right
, Condition cond
)
652 oneShortOp(getOpcodeGroup1(CMPEQ_OPCODE
, right
, left
));
655 oneShortOp(getOpcodeGroup1(CMPGT_OPCODE
, right
, left
));
658 oneShortOp(getOpcodeGroup1(CMPEQ_OPCODE
, right
, left
));
661 oneShortOp(getOpcodeGroup1(CMPGE_OPCODE
, right
, left
));
664 oneShortOp(getOpcodeGroup1(CMPHS_OPCODE
, right
, left
));
667 oneShortOp(getOpcodeGroup1(CMPHI_OPCODE
, right
, left
));
670 oneShortOp(getOpcodeGroup1(CMPHI_OPCODE
, left
, right
));
673 oneShortOp(getOpcodeGroup1(CMPHS_OPCODE
, left
, right
));
676 oneShortOp(getOpcodeGroup1(CMPGE_OPCODE
, left
, right
));
679 oneShortOp(getOpcodeGroup1(CMPGT_OPCODE
, left
, right
));
682 RELEASE_ASSERT_NOT_REACHED();
686 void cmppl(RegisterID reg
)
688 uint16_t opc
= getOpcodeGroup2(CMPPL_OPCODE
, reg
);
692 void cmppz(RegisterID reg
)
694 uint16_t opc
= getOpcodeGroup2(CMPPZ_OPCODE
, reg
);
698 void cmpEqImmR0(int imm
, RegisterID dst
)
700 ASSERT_UNUSED(dst
, dst
== SH4Registers::r0
);
701 uint16_t opc
= getOpcodeGroup5(CMPEQIMM_OPCODE
, imm
);
705 void testlRegReg(RegisterID src
, RegisterID dst
)
707 uint16_t opc
= getOpcodeGroup1(TST_OPCODE
, dst
, src
);
711 void testlImm8r(int imm
, RegisterID dst
)
713 ASSERT((imm
<= 255) && (imm
>= 0));
714 ASSERT_UNUSED(dst
, dst
== SH4Registers::r0
);
716 uint16_t opc
= getOpcodeGroup5(TSTIMM_OPCODE
, imm
);
722 oneShortOp(NOP_OPCODE
, false);
727 oneShortOp(SYNCO_OPCODE
);
732 oneShortOp(SETT_OPCODE
);
737 oneShortOp(CLRT_OPCODE
);
742 oneShortOp(FSCHG_OPCODE
);
747 oneShortOp(BRK_OPCODE
, false);
750 void branch(uint16_t opc
, int label
)
754 ASSERT((label
<= 127) && (label
>= -128));
755 oneShortOp(getOpcodeGroup5(BT_OPCODE
, label
));
758 ASSERT((label
<= 2047) && (label
>= -2048));
759 oneShortOp(getOpcodeGroup6(BRA_OPCODE
, label
));
762 ASSERT((label
<= 127) && (label
>= -128));
763 oneShortOp(getOpcodeGroup5(BF_OPCODE
, label
));
766 RELEASE_ASSERT_NOT_REACHED();
770 void branch(uint16_t opc
, RegisterID reg
)
774 oneShortOp(getOpcodeGroup2(BRAF_OPCODE
, reg
));
777 oneShortOp(getOpcodeGroup2(JMP_OPCODE
, reg
));
780 oneShortOp(getOpcodeGroup2(JSR_OPCODE
, reg
));
783 oneShortOp(getOpcodeGroup2(BSRF_OPCODE
, reg
));
786 RELEASE_ASSERT_NOT_REACHED();
790 void ldspr(RegisterID reg
)
792 uint16_t opc
= getOpcodeGroup2(LDSPR_OPCODE
, reg
);
796 void stspr(RegisterID reg
)
798 uint16_t opc
= getOpcodeGroup2(STSPR_OPCODE
, reg
);
802 void extub(RegisterID src
, RegisterID dst
)
804 uint16_t opc
= getOpcodeGroup1(EXTUB_OPCODE
, dst
, src
);
808 void extuw(RegisterID src
, RegisterID dst
)
810 uint16_t opc
= getOpcodeGroup1(EXTUW_OPCODE
, dst
, src
);
816 void ldsrmfpul(RegisterID src
)
818 uint16_t opc
= getOpcodeGroup2(LDS_RM_FPUL_OPCODE
, src
);
822 void fneg(FPRegisterID dst
)
824 uint16_t opc
= getOpcodeGroup2(FNEG_OPCODE
, dst
);
825 oneShortOp(opc
, true, false);
828 void fsqrt(FPRegisterID dst
)
830 uint16_t opc
= getOpcodeGroup2(FSQRT_OPCODE
, dst
);
831 oneShortOp(opc
, true, false);
834 void stsfpulReg(RegisterID src
)
836 uint16_t opc
= getOpcodeGroup2(STS_FPUL_RN_OPCODE
, src
);
840 void floatfpulfrn(FPRegisterID src
)
842 uint16_t opc
= getOpcodeGroup2(FLOAT_OPCODE
, src
);
843 oneShortOp(opc
, true, false);
846 void fmull(FPRegisterID src
, FPRegisterID dst
)
848 uint16_t opc
= getOpcodeGroup1(FMUL_OPCODE
, dst
, src
);
849 oneShortOp(opc
, true, false);
852 void fmovsRegReg(FPRegisterID src
, FPRegisterID dst
)
854 uint16_t opc
= getOpcodeGroup1(FMOV_OPCODE
, dst
, src
);
855 oneShortOp(opc
, true, false);
858 void fmovsReadrm(RegisterID src
, FPRegisterID dst
)
860 uint16_t opc
= getOpcodeGroup1(FMOVS_READ_RM_OPCODE
, dst
, src
);
861 oneShortOp(opc
, true, false);
864 void fmovsWriterm(FPRegisterID src
, RegisterID dst
)
866 uint16_t opc
= getOpcodeGroup1(FMOVS_WRITE_RN_OPCODE
, dst
, src
);
867 oneShortOp(opc
, true, false);
870 void fmovsWriter0r(FPRegisterID src
, RegisterID dst
)
872 uint16_t opc
= getOpcodeGroup1(FMOVS_WRITE_R0RN_OPCODE
, dst
, src
);
873 oneShortOp(opc
, true, false);
876 void fmovsReadr0r(RegisterID src
, FPRegisterID dst
)
878 uint16_t opc
= getOpcodeGroup1(FMOVS_READ_R0RM_OPCODE
, dst
, src
);
879 oneShortOp(opc
, true, false);
882 void fmovsReadrminc(RegisterID src
, FPRegisterID dst
)
884 uint16_t opc
= getOpcodeGroup1(FMOVS_READ_RM_INC_OPCODE
, dst
, src
);
885 oneShortOp(opc
, true, false);
888 void fmovsWriterndec(FPRegisterID src
, RegisterID dst
)
890 uint16_t opc
= getOpcodeGroup1(FMOVS_WRITE_RN_DEC_OPCODE
, dst
, src
);
891 oneShortOp(opc
, true, false);
894 void ftrcRegfpul(FPRegisterID src
)
896 uint16_t opc
= getOpcodeGroup2(FTRC_OPCODE
, src
);
897 oneShortOp(opc
, true, false);
900 void fldsfpul(FPRegisterID src
)
902 uint16_t opc
= getOpcodeGroup2(FLDS_FRM_FPUL_OPCODE
, src
);
906 void fstsfpul(FPRegisterID src
)
908 uint16_t opc
= getOpcodeGroup2(FSTS_FPUL_FRN_OPCODE
, src
);
912 void ldsfpscr(RegisterID reg
)
914 uint16_t opc
= getOpcodeGroup2(LDSFPSCR_OPCODE
, reg
);
918 void stsfpscr(RegisterID reg
)
920 uint16_t opc
= getOpcodeGroup2(STSFPSCR_OPCODE
, reg
);
926 void dcnvds(FPRegisterID src
)
928 uint16_t opc
= getOpcodeGroup7(FCNVDS_DRM_FPUL_OPCODE
, src
>> 1);
932 void dcnvsd(FPRegisterID dst
)
934 uint16_t opc
= getOpcodeGroup7(FCNVSD_FPUL_DRN_OPCODE
, dst
>> 1);
938 void dcmppeq(FPRegisterID src
, FPRegisterID dst
)
940 uint16_t opc
= getOpcodeGroup8(FCMPEQ_OPCODE
, dst
>> 1, src
>> 1);
944 void dcmppgt(FPRegisterID src
, FPRegisterID dst
)
946 uint16_t opc
= getOpcodeGroup8(FCMPGT_OPCODE
, dst
>> 1, src
>> 1);
950 void dmulRegReg(FPRegisterID src
, FPRegisterID dst
)
952 uint16_t opc
= getOpcodeGroup8(FMUL_OPCODE
, dst
>> 1, src
>> 1);
956 void dsubRegReg(FPRegisterID src
, FPRegisterID dst
)
958 uint16_t opc
= getOpcodeGroup8(FSUB_OPCODE
, dst
>> 1, src
>> 1);
962 void daddRegReg(FPRegisterID src
, FPRegisterID dst
)
964 uint16_t opc
= getOpcodeGroup8(FADD_OPCODE
, dst
>> 1, src
>> 1);
968 void dmovRegReg(FPRegisterID src
, FPRegisterID dst
)
970 uint16_t opc
= getOpcodeGroup8(FMOV_OPCODE
, dst
>> 1, src
>> 1);
974 void ddivRegReg(FPRegisterID src
, FPRegisterID dst
)
976 uint16_t opc
= getOpcodeGroup8(FDIV_OPCODE
, dst
>> 1, src
>> 1);
980 void dabs(FPRegisterID dst
)
982 uint16_t opc
= getOpcodeGroup7(FABS_OPCODE
, dst
>> 1);
986 void dsqrt(FPRegisterID dst
)
988 uint16_t opc
= getOpcodeGroup7(FSQRT_OPCODE
, dst
>> 1);
992 void dneg(FPRegisterID dst
)
994 uint16_t opc
= getOpcodeGroup7(FNEG_OPCODE
, dst
>> 1);
998 void fmovReadrm(RegisterID src
, FPRegisterID dst
)
1000 uint16_t opc
= getOpcodeGroup10(FMOVS_READ_RM_OPCODE
, dst
>> 1, src
);
1004 void fmovWriterm(FPRegisterID src
, RegisterID dst
)
1006 uint16_t opc
= getOpcodeGroup9(FMOVS_WRITE_RN_OPCODE
, dst
, src
>> 1);
1010 void fmovWriter0r(FPRegisterID src
, RegisterID dst
)
1012 uint16_t opc
= getOpcodeGroup9(FMOVS_WRITE_R0RN_OPCODE
, dst
, src
>> 1);
1016 void fmovReadr0r(RegisterID src
, FPRegisterID dst
)
1018 uint16_t opc
= getOpcodeGroup10(FMOVS_READ_R0RM_OPCODE
, dst
>> 1, src
);
1022 void fmovReadrminc(RegisterID src
, FPRegisterID dst
)
1024 uint16_t opc
= getOpcodeGroup10(FMOVS_READ_RM_INC_OPCODE
, dst
>> 1, src
);
1028 void fmovWriterndec(FPRegisterID src
, RegisterID dst
)
1030 uint16_t opc
= getOpcodeGroup9(FMOVS_WRITE_RN_DEC_OPCODE
, dst
, src
>> 1);
1034 void floatfpulDreg(FPRegisterID src
)
1036 uint16_t opc
= getOpcodeGroup7(FLOAT_OPCODE
, src
>> 1);
1040 void ftrcdrmfpul(FPRegisterID src
)
1042 uint16_t opc
= getOpcodeGroup7(FTRC_OPCODE
, src
>> 1);
1048 void movImm8(int imm8
, RegisterID dst
)
1050 ASSERT((imm8
<= 127) && (imm8
>= -128));
1052 uint16_t opc
= getOpcodeGroup3(MOVIMM_OPCODE
, dst
, imm8
);
1056 void movlRegReg(RegisterID src
, RegisterID dst
)
1058 uint16_t opc
= getOpcodeGroup1(MOV_OPCODE
, dst
, src
);
1062 void movwRegMem(RegisterID src
, RegisterID dst
)
1064 uint16_t opc
= getOpcodeGroup1(MOVW_WRITE_RN_OPCODE
, dst
, src
);
1068 void movwMemReg(RegisterID src
, RegisterID dst
)
1070 uint16_t opc
= getOpcodeGroup1(MOVW_READ_RM_OPCODE
, dst
, src
);
1074 void movwMemRegIn(RegisterID base
, RegisterID dst
)
1076 uint16_t opc
= getOpcodeGroup1(MOVW_READ_RMINC_OPCODE
, dst
, base
);
1080 void movwPCReg(int offset
, RegisterID base
, RegisterID dst
)
1082 ASSERT_UNUSED(base
, base
== SH4Registers::pc
);
1083 ASSERT((offset
<= 255) && (offset
>= 0));
1085 uint16_t opc
= getOpcodeGroup3(MOVW_READ_OFFPC_OPCODE
, dst
, offset
);
1089 void movwMemReg(int offset
, RegisterID base
, RegisterID dst
)
1091 ASSERT_UNUSED(dst
, dst
== SH4Registers::r0
);
1093 uint16_t opc
= getOpcodeGroup11(MOVW_READ_OFFRM_OPCODE
, base
, offset
);
1097 void movwR0mr(RegisterID src
, RegisterID dst
)
1099 uint16_t opc
= getOpcodeGroup1(MOVW_READ_R0RM_OPCODE
, dst
, src
);
1103 void movwRegMemr0(RegisterID src
, RegisterID dst
)
1105 uint16_t opc
= getOpcodeGroup1(MOVW_WRITE_R0RN_OPCODE
, dst
, src
);
1109 void movlRegMem(RegisterID src
, int offset
, RegisterID base
)
1111 ASSERT((offset
<= 15) && (offset
>= 0));
1114 oneShortOp(getOpcodeGroup1(MOVL_WRITE_RN_OPCODE
, base
, src
));
1118 oneShortOp(getOpcodeGroup4(MOVL_WRITE_OFFRN_OPCODE
, base
, src
, offset
));
1121 void movlRegMem(RegisterID src
, RegisterID base
)
1123 uint16_t opc
= getOpcodeGroup1(MOVL_WRITE_RN_OPCODE
, base
, src
);
1127 void movlMemReg(int offset
, RegisterID base
, RegisterID dst
)
1129 if (base
== SH4Registers::pc
) {
1130 ASSERT((offset
<= 255) && (offset
>= 0));
1131 oneShortOp(getOpcodeGroup3(MOVL_READ_OFFPC_OPCODE
, dst
, offset
));
1135 ASSERT((offset
<= 15) && (offset
>= 0));
1137 oneShortOp(getOpcodeGroup1(MOVL_READ_RM_OPCODE
, dst
, base
));
1141 oneShortOp(getOpcodeGroup4(MOVL_READ_OFFRM_OPCODE
, dst
, base
, offset
));
1144 void movlMemRegCompact(int offset
, RegisterID base
, RegisterID dst
)
1146 oneShortOp(getOpcodeGroup4(MOVL_READ_OFFRM_OPCODE
, dst
, base
, offset
));
1149 void movbRegMem(RegisterID src
, RegisterID base
)
1151 uint16_t opc
= getOpcodeGroup1(MOVB_WRITE_RN_OPCODE
, base
, src
);
1155 void movbMemReg(int offset
, RegisterID base
, RegisterID dst
)
1157 ASSERT_UNUSED(dst
, dst
== SH4Registers::r0
);
1159 uint16_t opc
= getOpcodeGroup11(MOVB_READ_OFFRM_OPCODE
, base
, offset
);
1163 void movbR0mr(RegisterID src
, RegisterID dst
)
1165 uint16_t opc
= getOpcodeGroup1(MOVB_READ_R0RM_OPCODE
, dst
, src
);
1169 void movbMemReg(RegisterID src
, RegisterID dst
)
1171 uint16_t opc
= getOpcodeGroup1(MOVB_READ_RM_OPCODE
, dst
, src
);
1175 void movbMemRegIn(RegisterID base
, RegisterID dst
)
1177 uint16_t opc
= getOpcodeGroup1(MOVB_READ_RMINC_OPCODE
, dst
, base
);
1181 void movbRegMemr0(RegisterID src
, RegisterID dst
)
1183 uint16_t opc
= getOpcodeGroup1(MOVB_WRITE_R0RN_OPCODE
, dst
, src
);
1187 void movlMemReg(RegisterID base
, RegisterID dst
)
1189 uint16_t opc
= getOpcodeGroup1(MOVL_READ_RM_OPCODE
, dst
, base
);
1193 void movlMemRegIn(RegisterID base
, RegisterID dst
)
1195 uint16_t opc
= getOpcodeGroup1(MOVL_READ_RMINC_OPCODE
, dst
, base
);
1199 void movlR0mr(RegisterID src
, RegisterID dst
)
1201 uint16_t opc
= getOpcodeGroup1(MOVL_READ_R0RM_OPCODE
, dst
, src
);
1205 void movlRegMemr0(RegisterID src
, RegisterID dst
)
1207 uint16_t opc
= getOpcodeGroup1(MOVL_WRITE_R0RN_OPCODE
, dst
, src
);
1211 void loadConstant(uint32_t constant
, RegisterID dst
)
1213 if (((int)constant
<= 0x7f) && ((int)constant
>= -0x80)) {
1214 movImm8(constant
, dst
);
1218 uint16_t opc
= getOpcodeGroup3(MOVIMM_OPCODE
, dst
, 0);
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);
1225 void loadConstantUnReusable(uint32_t constant
, RegisterID dst
, bool ensureSpace
= false)
1227 uint16_t opc
= getOpcodeGroup3(MOVIMM_OPCODE
, dst
, 0);
1230 m_buffer
.ensureSpace(maxInstructionSize
, sizeof(uint32_t));
1232 printInstr(getOpcodeGroup3(MOVIMM_OPCODE
, dst
, constant
), m_buffer
.codeSize());
1233 m_buffer
.putShortWithConstantInt(opc
, constant
);
1238 AssemblerLabel
call()
1240 RegisterID scr
= claimScratch();
1241 m_buffer
.ensureSpace(maxInstructionSize
+ 4, sizeof(uint32_t));
1242 loadConstantUnReusable(0x0, scr
);
1243 branch(JSR_OPCODE
, scr
);
1245 releaseScratch(scr
);
1246 return m_buffer
.label();
1249 AssemblerLabel
call(RegisterID dst
)
1251 m_buffer
.ensureSpace(maxInstructionSize
+ 2);
1252 branch(JSR_OPCODE
, dst
);
1254 return m_buffer
.label();
1257 AssemblerLabel
jmp()
1259 RegisterID scr
= claimScratch();
1260 m_buffer
.ensureSpace(maxInstructionSize
+ 4, sizeof(uint32_t));
1261 loadConstantUnReusable(0x0, scr
);
1262 branch(BRAF_OPCODE
, scr
);
1264 releaseScratch(scr
);
1265 return m_buffer
.label();
1268 AssemblerLabel
extraInstrForBranch(RegisterID dst
)
1270 loadConstantUnReusable(0x0, dst
);
1271 branch(BRAF_OPCODE
, dst
);
1273 return m_buffer
.label();
1276 AssemblerLabel
jmp(RegisterID dst
)
1279 return m_buffer
.label();
1282 void jmpReg(RegisterID dst
)
1284 m_buffer
.ensureSpace(maxInstructionSize
+ 2);
1285 branch(JMP_OPCODE
, dst
);
1289 AssemblerLabel
jne()
1291 branch(BF_OPCODE
, 0);
1292 return m_buffer
.label();
1297 branch(BT_OPCODE
, 0);
1298 return m_buffer
.label();
1301 AssemblerLabel
bra()
1303 branch(BRA_OPCODE
, 0);
1304 return m_buffer
.label();
1309 m_buffer
.ensureSpace(maxInstructionSize
+ 2);
1310 oneShortOp(RTS_OPCODE
, false);
1313 AssemblerLabel
labelIgnoringWatchpoints()
1315 m_buffer
.ensureSpaceForAnyInstruction();
1316 return m_buffer
.label();
1319 AssemblerLabel
labelForWatchpoint()
1321 m_buffer
.ensureSpaceForAnyInstruction();
1322 AssemblerLabel result
= m_buffer
.label();
1323 if (static_cast<int>(result
.m_offset
) != m_indexOfLastWatchpoint
)
1325 m_indexOfLastWatchpoint
= result
.m_offset
;
1326 m_indexOfTailOfLastWatchpoint
= result
.m_offset
+ maxJumpReplacementSize();
1330 AssemblerLabel
label()
1332 AssemblerLabel result
= labelIgnoringWatchpoints();
1333 while (UNLIKELY(static_cast<int>(result
.m_offset
) < m_indexOfTailOfLastWatchpoint
)) {
1335 result
= labelIgnoringWatchpoints();
1340 int sizeOfConstantPool()
1342 return m_buffer
.sizeOfConstantPool();
1345 AssemblerLabel
align(int alignment
)
1347 m_buffer
.ensureSpace(maxInstructionSize
+ 2);
1348 while (!m_buffer
.isAligned(alignment
)) {
1350 m_buffer
.ensureSpace(maxInstructionSize
+ 2);
1355 static void changePCrelativeAddress(int offset
, uint16_t* instructionPtr
, uint32_t newAddress
)
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
;
1362 static uint32_t readPCrelativeAddress(int offset
, uint16_t* instructionPtr
)
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
);
1369 static uint16_t* getInstructionPtr(void* code
, int offset
)
1371 return reinterpret_cast<uint16_t*> (reinterpret_cast<uint32_t>(code
) + offset
);
1374 static void linkJump(void* code
, AssemblerLabel from
, void* to
)
1376 ASSERT(from
.isSet());
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
;
1381 /* MOV #imm, reg => LDR reg
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);
1391 static void linkCall(void* code
, AssemblerLabel from
, void* to
)
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
));
1399 static void linkPointer(void* code
, AssemblerLabel where
, void* value
)
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
));
1406 static unsigned getCallReturnOffset(AssemblerLabel call
)
1408 ASSERT(call
.isSet());
1409 return call
.m_offset
;
1412 static uint32_t* getLdrImmAddressOnPool(SH4Word
* insn
, uint32_t* constPool
)
1414 return (constPool
+ (*insn
& 0xff));
1417 static SH4Word
patchConstantPoolLoad(SH4Word load
, int value
)
1419 return ((load
& ~0xff) | value
);
1422 static SH4Buffer::TwoShorts
placeConstantPoolBarrier(int offset
)
1424 ASSERT(((offset
>> 1) <= 2047) && ((offset
>> 1) >= -2048));
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);
1434 static void patchConstantPoolLoad(void* loadAddr
, void* constPoolAddr
)
1436 SH4Word
* instructionPtr
= reinterpret_cast<SH4Word
*>(loadAddr
);
1437 SH4Word instruction
= *instructionPtr
;
1438 SH4Word index
= instruction
& 0xff;
1440 if ((instruction
& 0xf000) != MOVIMM_OPCODE
)
1443 ASSERT((((reinterpret_cast<uint32_t>(constPoolAddr
) - reinterpret_cast<uint32_t>(loadAddr
)) + index
* 4)) < 1024);
1445 int offset
= reinterpret_cast<uint32_t>(constPoolAddr
) + (index
* 4) - ((reinterpret_cast<uint32_t>(instructionPtr
) & ~0x03) + 4);
1446 instruction
&= 0x0f00;
1447 instruction
|= 0xd000;
1449 instruction
|= (offset
>> 2);
1450 *instructionPtr
= instruction
;
1451 printInstr(instruction
, reinterpret_cast<uint32_t>(loadAddr
));
1454 static void repatchPointer(void* where
, void* value
)
1456 patchPointer(where
, value
);
1459 static void* readPointer(void* code
)
1461 return reinterpret_cast<void*>(readInt32(code
));
1464 static void repatchInt32(void* where
, int32_t value
)
1466 uint16_t* instructionPtr
= reinterpret_cast<uint16_t*>(where
);
1467 ASSERT((instructionPtr
[0] & 0xf000) == MOVL_READ_OFFPC_OPCODE
);
1468 changePCrelativeAddress((*instructionPtr
& 0xff), instructionPtr
, value
);
1471 static void repatchCompact(void* where
, int32_t value
)
1473 uint16_t* instructionPtr
= reinterpret_cast<uint16_t*>(where
);
1475 ASSERT(value
<= 60);
1477 // Handle the uncommon case where a flushConstantPool occured in movlMemRegCompact.
1478 if ((instructionPtr
[0] & 0xf000) == BRA_OPCODE
)
1479 instructionPtr
+= (instructionPtr
[0] & 0x0fff) + 2;
1481 ASSERT((instructionPtr
[0] & 0xf000) == MOVL_READ_OFFRM_OPCODE
);
1482 instructionPtr
[0] = (instructionPtr
[0] & 0xfff0) | (value
>> 2);
1483 cacheFlush(instructionPtr
, sizeof(uint16_t));
1486 static void relinkCall(void* from
, void* to
)
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
));
1494 static void relinkJump(void* from
, void* to
)
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
));
1503 // Linking & patching
1505 static ptrdiff_t maxJumpReplacementSize()
1507 return sizeof(SH4Word
) * 6;
1510 static void replaceWithJump(void *instructionStart
, void *to
)
1512 SH4Word
* instruction
= reinterpret_cast<SH4Word
*>(instructionStart
);
1513 intptr_t difference
= reinterpret_cast<intptr_t>(to
) - (reinterpret_cast<intptr_t>(instruction
) + 3 * sizeof(SH4Word
));
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
));
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
));
1530 changePCrelativeAddress(instruction
[0] & 0x00ff, instruction
, difference
);
1533 static void revertJumpReplacementToBranchPtrWithPatch(void* instructionStart
, RegisterID rd
, int imm
)
1535 SH4Word
*insn
= reinterpret_cast<SH4Word
*>(instructionStart
);
1536 ASSERT((insn
[0] & 0xf000) == MOVL_READ_OFFPC_OPCODE
);
1537 ASSERT((insn
[0] & 0x00ff) != 1);
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.
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
));
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
);
1558 changePCrelativeAddress(insn
[0] & 0x00ff, insn
, imm
);
1561 void linkJump(AssemblerLabel from
, AssemblerLabel to
, JumpType type
= JumpFar
)
1564 ASSERT(from
.isSet());
1566 uint16_t* instructionPtr
= getInstructionPtr(data(), from
.m_offset
) - 1;
1567 int offsetBits
= (to
.m_offset
- from
.m_offset
);
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);
1579 /* MOV # imm, reg => LDR reg
1583 instructionPtr
-= 2;
1584 ASSERT((instructionPtr
[1] & 0xf0ff) == BRAF_OPCODE
);
1586 if ((instructionPtr
[0] & 0xf000) == MOVIMM_OPCODE
) {
1587 uint32_t* addr
= getLdrImmAddressOnPool(instructionPtr
, m_buffer
.poolAddress());
1589 printInstr(*instructionPtr
, from
.m_offset
+ 2);
1593 ASSERT((instructionPtr
[0] & 0xf000) == MOVL_READ_OFFPC_OPCODE
);
1594 changePCrelativeAddress((*instructionPtr
& 0xff), instructionPtr
, offsetBits
);
1595 printInstr(*instructionPtr
, from
.m_offset
+ 2);
1598 static void* getRelocatedAddress(void* code
, AssemblerLabel label
)
1600 return reinterpret_cast<void*>(reinterpret_cast<char*>(code
) + label
.m_offset
);
1603 static int getDifferenceBetweenLabels(AssemblerLabel a
, AssemblerLabel b
)
1605 return b
.m_offset
- a
.m_offset
;
1608 static void patchPointer(void* code
, AssemblerLabel where
, void* value
)
1610 patchPointer(reinterpret_cast<uint32_t*>(code
) + where
.m_offset
, value
);
1613 static void patchPointer(void* code
, void* value
)
1615 patchInt32(code
, reinterpret_cast<uint32_t>(value
));
1618 static void patchInt32(void* code
, uint32_t value
)
1620 changePCrelativeAddress((*(reinterpret_cast<uint16_t*>(code
)) & 0xff), reinterpret_cast<uint16_t*>(code
), value
);
1623 static uint32_t readInt32(void* code
)
1625 return readPCrelativeAddress((*(reinterpret_cast<uint16_t*>(code
)) & 0xff), reinterpret_cast<uint16_t*>(code
));
1628 static void* readCallTarget(void* from
)
1630 uint16_t* instructionPtr
= static_cast<uint16_t*>(from
);
1631 instructionPtr
-= 3;
1632 return reinterpret_cast<void*>(readPCrelativeAddress((*instructionPtr
& 0xff), instructionPtr
));
1635 static void cacheFlush(void* code
, size_t size
)
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);
1642 #if defined CACHEFLUSH_D_L2
1643 syscall(__NR_cacheflush
, currentPage
, pageSize(), CACHEFLUSH_D_WB
| CACHEFLUSH_I
| CACHEFLUSH_D_L2
);
1645 syscall(__NR_cacheflush
, currentPage
, pageSize(), CACHEFLUSH_D_WB
| CACHEFLUSH_I
);
1647 currentPage
+= pageSize();
1648 } while (lastPage
>= currentPage
);
1650 #error "The cacheFlush support is missing on this platform."
1654 void prefix(uint16_t pre
)
1656 m_buffer
.putByte(pre
);
1659 void oneShortOp(uint16_t opcode
, bool checksize
= true, bool isDouble
= true)
1661 printInstr(opcode
, m_buffer
.codeSize(), isDouble
);
1663 m_buffer
.ensureSpace(maxInstructionSize
);
1664 m_buffer
.putShortUnchecked(opcode
);
1667 void ensureSpace(int space
)
1669 m_buffer
.ensureSpace(space
);
1672 void ensureSpace(int insnSpace
, int constSpace
)
1674 m_buffer
.ensureSpace(insnSpace
, constSpace
);
1677 // Administrative methods
1679 void* data() const { return m_buffer
.data(); }
1680 size_t codeSize() const { return m_buffer
.codeSize(); }
1682 unsigned debugOffset() { return m_buffer
.debugOffset(); }
1684 #ifdef SH4_ASSEMBLER_TRACING
1685 static void printInstr(uint16_t opc
, unsigned size
, bool isdoubleInst
= true)
1687 if (!getenv("JavaScriptCoreDumpJIT"))
1690 const char *format
= 0;
1691 printfStdoutInstr("offset: 0x%8.8x\t", size
);
1712 format
= " FSCHG\n";
1716 printfStdoutInstr(format
);
1719 switch (opc
& 0xf0ff) {
1721 format
= " *BRAF R%d\n";
1724 format
= " DT R%d\n";
1727 format
= " CMP/PL R%d\n";
1730 format
= " CMP/PZ R%d\n";
1733 format
= " *JMP @R%d\n";
1736 format
= " *JSR @R%d\n";
1739 format
= " LDS R%d, PR\n";
1742 format
= " LDS.L @R%d+, PR\n";
1745 format
= " MOVT R%d\n";
1748 format
= " SHAL R%d\n";
1751 format
= " SHAR R%d\n";
1754 format
= " SHLL R%d\n";
1757 format
= " SHLL2 R%d\n";
1760 format
= " SHLL8 R%d\n";
1763 format
= " SHLL16 R%d\n";
1766 format
= " SHLR R%d\n";
1769 format
= " SHLR2 R%d\n";
1772 format
= " SHLR8 R%d\n";
1775 format
= " SHLR16 R%d\n";
1778 format
= " STS PR, R%d\n";
1781 format
= " STS.L PR, @-R%d\n";
1783 case LDS_RM_FPUL_OPCODE
:
1784 format
= " LDS R%d, FPUL\n";
1786 case STS_FPUL_RN_OPCODE
:
1787 format
= " STS FPUL, R%d \n";
1789 case FLDS_FRM_FPUL_OPCODE
:
1790 format
= " FLDS FR%d, FPUL\n";
1792 case FSTS_FPUL_FRN_OPCODE
:
1793 format
= " FSTS FPUL, R%d \n";
1795 case LDSFPSCR_OPCODE
:
1796 format
= " LDS R%d, FPSCR \n";
1798 case STSFPSCR_OPCODE
:
1799 format
= " STS FPSCR, R%d \n";
1801 case STSMACL_OPCODE
:
1802 format
= " STS MACL, R%d \n";
1804 case STSMACH_OPCODE
:
1805 format
= " STS MACH, R%d \n";
1808 format
= " *BSRF R%d";
1811 format
= " FTRC FR%d, FPUL\n";
1815 printfStdoutInstr(format
, getRn(opc
));
1818 switch (opc
& 0xf0ff) {
1820 format
= " FNEG DR%d\n";
1823 format
= " FLOAT DR%d\n";
1826 format
= " FTRC FR%d, FPUL\n";
1829 format
= " FABS FR%d\n";
1832 format
= " FSQRT FR%d\n";
1834 case FCNVDS_DRM_FPUL_OPCODE
:
1835 format
= " FCNVDS FR%d, FPUL\n";
1837 case FCNVSD_FPUL_DRN_OPCODE
:
1838 format
= " FCNVSD FPUL, FR%d\n";
1843 printfStdoutInstr(format
, getDRn(opc
) << 1);
1845 printfStdoutInstr(format
, getRn(opc
));
1848 switch (opc
& 0xf00f) {
1850 format
= " ADD R%d, R%d\n";
1853 format
= " ADDC R%d, R%d\n";
1856 format
= " ADDV R%d, R%d\n";
1859 format
= " AND R%d, R%d\n";
1862 format
= " DIV1 R%d, R%d\n";
1865 format
= " CMP/EQ R%d, R%d\n";
1868 format
= " CMP/GE R%d, R%d\n";
1871 format
= " CMP/GT R%d, R%d\n";
1874 format
= " CMP/HI R%d, R%d\n";
1877 format
= " CMP/HS R%d, R%d\n";
1880 format
= " MOV R%d, R%d\n";
1882 case MOVB_WRITE_RN_OPCODE
:
1883 format
= " MOV.B R%d, @R%d\n";
1885 case MOVB_WRITE_RNDEC_OPCODE
:
1886 format
= " MOV.B R%d, @-R%d\n";
1888 case MOVB_WRITE_R0RN_OPCODE
:
1889 format
= " MOV.B R%d, @(R0, R%d)\n";
1891 case MOVB_READ_RM_OPCODE
:
1892 format
= " MOV.B @R%d, R%d\n";
1894 case MOVB_READ_RMINC_OPCODE
:
1895 format
= " MOV.B @R%d+, R%d\n";
1897 case MOVB_READ_R0RM_OPCODE
:
1898 format
= " MOV.B @(R0, R%d), R%d\n";
1900 case MOVL_WRITE_RN_OPCODE
:
1901 format
= " MOV.L R%d, @R%d\n";
1903 case MOVL_WRITE_RNDEC_OPCODE
:
1904 format
= " MOV.L R%d, @-R%d\n";
1906 case MOVL_WRITE_R0RN_OPCODE
:
1907 format
= " MOV.L R%d, @(R0, R%d)\n";
1909 case MOVL_READ_RM_OPCODE
:
1910 format
= " MOV.L @R%d, R%d\n";
1912 case MOVL_READ_RMINC_OPCODE
:
1913 format
= " MOV.L @R%d+, R%d\n";
1915 case MOVL_READ_R0RM_OPCODE
:
1916 format
= " MOV.L @(R0, R%d), R%d\n";
1919 format
= " MUL.L R%d, R%d\n";
1921 case DMULL_L_OPCODE
:
1922 format
= " DMULU.L R%d, R%d\n";
1925 format
= " DMULS.L R%d, R%d\n";
1928 format
= " NEG R%d, R%d\n";
1931 format
= " NEGC R%d, R%d\n";
1934 format
= " NOT R%d, R%d\n";
1937 format
= " OR R%d, R%d\n";
1940 format
= " SHAD R%d, R%d\n";
1943 format
= " SHLD R%d, R%d\n";
1946 format
= " SUB R%d, R%d\n";
1949 format
= " SUBC R%d, R%d\n";
1952 format
= " SUBV R%d, R%d\n";
1955 format
= " TST R%d, R%d\n";
1958 format
= " XOR R%d, R%d\n";break;
1959 case MOVW_WRITE_RN_OPCODE
:
1960 format
= " MOV.W R%d, @R%d\n";
1962 case MOVW_READ_RM_OPCODE
:
1963 format
= " MOV.W @R%d, R%d\n";
1965 case MOVW_READ_RMINC_OPCODE
:
1966 format
= " MOV.W @R%d+, R%d\n";
1968 case MOVW_READ_R0RM_OPCODE
:
1969 format
= " MOV.W @(R0, R%d), R%d\n";
1971 case MOVW_WRITE_R0RN_OPCODE
:
1972 format
= " MOV.W R%d, @(R0, R%d)\n";
1975 format
= " EXTU.B R%d, R%d\n";
1978 format
= " EXTU.W R%d, R%d\n";
1982 printfStdoutInstr(format
, getRm(opc
), getRn(opc
));
1985 switch (opc
& 0xf00f) {
1987 format
= " FSUB FR%d, FR%d\n";
1990 format
= " FADD FR%d, FR%d\n";
1993 format
= " FDIV FR%d, FR%d\n";
1996 format
= " DMULL FR%d, FR%d\n";
1999 format
= " FMOV FR%d, FR%d\n";
2002 format
= " FCMP/EQ FR%d, FR%d\n";
2005 format
= " FCMP/GT FR%d, FR%d\n";
2010 printfStdoutInstr(format
, getDRm(opc
) << 1, getDRn(opc
) << 1);
2012 printfStdoutInstr(format
, getRm(opc
), getRn(opc
));
2015 switch (opc
& 0xf00f) {
2016 case FMOVS_WRITE_RN_DEC_OPCODE
:
2017 format
= " %s FR%d, @-R%d\n";
2019 case FMOVS_WRITE_RN_OPCODE
:
2020 format
= " %s FR%d, @R%d\n";
2022 case FMOVS_WRITE_R0RN_OPCODE
:
2023 format
= " %s FR%d, @(R0, R%d)\n";
2028 printfStdoutInstr(format
, "FMOV", getDRm(opc
) << 1, getDRn(opc
));
2030 printfStdoutInstr(format
, "FMOV.S", getRm(opc
), getRn(opc
));
2033 switch (opc
& 0xf00f) {
2034 case FMOVS_READ_RM_OPCODE
:
2035 format
= " %s @R%d, FR%d\n";
2037 case FMOVS_READ_RM_INC_OPCODE
:
2038 format
= " %s @R%d+, FR%d\n";
2040 case FMOVS_READ_R0RM_OPCODE
:
2041 format
= " %s @(R0, R%d), FR%d\n";
2046 printfStdoutInstr(format
, "FMOV", getDRm(opc
), getDRn(opc
) << 1);
2048 printfStdoutInstr(format
, "FMOV.S", getRm(opc
), getRn(opc
));
2051 switch (opc
& 0xff00) {
2053 format
= " BF %d\n";
2056 format
= " *BF/S %d\n";
2059 format
= " AND #%d, R0\n";
2062 format
= " BT %d\n";
2065 format
= " *BT/S %d\n";
2067 case CMPEQIMM_OPCODE
:
2068 format
= " CMP/EQ #%d, R0\n";
2070 case MOVB_WRITE_OFFGBR_OPCODE
:
2071 format
= " MOV.B R0, @(%d, GBR)\n";
2073 case MOVB_READ_OFFGBR_OPCODE
:
2074 format
= " MOV.B @(%d, GBR), R0\n";
2076 case MOVL_WRITE_OFFGBR_OPCODE
:
2077 format
= " MOV.L R0, @(%d, GBR)\n";
2079 case MOVL_READ_OFFGBR_OPCODE
:
2080 format
= " MOV.L @(%d, GBR), R0\n";
2082 case MOVA_READ_OFFPC_OPCODE
:
2083 format
= " MOVA @(%d, PC), R0\n";
2086 format
= " OR #%d, R0\n";
2089 format
= " OR.B #%d, @(R0, GBR)\n";
2092 format
= " TST #%d, R0\n";
2095 format
= " TST.B %d, @(R0, GBR)\n";
2098 format
= " XOR #%d, R0\n";
2101 format
= " XOR.B %d, @(R0, GBR)\n";
2105 printfStdoutInstr(format
, getImm8(opc
));
2108 switch (opc
& 0xff00) {
2109 case MOVB_WRITE_OFFRN_OPCODE
:
2110 format
= " MOV.B R0, @(%d, R%d)\n";
2112 case MOVB_READ_OFFRM_OPCODE
:
2113 format
= " MOV.B @(%d, R%d), R0\n";
2117 printfStdoutInstr(format
, getDisp(opc
), getRm(opc
));
2120 switch (opc
& 0xf000) {
2122 format
= " *BRA %d\n";
2125 format
= " *BSR %d\n";
2129 printfStdoutInstr(format
, getImm12(opc
));
2132 switch (opc
& 0xf000) {
2133 case MOVL_READ_OFFPC_OPCODE
:
2134 format
= " MOV.L @(%d, PC), R%d\n";
2137 format
= " ADD #%d, R%d\n";
2140 format
= " MOV #%d, R%d\n";
2142 case MOVW_READ_OFFPC_OPCODE
:
2143 format
= " MOV.W @(%d, PC), R%d\n";
2147 printfStdoutInstr(format
, getImm8(opc
), getRn(opc
));
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
));
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
));
2162 static void printfStdoutInstr(const char* format
, ...)
2164 if (getenv("JavaScriptCoreDumpJIT")) {
2166 va_start(args
, format
);
2167 vprintfStdoutInstr(format
, args
);
2172 static void vprintfStdoutInstr(const char* format
, va_list args
)
2174 if (getenv("JavaScriptCoreDumpJIT"))
2175 WTF::dataLogFV(format
, args
);
2178 static void printBlockInstr(uint16_t* first
, unsigned offset
, int nbInstr
)
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");
2186 static void printInstr(uint16_t, unsigned, bool = true) { };
2187 static void printBlockInstr(uint16_t*, unsigned, int) { };
2190 static void replaceWithLoad(void* instructionStart
)
2192 SH4Word
* insPtr
= reinterpret_cast<SH4Word
*>(instructionStart
);
2194 insPtr
+= 2; // skip MOV and ADD opcodes
2196 if (((*insPtr
) & 0xf00f) != MOVL_READ_RM_OPCODE
) {
2197 *insPtr
= MOVL_READ_RM_OPCODE
| (*insPtr
& 0x0ff0);
2198 cacheFlush(insPtr
, sizeof(SH4Word
));
2202 static void replaceWithAddressComputation(void* instructionStart
)
2204 SH4Word
* insPtr
= reinterpret_cast<SH4Word
*>(instructionStart
);
2206 insPtr
+= 2; // skip MOV and ADD opcodes
2208 if (((*insPtr
) & 0xf00f) != MOV_OPCODE
) {
2209 *insPtr
= MOV_OPCODE
| (*insPtr
& 0x0ff0);
2210 cacheFlush(insPtr
, sizeof(SH4Word
));
2216 int m_claimscratchReg
;
2217 int m_indexOfLastWatchpoint
;
2218 int m_indexOfTailOfLastWatchpoint
;
2223 #endif // ENABLE(ASSEMBLER) && CPU(SH4)
2225 #endif // SH4Assembler_h