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 typedef MIPSRegisters::FPRegisterID FPRegisterID; 40 41 MacroAssemblerMIPS() 42 : m_fixedWidth(false) 43 { 44 } 45 46 static bool isCompactPtrAlignedAddressOffset(ptrdiff_t value) 47 { 48 return value >= -2147483647 - 1 && value <= 2147483647; 49 } 50 51 static const Scale ScalePtr = TimesFour; 52 53 // For storing immediate number 54 static const RegisterID immTempRegister = MIPSRegisters::t0; 55 // For storing data loaded from the memory 56 static const RegisterID dataTempRegister = MIPSRegisters::t1; 57 // For storing address base 58 static const RegisterID addrTempRegister = MIPSRegisters::t2; 59 // For storing compare result 60 static const RegisterID cmpTempRegister = MIPSRegisters::t3; 61 62 // FP temp register 63 static const FPRegisterID fpTempRegister = MIPSRegisters::f16; 64 65 static const int MaximumCompactPtrAlignedAddressOffset = 0x7FFFFFFF; 66 67 enum RelationalCondition { 68 Equal, 69 NotEqual, 70 Above, 71 AboveOrEqual, 72 Below, 73 BelowOrEqual, 74 GreaterThan, 75 GreaterThanOrEqual, 76 LessThan, 77 LessThanOrEqual 78 }; 79 80 enum ResultCondition { 81 Overflow, 82 Signed, 83 PositiveOrZero, 84 Zero, 85 NonZero 86 }; 87 88 enum DoubleCondition { 89 DoubleEqual, 90 DoubleNotEqual, 91 DoubleGreaterThan, 92 DoubleGreaterThanOrEqual, 93 DoubleLessThan, 94 DoubleLessThanOrEqual, 95 DoubleEqualOrUnordered, 96 DoubleNotEqualOrUnordered, 97 DoubleGreaterThanOrUnordered, 98 DoubleGreaterThanOrEqualOrUnordered, 99 DoubleLessThanOrUnordered, 100 DoubleLessThanOrEqualOrUnordered 101 }; 102 103 static const RegisterID stackPointerRegister = MIPSRegisters::sp; 104 static const RegisterID returnAddressRegister = MIPSRegisters::ra; 105 106 // Integer arithmetic operations: 107 // 108 // Operations are typically two operand - operation(source, srcDst) 109 // For many operations the source may be an TrustedImm32, the srcDst operand 110 // may often be a memory location (explictly described using an Address 111 // object). 112 113 void add32(RegisterID src, RegisterID dest) 114 { 115 m_assembler.addu(dest, dest, src); 116 } 117 118 void add32(RegisterID op1, RegisterID op2, RegisterID dest) 119 { 120 m_assembler.addu(dest, op1, op2); 121 } 122 123 void add32(TrustedImm32 imm, RegisterID dest) 124 { 125 add32(imm, dest, dest); 126 } 127 128 void add32(TrustedImm32 imm, RegisterID src, RegisterID dest) 129 { 130 if (imm.m_value >= -32768 && imm.m_value <= 32767 131 && !m_fixedWidth) { 132 /* 133 addiu dest, src, imm 134 */ 135 m_assembler.addiu(dest, src, imm.m_value); 136 } else { 137 /* 138 li immTemp, imm 139 addu dest, src, immTemp 140 */ 141 move(imm, immTempRegister); 142 m_assembler.addu(dest, src, immTempRegister); 143 } 144 } 145 146 void add32(RegisterID src, TrustedImm32 imm, RegisterID dest) 147 { 148 add32(imm, src, dest); 149 } 150 151 void add32(TrustedImm32 imm, Address address) 152 { 153 if (address.offset >= -32768 && address.offset <= 32767 154 && !m_fixedWidth) { 155 /* 156 lw dataTemp, offset(base) 157 li immTemp, imm 158 addu dataTemp, dataTemp, immTemp 159 sw dataTemp, offset(base) 160 */ 161 m_assembler.lw(dataTempRegister, address.base, address.offset); 162 if (imm.m_value >= -32768 && imm.m_value <= 32767 163 && !m_fixedWidth) 164 m_assembler.addiu(dataTempRegister, dataTempRegister, imm.m_value); 165 else { 166 move(imm, immTempRegister); 167 m_assembler.addu(dataTempRegister, dataTempRegister, immTempRegister); 168 } 169 m_assembler.sw(dataTempRegister, address.base, address.offset); 170 } else { 171 /* 172 lui addrTemp, (offset + 0x8000) >> 16 173 addu addrTemp, addrTemp, base 174 lw dataTemp, (offset & 0xffff)(addrTemp) 175 li immtemp, imm 176 addu dataTemp, dataTemp, immTemp 177 sw dataTemp, (offset & 0xffff)(addrTemp) 178 */ 179 m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16); 180 m_assembler.addu(addrTempRegister, addrTempRegister, address.base); 181 m_assembler.lw(dataTempRegister, addrTempRegister, address.offset); 182 183 if (imm.m_value >= -32768 && imm.m_value <= 32767 && !m_fixedWidth) 184 m_assembler.addiu(dataTempRegister, dataTempRegister, imm.m_value); 185 else { 186 move(imm, immTempRegister); 187 m_assembler.addu(dataTempRegister, dataTempRegister, immTempRegister); 188 } 189 m_assembler.sw(dataTempRegister, addrTempRegister, address.offset); 190 } 191 } 192 193 void add32(Address src, RegisterID dest) 194 { 195 load32(src, dataTempRegister); 196 add32(dataTempRegister, dest); 197 } 198 199 void add32(AbsoluteAddress src, RegisterID dest) 200 { 201 load32(src.m_ptr, dataTempRegister); 202 add32(dataTempRegister, dest); 203 } 204 205 void add32(RegisterID src, Address dest) 206 { 207 if (dest.offset >= -32768 && dest.offset <= 32767 && !m_fixedWidth) { 208 /* 209 lw dataTemp, offset(base) 210 addu dataTemp, dataTemp, src 211 sw dataTemp, offset(base) 212 */ 213 m_assembler.lw(dataTempRegister, dest.base, dest.offset); 214 m_assembler.addu(dataTempRegister, dataTempRegister, src); 215 m_assembler.sw(dataTempRegister, dest.base, dest.offset); 216 } else { 217 /* 218 lui addrTemp, (offset + 0x8000) >> 16 219 addu addrTemp, addrTemp, base 220 lw dataTemp, (offset & 0xffff)(addrTemp) 221 addu dataTemp, dataTemp, src 222 sw dataTemp, (offset & 0xffff)(addrTemp) 223 */ 224 m_assembler.lui(addrTempRegister, (dest.offset + 0x8000) >> 16); 225 m_assembler.addu(addrTempRegister, addrTempRegister, dest.base); 226 m_assembler.lw(dataTempRegister, addrTempRegister, dest.offset); 227 m_assembler.addu(dataTempRegister, dataTempRegister, src); 228 m_assembler.sw(dataTempRegister, addrTempRegister, dest.offset); 229 } 230 } 231 232 void add32(TrustedImm32 imm, AbsoluteAddress address) 233 { 234 /* 235 li addrTemp, address 236 li immTemp, imm 237 lw cmpTemp, 0(addrTemp) 238 addu dataTemp, cmpTemp, immTemp 239 sw dataTemp, 0(addrTemp) 240 */ 241 move(TrustedImmPtr(address.m_ptr), addrTempRegister); 242 m_assembler.lw(cmpTempRegister, addrTempRegister, 0); 243 if (imm.m_value >= -32768 && imm.m_value <= 32767 && !m_fixedWidth) 244 m_assembler.addiu(dataTempRegister, cmpTempRegister, imm.m_value); 245 else { 246 move(imm, immTempRegister); 247 m_assembler.addu(dataTempRegister, cmpTempRegister, immTempRegister); 248 } 249 m_assembler.sw(dataTempRegister, addrTempRegister, 0); 250 } 251 252 void add64(TrustedImm32 imm, AbsoluteAddress address) 253 { 254 /* 255 add32(imm, address) 256 sltu immTemp, dataTemp, cmpTemp # set carry-in bit 257 lw dataTemp, 4(addrTemp) 258 addiu dataTemp, imm.m_value >> 31 ? -1 : 0 259 addu dataTemp, dataTemp, immTemp 260 sw dataTemp, 4(addrTemp) 261 */ 262 add32(imm, address); 263 m_assembler.sltu(immTempRegister, dataTempRegister, cmpTempRegister); 264 m_assembler.lw(dataTempRegister, addrTempRegister, 4); 265 if (imm.m_value >> 31) 266 m_assembler.addiu(dataTempRegister, dataTempRegister, -1); 267 m_assembler.addu(dataTempRegister, dataTempRegister, immTempRegister); 268 m_assembler.sw(dataTempRegister, addrTempRegister, 4); 269 } 270 271 void and32(Address src, RegisterID dest) 272 { 273 load32(src, dataTempRegister); 274 and32(dataTempRegister, dest); 275 } 276 277 void and32(RegisterID src, RegisterID dest) 278 { 279 m_assembler.andInsn(dest, dest, src); 280 } 281 282 void and32(RegisterID op1, RegisterID op2, RegisterID dest) 283 { 284 m_assembler.andInsn(dest, op1, op2); 285 } 286 287 void and32(TrustedImm32 imm, RegisterID dest) 288 { 289 if (!imm.m_value && !m_fixedWidth) 290 move(MIPSRegisters::zero, dest); 291 else if (imm.m_value > 0 && imm.m_value < 65535 && !m_fixedWidth) 292 m_assembler.andi(dest, dest, imm.m_value); 293 else { 294 /* 295 li immTemp, imm 296 and dest, dest, immTemp 297 */ 298 move(imm, immTempRegister); 299 m_assembler.andInsn(dest, dest, immTempRegister); 300 } 301 } 302 303 void and32(TrustedImm32 imm, RegisterID src, RegisterID dest) 304 { 305 if (!imm.m_value && !m_fixedWidth) 306 move(MIPSRegisters::zero, dest); 307 else if (imm.m_value > 0 && imm.m_value < 65535 && !m_fixedWidth) 308 m_assembler.andi(dest, src, imm.m_value); 309 else { 310 move(imm, immTempRegister); 311 m_assembler.andInsn(dest, src, immTempRegister); 312 } 313 } 314 315 void lshift32(RegisterID shiftAmount, RegisterID dest) 316 { 317 m_assembler.sllv(dest, dest, shiftAmount); 318 } 319 320 void lshift32(RegisterID src, RegisterID shiftAmount, RegisterID dest) 321 { 322 m_assembler.sllv(dest, src, shiftAmount); 323 } 324 325 void lshift32(TrustedImm32 imm, RegisterID dest) 326 { 327 move(imm, immTempRegister); 328 m_assembler.sllv(dest, dest, immTempRegister); 329 } 330 331 void lshift32(RegisterID src, TrustedImm32 imm, RegisterID dest) 332 { 333 move(imm, immTempRegister); 334 m_assembler.sllv(dest, src, immTempRegister); 335 } 336 337 void mul32(RegisterID src, RegisterID dest) 338 { 339 m_assembler.mul(dest, dest, src); 340 } 341 342 void mul32(RegisterID op1, RegisterID op2, RegisterID dest) 343 { 344 m_assembler.mul(dest, op1, op2); 345 } 346 347 void mul32(TrustedImm32 imm, RegisterID src, RegisterID dest) 348 { 349 if (!imm.m_value && !m_fixedWidth) 350 move(MIPSRegisters::zero, dest); 351 else if (imm.m_value == 1 && !m_fixedWidth) 352 move(src, dest); 353 else { 354 /* 355 li dataTemp, imm 356 mul dest, src, dataTemp 357 */ 358 move(imm, dataTempRegister); 359 m_assembler.mul(dest, src, dataTempRegister); 360 } 361 } 362 363 void neg32(RegisterID srcDest) 364 { 365 m_assembler.subu(srcDest, MIPSRegisters::zero, srcDest); 366 } 367 368 void or32(RegisterID src, RegisterID dest) 369 { 370 m_assembler.orInsn(dest, dest, src); 371 } 372 373 void or32(RegisterID op1, RegisterID op2, RegisterID dest) 374 { 375 m_assembler.orInsn(dest, op1, op2); 376 } 377 378 void or32(TrustedImm32 imm, RegisterID dest) 379 { 380 if (!imm.m_value && !m_fixedWidth) 381 return; 382 383 if (imm.m_value > 0 && imm.m_value < 65535 384 && !m_fixedWidth) { 385 m_assembler.ori(dest, dest, imm.m_value); 386 return; 387 } 388 389 /* 390 li dataTemp, imm 391 or dest, dest, dataTemp 392 */ 393 move(imm, dataTempRegister); 394 m_assembler.orInsn(dest, dest, dataTempRegister); 395 } 396 397 void or32(TrustedImm32 imm, RegisterID src, RegisterID dest) 398 { 399 if (!imm.m_value && !m_fixedWidth) 400 return; 401 402 if (imm.m_value > 0 && imm.m_value < 65535 && !m_fixedWidth) { 403 m_assembler.ori(dest, src, imm.m_value); 404 return; 405 } 406 407 /* 408 li dataTemp, imm 409 or dest, src, dataTemp 410 */ 411 move(imm, dataTempRegister); 412 m_assembler.orInsn(dest, src, dataTempRegister); 413 } 414 415 void or32(RegisterID src, AbsoluteAddress dest) 416 { 417 load32(dest.m_ptr, dataTempRegister); 418 m_assembler.orInsn(dataTempRegister, dataTempRegister, src); 419 store32(dataTempRegister, dest.m_ptr); 420 } 421 422 void rshift32(RegisterID shiftAmount, RegisterID dest) 423 { 424 m_assembler.srav(dest, dest, shiftAmount); 425 } 426 427 void rshift32(RegisterID src, RegisterID shiftAmount, RegisterID dest) 428 { 429 m_assembler.srav(dest, src, shiftAmount); 430 } 431 432 void rshift32(TrustedImm32 imm, RegisterID dest) 433 { 434 m_assembler.sra(dest, dest, imm.m_value); 435 } 436 437 void rshift32(RegisterID src, TrustedImm32 imm, RegisterID dest) 438 { 439 m_assembler.sra(dest, src, imm.m_value); 440 } 441 442 void urshift32(RegisterID shiftAmount, RegisterID dest) 443 { 444 m_assembler.srlv(dest, dest, shiftAmount); 445 } 446 447 void urshift32(RegisterID src, RegisterID shiftAmount, RegisterID dest) 448 { 449 m_assembler.srlv(dest, src, shiftAmount); 450 } 451 452 void urshift32(TrustedImm32 imm, RegisterID dest) 453 { 454 m_assembler.srl(dest, dest, imm.m_value); 455 } 456 457 void urshift32(RegisterID src, TrustedImm32 imm, RegisterID dest) 458 { 459 m_assembler.srl(dest, src, imm.m_value); 460 } 461 462 void sub32(RegisterID src, RegisterID dest) 463 { 464 m_assembler.subu(dest, dest, src); 465 } 466 467 void sub32(RegisterID op1, RegisterID op2, RegisterID dest) 468 { 469 m_assembler.subu(dest, op1, op2); 470 } 471 472 void sub32(TrustedImm32 imm, RegisterID dest) 473 { 474 if (imm.m_value >= -32767 && imm.m_value <= 32768 475 && !m_fixedWidth) { 476 /* 477 addiu dest, src, imm 478 */ 479 m_assembler.addiu(dest, dest, -imm.m_value); 480 } else { 481 /* 482 li immTemp, imm 483 subu dest, src, immTemp 484 */ 485 move(imm, immTempRegister); 486 m_assembler.subu(dest, dest, immTempRegister); 487 } 488 } 489 490 void sub32(RegisterID src, TrustedImm32 imm, RegisterID dest) 491 { 492 if (imm.m_value >= -32767 && imm.m_value <= 32768 493 && !m_fixedWidth) { 494 /* 495 addiu dest, src, imm 496 */ 497 m_assembler.addiu(dest, src, -imm.m_value); 498 } else { 499 /* 500 li immTemp, imm 501 subu dest, src, immTemp 502 */ 503 move(imm, immTempRegister); 504 m_assembler.subu(dest, src, immTempRegister); 505 } 506 } 507 508 void sub32(TrustedImm32 imm, Address address) 509 { 510 if (address.offset >= -32768 && address.offset <= 32767 511 && !m_fixedWidth) { 512 /* 513 lw dataTemp, offset(base) 514 li immTemp, imm 515 subu dataTemp, dataTemp, immTemp 516 sw dataTemp, offset(base) 517 */ 518 m_assembler.lw(dataTempRegister, address.base, address.offset); 519 if (imm.m_value >= -32767 && imm.m_value <= 32768 && !m_fixedWidth) 520 m_assembler.addiu(dataTempRegister, dataTempRegister, -imm.m_value); 521 else { 522 move(imm, immTempRegister); 523 m_assembler.subu(dataTempRegister, dataTempRegister, immTempRegister); 524 } 525 m_assembler.sw(dataTempRegister, address.base, address.offset); 526 } else { 527 /* 528 lui addrTemp, (offset + 0x8000) >> 16 529 addu addrTemp, addrTemp, base 530 lw dataTemp, (offset & 0xffff)(addrTemp) 531 li immtemp, imm 532 subu dataTemp, dataTemp, immTemp 533 sw dataTemp, (offset & 0xffff)(addrTemp) 534 */ 535 m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16); 536 m_assembler.addu(addrTempRegister, addrTempRegister, address.base); 537 m_assembler.lw(dataTempRegister, addrTempRegister, address.offset); 538 539 if (imm.m_value >= -32767 && imm.m_value <= 32768 540 && !m_fixedWidth) 541 m_assembler.addiu(dataTempRegister, dataTempRegister, -imm.m_value); 542 else { 543 move(imm, immTempRegister); 544 m_assembler.subu(dataTempRegister, dataTempRegister, immTempRegister); 545 } 546 m_assembler.sw(dataTempRegister, addrTempRegister, address.offset); 547 } 548 } 549 550 void sub32(Address src, RegisterID dest) 551 { 552 load32(src, dataTempRegister); 553 sub32(dataTempRegister, dest); 554 } 555 556 void sub32(TrustedImm32 imm, AbsoluteAddress address) 557 { 558 /* 559 li addrTemp, address 560 li immTemp, imm 561 lw dataTemp, 0(addrTemp) 562 subu dataTemp, dataTemp, immTemp 563 sw dataTemp, 0(addrTemp) 564 */ 565 move(TrustedImmPtr(address.m_ptr), addrTempRegister); 566 m_assembler.lw(dataTempRegister, addrTempRegister, 0); 567 568 if (imm.m_value >= -32767 && imm.m_value <= 32768 && !m_fixedWidth) 569 m_assembler.addiu(dataTempRegister, dataTempRegister, -imm.m_value); 570 else { 571 move(imm, immTempRegister); 572 m_assembler.subu(dataTempRegister, dataTempRegister, immTempRegister); 573 } 574 m_assembler.sw(dataTempRegister, addrTempRegister, 0); 575 } 576 577 void xor32(RegisterID src, RegisterID dest) 578 { 579 m_assembler.xorInsn(dest, dest, src); 580 } 581 582 void xor32(RegisterID op1, RegisterID op2, RegisterID dest) 583 { 584 m_assembler.xorInsn(dest, op1, op2); 585 } 586 587 void xor32(TrustedImm32 imm, RegisterID dest) 588 { 589 if (imm.m_value == -1) { 590 m_assembler.nor(dest, dest, MIPSRegisters::zero); 591 return; 592 } 593 594 /* 595 li immTemp, imm 596 xor dest, dest, immTemp 597 */ 598 move(imm, immTempRegister); 599 m_assembler.xorInsn(dest, dest, immTempRegister); 600 } 601 602 void xor32(TrustedImm32 imm, RegisterID src, RegisterID dest) 603 { 604 if (imm.m_value == -1) { 605 m_assembler.nor(dest, src, MIPSRegisters::zero); 606 return; 607 } 608 609 /* 610 li immTemp, imm 611 xor dest, dest, immTemp 612 */ 613 move(imm, immTempRegister); 614 m_assembler.xorInsn(dest, src, immTempRegister); 615 } 616 617 void sqrtDouble(FPRegisterID src, FPRegisterID dst) 618 { 619 m_assembler.sqrtd(dst, src); 620 } 621 622 void absDouble(FPRegisterID, FPRegisterID) 623 { 624 RELEASE_ASSERT_NOT_REACHED(); 625 } 626 627 ConvertibleLoadLabel convertibleLoadPtr(Address address, RegisterID dest) 628 { 629 ConvertibleLoadLabel result(this); 630 /* 631 lui addrTemp, (offset + 0x8000) >> 16 632 addu addrTemp, addrTemp, base 633 lw dest, (offset & 0xffff)(addrTemp) 634 */ 635 m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16); 636 m_assembler.addu(addrTempRegister, addrTempRegister, address.base); 637 m_assembler.lw(dest, addrTempRegister, address.offset); 638 return result; 639 } 640 641 // Memory access operations: 642 // 643 // Loads are of the form load(address, destination) and stores of the form 644 // store(source, address). The source for a store may be an TrustedImm32. Address 645 // operand objects to loads and store will be implicitly constructed if a 646 // register is passed. 647 648 /* Need to use zero-extened load byte for load8. */ 649 void load8(ImplicitAddress address, RegisterID dest) 650 { 651 if (address.offset >= -32768 && address.offset <= 32767 652 && !m_fixedWidth) 653 m_assembler.lbu(dest, address.base, address.offset); 654 else { 655 /* 656 lui addrTemp, (offset + 0x8000) >> 16 657 addu addrTemp, addrTemp, base 658 lbu dest, (offset & 0xffff)(addrTemp) 659 */ 660 m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16); 661 m_assembler.addu(addrTempRegister, addrTempRegister, address.base); 662 m_assembler.lbu(dest, addrTempRegister, address.offset); 663 } 664 } 665 666 void load8(BaseIndex address, RegisterID dest) 667 { 668 if (address.offset >= -32768 && address.offset <= 32767 669 && !m_fixedWidth) { 670 /* 671 sll addrTemp, address.index, address.scale 672 addu addrTemp, addrTemp, address.base 673 lbu dest, address.offset(addrTemp) 674 */ 675 m_assembler.sll(addrTempRegister, address.index, address.scale); 676 m_assembler.addu(addrTempRegister, addrTempRegister, address.base); 677 m_assembler.lbu(dest, addrTempRegister, address.offset); 678 } else { 679 /* 680 sll addrTemp, address.index, address.scale 681 addu addrTemp, addrTemp, address.base 682 lui immTemp, (address.offset + 0x8000) >> 16 683 addu addrTemp, addrTemp, immTemp 684 lbu dest, (address.offset & 0xffff)(at) 685 */ 686 m_assembler.sll(addrTempRegister, address.index, address.scale); 687 m_assembler.addu(addrTempRegister, addrTempRegister, address.base); 688 m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16); 689 m_assembler.addu(addrTempRegister, addrTempRegister, immTempRegister); 690 m_assembler.lbu(dest, addrTempRegister, address.offset); 691 } 692 } 693 694 void load8Signed(BaseIndex address, RegisterID dest) 695 { 696 if (address.offset >= -32768 && address.offset <= 32767 697 && !m_fixedWidth) { 698 /* 699 sll addrTemp, address.index, address.scale 700 addu addrTemp, addrTemp, address.base 701 lb dest, address.offset(addrTemp) 702 */ 703 m_assembler.sll(addrTempRegister, address.index, address.scale); 704 m_assembler.addu(addrTempRegister, addrTempRegister, address.base); 705 m_assembler.lb(dest, addrTempRegister, address.offset); 706 } else { 707 /* 708 sll addrTemp, address.index, address.scale 709 addu addrTemp, addrTemp, address.base 710 lui immTemp, (address.offset + 0x8000) >> 16 711 addu addrTemp, addrTemp, immTemp 712 lb dest, (address.offset & 0xffff)(at) 713 */ 714 m_assembler.sll(addrTempRegister, address.index, address.scale); 715 m_assembler.addu(addrTempRegister, addrTempRegister, address.base); 716 m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16); 717 m_assembler.addu(addrTempRegister, addrTempRegister, immTempRegister); 718 m_assembler.lb(dest, addrTempRegister, address.offset); 719 } 720 } 721 722 void load32(ImplicitAddress address, RegisterID dest) 723 { 724 if (address.offset >= -32768 && address.offset <= 32767 725 && !m_fixedWidth) 726 m_assembler.lw(dest, address.base, address.offset); 727 else { 728 /* 729 lui addrTemp, (offset + 0x8000) >> 16 730 addu addrTemp, addrTemp, base 731 lw dest, (offset & 0xffff)(addrTemp) 732 */ 733 m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16); 734 m_assembler.addu(addrTempRegister, addrTempRegister, address.base); 735 m_assembler.lw(dest, addrTempRegister, address.offset); 736 } 737 } 738 739 void load32(BaseIndex address, RegisterID dest) 740 { 741 if (address.offset >= -32768 && address.offset <= 32767 742 && !m_fixedWidth) { 743 /* 744 sll addrTemp, address.index, address.scale 745 addu addrTemp, addrTemp, address.base 746 lw dest, address.offset(addrTemp) 747 */ 748 m_assembler.sll(addrTempRegister, address.index, address.scale); 749 m_assembler.addu(addrTempRegister, addrTempRegister, address.base); 750 m_assembler.lw(dest, addrTempRegister, address.offset); 751 } else { 752 /* 753 sll addrTemp, address.index, address.scale 754 addu addrTemp, addrTemp, address.base 755 lui immTemp, (address.offset + 0x8000) >> 16 756 addu addrTemp, addrTemp, immTemp 757 lw dest, (address.offset & 0xffff)(at) 758 */ 759 m_assembler.sll(addrTempRegister, address.index, address.scale); 760 m_assembler.addu(addrTempRegister, addrTempRegister, address.base); 761 m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16); 762 m_assembler.addu(addrTempRegister, addrTempRegister, immTempRegister); 763 m_assembler.lw(dest, addrTempRegister, address.offset); 764 } 765 } 766 767 void load16Unaligned(BaseIndex address, RegisterID dest) 768 { 769 load16(address, dest); 770 } 771 772 void load32WithUnalignedHalfWords(BaseIndex address, RegisterID dest) 773 { 774 if (address.offset >= -32768 && address.offset <= 32764 775 && !m_fixedWidth) { 776 /* 777 sll addrTemp, address.index, address.scale 778 addu addrTemp, addrTemp, address.base 779 (Big-Endian) 780 lwl dest, address.offset(addrTemp) 781 lwr dest, address.offset+3(addrTemp) 782 (Little-Endian) 783 lwl dest, address.offset+3(addrTemp) 784 lwr dest, address.offset(addrTemp) 785 */ 786 m_assembler.sll(addrTempRegister, address.index, address.scale); 787 m_assembler.addu(addrTempRegister, addrTempRegister, address.base); 788#if CPU(BIG_ENDIAN) 789 m_assembler.lwl(dest, addrTempRegister, address.offset); 790 m_assembler.lwr(dest, addrTempRegister, address.offset + 3); 791#else 792 m_assembler.lwl(dest, addrTempRegister, address.offset + 3); 793 m_assembler.lwr(dest, addrTempRegister, address.offset); 794 795#endif 796 } else { 797 /* 798 sll addrTemp, address.index, address.scale 799 addu addrTemp, addrTemp, address.base 800 lui immTemp, address.offset >> 16 801 ori immTemp, immTemp, address.offset & 0xffff 802 addu addrTemp, addrTemp, immTemp 803 (Big-Endian) 804 lw dest, 0(at) 805 lw dest, 3(at) 806 (Little-Endian) 807 lw dest, 3(at) 808 lw dest, 0(at) 809 */ 810 m_assembler.sll(addrTempRegister, address.index, address.scale); 811 m_assembler.addu(addrTempRegister, addrTempRegister, address.base); 812 m_assembler.lui(immTempRegister, address.offset >> 16); 813 m_assembler.ori(immTempRegister, immTempRegister, address.offset); 814 m_assembler.addu(addrTempRegister, addrTempRegister, immTempRegister); 815#if CPU(BIG_ENDIAN) 816 m_assembler.lwl(dest, addrTempRegister, 0); 817 m_assembler.lwr(dest, addrTempRegister, 3); 818#else 819 m_assembler.lwl(dest, addrTempRegister, 3); 820 m_assembler.lwr(dest, addrTempRegister, 0); 821#endif 822 } 823 } 824 825 void load32(const void* address, RegisterID dest) 826 { 827 /* 828 li addrTemp, address 829 lw dest, 0(addrTemp) 830 */ 831 move(TrustedImmPtr(address), addrTempRegister); 832 m_assembler.lw(dest, addrTempRegister, 0); 833 } 834 835 DataLabel32 load32WithAddressOffsetPatch(Address address, RegisterID dest) 836 { 837 m_fixedWidth = true; 838 /* 839 lui addrTemp, address.offset >> 16 840 ori addrTemp, addrTemp, address.offset & 0xffff 841 addu addrTemp, addrTemp, address.base 842 lw dest, 0(addrTemp) 843 */ 844 DataLabel32 dataLabel(this); 845 move(TrustedImm32(address.offset), addrTempRegister); 846 m_assembler.addu(addrTempRegister, addrTempRegister, address.base); 847 m_assembler.lw(dest, addrTempRegister, 0); 848 m_fixedWidth = false; 849 return dataLabel; 850 } 851 852 DataLabelCompact load32WithCompactAddressOffsetPatch(Address address, RegisterID dest) 853 { 854 DataLabelCompact dataLabel(this); 855 load32WithAddressOffsetPatch(address, dest); 856 return dataLabel; 857 } 858 859 /* Need to use zero-extened load half-word for load16. */ 860 void load16(ImplicitAddress address, RegisterID dest) 861 { 862 if (address.offset >= -32768 && address.offset <= 32767 863 && !m_fixedWidth) 864 m_assembler.lhu(dest, address.base, address.offset); 865 else { 866 /* 867 lui addrTemp, (offset + 0x8000) >> 16 868 addu addrTemp, addrTemp, base 869 lhu dest, (offset & 0xffff)(addrTemp) 870 */ 871 m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16); 872 m_assembler.addu(addrTempRegister, addrTempRegister, address.base); 873 m_assembler.lhu(dest, addrTempRegister, address.offset); 874 } 875 } 876 877 /* Need to use zero-extened load half-word for load16. */ 878 void load16(BaseIndex address, RegisterID dest) 879 { 880 if (address.offset >= -32768 && address.offset <= 32767 881 && !m_fixedWidth) { 882 /* 883 sll addrTemp, address.index, address.scale 884 addu addrTemp, addrTemp, address.base 885 lhu dest, address.offset(addrTemp) 886 */ 887 m_assembler.sll(addrTempRegister, address.index, address.scale); 888 m_assembler.addu(addrTempRegister, addrTempRegister, address.base); 889 m_assembler.lhu(dest, addrTempRegister, address.offset); 890 } else { 891 /* 892 sll addrTemp, address.index, address.scale 893 addu addrTemp, addrTemp, address.base 894 lui immTemp, (address.offset + 0x8000) >> 16 895 addu addrTemp, addrTemp, immTemp 896 lhu dest, (address.offset & 0xffff)(addrTemp) 897 */ 898 m_assembler.sll(addrTempRegister, address.index, address.scale); 899 m_assembler.addu(addrTempRegister, addrTempRegister, address.base); 900 m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16); 901 m_assembler.addu(addrTempRegister, addrTempRegister, immTempRegister); 902 m_assembler.lhu(dest, addrTempRegister, address.offset); 903 } 904 } 905 906 void load16Signed(BaseIndex address, RegisterID dest) 907 { 908 if (address.offset >= -32768 && address.offset <= 32767 909 && !m_fixedWidth) { 910 /* 911 sll addrTemp, address.index, address.scale 912 addu addrTemp, addrTemp, address.base 913 lh dest, address.offset(addrTemp) 914 */ 915 m_assembler.sll(addrTempRegister, address.index, address.scale); 916 m_assembler.addu(addrTempRegister, addrTempRegister, address.base); 917 m_assembler.lh(dest, addrTempRegister, address.offset); 918 } else { 919 /* 920 sll addrTemp, address.index, address.scale 921 addu addrTemp, addrTemp, address.base 922 lui immTemp, (address.offset + 0x8000) >> 16 923 addu addrTemp, addrTemp, immTemp 924 lh dest, (address.offset & 0xffff)(addrTemp) 925 */ 926 m_assembler.sll(addrTempRegister, address.index, address.scale); 927 m_assembler.addu(addrTempRegister, addrTempRegister, address.base); 928 m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16); 929 m_assembler.addu(addrTempRegister, addrTempRegister, immTempRegister); 930 m_assembler.lh(dest, addrTempRegister, address.offset); 931 } 932 } 933 934 DataLabel32 store32WithAddressOffsetPatch(RegisterID src, Address address) 935 { 936 m_fixedWidth = true; 937 /* 938 lui addrTemp, address.offset >> 16 939 ori addrTemp, addrTemp, address.offset & 0xffff 940 addu addrTemp, addrTemp, address.base 941 sw src, 0(addrTemp) 942 */ 943 DataLabel32 dataLabel(this); 944 move(TrustedImm32(address.offset), addrTempRegister); 945 m_assembler.addu(addrTempRegister, addrTempRegister, address.base); 946 m_assembler.sw(src, addrTempRegister, 0); 947 m_fixedWidth = false; 948 return dataLabel; 949 } 950 951 void store8(RegisterID src, BaseIndex address) 952 { 953 if (address.offset >= -32768 && address.offset <= 32767 954 && !m_fixedWidth) { 955 /* 956 sll addrTemp, address.index, address.scale 957 addu addrTemp, addrTemp, address.base 958 sb src, address.offset(addrTemp) 959 */ 960 m_assembler.sll(addrTempRegister, address.index, address.scale); 961 m_assembler.addu(addrTempRegister, addrTempRegister, address.base); 962 m_assembler.sb(src, addrTempRegister, address.offset); 963 } else { 964 /* 965 sll addrTemp, address.index, address.scale 966 addu addrTemp, addrTemp, address.base 967 lui immTemp, (address.offset + 0x8000) >> 16 968 addu addrTemp, addrTemp, immTemp 969 sb src, (address.offset & 0xffff)(at) 970 */ 971 m_assembler.sll(addrTempRegister, address.index, address.scale); 972 m_assembler.addu(addrTempRegister, addrTempRegister, address.base); 973 m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16); 974 m_assembler.addu(addrTempRegister, addrTempRegister, immTempRegister); 975 m_assembler.sb(src, addrTempRegister, address.offset); 976 } 977 } 978 979 void store8(TrustedImm32 imm, void* address) 980 { 981 /* 982 li immTemp, imm 983 li addrTemp, address 984 sb src, 0(addrTemp) 985 */ 986 if (!imm.m_value && !m_fixedWidth) { 987 move(TrustedImmPtr(address), addrTempRegister); 988 m_assembler.sb(MIPSRegisters::zero, addrTempRegister, 0); 989 } else { 990 move(imm, immTempRegister); 991 move(TrustedImmPtr(address), addrTempRegister); 992 m_assembler.sb(immTempRegister, addrTempRegister, 0); 993 } 994 } 995 996 void store16(RegisterID src, BaseIndex address) 997 { 998 if (address.offset >= -32768 && address.offset <= 32767 999 && !m_fixedWidth) { 1000 /* 1001 sll addrTemp, address.index, address.scale 1002 addu addrTemp, addrTemp, address.base 1003 sh src, address.offset(addrTemp) 1004 */ 1005 m_assembler.sll(addrTempRegister, address.index, address.scale); 1006 m_assembler.addu(addrTempRegister, addrTempRegister, address.base); 1007 m_assembler.sh(src, addrTempRegister, address.offset); 1008 } else { 1009 /* 1010 sll addrTemp, address.index, address.scale 1011 addu addrTemp, addrTemp, address.base 1012 lui immTemp, (address.offset + 0x8000) >> 16 1013 addu addrTemp, addrTemp, immTemp 1014 sh src, (address.offset & 0xffff)(at) 1015 */ 1016 m_assembler.sll(addrTempRegister, address.index, address.scale); 1017 m_assembler.addu(addrTempRegister, addrTempRegister, address.base); 1018 m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16); 1019 m_assembler.addu(addrTempRegister, addrTempRegister, immTempRegister); 1020 m_assembler.sh(src, addrTempRegister, address.offset); 1021 } 1022 } 1023 1024 void store32(RegisterID src, ImplicitAddress address) 1025 { 1026 if (address.offset >= -32768 && address.offset <= 32767 1027 && !m_fixedWidth) 1028 m_assembler.sw(src, address.base, address.offset); 1029 else { 1030 /* 1031 lui addrTemp, (offset + 0x8000) >> 16 1032 addu addrTemp, addrTemp, base 1033 sw src, (offset & 0xffff)(addrTemp) 1034 */ 1035 m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16); 1036 m_assembler.addu(addrTempRegister, addrTempRegister, address.base); 1037 m_assembler.sw(src, addrTempRegister, address.offset); 1038 } 1039 } 1040 1041 void store32(RegisterID src, BaseIndex address) 1042 { 1043 if (address.offset >= -32768 && address.offset <= 32767 1044 && !m_fixedWidth) { 1045 /* 1046 sll addrTemp, address.index, address.scale 1047 addu addrTemp, addrTemp, address.base 1048 sw src, address.offset(addrTemp) 1049 */ 1050 m_assembler.sll(addrTempRegister, address.index, address.scale); 1051 m_assembler.addu(addrTempRegister, addrTempRegister, address.base); 1052 m_assembler.sw(src, addrTempRegister, address.offset); 1053 } else { 1054 /* 1055 sll addrTemp, address.index, address.scale 1056 addu addrTemp, addrTemp, address.base 1057 lui immTemp, (address.offset + 0x8000) >> 16 1058 addu addrTemp, addrTemp, immTemp 1059 sw src, (address.offset & 0xffff)(at) 1060 */ 1061 m_assembler.sll(addrTempRegister, address.index, address.scale); 1062 m_assembler.addu(addrTempRegister, addrTempRegister, address.base); 1063 m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16); 1064 m_assembler.addu(addrTempRegister, addrTempRegister, immTempRegister); 1065 m_assembler.sw(src, addrTempRegister, address.offset); 1066 } 1067 } 1068 1069 void store32(TrustedImm32 imm, ImplicitAddress address) 1070 { 1071 if (address.offset >= -32768 && address.offset <= 32767 1072 && !m_fixedWidth) { 1073 if (!imm.m_value) 1074 m_assembler.sw(MIPSRegisters::zero, address.base, address.offset); 1075 else { 1076 move(imm, immTempRegister); 1077 m_assembler.sw(immTempRegister, address.base, address.offset); 1078 } 1079 } else { 1080 /* 1081 lui addrTemp, (offset + 0x8000) >> 16 1082 addu addrTemp, addrTemp, base 1083 sw immTemp, (offset & 0xffff)(addrTemp) 1084 */ 1085 m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16); 1086 m_assembler.addu(addrTempRegister, addrTempRegister, address.base); 1087 if (!imm.m_value && !m_fixedWidth) 1088 m_assembler.sw(MIPSRegisters::zero, addrTempRegister, address.offset); 1089 else { 1090 move(imm, immTempRegister); 1091 m_assembler.sw(immTempRegister, addrTempRegister, address.offset); 1092 } 1093 } 1094 } 1095 1096 void store32(TrustedImm32 imm, BaseIndex address) 1097 { 1098 if (address.offset >= -32768 && address.offset <= 32767 && !m_fixedWidth) { 1099 /* 1100 sll addrTemp, address.index, address.scale 1101 addu addrTemp, addrTemp, address.base 1102 sw src, address.offset(addrTemp) 1103 */ 1104 m_assembler.sll(addrTempRegister, address.index, address.scale); 1105 m_assembler.addu(addrTempRegister, addrTempRegister, address.base); 1106 if (!imm.m_value) 1107 m_assembler.sw(MIPSRegisters::zero, addrTempRegister, address.offset); 1108 else { 1109 move(imm, immTempRegister); 1110 m_assembler.sw(immTempRegister, addrTempRegister, address.offset); 1111 } 1112 } else { 1113 /* 1114 sll addrTemp, address.index, address.scale 1115 addu addrTemp, addrTemp, address.base 1116 lui immTemp, (address.offset + 0x8000) >> 16 1117 addu addrTemp, addrTemp, immTemp 1118 sw src, (address.offset & 0xffff)(at) 1119 */ 1120 m_assembler.sll(addrTempRegister, address.index, address.scale); 1121 m_assembler.addu(addrTempRegister, addrTempRegister, address.base); 1122 m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16); 1123 m_assembler.addu(addrTempRegister, addrTempRegister, immTempRegister); 1124 if (!imm.m_value && !m_fixedWidth) 1125 m_assembler.sw(MIPSRegisters::zero, addrTempRegister, address.offset); 1126 else { 1127 move(imm, immTempRegister); 1128 m_assembler.sw(immTempRegister, addrTempRegister, address.offset); 1129 } 1130 } 1131 } 1132 1133 1134 void store32(RegisterID src, const void* address) 1135 { 1136 /* 1137 li addrTemp, address 1138 sw src, 0(addrTemp) 1139 */ 1140 move(TrustedImmPtr(address), addrTempRegister); 1141 m_assembler.sw(src, addrTempRegister, 0); 1142 } 1143 1144 void store32(TrustedImm32 imm, const void* address) 1145 { 1146 /* 1147 li immTemp, imm 1148 li addrTemp, address 1149 sw src, 0(addrTemp) 1150 */ 1151 if (!imm.m_value && !m_fixedWidth) { 1152 move(TrustedImmPtr(address), addrTempRegister); 1153 m_assembler.sw(MIPSRegisters::zero, addrTempRegister, 0); 1154 } else { 1155 move(imm, immTempRegister); 1156 move(TrustedImmPtr(address), addrTempRegister); 1157 m_assembler.sw(immTempRegister, addrTempRegister, 0); 1158 } 1159 } 1160 1161 // Floating-point operations: 1162 1163 static bool supportsFloatingPoint() 1164 { 1165#if WTF_MIPS_DOUBLE_FLOAT 1166 return true; 1167#else 1168 return false; 1169#endif 1170 } 1171 1172 static bool supportsFloatingPointTruncate() 1173 { 1174#if WTF_MIPS_DOUBLE_FLOAT && WTF_MIPS_ISA_AT_LEAST(2) 1175 return true; 1176#else 1177 return false; 1178#endif 1179 } 1180 1181 static bool supportsFloatingPointSqrt() 1182 { 1183#if WTF_MIPS_DOUBLE_FLOAT && WTF_MIPS_ISA_AT_LEAST(2) 1184 return true; 1185#else 1186 return false; 1187#endif 1188 } 1189 static bool supportsFloatingPointAbs() { return false; } 1190 1191 // Stack manipulation operations: 1192 // 1193 // The ABI is assumed to provide a stack abstraction to memory, 1194 // containing machine word sized units of data. Push and pop 1195 // operations add and remove a single register sized unit of data 1196 // to or from the stack. Peek and poke operations read or write 1197 // values on the stack, without moving the current stack position. 1198 1199 void pop(RegisterID dest) 1200 { 1201 m_assembler.lw(dest, MIPSRegisters::sp, 0); 1202 m_assembler.addiu(MIPSRegisters::sp, MIPSRegisters::sp, 4); 1203 } 1204 1205 void push(RegisterID src) 1206 { 1207 m_assembler.addiu(MIPSRegisters::sp, MIPSRegisters::sp, -4); 1208 m_assembler.sw(src, MIPSRegisters::sp, 0); 1209 } 1210 1211 void push(Address address) 1212 { 1213 load32(address, dataTempRegister); 1214 push(dataTempRegister); 1215 } 1216 1217 void push(TrustedImm32 imm) 1218 { 1219 move(imm, immTempRegister); 1220 push(immTempRegister); 1221 } 1222 1223 // Register move operations: 1224 // 1225 // Move values in registers. 1226 1227 void move(TrustedImm32 imm, RegisterID dest) 1228 { 1229 if (!imm.m_value && !m_fixedWidth) 1230 move(MIPSRegisters::zero, dest); 1231 else if (m_fixedWidth) { 1232 m_assembler.lui(dest, imm.m_value >> 16); 1233 m_assembler.ori(dest, dest, imm.m_value); 1234 } else 1235 m_assembler.li(dest, imm.m_value); 1236 } 1237 1238 void move(RegisterID src, RegisterID dest) 1239 { 1240 if (src != dest || m_fixedWidth) 1241 m_assembler.move(dest, src); 1242 } 1243 1244 void move(TrustedImmPtr imm, RegisterID dest) 1245 { 1246 move(TrustedImm32(imm), dest); 1247 } 1248 1249 void swap(RegisterID reg1, RegisterID reg2) 1250 { 1251 move(reg1, immTempRegister); 1252 move(reg2, reg1); 1253 move(immTempRegister, reg2); 1254 } 1255 1256 void signExtend32ToPtr(RegisterID src, RegisterID dest) 1257 { 1258 if (src != dest || m_fixedWidth) 1259 move(src, dest); 1260 } 1261 1262 void zeroExtend32ToPtr(RegisterID src, RegisterID dest) 1263 { 1264 if (src != dest || m_fixedWidth) 1265 move(src, dest); 1266 } 1267 1268 // Forwards / external control flow operations: 1269 // 1270 // This set of jump and conditional branch operations return a Jump 1271 // object which may linked at a later point, allow forwards jump, 1272 // or jumps that will require external linkage (after the code has been 1273 // relocated). 1274 // 1275 // For branches, signed <, >, <= and >= are denoted as l, g, le, and ge 1276 // respecitvely, for unsigned comparisons the names b, a, be, and ae are 1277 // used (representing the names 'below' and 'above'). 1278 // 1279 // Operands to the comparision are provided in the expected order, e.g. 1280 // jle32(reg1, TrustedImm32(5)) will branch if the value held in reg1, when 1281 // treated as a signed 32bit value, is less than or equal to 5. 1282 // 1283 // jz and jnz test whether the first operand is equal to zero, and take 1284 // an optional second operand of a mask under which to perform the test. 1285 1286 Jump branch8(RelationalCondition cond, Address left, TrustedImm32 right) 1287 { 1288 // Make sure the immediate value is unsigned 8 bits. 1289 ASSERT(!(right.m_value & 0xFFFFFF00)); 1290 load8(left, dataTempRegister); 1291 move(right, immTempRegister); 1292 return branch32(cond, dataTempRegister, immTempRegister); 1293 } 1294 1295 void compare8(RelationalCondition cond, Address left, TrustedImm32 right, RegisterID dest) 1296 { 1297 // Make sure the immediate value is unsigned 8 bits. 1298 ASSERT(!(right.m_value & 0xFFFFFF00)); 1299 load8(left, dataTempRegister); 1300 move(right, immTempRegister); 1301 compare32(cond, dataTempRegister, immTempRegister, dest); 1302 } 1303 1304 Jump branch8(RelationalCondition cond, BaseIndex left, TrustedImm32 right) 1305 { 1306 ASSERT(!(right.m_value & 0xFFFFFF00)); 1307 load8(left, dataTempRegister); 1308 // Be careful that the previous load8() uses immTempRegister. 1309 // So, we need to put move() after load8(). 1310 move(right, immTempRegister); 1311 return branch32(cond, dataTempRegister, immTempRegister); 1312 } 1313 1314 Jump branch32(RelationalCondition cond, RegisterID left, RegisterID right) 1315 { 1316 if (cond == Equal) 1317 return branchEqual(left, right); 1318 if (cond == NotEqual) 1319 return branchNotEqual(left, right); 1320 if (cond == Above) { 1321 m_assembler.sltu(cmpTempRegister, right, left); 1322 return branchNotEqual(cmpTempRegister, MIPSRegisters::zero); 1323 } 1324 if (cond == AboveOrEqual) { 1325 m_assembler.sltu(cmpTempRegister, left, right); 1326 return branchEqual(cmpTempRegister, MIPSRegisters::zero); 1327 } 1328 if (cond == Below) { 1329 m_assembler.sltu(cmpTempRegister, left, right); 1330 return branchNotEqual(cmpTempRegister, MIPSRegisters::zero); 1331 } 1332 if (cond == BelowOrEqual) { 1333 m_assembler.sltu(cmpTempRegister, right, left); 1334 return branchEqual(cmpTempRegister, MIPSRegisters::zero); 1335 } 1336 if (cond == GreaterThan) { 1337 m_assembler.slt(cmpTempRegister, right, left); 1338 return branchNotEqual(cmpTempRegister, MIPSRegisters::zero); 1339 } 1340 if (cond == GreaterThanOrEqual) { 1341 m_assembler.slt(cmpTempRegister, left, right); 1342 return branchEqual(cmpTempRegister, MIPSRegisters::zero); 1343 } 1344 if (cond == LessThan) { 1345 m_assembler.slt(cmpTempRegister, left, right); 1346 return branchNotEqual(cmpTempRegister, MIPSRegisters::zero); 1347 } 1348 if (cond == LessThanOrEqual) { 1349 m_assembler.slt(cmpTempRegister, right, left); 1350 return branchEqual(cmpTempRegister, MIPSRegisters::zero); 1351 } 1352 ASSERT(0); 1353 1354 return Jump(); 1355 } 1356 1357 Jump branch32(RelationalCondition cond, RegisterID left, TrustedImm32 right) 1358 { 1359 move(right, immTempRegister); 1360 return branch32(cond, left, immTempRegister); 1361 } 1362 1363 Jump branch32(RelationalCondition cond, RegisterID left, Address right) 1364 { 1365 load32(right, dataTempRegister); 1366 return branch32(cond, left, dataTempRegister); 1367 } 1368 1369 Jump branch32(RelationalCondition cond, Address left, RegisterID right) 1370 { 1371 load32(left, dataTempRegister); 1372 return branch32(cond, dataTempRegister, right); 1373 } 1374 1375 Jump branch32(RelationalCondition cond, Address left, TrustedImm32 right) 1376 { 1377 load32(left, dataTempRegister); 1378 move(right, immTempRegister); 1379 return branch32(cond, dataTempRegister, immTempRegister); 1380 } 1381 1382 Jump branch32(RelationalCondition cond, BaseIndex left, TrustedImm32 right) 1383 { 1384 load32(left, dataTempRegister); 1385 // Be careful that the previous load32() uses immTempRegister. 1386 // So, we need to put move() after load32(). 1387 move(right, immTempRegister); 1388 return branch32(cond, dataTempRegister, immTempRegister); 1389 } 1390 1391 Jump branch32WithUnalignedHalfWords(RelationalCondition cond, BaseIndex left, TrustedImm32 right) 1392 { 1393 load32WithUnalignedHalfWords(left, dataTempRegister); 1394 // Be careful that the previous load32WithUnalignedHalfWords() 1395 // uses immTempRegister. 1396 // So, we need to put move() after load32WithUnalignedHalfWords(). 1397 move(right, immTempRegister); 1398 return branch32(cond, dataTempRegister, immTempRegister); 1399 } 1400 1401 Jump branch32(RelationalCondition cond, AbsoluteAddress left, RegisterID right) 1402 { 1403 load32(left.m_ptr, dataTempRegister); 1404 return branch32(cond, dataTempRegister, right); 1405 } 1406 1407 Jump branch32(RelationalCondition cond, AbsoluteAddress left, TrustedImm32 right) 1408 { 1409 load32(left.m_ptr, dataTempRegister); 1410 move(right, immTempRegister); 1411 return branch32(cond, dataTempRegister, immTempRegister); 1412 } 1413 1414 Jump branchTest32(ResultCondition cond, RegisterID reg, RegisterID mask) 1415 { 1416 ASSERT((cond == Zero) || (cond == NonZero)); 1417 m_assembler.andInsn(cmpTempRegister, reg, mask); 1418 if (cond == Zero) 1419 return branchEqual(cmpTempRegister, MIPSRegisters::zero); 1420 return branchNotEqual(cmpTempRegister, MIPSRegisters::zero); 1421 } 1422 1423 Jump branchTest32(ResultCondition cond, RegisterID reg, TrustedImm32 mask = TrustedImm32(-1)) 1424 { 1425 ASSERT((cond == Zero) || (cond == NonZero)); 1426 if (mask.m_value == -1 && !m_fixedWidth) { 1427 if (cond == Zero) 1428 return branchEqual(reg, MIPSRegisters::zero); 1429 return branchNotEqual(reg, MIPSRegisters::zero); 1430 } 1431 move(mask, immTempRegister); 1432 return branchTest32(cond, reg, immTempRegister); 1433 } 1434 1435 Jump branchTest32(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1)) 1436 { 1437 load32(address, dataTempRegister); 1438 return branchTest32(cond, dataTempRegister, mask); 1439 } 1440 1441 Jump branchTest32(ResultCondition cond, BaseIndex address, TrustedImm32 mask = TrustedImm32(-1)) 1442 { 1443 load32(address, dataTempRegister); 1444 return branchTest32(cond, dataTempRegister, mask); 1445 } 1446 1447 Jump branchTest8(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1)) 1448 { 1449 load8(address, dataTempRegister); 1450 return branchTest32(cond, dataTempRegister, mask); 1451 } 1452 1453 Jump branchTest8(ResultCondition cond, AbsoluteAddress address, TrustedImm32 mask = TrustedImm32(-1)) 1454 { 1455 move(TrustedImmPtr(address.m_ptr), dataTempRegister); 1456 load8(Address(dataTempRegister), dataTempRegister); 1457 return branchTest32(cond, dataTempRegister, mask); 1458 } 1459 1460 Jump jump() 1461 { 1462 return branchEqual(MIPSRegisters::zero, MIPSRegisters::zero); 1463 } 1464 1465 void jump(RegisterID target) 1466 { 1467 move(target, MIPSRegisters::t9); 1468 m_assembler.jr(MIPSRegisters::t9); 1469 m_assembler.nop(); 1470 } 1471 1472 void jump(Address address) 1473 { 1474 m_fixedWidth = true; 1475 load32(address, MIPSRegisters::t9); 1476 m_assembler.jr(MIPSRegisters::t9); 1477 m_assembler.nop(); 1478 m_fixedWidth = false; 1479 } 1480 1481 void jump(AbsoluteAddress address) 1482 { 1483 m_fixedWidth = true; 1484 load32(address.m_ptr, MIPSRegisters::t9); 1485 m_assembler.jr(MIPSRegisters::t9); 1486 m_assembler.nop(); 1487 m_fixedWidth = false; 1488 } 1489 1490 void moveDoubleToInts(FPRegisterID src, RegisterID dest1, RegisterID dest2) 1491 { 1492 m_assembler.vmov(dest1, dest2, src); 1493 } 1494 1495 void moveIntsToDouble(RegisterID src1, RegisterID src2, FPRegisterID dest, FPRegisterID scratch) 1496 { 1497 UNUSED_PARAM(scratch); 1498 m_assembler.vmov(dest, src1, src2); 1499 } 1500 1501 // Arithmetic control flow operations: 1502 // 1503 // This set of conditional branch operations branch based 1504 // on the result of an arithmetic operation. The operation 1505 // is performed as normal, storing the result. 1506 // 1507 // * jz operations branch if the result is zero. 1508 // * jo operations branch if the (signed) arithmetic 1509 // operation caused an overflow to occur. 1510 1511 Jump branchAdd32(ResultCondition cond, RegisterID src, RegisterID dest) 1512 { 1513 ASSERT((cond == Overflow) || (cond == Signed) || (cond == PositiveOrZero) || (cond == Zero) || (cond == NonZero)); 1514 if (cond == Overflow) { 1515 /* 1516 move dest, dataTemp 1517 xor cmpTemp, dataTemp, src 1518 bltz cmpTemp, No_overflow # diff sign bit -> no overflow 1519 addu dest, dataTemp, src 1520 xor cmpTemp, dest, dataTemp 1521 bgez cmpTemp, No_overflow # same sign big -> no overflow 1522 nop 1523 b Overflow 1524 nop 1525 nop 1526 nop 1527 nop 1528 nop 1529 No_overflow: 1530 */ 1531 move(dest, dataTempRegister); 1532 m_assembler.xorInsn(cmpTempRegister, dataTempRegister, src); 1533 m_assembler.bltz(cmpTempRegister, 10); 1534 m_assembler.addu(dest, dataTempRegister, src); 1535 m_assembler.xorInsn(cmpTempRegister, dest, dataTempRegister); 1536 m_assembler.bgez(cmpTempRegister, 7); 1537 m_assembler.nop(); 1538 return jump(); 1539 } 1540 if (cond == Signed) { 1541 add32(src, dest); 1542 // Check if dest is negative. 1543 m_assembler.slt(cmpTempRegister, dest, MIPSRegisters::zero); 1544 return branchNotEqual(cmpTempRegister, MIPSRegisters::zero); 1545 } 1546 if (cond == PositiveOrZero) { 1547 add32(src, dest); 1548 // Check if dest is not negative. 1549 m_assembler.slt(cmpTempRegister, dest, MIPSRegisters::zero); 1550 return branchEqual(cmpTempRegister, MIPSRegisters::zero); 1551 } 1552 if (cond == Zero) { 1553 add32(src, dest); 1554 return branchEqual(dest, MIPSRegisters::zero); 1555 } 1556 if (cond == NonZero) { 1557 add32(src, dest); 1558 return branchNotEqual(dest, MIPSRegisters::zero); 1559 } 1560 ASSERT(0); 1561 return Jump(); 1562 } 1563 1564 Jump branchAdd32(ResultCondition cond, RegisterID op1, RegisterID op2, RegisterID dest) 1565 { 1566 ASSERT((cond == Overflow) || (cond == Signed) || (cond == PositiveOrZero) || (cond == Zero) || (cond == NonZero)); 1567 if (cond == Overflow) { 1568 /* 1569 move dataTemp, op1 1570 xor cmpTemp, dataTemp, op2 1571 bltz cmpTemp, No_overflow # diff sign bit -> no overflow 1572 addu dest, dataTemp, op2 1573 xor cmpTemp, dest, dataTemp 1574 bgez cmpTemp, No_overflow # same sign big -> no overflow 1575 nop 1576 b Overflow 1577 nop 1578 nop 1579 nop 1580 nop 1581 nop 1582 No_overflow: 1583 */ 1584 move(op1, dataTempRegister); 1585 m_assembler.xorInsn(cmpTempRegister, dataTempRegister, op2); 1586 m_assembler.bltz(cmpTempRegister, 10); 1587 m_assembler.addu(dest, dataTempRegister, op2); 1588 m_assembler.xorInsn(cmpTempRegister, dest, dataTempRegister); 1589 m_assembler.bgez(cmpTempRegister, 7); 1590 m_assembler.nop(); 1591 return jump(); 1592 } 1593 if (cond == Signed) { 1594 add32(op1, op2, dest); 1595 // Check if dest is negative. 1596 m_assembler.slt(cmpTempRegister, dest, MIPSRegisters::zero); 1597 return branchNotEqual(cmpTempRegister, MIPSRegisters::zero); 1598 } 1599 if (cond == PositiveOrZero) { 1600 add32(op1, op2, dest); 1601 // Check if dest is not negative. 1602 m_assembler.slt(cmpTempRegister, dest, MIPSRegisters::zero); 1603 return branchEqual(cmpTempRegister, MIPSRegisters::zero); 1604 } 1605 if (cond == Zero) { 1606 add32(op1, op2, dest); 1607 return branchEqual(dest, MIPSRegisters::zero); 1608 } 1609 if (cond == NonZero) { 1610 add32(op1, op2, dest); 1611 return branchNotEqual(dest, MIPSRegisters::zero); 1612 } 1613 ASSERT(0); 1614 return Jump(); 1615 } 1616 1617 Jump branchAdd32(ResultCondition cond, TrustedImm32 imm, RegisterID dest) 1618 { 1619 move(imm, immTempRegister); 1620 return branchAdd32(cond, immTempRegister, dest); 1621 } 1622 1623 Jump branchAdd32(ResultCondition cond, RegisterID src, TrustedImm32 imm, RegisterID dest) 1624 { 1625 move(imm, immTempRegister); 1626 move(src, dest); 1627 return branchAdd32(cond, immTempRegister, dest); 1628 } 1629 1630 Jump branchAdd32(ResultCondition cond, TrustedImm32 imm, AbsoluteAddress dest) 1631 { 1632 ASSERT((cond == Overflow) || (cond == Signed) || (cond == PositiveOrZero) || (cond == Zero) || (cond == NonZero)); 1633 if (cond == Overflow) { 1634 /* 1635 move dataTemp, dest 1636 xori cmpTemp, dataTemp, imm 1637 bltz cmpTemp, No_overflow # diff sign bit -> no overflow 1638 addiu dataTemp, dataTemp, imm 1639 move dest, dataTemp 1640 xori cmpTemp, dataTemp, imm 1641 bgez cmpTemp, No_overflow # same sign big -> no overflow 1642 nop 1643 b Overflow 1644 nop 1645 nop 1646 nop 1647 nop 1648 nop 1649 No_overflow: 1650 */ 1651 if (imm.m_value >= -32768 && imm.m_value <= 32767 && !m_fixedWidth) { 1652 load32(dest.m_ptr, dataTempRegister); 1653 m_assembler.xori(cmpTempRegister, dataTempRegister, imm.m_value); 1654 m_assembler.bltz(cmpTempRegister, 10); 1655 m_assembler.addiu(dataTempRegister, dataTempRegister, imm.m_value); 1656 store32(dataTempRegister, dest.m_ptr); 1657 m_assembler.xori(cmpTempRegister, dataTempRegister, imm.m_value); 1658 m_assembler.bgez(cmpTempRegister, 7); 1659 m_assembler.nop(); 1660 } else { 1661 load32(dest.m_ptr, dataTempRegister); 1662 move(imm, immTempRegister); 1663 m_assembler.xorInsn(cmpTempRegister, dataTempRegister, immTempRegister); 1664 m_assembler.bltz(cmpTempRegister, 10); 1665 m_assembler.addiu(dataTempRegister, dataTempRegister, immTempRegister); 1666 store32(dataTempRegister, dest.m_ptr); 1667 m_assembler.xori(cmpTempRegister, dataTempRegister, immTempRegister); 1668 m_assembler.bgez(cmpTempRegister, 7); 1669 m_assembler.nop(); 1670 } 1671 return jump(); 1672 } 1673 move(imm, immTempRegister); 1674 load32(dest.m_ptr, dataTempRegister); 1675 add32(immTempRegister, dataTempRegister); 1676 store32(dataTempRegister, dest.m_ptr); 1677 if (cond == Signed) { 1678 // Check if dest is negative. 1679 m_assembler.slt(cmpTempRegister, dataTempRegister, MIPSRegisters::zero); 1680 return branchNotEqual(cmpTempRegister, MIPSRegisters::zero); 1681 } 1682 if (cond == PositiveOrZero) { 1683 // Check if dest is not negative. 1684 m_assembler.slt(cmpTempRegister, dataTempRegister, MIPSRegisters::zero); 1685 return branchEqual(cmpTempRegister, MIPSRegisters::zero); 1686 } 1687 if (cond == Zero) 1688 return branchEqual(dataTempRegister, MIPSRegisters::zero); 1689 if (cond == NonZero) 1690 return branchNotEqual(dataTempRegister, MIPSRegisters::zero); 1691 ASSERT(0); 1692 return Jump(); 1693 } 1694 1695 Jump branchMul32(ResultCondition cond, RegisterID src1, RegisterID src2, RegisterID dest) 1696 { 1697 ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); 1698 if (cond == Overflow) { 1699 /* 1700 mult src, dest 1701 mfhi dataTemp 1702 mflo dest 1703 sra addrTemp, dest, 31 1704 beq dataTemp, addrTemp, No_overflow # all sign bits (bit 63 to bit 31) are the same -> no overflow 1705 nop 1706 b Overflow 1707 nop 1708 nop 1709 nop 1710 nop 1711 nop 1712 No_overflow: 1713 */ 1714 m_assembler.mult(src1, src2); 1715 m_assembler.mfhi(dataTempRegister); 1716 m_assembler.mflo(dest); 1717 m_assembler.sra(addrTempRegister, dest, 31); 1718 m_assembler.beq(dataTempRegister, addrTempRegister, 7); 1719 m_assembler.nop(); 1720 return jump(); 1721 } 1722 if (cond == Signed) { 1723 mul32(src1, src2, dest); 1724 // Check if dest is negative. 1725 m_assembler.slt(cmpTempRegister, dest, MIPSRegisters::zero); 1726 return branchNotEqual(cmpTempRegister, MIPSRegisters::zero); 1727 } 1728 if (cond == Zero) { 1729 mul32(src1, src2, dest); 1730 return branchEqual(dest, MIPSRegisters::zero); 1731 } 1732 if (cond == NonZero) { 1733 mul32(src1, src2, dest); 1734 return branchNotEqual(dest, MIPSRegisters::zero); 1735 } 1736 ASSERT(0); 1737 return Jump(); 1738 } 1739 1740 Jump branchMul32(ResultCondition cond, RegisterID src, RegisterID dest) 1741 { 1742 ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); 1743 if (cond == Overflow) { 1744 /* 1745 mult src, dest 1746 mfhi dataTemp 1747 mflo dest 1748 sra addrTemp, dest, 31 1749 beq dataTemp, addrTemp, No_overflow # all sign bits (bit 63 to bit 31) are the same -> no overflow 1750 nop 1751 b Overflow 1752 nop 1753 nop 1754 nop 1755 nop 1756 nop 1757 No_overflow: 1758 */ 1759 m_assembler.mult(src, dest); 1760 m_assembler.mfhi(dataTempRegister); 1761 m_assembler.mflo(dest); 1762 m_assembler.sra(addrTempRegister, dest, 31); 1763 m_assembler.beq(dataTempRegister, addrTempRegister, 7); 1764 m_assembler.nop(); 1765 return jump(); 1766 } 1767 if (cond == Signed) { 1768 mul32(src, dest); 1769 // Check if dest is negative. 1770 m_assembler.slt(cmpTempRegister, dest, MIPSRegisters::zero); 1771 return branchNotEqual(cmpTempRegister, MIPSRegisters::zero); 1772 } 1773 if (cond == Zero) { 1774 mul32(src, dest); 1775 return branchEqual(dest, MIPSRegisters::zero); 1776 } 1777 if (cond == NonZero) { 1778 mul32(src, dest); 1779 return branchNotEqual(dest, MIPSRegisters::zero); 1780 } 1781 ASSERT(0); 1782 return Jump(); 1783 } 1784 1785 Jump branchMul32(ResultCondition cond, TrustedImm32 imm, RegisterID src, RegisterID dest) 1786 { 1787 move(imm, immTempRegister); 1788 return branchMul32(cond, immTempRegister, src, dest); 1789 } 1790 1791 Jump branchSub32(ResultCondition cond, RegisterID src, RegisterID dest) 1792 { 1793 ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); 1794 if (cond == Overflow) { 1795 /* 1796 move dest, dataTemp 1797 xor cmpTemp, dataTemp, src 1798 bgez cmpTemp, No_overflow # same sign bit -> no overflow 1799 subu dest, dataTemp, src 1800 xor cmpTemp, dest, dataTemp 1801 bgez cmpTemp, No_overflow # same sign bit -> no overflow 1802 nop 1803 b Overflow 1804 nop 1805 nop 1806 nop 1807 nop 1808 nop 1809 No_overflow: 1810 */ 1811 move(dest, dataTempRegister); 1812 m_assembler.xorInsn(cmpTempRegister, dataTempRegister, src); 1813 m_assembler.bgez(cmpTempRegister, 10); 1814 m_assembler.subu(dest, dataTempRegister, src); 1815 m_assembler.xorInsn(cmpTempRegister, dest, dataTempRegister); 1816 m_assembler.bgez(cmpTempRegister, 7); 1817 m_assembler.nop(); 1818 return jump(); 1819 } 1820 if (cond == Signed) { 1821 sub32(src, dest); 1822 // Check if dest is negative. 1823 m_assembler.slt(cmpTempRegister, dest, MIPSRegisters::zero); 1824 return branchNotEqual(cmpTempRegister, MIPSRegisters::zero); 1825 } 1826 if (cond == Zero) { 1827 sub32(src, dest); 1828 return branchEqual(dest, MIPSRegisters::zero); 1829 } 1830 if (cond == NonZero) { 1831 sub32(src, dest); 1832 return branchNotEqual(dest, MIPSRegisters::zero); 1833 } 1834 ASSERT(0); 1835 return Jump(); 1836 } 1837 1838 Jump branchSub32(ResultCondition cond, TrustedImm32 imm, RegisterID dest) 1839 { 1840 move(imm, immTempRegister); 1841 return branchSub32(cond, immTempRegister, dest); 1842 } 1843 1844 Jump branchSub32(ResultCondition cond, RegisterID src, TrustedImm32 imm, RegisterID dest) 1845 { 1846 move(imm, immTempRegister); 1847 return branchSub32(cond, src, immTempRegister, dest); 1848 } 1849 1850 Jump branchSub32(ResultCondition cond, RegisterID op1, RegisterID op2, RegisterID dest) 1851 { 1852 ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); 1853 if (cond == Overflow) { 1854 /* 1855 move dataTemp, op1 1856 xor cmpTemp, dataTemp, op2 1857 bgez cmpTemp, No_overflow # same sign bit -> no overflow 1858 subu dest, dataTemp, op2 1859 xor cmpTemp, dest, dataTemp 1860 bgez cmpTemp, No_overflow # same sign bit -> no overflow 1861 nop 1862 b Overflow 1863 nop 1864 nop 1865 nop 1866 nop 1867 nop 1868 No_overflow: 1869 */ 1870 move(op1, dataTempRegister); 1871 m_assembler.xorInsn(cmpTempRegister, dataTempRegister, op2); 1872 m_assembler.bgez(cmpTempRegister, 10); 1873 m_assembler.subu(dest, dataTempRegister, op2); 1874 m_assembler.xorInsn(cmpTempRegister, dest, dataTempRegister); 1875 m_assembler.bgez(cmpTempRegister, 7); 1876 m_assembler.nop(); 1877 return jump(); 1878 } 1879 if (cond == Signed) { 1880 sub32(op1, op2, dest); 1881 // Check if dest is negative. 1882 m_assembler.slt(cmpTempRegister, dest, MIPSRegisters::zero); 1883 return branchNotEqual(cmpTempRegister, MIPSRegisters::zero); 1884 } 1885 if (cond == Zero) { 1886 sub32(op1, op2, dest); 1887 return branchEqual(dest, MIPSRegisters::zero); 1888 } 1889 if (cond == NonZero) { 1890 sub32(op1, op2, dest); 1891 return branchNotEqual(dest, MIPSRegisters::zero); 1892 } 1893 ASSERT(0); 1894 return Jump(); 1895 } 1896 1897 Jump branchNeg32(ResultCondition cond, RegisterID srcDest) 1898 { 1899 m_assembler.li(dataTempRegister, -1); 1900 return branchMul32(cond, dataTempRegister, srcDest); 1901 } 1902 1903 Jump branchOr32(ResultCondition cond, RegisterID src, RegisterID dest) 1904 { 1905 ASSERT((cond == Signed) || (cond == Zero) || (cond == NonZero)); 1906 if (cond == Signed) { 1907 or32(src, dest); 1908 // Check if dest is negative. 1909 m_assembler.slt(cmpTempRegister, dest, MIPSRegisters::zero); 1910 return branchNotEqual(cmpTempRegister, MIPSRegisters::zero); 1911 } 1912 if (cond == Zero) { 1913 or32(src, dest); 1914 return branchEqual(dest, MIPSRegisters::zero); 1915 } 1916 if (cond == NonZero) { 1917 or32(src, dest); 1918 return branchNotEqual(dest, MIPSRegisters::zero); 1919 } 1920 ASSERT(0); 1921 return Jump(); 1922 } 1923 1924 // Miscellaneous operations: 1925 1926 void breakpoint() 1927 { 1928 m_assembler.bkpt(); 1929 } 1930 1931 Call nearCall() 1932 { 1933 /* We need two words for relaxation. */ 1934 m_assembler.nop(); 1935 m_assembler.nop(); 1936 m_assembler.jal(); 1937 m_assembler.nop(); 1938 return Call(m_assembler.label(), Call::LinkableNear); 1939 } 1940 1941 Call call() 1942 { 1943 m_assembler.lui(MIPSRegisters::t9, 0); 1944 m_assembler.ori(MIPSRegisters::t9, MIPSRegisters::t9, 0); 1945 m_assembler.jalr(MIPSRegisters::t9); 1946 m_assembler.nop(); 1947 return Call(m_assembler.label(), Call::Linkable); 1948 } 1949 1950 Call call(RegisterID target) 1951 { 1952 move(target, MIPSRegisters::t9); 1953 m_assembler.jalr(MIPSRegisters::t9); 1954 m_assembler.nop(); 1955 return Call(m_assembler.label(), Call::None); 1956 } 1957 1958 Call call(Address address) 1959 { 1960 m_fixedWidth = true; 1961 load32(address, MIPSRegisters::t9); 1962 m_assembler.jalr(MIPSRegisters::t9); 1963 m_assembler.nop(); 1964 m_fixedWidth = false; 1965 return Call(m_assembler.label(), Call::None); 1966 } 1967 1968 void ret() 1969 { 1970 m_assembler.jr(MIPSRegisters::ra); 1971 m_assembler.nop(); 1972 } 1973 1974 void compare32(RelationalCondition cond, RegisterID left, RegisterID right, RegisterID dest) 1975 { 1976 if (cond == Equal) { 1977 m_assembler.xorInsn(dest, left, right); 1978 m_assembler.sltiu(dest, dest, 1); 1979 } else if (cond == NotEqual) { 1980 m_assembler.xorInsn(dest, left, right); 1981 m_assembler.sltu(dest, MIPSRegisters::zero, dest); 1982 } else if (cond == Above) 1983 m_assembler.sltu(dest, right, left); 1984 else if (cond == AboveOrEqual) { 1985 m_assembler.sltu(dest, left, right); 1986 m_assembler.xori(dest, dest, 1); 1987 } else if (cond == Below) 1988 m_assembler.sltu(dest, left, right); 1989 else if (cond == BelowOrEqual) { 1990 m_assembler.sltu(dest, right, left); 1991 m_assembler.xori(dest, dest, 1); 1992 } else if (cond == GreaterThan) 1993 m_assembler.slt(dest, right, left); 1994 else if (cond == GreaterThanOrEqual) { 1995 m_assembler.slt(dest, left, right); 1996 m_assembler.xori(dest, dest, 1); 1997 } else if (cond == LessThan) 1998 m_assembler.slt(dest, left, right); 1999 else if (cond == LessThanOrEqual) { 2000 m_assembler.slt(dest, right, left); 2001 m_assembler.xori(dest, dest, 1); 2002 } 2003 } 2004 2005 void compare32(RelationalCondition cond, RegisterID left, TrustedImm32 right, RegisterID dest) 2006 { 2007 move(right, immTempRegister); 2008 compare32(cond, left, immTempRegister, dest); 2009 } 2010 2011 void test8(ResultCondition cond, Address address, TrustedImm32 mask, RegisterID dest) 2012 { 2013 ASSERT((cond == Zero) || (cond == NonZero)); 2014 load8(address, dataTempRegister); 2015 if (mask.m_value == -1 && !m_fixedWidth) { 2016 if (cond == Zero) 2017 m_assembler.sltiu(dest, dataTempRegister, 1); 2018 else 2019 m_assembler.sltu(dest, MIPSRegisters::zero, dataTempRegister); 2020 } else { 2021 move(mask, immTempRegister); 2022 m_assembler.andInsn(cmpTempRegister, dataTempRegister, immTempRegister); 2023 if (cond == Zero) 2024 m_assembler.sltiu(dest, cmpTempRegister, 1); 2025 else 2026 m_assembler.sltu(dest, MIPSRegisters::zero, cmpTempRegister); 2027 } 2028 } 2029 2030 void test32(ResultCondition cond, Address address, TrustedImm32 mask, RegisterID dest) 2031 { 2032 ASSERT((cond == Zero) || (cond == NonZero)); 2033 load32(address, dataTempRegister); 2034 if (mask.m_value == -1 && !m_fixedWidth) { 2035 if (cond == Zero) 2036 m_assembler.sltiu(dest, dataTempRegister, 1); 2037 else 2038 m_assembler.sltu(dest, MIPSRegisters::zero, dataTempRegister); 2039 } else { 2040 move(mask, immTempRegister); 2041 m_assembler.andInsn(cmpTempRegister, dataTempRegister, immTempRegister); 2042 if (cond == Zero) 2043 m_assembler.sltiu(dest, cmpTempRegister, 1); 2044 else 2045 m_assembler.sltu(dest, MIPSRegisters::zero, cmpTempRegister); 2046 } 2047 } 2048 2049 DataLabel32 moveWithPatch(TrustedImm32 imm, RegisterID dest) 2050 { 2051 m_fixedWidth = true; 2052 DataLabel32 label(this); 2053 move(imm, dest); 2054 m_fixedWidth = false; 2055 return label; 2056 } 2057 2058 DataLabelPtr moveWithPatch(TrustedImmPtr initialValue, RegisterID dest) 2059 { 2060 m_fixedWidth = true; 2061 DataLabelPtr label(this); 2062 move(initialValue, dest); 2063 m_fixedWidth = false; 2064 return label; 2065 } 2066 2067 Jump branchPtrWithPatch(RelationalCondition cond, RegisterID left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0)) 2068 { 2069 m_fixedWidth = true; 2070 dataLabel = moveWithPatch(initialRightValue, immTempRegister); 2071 Jump temp = branch32(cond, left, immTempRegister); 2072 m_fixedWidth = false; 2073 return temp; 2074 } 2075 2076 Jump branchPtrWithPatch(RelationalCondition cond, Address left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0)) 2077 { 2078 m_fixedWidth = true; 2079 load32(left, dataTempRegister); 2080 dataLabel = moveWithPatch(initialRightValue, immTempRegister); 2081 Jump temp = branch32(cond, dataTempRegister, immTempRegister); 2082 m_fixedWidth = false; 2083 return temp; 2084 } 2085 2086 DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address) 2087 { 2088 m_fixedWidth = true; 2089 DataLabelPtr dataLabel = moveWithPatch(initialValue, dataTempRegister); 2090 store32(dataTempRegister, address); 2091 m_fixedWidth = false; 2092 return dataLabel; 2093 } 2094 2095 DataLabelPtr storePtrWithPatch(ImplicitAddress address) 2096 { 2097 return storePtrWithPatch(TrustedImmPtr(0), address); 2098 } 2099 2100 Call tailRecursiveCall() 2101 { 2102 // Like a normal call, but don't update the returned address register 2103 m_fixedWidth = true; 2104 move(TrustedImm32(0), MIPSRegisters::t9); 2105 m_assembler.jr(MIPSRegisters::t9); 2106 m_assembler.nop(); 2107 m_fixedWidth = false; 2108 return Call(m_assembler.label(), Call::Linkable); 2109 } 2110 2111 Call makeTailRecursiveCall(Jump oldJump) 2112 { 2113 oldJump.link(this); 2114 return tailRecursiveCall(); 2115 } 2116 2117 void loadFloat(BaseIndex address, FPRegisterID dest) 2118 { 2119 if (address.offset >= -32768 && address.offset <= 32767 2120 && !m_fixedWidth) { 2121 /* 2122 sll addrTemp, address.index, address.scale 2123 addu addrTemp, addrTemp, address.base 2124 lwc1 dest, address.offset(addrTemp) 2125 */ 2126 m_assembler.sll(addrTempRegister, address.index, address.scale); 2127 m_assembler.addu(addrTempRegister, addrTempRegister, address.base); 2128 m_assembler.lwc1(dest, addrTempRegister, address.offset); 2129 } else { 2130 /* 2131 sll addrTemp, address.index, address.scale 2132 addu addrTemp, addrTemp, address.base 2133 lui immTemp, (address.offset + 0x8000) >> 16 2134 addu addrTemp, addrTemp, immTemp 2135 lwc1 dest, (address.offset & 0xffff)(at) 2136 */ 2137 m_assembler.sll(addrTempRegister, address.index, address.scale); 2138 m_assembler.addu(addrTempRegister, addrTempRegister, address.base); 2139 m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16); 2140 m_assembler.addu(addrTempRegister, addrTempRegister, immTempRegister); 2141 m_assembler.lwc1(dest, addrTempRegister, address.offset); 2142 } 2143 } 2144 2145 void loadDouble(ImplicitAddress address, FPRegisterID dest) 2146 { 2147#if WTF_MIPS_ISA(1) 2148 /* 2149 li addrTemp, address.offset 2150 addu addrTemp, addrTemp, base 2151 lwc1 dest, 0(addrTemp) 2152 lwc1 dest+1, 4(addrTemp) 2153 */ 2154 move(TrustedImm32(address.offset), addrTempRegister); 2155 m_assembler.addu(addrTempRegister, addrTempRegister, address.base); 2156 m_assembler.lwc1(dest, addrTempRegister, 0); 2157 m_assembler.lwc1(FPRegisterID(dest + 1), addrTempRegister, 4); 2158#else 2159 if (address.offset >= -32768 && address.offset <= 32767 2160 && !m_fixedWidth) { 2161 m_assembler.ldc1(dest, address.base, address.offset); 2162 } else { 2163 /* 2164 lui addrTemp, (offset + 0x8000) >> 16 2165 addu addrTemp, addrTemp, base 2166 ldc1 dest, (offset & 0xffff)(addrTemp) 2167 */ 2168 m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16); 2169 m_assembler.addu(addrTempRegister, addrTempRegister, address.base); 2170 m_assembler.ldc1(dest, addrTempRegister, address.offset); 2171 } 2172#endif 2173 } 2174 2175 void loadDouble(BaseIndex address, FPRegisterID dest) 2176 { 2177#if WTF_MIPS_ISA(1) 2178 if (address.offset >= -32768 && address.offset <= 32767 2179 && !m_fixedWidth) { 2180 /* 2181 sll addrTemp, address.index, address.scale 2182 addu addrTemp, addrTemp, address.base 2183 lwc1 dest, address.offset(addrTemp) 2184 lwc1 dest+1, (address.offset+4)(addrTemp) 2185 */ 2186 m_assembler.sll(addrTempRegister, address.index, address.scale); 2187 m_assembler.addu(addrTempRegister, addrTempRegister, address.base); 2188 m_assembler.lwc1(dest, addrTempRegister, address.offset); 2189 m_assembler.lwc1(FPRegisterID(dest + 1), addrTempRegister, address.offset + 4); 2190 } else { 2191 /* 2192 sll addrTemp, address.index, address.scale 2193 addu addrTemp, addrTemp, address.base 2194 lui immTemp, (address.offset + 0x8000) >> 16 2195 addu addrTemp, addrTemp, immTemp 2196 lwc1 dest, (address.offset & 0xffff)(at) 2197 lwc1 dest+1, (address.offset & 0xffff + 4)(at) 2198 */ 2199 m_assembler.sll(addrTempRegister, address.index, address.scale); 2200 m_assembler.addu(addrTempRegister, addrTempRegister, address.base); 2201 m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16); 2202 m_assembler.addu(addrTempRegister, addrTempRegister, immTempRegister); 2203 m_assembler.lwc1(dest, addrTempRegister, address.offset); 2204 m_assembler.lwc1(FPRegisterID(dest + 1), addrTempRegister, address.offset + 4); 2205 } 2206#else 2207 if (address.offset >= -32768 && address.offset <= 32767 2208 && !m_fixedWidth) { 2209 /* 2210 sll addrTemp, address.index, address.scale 2211 addu addrTemp, addrTemp, address.base 2212 ldc1 dest, address.offset(addrTemp) 2213 */ 2214 m_assembler.sll(addrTempRegister, address.index, address.scale); 2215 m_assembler.addu(addrTempRegister, addrTempRegister, address.base); 2216 m_assembler.ldc1(dest, addrTempRegister, address.offset); 2217 } else { 2218 /* 2219 sll addrTemp, address.index, address.scale 2220 addu addrTemp, addrTemp, address.base 2221 lui immTemp, (address.offset + 0x8000) >> 16 2222 addu addrTemp, addrTemp, immTemp 2223 ldc1 dest, (address.offset & 0xffff)(at) 2224 */ 2225 m_assembler.sll(addrTempRegister, address.index, address.scale); 2226 m_assembler.addu(addrTempRegister, addrTempRegister, address.base); 2227 m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16); 2228 m_assembler.addu(addrTempRegister, addrTempRegister, immTempRegister); 2229 m_assembler.ldc1(dest, addrTempRegister, address.offset); 2230 } 2231#endif 2232 } 2233 2234 void loadDouble(const void* address, FPRegisterID dest) 2235 { 2236#if WTF_MIPS_ISA(1) 2237 /* 2238 li addrTemp, address 2239 lwc1 dest, 0(addrTemp) 2240 lwc1 dest+1, 4(addrTemp) 2241 */ 2242 move(TrustedImmPtr(address), addrTempRegister); 2243 m_assembler.lwc1(dest, addrTempRegister, 0); 2244 m_assembler.lwc1(FPRegisterID(dest + 1), addrTempRegister, 4); 2245#else 2246 /* 2247 li addrTemp, address 2248 ldc1 dest, 0(addrTemp) 2249 */ 2250 move(TrustedImmPtr(address), addrTempRegister); 2251 m_assembler.ldc1(dest, addrTempRegister, 0); 2252#endif 2253 } 2254 2255 void storeFloat(FPRegisterID src, BaseIndex address) 2256 { 2257 if (address.offset >= -32768 && address.offset <= 32767 2258 && !m_fixedWidth) { 2259 /* 2260 sll addrTemp, address.index, address.scale 2261 addu addrTemp, addrTemp, address.base 2262 swc1 src, address.offset(addrTemp) 2263 */ 2264 m_assembler.sll(addrTempRegister, address.index, address.scale); 2265 m_assembler.addu(addrTempRegister, addrTempRegister, address.base); 2266 m_assembler.swc1(src, addrTempRegister, address.offset); 2267 } else { 2268 /* 2269 sll addrTemp, address.index, address.scale 2270 addu addrTemp, addrTemp, address.base 2271 lui immTemp, (address.offset + 0x8000) >> 16 2272 addu addrTemp, addrTemp, immTemp 2273 swc1 src, (address.offset & 0xffff)(at) 2274 */ 2275 m_assembler.sll(addrTempRegister, address.index, address.scale); 2276 m_assembler.addu(addrTempRegister, addrTempRegister, address.base); 2277 m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16); 2278 m_assembler.addu(addrTempRegister, addrTempRegister, immTempRegister); 2279 m_assembler.swc1(src, addrTempRegister, address.offset); 2280 } 2281 } 2282 2283 void storeDouble(FPRegisterID src, ImplicitAddress address) 2284 { 2285#if WTF_MIPS_ISA(1) 2286 /* 2287 li addrTemp, address.offset 2288 addu addrTemp, addrTemp, base 2289 swc1 dest, 0(addrTemp) 2290 swc1 dest+1, 4(addrTemp) 2291 */ 2292 move(TrustedImm32(address.offset), addrTempRegister); 2293 m_assembler.addu(addrTempRegister, addrTempRegister, address.base); 2294 m_assembler.swc1(src, addrTempRegister, 0); 2295 m_assembler.swc1(FPRegisterID(src + 1), addrTempRegister, 4); 2296#else 2297 if (address.offset >= -32768 && address.offset <= 32767 2298 && !m_fixedWidth) 2299 m_assembler.sdc1(src, address.base, address.offset); 2300 else { 2301 /* 2302 lui addrTemp, (offset + 0x8000) >> 16 2303 addu addrTemp, addrTemp, base 2304 sdc1 src, (offset & 0xffff)(addrTemp) 2305 */ 2306 m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16); 2307 m_assembler.addu(addrTempRegister, addrTempRegister, address.base); 2308 m_assembler.sdc1(src, addrTempRegister, address.offset); 2309 } 2310#endif 2311 } 2312 2313 void storeDouble(FPRegisterID src, BaseIndex address) 2314 { 2315#if WTF_MIPS_ISA(1) 2316 if (address.offset >= -32768 && address.offset <= 32767 2317 && !m_fixedWidth) { 2318 /* 2319 sll addrTemp, address.index, address.scale 2320 addu addrTemp, addrTemp, address.base 2321 swc1 src, address.offset(addrTemp) 2322 swc1 src+1, (address.offset + 4)(addrTemp) 2323 */ 2324 m_assembler.sll(addrTempRegister, address.index, address.scale); 2325 m_assembler.addu(addrTempRegister, addrTempRegister, address.base); 2326 m_assembler.swc1(src, addrTempRegister, address.offset); 2327 m_assembler.swc1(FPRegisterID(src + 1), addrTempRegister, address.offset + 4); 2328 } else { 2329 /* 2330 sll addrTemp, address.index, address.scale 2331 addu addrTemp, addrTemp, address.base 2332 lui immTemp, (address.offset + 0x8000) >> 16 2333 addu addrTemp, addrTemp, immTemp 2334 swc1 src, (address.offset & 0xffff)(at) 2335 swc1 src+1, (address.offset & 0xffff + 4)(at) 2336 */ 2337 m_assembler.sll(addrTempRegister, address.index, address.scale); 2338 m_assembler.addu(addrTempRegister, addrTempRegister, address.base); 2339 m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16); 2340 m_assembler.addu(addrTempRegister, addrTempRegister, immTempRegister); 2341 m_assembler.swc1(src, addrTempRegister, address.offset); 2342 m_assembler.swc1(FPRegisterID(src + 1), addrTempRegister, address.offset + 4); 2343 } 2344#else 2345 if (address.offset >= -32768 && address.offset <= 32767 2346 && !m_fixedWidth) { 2347 /* 2348 sll addrTemp, address.index, address.scale 2349 addu addrTemp, addrTemp, address.base 2350 sdc1 src, address.offset(addrTemp) 2351 */ 2352 m_assembler.sll(addrTempRegister, address.index, address.scale); 2353 m_assembler.addu(addrTempRegister, addrTempRegister, address.base); 2354 m_assembler.sdc1(src, addrTempRegister, address.offset); 2355 } else { 2356 /* 2357 sll addrTemp, address.index, address.scale 2358 addu addrTemp, addrTemp, address.base 2359 lui immTemp, (address.offset + 0x8000) >> 16 2360 addu addrTemp, addrTemp, immTemp 2361 sdc1 src, (address.offset & 0xffff)(at) 2362 */ 2363 m_assembler.sll(addrTempRegister, address.index, address.scale); 2364 m_assembler.addu(addrTempRegister, addrTempRegister, address.base); 2365 m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16); 2366 m_assembler.addu(addrTempRegister, addrTempRegister, immTempRegister); 2367 m_assembler.sdc1(src, addrTempRegister, address.offset); 2368 } 2369#endif 2370 } 2371 2372 void storeDouble(FPRegisterID src, const void* address) 2373 { 2374#if WTF_MIPS_ISA(1) 2375 move(TrustedImmPtr(address), addrTempRegister); 2376 m_assembler.swc1(src, addrTempRegister, 0); 2377 m_assembler.swc1(FPRegisterID(src + 1), addrTempRegister, 4); 2378#else 2379 move(TrustedImmPtr(address), addrTempRegister); 2380 m_assembler.sdc1(src, addrTempRegister, 0); 2381#endif 2382 } 2383 2384 void moveDouble(FPRegisterID src, FPRegisterID dest) 2385 { 2386 if (src != dest || m_fixedWidth) 2387 m_assembler.movd(dest, src); 2388 } 2389 2390 void swapDouble(FPRegisterID fr1, FPRegisterID fr2) 2391 { 2392 moveDouble(fr1, fpTempRegister); 2393 moveDouble(fr2, fr1); 2394 moveDouble(fpTempRegister, fr2); 2395 } 2396 2397 void addDouble(FPRegisterID src, FPRegisterID dest) 2398 { 2399 m_assembler.addd(dest, dest, src); 2400 } 2401 2402 void addDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest) 2403 { 2404 m_assembler.addd(dest, op1, op2); 2405 } 2406 2407 void addDouble(Address src, FPRegisterID dest) 2408 { 2409 loadDouble(src, fpTempRegister); 2410 m_assembler.addd(dest, dest, fpTempRegister); 2411 } 2412 2413 void addDouble(AbsoluteAddress address, FPRegisterID dest) 2414 { 2415 loadDouble(address.m_ptr, fpTempRegister); 2416 m_assembler.addd(dest, dest, fpTempRegister); 2417 } 2418 2419 void subDouble(FPRegisterID src, FPRegisterID dest) 2420 { 2421 m_assembler.subd(dest, dest, src); 2422 } 2423 2424 void subDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest) 2425 { 2426 m_assembler.subd(dest, op1, op2); 2427 } 2428 2429 void subDouble(Address src, FPRegisterID dest) 2430 { 2431 loadDouble(src, fpTempRegister); 2432 m_assembler.subd(dest, dest, fpTempRegister); 2433 } 2434 2435 void mulDouble(FPRegisterID src, FPRegisterID dest) 2436 { 2437 m_assembler.muld(dest, dest, src); 2438 } 2439 2440 void mulDouble(Address src, FPRegisterID dest) 2441 { 2442 loadDouble(src, fpTempRegister); 2443 m_assembler.muld(dest, dest, fpTempRegister); 2444 } 2445 2446 void mulDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest) 2447 { 2448 m_assembler.muld(dest, op1, op2); 2449 } 2450 2451 void divDouble(FPRegisterID src, FPRegisterID dest) 2452 { 2453 m_assembler.divd(dest, dest, src); 2454 } 2455 2456 void divDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest) 2457 { 2458 m_assembler.divd(dest, op1, op2); 2459 } 2460 2461 void divDouble(Address src, FPRegisterID dest) 2462 { 2463 loadDouble(src, fpTempRegister); 2464 m_assembler.divd(dest, dest, fpTempRegister); 2465 } 2466 2467 void negateDouble(FPRegisterID src, FPRegisterID dest) 2468 { 2469 m_assembler.negd(dest, src); 2470 } 2471 2472 void convertInt32ToDouble(RegisterID src, FPRegisterID dest) 2473 { 2474 m_assembler.mtc1(src, fpTempRegister); 2475 m_assembler.cvtdw(dest, fpTempRegister); 2476 } 2477 2478 void convertInt32ToDouble(Address src, FPRegisterID dest) 2479 { 2480 load32(src, dataTempRegister); 2481 m_assembler.mtc1(dataTempRegister, fpTempRegister); 2482 m_assembler.cvtdw(dest, fpTempRegister); 2483 } 2484 2485 void convertInt32ToDouble(AbsoluteAddress src, FPRegisterID dest) 2486 { 2487 load32(src.m_ptr, dataTempRegister); 2488 m_assembler.mtc1(dataTempRegister, fpTempRegister); 2489 m_assembler.cvtdw(dest, fpTempRegister); 2490 } 2491 2492 void convertFloatToDouble(FPRegisterID src, FPRegisterID dst) 2493 { 2494 m_assembler.cvtds(dst, src); 2495 } 2496 2497 void convertDoubleToFloat(FPRegisterID src, FPRegisterID dst) 2498 { 2499 m_assembler.cvtsd(dst, src); 2500 } 2501 2502 void insertRelaxationWords() 2503 { 2504 /* We need four words for relaxation. */ 2505 m_assembler.beq(MIPSRegisters::zero, MIPSRegisters::zero, 3); // Jump over nops; 2506 m_assembler.nop(); 2507 m_assembler.nop(); 2508 m_assembler.nop(); 2509 } 2510 2511 Jump branchTrue() 2512 { 2513 m_assembler.appendJump(); 2514 m_assembler.bc1t(); 2515 m_assembler.nop(); 2516 insertRelaxationWords(); 2517 return Jump(m_assembler.label()); 2518 } 2519 2520 Jump branchFalse() 2521 { 2522 m_assembler.appendJump(); 2523 m_assembler.bc1f(); 2524 m_assembler.nop(); 2525 insertRelaxationWords(); 2526 return Jump(m_assembler.label()); 2527 } 2528 2529 Jump branchEqual(RegisterID rs, RegisterID rt) 2530 { 2531 m_assembler.nop(); 2532 m_assembler.nop(); 2533 m_assembler.appendJump(); 2534 m_assembler.beq(rs, rt, 0); 2535 m_assembler.nop(); 2536 insertRelaxationWords(); 2537 return Jump(m_assembler.label()); 2538 } 2539 2540 Jump branchNotEqual(RegisterID rs, RegisterID rt) 2541 { 2542 m_assembler.nop(); 2543 m_assembler.nop(); 2544 m_assembler.appendJump(); 2545 m_assembler.bne(rs, rt, 0); 2546 m_assembler.nop(); 2547 insertRelaxationWords(); 2548 return Jump(m_assembler.label()); 2549 } 2550 2551 Jump branchDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right) 2552 { 2553 if (cond == DoubleEqual) { 2554 m_assembler.ceqd(left, right); 2555 return branchTrue(); 2556 } 2557 if (cond == DoubleNotEqual) { 2558 m_assembler.cueqd(left, right); 2559 return branchFalse(); // false 2560 } 2561 if (cond == DoubleGreaterThan) { 2562 m_assembler.cngtd(left, right); 2563 return branchFalse(); // false 2564 } 2565 if (cond == DoubleGreaterThanOrEqual) { 2566 m_assembler.cnged(left, right); 2567 return branchFalse(); // false 2568 } 2569 if (cond == DoubleLessThan) { 2570 m_assembler.cltd(left, right); 2571 return branchTrue(); 2572 } 2573 if (cond == DoubleLessThanOrEqual) { 2574 m_assembler.cled(left, right); 2575 return branchTrue(); 2576 } 2577 if (cond == DoubleEqualOrUnordered) { 2578 m_assembler.cueqd(left, right); 2579 return branchTrue(); 2580 } 2581 if (cond == DoubleNotEqualOrUnordered) { 2582 m_assembler.ceqd(left, right); 2583 return branchFalse(); // false 2584 } 2585 if (cond == DoubleGreaterThanOrUnordered) { 2586 m_assembler.coled(left, right); 2587 return branchFalse(); // false 2588 } 2589 if (cond == DoubleGreaterThanOrEqualOrUnordered) { 2590 m_assembler.coltd(left, right); 2591 return branchFalse(); // false 2592 } 2593 if (cond == DoubleLessThanOrUnordered) { 2594 m_assembler.cultd(left, right); 2595 return branchTrue(); 2596 } 2597 if (cond == DoubleLessThanOrEqualOrUnordered) { 2598 m_assembler.culed(left, right); 2599 return branchTrue(); 2600 } 2601 ASSERT(0); 2602 2603 return Jump(); 2604 } 2605 2606 // Truncates 'src' to an integer, and places the resulting 'dest'. 2607 // If the result is not representable as a 32 bit value, branch. 2608 // May also branch for some values that are representable in 32 bits 2609 // (specifically, in this case, INT_MAX 0x7fffffff). 2610 enum BranchTruncateType { BranchIfTruncateFailed, BranchIfTruncateSuccessful }; 2611 Jump branchTruncateDoubleToInt32(FPRegisterID src, RegisterID dest, BranchTruncateType branchType = BranchIfTruncateFailed) 2612 { 2613 m_assembler.truncwd(fpTempRegister, src); 2614 m_assembler.mfc1(dest, fpTempRegister); 2615 return branch32(branchType == BranchIfTruncateFailed ? Equal : NotEqual, dest, TrustedImm32(0x7fffffff)); 2616 } 2617 2618 Jump branchTruncateDoubleToUint32(FPRegisterID src, RegisterID dest, BranchTruncateType branchType = BranchIfTruncateFailed) 2619 { 2620 m_assembler.truncwd(fpTempRegister, src); 2621 m_assembler.mfc1(dest, fpTempRegister); 2622 return branch32(branchType == BranchIfTruncateFailed ? Equal : NotEqual, dest, TrustedImm32(0)); 2623 } 2624 2625 // Result is undefined if the value is outside of the integer range. 2626 void truncateDoubleToInt32(FPRegisterID src, RegisterID dest) 2627 { 2628 m_assembler.truncwd(fpTempRegister, src); 2629 m_assembler.mfc1(dest, fpTempRegister); 2630 } 2631 2632 // Result is undefined if src > 2^31 2633 void truncateDoubleToUint32(FPRegisterID src, RegisterID dest) 2634 { 2635 m_assembler.truncwd(fpTempRegister, src); 2636 m_assembler.mfc1(dest, fpTempRegister); 2637 } 2638 2639 // Convert 'src' to an integer, and places the resulting 'dest'. 2640 // If the result is not representable as a 32 bit value, branch. 2641 // May also branch for some values that are representable in 32 bits 2642 // (specifically, in this case, 0). 2643 void branchConvertDoubleToInt32(FPRegisterID src, RegisterID dest, JumpList& failureCases, FPRegisterID fpTemp, bool negZeroCheck = true) 2644 { 2645 m_assembler.cvtwd(fpTempRegister, src); 2646 m_assembler.mfc1(dest, fpTempRegister); 2647 2648 // If the result is zero, it might have been -0.0, and the double comparison won't catch this! 2649 if (negZeroCheck) 2650 failureCases.append(branch32(Equal, dest, MIPSRegisters::zero)); 2651 2652 // Convert the integer result back to float & compare to the original value - if not equal or unordered (NaN) then jump. 2653 convertInt32ToDouble(dest, fpTemp); 2654 failureCases.append(branchDouble(DoubleNotEqualOrUnordered, fpTemp, src)); 2655 } 2656 2657 Jump branchDoubleNonZero(FPRegisterID reg, FPRegisterID scratch) 2658 { 2659 m_assembler.vmov(scratch, MIPSRegisters::zero, MIPSRegisters::zero); 2660 return branchDouble(DoubleNotEqual, reg, scratch); 2661 } 2662 2663 Jump branchDoubleZeroOrNaN(FPRegisterID reg, FPRegisterID scratch) 2664 { 2665 m_assembler.vmov(scratch, MIPSRegisters::zero, MIPSRegisters::zero); 2666 return branchDouble(DoubleEqualOrUnordered, reg, scratch); 2667 } 2668 2669 // Invert a relational condition, e.g. == becomes !=, < becomes >=, etc. 2670 static RelationalCondition invert(RelationalCondition cond) 2671 { 2672 RelationalCondition r; 2673 if (cond == Equal) 2674 r = NotEqual; 2675 else if (cond == NotEqual) 2676 r = Equal; 2677 else if (cond == Above) 2678 r = BelowOrEqual; 2679 else if (cond == AboveOrEqual) 2680 r = Below; 2681 else if (cond == Below) 2682 r = AboveOrEqual; 2683 else if (cond == BelowOrEqual) 2684 r = Above; 2685 else if (cond == GreaterThan) 2686 r = LessThanOrEqual; 2687 else if (cond == GreaterThanOrEqual) 2688 r = LessThan; 2689 else if (cond == LessThan) 2690 r = GreaterThanOrEqual; 2691 else if (cond == LessThanOrEqual) 2692 r = GreaterThan; 2693 return r; 2694 } 2695 2696 void nop() 2697 { 2698 m_assembler.nop(); 2699 } 2700 2701 static FunctionPtr readCallTarget(CodeLocationCall call) 2702 { 2703 return FunctionPtr(reinterpret_cast<void(*)()>(MIPSAssembler::readCallTarget(call.dataLocation()))); 2704 } 2705 2706 static void replaceWithJump(CodeLocationLabel instructionStart, CodeLocationLabel destination) 2707 { 2708 MIPSAssembler::replaceWithJump(instructionStart.dataLocation(), destination.dataLocation()); 2709 } 2710 2711 static ptrdiff_t maxJumpReplacementSize() 2712 { 2713 MIPSAssembler::maxJumpReplacementSize(); 2714 return 0; 2715 } 2716 2717 static bool canJumpReplacePatchableBranchPtrWithPatch() { return false; } 2718 2719 static CodeLocationLabel startOfBranchPtrWithPatchOnRegister(CodeLocationDataLabelPtr label) 2720 { 2721 return label.labelAtOffset(0); 2722 } 2723 2724 static void revertJumpReplacementToBranchPtrWithPatch(CodeLocationLabel instructionStart, RegisterID, void* initialValue) 2725 { 2726 MIPSAssembler::revertJumpToMove(instructionStart.dataLocation(), immTempRegister, reinterpret_cast<int>(initialValue) & 0xffff); 2727 } 2728 2729 static CodeLocationLabel startOfPatchableBranchPtrWithPatchOnAddress(CodeLocationDataLabelPtr) 2730 { 2731 UNREACHABLE_FOR_PLATFORM(); 2732 return CodeLocationLabel(); 2733 } 2734 2735 static void revertJumpReplacementToPatchableBranchPtrWithPatch(CodeLocationLabel instructionStart, Address, void* initialValue) 2736 { 2737 UNREACHABLE_FOR_PLATFORM(); 2738 } 2739 2740 2741private: 2742 // If m_fixedWidth is true, we will generate a fixed number of instructions. 2743 // Otherwise, we can emit any number of instructions. 2744 bool m_fixedWidth; 2745 2746 friend class LinkBuffer; 2747 friend class RepatchBuffer; 2748 2749 static void linkCall(void* code, Call call, FunctionPtr function) 2750 { 2751 MIPSAssembler::linkCall(code, call.m_label, function.value()); 2752 } 2753 2754 static void repatchCall(CodeLocationCall call, CodeLocationLabel destination) 2755 { 2756 MIPSAssembler::relinkCall(call.dataLocation(), destination.executableAddress()); 2757 } 2758 2759 static void repatchCall(CodeLocationCall call, FunctionPtr destination) 2760 { 2761 MIPSAssembler::relinkCall(call.dataLocation(), destination.executableAddress()); 2762 } 2763 2764}; 2765 2766} 2767 2768#endif // ENABLE(ASSEMBLER) && CPU(MIPS) 2769 2770#endif // MacroAssemblerMIPS_h 2771