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