MacroAssembler-x86-inl.h (45353B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: set ts=8 sts=2 et sw=2 tw=80: 3 * This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef jit_x86_MacroAssembler_x86_inl_h 8 #define jit_x86_MacroAssembler_x86_inl_h 9 10 #include "jit/x86/MacroAssembler-x86.h" 11 12 #include "jit/x86-shared/MacroAssembler-x86-shared-inl.h" 13 14 namespace js { 15 namespace jit { 16 17 //{{{ check_macroassembler_style 18 19 void MacroAssembler::move64(Imm64 imm, Register64 dest) { 20 move32(Imm32(imm.value & 0xFFFFFFFFL), dest.low); 21 move32(Imm32((imm.value >> 32) & 0xFFFFFFFFL), dest.high); 22 } 23 24 void MacroAssembler::move64(Register64 src, Register64 dest) { 25 movl(src.low, dest.low); 26 movl(src.high, dest.high); 27 } 28 29 void MacroAssembler::moveDoubleToGPR64(FloatRegister src, Register64 dest) { 30 ScratchDoubleScope scratch(*this); 31 32 if (Assembler::HasSSE41()) { 33 vmovd(src, dest.low); 34 vpextrd(1, src, dest.high); 35 } else { 36 vmovd(src, dest.low); 37 moveDouble(src, scratch); 38 vpsrldq(Imm32(4), scratch, scratch); 39 vmovd(scratch, dest.high); 40 } 41 } 42 43 void MacroAssembler::moveGPR64ToDouble(Register64 src, FloatRegister dest) { 44 if (Assembler::HasSSE41()) { 45 vmovd(src.low, dest); 46 vpinsrd(1, src.high, dest, dest); 47 } else { 48 ScratchDoubleScope fpscratch(*this); 49 vmovd(src.low, dest); 50 vmovd(src.high, fpscratch); 51 vunpcklps(fpscratch, dest, dest); 52 } 53 } 54 55 void MacroAssembler::move64To32(Register64 src, Register dest) { 56 if (src.low != dest) { 57 movl(src.low, dest); 58 } 59 } 60 61 void MacroAssembler::move32To64ZeroExtend(Register src, Register64 dest) { 62 if (src != dest.low) { 63 movl(src, dest.low); 64 } 65 movl(Imm32(0), dest.high); 66 } 67 68 void MacroAssembler::move8To64SignExtend(Register src, Register64 dest) { 69 move8SignExtend(src, dest.low); 70 if (dest.low == eax && dest.high == edx) { 71 masm.cdq(); 72 } else { 73 movl(dest.low, dest.high); 74 sarl(Imm32(31), dest.high); 75 } 76 } 77 78 void MacroAssembler::move16To64SignExtend(Register src, Register64 dest) { 79 move16SignExtend(src, dest.low); 80 if (dest.low == eax && dest.high == edx) { 81 masm.cdq(); 82 } else { 83 movl(dest.low, dest.high); 84 sarl(Imm32(31), dest.high); 85 } 86 } 87 88 void MacroAssembler::move32To64SignExtend(Register src, Register64 dest) { 89 if (src != dest.low) { 90 movl(src, dest.low); 91 } 92 if (dest.low == eax && dest.high == edx) { 93 masm.cdq(); 94 } else { 95 movl(dest.low, dest.high); 96 sarl(Imm32(31), dest.high); 97 } 98 } 99 100 void MacroAssembler::move8SignExtendToPtr(Register src, Register dest) { 101 move8SignExtend(src, dest); 102 } 103 104 void MacroAssembler::move16SignExtendToPtr(Register src, Register dest) { 105 move16SignExtend(src, dest); 106 } 107 108 void MacroAssembler::move32SignExtendToPtr(Register src, Register dest) { 109 movl(src, dest); 110 } 111 112 void MacroAssembler::move32ZeroExtendToPtr(Register src, Register dest) { 113 movl(src, dest); 114 } 115 116 // =============================================================== 117 // Load instructions 118 119 void MacroAssembler::load32SignExtendToPtr(const Address& src, Register dest) { 120 load32(src, dest); 121 } 122 123 // =============================================================== 124 // Logical functions 125 126 void MacroAssembler::notPtr(Register reg) { notl(reg); } 127 128 void MacroAssembler::andPtr(Register src, Register dest) { andl(src, dest); } 129 130 void MacroAssembler::andPtr(Imm32 imm, Register dest) { andl(imm, dest); } 131 132 void MacroAssembler::andPtr(Imm32 imm, Register src, Register dest) { 133 if (src != dest) { 134 movl(src, dest); 135 } 136 andl(imm, dest); 137 } 138 139 void MacroAssembler::and64(Imm64 imm, Register64 dest) { 140 if (imm.low().value != int32_t(0xFFFFFFFF)) { 141 andl(imm.low(), dest.low); 142 } 143 if (imm.hi().value != int32_t(0xFFFFFFFF)) { 144 andl(imm.hi(), dest.high); 145 } 146 } 147 148 void MacroAssembler::or64(Imm64 imm, Register64 dest) { 149 if (imm.low().value != 0) { 150 orl(imm.low(), dest.low); 151 } 152 if (imm.hi().value != 0) { 153 orl(imm.hi(), dest.high); 154 } 155 } 156 157 void MacroAssembler::xor64(Imm64 imm, Register64 dest) { 158 if (imm.low().value != 0) { 159 xorl(imm.low(), dest.low); 160 } 161 if (imm.hi().value != 0) { 162 xorl(imm.hi(), dest.high); 163 } 164 } 165 166 void MacroAssembler::orPtr(Register src, Register dest) { orl(src, dest); } 167 168 void MacroAssembler::orPtr(Imm32 imm, Register dest) { orl(imm, dest); } 169 170 void MacroAssembler::orPtr(Imm32 imm, Register src, Register dest) { 171 if (src != dest) { 172 movl(src, dest); 173 } 174 orl(imm, dest); 175 } 176 177 void MacroAssembler::and64(Register64 src, Register64 dest) { 178 andl(src.low, dest.low); 179 andl(src.high, dest.high); 180 } 181 182 void MacroAssembler::or64(Register64 src, Register64 dest) { 183 orl(src.low, dest.low); 184 orl(src.high, dest.high); 185 } 186 187 void MacroAssembler::xor64(Register64 src, Register64 dest) { 188 xorl(src.low, dest.low); 189 xorl(src.high, dest.high); 190 } 191 192 void MacroAssembler::xorPtr(Register src, Register dest) { xorl(src, dest); } 193 194 void MacroAssembler::xorPtr(Imm32 imm, Register dest) { xorl(imm, dest); } 195 196 void MacroAssembler::xorPtr(Imm32 imm, Register src, Register dest) { 197 if (src != dest) { 198 movl(src, dest); 199 } 200 xorl(imm, dest); 201 } 202 203 // =============================================================== 204 // Swap instructions 205 206 void MacroAssembler::byteSwap64(Register64 reg) { 207 bswapl(reg.low); 208 bswapl(reg.high); 209 xchgl(reg.low, reg.high); 210 } 211 212 // =============================================================== 213 // Arithmetic functions 214 215 void MacroAssembler::addPtr(Register src, Register dest) { addl(src, dest); } 216 217 void MacroAssembler::addPtr(Imm32 imm, Register dest) { addl(imm, dest); } 218 219 void MacroAssembler::addPtr(ImmWord imm, Register dest) { 220 addl(Imm32(imm.value), dest); 221 } 222 223 void MacroAssembler::addPtr(Imm32 imm, const Address& dest) { 224 addl(imm, Operand(dest)); 225 } 226 227 void MacroAssembler::addPtr(Imm32 imm, const AbsoluteAddress& dest) { 228 addl(imm, Operand(dest)); 229 } 230 231 void MacroAssembler::addPtr(const Address& src, Register dest) { 232 addl(Operand(src), dest); 233 } 234 235 void MacroAssembler::add64(Register64 src, Register64 dest) { 236 addl(src.low, dest.low); 237 adcl(src.high, dest.high); 238 } 239 240 void MacroAssembler::add64(Imm32 imm, Register64 dest) { 241 addl(imm, dest.low); 242 adcl(Imm32(0), dest.high); 243 } 244 245 void MacroAssembler::add64(Imm64 imm, Register64 dest) { 246 if (imm.low().value == 0) { 247 addl(imm.hi(), dest.high); 248 return; 249 } 250 addl(imm.low(), dest.low); 251 adcl(imm.hi(), dest.high); 252 } 253 254 void MacroAssembler::addConstantDouble(double d, FloatRegister dest) { 255 Double* dbl = getDouble(d); 256 if (!dbl) { 257 return; 258 } 259 masm.vaddsd_mr(nullptr, dest.encoding(), dest.encoding()); 260 propagateOOM(dbl->uses.append(CodeOffset(masm.size()))); 261 } 262 263 CodeOffset MacroAssembler::sub32FromStackPtrWithPatch(Register dest) { 264 moveStackPtrTo(dest); 265 addlWithPatch(Imm32(0), dest); 266 return CodeOffset(currentOffset()); 267 } 268 269 void MacroAssembler::patchSub32FromStackPtr(CodeOffset offset, Imm32 imm) { 270 patchAddl(offset, -imm.value); 271 } 272 273 void MacroAssembler::subPtr(Register src, Register dest) { subl(src, dest); } 274 275 void MacroAssembler::subPtr(Register src, const Address& dest) { 276 subl(src, Operand(dest)); 277 } 278 279 void MacroAssembler::subPtr(Imm32 imm, Register dest) { subl(imm, dest); } 280 281 void MacroAssembler::subPtr(ImmWord imm, Register dest) { 282 subl(Imm32(imm.value), dest); 283 } 284 285 void MacroAssembler::subPtr(const Address& addr, Register dest) { 286 subl(Operand(addr), dest); 287 } 288 289 void MacroAssembler::sub64(Register64 src, Register64 dest) { 290 subl(src.low, dest.low); 291 sbbl(src.high, dest.high); 292 } 293 294 void MacroAssembler::sub64(Imm64 imm, Register64 dest) { 295 if (imm.low().value == 0) { 296 subl(imm.hi(), dest.high); 297 return; 298 } 299 subl(imm.low(), dest.low); 300 sbbl(imm.hi(), dest.high); 301 } 302 303 void MacroAssembler::mulHighUnsigned32(Imm32 imm, Register src, Register dest) { 304 // Preserve edx:eax, unless they're the destination register. 305 if (edx != dest) { 306 push(edx); 307 } 308 if (eax != dest) { 309 push(eax); 310 } 311 312 if (src != eax) { 313 // Compute edx:eax := eax ∗ src 314 movl(imm, eax); 315 mull(src); 316 } else { 317 // Compute edx:eax := eax ∗ edx 318 movl(imm, edx); 319 mull(edx); 320 } 321 322 // Move the high word from edx into |dest|. 323 if (edx != dest) { 324 movl(edx, dest); 325 } 326 327 // Restore edx:eax. 328 if (eax != dest) { 329 pop(eax); 330 } 331 if (edx != dest) { 332 pop(edx); 333 } 334 } 335 336 void MacroAssembler::mulPtr(Register rhs, Register srcDest) { 337 imull(rhs, srcDest); 338 } 339 340 void MacroAssembler::mulPtr(ImmWord rhs, Register srcDest) { 341 imull(Imm32(rhs.value), srcDest); 342 } 343 344 // Note: this function clobbers eax and edx. 345 void MacroAssembler::mul64(Imm64 imm, const Register64& dest) { 346 // LOW32 = LOW(LOW(dest) * LOW(imm)); 347 // HIGH32 = LOW(HIGH(dest) * LOW(imm)) [multiply imm into upper bits] 348 // + LOW(LOW(dest) * HIGH(imm)) [multiply dest into upper bits] 349 // + HIGH(LOW(dest) * LOW(imm)) [carry] 350 351 MOZ_ASSERT(dest.low != eax && dest.low != edx); 352 MOZ_ASSERT(dest.high != eax && dest.high != edx); 353 354 // HIGH(dest) = LOW(HIGH(dest) * LOW(imm)); 355 movl(Imm32(imm.value & 0xFFFFFFFFL), edx); 356 imull(edx, dest.high); 357 358 // edx:eax = LOW(dest) * LOW(imm); 359 movl(Imm32(imm.value & 0xFFFFFFFFL), edx); 360 movl(dest.low, eax); 361 mull(edx); 362 363 // HIGH(dest) += edx; 364 addl(edx, dest.high); 365 366 // HIGH(dest) += LOW(LOW(dest) * HIGH(imm)); 367 if (((imm.value >> 32) & 0xFFFFFFFFL) == 5) { 368 leal(Operand(dest.low, dest.low, TimesFour), edx); 369 } else { 370 MOZ_CRASH("Unsupported imm"); 371 } 372 addl(edx, dest.high); 373 374 // LOW(dest) = eax; 375 movl(eax, dest.low); 376 } 377 378 void MacroAssembler::mul64(Imm64 imm, const Register64& dest, 379 const Register temp) { 380 // LOW32 = LOW(LOW(dest) * LOW(src)); (1) 381 // HIGH32 = LOW(HIGH(dest) * LOW(src)) [multiply src into upper bits] (2) 382 // + LOW(LOW(dest) * HIGH(src)) [multiply dest into upper bits] (3) 383 // + HIGH(LOW(dest) * LOW(src)) [carry] (4) 384 385 MOZ_ASSERT(dest == Register64(edx, eax)); 386 MOZ_ASSERT(temp != edx && temp != eax); 387 388 movl(dest.low, temp); 389 390 // Compute mul64 391 imull(imm.low(), dest.high); // (2) 392 imull(imm.hi(), temp); // (3) 393 addl(dest.high, temp); 394 movl(imm.low(), dest.high); 395 mull(dest.high /*, dest.low*/); // (4) + (1) output in edx:eax 396 // (dest_hi:dest_lo) 397 addl(temp, dest.high); 398 } 399 400 void MacroAssembler::mul64(const Register64& src, const Register64& dest, 401 const Register temp) { 402 // LOW32 = LOW(LOW(dest) * LOW(src)); (1) 403 // HIGH32 = LOW(HIGH(dest) * LOW(src)) [multiply src into upper bits] (2) 404 // + LOW(LOW(dest) * HIGH(src)) [multiply dest into upper bits] (3) 405 // + HIGH(LOW(dest) * LOW(src)) [carry] (4) 406 407 MOZ_ASSERT(dest == Register64(edx, eax)); 408 MOZ_ASSERT(src != Register64(edx, eax) && src != Register64(eax, edx)); 409 410 // Make sure the rhs.high isn't the dest.high register anymore. 411 // This saves us from doing other register moves. 412 movl(dest.low, temp); 413 414 // Compute mul64 415 imull(src.low, dest.high); // (2) 416 imull(src.high, temp); // (3) 417 addl(dest.high, temp); 418 movl(src.low, dest.high); 419 mull(dest.high /*, dest.low*/); // (4) + (1) output in edx:eax 420 // (dest_hi:dest_lo) 421 addl(temp, dest.high); 422 } 423 424 void MacroAssembler::mulBy3(Register src, Register dest) { 425 lea(Operand(src, src, TimesTwo), dest); 426 } 427 428 void MacroAssembler::mulDoublePtr(ImmPtr imm, Register temp, 429 FloatRegister dest) { 430 movl(imm, temp); 431 vmulsd(Operand(temp, 0), dest, dest); 432 } 433 434 void MacroAssembler::inc64(AbsoluteAddress dest) { 435 addl(Imm32(1), Operand(dest)); 436 Label noOverflow; 437 j(NonZero, &noOverflow); 438 addl(Imm32(1), Operand(dest.offset(4))); 439 bind(&noOverflow); 440 } 441 442 void MacroAssembler::neg64(Register64 reg) { 443 negl(reg.low); 444 adcl(Imm32(0), reg.high); 445 negl(reg.high); 446 } 447 448 void MacroAssembler::negPtr(Register reg) { negl(reg); } 449 450 // =============================================================== 451 // Shift functions 452 453 void MacroAssembler::lshiftPtr(Imm32 imm, Register dest) { 454 lshift32(imm, dest); 455 } 456 457 void MacroAssembler::lshiftPtr(Imm32 imm, Register src, Register dest) { 458 lshift32(imm, src, dest); 459 } 460 461 void MacroAssembler::lshiftPtr(Register shift, Register srcDest) { 462 lshift32(shift, srcDest); 463 } 464 465 void MacroAssembler::flexibleLshiftPtr(Register shift, Register srcDest) { 466 flexibleLshift32(shift, srcDest); 467 } 468 469 void MacroAssembler::lshift64(Imm32 imm, Register64 dest) { 470 MOZ_ASSERT(0 <= imm.value && imm.value < 64); 471 if (imm.value < 32) { 472 shldl(imm, dest.low, dest.high); 473 shll(imm, dest.low); 474 return; 475 } 476 477 mov(dest.low, dest.high); 478 shll(Imm32(imm.value & 0x1f), dest.high); 479 xorl(dest.low, dest.low); 480 } 481 482 void MacroAssembler::lshift64(Register shift, Register64 srcDest) { 483 MOZ_ASSERT(shift == ecx); 484 MOZ_ASSERT(srcDest.low != ecx && srcDest.high != ecx); 485 486 Label done; 487 488 shldl_cl(srcDest.low, srcDest.high); 489 shll_cl(srcDest.low); 490 491 testl(Imm32(0x20), ecx); 492 j(Condition::Equal, &done); 493 494 // 32 - 63 bit shift 495 movl(srcDest.low, srcDest.high); 496 xorl(srcDest.low, srcDest.low); 497 498 bind(&done); 499 } 500 501 void MacroAssembler::rshiftPtr(Imm32 imm, Register dest) { 502 rshift32(imm, dest); 503 } 504 505 void MacroAssembler::rshiftPtr(Imm32 imm, Register src, Register dest) { 506 rshift32(imm, src, dest); 507 } 508 509 void MacroAssembler::rshiftPtr(Register shift, Register srcDest) { 510 rshift32(shift, srcDest); 511 } 512 513 void MacroAssembler::flexibleRshiftPtr(Register shift, Register srcDest) { 514 flexibleRshift32(shift, srcDest); 515 } 516 517 void MacroAssembler::rshift64(Imm32 imm, Register64 dest) { 518 MOZ_ASSERT(0 <= imm.value && imm.value < 64); 519 if (imm.value < 32) { 520 shrdl(imm, dest.high, dest.low); 521 shrl(imm, dest.high); 522 return; 523 } 524 525 movl(dest.high, dest.low); 526 shrl(Imm32(imm.value & 0x1f), dest.low); 527 xorl(dest.high, dest.high); 528 } 529 530 void MacroAssembler::rshift64(Register shift, Register64 srcDest) { 531 MOZ_ASSERT(shift == ecx); 532 MOZ_ASSERT(srcDest.low != ecx && srcDest.high != ecx); 533 534 Label done; 535 536 shrdl_cl(srcDest.high, srcDest.low); 537 shrl_cl(srcDest.high); 538 539 testl(Imm32(0x20), ecx); 540 j(Condition::Equal, &done); 541 542 // 32 - 63 bit shift 543 movl(srcDest.high, srcDest.low); 544 xorl(srcDest.high, srcDest.high); 545 546 bind(&done); 547 } 548 549 void MacroAssembler::rshiftPtrArithmetic(Imm32 imm, Register dest) { 550 rshift32Arithmetic(imm, dest); 551 } 552 553 void MacroAssembler::rshiftPtrArithmetic(Imm32 imm, Register src, 554 Register dest) { 555 rshift32Arithmetic(imm, src, dest); 556 } 557 558 void MacroAssembler::rshiftPtrArithmetic(Register shift, Register srcDest) { 559 rshift32Arithmetic(shift, srcDest); 560 } 561 562 void MacroAssembler::flexibleRshiftPtrArithmetic(Register shift, 563 Register srcDest) { 564 flexibleRshift32Arithmetic(shift, srcDest); 565 } 566 567 void MacroAssembler::rshift64Arithmetic(Imm32 imm, Register64 dest) { 568 MOZ_ASSERT(0 <= imm.value && imm.value < 64); 569 if (imm.value < 32) { 570 shrdl(imm, dest.high, dest.low); 571 sarl(imm, dest.high); 572 return; 573 } 574 575 movl(dest.high, dest.low); 576 sarl(Imm32(imm.value & 0x1f), dest.low); 577 sarl(Imm32(0x1f), dest.high); 578 } 579 580 void MacroAssembler::rshift64Arithmetic(Register shift, Register64 srcDest) { 581 MOZ_ASSERT(shift == ecx); 582 MOZ_ASSERT(srcDest.low != ecx && srcDest.high != ecx); 583 584 Label done; 585 586 shrdl_cl(srcDest.high, srcDest.low); 587 sarl_cl(srcDest.high); 588 589 testl(Imm32(0x20), ecx); 590 j(Condition::Equal, &done); 591 592 // 32 - 63 bit shift 593 movl(srcDest.high, srcDest.low); 594 sarl(Imm32(0x1f), srcDest.high); 595 596 bind(&done); 597 } 598 599 // =============================================================== 600 // Rotation functions 601 602 void MacroAssembler::rotateLeft64(Register count, Register64 src, 603 Register64 dest, Register temp) { 604 MOZ_ASSERT(src == dest, "defineReuseInput"); 605 MOZ_ASSERT(count == ecx, "defineFixed(ecx)"); 606 607 Label done; 608 609 movl(dest.high, temp); 610 shldl_cl(dest.low, dest.high); 611 shldl_cl(temp, dest.low); 612 613 testl(Imm32(0x20), count); 614 j(Condition::Equal, &done); 615 xchgl(dest.high, dest.low); 616 617 bind(&done); 618 } 619 620 void MacroAssembler::rotateRight64(Register count, Register64 src, 621 Register64 dest, Register temp) { 622 MOZ_ASSERT(src == dest, "defineReuseInput"); 623 MOZ_ASSERT(count == ecx, "defineFixed(ecx)"); 624 625 Label done; 626 627 movl(dest.high, temp); 628 shrdl_cl(dest.low, dest.high); 629 shrdl_cl(temp, dest.low); 630 631 testl(Imm32(0x20), count); 632 j(Condition::Equal, &done); 633 xchgl(dest.high, dest.low); 634 635 bind(&done); 636 } 637 638 void MacroAssembler::rotateLeft64(Imm32 count, Register64 src, Register64 dest, 639 Register temp) { 640 MOZ_ASSERT(src == dest, "defineReuseInput"); 641 642 int32_t amount = count.value & 0x3f; 643 if ((amount & 0x1f) != 0) { 644 movl(dest.high, temp); 645 shldl(Imm32(amount & 0x1f), dest.low, dest.high); 646 shldl(Imm32(amount & 0x1f), temp, dest.low); 647 } 648 649 if (!!(amount & 0x20)) { 650 xchgl(dest.high, dest.low); 651 } 652 } 653 654 void MacroAssembler::rotateRight64(Imm32 count, Register64 src, Register64 dest, 655 Register temp) { 656 MOZ_ASSERT(src == dest, "defineReuseInput"); 657 658 int32_t amount = count.value & 0x3f; 659 if ((amount & 0x1f) != 0) { 660 movl(dest.high, temp); 661 shrdl(Imm32(amount & 0x1f), dest.low, dest.high); 662 shrdl(Imm32(amount & 0x1f), temp, dest.low); 663 } 664 665 if (!!(amount & 0x20)) { 666 xchgl(dest.high, dest.low); 667 } 668 } 669 670 // =============================================================== 671 // Bit counting functions 672 673 void MacroAssembler::clz64(Register64 src, Register64 dest) { 674 if (AssemblerX86Shared::HasLZCNT()) { 675 Label nonzero, zero; 676 677 testl(src.high, src.high); 678 j(Assembler::Zero, &zero); 679 680 lzcntl(src.high, dest.low); 681 jump(&nonzero); 682 683 bind(&zero); 684 lzcntl(src.low, dest.low); 685 addl(Imm32(32), dest.low); 686 687 bind(&nonzero); 688 xorl(dest.high, dest.high); 689 return; 690 } 691 692 // Because |dest.low| may be equal to |src.low|, we rely on BSR not modifying 693 // its output when the input is zero. AMD ISA documents BSR not modifying the 694 // output and current Intel CPUs follow AMD. 695 696 Label nonzero, zero; 697 698 bsrl(src.high, dest.low); 699 j(Assembler::Zero, &zero); 700 orl(Imm32(32), dest.low); 701 jump(&nonzero); 702 703 bind(&zero); 704 bsrl(src.low, dest.low); 705 j(Assembler::NonZero, &nonzero); 706 movl(Imm32(0x7F), dest.low); 707 708 bind(&nonzero); 709 xorl(Imm32(0x3F), dest.low); 710 xorl(dest.high, dest.high); 711 } 712 713 void MacroAssembler::ctz64(Register64 src, Register64 dest) { 714 if (AssemblerX86Shared::HasBMI1()) { 715 Label nonzero, zero; 716 717 testl(src.low, src.low); 718 j(Assembler::Zero, &zero); 719 720 tzcntl(src.low, dest.low); 721 jump(&nonzero); 722 723 bind(&zero); 724 tzcntl(src.high, dest.low); 725 addl(Imm32(32), dest.low); 726 727 bind(&nonzero); 728 xorl(dest.high, dest.high); 729 return; 730 } 731 732 // Because |dest.low| may be equal to |src.low|, we rely on BSF not modifying 733 // its output when the input is zero. AMD ISA documents BSF not modifying the 734 // output and current Intel CPUs follow AMD. 735 736 Label done, nonzero; 737 738 bsfl(src.low, dest.low); 739 j(Assembler::NonZero, &done); 740 bsfl(src.high, dest.low); 741 j(Assembler::NonZero, &nonzero); 742 movl(Imm32(64), dest.low); 743 jump(&done); 744 745 bind(&nonzero); 746 orl(Imm32(32), dest.low); 747 748 bind(&done); 749 xorl(dest.high, dest.high); 750 } 751 752 void MacroAssembler::popcnt64(Register64 src, Register64 dest, Register tmp) { 753 // The tmp register is only needed if there is no native POPCNT. 754 755 MOZ_ASSERT(src.low != tmp && src.high != tmp); 756 MOZ_ASSERT(dest.low != tmp && dest.high != tmp); 757 758 if (dest.low != src.high) { 759 popcnt32(src.low, dest.low, tmp); 760 popcnt32(src.high, dest.high, tmp); 761 } else { 762 MOZ_ASSERT(dest.high != src.high); 763 popcnt32(src.low, dest.high, tmp); 764 popcnt32(src.high, dest.low, tmp); 765 } 766 addl(dest.high, dest.low); 767 xorl(dest.high, dest.high); 768 } 769 770 // =============================================================== 771 // Condition functions 772 773 void MacroAssembler::cmp64Set(Condition cond, Register64 lhs, Register64 rhs, 774 Register dest) { 775 if (lhs.high == dest || lhs.low == dest || rhs.high == dest || 776 rhs.low == dest) { 777 cmp64SetAliased(cond, lhs, rhs, dest); 778 } else { 779 cmp64SetNonAliased(cond, lhs, rhs, dest); 780 } 781 } 782 783 void MacroAssembler::cmp64Set(Condition cond, Register64 lhs, Imm64 rhs, 784 Register dest) { 785 if (rhs.value == 0 && 786 (cond == Assembler::Equal || cond == Assembler::NotEqual)) { 787 if (lhs.high == dest) { 788 or32(lhs.low, dest); 789 } else if (lhs.low == dest) { 790 or32(lhs.high, dest); 791 } else { 792 move32(lhs.high, dest); 793 or32(lhs.low, dest); 794 } 795 cmp32Set(cond, dest, Imm32(0), dest); 796 } else if (lhs.high == dest || lhs.low == dest) { 797 cmp64SetAliased(cond, lhs, rhs, dest); 798 } else { 799 cmp64SetNonAliased(cond, lhs, rhs, dest); 800 } 801 } 802 803 void MacroAssembler::cmp64Set(Condition cond, Address lhs, Register64 rhs, 804 Register dest) { 805 if (lhs.base == dest || rhs.high == dest || rhs.low == dest) { 806 cmp64SetAliased(cond, lhs, rhs, dest); 807 } else { 808 cmp64SetNonAliased(cond, lhs, rhs, dest); 809 } 810 } 811 812 void MacroAssembler::cmp64Set(Condition cond, Address lhs, Imm64 rhs, 813 Register dest) { 814 if (lhs.base == dest) { 815 cmp64SetAliased(cond, lhs, rhs, dest); 816 } else { 817 cmp64SetNonAliased(cond, lhs, rhs, dest); 818 } 819 } 820 821 template <typename T1, typename T2> 822 void MacroAssembler::cmpPtrSet(Condition cond, T1 lhs, T2 rhs, Register dest) { 823 bool destIsZero = maybeEmitSetZeroByteRegister(lhs, rhs, dest); 824 cmpPtr(lhs, rhs); 825 emitSet(cond, dest, destIsZero); 826 } 827 828 // =============================================================== 829 // Branch functions 830 831 void MacroAssembler::branch32(Condition cond, const AbsoluteAddress& lhs, 832 Register rhs, Label* label) { 833 cmp32(Operand(lhs), rhs); 834 j(cond, label); 835 } 836 837 void MacroAssembler::branch32(Condition cond, const AbsoluteAddress& lhs, 838 Imm32 rhs, Label* label) { 839 cmp32(Operand(lhs), rhs); 840 j(cond, label); 841 } 842 843 void MacroAssembler::branch32(Condition cond, wasm::SymbolicAddress lhs, 844 Imm32 rhs, Label* label) { 845 cmpl(rhs, lhs); 846 j(cond, label); 847 } 848 849 void MacroAssembler::branch64(Condition cond, Register64 lhs, Imm64 val, 850 Label* success, Label* fail) { 851 branch64Impl(cond, lhs, val, success, fail); 852 } 853 854 void MacroAssembler::branch64(Condition cond, Register64 lhs, Register64 rhs, 855 Label* success, Label* fail) { 856 branch64Impl(cond, lhs, rhs, success, fail); 857 } 858 859 void MacroAssembler::branch64(Condition cond, const Address& lhs, Imm64 val, 860 Label* success, Label* fail) { 861 branch64Impl(cond, lhs, val, success, fail); 862 } 863 864 void MacroAssembler::branch64(Condition cond, const Address& lhs, 865 Register64 rhs, Label* success, Label* fail) { 866 branch64Impl(cond, lhs, rhs, success, fail); 867 } 868 869 void MacroAssembler::branch64(Condition cond, const Address& lhs, 870 const Address& rhs, Register scratch, 871 Label* label) { 872 MOZ_ASSERT(cond == Assembler::NotEqual || cond == Assembler::Equal, 873 "other condition codes not supported"); 874 MOZ_ASSERT(lhs.base != scratch); 875 MOZ_ASSERT(rhs.base != scratch); 876 877 Label done; 878 879 load32(LowWord(rhs), scratch); 880 if (cond == Assembler::Equal) { 881 branch32(Assembler::NotEqual, LowWord(lhs), scratch, &done); 882 } else { 883 branch32(Assembler::NotEqual, LowWord(lhs), scratch, label); 884 } 885 886 load32(HighWord(rhs), scratch); 887 branch32(cond, HighWord(lhs), scratch, label); 888 889 bind(&done); 890 } 891 892 void MacroAssembler::branchTestPtr(Condition cond, Register lhs, ImmWord rhs, 893 Label* label) { 894 branchTestPtr(cond, lhs, Imm32(rhs.value), label); 895 } 896 897 void MacroAssembler::branchPtr(Condition cond, const AbsoluteAddress& lhs, 898 Register rhs, Label* label) { 899 branchPtrImpl(cond, lhs, rhs, label); 900 } 901 902 void MacroAssembler::branchPtr(Condition cond, const AbsoluteAddress& lhs, 903 ImmWord rhs, Label* label) { 904 branchPtrImpl(cond, lhs, rhs, label); 905 } 906 907 void MacroAssembler::branchPtr(Condition cond, wasm::SymbolicAddress lhs, 908 Register rhs, Label* label) { 909 cmpl(rhs, lhs); 910 j(cond, label); 911 } 912 913 void MacroAssembler::branchPrivatePtr(Condition cond, const Address& lhs, 914 Register rhs, Label* label) { 915 branchPtr(cond, lhs, rhs, label); 916 } 917 918 void MacroAssembler::branchTruncateFloat32ToPtr(FloatRegister src, 919 Register dest, Label* fail) { 920 branchTruncateFloat32ToInt32(src, dest, fail); 921 } 922 923 void MacroAssembler::branchTruncateFloat32MaybeModUint32(FloatRegister src, 924 Register dest, 925 Label* fail) { 926 branchTruncateFloat32ToInt32(src, dest, fail); 927 } 928 929 void MacroAssembler::branchTruncateFloat32ToInt32(FloatRegister src, 930 Register dest, Label* fail) { 931 vcvttss2si(src, dest); 932 933 // vcvttss2si returns 0x80000000 on failure. Test for it by 934 // subtracting 1 and testing overflow (this permits the use of a 935 // smaller immediate field). 936 cmp32(dest, Imm32(1)); 937 j(Assembler::Overflow, fail); 938 } 939 940 void MacroAssembler::branchTruncateDoubleToPtr(FloatRegister src, Register dest, 941 Label* fail) { 942 branchTruncateDoubleToInt32(src, dest, fail); 943 } 944 945 void MacroAssembler::branchTruncateDoubleMaybeModUint32(FloatRegister src, 946 Register dest, 947 Label* fail) { 948 // TODO: X64 supports supports integers up till 64bits. Here we only support 949 // 32bits, before failing. Implementing this for x86 might give a x86 kraken 950 // win. 951 branchTruncateDoubleToInt32(src, dest, fail); 952 } 953 954 void MacroAssembler::branchTruncateDoubleToInt32(FloatRegister src, 955 Register dest, Label* fail) { 956 vcvttsd2si(src, dest); 957 958 // vcvttsd2si returns 0x80000000 on failure. Test for it by 959 // subtracting 1 and testing overflow (this permits the use of a 960 // smaller immediate field). 961 cmp32(dest, Imm32(1)); 962 j(Assembler::Overflow, fail); 963 } 964 965 void MacroAssembler::branchInt64NotInPtrRange(Register64 src, Label* label) { 966 // The high-word needs to be either all zero or all one, depending on the MSB 967 // of the low-word. 968 push(src.low); 969 sarl(Imm32(31), src.low); 970 cmp32(src.low, src.high); 971 pop(src.low); 972 j(Assembler::NotEqual, label); 973 } 974 975 void MacroAssembler::branchUInt64NotInPtrRange(Register64 src, Label* label) { 976 // The low-word MSB and all bits in the high-word must be zero. 977 branchTest32(Assembler::Signed, src.low, src.low, label); 978 branchTest32(Assembler::NonZero, src.high, src.high, label); 979 } 980 981 void MacroAssembler::branchAdd64(Condition cond, Imm64 imm, Register64 dest, 982 Label* label) { 983 add64(imm, dest); 984 j(cond, label); 985 } 986 987 void MacroAssembler::branchTest32(Condition cond, const AbsoluteAddress& lhs, 988 Imm32 rhs, Label* label) { 989 test32(Operand(lhs), rhs); 990 j(cond, label); 991 } 992 993 void MacroAssembler::branchTest64(Condition cond, Register64 lhs, 994 Register64 rhs, Register temp, Label* success, 995 Label* fail) { 996 bool fallthrough = false; 997 Label fallthroughLabel; 998 999 if (!fail) { 1000 fail = &fallthroughLabel; 1001 fallthrough = true; 1002 } 1003 1004 if (cond == Assembler::Zero || cond == Assembler::NonZero) { 1005 if (lhs == rhs && temp != InvalidReg) { 1006 movl(lhs.low, temp); 1007 orl(lhs.high, temp); 1008 branchTest32(cond, temp, temp, success); 1009 } else if (cond == Assembler::Zero) { 1010 branchTest32(Assembler::NonZero, lhs.low, rhs.low, fail); 1011 branchTest32(Assembler::Zero, lhs.high, rhs.high, success); 1012 } else { 1013 branchTest32(Assembler::NonZero, lhs.low, rhs.low, success); 1014 branchTest32(Assembler::NonZero, lhs.high, rhs.high, success); 1015 } 1016 } else if (cond == Assembler::Signed || cond == Assembler::NotSigned) { 1017 branchTest32(cond, lhs.high, rhs.high, success); 1018 } else { 1019 MOZ_CRASH("Unsupported condition"); 1020 } 1021 1022 if (fallthrough) { 1023 bind(fail); 1024 } else { 1025 jump(fail); 1026 } 1027 } 1028 1029 void MacroAssembler::branchTest64(Condition cond, Register64 lhs, Imm64 rhs, 1030 Label* success, Label* fail) { 1031 bool fallthrough = false; 1032 Label fallthroughLabel; 1033 1034 if (!fail) { 1035 fail = &fallthroughLabel; 1036 fallthrough = true; 1037 } 1038 1039 if (cond == Assembler::Zero || cond == Assembler::NonZero) { 1040 if (rhs.hi().value == 0) { 1041 branchTest32(cond, lhs.low, rhs.low(), success); 1042 } else if (rhs.low().value == 0) { 1043 branchTest32(cond, lhs.high, rhs.hi(), success); 1044 } else if (cond == Assembler::Zero) { 1045 branchTest32(Assembler::NonZero, lhs.low, rhs.low(), fail); 1046 branchTest32(Assembler::Zero, lhs.high, rhs.hi(), success); 1047 } else { 1048 branchTest32(Assembler::NonZero, lhs.low, rhs.low(), success); 1049 branchTest32(Assembler::NonZero, lhs.high, rhs.hi(), success); 1050 } 1051 } else { 1052 MOZ_CRASH("Unsupported condition"); 1053 } 1054 1055 if (fallthrough) { 1056 bind(fail); 1057 } else { 1058 jump(fail); 1059 } 1060 } 1061 1062 void MacroAssembler::branchTestBooleanTruthy(bool truthy, 1063 const ValueOperand& value, 1064 Label* label) { 1065 test32(value.payloadReg(), value.payloadReg()); 1066 j(truthy ? NonZero : Zero, label); 1067 } 1068 1069 void MacroAssembler::branchTestMagic(Condition cond, const Address& valaddr, 1070 JSWhyMagic why, Label* label) { 1071 MOZ_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual); 1072 1073 Label notMagic; 1074 if (cond == Assembler::Equal) { 1075 branchTestMagic(Assembler::NotEqual, valaddr, ¬Magic); 1076 } else { 1077 branchTestMagic(Assembler::NotEqual, valaddr, label); 1078 } 1079 1080 branch32(cond, ToPayload(valaddr), Imm32(why), label); 1081 bind(¬Magic); 1082 } 1083 1084 template <typename T> 1085 void MacroAssembler::branchTestValue(Condition cond, const T& lhs, 1086 const ValueOperand& rhs, Label* label) { 1087 MOZ_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual); 1088 1089 Label notSameValue; 1090 if (cond == Assembler::Equal) { 1091 branch32(Assembler::NotEqual, ToType(lhs), rhs.typeReg(), ¬SameValue); 1092 } else { 1093 branch32(Assembler::NotEqual, ToType(lhs), rhs.typeReg(), label); 1094 } 1095 1096 branch32(cond, ToPayload(lhs), rhs.payloadReg(), label); 1097 bind(¬SameValue); 1098 } 1099 1100 void MacroAssembler::branchToComputedAddress(const BaseIndex& addr) { 1101 jmp(Operand(addr)); 1102 } 1103 1104 void MacroAssembler::cmp32MovePtr(Condition cond, Register lhs, Imm32 rhs, 1105 Register src, Register dest) { 1106 cmp32(lhs, rhs); 1107 cmovCCl(cond, Operand(src), dest); 1108 } 1109 1110 void MacroAssembler::cmp32LoadPtr(Condition cond, const Address& lhs, Imm32 rhs, 1111 const Address& src, Register dest) { 1112 cmp32(lhs, rhs); 1113 cmovCCl(cond, Operand(src), dest); 1114 } 1115 1116 void MacroAssembler::cmpPtrMovePtr(Condition cond, Register lhs, Imm32 rhs, 1117 Register src, Register dest) { 1118 cmp32MovePtr(cond, lhs, rhs, src, dest); 1119 } 1120 1121 void MacroAssembler::cmpPtrMovePtr(Condition cond, Register lhs, Register rhs, 1122 Register src, Register dest) { 1123 cmp32Move32(cond, lhs, rhs, src, dest); 1124 } 1125 1126 void MacroAssembler::cmpPtrMovePtr(Condition cond, Register lhs, 1127 const Address& rhs, Register src, 1128 Register dest) { 1129 cmp32Move32(cond, lhs, rhs, src, dest); 1130 } 1131 1132 void MacroAssembler::test32LoadPtr(Condition cond, const Address& addr, 1133 Imm32 mask, const Address& src, 1134 Register dest) { 1135 MOZ_ASSERT(cond == Assembler::Zero || cond == Assembler::NonZero); 1136 test32(addr, mask); 1137 cmovCCl(cond, Operand(src), dest); 1138 } 1139 1140 void MacroAssembler::test32MovePtr(Condition cond, Register operand, Imm32 mask, 1141 Register src, Register dest) { 1142 MOZ_ASSERT(cond == Assembler::Zero || cond == Assembler::NonZero); 1143 test32(operand, mask); 1144 cmovCCl(cond, Operand(src), dest); 1145 } 1146 1147 void MacroAssembler::test32MovePtr(Condition cond, const Address& addr, 1148 Imm32 mask, Register src, Register dest) { 1149 MOZ_ASSERT(cond == Assembler::Zero || cond == Assembler::NonZero); 1150 test32(addr, mask); 1151 cmovCCl(cond, Operand(src), dest); 1152 } 1153 1154 void MacroAssembler::spectreMovePtr(Condition cond, Register src, 1155 Register dest) { 1156 cmovCCl(cond, Operand(src), dest); 1157 } 1158 1159 void MacroAssembler::spectreBoundsCheck32(Register index, const Operand& length, 1160 Register maybeScratch, 1161 Label* failure) { 1162 Label failurePopValue; 1163 bool pushedValue = false; 1164 if (JitOptions.spectreIndexMasking) { 1165 if (maybeScratch == InvalidReg) { 1166 push(Imm32(0)); 1167 pushedValue = true; 1168 } else { 1169 move32(Imm32(0), maybeScratch); 1170 } 1171 } 1172 1173 cmp32(index, length); 1174 j(Assembler::AboveOrEqual, pushedValue ? &failurePopValue : failure); 1175 1176 if (JitOptions.spectreIndexMasking) { 1177 if (maybeScratch == InvalidReg) { 1178 Label done; 1179 cmovCCl(Assembler::AboveOrEqual, Operand(StackPointer, 0), index); 1180 lea(Operand(StackPointer, sizeof(void*)), StackPointer); 1181 jump(&done); 1182 1183 bind(&failurePopValue); 1184 lea(Operand(StackPointer, sizeof(void*)), StackPointer); 1185 jump(failure); 1186 1187 bind(&done); 1188 } else { 1189 cmovCCl(Assembler::AboveOrEqual, maybeScratch, index); 1190 } 1191 } 1192 } 1193 1194 void MacroAssembler::spectreBoundsCheck32(Register index, Register length, 1195 Register maybeScratch, 1196 Label* failure) { 1197 MOZ_ASSERT(length != maybeScratch); 1198 MOZ_ASSERT(index != maybeScratch); 1199 1200 spectreBoundsCheck32(index, Operand(length), maybeScratch, failure); 1201 } 1202 1203 void MacroAssembler::spectreBoundsCheck32(Register index, const Address& length, 1204 Register maybeScratch, 1205 Label* failure) { 1206 MOZ_ASSERT(index != length.base); 1207 MOZ_ASSERT(length.base != maybeScratch); 1208 MOZ_ASSERT(index != maybeScratch); 1209 1210 spectreBoundsCheck32(index, Operand(length), maybeScratch, failure); 1211 } 1212 1213 void MacroAssembler::spectreBoundsCheckPtr(Register index, Register length, 1214 Register maybeScratch, 1215 Label* failure) { 1216 spectreBoundsCheck32(index, length, maybeScratch, failure); 1217 } 1218 1219 void MacroAssembler::spectreBoundsCheckPtr(Register index, 1220 const Address& length, 1221 Register maybeScratch, 1222 Label* failure) { 1223 spectreBoundsCheck32(index, length, maybeScratch, failure); 1224 } 1225 1226 // ======================================================================== 1227 // SIMD 1228 1229 void MacroAssembler::extractLaneInt64x2(uint32_t lane, FloatRegister src, 1230 Register64 dest) { 1231 if (lane == 0) { 1232 vmovd(src, dest.low); 1233 } else { 1234 vpextrd(2 * lane, src, dest.low); 1235 } 1236 vpextrd(2 * lane + 1, src, dest.high); 1237 } 1238 1239 void MacroAssembler::replaceLaneInt64x2(unsigned lane, Register64 rhs, 1240 FloatRegister lhsDest) { 1241 vpinsrd(2 * lane, rhs.low, lhsDest, lhsDest); 1242 vpinsrd(2 * lane + 1, rhs.high, lhsDest, lhsDest); 1243 } 1244 1245 void MacroAssembler::replaceLaneInt64x2(unsigned lane, FloatRegister lhs, 1246 Register64 rhs, FloatRegister dest) { 1247 vpinsrd(2 * lane, rhs.low, lhs, dest); 1248 vpinsrd(2 * lane + 1, rhs.high, dest, dest); 1249 } 1250 1251 void MacroAssembler::splatX2(Register64 src, FloatRegister dest) { 1252 vmovd(src.low, dest); 1253 vpinsrd(1, src.high, dest, dest); 1254 vpunpcklqdq(dest, dest, dest); 1255 } 1256 1257 // ======================================================================== 1258 // Truncate floating point. 1259 1260 void MacroAssembler::truncateFloat32ToUInt64(Address src, Address dest, 1261 Register temp, 1262 FloatRegister floatTemp) { 1263 Label done; 1264 1265 loadFloat32(src, floatTemp); 1266 1267 truncateFloat32ToInt64(src, dest, temp); 1268 1269 // For unsigned conversion the case of [INT64, UINT64] needs to get handle 1270 // seperately. 1271 load32(HighWord(dest), temp); 1272 branch32(Assembler::Condition::NotSigned, temp, Imm32(0), &done); 1273 1274 // Move the value inside INT64 range. 1275 storeFloat32(floatTemp, dest); 1276 loadConstantFloat32(double(int64_t(0x8000000000000000)), floatTemp); 1277 vaddss(Operand(dest), floatTemp, floatTemp); 1278 storeFloat32(floatTemp, dest); 1279 truncateFloat32ToInt64(dest, dest, temp); 1280 1281 load32(HighWord(dest), temp); 1282 orl(Imm32(0x80000000), temp); 1283 store32(temp, HighWord(dest)); 1284 1285 bind(&done); 1286 } 1287 1288 void MacroAssembler::truncateDoubleToUInt64(Address src, Address dest, 1289 Register temp, 1290 FloatRegister floatTemp) { 1291 Label done; 1292 1293 loadDouble(src, floatTemp); 1294 1295 truncateDoubleToInt64(src, dest, temp); 1296 1297 // For unsigned conversion the case of [INT64, UINT64] needs to get handle 1298 // seperately. 1299 load32(HighWord(dest), temp); 1300 branch32(Assembler::Condition::NotSigned, temp, Imm32(0), &done); 1301 1302 // Move the value inside INT64 range. 1303 storeDouble(floatTemp, dest); 1304 loadConstantDouble(double(int64_t(0x8000000000000000)), floatTemp); 1305 vaddsd(Operand(dest), floatTemp, floatTemp); 1306 storeDouble(floatTemp, dest); 1307 truncateDoubleToInt64(dest, dest, temp); 1308 1309 load32(HighWord(dest), temp); 1310 orl(Imm32(0x80000000), temp); 1311 store32(temp, HighWord(dest)); 1312 1313 bind(&done); 1314 } 1315 1316 template <typename T> 1317 void MacroAssemblerX86::fallibleUnboxPtrImpl(const T& src, Register dest, 1318 JSValueType type, Label* fail) { 1319 switch (type) { 1320 case JSVAL_TYPE_OBJECT: 1321 asMasm().branchTestObject(Assembler::NotEqual, src, fail); 1322 break; 1323 case JSVAL_TYPE_STRING: 1324 asMasm().branchTestString(Assembler::NotEqual, src, fail); 1325 break; 1326 case JSVAL_TYPE_SYMBOL: 1327 asMasm().branchTestSymbol(Assembler::NotEqual, src, fail); 1328 break; 1329 case JSVAL_TYPE_BIGINT: 1330 asMasm().branchTestBigInt(Assembler::NotEqual, src, fail); 1331 break; 1332 default: 1333 MOZ_CRASH("Unexpected type"); 1334 } 1335 unboxNonDouble(src, dest, type); 1336 } 1337 1338 void MacroAssembler::fallibleUnboxPtr(const ValueOperand& src, Register dest, 1339 JSValueType type, Label* fail) { 1340 fallibleUnboxPtrImpl(src, dest, type, fail); 1341 } 1342 1343 void MacroAssembler::fallibleUnboxPtr(const Address& src, Register dest, 1344 JSValueType type, Label* fail) { 1345 fallibleUnboxPtrImpl(src, dest, type, fail); 1346 } 1347 1348 void MacroAssembler::fallibleUnboxPtr(const BaseIndex& src, Register dest, 1349 JSValueType type, Label* fail) { 1350 fallibleUnboxPtrImpl(src, dest, type, fail); 1351 } 1352 1353 void MacroAssembler::min32(Register lhs, Register rhs, Register dest) { 1354 minMax32(lhs, rhs, dest, /* isMax = */ false); 1355 } 1356 1357 void MacroAssembler::min32(Register lhs, Imm32 rhs, Register dest) { 1358 minMax32(lhs, rhs, dest, /* isMax = */ false); 1359 } 1360 1361 void MacroAssembler::max32(Register lhs, Register rhs, Register dest) { 1362 minMax32(lhs, rhs, dest, /* isMax = */ true); 1363 } 1364 1365 void MacroAssembler::max32(Register lhs, Imm32 rhs, Register dest) { 1366 minMax32(lhs, rhs, dest, /* isMax = */ true); 1367 } 1368 1369 void MacroAssembler::minPtr(Register lhs, Register rhs, Register dest) { 1370 minMax32(lhs, rhs, dest, /* isMax = */ false); 1371 } 1372 1373 void MacroAssembler::minPtr(Register lhs, ImmWord rhs, Register dest) { 1374 minMax32(lhs, Imm32(rhs.value), dest, /* isMax = */ false); 1375 } 1376 1377 void MacroAssembler::maxPtr(Register lhs, Register rhs, Register dest) { 1378 minMax32(lhs, rhs, dest, /* isMax = */ true); 1379 } 1380 1381 void MacroAssembler::maxPtr(Register lhs, ImmWord rhs, Register dest) { 1382 minMax32(lhs, Imm32(rhs.value), dest, /* isMax = */ true); 1383 } 1384 1385 //}}} check_macroassembler_style 1386 // =============================================================== 1387 1388 // Note: this function clobbers the source register. 1389 void MacroAssemblerX86::convertUInt32ToDouble(Register src, 1390 FloatRegister dest) { 1391 // src is [0, 2^32-1] 1392 subl(Imm32(0x80000000), src); 1393 1394 // Now src is [-2^31, 2^31-1] - int range, but not the same value. 1395 convertInt32ToDouble(src, dest); 1396 1397 // dest is now a double with the int range. 1398 // correct the double value by adding 0x80000000. 1399 asMasm().addConstantDouble(2147483648.0, dest); 1400 } 1401 1402 // Note: this function clobbers the source register. 1403 void MacroAssemblerX86::convertUInt32ToFloat32(Register src, 1404 FloatRegister dest) { 1405 convertUInt32ToDouble(src, dest); 1406 convertDoubleToFloat32(dest, dest); 1407 } 1408 1409 void MacroAssemblerX86::unboxValue(const ValueOperand& src, AnyRegister dest, 1410 JSValueType) { 1411 if (dest.isFloat()) { 1412 Label notInt32, end; 1413 asMasm().branchTestInt32(Assembler::NotEqual, src, ¬Int32); 1414 convertInt32ToDouble(src.payloadReg(), dest.fpu()); 1415 jump(&end); 1416 bind(¬Int32); 1417 unboxDouble(src, dest.fpu()); 1418 bind(&end); 1419 } else { 1420 if (src.payloadReg() != dest.gpr()) { 1421 movl(src.payloadReg(), dest.gpr()); 1422 } 1423 } 1424 } 1425 1426 template <typename T> 1427 void MacroAssemblerX86::loadInt32OrDouble(const T& src, FloatRegister dest) { 1428 Label notInt32, end; 1429 asMasm().branchTestInt32(Assembler::NotEqual, src, ¬Int32); 1430 convertInt32ToDouble(ToPayload(src), dest); 1431 jump(&end); 1432 bind(¬Int32); 1433 loadDouble(src, dest); 1434 bind(&end); 1435 } 1436 1437 template <typename T> 1438 void MacroAssemblerX86::loadUnboxedValue(const T& src, MIRType type, 1439 AnyRegister dest) { 1440 if (dest.isFloat()) { 1441 loadInt32OrDouble(src, dest.fpu()); 1442 } else { 1443 movl(Operand(src), dest.gpr()); 1444 } 1445 } 1446 1447 template <typename T1, typename T2> 1448 void MacroAssemblerX86::cmp64SetAliased(Condition cond, T1 lhs, T2 rhs, 1449 Register dest) { 1450 auto& masm = asMasm(); 1451 1452 Label success, done; 1453 1454 masm.branch64(cond, lhs, rhs, &success); 1455 masm.move32(Imm32(0), dest); 1456 masm.jump(&done); 1457 masm.bind(&success); 1458 masm.move32(Imm32(1), dest); 1459 masm.bind(&done); 1460 } 1461 1462 template <typename T1, typename T2> 1463 void MacroAssemblerX86::cmp64SetNonAliased(Condition cond, T1 lhs, T2 rhs, 1464 Register dest) { 1465 auto& masm = asMasm(); 1466 1467 Label done; 1468 1469 masm.move32(Imm32(1), dest); 1470 masm.branch64(cond, lhs, rhs, &done); 1471 masm.move32(Imm32(0), dest); 1472 masm.bind(&done); 1473 } 1474 1475 template <typename T1, typename T2> 1476 void MacroAssemblerX86::branch64Impl(Condition cond, T1 lhs, T2 rhs, 1477 Label* success, Label* fail) { 1478 auto& masm = asMasm(); 1479 1480 auto words = [](auto operand) { 1481 using Operand = decltype(operand); 1482 if constexpr (std::is_same_v<Operand, Imm64>) { 1483 return std::pair{operand.hi(), operand.low()}; 1484 } else if constexpr (std::is_same_v<Operand, Register64>) { 1485 return std::pair{operand.high, operand.low}; 1486 } else { 1487 return std::pair{HighWord(operand), LowWord(operand)}; 1488 } 1489 }; 1490 1491 auto [lhsHigh, lhsLow] = words(lhs); 1492 auto [rhsHigh, rhsLow] = words(rhs); 1493 1494 bool fallthrough = false; 1495 Label fallthroughLabel; 1496 1497 if (!fail) { 1498 fail = &fallthroughLabel; 1499 fallthrough = true; 1500 } 1501 1502 switch (cond) { 1503 case Assembler::Equal: 1504 masm.branch32(Assembler::NotEqual, lhsLow, rhsLow, fail); 1505 masm.branch32(Assembler::Equal, lhsHigh, rhsHigh, success); 1506 break; 1507 case Assembler::NotEqual: 1508 masm.branch32(Assembler::NotEqual, lhsLow, rhsLow, success); 1509 masm.branch32(Assembler::NotEqual, lhsHigh, rhsHigh, success); 1510 break; 1511 case Assembler::LessThan: 1512 case Assembler::LessThanOrEqual: 1513 case Assembler::GreaterThan: 1514 case Assembler::GreaterThanOrEqual: 1515 case Assembler::Below: 1516 case Assembler::BelowOrEqual: 1517 case Assembler::Above: 1518 case Assembler::AboveOrEqual: { 1519 Assembler::Condition cond1 = Assembler::ConditionWithoutEqual(cond); 1520 Assembler::Condition cond2 = 1521 Assembler::ConditionWithoutEqual(Assembler::InvertCondition(cond)); 1522 Assembler::Condition cond3 = Assembler::UnsignedCondition(cond); 1523 1524 cmp32(lhsHigh, rhsHigh); 1525 j(cond1, success); 1526 j(cond2, fail); 1527 cmp32(lhsLow, rhsLow); 1528 j(cond3, success); 1529 break; 1530 } 1531 default: 1532 MOZ_CRASH("Condition code not supported"); 1533 break; 1534 } 1535 1536 if (fallthrough) { 1537 bind(fail); 1538 } else { 1539 jump(fail); 1540 } 1541 } 1542 1543 } // namespace jit 1544 } // namespace js 1545 1546 #endif /* jit_x86_MacroAssembler_x86_inl_h */