[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:
parent
d009bf2b67
commit
931e18d538
@ -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() {
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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:
|
||||
|
Loading…
Reference in New Issue
Block a user