/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: set ts=8 sts=2 et sw=2 tw=80:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef jit_arm64_Architecture_arm64_h
#define jit_arm64_Architecture_arm64_h
#include "mozilla/Assertions.h"
#include "mozilla/MathAlgorithms.h"
#include <algorithm>
#include <iterator>
#include "jit/arm64/vixl/Instructions-vixl.h"
#include "jit/shared/Architecture-shared.h"
#include "js/Utility.h"
#define JS_HAS_HIDDEN_SP
static const uint32_t HiddenSPEncoding = vixl::kSPRegInternalCode;
namespace js {
namespace jit {
// AArch64 has 32 64-bit integer registers, x0 though x31.
//
// x31 (or, more accurately, the integer register with encoding 31, since
// there is no x31 per se) is special and functions as both the stack pointer
// and a zero register.
//
// The bottom 32 bits of each of the X registers is accessible as w0 through
// w31. The program counter is not accessible as a register.
//
// SIMD and scalar floating-point registers share a register bank.
// 32 bit float registers are s0 through s31.
// 64 bit double registers are d0 through d31.
// 128 bit SIMD registers are v0 through v31.
// e.g., s0 is the bottom 32 bits of d0, which is the bottom 64 bits of v0.
// AArch64 Calling Convention:
// x0 - x7: arguments and return value
// x8: indirect result (struct) location
// x9 - x15: temporary registers
// x16 - x17: intra-call-use registers (PLT, linker)
// x18: platform specific use (TLS)
// x19 - x28: callee-saved registers
// x29: frame pointer
// x30: link register
// AArch64 Calling Convention for Floats:
// d0 - d7: arguments and return value
// d8 - d15: callee-saved registers
// Bits 64:128 are not saved for v8-v15.
// d16 - d31: temporary registers
// AArch64 does not have soft float.
class Registers {
public :
enum RegisterID {
w0 =
0 ,
x0 =
0 ,
w1 =
1 ,
x1 =
1 ,
w2 =
2 ,
x2 =
2 ,
w3 =
3 ,
x3 =
3 ,
w4 =
4 ,
x4 =
4 ,
w5 =
5 ,
x5 =
5 ,
w6 =
6 ,
x6 =
6 ,
w7 =
7 ,
x7 =
7 ,
w8 =
8 ,
x8 =
8 ,
w9 =
9 ,
x9 =
9 ,
w10 =
10 ,
x10 =
10 ,
w11 =
11 ,
x11 =
11 ,
w12 =
12 ,
x12 =
12 ,
w13 =
13 ,
x13 =
13 ,
w14 =
14 ,
x14 =
14 ,
w15 =
15 ,
x15 =
15 ,
w16 =
16 ,
x16 =
16 ,
ip0 =
16 ,
// MacroAssembler scratch register 1.
w17 =
17 ,
x17 =
17 ,
ip1 =
17 ,
// MacroAssembler scratch register 2.
w18 =
18 ,
x18 =
18 ,
tls =
18 ,
// Platform-specific use (TLS).
w19 =
19 ,
x19 =
19 ,
w20 =
20 ,
x20 =
20 ,
w21 =
21 ,
x21 =
21 ,
w22 =
22 ,
x22 =
22 ,
w23 =
23 ,
x23 =
23 ,
w24 =
24 ,
x24 =
24 ,
w25 =
25 ,
x25 =
25 ,
w26 =
26 ,
x26 =
26 ,
w27 =
27 ,
x27 =
27 ,
w28 =
28 ,
x28 =
28 ,
w29 =
29 ,
x29 =
29 ,
fp =
29 ,
w30 =
30 ,
x30 =
30 ,
lr =
30 ,
w31 =
31 ,
x31 =
31 ,
wzr =
31 ,
xzr =
31 ,
sp =
31 ,
// Special: both stack pointer and a zero register.
};
using Code = uint8_t;
using Encoding = uint32_t;
using SetType = uint32_t;
static const Code Invalid =
0 xFF;
union RegisterContent {
uintptr_t r;
};
static uint32_t SetSize(SetType x) {
static_assert(
sizeof (SetType) ==
4 ,
"SetType must be 32 bits" );
return mozilla::CountPopulation32(x);
}
static uint32_t FirstBit(SetType x) {
return mozilla::CountTrailingZeroes32(x);
}
static uint32_t LastBit(SetType x) {
return 31 - mozilla::CountLeadingZeroes32(x);
}
static const char * GetName(uint32_t code) {
static const char *
const Names[] = {
"x0" ,
"x1" ,
"x2" ,
"x3" ,
"x4" ,
"x5" ,
"x6" ,
"x7" ,
"x8" ,
"x9" ,
"x10" ,
"x11" ,
"x12" ,
"x13" ,
"x14" ,
"x15" ,
"x16" ,
"x17" ,
"x18" ,
"x19" ,
"x20" ,
"x21" ,
"x22" ,
"x23" ,
"x24" ,
"x25" ,
"x26" ,
"x27" ,
"x28" ,
"x29" ,
"lr" ,
"sp" };
static_assert(Total == std::size(Names),
"Table is the correct size" );
if (code >= Total) {
return "invalid" ;
}
return Names[code];
}
static Code FromName(
const char * name);
static const uint32_t Total =
32 ;
static const uint32_t TotalPhys =
32 ;
static const uint32_t Allocatable =
27 ;
// No named special-function registers.
static const SetType AllMask =
0 xFFFFFFFF;
static const SetType NoneMask =
0 x0;
static const SetType ArgRegMask =
(
1 << Registers::x0) | (
1 << Registers::x1) | (
1 << Registers::x2) |
(
1 << Registers::x3) | (
1 << Registers::x4) | (
1 << Registers::x5) |
(
1 << Registers::x6) | (
1 << Registers::x7) | (
1 << Registers::x8);
static const SetType VolatileMask =
(
1 << Registers::x0) | (
1 << Registers::x1) | (
1 << Registers::x2) |
(
1 << Registers::x3) | (
1 << Registers::x4) | (
1 << Registers::x5) |
(
1 << Registers::x6) | (
1 << Registers::x7) | (
1 << Registers::x8) |
(
1 << Registers::x9) | (
1 << Registers::x10) | (
1 << Registers::x11) |
(
1 << Registers::x12) | (
1 << Registers::x13) | (
1 << Registers::x14) |
(
1 << Registers::x15) | (
1 << Registers::x16) | (
1 << Registers::x17) |
(
1 << Registers::x18);
static const SetType NonVolatileMask =
(
1 << Registers::x19) | (
1 << Registers::x20) | (
1 << Registers::x21) |
(
1 << Registers::x22) | (
1 << Registers::x23) | (
1 << Registers::x24) |
(
1 << Registers::x25) | (
1 << Registers::x26) | (
1 << Registers::x27) |
(
1 << Registers::x28) | (
1 << Registers::x29) | (
1 << Registers::x30);
static const SetType NonAllocatableMask =
(
1 << Registers::x28) |
// PseudoStackPointer.
(
1 << Registers::ip0) |
// First scratch register.
(
1 << Registers::ip1) |
// Second scratch register.
(
1 << Registers::tls) | (
1 << Registers::lr) | (
1 << Registers::sp) |
(
1 << Registers::fp);
static const SetType WrapperMask = VolatileMask;
// Registers returned from a JS -> JS call.
static const SetType JSCallMask = (
1 << Registers::x2);
// Registers returned from a JS -> C call.
static const SetType CallMask = (
1 << Registers::x0);
static const SetType AllocatableMask = AllMask & ~NonAllocatableMask;
};
// Smallest integer type that can hold a register bitmask.
using PackedRegisterMask = uint32_t;
template <
typename T>
class TypedRegisterSet;
// 128-bit bitset for FloatRegisters::SetType.
class Bitset128 {
// The order (hi, lo) looks best in the debugger.
uint64_t hi, lo;
public :
MOZ_IMPLICIT constexpr Bitset128(uint64_t initial) : hi(
0 ), lo(initial) {}
MOZ_IMPLICIT constexpr Bitset128(
const Bitset128& that)
: hi(that.hi), lo(that.lo) {}
constexpr Bitset128(uint64_t hi, uint64_t lo) : hi(hi), lo(lo) {}
constexpr uint64_t high()
const {
return hi; }
constexpr uint64_t low()
const {
return lo; }
constexpr Bitset128
operator |(Bitset128 that)
const {
return Bitset128(hi | that.hi, lo | that.lo);
}
constexpr Bitset128
operator &(Bitset128 that)
const {
return Bitset128(hi & that.hi, lo & that.lo);
}
constexpr Bitset128
operator ^(Bitset128 that)
const {
return Bitset128(hi ^ that.hi, lo ^ that.lo);
}
constexpr Bitset128
operator ~()
const {
return Bitset128(~hi, ~lo); }
// We must avoid shifting by the word width, which is complex. Inlining plus
// shift-by-constant will remove a lot of code in the normal case.
constexpr Bitset128
operator <<(size_t shift)
const {
if (shift ==
0 ) {
return *
this ;
}
if (shift <
64 ) {
return Bitset128((hi << shift) | (lo >> (
64 - shift)), lo << shift);
}
if (shift ==
64 ) {
return Bitset128(lo,
0 );
}
return Bitset128(lo << (shift -
64 ),
0 );
}
constexpr Bitset128
operator >>(size_t shift)
const {
if (shift ==
0 ) {
return *
this ;
}
if (shift <
64 ) {
return Bitset128(hi >> shift, (lo >> shift) | (hi << (
64 - shift)));
}
if (shift ==
64 ) {
return Bitset128(
0 , hi);
}
return Bitset128(
0 , hi >> (shift -
64 ));
}
constexpr
bool operator ==(Bitset128 that)
const {
return lo == that.lo && hi == that.hi;
}
constexpr
bool operator !=(Bitset128 that)
const {
return lo != that.lo || hi != that.hi;
}
constexpr
bool operator !()
const {
return (hi | lo) ==
0 ; }
Bitset128&
operator |=(
const Bitset128& that) {
hi |= that.hi;
lo |= that.lo;
return *
this ;
}
Bitset128&
operator &=(
const Bitset128& that) {
hi &= that.hi;
lo &= that.lo;
return *
this ;
}
uint32_t size()
const {
return mozilla::CountPopulation64(hi) + mozilla::CountPopulation64(lo);
}
uint32_t countTrailingZeroes()
const {
if (lo) {
return mozilla::CountTrailingZeroes64(lo);
}
return mozilla::CountTrailingZeroes64(hi) +
64 ;
}
uint32_t countLeadingZeroes()
const {
if (hi) {
return mozilla::CountLeadingZeroes64(hi);
}
return mozilla::CountLeadingZeroes64(lo) +
64 ;
}
};
class FloatRegisters {
public :
enum FPRegisterID {
s0 =
0 ,
d0 =
0 ,
v0 =
0 ,
s1 =
1 ,
d1 =
1 ,
v1 =
1 ,
s2 =
2 ,
d2 =
2 ,
v2 =
2 ,
s3 =
3 ,
d3 =
3 ,
v3 =
3 ,
s4 =
4 ,
d4 =
4 ,
v4 =
4 ,
s5 =
5 ,
d5 =
5 ,
v5 =
5 ,
s6 =
6 ,
d6 =
6 ,
v6 =
6 ,
s7 =
7 ,
d7 =
7 ,
v7 =
7 ,
s8 =
8 ,
d8 =
8 ,
v8 =
8 ,
s9 =
9 ,
d9 =
9 ,
v9 =
9 ,
s10 =
10 ,
d10 =
10 ,
v10 =
10 ,
s11 =
11 ,
d11 =
11 ,
v11 =
11 ,
s12 =
12 ,
d12 =
12 ,
v12 =
12 ,
s13 =
13 ,
d13 =
13 ,
v13 =
13 ,
s14 =
14 ,
d14 =
14 ,
v14 =
14 ,
s15 =
15 ,
d15 =
15 ,
v15 =
15 ,
s16 =
16 ,
d16 =
16 ,
v16 =
16 ,
s17 =
17 ,
d17 =
17 ,
v17 =
17 ,
s18 =
18 ,
d18 =
18 ,
v18 =
18 ,
s19 =
19 ,
d19 =
19 ,
v19 =
19 ,
s20 =
20 ,
d20 =
20 ,
v20 =
20 ,
s21 =
21 ,
d21 =
21 ,
v21 =
21 ,
s22 =
22 ,
d22 =
22 ,
v22 =
22 ,
s23 =
23 ,
d23 =
23 ,
v23 =
23 ,
s24 =
24 ,
d24 =
24 ,
v24 =
24 ,
s25 =
25 ,
d25 =
25 ,
v25 =
25 ,
s26 =
26 ,
d26 =
26 ,
v26 =
26 ,
s27 =
27 ,
d27 =
27 ,
v27 =
27 ,
s28 =
28 ,
d28 =
28 ,
v28 =
28 ,
s29 =
29 ,
d29 =
29 ,
v29 =
29 ,
s30 =
30 ,
d30 =
30 ,
v30 =
30 ,
s31 =
31 ,
d31 =
31 ,
v31 =
31 ,
// Scratch register.
};
// Eight bits: (invalid << 7) | (kind << 5) | encoding
using Code = uint8_t;
using Encoding = FPRegisterID;
using SetType = Bitset128;
enum Kind : uint8_t { Single,
Double , Simd128, NumTypes };
static constexpr Code Invalid =
0 x80;
static const char * GetName(uint32_t code) {
// clang-format off
static const char *
const Names[] = {
"s0" ,
"s1" ,
"s2" ,
"s3" ,
"s4" ,
"s5" ,
"s6" ,
"s7" ,
"s8" ,
"s9" ,
"s10" ,
"s11" ,
"s12" ,
"s13" ,
"s14" ,
"s15" ,
"s16" ,
"s17" ,
"s18" ,
"s19" ,
"s20" ,
"s21" ,
"s22" ,
"s23" ,
"s24" ,
"s25" ,
"s26" ,
"s27" ,
"s28" ,
"s29" ,
"s30" ,
"s31" ,
"d0" ,
"d1" ,
"d2" ,
"d3" ,
"d4" ,
"d5" ,
"d6" ,
"d7" ,
"d8" ,
"d9" ,
"d10" ,
"d11" ,
"d12" ,
"d13" ,
"d14" ,
"d15" ,
"d16" ,
"d17" ,
"d18" ,
"d19" ,
"d20" ,
"d21" ,
"d22" ,
"d23" ,
"d24" ,
"d25" ,
"d26" ,
"d27" ,
"d28" ,
"d29" ,
"d30" ,
"d31" ,
"v0" ,
"v1" ,
"v2" ,
"v3" ,
"v4" ,
"v5" ,
"v6" ,
"v7" ,
"v8" ,
"v9" ,
"v10" ,
"v11" ,
"v12" ,
"v13" ,
"v14" ,
"v15" ,
"v16" ,
"v17" ,
"v18" ,
"v19" ,
"v20" ,
"v21" ,
"v22" ,
"v23" ,
"v24" ,
"v25" ,
"v26" ,
"v27" ,
"v28" ,
"v29" ,
"v30" ,
"v31" ,
};
// clang-format on
static_assert(Total == std::size(Names),
"Table is the correct size" );
if (code >= Total) {
return "invalid" ;
}
return Names[code];
}
static Code FromName(
const char * name);
static const uint32_t TotalPhys =
32 ;
static const uint32_t Total = TotalPhys * NumTypes;
static const uint32_t Allocatable =
31 ;
// Without d31, the scratch register.
static_assert(
sizeof (SetType) *
8 >= Total,
"SetType should be large enough to enumerate all registers." );
static constexpr
unsigned ShiftSingle = uint32_t(Single) * TotalPhys;
static constexpr
unsigned ShiftDouble = uint32_t(
Double ) * TotalPhys;
static constexpr
unsigned ShiftSimd128 = uint32_t(Simd128) * TotalPhys;
static constexpr SetType NoneMask = SetType(
0 );
static constexpr SetType AllPhysMask = ~(~SetType(
0 ) << TotalPhys);
static constexpr SetType AllSingleMask = AllPhysMask << ShiftSingle;
static constexpr SetType AllDoubleMask = AllPhysMask << ShiftDouble;
static constexpr SetType AllSimd128Mask = AllPhysMask << ShiftSimd128;
static constexpr SetType AllMask =
AllDoubleMask | AllSingleMask | AllSimd128Mask;
static constexpr SetType AliasMask = (SetType(
1 ) << ShiftSingle) |
(SetType(
1 ) << ShiftDouble) |
(SetType(
1 ) << ShiftSimd128);
static_assert(ShiftSingle ==
0 ,
"Or the NonVolatileMask must be computed differently" );
static constexpr SetType NonVolatileSingleMask =
SetType((
1 << FloatRegisters::s8) | (
1 << FloatRegisters::s9) |
(
1 << FloatRegisters::s10) | (
1 << FloatRegisters::s11) |
(
1 << FloatRegisters::s12) | (
1 << FloatRegisters::s13) |
(
1 << FloatRegisters::s14) | (
1 << FloatRegisters::s15));
// Note: only the bottom 64 bits of v8-v15 will be preserved.
static constexpr SetType NonVolatileMask =
(NonVolatileSingleMask << ShiftSingle) |
(NonVolatileSingleMask << ShiftDouble);
static constexpr SetType VolatileMask = AllMask & ~NonVolatileMask;
static constexpr SetType WrapperMask = VolatileMask;
static_assert(ShiftSingle ==
0 ,
"Or the NonAllocatableMask must be computed differently" );
// d31 is the ScratchFloatReg.
static constexpr SetType NonAllocatableSingleMask =
(SetType(
1 ) << FloatRegisters::s31);
static constexpr SetType NonAllocatableMask =
NonAllocatableSingleMask | (NonAllocatableSingleMask << ShiftDouble) |
(NonAllocatableSingleMask << ShiftSimd128);
static constexpr SetType AllocatableMask = AllMask & ~NonAllocatableMask;
// Content spilled during bailouts.
union RegisterContent {
float s;
double d;
uint8_t v128[
16 ];
};
static constexpr Encoding encoding(Code c) {
// assert() not available in constexpr function.
// assert(c < Total);
return Encoding(c &
31 );
}
static constexpr Kind kind(Code c) {
// assert() not available in constexpr function.
// assert(c < Total && ((c >> 5) & 3) < NumTypes);
return Kind((c >>
5 ) &
3 );
}
static constexpr Code fromParts(uint32_t encoding, uint32_t kind,
uint32_t invalid) {
return Code((invalid <<
7 ) | (kind <<
5 ) | encoding);
}
};
static const uint32_t SpillSlotSize =
std::max(
sizeof (Registers::RegisterContent),
sizeof (FloatRegisters::RegisterContent));
static constexpr uint32_t ShadowStackSpace =
0 ;
// When our only strategy for far jumps is to encode the offset directly, and
// not insert any jump islands during assembly for even further jumps, then the
// architecture restricts us to -2^27 .. 2^27-4, to fit into a signed 28-bit
// value. We further reduce this range to allow the far-jump inserting code to
// have some breathing room.
static const uint32_t JumpImmediateRange = ((
1 <<
27 ) - (
20 *
1024 *
1024 ));
static const uint32_t ABIStackAlignment =
16 ;
static const uint32_t CodeAlignment =
16 ;
static const bool StackKeptAligned =
false ;
// Although sp is only usable if 16-byte alignment is kept,
// the Pseudo-StackPointer enables use of 8-byte alignment.
static const uint32_t StackAlignment =
8 ;
static const uint32_t NativeFrameSize =
8 ;
struct FloatRegister {
using Codes = FloatRegisters;
using Code = Codes::Code;
using Encoding = Codes::Encoding;
using SetType = Codes::SetType;
static uint32_t SetSize(SetType x) {
static_assert(
sizeof (SetType) ==
16 ,
"SetType must be 128 bits" );
x |= x >> FloatRegisters::TotalPhys;
x |= x >> FloatRegisters::TotalPhys;
x &= FloatRegisters::AllPhysMask;
MOZ_ASSERT(x.high() ==
0 );
MOZ_ASSERT((x.low() >>
32 ) ==
0 );
return mozilla::CountPopulation32(x.low());
}
static uint32_t FirstBit(SetType x) {
static_assert(
sizeof (SetType) ==
16 ,
"SetType" );
return x.countTrailingZeroes();
}
static uint32_t LastBit(SetType x) {
static_assert(
sizeof (SetType) ==
16 ,
"SetType" );
return 127 - x.countLeadingZeroes();
}
static constexpr size_t SizeOfSimd128 =
16 ;
private :
// These fields only hold valid values: an invalid register is always
// represented as a valid encoding and kind with the invalid_ bit set.
uint8_t encoding_;
// 32 encodings
uint8_t kind_;
// Double, Single, Simd128
bool invalid_;
using Kind = Codes::Kind;
public :
constexpr FloatRegister(Encoding encoding, Kind kind)
: encoding_(encoding), kind_(kind), invalid_(
false ) {
// assert(uint32_t(encoding) < Codes::TotalPhys);
}
constexpr FloatRegister()
: encoding_(
0 ), kind_(FloatRegisters::
Double ), invalid_(
true ) {}
static FloatRegister FromCode(uint32_t i) {
MOZ_ASSERT(i < Codes::Total);
return FloatRegister(FloatRegisters::encoding(i), FloatRegisters::kind(i));
}
bool isSingle()
const {
MOZ_ASSERT(!invalid_);
return kind_ == FloatRegisters::Single;
}
bool isDouble()
const {
MOZ_ASSERT(!invalid_);
return kind_ == FloatRegisters::
Double ;
}
bool isSimd128()
const {
MOZ_ASSERT(!invalid_);
return kind_ == FloatRegisters::Simd128;
}
bool isInvalid()
const {
return invalid_; }
FloatRegister asSingle()
const {
MOZ_ASSERT(!invalid_);
return FloatRegister(Encoding(encoding_), FloatRegisters::Single);
}
FloatRegister asDouble()
const {
MOZ_ASSERT(!invalid_);
return FloatRegister(Encoding(encoding_), FloatRegisters::
Double );
}
FloatRegister asSimd128()
const {
MOZ_ASSERT(!invalid_);
return FloatRegister(Encoding(encoding_), FloatRegisters::Simd128);
}
constexpr uint32_t size()
const {
MOZ_ASSERT(!invalid_);
if (kind_ == FloatRegisters::
Double ) {
return sizeof (
double );
}
if (kind_ == FloatRegisters::Single) {
return sizeof (
float );
}
MOZ_ASSERT(kind_ == FloatRegisters::Simd128);
return SizeOfSimd128;
}
constexpr Code code()
const {
// assert(!invalid_);
return Codes::fromParts(encoding_, kind_, invalid_);
}
constexpr Encoding encoding()
const {
MOZ_ASSERT(!invalid_);
return Encoding(encoding_);
}
const char * name()
const {
return FloatRegisters::GetName(code()); }
bool volatile_()
const {
MOZ_ASSERT(!invalid_);
return !!((SetType(
1 ) << code()) & FloatRegisters::VolatileMask);
}
constexpr
bool operator !=(FloatRegister other)
const {
return code() != other.code();
}
constexpr
bool operator ==(FloatRegister other)
const {
return code() == other.code();
}
bool aliases(FloatRegister other)
const {
return other.encoding_ == encoding_;
}
// This function mostly exists for the ARM backend. It is to ensure that two
// floating point registers' types are equivalent. e.g. S0 is not equivalent
// to D16, since S0 holds a float32, and D16 holds a Double.
// Since all floating point registers on x86 and x64 are equivalent, it is
// reasonable for this function to do the same.
bool equiv(FloatRegister other)
const {
MOZ_ASSERT(!invalid_);
return kind_ == other.kind_;
}
uint32_t numAliased()
const {
return Codes::NumTypes; }
uint32_t numAlignedAliased() {
return numAliased(); }
FloatRegister aliased(uint32_t aliasIdx) {
MOZ_ASSERT(!invalid_);
MOZ_ASSERT(aliasIdx < numAliased());
return FloatRegister(Encoding(encoding_),
Kind((aliasIdx + kind_) % Codes::NumTypes));
}
FloatRegister alignedAliased(uint32_t aliasIdx) {
return aliased(aliasIdx); }
SetType alignedOrDominatedAliasedSet()
const {
return Codes::AliasMask << encoding_;
}
static constexpr RegTypeName DefaultType = RegTypeName::Float64;
template <RegTypeName Name = DefaultType>
static SetType LiveAsIndexableSet(SetType s) {
return SetType(
0 );
}
template <RegTypeName Name = DefaultType>
static SetType AllocatableAsIndexableSet(SetType s) {
static_assert(Name != RegTypeName::Any,
"Allocatable set are not iterable" );
return LiveAsIndexableSet<Name>(s);
}
static TypedRegisterSet<FloatRegister> ReduceSetForPush(
const TypedRegisterSet<FloatRegister>& s);
static uint32_t GetPushSizeInBytes(
const TypedRegisterSet<FloatRegister>& s);
uint32_t getRegisterDumpOffsetInBytes();
// For N in 0..31, if any of sN, dN or qN is a member of `s`, the
// returned set will contain all of sN, dN and qN.
static TypedRegisterSet<FloatRegister> BroadcastToAllSizes(
const TypedRegisterSet<FloatRegister>& s);
};
template <>
inline FloatRegister::SetType
FloatRegister::LiveAsIndexableSet<RegTypeName::Float32>(SetType set) {
return set & FloatRegisters::AllSingleMask;
}
template <>
inline FloatRegister::SetType
FloatRegister::LiveAsIndexableSet<RegTypeName::Float64>(SetType set) {
return set & FloatRegisters::AllDoubleMask;
}
template <>
inline FloatRegister::SetType
FloatRegister::LiveAsIndexableSet<RegTypeName::Vector128>(SetType set) {
return set & FloatRegisters::AllSimd128Mask;
}
template <>
inline FloatRegister::SetType
FloatRegister::LiveAsIndexableSet<RegTypeName::Any>(SetType set) {
return set;
}
// ARM/D32 has double registers that cannot be treated as float32.
// Luckily, ARMv8 doesn't have the same misfortune.
inline bool hasUnaliasedDouble() {
return false ; }
// ARM prior to ARMv8 also has doubles that alias multiple floats.
// Again, ARMv8 is in the clear.
inline bool hasMultiAlias() {
return false ; }
uint32_t GetARM64Flags();
bool CanFlushICacheFromBackgroundThreads();
}
// namespace jit
}
// namespace js
#endif // jit_arm64_Architecture_arm64_h
Messung V0.5 in Prozent C=90 H=100 G=95
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.30Bemerkung:
(vorverarbeitet am 2026-06-08)
¤
*Bot Zugriff