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