Commit 216bcf9f authored by jarin's avatar jarin Committed by Commit bot

[turbofan] Initial version of number type feedback.

This introduces optimized number operations based on type feedback.

Summary of changes:

1. Typed lowering produces SpeculativeNumberAdd/Subtract for JSAdd/Subtract if
   there is suitable feedback. The speculative nodes are connected to both the
   effect chain and the control chain and they retain the eager frame state.

2. Simplified lowering now executes in three phases:
  a. Propagation phase computes truncations by traversing the graph from uses to
     definitions until checkpoint is reached. It also records type-check decisions
     for later typing phase, and computes representation.
  b. The typing phase computes more precise types base on the speculative types (and recomputes
     representation for affected nodes).
  c. The lowering phase performs lowering and inserts representation changes and/or checks.

3. Effect-control linearization lowers the checks to machine graphs.

Notes:

- SimplifiedLowering will be refactored to have handling of each operation one place and
  with clearer input/output protocol for each sub-phase. I would prefer to do this once
  we have more operations implemented, and the pattern is clearer.

- The check operations (Checked<A>To<B>) should have some flags that would affect
  the kind of truncations that they can handle. E.g., if we know that a node produces
  a number, we can omit the oddball check in the CheckedTaggedToFloat64 lowering.

- In future, we want the typer to reuse the logic from OperationTyper.

BUG=v8:4583
LOG=n

Review-Url: https://codereview.chromium.org/1921563002
Cr-Commit-Position: refs/heads/master@{#36674}
parent a8f57df4
...@@ -964,6 +964,8 @@ v8_source_set("v8_base") { ...@@ -964,6 +964,8 @@ v8_source_set("v8_base") {
"src/compiler/node.h", "src/compiler/node.h",
"src/compiler/opcodes.cc", "src/compiler/opcodes.cc",
"src/compiler/opcodes.h", "src/compiler/opcodes.h",
"src/compiler/operation-typer.cc",
"src/compiler/operation-typer.h",
"src/compiler/operator-properties.cc", "src/compiler/operator-properties.cc",
"src/compiler/operator-properties.h", "src/compiler/operator-properties.h",
"src/compiler/operator.cc", "src/compiler/operator.cc",
......
...@@ -146,6 +146,7 @@ class CompilationInfo final { ...@@ -146,6 +146,7 @@ class CompilationInfo final {
kSourcePositionsEnabled = 1 << 15, kSourcePositionsEnabled = 1 << 15,
kBailoutOnUninitialized = 1 << 16, kBailoutOnUninitialized = 1 << 16,
kOptimizeFromBytecode = 1 << 17, kOptimizeFromBytecode = 1 << 17,
kTypeFeedbackEnabled = 1 << 18,
}; };
CompilationInfo(ParseInfo* parse_info, Handle<JSFunction> closure); CompilationInfo(ParseInfo* parse_info, Handle<JSFunction> closure);
...@@ -256,6 +257,12 @@ class CompilationInfo final { ...@@ -256,6 +257,12 @@ class CompilationInfo final {
return GetFlag(kDeoptimizationEnabled); return GetFlag(kDeoptimizationEnabled);
} }
void MarkAsTypeFeedbackEnabled() { SetFlag(kTypeFeedbackEnabled); }
bool is_type_feedback_enabled() const {
return GetFlag(kTypeFeedbackEnabled);
}
void MarkAsSourcePositionsEnabled() { SetFlag(kSourcePositionsEnabled); } void MarkAsSourcePositionsEnabled() { SetFlag(kSourcePositionsEnabled); }
bool is_source_positions_enabled() const { bool is_source_positions_enabled() const {
......
...@@ -2735,6 +2735,7 @@ void AstGraphBuilder::VisitCountOperation(CountOperation* expr) { ...@@ -2735,6 +2735,7 @@ void AstGraphBuilder::VisitCountOperation(CountOperation* expr) {
// Create a proper eager frame state for the stores. // Create a proper eager frame state for the stores.
environment()->Push(old_value); environment()->Push(old_value);
FrameStateBeforeAndAfter store_states(this, expr->ToNumberId()); FrameStateBeforeAndAfter store_states(this, expr->ToNumberId());
FrameStateBeforeAndAfter binop_states(this, expr->ToNumberId());
old_value = environment()->Pop(); old_value = environment()->Pop();
// Save result for postfix expressions at correct stack depth. // Save result for postfix expressions at correct stack depth.
...@@ -2747,16 +2748,12 @@ void AstGraphBuilder::VisitCountOperation(CountOperation* expr) { ...@@ -2747,16 +2748,12 @@ void AstGraphBuilder::VisitCountOperation(CountOperation* expr) {
} }
// Create node to perform +1/-1 operation. // Create node to perform +1/-1 operation.
Node* value; // TODO(bmeurer): Cleanup this feedback/bailout mess!
{ Node* value = BuildBinaryOp(old_value, jsgraph()->OneConstant(),
// TODO(bmeurer): Cleanup this feedback/bailout mess! expr->binary_op(), expr->CountBinOpFeedbackId());
FrameStateBeforeAndAfter states(this, BailoutId::None()); // This should never deoptimize because we have converted to number before.
value = BuildBinaryOp(old_value, jsgraph()->OneConstant(), binop_states.AddToNode(value, BailoutId::None(),
expr->binary_op(), expr->CountBinOpFeedbackId()); OutputFrameStateCombine::Ignore());
// This should never deoptimize because we have converted to number before.
states.AddToNode(value, BailoutId::None(),
OutputFrameStateCombine::Ignore());
}
// Store the value. // Store the value.
VectorSlotPair feedback = CreateVectorSlotPair(expr->CountSlot()); VectorSlotPair feedback = CreateVectorSlotPair(expr->CountSlot());
......
...@@ -387,6 +387,18 @@ bool EffectControlLinearizer::TryWireInStateEffect(Node* node, Node** effect, ...@@ -387,6 +387,18 @@ bool EffectControlLinearizer::TryWireInStateEffect(Node* node, Node** effect,
case IrOpcode::kTruncateTaggedToFloat64: case IrOpcode::kTruncateTaggedToFloat64:
state = LowerTruncateTaggedToFloat64(node, *effect, *control); state = LowerTruncateTaggedToFloat64(node, *effect, *control);
break; break;
case IrOpcode::kCheckedUint32ToInt32:
state = LowerCheckedUint32ToInt32(node, *effect, *control);
break;
case IrOpcode::kCheckedFloat64ToInt32:
state = LowerCheckedFloat64ToInt32(node, *effect, *control);
break;
case IrOpcode::kCheckedTaggedToInt32:
state = LowerCheckedTaggedToInt32(node, *effect, *control);
break;
case IrOpcode::kCheckedTaggedToFloat64:
state = LowerCheckedTaggedToFloat64(node, *effect, *control);
break;
case IrOpcode::kTruncateTaggedToWord32: case IrOpcode::kTruncateTaggedToWord32:
state = LowerTruncateTaggedToWord32(node, *effect, *control); state = LowerTruncateTaggedToWord32(node, *effect, *control);
break; break;
...@@ -705,6 +717,186 @@ EffectControlLinearizer::LowerTruncateTaggedToFloat64(Node* node, Node* effect, ...@@ -705,6 +717,186 @@ EffectControlLinearizer::LowerTruncateTaggedToFloat64(Node* node, Node* effect,
return ValueEffectControl(value, effect, control); return ValueEffectControl(value, effect, control);
} }
EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerCheckedUint32ToInt32(Node* node, Node* effect,
Node* control) {
Node* value = node->InputAt(0);
Node* frame_state = NodeProperties::GetFrameStateInput(node, 0);
Node* max_int = jsgraph()->Int32Constant(std::numeric_limits<int32_t>::max());
Node* is_safe =
graph()->NewNode(machine()->Uint32LessThanOrEqual(), value, max_int);
control = effect = graph()->NewNode(common()->DeoptimizeUnless(), is_safe,
frame_state, effect, control);
// Make sure the lowered node does not appear in any use lists.
node->TrimInputCount(0);
return ValueEffectControl(value, effect, control);
}
EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::BuildCheckedFloat64ToInt32(Node* value,
Node* frame_state,
Node* effect,
Node* control) {
Node* value32 = graph()->NewNode(machine()->RoundFloat64ToInt32(), value);
Node* check_same = graph()->NewNode(
machine()->Float64Equal(), value,
graph()->NewNode(machine()->ChangeInt32ToFloat64(), value32));
control = effect = graph()->NewNode(common()->DeoptimizeUnless(), check_same,
frame_state, effect, control);
// Check if {value} is -0.
Node* check_zero = graph()->NewNode(machine()->Word32Equal(), value32,
jsgraph()->Int32Constant(0));
Node* branch_zero = graph()->NewNode(common()->Branch(BranchHint::kFalse),
check_zero, control);
Node* if_zero = graph()->NewNode(common()->IfTrue(), branch_zero);
Node* if_notzero = graph()->NewNode(common()->IfFalse(), branch_zero);
// In case of 0, we need to check the high bits for the IEEE -0 pattern.
Node* check_negative = graph()->NewNode(
machine()->Int32LessThan(),
graph()->NewNode(machine()->Float64ExtractHighWord32(), value),
jsgraph()->Int32Constant(0));
Node* deopt_minus_zero = graph()->NewNode(
common()->DeoptimizeIf(), check_negative, frame_state, effect, if_zero);
Node* merge =
graph()->NewNode(common()->Merge(2), deopt_minus_zero, if_notzero);
effect =
graph()->NewNode(common()->EffectPhi(2), deopt_minus_zero, effect, merge);
return ValueEffectControl(value32, effect, merge);
}
EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerCheckedFloat64ToInt32(Node* node, Node* effect,
Node* control) {
Node* value = node->InputAt(0);
Node* frame_state = NodeProperties::GetFrameStateInput(node, 0);
// Make sure the lowered node does not appear in any use lists.
node->TrimInputCount(0);
return BuildCheckedFloat64ToInt32(value, frame_state, effect, control);
}
EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerCheckedTaggedToInt32(Node* node, Node* effect,
Node* control) {
Node* value = node->InputAt(0);
Node* frame_state = NodeProperties::GetFrameStateInput(node, 0);
Node* check = ObjectIsSmi(value);
Node* branch =
graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
// In the Smi case, just convert to int32.
Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
Node* etrue = effect;
Node* vtrue = ChangeSmiToInt32(value);
// In the non-Smi case, check the heap numberness, load the number and convert
// to int32.
// TODO(jarin) Propagate/handle possible truncations here.
Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
ValueEffectControl number_state = BuildCheckedHeapNumberOrOddballToFloat64(
value, frame_state, effect, if_false);
number_state =
BuildCheckedFloat64ToInt32(number_state.value, frame_state,
number_state.effect, number_state.control);
Node* merge =
graph()->NewNode(common()->Merge(2), if_true, number_state.control);
Node* effect_phi = graph()->NewNode(common()->EffectPhi(2), etrue,
number_state.effect, merge);
Node* result =
graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 2), vtrue,
number_state.value, merge);
// Make sure the lowered node does not appear in any use lists.
node->TrimInputCount(0);
return ValueEffectControl(result, effect_phi, merge);
}
EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::BuildCheckedHeapNumberOrOddballToFloat64(
Node* value, Node* frame_state, Node* effect, Node* control) {
Node* value_map = effect = graph()->NewNode(
simplified()->LoadField(AccessBuilder::ForMap()), value, effect, control);
Node* check_number = graph()->NewNode(machine()->WordEqual(), value_map,
jsgraph()->HeapNumberMapConstant());
Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue),
check_number, control);
Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
Node* etrue = effect;
Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
// For oddballs also contain the numeric value, let us just check that
// we have an oddball here.
Node* efalse = effect;
Node* instance_type = efalse = graph()->NewNode(
simplified()->LoadField(AccessBuilder::ForMapInstanceType()), value_map,
efalse, if_false);
Node* check_oddball =
graph()->NewNode(machine()->Word32Equal(), instance_type,
jsgraph()->Int32Constant(ODDBALL_TYPE));
if_false = efalse =
graph()->NewNode(common()->DeoptimizeUnless(), check_oddball, frame_state,
efalse, if_false);
STATIC_ASSERT(HeapNumber::kValueOffset == Oddball::kToNumberRawOffset);
control = graph()->NewNode(common()->Merge(2), if_true, if_false);
effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
Node* result = effect = graph()->NewNode(
simplified()->LoadField(AccessBuilder::ForHeapNumberValue()), value,
effect, control);
return ValueEffectControl(result, effect, control);
}
EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerCheckedTaggedToFloat64(Node* node, Node* effect,
Node* control) {
Node* value = node->InputAt(0);
Node* frame_state = NodeProperties::GetFrameStateInput(node, 0);
Node* check = ObjectIsSmi(value);
Node* branch =
graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
// In the Smi case, just convert to int32 and then float64.
Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
Node* etrue = effect;
Node* vtrue = ChangeSmiToInt32(value);
vtrue = graph()->NewNode(machine()->ChangeInt32ToFloat64(), vtrue);
// Otherwise, check heap numberness and load the number.
Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
ValueEffectControl number_state = BuildCheckedHeapNumberOrOddballToFloat64(
value, frame_state, effect, if_false);
Node* merge =
graph()->NewNode(common()->Merge(2), if_true, number_state.control);
Node* effect_phi = graph()->NewNode(common()->EffectPhi(2), etrue,
number_state.effect, merge);
Node* result =
graph()->NewNode(common()->Phi(MachineRepresentation::kFloat64, 2), vtrue,
number_state.value, merge);
// Make sure the lowered node does not appear in any use lists.
node->TrimInputCount(0);
return ValueEffectControl(result, effect_phi, merge);
}
EffectControlLinearizer::ValueEffectControl EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerTruncateTaggedToWord32(Node* node, Node* effect, EffectControlLinearizer::LowerTruncateTaggedToWord32(Node* node, Node* effect,
Node* control) { Node* control) {
......
...@@ -60,6 +60,14 @@ class EffectControlLinearizer { ...@@ -60,6 +60,14 @@ class EffectControlLinearizer {
Node* control); Node* control);
ValueEffectControl LowerChangeTaggedToUint32(Node* node, Node* effect, ValueEffectControl LowerChangeTaggedToUint32(Node* node, Node* effect,
Node* control); Node* control);
ValueEffectControl LowerCheckedUint32ToInt32(Node* node, Node* effect,
Node* control);
ValueEffectControl LowerCheckedFloat64ToInt32(Node* node, Node* effect,
Node* control);
ValueEffectControl LowerCheckedTaggedToInt32(Node* node, Node* effect,
Node* control);
ValueEffectControl LowerCheckedTaggedToFloat64(Node* node, Node* effect,
Node* control);
ValueEffectControl LowerChangeTaggedToFloat64(Node* node, Node* effect, ValueEffectControl LowerChangeTaggedToFloat64(Node* node, Node* effect,
Node* control); Node* control);
ValueEffectControl LowerTruncateTaggedToFloat64(Node* node, Node* effect, ValueEffectControl LowerTruncateTaggedToFloat64(Node* node, Node* effect,
...@@ -81,7 +89,12 @@ class EffectControlLinearizer { ...@@ -81,7 +89,12 @@ class EffectControlLinearizer {
Node* control); Node* control);
ValueEffectControl AllocateHeapNumberWithValue(Node* node, Node* effect, ValueEffectControl AllocateHeapNumberWithValue(Node* node, Node* effect,
Node* control); Node* control);
ValueEffectControl BuildCheckedFloat64ToInt32(Node* value, Node* frame_state,
Node* effect, Node* control);
ValueEffectControl BuildCheckedHeapNumberOrOddballToFloat64(Node* value,
Node* frame_state,
Node* effect,
Node* control);
Node* ChangeInt32ToSmi(Node* value); Node* ChangeInt32ToSmi(Node* value);
Node* ChangeUint32ToSmi(Node* value); Node* ChangeUint32ToSmi(Node* value);
Node* ChangeInt32ToFloat64(Node* value); Node* ChangeInt32ToFloat64(Node* value);
......
...@@ -356,6 +356,7 @@ Reduction JSInliner::ReduceJSCall(Node* node, Handle<JSFunction> function) { ...@@ -356,6 +356,7 @@ Reduction JSInliner::ReduceJSCall(Node* node, Handle<JSFunction> function) {
ParseInfo parse_info(&zone, function); ParseInfo parse_info(&zone, function);
CompilationInfo info(&parse_info, function); CompilationInfo info(&parse_info, function);
if (info_->is_deoptimization_enabled()) info.MarkAsDeoptimizationEnabled(); if (info_->is_deoptimization_enabled()) info.MarkAsDeoptimizationEnabled();
if (info_->is_type_feedback_enabled()) info.MarkAsTypeFeedbackEnabled();
if (!Compiler::ParseAndAnalyze(info.parse_info())) { if (!Compiler::ParseAndAnalyze(info.parse_info())) {
TRACE("Not inlining %s into %s because parsing failed\n", TRACE("Not inlining %s into %s because parsing failed\n",
......
...@@ -376,6 +376,12 @@ const CreateLiteralParameters& CreateLiteralParametersOf(const Operator* op) { ...@@ -376,6 +376,12 @@ const CreateLiteralParameters& CreateLiteralParametersOf(const Operator* op) {
return OpParameter<CreateLiteralParameters>(op); return OpParameter<CreateLiteralParameters>(op);
} }
const BinaryOperationHints& BinaryOperationHintsOf(const Operator* op) {
DCHECK(op->opcode() == IrOpcode::kJSAdd ||
op->opcode() == IrOpcode::kJSSubtract);
return OpParameter<BinaryOperationHints>(op);
}
#define CACHED_OP_LIST(V) \ #define CACHED_OP_LIST(V) \
V(Equal, Operator::kNoProperties, 2, 1) \ V(Equal, Operator::kNoProperties, 2, 1) \
V(NotEqual, Operator::kNoProperties, 2, 1) \ V(NotEqual, Operator::kNoProperties, 2, 1) \
......
...@@ -344,7 +344,6 @@ std::ostream& operator<<(std::ostream&, CreateClosureParameters const&); ...@@ -344,7 +344,6 @@ std::ostream& operator<<(std::ostream&, CreateClosureParameters const&);
const CreateClosureParameters& CreateClosureParametersOf(const Operator* op); const CreateClosureParameters& CreateClosureParametersOf(const Operator* op);
// Defines shared information for the literal that should be created. This is // Defines shared information for the literal that should be created. This is
// used as parameter by JSCreateLiteralArray, JSCreateLiteralObject and // used as parameter by JSCreateLiteralArray, JSCreateLiteralObject and
// JSCreateLiteralRegExp operators. // JSCreateLiteralRegExp operators.
...@@ -375,6 +374,7 @@ std::ostream& operator<<(std::ostream&, CreateLiteralParameters const&); ...@@ -375,6 +374,7 @@ std::ostream& operator<<(std::ostream&, CreateLiteralParameters const&);
const CreateLiteralParameters& CreateLiteralParametersOf(const Operator* op); const CreateLiteralParameters& CreateLiteralParametersOf(const Operator* op);
const BinaryOperationHints& BinaryOperationHintsOf(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
......
...@@ -27,6 +27,24 @@ class JSBinopReduction final { ...@@ -27,6 +27,24 @@ class JSBinopReduction final {
JSBinopReduction(JSTypedLowering* lowering, Node* node) JSBinopReduction(JSTypedLowering* lowering, Node* node)
: lowering_(lowering), node_(node) {} : lowering_(lowering), node_(node) {}
BinaryOperationHints::Hint GetUsableNumberFeedback() {
if (!(lowering_->flags() & JSTypedLowering::kDeoptimizationEnabled) ||
!(lowering_->flags() & JSTypedLowering::kTypeFeedbackEnabled)) {
return BinaryOperationHints::kAny;
}
DCHECK_NE(0, node_->op()->ControlOutputCount());
DCHECK_EQ(1, node_->op()->EffectOutputCount());
DCHECK_EQ(2, OperatorProperties::GetFrameStateInputCount(node_->op()));
BinaryOperationHints hints = BinaryOperationHintsOf(node_->op());
BinaryOperationHints::Hint combined = hints.combined();
if (combined == BinaryOperationHints::kSignedSmall ||
combined == BinaryOperationHints::kSigned32 ||
combined == BinaryOperationHints::kNumberOrUndefined) {
return combined;
}
return BinaryOperationHints::kAny;
}
void ConvertInputsToNumberOrUndefined(Node* frame_state) { void ConvertInputsToNumberOrUndefined(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.
...@@ -107,6 +125,52 @@ class JSBinopReduction final { ...@@ -107,6 +125,52 @@ class JSBinopReduction final {
return lowering_->Changed(node_); return lowering_->Changed(node_);
} }
Reduction ChangeToSpeculativeOperator(const Operator* op) {
DCHECK_EQ(1, op->EffectInputCount());
DCHECK_EQ(1, op->EffectOutputCount());
DCHECK_EQ(false, OperatorProperties::HasContextInput(op));
DCHECK_EQ(1, op->ControlInputCount());
DCHECK_EQ(1, op->ControlOutputCount());
DCHECK_EQ(1, OperatorProperties::GetFrameStateInputCount(op));
DCHECK_EQ(2, op->ValueInputCount());
DCHECK_EQ(1, node_->op()->EffectInputCount());
DCHECK_EQ(1, node_->op()->EffectOutputCount());
DCHECK_EQ(1, node_->op()->ControlInputCount());
DCHECK_LT(1, node_->op()->ControlOutputCount());
DCHECK_EQ(2, OperatorProperties::GetFrameStateInputCount(node_->op()));
DCHECK_EQ(2, node_->op()->ValueInputCount());
// Reconnect the control output to bypass the IfSuccess node and
// possibly disconnect from the IfException node.
for (Edge edge : node_->use_edges()) {
Node* const user = edge.from();
DCHECK(!user->IsDead());
if (NodeProperties::IsControlEdge(edge)) {
if (user->opcode() == IrOpcode::kIfSuccess) {
user->ReplaceUses(node_);
user->Kill();
} else {
DCHECK_EQ(user->opcode(), IrOpcode::kIfException);
edge.UpdateTo(jsgraph()->Dead());
}
}
}
// Remove the lazy bailout frame state and the context.
node_->RemoveInput(NodeProperties::FirstFrameStateIndex(node_));
node_->RemoveInput(NodeProperties::FirstContextIndex(node_));
NodeProperties::ChangeOp(node_, op);
// Update the type to number.
Type* node_type = NodeProperties::GetType(node_);
NodeProperties::SetType(node_,
Type::Intersect(node_type, Type::Number(), zone()));
return lowering_->Changed(node_);
}
Reduction ChangeToPureOperator(const Operator* op, Type* type) { Reduction ChangeToPureOperator(const Operator* op, Type* type) {
return ChangeToPureOperator(op, false, type); return ChangeToPureOperator(op, false, type);
} }
...@@ -340,9 +404,18 @@ Reduction JSTypedLowering::ReduceJSAdd(Node* node) { ...@@ -340,9 +404,18 @@ Reduction JSTypedLowering::ReduceJSAdd(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();
if (feedback != BinaryOperationHints::kAny) {
// Lower to the optimistic number binop.
return r.ChangeToSpeculativeOperator(
simplified()->SpeculativeNumberAdd(feedback));
}
if (r.BothInputsAre(Type::NumberOrUndefined())) { if (r.BothInputsAre(Type::NumberOrUndefined())) {
// JSAdd(x:number, y:number) => NumberAdd(x, y) // JSAdd(x:number, y:number) => NumberAdd(x, y)
return ReduceNumberBinop(node, simplified()->NumberAdd()); Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
r.ConvertInputsToNumberOrUndefined(frame_state);
return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number());
} }
if (r.NeitherInputCanBe(Type::StringOrReceiver())) { if (r.NeitherInputCanBe(Type::StringOrReceiver())) {
// JSAdd(x:-string, y:-string) => NumberAdd(ToNumber(x), ToNumber(y)) // JSAdd(x:-string, y:-string) => NumberAdd(ToNumber(x), ToNumber(y))
...@@ -387,21 +460,34 @@ Reduction JSTypedLowering::ReduceJSModulus(Node* node) { ...@@ -387,21 +460,34 @@ Reduction JSTypedLowering::ReduceJSModulus(Node* node) {
return NoChange(); return NoChange();
} }
Reduction JSTypedLowering::ReduceJSSubtract(Node* node) {
if (flags() & kDisableBinaryOpReduction) return NoChange();
JSBinopReduction r(this, node);
BinaryOperationHints::Hint feedback = r.GetUsableNumberFeedback();
if (feedback != BinaryOperationHints::kAny) {
// Lower to the optimistic number binop.
return r.ChangeToSpeculativeOperator(
simplified()->SpeculativeNumberSubtract(feedback));
}
Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
r.ConvertInputsToNumberOrUndefined(frame_state);
return r.ChangeToPureOperator(simplified()->NumberSubtract(), Type::Number());
}
Reduction JSTypedLowering::ReduceNumberBinop(Node* node, Reduction JSTypedLowering::ReduceJSMultiply(Node* node) {
const Operator* numberOp) {
if (flags() & kDisableBinaryOpReduction) return NoChange(); if (flags() & kDisableBinaryOpReduction) return NoChange();
JSBinopReduction r(this, node);
Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
r.ConvertInputsToNumberOrUndefined(frame_state);
return r.ChangeToPureOperator(simplified()->NumberMultiply(), Type::Number());
}
Reduction JSTypedLowering::ReduceJSDivide(Node* node) {
if (flags() & kDisableBinaryOpReduction) return NoChange();
JSBinopReduction r(this, node); JSBinopReduction r(this, node);
if (numberOp == simplified()->NumberModulus()) {
if (r.BothInputsAre(Type::NumberOrUndefined())) {
return r.ChangeToPureOperator(numberOp, Type::Number());
}
return NoChange();
}
Node* frame_state = NodeProperties::GetFrameStateInput(node, 1); Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
r.ConvertInputsToNumberOrUndefined(frame_state); r.ConvertInputsToNumberOrUndefined(frame_state);
return r.ChangeToPureOperator(numberOp, Type::Number()); return r.ChangeToPureOperator(simplified()->NumberDivide(), Type::Number());
} }
...@@ -1785,11 +1871,11 @@ Reduction JSTypedLowering::Reduce(Node* node) { ...@@ -1785,11 +1871,11 @@ Reduction JSTypedLowering::Reduce(Node* node) {
case IrOpcode::kJSAdd: case IrOpcode::kJSAdd:
return ReduceJSAdd(node); return ReduceJSAdd(node);
case IrOpcode::kJSSubtract: case IrOpcode::kJSSubtract:
return ReduceNumberBinop(node, simplified()->NumberSubtract()); return ReduceJSSubtract(node);
case IrOpcode::kJSMultiply: case IrOpcode::kJSMultiply:
return ReduceNumberBinop(node, simplified()->NumberMultiply()); return ReduceJSMultiply(node);
case IrOpcode::kJSDivide: case IrOpcode::kJSDivide:
return ReduceNumberBinop(node, simplified()->NumberDivide()); return ReduceJSDivide(node);
case IrOpcode::kJSModulus: case IrOpcode::kJSModulus:
return ReduceJSModulus(node); return ReduceJSModulus(node);
case IrOpcode::kJSToBoolean: case IrOpcode::kJSToBoolean:
......
...@@ -36,6 +36,7 @@ class JSTypedLowering final : public AdvancedReducer { ...@@ -36,6 +36,7 @@ class JSTypedLowering final : public AdvancedReducer {
kNoFlags = 0u, kNoFlags = 0u,
kDeoptimizationEnabled = 1u << 0, kDeoptimizationEnabled = 1u << 0,
kDisableBinaryOpReduction = 1u << 1, kDisableBinaryOpReduction = 1u << 1,
kTypeFeedbackEnabled = 1u << 2,
}; };
typedef base::Flags<Flag> Flags; typedef base::Flags<Flag> Flags;
...@@ -80,7 +81,8 @@ class JSTypedLowering final : public AdvancedReducer { ...@@ -80,7 +81,8 @@ class JSTypedLowering final : public AdvancedReducer {
Reduction ReduceJSGeneratorRestoreContinuation(Node* node); Reduction ReduceJSGeneratorRestoreContinuation(Node* node);
Reduction ReduceJSGeneratorRestoreRegister(Node* node); Reduction ReduceJSGeneratorRestoreRegister(Node* node);
Reduction ReduceSelect(Node* node); Reduction ReduceSelect(Node* node);
Reduction ReduceNumberBinop(Node* node, const Operator* numberOp); Reduction ReduceJSSubtract(Node* node);
Reduction ReduceJSDivide(Node* node);
Reduction ReduceInt32Binop(Node* node, const Operator* intOp); Reduction ReduceInt32Binop(Node* node, const Operator* intOp);
Reduction ReduceUI32Shift(Node* node, Signedness left_signedness, Reduction ReduceUI32Shift(Node* node, Signedness left_signedness,
const Operator* shift_op); const Operator* shift_op);
......
...@@ -177,6 +177,8 @@ ...@@ -177,6 +177,8 @@
SIMPLIFIED_COMPARE_BINOP_LIST(V) \ SIMPLIFIED_COMPARE_BINOP_LIST(V) \
V(BooleanNot) \ V(BooleanNot) \
V(BooleanToNumber) \ V(BooleanToNumber) \
V(SpeculativeNumberAdd) \
V(SpeculativeNumberSubtract) \
V(NumberAdd) \ V(NumberAdd) \
V(NumberSubtract) \ V(NumberSubtract) \
V(NumberMultiply) \ V(NumberMultiply) \
...@@ -209,6 +211,10 @@ ...@@ -209,6 +211,10 @@
V(ChangeFloat64ToTagged) \ V(ChangeFloat64ToTagged) \
V(ChangeTaggedToBit) \ V(ChangeTaggedToBit) \
V(ChangeBitToTagged) \ V(ChangeBitToTagged) \
V(CheckedUint32ToInt32) \
V(CheckedFloat64ToInt32) \
V(CheckedTaggedToInt32) \
V(CheckedTaggedToFloat64) \
V(TruncateTaggedToWord32) \ V(TruncateTaggedToWord32) \
V(TruncateTaggedToFloat64) \ V(TruncateTaggedToFloat64) \
V(Allocate) \ V(Allocate) \
......
This diff is collapsed.
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_COMPILER_OPERATION_TYPER_H_
#define V8_COMPILER_OPERATION_TYPER_H_
#include "src/base/flags.h"
#include "src/compiler/opcodes.h"
namespace v8 {
namespace internal {
class Isolate;
class RangeType;
class Type;
class TypeCache;
class Zone;
namespace compiler {
class OperationTyper {
public:
OperationTyper(Isolate* isolate, Zone* zone);
// Typing Phi.
Type* Merge(Type* left, Type* right);
Type* ToPrimitive(Type* type);
// Helpers for number operation typing.
Type* ToNumber(Type* type);
Type* WeakenRange(Type* current_range, Type* previous_range);
Type* NumericAdd(Type* lhs, Type* rhs);
Type* NumericSubtract(Type* lhs, Type* rhs);
enum ComparisonOutcomeFlags {
kComparisonTrue = 1,
kComparisonFalse = 2,
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_; }
private:
typedef base::Flags<ComparisonOutcomeFlags> ComparisonOutcome;
ComparisonOutcome Invert(ComparisonOutcome);
Type* Invert(Type*);
Type* FalsifyUndefined(ComparisonOutcome);
Type* Rangify(Type*);
Type* AddRanger(RangeType* lhs, RangeType* rhs);
Type* SubtractRanger(RangeType* lhs, RangeType* rhs);
Type* ModulusRanger(RangeType* lhs, RangeType* rhs);
Zone* zone() { return zone_; }
Zone* zone_;
TypeCache const& cache_;
Type* singleton_false_;
Type* singleton_true_;
Type* singleton_the_hole_;
};
} // namespace compiler
} // namespace internal
} // namespace v8
#endif // V8_COMPILER_OPERATION_TYPER_H_
...@@ -107,6 +107,16 @@ int OperatorProperties::GetFrameStateInputCount(const Operator* op) { ...@@ -107,6 +107,16 @@ int OperatorProperties::GetFrameStateInputCount(const Operator* op) {
case IrOpcode::kJSLessThanOrEqual: case IrOpcode::kJSLessThanOrEqual:
return 2; return 2;
// Simplified operators with type feedback.
case IrOpcode::kSpeculativeNumberAdd:
case IrOpcode::kSpeculativeNumberSubtract:
// Checked conversions.
case IrOpcode::kCheckedUint32ToInt32:
case IrOpcode::kCheckedFloat64ToInt32:
case IrOpcode::kCheckedTaggedToInt32:
case IrOpcode::kCheckedTaggedToFloat64:
return 1;
default: default:
return 0; return 0;
} }
......
...@@ -597,6 +597,9 @@ PipelineCompilationJob::Status PipelineCompilationJob::CreateGraphImpl() { ...@@ -597,6 +597,9 @@ PipelineCompilationJob::Status PipelineCompilationJob::CreateGraphImpl() {
if (!info()->shared_info()->asm_function() || FLAG_turbo_asm_deoptimization) { if (!info()->shared_info()->asm_function() || FLAG_turbo_asm_deoptimization) {
info()->MarkAsDeoptimizationEnabled(); info()->MarkAsDeoptimizationEnabled();
} }
if (info()->is_deoptimization_enabled() && FLAG_turbo_type_feedback) {
info()->MarkAsTypeFeedbackEnabled();
}
if (!info()->is_optimizing_from_bytecode()) { if (!info()->is_optimizing_from_bytecode()) {
if (!Compiler::EnsureDeoptimizationSupport(info())) return FAILED; if (!Compiler::EnsureDeoptimizationSupport(info())) return FAILED;
} }
...@@ -883,6 +886,9 @@ struct TypedLoweringPhase { ...@@ -883,6 +886,9 @@ struct TypedLoweringPhase {
if (data->info()->shared_info()->HasBytecodeArray()) { if (data->info()->shared_info()->HasBytecodeArray()) {
typed_lowering_flags |= JSTypedLowering::kDisableBinaryOpReduction; typed_lowering_flags |= JSTypedLowering::kDisableBinaryOpReduction;
} }
if (data->info()->is_type_feedback_enabled()) {
typed_lowering_flags |= JSTypedLowering::kTypeFeedbackEnabled;
}
JSTypedLowering typed_lowering(&graph_reducer, data->info()->dependencies(), JSTypedLowering typed_lowering(&graph_reducer, data->info()->dependencies(),
typed_lowering_flags, data->jsgraph(), typed_lowering_flags, data->jsgraph(),
temp_zone); temp_zone);
...@@ -947,8 +953,12 @@ struct RepresentationSelectionPhase { ...@@ -947,8 +953,12 @@ struct RepresentationSelectionPhase {
static const char* phase_name() { return "representation selection"; } static const char* phase_name() { return "representation selection"; }
void Run(PipelineData* data, Zone* temp_zone) { void Run(PipelineData* data, Zone* temp_zone) {
SimplifiedLowering::Flags flags =
data->info()->is_type_feedback_enabled()
? SimplifiedLowering::kTypeFeedbackEnabled
: SimplifiedLowering::kNoFlag;
SimplifiedLowering lowering(data->jsgraph(), temp_zone, SimplifiedLowering lowering(data->jsgraph(), temp_zone,
data->source_positions()); data->source_positions(), flags);
lowering.LowerAllNodes(); lowering.LowerAllNodes();
} }
}; };
...@@ -1416,7 +1426,7 @@ bool PipelineImpl::CreateGraph() { ...@@ -1416,7 +1426,7 @@ bool PipelineImpl::CreateGraph() {
// Select representations. // Select representations.
Run<RepresentationSelectionPhase>(); Run<RepresentationSelectionPhase>();
RunPrintAndVerify("Representations selected"); RunPrintAndVerify("Representations selected", true);
} }
#ifdef DEBUG #ifdef DEBUG
......
This diff is collapsed.
...@@ -73,6 +73,86 @@ class Truncation final { ...@@ -73,6 +73,86 @@ class Truncation final {
static bool LessGeneral(TruncationKind rep1, TruncationKind rep2); static bool LessGeneral(TruncationKind rep1, TruncationKind rep2);
}; };
enum class TypeCheckKind : uint8_t {
kNone,
kSigned32,
kNumberOrUndefined,
kNumber
};
// The {UseInfo} class is used to describe a use of an input of a node.
//
// This information is used in two different ways, based on the phase:
//
// 1. During propagation, the use info is used to inform the input node
// about what part of the input is used (we call this truncation) and what
// is the preferred representation.
//
// 2. During lowering, the use info is used to properly convert the input
// to the preferred representation. The preferred representation might be
// insufficient to do the conversion (e.g. word32->float64 conv), so we also
// need the signedness information to produce the correct value.
class UseInfo {
public:
UseInfo(MachineRepresentation representation, Truncation truncation,
TypeCheckKind type_check = TypeCheckKind::kNone)
: representation_(representation),
truncation_(truncation),
type_check_(type_check) {}
static UseInfo TruncatingWord32() {
return UseInfo(MachineRepresentation::kWord32, Truncation::Word32());
}
static UseInfo TruncatingWord64() {
return UseInfo(MachineRepresentation::kWord64, Truncation::Word64());
}
static UseInfo Bool() {
return UseInfo(MachineRepresentation::kBit, Truncation::Bool());
}
static UseInfo TruncatingFloat32() {
return UseInfo(MachineRepresentation::kFloat32, Truncation::Float32());
}
static UseInfo TruncatingFloat64() {
return UseInfo(MachineRepresentation::kFloat64, Truncation::Float64());
}
static UseInfo PointerInt() {
return kPointerSize == 4 ? TruncatingWord32() : TruncatingWord64();
}
static UseInfo AnyTagged() {
return UseInfo(MachineRepresentation::kTagged, Truncation::Any());
}
// Possibly deoptimizing conversions.
static UseInfo CheckedSigned32AsWord32() {
return UseInfo(MachineRepresentation::kWord32, Truncation::Any(),
TypeCheckKind::kSigned32);
}
static UseInfo CheckedNumberOrUndefinedAsFloat64() {
return UseInfo(MachineRepresentation::kFloat64, Truncation::Any(),
TypeCheckKind::kNumberOrUndefined);
}
// Undetermined representation.
static UseInfo Any() {
return UseInfo(MachineRepresentation::kNone, Truncation::Any());
}
static UseInfo AnyTruncatingToBool() {
return UseInfo(MachineRepresentation::kNone, Truncation::Bool());
}
// Value not used.
static UseInfo None() {
return UseInfo(MachineRepresentation::kNone, Truncation::None());
}
MachineRepresentation representation() const { return representation_; }
Truncation truncation() const { return truncation_; }
TypeCheckKind type_check() const { return type_check_; }
private:
MachineRepresentation representation_;
Truncation truncation_;
TypeCheckKind type_check_;
};
// Contains logic related to changing the representation of values for constants // Contains logic related to changing the representation of values for constants
// and other nodes, as well as lowering Simplified->Machine operators. // and other nodes, as well as lowering Simplified->Machine operators.
...@@ -90,9 +170,10 @@ class RepresentationChanger final { ...@@ -90,9 +170,10 @@ class RepresentationChanger final {
// out signedness for the word32->float64 conversion, then we check that the // out signedness for the word32->float64 conversion, then we check that the
// uses truncate to word32 (so they do not care about signedness). // uses truncate to word32 (so they do not care about signedness).
Node* GetRepresentationFor(Node* node, MachineRepresentation output_rep, Node* GetRepresentationFor(Node* node, MachineRepresentation output_rep,
Type* output_type, MachineRepresentation use_rep, Type* output_type, Node* use_node,
Truncation truncation = Truncation::None()); UseInfo use_info);
const Operator* Int32OperatorFor(IrOpcode::Value opcode); const Operator* Int32OperatorFor(IrOpcode::Value opcode);
const Operator* Int32OverflowOperatorFor(IrOpcode::Value opcode);
const Operator* Uint32OperatorFor(IrOpcode::Value opcode); const Operator* Uint32OperatorFor(IrOpcode::Value opcode);
const Operator* Float64OperatorFor(IrOpcode::Value opcode); const Operator* Float64OperatorFor(IrOpcode::Value opcode);
...@@ -122,13 +203,20 @@ class RepresentationChanger final { ...@@ -122,13 +203,20 @@ class RepresentationChanger final {
Type* output_type, Truncation truncation); Type* output_type, Truncation truncation);
Node* GetFloat64RepresentationFor(Node* node, Node* GetFloat64RepresentationFor(Node* node,
MachineRepresentation output_rep, MachineRepresentation output_rep,
Type* output_type, Truncation truncation); Type* output_type, Node* use_node,
UseInfo use_info);
Node* GetWord32RepresentationFor(Node* node, MachineRepresentation output_rep, Node* GetWord32RepresentationFor(Node* node, MachineRepresentation output_rep,
Type* output_type, Truncation truncation); Type* output_type, Node* use_node,
UseInfo use_info);
Node* GetBitRepresentationFor(Node* node, MachineRepresentation output_rep, Node* GetBitRepresentationFor(Node* node, MachineRepresentation output_rep,
Type* output_type); Type* output_type);
Node* GetWord64RepresentationFor(Node* node, MachineRepresentation output_rep, Node* GetWord64RepresentationFor(Node* node, MachineRepresentation output_rep,
Type* output_type); Type* output_type);
Node* GetCheckedWord32RepresentationFor(Node* node,
MachineRepresentation output_rep,
Type* output_type, Node* use_node,
Truncation truncation,
TypeCheckKind check);
Node* TypeError(Node* node, MachineRepresentation output_rep, Node* TypeError(Node* node, MachineRepresentation output_rep,
Type* output_type, MachineRepresentation use); Type* output_type, MachineRepresentation use);
Node* MakeTruncatedInt32Constant(double value); Node* MakeTruncatedInt32Constant(double value);
...@@ -138,6 +226,8 @@ class RepresentationChanger final { ...@@ -138,6 +226,8 @@ class RepresentationChanger final {
Node* InsertChangeTaggedSignedToInt32(Node* node); Node* InsertChangeTaggedSignedToInt32(Node* node);
Node* InsertChangeTaggedToFloat64(Node* node); Node* InsertChangeTaggedToFloat64(Node* node);
Node* InsertConversion(Node* node, const Operator* op, Node* use_node);
JSGraph* jsgraph() const { return jsgraph_; } JSGraph* jsgraph() const { return jsgraph_; }
Isolate* isolate() const { return isolate_; } Isolate* isolate() const { return isolate_; }
Factory* factory() const { return isolate()->factory(); } Factory* factory() const { return isolate()->factory(); }
......
This diff is collapsed.
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#ifndef V8_COMPILER_SIMPLIFIED_LOWERING_H_ #ifndef V8_COMPILER_SIMPLIFIED_LOWERING_H_
#define V8_COMPILER_SIMPLIFIED_LOWERING_H_ #define V8_COMPILER_SIMPLIFIED_LOWERING_H_
#include "src/base/flags.h"
#include "src/compiler/js-graph.h" #include "src/compiler/js-graph.h"
#include "src/compiler/machine-operator.h" #include "src/compiler/machine-operator.h"
#include "src/compiler/node.h" #include "src/compiler/node.h"
...@@ -26,8 +27,11 @@ class SourcePositionTable; ...@@ -26,8 +27,11 @@ class SourcePositionTable;
class SimplifiedLowering final { class SimplifiedLowering final {
public: public:
enum Flag { kNoFlag = 0u, kTypeFeedbackEnabled = 1u << 0 };
typedef base::Flags<Flag> Flags;
SimplifiedLowering(JSGraph* jsgraph, Zone* zone, SimplifiedLowering(JSGraph* jsgraph, Zone* zone,
SourcePositionTable* source_positions); SourcePositionTable* source_positions,
Flags flags = kNoFlag);
~SimplifiedLowering() {} ~SimplifiedLowering() {}
void LowerAllNodes(); void LowerAllNodes();
...@@ -43,12 +47,15 @@ class SimplifiedLowering final { ...@@ -43,12 +47,15 @@ class SimplifiedLowering final {
void DoStoreBuffer(Node* node); void DoStoreBuffer(Node* node);
void DoShift(Node* node, Operator const* op, Type* rhs_type); void DoShift(Node* node, Operator const* op, Type* rhs_type);
Flags flags() const { return flags_; }
private: private:
JSGraph* const jsgraph_; JSGraph* const jsgraph_;
Zone* const zone_; Zone* const zone_;
TypeCache const& type_cache_; TypeCache const& type_cache_;
SetOncePointer<Node> to_number_code_; SetOncePointer<Node> to_number_code_;
SetOncePointer<Operator const> to_number_operator_; SetOncePointer<Operator const> to_number_operator_;
Flags flags_;
// TODO(danno): SimplifiedLowering shouldn't know anything about the source // TODO(danno): SimplifiedLowering shouldn't know anything about the source
// positions table, but must for now since there currently is no other way to // positions table, but must for now since there currently is no other way to
......
...@@ -177,6 +177,12 @@ Type* TypeOf(const Operator* op) { ...@@ -177,6 +177,12 @@ Type* TypeOf(const Operator* op) {
return OpParameter<Type*>(op); return OpParameter<Type*>(op);
} }
BinaryOperationHints::Hint BinaryOperationHintOf(const Operator* op) {
DCHECK(op->opcode() == IrOpcode::kSpeculativeNumberAdd ||
op->opcode() == IrOpcode::kSpeculativeNumberSubtract);
return OpParameter<BinaryOperationHints::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) \
...@@ -227,6 +233,12 @@ Type* TypeOf(const Operator* op) { ...@@ -227,6 +233,12 @@ Type* TypeOf(const Operator* op) {
V(StringLessThan, Operator::kNoProperties, 2) \ V(StringLessThan, Operator::kNoProperties, 2) \
V(StringLessThanOrEqual, Operator::kNoProperties, 2) V(StringLessThanOrEqual, Operator::kNoProperties, 2)
#define CHECKED_OP_LIST(V) \
V(CheckedUint32ToInt32) \
V(CheckedFloat64ToInt32) \
V(CheckedTaggedToInt32) \
V(CheckedTaggedToFloat64)
struct SimplifiedOperatorGlobalCache final { struct SimplifiedOperatorGlobalCache final {
#define PURE(Name, properties, input_count) \ #define PURE(Name, properties, input_count) \
struct Name##Operator final : public Operator { \ struct Name##Operator final : public Operator { \
...@@ -238,6 +250,16 @@ struct SimplifiedOperatorGlobalCache final { ...@@ -238,6 +250,16 @@ struct SimplifiedOperatorGlobalCache final {
PURE_OP_LIST(PURE) PURE_OP_LIST(PURE)
#undef PURE #undef PURE
#define CHECKED(Name) \
struct Name##Operator final : public Operator { \
Name##Operator() \
: Operator(IrOpcode::k##Name, Operator::kNoThrow, #Name, 1, 1, 1, 1, \
1, 1) {} \
}; \
Name##Operator k##Name;
CHECKED_OP_LIST(CHECKED)
#undef CHECKED
template <PretenureFlag kPretenure> template <PretenureFlag kPretenure>
struct AllocateOperator final : public Operator1<PretenureFlag> { struct AllocateOperator final : public Operator1<PretenureFlag> {
AllocateOperator() AllocateOperator()
...@@ -276,12 +298,15 @@ static base::LazyInstance<SimplifiedOperatorGlobalCache>::type kCache = ...@@ -276,12 +298,15 @@ static base::LazyInstance<SimplifiedOperatorGlobalCache>::type kCache =
SimplifiedOperatorBuilder::SimplifiedOperatorBuilder(Zone* zone) SimplifiedOperatorBuilder::SimplifiedOperatorBuilder(Zone* zone)
: cache_(kCache.Get()), zone_(zone) {} : cache_(kCache.Get()), zone_(zone) {}
#define GET_FROM_CACHE(Name, properties, input_count) \ #define GET_FROM_CACHE(Name, properties, input_count) \
const Operator* SimplifiedOperatorBuilder::Name() { return &cache_.k##Name; } const Operator* SimplifiedOperatorBuilder::Name() { return &cache_.k##Name; }
PURE_OP_LIST(GET_FROM_CACHE) PURE_OP_LIST(GET_FROM_CACHE)
#undef GET_FROM_CACHE #undef GET_FROM_CACHE
#define GET_FROM_CACHE(Name) \
const Operator* SimplifiedOperatorBuilder::Name() { return &cache_.k##Name; }
CHECKED_OP_LIST(GET_FROM_CACHE)
#undef GET_FROM_CACHE
const Operator* SimplifiedOperatorBuilder::ReferenceEqual(Type* type) { const Operator* SimplifiedOperatorBuilder::ReferenceEqual(Type* type) {
return new (zone()) Operator(IrOpcode::kReferenceEqual, return new (zone()) Operator(IrOpcode::kReferenceEqual,
...@@ -343,6 +368,19 @@ const Operator* SimplifiedOperatorBuilder::StoreBuffer(BufferAccess access) { ...@@ -343,6 +368,19 @@ const Operator* SimplifiedOperatorBuilder::StoreBuffer(BufferAccess access) {
return nullptr; return nullptr;
} }
const Operator* SimplifiedOperatorBuilder::SpeculativeNumberAdd(
BinaryOperationHints::Hint hint) {
return new (zone()) Operator1<BinaryOperationHints::Hint>(
IrOpcode::kSpeculativeNumberAdd, Operator::kNoThrow,
"SpeculativeNumberAdd", 2, 1, 1, 1, 1, 1, hint);
}
const Operator* SimplifiedOperatorBuilder::SpeculativeNumberSubtract(
BinaryOperationHints::Hint hint) {
return new (zone()) Operator1<BinaryOperationHints::Hint>(
IrOpcode::kSpeculativeNumberSubtract, Operator::kNoThrow,
"SpeculativeNumberSubtract", 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) \
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include <iosfwd> #include <iosfwd>
#include "src/compiler/type-hints.h"
#include "src/handles.h" #include "src/handles.h"
#include "src/machine-type.h" #include "src/machine-type.h"
#include "src/objects.h" #include "src/objects.h"
...@@ -104,6 +105,8 @@ ElementAccess const& ElementAccessOf(const Operator* op) WARN_UNUSED_RESULT; ...@@ -104,6 +105,8 @@ ElementAccess const& ElementAccessOf(const Operator* op) WARN_UNUSED_RESULT;
Type* TypeOf(const Operator* op) WARN_UNUSED_RESULT; Type* TypeOf(const Operator* op) WARN_UNUSED_RESULT;
BinaryOperationHints::Hint BinaryOperationHintOf(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.
...@@ -157,6 +160,9 @@ class SimplifiedOperatorBuilder final : public ZoneObject { ...@@ -157,6 +160,9 @@ class SimplifiedOperatorBuilder final : public ZoneObject {
const Operator* NumberToUint32(); const Operator* NumberToUint32();
const Operator* NumberIsHoleNaN(); const Operator* NumberIsHoleNaN();
const Operator* SpeculativeNumberAdd(BinaryOperationHints::Hint hint);
const Operator* SpeculativeNumberSubtract(BinaryOperationHints::Hint hint);
const Operator* ReferenceEqual(Type* type); const Operator* ReferenceEqual(Type* type);
const Operator* StringEqual(); const Operator* StringEqual();
...@@ -178,6 +184,11 @@ class SimplifiedOperatorBuilder final : public ZoneObject { ...@@ -178,6 +184,11 @@ class SimplifiedOperatorBuilder final : public ZoneObject {
const Operator* TruncateTaggedToWord32(); const Operator* TruncateTaggedToWord32();
const Operator* TruncateTaggedToFloat64(); const Operator* TruncateTaggedToFloat64();
const Operator* CheckedUint32ToInt32();
const Operator* CheckedFloat64ToInt32();
const Operator* CheckedTaggedToInt32();
const Operator* CheckedTaggedToFloat64();
const Operator* ObjectIsCallable(); const Operator* ObjectIsCallable();
const Operator* ObjectIsNumber(); const Operator* ObjectIsNumber();
const Operator* ObjectIsReceiver(); const Operator* ObjectIsReceiver();
......
...@@ -20,7 +20,7 @@ BinaryOperationHints::Hint ToHint(Type* type) { ...@@ -20,7 +20,7 @@ BinaryOperationHints::Hint ToHint(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;
if (type->Is(Type::Number())) return BinaryOperationHints::kNumber; if (type->Is(Type::Number())) return BinaryOperationHints::kNumberOrUndefined;
if (type->Is(Type::String())) return BinaryOperationHints::kString; if (type->Is(Type::String())) return BinaryOperationHints::kString;
return BinaryOperationHints::kAny; return BinaryOperationHints::kAny;
} }
......
...@@ -16,8 +16,8 @@ std::ostream& operator<<(std::ostream& os, BinaryOperationHints::Hint hint) { ...@@ -16,8 +16,8 @@ std::ostream& operator<<(std::ostream& os, BinaryOperationHints::Hint hint) {
return os << "SignedSmall"; return os << "SignedSmall";
case BinaryOperationHints::kSigned32: case BinaryOperationHints::kSigned32:
return os << "Signed32"; return os << "Signed32";
case BinaryOperationHints::kNumber: case BinaryOperationHints::kNumberOrUndefined:
return os << "Number"; return os << "NumberOrUndefined";
case BinaryOperationHints::kString: case BinaryOperationHints::kString:
return os << "String"; return os << "String";
case BinaryOperationHints::kAny: case BinaryOperationHints::kAny:
...@@ -78,6 +78,34 @@ std::ostream& operator<<(std::ostream& os, ToBooleanHints hints) { ...@@ -78,6 +78,34 @@ std::ostream& operator<<(std::ostream& os, ToBooleanHints hints) {
return os; return os;
} }
// static
bool BinaryOperationHints::Is(Hint h1, Hint h2) {
if (h1 == h2) return true;
switch (h1) {
case kNone:
return true;
case kSignedSmall:
return h2 == kSigned32 || h2 == kNumberOrUndefined || h2 == kAny;
case kSigned32:
return h2 == kNumberOrUndefined || h2 == kAny;
case kNumberOrUndefined:
return h2 == kAny;
case kString:
return h2 == kAny;
case kAny:
return false;
}
UNREACHABLE();
return false;
}
// static
BinaryOperationHints::Hint BinaryOperationHints::Combine(Hint h1, Hint h2) {
if (Is(h1, h2)) return h2;
if (Is(h2, h1)) return h1;
return kAny;
}
} // namespace compiler } // namespace compiler
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -15,7 +15,14 @@ namespace compiler { ...@@ -15,7 +15,14 @@ namespace compiler {
// Type hints for an binary operation. // Type hints for an binary operation.
class BinaryOperationHints final { class BinaryOperationHints final {
public: public:
enum Hint { kNone, kSignedSmall, kSigned32, kNumber, kString, kAny }; enum Hint {
kNone,
kSignedSmall,
kSigned32,
kNumberOrUndefined,
kString,
kAny
};
BinaryOperationHints() : BinaryOperationHints(kNone, kNone, kNone) {} BinaryOperationHints() : BinaryOperationHints(kNone, kNone, kNone) {}
BinaryOperationHints(Hint left, Hint right, Hint result) BinaryOperationHints(Hint left, Hint right, Hint result)
...@@ -29,6 +36,11 @@ class BinaryOperationHints final { ...@@ -29,6 +36,11 @@ class BinaryOperationHints final {
Hint left() const { return LeftField::decode(bit_field_); } Hint left() const { return LeftField::decode(bit_field_); }
Hint right() const { return RightField::decode(bit_field_); } Hint right() const { return RightField::decode(bit_field_); }
Hint result() const { return ResultField::decode(bit_field_); } Hint result() const { return ResultField::decode(bit_field_); }
Hint combined() const { return Combine(Combine(left(), right()), result()); }
// Hint 'subtyping' and generalization.
static bool Is(Hint h1, Hint h2);
static Hint Combine(Hint h1, Hint h2);
bool operator==(BinaryOperationHints const& that) const { bool operator==(BinaryOperationHints const& that) const {
return this->bit_field_ == that.bit_field_; return this->bit_field_ == that.bit_field_;
......
...@@ -1702,7 +1702,6 @@ Type* Typer::Visitor::TypeJSGeneratorRestoreRegister(Node* node) { ...@@ -1702,7 +1702,6 @@ Type* Typer::Visitor::TypeJSGeneratorRestoreRegister(Node* node) {
Type* Typer::Visitor::TypeJSStackCheck(Node* node) { return Type::Any(); } Type* Typer::Visitor::TypeJSStackCheck(Node* node) { return Type::Any(); }
// Simplified operators. // Simplified operators.
Type* Typer::Visitor::TypeBooleanNot(Node* node) { return Type::Boolean(); } Type* Typer::Visitor::TypeBooleanNot(Node* node) { return Type::Boolean(); }
...@@ -1723,6 +1722,14 @@ Type* Typer::Visitor::TypeNumberAdd(Node* node) { return Type::Number(); } ...@@ -1723,6 +1722,14 @@ 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(); }
Type* Typer::Visitor::TypeSpeculativeNumberAdd(Node* node) {
return Type::Number();
}
Type* Typer::Visitor::TypeSpeculativeNumberSubtract(Node* node) {
return Type::Number();
}
Type* Typer::Visitor::TypeNumberMultiply(Node* node) { return Type::Number(); } Type* Typer::Visitor::TypeNumberMultiply(Node* node) { return Type::Number(); }
Type* Typer::Visitor::TypeNumberDivide(Node* node) { return Type::Number(); } Type* Typer::Visitor::TypeNumberDivide(Node* node) { return Type::Number(); }
...@@ -1919,6 +1926,22 @@ Type* Typer::Visitor::TypeChangeBitToTagged(Node* node) { ...@@ -1919,6 +1926,22 @@ Type* Typer::Visitor::TypeChangeBitToTagged(Node* node) {
return ChangeRepresentation(arg, Type::TaggedPointer(), zone()); return ChangeRepresentation(arg, Type::TaggedPointer(), zone());
} }
Type* Typer::Visitor::TypeCheckedUint32ToInt32(Node* node) {
return Type::Signed32();
}
Type* Typer::Visitor::TypeCheckedFloat64ToInt32(Node* node) {
return Type::Signed32();
}
Type* Typer::Visitor::TypeCheckedTaggedToInt32(Node* node) {
return Type::Signed32();
}
Type* Typer::Visitor::TypeCheckedTaggedToFloat64(Node* node) {
return Type::Number();
}
Type* Typer::Visitor::TypeTruncateTaggedToWord32(Node* node) { Type* Typer::Visitor::TypeTruncateTaggedToWord32(Node* node) {
Type* arg = Operand(node, 0); Type* arg = Operand(node, 0);
// TODO(neis): DCHECK(arg->Is(Type::Number())); // TODO(neis): DCHECK(arg->Is(Type::Number()));
......
...@@ -682,6 +682,9 @@ void Verifier::Visitor::Check(Node* node) { ...@@ -682,6 +682,9 @@ void Verifier::Visitor::Check(Node* node) {
CheckValueInputIs(node, 1, Type::NumberOrUndefined()); CheckValueInputIs(node, 1, Type::NumberOrUndefined());
CheckUpperIs(node, Type::Boolean()); CheckUpperIs(node, Type::Boolean());
break; break;
case IrOpcode::kSpeculativeNumberAdd:
case IrOpcode::kSpeculativeNumberSubtract:
break;
case IrOpcode::kNumberAdd: case IrOpcode::kNumberAdd:
case IrOpcode::kNumberSubtract: case IrOpcode::kNumberSubtract:
case IrOpcode::kNumberMultiply: case IrOpcode::kNumberMultiply:
...@@ -901,6 +904,12 @@ void Verifier::Visitor::Check(Node* node) { ...@@ -901,6 +904,12 @@ void Verifier::Visitor::Check(Node* node) {
break; break;
} }
case IrOpcode::kCheckedUint32ToInt32:
case IrOpcode::kCheckedFloat64ToInt32:
case IrOpcode::kCheckedTaggedToInt32:
case IrOpcode::kCheckedTaggedToFloat64:
break;
case IrOpcode::kLoadField: case IrOpcode::kLoadField:
// Object -> fieldtype // Object -> fieldtype
// TODO(rossberg): activate once machine ops are typed. // TODO(rossberg): activate once machine ops are typed.
......
...@@ -449,6 +449,8 @@ DEFINE_BOOL(turbo_asm_deoptimization, false, ...@@ -449,6 +449,8 @@ DEFINE_BOOL(turbo_asm_deoptimization, false,
DEFINE_BOOL(turbo_verify, DEBUG_BOOL, "verify TurboFan graphs at each phase") DEFINE_BOOL(turbo_verify, DEBUG_BOOL, "verify TurboFan graphs at each phase")
DEFINE_BOOL(turbo_stats, false, "print TurboFan statistics") DEFINE_BOOL(turbo_stats, false, "print TurboFan statistics")
DEFINE_BOOL(turbo_splitting, true, "split nodes during scheduling in TurboFan") DEFINE_BOOL(turbo_splitting, true, "split nodes during scheduling in TurboFan")
DEFINE_BOOL(turbo_type_feedback, false,
"use typed feedback for representation inference in Turbofan")
DEFINE_BOOL(turbo_source_positions, false, DEFINE_BOOL(turbo_source_positions, false,
"track source code positions when building TurboFan IR") "track source code positions when building TurboFan IR")
DEFINE_IMPLICATION(trace_turbo, turbo_source_positions) DEFINE_IMPLICATION(trace_turbo, turbo_source_positions)
......
...@@ -628,6 +628,8 @@ ...@@ -628,6 +628,8 @@
'compiler/node.h', 'compiler/node.h',
'compiler/opcodes.cc', 'compiler/opcodes.cc',
'compiler/opcodes.h', 'compiler/opcodes.h',
'compiler/operation-typer.cc',
'compiler/operation-typer.h',
'compiler/operator-properties.cc', 'compiler/operator-properties.cc',
'compiler/operator-properties.h', 'compiler/operator-properties.h',
'compiler/operator.cc', 'compiler/operator.cc',
......
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --allow-natives-syntax --turbo-type-feedback
(function AddSubtractSmis() {
function f0(a, b, c) {
return a + b - c;
}
assertEquals(4, f0(3, 2, 1));
assertEquals(4, f0(3, 2, 1));
%OptimizeFunctionOnNextCall(f0);
assertEquals(4, f0(3, 2, 1));
})();
(function AddSubtractDoubles() {
function f1(a, b, c) {
return a + b - c;
}
assertEquals(4.5, f1(3.5, 2.5, 1.5));
assertEquals(4.5, f1(3.5, 2.5, 1.5));
%OptimizeFunctionOnNextCall(f1);
assertEquals(4.5, f1(3.5, 2.5, 1.5));
assertEquals(4, f1(3, 2, 1));
assertTrue(isNaN(f1(3, 2, undefined)));
assertTrue(isNaN(f1(3, undefined, 1)));
})();
(function CheckUint32ToInt32Conv() {
function f2(a) {
return (a >>> 0) + 1;
}
assertEquals(1, f2(0));
assertEquals(1, f2(0));
%OptimizeFunctionOnNextCall(f2);
assertEquals(1, f2(0));
assertEquals(4294967295, f2(-2));
})();
(function CheckFloat64ToInt32Conv() {
function f3(a, b) {
var x = 0;
if (a) {
x = 0.5;
}
return x + b;
}
assertEquals(1, f3(0, 1));
assertEquals(1, f3(0, 1));
%OptimizeFunctionOnNextCall(f3);
assertEquals(1, f3(0, 1));
assertEquals(1.5, f3(1, 1));
})();
...@@ -87,8 +87,9 @@ class JSTypedLoweringTest : public TypedGraphTest { ...@@ -87,8 +87,9 @@ class JSTypedLoweringTest : public TypedGraphTest {
// TODO(titzer): mock the GraphReducer here for better unit testing. // TODO(titzer): mock the GraphReducer here for better unit testing.
GraphReducer graph_reducer(zone(), graph()); GraphReducer graph_reducer(zone(), graph());
JSTypedLowering reducer(&graph_reducer, &deps_, JSTypedLowering reducer(&graph_reducer, &deps_,
JSTypedLowering::kDeoptimizationEnabled, &jsgraph, JSTypedLowering::kDeoptimizationEnabled |
zone()); JSTypedLowering::kTypeFeedbackEnabled,
&jsgraph, zone());
return reducer.Reduce(node); return reducer.Reduce(node);
} }
...@@ -838,6 +839,52 @@ TEST_F(JSTypedLoweringTest, JSAddWithString) { ...@@ -838,6 +839,52 @@ TEST_F(JSTypedLoweringTest, JSAddWithString) {
lhs, rhs, context, frame_state0, effect, control)); lhs, rhs, context, frame_state0, effect, control));
} }
TEST_F(JSTypedLoweringTest, JSAddSmis) {
BinaryOperationHints const hints(BinaryOperationHints::kSignedSmall,
BinaryOperationHints::kSignedSmall,
BinaryOperationHints::kSignedSmall);
TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) {
Node* lhs = Parameter(Type::Number(), 0);
Node* rhs = Parameter(Type::Number(), 1);
Node* context = Parameter(Type::Any(), 2);
Node* frame_state0 = EmptyFrameState();
Node* frame_state1 = EmptyFrameState();
Node* effect = graph()->start();
Node* control = graph()->start();
Reduction r =
Reduce(graph()->NewNode(javascript()->Add(hints), lhs, rhs, context,
frame_state0, frame_state1, effect, control));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(),
IsSpeculativeNumberAdd(BinaryOperationHints::kSignedSmall, lhs,
rhs, frame_state1, effect, control));
}
}
// -----------------------------------------------------------------------------
// JSSubtract
TEST_F(JSTypedLoweringTest, JSSubtractSmis) {
BinaryOperationHints const hints(BinaryOperationHints::kSignedSmall,
BinaryOperationHints::kSignedSmall,
BinaryOperationHints::kSignedSmall);
TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) {
Node* lhs = Parameter(Type::Number(), 0);
Node* rhs = Parameter(Type::Number(), 1);
Node* context = Parameter(Type::Any(), 2);
Node* frame_state0 = EmptyFrameState();
Node* frame_state1 = EmptyFrameState();
Node* effect = graph()->start();
Node* control = graph()->start();
Reduction r = Reduce(graph()->NewNode(javascript()->Subtract(hints), lhs,
rhs, context, frame_state0,
frame_state1, effect, control));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsSpeculativeNumberSubtract(
BinaryOperationHints::kSignedSmall, lhs,
rhs, frame_state1, effect, control));
}
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// JSInstanceOf // JSInstanceOf
......
...@@ -800,6 +800,46 @@ class IsReferenceEqualMatcher final : public NodeMatcher { ...@@ -800,6 +800,46 @@ class IsReferenceEqualMatcher final : public NodeMatcher {
const Matcher<Node*> rhs_matcher_; const Matcher<Node*> rhs_matcher_;
}; };
class IsSpeculativeBinopMatcher final : public NodeMatcher {
public:
IsSpeculativeBinopMatcher(
IrOpcode::Value opcode,
const Matcher<BinaryOperationHints::Hint>& hint_matcher,
const Matcher<Node*>& lhs_matcher, const Matcher<Node*>& rhs_matcher,
const Matcher<Node*>& frame_state_matcher,
const Matcher<Node*>& effect_matcher,
const Matcher<Node*>& control_matcher)
: NodeMatcher(opcode),
lhs_matcher_(lhs_matcher),
rhs_matcher_(rhs_matcher),
frame_state_matcher_(frame_state_matcher),
effect_matcher_(effect_matcher),
control_matcher_(control_matcher) {}
bool MatchAndExplain(Node* node, MatchResultListener* listener) const final {
return (NodeMatcher::MatchAndExplain(node, listener) &&
// TODO(bmeurer): The type parameter is currently ignored.
PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0), "lhs",
lhs_matcher_, listener) &&
PrintMatchAndExplain(NodeProperties::GetValueInput(node, 1), "rhs",
rhs_matcher_, listener) &&
PrintMatchAndExplain(NodeProperties::GetFrameStateInput(node, 0),
"frame state", frame_state_matcher_,
listener) &&
PrintMatchAndExplain(NodeProperties::GetEffectInput(node), "effect",
effect_matcher_, listener) &&
PrintMatchAndExplain(NodeProperties::GetControlInput(node),
"control", control_matcher_, listener));
}
private:
const Matcher<Type*> type_matcher_;
const Matcher<Node*> lhs_matcher_;
const Matcher<Node*> rhs_matcher_;
const Matcher<Node*> frame_state_matcher_;
const Matcher<Node*> effect_matcher_;
const Matcher<Node*> control_matcher_;
};
class IsAllocateMatcher final : public NodeMatcher { class IsAllocateMatcher final : public NodeMatcher {
public: public:
...@@ -2029,6 +2069,27 @@ Matcher<Node*> IsReferenceEqual(const Matcher<Type*>& type_matcher, ...@@ -2029,6 +2069,27 @@ Matcher<Node*> IsReferenceEqual(const Matcher<Type*>& type_matcher,
new IsReferenceEqualMatcher(type_matcher, lhs_matcher, rhs_matcher)); new IsReferenceEqualMatcher(type_matcher, lhs_matcher, rhs_matcher));
} }
Matcher<Node*> IsSpeculativeNumberAdd(
const Matcher<BinaryOperationHints::Hint>& hint_matcher,
const Matcher<Node*>& lhs_matcher, const Matcher<Node*>& rhs_matcher,
const Matcher<Node*>& frame_state_matcher,
const Matcher<Node*>& effect_matcher,
const Matcher<Node*>& control_matcher) {
return MakeMatcher(new IsSpeculativeBinopMatcher(
IrOpcode::kSpeculativeNumberAdd, hint_matcher, lhs_matcher, rhs_matcher,
frame_state_matcher, effect_matcher, control_matcher));
}
Matcher<Node*> IsSpeculativeNumberSubtract(
const Matcher<BinaryOperationHints::Hint>& hint_matcher,
const Matcher<Node*>& lhs_matcher, const Matcher<Node*>& rhs_matcher,
const Matcher<Node*>& frame_state_matcher,
const Matcher<Node*>& effect_matcher,
const Matcher<Node*>& control_matcher) {
return MakeMatcher(new IsSpeculativeBinopMatcher(
IrOpcode::kSpeculativeNumberSubtract, hint_matcher, lhs_matcher,
rhs_matcher, frame_state_matcher, effect_matcher, control_matcher));
}
Matcher<Node*> IsAllocate(const Matcher<Node*>& size_matcher, Matcher<Node*> IsAllocate(const Matcher<Node*>& size_matcher,
const Matcher<Node*>& effect_matcher, const Matcher<Node*>& effect_matcher,
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#define V8_UNITTESTS_COMPILER_NODE_TEST_UTILS_H_ #define V8_UNITTESTS_COMPILER_NODE_TEST_UTILS_H_
#include "src/compiler/machine-operator.h" #include "src/compiler/machine-operator.h"
#include "src/compiler/type-hints.h"
#include "src/machine-type.h" #include "src/machine-type.h"
#include "testing/gmock/include/gmock/gmock.h" #include "testing/gmock/include/gmock/gmock.h"
...@@ -199,6 +200,20 @@ Matcher<Node*> IsNumberEqual(const Matcher<Node*>& lhs_matcher, ...@@ -199,6 +200,20 @@ Matcher<Node*> IsNumberEqual(const Matcher<Node*>& lhs_matcher,
const Matcher<Node*>& rhs_matcher); const Matcher<Node*>& rhs_matcher);
Matcher<Node*> IsNumberLessThan(const Matcher<Node*>& lhs_matcher, Matcher<Node*> IsNumberLessThan(const Matcher<Node*>& lhs_matcher,
const Matcher<Node*>& rhs_matcher); const Matcher<Node*>& rhs_matcher);
Matcher<Node*> IsNumberAdd(const Matcher<Node*>& lhs_matcher,
const Matcher<Node*>& rhs_matcher);
Matcher<Node*> IsSpeculativeNumberAdd(
const Matcher<BinaryOperationHints::Hint>& hint_matcher,
const Matcher<Node*>& lhs_matcher, const Matcher<Node*>& rhs_matcher,
const Matcher<Node*>& frame_state_matcher,
const Matcher<Node*>& effect_matcher,
const Matcher<Node*>& control_matcher);
Matcher<Node*> IsSpeculativeNumberSubtract(
const Matcher<BinaryOperationHints::Hint>& hint_matcher,
const Matcher<Node*>& lhs_matcher, const Matcher<Node*>& rhs_matcher,
const Matcher<Node*>& frame_state_matcher,
const Matcher<Node*>& effect_matcher,
const Matcher<Node*>& control_matcher);
Matcher<Node*> IsNumberSubtract(const Matcher<Node*>& lhs_matcher, Matcher<Node*> IsNumberSubtract(const Matcher<Node*>& lhs_matcher,
const Matcher<Node*>& rhs_matcher); const Matcher<Node*>& rhs_matcher);
Matcher<Node*> IsNumberMultiply(const Matcher<Node*>& lhs_matcher, Matcher<Node*> IsNumberMultiply(const Matcher<Node*>& lhs_matcher,
......
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