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 MacroAssemblerSH4_h
28#define MacroAssemblerSH4_h
29
30#if ENABLE(ASSEMBLER) && CPU(SH4)
31
32#include "AbstractMacroAssembler.h"
33#include "SH4Assembler.h"
34#include <wtf/Assertions.h>
35
36namespace JSC {
37typedef SH4Assembler::Condition Condition;
38
39class MacroAssemblerSH4 : public AbstractMacroAssembler<SH4Assembler> {
40public:
41    typedef SH4Assembler::FPRegisterID FPRegisterID;
42
43    static const Condition Equal;
44    static const Condition NotEqual;
45    static const Condition GreaterThan;
46    static const Condition GreaterThanOrEqual;
47    static const Condition LessThan;
48    static const Condition LessThanOrEqual;
49    static const Condition UGreaterThan;
50    static const Condition UGreaterThanOrEqual;
51    static const Condition ULessThan;
52    static const Condition ULessThanOrEqual;
53    static const Condition Zero;
54    static const Condition NonZero;
55    static const Condition Overflow;
56    static const Condition Above;
57    static const Condition AboveOrEqual;
58    static const Condition Below;
59    static const Condition BelowOrEqual;
60    static const Condition DoubleEqual;
61    static const Condition DoubleNotEqual;
62    static const Condition DoubleGreaterThan;
63    static const Condition DoubleGreaterThanOrEqual;
64    static const Condition DoubleLessThan;
65    static const Condition DoubleLessThanOrEqual;
66    static const Condition DoubleEqualOrUnordered;
67    static const Condition DoubleNotEqualOrUnordered;
68    static const Condition DoubleGreaterThanOrUnordered;
69    static const Condition DoubleGreaterThanOrEqualOrUnordered;
70    static const Condition DoubleLessThanOrUnordered;
71    static const Condition DoubleLessThanOrEqualOrUnordered;
72    static const Condition Signed;
73    static const Scale ScalePtr = TimesFour;
74    static const FPRegisterID fscratch = SH4Registers::fr10;
75    static const RegisterID stackPointerRegister = SH4Registers::sp;
76    static const RegisterID linkRegister = SH4Registers::pr;
77    static const RegisterID scratchReg3 = SH4Registers::r13;
78
79    RegisterID claimScratch()
80    {
81        return m_assembler.claimScratch();
82    }
83
84    void releaseScratch(RegisterID reg)
85    {
86        m_assembler.releaseScratch(reg);
87    }
88
89    // Integer arithmetic operations
90
91    void add32(RegisterID src, RegisterID dest)
92    {
93        m_assembler.addlRegReg(src, dest);
94    }
95
96    void add32(TrustedImm32 imm, RegisterID dest)
97    {
98        if (m_assembler.isImmediate(imm.m_value)) {
99            m_assembler.addlImm8r(imm.m_value, dest);
100            return;
101        }
102
103        RegisterID scr = claimScratch();
104        m_assembler.loadConstant(imm.m_value, scr);
105        m_assembler.addlRegReg(scr, dest);
106        releaseScratch(scr);
107    }
108
109    void add32(TrustedImm32 imm, RegisterID src, RegisterID dest)
110    {
111        if (src != dest)
112            m_assembler.movlRegReg(src, dest);
113        add32(imm, dest);
114    }
115
116    void add32(TrustedImm32 imm, Address address)
117    {
118        RegisterID scr = claimScratch();
119        load32(address, scr);
120        add32(imm, scr);
121        store32(scr, address);
122        releaseScratch(scr);
123    }
124
125    void add32(Address src, RegisterID dest)
126    {
127        RegisterID scr = claimScratch();
128        load32(src, scr);
129        m_assembler.addlRegReg(scr, dest);
130        releaseScratch(scr);
131    }
132
133    void and32(RegisterID src, RegisterID dest)
134    {
135        m_assembler.andlRegReg(src, dest);
136    }
137
138    void and32(TrustedImm32 imm, RegisterID dest)
139    {
140        if ((imm.m_value <= 255) && (imm.m_value >= 0) && (dest == SH4Registers::r0)) {
141            m_assembler.andlImm8r(imm.m_value, dest);
142            return;
143        }
144
145        RegisterID scr = claimScratch();
146        m_assembler.loadConstant((imm.m_value), scr);
147        m_assembler.andlRegReg(scr, dest);
148        releaseScratch(scr);
149    }
150
151    void lshift32(RegisterID shiftamount, RegisterID dest)
152    {
153        m_assembler.shllRegReg(dest, shiftamount);
154    }
155
156    void rshift32(int imm, RegisterID dest)
157    {
158        RegisterID scr = claimScratch();
159        m_assembler.loadConstant(-imm, scr);
160        m_assembler.shaRegReg(dest, scr);
161        releaseScratch(scr);
162    }
163
164    void lshift32(TrustedImm32 imm, RegisterID dest)
165    {
166        if ((imm.m_value == 1) || (imm.m_value == 2) || (imm.m_value == 8) || (imm.m_value == 16)) {
167            m_assembler.shllImm8r(imm.m_value, dest);
168            return;
169        }
170
171        RegisterID scr = claimScratch();
172        m_assembler.loadConstant(imm.m_value, scr);
173        m_assembler.shllRegReg(dest, scr);
174        releaseScratch(scr);
175    }
176
177    void mul32(RegisterID src, RegisterID dest)
178    {
179        m_assembler.imullRegReg(src, dest);
180        m_assembler.stsmacl(dest);
181    }
182
183    void mul32(TrustedImm32 imm, RegisterID src, RegisterID dest)
184    {
185        RegisterID scr = claimScratch();
186        move(imm, scr);
187        if  (src != dest)
188            move(src, dest);
189        mul32(scr,  dest);
190        releaseScratch(scr);
191    }
192
193    void not32(RegisterID src, RegisterID dest)
194    {
195        m_assembler.notlReg(src, dest);
196    }
197
198    void or32(RegisterID src, RegisterID dest)
199    {
200        m_assembler.orlRegReg(src, dest);
201    }
202
203    void or32(TrustedImm32 imm, RegisterID dest)
204    {
205        if ((imm.m_value <= 255) && (imm.m_value >= 0) && (dest == SH4Registers::r0)) {
206            m_assembler.orlImm8r(imm.m_value, dest);
207            return;
208        }
209
210        RegisterID scr = claimScratch();
211        m_assembler.loadConstant(imm.m_value, scr);
212        m_assembler.orlRegReg(scr, dest);
213        releaseScratch(scr);
214    }
215
216    void rshift32(RegisterID shiftamount, RegisterID dest)
217    {
218        compare32(32, shiftamount, Equal);
219        m_assembler.ensureSpace(m_assembler.maxInstructionSize + 4);
220        m_assembler.branch(BT_OPCODE, 1);
221        m_assembler.neg(shiftamount, shiftamount);
222        m_assembler.shaRegReg(dest, shiftamount);
223    }
224
225    void rshift32(TrustedImm32 imm, RegisterID dest)
226    {
227        if (imm.m_value & 0x1f)
228            rshift32(imm.m_value & 0x1f, dest);
229    }
230
231    void sub32(RegisterID src, RegisterID dest)
232    {
233        m_assembler.sublRegReg(src, dest);
234    }
235
236    void sub32(TrustedImm32 imm, AbsoluteAddress address, RegisterID scratchReg)
237    {
238        RegisterID result = claimScratch();
239
240        m_assembler.loadConstant(reinterpret_cast<uint32_t>(address.m_ptr), scratchReg);
241        m_assembler.movlMemReg(scratchReg, result);
242
243        if (m_assembler.isImmediate(-imm.m_value))
244            m_assembler.addlImm8r(-imm.m_value, result);
245        else {
246            m_assembler.loadConstant(imm.m_value, scratchReg3);
247            m_assembler.sublRegReg(scratchReg3, result);
248        }
249
250        store32(result, scratchReg);
251        releaseScratch(result);
252    }
253
254    void sub32(TrustedImm32 imm, AbsoluteAddress address)
255    {
256        RegisterID result = claimScratch();
257        RegisterID scratchReg = claimScratch();
258
259        m_assembler.loadConstant(reinterpret_cast<uint32_t>(address.m_ptr), scratchReg);
260        m_assembler.movlMemReg(scratchReg, result);
261
262        if (m_assembler.isImmediate(-imm.m_value))
263            m_assembler.addlImm8r(-imm.m_value, result);
264        else {
265            m_assembler.loadConstant(imm.m_value, scratchReg3);
266            m_assembler.sublRegReg(scratchReg3, result);
267        }
268
269        store32(result, scratchReg);
270        releaseScratch(result);
271        releaseScratch(scratchReg);
272    }
273
274    void add32(TrustedImm32 imm, AbsoluteAddress address, RegisterID scratchReg)
275    {
276        RegisterID result = claimScratch();
277
278        m_assembler.loadConstant(reinterpret_cast<uint32_t>(address.m_ptr), scratchReg);
279        m_assembler.movlMemReg(scratchReg, result);
280
281        if (m_assembler.isImmediate(imm.m_value))
282            m_assembler.addlImm8r(imm.m_value, result);
283        else {
284            m_assembler.loadConstant(imm.m_value, scratchReg3);
285            m_assembler.addlRegReg(scratchReg3, result);
286        }
287
288        store32(result, scratchReg);
289        releaseScratch(result);
290    }
291
292    void add32(TrustedImm32 imm, AbsoluteAddress address)
293    {
294        RegisterID result = claimScratch();
295        RegisterID scratchReg = claimScratch();
296
297        m_assembler.loadConstant(reinterpret_cast<uint32_t>(address.m_ptr), scratchReg);
298        m_assembler.movlMemReg(scratchReg, result);
299
300        if (m_assembler.isImmediate(imm.m_value))
301            m_assembler.addlImm8r(imm.m_value, result);
302        else {
303            m_assembler.loadConstant(imm.m_value, scratchReg3);
304            m_assembler.addlRegReg(scratchReg3, result);
305        }
306
307        store32(result, scratchReg);
308        releaseScratch(result);
309        releaseScratch(scratchReg);
310    }
311
312    void sub32(TrustedImm32 imm, RegisterID dest)
313    {
314        if (m_assembler.isImmediate(-imm.m_value)) {
315            m_assembler.addlImm8r(-imm.m_value, dest);
316            return;
317        }
318
319        RegisterID scr = claimScratch();
320        m_assembler.loadConstant(imm.m_value, scr);
321        m_assembler.sublRegReg(scr, dest);
322        releaseScratch(scr);
323    }
324
325    void sub32(Address src, RegisterID dest)
326    {
327        RegisterID scr = claimScratch();
328        load32(src, scr);
329        m_assembler.sublRegReg(scr, dest);
330        releaseScratch(scr);
331    }
332
333    void xor32(RegisterID src, RegisterID dest)
334    {
335        m_assembler.xorlRegReg(src, dest);
336    }
337
338    void xor32(TrustedImm32 imm, RegisterID srcDest)
339    {
340        if ((srcDest != SH4Registers::r0) || (imm.m_value > 255) || (imm.m_value < 0)) {
341            RegisterID scr = claimScratch();
342            m_assembler.loadConstant((imm.m_value), scr);
343            m_assembler.xorlRegReg(scr, srcDest);
344            releaseScratch(scr);
345            return;
346        }
347
348        m_assembler.xorlImm8r(imm.m_value, srcDest);
349    }
350
351    void compare32(int imm, RegisterID dst, Condition cond)
352    {
353        if (((cond == Equal) || (cond == NotEqual)) && (dst == SH4Registers::r0) && m_assembler.isImmediate(imm)) {
354            m_assembler.cmpEqImmR0(imm, dst, cond);
355            return;
356        }
357
358        RegisterID scr = claimScratch();
359        m_assembler.loadConstant(imm, scr);
360        m_assembler.cmplRegReg(scr, dst, cond);
361        releaseScratch(scr);
362    }
363
364    void compare32(int offset, RegisterID base, RegisterID left, Condition cond)
365    {
366        RegisterID scr = claimScratch();
367        if (!offset) {
368            m_assembler.movlMemReg(base, scr);
369            m_assembler.cmplRegReg(scr, left, cond);
370            releaseScratch(scr);
371            return;
372        }
373
374        if ((offset < 0) || (offset >= 64)) {
375            m_assembler.loadConstant(offset, scr);
376            m_assembler.addlRegReg(base, scr);
377            m_assembler.movlMemReg(scr, scr);
378            m_assembler.cmplRegReg(scr, left, cond);
379            releaseScratch(scr);
380            return;
381        }
382
383        m_assembler.movlMemReg(offset >> 2, base, scr);
384        m_assembler.cmplRegReg(scr, left, cond);
385        releaseScratch(scr);
386    }
387
388    void testImm(int imm, int offset, RegisterID base)
389    {
390        RegisterID scr = claimScratch();
391        RegisterID scr1 = claimScratch();
392
393        if ((offset < 0) || (offset >= 64)) {
394            m_assembler.loadConstant(offset, scr);
395            m_assembler.addlRegReg(base, scr);
396            m_assembler.movlMemReg(scr, scr);
397        } else if (offset)
398            m_assembler.movlMemReg(offset >> 2, base, scr);
399        else
400            m_assembler.movlMemReg(base, scr);
401        if (m_assembler.isImmediate(imm))
402            m_assembler.movImm8(imm, scr1);
403        else
404            m_assembler.loadConstant(imm, scr1);
405
406        m_assembler.testlRegReg(scr, scr1);
407        releaseScratch(scr);
408        releaseScratch(scr1);
409    }
410
411    void testlImm(int imm, RegisterID dst)
412    {
413        if ((dst == SH4Registers::r0) && (imm <= 255) && (imm >= 0)) {
414            m_assembler.testlImm8r(imm, dst);
415            return;
416        }
417
418        RegisterID scr = claimScratch();
419        m_assembler.loadConstant(imm, scr);
420        m_assembler.testlRegReg(scr, dst);
421        releaseScratch(scr);
422    }
423
424    void compare32(RegisterID right, int offset, RegisterID base, Condition cond)
425    {
426        if (!offset) {
427            RegisterID scr = claimScratch();
428            m_assembler.movlMemReg(base, scr);
429            m_assembler.cmplRegReg(right, scr, cond);
430            releaseScratch(scr);
431            return;
432        }
433
434        if ((offset < 0) || (offset >= 64)) {
435            RegisterID scr = claimScratch();
436            m_assembler.loadConstant(offset, scr);
437            m_assembler.addlRegReg(base, scr);
438            m_assembler.movlMemReg(scr, scr);
439            m_assembler.cmplRegReg(right, scr, cond);
440            releaseScratch(scr);
441            return;
442        }
443
444        RegisterID scr = claimScratch();
445        m_assembler.movlMemReg(offset >> 2, base, scr);
446        m_assembler.cmplRegReg(right, scr, cond);
447        releaseScratch(scr);
448    }
449
450    void compare32(int imm, int offset, RegisterID base, Condition cond)
451    {
452        if (!offset) {
453            RegisterID scr = claimScratch();
454            RegisterID scr1 = claimScratch();
455            m_assembler.movlMemReg(base, scr);
456            m_assembler.loadConstant(imm, scr1);
457            m_assembler.cmplRegReg(scr1, scr, cond);
458            releaseScratch(scr1);
459            releaseScratch(scr);
460            return;
461        }
462
463        if ((offset < 0) || (offset >= 64)) {
464            RegisterID scr = claimScratch();
465            RegisterID scr1 = claimScratch();
466            m_assembler.loadConstant(offset, scr);
467            m_assembler.addlRegReg(base, scr);
468            m_assembler.movlMemReg(scr, scr);
469            m_assembler.loadConstant(imm, scr1);
470            m_assembler.cmplRegReg(scr1, scr, cond);
471            releaseScratch(scr1);
472            releaseScratch(scr);
473            return;
474        }
475
476        RegisterID scr = claimScratch();
477        RegisterID scr1 = claimScratch();
478        m_assembler.movlMemReg(offset >> 2, base, scr);
479        m_assembler.loadConstant(imm, scr1);
480        m_assembler.cmplRegReg(scr1, scr, cond);
481        releaseScratch(scr1);
482        releaseScratch(scr);
483    }
484
485    // Memory access operation
486
487    void load32(ImplicitAddress address, RegisterID dest)
488    {
489        load32(address.base, address.offset, dest);
490    }
491
492    void load8(ImplicitAddress address, RegisterID dest)
493    {
494        load8(address.base, address.offset, dest);
495    }
496
497    void load32(BaseIndex address, RegisterID dest)
498    {
499        RegisterID scr = claimScratch();
500        move(address.index, scr);
501        lshift32(TrustedImm32(address.scale), scr);
502        add32(address.base, scr);
503        load32(scr, address.offset, dest);
504        releaseScratch(scr);
505    }
506
507    void load32(void* address, RegisterID dest)
508    {
509        m_assembler.loadConstant(reinterpret_cast<uint32_t>(address), dest);
510        m_assembler.movlMemReg(dest, dest);
511    }
512
513    void load32(RegisterID base, int offset, RegisterID dest)
514    {
515        if (!offset) {
516            m_assembler.movlMemReg(base, dest);
517            return;
518        }
519
520        if ((offset >= 0) && (offset < 64)) {
521            m_assembler.movlMemReg(offset >> 2, base, dest);
522            return;
523        }
524
525        if ((dest == SH4Registers::r0) && (dest != base)) {
526            m_assembler.loadConstant((offset), dest);
527            m_assembler.movlR0mr(base, dest);
528            return;
529        }
530
531        RegisterID scr;
532        if (dest == base)
533            scr = claimScratch();
534        else
535            scr = dest;
536        m_assembler.loadConstant((offset), scr);
537        m_assembler.addlRegReg(base, scr);
538        m_assembler.movlMemReg(scr, dest);
539
540        if (dest == base)
541            releaseScratch(scr);
542    }
543
544    void load8(RegisterID base, int offset, RegisterID dest)
545    {
546        if (!offset) {
547            m_assembler.movbMemReg(base, dest);
548            return;
549        }
550
551        if ((offset > 0) && (offset < 64) && (dest == SH4Registers::r0)) {
552            m_assembler.movbMemReg(offset, base, dest);
553            return;
554        }
555
556        if (base != dest) {
557            m_assembler.loadConstant((offset), dest);
558            m_assembler.addlRegReg(base, dest);
559            m_assembler.movbMemReg(dest, dest);
560            return;
561        }
562
563        RegisterID scr = claimScratch();
564        m_assembler.loadConstant((offset), scr);
565        m_assembler.addlRegReg(base, scr);
566        m_assembler.movbMemReg(scr, dest);
567        releaseScratch(scr);
568    }
569
570    void load32(RegisterID r0, RegisterID src, RegisterID dst)
571    {
572        ASSERT(r0 == SH4Registers::r0);
573        m_assembler.movlR0mr(src, dst);
574    }
575
576    void load32(RegisterID src, RegisterID dst)
577    {
578        m_assembler.movlMemReg(src, dst);
579    }
580
581    void load16(ImplicitAddress address, RegisterID dest)
582    {
583        if (!address.offset) {
584            m_assembler.movwMemReg(address.base, dest);
585            return;
586        }
587
588        if ((address.offset > 0) && (address.offset < 64) && (dest == SH4Registers::r0)) {
589            m_assembler.movwMemReg(address.offset, address.base, dest);
590            return;
591        }
592
593        if (address.base != dest) {
594            m_assembler.loadConstant((address.offset), dest);
595            m_assembler.addlRegReg(address.base, dest);
596            m_assembler.movwMemReg(dest, dest);
597            return;
598        }
599
600        RegisterID scr = claimScratch();
601        m_assembler.loadConstant((address.offset), scr);
602        m_assembler.addlRegReg(address.base, scr);
603        m_assembler.movwMemReg(scr, dest);
604        releaseScratch(scr);
605    }
606
607    void load16(RegisterID src, RegisterID dest)
608    {
609        m_assembler.movwMemReg(src, dest);
610    }
611
612    void load16(RegisterID r0, RegisterID src, RegisterID dest)
613    {
614        ASSERT(r0 == SH4Registers::r0);
615        m_assembler.movwR0mr(src, dest);
616    }
617
618    void load16(BaseIndex address, RegisterID dest)
619    {
620        RegisterID scr = claimScratch();
621
622        move(address.index, scr);
623        lshift32(TrustedImm32(address.scale), scr);
624
625        if (address.offset)
626            add32(TrustedImm32(address.offset), scr);
627        if (scr == SH4Registers::r0)
628            m_assembler.movwR0mr(address.base, scr);
629        else {
630            add32(address.base, scr);
631            load16(scr, scr);
632        }
633
634        extuw(scr, dest);
635        releaseScratch(scr);
636    }
637
638    void store32(RegisterID src, ImplicitAddress address)
639    {
640        RegisterID scr = claimScratch();
641        store32(src, address.offset, address.base, scr);
642        releaseScratch(scr);
643    }
644
645    void store32(RegisterID src, int offset, RegisterID base, RegisterID scr)
646    {
647        if (!offset) {
648            m_assembler.movlRegMem(src, base);
649            return;
650        }
651
652        if ((offset >=0) && (offset < 64)) {
653            m_assembler.movlRegMem(src, offset >> 2, base);
654            return;
655        }
656
657        m_assembler.loadConstant((offset), scr);
658        if (scr == SH4Registers::r0) {
659            m_assembler.movlRegMemr0(src, base);
660            return;
661        }
662
663        m_assembler.addlRegReg(base, scr);
664        m_assembler.movlRegMem(src, scr);
665    }
666
667    void store32(RegisterID src, RegisterID offset, RegisterID base)
668    {
669        ASSERT(offset == SH4Registers::r0);
670        m_assembler.movlRegMemr0(src, base);
671    }
672
673    void store32(RegisterID src, RegisterID dst)
674    {
675        m_assembler.movlRegMem(src, dst);
676    }
677
678    void store32(TrustedImm32 imm, ImplicitAddress address)
679    {
680        RegisterID scr = claimScratch();
681        RegisterID scr1 = claimScratch();
682        m_assembler.loadConstant((imm.m_value), scr);
683        store32(scr, address.offset, address.base, scr1);
684        releaseScratch(scr);
685        releaseScratch(scr1);
686    }
687
688    void store32(RegisterID src, BaseIndex address)
689    {
690        RegisterID scr = claimScratch();
691
692        move(address.index, scr);
693        lshift32(TrustedImm32(address.scale), scr);
694        add32(address.base, scr);
695        store32(src, Address(scr, address.offset));
696
697        releaseScratch(scr);
698    }
699
700    void store32(TrustedImm32 imm, void* address)
701    {
702        RegisterID scr = claimScratch();
703        RegisterID scr1 = claimScratch();
704        m_assembler.loadConstant((imm.m_value), scr);
705        m_assembler.loadConstant(reinterpret_cast<uint32_t>(address), scr1);
706        m_assembler.movlMemReg(scr, scr1);
707        releaseScratch(scr);
708        releaseScratch(scr1);
709    }
710
711    void store32(RegisterID src, void* address)
712    {
713        RegisterID scr = claimScratch();
714        m_assembler.loadConstant(reinterpret_cast<uint32_t>(address), scr);
715        m_assembler.movlMemReg(src, scr);
716        releaseScratch(scr);
717    }
718
719    DataLabel32 load32WithAddressOffsetPatch(Address address, RegisterID dest)
720    {
721        RegisterID scr = claimScratch();
722        DataLabel32 label(this);
723        m_assembler.loadConstantUnReusable(address.offset, scr);
724        m_assembler.addlRegReg(address.base, scr);
725        m_assembler.movlMemReg(scr, dest);
726        releaseScratch(scr);
727        return label;
728    }
729
730    DataLabel32 store32WithAddressOffsetPatch(RegisterID src, Address address)
731    {
732        RegisterID scr = claimScratch();
733        DataLabel32 label(this);
734        m_assembler.loadConstantUnReusable(address.offset, scr);
735        m_assembler.addlRegReg(address.base, scr);
736        m_assembler.movlRegMem(src, scr);
737        releaseScratch(scr);
738        return label;
739    }
740
741     // Floating-point operations
742
743    bool supportsFloatingPoint() const { return true; }
744    bool supportsFloatingPointTruncate() const { return true; }
745    bool supportsFloatingPointSqrt() const { return true; }
746
747    void loadDouble(ImplicitAddress address, FPRegisterID dest)
748    {
749        RegisterID scr = claimScratch();
750
751        m_assembler.loadConstant(address.offset, scr);
752        if (address.base == SH4Registers::r0) {
753            m_assembler.fmovsReadr0r(scr, (FPRegisterID)(dest + 1));
754            m_assembler.addlImm8r(4, scr);
755            m_assembler.fmovsReadr0r(scr, dest);
756            releaseScratch(scr);
757            return;
758        }
759
760        m_assembler.addlRegReg(address.base, scr);
761        m_assembler.fmovsReadrminc(scr, (FPRegisterID)(dest + 1));
762        m_assembler.fmovsReadrm(scr, dest);
763        releaseScratch(scr);
764    }
765
766    void loadDouble(const void* address, FPRegisterID dest)
767    {
768        RegisterID scr = claimScratch();
769        m_assembler.loadConstant(reinterpret_cast<uint32_t>(address), scr);
770        m_assembler.fmovsReadrminc(scr, (FPRegisterID)(dest + 1));
771        m_assembler.fmovsReadrm(scr, dest);
772        releaseScratch(scr);
773    }
774
775    void storeDouble(FPRegisterID src, ImplicitAddress address)
776    {
777        RegisterID scr = claimScratch();
778        m_assembler.loadConstant(address.offset, scr);
779        m_assembler.addlRegReg(address.base, scr);
780        m_assembler.fmovsWriterm((FPRegisterID)(src + 1), scr);
781        m_assembler.addlImm8r(4, scr);
782        m_assembler.fmovsWriterm(src, scr);
783        releaseScratch(scr);
784    }
785
786    void addDouble(FPRegisterID src, FPRegisterID dest)
787    {
788        m_assembler.daddRegReg(src, dest);
789    }
790
791    void addDouble(Address address, FPRegisterID dest)
792    {
793        loadDouble(address, fscratch);
794        addDouble(fscratch, dest);
795    }
796
797    void subDouble(FPRegisterID src, FPRegisterID dest)
798    {
799        m_assembler.dsubRegReg(src, dest);
800    }
801
802    void subDouble(Address address, FPRegisterID dest)
803    {
804        loadDouble(address, fscratch);
805        subDouble(fscratch, dest);
806    }
807
808    void mulDouble(FPRegisterID src, FPRegisterID dest)
809    {
810        m_assembler.dmulRegReg(src, dest);
811    }
812
813    void mulDouble(Address address, FPRegisterID dest)
814    {
815        loadDouble(address, fscratch);
816        mulDouble(fscratch, dest);
817    }
818
819    void divDouble(FPRegisterID src, FPRegisterID dest)
820    {
821        m_assembler.ddivRegReg(src, dest);
822    }
823
824    void convertInt32ToDouble(RegisterID src, FPRegisterID dest)
825    {
826        m_assembler.ldsrmfpul(src);
827        m_assembler.floatfpulDreg(dest);
828    }
829
830    void convertInt32ToDouble(AbsoluteAddress src, FPRegisterID dest)
831    {
832        RegisterID scr = claimScratch();
833        m_assembler.loadConstant(reinterpret_cast<uint32_t>(src.m_ptr), scr);
834        convertInt32ToDouble(scr, dest);
835        releaseScratch(scr);
836    }
837
838    void convertInt32ToDouble(Address src, FPRegisterID dest)
839    {
840        RegisterID scr = claimScratch();
841        load32(src, scr);
842        convertInt32ToDouble(scr, dest);
843        releaseScratch(scr);
844    }
845
846    void load32WithUnalignedHalfWords(BaseIndex address, RegisterID dest)
847    {
848        RegisterID scr = claimScratch();
849
850        move(address.index, scr);
851        lshift32(TrustedImm32(address.scale), scr);
852        add32(address.base, scr);
853
854        if (address.offset)
855            add32(TrustedImm32(address.offset), scr);
856
857        RegisterID scr1 = claimScratch();
858        load16(scr, scr1);
859        add32(TrustedImm32(2), scr);
860        load16(scr, dest);
861        move(TrustedImm32(16), scr);
862        m_assembler.shllRegReg(dest, scr);
863        or32(scr1, dest);
864
865        releaseScratch(scr);
866        releaseScratch(scr1);
867    }
868
869    Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, TrustedImm32 right)
870    {
871        RegisterID scr = scratchReg3;
872        load32WithUnalignedHalfWords(left, scr);
873        if (((cond == Equal) || (cond == NotEqual)) && !right.m_value)
874            m_assembler.testlRegReg(scr, scr);
875        else
876            compare32(right.m_value, scr, cond);
877
878        if (cond == NotEqual)
879            return branchFalse();
880        return branchTrue();
881    }
882
883    Jump branchDoubleNonZero(FPRegisterID reg, FPRegisterID scratch)
884    {
885        m_assembler.movImm8(0, scratchReg3);
886        convertInt32ToDouble(scratchReg3, scratch);
887        return branchDouble(DoubleNotEqual, reg, scratch);
888    }
889
890    Jump branchDoubleZeroOrNaN(FPRegisterID reg, FPRegisterID scratch)
891    {
892        m_assembler.movImm8(0, scratchReg3);
893        convertInt32ToDouble(scratchReg3, scratch);
894        return branchDouble(DoubleEqualOrUnordered, reg, scratch);
895    }
896
897    Jump branchDouble(Condition cond, FPRegisterID left, FPRegisterID right)
898    {
899        if (cond == DoubleEqual) {
900            m_assembler.dcmppeq(right, left);
901            return branchTrue();
902        }
903
904        if (cond == DoubleNotEqual) {
905            RegisterID scr = claimScratch();
906            m_assembler.loadConstant(0x7fbfffff, scratchReg3);
907            m_assembler.dcnvds(right);
908            m_assembler.stsfpulReg(scr);
909            m_assembler.cmplRegReg(scratchReg3, scr, Equal);
910            m_assembler.ensureSpace(m_assembler.maxInstructionSize + 22, sizeof(uint32_t));
911            m_assembler.branch(BT_OPCODE, 8);
912            m_assembler.dcnvds(left);
913            m_assembler.stsfpulReg(scr);
914            m_assembler.cmplRegReg(scratchReg3, scr, Equal);
915            m_assembler.branch(BT_OPCODE, 4);
916            m_assembler.dcmppeq(right, left);
917            releaseScratch(scr);
918            return branchFalse();
919        }
920
921        if (cond == DoubleGreaterThan) {
922            m_assembler.dcmppgt(right, left);
923            return branchTrue();
924        }
925
926        if (cond == DoubleGreaterThanOrEqual) {
927            m_assembler.dcmppgt(left, right);
928            return branchFalse();
929        }
930
931        if (cond == DoubleLessThan) {
932            m_assembler.dcmppgt(left, right);
933            return branchTrue();
934        }
935
936        if (cond == DoubleLessThanOrEqual) {
937            m_assembler.dcmppgt(right, left);
938            return branchFalse();
939        }
940
941        if (cond == DoubleEqualOrUnordered) {
942            RegisterID scr = claimScratch();
943            m_assembler.loadConstant(0x7fbfffff, scratchReg3);
944            m_assembler.dcnvds(right);
945            m_assembler.stsfpulReg(scr);
946            m_assembler.cmplRegReg(scratchReg3, scr, Equal);
947            m_assembler.ensureSpace(m_assembler.maxInstructionSize + 22, sizeof(uint32_t));
948            m_assembler.branch(BT_OPCODE, 5);
949            m_assembler.dcnvds(left);
950            m_assembler.stsfpulReg(scr);
951            m_assembler.cmplRegReg(scratchReg3, scr, Equal);
952            m_assembler.branch(BT_OPCODE, 1);
953            m_assembler.dcmppeq(left, right);
954            releaseScratch(scr);
955            return branchTrue();
956        }
957
958        if (cond == DoubleGreaterThanOrUnordered) {
959            RegisterID scr = claimScratch();
960            m_assembler.loadConstant(0x7fbfffff, scratchReg3);
961            m_assembler.dcnvds(right);
962            m_assembler.stsfpulReg(scr);
963            m_assembler.cmplRegReg(scratchReg3, scr, Equal);
964            m_assembler.ensureSpace(m_assembler.maxInstructionSize + 22, sizeof(uint32_t));
965            m_assembler.branch(BT_OPCODE, 5);
966            m_assembler.dcnvds(left);
967            m_assembler.stsfpulReg(scr);
968            m_assembler.cmplRegReg(scratchReg3, scr, Equal);
969            m_assembler.branch(BT_OPCODE, 1);
970            m_assembler.dcmppgt(right, left);
971            releaseScratch(scr);
972            return branchTrue();
973        }
974
975        if (cond == DoubleGreaterThanOrEqualOrUnordered) {
976            RegisterID scr = claimScratch();
977            m_assembler.loadConstant(0x7fbfffff, scratchReg3);
978            m_assembler.dcnvds(right);
979            m_assembler.stsfpulReg(scr);
980            m_assembler.cmplRegReg(scratchReg3, scr, Equal);
981            m_assembler.ensureSpace(m_assembler.maxInstructionSize + 22, sizeof(uint32_t));
982            m_assembler.branch(BT_OPCODE, 5);
983            m_assembler.dcnvds(left);
984            m_assembler.stsfpulReg(scr);
985            m_assembler.cmplRegReg(scratchReg3, scr, Equal);
986            m_assembler.branch(BT_OPCODE, 1);
987            m_assembler.dcmppgt(left, right);
988            releaseScratch(scr);
989            return branchFalse();
990        }
991
992        if (cond == DoubleLessThanOrUnordered) {
993            RegisterID scr = claimScratch();
994            m_assembler.loadConstant(0x7fbfffff, scratchReg3);
995            m_assembler.dcnvds(right);
996            m_assembler.stsfpulReg(scr);
997            m_assembler.cmplRegReg(scratchReg3, scr, Equal);
998            m_assembler.ensureSpace(m_assembler.maxInstructionSize + 22, sizeof(uint32_t));
999            m_assembler.branch(BT_OPCODE, 5);
1000            m_assembler.dcnvds(left);
1001            m_assembler.stsfpulReg(scr);
1002            m_assembler.cmplRegReg(scratchReg3, scr, Equal);
1003            m_assembler.branch(BT_OPCODE, 1);
1004            m_assembler.dcmppgt(left, right);
1005            releaseScratch(scr);
1006            return branchTrue();
1007        }
1008
1009        if (cond == DoubleLessThanOrEqualOrUnordered) {
1010            RegisterID scr = claimScratch();
1011            m_assembler.loadConstant(0x7fbfffff, scratchReg3);
1012            m_assembler.dcnvds(right);
1013            m_assembler.stsfpulReg(scr);
1014            m_assembler.cmplRegReg(scratchReg3, scr, Equal);
1015            m_assembler.ensureSpace(m_assembler.maxInstructionSize + 22, sizeof(uint32_t));
1016            m_assembler.branch(BT_OPCODE, 5);
1017            m_assembler.dcnvds(left);
1018            m_assembler.stsfpulReg(scr);
1019            m_assembler.cmplRegReg(scratchReg3, scr, Equal);
1020            m_assembler.branch(BT_OPCODE, 1);
1021            m_assembler.dcmppgt(right, left);
1022            releaseScratch(scr);
1023            return branchFalse();
1024        }
1025
1026        ASSERT(cond == DoubleNotEqualOrUnordered);
1027        RegisterID scr = claimScratch();
1028        m_assembler.loadConstant(0x7fbfffff, scratchReg3);
1029        m_assembler.dcnvds(right);
1030        m_assembler.stsfpulReg(scr);
1031        m_assembler.cmplRegReg(scratchReg3, scr, Equal);
1032        m_assembler.ensureSpace(m_assembler.maxInstructionSize + 22, sizeof(uint32_t));
1033        m_assembler.branch(BT_OPCODE, 5);
1034        m_assembler.dcnvds(left);
1035        m_assembler.stsfpulReg(scr);
1036        m_assembler.cmplRegReg(scratchReg3, scr, Equal);
1037        m_assembler.branch(BT_OPCODE, 1);
1038        m_assembler.dcmppeq(right, left);
1039        releaseScratch(scr);
1040        return branchFalse();
1041    }
1042
1043    Jump branchTrue()
1044    {
1045        m_assembler.ensureSpace(m_assembler.maxInstructionSize + 6, sizeof(uint32_t));
1046        Jump m_jump = Jump(m_assembler.je());
1047        m_assembler.loadConstantUnReusable(0x0, scratchReg3);
1048        m_assembler.nop();
1049        m_assembler.nop();
1050        return m_jump;
1051    }
1052
1053    Jump branchFalse()
1054    {
1055        m_assembler.ensureSpace(m_assembler.maxInstructionSize + 6, sizeof(uint32_t));
1056        Jump m_jump = Jump(m_assembler.jne());
1057        m_assembler.loadConstantUnReusable(0x0, scratchReg3);
1058        m_assembler.nop();
1059        m_assembler.nop();
1060        return m_jump;
1061    }
1062
1063    void set8Compare32(Condition cond, RegisterID left, RegisterID right, RegisterID dest)
1064    {
1065        set32Compare32(cond, left, right, dest);
1066    }
1067
1068    void set8Compare32(Condition cond, RegisterID left, TrustedImm32 right, RegisterID dest)
1069    {
1070        if (left != dest) {
1071            m_assembler.loadConstant(right.m_value, dest);
1072            set32Compare32(cond, left, dest, dest);
1073            return;
1074        }
1075
1076        RegisterID scr = claimScratch();
1077        m_assembler.loadConstant(right.m_value, scr);
1078        set32Compare32(cond, left, scr, dest);
1079        releaseScratch(scr);
1080    }
1081
1082    Jump branch32(Condition cond, BaseIndex left, TrustedImm32 right)
1083    {
1084        RegisterID scr = claimScratch();
1085        move(left.index, scr);
1086        lshift32(TrustedImm32(left.scale), scr);
1087        add32(left.base, scr);
1088        load32(scr, left.offset, scr);
1089        compare32(right.m_value, scr, cond);
1090        releaseScratch(scr);
1091
1092        if (cond == NotEqual)
1093            return branchFalse();
1094        return branchTrue();
1095    }
1096
1097    void sqrtDouble(FPRegisterID src, FPRegisterID dest)
1098    {
1099        if (dest != src)
1100            m_assembler.dmovRegReg(src, dest);
1101        m_assembler.dsqrt(dest);
1102    }
1103
1104    Jump branchTest8(Condition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
1105    {
1106        RegisterID addressTempRegister = claimScratch();
1107        load8(address, addressTempRegister);
1108        Jump jmp = branchTest32(cond, addressTempRegister, mask);
1109        releaseScratch(addressTempRegister);
1110        return jmp;
1111    }
1112
1113    void signExtend32ToPtr(RegisterID src, RegisterID dest)
1114    {
1115        if (src != dest)
1116            move(src, dest);
1117    }
1118
1119    Jump branch8(Condition cond, Address left, TrustedImm32 right)
1120    {
1121        RegisterID addressTempRegister = claimScratch();
1122        load8(left, addressTempRegister);
1123        Jump jmp = branch32(cond, addressTempRegister, right);
1124        releaseScratch(addressTempRegister);
1125        return jmp;
1126    }
1127
1128    Jump branchTruncateDoubleToInt32(FPRegisterID src, RegisterID dest)
1129    {
1130        m_assembler.ftrcdrmfpul(src);
1131        m_assembler.stsfpulReg(dest);
1132        m_assembler.loadConstant(0x7fffffff, scratchReg3);
1133        m_assembler.cmplRegReg(dest, scratchReg3, Equal);
1134        m_assembler.ensureSpace(m_assembler.maxInstructionSize + 14, sizeof(uint32_t));
1135        m_assembler.branch(BT_OPCODE, 2);
1136        m_assembler.addlImm8r(1, scratchReg3);
1137        m_assembler.cmplRegReg(dest, scratchReg3, Equal);
1138        return branchTrue();
1139    }
1140
1141    // Stack manipulation operations
1142
1143    void pop(RegisterID dest)
1144    {
1145        m_assembler.popReg(dest);
1146    }
1147
1148    void push(RegisterID src)
1149    {
1150        m_assembler.pushReg(src);
1151    }
1152
1153    void push(Address address)
1154    {
1155        if (!address.offset) {
1156            push(address.base);
1157            return;
1158        }
1159
1160        if ((address.offset < 0) || (address.offset >= 64)) {
1161            RegisterID scr = claimScratch();
1162            m_assembler.loadConstant(address.offset, scr);
1163            m_assembler.addlRegReg(address.base, scr);
1164            m_assembler.movlMemReg(scr, SH4Registers::sp);
1165            m_assembler.addlImm8r(-4, SH4Registers::sp);
1166            releaseScratch(scr);
1167            return;
1168        }
1169
1170        m_assembler.movlMemReg(address.offset >> 2, address.base, SH4Registers::sp);
1171        m_assembler.addlImm8r(-4, SH4Registers::sp);
1172    }
1173
1174    void push(TrustedImm32 imm)
1175    {
1176        RegisterID scr = claimScratch();
1177        m_assembler.loadConstant(imm.m_value, scr);
1178        push(scr);
1179        releaseScratch(scr);
1180    }
1181
1182    // Register move operations
1183
1184    void move(TrustedImm32 imm, RegisterID dest)
1185    {
1186        m_assembler.loadConstant(imm.m_value, dest);
1187    }
1188
1189    DataLabelPtr moveWithPatch(TrustedImmPtr initialValue, RegisterID dest)
1190    {
1191        DataLabelPtr dataLabel(this);
1192        m_assembler.loadConstantUnReusable(reinterpret_cast<uint32_t>(initialValue.m_value), dest, true);
1193        return dataLabel;
1194    }
1195
1196    void move(RegisterID src, RegisterID dest)
1197    {
1198        m_assembler.movlRegReg(src, dest);
1199    }
1200
1201    void move(TrustedImmPtr imm, RegisterID dest)
1202    {
1203        m_assembler.loadConstant(imm.asIntptr(), dest);
1204    }
1205
1206    void extuw(RegisterID src, RegisterID dst)
1207    {
1208        m_assembler.extuw(src, dst);
1209    }
1210
1211    void set32Compare32(Condition cond, RegisterID left, RegisterID right, RegisterID dest)
1212    {
1213        m_assembler.cmplRegReg(right, left, cond);
1214        if (cond != NotEqual) {
1215            m_assembler.movt(dest);
1216            return;
1217        }
1218
1219        m_assembler.ensureSpace(m_assembler.maxInstructionSize + 4);
1220        m_assembler.movImm8(0, dest);
1221        m_assembler.branch(BT_OPCODE, 0);
1222        m_assembler.movImm8(1, dest);
1223    }
1224
1225    void set32Compare32(Condition cond, RegisterID left, TrustedImm32 right, RegisterID dest)
1226    {
1227        if (left != dest) {
1228            move(right, dest);
1229            set32Compare32(cond, left, dest, dest);
1230            return;
1231        }
1232
1233        RegisterID scr = claimScratch();
1234        move(right, scr);
1235        set32Compare32(cond, left, scr, dest);
1236        releaseScratch(scr);
1237    }
1238
1239    void set32Test8(Condition cond, Address address, TrustedImm32 mask, RegisterID dest)
1240    {
1241        ASSERT((cond == Zero) || (cond == NonZero));
1242
1243        load8(address, dest);
1244        if (mask.m_value == -1)
1245            compare32(0, dest, cond);
1246        else
1247            testlImm(mask.m_value, dest);
1248        if (cond != NonZero) {
1249            m_assembler.movt(dest);
1250            return;
1251        }
1252
1253        m_assembler.ensureSpace(m_assembler.maxInstructionSize + 4);
1254        m_assembler.movImm8(0, dest);
1255        m_assembler.branch(BT_OPCODE, 0);
1256        m_assembler.movImm8(1, dest);
1257    }
1258
1259    void loadPtrLinkReg(ImplicitAddress address)
1260    {
1261        RegisterID scr = claimScratch();
1262        load32(address, scr);
1263        m_assembler.ldspr(scr);
1264        releaseScratch(scr);
1265    }
1266
1267    Jump branch32(Condition cond, RegisterID left, RegisterID right)
1268    {
1269        m_assembler.cmplRegReg(right, left, cond);
1270        /* BT label => BF off
1271           nop         LDR reg
1272           nop         braf @reg
1273           nop         nop
1274         */
1275        if (cond == NotEqual)
1276            return branchFalse();
1277        return branchTrue();
1278    }
1279
1280    Jump branch32(Condition cond, RegisterID left, TrustedImm32 right)
1281    {
1282        if (((cond == Equal) || (cond == NotEqual)) && !right.m_value)
1283            m_assembler.testlRegReg(left, left);
1284        else
1285            compare32(right.m_value, left, cond);
1286
1287        if (cond == NotEqual)
1288            return branchFalse();
1289        return branchTrue();
1290    }
1291
1292    Jump branch32(Condition cond, RegisterID left, Address right)
1293    {
1294        compare32(right.offset, right.base, left, cond);
1295        if (cond == NotEqual)
1296            return branchFalse();
1297        return branchTrue();
1298    }
1299
1300    Jump branch32(Condition cond, Address left, RegisterID right)
1301    {
1302        compare32(right, left.offset, left.base, cond);
1303        if (cond == NotEqual)
1304            return branchFalse();
1305        return branchTrue();
1306    }
1307
1308    Jump branch32(Condition cond, Address left, TrustedImm32 right)
1309    {
1310        compare32(right.m_value, left.offset, left.base, cond);
1311        if (cond == NotEqual)
1312            return branchFalse();
1313        return branchTrue();
1314    }
1315
1316    Jump branch32(Condition cond, AbsoluteAddress left, RegisterID right)
1317    {
1318        RegisterID scr = claimScratch();
1319
1320        move(TrustedImm32(reinterpret_cast<uint32_t>(left.m_ptr)), scr);
1321        m_assembler.cmplRegReg(right, scr, cond);
1322        releaseScratch(scr);
1323
1324        if (cond == NotEqual)
1325            return branchFalse();
1326        return branchTrue();
1327    }
1328
1329    Jump branch32(Condition cond, AbsoluteAddress left, TrustedImm32 right)
1330    {
1331        RegisterID addressTempRegister = claimScratch();
1332
1333        m_assembler.loadConstant(reinterpret_cast<uint32_t>(left.m_ptr), addressTempRegister);
1334        m_assembler.movlMemReg(addressTempRegister, addressTempRegister);
1335        compare32(right.m_value, addressTempRegister, cond);
1336        releaseScratch(addressTempRegister);
1337
1338        if (cond == NotEqual)
1339            return branchFalse();
1340        return branchTrue();
1341    }
1342
1343    Jump branch16(Condition cond,  BaseIndex left, RegisterID right)
1344    {
1345        RegisterID scr = claimScratch();
1346
1347        move(left.index, scr);
1348        lshift32(TrustedImm32(left.scale), scr);
1349
1350        if (left.offset)
1351            add32(TrustedImm32(left.offset), scr);
1352        add32(left.base, scr);
1353        load16(scr, scr);
1354        extuw(scr, scr);
1355        releaseScratch(scr);
1356
1357        return branch32(cond, scr, right);
1358    }
1359
1360    Jump branch16(Condition cond, BaseIndex left, TrustedImm32 right)
1361    {
1362        RegisterID scr = claimScratch();
1363
1364        move(left.index, scr);
1365        lshift32(TrustedImm32(left.scale), scr);
1366
1367        if (left.offset)
1368            add32(TrustedImm32(left.offset), scr);
1369        add32(left.base, scr);
1370        load16(scr, scr);
1371        extuw(scr, scr);
1372        RegisterID scr1 = claimScratch();
1373        m_assembler.loadConstant(right.m_value, scr1);
1374        releaseScratch(scr);
1375        releaseScratch(scr1);
1376
1377        return branch32(cond, scr, scr1);
1378    }
1379
1380    Jump branchTest32(Condition cond, RegisterID reg, RegisterID mask)
1381    {
1382        ASSERT((cond == Zero) || (cond == NonZero));
1383
1384        m_assembler.testlRegReg(reg, mask);
1385
1386        if (cond == NotEqual)
1387            return branchFalse();
1388        return branchTrue();
1389    }
1390
1391    Jump branchTest32(Condition cond, RegisterID reg, TrustedImm32 mask = TrustedImm32(-1))
1392    {
1393        ASSERT((cond == Zero) || (cond == NonZero));
1394
1395        if (mask.m_value == -1)
1396            m_assembler.testlRegReg(reg, reg);
1397        else
1398            testlImm(mask.m_value, reg);
1399
1400        if (cond == NotEqual)
1401            return branchFalse();
1402        return branchTrue();
1403    }
1404
1405    Jump branchTest32(Condition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
1406    {
1407        ASSERT((cond == Zero) || (cond == NonZero));
1408
1409        if (mask.m_value == -1)
1410            compare32(0, address.offset, address.base, cond);
1411        else
1412            testImm(mask.m_value, address.offset, address.base);
1413
1414        if (cond == NotEqual)
1415            return branchFalse();
1416        return branchTrue();
1417    }
1418
1419    Jump branchTest32(Condition cond, BaseIndex address, TrustedImm32 mask = TrustedImm32(-1))
1420    {
1421        RegisterID scr = claimScratch();
1422
1423        move(address.index, scr);
1424        lshift32(TrustedImm32(address.scale), scr);
1425        add32(address.base, scr);
1426        load32(scr, address.offset, scr);
1427
1428        if (mask.m_value == -1)
1429            m_assembler.testlRegReg(scr, scr);
1430        else
1431            testlImm(mask.m_value, scr);
1432
1433        releaseScratch(scr);
1434
1435        if (cond == NotEqual)
1436            return branchFalse();
1437        return branchTrue();
1438    }
1439
1440    Jump jump()
1441    {
1442        return Jump(m_assembler.jmp());
1443    }
1444
1445    void jump(RegisterID target)
1446    {
1447        m_assembler.jmpReg(target);
1448    }
1449
1450    void jump(Address address)
1451    {
1452        RegisterID scr = claimScratch();
1453
1454        if ((address.offset < 0) || (address.offset >= 64)) {
1455            m_assembler.loadConstant(address.offset, scr);
1456            m_assembler.addlRegReg(address.base, scr);
1457            m_assembler.movlMemReg(scr, scr);
1458        } else if (address.offset)
1459            m_assembler.movlMemReg(address.offset >> 2, address.base, scr);
1460        else
1461            m_assembler.movlMemReg(address.base, scr);
1462        m_assembler.jmpReg(scr);
1463
1464        releaseScratch(scr);
1465    }
1466
1467    // Arithmetic control flow operations
1468
1469    Jump branchAdd32(Condition cond, RegisterID src, RegisterID dest)
1470    {
1471        ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
1472
1473        if (cond == Overflow) {
1474            m_assembler.addvlRegReg(src, dest);
1475            return branchTrue();
1476        }
1477
1478        if (cond == Signed) {
1479            m_assembler.addlRegReg(src, dest);
1480            // Check if dest is negative
1481            m_assembler.cmppz(dest);
1482            return branchFalse();
1483        }
1484
1485        m_assembler.addlRegReg(src, dest);
1486        compare32(0, dest, Equal);
1487
1488        if (cond == NotEqual)
1489            return branchFalse();
1490        return branchTrue();
1491    }
1492
1493    Jump branchAdd32(Condition cond, TrustedImm32 imm, RegisterID dest)
1494    {
1495        ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
1496
1497        move(imm, scratchReg3);
1498        return branchAdd32(cond, scratchReg3, dest);
1499    }
1500
1501    Jump branchMul32(Condition cond, RegisterID src, RegisterID dest)
1502    {
1503        ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
1504
1505        if (cond == Overflow) {
1506            RegisterID scr1 = claimScratch();
1507            RegisterID scr = claimScratch();
1508            m_assembler.dmullRegReg(src, dest);
1509            m_assembler.stsmacl(dest);
1510            m_assembler.movImm8(-31, scr);
1511            m_assembler.movlRegReg(dest, scr1);
1512            m_assembler.shaRegReg(scr1, scr);
1513            m_assembler.stsmach(scr);
1514            m_assembler.cmplRegReg(scr, scr1, Zero);
1515            releaseScratch(scr1);
1516            releaseScratch(scr);
1517            return branchFalse();
1518        }
1519
1520        m_assembler.imullRegReg(src, dest);
1521        m_assembler.stsmacl(dest);
1522        if (cond == Signed) {
1523            // Check if dest is negative
1524            m_assembler.cmppz(dest);
1525            return branchFalse();
1526        }
1527
1528        compare32(0, dest, cond);
1529
1530        if (cond == NotEqual)
1531            return branchFalse();
1532        return branchTrue();
1533    }
1534
1535    Jump branchMul32(Condition cond, TrustedImm32 imm, RegisterID src, RegisterID dest)
1536    {
1537        ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
1538
1539        move(imm, scratchReg3);
1540        if (src != dest)
1541            move(src, dest);
1542
1543        return branchMul32(cond, scratchReg3, dest);
1544    }
1545
1546    Jump branchSub32(Condition cond, RegisterID src, RegisterID dest)
1547    {
1548        ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
1549
1550        if (cond == Overflow) {
1551            m_assembler.subvlRegReg(src, dest);
1552            return branchTrue();
1553        }
1554
1555        if (cond == Signed) {
1556            // Check if dest is negative
1557            m_assembler.sublRegReg(src, dest);
1558            compare32(0, dest, LessThan);
1559            return branchTrue();
1560        }
1561
1562        sub32(src, dest);
1563        compare32(0, dest, cond);
1564
1565        if (cond == NotEqual)
1566            return branchFalse();
1567        return branchTrue();
1568    }
1569
1570    Jump branchSub32(Condition cond, TrustedImm32 imm, RegisterID dest)
1571    {
1572        ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
1573
1574        move(imm, scratchReg3);
1575        return branchSub32(cond, scratchReg3, dest);
1576    }
1577
1578    Jump branchOr32(Condition cond, RegisterID src, RegisterID dest)
1579    {
1580        ASSERT((cond == Signed) || (cond == Zero) || (cond == NonZero));
1581
1582        if (cond == Signed) {
1583            or32(src, dest);
1584            compare32(0, dest, LessThan);
1585            return branchTrue();
1586        }
1587
1588        or32(src, dest);
1589        compare32(0, dest, cond);
1590
1591        if (cond == NotEqual)
1592            return branchFalse();
1593        return branchTrue();
1594    }
1595
1596    void branchConvertDoubleToInt32(FPRegisterID src, RegisterID dest, JumpList& failureCases, FPRegisterID fpTemp)
1597    {
1598        m_assembler.ftrcdrmfpul(src);
1599        m_assembler.stsfpulReg(dest);
1600        convertInt32ToDouble(dest, fscratch);
1601        failureCases.append(branchDouble(DoubleNotEqualOrUnordered, fscratch, src));
1602
1603        if (dest == SH4Registers::r0)
1604            m_assembler.cmpEqImmR0(0, dest, Equal);
1605        else {
1606            m_assembler.movImm8(0, scratchReg3);
1607            m_assembler.cmplRegReg(scratchReg3, dest, Equal);
1608        }
1609        failureCases.append(branchTrue());
1610    }
1611
1612    void neg32(RegisterID dst)
1613    {
1614        m_assembler.neg(dst, dst);
1615    }
1616
1617    void not32(RegisterID dst)
1618    {
1619        m_assembler.notlReg(dst, dst);
1620    }
1621
1622    void urshift32(RegisterID shiftamount, RegisterID dest)
1623    {
1624        compare32(32, shiftamount, Equal);
1625        m_assembler.ensureSpace(m_assembler.maxInstructionSize + 4);
1626        m_assembler.branch(BT_OPCODE, 1);
1627        m_assembler.neg(shiftamount, shiftamount);
1628        m_assembler.shllRegReg(dest, shiftamount);
1629    }
1630
1631    void urshift32(TrustedImm32 imm, RegisterID dest)
1632    {
1633        RegisterID scr = claimScratch();
1634        m_assembler.loadConstant(-(imm.m_value), scr);
1635        m_assembler.shaRegReg(dest, scr);
1636        releaseScratch(scr);
1637    }
1638
1639    Call call()
1640    {
1641        return Call(m_assembler.call(), Call::Linkable);
1642    }
1643
1644    Call nearCall()
1645    {
1646        return Call(m_assembler.call(), Call::LinkableNear);
1647    }
1648
1649    Call call(RegisterID target)
1650    {
1651        return Call(m_assembler.call(target), Call::None);
1652    }
1653
1654    void call(Address address, RegisterID target)
1655    {
1656        load32(address.base, address.offset, target);
1657        m_assembler.ensureSpace(m_assembler.maxInstructionSize + 2);
1658        m_assembler.branch(JSR_OPCODE, target);
1659        m_assembler.nop();
1660    }
1661
1662    void breakpoint()
1663    {
1664        m_assembler.bkpt();
1665        m_assembler.nop();
1666    }
1667
1668    Jump branchPtrWithPatch(Condition cond, RegisterID left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
1669    {
1670        RegisterID dataTempRegister = claimScratch();
1671
1672        dataLabel = moveWithPatch(initialRightValue, dataTempRegister);
1673        m_assembler.cmplRegReg(dataTempRegister, left, cond);
1674        releaseScratch(dataTempRegister);
1675
1676        if (cond == NotEqual)
1677            return branchFalse();
1678        return branchTrue();
1679    }
1680
1681    Jump branchPtrWithPatch(Condition cond, Address left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
1682    {
1683        RegisterID scr = claimScratch();
1684
1685        m_assembler.loadConstant(left.offset, scr);
1686        m_assembler.addlRegReg(left.base, scr);
1687        m_assembler.movlMemReg(scr, scr);
1688        RegisterID scr1 = claimScratch();
1689        dataLabel = moveWithPatch(initialRightValue, scr1);
1690        m_assembler.cmplRegReg(scr1, scr, cond);
1691        releaseScratch(scr);
1692        releaseScratch(scr1);
1693
1694        if (cond == NotEqual)
1695            return branchFalse();
1696        return branchTrue();
1697    }
1698
1699    void ret()
1700    {
1701        m_assembler.ret();
1702        m_assembler.nop();
1703    }
1704
1705    DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address)
1706    {
1707        RegisterID scr = claimScratch();
1708        DataLabelPtr label = moveWithPatch(initialValue, scr);
1709        store32(scr, address);
1710        releaseScratch(scr);
1711        return label;
1712    }
1713
1714    DataLabelPtr storePtrWithPatch(ImplicitAddress address) { return storePtrWithPatch(TrustedImmPtr(0), address); }
1715
1716    int sizeOfConstantPool()
1717    {
1718        return m_assembler.sizeOfConstantPool();
1719    }
1720
1721    Call tailRecursiveCall()
1722    {
1723        RegisterID scr = claimScratch();
1724
1725        m_assembler.loadConstantUnReusable(0x0, scr, true);
1726        Jump m_jump = Jump(m_assembler.jmp(scr));
1727        releaseScratch(scr);
1728
1729        return Call::fromTailJump(m_jump);
1730    }
1731
1732    Call makeTailRecursiveCall(Jump oldJump)
1733    {
1734        oldJump.link(this);
1735        return tailRecursiveCall();
1736    }
1737
1738private:
1739    friend class LinkBuffer;
1740    friend class RepatchBuffer;
1741
1742    static void linkCall(void*, Call, FunctionPtr);
1743    static void repatchCall(CodeLocationCall, CodeLocationLabel);
1744    static void repatchCall(CodeLocationCall, FunctionPtr);
1745};
1746
1747} // namespace JSC
1748
1749#endif // ENABLE(ASSEMBLER)
1750
1751#endif // MacroAssemblerSH4_h
1752