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 @@
V(NumberEqual) \
V(NumberLessThan) \
V(NumberLessThanOrEqual) \
V(SpeculativeNumberEqual) \
V(SpeculativeNumberLessThan) \
V(SpeculativeNumberLessThanOrEqual) \
V(ReferenceEqual) \
V(StringEqual) \
V(StringLessThan) \
V(StringLessThanOrEqual)
#define SIMPLIFIED_OTHER_OP_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) \
#define SIMPLIFIED_NUMBER_BINOP_LIST(V) \
V(NumberAdd) \
V(NumberSubtract) \
V(NumberMultiply) \
......@@ -229,80 +220,98 @@
V(NumberShiftLeft) \
V(NumberShiftRight) \
V(NumberShiftRightLogical) \
V(SpeculativeNumberBitwiseAnd) \
V(SpeculativeNumberBitwiseOr) \
V(SpeculativeNumberBitwiseXor) \
V(SpeculativeNumberShiftLeft) \
V(SpeculativeNumberShiftRight) \
V(SpeculativeNumberShiftRightLogical) \
V(NumberImul) \
V(NumberAbs) \
V(NumberClz32) \
V(NumberCeil) \
V(NumberCos) \
V(NumberCosh) \
V(NumberFloor) \
V(NumberFround) \
V(NumberAcos) \
V(NumberAcosh) \
V(NumberAsin) \
V(NumberAsinh) \
V(NumberAtan) \
V(NumberAtanh) \
V(NumberAtan2) \
V(NumberExp) \
V(NumberExpm1) \
V(NumberLog) \
V(NumberLog1p) \
V(NumberLog2) \
V(NumberLog10) \
V(NumberImul) \
V(NumberMax) \
V(NumberMin) \
V(NumberCbrt) \
V(NumberPow) \
V(NumberRound) \
V(NumberSign) \
V(NumberSin) \
V(NumberSinh) \
V(NumberSqrt) \
V(NumberTan) \
V(NumberTanh) \
V(NumberTrunc) \
V(NumberToInt32) \
V(NumberToUint32) \
V(NumberSilenceNaN) \
V(StringCharCodeAt) \
V(StringFromCharCode) \
V(CheckBounds) \
V(CheckIf) \
V(CheckMaps) \
V(CheckNumber) \
V(CheckString) \
V(CheckTaggedPointer) \
V(CheckTaggedSigned) \
V(CheckFloat64Hole) \
V(CheckTaggedHole) \
V(Allocate) \
V(LoadField) \
V(LoadBuffer) \
V(LoadElement) \
V(LoadTypedElement) \
V(StoreField) \
V(StoreBuffer) \
V(StoreElement) \
V(StoreTypedElement) \
V(ObjectIsCallable) \
V(ObjectIsNumber) \
V(ObjectIsReceiver) \
V(ObjectIsSmi) \
V(ObjectIsString) \
V(ObjectIsUndetectable) \
V(NumberPow)
#define SIMPLIFIED_SPECULATIVE_NUMBER_BINOP_LIST(V) \
V(SpeculativeNumberAdd) \
V(SpeculativeNumberSubtract) \
V(SpeculativeNumberMultiply) \
V(SpeculativeNumberDivide) \
V(SpeculativeNumberModulus) \
V(SpeculativeNumberBitwiseAnd) \
V(SpeculativeNumberBitwiseOr) \
V(SpeculativeNumberBitwiseXor) \
V(SpeculativeNumberShiftLeft) \
V(SpeculativeNumberShiftRight) \
V(SpeculativeNumberShiftRightLogical)
#define SIMPLIFIED_NUMBER_UNOP_LIST(V) \
V(NumberAbs) \
V(NumberAcos) \
V(NumberAcosh) \
V(NumberAsin) \
V(NumberAsinh) \
V(NumberAtan) \
V(NumberAtanh) \
V(NumberCbrt) \
V(NumberCeil) \
V(NumberClz32) \
V(NumberCos) \
V(NumberCosh) \
V(NumberExp) \
V(NumberExpm1) \
V(NumberFloor) \
V(NumberFround) \
V(NumberLog) \
V(NumberLog1p) \
V(NumberLog2) \
V(NumberLog10) \
V(NumberRound) \
V(NumberSign) \
V(NumberSin) \
V(NumberSinh) \
V(NumberSqrt) \
V(NumberTan) \
V(NumberTanh) \
V(NumberTrunc) \
V(NumberToInt32) \
V(NumberToUint32) \
V(NumberSilenceNaN)
#define SIMPLIFIED_OTHER_OP_LIST(V) \
V(PlainPrimitiveToNumber) \
V(PlainPrimitiveToWord32) \
V(PlainPrimitiveToFloat64) \
V(BooleanNot) \
V(StringCharCodeAt) \
V(StringFromCharCode) \
V(CheckBounds) \
V(CheckIf) \
V(CheckMaps) \
V(CheckNumber) \
V(CheckString) \
V(CheckTaggedPointer) \
V(CheckTaggedSigned) \
V(CheckFloat64Hole) \
V(CheckTaggedHole) \
V(Allocate) \
V(LoadField) \
V(LoadBuffer) \
V(LoadElement) \
V(LoadTypedElement) \
V(StoreField) \
V(StoreBuffer) \
V(StoreElement) \
V(StoreTypedElement) \
V(ObjectIsCallable) \
V(ObjectIsNumber) \
V(ObjectIsReceiver) \
V(ObjectIsSmi) \
V(ObjectIsString) \
V(ObjectIsUndetectable) \
V(TransitionElementsKind)
#define SIMPLIFIED_OP_LIST(V) \
SIMPLIFIED_CHANGE_OP_LIST(V) \
SIMPLIFIED_CHECKED_OP_LIST(V) \
SIMPLIFIED_COMPARE_BINOP_LIST(V) \
#define SIMPLIFIED_OP_LIST(V) \
SIMPLIFIED_CHANGE_OP_LIST(V) \
SIMPLIFIED_CHECKED_OP_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)
// Opcodes for Machine-level operators.
......
This diff is collapsed.
......@@ -32,13 +32,16 @@ class OperationTyper {
Type* ToNumber(Type* type);
Type* WeakenRange(Type* current_range, Type* previous_range);
Type* NumberAdd(Type* lhs, Type* rhs);
Type* NumberSubtract(Type* lhs, Type* rhs);
Type* NumberMultiply(Type* lhs, Type* rhs);
Type* NumberDivide(Type* lhs, Type* rhs);
Type* NumberModulus(Type* lhs, Type* rhs);
// Number unary operators.
#define DECLARE_METHOD(Name) Type* Name(Type* type);
SIMPLIFIED_NUMBER_UNOP_LIST(DECLARE_METHOD)
#undef DECLARE_METHOD
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 {
kComparisonTrue = 1,
......@@ -46,14 +49,9 @@ class OperationTyper {
kComparisonUndefined = 4
};
// Javascript binop typers.
#define DECLARE_CASE(x) Type* Type##x(Type* lhs, Type* rhs);
JS_SIMPLE_BINOP_LIST(DECLARE_CASE)
#undef DECLARE_CASE
Type* singleton_false() { return singleton_false_; }
Type* singleton_true() { return singleton_true_; }
Type* singleton_the_hole() { return singleton_the_hole_; }
Type* singleton_false() const { return singleton_false_; }
Type* singleton_true() const { return singleton_true_; }
Type* singleton_the_hole() const { return singleton_the_hole_; }
private:
typedef base::Flags<ComparisonOutcomeFlags> ComparisonOutcome;
......@@ -68,14 +66,16 @@ class OperationTyper {
Type* SubtractRanger(RangeType* lhs, RangeType* rhs);
Type* MultiplyRanger(Type* lhs, Type* rhs);
Zone* zone() { return zone_; }
Zone* zone() const { return zone_; }
Zone* zone_;
Zone* const zone_;
TypeCache const& cache_;
Type* singleton_false_;
Type* singleton_true_;
Type* singleton_the_hole_;
Type* signed32ish_;
Type* unsigned32ish_;
};
} // namespace compiler
......
......@@ -358,85 +358,38 @@ class RepresentationSelector {
}
switch (node->opcode()) {
case IrOpcode::kNumberAdd:
case IrOpcode::kSpeculativeNumberAdd: {
// 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_.NumberAdd(lhs, rhs);
new_type = Type::Intersect(computed_type, info->restriction_type(),
graph_zone());
break;
}
case IrOpcode::kNumberSubtract:
case IrOpcode::kSpeculativeNumberSubtract: {
// 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_.NumberSubtract(lhs, rhs);
new_type = Type::Intersect(computed_type, info->restriction_type(),
graph_zone());
break;
}
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;
}
#define DECLARE_CASE(Name) \
case IrOpcode::k##Name: { \
new_type = op_typer_.Name(FeedbackTypeOf(node->InputAt(0)), \
FeedbackTypeOf(node->InputAt(1))); \
break; \
}
SIMPLIFIED_NUMBER_BINOP_LIST(DECLARE_CASE)
#undef DECLARE_CASE
#define DECLARE_CASE(Name) \
case IrOpcode::k##Name: { \
new_type = \
Type::Intersect(op_typer_.Name(FeedbackTypeOf(node->InputAt(0)), \
FeedbackTypeOf(node->InputAt(1))), \
info->restriction_type(), graph_zone()); \
break; \
}
SIMPLIFIED_SPECULATIVE_NUMBER_BINOP_LIST(DECLARE_CASE)
#undef DECLARE_CASE
#define DECLARE_CASE(Name) \
case IrOpcode::k##Name: { \
new_type = op_typer_.Name(FeedbackTypeOf(node->InputAt(0))); \
break; \
}
SIMPLIFIED_NUMBER_UNOP_LIST(DECLARE_CASE)
#undef DECLARE_CASE
case IrOpcode::kPlainPrimitiveToNumber:
new_type = op_typer_.ToNumber(FeedbackTypeOf(node->InputAt(0)));
break;
case IrOpcode::kNumberAbs: {
new_type = op_typer_.NumberAbs(FeedbackTypeOf(node->InputAt(0)));
break;
}
case IrOpcode::kPhi: {
new_type = TypePhi(node);
if (type != nullptr) {
......
This diff is collapsed.
......@@ -48,8 +48,6 @@ class Typer {
Type* singleton_false_;
Type* singleton_true_;
Type* singleton_the_hole_;
Type* signed32ish_;
Type* unsigned32ish_;
Type* falsish_;
Type* truish_;
......
......@@ -50,6 +50,7 @@ class TypeCache final {
Type::Union(kSingletonTen, Type::Undefined(), zone());
Type* const kMinusOneOrZero = CreateRange(-1.0, 0.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 kZeroToThirtyTwo = CreateRange(0.0, 32.0);
Type* const kZeroish =
......
......@@ -220,7 +220,9 @@ namespace internal {
V(UniqueName, kSymbol | kInternalizedString) \
V(Name, kSymbol | kString) \
V(BooleanOrNumber, kBoolean | kNumber) \
V(BooleanOrNullOrNumber, kBooleanOrNumber | kNull) \
V(BooleanOrNullOrUndefined, kBoolean | kNull | kUndefined) \
V(NullOrNumber, kNull | kNumber) \
V(NullOrUndefined, kNull | kUndefined) \
V(Undetectable, kNullOrUndefined | kOtherUndetectable) \
V(NumberOrOddball, kNumber | kNullOrUndefined | kBoolean) \
......
......@@ -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) {
TestingGraph t(Type::Signed32());
Node* k = t.jsgraph.Constant(1000000023);
......@@ -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) {
double constants[] = {1, 3, 100, 1000, 100998348};
......@@ -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) {
{
TestingGraph t(Type::Signed32());
......@@ -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) {
double constants[] = {1, 3, 100, 1000, 100998348};
......@@ -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) {
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