tor-browser

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

MacroAssembler-arm64-inl.h (150610B)


      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_arm64_MacroAssembler_arm64_inl_h
      8 #define jit_arm64_MacroAssembler_arm64_inl_h
      9 
     10 #include "jit/arm64/MacroAssembler-arm64.h"
     11 
     12 namespace js {
     13 namespace jit {
     14 
     15 //{{{ check_macroassembler_style
     16 
     17 void MacroAssembler::move64(Register64 src, Register64 dest) {
     18  Mov(ARMRegister(dest.reg, 64), ARMRegister(src.reg, 64));
     19 }
     20 
     21 void MacroAssembler::move64(Imm64 imm, Register64 dest) {
     22  Mov(ARMRegister(dest.reg, 64), imm.value);
     23 }
     24 
     25 void MacroAssembler::moveFloat16ToGPR(FloatRegister src, Register dest) {
     26  // Direct "half-precision to 32-bit" move requires (FEAT_FP16), so we
     27  // instead use a "single-precision to 32-bit" move.
     28  Fmov(ARMRegister(dest, 32), ARMFPRegister(src, 32));
     29 
     30  // Ensure the hi-word is zeroed.
     31  Uxth(ARMRegister(dest, 32), ARMRegister(dest, 32));
     32 }
     33 
     34 void MacroAssembler::moveGPRToFloat16(Register src, FloatRegister dest) {
     35  // Ensure the hi-word is zeroed.
     36  Uxth(ARMRegister(src, 32), ARMRegister(src, 32));
     37 
     38  // Direct "32-bit to half-precision" move requires (FEAT_FP16), so we
     39  // instead use a "32-bit to single-precision" move.
     40  Fmov(ARMFPRegister(dest, 32), ARMRegister(src, 32));
     41 }
     42 
     43 void MacroAssembler::moveFloat32ToGPR(FloatRegister src, Register dest) {
     44  Fmov(ARMRegister(dest, 32), ARMFPRegister(src, 32));
     45 }
     46 
     47 void MacroAssembler::moveGPRToFloat32(Register src, FloatRegister dest) {
     48  Fmov(ARMFPRegister(dest, 32), ARMRegister(src, 32));
     49 }
     50 
     51 void MacroAssembler::move8ZeroExtend(Register src, Register dest) {
     52  Uxtb(ARMRegister(dest, 32), ARMRegister(src, 32));
     53 }
     54 
     55 void MacroAssembler::move8SignExtend(Register src, Register dest) {
     56  Sxtb(ARMRegister(dest, 32), ARMRegister(src, 32));
     57 }
     58 
     59 void MacroAssembler::move16SignExtend(Register src, Register dest) {
     60  Sxth(ARMRegister(dest, 32), ARMRegister(src, 32));
     61 }
     62 
     63 void MacroAssembler::moveDoubleToGPR64(FloatRegister src, Register64 dest) {
     64  Fmov(ARMRegister(dest.reg, 64), ARMFPRegister(src, 64));
     65 }
     66 
     67 void MacroAssembler::moveGPR64ToDouble(Register64 src, FloatRegister dest) {
     68  Fmov(ARMFPRegister(dest, 64), ARMRegister(src.reg, 64));
     69 }
     70 
     71 void MacroAssembler::moveLowDoubleToGPR(FloatRegister src, Register dest) {
     72  Fmov(ARMRegister(dest, 32), ARMFPRegister(src, 32));
     73 }
     74 
     75 void MacroAssembler::move64To32(Register64 src, Register dest) {
     76  Mov(ARMRegister(dest, 32), ARMRegister(src.reg, 32));
     77 }
     78 
     79 void MacroAssembler::move32To64ZeroExtend(Register src, Register64 dest) {
     80  Uxtw(ARMRegister(dest.reg, 64), ARMRegister(src, 64));
     81 }
     82 
     83 void MacroAssembler::move8To64SignExtend(Register src, Register64 dest) {
     84  Sxtb(ARMRegister(dest.reg, 64), ARMRegister(src, 32));
     85 }
     86 
     87 void MacroAssembler::move16To64SignExtend(Register src, Register64 dest) {
     88  Sxth(ARMRegister(dest.reg, 64), ARMRegister(src, 32));
     89 }
     90 
     91 void MacroAssembler::move32To64SignExtend(Register src, Register64 dest) {
     92  Sxtw(ARMRegister(dest.reg, 64), ARMRegister(src, 32));
     93 }
     94 
     95 void MacroAssembler::move8SignExtendToPtr(Register src, Register dest) {
     96  Sxtb(ARMRegister(dest, 64), ARMRegister(src, 32));
     97 }
     98 
     99 void MacroAssembler::move16SignExtendToPtr(Register src, Register dest) {
    100  Sxth(ARMRegister(dest, 64), ARMRegister(src, 32));
    101 }
    102 
    103 void MacroAssembler::move32SignExtendToPtr(Register src, Register dest) {
    104  Sxtw(ARMRegister(dest, 64), ARMRegister(src, 32));
    105 }
    106 
    107 void MacroAssembler::move32ZeroExtendToPtr(Register src, Register dest) {
    108  Uxtw(ARMRegister(dest, 64), ARMRegister(src, 64));
    109 }
    110 
    111 // ===============================================================
    112 // Load instructions
    113 
    114 void MacroAssembler::load32SignExtendToPtr(const Address& src, Register dest) {
    115  load32(src, dest);
    116  move32To64SignExtend(dest, Register64(dest));
    117 }
    118 
    119 void MacroAssembler::loadAbiReturnAddress(Register dest) { movePtr(lr, dest); }
    120 
    121 // ===============================================================
    122 // Logical instructions
    123 
    124 void MacroAssembler::not32(Register reg) {
    125  Orn(ARMRegister(reg, 32), vixl::wzr, ARMRegister(reg, 32));
    126 }
    127 
    128 void MacroAssembler::notPtr(Register reg) {
    129  Orn(ARMRegister(reg, 64), vixl::xzr, ARMRegister(reg, 64));
    130 }
    131 
    132 void MacroAssembler::and32(Register src, Register dest) {
    133  And(ARMRegister(dest, 32), ARMRegister(dest, 32),
    134      Operand(ARMRegister(src, 32)));
    135 }
    136 
    137 void MacroAssembler::and32(Imm32 imm, Register dest) { and32(imm, dest, dest); }
    138 
    139 void MacroAssembler::and32(Imm32 imm, Register src, Register dest) {
    140  And(ARMRegister(dest, 32), ARMRegister(src, 32), Operand(imm.value));
    141 }
    142 
    143 void MacroAssembler::and32(Imm32 imm, const Address& dest) {
    144  vixl::UseScratchRegisterScope temps(this);
    145  const ARMRegister scratch32 = temps.AcquireW();
    146  MOZ_ASSERT(scratch32.asUnsized() != dest.base);
    147  load32(dest, scratch32.asUnsized());
    148  And(scratch32, scratch32, Operand(imm.value));
    149  store32(scratch32.asUnsized(), dest);
    150 }
    151 
    152 void MacroAssembler::and32(const Address& src, Register dest) {
    153  vixl::UseScratchRegisterScope temps(this);
    154  const ARMRegister scratch32 = temps.AcquireW();
    155  MOZ_ASSERT(scratch32.asUnsized() != src.base);
    156  load32(src, scratch32.asUnsized());
    157  And(ARMRegister(dest, 32), ARMRegister(dest, 32), Operand(scratch32));
    158 }
    159 
    160 void MacroAssembler::andPtr(Register src, Register dest) {
    161  And(ARMRegister(dest, 64), ARMRegister(dest, 64),
    162      Operand(ARMRegister(src, 64)));
    163 }
    164 
    165 void MacroAssembler::andPtr(Imm32 imm, Register dest) {
    166  andPtr(imm, dest, dest);
    167 }
    168 
    169 void MacroAssembler::andPtr(Imm32 imm, Register src, Register dest) {
    170  And(ARMRegister(dest, 64), ARMRegister(src, 64), Operand(imm.value));
    171 }
    172 
    173 void MacroAssembler::and64(Imm64 imm, Register64 dest) {
    174  And(ARMRegister(dest.reg, 64), ARMRegister(dest.reg, 64), Operand(imm.value));
    175 }
    176 
    177 void MacroAssembler::and64(Register64 src, Register64 dest) {
    178  And(ARMRegister(dest.reg, 64), ARMRegister(dest.reg, 64),
    179      ARMRegister(src.reg, 64));
    180 }
    181 
    182 void MacroAssembler::or64(Imm64 imm, Register64 dest) {
    183  Orr(ARMRegister(dest.reg, 64), ARMRegister(dest.reg, 64), Operand(imm.value));
    184 }
    185 
    186 void MacroAssembler::or32(Imm32 imm, Register dest) { or32(imm, dest, dest); }
    187 
    188 void MacroAssembler::or32(Imm32 imm, Register src, Register dest) {
    189  Orr(ARMRegister(dest, 32), ARMRegister(src, 32), Operand(imm.value));
    190 }
    191 
    192 void MacroAssembler::or32(Register src, Register dest) {
    193  Orr(ARMRegister(dest, 32), ARMRegister(dest, 32),
    194      Operand(ARMRegister(src, 32)));
    195 }
    196 
    197 void MacroAssembler::or32(Imm32 imm, const Address& dest) {
    198  vixl::UseScratchRegisterScope temps(this);
    199  const ARMRegister scratch32 = temps.AcquireW();
    200  MOZ_ASSERT(scratch32.asUnsized() != dest.base);
    201  load32(dest, scratch32.asUnsized());
    202  Orr(scratch32, scratch32, Operand(imm.value));
    203  store32(scratch32.asUnsized(), dest);
    204 }
    205 
    206 void MacroAssembler::orPtr(Register src, Register dest) {
    207  Orr(ARMRegister(dest, 64), ARMRegister(dest, 64),
    208      Operand(ARMRegister(src, 64)));
    209 }
    210 
    211 void MacroAssembler::orPtr(Imm32 imm, Register dest) { orPtr(imm, dest, dest); }
    212 
    213 void MacroAssembler::orPtr(Imm32 imm, Register src, Register dest) {
    214  Orr(ARMRegister(dest, 64), ARMRegister(src, 64), Operand(imm.value));
    215 }
    216 
    217 void MacroAssembler::or64(Register64 src, Register64 dest) {
    218  orPtr(src.reg, dest.reg);
    219 }
    220 
    221 void MacroAssembler::xor64(Register64 src, Register64 dest) {
    222  xorPtr(src.reg, dest.reg);
    223 }
    224 
    225 void MacroAssembler::xor32(Register src, Register dest) {
    226  Eor(ARMRegister(dest, 32), ARMRegister(dest, 32),
    227      Operand(ARMRegister(src, 32)));
    228 }
    229 
    230 void MacroAssembler::xor32(Imm32 imm, Register dest) { xor32(imm, dest, dest); }
    231 
    232 void MacroAssembler::xor32(Imm32 imm, Register src, Register dest) {
    233  Eor(ARMRegister(dest, 32), ARMRegister(src, 32), Operand(imm.value));
    234 }
    235 
    236 void MacroAssembler::xor32(Imm32 imm, const Address& dest) {
    237  vixl::UseScratchRegisterScope temps(this);
    238  const ARMRegister scratch32 = temps.AcquireW();
    239  MOZ_ASSERT(scratch32.asUnsized() != dest.base);
    240  load32(dest, scratch32.asUnsized());
    241  Eor(scratch32, scratch32, Operand(imm.value));
    242  store32(scratch32.asUnsized(), dest);
    243 }
    244 
    245 void MacroAssembler::xor32(const Address& src, Register dest) {
    246  vixl::UseScratchRegisterScope temps(this);
    247  const ARMRegister scratch32 = temps.AcquireW();
    248  MOZ_ASSERT(scratch32.asUnsized() != src.base);
    249  load32(src, scratch32.asUnsized());
    250  Eor(ARMRegister(dest, 32), ARMRegister(dest, 32), Operand(scratch32));
    251 }
    252 
    253 void MacroAssembler::xorPtr(Register src, Register dest) {
    254  Eor(ARMRegister(dest, 64), ARMRegister(dest, 64),
    255      Operand(ARMRegister(src, 64)));
    256 }
    257 
    258 void MacroAssembler::xorPtr(Imm32 imm, Register dest) {
    259  xorPtr(imm, dest, dest);
    260 }
    261 
    262 void MacroAssembler::xorPtr(Imm32 imm, Register src, Register dest) {
    263  Eor(ARMRegister(dest, 64), ARMRegister(src, 64), Operand(imm.value));
    264 }
    265 
    266 void MacroAssembler::xor64(Imm64 imm, Register64 dest) {
    267  Eor(ARMRegister(dest.reg, 64), ARMRegister(dest.reg, 64), Operand(imm.value));
    268 }
    269 
    270 // ===============================================================
    271 // Swap instructions
    272 
    273 void MacroAssembler::byteSwap16SignExtend(Register reg) {
    274  rev16(ARMRegister(reg, 32), ARMRegister(reg, 32));
    275  sxth(ARMRegister(reg, 32), ARMRegister(reg, 32));
    276 }
    277 
    278 void MacroAssembler::byteSwap16ZeroExtend(Register reg) {
    279  rev16(ARMRegister(reg, 32), ARMRegister(reg, 32));
    280  uxth(ARMRegister(reg, 32), ARMRegister(reg, 32));
    281 }
    282 
    283 void MacroAssembler::byteSwap32(Register reg) {
    284  rev(ARMRegister(reg, 32), ARMRegister(reg, 32));
    285 }
    286 
    287 void MacroAssembler::byteSwap64(Register64 reg) {
    288  rev(ARMRegister(reg.reg, 64), ARMRegister(reg.reg, 64));
    289 }
    290 
    291 // ===============================================================
    292 // Arithmetic functions
    293 
    294 void MacroAssembler::add32(Register src, Register dest) {
    295  Add(ARMRegister(dest, 32), ARMRegister(dest, 32),
    296      Operand(ARMRegister(src, 32)));
    297 }
    298 
    299 void MacroAssembler::add32(Imm32 imm, Register dest) {
    300  Add(ARMRegister(dest, 32), ARMRegister(dest, 32), Operand(imm.value));
    301 }
    302 
    303 void MacroAssembler::add32(Imm32 imm, Register src, Register dest) {
    304  Add(ARMRegister(dest, 32), ARMRegister(src, 32), Operand(imm.value));
    305 }
    306 
    307 void MacroAssembler::add32(Imm32 imm, const Address& dest) {
    308  vixl::UseScratchRegisterScope temps(this);
    309  const ARMRegister scratch32 = temps.AcquireW();
    310  MOZ_ASSERT(scratch32.asUnsized() != dest.base);
    311 
    312  Ldr(scratch32, toMemOperand(dest));
    313  Add(scratch32, scratch32, Operand(imm.value));
    314  Str(scratch32, toMemOperand(dest));
    315 }
    316 
    317 void MacroAssembler::add32(const Address& src, Register dest) {
    318  vixl::UseScratchRegisterScope temps(this);
    319  const ARMRegister scratch32 = temps.AcquireW();
    320  MOZ_ASSERT(scratch32.asUnsized() != src.base);
    321  load32(src, scratch32.asUnsized());
    322  Add(ARMRegister(dest, 32), ARMRegister(dest, 32), Operand(scratch32));
    323 }
    324 
    325 void MacroAssembler::addPtr(Register src, Register dest) {
    326  addPtr(src, dest, dest);
    327 }
    328 
    329 void MacroAssembler::addPtr(Register src1, Register src2, Register dest) {
    330  Add(ARMRegister(dest, 64), ARMRegister(src1, 64),
    331      Operand(ARMRegister(src2, 64)));
    332 }
    333 
    334 void MacroAssembler::addPtr(Imm32 imm, Register dest) {
    335  addPtr(imm, dest, dest);
    336 }
    337 
    338 void MacroAssembler::addPtr(Imm32 imm, Register src, Register dest) {
    339  Add(ARMRegister(dest, 64), ARMRegister(src, 64), Operand(imm.value));
    340 }
    341 
    342 void MacroAssembler::addPtr(ImmWord imm, Register dest) {
    343  Add(ARMRegister(dest, 64), ARMRegister(dest, 64), Operand(imm.value));
    344 }
    345 
    346 void MacroAssembler::addPtr(Imm32 imm, const Address& dest) {
    347  vixl::UseScratchRegisterScope temps(this);
    348  const ARMRegister scratch64 = temps.AcquireX();
    349  MOZ_ASSERT(scratch64.asUnsized() != dest.base);
    350 
    351  Ldr(scratch64, toMemOperand(dest));
    352  Add(scratch64, scratch64, Operand(imm.value));
    353  Str(scratch64, toMemOperand(dest));
    354 }
    355 
    356 void MacroAssembler::addPtr(const Address& src, Register dest) {
    357  vixl::UseScratchRegisterScope temps(this);
    358  const ARMRegister scratch64 = temps.AcquireX();
    359  MOZ_ASSERT(scratch64.asUnsized() != src.base);
    360 
    361  Ldr(scratch64, toMemOperand(src));
    362  Add(ARMRegister(dest, 64), ARMRegister(dest, 64), Operand(scratch64));
    363 }
    364 
    365 void MacroAssembler::add64(Register64 src, Register64 dest) {
    366  addPtr(src.reg, dest.reg);
    367 }
    368 
    369 void MacroAssembler::add64(Imm32 imm, Register64 dest) {
    370  Add(ARMRegister(dest.reg, 64), ARMRegister(dest.reg, 64), Operand(imm.value));
    371 }
    372 
    373 void MacroAssembler::add64(Imm64 imm, Register64 dest) {
    374  Add(ARMRegister(dest.reg, 64), ARMRegister(dest.reg, 64), Operand(imm.value));
    375 }
    376 
    377 CodeOffset MacroAssembler::sub32FromStackPtrWithPatch(Register dest) {
    378  vixl::UseScratchRegisterScope temps(this);
    379  const ARMRegister scratch = temps.AcquireX();
    380  AutoForbidPoolsAndNops afp(this,
    381                             /* max number of instructions in scope = */ 3);
    382  CodeOffset offs = CodeOffset(currentOffset());
    383  movz(scratch, 0, 0);
    384  movk(scratch, 0, 16);
    385  Sub(ARMRegister(dest, 64), sp, scratch);
    386  return offs;
    387 }
    388 
    389 void MacroAssembler::patchSub32FromStackPtr(CodeOffset offset, Imm32 imm) {
    390  Instruction* i1 = getInstructionAt(BufferOffset(offset.offset()));
    391  MOZ_ASSERT(i1->IsMovz());
    392  i1->SetInstructionBits(i1->InstructionBits() |
    393                         ImmMoveWide(uint16_t(imm.value)));
    394 
    395  Instruction* i2 = getInstructionAt(BufferOffset(offset.offset() + 4));
    396  MOZ_ASSERT(i2->IsMovk());
    397  i2->SetInstructionBits(i2->InstructionBits() |
    398                         ImmMoveWide(uint16_t(imm.value >> 16)));
    399 }
    400 
    401 void MacroAssembler::addDouble(FloatRegister src, FloatRegister dest) {
    402  fadd(ARMFPRegister(dest, 64), ARMFPRegister(dest, 64),
    403       ARMFPRegister(src, 64));
    404 }
    405 
    406 void MacroAssembler::addFloat32(FloatRegister src, FloatRegister dest) {
    407  fadd(ARMFPRegister(dest, 32), ARMFPRegister(dest, 32),
    408       ARMFPRegister(src, 32));
    409 }
    410 
    411 void MacroAssembler::sub32(Imm32 imm, Register dest) {
    412  Sub(ARMRegister(dest, 32), ARMRegister(dest, 32), Operand(imm.value));
    413 }
    414 
    415 void MacroAssembler::sub32(Register src, Register dest) {
    416  Sub(ARMRegister(dest, 32), ARMRegister(dest, 32),
    417      Operand(ARMRegister(src, 32)));
    418 }
    419 
    420 void MacroAssembler::sub32(const Address& src, Register dest) {
    421  vixl::UseScratchRegisterScope temps(this);
    422  const ARMRegister scratch32 = temps.AcquireW();
    423  MOZ_ASSERT(scratch32.asUnsized() != src.base);
    424  load32(src, scratch32.asUnsized());
    425  Sub(ARMRegister(dest, 32), ARMRegister(dest, 32), Operand(scratch32));
    426 }
    427 
    428 void MacroAssembler::subPtr(Register src, Register dest) {
    429  Sub(ARMRegister(dest, 64), ARMRegister(dest, 64),
    430      Operand(ARMRegister(src, 64)));
    431 }
    432 
    433 void MacroAssembler::subPtr(Register src, const Address& dest) {
    434  vixl::UseScratchRegisterScope temps(this);
    435  const ARMRegister scratch64 = temps.AcquireX();
    436  MOZ_ASSERT(scratch64.asUnsized() != dest.base);
    437 
    438  Ldr(scratch64, toMemOperand(dest));
    439  Sub(scratch64, scratch64, Operand(ARMRegister(src, 64)));
    440  Str(scratch64, toMemOperand(dest));
    441 }
    442 
    443 void MacroAssembler::subPtr(Imm32 imm, Register dest) {
    444  Sub(ARMRegister(dest, 64), ARMRegister(dest, 64), Operand(imm.value));
    445 }
    446 
    447 void MacroAssembler::subPtr(const Address& addr, Register dest) {
    448  vixl::UseScratchRegisterScope temps(this);
    449  const ARMRegister scratch64 = temps.AcquireX();
    450  MOZ_ASSERT(scratch64.asUnsized() != addr.base);
    451 
    452  Ldr(scratch64, toMemOperand(addr));
    453  Sub(ARMRegister(dest, 64), ARMRegister(dest, 64), Operand(scratch64));
    454 }
    455 
    456 void MacroAssembler::sub64(Register64 src, Register64 dest) {
    457  Sub(ARMRegister(dest.reg, 64), ARMRegister(dest.reg, 64),
    458      ARMRegister(src.reg, 64));
    459 }
    460 
    461 void MacroAssembler::sub64(Imm64 imm, Register64 dest) {
    462  Sub(ARMRegister(dest.reg, 64), ARMRegister(dest.reg, 64), Operand(imm.value));
    463 }
    464 
    465 void MacroAssembler::subDouble(FloatRegister src, FloatRegister dest) {
    466  fsub(ARMFPRegister(dest, 64), ARMFPRegister(dest, 64),
    467       ARMFPRegister(src, 64));
    468 }
    469 
    470 void MacroAssembler::subFloat32(FloatRegister src, FloatRegister dest) {
    471  fsub(ARMFPRegister(dest, 32), ARMFPRegister(dest, 32),
    472       ARMFPRegister(src, 32));
    473 }
    474 
    475 void MacroAssembler::mul32(Register rhs, Register srcDest) {
    476  mul32(srcDest, rhs, srcDest, nullptr);
    477 }
    478 
    479 void MacroAssembler::mul32(Imm32 imm, Register srcDest) {
    480  vixl::UseScratchRegisterScope temps(this);
    481  const ARMRegister scratch32 = temps.AcquireW();
    482 
    483  move32(imm, scratch32.asUnsized());
    484  mul32(scratch32.asUnsized(), srcDest);
    485 }
    486 
    487 void MacroAssembler::mul32(Register src1, Register src2, Register dest,
    488                           Label* onOver) {
    489  if (onOver) {
    490    Smull(ARMRegister(dest, 64), ARMRegister(src1, 32), ARMRegister(src2, 32));
    491    Cmp(ARMRegister(dest, 64), Operand(ARMRegister(dest, 32), vixl::SXTW));
    492    B(onOver, NotEqual);
    493 
    494    // Clear upper 32 bits.
    495    Uxtw(ARMRegister(dest, 64), ARMRegister(dest, 64));
    496  } else {
    497    Mul(ARMRegister(dest, 32), ARMRegister(src1, 32), ARMRegister(src2, 32));
    498  }
    499 }
    500 
    501 void MacroAssembler::mulHighUnsigned32(Imm32 imm, Register src, Register dest) {
    502  vixl::UseScratchRegisterScope temps(this);
    503  const ARMRegister scratch32 = temps.AcquireW();
    504 
    505  Mov(scratch32, int32_t(imm.value));
    506  Umull(ARMRegister(dest, 64), scratch32, ARMRegister(src, 32));
    507 
    508  Lsr(ARMRegister(dest, 64), ARMRegister(dest, 64), 32);
    509 }
    510 
    511 void MacroAssembler::mulPtr(Register rhs, Register srcDest) {
    512  Mul(ARMRegister(srcDest, 64), ARMRegister(srcDest, 64), ARMRegister(rhs, 64));
    513 }
    514 
    515 void MacroAssembler::mulPtr(ImmWord rhs, Register srcDest) {
    516  vixl::UseScratchRegisterScope temps(this);
    517  const ARMRegister scratch64 = temps.AcquireX();
    518  MOZ_ASSERT(srcDest != scratch64.asUnsized());
    519  mov(rhs, scratch64.asUnsized());
    520  mulPtr(scratch64.asUnsized(), srcDest);
    521 }
    522 
    523 void MacroAssembler::mul64(Imm64 imm, const Register64& dest) {
    524  vixl::UseScratchRegisterScope temps(this);
    525  const ARMRegister scratch64 = temps.AcquireX();
    526  MOZ_ASSERT(dest.reg != scratch64.asUnsized());
    527  mov(ImmWord(imm.value), scratch64.asUnsized());
    528  Mul(ARMRegister(dest.reg, 64), ARMRegister(dest.reg, 64), scratch64);
    529 }
    530 
    531 void MacroAssembler::mul64(const Register64& src, const Register64& dest,
    532                           const Register temp) {
    533  MOZ_ASSERT(temp == Register::Invalid());
    534  Mul(ARMRegister(dest.reg, 64), ARMRegister(dest.reg, 64),
    535      ARMRegister(src.reg, 64));
    536 }
    537 
    538 void MacroAssembler::mul64(const Register64& src1, const Register64& src2,
    539                           const Register64& dest) {
    540  Mul(ARMRegister(dest.reg, 64), ARMRegister(src1.reg, 64),
    541      ARMRegister(src2.reg, 64));
    542 }
    543 
    544 void MacroAssembler::mul64(Imm64 src1, const Register64& src2,
    545                           const Register64& dest) {
    546  vixl::UseScratchRegisterScope temps(this);
    547  const ARMRegister scratch64 = temps.AcquireX();
    548  MOZ_ASSERT(dest.reg != scratch64.asUnsized());
    549  mov(ImmWord(src1.value), scratch64.asUnsized());
    550  Mul(ARMRegister(dest.reg, 64), ARMRegister(src2.reg, 64), scratch64);
    551 }
    552 
    553 void MacroAssembler::mulBy3(Register src, Register dest) {
    554  ARMRegister xdest(dest, 64);
    555  ARMRegister xsrc(src, 64);
    556  Add(xdest, xsrc, Operand(xsrc, vixl::LSL, 1));
    557 }
    558 
    559 void MacroAssembler::mulFloat32(FloatRegister src, FloatRegister dest) {
    560  fmul(ARMFPRegister(dest, 32), ARMFPRegister(dest, 32),
    561       ARMFPRegister(src, 32));
    562 }
    563 
    564 void MacroAssembler::mulDouble(FloatRegister src, FloatRegister dest) {
    565  fmul(ARMFPRegister(dest, 64), ARMFPRegister(dest, 64),
    566       ARMFPRegister(src, 64));
    567 }
    568 
    569 void MacroAssembler::mulDoublePtr(ImmPtr imm, Register temp,
    570                                  FloatRegister dest) {
    571  vixl::UseScratchRegisterScope temps(this);
    572  const Register scratch = temps.AcquireX().asUnsized();
    573  MOZ_ASSERT(temp != scratch);
    574  movePtr(imm, scratch);
    575  const ARMFPRegister scratchDouble = temps.AcquireD();
    576  Ldr(scratchDouble, MemOperand(Address(scratch, 0)));
    577  fmul(ARMFPRegister(dest, 64), ARMFPRegister(dest, 64), scratchDouble);
    578 }
    579 
    580 void MacroAssembler::quotient32(Register lhs, Register rhs, Register dest,
    581                                bool isUnsigned) {
    582  if (isUnsigned) {
    583    Udiv(ARMRegister(dest, 32), ARMRegister(lhs, 32), ARMRegister(rhs, 32));
    584  } else {
    585    Sdiv(ARMRegister(dest, 32), ARMRegister(lhs, 32), ARMRegister(rhs, 32));
    586  }
    587 }
    588 
    589 void MacroAssembler::quotient64(Register lhs, Register rhs, Register dest,
    590                                bool isUnsigned) {
    591  if (isUnsigned) {
    592    Udiv(ARMRegister(dest, 64), ARMRegister(lhs, 64), ARMRegister(rhs, 64));
    593  } else {
    594    Sdiv(ARMRegister(dest, 64), ARMRegister(lhs, 64), ARMRegister(rhs, 64));
    595  }
    596 }
    597 
    598 // This does not deal with x % 0 or INT_MIN % -1, the caller needs to filter
    599 // those cases when they may occur.
    600 
    601 void MacroAssembler::remainder32(Register lhs, Register rhs, Register dest,
    602                                 bool isUnsigned) {
    603  vixl::UseScratchRegisterScope temps(this);
    604  ARMRegister scratch = temps.AcquireW();
    605  if (isUnsigned) {
    606    Udiv(scratch, ARMRegister(lhs, 32), ARMRegister(rhs, 32));
    607  } else {
    608    Sdiv(scratch, ARMRegister(lhs, 32), ARMRegister(rhs, 32));
    609  }
    610 
    611  // Compute the remainder: dest = lhs - (scratch * rhs).
    612  Msub(/* result= */ ARMRegister(dest, 32), scratch, ARMRegister(rhs, 32),
    613       ARMRegister(lhs, 32));
    614 }
    615 
    616 void MacroAssembler::remainder64(Register lhs, Register rhs, Register dest,
    617                                 bool isUnsigned) {
    618  vixl::UseScratchRegisterScope temps(this);
    619  ARMRegister scratch64 = temps.AcquireX();
    620  if (isUnsigned) {
    621    Udiv(scratch64, ARMRegister(lhs, 64), ARMRegister(rhs, 64));
    622  } else {
    623    Sdiv(scratch64, ARMRegister(lhs, 64), ARMRegister(rhs, 64));
    624  }
    625 
    626  // Compute the remainder: dest = lhs - (scratch64 * rhs).
    627  Msub(/* result= */ ARMRegister(dest, 64), scratch64, ARMRegister(rhs, 64),
    628       ARMRegister(lhs, 64));
    629 }
    630 
    631 void MacroAssembler::divFloat32(FloatRegister src, FloatRegister dest) {
    632  fdiv(ARMFPRegister(dest, 32), ARMFPRegister(dest, 32),
    633       ARMFPRegister(src, 32));
    634 }
    635 
    636 void MacroAssembler::divDouble(FloatRegister src, FloatRegister dest) {
    637  fdiv(ARMFPRegister(dest, 64), ARMFPRegister(dest, 64),
    638       ARMFPRegister(src, 64));
    639 }
    640 
    641 void MacroAssembler::inc64(AbsoluteAddress dest) {
    642  vixl::UseScratchRegisterScope temps(this);
    643  const ARMRegister scratchAddr64 = temps.AcquireX();
    644  const ARMRegister scratch64 = temps.AcquireX();
    645 
    646  Mov(scratchAddr64, uint64_t(dest.addr));
    647  Ldr(scratch64, MemOperand(scratchAddr64, 0));
    648  Add(scratch64, scratch64, Operand(1));
    649  Str(scratch64, MemOperand(scratchAddr64, 0));
    650 }
    651 
    652 void MacroAssembler::neg32(Register reg) {
    653  Neg(ARMRegister(reg, 32), Operand(ARMRegister(reg, 32)));
    654 }
    655 
    656 void MacroAssembler::neg64(Register64 reg) { negPtr(reg.reg); }
    657 
    658 void MacroAssembler::negPtr(Register reg) {
    659  Neg(ARMRegister(reg, 64), Operand(ARMRegister(reg, 64)));
    660 }
    661 
    662 void MacroAssembler::negateFloat(FloatRegister reg) {
    663  fneg(ARMFPRegister(reg, 32), ARMFPRegister(reg, 32));
    664 }
    665 
    666 void MacroAssembler::negateDouble(FloatRegister reg) {
    667  fneg(ARMFPRegister(reg, 64), ARMFPRegister(reg, 64));
    668 }
    669 
    670 void MacroAssembler::abs32(Register src, Register dest) {
    671  if (CPUHas(vixl::CPUFeatures::kCSSC)) {
    672    Abs(ARMRegister(dest, 32), ARMRegister(src, 32));
    673    return;
    674  }
    675  Cmp(ARMRegister(src, 32), wzr);
    676  Cneg(ARMRegister(dest, 32), ARMRegister(src, 32), Assembler::LessThan);
    677 }
    678 
    679 void MacroAssembler::absFloat32(FloatRegister src, FloatRegister dest) {
    680  fabs(ARMFPRegister(dest, 32), ARMFPRegister(src, 32));
    681 }
    682 
    683 void MacroAssembler::absDouble(FloatRegister src, FloatRegister dest) {
    684  fabs(ARMFPRegister(dest, 64), ARMFPRegister(src, 64));
    685 }
    686 
    687 void MacroAssembler::sqrtFloat32(FloatRegister src, FloatRegister dest) {
    688  fsqrt(ARMFPRegister(dest, 32), ARMFPRegister(src, 32));
    689 }
    690 
    691 void MacroAssembler::sqrtDouble(FloatRegister src, FloatRegister dest) {
    692  fsqrt(ARMFPRegister(dest, 64), ARMFPRegister(src, 64));
    693 }
    694 
    695 void MacroAssembler::min32(Register lhs, Register rhs, Register dest) {
    696  minMax32(lhs, rhs, dest, /* isMax = */ false);
    697 }
    698 
    699 void MacroAssembler::min32(Register lhs, Imm32 rhs, Register dest) {
    700  minMax32(lhs, rhs, dest, /* isMax = */ false);
    701 }
    702 
    703 void MacroAssembler::max32(Register lhs, Register rhs, Register dest) {
    704  minMax32(lhs, rhs, dest, /* isMax = */ true);
    705 }
    706 
    707 void MacroAssembler::max32(Register lhs, Imm32 rhs, Register dest) {
    708  minMax32(lhs, rhs, dest, /* isMax = */ true);
    709 }
    710 
    711 void MacroAssembler::minPtr(Register lhs, Register rhs, Register dest) {
    712  minMaxPtr(lhs, rhs, dest, /* isMax = */ false);
    713 }
    714 
    715 void MacroAssembler::minPtr(Register lhs, ImmWord rhs, Register dest) {
    716  minMaxPtr(lhs, rhs, dest, /* isMax = */ false);
    717 }
    718 
    719 void MacroAssembler::maxPtr(Register lhs, Register rhs, Register dest) {
    720  minMaxPtr(lhs, rhs, dest, /* isMax = */ true);
    721 }
    722 
    723 void MacroAssembler::maxPtr(Register lhs, ImmWord rhs, Register dest) {
    724  minMaxPtr(lhs, rhs, dest, /* isMax = */ true);
    725 }
    726 
    727 void MacroAssembler::minFloat32(FloatRegister other, FloatRegister srcDest,
    728                                bool handleNaN) {
    729  MOZ_ASSERT(handleNaN);  // Always true for wasm
    730  fmin(ARMFPRegister(srcDest, 32), ARMFPRegister(srcDest, 32),
    731       ARMFPRegister(other, 32));
    732 }
    733 
    734 void MacroAssembler::minDouble(FloatRegister other, FloatRegister srcDest,
    735                               bool handleNaN) {
    736  MOZ_ASSERT(handleNaN);  // Always true for wasm
    737  fmin(ARMFPRegister(srcDest, 64), ARMFPRegister(srcDest, 64),
    738       ARMFPRegister(other, 64));
    739 }
    740 
    741 void MacroAssembler::maxFloat32(FloatRegister other, FloatRegister srcDest,
    742                                bool handleNaN) {
    743  MOZ_ASSERT(handleNaN);  // Always true for wasm
    744  fmax(ARMFPRegister(srcDest, 32), ARMFPRegister(srcDest, 32),
    745       ARMFPRegister(other, 32));
    746 }
    747 
    748 void MacroAssembler::maxDouble(FloatRegister other, FloatRegister srcDest,
    749                               bool handleNaN) {
    750  MOZ_ASSERT(handleNaN);  // Always true for wasm
    751  fmax(ARMFPRegister(srcDest, 64), ARMFPRegister(srcDest, 64),
    752       ARMFPRegister(other, 64));
    753 }
    754 
    755 // ===============================================================
    756 // Shift functions
    757 
    758 void MacroAssembler::lshiftPtr(Imm32 imm, Register dest) {
    759  lshiftPtr(imm, dest, dest);
    760 }
    761 
    762 void MacroAssembler::lshiftPtr(Imm32 imm, Register src, Register dest) {
    763  MOZ_ASSERT(0 <= imm.value && imm.value < 64);
    764  Lsl(ARMRegister(dest, 64), ARMRegister(src, 64), imm.value);
    765 }
    766 
    767 void MacroAssembler::lshiftPtr(Register shift, Register dest) {
    768  Lsl(ARMRegister(dest, 64), ARMRegister(dest, 64), ARMRegister(shift, 64));
    769 }
    770 
    771 void MacroAssembler::flexibleLshiftPtr(Register shift, Register srcDest) {
    772  lshiftPtr(shift, srcDest);
    773 }
    774 
    775 void MacroAssembler::lshift64(Imm32 imm, Register64 dest) {
    776  MOZ_ASSERT(0 <= imm.value && imm.value < 64);
    777  lshiftPtr(imm, dest.reg);
    778 }
    779 
    780 void MacroAssembler::lshift64(Register shift, Register64 srcDest) {
    781  Lsl(ARMRegister(srcDest.reg, 64), ARMRegister(srcDest.reg, 64),
    782      ARMRegister(shift, 64));
    783 }
    784 
    785 void MacroAssembler::lshift32(Register shift, Register dest) {
    786  Lsl(ARMRegister(dest, 32), ARMRegister(dest, 32), ARMRegister(shift, 32));
    787 }
    788 
    789 void MacroAssembler::flexibleLshift32(Register src, Register dest) {
    790  lshift32(src, dest);
    791 }
    792 
    793 void MacroAssembler::lshift32(Imm32 imm, Register dest) {
    794  lshift32(imm, dest, dest);
    795 }
    796 
    797 void MacroAssembler::lshift32(Imm32 imm, Register src, Register dest) {
    798  MOZ_ASSERT(0 <= imm.value && imm.value < 32);
    799  Lsl(ARMRegister(dest, 32), ARMRegister(src, 32), imm.value);
    800 }
    801 
    802 void MacroAssembler::rshiftPtr(Imm32 imm, Register dest) {
    803  rshiftPtr(imm, dest, dest);
    804 }
    805 
    806 void MacroAssembler::rshiftPtr(Imm32 imm, Register src, Register dest) {
    807  MOZ_ASSERT(0 <= imm.value && imm.value < 64);
    808  Lsr(ARMRegister(dest, 64), ARMRegister(src, 64), imm.value);
    809 }
    810 
    811 void MacroAssembler::rshiftPtr(Register shift, Register dest) {
    812  Lsr(ARMRegister(dest, 64), ARMRegister(dest, 64), ARMRegister(shift, 64));
    813 }
    814 
    815 void MacroAssembler::flexibleRshiftPtr(Register shift, Register srcDest) {
    816  rshiftPtr(shift, srcDest);
    817 }
    818 
    819 void MacroAssembler::rshift32(Register shift, Register dest) {
    820  Lsr(ARMRegister(dest, 32), ARMRegister(dest, 32), ARMRegister(shift, 32));
    821 }
    822 
    823 void MacroAssembler::flexibleRshift32(Register src, Register dest) {
    824  rshift32(src, dest);
    825 }
    826 
    827 void MacroAssembler::rshift32(Imm32 imm, Register dest) {
    828  rshift32(imm, dest, dest);
    829 }
    830 
    831 void MacroAssembler::rshift32(Imm32 imm, Register src, Register dest) {
    832  MOZ_ASSERT(0 <= imm.value && imm.value < 32);
    833  Lsr(ARMRegister(dest, 32), ARMRegister(src, 32), imm.value);
    834 }
    835 
    836 void MacroAssembler::rshiftPtrArithmetic(Imm32 imm, Register dest) {
    837  rshiftPtrArithmetic(imm, dest, dest);
    838 }
    839 
    840 void MacroAssembler::rshiftPtrArithmetic(Imm32 imm, Register src,
    841                                         Register dest) {
    842  MOZ_ASSERT(0 <= imm.value && imm.value < 64);
    843  Asr(ARMRegister(dest, 64), ARMRegister(src, 64), imm.value);
    844 }
    845 
    846 void MacroAssembler::rshiftPtrArithmetic(Register shift, Register dest) {
    847  Asr(ARMRegister(dest, 64), ARMRegister(dest, 64), ARMRegister(shift, 64));
    848 }
    849 
    850 void MacroAssembler::flexibleRshiftPtrArithmetic(Register shift,
    851                                                 Register srcDest) {
    852  rshiftPtrArithmetic(shift, srcDest);
    853 }
    854 
    855 void MacroAssembler::rshift32Arithmetic(Register shift, Register dest) {
    856  Asr(ARMRegister(dest, 32), ARMRegister(dest, 32), ARMRegister(shift, 32));
    857 }
    858 
    859 void MacroAssembler::rshift32Arithmetic(Imm32 imm, Register dest) {
    860  rshift32Arithmetic(imm, dest, dest);
    861 }
    862 
    863 void MacroAssembler::rshift32Arithmetic(Imm32 imm, Register src,
    864                                        Register dest) {
    865  MOZ_ASSERT(0 <= imm.value && imm.value < 32);
    866  Asr(ARMRegister(dest, 32), ARMRegister(src, 32), imm.value);
    867 }
    868 
    869 void MacroAssembler::flexibleRshift32Arithmetic(Register src, Register dest) {
    870  rshift32Arithmetic(src, dest);
    871 }
    872 
    873 void MacroAssembler::rshift64(Imm32 imm, Register64 dest) {
    874  MOZ_ASSERT(0 <= imm.value && imm.value < 64);
    875  rshiftPtr(imm, dest.reg);
    876 }
    877 
    878 void MacroAssembler::rshift64(Register shift, Register64 srcDest) {
    879  Lsr(ARMRegister(srcDest.reg, 64), ARMRegister(srcDest.reg, 64),
    880      ARMRegister(shift, 64));
    881 }
    882 
    883 void MacroAssembler::rshift64Arithmetic(Imm32 imm, Register64 dest) {
    884  Asr(ARMRegister(dest.reg, 64), ARMRegister(dest.reg, 64), imm.value);
    885 }
    886 
    887 void MacroAssembler::rshift64Arithmetic(Register shift, Register64 srcDest) {
    888  Asr(ARMRegister(srcDest.reg, 64), ARMRegister(srcDest.reg, 64),
    889      ARMRegister(shift, 64));
    890 }
    891 
    892 // ===============================================================
    893 // Condition functions
    894 
    895 void MacroAssembler::cmp8Set(Condition cond, Address lhs, Imm32 rhs,
    896                             Register dest) {
    897  vixl::UseScratchRegisterScope temps(this);
    898  Register scratch = temps.AcquireX().asUnsized();
    899  MOZ_ASSERT(scratch != lhs.base);
    900 
    901  switch (cond) {
    902    case Assembler::Equal:
    903    case Assembler::NotEqual:
    904    case Assembler::Above:
    905    case Assembler::AboveOrEqual:
    906    case Assembler::Below:
    907    case Assembler::BelowOrEqual:
    908      load8ZeroExtend(lhs, scratch);
    909      cmp32Set(cond, scratch, Imm32(uint8_t(rhs.value)), dest);
    910      break;
    911 
    912    case Assembler::GreaterThan:
    913    case Assembler::GreaterThanOrEqual:
    914    case Assembler::LessThan:
    915    case Assembler::LessThanOrEqual:
    916      load8SignExtend(lhs, scratch);
    917      cmp32Set(cond, scratch, Imm32(int8_t(rhs.value)), dest);
    918      break;
    919 
    920    default:
    921      MOZ_CRASH("unexpected condition");
    922  }
    923 }
    924 
    925 void MacroAssembler::cmp16Set(Condition cond, Address lhs, Imm32 rhs,
    926                              Register dest) {
    927  vixl::UseScratchRegisterScope temps(this);
    928  Register scratch = temps.AcquireX().asUnsized();
    929  MOZ_ASSERT(scratch != lhs.base);
    930 
    931  switch (cond) {
    932    case Assembler::Equal:
    933    case Assembler::NotEqual:
    934    case Assembler::Above:
    935    case Assembler::AboveOrEqual:
    936    case Assembler::Below:
    937    case Assembler::BelowOrEqual:
    938      load16ZeroExtend(lhs, scratch);
    939      cmp32Set(cond, scratch, Imm32(uint16_t(rhs.value)), dest);
    940      break;
    941 
    942    case Assembler::GreaterThan:
    943    case Assembler::GreaterThanOrEqual:
    944    case Assembler::LessThan:
    945    case Assembler::LessThanOrEqual:
    946      load16SignExtend(lhs, scratch);
    947      cmp32Set(cond, scratch, Imm32(int16_t(rhs.value)), dest);
    948      break;
    949 
    950    default:
    951      MOZ_CRASH("unexpected condition");
    952  }
    953 }
    954 
    955 template <typename T1, typename T2>
    956 void MacroAssembler::cmp32Set(Condition cond, T1 lhs, T2 rhs, Register dest) {
    957  cmp32(lhs, rhs);
    958  emitSet(cond, dest);
    959 }
    960 
    961 void MacroAssembler::cmp64Set(Condition cond, Register64 lhs, Register64 rhs,
    962                              Register dest) {
    963  cmpPtrSet(cond, lhs.reg, rhs.reg, dest);
    964 }
    965 
    966 void MacroAssembler::cmp64Set(Condition cond, Register64 lhs, Imm64 rhs,
    967                              Register dest) {
    968  cmpPtrSet(cond, lhs.reg, ImmWord(static_cast<uintptr_t>(rhs.value)), dest);
    969 }
    970 
    971 void MacroAssembler::cmp64Set(Condition cond, Address lhs, Register64 rhs,
    972                              Register dest) {
    973  cmpPtrSet(cond, lhs, rhs.reg, dest);
    974 }
    975 
    976 void MacroAssembler::cmp64Set(Condition cond, Address lhs, Imm64 rhs,
    977                              Register dest) {
    978  cmpPtrSet(cond, lhs, ImmWord(static_cast<uintptr_t>(rhs.value)), dest);
    979 }
    980 
    981 template <typename T1, typename T2>
    982 void MacroAssembler::cmpPtrSet(Condition cond, T1 lhs, T2 rhs, Register dest) {
    983  cmpPtr(lhs, rhs);
    984  emitSet(cond, dest);
    985 }
    986 
    987 // ===============================================================
    988 // Rotation functions
    989 
    990 void MacroAssembler::rotateLeft(Imm32 count, Register input, Register dest) {
    991  Ror(ARMRegister(dest, 32), ARMRegister(input, 32), (32 - count.value) & 31);
    992 }
    993 
    994 void MacroAssembler::rotateLeft(Register count, Register input, Register dest) {
    995  vixl::UseScratchRegisterScope temps(this);
    996  const ARMRegister scratch = temps.AcquireW();
    997  // Really 32 - count, but the upper bits of the result are ignored.
    998  Neg(scratch, ARMRegister(count, 32));
    999  Ror(ARMRegister(dest, 32), ARMRegister(input, 32), scratch);
   1000 }
   1001 
   1002 void MacroAssembler::rotateRight(Imm32 count, Register input, Register dest) {
   1003  Ror(ARMRegister(dest, 32), ARMRegister(input, 32), count.value & 31);
   1004 }
   1005 
   1006 void MacroAssembler::rotateRight(Register count, Register input,
   1007                                 Register dest) {
   1008  Ror(ARMRegister(dest, 32), ARMRegister(input, 32), ARMRegister(count, 32));
   1009 }
   1010 
   1011 void MacroAssembler::rotateLeft64(Register count, Register64 input,
   1012                                  Register64 dest, Register temp) {
   1013  MOZ_ASSERT(temp == Register::Invalid());
   1014 
   1015  vixl::UseScratchRegisterScope temps(this);
   1016  const ARMRegister scratch = temps.AcquireX();
   1017  // Really 64 - count, but the upper bits of the result are ignored.
   1018  Neg(scratch, ARMRegister(count, 64));
   1019  Ror(ARMRegister(dest.reg, 64), ARMRegister(input.reg, 64), scratch);
   1020 }
   1021 
   1022 void MacroAssembler::rotateLeft64(Imm32 count, Register64 input,
   1023                                  Register64 dest, Register temp) {
   1024  MOZ_ASSERT(temp == Register::Invalid());
   1025 
   1026  Ror(ARMRegister(dest.reg, 64), ARMRegister(input.reg, 64),
   1027      (64 - count.value) & 63);
   1028 }
   1029 
   1030 void MacroAssembler::rotateRight64(Register count, Register64 input,
   1031                                   Register64 dest, Register temp) {
   1032  MOZ_ASSERT(temp == Register::Invalid());
   1033 
   1034  Ror(ARMRegister(dest.reg, 64), ARMRegister(input.reg, 64),
   1035      ARMRegister(count, 64));
   1036 }
   1037 
   1038 void MacroAssembler::rotateRight64(Imm32 count, Register64 input,
   1039                                   Register64 dest, Register temp) {
   1040  MOZ_ASSERT(temp == Register::Invalid());
   1041 
   1042  Ror(ARMRegister(dest.reg, 64), ARMRegister(input.reg, 64), count.value & 63);
   1043 }
   1044 
   1045 // ===============================================================
   1046 // Bit counting functions
   1047 
   1048 void MacroAssembler::clz32(Register src, Register dest, bool knownNotZero) {
   1049  Clz(ARMRegister(dest, 32), ARMRegister(src, 32));
   1050 }
   1051 
   1052 void MacroAssembler::ctz32(Register src, Register dest, bool knownNotZero) {
   1053  if (CPUHas(vixl::CPUFeatures::kCSSC)) {
   1054    Ctz(ARMRegister(dest, 32), ARMRegister(src, 32));
   1055    return;
   1056  }
   1057  Rbit(ARMRegister(dest, 32), ARMRegister(src, 32));
   1058  Clz(ARMRegister(dest, 32), ARMRegister(dest, 32));
   1059 }
   1060 
   1061 void MacroAssembler::clz64(Register64 src, Register64 dest) {
   1062  Clz(ARMRegister(dest.reg, 64), ARMRegister(src.reg, 64));
   1063 }
   1064 
   1065 void MacroAssembler::ctz64(Register64 src, Register64 dest) {
   1066  if (CPUHas(vixl::CPUFeatures::kCSSC)) {
   1067    Ctz(ARMRegister(dest.reg, 64), ARMRegister(src.reg, 64));
   1068    return;
   1069  }
   1070  Rbit(ARMRegister(dest.reg, 64), ARMRegister(src.reg, 64));
   1071  Clz(ARMRegister(dest.reg, 64), ARMRegister(dest.reg, 64));
   1072 }
   1073 
   1074 void MacroAssembler::popcnt32(Register src_, Register dest_, Register tmp_) {
   1075  ARMRegister src(src_, 32);
   1076  ARMRegister dest(dest_, 32);
   1077 
   1078  if (CPUHas(vixl::CPUFeatures::kCSSC)) {
   1079    Cnt(dest, src);
   1080    return;
   1081  }
   1082 
   1083  MOZ_ASSERT(tmp_ != Register::Invalid());
   1084 
   1085  // Equivalent to mozilla::CountPopulation32().
   1086 
   1087  ARMRegister tmp(tmp_, 32);
   1088 
   1089  Mov(tmp, src);
   1090  if (src_ != dest_) {
   1091    Mov(dest, src);
   1092  }
   1093  Lsr(dest, dest, 1);
   1094  And(dest, dest, 0x55555555);
   1095  Sub(dest, tmp, dest);
   1096  Lsr(tmp, dest, 2);
   1097  And(tmp, tmp, 0x33333333);
   1098  And(dest, dest, 0x33333333);
   1099  Add(dest, tmp, dest);
   1100  Add(dest, dest, Operand(dest, vixl::LSR, 4));
   1101  And(dest, dest, 0x0F0F0F0F);
   1102  Add(dest, dest, Operand(dest, vixl::LSL, 8));
   1103  Add(dest, dest, Operand(dest, vixl::LSL, 16));
   1104  Lsr(dest, dest, 24);
   1105 }
   1106 
   1107 void MacroAssembler::popcnt64(Register64 src_, Register64 dest_,
   1108                              Register tmp_) {
   1109  ARMRegister src(src_.reg, 64);
   1110  ARMRegister dest(dest_.reg, 64);
   1111 
   1112  if (CPUHas(vixl::CPUFeatures::kCSSC)) {
   1113    Cnt(dest, src);
   1114    return;
   1115  }
   1116 
   1117  MOZ_ASSERT(tmp_ != Register::Invalid());
   1118 
   1119  // Equivalent to mozilla::CountPopulation64(), though likely more efficient.
   1120 
   1121  ARMRegister tmp(tmp_, 64);
   1122 
   1123  Mov(tmp, src);
   1124  if (src_ != dest_) {
   1125    Mov(dest, src);
   1126  }
   1127  Lsr(dest, dest, 1);
   1128  And(dest, dest, 0x5555555555555555);
   1129  Sub(dest, tmp, dest);
   1130  Lsr(tmp, dest, 2);
   1131  And(tmp, tmp, 0x3333333333333333);
   1132  And(dest, dest, 0x3333333333333333);
   1133  Add(dest, tmp, dest);
   1134  Add(dest, dest, Operand(dest, vixl::LSR, 4));
   1135  And(dest, dest, 0x0F0F0F0F0F0F0F0F);
   1136  Add(dest, dest, Operand(dest, vixl::LSL, 8));
   1137  Add(dest, dest, Operand(dest, vixl::LSL, 16));
   1138  Add(dest, dest, Operand(dest, vixl::LSL, 32));
   1139  Lsr(dest, dest, 56);
   1140 }
   1141 
   1142 // ===============================================================
   1143 // Branch functions
   1144 
   1145 void MacroAssembler::branch8(Condition cond, const Address& lhs, Imm32 rhs,
   1146                             Label* label) {
   1147  vixl::UseScratchRegisterScope temps(this);
   1148  Register scratch = temps.AcquireX().asUnsized();
   1149  MOZ_ASSERT(scratch != lhs.base);
   1150 
   1151  switch (cond) {
   1152    case Assembler::Equal:
   1153    case Assembler::NotEqual:
   1154    case Assembler::Above:
   1155    case Assembler::AboveOrEqual:
   1156    case Assembler::Below:
   1157    case Assembler::BelowOrEqual:
   1158      load8ZeroExtend(lhs, scratch);
   1159      branch32(cond, scratch, Imm32(uint8_t(rhs.value)), label);
   1160      break;
   1161 
   1162    case Assembler::GreaterThan:
   1163    case Assembler::GreaterThanOrEqual:
   1164    case Assembler::LessThan:
   1165    case Assembler::LessThanOrEqual:
   1166      load8SignExtend(lhs, scratch);
   1167      branch32(cond, scratch, Imm32(int8_t(rhs.value)), label);
   1168      break;
   1169 
   1170    default:
   1171      MOZ_CRASH("unexpected condition");
   1172  }
   1173 }
   1174 
   1175 void MacroAssembler::branch8(Condition cond, const BaseIndex& lhs, Register rhs,
   1176                             Label* label) {
   1177  vixl::UseScratchRegisterScope temps(this);
   1178  Register scratch = temps.AcquireX().asUnsized();
   1179  MOZ_ASSERT(scratch != lhs.base);
   1180 
   1181  switch (cond) {
   1182    case Assembler::Equal:
   1183    case Assembler::NotEqual:
   1184    case Assembler::Above:
   1185    case Assembler::AboveOrEqual:
   1186    case Assembler::Below:
   1187    case Assembler::BelowOrEqual:
   1188      load8ZeroExtend(lhs, scratch);
   1189      branch32(cond, scratch, rhs, label);
   1190      break;
   1191 
   1192    case Assembler::GreaterThan:
   1193    case Assembler::GreaterThanOrEqual:
   1194    case Assembler::LessThan:
   1195    case Assembler::LessThanOrEqual:
   1196      load8SignExtend(lhs, scratch);
   1197      branch32(cond, scratch, rhs, label);
   1198      break;
   1199 
   1200    default:
   1201      MOZ_CRASH("unexpected condition");
   1202  }
   1203 }
   1204 
   1205 void MacroAssembler::branch16(Condition cond, const Address& lhs, Imm32 rhs,
   1206                              Label* label) {
   1207  vixl::UseScratchRegisterScope temps(this);
   1208  Register scratch = temps.AcquireX().asUnsized();
   1209  MOZ_ASSERT(scratch != lhs.base);
   1210 
   1211  switch (cond) {
   1212    case Assembler::Equal:
   1213    case Assembler::NotEqual:
   1214    case Assembler::Above:
   1215    case Assembler::AboveOrEqual:
   1216    case Assembler::Below:
   1217    case Assembler::BelowOrEqual:
   1218      load16ZeroExtend(lhs, scratch);
   1219      branch32(cond, scratch, Imm32(uint16_t(rhs.value)), label);
   1220      break;
   1221 
   1222    case Assembler::GreaterThan:
   1223    case Assembler::GreaterThanOrEqual:
   1224    case Assembler::LessThan:
   1225    case Assembler::LessThanOrEqual:
   1226      load16SignExtend(lhs, scratch);
   1227      branch32(cond, scratch, Imm32(int16_t(rhs.value)), label);
   1228      break;
   1229 
   1230    default:
   1231      MOZ_CRASH("unexpected condition");
   1232  }
   1233 }
   1234 
   1235 void MacroAssembler::branch32(Condition cond, Register lhs, Register rhs,
   1236                              Label* label) {
   1237  cmp32(lhs, rhs);
   1238  B(label, cond);
   1239 }
   1240 
   1241 void MacroAssembler::branch32(Condition cond, Register lhs, Imm32 imm,
   1242                              Label* label) {
   1243  if (imm.value == 0 && cond == Assembler::Equal) {
   1244    Cbz(ARMRegister(lhs, 32), label);
   1245  } else if (imm.value == 0 && cond == Assembler::NotEqual) {
   1246    Cbnz(ARMRegister(lhs, 32), label);
   1247  } else {
   1248    cmp32(lhs, imm);
   1249    B(label, cond);
   1250  }
   1251 }
   1252 
   1253 void MacroAssembler::branch32(Condition cond, Register lhs, const Address& rhs,
   1254                              Label* label) {
   1255  vixl::UseScratchRegisterScope temps(this);
   1256  const Register scratch = temps.AcquireX().asUnsized();
   1257  MOZ_ASSERT(scratch != lhs);
   1258  MOZ_ASSERT(scratch != rhs.base);
   1259  load32(rhs, scratch);
   1260  branch32(cond, lhs, scratch, label);
   1261 }
   1262 
   1263 void MacroAssembler::branch32(Condition cond, const Address& lhs, Register rhs,
   1264                              Label* label) {
   1265  vixl::UseScratchRegisterScope temps(this);
   1266  const Register scratch = temps.AcquireX().asUnsized();
   1267  MOZ_ASSERT(scratch != lhs.base);
   1268  MOZ_ASSERT(scratch != rhs);
   1269  load32(lhs, scratch);
   1270  branch32(cond, scratch, rhs, label);
   1271 }
   1272 
   1273 void MacroAssembler::branch32(Condition cond, const Address& lhs, Imm32 imm,
   1274                              Label* label) {
   1275  vixl::UseScratchRegisterScope temps(this);
   1276  const Register scratch = temps.AcquireX().asUnsized();
   1277  MOZ_ASSERT(scratch != lhs.base);
   1278  load32(lhs, scratch);
   1279  branch32(cond, scratch, imm, label);
   1280 }
   1281 
   1282 void MacroAssembler::branch32(Condition cond, const AbsoluteAddress& lhs,
   1283                              Register rhs, Label* label) {
   1284  vixl::UseScratchRegisterScope temps(this);
   1285  const Register scratch = temps.AcquireX().asUnsized();
   1286  movePtr(ImmPtr(lhs.addr), scratch);
   1287  branch32(cond, Address(scratch, 0), rhs, label);
   1288 }
   1289 
   1290 void MacroAssembler::branch32(Condition cond, const AbsoluteAddress& lhs,
   1291                              Imm32 rhs, Label* label) {
   1292  vixl::UseScratchRegisterScope temps(this);
   1293  const Register scratch = temps.AcquireX().asUnsized();
   1294  load32(lhs, scratch);
   1295  branch32(cond, scratch, rhs, label);
   1296 }
   1297 
   1298 void MacroAssembler::branch32(Condition cond, const BaseIndex& lhs, Imm32 rhs,
   1299                              Label* label) {
   1300  vixl::UseScratchRegisterScope temps(this);
   1301  const ARMRegister scratch32 = temps.AcquireW();
   1302  MOZ_ASSERT(scratch32.asUnsized() != lhs.base);
   1303  MOZ_ASSERT(scratch32.asUnsized() != lhs.index);
   1304  doBaseIndex(scratch32, lhs, vixl::LDR_w);
   1305  branch32(cond, scratch32.asUnsized(), rhs, label);
   1306 }
   1307 
   1308 void MacroAssembler::branch32(Condition cond, wasm::SymbolicAddress lhs,
   1309                              Imm32 rhs, Label* label) {
   1310  vixl::UseScratchRegisterScope temps(this);
   1311  const Register scratch = temps.AcquireX().asUnsized();
   1312  movePtr(lhs, scratch);
   1313  branch32(cond, Address(scratch, 0), rhs, label);
   1314 }
   1315 
   1316 void MacroAssembler::branch64(Condition cond, Register64 lhs, Imm64 val,
   1317                              Label* success, Label* fail) {
   1318  branchPtr(cond, lhs.reg, ImmWord(val.value), success);
   1319  if (fail) {
   1320    B(fail);
   1321  }
   1322 }
   1323 
   1324 void MacroAssembler::branch64(Condition cond, Register64 lhs, Register64 rhs,
   1325                              Label* success, Label* fail) {
   1326  branchPtr(cond, lhs.reg, rhs.reg, success);
   1327  if (fail) {
   1328    B(fail);
   1329  }
   1330 }
   1331 
   1332 void MacroAssembler::branch64(Condition cond, const Address& lhs, Imm64 val,
   1333                              Label* success, Label* fail) {
   1334  branchPtr(cond, lhs, ImmWord(val.value), success);
   1335  if (fail) {
   1336    B(fail);
   1337  }
   1338 }
   1339 
   1340 void MacroAssembler::branch64(Condition cond, const Address& lhs,
   1341                              Register64 rhs, Label* success, Label* fail) {
   1342  branchPtr(cond, lhs, rhs.reg, success);
   1343  if (fail) {
   1344    B(fail);
   1345  }
   1346 }
   1347 
   1348 void MacroAssembler::branch64(Condition cond, const Address& lhs,
   1349                              const Address& rhs, Register scratch,
   1350                              Label* label) {
   1351  MOZ_ASSERT(cond == Assembler::NotEqual || cond == Assembler::Equal,
   1352             "other condition codes not supported");
   1353  MOZ_ASSERT(lhs.base != scratch);
   1354  MOZ_ASSERT(rhs.base != scratch);
   1355 
   1356  loadPtr(rhs, scratch);
   1357  branchPtr(cond, lhs, scratch, label);
   1358 }
   1359 
   1360 void MacroAssembler::branchPtr(Condition cond, Register lhs, Register rhs,
   1361                               Label* label) {
   1362  Cmp(ARMRegister(lhs, 64), ARMRegister(rhs, 64));
   1363  B(label, cond);
   1364 }
   1365 
   1366 void MacroAssembler::branchPtr(Condition cond, Register lhs, Imm32 rhs,
   1367                               Label* label) {
   1368  if (rhs.value == 0 && cond == Assembler::Equal) {
   1369    Cbz(ARMRegister(lhs, 64), label);
   1370  } else if (rhs.value == 0 && cond == Assembler::NotEqual) {
   1371    Cbnz(ARMRegister(lhs, 64), label);
   1372  } else {
   1373    cmpPtr(lhs, rhs);
   1374    B(label, cond);
   1375  }
   1376 }
   1377 
   1378 void MacroAssembler::branchPtr(Condition cond, Register lhs, ImmPtr rhs,
   1379                               Label* label) {
   1380  if (rhs.value == 0 && cond == Assembler::Equal) {
   1381    Cbz(ARMRegister(lhs, 64), label);
   1382  } else if (rhs.value == 0 && cond == Assembler::NotEqual) {
   1383    Cbnz(ARMRegister(lhs, 64), label);
   1384  } else {
   1385    cmpPtr(lhs, rhs);
   1386    B(label, cond);
   1387  }
   1388 }
   1389 
   1390 void MacroAssembler::branchPtr(Condition cond, Register lhs, ImmGCPtr rhs,
   1391                               Label* label) {
   1392  vixl::UseScratchRegisterScope temps(this);
   1393  const Register scratch = temps.AcquireX().asUnsized();
   1394  MOZ_ASSERT(scratch != lhs);
   1395  movePtr(rhs, scratch);
   1396  branchPtr(cond, lhs, scratch, label);
   1397 }
   1398 
   1399 void MacroAssembler::branchPtr(Condition cond, Register lhs, ImmWord rhs,
   1400                               Label* label) {
   1401  if (rhs.value == 0 && cond == Assembler::Equal) {
   1402    Cbz(ARMRegister(lhs, 64), label);
   1403  } else if (rhs.value == 0 && cond == Assembler::NotEqual) {
   1404    Cbnz(ARMRegister(lhs, 64), label);
   1405  } else {
   1406    cmpPtr(lhs, rhs);
   1407    B(label, cond);
   1408  }
   1409 }
   1410 
   1411 void MacroAssembler::branchPtr(Condition cond, const Address& lhs, Register rhs,
   1412                               Label* label) {
   1413  vixl::UseScratchRegisterScope temps(this);
   1414  const Register scratch = temps.AcquireX().asUnsized();
   1415  MOZ_ASSERT(scratch != lhs.base);
   1416  MOZ_ASSERT(scratch != rhs);
   1417  loadPtr(lhs, scratch);
   1418  branchPtr(cond, scratch, rhs, label);
   1419 }
   1420 
   1421 void MacroAssembler::branchPtr(Condition cond, const Address& lhs, ImmPtr rhs,
   1422                               Label* label) {
   1423  vixl::UseScratchRegisterScope temps(this);
   1424  const Register scratch = temps.AcquireX().asUnsized();
   1425  MOZ_ASSERT(scratch != lhs.base);
   1426  loadPtr(lhs, scratch);
   1427  branchPtr(cond, scratch, rhs, label);
   1428 }
   1429 
   1430 void MacroAssembler::branchPtr(Condition cond, const Address& lhs, ImmGCPtr rhs,
   1431                               Label* label) {
   1432  vixl::UseScratchRegisterScope temps(this);
   1433  const ARMRegister scratch1_64 = temps.AcquireX();
   1434  const ARMRegister scratch2_64 = temps.AcquireX();
   1435  MOZ_ASSERT(scratch1_64.asUnsized() != lhs.base);
   1436  MOZ_ASSERT(scratch2_64.asUnsized() != lhs.base);
   1437 
   1438  movePtr(rhs, scratch1_64.asUnsized());
   1439  loadPtr(lhs, scratch2_64.asUnsized());
   1440  branchPtr(cond, scratch2_64.asUnsized(), scratch1_64.asUnsized(), label);
   1441 }
   1442 
   1443 void MacroAssembler::branchPtr(Condition cond, const Address& lhs, ImmWord rhs,
   1444                               Label* label) {
   1445  vixl::UseScratchRegisterScope temps(this);
   1446  const Register scratch = temps.AcquireX().asUnsized();
   1447  MOZ_ASSERT(scratch != lhs.base);
   1448  loadPtr(lhs, scratch);
   1449  branchPtr(cond, scratch, rhs, label);
   1450 }
   1451 
   1452 void MacroAssembler::branchPtr(Condition cond, const AbsoluteAddress& lhs,
   1453                               Register rhs, Label* label) {
   1454  vixl::UseScratchRegisterScope temps(this);
   1455  const Register scratch = temps.AcquireX().asUnsized();
   1456  MOZ_ASSERT(scratch != rhs);
   1457  loadPtr(lhs, scratch);
   1458  branchPtr(cond, scratch, rhs, label);
   1459 }
   1460 
   1461 void MacroAssembler::branchPtr(Condition cond, const AbsoluteAddress& lhs,
   1462                               ImmWord rhs, Label* label) {
   1463  vixl::UseScratchRegisterScope temps(this);
   1464  const Register scratch = temps.AcquireX().asUnsized();
   1465  loadPtr(lhs, scratch);
   1466  branchPtr(cond, scratch, rhs, label);
   1467 }
   1468 
   1469 void MacroAssembler::branchPtr(Condition cond, wasm::SymbolicAddress lhs,
   1470                               Register rhs, Label* label) {
   1471  vixl::UseScratchRegisterScope temps(this);
   1472  const Register scratch = temps.AcquireX().asUnsized();
   1473  MOZ_ASSERT(scratch != rhs);
   1474  loadPtr(lhs, scratch);
   1475  branchPtr(cond, scratch, rhs, label);
   1476 }
   1477 
   1478 void MacroAssembler::branchPtr(Condition cond, const BaseIndex& lhs,
   1479                               ImmWord rhs, Label* label) {
   1480  vixl::UseScratchRegisterScope temps(this);
   1481  const Register scratch = temps.AcquireX().asUnsized();
   1482  MOZ_ASSERT(scratch != lhs.base);
   1483  MOZ_ASSERT(scratch != lhs.index);
   1484  loadPtr(lhs, scratch);
   1485  branchPtr(cond, scratch, rhs, label);
   1486 }
   1487 
   1488 void MacroAssembler::branchPtr(Condition cond, const BaseIndex& lhs,
   1489                               Register rhs, Label* label) {
   1490  vixl::UseScratchRegisterScope temps(this);
   1491  const Register scratch = temps.AcquireX().asUnsized();
   1492  MOZ_ASSERT(scratch != lhs.base);
   1493  MOZ_ASSERT(scratch != lhs.index);
   1494  loadPtr(lhs, scratch);
   1495  branchPtr(cond, scratch, rhs, label);
   1496 }
   1497 
   1498 void MacroAssembler::branchPrivatePtr(Condition cond, const Address& lhs,
   1499                                      Register rhs, Label* label) {
   1500  branchPtr(cond, lhs, rhs, label);
   1501 }
   1502 
   1503 void MacroAssembler::branchFloat(DoubleCondition cond, FloatRegister lhs,
   1504                                 FloatRegister rhs, Label* label) {
   1505  compareFloat(lhs, rhs);
   1506  switch (cond) {
   1507    case DoubleNotEqual: {
   1508      Label unordered;
   1509      // not equal *and* ordered
   1510      branch(Overflow, &unordered);
   1511      branch(NotEqual, label);
   1512      bind(&unordered);
   1513      break;
   1514    }
   1515    case DoubleEqualOrUnordered:
   1516      branch(Overflow, label);
   1517      branch(Equal, label);
   1518      break;
   1519    default:
   1520      branch(Condition(cond), label);
   1521  }
   1522 }
   1523 
   1524 void MacroAssembler::branchTruncateFloat32MaybeModUint32(FloatRegister src,
   1525                                                         Register dest,
   1526                                                         Label* fail) {
   1527  // Infallible operation on ARM64.
   1528  truncateFloat32ModUint32(src, dest);
   1529 }
   1530 
   1531 void MacroAssembler::branchTruncateFloat32ToInt32(FloatRegister src,
   1532                                                  Register dest, Label* fail) {
   1533  convertFloat32ToInt32(src, dest, fail, false);
   1534 }
   1535 
   1536 void MacroAssembler::branchDouble(DoubleCondition cond, FloatRegister lhs,
   1537                                  FloatRegister rhs, Label* label) {
   1538  compareDouble(lhs, rhs);
   1539  switch (cond) {
   1540    case DoubleNotEqual: {
   1541      Label unordered;
   1542      // not equal *and* ordered
   1543      branch(Overflow, &unordered);
   1544      branch(NotEqual, label);
   1545      bind(&unordered);
   1546      break;
   1547    }
   1548    case DoubleEqualOrUnordered:
   1549      branch(Overflow, label);
   1550      branch(Equal, label);
   1551      break;
   1552    default:
   1553      branch(Condition(cond), label);
   1554  }
   1555 }
   1556 
   1557 void MacroAssembler::branchTruncateDoubleMaybeModUint32(FloatRegister src,
   1558                                                        Register dest,
   1559                                                        Label* fail) {
   1560  // ARMv8.3 chips support the FJCVTZS instruction, which handles exactly this
   1561  // logic.
   1562  if (hasFjcvtzs()) {
   1563    Fjcvtzs(ARMRegister(dest, 32), ARMFPRegister(src, 64));
   1564    return;
   1565  }
   1566 
   1567  vixl::UseScratchRegisterScope temps(this);
   1568  const ARMRegister scratch64 = temps.AcquireX();
   1569 
   1570  // An out of range integer will be saturated to the destination size.
   1571  ARMFPRegister src64(src, 64);
   1572  ARMRegister dest64(dest, 64);
   1573 
   1574  MOZ_ASSERT(!scratch64.Is(dest64));
   1575 
   1576  // Convert scalar to signed 64-bit fixed-point, rounding toward zero.
   1577  // In the case of overflow, the output is saturated.
   1578  // In the case of NaN and -0, the output is zero.
   1579  Fcvtzs(dest64, src64);
   1580 
   1581  // Fail if the result is saturated, i.e. it's either INT64_MIN or INT64_MAX.
   1582  Add(scratch64, dest64, Operand(0x7fff'ffff'ffff'ffff));
   1583  Cmn(scratch64, 3);
   1584  B(fail, Assembler::Above);
   1585 
   1586  // Clear upper 32 bits.
   1587  Uxtw(dest64, dest64);
   1588 }
   1589 
   1590 void MacroAssembler::branchTruncateDoubleToInt32(FloatRegister src,
   1591                                                 Register dest, Label* fail) {
   1592  ARMFPRegister src64(src, 64);
   1593  ARMRegister dest64(dest, 64);
   1594  ARMRegister dest32(dest, 32);
   1595 
   1596  // Convert scalar to signed 64-bit fixed-point, rounding toward zero.
   1597  // In the case of overflow, the output is saturated.
   1598  // In the case of NaN and -0, the output is zero.
   1599  Fcvtzs(dest64, src64);
   1600 
   1601  // Fail on overflow cases.
   1602  Cmp(dest64, Operand(dest32, vixl::SXTW));
   1603  B(fail, Assembler::NotEqual);
   1604 
   1605  // Clear upper 32 bits.
   1606  Uxtw(dest64, dest64);
   1607 }
   1608 
   1609 void MacroAssembler::branchInt64NotInPtrRange(Register64 src, Label* label) {
   1610  // No-op on 64-bit platforms.
   1611 }
   1612 
   1613 void MacroAssembler::branchUInt64NotInPtrRange(Register64 src, Label* label) {
   1614  branchTest64(Assembler::Signed, src, src, label);
   1615 }
   1616 
   1617 template <typename T>
   1618 void MacroAssembler::branchAdd32(Condition cond, T src, Register dest,
   1619                                 Label* label) {
   1620  adds32(src, dest);
   1621  B(label, cond);
   1622 }
   1623 
   1624 template <typename T>
   1625 void MacroAssembler::branchSub32(Condition cond, T src, Register dest,
   1626                                 Label* label) {
   1627  subs32(src, dest);
   1628  branch(cond, label);
   1629 }
   1630 
   1631 template <typename T>
   1632 void MacroAssembler::branchMul32(Condition cond, T src, Register dest,
   1633                                 Label* label) {
   1634  MOZ_ASSERT(cond == Assembler::Overflow);
   1635  mul32(src, dest, dest, label);
   1636 }
   1637 
   1638 template <typename T>
   1639 void MacroAssembler::branchRshift32(Condition cond, T src, Register dest,
   1640                                    Label* label) {
   1641  MOZ_ASSERT(cond == Zero || cond == NonZero);
   1642  rshift32(src, dest);
   1643  branch32(cond == Zero ? Equal : NotEqual, dest, Imm32(0), label);
   1644 }
   1645 
   1646 void MacroAssembler::branchNeg32(Condition cond, Register reg, Label* label) {
   1647  MOZ_ASSERT(cond == Overflow);
   1648  negs32(reg);
   1649  B(label, cond);
   1650 }
   1651 
   1652 template <typename T>
   1653 void MacroAssembler::branchAddPtr(Condition cond, T src, Register dest,
   1654                                  Label* label) {
   1655  adds64(src, dest);
   1656  B(label, cond);
   1657 }
   1658 
   1659 template <typename T>
   1660 void MacroAssembler::branchSubPtr(Condition cond, T src, Register dest,
   1661                                  Label* label) {
   1662  subs64(src, dest);
   1663  B(label, cond);
   1664 }
   1665 
   1666 void MacroAssembler::branchMulPtr(Condition cond, Register src, Register dest,
   1667                                  Label* label) {
   1668  MOZ_ASSERT(cond == Assembler::Overflow);
   1669 
   1670  vixl::UseScratchRegisterScope temps(this);
   1671  const ARMRegister scratch64 = temps.AcquireX();
   1672  const ARMRegister src64(src, 64);
   1673  const ARMRegister dest64(dest, 64);
   1674 
   1675  Smulh(scratch64, dest64, src64);
   1676  Mul(dest64, dest64, src64);
   1677  Cmp(scratch64, Operand(dest64, vixl::ASR, 63));
   1678  B(label, NotEqual);
   1679 }
   1680 
   1681 void MacroAssembler::branchNegPtr(Condition cond, Register reg, Label* label) {
   1682  MOZ_ASSERT(cond == Overflow);
   1683  negs64(reg);
   1684  B(label, cond);
   1685 }
   1686 
   1687 void MacroAssembler::decBranchPtr(Condition cond, Register lhs, Imm32 rhs,
   1688                                  Label* label) {
   1689  Subs(ARMRegister(lhs, 64), ARMRegister(lhs, 64), Operand(rhs.value));
   1690  B(cond, label);
   1691 }
   1692 
   1693 void MacroAssembler::branchTest32(Condition cond, Register lhs, Register rhs,
   1694                                  Label* label) {
   1695  MOZ_ASSERT(cond == Zero || cond == NonZero || cond == Signed ||
   1696             cond == NotSigned);
   1697  // The x86-biased front end prefers |test foo, foo| to |cmp foo, #0|.  We look
   1698  // for the former pattern and expand as Cbz/Cbnz when possible.
   1699  if (lhs == rhs && cond == Zero) {
   1700    Cbz(ARMRegister(lhs, 32), label);
   1701  } else if (lhs == rhs && cond == NonZero) {
   1702    Cbnz(ARMRegister(lhs, 32), label);
   1703  } else {
   1704    test32(lhs, rhs);
   1705    B(label, cond);
   1706  }
   1707 }
   1708 
   1709 void MacroAssembler::branchTest32(Condition cond, Register lhs, Imm32 rhs,
   1710                                  Label* label) {
   1711  MOZ_ASSERT(cond == Zero || cond == NonZero || cond == Signed ||
   1712             cond == NotSigned);
   1713  test32(lhs, rhs);
   1714  B(label, cond);
   1715 }
   1716 
   1717 void MacroAssembler::branchTest32(Condition cond, const Address& lhs, Imm32 rhs,
   1718                                  Label* label) {
   1719  vixl::UseScratchRegisterScope temps(this);
   1720  const Register scratch = temps.AcquireX().asUnsized();
   1721  MOZ_ASSERT(scratch != lhs.base);
   1722  load32(lhs, scratch);
   1723  branchTest32(cond, scratch, rhs, label);
   1724 }
   1725 
   1726 void MacroAssembler::branchTest32(Condition cond, const AbsoluteAddress& lhs,
   1727                                  Imm32 rhs, Label* label) {
   1728  vixl::UseScratchRegisterScope temps(this);
   1729  const Register scratch = temps.AcquireX().asUnsized();
   1730  load32(lhs, scratch);
   1731  branchTest32(cond, scratch, rhs, label);
   1732 }
   1733 
   1734 void MacroAssembler::branchTestPtr(Condition cond, Register lhs, Register rhs,
   1735                                   Label* label) {
   1736  // See branchTest32.
   1737  MOZ_ASSERT(cond == Zero || cond == NonZero || cond == Signed ||
   1738             cond == NotSigned);
   1739  if (lhs == rhs && cond == Zero) {
   1740    Cbz(ARMRegister(lhs, 64), label);
   1741  } else if (lhs == rhs && cond == NonZero) {
   1742    Cbnz(ARMRegister(lhs, 64), label);
   1743  } else {
   1744    Tst(ARMRegister(lhs, 64), Operand(ARMRegister(rhs, 64)));
   1745    B(label, cond);
   1746  }
   1747 }
   1748 
   1749 void MacroAssembler::branchTestPtr(Condition cond, Register lhs, Imm32 rhs,
   1750                                   Label* label) {
   1751  Tst(ARMRegister(lhs, 64), Operand(rhs.value));
   1752  B(label, cond);
   1753 }
   1754 
   1755 void MacroAssembler::branchTestPtr(Condition cond, Register lhs, ImmWord rhs,
   1756                                   Label* label) {
   1757  Tst(ARMRegister(lhs, 64), Operand(rhs.value));
   1758  B(label, cond);
   1759 }
   1760 
   1761 void MacroAssembler::branchTestPtr(Condition cond, const Address& lhs,
   1762                                   Imm32 rhs, Label* label) {
   1763  vixl::UseScratchRegisterScope temps(this);
   1764  const Register scratch = temps.AcquireX().asUnsized();
   1765  MOZ_ASSERT(scratch != lhs.base);
   1766  loadPtr(lhs, scratch);
   1767  branchTestPtr(cond, scratch, rhs, label);
   1768 }
   1769 
   1770 void MacroAssembler::branchTest64(Condition cond, Register64 lhs,
   1771                                  Register64 rhs, Register temp, Label* success,
   1772                                  Label* fail) {
   1773  branchTestPtr(cond, lhs.reg, rhs.reg, success);
   1774  if (fail) {
   1775    B(fail);
   1776  }
   1777 }
   1778 
   1779 void MacroAssembler::branchTest64(Condition cond, Register64 lhs, Imm64 rhs,
   1780                                  Label* success, Label* fail) {
   1781  branchTestPtr(cond, lhs.reg, ImmWord(rhs.value), success);
   1782  if (fail) {
   1783    B(fail);
   1784  }
   1785 }
   1786 
   1787 void MacroAssembler::branchTestUndefined(Condition cond, Register tag,
   1788                                         Label* label) {
   1789  branchTestUndefinedImpl(cond, tag, label);
   1790 }
   1791 
   1792 void MacroAssembler::branchTestUndefined(Condition cond, const Address& address,
   1793                                         Label* label) {
   1794  branchTestUndefinedImpl(cond, address, label);
   1795 }
   1796 
   1797 void MacroAssembler::branchTestUndefined(Condition cond,
   1798                                         const BaseIndex& address,
   1799                                         Label* label) {
   1800  branchTestUndefinedImpl(cond, address, label);
   1801 }
   1802 
   1803 void MacroAssembler::branchTestUndefined(Condition cond,
   1804                                         const ValueOperand& value,
   1805                                         Label* label) {
   1806  branchTestUndefinedImpl(cond, value, label);
   1807 }
   1808 
   1809 template <typename T>
   1810 void MacroAssembler::branchTestUndefinedImpl(Condition cond, const T& t,
   1811                                             Label* label) {
   1812  Condition c = testUndefined(cond, t);
   1813  B(label, c);
   1814 }
   1815 
   1816 void MacroAssembler::branchTestInt32(Condition cond, Register tag,
   1817                                     Label* label) {
   1818  branchTestInt32Impl(cond, tag, label);
   1819 }
   1820 
   1821 void MacroAssembler::branchTestInt32(Condition cond, const Address& address,
   1822                                     Label* label) {
   1823  branchTestInt32Impl(cond, address, label);
   1824 }
   1825 
   1826 void MacroAssembler::branchTestInt32(Condition cond, const BaseIndex& address,
   1827                                     Label* label) {
   1828  branchTestInt32Impl(cond, address, label);
   1829 }
   1830 
   1831 void MacroAssembler::branchTestInt32(Condition cond, const ValueOperand& value,
   1832                                     Label* label) {
   1833  branchTestInt32Impl(cond, value, label);
   1834 }
   1835 
   1836 template <typename T>
   1837 void MacroAssembler::branchTestInt32Impl(Condition cond, const T& t,
   1838                                         Label* label) {
   1839  Condition c = testInt32(cond, t);
   1840  B(label, c);
   1841 }
   1842 
   1843 void MacroAssembler::branchTestInt32Truthy(bool truthy,
   1844                                           const ValueOperand& value,
   1845                                           Label* label) {
   1846  Condition c = testInt32Truthy(truthy, value);
   1847  B(label, c);
   1848 }
   1849 
   1850 void MacroAssembler::branchTestDouble(Condition cond, Register tag,
   1851                                      Label* label) {
   1852  branchTestDoubleImpl(cond, tag, label);
   1853 }
   1854 
   1855 void MacroAssembler::branchTestDouble(Condition cond, const Address& address,
   1856                                      Label* label) {
   1857  branchTestDoubleImpl(cond, address, label);
   1858 }
   1859 
   1860 void MacroAssembler::branchTestDouble(Condition cond, const BaseIndex& address,
   1861                                      Label* label) {
   1862  branchTestDoubleImpl(cond, address, label);
   1863 }
   1864 
   1865 void MacroAssembler::branchTestDouble(Condition cond, const ValueOperand& value,
   1866                                      Label* label) {
   1867  branchTestDoubleImpl(cond, value, label);
   1868 }
   1869 
   1870 template <typename T>
   1871 void MacroAssembler::branchTestDoubleImpl(Condition cond, const T& t,
   1872                                          Label* label) {
   1873  Condition c = testDouble(cond, t);
   1874  B(label, c);
   1875 }
   1876 
   1877 void MacroAssembler::branchTestDoubleTruthy(bool truthy, FloatRegister reg,
   1878                                            Label* label) {
   1879  Fcmp(ARMFPRegister(reg, 64), 0.0);
   1880  if (!truthy) {
   1881    // falsy values are zero, and NaN.
   1882    branch(Zero, label);
   1883    branch(Overflow, label);
   1884  } else {
   1885    // truthy values are non-zero and not nan.
   1886    // If it is overflow
   1887    Label onFalse;
   1888    branch(Zero, &onFalse);
   1889    branch(Overflow, &onFalse);
   1890    B(label);
   1891    bind(&onFalse);
   1892  }
   1893 }
   1894 
   1895 void MacroAssembler::branchTestNumber(Condition cond, Register tag,
   1896                                      Label* label) {
   1897  branchTestNumberImpl(cond, tag, label);
   1898 }
   1899 
   1900 void MacroAssembler::branchTestNumber(Condition cond, const ValueOperand& value,
   1901                                      Label* label) {
   1902  branchTestNumberImpl(cond, value, label);
   1903 }
   1904 
   1905 template <typename T>
   1906 void MacroAssembler::branchTestNumberImpl(Condition cond, const T& t,
   1907                                          Label* label) {
   1908  Condition c = testNumber(cond, t);
   1909  B(label, c);
   1910 }
   1911 
   1912 void MacroAssembler::branchTestBoolean(Condition cond, Register tag,
   1913                                       Label* label) {
   1914  branchTestBooleanImpl(cond, tag, label);
   1915 }
   1916 
   1917 void MacroAssembler::branchTestBoolean(Condition cond, const Address& address,
   1918                                       Label* label) {
   1919  branchTestBooleanImpl(cond, address, label);
   1920 }
   1921 
   1922 void MacroAssembler::branchTestBoolean(Condition cond, const BaseIndex& address,
   1923                                       Label* label) {
   1924  branchTestBooleanImpl(cond, address, label);
   1925 }
   1926 
   1927 void MacroAssembler::branchTestBoolean(Condition cond,
   1928                                       const ValueOperand& value,
   1929                                       Label* label) {
   1930  branchTestBooleanImpl(cond, value, label);
   1931 }
   1932 
   1933 template <typename T>
   1934 void MacroAssembler::branchTestBooleanImpl(Condition cond, const T& tag,
   1935                                           Label* label) {
   1936  Condition c = testBoolean(cond, tag);
   1937  B(label, c);
   1938 }
   1939 
   1940 void MacroAssembler::branchTestBooleanTruthy(bool truthy,
   1941                                             const ValueOperand& value,
   1942                                             Label* label) {
   1943  Condition c = testBooleanTruthy(truthy, value);
   1944  B(label, c);
   1945 }
   1946 
   1947 void MacroAssembler::branchTestString(Condition cond, Register tag,
   1948                                      Label* label) {
   1949  branchTestStringImpl(cond, tag, label);
   1950 }
   1951 
   1952 void MacroAssembler::branchTestString(Condition cond, const Address& address,
   1953                                      Label* label) {
   1954  branchTestStringImpl(cond, address, label);
   1955 }
   1956 
   1957 void MacroAssembler::branchTestString(Condition cond, const BaseIndex& address,
   1958                                      Label* label) {
   1959  branchTestStringImpl(cond, address, label);
   1960 }
   1961 
   1962 void MacroAssembler::branchTestString(Condition cond, const ValueOperand& value,
   1963                                      Label* label) {
   1964  branchTestStringImpl(cond, value, label);
   1965 }
   1966 
   1967 template <typename T>
   1968 void MacroAssembler::branchTestStringImpl(Condition cond, const T& t,
   1969                                          Label* label) {
   1970  Condition c = testString(cond, t);
   1971  B(label, c);
   1972 }
   1973 
   1974 void MacroAssembler::branchTestStringTruthy(bool truthy,
   1975                                            const ValueOperand& value,
   1976                                            Label* label) {
   1977  Condition c = testStringTruthy(truthy, value);
   1978  B(label, c);
   1979 }
   1980 
   1981 void MacroAssembler::branchTestSymbol(Condition cond, Register tag,
   1982                                      Label* label) {
   1983  branchTestSymbolImpl(cond, tag, label);
   1984 }
   1985 
   1986 void MacroAssembler::branchTestSymbol(Condition cond, const Address& address,
   1987                                      Label* label) {
   1988  branchTestSymbolImpl(cond, address, label);
   1989 }
   1990 
   1991 void MacroAssembler::branchTestSymbol(Condition cond, const BaseIndex& address,
   1992                                      Label* label) {
   1993  branchTestSymbolImpl(cond, address, label);
   1994 }
   1995 
   1996 void MacroAssembler::branchTestSymbol(Condition cond, const ValueOperand& value,
   1997                                      Label* label) {
   1998  branchTestSymbolImpl(cond, value, label);
   1999 }
   2000 
   2001 template <typename T>
   2002 void MacroAssembler::branchTestSymbolImpl(Condition cond, const T& t,
   2003                                          Label* label) {
   2004  Condition c = testSymbol(cond, t);
   2005  B(label, c);
   2006 }
   2007 
   2008 void MacroAssembler::branchTestBigInt(Condition cond, Register tag,
   2009                                      Label* label) {
   2010  branchTestBigIntImpl(cond, tag, label);
   2011 }
   2012 
   2013 void MacroAssembler::branchTestBigInt(Condition cond, const Address& address,
   2014                                      Label* label) {
   2015  branchTestBigIntImpl(cond, address, label);
   2016 }
   2017 
   2018 void MacroAssembler::branchTestBigInt(Condition cond, const BaseIndex& address,
   2019                                      Label* label) {
   2020  branchTestBigIntImpl(cond, address, label);
   2021 }
   2022 
   2023 void MacroAssembler::branchTestBigInt(Condition cond, const ValueOperand& value,
   2024                                      Label* label) {
   2025  branchTestBigIntImpl(cond, value, label);
   2026 }
   2027 
   2028 template <typename T>
   2029 void MacroAssembler::branchTestBigIntImpl(Condition cond, const T& t,
   2030                                          Label* label) {
   2031  Condition c = testBigInt(cond, t);
   2032  B(label, c);
   2033 }
   2034 
   2035 void MacroAssembler::branchTestBigIntTruthy(bool truthy,
   2036                                            const ValueOperand& value,
   2037                                            Label* label) {
   2038  Condition c = testBigIntTruthy(truthy, value);
   2039  B(label, c);
   2040 }
   2041 
   2042 void MacroAssembler::branchTestNull(Condition cond, Register tag,
   2043                                    Label* label) {
   2044  branchTestNullImpl(cond, tag, label);
   2045 }
   2046 
   2047 void MacroAssembler::branchTestNull(Condition cond, const Address& address,
   2048                                    Label* label) {
   2049  branchTestNullImpl(cond, address, label);
   2050 }
   2051 
   2052 void MacroAssembler::branchTestNull(Condition cond, const BaseIndex& address,
   2053                                    Label* label) {
   2054  branchTestNullImpl(cond, address, label);
   2055 }
   2056 
   2057 void MacroAssembler::branchTestNull(Condition cond, const ValueOperand& value,
   2058                                    Label* label) {
   2059  branchTestNullImpl(cond, value, label);
   2060 }
   2061 
   2062 template <typename T>
   2063 void MacroAssembler::branchTestNullImpl(Condition cond, const T& t,
   2064                                        Label* label) {
   2065  Condition c = testNull(cond, t);
   2066  B(label, c);
   2067 }
   2068 
   2069 void MacroAssembler::branchTestObject(Condition cond, Register tag,
   2070                                      Label* label) {
   2071  branchTestObjectImpl(cond, tag, label);
   2072 }
   2073 
   2074 void MacroAssembler::branchTestObject(Condition cond, const Address& address,
   2075                                      Label* label) {
   2076  branchTestObjectImpl(cond, address, label);
   2077 }
   2078 
   2079 void MacroAssembler::branchTestObject(Condition cond, const BaseIndex& address,
   2080                                      Label* label) {
   2081  branchTestObjectImpl(cond, address, label);
   2082 }
   2083 
   2084 void MacroAssembler::branchTestObject(Condition cond, const ValueOperand& value,
   2085                                      Label* label) {
   2086  branchTestObjectImpl(cond, value, label);
   2087 }
   2088 
   2089 template <typename T>
   2090 void MacroAssembler::branchTestObjectImpl(Condition cond, const T& t,
   2091                                          Label* label) {
   2092  Condition c = testObject(cond, t);
   2093  B(label, c);
   2094 }
   2095 
   2096 void MacroAssembler::branchTestGCThing(Condition cond, const Address& address,
   2097                                       Label* label) {
   2098  branchTestGCThingImpl(cond, address, label);
   2099 }
   2100 
   2101 void MacroAssembler::branchTestGCThing(Condition cond, const BaseIndex& address,
   2102                                       Label* label) {
   2103  branchTestGCThingImpl(cond, address, label);
   2104 }
   2105 
   2106 void MacroAssembler::branchTestGCThing(Condition cond,
   2107                                       const ValueOperand& value,
   2108                                       Label* label) {
   2109  branchTestGCThingImpl(cond, value, label);
   2110 }
   2111 
   2112 template <typename T>
   2113 void MacroAssembler::branchTestGCThingImpl(Condition cond, const T& src,
   2114                                           Label* label) {
   2115  Condition c = testGCThing(cond, src);
   2116  B(label, c);
   2117 }
   2118 
   2119 void MacroAssembler::branchTestPrimitive(Condition cond, Register tag,
   2120                                         Label* label) {
   2121  branchTestPrimitiveImpl(cond, tag, label);
   2122 }
   2123 
   2124 void MacroAssembler::branchTestPrimitive(Condition cond,
   2125                                         const ValueOperand& value,
   2126                                         Label* label) {
   2127  branchTestPrimitiveImpl(cond, value, label);
   2128 }
   2129 
   2130 template <typename T>
   2131 void MacroAssembler::branchTestPrimitiveImpl(Condition cond, const T& t,
   2132                                             Label* label) {
   2133  Condition c = testPrimitive(cond, t);
   2134  B(label, c);
   2135 }
   2136 
   2137 void MacroAssembler::branchTestMagic(Condition cond, Register tag,
   2138                                     Label* label) {
   2139  branchTestMagicImpl(cond, tag, label);
   2140 }
   2141 
   2142 void MacroAssembler::branchTestMagic(Condition cond, const Address& address,
   2143                                     Label* label) {
   2144  branchTestMagicImpl(cond, address, label);
   2145 }
   2146 
   2147 void MacroAssembler::branchTestMagic(Condition cond, const BaseIndex& address,
   2148                                     Label* label) {
   2149  branchTestMagicImpl(cond, address, label);
   2150 }
   2151 
   2152 void MacroAssembler::branchTestMagic(Condition cond, const ValueOperand& value,
   2153                                     Label* label) {
   2154  branchTestMagicImpl(cond, value, label);
   2155 }
   2156 
   2157 template <typename T>
   2158 void MacroAssembler::branchTestMagicImpl(Condition cond, const T& t,
   2159                                         Label* label) {
   2160  Condition c = testMagic(cond, t);
   2161  B(label, c);
   2162 }
   2163 
   2164 void MacroAssembler::branchTestMagic(Condition cond, const Address& valaddr,
   2165                                     JSWhyMagic why, Label* label) {
   2166  uint64_t magic = MagicValue(why).asRawBits();
   2167  cmpPtr(valaddr, ImmWord(magic));
   2168  B(label, cond);
   2169 }
   2170 
   2171 template <typename T>
   2172 void MacroAssembler::branchTestValue(Condition cond, const T& lhs,
   2173                                     const ValueOperand& rhs, Label* label) {
   2174  MOZ_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
   2175  branchPtr(cond, lhs, rhs.valueReg(), label);
   2176 }
   2177 
   2178 template <typename T>
   2179 void MacroAssembler::testNumberSet(Condition cond, const T& src,
   2180                                   Register dest) {
   2181  cond = testNumber(cond, src);
   2182  emitSet(cond, dest);
   2183 }
   2184 
   2185 template <typename T>
   2186 void MacroAssembler::testBooleanSet(Condition cond, const T& src,
   2187                                    Register dest) {
   2188  cond = testBoolean(cond, src);
   2189  emitSet(cond, dest);
   2190 }
   2191 
   2192 template <typename T>
   2193 void MacroAssembler::testStringSet(Condition cond, const T& src,
   2194                                   Register dest) {
   2195  cond = testString(cond, src);
   2196  emitSet(cond, dest);
   2197 }
   2198 
   2199 template <typename T>
   2200 void MacroAssembler::testSymbolSet(Condition cond, const T& src,
   2201                                   Register dest) {
   2202  cond = testSymbol(cond, src);
   2203  emitSet(cond, dest);
   2204 }
   2205 
   2206 template <typename T>
   2207 void MacroAssembler::testBigIntSet(Condition cond, const T& src,
   2208                                   Register dest) {
   2209  cond = testBigInt(cond, src);
   2210  emitSet(cond, dest);
   2211 }
   2212 
   2213 void MacroAssembler::branchToComputedAddress(const BaseIndex& addr) {
   2214  vixl::UseScratchRegisterScope temps(&this->asVIXL());
   2215  const ARMRegister scratch64 = temps.AcquireX();
   2216  loadPtr(addr, scratch64.asUnsized());
   2217  Br(scratch64);
   2218 }
   2219 
   2220 void MacroAssembler::cmp32Move32(Condition cond, Register lhs, Imm32 rhs,
   2221                                 Register src, Register dest) {
   2222  cmp32(lhs, rhs);
   2223  Csel(ARMRegister(dest, 32), ARMRegister(src, 32), ARMRegister(dest, 32),
   2224       cond);
   2225 }
   2226 
   2227 void MacroAssembler::cmp32Move32(Condition cond, Register lhs, Register rhs,
   2228                                 Register src, Register dest) {
   2229  cmp32(lhs, rhs);
   2230  Csel(ARMRegister(dest, 32), ARMRegister(src, 32), ARMRegister(dest, 32),
   2231       cond);
   2232 }
   2233 
   2234 void MacroAssembler::cmp32Move32(Condition cond, Register lhs,
   2235                                 const Address& rhs, Register src,
   2236                                 Register dest) {
   2237  MOZ_CRASH("NYI");
   2238 }
   2239 
   2240 void MacroAssembler::cmpPtrMovePtr(Condition cond, Register lhs, Imm32 rhs,
   2241                                   Register src, Register dest) {
   2242  cmpPtr(lhs, rhs);
   2243  Csel(ARMRegister(dest, 64), ARMRegister(src, 64), ARMRegister(dest, 64),
   2244       cond);
   2245 }
   2246 
   2247 void MacroAssembler::cmpPtrMovePtr(Condition cond, Register lhs, Register rhs,
   2248                                   Register src, Register dest) {
   2249  cmpPtr(lhs, rhs);
   2250  Csel(ARMRegister(dest, 64), ARMRegister(src, 64), ARMRegister(dest, 64),
   2251       cond);
   2252 }
   2253 
   2254 void MacroAssembler::cmpPtrMovePtr(Condition cond, Register lhs,
   2255                                   const Address& rhs, Register src,
   2256                                   Register dest) {
   2257  MOZ_CRASH("NYI");
   2258 }
   2259 
   2260 void MacroAssembler::cmp32Load32(Condition cond, Register lhs,
   2261                                 const Address& rhs, const Address& src,
   2262                                 Register dest) {
   2263  MOZ_CRASH("NYI");
   2264 }
   2265 
   2266 void MacroAssembler::cmp32Load32(Condition cond, Register lhs, Register rhs,
   2267                                 const Address& src, Register dest) {
   2268  MOZ_CRASH("NYI");
   2269 }
   2270 
   2271 void MacroAssembler::cmp32Load32(Condition cond, Register lhs, Imm32 rhs,
   2272                                 const Address& src, Register dest) {
   2273  // Can't use branch32() here, because it may select Cbz/Cbnz which don't
   2274  // affect condition flags.
   2275  Label done;
   2276  cmp32(lhs, rhs);
   2277  B(&done, Assembler::InvertCondition(cond));
   2278 
   2279  // ARM64 does not support conditional loads, so we use a branch with a CSel
   2280  // (to prevent Spectre attacks).
   2281  vixl::UseScratchRegisterScope temps(this);
   2282  const ARMRegister scratch32 = temps.AcquireW();
   2283 
   2284  load32(src, scratch32.asUnsized());
   2285  Csel(ARMRegister(dest, 32), scratch32, ARMRegister(dest, 32), cond);
   2286 
   2287  bind(&done);
   2288 }
   2289 
   2290 void MacroAssembler::cmp32MovePtr(Condition cond, Register lhs, Imm32 rhs,
   2291                                  Register src, Register dest) {
   2292  cmp32(lhs, rhs);
   2293  Csel(ARMRegister(dest, 64), ARMRegister(src, 64), ARMRegister(dest, 64),
   2294       cond);
   2295 }
   2296 
   2297 void MacroAssembler::cmp32LoadPtr(Condition cond, const Address& lhs, Imm32 rhs,
   2298                                  const Address& src, Register dest) {
   2299  // Can't use branch32() here, because it may select Cbz/Cbnz which don't
   2300  // affect condition flags.
   2301  Label done;
   2302  cmp32(lhs, rhs);
   2303  B(&done, Assembler::InvertCondition(cond));
   2304 
   2305  // ARM64 does not support conditional loads, so we use a branch with a CSel
   2306  // (to prevent Spectre attacks).
   2307  vixl::UseScratchRegisterScope temps(this);
   2308  const ARMRegister scratch64 = temps.AcquireX();
   2309 
   2310  loadPtr(src, scratch64.asUnsized());
   2311  Csel(ARMRegister(dest, 64), scratch64, ARMRegister(dest, 64), cond);
   2312  bind(&done);
   2313 }
   2314 
   2315 void MacroAssembler::test32LoadPtr(Condition cond, const Address& addr,
   2316                                   Imm32 mask, const Address& src,
   2317                                   Register dest) {
   2318  MOZ_ASSERT(cond == Assembler::Zero || cond == Assembler::NonZero);
   2319 
   2320  Label done;
   2321  branchTest32(Assembler::InvertCondition(cond), addr, mask, &done);
   2322 
   2323  // ARM64 does not support conditional loads, so we use a branch with a CSel
   2324  // (to prevent Spectre attacks).
   2325  vixl::UseScratchRegisterScope temps(this);
   2326  const ARMRegister scratch64 = temps.AcquireX();
   2327 
   2328  loadPtr(src, scratch64.asUnsized());
   2329  Csel(ARMRegister(dest, 64), scratch64, ARMRegister(dest, 64), cond);
   2330  bind(&done);
   2331 }
   2332 
   2333 void MacroAssembler::test32MovePtr(Condition cond, Register operand, Imm32 mask,
   2334                                   Register src, Register dest) {
   2335  MOZ_ASSERT(cond == Assembler::Zero || cond == Assembler::NonZero);
   2336  test32(operand, mask);
   2337  Csel(ARMRegister(dest, 64), ARMRegister(src, 64), ARMRegister(dest, 64),
   2338       cond);
   2339 }
   2340 
   2341 void MacroAssembler::test32MovePtr(Condition cond, const Address& addr,
   2342                                   Imm32 mask, Register src, Register dest) {
   2343  MOZ_ASSERT(cond == Assembler::Zero || cond == Assembler::NonZero);
   2344  test32(addr, mask);
   2345  Csel(ARMRegister(dest, 64), ARMRegister(src, 64), ARMRegister(dest, 64),
   2346       cond);
   2347 }
   2348 
   2349 void MacroAssembler::spectreMovePtr(Condition cond, Register src,
   2350                                    Register dest) {
   2351  Csel(ARMRegister(dest, 64), ARMRegister(src, 64), ARMRegister(dest, 64),
   2352       cond);
   2353 }
   2354 
   2355 void MacroAssembler::spectreZeroRegister(Condition cond, Register,
   2356                                         Register dest) {
   2357  Csel(ARMRegister(dest, 64), ARMRegister(dest, 64), vixl::xzr,
   2358       Assembler::InvertCondition(cond));
   2359 }
   2360 
   2361 void MacroAssembler::spectreBoundsCheck32(Register index, Register length,
   2362                                          Register maybeScratch,
   2363                                          Label* failure) {
   2364  MOZ_ASSERT(length != maybeScratch);
   2365  MOZ_ASSERT(index != maybeScratch);
   2366 
   2367  branch32(Assembler::BelowOrEqual, length, index, failure);
   2368 
   2369  if (JitOptions.spectreIndexMasking) {
   2370    Csel(ARMRegister(index, 32), ARMRegister(index, 32), vixl::wzr,
   2371         Assembler::Above);
   2372  }
   2373 }
   2374 
   2375 void MacroAssembler::spectreBoundsCheck32(Register index, const Address& length,
   2376                                          Register maybeScratch,
   2377                                          Label* failure) {
   2378  MOZ_ASSERT(index != length.base);
   2379  MOZ_ASSERT(length.base != maybeScratch);
   2380  MOZ_ASSERT(index != maybeScratch);
   2381 
   2382  branch32(Assembler::BelowOrEqual, length, index, failure);
   2383 
   2384  if (JitOptions.spectreIndexMasking) {
   2385    Csel(ARMRegister(index, 32), ARMRegister(index, 32), vixl::wzr,
   2386         Assembler::Above);
   2387  }
   2388 }
   2389 
   2390 void MacroAssembler::spectreBoundsCheckPtr(Register index, Register length,
   2391                                           Register maybeScratch,
   2392                                           Label* failure) {
   2393  MOZ_ASSERT(length != maybeScratch);
   2394  MOZ_ASSERT(index != maybeScratch);
   2395 
   2396  branchPtr(Assembler::BelowOrEqual, length, index, failure);
   2397 
   2398  if (JitOptions.spectreIndexMasking) {
   2399    Csel(ARMRegister(index, 64), ARMRegister(index, 64), vixl::xzr,
   2400         Assembler::Above);
   2401  }
   2402 }
   2403 
   2404 void MacroAssembler::spectreBoundsCheckPtr(Register index,
   2405                                           const Address& length,
   2406                                           Register maybeScratch,
   2407                                           Label* failure) {
   2408  MOZ_ASSERT(index != length.base);
   2409  MOZ_ASSERT(length.base != maybeScratch);
   2410  MOZ_ASSERT(index != maybeScratch);
   2411 
   2412  branchPtr(Assembler::BelowOrEqual, length, index, failure);
   2413 
   2414  if (JitOptions.spectreIndexMasking) {
   2415    Csel(ARMRegister(index, 64), ARMRegister(index, 64), vixl::xzr,
   2416         Assembler::Above);
   2417  }
   2418 }
   2419 
   2420 // ========================================================================
   2421 // Memory access primitives.
   2422 FaultingCodeOffset MacroAssembler::storeDouble(FloatRegister src,
   2423                                               const Address& dest) {
   2424  return Str(ARMFPRegister(src, 64), toMemOperand(dest));
   2425 }
   2426 FaultingCodeOffset MacroAssembler::storeDouble(FloatRegister src,
   2427                                               const BaseIndex& dest) {
   2428  return doBaseIndex(ARMFPRegister(src, 64), dest, vixl::STR_d);
   2429 }
   2430 
   2431 FaultingCodeOffset MacroAssembler::storeFloat32(FloatRegister src,
   2432                                                const Address& addr) {
   2433  return Str(ARMFPRegister(src, 32), toMemOperand(addr));
   2434 }
   2435 FaultingCodeOffset MacroAssembler::storeFloat32(FloatRegister src,
   2436                                                const BaseIndex& addr) {
   2437  return doBaseIndex(ARMFPRegister(src, 32), addr, vixl::STR_s);
   2438 }
   2439 
   2440 FaultingCodeOffset MacroAssembler::storeFloat16(FloatRegister src,
   2441                                                const Address& dest, Register) {
   2442  return Str(ARMFPRegister(src, 16), toMemOperand(dest));
   2443 }
   2444 FaultingCodeOffset MacroAssembler::storeFloat16(FloatRegister src,
   2445                                                const BaseIndex& dest,
   2446                                                Register) {
   2447  return doBaseIndex(ARMFPRegister(src, 16), dest, vixl::STR_h);
   2448 }
   2449 
   2450 void MacroAssembler::memoryBarrier(MemoryBarrier barrier) {
   2451  // Bug 1715494: Discriminating barriers such as StoreStore are hard to reason
   2452  // about.  Execute the full barrier for everything that requires a barrier.
   2453  if (!barrier.isNone()) {
   2454    Dmb(vixl::InnerShareable, vixl::BarrierAll);
   2455  }
   2456 }
   2457 
   2458 // ===============================================================
   2459 // Clamping functions.
   2460 
   2461 void MacroAssembler::clampIntToUint8(Register reg) {
   2462  vixl::UseScratchRegisterScope temps(this);
   2463  const ARMRegister scratch32 = temps.AcquireW();
   2464  const ARMRegister reg32(reg, 32);
   2465  MOZ_ASSERT(!scratch32.Is(reg32));
   2466 
   2467  Cmp(reg32, Operand(reg32, vixl::UXTB));
   2468  Csel(reg32, reg32, vixl::wzr, Assembler::GreaterThanOrEqual);
   2469  Mov(scratch32, Operand(0xff));
   2470  Csel(reg32, reg32, scratch32, Assembler::LessThanOrEqual);
   2471 }
   2472 
   2473 void MacroAssembler::fallibleUnboxPtr(const ValueOperand& src, Register dest,
   2474                                      JSValueType type, Label* fail) {
   2475  MOZ_ASSERT(type == JSVAL_TYPE_OBJECT || type == JSVAL_TYPE_STRING ||
   2476             type == JSVAL_TYPE_SYMBOL || type == JSVAL_TYPE_BIGINT);
   2477  // dest := src XOR mask
   2478  // fail if dest >> JSVAL_TAG_SHIFT != 0
   2479  const ARMRegister src64(src.valueReg(), 64);
   2480  const ARMRegister dest64(dest, 64);
   2481  Eor(dest64, src64, Operand(JSVAL_TYPE_TO_SHIFTED_TAG(type)));
   2482  Cmp(vixl::xzr, Operand(dest64, vixl::LSR, JSVAL_TAG_SHIFT));
   2483  j(Assembler::NotEqual, fail);
   2484 }
   2485 
   2486 void MacroAssembler::fallibleUnboxPtr(const Address& src, Register dest,
   2487                                      JSValueType type, Label* fail) {
   2488  loadValue(src, ValueOperand(dest));
   2489  fallibleUnboxPtr(ValueOperand(dest), dest, type, fail);
   2490 }
   2491 
   2492 void MacroAssembler::fallibleUnboxPtr(const BaseIndex& src, Register dest,
   2493                                      JSValueType type, Label* fail) {
   2494  loadValue(src, ValueOperand(dest));
   2495  fallibleUnboxPtr(ValueOperand(dest), dest, type, fail);
   2496 }
   2497 
   2498 //}}} check_macroassembler_style
   2499 
   2500 // Wasm SIMD
   2501 
   2502 static inline ARMFPRegister SimdReg(FloatRegister r) {
   2503  MOZ_ASSERT(r.isSimd128());
   2504  return ARMFPRegister(r, 128);
   2505 }
   2506 
   2507 static inline ARMFPRegister Simd16B(FloatRegister r) {
   2508  return SimdReg(r).V16B();
   2509 }
   2510 
   2511 static inline ARMFPRegister Simd8B(FloatRegister r) { return SimdReg(r).V8B(); }
   2512 
   2513 static inline ARMFPRegister Simd8H(FloatRegister r) { return SimdReg(r).V8H(); }
   2514 
   2515 static inline ARMFPRegister Simd4H(FloatRegister r) { return SimdReg(r).V4H(); }
   2516 
   2517 static inline ARMFPRegister Simd4S(FloatRegister r) { return SimdReg(r).V4S(); }
   2518 
   2519 static inline ARMFPRegister Simd2S(FloatRegister r) { return SimdReg(r).V2S(); }
   2520 
   2521 static inline ARMFPRegister Simd2D(FloatRegister r) { return SimdReg(r).V2D(); }
   2522 
   2523 static inline ARMFPRegister Simd1D(FloatRegister r) { return SimdReg(r).V1D(); }
   2524 
   2525 static inline ARMFPRegister SimdQ(FloatRegister r) { return SimdReg(r).Q(); }
   2526 
   2527 //{{{ check_macroassembler_style
   2528 
   2529 // Moves
   2530 
   2531 void MacroAssembler::moveSimd128(FloatRegister src, FloatRegister dest) {
   2532  if (src != dest) {
   2533    Mov(SimdReg(dest), SimdReg(src));
   2534  }
   2535 }
   2536 
   2537 void MacroAssembler::loadConstantSimd128(const SimdConstant& v,
   2538                                         FloatRegister dest) {
   2539  // Movi does not yet generate good code for many cases, bug 1664397.
   2540  SimdConstant c = SimdConstant::CreateX2((const int64_t*)v.bytes());
   2541  Movi(SimdReg(dest), c.asInt64x2()[1], c.asInt64x2()[0]);
   2542 }
   2543 
   2544 // Splat
   2545 
   2546 void MacroAssembler::splatX16(Register src, FloatRegister dest) {
   2547  Dup(Simd16B(dest), ARMRegister(src, 32));
   2548 }
   2549 
   2550 void MacroAssembler::splatX16(uint32_t srcLane, FloatRegister src,
   2551                              FloatRegister dest) {
   2552  Dup(Simd16B(dest), Simd16B(src), srcLane);
   2553 }
   2554 
   2555 void MacroAssembler::splatX8(Register src, FloatRegister dest) {
   2556  Dup(Simd8H(dest), ARMRegister(src, 32));
   2557 }
   2558 
   2559 void MacroAssembler::splatX8(uint32_t srcLane, FloatRegister src,
   2560                             FloatRegister dest) {
   2561  Dup(Simd8H(dest), Simd8H(src), srcLane);
   2562 }
   2563 
   2564 void MacroAssembler::splatX4(Register src, FloatRegister dest) {
   2565  Dup(Simd4S(dest), ARMRegister(src, 32));
   2566 }
   2567 
   2568 void MacroAssembler::splatX4(FloatRegister src, FloatRegister dest) {
   2569  Dup(Simd4S(dest), ARMFPRegister(src), 0);
   2570 }
   2571 
   2572 void MacroAssembler::splatX2(Register64 src, FloatRegister dest) {
   2573  Dup(Simd2D(dest), ARMRegister(src.reg, 64));
   2574 }
   2575 
   2576 void MacroAssembler::splatX2(FloatRegister src, FloatRegister dest) {
   2577  Dup(Simd2D(dest), ARMFPRegister(src), 0);
   2578 }
   2579 
   2580 // Extract lane as scalar.  Float extraction does not canonicalize the value.
   2581 
   2582 void MacroAssembler::extractLaneInt8x16(uint32_t lane, FloatRegister src,
   2583                                        Register dest_) {
   2584  MOZ_ASSERT(lane < 16);
   2585  ARMRegister dest(dest_, 32);
   2586  Umov(dest, Simd4S(src), lane / 4);
   2587  Sbfx(dest, dest, (lane % 4) * 8, 8);
   2588 }
   2589 
   2590 void MacroAssembler::unsignedExtractLaneInt8x16(uint32_t lane,
   2591                                                FloatRegister src,
   2592                                                Register dest_) {
   2593  MOZ_ASSERT(lane < 16);
   2594  ARMRegister dest(dest_, 32);
   2595  Umov(dest, Simd4S(src), lane / 4);
   2596  Ubfx(dest, dest, (lane % 4) * 8, 8);
   2597 }
   2598 
   2599 void MacroAssembler::extractLaneInt16x8(uint32_t lane, FloatRegister src,
   2600                                        Register dest_) {
   2601  MOZ_ASSERT(lane < 8);
   2602  ARMRegister dest(dest_, 32);
   2603  Umov(dest, Simd4S(src), lane / 2);
   2604  Sbfx(dest, dest, (lane % 2) * 16, 16);
   2605 }
   2606 
   2607 void MacroAssembler::unsignedExtractLaneInt16x8(uint32_t lane,
   2608                                                FloatRegister src,
   2609                                                Register dest_) {
   2610  MOZ_ASSERT(lane < 8);
   2611  ARMRegister dest(dest_, 32);
   2612  Umov(dest, Simd4S(src), lane / 2);
   2613  Ubfx(dest, dest, (lane % 2) * 16, 16);
   2614 }
   2615 
   2616 void MacroAssembler::extractLaneInt32x4(uint32_t lane, FloatRegister src,
   2617                                        Register dest_) {
   2618  MOZ_ASSERT(lane < 4);
   2619  ARMRegister dest(dest_, 32);
   2620  Umov(dest, Simd4S(src), lane);
   2621 }
   2622 
   2623 void MacroAssembler::extractLaneInt64x2(uint32_t lane, FloatRegister src,
   2624                                        Register64 dest_) {
   2625  MOZ_ASSERT(lane < 2);
   2626  ARMRegister dest(dest_.reg, 64);
   2627  Umov(dest, Simd2D(src), lane);
   2628 }
   2629 
   2630 void MacroAssembler::extractLaneFloat32x4(uint32_t lane, FloatRegister src,
   2631                                          FloatRegister dest) {
   2632  MOZ_ASSERT(lane < 4);
   2633  Mov(ARMFPRegister(dest).V4S(), 0, Simd4S(src), lane);
   2634 }
   2635 
   2636 void MacroAssembler::extractLaneFloat64x2(uint32_t lane, FloatRegister src,
   2637                                          FloatRegister dest) {
   2638  MOZ_ASSERT(lane < 2);
   2639  Mov(ARMFPRegister(dest).V2D(), 0, Simd2D(src), lane);
   2640 }
   2641 
   2642 // Replace lane value
   2643 
   2644 void MacroAssembler::replaceLaneInt8x16(unsigned lane, Register rhs,
   2645                                        FloatRegister lhsDest) {
   2646  MOZ_ASSERT(lane < 16);
   2647  Mov(Simd16B(lhsDest), lane, ARMRegister(rhs, 32));
   2648 }
   2649 
   2650 void MacroAssembler::replaceLaneInt16x8(unsigned lane, Register rhs,
   2651                                        FloatRegister lhsDest) {
   2652  MOZ_ASSERT(lane < 8);
   2653  Mov(Simd8H(lhsDest), lane, ARMRegister(rhs, 32));
   2654 }
   2655 
   2656 void MacroAssembler::replaceLaneInt32x4(unsigned lane, Register rhs,
   2657                                        FloatRegister lhsDest) {
   2658  MOZ_ASSERT(lane < 4);
   2659  Mov(Simd4S(lhsDest), lane, ARMRegister(rhs, 32));
   2660 }
   2661 
   2662 void MacroAssembler::replaceLaneInt64x2(unsigned lane, Register64 rhs,
   2663                                        FloatRegister lhsDest) {
   2664  MOZ_ASSERT(lane < 2);
   2665  Mov(Simd2D(lhsDest), lane, ARMRegister(rhs.reg, 64));
   2666 }
   2667 
   2668 void MacroAssembler::replaceLaneFloat32x4(unsigned lane, FloatRegister rhs,
   2669                                          FloatRegister lhsDest) {
   2670  MOZ_ASSERT(lane < 4);
   2671  Mov(Simd4S(lhsDest), lane, ARMFPRegister(rhs).V4S(), 0);
   2672 }
   2673 
   2674 void MacroAssembler::replaceLaneFloat64x2(unsigned lane, FloatRegister rhs,
   2675                                          FloatRegister lhsDest) {
   2676  MOZ_ASSERT(lane < 2);
   2677  Mov(Simd2D(lhsDest), lane, ARMFPRegister(rhs).V2D(), 0);
   2678 }
   2679 
   2680 // Shuffle - blend and permute with immediate indices, and its many
   2681 // specializations.  Lane values other than those mentioned are illegal.
   2682 
   2683 // lane values 0..31
   2684 void MacroAssembler::shuffleInt8x16(const uint8_t lanes[16], FloatRegister lhs,
   2685                                    FloatRegister rhs, FloatRegister dest) {
   2686  // The general solution generates ho-hum code.  Realistic programs will use
   2687  // patterns that can be specialized, and this will be much better.  That will
   2688  // be handled by bug 1656834, so don't worry about it here.
   2689 
   2690  // Set scratch to the lanevalue when it selects from lhs or ~lanevalue when it
   2691  // selects from rhs.
   2692  ScratchSimd128Scope scratch(*this);
   2693  int8_t idx[16];
   2694 
   2695  if (lhs == rhs) {
   2696    for (unsigned i = 0; i < 16; i++) {
   2697      idx[i] = lanes[i] < 16 ? lanes[i] : (lanes[i] - 16);
   2698    }
   2699    loadConstantSimd128(SimdConstant::CreateX16(idx), scratch);
   2700    Tbl(Simd16B(dest), Simd16B(lhs), Simd16B(scratch));
   2701    return;
   2702  }
   2703 
   2704  if (rhs != dest) {
   2705    for (unsigned i = 0; i < 16; i++) {
   2706      idx[i] = lanes[i] < 16 ? lanes[i] : ~(lanes[i] - 16);
   2707    }
   2708  } else {
   2709    MOZ_ASSERT(lhs != dest);
   2710    for (unsigned i = 0; i < 16; i++) {
   2711      idx[i] = lanes[i] < 16 ? ~lanes[i] : (lanes[i] - 16);
   2712    }
   2713    std::swap(lhs, rhs);
   2714  }
   2715  loadConstantSimd128(SimdConstant::CreateX16(idx), scratch);
   2716  Tbl(Simd16B(dest), Simd16B(lhs), Simd16B(scratch));
   2717  Not(Simd16B(scratch), Simd16B(scratch));
   2718  Tbx(Simd16B(dest), Simd16B(rhs), Simd16B(scratch));
   2719 }
   2720 
   2721 void MacroAssembler::shuffleInt8x16(const uint8_t lanes[16], FloatRegister rhs,
   2722                                    FloatRegister lhsDest) {
   2723  shuffleInt8x16(lanes, lhsDest, rhs, lhsDest);
   2724 }
   2725 
   2726 void MacroAssembler::blendInt8x16(const uint8_t lanes[16], FloatRegister lhs,
   2727                                  FloatRegister rhs, FloatRegister dest) {
   2728  ScratchSimd128Scope scratch(*this);
   2729  int8_t lanes_[16];
   2730 
   2731  if (rhs == dest) {
   2732    for (unsigned i = 0; i < 16; i++) {
   2733      lanes_[i] = lanes[i] == 0 ? i : 16 + i;
   2734    }
   2735    loadConstantSimd128(SimdConstant::CreateX16(lanes_), scratch);
   2736    Tbx(Simd16B(dest), Simd16B(lhs), Simd16B(scratch));
   2737    return;
   2738  }
   2739 
   2740  moveSimd128(lhs, dest);
   2741  for (unsigned i = 0; i < 16; i++) {
   2742    lanes_[i] = lanes[i] != 0 ? i : 16 + i;
   2743  }
   2744  loadConstantSimd128(SimdConstant::CreateX16(lanes_), scratch);
   2745  Tbx(Simd16B(dest), Simd16B(rhs), Simd16B(scratch));
   2746 }
   2747 
   2748 void MacroAssembler::blendInt16x8(const uint16_t lanes[8], FloatRegister lhs,
   2749                                  FloatRegister rhs, FloatRegister dest) {
   2750  static_assert(sizeof(const uint16_t /*lanes*/[8]) == sizeof(uint8_t[16]));
   2751  blendInt8x16(reinterpret_cast<const uint8_t*>(lanes), lhs, rhs, dest);
   2752 }
   2753 
   2754 void MacroAssembler::laneSelectSimd128(FloatRegister mask, FloatRegister lhs,
   2755                                       FloatRegister rhs, FloatRegister dest) {
   2756  MOZ_ASSERT(mask == dest);
   2757  Bsl(Simd16B(mask), Simd16B(lhs), Simd16B(rhs));
   2758 }
   2759 
   2760 void MacroAssembler::interleaveHighInt16x8(FloatRegister lhs, FloatRegister rhs,
   2761                                           FloatRegister dest) {
   2762  Zip2(Simd8H(dest), Simd8H(lhs), Simd8H(rhs));
   2763 }
   2764 
   2765 void MacroAssembler::interleaveHighInt32x4(FloatRegister lhs, FloatRegister rhs,
   2766                                           FloatRegister dest) {
   2767  Zip2(Simd4S(dest), Simd4S(lhs), Simd4S(rhs));
   2768 }
   2769 
   2770 void MacroAssembler::interleaveHighInt64x2(FloatRegister lhs, FloatRegister rhs,
   2771                                           FloatRegister dest) {
   2772  Zip2(Simd2D(dest), Simd2D(lhs), Simd2D(rhs));
   2773 }
   2774 
   2775 void MacroAssembler::interleaveHighInt8x16(FloatRegister lhs, FloatRegister rhs,
   2776                                           FloatRegister dest) {
   2777  Zip2(Simd16B(dest), Simd16B(lhs), Simd16B(rhs));
   2778 }
   2779 
   2780 void MacroAssembler::interleaveLowInt16x8(FloatRegister lhs, FloatRegister rhs,
   2781                                          FloatRegister dest) {
   2782  Zip1(Simd8H(dest), Simd8H(lhs), Simd8H(rhs));
   2783 }
   2784 
   2785 void MacroAssembler::interleaveLowInt32x4(FloatRegister lhs, FloatRegister rhs,
   2786                                          FloatRegister dest) {
   2787  Zip1(Simd4S(dest), Simd4S(lhs), Simd4S(rhs));
   2788 }
   2789 
   2790 void MacroAssembler::interleaveLowInt64x2(FloatRegister lhs, FloatRegister rhs,
   2791                                          FloatRegister dest) {
   2792  Zip1(Simd2D(dest), Simd2D(lhs), Simd2D(rhs));
   2793 }
   2794 
   2795 void MacroAssembler::interleaveLowInt8x16(FloatRegister lhs, FloatRegister rhs,
   2796                                          FloatRegister dest) {
   2797  Zip1(Simd16B(dest), Simd16B(lhs), Simd16B(rhs));
   2798 }
   2799 
   2800 void MacroAssembler::permuteInt8x16(const uint8_t lanes[16], FloatRegister src,
   2801                                    FloatRegister dest) {
   2802  ScratchSimd128Scope scratch(*this);
   2803  loadConstantSimd128(SimdConstant::CreateX16((const int8_t*)lanes), scratch);
   2804  Tbl(Simd16B(dest), Simd16B(src), Simd16B(scratch));
   2805 }
   2806 
   2807 void MacroAssembler::permuteInt16x8(const uint16_t lanes[8], FloatRegister src,
   2808                                    FloatRegister dest) {
   2809  MOZ_ASSERT(lanes[0] < 8 && lanes[1] < 8 && lanes[2] < 8 && lanes[3] < 8 &&
   2810             lanes[4] < 8 && lanes[5] < 8 && lanes[6] < 8 && lanes[7] < 8);
   2811  const int8_t lanes_[16] = {
   2812      (int8_t)(lanes[0] << 1), (int8_t)((lanes[0] << 1) + 1),
   2813      (int8_t)(lanes[1] << 1), (int8_t)((lanes[1] << 1) + 1),
   2814      (int8_t)(lanes[2] << 1), (int8_t)((lanes[2] << 1) + 1),
   2815      (int8_t)(lanes[3] << 1), (int8_t)((lanes[3] << 1) + 1),
   2816      (int8_t)(lanes[4] << 1), (int8_t)((lanes[4] << 1) + 1),
   2817      (int8_t)(lanes[5] << 1), (int8_t)((lanes[5] << 1) + 1),
   2818      (int8_t)(lanes[6] << 1), (int8_t)((lanes[6] << 1) + 1),
   2819      (int8_t)(lanes[7] << 1), (int8_t)((lanes[7] << 1) + 1),
   2820  };
   2821  ScratchSimd128Scope scratch(*this);
   2822  loadConstantSimd128(SimdConstant::CreateX16(lanes_), scratch);
   2823  Tbl(Simd16B(dest), Simd16B(src), Simd16B(scratch));
   2824 }
   2825 
   2826 void MacroAssembler::permuteInt32x4(const uint32_t lanes[4], FloatRegister src,
   2827                                    FloatRegister dest) {
   2828  ScratchSimd128Scope scratch(*this);
   2829  const int8_t lanes_[16] = {
   2830      (int8_t)(lanes[0] << 2),       (int8_t)((lanes[0] << 2) + 1),
   2831      (int8_t)((lanes[0] << 2) + 2), (int8_t)((lanes[0] << 2) + 3),
   2832      (int8_t)(lanes[1] << 2),       (int8_t)((lanes[1] << 2) + 1),
   2833      (int8_t)((lanes[1] << 2) + 2), (int8_t)((lanes[1] << 2) + 3),
   2834      (int8_t)(lanes[2] << 2),       (int8_t)((lanes[2] << 2) + 1),
   2835      (int8_t)((lanes[2] << 2) + 2), (int8_t)((lanes[2] << 2) + 3),
   2836      (int8_t)(lanes[3] << 2),       (int8_t)((lanes[3] << 2) + 1),
   2837      (int8_t)((lanes[3] << 2) + 2), (int8_t)((lanes[3] << 2) + 3),
   2838  };
   2839  loadConstantSimd128(SimdConstant::CreateX16(lanes_), scratch);
   2840  Tbl(Simd16B(dest), Simd16B(src), Simd16B(scratch));
   2841 }
   2842 
   2843 void MacroAssembler::rotateRightSimd128(FloatRegister src, FloatRegister dest,
   2844                                        uint32_t shift) {
   2845  Ext(Simd16B(dest), Simd16B(src), Simd16B(src), shift);
   2846 }
   2847 
   2848 void MacroAssembler::leftShiftSimd128(Imm32 count, FloatRegister src,
   2849                                      FloatRegister dest) {
   2850  MOZ_ASSERT(count.value < 16);
   2851  ScratchSimd128Scope scratch(*this);
   2852  Movi(Simd16B(scratch), 0);
   2853  Ext(Simd16B(dest), Simd16B(scratch), Simd16B(src), 16 - count.value);
   2854 }
   2855 
   2856 void MacroAssembler::rightShiftSimd128(Imm32 count, FloatRegister src,
   2857                                       FloatRegister dest) {
   2858  MOZ_ASSERT(count.value < 16);
   2859  ScratchSimd128Scope scratch(*this);
   2860  Movi(Simd16B(scratch), 0);
   2861  Ext(Simd16B(dest), Simd16B(src), Simd16B(scratch), count.value);
   2862 }
   2863 
   2864 void MacroAssembler::concatAndRightShiftSimd128(FloatRegister lhs,
   2865                                                FloatRegister rhs,
   2866                                                FloatRegister dest,
   2867                                                uint32_t shift) {
   2868  MOZ_ASSERT(shift < 16);
   2869  Ext(Simd16B(dest), Simd16B(rhs), Simd16B(lhs), shift);
   2870 }
   2871 
   2872 // Zero extend int values.
   2873 
   2874 void MacroAssembler::zeroExtend8x16To16x8(FloatRegister src,
   2875                                          FloatRegister dest) {
   2876  Ushll(Simd8H(dest), Simd8B(src), 0);
   2877 }
   2878 
   2879 void MacroAssembler::zeroExtend8x16To32x4(FloatRegister src,
   2880                                          FloatRegister dest) {
   2881  Ushll(Simd8H(dest), Simd8B(src), 0);
   2882  Ushll(Simd4S(dest), Simd4H(dest), 0);
   2883 }
   2884 
   2885 void MacroAssembler::zeroExtend8x16To64x2(FloatRegister src,
   2886                                          FloatRegister dest) {
   2887  Ushll(Simd8H(dest), Simd8B(src), 0);
   2888  Ushll(Simd4S(dest), Simd4H(dest), 0);
   2889  Ushll(Simd2D(dest), Simd2S(dest), 0);
   2890 }
   2891 
   2892 void MacroAssembler::zeroExtend16x8To32x4(FloatRegister src,
   2893                                          FloatRegister dest) {
   2894  Ushll(Simd4S(dest), Simd4H(src), 0);
   2895 }
   2896 
   2897 void MacroAssembler::zeroExtend16x8To64x2(FloatRegister src,
   2898                                          FloatRegister dest) {
   2899  Ushll(Simd4S(dest), Simd4H(src), 0);
   2900  Ushll(Simd2D(dest), Simd2S(dest), 0);
   2901 }
   2902 
   2903 void MacroAssembler::zeroExtend32x4To64x2(FloatRegister src,
   2904                                          FloatRegister dest) {
   2905  Ushll(Simd2D(dest), Simd2S(src), 0);
   2906 }
   2907 
   2908 // Reverse bytes in lanes.
   2909 
   2910 void MacroAssembler::reverseInt16x8(FloatRegister src, FloatRegister dest) {
   2911  Rev16(Simd16B(dest), Simd16B(src));
   2912 }
   2913 
   2914 void MacroAssembler::reverseInt32x4(FloatRegister src, FloatRegister dest) {
   2915  Rev32(Simd16B(dest), Simd16B(src));
   2916 }
   2917 
   2918 void MacroAssembler::reverseInt64x2(FloatRegister src, FloatRegister dest) {
   2919  Rev64(Simd16B(dest), Simd16B(src));
   2920 }
   2921 
   2922 // Swizzle - permute with variable indices.  `rhs` holds the lanes parameter.
   2923 
   2924 void MacroAssembler::swizzleInt8x16(FloatRegister lhs, FloatRegister rhs,
   2925                                    FloatRegister dest) {
   2926  Tbl(Simd16B(dest), Simd16B(lhs), Simd16B(rhs));
   2927 }
   2928 
   2929 void MacroAssembler::swizzleInt8x16Relaxed(FloatRegister lhs, FloatRegister rhs,
   2930                                           FloatRegister dest) {
   2931  Tbl(Simd16B(dest), Simd16B(lhs), Simd16B(rhs));
   2932 }
   2933 
   2934 // Integer Add
   2935 
   2936 void MacroAssembler::addInt8x16(FloatRegister lhs, FloatRegister rhs,
   2937                                FloatRegister dest) {
   2938  Add(Simd16B(dest), Simd16B(lhs), Simd16B(rhs));
   2939 }
   2940 
   2941 void MacroAssembler::addInt16x8(FloatRegister lhs, FloatRegister rhs,
   2942                                FloatRegister dest) {
   2943  Add(Simd8H(dest), Simd8H(lhs), Simd8H(rhs));
   2944 }
   2945 
   2946 void MacroAssembler::addInt32x4(FloatRegister lhs, FloatRegister rhs,
   2947                                FloatRegister dest) {
   2948  Add(Simd4S(dest), Simd4S(lhs), Simd4S(rhs));
   2949 }
   2950 
   2951 void MacroAssembler::addInt64x2(FloatRegister lhs, FloatRegister rhs,
   2952                                FloatRegister dest) {
   2953  Add(Simd2D(dest), Simd2D(lhs), Simd2D(rhs));
   2954 }
   2955 
   2956 // Integer Subtract
   2957 
   2958 void MacroAssembler::subInt8x16(FloatRegister lhs, FloatRegister rhs,
   2959                                FloatRegister dest) {
   2960  Sub(Simd16B(dest), Simd16B(lhs), Simd16B(rhs));
   2961 }
   2962 
   2963 void MacroAssembler::subInt16x8(FloatRegister lhs, FloatRegister rhs,
   2964                                FloatRegister dest) {
   2965  Sub(Simd8H(dest), Simd8H(lhs), Simd8H(rhs));
   2966 }
   2967 
   2968 void MacroAssembler::subInt32x4(FloatRegister lhs, FloatRegister rhs,
   2969                                FloatRegister dest) {
   2970  Sub(Simd4S(dest), Simd4S(lhs), Simd4S(rhs));
   2971 }
   2972 
   2973 void MacroAssembler::subInt64x2(FloatRegister lhs, FloatRegister rhs,
   2974                                FloatRegister dest) {
   2975  Sub(Simd2D(dest), Simd2D(lhs), Simd2D(rhs));
   2976 }
   2977 
   2978 // Integer Multiply
   2979 
   2980 void MacroAssembler::mulInt16x8(FloatRegister lhs, FloatRegister rhs,
   2981                                FloatRegister dest) {
   2982  Mul(Simd8H(dest), Simd8H(lhs), Simd8H(rhs));
   2983 }
   2984 
   2985 void MacroAssembler::mulInt32x4(FloatRegister lhs, FloatRegister rhs,
   2986                                FloatRegister dest) {
   2987  Mul(Simd4S(dest), Simd4S(lhs), Simd4S(rhs));
   2988 }
   2989 
   2990 void MacroAssembler::mulInt64x2(FloatRegister lhs, FloatRegister rhs,
   2991                                FloatRegister dest, FloatRegister temp1,
   2992                                FloatRegister temp2) {
   2993  // As documented at https://chromium-review.googlesource.com/c/v8/v8/+/1781696
   2994  // lhs = <D C> <B A>
   2995  // rhs = <H G> <F E>
   2996  // result = <(DG+CH)_low+CG_high CG_low> <(BE+AF)_low+AE_high AE_low>
   2997  ScratchSimd128Scope scratch(*this);
   2998  Rev64(Simd4S(temp2), Simd4S(lhs));                  // temp2 = <C D> <A B>
   2999  Mul(Simd4S(temp2), Simd4S(temp2), Simd4S(rhs));     // temp2 = <CH DG> <AF BE>
   3000  Xtn(Simd2S(temp1), Simd2D(rhs));                    // temp1 = <0 0> <G E>
   3001  Addp(Simd4S(temp2), Simd4S(temp2), Simd4S(temp2));  // temp2 = <CH+DG AF+BE>..
   3002  Xtn(Simd2S(scratch), Simd2D(lhs));                  // scratch = <0 0> <C A>
   3003  Shll(Simd2D(dest), Simd2S(temp2), 32);              // dest = <(DG+CH)_low 0>
   3004                                                      //        <(BE+AF)_low 0>
   3005  Umlal(Simd2D(dest), Simd2S(scratch), Simd2S(temp1));
   3006 }
   3007 
   3008 void MacroAssembler::extMulLowInt8x16(FloatRegister lhs, FloatRegister rhs,
   3009                                      FloatRegister dest) {
   3010  Smull(Simd8H(dest), Simd8B(lhs), Simd8B(rhs));
   3011 }
   3012 
   3013 void MacroAssembler::extMulHighInt8x16(FloatRegister lhs, FloatRegister rhs,
   3014                                       FloatRegister dest) {
   3015  Smull2(Simd8H(dest), Simd16B(lhs), Simd16B(rhs));
   3016 }
   3017 
   3018 void MacroAssembler::unsignedExtMulLowInt8x16(FloatRegister lhs,
   3019                                              FloatRegister rhs,
   3020                                              FloatRegister dest) {
   3021  Umull(Simd8H(dest), Simd8B(lhs), Simd8B(rhs));
   3022 }
   3023 
   3024 void MacroAssembler::unsignedExtMulHighInt8x16(FloatRegister lhs,
   3025                                               FloatRegister rhs,
   3026                                               FloatRegister dest) {
   3027  Umull2(Simd8H(dest), Simd16B(lhs), Simd16B(rhs));
   3028 }
   3029 
   3030 void MacroAssembler::extMulLowInt16x8(FloatRegister lhs, FloatRegister rhs,
   3031                                      FloatRegister dest) {
   3032  Smull(Simd4S(dest), Simd4H(lhs), Simd4H(rhs));
   3033 }
   3034 
   3035 void MacroAssembler::extMulHighInt16x8(FloatRegister lhs, FloatRegister rhs,
   3036                                       FloatRegister dest) {
   3037  Smull2(Simd4S(dest), Simd8H(lhs), Simd8H(rhs));
   3038 }
   3039 
   3040 void MacroAssembler::unsignedExtMulLowInt16x8(FloatRegister lhs,
   3041                                              FloatRegister rhs,
   3042                                              FloatRegister dest) {
   3043  Umull(Simd4S(dest), Simd4H(lhs), Simd4H(rhs));
   3044 }
   3045 
   3046 void MacroAssembler::unsignedExtMulHighInt16x8(FloatRegister lhs,
   3047                                               FloatRegister rhs,
   3048                                               FloatRegister dest) {
   3049  Umull2(Simd4S(dest), Simd8H(lhs), Simd8H(rhs));
   3050 }
   3051 
   3052 void MacroAssembler::extMulLowInt32x4(FloatRegister lhs, FloatRegister rhs,
   3053                                      FloatRegister dest) {
   3054  Smull(Simd2D(dest), Simd2S(lhs), Simd2S(rhs));
   3055 }
   3056 
   3057 void MacroAssembler::extMulHighInt32x4(FloatRegister lhs, FloatRegister rhs,
   3058                                       FloatRegister dest) {
   3059  Smull2(Simd2D(dest), Simd4S(lhs), Simd4S(rhs));
   3060 }
   3061 
   3062 void MacroAssembler::unsignedExtMulLowInt32x4(FloatRegister lhs,
   3063                                              FloatRegister rhs,
   3064                                              FloatRegister dest) {
   3065  Umull(Simd2D(dest), Simd2S(lhs), Simd2S(rhs));
   3066 }
   3067 
   3068 void MacroAssembler::unsignedExtMulHighInt32x4(FloatRegister lhs,
   3069                                               FloatRegister rhs,
   3070                                               FloatRegister dest) {
   3071  Umull2(Simd2D(dest), Simd4S(lhs), Simd4S(rhs));
   3072 }
   3073 
   3074 void MacroAssembler::q15MulrSatInt16x8(FloatRegister lhs, FloatRegister rhs,
   3075                                       FloatRegister dest) {
   3076  Sqrdmulh(Simd8H(dest), Simd8H(lhs), Simd8H(rhs));
   3077 }
   3078 
   3079 void MacroAssembler::q15MulrInt16x8Relaxed(FloatRegister lhs, FloatRegister rhs,
   3080                                           FloatRegister dest) {
   3081  Sqrdmulh(Simd8H(dest), Simd8H(lhs), Simd8H(rhs));
   3082 }
   3083 
   3084 // Integer Negate
   3085 
   3086 void MacroAssembler::negInt8x16(FloatRegister src, FloatRegister dest) {
   3087  Neg(Simd16B(dest), Simd16B(src));
   3088 }
   3089 
   3090 void MacroAssembler::negInt16x8(FloatRegister src, FloatRegister dest) {
   3091  Neg(Simd8H(dest), Simd8H(src));
   3092 }
   3093 
   3094 void MacroAssembler::negInt32x4(FloatRegister src, FloatRegister dest) {
   3095  Neg(Simd4S(dest), Simd4S(src));
   3096 }
   3097 
   3098 void MacroAssembler::negInt64x2(FloatRegister src, FloatRegister dest) {
   3099  Neg(Simd2D(dest), Simd2D(src));
   3100 }
   3101 
   3102 // Saturating integer add
   3103 
   3104 void MacroAssembler::addSatInt8x16(FloatRegister lhs, FloatRegister rhs,
   3105                                   FloatRegister dest) {
   3106  Sqadd(Simd16B(dest), Simd16B(lhs), Simd16B(rhs));
   3107 }
   3108 
   3109 void MacroAssembler::unsignedAddSatInt8x16(FloatRegister lhs, FloatRegister rhs,
   3110                                           FloatRegister dest) {
   3111  Uqadd(Simd16B(dest), Simd16B(lhs), Simd16B(rhs));
   3112 }
   3113 
   3114 void MacroAssembler::addSatInt16x8(FloatRegister lhs, FloatRegister rhs,
   3115                                   FloatRegister dest) {
   3116  Sqadd(Simd8H(dest), Simd8H(lhs), Simd8H(rhs));
   3117 }
   3118 
   3119 void MacroAssembler::unsignedAddSatInt16x8(FloatRegister lhs, FloatRegister rhs,
   3120                                           FloatRegister dest) {
   3121  Uqadd(Simd8H(dest), Simd8H(lhs), Simd8H(rhs));
   3122 }
   3123 
   3124 // Saturating integer subtract
   3125 
   3126 void MacroAssembler::subSatInt8x16(FloatRegister lhs, FloatRegister rhs,
   3127                                   FloatRegister dest) {
   3128  Sqsub(Simd16B(dest), Simd16B(lhs), Simd16B(rhs));
   3129 }
   3130 
   3131 void MacroAssembler::unsignedSubSatInt8x16(FloatRegister lhs, FloatRegister rhs,
   3132                                           FloatRegister dest) {
   3133  Uqsub(Simd16B(dest), Simd16B(lhs), Simd16B(rhs));
   3134 }
   3135 
   3136 void MacroAssembler::subSatInt16x8(FloatRegister lhs, FloatRegister rhs,
   3137                                   FloatRegister dest) {
   3138  Sqsub(Simd8H(dest), Simd8H(lhs), Simd8H(rhs));
   3139 }
   3140 
   3141 void MacroAssembler::unsignedSubSatInt16x8(FloatRegister lhs, FloatRegister rhs,
   3142                                           FloatRegister dest) {
   3143  Uqsub(Simd8H(dest), Simd8H(lhs), Simd8H(rhs));
   3144 }
   3145 
   3146 // Lane-wise integer minimum
   3147 
   3148 void MacroAssembler::minInt8x16(FloatRegister lhs, FloatRegister rhs,
   3149                                FloatRegister dest) {
   3150  Smin(Simd16B(dest), Simd16B(lhs), Simd16B(rhs));
   3151 }
   3152 
   3153 void MacroAssembler::unsignedMinInt8x16(FloatRegister lhs, FloatRegister rhs,
   3154                                        FloatRegister dest) {
   3155  Umin(Simd16B(dest), Simd16B(lhs), Simd16B(rhs));
   3156 }
   3157 
   3158 void MacroAssembler::minInt16x8(FloatRegister lhs, FloatRegister rhs,
   3159                                FloatRegister dest) {
   3160  Smin(Simd8H(dest), Simd8H(lhs), Simd8H(rhs));
   3161 }
   3162 
   3163 void MacroAssembler::unsignedMinInt16x8(FloatRegister lhs, FloatRegister rhs,
   3164                                        FloatRegister dest) {
   3165  Umin(Simd8H(dest), Simd8H(lhs), Simd8H(rhs));
   3166 }
   3167 
   3168 void MacroAssembler::minInt32x4(FloatRegister lhs, FloatRegister rhs,
   3169                                FloatRegister dest) {
   3170  Smin(Simd4S(dest), Simd4S(lhs), Simd4S(rhs));
   3171 }
   3172 
   3173 void MacroAssembler::unsignedMinInt32x4(FloatRegister lhs, FloatRegister rhs,
   3174                                        FloatRegister dest) {
   3175  Umin(Simd4S(dest), Simd4S(lhs), Simd4S(rhs));
   3176 }
   3177 
   3178 // Lane-wise integer maximum
   3179 
   3180 void MacroAssembler::maxInt8x16(FloatRegister lhs, FloatRegister rhs,
   3181                                FloatRegister dest) {
   3182  Smax(Simd16B(dest), Simd16B(lhs), Simd16B(rhs));
   3183 }
   3184 
   3185 void MacroAssembler::unsignedMaxInt8x16(FloatRegister lhs, FloatRegister rhs,
   3186                                        FloatRegister dest) {
   3187  Umax(Simd16B(dest), Simd16B(lhs), Simd16B(rhs));
   3188 }
   3189 
   3190 void MacroAssembler::maxInt16x8(FloatRegister lhs, FloatRegister rhs,
   3191                                FloatRegister dest) {
   3192  Smax(Simd8H(dest), Simd8H(lhs), Simd8H(rhs));
   3193 }
   3194 
   3195 void MacroAssembler::unsignedMaxInt16x8(FloatRegister lhs, FloatRegister rhs,
   3196                                        FloatRegister dest) {
   3197  Umax(Simd8H(dest), Simd8H(lhs), Simd8H(rhs));
   3198 }
   3199 
   3200 void MacroAssembler::maxInt32x4(FloatRegister lhs, FloatRegister rhs,
   3201                                FloatRegister dest) {
   3202  Smax(Simd4S(dest), Simd4S(lhs), Simd4S(rhs));
   3203 }
   3204 
   3205 void MacroAssembler::unsignedMaxInt32x4(FloatRegister lhs, FloatRegister rhs,
   3206                                        FloatRegister dest) {
   3207  Umax(Simd4S(dest), Simd4S(lhs), Simd4S(rhs));
   3208 }
   3209 
   3210 // Lane-wise integer rounding average
   3211 
   3212 void MacroAssembler::unsignedAverageInt8x16(FloatRegister lhs,
   3213                                            FloatRegister rhs,
   3214                                            FloatRegister dest) {
   3215  Urhadd(Simd16B(dest), Simd16B(lhs), Simd16B(rhs));
   3216 }
   3217 
   3218 void MacroAssembler::unsignedAverageInt16x8(FloatRegister lhs,
   3219                                            FloatRegister rhs,
   3220                                            FloatRegister dest) {
   3221  Urhadd(Simd8H(dest), Simd8H(lhs), Simd8H(rhs));
   3222 }
   3223 
   3224 // Lane-wise integer absolute value
   3225 
   3226 void MacroAssembler::absInt8x16(FloatRegister src, FloatRegister dest) {
   3227  Abs(Simd16B(dest), Simd16B(src));
   3228 }
   3229 
   3230 void MacroAssembler::absInt16x8(FloatRegister src, FloatRegister dest) {
   3231  Abs(Simd8H(dest), Simd8H(src));
   3232 }
   3233 
   3234 void MacroAssembler::absInt32x4(FloatRegister src, FloatRegister dest) {
   3235  Abs(Simd4S(dest), Simd4S(src));
   3236 }
   3237 
   3238 void MacroAssembler::absInt64x2(FloatRegister src, FloatRegister dest) {
   3239  Abs(Simd2D(dest), Simd2D(src));
   3240 }
   3241 
   3242 // Left shift by variable scalar
   3243 
   3244 void MacroAssembler::leftShiftInt8x16(FloatRegister lhs, Register rhs,
   3245                                      FloatRegister dest) {
   3246  ScratchSimd128Scope vscratch(*this);
   3247  Dup(Simd16B(vscratch), ARMRegister(rhs, 32));
   3248  Sshl(Simd16B(dest), Simd16B(lhs), Simd16B(vscratch));
   3249 }
   3250 
   3251 void MacroAssembler::leftShiftInt8x16(Imm32 count, FloatRegister src,
   3252                                      FloatRegister dest) {
   3253  Shl(Simd16B(dest), Simd16B(src), count.value);
   3254 }
   3255 
   3256 void MacroAssembler::leftShiftInt16x8(FloatRegister lhs, Register rhs,
   3257                                      FloatRegister dest) {
   3258  ScratchSimd128Scope vscratch(*this);
   3259  Dup(Simd8H(vscratch), ARMRegister(rhs, 32));
   3260  Sshl(Simd8H(dest), Simd8H(lhs), Simd8H(vscratch));
   3261 }
   3262 
   3263 void MacroAssembler::leftShiftInt16x8(Imm32 count, FloatRegister src,
   3264                                      FloatRegister dest) {
   3265  Shl(Simd8H(dest), Simd8H(src), count.value);
   3266 }
   3267 
   3268 void MacroAssembler::leftShiftInt32x4(FloatRegister lhs, Register rhs,
   3269                                      FloatRegister dest) {
   3270  ScratchSimd128Scope vscratch(*this);
   3271  Dup(Simd4S(vscratch), ARMRegister(rhs, 32));
   3272  Sshl(Simd4S(dest), Simd4S(lhs), Simd4S(vscratch));
   3273 }
   3274 
   3275 void MacroAssembler::leftShiftInt32x4(Imm32 count, FloatRegister src,
   3276                                      FloatRegister dest) {
   3277  Shl(Simd4S(dest), Simd4S(src), count.value);
   3278 }
   3279 
   3280 void MacroAssembler::leftShiftInt64x2(FloatRegister lhs, Register rhs,
   3281                                      FloatRegister dest) {
   3282  ScratchSimd128Scope vscratch(*this);
   3283  Dup(Simd2D(vscratch), ARMRegister(rhs, 64));
   3284  Sshl(Simd2D(dest), Simd2D(lhs), Simd2D(vscratch));
   3285 }
   3286 
   3287 void MacroAssembler::leftShiftInt64x2(Imm32 count, FloatRegister src,
   3288                                      FloatRegister dest) {
   3289  Shl(Simd2D(dest), Simd2D(src), count.value);
   3290 }
   3291 
   3292 // Right shift by variable scalar
   3293 
   3294 void MacroAssembler::rightShiftInt8x16(FloatRegister lhs, Register rhs,
   3295                                       FloatRegister dest) {
   3296  MacroAssemblerCompat::rightShiftInt8x16(lhs, rhs, dest,
   3297                                          /* isUnsigned */ false);
   3298 }
   3299 
   3300 void MacroAssembler::rightShiftInt8x16(Imm32 count, FloatRegister src,
   3301                                       FloatRegister dest) {
   3302  Sshr(Simd16B(dest), Simd16B(src), count.value);
   3303 }
   3304 
   3305 void MacroAssembler::unsignedRightShiftInt8x16(FloatRegister lhs, Register rhs,
   3306                                               FloatRegister dest) {
   3307  MacroAssemblerCompat::rightShiftInt8x16(lhs, rhs, dest,
   3308                                          /* isUnsigned */ true);
   3309 }
   3310 
   3311 void MacroAssembler::unsignedRightShiftInt8x16(Imm32 count, FloatRegister src,
   3312                                               FloatRegister dest) {
   3313  Ushr(Simd16B(dest), Simd16B(src), count.value);
   3314 }
   3315 
   3316 void MacroAssembler::rightShiftInt16x8(FloatRegister lhs, Register rhs,
   3317                                       FloatRegister dest) {
   3318  MacroAssemblerCompat::rightShiftInt16x8(lhs, rhs, dest,
   3319                                          /* isUnsigned */ false);
   3320 }
   3321 
   3322 void MacroAssembler::rightShiftInt16x8(Imm32 count, FloatRegister src,
   3323                                       FloatRegister dest) {
   3324  Sshr(Simd8H(dest), Simd8H(src), count.value);
   3325 }
   3326 
   3327 void MacroAssembler::unsignedRightShiftInt16x8(FloatRegister lhs, Register rhs,
   3328                                               FloatRegister dest) {
   3329  MacroAssemblerCompat::rightShiftInt16x8(lhs, rhs, dest,
   3330                                          /* isUnsigned */ true);
   3331 }
   3332 
   3333 void MacroAssembler::unsignedRightShiftInt16x8(Imm32 count, FloatRegister src,
   3334                                               FloatRegister dest) {
   3335  Ushr(Simd8H(dest), Simd8H(src), count.value);
   3336 }
   3337 
   3338 void MacroAssembler::rightShiftInt32x4(FloatRegister lhs, Register rhs,
   3339                                       FloatRegister dest) {
   3340  MacroAssemblerCompat::rightShiftInt32x4(lhs, rhs, dest,
   3341                                          /* isUnsigned */ false);
   3342 }
   3343 
   3344 void MacroAssembler::rightShiftInt32x4(Imm32 count, FloatRegister src,
   3345                                       FloatRegister dest) {
   3346  Sshr(Simd4S(dest), Simd4S(src), count.value);
   3347 }
   3348 
   3349 void MacroAssembler::unsignedRightShiftInt32x4(FloatRegister lhs, Register rhs,
   3350                                               FloatRegister dest) {
   3351  MacroAssemblerCompat::rightShiftInt32x4(lhs, rhs, dest,
   3352                                          /* isUnsigned */ true);
   3353 }
   3354 
   3355 void MacroAssembler::unsignedRightShiftInt32x4(Imm32 count, FloatRegister src,
   3356                                               FloatRegister dest) {
   3357  Ushr(Simd4S(dest), Simd4S(src), count.value);
   3358 }
   3359 
   3360 void MacroAssembler::rightShiftInt64x2(FloatRegister lhs, Register rhs,
   3361                                       FloatRegister dest) {
   3362  MacroAssemblerCompat::rightShiftInt64x2(lhs, rhs, dest,
   3363                                          /* isUnsigned */ false);
   3364 }
   3365 
   3366 void MacroAssembler::rightShiftInt64x2(Imm32 count, FloatRegister src,
   3367                                       FloatRegister dest) {
   3368  Sshr(Simd2D(dest), Simd2D(src), count.value);
   3369 }
   3370 
   3371 void MacroAssembler::unsignedRightShiftInt64x2(FloatRegister lhs, Register rhs,
   3372                                               FloatRegister dest) {
   3373  MacroAssemblerCompat::rightShiftInt64x2(lhs, rhs, dest,
   3374                                          /* isUnsigned */ true);
   3375 }
   3376 
   3377 void MacroAssembler::unsignedRightShiftInt64x2(Imm32 count, FloatRegister src,
   3378                                               FloatRegister dest) {
   3379  Ushr(Simd2D(dest), Simd2D(src), count.value);
   3380 }
   3381 
   3382 // Bitwise and, or, xor, not
   3383 
   3384 void MacroAssembler::bitwiseAndSimd128(FloatRegister rhs,
   3385                                       FloatRegister lhsDest) {
   3386  And(Simd16B(lhsDest), Simd16B(lhsDest), Simd16B(rhs));
   3387 }
   3388 
   3389 void MacroAssembler::bitwiseAndSimd128(FloatRegister lhs, FloatRegister rhs,
   3390                                       FloatRegister dest) {
   3391  And(Simd16B(dest), Simd16B(lhs), Simd16B(rhs));
   3392 }
   3393 
   3394 void MacroAssembler::bitwiseOrSimd128(FloatRegister rhs,
   3395                                      FloatRegister lhsDest) {
   3396  Orr(Simd16B(lhsDest), Simd16B(lhsDest), Simd16B(rhs));
   3397 }
   3398 
   3399 void MacroAssembler::bitwiseOrSimd128(FloatRegister lhs, FloatRegister rhs,
   3400                                      FloatRegister dest) {
   3401  Orr(Simd16B(dest), Simd16B(lhs), Simd16B(rhs));
   3402 }
   3403 
   3404 void MacroAssembler::bitwiseXorSimd128(FloatRegister rhs,
   3405                                       FloatRegister lhsDest) {
   3406  Eor(Simd16B(lhsDest), Simd16B(lhsDest), Simd16B(rhs));
   3407 }
   3408 
   3409 void MacroAssembler::bitwiseXorSimd128(FloatRegister lhs, FloatRegister rhs,
   3410                                       FloatRegister dest) {
   3411  Eor(Simd16B(dest), Simd16B(lhs), Simd16B(rhs));
   3412 }
   3413 
   3414 void MacroAssembler::bitwiseNotSimd128(FloatRegister src, FloatRegister dest) {
   3415  Not(Simd16B(dest), Simd16B(src));
   3416 }
   3417 
   3418 void MacroAssembler::bitwiseAndNotSimd128(FloatRegister lhs, FloatRegister rhs,
   3419                                          FloatRegister dest) {
   3420  Bic(Simd16B(dest), Simd16B(lhs), Simd16B(rhs));
   3421 }
   3422 
   3423 // Bitwise AND with complement: dest = ~lhs & rhs, note this is not what Wasm
   3424 // wants but what the x86 hardware offers.  Hence the name.  Since arm64 has
   3425 // dest = lhs & ~rhs we just swap operands.
   3426 
   3427 void MacroAssembler::bitwiseNotAndSimd128(FloatRegister rhs,
   3428                                          FloatRegister lhsDest) {
   3429  Bic(Simd16B(lhsDest), Simd16B(rhs), Simd16B(lhsDest));
   3430 }
   3431 
   3432 // Bitwise select
   3433 
   3434 void MacroAssembler::bitwiseSelectSimd128(FloatRegister onTrue,
   3435                                          FloatRegister onFalse,
   3436                                          FloatRegister maskDest) {
   3437  Bsl(Simd16B(maskDest), Simd16B(onTrue), Simd16B(onFalse));
   3438 }
   3439 
   3440 // Population count
   3441 
   3442 void MacroAssembler::popcntInt8x16(FloatRegister src, FloatRegister dest) {
   3443  Cnt(Simd16B(dest), Simd16B(src));
   3444 }
   3445 
   3446 // Any lane true, ie, any bit set
   3447 
   3448 void MacroAssembler::anyTrueSimd128(FloatRegister src, Register dest_) {
   3449  ScratchSimd128Scope scratch_(*this);
   3450  ARMFPRegister scratch(Simd1D(scratch_));
   3451  ARMRegister dest(dest_, 64);
   3452  Addp(scratch, Simd2D(src));
   3453  Umov(dest, scratch, 0);
   3454  Cmp(dest, Operand(0));
   3455  Cset(dest, Assembler::NonZero);
   3456 }
   3457 
   3458 // All lanes true
   3459 
   3460 void MacroAssembler::allTrueInt8x16(FloatRegister src, Register dest_) {
   3461  ScratchSimd128Scope scratch(*this);
   3462  ARMRegister dest(dest_, 64);
   3463  Cmeq(Simd16B(scratch), Simd16B(src), 0);
   3464  Addp(Simd1D(scratch), Simd2D(scratch));
   3465  Umov(dest, Simd1D(scratch), 0);
   3466  Cmp(dest, Operand(0));
   3467  Cset(dest, Assembler::Zero);
   3468 }
   3469 
   3470 void MacroAssembler::allTrueInt16x8(FloatRegister src, Register dest_) {
   3471  ScratchSimd128Scope scratch(*this);
   3472  ARMRegister dest(dest_, 64);
   3473  Cmeq(Simd8H(scratch), Simd8H(src), 0);
   3474  Addp(Simd1D(scratch), Simd2D(scratch));
   3475  Umov(dest, Simd1D(scratch), 0);
   3476  Cmp(dest, Operand(0));
   3477  Cset(dest, Assembler::Zero);
   3478 }
   3479 
   3480 void MacroAssembler::allTrueInt32x4(FloatRegister src, Register dest_) {
   3481  ScratchSimd128Scope scratch(*this);
   3482  ARMRegister dest(dest_, 64);
   3483  Cmeq(Simd4S(scratch), Simd4S(src), 0);
   3484  Addp(Simd1D(scratch), Simd2D(scratch));
   3485  Umov(dest, Simd1D(scratch), 0);
   3486  Cmp(dest, Operand(0));
   3487  Cset(dest, Assembler::Zero);
   3488 }
   3489 
   3490 void MacroAssembler::allTrueInt64x2(FloatRegister src, Register dest_) {
   3491  ScratchSimd128Scope scratch(*this);
   3492  ARMRegister dest(dest_, 64);
   3493  Cmeq(Simd2D(scratch), Simd2D(src), 0);
   3494  Addp(Simd1D(scratch), Simd2D(scratch));
   3495  Umov(dest, Simd1D(scratch), 0);
   3496  Cmp(dest, Operand(0));
   3497  Cset(dest, Assembler::Zero);
   3498 }
   3499 
   3500 // Bitmask, ie extract and compress high bits of all lanes
   3501 //
   3502 // There's no direct support for this on the chip.  These implementations come
   3503 // from the writeup that added the instruction to the SIMD instruction set.
   3504 // Generally, shifting and masking is used to isolate the sign bit of each
   3505 // element in the right position, then a horizontal add creates the result.  For
   3506 // 8-bit elements an intermediate step is needed to assemble the bits of the
   3507 // upper and lower 8 bytes into 8 halfwords.
   3508 
   3509 void MacroAssembler::bitmaskInt8x16(FloatRegister src, Register dest,
   3510                                    FloatRegister temp) {
   3511  ScratchSimd128Scope scratch(*this);
   3512  int8_t values[] = {1, 2, 4, 8, 16, 32, 64, -128,
   3513                     1, 2, 4, 8, 16, 32, 64, -128};
   3514  loadConstantSimd128(SimdConstant::CreateX16(values), temp);
   3515  Sshr(Simd16B(scratch), Simd16B(src), 7);
   3516  And(Simd16B(scratch), Simd16B(scratch), Simd16B(temp));
   3517  Ext(Simd16B(temp), Simd16B(scratch), Simd16B(scratch), 8);
   3518  Zip1(Simd16B(temp), Simd16B(scratch), Simd16B(temp));
   3519  Addv(ARMFPRegister(temp, 16), Simd8H(temp));
   3520  Mov(ARMRegister(dest, 32), Simd8H(temp), 0);
   3521 }
   3522 
   3523 void MacroAssembler::bitmaskInt16x8(FloatRegister src, Register dest,
   3524                                    FloatRegister temp) {
   3525  ScratchSimd128Scope scratch(*this);
   3526  int16_t values[] = {1, 2, 4, 8, 16, 32, 64, 128};
   3527  loadConstantSimd128(SimdConstant::CreateX8(values), temp);
   3528  Sshr(Simd8H(scratch), Simd8H(src), 15);
   3529  And(Simd16B(scratch), Simd16B(scratch), Simd16B(temp));
   3530  Addv(ARMFPRegister(scratch, 16), Simd8H(scratch));
   3531  Mov(ARMRegister(dest, 32), Simd8H(scratch), 0);
   3532 }
   3533 
   3534 void MacroAssembler::bitmaskInt32x4(FloatRegister src, Register dest,
   3535                                    FloatRegister temp) {
   3536  ScratchSimd128Scope scratch(*this);
   3537  int32_t values[] = {1, 2, 4, 8};
   3538  loadConstantSimd128(SimdConstant::CreateX4(values), temp);
   3539  Sshr(Simd4S(scratch), Simd4S(src), 31);
   3540  And(Simd16B(scratch), Simd16B(scratch), Simd16B(temp));
   3541  Addv(ARMFPRegister(scratch, 32), Simd4S(scratch));
   3542  Mov(ARMRegister(dest, 32), Simd4S(scratch), 0);
   3543 }
   3544 
   3545 void MacroAssembler::bitmaskInt64x2(FloatRegister src, Register dest,
   3546                                    FloatRegister temp) {
   3547  Sqxtn(Simd2S(temp), Simd2D(src));
   3548  Ushr(Simd2S(temp), Simd2S(temp), 31);
   3549  Usra(ARMFPRegister(temp, 64), ARMFPRegister(temp, 64), 31);
   3550  Fmov(ARMRegister(dest, 32), ARMFPRegister(temp, 32));
   3551 }
   3552 
   3553 // Comparisons (integer and floating-point)
   3554 
   3555 void MacroAssembler::compareInt8x16(Assembler::Condition cond,
   3556                                    FloatRegister rhs, FloatRegister lhsDest) {
   3557  compareSimd128Int(cond, Simd16B(lhsDest), Simd16B(lhsDest), Simd16B(rhs));
   3558 }
   3559 
   3560 void MacroAssembler::compareInt8x16(Assembler::Condition cond,
   3561                                    FloatRegister lhs, FloatRegister rhs,
   3562                                    FloatRegister dest) {
   3563  compareSimd128Int(cond, Simd16B(dest), Simd16B(lhs), Simd16B(rhs));
   3564 }
   3565 
   3566 void MacroAssembler::compareInt16x8(Assembler::Condition cond,
   3567                                    FloatRegister rhs, FloatRegister lhsDest) {
   3568  compareSimd128Int(cond, Simd8H(lhsDest), Simd8H(lhsDest), Simd8H(rhs));
   3569 }
   3570 
   3571 void MacroAssembler::compareInt16x8(Assembler::Condition cond,
   3572                                    FloatRegister lhs, FloatRegister rhs,
   3573                                    FloatRegister dest) {
   3574  compareSimd128Int(cond, Simd8H(dest), Simd8H(lhs), Simd8H(rhs));
   3575 }
   3576 
   3577 void MacroAssembler::compareInt32x4(Assembler::Condition cond,
   3578                                    FloatRegister rhs, FloatRegister lhsDest) {
   3579  compareSimd128Int(cond, Simd4S(lhsDest), Simd4S(lhsDest), Simd4S(rhs));
   3580 }
   3581 
   3582 void MacroAssembler::compareInt32x4(Assembler::Condition cond,
   3583                                    FloatRegister lhs, FloatRegister rhs,
   3584                                    FloatRegister dest) {
   3585  compareSimd128Int(cond, Simd4S(dest), Simd4S(lhs), Simd4S(rhs));
   3586 }
   3587 
   3588 void MacroAssembler::compareInt64x2(Assembler::Condition cond,
   3589                                    FloatRegister rhs, FloatRegister lhsDest) {
   3590  compareSimd128Int(cond, Simd2D(lhsDest), Simd2D(lhsDest), Simd2D(rhs));
   3591 }
   3592 
   3593 void MacroAssembler::compareInt64x2(Assembler::Condition cond,
   3594                                    FloatRegister lhs, FloatRegister rhs,
   3595                                    FloatRegister dest) {
   3596  compareSimd128Int(cond, Simd2D(dest), Simd2D(lhs), Simd2D(rhs));
   3597 }
   3598 
   3599 void MacroAssembler::compareFloat32x4(Assembler::Condition cond,
   3600                                      FloatRegister rhs,
   3601                                      FloatRegister lhsDest) {
   3602  compareSimd128Float(cond, Simd4S(lhsDest), Simd4S(lhsDest), Simd4S(rhs));
   3603 }
   3604 
   3605 void MacroAssembler::compareFloat32x4(Assembler::Condition cond,
   3606                                      FloatRegister lhs, FloatRegister rhs,
   3607                                      FloatRegister dest) {
   3608  compareSimd128Float(cond, Simd4S(dest), Simd4S(lhs), Simd4S(rhs));
   3609 }
   3610 
   3611 void MacroAssembler::compareFloat64x2(Assembler::Condition cond,
   3612                                      FloatRegister rhs,
   3613                                      FloatRegister lhsDest) {
   3614  compareSimd128Float(cond, Simd2D(lhsDest), Simd2D(lhsDest), Simd2D(rhs));
   3615 }
   3616 
   3617 void MacroAssembler::compareFloat64x2(Assembler::Condition cond,
   3618                                      FloatRegister lhs, FloatRegister rhs,
   3619                                      FloatRegister dest) {
   3620  compareSimd128Float(cond, Simd2D(dest), Simd2D(lhs), Simd2D(rhs));
   3621 }
   3622 
   3623 // Load
   3624 
   3625 FaultingCodeOffset MacroAssembler::loadUnalignedSimd128(const Address& src,
   3626                                                        FloatRegister dest) {
   3627  return Ldr(ARMFPRegister(dest, 128), toMemOperand(src));
   3628 }
   3629 
   3630 FaultingCodeOffset MacroAssembler::loadUnalignedSimd128(
   3631    const BaseIndex& address, FloatRegister dest) {
   3632  return doBaseIndex(ARMFPRegister(dest, 128), address, vixl::LDR_q);
   3633 }
   3634 
   3635 // Store
   3636 
   3637 FaultingCodeOffset MacroAssembler::storeUnalignedSimd128(FloatRegister src,
   3638                                                         const Address& dest) {
   3639  return Str(ARMFPRegister(src, 128), toMemOperand(dest));
   3640 }
   3641 
   3642 FaultingCodeOffset MacroAssembler::storeUnalignedSimd128(
   3643    FloatRegister src, const BaseIndex& dest) {
   3644  return doBaseIndex(ARMFPRegister(src, 128), dest, vixl::STR_q);
   3645 }
   3646 
   3647 // Floating point negation
   3648 
   3649 void MacroAssembler::negFloat32x4(FloatRegister src, FloatRegister dest) {
   3650  Fneg(Simd4S(dest), Simd4S(src));
   3651 }
   3652 
   3653 void MacroAssembler::negFloat64x2(FloatRegister src, FloatRegister dest) {
   3654  Fneg(Simd2D(dest), Simd2D(src));
   3655 }
   3656 
   3657 // Floating point absolute value
   3658 
   3659 void MacroAssembler::absFloat32x4(FloatRegister src, FloatRegister dest) {
   3660  Fabs(Simd4S(dest), Simd4S(src));
   3661 }
   3662 
   3663 void MacroAssembler::absFloat64x2(FloatRegister src, FloatRegister dest) {
   3664  Fabs(Simd2D(dest), Simd2D(src));
   3665 }
   3666 
   3667 // NaN-propagating minimum
   3668 
   3669 void MacroAssembler::minFloat32x4(FloatRegister lhs, FloatRegister rhs,
   3670                                  FloatRegister dest) {
   3671  Fmin(Simd4S(dest), Simd4S(lhs), Simd4S(rhs));
   3672 }
   3673 
   3674 void MacroAssembler::minFloat32x4(FloatRegister rhs, FloatRegister lhsDest) {
   3675  Fmin(Simd4S(lhsDest), Simd4S(lhsDest), Simd4S(rhs));
   3676 }
   3677 
   3678 void MacroAssembler::minFloat64x2(FloatRegister rhs, FloatRegister lhsDest) {
   3679  Fmin(Simd2D(lhsDest), Simd2D(lhsDest), Simd2D(rhs));
   3680 }
   3681 
   3682 void MacroAssembler::minFloat64x2(FloatRegister lhs, FloatRegister rhs,
   3683                                  FloatRegister dest) {
   3684  Fmin(Simd2D(dest), Simd2D(lhs), Simd2D(rhs));
   3685 }
   3686 
   3687 // NaN-propagating maximum
   3688 
   3689 void MacroAssembler::maxFloat32x4(FloatRegister lhs, FloatRegister rhs,
   3690                                  FloatRegister dest) {
   3691  Fmax(Simd4S(dest), Simd4S(lhs), Simd4S(rhs));
   3692 }
   3693 
   3694 void MacroAssembler::maxFloat32x4(FloatRegister rhs, FloatRegister lhsDest) {
   3695  Fmax(Simd4S(lhsDest), Simd4S(lhsDest), Simd4S(rhs));
   3696 }
   3697 
   3698 void MacroAssembler::maxFloat64x2(FloatRegister lhs, FloatRegister rhs,
   3699                                  FloatRegister dest) {
   3700  Fmax(Simd2D(dest), Simd2D(lhs), Simd2D(rhs));
   3701 }
   3702 
   3703 void MacroAssembler::maxFloat64x2(FloatRegister rhs, FloatRegister lhsDest) {
   3704  Fmax(Simd2D(lhsDest), Simd2D(lhsDest), Simd2D(rhs));
   3705 }
   3706 
   3707 // Floating add
   3708 
   3709 void MacroAssembler::addFloat32x4(FloatRegister lhs, FloatRegister rhs,
   3710                                  FloatRegister dest) {
   3711  Fadd(Simd4S(dest), Simd4S(lhs), Simd4S(rhs));
   3712 }
   3713 
   3714 void MacroAssembler::addFloat64x2(FloatRegister lhs, FloatRegister rhs,
   3715                                  FloatRegister dest) {
   3716  Fadd(Simd2D(dest), Simd2D(lhs), Simd2D(rhs));
   3717 }
   3718 
   3719 // Floating subtract
   3720 
   3721 void MacroAssembler::subFloat32x4(FloatRegister lhs, FloatRegister rhs,
   3722                                  FloatRegister dest) {
   3723  Fsub(Simd4S(dest), Simd4S(lhs), Simd4S(rhs));
   3724 }
   3725 
   3726 void MacroAssembler::subFloat64x2(FloatRegister lhs, FloatRegister rhs,
   3727                                  FloatRegister dest) {
   3728  Fsub(Simd2D(dest), Simd2D(lhs), Simd2D(rhs));
   3729 }
   3730 
   3731 // Floating division
   3732 
   3733 void MacroAssembler::divFloat32x4(FloatRegister lhs, FloatRegister rhs,
   3734                                  FloatRegister dest) {
   3735  Fdiv(Simd4S(dest), Simd4S(lhs), Simd4S(rhs));
   3736 }
   3737 
   3738 void MacroAssembler::divFloat64x2(FloatRegister lhs, FloatRegister rhs,
   3739                                  FloatRegister dest) {
   3740  Fdiv(Simd2D(dest), Simd2D(lhs), Simd2D(rhs));
   3741 }
   3742 
   3743 // Floating Multiply
   3744 
   3745 void MacroAssembler::mulFloat32x4(FloatRegister lhs, FloatRegister rhs,
   3746                                  FloatRegister dest) {
   3747  Fmul(Simd4S(dest), Simd4S(lhs), Simd4S(rhs));
   3748 }
   3749 
   3750 void MacroAssembler::mulFloat64x2(FloatRegister lhs, FloatRegister rhs,
   3751                                  FloatRegister dest) {
   3752  Fmul(Simd2D(dest), Simd2D(lhs), Simd2D(rhs));
   3753 }
   3754 
   3755 // Pairwise add
   3756 
   3757 void MacroAssembler::extAddPairwiseInt8x16(FloatRegister src,
   3758                                           FloatRegister dest) {
   3759  Saddlp(Simd8H(dest), Simd16B(src));
   3760 }
   3761 
   3762 void MacroAssembler::unsignedExtAddPairwiseInt8x16(FloatRegister src,
   3763                                                   FloatRegister dest) {
   3764  Uaddlp(Simd8H(dest), Simd16B(src));
   3765 }
   3766 
   3767 void MacroAssembler::extAddPairwiseInt16x8(FloatRegister src,
   3768                                           FloatRegister dest) {
   3769  Saddlp(Simd4S(dest), Simd8H(src));
   3770 }
   3771 
   3772 void MacroAssembler::unsignedExtAddPairwiseInt16x8(FloatRegister src,
   3773                                                   FloatRegister dest) {
   3774  Uaddlp(Simd4S(dest), Simd8H(src));
   3775 }
   3776 
   3777 // Floating square root
   3778 
   3779 void MacroAssembler::sqrtFloat32x4(FloatRegister src, FloatRegister dest) {
   3780  Fsqrt(Simd4S(dest), Simd4S(src));
   3781 }
   3782 
   3783 void MacroAssembler::sqrtFloat64x2(FloatRegister src, FloatRegister dest) {
   3784  Fsqrt(Simd2D(dest), Simd2D(src));
   3785 }
   3786 
   3787 // Integer to floating point with rounding
   3788 
   3789 void MacroAssembler::convertInt32x4ToFloat32x4(FloatRegister src,
   3790                                               FloatRegister dest) {
   3791  Scvtf(Simd4S(dest), Simd4S(src));
   3792 }
   3793 
   3794 void MacroAssembler::unsignedConvertInt32x4ToFloat32x4(FloatRegister src,
   3795                                                       FloatRegister dest) {
   3796  Ucvtf(Simd4S(dest), Simd4S(src));
   3797 }
   3798 
   3799 void MacroAssembler::convertInt32x4ToFloat64x2(FloatRegister src,
   3800                                               FloatRegister dest) {
   3801  Sshll(Simd2D(dest), Simd2S(src), 0);
   3802  Scvtf(Simd2D(dest), Simd2D(dest));
   3803 }
   3804 
   3805 void MacroAssembler::unsignedConvertInt32x4ToFloat64x2(FloatRegister src,
   3806                                                       FloatRegister dest) {
   3807  Ushll(Simd2D(dest), Simd2S(src), 0);
   3808  Ucvtf(Simd2D(dest), Simd2D(dest));
   3809 }
   3810 
   3811 // Floating point to integer with saturation
   3812 
   3813 void MacroAssembler::truncSatFloat32x4ToInt32x4(FloatRegister src,
   3814                                                FloatRegister dest) {
   3815  Fcvtzs(Simd4S(dest), Simd4S(src));
   3816 }
   3817 
   3818 void MacroAssembler::unsignedTruncSatFloat32x4ToInt32x4(FloatRegister src,
   3819                                                        FloatRegister dest) {
   3820  Fcvtzu(Simd4S(dest), Simd4S(src));
   3821 }
   3822 
   3823 void MacroAssembler::truncSatFloat64x2ToInt32x4(FloatRegister src,
   3824                                                FloatRegister dest,
   3825                                                FloatRegister temp) {
   3826  Fcvtzs(Simd2D(dest), Simd2D(src));
   3827  Sqxtn(Simd2S(dest), Simd2D(dest));
   3828 }
   3829 
   3830 void MacroAssembler::unsignedTruncSatFloat64x2ToInt32x4(FloatRegister src,
   3831                                                        FloatRegister dest,
   3832                                                        FloatRegister temp) {
   3833  Fcvtzu(Simd2D(dest), Simd2D(src));
   3834  Uqxtn(Simd2S(dest), Simd2D(dest));
   3835 }
   3836 
   3837 void MacroAssembler::truncFloat32x4ToInt32x4Relaxed(FloatRegister src,
   3838                                                    FloatRegister dest) {
   3839  Fcvtzs(Simd4S(dest), Simd4S(src));
   3840 }
   3841 
   3842 void MacroAssembler::unsignedTruncFloat32x4ToInt32x4Relaxed(
   3843    FloatRegister src, FloatRegister dest) {
   3844  Fcvtzu(Simd4S(dest), Simd4S(src));
   3845 }
   3846 
   3847 void MacroAssembler::truncFloat64x2ToInt32x4Relaxed(FloatRegister src,
   3848                                                    FloatRegister dest) {
   3849  Fcvtzs(Simd2D(dest), Simd2D(src));
   3850  Sqxtn(Simd2S(dest), Simd2D(dest));
   3851 }
   3852 
   3853 void MacroAssembler::unsignedTruncFloat64x2ToInt32x4Relaxed(
   3854    FloatRegister src, FloatRegister dest) {
   3855  Fcvtzu(Simd2D(dest), Simd2D(src));
   3856  Uqxtn(Simd2S(dest), Simd2D(dest));
   3857 }
   3858 
   3859 // Floating point narrowing
   3860 
   3861 void MacroAssembler::convertFloat64x2ToFloat32x4(FloatRegister src,
   3862                                                 FloatRegister dest) {
   3863  Fcvtn(Simd2S(dest), Simd2D(src));
   3864 }
   3865 
   3866 // Floating point widening
   3867 
   3868 void MacroAssembler::convertFloat32x4ToFloat64x2(FloatRegister src,
   3869                                                 FloatRegister dest) {
   3870  Fcvtl(Simd2D(dest), Simd2S(src));
   3871 }
   3872 
   3873 // Integer to integer narrowing
   3874 
   3875 void MacroAssembler::narrowInt16x8(FloatRegister lhs, FloatRegister rhs,
   3876                                   FloatRegister dest) {
   3877  ScratchSimd128Scope scratch(*this);
   3878  if (rhs == dest) {
   3879    Mov(scratch, SimdReg(rhs));
   3880    rhs = scratch;
   3881  }
   3882  Sqxtn(Simd8B(dest), Simd8H(lhs));
   3883  Sqxtn2(Simd16B(dest), Simd8H(rhs));
   3884 }
   3885 
   3886 void MacroAssembler::unsignedNarrowInt16x8(FloatRegister lhs, FloatRegister rhs,
   3887                                           FloatRegister dest) {
   3888  ScratchSimd128Scope scratch(*this);
   3889  if (rhs == dest) {
   3890    Mov(scratch, SimdReg(rhs));
   3891    rhs = scratch;
   3892  }
   3893  Sqxtun(Simd8B(dest), Simd8H(lhs));
   3894  Sqxtun2(Simd16B(dest), Simd8H(rhs));
   3895 }
   3896 
   3897 void MacroAssembler::narrowInt32x4(FloatRegister lhs, FloatRegister rhs,
   3898                                   FloatRegister dest) {
   3899  ScratchSimd128Scope scratch(*this);
   3900  if (rhs == dest) {
   3901    Mov(scratch, SimdReg(rhs));
   3902    rhs = scratch;
   3903  }
   3904  Sqxtn(Simd4H(dest), Simd4S(lhs));
   3905  Sqxtn2(Simd8H(dest), Simd4S(rhs));
   3906 }
   3907 
   3908 void MacroAssembler::unsignedNarrowInt32x4(FloatRegister lhs, FloatRegister rhs,
   3909                                           FloatRegister dest) {
   3910  ScratchSimd128Scope scratch(*this);
   3911  if (rhs == dest) {
   3912    Mov(scratch, SimdReg(rhs));
   3913    rhs = scratch;
   3914  }
   3915  Sqxtun(Simd4H(dest), Simd4S(lhs));
   3916  Sqxtun2(Simd8H(dest), Simd4S(rhs));
   3917 }
   3918 
   3919 // Integer to integer widening
   3920 
   3921 void MacroAssembler::widenLowInt8x16(FloatRegister src, FloatRegister dest) {
   3922  Sshll(Simd8H(dest), Simd8B(src), 0);
   3923 }
   3924 
   3925 void MacroAssembler::widenHighInt8x16(FloatRegister src, FloatRegister dest) {
   3926  Sshll2(Simd8H(dest), Simd16B(src), 0);
   3927 }
   3928 
   3929 void MacroAssembler::unsignedWidenLowInt8x16(FloatRegister src,
   3930                                             FloatRegister dest) {
   3931  Ushll(Simd8H(dest), Simd8B(src), 0);
   3932 }
   3933 
   3934 void MacroAssembler::unsignedWidenHighInt8x16(FloatRegister src,
   3935                                              FloatRegister dest) {
   3936  Ushll2(Simd8H(dest), Simd16B(src), 0);
   3937 }
   3938 
   3939 void MacroAssembler::widenLowInt16x8(FloatRegister src, FloatRegister dest) {
   3940  Sshll(Simd4S(dest), Simd4H(src), 0);
   3941 }
   3942 
   3943 void MacroAssembler::widenHighInt16x8(FloatRegister src, FloatRegister dest) {
   3944  Sshll2(Simd4S(dest), Simd8H(src), 0);
   3945 }
   3946 
   3947 void MacroAssembler::unsignedWidenLowInt16x8(FloatRegister src,
   3948                                             FloatRegister dest) {
   3949  Ushll(Simd4S(dest), Simd4H(src), 0);
   3950 }
   3951 
   3952 void MacroAssembler::unsignedWidenHighInt16x8(FloatRegister src,
   3953                                              FloatRegister dest) {
   3954  Ushll2(Simd4S(dest), Simd8H(src), 0);
   3955 }
   3956 
   3957 void MacroAssembler::widenLowInt32x4(FloatRegister src, FloatRegister dest) {
   3958  Sshll(Simd2D(dest), Simd2S(src), 0);
   3959 }
   3960 
   3961 void MacroAssembler::unsignedWidenLowInt32x4(FloatRegister src,
   3962                                             FloatRegister dest) {
   3963  Ushll(Simd2D(dest), Simd2S(src), 0);
   3964 }
   3965 
   3966 void MacroAssembler::widenHighInt32x4(FloatRegister src, FloatRegister dest) {
   3967  Sshll2(Simd2D(dest), Simd4S(src), 0);
   3968 }
   3969 
   3970 void MacroAssembler::unsignedWidenHighInt32x4(FloatRegister src,
   3971                                              FloatRegister dest) {
   3972  Ushll2(Simd2D(dest), Simd4S(src), 0);
   3973 }
   3974 
   3975 // Compare-based minimum/maximum (experimental as of August, 2020)
   3976 // https://github.com/WebAssembly/simd/pull/122
   3977 
   3978 void MacroAssembler::pseudoMinFloat32x4(FloatRegister rhsOrRhsDest,
   3979                                        FloatRegister lhsOrLhsDest) {
   3980  // Shut up the linter by using the same names as in the declaration, then
   3981  // aliasing here.
   3982  FloatRegister rhs = rhsOrRhsDest;
   3983  FloatRegister lhsDest = lhsOrLhsDest;
   3984  ScratchSimd128Scope scratch(*this);
   3985  Fcmgt(Simd4S(scratch), Simd4S(lhsDest), Simd4S(rhs));
   3986  Bsl(Simd16B(scratch), Simd16B(rhs), Simd16B(lhsDest));
   3987  Mov(SimdReg(lhsDest), scratch);
   3988 }
   3989 
   3990 void MacroAssembler::pseudoMinFloat32x4(FloatRegister lhs, FloatRegister rhs,
   3991                                        FloatRegister dest) {
   3992  ScratchSimd128Scope scratch(*this);
   3993  Fcmgt(Simd4S(scratch), Simd4S(lhs), Simd4S(rhs));
   3994  Bsl(Simd16B(scratch), Simd16B(rhs), Simd16B(lhs));
   3995  Mov(SimdReg(dest), scratch);
   3996 }
   3997 
   3998 void MacroAssembler::pseudoMinFloat64x2(FloatRegister rhsOrRhsDest,
   3999                                        FloatRegister lhsOrLhsDest) {
   4000  FloatRegister rhs = rhsOrRhsDest;
   4001  FloatRegister lhsDest = lhsOrLhsDest;
   4002  ScratchSimd128Scope scratch(*this);
   4003  Fcmgt(Simd2D(scratch), Simd2D(lhsDest), Simd2D(rhs));
   4004  Bsl(Simd16B(scratch), Simd16B(rhs), Simd16B(lhsDest));
   4005  Mov(SimdReg(lhsDest), scratch);
   4006 }
   4007 
   4008 void MacroAssembler::pseudoMinFloat64x2(FloatRegister lhs, FloatRegister rhs,
   4009                                        FloatRegister dest) {
   4010  ScratchSimd128Scope scratch(*this);
   4011  Fcmgt(Simd2D(scratch), Simd2D(lhs), Simd2D(rhs));
   4012  Bsl(Simd16B(scratch), Simd16B(rhs), Simd16B(lhs));
   4013  Mov(SimdReg(dest), scratch);
   4014 }
   4015 
   4016 void MacroAssembler::pseudoMaxFloat32x4(FloatRegister rhsOrRhsDest,
   4017                                        FloatRegister lhsOrLhsDest) {
   4018  FloatRegister rhs = rhsOrRhsDest;
   4019  FloatRegister lhsDest = lhsOrLhsDest;
   4020  ScratchSimd128Scope scratch(*this);
   4021  Fcmgt(Simd4S(scratch), Simd4S(rhs), Simd4S(lhsDest));
   4022  Bsl(Simd16B(scratch), Simd16B(rhs), Simd16B(lhsDest));
   4023  Mov(SimdReg(lhsDest), scratch);
   4024 }
   4025 
   4026 void MacroAssembler::pseudoMaxFloat32x4(FloatRegister lhs, FloatRegister rhs,
   4027                                        FloatRegister dest) {
   4028  ScratchSimd128Scope scratch(*this);
   4029  Fcmgt(Simd4S(scratch), Simd4S(rhs), Simd4S(lhs));
   4030  Bsl(Simd16B(scratch), Simd16B(rhs), Simd16B(lhs));
   4031  Mov(SimdReg(dest), scratch);
   4032 }
   4033 
   4034 void MacroAssembler::pseudoMaxFloat64x2(FloatRegister rhsOrRhsDest,
   4035                                        FloatRegister lhsOrLhsDest) {
   4036  FloatRegister rhs = rhsOrRhsDest;
   4037  FloatRegister lhsDest = lhsOrLhsDest;
   4038  ScratchSimd128Scope scratch(*this);
   4039  Fcmgt(Simd2D(scratch), Simd2D(rhs), Simd2D(lhsDest));
   4040  Bsl(Simd16B(scratch), Simd16B(rhs), Simd16B(lhsDest));
   4041  Mov(SimdReg(lhsDest), scratch);
   4042 }
   4043 
   4044 void MacroAssembler::pseudoMaxFloat64x2(FloatRegister lhs, FloatRegister rhs,
   4045                                        FloatRegister dest) {
   4046  ScratchSimd128Scope scratch(*this);
   4047  Fcmgt(Simd2D(scratch), Simd2D(rhs), Simd2D(lhs));
   4048  Bsl(Simd16B(scratch), Simd16B(rhs), Simd16B(lhs));
   4049  Mov(SimdReg(dest), scratch);
   4050 }
   4051 
   4052 // Widening/pairwise integer dot product (experimental as of August, 2020)
   4053 // https://github.com/WebAssembly/simd/pull/127
   4054 
   4055 void MacroAssembler::widenDotInt16x8(FloatRegister lhs, FloatRegister rhs,
   4056                                     FloatRegister dest) {
   4057  ScratchSimd128Scope scratch(*this);
   4058  Smull(Simd4S(scratch), Simd4H(lhs), Simd4H(rhs));
   4059  Smull2(Simd4S(dest), Simd8H(lhs), Simd8H(rhs));
   4060  Addp(Simd4S(dest), Simd4S(scratch), Simd4S(dest));
   4061 }
   4062 
   4063 void MacroAssembler::dotInt8x16Int7x16(FloatRegister lhs, FloatRegister rhs,
   4064                                       FloatRegister dest) {
   4065  ScratchSimd128Scope scratch(*this);
   4066  Smull(Simd8H(scratch), Simd8B(lhs), Simd8B(rhs));
   4067  Smull2(Simd8H(dest), Simd16B(lhs), Simd16B(rhs));
   4068  Addp(Simd8H(dest), Simd8H(scratch), Simd8H(dest));
   4069 }
   4070 
   4071 void MacroAssembler::dotInt8x16Int7x16ThenAdd(FloatRegister lhs,
   4072                                              FloatRegister rhs,
   4073                                              FloatRegister dest,
   4074                                              FloatRegister temp) {
   4075  ScratchSimd128Scope scratch(*this);
   4076  Smull(Simd8H(scratch), Simd8B(lhs), Simd8B(rhs));
   4077  Smull2(Simd8H(temp), Simd16B(lhs), Simd16B(rhs));
   4078  Addp(Simd8H(temp), Simd8H(scratch), Simd8H(temp));
   4079  Sadalp(Simd4S(dest), Simd8H(temp));
   4080 }
   4081 
   4082 // Floating point rounding (experimental as of August, 2020)
   4083 // https://github.com/WebAssembly/simd/pull/232
   4084 
   4085 void MacroAssembler::ceilFloat32x4(FloatRegister src, FloatRegister dest) {
   4086  Frintp(Simd4S(dest), Simd4S(src));
   4087 }
   4088 
   4089 void MacroAssembler::ceilFloat64x2(FloatRegister src, FloatRegister dest) {
   4090  Frintp(Simd2D(dest), Simd2D(src));
   4091 }
   4092 
   4093 void MacroAssembler::floorFloat32x4(FloatRegister src, FloatRegister dest) {
   4094  Frintm(Simd4S(dest), Simd4S(src));
   4095 }
   4096 
   4097 void MacroAssembler::floorFloat64x2(FloatRegister src, FloatRegister dest) {
   4098  Frintm(Simd2D(dest), Simd2D(src));
   4099 }
   4100 
   4101 void MacroAssembler::truncFloat32x4(FloatRegister src, FloatRegister dest) {
   4102  Frintz(Simd4S(dest), Simd4S(src));
   4103 }
   4104 
   4105 void MacroAssembler::truncFloat64x2(FloatRegister src, FloatRegister dest) {
   4106  Frintz(Simd2D(dest), Simd2D(src));
   4107 }
   4108 
   4109 void MacroAssembler::nearestFloat32x4(FloatRegister src, FloatRegister dest) {
   4110  Frintn(Simd4S(dest), Simd4S(src));
   4111 }
   4112 
   4113 void MacroAssembler::nearestFloat64x2(FloatRegister src, FloatRegister dest) {
   4114  Frintn(Simd2D(dest), Simd2D(src));
   4115 }
   4116 
   4117 // Floating multiply-accumulate: srcDest [+-]= src1 * src2
   4118 
   4119 void MacroAssembler::fmaFloat32x4(FloatRegister src1, FloatRegister src2,
   4120                                  FloatRegister srcDest) {
   4121  Fmla(Simd4S(srcDest), Simd4S(src1), Simd4S(src2));
   4122 }
   4123 
   4124 void MacroAssembler::fnmaFloat32x4(FloatRegister src1, FloatRegister src2,
   4125                                   FloatRegister srcDest) {
   4126  Fmls(Simd4S(srcDest), Simd4S(src1), Simd4S(src2));
   4127 }
   4128 
   4129 void MacroAssembler::fmaFloat64x2(FloatRegister src1, FloatRegister src2,
   4130                                  FloatRegister srcDest) {
   4131  Fmla(Simd2D(srcDest), Simd2D(src1), Simd2D(src2));
   4132 }
   4133 
   4134 void MacroAssembler::fnmaFloat64x2(FloatRegister src1, FloatRegister src2,
   4135                                   FloatRegister srcDest) {
   4136  Fmls(Simd2D(srcDest), Simd2D(src1), Simd2D(src2));
   4137 }
   4138 
   4139 void MacroAssembler::minFloat32x4Relaxed(FloatRegister src,
   4140                                         FloatRegister srcDest) {
   4141  Fmin(Simd4S(srcDest), Simd4S(src), Simd4S(srcDest));
   4142 }
   4143 
   4144 void MacroAssembler::minFloat32x4Relaxed(FloatRegister lhs, FloatRegister rhs,
   4145                                         FloatRegister dest) {
   4146  Fmin(Simd4S(dest), Simd4S(rhs), Simd4S(lhs));
   4147 }
   4148 
   4149 void MacroAssembler::maxFloat32x4Relaxed(FloatRegister src,
   4150                                         FloatRegister srcDest) {
   4151  Fmax(Simd4S(srcDest), Simd4S(src), Simd4S(srcDest));
   4152 }
   4153 
   4154 void MacroAssembler::maxFloat32x4Relaxed(FloatRegister lhs, FloatRegister rhs,
   4155                                         FloatRegister dest) {
   4156  Fmax(Simd4S(dest), Simd4S(rhs), Simd4S(lhs));
   4157 }
   4158 
   4159 void MacroAssembler::minFloat64x2Relaxed(FloatRegister src,
   4160                                         FloatRegister srcDest) {
   4161  Fmin(Simd2D(srcDest), Simd2D(src), Simd2D(srcDest));
   4162 }
   4163 
   4164 void MacroAssembler::minFloat64x2Relaxed(FloatRegister lhs, FloatRegister rhs,
   4165                                         FloatRegister dest) {
   4166  Fmin(Simd2D(dest), Simd2D(rhs), Simd2D(lhs));
   4167 }
   4168 
   4169 void MacroAssembler::maxFloat64x2Relaxed(FloatRegister src,
   4170                                         FloatRegister srcDest) {
   4171  Fmax(Simd2D(srcDest), Simd2D(src), Simd2D(srcDest));
   4172 }
   4173 
   4174 void MacroAssembler::maxFloat64x2Relaxed(FloatRegister lhs, FloatRegister rhs,
   4175                                         FloatRegister dest) {
   4176  Fmax(Simd2D(dest), Simd2D(rhs), Simd2D(lhs));
   4177 }
   4178 
   4179 //}}} check_macroassembler_style
   4180 // ===============================================================
   4181 
   4182 void MacroAssemblerCompat::addToStackPtr(Register src) {
   4183  Add(GetStackPointer64(), GetStackPointer64(), ARMRegister(src, 64));
   4184  // Given that required invariant SP <= PSP, this is probably pointless,
   4185  // since it gives PSP a larger value.
   4186  syncStackPtr();
   4187 }
   4188 
   4189 void MacroAssemblerCompat::addToStackPtr(Imm32 imm) {
   4190  Add(GetStackPointer64(), GetStackPointer64(), Operand(imm.value));
   4191  // As above, probably pointless.
   4192  syncStackPtr();
   4193 }
   4194 
   4195 void MacroAssemblerCompat::addToStackPtr(const Address& src) {
   4196  vixl::UseScratchRegisterScope temps(this);
   4197  const ARMRegister scratch = temps.AcquireX();
   4198  Ldr(scratch, toMemOperand(src));
   4199  Add(GetStackPointer64(), GetStackPointer64(), scratch);
   4200  // As above, probably pointless.
   4201  syncStackPtr();
   4202 }
   4203 
   4204 void MacroAssemblerCompat::addStackPtrTo(Register dest) {
   4205  Add(ARMRegister(dest, 64), ARMRegister(dest, 64), GetStackPointer64());
   4206 }
   4207 
   4208 void MacroAssemblerCompat::subFromStackPtr(Register src) {
   4209  Sub(GetStackPointer64(), GetStackPointer64(), ARMRegister(src, 64));
   4210  syncStackPtr();
   4211 }
   4212 
   4213 void MacroAssemblerCompat::subFromStackPtr(Imm32 imm) {
   4214  Sub(GetStackPointer64(), GetStackPointer64(), Operand(imm.value));
   4215  syncStackPtr();
   4216 }
   4217 
   4218 void MacroAssemblerCompat::subStackPtrFrom(Register dest) {
   4219  Sub(ARMRegister(dest, 64), ARMRegister(dest, 64), GetStackPointer64());
   4220 }
   4221 
   4222 void MacroAssemblerCompat::andToStackPtr(Imm32 imm) {
   4223  if (sp.Is(GetStackPointer64())) {
   4224    vixl::UseScratchRegisterScope temps(this);
   4225    const ARMRegister scratch = temps.AcquireX();
   4226    Mov(scratch, sp);
   4227    And(sp, scratch, Operand(imm.value));
   4228    // syncStackPtr() not needed since our SP is the real SP.
   4229  } else {
   4230    And(GetStackPointer64(), GetStackPointer64(), Operand(imm.value));
   4231    syncStackPtr();
   4232  }
   4233 }
   4234 
   4235 void MacroAssemblerCompat::moveToStackPtr(Register src) {
   4236  Mov(GetStackPointer64(), ARMRegister(src, 64));
   4237  syncStackPtr();
   4238 }
   4239 
   4240 void MacroAssemblerCompat::moveStackPtrTo(Register dest) {
   4241  Mov(ARMRegister(dest, 64), GetStackPointer64());
   4242 }
   4243 
   4244 void MacroAssemblerCompat::loadStackPtr(const Address& src) {
   4245  if (sp.Is(GetStackPointer64())) {
   4246    vixl::UseScratchRegisterScope temps(this);
   4247    const ARMRegister scratch = temps.AcquireX();
   4248    Ldr(scratch, toMemOperand(src));
   4249    Mov(sp, scratch);
   4250    // syncStackPtr() not needed since our SP is the real SP.
   4251  } else {
   4252    Ldr(GetStackPointer64(), toMemOperand(src));
   4253    syncStackPtr();
   4254  }
   4255 }
   4256 
   4257 void MacroAssemblerCompat::storeStackPtr(const Address& dest) {
   4258  if (sp.Is(GetStackPointer64())) {
   4259    vixl::UseScratchRegisterScope temps(this);
   4260    const ARMRegister scratch = temps.AcquireX();
   4261    Mov(scratch, sp);
   4262    Str(scratch, toMemOperand(dest));
   4263  } else {
   4264    Str(GetStackPointer64(), toMemOperand(dest));
   4265  }
   4266 }
   4267 
   4268 void MacroAssemblerCompat::loadStackPtrFromPrivateValue(const Address& src) {
   4269  // On ARM64, a private value is stored the same as any pointer.
   4270  loadStackPtr(src);
   4271 }
   4272 
   4273 void MacroAssemblerCompat::storeStackPtrToPrivateValue(const Address& dest) {
   4274  // On ARM64, a private value is stored the same as any pointer.
   4275  storeStackPtr(dest);
   4276 }
   4277 
   4278 void MacroAssemblerCompat::branchTestStackPtr(Condition cond, Imm32 rhs,
   4279                                              Label* label) {
   4280  if (sp.Is(GetStackPointer64())) {
   4281    vixl::UseScratchRegisterScope temps(this);
   4282    const ARMRegister scratch = temps.AcquireX();
   4283    Mov(scratch, sp);
   4284    Tst(scratch, Operand(rhs.value));
   4285  } else {
   4286    Tst(GetStackPointer64(), Operand(rhs.value));
   4287  }
   4288  B(label, cond);
   4289 }
   4290 
   4291 void MacroAssemblerCompat::branchStackPtr(Condition cond, Register rhs_,
   4292                                          Label* label) {
   4293  ARMRegister rhs(rhs_, 64);
   4294  if (sp.Is(GetStackPointer64())) {
   4295    vixl::UseScratchRegisterScope temps(this);
   4296    const ARMRegister scratch = temps.AcquireX();
   4297    Mov(scratch, sp);
   4298    Cmp(scratch, rhs);
   4299  } else {
   4300    Cmp(GetStackPointer64(), rhs);
   4301  }
   4302  B(label, cond);
   4303 }
   4304 
   4305 void MacroAssemblerCompat::branchStackPtrRhs(Condition cond, Address lhs,
   4306                                             Label* label) {
   4307  vixl::UseScratchRegisterScope temps(this);
   4308  const ARMRegister scratch = temps.AcquireX();
   4309  Ldr(scratch, toMemOperand(lhs));
   4310  // Cmp disallows SP as the rhs, so flip the operands and invert the
   4311  // condition.
   4312  Cmp(GetStackPointer64(), scratch);
   4313  B(label, Assembler::InvertCondition(cond));
   4314 }
   4315 
   4316 void MacroAssemblerCompat::branchStackPtrRhs(Condition cond,
   4317                                             AbsoluteAddress lhs,
   4318                                             Label* label) {
   4319  vixl::UseScratchRegisterScope temps(this);
   4320  const ARMRegister scratch = temps.AcquireX();
   4321  loadPtr(lhs, scratch.asUnsized());
   4322  // Cmp disallows SP as the rhs, so flip the operands and invert the
   4323  // condition.
   4324  Cmp(GetStackPointer64(), scratch);
   4325  B(label, Assembler::InvertCondition(cond));
   4326 }
   4327 
   4328 void MacroAssemblerCompat::unboxValue(const ValueOperand& src, AnyRegister dest,
   4329                                      JSValueType type) {
   4330  if (dest.isFloat()) {
   4331    Label notInt32, end;
   4332    asMasm().branchTestInt32(Assembler::NotEqual, src, &notInt32);
   4333    convertInt32ToDouble(src.valueReg(), dest.fpu());
   4334    jump(&end);
   4335    bind(&notInt32);
   4336    unboxDouble(src, dest.fpu());
   4337    bind(&end);
   4338  } else {
   4339    unboxNonDouble(src, dest.gpr(), type);
   4340  }
   4341 }
   4342 
   4343 }  // namespace jit
   4344 }  // namespace js
   4345 
   4346 #endif /* jit_arm64_MacroAssembler_arm64_inl_h */