#ifndef jit_x86_shared_Architecture_x86_h
#define jit_x86_shared_Architecture_x86_h
#if !defined(JS_CODEGEN_X86) && !defined(JS_CODEGEN_X64)
# error "Unsupported architecture!"
#endif
#include "mozilla/MathAlgorithms.h"
#include <string.h>
#include "jit/shared/Architecture-shared.h"
#include "jit/x86-shared/Constants-x86-shared.h"
namespace js {
namespace jit {
static constexpr bool SupportsUint32x4FloatConversions = false;
static constexpr bool SupportsUint8x16Compares = false;
static constexpr bool SupportsUint16x8Compares = false;
static constexpr bool SupportsUint32x4Compares = false;
#if defined(JS_CODEGEN_X86)
static const uint32_t ION_FRAME_SLACK_SIZE = 20;
#elif defined(JS_CODEGEN_X64)
static const uint32_t ION_FRAME_SLACK_SIZE = 24;
#endif
#if defined(JS_CODEGEN_X86)
static const int32_t NUNBOX32_TYPE_OFFSET = 4;
static const int32_t NUNBOX32_PAYLOAD_OFFSET = 0;
static const uint32_t BAILOUT_TABLE_ENTRY_SIZE = 5;
#endif
#if defined(JS_CODEGEN_X64) && defined(_WIN64)
static const uint32_t ShadowStackSpace = 32;
#else
static const uint32_t ShadowStackSpace = 0;
#endif
static const uint32_t JumpImmediateRange = INT32_MAX;
class Registers {
public:
typedef uint8_t Code;
typedef X86Encoding::RegisterID Encoding;
union RegisterContent {
uintptr_t r;
};
#if defined(JS_CODEGEN_X86)
typedef uint8_t SetType;
static const char* GetName(Code code) {
return X86Encoding::GPRegName(Encoding(code));
}
static const uint32_t Total = 8;
static const uint32_t TotalPhys = 8;
static const uint32_t Allocatable = 7;
#elif defined(JS_CODEGEN_X64)
typedef uint16_t SetType;
static const char* GetName(Code code) {
static const char* const Names[] = {
"rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"};
return Names[code];
}
static const uint32_t Total = 16;
static const uint32_t TotalPhys = 16;
static const uint32_t Allocatable = 14;
#endif
static uint32_t SetSize(SetType x) {
static_assert(sizeof(SetType) <= 4, "SetType must be, at most, 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 Code FromName(const char* name) {
for (size_t i = 0; i < Total; i++) {
if (strcmp(GetName(Code(i)), name) == 0) {
return Code(i);
}
}
return Invalid;
}
static const Encoding StackPointer = X86Encoding::rsp;
static const Encoding Invalid = X86Encoding::invalid_reg;
static const SetType AllMask = (1 << Total) - 1;
#if defined(JS_CODEGEN_X86)
static const SetType ArgRegMask = 0;
static const SetType VolatileMask = (1 << X86Encoding::rax) |
(1 << X86Encoding::rcx) |
(1 << X86Encoding::rdx);
static const SetType WrapperMask = VolatileMask | (1 << X86Encoding::rbx);
static const SetType SingleByteRegs =
(1 << X86Encoding::rax) | (1 << X86Encoding::rcx) |
(1 << X86Encoding::rdx) | (1 << X86Encoding::rbx);
static const SetType NonAllocatableMask = (1 << X86Encoding::rsp);
static const SetType JSCallMask =
(1 << X86Encoding::rcx) | (1 << X86Encoding::rdx);
static const SetType CallMask = (1 << X86Encoding::rax);
#elif defined(JS_CODEGEN_X64)
static const SetType ArgRegMask =
# if !defined(_WIN64)
(1 << X86Encoding::rdi) | (1 << X86Encoding::rsi) |
# endif
(1 << X86Encoding::rdx) | (1 << X86Encoding::rcx) |
(1 << X86Encoding::r8) | (1 << X86Encoding::r9);
static const SetType VolatileMask = (1 << X86Encoding::rax) | ArgRegMask |
(1 << X86Encoding::r10) |
(1 << X86Encoding::r11);
static const SetType WrapperMask = VolatileMask;
static const SetType SingleByteRegs = AllMask & ~(1 << X86Encoding::rsp);
static const SetType NonAllocatableMask =
(1 << X86Encoding::rsp) | (1 << X86Encoding::r11);
static const SetType JSCallMask = (1 << X86Encoding::rcx);
static const SetType CallMask = (1 << X86Encoding::rax);
#endif
static const SetType NonVolatileMask =
AllMask & ~VolatileMask & ~(1 << X86Encoding::rsp);
static const SetType AllocatableMask = AllMask & ~NonAllocatableMask;
};
typedef Registers::SetType PackedRegisterMask;
class FloatRegisters {
public:
typedef X86Encoding::XMMRegisterID Encoding;
enum ContentType {
Single, Double, Simd128, NumTypes
};
union RegisterContent {
float s;
double d;
int32_t i4[4];
float s4[4];
};
static const char* GetName(Encoding code) {
return X86Encoding::XMMRegName(code);
}
static Encoding FromName(const char* name) {
for (size_t i = 0; i < Total; i++) {
if (strcmp(GetName(Encoding(i)), name) == 0) {
return Encoding(i);
}
}
return Invalid;
}
static const Encoding Invalid = X86Encoding::invalid_xmm;
#if defined(JS_CODEGEN_X86)
static const uint32_t Total = 8 * NumTypes;
static const uint32_t TotalPhys = 8;
static const uint32_t Allocatable = 7;
typedef uint32_t SetType;
#elif defined(JS_CODEGEN_X64)
static const uint32_t Total = 16 * NumTypes;
static const uint32_t TotalPhys = 16;
static const uint32_t Allocatable = 15;
typedef uint64_t SetType;
#endif
static_assert(sizeof(SetType) * 8 >= Total,
"SetType should be large enough to enumerate all registers.");
static const SetType SpreadSingle = SetType(1)
<< (uint32_t(Single) * TotalPhys);
static const SetType SpreadDouble = SetType(1)
<< (uint32_t(Double) * TotalPhys);
static const SetType SpreadSimd128 = SetType(1)
<< (uint32_t(Simd128) * TotalPhys);
static const SetType SpreadScalar = SpreadSingle | SpreadDouble;
static const SetType SpreadVector = SpreadSimd128;
static const SetType Spread = SpreadScalar | SpreadVector;
static const SetType AllPhysMask = ((1 << TotalPhys) - 1);
static const SetType AllMask = AllPhysMask * Spread;
static const SetType AllDoubleMask = AllPhysMask * SpreadDouble;
static const SetType AllSingleMask = AllPhysMask * SpreadSingle;
static const SetType AllVector128Mask = AllPhysMask * SpreadSimd128;
#if defined(JS_CODEGEN_X86)
static const SetType NonAllocatableMask =
Spread * (1 << X86Encoding::xmm7);
#elif defined(JS_CODEGEN_X64)
static const SetType NonAllocatableMask =
Spread * (1 << X86Encoding::xmm15); #endif
#if defined(JS_CODEGEN_X64) && defined(_WIN64)
static const SetType VolatileMask =
((1 << X86Encoding::xmm0) | (1 << X86Encoding::xmm1) |
(1 << X86Encoding::xmm2) | (1 << X86Encoding::xmm3) |
(1 << X86Encoding::xmm4) | (1 << X86Encoding::xmm5)) *
SpreadScalar |
AllPhysMask * SpreadVector;
#else
static const SetType VolatileMask = AllMask;
#endif
static const SetType NonVolatileMask = AllMask & ~VolatileMask;
static const SetType WrapperMask = VolatileMask;
static const SetType AllocatableMask = AllMask & ~NonAllocatableMask;
};
template <typename T>
class TypedRegisterSet;
struct FloatRegister {
typedef FloatRegisters Codes;
typedef size_t Code;
typedef Codes::Encoding Encoding;
typedef Codes::SetType SetType;
static uint32_t SetSize(SetType x) {
x |= x >> (2 * Codes::TotalPhys);
x |= x >> Codes::TotalPhys;
x &= Codes::AllPhysMask;
static_assert(Codes::AllPhysMask <= 0xffff,
"We can safely use CountPopulation32");
return mozilla::CountPopulation32(x);
}
#if defined(JS_CODEGEN_X86)
static uint32_t FirstBit(SetType x) {
static_assert(sizeof(SetType) == 4, "SetType must be 32 bits");
return mozilla::CountTrailingZeroes32(x);
}
static uint32_t LastBit(SetType x) {
return 31 - mozilla::CountLeadingZeroes32(x);
}
#elif defined(JS_CODEGEN_X64)
static uint32_t FirstBit(SetType x) {
static_assert(sizeof(SetType) == 8, "SetType must be 64 bits");
return mozilla::CountTrailingZeroes64(x);
}
static uint32_t LastBit(SetType x) {
return 63 - mozilla::CountLeadingZeroes64(x);
}
#endif
private:
Codes::Encoding reg_ : 5;
Codes::ContentType type_ : 3;
bool isInvalid_ : 1;
#if defined(JS_CODEGEN_X86)
static const size_t RegSize = 3;
#elif defined(JS_CODEGEN_X64)
static const size_t RegSize = 4;
#endif
static const size_t RegMask = (1 << RegSize) - 1;
public:
constexpr FloatRegister()
: reg_(Codes::Encoding(0)), type_(Codes::Single), isInvalid_(true) {}
constexpr FloatRegister(uint32_t r, Codes::ContentType k)
: reg_(Codes::Encoding(r)), type_(k), isInvalid_(false) {}
constexpr FloatRegister(Codes::Encoding r, Codes::ContentType k)
: reg_(r), type_(k), isInvalid_(false) {}
static FloatRegister FromCode(uint32_t i) {
MOZ_ASSERT(i < Codes::Total);
return FloatRegister(i & RegMask, Codes::ContentType(i >> RegSize));
}
bool isSingle() const {
MOZ_ASSERT(!isInvalid());
return type_ == Codes::Single;
}
bool isDouble() const {
MOZ_ASSERT(!isInvalid());
return type_ == Codes::Double;
}
bool isSimd128() const {
MOZ_ASSERT(!isInvalid());
return type_ == Codes::Simd128;
}
bool isInvalid() const { return isInvalid_; }
FloatRegister asSingle() const {
MOZ_ASSERT(!isInvalid());
return FloatRegister(reg_, Codes::Single);
}
FloatRegister asDouble() const {
MOZ_ASSERT(!isInvalid());
return FloatRegister(reg_, Codes::Double);
}
FloatRegister asSimd128() const {
MOZ_ASSERT(!isInvalid());
return FloatRegister(reg_, Codes::Simd128);
}
uint32_t size() const {
MOZ_ASSERT(!isInvalid());
if (isSingle()) {
return sizeof(float);
}
if (isDouble()) {
return sizeof(double);
}
MOZ_ASSERT(isSimd128());
return 4 * sizeof(int32_t);
}
Code code() const {
MOZ_ASSERT(!isInvalid());
MOZ_ASSERT(uint32_t(reg_) < Codes::TotalPhys);
return Code(reg_ | (type_ << RegSize));
}
Encoding encoding() const {
MOZ_ASSERT(!isInvalid());
MOZ_ASSERT(uint32_t(reg_) < Codes::TotalPhys);
return reg_;
}
const char* name() const;
bool volatile_() const {
return !!((SetType(1) << code()) & FloatRegisters::VolatileMask);
}
bool operator!=(FloatRegister other) const {
return other.reg_ != reg_ || other.type_ != type_;
}
bool operator==(FloatRegister other) const {
return other.reg_ == reg_ && other.type_ == type_;
}
bool aliases(FloatRegister other) const { return other.reg_ == reg_; }
bool equiv(FloatRegister other) const { return other.type_ == type_; }
uint32_t numAliased() const { return Codes::NumTypes; }
uint32_t numAlignedAliased() const { return numAliased(); }
FloatRegister aliased(uint32_t aliasIdx) const {
MOZ_ASSERT(aliasIdx < Codes::NumTypes);
return FloatRegister(
reg_, Codes::ContentType((aliasIdx + type_) % Codes::NumTypes));
}
FloatRegister alignedAliased(uint32_t aliasIdx) const {
return aliased(aliasIdx);
}
SetType alignedOrDominatedAliasedSet() const { return Codes::Spread << reg_; }
static constexpr RegTypeName DefaultType = RegTypeName::Float64;
template <RegTypeName = 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();
};
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::AllVector128Mask;
}
template <>
inline FloatRegister::SetType
FloatRegister::LiveAsIndexableSet<RegTypeName::Any>(SetType set) {
return set;
}
inline bool hasUnaliasedDouble() { return false; }
inline bool hasMultiAlias() { return false; }
} }
#endif