Bug 1302367 - Use unsigned integer modulo instead of ModD opcode. r=nbp, r=jandem

--HG--
extra : rebase_source : 63337ef0e28137e69e7d7894cb21dcc5c3300c5e
This commit is contained in:
Sander Mathijs van Veen 2016-10-03 02:36:00 -04:00
parent 299f264eae
commit acb9b45ad4
3 changed files with 71 additions and 2 deletions

View File

@ -2736,6 +2736,20 @@ MBinaryBitwiseInstruction::foldsTo(TempAllocator& alloc)
MDefinition*
MBinaryBitwiseInstruction::foldUnnecessaryBitop()
{
// Fold unsigned shift right operator when the second operand is zero and
// the only use is an unsigned modulo. Thus, the expression
// |(x >>> 0) % y| becomes |x % y|.
if (isUrsh() && hasOneDefUse() && getOperand(1)->isConstant()) {
MConstant* constant = getOperand(1)->toConstant();
if (constant->type() == MIRType::Int32 && constant->toInt32() == 0) {
for (MUseDefIterator use(this); use; use++) {
if (use.def()->isMod() && use.def()->toMod()->isUnsigned())
return getOperand(0);
break;
}
}
}
if (specialization_ != MIRType::Int32)
return this;

View File

@ -7139,23 +7139,51 @@ class MDiv : public MBinaryArithInstruction
class MMod : public MBinaryArithInstruction
{
public:
enum class PossiblyUnsigned {
NotPossible,
LHSPossible,
RHSPossible,
BothPossible,
};
protected:
bool unsigned_;
bool canBeNegativeDividend_;
bool canBePowerOfTwoDivisor_;
bool canBeDivideByZero_;
bool trapOnError_;
PossiblyUnsigned possiblyUnsigned_;
MMod(MDefinition* left, MDefinition* right, MIRType type)
: MBinaryArithInstruction(left, right),
unsigned_(false),
canBeNegativeDividend_(true),
canBePowerOfTwoDivisor_(true),
canBeDivideByZero_(true),
trapOnError_(false)
trapOnError_(false),
possiblyUnsigned_(PossiblyUnsigned::NotPossible)
{
if (type != MIRType::Value)
specialization_ = type;
setResultType(type);
if (left->isUrsh() && left->getOperand(1)->isConstant()) {
MConstant* constant = left->getOperand(1)->toConstant();
if (constant->type() == MIRType::Int32 && constant->toInt32() == 0)
possiblyUnsigned_ = PossiblyUnsigned::LHSPossible;
}
if (right->isUrsh() && right->getOperand(1)->isConstant()) {
MConstant* constant = right->getOperand(1)->toConstant();
if (constant->type() == MIRType::Int32 && constant->toInt32() == 0) {
if (possiblyUnsigned_ == PossiblyUnsigned::NotPossible)
possiblyUnsigned_ = PossiblyUnsigned::RHSPossible;
else
possiblyUnsigned_ = PossiblyUnsigned::BothPossible;
}
}
}
public:

View File

@ -1561,13 +1561,40 @@ MMod::computeRange(TempAllocator& alloc)
// If either operand is a NaN, the result is NaN. This also conservatively
// handles Infinity cases.
if (!lhs.hasInt32Bounds() || !rhs.hasInt32Bounds())
if ((possiblyUnsigned_ == PossiblyUnsigned::NotPossible &&
!lhs.hasInt32Bounds()) || !rhs.hasInt32Bounds())
{
return;
}
// If RHS can be zero, the result can be NaN.
if (rhs.lower() <= 0 && rhs.upper() >= 0)
return;
// (x >>> 0) % y is an unsigned modulo operation but the lhs' range is not
// always >= 0. The lhs range assumes a signed integer 32 bit while the
// value is unsigned 32 bit. That breaks the assumption that range >= 0.
if (specialization() == MIRType::Int32) {
switch (possiblyUnsigned_) {
case PossiblyUnsigned::NotPossible:
break;
case PossiblyUnsigned::LHSPossible:
if (rhs.lower() > 0 && !rhs.canHaveFractionalPart())
unsigned_ = true;
break;
case PossiblyUnsigned::RHSPossible:
if (lhs.lower() >= 0 && !lhs.canHaveFractionalPart())
unsigned_ = true;
break;
case PossiblyUnsigned::BothPossible:
if (lhs.lower() >= 0 && !lhs.canHaveFractionalPart())
unsigned_ = true;
else if (rhs.lower() > 0 && !rhs.canHaveFractionalPart())
unsigned_ = true;
break;
}
}
// If both operands are non-negative integers, we can optimize this to an
// unsigned mod.
if (specialization() == MIRType::Int32 && lhs.lower() >= 0 && rhs.lower() > 0 &&