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