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
48namespace JSC {
49typedef uint16_t SH4Word;
50
51enum {
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
189namespace SH4Registers {
190typedef 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
211typedef 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
231inline uint16_t getOpcodeGroup1(uint16_t opc, int rm, int rn)
232{
233    return (opc | ((rm & 0xf) << 8) | ((rn & 0xf) << 4));
234}
235
236inline uint16_t getOpcodeGroup2(uint16_t opc, int rm)
237{
238    return (opc | ((rm & 0xf) << 8));
239}
240
241inline uint16_t getOpcodeGroup3(uint16_t opc, int rm, int rn)
242{
243    return (opc | ((rm & 0xf) << 8) | (rn & 0xff));
244}
245
246inline 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
251inline uint16_t getOpcodeGroup5(uint16_t opc, int rm)
252{
253    return (opc | (rm & 0xff));
254}
255
256inline uint16_t getOpcodeGroup6(uint16_t opc, int rm)
257{
258    return (opc | (rm & 0xfff));
259}
260
261inline uint16_t getOpcodeGroup7(uint16_t opc, int rm)
262{
263    return (opc | ((rm & 0x7) << 9));
264}
265
266inline uint16_t getOpcodeGroup8(uint16_t opc, int rm, int rn)
267{
268    return (opc | ((rm & 0x7) << 9) | ((rn & 0x7) << 5));
269}
270
271inline uint16_t getOpcodeGroup9(uint16_t opc, int rm, int rn)
272{
273    return (opc | ((rm & 0xf) << 8) | ((rn & 0x7) << 5));
274}
275
276inline uint16_t getOpcodeGroup10(uint16_t opc, int rm, int rn)
277{
278    return (opc | ((rm & 0x7) << 9) | ((rn & 0xf) << 4));
279}
280
281inline uint16_t getOpcodeGroup11(uint16_t opc, int rm, int rn)
282{
283    return (opc | ((rm & 0xf) << 4) | (rn & 0xf));
284}
285
286inline uint16_t getRn(uint16_t x)
287{
288    return ((x & 0xf00) >> 8);
289}
290
291inline uint16_t getRm(uint16_t x)
292{
293    return ((x & 0xf0) >> 4);
294}
295
296inline uint16_t getDisp(uint16_t x)
297{
298    return (x & 0xf);
299}
300
301inline uint16_t getImm8(uint16_t x)
302{
303    return (x & 0xff);
304}
305
306inline uint16_t getImm12(uint16_t x)
307{
308    return (x & 0xfff);
309}
310
311inline uint16_t getDRn(uint16_t x)
312{
313    return ((x & 0xe00) >> 9);
314}
315
316inline uint16_t getDRm(uint16_t x)
317{
318    return ((x & 0xe0) >> 5);
319}
320
321class SH4Assembler {
322public:
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
380public:
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
2214private:
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
2226