| 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/instruction-selector-impl.h" | 5 #include "src/compiler/instruction-selector-impl.h" |
| 6 #include "src/compiler/node-matchers.h" | 6 #include "src/compiler/node-matchers.h" |
| 7 #include "src/compiler-intrinsics.h" | 7 #include "src/compiler-intrinsics.h" |
| 8 | 8 |
| 9 namespace v8 { | 9 namespace v8 { |
| 10 namespace internal { | 10 namespace internal { |
| (...skipping 286 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 297 } | 297 } |
| 298 | 298 |
| 299 | 299 |
| 300 static void VisitBinop(InstructionSelector* selector, Node* node, | 300 static void VisitBinop(InstructionSelector* selector, Node* node, |
| 301 InstructionCode opcode, InstructionCode reverse_opcode) { | 301 InstructionCode opcode, InstructionCode reverse_opcode) { |
| 302 FlagsContinuation cont; | 302 FlagsContinuation cont; |
| 303 VisitBinop(selector, node, opcode, reverse_opcode, &cont); | 303 VisitBinop(selector, node, opcode, reverse_opcode, &cont); |
| 304 } | 304 } |
| 305 | 305 |
| 306 | 306 |
| 307 static void VisitBinop(InstructionSelector* selector, Node* node, |
| 308 InstructionCode opcode, InstructionCode reverse_opcode, |
| 309 FlagsCondition overflow_condition) { |
| 310 if (Node* overflow = node->FindProjection(1)) { |
| 311 FlagsContinuation cont(overflow_condition, overflow); |
| 312 return VisitBinop(selector, node, opcode, reverse_opcode, &cont); |
| 313 } |
| 314 FlagsContinuation cont; |
| 315 return VisitBinop(selector, node, opcode, reverse_opcode, &cont); |
| 316 } |
| 317 |
| 318 |
| 307 void InstructionSelector::VisitLoad(Node* node) { | 319 void InstructionSelector::VisitLoad(Node* node) { |
| 308 MachineRepresentation rep = OpParameter<MachineRepresentation>(node); | 320 MachineRepresentation rep = OpParameter<MachineRepresentation>(node); |
| 309 ArmOperandGenerator g(this); | 321 ArmOperandGenerator g(this); |
| 310 Node* base = node->InputAt(0); | 322 Node* base = node->InputAt(0); |
| 311 Node* index = node->InputAt(1); | 323 Node* index = node->InputAt(1); |
| 312 | 324 |
| 313 InstructionOperand* result = rep == kMachineFloat64 | 325 InstructionOperand* result = rep == kMachineFloat64 |
| 314 ? g.DefineAsDoubleRegister(node) | 326 ? g.DefineAsDoubleRegister(node) |
| 315 : g.DefineAsRegister(node); | 327 : g.DefineAsRegister(node); |
| 316 | 328 |
| (...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 563 if (m.right().IsInt32Mul() && CanCover(node, m.right().node())) { | 575 if (m.right().IsInt32Mul() && CanCover(node, m.right().node())) { |
| 564 Int32BinopMatcher mright(m.right().node()); | 576 Int32BinopMatcher mright(m.right().node()); |
| 565 Emit(kArmMla, g.DefineAsRegister(node), g.UseRegister(mright.left().node()), | 577 Emit(kArmMla, g.DefineAsRegister(node), g.UseRegister(mright.left().node()), |
| 566 g.UseRegister(mright.right().node()), g.UseRegister(m.left().node())); | 578 g.UseRegister(mright.right().node()), g.UseRegister(m.left().node())); |
| 567 return; | 579 return; |
| 568 } | 580 } |
| 569 VisitBinop(this, node, kArmAdd, kArmAdd); | 581 VisitBinop(this, node, kArmAdd, kArmAdd); |
| 570 } | 582 } |
| 571 | 583 |
| 572 | 584 |
| 585 void InstructionSelector::VisitInt32AddWithOverflow(Node* node) { |
| 586 VisitBinop(this, node, kArmAdd, kArmAdd, kOverflow); |
| 587 } |
| 588 |
| 589 |
| 590 void InstructionSelector::VisitUint32AddWithOverflow(Node* node) { |
| 591 VisitBinop(this, node, kArmAdd, kArmAdd, kUnsignedGreaterThanOrEqual); |
| 592 } |
| 593 |
| 594 |
| 573 void InstructionSelector::VisitInt32Sub(Node* node) { | 595 void InstructionSelector::VisitInt32Sub(Node* node) { |
| 574 ArmOperandGenerator g(this); | 596 ArmOperandGenerator g(this); |
| 575 Int32BinopMatcher m(node); | 597 Int32BinopMatcher m(node); |
| 576 if (IsSupported(MLS) && m.right().IsInt32Mul() && | 598 if (IsSupported(MLS) && m.right().IsInt32Mul() && |
| 577 CanCover(node, m.right().node())) { | 599 CanCover(node, m.right().node())) { |
| 578 Int32BinopMatcher mright(m.right().node()); | 600 Int32BinopMatcher mright(m.right().node()); |
| 579 Emit(kArmMls, g.DefineAsRegister(node), g.UseRegister(mright.left().node()), | 601 Emit(kArmMls, g.DefineAsRegister(node), g.UseRegister(mright.left().node()), |
| 580 g.UseRegister(mright.right().node()), g.UseRegister(m.left().node())); | 602 g.UseRegister(mright.right().node()), g.UseRegister(m.left().node())); |
| 581 return; | 603 return; |
| 582 } | 604 } |
| 583 VisitBinop(this, node, kArmSub, kArmRsb); | 605 VisitBinop(this, node, kArmSub, kArmRsb); |
| 584 } | 606 } |
| 585 | 607 |
| 586 | 608 |
| 609 void InstructionSelector::VisitInt32SubWithOverflow(Node* node) { |
| 610 VisitBinop(this, node, kArmSub, kArmRsb, kOverflow); |
| 611 } |
| 612 |
| 613 |
| 614 void InstructionSelector::VisitUint32SubWithOverflow(Node* node) { |
| 615 VisitBinop(this, node, kArmSub, kArmRsb, kUnsignedLessThan); |
| 616 } |
| 617 |
| 618 |
| 587 void InstructionSelector::VisitInt32Mul(Node* node) { | 619 void InstructionSelector::VisitInt32Mul(Node* node) { |
| 588 ArmOperandGenerator g(this); | 620 ArmOperandGenerator g(this); |
| 589 Int32BinopMatcher m(node); | 621 Int32BinopMatcher m(node); |
| 590 if (m.right().HasValue() && m.right().Value() > 0) { | 622 if (m.right().HasValue() && m.right().Value() > 0) { |
| 591 int32_t value = m.right().Value(); | 623 int32_t value = m.right().Value(); |
| 592 if (IsPowerOf2(value - 1)) { | 624 if (IsPowerOf2(value - 1)) { |
| 593 Emit(kArmAdd | AddressingModeField::encode(kMode_Operand2_R_LSL_I), | 625 Emit(kArmAdd | AddressingModeField::encode(kMode_Operand2_R_LSL_I), |
| 594 g.DefineAsRegister(node), g.UseRegister(m.left().node()), | 626 g.DefineAsRegister(node), g.UseRegister(m.left().node()), |
| 595 g.UseRegister(m.left().node()), | 627 g.UseRegister(m.left().node()), |
| 596 g.TempImmediate(WhichPowerOf2(value - 1))); | 628 g.TempImmediate(WhichPowerOf2(value - 1))); |
| (...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 764 | 796 |
| 765 | 797 |
| 766 void InstructionSelector::VisitFloat64Mod(Node* node) { | 798 void InstructionSelector::VisitFloat64Mod(Node* node) { |
| 767 ArmOperandGenerator g(this); | 799 ArmOperandGenerator g(this); |
| 768 Emit(kArmVmodF64, g.DefineAsFixedDouble(node, d0), | 800 Emit(kArmVmodF64, g.DefineAsFixedDouble(node, d0), |
| 769 g.UseFixedDouble(node->InputAt(0), d0), | 801 g.UseFixedDouble(node->InputAt(0), d0), |
| 770 g.UseFixedDouble(node->InputAt(1), d1))->MarkAsCall(); | 802 g.UseFixedDouble(node->InputAt(1), d1))->MarkAsCall(); |
| 771 } | 803 } |
| 772 | 804 |
| 773 | 805 |
| 806 void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch, |
| 807 BasicBlock* fbranch) { |
| 808 OperandGenerator g(this); |
| 809 Node* user = branch; |
| 810 Node* value = branch->InputAt(0); |
| 811 |
| 812 FlagsContinuation cont(kNotEqual, tbranch, fbranch); |
| 813 |
| 814 // If we can fall through to the true block, invert the branch. |
| 815 if (IsNextInAssemblyOrder(tbranch)) { |
| 816 cont.Negate(); |
| 817 cont.SwapBlocks(); |
| 818 } |
| 819 |
| 820 // Try to combine with comparisons against 0 by simply inverting the branch. |
| 821 while (CanCover(user, value)) { |
| 822 if (value->opcode() == IrOpcode::kWord32Equal) { |
| 823 Int32BinopMatcher m(value); |
| 824 if (m.right().Is(0)) { |
| 825 user = value; |
| 826 value = m.left().node(); |
| 827 cont.Negate(); |
| 828 } else { |
| 829 break; |
| 830 } |
| 831 } else { |
| 832 break; |
| 833 } |
| 834 } |
| 835 |
| 836 // Try to combine the branch with a comparison. |
| 837 if (CanCover(user, value)) { |
| 838 switch (value->opcode()) { |
| 839 case IrOpcode::kWord32Equal: |
| 840 cont.OverwriteAndNegateIfEqual(kEqual); |
| 841 return VisitWord32Compare(value, &cont); |
| 842 case IrOpcode::kInt32LessThan: |
| 843 cont.OverwriteAndNegateIfEqual(kSignedLessThan); |
| 844 return VisitWord32Compare(value, &cont); |
| 845 case IrOpcode::kInt32LessThanOrEqual: |
| 846 cont.OverwriteAndNegateIfEqual(kSignedLessThanOrEqual); |
| 847 return VisitWord32Compare(value, &cont); |
| 848 case IrOpcode::kUint32LessThan: |
| 849 cont.OverwriteAndNegateIfEqual(kUnsignedLessThan); |
| 850 return VisitWord32Compare(value, &cont); |
| 851 case IrOpcode::kUint32LessThanOrEqual: |
| 852 cont.OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual); |
| 853 return VisitWord32Compare(value, &cont); |
| 854 case IrOpcode::kFloat64Equal: |
| 855 cont.OverwriteAndNegateIfEqual(kUnorderedEqual); |
| 856 return VisitFloat64Compare(value, &cont); |
| 857 case IrOpcode::kFloat64LessThan: |
| 858 cont.OverwriteAndNegateIfEqual(kUnorderedLessThan); |
| 859 return VisitFloat64Compare(value, &cont); |
| 860 case IrOpcode::kFloat64LessThanOrEqual: |
| 861 cont.OverwriteAndNegateIfEqual(kUnorderedLessThanOrEqual); |
| 862 return VisitFloat64Compare(value, &cont); |
| 863 case IrOpcode::kProjection: |
| 864 // Check if this is the overflow output projection of an |
| 865 // <Operation>WithOverflow node. |
| 866 if (OpParameter<int32_t>(value) == 1) { |
| 867 // We cannot combine the <Operation>WithOverflow with this branch |
| 868 // unless the 0th projection (the use of the actual value of the |
| 869 // <Operation> is either NULL, which means there's no use of the |
| 870 // actual value, or was already defined, which means it is scheduled |
| 871 // *AFTER* this branch). |
| 872 Node* node = value->InputAt(0); |
| 873 Node* result = node->FindProjection(0); |
| 874 if (result == NULL || IsDefined(result)) { |
| 875 switch (node->opcode()) { |
| 876 case IrOpcode::kInt32AddWithOverflow: |
| 877 cont.OverwriteAndNegateIfEqual(kOverflow); |
| 878 return VisitBinop(this, node, kArmAdd, kArmAdd, &cont); |
| 879 case IrOpcode::kUint32AddWithOverflow: |
| 880 cont.OverwriteAndNegateIfEqual(kUnsignedGreaterThanOrEqual); |
| 881 return VisitBinop(this, node, kArmAdd, kArmAdd, &cont); |
| 882 case IrOpcode::kInt32SubWithOverflow: |
| 883 cont.OverwriteAndNegateIfEqual(kOverflow); |
| 884 return VisitBinop(this, node, kArmSub, kArmRsb, &cont); |
| 885 case IrOpcode::kUint32SubWithOverflow: |
| 886 cont.OverwriteAndNegateIfEqual(kUnsignedLessThan); |
| 887 return VisitBinop(this, node, kArmSub, kArmRsb, &cont); |
| 888 default: |
| 889 break; |
| 890 } |
| 891 } |
| 892 } |
| 893 break; |
| 894 default: |
| 895 break; |
| 896 } |
| 897 } |
| 898 |
| 899 // Branch could not be combined with a compare, emit compare against 0. |
| 900 VisitWord32Test(value, &cont); |
| 901 } |
| 902 |
| 903 |
| 774 void InstructionSelector::VisitCall(Node* call, BasicBlock* continuation, | 904 void InstructionSelector::VisitCall(Node* call, BasicBlock* continuation, |
| 775 BasicBlock* deoptimization) { | 905 BasicBlock* deoptimization) { |
| 776 ArmOperandGenerator g(this); | 906 ArmOperandGenerator g(this); |
| 777 CallDescriptor* descriptor = OpParameter<CallDescriptor*>(call); | 907 CallDescriptor* descriptor = OpParameter<CallDescriptor*>(call); |
| 778 CallBuffer buffer(zone(), descriptor); // TODO(turbofan): temp zone here? | 908 CallBuffer buffer(zone(), descriptor); // TODO(turbofan): temp zone here? |
| 779 | 909 |
| 780 // Compute InstructionOperands for inputs and outputs. | 910 // Compute InstructionOperands for inputs and outputs. |
| 781 // TODO(turbofan): on ARM64 it's probably better to use the code object in a | 911 // TODO(turbofan): on ARM64 it's probably better to use the code object in a |
| 782 // register if there are multiple uses of it. Improve constant pool and the | 912 // register if there are multiple uses of it. Improve constant pool and the |
| 783 // heuristics in the register allocator for where to emit constants. | 913 // heuristics in the register allocator for where to emit constants. |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 823 | 953 |
| 824 // Caller clean up of stack for C-style calls. | 954 // Caller clean up of stack for C-style calls. |
| 825 if (descriptor->kind() == CallDescriptor::kCallAddress && | 955 if (descriptor->kind() == CallDescriptor::kCallAddress && |
| 826 buffer.pushed_count > 0) { | 956 buffer.pushed_count > 0) { |
| 827 DCHECK(deoptimization == NULL && continuation == NULL); | 957 DCHECK(deoptimization == NULL && continuation == NULL); |
| 828 Emit(kArmDrop | MiscField::encode(buffer.pushed_count), NULL); | 958 Emit(kArmDrop | MiscField::encode(buffer.pushed_count), NULL); |
| 829 } | 959 } |
| 830 } | 960 } |
| 831 | 961 |
| 832 | 962 |
| 833 void InstructionSelector::VisitInt32AddWithOverflow(Node* node, | |
| 834 FlagsContinuation* cont) { | |
| 835 VisitBinop(this, node, kArmAdd, kArmAdd, cont); | |
| 836 } | |
| 837 | |
| 838 | |
| 839 void InstructionSelector::VisitInt32SubWithOverflow(Node* node, | |
| 840 FlagsContinuation* cont) { | |
| 841 VisitBinop(this, node, kArmSub, kArmRsb, cont); | |
| 842 } | |
| 843 | |
| 844 | |
| 845 // Shared routine for multiple compare operations. | 963 // Shared routine for multiple compare operations. |
| 846 static void VisitWordCompare(InstructionSelector* selector, Node* node, | 964 static void VisitWordCompare(InstructionSelector* selector, Node* node, |
| 847 InstructionCode opcode, FlagsContinuation* cont, | 965 InstructionCode opcode, FlagsContinuation* cont, |
| 848 bool commutative) { | 966 bool commutative) { |
| 849 ArmOperandGenerator g(selector); | 967 ArmOperandGenerator g(selector); |
| 850 Int32BinopMatcher m(node); | 968 Int32BinopMatcher m(node); |
| 851 InstructionOperand* inputs[5]; | 969 InstructionOperand* inputs[5]; |
| 852 size_t input_count = 0; | 970 size_t input_count = 0; |
| 853 InstructionOperand* outputs[1]; | 971 InstructionOperand* outputs[1]; |
| 854 size_t output_count = 0; | 972 size_t output_count = 0; |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 934 DCHECK(cont->IsSet()); | 1052 DCHECK(cont->IsSet()); |
| 935 Emit(cont->Encode(kArmVcmpF64), g.DefineAsRegister(cont->result()), | 1053 Emit(cont->Encode(kArmVcmpF64), g.DefineAsRegister(cont->result()), |
| 936 g.UseDoubleRegister(m.left().node()), | 1054 g.UseDoubleRegister(m.left().node()), |
| 937 g.UseDoubleRegister(m.right().node())); | 1055 g.UseDoubleRegister(m.right().node())); |
| 938 } | 1056 } |
| 939 } | 1057 } |
| 940 | 1058 |
| 941 } // namespace compiler | 1059 } // namespace compiler |
| 942 } // namespace internal | 1060 } // namespace internal |
| 943 } // namespace v8 | 1061 } // namespace v8 |
| OLD | NEW |