MacroAssembler-x64.h (45590B)
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_x64_MacroAssembler_x64_h 8 #define jit_x64_MacroAssembler_x64_h 9 10 #include "jit/x86-shared/MacroAssembler-x86-shared.h" 11 #include "js/HeapAPI.h" 12 #include "wasm/WasmBuiltins.h" 13 14 namespace js { 15 namespace jit { 16 17 struct ImmShiftedTag : public ImmWord { 18 explicit ImmShiftedTag(JSValueType type) 19 : ImmWord(uintptr_t(JSVAL_TYPE_TO_SHIFTED_TAG(type))) {} 20 }; 21 22 struct ImmTag : public Imm32 { 23 explicit ImmTag(JSValueTag tag) : Imm32(tag) {} 24 }; 25 26 // ScratchTagScope and ScratchTagScopeRelease are used to manage the tag 27 // register for splitTagForTest(), which has different register management on 28 // different platforms. On 64-bit platforms it requires a scratch register that 29 // does not interfere with other operations; on 32-bit platforms it uses a 30 // register that is already part of the Value. 31 // 32 // The ScratchTagScope RAII type acquires the appropriate register; a reference 33 // to a variable of this type is then passed to splitTagForTest(). 34 // 35 // On 64-bit platforms ScratchTagScopeRelease makes the owned scratch register 36 // available in a dynamic scope during compilation. However it is important to 37 // remember that that does not preserve the register value in any way, so this 38 // RAII type should only be used along paths that eventually branch past further 39 // uses of the extracted tag value. 40 // 41 // On 32-bit platforms ScratchTagScopeRelease has no effect, since it does not 42 // manage a register, it only aliases a register in the ValueOperand. 43 44 class ScratchTagScope : public ScratchRegisterScope { 45 public: 46 ScratchTagScope(MacroAssembler& masm, const ValueOperand&) 47 : ScratchRegisterScope(masm) {} 48 }; 49 50 class ScratchTagScopeRelease { 51 ScratchTagScope* ts_; 52 53 public: 54 explicit ScratchTagScopeRelease(ScratchTagScope* ts) : ts_(ts) { 55 ts_->release(); 56 } 57 ~ScratchTagScopeRelease() { ts_->reacquire(); } 58 }; 59 60 class MacroAssemblerX64 : public MacroAssemblerX86Shared { 61 private: 62 // Perform a downcast. Should be removed by Bug 996602. 63 MacroAssembler& asMasm(); 64 const MacroAssembler& asMasm() const; 65 66 void bindOffsets(const MacroAssemblerX86Shared::UsesVector&); 67 68 void vpRiprOpSimd128(const SimdConstant& v, FloatRegister reg, 69 JmpSrc (X86Encoding::BaseAssemblerX64::*op)( 70 X86Encoding::XMMRegisterID id)); 71 72 void vpRiprOpSimd128(const SimdConstant& v, FloatRegister lhs, 73 FloatRegister dest, 74 JmpSrc (X86Encoding::BaseAssemblerX64::*op)( 75 X86Encoding::XMMRegisterID srcId, 76 X86Encoding::XMMRegisterID destId)); 77 78 protected: 79 void flexibleDivMod64(Register lhs, Register rhs, Register output, 80 bool isUnsigned, bool isDiv); 81 82 public: 83 using MacroAssemblerX86Shared::load32; 84 using MacroAssemblerX86Shared::store16; 85 using MacroAssemblerX86Shared::store32; 86 87 MacroAssemblerX64() = default; 88 89 // The buffer is about to be linked, make sure any constant pools or excess 90 // bookkeeping has been flushed to the instruction stream. 91 void finish(); 92 93 ///////////////////////////////////////////////////////////////// 94 // X64 helpers. 95 ///////////////////////////////////////////////////////////////// 96 void writeDataRelocation(const Value& val) { 97 MOZ_ASSERT(val.isGCThing(), "only called for gc-things"); 98 99 // Raw GC pointer relocations and Value relocations both end up in 100 // Assembler::TraceDataRelocations. 101 gc::Cell* cell = val.toGCThing(); 102 if (cell && gc::IsInsideNursery(cell)) { 103 embedsNurseryPointers_ = true; 104 } 105 dataRelocations_.writeUnsigned(masm.currentOffset()); 106 } 107 108 // Refers to the upper 32 bits of a 64-bit Value operand. 109 // On x86_64, the upper 32 bits do not necessarily only contain the type. 110 Operand ToUpper32(Operand base) { 111 switch (base.kind()) { 112 case Operand::MEM_REG_DISP: 113 return Operand(Register::FromCode(base.base()), base.disp() + 4); 114 115 case Operand::MEM_SCALE: 116 return Operand(Register::FromCode(base.base()), 117 Register::FromCode(base.index()), base.scale(), 118 base.disp() + 4); 119 120 default: 121 MOZ_CRASH("unexpected operand kind"); 122 } 123 } 124 static inline Operand ToUpper32(const Address& address) { 125 return Operand(address.base, address.offset + 4); 126 } 127 static inline Operand ToUpper32(const BaseIndex& address) { 128 return Operand(address.base, address.index, address.scale, 129 address.offset + 4); 130 } 131 132 uint32_t Upper32Of(JSValueShiftedTag tag) { return uint32_t(tag >> 32); } 133 134 JSValueShiftedTag GetShiftedTag(JSValueType type) { 135 return (JSValueShiftedTag)JSVAL_TYPE_TO_SHIFTED_TAG(type); 136 } 137 138 ///////////////////////////////////////////////////////////////// 139 // X86/X64-common interface. 140 ///////////////////////////////////////////////////////////////// 141 142 void storeValue(ValueOperand val, Operand dest) { 143 movq(val.valueReg(), dest); 144 } 145 void storeValue(ValueOperand val, const Address& dest) { 146 storeValue(val, Operand(dest)); 147 } 148 template <typename T> 149 void storeValue(JSValueType type, Register reg, const T& dest) { 150 ScratchRegisterScope scratch(asMasm()); 151 boxValue(type, reg, scratch); 152 movq(scratch, Operand(dest)); 153 } 154 template <typename T> 155 void storeValue(const Value& val, const T& dest) { 156 if (val.isGCThing()) { 157 ScratchRegisterScope scratch(asMasm()); 158 movWithPatch(ImmWord(val.asRawBits()), scratch); 159 writeDataRelocation(val); 160 movq(scratch, Operand(dest)); 161 } else { 162 storePtr(ImmWord(val.asRawBits()), dest); 163 } 164 } 165 void storeValue(ValueOperand val, BaseIndex dest) { 166 storeValue(val, Operand(dest)); 167 } 168 void storeValue(const Address& src, const Address& dest, Register temp) { 169 loadPtr(src, temp); 170 storePtr(temp, dest); 171 } 172 void storePrivateValue(Register src, const Address& dest) { 173 storePtr(src, dest); 174 } 175 void storePrivateValue(ImmGCPtr imm, const Address& dest) { 176 storePtr(imm, dest); 177 } 178 void loadValue(Operand src, ValueOperand val) { movq(src, val.valueReg()); } 179 void loadValue(Address src, ValueOperand val) { 180 loadValue(Operand(src), val); 181 } 182 void loadValue(const BaseIndex& src, ValueOperand val) { 183 loadValue(Operand(src), val); 184 } 185 void loadUnalignedValue(const Address& src, ValueOperand dest) { 186 loadValue(src, dest); 187 } 188 void tagValue(JSValueType type, Register payload, ValueOperand dest); 189 void pushValue(ValueOperand val) { push(val.valueReg()); } 190 void popValue(ValueOperand val) { pop(val.valueReg()); } 191 void pushValue(const Value& val) { 192 if (val.isGCThing()) { 193 ScratchRegisterScope scratch(asMasm()); 194 movWithPatch(ImmWord(val.asRawBits()), scratch); 195 writeDataRelocation(val); 196 push(scratch); 197 } else { 198 push(ImmWord(val.asRawBits())); 199 } 200 } 201 void pushValue(JSValueType type, Register reg) { 202 ScratchRegisterScope scratch(asMasm()); 203 boxValue(type, reg, scratch); 204 push(scratch); 205 } 206 void pushValue(const Address& addr) { push(Operand(addr)); } 207 208 void pushValue(const BaseIndex& addr, Register scratch) { 209 push(Operand(addr)); 210 } 211 212 void boxValue(JSValueType type, Register src, Register dest); 213 void boxValue(Register type, Register src, Register dest); 214 215 Condition testUndefined(Condition cond, Register tag) { 216 MOZ_ASSERT(cond == Equal || cond == NotEqual); 217 cmp32(tag, ImmTag(JSVAL_TAG_UNDEFINED)); 218 return cond; 219 } 220 Condition testInt32(Condition cond, Register tag) { 221 MOZ_ASSERT(cond == Equal || cond == NotEqual); 222 cmp32(tag, ImmTag(JSVAL_TAG_INT32)); 223 return cond; 224 } 225 Condition testBoolean(Condition cond, Register tag) { 226 MOZ_ASSERT(cond == Equal || cond == NotEqual); 227 cmp32(tag, ImmTag(JSVAL_TAG_BOOLEAN)); 228 return cond; 229 } 230 Condition testNull(Condition cond, Register tag) { 231 MOZ_ASSERT(cond == Equal || cond == NotEqual); 232 cmp32(tag, ImmTag(JSVAL_TAG_NULL)); 233 return cond; 234 } 235 Condition testString(Condition cond, Register tag) { 236 MOZ_ASSERT(cond == Equal || cond == NotEqual); 237 cmp32(tag, ImmTag(JSVAL_TAG_STRING)); 238 return cond; 239 } 240 Condition testSymbol(Condition cond, Register tag) { 241 MOZ_ASSERT(cond == Equal || cond == NotEqual); 242 cmp32(tag, ImmTag(JSVAL_TAG_SYMBOL)); 243 return cond; 244 } 245 Condition testBigInt(Condition cond, Register tag) { 246 MOZ_ASSERT(cond == Equal || cond == NotEqual); 247 cmp32(tag, ImmTag(JSVAL_TAG_BIGINT)); 248 return cond; 249 } 250 Condition testObject(Condition cond, Register tag) { 251 MOZ_ASSERT(cond == Equal || cond == NotEqual); 252 cmp32(tag, ImmTag(JSVAL_TAG_OBJECT)); 253 return cond; 254 } 255 Condition testDouble(Condition cond, Register tag) { 256 MOZ_ASSERT(cond == Equal || cond == NotEqual); 257 cmp32(tag, Imm32(JSVAL_TAG_MAX_DOUBLE)); 258 return cond == Equal ? BelowOrEqual : Above; 259 } 260 Condition testNumber(Condition cond, Register tag) { 261 MOZ_ASSERT(cond == Equal || cond == NotEqual); 262 cmp32(tag, Imm32(JS::detail::ValueUpperInclNumberTag)); 263 return cond == Equal ? BelowOrEqual : Above; 264 } 265 Condition testGCThing(Condition cond, Register tag) { 266 MOZ_ASSERT(cond == Equal || cond == NotEqual); 267 cmp32(tag, Imm32(JS::detail::ValueLowerInclGCThingTag)); 268 return cond == Equal ? AboveOrEqual : Below; 269 } 270 271 Condition testMagic(Condition cond, Register tag) { 272 MOZ_ASSERT(cond == Equal || cond == NotEqual); 273 cmp32(tag, ImmTag(JSVAL_TAG_MAGIC)); 274 return cond; 275 } 276 Condition testError(Condition cond, Register tag) { 277 return testMagic(cond, tag); 278 } 279 Condition testPrimitive(Condition cond, Register tag) { 280 MOZ_ASSERT(cond == Equal || cond == NotEqual); 281 cmp32(tag, ImmTag(JS::detail::ValueUpperExclPrimitiveTag)); 282 return cond == Equal ? Below : AboveOrEqual; 283 } 284 285 Condition testUndefined(Condition cond, const ValueOperand& src) { 286 ScratchRegisterScope scratch(asMasm()); 287 splitTag(src, scratch); 288 return testUndefined(cond, scratch); 289 } 290 Condition testInt32(Condition cond, const ValueOperand& src) { 291 ScratchRegisterScope scratch(asMasm()); 292 splitTag(src, scratch); 293 return testInt32(cond, scratch); 294 } 295 Condition testBoolean(Condition cond, const ValueOperand& src) { 296 ScratchRegisterScope scratch(asMasm()); 297 splitTag(src, scratch); 298 return testBoolean(cond, scratch); 299 } 300 Condition testDouble(Condition cond, const ValueOperand& src) { 301 ScratchRegisterScope scratch(asMasm()); 302 splitTag(src, scratch); 303 return testDouble(cond, scratch); 304 } 305 Condition testNumber(Condition cond, const ValueOperand& src) { 306 ScratchRegisterScope scratch(asMasm()); 307 splitTag(src, scratch); 308 return testNumber(cond, scratch); 309 } 310 Condition testNull(Condition cond, const ValueOperand& src) { 311 ScratchRegisterScope scratch(asMasm()); 312 splitTag(src, scratch); 313 return testNull(cond, scratch); 314 } 315 Condition testString(Condition cond, const ValueOperand& src) { 316 ScratchRegisterScope scratch(asMasm()); 317 splitTag(src, scratch); 318 return testString(cond, scratch); 319 } 320 Condition testSymbol(Condition cond, const ValueOperand& src) { 321 ScratchRegisterScope scratch(asMasm()); 322 splitTag(src, scratch); 323 return testSymbol(cond, scratch); 324 } 325 Condition testBigInt(Condition cond, const ValueOperand& src) { 326 ScratchRegisterScope scratch(asMasm()); 327 splitTag(src, scratch); 328 return testBigInt(cond, scratch); 329 } 330 Condition testObject(Condition cond, const ValueOperand& src) { 331 ScratchRegisterScope scratch(asMasm()); 332 splitTag(src, scratch); 333 return testObject(cond, scratch); 334 } 335 Condition testGCThing(Condition cond, const ValueOperand& src) { 336 ScratchRegisterScope scratch(asMasm()); 337 splitTag(src, scratch); 338 return testGCThing(cond, scratch); 339 } 340 Condition testPrimitive(Condition cond, const ValueOperand& src) { 341 ScratchRegisterScope scratch(asMasm()); 342 splitTag(src, scratch); 343 return testPrimitive(cond, scratch); 344 } 345 346 Condition testUndefined(Condition cond, const Address& src) { 347 cmp32(ToUpper32(src), 348 Imm32(Upper32Of(GetShiftedTag(JSVAL_TYPE_UNDEFINED)))); 349 return cond; 350 } 351 Condition testInt32(Condition cond, const Address& src) { 352 cmp32(ToUpper32(src), Imm32(Upper32Of(GetShiftedTag(JSVAL_TYPE_INT32)))); 353 return cond; 354 } 355 Condition testBoolean(Condition cond, const Address& src) { 356 cmp32(ToUpper32(src), Imm32(Upper32Of(GetShiftedTag(JSVAL_TYPE_BOOLEAN)))); 357 return cond; 358 } 359 Condition testDouble(Condition cond, const Address& src) { 360 ScratchRegisterScope scratch(asMasm()); 361 splitTag(src, scratch); 362 return testDouble(cond, scratch); 363 } 364 Condition testNumber(Condition cond, const Address& src) { 365 ScratchRegisterScope scratch(asMasm()); 366 splitTag(src, scratch); 367 return testNumber(cond, scratch); 368 } 369 Condition testNull(Condition cond, const Address& src) { 370 cmp32(ToUpper32(src), Imm32(Upper32Of(GetShiftedTag(JSVAL_TYPE_NULL)))); 371 return cond; 372 } 373 Condition testString(Condition cond, const Address& src) { 374 ScratchRegisterScope scratch(asMasm()); 375 splitTag(src, scratch); 376 return testString(cond, scratch); 377 } 378 Condition testSymbol(Condition cond, const Address& src) { 379 ScratchRegisterScope scratch(asMasm()); 380 splitTag(src, scratch); 381 return testSymbol(cond, scratch); 382 } 383 Condition testBigInt(Condition cond, const Address& src) { 384 ScratchRegisterScope scratch(asMasm()); 385 splitTag(src, scratch); 386 return testBigInt(cond, scratch); 387 } 388 Condition testObject(Condition cond, const Address& src) { 389 ScratchRegisterScope scratch(asMasm()); 390 splitTag(src, scratch); 391 return testObject(cond, scratch); 392 } 393 Condition testPrimitive(Condition cond, const Address& src) { 394 ScratchRegisterScope scratch(asMasm()); 395 splitTag(src, scratch); 396 return testPrimitive(cond, scratch); 397 } 398 Condition testGCThing(Condition cond, const Address& src) { 399 ScratchRegisterScope scratch(asMasm()); 400 splitTag(src, scratch); 401 return testGCThing(cond, scratch); 402 } 403 Condition testMagic(Condition cond, const Address& src) { 404 ScratchRegisterScope scratch(asMasm()); 405 splitTag(src, scratch); 406 return testMagic(cond, scratch); 407 } 408 409 Condition testUndefined(Condition cond, const BaseIndex& src) { 410 ScratchRegisterScope scratch(asMasm()); 411 splitTag(src, scratch); 412 return testUndefined(cond, scratch); 413 } 414 Condition testNull(Condition cond, const BaseIndex& src) { 415 ScratchRegisterScope scratch(asMasm()); 416 splitTag(src, scratch); 417 return testNull(cond, scratch); 418 } 419 Condition testBoolean(Condition cond, const BaseIndex& src) { 420 ScratchRegisterScope scratch(asMasm()); 421 splitTag(src, scratch); 422 return testBoolean(cond, scratch); 423 } 424 Condition testString(Condition cond, const BaseIndex& src) { 425 ScratchRegisterScope scratch(asMasm()); 426 splitTag(src, scratch); 427 return testString(cond, scratch); 428 } 429 Condition testSymbol(Condition cond, const BaseIndex& src) { 430 ScratchRegisterScope scratch(asMasm()); 431 splitTag(src, scratch); 432 return testSymbol(cond, scratch); 433 } 434 Condition testBigInt(Condition cond, const BaseIndex& src) { 435 ScratchRegisterScope scratch(asMasm()); 436 splitTag(src, scratch); 437 return testBigInt(cond, scratch); 438 } 439 Condition testInt32(Condition cond, const BaseIndex& src) { 440 ScratchRegisterScope scratch(asMasm()); 441 splitTag(src, scratch); 442 return testInt32(cond, scratch); 443 } 444 Condition testObject(Condition cond, const BaseIndex& src) { 445 ScratchRegisterScope scratch(asMasm()); 446 splitTag(src, scratch); 447 return testObject(cond, scratch); 448 } 449 Condition testDouble(Condition cond, const BaseIndex& src) { 450 ScratchRegisterScope scratch(asMasm()); 451 splitTag(src, scratch); 452 return testDouble(cond, scratch); 453 } 454 Condition testMagic(Condition cond, const BaseIndex& src) { 455 ScratchRegisterScope scratch(asMasm()); 456 splitTag(src, scratch); 457 return testMagic(cond, scratch); 458 } 459 Condition testGCThing(Condition cond, const BaseIndex& src) { 460 ScratchRegisterScope scratch(asMasm()); 461 splitTag(src, scratch); 462 return testGCThing(cond, scratch); 463 } 464 465 Condition isMagic(Condition cond, const ValueOperand& src, JSWhyMagic why) { 466 uint64_t magic = MagicValue(why).asRawBits(); 467 cmpPtr(src.valueReg(), ImmWord(magic)); 468 return cond; 469 } 470 471 void cmpPtr(Register lhs, const ImmWord rhs) { 472 ScratchRegisterScope scratch(asMasm()); 473 MOZ_ASSERT(lhs != scratch); 474 if (intptr_t(rhs.value) <= INT32_MAX && intptr_t(rhs.value) >= INT32_MIN) { 475 cmpPtr(lhs, Imm32(int32_t(rhs.value))); 476 } else { 477 movePtr(rhs, scratch); 478 cmpPtr(lhs, scratch); 479 } 480 } 481 void cmpPtr(Register lhs, const ImmPtr rhs) { 482 cmpPtr(lhs, ImmWord(uintptr_t(rhs.value))); 483 } 484 void cmpPtr(Register lhs, const ImmGCPtr rhs) { 485 ScratchRegisterScope scratch(asMasm()); 486 MOZ_ASSERT(lhs != scratch); 487 movePtr(rhs, scratch); 488 cmpPtr(lhs, scratch); 489 } 490 void cmpPtr(Register lhs, const Imm32 rhs) { cmpq(rhs, lhs); } 491 void cmpPtr(const Operand& lhs, const ImmGCPtr rhs) { 492 ScratchRegisterScope scratch(asMasm()); 493 MOZ_ASSERT(!lhs.containsReg(scratch)); 494 movePtr(rhs, scratch); 495 cmpPtr(lhs, scratch); 496 } 497 void cmpPtr(const Operand& lhs, const ImmWord rhs) { 498 if ((intptr_t)rhs.value <= INT32_MAX && (intptr_t)rhs.value >= INT32_MIN) { 499 cmpPtr(lhs, Imm32((int32_t)rhs.value)); 500 } else { 501 ScratchRegisterScope scratch(asMasm()); 502 movePtr(rhs, scratch); 503 cmpPtr(lhs, scratch); 504 } 505 } 506 void cmpPtr(const Operand& lhs, const ImmPtr rhs) { 507 cmpPtr(lhs, ImmWord(uintptr_t(rhs.value))); 508 } 509 void cmpPtr(const Address& lhs, const ImmGCPtr rhs) { 510 cmpPtr(Operand(lhs), rhs); 511 } 512 void cmpPtr(const Address& lhs, const ImmWord rhs) { 513 cmpPtr(Operand(lhs), rhs); 514 } 515 void cmpPtr(const Address& lhs, const ImmPtr rhs) { 516 cmpPtr(lhs, ImmWord(uintptr_t(rhs.value))); 517 } 518 void cmpPtr(const Operand& lhs, Register rhs) { cmpq(rhs, lhs); } 519 void cmpPtr(Register lhs, const Operand& rhs) { cmpq(rhs, lhs); } 520 void cmpPtr(const Operand& lhs, const Imm32 rhs) { cmpq(rhs, lhs); } 521 void cmpPtr(const Address& lhs, Register rhs) { cmpPtr(Operand(lhs), rhs); } 522 void cmpPtr(Register lhs, Register rhs) { cmpq(rhs, lhs); } 523 void testPtr(Register lhs, Register rhs) { testq(rhs, lhs); } 524 void testPtr(Register lhs, Imm32 rhs) { testq(rhs, lhs); } 525 void testPtr(Register lhs, ImmWord rhs) { test64(lhs, Imm64(rhs.value)); } 526 void testPtr(const Operand& lhs, Imm32 rhs) { testq(rhs, lhs); } 527 void test64(Register lhs, Register rhs) { testq(rhs, lhs); } 528 void test64(Register lhs, const Imm64 rhs) { 529 if ((intptr_t)rhs.value <= INT32_MAX && (intptr_t)rhs.value >= INT32_MIN) { 530 testq(Imm32((int32_t)rhs.value), lhs); 531 } else { 532 ScratchRegisterScope scratch(asMasm()); 533 movq(ImmWord(rhs.value), scratch); 534 testq(scratch, lhs); 535 } 536 } 537 538 // Compare-then-conditionally-move/load, for integer types 539 template <size_t CmpSize, size_t MoveSize> 540 void cmpMove(Condition cond, Register lhs, Register rhs, Register falseVal, 541 Register trueValAndDest); 542 543 template <size_t CmpSize, size_t MoveSize> 544 void cmpMove(Condition cond, Register lhs, const Address& rhs, 545 Register falseVal, Register trueValAndDest); 546 547 template <size_t CmpSize, size_t LoadSize> 548 void cmpLoad(Condition cond, Register lhs, Register rhs, 549 const Address& falseVal, Register trueValAndDest); 550 551 template <size_t CmpSize, size_t LoadSize> 552 void cmpLoad(Condition cond, Register lhs, const Address& rhs, 553 const Address& falseVal, Register trueValAndDest); 554 555 ///////////////////////////////////////////////////////////////// 556 // Common interface. 557 ///////////////////////////////////////////////////////////////// 558 559 void movePtr(Register src, Register dest) { movq(src, dest); } 560 void movePtr(Register src, const Operand& dest) { movq(src, dest); } 561 void movePtr(ImmWord imm, Register dest) { mov(imm, dest); } 562 void movePtr(ImmPtr imm, Register dest) { mov(imm, dest); } 563 void movePtr(wasm::SymbolicAddress imm, Register dest) { mov(imm, dest); } 564 void movePtr(ImmGCPtr imm, Register dest) { movq(imm, dest); } 565 void loadPtr(AbsoluteAddress address, Register dest) { 566 if (X86Encoding::IsAddressImmediate(address.addr)) { 567 movq(Operand(address), dest); 568 } else { 569 ScratchRegisterScope scratch(asMasm()); 570 mov(ImmPtr(address.addr), scratch); 571 loadPtr(Address(scratch, 0x0), dest); 572 } 573 } 574 FaultingCodeOffset loadPtr(const Address& address, Register dest) { 575 FaultingCodeOffset fco = FaultingCodeOffset(currentOffset()); 576 movq(Operand(address), dest); 577 return fco; 578 } 579 void load64(const Address& address, Register dest) { 580 movq(Operand(address), dest); 581 } 582 void loadPtr(const Operand& src, Register dest) { movq(src, dest); } 583 FaultingCodeOffset loadPtr(const BaseIndex& src, Register dest) { 584 FaultingCodeOffset fco = FaultingCodeOffset(currentOffset()); 585 movq(Operand(src), dest); 586 return fco; 587 } 588 void loadPrivate(const Address& src, Register dest) { loadPtr(src, dest); } 589 void load32(AbsoluteAddress address, Register dest) { 590 if (X86Encoding::IsAddressImmediate(address.addr)) { 591 movl(Operand(address), dest); 592 } else { 593 ScratchRegisterScope scratch(asMasm()); 594 mov(ImmPtr(address.addr), scratch); 595 load32(Address(scratch, 0x0), dest); 596 } 597 } 598 void load64(const Operand& address, Register64 dest) { 599 movq(address, dest.reg); 600 } 601 FaultingCodeOffset load64(const Address& address, Register64 dest) { 602 FaultingCodeOffset fco = FaultingCodeOffset(currentOffset()); 603 movq(Operand(address), dest.reg); 604 return fco; 605 } 606 FaultingCodeOffset load64(const BaseIndex& address, Register64 dest) { 607 FaultingCodeOffset fco = FaultingCodeOffset(currentOffset()); 608 movq(Operand(address), dest.reg); 609 return fco; 610 } 611 template <typename S> 612 void load64Unaligned(const S& src, Register64 dest) { 613 load64(src, dest); 614 } 615 template <typename T> 616 void storePtr(ImmWord imm, T address) { 617 if ((intptr_t)imm.value <= INT32_MAX && (intptr_t)imm.value >= INT32_MIN) { 618 movq(Imm32((int32_t)imm.value), Operand(address)); 619 } else { 620 ScratchRegisterScope scratch(asMasm()); 621 mov(imm, scratch); 622 movq(scratch, Operand(address)); 623 } 624 } 625 template <typename T> 626 void storePtr(ImmPtr imm, T address) { 627 storePtr(ImmWord(uintptr_t(imm.value)), address); 628 } 629 template <typename T> 630 void storePtr(ImmGCPtr imm, T address) { 631 ScratchRegisterScope scratch(asMasm()); 632 movq(imm, scratch); 633 movq(scratch, Operand(address)); 634 } 635 FaultingCodeOffset storePtr(Register src, const Address& address) { 636 FaultingCodeOffset fco = FaultingCodeOffset(currentOffset()); 637 movq(src, Operand(address)); 638 return fco; 639 } 640 void store64(Register src, const Address& address) { 641 movq(src, Operand(address)); 642 } 643 void store64(Register64 src, const Operand& address) { 644 movq(src.reg, address); 645 } 646 FaultingCodeOffset storePtr(Register src, const BaseIndex& address) { 647 FaultingCodeOffset fco = FaultingCodeOffset(currentOffset()); 648 movq(src, Operand(address)); 649 return fco; 650 } 651 void storePtr(Register src, const Operand& dest) { movq(src, dest); } 652 void storePtr(Register src, AbsoluteAddress address) { 653 if (X86Encoding::IsAddressImmediate(address.addr)) { 654 movq(src, Operand(address)); 655 } else { 656 ScratchRegisterScope scratch(asMasm()); 657 mov(ImmPtr(address.addr), scratch); 658 storePtr(src, Address(scratch, 0x0)); 659 } 660 } 661 void store32(Register src, AbsoluteAddress address) { 662 if (X86Encoding::IsAddressImmediate(address.addr)) { 663 movl(src, Operand(address)); 664 } else { 665 ScratchRegisterScope scratch(asMasm()); 666 mov(ImmPtr(address.addr), scratch); 667 store32(src, Address(scratch, 0x0)); 668 } 669 } 670 void store16(Register src, AbsoluteAddress address) { 671 if (X86Encoding::IsAddressImmediate(address.addr)) { 672 movw(src, Operand(address)); 673 } else { 674 ScratchRegisterScope scratch(asMasm()); 675 mov(ImmPtr(address.addr), scratch); 676 store16(src, Address(scratch, 0x0)); 677 } 678 } 679 FaultingCodeOffset store64(Register64 src, Address address) { 680 FaultingCodeOffset fco = FaultingCodeOffset(currentOffset()); 681 storePtr(src.reg, address); 682 return fco; 683 } 684 FaultingCodeOffset store64(Register64 src, const BaseIndex& address) { 685 return storePtr(src.reg, address); 686 } 687 void store64(Imm64 imm, Address address) { 688 storePtr(ImmWord(imm.value), address); 689 } 690 void store64(Imm64 imm, const BaseIndex& address) { 691 storePtr(ImmWord(imm.value), address); 692 } 693 template <typename S, typename T> 694 void store64Unaligned(const S& src, const T& dest) { 695 store64(src, dest); 696 } 697 698 void splitTag(Register src, Register dest) { 699 if (src != dest) { 700 movq(src, dest); 701 } 702 shrq(Imm32(JSVAL_TAG_SHIFT), dest); 703 } 704 void splitTag(const ValueOperand& operand, Register dest) { 705 splitTag(operand.valueReg(), dest); 706 } 707 void splitTag(const Operand& operand, Register dest) { 708 movq(operand, dest); 709 shrq(Imm32(JSVAL_TAG_SHIFT), dest); 710 } 711 void splitTag(const Address& operand, Register dest) { 712 splitTag(Operand(operand), dest); 713 } 714 void splitTag(const BaseIndex& operand, Register dest) { 715 splitTag(Operand(operand), dest); 716 } 717 718 // Extracts the tag of a value and places it in tag. 719 void splitTagForTest(const ValueOperand& value, ScratchTagScope& tag) { 720 splitTag(value, tag); 721 } 722 void cmpTag(const ValueOperand& operand, ImmTag tag) { 723 ScratchTagScope reg(asMasm(), operand); 724 splitTagForTest(operand, reg); 725 cmp32(reg, tag); 726 } 727 728 Condition testMagic(Condition cond, const ValueOperand& src) { 729 ScratchTagScope scratch(asMasm(), src); 730 splitTagForTest(src, scratch); 731 return testMagic(cond, scratch); 732 } 733 Condition testError(Condition cond, const ValueOperand& src) { 734 return testMagic(cond, src); 735 } 736 737 void testNullSet(Condition cond, const ValueOperand& value, Register dest) { 738 bool destIsZero = maybeEmitSetZeroByteRegister(value, dest); 739 cond = testNull(cond, value); 740 emitSet(cond, dest, destIsZero); 741 } 742 743 void testObjectSet(Condition cond, const ValueOperand& value, Register dest) { 744 bool destIsZero = maybeEmitSetZeroByteRegister(value, dest); 745 cond = testObject(cond, value); 746 emitSet(cond, dest, destIsZero); 747 } 748 749 void testUndefinedSet(Condition cond, const ValueOperand& value, 750 Register dest) { 751 bool destIsZero = maybeEmitSetZeroByteRegister(value, dest); 752 cond = testUndefined(cond, value); 753 emitSet(cond, dest, destIsZero); 754 } 755 756 void boxDouble(FloatRegister src, const ValueOperand& dest, FloatRegister) { 757 vmovq(src, dest.valueReg()); 758 } 759 void boxNonDouble(JSValueType type, Register src, const ValueOperand& dest) { 760 boxValue(type, src, dest.valueReg()); 761 } 762 void boxNonDouble(Register type, Register src, const ValueOperand& dest) { 763 boxValue(type, src, dest.valueReg()); 764 } 765 766 // Note that the |dest| register here may be ScratchReg, so we shouldn't 767 // use it. 768 void unboxInt32(const ValueOperand& src, Register dest) { 769 movl(src.valueReg(), dest); 770 } 771 void unboxInt32(const Operand& src, Register dest) { movl(src, dest); } 772 void unboxInt32(const Address& src, Register dest) { 773 unboxInt32(Operand(src), dest); 774 } 775 void unboxInt32(const BaseIndex& src, Register dest) { 776 unboxInt32(Operand(src), dest); 777 } 778 template <typename T> 779 void unboxDouble(const T& src, FloatRegister dest) { 780 loadDouble(Operand(src), dest); 781 } 782 783 void unboxBoolean(const ValueOperand& src, Register dest) { 784 movl(src.valueReg(), dest); 785 } 786 void unboxBoolean(const Operand& src, Register dest) { movl(src, dest); } 787 void unboxBoolean(const Address& src, Register dest) { 788 unboxBoolean(Operand(src), dest); 789 } 790 void unboxBoolean(const BaseIndex& src, Register dest) { 791 unboxBoolean(Operand(src), dest); 792 } 793 794 void unboxMagic(const ValueOperand& src, Register dest) { 795 movl(src.valueReg(), dest); 796 } 797 798 void unboxDouble(const ValueOperand& src, FloatRegister dest) { 799 vmovq(src.valueReg(), dest); 800 } 801 802 void notBoolean(const ValueOperand& val) { xorq(Imm32(1), val.valueReg()); } 803 804 void unboxNonDouble(const ValueOperand& src, Register dest, 805 JSValueType type) { 806 MOZ_ASSERT(type != JSVAL_TYPE_DOUBLE); 807 if (type == JSVAL_TYPE_INT32 || type == JSVAL_TYPE_BOOLEAN) { 808 movl(src.valueReg(), dest); 809 return; 810 } 811 if (src.valueReg() == dest) { 812 ScratchRegisterScope scratch(asMasm()); 813 mov(ImmShiftedTag(type), scratch); 814 xorq(scratch, dest); 815 } else { 816 mov(ImmShiftedTag(type), dest); 817 xorq(src.valueReg(), dest); 818 } 819 } 820 void unboxNonDouble(const Operand& src, Register dest, JSValueType type) { 821 MOZ_ASSERT(type != JSVAL_TYPE_DOUBLE); 822 if (type == JSVAL_TYPE_INT32 || type == JSVAL_TYPE_BOOLEAN) { 823 movl(src, dest); 824 return; 825 } 826 // Explicitly permits |dest| to be used in |src|. 827 ScratchRegisterScope scratch(asMasm()); 828 MOZ_ASSERT(dest != scratch); 829 if (src.containsReg(dest)) { 830 mov(ImmShiftedTag(type), scratch); 831 // If src is already a register, then src and dest are the same 832 // thing and we don't need to move anything into dest. 833 if (src.kind() != Operand::REG) { 834 movq(src, dest); 835 } 836 xorq(scratch, dest); 837 } else { 838 mov(ImmShiftedTag(type), dest); 839 xorq(src, dest); 840 } 841 } 842 void unboxNonDouble(const Address& src, Register dest, JSValueType type) { 843 unboxNonDouble(Operand(src), dest, type); 844 } 845 void unboxNonDouble(const BaseIndex& src, Register dest, JSValueType type) { 846 unboxNonDouble(Operand(src), dest, type); 847 } 848 849 void unboxString(const ValueOperand& src, Register dest) { 850 unboxNonDouble(src, dest, JSVAL_TYPE_STRING); 851 } 852 void unboxString(const Operand& src, Register dest) { 853 unboxNonDouble(src, dest, JSVAL_TYPE_STRING); 854 } 855 void unboxString(const Address& src, Register dest) { 856 unboxNonDouble(src, dest, JSVAL_TYPE_STRING); 857 } 858 859 void unboxSymbol(const ValueOperand& src, Register dest) { 860 unboxNonDouble(src, dest, JSVAL_TYPE_SYMBOL); 861 } 862 void unboxSymbol(const Operand& src, Register dest) { 863 unboxNonDouble(src, dest, JSVAL_TYPE_SYMBOL); 864 } 865 866 void unboxBigInt(const ValueOperand& src, Register dest) { 867 unboxNonDouble(src, dest, JSVAL_TYPE_BIGINT); 868 } 869 void unboxBigInt(const Operand& src, Register dest) { 870 unboxNonDouble(src, dest, JSVAL_TYPE_BIGINT); 871 } 872 void unboxBigInt(const Address& src, Register dest) { 873 unboxNonDouble(src, dest, JSVAL_TYPE_BIGINT); 874 } 875 876 void unboxObject(const ValueOperand& src, Register dest) { 877 unboxNonDouble(src, dest, JSVAL_TYPE_OBJECT); 878 } 879 void unboxObject(const Operand& src, Register dest) { 880 unboxNonDouble(src, dest, JSVAL_TYPE_OBJECT); 881 } 882 void unboxObject(const Address& src, Register dest) { 883 unboxNonDouble(Operand(src), dest, JSVAL_TYPE_OBJECT); 884 } 885 void unboxObject(const BaseIndex& src, Register dest) { 886 unboxNonDouble(Operand(src), dest, JSVAL_TYPE_OBJECT); 887 } 888 889 // This should only be used for GC barrier code, to unbox a GC thing Value. 890 // It's fine there because we don't depend on the actual Value type (all Cells 891 // are treated the same way). In almost all other cases this would be 892 // Spectre-unsafe - use unboxNonDouble and friends instead. 893 void unboxGCThingForGCBarrier(const Address& src, Register dest) { 894 movq(ImmWord(JS::detail::ValueGCThingPayloadMask), dest); 895 andq(Operand(src), dest); 896 } 897 void unboxGCThingForGCBarrier(const ValueOperand& src, Register dest) { 898 MOZ_ASSERT(src.valueReg() != dest); 899 movq(ImmWord(JS::detail::ValueGCThingPayloadMask), dest); 900 andq(src.valueReg(), dest); 901 } 902 903 void unboxWasmAnyRefGCThingForGCBarrier(const Address& src, Register dest) { 904 movq(ImmWord(wasm::AnyRef::GCThingMask), dest); 905 andq(Operand(src), dest); 906 } 907 908 // Like unboxGCThingForGCBarrier, but loads the GC thing's chunk base. 909 void getGCThingValueChunk(const Address& src, Register dest) { 910 movq(ImmWord(JS::detail::ValueGCThingPayloadChunkMask), dest); 911 andq(Operand(src), dest); 912 } 913 void getGCThingValueChunk(const ValueOperand& src, Register dest) { 914 MOZ_ASSERT(src.valueReg() != dest); 915 movq(ImmWord(JS::detail::ValueGCThingPayloadChunkMask), dest); 916 andq(src.valueReg(), dest); 917 } 918 919 void getWasmAnyRefGCThingChunk(Register src, Register dest) { 920 MOZ_ASSERT(src != dest); 921 movq(ImmWord(wasm::AnyRef::GCThingChunkMask), dest); 922 andq(src, dest); 923 } 924 925 inline void fallibleUnboxPtrImpl(const Operand& src, Register dest, 926 JSValueType type, Label* fail); 927 928 // Extended unboxing API. If the payload is already in a register, returns 929 // that register. Otherwise, provides a move to the given scratch register, 930 // and returns that. 931 [[nodiscard]] Register extractObject(const Address& address, 932 Register scratch) { 933 MOZ_ASSERT(scratch != ScratchReg); 934 unboxObject(address, scratch); 935 return scratch; 936 } 937 [[nodiscard]] Register extractObject(const ValueOperand& value, 938 Register scratch) { 939 MOZ_ASSERT(scratch != ScratchReg); 940 unboxObject(value, scratch); 941 return scratch; 942 } 943 [[nodiscard]] Register extractSymbol(const ValueOperand& value, 944 Register scratch) { 945 MOZ_ASSERT(scratch != ScratchReg); 946 unboxSymbol(value, scratch); 947 return scratch; 948 } 949 [[nodiscard]] Register extractInt32(const ValueOperand& value, 950 Register scratch) { 951 MOZ_ASSERT(scratch != ScratchReg); 952 unboxInt32(value, scratch); 953 return scratch; 954 } 955 [[nodiscard]] Register extractBoolean(const ValueOperand& value, 956 Register scratch) { 957 MOZ_ASSERT(scratch != ScratchReg); 958 unboxBoolean(value, scratch); 959 return scratch; 960 } 961 [[nodiscard]] Register extractTag(const Address& address, Register scratch) { 962 MOZ_ASSERT(scratch != ScratchReg); 963 loadPtr(address, scratch); 964 splitTag(scratch, scratch); 965 return scratch; 966 } 967 [[nodiscard]] Register extractTag(const ValueOperand& value, 968 Register scratch) { 969 MOZ_ASSERT(scratch != ScratchReg); 970 splitTag(value, scratch); 971 return scratch; 972 } 973 974 inline void unboxValue(const ValueOperand& src, AnyRegister dest, 975 JSValueType type); 976 977 void loadConstantDouble(double d, FloatRegister dest); 978 void loadConstantFloat32(float f, FloatRegister dest); 979 980 void loadConstantSimd128Int(const SimdConstant& v, FloatRegister dest); 981 void loadConstantSimd128Float(const SimdConstant& v, FloatRegister dest); 982 void vpaddbSimd128(const SimdConstant& v, FloatRegister lhs, 983 FloatRegister dest); 984 void vpaddwSimd128(const SimdConstant& v, FloatRegister lhs, 985 FloatRegister dest); 986 void vpadddSimd128(const SimdConstant& v, FloatRegister lhs, 987 FloatRegister dest); 988 void vpaddqSimd128(const SimdConstant& v, FloatRegister lhs, 989 FloatRegister dest); 990 void vpsubbSimd128(const SimdConstant& v, FloatRegister lhs, 991 FloatRegister dest); 992 void vpsubwSimd128(const SimdConstant& v, FloatRegister lhs, 993 FloatRegister dest); 994 void vpsubdSimd128(const SimdConstant& v, FloatRegister lhs, 995 FloatRegister dest); 996 void vpsubqSimd128(const SimdConstant& v, FloatRegister lhs, 997 FloatRegister dest); 998 void vpmullwSimd128(const SimdConstant& v, FloatRegister lhs, 999 FloatRegister dest); 1000 void vpmulldSimd128(const SimdConstant& v, FloatRegister lhs, 1001 FloatRegister dest); 1002 void vpaddsbSimd128(const SimdConstant& v, FloatRegister lhs, 1003 FloatRegister dest); 1004 void vpaddusbSimd128(const SimdConstant& v, FloatRegister lhs, 1005 FloatRegister dest); 1006 void vpaddswSimd128(const SimdConstant& v, FloatRegister lhs, 1007 FloatRegister dest); 1008 void vpadduswSimd128(const SimdConstant& v, FloatRegister lhs, 1009 FloatRegister dest); 1010 void vpsubsbSimd128(const SimdConstant& v, FloatRegister lhs, 1011 FloatRegister dest); 1012 void vpsubusbSimd128(const SimdConstant& v, FloatRegister lhs, 1013 FloatRegister dest); 1014 void vpsubswSimd128(const SimdConstant& v, FloatRegister lhs, 1015 FloatRegister dest); 1016 void vpsubuswSimd128(const SimdConstant& v, FloatRegister lhs, 1017 FloatRegister dest); 1018 void vpminsbSimd128(const SimdConstant& v, FloatRegister lhs, 1019 FloatRegister dest); 1020 void vpminubSimd128(const SimdConstant& v, FloatRegister lhs, 1021 FloatRegister dest); 1022 void vpminswSimd128(const SimdConstant& v, FloatRegister lhs, 1023 FloatRegister dest); 1024 void vpminuwSimd128(const SimdConstant& v, FloatRegister lhs, 1025 FloatRegister dest); 1026 void vpminsdSimd128(const SimdConstant& v, FloatRegister lhs, 1027 FloatRegister dest); 1028 void vpminudSimd128(const SimdConstant& v, FloatRegister lhs, 1029 FloatRegister dest); 1030 void vpmaxsbSimd128(const SimdConstant& v, FloatRegister lhs, 1031 FloatRegister dest); 1032 void vpmaxubSimd128(const SimdConstant& v, FloatRegister lhs, 1033 FloatRegister dest); 1034 void vpmaxswSimd128(const SimdConstant& v, FloatRegister lhs, 1035 FloatRegister dest); 1036 void vpmaxuwSimd128(const SimdConstant& v, FloatRegister lhs, 1037 FloatRegister dest); 1038 void vpmaxsdSimd128(const SimdConstant& v, FloatRegister lhs, 1039 FloatRegister dest); 1040 void vpmaxudSimd128(const SimdConstant& v, FloatRegister lhs, 1041 FloatRegister dest); 1042 void vpandSimd128(const SimdConstant& v, FloatRegister lhs, 1043 FloatRegister dest); 1044 void vpxorSimd128(const SimdConstant& v, FloatRegister lhs, 1045 FloatRegister dest); 1046 void vporSimd128(const SimdConstant& v, FloatRegister lhs, 1047 FloatRegister dest); 1048 void vaddpsSimd128(const SimdConstant& v, FloatRegister lhs, 1049 FloatRegister dest); 1050 void vaddpdSimd128(const SimdConstant& v, FloatRegister lhs, 1051 FloatRegister dest); 1052 void vsubpsSimd128(const SimdConstant& v, FloatRegister lhs, 1053 FloatRegister dest); 1054 void vsubpdSimd128(const SimdConstant& v, FloatRegister lhs, 1055 FloatRegister dest); 1056 void vdivpsSimd128(const SimdConstant& v, FloatRegister lhs, 1057 FloatRegister dest); 1058 void vdivpdSimd128(const SimdConstant& v, FloatRegister lhs, 1059 FloatRegister dest); 1060 void vmulpsSimd128(const SimdConstant& v, FloatRegister lhs, 1061 FloatRegister dest); 1062 void vmulpdSimd128(const SimdConstant& v, FloatRegister lhs, 1063 FloatRegister dest); 1064 void vandpsSimd128(const SimdConstant& v, FloatRegister lhs, 1065 FloatRegister dest); 1066 void vandpdSimd128(const SimdConstant& v, FloatRegister lhs, 1067 FloatRegister dest); 1068 void vxorpsSimd128(const SimdConstant& v, FloatRegister lhs, 1069 FloatRegister dest); 1070 void vxorpdSimd128(const SimdConstant& v, FloatRegister lhs, 1071 FloatRegister dest); 1072 void vminpdSimd128(const SimdConstant& v, FloatRegister lhs, 1073 FloatRegister dest); 1074 void vpacksswbSimd128(const SimdConstant& v, FloatRegister lhs, 1075 FloatRegister dest); 1076 void vpackuswbSimd128(const SimdConstant& v, FloatRegister lhs, 1077 FloatRegister dest); 1078 void vpackssdwSimd128(const SimdConstant& v, FloatRegister lhs, 1079 FloatRegister dest); 1080 void vpackusdwSimd128(const SimdConstant& v, FloatRegister lhs, 1081 FloatRegister dest); 1082 void vpunpckldqSimd128(const SimdConstant& v, FloatRegister lhs, 1083 FloatRegister dest); 1084 void vunpcklpsSimd128(const SimdConstant& v, FloatRegister lhs, 1085 FloatRegister dest); 1086 void vpshufbSimd128(const SimdConstant& v, FloatRegister lhs, 1087 FloatRegister dest); 1088 void vptestSimd128(const SimdConstant& v, FloatRegister lhs); 1089 void vpmaddwdSimd128(const SimdConstant& v, FloatRegister lhs, 1090 FloatRegister dest); 1091 void vpcmpeqbSimd128(const SimdConstant& v, FloatRegister lhs, 1092 FloatRegister dest); 1093 void vpcmpgtbSimd128(const SimdConstant& v, FloatRegister lhs, 1094 FloatRegister dest); 1095 void vpcmpeqwSimd128(const SimdConstant& v, FloatRegister lhs, 1096 FloatRegister dest); 1097 void vpcmpgtwSimd128(const SimdConstant& v, FloatRegister lhs, 1098 FloatRegister dest); 1099 void vpcmpeqdSimd128(const SimdConstant& v, FloatRegister lhs, 1100 FloatRegister dest); 1101 void vpcmpgtdSimd128(const SimdConstant& v, FloatRegister lhs, 1102 FloatRegister dest); 1103 void vcmpeqpsSimd128(const SimdConstant& v, FloatRegister lhs, 1104 FloatRegister dest); 1105 void vcmpneqpsSimd128(const SimdConstant& v, FloatRegister lhs, 1106 FloatRegister dest); 1107 void vcmpltpsSimd128(const SimdConstant& v, FloatRegister lhs, 1108 FloatRegister dest); 1109 void vcmplepsSimd128(const SimdConstant& v, FloatRegister lhs, 1110 FloatRegister dest); 1111 void vcmpgepsSimd128(const SimdConstant& v, FloatRegister lhs, 1112 FloatRegister dest); 1113 void vcmpeqpdSimd128(const SimdConstant& v, FloatRegister lhs, 1114 FloatRegister dest); 1115 void vcmpneqpdSimd128(const SimdConstant& v, FloatRegister lhs, 1116 FloatRegister dest); 1117 void vcmpltpdSimd128(const SimdConstant& v, FloatRegister lhs, 1118 FloatRegister dest); 1119 void vcmplepdSimd128(const SimdConstant& v, FloatRegister lhs, 1120 FloatRegister dest); 1121 void vpmaddubswSimd128(const SimdConstant& v, FloatRegister lhs, 1122 FloatRegister dest); 1123 void vpmuludqSimd128(const SimdConstant& v, FloatRegister lhs, 1124 FloatRegister dest); 1125 1126 public: 1127 Condition testInt32Truthy(bool truthy, const ValueOperand& operand) { 1128 test32(operand.valueReg(), operand.valueReg()); 1129 return truthy ? NonZero : Zero; 1130 } 1131 Condition testStringTruthy(bool truthy, const ValueOperand& value); 1132 Condition testBigIntTruthy(bool truthy, const ValueOperand& value); 1133 1134 template <typename T> 1135 inline void loadInt32OrDouble(const T& src, FloatRegister dest); 1136 1137 template <typename T> 1138 void loadUnboxedValue(const T& src, MIRType type, AnyRegister dest) { 1139 if (dest.isFloat()) { 1140 loadInt32OrDouble(src, dest.fpu()); 1141 } else { 1142 unboxNonDouble(Operand(src), dest.gpr(), ValueTypeFromMIRType(type)); 1143 } 1144 } 1145 1146 // Checks whether a double is representable as a 64-bit integer. If so, the 1147 // integer is written to the output register. Otherwise, a bailout is taken to 1148 // the given snapshot. This function overwrites the scratch float register. 1149 void convertDoubleToPtr(FloatRegister src, Register dest, Label* fail, 1150 bool negativeZeroCheck = true); 1151 1152 void convertUInt32ToDouble(Register src, FloatRegister dest) { 1153 // Zero the output register to break dependencies, see convertInt32ToDouble. 1154 zeroDouble(dest); 1155 1156 vcvtsq2sd(src, dest, dest); 1157 } 1158 1159 void convertUInt32ToFloat32(Register src, FloatRegister dest) { 1160 // Zero the output register to break dependencies, see convertInt32ToDouble. 1161 zeroDouble(dest); 1162 1163 vcvtsq2ss(src, dest, dest); 1164 } 1165 1166 void truncateFloat32ModUint32(FloatRegister src, Register dest) { 1167 // vcvttss2sq returns 0x8000000000000000 on failure. It fails if 1168 // 1. The input is non-finite (NaN or ±Infinity). 1169 // 2. The input's exponent is at least 63. 1170 // 1171 // In both cases the input is too large for an int32 and the truncated 1172 // result is zero. So unconditionally zeroing the upper 32-bits gives the 1173 // correct result for all inputs. 1174 1175 vcvttss2sq(src, dest); 1176 movl(dest, dest); // Zero upper 32-bits. 1177 } 1178 1179 inline void incrementInt32Value(const Address& addr); 1180 1181 void minMax32(Register lhs, Register rhs, Register dest, bool isMax); 1182 void minMax32(Register lhs, Imm32 rhs, Register dest, bool isMax); 1183 1184 void minMaxPtr(Register lhs, Register rhs, Register dest, bool isMax); 1185 void minMaxPtr(Register lhs, ImmWord rhs, Register dest, bool isMax); 1186 1187 public: 1188 void handleFailureWithHandlerTail(Label* profilerExitTail, Label* bailoutTail, 1189 uint32_t* returnValueCheckOffset); 1190 1191 // Instrumentation for entering and leaving the profiler. 1192 void profilerEnterFrame(Register framePtr, Register scratch); 1193 void profilerExitFrame(); 1194 }; 1195 1196 using MacroAssemblerSpecific = MacroAssemblerX64; 1197 1198 } // namespace jit 1199 } // namespace js 1200 1201 #endif /* jit_x64_MacroAssembler_x64_h */