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