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