| 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/simplified-lowering.h" | 5 #include "src/compiler/simplified-lowering.h" |
| 6 | 6 |
| 7 #include <limits> | 7 #include <limits> |
| 8 | 8 |
| 9 #include "src/base/bits.h" | 9 #include "src/base/bits.h" |
| 10 #include "src/code-factory.h" | 10 #include "src/code-factory.h" |
| (...skipping 482 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 493 type = Type::Any(); | 493 type = Type::Any(); |
| 494 break; | 494 break; |
| 495 } | 495 } |
| 496 return SetOutput(node, NodeOutputInfo(machine_type.representation(), type)); | 496 return SetOutput(node, NodeOutputInfo(machine_type.representation(), type)); |
| 497 } | 497 } |
| 498 | 498 |
| 499 void SetOutput(Node* node, NodeOutputInfo output_info) { | 499 void SetOutput(Node* node, NodeOutputInfo output_info) { |
| 500 // Every node should have at most one output representation. Note that | 500 // Every node should have at most one output representation. Note that |
| 501 // phis can have 0, if they have not been used in a representation-inducing | 501 // phis can have 0, if they have not been used in a representation-inducing |
| 502 // instruction. | 502 // instruction. |
| 503 Type* output_type = output_info.type(); |
| 504 if (NodeProperties::IsTyped(node)) { |
| 505 output_type = Type::Intersect(NodeProperties::GetType(node), |
| 506 output_info.type(), jsgraph_->zone()); |
| 507 } |
| 503 NodeInfo* info = GetInfo(node); | 508 NodeInfo* info = GetInfo(node); |
| 509 DCHECK(info->output_type()->Is(output_type)); |
| 504 DCHECK(MachineRepresentationIsSubtype(info->representation(), | 510 DCHECK(MachineRepresentationIsSubtype(info->representation(), |
| 505 output_info.representation())); | 511 output_info.representation())); |
| 506 DCHECK(info->output_type()->Is(output_info.type())); | 512 if (!output_type->Is(info->output_type()) || |
| 507 if (!output_info.type()->Is(info->output_type()) || | |
| 508 output_info.representation() != info->representation()) { | 513 output_info.representation() != info->representation()) { |
| 509 EnqueueUses(node); | 514 EnqueueUses(node); |
| 510 } | 515 } |
| 511 info->set_output_type(output_info); | 516 info->set_output_type( |
| 517 NodeOutputInfo(output_info.representation(), output_type)); |
| 512 } | 518 } |
| 513 | 519 |
| 514 bool BothInputsAreSigned32(Node* node) { | 520 bool BothInputsAreSigned32(Node* node) { |
| 515 DCHECK_EQ(2, node->InputCount()); | 521 DCHECK_EQ(2, node->InputCount()); |
| 516 return (NodeProperties::GetType(node->InputAt(0))->Is(Type::Signed32()) || | 522 return GetInfo(node->InputAt(0))->output_type()->Is(Type::Signed32()) && |
| 517 GetInfo(node->InputAt(0))->output_type()->Is(Type::Signed32())) && | 523 GetInfo(node->InputAt(1))->output_type()->Is(Type::Signed32()); |
| 518 (NodeProperties::GetType(node->InputAt(1))->Is(Type::Signed32()) || | |
| 519 GetInfo(node->InputAt(1))->output_type()->Is(Type::Signed32())); | |
| 520 } | 524 } |
| 521 | 525 |
| 522 bool BothInputsAreUnsigned32(Node* node) { | 526 bool BothInputsAreUnsigned32(Node* node) { |
| 523 DCHECK_EQ(2, node->InputCount()); | 527 DCHECK_EQ(2, node->InputCount()); |
| 524 return (NodeProperties::GetType(node->InputAt(0))->Is(Type::Unsigned32()) || | 528 return GetInfo(node->InputAt(0))->output_type()->Is(Type::Unsigned32()) && |
| 525 GetInfo(node->InputAt(0))->output_type()->Is(Type::Unsigned32())) && | 529 GetInfo(node->InputAt(1))->output_type()->Is(Type::Unsigned32()); |
| 526 (NodeProperties::GetType(node->InputAt(1))->Is(Type::Unsigned32()) || | |
| 527 GetInfo(node->InputAt(1))->output_type()->Is(Type::Unsigned32())); | |
| 528 } | 530 } |
| 529 | 531 |
| 530 bool BothInputsAre(Node* node, Type* type) { | 532 bool BothInputsAre(Node* node, Type* type) { |
| 531 DCHECK_EQ(2, node->InputCount()); | 533 DCHECK_EQ(2, node->InputCount()); |
| 532 return NodeProperties::GetType(node->InputAt(0))->Is(type) && | 534 return GetInfo(node->InputAt(0))->output_type()->Is(type) && |
| 533 NodeProperties::GetType(node->InputAt(1))->Is(type); | 535 GetInfo(node->InputAt(1))->output_type()->Is(type); |
| 534 } | 536 } |
| 535 | 537 |
| 536 void ConvertInput(Node* node, int index, UseInfo use) { | 538 void ConvertInput(Node* node, int index, UseInfo use) { |
| 537 Node* input = node->InputAt(index); | 539 Node* input = node->InputAt(index); |
| 538 // In the change phase, insert a change before the use if necessary. | 540 // In the change phase, insert a change before the use if necessary. |
| 539 if (use.preferred() == MachineRepresentation::kNone) | 541 if (use.preferred() == MachineRepresentation::kNone) |
| 540 return; // No input requirement on the use. | 542 return; // No input requirement on the use. |
| 541 NodeInfo* input_info = GetInfo(input); | 543 NodeInfo* input_info = GetInfo(input); |
| 542 MachineRepresentation input_rep = input_info->representation(); | 544 MachineRepresentation input_rep = input_info->representation(); |
| 543 if (input_rep != use.preferred()) { | 545 if (input_rep != use.preferred()) { |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 654 VisitBinop(node, UseInfo::TruncatingWord32(), NodeOutputInfo::Bool()); | 656 VisitBinop(node, UseInfo::TruncatingWord32(), NodeOutputInfo::Bool()); |
| 655 } | 657 } |
| 656 void VisitInt64Cmp(Node* node) { | 658 void VisitInt64Cmp(Node* node) { |
| 657 VisitBinop(node, UseInfo::TruncatingWord64(), NodeOutputInfo::Bool()); | 659 VisitBinop(node, UseInfo::TruncatingWord64(), NodeOutputInfo::Bool()); |
| 658 } | 660 } |
| 659 void VisitUint64Cmp(Node* node) { | 661 void VisitUint64Cmp(Node* node) { |
| 660 VisitBinop(node, UseInfo::TruncatingWord64(), NodeOutputInfo::Bool()); | 662 VisitBinop(node, UseInfo::TruncatingWord64(), NodeOutputInfo::Bool()); |
| 661 } | 663 } |
| 662 | 664 |
| 663 // Infer representation for phi-like nodes. | 665 // Infer representation for phi-like nodes. |
| 664 static MachineRepresentation GetRepresentationForPhi(Node* node, | 666 NodeOutputInfo GetOutputInfoForPhi(Node* node, Truncation use) { |
| 665 Truncation use) { | 667 // Compute the type. |
| 666 // Phis adapt to the output representation their uses demand. | 668 Type* type = GetInfo(node->InputAt(0))->output_type(); |
| 667 Type* type = NodeProperties::GetType(node); | 669 for (int i = 1; i < node->op()->ValueInputCount(); ++i) { |
| 668 if (type->Is(Type::Signed32()) || type->Is(Type::Unsigned32())) { | 670 type = Type::Union(type, GetInfo(node->InputAt(i))->output_type(), |
| 669 // We are within 32 bits range => pick kRepWord32. | 671 jsgraph_->zone()); |
| 670 return MachineRepresentation::kWord32; | 672 } |
| 673 |
| 674 // Compute the representation. |
| 675 MachineRepresentation rep = MachineRepresentation::kTagged; |
| 676 if (type->Is(Type::None())) { |
| 677 rep = MachineRepresentation::kNone; |
| 678 } else if (type->Is(Type::Signed32()) || type->Is(Type::Unsigned32())) { |
| 679 rep = MachineRepresentation::kWord32; |
| 671 } else if (use.TruncatesToWord32()) { | 680 } else if (use.TruncatesToWord32()) { |
| 672 // We only use 32 bits. | 681 rep = MachineRepresentation::kWord32; |
| 673 return MachineRepresentation::kWord32; | |
| 674 } else if (type->Is(Type::Boolean())) { | 682 } else if (type->Is(Type::Boolean())) { |
| 675 // multiple uses => pick kRepBit. | 683 rep = MachineRepresentation::kBit; |
| 676 return MachineRepresentation::kBit; | |
| 677 } else if (type->Is(Type::Number())) { | 684 } else if (type->Is(Type::Number())) { |
| 678 // multiple uses => pick kRepFloat64. | 685 rep = MachineRepresentation::kFloat64; |
| 679 return MachineRepresentation::kFloat64; | |
| 680 } else if (type->Is(Type::Internal())) { | 686 } else if (type->Is(Type::Internal())) { |
| 681 return MachineType::PointerRepresentation(); | 687 // We mark (u)int64 as Type::Internal. |
| 688 // TODO(jarin) This is a workaround for our lack of (u)int64 |
| 689 // types. This can be removed once we can represent (u)int64 |
| 690 // unambiguously. (At the moment internal objects, such as the hole, |
| 691 // are also Type::Internal()). |
| 692 bool is_word64 = GetInfo(node->InputAt(0))->representation() == |
| 693 MachineRepresentation::kWord64; |
| 694 #ifdef DEBUG |
| 695 // Check that all the inputs agree on being Word64. |
| 696 for (int i = 1; i < node->op()->ValueInputCount(); i++) { |
| 697 DCHECK_EQ(is_word64, GetInfo(node->InputAt(i))->representation() == |
| 698 MachineRepresentation::kWord64); |
| 699 } |
| 700 #endif |
| 701 rep = is_word64 ? MachineRepresentation::kWord64 |
| 702 : MachineRepresentation::kTagged; |
| 682 } | 703 } |
| 683 return MachineRepresentation::kTagged; | 704 return NodeOutputInfo(rep, type); |
| 684 } | 705 } |
| 685 | 706 |
| 686 // Helper for handling selects. | 707 // Helper for handling selects. |
| 687 void VisitSelect(Node* node, Truncation truncation, | 708 void VisitSelect(Node* node, Truncation truncation, |
| 688 SimplifiedLowering* lowering) { | 709 SimplifiedLowering* lowering) { |
| 689 ProcessInput(node, 0, UseInfo::Bool()); | 710 ProcessInput(node, 0, UseInfo::Bool()); |
| 690 MachineRepresentation output = GetRepresentationForPhi(node, truncation); | |
| 691 | 711 |
| 692 Type* type = NodeProperties::GetType(node); | 712 NodeOutputInfo output = GetOutputInfoForPhi(node, truncation); |
| 693 SetOutput(node, NodeOutputInfo(output, type)); | 713 SetOutput(node, output); |
| 694 | 714 |
| 695 if (lower()) { | 715 if (lower()) { |
| 696 // Update the select operator. | 716 // Update the select operator. |
| 697 SelectParameters p = SelectParametersOf(node->op()); | 717 SelectParameters p = SelectParametersOf(node->op()); |
| 698 if (output != p.representation()) { | 718 if (output.representation() != p.representation()) { |
| 699 NodeProperties::ChangeOp(node, | 719 NodeProperties::ChangeOp(node, lowering->common()->Select( |
| 700 lowering->common()->Select(output, p.hint())); | 720 output.representation(), p.hint())); |
| 701 } | 721 } |
| 702 } | 722 } |
| 703 // Convert inputs to the output representation of this phi, pass the | 723 // Convert inputs to the output representation of this phi, pass the |
| 704 // truncation truncation along. | 724 // truncation truncation along. |
| 705 UseInfo input_use(output, truncation); | 725 UseInfo input_use(output.representation(), truncation); |
| 706 ProcessInput(node, 1, input_use); | 726 ProcessInput(node, 1, input_use); |
| 707 ProcessInput(node, 2, input_use); | 727 ProcessInput(node, 2, input_use); |
| 708 } | 728 } |
| 709 | 729 |
| 710 // Helper for handling phis. | 730 // Helper for handling phis. |
| 711 void VisitPhi(Node* node, Truncation truncation, | 731 void VisitPhi(Node* node, Truncation truncation, |
| 712 SimplifiedLowering* lowering) { | 732 SimplifiedLowering* lowering) { |
| 713 MachineRepresentation output = GetRepresentationForPhi(node, truncation); | 733 NodeOutputInfo output = GetOutputInfoForPhi(node, truncation); |
| 714 | 734 SetOutput(node, output); |
| 715 Type* type = NodeProperties::GetType(node); | |
| 716 SetOutput(node, NodeOutputInfo(output, type)); | |
| 717 | 735 |
| 718 int values = node->op()->ValueInputCount(); | 736 int values = node->op()->ValueInputCount(); |
| 719 | |
| 720 if (lower()) { | 737 if (lower()) { |
| 721 // Update the phi operator. | 738 // Update the phi operator. |
| 722 if (output != PhiRepresentationOf(node->op())) { | 739 if (output.representation() != PhiRepresentationOf(node->op())) { |
| 723 NodeProperties::ChangeOp(node, lowering->common()->Phi(output, values)); | 740 NodeProperties::ChangeOp( |
| 741 node, lowering->common()->Phi(output.representation(), values)); |
| 724 } | 742 } |
| 725 } | 743 } |
| 726 | 744 |
| 727 // Convert inputs to the output representation of this phi, pass the | 745 // Convert inputs to the output representation of this phi, pass the |
| 728 // truncation truncation along. | 746 // truncation truncation along. |
| 729 UseInfo input_use(output, truncation); | 747 UseInfo input_use(output.representation(), truncation); |
| 730 for (int i = 0; i < node->InputCount(); i++) { | 748 for (int i = 0; i < node->InputCount(); i++) { |
| 731 ProcessInput(node, i, i < values ? input_use : UseInfo::None()); | 749 ProcessInput(node, i, i < values ? input_use : UseInfo::None()); |
| 732 } | 750 } |
| 733 } | 751 } |
| 734 | 752 |
| 735 void VisitCall(Node* node, SimplifiedLowering* lowering) { | 753 void VisitCall(Node* node, SimplifiedLowering* lowering) { |
| 736 const CallDescriptor* desc = OpParameter<const CallDescriptor*>(node->op()); | 754 const CallDescriptor* desc = OpParameter<const CallDescriptor*>(node->op()); |
| 737 const MachineSignature* sig = desc->GetMachineSignature(); | 755 const MachineSignature* sig = desc->GetMachineSignature(); |
| 738 int params = static_cast<int>(sig->parameter_count()); | 756 int params = static_cast<int>(sig->parameter_count()); |
| 739 // Propagate representation information from call descriptor. | 757 // Propagate representation information from call descriptor. |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 773 for (int i = 0; i < node->InputCount(); i++) { | 791 for (int i = 0; i < node->InputCount(); i++) { |
| 774 EnqueueInput(node, i, UseInfo::Any()); | 792 EnqueueInput(node, i, UseInfo::Any()); |
| 775 } | 793 } |
| 776 } else { | 794 } else { |
| 777 Zone* zone = jsgraph_->zone(); | 795 Zone* zone = jsgraph_->zone(); |
| 778 ZoneVector<MachineType>* types = | 796 ZoneVector<MachineType>* types = |
| 779 new (zone->New(sizeof(ZoneVector<MachineType>))) | 797 new (zone->New(sizeof(ZoneVector<MachineType>))) |
| 780 ZoneVector<MachineType>(node->InputCount(), zone); | 798 ZoneVector<MachineType>(node->InputCount(), zone); |
| 781 for (int i = 0; i < node->InputCount(); i++) { | 799 for (int i = 0; i < node->InputCount(); i++) { |
| 782 NodeInfo* input_info = GetInfo(node->InputAt(i)); | 800 NodeInfo* input_info = GetInfo(node->InputAt(i)); |
| 783 (*types)[i] = | 801 MachineType machine_type( |
| 784 MachineType(input_info->representation(), | 802 input_info->representation(), |
| 785 DeoptValueSemanticOf(input_info->output_type())); | 803 DeoptValueSemanticOf(input_info->output_type())); |
| 804 DCHECK(machine_type.representation() != |
| 805 MachineRepresentation::kWord32 || |
| 806 machine_type.semantic() == MachineSemantic::kInt32 || |
| 807 machine_type.semantic() == MachineSemantic::kUint32); |
| 808 (*types)[i] = machine_type; |
| 786 } | 809 } |
| 787 NodeProperties::ChangeOp(node, | 810 NodeProperties::ChangeOp(node, |
| 788 jsgraph_->common()->TypedStateValues(types)); | 811 jsgraph_->common()->TypedStateValues(types)); |
| 789 } | 812 } |
| 790 SetOutput(node, NodeOutputInfo::AnyTagged()); | 813 SetOutput(node, NodeOutputInfo::AnyTagged()); |
| 791 } | 814 } |
| 792 | 815 |
| 793 const Operator* Int32Op(Node* node) { | 816 const Operator* Int32Op(Node* node) { |
| 794 return changer_->Int32OperatorFor(node->opcode()); | 817 return changer_->Int32OperatorFor(node->opcode()); |
| 795 } | 818 } |
| 796 | 819 |
| 797 const Operator* Uint32Op(Node* node) { | 820 const Operator* Uint32Op(Node* node) { |
| 798 return changer_->Uint32OperatorFor(node->opcode()); | 821 return changer_->Uint32OperatorFor(node->opcode()); |
| 799 } | 822 } |
| 800 | 823 |
| 801 const Operator* Float64Op(Node* node) { | 824 const Operator* Float64Op(Node* node) { |
| 802 return changer_->Float64OperatorFor(node->opcode()); | 825 return changer_->Float64OperatorFor(node->opcode()); |
| 803 } | 826 } |
| 804 | 827 |
| 805 bool CanLowerToInt32Binop(Node* node, Truncation use) { | |
| 806 return BothInputsAreSigned32(node) && | |
| 807 NodeProperties::GetType(node)->Is(Type::Signed32()); | |
| 808 } | |
| 809 | |
| 810 bool CanLowerToInt32AdditiveBinop(Node* node, Truncation use) { | |
| 811 // It is safe to lower to word32 operation if: | |
| 812 // - the inputs are safe integers (so the low bits are not discarded), and | |
| 813 // - the uses can only observe the lowest 32 bits. | |
| 814 // TODO(jarin): we could support the uint32 case here, but that would | |
| 815 // require setting kTypeUint32 as the output type. Eventually, we will want | |
| 816 // to use only the big types, then this should work automatically. | |
| 817 return BothInputsAre(node, type_cache_.kAdditiveSafeInteger) && | |
| 818 use.TruncatesToWord32(); | |
| 819 } | |
| 820 | |
| 821 bool CanLowerToInt32MultiplicativeBinop(Node* node, Truncation use) { | |
| 822 return BothInputsAreSigned32(node) && use.TruncatesToWord32() && | |
| 823 NodeProperties::GetType(node)->Is(type_cache_.kSafeInteger); | |
| 824 } | |
| 825 | |
| 826 // Dispatching routine for visiting the node {node} with the usage {use}. | 828 // Dispatching routine for visiting the node {node} with the usage {use}. |
| 827 // Depending on the operator, propagate new usage info to the inputs. | 829 // Depending on the operator, propagate new usage info to the inputs. |
| 828 void VisitNode(Node* node, Truncation truncation, | 830 void VisitNode(Node* node, Truncation truncation, |
| 829 SimplifiedLowering* lowering) { | 831 SimplifiedLowering* lowering) { |
| 830 switch (node->opcode()) { | 832 switch (node->opcode()) { |
| 831 //------------------------------------------------------------------ | 833 //------------------------------------------------------------------ |
| 832 // Common operators. | 834 // Common operators. |
| 833 //------------------------------------------------------------------ | 835 //------------------------------------------------------------------ |
| 834 case IrOpcode::kStart: | 836 case IrOpcode::kStart: |
| 835 case IrOpcode::kDead: | 837 case IrOpcode::kDead: |
| (...skipping 1083 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1919 ReplaceEffectUses(node, comparison); | 1921 ReplaceEffectUses(node, comparison); |
| 1920 node->ReplaceInput(0, comparison); | 1922 node->ReplaceInput(0, comparison); |
| 1921 node->ReplaceInput(1, jsgraph()->SmiConstant(EQUAL)); | 1923 node->ReplaceInput(1, jsgraph()->SmiConstant(EQUAL)); |
| 1922 node->TrimInputCount(2); | 1924 node->TrimInputCount(2); |
| 1923 NodeProperties::ChangeOp(node, machine()->IntLessThanOrEqual()); | 1925 NodeProperties::ChangeOp(node, machine()->IntLessThanOrEqual()); |
| 1924 } | 1926 } |
| 1925 | 1927 |
| 1926 } // namespace compiler | 1928 } // namespace compiler |
| 1927 } // namespace internal | 1929 } // namespace internal |
| 1928 } // namespace v8 | 1930 } // namespace v8 |
| OLD | NEW |