| 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/code-generator.h" | 5 #include "src/compiler/code-generator.h" |
| 6 #include "src/compiler/code-generator-impl.h" | 6 #include "src/compiler/code-generator-impl.h" |
| 7 #include "src/compiler/gap-resolver.h" | 7 #include "src/compiler/gap-resolver.h" |
| 8 #include "src/compiler/node-matchers.h" | 8 #include "src/compiler/node-matchers.h" |
| 9 #include "src/compiler/node-properties-inl.h" | 9 #include "src/compiler/node-properties-inl.h" |
| 10 #include "src/compiler/osr.h" | 10 #include "src/compiler/osr.h" |
| (...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 196 : OutOfLineRound(gen, result) {} | 196 : OutOfLineRound(gen, result) {} |
| 197 }; | 197 }; |
| 198 | 198 |
| 199 | 199 |
| 200 class OutOfLineCeil FINAL : public OutOfLineRound { | 200 class OutOfLineCeil FINAL : public OutOfLineRound { |
| 201 public: | 201 public: |
| 202 OutOfLineCeil(CodeGenerator* gen, DoubleRegister result) | 202 OutOfLineCeil(CodeGenerator* gen, DoubleRegister result) |
| 203 : OutOfLineRound(gen, result) {} | 203 : OutOfLineRound(gen, result) {} |
| 204 }; | 204 }; |
| 205 | 205 |
| 206 |
| 207 Condition FlagsConditionToConditionCmp(FlagsCondition condition) { |
| 208 switch (condition) { |
| 209 case kEqual: |
| 210 return eq; |
| 211 case kNotEqual: |
| 212 return ne; |
| 213 case kSignedLessThan: |
| 214 return lt; |
| 215 case kSignedGreaterThanOrEqual: |
| 216 return ge; |
| 217 case kSignedLessThanOrEqual: |
| 218 return le; |
| 219 case kSignedGreaterThan: |
| 220 return gt; |
| 221 case kUnsignedLessThan: |
| 222 return lo; |
| 223 case kUnsignedGreaterThanOrEqual: |
| 224 return hs; |
| 225 case kUnsignedLessThanOrEqual: |
| 226 return ls; |
| 227 case kUnsignedGreaterThan: |
| 228 return hi; |
| 229 case kUnorderedEqual: |
| 230 case kUnorderedNotEqual: |
| 231 break; |
| 232 default: |
| 233 break; |
| 234 } |
| 235 UNREACHABLE(); |
| 236 return kNoCondition; |
| 237 } |
| 238 |
| 239 |
| 240 Condition FlagsConditionToConditionTst(FlagsCondition condition) { |
| 241 switch (condition) { |
| 242 case kNotEqual: |
| 243 return ne; |
| 244 case kEqual: |
| 245 return eq; |
| 246 default: |
| 247 break; |
| 248 } |
| 249 UNREACHABLE(); |
| 250 return kNoCondition; |
| 251 } |
| 252 |
| 253 |
| 254 Condition FlagsConditionToConditionOvf(FlagsCondition condition) { |
| 255 switch (condition) { |
| 256 case kOverflow: |
| 257 return lt; |
| 258 case kNotOverflow: |
| 259 return ge; |
| 260 default: |
| 261 break; |
| 262 } |
| 263 UNREACHABLE(); |
| 264 return kNoCondition; |
| 265 } |
| 266 |
| 206 } // namespace | 267 } // namespace |
| 207 | 268 |
| 208 | 269 |
| 209 #define ASSEMBLE_CHECKED_LOAD_FLOAT(width, asm_instr) \ | 270 #define ASSEMBLE_CHECKED_LOAD_FLOAT(width, asm_instr) \ |
| 210 do { \ | 271 do { \ |
| 211 auto result = i.Output##width##Register(); \ | 272 auto result = i.Output##width##Register(); \ |
| 212 auto ool = new (zone()) OutOfLineLoad##width(this, result); \ | 273 auto ool = new (zone()) OutOfLineLoad##width(this, result); \ |
| 213 if (instr->InputAt(0)->IsRegister()) { \ | 274 if (instr->InputAt(0)->IsRegister()) { \ |
| 214 auto offset = i.InputRegister(0); \ | 275 auto offset = i.InputRegister(0); \ |
| 215 __ Branch(USE_DELAY_SLOT, ool->entry(), hs, offset, i.InputOperand(1)); \ | 276 __ Branch(USE_DELAY_SLOT, ool->entry(), hs, offset, i.InputOperand(1)); \ |
| (...skipping 423 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 639 // MIPS does not have condition code flags, so compare and branch are | 700 // MIPS does not have condition code flags, so compare and branch are |
| 640 // implemented differently than on the other arch's. The compare operations | 701 // implemented differently than on the other arch's. The compare operations |
| 641 // emit mips pseudo-instructions, which are handled here by branch | 702 // emit mips pseudo-instructions, which are handled here by branch |
| 642 // instructions that do the actual comparison. Essential that the input | 703 // instructions that do the actual comparison. Essential that the input |
| 643 // registers to compare pseudo-op are not modified before this branch op, as | 704 // registers to compare pseudo-op are not modified before this branch op, as |
| 644 // they are tested here. | 705 // they are tested here. |
| 645 // TODO(plind): Add CHECK() to ensure that test/cmp and this branch were | 706 // TODO(plind): Add CHECK() to ensure that test/cmp and this branch were |
| 646 // not separated by other instructions. | 707 // not separated by other instructions. |
| 647 | 708 |
| 648 if (instr->arch_opcode() == kMipsTst) { | 709 if (instr->arch_opcode() == kMipsTst) { |
| 649 switch (branch->condition) { | 710 cc = FlagsConditionToConditionTst(branch->condition); |
| 650 case kNotEqual: | |
| 651 cc = ne; | |
| 652 break; | |
| 653 case kEqual: | |
| 654 cc = eq; | |
| 655 break; | |
| 656 default: | |
| 657 UNSUPPORTED_COND(kMipsTst, branch->condition); | |
| 658 break; | |
| 659 } | |
| 660 __ And(at, i.InputRegister(0), i.InputOperand(1)); | 711 __ And(at, i.InputRegister(0), i.InputOperand(1)); |
| 661 __ Branch(tlabel, cc, at, Operand(zero_reg)); | 712 __ Branch(tlabel, cc, at, Operand(zero_reg)); |
| 662 | 713 |
| 663 } else if (instr->arch_opcode() == kMipsAddOvf || | 714 } else if (instr->arch_opcode() == kMipsAddOvf || |
| 664 instr->arch_opcode() == kMipsSubOvf) { | 715 instr->arch_opcode() == kMipsSubOvf) { |
| 665 // kMipsAddOvf, SubOvf emit negative result to 'kCompareReg' on overflow. | 716 // kMipsAddOvf, SubOvf emit negative result to 'kCompareReg' on overflow. |
| 666 switch (branch->condition) { | 717 cc = FlagsConditionToConditionOvf(branch->condition); |
| 667 case kOverflow: | |
| 668 cc = lt; | |
| 669 break; | |
| 670 case kNotOverflow: | |
| 671 cc = ge; | |
| 672 break; | |
| 673 default: | |
| 674 UNSUPPORTED_COND(kMipsAddOvf, branch->condition); | |
| 675 break; | |
| 676 } | |
| 677 __ Branch(tlabel, cc, kCompareReg, Operand(zero_reg)); | 718 __ Branch(tlabel, cc, kCompareReg, Operand(zero_reg)); |
| 678 | 719 |
| 679 } else if (instr->arch_opcode() == kMipsCmp) { | 720 } else if (instr->arch_opcode() == kMipsCmp) { |
| 680 switch (branch->condition) { | 721 cc = FlagsConditionToConditionCmp(branch->condition); |
| 681 case kEqual: | |
| 682 cc = eq; | |
| 683 break; | |
| 684 case kNotEqual: | |
| 685 cc = ne; | |
| 686 break; | |
| 687 case kSignedLessThan: | |
| 688 cc = lt; | |
| 689 break; | |
| 690 case kSignedGreaterThanOrEqual: | |
| 691 cc = ge; | |
| 692 break; | |
| 693 case kSignedLessThanOrEqual: | |
| 694 cc = le; | |
| 695 break; | |
| 696 case kSignedGreaterThan: | |
| 697 cc = gt; | |
| 698 break; | |
| 699 case kUnsignedLessThan: | |
| 700 cc = lo; | |
| 701 break; | |
| 702 case kUnsignedGreaterThanOrEqual: | |
| 703 cc = hs; | |
| 704 break; | |
| 705 case kUnsignedLessThanOrEqual: | |
| 706 cc = ls; | |
| 707 break; | |
| 708 case kUnsignedGreaterThan: | |
| 709 cc = hi; | |
| 710 break; | |
| 711 default: | |
| 712 UNSUPPORTED_COND(kMipsCmp, branch->condition); | |
| 713 break; | |
| 714 } | |
| 715 __ Branch(tlabel, cc, i.InputRegister(0), i.InputOperand(1)); | 722 __ Branch(tlabel, cc, i.InputRegister(0), i.InputOperand(1)); |
| 716 | 723 |
| 717 if (!branch->fallthru) __ Branch(flabel); // no fallthru to flabel. | 724 if (!branch->fallthru) __ Branch(flabel); // no fallthru to flabel. |
| 718 | 725 |
| 719 } else if (instr->arch_opcode() == kMipsCmpD) { | 726 } else if (instr->arch_opcode() == kMipsCmpD) { |
| 720 // TODO(dusmil) optimize unordered checks to use fewer instructions | 727 // TODO(dusmil) optimize unordered checks to use fewer instructions |
| 721 // even if we have to unfold BranchF macro. | 728 // even if we have to unfold BranchF macro. |
| 722 Label* nan = flabel; | 729 Label* nan = flabel; |
| 723 switch (branch->condition) { | 730 switch (branch->condition) { |
| 724 case kUnorderedEqual: | 731 case kEqual: |
| 725 cc = eq; | 732 cc = eq; |
| 726 break; | 733 break; |
| 727 case kUnorderedNotEqual: | 734 case kNotEqual: |
| 728 cc = ne; | 735 cc = ne; |
| 729 nan = tlabel; | 736 nan = tlabel; |
| 730 break; | 737 break; |
| 731 case kUnorderedLessThan: | 738 case kUnsignedLessThan: |
| 732 cc = lt; | 739 cc = lt; |
| 733 break; | 740 break; |
| 734 case kUnorderedGreaterThanOrEqual: | 741 case kUnsignedGreaterThanOrEqual: |
| 735 cc = ge; | 742 cc = ge; |
| 736 nan = tlabel; | 743 nan = tlabel; |
| 737 break; | 744 break; |
| 738 case kUnorderedLessThanOrEqual: | 745 case kUnsignedLessThanOrEqual: |
| 739 cc = le; | 746 cc = le; |
| 740 break; | 747 break; |
| 741 case kUnorderedGreaterThan: | 748 case kUnsignedGreaterThan: |
| 742 cc = gt; | 749 cc = gt; |
| 743 nan = tlabel; | 750 nan = tlabel; |
| 744 break; | 751 break; |
| 745 default: | 752 default: |
| 746 UNSUPPORTED_COND(kMipsCmpD, branch->condition); | 753 UNSUPPORTED_COND(kMipsCmpD, branch->condition); |
| 747 break; | 754 break; |
| 748 } | 755 } |
| 749 __ BranchF(tlabel, nan, cc, i.InputDoubleRegister(0), | 756 __ BranchF(tlabel, nan, cc, i.InputDoubleRegister(0), |
| 750 i.InputDoubleRegister(1)); | 757 i.InputDoubleRegister(1)); |
| 751 | 758 |
| (...skipping 29 matching lines...) Expand all Loading... |
| 781 // implemented differently than on the other arch's. The compare operations | 788 // implemented differently than on the other arch's. The compare operations |
| 782 // emit mips psuedo-instructions, which are checked and handled here. | 789 // emit mips psuedo-instructions, which are checked and handled here. |
| 783 | 790 |
| 784 // For materializations, we use delay slot to set the result true, and | 791 // For materializations, we use delay slot to set the result true, and |
| 785 // in the false case, where we fall thru the branch, we reset the result | 792 // in the false case, where we fall thru the branch, we reset the result |
| 786 // false. | 793 // false. |
| 787 | 794 |
| 788 // TODO(plind): Add CHECK() to ensure that test/cmp and this branch were | 795 // TODO(plind): Add CHECK() to ensure that test/cmp and this branch were |
| 789 // not separated by other instructions. | 796 // not separated by other instructions. |
| 790 if (instr->arch_opcode() == kMipsTst) { | 797 if (instr->arch_opcode() == kMipsTst) { |
| 791 switch (condition) { | 798 cc = FlagsConditionToConditionTst(condition); |
| 792 case kNotEqual: | |
| 793 cc = ne; | |
| 794 break; | |
| 795 case kEqual: | |
| 796 cc = eq; | |
| 797 break; | |
| 798 default: | |
| 799 UNSUPPORTED_COND(kMipsTst, condition); | |
| 800 break; | |
| 801 } | |
| 802 __ And(at, i.InputRegister(0), i.InputOperand(1)); | 799 __ And(at, i.InputRegister(0), i.InputOperand(1)); |
| 803 __ Branch(USE_DELAY_SLOT, &done, cc, at, Operand(zero_reg)); | 800 __ Branch(USE_DELAY_SLOT, &done, cc, at, Operand(zero_reg)); |
| 804 __ li(result, Operand(1)); // In delay slot. | 801 __ li(result, Operand(1)); // In delay slot. |
| 805 | 802 |
| 806 } else if (instr->arch_opcode() == kMipsAddOvf || | 803 } else if (instr->arch_opcode() == kMipsAddOvf || |
| 807 instr->arch_opcode() == kMipsSubOvf) { | 804 instr->arch_opcode() == kMipsSubOvf) { |
| 808 // kMipsAddOvf, SubOvf emits negative result to 'kCompareReg' on overflow. | 805 // kMipsAddOvf, SubOvf emits negative result to 'kCompareReg' on overflow. |
| 809 switch (condition) { | 806 cc = FlagsConditionToConditionOvf(condition); |
| 810 case kOverflow: | |
| 811 cc = lt; | |
| 812 break; | |
| 813 case kNotOverflow: | |
| 814 cc = ge; | |
| 815 break; | |
| 816 default: | |
| 817 UNSUPPORTED_COND(kMipsAddOvf, condition); | |
| 818 break; | |
| 819 } | |
| 820 __ Branch(USE_DELAY_SLOT, &done, cc, kCompareReg, Operand(zero_reg)); | 807 __ Branch(USE_DELAY_SLOT, &done, cc, kCompareReg, Operand(zero_reg)); |
| 821 __ li(result, Operand(1)); // In delay slot. | 808 __ li(result, Operand(1)); // In delay slot. |
| 822 | 809 |
| 823 | 810 |
| 824 } else if (instr->arch_opcode() == kMipsCmp) { | 811 } else if (instr->arch_opcode() == kMipsCmp) { |
| 825 Register left = i.InputRegister(0); | 812 Register left = i.InputRegister(0); |
| 826 Operand right = i.InputOperand(1); | 813 Operand right = i.InputOperand(1); |
| 827 switch (condition) { | 814 cc = FlagsConditionToConditionCmp(condition); |
| 828 case kEqual: | |
| 829 cc = eq; | |
| 830 break; | |
| 831 case kNotEqual: | |
| 832 cc = ne; | |
| 833 break; | |
| 834 case kSignedLessThan: | |
| 835 cc = lt; | |
| 836 break; | |
| 837 case kSignedGreaterThanOrEqual: | |
| 838 cc = ge; | |
| 839 break; | |
| 840 case kSignedLessThanOrEqual: | |
| 841 cc = le; | |
| 842 break; | |
| 843 case kSignedGreaterThan: | |
| 844 cc = gt; | |
| 845 break; | |
| 846 case kUnsignedLessThan: | |
| 847 cc = lo; | |
| 848 break; | |
| 849 case kUnsignedGreaterThanOrEqual: | |
| 850 cc = hs; | |
| 851 break; | |
| 852 case kUnsignedLessThanOrEqual: | |
| 853 cc = ls; | |
| 854 break; | |
| 855 case kUnsignedGreaterThan: | |
| 856 cc = hi; | |
| 857 break; | |
| 858 default: | |
| 859 UNSUPPORTED_COND(kMipsCmp, condition); | |
| 860 break; | |
| 861 } | |
| 862 __ Branch(USE_DELAY_SLOT, &done, cc, left, right); | 815 __ Branch(USE_DELAY_SLOT, &done, cc, left, right); |
| 863 __ li(result, Operand(1)); // In delay slot. | 816 __ li(result, Operand(1)); // In delay slot. |
| 864 | 817 |
| 865 } else if (instr->arch_opcode() == kMipsCmpD) { | 818 } else if (instr->arch_opcode() == kMipsCmpD) { |
| 866 FPURegister left = i.InputDoubleRegister(0); | 819 FPURegister left = i.InputDoubleRegister(0); |
| 867 FPURegister right = i.InputDoubleRegister(1); | 820 FPURegister right = i.InputDoubleRegister(1); |
| 868 // TODO(plind): Provide NaN-testing macro-asm function without need for | 821 // TODO(plind): Provide NaN-testing macro-asm function without need for |
| 869 // BranchF. | 822 // BranchF. |
| 870 FPURegister dummy1 = f0; | 823 FPURegister dummy1 = f0; |
| 871 FPURegister dummy2 = f2; | 824 FPURegister dummy2 = f2; |
| 872 switch (condition) { | 825 switch (condition) { |
| 873 case kUnorderedEqual: | 826 case kEqual: |
| 874 // TODO(plind): improve the NaN testing throughout this function. | 827 // TODO(plind): improve the NaN testing throughout this function. |
| 875 __ BranchF(NULL, &false_value, kNoCondition, dummy1, dummy2); | 828 __ BranchF(NULL, &false_value, kNoCondition, dummy1, dummy2); |
| 876 cc = eq; | 829 cc = eq; |
| 877 break; | 830 break; |
| 878 case kUnorderedNotEqual: | 831 case kNotEqual: |
| 879 __ BranchF(USE_DELAY_SLOT, NULL, &done, kNoCondition, dummy1, dummy2); | 832 __ BranchF(USE_DELAY_SLOT, NULL, &done, kNoCondition, dummy1, dummy2); |
| 880 __ li(result, Operand(1)); // In delay slot - returns 1 on NaN. | 833 __ li(result, Operand(1)); // In delay slot - returns 1 on NaN. |
| 881 cc = ne; | 834 cc = ne; |
| 882 break; | 835 break; |
| 883 case kUnorderedLessThan: | 836 case kUnsignedLessThan: |
| 884 __ BranchF(NULL, &false_value, kNoCondition, dummy1, dummy2); | 837 __ BranchF(NULL, &false_value, kNoCondition, dummy1, dummy2); |
| 885 cc = lt; | 838 cc = lt; |
| 886 break; | 839 break; |
| 887 case kUnorderedGreaterThanOrEqual: | 840 case kUnsignedGreaterThanOrEqual: |
| 888 __ BranchF(USE_DELAY_SLOT, NULL, &done, kNoCondition, dummy1, dummy2); | 841 __ BranchF(USE_DELAY_SLOT, NULL, &done, kNoCondition, dummy1, dummy2); |
| 889 __ li(result, Operand(1)); // In delay slot - returns 1 on NaN. | 842 __ li(result, Operand(1)); // In delay slot - returns 1 on NaN. |
| 890 cc = ge; | 843 cc = ge; |
| 891 break; | 844 break; |
| 892 case kUnorderedLessThanOrEqual: | 845 case kUnsignedLessThanOrEqual: |
| 893 __ BranchF(NULL, &false_value, kNoCondition, dummy1, dummy2); | 846 __ BranchF(NULL, &false_value, kNoCondition, dummy1, dummy2); |
| 894 cc = le; | 847 cc = le; |
| 895 break; | 848 break; |
| 896 case kUnorderedGreaterThan: | 849 case kUnsignedGreaterThan: |
| 897 __ BranchF(USE_DELAY_SLOT, NULL, &done, kNoCondition, dummy1, dummy2); | 850 __ BranchF(USE_DELAY_SLOT, NULL, &done, kNoCondition, dummy1, dummy2); |
| 898 __ li(result, Operand(1)); // In delay slot - returns 1 on NaN. | 851 __ li(result, Operand(1)); // In delay slot - returns 1 on NaN. |
| 899 cc = gt; | 852 cc = gt; |
| 900 break; | 853 break; |
| 901 default: | 854 default: |
| 902 UNSUPPORTED_COND(kMipsCmp, condition); | 855 UNSUPPORTED_COND(kMipsCmp, condition); |
| 903 break; | 856 break; |
| 904 } | 857 } |
| 905 __ BranchF(USE_DELAY_SLOT, &done, NULL, cc, left, right); | 858 __ BranchF(USE_DELAY_SLOT, &done, NULL, cc, left, right); |
| 906 __ li(result, Operand(1)); // In delay slot - branch taken returns 1. | 859 __ li(result, Operand(1)); // In delay slot - branch taken returns 1. |
| (...skipping 287 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1194 } | 1147 } |
| 1195 } | 1148 } |
| 1196 MarkLazyDeoptSite(); | 1149 MarkLazyDeoptSite(); |
| 1197 } | 1150 } |
| 1198 | 1151 |
| 1199 #undef __ | 1152 #undef __ |
| 1200 | 1153 |
| 1201 } // namespace compiler | 1154 } // namespace compiler |
| 1202 } // namespace internal | 1155 } // namespace internal |
| 1203 } // namespace v8 | 1156 } // namespace v8 |
| OLD | NEW |