Bug 1752504: Fold binary MIR operations involving NaN. r=jandem

Differential Revision: https://phabricator.services.mozilla.com/D218747
This commit is contained in:
André Bargull 2024-08-08 13:37:01 +00:00
Родитель 25ca34e36c
Коммит c29d5c26c2
3 изменённых файлов: 97 добавлений и 1 удалений

Просмотреть файл

@ -1992,7 +1992,7 @@ function rint32tobigint(i) {
let uceFault_nantozero_nan = eval(`(${uceFault})`.replace('uceFault', 'uceFault_nantozero_nan'));
function rnantozero_nan(i) {
// Note: |x| must be Double-typed.
var x = (i + 0.5) * NaN;
var x = NaN ** (i + 0.5);
var y = x ? x : +0;
if (uceFault_nantozero_nan(i) || uceFault_nantozero_nan(i))
assertEq(y, +0);

Просмотреть файл

@ -0,0 +1,52 @@
const values = [
-Infinity,
-Number.MAX_VALUE,
-Number.MIN_VALUE,
-0,
+0,
+Number.MIN_VALUE,
+Number.MAX_VALUE
+Infinity,
-123,
-0.5,
+123,
+0.5,
];
for (let i = 0; i < 200; ++i) {
let val = values[i % values.length];
// rhs is NaN
assertEq(val + NaN, NaN);
assertEq(val - NaN, NaN);
assertEq(val * NaN, NaN);
assertEq(val / NaN, NaN);
assertEq(val % NaN, NaN);
assertEq(val ** NaN, NaN);
// rhs is undefined, ToNumber(undefined) is NaN
assertEq(val + undefined, NaN);
assertEq(val - undefined, NaN);
assertEq(val * undefined, NaN);
assertEq(val / undefined, NaN);
assertEq(val % undefined, NaN);
assertEq(val ** undefined, NaN);
// lhs is NaN
assertEq(NaN + val, NaN);
assertEq(NaN - val, NaN);
assertEq(NaN * val, NaN);
assertEq(NaN / val, NaN);
assertEq(NaN % val, NaN);
assertEq(NaN ** val, (val === 0 ? 1 : NaN));
// lhs is undefined, ToNumber(undefined) is NaN
assertEq(undefined + val, NaN);
assertEq(undefined - val, NaN);
assertEq(undefined * val, NaN);
assertEq(undefined / val, NaN);
assertEq(undefined % val, NaN);
assertEq(undefined ** val, (val === 0 ? 1 : NaN));
}

Просмотреть файл

@ -309,6 +309,40 @@ static MConstant* EvaluateConstantOperands(TempAllocator& alloc,
return MConstant::New(alloc, retVal);
}
static MConstant* EvaluateConstantNaNOperand(MBinaryInstruction* ins) {
auto* left = ins->lhs();
auto* right = ins->rhs();
MOZ_ASSERT(IsTypeRepresentableAsDouble(left->type()));
MOZ_ASSERT(IsTypeRepresentableAsDouble(right->type()));
MOZ_ASSERT(left->type() == ins->type());
MOZ_ASSERT(right->type() == ins->type());
// Don't fold NaN if we can't return a floating point type.
if (!IsFloatingPointType(ins->type())) {
return nullptr;
}
MOZ_ASSERT(!left->isConstant() || !right->isConstant(),
"EvaluateConstantOperands should have handled this case");
// One operand must be a constant NaN.
MConstant* cst;
if (left->isConstant()) {
cst = left->toConstant();
} else if (right->isConstant()) {
cst = right->toConstant();
} else {
return nullptr;
}
if (!std::isnan(cst->numberToDouble())) {
return nullptr;
}
// Fold to constant NaN.
return cst;
}
static MMul* EvaluateExactReciprocal(TempAllocator& alloc, MDiv* ins) {
// we should fold only when it is a floating point operation
if (!IsFloatingPointType(ins->type())) {
@ -2844,6 +2878,11 @@ MDefinition* MBinaryArithInstruction::foldsTo(TempAllocator& alloc) {
return folded;
}
if (MConstant* folded = EvaluateConstantNaNOperand(this)) {
MOZ_ASSERT(!isTruncated());
return folded;
}
if (mustPreserveNaN_) {
return this;
}
@ -3224,6 +3263,11 @@ MDefinition* MPow::foldsConstantPower(TempAllocator& alloc) {
return multiply(y, y);
}
// Math.pow(x, NaN) == NaN.
if (std::isnan(pow)) {
return power();
}
// No optimization
return nullptr;
}