Architecture-arm.h (25163B)
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_arm_Architecture_arm_h 8 #define jit_arm_Architecture_arm_h 9 10 #include "mozilla/EnumSet.h" 11 #include "mozilla/MathAlgorithms.h" 12 13 #include <algorithm> 14 #include <limits.h> 15 #include <stdint.h> 16 17 #include "jit/shared/Architecture-shared.h" 18 19 #include "js/Utility.h" 20 21 namespace js { 22 namespace jit { 23 24 // These offsets are specific to nunboxing, and capture offsets into the 25 // components of a js::Value. 26 static const int32_t NUNBOX32_TYPE_OFFSET = 4; 27 static const int32_t NUNBOX32_PAYLOAD_OFFSET = 0; 28 29 static constexpr uint32_t ShadowStackSpace = 0; 30 31 // How far forward/back can a jump go? Provide a generous buffer for thunks. 32 static const uint32_t JumpImmediateRange = 20 * 1024 * 1024; 33 34 class Registers { 35 public: 36 enum RegisterID { 37 r0 = 0, 38 r1, 39 r2, 40 r3, 41 r4, 42 r5, 43 r6, 44 r7, 45 r8, 46 r9, 47 r10, 48 r11, 49 fp = r11, 50 r12, 51 ip = r12, 52 r13, 53 sp = r13, 54 r14, 55 lr = r14, 56 r15, 57 pc = r15, 58 invalid_reg 59 }; 60 using Code = uint8_t; 61 using Encoding = RegisterID; 62 63 // Content spilled during bailouts. 64 union RegisterContent { 65 uintptr_t r; 66 }; 67 68 static const char* GetName(Code code) { 69 MOZ_ASSERT(code < Total); 70 static const char* const Names[] = {"r0", "r1", "r2", "r3", "r4", "r5", 71 "r6", "r7", "r8", "r9", "r10", "r11", 72 "r12", "sp", "r14", "pc"}; 73 return Names[code]; 74 } 75 static const char* GetName(Encoding i) { return GetName(Code(i)); } 76 77 static Code FromName(const char* name); 78 79 static const Encoding StackPointer = sp; 80 static const Encoding Invalid = invalid_reg; 81 82 static const uint32_t Total = 16; 83 static const uint32_t Allocatable = 13; 84 85 using SetType = uint32_t; 86 87 static const SetType AllMask = (1 << Total) - 1; 88 static const SetType ArgRegMask = 89 (1 << r0) | (1 << r1) | (1 << r2) | (1 << r3); 90 91 static const SetType VolatileMask = 92 (1 << r0) | (1 << r1) | (1 << Registers::r2) | 93 (1 << Registers::r3) 94 #if defined(XP_IOS) 95 // per 96 // https://developer.apple.com/library/ios/documentation/Xcode/Conceptual/iPhoneOSABIReference/Articles/ARMv6FunctionCallingConventions.html#//apple_ref/doc/uid/TP40009021-SW4 97 | (1 << Registers::r9) 98 #endif 99 ; 100 101 static const SetType NonVolatileMask = 102 (1 << Registers::r4) | (1 << Registers::r5) | (1 << Registers::r6) | 103 (1 << Registers::r7) | (1 << Registers::r8) | 104 #if !defined(XP_IOS) 105 (1 << Registers::r9) | 106 #endif 107 (1 << Registers::r10) | (1 << Registers::r11) | (1 << Registers::r12) | 108 (1 << Registers::r14); 109 110 static const SetType WrapperMask = VolatileMask | // = arguments 111 (1 << Registers::r4) | // = outReg 112 (1 << Registers::r5); // = argBase 113 114 static const SetType NonAllocatableMask = 115 (1 << Registers::sp) | (1 << Registers::r12) | // r12 = ip = scratch 116 (1 << Registers::lr) | (1 << Registers::pc) | (1 << Registers::fp); 117 118 // Registers returned from a JS -> JS call. 119 static const SetType JSCallMask = (1 << Registers::r2) | (1 << Registers::r3); 120 121 // Registers returned from a JS -> C call. 122 static const SetType CallMask = 123 (1 << Registers::r0) | 124 (1 << Registers::r1); // Used for double-size returns. 125 126 static const SetType AllocatableMask = AllMask & ~NonAllocatableMask; 127 128 static uint32_t SetSize(SetType x) { 129 static_assert(sizeof(SetType) == 4, "SetType must be 32 bits"); 130 return mozilla::CountPopulation32(x); 131 } 132 static uint32_t FirstBit(SetType x) { 133 return mozilla::CountTrailingZeroes32(x); 134 } 135 static uint32_t LastBit(SetType x) { 136 return 31 - mozilla::CountLeadingZeroes32(x); 137 } 138 }; 139 140 // Smallest integer type that can hold a register bitmask. 141 using PackedRegisterMask = uint16_t; 142 143 class FloatRegisters { 144 public: 145 enum FPRegisterID { 146 s0, 147 s1, 148 s2, 149 s3, 150 s4, 151 s5, 152 s6, 153 s7, 154 s8, 155 s9, 156 s10, 157 s11, 158 s12, 159 s13, 160 s14, 161 s15, 162 s16, 163 s17, 164 s18, 165 s19, 166 s20, 167 s21, 168 s22, 169 s23, 170 s24, 171 s25, 172 s26, 173 s27, 174 s28, 175 s29, 176 s30, 177 s31, 178 d0, 179 d1, 180 d2, 181 d3, 182 d4, 183 d5, 184 d6, 185 d7, 186 d8, 187 d9, 188 d10, 189 d11, 190 d12, 191 d13, 192 d14, 193 d15, 194 d16, 195 d17, 196 d18, 197 d19, 198 d20, 199 d21, 200 d22, 201 d23, 202 d24, 203 d25, 204 d26, 205 d27, 206 d28, 207 d29, 208 d30, 209 d31, 210 invalid_freg 211 }; 212 213 using Code = uint32_t; 214 using Encoding = FPRegisterID; 215 216 // Content spilled during bailouts. 217 union RegisterContent { 218 double d; 219 }; 220 221 static const char* GetDoubleName(Encoding code) { 222 static const char* const Names[] = { 223 "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", 224 "d8", "d9", "d10", "d11", "d12", "d13", "d14", "d15", 225 "d16", "d17", "d18", "d19", "d20", "d21", "d22", "d23", 226 "d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31"}; 227 return Names[code]; 228 } 229 static const char* GetSingleName(Encoding code) { 230 static const char* const Names[] = { 231 "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", 232 "s8", "s9", "s10", "s11", "s12", "s13", "s14", "s15", 233 "s16", "s17", "s18", "s19", "s20", "s21", "s22", "s23", 234 "s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31"}; 235 return Names[code]; 236 } 237 238 static Code FromName(const char* name); 239 240 static const Encoding Invalid = invalid_freg; 241 static const uint32_t Total = 48; 242 static const uint32_t TotalDouble = 16; 243 static const uint32_t TotalSingle = 32; 244 static const uint32_t Allocatable = 45; 245 // There are only 32 places that we can put values. 246 static const uint32_t TotalPhys = 32; 247 static uint32_t ActualTotalPhys(); 248 249 /* clang-format off */ 250 // ARM float registers overlap in a way that for 1 double registers, in the 251 // range d0-d15, we have 2 singles register in the range s0-s31. d16-d31 252 // have no single register aliases. The aliasing rule state that d{n} 253 // aliases s{2n} and s{2n+1}, for n in [0 .. 15]. 254 // 255 // The register set is used to represent either allocatable register or live 256 // registers. The register maps d0-d15 and s0-s31 to a single bit each. The 257 // registers d16-d31 are not used at the moment. 258 // 259 // uuuu uuuu uuuu uuuu dddd dddd dddd dddd ssss ssss ssss ssss ssss ssss ssss ssss 260 // ^ ^ ^ ^ 261 // '-- d15 d0 --' '-- s31 s0 --' 262 // 263 // LiveSet are handled by adding the bit of each register without 264 // considering the aliases. 265 // 266 // AllocatableSet are handled by adding and removing the bit of each 267 // aligned-or-dominated-aliased registers. 268 // 269 // ...0...00... : s{2n}, s{2n+1} and d{n} are not available 270 // ...1...01... : s{2n} is available (*) 271 // ...0...10... : s{2n+1} is available 272 // ...1...11... : s{2n}, s{2n+1} and d{n} are available 273 // 274 // (*) Note that d{n} bit is set, but is not available because s{2n+1} bit 275 // is not set, which is required as d{n} dominates s{2n+1}. The d{n} bit is 276 // set, because s{2n} is aligned. 277 // 278 // | d{n} | 279 // | s{2n+1} | s{2n} | 280 // 281 /* clang-format on */ 282 using SetType = uint64_t; 283 static const SetType AllSingleMask = (1ull << TotalSingle) - 1; 284 static const SetType AllDoubleMask = ((1ull << TotalDouble) - 1) 285 << TotalSingle; 286 static const SetType AllMask = AllDoubleMask | AllSingleMask; 287 288 // d15 is the ScratchFloatReg. 289 static const SetType NonVolatileDoubleMask = 290 ((1ULL << d8) | (1ULL << d9) | (1ULL << d10) | (1ULL << d11) | 291 (1ULL << d12) | (1ULL << d13) | (1ULL << d14)); 292 // s30 and s31 alias d15. 293 static const SetType NonVolatileMask = 294 (NonVolatileDoubleMask | 295 ((1 << s16) | (1 << s17) | (1 << s18) | (1 << s19) | (1 << s20) | 296 (1 << s21) | (1 << s22) | (1 << s23) | (1 << s24) | (1 << s25) | 297 (1 << s26) | (1 << s27) | (1 << s28) | (1 << s29) | (1 << s30))); 298 299 static const SetType VolatileMask = AllMask & ~NonVolatileMask; 300 static const SetType VolatileDoubleMask = 301 AllDoubleMask & ~NonVolatileDoubleMask; 302 303 static const SetType WrapperMask = VolatileMask; 304 305 // d15 is the ARM scratch float register. 306 // s30 and s31 alias d15. 307 static const SetType NonAllocatableMask = 308 ((1ULL << d15)) | (1ULL << s30) | (1ULL << s31); 309 310 static const SetType AllocatableMask = AllMask & ~NonAllocatableMask; 311 }; 312 313 static const uint32_t SpillSlotSize = 314 std::max(sizeof(Registers::RegisterContent), 315 sizeof(FloatRegisters::RegisterContent)); 316 317 template <typename T> 318 class TypedRegisterSet; 319 320 class VFPRegister { 321 public: 322 // What type of data is being stored in this register? UInt / Int are 323 // specifically for vcvt, where we need to know how the data is supposed to 324 // be converted. 325 enum RegType : uint8_t { Single = 0x0, Double = 0x1, UInt = 0x2, Int = 0x3 }; 326 327 using Codes = FloatRegisters; 328 using Code = Codes::Code; 329 using Encoding = Codes::Encoding; 330 331 // Bitfields below are all uint32_t to make sure MSVC packs them correctly. 332 public: 333 // ARM doesn't have more than 32 registers of each type, so 5 bits should 334 // suffice. 335 uint32_t code_ : 5; 336 337 protected: 338 uint32_t kind : 2; 339 uint32_t _isInvalid : 1; 340 uint32_t _isMissing : 1; 341 342 public: 343 constexpr VFPRegister(uint32_t r, RegType k) 344 : code_(Code(r)), kind(k), _isInvalid(false), _isMissing(false) {} 345 constexpr VFPRegister() 346 : code_(Code(0)), kind(Double), _isInvalid(true), _isMissing(false) {} 347 348 constexpr VFPRegister(RegType k, uint32_t id, bool invalid, bool missing) 349 : code_(Code(id)), kind(k), _isInvalid(invalid), _isMissing(missing) {} 350 351 explicit constexpr VFPRegister(Code id) 352 : code_(id), kind(Double), _isInvalid(false), _isMissing(false) {} 353 bool operator==(const VFPRegister& other) const { 354 return kind == other.kind && code_ == other.code_ && 355 isInvalid() == other.isInvalid(); 356 } 357 bool operator!=(const VFPRegister& other) const { return !operator==(other); } 358 359 bool isSingle() const { return kind == Single; } 360 bool isDouble() const { return kind == Double; } 361 bool isSimd128() const { return false; } 362 bool isFloat() const { return (kind == Double) || (kind == Single); } 363 bool isInt() const { return (kind == UInt) || (kind == Int); } 364 bool isSInt() const { return kind == Int; } 365 bool isUInt() const { return kind == UInt; } 366 bool equiv(const VFPRegister& other) const { return other.kind == kind; } 367 size_t size() const { return (kind == Double) ? 8 : 4; } 368 bool isInvalid() const { return _isInvalid; } 369 bool isMissing() const { 370 MOZ_ASSERT(!_isInvalid); 371 return _isMissing; 372 } 373 374 VFPRegister doubleOverlay(unsigned int which = 0) const; 375 VFPRegister singleOverlay(unsigned int which = 0) const; 376 VFPRegister sintOverlay(unsigned int which = 0) const; 377 VFPRegister uintOverlay(unsigned int which = 0) const; 378 379 VFPRegister asSingle() const { return singleOverlay(); } 380 VFPRegister asDouble() const { return doubleOverlay(); } 381 VFPRegister asSimd128() const { MOZ_CRASH("NYI"); } 382 383 struct VFPRegIndexSplit; 384 VFPRegIndexSplit encode(); 385 386 // For serializing values. 387 struct VFPRegIndexSplit { 388 const uint32_t block : 4; 389 const uint32_t bit : 1; 390 391 private: 392 friend VFPRegIndexSplit js::jit::VFPRegister::encode(); 393 394 VFPRegIndexSplit(uint32_t block_, uint32_t bit_) 395 : block(block_), bit(bit_) { 396 MOZ_ASSERT(block == block_); 397 MOZ_ASSERT(bit == bit_); 398 } 399 }; 400 401 Code code() const { 402 MOZ_ASSERT(!_isInvalid && !_isMissing); 403 // This should only be used in areas where we only have doubles and 404 // singles. 405 MOZ_ASSERT(isFloat()); 406 return Code(code_ | (kind << 5)); 407 } 408 Encoding encoding() const { 409 MOZ_ASSERT(!_isInvalid && !_isMissing); 410 return Encoding(code_); 411 } 412 uint32_t id() const { return code_; } 413 static VFPRegister FromCode(uint32_t i) { 414 uint32_t code = i & 31; 415 uint32_t kind = i >> 5; 416 return VFPRegister(code, RegType(kind)); 417 } 418 bool volatile_() const { 419 if (isDouble()) { 420 return !!((1ULL << (code_ >> 1)) & FloatRegisters::VolatileMask); 421 } 422 return !!((1ULL << code_) & FloatRegisters::VolatileMask); 423 } 424 const char* name() const { 425 if (isDouble()) { 426 return FloatRegisters::GetDoubleName(Encoding(code_)); 427 } 428 return FloatRegisters::GetSingleName(Encoding(code_)); 429 } 430 bool aliases(const VFPRegister& other) { 431 if (kind == other.kind) { 432 return code_ == other.code_; 433 } 434 return doubleOverlay() == other.doubleOverlay(); 435 } 436 static const int NumAliasedDoubles = 16; 437 uint32_t numAliased() const { 438 if (isDouble()) { 439 if (code_ < NumAliasedDoubles) { 440 return 3; 441 } 442 return 1; 443 } 444 return 2; 445 } 446 447 VFPRegister aliased(uint32_t aliasIdx) { 448 if (aliasIdx == 0) { 449 return *this; 450 } 451 if (isDouble()) { 452 MOZ_ASSERT(code_ < NumAliasedDoubles); 453 MOZ_ASSERT(aliasIdx <= 2); 454 return singleOverlay(aliasIdx - 1); 455 } 456 MOZ_ASSERT(aliasIdx == 1); 457 return doubleOverlay(aliasIdx - 1); 458 } 459 uint32_t numAlignedAliased() const { 460 if (isDouble()) { 461 if (code_ < NumAliasedDoubles) { 462 return 2; 463 } 464 return 1; 465 } 466 // s1 has 0 other aligned aliases, 1 total. 467 // s0 has 1 other aligned aliase, 2 total. 468 return 2 - (code_ & 1); 469 } 470 // | d0 | 471 // | s0 | s1 | 472 // If we've stored s0 and s1 in memory, we also want to say that d0 is 473 // stored there, but it is only stored at the location where it is aligned 474 // e.g. at s0, not s1. 475 VFPRegister alignedAliased(uint32_t aliasIdx) { 476 if (aliasIdx == 0) { 477 return *this; 478 } 479 MOZ_ASSERT(aliasIdx == 1); 480 if (isDouble()) { 481 MOZ_ASSERT(code_ < NumAliasedDoubles); 482 return singleOverlay(aliasIdx - 1); 483 } 484 MOZ_ASSERT((code_ & 1) == 0); 485 return doubleOverlay(aliasIdx - 1); 486 } 487 488 using SetType = FloatRegisters::SetType; 489 490 // This function is used to ensure that Register set can take all Single 491 // registers, even if we are taking a mix of either double or single 492 // registers. 493 // 494 // s0.alignedOrDominatedAliasedSet() == s0 | d0. 495 // s1.alignedOrDominatedAliasedSet() == s1. 496 // d0.alignedOrDominatedAliasedSet() == s0 | s1 | d0. 497 // 498 // This way the Allocatable register set does not have to do any arithmetics 499 // to know if a register is available or not, as we have the following 500 // relations: 501 // 502 // d0.alignedOrDominatedAliasedSet() == 503 // s0.alignedOrDominatedAliasedSet() | s1.alignedOrDominatedAliasedSet() 504 // 505 // s0.alignedOrDominatedAliasedSet() & s1.alignedOrDominatedAliasedSet() == 0 506 // 507 SetType alignedOrDominatedAliasedSet() const { 508 if (isSingle()) { 509 if (code_ % 2 != 0) { 510 return SetType(1) << code_; 511 } 512 return (SetType(1) << code_) | (SetType(1) << (32 + code_ / 2)); 513 } 514 515 MOZ_ASSERT(isDouble()); 516 return (SetType(0b11) << (code_ * 2)) | (SetType(1) << (32 + code_)); 517 } 518 519 static constexpr RegTypeName DefaultType = RegTypeName::Float64; 520 521 template <RegTypeName = DefaultType> 522 static SetType LiveAsIndexableSet(SetType s) { 523 return SetType(0); 524 } 525 526 template <RegTypeName Name = DefaultType> 527 static SetType AllocatableAsIndexableSet(SetType s) { 528 static_assert(Name != RegTypeName::Any, "Allocatable set are not iterable"); 529 return SetType(0); 530 } 531 532 static uint32_t SetSize(SetType x) { 533 static_assert(sizeof(SetType) == 8, "SetType must be 64 bits"); 534 return mozilla::CountPopulation32(x); 535 } 536 static Code FromName(const char* name) { 537 return FloatRegisters::FromName(name); 538 } 539 static TypedRegisterSet<VFPRegister> ReduceSetForPush( 540 const TypedRegisterSet<VFPRegister>& s); 541 static uint32_t GetPushSizeInBytes(const TypedRegisterSet<VFPRegister>& s); 542 uint32_t getRegisterDumpOffsetInBytes(); 543 static uint32_t FirstBit(SetType x) { 544 return mozilla::CountTrailingZeroes64(x); 545 } 546 static uint32_t LastBit(SetType x) { 547 return 63 - mozilla::CountLeadingZeroes64(x); 548 } 549 }; 550 551 template <> 552 inline VFPRegister::SetType 553 VFPRegister::LiveAsIndexableSet<RegTypeName::Float32>(SetType set) { 554 return set & FloatRegisters::AllSingleMask; 555 } 556 557 template <> 558 inline VFPRegister::SetType 559 VFPRegister::LiveAsIndexableSet<RegTypeName::Float64>(SetType set) { 560 return set & FloatRegisters::AllDoubleMask; 561 } 562 563 template <> 564 inline VFPRegister::SetType VFPRegister::LiveAsIndexableSet<RegTypeName::Any>( 565 SetType set) { 566 return set; 567 } 568 569 template <> 570 inline VFPRegister::SetType 571 VFPRegister::AllocatableAsIndexableSet<RegTypeName::Float32>(SetType set) { 572 // Single registers are not dominating any smaller registers, thus masking 573 // is enough to convert an allocatable set into a set of register list all 574 // single register available. 575 return set & FloatRegisters::AllSingleMask; 576 } 577 578 template <> 579 inline VFPRegister::SetType 580 VFPRegister::AllocatableAsIndexableSet<RegTypeName::Float64>(SetType set) { 581 /* clang-format off */ 582 // An allocatable float register set is represented as follow: 583 // 584 // uuuu uuuu uuuu uuuu dddd dddd dddd dddd ssss ssss ssss ssss ssss ssss ssss ssss 585 // ^ ^ ^ ^ 586 // '-- d15 d0 --' '-- s31 s0 --' 587 // 588 // ...0...00... : s{2n}, s{2n+1} and d{n} are not available 589 // ...1...01... : s{2n} is available 590 // ...0...10... : s{2n+1} is available 591 // ...1...11... : s{2n}, s{2n+1} and d{n} are available 592 // 593 // The goal of this function is to return the set of double registers which 594 // are available as an indexable bit set. This implies that iff a double bit 595 // is set in the returned set, then the register is available. 596 // 597 // To do so, this functions converts the 32 bits set of single registers 598 // into a 16 bits set of equivalent double registers. Then, we mask out 599 // double registers which do not have all the single register that compose 600 // them. As d{n} bit is set when s{2n} is available, we only need to take 601 // s{2n+1} into account. 602 /* clang-format on */ 603 604 // Convert s7s6s5s4 s3s2s1s0 into s7s5s3s1, for all s0-s31. 605 SetType s2d = AllocatableAsIndexableSet<RegTypeName::Float32>(set); 606 static_assert(FloatRegisters::TotalSingle == 32, "Wrong mask"); 607 s2d = (0xaaaaaaaa & s2d) >> 1; // Filter s{2n+1} registers. 608 // Group adjacent bits as follow: 609 // 0.0.s3.s1 == ((0.s3.0.s1) >> 1 | (0.s3.0.s1)) & 0b0011; 610 s2d = ((s2d >> 1) | s2d) & 0x33333333; // 0a0b --> 00ab 611 s2d = ((s2d >> 2) | s2d) & 0x0f0f0f0f; // 00ab00cd --> 0000abcd 612 s2d = ((s2d >> 4) | s2d) & 0x00ff00ff; 613 s2d = ((s2d >> 8) | s2d) & 0x0000ffff; 614 // Move the s7s5s3s1 to the aliased double positions. 615 s2d = s2d << FloatRegisters::TotalSingle; 616 617 // Note: We currently do not use any representation for d16-d31. 618 static_assert(FloatRegisters::TotalDouble == 16, 619 "d16-d31 do not have a single register mapping"); 620 621 // Filter out any double register which are not allocatable due to 622 // non-aligned dominated single registers. 623 return set & s2d; 624 } 625 626 // The only floating point register set that we work with are the VFP Registers. 627 using FloatRegister = VFPRegister; 628 629 enum class ARMCapability : uint32_t { 630 // Flag when the capabilities are initialized, so they can be atomically set. 631 Initialized, 632 633 // Flag when HWCAP_VFP is set. 634 VFP, 635 636 // Flag when HWCAP_VFPD32 is set. 637 VFPD32, 638 639 // Flag when HWCAP_VFPv3 is set. 640 VFPv3, 641 642 // Flag when HWCAP_VFPv3D16 is set. 643 VFPv3D16, 644 645 // Flag when HWCAP_VFPv4 is set. 646 VFPv4, 647 648 // Flag when HWCAP_NEON is set. 649 Neon, 650 651 // Flag when HWCAP_IDIVA is set. 652 IDivA, 653 654 // Flag when HWCAP_FPHP is set (floating point half-precision). 655 FPHP, 656 657 // Flag when signaled alignment faults are to be fixed up. 658 FixupFault, 659 660 // Flag when alignment faults are enabled and signal. 661 AlignmentFault, 662 663 // Flag the use of the hardfp ABI. 664 UseHardFpABI, 665 666 // Flag the use of the ARMv7 arch, otherwise ARMv6. 667 ARMv7, 668 }; 669 670 using ARMCapabilities = mozilla::EnumSet<ARMCapability>; 671 672 class ARMFlags final { 673 // The override flags parsed from the ARMHWCAP environment variable or from 674 // the --arm-hwcap js shell argument. They are stable after startup: there is 675 // no longer a programmatic way of setting these from JS. 676 static inline ARMCapabilities capabilities{}; 677 678 public: 679 ARMFlags() = delete; 680 681 // ARMFlags::Init is called from the JitContext constructor to read the 682 // hardware flags. This method must only be called exactly once. 683 // 684 // If the environment variable ARMHWCAP is set then the flags are read from it 685 // instead; see ParseARMHwCapFlags. 686 static void Init(); 687 688 static bool IsInitialized() { 689 return capabilities.contains(ARMCapability::Initialized); 690 } 691 692 static uint32_t GetFlags() { 693 MOZ_ASSERT(IsInitialized()); 694 return capabilities.serialize(); 695 } 696 static bool HasARMv7() { 697 MOZ_ASSERT(IsInitialized()); 698 return capabilities.contains(ARMCapability::ARMv7); 699 } 700 static bool HasMOVWT() { 701 MOZ_ASSERT(IsInitialized()); 702 return capabilities.contains(ARMCapability::ARMv7); 703 } 704 // {LD,ST}REX{B,H,D} 705 static bool HasLDSTREXBHD() { 706 // These are really available from ARMv6K and later, but why bother? 707 MOZ_ASSERT(IsInitialized()); 708 return capabilities.contains(ARMCapability::ARMv7); 709 } 710 // DMB, DSB, and ISB 711 static bool HasDMBDSBISB() { 712 MOZ_ASSERT(IsInitialized()); 713 return capabilities.contains(ARMCapability::ARMv7); 714 } 715 static bool HasVFP() { 716 MOZ_ASSERT(IsInitialized()); 717 return capabilities.contains(ARMCapability::VFP); 718 } 719 static bool Has32DP() { 720 MOZ_ASSERT(IsInitialized()); 721 return capabilities.contains(ARMCapability::VFPD32); 722 } 723 static bool HasVFPv3() { 724 MOZ_ASSERT(IsInitialized()); 725 return capabilities.contains(ARMCapability::VFPv3); 726 } 727 static bool HasVFPv4() { 728 MOZ_ASSERT(IsInitialized()); 729 return capabilities.contains(ARMCapability::VFPv4); 730 } 731 static bool HasNEON() { 732 MOZ_ASSERT(IsInitialized()); 733 return capabilities.contains(ARMCapability::Neon); 734 } 735 static bool HasIDIV() { 736 MOZ_ASSERT(IsInitialized()); 737 return capabilities.contains(ARMCapability::IDivA); 738 } 739 static bool HasFPHalfPrecision() { 740 MOZ_ASSERT(IsInitialized()); 741 return capabilities.contains(ARMCapability::FPHP); 742 } 743 744 // Returns true when cpu alignment faults are enabled and signaled, and thus 745 // we should ensure loads and stores are aligned. 746 static bool HasAlignmentFault() { 747 MOZ_ASSERT(IsInitialized()); 748 return capabilities.contains(ARMCapability::AlignmentFault); 749 } 750 751 #ifdef JS_SIMULATOR_ARM 752 // Returns true when cpu alignment faults will be fixed up by the 753 // "operating system", which functionality we will emulate. 754 static bool FixupFault() { 755 MOZ_ASSERT(IsInitialized()); 756 return capabilities.contains(ARMCapability::FixupFault); 757 } 758 #endif 759 760 // If the simulator is used then the ABI choice is dynamic. Otherwise the ABI is 761 // static and useHardFpABI is constexpr so that unused branches can be optimized 762 // away. 763 #ifdef JS_SIMULATOR_ARM 764 static bool UseHardFpABI() { 765 MOZ_ASSERT(IsInitialized()); 766 return capabilities.contains(ARMCapability::UseHardFpABI); 767 } 768 #else 769 static constexpr bool UseHardFpABI() { 770 // GCC versions 4.6 and above define __ARM_PCS_VFP to denote a hard-float 771 // ABI target. The iOS toolchain doesn't define anything specific here, but 772 // iOS always supports VFP. 773 # if defined(__ARM_PCS_VFP) || defined(XP_IOS) 774 return true; 775 # else 776 return false; 777 # endif 778 } 779 #endif 780 }; 781 782 // Arm/D32 has double registers that can NOT be treated as float32 and this 783 // requires some dances in lowering. 784 inline bool hasUnaliasedDouble() { return ARMFlags::Has32DP(); } 785 786 // On ARM, Dn aliases both S2n and S2n+1, so if you need to convert a float32 to 787 // a double as a temporary, you need a temporary double register. 788 inline bool hasMultiAlias() { return true; } 789 790 // Register a string denoting ARM hardware flags. During engine initialization, 791 // these flags will then be used instead of the actual hardware capabilities. 792 // This must be called before JS_Init and the passed string's buffer must 793 // outlive the JS_Init call. 794 void SetARMHwCapFlagsString(const char* armHwCap); 795 796 // Retrieve the ARM hardware flags as a bitmask. They must have been set. 797 inline uint32_t GetARMFlags() { return ARMFlags::GetFlags(); } 798 799 // In order to handle SoftFp ABI calls, we need to be able to express that we 800 // have ABIArg which are represented by pair of general purpose registers. 801 #define JS_CODEGEN_REGISTER_PAIR 1 802 803 } // namespace jit 804 } // namespace js 805 806 #endif /* jit_arm_Architecture_arm_h */