Chromium Code Reviews

Side by Side Diff: src/compiler/js-typed-lowering.cc

Issue 2035383003: [turbofan] Type feedback for numeric comparisons. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Fixes Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff |
OLDNEW
1 // Copyright 2014 the V8 project authors. All rights reserved. 1 // Copyright 2014 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/code-factory.h" 5 #include "src/code-factory.h"
6 #include "src/compilation-dependencies.h" 6 #include "src/compilation-dependencies.h"
7 #include "src/compiler/access-builder.h" 7 #include "src/compiler/access-builder.h"
8 #include "src/compiler/js-graph.h" 8 #include "src/compiler/js-graph.h"
9 #include "src/compiler/js-typed-lowering.h" 9 #include "src/compiler/js-typed-lowering.h"
10 #include "src/compiler/linkage.h" 10 #include "src/compiler/linkage.h"
11 #include "src/compiler/node-matchers.h" 11 #include "src/compiler/node-matchers.h"
12 #include "src/compiler/node-properties.h" 12 #include "src/compiler/node-properties.h"
13 #include "src/compiler/operator-properties.h" 13 #include "src/compiler/operator-properties.h"
14 #include "src/type-cache.h" 14 #include "src/type-cache.h"
15 #include "src/types.h" 15 #include "src/types.h"
16 16
17 namespace v8 { 17 namespace v8 {
18 namespace internal { 18 namespace internal {
19 namespace compiler { 19 namespace compiler {
20 20
21 // A helper class to simplify the process of reducing a single binop node with a 21 // A helper class to simplify the process of reducing a single binop node with a
22 // JSOperator. This class manages the rewriting of context, control, and effect 22 // JSOperator. This class manages the rewriting of context, control, and effect
23 // dependencies during lowering of a binop and contains numerous helper 23 // dependencies during lowering of a binop and contains numerous helper
24 // functions for matching the types of inputs to an operation. 24 // functions for matching the types of inputs to an operation.
25 class JSBinopReduction final { 25 class JSBinopReduction final {
26 public: 26 public:
27 JSBinopReduction(JSTypedLowering* lowering, Node* node) 27 JSBinopReduction(JSTypedLowering* lowering, Node* node)
28 : lowering_(lowering), node_(node) {} 28 : lowering_(lowering), node_(node) {}
29 29
30 BinaryOperationHints::Hint GetUsableNumberFeedback() { 30 BinaryOperationHints::Hint GetNumberBinaryOperationFeedback() {
31 if (!(lowering_->flags() & JSTypedLowering::kDeoptimizationEnabled) || 31 if (!(lowering_->flags() & JSTypedLowering::kDeoptimizationEnabled) ||
32 !(lowering_->flags() & JSTypedLowering::kTypeFeedbackEnabled)) { 32 !(lowering_->flags() & JSTypedLowering::kTypeFeedbackEnabled)) {
33 return BinaryOperationHints::kAny; 33 return BinaryOperationHints::kAny;
34 } 34 }
35 DCHECK_NE(0, node_->op()->ControlOutputCount()); 35 DCHECK_NE(0, node_->op()->ControlOutputCount());
36 DCHECK_EQ(1, node_->op()->EffectOutputCount()); 36 DCHECK_EQ(1, node_->op()->EffectOutputCount());
37 DCHECK_EQ(2, OperatorProperties::GetFrameStateInputCount(node_->op())); 37 DCHECK_EQ(2, OperatorProperties::GetFrameStateInputCount(node_->op()));
38 BinaryOperationHints hints = BinaryOperationHintsOf(node_->op()); 38 BinaryOperationHints hints = BinaryOperationHintsOf(node_->op());
39 BinaryOperationHints::Hint combined = hints.combined(); 39 BinaryOperationHints::Hint combined = hints.combined();
40 if (combined == BinaryOperationHints::kSignedSmall || 40 if (combined == BinaryOperationHints::kSignedSmall ||
41 combined == BinaryOperationHints::kSigned32 || 41 combined == BinaryOperationHints::kSigned32 ||
42 combined == BinaryOperationHints::kNumberOrUndefined) { 42 combined == BinaryOperationHints::kNumberOrUndefined) {
43 return combined; 43 return combined;
44 } 44 }
45 return BinaryOperationHints::kAny; 45 return BinaryOperationHints::kAny;
46 } 46 }
47 47
48 CompareOperationHints::Hint GetNumberCompareOperationFeedback() {
49 if (!(lowering_->flags() & JSTypedLowering::kDeoptimizationEnabled) ||
50 !(lowering_->flags() & JSTypedLowering::kTypeFeedbackEnabled)) {
51 return CompareOperationHints::kAny;
52 }
53 DCHECK_NE(0, node_->op()->ControlOutputCount());
54 DCHECK_EQ(1, node_->op()->EffectOutputCount());
55 DCHECK_EQ(2, OperatorProperties::GetFrameStateInputCount(node_->op()));
56 CompareOperationHints hints = CompareOperationHintsOf(node_->op());
57 CompareOperationHints::Hint combined = hints.combined();
58 if (combined == CompareOperationHints::kSignedSmall ||
59 combined == CompareOperationHints::kSigned32 ||
60 combined == CompareOperationHints::kNumberOrUndefined) {
61 return combined;
62 }
63 return CompareOperationHints::kAny;
64 }
65
48 void ConvertInputsToNumberOrUndefined(Node* frame_state) { 66 void ConvertInputsToNumberOrUndefined(Node* frame_state) {
49 // To convert the inputs to numbers, we have to provide frame states 67 // To convert the inputs to numbers, we have to provide frame states
50 // for lazy bailouts in the ToNumber conversions. 68 // for lazy bailouts in the ToNumber conversions.
51 // We use a little hack here: we take the frame state before the binary 69 // We use a little hack here: we take the frame state before the binary
52 // operation and use it to construct the frame states for the conversion 70 // operation and use it to construct the frame states for the conversion
53 // so that after the deoptimization, the binary operation IC gets 71 // so that after the deoptimization, the binary operation IC gets
54 // already converted values from full code. This way we are sure that we 72 // already converted values from full code. This way we are sure that we
55 // will not re-do any of the side effects. 73 // will not re-do any of the side effects.
56 74
57 Node* left_input = nullptr; 75 Node* left_input = nullptr;
(...skipping 60 matching lines...)
118 // Insert an boolean not to invert the value. 136 // Insert an boolean not to invert the value.
119 Node* value = graph()->NewNode(simplified()->BooleanNot(), node_); 137 Node* value = graph()->NewNode(simplified()->BooleanNot(), node_);
120 node_->ReplaceUses(value); 138 node_->ReplaceUses(value);
121 // Note: ReplaceUses() smashes all uses, so smash it back here. 139 // Note: ReplaceUses() smashes all uses, so smash it back here.
122 value->ReplaceInput(0, node_); 140 value->ReplaceInput(0, node_);
123 return lowering_->Replace(value); 141 return lowering_->Replace(value);
124 } 142 }
125 return lowering_->Changed(node_); 143 return lowering_->Changed(node_);
126 } 144 }
127 145
128 Reduction ChangeToSpeculativeOperator(const Operator* op) { 146 Reduction ChangeToSpeculativeOperator(const Operator* op, Type* upper_bound) {
129 DCHECK_EQ(1, op->EffectInputCount()); 147 DCHECK_EQ(1, op->EffectInputCount());
130 DCHECK_EQ(1, op->EffectOutputCount()); 148 DCHECK_EQ(1, op->EffectOutputCount());
131 DCHECK_EQ(false, OperatorProperties::HasContextInput(op)); 149 DCHECK_EQ(false, OperatorProperties::HasContextInput(op));
132 DCHECK_EQ(1, op->ControlInputCount()); 150 DCHECK_EQ(1, op->ControlInputCount());
133 DCHECK_EQ(1, op->ControlOutputCount()); 151 DCHECK_EQ(1, op->ControlOutputCount());
134 DCHECK_EQ(0, OperatorProperties::GetFrameStateInputCount(op)); 152 DCHECK_EQ(0, OperatorProperties::GetFrameStateInputCount(op));
135 DCHECK_EQ(2, op->ValueInputCount()); 153 DCHECK_EQ(2, op->ValueInputCount());
136 154
137 DCHECK_EQ(1, node_->op()->EffectInputCount()); 155 DCHECK_EQ(1, node_->op()->EffectInputCount());
138 DCHECK_EQ(1, node_->op()->EffectOutputCount()); 156 DCHECK_EQ(1, node_->op()->EffectOutputCount());
(...skipping 21 matching lines...)
160 // Remove both bailout frame states and the context. 178 // Remove both bailout frame states and the context.
161 node_->RemoveInput(NodeProperties::FirstFrameStateIndex(node_) + 1); 179 node_->RemoveInput(NodeProperties::FirstFrameStateIndex(node_) + 1);
162 node_->RemoveInput(NodeProperties::FirstFrameStateIndex(node_)); 180 node_->RemoveInput(NodeProperties::FirstFrameStateIndex(node_));
163 node_->RemoveInput(NodeProperties::FirstContextIndex(node_)); 181 node_->RemoveInput(NodeProperties::FirstContextIndex(node_));
164 182
165 NodeProperties::ChangeOp(node_, op); 183 NodeProperties::ChangeOp(node_, op);
166 184
167 // Update the type to number. 185 // Update the type to number.
168 Type* node_type = NodeProperties::GetType(node_); 186 Type* node_type = NodeProperties::GetType(node_);
169 NodeProperties::SetType(node_, 187 NodeProperties::SetType(node_,
170 Type::Intersect(node_type, Type::Number(), zone())); 188 Type::Intersect(node_type, upper_bound, zone()));
171 189
172 return lowering_->Changed(node_); 190 return lowering_->Changed(node_);
173 } 191 }
174 192
175 Reduction ChangeToPureOperator(const Operator* op, Type* type) { 193 Reduction ChangeToPureOperator(const Operator* op, Type* type) {
176 return ChangeToPureOperator(op, false, type); 194 return ChangeToPureOperator(op, false, type);
177 } 195 }
178 196
179 bool LeftInputIs(Type* t) { return left_type()->Is(t); } 197 bool LeftInputIs(Type* t) { return left_type()->Is(t); }
180 198
(...skipping 218 matching lines...)
399 shifted_int32_ranges_[k] = Type::Range(min, max, graph()->zone()); 417 shifted_int32_ranges_[k] = Type::Range(min, max, graph()->zone());
400 } 418 }
401 } 419 }
402 420
403 421
404 Reduction JSTypedLowering::ReduceJSAdd(Node* node) { 422 Reduction JSTypedLowering::ReduceJSAdd(Node* node) {
405 if (flags() & kDisableBinaryOpReduction) return NoChange(); 423 if (flags() & kDisableBinaryOpReduction) return NoChange();
406 424
407 JSBinopReduction r(this, node); 425 JSBinopReduction r(this, node);
408 426
409 BinaryOperationHints::Hint feedback = r.GetUsableNumberFeedback(); 427 BinaryOperationHints::Hint feedback = r.GetNumberBinaryOperationFeedback();
410 if (feedback != BinaryOperationHints::kAny) { 428 if (feedback != BinaryOperationHints::kAny) {
411 // Lower to the optimistic number binop. 429 // Lower to the optimistic number binop.
412 return r.ChangeToSpeculativeOperator( 430 return r.ChangeToSpeculativeOperator(
413 simplified()->SpeculativeNumberAdd(feedback)); 431 simplified()->SpeculativeNumberAdd(feedback), Type::Number());
414 } 432 }
415 if (r.BothInputsAre(Type::NumberOrUndefined())) { 433 if (r.BothInputsAre(Type::NumberOrUndefined())) {
416 // JSAdd(x:number, y:number) => NumberAdd(x, y) 434 // JSAdd(x:number, y:number) => NumberAdd(x, y)
417 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1); 435 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
418 r.ConvertInputsToNumberOrUndefined(frame_state); 436 r.ConvertInputsToNumberOrUndefined(frame_state);
419 return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number()); 437 return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number());
420 } 438 }
421 if (r.NeitherInputCanBe(Type::StringOrReceiver())) { 439 if (r.NeitherInputCanBe(Type::StringOrReceiver())) {
422 // JSAdd(x:-string, y:-string) => NumberAdd(ToNumber(x), ToNumber(y)) 440 // JSAdd(x:-string, y:-string) => NumberAdd(ToNumber(x), ToNumber(y))
423 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1); 441 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
(...skipping 33 matching lines...)
457 // JSModulus(x:number, x:number) => NumberModulus(x, y) 475 // JSModulus(x:number, x:number) => NumberModulus(x, y)
458 return r.ChangeToPureOperator(simplified()->NumberModulus(), 476 return r.ChangeToPureOperator(simplified()->NumberModulus(),
459 Type::Number()); 477 Type::Number());
460 } 478 }
461 return NoChange(); 479 return NoChange();
462 } 480 }
463 481
464 Reduction JSTypedLowering::ReduceJSSubtract(Node* node) { 482 Reduction JSTypedLowering::ReduceJSSubtract(Node* node) {
465 if (flags() & kDisableBinaryOpReduction) return NoChange(); 483 if (flags() & kDisableBinaryOpReduction) return NoChange();
466 JSBinopReduction r(this, node); 484 JSBinopReduction r(this, node);
467 BinaryOperationHints::Hint feedback = r.GetUsableNumberFeedback(); 485 BinaryOperationHints::Hint feedback = r.GetNumberBinaryOperationFeedback();
468 if (feedback != BinaryOperationHints::kAny) { 486 if (feedback != BinaryOperationHints::kAny) {
469 // Lower to the optimistic number binop. 487 // Lower to the optimistic number binop.
470 return r.ChangeToSpeculativeOperator( 488 return r.ChangeToSpeculativeOperator(
471 simplified()->SpeculativeNumberSubtract(feedback)); 489 simplified()->SpeculativeNumberSubtract(feedback), Type::Number());
472 } 490 }
473 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1); 491 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
474 r.ConvertInputsToNumberOrUndefined(frame_state); 492 r.ConvertInputsToNumberOrUndefined(frame_state);
475 return r.ChangeToPureOperator(simplified()->NumberSubtract(), Type::Number()); 493 return r.ChangeToPureOperator(simplified()->NumberSubtract(), Type::Number());
476 } 494 }
477 495
478 Reduction JSTypedLowering::ReduceJSMultiply(Node* node) { 496 Reduction JSTypedLowering::ReduceJSMultiply(Node* node) {
479 if (flags() & kDisableBinaryOpReduction) return NoChange(); 497 if (flags() & kDisableBinaryOpReduction) return NoChange();
480 JSBinopReduction r(this, node); 498 JSBinopReduction r(this, node);
481 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1); 499 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
(...skipping 55 matching lines...)
537 case IrOpcode::kJSGreaterThanOrEqual: 555 case IrOpcode::kJSGreaterThanOrEqual:
538 stringOp = simplified()->StringLessThanOrEqual(); 556 stringOp = simplified()->StringLessThanOrEqual();
539 r.SwapInputs(); // a >= b => b <= a 557 r.SwapInputs(); // a >= b => b <= a
540 break; 558 break;
541 default: 559 default:
542 return NoChange(); 560 return NoChange();
543 } 561 }
544 r.ChangeToPureOperator(stringOp); 562 r.ChangeToPureOperator(stringOp);
545 return Changed(node); 563 return Changed(node);
546 } 564 }
547 if (r.OneInputCannotBe(Type::StringOrReceiver())) { 565
566 CompareOperationHints::Hint hint = r.GetNumberCompareOperationFeedback();
567 if (hint != CompareOperationHints::kAny ||
568 r.OneInputCannotBe(Type::StringOrReceiver())) {
548 const Operator* less_than; 569 const Operator* less_than;
549 const Operator* less_than_or_equal; 570 const Operator* less_than_or_equal;
550 if (r.BothInputsAre(Type::Unsigned32())) { 571 if (r.BothInputsAre(Type::Unsigned32())) {
551 less_than = machine()->Uint32LessThan(); 572 less_than = machine()->Uint32LessThan();
552 less_than_or_equal = machine()->Uint32LessThanOrEqual(); 573 less_than_or_equal = machine()->Uint32LessThanOrEqual();
553 } else if (r.BothInputsAre(Type::Signed32())) { 574 } else if (r.BothInputsAre(Type::Signed32())) {
554 less_than = machine()->Int32LessThan(); 575 less_than = machine()->Int32LessThan();
555 less_than_or_equal = machine()->Int32LessThanOrEqual(); 576 less_than_or_equal = machine()->Int32LessThanOrEqual();
577 } else if (hint != CompareOperationHints::kAny) {
578 less_than = simplified()->SpeculativeNumberLessThan(hint);
579 less_than_or_equal = simplified()->SpeculativeNumberLessThanOrEqual(hint);
556 } else { 580 } else {
557 // TODO(turbofan): mixed signed/unsigned int32 comparisons. 581 // TODO(turbofan): mixed signed/unsigned int32 comparisons.
558 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1); 582 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
559 r.ConvertInputsToNumberOrUndefined(frame_state); 583 r.ConvertInputsToNumberOrUndefined(frame_state);
560 less_than = simplified()->NumberLessThan(); 584 less_than = simplified()->NumberLessThan();
561 less_than_or_equal = simplified()->NumberLessThanOrEqual(); 585 less_than_or_equal = simplified()->NumberLessThanOrEqual();
562 } 586 }
563 const Operator* comparison; 587 const Operator* comparison;
564 switch (node->opcode()) { 588 switch (node->opcode()) {
565 case IrOpcode::kJSLessThan: 589 case IrOpcode::kJSLessThan:
566 comparison = less_than; 590 comparison = less_than;
567 break; 591 break;
568 case IrOpcode::kJSGreaterThan: 592 case IrOpcode::kJSGreaterThan:
569 comparison = less_than; 593 comparison = less_than;
570 r.SwapInputs(); // a > b => b < a 594 r.SwapInputs(); // a > b => b < a
571 break; 595 break;
572 case IrOpcode::kJSLessThanOrEqual: 596 case IrOpcode::kJSLessThanOrEqual:
573 comparison = less_than_or_equal; 597 comparison = less_than_or_equal;
574 break; 598 break;
575 case IrOpcode::kJSGreaterThanOrEqual: 599 case IrOpcode::kJSGreaterThanOrEqual:
576 comparison = less_than_or_equal; 600 comparison = less_than_or_equal;
577 r.SwapInputs(); // a >= b => b <= a 601 r.SwapInputs(); // a >= b => b <= a
578 break; 602 break;
579 default: 603 default:
580 return NoChange(); 604 return NoChange();
581 } 605 }
582 return r.ChangeToPureOperator(comparison); 606 if (comparison->EffectInputCount() > 0) {
607 return r.ChangeToSpeculativeOperator(comparison, Type::Boolean());
608 } else {
609 return r.ChangeToPureOperator(comparison);
610 }
583 } 611 }
584 // TODO(turbofan): relax/remove effects of this operator in other cases. 612 // TODO(turbofan): relax/remove effects of this operator in other cases.
585 return NoChange(); // Keep a generic comparison. 613 return NoChange(); // Keep a generic comparison.
586 } 614 }
587 615
588 Reduction JSTypedLowering::ReduceJSEqualTypeOf(Node* node, bool invert) { 616 Reduction JSTypedLowering::ReduceJSEqualTypeOf(Node* node, bool invert) {
589 HeapObjectBinopMatcher m(node); 617 HeapObjectBinopMatcher m(node);
590 if (m.left().IsJSTypeOf() && m.right().HasValue() && 618 if (m.left().IsJSTypeOf() && m.right().HasValue() &&
591 m.right().Value()->IsString()) { 619 m.right().Value()->IsString()) {
592 Node* replacement; 620 Node* replacement;
(...skipping 1381 matching lines...)
1974 } 2002 }
1975 2003
1976 2004
1977 CompilationDependencies* JSTypedLowering::dependencies() const { 2005 CompilationDependencies* JSTypedLowering::dependencies() const {
1978 return dependencies_; 2006 return dependencies_;
1979 } 2007 }
1980 2008
1981 } // namespace compiler 2009 } // namespace compiler
1982 } // namespace internal 2010 } // namespace internal
1983 } // namespace v8 2011 } // namespace v8
OLDNEW

Powered by Google App Engine