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