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, ¬Int32); 4333 convertInt32ToDouble(src.valueReg(), dest.fpu()); 4334 jump(&end); 4335 bind(¬Int32); 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 */