зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1406999: [MIPS32] Cleanup floating point registers handling; r=nbp
This commit is contained in:
Родитель
6821480454
Коммит
ebf5c48dc5
|
@ -2242,14 +2242,9 @@ MachineState::FromBailout(RegisterDump::GPRArray& regs, RegisterDump::FPUArray&
|
|||
for (unsigned i = 0; i < FloatRegisters::TotalSingle; i++)
|
||||
machine.setRegisterLocation(FloatRegister(i, FloatRegister::Single), (double*)&fbase[i]);
|
||||
#elif defined(JS_CODEGEN_MIPS32)
|
||||
float* fbase = (float*)&fpregs[0];
|
||||
for (unsigned i = 0; i < FloatRegisters::TotalDouble; i++) {
|
||||
machine.setRegisterLocation(FloatRegister::FromIndex(i, FloatRegister::Double),
|
||||
&fpregs[i].d);
|
||||
}
|
||||
for (unsigned i = 0; i < FloatRegisters::TotalSingle; i++) {
|
||||
machine.setRegisterLocation(FloatRegister::FromIndex(i, FloatRegister::Single),
|
||||
(double*)&fbase[i]);
|
||||
for (unsigned i = 0; i < FloatRegisters::TotalPhys; i++) {
|
||||
machine.setRegisterLocation(FloatRegister::FromIndex(i, FloatRegister::Double), &fpregs[i]);
|
||||
machine.setRegisterLocation(FloatRegister::FromIndex(i, FloatRegister::Single), &fpregs[i]);
|
||||
}
|
||||
#elif defined(JS_CODEGEN_MIPS64)
|
||||
for (unsigned i = 0; i < FloatRegisters::TotalPhys; i++) {
|
||||
|
|
|
@ -1967,7 +1967,7 @@ MacroAssembler::convertValueToFloatingPoint(ValueOperand value, FloatRegister ou
|
|||
jump(&done);
|
||||
|
||||
bind(&isDouble);
|
||||
FloatRegister tmp = output;
|
||||
FloatRegister tmp = output.asDouble();
|
||||
if (outputType == MIRType::Float32 && hasMultiAlias())
|
||||
tmp = ScratchDoubleReg;
|
||||
|
||||
|
|
|
@ -423,6 +423,10 @@ struct FloatRegister
|
|||
return false;
|
||||
}
|
||||
|
||||
FloatRegister asSingle() const { return FloatRegister(code_, FloatRegisters::Single); }
|
||||
FloatRegister asDouble() const { return FloatRegister(code_, FloatRegisters::Double); }
|
||||
FloatRegister asSimd128() const { MOZ_CRASH(); }
|
||||
|
||||
static uint32_t FirstBit(SetType x) {
|
||||
JS_STATIC_ASSERT(sizeof(SetType) == 8);
|
||||
return mozilla::CountTrailingZeroes64(x);
|
||||
|
|
|
@ -266,7 +266,7 @@ class FloatRegistersMIPSShared
|
|||
f31,
|
||||
invalid_freg
|
||||
};
|
||||
typedef FPRegisterID Code;
|
||||
typedef uint32_t Code;
|
||||
typedef FPRegisterID Encoding;
|
||||
|
||||
// Content spilled during bailouts.
|
||||
|
@ -274,7 +274,7 @@ class FloatRegistersMIPSShared
|
|||
double d;
|
||||
};
|
||||
|
||||
static const char* GetName(Code code) {
|
||||
static const char* GetName(Encoding code) {
|
||||
static const char * const Names[] = { "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
|
||||
"f8", "f9", "f10", "f11", "f12", "f13",
|
||||
"f14", "f15", "f16", "f17", "f18", "f19",
|
||||
|
@ -283,9 +283,13 @@ class FloatRegistersMIPSShared
|
|||
return Names[code];
|
||||
}
|
||||
|
||||
static const Code Invalid = invalid_freg;
|
||||
static const Encoding Invalid = invalid_freg;
|
||||
|
||||
#if defined(JS_CODEGEN_MIPS32)
|
||||
typedef uint32_t SetType;
|
||||
#elif defined(JS_CODEGEN_MIPS64)
|
||||
typedef uint64_t SetType;
|
||||
#endif
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
|
@ -298,16 +302,33 @@ class FloatRegisterMIPSShared
|
|||
|
||||
typedef FloatRegistersMIPSShared::SetType SetType;
|
||||
|
||||
#if defined(JS_CODEGEN_MIPS32)
|
||||
static uint32_t SetSize(SetType x) {
|
||||
static_assert(sizeof(SetType) == 8, "SetType must be 64 bits");
|
||||
static_assert(sizeof(SetType) == 4, "SetType must be 32 bits");
|
||||
return mozilla::CountPopulation32(x);
|
||||
}
|
||||
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) {
|
||||
static_assert(sizeof(SetType) == 4, "SetType must be 32 bits");
|
||||
return 31 - mozilla::CountLeadingZeroes32(x);
|
||||
}
|
||||
#elif defined(JS_CODEGEN_MIPS64)
|
||||
static uint32_t SetSize(SetType x) {
|
||||
static_assert(sizeof(SetType) == 8, "SetType must be 64 bits");
|
||||
return mozilla::CountPopulation64(x);
|
||||
}
|
||||
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) {
|
||||
static_assert(sizeof(SetType) == 8, "SetType must be 64 bits");
|
||||
return 63 - mozilla::CountLeadingZeroes64(x);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
namespace mips_private {
|
||||
|
@ -328,12 +349,12 @@ hasUnaliasedDouble() {
|
|||
return false;
|
||||
}
|
||||
|
||||
// On MIPS, fn-double aliases both fn-float32 and fn+1-float32, so if you need
|
||||
// to convert a float32 to a double as a temporary, you need a temporary
|
||||
// double register.
|
||||
// MIPS64 doesn't support it and on MIPS32 we don't allocate odd single fp
|
||||
// registers thus not exposing multi aliasing to the jit.
|
||||
// See comments in Arhitecture-mips32.h.
|
||||
inline bool
|
||||
hasMultiAlias() {
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace jit
|
||||
|
|
|
@ -58,6 +58,13 @@ js::jit::SA(uint32_t value)
|
|||
return value << SAShift;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
js::jit::FS(uint32_t value)
|
||||
{
|
||||
MOZ_ASSERT(value < 32);
|
||||
return value << FSShift;
|
||||
}
|
||||
|
||||
Register
|
||||
js::jit::toRS(Instruction& i)
|
||||
{
|
||||
|
@ -1341,15 +1348,15 @@ AssemblerMIPSShared::as_movd(FloatRegister fd, FloatRegister fs)
|
|||
BufferOffset
|
||||
AssemblerMIPSShared::as_ctc1(Register rt, FPControl fc)
|
||||
{
|
||||
spew("ctc1 %3s,%3s", rt.name(), FloatRegister(fc).name());
|
||||
return writeInst(InstReg(op_cop1, rs_ctc1, rt, FloatRegister(fc)).encode());
|
||||
spew("ctc1 %3s,%d", rt.name(), fc);
|
||||
return writeInst(InstReg(op_cop1, rs_ctc1, rt, (uint32_t)fc).encode());
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
AssemblerMIPSShared::as_cfc1(Register rt, FPControl fc)
|
||||
{
|
||||
spew("cfc1 %3s,%3s", rt.name(), FloatRegister(fc).name());
|
||||
return writeInst(InstReg(op_cop1, rs_cfc1, rt, FloatRegister(fc)).encode());
|
||||
spew("cfc1 %3s,%d", rt.name(), fc);
|
||||
return writeInst(InstReg(op_cop1, rs_cfc1, rt, (uint32_t)fc).encode());
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
|
|
|
@ -219,15 +219,14 @@ class InstJump;
|
|||
|
||||
uint32_t RS(Register r);
|
||||
uint32_t RT(Register r);
|
||||
uint32_t RT(uint32_t regCode);
|
||||
uint32_t RT(FloatRegister r);
|
||||
uint32_t RD(Register r);
|
||||
uint32_t RD(FloatRegister r);
|
||||
uint32_t RD(uint32_t regCode);
|
||||
uint32_t RZ(Register r);
|
||||
uint32_t RZ(FloatRegister r);
|
||||
uint32_t SA(uint32_t value);
|
||||
uint32_t SA(FloatRegister r);
|
||||
uint32_t FS(uint32_t value);
|
||||
|
||||
Register toRS (Instruction& i);
|
||||
Register toRT (Instruction& i);
|
||||
|
@ -1422,6 +1421,9 @@ class InstReg : public Instruction
|
|||
: Instruction(op | code | ff)
|
||||
{ }
|
||||
// for float point
|
||||
InstReg(Opcode op, RSField rs, Register rt, uint32_t fs)
|
||||
: Instruction(op | rs | RT(rt) | FS(fs))
|
||||
{ }
|
||||
InstReg(Opcode op, RSField rs, Register rt, FloatRegister rd)
|
||||
: Instruction(op | rs | RT(rt) | RD(rd))
|
||||
{ }
|
||||
|
|
|
@ -28,38 +28,33 @@ const Registers::SetType Registers::CallMask =
|
|||
(1 << Registers::v0) |
|
||||
(1 << Registers::v1); // used for double-size returns
|
||||
|
||||
FloatRegisters::Code
|
||||
FloatRegisters::Encoding
|
||||
FloatRegisters::FromName(const char* name)
|
||||
{
|
||||
for (size_t i = 0; i < Total; i++) {
|
||||
for (size_t i = 0; i < RegisterIdLimit; i++) {
|
||||
if (strcmp(GetName(i), name) == 0)
|
||||
return Code(i);
|
||||
return Encoding(i);
|
||||
}
|
||||
|
||||
return Invalid;
|
||||
}
|
||||
|
||||
FloatRegister
|
||||
FloatRegister::doubleOverlay(unsigned int which) const
|
||||
FloatRegister::doubleOverlay() const
|
||||
{
|
||||
MOZ_ASSERT(!isInvalid());
|
||||
if (kind_ != Double)
|
||||
return FloatRegister(code_ & ~1, Double);
|
||||
MOZ_ASSERT(isNotOdd());
|
||||
if (isSingle())
|
||||
return FloatRegister(code_, Double);
|
||||
return *this;
|
||||
}
|
||||
|
||||
FloatRegister
|
||||
FloatRegister::singleOverlay(unsigned int which) const
|
||||
FloatRegister::singleOverlay() const
|
||||
{
|
||||
MOZ_ASSERT(!isInvalid());
|
||||
if (kind_ == Double) {
|
||||
// Only even registers are double
|
||||
MOZ_ASSERT(code_ % 2 == 0);
|
||||
MOZ_ASSERT(which < 2);
|
||||
return FloatRegister(code_ + which, Single);
|
||||
}
|
||||
MOZ_ASSERT(which == 0);
|
||||
return FloatRegister(code_, Single);
|
||||
MOZ_ASSERT(isNotOdd());
|
||||
if (isDouble())
|
||||
return FloatRegister(code_, Single);
|
||||
return *this;
|
||||
}
|
||||
|
||||
FloatRegisterSet
|
||||
|
@ -67,12 +62,8 @@ FloatRegister::ReduceSetForPush(const FloatRegisterSet& s)
|
|||
{
|
||||
LiveFloatRegisterSet mod;
|
||||
for (FloatRegisterIterator iter(s); iter.more(); ++iter) {
|
||||
if ((*iter).isSingle()) {
|
||||
// Even for single size registers save complete double register.
|
||||
mod.addUnchecked((*iter).doubleOverlay());
|
||||
} else {
|
||||
mod.addUnchecked(*iter);
|
||||
}
|
||||
// Even for single size registers save complete double register.
|
||||
mod.addUnchecked((*iter).doubleOverlay());
|
||||
}
|
||||
return mod.set();
|
||||
}
|
||||
|
@ -83,18 +74,21 @@ FloatRegister::GetPushSizeInBytes(const FloatRegisterSet& s)
|
|||
FloatRegisterSet ss = s.reduceSetForPush();
|
||||
uint64_t bits = ss.bits();
|
||||
// We are only pushing double registers.
|
||||
MOZ_ASSERT((bits & 0xffffffff) == 0);
|
||||
uint32_t ret = mozilla::CountPopulation32(bits >> 32) * sizeof(double);
|
||||
MOZ_ASSERT((bits & 0xFFFF) == 0);
|
||||
uint32_t ret = mozilla::CountPopulation32(bits) * sizeof(double);
|
||||
|
||||
// Additional space needed by MacroAssembler::PushRegsInMask to ensure
|
||||
// correct alignment of double values.
|
||||
if (ret)
|
||||
ret += sizeof(double);
|
||||
|
||||
return ret;
|
||||
}
|
||||
uint32_t
|
||||
FloatRegister::getRegisterDumpOffsetInBytes()
|
||||
{
|
||||
if (isSingle())
|
||||
return id() * sizeof(float);
|
||||
if (isDouble())
|
||||
return id() * sizeof(double);
|
||||
MOZ_CRASH();
|
||||
MOZ_ASSERT(isNotOdd());
|
||||
return id() * sizeof(float);
|
||||
}
|
||||
|
||||
} // namespace ion
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
namespace js {
|
||||
namespace jit {
|
||||
|
||||
// Shadow stack space is not required on MIPS.
|
||||
static const uint32_t ShadowStackSpace = 4 * sizeof(uintptr_t);
|
||||
|
||||
// These offsets are specific to nunboxing, and capture offsets into the
|
||||
|
@ -32,88 +31,66 @@ static const int32_t NUNBOX32_PAYLOAD_OFFSET = 0;
|
|||
// For MIPS this is 2 instructions relative call.
|
||||
static const uint32_t BAILOUT_TABLE_ENTRY_SIZE = 2 * sizeof(void*);
|
||||
|
||||
// MIPS32 can have two types of floating-point coprocessors:
|
||||
// - 32 bit floating-point coprocessor - In this case, there are 32 single
|
||||
// MIPS32 can have two types of floating-point coprocessors modes:
|
||||
// - FR=0 mode/ 32-bit FPRs - Historical default, there are 32 single
|
||||
// precision registers and pairs of even and odd float registers are used as
|
||||
// double precision registers. Example: f0 (double) is composed of
|
||||
// f0 and f1 (single).
|
||||
// - 64 bit floating-point coprocessor - In this case, there are 32 double
|
||||
// precision register which can also be used as single precision registers.
|
||||
// f0 and f1 (single). Loongson3A FPU running in this mode doesn't allow
|
||||
// use of odd registers for single precision arithmetic.
|
||||
// - FR=1 mode/ 64-bit FPRs - In this case, there are 32 double precision register
|
||||
// which can also be used as single precision registers.
|
||||
// More info https://dmz-portal.imgtec.com/wiki/MIPS_O32_ABI_-_FR0_and_FR1_Interlinking
|
||||
|
||||
// Currently we enable 16 even single precision registers which can be also can be used
|
||||
// as double precision registers. It enables jit code to run even on Loongson3A.
|
||||
// It does not support FR=1 mode because MacroAssembler threats odd single precision
|
||||
// registers as high parts of even double precision registers.
|
||||
#ifdef __mips_fpr
|
||||
static_assert(__mips_fpr == 32, "MIPS32 jit only supports FR=0 fpu mode.");
|
||||
#endif
|
||||
|
||||
// When using O32 ABI, floating-point coprocessor is 32 bit.
|
||||
// When using N32 ABI, floating-point coprocessor is 64 bit.
|
||||
class FloatRegisters : public FloatRegistersMIPSShared
|
||||
{
|
||||
public:
|
||||
static const char* GetName(uint32_t i) {
|
||||
MOZ_ASSERT(i < Total);
|
||||
return FloatRegistersMIPSShared::GetName(Code(i % 32));
|
||||
MOZ_ASSERT(i < RegisterIdLimit);
|
||||
return FloatRegistersMIPSShared::GetName(Encoding(i % 32));
|
||||
}
|
||||
|
||||
static Code FromName(const char* name);
|
||||
static Encoding FromName(const char* name);
|
||||
|
||||
static const uint32_t Total = 64;
|
||||
static const uint32_t Total = 32;
|
||||
static const uint32_t TotalDouble = 16;
|
||||
static const uint32_t RegisterIdLimit = 32;
|
||||
// Workarounds: On Loongson CPU-s the odd FP registers behave differently
|
||||
// in fp-32 mode than standard MIPS.
|
||||
#if defined(_MIPS_ARCH_LOONGSON3A)
|
||||
static const uint32_t TotalSingle = 16;
|
||||
|
||||
static const uint32_t Allocatable = 28;
|
||||
static const SetType AllSingleMask = 0x55555555ULL;
|
||||
#else
|
||||
static const uint32_t TotalSingle = 32;
|
||||
static const uint32_t Allocatable = 42;
|
||||
static const SetType AllSingleMask = (1ULL << 32) - 1;
|
||||
#endif
|
||||
static const SetType AllSingleMask = (1ULL << TotalSingle) - 1;
|
||||
|
||||
static const SetType AllDoubleMask = ((1ULL << TotalDouble) - 1) << TotalSingle;
|
||||
static const SetType AllMask = AllDoubleMask | AllSingleMask;
|
||||
|
||||
// When saving all registers we only need to do is save double registers.
|
||||
static const uint32_t TotalPhys = 16;
|
||||
static const uint32_t RegisterIdLimit = 32;
|
||||
|
||||
static_assert(sizeof(SetType) * 8 >= Total,
|
||||
"SetType should be large enough to enumerate all registers.");
|
||||
|
||||
static const SetType AllDoubleMask = 0x55555555ULL << 32;
|
||||
static const SetType AllMask = AllDoubleMask | AllSingleMask;
|
||||
|
||||
static const SetType NonVolatileDoubleMask =
|
||||
((1ULL << FloatRegisters::f20) |
|
||||
(1ULL << FloatRegisters::f22) |
|
||||
(1ULL << FloatRegisters::f24) |
|
||||
(1ULL << FloatRegisters::f26) |
|
||||
(1ULL << FloatRegisters::f28) |
|
||||
(1ULL << FloatRegisters::f30)) << 32;
|
||||
|
||||
// f20-single and f21-single alias f20-double ...
|
||||
static const SetType NonVolatileMask =
|
||||
NonVolatileDoubleMask |
|
||||
(1ULL << FloatRegisters::f20) |
|
||||
(1ULL << FloatRegisters::f21) |
|
||||
(1ULL << FloatRegisters::f22) |
|
||||
(1ULL << FloatRegisters::f23) |
|
||||
(1ULL << FloatRegisters::f24) |
|
||||
(1ULL << FloatRegisters::f25) |
|
||||
(1ULL << FloatRegisters::f26) |
|
||||
(1ULL << FloatRegisters::f27) |
|
||||
(1ULL << FloatRegisters::f28) |
|
||||
(1ULL << FloatRegisters::f29) |
|
||||
(1ULL << FloatRegisters::f30) |
|
||||
(1ULL << FloatRegisters::f31);
|
||||
((SetType(1) << (FloatRegisters::f20 >> 1)) |
|
||||
(SetType(1) << (FloatRegisters::f22 >> 1)) |
|
||||
(SetType(1) << (FloatRegisters::f24 >> 1)) |
|
||||
(SetType(1) << (FloatRegisters::f26 >> 1)) |
|
||||
(SetType(1) << (FloatRegisters::f28 >> 1)) |
|
||||
(SetType(1) << (FloatRegisters::f30 >> 1))) * ((1 << TotalSingle) + 1);
|
||||
|
||||
static const SetType VolatileMask = AllMask & ~NonVolatileMask;
|
||||
static const SetType VolatileDoubleMask = AllDoubleMask & ~NonVolatileDoubleMask;
|
||||
|
||||
static const SetType WrapperMask = VolatileMask;
|
||||
|
||||
static const SetType NonAllocatableDoubleMask =
|
||||
((1ULL << FloatRegisters::f16) |
|
||||
(1ULL << FloatRegisters::f18)) << 32;
|
||||
// f16-single and f17-single alias f16-double ...
|
||||
static const SetType NonAllocatableMask =
|
||||
NonAllocatableDoubleMask |
|
||||
(1ULL << FloatRegisters::f16) |
|
||||
(1ULL << FloatRegisters::f17) |
|
||||
(1ULL << FloatRegisters::f18) |
|
||||
(1ULL << FloatRegisters::f19);
|
||||
((SetType(1) << (FloatRegisters::f16 >> 1)) |
|
||||
(SetType(1) << (FloatRegisters::f18 >> 1))) * ((1 << TotalSingle) + 1);
|
||||
|
||||
// Registers that can be allocated without being saved, generally.
|
||||
static const SetType TempMask = VolatileMask & ~NonAllocatableMask;
|
||||
|
@ -133,16 +110,16 @@ class FloatRegister : public FloatRegisterMIPSShared
|
|||
typedef Codes::Code Code;
|
||||
typedef Codes::Encoding Encoding;
|
||||
|
||||
uint32_t code_ : 6;
|
||||
Encoding code_ : 6;
|
||||
protected:
|
||||
RegType kind_ : 1;
|
||||
|
||||
public:
|
||||
constexpr FloatRegister(uint32_t code, RegType kind = Double)
|
||||
: code_ (Code(code)), kind_(kind)
|
||||
: code_ (Encoding(code)), kind_(kind)
|
||||
{ }
|
||||
constexpr FloatRegister()
|
||||
: code_(Code(FloatRegisters::invalid_freg)), kind_(Double)
|
||||
: code_(FloatRegisters::invalid_freg), kind_(Double)
|
||||
{ }
|
||||
|
||||
bool operator==(const FloatRegister& other) const {
|
||||
|
@ -156,52 +133,43 @@ class FloatRegister : public FloatRegisterMIPSShared
|
|||
return code_ == FloatRegisters::invalid_freg;
|
||||
}
|
||||
|
||||
bool isNotOdd() const { return !isInvalid() && ((code_ & 1) == 0); }
|
||||
|
||||
bool isSingle() const { return kind_ == Single; }
|
||||
bool isDouble() const { return kind_ == Double; }
|
||||
|
||||
FloatRegister doubleOverlay(unsigned int which = 0) const;
|
||||
FloatRegister singleOverlay(unsigned int which = 0) const;
|
||||
FloatRegister sintOverlay(unsigned int which = 0) const;
|
||||
FloatRegister uintOverlay(unsigned int which = 0) const;
|
||||
FloatRegister doubleOverlay() const;
|
||||
FloatRegister singleOverlay() const;
|
||||
|
||||
FloatRegister asSingle() const { return singleOverlay(); }
|
||||
FloatRegister asDouble() const { return doubleOverlay(); }
|
||||
FloatRegister asSimd128() const { MOZ_CRASH("NYI"); }
|
||||
|
||||
Code code() const {
|
||||
MOZ_ASSERT(!isInvalid());
|
||||
return Code(code_ | (kind_ << 5));
|
||||
MOZ_ASSERT(isNotOdd());
|
||||
return Code((code_ >> 1) | (kind_ << 4));
|
||||
}
|
||||
Encoding encoding() const {
|
||||
MOZ_ASSERT(!isInvalid());
|
||||
return Encoding(code_);
|
||||
return code_;
|
||||
}
|
||||
uint32_t id() const {
|
||||
MOZ_ASSERT(!isInvalid());
|
||||
return code_;
|
||||
}
|
||||
static FloatRegister FromCode(uint32_t i) {
|
||||
uint32_t code = i & 31;
|
||||
uint32_t kind = i >> 5;
|
||||
return FloatRegister(code, RegType(kind));
|
||||
uint32_t code = i & 15;
|
||||
uint32_t kind = i >> 4;
|
||||
return FloatRegister(Encoding(code << 1), RegType(kind));
|
||||
}
|
||||
// This is similar to FromCode except for double registers on O32.
|
||||
|
||||
static FloatRegister FromIndex(uint32_t index, RegType kind) {
|
||||
#if defined(USES_O32_ABI)
|
||||
// Only even FP registers are avaiable for Loongson on O32.
|
||||
# if defined(_MIPS_ARCH_LOONGSON3A)
|
||||
return FloatRegister(index * 2, kind);
|
||||
# else
|
||||
if (kind == Double)
|
||||
return FloatRegister(index * 2, kind);
|
||||
# endif
|
||||
#endif
|
||||
return FloatRegister(index, kind);
|
||||
MOZ_ASSERT(index < 16);
|
||||
return FloatRegister(Encoding(index << 1), kind);
|
||||
}
|
||||
|
||||
bool volatile_() const {
|
||||
if (isDouble())
|
||||
return !!((1ULL << code_) & FloatRegisters::VolatileMask);
|
||||
return !!((1ULL << (code_ & ~1)) & FloatRegisters::VolatileMask);
|
||||
return !!((SetType(1) << code()) & FloatRegisters::VolatileMask);
|
||||
}
|
||||
const char* name() const {
|
||||
return FloatRegisters::GetName(code_);
|
||||
|
@ -210,61 +178,49 @@ class FloatRegister : public FloatRegisterMIPSShared
|
|||
return other.kind_ != kind_ || code_ != other.code_;
|
||||
}
|
||||
bool aliases(const FloatRegister& other) {
|
||||
if (kind_ == other.kind_)
|
||||
return code_ == other.code_;
|
||||
return doubleOverlay() == other.doubleOverlay();
|
||||
MOZ_ASSERT(isNotOdd());
|
||||
return code_ == other.code_;
|
||||
}
|
||||
uint32_t numAliased() const {
|
||||
if (isDouble()) {
|
||||
MOZ_ASSERT((code_ & 1) == 0);
|
||||
return 3;
|
||||
}
|
||||
MOZ_ASSERT(isNotOdd());
|
||||
return 2;
|
||||
}
|
||||
void aliased(uint32_t aliasIdx, FloatRegister* ret) {
|
||||
MOZ_ASSERT(isNotOdd());
|
||||
|
||||
if (aliasIdx == 0) {
|
||||
*ret = *this;
|
||||
return;
|
||||
}
|
||||
if (isDouble()) {
|
||||
MOZ_ASSERT((code_ & 1) == 0);
|
||||
MOZ_ASSERT(aliasIdx <= 2);
|
||||
*ret = singleOverlay(aliasIdx - 1);
|
||||
return;
|
||||
}
|
||||
MOZ_ASSERT(aliasIdx == 1);
|
||||
*ret = doubleOverlay(aliasIdx - 1);
|
||||
if (isDouble()) {
|
||||
*ret = singleOverlay();
|
||||
} else {
|
||||
*ret = doubleOverlay();
|
||||
}
|
||||
}
|
||||
uint32_t numAlignedAliased() const {
|
||||
if (isDouble()) {
|
||||
MOZ_ASSERT((code_ & 1) == 0);
|
||||
return 2;
|
||||
}
|
||||
// f1-float32 has 0 other aligned aliases, 1 total.
|
||||
// f0-float32 has 1 other aligned alias, 2 total.
|
||||
return 2 - (code_ & 1);
|
||||
MOZ_ASSERT(isNotOdd());
|
||||
return 2;
|
||||
}
|
||||
// | f0-double |
|
||||
// | f0-float32 | f1-float32 |
|
||||
// We only push double registers on MIPS. So, if we've stored f0-double
|
||||
// we also want to f0-float32 is stored there.
|
||||
void alignedAliased(uint32_t aliasIdx, FloatRegister* ret) {
|
||||
MOZ_ASSERT(isDouble());
|
||||
MOZ_ASSERT((code_ & 1) == 0);
|
||||
MOZ_ASSERT(isNotOdd());
|
||||
|
||||
if (aliasIdx == 0) {
|
||||
*ret = *this;
|
||||
return;
|
||||
}
|
||||
MOZ_ASSERT(aliasIdx == 1);
|
||||
*ret = singleOverlay(aliasIdx - 1);
|
||||
if (isDouble()) {
|
||||
*ret = singleOverlay();
|
||||
} else {
|
||||
*ret = doubleOverlay();
|
||||
}
|
||||
}
|
||||
|
||||
SetType alignedOrDominatedAliasedSet() const {
|
||||
if (isSingle())
|
||||
return SetType(1) << code_;
|
||||
|
||||
MOZ_ASSERT(isDouble());
|
||||
return SetType(0b11) << code_;
|
||||
MOZ_ASSERT(isNotOdd());
|
||||
return (SetType(1) << (code_ >> 1)) * ((1 << FloatRegisters::TotalSingle) + 1);
|
||||
}
|
||||
|
||||
static constexpr RegTypeName DefaultType = RegTypeName::Float64;
|
||||
|
@ -306,6 +262,21 @@ FloatRegister::LiveAsIndexableSet<RegTypeName::Any>(SetType set)
|
|||
return set;
|
||||
}
|
||||
|
||||
template <> inline FloatRegister::SetType
|
||||
FloatRegister::AllocatableAsIndexableSet<RegTypeName::Float32>(SetType set)
|
||||
{
|
||||
// Single registers are not dominating any smaller registers, thus masking
|
||||
// is enough to convert an allocatable set into a set of register list all
|
||||
// single register available.
|
||||
return set & FloatRegisters::AllSingleMask;
|
||||
}
|
||||
|
||||
template <> inline FloatRegister::SetType
|
||||
FloatRegister::AllocatableAsIndexableSet<RegTypeName::Float64>(SetType set)
|
||||
{
|
||||
return set & FloatRegisters::AllDoubleMask;
|
||||
}
|
||||
|
||||
// In order to handle functions such as int(*)(int, double) where the first
|
||||
// argument is a general purpose register, and the second argument is a floating
|
||||
// point register, we have to store the double content into 2 general purpose
|
||||
|
|
|
@ -157,7 +157,9 @@ class Assembler : public AssemblerMIPSShared
|
|||
// precision registers that make one double register.
|
||||
FloatRegister getOddPair(FloatRegister reg) {
|
||||
MOZ_ASSERT(reg.isDouble());
|
||||
return reg.singleOverlay(1);
|
||||
MOZ_ASSERT(reg.id() % 2 == 0);
|
||||
FloatRegister odd(reg.id() | 1, FloatRegister::Single);
|
||||
return odd;
|
||||
}
|
||||
|
||||
public:
|
||||
|
|
|
@ -826,6 +826,5 @@ CodeGeneratorMIPS::setReturnDoubleRegs(LiveRegisterSet* regs)
|
|||
{
|
||||
MOZ_ASSERT(ReturnFloat32Reg.code_ == ReturnDoubleReg.code_);
|
||||
regs->add(ReturnFloat32Reg);
|
||||
regs->add(ReturnDoubleReg.singleOverlay(1));
|
||||
regs->add(ReturnDoubleReg);
|
||||
}
|
|
@ -751,7 +751,7 @@ MacroAssemblerMIPS::ma_ss(FloatRegister ft, Address address)
|
|||
void
|
||||
MacroAssemblerMIPS::ma_pop(FloatRegister fs)
|
||||
{
|
||||
ma_ld(fs.doubleOverlay(0), Address(StackPointer, 0));
|
||||
ma_ld(fs.doubleOverlay(), Address(StackPointer, 0));
|
||||
as_addiu(StackPointer, StackPointer, sizeof(double));
|
||||
}
|
||||
|
||||
|
@ -759,7 +759,7 @@ void
|
|||
MacroAssemblerMIPS::ma_push(FloatRegister fs)
|
||||
{
|
||||
as_addiu(StackPointer, StackPointer, -sizeof(double));
|
||||
ma_sd(fs.doubleOverlay(0), Address(StackPointer, 0));
|
||||
ma_sd(fs.doubleOverlay(), Address(StackPointer, 0));
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -2110,18 +2110,22 @@ MacroAssembler::PushRegsInMask(LiveRegisterSet set)
|
|||
}
|
||||
MOZ_ASSERT(diffG == 0);
|
||||
|
||||
// Double values have to be aligned. We reserve extra space so that we can
|
||||
// start writing from the first aligned location.
|
||||
// We reserve a whole extra double so that the buffer has even size.
|
||||
ma_and(SecondScratchReg, sp, Imm32(~(ABIStackAlignment - 1)));
|
||||
reserveStack(diffF + sizeof(double));
|
||||
if (diffF > 0) {
|
||||
// Double values have to be aligned. We reserve extra space so that we can
|
||||
// start writing from the first aligned location.
|
||||
// We reserve a whole extra double so that the buffer has even size.
|
||||
ma_and(SecondScratchReg, sp, Imm32(~(ABIStackAlignment - 1)));
|
||||
reserveStack(diffF);
|
||||
|
||||
for (FloatRegisterForwardIterator iter(set.fpus().reduceSetForPush()); iter.more(); ++iter) {
|
||||
if ((*iter).code() % 2 == 0)
|
||||
as_sd(*iter, SecondScratchReg, -diffF);
|
||||
diffF -= sizeof(double);
|
||||
|
||||
for (FloatRegisterForwardIterator iter(set.fpus().reduceSetForPush()); iter.more(); ++iter) {
|
||||
as_sd(*iter, SecondScratchReg, -diffF);
|
||||
diffF -= sizeof(double);
|
||||
}
|
||||
|
||||
MOZ_ASSERT(diffF == 0);
|
||||
}
|
||||
MOZ_ASSERT(diffF == 0);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -2132,18 +2136,22 @@ MacroAssembler::PopRegsInMaskIgnore(LiveRegisterSet set, LiveRegisterSet ignore)
|
|||
const int32_t reservedG = diffG;
|
||||
const int32_t reservedF = diffF;
|
||||
|
||||
// Read the buffer form the first aligned location.
|
||||
ma_addu(SecondScratchReg, sp, Imm32(reservedF + sizeof(double)));
|
||||
ma_and(SecondScratchReg, SecondScratchReg, Imm32(~(ABIStackAlignment - 1)));
|
||||
if (reservedF > 0) {
|
||||
// Read the buffer form the first aligned location.
|
||||
ma_addu(SecondScratchReg, sp, Imm32(reservedF));
|
||||
ma_and(SecondScratchReg, SecondScratchReg, Imm32(~(ABIStackAlignment - 1)));
|
||||
|
||||
for (FloatRegisterForwardIterator iter(set.fpus().reduceSetForPush()); iter.more(); ++iter) {
|
||||
if (!ignore.has(*iter) && ((*iter).code() % 2 == 0))
|
||||
// Use assembly l.d because we have alligned the stack.
|
||||
as_ld(*iter, SecondScratchReg, -diffF);
|
||||
diffF -= sizeof(double);
|
||||
|
||||
LiveFloatRegisterSet fpignore(ignore.fpus().reduceSetForPush());
|
||||
for (FloatRegisterForwardIterator iter(set.fpus().reduceSetForPush()); iter.more(); ++iter) {
|
||||
if (!ignore.has(*iter))
|
||||
as_ld(*iter, SecondScratchReg, -diffF);
|
||||
diffF -= sizeof(double);
|
||||
}
|
||||
freeStack(reservedF);
|
||||
MOZ_ASSERT(diffF == 0);
|
||||
}
|
||||
freeStack(reservedF + sizeof(double));
|
||||
MOZ_ASSERT(diffF == 0);
|
||||
|
||||
for (GeneralRegisterBackwardIterator iter(set.gprs()); iter.more(); ++iter) {
|
||||
diffG -= sizeof(intptr_t);
|
||||
|
@ -2155,14 +2163,13 @@ MacroAssembler::PopRegsInMaskIgnore(LiveRegisterSet set, LiveRegisterSet ignore)
|
|||
}
|
||||
|
||||
void
|
||||
MacroAssembler::storeRegsInMask(LiveRegisterSet set, Address dest, Register)
|
||||
MacroAssembler::storeRegsInMask(LiveRegisterSet set, Address dest, Register scratch)
|
||||
{
|
||||
FloatRegisterSet fpuSet(set.fpus().reduceSetForPush());
|
||||
unsigned numFpu = fpuSet.size();
|
||||
int32_t diffF = fpuSet.getPushSizeInBytes();
|
||||
int32_t diffF = set.fpus().getPushSizeInBytes();
|
||||
int32_t diffG = set.gprs().size() * sizeof(intptr_t);
|
||||
|
||||
MOZ_ASSERT(dest.offset >= diffG + diffF);
|
||||
MOZ_ASSERT(dest.base == StackPointer);
|
||||
|
||||
for (GeneralRegisterBackwardIterator iter(set.gprs()); iter.more(); ++iter) {
|
||||
diffG -= sizeof(intptr_t);
|
||||
|
@ -2171,21 +2178,19 @@ MacroAssembler::storeRegsInMask(LiveRegisterSet set, Address dest, Register)
|
|||
}
|
||||
MOZ_ASSERT(diffG == 0);
|
||||
|
||||
for (FloatRegisterBackwardIterator iter(fpuSet); iter.more(); ++iter) {
|
||||
FloatRegister reg = *iter;
|
||||
diffF -= reg.size();
|
||||
numFpu -= 1;
|
||||
dest.offset -= reg.size();
|
||||
if (reg.isDouble())
|
||||
storeDouble(reg, dest);
|
||||
else if (reg.isSingle())
|
||||
storeFloat32(reg, dest);
|
||||
else
|
||||
MOZ_CRASH("Unknown register type.");
|
||||
if (diffF > 0) {
|
||||
|
||||
computeEffectiveAddress(dest, scratch);
|
||||
ma_and(scratch, scratch, Imm32(~(ABIStackAlignment - 1)));
|
||||
|
||||
diffF -= sizeof(double);
|
||||
|
||||
for (FloatRegisterForwardIterator iter(set.fpus().reduceSetForPush()); iter.more(); ++iter) {
|
||||
as_sd(*iter, scratch, -diffF);
|
||||
diffF -= sizeof(double);
|
||||
}
|
||||
MOZ_ASSERT(diffF == 0);
|
||||
}
|
||||
MOZ_ASSERT(numFpu == 0);
|
||||
diffF -= diffF % sizeof(uintptr_t);
|
||||
MOZ_ASSERT(diffF == 0);
|
||||
}
|
||||
// ===============================================================
|
||||
// ABI function calls.
|
||||
|
|
|
@ -239,11 +239,7 @@ static const LiveRegisterSet NonVolatileRegs =
|
|||
FloatRegisterSet(FloatRegisters::NonVolatileMask));
|
||||
#endif
|
||||
|
||||
#if defined(JS_CODEGEN_MIPS32)
|
||||
static const unsigned NonVolatileRegsPushSize = NonVolatileRegs.gprs().size() * sizeof(intptr_t) +
|
||||
NonVolatileRegs.fpus().getPushSizeInBytes() +
|
||||
sizeof(double);
|
||||
#elif defined(JS_CODEGEN_NONE)
|
||||
#if defined(JS_CODEGEN_NONE)
|
||||
static const unsigned NonVolatileRegsPushSize = 0;
|
||||
#else
|
||||
static const unsigned NonVolatileRegsPushSize = NonVolatileRegs.gprs().size() * sizeof(intptr_t) +
|
||||
|
|
Загрузка…
Ссылка в новой задаче