Bug 1112164 part 14 - Add types to x86/x64 float registers. r=bbouvier,jandem

This commit is contained in:
Nicolas B. Pierron 2015-02-26 12:18:28 +01:00
parent fa375effb5
commit d578d5f79f
8 changed files with 334 additions and 152 deletions

View File

@ -2483,9 +2483,15 @@ MachineState::FromBailout(RegisterDump::GPRArray &regs, 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;
}

View File

@ -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;
}

View File

@ -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::xmm1) |
(1 << X86Encoding::xmm2) |
(1 << X86Encoding::xmm3) |
(1 << X86Encoding::xmm4) |
(1 << X86Encoding::xmm5);
( (1 << X86Encoding::xmm0) |
(1 << X86Encoding::xmm1) |
(1 << X86Encoding::xmm2) |
(1 << X86Encoding::xmm3) |
(1 << X86Encoding::xmm4) |
(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);

View File

@ -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);
}

View File

@ -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.

View File

@ -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);

View File

@ -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);
}

View File

@ -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.