OLD | NEW |
---|---|
1 // Copyright 2006-2009 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2009 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
43 | 43 |
44 static void EmitIdenticalObjectComparison(MacroAssembler* masm, | 44 static void EmitIdenticalObjectComparison(MacroAssembler* masm, |
45 Label* slow, | 45 Label* slow, |
46 Condition cc); | 46 Condition cc); |
47 static void EmitSmiNonsmiComparison(MacroAssembler* masm, | 47 static void EmitSmiNonsmiComparison(MacroAssembler* masm, |
48 Label* rhs_not_nan, | 48 Label* rhs_not_nan, |
49 Label* slow, | 49 Label* slow, |
50 bool strict); | 50 bool strict); |
51 static void EmitTwoNonNanDoubleComparison(MacroAssembler* masm, Condition cc); | 51 static void EmitTwoNonNanDoubleComparison(MacroAssembler* masm, Condition cc); |
52 static void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm); | 52 static void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm); |
53 static void MultiplyByKnownInt(MacroAssembler* masm, | |
54 Register source, | |
55 Register destination, | |
56 int known_int); | |
57 static bool IsEasyToMultiplyBy(int x); | |
53 | 58 |
54 | 59 |
55 | 60 |
56 // ------------------------------------------------------------------------- | 61 // ------------------------------------------------------------------------- |
57 // Platform-specific DeferredCode functions. | 62 // Platform-specific DeferredCode functions. |
58 | 63 |
59 void DeferredCode::SaveRegisters() { | 64 void DeferredCode::SaveRegisters() { |
60 for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) { | 65 for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) { |
61 int action = registers_[i]; | 66 int action = registers_[i]; |
62 if (action == kPush) { | 67 if (action == kPush) { |
(...skipping 625 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
688 // Convert the result (r0) to a condition code. | 693 // Convert the result (r0) to a condition code. |
689 __ cmp(r0, Operand(Factory::false_value())); | 694 __ cmp(r0, Operand(Factory::false_value())); |
690 | 695 |
691 cc_reg_ = ne; | 696 cc_reg_ = ne; |
692 } | 697 } |
693 | 698 |
694 | 699 |
695 class GenericBinaryOpStub : public CodeStub { | 700 class GenericBinaryOpStub : public CodeStub { |
696 public: | 701 public: |
697 GenericBinaryOpStub(Token::Value op, | 702 GenericBinaryOpStub(Token::Value op, |
698 OverwriteMode mode) | 703 OverwriteMode mode, |
699 : op_(op), mode_(mode) { } | 704 int known_rhs = CodeGenerator::kUnknownIntValue) |
705 : op_(op), | |
706 mode_(mode), | |
707 known_rhs_(known_rhs), | |
708 specialized_on_rhs_(RhsIsOneWeWantToOptimizeFor(op, known_rhs)) { } | |
700 | 709 |
701 private: | 710 private: |
702 Token::Value op_; | 711 Token::Value op_; |
703 OverwriteMode mode_; | 712 OverwriteMode mode_; |
713 int known_rhs_; | |
714 bool specialized_on_rhs_; | |
715 | |
716 static const int kMaxKnownRhs = 0x40000000; | |
704 | 717 |
705 // Minor key encoding in 16 bits. | 718 // Minor key encoding in 16 bits. |
706 class ModeBits: public BitField<OverwriteMode, 0, 2> {}; | 719 class ModeBits: public BitField<OverwriteMode, 0, 2> {}; |
707 class OpBits: public BitField<Token::Value, 2, 14> {}; | 720 class OpBits: public BitField<Token::Value, 2, 6> {}; |
721 class KnownIntBits: public BitField<int, 8, 8> {}; | |
708 | 722 |
709 Major MajorKey() { return GenericBinaryOp; } | 723 Major MajorKey() { return GenericBinaryOp; } |
710 int MinorKey() { | 724 int MinorKey() { |
711 // Encode the parameters in a unique 16 bit value. | 725 // Encode the parameters in a unique 16 bit value. |
712 return OpBits::encode(op_) | 726 return OpBits::encode(op_) |
713 | ModeBits::encode(mode_); | 727 | ModeBits::encode(mode_) |
728 | KnownIntBits::encode(MinorKeyForKnownInt()); | |
714 } | 729 } |
715 | 730 |
716 void Generate(MacroAssembler* masm); | 731 void Generate(MacroAssembler* masm); |
717 void HandleNonSmiBitwiseOp(MacroAssembler* masm); | 732 void HandleNonSmiBitwiseOp(MacroAssembler* masm); |
718 | 733 |
734 static bool RhsIsOneWeWantToOptimizeFor(Token::Value op, int known_rhs) { | |
735 if (known_rhs == CodeGenerator::kUnknownIntValue) return false; | |
736 if (op == Token::DIV) return known_rhs >= 2 && known_rhs <= 3; | |
737 if (op == Token::MOD) { | |
738 if (known_rhs <= 1) return false; | |
739 if (known_rhs <= 10) return true; | |
740 if (known_rhs <= kMaxKnownRhs && IsPowerOf2(known_rhs)) return true; | |
741 return false; | |
742 } | |
743 return false; | |
744 } | |
745 | |
746 int MinorKeyForKnownInt() { | |
747 if (!specialized_on_rhs_) return 0; | |
748 if (known_rhs_ <= 10) return known_rhs_ + 1; | |
749 ASSERT(IsPowerOf2(known_rhs_)); | |
750 int key = 12; | |
751 int d = known_rhs_; | |
752 while ((d & 1) == 0) { | |
753 key++; | |
754 d >>= 1; | |
755 } | |
756 return key; | |
757 } | |
758 | |
719 const char* GetName() { | 759 const char* GetName() { |
720 switch (op_) { | 760 switch (op_) { |
721 case Token::ADD: return "GenericBinaryOpStub_ADD"; | 761 case Token::ADD: return "GenericBinaryOpStub_ADD"; |
722 case Token::SUB: return "GenericBinaryOpStub_SUB"; | 762 case Token::SUB: return "GenericBinaryOpStub_SUB"; |
723 case Token::MUL: return "GenericBinaryOpStub_MUL"; | 763 case Token::MUL: return "GenericBinaryOpStub_MUL"; |
724 case Token::DIV: return "GenericBinaryOpStub_DIV"; | 764 case Token::DIV: return "GenericBinaryOpStub_DIV"; |
765 case Token::MOD: return "GenericBinaryOpStub_MOD"; | |
725 case Token::BIT_OR: return "GenericBinaryOpStub_BIT_OR"; | 766 case Token::BIT_OR: return "GenericBinaryOpStub_BIT_OR"; |
726 case Token::BIT_AND: return "GenericBinaryOpStub_BIT_AND"; | 767 case Token::BIT_AND: return "GenericBinaryOpStub_BIT_AND"; |
727 case Token::BIT_XOR: return "GenericBinaryOpStub_BIT_XOR"; | 768 case Token::BIT_XOR: return "GenericBinaryOpStub_BIT_XOR"; |
728 case Token::SAR: return "GenericBinaryOpStub_SAR"; | 769 case Token::SAR: return "GenericBinaryOpStub_SAR"; |
729 case Token::SHL: return "GenericBinaryOpStub_SHL"; | 770 case Token::SHL: return "GenericBinaryOpStub_SHL"; |
730 case Token::SHR: return "GenericBinaryOpStub_SHR"; | 771 case Token::SHR: return "GenericBinaryOpStub_SHR"; |
731 default: return "GenericBinaryOpStub"; | 772 default: return "GenericBinaryOpStub"; |
732 } | 773 } |
733 } | 774 } |
734 | 775 |
735 #ifdef DEBUG | 776 #ifdef DEBUG |
736 void Print() { PrintF("GenericBinaryOpStub (%s)\n", Token::String(op_)); } | 777 void Print() { |
778 if (specialized_on_rhs_) { | |
779 PrintF("GenericBinaryOpStub (%s)\n", Token::String(op_)); | |
William Hesse
2009/07/03 11:27:01
Why not make this message more informative, by inc
Erik Corry
2009/07/03 17:43:38
Oops, that is what I was trying to do, but I got t
| |
780 } else { | |
781 PrintF("GenericBinaryOpStub (%s by %d)\n", | |
782 Token::String(op_), | |
783 known_rhs_); | |
784 } | |
785 } | |
737 #endif | 786 #endif |
738 }; | 787 }; |
739 | 788 |
740 | 789 |
741 void CodeGenerator::GenericBinaryOperation(Token::Value op, | 790 void CodeGenerator::GenericBinaryOperation(Token::Value op, |
742 OverwriteMode overwrite_mode) { | 791 OverwriteMode overwrite_mode, |
792 int known_rhs) { | |
William Hesse
2009/07/03 11:27:01
Would "constant_rhs" be a better name than "known_
Erik Corry
2009/07/03 17:43:38
Probably
| |
743 VirtualFrame::SpilledScope spilled_scope; | 793 VirtualFrame::SpilledScope spilled_scope; |
744 // sp[0] : y | 794 // sp[0] : y |
745 // sp[1] : x | 795 // sp[1] : x |
746 // result : r0 | 796 // result : r0 |
747 | 797 |
748 // Stub is entered with a call: 'return address' is in lr. | 798 // Stub is entered with a call: 'return address' is in lr. |
749 switch (op) { | 799 switch (op) { |
750 case Token::ADD: // fall through. | 800 case Token::ADD: // fall through. |
751 case Token::SUB: // fall through. | 801 case Token::SUB: // fall through. |
752 case Token::MUL: | 802 case Token::MUL: |
803 case Token::DIV: | |
804 case Token::MOD: | |
753 case Token::BIT_OR: | 805 case Token::BIT_OR: |
754 case Token::BIT_AND: | 806 case Token::BIT_AND: |
755 case Token::BIT_XOR: | 807 case Token::BIT_XOR: |
756 case Token::SHL: | 808 case Token::SHL: |
757 case Token::SHR: | 809 case Token::SHR: |
758 case Token::SAR: { | 810 case Token::SAR: { |
759 frame_->EmitPop(r0); // r0 : y | 811 frame_->EmitPop(r0); // r0 : y |
760 frame_->EmitPop(r1); // r1 : x | 812 frame_->EmitPop(r1); // r1 : x |
761 GenericBinaryOpStub stub(op, overwrite_mode); | 813 GenericBinaryOpStub stub(op, overwrite_mode, known_rhs); |
762 frame_->CallStub(&stub, 0); | 814 frame_->CallStub(&stub, 0); |
763 break; | 815 break; |
764 } | 816 } |
765 | 817 |
766 case Token::DIV: { | |
767 Result arg_count = allocator_->Allocate(r0); | |
768 ASSERT(arg_count.is_valid()); | |
769 __ mov(arg_count.reg(), Operand(1)); | |
770 frame_->InvokeBuiltin(Builtins::DIV, CALL_JS, &arg_count, 2); | |
771 break; | |
772 } | |
773 | |
774 case Token::MOD: { | |
775 Result arg_count = allocator_->Allocate(r0); | |
776 ASSERT(arg_count.is_valid()); | |
777 __ mov(arg_count.reg(), Operand(1)); | |
778 frame_->InvokeBuiltin(Builtins::MOD, CALL_JS, &arg_count, 2); | |
779 break; | |
780 } | |
781 | |
782 case Token::COMMA: | 818 case Token::COMMA: |
783 frame_->EmitPop(r0); | 819 frame_->EmitPop(r0); |
784 // simply discard left value | 820 // simply discard left value |
785 frame_->Drop(); | 821 frame_->Drop(); |
786 break; | 822 break; |
787 | 823 |
788 default: | 824 default: |
789 // Other cases should have been handled before this point. | 825 // Other cases should have been handled before this point. |
790 UNREACHABLE(); | 826 UNREACHABLE(); |
791 break; | 827 break; |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
835 if (reversed_) { | 871 if (reversed_) { |
836 __ rsb(r0, r0, Operand(Smi::FromInt(value_))); | 872 __ rsb(r0, r0, Operand(Smi::FromInt(value_))); |
837 __ mov(r1, Operand(Smi::FromInt(value_))); | 873 __ mov(r1, Operand(Smi::FromInt(value_))); |
838 } else { | 874 } else { |
839 __ add(r1, r0, Operand(Smi::FromInt(value_))); | 875 __ add(r1, r0, Operand(Smi::FromInt(value_))); |
840 __ mov(r0, Operand(Smi::FromInt(value_))); | 876 __ mov(r0, Operand(Smi::FromInt(value_))); |
841 } | 877 } |
842 break; | 878 break; |
843 } | 879 } |
844 | 880 |
881 // For these operations there is no optimistic operation that needs to be | |
882 // reverted. | |
883 case Token::MUL: | |
884 case Token::MOD: | |
845 case Token::BIT_OR: | 885 case Token::BIT_OR: |
846 case Token::BIT_XOR: | 886 case Token::BIT_XOR: |
847 case Token::BIT_AND: { | 887 case Token::BIT_AND: { |
848 if (reversed_) { | 888 if (reversed_) { |
849 __ mov(r1, Operand(Smi::FromInt(value_))); | 889 __ mov(r1, Operand(Smi::FromInt(value_))); |
850 } else { | 890 } else { |
851 __ mov(r1, Operand(r0)); | 891 __ mov(r1, Operand(r0)); |
852 __ mov(r0, Operand(Smi::FromInt(value_))); | 892 __ mov(r0, Operand(Smi::FromInt(value_))); |
853 } | 893 } |
854 break; | 894 break; |
(...skipping 10 matching lines...) Expand all Loading... | |
865 } | 905 } |
866 break; | 906 break; |
867 } | 907 } |
868 | 908 |
869 default: | 909 default: |
870 // Other cases should have been handled before this point. | 910 // Other cases should have been handled before this point. |
871 UNREACHABLE(); | 911 UNREACHABLE(); |
872 break; | 912 break; |
873 } | 913 } |
874 | 914 |
875 GenericBinaryOpStub stub(op_, overwrite_mode_); | 915 GenericBinaryOpStub stub(op_, overwrite_mode_, value_); |
876 __ CallStub(&stub); | 916 __ CallStub(&stub); |
877 } | 917 } |
878 | 918 |
879 | 919 |
920 static bool PopCountLessThanEqual2(unsigned int x) { | |
921 int popcnt = 0; | |
922 while (x != 0) { | |
923 if ((x & 1) != 0) { | |
924 popcnt++; | |
925 if (popcnt > 2) return false; | |
William Hesse
2009/07/03 11:27:01
The whole function can be replaced by:
x &= x - 1;
Erik Corry
2009/07/03 17:43:38
Cool
| |
926 } | |
927 x >>= 1; | |
928 } | |
929 return true; | |
930 } | |
931 | |
932 | |
933 // Return an int that is <= x that can be encoded as an 8 bit constant shifted | |
934 // left by an even number of bits. | |
935 static int ArmEncodableLessThan(unsigned int x) { | |
936 int shift_distance = 0; | |
937 while (x > 0xffff) { | |
938 x >>= 8; | |
939 shift_distance += 8; | |
940 } | |
941 while (x > 0xff) { | |
942 x >>= 2; | |
943 shift_distance += 2; | |
944 } | |
945 return x << shift_distance; | |
946 } | |
947 | |
948 | |
949 // Returns the index of the lowest bit set. | |
950 static int BitPosition(unsigned x) { | |
951 int bit_posn = 0; | |
952 while ((x & 0xf) == 0) { | |
953 bit_posn += 4; | |
954 x >>= 4; | |
955 } | |
956 while ((x & 1) == 0) { | |
957 bit_posn++; | |
958 x >>= 1; | |
959 } | |
960 return bit_posn; | |
961 } | |
962 | |
963 | |
880 void CodeGenerator::SmiOperation(Token::Value op, | 964 void CodeGenerator::SmiOperation(Token::Value op, |
881 Handle<Object> value, | 965 Handle<Object> value, |
882 bool reversed, | 966 bool reversed, |
883 OverwriteMode mode) { | 967 OverwriteMode mode) { |
884 VirtualFrame::SpilledScope spilled_scope; | 968 VirtualFrame::SpilledScope spilled_scope; |
885 // NOTE: This is an attempt to inline (a bit) more of the code for | 969 // NOTE: This is an attempt to inline (a bit) more of the code for |
886 // some possible smi operations (like + and -) when (at least) one | 970 // some possible smi operations (like + and -) when (at least) one |
887 // of the operands is a literal smi. With this optimization, the | 971 // of the operands is a literal smi. With this optimization, the |
888 // performance of the system is increased by ~15%, and the generated | 972 // performance of the system is increased by ~15%, and the generated |
889 // code size is increased by ~1% (measured on a combination of | 973 // code size is increased by ~1% (measured on a combination of |
890 // different benchmarks). | 974 // different benchmarks). |
891 | 975 |
892 // sp[0] : operand | 976 // sp[0] : operand |
893 | 977 |
894 int int_value = Smi::cast(*value)->value(); | 978 int int_value = Smi::cast(*value)->value(); |
895 | 979 |
896 JumpTarget exit; | 980 JumpTarget exit; |
897 frame_->EmitPop(r0); | 981 frame_->EmitPop(r0); |
898 | 982 |
983 bool something_to_inline = true; | |
899 switch (op) { | 984 switch (op) { |
900 case Token::ADD: { | 985 case Token::ADD: { |
901 DeferredCode* deferred = | 986 DeferredCode* deferred = |
902 new DeferredInlineSmiOperation(op, int_value, reversed, mode); | 987 new DeferredInlineSmiOperation(op, int_value, reversed, mode); |
903 | 988 |
904 __ add(r0, r0, Operand(value), SetCC); | 989 __ add(r0, r0, Operand(value), SetCC); |
905 deferred->Branch(vs); | 990 deferred->Branch(vs); |
906 __ tst(r0, Operand(kSmiTagMask)); | 991 __ tst(r0, Operand(kSmiTagMask)); |
907 deferred->Branch(ne); | 992 deferred->Branch(ne); |
908 deferred->BindExit(); | 993 deferred->BindExit(); |
909 break; | 994 break; |
910 } | 995 } |
911 | 996 |
912 case Token::SUB: { | 997 case Token::SUB: { |
913 DeferredCode* deferred = | 998 DeferredCode* deferred = |
914 new DeferredInlineSmiOperation(op, int_value, reversed, mode); | 999 new DeferredInlineSmiOperation(op, int_value, reversed, mode); |
915 | 1000 |
916 if (reversed) { | 1001 if (reversed) { |
917 __ rsb(r0, r0, Operand(value), SetCC); | 1002 __ rsb(r0, r0, Operand(value), SetCC); |
918 } else { | 1003 } else { |
919 __ sub(r0, r0, Operand(value), SetCC); | 1004 __ sub(r0, r0, Operand(value), SetCC); |
920 } | 1005 } |
921 deferred->Branch(vs); | 1006 deferred->Branch(vs); |
922 __ tst(r0, Operand(kSmiTagMask)); | 1007 __ tst(r0, Operand(kSmiTagMask)); |
923 deferred->Branch(ne); | 1008 deferred->Branch(ne); |
924 deferred->BindExit(); | 1009 deferred->BindExit(); |
925 break; | 1010 break; |
926 } | 1011 } |
927 | 1012 |
1013 | |
928 case Token::BIT_OR: | 1014 case Token::BIT_OR: |
929 case Token::BIT_XOR: | 1015 case Token::BIT_XOR: |
930 case Token::BIT_AND: { | 1016 case Token::BIT_AND: { |
931 DeferredCode* deferred = | 1017 DeferredCode* deferred = |
932 new DeferredInlineSmiOperation(op, int_value, reversed, mode); | 1018 new DeferredInlineSmiOperation(op, int_value, reversed, mode); |
933 __ tst(r0, Operand(kSmiTagMask)); | 1019 __ tst(r0, Operand(kSmiTagMask)); |
934 deferred->Branch(ne); | 1020 deferred->Branch(ne); |
935 switch (op) { | 1021 switch (op) { |
936 case Token::BIT_OR: __ orr(r0, r0, Operand(value)); break; | 1022 case Token::BIT_OR: __ orr(r0, r0, Operand(value)); break; |
937 case Token::BIT_XOR: __ eor(r0, r0, Operand(value)); break; | 1023 case Token::BIT_XOR: __ eor(r0, r0, Operand(value)); break; |
938 case Token::BIT_AND: __ and_(r0, r0, Operand(value)); break; | 1024 case Token::BIT_AND: __ and_(r0, r0, Operand(value)); break; |
939 default: UNREACHABLE(); | 1025 default: UNREACHABLE(); |
940 } | 1026 } |
941 deferred->BindExit(); | 1027 deferred->BindExit(); |
942 break; | 1028 break; |
943 } | 1029 } |
944 | 1030 |
945 case Token::SHL: | 1031 case Token::SHL: |
946 case Token::SHR: | 1032 case Token::SHR: |
947 case Token::SAR: { | 1033 case Token::SAR: { |
948 if (reversed) { | 1034 if (reversed) { |
949 __ mov(ip, Operand(value)); | 1035 something_to_inline = false; |
950 frame_->EmitPush(ip); | 1036 break; |
951 frame_->EmitPush(r0); | 1037 } |
952 GenericBinaryOperation(op, mode); | 1038 int shift_value = int_value & 0x1f; // least significant 5 bits |
1039 DeferredCode* deferred = | |
1040 new DeferredInlineSmiOperation(op, shift_value, false, mode); | |
1041 __ tst(r0, Operand(kSmiTagMask)); | |
1042 deferred->Branch(ne); | |
1043 __ mov(r2, Operand(r0, ASR, kSmiTagSize)); // remove tags | |
1044 switch (op) { | |
1045 case Token::SHL: { | |
William Hesse
2009/07/03 11:27:01
Why no check of shift_value with 0 for SHL? If it
Erik Corry
2009/07/03 17:43:38
Shift left by zero is the way reg-reg mov is encod
| |
1046 __ mov(r2, Operand(r2, LSL, shift_value)); | |
1047 // check that the *unsigned* result fits in a smi | |
1048 __ add(r3, r2, Operand(0x40000000), SetCC); | |
1049 deferred->Branch(mi); | |
1050 break; | |
1051 } | |
1052 case Token::SHR: { | |
1053 // LSR by immediate 0 means shifting 32 bits. | |
1054 if (shift_value != 0) { | |
1055 __ mov(r2, Operand(r2, LSR, shift_value)); | |
1056 } | |
1057 // check that the *unsigned* result fits in a smi | |
1058 // neither of the two high-order bits can be set: | |
1059 // - 0x80000000: high bit would be lost when smi tagging | |
1060 // - 0x40000000: this number would convert to negative when | |
1061 // smi tagging these two cases can only happen with shifts | |
1062 // by 0 or 1 when handed a valid smi | |
1063 __ and_(r3, r2, Operand(0xc0000000), SetCC); | |
1064 deferred->Branch(ne); | |
1065 break; | |
1066 } | |
1067 case Token::SAR: { | |
1068 if (shift_value != 0) { | |
1069 // ASR by immediate 0 means shifting 32 bits. | |
1070 __ mov(r2, Operand(r2, ASR, shift_value)); | |
1071 } | |
1072 break; | |
1073 } | |
1074 default: UNREACHABLE(); | |
1075 } | |
1076 __ mov(r0, Operand(r2, LSL, kSmiTagSize)); | |
1077 deferred->BindExit(); | |
1078 break; | |
1079 } | |
953 | 1080 |
954 } else { | 1081 case Token::MOD: { |
955 int shift_value = int_value & 0x1f; // least significant 5 bits | 1082 if (reversed || int_value < 2 || !IsPowerOf2(int_value)) { |
956 DeferredCode* deferred = | 1083 something_to_inline = false; |
957 new DeferredInlineSmiOperation(op, shift_value, false, mode); | 1084 break; |
958 __ tst(r0, Operand(kSmiTagMask)); | |
959 deferred->Branch(ne); | |
960 __ mov(r2, Operand(r0, ASR, kSmiTagSize)); // remove tags | |
961 switch (op) { | |
962 case Token::SHL: { | |
963 __ mov(r2, Operand(r2, LSL, shift_value)); | |
964 // check that the *unsigned* result fits in a smi | |
965 __ add(r3, r2, Operand(0x40000000), SetCC); | |
966 deferred->Branch(mi); | |
967 break; | |
968 } | |
969 case Token::SHR: { | |
970 // LSR by immediate 0 means shifting 32 bits. | |
971 if (shift_value != 0) { | |
972 __ mov(r2, Operand(r2, LSR, shift_value)); | |
973 } | |
974 // check that the *unsigned* result fits in a smi | |
975 // neither of the two high-order bits can be set: | |
976 // - 0x80000000: high bit would be lost when smi tagging | |
977 // - 0x40000000: this number would convert to negative when | |
978 // smi tagging these two cases can only happen with shifts | |
979 // by 0 or 1 when handed a valid smi | |
980 __ and_(r3, r2, Operand(0xc0000000), SetCC); | |
981 deferred->Branch(ne); | |
982 break; | |
983 } | |
984 case Token::SAR: { | |
985 if (shift_value != 0) { | |
986 // ASR by immediate 0 means shifting 32 bits. | |
987 __ mov(r2, Operand(r2, ASR, shift_value)); | |
988 } | |
989 break; | |
990 } | |
991 default: UNREACHABLE(); | |
992 } | |
993 __ mov(r0, Operand(r2, LSL, kSmiTagSize)); | |
994 deferred->BindExit(); | |
995 } | 1085 } |
1086 DeferredCode* deferred = | |
1087 new DeferredInlineSmiOperation(op, int_value, reversed, mode); | |
1088 unsigned mask = (0x80000000u | kSmiTagMask); | |
1089 __ tst(r0, Operand(mask)); | |
1090 deferred->Branch(ne); // Go to deferred code on non-Smis and negative. | |
1091 mask = (int_value << kSmiTagSize) - 1; | |
1092 __ and_(r0, r0, Operand(mask)); | |
1093 deferred->BindExit(); | |
1094 break; | |
1095 } | |
1096 | |
1097 case Token::MUL: { | |
1098 if (!IsEasyToMultiplyBy(int_value)) { | |
1099 something_to_inline = false; | |
1100 break; | |
1101 } | |
1102 DeferredCode* deferred = | |
1103 new DeferredInlineSmiOperation(op, int_value, reversed, mode); | |
1104 unsigned max_smi_that_wont_overflow = | |
1105 ArmEncodableLessThan(Smi::kMaxValue / int_value); | |
1106 max_smi_that_wont_overflow <<= kSmiTagSize; | |
1107 unsigned mask = 0x80000000u; | |
1108 while ((mask & max_smi_that_wont_overflow) == 0) { | |
1109 mask |= mask >> 1; | |
1110 } | |
1111 mask |= kSmiTagMask; | |
1112 // This does a single mask that checks for a too high value in a | |
1113 // conservative way and for a non-Smi. It also filters out negative | |
1114 // numbers, unfortunately, but since this code is inline we prefer | |
1115 // brevity to comprehensiveness. | |
1116 __ tst(r0, Operand(mask)); | |
1117 deferred->Branch(ne); | |
1118 MultiplyByKnownInt(masm_, r0, r0, int_value); | |
1119 deferred->BindExit(); | |
996 break; | 1120 break; |
997 } | 1121 } |
998 | 1122 |
999 default: | 1123 default: |
1000 if (!reversed) { | 1124 something_to_inline = false; |
1001 frame_->EmitPush(r0); | |
1002 __ mov(r0, Operand(value)); | |
1003 frame_->EmitPush(r0); | |
1004 } else { | |
1005 __ mov(ip, Operand(value)); | |
1006 frame_->EmitPush(ip); | |
1007 frame_->EmitPush(r0); | |
1008 } | |
1009 GenericBinaryOperation(op, mode); | |
1010 break; | 1125 break; |
1011 } | 1126 } |
1012 | 1127 |
1128 if (!something_to_inline) { | |
1129 if (!reversed) { | |
1130 frame_->EmitPush(r0); | |
1131 __ mov(r0, Operand(value)); | |
1132 frame_->EmitPush(r0); | |
1133 GenericBinaryOperation(op, mode, int_value); | |
1134 } else { | |
1135 __ mov(ip, Operand(value)); | |
1136 frame_->EmitPush(ip); | |
1137 frame_->EmitPush(r0); | |
1138 GenericBinaryOperation(op, mode, kUnknownIntValue); | |
1139 } | |
1140 } | |
1141 | |
1013 exit.Bind(); | 1142 exit.Bind(); |
1014 } | 1143 } |
1015 | 1144 |
1016 | 1145 |
1017 void CodeGenerator::Comparison(Condition cc, | 1146 void CodeGenerator::Comparison(Condition cc, |
1018 Expression* left, | 1147 Expression* left, |
1019 Expression* right, | 1148 Expression* right, |
1020 bool strict) { | 1149 bool strict) { |
1021 if (left != NULL) LoadAndSpill(left); | 1150 if (left != NULL) LoadAndSpill(left); |
1022 if (right != NULL) LoadAndSpill(right); | 1151 if (right != NULL) LoadAndSpill(right); |
(...skipping 2278 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3301 __ mov(r0, Operand(Factory::undefined_value())); | 3430 __ mov(r0, Operand(Factory::undefined_value())); |
3302 frame_->EmitPush(r0); | 3431 frame_->EmitPush(r0); |
3303 } | 3432 } |
3304 | 3433 |
3305 | 3434 |
3306 void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) { | 3435 void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) { |
3307 VirtualFrame::SpilledScope spilled_scope; | 3436 VirtualFrame::SpilledScope spilled_scope; |
3308 ASSERT(args->length() == 1); | 3437 ASSERT(args->length() == 1); |
3309 LoadAndSpill(args->at(0)); | 3438 LoadAndSpill(args->at(0)); |
3310 frame_->EmitPop(r0); | 3439 frame_->EmitPop(r0); |
3311 __ tst(r0, Operand(kSmiTagMask | 0x80000000)); | 3440 __ tst(r0, Operand(kSmiTagMask | 0x80000000u)); |
3312 cc_reg_ = eq; | 3441 cc_reg_ = eq; |
3313 } | 3442 } |
3314 | 3443 |
3315 | 3444 |
3316 // This should generate code that performs a charCodeAt() call or returns | 3445 // This should generate code that performs a charCodeAt() call or returns |
3317 // undefined in order to trigger the slow case, Runtime_StringCharCodeAt. | 3446 // undefined in order to trigger the slow case, Runtime_StringCharCodeAt. |
3318 // It is not yet implemented on ARM, so it always goes to the slow case. | 3447 // It is not yet implemented on ARM, so it always goes to the slow case. |
3319 void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) { | 3448 void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) { |
3320 VirtualFrame::SpilledScope spilled_scope; | 3449 VirtualFrame::SpilledScope spilled_scope; |
3321 ASSERT(args->length() == 2); | 3450 ASSERT(args->length() == 2); |
(...skipping 1025 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4347 __ mov(scratch, Operand(scratch, LSL, 8), LeaveCC, eq); | 4476 __ mov(scratch, Operand(scratch, LSL, 8), LeaveCC, eq); |
4348 // Top 4. | 4477 // Top 4. |
4349 __ tst(scratch, Operand(0xf0000000)); | 4478 __ tst(scratch, Operand(0xf0000000)); |
4350 __ add(zeros, zeros, Operand(4), LeaveCC, eq); | 4479 __ add(zeros, zeros, Operand(4), LeaveCC, eq); |
4351 __ mov(scratch, Operand(scratch, LSL, 4), LeaveCC, eq); | 4480 __ mov(scratch, Operand(scratch, LSL, 4), LeaveCC, eq); |
4352 // Top 2. | 4481 // Top 2. |
4353 __ tst(scratch, Operand(0xc0000000)); | 4482 __ tst(scratch, Operand(0xc0000000)); |
4354 __ add(zeros, zeros, Operand(2), LeaveCC, eq); | 4483 __ add(zeros, zeros, Operand(2), LeaveCC, eq); |
4355 __ mov(scratch, Operand(scratch, LSL, 2), LeaveCC, eq); | 4484 __ mov(scratch, Operand(scratch, LSL, 2), LeaveCC, eq); |
4356 // Top bit. | 4485 // Top bit. |
4357 __ tst(scratch, Operand(0x80000000)); | 4486 __ tst(scratch, Operand(0x80000000u)); |
4358 __ add(zeros, zeros, Operand(1), LeaveCC, eq); | 4487 __ add(zeros, zeros, Operand(1), LeaveCC, eq); |
4359 #endif | 4488 #endif |
4360 } | 4489 } |
4361 | 4490 |
4362 | 4491 |
4363 // Takes a Smi and converts to an IEEE 64 bit floating point value in two | 4492 // Takes a Smi and converts to an IEEE 64 bit floating point value in two |
4364 // registers. The format is 1 sign bit, 11 exponent bits (biased 1023) and | 4493 // registers. The format is 1 sign bit, 11 exponent bits (biased 1023) and |
4365 // 52 fraction bits (20 in the first word, 32 in the second). Zeros is a | 4494 // 52 fraction bits (20 in the first word, 32 in the second). Zeros is a |
4366 // scratch register. Destroys the source register. No GC occurs during this | 4495 // scratch register. Destroys the source register. No GC occurs during this |
4367 // stub so you don't have to set up the frame. | 4496 // stub so you don't have to set up the frame. |
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4499 }; | 4628 }; |
4500 | 4629 |
4501 | 4630 |
4502 // See comment for class. | 4631 // See comment for class. |
4503 void WriteInt32ToHeapNumberStub::Generate(MacroAssembler *masm) { | 4632 void WriteInt32ToHeapNumberStub::Generate(MacroAssembler *masm) { |
4504 Label max_negative_int; | 4633 Label max_negative_int; |
4505 // the_int_ has the answer which is a signed int32 but not a Smi. | 4634 // the_int_ has the answer which is a signed int32 but not a Smi. |
4506 // We test for the special value that has a different exponent. This test | 4635 // We test for the special value that has a different exponent. This test |
4507 // has the neat side effect of setting the flags according to the sign. | 4636 // has the neat side effect of setting the flags according to the sign. |
4508 ASSERT(HeapNumber::kSignMask == 0x80000000u); | 4637 ASSERT(HeapNumber::kSignMask == 0x80000000u); |
4509 __ cmp(the_int_, Operand(0x80000000)); | 4638 __ cmp(the_int_, Operand(0x80000000u)); |
4510 __ b(eq, &max_negative_int); | 4639 __ b(eq, &max_negative_int); |
4511 // Set up the correct exponent in scratch_. All non-Smi int32s have the same. | 4640 // Set up the correct exponent in scratch_. All non-Smi int32s have the same. |
4512 // A non-Smi integer is 1.xxx * 2^30 so the exponent is 30 (biased). | 4641 // A non-Smi integer is 1.xxx * 2^30 so the exponent is 30 (biased). |
4513 uint32_t non_smi_exponent = | 4642 uint32_t non_smi_exponent = |
4514 (HeapNumber::kExponentBias + 30) << HeapNumber::kExponentShift; | 4643 (HeapNumber::kExponentBias + 30) << HeapNumber::kExponentShift; |
4515 __ mov(scratch_, Operand(non_smi_exponent)); | 4644 __ mov(scratch_, Operand(non_smi_exponent)); |
4516 // Set the sign bit in scratch_ if the value was negative. | 4645 // Set the sign bit in scratch_ if the value was negative. |
4517 __ orr(scratch_, scratch_, Operand(HeapNumber::kSignMask), LeaveCC, cs); | 4646 __ orr(scratch_, scratch_, Operand(HeapNumber::kSignMask), LeaveCC, cs); |
4518 // Subtract from 0 if the value was negative. | 4647 // Subtract from 0 if the value was negative. |
4519 __ rsb(the_int_, the_int_, Operand(0), LeaveCC, cs); | 4648 __ rsb(the_int_, the_int_, Operand(0), LeaveCC, cs); |
(...skipping 793 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5313 break; | 5442 break; |
5314 case Token::SHL: | 5443 case Token::SHL: |
5315 __ InvokeBuiltin(Builtins::SHL, JUMP_JS); | 5444 __ InvokeBuiltin(Builtins::SHL, JUMP_JS); |
5316 break; | 5445 break; |
5317 default: | 5446 default: |
5318 UNREACHABLE(); | 5447 UNREACHABLE(); |
5319 } | 5448 } |
5320 } | 5449 } |
5321 | 5450 |
5322 | 5451 |
5452 // Can we multiply by x with max two shifts and an add. | |
5453 // This answers yes to all integers from 2 to 10. | |
5454 static bool IsEasyToMultiplyBy(int x) { | |
5455 if (x < 2) return false; // Avoid special cases. | |
5456 if (x > (Smi::kMaxValue + 1) >> 2) return false; // Almost always overflows. | |
5457 if (IsPowerOf2(x)) return true; // Simple shift. | |
5458 if (PopCountLessThanEqual2(x)) return true; // Shift and add and shift. | |
5459 if (IsPowerOf2(x + 1)) return true; // Patterns like 11111. | |
5460 return false; | |
5461 } | |
5462 | |
5463 | |
5464 // Can multiply by anything that IsEasyToMultiplyBy returns true for. | |
5465 // Source and destination may be the same register. | |
5466 static void MultiplyByKnownInt(MacroAssembler* masm, | |
5467 Register source, | |
5468 Register destination, | |
5469 int known_int) { | |
5470 if (IsPowerOf2(known_int)) { | |
5471 __ mov(destination, Operand(source, LSL, BitPosition(known_int))); | |
5472 } else if (PopCountLessThanEqual2(known_int)) { | |
5473 int first_bit = BitPosition(known_int); | |
5474 int second_bit = BitPosition(known_int ^ (1 << first_bit)); | |
5475 __ add(destination, source, Operand(source, LSL, second_bit - first_bit)); | |
5476 if (first_bit != 0) { | |
5477 __ mov(destination, Operand(destination, LSL, first_bit)); | |
William Hesse
2009/07/03 11:27:01
Are you going to find out if the value overflowed
Erik Corry
2009/07/03 17:43:38
No, the flags are not set by this routine. Commen
| |
5478 } | |
5479 } else { | |
5480 ASSERT(IsPowerOf2(known_int + 1)); // Patterns like 1111. | |
5481 int the_bit = BitPosition(known_int + 1); | |
5482 __ rsb(destination, source, Operand(source, LSL, the_bit)); | |
5483 } | |
5484 } | |
5485 | |
5486 | |
5487 // This function (as opposed to MultiplyByKnownInt) takes the known int in a | |
5488 // a register for the cases where it doesn't know a good trick, and may deliver | |
5489 // a result that needs shifting. | |
5490 static void MultiplyByKnownInt2( | |
5491 MacroAssembler* masm, | |
5492 Register result, | |
5493 Register source, | |
5494 Register known_int_register, // Smi tagged. | |
5495 int known_int, | |
5496 int* result_needs_shifting) { // Including Smi tag shift | |
William Hesse
2009/07/03 11:27:01
I would call this shift_amount or required_shift.
| |
5497 switch (known_int) { | |
5498 case 3: | |
5499 __ add(result, source, Operand(source, LSL, 1)); | |
5500 *result_needs_shifting = 1; | |
5501 break; | |
5502 case 5: | |
5503 __ add(result, source, Operand(source, LSL, 2)); | |
5504 *result_needs_shifting = 1; | |
5505 break; | |
5506 case 6: | |
5507 __ add(result, source, Operand(source, LSL, 1)); | |
5508 *result_needs_shifting = 2; | |
5509 break; | |
5510 case 7: | |
5511 __ rsb(result, source, Operand(source, LSL, 3)); | |
5512 *result_needs_shifting = 1; | |
5513 break; | |
5514 case 9: | |
5515 __ add(result, source, Operand(source, LSL, 3)); | |
5516 *result_needs_shifting = 1; | |
5517 break; | |
5518 case 10: | |
5519 __ add(result, source, Operand(source, LSL, 2)); | |
5520 *result_needs_shifting = 2; | |
5521 break; | |
5522 default: | |
5523 ASSERT(!IsPowerOf2(known_int)); // That would be very inefficient. | |
5524 __ mul(result, source, known_int_register); | |
5525 *result_needs_shifting = 0; | |
5526 } | |
5527 } | |
5528 | |
5529 | |
5323 void GenericBinaryOpStub::Generate(MacroAssembler* masm) { | 5530 void GenericBinaryOpStub::Generate(MacroAssembler* masm) { |
5324 // r1 : x | 5531 // r1 : x |
5325 // r0 : y | 5532 // r0 : y |
5326 // result : r0 | 5533 // result : r0 |
5327 | 5534 |
5328 // All ops need to know whether we are dealing with two Smis. Set up r2 to | 5535 // All ops need to know whether we are dealing with two Smis. Set up r2 to |
5329 // tell us that. | 5536 // tell us that. |
5330 __ orr(r2, r1, Operand(r0)); // r2 = x | y; | 5537 __ orr(r2, r1, Operand(r0)); // r2 = x | y; |
5331 | 5538 |
5332 switch (op_) { | 5539 switch (op_) { |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5391 __ mov(r0, Operand(Smi::FromInt(0)), LeaveCC, pl); | 5598 __ mov(r0, Operand(Smi::FromInt(0)), LeaveCC, pl); |
5392 __ Ret(pl); // Return Smi 0 if the non-zero one was positive. | 5599 __ Ret(pl); // Return Smi 0 if the non-zero one was positive. |
5393 // Slow case. We fall through here if we multiplied a negative number | 5600 // Slow case. We fall through here if we multiplied a negative number |
5394 // with 0, because that would mean we should produce -0. | 5601 // with 0, because that would mean we should produce -0. |
5395 __ bind(&slow); | 5602 __ bind(&slow); |
5396 | 5603 |
5397 HandleBinaryOpSlowCases(masm, | 5604 HandleBinaryOpSlowCases(masm, |
5398 ¬_smi, | 5605 ¬_smi, |
5399 Builtins::MUL, | 5606 Builtins::MUL, |
5400 Token::MUL, | 5607 Token::MUL, |
5401 mode_); | 5608 mode_); |
5609 break; | |
5610 } | |
5611 | |
5612 case Token::DIV: | |
5613 case Token::MOD: { | |
5614 Label not_smi; | |
5615 if (specialized_on_rhs_) { | |
5616 Label smi_is_unsuitable; | |
5617 __ BranchOnNotSmi(r1, ¬_smi); | |
5618 if (IsPowerOf2(known_rhs_)) { | |
5619 if (op_ == Token::MOD) { | |
5620 __ and_(r0, | |
5621 r1, | |
5622 Operand(0x80000000u | ((known_rhs_ << kSmiTagSize) - 1)), | |
5623 SetCC); | |
5624 // We now have the answer, but if the input was negative we also | |
5625 // have the sign bit. Our work is done if the result is | |
5626 // positive or zero: | |
5627 __ Ret(pl); | |
5628 // A mod of a negative left hand side must return a negative number. | |
5629 // Unfortunately if the answer is 0 then we must return -0. And we | |
5630 // already optimistically trashed r0 so we may need to restore it. | |
5631 __ eor(r0, r0, Operand(0x80000000u), SetCC); | |
5632 __ mov(r0, Operand(Smi::FromInt(known_rhs_)), LeaveCC, eq); // -0. | |
5633 __ b(eq, &smi_is_unsuitable); // -0. | |
5634 __ sub(r0, r0, Operand(Smi::FromInt(known_rhs_))); // -3 % 4 == -3. | |
5635 } else { | |
5636 ASSERT(op_ == Token::DIV); | |
5637 __ tst(r1, | |
5638 Operand(0x80000000u | ((known_rhs_ << kSmiTagSize) - 1))); | |
5639 __ b(ne, &smi_is_unsuitable); // Go slow on negative or remainder. | |
5640 int shift = 0; | |
5641 int d = known_rhs_; | |
5642 while ((d & 1) == 0) { | |
5643 d >>= 1; | |
5644 shift++; | |
5645 } | |
5646 __ mov(r0, Operand(r1, LSR, shift)); | |
5647 __ bic(r0, r0, Operand(kSmiTagMask)); | |
5648 } | |
5649 } else { | |
5650 // Not a power of 2. | |
5651 __ tst(r1, Operand(0x80000000u)); | |
5652 __ b(ne, &smi_is_unsuitable); | |
5653 // Find a fixed point reciprocal of the divisor so we can divide by | |
5654 // multiplying. | |
5655 double divisor = 1.0 / known_rhs_; | |
5656 int shift = 32; | |
5657 double scale = 4294967296.0; // 1 << 32. | |
5658 uint32_t mul; | |
5659 // Maximise the precision of the fixed point reciprocal. | |
5660 while (true) { | |
5661 mul = static_cast<uint32_t>(scale * divisor); | |
5662 if (mul >= 0x7fffffff) break; | |
5663 scale *= 2.0; | |
5664 shift++; | |
5665 } | |
5666 mul++; | |
5667 __ mov(r2, Operand(mul)); | |
5668 __ umull(r3, r2, r2, r1); | |
5669 __ mov(r2, Operand(r2, LSR, shift - 31)); | |
5670 // r2 is r1 / rhs. r2 is not Smi tagged. | |
5671 // r0 is still the known rhs. r0 is Smi tagged. | |
5672 // r1 is still the unkown lhs. r1 is Smi tagged. | |
5673 int r4_needs_shifting = 0; // Including the Smi tag shift of 1. | |
5674 // r4 = r2 * r0. | |
5675 MultiplyByKnownInt2(masm, r4, r2, r0, known_rhs_, &r4_needs_shifting); | |
5676 // r4 << r4_needs_shifting is now the Smi tagged rhs * (r1 / rhs). | |
5677 if (op_ == Token::DIV) { | |
5678 __ sub(r3, r1, Operand(r4, LSL, r4_needs_shifting), SetCC); | |
5679 __ b(ne, &smi_is_unsuitable); // There was a remainder. | |
5680 __ mov(r0, Operand(r2, LSL, kSmiTagSize)); | |
5681 } else { | |
5682 ASSERT(op_ == Token::MOD); | |
5683 __ sub(r0, r1, Operand(r4, LSL, r4_needs_shifting)); | |
5684 } | |
5685 } | |
5686 __ Ret(); | |
5687 __ bind(&smi_is_unsuitable); | |
5688 } else { | |
5689 __ jmp(¬_smi); | |
5690 } | |
5691 HandleBinaryOpSlowCases(masm, | |
5692 ¬_smi, | |
5693 op_ == Token::MOD ? Builtins::MOD : Builtins::DIV, | |
5694 op_, | |
5695 mode_); | |
5402 break; | 5696 break; |
5403 } | 5697 } |
5404 | 5698 |
5405 case Token::BIT_OR: | 5699 case Token::BIT_OR: |
5406 case Token::BIT_AND: | 5700 case Token::BIT_AND: |
5407 case Token::BIT_XOR: | 5701 case Token::BIT_XOR: |
5408 case Token::SAR: | 5702 case Token::SAR: |
5409 case Token::SHR: | 5703 case Token::SHR: |
5410 case Token::SHL: { | 5704 case Token::SHL: { |
5411 Label slow; | 5705 Label slow; |
5412 ASSERT(kSmiTag == 0); // adjust code below | 5706 ASSERT(kSmiTag == 0); // adjust code below |
5413 __ tst(r2, Operand(kSmiTagMask)); | 5707 __ tst(r2, Operand(kSmiTagMask)); |
5414 __ b(ne, &slow); | 5708 __ b(ne, &slow); |
5415 switch (op_) { | 5709 switch (op_) { |
5416 case Token::BIT_OR: __ orr(r0, r0, Operand(r1)); break; | 5710 case Token::BIT_OR: __ orr(r0, r0, Operand(r1)); break; |
5417 case Token::BIT_AND: __ and_(r0, r0, Operand(r1)); break; | 5711 case Token::BIT_AND: __ and_(r0, r0, Operand(r1)); break; |
5418 case Token::BIT_XOR: __ eor(r0, r0, Operand(r1)); break; | 5712 case Token::BIT_XOR: __ eor(r0, r0, Operand(r1)); break; |
5419 case Token::SAR: | 5713 case Token::SAR: |
5420 // Remove tags from right operand. | 5714 // Remove tags from right operand. |
5421 __ mov(r2, Operand(r0, ASR, kSmiTagSize)); // y | 5715 __ mov(r2, Operand(r0, ASR, kSmiTagSize)); // y |
5422 // Use only the 5 least significant bits of the shift count. | 5716 // Use only the 5 least significant bits of the shift count. |
5423 __ and_(r2, r2, Operand(0x1f)); | 5717 __ and_(r2, r2, Operand(0x1f)); |
5424 __ mov(r0, Operand(r1, ASR, r2)); | 5718 __ mov(r0, Operand(r1, ASR, r2)); |
5425 // Smi tag result. | 5719 // Smi tag result. |
5426 __ and_(r0, r0, Operand(~kSmiTagMask)); | 5720 __ bic(r0, r0, Operand(kSmiTagMask)); |
5427 break; | 5721 break; |
5428 case Token::SHR: | 5722 case Token::SHR: |
5429 // Remove tags from operands. We can't do this on a 31 bit number | 5723 // Remove tags from operands. We can't do this on a 31 bit number |
5430 // because then the 0s get shifted into bit 30 instead of bit 31. | 5724 // because then the 0s get shifted into bit 30 instead of bit 31. |
5431 __ mov(r3, Operand(r1, ASR, kSmiTagSize)); // x | 5725 __ mov(r3, Operand(r1, ASR, kSmiTagSize)); // x |
5432 __ mov(r2, Operand(r0, ASR, kSmiTagSize)); // y | 5726 __ mov(r2, Operand(r0, ASR, kSmiTagSize)); // y |
5433 // Use only the 5 least significant bits of the shift count. | 5727 // Use only the 5 least significant bits of the shift count. |
5434 __ and_(r2, r2, Operand(0x1f)); | 5728 __ and_(r2, r2, Operand(0x1f)); |
5435 __ mov(r3, Operand(r3, LSR, r2)); | 5729 __ mov(r3, Operand(r3, LSR, r2)); |
5436 // Unsigned shift is not allowed to produce a negative number, so | 5730 // Unsigned shift is not allowed to produce a negative number, so |
(...skipping 663 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
6100 int CompareStub::MinorKey() { | 6394 int CompareStub::MinorKey() { |
6101 // Encode the two parameters in a unique 16 bit value. | 6395 // Encode the two parameters in a unique 16 bit value. |
6102 ASSERT(static_cast<unsigned>(cc_) >> 28 < (1 << 15)); | 6396 ASSERT(static_cast<unsigned>(cc_) >> 28 < (1 << 15)); |
6103 return (static_cast<unsigned>(cc_) >> 27) | (strict_ ? 1 : 0); | 6397 return (static_cast<unsigned>(cc_) >> 27) | (strict_ ? 1 : 0); |
6104 } | 6398 } |
6105 | 6399 |
6106 | 6400 |
6107 #undef __ | 6401 #undef __ |
6108 | 6402 |
6109 } } // namespace v8::internal | 6403 } } // namespace v8::internal |
OLD | NEW |