Commit 14de196a authored by Michael Starzinger's avatar Michael Starzinger Committed by Commit Bot

[turbofan] Handle comparison operations in early lowering.

This handles relational comparison operations (no equality yet) having
number feedback during the early type-hint lowering (i.e. during graph
construction).

R=bmeurer@chromium.org

Change-Id: I0ac1539f85de1770c3d518855754550932f6fcd3
Reviewed-on: https://chromium-review.googlesource.com/445716Reviewed-by: 's avatarJaroslav Sevcik <jarin@chromium.org>
Commit-Queue: Michael Starzinger <mstarzinger@chromium.org>
Cr-Commit-Position: refs/heads/master@{#43365}
parent 56312be1
...@@ -1745,12 +1745,25 @@ void BytecodeGraphBuilder::VisitGetSuperConstructor() { ...@@ -1745,12 +1745,25 @@ void BytecodeGraphBuilder::VisitGetSuperConstructor() {
Environment::kAttachFrameState); Environment::kAttachFrameState);
} }
void BytecodeGraphBuilder::BuildCompareOp(const Operator* js_op) { void BytecodeGraphBuilder::BuildCompareOp(const Operator* op) {
PrepareEagerCheckpoint(); PrepareEagerCheckpoint();
Node* left = Node* left =
environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0)); environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
Node* right = environment()->LookupAccumulator(); Node* right = environment()->LookupAccumulator();
Node* node = NewNode(js_op, left, right);
Node* node = nullptr;
int slot_index = bytecode_iterator().GetIndexOperand(1);
if (slot_index != 0) {
FeedbackSlot slot = feedback_vector()->ToSlot(slot_index);
if (Node* simplified = TryBuildSimplifiedBinaryOp(op, left, right, slot)) {
node = simplified;
} else {
node = NewNode(op, left, right);
}
} else {
node = NewNode(op, left, right);
}
environment()->BindAccumulator(node, Environment::kAttachFrameState); environment()->BindAccumulator(node, Environment::kAttachFrameState);
} }
...@@ -1782,12 +1795,21 @@ void BytecodeGraphBuilder::VisitTestGreaterThanOrEqual() { ...@@ -1782,12 +1795,21 @@ void BytecodeGraphBuilder::VisitTestGreaterThanOrEqual() {
BuildCompareOp(javascript()->GreaterThanOrEqual(GetCompareOperationHint())); BuildCompareOp(javascript()->GreaterThanOrEqual(GetCompareOperationHint()));
} }
void BytecodeGraphBuilder::BuildTestingOp(const Operator* op) {
PrepareEagerCheckpoint();
Node* left =
environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
Node* right = environment()->LookupAccumulator();
Node* node = NewNode(op, left, right);
environment()->BindAccumulator(node, Environment::kAttachFrameState);
}
void BytecodeGraphBuilder::VisitTestIn() { void BytecodeGraphBuilder::VisitTestIn() {
BuildCompareOp(javascript()->HasProperty()); BuildTestingOp(javascript()->HasProperty());
} }
void BytecodeGraphBuilder::VisitTestInstanceOf() { void BytecodeGraphBuilder::VisitTestInstanceOf() {
BuildCompareOp(javascript()->InstanceOf()); BuildTestingOp(javascript()->InstanceOf());
} }
void BytecodeGraphBuilder::VisitTestUndetectable() { void BytecodeGraphBuilder::VisitTestUndetectable() {
......
...@@ -155,6 +155,7 @@ class BytecodeGraphBuilder { ...@@ -155,6 +155,7 @@ class BytecodeGraphBuilder {
void BuildBinaryOp(const Operator* op); void BuildBinaryOp(const Operator* op);
void BuildBinaryOpWithImmediate(const Operator* op); void BuildBinaryOpWithImmediate(const Operator* op);
void BuildCompareOp(const Operator* op); void BuildCompareOp(const Operator* op);
void BuildTestingOp(const Operator* op);
void BuildDelete(LanguageMode language_mode); void BuildDelete(LanguageMode language_mode);
void BuildCastOperator(const Operator* op); void BuildCastOperator(const Operator* op);
void BuildForInPrepare(); void BuildForInPrepare();
......
...@@ -33,6 +33,12 @@ class JSSpeculativeBinopBuilder final { ...@@ -33,6 +33,12 @@ class JSSpeculativeBinopBuilder final {
return nexus.GetBinaryOperationFeedback(); return nexus.GetBinaryOperationFeedback();
} }
CompareOperationHint GetCompareOperationHint() {
DCHECK_EQ(FeedbackSlotKind::kCompareOp, feedback_vector()->GetKind(slot_));
CompareICNexus nexus(feedback_vector(), slot_);
return nexus.GetCompareOperationFeedback();
}
bool GetBinaryNumberOperationHint(NumberOperationHint* hint) { bool GetBinaryNumberOperationHint(NumberOperationHint* hint) {
switch (GetBinaryOperationHint()) { switch (GetBinaryOperationHint()) {
case BinaryOperationHint::kSignedSmall: case BinaryOperationHint::kSignedSmall:
...@@ -52,6 +58,27 @@ class JSSpeculativeBinopBuilder final { ...@@ -52,6 +58,27 @@ class JSSpeculativeBinopBuilder final {
return false; return false;
} }
bool GetCompareNumberOperationHint(NumberOperationHint* hint) {
switch (GetCompareOperationHint()) {
case CompareOperationHint::kSignedSmall:
*hint = NumberOperationHint::kSignedSmall;
return true;
case CompareOperationHint::kNumber:
*hint = NumberOperationHint::kNumber;
return true;
case CompareOperationHint::kNumberOrOddball:
*hint = NumberOperationHint::kNumberOrOddball;
return true;
case CompareOperationHint::kAny:
case CompareOperationHint::kNone:
case CompareOperationHint::kString:
case CompareOperationHint::kReceiver:
case CompareOperationHint::kInternalizedString:
break;
}
return false;
}
const Operator* SpeculativeNumberOp(NumberOperationHint hint) { const Operator* SpeculativeNumberOp(NumberOperationHint hint) {
switch (op_->opcode()) { switch (op_->opcode()) {
case IrOpcode::kJSAdd: case IrOpcode::kJSAdd:
...@@ -83,7 +110,26 @@ class JSSpeculativeBinopBuilder final { ...@@ -83,7 +110,26 @@ class JSSpeculativeBinopBuilder final {
return nullptr; return nullptr;
} }
Node* BuildSpeculativeOperator(const Operator* op) { const Operator* SpeculativeCompareOp(NumberOperationHint hint) {
switch (op_->opcode()) {
case IrOpcode::kJSLessThan:
return simplified()->SpeculativeNumberLessThan(hint);
case IrOpcode::kJSGreaterThan:
std::swap(left_, right_); // a > b => b < a
return simplified()->SpeculativeNumberLessThan(hint);
case IrOpcode::kJSLessThanOrEqual:
return simplified()->SpeculativeNumberLessThanOrEqual(hint);
case IrOpcode::kJSGreaterThanOrEqual:
std::swap(left_, right_); // a >= b => b <= a
return simplified()->SpeculativeNumberLessThanOrEqual(hint);
default:
break;
}
UNREACHABLE();
return nullptr;
}
Node* BuildSpeculativeOperation(const Operator* op) {
DCHECK_EQ(2, op->ValueInputCount()); DCHECK_EQ(2, op->ValueInputCount());
DCHECK_EQ(1, op->EffectInputCount()); DCHECK_EQ(1, op->EffectInputCount());
DCHECK_EQ(1, op->ControlInputCount()); DCHECK_EQ(1, op->ControlInputCount());
...@@ -94,6 +140,26 @@ class JSSpeculativeBinopBuilder final { ...@@ -94,6 +140,26 @@ class JSSpeculativeBinopBuilder final {
return graph()->NewNode(op, left_, right_, effect_, control_); return graph()->NewNode(op, left_, right_, effect_, control_);
} }
Node* TryBuildNumberBinop() {
NumberOperationHint hint;
if (GetBinaryNumberOperationHint(&hint)) {
const Operator* op = SpeculativeNumberOp(hint);
Node* node = BuildSpeculativeOperation(op);
return node;
}
return nullptr;
}
Node* TryBuildNumberCompare() {
NumberOperationHint hint;
if (GetCompareNumberOperationHint(&hint)) {
const Operator* op = SpeculativeCompareOp(hint);
Node* node = BuildSpeculativeOperation(op);
return node;
}
return nullptr;
}
JSGraph* jsgraph() const { return lowering_->jsgraph(); } JSGraph* jsgraph() const { return lowering_->jsgraph(); }
Graph* graph() const { return jsgraph()->graph(); } Graph* graph() const { return jsgraph()->graph(); }
JSOperatorBuilder* javascript() { return jsgraph()->javascript(); } JSOperatorBuilder* javascript() { return jsgraph()->javascript(); }
...@@ -122,6 +188,21 @@ Reduction JSTypeHintLowering::ReduceBinaryOperation(const Operator* op, ...@@ -122,6 +188,21 @@ Reduction JSTypeHintLowering::ReduceBinaryOperation(const Operator* op,
Node* effect, Node* control, Node* effect, Node* control,
FeedbackSlot slot) { FeedbackSlot slot) {
switch (op->opcode()) { switch (op->opcode()) {
case IrOpcode::kJSEqual:
case IrOpcode::kJSStrictEqual:
case IrOpcode::kJSNotEqual:
case IrOpcode::kJSStrictNotEqual:
break;
case IrOpcode::kJSLessThan:
case IrOpcode::kJSGreaterThan:
case IrOpcode::kJSLessThanOrEqual:
case IrOpcode::kJSGreaterThanOrEqual: {
JSSpeculativeBinopBuilder b(this, op, left, right, effect, control, slot);
if (Node* node = b.TryBuildNumberCompare()) {
return Reduction(node);
}
break;
}
case IrOpcode::kJSBitwiseOr: case IrOpcode::kJSBitwiseOr:
case IrOpcode::kJSBitwiseXor: case IrOpcode::kJSBitwiseXor:
case IrOpcode::kJSBitwiseAnd: case IrOpcode::kJSBitwiseAnd:
...@@ -134,9 +215,7 @@ Reduction JSTypeHintLowering::ReduceBinaryOperation(const Operator* op, ...@@ -134,9 +215,7 @@ Reduction JSTypeHintLowering::ReduceBinaryOperation(const Operator* op,
case IrOpcode::kJSDivide: case IrOpcode::kJSDivide:
case IrOpcode::kJSModulus: { case IrOpcode::kJSModulus: {
JSSpeculativeBinopBuilder b(this, op, left, right, effect, control, slot); JSSpeculativeBinopBuilder b(this, op, left, right, effect, control, slot);
NumberOperationHint hint; if (Node* node = b.TryBuildNumberBinop()) {
if (b.GetBinaryNumberOperationHint(&hint)) {
Node* node = b.BuildSpeculativeOperator(b.SpeculativeNumberOp(hint));
return Reduction(node); return Reduction(node);
} }
break; break;
......
...@@ -10,10 +10,16 @@ ...@@ -10,10 +10,16 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
// Forward declarations.
class FeedbackSlot;
namespace compiler { namespace compiler {
// Forward declarations. // Forward declarations.
class JSGraph; class JSGraph;
class Node;
class Operator;
// The type-hint lowering consumes feedback about data operations (i.e. unary // The type-hint lowering consumes feedback about data operations (i.e. unary
// and binary operations) to emit nodes using speculative simplified operators // and binary operations) to emit nodes using speculative simplified operators
...@@ -28,7 +34,8 @@ class JSTypeHintLowering { ...@@ -28,7 +34,8 @@ class JSTypeHintLowering {
public: public:
JSTypeHintLowering(JSGraph* jsgraph, Handle<FeedbackVector> feedback_vector); JSTypeHintLowering(JSGraph* jsgraph, Handle<FeedbackVector> feedback_vector);
// Potential reduction of binary (arithmetic, logical and shift) operations. // Potential reduction of binary (arithmetic, logical, shift and relational
// comparison) operations.
Reduction ReduceBinaryOperation(const Operator* op, Node* left, Node* right, Reduction ReduceBinaryOperation(const Operator* op, Node* left, Node* right,
Node* effect, Node* control, Node* effect, Node* control,
FeedbackSlot slot); FeedbackSlot slot);
......
...@@ -349,6 +349,10 @@ class JSBinopReduction final { ...@@ -349,6 +349,10 @@ class JSBinopReduction final {
const Operator* NumberOpFromSpeculativeNumberOp() { const Operator* NumberOpFromSpeculativeNumberOp() {
switch (node_->opcode()) { switch (node_->opcode()) {
case IrOpcode::kSpeculativeNumberLessThan:
return simplified()->NumberLessThan();
case IrOpcode::kSpeculativeNumberLessThanOrEqual:
return simplified()->NumberLessThanOrEqual();
case IrOpcode::kSpeculativeNumberAdd: case IrOpcode::kSpeculativeNumberAdd:
return simplified()->NumberAdd(); return simplified()->NumberAdd();
case IrOpcode::kSpeculativeNumberSubtract: case IrOpcode::kSpeculativeNumberSubtract:
...@@ -770,6 +774,15 @@ Reduction JSTypedLowering::ReduceCreateConsString(Node* node) { ...@@ -770,6 +774,15 @@ Reduction JSTypedLowering::ReduceCreateConsString(Node* node) {
return Changed(node); return Changed(node);
} }
Reduction JSTypedLowering::ReduceSpeculativeNumberComparison(Node* node) {
JSBinopReduction r(this, node);
if (r.BothInputsAre(Type::Signed32()) ||
r.BothInputsAre(Type::Unsigned32())) {
return r.ChangeToPureOperator(r.NumberOpFromSpeculativeNumberOp());
}
return Changed(node);
}
Reduction JSTypedLowering::ReduceJSComparison(Node* node) { Reduction JSTypedLowering::ReduceJSComparison(Node* node) {
JSBinopReduction r(this, node); JSBinopReduction r(this, node);
if (r.BothInputsAre(Type::String())) { if (r.BothInputsAre(Type::String())) {
...@@ -797,16 +810,12 @@ Reduction JSTypedLowering::ReduceJSComparison(Node* node) { ...@@ -797,16 +810,12 @@ Reduction JSTypedLowering::ReduceJSComparison(Node* node) {
return Changed(node); return Changed(node);
} }
NumberOperationHint hint;
const Operator* less_than; const Operator* less_than;
const Operator* less_than_or_equal; const Operator* less_than_or_equal;
if (r.BothInputsAre(Type::Signed32()) || if (r.BothInputsAre(Type::Signed32()) ||
r.BothInputsAre(Type::Unsigned32())) { r.BothInputsAre(Type::Unsigned32())) {
less_than = simplified()->NumberLessThan(); less_than = simplified()->NumberLessThan();
less_than_or_equal = simplified()->NumberLessThanOrEqual(); 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()) && } else if (r.OneInputCannotBe(Type::StringOrReceiver()) &&
(r.BothInputsAre(Type::PlainPrimitive()) || (r.BothInputsAre(Type::PlainPrimitive()) ||
!(flags() & kDeoptimizationEnabled))) { !(flags() & kDeoptimizationEnabled))) {
...@@ -839,11 +848,7 @@ Reduction JSTypedLowering::ReduceJSComparison(Node* node) { ...@@ -839,11 +848,7 @@ Reduction JSTypedLowering::ReduceJSComparison(Node* node) {
default: default:
return NoChange(); return NoChange();
} }
if (comparison->EffectInputCount() > 0) { return r.ChangeToPureOperator(comparison);
return r.ChangeToSpeculativeOperator(comparison, Type::Boolean());
} else {
return r.ChangeToPureOperator(comparison);
}
} }
Reduction JSTypedLowering::ReduceJSTypeOf(Node* node) { Reduction JSTypedLowering::ReduceJSTypeOf(Node* node) {
...@@ -2451,6 +2456,9 @@ Reduction JSTypedLowering::Reduce(Node* node) { ...@@ -2451,6 +2456,9 @@ Reduction JSTypedLowering::Reduce(Node* node) {
case IrOpcode::kSpeculativeNumberDivide: case IrOpcode::kSpeculativeNumberDivide:
case IrOpcode::kSpeculativeNumberModulus: case IrOpcode::kSpeculativeNumberModulus:
return ReduceSpeculativeNumberBinop(node); return ReduceSpeculativeNumberBinop(node);
case IrOpcode::kSpeculativeNumberLessThan:
case IrOpcode::kSpeculativeNumberLessThanOrEqual:
return ReduceSpeculativeNumberComparison(node);
default: default:
break; break;
} }
......
...@@ -86,6 +86,7 @@ class V8_EXPORT_PRIVATE JSTypedLowering final ...@@ -86,6 +86,7 @@ class V8_EXPORT_PRIVATE JSTypedLowering final
Reduction ReduceCreateConsString(Node* node); Reduction ReduceCreateConsString(Node* node);
Reduction ReduceSpeculativeNumberAdd(Node* node); Reduction ReduceSpeculativeNumberAdd(Node* node);
Reduction ReduceSpeculativeNumberBinop(Node* node); Reduction ReduceSpeculativeNumberBinop(Node* node);
Reduction ReduceSpeculativeNumberComparison(Node* node);
Factory* factory() const; Factory* factory() const;
Graph* graph() const; Graph* graph() const;
......
...@@ -234,12 +234,14 @@ void LoopVariableOptimizer::VisitIf(Node* node, bool polarity) { ...@@ -234,12 +234,14 @@ void LoopVariableOptimizer::VisitIf(Node* node, bool polarity) {
// Normalize to less than comparison. // Normalize to less than comparison.
switch (cond->opcode()) { switch (cond->opcode()) {
case IrOpcode::kJSLessThan: case IrOpcode::kJSLessThan:
case IrOpcode::kSpeculativeNumberLessThan:
AddCmpToLimits(limits, cond, InductionVariable::kStrict, polarity); AddCmpToLimits(limits, cond, InductionVariable::kStrict, polarity);
break; break;
case IrOpcode::kJSGreaterThan: case IrOpcode::kJSGreaterThan:
AddCmpToLimits(limits, cond, InductionVariable::kNonStrict, !polarity); AddCmpToLimits(limits, cond, InductionVariable::kNonStrict, !polarity);
break; break;
case IrOpcode::kJSLessThanOrEqual: case IrOpcode::kJSLessThanOrEqual:
case IrOpcode::kSpeculativeNumberLessThanOrEqual:
AddCmpToLimits(limits, cond, InductionVariable::kNonStrict, polarity); AddCmpToLimits(limits, cond, InductionVariable::kNonStrict, polarity);
break; break;
case IrOpcode::kJSGreaterThanOrEqual: case IrOpcode::kJSGreaterThanOrEqual:
......
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