Architecture-arm64.h (23278B)
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_Architecture_arm64_h 8 #define jit_arm64_Architecture_arm64_h 9 10 #include "mozilla/Assertions.h" 11 #include "mozilla/MathAlgorithms.h" 12 13 #include <algorithm> 14 15 #include "jit/arm64/vixl/Cpu-Features-vixl.h" 16 #include "jit/arm64/vixl/Instructions-vixl.h" 17 #include "jit/shared/Architecture-shared.h" 18 19 #include "js/Utility.h" 20 21 #define JS_HAS_HIDDEN_SP 22 static const uint32_t HiddenSPEncoding = vixl::kSPRegInternalCode; 23 24 namespace js { 25 namespace jit { 26 27 // AArch64 has 32 64-bit integer registers, x0 though x31. 28 // 29 // x31 (or, more accurately, the integer register with encoding 31, since 30 // there is no x31 per se) is special and functions as both the stack pointer 31 // and a zero register. 32 // 33 // The bottom 32 bits of each of the X registers is accessible as w0 through 34 // w31. The program counter is not accessible as a register. 35 // 36 // SIMD and scalar floating-point registers share a register bank. 37 // 32 bit float registers are s0 through s31. 38 // 64 bit double registers are d0 through d31. 39 // 128 bit SIMD registers are v0 through v31. 40 // e.g., s0 is the bottom 32 bits of d0, which is the bottom 64 bits of v0. 41 42 // AArch64 Calling Convention: 43 // x0 - x7: arguments and return value 44 // x8: indirect result (struct) location 45 // x9 - x15: temporary registers 46 // x16 - x17: intra-call-use registers (PLT, linker) 47 // x18: platform specific use (TLS) 48 // x19 - x28: callee-saved registers 49 // x29: frame pointer 50 // x30: link register 51 52 // AArch64 Calling Convention for Floats: 53 // d0 - d7: arguments and return value 54 // d8 - d15: callee-saved registers 55 // Bits 64:128 are not saved for v8-v15. 56 // d16 - d31: temporary registers 57 58 // AArch64 does not have soft float. 59 60 class Registers { 61 public: 62 enum RegisterID { 63 w0 = 0, 64 x0 = 0, 65 w1 = 1, 66 x1 = 1, 67 w2 = 2, 68 x2 = 2, 69 w3 = 3, 70 x3 = 3, 71 w4 = 4, 72 x4 = 4, 73 w5 = 5, 74 x5 = 5, 75 w6 = 6, 76 x6 = 6, 77 w7 = 7, 78 x7 = 7, 79 w8 = 8, 80 x8 = 8, 81 w9 = 9, 82 x9 = 9, 83 w10 = 10, 84 x10 = 10, 85 w11 = 11, 86 x11 = 11, 87 w12 = 12, 88 x12 = 12, 89 w13 = 13, 90 x13 = 13, 91 w14 = 14, 92 x14 = 14, 93 w15 = 15, 94 x15 = 15, 95 w16 = 16, 96 x16 = 16, 97 ip0 = 16, // MacroAssembler scratch register 1. 98 w17 = 17, 99 x17 = 17, 100 ip1 = 17, // MacroAssembler scratch register 2. 101 w18 = 18, 102 x18 = 18, 103 tls = 18, // Platform-specific use (TLS). 104 w19 = 19, 105 x19 = 19, 106 w20 = 20, 107 x20 = 20, 108 w21 = 21, 109 x21 = 21, 110 w22 = 22, 111 x22 = 22, 112 w23 = 23, 113 x23 = 23, 114 w24 = 24, 115 x24 = 24, 116 w25 = 25, 117 x25 = 25, 118 w26 = 26, 119 x26 = 26, 120 w27 = 27, 121 x27 = 27, 122 w28 = 28, 123 x28 = 28, 124 w29 = 29, 125 x29 = 29, 126 fp = 29, 127 w30 = 30, 128 x30 = 30, 129 lr = 30, 130 w31 = 31, 131 x31 = 31, 132 wzr = 31, 133 xzr = 31, 134 sp = 31, // Special: both stack pointer and a zero register. 135 }; 136 using Code = uint8_t; 137 using Encoding = uint32_t; 138 using SetType = uint32_t; 139 140 static const Code Invalid = 0xFF; 141 142 union RegisterContent { 143 uintptr_t r; 144 }; 145 146 static uint32_t SetSize(SetType x) { 147 static_assert(sizeof(SetType) == 4, "SetType must be 32 bits"); 148 return mozilla::CountPopulation32(x); 149 } 150 static uint32_t FirstBit(SetType x) { 151 return mozilla::CountTrailingZeroes32(x); 152 } 153 static uint32_t LastBit(SetType x) { 154 return 31 - mozilla::CountLeadingZeroes32(x); 155 } 156 157 static const char* GetName(uint32_t code) { 158 static const char* const Names[] = { 159 "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", 160 "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", 161 "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23", 162 "x24", "x25", "x26", "x27", "x28", "x29", "lr", "sp"}; 163 static_assert(Total == std::size(Names), "Table is the correct size"); 164 if (code >= Total) { 165 return "invalid"; 166 } 167 return Names[code]; 168 } 169 170 static Code FromName(const char* name); 171 172 static const uint32_t Total = 32; 173 static const uint32_t TotalPhys = 32; 174 static const uint32_t Allocatable = 175 27; // No named special-function registers. 176 177 static const SetType AllMask = 0xFFFFFFFF; 178 static const SetType NoneMask = 0x0; 179 180 static const SetType ArgRegMask = 181 (1 << Registers::x0) | (1 << Registers::x1) | (1 << Registers::x2) | 182 (1 << Registers::x3) | (1 << Registers::x4) | (1 << Registers::x5) | 183 (1 << Registers::x6) | (1 << Registers::x7); 184 185 static const SetType VolatileMask = 186 (1 << Registers::x0) | (1 << Registers::x1) | (1 << Registers::x2) | 187 (1 << Registers::x3) | (1 << Registers::x4) | (1 << Registers::x5) | 188 (1 << Registers::x6) | (1 << Registers::x7) | (1 << Registers::x8) | 189 (1 << Registers::x9) | (1 << Registers::x10) | (1 << Registers::x11) | 190 (1 << Registers::x12) | (1 << Registers::x13) | (1 << Registers::x14) | 191 (1 << Registers::x15) | (1 << Registers::x16) | (1 << Registers::x17) | 192 (1 << Registers::x18); 193 194 static const SetType NonVolatileMask = 195 (1 << Registers::x19) | (1 << Registers::x20) | (1 << Registers::x21) | 196 (1 << Registers::x22) | (1 << Registers::x23) | (1 << Registers::x24) | 197 (1 << Registers::x25) | (1 << Registers::x26) | (1 << Registers::x27) | 198 (1 << Registers::x28) | (1 << Registers::x29) | (1 << Registers::x30); 199 200 static const SetType NonAllocatableMask = 201 (1 << Registers::x28) | // PseudoStackPointer. 202 (1 << Registers::ip0) | // First scratch register. 203 (1 << Registers::ip1) | // Second scratch register. 204 (1 << Registers::tls) | (1 << Registers::lr) | (1 << Registers::sp) | 205 (1 << Registers::fp); 206 207 static const SetType WrapperMask = VolatileMask; 208 209 // Registers returned from a JS -> JS call. 210 static const SetType JSCallMask = (1 << Registers::x2); 211 212 // Registers returned from a JS -> C call. 213 static const SetType CallMask = (1 << Registers::x0); 214 215 static const SetType AllocatableMask = AllMask & ~NonAllocatableMask; 216 }; 217 218 // Smallest integer type that can hold a register bitmask. 219 using PackedRegisterMask = uint32_t; 220 221 template <typename T> 222 class TypedRegisterSet; 223 224 // 128-bit bitset for FloatRegisters::SetType. 225 226 class Bitset128 { 227 // The order (hi, lo) looks best in the debugger. 228 uint64_t hi, lo; 229 230 public: 231 MOZ_IMPLICIT constexpr Bitset128(uint64_t initial) : hi(0), lo(initial) {} 232 MOZ_IMPLICIT constexpr Bitset128(const Bitset128& that) 233 : hi(that.hi), lo(that.lo) {} 234 235 constexpr Bitset128(uint64_t hi, uint64_t lo) : hi(hi), lo(lo) {} 236 237 constexpr uint64_t high() const { return hi; } 238 239 constexpr uint64_t low() const { return lo; } 240 241 constexpr Bitset128 operator|(Bitset128 that) const { 242 return Bitset128(hi | that.hi, lo | that.lo); 243 } 244 245 constexpr Bitset128 operator&(Bitset128 that) const { 246 return Bitset128(hi & that.hi, lo & that.lo); 247 } 248 249 constexpr Bitset128 operator^(Bitset128 that) const { 250 return Bitset128(hi ^ that.hi, lo ^ that.lo); 251 } 252 253 constexpr Bitset128 operator~() const { return Bitset128(~hi, ~lo); } 254 255 // We must avoid shifting by the word width, which is complex. Inlining plus 256 // shift-by-constant will remove a lot of code in the normal case. 257 258 constexpr Bitset128 operator<<(size_t shift) const { 259 if (shift == 0) { 260 return *this; 261 } 262 if (shift < 64) { 263 return Bitset128((hi << shift) | (lo >> (64 - shift)), lo << shift); 264 } 265 if (shift == 64) { 266 return Bitset128(lo, 0); 267 } 268 return Bitset128(lo << (shift - 64), 0); 269 } 270 271 constexpr Bitset128 operator>>(size_t shift) const { 272 if (shift == 0) { 273 return *this; 274 } 275 if (shift < 64) { 276 return Bitset128(hi >> shift, (lo >> shift) | (hi << (64 - shift))); 277 } 278 if (shift == 64) { 279 return Bitset128(0, hi); 280 } 281 return Bitset128(0, hi >> (shift - 64)); 282 } 283 284 constexpr bool operator==(Bitset128 that) const { 285 return lo == that.lo && hi == that.hi; 286 } 287 288 constexpr bool operator!=(Bitset128 that) const { 289 return lo != that.lo || hi != that.hi; 290 } 291 292 constexpr bool operator!() const { return (hi | lo) == 0; } 293 294 Bitset128& operator|=(const Bitset128& that) { 295 hi |= that.hi; 296 lo |= that.lo; 297 return *this; 298 } 299 300 Bitset128& operator&=(const Bitset128& that) { 301 hi &= that.hi; 302 lo &= that.lo; 303 return *this; 304 } 305 306 uint32_t size() const { 307 return mozilla::CountPopulation64(hi) + mozilla::CountPopulation64(lo); 308 } 309 310 uint32_t countTrailingZeroes() const { 311 if (lo) { 312 return mozilla::CountTrailingZeroes64(lo); 313 } 314 return mozilla::CountTrailingZeroes64(hi) + 64; 315 } 316 317 uint32_t countLeadingZeroes() const { 318 if (hi) { 319 return mozilla::CountLeadingZeroes64(hi); 320 } 321 return mozilla::CountLeadingZeroes64(lo) + 64; 322 } 323 }; 324 325 class FloatRegisters { 326 public: 327 enum FPRegisterID { 328 s0 = 0, 329 d0 = 0, 330 v0 = 0, 331 s1 = 1, 332 d1 = 1, 333 v1 = 1, 334 s2 = 2, 335 d2 = 2, 336 v2 = 2, 337 s3 = 3, 338 d3 = 3, 339 v3 = 3, 340 s4 = 4, 341 d4 = 4, 342 v4 = 4, 343 s5 = 5, 344 d5 = 5, 345 v5 = 5, 346 s6 = 6, 347 d6 = 6, 348 v6 = 6, 349 s7 = 7, 350 d7 = 7, 351 v7 = 7, 352 s8 = 8, 353 d8 = 8, 354 v8 = 8, 355 s9 = 9, 356 d9 = 9, 357 v9 = 9, 358 s10 = 10, 359 d10 = 10, 360 v10 = 10, 361 s11 = 11, 362 d11 = 11, 363 v11 = 11, 364 s12 = 12, 365 d12 = 12, 366 v12 = 12, 367 s13 = 13, 368 d13 = 13, 369 v13 = 13, 370 s14 = 14, 371 d14 = 14, 372 v14 = 14, 373 s15 = 15, 374 d15 = 15, 375 v15 = 15, 376 s16 = 16, 377 d16 = 16, 378 v16 = 16, 379 s17 = 17, 380 d17 = 17, 381 v17 = 17, 382 s18 = 18, 383 d18 = 18, 384 v18 = 18, 385 s19 = 19, 386 d19 = 19, 387 v19 = 19, 388 s20 = 20, 389 d20 = 20, 390 v20 = 20, 391 s21 = 21, 392 d21 = 21, 393 v21 = 21, 394 s22 = 22, 395 d22 = 22, 396 v22 = 22, 397 s23 = 23, 398 d23 = 23, 399 v23 = 23, 400 s24 = 24, 401 d24 = 24, 402 v24 = 24, 403 s25 = 25, 404 d25 = 25, 405 v25 = 25, 406 s26 = 26, 407 d26 = 26, 408 v26 = 26, 409 s27 = 27, 410 d27 = 27, 411 v27 = 27, 412 s28 = 28, 413 d28 = 28, 414 v28 = 28, 415 s29 = 29, 416 d29 = 29, 417 v29 = 29, 418 s30 = 30, 419 d30 = 30, 420 v30 = 30, 421 s31 = 31, 422 d31 = 31, 423 v31 = 31, // Scratch register. 424 }; 425 426 // Eight bits: (invalid << 7) | (kind << 5) | encoding 427 using Code = uint8_t; 428 using Encoding = FPRegisterID; 429 using SetType = Bitset128; 430 431 enum Kind : uint8_t { Single, Double, Simd128, NumTypes }; 432 433 static constexpr Code Invalid = 0x80; 434 435 static const char* GetName(uint32_t code) { 436 // clang-format off 437 static const char* const Names[] = { 438 "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", 439 "s10", "s11", "s12", "s13", "s14", "s15", "s16", "s17", "s18", "s19", 440 "s20", "s21", "s22", "s23", "s24", "s25", "s26", "s27", "s28", "s29", 441 "s30", "s31", 442 443 "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", 444 "d10", "d11", "d12", "d13", "d14", "d15", "d16", "d17", "d18", "d19", 445 "d20", "d21", "d22", "d23", "d24", "d25", "d26", "d27", "d28", "d29", 446 "d30", "d31", 447 448 "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", 449 "v10", "v11", "v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19", 450 "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", "v28", "v29", 451 "v30", "v31", 452 }; 453 // clang-format on 454 static_assert(Total == std::size(Names), "Table is the correct size"); 455 if (code >= Total) { 456 return "invalid"; 457 } 458 return Names[code]; 459 } 460 461 static Code FromName(const char* name); 462 463 static const uint32_t TotalPhys = 32; 464 static const uint32_t Total = TotalPhys * NumTypes; 465 static const uint32_t Allocatable = 31; // Without d31, the scratch register. 466 467 static_assert(sizeof(SetType) * 8 >= Total, 468 "SetType should be large enough to enumerate all registers."); 469 470 static constexpr unsigned ShiftSingle = uint32_t(Single) * TotalPhys; 471 static constexpr unsigned ShiftDouble = uint32_t(Double) * TotalPhys; 472 static constexpr unsigned ShiftSimd128 = uint32_t(Simd128) * TotalPhys; 473 474 static constexpr SetType NoneMask = SetType(0); 475 static constexpr SetType AllPhysMask = ~(~SetType(0) << TotalPhys); 476 static constexpr SetType AllSingleMask = AllPhysMask << ShiftSingle; 477 static constexpr SetType AllDoubleMask = AllPhysMask << ShiftDouble; 478 static constexpr SetType AllSimd128Mask = AllPhysMask << ShiftSimd128; 479 static constexpr SetType AllMask = 480 AllDoubleMask | AllSingleMask | AllSimd128Mask; 481 static constexpr SetType AliasMask = (SetType(1) << ShiftSingle) | 482 (SetType(1) << ShiftDouble) | 483 (SetType(1) << ShiftSimd128); 484 485 static_assert(ShiftSingle == 0, 486 "Or the NonVolatileMask must be computed differently"); 487 488 static constexpr SetType NonVolatileSingleMask = 489 SetType((1 << FloatRegisters::s8) | (1 << FloatRegisters::s9) | 490 (1 << FloatRegisters::s10) | (1 << FloatRegisters::s11) | 491 (1 << FloatRegisters::s12) | (1 << FloatRegisters::s13) | 492 (1 << FloatRegisters::s14) | (1 << FloatRegisters::s15)); 493 494 // Note: only the bottom 64 bits of v8-v15 will be preserved. 495 static constexpr SetType NonVolatileMask = 496 (NonVolatileSingleMask << ShiftSingle) | 497 (NonVolatileSingleMask << ShiftDouble); 498 499 static constexpr SetType VolatileMask = AllMask & ~NonVolatileMask; 500 501 static constexpr SetType WrapperMask = VolatileMask; 502 503 static_assert(ShiftSingle == 0, 504 "Or the NonAllocatableMask must be computed differently"); 505 506 // d31 is the ScratchFloatReg. 507 static constexpr SetType NonAllocatableSingleMask = 508 (SetType(1) << FloatRegisters::s31); 509 510 static constexpr SetType NonAllocatableMask = 511 NonAllocatableSingleMask | (NonAllocatableSingleMask << ShiftDouble) | 512 (NonAllocatableSingleMask << ShiftSimd128); 513 514 static constexpr SetType AllocatableMask = AllMask & ~NonAllocatableMask; 515 516 // Content spilled during bailouts. 517 union RegisterContent { 518 float s; 519 double d; 520 uint8_t v128[16]; 521 }; 522 523 static constexpr Encoding encoding(Code c) { 524 // assert() not available in constexpr function. 525 // assert(c < Total); 526 return Encoding(c & 31); 527 } 528 529 static constexpr Kind kind(Code c) { 530 // assert() not available in constexpr function. 531 // assert(c < Total && ((c >> 5) & 3) < NumTypes); 532 return Kind((c >> 5) & 3); 533 } 534 535 static constexpr Code fromParts(uint32_t encoding, uint32_t kind, 536 uint32_t invalid) { 537 return Code((invalid << 7) | (kind << 5) | encoding); 538 } 539 }; 540 541 static const uint32_t SpillSlotSize = 542 std::max(sizeof(Registers::RegisterContent), 543 sizeof(FloatRegisters::RegisterContent)); 544 545 static constexpr uint32_t ShadowStackSpace = 0; 546 547 // When our only strategy for far jumps is to encode the offset directly, and 548 // not insert any jump islands during assembly for even further jumps, then the 549 // architecture restricts us to -2^27 .. 2^27-4, to fit into a signed 28-bit 550 // value. We further reduce this range to allow the far-jump inserting code to 551 // have some breathing room. 552 static const uint32_t JumpImmediateRange = ((1 << 27) - (20 * 1024 * 1024)); 553 554 static const uint32_t ABIStackAlignment = 16; 555 static const uint32_t CodeAlignment = 16; 556 static const bool StackKeptAligned = false; 557 558 // Although sp is only usable if 16-byte alignment is kept, 559 // the Pseudo-StackPointer enables use of 8-byte alignment. 560 static const uint32_t StackAlignment = 8; 561 static const uint32_t NativeFrameSize = 8; 562 563 struct FloatRegister { 564 using Codes = FloatRegisters; 565 using Code = Codes::Code; 566 using Encoding = Codes::Encoding; 567 using SetType = Codes::SetType; 568 569 static uint32_t SetSize(SetType x) { 570 static_assert(sizeof(SetType) == 16, "SetType must be 128 bits"); 571 x |= x >> FloatRegisters::TotalPhys; 572 x |= x >> FloatRegisters::TotalPhys; 573 x &= FloatRegisters::AllPhysMask; 574 MOZ_ASSERT(x.high() == 0); 575 MOZ_ASSERT((x.low() >> 32) == 0); 576 return mozilla::CountPopulation32(x.low()); 577 } 578 579 static uint32_t FirstBit(SetType x) { 580 static_assert(sizeof(SetType) == 16, "SetType"); 581 return x.countTrailingZeroes(); 582 } 583 static uint32_t LastBit(SetType x) { 584 static_assert(sizeof(SetType) == 16, "SetType"); 585 return 127 - x.countLeadingZeroes(); 586 } 587 588 static constexpr size_t SizeOfSimd128 = 16; 589 590 private: 591 // These fields only hold valid values: an invalid register is always 592 // represented as a valid encoding and kind with the invalid_ bit set. 593 uint8_t encoding_; // 32 encodings 594 uint8_t kind_; // Double, Single, Simd128 595 bool invalid_; 596 597 using Kind = Codes::Kind; 598 599 public: 600 constexpr FloatRegister(Encoding encoding, Kind kind) 601 : encoding_(encoding), kind_(kind), invalid_(false) { 602 // assert(uint32_t(encoding) < Codes::TotalPhys); 603 } 604 605 constexpr FloatRegister() 606 : encoding_(0), kind_(FloatRegisters::Double), invalid_(true) {} 607 608 static FloatRegister FromCode(uint32_t i) { 609 MOZ_ASSERT(i < Codes::Total); 610 return FloatRegister(FloatRegisters::encoding(i), FloatRegisters::kind(i)); 611 } 612 613 bool isSingle() const { 614 MOZ_ASSERT(!invalid_); 615 return kind_ == FloatRegisters::Single; 616 } 617 bool isDouble() const { 618 MOZ_ASSERT(!invalid_); 619 return kind_ == FloatRegisters::Double; 620 } 621 bool isSimd128() const { 622 MOZ_ASSERT(!invalid_); 623 return kind_ == FloatRegisters::Simd128; 624 } 625 bool isInvalid() const { return invalid_; } 626 627 FloatRegister asSingle() const { 628 MOZ_ASSERT(!invalid_); 629 return FloatRegister(Encoding(encoding_), FloatRegisters::Single); 630 } 631 FloatRegister asDouble() const { 632 MOZ_ASSERT(!invalid_); 633 return FloatRegister(Encoding(encoding_), FloatRegisters::Double); 634 } 635 FloatRegister asSimd128() const { 636 MOZ_ASSERT(!invalid_); 637 return FloatRegister(Encoding(encoding_), FloatRegisters::Simd128); 638 } 639 640 constexpr uint32_t size() const { 641 MOZ_ASSERT(!invalid_); 642 if (kind_ == FloatRegisters::Double) { 643 return sizeof(double); 644 } 645 if (kind_ == FloatRegisters::Single) { 646 return sizeof(float); 647 } 648 MOZ_ASSERT(kind_ == FloatRegisters::Simd128); 649 return SizeOfSimd128; 650 } 651 652 constexpr Code code() const { 653 // assert(!invalid_); 654 return Codes::fromParts(encoding_, kind_, invalid_); 655 } 656 657 constexpr Encoding encoding() const { 658 MOZ_ASSERT(!invalid_); 659 return Encoding(encoding_); 660 } 661 662 const char* name() const { return FloatRegisters::GetName(code()); } 663 bool volatile_() const { 664 MOZ_ASSERT(!invalid_); 665 return !!((SetType(1) << code()) & FloatRegisters::VolatileMask); 666 } 667 constexpr bool operator!=(FloatRegister other) const { 668 return code() != other.code(); 669 } 670 constexpr bool operator==(FloatRegister other) const { 671 return code() == other.code(); 672 } 673 674 bool aliases(FloatRegister other) const { 675 return other.encoding_ == encoding_; 676 } 677 // This function mostly exists for the ARM backend. It is to ensure that two 678 // floating point registers' types are equivalent. e.g. S0 is not equivalent 679 // to D16, since S0 holds a float32, and D16 holds a Double. 680 // Since all floating point registers on x86 and x64 are equivalent, it is 681 // reasonable for this function to do the same. 682 bool equiv(FloatRegister other) const { 683 MOZ_ASSERT(!invalid_); 684 return kind_ == other.kind_; 685 } 686 687 uint32_t numAliased() const { return Codes::NumTypes; } 688 uint32_t numAlignedAliased() { return numAliased(); } 689 690 FloatRegister aliased(uint32_t aliasIdx) { 691 MOZ_ASSERT(!invalid_); 692 MOZ_ASSERT(aliasIdx < numAliased()); 693 return FloatRegister(Encoding(encoding_), 694 Kind((aliasIdx + kind_) % Codes::NumTypes)); 695 } 696 FloatRegister alignedAliased(uint32_t aliasIdx) { return aliased(aliasIdx); } 697 SetType alignedOrDominatedAliasedSet() const { 698 return Codes::AliasMask << encoding_; 699 } 700 701 static constexpr RegTypeName DefaultType = RegTypeName::Float64; 702 703 template <RegTypeName Name = DefaultType> 704 static SetType LiveAsIndexableSet(SetType s) { 705 return SetType(0); 706 } 707 708 template <RegTypeName Name = DefaultType> 709 static SetType AllocatableAsIndexableSet(SetType s) { 710 static_assert(Name != RegTypeName::Any, "Allocatable set are not iterable"); 711 return LiveAsIndexableSet<Name>(s); 712 } 713 714 static TypedRegisterSet<FloatRegister> ReduceSetForPush( 715 const TypedRegisterSet<FloatRegister>& s); 716 static uint32_t GetPushSizeInBytes(const TypedRegisterSet<FloatRegister>& s); 717 uint32_t getRegisterDumpOffsetInBytes(); 718 719 // For N in 0..31, if any of sN, dN or qN is a member of `s`, the 720 // returned set will contain all of sN, dN and qN. 721 static TypedRegisterSet<FloatRegister> BroadcastToAllSizes( 722 const TypedRegisterSet<FloatRegister>& s); 723 }; 724 725 template <> 726 inline FloatRegister::SetType 727 FloatRegister::LiveAsIndexableSet<RegTypeName::Float32>(SetType set) { 728 return set & FloatRegisters::AllSingleMask; 729 } 730 731 template <> 732 inline FloatRegister::SetType 733 FloatRegister::LiveAsIndexableSet<RegTypeName::Float64>(SetType set) { 734 return set & FloatRegisters::AllDoubleMask; 735 } 736 737 template <> 738 inline FloatRegister::SetType 739 FloatRegister::LiveAsIndexableSet<RegTypeName::Vector128>(SetType set) { 740 return set & FloatRegisters::AllSimd128Mask; 741 } 742 743 template <> 744 inline FloatRegister::SetType 745 FloatRegister::LiveAsIndexableSet<RegTypeName::Any>(SetType set) { 746 return set; 747 } 748 749 class ARM64Flags final { 750 // List of enabled CPU features. Initialized once |Init()|. 751 static inline vixl::CPUFeatures features{}; 752 753 // List of disabled CPU features. Must be set before calling |Init()|. 754 static inline vixl::CPUFeatures disabledFeatures{}; 755 756 public: 757 ARM64Flags() = delete; 758 759 // ARM64Flags::Init is called from the JitContext constructor to read the 760 // hardware flags. This method must only be called exactly once. 761 static void Init(); 762 763 static bool IsInitialized() { return features != vixl::CPUFeatures::None(); } 764 765 static vixl::CPUFeatures GetCPUFeatures() { 766 MOZ_ASSERT(IsInitialized()); 767 return features; 768 } 769 770 // Disable CPU features for testing. Can be called repeatedly to disable 771 // additional features. Must be called before |Init()|. 772 static void DisableCPUFeatures(vixl::CPUFeatures features) { 773 MOZ_ASSERT(!IsInitialized()); 774 disabledFeatures.Combine(features); 775 } 776 777 static uint32_t GetFlags() { 778 MOZ_ASSERT(IsInitialized()); 779 780 // TODO: vixl::CPUFeatures supports more than 32 values, so it can't be used 781 // directly for GetFlags. 782 return 0; 783 } 784 }; 785 786 // ARM/D32 has double registers that cannot be treated as float32. 787 // Luckily, ARMv8 doesn't have the same misfortune. 788 inline bool hasUnaliasedDouble() { return false; } 789 790 // ARM prior to ARMv8 also has doubles that alias multiple floats. 791 // Again, ARMv8 is in the clear. 792 inline bool hasMultiAlias() { return false; } 793 794 // Retrieve the ARM64 hardware flags as a bitmask. They must have been set. 795 inline uint32_t GetARM64Flags() { return ARM64Flags::GetFlags(); } 796 797 bool CanFlushICacheFromBackgroundThreads(); 798 799 } // namespace jit 800 } // namespace js 801 802 #endif // jit_arm64_Architecture_arm64_h