[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=jarin@chromium.org

Change-Id: Ia276d1d7c5931f1e92f31e4e24c181d82d48a138
Reviewed-on: https://chromium-review.googlesource.com/446762
Reviewed-by: Benedikt Meurer <bmeurer@chromium.org>
Commit-Queue: Michael Starzinger <mstarzinger@chromium.org>
Cr-Commit-Position: refs/heads/master@{#43471}
This commit is contained in:
Michael Starzinger 2017-02-27 13:26:01 +01:00 committed by Commit Bot
parent d009bf2b67
commit 931e18d538
7 changed files with 138 additions and 18 deletions

View File

@ -1745,12 +1745,25 @@ void BytecodeGraphBuilder::VisitGetSuperConstructor() {
Environment::kAttachFrameState);
}
void BytecodeGraphBuilder::BuildCompareOp(const Operator* js_op) {
void BytecodeGraphBuilder::BuildCompareOp(const Operator* op) {
PrepareEagerCheckpoint();
Node* left =
environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
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);
}
@ -1782,12 +1795,21 @@ void BytecodeGraphBuilder::VisitTestGreaterThanOrEqual() {
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() {
BuildCompareOp(javascript()->HasProperty());
BuildTestingOp(javascript()->HasProperty());
}
void BytecodeGraphBuilder::VisitTestInstanceOf() {
BuildCompareOp(javascript()->InstanceOf());
BuildTestingOp(javascript()->InstanceOf());
}
void BytecodeGraphBuilder::VisitTestUndetectable() {

View File

@ -155,6 +155,7 @@ class BytecodeGraphBuilder {
void BuildBinaryOp(const Operator* op);
void BuildBinaryOpWithImmediate(const Operator* op);
void BuildCompareOp(const Operator* op);
void BuildTestingOp(const Operator* op);
void BuildDelete(LanguageMode language_mode);
void BuildCastOperator(const Operator* op);
void BuildForInPrepare();

View File

@ -33,6 +33,12 @@ class JSSpeculativeBinopBuilder final {
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) {
switch (GetBinaryOperationHint()) {
case BinaryOperationHint::kSignedSmall:
@ -52,6 +58,27 @@ class JSSpeculativeBinopBuilder final {
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) {
switch (op_->opcode()) {
case IrOpcode::kJSAdd:
@ -83,7 +110,26 @@ class JSSpeculativeBinopBuilder final {
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(1, op->EffectInputCount());
DCHECK_EQ(1, op->ControlInputCount());
@ -94,6 +140,26 @@ class JSSpeculativeBinopBuilder final {
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(); }
Graph* graph() const { return jsgraph()->graph(); }
JSOperatorBuilder* javascript() { return jsgraph()->javascript(); }
@ -122,6 +188,21 @@ Reduction JSTypeHintLowering::ReduceBinaryOperation(const Operator* op,
Node* effect, Node* control,
FeedbackSlot slot) {
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::kJSBitwiseXor:
case IrOpcode::kJSBitwiseAnd:
@ -134,9 +215,7 @@ Reduction JSTypeHintLowering::ReduceBinaryOperation(const Operator* op,
case IrOpcode::kJSDivide:
case IrOpcode::kJSModulus: {
JSSpeculativeBinopBuilder b(this, op, left, right, effect, control, slot);
NumberOperationHint hint;
if (b.GetBinaryNumberOperationHint(&hint)) {
Node* node = b.BuildSpeculativeOperator(b.SpeculativeNumberOp(hint));
if (Node* node = b.TryBuildNumberBinop()) {
return Reduction(node);
}
break;

View File

@ -10,10 +10,16 @@
namespace v8 {
namespace internal {
// Forward declarations.
class FeedbackSlot;
namespace compiler {
// Forward declarations.
class JSGraph;
class Node;
class Operator;
// The type-hint lowering consumes feedback about data operations (i.e. unary
// and binary operations) to emit nodes using speculative simplified operators
@ -28,7 +34,8 @@ class JSTypeHintLowering {
public:
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,
Node* effect, Node* control,
FeedbackSlot slot);

View File

@ -350,6 +350,10 @@ class JSBinopReduction final {
const Operator* NumberOpFromSpeculativeNumberOp() {
switch (node_->opcode()) {
case IrOpcode::kSpeculativeNumberLessThan:
return simplified()->NumberLessThan();
case IrOpcode::kSpeculativeNumberLessThanOrEqual:
return simplified()->NumberLessThanOrEqual();
case IrOpcode::kSpeculativeNumberAdd:
return simplified()->NumberAdd();
case IrOpcode::kSpeculativeNumberSubtract:
@ -771,6 +775,15 @@ Reduction JSTypedLowering::ReduceCreateConsString(Node* 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) {
JSBinopReduction r(this, node);
if (r.BothInputsAre(Type::String())) {
@ -798,16 +811,12 @@ Reduction JSTypedLowering::ReduceJSComparison(Node* node) {
return Changed(node);
}
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))) {
@ -840,11 +849,7 @@ Reduction JSTypedLowering::ReduceJSComparison(Node* node) {
default:
return NoChange();
}
if (comparison->EffectInputCount() > 0) {
return r.ChangeToSpeculativeOperator(comparison, Type::Boolean());
} else {
return r.ChangeToPureOperator(comparison);
}
return r.ChangeToPureOperator(comparison);
}
Reduction JSTypedLowering::ReduceJSTypeOf(Node* node) {
@ -2452,6 +2457,9 @@ Reduction JSTypedLowering::Reduce(Node* node) {
case IrOpcode::kSpeculativeNumberDivide:
case IrOpcode::kSpeculativeNumberModulus:
return ReduceSpeculativeNumberBinop(node);
case IrOpcode::kSpeculativeNumberLessThan:
case IrOpcode::kSpeculativeNumberLessThanOrEqual:
return ReduceSpeculativeNumberComparison(node);
default:
break;
}

View File

@ -86,6 +86,7 @@ class V8_EXPORT_PRIVATE JSTypedLowering final
Reduction ReduceCreateConsString(Node* node);
Reduction ReduceSpeculativeNumberAdd(Node* node);
Reduction ReduceSpeculativeNumberBinop(Node* node);
Reduction ReduceSpeculativeNumberComparison(Node* node);
Factory* factory() const;
Graph* graph() const;

View File

@ -234,12 +234,14 @@ void LoopVariableOptimizer::VisitIf(Node* node, bool polarity) {
// Normalize to less than comparison.
switch (cond->opcode()) {
case IrOpcode::kJSLessThan:
case IrOpcode::kSpeculativeNumberLessThan:
AddCmpToLimits(limits, cond, InductionVariable::kStrict, polarity);
break;
case IrOpcode::kJSGreaterThan:
AddCmpToLimits(limits, cond, InductionVariable::kNonStrict, !polarity);
break;
case IrOpcode::kJSLessThanOrEqual:
case IrOpcode::kSpeculativeNumberLessThanOrEqual:
AddCmpToLimits(limits, cond, InductionVariable::kNonStrict, polarity);
break;
case IrOpcode::kJSGreaterThanOrEqual: