OLD | NEW |
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/compiler/access-builder.h" | 5 #include "src/compiler/access-builder.h" |
6 #include "src/compiler/graph-inl.h" | 6 #include "src/compiler/graph-inl.h" |
7 #include "src/compiler/js-builtin-reducer.h" | 7 #include "src/compiler/js-builtin-reducer.h" |
8 #include "src/compiler/js-typed-lowering.h" | 8 #include "src/compiler/js-typed-lowering.h" |
9 #include "src/compiler/node-aux-data-inl.h" | 9 #include "src/compiler/node-aux-data-inl.h" |
10 #include "src/compiler/node-matchers.h" | 10 #include "src/compiler/node-matchers.h" |
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
134 // that encapsulates changing the operator and re-typing. | 134 // that encapsulates changing the operator and re-typing. |
135 Bounds const bounds = NodeProperties::GetBounds(node_); | 135 Bounds const bounds = NodeProperties::GetBounds(node_); |
136 NodeProperties::SetBounds(node_, Bounds::NarrowUpper(bounds, type, zone())); | 136 NodeProperties::SetBounds(node_, Bounds::NarrowUpper(bounds, type, zone())); |
137 | 137 |
138 if (invert) { | 138 if (invert) { |
139 // Insert an boolean not to invert the value. | 139 // Insert an boolean not to invert the value. |
140 Node* value = graph()->NewNode(simplified()->BooleanNot(), node_); | 140 Node* value = graph()->NewNode(simplified()->BooleanNot(), node_); |
141 node_->ReplaceUses(value); | 141 node_->ReplaceUses(value); |
142 // Note: ReplaceUses() smashes all uses, so smash it back here. | 142 // Note: ReplaceUses() smashes all uses, so smash it back here. |
143 value->ReplaceInput(0, node_); | 143 value->ReplaceInput(0, node_); |
144 return lowering_->ReplaceWith(value); | 144 return lowering_->Replace(value); |
145 } | 145 } |
146 return lowering_->Changed(node_); | 146 return lowering_->Changed(node_); |
147 } | 147 } |
148 | 148 |
149 Reduction ChangeToPureOperator(const Operator* op, Type* type) { | 149 Reduction ChangeToPureOperator(const Operator* op, Type* type) { |
150 return ChangeToPureOperator(op, false, type); | 150 return ChangeToPureOperator(op, false, type); |
151 } | 151 } |
152 | 152 |
153 bool OneInputIs(Type* t) { return left_type_->Is(t) || right_type_->Is(t); } | 153 bool OneInputIs(Type* t) { return left_type_->Is(t) || right_type_->Is(t); } |
154 | 154 |
(...skipping 342 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
497 if (result.Changed()) return result; | 497 if (result.Changed()) return result; |
498 return Changed(input); // JSToNumber(JSToNumber(x)) => JSToNumber(x) | 498 return Changed(input); // JSToNumber(JSToNumber(x)) => JSToNumber(x) |
499 } | 499 } |
500 Type* input_type = NodeProperties::GetBounds(input).upper; | 500 Type* input_type = NodeProperties::GetBounds(input).upper; |
501 if (input_type->Is(Type::Number())) { | 501 if (input_type->Is(Type::Number())) { |
502 // JSToNumber(x:number) => x | 502 // JSToNumber(x:number) => x |
503 return Changed(input); | 503 return Changed(input); |
504 } | 504 } |
505 if (input_type->Is(Type::Undefined())) { | 505 if (input_type->Is(Type::Undefined())) { |
506 // JSToNumber(undefined) => #NaN | 506 // JSToNumber(undefined) => #NaN |
507 return ReplaceWith(jsgraph()->NaNConstant()); | 507 return Replace(jsgraph()->NaNConstant()); |
508 } | 508 } |
509 if (input_type->Is(Type::Null())) { | 509 if (input_type->Is(Type::Null())) { |
510 // JSToNumber(null) => #0 | 510 // JSToNumber(null) => #0 |
511 return ReplaceWith(jsgraph()->ZeroConstant()); | 511 return Replace(jsgraph()->ZeroConstant()); |
512 } | 512 } |
513 if (input_type->Is(Type::Boolean())) { | 513 if (input_type->Is(Type::Boolean())) { |
514 // JSToNumber(x:boolean) => BooleanToNumber(x) | 514 // JSToNumber(x:boolean) => BooleanToNumber(x) |
515 return ReplaceWith( | 515 return Replace(graph()->NewNode(simplified()->BooleanToNumber(), input)); |
516 graph()->NewNode(simplified()->BooleanToNumber(), input)); | |
517 } | 516 } |
518 // TODO(turbofan): js-typed-lowering of ToNumber(x:string) | 517 // TODO(turbofan): js-typed-lowering of ToNumber(x:string) |
519 return NoChange(); | 518 return NoChange(); |
520 } | 519 } |
521 | 520 |
522 | 521 |
523 Reduction JSTypedLowering::ReduceJSToNumber(Node* node) { | 522 Reduction JSTypedLowering::ReduceJSToNumber(Node* node) { |
524 // Try to reduce the input first. | 523 // Try to reduce the input first. |
525 Node* const input = node->InputAt(0); | 524 Node* const input = node->InputAt(0); |
526 Reduction reduction = ReduceJSToNumberInput(input); | 525 Reduction reduction = ReduceJSToNumberInput(input); |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
577 RelaxEffects(input); | 576 RelaxEffects(input); |
578 return result; | 577 return result; |
579 } | 578 } |
580 return Changed(input); // JSToString(JSToString(x)) => JSToString(x) | 579 return Changed(input); // JSToString(JSToString(x)) => JSToString(x) |
581 } | 580 } |
582 Type* input_type = NodeProperties::GetBounds(input).upper; | 581 Type* input_type = NodeProperties::GetBounds(input).upper; |
583 if (input_type->Is(Type::String())) { | 582 if (input_type->Is(Type::String())) { |
584 return Changed(input); // JSToString(x:string) => x | 583 return Changed(input); // JSToString(x:string) => x |
585 } | 584 } |
586 if (input_type->Is(Type::Undefined())) { | 585 if (input_type->Is(Type::Undefined())) { |
587 return ReplaceWith(jsgraph()->HeapConstant( | 586 return Replace(jsgraph()->HeapConstant( |
588 graph()->zone()->isolate()->factory()->undefined_string())); | 587 graph()->zone()->isolate()->factory()->undefined_string())); |
589 } | 588 } |
590 if (input_type->Is(Type::Null())) { | 589 if (input_type->Is(Type::Null())) { |
591 return ReplaceWith(jsgraph()->HeapConstant( | 590 return Replace(jsgraph()->HeapConstant( |
592 graph()->zone()->isolate()->factory()->null_string())); | 591 graph()->zone()->isolate()->factory()->null_string())); |
593 } | 592 } |
594 // TODO(turbofan): js-typed-lowering of ToString(x:boolean) | 593 // TODO(turbofan): js-typed-lowering of ToString(x:boolean) |
595 // TODO(turbofan): js-typed-lowering of ToString(x:number) | 594 // TODO(turbofan): js-typed-lowering of ToString(x:number) |
596 return NoChange(); | 595 return NoChange(); |
597 } | 596 } |
598 | 597 |
599 | 598 |
600 Reduction JSTypedLowering::ReduceJSToBooleanInput(Node* input) { | 599 Reduction JSTypedLowering::ReduceJSToBooleanInput(Node* input) { |
601 if (input->opcode() == IrOpcode::kJSToBoolean) { | 600 if (input->opcode() == IrOpcode::kJSToBoolean) { |
602 // Recursively try to reduce the input first. | 601 // Recursively try to reduce the input first. |
603 Reduction result = ReduceJSToBoolean(input); | 602 Reduction result = ReduceJSToBoolean(input); |
604 if (result.Changed()) return result; | 603 if (result.Changed()) return result; |
605 return Changed(input); // JSToBoolean(JSToBoolean(x)) => JSToBoolean(x) | 604 return Changed(input); // JSToBoolean(JSToBoolean(x)) => JSToBoolean(x) |
606 } | 605 } |
607 Type* input_type = NodeProperties::GetBounds(input).upper; | 606 Type* input_type = NodeProperties::GetBounds(input).upper; |
608 if (input_type->Is(Type::Boolean())) { | 607 if (input_type->Is(Type::Boolean())) { |
609 return Changed(input); // JSToBoolean(x:boolean) => x | 608 return Changed(input); // JSToBoolean(x:boolean) => x |
610 } | 609 } |
611 if (input_type->Is(Type::Undefined())) { | 610 if (input_type->Is(Type::Undefined())) { |
612 // JSToBoolean(undefined) => #false | 611 // JSToBoolean(undefined) => #false |
613 return ReplaceWith(jsgraph()->FalseConstant()); | 612 return Replace(jsgraph()->FalseConstant()); |
614 } | 613 } |
615 if (input_type->Is(Type::Null())) { | 614 if (input_type->Is(Type::Null())) { |
616 // JSToBoolean(null) => #false | 615 // JSToBoolean(null) => #false |
617 return ReplaceWith(jsgraph()->FalseConstant()); | 616 return Replace(jsgraph()->FalseConstant()); |
618 } | 617 } |
619 if (input_type->Is(Type::DetectableReceiver())) { | 618 if (input_type->Is(Type::DetectableReceiver())) { |
620 // JSToBoolean(x:detectable) => #true | 619 // JSToBoolean(x:detectable) => #true |
621 return ReplaceWith(jsgraph()->TrueConstant()); | 620 return Replace(jsgraph()->TrueConstant()); |
622 } | 621 } |
623 if (input_type->Is(Type::Undetectable())) { | 622 if (input_type->Is(Type::Undetectable())) { |
624 // JSToBoolean(x:undetectable) => #false | 623 // JSToBoolean(x:undetectable) => #false |
625 return ReplaceWith(jsgraph()->FalseConstant()); | 624 return Replace(jsgraph()->FalseConstant()); |
626 } | 625 } |
627 if (input_type->Is(Type::OrderedNumber())) { | 626 if (input_type->Is(Type::OrderedNumber())) { |
628 // JSToBoolean(x:ordered-number) => BooleanNot(NumberEqual(x, #0)) | 627 // JSToBoolean(x:ordered-number) => BooleanNot(NumberEqual(x, #0)) |
629 Node* cmp = graph()->NewNode(simplified()->NumberEqual(), input, | 628 Node* cmp = graph()->NewNode(simplified()->NumberEqual(), input, |
630 jsgraph()->ZeroConstant()); | 629 jsgraph()->ZeroConstant()); |
631 Node* inv = graph()->NewNode(simplified()->BooleanNot(), cmp); | 630 Node* inv = graph()->NewNode(simplified()->BooleanNot(), cmp); |
632 return ReplaceWith(inv); | 631 return Replace(inv); |
633 } | 632 } |
634 if (input_type->Is(Type::String())) { | 633 if (input_type->Is(Type::String())) { |
635 // JSToBoolean(x:string) => BooleanNot(NumberEqual(x.length, #0)) | 634 // JSToBoolean(x:string) => BooleanNot(NumberEqual(x.length, #0)) |
636 FieldAccess access = AccessBuilder::ForStringLength(); | 635 FieldAccess access = AccessBuilder::ForStringLength(); |
637 Node* length = graph()->NewNode(simplified()->LoadField(access), input, | 636 Node* length = graph()->NewNode(simplified()->LoadField(access), input, |
638 graph()->start(), graph()->start()); | 637 graph()->start(), graph()->start()); |
639 Node* cmp = graph()->NewNode(simplified()->NumberEqual(), length, | 638 Node* cmp = graph()->NewNode(simplified()->NumberEqual(), length, |
640 jsgraph()->ZeroConstant()); | 639 jsgraph()->ZeroConstant()); |
641 Node* inv = graph()->NewNode(simplified()->BooleanNot(), cmp); | 640 Node* inv = graph()->NewNode(simplified()->BooleanNot(), cmp); |
642 return ReplaceWith(inv); | 641 return Replace(inv); |
643 } | 642 } |
644 return NoChange(); | 643 return NoChange(); |
645 } | 644 } |
646 | 645 |
647 | 646 |
648 Reduction JSTypedLowering::ReduceJSToBoolean(Node* node) { | 647 Reduction JSTypedLowering::ReduceJSToBoolean(Node* node) { |
649 // Try to reduce the input first. | 648 // Try to reduce the input first. |
650 Node* const input = node->InputAt(0); | 649 Node* const input = node->InputAt(0); |
651 Reduction reduction = ReduceJSToBooleanInput(input); | 650 Reduction reduction = ReduceJSToBooleanInput(input); |
652 if (reduction.Changed()) { | 651 if (reduction.Changed()) return reduction; |
653 NodeProperties::ReplaceWithValue(node, reduction.replacement()); | 652 if (input->opcode() == IrOpcode::kPhi) { |
654 return reduction; | 653 // JSToBoolean(phi(x1,...,xn,control),context) |
655 } | 654 // => phi(JSToBoolean(x1,no-context),...,JSToBoolean(xn,no-context)) |
656 Type* const input_type = NodeProperties::GetBounds(input).upper; | |
657 if (input->opcode() == IrOpcode::kPhi && input_type->Is(Type::Primitive())) { | |
658 Node* const context = node->InputAt(1); | |
659 // JSToBoolean(phi(x1,...,xn,control):primitive) | |
660 // => phi(JSToBoolean(x1),...,JSToBoolean(xn),control):boolean | |
661 RelaxEffects(node); | |
662 int const input_count = input->InputCount() - 1; | 655 int const input_count = input->InputCount() - 1; |
663 Node* const control = input->InputAt(input_count); | 656 Node* const control = input->InputAt(input_count); |
664 DCHECK_LE(0, input_count); | 657 DCHECK_LE(0, input_count); |
665 DCHECK(NodeProperties::IsControl(control)); | 658 DCHECK(NodeProperties::IsControl(control)); |
666 DCHECK(NodeProperties::GetBounds(node).upper->Is(Type::Boolean())); | 659 DCHECK(NodeProperties::GetBounds(node).upper->Is(Type::Boolean())); |
667 DCHECK(!NodeProperties::GetBounds(input).upper->Is(Type::Boolean())); | 660 DCHECK(!NodeProperties::GetBounds(input).upper->Is(Type::Boolean())); |
668 node->set_op(common()->Phi(kMachAnyTagged, input_count)); | 661 node->set_op(common()->Phi(kMachAnyTagged, input_count)); |
669 for (int i = 0; i < input_count; ++i) { | 662 for (int i = 0; i < input_count; ++i) { |
670 Node* value = input->InputAt(i); | 663 Node* value = input->InputAt(i); |
671 // Recursively try to reduce the value first. | 664 // Recursively try to reduce the value first. |
672 Reduction reduction = ReduceJSToBooleanInput(value); | 665 Reduction reduction = ReduceJSToBooleanInput(value); |
673 if (reduction.Changed()) { | 666 if (reduction.Changed()) { |
674 value = reduction.replacement(); | 667 value = reduction.replacement(); |
675 } else { | 668 } else { |
676 value = graph()->NewNode(javascript()->ToBoolean(), value, context, | 669 // We must be very careful not to introduce cycles when pushing |
677 graph()->start(), graph()->start()); | 670 // operations into phis. It is safe for {value}, since it appears |
| 671 // as input to the phi that we are replacing, but it's not safe |
| 672 // to simply reuse the context of the {node}. However, ToBoolean() |
| 673 // does not require a context anyways, so it's safe to discard it |
| 674 // here and pass the dummy context. |
| 675 value = graph()->NewNode(javascript()->ToBoolean(), value, |
| 676 jsgraph()->NoContextConstant()); |
678 } | 677 } |
679 if (i < node->InputCount()) { | 678 if (i < node->InputCount()) { |
680 node->ReplaceInput(i, value); | 679 node->ReplaceInput(i, value); |
681 } else { | 680 } else { |
682 node->AppendInput(graph()->zone(), value); | 681 node->AppendInput(graph()->zone(), value); |
683 } | 682 } |
684 } | 683 } |
685 if (input_count < node->InputCount()) { | 684 if (input_count < node->InputCount()) { |
686 node->ReplaceInput(input_count, control); | 685 node->ReplaceInput(input_count, control); |
687 } else { | 686 } else { |
688 node->AppendInput(graph()->zone(), control); | 687 node->AppendInput(graph()->zone(), control); |
689 } | 688 } |
690 node->TrimInputCount(input_count + 1); | 689 node->TrimInputCount(input_count + 1); |
691 return Changed(node); | 690 return Changed(node); |
692 } | 691 } |
| 692 if (input->opcode() == IrOpcode::kSelect) { |
| 693 // JSToBoolean(select(c,x1,x2),context) |
| 694 // => select(c,JSToBoolean(x1,no-context),...,JSToBoolean(x2,no-context)) |
| 695 int const input_count = input->InputCount(); |
| 696 BranchHint const input_hint = SelectParametersOf(input->op()).hint(); |
| 697 DCHECK_EQ(3, input_count); |
| 698 DCHECK(NodeProperties::GetBounds(node).upper->Is(Type::Boolean())); |
| 699 DCHECK(!NodeProperties::GetBounds(input).upper->Is(Type::Boolean())); |
| 700 node->set_op(common()->Select(kMachAnyTagged, input_hint)); |
| 701 node->InsertInput(graph()->zone(), 0, input->InputAt(0)); |
| 702 for (int i = 1; i < input_count; ++i) { |
| 703 Node* value = input->InputAt(i); |
| 704 // Recursively try to reduce the value first. |
| 705 Reduction reduction = ReduceJSToBooleanInput(value); |
| 706 if (reduction.Changed()) { |
| 707 value = reduction.replacement(); |
| 708 } else { |
| 709 // We must be very careful not to introduce cycles when pushing |
| 710 // operations into selects. It is safe for {value}, since it appears |
| 711 // as input to the select that we are replacing, but it's not safe |
| 712 // to simply reuse the context of the {node}. However, ToBoolean() |
| 713 // does not require a context anyways, so it's safe to discard it |
| 714 // here and pass the dummy context. |
| 715 value = graph()->NewNode(javascript()->ToBoolean(), value, |
| 716 jsgraph()->NoContextConstant()); |
| 717 } |
| 718 node->ReplaceInput(i, value); |
| 719 } |
| 720 DCHECK_EQ(3, node->InputCount()); |
| 721 return Changed(node); |
| 722 } |
693 return NoChange(); | 723 return NoChange(); |
694 } | 724 } |
695 | 725 |
696 | 726 |
697 Reduction JSTypedLowering::ReduceJSLoadProperty(Node* node) { | 727 Reduction JSTypedLowering::ReduceJSLoadProperty(Node* node) { |
698 Node* key = NodeProperties::GetValueInput(node, 1); | 728 Node* key = NodeProperties::GetValueInput(node, 1); |
699 Node* base = NodeProperties::GetValueInput(node, 0); | 729 Node* base = NodeProperties::GetValueInput(node, 0); |
700 Type* key_type = NodeProperties::GetBounds(key).upper; | 730 Type* key_type = NodeProperties::GetBounds(key).upper; |
701 Type* base_type = NodeProperties::GetBounds(base).upper; | 731 Type* base_type = NodeProperties::GetBounds(base).upper; |
702 // TODO(mstarzinger): This lowering is not correct if: | 732 // TODO(mstarzinger): This lowering is not correct if: |
(...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
908 case IrOpcode::kJSSubtract: | 938 case IrOpcode::kJSSubtract: |
909 return ReduceNumberBinop(node, simplified()->NumberSubtract()); | 939 return ReduceNumberBinop(node, simplified()->NumberSubtract()); |
910 case IrOpcode::kJSMultiply: | 940 case IrOpcode::kJSMultiply: |
911 return ReduceJSMultiply(node); | 941 return ReduceJSMultiply(node); |
912 case IrOpcode::kJSDivide: | 942 case IrOpcode::kJSDivide: |
913 return ReduceNumberBinop(node, simplified()->NumberDivide()); | 943 return ReduceNumberBinop(node, simplified()->NumberDivide()); |
914 case IrOpcode::kJSModulus: | 944 case IrOpcode::kJSModulus: |
915 return ReduceNumberBinop(node, simplified()->NumberModulus()); | 945 return ReduceNumberBinop(node, simplified()->NumberModulus()); |
916 case IrOpcode::kJSUnaryNot: { | 946 case IrOpcode::kJSUnaryNot: { |
917 Reduction result = ReduceJSToBooleanInput(node->InputAt(0)); | 947 Reduction result = ReduceJSToBooleanInput(node->InputAt(0)); |
918 Node* value; | |
919 if (result.Changed()) { | 948 if (result.Changed()) { |
920 // JSUnaryNot(x:boolean) => BooleanNot(x) | 949 // JSUnaryNot(x:boolean) => BooleanNot(x) |
921 value = | 950 node = result.replacement(); |
922 graph()->NewNode(simplified()->BooleanNot(), result.replacement()); | |
923 NodeProperties::ReplaceWithValue(node, value); | |
924 return Changed(value); | |
925 } else { | 951 } else { |
926 // JSUnaryNot(x) => BooleanNot(JSToBoolean(x)) | 952 // JSUnaryNot(x) => BooleanNot(JSToBoolean(x)) |
927 value = graph()->NewNode(simplified()->BooleanNot(), node); | |
928 node->set_op(javascript()->ToBoolean()); | 953 node->set_op(javascript()->ToBoolean()); |
929 NodeProperties::ReplaceWithValue(node, value, node); | |
930 // Note: ReplaceUses() smashes all uses, so smash it back here. | |
931 value->ReplaceInput(0, node); | |
932 return Changed(node); | |
933 } | 954 } |
| 955 Node* value = graph()->NewNode(simplified()->BooleanNot(), node); |
| 956 return Replace(value); |
934 } | 957 } |
935 case IrOpcode::kJSToBoolean: | 958 case IrOpcode::kJSToBoolean: |
936 return ReduceJSToBoolean(node); | 959 return ReduceJSToBoolean(node); |
937 case IrOpcode::kJSToNumber: | 960 case IrOpcode::kJSToNumber: |
938 return ReduceJSToNumber(node); | 961 return ReduceJSToNumber(node); |
939 case IrOpcode::kJSToString: | 962 case IrOpcode::kJSToString: |
940 return ReplaceWithReduction(node, | 963 return ReplaceWithReduction(node, |
941 ReduceJSToStringInput(node->InputAt(0))); | 964 ReduceJSToStringInput(node->InputAt(0))); |
942 case IrOpcode::kJSLoadProperty: | 965 case IrOpcode::kJSLoadProperty: |
943 return ReduceJSLoadProperty(node); | 966 return ReduceJSLoadProperty(node); |
(...skipping 14 matching lines...) Expand all Loading... |
958 | 981 |
959 Node* JSTypedLowering::Word32Shl(Node* const lhs, int32_t const rhs) { | 982 Node* JSTypedLowering::Word32Shl(Node* const lhs, int32_t const rhs) { |
960 if (rhs == 0) return lhs; | 983 if (rhs == 0) return lhs; |
961 return graph()->NewNode(machine()->Word32Shl(), lhs, | 984 return graph()->NewNode(machine()->Word32Shl(), lhs, |
962 jsgraph()->Int32Constant(rhs)); | 985 jsgraph()->Int32Constant(rhs)); |
963 } | 986 } |
964 | 987 |
965 } // namespace compiler | 988 } // namespace compiler |
966 } // namespace internal | 989 } // namespace internal |
967 } // namespace v8 | 990 } // namespace v8 |
OLD | NEW |