1/*
2 * Copyright (C) 2008 Apple Inc. All rights reserved.
3 * Copyright (C) 2010 MIPS Technologies, 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 MIPS TECHNOLOGIES, 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 MIPS TECHNOLOGIES, 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 MacroAssemblerMIPS_h
28#define MacroAssemblerMIPS_h
29
30#if ENABLE(ASSEMBLER) && CPU(MIPS)
31
32#include "AbstractMacroAssembler.h"
33#include "MIPSAssembler.h"
34
35namespace JSC {
36
37class MacroAssemblerMIPS : public AbstractMacroAssembler<MIPSAssembler> {
38public:
39    typedef MIPSRegisters::FPRegisterID FPRegisterID;
40
41    MacroAssemblerMIPS()
42        : m_fixedWidth(false)
43    {
44    }
45
46    static bool isCompactPtrAlignedAddressOffset(ptrdiff_t value)
47    {
48        return value >= -2147483647 - 1 && value <= 2147483647;
49    }
50
51    static const Scale ScalePtr = TimesFour;
52
53    // For storing immediate number
54    static const RegisterID immTempRegister = MIPSRegisters::t0;
55    // For storing data loaded from the memory
56    static const RegisterID dataTempRegister = MIPSRegisters::t1;
57    // For storing address base
58    static const RegisterID addrTempRegister = MIPSRegisters::t2;
59    // For storing compare result
60    static const RegisterID cmpTempRegister = MIPSRegisters::t3;
61
62    // FP temp register
63    static const FPRegisterID fpTempRegister = MIPSRegisters::f16;
64
65    static const int MaximumCompactPtrAlignedAddressOffset = 0x7FFFFFFF;
66
67    enum RelationalCondition {
68        Equal,
69        NotEqual,
70        Above,
71        AboveOrEqual,
72        Below,
73        BelowOrEqual,
74        GreaterThan,
75        GreaterThanOrEqual,
76        LessThan,
77        LessThanOrEqual
78    };
79
80    enum ResultCondition {
81        Overflow,
82        Signed,
83        PositiveOrZero,
84        Zero,
85        NonZero
86    };
87
88    enum DoubleCondition {
89        DoubleEqual,
90        DoubleNotEqual,
91        DoubleGreaterThan,
92        DoubleGreaterThanOrEqual,
93        DoubleLessThan,
94        DoubleLessThanOrEqual,
95        DoubleEqualOrUnordered,
96        DoubleNotEqualOrUnordered,
97        DoubleGreaterThanOrUnordered,
98        DoubleGreaterThanOrEqualOrUnordered,
99        DoubleLessThanOrUnordered,
100        DoubleLessThanOrEqualOrUnordered
101    };
102
103    static const RegisterID stackPointerRegister = MIPSRegisters::sp;
104    static const RegisterID returnAddressRegister = MIPSRegisters::ra;
105
106    // Integer arithmetic operations:
107    //
108    // Operations are typically two operand - operation(source, srcDst)
109    // For many operations the source may be an TrustedImm32, the srcDst operand
110    // may often be a memory location (explictly described using an Address
111    // object).
112
113    void add32(RegisterID src, RegisterID dest)
114    {
115        m_assembler.addu(dest, dest, src);
116    }
117
118    void add32(RegisterID op1, RegisterID op2, RegisterID dest)
119    {
120        m_assembler.addu(dest, op1, op2);
121    }
122
123    void add32(TrustedImm32 imm, RegisterID dest)
124    {
125        add32(imm, dest, dest);
126    }
127
128    void add32(TrustedImm32 imm, RegisterID src, RegisterID dest)
129    {
130        if (imm.m_value >= -32768 && imm.m_value <= 32767
131            && !m_fixedWidth) {
132            /*
133              addiu     dest, src, imm
134            */
135            m_assembler.addiu(dest, src, imm.m_value);
136        } else {
137            /*
138              li        immTemp, imm
139              addu      dest, src, immTemp
140            */
141            move(imm, immTempRegister);
142            m_assembler.addu(dest, src, immTempRegister);
143        }
144    }
145
146    void add32(RegisterID src, TrustedImm32 imm, RegisterID dest)
147    {
148        add32(imm, src, dest);
149    }
150
151    void add32(TrustedImm32 imm, Address address)
152    {
153        if (address.offset >= -32768 && address.offset <= 32767
154            && !m_fixedWidth) {
155            /*
156              lw        dataTemp, offset(base)
157              li        immTemp, imm
158              addu      dataTemp, dataTemp, immTemp
159              sw        dataTemp, offset(base)
160            */
161            m_assembler.lw(dataTempRegister, address.base, address.offset);
162            if (imm.m_value >= -32768 && imm.m_value <= 32767
163                && !m_fixedWidth)
164                m_assembler.addiu(dataTempRegister, dataTempRegister, imm.m_value);
165            else {
166                move(imm, immTempRegister);
167                m_assembler.addu(dataTempRegister, dataTempRegister, immTempRegister);
168            }
169            m_assembler.sw(dataTempRegister, address.base, address.offset);
170        } else {
171            /*
172              lui       addrTemp, (offset + 0x8000) >> 16
173              addu      addrTemp, addrTemp, base
174              lw        dataTemp, (offset & 0xffff)(addrTemp)
175              li        immtemp, imm
176              addu      dataTemp, dataTemp, immTemp
177              sw        dataTemp, (offset & 0xffff)(addrTemp)
178            */
179            m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16);
180            m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
181            m_assembler.lw(dataTempRegister, addrTempRegister, address.offset);
182
183            if (imm.m_value >= -32768 && imm.m_value <= 32767 && !m_fixedWidth)
184                m_assembler.addiu(dataTempRegister, dataTempRegister, imm.m_value);
185            else {
186                move(imm, immTempRegister);
187                m_assembler.addu(dataTempRegister, dataTempRegister, immTempRegister);
188            }
189            m_assembler.sw(dataTempRegister, addrTempRegister, address.offset);
190        }
191    }
192
193    void add32(Address src, RegisterID dest)
194    {
195        load32(src, dataTempRegister);
196        add32(dataTempRegister, dest);
197    }
198
199    void add32(AbsoluteAddress src, RegisterID dest)
200    {
201        load32(src.m_ptr, dataTempRegister);
202        add32(dataTempRegister, dest);
203    }
204
205    void add32(RegisterID src, Address dest)
206    {
207        if (dest.offset >= -32768 && dest.offset <= 32767 && !m_fixedWidth) {
208            /*
209              lw        dataTemp, offset(base)
210              addu      dataTemp, dataTemp, src
211              sw        dataTemp, offset(base)
212            */
213            m_assembler.lw(dataTempRegister, dest.base, dest.offset);
214            m_assembler.addu(dataTempRegister, dataTempRegister, src);
215            m_assembler.sw(dataTempRegister, dest.base, dest.offset);
216        } else {
217            /*
218              lui       addrTemp, (offset + 0x8000) >> 16
219              addu      addrTemp, addrTemp, base
220              lw        dataTemp, (offset & 0xffff)(addrTemp)
221              addu      dataTemp, dataTemp, src
222              sw        dataTemp, (offset & 0xffff)(addrTemp)
223            */
224            m_assembler.lui(addrTempRegister, (dest.offset + 0x8000) >> 16);
225            m_assembler.addu(addrTempRegister, addrTempRegister, dest.base);
226            m_assembler.lw(dataTempRegister, addrTempRegister, dest.offset);
227            m_assembler.addu(dataTempRegister, dataTempRegister, src);
228            m_assembler.sw(dataTempRegister, addrTempRegister, dest.offset);
229        }
230    }
231
232    void add32(TrustedImm32 imm, AbsoluteAddress address)
233    {
234        /*
235           li   addrTemp, address
236           li   immTemp, imm
237           lw   cmpTemp, 0(addrTemp)
238           addu dataTemp, cmpTemp, immTemp
239           sw   dataTemp, 0(addrTemp)
240        */
241        move(TrustedImmPtr(address.m_ptr), addrTempRegister);
242        m_assembler.lw(cmpTempRegister, addrTempRegister, 0);
243        if (imm.m_value >= -32768 && imm.m_value <= 32767 && !m_fixedWidth)
244            m_assembler.addiu(dataTempRegister, cmpTempRegister, imm.m_value);
245        else {
246            move(imm, immTempRegister);
247            m_assembler.addu(dataTempRegister, cmpTempRegister, immTempRegister);
248        }
249        m_assembler.sw(dataTempRegister, addrTempRegister, 0);
250    }
251
252    void add64(TrustedImm32 imm, AbsoluteAddress address)
253    {
254        /*
255            add32(imm, address)
256            sltu  immTemp, dataTemp, cmpTemp    # set carry-in bit
257            lw    dataTemp, 4(addrTemp)
258            addiu dataTemp, imm.m_value >> 31 ? -1 : 0
259            addu  dataTemp, dataTemp, immTemp
260            sw    dataTemp, 4(addrTemp)
261        */
262        add32(imm, address);
263        m_assembler.sltu(immTempRegister, dataTempRegister, cmpTempRegister);
264        m_assembler.lw(dataTempRegister, addrTempRegister, 4);
265        if (imm.m_value >> 31)
266            m_assembler.addiu(dataTempRegister, dataTempRegister, -1);
267        m_assembler.addu(dataTempRegister, dataTempRegister, immTempRegister);
268        m_assembler.sw(dataTempRegister, addrTempRegister, 4);
269    }
270
271    void and32(Address src, RegisterID dest)
272    {
273        load32(src, dataTempRegister);
274        and32(dataTempRegister, dest);
275    }
276
277    void and32(RegisterID src, RegisterID dest)
278    {
279        m_assembler.andInsn(dest, dest, src);
280    }
281
282    void and32(RegisterID op1, RegisterID op2, RegisterID dest)
283    {
284        m_assembler.andInsn(dest, op1, op2);
285    }
286
287    void and32(TrustedImm32 imm, RegisterID dest)
288    {
289        if (!imm.m_value && !m_fixedWidth)
290            move(MIPSRegisters::zero, dest);
291        else if (imm.m_value > 0 && imm.m_value < 65535 && !m_fixedWidth)
292            m_assembler.andi(dest, dest, imm.m_value);
293        else {
294            /*
295              li        immTemp, imm
296              and       dest, dest, immTemp
297            */
298            move(imm, immTempRegister);
299            m_assembler.andInsn(dest, dest, immTempRegister);
300        }
301    }
302
303    void and32(TrustedImm32 imm, RegisterID src, RegisterID dest)
304    {
305        if (!imm.m_value && !m_fixedWidth)
306            move(MIPSRegisters::zero, dest);
307        else if (imm.m_value > 0 && imm.m_value < 65535 && !m_fixedWidth)
308            m_assembler.andi(dest, src, imm.m_value);
309        else {
310            move(imm, immTempRegister);
311            m_assembler.andInsn(dest, src, immTempRegister);
312        }
313    }
314
315    void lshift32(RegisterID shiftAmount, RegisterID dest)
316    {
317        m_assembler.sllv(dest, dest, shiftAmount);
318    }
319
320    void lshift32(RegisterID src, RegisterID shiftAmount, RegisterID dest)
321    {
322        m_assembler.sllv(dest, src, shiftAmount);
323    }
324
325    void lshift32(TrustedImm32 imm, RegisterID dest)
326    {
327        move(imm, immTempRegister);
328        m_assembler.sllv(dest, dest, immTempRegister);
329    }
330
331    void lshift32(RegisterID src, TrustedImm32 imm, RegisterID dest)
332    {
333        move(imm, immTempRegister);
334        m_assembler.sllv(dest, src, immTempRegister);
335    }
336
337    void mul32(RegisterID src, RegisterID dest)
338    {
339        m_assembler.mul(dest, dest, src);
340    }
341
342    void mul32(RegisterID op1, RegisterID op2, RegisterID dest)
343    {
344        m_assembler.mul(dest, op1, op2);
345    }
346
347    void mul32(TrustedImm32 imm, RegisterID src, RegisterID dest)
348    {
349        if (!imm.m_value && !m_fixedWidth)
350            move(MIPSRegisters::zero, dest);
351        else if (imm.m_value == 1 && !m_fixedWidth)
352            move(src, dest);
353        else {
354            /*
355                li      dataTemp, imm
356                mul     dest, src, dataTemp
357            */
358            move(imm, dataTempRegister);
359            m_assembler.mul(dest, src, dataTempRegister);
360        }
361    }
362
363    void neg32(RegisterID srcDest)
364    {
365        m_assembler.subu(srcDest, MIPSRegisters::zero, srcDest);
366    }
367
368    void or32(RegisterID src, RegisterID dest)
369    {
370        m_assembler.orInsn(dest, dest, src);
371    }
372
373    void or32(RegisterID op1, RegisterID op2, RegisterID dest)
374    {
375        m_assembler.orInsn(dest, op1, op2);
376    }
377
378    void or32(TrustedImm32 imm, RegisterID dest)
379    {
380        if (!imm.m_value && !m_fixedWidth)
381            return;
382
383        if (imm.m_value > 0 && imm.m_value < 65535
384            && !m_fixedWidth) {
385            m_assembler.ori(dest, dest, imm.m_value);
386            return;
387        }
388
389        /*
390            li      dataTemp, imm
391            or      dest, dest, dataTemp
392        */
393        move(imm, dataTempRegister);
394        m_assembler.orInsn(dest, dest, dataTempRegister);
395    }
396
397    void or32(TrustedImm32 imm, RegisterID src, RegisterID dest)
398    {
399        if (!imm.m_value && !m_fixedWidth)
400            return;
401
402        if (imm.m_value > 0 && imm.m_value < 65535 && !m_fixedWidth) {
403            m_assembler.ori(dest, src, imm.m_value);
404            return;
405        }
406
407        /*
408            li      dataTemp, imm
409            or      dest, src, dataTemp
410        */
411        move(imm, dataTempRegister);
412        m_assembler.orInsn(dest, src, dataTempRegister);
413    }
414
415    void or32(RegisterID src, AbsoluteAddress dest)
416    {
417        load32(dest.m_ptr, dataTempRegister);
418        m_assembler.orInsn(dataTempRegister, dataTempRegister, src);
419        store32(dataTempRegister, dest.m_ptr);
420    }
421
422    void rshift32(RegisterID shiftAmount, RegisterID dest)
423    {
424        m_assembler.srav(dest, dest, shiftAmount);
425    }
426
427    void rshift32(RegisterID src, RegisterID shiftAmount, RegisterID dest)
428    {
429        m_assembler.srav(dest, src, shiftAmount);
430    }
431
432    void rshift32(TrustedImm32 imm, RegisterID dest)
433    {
434        m_assembler.sra(dest, dest, imm.m_value);
435    }
436
437    void rshift32(RegisterID src, TrustedImm32 imm, RegisterID dest)
438    {
439        m_assembler.sra(dest, src, imm.m_value);
440    }
441
442    void urshift32(RegisterID shiftAmount, RegisterID dest)
443    {
444        m_assembler.srlv(dest, dest, shiftAmount);
445    }
446
447    void urshift32(RegisterID src, RegisterID shiftAmount, RegisterID dest)
448    {
449        m_assembler.srlv(dest, src, shiftAmount);
450    }
451
452    void urshift32(TrustedImm32 imm, RegisterID dest)
453    {
454        m_assembler.srl(dest, dest, imm.m_value);
455    }
456
457    void urshift32(RegisterID src, TrustedImm32 imm, RegisterID dest)
458    {
459        m_assembler.srl(dest, src, imm.m_value);
460    }
461
462    void sub32(RegisterID src, RegisterID dest)
463    {
464        m_assembler.subu(dest, dest, src);
465    }
466
467    void sub32(RegisterID op1, RegisterID op2, RegisterID dest)
468    {
469        m_assembler.subu(dest, op1, op2);
470    }
471
472    void sub32(TrustedImm32 imm, RegisterID dest)
473    {
474        if (imm.m_value >= -32767 && imm.m_value <= 32768
475            && !m_fixedWidth) {
476            /*
477              addiu     dest, src, imm
478            */
479            m_assembler.addiu(dest, dest, -imm.m_value);
480        } else {
481            /*
482              li        immTemp, imm
483              subu      dest, src, immTemp
484            */
485            move(imm, immTempRegister);
486            m_assembler.subu(dest, dest, immTempRegister);
487        }
488    }
489
490    void sub32(RegisterID src, TrustedImm32 imm, RegisterID dest)
491    {
492        if (imm.m_value >= -32767 && imm.m_value <= 32768
493            && !m_fixedWidth) {
494            /*
495              addiu     dest, src, imm
496            */
497            m_assembler.addiu(dest, src, -imm.m_value);
498        } else {
499            /*
500              li        immTemp, imm
501              subu      dest, src, immTemp
502            */
503            move(imm, immTempRegister);
504            m_assembler.subu(dest, src, immTempRegister);
505        }
506    }
507
508    void sub32(TrustedImm32 imm, Address address)
509    {
510        if (address.offset >= -32768 && address.offset <= 32767
511            && !m_fixedWidth) {
512            /*
513              lw        dataTemp, offset(base)
514              li        immTemp, imm
515              subu      dataTemp, dataTemp, immTemp
516              sw        dataTemp, offset(base)
517            */
518            m_assembler.lw(dataTempRegister, address.base, address.offset);
519            if (imm.m_value >= -32767 && imm.m_value <= 32768 && !m_fixedWidth)
520                m_assembler.addiu(dataTempRegister, dataTempRegister, -imm.m_value);
521            else {
522                move(imm, immTempRegister);
523                m_assembler.subu(dataTempRegister, dataTempRegister, immTempRegister);
524            }
525            m_assembler.sw(dataTempRegister, address.base, address.offset);
526        } else {
527            /*
528              lui       addrTemp, (offset + 0x8000) >> 16
529              addu      addrTemp, addrTemp, base
530              lw        dataTemp, (offset & 0xffff)(addrTemp)
531              li        immtemp, imm
532              subu      dataTemp, dataTemp, immTemp
533              sw        dataTemp, (offset & 0xffff)(addrTemp)
534            */
535            m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16);
536            m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
537            m_assembler.lw(dataTempRegister, addrTempRegister, address.offset);
538
539            if (imm.m_value >= -32767 && imm.m_value <= 32768
540                && !m_fixedWidth)
541                m_assembler.addiu(dataTempRegister, dataTempRegister, -imm.m_value);
542            else {
543                move(imm, immTempRegister);
544                m_assembler.subu(dataTempRegister, dataTempRegister, immTempRegister);
545            }
546            m_assembler.sw(dataTempRegister, addrTempRegister, address.offset);
547        }
548    }
549
550    void sub32(Address src, RegisterID dest)
551    {
552        load32(src, dataTempRegister);
553        sub32(dataTempRegister, dest);
554    }
555
556    void sub32(TrustedImm32 imm, AbsoluteAddress address)
557    {
558        /*
559           li   addrTemp, address
560           li   immTemp, imm
561           lw   dataTemp, 0(addrTemp)
562           subu dataTemp, dataTemp, immTemp
563           sw   dataTemp, 0(addrTemp)
564        */
565        move(TrustedImmPtr(address.m_ptr), addrTempRegister);
566        m_assembler.lw(dataTempRegister, addrTempRegister, 0);
567
568        if (imm.m_value >= -32767 && imm.m_value <= 32768 && !m_fixedWidth)
569            m_assembler.addiu(dataTempRegister, dataTempRegister, -imm.m_value);
570        else {
571            move(imm, immTempRegister);
572            m_assembler.subu(dataTempRegister, dataTempRegister, immTempRegister);
573        }
574        m_assembler.sw(dataTempRegister, addrTempRegister, 0);
575    }
576
577    void xor32(RegisterID src, RegisterID dest)
578    {
579        m_assembler.xorInsn(dest, dest, src);
580    }
581
582    void xor32(RegisterID op1, RegisterID op2, RegisterID dest)
583    {
584        m_assembler.xorInsn(dest, op1, op2);
585    }
586
587    void xor32(TrustedImm32 imm, RegisterID dest)
588    {
589        if (imm.m_value == -1) {
590            m_assembler.nor(dest, dest, MIPSRegisters::zero);
591            return;
592        }
593
594        /*
595            li  immTemp, imm
596            xor dest, dest, immTemp
597        */
598        move(imm, immTempRegister);
599        m_assembler.xorInsn(dest, dest, immTempRegister);
600    }
601
602    void xor32(TrustedImm32 imm, RegisterID src, RegisterID dest)
603    {
604        if (imm.m_value == -1) {
605            m_assembler.nor(dest, src, MIPSRegisters::zero);
606            return;
607        }
608
609        /*
610            li  immTemp, imm
611            xor dest, dest, immTemp
612        */
613        move(imm, immTempRegister);
614        m_assembler.xorInsn(dest, src, immTempRegister);
615    }
616
617    void sqrtDouble(FPRegisterID src, FPRegisterID dst)
618    {
619        m_assembler.sqrtd(dst, src);
620    }
621
622    void absDouble(FPRegisterID, FPRegisterID)
623    {
624        RELEASE_ASSERT_NOT_REACHED();
625    }
626
627    ConvertibleLoadLabel convertibleLoadPtr(Address address, RegisterID dest)
628    {
629        ConvertibleLoadLabel result(this);
630        /*
631            lui     addrTemp, (offset + 0x8000) >> 16
632            addu    addrTemp, addrTemp, base
633            lw      dest, (offset & 0xffff)(addrTemp)
634        */
635        m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16);
636        m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
637        m_assembler.lw(dest, addrTempRegister, address.offset);
638        return result;
639    }
640
641    // Memory access operations:
642    //
643    // Loads are of the form load(address, destination) and stores of the form
644    // store(source, address). The source for a store may be an TrustedImm32. Address
645    // operand objects to loads and store will be implicitly constructed if a
646    // register is passed.
647
648    /* Need to use zero-extened load byte for load8.  */
649    void load8(ImplicitAddress address, RegisterID dest)
650    {
651        if (address.offset >= -32768 && address.offset <= 32767
652            && !m_fixedWidth)
653            m_assembler.lbu(dest, address.base, address.offset);
654        else {
655            /*
656                lui     addrTemp, (offset + 0x8000) >> 16
657                addu    addrTemp, addrTemp, base
658                lbu     dest, (offset & 0xffff)(addrTemp)
659              */
660            m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16);
661            m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
662            m_assembler.lbu(dest, addrTempRegister, address.offset);
663        }
664    }
665
666    void load8(BaseIndex address, RegisterID dest)
667    {
668        if (address.offset >= -32768 && address.offset <= 32767
669            && !m_fixedWidth) {
670            /*
671             sll     addrTemp, address.index, address.scale
672             addu    addrTemp, addrTemp, address.base
673             lbu     dest, address.offset(addrTemp)
674             */
675            m_assembler.sll(addrTempRegister, address.index, address.scale);
676            m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
677            m_assembler.lbu(dest, addrTempRegister, address.offset);
678        } else {
679            /*
680             sll     addrTemp, address.index, address.scale
681             addu    addrTemp, addrTemp, address.base
682             lui     immTemp, (address.offset + 0x8000) >> 16
683             addu    addrTemp, addrTemp, immTemp
684             lbu     dest, (address.offset & 0xffff)(at)
685             */
686            m_assembler.sll(addrTempRegister, address.index, address.scale);
687            m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
688            m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16);
689            m_assembler.addu(addrTempRegister, addrTempRegister, immTempRegister);
690            m_assembler.lbu(dest, addrTempRegister, address.offset);
691        }
692    }
693
694    void load8Signed(BaseIndex address, RegisterID dest)
695    {
696        if (address.offset >= -32768 && address.offset <= 32767
697            && !m_fixedWidth) {
698            /*
699                sll     addrTemp, address.index, address.scale
700                addu    addrTemp, addrTemp, address.base
701                lb      dest, address.offset(addrTemp)
702            */
703            m_assembler.sll(addrTempRegister, address.index, address.scale);
704            m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
705            m_assembler.lb(dest, addrTempRegister, address.offset);
706        } else {
707            /*
708                sll     addrTemp, address.index, address.scale
709                addu    addrTemp, addrTemp, address.base
710                lui     immTemp, (address.offset + 0x8000) >> 16
711                addu    addrTemp, addrTemp, immTemp
712                lb     dest, (address.offset & 0xffff)(at)
713            */
714            m_assembler.sll(addrTempRegister, address.index, address.scale);
715            m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
716            m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16);
717            m_assembler.addu(addrTempRegister, addrTempRegister, immTempRegister);
718            m_assembler.lb(dest, addrTempRegister, address.offset);
719        }
720    }
721
722    void load32(ImplicitAddress address, RegisterID dest)
723    {
724        if (address.offset >= -32768 && address.offset <= 32767
725            && !m_fixedWidth)
726            m_assembler.lw(dest, address.base, address.offset);
727        else {
728            /*
729                lui     addrTemp, (offset + 0x8000) >> 16
730                addu    addrTemp, addrTemp, base
731                lw      dest, (offset & 0xffff)(addrTemp)
732              */
733            m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16);
734            m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
735            m_assembler.lw(dest, addrTempRegister, address.offset);
736        }
737    }
738
739    void load32(BaseIndex address, RegisterID dest)
740    {
741        if (address.offset >= -32768 && address.offset <= 32767
742            && !m_fixedWidth) {
743            /*
744                sll     addrTemp, address.index, address.scale
745                addu    addrTemp, addrTemp, address.base
746                lw      dest, address.offset(addrTemp)
747            */
748            m_assembler.sll(addrTempRegister, address.index, address.scale);
749            m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
750            m_assembler.lw(dest, addrTempRegister, address.offset);
751        } else {
752            /*
753                sll     addrTemp, address.index, address.scale
754                addu    addrTemp, addrTemp, address.base
755                lui     immTemp, (address.offset + 0x8000) >> 16
756                addu    addrTemp, addrTemp, immTemp
757                lw      dest, (address.offset & 0xffff)(at)
758            */
759            m_assembler.sll(addrTempRegister, address.index, address.scale);
760            m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
761            m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16);
762            m_assembler.addu(addrTempRegister, addrTempRegister, immTempRegister);
763            m_assembler.lw(dest, addrTempRegister, address.offset);
764        }
765    }
766
767    void load16Unaligned(BaseIndex address, RegisterID dest)
768    {
769        load16(address, dest);
770    }
771
772    void load32WithUnalignedHalfWords(BaseIndex address, RegisterID dest)
773    {
774        if (address.offset >= -32768 && address.offset <= 32764
775            && !m_fixedWidth) {
776            /*
777                sll     addrTemp, address.index, address.scale
778                addu    addrTemp, addrTemp, address.base
779                (Big-Endian)
780                lwl     dest, address.offset(addrTemp)
781                lwr     dest, address.offset+3(addrTemp)
782                (Little-Endian)
783                lwl     dest, address.offset+3(addrTemp)
784                lwr     dest, address.offset(addrTemp)
785            */
786            m_assembler.sll(addrTempRegister, address.index, address.scale);
787            m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
788#if CPU(BIG_ENDIAN)
789            m_assembler.lwl(dest, addrTempRegister, address.offset);
790            m_assembler.lwr(dest, addrTempRegister, address.offset + 3);
791#else
792            m_assembler.lwl(dest, addrTempRegister, address.offset + 3);
793            m_assembler.lwr(dest, addrTempRegister, address.offset);
794
795#endif
796        } else {
797            /*
798                sll     addrTemp, address.index, address.scale
799                addu    addrTemp, addrTemp, address.base
800                lui     immTemp, address.offset >> 16
801                ori     immTemp, immTemp, address.offset & 0xffff
802                addu    addrTemp, addrTemp, immTemp
803                (Big-Endian)
804                lw      dest, 0(at)
805                lw      dest, 3(at)
806                (Little-Endian)
807                lw      dest, 3(at)
808                lw      dest, 0(at)
809            */
810            m_assembler.sll(addrTempRegister, address.index, address.scale);
811            m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
812            m_assembler.lui(immTempRegister, address.offset >> 16);
813            m_assembler.ori(immTempRegister, immTempRegister, address.offset);
814            m_assembler.addu(addrTempRegister, addrTempRegister, immTempRegister);
815#if CPU(BIG_ENDIAN)
816            m_assembler.lwl(dest, addrTempRegister, 0);
817            m_assembler.lwr(dest, addrTempRegister, 3);
818#else
819            m_assembler.lwl(dest, addrTempRegister, 3);
820            m_assembler.lwr(dest, addrTempRegister, 0);
821#endif
822        }
823    }
824
825    void load32(const void* address, RegisterID dest)
826    {
827        /*
828            li  addrTemp, address
829            lw  dest, 0(addrTemp)
830        */
831        move(TrustedImmPtr(address), addrTempRegister);
832        m_assembler.lw(dest, addrTempRegister, 0);
833    }
834
835    DataLabel32 load32WithAddressOffsetPatch(Address address, RegisterID dest)
836    {
837        m_fixedWidth = true;
838        /*
839            lui addrTemp, address.offset >> 16
840            ori addrTemp, addrTemp, address.offset & 0xffff
841            addu        addrTemp, addrTemp, address.base
842            lw  dest, 0(addrTemp)
843        */
844        DataLabel32 dataLabel(this);
845        move(TrustedImm32(address.offset), addrTempRegister);
846        m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
847        m_assembler.lw(dest, addrTempRegister, 0);
848        m_fixedWidth = false;
849        return dataLabel;
850    }
851
852    DataLabelCompact load32WithCompactAddressOffsetPatch(Address address, RegisterID dest)
853    {
854        DataLabelCompact dataLabel(this);
855        load32WithAddressOffsetPatch(address, dest);
856        return dataLabel;
857    }
858
859    /* Need to use zero-extened load half-word for load16.  */
860    void load16(ImplicitAddress address, RegisterID dest)
861    {
862        if (address.offset >= -32768 && address.offset <= 32767
863            && !m_fixedWidth)
864            m_assembler.lhu(dest, address.base, address.offset);
865        else {
866            /*
867                lui     addrTemp, (offset + 0x8000) >> 16
868                addu    addrTemp, addrTemp, base
869                lhu     dest, (offset & 0xffff)(addrTemp)
870              */
871            m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16);
872            m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
873            m_assembler.lhu(dest, addrTempRegister, address.offset);
874        }
875    }
876
877    /* Need to use zero-extened load half-word for load16.  */
878    void load16(BaseIndex address, RegisterID dest)
879    {
880        if (address.offset >= -32768 && address.offset <= 32767
881            && !m_fixedWidth) {
882            /*
883                sll     addrTemp, address.index, address.scale
884                addu    addrTemp, addrTemp, address.base
885                lhu     dest, address.offset(addrTemp)
886            */
887            m_assembler.sll(addrTempRegister, address.index, address.scale);
888            m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
889            m_assembler.lhu(dest, addrTempRegister, address.offset);
890        } else {
891            /*
892                sll     addrTemp, address.index, address.scale
893                addu    addrTemp, addrTemp, address.base
894                lui     immTemp, (address.offset + 0x8000) >> 16
895                addu    addrTemp, addrTemp, immTemp
896                lhu     dest, (address.offset & 0xffff)(addrTemp)
897            */
898            m_assembler.sll(addrTempRegister, address.index, address.scale);
899            m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
900            m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16);
901            m_assembler.addu(addrTempRegister, addrTempRegister, immTempRegister);
902            m_assembler.lhu(dest, addrTempRegister, address.offset);
903        }
904    }
905
906    void load16Signed(BaseIndex address, RegisterID dest)
907    {
908        if (address.offset >= -32768 && address.offset <= 32767
909            && !m_fixedWidth) {
910            /*
911                sll     addrTemp, address.index, address.scale
912                addu    addrTemp, addrTemp, address.base
913                lh     dest, address.offset(addrTemp)
914            */
915            m_assembler.sll(addrTempRegister, address.index, address.scale);
916            m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
917            m_assembler.lh(dest, addrTempRegister, address.offset);
918        } else {
919            /*
920                sll     addrTemp, address.index, address.scale
921                addu    addrTemp, addrTemp, address.base
922                lui     immTemp, (address.offset + 0x8000) >> 16
923                addu    addrTemp, addrTemp, immTemp
924                lh     dest, (address.offset & 0xffff)(addrTemp)
925            */
926            m_assembler.sll(addrTempRegister, address.index, address.scale);
927            m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
928            m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16);
929            m_assembler.addu(addrTempRegister, addrTempRegister, immTempRegister);
930            m_assembler.lh(dest, addrTempRegister, address.offset);
931        }
932    }
933
934    DataLabel32 store32WithAddressOffsetPatch(RegisterID src, Address address)
935    {
936        m_fixedWidth = true;
937        /*
938            lui addrTemp, address.offset >> 16
939            ori addrTemp, addrTemp, address.offset & 0xffff
940            addu        addrTemp, addrTemp, address.base
941            sw  src, 0(addrTemp)
942        */
943        DataLabel32 dataLabel(this);
944        move(TrustedImm32(address.offset), addrTempRegister);
945        m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
946        m_assembler.sw(src, addrTempRegister, 0);
947        m_fixedWidth = false;
948        return dataLabel;
949    }
950
951    void store8(RegisterID src, BaseIndex address)
952    {
953        if (address.offset >= -32768 && address.offset <= 32767
954            && !m_fixedWidth) {
955            /*
956                sll     addrTemp, address.index, address.scale
957                addu    addrTemp, addrTemp, address.base
958                sb      src, address.offset(addrTemp)
959            */
960            m_assembler.sll(addrTempRegister, address.index, address.scale);
961            m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
962            m_assembler.sb(src, addrTempRegister, address.offset);
963        } else {
964            /*
965                sll     addrTemp, address.index, address.scale
966                addu    addrTemp, addrTemp, address.base
967                lui     immTemp, (address.offset + 0x8000) >> 16
968                addu    addrTemp, addrTemp, immTemp
969                sb      src, (address.offset & 0xffff)(at)
970            */
971            m_assembler.sll(addrTempRegister, address.index, address.scale);
972            m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
973            m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16);
974            m_assembler.addu(addrTempRegister, addrTempRegister, immTempRegister);
975            m_assembler.sb(src, addrTempRegister, address.offset);
976        }
977    }
978
979    void store8(TrustedImm32 imm, void* address)
980    {
981        /*
982            li  immTemp, imm
983            li  addrTemp, address
984            sb  src, 0(addrTemp)
985        */
986        if (!imm.m_value && !m_fixedWidth) {
987            move(TrustedImmPtr(address), addrTempRegister);
988            m_assembler.sb(MIPSRegisters::zero, addrTempRegister, 0);
989        } else {
990            move(imm, immTempRegister);
991            move(TrustedImmPtr(address), addrTempRegister);
992            m_assembler.sb(immTempRegister, addrTempRegister, 0);
993        }
994    }
995
996    void store16(RegisterID src, BaseIndex address)
997    {
998        if (address.offset >= -32768 && address.offset <= 32767
999            && !m_fixedWidth) {
1000            /*
1001                sll     addrTemp, address.index, address.scale
1002                addu    addrTemp, addrTemp, address.base
1003                sh      src, address.offset(addrTemp)
1004            */
1005            m_assembler.sll(addrTempRegister, address.index, address.scale);
1006            m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
1007            m_assembler.sh(src, addrTempRegister, address.offset);
1008        } else {
1009            /*
1010                sll     addrTemp, address.index, address.scale
1011                addu    addrTemp, addrTemp, address.base
1012                lui     immTemp, (address.offset + 0x8000) >> 16
1013                addu    addrTemp, addrTemp, immTemp
1014                sh      src, (address.offset & 0xffff)(at)
1015            */
1016            m_assembler.sll(addrTempRegister, address.index, address.scale);
1017            m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
1018            m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16);
1019            m_assembler.addu(addrTempRegister, addrTempRegister, immTempRegister);
1020            m_assembler.sh(src, addrTempRegister, address.offset);
1021        }
1022    }
1023
1024    void store32(RegisterID src, ImplicitAddress address)
1025    {
1026        if (address.offset >= -32768 && address.offset <= 32767
1027            && !m_fixedWidth)
1028            m_assembler.sw(src, address.base, address.offset);
1029        else {
1030            /*
1031                lui     addrTemp, (offset + 0x8000) >> 16
1032                addu    addrTemp, addrTemp, base
1033                sw      src, (offset & 0xffff)(addrTemp)
1034              */
1035            m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16);
1036            m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
1037            m_assembler.sw(src, addrTempRegister, address.offset);
1038        }
1039    }
1040
1041    void store32(RegisterID src, BaseIndex address)
1042    {
1043        if (address.offset >= -32768 && address.offset <= 32767
1044            && !m_fixedWidth) {
1045            /*
1046                sll     addrTemp, address.index, address.scale
1047                addu    addrTemp, addrTemp, address.base
1048                sw      src, address.offset(addrTemp)
1049            */
1050            m_assembler.sll(addrTempRegister, address.index, address.scale);
1051            m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
1052            m_assembler.sw(src, addrTempRegister, address.offset);
1053        } else {
1054            /*
1055                sll     addrTemp, address.index, address.scale
1056                addu    addrTemp, addrTemp, address.base
1057                lui     immTemp, (address.offset + 0x8000) >> 16
1058                addu    addrTemp, addrTemp, immTemp
1059                sw      src, (address.offset & 0xffff)(at)
1060            */
1061            m_assembler.sll(addrTempRegister, address.index, address.scale);
1062            m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
1063            m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16);
1064            m_assembler.addu(addrTempRegister, addrTempRegister, immTempRegister);
1065            m_assembler.sw(src, addrTempRegister, address.offset);
1066        }
1067    }
1068
1069    void store32(TrustedImm32 imm, ImplicitAddress address)
1070    {
1071        if (address.offset >= -32768 && address.offset <= 32767
1072            && !m_fixedWidth) {
1073            if (!imm.m_value)
1074                m_assembler.sw(MIPSRegisters::zero, address.base, address.offset);
1075            else {
1076                move(imm, immTempRegister);
1077                m_assembler.sw(immTempRegister, address.base, address.offset);
1078            }
1079        } else {
1080            /*
1081                lui     addrTemp, (offset + 0x8000) >> 16
1082                addu    addrTemp, addrTemp, base
1083                sw      immTemp, (offset & 0xffff)(addrTemp)
1084              */
1085            m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16);
1086            m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
1087            if (!imm.m_value && !m_fixedWidth)
1088                m_assembler.sw(MIPSRegisters::zero, addrTempRegister, address.offset);
1089            else {
1090                move(imm, immTempRegister);
1091                m_assembler.sw(immTempRegister, addrTempRegister, address.offset);
1092            }
1093        }
1094    }
1095
1096    void store32(TrustedImm32 imm, BaseIndex address)
1097    {
1098        if (address.offset >= -32768 && address.offset <= 32767 && !m_fixedWidth) {
1099            /*
1100                sll     addrTemp, address.index, address.scale
1101                addu    addrTemp, addrTemp, address.base
1102                sw      src, address.offset(addrTemp)
1103            */
1104            m_assembler.sll(addrTempRegister, address.index, address.scale);
1105            m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
1106            if (!imm.m_value)
1107                m_assembler.sw(MIPSRegisters::zero, addrTempRegister, address.offset);
1108            else {
1109                move(imm, immTempRegister);
1110                m_assembler.sw(immTempRegister, addrTempRegister, address.offset);
1111            }
1112        } else {
1113            /*
1114                sll     addrTemp, address.index, address.scale
1115                addu    addrTemp, addrTemp, address.base
1116                lui     immTemp, (address.offset + 0x8000) >> 16
1117                addu    addrTemp, addrTemp, immTemp
1118                sw      src, (address.offset & 0xffff)(at)
1119            */
1120            m_assembler.sll(addrTempRegister, address.index, address.scale);
1121            m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
1122            m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16);
1123            m_assembler.addu(addrTempRegister, addrTempRegister, immTempRegister);
1124            if (!imm.m_value && !m_fixedWidth)
1125                m_assembler.sw(MIPSRegisters::zero, addrTempRegister, address.offset);
1126            else {
1127                move(imm, immTempRegister);
1128                m_assembler.sw(immTempRegister, addrTempRegister, address.offset);
1129            }
1130        }
1131    }
1132
1133
1134    void store32(RegisterID src, const void* address)
1135    {
1136        /*
1137            li  addrTemp, address
1138            sw  src, 0(addrTemp)
1139        */
1140        move(TrustedImmPtr(address), addrTempRegister);
1141        m_assembler.sw(src, addrTempRegister, 0);
1142    }
1143
1144    void store32(TrustedImm32 imm, const void* address)
1145    {
1146        /*
1147            li  immTemp, imm
1148            li  addrTemp, address
1149            sw  src, 0(addrTemp)
1150        */
1151        if (!imm.m_value && !m_fixedWidth) {
1152            move(TrustedImmPtr(address), addrTempRegister);
1153            m_assembler.sw(MIPSRegisters::zero, addrTempRegister, 0);
1154        } else {
1155            move(imm, immTempRegister);
1156            move(TrustedImmPtr(address), addrTempRegister);
1157            m_assembler.sw(immTempRegister, addrTempRegister, 0);
1158        }
1159    }
1160
1161    // Floating-point operations:
1162
1163    static bool supportsFloatingPoint()
1164    {
1165#if WTF_MIPS_DOUBLE_FLOAT
1166        return true;
1167#else
1168        return false;
1169#endif
1170    }
1171
1172    static bool supportsFloatingPointTruncate()
1173    {
1174#if WTF_MIPS_DOUBLE_FLOAT && WTF_MIPS_ISA_AT_LEAST(2)
1175        return true;
1176#else
1177        return false;
1178#endif
1179    }
1180
1181    static bool supportsFloatingPointSqrt()
1182    {
1183#if WTF_MIPS_DOUBLE_FLOAT && WTF_MIPS_ISA_AT_LEAST(2)
1184        return true;
1185#else
1186        return false;
1187#endif
1188    }
1189    static bool supportsFloatingPointAbs() { return false; }
1190
1191    // Stack manipulation operations:
1192    //
1193    // The ABI is assumed to provide a stack abstraction to memory,
1194    // containing machine word sized units of data. Push and pop
1195    // operations add and remove a single register sized unit of data
1196    // to or from the stack. Peek and poke operations read or write
1197    // values on the stack, without moving the current stack position.
1198
1199    void pop(RegisterID dest)
1200    {
1201        m_assembler.lw(dest, MIPSRegisters::sp, 0);
1202        m_assembler.addiu(MIPSRegisters::sp, MIPSRegisters::sp, 4);
1203    }
1204
1205    void push(RegisterID src)
1206    {
1207        m_assembler.addiu(MIPSRegisters::sp, MIPSRegisters::sp, -4);
1208        m_assembler.sw(src, MIPSRegisters::sp, 0);
1209    }
1210
1211    void push(Address address)
1212    {
1213        load32(address, dataTempRegister);
1214        push(dataTempRegister);
1215    }
1216
1217    void push(TrustedImm32 imm)
1218    {
1219        move(imm, immTempRegister);
1220        push(immTempRegister);
1221    }
1222
1223    // Register move operations:
1224    //
1225    // Move values in registers.
1226
1227    void move(TrustedImm32 imm, RegisterID dest)
1228    {
1229        if (!imm.m_value && !m_fixedWidth)
1230            move(MIPSRegisters::zero, dest);
1231        else if (m_fixedWidth) {
1232            m_assembler.lui(dest, imm.m_value >> 16);
1233            m_assembler.ori(dest, dest, imm.m_value);
1234        } else
1235            m_assembler.li(dest, imm.m_value);
1236    }
1237
1238    void move(RegisterID src, RegisterID dest)
1239    {
1240        if (src != dest || m_fixedWidth)
1241            m_assembler.move(dest, src);
1242    }
1243
1244    void move(TrustedImmPtr imm, RegisterID dest)
1245    {
1246        move(TrustedImm32(imm), dest);
1247    }
1248
1249    void swap(RegisterID reg1, RegisterID reg2)
1250    {
1251        move(reg1, immTempRegister);
1252        move(reg2, reg1);
1253        move(immTempRegister, reg2);
1254    }
1255
1256    void signExtend32ToPtr(RegisterID src, RegisterID dest)
1257    {
1258        if (src != dest || m_fixedWidth)
1259            move(src, dest);
1260    }
1261
1262    void zeroExtend32ToPtr(RegisterID src, RegisterID dest)
1263    {
1264        if (src != dest || m_fixedWidth)
1265            move(src, dest);
1266    }
1267
1268    // Forwards / external control flow operations:
1269    //
1270    // This set of jump and conditional branch operations return a Jump
1271    // object which may linked at a later point, allow forwards jump,
1272    // or jumps that will require external linkage (after the code has been
1273    // relocated).
1274    //
1275    // For branches, signed <, >, <= and >= are denoted as l, g, le, and ge
1276    // respecitvely, for unsigned comparisons the names b, a, be, and ae are
1277    // used (representing the names 'below' and 'above').
1278    //
1279    // Operands to the comparision are provided in the expected order, e.g.
1280    // jle32(reg1, TrustedImm32(5)) will branch if the value held in reg1, when
1281    // treated as a signed 32bit value, is less than or equal to 5.
1282    //
1283    // jz and jnz test whether the first operand is equal to zero, and take
1284    // an optional second operand of a mask under which to perform the test.
1285
1286    Jump branch8(RelationalCondition cond, Address left, TrustedImm32 right)
1287    {
1288        // Make sure the immediate value is unsigned 8 bits.
1289        ASSERT(!(right.m_value & 0xFFFFFF00));
1290        load8(left, dataTempRegister);
1291        move(right, immTempRegister);
1292        return branch32(cond, dataTempRegister, immTempRegister);
1293    }
1294
1295    void compare8(RelationalCondition cond, Address left, TrustedImm32 right, RegisterID dest)
1296    {
1297        // Make sure the immediate value is unsigned 8 bits.
1298        ASSERT(!(right.m_value & 0xFFFFFF00));
1299        load8(left, dataTempRegister);
1300        move(right, immTempRegister);
1301        compare32(cond, dataTempRegister, immTempRegister, dest);
1302    }
1303
1304    Jump branch8(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
1305    {
1306        ASSERT(!(right.m_value & 0xFFFFFF00));
1307        load8(left, dataTempRegister);
1308        // Be careful that the previous load8() uses immTempRegister.
1309        // So, we need to put move() after load8().
1310        move(right, immTempRegister);
1311        return branch32(cond, dataTempRegister, immTempRegister);
1312    }
1313
1314    Jump branch32(RelationalCondition cond, RegisterID left, RegisterID right)
1315    {
1316        if (cond == Equal)
1317            return branchEqual(left, right);
1318        if (cond == NotEqual)
1319            return branchNotEqual(left, right);
1320        if (cond == Above) {
1321            m_assembler.sltu(cmpTempRegister, right, left);
1322            return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
1323        }
1324        if (cond == AboveOrEqual) {
1325            m_assembler.sltu(cmpTempRegister, left, right);
1326            return branchEqual(cmpTempRegister, MIPSRegisters::zero);
1327        }
1328        if (cond == Below) {
1329            m_assembler.sltu(cmpTempRegister, left, right);
1330            return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
1331        }
1332        if (cond == BelowOrEqual) {
1333            m_assembler.sltu(cmpTempRegister, right, left);
1334            return branchEqual(cmpTempRegister, MIPSRegisters::zero);
1335        }
1336        if (cond == GreaterThan) {
1337            m_assembler.slt(cmpTempRegister, right, left);
1338            return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
1339        }
1340        if (cond == GreaterThanOrEqual) {
1341            m_assembler.slt(cmpTempRegister, left, right);
1342            return branchEqual(cmpTempRegister, MIPSRegisters::zero);
1343        }
1344        if (cond == LessThan) {
1345            m_assembler.slt(cmpTempRegister, left, right);
1346            return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
1347        }
1348        if (cond == LessThanOrEqual) {
1349            m_assembler.slt(cmpTempRegister, right, left);
1350            return branchEqual(cmpTempRegister, MIPSRegisters::zero);
1351        }
1352        ASSERT(0);
1353
1354        return Jump();
1355    }
1356
1357    Jump branch32(RelationalCondition cond, RegisterID left, TrustedImm32 right)
1358    {
1359        move(right, immTempRegister);
1360        return branch32(cond, left, immTempRegister);
1361    }
1362
1363    Jump branch32(RelationalCondition cond, RegisterID left, Address right)
1364    {
1365        load32(right, dataTempRegister);
1366        return branch32(cond, left, dataTempRegister);
1367    }
1368
1369    Jump branch32(RelationalCondition cond, Address left, RegisterID right)
1370    {
1371        load32(left, dataTempRegister);
1372        return branch32(cond, dataTempRegister, right);
1373    }
1374
1375    Jump branch32(RelationalCondition cond, Address left, TrustedImm32 right)
1376    {
1377        load32(left, dataTempRegister);
1378        move(right, immTempRegister);
1379        return branch32(cond, dataTempRegister, immTempRegister);
1380    }
1381
1382    Jump branch32(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
1383    {
1384        load32(left, dataTempRegister);
1385        // Be careful that the previous load32() uses immTempRegister.
1386        // So, we need to put move() after load32().
1387        move(right, immTempRegister);
1388        return branch32(cond, dataTempRegister, immTempRegister);
1389    }
1390
1391    Jump branch32WithUnalignedHalfWords(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
1392    {
1393        load32WithUnalignedHalfWords(left, dataTempRegister);
1394        // Be careful that the previous load32WithUnalignedHalfWords()
1395        // uses immTempRegister.
1396        // So, we need to put move() after load32WithUnalignedHalfWords().
1397        move(right, immTempRegister);
1398        return branch32(cond, dataTempRegister, immTempRegister);
1399    }
1400
1401    Jump branch32(RelationalCondition cond, AbsoluteAddress left, RegisterID right)
1402    {
1403        load32(left.m_ptr, dataTempRegister);
1404        return branch32(cond, dataTempRegister, right);
1405    }
1406
1407    Jump branch32(RelationalCondition cond, AbsoluteAddress left, TrustedImm32 right)
1408    {
1409        load32(left.m_ptr, dataTempRegister);
1410        move(right, immTempRegister);
1411        return branch32(cond, dataTempRegister, immTempRegister);
1412    }
1413
1414    Jump branchTest32(ResultCondition cond, RegisterID reg, RegisterID mask)
1415    {
1416        ASSERT((cond == Zero) || (cond == NonZero));
1417        m_assembler.andInsn(cmpTempRegister, reg, mask);
1418        if (cond == Zero)
1419            return branchEqual(cmpTempRegister, MIPSRegisters::zero);
1420        return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
1421    }
1422
1423    Jump branchTest32(ResultCondition cond, RegisterID reg, TrustedImm32 mask = TrustedImm32(-1))
1424    {
1425        ASSERT((cond == Zero) || (cond == NonZero));
1426        if (mask.m_value == -1 && !m_fixedWidth) {
1427            if (cond == Zero)
1428                return branchEqual(reg, MIPSRegisters::zero);
1429            return branchNotEqual(reg, MIPSRegisters::zero);
1430        }
1431        move(mask, immTempRegister);
1432        return branchTest32(cond, reg, immTempRegister);
1433    }
1434
1435    Jump branchTest32(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
1436    {
1437        load32(address, dataTempRegister);
1438        return branchTest32(cond, dataTempRegister, mask);
1439    }
1440
1441    Jump branchTest32(ResultCondition cond, BaseIndex address, TrustedImm32 mask = TrustedImm32(-1))
1442    {
1443        load32(address, dataTempRegister);
1444        return branchTest32(cond, dataTempRegister, mask);
1445    }
1446
1447    Jump branchTest8(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
1448    {
1449        load8(address, dataTempRegister);
1450        return branchTest32(cond, dataTempRegister, mask);
1451    }
1452
1453    Jump branchTest8(ResultCondition cond, AbsoluteAddress address, TrustedImm32 mask = TrustedImm32(-1))
1454    {
1455        move(TrustedImmPtr(address.m_ptr), dataTempRegister);
1456        load8(Address(dataTempRegister), dataTempRegister);
1457        return branchTest32(cond, dataTempRegister, mask);
1458    }
1459
1460    Jump jump()
1461    {
1462        return branchEqual(MIPSRegisters::zero, MIPSRegisters::zero);
1463    }
1464
1465    void jump(RegisterID target)
1466    {
1467        move(target, MIPSRegisters::t9);
1468        m_assembler.jr(MIPSRegisters::t9);
1469        m_assembler.nop();
1470    }
1471
1472    void jump(Address address)
1473    {
1474        m_fixedWidth = true;
1475        load32(address, MIPSRegisters::t9);
1476        m_assembler.jr(MIPSRegisters::t9);
1477        m_assembler.nop();
1478        m_fixedWidth = false;
1479    }
1480
1481    void jump(AbsoluteAddress address)
1482    {
1483        m_fixedWidth = true;
1484        load32(address.m_ptr, MIPSRegisters::t9);
1485        m_assembler.jr(MIPSRegisters::t9);
1486        m_assembler.nop();
1487        m_fixedWidth = false;
1488    }
1489
1490    void moveDoubleToInts(FPRegisterID src, RegisterID dest1, RegisterID dest2)
1491    {
1492        m_assembler.vmov(dest1, dest2, src);
1493    }
1494
1495    void moveIntsToDouble(RegisterID src1, RegisterID src2, FPRegisterID dest, FPRegisterID scratch)
1496    {
1497        UNUSED_PARAM(scratch);
1498        m_assembler.vmov(dest, src1, src2);
1499    }
1500
1501    // Arithmetic control flow operations:
1502    //
1503    // This set of conditional branch operations branch based
1504    // on the result of an arithmetic operation. The operation
1505    // is performed as normal, storing the result.
1506    //
1507    // * jz operations branch if the result is zero.
1508    // * jo operations branch if the (signed) arithmetic
1509    //   operation caused an overflow to occur.
1510
1511    Jump branchAdd32(ResultCondition cond, RegisterID src, RegisterID dest)
1512    {
1513        ASSERT((cond == Overflow) || (cond == Signed) || (cond == PositiveOrZero) || (cond == Zero) || (cond == NonZero));
1514        if (cond == Overflow) {
1515            /*
1516                move    dest, dataTemp
1517                xor     cmpTemp, dataTemp, src
1518                bltz    cmpTemp, No_overflow    # diff sign bit -> no overflow
1519                addu    dest, dataTemp, src
1520                xor     cmpTemp, dest, dataTemp
1521                bgez    cmpTemp, No_overflow    # same sign big -> no overflow
1522                nop
1523                b       Overflow
1524                nop
1525                nop
1526                nop
1527                nop
1528                nop
1529            No_overflow:
1530            */
1531            move(dest, dataTempRegister);
1532            m_assembler.xorInsn(cmpTempRegister, dataTempRegister, src);
1533            m_assembler.bltz(cmpTempRegister, 10);
1534            m_assembler.addu(dest, dataTempRegister, src);
1535            m_assembler.xorInsn(cmpTempRegister, dest, dataTempRegister);
1536            m_assembler.bgez(cmpTempRegister, 7);
1537            m_assembler.nop();
1538            return jump();
1539        }
1540        if (cond == Signed) {
1541            add32(src, dest);
1542            // Check if dest is negative.
1543            m_assembler.slt(cmpTempRegister, dest, MIPSRegisters::zero);
1544            return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
1545        }
1546        if (cond == PositiveOrZero) {
1547            add32(src, dest);
1548            // Check if dest is not negative.
1549            m_assembler.slt(cmpTempRegister, dest, MIPSRegisters::zero);
1550            return branchEqual(cmpTempRegister, MIPSRegisters::zero);
1551        }
1552        if (cond == Zero) {
1553            add32(src, dest);
1554            return branchEqual(dest, MIPSRegisters::zero);
1555        }
1556        if (cond == NonZero) {
1557            add32(src, dest);
1558            return branchNotEqual(dest, MIPSRegisters::zero);
1559        }
1560        ASSERT(0);
1561        return Jump();
1562    }
1563
1564    Jump branchAdd32(ResultCondition cond, RegisterID op1, RegisterID op2, RegisterID dest)
1565    {
1566        ASSERT((cond == Overflow) || (cond == Signed) || (cond == PositiveOrZero) || (cond == Zero) || (cond == NonZero));
1567        if (cond == Overflow) {
1568            /*
1569                move    dataTemp, op1
1570                xor     cmpTemp, dataTemp, op2
1571                bltz    cmpTemp, No_overflow    # diff sign bit -> no overflow
1572                addu    dest, dataTemp, op2
1573                xor     cmpTemp, dest, dataTemp
1574                bgez    cmpTemp, No_overflow    # same sign big -> no overflow
1575                nop
1576                b       Overflow
1577                nop
1578                nop
1579                nop
1580                nop
1581                nop
1582            No_overflow:
1583            */
1584            move(op1, dataTempRegister);
1585            m_assembler.xorInsn(cmpTempRegister, dataTempRegister, op2);
1586            m_assembler.bltz(cmpTempRegister, 10);
1587            m_assembler.addu(dest, dataTempRegister, op2);
1588            m_assembler.xorInsn(cmpTempRegister, dest, dataTempRegister);
1589            m_assembler.bgez(cmpTempRegister, 7);
1590            m_assembler.nop();
1591            return jump();
1592        }
1593        if (cond == Signed) {
1594            add32(op1, op2, dest);
1595            // Check if dest is negative.
1596            m_assembler.slt(cmpTempRegister, dest, MIPSRegisters::zero);
1597            return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
1598        }
1599        if (cond == PositiveOrZero) {
1600            add32(op1, op2, dest);
1601            // Check if dest is not negative.
1602            m_assembler.slt(cmpTempRegister, dest, MIPSRegisters::zero);
1603            return branchEqual(cmpTempRegister, MIPSRegisters::zero);
1604        }
1605        if (cond == Zero) {
1606            add32(op1, op2, dest);
1607            return branchEqual(dest, MIPSRegisters::zero);
1608        }
1609        if (cond == NonZero) {
1610            add32(op1, op2, dest);
1611            return branchNotEqual(dest, MIPSRegisters::zero);
1612        }
1613        ASSERT(0);
1614        return Jump();
1615    }
1616
1617    Jump branchAdd32(ResultCondition cond, TrustedImm32 imm, RegisterID dest)
1618    {
1619        move(imm, immTempRegister);
1620        return branchAdd32(cond, immTempRegister, dest);
1621    }
1622
1623    Jump branchAdd32(ResultCondition cond, RegisterID src, TrustedImm32 imm, RegisterID dest)
1624    {
1625        move(imm, immTempRegister);
1626        move(src, dest);
1627        return branchAdd32(cond, immTempRegister, dest);
1628    }
1629
1630    Jump branchAdd32(ResultCondition cond, TrustedImm32 imm, AbsoluteAddress dest)
1631    {
1632        ASSERT((cond == Overflow) || (cond == Signed) || (cond == PositiveOrZero) || (cond == Zero) || (cond == NonZero));
1633        if (cond == Overflow) {
1634            /*
1635                move    dataTemp, dest
1636                xori    cmpTemp, dataTemp, imm
1637                bltz    cmpTemp, No_overflow    # diff sign bit -> no overflow
1638                addiu   dataTemp, dataTemp, imm
1639                move    dest, dataTemp
1640                xori    cmpTemp, dataTemp, imm
1641                bgez    cmpTemp, No_overflow    # same sign big -> no overflow
1642                nop
1643                b       Overflow
1644                nop
1645                nop
1646                nop
1647                nop
1648                nop
1649            No_overflow:
1650            */
1651            if (imm.m_value >= -32768 && imm.m_value  <= 32767 && !m_fixedWidth) {
1652                load32(dest.m_ptr, dataTempRegister);
1653                m_assembler.xori(cmpTempRegister, dataTempRegister, imm.m_value);
1654                m_assembler.bltz(cmpTempRegister, 10);
1655                m_assembler.addiu(dataTempRegister, dataTempRegister, imm.m_value);
1656                store32(dataTempRegister, dest.m_ptr);
1657                m_assembler.xori(cmpTempRegister, dataTempRegister, imm.m_value);
1658                m_assembler.bgez(cmpTempRegister, 7);
1659                m_assembler.nop();
1660            } else {
1661                load32(dest.m_ptr, dataTempRegister);
1662                move(imm, immTempRegister);
1663                m_assembler.xorInsn(cmpTempRegister, dataTempRegister, immTempRegister);
1664                m_assembler.bltz(cmpTempRegister, 10);
1665                m_assembler.addiu(dataTempRegister, dataTempRegister, immTempRegister);
1666                store32(dataTempRegister, dest.m_ptr);
1667                m_assembler.xori(cmpTempRegister, dataTempRegister, immTempRegister);
1668                m_assembler.bgez(cmpTempRegister, 7);
1669                m_assembler.nop();
1670            }
1671            return jump();
1672        }
1673        move(imm, immTempRegister);
1674        load32(dest.m_ptr, dataTempRegister);
1675        add32(immTempRegister, dataTempRegister);
1676        store32(dataTempRegister, dest.m_ptr);
1677        if (cond == Signed) {
1678            // Check if dest is negative.
1679            m_assembler.slt(cmpTempRegister, dataTempRegister, MIPSRegisters::zero);
1680            return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
1681        }
1682        if (cond == PositiveOrZero) {
1683            // Check if dest is not negative.
1684            m_assembler.slt(cmpTempRegister, dataTempRegister, MIPSRegisters::zero);
1685            return branchEqual(cmpTempRegister, MIPSRegisters::zero);
1686        }
1687        if (cond == Zero)
1688            return branchEqual(dataTempRegister, MIPSRegisters::zero);
1689        if (cond == NonZero)
1690            return branchNotEqual(dataTempRegister, MIPSRegisters::zero);
1691        ASSERT(0);
1692        return Jump();
1693    }
1694
1695    Jump branchMul32(ResultCondition cond, RegisterID src1, RegisterID src2, RegisterID dest)
1696    {
1697        ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
1698        if (cond == Overflow) {
1699            /*
1700                mult    src, dest
1701                mfhi    dataTemp
1702                mflo    dest
1703                sra     addrTemp, dest, 31
1704                beq     dataTemp, addrTemp, No_overflow # all sign bits (bit 63 to bit 31) are the same -> no overflow
1705                nop
1706                b       Overflow
1707                nop
1708                nop
1709                nop
1710                nop
1711                nop
1712            No_overflow:
1713            */
1714            m_assembler.mult(src1, src2);
1715            m_assembler.mfhi(dataTempRegister);
1716            m_assembler.mflo(dest);
1717            m_assembler.sra(addrTempRegister, dest, 31);
1718            m_assembler.beq(dataTempRegister, addrTempRegister, 7);
1719            m_assembler.nop();
1720            return jump();
1721        }
1722        if (cond == Signed) {
1723            mul32(src1, src2, dest);
1724            // Check if dest is negative.
1725            m_assembler.slt(cmpTempRegister, dest, MIPSRegisters::zero);
1726            return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
1727        }
1728        if (cond == Zero) {
1729            mul32(src1, src2, dest);
1730            return branchEqual(dest, MIPSRegisters::zero);
1731        }
1732        if (cond == NonZero) {
1733            mul32(src1, src2, dest);
1734            return branchNotEqual(dest, MIPSRegisters::zero);
1735        }
1736        ASSERT(0);
1737        return Jump();
1738    }
1739
1740    Jump branchMul32(ResultCondition cond, RegisterID src, RegisterID dest)
1741    {
1742        ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
1743        if (cond == Overflow) {
1744            /*
1745                mult    src, dest
1746                mfhi    dataTemp
1747                mflo    dest
1748                sra     addrTemp, dest, 31
1749                beq     dataTemp, addrTemp, No_overflow # all sign bits (bit 63 to bit 31) are the same -> no overflow
1750                nop
1751                b       Overflow
1752                nop
1753                nop
1754                nop
1755                nop
1756                nop
1757            No_overflow:
1758            */
1759            m_assembler.mult(src, dest);
1760            m_assembler.mfhi(dataTempRegister);
1761            m_assembler.mflo(dest);
1762            m_assembler.sra(addrTempRegister, dest, 31);
1763            m_assembler.beq(dataTempRegister, addrTempRegister, 7);
1764            m_assembler.nop();
1765            return jump();
1766        }
1767        if (cond == Signed) {
1768            mul32(src, dest);
1769            // Check if dest is negative.
1770            m_assembler.slt(cmpTempRegister, dest, MIPSRegisters::zero);
1771            return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
1772        }
1773        if (cond == Zero) {
1774            mul32(src, dest);
1775            return branchEqual(dest, MIPSRegisters::zero);
1776        }
1777        if (cond == NonZero) {
1778            mul32(src, dest);
1779            return branchNotEqual(dest, MIPSRegisters::zero);
1780        }
1781        ASSERT(0);
1782        return Jump();
1783    }
1784
1785    Jump branchMul32(ResultCondition cond, TrustedImm32 imm, RegisterID src, RegisterID dest)
1786    {
1787        move(imm, immTempRegister);
1788        return branchMul32(cond, immTempRegister, src, dest);
1789    }
1790
1791    Jump branchSub32(ResultCondition cond, RegisterID src, RegisterID dest)
1792    {
1793        ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
1794        if (cond == Overflow) {
1795            /*
1796                move    dest, dataTemp
1797                xor     cmpTemp, dataTemp, src
1798                bgez    cmpTemp, No_overflow    # same sign bit -> no overflow
1799                subu    dest, dataTemp, src
1800                xor     cmpTemp, dest, dataTemp
1801                bgez    cmpTemp, No_overflow    # same sign bit -> no overflow
1802                nop
1803                b       Overflow
1804                nop
1805                nop
1806                nop
1807                nop
1808                nop
1809            No_overflow:
1810            */
1811            move(dest, dataTempRegister);
1812            m_assembler.xorInsn(cmpTempRegister, dataTempRegister, src);
1813            m_assembler.bgez(cmpTempRegister, 10);
1814            m_assembler.subu(dest, dataTempRegister, src);
1815            m_assembler.xorInsn(cmpTempRegister, dest, dataTempRegister);
1816            m_assembler.bgez(cmpTempRegister, 7);
1817            m_assembler.nop();
1818            return jump();
1819        }
1820        if (cond == Signed) {
1821            sub32(src, dest);
1822            // Check if dest is negative.
1823            m_assembler.slt(cmpTempRegister, dest, MIPSRegisters::zero);
1824            return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
1825        }
1826        if (cond == Zero) {
1827            sub32(src, dest);
1828            return branchEqual(dest, MIPSRegisters::zero);
1829        }
1830        if (cond == NonZero) {
1831            sub32(src, dest);
1832            return branchNotEqual(dest, MIPSRegisters::zero);
1833        }
1834        ASSERT(0);
1835        return Jump();
1836    }
1837
1838    Jump branchSub32(ResultCondition cond, TrustedImm32 imm, RegisterID dest)
1839    {
1840        move(imm, immTempRegister);
1841        return branchSub32(cond, immTempRegister, dest);
1842    }
1843
1844    Jump branchSub32(ResultCondition cond, RegisterID src, TrustedImm32 imm, RegisterID dest)
1845    {
1846        move(imm, immTempRegister);
1847        return branchSub32(cond, src, immTempRegister, dest);
1848    }
1849
1850    Jump branchSub32(ResultCondition cond, RegisterID op1, RegisterID op2, RegisterID dest)
1851    {
1852        ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
1853        if (cond == Overflow) {
1854            /*
1855                move    dataTemp, op1
1856                xor     cmpTemp, dataTemp, op2
1857                bgez    cmpTemp, No_overflow    # same sign bit -> no overflow
1858                subu    dest, dataTemp, op2
1859                xor     cmpTemp, dest, dataTemp
1860                bgez    cmpTemp, No_overflow    # same sign bit -> no overflow
1861                nop
1862                b       Overflow
1863                nop
1864                nop
1865                nop
1866                nop
1867                nop
1868            No_overflow:
1869            */
1870            move(op1, dataTempRegister);
1871            m_assembler.xorInsn(cmpTempRegister, dataTempRegister, op2);
1872            m_assembler.bgez(cmpTempRegister, 10);
1873            m_assembler.subu(dest, dataTempRegister, op2);
1874            m_assembler.xorInsn(cmpTempRegister, dest, dataTempRegister);
1875            m_assembler.bgez(cmpTempRegister, 7);
1876            m_assembler.nop();
1877            return jump();
1878        }
1879        if (cond == Signed) {
1880            sub32(op1, op2, dest);
1881            // Check if dest is negative.
1882            m_assembler.slt(cmpTempRegister, dest, MIPSRegisters::zero);
1883            return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
1884        }
1885        if (cond == Zero) {
1886            sub32(op1, op2, dest);
1887            return branchEqual(dest, MIPSRegisters::zero);
1888        }
1889        if (cond == NonZero) {
1890            sub32(op1, op2, dest);
1891            return branchNotEqual(dest, MIPSRegisters::zero);
1892        }
1893        ASSERT(0);
1894        return Jump();
1895    }
1896
1897    Jump branchNeg32(ResultCondition cond, RegisterID srcDest)
1898    {
1899        m_assembler.li(dataTempRegister, -1);
1900        return branchMul32(cond, dataTempRegister, srcDest);
1901    }
1902
1903    Jump branchOr32(ResultCondition cond, RegisterID src, RegisterID dest)
1904    {
1905        ASSERT((cond == Signed) || (cond == Zero) || (cond == NonZero));
1906        if (cond == Signed) {
1907            or32(src, dest);
1908            // Check if dest is negative.
1909            m_assembler.slt(cmpTempRegister, dest, MIPSRegisters::zero);
1910            return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
1911        }
1912        if (cond == Zero) {
1913            or32(src, dest);
1914            return branchEqual(dest, MIPSRegisters::zero);
1915        }
1916        if (cond == NonZero) {
1917            or32(src, dest);
1918            return branchNotEqual(dest, MIPSRegisters::zero);
1919        }
1920        ASSERT(0);
1921        return Jump();
1922    }
1923
1924    // Miscellaneous operations:
1925
1926    void breakpoint()
1927    {
1928        m_assembler.bkpt();
1929    }
1930
1931    Call nearCall()
1932    {
1933        /* We need two words for relaxation. */
1934        m_assembler.nop();
1935        m_assembler.nop();
1936        m_assembler.jal();
1937        m_assembler.nop();
1938        return Call(m_assembler.label(), Call::LinkableNear);
1939    }
1940
1941    Call call()
1942    {
1943        m_assembler.lui(MIPSRegisters::t9, 0);
1944        m_assembler.ori(MIPSRegisters::t9, MIPSRegisters::t9, 0);
1945        m_assembler.jalr(MIPSRegisters::t9);
1946        m_assembler.nop();
1947        return Call(m_assembler.label(), Call::Linkable);
1948    }
1949
1950    Call call(RegisterID target)
1951    {
1952        move(target, MIPSRegisters::t9);
1953        m_assembler.jalr(MIPSRegisters::t9);
1954        m_assembler.nop();
1955        return Call(m_assembler.label(), Call::None);
1956    }
1957
1958    Call call(Address address)
1959    {
1960        m_fixedWidth = true;
1961        load32(address, MIPSRegisters::t9);
1962        m_assembler.jalr(MIPSRegisters::t9);
1963        m_assembler.nop();
1964        m_fixedWidth = false;
1965        return Call(m_assembler.label(), Call::None);
1966    }
1967
1968    void ret()
1969    {
1970        m_assembler.jr(MIPSRegisters::ra);
1971        m_assembler.nop();
1972    }
1973
1974    void compare32(RelationalCondition cond, RegisterID left, RegisterID right, RegisterID dest)
1975    {
1976        if (cond == Equal) {
1977            m_assembler.xorInsn(dest, left, right);
1978            m_assembler.sltiu(dest, dest, 1);
1979        } else if (cond == NotEqual) {
1980            m_assembler.xorInsn(dest, left, right);
1981            m_assembler.sltu(dest, MIPSRegisters::zero, dest);
1982        } else if (cond == Above)
1983            m_assembler.sltu(dest, right, left);
1984        else if (cond == AboveOrEqual) {
1985            m_assembler.sltu(dest, left, right);
1986            m_assembler.xori(dest, dest, 1);
1987        } else if (cond == Below)
1988            m_assembler.sltu(dest, left, right);
1989        else if (cond == BelowOrEqual) {
1990            m_assembler.sltu(dest, right, left);
1991            m_assembler.xori(dest, dest, 1);
1992        } else if (cond == GreaterThan)
1993            m_assembler.slt(dest, right, left);
1994        else if (cond == GreaterThanOrEqual) {
1995            m_assembler.slt(dest, left, right);
1996            m_assembler.xori(dest, dest, 1);
1997        } else if (cond == LessThan)
1998            m_assembler.slt(dest, left, right);
1999        else if (cond == LessThanOrEqual) {
2000            m_assembler.slt(dest, right, left);
2001            m_assembler.xori(dest, dest, 1);
2002        }
2003    }
2004
2005    void compare32(RelationalCondition cond, RegisterID left, TrustedImm32 right, RegisterID dest)
2006    {
2007        move(right, immTempRegister);
2008        compare32(cond, left, immTempRegister, dest);
2009    }
2010
2011    void test8(ResultCondition cond, Address address, TrustedImm32 mask, RegisterID dest)
2012    {
2013        ASSERT((cond == Zero) || (cond == NonZero));
2014        load8(address, dataTempRegister);
2015        if (mask.m_value == -1 && !m_fixedWidth) {
2016            if (cond == Zero)
2017                m_assembler.sltiu(dest, dataTempRegister, 1);
2018            else
2019                m_assembler.sltu(dest, MIPSRegisters::zero, dataTempRegister);
2020        } else {
2021            move(mask, immTempRegister);
2022            m_assembler.andInsn(cmpTempRegister, dataTempRegister, immTempRegister);
2023            if (cond == Zero)
2024                m_assembler.sltiu(dest, cmpTempRegister, 1);
2025            else
2026                m_assembler.sltu(dest, MIPSRegisters::zero, cmpTempRegister);
2027        }
2028    }
2029
2030    void test32(ResultCondition cond, Address address, TrustedImm32 mask, RegisterID dest)
2031    {
2032        ASSERT((cond == Zero) || (cond == NonZero));
2033        load32(address, dataTempRegister);
2034        if (mask.m_value == -1 && !m_fixedWidth) {
2035            if (cond == Zero)
2036                m_assembler.sltiu(dest, dataTempRegister, 1);
2037            else
2038                m_assembler.sltu(dest, MIPSRegisters::zero, dataTempRegister);
2039        } else {
2040            move(mask, immTempRegister);
2041            m_assembler.andInsn(cmpTempRegister, dataTempRegister, immTempRegister);
2042            if (cond == Zero)
2043                m_assembler.sltiu(dest, cmpTempRegister, 1);
2044            else
2045                m_assembler.sltu(dest, MIPSRegisters::zero, cmpTempRegister);
2046        }
2047    }
2048
2049    DataLabel32 moveWithPatch(TrustedImm32 imm, RegisterID dest)
2050    {
2051        m_fixedWidth = true;
2052        DataLabel32 label(this);
2053        move(imm, dest);
2054        m_fixedWidth = false;
2055        return label;
2056    }
2057
2058    DataLabelPtr moveWithPatch(TrustedImmPtr initialValue, RegisterID dest)
2059    {
2060        m_fixedWidth = true;
2061        DataLabelPtr label(this);
2062        move(initialValue, dest);
2063        m_fixedWidth = false;
2064        return label;
2065    }
2066
2067    Jump branchPtrWithPatch(RelationalCondition cond, RegisterID left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
2068    {
2069        m_fixedWidth = true;
2070        dataLabel = moveWithPatch(initialRightValue, immTempRegister);
2071        Jump temp = branch32(cond, left, immTempRegister);
2072        m_fixedWidth = false;
2073        return temp;
2074    }
2075
2076    Jump branchPtrWithPatch(RelationalCondition cond, Address left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
2077    {
2078        m_fixedWidth = true;
2079        load32(left, dataTempRegister);
2080        dataLabel = moveWithPatch(initialRightValue, immTempRegister);
2081        Jump temp = branch32(cond, dataTempRegister, immTempRegister);
2082        m_fixedWidth = false;
2083        return temp;
2084    }
2085
2086    DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address)
2087    {
2088        m_fixedWidth = true;
2089        DataLabelPtr dataLabel = moveWithPatch(initialValue, dataTempRegister);
2090        store32(dataTempRegister, address);
2091        m_fixedWidth = false;
2092        return dataLabel;
2093    }
2094
2095    DataLabelPtr storePtrWithPatch(ImplicitAddress address)
2096    {
2097        return storePtrWithPatch(TrustedImmPtr(0), address);
2098    }
2099
2100    Call tailRecursiveCall()
2101    {
2102        // Like a normal call, but don't update the returned address register
2103        m_fixedWidth = true;
2104        move(TrustedImm32(0), MIPSRegisters::t9);
2105        m_assembler.jr(MIPSRegisters::t9);
2106        m_assembler.nop();
2107        m_fixedWidth = false;
2108        return Call(m_assembler.label(), Call::Linkable);
2109    }
2110
2111    Call makeTailRecursiveCall(Jump oldJump)
2112    {
2113        oldJump.link(this);
2114        return tailRecursiveCall();
2115    }
2116
2117    void loadFloat(BaseIndex address, FPRegisterID dest)
2118    {
2119        if (address.offset >= -32768 && address.offset <= 32767
2120            && !m_fixedWidth) {
2121            /*
2122                sll     addrTemp, address.index, address.scale
2123                addu    addrTemp, addrTemp, address.base
2124                lwc1    dest, address.offset(addrTemp)
2125            */
2126            m_assembler.sll(addrTempRegister, address.index, address.scale);
2127            m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
2128            m_assembler.lwc1(dest, addrTempRegister, address.offset);
2129        } else {
2130            /*
2131                sll     addrTemp, address.index, address.scale
2132                addu    addrTemp, addrTemp, address.base
2133                lui     immTemp, (address.offset + 0x8000) >> 16
2134                addu    addrTemp, addrTemp, immTemp
2135                lwc1    dest, (address.offset & 0xffff)(at)
2136            */
2137            m_assembler.sll(addrTempRegister, address.index, address.scale);
2138            m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
2139            m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16);
2140            m_assembler.addu(addrTempRegister, addrTempRegister, immTempRegister);
2141            m_assembler.lwc1(dest, addrTempRegister, address.offset);
2142        }
2143    }
2144
2145    void loadDouble(ImplicitAddress address, FPRegisterID dest)
2146    {
2147#if WTF_MIPS_ISA(1)
2148        /*
2149            li          addrTemp, address.offset
2150            addu        addrTemp, addrTemp, base
2151            lwc1        dest, 0(addrTemp)
2152            lwc1        dest+1, 4(addrTemp)
2153         */
2154        move(TrustedImm32(address.offset), addrTempRegister);
2155        m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
2156        m_assembler.lwc1(dest, addrTempRegister, 0);
2157        m_assembler.lwc1(FPRegisterID(dest + 1), addrTempRegister, 4);
2158#else
2159        if (address.offset >= -32768 && address.offset <= 32767
2160            && !m_fixedWidth) {
2161            m_assembler.ldc1(dest, address.base, address.offset);
2162        } else {
2163            /*
2164                lui     addrTemp, (offset + 0x8000) >> 16
2165                addu    addrTemp, addrTemp, base
2166                ldc1    dest, (offset & 0xffff)(addrTemp)
2167              */
2168            m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16);
2169            m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
2170            m_assembler.ldc1(dest, addrTempRegister, address.offset);
2171        }
2172#endif
2173    }
2174
2175    void loadDouble(BaseIndex address, FPRegisterID dest)
2176    {
2177#if WTF_MIPS_ISA(1)
2178        if (address.offset >= -32768 && address.offset <= 32767
2179            && !m_fixedWidth) {
2180            /*
2181                sll     addrTemp, address.index, address.scale
2182                addu    addrTemp, addrTemp, address.base
2183                lwc1    dest, address.offset(addrTemp)
2184                lwc1    dest+1, (address.offset+4)(addrTemp)
2185            */
2186            m_assembler.sll(addrTempRegister, address.index, address.scale);
2187            m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
2188            m_assembler.lwc1(dest, addrTempRegister, address.offset);
2189            m_assembler.lwc1(FPRegisterID(dest + 1), addrTempRegister, address.offset + 4);
2190        } else {
2191            /*
2192                sll     addrTemp, address.index, address.scale
2193                addu    addrTemp, addrTemp, address.base
2194                lui     immTemp, (address.offset + 0x8000) >> 16
2195                addu    addrTemp, addrTemp, immTemp
2196                lwc1    dest, (address.offset & 0xffff)(at)
2197                lwc1    dest+1, (address.offset & 0xffff + 4)(at)
2198            */
2199            m_assembler.sll(addrTempRegister, address.index, address.scale);
2200            m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
2201            m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16);
2202            m_assembler.addu(addrTempRegister, addrTempRegister, immTempRegister);
2203            m_assembler.lwc1(dest, addrTempRegister, address.offset);
2204            m_assembler.lwc1(FPRegisterID(dest + 1), addrTempRegister, address.offset + 4);
2205        }
2206#else
2207        if (address.offset >= -32768 && address.offset <= 32767
2208            && !m_fixedWidth) {
2209            /*
2210                sll     addrTemp, address.index, address.scale
2211                addu    addrTemp, addrTemp, address.base
2212                ldc1    dest, address.offset(addrTemp)
2213            */
2214            m_assembler.sll(addrTempRegister, address.index, address.scale);
2215            m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
2216            m_assembler.ldc1(dest, addrTempRegister, address.offset);
2217        } else {
2218            /*
2219                sll     addrTemp, address.index, address.scale
2220                addu    addrTemp, addrTemp, address.base
2221                lui     immTemp, (address.offset + 0x8000) >> 16
2222                addu    addrTemp, addrTemp, immTemp
2223                ldc1    dest, (address.offset & 0xffff)(at)
2224            */
2225            m_assembler.sll(addrTempRegister, address.index, address.scale);
2226            m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
2227            m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16);
2228            m_assembler.addu(addrTempRegister, addrTempRegister, immTempRegister);
2229            m_assembler.ldc1(dest, addrTempRegister, address.offset);
2230        }
2231#endif
2232    }
2233
2234    void loadDouble(const void* address, FPRegisterID dest)
2235    {
2236#if WTF_MIPS_ISA(1)
2237        /*
2238            li          addrTemp, address
2239            lwc1        dest, 0(addrTemp)
2240            lwc1        dest+1, 4(addrTemp)
2241         */
2242        move(TrustedImmPtr(address), addrTempRegister);
2243        m_assembler.lwc1(dest, addrTempRegister, 0);
2244        m_assembler.lwc1(FPRegisterID(dest + 1), addrTempRegister, 4);
2245#else
2246        /*
2247            li          addrTemp, address
2248            ldc1        dest, 0(addrTemp)
2249        */
2250        move(TrustedImmPtr(address), addrTempRegister);
2251        m_assembler.ldc1(dest, addrTempRegister, 0);
2252#endif
2253    }
2254
2255    void storeFloat(FPRegisterID src, BaseIndex address)
2256    {
2257        if (address.offset >= -32768 && address.offset <= 32767
2258            && !m_fixedWidth) {
2259            /*
2260                sll     addrTemp, address.index, address.scale
2261                addu    addrTemp, addrTemp, address.base
2262                swc1    src, address.offset(addrTemp)
2263            */
2264            m_assembler.sll(addrTempRegister, address.index, address.scale);
2265            m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
2266            m_assembler.swc1(src, addrTempRegister, address.offset);
2267        } else {
2268            /*
2269                sll     addrTemp, address.index, address.scale
2270                addu    addrTemp, addrTemp, address.base
2271                lui     immTemp, (address.offset + 0x8000) >> 16
2272                addu    addrTemp, addrTemp, immTemp
2273                swc1    src, (address.offset & 0xffff)(at)
2274            */
2275            m_assembler.sll(addrTempRegister, address.index, address.scale);
2276            m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
2277            m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16);
2278            m_assembler.addu(addrTempRegister, addrTempRegister, immTempRegister);
2279            m_assembler.swc1(src, addrTempRegister, address.offset);
2280        }
2281    }
2282
2283    void storeDouble(FPRegisterID src, ImplicitAddress address)
2284    {
2285#if WTF_MIPS_ISA(1)
2286        /*
2287            li          addrTemp, address.offset
2288            addu        addrTemp, addrTemp, base
2289            swc1        dest, 0(addrTemp)
2290            swc1        dest+1, 4(addrTemp)
2291         */
2292        move(TrustedImm32(address.offset), addrTempRegister);
2293        m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
2294        m_assembler.swc1(src, addrTempRegister, 0);
2295        m_assembler.swc1(FPRegisterID(src + 1), addrTempRegister, 4);
2296#else
2297        if (address.offset >= -32768 && address.offset <= 32767
2298            && !m_fixedWidth)
2299            m_assembler.sdc1(src, address.base, address.offset);
2300        else {
2301            /*
2302                lui     addrTemp, (offset + 0x8000) >> 16
2303                addu    addrTemp, addrTemp, base
2304                sdc1    src, (offset & 0xffff)(addrTemp)
2305              */
2306            m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16);
2307            m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
2308            m_assembler.sdc1(src, addrTempRegister, address.offset);
2309        }
2310#endif
2311    }
2312
2313    void storeDouble(FPRegisterID src, BaseIndex address)
2314    {
2315#if WTF_MIPS_ISA(1)
2316        if (address.offset >= -32768 && address.offset <= 32767
2317            && !m_fixedWidth) {
2318            /*
2319                sll     addrTemp, address.index, address.scale
2320                addu    addrTemp, addrTemp, address.base
2321                swc1    src, address.offset(addrTemp)
2322                swc1    src+1, (address.offset + 4)(addrTemp)
2323            */
2324            m_assembler.sll(addrTempRegister, address.index, address.scale);
2325            m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
2326            m_assembler.swc1(src, addrTempRegister, address.offset);
2327            m_assembler.swc1(FPRegisterID(src + 1), addrTempRegister, address.offset + 4);
2328        } else {
2329            /*
2330                sll     addrTemp, address.index, address.scale
2331                addu    addrTemp, addrTemp, address.base
2332                lui     immTemp, (address.offset + 0x8000) >> 16
2333                addu    addrTemp, addrTemp, immTemp
2334                swc1    src, (address.offset & 0xffff)(at)
2335                swc1    src+1, (address.offset & 0xffff + 4)(at)
2336            */
2337            m_assembler.sll(addrTempRegister, address.index, address.scale);
2338            m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
2339            m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16);
2340            m_assembler.addu(addrTempRegister, addrTempRegister, immTempRegister);
2341            m_assembler.swc1(src, addrTempRegister, address.offset);
2342            m_assembler.swc1(FPRegisterID(src + 1), addrTempRegister, address.offset + 4);
2343        }
2344#else
2345        if (address.offset >= -32768 && address.offset <= 32767
2346            && !m_fixedWidth) {
2347            /*
2348                sll     addrTemp, address.index, address.scale
2349                addu    addrTemp, addrTemp, address.base
2350                sdc1    src, address.offset(addrTemp)
2351            */
2352            m_assembler.sll(addrTempRegister, address.index, address.scale);
2353            m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
2354            m_assembler.sdc1(src, addrTempRegister, address.offset);
2355        } else {
2356            /*
2357                sll     addrTemp, address.index, address.scale
2358                addu    addrTemp, addrTemp, address.base
2359                lui     immTemp, (address.offset + 0x8000) >> 16
2360                addu    addrTemp, addrTemp, immTemp
2361                sdc1    src, (address.offset & 0xffff)(at)
2362            */
2363            m_assembler.sll(addrTempRegister, address.index, address.scale);
2364            m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
2365            m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16);
2366            m_assembler.addu(addrTempRegister, addrTempRegister, immTempRegister);
2367            m_assembler.sdc1(src, addrTempRegister, address.offset);
2368        }
2369#endif
2370    }
2371
2372    void storeDouble(FPRegisterID src, const void* address)
2373    {
2374#if WTF_MIPS_ISA(1)
2375        move(TrustedImmPtr(address), addrTempRegister);
2376        m_assembler.swc1(src, addrTempRegister, 0);
2377        m_assembler.swc1(FPRegisterID(src + 1), addrTempRegister, 4);
2378#else
2379        move(TrustedImmPtr(address), addrTempRegister);
2380        m_assembler.sdc1(src, addrTempRegister, 0);
2381#endif
2382    }
2383
2384    void moveDouble(FPRegisterID src, FPRegisterID dest)
2385    {
2386        if (src != dest || m_fixedWidth)
2387            m_assembler.movd(dest, src);
2388    }
2389
2390    void swapDouble(FPRegisterID fr1, FPRegisterID fr2)
2391    {
2392        moveDouble(fr1, fpTempRegister);
2393        moveDouble(fr2, fr1);
2394        moveDouble(fpTempRegister, fr2);
2395    }
2396
2397    void addDouble(FPRegisterID src, FPRegisterID dest)
2398    {
2399        m_assembler.addd(dest, dest, src);
2400    }
2401
2402    void addDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
2403    {
2404        m_assembler.addd(dest, op1, op2);
2405    }
2406
2407    void addDouble(Address src, FPRegisterID dest)
2408    {
2409        loadDouble(src, fpTempRegister);
2410        m_assembler.addd(dest, dest, fpTempRegister);
2411    }
2412
2413    void addDouble(AbsoluteAddress address, FPRegisterID dest)
2414    {
2415        loadDouble(address.m_ptr, fpTempRegister);
2416        m_assembler.addd(dest, dest, fpTempRegister);
2417    }
2418
2419    void subDouble(FPRegisterID src, FPRegisterID dest)
2420    {
2421        m_assembler.subd(dest, dest, src);
2422    }
2423
2424    void subDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
2425    {
2426        m_assembler.subd(dest, op1, op2);
2427    }
2428
2429    void subDouble(Address src, FPRegisterID dest)
2430    {
2431        loadDouble(src, fpTempRegister);
2432        m_assembler.subd(dest, dest, fpTempRegister);
2433    }
2434
2435    void mulDouble(FPRegisterID src, FPRegisterID dest)
2436    {
2437        m_assembler.muld(dest, dest, src);
2438    }
2439
2440    void mulDouble(Address src, FPRegisterID dest)
2441    {
2442        loadDouble(src, fpTempRegister);
2443        m_assembler.muld(dest, dest, fpTempRegister);
2444    }
2445
2446    void mulDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
2447    {
2448        m_assembler.muld(dest, op1, op2);
2449    }
2450
2451    void divDouble(FPRegisterID src, FPRegisterID dest)
2452    {
2453        m_assembler.divd(dest, dest, src);
2454    }
2455
2456    void divDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
2457    {
2458        m_assembler.divd(dest, op1, op2);
2459    }
2460
2461    void divDouble(Address src, FPRegisterID dest)
2462    {
2463        loadDouble(src, fpTempRegister);
2464        m_assembler.divd(dest, dest, fpTempRegister);
2465    }
2466
2467    void negateDouble(FPRegisterID src, FPRegisterID dest)
2468    {
2469        m_assembler.negd(dest, src);
2470    }
2471
2472    void convertInt32ToDouble(RegisterID src, FPRegisterID dest)
2473    {
2474        m_assembler.mtc1(src, fpTempRegister);
2475        m_assembler.cvtdw(dest, fpTempRegister);
2476    }
2477
2478    void convertInt32ToDouble(Address src, FPRegisterID dest)
2479    {
2480        load32(src, dataTempRegister);
2481        m_assembler.mtc1(dataTempRegister, fpTempRegister);
2482        m_assembler.cvtdw(dest, fpTempRegister);
2483    }
2484
2485    void convertInt32ToDouble(AbsoluteAddress src, FPRegisterID dest)
2486    {
2487        load32(src.m_ptr, dataTempRegister);
2488        m_assembler.mtc1(dataTempRegister, fpTempRegister);
2489        m_assembler.cvtdw(dest, fpTempRegister);
2490    }
2491
2492    void convertFloatToDouble(FPRegisterID src, FPRegisterID dst)
2493    {
2494        m_assembler.cvtds(dst, src);
2495    }
2496
2497    void convertDoubleToFloat(FPRegisterID src, FPRegisterID dst)
2498    {
2499        m_assembler.cvtsd(dst, src);
2500    }
2501
2502    void insertRelaxationWords()
2503    {
2504        /* We need four words for relaxation. */
2505        m_assembler.beq(MIPSRegisters::zero, MIPSRegisters::zero, 3); // Jump over nops;
2506        m_assembler.nop();
2507        m_assembler.nop();
2508        m_assembler.nop();
2509    }
2510
2511    Jump branchTrue()
2512    {
2513        m_assembler.appendJump();
2514        m_assembler.bc1t();
2515        m_assembler.nop();
2516        insertRelaxationWords();
2517        return Jump(m_assembler.label());
2518    }
2519
2520    Jump branchFalse()
2521    {
2522        m_assembler.appendJump();
2523        m_assembler.bc1f();
2524        m_assembler.nop();
2525        insertRelaxationWords();
2526        return Jump(m_assembler.label());
2527    }
2528
2529    Jump branchEqual(RegisterID rs, RegisterID rt)
2530    {
2531        m_assembler.nop();
2532        m_assembler.nop();
2533        m_assembler.appendJump();
2534        m_assembler.beq(rs, rt, 0);
2535        m_assembler.nop();
2536        insertRelaxationWords();
2537        return Jump(m_assembler.label());
2538    }
2539
2540    Jump branchNotEqual(RegisterID rs, RegisterID rt)
2541    {
2542        m_assembler.nop();
2543        m_assembler.nop();
2544        m_assembler.appendJump();
2545        m_assembler.bne(rs, rt, 0);
2546        m_assembler.nop();
2547        insertRelaxationWords();
2548        return Jump(m_assembler.label());
2549    }
2550
2551    Jump branchDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right)
2552    {
2553        if (cond == DoubleEqual) {
2554            m_assembler.ceqd(left, right);
2555            return branchTrue();
2556        }
2557        if (cond == DoubleNotEqual) {
2558            m_assembler.cueqd(left, right);
2559            return branchFalse(); // false
2560        }
2561        if (cond == DoubleGreaterThan) {
2562            m_assembler.cngtd(left, right);
2563            return branchFalse(); // false
2564        }
2565        if (cond == DoubleGreaterThanOrEqual) {
2566            m_assembler.cnged(left, right);
2567            return branchFalse(); // false
2568        }
2569        if (cond == DoubleLessThan) {
2570            m_assembler.cltd(left, right);
2571            return branchTrue();
2572        }
2573        if (cond == DoubleLessThanOrEqual) {
2574            m_assembler.cled(left, right);
2575            return branchTrue();
2576        }
2577        if (cond == DoubleEqualOrUnordered) {
2578            m_assembler.cueqd(left, right);
2579            return branchTrue();
2580        }
2581        if (cond == DoubleNotEqualOrUnordered) {
2582            m_assembler.ceqd(left, right);
2583            return branchFalse(); // false
2584        }
2585        if (cond == DoubleGreaterThanOrUnordered) {
2586            m_assembler.coled(left, right);
2587            return branchFalse(); // false
2588        }
2589        if (cond == DoubleGreaterThanOrEqualOrUnordered) {
2590            m_assembler.coltd(left, right);
2591            return branchFalse(); // false
2592        }
2593        if (cond == DoubleLessThanOrUnordered) {
2594            m_assembler.cultd(left, right);
2595            return branchTrue();
2596        }
2597        if (cond == DoubleLessThanOrEqualOrUnordered) {
2598            m_assembler.culed(left, right);
2599            return branchTrue();
2600        }
2601        ASSERT(0);
2602
2603        return Jump();
2604    }
2605
2606    // Truncates 'src' to an integer, and places the resulting 'dest'.
2607    // If the result is not representable as a 32 bit value, branch.
2608    // May also branch for some values that are representable in 32 bits
2609    // (specifically, in this case, INT_MAX 0x7fffffff).
2610    enum BranchTruncateType { BranchIfTruncateFailed, BranchIfTruncateSuccessful };
2611    Jump branchTruncateDoubleToInt32(FPRegisterID src, RegisterID dest, BranchTruncateType branchType = BranchIfTruncateFailed)
2612    {
2613        m_assembler.truncwd(fpTempRegister, src);
2614        m_assembler.mfc1(dest, fpTempRegister);
2615        return branch32(branchType == BranchIfTruncateFailed ? Equal : NotEqual, dest, TrustedImm32(0x7fffffff));
2616    }
2617
2618    Jump branchTruncateDoubleToUint32(FPRegisterID src, RegisterID dest, BranchTruncateType branchType = BranchIfTruncateFailed)
2619    {
2620        m_assembler.truncwd(fpTempRegister, src);
2621        m_assembler.mfc1(dest, fpTempRegister);
2622        return branch32(branchType == BranchIfTruncateFailed ? Equal : NotEqual, dest, TrustedImm32(0));
2623    }
2624
2625    // Result is undefined if the value is outside of the integer range.
2626    void truncateDoubleToInt32(FPRegisterID src, RegisterID dest)
2627    {
2628        m_assembler.truncwd(fpTempRegister, src);
2629        m_assembler.mfc1(dest, fpTempRegister);
2630    }
2631
2632    // Result is undefined if src > 2^31
2633    void truncateDoubleToUint32(FPRegisterID src, RegisterID dest)
2634    {
2635        m_assembler.truncwd(fpTempRegister, src);
2636        m_assembler.mfc1(dest, fpTempRegister);
2637    }
2638
2639    // Convert 'src' to an integer, and places the resulting 'dest'.
2640    // If the result is not representable as a 32 bit value, branch.
2641    // May also branch for some values that are representable in 32 bits
2642    // (specifically, in this case, 0).
2643    void branchConvertDoubleToInt32(FPRegisterID src, RegisterID dest, JumpList& failureCases, FPRegisterID fpTemp, bool negZeroCheck = true)
2644    {
2645        m_assembler.cvtwd(fpTempRegister, src);
2646        m_assembler.mfc1(dest, fpTempRegister);
2647
2648        // If the result is zero, it might have been -0.0, and the double comparison won't catch this!
2649        if (negZeroCheck)
2650            failureCases.append(branch32(Equal, dest, MIPSRegisters::zero));
2651
2652        // Convert the integer result back to float & compare to the original value - if not equal or unordered (NaN) then jump.
2653        convertInt32ToDouble(dest, fpTemp);
2654        failureCases.append(branchDouble(DoubleNotEqualOrUnordered, fpTemp, src));
2655    }
2656
2657    Jump branchDoubleNonZero(FPRegisterID reg, FPRegisterID scratch)
2658    {
2659        m_assembler.vmov(scratch, MIPSRegisters::zero, MIPSRegisters::zero);
2660        return branchDouble(DoubleNotEqual, reg, scratch);
2661    }
2662
2663    Jump branchDoubleZeroOrNaN(FPRegisterID reg, FPRegisterID scratch)
2664    {
2665        m_assembler.vmov(scratch, MIPSRegisters::zero, MIPSRegisters::zero);
2666        return branchDouble(DoubleEqualOrUnordered, reg, scratch);
2667    }
2668
2669    // Invert a relational condition, e.g. == becomes !=, < becomes >=, etc.
2670    static RelationalCondition invert(RelationalCondition cond)
2671    {
2672        RelationalCondition r;
2673        if (cond == Equal)
2674            r = NotEqual;
2675        else if (cond == NotEqual)
2676            r = Equal;
2677        else if (cond == Above)
2678            r = BelowOrEqual;
2679        else if (cond == AboveOrEqual)
2680            r = Below;
2681        else if (cond == Below)
2682            r = AboveOrEqual;
2683        else if (cond == BelowOrEqual)
2684            r = Above;
2685        else if (cond == GreaterThan)
2686            r = LessThanOrEqual;
2687        else if (cond == GreaterThanOrEqual)
2688            r = LessThan;
2689        else if (cond == LessThan)
2690            r = GreaterThanOrEqual;
2691        else if (cond == LessThanOrEqual)
2692            r = GreaterThan;
2693        return r;
2694    }
2695
2696    void nop()
2697    {
2698        m_assembler.nop();
2699    }
2700
2701    static FunctionPtr readCallTarget(CodeLocationCall call)
2702    {
2703        return FunctionPtr(reinterpret_cast<void(*)()>(MIPSAssembler::readCallTarget(call.dataLocation())));
2704    }
2705
2706    static void replaceWithJump(CodeLocationLabel instructionStart, CodeLocationLabel destination)
2707    {
2708        MIPSAssembler::replaceWithJump(instructionStart.dataLocation(), destination.dataLocation());
2709    }
2710
2711    static ptrdiff_t maxJumpReplacementSize()
2712    {
2713        MIPSAssembler::maxJumpReplacementSize();
2714        return 0;
2715    }
2716
2717    static bool canJumpReplacePatchableBranchPtrWithPatch() { return false; }
2718
2719    static CodeLocationLabel startOfBranchPtrWithPatchOnRegister(CodeLocationDataLabelPtr label)
2720    {
2721        return label.labelAtOffset(0);
2722    }
2723
2724    static void revertJumpReplacementToBranchPtrWithPatch(CodeLocationLabel instructionStart, RegisterID, void* initialValue)
2725    {
2726        MIPSAssembler::revertJumpToMove(instructionStart.dataLocation(), immTempRegister, reinterpret_cast<int>(initialValue) & 0xffff);
2727    }
2728
2729    static CodeLocationLabel startOfPatchableBranchPtrWithPatchOnAddress(CodeLocationDataLabelPtr)
2730    {
2731        UNREACHABLE_FOR_PLATFORM();
2732        return CodeLocationLabel();
2733    }
2734
2735    static void revertJumpReplacementToPatchableBranchPtrWithPatch(CodeLocationLabel instructionStart, Address, void* initialValue)
2736    {
2737        UNREACHABLE_FOR_PLATFORM();
2738    }
2739
2740
2741private:
2742    // If m_fixedWidth is true, we will generate a fixed number of instructions.
2743    // Otherwise, we can emit any number of instructions.
2744    bool m_fixedWidth;
2745
2746    friend class LinkBuffer;
2747    friend class RepatchBuffer;
2748
2749    static void linkCall(void* code, Call call, FunctionPtr function)
2750    {
2751        MIPSAssembler::linkCall(code, call.m_label, function.value());
2752    }
2753
2754    static void repatchCall(CodeLocationCall call, CodeLocationLabel destination)
2755    {
2756        MIPSAssembler::relinkCall(call.dataLocation(), destination.executableAddress());
2757    }
2758
2759    static void repatchCall(CodeLocationCall call, FunctionPtr destination)
2760    {
2761        MIPSAssembler::relinkCall(call.dataLocation(), destination.executableAddress());
2762    }
2763
2764};
2765
2766}
2767
2768#endif // ENABLE(ASSEMBLER) && CPU(MIPS)
2769
2770#endif // MacroAssemblerMIPS_h
2771