Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(64)

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: Rebase, pure ops Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/compiler/js-operator.cc ('k') | src/compiler/opcodes.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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::kNumber) {
60 return combined;
61 }
62 return CompareOperationHints::kAny;
63 }
64
48 void ConvertInputsToNumber(Node* frame_state) { 65 void ConvertInputsToNumber(Node* frame_state) {
49 // To convert the inputs to numbers, we have to provide frame states 66 // To convert the inputs to numbers, we have to provide frame states
50 // for lazy bailouts in the ToNumber conversions. 67 // for lazy bailouts in the ToNumber conversions.
51 // We use a little hack here: we take the frame state before the binary 68 // 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 69 // operation and use it to construct the frame states for the conversion
53 // so that after the deoptimization, the binary operation IC gets 70 // so that after the deoptimization, the binary operation IC gets
54 // already converted values from full code. This way we are sure that we 71 // already converted values from full code. This way we are sure that we
55 // will not re-do any of the side effects. 72 // will not re-do any of the side effects.
56 73
57 Node* left_input = nullptr; 74 Node* left_input = nullptr;
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
118 // Insert an boolean not to invert the value. 135 // Insert an boolean not to invert the value.
119 Node* value = graph()->NewNode(simplified()->BooleanNot(), node_); 136 Node* value = graph()->NewNode(simplified()->BooleanNot(), node_);
120 node_->ReplaceUses(value); 137 node_->ReplaceUses(value);
121 // Note: ReplaceUses() smashes all uses, so smash it back here. 138 // Note: ReplaceUses() smashes all uses, so smash it back here.
122 value->ReplaceInput(0, node_); 139 value->ReplaceInput(0, node_);
123 return lowering_->Replace(value); 140 return lowering_->Replace(value);
124 } 141 }
125 return lowering_->Changed(node_); 142 return lowering_->Changed(node_);
126 } 143 }
127 144
128 Reduction ChangeToSpeculativeOperator(const Operator* op) { 145 Reduction ChangeToSpeculativeOperator(const Operator* op, Type* upper_bound) {
129 DCHECK_EQ(1, op->EffectInputCount()); 146 DCHECK_EQ(1, op->EffectInputCount());
130 DCHECK_EQ(1, op->EffectOutputCount()); 147 DCHECK_EQ(1, op->EffectOutputCount());
131 DCHECK_EQ(false, OperatorProperties::HasContextInput(op)); 148 DCHECK_EQ(false, OperatorProperties::HasContextInput(op));
132 DCHECK_EQ(1, op->ControlInputCount()); 149 DCHECK_EQ(1, op->ControlInputCount());
133 DCHECK_EQ(1, op->ControlOutputCount()); 150 DCHECK_EQ(1, op->ControlOutputCount());
134 DCHECK_EQ(0, OperatorProperties::GetFrameStateInputCount(op)); 151 DCHECK_EQ(0, OperatorProperties::GetFrameStateInputCount(op));
135 DCHECK_EQ(2, op->ValueInputCount()); 152 DCHECK_EQ(2, op->ValueInputCount());
136 153
137 DCHECK_EQ(1, node_->op()->EffectInputCount()); 154 DCHECK_EQ(1, node_->op()->EffectInputCount());
138 DCHECK_EQ(1, node_->op()->EffectOutputCount()); 155 DCHECK_EQ(1, node_->op()->EffectOutputCount());
(...skipping 21 matching lines...) Expand all
160 // Remove both bailout frame states and the context. 177 // Remove both bailout frame states and the context.
161 node_->RemoveInput(NodeProperties::FirstFrameStateIndex(node_) + 1); 178 node_->RemoveInput(NodeProperties::FirstFrameStateIndex(node_) + 1);
162 node_->RemoveInput(NodeProperties::FirstFrameStateIndex(node_)); 179 node_->RemoveInput(NodeProperties::FirstFrameStateIndex(node_));
163 node_->RemoveInput(NodeProperties::FirstContextIndex(node_)); 180 node_->RemoveInput(NodeProperties::FirstContextIndex(node_));
164 181
165 NodeProperties::ChangeOp(node_, op); 182 NodeProperties::ChangeOp(node_, op);
166 183
167 // Update the type to number. 184 // Update the type to number.
168 Type* node_type = NodeProperties::GetType(node_); 185 Type* node_type = NodeProperties::GetType(node_);
169 NodeProperties::SetType(node_, 186 NodeProperties::SetType(node_,
170 Type::Intersect(node_type, Type::Number(), zone())); 187 Type::Intersect(node_type, upper_bound, zone()));
171 188
172 return lowering_->Changed(node_); 189 return lowering_->Changed(node_);
173 } 190 }
174 191
175 Reduction ChangeToPureOperator(const Operator* op, Type* type) { 192 Reduction ChangeToPureOperator(const Operator* op, Type* type) {
176 return ChangeToPureOperator(op, false, type); 193 return ChangeToPureOperator(op, false, type);
177 } 194 }
178 195
179 bool LeftInputIs(Type* t) { return left_type()->Is(t); } 196 bool LeftInputIs(Type* t) { return left_type()->Is(t); }
180 197
(...skipping 215 matching lines...) Expand 10 before | Expand all | Expand 10 after
396 shifted_int32_ranges_[k] = Type::Range(min, max, graph()->zone()); 413 shifted_int32_ranges_[k] = Type::Range(min, max, graph()->zone());
397 } 414 }
398 } 415 }
399 416
400 417
401 Reduction JSTypedLowering::ReduceJSAdd(Node* node) { 418 Reduction JSTypedLowering::ReduceJSAdd(Node* node) {
402 if (flags() & kDisableBinaryOpReduction) return NoChange(); 419 if (flags() & kDisableBinaryOpReduction) return NoChange();
403 420
404 JSBinopReduction r(this, node); 421 JSBinopReduction r(this, node);
405 422
406 BinaryOperationHints::Hint feedback = r.GetUsableNumberFeedback(); 423 BinaryOperationHints::Hint feedback = r.GetNumberBinaryOperationFeedback();
407 if (feedback == BinaryOperationHints::kNumberOrUndefined && 424 if (feedback == BinaryOperationHints::kNumberOrUndefined &&
408 r.BothInputsAre(Type::PlainPrimitive()) && 425 r.BothInputsAre(Type::PlainPrimitive()) &&
409 r.NeitherInputCanBe(Type::StringOrReceiver())) { 426 r.NeitherInputCanBe(Type::StringOrReceiver())) {
410 // JSAdd(x:-string, y:-string) => NumberAdd(ToNumber(x), ToNumber(y)) 427 // JSAdd(x:-string, y:-string) => NumberAdd(ToNumber(x), ToNumber(y))
411 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1); 428 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
412 r.ConvertInputsToNumber(frame_state); 429 r.ConvertInputsToNumber(frame_state);
413 return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number()); 430 return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number());
414 } 431 }
415 if (feedback != BinaryOperationHints::kAny) { 432 if (feedback != BinaryOperationHints::kAny) {
416 // Lower to the optimistic number binop. 433 // Lower to the optimistic number binop.
417 return r.ChangeToSpeculativeOperator( 434 return r.ChangeToSpeculativeOperator(
418 simplified()->SpeculativeNumberAdd(feedback)); 435 simplified()->SpeculativeNumberAdd(feedback), Type::Number());
419 } 436 }
420 if (r.BothInputsAre(Type::Number())) { 437 if (r.BothInputsAre(Type::Number())) {
421 // JSAdd(x:number, y:number) => NumberAdd(x, y) 438 // JSAdd(x:number, y:number) => NumberAdd(x, y)
422 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1); 439 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
423 r.ConvertInputsToNumber(frame_state); 440 r.ConvertInputsToNumber(frame_state);
424 return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number()); 441 return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number());
425 } 442 }
426 if (r.NeitherInputCanBe(Type::StringOrReceiver())) { 443 if (r.NeitherInputCanBe(Type::StringOrReceiver())) {
427 // JSAdd(x:-string, y:-string) => NumberAdd(ToNumber(x), ToNumber(y)) 444 // JSAdd(x:-string, y:-string) => NumberAdd(ToNumber(x), ToNumber(y))
428 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1); 445 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
462 // JSModulus(x:number, x:number) => NumberModulus(x, y) 479 // JSModulus(x:number, x:number) => NumberModulus(x, y)
463 return r.ChangeToPureOperator(simplified()->NumberModulus(), 480 return r.ChangeToPureOperator(simplified()->NumberModulus(),
464 Type::Number()); 481 Type::Number());
465 } 482 }
466 return NoChange(); 483 return NoChange();
467 } 484 }
468 485
469 Reduction JSTypedLowering::ReduceJSSubtract(Node* node) { 486 Reduction JSTypedLowering::ReduceJSSubtract(Node* node) {
470 if (flags() & kDisableBinaryOpReduction) return NoChange(); 487 if (flags() & kDisableBinaryOpReduction) return NoChange();
471 JSBinopReduction r(this, node); 488 JSBinopReduction r(this, node);
472 BinaryOperationHints::Hint feedback = r.GetUsableNumberFeedback(); 489 BinaryOperationHints::Hint feedback = r.GetNumberBinaryOperationFeedback();
473 if (feedback == BinaryOperationHints::kNumberOrUndefined && 490 if (feedback == BinaryOperationHints::kNumberOrUndefined &&
474 r.BothInputsAre(Type::PlainPrimitive())) { 491 r.BothInputsAre(Type::PlainPrimitive())) {
475 // JSSubtract(x:plain-primitive, y:plain-primitive) 492 // JSSubtract(x:plain-primitive, y:plain-primitive)
476 // => NumberSubtract(ToNumber(x), ToNumber(y)) 493 // => NumberSubtract(ToNumber(x), ToNumber(y))
477 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1); 494 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
478 r.ConvertInputsToNumber(frame_state); 495 r.ConvertInputsToNumber(frame_state);
479 return r.ChangeToPureOperator(simplified()->NumberSubtract(), 496 return r.ChangeToPureOperator(simplified()->NumberSubtract(),
480 Type::Number()); 497 Type::Number());
481 } 498 }
482 if (feedback != BinaryOperationHints::kAny) { 499 if (feedback != BinaryOperationHints::kAny) {
483 // Lower to the optimistic number binop. 500 // Lower to the optimistic number binop.
484 return r.ChangeToSpeculativeOperator( 501 return r.ChangeToSpeculativeOperator(
485 simplified()->SpeculativeNumberSubtract(feedback)); 502 simplified()->SpeculativeNumberSubtract(feedback), Type::Number());
486 } 503 }
487 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1); 504 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
488 r.ConvertInputsToNumber(frame_state); 505 r.ConvertInputsToNumber(frame_state);
489 return r.ChangeToPureOperator(simplified()->NumberSubtract(), Type::Number()); 506 return r.ChangeToPureOperator(simplified()->NumberSubtract(), Type::Number());
490 } 507 }
491 508
492 Reduction JSTypedLowering::ReduceJSMultiply(Node* node) { 509 Reduction JSTypedLowering::ReduceJSMultiply(Node* node) {
493 if (flags() & kDisableBinaryOpReduction) return NoChange(); 510 if (flags() & kDisableBinaryOpReduction) return NoChange();
494 JSBinopReduction r(this, node); 511 JSBinopReduction r(this, node);
495 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1); 512 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
551 case IrOpcode::kJSGreaterThanOrEqual: 568 case IrOpcode::kJSGreaterThanOrEqual:
552 stringOp = simplified()->StringLessThanOrEqual(); 569 stringOp = simplified()->StringLessThanOrEqual();
553 r.SwapInputs(); // a >= b => b <= a 570 r.SwapInputs(); // a >= b => b <= a
554 break; 571 break;
555 default: 572 default:
556 return NoChange(); 573 return NoChange();
557 } 574 }
558 r.ChangeToPureOperator(stringOp); 575 r.ChangeToPureOperator(stringOp);
559 return Changed(node); 576 return Changed(node);
560 } 577 }
561 if (r.OneInputCannotBe(Type::StringOrReceiver())) { 578
579 CompareOperationHints::Hint hint = r.GetNumberCompareOperationFeedback();
580 if (hint != CompareOperationHints::kAny ||
581 r.OneInputCannotBe(Type::StringOrReceiver())) {
562 const Operator* less_than; 582 const Operator* less_than;
563 const Operator* less_than_or_equal; 583 const Operator* less_than_or_equal;
564 if (r.BothInputsAre(Type::Unsigned32())) { 584 if (r.BothInputsAre(Type::Unsigned32())) {
565 less_than = machine()->Uint32LessThan(); 585 less_than = machine()->Uint32LessThan();
566 less_than_or_equal = machine()->Uint32LessThanOrEqual(); 586 less_than_or_equal = machine()->Uint32LessThanOrEqual();
567 } else if (r.BothInputsAre(Type::Signed32())) { 587 } else if (r.BothInputsAre(Type::Signed32())) {
568 less_than = machine()->Int32LessThan(); 588 less_than = machine()->Int32LessThan();
569 less_than_or_equal = machine()->Int32LessThanOrEqual(); 589 less_than_or_equal = machine()->Int32LessThanOrEqual();
590 } else if (hint != CompareOperationHints::kAny) {
591 less_than = simplified()->SpeculativeNumberLessThan(hint);
592 less_than_or_equal = simplified()->SpeculativeNumberLessThanOrEqual(hint);
570 } else { 593 } else {
571 // TODO(turbofan): mixed signed/unsigned int32 comparisons. 594 // TODO(turbofan): mixed signed/unsigned int32 comparisons.
572 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1); 595 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
573 r.ConvertInputsToNumber(frame_state); 596 r.ConvertInputsToNumber(frame_state);
574 less_than = simplified()->NumberLessThan(); 597 less_than = simplified()->NumberLessThan();
575 less_than_or_equal = simplified()->NumberLessThanOrEqual(); 598 less_than_or_equal = simplified()->NumberLessThanOrEqual();
576 } 599 }
577 const Operator* comparison; 600 const Operator* comparison;
578 switch (node->opcode()) { 601 switch (node->opcode()) {
579 case IrOpcode::kJSLessThan: 602 case IrOpcode::kJSLessThan:
580 comparison = less_than; 603 comparison = less_than;
581 break; 604 break;
582 case IrOpcode::kJSGreaterThan: 605 case IrOpcode::kJSGreaterThan:
583 comparison = less_than; 606 comparison = less_than;
584 r.SwapInputs(); // a > b => b < a 607 r.SwapInputs(); // a > b => b < a
585 break; 608 break;
586 case IrOpcode::kJSLessThanOrEqual: 609 case IrOpcode::kJSLessThanOrEqual:
587 comparison = less_than_or_equal; 610 comparison = less_than_or_equal;
588 break; 611 break;
589 case IrOpcode::kJSGreaterThanOrEqual: 612 case IrOpcode::kJSGreaterThanOrEqual:
590 comparison = less_than_or_equal; 613 comparison = less_than_or_equal;
591 r.SwapInputs(); // a >= b => b <= a 614 r.SwapInputs(); // a >= b => b <= a
592 break; 615 break;
593 default: 616 default:
594 return NoChange(); 617 return NoChange();
595 } 618 }
596 return r.ChangeToPureOperator(comparison); 619 if (comparison->EffectInputCount() > 0) {
620 return r.ChangeToSpeculativeOperator(comparison, Type::Boolean());
621 } else {
622 return r.ChangeToPureOperator(comparison);
623 }
597 } 624 }
598 // TODO(turbofan): relax/remove effects of this operator in other cases. 625 // TODO(turbofan): relax/remove effects of this operator in other cases.
599 return NoChange(); // Keep a generic comparison. 626 return NoChange(); // Keep a generic comparison.
600 } 627 }
601 628
602 Reduction JSTypedLowering::ReduceJSEqualTypeOf(Node* node, bool invert) { 629 Reduction JSTypedLowering::ReduceJSEqualTypeOf(Node* node, bool invert) {
603 HeapObjectBinopMatcher m(node); 630 HeapObjectBinopMatcher m(node);
604 if (m.left().IsJSTypeOf() && m.right().HasValue() && 631 if (m.left().IsJSTypeOf() && m.right().HasValue() &&
605 m.right().Value()->IsString()) { 632 m.right().Value()->IsString()) {
606 Node* replacement; 633 Node* replacement;
(...skipping 1357 matching lines...) Expand 10 before | Expand all | Expand 10 after
1964 } 1991 }
1965 1992
1966 1993
1967 CompilationDependencies* JSTypedLowering::dependencies() const { 1994 CompilationDependencies* JSTypedLowering::dependencies() const {
1968 return dependencies_; 1995 return dependencies_;
1969 } 1996 }
1970 1997
1971 } // namespace compiler 1998 } // namespace compiler
1972 } // namespace internal 1999 } // namespace internal
1973 } // namespace v8 2000 } // namespace v8
OLDNEW
« no previous file with comments | « src/compiler/js-operator.cc ('k') | src/compiler/opcodes.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698