Commit 66e96fc9 authored by bmeurer's avatar bmeurer Committed by Commit bot

[turbofan] Unify number operation typing rules.

Move all the typing rules for unary and binary number operations to the
OperationTyper and use them for both the regular Typer as well as the
retyper that runs as part of SimplifiedLowering.

R=epertoso@chromium.org

Review-Url: https://codereview.chromium.org/2202883005
Cr-Commit-Position: refs/heads/master@{#38283}
parent cc1e84b9
...@@ -200,24 +200,15 @@ ...@@ -200,24 +200,15 @@
V(NumberEqual) \ V(NumberEqual) \
V(NumberLessThan) \ V(NumberLessThan) \
V(NumberLessThanOrEqual) \ V(NumberLessThanOrEqual) \
V(SpeculativeNumberEqual) \
V(SpeculativeNumberLessThan) \
V(SpeculativeNumberLessThanOrEqual) \
V(ReferenceEqual) \ V(ReferenceEqual) \
V(StringEqual) \ V(StringEqual) \
V(StringLessThan) \ V(StringLessThan) \
V(StringLessThanOrEqual) V(StringLessThanOrEqual)
#define SIMPLIFIED_OTHER_OP_LIST(V) \ #define SIMPLIFIED_NUMBER_BINOP_LIST(V) \
V(PlainPrimitiveToNumber) \
V(PlainPrimitiveToWord32) \
V(PlainPrimitiveToFloat64) \
V(BooleanNot) \
V(SpeculativeNumberAdd) \
V(SpeculativeNumberSubtract) \
V(SpeculativeNumberMultiply) \
V(SpeculativeNumberDivide) \
V(SpeculativeNumberModulus) \
V(SpeculativeNumberEqual) \
V(SpeculativeNumberLessThan) \
V(SpeculativeNumberLessThanOrEqual) \
V(NumberAdd) \ V(NumberAdd) \
V(NumberSubtract) \ V(NumberSubtract) \
V(NumberMultiply) \ V(NumberMultiply) \
...@@ -229,37 +220,46 @@ ...@@ -229,37 +220,46 @@
V(NumberShiftLeft) \ V(NumberShiftLeft) \
V(NumberShiftRight) \ V(NumberShiftRight) \
V(NumberShiftRightLogical) \ V(NumberShiftRightLogical) \
V(NumberAtan2) \
V(NumberImul) \
V(NumberMax) \
V(NumberMin) \
V(NumberPow)
#define SIMPLIFIED_SPECULATIVE_NUMBER_BINOP_LIST(V) \
V(SpeculativeNumberAdd) \
V(SpeculativeNumberSubtract) \
V(SpeculativeNumberMultiply) \
V(SpeculativeNumberDivide) \
V(SpeculativeNumberModulus) \
V(SpeculativeNumberBitwiseAnd) \ V(SpeculativeNumberBitwiseAnd) \
V(SpeculativeNumberBitwiseOr) \ V(SpeculativeNumberBitwiseOr) \
V(SpeculativeNumberBitwiseXor) \ V(SpeculativeNumberBitwiseXor) \
V(SpeculativeNumberShiftLeft) \ V(SpeculativeNumberShiftLeft) \
V(SpeculativeNumberShiftRight) \ V(SpeculativeNumberShiftRight) \
V(SpeculativeNumberShiftRightLogical) \ V(SpeculativeNumberShiftRightLogical)
V(NumberImul) \
#define SIMPLIFIED_NUMBER_UNOP_LIST(V) \
V(NumberAbs) \ V(NumberAbs) \
V(NumberClz32) \
V(NumberCeil) \
V(NumberCos) \
V(NumberCosh) \
V(NumberFloor) \
V(NumberFround) \
V(NumberAcos) \ V(NumberAcos) \
V(NumberAcosh) \ V(NumberAcosh) \
V(NumberAsin) \ V(NumberAsin) \
V(NumberAsinh) \ V(NumberAsinh) \
V(NumberAtan) \ V(NumberAtan) \
V(NumberAtanh) \ V(NumberAtanh) \
V(NumberAtan2) \ V(NumberCbrt) \
V(NumberCeil) \
V(NumberClz32) \
V(NumberCos) \
V(NumberCosh) \
V(NumberExp) \ V(NumberExp) \
V(NumberExpm1) \ V(NumberExpm1) \
V(NumberFloor) \
V(NumberFround) \
V(NumberLog) \ V(NumberLog) \
V(NumberLog1p) \ V(NumberLog1p) \
V(NumberLog2) \ V(NumberLog2) \
V(NumberLog10) \ V(NumberLog10) \
V(NumberMax) \
V(NumberMin) \
V(NumberCbrt) \
V(NumberPow) \
V(NumberRound) \ V(NumberRound) \
V(NumberSign) \ V(NumberSign) \
V(NumberSin) \ V(NumberSin) \
...@@ -270,7 +270,13 @@ ...@@ -270,7 +270,13 @@
V(NumberTrunc) \ V(NumberTrunc) \
V(NumberToInt32) \ V(NumberToInt32) \
V(NumberToUint32) \ V(NumberToUint32) \
V(NumberSilenceNaN) \ V(NumberSilenceNaN)
#define SIMPLIFIED_OTHER_OP_LIST(V) \
V(PlainPrimitiveToNumber) \
V(PlainPrimitiveToWord32) \
V(PlainPrimitiveToFloat64) \
V(BooleanNot) \
V(StringCharCodeAt) \ V(StringCharCodeAt) \
V(StringFromCharCode) \ V(StringFromCharCode) \
V(CheckBounds) \ V(CheckBounds) \
...@@ -303,6 +309,9 @@ ...@@ -303,6 +309,9 @@
SIMPLIFIED_CHANGE_OP_LIST(V) \ SIMPLIFIED_CHANGE_OP_LIST(V) \
SIMPLIFIED_CHECKED_OP_LIST(V) \ SIMPLIFIED_CHECKED_OP_LIST(V) \
SIMPLIFIED_COMPARE_BINOP_LIST(V) \ SIMPLIFIED_COMPARE_BINOP_LIST(V) \
SIMPLIFIED_NUMBER_BINOP_LIST(V) \
SIMPLIFIED_SPECULATIVE_NUMBER_BINOP_LIST(V) \
SIMPLIFIED_NUMBER_UNOP_LIST(V) \
SIMPLIFIED_OTHER_OP_LIST(V) SIMPLIFIED_OTHER_OP_LIST(V)
// Opcodes for Machine-level operators. // Opcodes for Machine-level operators.
......
...@@ -18,9 +18,20 @@ namespace compiler { ...@@ -18,9 +18,20 @@ namespace compiler {
OperationTyper::OperationTyper(Isolate* isolate, Zone* zone) OperationTyper::OperationTyper(Isolate* isolate, Zone* zone)
: zone_(zone), cache_(TypeCache::Get()) { : zone_(zone), cache_(TypeCache::Get()) {
Factory* factory = isolate->factory(); Factory* factory = isolate->factory();
Type* infinity = Type::Constant(factory->infinity_value(), zone);
Type* minus_infinity = Type::Constant(factory->minus_infinity_value(), zone);
// Unfortunately, the infinities created in other places might be different
// ones (eg the result of NewNumber in TypeNumberConstant).
Type* truncating_to_zero =
Type::Union(Type::Union(infinity, minus_infinity, zone),
Type::MinusZeroOrNaN(), zone);
DCHECK(!truncating_to_zero->Maybe(Type::Integral32()));
singleton_false_ = Type::Constant(factory->false_value(), zone); singleton_false_ = Type::Constant(factory->false_value(), zone);
singleton_true_ = Type::Constant(factory->true_value(), zone); singleton_true_ = Type::Constant(factory->true_value(), zone);
singleton_the_hole_ = Type::Constant(factory->the_hole_value(), zone); singleton_the_hole_ = Type::Constant(factory->the_hole_value(), zone);
signed32ish_ = Type::Union(Type::Signed32(), truncating_to_zero, zone);
unsigned32ish_ = Type::Union(Type::Unsigned32(), truncating_to_zero, zone);
} }
Type* OperationTyper::Merge(Type* left, Type* right) { Type* OperationTyper::Merge(Type* left, Type* right) {
...@@ -214,12 +225,9 @@ Type* OperationTyper::MultiplyRanger(Type* lhs, Type* rhs) { ...@@ -214,12 +225,9 @@ Type* OperationTyper::MultiplyRanger(Type* lhs, Type* rhs) {
results[1] = lmin * rmax; results[1] = lmin * rmax;
results[2] = lmax * rmin; results[2] = lmax * rmin;
results[3] = lmax * rmax; results[3] = lmax * rmax;
// If the result may be nan, we give up on calculating a precise type, // If the result may be nan, we give up on calculating a precise type, because
// because // the discontinuity makes it too complicated. Note that even if none of the
// the discontinuity makes it too complicated. Note that even if none of // "results" above is nan, the actual result may still be, so we have to do a
// the
// "results" above is nan, the actual result may still be, so we have to do
// a
// different check: // different check:
bool maybe_nan = (lhs->Maybe(cache_.kSingletonZero) && bool maybe_nan = (lhs->Maybe(cache_.kSingletonZero) &&
(rmin == -V8_INFINITY || rmax == +V8_INFINITY)) || (rmin == -V8_INFINITY || rmax == +V8_INFINITY)) ||
...@@ -241,20 +249,244 @@ Type* OperationTyper::ToNumber(Type* type) { ...@@ -241,20 +249,244 @@ Type* OperationTyper::ToNumber(Type* type) {
if (type->Is(Type::Undefined())) return Type::NaN(); if (type->Is(Type::Undefined())) return Type::NaN();
return Type::Union(Type::NaN(), cache_.kSingletonZero, zone()); return Type::Union(Type::NaN(), cache_.kSingletonZero, zone());
} }
if (type->Is(Type::NumberOrUndefined())) { if (type->Is(Type::Boolean())) {
return Type::Union(Type::Intersect(type, Type::Number(), zone()),
Type::NaN(), zone());
}
if (type->Is(singleton_false_)) return cache_.kSingletonZero; if (type->Is(singleton_false_)) return cache_.kSingletonZero;
if (type->Is(singleton_true_)) return cache_.kSingletonOne; if (type->Is(singleton_true_)) return cache_.kSingletonOne;
if (type->Is(Type::Boolean())) return cache_.kZeroOrOne; return cache_.kZeroOrOne;
if (type->Is(Type::BooleanOrNumber())) { }
return Type::Union(Type::Intersect(type, Type::Number(), zone()), if (type->Is(Type::NumberOrOddball())) {
cache_.kZeroOrOne, zone()); if (type->Is(Type::NumberOrUndefined())) {
type = Type::Union(type, Type::NaN(), zone());
} else if (type->Is(Type::NullOrNumber())) {
type = Type::Union(type, cache_.kSingletonZero, zone());
} else if (type->Is(Type::BooleanOrNullOrNumber())) {
type = Type::Union(type, cache_.kZeroOrOne, zone());
} else {
type = Type::Union(type, cache_.kZeroOrOneOrNaN, zone());
}
return Type::Intersect(type, Type::Number(), zone());
}
return Type::Number();
}
Type* OperationTyper::NumberAbs(Type* type) {
DCHECK(type->Is(Type::Number()));
if (!type->IsInhabited()) {
return Type::None();
}
bool const maybe_nan = type->Maybe(Type::NaN());
bool const maybe_minuszero = type->Maybe(Type::MinusZero());
type = Type::Intersect(type, Type::PlainNumber(), zone());
double const max = type->Max();
double const min = type->Min();
if (min < 0) {
if (type->Is(cache_.kInteger)) {
type = Type::Range(0.0, std::max(std::fabs(min), std::fabs(max)), zone());
} else {
type = Type::PlainNumber();
}
}
if (maybe_minuszero) {
type = Type::Union(type, cache_.kSingletonZero, zone());
} }
if (maybe_nan) {
type = Type::Union(type, Type::NaN(), zone());
}
return type;
}
Type* OperationTyper::NumberAcos(Type* type) {
DCHECK(type->Is(Type::Number()));
return Type::Number();
}
Type* OperationTyper::NumberAcosh(Type* type) {
DCHECK(type->Is(Type::Number()));
return Type::Number();
}
Type* OperationTyper::NumberAsin(Type* type) {
DCHECK(type->Is(Type::Number()));
return Type::Number();
}
Type* OperationTyper::NumberAsinh(Type* type) {
DCHECK(type->Is(Type::Number()));
return Type::Number();
}
Type* OperationTyper::NumberAtan(Type* type) {
DCHECK(type->Is(Type::Number()));
return Type::Number();
}
Type* OperationTyper::NumberAtanh(Type* type) {
DCHECK(type->Is(Type::Number()));
return Type::Number();
}
Type* OperationTyper::NumberCbrt(Type* type) {
DCHECK(type->Is(Type::Number()));
return Type::Number();
}
Type* OperationTyper::NumberCeil(Type* type) {
DCHECK(type->Is(Type::Number()));
if (type->Is(cache_.kIntegerOrMinusZeroOrNaN)) return type;
// TODO(bmeurer): We could infer a more precise type here.
return cache_.kIntegerOrMinusZeroOrNaN;
}
Type* OperationTyper::NumberClz32(Type* type) {
DCHECK(type->Is(Type::Number()));
return cache_.kZeroToThirtyTwo;
}
Type* OperationTyper::NumberCos(Type* type) {
DCHECK(type->Is(Type::Number()));
return Type::Number();
}
Type* OperationTyper::NumberCosh(Type* type) {
DCHECK(type->Is(Type::Number()));
return Type::Number();
}
Type* OperationTyper::NumberExp(Type* type) {
DCHECK(type->Is(Type::Number()));
return Type::Union(Type::PlainNumber(), Type::NaN(), zone());
}
Type* OperationTyper::NumberExpm1(Type* type) {
DCHECK(type->Is(Type::Number()));
return Type::Union(Type::PlainNumber(), Type::NaN(), zone());
}
Type* OperationTyper::NumberFloor(Type* type) {
DCHECK(type->Is(Type::Number()));
if (type->Is(cache_.kIntegerOrMinusZeroOrNaN)) return type;
// TODO(bmeurer): We could infer a more precise type here.
return cache_.kIntegerOrMinusZeroOrNaN;
}
Type* OperationTyper::NumberFround(Type* type) {
DCHECK(type->Is(Type::Number()));
return Type::Number();
}
Type* OperationTyper::NumberLog(Type* type) {
DCHECK(type->Is(Type::Number()));
return Type::Number();
}
Type* OperationTyper::NumberLog1p(Type* type) {
DCHECK(type->Is(Type::Number()));
return Type::Number();
}
Type* OperationTyper::NumberLog2(Type* type) {
DCHECK(type->Is(Type::Number()));
return Type::Number();
}
Type* OperationTyper::NumberLog10(Type* type) {
DCHECK(type->Is(Type::Number()));
return Type::Number();
}
Type* OperationTyper::NumberRound(Type* type) {
DCHECK(type->Is(Type::Number()));
if (type->Is(cache_.kIntegerOrMinusZeroOrNaN)) return type;
// TODO(bmeurer): We could infer a more precise type here.
return cache_.kIntegerOrMinusZeroOrNaN;
}
Type* OperationTyper::NumberSign(Type* type) {
DCHECK(type->Is(Type::Number()));
if (type->Is(cache_.kZeroish)) return type;
bool maybe_minuszero = type->Maybe(Type::MinusZero());
bool maybe_nan = type->Maybe(Type::NaN());
type = Type::Intersect(type, Type::PlainNumber(), zone());
if (type->Max() < 0.0) {
type = cache_.kSingletonMinusOne;
} else if (type->Max() <= 0.0) {
type = cache_.kMinusOneOrZero;
} else if (type->Min() > 0.0) {
type = cache_.kSingletonOne;
} else if (type->Min() >= 0.0) {
type = cache_.kZeroOrOne;
} else {
type = Type::Range(-1.0, 1.0, zone());
}
if (maybe_minuszero) type = Type::Union(type, Type::MinusZero(), zone());
if (maybe_nan) type = Type::Union(type, Type::NaN(), zone());
return type;
}
Type* OperationTyper::NumberSin(Type* type) {
DCHECK(type->Is(Type::Number()));
return Type::Number();
}
Type* OperationTyper::NumberSinh(Type* type) {
DCHECK(type->Is(Type::Number()));
return Type::Number();
}
Type* OperationTyper::NumberSqrt(Type* type) {
DCHECK(type->Is(Type::Number()));
return Type::Number();
}
Type* OperationTyper::NumberTan(Type* type) {
DCHECK(type->Is(Type::Number()));
return Type::Number();
}
Type* OperationTyper::NumberTanh(Type* type) {
DCHECK(type->Is(Type::Number()));
return Type::Number(); return Type::Number();
} }
Type* OperationTyper::NumberTrunc(Type* type) {
DCHECK(type->Is(Type::Number()));
if (type->Is(cache_.kIntegerOrMinusZeroOrNaN)) return type;
// TODO(bmeurer): We could infer a more precise type here.
return cache_.kIntegerOrMinusZeroOrNaN;
}
Type* OperationTyper::NumberToInt32(Type* type) {
DCHECK(type->Is(Type::Number()));
if (type->Is(Type::Signed32())) return type;
if (type->Is(cache_.kZeroish)) return cache_.kSingletonZero;
if (type->Is(signed32ish_)) {
return Type::Intersect(Type::Union(type, cache_.kSingletonZero, zone()),
Type::Signed32(), zone());
}
return Type::Signed32();
}
Type* OperationTyper::NumberToUint32(Type* type) {
DCHECK(type->Is(Type::Number()));
if (type->Is(Type::Unsigned32())) return type;
if (type->Is(cache_.kZeroish)) return cache_.kSingletonZero;
if (type->Is(unsigned32ish_)) {
return Type::Intersect(Type::Union(type, cache_.kSingletonZero, zone()),
Type::Unsigned32(), zone());
}
return Type::Unsigned32();
}
Type* OperationTyper::NumberSilenceNaN(Type* type) {
DCHECK(type->Is(Type::Number()));
// TODO(turbofan): We should have a dedicated type for the signaling NaN.
return type;
}
Type* OperationTyper::NumberAdd(Type* lhs, Type* rhs) { Type* OperationTyper::NumberAdd(Type* lhs, Type* rhs) {
DCHECK(lhs->Is(Type::Number())); DCHECK(lhs->Is(Type::Number()));
DCHECK(rhs->Is(Type::Number())); DCHECK(rhs->Is(Type::Number()));
...@@ -406,34 +638,244 @@ Type* OperationTyper::NumberModulus(Type* lhs, Type* rhs) { ...@@ -406,34 +638,244 @@ Type* OperationTyper::NumberModulus(Type* lhs, Type* rhs) {
return type; return type;
} }
Type* OperationTyper::NumberAbs(Type* type) { Type* OperationTyper::NumberBitwiseOr(Type* lhs, Type* rhs) {
DCHECK(type->Is(Type::Number())); DCHECK(lhs->Is(Type::Number()));
DCHECK(rhs->Is(Type::Number()));
if (!type->IsInhabited()) { if (!lhs->IsInhabited() || !rhs->IsInhabited()) return Type::None();
return Type::None();
lhs = NumberToInt32(lhs);
rhs = NumberToInt32(rhs);
double lmin = lhs->Min();
double rmin = rhs->Min();
double lmax = lhs->Max();
double rmax = rhs->Max();
// Or-ing any two values results in a value no smaller than their minimum.
// Even no smaller than their maximum if both values are non-negative.
double min =
lmin >= 0 && rmin >= 0 ? std::max(lmin, rmin) : std::min(lmin, rmin);
double max = kMaxInt;
// Or-ing with 0 is essentially a conversion to int32.
if (rmin == 0 && rmax == 0) {
min = lmin;
max = lmax;
}
if (lmin == 0 && lmax == 0) {
min = rmin;
max = rmax;
} }
bool const maybe_nan = type->Maybe(Type::NaN()); if (lmax < 0 || rmax < 0) {
bool const maybe_minuszero = type->Maybe(Type::MinusZero()); // Or-ing two values of which at least one is negative results in a negative
type = Type::Intersect(type, Type::PlainNumber(), zone()); // value.
double const max = type->Max(); max = std::min(max, -1.0);
double const min = type->Min();
if (min < 0) {
if (type->Is(cache_.kInteger)) {
type = Type::Range(0.0, std::max(std::fabs(min), std::fabs(max)), zone());
} else {
type = Type::PlainNumber();
} }
return Type::Range(min, max, zone());
}
Type* OperationTyper::NumberBitwiseAnd(Type* lhs, Type* rhs) {
DCHECK(lhs->Is(Type::Number()));
DCHECK(rhs->Is(Type::Number()));
if (!lhs->IsInhabited() || !rhs->IsInhabited()) return Type::None();
lhs = NumberToInt32(lhs);
rhs = NumberToInt32(rhs);
double lmin = lhs->Min();
double rmin = rhs->Min();
double lmax = lhs->Max();
double rmax = rhs->Max();
double min = kMinInt;
// And-ing any two values results in a value no larger than their maximum.
// Even no larger than their minimum if both values are non-negative.
double max =
lmin >= 0 && rmin >= 0 ? std::min(lmax, rmax) : std::max(lmax, rmax);
// And-ing with a non-negative value x causes the result to be between
// zero and x.
if (lmin >= 0) {
min = 0;
max = std::min(max, lmax);
}
if (rmin >= 0) {
min = 0;
max = std::min(max, rmax);
} }
if (maybe_minuszero) { return Type::Range(min, max, zone());
type = Type::Union(type, cache_.kSingletonZero, zone()); }
Type* OperationTyper::NumberBitwiseXor(Type* lhs, Type* rhs) {
DCHECK(lhs->Is(Type::Number()));
DCHECK(rhs->Is(Type::Number()));
if (!lhs->IsInhabited() || !rhs->IsInhabited()) return Type::None();
lhs = NumberToInt32(lhs);
rhs = NumberToInt32(rhs);
double lmin = lhs->Min();
double rmin = rhs->Min();
double lmax = lhs->Max();
double rmax = rhs->Max();
if ((lmin >= 0 && rmin >= 0) || (lmax < 0 && rmax < 0)) {
// Xor-ing negative or non-negative values results in a non-negative value.
return Type::Unsigned31();
} }
if (maybe_nan) { if ((lmax < 0 && rmin >= 0) || (lmin >= 0 && rmax < 0)) {
// Xor-ing a negative and a non-negative value results in a negative value.
// TODO(jarin) Use a range here.
return Type::Negative32();
}
return Type::Signed32();
}
Type* OperationTyper::NumberShiftLeft(Type* lhs, Type* rhs) {
DCHECK(lhs->Is(Type::Number()));
DCHECK(rhs->Is(Type::Number()));
// TODO(turbofan): Infer a better type here.
return Type::Signed32();
}
Type* OperationTyper::NumberShiftRight(Type* lhs, Type* rhs) {
DCHECK(lhs->Is(Type::Number()));
DCHECK(rhs->Is(Type::Number()));
if (!lhs->IsInhabited() || !rhs->IsInhabited()) return Type::None();
lhs = NumberToInt32(lhs);
rhs = NumberToUint32(rhs);
double min = kMinInt;
double max = kMaxInt;
if (lhs->Min() >= 0) {
// Right-shifting a non-negative value cannot make it negative, nor larger.
min = std::max(min, 0.0);
max = std::min(max, lhs->Max());
if (rhs->Min() > 0 && rhs->Max() <= 31) {
max = static_cast<int>(max) >> static_cast<int>(rhs->Min());
}
}
if (lhs->Max() < 0) {
// Right-shifting a negative value cannot make it non-negative, nor smaller.
min = std::max(min, lhs->Min());
max = std::min(max, -1.0);
if (rhs->Min() > 0 && rhs->Max() <= 31) {
min = static_cast<int>(min) >> static_cast<int>(rhs->Min());
}
}
if (rhs->Min() > 0 && rhs->Max() <= 31) {
// Right-shifting by a positive value yields a small integer value.
double shift_min = kMinInt >> static_cast<int>(rhs->Min());
double shift_max = kMaxInt >> static_cast<int>(rhs->Min());
min = std::max(min, shift_min);
max = std::min(max, shift_max);
}
// TODO(jarin) Ideally, the following micro-optimization should be performed
// by the type constructor.
if (max == kMaxInt && min == kMinInt) return Type::Signed32();
return Type::Range(min, max, zone());
}
Type* OperationTyper::NumberShiftRightLogical(Type* lhs, Type* rhs) {
DCHECK(lhs->Is(Type::Number()));
DCHECK(rhs->Is(Type::Number()));
if (!lhs->IsInhabited()) return Type::None();
lhs = NumberToUint32(lhs);
// Logical right-shifting any value cannot make it larger.
return Type::Range(0.0, lhs->Max(), zone());
}
Type* OperationTyper::NumberAtan2(Type* lhs, Type* rhs) {
DCHECK(lhs->Is(Type::Number()));
DCHECK(rhs->Is(Type::Number()));
return Type::Number();
}
Type* OperationTyper::NumberImul(Type* lhs, Type* rhs) {
DCHECK(lhs->Is(Type::Number()));
DCHECK(rhs->Is(Type::Number()));
// TODO(turbofan): We should be able to do better here.
return Type::Signed32();
}
Type* OperationTyper::NumberMax(Type* lhs, Type* rhs) {
DCHECK(lhs->Is(Type::Number()));
DCHECK(rhs->Is(Type::Number()));
if (lhs->Is(Type::NaN()) || rhs->Is(Type::NaN())) {
return Type::NaN();
}
Type* type = Type::None();
// TODO(turbofan): Improve minus zero handling here.
if (lhs->Maybe(Type::NaN()) || rhs->Maybe(Type::NaN())) {
type = Type::Union(type, Type::NaN(), zone()); type = Type::Union(type, Type::NaN(), zone());
} }
lhs = Type::Intersect(lhs, Type::OrderedNumber(), zone());
rhs = Type::Intersect(rhs, Type::OrderedNumber(), zone());
if (lhs->Is(cache_.kInteger) && rhs->Is(cache_.kInteger)) {
double max = std::max(lhs->Max(), rhs->Max());
double min = std::max(lhs->Min(), rhs->Min());
type = Type::Union(type, Type::Range(min, max, zone()), zone());
} else {
type = Type::Union(type, Type::Union(lhs, rhs, zone()), zone());
}
return type; return type;
} }
Type* OperationTyper::NumberMin(Type* lhs, Type* rhs) {
DCHECK(lhs->Is(Type::Number()));
DCHECK(rhs->Is(Type::Number()));
if (lhs->Is(Type::NaN()) || rhs->Is(Type::NaN())) {
return Type::NaN();
}
Type* type = Type::None();
// TODO(turbofan): Improve minus zero handling here.
if (lhs->Maybe(Type::NaN()) || rhs->Maybe(Type::NaN())) {
type = Type::Union(type, Type::NaN(), zone());
}
lhs = Type::Intersect(lhs, Type::OrderedNumber(), zone());
rhs = Type::Intersect(rhs, Type::OrderedNumber(), zone());
if (lhs->Is(cache_.kInteger) && rhs->Is(cache_.kInteger)) {
double max = std::min(lhs->Max(), rhs->Max());
double min = std::min(lhs->Min(), rhs->Min());
type = Type::Union(type, Type::Range(min, max, zone()), zone());
} else {
type = Type::Union(type, Type::Union(lhs, rhs, zone()), zone());
}
return type;
}
Type* OperationTyper::NumberPow(Type* lhs, Type* rhs) {
DCHECK(lhs->Is(Type::Number()));
DCHECK(rhs->Is(Type::Number()));
// TODO(turbofan): We should be able to do better here.
return Type::Number();
}
#define SPECULATIVE_NUMBER_BINOP(Name) \
Type* OperationTyper::Speculative##Name(Type* lhs, Type* rhs) { \
lhs = ToNumber(Type::Intersect(lhs, Type::NumberOrOddball(), zone())); \
rhs = ToNumber(Type::Intersect(rhs, Type::NumberOrOddball(), zone())); \
return Name(lhs, rhs); \
}
SPECULATIVE_NUMBER_BINOP(NumberAdd)
SPECULATIVE_NUMBER_BINOP(NumberSubtract)
SPECULATIVE_NUMBER_BINOP(NumberMultiply)
SPECULATIVE_NUMBER_BINOP(NumberDivide)
SPECULATIVE_NUMBER_BINOP(NumberModulus)
SPECULATIVE_NUMBER_BINOP(NumberBitwiseOr)
SPECULATIVE_NUMBER_BINOP(NumberBitwiseAnd)
SPECULATIVE_NUMBER_BINOP(NumberBitwiseXor)
SPECULATIVE_NUMBER_BINOP(NumberShiftLeft)
SPECULATIVE_NUMBER_BINOP(NumberShiftRight)
SPECULATIVE_NUMBER_BINOP(NumberShiftRightLogical)
#undef SPECULATIVE_NUMBER_BINOP
Type* OperationTyper::ToPrimitive(Type* type) { Type* OperationTyper::ToPrimitive(Type* type) {
if (type->Is(Type::Primitive()) && !type->Maybe(Type::Receiver())) { if (type->Is(Type::Primitive()) && !type->Maybe(Type::Receiver())) {
return type; return type;
...@@ -469,30 +911,6 @@ Type* OperationTyper::FalsifyUndefined(ComparisonOutcome outcome) { ...@@ -469,30 +911,6 @@ Type* OperationTyper::FalsifyUndefined(ComparisonOutcome outcome) {
return singleton_true(); return singleton_true();
} }
Type* OperationTyper::TypeJSAdd(Type* lhs, Type* rhs) {
lhs = ToPrimitive(lhs);
rhs = ToPrimitive(rhs);
if (!lhs->IsInhabited() || !rhs->IsInhabited()) {
return Type::None();
}
if (lhs->Maybe(Type::String()) || rhs->Maybe(Type::String())) {
if (lhs->Is(Type::String()) || rhs->Is(Type::String())) {
return Type::String();
} else {
return Type::NumberOrString();
}
}
lhs = ToNumber(lhs);
rhs = ToNumber(rhs);
return NumberAdd(lhs, rhs);
}
Type* OperationTyper::TypeJSSubtract(Type* lhs, Type* rhs) {
return NumberSubtract(ToNumber(lhs), ToNumber(rhs));
}
} // namespace compiler } // namespace compiler
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -32,13 +32,16 @@ class OperationTyper { ...@@ -32,13 +32,16 @@ class OperationTyper {
Type* ToNumber(Type* type); Type* ToNumber(Type* type);
Type* WeakenRange(Type* current_range, Type* previous_range); Type* WeakenRange(Type* current_range, Type* previous_range);
Type* NumberAdd(Type* lhs, Type* rhs); // Number unary operators.
Type* NumberSubtract(Type* lhs, Type* rhs); #define DECLARE_METHOD(Name) Type* Name(Type* type);
Type* NumberMultiply(Type* lhs, Type* rhs); SIMPLIFIED_NUMBER_UNOP_LIST(DECLARE_METHOD)
Type* NumberDivide(Type* lhs, Type* rhs); #undef DECLARE_METHOD
Type* NumberModulus(Type* lhs, Type* rhs);
Type* NumberAbs(Type* type); // Number binary operators.
#define DECLARE_METHOD(Name) Type* Name(Type* lhs, Type* rhs);
SIMPLIFIED_NUMBER_BINOP_LIST(DECLARE_METHOD)
SIMPLIFIED_SPECULATIVE_NUMBER_BINOP_LIST(DECLARE_METHOD)
#undef DECLARE_METHOD
enum ComparisonOutcomeFlags { enum ComparisonOutcomeFlags {
kComparisonTrue = 1, kComparisonTrue = 1,
...@@ -46,14 +49,9 @@ class OperationTyper { ...@@ -46,14 +49,9 @@ class OperationTyper {
kComparisonUndefined = 4 kComparisonUndefined = 4
}; };
// Javascript binop typers. Type* singleton_false() const { return singleton_false_; }
#define DECLARE_CASE(x) Type* Type##x(Type* lhs, Type* rhs); Type* singleton_true() const { return singleton_true_; }
JS_SIMPLE_BINOP_LIST(DECLARE_CASE) Type* singleton_the_hole() const { return singleton_the_hole_; }
#undef DECLARE_CASE
Type* singleton_false() { return singleton_false_; }
Type* singleton_true() { return singleton_true_; }
Type* singleton_the_hole() { return singleton_the_hole_; }
private: private:
typedef base::Flags<ComparisonOutcomeFlags> ComparisonOutcome; typedef base::Flags<ComparisonOutcomeFlags> ComparisonOutcome;
...@@ -68,14 +66,16 @@ class OperationTyper { ...@@ -68,14 +66,16 @@ class OperationTyper {
Type* SubtractRanger(RangeType* lhs, RangeType* rhs); Type* SubtractRanger(RangeType* lhs, RangeType* rhs);
Type* MultiplyRanger(Type* lhs, Type* rhs); Type* MultiplyRanger(Type* lhs, Type* rhs);
Zone* zone() { return zone_; } Zone* zone() const { return zone_; }
Zone* zone_; Zone* const zone_;
TypeCache const& cache_; TypeCache const& cache_;
Type* singleton_false_; Type* singleton_false_;
Type* singleton_true_; Type* singleton_true_;
Type* singleton_the_hole_; Type* singleton_the_hole_;
Type* signed32ish_;
Type* unsigned32ish_;
}; };
} // namespace compiler } // namespace compiler
......
...@@ -358,85 +358,38 @@ class RepresentationSelector { ...@@ -358,85 +358,38 @@ class RepresentationSelector {
} }
switch (node->opcode()) { switch (node->opcode()) {
case IrOpcode::kNumberAdd: #define DECLARE_CASE(Name) \
case IrOpcode::kSpeculativeNumberAdd: { case IrOpcode::k##Name: { \
// TODO(jarin) The ToNumber conversion is too conservative here, new_type = op_typer_.Name(FeedbackTypeOf(node->InputAt(0)), \
// e.g. it will treat true as 1 even though the number check will FeedbackTypeOf(node->InputAt(1))); \
// fail on a boolean. OperationTyper should have a function that break; \
// computes a more precise type. }
Type* lhs = op_typer_.ToNumber(FeedbackTypeOf(node->InputAt(0))); SIMPLIFIED_NUMBER_BINOP_LIST(DECLARE_CASE)
Type* rhs = op_typer_.ToNumber(FeedbackTypeOf(node->InputAt(1))); #undef DECLARE_CASE
Type* computed_type = op_typer_.NumberAdd(lhs, rhs);
new_type = Type::Intersect(computed_type, info->restriction_type(), #define DECLARE_CASE(Name) \
graph_zone()); case IrOpcode::k##Name: { \
break; new_type = \
} Type::Intersect(op_typer_.Name(FeedbackTypeOf(node->InputAt(0)), \
FeedbackTypeOf(node->InputAt(1))), \
case IrOpcode::kNumberSubtract: info->restriction_type(), graph_zone()); \
case IrOpcode::kSpeculativeNumberSubtract: { break; \
// TODO(jarin) The ToNumber conversion is too conservative here, }
// e.g. it will treat true as 1 even though the number check will SIMPLIFIED_SPECULATIVE_NUMBER_BINOP_LIST(DECLARE_CASE)
// fail on a boolean. OperationTyper should have a function that #undef DECLARE_CASE
// computes a more precise type.
Type* lhs = op_typer_.ToNumber(FeedbackTypeOf(node->InputAt(0))); #define DECLARE_CASE(Name) \
Type* rhs = op_typer_.ToNumber(FeedbackTypeOf(node->InputAt(1))); case IrOpcode::k##Name: { \
Type* computed_type = op_typer_.NumberSubtract(lhs, rhs); new_type = op_typer_.Name(FeedbackTypeOf(node->InputAt(0))); \
new_type = Type::Intersect(computed_type, info->restriction_type(), break; \
graph_zone()); }
break; SIMPLIFIED_NUMBER_UNOP_LIST(DECLARE_CASE)
} #undef DECLARE_CASE
case IrOpcode::kNumberMultiply:
case IrOpcode::kSpeculativeNumberMultiply: {
// TODO(jarin) The ToNumber conversion is too conservative here,
// e.g. it will treat true as 1 even though the number check will
// fail on a boolean. OperationTyper should have a function that
// computes a more precise type.
Type* lhs = op_typer_.ToNumber(FeedbackTypeOf(node->InputAt(0)));
Type* rhs = op_typer_.ToNumber(FeedbackTypeOf(node->InputAt(1)));
Type* computed_type = op_typer_.NumberMultiply(lhs, rhs);
new_type = Type::Intersect(computed_type, info->restriction_type(),
graph_zone());
break;
}
case IrOpcode::kNumberDivide:
case IrOpcode::kSpeculativeNumberDivide: {
// TODO(jarin) The ToNumber conversion is too conservative here,
// e.g. it will treat true as 1 even though the number check will
// fail on a boolean. OperationTyper should have a function that
// computes a more precise type.
Type* lhs = op_typer_.ToNumber(FeedbackTypeOf(node->InputAt(0)));
Type* rhs = op_typer_.ToNumber(FeedbackTypeOf(node->InputAt(1)));
Type* computed_type = op_typer_.NumberDivide(lhs, rhs);
new_type = Type::Intersect(computed_type, info->restriction_type(),
graph_zone());
break;
}
case IrOpcode::kNumberModulus:
case IrOpcode::kSpeculativeNumberModulus: {
// TODO(jarin) The ToNumber conversion is too conservative here,
// e.g. it will treat true as 1 even though the number check will
// fail on a boolean. OperationTyper should have a function that
// computes a more precise type.
Type* lhs = op_typer_.ToNumber(FeedbackTypeOf(node->InputAt(0)));
Type* rhs = op_typer_.ToNumber(FeedbackTypeOf(node->InputAt(1)));
Type* computed_type = op_typer_.NumberModulus(lhs, rhs);
new_type = Type::Intersect(computed_type, info->restriction_type(),
graph_zone());
break;
}
case IrOpcode::kPlainPrimitiveToNumber: case IrOpcode::kPlainPrimitiveToNumber:
new_type = op_typer_.ToNumber(FeedbackTypeOf(node->InputAt(0))); new_type = op_typer_.ToNumber(FeedbackTypeOf(node->InputAt(0)));
break; break;
case IrOpcode::kNumberAbs: {
new_type = op_typer_.NumberAbs(FeedbackTypeOf(node->InputAt(0)));
break;
}
case IrOpcode::kPhi: { case IrOpcode::kPhi: {
new_type = TypePhi(node); new_type = TypePhi(node);
if (type != nullptr) { if (type != nullptr) {
......
...@@ -39,20 +39,9 @@ Typer::Typer(Isolate* isolate, Graph* graph) ...@@ -39,20 +39,9 @@ Typer::Typer(Isolate* isolate, Graph* graph)
Zone* zone = this->zone(); Zone* zone = this->zone();
Factory* const factory = isolate->factory(); Factory* const factory = isolate->factory();
Type* infinity = Type::Constant(factory->infinity_value(), zone);
Type* minus_infinity = Type::Constant(factory->minus_infinity_value(), zone);
// Unfortunately, the infinities created in other places might be different
// ones (eg the result of NewNumber in TypeNumberConstant).
Type* truncating_to_zero =
Type::Union(Type::Union(infinity, minus_infinity, zone),
Type::MinusZeroOrNaN(), zone);
DCHECK(!truncating_to_zero->Maybe(Type::Integral32()));
singleton_false_ = Type::Constant(factory->false_value(), zone); singleton_false_ = Type::Constant(factory->false_value(), zone);
singleton_true_ = Type::Constant(factory->true_value(), zone); singleton_true_ = Type::Constant(factory->true_value(), zone);
singleton_the_hole_ = Type::Constant(factory->the_hole_value(), zone); singleton_the_hole_ = Type::Constant(factory->the_hole_value(), zone);
signed32ish_ = Type::Union(Type::Signed32(), truncating_to_zero, zone);
unsigned32ish_ = Type::Union(Type::Unsigned32(), truncating_to_zero, zone);
falsish_ = Type::Union( falsish_ = Type::Union(
Type::Undetectable(), Type::Undetectable(),
Type::Union(Type::Union(singleton_false_, cache_.kZeroish, zone), Type::Union(Type::Union(singleton_false_, cache_.kZeroish, zone),
...@@ -105,6 +94,19 @@ class Typer::Visitor : public Reducer { ...@@ -105,6 +94,19 @@ class Typer::Visitor : public Reducer {
JS_OTHER_OP_LIST(DECLARE_CASE) JS_OTHER_OP_LIST(DECLARE_CASE)
#undef DECLARE_CASE #undef DECLARE_CASE
#define DECLARE_CASE(x) \
case IrOpcode::k##x: \
return UpdateType(node, TypeBinaryOp(node, x));
SIMPLIFIED_NUMBER_BINOP_LIST(DECLARE_CASE)
SIMPLIFIED_SPECULATIVE_NUMBER_BINOP_LIST(DECLARE_CASE)
#undef DECLARE_CASE
#define DECLARE_CASE(x) \
case IrOpcode::k##x: \
return UpdateType(node, TypeUnaryOp(node, x));
SIMPLIFIED_NUMBER_UNOP_LIST(DECLARE_CASE)
#undef DECLARE_CASE
#define DECLARE_CASE(x) case IrOpcode::k##x: #define DECLARE_CASE(x) case IrOpcode::k##x:
DECLARE_CASE(Loop) DECLARE_CASE(Loop)
DECLARE_CASE(Branch) DECLARE_CASE(Branch)
...@@ -155,6 +157,19 @@ class Typer::Visitor : public Reducer { ...@@ -155,6 +157,19 @@ class Typer::Visitor : public Reducer {
JS_OTHER_OP_LIST(DECLARE_CASE) JS_OTHER_OP_LIST(DECLARE_CASE)
#undef DECLARE_CASE #undef DECLARE_CASE
#define DECLARE_CASE(x) \
case IrOpcode::k##x: \
return TypeBinaryOp(node, x);
SIMPLIFIED_NUMBER_BINOP_LIST(DECLARE_CASE)
SIMPLIFIED_SPECULATIVE_NUMBER_BINOP_LIST(DECLARE_CASE)
#undef DECLARE_CASE
#define DECLARE_CASE(x) \
case IrOpcode::k##x: \
return TypeUnaryOp(node, x);
SIMPLIFIED_NUMBER_UNOP_LIST(DECLARE_CASE)
#undef DECLARE_CASE
#define DECLARE_CASE(x) case IrOpcode::k##x: #define DECLARE_CASE(x) case IrOpcode::k##x:
DECLARE_CASE(Loop) DECLARE_CASE(Loop)
DECLARE_CASE(Branch) DECLARE_CASE(Branch)
...@@ -249,15 +264,19 @@ class Typer::Visitor : public Reducer { ...@@ -249,15 +264,19 @@ class Typer::Visitor : public Reducer {
static Type* ToNumber(Type*, Typer*); static Type* ToNumber(Type*, Typer*);
static Type* ToObject(Type*, Typer*); static Type* ToObject(Type*, Typer*);
static Type* ToString(Type*, Typer*); static Type* ToString(Type*, Typer*);
static Type* NumberCeil(Type*, Typer*); #define DECLARE_METHOD(Name) \
static Type* NumberFloor(Type*, Typer*); static Type* Name(Type* type, Typer* t) { \
static Type* NumberMax(Type*, Type*, Typer*); return t->operation_typer_.Name(type); \
static Type* NumberMin(Type*, Type*, Typer*); }
static Type* NumberRound(Type*, Typer*); SIMPLIFIED_NUMBER_UNOP_LIST(DECLARE_METHOD)
static Type* NumberSign(Type*, Typer*); #undef DECLARE_METHOD
static Type* NumberTrunc(Type*, Typer*); #define DECLARE_METHOD(Name) \
static Type* NumberToInt32(Type*, Typer*); static Type* Name(Type* lhs, Type* rhs, Typer* t) { \
static Type* NumberToUint32(Type*, Typer*); return t->operation_typer_.Name(lhs, rhs); \
}
SIMPLIFIED_NUMBER_BINOP_LIST(DECLARE_METHOD)
SIMPLIFIED_SPECULATIVE_NUMBER_BINOP_LIST(DECLARE_METHOD)
#undef DECLARE_METHOD
static Type* ObjectIsCallable(Type*, Typer*); static Type* ObjectIsCallable(Type*, Typer*);
static Type* ObjectIsNumber(Type*, Typer*); static Type* ObjectIsNumber(Type*, Typer*);
...@@ -451,24 +470,7 @@ Type* Typer::Visitor::ToName(Type* type, Typer* t) { ...@@ -451,24 +470,7 @@ Type* Typer::Visitor::ToName(Type* type, Typer* t) {
// static // static
Type* Typer::Visitor::ToNumber(Type* type, Typer* t) { Type* Typer::Visitor::ToNumber(Type* type, Typer* t) {
if (type->Is(Type::Number())) return type; return t->operation_typer_.ToNumber(type);
if (type->Is(Type::NullOrUndefined())) {
if (type->Is(Type::Null())) return t->cache_.kSingletonZero;
if (type->Is(Type::Undefined())) return Type::NaN();
return Type::Union(Type::NaN(), t->cache_.kSingletonZero, t->zone());
}
if (type->Is(Type::NumberOrUndefined())) {
return Type::Union(Type::Intersect(type, Type::Number(), t->zone()),
Type::NaN(), t->zone());
}
if (type->Is(t->singleton_false_)) return t->cache_.kSingletonZero;
if (type->Is(t->singleton_true_)) return t->cache_.kSingletonOne;
if (type->Is(Type::Boolean())) return t->cache_.kZeroOrOne;
if (type->Is(Type::BooleanOrNumber())) {
return Type::Union(Type::Intersect(type, Type::Number(), t->zone()),
t->cache_.kZeroOrOne, t->zone());
}
return Type::Number();
} }
...@@ -492,136 +494,6 @@ Type* Typer::Visitor::ToString(Type* type, Typer* t) { ...@@ -492,136 +494,6 @@ Type* Typer::Visitor::ToString(Type* type, Typer* t) {
return Type::String(); return Type::String();
} }
// static
Type* Typer::Visitor::NumberCeil(Type* type, Typer* t) {
DCHECK(type->Is(Type::Number()));
if (type->Is(t->cache_.kIntegerOrMinusZeroOrNaN)) return type;
// TODO(bmeurer): We could infer a more precise type here.
return t->cache_.kIntegerOrMinusZeroOrNaN;
}
// static
Type* Typer::Visitor::NumberFloor(Type* type, Typer* t) {
DCHECK(type->Is(Type::Number()));
if (type->Is(t->cache_.kIntegerOrMinusZeroOrNaN)) return type;
// TODO(bmeurer): We could infer a more precise type here.
return t->cache_.kIntegerOrMinusZeroOrNaN;
}
// static
Type* Typer::Visitor::NumberMax(Type* lhs, Type* rhs, Typer* t) {
DCHECK(lhs->Is(Type::Number()));
DCHECK(rhs->Is(Type::Number()));
if (lhs->Is(Type::NaN()) || rhs->Is(Type::NaN())) {
return Type::NaN();
}
Type* type = Type::None();
// TODO(turbofan): Improve minus zero handling here.
if (lhs->Maybe(Type::NaN()) || rhs->Maybe(Type::NaN())) {
type = Type::Union(type, Type::NaN(), t->zone());
}
lhs = Type::Intersect(lhs, Type::OrderedNumber(), t->zone());
rhs = Type::Intersect(rhs, Type::OrderedNumber(), t->zone());
if (lhs->Is(t->cache_.kInteger) && rhs->Is(t->cache_.kInteger)) {
double max = std::max(lhs->Max(), rhs->Max());
double min = std::max(lhs->Min(), rhs->Min());
type = Type::Union(type, Type::Range(min, max, t->zone()), t->zone());
} else {
type = Type::Union(type, Type::Union(lhs, rhs, t->zone()), t->zone());
}
return type;
}
// static
Type* Typer::Visitor::NumberMin(Type* lhs, Type* rhs, Typer* t) {
DCHECK(lhs->Is(Type::Number()));
DCHECK(rhs->Is(Type::Number()));
if (lhs->Is(Type::NaN()) || rhs->Is(Type::NaN())) {
return Type::NaN();
}
Type* type = Type::None();
// TODO(turbofan): Improve minus zero handling here.
if (lhs->Maybe(Type::NaN()) || rhs->Maybe(Type::NaN())) {
type = Type::Union(type, Type::NaN(), t->zone());
}
lhs = Type::Intersect(lhs, Type::OrderedNumber(), t->zone());
rhs = Type::Intersect(rhs, Type::OrderedNumber(), t->zone());
if (lhs->Is(t->cache_.kInteger) && rhs->Is(t->cache_.kInteger)) {
double max = std::min(lhs->Max(), rhs->Max());
double min = std::min(lhs->Min(), rhs->Min());
type = Type::Union(type, Type::Range(min, max, t->zone()), t->zone());
} else {
type = Type::Union(type, Type::Union(lhs, rhs, t->zone()), t->zone());
}
return type;
}
// static
Type* Typer::Visitor::NumberRound(Type* type, Typer* t) {
DCHECK(type->Is(Type::Number()));
if (type->Is(t->cache_.kIntegerOrMinusZeroOrNaN)) return type;
// TODO(bmeurer): We could infer a more precise type here.
return t->cache_.kIntegerOrMinusZeroOrNaN;
}
// static
Type* Typer::Visitor::NumberSign(Type* type, Typer* t) {
DCHECK(type->Is(Type::Number()));
if (type->Is(t->cache_.kZeroish)) return type;
bool maybe_minuszero = type->Maybe(Type::MinusZero());
bool maybe_nan = type->Maybe(Type::NaN());
type = Type::Intersect(type, Type::PlainNumber(), t->zone());
if (type->Max() < 0.0) {
type = t->cache_.kSingletonMinusOne;
} else if (type->Max() <= 0.0) {
type = t->cache_.kMinusOneOrZero;
} else if (type->Min() > 0.0) {
type = t->cache_.kSingletonOne;
} else if (type->Min() >= 0.0) {
type = t->cache_.kZeroOrOne;
} else {
type = Type::Range(-1.0, 1.0, t->zone());
}
if (maybe_minuszero) {
type = Type::Union(type, Type::MinusZero(), t->zone());
}
if (maybe_nan) {
type = Type::Union(type, Type::NaN(), t->zone());
}
return type;
}
// static
Type* Typer::Visitor::NumberTrunc(Type* type, Typer* t) {
DCHECK(type->Is(Type::Number()));
if (type->Is(t->cache_.kIntegerOrMinusZeroOrNaN)) return type;
// TODO(bmeurer): We could infer a more precise type here.
return t->cache_.kIntegerOrMinusZeroOrNaN;
}
Type* Typer::Visitor::NumberToInt32(Type* type, Typer* t) {
if (type->Is(Type::Signed32())) return type;
if (type->Is(t->cache_.kZeroish)) return t->cache_.kSingletonZero;
if (type->Is(t->signed32ish_)) {
return Type::Intersect(
Type::Union(type, t->cache_.kSingletonZero, t->zone()),
Type::Signed32(), t->zone());
}
return Type::Signed32();
}
Type* Typer::Visitor::NumberToUint32(Type* type, Typer* t) {
if (type->Is(Type::Unsigned32())) return type;
if (type->Is(t->cache_.kZeroish)) return t->cache_.kSingletonZero;
if (type->Is(t->unsigned32ish_)) {
return Type::Intersect(
Type::Union(type, t->cache_.kSingletonZero, t->zone()),
Type::Unsigned32(), t->zone());
}
return Type::Unsigned32();
}
// Type checks. // Type checks.
Type* Typer::Visitor::ObjectIsCallable(Type* type, Typer* t) { Type* Typer::Visitor::ObjectIsCallable(Type* type, Typer* t) {
...@@ -1024,129 +896,32 @@ Type* Typer::Visitor::JSGreaterThanOrEqualTyper( ...@@ -1024,129 +896,32 @@ Type* Typer::Visitor::JSGreaterThanOrEqualTyper(
Type* Typer::Visitor::JSBitwiseOrTyper(Type* lhs, Type* rhs, Typer* t) { Type* Typer::Visitor::JSBitwiseOrTyper(Type* lhs, Type* rhs, Typer* t) {
lhs = NumberToInt32(ToNumber(lhs, t), t); return NumberBitwiseOr(ToNumber(lhs, t), ToNumber(rhs, t), t);
rhs = NumberToInt32(ToNumber(rhs, t), t);
double lmin = lhs->Min();
double rmin = rhs->Min();
double lmax = lhs->Max();
double rmax = rhs->Max();
// Or-ing any two values results in a value no smaller than their minimum.
// Even no smaller than their maximum if both values are non-negative.
double min =
lmin >= 0 && rmin >= 0 ? std::max(lmin, rmin) : std::min(lmin, rmin);
double max = Type::Signed32()->Max();
// Or-ing with 0 is essentially a conversion to int32.
if (rmin == 0 && rmax == 0) {
min = lmin;
max = lmax;
}
if (lmin == 0 && lmax == 0) {
min = rmin;
max = rmax;
}
if (lmax < 0 || rmax < 0) {
// Or-ing two values of which at least one is negative results in a negative
// value.
max = std::min(max, -1.0);
}
return Type::Range(min, max, t->zone());
} }
Type* Typer::Visitor::JSBitwiseAndTyper(Type* lhs, Type* rhs, Typer* t) { Type* Typer::Visitor::JSBitwiseAndTyper(Type* lhs, Type* rhs, Typer* t) {
lhs = NumberToInt32(ToNumber(lhs, t), t); return NumberBitwiseAnd(ToNumber(lhs, t), ToNumber(rhs, t), t);
rhs = NumberToInt32(ToNumber(rhs, t), t);
double lmin = lhs->Min();
double rmin = rhs->Min();
double lmax = lhs->Max();
double rmax = rhs->Max();
double min = Type::Signed32()->Min();
// And-ing any two values results in a value no larger than their maximum.
// Even no larger than their minimum if both values are non-negative.
double max =
lmin >= 0 && rmin >= 0 ? std::min(lmax, rmax) : std::max(lmax, rmax);
// And-ing with a non-negative value x causes the result to be between
// zero and x.
if (lmin >= 0) {
min = 0;
max = std::min(max, lmax);
}
if (rmin >= 0) {
min = 0;
max = std::min(max, rmax);
}
return Type::Range(min, max, t->zone());
} }
Type* Typer::Visitor::JSBitwiseXorTyper(Type* lhs, Type* rhs, Typer* t) { Type* Typer::Visitor::JSBitwiseXorTyper(Type* lhs, Type* rhs, Typer* t) {
lhs = NumberToInt32(ToNumber(lhs, t), t); return NumberBitwiseXor(ToNumber(lhs, t), ToNumber(rhs, t), t);
rhs = NumberToInt32(ToNumber(rhs, t), t);
double lmin = lhs->Min();
double rmin = rhs->Min();
double lmax = lhs->Max();
double rmax = rhs->Max();
if ((lmin >= 0 && rmin >= 0) || (lmax < 0 && rmax < 0)) {
// Xor-ing negative or non-negative values results in a non-negative value.
return Type::Unsigned31();
}
if ((lmax < 0 && rmin >= 0) || (lmin >= 0 && rmax < 0)) {
// Xor-ing a negative and a non-negative value results in a negative value.
// TODO(jarin) Use a range here.
return Type::Negative32();
}
return Type::Signed32();
} }
Type* Typer::Visitor::JSShiftLeftTyper(Type* lhs, Type* rhs, Typer* t) { Type* Typer::Visitor::JSShiftLeftTyper(Type* lhs, Type* rhs, Typer* t) {
return Type::Signed32(); return NumberShiftLeft(ToNumber(lhs, t), ToNumber(rhs, t), t);
} }
Type* Typer::Visitor::JSShiftRightTyper(Type* lhs, Type* rhs, Typer* t) { Type* Typer::Visitor::JSShiftRightTyper(Type* lhs, Type* rhs, Typer* t) {
lhs = NumberToInt32(ToNumber(lhs, t), t); return NumberShiftRight(ToNumber(lhs, t), ToNumber(rhs, t), t);
rhs = NumberToUint32(ToNumber(rhs, t), t);
double min = kMinInt;
double max = kMaxInt;
if (lhs->Min() >= 0) {
// Right-shifting a non-negative value cannot make it negative, nor larger.
min = std::max(min, 0.0);
max = std::min(max, lhs->Max());
if (rhs->Min() > 0 && rhs->Max() <= 31) {
max = static_cast<int>(max) >> static_cast<int>(rhs->Min());
}
}
if (lhs->Max() < 0) {
// Right-shifting a negative value cannot make it non-negative, nor smaller.
min = std::max(min, lhs->Min());
max = std::min(max, -1.0);
if (rhs->Min() > 0 && rhs->Max() <= 31) {
min = static_cast<int>(min) >> static_cast<int>(rhs->Min());
}
}
if (rhs->Min() > 0 && rhs->Max() <= 31) {
// Right-shifting by a positive value yields a small integer value.
double shift_min = kMinInt >> static_cast<int>(rhs->Min());
double shift_max = kMaxInt >> static_cast<int>(rhs->Min());
min = std::max(min, shift_min);
max = std::min(max, shift_max);
}
// TODO(jarin) Ideally, the following micro-optimization should be performed
// by the type constructor.
if (max != Type::Signed32()->Max() || min != Type::Signed32()->Min()) {
return Type::Range(min, max, t->zone());
}
return Type::Signed32();
} }
Type* Typer::Visitor::JSShiftRightLogicalTyper(Type* lhs, Type* rhs, Typer* t) { Type* Typer::Visitor::JSShiftRightLogicalTyper(Type* lhs, Type* rhs, Typer* t) {
lhs = NumberToUint32(ToNumber(lhs, t), t); return NumberShiftRightLogical(ToNumber(lhs, t), ToNumber(rhs, t), t);
// Logical right-shifting any value cannot make it larger.
return Type::Range(0.0, lhs->Max(), t->zone());
} }
...@@ -1163,26 +938,23 @@ Type* Typer::Visitor::JSAddTyper(Type* lhs, Type* rhs, Typer* t) { ...@@ -1163,26 +938,23 @@ Type* Typer::Visitor::JSAddTyper(Type* lhs, Type* rhs, Typer* t) {
} }
} }
// The addition must be numeric. // The addition must be numeric.
return t->operation_typer()->NumberAdd(ToNumber(lhs, t), ToNumber(rhs, t)); return NumberAdd(ToNumber(lhs, t), ToNumber(rhs, t), t);
} }
Type* Typer::Visitor::JSSubtractTyper(Type* lhs, Type* rhs, Typer* t) { Type* Typer::Visitor::JSSubtractTyper(Type* lhs, Type* rhs, Typer* t) {
return t->operation_typer()->NumberSubtract(ToNumber(lhs, t), return NumberSubtract(ToNumber(lhs, t), ToNumber(rhs, t), t);
ToNumber(rhs, t));
} }
Type* Typer::Visitor::JSMultiplyTyper(Type* lhs, Type* rhs, Typer* t) { Type* Typer::Visitor::JSMultiplyTyper(Type* lhs, Type* rhs, Typer* t) {
return t->operation_typer()->NumberMultiply(ToNumber(lhs, t), return NumberMultiply(ToNumber(lhs, t), ToNumber(rhs, t), t);
ToNumber(rhs, t));
} }
Type* Typer::Visitor::JSDivideTyper(Type* lhs, Type* rhs, Typer* t) { Type* Typer::Visitor::JSDivideTyper(Type* lhs, Type* rhs, Typer* t) {
return t->operation_typer()->NumberDivide(ToNumber(lhs, t), ToNumber(rhs, t)); return NumberDivide(ToNumber(lhs, t), ToNumber(rhs, t), t);
} }
Type* Typer::Visitor::JSModulusTyper(Type* lhs, Type* rhs, Typer* t) { Type* Typer::Visitor::JSModulusTyper(Type* lhs, Type* rhs, Typer* t) {
return t->operation_typer()->NumberModulus(ToNumber(lhs, t), return NumberModulus(ToNumber(lhs, t), ToNumber(rhs, t), t);
ToNumber(rhs, t));
} }
...@@ -1669,89 +1441,6 @@ Type* Typer::Visitor::TypeSpeculativeNumberLessThanOrEqual(Node* node) { ...@@ -1669,89 +1441,6 @@ Type* Typer::Visitor::TypeSpeculativeNumberLessThanOrEqual(Node* node) {
return Type::Boolean(); return Type::Boolean();
} }
Type* Typer::Visitor::TypeNumberAdd(Node* node) { return Type::Number(); }
Type* Typer::Visitor::TypeNumberSubtract(Node* node) { return Type::Number(); }
Type* Typer::Visitor::TypeSpeculativeNumberAdd(Node* node) {
return Type::Number();
}
Type* Typer::Visitor::TypeSpeculativeNumberSubtract(Node* node) {
return Type::Number();
}
Type* Typer::Visitor::TypeSpeculativeNumberMultiply(Node* node) {
return Type::Number();
}
Type* Typer::Visitor::TypeSpeculativeNumberDivide(Node* node) {
return Type::Number();
}
Type* Typer::Visitor::TypeSpeculativeNumberModulus(Node* node) {
return Type::Number();
}
Type* Typer::Visitor::TypeSpeculativeNumberShiftLeft(Node* node) {
return Type::Signed32();
}
Type* Typer::Visitor::TypeSpeculativeNumberShiftRight(Node* node) {
return Type::Signed32();
}
Type* Typer::Visitor::TypeSpeculativeNumberShiftRightLogical(Node* node) {
return Type::Unsigned32();
}
Type* Typer::Visitor::TypeSpeculativeNumberBitwiseOr(Node* node) {
return Type::Signed32();
}
Type* Typer::Visitor::TypeSpeculativeNumberBitwiseXor(Node* node) {
return Type::Signed32();
}
Type* Typer::Visitor::TypeSpeculativeNumberBitwiseAnd(Node* node) {
return Type::Signed32();
}
Type* Typer::Visitor::TypeNumberMultiply(Node* node) { return Type::Number(); }
Type* Typer::Visitor::TypeNumberDivide(Node* node) { return Type::Number(); }
Type* Typer::Visitor::TypeNumberModulus(Node* node) { return Type::Number(); }
Type* Typer::Visitor::TypeNumberBitwiseOr(Node* node) {
return Type::Signed32();
}
Type* Typer::Visitor::TypeNumberBitwiseXor(Node* node) {
return Type::Signed32();
}
Type* Typer::Visitor::TypeNumberBitwiseAnd(Node* node) {
return Type::Signed32();
}
Type* Typer::Visitor::TypeNumberShiftLeft(Node* node) {
return Type::Signed32();
}
Type* Typer::Visitor::TypeNumberShiftRight(Node* node) {
return Type::Signed32();
}
Type* Typer::Visitor::TypeNumberShiftRightLogical(Node* node) {
return Type::Unsigned32();
}
Type* Typer::Visitor::TypePlainPrimitiveToNumber(Node* node) { Type* Typer::Visitor::TypePlainPrimitiveToNumber(Node* node) {
return TypeUnaryOp(node, ToNumber); return TypeUnaryOp(node, ToNumber);
} }
...@@ -1764,103 +1453,6 @@ Type* Typer::Visitor::TypePlainPrimitiveToFloat64(Node* node) { ...@@ -1764,103 +1453,6 @@ Type* Typer::Visitor::TypePlainPrimitiveToFloat64(Node* node) {
return Type::Number(); return Type::Number();
} }
Type* Typer::Visitor::TypeNumberImul(Node* node) { return Type::Signed32(); }
Type* Typer::Visitor::TypeNumberAbs(Node* node) {
return typer_->operation_typer()->NumberAbs(Operand(node, 0));
}
Type* Typer::Visitor::TypeNumberClz32(Node* node) {
return typer_->cache_.kZeroToThirtyTwo;
}
Type* Typer::Visitor::TypeNumberCeil(Node* node) {
return TypeUnaryOp(node, NumberCeil);
}
Type* Typer::Visitor::TypeNumberFloor(Node* node) {
return TypeUnaryOp(node, NumberFloor);
}
Type* Typer::Visitor::TypeNumberFround(Node* node) { return Type::Number(); }
Type* Typer::Visitor::TypeNumberSign(Node* node) {
return TypeUnaryOp(node, NumberSign);
}
Type* Typer::Visitor::TypeNumberAcos(Node* node) { return Type::Number(); }
Type* Typer::Visitor::TypeNumberAcosh(Node* node) { return Type::Number(); }
Type* Typer::Visitor::TypeNumberAsin(Node* node) { return Type::Number(); }
Type* Typer::Visitor::TypeNumberAsinh(Node* node) { return Type::Number(); }
Type* Typer::Visitor::TypeNumberAtan(Node* node) { return Type::Number(); }
Type* Typer::Visitor::TypeNumberAtanh(Node* node) { return Type::Number(); }
Type* Typer::Visitor::TypeNumberAtan2(Node* node) { return Type::Number(); }
Type* Typer::Visitor::TypeNumberCos(Node* node) { return Type::Number(); }
Type* Typer::Visitor::TypeNumberCosh(Node* node) { return Type::Number(); }
Type* Typer::Visitor::TypeNumberExp(Node* node) {
return Type::Union(Type::PlainNumber(), Type::NaN(), zone());
}
// TODO(mvstanton): Is this type sufficient, or should it look like Exp()?
Type* Typer::Visitor::TypeNumberExpm1(Node* node) { return Type::Number(); }
Type* Typer::Visitor::TypeNumberLog(Node* node) { return Type::Number(); }
Type* Typer::Visitor::TypeNumberLog1p(Node* node) { return Type::Number(); }
Type* Typer::Visitor::TypeNumberLog2(Node* node) { return Type::Number(); }
Type* Typer::Visitor::TypeNumberLog10(Node* node) { return Type::Number(); }
Type* Typer::Visitor::TypeNumberCbrt(Node* node) { return Type::Number(); }
Type* Typer::Visitor::TypeNumberMax(Node* node) {
return TypeBinaryOp(node, NumberMax);
}
Type* Typer::Visitor::TypeNumberMin(Node* node) {
return TypeBinaryOp(node, NumberMin);
}
Type* Typer::Visitor::TypeNumberPow(Node* node) { return Type::Number(); }
Type* Typer::Visitor::TypeNumberRound(Node* node) {
return TypeUnaryOp(node, NumberRound);
}
Type* Typer::Visitor::TypeNumberSin(Node* node) { return Type::Number(); }
Type* Typer::Visitor::TypeNumberSinh(Node* node) { return Type::Number(); }
Type* Typer::Visitor::TypeNumberSqrt(Node* node) { return Type::Number(); }
Type* Typer::Visitor::TypeNumberTan(Node* node) { return Type::Number(); }
Type* Typer::Visitor::TypeNumberTanh(Node* node) { return Type::Number(); }
Type* Typer::Visitor::TypeNumberTrunc(Node* node) {
return TypeUnaryOp(node, NumberTrunc);
}
Type* Typer::Visitor::TypeNumberToInt32(Node* node) {
return TypeUnaryOp(node, NumberToInt32);
}
Type* Typer::Visitor::TypeNumberToUint32(Node* node) {
return TypeUnaryOp(node, NumberToUint32);
}
// static // static
Type* Typer::Visitor::ReferenceEqualTyper(Type* lhs, Type* rhs, Typer* t) { Type* Typer::Visitor::ReferenceEqualTyper(Type* lhs, Type* rhs, Typer* t) {
if (lhs->IsConstant() && rhs->Is(lhs)) { if (lhs->IsConstant() && rhs->Is(lhs)) {
...@@ -2271,10 +1863,6 @@ Type* Typer::Visitor::TypeChangeFloat64ToInt32(Node* node) { ...@@ -2271,10 +1863,6 @@ Type* Typer::Visitor::TypeChangeFloat64ToInt32(Node* node) {
return Type::Intersect(Type::Signed32(), Type::UntaggedIntegral32(), zone()); return Type::Intersect(Type::Signed32(), Type::UntaggedIntegral32(), zone());
} }
Type* Typer::Visitor::TypeNumberSilenceNaN(Node* node) {
return Type::Number();
}
Type* Typer::Visitor::TypeChangeFloat64ToUint32(Node* node) { Type* Typer::Visitor::TypeChangeFloat64ToUint32(Node* node) {
return Type::Intersect(Type::Unsigned32(), Type::UntaggedIntegral32(), return Type::Intersect(Type::Unsigned32(), Type::UntaggedIntegral32(),
zone()); zone());
......
...@@ -48,8 +48,6 @@ class Typer { ...@@ -48,8 +48,6 @@ class Typer {
Type* singleton_false_; Type* singleton_false_;
Type* singleton_true_; Type* singleton_true_;
Type* singleton_the_hole_; Type* singleton_the_hole_;
Type* signed32ish_;
Type* unsigned32ish_;
Type* falsish_; Type* falsish_;
Type* truish_; Type* truish_;
......
...@@ -50,6 +50,7 @@ class TypeCache final { ...@@ -50,6 +50,7 @@ class TypeCache final {
Type::Union(kSingletonTen, Type::Undefined(), zone()); Type::Union(kSingletonTen, Type::Undefined(), zone());
Type* const kMinusOneOrZero = CreateRange(-1.0, 0.0); Type* const kMinusOneOrZero = CreateRange(-1.0, 0.0);
Type* const kZeroOrOne = CreateRange(0.0, 1.0); Type* const kZeroOrOne = CreateRange(0.0, 1.0);
Type* const kZeroOrOneOrNaN = Type::Union(kZeroOrOne, Type::NaN(), zone());
Type* const kZeroToThirtyOne = CreateRange(0.0, 31.0); Type* const kZeroToThirtyOne = CreateRange(0.0, 31.0);
Type* const kZeroToThirtyTwo = CreateRange(0.0, 32.0); Type* const kZeroToThirtyTwo = CreateRange(0.0, 32.0);
Type* const kZeroish = Type* const kZeroish =
......
...@@ -220,7 +220,9 @@ namespace internal { ...@@ -220,7 +220,9 @@ namespace internal {
V(UniqueName, kSymbol | kInternalizedString) \ V(UniqueName, kSymbol | kInternalizedString) \
V(Name, kSymbol | kString) \ V(Name, kSymbol | kString) \
V(BooleanOrNumber, kBoolean | kNumber) \ V(BooleanOrNumber, kBoolean | kNumber) \
V(BooleanOrNullOrNumber, kBooleanOrNumber | kNull) \
V(BooleanOrNullOrUndefined, kBoolean | kNull | kUndefined) \ V(BooleanOrNullOrUndefined, kBoolean | kNull | kUndefined) \
V(NullOrNumber, kNull | kNumber) \
V(NullOrUndefined, kNull | kUndefined) \ V(NullOrUndefined, kNull | kUndefined) \
V(Undetectable, kNullOrUndefined | kOtherUndetectable) \ V(Undetectable, kNullOrUndefined | kOtherUndetectable) \
V(NumberOrOddball, kNumber | kNullOrUndefined | kBoolean) \ V(NumberOrOddball, kNumber | kNullOrUndefined | kBoolean) \
......
...@@ -1547,84 +1547,6 @@ TEST(UpdatePhi) { ...@@ -1547,84 +1547,6 @@ TEST(UpdatePhi) {
} }
TEST(RunNumberDivide_minus_1_TruncatingToInt32) {
SimplifiedLoweringTester<Object*> t(MachineType::AnyTagged());
Node* num = t.NumberToInt32(t.Parameter(0));
Node* div = t.NumberDivide(num, t.jsgraph.Constant(-1));
Node* trunc = t.NumberToInt32(div);
t.Return(trunc);
t.LowerAllNodesAndLowerChanges();
t.GenerateCode();
FOR_INT32_INPUTS(i) {
int32_t x = 0 - *i;
t.CheckNumberCall(static_cast<double>(x), static_cast<double>(*i));
}
}
TEST(RunNumberMultiply_TruncatingToInt32) {
int32_t constants[] = {-100, -10, -1, 0, 1, 100, 1000, 3000999};
for (size_t i = 0; i < arraysize(constants); i++) {
double k = static_cast<double>(constants[i]);
SimplifiedLoweringTester<Object*> t(MachineType::AnyTagged());
Node* num = t.NumberToInt32(t.Parameter(0));
Node* mul = t.NumberMultiply(num, t.jsgraph.Constant(k));
Node* trunc = t.NumberToInt32(mul);
t.Return(trunc);
t.LowerAllNodesAndLowerChanges();
t.GenerateCode();
FOR_INT32_INPUTS(i) {
int32_t x = DoubleToInt32(static_cast<double>(*i) * k);
t.CheckNumberCall(static_cast<double>(x), static_cast<double>(*i));
}
}
}
TEST(RunNumberMultiply_TruncatingToUint32) {
uint32_t constants[] = {0, 1, 2, 3, 4, 100, 1000, 1024, 2048, 3000999};
for (size_t i = 0; i < arraysize(constants); i++) {
double k = static_cast<double>(constants[i]);
SimplifiedLoweringTester<Object*> t(MachineType::AnyTagged());
Node* num = t.NumberToUint32(t.Parameter(0));
Node* mul = t.NumberMultiply(num, t.jsgraph.Constant(k));
Node* trunc = t.NumberToUint32(mul);
t.Return(trunc);
t.LowerAllNodesAndLowerChanges();
t.GenerateCode();
FOR_UINT32_INPUTS(i) {
uint32_t x = DoubleToUint32(static_cast<double>(*i) * k);
t.CheckNumberCall(static_cast<double>(x), static_cast<double>(*i));
}
}
}
TEST(RunNumberDivide_2_TruncatingToUint32) {
SimplifiedLoweringTester<Object*> t(MachineType::AnyTagged());
Node* num = t.NumberToUint32(t.Parameter(0));
Node* div = t.NumberDivide(num, t.jsgraph.Constant(2));
Node* trunc = t.NumberToUint32(div);
t.Return(trunc);
t.LowerAllNodesAndLowerChanges();
t.GenerateCode();
FOR_UINT32_INPUTS(i) {
uint32_t x = DoubleToUint32(static_cast<double>(*i / 2.0));
t.CheckNumberCall(static_cast<double>(x), static_cast<double>(*i));
}
}
TEST(NumberMultiply_ConstantOutOfRange) { TEST(NumberMultiply_ConstantOutOfRange) {
TestingGraph t(Type::Signed32()); TestingGraph t(Type::Signed32());
Node* k = t.jsgraph.Constant(1000000023); Node* k = t.jsgraph.Constant(1000000023);
...@@ -1664,29 +1586,6 @@ TEST(NumberDivide_TruncatingToInt32) { ...@@ -1664,29 +1586,6 @@ TEST(NumberDivide_TruncatingToInt32) {
} }
TEST(RunNumberDivide_TruncatingToInt32) {
int32_t constants[] = {-100, -10, -1, 1, 2, 100, 1000, 1024, 2048};
for (size_t i = 0; i < arraysize(constants); i++) {
int32_t k = constants[i];
SimplifiedLoweringTester<Object*> t(MachineType::AnyTagged());
Node* num = t.NumberToInt32(t.Parameter(0));
Node* div = t.NumberDivide(num, t.jsgraph.Constant(k));
Node* trunc = t.NumberToInt32(div);
t.Return(trunc);
t.LowerAllNodesAndLowerChanges();
t.GenerateCode();
FOR_INT32_INPUTS(i) {
if (*i == INT_MAX) continue; // exclude max int.
int32_t x = DoubleToInt32(static_cast<double>(*i) / k);
t.CheckNumberCall(static_cast<double>(x), static_cast<double>(*i));
}
}
}
TEST(NumberDivide_TruncatingToUint32) { TEST(NumberDivide_TruncatingToUint32) {
double constants[] = {1, 3, 100, 1000, 100998348}; double constants[] = {1, 3, 100, 1000, 100998348};
...@@ -1703,28 +1602,6 @@ TEST(NumberDivide_TruncatingToUint32) { ...@@ -1703,28 +1602,6 @@ TEST(NumberDivide_TruncatingToUint32) {
} }
TEST(RunNumberDivide_TruncatingToUint32) {
uint32_t constants[] = {100, 10, 1, 1, 2, 4, 1000, 1024, 2048};
for (size_t i = 0; i < arraysize(constants); i++) {
uint32_t k = constants[i];
SimplifiedLoweringTester<Object*> t(MachineType::AnyTagged());
Node* num = t.NumberToUint32(t.Parameter(0));
Node* div = t.NumberDivide(num, t.jsgraph.Constant(static_cast<double>(k)));
Node* trunc = t.NumberToUint32(div);
t.Return(trunc);
t.LowerAllNodesAndLowerChanges();
t.GenerateCode();
FOR_UINT32_INPUTS(i) {
uint32_t x = *i / k;
t.CheckNumberCall(static_cast<double>(x), static_cast<double>(*i));
}
}
}
TEST(NumberDivide_BadConstants) { TEST(NumberDivide_BadConstants) {
{ {
TestingGraph t(Type::Signed32()); TestingGraph t(Type::Signed32());
...@@ -1779,29 +1656,6 @@ TEST(NumberModulus_TruncatingToInt32) { ...@@ -1779,29 +1656,6 @@ TEST(NumberModulus_TruncatingToInt32) {
} }
TEST(RunNumberModulus_TruncatingToInt32) {
int32_t constants[] = {-100, -10, -1, 1, 2, 100, 1000, 1024, 2048};
for (size_t i = 0; i < arraysize(constants); i++) {
int32_t k = constants[i];
SimplifiedLoweringTester<Object*> t(MachineType::AnyTagged());
Node* num = t.NumberToInt32(t.Parameter(0));
Node* mod = t.NumberModulus(num, t.jsgraph.Constant(k));
Node* trunc = t.NumberToInt32(mod);
t.Return(trunc);
t.LowerAllNodesAndLowerChanges();
t.GenerateCode();
FOR_INT32_INPUTS(i) {
if (*i == INT_MAX) continue; // exclude max int.
int32_t x = DoubleToInt32(std::fmod(static_cast<double>(*i), k));
t.CheckNumberCall(static_cast<double>(x), static_cast<double>(*i));
}
}
}
TEST(NumberModulus_TruncatingToUint32) { TEST(NumberModulus_TruncatingToUint32) {
double constants[] = {1, 3, 100, 1000, 100998348}; double constants[] = {1, 3, 100, 1000, 100998348};
...@@ -1818,29 +1672,6 @@ TEST(NumberModulus_TruncatingToUint32) { ...@@ -1818,29 +1672,6 @@ TEST(NumberModulus_TruncatingToUint32) {
} }
TEST(RunNumberModulus_TruncatingToUint32) {
uint32_t constants[] = {1, 2, 100, 1000, 1024, 2048};
for (size_t i = 0; i < arraysize(constants); i++) {
uint32_t k = constants[i];
SimplifiedLoweringTester<Object*> t(MachineType::AnyTagged());
Node* num = t.NumberToUint32(t.Parameter(0));
Node* mod =
t.NumberModulus(num, t.jsgraph.Constant(static_cast<double>(k)));
Node* trunc = t.NumberToUint32(mod);
t.Return(trunc);
t.LowerAllNodesAndLowerChanges();
t.GenerateCode();
FOR_UINT32_INPUTS(i) {
uint32_t x = *i % k;
t.CheckNumberCall(static_cast<double>(x), static_cast<double>(*i));
}
}
}
TEST(NumberModulus_Int32) { TEST(NumberModulus_Int32) {
int32_t constants[] = {-100, -10, 1, 4, 100, 1000}; int32_t constants[] = {-100, -10, 1, 4, 100, 1000};
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment