зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1293313
- IonMonkey: Handle non-canonical NaNs in constant folding. r=luke
This commit is contained in:
Родитель
cbb507cc3e
Коммит
95d7524476
|
@ -681,7 +681,7 @@ BUILD_JSVAL(JSValueTag tag, uint64_t payload)
|
|||
static inline bool
|
||||
JSVAL_IS_DOUBLE_IMPL(jsval_layout l)
|
||||
{
|
||||
return l.asBits <= JSVAL_SHIFTED_TAG_MAX_DOUBLE;
|
||||
return (l.asBits | mozilla::DoubleTypeTraits::kSignBit) <= JSVAL_SHIFTED_TAG_MAX_DOUBLE;
|
||||
}
|
||||
|
||||
static inline jsval_layout
|
||||
|
@ -689,7 +689,7 @@ DOUBLE_TO_JSVAL_IMPL(double d)
|
|||
{
|
||||
jsval_layout l;
|
||||
l.asDouble = d;
|
||||
MOZ_ASSERT(l.asBits <= JSVAL_SHIFTED_TAG_MAX_DOUBLE);
|
||||
MOZ_ASSERT(JSVAL_IS_DOUBLE_IMPL(l));
|
||||
return l;
|
||||
}
|
||||
|
||||
|
@ -941,9 +941,8 @@ MAGIC_UINT32_TO_JSVAL_IMPL(uint32_t payload)
|
|||
static inline bool
|
||||
JSVAL_SAME_TYPE_IMPL(jsval_layout lhs, jsval_layout rhs)
|
||||
{
|
||||
uint64_t lbits = lhs.asBits, rbits = rhs.asBits;
|
||||
return (lbits <= JSVAL_SHIFTED_TAG_MAX_DOUBLE && rbits <= JSVAL_SHIFTED_TAG_MAX_DOUBLE) ||
|
||||
(((lbits ^ rbits) & 0xFFFF800000000000LL) == 0);
|
||||
return (JSVAL_IS_DOUBLE_IMPL(lhs) && JSVAL_IS_DOUBLE_IMPL(rhs)) ||
|
||||
(((lhs.asBits ^ rhs.asBits) & 0xFFFF800000000000LL) == 0);
|
||||
}
|
||||
|
||||
static inline JSValueType
|
||||
|
|
|
@ -95,3 +95,11 @@ assertErrorMessage(() => wasmEvalText('(module (func (param f32) (param f32) (re
|
|||
assertErrorMessage(() => wasmEvalText('(module (func (param i32) (param f64) (result f64) (f64.eq (get_local 0) (get_local 1))))'), TypeError, mismatchError("i32", "f64"));
|
||||
assertErrorMessage(() => wasmEvalText('(module (func (param f64) (param i32) (result f64) (f64.eq (get_local 0) (get_local 1))))'), TypeError, mismatchError("i32", "f64"));
|
||||
assertErrorMessage(() => wasmEvalText('(module (func (param f64) (param f64) (result f64) (f64.eq (get_local 0) (get_local 1))))'), TypeError, mismatchError("i32", "f64"));
|
||||
|
||||
// Non-canonical NaNs.
|
||||
assertEq(wasmEvalText('(module (func (result i32) (i32.reinterpret/f32 (f32.mul (f32.const 0.0) (f32.const -nan:0x222222)))) (export "" 0))')(), -0x1dddde);
|
||||
assertEq(wasmEvalText('(module (func (result i32) (i32.reinterpret/f32 (f32.min (f32.const 0.0) (f32.const -nan:0x222222)))) (export "" 0))')(), -0x1dddde);
|
||||
assertEq(wasmEvalText('(module (func (result i32) (i32.reinterpret/f32 (f32.max (f32.const 0.0) (f32.const -nan:0x222222)))) (export "" 0))')(), -0x1dddde);
|
||||
assertEq(wasmEvalText('(module (func (result i32) (local i64) (set_local 0 (i64.reinterpret/f64 (f64.mul (f64.const 0.0) (f64.const -nan:0x4444444444444)))) (i32.xor (i32.wrap/i64 (get_local 0)) (i32.wrap/i64 (i64.shr_u (get_local 0) (i64.const 32))))) (export "" 0))')(), -0x44480000);
|
||||
assertEq(wasmEvalText('(module (func (result i32) (local i64) (set_local 0 (i64.reinterpret/f64 (f64.min (f64.const 0.0) (f64.const -nan:0x4444444444444)))) (i32.xor (i32.wrap/i64 (get_local 0)) (i32.wrap/i64 (i64.shr_u (get_local 0) (i64.const 32))))) (export "" 0))')(), -0x44480000);
|
||||
assertEq(wasmEvalText('(module (func (result i32) (local i64) (set_local 0 (i64.reinterpret/f64 (f64.max (f64.const 0.0) (f64.const -nan:0x4444444444444)))) (i32.xor (i32.wrap/i64 (get_local 0)) (i32.wrap/i64 (i64.shr_u (get_local 0) (i64.const 32))))) (export "" 0))')(), -0x44480000);
|
||||
|
|
|
@ -283,3 +283,7 @@ testConversion('f64', 'convert_u', 'i32', 40, 40);
|
|||
|
||||
testConversion('f32', 'demote', 'f64', 40.1, 40.099998474121094);
|
||||
testConversion('f64', 'promote', 'f32', 40.1, 40.099998474121094);
|
||||
|
||||
// Non-canonical NaNs.
|
||||
assertEq(wasmEvalText('(module (func (result i32) (i32.reinterpret/f32 (f32.demote/f64 (f64.const -nan:0x4444444444444)))) (export "" 0))')(), -0x1dddde);
|
||||
assertEq(wasmEvalText('(module (func (result i32) (local i64) (set_local 0 (i64.reinterpret/f64 (f64.promote/f32 (f32.const -nan:0x222222)))) (i32.xor (i32.wrap/i64 (get_local 0)) (i32.wrap/i64 (i64.shr_u (get_local 0) (i64.const 32))))) (export "" 0))')(), -0x4003bbbc);
|
||||
|
|
|
@ -93,47 +93,47 @@ EvaluateConstantOperands(TempAllocator& alloc, MBinaryInstruction* ins, bool* pt
|
|||
|
||||
MConstant* lhs = left->toConstant();
|
||||
MConstant* rhs = right->toConstant();
|
||||
Value ret = UndefinedValue();
|
||||
double ret = JS::GenericNaN();
|
||||
|
||||
switch (ins->op()) {
|
||||
case MDefinition::Op_BitAnd:
|
||||
ret = Int32Value(lhs->toInt32() & rhs->toInt32());
|
||||
ret = double(lhs->toInt32() & rhs->toInt32());
|
||||
break;
|
||||
case MDefinition::Op_BitOr:
|
||||
ret = Int32Value(lhs->toInt32() | rhs->toInt32());
|
||||
ret = double(lhs->toInt32() | rhs->toInt32());
|
||||
break;
|
||||
case MDefinition::Op_BitXor:
|
||||
ret = Int32Value(lhs->toInt32() ^ rhs->toInt32());
|
||||
ret = double(lhs->toInt32() ^ rhs->toInt32());
|
||||
break;
|
||||
case MDefinition::Op_Lsh:
|
||||
ret = Int32Value(uint32_t(lhs->toInt32()) << (rhs->toInt32() & 0x1F));
|
||||
ret = double(uint32_t(lhs->toInt32()) << (rhs->toInt32() & 0x1F));
|
||||
break;
|
||||
case MDefinition::Op_Rsh:
|
||||
ret = Int32Value(lhs->toInt32() >> (rhs->toInt32() & 0x1F));
|
||||
ret = double(lhs->toInt32() >> (rhs->toInt32() & 0x1F));
|
||||
break;
|
||||
case MDefinition::Op_Ursh:
|
||||
ret.setNumber(uint32_t(lhs->toInt32()) >> (rhs->toInt32() & 0x1F));
|
||||
ret = double(uint32_t(lhs->toInt32()) >> (rhs->toInt32() & 0x1F));
|
||||
break;
|
||||
case MDefinition::Op_Add:
|
||||
ret.setNumber(lhs->numberToDouble() + rhs->numberToDouble());
|
||||
ret = lhs->numberToDouble() + rhs->numberToDouble();
|
||||
break;
|
||||
case MDefinition::Op_Sub:
|
||||
ret.setNumber(lhs->numberToDouble() - rhs->numberToDouble());
|
||||
ret = lhs->numberToDouble() - rhs->numberToDouble();
|
||||
break;
|
||||
case MDefinition::Op_Mul:
|
||||
ret.setNumber(lhs->numberToDouble() * rhs->numberToDouble());
|
||||
ret = lhs->numberToDouble() * rhs->numberToDouble();
|
||||
break;
|
||||
case MDefinition::Op_Div:
|
||||
if (ins->toDiv()->isUnsigned()) {
|
||||
if (rhs->isInt32(0)) {
|
||||
if (ins->toDiv()->trapOnError())
|
||||
return nullptr;
|
||||
ret.setInt32(0);
|
||||
ret = 0.0;
|
||||
} else {
|
||||
ret.setInt32(uint32_t(lhs->toInt32()) / uint32_t(rhs->toInt32()));
|
||||
ret = double(uint32_t(lhs->toInt32()) / uint32_t(rhs->toInt32()));
|
||||
}
|
||||
} else {
|
||||
ret.setNumber(NumberDiv(lhs->numberToDouble(), rhs->numberToDouble()));
|
||||
ret = NumberDiv(lhs->numberToDouble(), rhs->numberToDouble());
|
||||
}
|
||||
break;
|
||||
case MDefinition::Op_Mod:
|
||||
|
@ -141,30 +141,40 @@ EvaluateConstantOperands(TempAllocator& alloc, MBinaryInstruction* ins, bool* pt
|
|||
if (rhs->isInt32(0)) {
|
||||
if (ins->toMod()->trapOnError())
|
||||
return nullptr;
|
||||
ret.setInt32(0);
|
||||
ret = 0.0;
|
||||
} else {
|
||||
ret.setInt32(uint32_t(lhs->toInt32()) % uint32_t(rhs->toInt32()));
|
||||
ret = double(uint32_t(lhs->toInt32()) % uint32_t(rhs->toInt32()));
|
||||
}
|
||||
} else {
|
||||
ret.setNumber(NumberMod(lhs->numberToDouble(), rhs->numberToDouble()));
|
||||
ret = NumberMod(lhs->numberToDouble(), rhs->numberToDouble());
|
||||
}
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("NYI");
|
||||
}
|
||||
|
||||
// setNumber eagerly transforms a number to int32.
|
||||
// Transform back to double, if the output type is double.
|
||||
if (ins->type() == MIRType::Double && ret.isInt32())
|
||||
ret.setDouble(ret.toNumber());
|
||||
// For a float32 or double value, use NewRawDouble so that we preserve NaN
|
||||
// bits. This isn't strictly required for either ES or wasm, but it does
|
||||
// avoid making constant-folding observable.
|
||||
if (ins->type() == MIRType::Double)
|
||||
return MConstant::NewRawDouble(alloc, ret);
|
||||
if (ins->type() == MIRType::Float32)
|
||||
return MConstant::NewRawFloat32(alloc, float(ret));
|
||||
|
||||
if (ins->type() != MIRTypeFromValue(ret)) {
|
||||
Value retVal;
|
||||
retVal.setNumber(JS::CanonicalizeNaN(ret));
|
||||
|
||||
// If this was an int32 operation but the result isn't an int32 (for
|
||||
// example, a division where the numerator isn't evenly divisible by the
|
||||
// denominator), decline folding.
|
||||
MOZ_ASSERT(ins->type() == MIRType::Int32);
|
||||
if (!retVal.isInt32()) {
|
||||
if (ptypeChange)
|
||||
*ptypeChange = true;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return MConstant::New(alloc, ret);
|
||||
return MConstant::New(alloc, retVal);
|
||||
}
|
||||
|
||||
static MMul*
|
||||
|
@ -3150,7 +3160,7 @@ MMinMax::foldsTo(TempAllocator& alloc)
|
|||
return MConstant::NewFloat32(alloc, result);
|
||||
} else {
|
||||
MOZ_ASSERT(type() == MIRType::Double);
|
||||
return MConstant::New(alloc, DoubleValue(result));
|
||||
return MConstant::NewRawDouble(alloc, result);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4134,7 +4144,7 @@ MToDouble::foldsTo(TempAllocator& alloc)
|
|||
|
||||
if (input->isConstant() && input->toConstant()->isTypeRepresentableAsDouble()) {
|
||||
double out = input->toConstant()->numberToDouble();
|
||||
return MConstant::New(alloc, DoubleValue(out));
|
||||
return MConstant::NewRawDouble(alloc, out);
|
||||
}
|
||||
|
||||
return this;
|
||||
|
@ -4159,7 +4169,7 @@ MToFloat32::foldsTo(TempAllocator& alloc)
|
|||
}
|
||||
|
||||
if (input->isConstant() && input->toConstant()->isTypeRepresentableAsDouble())
|
||||
return MConstant::NewFloat32(alloc, float(input->toConstant()->numberToDouble()));
|
||||
return MConstant::NewRawFloat32(alloc, float(input->toConstant()->numberToDouble()));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче