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 const Scale ScalePtr = TimesFour;
47
48    // For storing immediate number
49    static const RegisterID immTempRegister = MIPSRegisters::t0;
50    // For storing data loaded from the memory
51    static const RegisterID dataTempRegister = MIPSRegisters::t1;
52    // For storing address base
53    static const RegisterID addrTempRegister = MIPSRegisters::t2;
54    // For storing compare result
55    static const RegisterID cmpTempRegister = MIPSRegisters::t3;
56
57    // FP temp register
58    static const FPRegisterID fpTempRegister = MIPSRegisters::f16;
59
60    enum Condition {
61        Equal,
62        NotEqual,
63        Above,
64        AboveOrEqual,
65        Below,
66        BelowOrEqual,
67        GreaterThan,
68        GreaterThanOrEqual,
69        LessThan,
70        LessThanOrEqual,
71        Overflow,
72        Signed,
73        Zero,
74        NonZero
75    };
76
77    enum DoubleCondition {
78        DoubleEqual,
79        DoubleNotEqual,
80        DoubleGreaterThan,
81        DoubleGreaterThanOrEqual,
82        DoubleLessThan,
83        DoubleLessThanOrEqual,
84        DoubleEqualOrUnordered,
85        DoubleNotEqualOrUnordered,
86        DoubleGreaterThanOrUnordered,
87        DoubleGreaterThanOrEqualOrUnordered,
88        DoubleLessThanOrUnordered,
89        DoubleLessThanOrEqualOrUnordered
90    };
91
92    static const RegisterID stackPointerRegister = MIPSRegisters::sp;
93    static const RegisterID returnAddressRegister = MIPSRegisters::ra;
94
95    // Integer arithmetic operations:
96    //
97    // Operations are typically two operand - operation(source, srcDst)
98    // For many operations the source may be an TrustedImm32, the srcDst operand
99    // may often be a memory location (explictly described using an Address
100    // object).
101
102    void add32(RegisterID src, RegisterID dest)
103    {
104        m_assembler.addu(dest, dest, src);
105    }
106
107    void add32(TrustedImm32 imm, RegisterID dest)
108    {
109        add32(imm, dest, dest);
110    }
111
112    void add32(TrustedImm32 imm, RegisterID src, RegisterID dest)
113    {
114        if (!imm.m_isPointer && imm.m_value >= -32768 && imm.m_value <= 32767
115            && !m_fixedWidth) {
116            /*
117              addiu     dest, src, imm
118            */
119            m_assembler.addiu(dest, src, imm.m_value);
120        } else {
121            /*
122              li        immTemp, imm
123              addu      dest, src, immTemp
124            */
125            move(imm, immTempRegister);
126            m_assembler.addu(dest, src, immTempRegister);
127        }
128    }
129
130    void add32(TrustedImm32 imm, Address address)
131    {
132        if (address.offset >= -32768 && address.offset <= 32767
133            && !m_fixedWidth) {
134            /*
135              lw        dataTemp, offset(base)
136              li        immTemp, imm
137              addu      dataTemp, dataTemp, immTemp
138              sw        dataTemp, offset(base)
139            */
140            m_assembler.lw(dataTempRegister, address.base, address.offset);
141            if (!imm.m_isPointer
142                && imm.m_value >= -32768 && imm.m_value <= 32767
143                && !m_fixedWidth)
144                m_assembler.addiu(dataTempRegister, dataTempRegister,
145                                  imm.m_value);
146            else {
147                move(imm, immTempRegister);
148                m_assembler.addu(dataTempRegister, dataTempRegister,
149                                 immTempRegister);
150            }
151            m_assembler.sw(dataTempRegister, address.base, address.offset);
152        } else {
153            /*
154              lui       addrTemp, (offset + 0x8000) >> 16
155              addu      addrTemp, addrTemp, base
156              lw        dataTemp, (offset & 0xffff)(addrTemp)
157              li        immtemp, imm
158              addu      dataTemp, dataTemp, immTemp
159              sw        dataTemp, (offset & 0xffff)(addrTemp)
160            */
161            m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16);
162            m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
163            m_assembler.lw(dataTempRegister, addrTempRegister, address.offset);
164
165            if (imm.m_value >= -32768 && imm.m_value <= 32767 && !m_fixedWidth)
166                m_assembler.addiu(dataTempRegister, dataTempRegister,
167                                  imm.m_value);
168            else {
169                move(imm, immTempRegister);
170                m_assembler.addu(dataTempRegister, dataTempRegister,
171                                 immTempRegister);
172            }
173            m_assembler.sw(dataTempRegister, addrTempRegister, address.offset);
174        }
175    }
176
177    void add32(Address src, RegisterID dest)
178    {
179        load32(src, dataTempRegister);
180        add32(dataTempRegister, dest);
181    }
182
183    void add32(RegisterID src, Address dest)
184    {
185        if (dest.offset >= -32768 && dest.offset <= 32767 && !m_fixedWidth) {
186            /*
187              lw        dataTemp, offset(base)
188              addu      dataTemp, dataTemp, src
189              sw        dataTemp, offset(base)
190            */
191            m_assembler.lw(dataTempRegister, dest.base, dest.offset);
192            m_assembler.addu(dataTempRegister, dataTempRegister, src);
193            m_assembler.sw(dataTempRegister, dest.base, dest.offset);
194        } else {
195            /*
196              lui       addrTemp, (offset + 0x8000) >> 16
197              addu      addrTemp, addrTemp, base
198              lw        dataTemp, (offset & 0xffff)(addrTemp)
199              addu      dataTemp, dataTemp, src
200              sw        dataTemp, (offset & 0xffff)(addrTemp)
201            */
202            m_assembler.lui(addrTempRegister, (dest.offset + 0x8000) >> 16);
203            m_assembler.addu(addrTempRegister, addrTempRegister, dest.base);
204            m_assembler.lw(dataTempRegister, addrTempRegister, dest.offset);
205            m_assembler.addu(dataTempRegister, dataTempRegister, src);
206            m_assembler.sw(dataTempRegister, addrTempRegister, dest.offset);
207        }
208    }
209
210    void add32(TrustedImm32 imm, AbsoluteAddress address)
211    {
212        /*
213           li   addrTemp, address
214           li   immTemp, imm
215           lw   dataTemp, 0(addrTemp)
216           addu dataTemp, dataTemp, immTemp
217           sw   dataTemp, 0(addrTemp)
218        */
219        move(TrustedImmPtr(address.m_ptr), addrTempRegister);
220        m_assembler.lw(dataTempRegister, addrTempRegister, 0);
221        if (!imm.m_isPointer && imm.m_value >= -32768 && imm.m_value <= 32767
222            && !m_fixedWidth)
223            m_assembler.addiu(dataTempRegister, dataTempRegister, imm.m_value);
224        else {
225            move(imm, immTempRegister);
226            m_assembler.addu(dataTempRegister, dataTempRegister, immTempRegister);
227        }
228        m_assembler.sw(dataTempRegister, addrTempRegister, 0);
229    }
230
231    void and32(RegisterID src, RegisterID dest)
232    {
233        m_assembler.andInsn(dest, dest, src);
234    }
235
236    void and32(TrustedImm32 imm, RegisterID dest)
237    {
238        if (!imm.m_isPointer && !imm.m_value && !m_fixedWidth)
239            move(MIPSRegisters::zero, dest);
240        else if (!imm.m_isPointer && imm.m_value > 0 && imm.m_value < 65535
241                 && !m_fixedWidth)
242            m_assembler.andi(dest, dest, imm.m_value);
243        else {
244            /*
245              li        immTemp, imm
246              and       dest, dest, immTemp
247            */
248            move(imm, immTempRegister);
249            m_assembler.andInsn(dest, dest, immTempRegister);
250        }
251    }
252
253    void lshift32(TrustedImm32 imm, RegisterID dest)
254    {
255        m_assembler.sll(dest, dest, imm.m_value);
256    }
257
258    void lshift32(RegisterID shiftAmount, RegisterID dest)
259    {
260        m_assembler.sllv(dest, dest, shiftAmount);
261    }
262
263    void mul32(RegisterID src, RegisterID dest)
264    {
265        m_assembler.mul(dest, dest, src);
266    }
267
268    void mul32(TrustedImm32 imm, RegisterID src, RegisterID dest)
269    {
270        if (!imm.m_isPointer && !imm.m_value && !m_fixedWidth)
271            move(MIPSRegisters::zero, dest);
272        else if (!imm.m_isPointer && imm.m_value == 1 && !m_fixedWidth)
273            move(src, dest);
274        else {
275            /*
276                li      dataTemp, imm
277                mul     dest, src, dataTemp
278            */
279            move(imm, dataTempRegister);
280            m_assembler.mul(dest, src, dataTempRegister);
281        }
282    }
283
284    void neg32(RegisterID srcDest)
285    {
286        m_assembler.subu(srcDest, MIPSRegisters::zero, srcDest);
287    }
288
289    void not32(RegisterID srcDest)
290    {
291        m_assembler.nor(srcDest, srcDest, MIPSRegisters::zero);
292    }
293
294    void or32(RegisterID src, RegisterID dest)
295    {
296        m_assembler.orInsn(dest, dest, src);
297    }
298
299    void or32(TrustedImm32 imm, RegisterID dest)
300    {
301        if (!imm.m_isPointer && !imm.m_value && !m_fixedWidth)
302            return;
303
304        if (!imm.m_isPointer && imm.m_value > 0 && imm.m_value < 65535
305            && !m_fixedWidth) {
306            m_assembler.ori(dest, dest, imm.m_value);
307            return;
308        }
309
310        /*
311            li      dataTemp, imm
312            or      dest, dest, dataTemp
313        */
314        move(imm, dataTempRegister);
315        m_assembler.orInsn(dest, dest, dataTempRegister);
316    }
317
318    void rshift32(RegisterID shiftAmount, RegisterID dest)
319    {
320        m_assembler.srav(dest, dest, shiftAmount);
321    }
322
323    void rshift32(TrustedImm32 imm, RegisterID dest)
324    {
325        m_assembler.sra(dest, dest, imm.m_value);
326    }
327
328    void urshift32(RegisterID shiftAmount, RegisterID dest)
329    {
330        m_assembler.srlv(dest, dest, shiftAmount);
331    }
332
333    void urshift32(TrustedImm32 imm, RegisterID dest)
334    {
335        m_assembler.srl(dest, dest, imm.m_value);
336    }
337
338    void sub32(RegisterID src, RegisterID dest)
339    {
340        m_assembler.subu(dest, dest, src);
341    }
342
343    void sub32(TrustedImm32 imm, RegisterID dest)
344    {
345        if (!imm.m_isPointer && imm.m_value >= -32767 && imm.m_value <= 32768
346            && !m_fixedWidth) {
347            /*
348              addiu     dest, src, imm
349            */
350            m_assembler.addiu(dest, dest, -imm.m_value);
351        } else {
352            /*
353              li        immTemp, imm
354              subu      dest, src, immTemp
355            */
356            move(imm, immTempRegister);
357            m_assembler.subu(dest, dest, immTempRegister);
358        }
359    }
360
361    void sub32(TrustedImm32 imm, Address address)
362    {
363        if (address.offset >= -32768 && address.offset <= 32767
364            && !m_fixedWidth) {
365            /*
366              lw        dataTemp, offset(base)
367              li        immTemp, imm
368              subu      dataTemp, dataTemp, immTemp
369              sw        dataTemp, offset(base)
370            */
371            m_assembler.lw(dataTempRegister, address.base, address.offset);
372            if (!imm.m_isPointer
373                && imm.m_value >= -32767 && imm.m_value <= 32768
374                && !m_fixedWidth)
375                m_assembler.addiu(dataTempRegister, dataTempRegister,
376                                  -imm.m_value);
377            else {
378                move(imm, immTempRegister);
379                m_assembler.subu(dataTempRegister, dataTempRegister,
380                                 immTempRegister);
381            }
382            m_assembler.sw(dataTempRegister, address.base, address.offset);
383        } else {
384            /*
385              lui       addrTemp, (offset + 0x8000) >> 16
386              addu      addrTemp, addrTemp, base
387              lw        dataTemp, (offset & 0xffff)(addrTemp)
388              li        immtemp, imm
389              subu      dataTemp, dataTemp, immTemp
390              sw        dataTemp, (offset & 0xffff)(addrTemp)
391            */
392            m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16);
393            m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
394            m_assembler.lw(dataTempRegister, addrTempRegister, address.offset);
395
396            if (!imm.m_isPointer
397                && imm.m_value >= -32767 && imm.m_value <= 32768
398                && !m_fixedWidth)
399                m_assembler.addiu(dataTempRegister, dataTempRegister,
400                                  -imm.m_value);
401            else {
402                move(imm, immTempRegister);
403                m_assembler.subu(dataTempRegister, dataTempRegister,
404                                 immTempRegister);
405            }
406            m_assembler.sw(dataTempRegister, addrTempRegister, address.offset);
407        }
408    }
409
410    void sub32(Address src, RegisterID dest)
411    {
412        load32(src, dataTempRegister);
413        sub32(dataTempRegister, dest);
414    }
415
416    void sub32(TrustedImm32 imm, AbsoluteAddress address)
417    {
418        /*
419           li   addrTemp, address
420           li   immTemp, imm
421           lw   dataTemp, 0(addrTemp)
422           subu dataTemp, dataTemp, immTemp
423           sw   dataTemp, 0(addrTemp)
424        */
425        move(TrustedImmPtr(address.m_ptr), addrTempRegister);
426        m_assembler.lw(dataTempRegister, addrTempRegister, 0);
427
428        if (!imm.m_isPointer && imm.m_value >= -32767 && imm.m_value <= 32768
429            && !m_fixedWidth) {
430            m_assembler.addiu(dataTempRegister, dataTempRegister,
431                              -imm.m_value);
432        } else {
433            move(imm, immTempRegister);
434            m_assembler.subu(dataTempRegister, dataTempRegister, immTempRegister);
435        }
436        m_assembler.sw(dataTempRegister, addrTempRegister, 0);
437    }
438
439    void xor32(RegisterID src, RegisterID dest)
440    {
441        m_assembler.xorInsn(dest, dest, src);
442    }
443
444    void xor32(TrustedImm32 imm, RegisterID dest)
445    {
446        /*
447            li  immTemp, imm
448            xor dest, dest, immTemp
449        */
450        move(imm, immTempRegister);
451        m_assembler.xorInsn(dest, dest, immTempRegister);
452    }
453
454    void sqrtDouble(FPRegisterID src, FPRegisterID dst)
455    {
456        m_assembler.sqrtd(dst, src);
457    }
458
459    // Memory access operations:
460    //
461    // Loads are of the form load(address, destination) and stores of the form
462    // store(source, address).  The source for a store may be an TrustedImm32.  Address
463    // operand objects to loads and store will be implicitly constructed if a
464    // register is passed.
465
466    /* Need to use zero-extened load byte for load8.  */
467    void load8(ImplicitAddress address, RegisterID dest)
468    {
469        if (address.offset >= -32768 && address.offset <= 32767
470            && !m_fixedWidth)
471            m_assembler.lbu(dest, address.base, address.offset);
472        else {
473            /*
474                lui     addrTemp, (offset + 0x8000) >> 16
475                addu    addrTemp, addrTemp, base
476                lbu     dest, (offset & 0xffff)(addrTemp)
477              */
478            m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16);
479            m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
480            m_assembler.lbu(dest, addrTempRegister, address.offset);
481        }
482    }
483
484    void load32(ImplicitAddress address, RegisterID dest)
485    {
486        if (address.offset >= -32768 && address.offset <= 32767
487            && !m_fixedWidth)
488            m_assembler.lw(dest, address.base, address.offset);
489        else {
490            /*
491                lui     addrTemp, (offset + 0x8000) >> 16
492                addu    addrTemp, addrTemp, base
493                lw      dest, (offset & 0xffff)(addrTemp)
494              */
495            m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16);
496            m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
497            m_assembler.lw(dest, addrTempRegister, address.offset);
498        }
499    }
500
501    void load32(BaseIndex address, RegisterID dest)
502    {
503        if (address.offset >= -32768 && address.offset <= 32767
504            && !m_fixedWidth) {
505            /*
506                sll     addrTemp, address.index, address.scale
507                addu    addrTemp, addrTemp, address.base
508                lw      dest, address.offset(addrTemp)
509            */
510            m_assembler.sll(addrTempRegister, address.index, address.scale);
511            m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
512            m_assembler.lw(dest, addrTempRegister, address.offset);
513        } else {
514            /*
515                sll     addrTemp, address.index, address.scale
516                addu    addrTemp, addrTemp, address.base
517                lui     immTemp, (address.offset + 0x8000) >> 16
518                addu    addrTemp, addrTemp, immTemp
519                lw      dest, (address.offset & 0xffff)(at)
520            */
521            m_assembler.sll(addrTempRegister, address.index, address.scale);
522            m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
523            m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16);
524            m_assembler.addu(addrTempRegister, addrTempRegister,
525                             immTempRegister);
526            m_assembler.lw(dest, addrTempRegister, address.offset);
527        }
528    }
529
530    void load32WithUnalignedHalfWords(BaseIndex address, RegisterID dest)
531    {
532        if (address.offset >= -32768 && address.offset <= 32764
533            && !m_fixedWidth) {
534            /*
535                sll     addrTemp, address.index, address.scale
536                addu    addrTemp, addrTemp, address.base
537                (Big-Endian)
538                lwl     dest, address.offset(addrTemp)
539                lwr     dest, address.offset+3(addrTemp)
540                (Little-Endian)
541                lwl     dest, address.offset+3(addrTemp)
542                lwr     dest, address.offset(addrTemp)
543            */
544            m_assembler.sll(addrTempRegister, address.index, address.scale);
545            m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
546#if CPU(BIG_ENDIAN)
547            m_assembler.lwl(dest, addrTempRegister, address.offset);
548            m_assembler.lwr(dest, addrTempRegister, address.offset + 3);
549#else
550            m_assembler.lwl(dest, addrTempRegister, address.offset + 3);
551            m_assembler.lwr(dest, addrTempRegister, address.offset);
552
553#endif
554        } else {
555            /*
556                sll     addrTemp, address.index, address.scale
557                addu    addrTemp, addrTemp, address.base
558                lui     immTemp, address.offset >> 16
559                ori     immTemp, immTemp, address.offset & 0xffff
560                addu    addrTemp, addrTemp, immTemp
561                (Big-Endian)
562                lw      dest, 0(at)
563                lw      dest, 3(at)
564                (Little-Endian)
565                lw      dest, 3(at)
566                lw      dest, 0(at)
567            */
568            m_assembler.sll(addrTempRegister, address.index, address.scale);
569            m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
570            m_assembler.lui(immTempRegister, address.offset >> 16);
571            m_assembler.ori(immTempRegister, immTempRegister, address.offset);
572            m_assembler.addu(addrTempRegister, addrTempRegister,
573                             immTempRegister);
574#if CPU(BIG_ENDIAN)
575            m_assembler.lwl(dest, addrTempRegister, 0);
576            m_assembler.lwr(dest, addrTempRegister, 3);
577#else
578            m_assembler.lwl(dest, addrTempRegister, 3);
579            m_assembler.lwr(dest, addrTempRegister, 0);
580#endif
581        }
582    }
583
584    void load32(const void* address, RegisterID dest)
585    {
586        /*
587            li  addrTemp, address
588            lw  dest, 0(addrTemp)
589        */
590        move(TrustedImmPtr(address), addrTempRegister);
591        m_assembler.lw(dest, addrTempRegister, 0);
592    }
593
594    DataLabel32 load32WithAddressOffsetPatch(Address address, RegisterID dest)
595    {
596        m_fixedWidth = true;
597        /*
598            lui addrTemp, address.offset >> 16
599            ori addrTemp, addrTemp, address.offset & 0xffff
600            addu        addrTemp, addrTemp, address.base
601            lw  dest, 0(addrTemp)
602        */
603        DataLabel32 dataLabel(this);
604        move(TrustedImm32(address.offset), addrTempRegister);
605        m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
606        m_assembler.lw(dest, addrTempRegister, 0);
607        m_fixedWidth = false;
608        return dataLabel;
609    }
610
611    /* Need to use zero-extened load half-word for load16.  */
612    void load16(ImplicitAddress address, RegisterID dest)
613    {
614        if (address.offset >= -32768 && address.offset <= 32767
615            && !m_fixedWidth)
616            m_assembler.lhu(dest, address.base, address.offset);
617        else {
618            /*
619                lui     addrTemp, (offset + 0x8000) >> 16
620                addu    addrTemp, addrTemp, base
621                lhu     dest, (offset & 0xffff)(addrTemp)
622              */
623            m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16);
624            m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
625            m_assembler.lhu(dest, addrTempRegister, address.offset);
626        }
627    }
628
629    /* Need to use zero-extened load half-word for load16.  */
630    void load16(BaseIndex address, RegisterID dest)
631    {
632        if (address.offset >= -32768 && address.offset <= 32767
633            && !m_fixedWidth) {
634            /*
635                sll     addrTemp, address.index, address.scale
636                addu    addrTemp, addrTemp, address.base
637                lhu     dest, address.offset(addrTemp)
638            */
639            m_assembler.sll(addrTempRegister, address.index, address.scale);
640            m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
641            m_assembler.lhu(dest, addrTempRegister, address.offset);
642        } else {
643            /*
644                sll     addrTemp, address.index, address.scale
645                addu    addrTemp, addrTemp, address.base
646                lui     immTemp, (address.offset + 0x8000) >> 16
647                addu    addrTemp, addrTemp, immTemp
648                lhu     dest, (address.offset & 0xffff)(addrTemp)
649            */
650            m_assembler.sll(addrTempRegister, address.index, address.scale);
651            m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
652            m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16);
653            m_assembler.addu(addrTempRegister, addrTempRegister,
654                             immTempRegister);
655            m_assembler.lhu(dest, addrTempRegister, address.offset);
656        }
657    }
658
659    DataLabel32 store32WithAddressOffsetPatch(RegisterID src, Address address)
660    {
661        m_fixedWidth = true;
662        /*
663            lui addrTemp, address.offset >> 16
664            ori addrTemp, addrTemp, address.offset & 0xffff
665            addu        addrTemp, addrTemp, address.base
666            sw  src, 0(addrTemp)
667        */
668        DataLabel32 dataLabel(this);
669        move(TrustedImm32(address.offset), addrTempRegister);
670        m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
671        m_assembler.sw(src, addrTempRegister, 0);
672        m_fixedWidth = false;
673        return dataLabel;
674    }
675
676    void store32(RegisterID src, ImplicitAddress address)
677    {
678        if (address.offset >= -32768 && address.offset <= 32767
679            && !m_fixedWidth)
680            m_assembler.sw(src, address.base, address.offset);
681        else {
682            /*
683                lui     addrTemp, (offset + 0x8000) >> 16
684                addu    addrTemp, addrTemp, base
685                sw      src, (offset & 0xffff)(addrTemp)
686              */
687            m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16);
688            m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
689            m_assembler.sw(src, addrTempRegister, address.offset);
690        }
691    }
692
693    void store32(RegisterID src, BaseIndex address)
694    {
695        if (address.offset >= -32768 && address.offset <= 32767
696            && !m_fixedWidth) {
697            /*
698                sll     addrTemp, address.index, address.scale
699                addu    addrTemp, addrTemp, address.base
700                sw      src, address.offset(addrTemp)
701            */
702            m_assembler.sll(addrTempRegister, address.index, address.scale);
703            m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
704            m_assembler.sw(src, addrTempRegister, address.offset);
705        } else {
706            /*
707                sll     addrTemp, address.index, address.scale
708                addu    addrTemp, addrTemp, address.base
709                lui     immTemp, (address.offset + 0x8000) >> 16
710                addu    addrTemp, addrTemp, immTemp
711                sw      src, (address.offset & 0xffff)(at)
712            */
713            m_assembler.sll(addrTempRegister, address.index, address.scale);
714            m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
715            m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16);
716            m_assembler.addu(addrTempRegister, addrTempRegister,
717                             immTempRegister);
718            m_assembler.sw(src, addrTempRegister, address.offset);
719        }
720    }
721
722    void store32(TrustedImm32 imm, ImplicitAddress address)
723    {
724        if (address.offset >= -32768 && address.offset <= 32767
725            && !m_fixedWidth) {
726            if (!imm.m_isPointer && !imm.m_value)
727                m_assembler.sw(MIPSRegisters::zero, address.base,
728                               address.offset);
729            else {
730                move(imm, immTempRegister);
731                m_assembler.sw(immTempRegister, address.base, address.offset);
732            }
733        } else {
734            /*
735                lui     addrTemp, (offset + 0x8000) >> 16
736                addu    addrTemp, addrTemp, base
737                sw      immTemp, (offset & 0xffff)(addrTemp)
738              */
739            m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16);
740            m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
741            if (!imm.m_isPointer && !imm.m_value && !m_fixedWidth)
742                m_assembler.sw(MIPSRegisters::zero, addrTempRegister,
743                               address.offset);
744            else {
745                move(imm, immTempRegister);
746                m_assembler.sw(immTempRegister, addrTempRegister,
747                               address.offset);
748            }
749        }
750    }
751
752    void store32(RegisterID src, const void* address)
753    {
754        /*
755            li  addrTemp, address
756            sw  src, 0(addrTemp)
757        */
758        move(TrustedImmPtr(address), addrTempRegister);
759        m_assembler.sw(src, addrTempRegister, 0);
760    }
761
762    void store32(TrustedImm32 imm, const void* address)
763    {
764        /*
765            li  immTemp, imm
766            li  addrTemp, address
767            sw  src, 0(addrTemp)
768        */
769        if (!imm.m_isPointer && !imm.m_value && !m_fixedWidth) {
770            move(TrustedImmPtr(address), addrTempRegister);
771            m_assembler.sw(MIPSRegisters::zero, addrTempRegister, 0);
772        } else {
773            move(imm, immTempRegister);
774            move(TrustedImmPtr(address), addrTempRegister);
775            m_assembler.sw(immTempRegister, addrTempRegister, 0);
776        }
777    }
778
779    // Floating-point operations:
780
781    bool supportsFloatingPoint() const
782    {
783#if WTF_MIPS_DOUBLE_FLOAT
784        return true;
785#else
786        return false;
787#endif
788    }
789
790    bool supportsFloatingPointTruncate() const
791    {
792#if WTF_MIPS_DOUBLE_FLOAT && WTF_MIPS_ISA_AT_LEAST(2)
793        return true;
794#else
795        return false;
796#endif
797    }
798
799    bool supportsFloatingPointSqrt() const
800    {
801#if WTF_MIPS_DOUBLE_FLOAT && WTF_MIPS_ISA_AT_LEAST(2)
802        return true;
803#else
804        return false;
805#endif
806    }
807
808    // Stack manipulation operations:
809    //
810    // The ABI is assumed to provide a stack abstraction to memory,
811    // containing machine word sized units of data.  Push and pop
812    // operations add and remove a single register sized unit of data
813    // to or from the stack.  Peek and poke operations read or write
814    // values on the stack, without moving the current stack position.
815
816    void pop(RegisterID dest)
817    {
818        m_assembler.lw(dest, MIPSRegisters::sp, 0);
819        m_assembler.addiu(MIPSRegisters::sp, MIPSRegisters::sp, 4);
820    }
821
822    void push(RegisterID src)
823    {
824        m_assembler.addiu(MIPSRegisters::sp, MIPSRegisters::sp, -4);
825        m_assembler.sw(src, MIPSRegisters::sp, 0);
826    }
827
828    void push(Address address)
829    {
830        load32(address, dataTempRegister);
831        push(dataTempRegister);
832    }
833
834    void push(TrustedImm32 imm)
835    {
836        move(imm, immTempRegister);
837        push(immTempRegister);
838    }
839
840    // Register move operations:
841    //
842    // Move values in registers.
843
844    void move(TrustedImm32 imm, RegisterID dest)
845    {
846        if (!imm.m_isPointer && !imm.m_value && !m_fixedWidth)
847            move(MIPSRegisters::zero, dest);
848        else if (imm.m_isPointer || m_fixedWidth) {
849            m_assembler.lui(dest, imm.m_value >> 16);
850            m_assembler.ori(dest, dest, imm.m_value);
851        } else
852            m_assembler.li(dest, imm.m_value);
853    }
854
855    void move(RegisterID src, RegisterID dest)
856    {
857        if (src != dest || m_fixedWidth)
858            m_assembler.move(dest, src);
859    }
860
861    void move(TrustedImmPtr imm, RegisterID dest)
862    {
863        move(TrustedImm32(imm), dest);
864    }
865
866    void swap(RegisterID reg1, RegisterID reg2)
867    {
868        move(reg1, immTempRegister);
869        move(reg2, reg1);
870        move(immTempRegister, reg2);
871    }
872
873    void signExtend32ToPtr(RegisterID src, RegisterID dest)
874    {
875        if (src != dest || m_fixedWidth)
876            move(src, dest);
877    }
878
879    void zeroExtend32ToPtr(RegisterID src, RegisterID dest)
880    {
881        if (src != dest || m_fixedWidth)
882            move(src, dest);
883    }
884
885    // Forwards / external control flow operations:
886    //
887    // This set of jump and conditional branch operations return a Jump
888    // object which may linked at a later point, allow forwards jump,
889    // or jumps that will require external linkage (after the code has been
890    // relocated).
891    //
892    // For branches, signed <, >, <= and >= are denoted as l, g, le, and ge
893    // respecitvely, for unsigned comparisons the names b, a, be, and ae are
894    // used (representing the names 'below' and 'above').
895    //
896    // Operands to the comparision are provided in the expected order, e.g.
897    // jle32(reg1, TrustedImm32(5)) will branch if the value held in reg1, when
898    // treated as a signed 32bit value, is less than or equal to 5.
899    //
900    // jz and jnz test whether the first operand is equal to zero, and take
901    // an optional second operand of a mask under which to perform the test.
902
903    Jump branch8(Condition cond, Address left, TrustedImm32 right)
904    {
905        // Make sure the immediate value is unsigned 8 bits.
906        ASSERT(!(right.m_value & 0xFFFFFF00));
907        load8(left, dataTempRegister);
908        move(right, immTempRegister);
909        return branch32(cond, dataTempRegister, immTempRegister);
910    }
911
912    Jump branch32(Condition cond, RegisterID left, RegisterID right)
913    {
914        if (cond == Equal || cond == Zero)
915            return branchEqual(left, right);
916        if (cond == NotEqual || cond == NonZero)
917            return branchNotEqual(left, right);
918        if (cond == Above) {
919            m_assembler.sltu(cmpTempRegister, right, left);
920            return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
921        }
922        if (cond == AboveOrEqual) {
923            m_assembler.sltu(cmpTempRegister, left, right);
924            return branchEqual(cmpTempRegister, MIPSRegisters::zero);
925        }
926        if (cond == Below) {
927            m_assembler.sltu(cmpTempRegister, left, right);
928            return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
929        }
930        if (cond == BelowOrEqual) {
931            m_assembler.sltu(cmpTempRegister, right, left);
932            return branchEqual(cmpTempRegister, MIPSRegisters::zero);
933        }
934        if (cond == GreaterThan) {
935            m_assembler.slt(cmpTempRegister, right, left);
936            return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
937        }
938        if (cond == GreaterThanOrEqual) {
939            m_assembler.slt(cmpTempRegister, left, right);
940            return branchEqual(cmpTempRegister, MIPSRegisters::zero);
941        }
942        if (cond == LessThan) {
943            m_assembler.slt(cmpTempRegister, left, right);
944            return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
945        }
946        if (cond == LessThanOrEqual) {
947            m_assembler.slt(cmpTempRegister, right, left);
948            return branchEqual(cmpTempRegister, MIPSRegisters::zero);
949        }
950        if (cond == Overflow) {
951            /*
952                xor     cmpTemp, left, right
953                bgez    No_overflow, cmpTemp    # same sign bit -> no overflow
954                nop
955                subu    cmpTemp, left, right
956                xor     cmpTemp, cmpTemp, left
957                bgez    No_overflow, cmpTemp    # same sign bit -> no overflow
958                nop
959                b       Overflow
960                nop
961                nop
962                nop
963                nop
964                nop
965              No_overflow:
966            */
967            m_assembler.xorInsn(cmpTempRegister, left, right);
968            m_assembler.bgez(cmpTempRegister, 11);
969            m_assembler.nop();
970            m_assembler.subu(cmpTempRegister, left, right);
971            m_assembler.xorInsn(cmpTempRegister, cmpTempRegister, left);
972            m_assembler.bgez(cmpTempRegister, 7);
973            m_assembler.nop();
974            return jump();
975        }
976        if (cond == Signed) {
977            m_assembler.subu(cmpTempRegister, left, right);
978            // Check if the result is negative.
979            m_assembler.slt(cmpTempRegister, cmpTempRegister,
980                            MIPSRegisters::zero);
981            return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
982        }
983        ASSERT(0);
984
985        return Jump();
986    }
987
988    Jump branch32(Condition cond, RegisterID left, TrustedImm32 right)
989    {
990        move(right, immTempRegister);
991        return branch32(cond, left, immTempRegister);
992    }
993
994    Jump branch32(Condition cond, RegisterID left, Address right)
995    {
996        load32(right, dataTempRegister);
997        return branch32(cond, left, dataTempRegister);
998    }
999
1000    Jump branch32(Condition cond, Address left, RegisterID right)
1001    {
1002        load32(left, dataTempRegister);
1003        return branch32(cond, dataTempRegister, right);
1004    }
1005
1006    Jump branch32(Condition cond, Address left, TrustedImm32 right)
1007    {
1008        load32(left, dataTempRegister);
1009        move(right, immTempRegister);
1010        return branch32(cond, dataTempRegister, immTempRegister);
1011    }
1012
1013    Jump branch32(Condition cond, BaseIndex left, TrustedImm32 right)
1014    {
1015        load32(left, dataTempRegister);
1016        // Be careful that the previous load32() uses immTempRegister.
1017        // So, we need to put move() after load32().
1018        move(right, immTempRegister);
1019        return branch32(cond, dataTempRegister, immTempRegister);
1020    }
1021
1022    Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, TrustedImm32 right)
1023    {
1024        load32WithUnalignedHalfWords(left, dataTempRegister);
1025        // Be careful that the previous load32WithUnalignedHalfWords()
1026        // uses immTempRegister.
1027        // So, we need to put move() after load32WithUnalignedHalfWords().
1028        move(right, immTempRegister);
1029        return branch32(cond, dataTempRegister, immTempRegister);
1030    }
1031
1032    Jump branch32(Condition cond, AbsoluteAddress left, RegisterID right)
1033    {
1034        load32(left.m_ptr, dataTempRegister);
1035        return branch32(cond, dataTempRegister, right);
1036    }
1037
1038    Jump branch32(Condition cond, AbsoluteAddress left, TrustedImm32 right)
1039    {
1040        load32(left.m_ptr, dataTempRegister);
1041        move(right, immTempRegister);
1042        return branch32(cond, dataTempRegister, immTempRegister);
1043    }
1044
1045    Jump branch16(Condition cond, BaseIndex left, RegisterID right)
1046    {
1047        load16(left, dataTempRegister);
1048        return branch32(cond, dataTempRegister, right);
1049    }
1050
1051    Jump branch16(Condition cond, BaseIndex left, TrustedImm32 right)
1052    {
1053        ASSERT(!(right.m_value & 0xFFFF0000));
1054        load16(left, dataTempRegister);
1055        // Be careful that the previous load16() uses immTempRegister.
1056        // So, we need to put move() after load16().
1057        move(right, immTempRegister);
1058        return branch32(cond, dataTempRegister, immTempRegister);
1059    }
1060
1061    Jump branchTest32(Condition cond, RegisterID reg, RegisterID mask)
1062    {
1063        ASSERT((cond == Zero) || (cond == NonZero));
1064        m_assembler.andInsn(cmpTempRegister, reg, mask);
1065        if (cond == Zero)
1066            return branchEqual(cmpTempRegister, MIPSRegisters::zero);
1067        return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
1068    }
1069
1070    Jump branchTest32(Condition cond, RegisterID reg, TrustedImm32 mask = TrustedImm32(-1))
1071    {
1072        ASSERT((cond == Zero) || (cond == NonZero));
1073        if (mask.m_value == -1 && !m_fixedWidth) {
1074            if (cond == Zero)
1075                return branchEqual(reg, MIPSRegisters::zero);
1076            return branchNotEqual(reg, MIPSRegisters::zero);
1077        }
1078        move(mask, immTempRegister);
1079        return branchTest32(cond, reg, immTempRegister);
1080    }
1081
1082    Jump branchTest32(Condition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
1083    {
1084        load32(address, dataTempRegister);
1085        return branchTest32(cond, dataTempRegister, mask);
1086    }
1087
1088    Jump branchTest32(Condition cond, BaseIndex address, TrustedImm32 mask = TrustedImm32(-1))
1089    {
1090        load32(address, dataTempRegister);
1091        return branchTest32(cond, dataTempRegister, mask);
1092    }
1093
1094    Jump branchTest8(Condition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
1095    {
1096        load8(address, dataTempRegister);
1097        return branchTest32(cond, dataTempRegister, mask);
1098    }
1099
1100    Jump jump()
1101    {
1102        return branchEqual(MIPSRegisters::zero, MIPSRegisters::zero);
1103    }
1104
1105    void jump(RegisterID target)
1106    {
1107        m_assembler.jr(target);
1108        m_assembler.nop();
1109    }
1110
1111    void jump(Address address)
1112    {
1113        m_fixedWidth = true;
1114        load32(address, MIPSRegisters::t9);
1115        m_assembler.jr(MIPSRegisters::t9);
1116        m_assembler.nop();
1117        m_fixedWidth = false;
1118    }
1119
1120    // Arithmetic control flow operations:
1121    //
1122    // This set of conditional branch operations branch based
1123    // on the result of an arithmetic operation.  The operation
1124    // is performed as normal, storing the result.
1125    //
1126    // * jz operations branch if the result is zero.
1127    // * jo operations branch if the (signed) arithmetic
1128    //   operation caused an overflow to occur.
1129
1130    Jump branchAdd32(Condition cond, RegisterID src, RegisterID dest)
1131    {
1132        ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
1133        if (cond == Overflow) {
1134            /*
1135                move    dest, dataTemp
1136                xor     cmpTemp, dataTemp, src
1137                bltz    cmpTemp, No_overflow    # diff sign bit -> no overflow
1138                addu    dest, dataTemp, src
1139                xor     cmpTemp, dest, dataTemp
1140                bgez    cmpTemp, No_overflow    # same sign big -> no overflow
1141                nop
1142                b       Overflow
1143                nop
1144                nop
1145                nop
1146                nop
1147                nop
1148            No_overflow:
1149            */
1150            move(dest, dataTempRegister);
1151            m_assembler.xorInsn(cmpTempRegister, dataTempRegister, src);
1152            m_assembler.bltz(cmpTempRegister, 10);
1153            m_assembler.addu(dest, dataTempRegister, src);
1154            m_assembler.xorInsn(cmpTempRegister, dest, dataTempRegister);
1155            m_assembler.bgez(cmpTempRegister, 7);
1156            m_assembler.nop();
1157            return jump();
1158        }
1159        if (cond == Signed) {
1160            add32(src, dest);
1161            // Check if dest is negative.
1162            m_assembler.slt(cmpTempRegister, dest, MIPSRegisters::zero);
1163            return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
1164        }
1165        if (cond == Zero) {
1166            add32(src, dest);
1167            return branchEqual(dest, MIPSRegisters::zero);
1168        }
1169        if (cond == NonZero) {
1170            add32(src, dest);
1171            return branchNotEqual(dest, MIPSRegisters::zero);
1172        }
1173        ASSERT(0);
1174        return Jump();
1175    }
1176
1177    Jump branchAdd32(Condition cond, TrustedImm32 imm, RegisterID dest)
1178    {
1179        move(imm, immTempRegister);
1180        return branchAdd32(cond, immTempRegister, dest);
1181    }
1182
1183    Jump branchMul32(Condition cond, RegisterID src, RegisterID dest)
1184    {
1185        ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
1186        if (cond == Overflow) {
1187            /*
1188                mult    src, dest
1189                mfhi    dataTemp
1190                mflo    dest
1191                sra     addrTemp, dest, 31
1192                beq     dataTemp, addrTemp, No_overflow # all sign bits (bit 63 to bit 31) are the same -> no overflow
1193                nop
1194                b       Overflow
1195                nop
1196                nop
1197                nop
1198                nop
1199                nop
1200            No_overflow:
1201            */
1202            m_assembler.mult(src, dest);
1203            m_assembler.mfhi(dataTempRegister);
1204            m_assembler.mflo(dest);
1205            m_assembler.sra(addrTempRegister, dest, 31);
1206            m_assembler.beq(dataTempRegister, addrTempRegister, 7);
1207            m_assembler.nop();
1208            return jump();
1209        }
1210        if (cond == Signed) {
1211            mul32(src, dest);
1212            // Check if dest is negative.
1213            m_assembler.slt(cmpTempRegister, dest, MIPSRegisters::zero);
1214            return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
1215        }
1216        if (cond == Zero) {
1217            mul32(src, dest);
1218            return branchEqual(dest, MIPSRegisters::zero);
1219        }
1220        if (cond == NonZero) {
1221            mul32(src, dest);
1222            return branchNotEqual(dest, MIPSRegisters::zero);
1223        }
1224        ASSERT(0);
1225        return Jump();
1226    }
1227
1228    Jump branchMul32(Condition cond, TrustedImm32 imm, RegisterID src, RegisterID dest)
1229    {
1230        move(imm, immTempRegister);
1231        move(src, dest);
1232        return branchMul32(cond, immTempRegister, dest);
1233    }
1234
1235    Jump branchSub32(Condition cond, RegisterID src, RegisterID dest)
1236    {
1237        ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
1238        if (cond == Overflow) {
1239            /*
1240                move    dest, dataTemp
1241                xor     cmpTemp, dataTemp, src
1242                bgez    cmpTemp, No_overflow    # same sign bit -> no overflow
1243                subu    dest, dataTemp, src
1244                xor     cmpTemp, dest, dataTemp
1245                bgez    cmpTemp, No_overflow    # same sign bit -> no overflow
1246                nop
1247                b       Overflow
1248                nop
1249                nop
1250                nop
1251                nop
1252                nop
1253            No_overflow:
1254            */
1255            move(dest, dataTempRegister);
1256            m_assembler.xorInsn(cmpTempRegister, dataTempRegister, src);
1257            m_assembler.bgez(cmpTempRegister, 10);
1258            m_assembler.subu(dest, dataTempRegister, src);
1259            m_assembler.xorInsn(cmpTempRegister, dest, dataTempRegister);
1260            m_assembler.bgez(cmpTempRegister, 7);
1261            m_assembler.nop();
1262            return jump();
1263        }
1264        if (cond == Signed) {
1265            sub32(src, dest);
1266            // Check if dest is negative.
1267            m_assembler.slt(cmpTempRegister, dest, MIPSRegisters::zero);
1268            return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
1269        }
1270        if (cond == Zero) {
1271            sub32(src, dest);
1272            return branchEqual(dest, MIPSRegisters::zero);
1273        }
1274        if (cond == NonZero) {
1275            sub32(src, dest);
1276            return branchNotEqual(dest, MIPSRegisters::zero);
1277        }
1278        ASSERT(0);
1279        return Jump();
1280    }
1281
1282    Jump branchSub32(Condition cond, TrustedImm32 imm, RegisterID dest)
1283    {
1284        move(imm, immTempRegister);
1285        return branchSub32(cond, immTempRegister, dest);
1286    }
1287
1288    Jump branchOr32(Condition cond, RegisterID src, RegisterID dest)
1289    {
1290        ASSERT((cond == Signed) || (cond == Zero) || (cond == NonZero));
1291        if (cond == Signed) {
1292            or32(src, dest);
1293            // Check if dest is negative.
1294            m_assembler.slt(cmpTempRegister, dest, MIPSRegisters::zero);
1295            return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
1296        }
1297        if (cond == Zero) {
1298            or32(src, dest);
1299            return branchEqual(dest, MIPSRegisters::zero);
1300        }
1301        if (cond == NonZero) {
1302            or32(src, dest);
1303            return branchNotEqual(dest, MIPSRegisters::zero);
1304        }
1305        ASSERT(0);
1306        return Jump();
1307    }
1308
1309    // Miscellaneous operations:
1310
1311    void breakpoint()
1312    {
1313        m_assembler.bkpt();
1314    }
1315
1316    Call nearCall()
1317    {
1318        /* We need two words for relaxation.  */
1319        m_assembler.nop();
1320        m_assembler.nop();
1321        m_assembler.jal();
1322        m_assembler.nop();
1323        return Call(m_assembler.newJmpSrc(), Call::LinkableNear);
1324    }
1325
1326    Call call()
1327    {
1328        m_assembler.lui(MIPSRegisters::t9, 0);
1329        m_assembler.ori(MIPSRegisters::t9, MIPSRegisters::t9, 0);
1330        m_assembler.jalr(MIPSRegisters::t9);
1331        m_assembler.nop();
1332        return Call(m_assembler.newJmpSrc(), Call::Linkable);
1333    }
1334
1335    Call call(RegisterID target)
1336    {
1337        m_assembler.jalr(target);
1338        m_assembler.nop();
1339        return Call(m_assembler.newJmpSrc(), Call::None);
1340    }
1341
1342    Call call(Address address)
1343    {
1344        m_fixedWidth = true;
1345        load32(address, MIPSRegisters::t9);
1346        m_assembler.jalr(MIPSRegisters::t9);
1347        m_assembler.nop();
1348        m_fixedWidth = false;
1349        return Call(m_assembler.newJmpSrc(), Call::None);
1350    }
1351
1352    void ret()
1353    {
1354        m_assembler.jr(MIPSRegisters::ra);
1355        m_assembler.nop();
1356    }
1357
1358    void set8Compare32(Condition cond, RegisterID left, RegisterID right, RegisterID dest)
1359    {
1360        set32Compare32(cond, left, right, dest);
1361    }
1362
1363    void set8Compare32(Condition cond, RegisterID left, TrustedImm32 right, RegisterID dest)
1364    {
1365        move(right, immTempRegister);
1366        set32Compare32(cond, left, immTempRegister, dest);
1367    }
1368
1369    void set32Compare32(Condition cond, RegisterID left, RegisterID right, RegisterID dest)
1370    {
1371        if (cond == Equal || cond == Zero) {
1372            m_assembler.xorInsn(dest, left, right);
1373            m_assembler.sltiu(dest, dest, 1);
1374        } else if (cond == NotEqual || cond == NonZero) {
1375            m_assembler.xorInsn(dest, left, right);
1376            m_assembler.sltu(dest, MIPSRegisters::zero, dest);
1377        } else if (cond == Above)
1378            m_assembler.sltu(dest, right, left);
1379        else if (cond == AboveOrEqual) {
1380            m_assembler.sltu(dest, left, right);
1381            m_assembler.xori(dest, dest, 1);
1382        } else if (cond == Below)
1383            m_assembler.sltu(dest, left, right);
1384        else if (cond == BelowOrEqual) {
1385            m_assembler.sltu(dest, right, left);
1386            m_assembler.xori(dest, dest, 1);
1387        } else if (cond == GreaterThan)
1388            m_assembler.slt(dest, right, left);
1389        else if (cond == GreaterThanOrEqual) {
1390            m_assembler.slt(dest, left, right);
1391            m_assembler.xori(dest, dest, 1);
1392        } else if (cond == LessThan)
1393            m_assembler.slt(dest, left, right);
1394        else if (cond == LessThanOrEqual) {
1395            m_assembler.slt(dest, right, left);
1396            m_assembler.xori(dest, dest, 1);
1397        } else if (cond == Overflow) {
1398            /*
1399                xor     cmpTemp, left, right
1400                bgez    Done, cmpTemp   # same sign bit -> no overflow
1401                move    dest, 0
1402                subu    cmpTemp, left, right
1403                xor     cmpTemp, cmpTemp, left # diff sign bit -> overflow
1404                slt     dest, cmpTemp, 0
1405              Done:
1406            */
1407            m_assembler.xorInsn(cmpTempRegister, left, right);
1408            m_assembler.bgez(cmpTempRegister, 4);
1409            m_assembler.move(dest, MIPSRegisters::zero);
1410            m_assembler.subu(cmpTempRegister, left, right);
1411            m_assembler.xorInsn(cmpTempRegister, cmpTempRegister, left);
1412            m_assembler.slt(dest, cmpTempRegister, MIPSRegisters::zero);
1413        } else if (cond == Signed) {
1414            m_assembler.subu(dest, left, right);
1415            // Check if the result is negative.
1416            m_assembler.slt(dest, dest, MIPSRegisters::zero);
1417        }
1418    }
1419
1420    void set32Compare32(Condition cond, RegisterID left, TrustedImm32 right, RegisterID dest)
1421    {
1422        move(right, immTempRegister);
1423        set32Compare32(cond, left, immTempRegister, dest);
1424    }
1425
1426    void set32Test8(Condition cond, Address address, TrustedImm32 mask, RegisterID dest)
1427    {
1428        ASSERT((cond == Zero) || (cond == NonZero));
1429        load8(address, dataTempRegister);
1430        if (mask.m_value == -1 && !m_fixedWidth) {
1431            if (cond == Zero)
1432                m_assembler.sltiu(dest, dataTempRegister, 1);
1433            else
1434                m_assembler.sltu(dest, MIPSRegisters::zero, dataTempRegister);
1435        } else {
1436            move(mask, immTempRegister);
1437            m_assembler.andInsn(cmpTempRegister, dataTempRegister,
1438                                immTempRegister);
1439            if (cond == Zero)
1440                m_assembler.sltiu(dest, cmpTempRegister, 1);
1441            else
1442                m_assembler.sltu(dest, MIPSRegisters::zero, cmpTempRegister);
1443        }
1444    }
1445
1446    void set32Test32(Condition cond, Address address, TrustedImm32 mask, RegisterID dest)
1447    {
1448        ASSERT((cond == Zero) || (cond == NonZero));
1449        load32(address, dataTempRegister);
1450        if (mask.m_value == -1 && !m_fixedWidth) {
1451            if (cond == Zero)
1452                m_assembler.sltiu(dest, dataTempRegister, 1);
1453            else
1454                m_assembler.sltu(dest, MIPSRegisters::zero, dataTempRegister);
1455        } else {
1456            move(mask, immTempRegister);
1457            m_assembler.andInsn(cmpTempRegister, dataTempRegister,
1458                                immTempRegister);
1459            if (cond == Zero)
1460                m_assembler.sltiu(dest, cmpTempRegister, 1);
1461            else
1462                m_assembler.sltu(dest, MIPSRegisters::zero, cmpTempRegister);
1463        }
1464    }
1465
1466    DataLabel32 moveWithPatch(TrustedImm32 imm, RegisterID dest)
1467    {
1468        m_fixedWidth = true;
1469        DataLabel32 label(this);
1470        move(imm, dest);
1471        m_fixedWidth = false;
1472        return label;
1473    }
1474
1475    DataLabelPtr moveWithPatch(TrustedImmPtr initialValue, RegisterID dest)
1476    {
1477        m_fixedWidth = true;
1478        DataLabelPtr label(this);
1479        move(initialValue, dest);
1480        m_fixedWidth = false;
1481        return label;
1482    }
1483
1484    Jump branchPtrWithPatch(Condition cond, RegisterID left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
1485    {
1486        m_fixedWidth = true;
1487        dataLabel = moveWithPatch(initialRightValue, immTempRegister);
1488        Jump temp = branch32(cond, left, immTempRegister);
1489        m_fixedWidth = false;
1490        return temp;
1491    }
1492
1493    Jump branchPtrWithPatch(Condition cond, Address left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
1494    {
1495        m_fixedWidth = true;
1496        load32(left, dataTempRegister);
1497        dataLabel = moveWithPatch(initialRightValue, immTempRegister);
1498        Jump temp = branch32(cond, dataTempRegister, immTempRegister);
1499        m_fixedWidth = false;
1500        return temp;
1501    }
1502
1503    DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address)
1504    {
1505        m_fixedWidth = true;
1506        DataLabelPtr dataLabel = moveWithPatch(initialValue, dataTempRegister);
1507        store32(dataTempRegister, address);
1508        m_fixedWidth = false;
1509        return dataLabel;
1510    }
1511
1512    DataLabelPtr storePtrWithPatch(ImplicitAddress address)
1513    {
1514        return storePtrWithPatch(TrustedImmPtr(0), address);
1515    }
1516
1517    Call tailRecursiveCall()
1518    {
1519        // Like a normal call, but don't update the returned address register
1520        m_fixedWidth = true;
1521        move(TrustedImm32(0), MIPSRegisters::t9);
1522        m_assembler.jr(MIPSRegisters::t9);
1523        m_assembler.nop();
1524        m_fixedWidth = false;
1525        return Call(m_assembler.newJmpSrc(), Call::Linkable);
1526    }
1527
1528    Call makeTailRecursiveCall(Jump oldJump)
1529    {
1530        oldJump.link(this);
1531        return tailRecursiveCall();
1532    }
1533
1534    void loadDouble(ImplicitAddress address, FPRegisterID dest)
1535    {
1536#if WTF_MIPS_ISA(1)
1537        /*
1538            li          addrTemp, address.offset
1539            addu        addrTemp, addrTemp, base
1540            lwc1        dest, 0(addrTemp)
1541            lwc1        dest+1, 4(addrTemp)
1542         */
1543        move(TrustedImm32(address.offset), addrTempRegister);
1544        m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
1545        m_assembler.lwc1(dest, addrTempRegister, 0);
1546        m_assembler.lwc1(FPRegisterID(dest + 1), addrTempRegister, 4);
1547#else
1548        if (address.offset >= -32768 && address.offset <= 32767
1549            && !m_fixedWidth) {
1550            m_assembler.ldc1(dest, address.base, address.offset);
1551        } else {
1552            /*
1553                lui     addrTemp, (offset + 0x8000) >> 16
1554                addu    addrTemp, addrTemp, base
1555                ldc1    dest, (offset & 0xffff)(addrTemp)
1556              */
1557            m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16);
1558            m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
1559            m_assembler.ldc1(dest, addrTempRegister, address.offset);
1560        }
1561#endif
1562    }
1563
1564    void loadDouble(const void* address, FPRegisterID dest)
1565    {
1566#if WTF_MIPS_ISA(1)
1567        /*
1568            li          addrTemp, address
1569            lwc1        dest, 0(addrTemp)
1570            lwc1        dest+1, 4(addrTemp)
1571         */
1572        move(TrustedImmPtr(address), addrTempRegister);
1573        m_assembler.lwc1(dest, addrTempRegister, 0);
1574        m_assembler.lwc1(FPRegisterID(dest + 1), addrTempRegister, 4);
1575#else
1576        /*
1577            li          addrTemp, address
1578            ldc1        dest, 0(addrTemp)
1579        */
1580        move(TrustedImmPtr(address), addrTempRegister);
1581        m_assembler.ldc1(dest, addrTempRegister, 0);
1582#endif
1583    }
1584
1585
1586    void storeDouble(FPRegisterID src, ImplicitAddress address)
1587    {
1588#if WTF_MIPS_ISA(1)
1589        /*
1590            li          addrTemp, address.offset
1591            addu        addrTemp, addrTemp, base
1592            swc1        dest, 0(addrTemp)
1593            swc1        dest+1, 4(addrTemp)
1594         */
1595        move(TrustedImm32(address.offset), addrTempRegister);
1596        m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
1597        m_assembler.swc1(src, addrTempRegister, 0);
1598        m_assembler.swc1(FPRegisterID(src + 1), addrTempRegister, 4);
1599#else
1600        if (address.offset >= -32768 && address.offset <= 32767
1601            && !m_fixedWidth)
1602            m_assembler.sdc1(src, address.base, address.offset);
1603        else {
1604            /*
1605                lui     addrTemp, (offset + 0x8000) >> 16
1606                addu    addrTemp, addrTemp, base
1607                sdc1    src, (offset & 0xffff)(addrTemp)
1608              */
1609            m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16);
1610            m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
1611            m_assembler.sdc1(src, addrTempRegister, address.offset);
1612        }
1613#endif
1614    }
1615
1616    void addDouble(FPRegisterID src, FPRegisterID dest)
1617    {
1618        m_assembler.addd(dest, dest, src);
1619    }
1620
1621    void addDouble(Address src, FPRegisterID dest)
1622    {
1623        loadDouble(src, fpTempRegister);
1624        m_assembler.addd(dest, dest, fpTempRegister);
1625    }
1626
1627    void subDouble(FPRegisterID src, FPRegisterID dest)
1628    {
1629        m_assembler.subd(dest, dest, src);
1630    }
1631
1632    void subDouble(Address src, FPRegisterID dest)
1633    {
1634        loadDouble(src, fpTempRegister);
1635        m_assembler.subd(dest, dest, fpTempRegister);
1636    }
1637
1638    void mulDouble(FPRegisterID src, FPRegisterID dest)
1639    {
1640        m_assembler.muld(dest, dest, src);
1641    }
1642
1643    void mulDouble(Address src, FPRegisterID dest)
1644    {
1645        loadDouble(src, fpTempRegister);
1646        m_assembler.muld(dest, dest, fpTempRegister);
1647    }
1648
1649    void divDouble(FPRegisterID src, FPRegisterID dest)
1650    {
1651        m_assembler.divd(dest, dest, src);
1652    }
1653
1654    void convertInt32ToDouble(RegisterID src, FPRegisterID dest)
1655    {
1656        m_assembler.mtc1(src, fpTempRegister);
1657        m_assembler.cvtdw(dest, fpTempRegister);
1658    }
1659
1660    void convertInt32ToDouble(Address src, FPRegisterID dest)
1661    {
1662        load32(src, dataTempRegister);
1663        m_assembler.mtc1(dataTempRegister, fpTempRegister);
1664        m_assembler.cvtdw(dest, fpTempRegister);
1665    }
1666
1667    void convertInt32ToDouble(AbsoluteAddress src, FPRegisterID dest)
1668    {
1669        load32(src.m_ptr, dataTempRegister);
1670        m_assembler.mtc1(dataTempRegister, fpTempRegister);
1671        m_assembler.cvtdw(dest, fpTempRegister);
1672    }
1673
1674    void insertRelaxationWords()
1675    {
1676        /* We need four words for relaxation. */
1677        m_assembler.beq(MIPSRegisters::zero, MIPSRegisters::zero, 3); // Jump over nops;
1678        m_assembler.nop();
1679        m_assembler.nop();
1680        m_assembler.nop();
1681    }
1682
1683    Jump branchTrue()
1684    {
1685        m_assembler.appendJump();
1686        m_assembler.bc1t();
1687        m_assembler.nop();
1688        insertRelaxationWords();
1689        return Jump(m_assembler.newJmpSrc());
1690    }
1691
1692    Jump branchFalse()
1693    {
1694        m_assembler.appendJump();
1695        m_assembler.bc1f();
1696        m_assembler.nop();
1697        insertRelaxationWords();
1698        return Jump(m_assembler.newJmpSrc());
1699    }
1700
1701    Jump branchEqual(RegisterID rs, RegisterID rt)
1702    {
1703        m_assembler.appendJump();
1704        m_assembler.beq(rs, rt, 0);
1705        m_assembler.nop();
1706        insertRelaxationWords();
1707        return Jump(m_assembler.newJmpSrc());
1708    }
1709
1710    Jump branchNotEqual(RegisterID rs, RegisterID rt)
1711    {
1712        m_assembler.appendJump();
1713        m_assembler.bne(rs, rt, 0);
1714        m_assembler.nop();
1715        insertRelaxationWords();
1716        return Jump(m_assembler.newJmpSrc());
1717    }
1718
1719    Jump branchDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right)
1720    {
1721        if (cond == DoubleEqual) {
1722            m_assembler.ceqd(left, right);
1723            return branchTrue();
1724        }
1725        if (cond == DoubleNotEqual) {
1726            m_assembler.cueqd(left, right);
1727            return branchFalse(); // false
1728        }
1729        if (cond == DoubleGreaterThan) {
1730            m_assembler.cngtd(left, right);
1731            return branchFalse(); // false
1732        }
1733        if (cond == DoubleGreaterThanOrEqual) {
1734            m_assembler.cnged(left, right);
1735            return branchFalse(); // false
1736        }
1737        if (cond == DoubleLessThan) {
1738            m_assembler.cltd(left, right);
1739            return branchTrue();
1740        }
1741        if (cond == DoubleLessThanOrEqual) {
1742            m_assembler.cled(left, right);
1743            return branchTrue();
1744        }
1745        if (cond == DoubleEqualOrUnordered) {
1746            m_assembler.cueqd(left, right);
1747            return branchTrue();
1748        }
1749        if (cond == DoubleNotEqualOrUnordered) {
1750            m_assembler.ceqd(left, right);
1751            return branchFalse(); // false
1752        }
1753        if (cond == DoubleGreaterThanOrUnordered) {
1754            m_assembler.coled(left, right);
1755            return branchFalse(); // false
1756        }
1757        if (cond == DoubleGreaterThanOrEqualOrUnordered) {
1758            m_assembler.coltd(left, right);
1759            return branchFalse(); // false
1760        }
1761        if (cond == DoubleLessThanOrUnordered) {
1762            m_assembler.cultd(left, right);
1763            return branchTrue();
1764        }
1765        if (cond == DoubleLessThanOrEqualOrUnordered) {
1766            m_assembler.culed(left, right);
1767            return branchTrue();
1768        }
1769        ASSERT(0);
1770
1771        return Jump();
1772    }
1773
1774    // Truncates 'src' to an integer, and places the resulting 'dest'.
1775    // If the result is not representable as a 32 bit value, branch.
1776    // May also branch for some values that are representable in 32 bits
1777    // (specifically, in this case, INT_MAX 0x7fffffff).
1778    Jump branchTruncateDoubleToInt32(FPRegisterID src, RegisterID dest)
1779    {
1780        m_assembler.truncwd(fpTempRegister, src);
1781        m_assembler.mfc1(dest, fpTempRegister);
1782        return branch32(Equal, dest, TrustedImm32(0x7fffffff));
1783    }
1784
1785    // Convert 'src' to an integer, and places the resulting 'dest'.
1786    // If the result is not representable as a 32 bit value, branch.
1787    // May also branch for some values that are representable in 32 bits
1788    // (specifically, in this case, 0).
1789    void branchConvertDoubleToInt32(FPRegisterID src, RegisterID dest, JumpList& failureCases, FPRegisterID fpTemp)
1790    {
1791        m_assembler.cvtwd(fpTempRegister, src);
1792        m_assembler.mfc1(dest, fpTempRegister);
1793
1794        // If the result is zero, it might have been -0.0, and the double comparison won't catch this!
1795        failureCases.append(branch32(Equal, dest, MIPSRegisters::zero));
1796
1797        // Convert the integer result back to float & compare to the original value - if not equal or unordered (NaN) then jump.
1798        convertInt32ToDouble(dest, fpTemp);
1799        failureCases.append(branchDouble(DoubleNotEqualOrUnordered, fpTemp, src));
1800    }
1801
1802    Jump branchDoubleNonZero(FPRegisterID reg, FPRegisterID scratch)
1803    {
1804#if WTF_MIPS_ISA_REV(2) && WTF_MIPS_FP64
1805        m_assembler.mtc1(MIPSRegisters::zero, scratch);
1806        m_assembler.mthc1(MIPSRegisters::zero, scratch);
1807#else
1808        m_assembler.mtc1(MIPSRegisters::zero, scratch);
1809        m_assembler.mtc1(MIPSRegisters::zero, FPRegisterID(scratch + 1));
1810#endif
1811        return branchDouble(DoubleNotEqual, reg, scratch);
1812    }
1813
1814    Jump branchDoubleZeroOrNaN(FPRegisterID reg, FPRegisterID scratch)
1815    {
1816#if WTF_MIPS_ISA_REV(2) && WTF_MIPS_FP64
1817        m_assembler.mtc1(MIPSRegisters::zero, scratch);
1818        m_assembler.mthc1(MIPSRegisters::zero, scratch);
1819#else
1820        m_assembler.mtc1(MIPSRegisters::zero, scratch);
1821        m_assembler.mtc1(MIPSRegisters::zero, FPRegisterID(scratch + 1));
1822#endif
1823        return branchDouble(DoubleEqualOrUnordered, reg, scratch);
1824    }
1825
1826
1827private:
1828    // If m_fixedWidth is true, we will generate a fixed number of instructions.
1829    // Otherwise, we can emit any number of instructions.
1830    bool m_fixedWidth;
1831
1832    friend class LinkBuffer;
1833    friend class RepatchBuffer;
1834
1835    static void linkCall(void* code, Call call, FunctionPtr function)
1836    {
1837        MIPSAssembler::linkCall(code, call.m_jmp, function.value());
1838    }
1839
1840    static void repatchCall(CodeLocationCall call, CodeLocationLabel destination)
1841    {
1842        MIPSAssembler::relinkCall(call.dataLocation(), destination.executableAddress());
1843    }
1844
1845    static void repatchCall(CodeLocationCall call, FunctionPtr destination)
1846    {
1847        MIPSAssembler::relinkCall(call.dataLocation(), destination.executableAddress());
1848    }
1849
1850};
1851
1852}
1853
1854#endif // ENABLE(ASSEMBLER) && CPU(MIPS)
1855
1856#endif // MacroAssemblerMIPS_h
1857