mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1112164 part 14 - Add types to x86/x64 float registers. r=bbouvier,jandem
This commit is contained in:
parent
fa375effb5
commit
d578d5f79f
@ -2483,9 +2483,15 @@ MachineState::FromBailout(RegisterDump::GPRArray ®s, RegisterDump::FPUArray &
|
||||
machine.setRegisterLocation(FloatRegister::FromIndex(i, FloatRegister::Single),
|
||||
(double*)&fbase[i]);
|
||||
}
|
||||
#elif defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
|
||||
for (unsigned i = 0; i < FloatRegisters::TotalPhys; i++) {
|
||||
machine.setRegisterLocation(FloatRegister(i, FloatRegisters::Single), &fpregs[i].s);
|
||||
machine.setRegisterLocation(FloatRegister(i, FloatRegisters::Double), &fpregs[i].d);
|
||||
}
|
||||
#elif defined(JS_CODEGEN_NONE)
|
||||
MOZ_CRASH();
|
||||
#else
|
||||
for (unsigned i = 0; i < FloatRegisters::Total; i++)
|
||||
machine.setRegisterLocation(FloatRegister::FromCode(i), &fpregs[i].d);
|
||||
# error "Unknown architecture!"
|
||||
#endif
|
||||
return machine;
|
||||
}
|
||||
|
@ -115,6 +115,10 @@ class MachineState
|
||||
void setRegisterLocation(Register reg, uintptr_t *up) {
|
||||
regs_[reg.code()] = (Registers::RegisterContent *) up;
|
||||
}
|
||||
void setRegisterLocation(FloatRegister reg, float *fp) {
|
||||
MOZ_ASSERT(reg.isSingle());
|
||||
fpregs_[reg.code()] = (FloatRegisters::RegisterContent *) fp;
|
||||
}
|
||||
void setRegisterLocation(FloatRegister reg, double *dp) {
|
||||
fpregs_[reg.code()] = (FloatRegisters::RegisterContent *) dp;
|
||||
}
|
||||
|
@ -134,12 +134,22 @@ class FloatRegisters {
|
||||
public:
|
||||
typedef X86Encoding::XMMRegisterID Encoding;
|
||||
|
||||
// Content spilled during bailouts.
|
||||
union RegisterContent {
|
||||
double d;
|
||||
enum ContentType {
|
||||
Single,
|
||||
Double,
|
||||
Int32x4,
|
||||
Float32x4,
|
||||
NumTypes
|
||||
};
|
||||
|
||||
// Content spilled during bailouts.
|
||||
union RegisterContent {
|
||||
float s;
|
||||
double d;
|
||||
int32_t i4[4];
|
||||
float s4[4];
|
||||
};
|
||||
|
||||
typedef uint32_t SetType;
|
||||
static const char *GetName(Encoding code) {
|
||||
return X86Encoding::XMMRegName(code);
|
||||
}
|
||||
@ -154,21 +164,38 @@ class FloatRegisters {
|
||||
|
||||
static const Encoding Invalid = X86Encoding::invalid_xmm;
|
||||
|
||||
static const uint32_t Total = 16;
|
||||
static const uint32_t Total = 16 * NumTypes;
|
||||
static const uint32_t TotalPhys = 16;
|
||||
|
||||
static const uint32_t Allocatable = 15;
|
||||
|
||||
static const SetType AllMask = (1 << Total) - 1;
|
||||
static const SetType AllDoubleMask = AllMask;
|
||||
typedef uint64_t SetType;
|
||||
static_assert(sizeof(SetType) * 8 >= Total,
|
||||
"SetType should be large enough to enumerate all registers.");
|
||||
|
||||
// Magic values which are used to duplicate a mask of physical register for
|
||||
// a specific type of register. A multiplication is used to copy and shift
|
||||
// the bits of the physical register mask.
|
||||
static const SetType SpreadSingle = SetType(1) << (uint32_t(Single) * TotalPhys);
|
||||
static const SetType SpreadDouble = SetType(1) << (uint32_t(Double) * TotalPhys);
|
||||
static const SetType SpreadInt32x4 = SetType(1) << (uint32_t(Int32x4) * TotalPhys);
|
||||
static const SetType SpreadFloat32x4 = SetType(1) << (uint32_t(Float32x4) * TotalPhys);
|
||||
static const SetType SpreadScalar = SpreadSingle | SpreadDouble;
|
||||
static const SetType SpreadVector = SpreadInt32x4 | SpreadFloat32x4;
|
||||
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 VolatileMask =
|
||||
#if defined(_WIN64)
|
||||
(1 << X86Encoding::xmm0) |
|
||||
( (1 << X86Encoding::xmm0) |
|
||||
(1 << X86Encoding::xmm1) |
|
||||
(1 << X86Encoding::xmm2) |
|
||||
(1 << X86Encoding::xmm3) |
|
||||
(1 << X86Encoding::xmm4) |
|
||||
(1 << X86Encoding::xmm5);
|
||||
(1 << X86Encoding::xmm5)
|
||||
) * SpreadScalar
|
||||
| AllPhysMask * SpreadVector;
|
||||
#else
|
||||
AllMask;
|
||||
#endif
|
||||
@ -178,7 +205,7 @@ class FloatRegisters {
|
||||
static const SetType WrapperMask = VolatileMask;
|
||||
|
||||
static const SetType NonAllocatableMask =
|
||||
(1 << X86Encoding::xmm15); // This is ScratchDoubleReg.
|
||||
Spread * (1 << X86Encoding::xmm15); // This is ScratchDoubleReg.
|
||||
|
||||
static const SetType AllocatableMask = AllMask & ~NonAllocatableMask;
|
||||
};
|
||||
@ -192,83 +219,124 @@ struct FloatRegister {
|
||||
typedef Codes::Encoding Encoding;
|
||||
typedef Codes::SetType SetType;
|
||||
static uint32_t SetSize(SetType x) {
|
||||
static_assert(sizeof(SetType) == 4, "SetType must be 32 bits");
|
||||
static_assert(sizeof(SetType) == 8, "SetType must be 64 bits");
|
||||
// Count the number of non-aliased registers, for the moment.
|
||||
//
|
||||
// Copy the set bits of each typed register to the low part of the of
|
||||
// the Set, and count the number of registers. This is made to avoid
|
||||
// registers which are allocated twice with different types (such as in
|
||||
// AllMask).
|
||||
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);
|
||||
}
|
||||
static uint32_t FirstBit(SetType x) {
|
||||
return mozilla::CountTrailingZeroes32(x);
|
||||
return mozilla::CountTrailingZeroes64(x);
|
||||
}
|
||||
static uint32_t LastBit(SetType x) {
|
||||
return 31 - mozilla::CountLeadingZeroes32(x);
|
||||
return 63 - mozilla::CountLeadingZeroes64(x);
|
||||
}
|
||||
Code code_;
|
||||
|
||||
private:
|
||||
// Note: These fields are using one extra bit to make the invalid enumerated
|
||||
// values fit, and thus prevent a warning.
|
||||
Codes::Encoding reg_ : 5;
|
||||
Codes::ContentType type_ : 3;
|
||||
bool isInvalid_ : 1;
|
||||
|
||||
// Constants used for exporting/importing the float register code.
|
||||
static const size_t RegSize = 4;
|
||||
static const size_t RegMask = (1 << RegSize) - 1;
|
||||
|
||||
public:
|
||||
MOZ_CONSTEXPR FloatRegister()
|
||||
: reg_(Codes::Encoding(0)), type_(Codes::Single), isInvalid_(true)
|
||||
{ }
|
||||
MOZ_CONSTEXPR FloatRegister(uint32_t r, Codes::ContentType k)
|
||||
: reg_(Codes::Encoding(r)), type_(k), isInvalid_(false)
|
||||
{ }
|
||||
MOZ_CONSTEXPR FloatRegister(Codes::Encoding r, Codes::ContentType k)
|
||||
: reg_(r), type_(k), isInvalid_(false)
|
||||
{ }
|
||||
|
||||
static FloatRegister FromCode(uint32_t i) {
|
||||
MOZ_ASSERT(i < FloatRegisters::Total);
|
||||
FloatRegister r = { Code(i) };
|
||||
return r;
|
||||
MOZ_ASSERT(i < Codes::Total);
|
||||
return FloatRegister(i & RegMask, Codes::ContentType(i >> RegSize));
|
||||
}
|
||||
|
||||
bool isSingle() const { return true; }
|
||||
bool isDouble() const { return true; }
|
||||
bool isInt32x4() const { return true; }
|
||||
bool isFloat32x4() const { return true; }
|
||||
bool isSingle() const { MOZ_ASSERT(!isInvalid()); return type_ == Codes::Single; }
|
||||
bool isDouble() const { MOZ_ASSERT(!isInvalid()); return type_ == Codes::Double; }
|
||||
bool isInt32x4() const { MOZ_ASSERT(!isInvalid()); return type_ == Codes::Int32x4; }
|
||||
bool isFloat32x4() const { MOZ_ASSERT(!isInvalid()); return type_ == Codes::Float32x4; }
|
||||
bool isInvalid() const { return isInvalid_; }
|
||||
|
||||
FloatRegister asSingle() const { return *this; }
|
||||
FloatRegister asDouble() const { return *this; }
|
||||
FloatRegister asInt32x4() const { return *this; }
|
||||
FloatRegister asFloat32x4() const { return *this; }
|
||||
FloatRegister asSingle() const { MOZ_ASSERT(!isInvalid()); return FloatRegister(reg_, Codes::Single); }
|
||||
FloatRegister asDouble() const { MOZ_ASSERT(!isInvalid()); return FloatRegister(reg_, Codes::Double); }
|
||||
FloatRegister asInt32x4() const { MOZ_ASSERT(!isInvalid()); return FloatRegister(reg_, Codes::Int32x4); }
|
||||
FloatRegister asFloat32x4() const { MOZ_ASSERT(!isInvalid()); return FloatRegister(reg_, Codes::Float32x4); }
|
||||
|
||||
uint32_t size() const {
|
||||
MOZ_ASSERT(!isInvalid());
|
||||
if (isSingle())
|
||||
return sizeof(float);
|
||||
if (isDouble())
|
||||
return sizeof(double);
|
||||
MOZ_ASSERT(isInt32x4() || isFloat32x4());
|
||||
return 4 * sizeof(int32_t);
|
||||
}
|
||||
|
||||
Code code() const {
|
||||
MOZ_ASSERT(uint32_t(code_) < FloatRegisters::Total);
|
||||
return code_;
|
||||
MOZ_ASSERT(!isInvalid());
|
||||
MOZ_ASSERT(uint32_t(reg_) < Codes::TotalPhys);
|
||||
// :TODO: ARM is doing the same thing, but we should avoid this, except
|
||||
// that the RegisterSets depends on this.
|
||||
return Code(reg_ | (type_ << RegSize));
|
||||
}
|
||||
Encoding encoding() const {
|
||||
MOZ_ASSERT(uint32_t(code_) < FloatRegisters::Total);
|
||||
return Encoding(code_);
|
||||
MOZ_ASSERT(!isInvalid());
|
||||
MOZ_ASSERT(uint32_t(reg_) < Codes::TotalPhys);
|
||||
return reg_;
|
||||
}
|
||||
const char *name() const {
|
||||
// :TODO: Add type
|
||||
return FloatRegisters::GetName(encoding());
|
||||
}
|
||||
bool volatile_() const {
|
||||
return !!((1 << code()) & FloatRegisters::VolatileMask);
|
||||
return !!((SetType(1) << code()) & FloatRegisters::VolatileMask);
|
||||
}
|
||||
bool operator !=(FloatRegister other) const {
|
||||
return other.code_ != code_;
|
||||
return other.reg_ != reg_ || other.type_ != type_;
|
||||
}
|
||||
bool operator ==(FloatRegister other) const {
|
||||
return other.code_ == code_;
|
||||
return other.reg_ == reg_ && other.type_ == type_;
|
||||
}
|
||||
bool aliases(FloatRegister other) const {
|
||||
return other.code_ == code_;
|
||||
return other.reg_ == reg_;
|
||||
}
|
||||
uint32_t numAliased() const {
|
||||
return 1;
|
||||
}
|
||||
// N.B. FloatRegister is an explicit outparam here because msvc-2010
|
||||
// miscompiled it on win64 when the value was simply returned
|
||||
void aliased(uint32_t aliasIdx, FloatRegister *ret) {
|
||||
MOZ_ASSERT(aliasIdx == 0);
|
||||
*ret = *this;
|
||||
}
|
||||
// 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.
|
||||
// Check if two floating point registers have the same type.
|
||||
bool equiv(FloatRegister other) const {
|
||||
return true;
|
||||
return other.type_ == type_;
|
||||
}
|
||||
uint32_t size() const {
|
||||
return sizeof(double);
|
||||
|
||||
uint32_t numAliased() const {
|
||||
return Codes::NumTypes;
|
||||
}
|
||||
uint32_t numAlignedAliased() const {
|
||||
return 1;
|
||||
return numAliased();
|
||||
}
|
||||
void alignedAliased(uint32_t aliasIdx, FloatRegister *ret) {
|
||||
MOZ_ASSERT(aliasIdx == 0);
|
||||
*ret = *this;
|
||||
|
||||
// N.B. FloatRegister is an explicit outparam here because msvc-2010
|
||||
// miscompiled it on win64 when the value was simply returned
|
||||
void aliased(uint32_t aliasIdx, FloatRegister *ret) const {
|
||||
MOZ_ASSERT(aliasIdx < Codes::NumTypes);
|
||||
*ret = FloatRegister(reg_, Codes::ContentType((aliasIdx + type_) % Codes::NumTypes));
|
||||
}
|
||||
void alignedAliased(uint32_t aliasIdx, FloatRegister *ret) const {
|
||||
aliased(aliasIdx, ret);
|
||||
}
|
||||
|
||||
static TypedRegisterSet<FloatRegister> ReduceSetForPush(const TypedRegisterSet<FloatRegister> &s);
|
||||
static uint32_t GetSizeInBytes(const TypedRegisterSet<FloatRegister> &s);
|
||||
static uint32_t GetPushSizeInBytes(const TypedRegisterSet<FloatRegister> &s);
|
||||
|
@ -318,10 +318,30 @@ FloatRegister::GetSizeInBytes(const FloatRegisterSet &s)
|
||||
uint32_t
|
||||
FloatRegister::GetPushSizeInBytes(const FloatRegisterSet &s)
|
||||
{
|
||||
return s.size() * sizeof(double);
|
||||
SetType all = s.bits();
|
||||
SetType float32x4Set =
|
||||
(all >> (uint32_t(Codes::Float32x4) * Codes::TotalPhys)) & Codes::AllPhysMask;
|
||||
SetType int32x4Set =
|
||||
(all >> (uint32_t(Codes::Int32x4) * Codes::TotalPhys)) & Codes::AllPhysMask;
|
||||
SetType doubleSet =
|
||||
(all >> (uint32_t(Codes::Double) * Codes::TotalPhys)) & Codes::AllPhysMask;
|
||||
SetType singleSet =
|
||||
(all >> (uint32_t(Codes::Single) * Codes::TotalPhys)) & Codes::AllPhysMask;
|
||||
|
||||
// PushRegsInMask pushes the largest register first, and thus avoids pushing
|
||||
// aliased registers. So we have to filter out the physical registers which
|
||||
// are already pushed as part of larger registers.
|
||||
SetType set128b = int32x4Set | float32x4Set;
|
||||
SetType set64b = doubleSet & ~set128b;
|
||||
SetType set32b = singleSet & ~set64b & ~set128b;
|
||||
|
||||
static_assert(Codes::AllPhysMask <= 0xffff, "We can safely use CountPopulation32");
|
||||
return mozilla::CountPopulation32(set128b) * (4 * sizeof(int32_t))
|
||||
+ mozilla::CountPopulation32(set64b) * sizeof(double)
|
||||
+ mozilla::CountPopulation32(set32b) * sizeof(float);
|
||||
}
|
||||
uint32_t
|
||||
FloatRegister::getRegisterDumpOffsetInBytes()
|
||||
{
|
||||
return code() * sizeof(double);
|
||||
return uint32_t(encoding()) * sizeof(FloatRegisters::RegisterContent);
|
||||
}
|
||||
|
@ -33,22 +33,22 @@ static MOZ_CONSTEXPR_VAR Register r14 = { X86Encoding::r14 };
|
||||
static MOZ_CONSTEXPR_VAR Register r15 = { X86Encoding::r15 };
|
||||
static MOZ_CONSTEXPR_VAR Register rsp = { X86Encoding::rsp };
|
||||
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister xmm0 = { X86Encoding::xmm0 };
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister xmm1 = { X86Encoding::xmm1 };
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister xmm2 = { X86Encoding::xmm2 };
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister xmm3 = { X86Encoding::xmm3 };
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister xmm4 = { X86Encoding::xmm4 };
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister xmm5 = { X86Encoding::xmm5 };
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister xmm6 = { X86Encoding::xmm6 };
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister xmm7 = { X86Encoding::xmm7 };
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister xmm8 = { X86Encoding::xmm8 };
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister xmm9 = { X86Encoding::xmm9 };
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister xmm10 = { X86Encoding::xmm10 };
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister xmm11 = { X86Encoding::xmm11 };
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister xmm12 = { X86Encoding::xmm12 };
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister xmm13 = { X86Encoding::xmm13 };
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister xmm14 = { X86Encoding::xmm14 };
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister xmm15 = { X86Encoding::xmm15 };
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister xmm0 = FloatRegister(X86Encoding::xmm0, FloatRegisters::Double);
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister xmm1 = FloatRegister(X86Encoding::xmm1, FloatRegisters::Double);
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister xmm2 = FloatRegister(X86Encoding::xmm2, FloatRegisters::Double);
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister xmm3 = FloatRegister(X86Encoding::xmm3, FloatRegisters::Double);
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister xmm4 = FloatRegister(X86Encoding::xmm4, FloatRegisters::Double);
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister xmm5 = FloatRegister(X86Encoding::xmm5, FloatRegisters::Double);
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister xmm6 = FloatRegister(X86Encoding::xmm6, FloatRegisters::Double);
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister xmm7 = FloatRegister(X86Encoding::xmm7, FloatRegisters::Double);
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister xmm8 = FloatRegister(X86Encoding::xmm8, FloatRegisters::Double);
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister xmm9 = FloatRegister(X86Encoding::xmm9, FloatRegisters::Double);
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister xmm10 = FloatRegister(X86Encoding::xmm10, FloatRegisters::Double);
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister xmm11 = FloatRegister(X86Encoding::xmm11, FloatRegisters::Double);
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister xmm12 = FloatRegister(X86Encoding::xmm12, FloatRegisters::Double);
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister xmm13 = FloatRegister(X86Encoding::xmm13, FloatRegisters::Double);
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister xmm14 = FloatRegister(X86Encoding::xmm14, FloatRegisters::Double);
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister xmm15 = FloatRegister(X86Encoding::xmm15, FloatRegisters::Double);
|
||||
|
||||
// X86-common synonyms.
|
||||
static MOZ_CONSTEXPR_VAR Register eax = rax;
|
||||
@ -61,7 +61,7 @@ static MOZ_CONSTEXPR_VAR Register ebp = rbp;
|
||||
static MOZ_CONSTEXPR_VAR Register esp = rsp;
|
||||
|
||||
static MOZ_CONSTEXPR_VAR Register InvalidReg = { X86Encoding::invalid_reg };
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister InvalidFloatReg = { X86Encoding::invalid_xmm };
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister InvalidFloatReg = FloatRegister();
|
||||
|
||||
static MOZ_CONSTEXPR_VAR Register StackPointer = rsp;
|
||||
static MOZ_CONSTEXPR_VAR Register FramePointer = rbp;
|
||||
@ -73,12 +73,12 @@ static MOZ_CONSTEXPR_VAR Register JSReturnReg_Data = JSReturnReg;
|
||||
static MOZ_CONSTEXPR_VAR Register ReturnReg = rax;
|
||||
static MOZ_CONSTEXPR_VAR Register ScratchReg = r11;
|
||||
static MOZ_CONSTEXPR_VAR Register HeapReg = r15;
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister ReturnFloat32Reg = xmm0;
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister ReturnDoubleReg = xmm0;
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister ReturnInt32x4Reg = xmm0;
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister ReturnFloat32x4Reg = xmm0;
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister ScratchFloat32Reg = xmm15;
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister ScratchDoubleReg = xmm15;
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister ReturnFloat32Reg = FloatRegister(X86Encoding::xmm0, FloatRegisters::Single);
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister ReturnDoubleReg = FloatRegister(X86Encoding::xmm0, FloatRegisters::Double);
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister ReturnInt32x4Reg = FloatRegister(X86Encoding::xmm0, FloatRegisters::Int32x4);
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister ReturnFloat32x4Reg = FloatRegister(X86Encoding::xmm0, FloatRegisters::Float32x4);
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister ScratchFloat32Reg = FloatRegister(X86Encoding::xmm15, FloatRegisters::Single);
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister ScratchDoubleReg = FloatRegister(X86Encoding::xmm15, FloatRegisters::Double);
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister ScratchSimdReg = xmm15;
|
||||
|
||||
// Avoid rbp, which is the FramePointer, which is unavailable in some modes.
|
||||
|
@ -123,12 +123,22 @@ class FloatRegisters {
|
||||
public:
|
||||
typedef X86Encoding::XMMRegisterID Encoding;
|
||||
|
||||
// Content spilled during bailouts.
|
||||
union RegisterContent {
|
||||
double d;
|
||||
enum ContentType {
|
||||
Single,
|
||||
Double,
|
||||
Int32x4,
|
||||
Float32x4,
|
||||
NumTypes
|
||||
};
|
||||
|
||||
// Content spilled during bailouts.
|
||||
union RegisterContent {
|
||||
float s;
|
||||
double d;
|
||||
int32_t i4[4];
|
||||
float s4[4];
|
||||
};
|
||||
|
||||
typedef uint32_t SetType;
|
||||
static const char *GetName(Encoding code) {
|
||||
return X86Encoding::XMMRegName(code);
|
||||
}
|
||||
@ -143,19 +153,35 @@ class FloatRegisters {
|
||||
|
||||
static const Encoding Invalid = X86Encoding::invalid_xmm;
|
||||
|
||||
static const uint32_t Total = 8;
|
||||
static const uint32_t Total = 8 * NumTypes;
|
||||
static const uint32_t TotalPhys = 8;
|
||||
static const uint32_t Allocatable = 7;
|
||||
|
||||
static const SetType AllMask = (1 << Total) - 1;
|
||||
static const SetType AllDoubleMask = AllMask;
|
||||
typedef uint32_t SetType;
|
||||
static_assert(sizeof(SetType) * 8 >= Total,
|
||||
"SetType should be large enough to enumerate all registers.");
|
||||
|
||||
// Magic values which are used to duplicate a mask of physical register for
|
||||
// a specific type of register. A multiplication is used to copy and shift
|
||||
// the bits of the physical register mask.
|
||||
static const SetType SpreadSingle = SetType(1) << (uint32_t(Single) * TotalPhys);
|
||||
static const SetType SpreadDouble = SetType(1) << (uint32_t(Double) * TotalPhys);
|
||||
static const SetType SpreadInt32x4 = SetType(1) << (uint32_t(Int32x4) * TotalPhys);
|
||||
static const SetType SpreadFloat32x4 = SetType(1) << (uint32_t(Float32x4) * TotalPhys);
|
||||
static const SetType SpreadScalar = SpreadSingle | SpreadDouble;
|
||||
static const SetType SpreadVector = SpreadInt32x4 | SpreadFloat32x4;
|
||||
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 VolatileMask = AllMask;
|
||||
static const SetType NonVolatileMask = 0;
|
||||
|
||||
static const SetType WrapperMask = VolatileMask;
|
||||
|
||||
static const SetType NonAllocatableMask =
|
||||
(1 << X86Encoding::xmm7); // This is ScratchDoubleReg.
|
||||
Spread * (1 << X86Encoding::xmm7); // This is ScratchDoubleReg.
|
||||
|
||||
static const SetType AllocatableMask = AllMask & ~NonAllocatableMask;
|
||||
};
|
||||
@ -170,6 +196,16 @@ struct FloatRegister {
|
||||
typedef Codes::SetType SetType;
|
||||
static uint32_t SetSize(SetType x) {
|
||||
static_assert(sizeof(SetType) == 4, "SetType must be 32 bits");
|
||||
// Count the number of non-aliased registers, for the moment.
|
||||
//
|
||||
// Copy the set bits of each typed register to the low part of the of
|
||||
// the Set, and count the number of registers. This is made to avoid
|
||||
// registers which are allocated twice with different types (such as in
|
||||
// AllMask).
|
||||
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);
|
||||
}
|
||||
static uint32_t FirstBit(SetType x) {
|
||||
@ -178,74 +214,102 @@ struct FloatRegister {
|
||||
static uint32_t LastBit(SetType x) {
|
||||
return 31 - mozilla::CountLeadingZeroes32(x);
|
||||
}
|
||||
Code code_;
|
||||
|
||||
private:
|
||||
// Note: These fields are using one extra bit to make the invalid enumerated
|
||||
// values fit, and thus prevent a warning.
|
||||
Codes::Encoding reg_ : 4;
|
||||
Codes::ContentType type_ : 3;
|
||||
bool isInvalid_ : 1;
|
||||
|
||||
// Constants used for exporting/importing the float register code.
|
||||
static const size_t RegSize = 3;
|
||||
static const size_t RegMask = (1 << RegSize) - 1;
|
||||
|
||||
public:
|
||||
MOZ_CONSTEXPR FloatRegister()
|
||||
: reg_(Codes::Encoding(0)), type_(Codes::Single), isInvalid_(true)
|
||||
{ }
|
||||
MOZ_CONSTEXPR FloatRegister(uint32_t r, Codes::ContentType k)
|
||||
: reg_(Codes::Encoding(r)), type_(k), isInvalid_(false)
|
||||
{ }
|
||||
|
||||
static FloatRegister FromCode(uint32_t i) {
|
||||
MOZ_ASSERT(i < FloatRegisters::Total);
|
||||
FloatRegister r = { Code(i) };
|
||||
return r;
|
||||
MOZ_ASSERT(i < Codes::Total);
|
||||
return FloatRegister(i & RegMask, Codes::ContentType(i >> RegSize));
|
||||
}
|
||||
|
||||
bool isSingle() const { return true; }
|
||||
bool isDouble() const { return true; }
|
||||
bool isInt32x4() const { return true; }
|
||||
bool isFloat32x4() const { return true; }
|
||||
bool isSingle() const { MOZ_ASSERT(!isInvalid()); return type_ == Codes::Single; }
|
||||
bool isDouble() const { MOZ_ASSERT(!isInvalid()); return type_ == Codes::Double; }
|
||||
bool isInt32x4() const { MOZ_ASSERT(!isInvalid()); return type_ == Codes::Int32x4; }
|
||||
bool isFloat32x4() const { MOZ_ASSERT(!isInvalid()); return type_ == Codes::Float32x4; }
|
||||
bool isInvalid() const { return isInvalid_; }
|
||||
|
||||
FloatRegister asSingle() const { return *this; }
|
||||
FloatRegister asDouble() const { return *this; }
|
||||
FloatRegister asInt32x4() const { return *this; }
|
||||
FloatRegister asFloat32x4() const { return *this; }
|
||||
FloatRegister asSingle() const { MOZ_ASSERT(!isInvalid()); return FloatRegister(reg_, Codes::Single); }
|
||||
FloatRegister asDouble() const { MOZ_ASSERT(!isInvalid()); return FloatRegister(reg_, Codes::Double); }
|
||||
FloatRegister asInt32x4() const { MOZ_ASSERT(!isInvalid()); return FloatRegister(reg_, Codes::Int32x4); }
|
||||
FloatRegister asFloat32x4() const { MOZ_ASSERT(!isInvalid()); return FloatRegister(reg_, Codes::Float32x4); }
|
||||
|
||||
uint32_t size() const {
|
||||
MOZ_ASSERT(!isInvalid());
|
||||
if (isSingle())
|
||||
return sizeof(float);
|
||||
if (isDouble())
|
||||
return sizeof(double);
|
||||
MOZ_ASSERT(isInt32x4() || isFloat32x4());
|
||||
return 4 * sizeof(int32_t);
|
||||
}
|
||||
|
||||
Code code() const {
|
||||
MOZ_ASSERT(uint32_t(code_) < FloatRegisters::Total);
|
||||
return code_;
|
||||
MOZ_ASSERT(!isInvalid());
|
||||
MOZ_ASSERT(uint32_t(reg_) < Codes::TotalPhys);
|
||||
// :TODO: ARM is doing the same thing, but we should avoid this, except
|
||||
// that the RegisterSets depends on this.
|
||||
return Code(reg_ | (type_ << RegSize));
|
||||
}
|
||||
Encoding encoding() const {
|
||||
MOZ_ASSERT(uint32_t(code_) < FloatRegisters::Total);
|
||||
return Encoding(code_);
|
||||
MOZ_ASSERT(!isInvalid());
|
||||
MOZ_ASSERT(uint32_t(reg_) < Codes::TotalPhys);
|
||||
return reg_;
|
||||
}
|
||||
const char *name() const {
|
||||
// :TODO: Add type
|
||||
return FloatRegisters::GetName(encoding());
|
||||
}
|
||||
bool volatile_() const {
|
||||
return !!((1 << code()) & FloatRegisters::VolatileMask);
|
||||
return !!((SetType(1) << code()) & FloatRegisters::VolatileMask);
|
||||
}
|
||||
bool operator !=(FloatRegister other) const {
|
||||
return other.code_ != code_;
|
||||
return other.reg_ != reg_ || other.type_ != type_;
|
||||
}
|
||||
bool operator ==(FloatRegister other) const {
|
||||
return other.code_ == code_;
|
||||
return other.reg_ == reg_ && other.type_ == type_;
|
||||
}
|
||||
bool aliases(FloatRegister other) const {
|
||||
return other.code_ == code_;
|
||||
return other.reg_ == reg_;
|
||||
}
|
||||
uint32_t numAliased() const {
|
||||
return 1;
|
||||
}
|
||||
// N.B. FloatRegister is an explicit outparam here because msvc-2010
|
||||
// miscompiled it on win64 when the value was simply returned
|
||||
void aliased(uint32_t aliasIdx, FloatRegister *ret) {
|
||||
MOZ_ASSERT(aliasIdx == 0);
|
||||
*ret = *this;
|
||||
}
|
||||
// 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.
|
||||
// Check if two floating point registers have the same type.
|
||||
bool equiv(FloatRegister other) const {
|
||||
return true;
|
||||
return other.type_ == type_;
|
||||
}
|
||||
uint32_t size() const {
|
||||
return sizeof(double);
|
||||
|
||||
uint32_t numAliased() const {
|
||||
return Codes::NumTypes;
|
||||
}
|
||||
uint32_t numAlignedAliased() const {
|
||||
return 1;
|
||||
return numAliased();
|
||||
}
|
||||
void alignedAliased(uint32_t aliasIdx, FloatRegister *ret) {
|
||||
MOZ_ASSERT(aliasIdx == 0);
|
||||
*ret = *this;
|
||||
|
||||
// N.B. FloatRegister is an explicit outparam here because msvc-2010
|
||||
// miscompiled it on win64 when the value was simply returned
|
||||
void aliased(uint32_t aliasIdx, FloatRegister *ret) const {
|
||||
MOZ_ASSERT(aliasIdx < Codes::NumTypes);
|
||||
*ret = FloatRegister(reg_, Codes::ContentType((aliasIdx + type_) % Codes::NumTypes));
|
||||
}
|
||||
void alignedAliased(uint32_t aliasIdx, FloatRegister *ret) const {
|
||||
aliased(aliasIdx, ret);
|
||||
}
|
||||
|
||||
static TypedRegisterSet<FloatRegister> ReduceSetForPush(const TypedRegisterSet<FloatRegister> &s);
|
||||
static uint32_t GetSizeInBytes(const TypedRegisterSet<FloatRegister> &s);
|
||||
static uint32_t GetPushSizeInBytes(const TypedRegisterSet<FloatRegister> &s);
|
||||
|
@ -117,10 +117,30 @@ FloatRegister::ReduceSetForPush(const FloatRegisterSet &s)
|
||||
uint32_t
|
||||
FloatRegister::GetPushSizeInBytes(const FloatRegisterSet &s)
|
||||
{
|
||||
return s.size() * sizeof(double);
|
||||
SetType all = s.bits();
|
||||
SetType float32x4Set =
|
||||
(all >> (uint32_t(Codes::Float32x4) * Codes::TotalPhys)) & Codes::AllPhysMask;
|
||||
SetType int32x4Set =
|
||||
(all >> (uint32_t(Codes::Int32x4) * Codes::TotalPhys)) & Codes::AllPhysMask;
|
||||
SetType doubleSet =
|
||||
(all >> (uint32_t(Codes::Double) * Codes::TotalPhys)) & Codes::AllPhysMask;
|
||||
SetType singleSet =
|
||||
(all >> (uint32_t(Codes::Single) * Codes::TotalPhys)) & Codes::AllPhysMask;
|
||||
|
||||
// PushRegsInMask pushes the largest register first, and thus avoids pushing
|
||||
// aliased registers. So we have to filter out the physical registers which
|
||||
// are already pushed as part of larger registers.
|
||||
SetType set128b = int32x4Set | float32x4Set;
|
||||
SetType set64b = doubleSet & ~set128b;
|
||||
SetType set32b = singleSet & ~set64b & ~set128b;
|
||||
|
||||
static_assert(Codes::AllPhysMask <= 0xffff, "We can safely use CountPopulation32");
|
||||
return mozilla::CountPopulation32(set128b) * (4 * sizeof(int32_t))
|
||||
+ mozilla::CountPopulation32(set64b) * sizeof(double)
|
||||
+ mozilla::CountPopulation32(set32b) * sizeof(float);
|
||||
}
|
||||
uint32_t
|
||||
FloatRegister::getRegisterDumpOffsetInBytes()
|
||||
{
|
||||
return code() * sizeof(double);
|
||||
return uint32_t(encoding()) * sizeof(FloatRegisters::RegisterContent);
|
||||
}
|
||||
|
@ -27,29 +27,29 @@ static MOZ_CONSTEXPR_VAR Register ebp = { X86Encoding::rbp };
|
||||
static MOZ_CONSTEXPR_VAR Register esi = { X86Encoding::rsi };
|
||||
static MOZ_CONSTEXPR_VAR Register edi = { X86Encoding::rdi };
|
||||
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister xmm0 = { X86Encoding::xmm0 };
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister xmm1 = { X86Encoding::xmm1 };
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister xmm2 = { X86Encoding::xmm2 };
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister xmm3 = { X86Encoding::xmm3 };
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister xmm4 = { X86Encoding::xmm4 };
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister xmm5 = { X86Encoding::xmm5 };
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister xmm6 = { X86Encoding::xmm6 };
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister xmm7 = { X86Encoding::xmm7 };
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister xmm0 = FloatRegister(X86Encoding::xmm0, FloatRegisters::Double);
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister xmm1 = FloatRegister(X86Encoding::xmm1, FloatRegisters::Double);
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister xmm2 = FloatRegister(X86Encoding::xmm2, FloatRegisters::Double);
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister xmm3 = FloatRegister(X86Encoding::xmm3, FloatRegisters::Double);
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister xmm4 = FloatRegister(X86Encoding::xmm4, FloatRegisters::Double);
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister xmm5 = FloatRegister(X86Encoding::xmm5, FloatRegisters::Double);
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister xmm6 = FloatRegister(X86Encoding::xmm6, FloatRegisters::Double);
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister xmm7 = FloatRegister(X86Encoding::xmm7, FloatRegisters::Double);
|
||||
|
||||
static MOZ_CONSTEXPR_VAR Register InvalidReg = { X86Encoding::invalid_reg };
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister InvalidFloatReg = { X86Encoding::invalid_xmm };
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister InvalidFloatReg = FloatRegister();
|
||||
|
||||
static MOZ_CONSTEXPR_VAR Register JSReturnReg_Type = ecx;
|
||||
static MOZ_CONSTEXPR_VAR Register JSReturnReg_Data = edx;
|
||||
static MOZ_CONSTEXPR_VAR Register StackPointer = esp;
|
||||
static MOZ_CONSTEXPR_VAR Register FramePointer = ebp;
|
||||
static MOZ_CONSTEXPR_VAR Register ReturnReg = eax;
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister ReturnFloat32Reg = xmm0;
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister ReturnDoubleReg = xmm0;
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister ReturnInt32x4Reg = xmm0;
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister ReturnFloat32x4Reg = xmm0;
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister ScratchFloat32Reg = xmm7;
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister ScratchDoubleReg = xmm7;
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister ReturnFloat32Reg = FloatRegister(X86Encoding::xmm0, FloatRegisters::Single);
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister ReturnDoubleReg = FloatRegister(X86Encoding::xmm0, FloatRegisters::Double);
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister ReturnInt32x4Reg = FloatRegister(X86Encoding::xmm0, FloatRegisters::Int32x4);
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister ReturnFloat32x4Reg = FloatRegister(X86Encoding::xmm0, FloatRegisters::Float32x4);
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister ScratchFloat32Reg = FloatRegister(X86Encoding::xmm7, FloatRegisters::Single);
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister ScratchDoubleReg = FloatRegister(X86Encoding::xmm7, FloatRegisters::Double);
|
||||
static MOZ_CONSTEXPR_VAR FloatRegister ScratchSimdReg = xmm7;
|
||||
|
||||
// Avoid ebp, which is the FramePointer, which is unavailable in some modes.
|
||||
|
Loading…
Reference in New Issue
Block a user