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