tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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, &notMagic);
   1076  } else {
   1077    branchTestMagic(Assembler::NotEqual, valaddr, label);
   1078  }
   1079 
   1080  branch32(cond, ToPayload(valaddr), Imm32(why), label);
   1081  bind(&notMagic);
   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(), &notSameValue);
   1092  } else {
   1093    branch32(Assembler::NotEqual, ToType(lhs), rhs.typeReg(), label);
   1094  }
   1095 
   1096  branch32(cond, ToPayload(lhs), rhs.payloadReg(), label);
   1097  bind(&notSameValue);
   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, &notInt32);
   1414    convertInt32ToDouble(src.payloadReg(), dest.fpu());
   1415    jump(&end);
   1416    bind(&notInt32);
   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, &notInt32);
   1430  convertInt32ToDouble(ToPayload(src), dest);
   1431  jump(&end);
   1432  bind(&notInt32);
   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 */