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