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 MacroAssemblerSH4_h
29#define MacroAssemblerSH4_h
30
31#if ENABLE(ASSEMBLER) && CPU(SH4)
32
33#include "SH4Assembler.h"
34#include "AbstractMacroAssembler.h"
35#include <wtf/Assertions.h>
36
37namespace JSC {
38
39class MacroAssemblerSH4 : public AbstractMacroAssembler<SH4Assembler> {
40public:
41    typedef SH4Assembler::FPRegisterID FPRegisterID;
42
43    static const Scale ScalePtr = TimesFour;
44    static const FPRegisterID fscratch = SH4Registers::dr10;
45    static const RegisterID stackPointerRegister = SH4Registers::sp;
46    static const RegisterID framePointerRegister = SH4Registers::fp;
47    static const RegisterID linkRegister = SH4Registers::pr;
48    static const RegisterID scratchReg3 = SH4Registers::r13;
49
50    static const int MaximumCompactPtrAlignedAddressOffset = 60;
51
52    static bool isCompactPtrAlignedAddressOffset(ptrdiff_t value)
53    {
54        return (value >= 0) && (value <= MaximumCompactPtrAlignedAddressOffset) && (!(value & 3));
55    }
56
57    enum RelationalCondition {
58        Equal = SH4Assembler::EQ,
59        NotEqual = SH4Assembler::NE,
60        Above = SH4Assembler::HI,
61        AboveOrEqual = SH4Assembler::HS,
62        Below = SH4Assembler::LI,
63        BelowOrEqual = SH4Assembler::LS,
64        GreaterThan = SH4Assembler::GT,
65        GreaterThanOrEqual = SH4Assembler::GE,
66        LessThan = SH4Assembler::LT,
67        LessThanOrEqual = SH4Assembler::LE
68    };
69
70    enum ResultCondition {
71        Overflow = SH4Assembler::OF,
72        Signed = SH4Assembler::SI,
73        PositiveOrZero = SH4Assembler::NS,
74        Zero = SH4Assembler::EQ,
75        NonZero = SH4Assembler::NE
76    };
77
78    enum DoubleCondition {
79        // These conditions will only evaluate to true if the comparison is ordered - i.e. neither operand is NaN.
80        DoubleEqual = SH4Assembler::EQ,
81        DoubleNotEqual = SH4Assembler::NE,
82        DoubleGreaterThan = SH4Assembler::GT,
83        DoubleGreaterThanOrEqual = SH4Assembler::GE,
84        DoubleLessThan = SH4Assembler::LT,
85        DoubleLessThanOrEqual = SH4Assembler::LE,
86        // If either operand is NaN, these conditions always evaluate to true.
87        DoubleEqualOrUnordered = SH4Assembler::EQU,
88        DoubleNotEqualOrUnordered = SH4Assembler::NEU,
89        DoubleGreaterThanOrUnordered = SH4Assembler::GTU,
90        DoubleGreaterThanOrEqualOrUnordered = SH4Assembler::GEU,
91        DoubleLessThanOrUnordered = SH4Assembler::LTU,
92        DoubleLessThanOrEqualOrUnordered = SH4Assembler::LEU,
93    };
94
95    RegisterID claimScratch()
96    {
97        return m_assembler.claimScratch();
98    }
99
100    void releaseScratch(RegisterID reg)
101    {
102        m_assembler.releaseScratch(reg);
103    }
104
105    static RelationalCondition invert(RelationalCondition cond)
106    {
107        switch (cond) {
108        case Equal:
109            return NotEqual;
110        case NotEqual:
111            return Equal;
112        case Above:
113            return BelowOrEqual;
114        case AboveOrEqual:
115            return Below;
116        case Below:
117            return AboveOrEqual;
118        case BelowOrEqual:
119            return Above;
120        case GreaterThan:
121            return LessThanOrEqual;
122        case GreaterThanOrEqual:
123            return LessThan;
124        case LessThan:
125            return GreaterThanOrEqual;
126        case LessThanOrEqual:
127            return GreaterThan;
128        default:
129            RELEASE_ASSERT_NOT_REACHED();
130        }
131    }
132
133    // Integer arithmetic operations
134
135    void add32(RegisterID src, RegisterID dest)
136    {
137        m_assembler.addlRegReg(src, dest);
138    }
139
140    void add32(RegisterID src1, RegisterID src2, RegisterID dest)
141    {
142        if (src1 == dest)
143            add32(src2, dest);
144        else {
145            move(src2, dest);
146            add32(src1, dest);
147        }
148    }
149
150    void add32(TrustedImm32 imm, RegisterID dest)
151    {
152        if (!imm.m_value)
153            return;
154
155        if (m_assembler.isImmediate(imm.m_value)) {
156            m_assembler.addlImm8r(imm.m_value, dest);
157            return;
158        }
159
160        RegisterID scr = claimScratch();
161        m_assembler.loadConstant(imm.m_value, scr);
162        m_assembler.addlRegReg(scr, dest);
163        releaseScratch(scr);
164    }
165
166    void add32(TrustedImm32 imm, RegisterID src, RegisterID dest)
167    {
168        move(src, dest);
169        add32(imm, dest);
170    }
171
172    void add32(TrustedImm32 imm, Address address)
173    {
174        if (!imm.m_value)
175            return;
176
177        RegisterID scr = claimScratch();
178        load32(address, scr);
179        add32(imm, scr);
180        store32(scr, address);
181        releaseScratch(scr);
182    }
183
184    void add32(Address src, RegisterID dest)
185    {
186        RegisterID scr = claimScratch();
187        load32(src, scr);
188        m_assembler.addlRegReg(scr, dest);
189        releaseScratch(scr);
190    }
191
192    void add32(AbsoluteAddress src, RegisterID dest)
193    {
194        RegisterID scr = claimScratch();
195        load32(src.m_ptr, scr);
196        m_assembler.addlRegReg(scr, dest);
197        releaseScratch(scr);
198    }
199
200    void and32(RegisterID src, RegisterID dest)
201    {
202        m_assembler.andlRegReg(src, dest);
203    }
204
205    void and32(RegisterID src1, RegisterID src2, RegisterID dest)
206    {
207        if (src1 == dest)
208            and32(src2, dest);
209        else {
210            move(src2, dest);
211            and32(src1, dest);
212        }
213    }
214
215    void and32(Address src, RegisterID dest)
216    {
217        RegisterID scr = claimScratch();
218        load32(src, scr);
219        and32(scr, dest);
220        releaseScratch(scr);
221    }
222
223    void and32(TrustedImm32 imm, RegisterID dest)
224    {
225        if (!imm.m_value) {
226            m_assembler.movImm8(0, dest);
227            return;
228        }
229
230        if ((imm.m_value <= 255) && (imm.m_value >= 0) && (dest == SH4Registers::r0)) {
231            m_assembler.andlImm8r(imm.m_value, dest);
232            return;
233        }
234
235        RegisterID scr = claimScratch();
236        m_assembler.loadConstant(imm.m_value, scr);
237        m_assembler.andlRegReg(scr, dest);
238        releaseScratch(scr);
239    }
240
241    void and32(TrustedImm32 imm, RegisterID src, RegisterID dest)
242    {
243        if (src != dest) {
244            move(imm, dest);
245            and32(src, dest);
246            return;
247        }
248
249        and32(imm, dest);
250    }
251
252    void lshift32(RegisterID shiftamount, RegisterID dest)
253    {
254        RegisterID shiftTmp = claimScratch();
255        m_assembler.loadConstant(0x1f, shiftTmp);
256        m_assembler.andlRegReg(shiftamount, shiftTmp);
257        m_assembler.shldRegReg(dest, shiftTmp);
258        releaseScratch(shiftTmp);
259    }
260
261    void lshift32(RegisterID src, RegisterID shiftAmount, RegisterID dest)
262    {
263        move(src, dest);
264        lshift32(shiftAmount, dest);
265    }
266
267    void lshift32(TrustedImm32 imm, RegisterID dest)
268    {
269        int immMasked = imm.m_value & 0x1f;
270        if (!immMasked)
271            return;
272
273        if ((immMasked == 1) || (immMasked == 2) || (immMasked == 8) || (immMasked == 16)) {
274            m_assembler.shllImm8r(immMasked, dest);
275            return;
276        }
277
278        RegisterID shiftTmp = claimScratch();
279        m_assembler.loadConstant(immMasked, shiftTmp);
280        m_assembler.shldRegReg(dest, shiftTmp);
281        releaseScratch(shiftTmp);
282    }
283
284    void lshift32(RegisterID src, TrustedImm32 shiftamount, RegisterID dest)
285    {
286        move(src, dest);
287        lshift32(shiftamount, dest);
288    }
289
290    void mul32(RegisterID src, RegisterID dest)
291    {
292        mul32(src, dest, dest);
293    }
294
295    void mul32(RegisterID src1, RegisterID src2, RegisterID dest)
296    {
297        m_assembler.imullRegReg(src1, src2);
298        m_assembler.stsmacl(dest);
299    }
300
301    void mul32(TrustedImm32 imm, RegisterID src, RegisterID dest)
302    {
303        if (src == dest) {
304            RegisterID immval = claimScratch();
305            move(imm, immval);
306            mul32(immval, dest);
307            releaseScratch(immval);
308        } else {
309            move(imm, dest);
310            mul32(src, dest);
311        }
312    }
313
314    void or32(RegisterID src, RegisterID dest)
315    {
316        m_assembler.orlRegReg(src, dest);
317    }
318
319    void or32(TrustedImm32 imm, RegisterID dest)
320    {
321        if ((imm.m_value <= 255) && (imm.m_value >= 0) && (dest == SH4Registers::r0)) {
322            m_assembler.orlImm8r(imm.m_value, dest);
323            return;
324        }
325
326        RegisterID scr = claimScratch();
327        m_assembler.loadConstant(imm.m_value, scr);
328        m_assembler.orlRegReg(scr, dest);
329        releaseScratch(scr);
330    }
331
332    void or32(RegisterID op1, RegisterID op2, RegisterID dest)
333    {
334        if (op1 == op2)
335            move(op1, dest);
336        else if (op1 == dest)
337            or32(op2, dest);
338        else {
339            move(op2, dest);
340            or32(op1, dest);
341        }
342    }
343
344    void or32(TrustedImm32 imm, RegisterID src, RegisterID dest)
345    {
346        if (src != dest) {
347            move(imm, dest);
348            or32(src, dest);
349            return;
350        }
351
352        or32(imm, dest);
353    }
354
355    void or32(RegisterID src, AbsoluteAddress address)
356    {
357        RegisterID destptr = claimScratch();
358        move(TrustedImmPtr(address.m_ptr), destptr);
359        RegisterID destval = claimScratch();
360        m_assembler.movlMemReg(destptr, destval);
361        m_assembler.orlRegReg(src, destval);
362        m_assembler.movlRegMem(destval, destptr);
363        releaseScratch(destval);
364        releaseScratch(destptr);
365    }
366
367    void xor32(TrustedImm32 imm, RegisterID src, RegisterID dest)
368    {
369        if (src != dest) {
370            move(imm, dest);
371            xor32(src, dest);
372            return;
373        }
374
375        xor32(imm, dest);
376    }
377
378    void rshift32(RegisterID shiftamount, RegisterID dest)
379    {
380        RegisterID shiftTmp = claimScratch();
381        m_assembler.loadConstant(0x1f, shiftTmp);
382        m_assembler.andlRegReg(shiftamount, shiftTmp);
383        m_assembler.neg(shiftTmp, shiftTmp);
384        m_assembler.shadRegReg(dest, shiftTmp);
385        releaseScratch(shiftTmp);
386    }
387
388    void rshift32(RegisterID src, RegisterID shiftAmount, RegisterID dest)
389    {
390        move(src, dest);
391        rshift32(shiftAmount, dest);
392    }
393
394    void rshift32(TrustedImm32 imm, RegisterID dest)
395    {
396        int immMasked = imm.m_value & 0x1f;
397        if (!immMasked)
398            return;
399
400        if (immMasked == 1) {
401            m_assembler.sharImm8r(immMasked, dest);
402            return;
403        }
404
405        RegisterID shiftTmp = claimScratch();
406        m_assembler.loadConstant(-immMasked, shiftTmp);
407        m_assembler.shadRegReg(dest, shiftTmp);
408        releaseScratch(shiftTmp);
409    }
410
411    void rshift32(RegisterID src, TrustedImm32 imm, RegisterID dest)
412    {
413        move(src, dest);
414        rshift32(imm, dest);
415    }
416
417    void sub32(RegisterID src, RegisterID dest)
418    {
419        m_assembler.sublRegReg(src, dest);
420    }
421
422    void sub32(TrustedImm32 imm, AbsoluteAddress address)
423    {
424        if (!imm.m_value)
425            return;
426
427        RegisterID result = claimScratch();
428        RegisterID scratchReg = claimScratch();
429
430        move(TrustedImmPtr(address.m_ptr), scratchReg);
431        m_assembler.movlMemReg(scratchReg, result);
432
433        if (m_assembler.isImmediate(-imm.m_value))
434            m_assembler.addlImm8r(-imm.m_value, result);
435        else {
436            m_assembler.loadConstant(imm.m_value, scratchReg3);
437            m_assembler.sublRegReg(scratchReg3, result);
438        }
439
440        store32(result, scratchReg);
441        releaseScratch(result);
442        releaseScratch(scratchReg);
443    }
444
445    void sub32(TrustedImm32 imm, Address address)
446    {
447        add32(TrustedImm32(-imm.m_value), address);
448    }
449
450    void add32(TrustedImm32 imm, AbsoluteAddress address)
451    {
452        if (!imm.m_value)
453            return;
454
455        RegisterID result = claimScratch();
456        RegisterID scratchReg = claimScratch();
457
458        move(TrustedImmPtr(address.m_ptr), scratchReg);
459        m_assembler.movlMemReg(scratchReg, result);
460
461        if (m_assembler.isImmediate(imm.m_value))
462            m_assembler.addlImm8r(imm.m_value, result);
463        else {
464            m_assembler.loadConstant(imm.m_value, scratchReg3);
465            m_assembler.addlRegReg(scratchReg3, result);
466        }
467
468        store32(result, scratchReg);
469        releaseScratch(result);
470        releaseScratch(scratchReg);
471    }
472
473    void add64(TrustedImm32 imm, AbsoluteAddress address)
474    {
475        RegisterID scr1 = claimScratch();
476        RegisterID scr2 = claimScratch();
477
478        // Add 32-bit LSB first.
479        move(TrustedImmPtr(address.m_ptr), scratchReg3);
480        m_assembler.movlMemReg(scratchReg3, scr1); // scr1 = 32-bit LSB of int64 @ address
481        m_assembler.loadConstant(imm.m_value, scr2);
482        m_assembler.clrt();
483        m_assembler.addclRegReg(scr1, scr2);
484        m_assembler.movlRegMem(scr2, scratchReg3); // Update address with 32-bit LSB result.
485
486        // Then add 32-bit MSB.
487        m_assembler.addlImm8r(4, scratchReg3);
488        m_assembler.movlMemReg(scratchReg3, scr1); // scr1 = 32-bit MSB of int64 @ address
489        m_assembler.movt(scr2);
490        if (imm.m_value < 0)
491            m_assembler.addlImm8r(-1, scr2); // Sign extend imm value if needed.
492        m_assembler.addvlRegReg(scr2, scr1);
493        m_assembler.movlRegMem(scr1, scratchReg3); // Update (address + 4) with 32-bit MSB result.
494
495        releaseScratch(scr2);
496        releaseScratch(scr1);
497    }
498
499    void sub32(TrustedImm32 imm, RegisterID dest)
500    {
501        if (!imm.m_value)
502            return;
503
504        if (m_assembler.isImmediate(-imm.m_value)) {
505            m_assembler.addlImm8r(-imm.m_value, dest);
506            return;
507        }
508
509        RegisterID scr = claimScratch();
510        m_assembler.loadConstant(imm.m_value, scr);
511        m_assembler.sublRegReg(scr, dest);
512        releaseScratch(scr);
513    }
514
515    void sub32(Address src, RegisterID dest)
516    {
517        RegisterID scr = claimScratch();
518        load32(src, scr);
519        m_assembler.sublRegReg(scr, dest);
520        releaseScratch(scr);
521    }
522
523    void xor32(RegisterID src, RegisterID dest)
524    {
525        m_assembler.xorlRegReg(src, dest);
526    }
527
528    void xor32(RegisterID src1, RegisterID src2, RegisterID dest)
529    {
530        if (src1 == dest)
531            xor32(src2, dest);
532        else {
533            move(src2, dest);
534            xor32(src1, dest);
535        }
536    }
537
538    void xor32(TrustedImm32 imm, RegisterID srcDest)
539    {
540        if (imm.m_value == -1) {
541            m_assembler.notlReg(srcDest, srcDest);
542            return;
543        }
544
545        if ((srcDest != SH4Registers::r0) || (imm.m_value > 255) || (imm.m_value < 0)) {
546            RegisterID scr = claimScratch();
547            m_assembler.loadConstant(imm.m_value, scr);
548            m_assembler.xorlRegReg(scr, srcDest);
549            releaseScratch(scr);
550            return;
551        }
552
553        m_assembler.xorlImm8r(imm.m_value, srcDest);
554    }
555
556    void compare32(int imm, RegisterID dst, RelationalCondition cond)
557    {
558        if (((cond == Equal) || (cond == NotEqual)) && (dst == SH4Registers::r0) && m_assembler.isImmediate(imm)) {
559            m_assembler.cmpEqImmR0(imm, dst);
560            return;
561        }
562
563        if (((cond == Equal) || (cond == NotEqual)) && !imm) {
564            m_assembler.testlRegReg(dst, dst);
565            return;
566        }
567
568        RegisterID scr = claimScratch();
569        m_assembler.loadConstant(imm, scr);
570        m_assembler.cmplRegReg(scr, dst, SH4Condition(cond));
571        releaseScratch(scr);
572    }
573
574    void compare32(int offset, RegisterID base, RegisterID left, RelationalCondition cond)
575    {
576        RegisterID scr = claimScratch();
577        if (!offset) {
578            m_assembler.movlMemReg(base, scr);
579            m_assembler.cmplRegReg(scr, left, SH4Condition(cond));
580            releaseScratch(scr);
581            return;
582        }
583
584        if ((offset < 0) || (offset >= 64)) {
585            m_assembler.loadConstant(offset, scr);
586            m_assembler.addlRegReg(base, scr);
587            m_assembler.movlMemReg(scr, scr);
588            m_assembler.cmplRegReg(scr, left, SH4Condition(cond));
589            releaseScratch(scr);
590            return;
591        }
592
593        m_assembler.movlMemReg(offset >> 2, base, scr);
594        m_assembler.cmplRegReg(scr, left, SH4Condition(cond));
595        releaseScratch(scr);
596    }
597
598    void testImm(int imm, int offset, RegisterID base)
599    {
600        RegisterID scr = claimScratch();
601        load32(base, offset, scr);
602
603        RegisterID scr1 = claimScratch();
604        move(TrustedImm32(imm), scr1);
605
606        m_assembler.testlRegReg(scr, scr1);
607        releaseScratch(scr);
608        releaseScratch(scr1);
609    }
610
611    void testlImm(int imm, RegisterID dst)
612    {
613        if ((dst == SH4Registers::r0) && (imm <= 255) && (imm >= 0)) {
614            m_assembler.testlImm8r(imm, dst);
615            return;
616        }
617
618        RegisterID scr = claimScratch();
619        m_assembler.loadConstant(imm, scr);
620        m_assembler.testlRegReg(scr, dst);
621        releaseScratch(scr);
622    }
623
624    void compare32(RegisterID right, int offset, RegisterID base, RelationalCondition cond)
625    {
626        if (!offset) {
627            RegisterID scr = claimScratch();
628            m_assembler.movlMemReg(base, scr);
629            m_assembler.cmplRegReg(right, scr, SH4Condition(cond));
630            releaseScratch(scr);
631            return;
632        }
633
634        if ((offset < 0) || (offset >= 64)) {
635            RegisterID scr = claimScratch();
636            m_assembler.loadConstant(offset, scr);
637            m_assembler.addlRegReg(base, scr);
638            m_assembler.movlMemReg(scr, scr);
639            m_assembler.cmplRegReg(right, scr, SH4Condition(cond));
640            releaseScratch(scr);
641            return;
642        }
643
644        RegisterID scr = claimScratch();
645        m_assembler.movlMemReg(offset >> 2, base, scr);
646        m_assembler.cmplRegReg(right, scr, SH4Condition(cond));
647        releaseScratch(scr);
648    }
649
650    void compare32(int imm, int offset, RegisterID base, RelationalCondition cond)
651    {
652        RegisterID scr = claimScratch();
653        load32(base, offset, scr);
654
655        RegisterID scr1 = claimScratch();
656        move(TrustedImm32(imm), scr1);
657
658        m_assembler.cmplRegReg(scr1, scr, SH4Condition(cond));
659
660        releaseScratch(scr1);
661        releaseScratch(scr);
662    }
663
664    // Memory access operation
665
666    ALWAYS_INLINE void loadEffectiveAddress(BaseIndex address, RegisterID dest, int extraoffset = 0)
667    {
668        if (dest == address.base) {
669            RegisterID scaledIndex = claimScratch();
670            move(address.index, scaledIndex);
671            lshift32(TrustedImm32(address.scale), scaledIndex);
672            add32(scaledIndex, dest);
673            releaseScratch(scaledIndex);
674        } else {
675            move(address.index, dest);
676            lshift32(TrustedImm32(address.scale), dest);
677            add32(address.base, dest);
678        }
679
680        add32(TrustedImm32(address.offset + extraoffset), dest);
681    }
682
683    void load32(ImplicitAddress address, RegisterID dest)
684    {
685        load32(address.base, address.offset, dest);
686    }
687
688    void load8(ImplicitAddress address, RegisterID dest)
689    {
690        load8(address.base, address.offset, dest);
691    }
692
693    void load8(BaseIndex address, RegisterID dest)
694    {
695        RegisterID scr = claimScratch();
696        move(address.index, scr);
697        lshift32(TrustedImm32(address.scale), scr);
698        add32(address.base, scr);
699        load8(scr, address.offset, dest);
700        releaseScratch(scr);
701    }
702
703    void load8(AbsoluteAddress address, RegisterID dest)
704    {
705        move(TrustedImmPtr(address.m_ptr), dest);
706        m_assembler.movbMemReg(dest, dest);
707        m_assembler.extub(dest, dest);
708    }
709
710    void load8(const void* address, RegisterID dest)
711    {
712        load8(AbsoluteAddress(address), dest);
713    }
714
715    void load8PostInc(RegisterID base, RegisterID dest)
716    {
717        m_assembler.movbMemRegIn(base, dest);
718        m_assembler.extub(dest, dest);
719    }
720
721    void load8Signed(BaseIndex address, RegisterID dest)
722    {
723        RegisterID scr = claimScratch();
724        move(address.index, scr);
725        lshift32(TrustedImm32(address.scale), scr);
726        add32(address.base, scr);
727        load8Signed(scr, address.offset, dest);
728        releaseScratch(scr);
729    }
730
731    void load32(BaseIndex address, RegisterID dest)
732    {
733        RegisterID scr = claimScratch();
734        move(address.index, scr);
735        lshift32(TrustedImm32(address.scale), scr);
736        add32(address.base, scr);
737        load32(scr, address.offset, dest);
738        releaseScratch(scr);
739    }
740
741    void load32(const void* address, RegisterID dest)
742    {
743        move(TrustedImmPtr(address), dest);
744        m_assembler.movlMemReg(dest, dest);
745    }
746
747    void load32(RegisterID base, int offset, RegisterID dest)
748    {
749        if (!offset) {
750            m_assembler.movlMemReg(base, dest);
751            return;
752        }
753
754        if ((offset >= 0) && (offset < 64)) {
755            m_assembler.movlMemReg(offset >> 2, base, dest);
756            return;
757        }
758
759        RegisterID scr = (dest == base) ? claimScratch() : dest;
760
761        m_assembler.loadConstant(offset, scr);
762        if (base == SH4Registers::r0)
763            m_assembler.movlR0mr(scr, dest);
764        else {
765            m_assembler.addlRegReg(base, scr);
766            m_assembler.movlMemReg(scr, dest);
767        }
768
769        if (dest == base)
770            releaseScratch(scr);
771    }
772
773    void load8Signed(RegisterID base, int offset, RegisterID dest)
774    {
775        if (!offset) {
776            m_assembler.movbMemReg(base, dest);
777            return;
778        }
779
780        if ((offset > 0) && (offset <= 15) && (dest == SH4Registers::r0)) {
781            m_assembler.movbMemReg(offset, base, dest);
782            return;
783        }
784
785        RegisterID scr = (dest == base) ? claimScratch() : dest;
786
787        m_assembler.loadConstant(offset, scr);
788        if (base == SH4Registers::r0)
789            m_assembler.movbR0mr(scr, dest);
790        else {
791            m_assembler.addlRegReg(base, scr);
792            m_assembler.movbMemReg(scr, dest);
793        }
794
795        if (dest == base)
796            releaseScratch(scr);
797    }
798
799    void load8(RegisterID base, int offset, RegisterID dest)
800    {
801        load8Signed(base, offset, dest);
802        m_assembler.extub(dest, dest);
803    }
804
805    void load32(RegisterID src, RegisterID dst)
806    {
807        m_assembler.movlMemReg(src, dst);
808    }
809
810    void load16(ImplicitAddress address, RegisterID dest)
811    {
812        if (!address.offset) {
813            m_assembler.movwMemReg(address.base, dest);
814            m_assembler.extuw(dest, dest);
815            return;
816        }
817
818        if ((address.offset > 0) && (address.offset <= 30) && (dest == SH4Registers::r0)) {
819            m_assembler.movwMemReg(address.offset >> 1, address.base, dest);
820            m_assembler.extuw(dest, dest);
821            return;
822        }
823
824        RegisterID scr = (dest == address.base) ? claimScratch() : dest;
825
826        m_assembler.loadConstant(address.offset, scr);
827        if (address.base == SH4Registers::r0)
828            m_assembler.movwR0mr(scr, dest);
829        else {
830            m_assembler.addlRegReg(address.base, scr);
831            m_assembler.movwMemReg(scr, dest);
832        }
833        m_assembler.extuw(dest, dest);
834
835        if (dest == address.base)
836            releaseScratch(scr);
837    }
838
839    void load16Unaligned(BaseIndex address, RegisterID dest)
840    {
841        RegisterID scr = claimScratch();
842
843        loadEffectiveAddress(address, scr);
844
845        RegisterID scr1 = claimScratch();
846        load8PostInc(scr, scr1);
847        load8(scr, dest);
848        m_assembler.shllImm8r(8, dest);
849        or32(scr1, dest);
850
851        releaseScratch(scr);
852        releaseScratch(scr1);
853    }
854
855    void load16(RegisterID src, RegisterID dest)
856    {
857        m_assembler.movwMemReg(src, dest);
858        m_assembler.extuw(dest, dest);
859    }
860
861    void load16Signed(RegisterID src, RegisterID dest)
862    {
863        m_assembler.movwMemReg(src, dest);
864    }
865
866    void load16(BaseIndex address, RegisterID dest)
867    {
868        load16Signed(address, dest);
869        m_assembler.extuw(dest, dest);
870    }
871
872    void load16PostInc(RegisterID base, RegisterID dest)
873    {
874        m_assembler.movwMemRegIn(base, dest);
875        m_assembler.extuw(dest, dest);
876    }
877
878    void load16Signed(BaseIndex address, RegisterID dest)
879    {
880        RegisterID scr = claimScratch();
881
882        move(address.index, scr);
883        lshift32(TrustedImm32(address.scale), scr);
884        add32(TrustedImm32(address.offset), scr);
885
886        if (address.base == SH4Registers::r0)
887            m_assembler.movwR0mr(scr, dest);
888        else {
889            add32(address.base, scr);
890            load16Signed(scr, dest);
891        }
892
893        releaseScratch(scr);
894    }
895
896    void store8(RegisterID src, BaseIndex address)
897    {
898        RegisterID scr = claimScratch();
899
900        move(address.index, scr);
901        lshift32(TrustedImm32(address.scale), scr);
902        add32(TrustedImm32(address.offset), scr);
903
904        if (address.base == SH4Registers::r0)
905            m_assembler.movbRegMemr0(src, scr);
906        else {
907            add32(address.base, scr);
908            m_assembler.movbRegMem(src, scr);
909        }
910
911        releaseScratch(scr);
912    }
913
914    void store8(RegisterID src, void* address)
915    {
916        RegisterID destptr = claimScratch();
917        move(TrustedImmPtr(address), destptr);
918        m_assembler.movbRegMem(src, destptr);
919        releaseScratch(destptr);
920    }
921
922    void store8(TrustedImm32 imm, void* address)
923    {
924        ASSERT((imm.m_value >= -128) && (imm.m_value <= 127));
925        RegisterID dstptr = claimScratch();
926        move(TrustedImmPtr(address), dstptr);
927        RegisterID srcval = claimScratch();
928        move(imm, srcval);
929        m_assembler.movbRegMem(srcval, dstptr);
930        releaseScratch(dstptr);
931        releaseScratch(srcval);
932    }
933
934    void store16(RegisterID src, BaseIndex address)
935    {
936        RegisterID scr = claimScratch();
937
938        move(address.index, scr);
939        lshift32(TrustedImm32(address.scale), scr);
940        add32(TrustedImm32(address.offset), scr);
941
942        if (address.base == SH4Registers::r0)
943            m_assembler.movwRegMemr0(src, scr);
944        else {
945            add32(address.base, scr);
946            m_assembler.movwRegMem(src, scr);
947        }
948
949        releaseScratch(scr);
950    }
951
952    void store32(RegisterID src, ImplicitAddress address)
953    {
954        if (!address.offset) {
955            m_assembler.movlRegMem(src, address.base);
956            return;
957        }
958
959        if ((address.offset >= 0) && (address.offset < 64)) {
960            m_assembler.movlRegMem(src, address.offset >> 2, address.base);
961            return;
962        }
963
964        RegisterID scr = claimScratch();
965        m_assembler.loadConstant(address.offset, scr);
966        if (address.base == SH4Registers::r0)
967            m_assembler.movlRegMemr0(src, scr);
968        else {
969            m_assembler.addlRegReg(address.base, scr);
970            m_assembler.movlRegMem(src, scr);
971        }
972        releaseScratch(scr);
973    }
974
975    void store32(RegisterID src, RegisterID dst)
976    {
977        m_assembler.movlRegMem(src, dst);
978    }
979
980    void store32(TrustedImm32 imm, ImplicitAddress address)
981    {
982        RegisterID scr = claimScratch();
983        m_assembler.loadConstant(imm.m_value, scr);
984        store32(scr, address);
985        releaseScratch(scr);
986    }
987
988    void store32(RegisterID src, BaseIndex address)
989    {
990        RegisterID scr = claimScratch();
991
992        move(address.index, scr);
993        lshift32(TrustedImm32(address.scale), scr);
994        add32(address.base, scr);
995        store32(src, Address(scr, address.offset));
996
997        releaseScratch(scr);
998    }
999
1000    void store32(TrustedImm32 imm, void* address)
1001    {
1002        RegisterID scr = claimScratch();
1003        RegisterID scr1 = claimScratch();
1004        m_assembler.loadConstant(imm.m_value, scr);
1005        move(TrustedImmPtr(address), scr1);
1006        m_assembler.movlRegMem(scr, scr1);
1007        releaseScratch(scr);
1008        releaseScratch(scr1);
1009    }
1010
1011    void store32(RegisterID src, void* address)
1012    {
1013        RegisterID scr = claimScratch();
1014        move(TrustedImmPtr(address), scr);
1015        m_assembler.movlRegMem(src, scr);
1016        releaseScratch(scr);
1017    }
1018
1019    void store32(TrustedImm32 imm, BaseIndex address)
1020    {
1021        RegisterID destptr = claimScratch();
1022
1023        loadEffectiveAddress(address, destptr);
1024
1025        RegisterID srcval = claimScratch();
1026        move(imm, srcval);
1027        m_assembler.movlRegMem(srcval, destptr);
1028        releaseScratch(srcval);
1029        releaseScratch(destptr);
1030    }
1031
1032    DataLabel32 load32WithAddressOffsetPatch(Address address, RegisterID dest)
1033    {
1034        RegisterID scr = claimScratch();
1035        DataLabel32 label(this);
1036        m_assembler.loadConstantUnReusable(address.offset, scr);
1037        m_assembler.addlRegReg(address.base, scr);
1038        m_assembler.movlMemReg(scr, dest);
1039        releaseScratch(scr);
1040        return label;
1041    }
1042
1043    DataLabel32 store32WithAddressOffsetPatch(RegisterID src, Address address)
1044    {
1045        RegisterID scr = claimScratch();
1046        DataLabel32 label(this);
1047        m_assembler.loadConstantUnReusable(address.offset, scr);
1048        m_assembler.addlRegReg(address.base, scr);
1049        m_assembler.movlRegMem(src, scr);
1050        releaseScratch(scr);
1051        return label;
1052    }
1053
1054    DataLabelCompact load32WithCompactAddressOffsetPatch(Address address, RegisterID dest)
1055    {
1056        DataLabelCompact dataLabel(this);
1057        ASSERT(isCompactPtrAlignedAddressOffset(address.offset));
1058        m_assembler.movlMemRegCompact(address.offset >> 2, address.base, dest);
1059        return dataLabel;
1060    }
1061
1062    ConvertibleLoadLabel convertibleLoadPtr(Address address, RegisterID dest)
1063    {
1064        ConvertibleLoadLabel result(this);
1065
1066        RegisterID scr = claimScratch();
1067        m_assembler.movImm8(address.offset, scr);
1068        m_assembler.addlRegReg(address.base, scr);
1069        m_assembler.movlMemReg(scr, dest);
1070        releaseScratch(scr);
1071
1072        return result;
1073    }
1074
1075    // Floating-point operations
1076
1077    static bool supportsFloatingPoint() { return true; }
1078    static bool supportsFloatingPointTruncate() { return true; }
1079    static bool supportsFloatingPointSqrt() { return true; }
1080    static bool supportsFloatingPointAbs() { return true; }
1081
1082    void moveDoubleToInts(FPRegisterID src, RegisterID dest1, RegisterID dest2)
1083    {
1084        m_assembler.fldsfpul((FPRegisterID)(src + 1));
1085        m_assembler.stsfpulReg(dest1);
1086        m_assembler.fldsfpul(src);
1087        m_assembler.stsfpulReg(dest2);
1088    }
1089
1090    void moveIntsToDouble(RegisterID src1, RegisterID src2, FPRegisterID dest, FPRegisterID)
1091    {
1092        m_assembler.ldsrmfpul(src1);
1093        m_assembler.fstsfpul((FPRegisterID)(dest + 1));
1094        m_assembler.ldsrmfpul(src2);
1095        m_assembler.fstsfpul(dest);
1096    }
1097
1098    void moveDouble(FPRegisterID src, FPRegisterID dest)
1099    {
1100        if (src != dest) {
1101            m_assembler.fmovsRegReg((FPRegisterID)(src + 1), (FPRegisterID)(dest + 1));
1102            m_assembler.fmovsRegReg(src, dest);
1103        }
1104    }
1105
1106    void swapDouble(FPRegisterID fr1, FPRegisterID fr2)
1107    {
1108        if (fr1 != fr2) {
1109            m_assembler.fldsfpul((FPRegisterID)(fr1 + 1));
1110            m_assembler.fmovsRegReg((FPRegisterID)(fr2 + 1), (FPRegisterID)(fr1 + 1));
1111            m_assembler.fstsfpul((FPRegisterID)(fr2 + 1));
1112            m_assembler.fldsfpul(fr1);
1113            m_assembler.fmovsRegReg(fr2, fr1);
1114            m_assembler.fstsfpul(fr2);
1115        }
1116    }
1117
1118    void loadFloat(BaseIndex address, FPRegisterID dest)
1119    {
1120        RegisterID scr = claimScratch();
1121
1122        loadEffectiveAddress(address, scr);
1123
1124        m_assembler.fmovsReadrm(scr, dest);
1125        releaseScratch(scr);
1126    }
1127
1128    void loadDouble(BaseIndex address, FPRegisterID dest)
1129    {
1130        RegisterID scr = claimScratch();
1131
1132        loadEffectiveAddress(address, scr);
1133
1134        m_assembler.fmovsReadrminc(scr, (FPRegisterID)(dest + 1));
1135        m_assembler.fmovsReadrm(scr, dest);
1136        releaseScratch(scr);
1137    }
1138
1139    void loadDouble(ImplicitAddress address, FPRegisterID dest)
1140    {
1141        RegisterID scr = claimScratch();
1142
1143        m_assembler.loadConstant(address.offset, scr);
1144        if (address.base == SH4Registers::r0) {
1145            m_assembler.fmovsReadr0r(scr, (FPRegisterID)(dest + 1));
1146            m_assembler.addlImm8r(4, scr);
1147            m_assembler.fmovsReadr0r(scr, dest);
1148            releaseScratch(scr);
1149            return;
1150        }
1151
1152        m_assembler.addlRegReg(address.base, scr);
1153        m_assembler.fmovsReadrminc(scr, (FPRegisterID)(dest + 1));
1154        m_assembler.fmovsReadrm(scr, dest);
1155        releaseScratch(scr);
1156    }
1157
1158    void loadDouble(TrustedImmPtr address, FPRegisterID dest)
1159    {
1160        RegisterID scr = claimScratch();
1161        move(address, scr);
1162        m_assembler.fmovsReadrminc(scr, (FPRegisterID)(dest + 1));
1163        m_assembler.fmovsReadrm(scr, dest);
1164        releaseScratch(scr);
1165    }
1166
1167    void storeFloat(FPRegisterID src, BaseIndex address)
1168    {
1169        RegisterID scr = claimScratch();
1170        loadEffectiveAddress(address, scr);
1171        m_assembler.fmovsWriterm(src, scr);
1172        releaseScratch(scr);
1173    }
1174
1175    void storeDouble(FPRegisterID src, ImplicitAddress address)
1176    {
1177        RegisterID scr = claimScratch();
1178        m_assembler.loadConstant(address.offset + 8, scr);
1179        m_assembler.addlRegReg(address.base, scr);
1180        m_assembler.fmovsWriterndec(src, scr);
1181        m_assembler.fmovsWriterndec((FPRegisterID)(src + 1), scr);
1182        releaseScratch(scr);
1183    }
1184
1185    void storeDouble(FPRegisterID src, BaseIndex address)
1186    {
1187        RegisterID scr = claimScratch();
1188
1189        loadEffectiveAddress(address, scr, 8);
1190
1191        m_assembler.fmovsWriterndec(src, scr);
1192        m_assembler.fmovsWriterndec((FPRegisterID)(src + 1), scr);
1193
1194        releaseScratch(scr);
1195    }
1196
1197    void addDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
1198    {
1199        if (op1 == dest)
1200            addDouble(op2, dest);
1201        else {
1202            moveDouble(op2, dest);
1203            addDouble(op1, dest);
1204        }
1205    }
1206
1207    void storeDouble(FPRegisterID src, TrustedImmPtr address)
1208    {
1209        RegisterID scr = claimScratch();
1210        m_assembler.loadConstant(reinterpret_cast<uint32_t>(const_cast<void*>(address.m_value)) + 8, scr);
1211        m_assembler.fmovsWriterndec(src, scr);
1212        m_assembler.fmovsWriterndec((FPRegisterID)(src + 1), scr);
1213        releaseScratch(scr);
1214    }
1215
1216    void addDouble(FPRegisterID src, FPRegisterID dest)
1217    {
1218        m_assembler.daddRegReg(src, dest);
1219    }
1220
1221    void addDouble(AbsoluteAddress address, FPRegisterID dest)
1222    {
1223        loadDouble(TrustedImmPtr(address.m_ptr), fscratch);
1224        addDouble(fscratch, dest);
1225    }
1226
1227    void addDouble(Address address, FPRegisterID dest)
1228    {
1229        loadDouble(address, fscratch);
1230        addDouble(fscratch, dest);
1231    }
1232
1233    void subDouble(FPRegisterID src, FPRegisterID dest)
1234    {
1235        m_assembler.dsubRegReg(src, dest);
1236    }
1237
1238    void subDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
1239    {
1240        if (op2 == dest) {
1241            moveDouble(op1, fscratch);
1242            subDouble(op2, fscratch);
1243            moveDouble(fscratch, dest);
1244        } else {
1245            moveDouble(op1, dest);
1246            subDouble(op2, dest);
1247        }
1248    }
1249
1250    void subDouble(Address address, FPRegisterID dest)
1251    {
1252        loadDouble(address, fscratch);
1253        subDouble(fscratch, dest);
1254    }
1255
1256    void mulDouble(FPRegisterID src, FPRegisterID dest)
1257    {
1258        m_assembler.dmulRegReg(src, dest);
1259    }
1260
1261    void mulDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
1262    {
1263        if (op1 == dest)
1264            mulDouble(op2, dest);
1265        else {
1266            moveDouble(op2, dest);
1267            mulDouble(op1, dest);
1268        }
1269    }
1270
1271    void mulDouble(Address address, FPRegisterID dest)
1272    {
1273        loadDouble(address, fscratch);
1274        mulDouble(fscratch, dest);
1275    }
1276
1277    void divDouble(FPRegisterID src, FPRegisterID dest)
1278    {
1279        m_assembler.ddivRegReg(src, dest);
1280    }
1281
1282    void divDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
1283    {
1284        if (op2 == dest) {
1285            moveDouble(op1, fscratch);
1286            divDouble(op2, fscratch);
1287            moveDouble(fscratch, dest);
1288        } else {
1289            moveDouble(op1, dest);
1290            divDouble(op2, dest);
1291        }
1292    }
1293
1294    void negateDouble(FPRegisterID src, FPRegisterID dest)
1295    {
1296        moveDouble(src, dest);
1297        m_assembler.dneg(dest);
1298    }
1299
1300    void convertFloatToDouble(FPRegisterID src, FPRegisterID dst)
1301    {
1302        m_assembler.fldsfpul(src);
1303        m_assembler.dcnvsd(dst);
1304    }
1305
1306    void convertDoubleToFloat(FPRegisterID src, FPRegisterID dst)
1307    {
1308        m_assembler.dcnvds(src);
1309        m_assembler.fstsfpul(dst);
1310    }
1311
1312    void convertInt32ToDouble(RegisterID src, FPRegisterID dest)
1313    {
1314        m_assembler.ldsrmfpul(src);
1315        m_assembler.floatfpulDreg(dest);
1316    }
1317
1318    void convertInt32ToDouble(AbsoluteAddress src, FPRegisterID dest)
1319    {
1320        RegisterID scr = claimScratch();
1321        load32(src.m_ptr, scr);
1322        convertInt32ToDouble(scr, dest);
1323        releaseScratch(scr);
1324    }
1325
1326    void convertInt32ToDouble(Address src, FPRegisterID dest)
1327    {
1328        RegisterID scr = claimScratch();
1329        load32(src, scr);
1330        convertInt32ToDouble(scr, dest);
1331        releaseScratch(scr);
1332    }
1333
1334    void load32WithUnalignedHalfWords(BaseIndex address, RegisterID dest)
1335    {
1336        RegisterID scr = claimScratch();
1337        Jump m_jump;
1338        JumpList end;
1339
1340        loadEffectiveAddress(address, scr);
1341
1342        RegisterID scr1 = claimScratch();
1343        if (dest != SH4Registers::r0)
1344            move(SH4Registers::r0, scr1);
1345
1346        m_assembler.ensureSpace(m_assembler.maxInstructionSize + 58, sizeof(uint32_t));
1347        move(scr, SH4Registers::r0);
1348        m_assembler.testlImm8r(0x3, SH4Registers::r0);
1349        m_jump = Jump(m_assembler.jne(), SH4Assembler::JumpNear);
1350
1351        if (dest != SH4Registers::r0)
1352            move(scr1, SH4Registers::r0);
1353
1354        load32(scr, dest);
1355        end.append(Jump(m_assembler.bra(), SH4Assembler::JumpNear));
1356        m_assembler.nop();
1357        m_jump.link(this);
1358        m_assembler.testlImm8r(0x1, SH4Registers::r0);
1359
1360        if (dest != SH4Registers::r0)
1361            move(scr1, SH4Registers::r0);
1362
1363        m_jump = Jump(m_assembler.jne(), SH4Assembler::JumpNear);
1364        load16PostInc(scr, scr1);
1365        load16(scr, dest);
1366        m_assembler.shllImm8r(16, dest);
1367        or32(scr1, dest);
1368        end.append(Jump(m_assembler.bra(), SH4Assembler::JumpNear));
1369        m_assembler.nop();
1370        m_jump.link(this);
1371        load8PostInc(scr, scr1);
1372        load16PostInc(scr, dest);
1373        m_assembler.shllImm8r(8, dest);
1374        or32(dest, scr1);
1375        load8(scr, dest);
1376        m_assembler.shllImm8r(8, dest);
1377        m_assembler.shllImm8r(16, dest);
1378        or32(scr1, dest);
1379        end.link(this);
1380
1381        releaseScratch(scr);
1382        releaseScratch(scr1);
1383    }
1384
1385    Jump branch32WithUnalignedHalfWords(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
1386    {
1387        RegisterID scr = scratchReg3;
1388        load32WithUnalignedHalfWords(left, scr);
1389        if (((cond == Equal) || (cond == NotEqual)) && !right.m_value)
1390            m_assembler.testlRegReg(scr, scr);
1391        else
1392            compare32(right.m_value, scr, cond);
1393
1394        if (cond == NotEqual)
1395            return branchFalse();
1396        return branchTrue();
1397    }
1398
1399    Jump branchDoubleNonZero(FPRegisterID reg, FPRegisterID scratch)
1400    {
1401        m_assembler.movImm8(0, scratchReg3);
1402        convertInt32ToDouble(scratchReg3, scratch);
1403        return branchDouble(DoubleNotEqual, reg, scratch);
1404    }
1405
1406    Jump branchDoubleZeroOrNaN(FPRegisterID reg, FPRegisterID scratch)
1407    {
1408        m_assembler.movImm8(0, scratchReg3);
1409        convertInt32ToDouble(scratchReg3, scratch);
1410        return branchDouble(DoubleEqualOrUnordered, reg, scratch);
1411    }
1412
1413    Jump branchDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right)
1414    {
1415        if (cond == DoubleEqual) {
1416            m_assembler.dcmppeq(right, left);
1417            return branchTrue();
1418        }
1419
1420        if (cond == DoubleNotEqual) {
1421            JumpList end;
1422            m_assembler.dcmppeq(left, left);
1423            m_assembler.ensureSpace(m_assembler.maxInstructionSize + 22, sizeof(uint32_t));
1424            end.append(Jump(m_assembler.jne(), SH4Assembler::JumpNear));
1425            m_assembler.dcmppeq(right, right);
1426            end.append(Jump(m_assembler.jne(), SH4Assembler::JumpNear));
1427            m_assembler.dcmppeq(right, left);
1428            Jump m_jump = branchFalse();
1429            end.link(this);
1430            return m_jump;
1431        }
1432
1433        if (cond == DoubleGreaterThan) {
1434            m_assembler.dcmppgt(right, left);
1435            return branchTrue();
1436        }
1437
1438        if (cond == DoubleGreaterThanOrEqual) {
1439            JumpList end;
1440            m_assembler.dcmppeq(left, left);
1441            m_assembler.ensureSpace(m_assembler.maxInstructionSize + 22, sizeof(uint32_t));
1442            end.append(Jump(m_assembler.jne(), SH4Assembler::JumpNear));
1443            m_assembler.dcmppeq(right, right);
1444            end.append(Jump(m_assembler.jne(), SH4Assembler::JumpNear));
1445            m_assembler.dcmppgt(left, right);
1446            Jump m_jump = branchFalse();
1447            end.link(this);
1448            return m_jump;
1449        }
1450
1451        if (cond == DoubleLessThan) {
1452            m_assembler.dcmppgt(left, right);
1453            return branchTrue();
1454        }
1455
1456        if (cond == DoubleLessThanOrEqual) {
1457            JumpList end;
1458            m_assembler.dcmppeq(left, left);
1459            m_assembler.ensureSpace(m_assembler.maxInstructionSize + 22, sizeof(uint32_t));
1460            end.append(Jump(m_assembler.jne(), SH4Assembler::JumpNear));
1461            m_assembler.dcmppeq(right, right);
1462            end.append(Jump(m_assembler.jne(), SH4Assembler::JumpNear));
1463            m_assembler.dcmppgt(right, left);
1464            Jump m_jump = branchFalse();
1465            end.link(this);
1466            return m_jump;
1467        }
1468
1469        if (cond == DoubleEqualOrUnordered) {
1470            JumpList takeBranch;
1471            m_assembler.dcmppeq(left, left);
1472            m_assembler.ensureSpace(m_assembler.maxInstructionSize + 22, sizeof(uint32_t));
1473            takeBranch.append(Jump(m_assembler.jne(), SH4Assembler::JumpNear));
1474            m_assembler.dcmppeq(right, right);
1475            takeBranch.append(Jump(m_assembler.jne(), SH4Assembler::JumpNear));
1476            m_assembler.dcmppeq(left, right);
1477            m_assembler.branch(BF_OPCODE, 2);
1478            takeBranch.link(this);
1479            return Jump(m_assembler.extraInstrForBranch(scratchReg3));
1480        }
1481
1482        if (cond == DoubleGreaterThanOrUnordered) {
1483            JumpList takeBranch;
1484            m_assembler.dcmppeq(left, left);
1485            m_assembler.ensureSpace(m_assembler.maxInstructionSize + 22, sizeof(uint32_t));
1486            takeBranch.append(Jump(m_assembler.jne(), SH4Assembler::JumpNear));
1487            m_assembler.dcmppeq(right, right);
1488            takeBranch.append(Jump(m_assembler.jne(), SH4Assembler::JumpNear));
1489            m_assembler.dcmppgt(right, left);
1490            m_assembler.branch(BF_OPCODE, 2);
1491            takeBranch.link(this);
1492            return Jump(m_assembler.extraInstrForBranch(scratchReg3));
1493        }
1494
1495        if (cond == DoubleGreaterThanOrEqualOrUnordered) {
1496            m_assembler.dcmppgt(left, right);
1497            return branchFalse();
1498        }
1499
1500        if (cond == DoubleLessThanOrUnordered) {
1501            JumpList takeBranch;
1502            m_assembler.dcmppeq(left, left);
1503            m_assembler.ensureSpace(m_assembler.maxInstructionSize + 22, sizeof(uint32_t));
1504            takeBranch.append(Jump(m_assembler.jne(), SH4Assembler::JumpNear));
1505            m_assembler.dcmppeq(right, right);
1506            takeBranch.append(Jump(m_assembler.jne(), SH4Assembler::JumpNear));
1507            m_assembler.dcmppgt(left, right);
1508            m_assembler.branch(BF_OPCODE, 2);
1509            takeBranch.link(this);
1510            return Jump(m_assembler.extraInstrForBranch(scratchReg3));
1511        }
1512
1513        if (cond == DoubleLessThanOrEqualOrUnordered) {
1514            m_assembler.dcmppgt(right, left);
1515            return branchFalse();
1516        }
1517
1518        ASSERT(cond == DoubleNotEqualOrUnordered);
1519        m_assembler.dcmppeq(right, left);
1520        return branchFalse();
1521    }
1522
1523    Jump branchTrue()
1524    {
1525        m_assembler.ensureSpace(m_assembler.maxInstructionSize + 6, sizeof(uint32_t));
1526        m_assembler.branch(BF_OPCODE, 2);
1527        return Jump(m_assembler.extraInstrForBranch(scratchReg3));
1528    }
1529
1530    Jump branchFalse()
1531    {
1532        m_assembler.ensureSpace(m_assembler.maxInstructionSize + 6, sizeof(uint32_t));
1533        m_assembler.branch(BT_OPCODE, 2);
1534        return Jump(m_assembler.extraInstrForBranch(scratchReg3));
1535    }
1536
1537    Jump branch32(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
1538    {
1539        RegisterID scr = claimScratch();
1540        move(left.index, scr);
1541        lshift32(TrustedImm32(left.scale), scr);
1542        add32(left.base, scr);
1543        load32(scr, left.offset, scr);
1544        compare32(right.m_value, scr, cond);
1545        releaseScratch(scr);
1546
1547        if (cond == NotEqual)
1548            return branchFalse();
1549        return branchTrue();
1550    }
1551
1552    void sqrtDouble(FPRegisterID src, FPRegisterID dest)
1553    {
1554        moveDouble(src, dest);
1555        m_assembler.dsqrt(dest);
1556    }
1557
1558    void absDouble(FPRegisterID src, FPRegisterID dest)
1559    {
1560        moveDouble(src, dest);
1561        m_assembler.dabs(dest);
1562    }
1563
1564    Jump branchTest8(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
1565    {
1566        RegisterID addressTempRegister = claimScratch();
1567        load8(address, addressTempRegister);
1568        Jump jmp = branchTest32(cond, addressTempRegister, mask);
1569        releaseScratch(addressTempRegister);
1570        return jmp;
1571    }
1572
1573    Jump branchTest8(ResultCondition cond, BaseIndex address, TrustedImm32 mask = TrustedImm32(-1))
1574    {
1575        RegisterID addressTempRegister = claimScratch();
1576        load8(address, addressTempRegister);
1577        Jump jmp = branchTest32(cond, addressTempRegister, mask);
1578        releaseScratch(addressTempRegister);
1579        return jmp;
1580    }
1581
1582    Jump branchTest8(ResultCondition cond, AbsoluteAddress address, TrustedImm32 mask = TrustedImm32(-1))
1583    {
1584        RegisterID addressTempRegister = claimScratch();
1585        move(TrustedImmPtr(address.m_ptr), addressTempRegister);
1586        load8(Address(addressTempRegister), addressTempRegister);
1587        Jump jmp = branchTest32(cond, addressTempRegister, mask);
1588        releaseScratch(addressTempRegister);
1589        return jmp;
1590    }
1591
1592    void signExtend32ToPtr(RegisterID src, RegisterID dest)
1593    {
1594        move(src, dest);
1595    }
1596
1597    void zeroExtend32ToPtr(RegisterID src, RegisterID dest)
1598    {
1599        move(src, dest);
1600    }
1601
1602    Jump branch8(RelationalCondition cond, Address left, TrustedImm32 right)
1603    {
1604        RegisterID addressTempRegister = claimScratch();
1605        load8(left, addressTempRegister);
1606        Jump jmp = branch32(cond, addressTempRegister, right);
1607        releaseScratch(addressTempRegister);
1608        return jmp;
1609    }
1610
1611    Jump branch8(RelationalCondition cond, AbsoluteAddress left, TrustedImm32 right)
1612    {
1613        RegisterID addressTempRegister = claimScratch();
1614        load8(left, addressTempRegister);
1615        Jump jmp = branch32(cond, addressTempRegister, right);
1616        releaseScratch(addressTempRegister);
1617        return jmp;
1618    }
1619
1620    void compare8(RelationalCondition cond, Address left, TrustedImm32 right, RegisterID dest)
1621    {
1622        RegisterID addressTempRegister = claimScratch();
1623        load8(left, addressTempRegister);
1624        compare32(cond, addressTempRegister, right, dest);
1625        releaseScratch(addressTempRegister);
1626    }
1627
1628    enum BranchTruncateType { BranchIfTruncateFailed, BranchIfTruncateSuccessful };
1629    Jump branchTruncateDoubleToInt32(FPRegisterID src, RegisterID dest, BranchTruncateType branchType = BranchIfTruncateFailed)
1630    {
1631        Jump result;
1632        truncateDoubleToInt32(src, dest);
1633        RegisterID intscr = claimScratch();
1634        m_assembler.loadConstant(0x7fffffff, intscr);
1635        m_assembler.cmplRegReg(dest, intscr, SH4Condition(Equal));
1636        m_assembler.ensureSpace(m_assembler.maxInstructionSize + 12, sizeof(uint32_t));
1637        if (branchType == BranchIfTruncateFailed) {
1638            m_assembler.branch(BT_OPCODE, 2);
1639            m_assembler.addlImm8r(1, intscr);
1640            m_assembler.cmplRegReg(dest, intscr, SH4Condition(Equal));
1641            result = branchTrue();
1642        } else {
1643            Jump out = Jump(m_assembler.je(), SH4Assembler::JumpNear);
1644            m_assembler.addlImm8r(1, intscr);
1645            m_assembler.cmplRegReg(dest, intscr, SH4Condition(Equal));
1646            result = branchFalse();
1647            out.link(this);
1648        }
1649        releaseScratch(intscr);
1650        return result;
1651    }
1652
1653    Jump branchTruncateDoubleToUint32(FPRegisterID src, RegisterID dest, BranchTruncateType branchType = BranchIfTruncateFailed)
1654    {
1655        Jump result;
1656        RegisterID intscr = claimScratch();
1657        m_assembler.loadConstant(0x80000000, intscr);
1658        convertInt32ToDouble(intscr, fscratch);
1659        addDouble(src, fscratch);
1660        truncateDoubleToInt32(fscratch, dest);
1661        m_assembler.cmplRegReg(dest, intscr, SH4Condition(Equal));
1662        m_assembler.ensureSpace(m_assembler.maxInstructionSize + 16, sizeof(uint32_t));
1663        if (branchType == BranchIfTruncateFailed) {
1664            m_assembler.branch(BT_OPCODE, 4);
1665            m_assembler.addlImm8r(-1, intscr);
1666            m_assembler.cmplRegReg(dest, intscr, SH4Condition(Equal));
1667            m_assembler.addlImm8r(1, intscr);
1668            m_assembler.sublRegReg(intscr, dest);
1669            result = branchTrue();
1670        } else {
1671            Jump out = Jump(m_assembler.je(), SH4Assembler::JumpNear);
1672            m_assembler.addlImm8r(-1, intscr);
1673            m_assembler.cmplRegReg(dest, intscr, SH4Condition(Equal));
1674            m_assembler.addlImm8r(1, intscr);
1675            m_assembler.sublRegReg(intscr, dest);
1676            result = branchFalse();
1677            out.link(this);
1678        }
1679        releaseScratch(intscr);
1680        return result;
1681    }
1682
1683    void truncateDoubleToInt32(FPRegisterID src, RegisterID dest)
1684    {
1685        m_assembler.ftrcdrmfpul(src);
1686        m_assembler.stsfpulReg(dest);
1687    }
1688
1689    void truncateDoubleToUint32(FPRegisterID src, RegisterID dest)
1690    {
1691        RegisterID intscr = claimScratch();
1692        m_assembler.loadConstant(0x80000000, intscr);
1693        convertInt32ToDouble(intscr, fscratch);
1694        addDouble(src, fscratch);
1695        m_assembler.ftrcdrmfpul(fscratch);
1696        m_assembler.stsfpulReg(dest);
1697        m_assembler.sublRegReg(intscr, dest);
1698        releaseScratch(intscr);
1699    }
1700
1701    // Stack manipulation operations
1702
1703    void pop(RegisterID dest)
1704    {
1705        m_assembler.popReg(dest);
1706    }
1707
1708    void push(RegisterID src)
1709    {
1710        m_assembler.pushReg(src);
1711    }
1712
1713    void push(TrustedImm32 imm)
1714    {
1715        RegisterID scr = claimScratch();
1716        m_assembler.loadConstant(imm.m_value, scr);
1717        push(scr);
1718        releaseScratch(scr);
1719    }
1720
1721    // Register move operations
1722
1723    void move(TrustedImm32 imm, RegisterID dest)
1724    {
1725        m_assembler.loadConstant(imm.m_value, dest);
1726    }
1727
1728    DataLabelPtr moveWithPatch(TrustedImmPtr initialValue, RegisterID dest)
1729    {
1730        m_assembler.ensureSpace(m_assembler.maxInstructionSize, sizeof(uint32_t));
1731        DataLabelPtr dataLabel(this);
1732        m_assembler.loadConstantUnReusable(reinterpret_cast<uint32_t>(initialValue.m_value), dest);
1733        return dataLabel;
1734    }
1735
1736    void move(RegisterID src, RegisterID dest)
1737    {
1738        if (src != dest)
1739            m_assembler.movlRegReg(src, dest);
1740    }
1741
1742    void move(TrustedImmPtr imm, RegisterID dest)
1743    {
1744        m_assembler.loadConstant(imm.asIntptr(), dest);
1745    }
1746
1747    void swap(RegisterID reg1, RegisterID reg2)
1748    {
1749        if (reg1 != reg2) {
1750            xor32(reg1, reg2);
1751            xor32(reg2, reg1);
1752            xor32(reg1, reg2);
1753        }
1754    }
1755
1756    void compare32(RelationalCondition cond, RegisterID left, RegisterID right, RegisterID dest)
1757    {
1758        m_assembler.cmplRegReg(right, left, SH4Condition(cond));
1759        if (cond != NotEqual) {
1760            m_assembler.movt(dest);
1761            return;
1762        }
1763
1764        m_assembler.ensureSpace(m_assembler.maxInstructionSize + 4);
1765        m_assembler.movImm8(0, dest);
1766        m_assembler.branch(BT_OPCODE, 0);
1767        m_assembler.movImm8(1, dest);
1768    }
1769
1770    void compare32(RelationalCondition cond, RegisterID left, TrustedImm32 right, RegisterID dest)
1771    {
1772        if (left != dest) {
1773            move(right, dest);
1774            compare32(cond, left, dest, dest);
1775            return;
1776        }
1777
1778        RegisterID scr = claimScratch();
1779        move(right, scr);
1780        compare32(cond, left, scr, dest);
1781        releaseScratch(scr);
1782    }
1783
1784    void test8(ResultCondition cond, Address address, TrustedImm32 mask, RegisterID dest)
1785    {
1786        ASSERT((cond == Zero) || (cond == NonZero));
1787
1788        load8(address, dest);
1789        if (mask.m_value == -1)
1790            compare32(0, dest, static_cast<RelationalCondition>(cond));
1791        else
1792            testlImm(mask.m_value, dest);
1793        if (cond != NonZero) {
1794            m_assembler.movt(dest);
1795            return;
1796        }
1797
1798        m_assembler.ensureSpace(m_assembler.maxInstructionSize + 4);
1799        m_assembler.movImm8(0, dest);
1800        m_assembler.branch(BT_OPCODE, 0);
1801        m_assembler.movImm8(1, dest);
1802    }
1803
1804    void test32(ResultCondition cond, Address address, TrustedImm32 mask, RegisterID dest)
1805    {
1806        ASSERT((cond == Zero) || (cond == NonZero));
1807
1808        load32(address, dest);
1809        if (mask.m_value == -1)
1810            compare32(0, dest, static_cast<RelationalCondition>(cond));
1811        else
1812            testlImm(mask.m_value, dest);
1813        if (cond != NonZero) {
1814            m_assembler.movt(dest);
1815            return;
1816        }
1817
1818        m_assembler.ensureSpace(m_assembler.maxInstructionSize + 4);
1819        m_assembler.movImm8(0, dest);
1820        m_assembler.branch(BT_OPCODE, 0);
1821        m_assembler.movImm8(1, dest);
1822    }
1823
1824    void loadPtrLinkReg(ImplicitAddress address)
1825    {
1826        RegisterID scr = claimScratch();
1827        load32(address, scr);
1828        m_assembler.ldspr(scr);
1829        releaseScratch(scr);
1830    }
1831
1832    Jump branch32(RelationalCondition cond, RegisterID left, RegisterID right)
1833    {
1834        m_assembler.cmplRegReg(right, left, SH4Condition(cond));
1835        /* BT label => BF off
1836           nop         LDR reg
1837           nop         braf @reg
1838           nop         nop
1839         */
1840        if (cond == NotEqual)
1841            return branchFalse();
1842        return branchTrue();
1843    }
1844
1845    Jump branch32(RelationalCondition cond, RegisterID left, TrustedImm32 right)
1846    {
1847        if (((cond == Equal) || (cond == NotEqual)) && !right.m_value)
1848            m_assembler.testlRegReg(left, left);
1849        else
1850            compare32(right.m_value, left, cond);
1851
1852        if (cond == NotEqual)
1853            return branchFalse();
1854        return branchTrue();
1855    }
1856
1857    Jump branch32(RelationalCondition cond, RegisterID left, Address right)
1858    {
1859        compare32(right.offset, right.base, left, cond);
1860        if (cond == NotEqual)
1861            return branchFalse();
1862        return branchTrue();
1863    }
1864
1865    Jump branch32(RelationalCondition cond, Address left, RegisterID right)
1866    {
1867        compare32(right, left.offset, left.base, cond);
1868        if (cond == NotEqual)
1869            return branchFalse();
1870        return branchTrue();
1871    }
1872
1873    Jump branch32(RelationalCondition cond, Address left, TrustedImm32 right)
1874    {
1875        compare32(right.m_value, left.offset, left.base, cond);
1876        if (cond == NotEqual)
1877            return branchFalse();
1878        return branchTrue();
1879    }
1880
1881    Jump branch32(RelationalCondition cond, AbsoluteAddress left, RegisterID right)
1882    {
1883        RegisterID scr = claimScratch();
1884
1885        load32(left.m_ptr, scr);
1886        m_assembler.cmplRegReg(right, scr, SH4Condition(cond));
1887        releaseScratch(scr);
1888
1889        if (cond == NotEqual)
1890            return branchFalse();
1891        return branchTrue();
1892    }
1893
1894    Jump branch32(RelationalCondition cond, AbsoluteAddress left, TrustedImm32 right)
1895    {
1896        RegisterID addressTempRegister = claimScratch();
1897
1898        move(TrustedImmPtr(left.m_ptr), addressTempRegister);
1899        m_assembler.movlMemReg(addressTempRegister, addressTempRegister);
1900        compare32(right.m_value, addressTempRegister, cond);
1901        releaseScratch(addressTempRegister);
1902
1903        if (cond == NotEqual)
1904            return branchFalse();
1905        return branchTrue();
1906    }
1907
1908    Jump branch8(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
1909    {
1910        ASSERT(!(right.m_value & 0xFFFFFF00));
1911        RegisterID lefttmp = claimScratch();
1912
1913        loadEffectiveAddress(left, lefttmp);
1914
1915        load8(lefttmp, lefttmp);
1916        RegisterID righttmp = claimScratch();
1917        m_assembler.loadConstant(right.m_value, righttmp);
1918
1919        Jump result = branch32(cond, lefttmp, righttmp);
1920        releaseScratch(lefttmp);
1921        releaseScratch(righttmp);
1922        return result;
1923    }
1924
1925    Jump branchTest32(ResultCondition cond, RegisterID reg, RegisterID mask)
1926    {
1927        ASSERT((cond == Zero) || (cond == NonZero));
1928
1929        m_assembler.testlRegReg(reg, mask);
1930
1931        if (cond == NonZero) // NotEqual
1932            return branchFalse();
1933        return branchTrue();
1934    }
1935
1936    Jump branchTest32(ResultCondition cond, RegisterID reg, TrustedImm32 mask = TrustedImm32(-1))
1937    {
1938        ASSERT((cond == Zero) || (cond == NonZero));
1939
1940        if (mask.m_value == -1)
1941            m_assembler.testlRegReg(reg, reg);
1942        else
1943            testlImm(mask.m_value, reg);
1944
1945        if (cond == NonZero) // NotEqual
1946            return branchFalse();
1947        return branchTrue();
1948    }
1949
1950    Jump branchTest32(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
1951    {
1952        ASSERT((cond == Zero) || (cond == NonZero));
1953
1954        if (mask.m_value == -1)
1955            compare32(0, address.offset, address.base, static_cast<RelationalCondition>(cond));
1956        else
1957            testImm(mask.m_value, address.offset, address.base);
1958
1959        if (cond == NonZero) // NotEqual
1960            return branchFalse();
1961        return branchTrue();
1962    }
1963
1964    Jump branchTest32(ResultCondition cond, BaseIndex address, TrustedImm32 mask = TrustedImm32(-1))
1965    {
1966        ASSERT((cond == Zero) || (cond == NonZero));
1967
1968        RegisterID scr = claimScratch();
1969
1970        move(address.index, scr);
1971        lshift32(TrustedImm32(address.scale), scr);
1972        add32(address.base, scr);
1973        load32(scr, address.offset, scr);
1974
1975        if (mask.m_value == -1)
1976            m_assembler.testlRegReg(scr, scr);
1977        else
1978            testlImm(mask.m_value, scr);
1979
1980        releaseScratch(scr);
1981
1982        if (cond == NonZero) // NotEqual
1983            return branchFalse();
1984        return branchTrue();
1985    }
1986
1987    Jump jump()
1988    {
1989        return Jump(m_assembler.jmp());
1990    }
1991
1992    void jump(RegisterID target)
1993    {
1994        m_assembler.jmpReg(target);
1995    }
1996
1997    void jump(Address address)
1998    {
1999        RegisterID scr = claimScratch();
2000        load32(address, scr);
2001        m_assembler.jmpReg(scr);
2002        releaseScratch(scr);
2003    }
2004
2005    void jump(AbsoluteAddress address)
2006    {
2007        RegisterID scr = claimScratch();
2008
2009        move(TrustedImmPtr(address.m_ptr), scr);
2010        m_assembler.movlMemReg(scr, scr);
2011        m_assembler.jmpReg(scr);
2012        releaseScratch(scr);
2013    }
2014
2015    // Arithmetic control flow operations
2016
2017    Jump branchNeg32(ResultCondition cond, RegisterID srcDest)
2018    {
2019        ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
2020
2021        if (cond == Overflow)
2022            return branchMul32(cond, TrustedImm32(-1), srcDest, srcDest);
2023
2024        neg32(srcDest);
2025
2026        if (cond == Signed) {
2027            m_assembler.cmppz(srcDest);
2028            return branchFalse();
2029        }
2030
2031        compare32(0, srcDest, Equal);
2032        return (cond == NonZero) ? branchFalse() : branchTrue();
2033    }
2034
2035    Jump branchAdd32(ResultCondition cond, RegisterID src, RegisterID dest)
2036    {
2037        ASSERT((cond == Overflow) || (cond == Signed) || (cond == PositiveOrZero) || (cond == Zero) || (cond == NonZero));
2038
2039        if (cond == Overflow) {
2040            m_assembler.addvlRegReg(src, dest);
2041            return branchTrue();
2042        }
2043
2044        m_assembler.addlRegReg(src, dest);
2045
2046        if ((cond == Signed) || (cond == PositiveOrZero)) {
2047            m_assembler.cmppz(dest);
2048            return (cond == Signed) ? branchFalse() : branchTrue();
2049        }
2050
2051        compare32(0, dest, Equal);
2052        return (cond == NonZero) ? branchFalse() : branchTrue();
2053    }
2054
2055    Jump branchAdd32(ResultCondition cond, RegisterID src1, RegisterID src2, RegisterID dest)
2056    {
2057        ASSERT((cond == Overflow) || (cond == Signed) || (cond == PositiveOrZero) || (cond == Zero) || (cond == NonZero));
2058
2059        if (cond == Overflow) {
2060            if (src1 == dest)
2061                m_assembler.addvlRegReg(src2, dest);
2062            else {
2063                move(src2, dest);
2064                m_assembler.addvlRegReg(src1, dest);
2065            }
2066            return branchTrue();
2067        }
2068
2069        add32(src1, src2, dest);
2070
2071        if ((cond == Signed) || (cond == PositiveOrZero)) {
2072            m_assembler.cmppz(dest);
2073            return (cond == Signed) ? branchFalse() : branchTrue();
2074        }
2075
2076        compare32(0, dest, Equal);
2077        return (cond == NonZero) ? branchFalse() : branchTrue();
2078    }
2079
2080    Jump branchAdd32(ResultCondition cond, TrustedImm32 imm, RegisterID dest)
2081    {
2082        ASSERT((cond == Overflow) || (cond == Signed) || (cond == PositiveOrZero) || (cond == Zero) || (cond == NonZero));
2083
2084        RegisterID immval = claimScratch();
2085        move(imm, immval);
2086        Jump result = branchAdd32(cond, immval, dest);
2087        releaseScratch(immval);
2088        return result;
2089    }
2090
2091    Jump branchAdd32(ResultCondition cond, RegisterID src, TrustedImm32 imm, RegisterID dest)
2092    {
2093        ASSERT((cond == Overflow) || (cond == Signed) || (cond == PositiveOrZero) || (cond == Zero) || (cond == NonZero));
2094
2095        move(src, dest);
2096
2097        if (cond == Overflow) {
2098            move(imm, scratchReg3);
2099            m_assembler.addvlRegReg(scratchReg3, dest);
2100            return branchTrue();
2101        }
2102
2103        add32(imm, dest);
2104
2105        if ((cond == Signed) || (cond == PositiveOrZero)) {
2106            m_assembler.cmppz(dest);
2107            return (cond == Signed) ? branchFalse() : branchTrue();
2108        }
2109
2110        compare32(0, dest, Equal);
2111        return (cond == NonZero) ? branchFalse() : branchTrue();
2112    }
2113
2114    Jump branchAdd32(ResultCondition cond, TrustedImm32 imm, AbsoluteAddress dest)
2115    {
2116        ASSERT((cond == Overflow) || (cond == Signed) || (cond == PositiveOrZero) || (cond == Zero) || (cond == NonZero));
2117        bool result;
2118
2119        move(imm, scratchReg3);
2120        RegisterID destptr = claimScratch();
2121        RegisterID destval = claimScratch();
2122        move(TrustedImmPtr(dest.m_ptr), destptr);
2123        m_assembler.movlMemReg(destptr, destval);
2124        if (cond == Overflow) {
2125            m_assembler.addvlRegReg(scratchReg3, destval);
2126            result = true;
2127        } else {
2128            m_assembler.addlRegReg(scratchReg3, destval);
2129            if ((cond == Signed) || (cond == PositiveOrZero)) {
2130                m_assembler.cmppz(destval);
2131                result = (cond == PositiveOrZero);
2132            } else {
2133                m_assembler.testlRegReg(destval, destval);
2134                result = (cond != NonZero);
2135            }
2136        }
2137        m_assembler.movlRegMem(destval, destptr);
2138        releaseScratch(destval);
2139        releaseScratch(destptr);
2140        return result ? branchTrue() : branchFalse();
2141    }
2142
2143    Jump branchMul32(ResultCondition cond, RegisterID src, RegisterID dest)
2144    {
2145        ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
2146
2147        if (cond == Overflow) {
2148            RegisterID scrsign = claimScratch();
2149            RegisterID msbres = claimScratch();
2150            m_assembler.dmulslRegReg(src, dest);
2151            m_assembler.stsmacl(dest);
2152            m_assembler.cmppz(dest);
2153            m_assembler.movt(scrsign);
2154            m_assembler.addlImm8r(-1, scrsign);
2155            m_assembler.stsmach(msbres);
2156            m_assembler.cmplRegReg(msbres, scrsign, SH4Condition(Equal));
2157            releaseScratch(msbres);
2158            releaseScratch(scrsign);
2159            return branchFalse();
2160        }
2161
2162        mul32(src, dest);
2163
2164        if (cond == Signed) {
2165            m_assembler.cmppz(dest);
2166            return branchFalse();
2167        }
2168
2169        compare32(0, dest, static_cast<RelationalCondition>(cond));
2170        return (cond == NonZero) ? branchFalse() : branchTrue();
2171    }
2172
2173    Jump branchMul32(ResultCondition cond, RegisterID src1, RegisterID src2, RegisterID dest)
2174    {
2175        ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
2176
2177        if (cond == Overflow) {
2178            RegisterID scrsign = claimScratch();
2179            RegisterID msbres = claimScratch();
2180            m_assembler.dmulslRegReg(src1, src2);
2181            m_assembler.stsmacl(dest);
2182            m_assembler.cmppz(dest);
2183            m_assembler.movt(scrsign);
2184            m_assembler.addlImm8r(-1, scrsign);
2185            m_assembler.stsmach(msbres);
2186            m_assembler.cmplRegReg(msbres, scrsign, SH4Condition(Equal));
2187            releaseScratch(msbres);
2188            releaseScratch(scrsign);
2189            return branchFalse();
2190        }
2191
2192        mul32(src1, src2, dest);
2193
2194        if (cond == Signed) {
2195            m_assembler.cmppz(dest);
2196            return branchFalse();
2197        }
2198
2199        compare32(0, dest, Equal);
2200        return (cond == NonZero) ? branchFalse() : branchTrue();
2201    }
2202
2203    Jump branchMul32(ResultCondition cond, TrustedImm32 imm, RegisterID src, RegisterID dest)
2204    {
2205        ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
2206
2207        if (src == dest) {
2208            move(imm, scratchReg3);
2209            return branchMul32(cond, scratchReg3, dest);
2210        }
2211
2212        move(imm, dest);
2213        return branchMul32(cond, src, dest);
2214    }
2215
2216    Jump branchSub32(ResultCondition cond, RegisterID src, RegisterID dest)
2217    {
2218        ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
2219
2220        if (cond == Overflow) {
2221            m_assembler.subvlRegReg(src, dest);
2222            return branchTrue();
2223        }
2224
2225        sub32(src, dest);
2226
2227        if (cond == Signed) {
2228            m_assembler.cmppz(dest);
2229            return branchFalse();
2230        }
2231
2232        compare32(0, dest, static_cast<RelationalCondition>(cond));
2233        return (cond == NonZero) ? branchFalse() : branchTrue();
2234    }
2235
2236    Jump branchSub32(ResultCondition cond, TrustedImm32 imm, RegisterID dest)
2237    {
2238        ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
2239
2240        RegisterID immval = claimScratch();
2241        move(imm, immval);
2242        Jump result = branchSub32(cond, immval, dest);
2243        releaseScratch(immval);
2244        return result;
2245    }
2246
2247    Jump branchSub32(ResultCondition cond, RegisterID src, TrustedImm32 imm, RegisterID dest)
2248    {
2249        ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
2250
2251        move(src, dest);
2252        return branchSub32(cond, imm, dest);
2253    }
2254
2255    Jump branchSub32(ResultCondition cond, RegisterID src1, RegisterID src2, RegisterID dest)
2256    {
2257        ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
2258
2259        if (src2 != dest) {
2260            move(src1, dest);
2261            return branchSub32(cond, src2, dest);
2262        }
2263
2264        if (cond == Overflow) {
2265            RegisterID tmpval = claimScratch();
2266            move(src1, tmpval);
2267            m_assembler.subvlRegReg(src2, tmpval);
2268            move(tmpval, dest);
2269            releaseScratch(tmpval);
2270            return branchTrue();
2271        }
2272
2273        RegisterID tmpval = claimScratch();
2274        move(src1, tmpval);
2275        sub32(src2, tmpval);
2276        move(tmpval, dest);
2277        releaseScratch(tmpval);
2278
2279        if (cond == Signed) {
2280            m_assembler.cmppz(dest);
2281            return branchFalse();
2282        }
2283
2284        compare32(0, dest, static_cast<RelationalCondition>(cond));
2285        return (cond == NonZero) ? branchFalse() : branchTrue();
2286    }
2287
2288    Jump branchOr32(ResultCondition cond, RegisterID src, RegisterID dest)
2289    {
2290        ASSERT((cond == Signed) || (cond == Zero) || (cond == NonZero));
2291
2292        or32(src, dest);
2293
2294        if (cond == Signed) {
2295            m_assembler.cmppz(dest);
2296            return branchFalse();
2297        }
2298
2299        compare32(0, dest, static_cast<RelationalCondition>(cond));
2300        return (cond == NonZero) ? branchFalse() : branchTrue();
2301    }
2302
2303    void branchConvertDoubleToInt32(FPRegisterID src, RegisterID dest, JumpList& failureCases, FPRegisterID, bool negZeroCheck = true)
2304    {
2305        truncateDoubleToInt32(src, dest);
2306        convertInt32ToDouble(dest, fscratch);
2307        failureCases.append(branchDouble(DoubleNotEqualOrUnordered, fscratch, src));
2308
2309        if (negZeroCheck)
2310            failureCases.append(branch32(Equal, dest, TrustedImm32(0)));
2311    }
2312
2313    void neg32(RegisterID dst)
2314    {
2315        m_assembler.neg(dst, dst);
2316    }
2317
2318    void urshift32(RegisterID shiftamount, RegisterID dest)
2319    {
2320        RegisterID shiftTmp = claimScratch();
2321        m_assembler.loadConstant(0x1f, shiftTmp);
2322        m_assembler.andlRegReg(shiftamount, shiftTmp);
2323        m_assembler.neg(shiftTmp, shiftTmp);
2324        m_assembler.shldRegReg(dest, shiftTmp);
2325        releaseScratch(shiftTmp);
2326    }
2327
2328    void urshift32(RegisterID src, RegisterID shiftAmount, RegisterID dest)
2329    {
2330        move(src, dest);
2331        urshift32(shiftAmount, dest);
2332    }
2333
2334    void urshift32(TrustedImm32 imm, RegisterID dest)
2335    {
2336        int immMasked = imm.m_value & 0x1f;
2337        if (!immMasked)
2338            return;
2339
2340        if ((immMasked == 1) || (immMasked == 2) || (immMasked == 8) || (immMasked == 16)) {
2341            m_assembler.shlrImm8r(immMasked, dest);
2342            return;
2343        }
2344
2345        RegisterID shiftTmp = claimScratch();
2346        m_assembler.loadConstant(-immMasked, shiftTmp);
2347        m_assembler.shldRegReg(dest, shiftTmp);
2348        releaseScratch(shiftTmp);
2349    }
2350
2351    void urshift32(RegisterID src, TrustedImm32 shiftamount, RegisterID dest)
2352    {
2353        move(src, dest);
2354        urshift32(shiftamount, dest);
2355    }
2356
2357    Call call()
2358    {
2359        return Call(m_assembler.call(), Call::Linkable);
2360    }
2361
2362    Call nearCall()
2363    {
2364        return Call(m_assembler.call(), Call::LinkableNear);
2365    }
2366
2367    Call call(RegisterID target)
2368    {
2369        return Call(m_assembler.call(target), Call::None);
2370    }
2371
2372    void call(Address address)
2373    {
2374        RegisterID target = claimScratch();
2375        load32(address.base, address.offset, target);
2376        m_assembler.ensureSpace(m_assembler.maxInstructionSize + 2);
2377        m_assembler.branch(JSR_OPCODE, target);
2378        m_assembler.nop();
2379        releaseScratch(target);
2380    }
2381
2382    void breakpoint()
2383    {
2384        m_assembler.ensureSpace(m_assembler.maxInstructionSize + 2);
2385        m_assembler.bkpt();
2386        m_assembler.nop();
2387    }
2388
2389    Jump branchPtrWithPatch(RelationalCondition cond, RegisterID left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
2390    {
2391        RegisterID dataTempRegister = claimScratch();
2392
2393        m_assembler.ensureSpace(m_assembler.maxInstructionSize + 10, 2 * sizeof(uint32_t));
2394        dataLabel = moveWithPatch(initialRightValue, dataTempRegister);
2395        m_assembler.cmplRegReg(dataTempRegister, left, SH4Condition(cond));
2396        releaseScratch(dataTempRegister);
2397
2398        if (cond == NotEqual)
2399            return branchFalse();
2400        return branchTrue();
2401    }
2402
2403    Jump branchPtrWithPatch(RelationalCondition cond, Address left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
2404    {
2405        RegisterID scr = claimScratch();
2406
2407        m_assembler.loadConstant(left.offset, scr);
2408        m_assembler.addlRegReg(left.base, scr);
2409        m_assembler.movlMemReg(scr, scr);
2410        RegisterID scr1 = claimScratch();
2411        m_assembler.ensureSpace(m_assembler.maxInstructionSize + 10, 2 * sizeof(uint32_t));
2412        dataLabel = moveWithPatch(initialRightValue, scr1);
2413        m_assembler.cmplRegReg(scr1, scr, SH4Condition(cond));
2414        releaseScratch(scr);
2415        releaseScratch(scr1);
2416
2417        if (cond == NotEqual)
2418            return branchFalse();
2419        return branchTrue();
2420    }
2421
2422    void ret()
2423    {
2424        m_assembler.ret();
2425        m_assembler.nop();
2426    }
2427
2428    DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address)
2429    {
2430        RegisterID scr = claimScratch();
2431        DataLabelPtr label = moveWithPatch(initialValue, scr);
2432        store32(scr, address);
2433        releaseScratch(scr);
2434        return label;
2435    }
2436
2437    DataLabelPtr storePtrWithPatch(ImplicitAddress address) { return storePtrWithPatch(TrustedImmPtr(0), address); }
2438
2439    int sizeOfConstantPool()
2440    {
2441        return m_assembler.sizeOfConstantPool();
2442    }
2443
2444    Call tailRecursiveCall()
2445    {
2446        RegisterID scr = claimScratch();
2447
2448        m_assembler.loadConstantUnReusable(0x0, scr, true);
2449        Jump m_jump = Jump(m_assembler.jmp(scr));
2450        releaseScratch(scr);
2451
2452        return Call::fromTailJump(m_jump);
2453    }
2454
2455    Call makeTailRecursiveCall(Jump oldJump)
2456    {
2457        oldJump.link(this);
2458        return tailRecursiveCall();
2459    }
2460
2461    void nop()
2462    {
2463        m_assembler.nop();
2464    }
2465
2466    void memoryFence()
2467    {
2468        m_assembler.synco();
2469    }
2470
2471    static FunctionPtr readCallTarget(CodeLocationCall call)
2472    {
2473        return FunctionPtr(reinterpret_cast<void(*)()>(SH4Assembler::readCallTarget(call.dataLocation())));
2474    }
2475
2476    static void replaceWithJump(CodeLocationLabel instructionStart, CodeLocationLabel destination)
2477    {
2478        SH4Assembler::replaceWithJump(instructionStart.dataLocation(), destination.dataLocation());
2479    }
2480
2481    static ptrdiff_t maxJumpReplacementSize()
2482    {
2483        return SH4Assembler::maxJumpReplacementSize();
2484    }
2485
2486    static bool canJumpReplacePatchableBranchPtrWithPatch() { return false; }
2487
2488    static CodeLocationLabel startOfBranchPtrWithPatchOnRegister(CodeLocationDataLabelPtr label)
2489    {
2490        return label.labelAtOffset(0);
2491    }
2492
2493    static void revertJumpReplacementToBranchPtrWithPatch(CodeLocationLabel instructionStart, RegisterID rd, void* initialValue)
2494    {
2495        SH4Assembler::revertJumpReplacementToBranchPtrWithPatch(instructionStart.dataLocation(), rd, reinterpret_cast<int>(initialValue));
2496    }
2497
2498    static CodeLocationLabel startOfPatchableBranchPtrWithPatchOnAddress(CodeLocationDataLabelPtr)
2499    {
2500        UNREACHABLE_FOR_PLATFORM();
2501        return CodeLocationLabel();
2502    }
2503
2504    static void revertJumpReplacementToPatchableBranchPtrWithPatch(CodeLocationLabel, Address, void*)
2505    {
2506        UNREACHABLE_FOR_PLATFORM();
2507    }
2508
2509protected:
2510    SH4Assembler::Condition SH4Condition(RelationalCondition cond)
2511    {
2512        return static_cast<SH4Assembler::Condition>(cond);
2513    }
2514
2515    SH4Assembler::Condition SH4Condition(ResultCondition cond)
2516    {
2517        return static_cast<SH4Assembler::Condition>(cond);
2518    }
2519private:
2520    friend class LinkBuffer;
2521    friend class RepatchBuffer;
2522
2523    static void linkCall(void* code, Call call, FunctionPtr function)
2524    {
2525        SH4Assembler::linkCall(code, call.m_label, function.value());
2526    }
2527
2528    static void repatchCall(CodeLocationCall call, CodeLocationLabel destination)
2529    {
2530        SH4Assembler::relinkCall(call.dataLocation(), destination.executableAddress());
2531    }
2532
2533    static void repatchCall(CodeLocationCall call, FunctionPtr destination)
2534    {
2535        SH4Assembler::relinkCall(call.dataLocation(), destination.executableAddress());
2536    }
2537};
2538
2539} // namespace JSC
2540
2541#endif // ENABLE(ASSEMBLER)
2542
2543#endif // MacroAssemblerSH4_h
2544