Bug 991153: Add machinery necessary for both register allocators to deal with aliased registers (r=bbouvier)

This commit is contained in:
Marty Rosenberg 2014-06-25 12:54:33 -04:00
parent 9479a316d2
commit d0c5858924
9 changed files with 160 additions and 25 deletions

View File

@ -379,6 +379,14 @@ LDefinition::toString() const
return buf;
}
bool
LAllocation::aliases(const LAllocation &other) const
{
if (isFloatReg() && other.isFloatReg())
return toFloatReg()->reg().aliases(other.toFloatReg()->reg());
return *this == other;
}
static void
PrintUse(char *buf, size_t size, const LUse *use)
{

View File

@ -195,8 +195,9 @@ class LAllocation : public TempObject
#else
const char *toString() const { return "???"; }
#endif
bool aliases(const LAllocation &other) const;
void dump() const;
};
class LUse : public LAllocation
@ -481,6 +482,28 @@ class LDefinition
Type type() const {
return (Type)((bits_ >> TYPE_SHIFT) & TYPE_MASK);
}
bool isCompatibleReg(const AnyRegister &r) const {
if (isFloatReg() && r.isFloat()) {
#if defined(JS_CODEGEN_ARM) && defined(EVERYONE_KNOWS_ABOUT_ALIASING)
if (type() == FLOAT32)
return r.fpu().isSingle();
return r.fpu().isDouble();
#else
return true;
#endif
}
return !isFloatReg() && !r.isFloat();
}
bool isCompatibleDef(const LDefinition &other) const {
#ifdef JS_CODEGEN_ARM
if (isFloatReg() && other.isFloatReg())
return type() == other.type();
return !isFloatReg() && !other.isFloatReg();
#else
return isFloatReg() == other.isFloatReg();
#endif
}
bool isFloatReg() const {
return type() == FLOAT32 || type() == DOUBLE;
}

View File

@ -647,7 +647,7 @@ LiveRangeAllocator<VREG, forLSRA>::buildLivenessInfo()
bool found = false;
for (size_t i = 0; i < ins->numDefs(); i++) {
if (ins->getDef(i)->isFixed() &&
*ins->getDef(i)->output() == LAllocation(*iter)) {
ins->getDef(i)->output()->aliases(LAllocation(*iter))) {
found = true;
break;
}

View File

@ -494,6 +494,12 @@ class VirtualRegister
bool isFloatReg() const {
return def_->isFloatReg();
}
bool isCompatibleReg(const AnyRegister &r) const {
return def_->isCompatibleReg(r);
}
bool isCompatibleVReg(const VirtualRegister &vr) const {
return def_->isCompatibleDef(*vr.def_);
}
LiveInterval *intervalFor(CodePosition pos);
LiveInterval *getFirstInterval();

View File

@ -66,6 +66,41 @@ struct AnyRegister {
bool volatile_() const {
return isFloat() ? fpu().volatile_() : gpr().volatile_();
}
AnyRegister aliased(uint32_t aliasIdx) const {
AnyRegister ret;
if (isFloat()) {
FloatRegister fret;
fpu().aliased(aliasIdx, &fret);
ret = AnyRegister(fret);
} else {
Register gret;
gpr().aliased(aliasIdx, &gret);
ret = AnyRegister(gret);
}
JS_ASSERT_IF(aliasIdx == 0, ret == *this);
return ret;
}
uint32_t numAliased() const {
if (isFloat())
return fpu().numAliased();
return gpr().numAliased();
}
bool aliases(const AnyRegister &other) const {
if (isFloat() && other.isFloat())
return fpu().aliases(other.fpu());
if (!isFloat() && !other.isFloat())
return gpr().aliases(other.gpr());
return false;
}
// do the two registers hold the same type of data (e.g. both float32, both gpr)
bool isCompatibleReg (const AnyRegister other) const {
if (isFloat() && other.isFloat())
return fpu().equiv(other.fpu());
if (!isFloat() && !other.isFloat())
return true;
return false;
}
};
// Registers to hold a boxed value. Uses one register on 64 bit

View File

@ -62,9 +62,9 @@ struct Register {
uint32_t numAliased() const {
return 1;
}
Register aliased(int a) const {
JS_ASSERT(a == 0);
return *this;
void aliased(uint32_t aliasIdx, Register *ret) const {
JS_ASSERT(aliasIdx == 0);
*ret = *this;
}
};

View File

@ -345,23 +345,29 @@ class VFPRegister
}
static const int NumAliasedDoubles = 16;
uint32_t numAliased() const {
return 1;
#ifdef EVERYONE_KNOWS_ABOUT_ALIASING
if (isDouble()) {
if (code_ < NumAliasedDoubles)
return 3;
return 1;
}
return 2;
#endif
}
VFPRegister aliased(uint32_t a) {
if (a == 0)
return *this;
void aliased(uint32_t aliasIdx, VFPRegister *ret) {
if (aliasIdx == 0) {
*ret = *this;
return;
}
if (isDouble()) {
JS_ASSERT(code_ < NumAliasedDoubles);
JS_ASSERT(a <= 2);
return singleOverlay(a - 1);
JS_ASSERT(aliasIdx <= 2);
*ret = singleOverlay(aliasIdx - 1);
return;
}
JS_ASSERT(a == 1);
return doubleOverlay(a - 1);
JS_ASSERT(aliasIdx == 1);
*ret = doubleOverlay(aliasIdx - 1);
}
uint32_t numAlignedAliased() const {
if (isDouble()) {
@ -369,21 +375,25 @@ class VFPRegister
return 2;
return 1;
}
// s1 has 0 other aligned aliases
// s0 has 1 other aligned aliases
// s1 has 0 other aligned aliases, 1 total.
// s0 has 1 other aligned aliase, 2 total.
return 2 - (code_ & 1);
}
VFPRegister alignedAliased(uint32_t a) {
if (a == 0)
return *this;
void alignedAliased(uint32_t aliasIdx, VFPRegister *ret) {
if (aliasIdx == 0) {
*ret = *this;
return;
}
if (isDouble()) {
JS_ASSERT(code_ < NumAliasedDoubles);
JS_ASSERT(a <= 1);
return singleOverlay(a - 1);
JS_ASSERT(aliasIdx <= 1);
*ret = singleOverlay(aliasIdx - 1);
return;
}
JS_ASSERT(a == 1);
JS_ASSERT(aliasIdx == 1);
JS_ASSERT((code_ & 1) == 0);
return doubleOverlay(a - 1);
*ret = doubleOverlay(aliasIdx - 1);
return;
}
static Code FromName(const char *name) {
return FloatRegisters::FromName(name);

View File

@ -188,7 +188,33 @@ struct FloatRegister {
bool operator ==(FloatRegister other) const {
return other.code_ == code_;
}
bool aliases(FloatRegister const &other) const;
bool aliases(FloatRegister const &other) const {
return other.code_ == code_;
}
uint32_t numAliased() {
return 1;
}
void aliased(uint32_t aliasIdx, FloatRegister *ret) {
JS_ASSERT(aliasIdx == 0);
*ret = *this;
}
// This function mostly exists for the ARM backend. It is to ensure that two
// floating point registers are equivalent. e.g. S0 is not equivalent to D16.
// Since all floating point registers on x86 and x64 are equivalent, it is
// reasonable for this function to do the same.
bool equiv(FloatRegister other) const {
return true;
}
uint32_t size() {
return sizeof(double);
}
uint32_t numAlignedAliased() {
return 1;
}
void alignedAliased(uint32_t aliasIdx, FloatRegister *ret) {
JS_ASSERT(aliasIdx == 0);
*ret = *this;
}
};
// Arm/D32 has double registers that can NOT be treated as float32

View File

@ -160,13 +160,40 @@ struct FloatRegister {
bool volatile_() const {
return !!((1 << code()) & FloatRegisters::VolatileMask);
}
bool operator != (const FloatRegister &other) const {
bool operator != (FloatRegister other) const {
return other.code_ != code_;
}
bool operator == (const FloatRegister &other) const {
bool operator == (FloatRegister other) const {
return other.code_ == code_;
}
bool aliases(FloatRegister const &other) const;
bool aliases(FloatRegister other) const {
return other.code_ == code_;
}
uint32_t numAliased() {
return 1;
}
void aliased(uint32_t aliasIdx, FloatRegister *ret) {
JS_ASSERT(aliasIdx == 0);
*ret = *this;
}
// This function mostly exists for the ARM backend. It is to ensure that two
// floating point registers are equivalent. e.g. S0 is not equivalent to D16.
// Since all floating point registers on x86 and x64 are equivalent, it is
// reasonable for this function to do the same.
bool equiv(FloatRegister other) const {
return true;
}
uint32_t size() {
return sizeof(double);
}
uint32_t numAlignedAliased() {
return 1;
}
void alignedAliased(uint32_t aliasIdx, FloatRegister *ret) {
JS_ASSERT(aliasIdx == 0);
*ret = *this;
}
};
// Arm/D32 has double registers that can NOT be treated as float32