mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-26 06:11:37 +00:00
Bug 1042823 - Don't blindly make MMinMax optimize for doubles, r=jandem,sunfish
This commit is contained in:
parent
477e00b11f
commit
a1e41d89c8
@ -100,7 +100,7 @@ function ToLength(v) {
|
||||
return 0;
|
||||
|
||||
// Math.pow(2, 53) - 1 = 0x1fffffffffffff
|
||||
return v < 0x1fffffffffffff ? v : 0x1fffffffffffff;
|
||||
return std_Math_min(v, 0x1fffffffffffff);
|
||||
}
|
||||
|
||||
/********** Testing code **********/
|
||||
|
@ -1147,31 +1147,64 @@ IonBuilder::inlineMathFRound(CallInfo &callInfo)
|
||||
IonBuilder::InliningStatus
|
||||
IonBuilder::inlineMathMinMax(CallInfo &callInfo, bool max)
|
||||
{
|
||||
if (callInfo.argc() < 2 || callInfo.constructing())
|
||||
if (callInfo.argc() < 1 || callInfo.constructing())
|
||||
return InliningStatus_NotInlined;
|
||||
|
||||
MIRType returnType = getInlineReturnType();
|
||||
if (!IsNumberType(returnType))
|
||||
return InliningStatus_NotInlined;
|
||||
|
||||
MDefinitionVector int32_cases(alloc());
|
||||
for (unsigned i = 0; i < callInfo.argc(); i++) {
|
||||
MIRType argType = callInfo.getArg(i)->type();
|
||||
if (!IsNumberType(argType))
|
||||
return InliningStatus_NotInlined;
|
||||
MDefinition *arg = callInfo.getArg(i);
|
||||
|
||||
// When one of the arguments is double, do a double MMinMax.
|
||||
if (returnType == MIRType_Int32 && IsFloatingPointType(argType))
|
||||
switch (arg->type()) {
|
||||
case MIRType_Int32:
|
||||
if (!int32_cases.append(arg))
|
||||
return InliningStatus_Error;
|
||||
break;
|
||||
case MIRType_Double:
|
||||
case MIRType_Float32:
|
||||
// Don't force a double MMinMax for arguments that would be a NOP
|
||||
// when doing an integer MMinMax.
|
||||
if (arg->isConstant()) {
|
||||
double cte = arg->toConstant()->value().toDouble();
|
||||
// min(int32, cte >= INT32_MAX) = int32
|
||||
if (cte >= INT32_MAX && !max)
|
||||
break;
|
||||
// max(int32, cte <= INT32_MIN) = int32
|
||||
if (cte <= INT32_MIN && max)
|
||||
break;
|
||||
}
|
||||
|
||||
// Force double MMinMax if argument is a "effectfull" double.
|
||||
returnType = MIRType_Double;
|
||||
break;
|
||||
default:
|
||||
return InliningStatus_NotInlined;
|
||||
}
|
||||
}
|
||||
|
||||
if (int32_cases.length() == 0)
|
||||
returnType = MIRType_Double;
|
||||
|
||||
callInfo.setImplicitlyUsedUnchecked();
|
||||
|
||||
MDefinitionVector &cases = (returnType == MIRType_Int32) ? int32_cases : callInfo.argv();
|
||||
|
||||
if (cases.length() == 1) {
|
||||
MLimitedTruncate *limit = MLimitedTruncate::New(alloc(), cases[0], MDefinition::NoTruncate);
|
||||
current->add(limit);
|
||||
current->push(limit);
|
||||
return InliningStatus_Inlined;
|
||||
}
|
||||
|
||||
// Chain N-1 MMinMax instructions to compute the MinMax.
|
||||
MMinMax *last = MMinMax::New(alloc(), callInfo.getArg(0), callInfo.getArg(1), returnType, max);
|
||||
MMinMax *last = MMinMax::New(alloc(), cases[0], cases[1], returnType, max);
|
||||
current->add(last);
|
||||
|
||||
for (unsigned i = 2; i < callInfo.argc(); i++) {
|
||||
MMinMax *ins = MMinMax::New(alloc(), last, callInfo.getArg(i), returnType, max);
|
||||
for (unsigned i = 2; i < cases.length(); i++) {
|
||||
MMinMax *ins = MMinMax::New(alloc(), last, cases[2], returnType, max);
|
||||
current->add(ins);
|
||||
last = ins;
|
||||
}
|
||||
|
@ -1830,6 +1830,41 @@ MMinMax::trySpecializeFloat32(TempAllocator &alloc)
|
||||
setResultType(MIRType_Float32);
|
||||
}
|
||||
|
||||
MDefinition *
|
||||
MMinMax::foldsTo(TempAllocator &alloc)
|
||||
{
|
||||
if (!lhs()->isConstant() && !rhs()->isConstant())
|
||||
return this;
|
||||
|
||||
MDefinition *operand = lhs()->isConstant() ? rhs() : lhs();
|
||||
MConstant *constant = lhs()->isConstant() ? lhs()->toConstant() : rhs()->toConstant();
|
||||
|
||||
if (operand->isToDouble() && operand->getOperand(0)->type() == MIRType_Int32) {
|
||||
const js::Value &val = constant->value();
|
||||
|
||||
// min(int32, cte >= INT32_MAX) = int32
|
||||
if (val.isDouble() && val.toDouble() >= INT32_MAX && !isMax()) {
|
||||
MLimitedTruncate *limit =
|
||||
MLimitedTruncate::New(alloc, operand->getOperand(0), MDefinition::NoTruncate);
|
||||
block()->insertBefore(this, limit);
|
||||
MToDouble *toDouble = MToDouble::New(alloc, limit);
|
||||
block()->insertBefore(this, toDouble);
|
||||
return toDouble;
|
||||
}
|
||||
|
||||
// max(int32, cte <= INT32_MIN) = int32
|
||||
if (val.isDouble() && val.toDouble() < INT32_MIN && isMax()) {
|
||||
MLimitedTruncate *limit =
|
||||
MLimitedTruncate::New(alloc, operand->getOperand(0), MDefinition::NoTruncate);
|
||||
block()->insertBefore(this, limit);
|
||||
MToDouble *toDouble = MToDouble::New(alloc, limit);
|
||||
block()->insertBefore(this, toDouble);
|
||||
return toDouble;
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
bool
|
||||
MAbs::fallible() const
|
||||
{
|
||||
@ -2976,7 +3011,7 @@ MCompare::tryFold(bool *result)
|
||||
}
|
||||
|
||||
bool
|
||||
MCompare::evaluateConstantOperands(bool *result)
|
||||
MCompare::evaluateConstantOperands(TempAllocator &alloc, bool *result)
|
||||
{
|
||||
if (type() != MIRType_Boolean && type() != MIRType_Int32)
|
||||
return false;
|
||||
@ -2984,6 +3019,73 @@ MCompare::evaluateConstantOperands(bool *result)
|
||||
MDefinition *left = getOperand(0);
|
||||
MDefinition *right = getOperand(1);
|
||||
|
||||
if (compareType() == Compare_Double) {
|
||||
// Optimize "MCompare MConstant (MToDouble SomethingInInt32Range).
|
||||
// In most cases the MToDouble was added, because the constant is
|
||||
// a double.
|
||||
// e.g. v < 9007199254740991, where v is an int32 is always true.
|
||||
if (!lhs()->isConstant() && !rhs()->isConstant())
|
||||
return false;
|
||||
|
||||
MDefinition *operand = left->isConstant() ? right : left;
|
||||
MConstant *constant = left->isConstant() ? left->toConstant() : right->toConstant();
|
||||
MOZ_ASSERT(constant->value().isDouble());
|
||||
double cte = constant->value().toDouble();
|
||||
|
||||
if (operand->isToDouble() && operand->getOperand(0)->type() == MIRType_Int32) {
|
||||
bool replaced = false;
|
||||
switch (jsop_) {
|
||||
case JSOP_LT:
|
||||
if (cte > INT32_MAX || cte < INT32_MIN) {
|
||||
*result = !((constant == lhs()) ^ (cte < INT32_MIN));
|
||||
replaced = true;
|
||||
}
|
||||
break;
|
||||
case JSOP_LE:
|
||||
if (cte >= INT32_MAX || cte <= INT32_MIN) {
|
||||
*result = !((constant == lhs()) ^ (cte <= INT32_MIN));
|
||||
replaced = true;
|
||||
}
|
||||
break;
|
||||
case JSOP_GT:
|
||||
if (cte > INT32_MAX || cte < INT32_MIN) {
|
||||
*result = !((constant == rhs()) ^ (cte < INT32_MIN));
|
||||
replaced = true;
|
||||
}
|
||||
break;
|
||||
case JSOP_GE:
|
||||
if (cte >= INT32_MAX || cte <= INT32_MIN) {
|
||||
*result = !((constant == rhs()) ^ (cte <= INT32_MIN));
|
||||
replaced = true;
|
||||
}
|
||||
break;
|
||||
case JSOP_STRICTEQ: // Fall through.
|
||||
case JSOP_EQ:
|
||||
if (cte > INT32_MAX || cte < INT32_MIN) {
|
||||
*result = false;
|
||||
replaced = true;
|
||||
}
|
||||
break;
|
||||
case JSOP_STRICTNE: // Fall through.
|
||||
case JSOP_NE:
|
||||
if (cte > INT32_MAX || cte < INT32_MIN) {
|
||||
*result = true;
|
||||
replaced = true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("Unexpected op.");
|
||||
}
|
||||
if (replaced) {
|
||||
MLimitedTruncate *limit =
|
||||
MLimitedTruncate::New(alloc, operand->getOperand(0), MDefinition::NoTruncate);
|
||||
limit->setGuardUnchecked();
|
||||
block()->insertBefore(this, limit);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!left->isConstant() || !right->isConstant())
|
||||
return false;
|
||||
|
||||
@ -3092,7 +3194,7 @@ MCompare::foldsTo(TempAllocator &alloc)
|
||||
{
|
||||
bool result;
|
||||
|
||||
if (tryFold(&result) || evaluateConstantOperands(&result)) {
|
||||
if (tryFold(&result) || evaluateConstantOperands(alloc, &result)) {
|
||||
if (type() == MIRType_Int32)
|
||||
return MConstant::New(alloc, Int32Value(result));
|
||||
|
||||
|
@ -3643,7 +3643,7 @@ class MCompare
|
||||
CompareType compareType);
|
||||
|
||||
bool tryFold(bool *result);
|
||||
bool evaluateConstantOperands(bool *result);
|
||||
bool evaluateConstantOperands(TempAllocator &alloc, bool *result);
|
||||
MDefinition *foldsTo(TempAllocator &alloc);
|
||||
void filtersUndefinedOrNull(bool trueBranch, MDefinition **subject, bool *filtersUndefined,
|
||||
bool *filtersNull);
|
||||
@ -5008,6 +5008,7 @@ class MMinMax
|
||||
AliasSet getAliasSet() const {
|
||||
return AliasSet::None();
|
||||
}
|
||||
MDefinition *foldsTo(TempAllocator &alloc);
|
||||
void computeRange(TempAllocator &alloc);
|
||||
bool writeRecoverData(CompactBufferWriter &writer) const;
|
||||
bool canRecoverOnBailout() const {
|
||||
|
Loading…
Reference in New Issue
Block a user