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