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