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