Commit 2c8b5144 authored by bmeurer's avatar bmeurer Committed by Commit bot

[turbofan] Add NumberOperationHint for speculative number operations.

Introduce a dedicated NumberOperationHint enum that represents the
feedback we can use for speculative number operations.

BUG=v8:4930

Review-Url: https://codereview.chromium.org/2220573002
Cr-Commit-Position: refs/heads/master@{#38411}
parent 96c90f6c
......@@ -2,11 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/compiler/js-typed-lowering.h"
#include "src/code-factory.h"
#include "src/compilation-dependencies.h"
#include "src/compiler/access-builder.h"
#include "src/compiler/js-graph.h"
#include "src/compiler/js-typed-lowering.h"
#include "src/compiler/linkage.h"
#include "src/compiler/node-matchers.h"
#include "src/compiler/node-properties.h"
......@@ -27,35 +28,55 @@ class JSBinopReduction final {
JSBinopReduction(JSTypedLowering* lowering, Node* node)
: lowering_(lowering), node_(node) {}
BinaryOperationHints::Hint GetNumberBinaryOperationFeedback() {
bool GetBinaryNumberOperationHint(NumberOperationHint* hint) {
if (lowering_->flags() & JSTypedLowering::kDeoptimizationEnabled) {
DCHECK_NE(0, node_->op()->ControlOutputCount());
DCHECK_EQ(1, node_->op()->EffectOutputCount());
DCHECK_EQ(1, OperatorProperties::GetFrameStateInputCount(node_->op()));
BinaryOperationHints hints = BinaryOperationHintsOf(node_->op());
BinaryOperationHints::Hint combined = hints.combined();
if (combined == BinaryOperationHints::kSignedSmall ||
combined == BinaryOperationHints::kSigned32 ||
combined == BinaryOperationHints::kNumberOrOddball) {
return combined;
switch (hints.combined()) {
case BinaryOperationHints::kSignedSmall:
*hint = NumberOperationHint::kSignedSmall;
return true;
case BinaryOperationHints::kSigned32:
*hint = NumberOperationHint::kSigned32;
return true;
case BinaryOperationHints::kNumberOrOddball:
*hint = NumberOperationHint::kNumberOrOddball;
return true;
case BinaryOperationHints::kAny:
case BinaryOperationHints::kNone:
case BinaryOperationHints::kString:
break;
}
}
return BinaryOperationHints::kAny;
return false;
}
CompareOperationHints::Hint GetNumberCompareOperationFeedback() {
bool GetCompareNumberOperationHint(NumberOperationHint* hint) {
if (lowering_->flags() & JSTypedLowering::kDeoptimizationEnabled) {
DCHECK_NE(0, node_->op()->ControlOutputCount());
DCHECK_EQ(1, node_->op()->EffectOutputCount());
DCHECK_EQ(1, OperatorProperties::GetFrameStateInputCount(node_->op()));
CompareOperationHints hints = CompareOperationHintsOf(node_->op());
CompareOperationHints::Hint combined = hints.combined();
if (combined == CompareOperationHints::kSignedSmall ||
combined == CompareOperationHints::kNumberOrOddball) {
return combined;
switch (hints.combined()) {
case CompareOperationHints::kSignedSmall:
*hint = NumberOperationHint::kSignedSmall;
return true;
case CompareOperationHints::kNumberOrOddball:
*hint = NumberOperationHint::kNumberOrOddball;
return true;
case CompareOperationHints::kAny:
case CompareOperationHints::kNone:
case CompareOperationHints::kString:
case CompareOperationHints::kBoolean:
case CompareOperationHints::kUniqueName:
case CompareOperationHints::kInternalizedString:
case CompareOperationHints::kReceiver:
break;
}
}
return CompareOperationHints::kAny;
return false;
}
void ConvertInputsToNumber() {
......@@ -354,18 +375,17 @@ JSTypedLowering::JSTypedLowering(Editor* editor,
Reduction JSTypedLowering::ReduceJSAdd(Node* node) {
JSBinopReduction r(this, node);
BinaryOperationHints::Hint feedback = r.GetNumberBinaryOperationFeedback();
if (feedback == BinaryOperationHints::kNumberOrOddball &&
r.BothInputsAre(Type::PlainPrimitive()) &&
r.NeitherInputCanBe(Type::StringOrReceiver())) {
// JSAdd(x:-string, y:-string) => NumberAdd(ToNumber(x), ToNumber(y))
r.ConvertInputsToNumber();
return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number());
}
if (feedback != BinaryOperationHints::kAny) {
// Lower to the optimistic number binop.
NumberOperationHint hint;
if (r.GetBinaryNumberOperationHint(&hint)) {
if (hint == NumberOperationHint::kNumberOrOddball &&
r.BothInputsAre(Type::PlainPrimitive()) &&
r.NeitherInputCanBe(Type::StringOrReceiver())) {
// JSAdd(x:-string, y:-string) => NumberAdd(ToNumber(x), ToNumber(y))
r.ConvertInputsToNumber();
return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number());
}
return r.ChangeToSpeculativeOperator(
simplified()->SpeculativeNumberAdd(feedback), Type::Number());
simplified()->SpeculativeNumberAdd(hint), Type::Number());
}
if (r.BothInputsAre(Type::Number())) {
// JSAdd(x:number, y:number) => NumberAdd(x, y)
......@@ -402,75 +422,69 @@ Reduction JSTypedLowering::ReduceJSAdd(Node* node) {
return NoChange();
}
Reduction JSTypedLowering::ReduceJSSubtract(Node* node) {
JSBinopReduction r(this, node);
BinaryOperationHints::Hint feedback = r.GetNumberBinaryOperationFeedback();
if (feedback == BinaryOperationHints::kNumberOrOddball &&
r.BothInputsAre(Type::PlainPrimitive())) {
// JSSubtract(x:plain-primitive, y:plain-primitive)
// => NumberSubtract(ToNumber(x), ToNumber(y))
r.ConvertInputsToNumber();
return r.ChangeToPureOperator(simplified()->NumberSubtract(),
Type::Number());
}
if (feedback != BinaryOperationHints::kAny) {
// Lower to the optimistic number binop.
NumberOperationHint hint;
if (r.GetBinaryNumberOperationHint(&hint)) {
if (hint == NumberOperationHint::kNumberOrOddball &&
r.BothInputsAre(Type::PlainPrimitive())) {
// JSSubtract(x:plain-primitive, y:plain-primitive)
// => NumberSubtract(ToNumber(x), ToNumber(y))
r.ConvertInputsToNumber();
return r.ChangeToPureOperator(simplified()->NumberSubtract(),
Type::Number());
}
return r.ChangeToSpeculativeOperator(
simplified()->SpeculativeNumberSubtract(feedback), Type::Number());
simplified()->SpeculativeNumberSubtract(hint), Type::Number());
}
// If deoptimization is enabled we rely on type feedback.
if (r.BothInputsAre(Type::PlainPrimitive()) ||
!(flags() & kDeoptimizationEnabled)) {
r.ConvertInputsToNumber();
return r.ChangeToPureOperator(simplified()->NumberSubtract(),
Type::Number());
}
return NoChange();
}
Reduction JSTypedLowering::ReduceJSMultiply(Node* node) {
JSBinopReduction r(this, node);
BinaryOperationHints::Hint feedback = r.GetNumberBinaryOperationFeedback();
if (feedback == BinaryOperationHints::kNumberOrOddball &&
r.BothInputsAre(Type::PlainPrimitive())) {
// JSMultiply(x:plain-primitive,
// y:plain-primitive) => NumberMultiply(ToNumber(x), ToNumber(y))
r.ConvertInputsToNumber();
return r.ChangeToPureOperator(simplified()->NumberMultiply(),
Type::Number());
}
if (feedback != BinaryOperationHints::kAny) {
NumberOperationHint hint;
if (r.GetBinaryNumberOperationHint(&hint)) {
if (hint == NumberOperationHint::kNumberOrOddball &&
r.BothInputsAre(Type::PlainPrimitive())) {
// JSMultiply(x:plain-primitive,
// y:plain-primitive) => NumberMultiply(ToNumber(x),
// ToNumber(y))
r.ConvertInputsToNumber();
return r.ChangeToPureOperator(simplified()->NumberMultiply(),
Type::Number());
}
return r.ChangeToSpeculativeOperator(
simplified()->SpeculativeNumberMultiply(feedback), Type::Number());
simplified()->SpeculativeNumberMultiply(hint), Type::Number());
}
// If deoptimization is enabled we rely on type feedback.
if (r.BothInputsAre(Type::PlainPrimitive()) ||
!(flags() & kDeoptimizationEnabled)) {
r.ConvertInputsToNumber();
return r.ChangeToPureOperator(simplified()->NumberMultiply(),
Type::Number());
}
return NoChange();
}
Reduction JSTypedLowering::ReduceJSDivide(Node* node) {
JSBinopReduction r(this, node);
BinaryOperationHints::Hint feedback = r.GetNumberBinaryOperationFeedback();
if (feedback == BinaryOperationHints::kNumberOrOddball &&
r.BothInputsAre(Type::PlainPrimitive())) {
// JSDivide(x:plain-primitive,
// y:plain-primitive) => NumberDivide(ToNumber(x), ToNumber(y))
r.ConvertInputsToNumber();
return r.ChangeToPureOperator(simplified()->NumberDivide(), Type::Number());
}
if (feedback != BinaryOperationHints::kAny) {
NumberOperationHint hint;
if (r.GetBinaryNumberOperationHint(&hint)) {
if (hint == NumberOperationHint::kNumberOrOddball &&
r.BothInputsAre(Type::PlainPrimitive())) {
// JSDivide(x:plain-primitive,
// y:plain-primitive) => NumberDivide(ToNumber(x), ToNumber(y))
r.ConvertInputsToNumber();
return r.ChangeToPureOperator(simplified()->NumberDivide(),
Type::Number());
}
return r.ChangeToSpeculativeOperator(
simplified()->SpeculativeNumberDivide(feedback), Type::Number());
simplified()->SpeculativeNumberDivide(hint), Type::Number());
}
if (r.BothInputsAre(Type::PlainPrimitive())) {
// JSDivide(x:plain-primitive,
......@@ -483,18 +497,18 @@ Reduction JSTypedLowering::ReduceJSDivide(Node* node) {
Reduction JSTypedLowering::ReduceJSModulus(Node* node) {
JSBinopReduction r(this, node);
BinaryOperationHints::Hint feedback = r.GetNumberBinaryOperationFeedback();
if (feedback == BinaryOperationHints::kNumberOrOddball &&
r.BothInputsAre(Type::PlainPrimitive())) {
// JSModulus(x:plain-primitive,
// y:plain-primitive) => NumberModulus(ToNumber(x), ToNumber(y))
r.ConvertInputsToNumber();
return r.ChangeToPureOperator(simplified()->NumberModulus(),
Type::Number());
}
if (feedback != BinaryOperationHints::kAny) {
NumberOperationHint hint;
if (r.GetBinaryNumberOperationHint(&hint)) {
if (hint == NumberOperationHint::kNumberOrOddball &&
r.BothInputsAre(Type::PlainPrimitive())) {
// JSModulus(x:plain-primitive,
// y:plain-primitive) => NumberModulus(ToNumber(x), ToNumber(y))
r.ConvertInputsToNumber();
return r.ChangeToPureOperator(simplified()->NumberModulus(),
Type::Number());
}
return r.ChangeToSpeculativeOperator(
simplified()->SpeculativeNumberModulus(feedback), Type::Number());
simplified()->SpeculativeNumberModulus(hint), Type::Number());
}
if (r.BothInputsAre(Type::PlainPrimitive())) {
// JSModulus(x:plain-primitive,
......@@ -509,21 +523,19 @@ Reduction JSTypedLowering::ReduceJSModulus(Node* node) {
Reduction JSTypedLowering::ReduceInt32Binop(Node* node,
const Operator* int_op) {
JSBinopReduction r(this, node);
BinaryOperationHints::Hint feedback = r.GetNumberBinaryOperationFeedback();
if (feedback != BinaryOperationHints::kAny) {
NumberOperationHint hint;
if (r.GetBinaryNumberOperationHint(&hint)) {
Operator const* speculative_op;
if (int_op->opcode() == IrOpcode::kNumberBitwiseAnd) {
speculative_op = simplified()->SpeculativeNumberBitwiseAnd(feedback);
speculative_op = simplified()->SpeculativeNumberBitwiseAnd(hint);
} else if (int_op->opcode() == IrOpcode::kNumberBitwiseOr) {
speculative_op = simplified()->SpeculativeNumberBitwiseOr(feedback);
speculative_op = simplified()->SpeculativeNumberBitwiseOr(hint);
} else {
DCHECK_EQ(IrOpcode::kNumberBitwiseXor, int_op->opcode());
speculative_op = simplified()->SpeculativeNumberBitwiseXor(feedback);
speculative_op = simplified()->SpeculativeNumberBitwiseXor(hint);
}
return r.ChangeToSpeculativeOperator(speculative_op, Type::Signed32());
}
// If deoptimization is enabled we rely on type feedback.
if (r.BothInputsAre(Type::PlainPrimitive()) ||
!(flags() & kDeoptimizationEnabled)) {
r.ConvertInputsToNumber();
......@@ -533,33 +545,28 @@ Reduction JSTypedLowering::ReduceInt32Binop(Node* node,
return NoChange();
}
Reduction JSTypedLowering::ReduceUI32Shift(Node* node,
Signedness left_signedness,
Reduction JSTypedLowering::ReduceUI32Shift(Node* node, Signedness signedness,
const Operator* shift_op) {
JSBinopReduction r(this, node);
BinaryOperationHints::Hint feedback = r.GetNumberBinaryOperationFeedback();
if (feedback != BinaryOperationHints::kAny) {
NumberOperationHint hint;
if (r.GetBinaryNumberOperationHint(&hint)) {
Operator const* speculative_op;
if (shift_op->opcode() == IrOpcode::kNumberShiftLeft) {
speculative_op = simplified()->SpeculativeNumberShiftLeft(feedback);
speculative_op = simplified()->SpeculativeNumberShiftLeft(hint);
} else if (shift_op->opcode() == IrOpcode::kNumberShiftRightLogical) {
speculative_op =
simplified()->SpeculativeNumberShiftRightLogical(feedback);
speculative_op = simplified()->SpeculativeNumberShiftRightLogical(hint);
} else {
DCHECK_EQ(IrOpcode::kNumberShiftRight, shift_op->opcode());
speculative_op = simplified()->SpeculativeNumberShiftRight(feedback);
speculative_op = simplified()->SpeculativeNumberShiftRight(hint);
}
return r.ChangeToSpeculativeOperator(
speculative_op, shift_op->opcode() == IrOpcode::kNumberShiftRightLogical
? Type::Unsigned32()
: Type::Signed32());
speculative_op,
signedness == kUnsigned ? Type::Unsigned32() : Type::Signed32());
}
// If deoptimization is enabled we rely on type feedback.
if (r.BothInputsAre(Type::PlainPrimitive()) ||
!(flags() & kDeoptimizationEnabled)) {
r.ConvertInputsToNumber();
r.ConvertInputsToUI32(left_signedness, kUnsigned);
r.ConvertInputsToUI32(signedness, kUnsigned);
return r.ChangeToPureOperator(shift_op);
}
return NoChange();
......@@ -592,53 +599,49 @@ Reduction JSTypedLowering::ReduceJSComparison(Node* node) {
return Changed(node);
}
CompareOperationHints::Hint hint = r.GetNumberCompareOperationFeedback();
if (hint != CompareOperationHints::kAny ||
r.OneInputCannotBe(Type::StringOrReceiver())) {
const Operator* less_than;
const Operator* less_than_or_equal;
if (r.BothInputsAre(Type::Signed32()) ||
r.BothInputsAre(Type::Unsigned32())) {
less_than = simplified()->NumberLessThan();
less_than_or_equal = simplified()->NumberLessThanOrEqual();
} else if (hint != CompareOperationHints::kAny) {
less_than = simplified()->SpeculativeNumberLessThan(hint);
less_than_or_equal = simplified()->SpeculativeNumberLessThanOrEqual(hint);
} else if (r.BothInputsAre(Type::PlainPrimitive()) ||
!(flags() & kDeoptimizationEnabled)) {
r.ConvertInputsToNumber();
less_than = simplified()->NumberLessThan();
less_than_or_equal = simplified()->NumberLessThanOrEqual();
} else {
NumberOperationHint hint;
const Operator* less_than;
const Operator* less_than_or_equal;
if (r.BothInputsAre(Type::Signed32()) ||
r.BothInputsAre(Type::Unsigned32())) {
less_than = simplified()->NumberLessThan();
less_than_or_equal = simplified()->NumberLessThanOrEqual();
} else if (r.GetCompareNumberOperationHint(&hint)) {
less_than = simplified()->SpeculativeNumberLessThan(hint);
less_than_or_equal = simplified()->SpeculativeNumberLessThanOrEqual(hint);
} else if (r.OneInputCannotBe(Type::StringOrReceiver()) &&
(r.BothInputsAre(Type::PlainPrimitive()) ||
!(flags() & kDeoptimizationEnabled))) {
r.ConvertInputsToNumber();
less_than = simplified()->NumberLessThan();
less_than_or_equal = simplified()->NumberLessThanOrEqual();
} else {
return NoChange();
}
const Operator* comparison;
switch (node->opcode()) {
case IrOpcode::kJSLessThan:
comparison = less_than;
break;
case IrOpcode::kJSGreaterThan:
comparison = less_than;
r.SwapInputs(); // a > b => b < a
break;
case IrOpcode::kJSLessThanOrEqual:
comparison = less_than_or_equal;
break;
case IrOpcode::kJSGreaterThanOrEqual:
comparison = less_than_or_equal;
r.SwapInputs(); // a >= b => b <= a
break;
default:
return NoChange();
}
const Operator* comparison;
switch (node->opcode()) {
case IrOpcode::kJSLessThan:
comparison = less_than;
break;
case IrOpcode::kJSGreaterThan:
comparison = less_than;
r.SwapInputs(); // a > b => b < a
break;
case IrOpcode::kJSLessThanOrEqual:
comparison = less_than_or_equal;
break;
case IrOpcode::kJSGreaterThanOrEqual:
comparison = less_than_or_equal;
r.SwapInputs(); // a >= b => b <= a
break;
default:
return NoChange();
}
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.
return NoChange(); // Keep a generic comparison.
if (comparison->EffectInputCount() > 0) {
return r.ChangeToSpeculativeOperator(comparison, Type::Boolean());
} else {
return r.ChangeToPureOperator(comparison);
}
}
Reduction JSTypedLowering::ReduceJSEqualTypeOf(Node* node, bool invert) {
......
......@@ -24,6 +24,7 @@ namespace compiler {
class CommonOperatorBuilder;
class JSGraph;
class JSOperatorBuilder;
class MachineOperatorBuilder;
class SimplifiedOperatorBuilder;
......@@ -85,7 +86,7 @@ class JSTypedLowering final : public AdvancedReducer {
Reduction ReduceJSSubtract(Node* node);
Reduction ReduceJSDivide(Node* node);
Reduction ReduceInt32Binop(Node* node, const Operator* intOp);
Reduction ReduceUI32Shift(Node* node, Signedness left_signedness,
Reduction ReduceUI32Shift(Node* node, Signedness signedness,
const Operator* shift_op);
Factory* factory() const;
......
......@@ -87,18 +87,14 @@ MachineRepresentation MachineRepresentationFromArrayType(
return MachineRepresentation::kNone;
}
UseInfo CheckedUseInfoAsWord32FromHint(BinaryOperationHints::Hint hint) {
UseInfo CheckedUseInfoAsWord32FromHint(NumberOperationHint hint) {
switch (hint) {
case BinaryOperationHints::kSignedSmall:
case NumberOperationHint::kSignedSmall:
return UseInfo::CheckedSignedSmallAsWord32();
case BinaryOperationHints::kSigned32:
case NumberOperationHint::kSigned32:
return UseInfo::CheckedSigned32AsWord32();
case BinaryOperationHints::kNumberOrOddball:
case NumberOperationHint::kNumberOrOddball:
return UseInfo::CheckedNumberOrOddballAsWord32();
case BinaryOperationHints::kNone:
case BinaryOperationHints::kString:
case BinaryOperationHints::kAny:
break;
}
UNREACHABLE();
return UseInfo::None();
......@@ -764,7 +760,7 @@ class RepresentationSelector {
return VisitBinop(node, UseInfo::TruncatingWord32(),
MachineRepresentation::kWord32);
}
BinaryOperationHints::Hint hint = BinaryOperationHintOf(node->op());
NumberOperationHint hint = NumberOperationHintOf(node->op());
return VisitBinop(node, CheckedUseInfoAsWord32FromHint(hint),
MachineRepresentation::kWord32);
}
......@@ -1127,7 +1123,7 @@ class RepresentationSelector {
}
// Try to use type feedback.
BinaryOperationHints::Hint hint = BinaryOperationHintOf(node->op());
NumberOperationHint hint = NumberOperationHintOf(node->op());
// Handle the case when no int32 checks on inputs are necessary
// (but an overflow check is needed on the output).
......@@ -1135,8 +1131,8 @@ class RepresentationSelector {
(BothInputsAre(node, Type::Signed32OrMinusZero()) &&
NodeProperties::GetType(node)->Is(type_cache_.kSafeInteger))) {
// If both the inputs the feedback are int32, use the overflow op.
if (hint == BinaryOperationHints::kSignedSmall ||
hint == BinaryOperationHints::kSigned32) {
if (hint == NumberOperationHint::kSignedSmall ||
hint == NumberOperationHint::kSigned32) {
VisitBinop(node, UseInfo::TruncatingWord32(),
MachineRepresentation::kWord32, Type::Signed32());
if (lower()) ChangeToInt32OverflowOp(node);
......@@ -1144,8 +1140,8 @@ class RepresentationSelector {
}
}
if (hint == BinaryOperationHints::kSignedSmall ||
hint == BinaryOperationHints::kSigned32) {
if (hint == NumberOperationHint::kSignedSmall ||
hint == NumberOperationHint::kSigned32) {
VisitBinop(node, CheckedUseInfoAsWord32FromHint(hint),
MachineRepresentation::kWord32, Type::Signed32());
if (lower()) ChangeToInt32OverflowOp(node);
......@@ -1350,15 +1346,15 @@ class RepresentationSelector {
return;
}
// Try to use type feedback.
CompareOperationHints::Hint hint = CompareOperationHintOf(node->op());
NumberOperationHint hint = NumberOperationHintOf(node->op());
if (hint == CompareOperationHints::kSignedSmall) {
if (hint == NumberOperationHint::kSignedSmall) {
VisitBinop(node, UseInfo::CheckedSigned32AsWord32(),
MachineRepresentation::kBit);
if (lower()) ChangeToPureOp(node, Int32Op(node));
return;
}
DCHECK_EQ(CompareOperationHints::kNumberOrOddball, hint);
DCHECK_EQ(NumberOperationHint::kNumberOrOddball, hint);
// default case => Float64 comparison
VisitBinop(node, UseInfo::CheckedNumberOrOddballAsFloat64(),
MachineRepresentation::kBit);
......@@ -1412,7 +1408,7 @@ class RepresentationSelector {
return;
}
// Try to use type feedback.
BinaryOperationHints::Hint hint = BinaryOperationHintOf(node->op());
NumberOperationHint hint = NumberOperationHintOf(node->op());
Type* input0_type = TypeOf(node->InputAt(0));
Type* input1_type = TypeOf(node->InputAt(1));
......@@ -1420,8 +1416,8 @@ class RepresentationSelector {
// (but an overflow check is needed on the output).
if (BothInputsAre(node, Type::Signed32())) {
// If both the inputs the feedback are int32, use the overflow op.
if (hint == BinaryOperationHints::kSignedSmall ||
hint == BinaryOperationHints::kSigned32) {
if (hint == NumberOperationHint::kSignedSmall ||
hint == NumberOperationHint::kSigned32) {
VisitBinop(node, UseInfo::TruncatingWord32(),
MachineRepresentation::kWord32, Type::Signed32());
if (lower()) {
......@@ -1432,8 +1428,8 @@ class RepresentationSelector {
}
}
if (hint == BinaryOperationHints::kSignedSmall ||
hint == BinaryOperationHints::kSigned32) {
if (hint == NumberOperationHint::kSignedSmall ||
hint == NumberOperationHint::kSigned32) {
VisitBinop(node, CheckedUseInfoAsWord32FromHint(hint),
MachineRepresentation::kWord32, Type::Signed32());
if (lower()) {
......@@ -1499,13 +1495,13 @@ class RepresentationSelector {
}
// Try to use type feedback.
BinaryOperationHints::Hint hint = BinaryOperationHintOf(node->op());
NumberOperationHint hint = NumberOperationHintOf(node->op());
// Handle the case when no uint32 checks on inputs are necessary
// (but an overflow check is needed on the output).
if (BothInputsAreUnsigned32(node)) {
if (hint == BinaryOperationHints::kSignedSmall ||
hint == BinaryOperationHints::kSigned32) {
if (hint == NumberOperationHint::kSignedSmall ||
hint == NumberOperationHint::kSigned32) {
VisitBinop(node, UseInfo::TruncatingWord32(),
MachineRepresentation::kWord32, Type::Unsigned32());
if (lower()) ChangeToUint32OverflowOp(node);
......@@ -1517,8 +1513,8 @@ class RepresentationSelector {
// (but an overflow check is needed on the output).
if (BothInputsAreSigned32(node)) {
// If both the inputs the feedback are int32, use the overflow op.
if (hint == BinaryOperationHints::kSignedSmall ||
hint == BinaryOperationHints::kSigned32) {
if (hint == NumberOperationHint::kSignedSmall ||
hint == NumberOperationHint::kSigned32) {
VisitBinop(node, UseInfo::TruncatingWord32(),
MachineRepresentation::kWord32, Type::Signed32());
if (lower()) ChangeToInt32OverflowOp(node);
......@@ -1526,8 +1522,8 @@ class RepresentationSelector {
}
}
if (hint == BinaryOperationHints::kSignedSmall ||
hint == BinaryOperationHints::kSigned32) {
if (hint == NumberOperationHint::kSignedSmall ||
hint == NumberOperationHint::kSigned32) {
// If the result is truncated, we only need to check the inputs.
if (truncation.IsUsedAsWord32()) {
VisitBinop(node, CheckedUseInfoAsWord32FromHint(hint),
......@@ -1607,13 +1603,13 @@ class RepresentationSelector {
}
// Try to use type feedback.
BinaryOperationHints::Hint hint = BinaryOperationHintOf(node->op());
NumberOperationHint hint = NumberOperationHintOf(node->op());
// Handle the case when no uint32 checks on inputs are necessary
// (but an overflow check is needed on the output).
if (BothInputsAreUnsigned32(node)) {
if (hint == BinaryOperationHints::kSignedSmall ||
hint == BinaryOperationHints::kSigned32) {
if (hint == NumberOperationHint::kSignedSmall ||
hint == NumberOperationHint::kSigned32) {
VisitBinop(node, UseInfo::TruncatingWord32(),
MachineRepresentation::kWord32, Type::Unsigned32());
if (lower()) ChangeToUint32OverflowOp(node);
......@@ -1625,8 +1621,8 @@ class RepresentationSelector {
// (but an overflow check is needed on the output).
if (BothInputsAre(node, Type::Signed32())) {
// If both the inputs the feedback are int32, use the overflow op.
if (hint == BinaryOperationHints::kSignedSmall ||
hint == BinaryOperationHints::kSigned32) {
if (hint == NumberOperationHint::kSignedSmall ||
hint == NumberOperationHint::kSigned32) {
VisitBinop(node, UseInfo::TruncatingWord32(),
MachineRepresentation::kWord32, Type::Signed32());
if (lower()) ChangeToInt32OverflowOp(node);
......@@ -1634,8 +1630,8 @@ class RepresentationSelector {
}
}
if (hint == BinaryOperationHints::kSignedSmall ||
hint == BinaryOperationHints::kSigned32) {
if (hint == NumberOperationHint::kSignedSmall ||
hint == NumberOperationHint::kSigned32) {
// If the result is truncated, we only need to check the inputs.
if (truncation.IsUsedAsWord32()) {
VisitBinop(node, CheckedUseInfoAsWord32FromHint(hint),
......@@ -1767,7 +1763,7 @@ class RepresentationSelector {
}
return;
}
BinaryOperationHints::Hint hint = BinaryOperationHintOf(node->op());
NumberOperationHint hint = NumberOperationHintOf(node->op());
Type* rhs_type = GetUpperBound(node->InputAt(1));
VisitBinop(node, CheckedUseInfoAsWord32FromHint(hint),
MachineRepresentation::kWord32, Type::Signed32());
......@@ -1803,7 +1799,7 @@ class RepresentationSelector {
}
return;
}
BinaryOperationHints::Hint hint = BinaryOperationHintOf(node->op());
NumberOperationHint hint = NumberOperationHintOf(node->op());
Type* rhs_type = GetUpperBound(node->InputAt(1));
VisitBinop(node, CheckedUseInfoAsWord32FromHint(hint),
MachineRepresentation::kWord32, Type::Signed32());
......@@ -1839,7 +1835,7 @@ class RepresentationSelector {
}
return;
}
BinaryOperationHints::Hint hint = BinaryOperationHintOf(node->op());
NumberOperationHint hint = NumberOperationHintOf(node->op());
Type* rhs_type = GetUpperBound(node->InputAt(1));
VisitBinop(node, CheckedUseInfoAsWord32FromHint(hint),
MachineRepresentation::kWord32, Type::Unsigned32());
......
......@@ -269,7 +269,24 @@ ElementsTransition ElementsTransitionOf(const Operator* op) {
return OpParameter<ElementsTransition>(op);
}
BinaryOperationHints::Hint BinaryOperationHintOf(const Operator* op) {
std::ostream& operator<<(std::ostream& os, NumberOperationHint hint) {
switch (hint) {
case NumberOperationHint::kSignedSmall:
return os << "SignedSmall";
case NumberOperationHint::kSigned32:
return os << "Signed32";
case NumberOperationHint::kNumberOrOddball:
return os << "NumberOrOddball";
}
UNREACHABLE();
return os;
}
size_t hash_value(NumberOperationHint hint) {
return static_cast<uint8_t>(hint);
}
NumberOperationHint NumberOperationHintOf(const Operator* op) {
DCHECK(op->opcode() == IrOpcode::kSpeculativeNumberAdd ||
op->opcode() == IrOpcode::kSpeculativeNumberSubtract ||
op->opcode() == IrOpcode::kSpeculativeNumberMultiply ||
......@@ -280,15 +297,11 @@ BinaryOperationHints::Hint BinaryOperationHintOf(const Operator* op) {
op->opcode() == IrOpcode::kSpeculativeNumberShiftRightLogical ||
op->opcode() == IrOpcode::kSpeculativeNumberBitwiseAnd ||
op->opcode() == IrOpcode::kSpeculativeNumberBitwiseOr ||
op->opcode() == IrOpcode::kSpeculativeNumberBitwiseXor);
return OpParameter<BinaryOperationHints::Hint>(op);
}
CompareOperationHints::Hint CompareOperationHintOf(const Operator* op) {
DCHECK(op->opcode() == IrOpcode::kSpeculativeNumberEqual ||
op->opcode() == IrOpcode::kSpeculativeNumberBitwiseXor ||
op->opcode() == IrOpcode::kSpeculativeNumberEqual ||
op->opcode() == IrOpcode::kSpeculativeNumberLessThan ||
op->opcode() == IrOpcode::kSpeculativeNumberLessThanOrEqual);
return OpParameter<CompareOperationHints::Hint>(op);
return OpParameter<NumberOperationHint>(op);
}
#define PURE_OP_LIST(V) \
......@@ -370,18 +383,11 @@ CompareOperationHints::Hint CompareOperationHintOf(const Operator* op) {
V(StringLessThan, Operator::kNoProperties, 2, 0) \
V(StringLessThanOrEqual, Operator::kNoProperties, 2, 0)
#define SPECULATIVE_BINOP_LIST(V) \
V(SpeculativeNumberAdd) \
V(SpeculativeNumberSubtract) \
V(SpeculativeNumberDivide) \
V(SpeculativeNumberMultiply) \
V(SpeculativeNumberModulus) \
V(SpeculativeNumberShiftLeft) \
V(SpeculativeNumberShiftRight) \
V(SpeculativeNumberShiftRightLogical) \
V(SpeculativeNumberBitwiseAnd) \
V(SpeculativeNumberBitwiseOr) \
V(SpeculativeNumberBitwiseXor)
#define SPECULATIVE_NUMBER_BINOP_LIST(V) \
SIMPLIFIED_SPECULATIVE_NUMBER_BINOP_LIST(V) \
V(SpeculativeNumberEqual) \
V(SpeculativeNumberLessThan) \
V(SpeculativeNumberLessThanOrEqual)
#define CHECKED_OP_LIST(V) \
V(CheckBounds, 2, 1) \
......@@ -513,6 +519,22 @@ struct SimplifiedOperatorGlobalCache final {
};
EnsureWritableFastElementsOperator kEnsureWritableFastElements;
#define SPECULATIVE_NUMBER_BINOP(Name) \
template <NumberOperationHint kHint> \
struct Name##Operator final : public Operator1<NumberOperationHint> { \
Name##Operator() \
: Operator1<NumberOperationHint>( \
IrOpcode::k##Name, Operator::kFoldable | Operator::kNoThrow, \
#Name, 2, 1, 1, 1, 1, 0, kHint) {} \
}; \
Name##Operator<NumberOperationHint::kSignedSmall> \
k##Name##SignedSmallOperator; \
Name##Operator<NumberOperationHint::kSigned32> k##Name##Signed32Operator; \
Name##Operator<NumberOperationHint::kNumberOrOddball> \
k##Name##NumberOrOddballOperator;
SPECULATIVE_NUMBER_BINOP_LIST(SPECULATIVE_NUMBER_BINOP)
#undef SPECULATIVE_NUMBER_BINOP
#define BUFFER_ACCESS(Type, type, TYPE, ctype, size) \
struct LoadBuffer##Type##Operator final : public Operator1<BufferAccess> { \
LoadBuffer##Type##Operator() \
......@@ -679,39 +701,21 @@ const Operator* SimplifiedOperatorBuilder::StoreBuffer(BufferAccess access) {
return nullptr;
}
#define SPECULATIVE_BINOP_DEF(Name) \
const Operator* SimplifiedOperatorBuilder::Name( \
BinaryOperationHints::Hint hint) { \
return new (zone()) Operator1<BinaryOperationHints::Hint>( \
IrOpcode::k##Name, Operator::kFoldable | Operator::kNoThrow, #Name, 2, \
1, 1, 1, 1, 0, hint); \
#define SPECULATIVE_NUMBER_BINOP(Name) \
const Operator* SimplifiedOperatorBuilder::Name(NumberOperationHint hint) { \
switch (hint) { \
case NumberOperationHint::kSignedSmall: \
return &cache_.k##Name##SignedSmallOperator; \
case NumberOperationHint::kSigned32: \
return &cache_.k##Name##Signed32Operator; \
case NumberOperationHint::kNumberOrOddball: \
return &cache_.k##Name##NumberOrOddballOperator; \
} \
UNREACHABLE(); \
return nullptr; \
}
SPECULATIVE_BINOP_LIST(SPECULATIVE_BINOP_DEF)
#undef SPECULATIVE_BINOP_DEF
const Operator* SimplifiedOperatorBuilder::SpeculativeNumberEqual(
CompareOperationHints::Hint hint) {
return new (zone()) Operator1<CompareOperationHints::Hint>(
IrOpcode::kSpeculativeNumberEqual,
Operator::kFoldable | Operator::kNoThrow, "SpeculativeNumberEqual", 2, 1,
1, 1, 1, 0, hint);
}
const Operator* SimplifiedOperatorBuilder::SpeculativeNumberLessThan(
CompareOperationHints::Hint hint) {
return new (zone()) Operator1<CompareOperationHints::Hint>(
IrOpcode::kSpeculativeNumberLessThan,
Operator::kFoldable | Operator::kNoThrow, "SpeculativeNumberLessThan", 2,
1, 1, 1, 1, 0, hint);
}
const Operator* SimplifiedOperatorBuilder::SpeculativeNumberLessThanOrEqual(
CompareOperationHints::Hint hint) {
return new (zone()) Operator1<CompareOperationHints::Hint>(
IrOpcode::kSpeculativeNumberLessThanOrEqual,
Operator::kFoldable | Operator::kNoThrow,
"SpeculativeNumberLessThanOrEqual", 2, 1, 1, 1, 1, 0, hint);
}
SPECULATIVE_NUMBER_BINOP_LIST(SPECULATIVE_NUMBER_BINOP)
#undef SPECULATIVE_NUMBER_BINOP
#define ACCESS_OP_LIST(V) \
V(LoadField, FieldAccess, Operator::kNoWrite, 1, 1, 1) \
......
......@@ -8,7 +8,6 @@
#include <iosfwd>
#include "src/compiler/operator.h"
#include "src/compiler/type-hints.h"
#include "src/handles.h"
#include "src/machine-type.h"
#include "src/objects.h"
......@@ -154,9 +153,19 @@ std::ostream& operator<<(std::ostream&, ElementsTransition);
ElementsTransition ElementsTransitionOf(const Operator* op) WARN_UNUSED_RESULT;
BinaryOperationHints::Hint BinaryOperationHintOf(const Operator* op);
// A hint for speculative number operations.
enum class NumberOperationHint : uint8_t {
kSignedSmall, // Inputs were always Smi so far, output was in Smi range.
kSigned32, // Inputs and output were Signed32 so far.
kNumberOrOddball, // Inputs were Number or Oddball, output was Number.
};
size_t hash_value(NumberOperationHint);
std::ostream& operator<<(std::ostream&, NumberOperationHint);
CompareOperationHints::Hint CompareOperationHintOf(const Operator* op);
NumberOperationHint NumberOperationHintOf(const Operator* op)
WARN_UNUSED_RESULT;
// Interface for building simplified operators, which represent the
// medium-level operations of V8, including adding numbers, allocating objects,
......@@ -238,23 +247,21 @@ class SimplifiedOperatorBuilder final : public ZoneObject {
const Operator* NumberSilenceNaN();
const Operator* SpeculativeNumberAdd(BinaryOperationHints::Hint hint);
const Operator* SpeculativeNumberSubtract(BinaryOperationHints::Hint hint);
const Operator* SpeculativeNumberMultiply(BinaryOperationHints::Hint hint);
const Operator* SpeculativeNumberDivide(BinaryOperationHints::Hint hint);
const Operator* SpeculativeNumberModulus(BinaryOperationHints::Hint hint);
const Operator* SpeculativeNumberShiftLeft(BinaryOperationHints::Hint hint);
const Operator* SpeculativeNumberShiftRight(BinaryOperationHints::Hint hint);
const Operator* SpeculativeNumberShiftRightLogical(
BinaryOperationHints::Hint hint);
const Operator* SpeculativeNumberBitwiseAnd(BinaryOperationHints::Hint hint);
const Operator* SpeculativeNumberBitwiseOr(BinaryOperationHints::Hint hint);
const Operator* SpeculativeNumberBitwiseXor(BinaryOperationHints::Hint hint);
const Operator* SpeculativeNumberLessThan(CompareOperationHints::Hint hint);
const Operator* SpeculativeNumberLessThanOrEqual(
CompareOperationHints::Hint hint);
const Operator* SpeculativeNumberEqual(CompareOperationHints::Hint hint);
const Operator* SpeculativeNumberAdd(NumberOperationHint hint);
const Operator* SpeculativeNumberSubtract(NumberOperationHint hint);
const Operator* SpeculativeNumberMultiply(NumberOperationHint hint);
const Operator* SpeculativeNumberDivide(NumberOperationHint hint);
const Operator* SpeculativeNumberModulus(NumberOperationHint hint);
const Operator* SpeculativeNumberShiftLeft(NumberOperationHint hint);
const Operator* SpeculativeNumberShiftRight(NumberOperationHint hint);
const Operator* SpeculativeNumberShiftRightLogical(NumberOperationHint hint);
const Operator* SpeculativeNumberBitwiseAnd(NumberOperationHint hint);
const Operator* SpeculativeNumberBitwiseOr(NumberOperationHint hint);
const Operator* SpeculativeNumberBitwiseXor(NumberOperationHint hint);
const Operator* SpeculativeNumberLessThan(NumberOperationHint hint);
const Operator* SpeculativeNumberLessThanOrEqual(NumberOperationHint hint);
const Operator* SpeculativeNumberEqual(NumberOperationHint hint);
const Operator* ReferenceEqual(Type* type);
......
......@@ -416,7 +416,6 @@ TEST_F(JSTypedLoweringTest, JSStrictEqualWithUnique) {
// -----------------------------------------------------------------------------
// JSShiftLeft
TEST_F(JSTypedLoweringTest, JSShiftLeftWithSigned32AndConstant) {
BinaryOperationHints const hints = BinaryOperationHints::Any();
Node* const lhs = Parameter(Type::Signed32());
......@@ -433,7 +432,6 @@ TEST_F(JSTypedLoweringTest, JSShiftLeftWithSigned32AndConstant) {
}
}
TEST_F(JSTypedLoweringTest, JSShiftLeftWithSigned32AndUnsigned32) {
BinaryOperationHints const hints = BinaryOperationHints::Any();
Node* const lhs = Parameter(Type::Signed32());
......@@ -448,23 +446,55 @@ TEST_F(JSTypedLoweringTest, JSShiftLeftWithSigned32AndUnsigned32) {
EXPECT_THAT(r.replacement(), IsNumberShiftLeft(lhs, rhs));
}
TEST_F(JSTypedLoweringTest, JSShiftLeftWithTypeFeedback) {
BinaryOperationHints::Hint const feedback_types[] = {
BinaryOperationHints::kSignedSmall,
BinaryOperationHints::kNumberOrOddball};
for (BinaryOperationHints::Hint feedback : feedback_types) {
BinaryOperationHints const hints(feedback, feedback, feedback);
Node* lhs = Parameter(Type::Number(), 2);
Node* rhs = Parameter(Type::Number(), 3);
Node* effect = graph()->start();
Node* control = graph()->start();
Reduction r = Reduce(graph()->NewNode(javascript()->ShiftLeft(hints), lhs,
rhs, UndefinedConstant(),
EmptyFrameState(), effect, control));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsSpeculativeNumberShiftLeft(
feedback, lhs, rhs, effect, control));
}
TEST_F(JSTypedLoweringTest, JSShiftLeftWithSignedSmallHint) {
BinaryOperationHints const hints(BinaryOperationHints::kSignedSmall,
BinaryOperationHints::kSignedSmall,
BinaryOperationHints::kSignedSmall);
Node* lhs = Parameter(Type::Number(), 2);
Node* rhs = Parameter(Type::Number(), 3);
Node* effect = graph()->start();
Node* control = graph()->start();
Reduction r = Reduce(graph()->NewNode(javascript()->ShiftLeft(hints), lhs,
rhs, UndefinedConstant(),
EmptyFrameState(), effect, control));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(),
IsSpeculativeNumberShiftLeft(NumberOperationHint::kSignedSmall,
lhs, rhs, effect, control));
}
TEST_F(JSTypedLoweringTest, JSShiftLeftWithSigned32Hint) {
BinaryOperationHints const hints(BinaryOperationHints::kSigned32,
BinaryOperationHints::kSigned32,
BinaryOperationHints::kSigned32);
Node* lhs = Parameter(Type::Number(), 2);
Node* rhs = Parameter(Type::Number(), 3);
Node* effect = graph()->start();
Node* control = graph()->start();
Reduction r = Reduce(graph()->NewNode(javascript()->ShiftLeft(hints), lhs,
rhs, UndefinedConstant(),
EmptyFrameState(), effect, control));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(),
IsSpeculativeNumberShiftLeft(NumberOperationHint::kSigned32, lhs,
rhs, effect, control));
}
TEST_F(JSTypedLoweringTest, JSShiftLeftWithNumberOrOddballHint) {
BinaryOperationHints const hints(BinaryOperationHints::kNumberOrOddball,
BinaryOperationHints::kNumberOrOddball,
BinaryOperationHints::kNumberOrOddball);
Node* lhs = Parameter(Type::Number(), 2);
Node* rhs = Parameter(Type::Number(), 3);
Node* effect = graph()->start();
Node* control = graph()->start();
Reduction r = Reduce(graph()->NewNode(javascript()->ShiftLeft(hints), lhs,
rhs, UndefinedConstant(),
EmptyFrameState(), effect, control));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsSpeculativeNumberShiftLeft(
NumberOperationHint::kNumberOrOddball, lhs,
rhs, effect, control));
}
// -----------------------------------------------------------------------------
......@@ -502,23 +532,55 @@ TEST_F(JSTypedLoweringTest, JSShiftRightWithSigned32AndUnsigned32) {
EXPECT_THAT(r.replacement(), IsNumberShiftRight(lhs, rhs));
}
TEST_F(JSTypedLoweringTest, JSShiftRightWithTypeFeedback) {
BinaryOperationHints::Hint const feedback_types[] = {
BinaryOperationHints::kSignedSmall,
BinaryOperationHints::kNumberOrOddball};
for (BinaryOperationHints::Hint feedback : feedback_types) {
BinaryOperationHints const hints(feedback, feedback, feedback);
Node* lhs = Parameter(Type::Number(), 2);
Node* rhs = Parameter(Type::Number(), 3);
Node* effect = graph()->start();
Node* control = graph()->start();
Reduction r = Reduce(graph()->NewNode(javascript()->ShiftRight(hints), lhs,
rhs, UndefinedConstant(),
EmptyFrameState(), effect, control));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsSpeculativeNumberShiftRight(
feedback, lhs, rhs, effect, control));
}
TEST_F(JSTypedLoweringTest, JSShiftRightWithSignedSmallHint) {
BinaryOperationHints const hints(BinaryOperationHints::kSignedSmall,
BinaryOperationHints::kSignedSmall,
BinaryOperationHints::kSignedSmall);
Node* lhs = Parameter(Type::Number(), 2);
Node* rhs = Parameter(Type::Number(), 3);
Node* effect = graph()->start();
Node* control = graph()->start();
Reduction r = Reduce(graph()->NewNode(javascript()->ShiftRight(hints), lhs,
rhs, UndefinedConstant(),
EmptyFrameState(), effect, control));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(),
IsSpeculativeNumberShiftRight(NumberOperationHint::kSignedSmall,
lhs, rhs, effect, control));
}
TEST_F(JSTypedLoweringTest, JSShiftRightWithSigned32Hint) {
BinaryOperationHints const hints(BinaryOperationHints::kSigned32,
BinaryOperationHints::kSigned32,
BinaryOperationHints::kSigned32);
Node* lhs = Parameter(Type::Number(), 2);
Node* rhs = Parameter(Type::Number(), 3);
Node* effect = graph()->start();
Node* control = graph()->start();
Reduction r = Reduce(graph()->NewNode(javascript()->ShiftRight(hints), lhs,
rhs, UndefinedConstant(),
EmptyFrameState(), effect, control));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(),
IsSpeculativeNumberShiftRight(NumberOperationHint::kSigned32, lhs,
rhs, effect, control));
}
TEST_F(JSTypedLoweringTest, JSShiftRightWithNumberOrOddballHint) {
BinaryOperationHints const hints(BinaryOperationHints::kNumberOrOddball,
BinaryOperationHints::kNumberOrOddball,
BinaryOperationHints::kNumberOrOddball);
Node* lhs = Parameter(Type::Number(), 2);
Node* rhs = Parameter(Type::Number(), 3);
Node* effect = graph()->start();
Node* control = graph()->start();
Reduction r = Reduce(graph()->NewNode(javascript()->ShiftRight(hints), lhs,
rhs, UndefinedConstant(),
EmptyFrameState(), effect, control));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsSpeculativeNumberShiftRight(
NumberOperationHint::kNumberOrOddball, lhs,
rhs, effect, control));
}
// -----------------------------------------------------------------------------
......@@ -557,23 +619,55 @@ TEST_F(JSTypedLoweringTest, JSShiftRightLogicalWithUnsigned32AndUnsigned32) {
EXPECT_THAT(r.replacement(), IsNumberShiftRightLogical(lhs, rhs));
}
TEST_F(JSTypedLoweringTest, JSShiftRightLogicalWithTypeFeedback) {
BinaryOperationHints::Hint const feedback_types[] = {
BinaryOperationHints::kSignedSmall,
BinaryOperationHints::kNumberOrOddball};
for (BinaryOperationHints::Hint feedback : feedback_types) {
BinaryOperationHints const hints(feedback, feedback, feedback);
Node* lhs = Parameter(Type::Number(), 2);
Node* rhs = Parameter(Type::Number(), 3);
Node* effect = graph()->start();
Node* control = graph()->start();
Reduction r = Reduce(graph()->NewNode(
javascript()->ShiftRightLogical(hints), lhs, rhs, UndefinedConstant(),
EmptyFrameState(), effect, control));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsSpeculativeNumberShiftRightLogical(
feedback, lhs, rhs, effect, control));
}
TEST_F(JSTypedLoweringTest, JSShiftRightLogicalWithSignedSmallHint) {
BinaryOperationHints const hints(BinaryOperationHints::kSignedSmall,
BinaryOperationHints::kSignedSmall,
BinaryOperationHints::kSignedSmall);
Node* lhs = Parameter(Type::Number(), 2);
Node* rhs = Parameter(Type::Number(), 3);
Node* effect = graph()->start();
Node* control = graph()->start();
Reduction r = Reduce(graph()->NewNode(javascript()->ShiftRightLogical(hints),
lhs, rhs, UndefinedConstant(),
EmptyFrameState(), effect, control));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsSpeculativeNumberShiftRightLogical(
NumberOperationHint::kSignedSmall, lhs, rhs,
effect, control));
}
TEST_F(JSTypedLoweringTest, JSShiftRightLogicalWithSigned32Hint) {
BinaryOperationHints const hints(BinaryOperationHints::kSigned32,
BinaryOperationHints::kSigned32,
BinaryOperationHints::kSigned32);
Node* lhs = Parameter(Type::Number(), 2);
Node* rhs = Parameter(Type::Number(), 3);
Node* effect = graph()->start();
Node* control = graph()->start();
Reduction r = Reduce(graph()->NewNode(javascript()->ShiftRightLogical(hints),
lhs, rhs, UndefinedConstant(),
EmptyFrameState(), effect, control));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(),
IsSpeculativeNumberShiftRightLogical(
NumberOperationHint::kSigned32, lhs, rhs, effect, control));
}
TEST_F(JSTypedLoweringTest, JSShiftRightLogicalWithNumberOrOddballHint) {
BinaryOperationHints const hints(BinaryOperationHints::kNumberOrOddball,
BinaryOperationHints::kNumberOrOddball,
BinaryOperationHints::kNumberOrOddball);
Node* lhs = Parameter(Type::Number(), 2);
Node* rhs = Parameter(Type::Number(), 3);
Node* effect = graph()->start();
Node* control = graph()->start();
Reduction r = Reduce(graph()->NewNode(javascript()->ShiftRightLogical(hints),
lhs, rhs, UndefinedConstant(),
EmptyFrameState(), effect, control));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsSpeculativeNumberShiftRightLogical(
NumberOperationHint::kNumberOrOddball, lhs,
rhs, effect, control));
}
// -----------------------------------------------------------------------------
......@@ -919,7 +1013,7 @@ TEST_F(JSTypedLoweringTest, JSAddSmis) {
context, frame_state, effect, control));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(),
IsSpeculativeNumberAdd(BinaryOperationHints::kSignedSmall, lhs,
IsSpeculativeNumberAdd(NumberOperationHint::kSignedSmall, lhs,
rhs, effect, control));
}
......@@ -940,7 +1034,7 @@ TEST_F(JSTypedLoweringTest, JSSubtractSmis) {
context, frame_state, effect, control));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(),
IsSpeculativeNumberSubtract(BinaryOperationHints::kSignedSmall,
IsSpeculativeNumberSubtract(NumberOperationHint::kSignedSmall,
lhs, rhs, effect, control));
}
......@@ -1009,67 +1103,163 @@ TEST_F(JSTypedLoweringTest, JSInstanceOfNoSpecialization) {
// -----------------------------------------------------------------------------
// JSBitwiseAnd
TEST_F(JSTypedLoweringTest, JSBitwiseAndWithTypeFeedback) {
BinaryOperationHints::Hint const feedback_types[] = {
BinaryOperationHints::kSignedSmall,
BinaryOperationHints::kNumberOrOddball};
for (BinaryOperationHints::Hint feedback : feedback_types) {
BinaryOperationHints const hints(feedback, feedback, feedback);
Node* lhs = Parameter(Type::Number(), 2);
Node* rhs = Parameter(Type::Number(), 3);
Node* effect = graph()->start();
Node* control = graph()->start();
Reduction r = Reduce(graph()->NewNode(javascript()->BitwiseAnd(hints), lhs,
rhs, UndefinedConstant(),
EmptyFrameState(), effect, control));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsSpeculativeNumberBitwiseAnd(
feedback, lhs, rhs, effect, control));
}
TEST_F(JSTypedLoweringTest, JSBitwiseAndWithSignedSmallHint) {
BinaryOperationHints const hints(BinaryOperationHints::kSignedSmall,
BinaryOperationHints::kSignedSmall,
BinaryOperationHints::kSignedSmall);
Node* lhs = Parameter(Type::Number(), 2);
Node* rhs = Parameter(Type::Number(), 3);
Node* effect = graph()->start();
Node* control = graph()->start();
Reduction r = Reduce(graph()->NewNode(javascript()->BitwiseAnd(hints), lhs,
rhs, UndefinedConstant(),
EmptyFrameState(), effect, control));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(),
IsSpeculativeNumberBitwiseAnd(NumberOperationHint::kSignedSmall,
lhs, rhs, effect, control));
}
TEST_F(JSTypedLoweringTest, JSBitwiseAndWithSigned32Hint) {
BinaryOperationHints const hints(BinaryOperationHints::kSigned32,
BinaryOperationHints::kSigned32,
BinaryOperationHints::kSigned32);
Node* lhs = Parameter(Type::Number(), 2);
Node* rhs = Parameter(Type::Number(), 3);
Node* effect = graph()->start();
Node* control = graph()->start();
Reduction r = Reduce(graph()->NewNode(javascript()->BitwiseAnd(hints), lhs,
rhs, UndefinedConstant(),
EmptyFrameState(), effect, control));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(),
IsSpeculativeNumberBitwiseAnd(NumberOperationHint::kSigned32, lhs,
rhs, effect, control));
}
TEST_F(JSTypedLoweringTest, JSBitwiseAndWithNumberOrOddballHint) {
BinaryOperationHints const hints(BinaryOperationHints::kNumberOrOddball,
BinaryOperationHints::kNumberOrOddball,
BinaryOperationHints::kNumberOrOddball);
Node* lhs = Parameter(Type::Number(), 2);
Node* rhs = Parameter(Type::Number(), 3);
Node* effect = graph()->start();
Node* control = graph()->start();
Reduction r = Reduce(graph()->NewNode(javascript()->BitwiseAnd(hints), lhs,
rhs, UndefinedConstant(),
EmptyFrameState(), effect, control));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsSpeculativeNumberBitwiseAnd(
NumberOperationHint::kNumberOrOddball, lhs,
rhs, effect, control));
}
// -----------------------------------------------------------------------------
// JSBitwiseOr
TEST_F(JSTypedLoweringTest, JSBitwiseOrWithTypeFeedback) {
BinaryOperationHints::Hint const feedback_types[] = {
BinaryOperationHints::kSignedSmall,
BinaryOperationHints::kNumberOrOddball};
for (BinaryOperationHints::Hint feedback : feedback_types) {
BinaryOperationHints const hints(feedback, feedback, feedback);
Node* lhs = Parameter(Type::Number(), 2);
Node* rhs = Parameter(Type::Number(), 3);
Node* effect = graph()->start();
Node* control = graph()->start();
Reduction r = Reduce(graph()->NewNode(javascript()->BitwiseOr(hints), lhs,
rhs, UndefinedConstant(),
EmptyFrameState(), effect, control));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsSpeculativeNumberBitwiseOr(
feedback, lhs, rhs, effect, control));
}
TEST_F(JSTypedLoweringTest, JSBitwiseOrWithSignedSmallHint) {
BinaryOperationHints const hints(BinaryOperationHints::kSignedSmall,
BinaryOperationHints::kSignedSmall,
BinaryOperationHints::kSignedSmall);
Node* lhs = Parameter(Type::Number(), 2);
Node* rhs = Parameter(Type::Number(), 3);
Node* effect = graph()->start();
Node* control = graph()->start();
Reduction r = Reduce(graph()->NewNode(javascript()->BitwiseOr(hints), lhs,
rhs, UndefinedConstant(),
EmptyFrameState(), effect, control));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(),
IsSpeculativeNumberBitwiseOr(NumberOperationHint::kSignedSmall,
lhs, rhs, effect, control));
}
TEST_F(JSTypedLoweringTest, JSBitwiseOrWithSigned32Hint) {
BinaryOperationHints const hints(BinaryOperationHints::kSigned32,
BinaryOperationHints::kSigned32,
BinaryOperationHints::kSigned32);
Node* lhs = Parameter(Type::Number(), 2);
Node* rhs = Parameter(Type::Number(), 3);
Node* effect = graph()->start();
Node* control = graph()->start();
Reduction r = Reduce(graph()->NewNode(javascript()->BitwiseOr(hints), lhs,
rhs, UndefinedConstant(),
EmptyFrameState(), effect, control));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(),
IsSpeculativeNumberBitwiseOr(NumberOperationHint::kSigned32, lhs,
rhs, effect, control));
}
TEST_F(JSTypedLoweringTest, JSBitwiseOrWithNumberOrOddballHint) {
BinaryOperationHints const hints(BinaryOperationHints::kNumberOrOddball,
BinaryOperationHints::kNumberOrOddball,
BinaryOperationHints::kNumberOrOddball);
Node* lhs = Parameter(Type::Number(), 2);
Node* rhs = Parameter(Type::Number(), 3);
Node* effect = graph()->start();
Node* control = graph()->start();
Reduction r = Reduce(graph()->NewNode(javascript()->BitwiseOr(hints), lhs,
rhs, UndefinedConstant(),
EmptyFrameState(), effect, control));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsSpeculativeNumberBitwiseOr(
NumberOperationHint::kNumberOrOddball, lhs,
rhs, effect, control));
}
// -----------------------------------------------------------------------------
// JSBitwiseXor
TEST_F(JSTypedLoweringTest, JSBitwiseXorWithTypeFeedback) {
BinaryOperationHints::Hint const feedback_types[] = {
BinaryOperationHints::kSignedSmall,
BinaryOperationHints::kNumberOrOddball};
for (BinaryOperationHints::Hint feedback : feedback_types) {
BinaryOperationHints const hints(feedback, feedback, feedback);
Node* lhs = Parameter(Type::Number(), 2);
Node* rhs = Parameter(Type::Number(), 3);
Node* effect = graph()->start();
Node* control = graph()->start();
Reduction r = Reduce(graph()->NewNode(javascript()->BitwiseXor(hints), lhs,
rhs, UndefinedConstant(),
EmptyFrameState(), effect, control));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsSpeculativeNumberBitwiseXor(
feedback, lhs, rhs, effect, control));
}
TEST_F(JSTypedLoweringTest, JSBitwiseXorWithSignedSmallHint) {
BinaryOperationHints const hints(BinaryOperationHints::kSignedSmall,
BinaryOperationHints::kSignedSmall,
BinaryOperationHints::kSignedSmall);
Node* lhs = Parameter(Type::Number(), 2);
Node* rhs = Parameter(Type::Number(), 3);
Node* effect = graph()->start();
Node* control = graph()->start();
Reduction r = Reduce(graph()->NewNode(javascript()->BitwiseXor(hints), lhs,
rhs, UndefinedConstant(),
EmptyFrameState(), effect, control));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(),
IsSpeculativeNumberBitwiseXor(NumberOperationHint::kSignedSmall,
lhs, rhs, effect, control));
}
TEST_F(JSTypedLoweringTest, JSBitwiseXorWithSigned32Hint) {
BinaryOperationHints const hints(BinaryOperationHints::kSigned32,
BinaryOperationHints::kSigned32,
BinaryOperationHints::kSigned32);
Node* lhs = Parameter(Type::Number(), 2);
Node* rhs = Parameter(Type::Number(), 3);
Node* effect = graph()->start();
Node* control = graph()->start();
Reduction r = Reduce(graph()->NewNode(javascript()->BitwiseXor(hints), lhs,
rhs, UndefinedConstant(),
EmptyFrameState(), effect, control));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(),
IsSpeculativeNumberBitwiseXor(NumberOperationHint::kSigned32, lhs,
rhs, effect, control));
}
TEST_F(JSTypedLoweringTest, JSBitwiseXorWithNumberOrOddballHint) {
BinaryOperationHints const hints(BinaryOperationHints::kNumberOrOddball,
BinaryOperationHints::kNumberOrOddball,
BinaryOperationHints::kNumberOrOddball);
Node* lhs = Parameter(Type::Number(), 2);
Node* rhs = Parameter(Type::Number(), 3);
Node* effect = graph()->start();
Node* control = graph()->start();
Reduction r = Reduce(graph()->NewNode(javascript()->BitwiseXor(hints), lhs,
rhs, UndefinedConstant(),
EmptyFrameState(), effect, control));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsSpeculativeNumberBitwiseXor(
NumberOperationHint::kNumberOrOddball, lhs,
rhs, effect, control));
}
} // namespace compiler
......
......@@ -802,12 +802,12 @@ class IsReferenceEqualMatcher final : public NodeMatcher {
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*>& effect_matcher,
const Matcher<Node*>& control_matcher)
IsSpeculativeBinopMatcher(IrOpcode::Value opcode,
const Matcher<NumberOperationHint>& hint_matcher,
const Matcher<Node*>& lhs_matcher,
const Matcher<Node*>& rhs_matcher,
const Matcher<Node*>& effect_matcher,
const Matcher<Node*>& control_matcher)
: NodeMatcher(opcode),
hint_matcher_(hint_matcher),
lhs_matcher_(lhs_matcher),
......@@ -818,9 +818,8 @@ class IsSpeculativeBinopMatcher final : public NodeMatcher {
bool MatchAndExplain(Node* node, MatchResultListener* listener) const final {
return (NodeMatcher::MatchAndExplain(node, listener) &&
// TODO(bmeurer): The type parameter is currently ignored.
PrintMatchAndExplain(
OpParameter<BinaryOperationHints::Hint>(node->op()), "hints",
hint_matcher_, listener) &&
PrintMatchAndExplain(OpParameter<NumberOperationHint>(node->op()),
"hints", hint_matcher_, listener) &&
PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0), "lhs",
lhs_matcher_, listener) &&
PrintMatchAndExplain(NodeProperties::GetValueInput(node, 1), "rhs",
......@@ -832,7 +831,7 @@ class IsSpeculativeBinopMatcher final : public NodeMatcher {
}
private:
const Matcher<BinaryOperationHints::Hint> hint_matcher_;
const Matcher<NumberOperationHint> hint_matcher_;
const Matcher<Type*> type_matcher_;
const Matcher<Node*> lhs_matcher_;
const Matcher<Node*> rhs_matcher_;
......@@ -2043,15 +2042,15 @@ Matcher<Node*> IsReferenceEqual(const Matcher<Type*>& type_matcher,
new IsReferenceEqualMatcher(type_matcher, lhs_matcher, rhs_matcher));
}
#define DEFINE_SPECULATIVE_BINOP_MATCHER(opcode) \
Matcher<Node*> Is##opcode( \
const Matcher<BinaryOperationHints::Hint>& hint_matcher, \
const Matcher<Node*>& lhs_matcher, const Matcher<Node*>& rhs_matcher, \
const Matcher<Node*>& effect_matcher, \
const Matcher<Node*>& control_matcher) { \
return MakeMatcher(new IsSpeculativeBinopMatcher( \
IrOpcode::k##opcode, hint_matcher, lhs_matcher, rhs_matcher, \
effect_matcher, control_matcher)); \
#define DEFINE_SPECULATIVE_BINOP_MATCHER(opcode) \
Matcher<Node*> Is##opcode(const Matcher<NumberOperationHint>& hint_matcher, \
const Matcher<Node*>& lhs_matcher, \
const Matcher<Node*>& rhs_matcher, \
const Matcher<Node*>& effect_matcher, \
const Matcher<Node*>& control_matcher) { \
return MakeMatcher(new IsSpeculativeBinopMatcher( \
IrOpcode::k##opcode, hint_matcher, lhs_matcher, rhs_matcher, \
effect_matcher, control_matcher)); \
}
SPECULATIVE_BINOPS(DEFINE_SPECULATIVE_BINOP_MATCHER);
#undef DEFINE_SPECULATIVE_BINOP_MATCHER
......
......@@ -6,7 +6,7 @@
#define V8_UNITTESTS_COMPILER_NODE_TEST_UTILS_H_
#include "src/compiler/machine-operator.h"
#include "src/compiler/type-hints.h"
#include "src/compiler/simplified-operator.h"
#include "src/machine-type.h"
#include "testing/gmock/include/gmock/gmock.h"
......@@ -212,12 +212,12 @@ Matcher<Node*> IsNumberLessThan(const Matcher<Node*>& lhs_matcher,
Matcher<Node*> IsNumberAdd(const Matcher<Node*>& lhs_matcher,
const Matcher<Node*>& rhs_matcher);
#define DECLARE_SPECULATIVE_BINOP_MATCHER(opcode) \
Matcher<Node*> Is##opcode( \
const Matcher<BinaryOperationHints::Hint>& hint_matcher, \
const Matcher<Node*>& lhs_matcher, const Matcher<Node*>& rhs_matcher, \
const Matcher<Node*>& effect_matcher, \
const Matcher<Node*>& control_matcher);
#define DECLARE_SPECULATIVE_BINOP_MATCHER(opcode) \
Matcher<Node*> Is##opcode(const Matcher<NumberOperationHint>& hint_matcher, \
const Matcher<Node*>& lhs_matcher, \
const Matcher<Node*>& rhs_matcher, \
const Matcher<Node*>& effect_matcher, \
const Matcher<Node*>& control_matcher);
SPECULATIVE_BINOPS(DECLARE_SPECULATIVE_BINOP_MATCHER);
#undef DECLARE_SPECULATIVE_BINOP_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