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