Commit a49c4b0a authored by jarin's avatar jarin Committed by Commit bot

[turbofan] Type feedback for numeric comparisons.

Review-Url: https://codereview.chromium.org/2035383003
Cr-Commit-Position: refs/heads/master@{#37024}
parent b95de044
...@@ -281,7 +281,9 @@ class AstGraphBuilder::ControlScope::DeferredCommands : public ZoneObject { ...@@ -281,7 +281,9 @@ class AstGraphBuilder::ControlScope::DeferredCommands : public ZoneObject {
return NewPathToken(TokenDispenserForFinally::kFallThroughToken); return NewPathToken(TokenDispenserForFinally::kFallThroughToken);
} }
Node* NewPathDispatchCondition(Node* t1, Node* t2) { Node* NewPathDispatchCondition(Node* t1, Node* t2) {
return owner_->NewNode(owner_->javascript()->StrictEqual(), t1, t2); return owner_->NewNode(
owner_->javascript()->StrictEqual(CompareOperationHints::Any()), t1,
t2);
} }
private: private:
...@@ -1303,7 +1305,15 @@ void AstGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) { ...@@ -1303,7 +1305,15 @@ void AstGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) {
VisitForValue(clause->label()); VisitForValue(clause->label());
Node* label = environment()->Pop(); Node* label = environment()->Pop();
Node* tag = environment()->Top(); Node* tag = environment()->Top();
const Operator* op = javascript()->StrictEqual();
CompareOperationHints hints;
if (!type_hint_analysis_ ||
!type_hint_analysis_->GetCompareOperationHints(clause->CompareId(),
&hints)) {
hints = CompareOperationHints::Any();
}
const Operator* op = javascript()->StrictEqual(hints);
Node* condition = NewNode(op, tag, label); Node* condition = NewNode(op, tag, label);
compare_switch.BeginLabel(i, condition); compare_switch.BeginLabel(i, condition);
...@@ -1379,10 +1389,12 @@ void AstGraphBuilder::VisitForInStatement(ForInStatement* stmt) { ...@@ -1379,10 +1389,12 @@ void AstGraphBuilder::VisitForInStatement(ForInStatement* stmt) {
for_block.BeginBlock(); for_block.BeginBlock();
// Check for null or undefined before entering loop. // Check for null or undefined before entering loop.
Node* is_null_cond = Node* is_null_cond =
NewNode(javascript()->StrictEqual(), object, jsgraph()->NullConstant()); NewNode(javascript()->StrictEqual(CompareOperationHints::Any()), object,
jsgraph()->NullConstant());
for_block.BreakWhen(is_null_cond, BranchHint::kFalse); for_block.BreakWhen(is_null_cond, BranchHint::kFalse);
Node* is_undefined_cond = NewNode(javascript()->StrictEqual(), object, Node* is_undefined_cond =
jsgraph()->UndefinedConstant()); NewNode(javascript()->StrictEqual(CompareOperationHints::Any()), object,
jsgraph()->UndefinedConstant());
for_block.BreakWhen(is_undefined_cond, BranchHint::kFalse); for_block.BreakWhen(is_undefined_cond, BranchHint::kFalse);
{ {
// Convert object to jsobject. // Convert object to jsobject.
...@@ -1425,8 +1437,9 @@ void AstGraphBuilder::VisitForInStatement(ForInStatement* stmt) { ...@@ -1425,8 +1437,9 @@ void AstGraphBuilder::VisitForInStatement(ForInStatement* stmt) {
PrepareFrameState(value, stmt->FilterId(), PrepareFrameState(value, stmt->FilterId(),
OutputFrameStateCombine::Push()); OutputFrameStateCombine::Push());
IfBuilder test_value(this); IfBuilder test_value(this);
Node* test_value_cond = NewNode(javascript()->StrictEqual(), value, Node* test_value_cond =
jsgraph()->UndefinedConstant()); NewNode(javascript()->StrictEqual(CompareOperationHints::Any()),
value, jsgraph()->UndefinedConstant());
test_value.If(test_value_cond, BranchHint::kFalse); test_value.If(test_value_cond, BranchHint::kFalse);
test_value.Then(); test_value.Then();
test_value.Else(); test_value.Else();
...@@ -2831,10 +2844,10 @@ void AstGraphBuilder::VisitLiteralCompareNil(CompareOperation* expr, ...@@ -2831,10 +2844,10 @@ void AstGraphBuilder::VisitLiteralCompareNil(CompareOperation* expr,
const Operator* op = nullptr; const Operator* op = nullptr;
switch (expr->op()) { switch (expr->op()) {
case Token::EQ: case Token::EQ:
op = javascript()->Equal(); op = javascript()->Equal(CompareOperationHints::Any());
break; break;
case Token::EQ_STRICT: case Token::EQ_STRICT:
op = javascript()->StrictEqual(); op = javascript()->StrictEqual(CompareOperationHints::Any());
break; break;
default: default:
UNREACHABLE(); UNREACHABLE();
...@@ -2853,8 +2866,8 @@ void AstGraphBuilder::VisitLiteralCompareTypeof(CompareOperation* expr, ...@@ -2853,8 +2866,8 @@ void AstGraphBuilder::VisitLiteralCompareTypeof(CompareOperation* expr,
VisitTypeofExpression(sub_expr); VisitTypeofExpression(sub_expr);
PrepareEagerCheckpoint(sub_expr->id()); PrepareEagerCheckpoint(sub_expr->id());
Node* typeof_arg = NewNode(javascript()->TypeOf(), environment()->Pop()); Node* typeof_arg = NewNode(javascript()->TypeOf(), environment()->Pop());
Node* value = NewNode(javascript()->StrictEqual(), typeof_arg, Node* value = NewNode(javascript()->StrictEqual(CompareOperationHints::Any()),
jsgraph()->Constant(check)); typeof_arg, jsgraph()->Constant(check));
PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine()); PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
return ast_context()->ProduceValue(value); return ast_context()->ProduceValue(value);
} }
...@@ -2876,31 +2889,38 @@ void AstGraphBuilder::VisitCompareOperation(CompareOperation* expr) { ...@@ -2876,31 +2889,38 @@ void AstGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
return VisitLiteralCompareNil(expr, sub_expr, jsgraph()->NullConstant()); return VisitLiteralCompareNil(expr, sub_expr, jsgraph()->NullConstant());
} }
CompareOperationHints hints;
if (!type_hint_analysis_ ||
!type_hint_analysis_->GetCompareOperationHints(
expr->CompareOperationFeedbackId(), &hints)) {
hints = CompareOperationHints::Any();
}
const Operator* op; const Operator* op;
switch (expr->op()) { switch (expr->op()) {
case Token::EQ: case Token::EQ:
op = javascript()->Equal(); op = javascript()->Equal(hints);
break; break;
case Token::NE: case Token::NE:
op = javascript()->NotEqual(); op = javascript()->NotEqual(hints);
break; break;
case Token::EQ_STRICT: case Token::EQ_STRICT:
op = javascript()->StrictEqual(); op = javascript()->StrictEqual(hints);
break; break;
case Token::NE_STRICT: case Token::NE_STRICT:
op = javascript()->StrictNotEqual(); op = javascript()->StrictNotEqual(hints);
break; break;
case Token::LT: case Token::LT:
op = javascript()->LessThan(); op = javascript()->LessThan(hints);
break; break;
case Token::GT: case Token::GT:
op = javascript()->GreaterThan(); op = javascript()->GreaterThan(hints);
break; break;
case Token::LTE: case Token::LTE:
op = javascript()->LessThanOrEqual(); op = javascript()->LessThanOrEqual(hints);
break; break;
case Token::GTE: case Token::GTE:
op = javascript()->GreaterThanOrEqual(); op = javascript()->GreaterThanOrEqual(hints);
break; break;
case Token::INSTANCEOF: case Token::INSTANCEOF:
op = javascript()->InstanceOf(); op = javascript()->InstanceOf();
...@@ -3319,7 +3339,8 @@ Node* AstGraphBuilder::BuildHoleCheckThenThrow(Node* value, Variable* variable, ...@@ -3319,7 +3339,8 @@ Node* AstGraphBuilder::BuildHoleCheckThenThrow(Node* value, Variable* variable,
BailoutId bailout_id) { BailoutId bailout_id) {
IfBuilder hole_check(this); IfBuilder hole_check(this);
Node* the_hole = jsgraph()->TheHoleConstant(); Node* the_hole = jsgraph()->TheHoleConstant();
Node* check = NewNode(javascript()->StrictEqual(), value, the_hole); Node* check = NewNode(javascript()->StrictEqual(CompareOperationHints::Any()),
value, the_hole);
hole_check.If(check); hole_check.If(check);
hole_check.Then(); hole_check.Then();
Node* error = BuildThrowReferenceError(variable, bailout_id); Node* error = BuildThrowReferenceError(variable, bailout_id);
...@@ -3336,7 +3357,8 @@ Node* AstGraphBuilder::BuildHoleCheckElseThrow(Node* value, Variable* variable, ...@@ -3336,7 +3357,8 @@ Node* AstGraphBuilder::BuildHoleCheckElseThrow(Node* value, Variable* variable,
BailoutId bailout_id) { BailoutId bailout_id) {
IfBuilder hole_check(this); IfBuilder hole_check(this);
Node* the_hole = jsgraph()->TheHoleConstant(); Node* the_hole = jsgraph()->TheHoleConstant();
Node* check = NewNode(javascript()->StrictEqual(), value, the_hole); Node* check = NewNode(javascript()->StrictEqual(CompareOperationHints::Any()),
value, the_hole);
hole_check.If(check); hole_check.If(check);
hole_check.Then(); hole_check.Then();
environment()->Push(for_hole); environment()->Push(for_hole);
...@@ -3353,7 +3375,8 @@ Node* AstGraphBuilder::BuildThrowIfStaticPrototype(Node* name, ...@@ -3353,7 +3375,8 @@ Node* AstGraphBuilder::BuildThrowIfStaticPrototype(Node* name,
IfBuilder prototype_check(this); IfBuilder prototype_check(this);
Node* prototype_string = Node* prototype_string =
jsgraph()->Constant(isolate()->factory()->prototype_string()); jsgraph()->Constant(isolate()->factory()->prototype_string());
Node* check = NewNode(javascript()->StrictEqual(), name, prototype_string); Node* check = NewNode(javascript()->StrictEqual(CompareOperationHints::Any()),
name, prototype_string);
prototype_check.If(check); prototype_check.If(check);
prototype_check.Then(); prototype_check.Then();
Node* error = BuildThrowStaticPrototypeError(bailout_id); Node* error = BuildThrowStaticPrototypeError(bailout_id);
...@@ -3903,8 +3926,9 @@ Node* AstGraphBuilder::TryLoadDynamicVariable(Variable* variable, ...@@ -3903,8 +3926,9 @@ Node* AstGraphBuilder::TryLoadDynamicVariable(Variable* variable,
Node* load = NewNode( Node* load = NewNode(
javascript()->LoadContext(depth, Context::EXTENSION_INDEX, false), javascript()->LoadContext(depth, Context::EXTENSION_INDEX, false),
current_context()); current_context());
Node* check = NewNode(javascript()->StrictEqual(), load, Node* check =
jsgraph()->TheHoleConstant()); NewNode(javascript()->StrictEqual(CompareOperationHints::Any()), load,
jsgraph()->TheHoleConstant());
fast_block.BreakUnless(check, BranchHint::kTrue); fast_block.BreakUnless(check, BranchHint::kTrue);
} }
...@@ -3949,8 +3973,9 @@ Node* AstGraphBuilder::TryLoadDynamicVariable(Variable* variable, ...@@ -3949,8 +3973,9 @@ Node* AstGraphBuilder::TryLoadDynamicVariable(Variable* variable,
Node* load = NewNode( Node* load = NewNode(
javascript()->LoadContext(depth, Context::EXTENSION_INDEX, false), javascript()->LoadContext(depth, Context::EXTENSION_INDEX, false),
current_context()); current_context());
Node* check = NewNode(javascript()->StrictEqual(), load, Node* check =
jsgraph()->TheHoleConstant()); NewNode(javascript()->StrictEqual(CompareOperationHints::Any()), load,
jsgraph()->TheHoleConstant());
fast_block.BreakUnless(check, BranchHint::kTrue); fast_block.BreakUnless(check, BranchHint::kTrue);
} }
......
...@@ -1224,31 +1224,38 @@ void BytecodeGraphBuilder::BuildCompareOp(const Operator* js_op) { ...@@ -1224,31 +1224,38 @@ void BytecodeGraphBuilder::BuildCompareOp(const Operator* js_op) {
} }
void BytecodeGraphBuilder::VisitTestEqual() { void BytecodeGraphBuilder::VisitTestEqual() {
BuildCompareOp(javascript()->Equal()); CompareOperationHints hints = CompareOperationHints::Any();
BuildCompareOp(javascript()->Equal(hints));
} }
void BytecodeGraphBuilder::VisitTestNotEqual() { void BytecodeGraphBuilder::VisitTestNotEqual() {
BuildCompareOp(javascript()->NotEqual()); CompareOperationHints hints = CompareOperationHints::Any();
BuildCompareOp(javascript()->NotEqual(hints));
} }
void BytecodeGraphBuilder::VisitTestEqualStrict() { void BytecodeGraphBuilder::VisitTestEqualStrict() {
BuildCompareOp(javascript()->StrictEqual()); CompareOperationHints hints = CompareOperationHints::Any();
BuildCompareOp(javascript()->StrictEqual(hints));
} }
void BytecodeGraphBuilder::VisitTestLessThan() { void BytecodeGraphBuilder::VisitTestLessThan() {
BuildCompareOp(javascript()->LessThan()); CompareOperationHints hints = CompareOperationHints::Any();
BuildCompareOp(javascript()->LessThan(hints));
} }
void BytecodeGraphBuilder::VisitTestGreaterThan() { void BytecodeGraphBuilder::VisitTestGreaterThan() {
BuildCompareOp(javascript()->GreaterThan()); CompareOperationHints hints = CompareOperationHints::Any();
BuildCompareOp(javascript()->GreaterThan(hints));
} }
void BytecodeGraphBuilder::VisitTestLessThanOrEqual() { void BytecodeGraphBuilder::VisitTestLessThanOrEqual() {
BuildCompareOp(javascript()->LessThanOrEqual()); CompareOperationHints hints = CompareOperationHints::Any();
BuildCompareOp(javascript()->LessThanOrEqual(hints));
} }
void BytecodeGraphBuilder::VisitTestGreaterThanOrEqual() { void BytecodeGraphBuilder::VisitTestGreaterThanOrEqual() {
BuildCompareOp(javascript()->GreaterThanOrEqual()); CompareOperationHints hints = CompareOperationHints::Any();
BuildCompareOp(javascript()->GreaterThanOrEqual(hints));
} }
void BytecodeGraphBuilder::VisitTestIn() { void BytecodeGraphBuilder::VisitTestIn() {
...@@ -1518,7 +1525,8 @@ void BytecodeGraphBuilder::BuildConditionalJump(Node* condition) { ...@@ -1518,7 +1525,8 @@ void BytecodeGraphBuilder::BuildConditionalJump(Node* condition) {
void BytecodeGraphBuilder::BuildJumpIfEqual(Node* comperand) { void BytecodeGraphBuilder::BuildJumpIfEqual(Node* comperand) {
Node* accumulator = environment()->LookupAccumulator(); Node* accumulator = environment()->LookupAccumulator();
Node* condition = Node* condition =
NewNode(javascript()->StrictEqual(), accumulator, comperand); NewNode(javascript()->StrictEqual(CompareOperationHints::Any()),
accumulator, comperand);
BuildConditionalJump(condition); BuildConditionalJump(condition);
} }
...@@ -1527,14 +1535,17 @@ void BytecodeGraphBuilder::BuildJumpIfToBooleanEqual(Node* comperand) { ...@@ -1527,14 +1535,17 @@ void BytecodeGraphBuilder::BuildJumpIfToBooleanEqual(Node* comperand) {
Node* accumulator = environment()->LookupAccumulator(); Node* accumulator = environment()->LookupAccumulator();
Node* to_boolean = Node* to_boolean =
NewNode(javascript()->ToBoolean(ToBooleanHint::kAny), accumulator); NewNode(javascript()->ToBoolean(ToBooleanHint::kAny), accumulator);
Node* condition = NewNode(javascript()->StrictEqual(), to_boolean, comperand); Node* condition =
NewNode(javascript()->StrictEqual(CompareOperationHints::Any()),
to_boolean, comperand);
BuildConditionalJump(condition); BuildConditionalJump(condition);
} }
void BytecodeGraphBuilder::BuildJumpIfNotHole() { void BytecodeGraphBuilder::BuildJumpIfNotHole() {
Node* accumulator = environment()->LookupAccumulator(); Node* accumulator = environment()->LookupAccumulator();
Node* condition = NewNode(javascript()->StrictEqual(), accumulator, Node* condition =
jsgraph()->TheHoleConstant()); NewNode(javascript()->StrictEqual(CompareOperationHints::Any()),
accumulator, jsgraph()->TheHoleConstant());
Node* node = Node* node =
NewNode(common()->Select(MachineRepresentation::kTagged), condition, NewNode(common()->Select(MachineRepresentation::kTagged), condition,
jsgraph()->FalseConstant(), jsgraph()->TrueConstant()); jsgraph()->FalseConstant(), jsgraph()->TrueConstant());
......
...@@ -323,8 +323,9 @@ Reduction JSCallReducer::ReduceJSCallFunction(Node* node) { ...@@ -323,8 +323,9 @@ Reduction JSCallReducer::ReduceJSCallFunction(Node* node) {
} }
// Check that the {target} is still the {array_function}. // Check that the {target} is still the {array_function}.
Node* check = graph()->NewNode(javascript()->StrictEqual(), target, Node* check = graph()->NewNode(
array_function, context); javascript()->StrictEqual(CompareOperationHints::Any()), target,
array_function, context);
control = effect = graph()->NewNode(common()->DeoptimizeUnless(), check, control = effect = graph()->NewNode(common()->DeoptimizeUnless(), check,
frame_state, effect, control); frame_state, effect, control);
...@@ -340,8 +341,9 @@ Reduction JSCallReducer::ReduceJSCallFunction(Node* node) { ...@@ -340,8 +341,9 @@ Reduction JSCallReducer::ReduceJSCallFunction(Node* node) {
jsgraph()->Constant(handle(cell->value(), isolate())); jsgraph()->Constant(handle(cell->value(), isolate()));
// Check that the {target} is still the {target_function}. // Check that the {target} is still the {target_function}.
Node* check = graph()->NewNode(javascript()->StrictEqual(), target, Node* check = graph()->NewNode(
target_function, context); javascript()->StrictEqual(CompareOperationHints::Any()), target,
target_function, context);
control = effect = graph()->NewNode(common()->DeoptimizeUnless(), check, control = effect = graph()->NewNode(common()->DeoptimizeUnless(), check,
frame_state, effect, control); frame_state, effect, control);
...@@ -443,8 +445,9 @@ Reduction JSCallReducer::ReduceJSCallConstruct(Node* node) { ...@@ -443,8 +445,9 @@ Reduction JSCallReducer::ReduceJSCallConstruct(Node* node) {
} }
// Check that the {target} is still the {array_function}. // Check that the {target} is still the {array_function}.
Node* check = graph()->NewNode(javascript()->StrictEqual(), target, Node* check = graph()->NewNode(
array_function, context); javascript()->StrictEqual(CompareOperationHints::Any()), target,
array_function, context);
control = effect = graph()->NewNode(common()->DeoptimizeUnless(), check, control = effect = graph()->NewNode(common()->DeoptimizeUnless(), check,
frame_state, effect, control); frame_state, effect, control);
...@@ -465,8 +468,9 @@ Reduction JSCallReducer::ReduceJSCallConstruct(Node* node) { ...@@ -465,8 +468,9 @@ Reduction JSCallReducer::ReduceJSCallConstruct(Node* node) {
jsgraph()->Constant(handle(cell->value(), isolate())); jsgraph()->Constant(handle(cell->value(), isolate()));
// Check that the {target} is still the {target_function}. // Check that the {target} is still the {target_function}.
Node* check = graph()->NewNode(javascript()->StrictEqual(), target, Node* check = graph()->NewNode(
target_function, context); javascript()->StrictEqual(CompareOperationHints::Any()), target,
target_function, context);
control = effect = graph()->NewNode(common()->DeoptimizeUnless(), check, control = effect = graph()->NewNode(common()->DeoptimizeUnless(), check,
frame_state, effect, control); frame_state, effect, control);
......
...@@ -377,20 +377,33 @@ const CreateLiteralParameters& CreateLiteralParametersOf(const Operator* op) { ...@@ -377,20 +377,33 @@ const CreateLiteralParameters& CreateLiteralParametersOf(const Operator* op) {
} }
const BinaryOperationHints& BinaryOperationHintsOf(const Operator* op) { const BinaryOperationHints& BinaryOperationHintsOf(const Operator* op) {
DCHECK(op->opcode() == IrOpcode::kJSAdd || DCHECK(op->opcode() == IrOpcode::kJSBitwiseOr ||
op->opcode() == IrOpcode::kJSSubtract); op->opcode() == IrOpcode::kJSBitwiseXor ||
op->opcode() == IrOpcode::kJSBitwiseAnd ||
op->opcode() == IrOpcode::kJSShiftLeft ||
op->opcode() == IrOpcode::kJSShiftRight ||
op->opcode() == IrOpcode::kJSShiftRightLogical ||
op->opcode() == IrOpcode::kJSAdd ||
op->opcode() == IrOpcode::kJSSubtract ||
op->opcode() == IrOpcode::kJSMultiply ||
op->opcode() == IrOpcode::kJSDivide ||
op->opcode() == IrOpcode::kJSModulus);
return OpParameter<BinaryOperationHints>(op); return OpParameter<BinaryOperationHints>(op);
} }
const CompareOperationHints& CompareOperationHintsOf(const Operator* op) {
DCHECK(op->opcode() == IrOpcode::kJSEqual ||
op->opcode() == IrOpcode::kJSNotEqual ||
op->opcode() == IrOpcode::kJSStrictEqual ||
op->opcode() == IrOpcode::kJSStrictNotEqual ||
op->opcode() == IrOpcode::kJSLessThan ||
op->opcode() == IrOpcode::kJSGreaterThan ||
op->opcode() == IrOpcode::kJSLessThanOrEqual ||
op->opcode() == IrOpcode::kJSGreaterThanOrEqual);
return OpParameter<CompareOperationHints>(op);
}
#define CACHED_OP_LIST(V) \ #define CACHED_OP_LIST(V) \
V(Equal, Operator::kNoProperties, 2, 1) \
V(NotEqual, Operator::kNoProperties, 2, 1) \
V(StrictEqual, Operator::kPure, 2, 1) \
V(StrictNotEqual, Operator::kPure, 2, 1) \
V(LessThan, Operator::kNoProperties, 2, 1) \
V(GreaterThan, Operator::kNoProperties, 2, 1) \
V(LessThanOrEqual, Operator::kNoProperties, 2, 1) \
V(GreaterThanOrEqual, Operator::kNoProperties, 2, 1) \
V(ToInteger, Operator::kNoProperties, 1, 1) \ V(ToInteger, Operator::kNoProperties, 1, 1) \
V(ToLength, Operator::kNoProperties, 1, 1) \ V(ToLength, Operator::kNoProperties, 1, 1) \
V(ToName, Operator::kNoProperties, 1, 1) \ V(ToName, Operator::kNoProperties, 1, 1) \
...@@ -544,6 +557,79 @@ const Operator* JSOperatorBuilder::Modulus(BinaryOperationHints hints) { ...@@ -544,6 +557,79 @@ const Operator* JSOperatorBuilder::Modulus(BinaryOperationHints hints) {
hints); // parameter hints); // parameter
} }
const Operator* JSOperatorBuilder::Equal(CompareOperationHints hints) {
// TODO(turbofan): Cache most important versions of this operator.
return new (zone()) Operator1<CompareOperationHints>( //--
IrOpcode::kJSEqual, Operator::kNoProperties, // opcode
"JSEqual", // name
2, 1, 1, 1, 1, 2, // inputs/outputs
hints); // parameter
}
const Operator* JSOperatorBuilder::NotEqual(CompareOperationHints hints) {
// TODO(turbofan): Cache most important versions of this operator.
return new (zone()) Operator1<CompareOperationHints>( //--
IrOpcode::kJSNotEqual, Operator::kNoProperties, // opcode
"JSNotEqual", // name
2, 1, 1, 1, 1, 2, // inputs/outputs
hints); // parameter
}
const Operator* JSOperatorBuilder::StrictEqual(CompareOperationHints hints) {
// TODO(turbofan): Cache most important versions of this operator.
return new (zone()) Operator1<CompareOperationHints>( //--
IrOpcode::kJSStrictEqual, Operator::kPure, // opcode
"JSStrictEqual", // name
2, 0, 0, 1, 0, 0, // inputs/outputs
hints); // parameter
}
const Operator* JSOperatorBuilder::StrictNotEqual(CompareOperationHints hints) {
// TODO(turbofan): Cache most important versions of this operator.
return new (zone()) Operator1<CompareOperationHints>( //--
IrOpcode::kJSStrictNotEqual, Operator::kPure, // opcode
"JSStrictNotEqual", // name
2, 0, 0, 1, 0, 0, // inputs/outputs
hints); // parameter
}
const Operator* JSOperatorBuilder::LessThan(CompareOperationHints hints) {
// TODO(turbofan): Cache most important versions of this operator.
return new (zone()) Operator1<CompareOperationHints>( //--
IrOpcode::kJSLessThan, Operator::kNoProperties, // opcode
"JSLessThan", // name
2, 1, 1, 1, 1, 2, // inputs/outputs
hints); // parameter
}
const Operator* JSOperatorBuilder::GreaterThan(CompareOperationHints hints) {
// TODO(turbofan): Cache most important versions of this operator.
return new (zone()) Operator1<CompareOperationHints>( //--
IrOpcode::kJSGreaterThan, Operator::kNoProperties, // opcode
"JSGreaterThan", // name
2, 1, 1, 1, 1, 2, // inputs/outputs
hints); // parameter
}
const Operator* JSOperatorBuilder::LessThanOrEqual(
CompareOperationHints hints) {
// TODO(turbofan): Cache most important versions of this operator.
return new (zone()) Operator1<CompareOperationHints>( //--
IrOpcode::kJSLessThanOrEqual, Operator::kNoProperties, // opcode
"JSLessThanOrEqual", // name
2, 1, 1, 1, 1, 2, // inputs/outputs
hints); // parameter
}
const Operator* JSOperatorBuilder::GreaterThanOrEqual(
CompareOperationHints hints) {
// TODO(turbofan): Cache most important versions of this operator.
return new (zone()) Operator1<CompareOperationHints>( //--
IrOpcode::kJSGreaterThanOrEqual, Operator::kNoProperties, // opcode
"JSGreaterThanOrEqual", // name
2, 1, 1, 1, 1, 2, // inputs/outputs
hints); // parameter
}
const Operator* JSOperatorBuilder::ToBoolean(ToBooleanHints hints) { const Operator* JSOperatorBuilder::ToBoolean(ToBooleanHints hints) {
// TODO(turbofan): Cache most important versions of this operator. // TODO(turbofan): Cache most important versions of this operator.
......
...@@ -376,6 +376,8 @@ const CreateLiteralParameters& CreateLiteralParametersOf(const Operator* op); ...@@ -376,6 +376,8 @@ const CreateLiteralParameters& CreateLiteralParametersOf(const Operator* op);
const BinaryOperationHints& BinaryOperationHintsOf(const Operator* op); const BinaryOperationHints& BinaryOperationHintsOf(const Operator* op);
const CompareOperationHints& CompareOperationHintsOf(const Operator* op);
// Interface for building JavaScript-level operators, e.g. directly from the // Interface for building JavaScript-level operators, e.g. directly from the
// AST. Most operators have no parameters, thus can be globally shared for all // AST. Most operators have no parameters, thus can be globally shared for all
// graphs. // graphs.
...@@ -383,14 +385,14 @@ class JSOperatorBuilder final : public ZoneObject { ...@@ -383,14 +385,14 @@ class JSOperatorBuilder final : public ZoneObject {
public: public:
explicit JSOperatorBuilder(Zone* zone); explicit JSOperatorBuilder(Zone* zone);
const Operator* Equal(); const Operator* Equal(CompareOperationHints hints);
const Operator* NotEqual(); const Operator* NotEqual(CompareOperationHints hints);
const Operator* StrictEqual(); const Operator* StrictEqual(CompareOperationHints hints);
const Operator* StrictNotEqual(); const Operator* StrictNotEqual(CompareOperationHints hints);
const Operator* LessThan(); const Operator* LessThan(CompareOperationHints hints);
const Operator* GreaterThan(); const Operator* GreaterThan(CompareOperationHints hints);
const Operator* LessThanOrEqual(); const Operator* LessThanOrEqual(CompareOperationHints hints);
const Operator* GreaterThanOrEqual(); const Operator* GreaterThanOrEqual(CompareOperationHints hints);
const Operator* BitwiseOr(BinaryOperationHints hints); const Operator* BitwiseOr(BinaryOperationHints hints);
const Operator* BitwiseXor(BinaryOperationHints hints); const Operator* BitwiseXor(BinaryOperationHints hints);
const Operator* BitwiseAnd(BinaryOperationHints hints); const Operator* BitwiseAnd(BinaryOperationHints hints);
......
...@@ -27,7 +27,7 @@ class JSBinopReduction final { ...@@ -27,7 +27,7 @@ class JSBinopReduction final {
JSBinopReduction(JSTypedLowering* lowering, Node* node) JSBinopReduction(JSTypedLowering* lowering, Node* node)
: lowering_(lowering), node_(node) {} : lowering_(lowering), node_(node) {}
BinaryOperationHints::Hint GetUsableNumberFeedback() { BinaryOperationHints::Hint GetNumberBinaryOperationFeedback() {
if (!(lowering_->flags() & JSTypedLowering::kDeoptimizationEnabled) || if (!(lowering_->flags() & JSTypedLowering::kDeoptimizationEnabled) ||
!(lowering_->flags() & JSTypedLowering::kTypeFeedbackEnabled)) { !(lowering_->flags() & JSTypedLowering::kTypeFeedbackEnabled)) {
return BinaryOperationHints::kAny; return BinaryOperationHints::kAny;
...@@ -45,6 +45,23 @@ class JSBinopReduction final { ...@@ -45,6 +45,23 @@ class JSBinopReduction final {
return BinaryOperationHints::kAny; return BinaryOperationHints::kAny;
} }
CompareOperationHints::Hint GetNumberCompareOperationFeedback() {
if (!(lowering_->flags() & JSTypedLowering::kDeoptimizationEnabled) ||
!(lowering_->flags() & JSTypedLowering::kTypeFeedbackEnabled)) {
return CompareOperationHints::kAny;
}
DCHECK_NE(0, node_->op()->ControlOutputCount());
DCHECK_EQ(1, node_->op()->EffectOutputCount());
DCHECK_EQ(2, OperatorProperties::GetFrameStateInputCount(node_->op()));
CompareOperationHints hints = CompareOperationHintsOf(node_->op());
CompareOperationHints::Hint combined = hints.combined();
if (combined == CompareOperationHints::kSignedSmall ||
combined == CompareOperationHints::kNumber) {
return combined;
}
return CompareOperationHints::kAny;
}
void ConvertInputsToNumber(Node* frame_state) { void ConvertInputsToNumber(Node* frame_state) {
// To convert the inputs to numbers, we have to provide frame states // To convert the inputs to numbers, we have to provide frame states
// for lazy bailouts in the ToNumber conversions. // for lazy bailouts in the ToNumber conversions.
...@@ -125,7 +142,7 @@ class JSBinopReduction final { ...@@ -125,7 +142,7 @@ class JSBinopReduction final {
return lowering_->Changed(node_); return lowering_->Changed(node_);
} }
Reduction ChangeToSpeculativeOperator(const Operator* op) { Reduction ChangeToSpeculativeOperator(const Operator* op, Type* upper_bound) {
DCHECK_EQ(1, op->EffectInputCount()); DCHECK_EQ(1, op->EffectInputCount());
DCHECK_EQ(1, op->EffectOutputCount()); DCHECK_EQ(1, op->EffectOutputCount());
DCHECK_EQ(false, OperatorProperties::HasContextInput(op)); DCHECK_EQ(false, OperatorProperties::HasContextInput(op));
...@@ -167,7 +184,7 @@ class JSBinopReduction final { ...@@ -167,7 +184,7 @@ class JSBinopReduction final {
// Update the type to number. // Update the type to number.
Type* node_type = NodeProperties::GetType(node_); Type* node_type = NodeProperties::GetType(node_);
NodeProperties::SetType(node_, NodeProperties::SetType(node_,
Type::Intersect(node_type, Type::Number(), zone())); Type::Intersect(node_type, upper_bound, zone()));
return lowering_->Changed(node_); return lowering_->Changed(node_);
} }
...@@ -403,7 +420,7 @@ Reduction JSTypedLowering::ReduceJSAdd(Node* node) { ...@@ -403,7 +420,7 @@ Reduction JSTypedLowering::ReduceJSAdd(Node* node) {
JSBinopReduction r(this, node); JSBinopReduction r(this, node);
BinaryOperationHints::Hint feedback = r.GetUsableNumberFeedback(); BinaryOperationHints::Hint feedback = r.GetNumberBinaryOperationFeedback();
if (feedback == BinaryOperationHints::kNumberOrUndefined && if (feedback == BinaryOperationHints::kNumberOrUndefined &&
r.BothInputsAre(Type::PlainPrimitive()) && r.BothInputsAre(Type::PlainPrimitive()) &&
r.NeitherInputCanBe(Type::StringOrReceiver())) { r.NeitherInputCanBe(Type::StringOrReceiver())) {
...@@ -415,7 +432,7 @@ Reduction JSTypedLowering::ReduceJSAdd(Node* node) { ...@@ -415,7 +432,7 @@ Reduction JSTypedLowering::ReduceJSAdd(Node* node) {
if (feedback != BinaryOperationHints::kAny) { if (feedback != BinaryOperationHints::kAny) {
// Lower to the optimistic number binop. // Lower to the optimistic number binop.
return r.ChangeToSpeculativeOperator( return r.ChangeToSpeculativeOperator(
simplified()->SpeculativeNumberAdd(feedback)); simplified()->SpeculativeNumberAdd(feedback), Type::Number());
} }
if (r.BothInputsAre(Type::Number())) { if (r.BothInputsAre(Type::Number())) {
// JSAdd(x:number, y:number) => NumberAdd(x, y) // JSAdd(x:number, y:number) => NumberAdd(x, y)
...@@ -469,7 +486,7 @@ Reduction JSTypedLowering::ReduceJSModulus(Node* node) { ...@@ -469,7 +486,7 @@ Reduction JSTypedLowering::ReduceJSModulus(Node* node) {
Reduction JSTypedLowering::ReduceJSSubtract(Node* node) { Reduction JSTypedLowering::ReduceJSSubtract(Node* node) {
if (flags() & kDisableBinaryOpReduction) return NoChange(); if (flags() & kDisableBinaryOpReduction) return NoChange();
JSBinopReduction r(this, node); JSBinopReduction r(this, node);
BinaryOperationHints::Hint feedback = r.GetUsableNumberFeedback(); BinaryOperationHints::Hint feedback = r.GetNumberBinaryOperationFeedback();
if (feedback == BinaryOperationHints::kNumberOrUndefined && if (feedback == BinaryOperationHints::kNumberOrUndefined &&
r.BothInputsAre(Type::PlainPrimitive())) { r.BothInputsAre(Type::PlainPrimitive())) {
// JSSubtract(x:plain-primitive, y:plain-primitive) // JSSubtract(x:plain-primitive, y:plain-primitive)
...@@ -482,7 +499,7 @@ Reduction JSTypedLowering::ReduceJSSubtract(Node* node) { ...@@ -482,7 +499,7 @@ Reduction JSTypedLowering::ReduceJSSubtract(Node* node) {
if (feedback != BinaryOperationHints::kAny) { if (feedback != BinaryOperationHints::kAny) {
// Lower to the optimistic number binop. // Lower to the optimistic number binop.
return r.ChangeToSpeculativeOperator( return r.ChangeToSpeculativeOperator(
simplified()->SpeculativeNumberSubtract(feedback)); simplified()->SpeculativeNumberSubtract(feedback), Type::Number());
} }
Node* frame_state = NodeProperties::GetFrameStateInput(node, 1); Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
r.ConvertInputsToNumber(frame_state); r.ConvertInputsToNumber(frame_state);
...@@ -558,7 +575,10 @@ Reduction JSTypedLowering::ReduceJSComparison(Node* node) { ...@@ -558,7 +575,10 @@ Reduction JSTypedLowering::ReduceJSComparison(Node* node) {
r.ChangeToPureOperator(stringOp); r.ChangeToPureOperator(stringOp);
return Changed(node); return Changed(node);
} }
if (r.OneInputCannotBe(Type::StringOrReceiver())) {
CompareOperationHints::Hint hint = r.GetNumberCompareOperationFeedback();
if (hint != CompareOperationHints::kAny ||
r.OneInputCannotBe(Type::StringOrReceiver())) {
const Operator* less_than; const Operator* less_than;
const Operator* less_than_or_equal; const Operator* less_than_or_equal;
if (r.BothInputsAre(Type::Unsigned32())) { if (r.BothInputsAre(Type::Unsigned32())) {
...@@ -567,6 +587,9 @@ Reduction JSTypedLowering::ReduceJSComparison(Node* node) { ...@@ -567,6 +587,9 @@ Reduction JSTypedLowering::ReduceJSComparison(Node* node) {
} else if (r.BothInputsAre(Type::Signed32())) { } else if (r.BothInputsAre(Type::Signed32())) {
less_than = machine()->Int32LessThan(); less_than = machine()->Int32LessThan();
less_than_or_equal = machine()->Int32LessThanOrEqual(); less_than_or_equal = machine()->Int32LessThanOrEqual();
} else if (hint != CompareOperationHints::kAny) {
less_than = simplified()->SpeculativeNumberLessThan(hint);
less_than_or_equal = simplified()->SpeculativeNumberLessThanOrEqual(hint);
} else { } else {
// TODO(turbofan): mixed signed/unsigned int32 comparisons. // TODO(turbofan): mixed signed/unsigned int32 comparisons.
Node* frame_state = NodeProperties::GetFrameStateInput(node, 1); Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
...@@ -593,7 +616,11 @@ Reduction JSTypedLowering::ReduceJSComparison(Node* node) { ...@@ -593,7 +616,11 @@ Reduction JSTypedLowering::ReduceJSComparison(Node* node) {
default: default:
return NoChange(); return NoChange();
} }
return r.ChangeToPureOperator(comparison); if (comparison->EffectInputCount() > 0) {
return r.ChangeToSpeculativeOperator(comparison, Type::Boolean());
} else {
return r.ChangeToPureOperator(comparison);
}
} }
// TODO(turbofan): relax/remove effects of this operator in other cases. // TODO(turbofan): relax/remove effects of this operator in other cases.
return NoChange(); // Keep a generic comparison. return NoChange(); // Keep a generic comparison.
......
...@@ -173,76 +173,79 @@ ...@@ -173,76 +173,79 @@
V(StringLessThan) \ V(StringLessThan) \
V(StringLessThanOrEqual) V(StringLessThanOrEqual)
#define SIMPLIFIED_OP_LIST(V) \ #define SIMPLIFIED_OP_LIST(V) \
SIMPLIFIED_COMPARE_BINOP_LIST(V) \ SIMPLIFIED_COMPARE_BINOP_LIST(V) \
V(PlainPrimitiveToNumber) \ V(PlainPrimitiveToNumber) \
V(PlainPrimitiveToWord32) \ V(PlainPrimitiveToWord32) \
V(PlainPrimitiveToFloat64) \ V(PlainPrimitiveToFloat64) \
V(BooleanNot) \ V(BooleanNot) \
V(BooleanToNumber) \ V(BooleanToNumber) \
V(SpeculativeNumberAdd) \ V(SpeculativeNumberAdd) \
V(SpeculativeNumberSubtract) \ V(SpeculativeNumberSubtract) \
V(NumberAdd) \ V(SpeculativeNumberEqual) \
V(NumberSubtract) \ V(SpeculativeNumberLessThan) \
V(NumberMultiply) \ V(SpeculativeNumberLessThanOrEqual) \
V(NumberDivide) \ V(NumberAdd) \
V(NumberModulus) \ V(NumberSubtract) \
V(NumberBitwiseOr) \ V(NumberMultiply) \
V(NumberBitwiseXor) \ V(NumberDivide) \
V(NumberBitwiseAnd) \ V(NumberModulus) \
V(NumberShiftLeft) \ V(NumberBitwiseOr) \
V(NumberShiftRight) \ V(NumberBitwiseXor) \
V(NumberShiftRightLogical) \ V(NumberBitwiseAnd) \
V(NumberImul) \ V(NumberShiftLeft) \
V(NumberClz32) \ V(NumberShiftRight) \
V(NumberCeil) \ V(NumberShiftRightLogical) \
V(NumberFloor) \ V(NumberImul) \
V(NumberFround) \ V(NumberClz32) \
V(NumberAtan) \ V(NumberCeil) \
V(NumberAtan2) \ V(NumberFloor) \
V(NumberLog) \ V(NumberFround) \
V(NumberLog1p) \ V(NumberAtan) \
V(NumberRound) \ V(NumberAtan2) \
V(NumberSqrt) \ V(NumberLog) \
V(NumberTrunc) \ V(NumberLog1p) \
V(NumberToInt32) \ V(NumberRound) \
V(NumberToUint32) \ V(NumberSqrt) \
V(NumberSilenceNaN) \ V(NumberTrunc) \
V(StringFromCharCode) \ V(NumberToInt32) \
V(StringToNumber) \ V(NumberToUint32) \
V(ChangeTaggedSignedToInt32) \ V(NumberSilenceNaN) \
V(ChangeTaggedToInt32) \ V(StringFromCharCode) \
V(ChangeTaggedToUint32) \ V(StringToNumber) \
V(ChangeTaggedToFloat64) \ V(ChangeTaggedSignedToInt32) \
V(ChangeInt31ToTaggedSigned) \ V(ChangeTaggedToInt32) \
V(ChangeInt32ToTagged) \ V(ChangeTaggedToUint32) \
V(ChangeUint32ToTagged) \ V(ChangeTaggedToFloat64) \
V(ChangeFloat64ToTagged) \ V(ChangeInt31ToTaggedSigned) \
V(ChangeTaggedToBit) \ V(ChangeInt32ToTagged) \
V(ChangeBitToTagged) \ V(ChangeUint32ToTagged) \
V(CheckBounds) \ V(ChangeFloat64ToTagged) \
V(CheckedUint32ToInt32) \ V(ChangeTaggedToBit) \
V(CheckedFloat64ToInt32) \ V(ChangeBitToTagged) \
V(CheckedTaggedToInt32) \ V(CheckBounds) \
V(CheckedTaggedToFloat64) \ V(CheckedUint32ToInt32) \
V(CheckFloat64Hole) \ V(CheckedFloat64ToInt32) \
V(CheckTaggedHole) \ V(CheckedTaggedToInt32) \
V(CheckIf) \ V(CheckedTaggedToFloat64) \
V(TruncateTaggedToWord32) \ V(CheckFloat64Hole) \
V(TruncateTaggedToFloat64) \ V(CheckTaggedHole) \
V(Allocate) \ V(CheckIf) \
V(LoadField) \ V(TruncateTaggedToWord32) \
V(LoadBuffer) \ V(TruncateTaggedToFloat64) \
V(LoadElement) \ V(Allocate) \
V(StoreField) \ V(LoadField) \
V(StoreBuffer) \ V(LoadBuffer) \
V(StoreElement) \ V(LoadElement) \
V(ObjectIsCallable) \ V(StoreField) \
V(ObjectIsNumber) \ V(StoreBuffer) \
V(ObjectIsReceiver) \ V(StoreElement) \
V(ObjectIsSmi) \ V(ObjectIsCallable) \
V(ObjectIsString) \ V(ObjectIsNumber) \
V(ObjectIsUndetectable) \ V(ObjectIsReceiver) \
V(ObjectIsSmi) \
V(ObjectIsString) \
V(ObjectIsUndetectable) \
V(TypeGuard) V(TypeGuard)
// Opcodes for Machine-level operators. // Opcodes for Machine-level operators.
......
...@@ -583,10 +583,13 @@ const Operator* RepresentationChanger::Int32OperatorFor( ...@@ -583,10 +583,13 @@ const Operator* RepresentationChanger::Int32OperatorFor(
case IrOpcode::kNumberBitwiseAnd: case IrOpcode::kNumberBitwiseAnd:
return machine()->Word32And(); return machine()->Word32And();
case IrOpcode::kNumberEqual: case IrOpcode::kNumberEqual:
case IrOpcode::kSpeculativeNumberEqual:
return machine()->Word32Equal(); return machine()->Word32Equal();
case IrOpcode::kNumberLessThan: case IrOpcode::kNumberLessThan:
case IrOpcode::kSpeculativeNumberLessThan:
return machine()->Int32LessThan(); return machine()->Int32LessThan();
case IrOpcode::kNumberLessThanOrEqual: case IrOpcode::kNumberLessThanOrEqual:
case IrOpcode::kSpeculativeNumberLessThanOrEqual:
return machine()->Int32LessThanOrEqual(); return machine()->Int32LessThanOrEqual();
default: default:
UNREACHABLE(); UNREACHABLE();
...@@ -621,10 +624,13 @@ const Operator* RepresentationChanger::Uint32OperatorFor( ...@@ -621,10 +624,13 @@ const Operator* RepresentationChanger::Uint32OperatorFor(
case IrOpcode::kNumberModulus: case IrOpcode::kNumberModulus:
return machine()->Uint32Mod(); return machine()->Uint32Mod();
case IrOpcode::kNumberEqual: case IrOpcode::kNumberEqual:
case IrOpcode::kSpeculativeNumberEqual:
return machine()->Word32Equal(); return machine()->Word32Equal();
case IrOpcode::kNumberLessThan: case IrOpcode::kNumberLessThan:
case IrOpcode::kSpeculativeNumberLessThan:
return machine()->Uint32LessThan(); return machine()->Uint32LessThan();
case IrOpcode::kNumberLessThanOrEqual: case IrOpcode::kNumberLessThanOrEqual:
case IrOpcode::kSpeculativeNumberLessThanOrEqual:
return machine()->Uint32LessThanOrEqual(); return machine()->Uint32LessThanOrEqual();
case IrOpcode::kNumberClz32: case IrOpcode::kNumberClz32:
return machine()->Word32Clz(); return machine()->Word32Clz();
...@@ -653,10 +659,13 @@ const Operator* RepresentationChanger::Float64OperatorFor( ...@@ -653,10 +659,13 @@ const Operator* RepresentationChanger::Float64OperatorFor(
case IrOpcode::kNumberModulus: case IrOpcode::kNumberModulus:
return machine()->Float64Mod(); return machine()->Float64Mod();
case IrOpcode::kNumberEqual: case IrOpcode::kNumberEqual:
case IrOpcode::kSpeculativeNumberEqual:
return machine()->Float64Equal(); return machine()->Float64Equal();
case IrOpcode::kNumberLessThan: case IrOpcode::kNumberLessThan:
case IrOpcode::kSpeculativeNumberLessThan:
return machine()->Float64LessThan(); return machine()->Float64LessThan();
case IrOpcode::kNumberLessThanOrEqual: case IrOpcode::kNumberLessThanOrEqual:
case IrOpcode::kSpeculativeNumberLessThanOrEqual:
return machine()->Float64LessThanOrEqual(); return machine()->Float64LessThanOrEqual();
case IrOpcode::kNumberAtan: case IrOpcode::kNumberAtan:
return machine()->Float64Atan(); return machine()->Float64Atan();
......
...@@ -1040,7 +1040,6 @@ class RepresentationSelector { ...@@ -1040,7 +1040,6 @@ class RepresentationSelector {
Node* overflow = graph()->NewNode(common()->Projection(1), arith); Node* overflow = graph()->NewNode(common()->Projection(1), arith);
effect = effect =
graph()->NewNode(simplified()->CheckIf(), overflow, effect, control); graph()->NewNode(simplified()->CheckIf(), overflow, effect, control);
Node* value = graph()->NewNode(common()->Projection(0), arith); Node* value = graph()->NewNode(common()->Projection(0), arith);
ReplaceEffectControlUses(node, effect, control); ReplaceEffectControlUses(node, effect, control);
DeferReplacement(node, value); DeferReplacement(node, value);
...@@ -1219,11 +1218,13 @@ class RepresentationSelector { ...@@ -1219,11 +1218,13 @@ class RepresentationSelector {
case IrOpcode::kNumberLessThan: case IrOpcode::kNumberLessThan:
case IrOpcode::kNumberLessThanOrEqual: { case IrOpcode::kNumberLessThanOrEqual: {
// Number comparisons reduce to integer comparisons for integer inputs. // Number comparisons reduce to integer comparisons for integer inputs.
if (BothInputsAreSigned32(node)) { if (TypeOf(node->InputAt(0))->Is(Type::Signed32()) &&
TypeOf(node->InputAt(1))->Is(Type::Signed32())) {
// => signed Int32Cmp // => signed Int32Cmp
VisitInt32Cmp(node); VisitInt32Cmp(node);
if (lower()) NodeProperties::ChangeOp(node, Int32Op(node)); if (lower()) NodeProperties::ChangeOp(node, Int32Op(node));
} else if (BothInputsAreUnsigned32(node)) { } else if (TypeOf(node->InputAt(0))->Is(Type::Unsigned32()) &&
TypeOf(node->InputAt(1))->Is(Type::Unsigned32())) {
// => unsigned Int32Cmp // => unsigned Int32Cmp
VisitUint32Cmp(node); VisitUint32Cmp(node);
if (lower()) NodeProperties::ChangeOp(node, Uint32Op(node)); if (lower()) NodeProperties::ChangeOp(node, Uint32Op(node));
...@@ -1239,6 +1240,40 @@ class RepresentationSelector { ...@@ -1239,6 +1240,40 @@ class RepresentationSelector {
case IrOpcode::kSpeculativeNumberSubtract: case IrOpcode::kSpeculativeNumberSubtract:
return VisitSpeculativeAdditiveOp(node, truncation, lowering); return VisitSpeculativeAdditiveOp(node, truncation, lowering);
case IrOpcode::kSpeculativeNumberLessThan:
case IrOpcode::kSpeculativeNumberLessThanOrEqual:
case IrOpcode::kSpeculativeNumberEqual: {
// Number comparisons reduce to integer comparisons for integer inputs.
if (TypeOf(node->InputAt(0))->Is(Type::Signed32()) &&
TypeOf(node->InputAt(1))->Is(Type::Signed32())) {
// => signed Int32Cmp
VisitInt32Cmp(node);
if (lower()) ChangeToPureOp(node, Int32Op(node));
return;
} else if (TypeOf(node->InputAt(0))->Is(Type::Unsigned32()) &&
TypeOf(node->InputAt(1))->Is(Type::Unsigned32())) {
// => unsigned Int32Cmp
VisitUint32Cmp(node);
if (lower()) ChangeToPureOp(node, Uint32Op(node));
return;
}
// Try to use type feedback.
CompareOperationHints::Hint hint = CompareOperationHintOf(node->op());
if (hint == CompareOperationHints::kSignedSmall) {
VisitBinop(node, UseInfo::CheckedSigned32AsWord32(),
MachineRepresentation::kBit);
if (lower()) ChangeToPureOp(node, Int32Op(node));
return;
}
DCHECK_EQ(CompareOperationHints::kNumber, hint);
// default case => Float64 comparison
VisitBinop(node, UseInfo::CheckedNumberOrUndefinedAsFloat64(),
MachineRepresentation::kBit);
if (lower()) ChangeToPureOp(node, Float64Op(node));
return;
}
case IrOpcode::kNumberAdd: case IrOpcode::kNumberAdd:
case IrOpcode::kNumberSubtract: { case IrOpcode::kNumberSubtract: {
if (BothInputsAre(node, Type::Signed32()) && if (BothInputsAre(node, Type::Signed32()) &&
......
...@@ -223,6 +223,13 @@ BinaryOperationHints::Hint BinaryOperationHintOf(const Operator* op) { ...@@ -223,6 +223,13 @@ BinaryOperationHints::Hint BinaryOperationHintOf(const Operator* op) {
return OpParameter<BinaryOperationHints::Hint>(op); return OpParameter<BinaryOperationHints::Hint>(op);
} }
CompareOperationHints::Hint CompareOperationHintOf(const Operator* op) {
DCHECK(op->opcode() == IrOpcode::kSpeculativeNumberEqual ||
op->opcode() == IrOpcode::kSpeculativeNumberLessThan ||
op->opcode() == IrOpcode::kSpeculativeNumberLessThanOrEqual);
return OpParameter<CompareOperationHints::Hint>(op);
}
#define PURE_OP_LIST(V) \ #define PURE_OP_LIST(V) \
V(BooleanNot, Operator::kNoProperties, 1) \ V(BooleanNot, Operator::kNoProperties, 1) \
V(BooleanToNumber, Operator::kNoProperties, 1) \ V(BooleanToNumber, Operator::kNoProperties, 1) \
...@@ -497,6 +504,27 @@ const Operator* SimplifiedOperatorBuilder::SpeculativeNumberSubtract( ...@@ -497,6 +504,27 @@ const Operator* SimplifiedOperatorBuilder::SpeculativeNumberSubtract(
"SpeculativeNumberSubtract", 2, 1, 1, 1, 1, 1, hint); "SpeculativeNumberSubtract", 2, 1, 1, 1, 1, 1, hint);
} }
const Operator* SimplifiedOperatorBuilder::SpeculativeNumberEqual(
CompareOperationHints::Hint hint) {
return new (zone()) Operator1<CompareOperationHints::Hint>(
IrOpcode::kSpeculativeNumberEqual, Operator::kPure,
"SpeculativeNumberEqual", 2, 1, 1, 1, 1, 1, hint);
}
const Operator* SimplifiedOperatorBuilder::SpeculativeNumberLessThan(
CompareOperationHints::Hint hint) {
return new (zone()) Operator1<CompareOperationHints::Hint>(
IrOpcode::kSpeculativeNumberLessThan, Operator::kPure,
"SpeculativeNumberLessThan", 2, 1, 1, 1, 1, 1, hint);
}
const Operator* SimplifiedOperatorBuilder::SpeculativeNumberLessThanOrEqual(
CompareOperationHints::Hint hint) {
return new (zone()) Operator1<CompareOperationHints::Hint>(
IrOpcode::kSpeculativeNumberLessThanOrEqual, Operator::kPure,
"SpeculativeNumberLessThanOrEqual", 2, 1, 1, 1, 1, 1, hint);
}
#define ACCESS_OP_LIST(V) \ #define ACCESS_OP_LIST(V) \
V(LoadField, FieldAccess, Operator::kNoWrite, 1, 1, 1) \ V(LoadField, FieldAccess, Operator::kNoWrite, 1, 1, 1) \
V(StoreField, FieldAccess, Operator::kNoRead, 2, 1, 0) \ V(StoreField, FieldAccess, Operator::kNoRead, 2, 1, 0) \
......
...@@ -129,6 +129,8 @@ Type* TypeOf(const Operator* op) WARN_UNUSED_RESULT; ...@@ -129,6 +129,8 @@ Type* TypeOf(const Operator* op) WARN_UNUSED_RESULT;
BinaryOperationHints::Hint BinaryOperationHintOf(const Operator* op); BinaryOperationHints::Hint BinaryOperationHintOf(const Operator* op);
CompareOperationHints::Hint CompareOperationHintOf(const Operator* op);
// Interface for building simplified operators, which represent the // Interface for building simplified operators, which represent the
// medium-level operations of V8, including adding numbers, allocating objects, // medium-level operations of V8, including adding numbers, allocating objects,
// indexing into objects and arrays, etc. // indexing into objects and arrays, etc.
...@@ -192,6 +194,11 @@ class SimplifiedOperatorBuilder final : public ZoneObject { ...@@ -192,6 +194,11 @@ class SimplifiedOperatorBuilder final : public ZoneObject {
const Operator* SpeculativeNumberAdd(BinaryOperationHints::Hint hint); const Operator* SpeculativeNumberAdd(BinaryOperationHints::Hint hint);
const Operator* SpeculativeNumberSubtract(BinaryOperationHints::Hint hint); const Operator* SpeculativeNumberSubtract(BinaryOperationHints::Hint hint);
const Operator* SpeculativeNumberLessThan(CompareOperationHints::Hint hint);
const Operator* SpeculativeNumberLessThanOrEqual(
CompareOperationHints::Hint hint);
const Operator* SpeculativeNumberEqual(CompareOperationHints::Hint hint);
const Operator* ReferenceEqual(Type* type); const Operator* ReferenceEqual(Type* type);
const Operator* StringEqual(); const Operator* StringEqual();
......
...@@ -16,7 +16,7 @@ namespace compiler { ...@@ -16,7 +16,7 @@ namespace compiler {
namespace { namespace {
// TODO(bmeurer): This detour via types is ugly. // TODO(bmeurer): This detour via types is ugly.
BinaryOperationHints::Hint ToHint(Type* type) { BinaryOperationHints::Hint ToBinaryOperationHint(Type* type) {
if (type->Is(Type::None())) return BinaryOperationHints::kNone; if (type->Is(Type::None())) return BinaryOperationHints::kNone;
if (type->Is(Type::SignedSmall())) return BinaryOperationHints::kSignedSmall; if (type->Is(Type::SignedSmall())) return BinaryOperationHints::kSignedSmall;
if (type->Is(Type::Signed32())) return BinaryOperationHints::kSigned32; if (type->Is(Type::Signed32())) return BinaryOperationHints::kSigned32;
...@@ -25,8 +25,34 @@ BinaryOperationHints::Hint ToHint(Type* type) { ...@@ -25,8 +25,34 @@ BinaryOperationHints::Hint ToHint(Type* type) {
return BinaryOperationHints::kAny; return BinaryOperationHints::kAny;
} }
} // namespace CompareOperationHints::Hint ToCompareOperationHint(
CompareICState::State state) {
switch (state) {
case CompareICState::UNINITIALIZED:
return CompareOperationHints::kNone;
case CompareICState::BOOLEAN:
return CompareOperationHints::kBoolean;
case CompareICState::SMI:
return CompareOperationHints::kSignedSmall;
case CompareICState::NUMBER:
return CompareOperationHints::kNumber;
case CompareICState::STRING:
return CompareOperationHints::kString;
case CompareICState::INTERNALIZED_STRING:
return CompareOperationHints::kInternalizedString;
case CompareICState::UNIQUE_NAME:
return CompareOperationHints::kUniqueName;
case CompareICState::RECEIVER:
case CompareICState::KNOWN_RECEIVER:
return CompareOperationHints::kReceiver;
case CompareICState::GENERIC:
return CompareOperationHints::kAny;
}
UNREACHABLE();
return CompareOperationHints::kAny;
}
} // namespace
bool TypeHintAnalysis::GetBinaryOperationHints( bool TypeHintAnalysis::GetBinaryOperationHints(
TypeFeedbackId id, BinaryOperationHints* hints) const { TypeFeedbackId id, BinaryOperationHints* hints) const {
...@@ -35,12 +61,29 @@ bool TypeHintAnalysis::GetBinaryOperationHints( ...@@ -35,12 +61,29 @@ bool TypeHintAnalysis::GetBinaryOperationHints(
Handle<Code> code = i->second; Handle<Code> code = i->second;
DCHECK_EQ(Code::BINARY_OP_IC, code->kind()); DCHECK_EQ(Code::BINARY_OP_IC, code->kind());
BinaryOpICState state(code->GetIsolate(), code->extra_ic_state()); BinaryOpICState state(code->GetIsolate(), code->extra_ic_state());
*hints = BinaryOperationHints(ToHint(state.GetLeftType()), *hints = BinaryOperationHints(ToBinaryOperationHint(state.GetLeftType()),
ToHint(state.GetRightType()), ToBinaryOperationHint(state.GetRightType()),
ToHint(state.GetResultType())); ToBinaryOperationHint(state.GetResultType()));
return true; return true;
} }
bool TypeHintAnalysis::GetCompareOperationHints(
TypeFeedbackId id, CompareOperationHints* hints) const {
auto i = infos_.find(id);
if (i == infos_.end()) return false;
Handle<Code> code = i->second;
DCHECK_EQ(Code::COMPARE_IC, code->kind());
Handle<Map> map;
Map* raw_map = code->FindFirstMap();
if (raw_map != nullptr) Map::TryUpdate(handle(raw_map)).ToHandle(&map);
CompareICStub stub(code->stub_key(), code->GetIsolate());
*hints = CompareOperationHints(ToCompareOperationHint(stub.left()),
ToCompareOperationHint(stub.right()),
ToCompareOperationHint(stub.state()));
return true;
}
bool TypeHintAnalysis::GetToBooleanHints(TypeFeedbackId id, bool TypeHintAnalysis::GetToBooleanHints(TypeFeedbackId id,
ToBooleanHints* hints) const { ToBooleanHints* hints) const {
...@@ -67,7 +110,6 @@ bool TypeHintAnalysis::GetToBooleanHints(TypeFeedbackId id, ...@@ -67,7 +110,6 @@ bool TypeHintAnalysis::GetToBooleanHints(TypeFeedbackId id,
return true; return true;
} }
TypeHintAnalysis* TypeHintAnalyzer::Analyze(Handle<Code> code) { TypeHintAnalysis* TypeHintAnalyzer::Analyze(Handle<Code> code) {
DisallowHeapAllocation no_gc; DisallowHeapAllocation no_gc;
TypeHintAnalysis::Infos infos(zone()); TypeHintAnalysis::Infos infos(zone());
...@@ -79,6 +121,7 @@ TypeHintAnalysis* TypeHintAnalyzer::Analyze(Handle<Code> code) { ...@@ -79,6 +121,7 @@ TypeHintAnalysis* TypeHintAnalyzer::Analyze(Handle<Code> code) {
Code* target = Code::GetCodeFromTargetAddress(target_address); Code* target = Code::GetCodeFromTargetAddress(target_address);
switch (target->kind()) { switch (target->kind()) {
case Code::BINARY_OP_IC: case Code::BINARY_OP_IC:
case Code::COMPARE_IC:
case Code::TO_BOOLEAN_IC: { case Code::TO_BOOLEAN_IC: {
// Add this feedback to the {infos}. // Add this feedback to the {infos}.
TypeFeedbackId id(static_cast<unsigned>(rinfo->data())); TypeFeedbackId id(static_cast<unsigned>(rinfo->data()));
...@@ -90,7 +133,7 @@ TypeHintAnalysis* TypeHintAnalyzer::Analyze(Handle<Code> code) { ...@@ -90,7 +133,7 @@ TypeHintAnalysis* TypeHintAnalyzer::Analyze(Handle<Code> code) {
break; break;
} }
} }
return new (zone()) TypeHintAnalysis(infos); return new (zone()) TypeHintAnalysis(infos, zone());
} }
} // namespace compiler } // namespace compiler
......
...@@ -18,14 +18,20 @@ class TypeHintAnalysis final : public ZoneObject { ...@@ -18,14 +18,20 @@ class TypeHintAnalysis final : public ZoneObject {
public: public:
typedef ZoneMap<TypeFeedbackId, Handle<Code>> Infos; typedef ZoneMap<TypeFeedbackId, Handle<Code>> Infos;
explicit TypeHintAnalysis(Infos const& infos) : infos_(infos) {} explicit TypeHintAnalysis(Infos const& infos, Zone* zone)
: infos_(infos), zone_(zone) {}
bool GetBinaryOperationHints(TypeFeedbackId id, bool GetBinaryOperationHints(TypeFeedbackId id,
BinaryOperationHints* hints) const; BinaryOperationHints* hints) const;
bool GetCompareOperationHints(TypeFeedbackId id,
CompareOperationHints* hints) const;
bool GetToBooleanHints(TypeFeedbackId id, ToBooleanHints* hints) const; bool GetToBooleanHints(TypeFeedbackId id, ToBooleanHints* hints) const;
private: private:
Zone* zone() const { return zone_; }
Infos const infos_; Infos const infos_;
Zone* zone_;
}; };
......
...@@ -27,11 +27,39 @@ std::ostream& operator<<(std::ostream& os, BinaryOperationHints::Hint hint) { ...@@ -27,11 +27,39 @@ std::ostream& operator<<(std::ostream& os, BinaryOperationHints::Hint hint) {
return os; return os;
} }
std::ostream& operator<<(std::ostream& os, BinaryOperationHints hints) { std::ostream& operator<<(std::ostream& os, BinaryOperationHints hints) {
return os << hints.left() << "*" << hints.right() << "->" << hints.result(); return os << hints.left() << "*" << hints.right() << "->" << hints.result();
} }
std::ostream& operator<<(std::ostream& os, CompareOperationHints::Hint hint) {
switch (hint) {
case CompareOperationHints::kNone:
return os << "None";
case CompareOperationHints::kBoolean:
return os << "Boolean";
case CompareOperationHints::kSignedSmall:
return os << "SignedSmall";
case CompareOperationHints::kNumber:
return os << "Number";
case CompareOperationHints::kString:
return os << "String";
case CompareOperationHints::kInternalizedString:
return os << "InternalizedString";
case CompareOperationHints::kUniqueName:
return os << "UniqueName";
case CompareOperationHints::kReceiver:
return os << "Receiver";
case CompareOperationHints::kAny:
return os << "Any";
}
UNREACHABLE();
return os;
}
std::ostream& operator<<(std::ostream& os, CompareOperationHints hints) {
return os << hints.left() << "*" << hints.right() << " (" << hints.combined()
<< ")";
}
std::ostream& operator<<(std::ostream& os, ToBooleanHint hint) { std::ostream& operator<<(std::ostream& os, ToBooleanHint hint) {
switch (hint) { switch (hint) {
...@@ -62,7 +90,6 @@ std::ostream& operator<<(std::ostream& os, ToBooleanHint hint) { ...@@ -62,7 +90,6 @@ std::ostream& operator<<(std::ostream& os, ToBooleanHint hint) {
return os; return os;
} }
std::ostream& operator<<(std::ostream& os, ToBooleanHints hints) { std::ostream& operator<<(std::ostream& os, ToBooleanHints hints) {
if (hints == ToBooleanHint::kAny) return os << "Any"; if (hints == ToBooleanHint::kAny) return os << "Any";
if (hints == ToBooleanHint::kNone) return os << "None"; if (hints == ToBooleanHint::kNone) return os << "None";
......
...@@ -64,6 +64,55 @@ class BinaryOperationHints final { ...@@ -64,6 +64,55 @@ class BinaryOperationHints final {
std::ostream& operator<<(std::ostream&, BinaryOperationHints::Hint); std::ostream& operator<<(std::ostream&, BinaryOperationHints::Hint);
std::ostream& operator<<(std::ostream&, BinaryOperationHints); std::ostream& operator<<(std::ostream&, BinaryOperationHints);
// Type hints for an binary operation.
class CompareOperationHints final {
public:
enum Hint {
kNone,
kBoolean,
kSignedSmall,
kNumber,
kString,
kInternalizedString,
kUniqueName,
kReceiver,
kAny
};
CompareOperationHints() : CompareOperationHints(kNone, kNone, kNone) {}
CompareOperationHints(Hint left, Hint right, Hint combined)
: bit_field_(LeftField::encode(left) | RightField::encode(right) |
CombinedField::encode(combined)) {}
static CompareOperationHints Any() {
return CompareOperationHints(kAny, kAny, kAny);
}
Hint left() const { return LeftField::decode(bit_field_); }
Hint right() const { return RightField::decode(bit_field_); }
Hint combined() const { return CombinedField::decode(bit_field_); }
bool operator==(CompareOperationHints const& that) const {
return this->bit_field_ == that.bit_field_;
}
bool operator!=(CompareOperationHints const& that) const {
return !(*this == that);
}
friend size_t hash_value(CompareOperationHints const& hints) {
return hints.bit_field_;
}
private:
typedef BitField<Hint, 0, 4> LeftField;
typedef BitField<Hint, 4, 4> RightField;
typedef BitField<Hint, 8, 4> CombinedField;
uint32_t bit_field_;
};
std::ostream& operator<<(std::ostream&, CompareOperationHints::Hint);
std::ostream& operator<<(std::ostream&, CompareOperationHints);
// Type hints for the ToBoolean type conversion. // Type hints for the ToBoolean type conversion.
enum class ToBooleanHint : uint16_t { enum class ToBooleanHint : uint16_t {
......
...@@ -873,7 +873,6 @@ Type* Typer::Visitor::JSGreaterThanOrEqualTyper( ...@@ -873,7 +873,6 @@ Type* Typer::Visitor::JSGreaterThanOrEqualTyper(
return FalsifyUndefined(Invert(JSCompareTyper(lhs, rhs, t), t), t); return FalsifyUndefined(Invert(JSCompareTyper(lhs, rhs, t), t), t);
} }
// JS bitwise operators. // JS bitwise operators.
...@@ -1710,6 +1709,18 @@ Type* Typer::Visitor::TypeNumberLessThanOrEqual(Node* node) { ...@@ -1710,6 +1709,18 @@ Type* Typer::Visitor::TypeNumberLessThanOrEqual(Node* node) {
return Type::Boolean(); return Type::Boolean();
} }
Type* Typer::Visitor::TypeSpeculativeNumberEqual(Node* node) {
return Type::Boolean();
}
Type* Typer::Visitor::TypeSpeculativeNumberLessThan(Node* node) {
return Type::Boolean();
}
Type* Typer::Visitor::TypeSpeculativeNumberLessThanOrEqual(Node* node) {
return Type::Boolean();
}
Type* Typer::Visitor::TypeNumberAdd(Node* node) { return Type::Number(); } Type* Typer::Visitor::TypeNumberAdd(Node* node) { return Type::Number(); }
Type* Typer::Visitor::TypeNumberSubtract(Node* node) { return Type::Number(); } Type* Typer::Visitor::TypeNumberSubtract(Node* node) { return Type::Number(); }
......
...@@ -689,6 +689,12 @@ void Verifier::Visitor::Check(Node* node) { ...@@ -689,6 +689,12 @@ void Verifier::Visitor::Check(Node* node) {
break; break;
case IrOpcode::kSpeculativeNumberAdd: case IrOpcode::kSpeculativeNumberAdd:
case IrOpcode::kSpeculativeNumberSubtract: case IrOpcode::kSpeculativeNumberSubtract:
CheckUpperIs(node, Type::Number());
break;
case IrOpcode::kSpeculativeNumberEqual:
case IrOpcode::kSpeculativeNumberLessThan:
case IrOpcode::kSpeculativeNumberLessThanOrEqual:
CheckUpperIs(node, Type::Boolean());
break; break;
case IrOpcode::kNumberAdd: case IrOpcode::kNumberAdd:
case IrOpcode::kNumberSubtract: case IrOpcode::kNumberSubtract:
......
...@@ -47,7 +47,8 @@ class JSTypedLoweringTester : public HandleAndZoneScope { ...@@ -47,7 +47,8 @@ class JSTypedLoweringTester : public HandleAndZoneScope {
Graph graph; Graph graph;
Typer typer; Typer typer;
Node* context_node; Node* context_node;
BinaryOperationHints const hints = BinaryOperationHints::Any(); BinaryOperationHints const binop_hints = BinaryOperationHints::Any();
CompareOperationHints const compare_hints = CompareOperationHints::Any();
Node* Parameter(Type* t, int32_t index = 0) { Node* Parameter(Type* t, int32_t index = 0) {
Node* n = graph.NewNode(common.Parameter(index), graph.start()); Node* n = graph.NewNode(common.Parameter(index), graph.start());
...@@ -255,11 +256,11 @@ TEST(AddNumber1) { ...@@ -255,11 +256,11 @@ TEST(AddNumber1) {
TEST(NumberBinops) { TEST(NumberBinops) {
JSTypedLoweringTester R; JSTypedLoweringTester R;
const Operator* ops[] = { const Operator* ops[] = {
R.javascript.Add(R.hints), R.simplified.NumberAdd(), R.javascript.Add(R.binop_hints), R.simplified.NumberAdd(),
R.javascript.Subtract(R.hints), R.simplified.NumberSubtract(), R.javascript.Subtract(R.binop_hints), R.simplified.NumberSubtract(),
R.javascript.Multiply(R.hints), R.simplified.NumberMultiply(), R.javascript.Multiply(R.binop_hints), R.simplified.NumberMultiply(),
R.javascript.Divide(R.hints), R.simplified.NumberDivide(), R.javascript.Divide(R.binop_hints), R.simplified.NumberDivide(),
R.javascript.Modulus(R.hints), R.simplified.NumberModulus(), R.javascript.Modulus(R.binop_hints), R.simplified.NumberModulus(),
}; };
for (size_t i = 0; i < arraysize(kNumberTypes); ++i) { for (size_t i = 0; i < arraysize(kNumberTypes); ++i) {
...@@ -301,11 +302,11 @@ class JSBitwiseShiftTypedLoweringTester : public JSTypedLoweringTester { ...@@ -301,11 +302,11 @@ class JSBitwiseShiftTypedLoweringTester : public JSTypedLoweringTester {
public: public:
JSBitwiseShiftTypedLoweringTester() : JSTypedLoweringTester() { JSBitwiseShiftTypedLoweringTester() : JSTypedLoweringTester() {
int i = 0; int i = 0;
set(i++, javascript.ShiftLeft(hints), true); set(i++, javascript.ShiftLeft(binop_hints), true);
set(i++, simplified.NumberShiftLeft(), false); set(i++, simplified.NumberShiftLeft(), false);
set(i++, javascript.ShiftRight(hints), true); set(i++, javascript.ShiftRight(binop_hints), true);
set(i++, simplified.NumberShiftRight(), false); set(i++, simplified.NumberShiftRight(), false);
set(i++, javascript.ShiftRightLogical(hints), false); set(i++, javascript.ShiftRightLogical(binop_hints), false);
set(i++, simplified.NumberShiftRightLogical(), false); set(i++, simplified.NumberShiftRightLogical(), false);
} }
static const int kNumberOps = 6; static const int kNumberOps = 6;
...@@ -357,11 +358,11 @@ class JSBitwiseTypedLoweringTester : public JSTypedLoweringTester { ...@@ -357,11 +358,11 @@ class JSBitwiseTypedLoweringTester : public JSTypedLoweringTester {
public: public:
JSBitwiseTypedLoweringTester() : JSTypedLoweringTester() { JSBitwiseTypedLoweringTester() : JSTypedLoweringTester() {
int i = 0; int i = 0;
set(i++, javascript.BitwiseOr(hints), true); set(i++, javascript.BitwiseOr(binop_hints), true);
set(i++, simplified.NumberBitwiseOr(), true); set(i++, simplified.NumberBitwiseOr(), true);
set(i++, javascript.BitwiseXor(hints), true); set(i++, javascript.BitwiseXor(binop_hints), true);
set(i++, simplified.NumberBitwiseXor(), true); set(i++, simplified.NumberBitwiseXor(), true);
set(i++, javascript.BitwiseAnd(hints), true); set(i++, javascript.BitwiseAnd(binop_hints), true);
set(i++, simplified.NumberBitwiseAnd(), true); set(i++, simplified.NumberBitwiseAnd(), true);
} }
static const int kNumberOps = 6; static const int kNumberOps = 6;
...@@ -571,10 +572,14 @@ TEST(StringComparison) { ...@@ -571,10 +572,14 @@ TEST(StringComparison) {
JSTypedLoweringTester R; JSTypedLoweringTester R;
const Operator* ops[] = { const Operator* ops[] = {
R.javascript.LessThan(), R.simplified.StringLessThan(), R.javascript.LessThan(CompareOperationHints::Any()),
R.javascript.LessThanOrEqual(), R.simplified.StringLessThanOrEqual(), R.simplified.StringLessThan(),
R.javascript.GreaterThan(), R.simplified.StringLessThan(), R.javascript.LessThanOrEqual(CompareOperationHints::Any()),
R.javascript.GreaterThanOrEqual(), R.simplified.StringLessThanOrEqual()}; R.simplified.StringLessThanOrEqual(),
R.javascript.GreaterThan(CompareOperationHints::Any()),
R.simplified.StringLessThan(),
R.javascript.GreaterThanOrEqual(CompareOperationHints::Any()),
R.simplified.StringLessThanOrEqual()};
for (size_t i = 0; i < arraysize(kStringTypes); i++) { for (size_t i = 0; i < arraysize(kStringTypes); i++) {
Node* p0 = R.Parameter(kStringTypes[i], 0); Node* p0 = R.Parameter(kStringTypes[i], 0);
...@@ -618,10 +623,14 @@ TEST(NumberComparison) { ...@@ -618,10 +623,14 @@ TEST(NumberComparison) {
JSTypedLoweringTester R; JSTypedLoweringTester R;
const Operator* ops[] = { const Operator* ops[] = {
R.javascript.LessThan(), R.simplified.NumberLessThan(), R.javascript.LessThan(CompareOperationHints::Any()),
R.javascript.LessThanOrEqual(), R.simplified.NumberLessThanOrEqual(), R.simplified.NumberLessThan(),
R.javascript.GreaterThan(), R.simplified.NumberLessThan(), R.javascript.LessThanOrEqual(CompareOperationHints::Any()),
R.javascript.GreaterThanOrEqual(), R.simplified.NumberLessThanOrEqual()}; R.simplified.NumberLessThanOrEqual(),
R.javascript.GreaterThan(CompareOperationHints::Any()),
R.simplified.NumberLessThan(),
R.javascript.GreaterThanOrEqual(CompareOperationHints::Any()),
R.simplified.NumberLessThanOrEqual()};
Node* const p0 = R.Parameter(Type::Number(), 0); Node* const p0 = R.Parameter(Type::Number(), 0);
Node* const p1 = R.Parameter(Type::Number(), 1); Node* const p1 = R.Parameter(Type::Number(), 1);
...@@ -655,7 +664,8 @@ TEST(MixedComparison1) { ...@@ -655,7 +664,8 @@ TEST(MixedComparison1) {
for (size_t j = 0; j < arraysize(types); j++) { for (size_t j = 0; j < arraysize(types); j++) {
Node* p1 = R.Parameter(types[j], 1); Node* p1 = R.Parameter(types[j], 1);
{ {
const Operator* less_than = R.javascript.LessThan(); const Operator* less_than =
R.javascript.LessThan(CompareOperationHints::Any());
Node* cmp = R.Binop(less_than, p0, p1); Node* cmp = R.Binop(less_than, p0, p1);
Node* r = R.reduce(cmp); Node* r = R.reduce(cmp);
if (types[i]->Is(Type::String()) && types[j]->Is(Type::String())) { if (types[i]->Is(Type::String()) && types[j]->Is(Type::String())) {
...@@ -700,14 +710,14 @@ TEST(RemoveToNumberEffects) { ...@@ -700,14 +710,14 @@ TEST(RemoveToNumberEffects) {
case 2: case 2:
effect_use = R.graph.NewNode(R.common.EffectPhi(1), ton, R.start()); effect_use = R.graph.NewNode(R.common.EffectPhi(1), ton, R.start());
case 3: case 3:
effect_use = effect_use = R.graph.NewNode(R.javascript.Add(R.binop_hints), ton, ton,
R.graph.NewNode(R.javascript.Add(R.hints), ton, ton, R.context(), R.context(), frame_state, frame_state, ton,
frame_state, frame_state, ton, R.start()); R.start());
break; break;
case 4: case 4:
effect_use = effect_use = R.graph.NewNode(R.javascript.Add(R.binop_hints), p0, p0,
R.graph.NewNode(R.javascript.Add(R.hints), p0, p0, R.context(), R.context(), frame_state, frame_state, ton,
frame_state, frame_state, ton, R.start()); R.start());
break; break;
case 5: case 5:
effect_use = R.graph.NewNode(R.common.Return(), p0, ton, R.start()); effect_use = R.graph.NewNode(R.common.Return(), p0, ton, R.start());
...@@ -801,7 +811,8 @@ void CheckEqualityReduction(JSTypedLoweringTester* R, bool strict, Node* l, ...@@ -801,7 +811,8 @@ void CheckEqualityReduction(JSTypedLoweringTester* R, bool strict, Node* l,
{ {
const Operator* op = const Operator* op =
strict ? R->javascript.StrictEqual() : R->javascript.Equal(); strict ? R->javascript.StrictEqual(CompareOperationHints::Any())
: R->javascript.Equal(CompareOperationHints::Any());
Node* eq = R->Binop(op, p0, p1); Node* eq = R->Binop(op, p0, p1);
Node* r = R->reduce(eq); Node* r = R->reduce(eq);
R->CheckBinop(expected, r); R->CheckBinop(expected, r);
...@@ -809,7 +820,8 @@ void CheckEqualityReduction(JSTypedLoweringTester* R, bool strict, Node* l, ...@@ -809,7 +820,8 @@ void CheckEqualityReduction(JSTypedLoweringTester* R, bool strict, Node* l,
{ {
const Operator* op = const Operator* op =
strict ? R->javascript.StrictNotEqual() : R->javascript.NotEqual(); strict ? R->javascript.StrictNotEqual(CompareOperationHints::Any())
: R->javascript.NotEqual(CompareOperationHints::Any());
Node* ne = R->Binop(op, p0, p1); Node* ne = R->Binop(op, p0, p1);
Node* n = R->reduce(ne); Node* n = R->reduce(ne);
CHECK_EQ(IrOpcode::kBooleanNot, n->opcode()); CHECK_EQ(IrOpcode::kBooleanNot, n->opcode());
...@@ -876,14 +888,22 @@ TEST(RemovePureNumberBinopEffects) { ...@@ -876,14 +888,22 @@ TEST(RemovePureNumberBinopEffects) {
JSTypedLoweringTester R; JSTypedLoweringTester R;
const Operator* ops[] = { const Operator* ops[] = {
R.javascript.Equal(), R.simplified.NumberEqual(), R.javascript.Equal(R.compare_hints),
R.javascript.Add(R.hints), R.simplified.NumberAdd(), R.simplified.NumberEqual(),
R.javascript.Subtract(R.hints), R.simplified.NumberSubtract(), R.javascript.Add(R.binop_hints),
R.javascript.Multiply(R.hints), R.simplified.NumberMultiply(), R.simplified.NumberAdd(),
R.javascript.Divide(R.hints), R.simplified.NumberDivide(), R.javascript.Subtract(R.binop_hints),
R.javascript.Modulus(R.hints), R.simplified.NumberModulus(), R.simplified.NumberSubtract(),
R.javascript.LessThan(), R.simplified.NumberLessThan(), R.javascript.Multiply(R.binop_hints),
R.javascript.LessThanOrEqual(), R.simplified.NumberLessThanOrEqual(), R.simplified.NumberMultiply(),
R.javascript.Divide(R.binop_hints),
R.simplified.NumberDivide(),
R.javascript.Modulus(R.binop_hints),
R.simplified.NumberModulus(),
R.javascript.LessThan(R.compare_hints),
R.simplified.NumberLessThan(),
R.javascript.LessThanOrEqual(R.compare_hints),
R.simplified.NumberLessThanOrEqual(),
}; };
for (size_t j = 0; j < arraysize(ops); j += 2) { for (size_t j = 0; j < arraysize(ops); j += 2) {
...@@ -904,9 +924,9 @@ TEST(OrderNumberBinopEffects1) { ...@@ -904,9 +924,9 @@ TEST(OrderNumberBinopEffects1) {
JSTypedLoweringTester R; JSTypedLoweringTester R;
const Operator* ops[] = { const Operator* ops[] = {
R.javascript.Subtract(R.hints), R.simplified.NumberSubtract(), R.javascript.Subtract(R.binop_hints), R.simplified.NumberSubtract(),
R.javascript.Multiply(R.hints), R.simplified.NumberMultiply(), R.javascript.Multiply(R.binop_hints), R.simplified.NumberMultiply(),
R.javascript.Divide(R.hints), R.simplified.NumberDivide(), R.javascript.Divide(R.binop_hints), R.simplified.NumberDivide(),
}; };
for (size_t j = 0; j < arraysize(ops); j += 2) { for (size_t j = 0; j < arraysize(ops); j += 2) {
...@@ -929,10 +949,10 @@ TEST(OrderNumberBinopEffects2) { ...@@ -929,10 +949,10 @@ TEST(OrderNumberBinopEffects2) {
JSTypedLoweringTester R; JSTypedLoweringTester R;
const Operator* ops[] = { const Operator* ops[] = {
R.javascript.Add(R.hints), R.simplified.NumberAdd(), R.javascript.Add(R.binop_hints), R.simplified.NumberAdd(),
R.javascript.Subtract(R.hints), R.simplified.NumberSubtract(), R.javascript.Subtract(R.binop_hints), R.simplified.NumberSubtract(),
R.javascript.Multiply(R.hints), R.simplified.NumberMultiply(), R.javascript.Multiply(R.binop_hints), R.simplified.NumberMultiply(),
R.javascript.Divide(R.hints), R.simplified.NumberDivide(), R.javascript.Divide(R.binop_hints), R.simplified.NumberDivide(),
}; };
for (size_t j = 0; j < arraysize(ops); j += 2) { for (size_t j = 0; j < arraysize(ops); j += 2) {
...@@ -967,8 +987,9 @@ TEST(OrderCompareEffects) { ...@@ -967,8 +987,9 @@ TEST(OrderCompareEffects) {
JSTypedLoweringTester R; JSTypedLoweringTester R;
const Operator* ops[] = { const Operator* ops[] = {
R.javascript.GreaterThan(), R.simplified.NumberLessThan(), R.javascript.GreaterThan(R.compare_hints), R.simplified.NumberLessThan(),
R.javascript.GreaterThanOrEqual(), R.simplified.NumberLessThanOrEqual(), R.javascript.GreaterThanOrEqual(R.compare_hints),
R.simplified.NumberLessThanOrEqual(),
}; };
for (size_t j = 0; j < arraysize(ops); j += 2) { for (size_t j = 0; j < arraysize(ops); j += 2) {
...@@ -1178,16 +1199,16 @@ TEST(Int32Comparisons) { ...@@ -1178,16 +1199,16 @@ TEST(Int32Comparisons) {
}; };
Entry ops[] = { Entry ops[] = {
{R.javascript.LessThan(), R.machine.Uint32LessThan(), {R.javascript.LessThan(R.compare_hints), R.machine.Uint32LessThan(),
R.machine.Int32LessThan(), R.simplified.NumberLessThan(), false}, R.machine.Int32LessThan(), R.simplified.NumberLessThan(), false},
{R.javascript.LessThanOrEqual(), R.machine.Uint32LessThanOrEqual(), {R.javascript.LessThanOrEqual(R.compare_hints),
R.machine.Int32LessThanOrEqual(), R.simplified.NumberLessThanOrEqual(), R.machine.Uint32LessThanOrEqual(), R.machine.Int32LessThanOrEqual(),
false}, R.simplified.NumberLessThanOrEqual(), false},
{R.javascript.GreaterThan(), R.machine.Uint32LessThan(), {R.javascript.GreaterThan(R.compare_hints), R.machine.Uint32LessThan(),
R.machine.Int32LessThan(), R.simplified.NumberLessThan(), true}, R.machine.Int32LessThan(), R.simplified.NumberLessThan(), true},
{R.javascript.GreaterThanOrEqual(), R.machine.Uint32LessThanOrEqual(), {R.javascript.GreaterThanOrEqual(R.compare_hints),
R.machine.Int32LessThanOrEqual(), R.simplified.NumberLessThanOrEqual(), R.machine.Uint32LessThanOrEqual(), R.machine.Int32LessThanOrEqual(),
true}}; R.simplified.NumberLessThanOrEqual(), true}};
for (size_t o = 0; o < arraysize(ops); o++) { for (size_t o = 0; o < arraysize(ops); o++) {
for (size_t i = 0; i < arraysize(kNumberTypes); i++) { for (size_t i = 0; i < arraysize(kNumberTypes); i++) {
......
...@@ -40,22 +40,12 @@ const SharedOperator kSharedOperators[] = { ...@@ -40,22 +40,12 @@ const SharedOperator kSharedOperators[] = {
control_input_count, value_output_count, effect_output_count, \ control_input_count, value_output_count, effect_output_count, \
control_output_count \ control_output_count \
} }
SHARED(Equal, Operator::kNoProperties, 2, 1, 1, 1, 1, 1, 2),
SHARED(NotEqual, Operator::kNoProperties, 2, 1, 1, 1, 1, 1, 2),
SHARED(StrictEqual, Operator::kPure, 2, 0, 0, 0, 1, 0, 0),
SHARED(StrictNotEqual, Operator::kPure, 2, 0, 0, 0, 1, 0, 0),
SHARED(LessThan, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2),
SHARED(GreaterThan, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2),
SHARED(LessThanOrEqual, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2),
SHARED(GreaterThanOrEqual, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2),
SHARED(ToNumber, Operator::kNoProperties, 1, 1, 1, 1, 1, 1, 2), SHARED(ToNumber, Operator::kNoProperties, 1, 1, 1, 1, 1, 1, 2),
SHARED(ToString, Operator::kNoProperties, 1, 1, 1, 1, 1, 1, 2), SHARED(ToString, Operator::kNoProperties, 1, 1, 1, 1, 1, 1, 2),
SHARED(ToName, Operator::kNoProperties, 1, 1, 1, 1, 1, 1, 2), SHARED(ToName, Operator::kNoProperties, 1, 1, 1, 1, 1, 1, 2),
SHARED(ToObject, Operator::kFoldable, 1, 1, 1, 1, 1, 1, 2), SHARED(ToObject, Operator::kFoldable, 1, 1, 1, 1, 1, 1, 2),
SHARED(Create, Operator::kEliminatable, 2, 1, 1, 0, 1, 1, 0), SHARED(Create, Operator::kEliminatable, 2, 1, 1, 0, 1, 1, 0),
SHARED(HasProperty, Operator::kNoProperties, 2, 1, 1, 1, 1, 1, 2),
SHARED(TypeOf, Operator::kPure, 1, 0, 0, 0, 1, 0, 0), SHARED(TypeOf, Operator::kPure, 1, 0, 0, 0, 1, 0, 0),
SHARED(InstanceOf, Operator::kNoProperties, 2, 1, 1, 1, 1, 1, 2),
SHARED(CreateWithContext, Operator::kNoProperties, 2, 0, 1, 1, 1, 1, 2), SHARED(CreateWithContext, Operator::kNoProperties, 2, 0, 1, 1, 1, 1, 2),
SHARED(CreateModuleContext, Operator::kNoProperties, 2, 0, 1, 1, 1, 1, 2), SHARED(CreateModuleContext, Operator::kNoProperties, 2, 0, 1, 1, 1, 1, 2),
#undef SHARED #undef SHARED
......
...@@ -384,8 +384,9 @@ TEST_F(JSTypedLoweringTest, JSStrictEqualWithTheHole) { ...@@ -384,8 +384,9 @@ TEST_F(JSTypedLoweringTest, JSStrictEqualWithTheHole) {
Node* const context = UndefinedConstant(); Node* const context = UndefinedConstant();
TRACED_FOREACH(Type*, type, kJSTypes) { TRACED_FOREACH(Type*, type, kJSTypes) {
Node* const lhs = Parameter(type); Node* const lhs = Parameter(type);
Reduction r = Reduce( Reduction r = Reduce(graph()->NewNode(
graph()->NewNode(javascript()->StrictEqual(), lhs, the_hole, context)); javascript()->StrictEqual(CompareOperationHints::Any()), lhs, the_hole,
context));
ASSERT_TRUE(r.Changed()); ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsFalseConstant()); EXPECT_THAT(r.replacement(), IsFalseConstant());
} }
...@@ -396,8 +397,9 @@ TEST_F(JSTypedLoweringTest, JSStrictEqualWithUnique) { ...@@ -396,8 +397,9 @@ TEST_F(JSTypedLoweringTest, JSStrictEqualWithUnique) {
Node* const lhs = Parameter(Type::Unique(), 0); Node* const lhs = Parameter(Type::Unique(), 0);
Node* const rhs = Parameter(Type::Unique(), 1); Node* const rhs = Parameter(Type::Unique(), 1);
Node* const context = Parameter(Type::Any(), 2); Node* const context = Parameter(Type::Any(), 2);
Reduction r = Reduction r = Reduce(
Reduce(graph()->NewNode(javascript()->StrictEqual(), lhs, rhs, context)); graph()->NewNode(javascript()->StrictEqual(CompareOperationHints::Any()),
lhs, rhs, context));
ASSERT_TRUE(r.Changed()); ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsReferenceEqual(Type::Unique(), lhs, rhs)); EXPECT_THAT(r.replacement(), IsReferenceEqual(Type::Unique(), lhs, rhs));
} }
......
...@@ -290,44 +290,51 @@ TEST_F(TyperTest, TypeJSShiftRight) { ...@@ -290,44 +290,51 @@ TEST_F(TyperTest, TypeJSShiftRight) {
TEST_F(TyperTest, TypeJSLessThan) { TEST_F(TyperTest, TypeJSLessThan) {
TestBinaryCompareOp(javascript_.LessThan(), std::less<double>()); TestBinaryCompareOp(javascript_.LessThan(CompareOperationHints::Any()),
std::less<double>());
} }
TEST_F(TyperTest, TypeJSLessThanOrEqual) { TEST_F(TyperTest, TypeJSLessThanOrEqual) {
TestBinaryCompareOp(javascript_.LessThanOrEqual(), std::less_equal<double>()); TestBinaryCompareOp(javascript_.LessThanOrEqual(CompareOperationHints::Any()),
std::less_equal<double>());
} }
TEST_F(TyperTest, TypeJSGreaterThan) { TEST_F(TyperTest, TypeJSGreaterThan) {
TestBinaryCompareOp(javascript_.GreaterThan(), std::greater<double>()); TestBinaryCompareOp(javascript_.GreaterThan(CompareOperationHints::Any()),
std::greater<double>());
} }
TEST_F(TyperTest, TypeJSGreaterThanOrEqual) { TEST_F(TyperTest, TypeJSGreaterThanOrEqual) {
TestBinaryCompareOp(javascript_.GreaterThanOrEqual(), TestBinaryCompareOp(
std::greater_equal<double>()); javascript_.GreaterThanOrEqual(CompareOperationHints::Any()),
std::greater_equal<double>());
} }
TEST_F(TyperTest, TypeJSEqual) { TEST_F(TyperTest, TypeJSEqual) {
TestBinaryCompareOp(javascript_.Equal(), std::equal_to<double>()); TestBinaryCompareOp(javascript_.Equal(CompareOperationHints::Any()),
std::equal_to<double>());
} }
TEST_F(TyperTest, TypeJSNotEqual) { TEST_F(TyperTest, TypeJSNotEqual) {
TestBinaryCompareOp(javascript_.NotEqual(), std::not_equal_to<double>()); TestBinaryCompareOp(javascript_.NotEqual(CompareOperationHints::Any()),
std::not_equal_to<double>());
} }
// For numbers there's no difference between strict and non-strict equality. // For numbers there's no difference between strict and non-strict equality.
TEST_F(TyperTest, TypeJSStrictEqual) { TEST_F(TyperTest, TypeJSStrictEqual) {
TestBinaryCompareOp(javascript_.StrictEqual(), std::equal_to<double>()); TestBinaryCompareOp(javascript_.StrictEqual(CompareOperationHints::Any()),
std::equal_to<double>());
} }
TEST_F(TyperTest, TypeJSStrictNotEqual) { TEST_F(TyperTest, TypeJSStrictNotEqual) {
TestBinaryCompareOp(javascript_.StrictNotEqual(), TestBinaryCompareOp(javascript_.StrictNotEqual(CompareOperationHints::Any()),
std::not_equal_to<double>()); std::not_equal_to<double>());
} }
...@@ -335,10 +342,9 @@ TEST_F(TyperTest, TypeJSStrictNotEqual) { ...@@ -335,10 +342,9 @@ TEST_F(TyperTest, TypeJSStrictNotEqual) {
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Monotonicity // Monotonicity
#define TEST_BINARY_MONOTONICITY(name) \
#define TEST_BINARY_MONOTONICITY(name) \ TEST_F(TyperTest, Monotonicity_##name) { \
TEST_F(TyperTest, Monotonicity_##name) { \ TestBinaryMonotonicity(javascript_.name(CompareOperationHints::Any())); \
TestBinaryMonotonicity(javascript_.name()); \
} }
TEST_BINARY_MONOTONICITY(Equal) TEST_BINARY_MONOTONICITY(Equal)
TEST_BINARY_MONOTONICITY(NotEqual) TEST_BINARY_MONOTONICITY(NotEqual)
......
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