Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(373)

Side by Side Diff: src/arm/code-stubs-arm.cc

Issue 13560007: Remove ARM support for soft float (pre-VFP2) (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: tweaks Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright 2012 the V8 project authors. All rights reserved. 1 // Copyright 2012 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 115 matching lines...) Expand 10 before | Expand all | Expand 10 after
126 126
127 static void EmitIdenticalObjectComparison(MacroAssembler* masm, 127 static void EmitIdenticalObjectComparison(MacroAssembler* masm,
128 Label* slow, 128 Label* slow,
129 Condition cond); 129 Condition cond);
130 static void EmitSmiNonsmiComparison(MacroAssembler* masm, 130 static void EmitSmiNonsmiComparison(MacroAssembler* masm,
131 Register lhs, 131 Register lhs,
132 Register rhs, 132 Register rhs,
133 Label* lhs_not_nan, 133 Label* lhs_not_nan,
134 Label* slow, 134 Label* slow,
135 bool strict); 135 bool strict);
136 static void EmitTwoNonNanDoubleComparison(MacroAssembler* masm, Condition cond);
137 static void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm, 136 static void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm,
138 Register lhs, 137 Register lhs,
139 Register rhs); 138 Register rhs);
140 139
141 140
142 // Check if the operand is a heap number. 141 // Check if the operand is a heap number.
143 static void EmitCheckForHeapNumber(MacroAssembler* masm, Register operand, 142 static void EmitCheckForHeapNumber(MacroAssembler* masm, Register operand,
144 Register scratch1, Register scratch2, 143 Register scratch1, Register scratch2,
145 Label* not_a_heap_number) { 144 Label* not_a_heap_number) {
146 __ ldr(scratch1, FieldMemOperand(operand, HeapObject::kMapOffset)); 145 __ ldr(scratch1, FieldMemOperand(operand, HeapObject::kMapOffset));
(...skipping 496 matching lines...) Expand 10 before | Expand all | Expand 10 after
643 exponent, 642 exponent,
644 Operand(source_, LSR, 32 - HeapNumber::kMantissaBitsInTopWord)); 643 Operand(source_, LSR, 32 - HeapNumber::kMantissaBitsInTopWord));
645 __ Ret(); 644 __ Ret();
646 } 645 }
647 646
648 647
649 void FloatingPointHelper::LoadSmis(MacroAssembler* masm, 648 void FloatingPointHelper::LoadSmis(MacroAssembler* masm,
650 FloatingPointHelper::Destination destination, 649 FloatingPointHelper::Destination destination,
651 Register scratch1, 650 Register scratch1,
652 Register scratch2) { 651 Register scratch2) {
653 if (CpuFeatures::IsSupported(VFP2)) { 652 __ mov(scratch1, Operand(r0, ASR, kSmiTagSize));
654 CpuFeatureScope scope(masm, VFP2); 653 __ vmov(d7.high(), scratch1);
655 __ mov(scratch1, Operand(r0, ASR, kSmiTagSize)); 654 __ vcvt_f64_s32(d7, d7.high());
656 __ vmov(d7.high(), scratch1); 655 __ mov(scratch1, Operand(r1, ASR, kSmiTagSize));
657 __ vcvt_f64_s32(d7, d7.high()); 656 __ vmov(d6.high(), scratch1);
658 __ mov(scratch1, Operand(r1, ASR, kSmiTagSize)); 657 __ vcvt_f64_s32(d6, d6.high());
659 __ vmov(d6.high(), scratch1); 658 if (destination == kCoreRegisters) {
660 __ vcvt_f64_s32(d6, d6.high()); 659 __ vmov(r2, r3, d7);
661 if (destination == kCoreRegisters) { 660 __ vmov(r0, r1, d6);
662 __ vmov(r2, r3, d7);
663 __ vmov(r0, r1, d6);
664 }
665 } else {
666 ASSERT(destination == kCoreRegisters);
667 // Write Smi from r0 to r3 and r2 in double format.
668 __ mov(scratch1, Operand(r0));
669 ConvertToDoubleStub stub1(r3, r2, scratch1, scratch2);
670 __ push(lr);
671 __ Call(stub1.GetCode(masm->isolate()));
672 // Write Smi from r1 to r1 and r0 in double format.
673 __ mov(scratch1, Operand(r1));
674 ConvertToDoubleStub stub2(r1, r0, scratch1, scratch2);
675 __ Call(stub2.GetCode(masm->isolate()));
676 __ pop(lr);
677 } 661 }
678 } 662 }
679 663
680 664
681 void FloatingPointHelper::LoadNumber(MacroAssembler* masm, 665 void FloatingPointHelper::LoadNumber(MacroAssembler* masm,
682 Destination destination, 666 Destination destination,
683 Register object, 667 Register object,
684 DwVfpRegister dst, 668 DwVfpRegister dst,
685 Register dst1, 669 Register dst1,
686 Register dst2, 670 Register dst2,
687 Register heap_number_map, 671 Register heap_number_map,
688 Register scratch1, 672 Register scratch1,
689 Register scratch2, 673 Register scratch2,
690 Label* not_number) { 674 Label* not_number) {
691 __ AssertRootValue(heap_number_map, 675 __ AssertRootValue(heap_number_map,
692 Heap::kHeapNumberMapRootIndex, 676 Heap::kHeapNumberMapRootIndex,
693 "HeapNumberMap register clobbered."); 677 "HeapNumberMap register clobbered.");
694 678
695 Label is_smi, done; 679 Label is_smi, done;
696 680
697 // Smi-check 681 // Smi-check
698 __ UntagAndJumpIfSmi(scratch1, object, &is_smi); 682 __ UntagAndJumpIfSmi(scratch1, object, &is_smi);
699 // Heap number check 683 // Heap number check
700 __ JumpIfNotHeapNumber(object, heap_number_map, scratch1, not_number); 684 __ JumpIfNotHeapNumber(object, heap_number_map, scratch1, not_number);
701 685
702 // Handle loading a double from a heap number. 686 // Handle loading a double from a heap number.
703 if (CpuFeatures::IsSupported(VFP2) && 687 if (destination == kVFPRegisters) {
704 destination == kVFPRegisters) {
705 CpuFeatureScope scope(masm, VFP2);
706 // Load the double from tagged HeapNumber to double register. 688 // Load the double from tagged HeapNumber to double register.
707 __ sub(scratch1, object, Operand(kHeapObjectTag)); 689 __ sub(scratch1, object, Operand(kHeapObjectTag));
708 __ vldr(dst, scratch1, HeapNumber::kValueOffset); 690 __ vldr(dst, scratch1, HeapNumber::kValueOffset);
709 } else { 691 } else {
710 ASSERT(destination == kCoreRegisters); 692 ASSERT(destination == kCoreRegisters);
711 // Load the double from heap number to dst1 and dst2 in double format. 693 // Load the double from heap number to dst1 and dst2 in double format.
712 __ Ldrd(dst1, dst2, FieldMemOperand(object, HeapNumber::kValueOffset)); 694 __ Ldrd(dst1, dst2, FieldMemOperand(object, HeapNumber::kValueOffset));
713 } 695 }
714 __ jmp(&done); 696 __ jmp(&done);
715 697
716 // Handle loading a double from a smi. 698 // Handle loading a double from a smi.
717 __ bind(&is_smi); 699 __ bind(&is_smi);
718 if (CpuFeatures::IsSupported(VFP2)) { 700 // Convert smi to double using VFP instructions.
719 CpuFeatureScope scope(masm, VFP2); 701 __ vmov(dst.high(), scratch1);
720 // Convert smi to double using VFP instructions. 702 __ vcvt_f64_s32(dst, dst.high());
721 __ vmov(dst.high(), scratch1); 703 if (destination == kCoreRegisters) {
722 __ vcvt_f64_s32(dst, dst.high()); 704 // Load the converted smi to dst1 and dst2 in double format.
723 if (destination == kCoreRegisters) { 705 __ vmov(dst1, dst2, dst);
724 // Load the converted smi to dst1 and dst2 in double format.
725 __ vmov(dst1, dst2, dst);
726 }
727 } else {
728 ASSERT(destination == kCoreRegisters);
729 // Write smi to dst1 and dst2 double format.
730 __ mov(scratch1, Operand(object));
731 ConvertToDoubleStub stub(dst2, dst1, scratch1, scratch2);
732 __ push(lr);
733 __ Call(stub.GetCode(masm->isolate()));
734 __ pop(lr);
735 } 706 }
736 707
737 __ bind(&done); 708 __ bind(&done);
738 } 709 }
739 710
740 711
741 void FloatingPointHelper::ConvertNumberToInt32(MacroAssembler* masm, 712 void FloatingPointHelper::ConvertNumberToInt32(MacroAssembler* masm,
742 Register object, 713 Register object,
743 Register dst, 714 Register dst,
744 Register heap_number_map, 715 Register heap_number_map,
(...skipping 26 matching lines...) Expand all
771 Register dst_mantissa, 742 Register dst_mantissa,
772 Register dst_exponent, 743 Register dst_exponent,
773 Register scratch2, 744 Register scratch2,
774 SwVfpRegister single_scratch) { 745 SwVfpRegister single_scratch) {
775 ASSERT(!int_scratch.is(scratch2)); 746 ASSERT(!int_scratch.is(scratch2));
776 ASSERT(!int_scratch.is(dst_mantissa)); 747 ASSERT(!int_scratch.is(dst_mantissa));
777 ASSERT(!int_scratch.is(dst_exponent)); 748 ASSERT(!int_scratch.is(dst_exponent));
778 749
779 Label done; 750 Label done;
780 751
781 if (CpuFeatures::IsSupported(VFP2)) { 752 __ vmov(single_scratch, int_scratch);
782 CpuFeatureScope scope(masm, VFP2); 753 __ vcvt_f64_s32(double_dst, single_scratch);
783 __ vmov(single_scratch, int_scratch); 754 if (destination == kCoreRegisters) {
784 __ vcvt_f64_s32(double_dst, single_scratch); 755 __ vmov(dst_mantissa, dst_exponent, double_dst);
785 if (destination == kCoreRegisters) {
786 __ vmov(dst_mantissa, dst_exponent, double_dst);
787 }
788 } else {
789 Label fewer_than_20_useful_bits;
790 // Expected output:
791 // | dst_exponent | dst_mantissa |
792 // | s | exp | mantissa |
793
794 // Check for zero.
795 __ cmp(int_scratch, Operand::Zero());
796 __ mov(dst_exponent, int_scratch);
797 __ mov(dst_mantissa, int_scratch);
798 __ b(eq, &done);
799
800 // Preload the sign of the value.
801 __ and_(dst_exponent, int_scratch, Operand(HeapNumber::kSignMask), SetCC);
802 // Get the absolute value of the object (as an unsigned integer).
803 __ rsb(int_scratch, int_scratch, Operand::Zero(), SetCC, mi);
804
805 // Get mantissa[51:20].
806
807 // Get the position of the first set bit.
808 __ CountLeadingZeros(dst_mantissa, int_scratch, scratch2);
809 __ rsb(dst_mantissa, dst_mantissa, Operand(31));
810
811 // Set the exponent.
812 __ add(scratch2, dst_mantissa, Operand(HeapNumber::kExponentBias));
813 __ Bfi(dst_exponent, scratch2, scratch2,
814 HeapNumber::kExponentShift, HeapNumber::kExponentBits);
815
816 // Clear the first non null bit.
817 __ mov(scratch2, Operand(1));
818 __ bic(int_scratch, int_scratch, Operand(scratch2, LSL, dst_mantissa));
819
820 __ cmp(dst_mantissa, Operand(HeapNumber::kMantissaBitsInTopWord));
821 // Get the number of bits to set in the lower part of the mantissa.
822 __ sub(scratch2, dst_mantissa, Operand(HeapNumber::kMantissaBitsInTopWord),
823 SetCC);
824 __ b(mi, &fewer_than_20_useful_bits);
825 // Set the higher 20 bits of the mantissa.
826 __ orr(dst_exponent, dst_exponent, Operand(int_scratch, LSR, scratch2));
827 __ rsb(scratch2, scratch2, Operand(32));
828 __ mov(dst_mantissa, Operand(int_scratch, LSL, scratch2));
829 __ b(&done);
830
831 __ bind(&fewer_than_20_useful_bits);
832 __ rsb(scratch2, dst_mantissa, Operand(HeapNumber::kMantissaBitsInTopWord));
833 __ mov(scratch2, Operand(int_scratch, LSL, scratch2));
834 __ orr(dst_exponent, dst_exponent, scratch2);
835 // Set dst1 to 0.
836 __ mov(dst_mantissa, Operand::Zero());
837 } 756 }
838 __ bind(&done); 757 __ bind(&done);
839 } 758 }
840 759
841 760
842 void FloatingPointHelper::LoadNumberAsInt32Double(MacroAssembler* masm, 761 void FloatingPointHelper::LoadNumberAsInt32Double(MacroAssembler* masm,
843 Register object, 762 Register object,
844 Destination destination, 763 Destination destination,
845 DwVfpRegister double_dst, 764 DwVfpRegister double_dst,
846 DwVfpRegister double_scratch, 765 DwVfpRegister double_scratch,
(...skipping 18 matching lines...) Expand all
865 dst_exponent, scratch2, single_scratch); 784 dst_exponent, scratch2, single_scratch);
866 __ b(&done); 785 __ b(&done);
867 786
868 __ bind(&obj_is_not_smi); 787 __ bind(&obj_is_not_smi);
869 __ AssertRootValue(heap_number_map, 788 __ AssertRootValue(heap_number_map,
870 Heap::kHeapNumberMapRootIndex, 789 Heap::kHeapNumberMapRootIndex,
871 "HeapNumberMap register clobbered."); 790 "HeapNumberMap register clobbered.");
872 __ JumpIfNotHeapNumber(object, heap_number_map, scratch1, not_int32); 791 __ JumpIfNotHeapNumber(object, heap_number_map, scratch1, not_int32);
873 792
874 // Load the number. 793 // Load the number.
875 if (CpuFeatures::IsSupported(VFP2)) { 794 // Load the double value.
876 CpuFeatureScope scope(masm, VFP2); 795 __ sub(scratch1, object, Operand(kHeapObjectTag));
877 // Load the double value. 796 __ vldr(double_dst, scratch1, HeapNumber::kValueOffset);
878 __ sub(scratch1, object, Operand(kHeapObjectTag));
879 __ vldr(double_dst, scratch1, HeapNumber::kValueOffset);
880 797
881 __ TestDoubleIsInt32(double_dst, double_scratch); 798 __ TestDoubleIsInt32(double_dst, double_scratch);
882 // Jump to not_int32 if the operation did not succeed. 799 // Jump to not_int32 if the operation did not succeed.
883 __ b(ne, not_int32); 800 __ b(ne, not_int32);
884 801
885 if (destination == kCoreRegisters) { 802 if (destination == kCoreRegisters) {
886 __ vmov(dst_mantissa, dst_exponent, double_dst); 803 __ vmov(dst_mantissa, dst_exponent, double_dst);
887 }
888
889 } else {
890 ASSERT(!scratch1.is(object) && !scratch2.is(object));
891 // Load the double value in the destination registers.
892 bool save_registers = object.is(dst_mantissa) || object.is(dst_exponent);
893 if (save_registers) {
894 // Save both output registers, because the other one probably holds
895 // an important value too.
896 __ Push(dst_exponent, dst_mantissa);
897 }
898 __ Ldrd(dst_mantissa, dst_exponent,
899 FieldMemOperand(object, HeapNumber::kValueOffset));
900
901 // Check for 0 and -0.
902 Label zero;
903 __ bic(scratch1, dst_exponent, Operand(HeapNumber::kSignMask));
904 __ orr(scratch1, scratch1, Operand(dst_mantissa));
905 __ cmp(scratch1, Operand::Zero());
906 __ b(eq, &zero);
907
908 // Check that the value can be exactly represented by a 32-bit integer.
909 // Jump to not_int32 if that's not the case.
910 Label restore_input_and_miss;
911 DoubleIs32BitInteger(masm, dst_exponent, dst_mantissa, scratch1, scratch2,
912 &restore_input_and_miss);
913
914 // dst_* were trashed. Reload the double value.
915 if (save_registers) {
916 __ Pop(dst_exponent, dst_mantissa);
917 }
918 __ Ldrd(dst_mantissa, dst_exponent,
919 FieldMemOperand(object, HeapNumber::kValueOffset));
920 __ b(&done);
921
922 __ bind(&restore_input_and_miss);
923 if (save_registers) {
924 __ Pop(dst_exponent, dst_mantissa);
925 }
926 __ b(not_int32);
927
928 __ bind(&zero);
929 if (save_registers) {
930 __ Drop(2);
931 }
932 } 804 }
933
934 __ bind(&done); 805 __ bind(&done);
935 } 806 }
936 807
937 808
938 void FloatingPointHelper::LoadNumberAsInt32(MacroAssembler* masm, 809 void FloatingPointHelper::LoadNumberAsInt32(MacroAssembler* masm,
939 Register object, 810 Register object,
940 Register dst, 811 Register dst,
941 Register heap_number_map, 812 Register heap_number_map,
942 Register scratch1, 813 Register scratch1,
943 Register scratch2, 814 Register scratch2,
(...skipping 12 matching lines...) Expand all
956 __ UntagAndJumpIfSmi(dst, object, &done); 827 __ UntagAndJumpIfSmi(dst, object, &done);
957 828
958 __ AssertRootValue(heap_number_map, 829 __ AssertRootValue(heap_number_map,
959 Heap::kHeapNumberMapRootIndex, 830 Heap::kHeapNumberMapRootIndex,
960 "HeapNumberMap register clobbered."); 831 "HeapNumberMap register clobbered.");
961 832
962 __ JumpIfNotHeapNumber(object, heap_number_map, scratch1, &maybe_undefined); 833 __ JumpIfNotHeapNumber(object, heap_number_map, scratch1, &maybe_undefined);
963 834
964 // Object is a heap number. 835 // Object is a heap number.
965 // Convert the floating point value to a 32-bit integer. 836 // Convert the floating point value to a 32-bit integer.
966 if (CpuFeatures::IsSupported(VFP2)) { 837 // Load the double value.
967 CpuFeatureScope scope(masm, VFP2); 838 __ sub(scratch1, object, Operand(kHeapObjectTag));
839 __ vldr(double_scratch0, scratch1, HeapNumber::kValueOffset);
968 840
969 // Load the double value. 841 __ TryDoubleToInt32Exact(dst, double_scratch0, double_scratch1);
970 __ sub(scratch1, object, Operand(kHeapObjectTag)); 842 // Jump to not_int32 if the operation did not succeed.
971 __ vldr(double_scratch0, scratch1, HeapNumber::kValueOffset); 843 __ b(ne, not_int32);
972
973 __ TryDoubleToInt32Exact(dst, double_scratch0, double_scratch1);
974 // Jump to not_int32 if the operation did not succeed.
975 __ b(ne, not_int32);
976 } else {
977 // Load the double value in the destination registers.
978 __ ldr(scratch1, FieldMemOperand(object, HeapNumber::kExponentOffset));
979 __ ldr(scratch2, FieldMemOperand(object, HeapNumber::kMantissaOffset));
980
981 // Check for 0 and -0.
982 __ bic(dst, scratch1, Operand(HeapNumber::kSignMask));
983 __ orr(dst, scratch2, Operand(dst));
984 __ cmp(dst, Operand::Zero());
985 __ b(eq, &done);
986
987 DoubleIs32BitInteger(masm, scratch1, scratch2, dst, scratch3, not_int32);
988
989 // Registers state after DoubleIs32BitInteger.
990 // dst: mantissa[51:20].
991 // scratch2: 1
992
993 // Shift back the higher bits of the mantissa.
994 __ mov(dst, Operand(dst, LSR, scratch3));
995 // Set the implicit first bit.
996 __ rsb(scratch3, scratch3, Operand(32));
997 __ orr(dst, dst, Operand(scratch2, LSL, scratch3));
998 // Set the sign.
999 __ ldr(scratch1, FieldMemOperand(object, HeapNumber::kExponentOffset));
1000 __ tst(scratch1, Operand(HeapNumber::kSignMask));
1001 __ rsb(dst, dst, Operand::Zero(), LeaveCC, mi);
1002 }
1003 __ b(&done); 844 __ b(&done);
1004 845
1005 __ bind(&maybe_undefined); 846 __ bind(&maybe_undefined);
1006 __ CompareRoot(object, Heap::kUndefinedValueRootIndex); 847 __ CompareRoot(object, Heap::kUndefinedValueRootIndex);
1007 __ b(ne, not_int32); 848 __ b(ne, not_int32);
1008 // |undefined| is truncated to 0. 849 // |undefined| is truncated to 0.
1009 __ mov(dst, Operand(Smi::FromInt(0))); 850 __ mov(dst, Operand(Smi::FromInt(0)));
1010 // Fall through. 851 // Fall through.
1011 852
1012 __ bind(&done); 853 __ bind(&done);
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
1086 927
1087 // Assert that heap_number_result is callee-saved. 928 // Assert that heap_number_result is callee-saved.
1088 // We currently always use r5 to pass it. 929 // We currently always use r5 to pass it.
1089 ASSERT(heap_number_result.is(r5)); 930 ASSERT(heap_number_result.is(r5));
1090 931
1091 // Push the current return address before the C call. Return will be 932 // Push the current return address before the C call. Return will be
1092 // through pop(pc) below. 933 // through pop(pc) below.
1093 __ push(lr); 934 __ push(lr);
1094 __ PrepareCallCFunction(0, 2, scratch); 935 __ PrepareCallCFunction(0, 2, scratch);
1095 if (masm->use_eabi_hardfloat()) { 936 if (masm->use_eabi_hardfloat()) {
1096 CpuFeatureScope scope(masm, VFP2);
1097 __ vmov(d0, r0, r1); 937 __ vmov(d0, r0, r1);
1098 __ vmov(d1, r2, r3); 938 __ vmov(d1, r2, r3);
1099 } 939 }
1100 { 940 {
1101 AllowExternalCallThatCantCauseGC scope(masm); 941 AllowExternalCallThatCantCauseGC scope(masm);
1102 __ CallCFunction( 942 __ CallCFunction(
1103 ExternalReference::double_fp_operation(op, masm->isolate()), 0, 2); 943 ExternalReference::double_fp_operation(op, masm->isolate()), 0, 2);
1104 } 944 }
1105 // Store answer in the overwritable heap number. Double returned in 945 // Store answer in the overwritable heap number. Double returned in
1106 // registers r0 and r1 or in d0. 946 // registers r0 and r1 or in d0.
1107 if (masm->use_eabi_hardfloat()) { 947 if (masm->use_eabi_hardfloat()) {
1108 CpuFeatureScope scope(masm, VFP2);
1109 __ vstr(d0, 948 __ vstr(d0,
1110 FieldMemOperand(heap_number_result, HeapNumber::kValueOffset)); 949 FieldMemOperand(heap_number_result, HeapNumber::kValueOffset));
1111 } else { 950 } else {
1112 __ Strd(r0, r1, FieldMemOperand(heap_number_result, 951 __ Strd(r0, r1, FieldMemOperand(heap_number_result,
1113 HeapNumber::kValueOffset)); 952 HeapNumber::kValueOffset));
1114 } 953 }
1115 // Place heap_number_result in r0 and return to the pushed return address. 954 // Place heap_number_result in r0 and return to the pushed return address.
1116 __ mov(r0, Operand(heap_number_result)); 955 __ mov(r0, Operand(heap_number_result));
1117 __ pop(pc); 956 __ pop(pc);
1118 } 957 }
(...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after
1311 __ mov(r0, Operand(NOT_EQUAL), LeaveCC, ne); 1150 __ mov(r0, Operand(NOT_EQUAL), LeaveCC, ne);
1312 } 1151 }
1313 __ Ret(ne); 1152 __ Ret(ne);
1314 } else { 1153 } else {
1315 // Smi compared non-strictly with a non-Smi non-heap-number. Call 1154 // Smi compared non-strictly with a non-Smi non-heap-number. Call
1316 // the runtime. 1155 // the runtime.
1317 __ b(ne, slow); 1156 __ b(ne, slow);
1318 } 1157 }
1319 1158
1320 // Lhs is a smi, rhs is a number. 1159 // Lhs is a smi, rhs is a number.
1321 if (CpuFeatures::IsSupported(VFP2)) { 1160 // Convert lhs to a double in d7.
1322 // Convert lhs to a double in d7. 1161 __ SmiToDoubleVFPRegister(lhs, d7, r7, s15);
1323 CpuFeatureScope scope(masm, VFP2); 1162 // Load the double from rhs, tagged HeapNumber r0, to d6.
1324 __ SmiToDoubleVFPRegister(lhs, d7, r7, s15); 1163 __ sub(r7, rhs, Operand(kHeapObjectTag));
1325 // Load the double from rhs, tagged HeapNumber r0, to d6. 1164 __ vldr(d6, r7, HeapNumber::kValueOffset);
1326 __ sub(r7, rhs, Operand(kHeapObjectTag));
1327 __ vldr(d6, r7, HeapNumber::kValueOffset);
1328 } else {
1329 __ push(lr);
1330 // Convert lhs to a double in r2, r3.
1331 __ mov(r7, Operand(lhs));
1332 ConvertToDoubleStub stub1(r3, r2, r7, r6);
1333 __ Call(stub1.GetCode(masm->isolate()));
1334 // Load rhs to a double in r0, r1.
1335 __ Ldrd(r0, r1, FieldMemOperand(rhs, HeapNumber::kValueOffset));
1336 __ pop(lr);
1337 }
1338 1165
1339 // We now have both loaded as doubles but we can skip the lhs nan check 1166 // We now have both loaded as doubles but we can skip the lhs nan check
1340 // since it's a smi. 1167 // since it's a smi.
1341 __ jmp(lhs_not_nan); 1168 __ jmp(lhs_not_nan);
1342 1169
1343 __ bind(&rhs_is_smi); 1170 __ bind(&rhs_is_smi);
1344 // Rhs is a smi. Check whether the non-smi lhs is a heap number. 1171 // Rhs is a smi. Check whether the non-smi lhs is a heap number.
1345 __ CompareObjectType(lhs, r4, r4, HEAP_NUMBER_TYPE); 1172 __ CompareObjectType(lhs, r4, r4, HEAP_NUMBER_TYPE);
1346 if (strict) { 1173 if (strict) {
1347 // If lhs is not a number and rhs is a smi then strict equality cannot 1174 // If lhs is not a number and rhs is a smi then strict equality cannot
1348 // succeed. Return non-equal. 1175 // succeed. Return non-equal.
1349 // If lhs is r0 then there is already a non zero value in it. 1176 // If lhs is r0 then there is already a non zero value in it.
1350 if (!lhs.is(r0)) { 1177 if (!lhs.is(r0)) {
1351 __ mov(r0, Operand(NOT_EQUAL), LeaveCC, ne); 1178 __ mov(r0, Operand(NOT_EQUAL), LeaveCC, ne);
1352 } 1179 }
1353 __ Ret(ne); 1180 __ Ret(ne);
1354 } else { 1181 } else {
1355 // Smi compared non-strictly with a non-smi non-heap-number. Call 1182 // Smi compared non-strictly with a non-smi non-heap-number. Call
1356 // the runtime. 1183 // the runtime.
1357 __ b(ne, slow); 1184 __ b(ne, slow);
1358 } 1185 }
1359 1186
1360 // Rhs is a smi, lhs is a heap number. 1187 // Rhs is a smi, lhs is a heap number.
1361 if (CpuFeatures::IsSupported(VFP2)) { 1188 // Load the double from lhs, tagged HeapNumber r1, to d7.
1362 CpuFeatureScope scope(masm, VFP2); 1189 __ sub(r7, lhs, Operand(kHeapObjectTag));
1363 // Load the double from lhs, tagged HeapNumber r1, to d7. 1190 __ vldr(d7, r7, HeapNumber::kValueOffset);
1364 __ sub(r7, lhs, Operand(kHeapObjectTag)); 1191 // Convert rhs to a double in d6 .
1365 __ vldr(d7, r7, HeapNumber::kValueOffset); 1192 __ SmiToDoubleVFPRegister(rhs, d6, r7, s13);
1366 // Convert rhs to a double in d6 .
1367 __ SmiToDoubleVFPRegister(rhs, d6, r7, s13);
1368 } else {
1369 __ push(lr);
1370 // Load lhs to a double in r2, r3.
1371 __ Ldrd(r2, r3, FieldMemOperand(lhs, HeapNumber::kValueOffset));
1372 // Convert rhs to a double in r0, r1.
1373 __ mov(r7, Operand(rhs));
1374 ConvertToDoubleStub stub2(r1, r0, r7, r6);
1375 __ Call(stub2.GetCode(masm->isolate()));
1376 __ pop(lr);
1377 }
1378 // Fall through to both_loaded_as_doubles. 1193 // Fall through to both_loaded_as_doubles.
1379 } 1194 }
1380 1195
1381 1196
1382 void EmitNanCheck(MacroAssembler* masm, Label* lhs_not_nan, Condition cond) { 1197 void EmitNanCheck(MacroAssembler* masm, Label* lhs_not_nan, Condition cond) {
1383 bool exp_first = (HeapNumber::kExponentOffset == HeapNumber::kValueOffset); 1198 bool exp_first = (HeapNumber::kExponentOffset == HeapNumber::kValueOffset);
1384 Register rhs_exponent = exp_first ? r0 : r1; 1199 Register rhs_exponent = exp_first ? r0 : r1;
1385 Register lhs_exponent = exp_first ? r2 : r3; 1200 Register lhs_exponent = exp_first ? r2 : r3;
1386 Register rhs_mantissa = exp_first ? r1 : r0; 1201 Register rhs_mantissa = exp_first ? r1 : r0;
1387 Register lhs_mantissa = exp_first ? r3 : r2; 1202 Register lhs_mantissa = exp_first ? r3 : r2;
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
1424 } else { 1239 } else {
1425 __ mov(r0, Operand(LESS)); 1240 __ mov(r0, Operand(LESS));
1426 } 1241 }
1427 __ Ret(); 1242 __ Ret();
1428 1243
1429 __ bind(&neither_is_nan); 1244 __ bind(&neither_is_nan);
1430 } 1245 }
1431 1246
1432 1247
1433 // See comment at call site. 1248 // See comment at call site.
1434 static void EmitTwoNonNanDoubleComparison(MacroAssembler* masm,
1435 Condition cond) {
1436 bool exp_first = (HeapNumber::kExponentOffset == HeapNumber::kValueOffset);
1437 Register rhs_exponent = exp_first ? r0 : r1;
1438 Register lhs_exponent = exp_first ? r2 : r3;
1439 Register rhs_mantissa = exp_first ? r1 : r0;
1440 Register lhs_mantissa = exp_first ? r3 : r2;
1441
1442 // r0, r1, r2, r3 have the two doubles. Neither is a NaN.
1443 if (cond == eq) {
1444 // Doubles are not equal unless they have the same bit pattern.
1445 // Exception: 0 and -0.
1446 __ cmp(rhs_mantissa, Operand(lhs_mantissa));
1447 __ orr(r0, rhs_mantissa, Operand(lhs_mantissa), LeaveCC, ne);
1448 // Return non-zero if the numbers are unequal.
1449 __ Ret(ne);
1450
1451 __ sub(r0, rhs_exponent, Operand(lhs_exponent), SetCC);
1452 // If exponents are equal then return 0.
1453 __ Ret(eq);
1454
1455 // Exponents are unequal. The only way we can return that the numbers
1456 // are equal is if one is -0 and the other is 0. We already dealt
1457 // with the case where both are -0 or both are 0.
1458 // We start by seeing if the mantissas (that are equal) or the bottom
1459 // 31 bits of the rhs exponent are non-zero. If so we return not
1460 // equal.
1461 __ orr(r4, lhs_mantissa, Operand(lhs_exponent, LSL, kSmiTagSize), SetCC);
1462 __ mov(r0, Operand(r4), LeaveCC, ne);
1463 __ Ret(ne);
1464 // Now they are equal if and only if the lhs exponent is zero in its
1465 // low 31 bits.
1466 __ mov(r0, Operand(rhs_exponent, LSL, kSmiTagSize));
1467 __ Ret();
1468 } else {
1469 // Call a native function to do a comparison between two non-NaNs.
1470 // Call C routine that may not cause GC or other trouble.
1471 __ push(lr);
1472 __ PrepareCallCFunction(0, 2, r5);
1473 if (masm->use_eabi_hardfloat()) {
1474 CpuFeatureScope scope(masm, VFP2);
1475 __ vmov(d0, r0, r1);
1476 __ vmov(d1, r2, r3);
1477 }
1478
1479 AllowExternalCallThatCantCauseGC scope(masm);
1480 __ CallCFunction(ExternalReference::compare_doubles(masm->isolate()),
1481 0, 2);
1482 __ pop(pc); // Return.
1483 }
1484 }
1485
1486
1487 // See comment at call site.
1488 static void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm, 1249 static void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm,
1489 Register lhs, 1250 Register lhs,
1490 Register rhs) { 1251 Register rhs) {
1491 ASSERT((lhs.is(r0) && rhs.is(r1)) || 1252 ASSERT((lhs.is(r0) && rhs.is(r1)) ||
1492 (lhs.is(r1) && rhs.is(r0))); 1253 (lhs.is(r1) && rhs.is(r0)));
1493 1254
1494 // If either operand is a JS object or an oddball value, then they are 1255 // If either operand is a JS object or an oddball value, then they are
1495 // not equal since their pointers are different. 1256 // not equal since their pointers are different.
1496 // There is no test for undetectability in strict equality. 1257 // There is no test for undetectability in strict equality.
1497 STATIC_ASSERT(LAST_TYPE == LAST_SPEC_OBJECT_TYPE); 1258 STATIC_ASSERT(LAST_TYPE == LAST_SPEC_OBJECT_TYPE);
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
1540 (lhs.is(r1) && rhs.is(r0))); 1301 (lhs.is(r1) && rhs.is(r0)));
1541 1302
1542 __ CompareObjectType(rhs, r3, r2, HEAP_NUMBER_TYPE); 1303 __ CompareObjectType(rhs, r3, r2, HEAP_NUMBER_TYPE);
1543 __ b(ne, not_heap_numbers); 1304 __ b(ne, not_heap_numbers);
1544 __ ldr(r2, FieldMemOperand(lhs, HeapObject::kMapOffset)); 1305 __ ldr(r2, FieldMemOperand(lhs, HeapObject::kMapOffset));
1545 __ cmp(r2, r3); 1306 __ cmp(r2, r3);
1546 __ b(ne, slow); // First was a heap number, second wasn't. Go slow case. 1307 __ b(ne, slow); // First was a heap number, second wasn't. Go slow case.
1547 1308
1548 // Both are heap numbers. Load them up then jump to the code we have 1309 // Both are heap numbers. Load them up then jump to the code we have
1549 // for that. 1310 // for that.
1550 if (CpuFeatures::IsSupported(VFP2)) { 1311 __ sub(r7, rhs, Operand(kHeapObjectTag));
1551 CpuFeatureScope scope(masm, VFP2); 1312 __ vldr(d6, r7, HeapNumber::kValueOffset);
1552 __ sub(r7, rhs, Operand(kHeapObjectTag)); 1313 __ sub(r7, lhs, Operand(kHeapObjectTag));
1553 __ vldr(d6, r7, HeapNumber::kValueOffset); 1314 __ vldr(d7, r7, HeapNumber::kValueOffset);
1554 __ sub(r7, lhs, Operand(kHeapObjectTag));
1555 __ vldr(d7, r7, HeapNumber::kValueOffset);
1556 } else {
1557 __ Ldrd(r2, r3, FieldMemOperand(lhs, HeapNumber::kValueOffset));
1558 __ Ldrd(r0, r1, FieldMemOperand(rhs, HeapNumber::kValueOffset));
1559 }
1560 __ jmp(both_loaded_as_doubles); 1315 __ jmp(both_loaded_as_doubles);
1561 } 1316 }
1562 1317
1563 1318
1564 // Fast negative check for internalized-to-internalized equality. 1319 // Fast negative check for internalized-to-internalized equality.
1565 static void EmitCheckForInternalizedStringsOrObjects(MacroAssembler* masm, 1320 static void EmitCheckForInternalizedStringsOrObjects(MacroAssembler* masm,
1566 Register lhs, 1321 Register lhs,
1567 Register rhs, 1322 Register rhs,
1568 Label* possible_strings, 1323 Label* possible_strings,
1569 Label* not_both_strings) { 1324 Label* not_both_strings) {
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
1630 1385
1631 // Calculate the entry in the number string cache. The hash value in the 1386 // Calculate the entry in the number string cache. The hash value in the
1632 // number string cache for smis is just the smi value, and the hash for 1387 // number string cache for smis is just the smi value, and the hash for
1633 // doubles is the xor of the upper and lower words. See 1388 // doubles is the xor of the upper and lower words. See
1634 // Heap::GetNumberStringCache. 1389 // Heap::GetNumberStringCache.
1635 Isolate* isolate = masm->isolate(); 1390 Isolate* isolate = masm->isolate();
1636 Label is_smi; 1391 Label is_smi;
1637 Label load_result_from_cache; 1392 Label load_result_from_cache;
1638 if (!object_is_smi) { 1393 if (!object_is_smi) {
1639 __ JumpIfSmi(object, &is_smi); 1394 __ JumpIfSmi(object, &is_smi);
1640 if (CpuFeatures::IsSupported(VFP2)) { 1395 __ CheckMap(object,
1641 CpuFeatureScope scope(masm, VFP2); 1396 scratch1,
1642 __ CheckMap(object, 1397 Heap::kHeapNumberMapRootIndex,
1643 scratch1, 1398 not_found,
1644 Heap::kHeapNumberMapRootIndex, 1399 DONT_DO_SMI_CHECK);
1645 not_found,
1646 DONT_DO_SMI_CHECK);
1647 1400
1648 STATIC_ASSERT(8 == kDoubleSize); 1401 STATIC_ASSERT(8 == kDoubleSize);
1649 __ add(scratch1, 1402 __ add(scratch1,
1650 object, 1403 object,
1651 Operand(HeapNumber::kValueOffset - kHeapObjectTag)); 1404 Operand(HeapNumber::kValueOffset - kHeapObjectTag));
1652 __ ldm(ia, scratch1, scratch1.bit() | scratch2.bit()); 1405 __ ldm(ia, scratch1, scratch1.bit() | scratch2.bit());
1653 __ eor(scratch1, scratch1, Operand(scratch2)); 1406 __ eor(scratch1, scratch1, Operand(scratch2));
1654 __ and_(scratch1, scratch1, Operand(mask)); 1407 __ and_(scratch1, scratch1, Operand(mask));
1655 1408
1656 // Calculate address of entry in string cache: each entry consists 1409 // Calculate address of entry in string cache: each entry consists
1657 // of two pointer sized fields. 1410 // of two pointer sized fields.
1658 __ add(scratch1, 1411 __ add(scratch1,
1659 number_string_cache, 1412 number_string_cache,
1660 Operand(scratch1, LSL, kPointerSizeLog2 + 1)); 1413 Operand(scratch1, LSL, kPointerSizeLog2 + 1));
1661 1414
1662 Register probe = mask; 1415 Register probe = mask;
1663 __ ldr(probe, 1416 __ ldr(probe,
1664 FieldMemOperand(scratch1, FixedArray::kHeaderSize)); 1417 FieldMemOperand(scratch1, FixedArray::kHeaderSize));
1665 __ JumpIfSmi(probe, not_found); 1418 __ JumpIfSmi(probe, not_found);
1666 __ sub(scratch2, object, Operand(kHeapObjectTag)); 1419 __ sub(scratch2, object, Operand(kHeapObjectTag));
1667 __ vldr(d0, scratch2, HeapNumber::kValueOffset); 1420 __ vldr(d0, scratch2, HeapNumber::kValueOffset);
1668 __ sub(probe, probe, Operand(kHeapObjectTag)); 1421 __ sub(probe, probe, Operand(kHeapObjectTag));
1669 __ vldr(d1, probe, HeapNumber::kValueOffset); 1422 __ vldr(d1, probe, HeapNumber::kValueOffset);
1670 __ VFPCompareAndSetFlags(d0, d1); 1423 __ VFPCompareAndSetFlags(d0, d1);
1671 __ b(ne, not_found); // The cache did not contain this value. 1424 __ b(ne, not_found); // The cache did not contain this value.
1672 __ b(&load_result_from_cache); 1425 __ b(&load_result_from_cache);
1673 } else { 1426 } else {
Rodolph Perfetta 2013/04/04 15:30:04 This was the else from CpuFeatures::IsSupported(VF
danno 2013/04/08 19:45:33 Done.
1674 __ b(not_found); 1427 __ b(not_found);
1675 }
1676 } 1428 }
1677 1429
1678 __ bind(&is_smi); 1430 __ bind(&is_smi);
1679 Register scratch = scratch1; 1431 Register scratch = scratch1;
1680 __ and_(scratch, mask, Operand(object, ASR, 1)); 1432 __ and_(scratch, mask, Operand(object, ASR, 1));
1681 // Calculate address of entry in string cache: each entry consists 1433 // Calculate address of entry in string cache: each entry consists
1682 // of two pointer sized fields. 1434 // of two pointer sized fields.
1683 __ add(scratch, 1435 __ add(scratch,
1684 number_string_cache, 1436 number_string_cache,
1685 Operand(scratch, LSL, kPointerSizeLog2 + 1)); 1437 Operand(scratch, LSL, kPointerSizeLog2 + 1));
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
1780 // In cases 3 and 4 we have found out we were dealing with a number-number 1532 // In cases 3 and 4 we have found out we were dealing with a number-number
1781 // comparison. If VFP3 is supported the double values of the numbers have 1533 // comparison. If VFP3 is supported the double values of the numbers have
1782 // been loaded into d7 and d6. Otherwise, the double values have been loaded 1534 // been loaded into d7 and d6. Otherwise, the double values have been loaded
1783 // into r0, r1, r2, and r3. 1535 // into r0, r1, r2, and r3.
1784 EmitSmiNonsmiComparison(masm, lhs, rhs, &lhs_not_nan, &slow, strict()); 1536 EmitSmiNonsmiComparison(masm, lhs, rhs, &lhs_not_nan, &slow, strict());
1785 1537
1786 __ bind(&both_loaded_as_doubles); 1538 __ bind(&both_loaded_as_doubles);
1787 // The arguments have been converted to doubles and stored in d6 and d7, if 1539 // The arguments have been converted to doubles and stored in d6 and d7, if
1788 // VFP3 is supported, or in r0, r1, r2, and r3. 1540 // VFP3 is supported, or in r0, r1, r2, and r3.
1789 Isolate* isolate = masm->isolate(); 1541 Isolate* isolate = masm->isolate();
1790 if (CpuFeatures::IsSupported(VFP2)) { 1542 __ bind(&lhs_not_nan);
1791 __ bind(&lhs_not_nan); 1543 Label no_nan;
1792 CpuFeatureScope scope(masm, VFP2); 1544 // ARMv7 VFP3 instructions to implement double precision comparison.
1793 Label no_nan; 1545 __ VFPCompareAndSetFlags(d7, d6);
1794 // ARMv7 VFP3 instructions to implement double precision comparison. 1546 Label nan;
1795 __ VFPCompareAndSetFlags(d7, d6); 1547 __ b(vs, &nan);
1796 Label nan; 1548 __ mov(r0, Operand(EQUAL), LeaveCC, eq);
1797 __ b(vs, &nan); 1549 __ mov(r0, Operand(LESS), LeaveCC, lt);
1798 __ mov(r0, Operand(EQUAL), LeaveCC, eq); 1550 __ mov(r0, Operand(GREATER), LeaveCC, gt);
1799 __ mov(r0, Operand(LESS), LeaveCC, lt); 1551 __ Ret();
1800 __ mov(r0, Operand(GREATER), LeaveCC, gt);
1801 __ Ret();
1802 1552
1803 __ bind(&nan); 1553 __ bind(&nan);
1804 // If one of the sides was a NaN then the v flag is set. Load r0 with 1554 // If one of the sides was a NaN then the v flag is set. Load r0 with
1805 // whatever it takes to make the comparison fail, since comparisons with NaN 1555 // whatever it takes to make the comparison fail, since comparisons with NaN
1806 // always fail. 1556 // always fail.
1807 if (cc == lt || cc == le) { 1557 if (cc == lt || cc == le) {
1808 __ mov(r0, Operand(GREATER)); 1558 __ mov(r0, Operand(GREATER));
1809 } else {
1810 __ mov(r0, Operand(LESS));
1811 }
1812 __ Ret();
1813 } else { 1559 } else {
1814 // Checks for NaN in the doubles we have loaded. Can return the answer or 1560 __ mov(r0, Operand(LESS));
1815 // fall through if neither is a NaN. Also binds lhs_not_nan.
1816 EmitNanCheck(masm, &lhs_not_nan, cc);
1817 // Compares two doubles in r0, r1, r2, r3 that are not NaNs. Returns the
1818 // answer. Never falls through.
1819 EmitTwoNonNanDoubleComparison(masm, cc);
1820 } 1561 }
1562 __ Ret();
1821 1563
1822 __ bind(&not_smis); 1564 __ bind(&not_smis);
1823 // At this point we know we are dealing with two different objects, 1565 // At this point we know we are dealing with two different objects,
1824 // and neither of them is a Smi. The objects are in rhs_ and lhs_. 1566 // and neither of them is a Smi. The objects are in rhs_ and lhs_.
1825 if (strict()) { 1567 if (strict()) {
1826 // This returns non-equal for some object types, or falls through if it 1568 // This returns non-equal for some object types, or falls through if it
1827 // was not lucky. 1569 // was not lucky.
1828 EmitStrictTwoHeapObjectCompare(masm, lhs, rhs); 1570 EmitStrictTwoHeapObjectCompare(masm, lhs, rhs);
1829 } 1571 }
1830 1572
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
1907 } 1649 }
1908 1650
1909 1651
1910 // The stub expects its argument in the tos_ register and returns its result in 1652 // The stub expects its argument in the tos_ register and returns its result in
1911 // it, too: zero for false, and a non-zero value for true. 1653 // it, too: zero for false, and a non-zero value for true.
1912 void ToBooleanStub::Generate(MacroAssembler* masm) { 1654 void ToBooleanStub::Generate(MacroAssembler* masm) {
1913 // This stub overrides SometimesSetsUpAFrame() to return false. That means 1655 // This stub overrides SometimesSetsUpAFrame() to return false. That means
1914 // we cannot call anything that could cause a GC from this stub. 1656 // we cannot call anything that could cause a GC from this stub.
1915 Label patch; 1657 Label patch;
1916 const Register map = r9.is(tos_) ? r7 : r9; 1658 const Register map = r9.is(tos_) ? r7 : r9;
1917 const Register temp = map;
1918 1659
1919 // undefined -> false. 1660 // undefined -> false.
1920 CheckOddball(masm, UNDEFINED, Heap::kUndefinedValueRootIndex, false); 1661 CheckOddball(masm, UNDEFINED, Heap::kUndefinedValueRootIndex, false);
1921 1662
1922 // Boolean -> its value. 1663 // Boolean -> its value.
1923 CheckOddball(masm, BOOLEAN, Heap::kFalseValueRootIndex, false); 1664 CheckOddball(masm, BOOLEAN, Heap::kFalseValueRootIndex, false);
1924 CheckOddball(masm, BOOLEAN, Heap::kTrueValueRootIndex, true); 1665 CheckOddball(masm, BOOLEAN, Heap::kTrueValueRootIndex, true);
1925 1666
1926 // 'null' -> false. 1667 // 'null' -> false.
1927 CheckOddball(masm, NULL_TYPE, Heap::kNullValueRootIndex, false); 1668 CheckOddball(masm, NULL_TYPE, Heap::kNullValueRootIndex, false);
(...skipping 22 matching lines...) Expand all
1950 1691
1951 if (types_.Contains(SPEC_OBJECT)) { 1692 if (types_.Contains(SPEC_OBJECT)) {
1952 // Spec object -> true. 1693 // Spec object -> true.
1953 __ CompareInstanceType(map, ip, FIRST_SPEC_OBJECT_TYPE); 1694 __ CompareInstanceType(map, ip, FIRST_SPEC_OBJECT_TYPE);
1954 // tos_ contains the correct non-zero return value already. 1695 // tos_ contains the correct non-zero return value already.
1955 __ Ret(ge); 1696 __ Ret(ge);
1956 } 1697 }
1957 1698
1958 if (types_.Contains(STRING)) { 1699 if (types_.Contains(STRING)) {
1959 // String value -> false iff empty. 1700 // String value -> false iff empty.
1960 __ CompareInstanceType(map, ip, FIRST_NONSTRING_TYPE); 1701 __ CompareInstanceType(map, ip, FIRST_NONSTRING_TYPE);
1961 __ ldr(tos_, FieldMemOperand(tos_, String::kLengthOffset), lt); 1702 __ ldr(tos_, FieldMemOperand(tos_, String::kLengthOffset), lt);
1962 __ Ret(lt); // the string length is OK as the return value 1703 __ Ret(lt); // the string length is OK as the return value
1963 } 1704 }
1964 1705
1965 if (types_.Contains(HEAP_NUMBER)) { 1706 if (types_.Contains(HEAP_NUMBER)) {
1966 // Heap number -> false iff +0, -0, or NaN. 1707 // Heap number -> false iff +0, -0, or NaN.
1967 Label not_heap_number; 1708 Label not_heap_number;
1968 __ CompareRoot(map, Heap::kHeapNumberMapRootIndex); 1709 __ CompareRoot(map, Heap::kHeapNumberMapRootIndex);
1969 __ b(ne, &not_heap_number); 1710 __ b(ne, &not_heap_number);
1970 1711
1971 if (CpuFeatures::IsSupported(VFP2)) { 1712 __ vldr(d1, FieldMemOperand(tos_, HeapNumber::kValueOffset));
1972 CpuFeatureScope scope(masm, VFP2); 1713 __ VFPCompareAndSetFlags(d1, 0.0);
1973 1714 // "tos_" is a register, and contains a non zero value by default.
1974 __ vldr(d1, FieldMemOperand(tos_, HeapNumber::kValueOffset)); 1715 // Hence we only need to overwrite "tos_" with zero to return false for
1975 __ VFPCompareAndSetFlags(d1, 0.0); 1716 // FP_ZERO or FP_NAN cases. Otherwise, by default it returns true.
1976 // "tos_" is a register, and contains a non zero value by default. 1717 __ mov(tos_, Operand::Zero(), LeaveCC, eq); // for FP_ZERO
1977 // Hence we only need to overwrite "tos_" with zero to return false for 1718 __ mov(tos_, Operand::Zero(), LeaveCC, vs); // for FP_NAN
1978 // FP_ZERO or FP_NAN cases. Otherwise, by default it returns true.
1979 __ mov(tos_, Operand::Zero(), LeaveCC, eq); // for FP_ZERO
1980 __ mov(tos_, Operand::Zero(), LeaveCC, vs); // for FP_NAN
1981 } else {
1982 Label done, not_nan, not_zero;
1983 __ ldr(temp, FieldMemOperand(tos_, HeapNumber::kExponentOffset));
1984 // -0 maps to false:
1985 __ bic(
1986 temp, temp, Operand(HeapNumber::kSignMask, RelocInfo::NONE32), SetCC);
1987 __ b(ne, &not_zero);
1988 // If exponent word is zero then the answer depends on the mantissa word.
1989 __ ldr(tos_, FieldMemOperand(tos_, HeapNumber::kMantissaOffset));
1990 __ jmp(&done);
1991
1992 // Check for NaN.
1993 __ bind(&not_zero);
1994 // We already zeroed the sign bit, now shift out the mantissa so we only
1995 // have the exponent left.
1996 __ mov(temp, Operand(temp, LSR, HeapNumber::kMantissaBitsInTopWord));
1997 unsigned int shifted_exponent_mask =
1998 HeapNumber::kExponentMask >> HeapNumber::kMantissaBitsInTopWord;
1999 __ cmp(temp, Operand(shifted_exponent_mask, RelocInfo::NONE32));
2000 __ b(ne, &not_nan); // If exponent is not 0x7ff then it can't be a NaN.
2001
2002 // Reload exponent word.
2003 __ ldr(temp, FieldMemOperand(tos_, HeapNumber::kExponentOffset));
2004 __ tst(temp, Operand(HeapNumber::kMantissaMask, RelocInfo::NONE32));
2005 // If mantissa is not zero then we have a NaN, so return 0.
2006 __ mov(tos_, Operand::Zero(), LeaveCC, ne);
2007 __ b(ne, &done);
2008
2009 // Load mantissa word.
2010 __ ldr(temp, FieldMemOperand(tos_, HeapNumber::kMantissaOffset));
2011 __ cmp(temp, Operand::Zero());
2012 // If mantissa is not zero then we have a NaN, so return 0.
2013 __ mov(tos_, Operand::Zero(), LeaveCC, ne);
2014 __ b(ne, &done);
2015
2016 __ bind(&not_nan);
2017 __ mov(tos_, Operand(1, RelocInfo::NONE32));
2018 __ bind(&done);
2019 }
2020 __ Ret(); 1719 __ Ret();
2021 __ bind(&not_heap_number); 1720 __ bind(&not_heap_number);
2022 } 1721 }
2023 1722
2024 __ bind(&patch); 1723 __ bind(&patch);
2025 GenerateTypeTransition(masm); 1724 GenerateTypeTransition(masm);
2026 } 1725 }
2027 1726
2028 1727
2029 void ToBooleanStub::CheckOddball(MacroAssembler* masm, 1728 void ToBooleanStub::CheckOddball(MacroAssembler* masm,
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
2062 1761
2063 void StoreBufferOverflowStub::Generate(MacroAssembler* masm) { 1762 void StoreBufferOverflowStub::Generate(MacroAssembler* masm) {
2064 // We don't allow a GC during a store buffer overflow so there is no need to 1763 // We don't allow a GC during a store buffer overflow so there is no need to
2065 // store the registers in any particular way, but we do have to store and 1764 // store the registers in any particular way, but we do have to store and
2066 // restore them. 1765 // restore them.
2067 __ stm(db_w, sp, kCallerSaved | lr.bit()); 1766 __ stm(db_w, sp, kCallerSaved | lr.bit());
2068 1767
2069 const Register scratch = r1; 1768 const Register scratch = r1;
2070 1769
2071 if (save_doubles_ == kSaveFPRegs) { 1770 if (save_doubles_ == kSaveFPRegs) {
2072 CpuFeatureScope scope(masm, VFP2);
2073 // Check CPU flags for number of registers, setting the Z condition flag. 1771 // Check CPU flags for number of registers, setting the Z condition flag.
2074 __ CheckFor32DRegs(scratch); 1772 __ CheckFor32DRegs(scratch);
2075 1773
2076 __ sub(sp, sp, Operand(kDoubleSize * DwVfpRegister::kMaxNumRegisters)); 1774 __ sub(sp, sp, Operand(kDoubleSize * DwVfpRegister::kMaxNumRegisters));
2077 for (int i = 0; i < DwVfpRegister::kMaxNumRegisters; i++) { 1775 for (int i = 0; i < DwVfpRegister::kMaxNumRegisters; i++) {
2078 DwVfpRegister reg = DwVfpRegister::from_code(i); 1776 DwVfpRegister reg = DwVfpRegister::from_code(i);
2079 __ vstr(reg, MemOperand(sp, i * kDoubleSize), i < 16 ? al : ne); 1777 __ vstr(reg, MemOperand(sp, i * kDoubleSize), i < 16 ? al : ne);
2080 } 1778 }
2081 } 1779 }
2082 const int argument_count = 1; 1780 const int argument_count = 1;
2083 const int fp_argument_count = 0; 1781 const int fp_argument_count = 0;
2084 1782
2085 AllowExternalCallThatCantCauseGC scope(masm); 1783 AllowExternalCallThatCantCauseGC scope(masm);
2086 __ PrepareCallCFunction(argument_count, fp_argument_count, scratch); 1784 __ PrepareCallCFunction(argument_count, fp_argument_count, scratch);
2087 __ mov(r0, Operand(ExternalReference::isolate_address())); 1785 __ mov(r0, Operand(ExternalReference::isolate_address()));
2088 __ CallCFunction( 1786 __ CallCFunction(
2089 ExternalReference::store_buffer_overflow_function(masm->isolate()), 1787 ExternalReference::store_buffer_overflow_function(masm->isolate()),
2090 argument_count); 1788 argument_count);
2091 if (save_doubles_ == kSaveFPRegs) { 1789 if (save_doubles_ == kSaveFPRegs) {
2092 CpuFeatureScope scope(masm, VFP2);
2093
2094 // Check CPU flags for number of registers, setting the Z condition flag. 1790 // Check CPU flags for number of registers, setting the Z condition flag.
2095 __ CheckFor32DRegs(scratch); 1791 __ CheckFor32DRegs(scratch);
2096 1792
2097 for (int i = 0; i < DwVfpRegister::kMaxNumRegisters; i++) { 1793 for (int i = 0; i < DwVfpRegister::kMaxNumRegisters; i++) {
2098 DwVfpRegister reg = DwVfpRegister::from_code(i); 1794 DwVfpRegister reg = DwVfpRegister::from_code(i);
2099 __ vldr(reg, MemOperand(sp, i * kDoubleSize), i < 16 ? al : ne); 1795 __ vldr(reg, MemOperand(sp, i * kDoubleSize), i < 16 ? al : ne);
2100 } 1796 }
2101 __ add(sp, sp, Operand(kDoubleSize * DwVfpRegister::kMaxNumRegisters)); 1797 __ add(sp, sp, Operand(kDoubleSize * DwVfpRegister::kMaxNumRegisters));
2102 } 1798 }
2103 __ ldm(ia_w, sp, kCallerSaved | pc.bit()); // Also pop pc to get Ret(0). 1799 __ ldm(ia_w, sp, kCallerSaved | pc.bit()); // Also pop pc to get Ret(0).
(...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after
2308 // Push the 31 high bits (bit 0 cleared to look like a smi). 2004 // Push the 31 high bits (bit 0 cleared to look like a smi).
2309 __ bic(r1, r1, Operand(1)); 2005 __ bic(r1, r1, Operand(1));
2310 __ Push(r2, r1); 2006 __ Push(r2, r1);
2311 __ CallRuntime(Runtime::kNumberAlloc, 0); 2007 __ CallRuntime(Runtime::kNumberAlloc, 0);
2312 __ Pop(r2, r1); // Restore the result. 2008 __ Pop(r2, r1); // Restore the result.
2313 __ orr(r1, r1, Operand(r2, LSR, 31)); 2009 __ orr(r1, r1, Operand(r2, LSR, 31));
2314 } 2010 }
2315 __ bind(&heapnumber_allocated); 2011 __ bind(&heapnumber_allocated);
2316 } 2012 }
2317 2013
2318 if (CpuFeatures::IsSupported(VFP2)) { 2014 __ vmov(s0, r1);
2319 // Convert the int32 in r1 to the heap number in r0. r2 is corrupted. 2015 __ vcvt_f64_s32(d0, s0);
2320 CpuFeatureScope scope(masm, VFP2); 2016 __ vstr(d0, FieldMemOperand(r0, HeapNumber::kValueOffset));
2321 __ vmov(s0, r1); 2017 __ Ret();
2322 __ vcvt_f64_s32(d0, s0);
2323 __ vstr(d0, FieldMemOperand(r0, HeapNumber::kValueOffset));
2324 __ Ret();
2325 } else {
2326 // WriteInt32ToHeapNumberStub does not trigger GC, so we do not
2327 // have to set up a frame.
2328 WriteInt32ToHeapNumberStub stub(r1, r0, r2);
2329 __ Jump(stub.GetCode(masm->isolate()), RelocInfo::CODE_TARGET);
2330 }
2331 } 2018 }
2332 2019
2333 2020
2334 // TODO(svenpanne): Use virtual functions instead of switch. 2021 // TODO(svenpanne): Use virtual functions instead of switch.
2335 void UnaryOpStub::GenerateGenericStub(MacroAssembler* masm) { 2022 void UnaryOpStub::GenerateGenericStub(MacroAssembler* masm) {
2336 switch (op_) { 2023 switch (op_) {
2337 case Token::SUB: 2024 case Token::SUB:
2338 GenerateGenericStubSub(masm); 2025 GenerateGenericStubSub(masm);
2339 break; 2026 break;
2340 case Token::BIT_NOT: 2027 case Token::BIT_NOT:
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
2376 case Token::BIT_NOT: 2063 case Token::BIT_NOT:
2377 __ InvokeBuiltin(Builtins::BIT_NOT, JUMP_FUNCTION); 2064 __ InvokeBuiltin(Builtins::BIT_NOT, JUMP_FUNCTION);
2378 break; 2065 break;
2379 default: 2066 default:
2380 UNREACHABLE(); 2067 UNREACHABLE();
2381 } 2068 }
2382 } 2069 }
2383 2070
2384 2071
2385 void BinaryOpStub::Initialize() { 2072 void BinaryOpStub::Initialize() {
2386 platform_specific_bit_ = CpuFeatures::IsSupported(VFP2); 2073 platform_specific_bit_ = true; // VFP2 is a base requirement for V8
2387 } 2074 }
2388 2075
2389 2076
2390 void BinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) { 2077 void BinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) {
2391 Label get_result; 2078 Label get_result;
2392 2079
2393 __ Push(r1, r0); 2080 __ Push(r1, r0);
2394 2081
2395 __ mov(r2, Operand(Smi::FromInt(MinorKey()))); 2082 __ mov(r2, Operand(Smi::FromInt(MinorKey())));
2396 __ push(r2); 2083 __ push(r2);
(...skipping 258 matching lines...) Expand 10 before | Expand all | Expand 10 after
2655 2342
2656 switch (op) { 2343 switch (op) {
2657 case Token::ADD: 2344 case Token::ADD:
2658 case Token::SUB: 2345 case Token::SUB:
2659 case Token::MUL: 2346 case Token::MUL:
2660 case Token::DIV: 2347 case Token::DIV:
2661 case Token::MOD: { 2348 case Token::MOD: {
2662 // Load left and right operands into d6 and d7 or r0/r1 and r2/r3 2349 // Load left and right operands into d6 and d7 or r0/r1 and r2/r3
2663 // depending on whether VFP3 is available or not. 2350 // depending on whether VFP3 is available or not.
2664 FloatingPointHelper::Destination destination = 2351 FloatingPointHelper::Destination destination =
2665 CpuFeatures::IsSupported(VFP2) &&
2666 op != Token::MOD ? 2352 op != Token::MOD ?
2667 FloatingPointHelper::kVFPRegisters : 2353 FloatingPointHelper::kVFPRegisters :
2668 FloatingPointHelper::kCoreRegisters; 2354 FloatingPointHelper::kCoreRegisters;
2669 2355
2670 // Allocate new heap number for result. 2356 // Allocate new heap number for result.
2671 Register result = r5; 2357 Register result = r5;
2672 BinaryOpStub_GenerateHeapResultAllocation( 2358 BinaryOpStub_GenerateHeapResultAllocation(
2673 masm, result, heap_number_map, scratch1, scratch2, gc_required, mode); 2359 masm, result, heap_number_map, scratch1, scratch2, gc_required, mode);
2674 2360
2675 // Load the operands. 2361 // Load the operands.
(...skipping 23 matching lines...) Expand all
2699 masm, destination, left, d6, r0, r1, heap_number_map, 2385 masm, destination, left, d6, r0, r1, heap_number_map,
2700 scratch1, scratch2, fail); 2386 scratch1, scratch2, fail);
2701 } 2387 }
2702 } 2388 }
2703 2389
2704 // Calculate the result. 2390 // Calculate the result.
2705 if (destination == FloatingPointHelper::kVFPRegisters) { 2391 if (destination == FloatingPointHelper::kVFPRegisters) {
2706 // Using VFP registers: 2392 // Using VFP registers:
2707 // d6: Left value 2393 // d6: Left value
2708 // d7: Right value 2394 // d7: Right value
2709 CpuFeatureScope scope(masm, VFP2);
2710 switch (op) { 2395 switch (op) {
2711 case Token::ADD: 2396 case Token::ADD:
2712 __ vadd(d5, d6, d7); 2397 __ vadd(d5, d6, d7);
2713 break; 2398 break;
2714 case Token::SUB: 2399 case Token::SUB:
2715 __ vsub(d5, d6, d7); 2400 __ vsub(d5, d6, d7);
2716 break; 2401 break;
2717 case Token::MUL: 2402 case Token::MUL:
2718 __ vmul(d5, d6, d7); 2403 __ vmul(d5, d6, d7);
2719 break; 2404 break;
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
2790 __ mov(r2, Operand(r3, ASR, r2)); 2475 __ mov(r2, Operand(r3, ASR, r2));
2791 break; 2476 break;
2792 case Token::SHR: 2477 case Token::SHR:
2793 // Use only the 5 least significant bits of the shift count. 2478 // Use only the 5 least significant bits of the shift count.
2794 __ GetLeastBitsFromInt32(r2, r2, 5); 2479 __ GetLeastBitsFromInt32(r2, r2, 5);
2795 __ mov(r2, Operand(r3, LSR, r2), SetCC); 2480 __ mov(r2, Operand(r3, LSR, r2), SetCC);
2796 // SHR is special because it is required to produce a positive answer. 2481 // SHR is special because it is required to produce a positive answer.
2797 // The code below for writing into heap numbers isn't capable of 2482 // The code below for writing into heap numbers isn't capable of
2798 // writing the register as an unsigned int so we go to slow case if we 2483 // writing the register as an unsigned int so we go to slow case if we
2799 // hit this case. 2484 // hit this case.
2800 if (CpuFeatures::IsSupported(VFP2)) { 2485 __ b(mi, &result_not_a_smi);
2801 __ b(mi, &result_not_a_smi);
2802 } else {
2803 __ b(mi, not_numbers);
2804 }
2805 break; 2486 break;
2806 case Token::SHL: 2487 case Token::SHL:
2807 // Use only the 5 least significant bits of the shift count. 2488 // Use only the 5 least significant bits of the shift count.
2808 __ GetLeastBitsFromInt32(r2, r2, 5); 2489 __ GetLeastBitsFromInt32(r2, r2, 5);
2809 __ mov(r2, Operand(r3, LSL, r2)); 2490 __ mov(r2, Operand(r3, LSL, r2));
2810 break; 2491 break;
2811 default: 2492 default:
2812 UNREACHABLE(); 2493 UNREACHABLE();
2813 } 2494 }
2814 2495
(...skipping 15 matching lines...) Expand all
2830 mode); 2511 mode);
2831 } 2512 }
2832 2513
2833 // r2: Answer as signed int32. 2514 // r2: Answer as signed int32.
2834 // r5: Heap number to write answer into. 2515 // r5: Heap number to write answer into.
2835 2516
2836 // Nothing can go wrong now, so move the heap number to r0, which is the 2517 // Nothing can go wrong now, so move the heap number to r0, which is the
2837 // result. 2518 // result.
2838 __ mov(r0, Operand(r5)); 2519 __ mov(r0, Operand(r5));
2839 2520
2840 if (CpuFeatures::IsSupported(VFP2)) { 2521 // Convert the int32 in r2 to the heap number in r0. r3 is corrupted. As
2841 // Convert the int32 in r2 to the heap number in r0. r3 is corrupted. As 2522 // mentioned above SHR needs to always produce a positive result.
2842 // mentioned above SHR needs to always produce a positive result. 2523 __ vmov(s0, r2);
2843 CpuFeatureScope scope(masm, VFP2); 2524 if (op == Token::SHR) {
2844 __ vmov(s0, r2); 2525 __ vcvt_f64_u32(d0, s0);
2845 if (op == Token::SHR) {
2846 __ vcvt_f64_u32(d0, s0);
2847 } else {
2848 __ vcvt_f64_s32(d0, s0);
2849 }
2850 __ sub(r3, r0, Operand(kHeapObjectTag));
2851 __ vstr(d0, r3, HeapNumber::kValueOffset);
2852 __ Ret();
2853 } else { 2526 } else {
2854 // Tail call that writes the int32 in r2 to the heap number in r0, using 2527 __ vcvt_f64_s32(d0, s0);
2855 // r3 as scratch. r0 is preserved and returned.
2856 WriteInt32ToHeapNumberStub stub(r2, r0, r3);
2857 __ TailCallStub(&stub);
2858 } 2528 }
2529 __ sub(r3, r0, Operand(kHeapObjectTag));
2530 __ vstr(d0, r3, HeapNumber::kValueOffset);
2531 __ Ret();
2859 break; 2532 break;
2860 } 2533 }
2861 default: 2534 default:
2862 UNREACHABLE(); 2535 UNREACHABLE();
2863 } 2536 }
2864 } 2537 }
2865 2538
2866 2539
2867 // Generate the smi code. If the operation on smis are successful this return is 2540 // Generate the smi code. If the operation on smis are successful this return is
2868 // generated. If the result is not a smi and heap number allocation is not 2541 // generated. If the result is not a smi and heap number allocation is not
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after
2994 // again if this changes. 2667 // again if this changes.
2995 if (left_type_ == BinaryOpIC::SMI) { 2668 if (left_type_ == BinaryOpIC::SMI) {
2996 __ JumpIfNotSmi(left, &transition); 2669 __ JumpIfNotSmi(left, &transition);
2997 } 2670 }
2998 if (right_type_ == BinaryOpIC::SMI) { 2671 if (right_type_ == BinaryOpIC::SMI) {
2999 __ JumpIfNotSmi(right, &transition); 2672 __ JumpIfNotSmi(right, &transition);
3000 } 2673 }
3001 // Load both operands and check that they are 32-bit integer. 2674 // Load both operands and check that they are 32-bit integer.
3002 // Jump to type transition if they are not. The registers r0 and r1 (right 2675 // Jump to type transition if they are not. The registers r0 and r1 (right
3003 // and left) are preserved for the runtime call. 2676 // and left) are preserved for the runtime call.
3004 FloatingPointHelper::Destination destination = 2677 FloatingPointHelper::Destination destination = (op_ != Token::MOD)
3005 (CpuFeatures::IsSupported(VFP2) && op_ != Token::MOD)
3006 ? FloatingPointHelper::kVFPRegisters 2678 ? FloatingPointHelper::kVFPRegisters
3007 : FloatingPointHelper::kCoreRegisters; 2679 : FloatingPointHelper::kCoreRegisters;
3008 2680
3009 FloatingPointHelper::LoadNumberAsInt32Double(masm, 2681 FloatingPointHelper::LoadNumberAsInt32Double(masm,
3010 right, 2682 right,
3011 destination, 2683 destination,
3012 d7, 2684 d7,
3013 d8, 2685 d8,
3014 r2, 2686 r2,
3015 r3, 2687 r3,
3016 heap_number_map, 2688 heap_number_map,
3017 scratch1, 2689 scratch1,
3018 scratch2, 2690 scratch2,
3019 s0, 2691 s0,
3020 &transition); 2692 &transition);
3021 FloatingPointHelper::LoadNumberAsInt32Double(masm, 2693 FloatingPointHelper::LoadNumberAsInt32Double(masm,
3022 left, 2694 left,
3023 destination, 2695 destination,
3024 d6, 2696 d6,
3025 d8, 2697 d8,
3026 r4, 2698 r4,
3027 r5, 2699 r5,
3028 heap_number_map, 2700 heap_number_map,
3029 scratch1, 2701 scratch1,
3030 scratch2, 2702 scratch2,
3031 s0, 2703 s0,
3032 &transition); 2704 &transition);
3033 2705
3034 if (destination == FloatingPointHelper::kVFPRegisters) { 2706 if (destination == FloatingPointHelper::kVFPRegisters) {
3035 CpuFeatureScope scope(masm, VFP2);
3036 Label return_heap_number; 2707 Label return_heap_number;
3037 switch (op_) { 2708 switch (op_) {
3038 case Token::ADD: 2709 case Token::ADD:
3039 __ vadd(d5, d6, d7); 2710 __ vadd(d5, d6, d7);
3040 break; 2711 break;
3041 case Token::SUB: 2712 case Token::SUB:
3042 __ vsub(d5, d6, d7); 2713 __ vsub(d5, d6, d7);
3043 break; 2714 break;
3044 case Token::MUL: 2715 case Token::MUL:
3045 __ vmul(d5, d6, d7); 2716 __ vmul(d5, d6, d7);
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after
3193 __ and_(r2, r2, Operand(0x1f)); 2864 __ and_(r2, r2, Operand(0x1f));
3194 __ mov(r2, Operand(r3, ASR, r2)); 2865 __ mov(r2, Operand(r3, ASR, r2));
3195 break; 2866 break;
3196 case Token::SHR: 2867 case Token::SHR:
3197 __ and_(r2, r2, Operand(0x1f)); 2868 __ and_(r2, r2, Operand(0x1f));
3198 __ mov(r2, Operand(r3, LSR, r2), SetCC); 2869 __ mov(r2, Operand(r3, LSR, r2), SetCC);
3199 // SHR is special because it is required to produce a positive answer. 2870 // SHR is special because it is required to produce a positive answer.
3200 // We only get a negative result if the shift value (r2) is 0. 2871 // We only get a negative result if the shift value (r2) is 0.
3201 // This result cannot be respresented as a signed 32-bit integer, try 2872 // This result cannot be respresented as a signed 32-bit integer, try
3202 // to return a heap number if we can. 2873 // to return a heap number if we can.
3203 // The non vfp2 code does not support this special case, so jump to 2874 __ b(mi, (result_type_ <= BinaryOpIC::INT32)
3204 // runtime if we don't support it. 2875 ? &transition
3205 if (CpuFeatures::IsSupported(VFP2)) { 2876 : &return_heap_number);
3206 __ b(mi, (result_type_ <= BinaryOpIC::INT32)
3207 ? &transition
3208 : &return_heap_number);
3209 } else {
3210 __ b(mi, (result_type_ <= BinaryOpIC::INT32)
3211 ? &transition
3212 : &call_runtime);
3213 }
3214 break; 2877 break;
3215 case Token::SHL: 2878 case Token::SHL:
3216 __ and_(r2, r2, Operand(0x1f)); 2879 __ and_(r2, r2, Operand(0x1f));
3217 __ mov(r2, Operand(r3, LSL, r2)); 2880 __ mov(r2, Operand(r3, LSL, r2));
3218 break; 2881 break;
3219 default: 2882 default:
3220 UNREACHABLE(); 2883 UNREACHABLE();
3221 } 2884 }
3222 2885
3223 // Check if the result fits in a smi. 2886 // Check if the result fits in a smi.
3224 __ add(scratch1, r2, Operand(0x40000000), SetCC); 2887 __ add(scratch1, r2, Operand(0x40000000), SetCC);
3225 // If not try to return a heap number. (We know the result is an int32.) 2888 // If not try to return a heap number. (We know the result is an int32.)
3226 __ b(mi, &return_heap_number); 2889 __ b(mi, &return_heap_number);
3227 // Tag the result and return. 2890 // Tag the result and return.
3228 __ SmiTag(r0, r2); 2891 __ SmiTag(r0, r2);
3229 __ Ret(); 2892 __ Ret();
3230 2893
3231 __ bind(&return_heap_number); 2894 __ bind(&return_heap_number);
3232 heap_number_result = r5; 2895 heap_number_result = r5;
3233 BinaryOpStub_GenerateHeapResultAllocation(masm, 2896 BinaryOpStub_GenerateHeapResultAllocation(masm,
3234 heap_number_result, 2897 heap_number_result,
3235 heap_number_map, 2898 heap_number_map,
3236 scratch1, 2899 scratch1,
3237 scratch2, 2900 scratch2,
3238 &call_runtime, 2901 &call_runtime,
3239 mode_); 2902 mode_);
3240 2903
3241 if (CpuFeatures::IsSupported(VFP2)) { 2904 if (op_ != Token::SHR) {
3242 CpuFeatureScope scope(masm, VFP2); 2905 // Convert the result to a floating point value.
3243 if (op_ != Token::SHR) { 2906 __ vmov(double_scratch.low(), r2);
3244 // Convert the result to a floating point value. 2907 __ vcvt_f64_s32(double_scratch, double_scratch.low());
3245 __ vmov(double_scratch.low(), r2); 2908 } else {
3246 __ vcvt_f64_s32(double_scratch, double_scratch.low()); 2909 // The result must be interpreted as an unsigned 32-bit integer.
3247 } else { 2910 __ vmov(double_scratch.low(), r2);
3248 // The result must be interpreted as an unsigned 32-bit integer. 2911 __ vcvt_f64_u32(double_scratch, double_scratch.low());
3249 __ vmov(double_scratch.low(), r2); 2912 }
3250 __ vcvt_f64_u32(double_scratch, double_scratch.low());
3251 }
3252 2913
3253 // Store the result. 2914 // Store the result.
3254 __ sub(r0, heap_number_result, Operand(kHeapObjectTag)); 2915 __ sub(r0, heap_number_result, Operand(kHeapObjectTag));
3255 __ vstr(double_scratch, r0, HeapNumber::kValueOffset); 2916 __ vstr(double_scratch, r0, HeapNumber::kValueOffset);
3256 __ mov(r0, heap_number_result); 2917 __ mov(r0, heap_number_result);
3257 __ Ret(); 2918 __ Ret();
3258 } else {
3259 // Tail call that writes the int32 in r2 to the heap number in r0, using
3260 // r3 as scratch. r0 is preserved and returned.
3261 __ mov(r0, r5);
3262 WriteInt32ToHeapNumberStub stub(r2, r0, r3);
3263 __ TailCallStub(&stub);
3264 }
3265 2919
3266 break; 2920 break;
3267 } 2921 }
3268 2922
3269 default: 2923 default:
3270 UNREACHABLE(); 2924 UNREACHABLE();
3271 } 2925 }
3272 2926
3273 // We never expect DIV to yield an integer result, so we always generate 2927 // We never expect DIV to yield an integer result, so we always generate
3274 // type transition code for DIV operations expecting an integer result: the 2928 // type transition code for DIV operations expecting an integer result: the
(...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after
3434 3088
3435 Label input_not_smi; 3089 Label input_not_smi;
3436 Label loaded; 3090 Label loaded;
3437 Label calculate; 3091 Label calculate;
3438 Label invalid_cache; 3092 Label invalid_cache;
3439 const Register scratch0 = r9; 3093 const Register scratch0 = r9;
3440 const Register scratch1 = r7; 3094 const Register scratch1 = r7;
3441 const Register cache_entry = r0; 3095 const Register cache_entry = r0;
3442 const bool tagged = (argument_type_ == TAGGED); 3096 const bool tagged = (argument_type_ == TAGGED);
3443 3097
3444 if (CpuFeatures::IsSupported(VFP2)) { 3098 if (tagged) {
3445 CpuFeatureScope scope(masm, VFP2); 3099 // Argument is a number and is on stack and in r0.
3446 if (tagged) { 3100 // Load argument and check if it is a smi.
3447 // Argument is a number and is on stack and in r0. 3101 __ JumpIfNotSmi(r0, &input_not_smi);
3448 // Load argument and check if it is a smi.
3449 __ JumpIfNotSmi(r0, &input_not_smi);
3450 3102
3451 // Input is a smi. Convert to double and load the low and high words 3103 // Input is a smi. Convert to double and load the low and high words
3452 // of the double into r2, r3. 3104 // of the double into r2, r3.
3453 __ IntegerToDoubleConversionWithVFP3(r0, r3, r2); 3105 __ IntegerToDoubleConversionWithVFP3(r0, r3, r2);
3454 __ b(&loaded); 3106 __ b(&loaded);
3455 3107
3456 __ bind(&input_not_smi); 3108 __ bind(&input_not_smi);
3457 // Check if input is a HeapNumber. 3109 // Check if input is a HeapNumber.
3458 __ CheckMap(r0, 3110 __ CheckMap(r0,
3459 r1, 3111 r1,
3460 Heap::kHeapNumberMapRootIndex, 3112 Heap::kHeapNumberMapRootIndex,
3461 &calculate, 3113 &calculate,
3462 DONT_DO_SMI_CHECK); 3114 DONT_DO_SMI_CHECK);
3463 // Input is a HeapNumber. Load it to a double register and store the 3115 // Input is a HeapNumber. Load it to a double register and store the
3464 // low and high words into r2, r3. 3116 // low and high words into r2, r3.
3465 __ vldr(d0, FieldMemOperand(r0, HeapNumber::kValueOffset)); 3117 __ vldr(d0, FieldMemOperand(r0, HeapNumber::kValueOffset));
3466 __ vmov(r2, r3, d0); 3118 __ vmov(r2, r3, d0);
3467 } else { 3119 } else {
3468 // Input is untagged double in d2. Output goes to d2. 3120 // Input is untagged double in d2. Output goes to d2.
3469 __ vmov(r2, r3, d2); 3121 __ vmov(r2, r3, d2);
3470 } 3122 }
3471 __ bind(&loaded); 3123 __ bind(&loaded);
3472 // r2 = low 32 bits of double value 3124 // r2 = low 32 bits of double value
3473 // r3 = high 32 bits of double value 3125 // r3 = high 32 bits of double value
3474 // Compute hash (the shifts are arithmetic): 3126 // Compute hash (the shifts are arithmetic):
3475 // h = (low ^ high); h ^= h >> 16; h ^= h >> 8; h = h & (cacheSize - 1); 3127 // h = (low ^ high); h ^= h >> 16; h ^= h >> 8; h = h & (cacheSize - 1);
3476 __ eor(r1, r2, Operand(r3)); 3128 __ eor(r1, r2, Operand(r3));
3477 __ eor(r1, r1, Operand(r1, ASR, 16)); 3129 __ eor(r1, r1, Operand(r1, ASR, 16));
3478 __ eor(r1, r1, Operand(r1, ASR, 8)); 3130 __ eor(r1, r1, Operand(r1, ASR, 8));
3479 ASSERT(IsPowerOf2(TranscendentalCache::SubCache::kCacheSize)); 3131 ASSERT(IsPowerOf2(TranscendentalCache::SubCache::kCacheSize));
3480 __ And(r1, r1, Operand(TranscendentalCache::SubCache::kCacheSize - 1)); 3132 __ And(r1, r1, Operand(TranscendentalCache::SubCache::kCacheSize - 1));
3481 3133
3482 // r2 = low 32 bits of double value. 3134 // r2 = low 32 bits of double value.
3483 // r3 = high 32 bits of double value. 3135 // r3 = high 32 bits of double value.
3484 // r1 = TranscendentalCache::hash(double value). 3136 // r1 = TranscendentalCache::hash(double value).
3485 Isolate* isolate = masm->isolate(); 3137 Isolate* isolate = masm->isolate();
3486 ExternalReference cache_array = 3138 ExternalReference cache_array =
3487 ExternalReference::transcendental_cache_array_address(isolate); 3139 ExternalReference::transcendental_cache_array_address(isolate);
3488 __ mov(cache_entry, Operand(cache_array)); 3140 __ mov(cache_entry, Operand(cache_array));
3489 // cache_entry points to cache array. 3141 // cache_entry points to cache array.
3490 int cache_array_index 3142 int cache_array_index
3491 = type_ * sizeof(isolate->transcendental_cache()->caches_[0]); 3143 = type_ * sizeof(isolate->transcendental_cache()->caches_[0]);
3492 __ ldr(cache_entry, MemOperand(cache_entry, cache_array_index)); 3144 __ ldr(cache_entry, MemOperand(cache_entry, cache_array_index));
3493 // r0 points to the cache for the type type_. 3145 // r0 points to the cache for the type type_.
3494 // If NULL, the cache hasn't been initialized yet, so go through runtime. 3146 // If NULL, the cache hasn't been initialized yet, so go through runtime.
3495 __ cmp(cache_entry, Operand::Zero()); 3147 __ cmp(cache_entry, Operand::Zero());
3496 __ b(eq, &invalid_cache); 3148 __ b(eq, &invalid_cache);
3497 3149
3498 #ifdef DEBUG 3150 #ifdef DEBUG
3499 // Check that the layout of cache elements match expectations. 3151 // Check that the layout of cache elements match expectations.
3500 { TranscendentalCache::SubCache::Element test_elem[2]; 3152 { TranscendentalCache::SubCache::Element test_elem[2];
3501 char* elem_start = reinterpret_cast<char*>(&test_elem[0]); 3153 char* elem_start = reinterpret_cast<char*>(&test_elem[0]);
3502 char* elem2_start = reinterpret_cast<char*>(&test_elem[1]); 3154 char* elem2_start = reinterpret_cast<char*>(&test_elem[1]);
3503 char* elem_in0 = reinterpret_cast<char*>(&(test_elem[0].in[0])); 3155 char* elem_in0 = reinterpret_cast<char*>(&(test_elem[0].in[0]));
3504 char* elem_in1 = reinterpret_cast<char*>(&(test_elem[0].in[1])); 3156 char* elem_in1 = reinterpret_cast<char*>(&(test_elem[0].in[1]));
3505 char* elem_out = reinterpret_cast<char*>(&(test_elem[0].output)); 3157 char* elem_out = reinterpret_cast<char*>(&(test_elem[0].output));
3506 CHECK_EQ(12, elem2_start - elem_start); // Two uint_32's and a pointer. 3158 CHECK_EQ(12, elem2_start - elem_start); // Two uint_32's and a pointer.
3507 CHECK_EQ(0, elem_in0 - elem_start); 3159 CHECK_EQ(0, elem_in0 - elem_start);
3508 CHECK_EQ(kIntSize, elem_in1 - elem_start); 3160 CHECK_EQ(kIntSize, elem_in1 - elem_start);
3509 CHECK_EQ(2 * kIntSize, elem_out - elem_start); 3161 CHECK_EQ(2 * kIntSize, elem_out - elem_start);
3510 } 3162 }
3511 #endif 3163 #endif
3512 3164
3513 // Find the address of the r1'st entry in the cache, i.e., &r0[r1*12]. 3165 // Find the address of the r1'st entry in the cache, i.e., &r0[r1*12].
3514 __ add(r1, r1, Operand(r1, LSL, 1)); 3166 __ add(r1, r1, Operand(r1, LSL, 1));
3515 __ add(cache_entry, cache_entry, Operand(r1, LSL, 2)); 3167 __ add(cache_entry, cache_entry, Operand(r1, LSL, 2));
3516 // Check if cache matches: Double value is stored in uint32_t[2] array. 3168 // Check if cache matches: Double value is stored in uint32_t[2] array.
3517 __ ldm(ia, cache_entry, r4.bit() | r5.bit() | r6.bit()); 3169 __ ldm(ia, cache_entry, r4.bit() | r5.bit() | r6.bit());
3518 __ cmp(r2, r4); 3170 __ cmp(r2, r4);
3519 __ cmp(r3, r5, eq); 3171 __ cmp(r3, r5, eq);
3520 __ b(ne, &calculate); 3172 __ b(ne, &calculate);
3521 // Cache hit. Load result, cleanup and return. 3173 // Cache hit. Load result, cleanup and return.
3522 Counters* counters = masm->isolate()->counters(); 3174 Counters* counters = masm->isolate()->counters();
3523 __ IncrementCounter( 3175 __ IncrementCounter(
3524 counters->transcendental_cache_hit(), 1, scratch0, scratch1); 3176 counters->transcendental_cache_hit(), 1, scratch0, scratch1);
3525 if (tagged) { 3177 if (tagged) {
3526 // Pop input value from stack and load result into r0. 3178 // Pop input value from stack and load result into r0.
3527 __ pop(); 3179 __ pop();
3528 __ mov(r0, Operand(r6)); 3180 __ mov(r0, Operand(r6));
3529 } else { 3181 } else {
3530 // Load result into d2. 3182 // Load result into d2.
3531 __ vldr(d2, FieldMemOperand(r6, HeapNumber::kValueOffset)); 3183 __ vldr(d2, FieldMemOperand(r6, HeapNumber::kValueOffset));
3532 } 3184 }
3533 __ Ret(); 3185 __ Ret();
3534 } // if (CpuFeatures::IsSupported(VFP3))
3535 3186
3536 __ bind(&calculate); 3187 __ bind(&calculate);
3537 Counters* counters = masm->isolate()->counters();
3538 __ IncrementCounter( 3188 __ IncrementCounter(
3539 counters->transcendental_cache_miss(), 1, scratch0, scratch1); 3189 counters->transcendental_cache_miss(), 1, scratch0, scratch1);
3540 if (tagged) { 3190 if (tagged) {
3541 __ bind(&invalid_cache); 3191 __ bind(&invalid_cache);
3542 ExternalReference runtime_function = 3192 ExternalReference runtime_function =
3543 ExternalReference(RuntimeFunction(), masm->isolate()); 3193 ExternalReference(RuntimeFunction(), masm->isolate());
3544 __ TailCallExternalReference(runtime_function, 1, 1); 3194 __ TailCallExternalReference(runtime_function, 1, 1);
3545 } else { 3195 } else {
3546 ASSERT(CpuFeatures::IsSupported(VFP2));
3547 CpuFeatureScope scope(masm, VFP2);
3548
3549 Label no_update; 3196 Label no_update;
3550 Label skip_cache; 3197 Label skip_cache;
3551 3198
3552 // Call C function to calculate the result and update the cache. 3199 // Call C function to calculate the result and update the cache.
3553 // r0: precalculated cache entry address. 3200 // r0: precalculated cache entry address.
3554 // r2 and r3: parts of the double value. 3201 // r2 and r3: parts of the double value.
3555 // Store r0, r2 and r3 on stack for later before calling C function. 3202 // Store r0, r2 and r3 on stack for later before calling C function.
3556 __ Push(r3, r2, cache_entry); 3203 __ Push(r3, r2, cache_entry);
3557 GenerateCallCFunction(masm, scratch0); 3204 GenerateCallCFunction(masm, scratch0);
3558 __ GetCFunctionDoubleResult(d2); 3205 __ GetCFunctionDoubleResult(d2);
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
3598 __ push(scratch0); 3245 __ push(scratch0);
3599 __ CallRuntimeSaveDoubles(Runtime::kAllocateInNewSpace); 3246 __ CallRuntimeSaveDoubles(Runtime::kAllocateInNewSpace);
3600 } 3247 }
3601 __ Ret(); 3248 __ Ret();
3602 } 3249 }
3603 } 3250 }
3604 3251
3605 3252
3606 void TranscendentalCacheStub::GenerateCallCFunction(MacroAssembler* masm, 3253 void TranscendentalCacheStub::GenerateCallCFunction(MacroAssembler* masm,
3607 Register scratch) { 3254 Register scratch) {
3608 ASSERT(masm->IsEnabled(VFP2));
3609 Isolate* isolate = masm->isolate(); 3255 Isolate* isolate = masm->isolate();
3610 3256
3611 __ push(lr); 3257 __ push(lr);
3612 __ PrepareCallCFunction(0, 1, scratch); 3258 __ PrepareCallCFunction(0, 1, scratch);
3613 if (masm->use_eabi_hardfloat()) { 3259 if (masm->use_eabi_hardfloat()) {
3614 __ vmov(d0, d2); 3260 __ vmov(d0, d2);
3615 } else { 3261 } else {
3616 __ vmov(r0, r1, d2); 3262 __ vmov(r0, r1, d2);
3617 } 3263 }
3618 AllowExternalCallThatCantCauseGC scope(masm); 3264 AllowExternalCallThatCantCauseGC scope(masm);
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
3659 __ TailCallRuntime(Runtime::kStackGuard, 0, 1); 3305 __ TailCallRuntime(Runtime::kStackGuard, 0, 1);
3660 } 3306 }
3661 3307
3662 3308
3663 void InterruptStub::Generate(MacroAssembler* masm) { 3309 void InterruptStub::Generate(MacroAssembler* masm) {
3664 __ TailCallRuntime(Runtime::kInterrupt, 0, 1); 3310 __ TailCallRuntime(Runtime::kInterrupt, 0, 1);
3665 } 3311 }
3666 3312
3667 3313
3668 void MathPowStub::Generate(MacroAssembler* masm) { 3314 void MathPowStub::Generate(MacroAssembler* masm) {
3669 CpuFeatureScope vfp2_scope(masm, VFP2);
3670 const Register base = r1; 3315 const Register base = r1;
3671 const Register exponent = r2; 3316 const Register exponent = r2;
3672 const Register heapnumbermap = r5; 3317 const Register heapnumbermap = r5;
3673 const Register heapnumber = r0; 3318 const Register heapnumber = r0;
3674 const DwVfpRegister double_base = d1; 3319 const DwVfpRegister double_base = d1;
3675 const DwVfpRegister double_exponent = d2; 3320 const DwVfpRegister double_exponent = d2;
3676 const DwVfpRegister double_result = d3; 3321 const DwVfpRegister double_result = d3;
3677 const DwVfpRegister double_scratch = d0; 3322 const DwVfpRegister double_scratch = d0;
3678 const SwVfpRegister single_scratch = s0; 3323 const SwVfpRegister single_scratch = s0;
3679 const Register scratch = r9; 3324 const Register scratch = r9;
(...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after
3877 3522
3878 void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) { 3523 void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) {
3879 CEntryStub::GenerateAheadOfTime(isolate); 3524 CEntryStub::GenerateAheadOfTime(isolate);
3880 WriteInt32ToHeapNumberStub::GenerateFixedRegStubsAheadOfTime(isolate); 3525 WriteInt32ToHeapNumberStub::GenerateFixedRegStubsAheadOfTime(isolate);
3881 StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(isolate); 3526 StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(isolate);
3882 RecordWriteStub::GenerateFixedRegStubsAheadOfTime(isolate); 3527 RecordWriteStub::GenerateFixedRegStubsAheadOfTime(isolate);
3883 } 3528 }
3884 3529
3885 3530
3886 void CodeStub::GenerateFPStubs(Isolate* isolate) { 3531 void CodeStub::GenerateFPStubs(Isolate* isolate) {
3887 SaveFPRegsMode mode = CpuFeatures::IsSupported(VFP2) 3532 SaveFPRegsMode mode = kSaveFPRegs;
3888 ? kSaveFPRegs
3889 : kDontSaveFPRegs;
3890 CEntryStub save_doubles(1, mode); 3533 CEntryStub save_doubles(1, mode);
3891 StoreBufferOverflowStub stub(mode); 3534 StoreBufferOverflowStub stub(mode);
3892 // These stubs might already be in the snapshot, detect that and don't 3535 // These stubs might already be in the snapshot, detect that and don't
3893 // regenerate, which would lead to code stub initialization state being messed 3536 // regenerate, which would lead to code stub initialization state being messed
3894 // up. 3537 // up.
3895 Code* save_doubles_code; 3538 Code* save_doubles_code;
3896 if (!save_doubles.FindCodeInCache(&save_doubles_code, isolate)) { 3539 if (!save_doubles.FindCodeInCache(&save_doubles_code, isolate)) {
3897 save_doubles_code = *save_doubles.GetCode(isolate); 3540 save_doubles_code = *save_doubles.GetCode(isolate);
3898 save_doubles_code->set_is_pregenerated(true); 3541 save_doubles_code->set_is_pregenerated(true);
3899 3542
(...skipping 239 matching lines...) Expand 10 before | Expand all | Expand 10 after
4139 // r3: argc 3782 // r3: argc
4140 // [sp+0]: argv 3783 // [sp+0]: argv
4141 3784
4142 Label invoke, handler_entry, exit; 3785 Label invoke, handler_entry, exit;
4143 3786
4144 // Called from C, so do not pop argc and args on exit (preserve sp) 3787 // Called from C, so do not pop argc and args on exit (preserve sp)
4145 // No need to save register-passed args 3788 // No need to save register-passed args
4146 // Save callee-saved registers (incl. cp and fp), sp, and lr 3789 // Save callee-saved registers (incl. cp and fp), sp, and lr
4147 __ stm(db_w, sp, kCalleeSaved | lr.bit()); 3790 __ stm(db_w, sp, kCalleeSaved | lr.bit());
4148 3791
4149 if (CpuFeatures::IsSupported(VFP2)) { 3792 // Save callee-saved vfp registers.
4150 CpuFeatureScope scope(masm, VFP2); 3793 __ vstm(db_w, sp, kFirstCalleeSavedDoubleReg, kLastCalleeSavedDoubleReg);
4151 // Save callee-saved vfp registers. 3794 // Set up the reserved register for 0.0.
4152 __ vstm(db_w, sp, kFirstCalleeSavedDoubleReg, kLastCalleeSavedDoubleReg); 3795 __ vmov(kDoubleRegZero, 0.0);
4153 // Set up the reserved register for 0.0.
4154 __ vmov(kDoubleRegZero, 0.0);
4155 }
4156 3796
4157 // Get address of argv, see stm above. 3797 // Get address of argv, see stm above.
4158 // r0: code entry 3798 // r0: code entry
4159 // r1: function 3799 // r1: function
4160 // r2: receiver 3800 // r2: receiver
4161 // r3: argc 3801 // r3: argc
4162 3802
4163 // Set up argv in r4. 3803 // Set up argv in r4.
4164 int offset_to_argv = (kNumCalleeSaved + 1) * kPointerSize; 3804 int offset_to_argv = (kNumCalleeSaved + 1) * kPointerSize;
4165 if (CpuFeatures::IsSupported(VFP2)) { 3805 offset_to_argv += kNumDoubleCalleeSaved * kDoubleSize;
4166 offset_to_argv += kNumDoubleCalleeSaved * kDoubleSize;
4167 }
4168 __ ldr(r4, MemOperand(sp, offset_to_argv)); 3806 __ ldr(r4, MemOperand(sp, offset_to_argv));
4169 3807
4170 // Push a frame with special values setup to mark it as an entry frame. 3808 // Push a frame with special values setup to mark it as an entry frame.
4171 // r0: code entry 3809 // r0: code entry
4172 // r1: function 3810 // r1: function
4173 // r2: receiver 3811 // r2: receiver
4174 // r3: argc 3812 // r3: argc
4175 // r4: argv 3813 // r4: argv
4176 Isolate* isolate = masm->isolate(); 3814 Isolate* isolate = masm->isolate();
4177 __ mov(r8, Operand(-1)); // Push a bad frame pointer to fail if it is used. 3815 __ mov(r8, Operand(-1)); // Push a bad frame pointer to fail if it is used.
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after
4293 // Reset the stack to the callee saved registers. 3931 // Reset the stack to the callee saved registers.
4294 __ add(sp, sp, Operand(-EntryFrameConstants::kCallerFPOffset)); 3932 __ add(sp, sp, Operand(-EntryFrameConstants::kCallerFPOffset));
4295 3933
4296 // Restore callee-saved registers and return. 3934 // Restore callee-saved registers and return.
4297 #ifdef DEBUG 3935 #ifdef DEBUG
4298 if (FLAG_debug_code) { 3936 if (FLAG_debug_code) {
4299 __ mov(lr, Operand(pc)); 3937 __ mov(lr, Operand(pc));
4300 } 3938 }
4301 #endif 3939 #endif
4302 3940
4303 if (CpuFeatures::IsSupported(VFP2)) { 3941 // Restore callee-saved vfp registers.
4304 CpuFeatureScope scope(masm, VFP2); 3942 __ vldm(ia_w, sp, kFirstCalleeSavedDoubleReg, kLastCalleeSavedDoubleReg);
4305 // Restore callee-saved vfp registers.
4306 __ vldm(ia_w, sp, kFirstCalleeSavedDoubleReg, kLastCalleeSavedDoubleReg);
4307 }
4308 3943
4309 __ ldm(ia_w, sp, kCalleeSaved | pc.bit()); 3944 __ ldm(ia_w, sp, kCalleeSaved | pc.bit());
4310 } 3945 }
4311 3946
4312 3947
4313 // Uses registers r0 to r4. 3948 // Uses registers r0 to r4.
4314 // Expected input (depending on whether args are in registers or on the stack): 3949 // Expected input (depending on whether args are in registers or on the stack):
4315 // * object: r0 or at sp + 1 * kPointerSize. 3950 // * object: r0 or at sp + 1 * kPointerSize.
4316 // * function: r1 or at sp. 3951 // * function: r1 or at sp.
4317 // 3952 //
(...skipping 2684 matching lines...) Expand 10 before | Expand all | Expand 10 after
7002 Label miss; 6637 Label miss;
7003 6638
7004 if (left_ == CompareIC::SMI) { 6639 if (left_ == CompareIC::SMI) {
7005 __ JumpIfNotSmi(r1, &miss); 6640 __ JumpIfNotSmi(r1, &miss);
7006 } 6641 }
7007 if (right_ == CompareIC::SMI) { 6642 if (right_ == CompareIC::SMI) {
7008 __ JumpIfNotSmi(r0, &miss); 6643 __ JumpIfNotSmi(r0, &miss);
7009 } 6644 }
7010 6645
7011 // Inlining the double comparison and falling back to the general compare 6646 // Inlining the double comparison and falling back to the general compare
7012 // stub if NaN is involved or VFP2 is unsupported. 6647 // stub if NaN is involved.
7013 if (CpuFeatures::IsSupported(VFP2)) { 6648 // Load left and right operand.
7014 CpuFeatureScope scope(masm, VFP2); 6649 Label done, left, left_smi, right_smi;
6650 __ JumpIfSmi(r0, &right_smi);
6651 __ CheckMap(r0, r2, Heap::kHeapNumberMapRootIndex, &maybe_undefined1,
6652 DONT_DO_SMI_CHECK);
6653 __ sub(r2, r0, Operand(kHeapObjectTag));
6654 __ vldr(d1, r2, HeapNumber::kValueOffset);
6655 __ b(&left);
6656 __ bind(&right_smi);
6657 __ SmiUntag(r2, r0); // Can't clobber r0 yet.
6658 SwVfpRegister single_scratch = d2.low();
6659 __ vmov(single_scratch, r2);
6660 __ vcvt_f64_s32(d1, single_scratch);
7015 6661
7016 // Load left and right operand. 6662 __ bind(&left);
7017 Label done, left, left_smi, right_smi; 6663 __ JumpIfSmi(r1, &left_smi);
7018 __ JumpIfSmi(r0, &right_smi); 6664 __ CheckMap(r1, r2, Heap::kHeapNumberMapRootIndex, &maybe_undefined2,
7019 __ CheckMap(r0, r2, Heap::kHeapNumberMapRootIndex, &maybe_undefined1, 6665 DONT_DO_SMI_CHECK);
7020 DONT_DO_SMI_CHECK); 6666 __ sub(r2, r1, Operand(kHeapObjectTag));
7021 __ sub(r2, r0, Operand(kHeapObjectTag)); 6667 __ vldr(d0, r2, HeapNumber::kValueOffset);
7022 __ vldr(d1, r2, HeapNumber::kValueOffset); 6668 __ b(&done);
7023 __ b(&left); 6669 __ bind(&left_smi);
7024 __ bind(&right_smi); 6670 __ SmiUntag(r2, r1); // Can't clobber r1 yet.
7025 __ SmiUntag(r2, r0); // Can't clobber r0 yet. 6671 single_scratch = d3.low();
7026 SwVfpRegister single_scratch = d2.low(); 6672 __ vmov(single_scratch, r2);
7027 __ vmov(single_scratch, r2); 6673 __ vcvt_f64_s32(d0, single_scratch);
7028 __ vcvt_f64_s32(d1, single_scratch);
7029 6674
7030 __ bind(&left); 6675 __ bind(&done);
7031 __ JumpIfSmi(r1, &left_smi); 6676 // Compare operands.
7032 __ CheckMap(r1, r2, Heap::kHeapNumberMapRootIndex, &maybe_undefined2, 6677 __ VFPCompareAndSetFlags(d0, d1);
7033 DONT_DO_SMI_CHECK);
7034 __ sub(r2, r1, Operand(kHeapObjectTag));
7035 __ vldr(d0, r2, HeapNumber::kValueOffset);
7036 __ b(&done);
7037 __ bind(&left_smi);
7038 __ SmiUntag(r2, r1); // Can't clobber r1 yet.
7039 single_scratch = d3.low();
7040 __ vmov(single_scratch, r2);
7041 __ vcvt_f64_s32(d0, single_scratch);
7042 6678
7043 __ bind(&done); 6679 // Don't base result on status bits when a NaN is involved.
7044 // Compare operands. 6680 __ b(vs, &unordered);
7045 __ VFPCompareAndSetFlags(d0, d1);
7046 6681
7047 // Don't base result on status bits when a NaN is involved. 6682 // Return a result of -1, 0, or 1, based on status bits.
7048 __ b(vs, &unordered); 6683 __ mov(r0, Operand(EQUAL), LeaveCC, eq);
7049 6684 __ mov(r0, Operand(LESS), LeaveCC, lt);
7050 // Return a result of -1, 0, or 1, based on status bits. 6685 __ mov(r0, Operand(GREATER), LeaveCC, gt);
7051 __ mov(r0, Operand(EQUAL), LeaveCC, eq); 6686 __ Ret();
7052 __ mov(r0, Operand(LESS), LeaveCC, lt);
7053 __ mov(r0, Operand(GREATER), LeaveCC, gt);
7054 __ Ret();
7055 }
7056 6687
7057 __ bind(&unordered); 6688 __ bind(&unordered);
7058 __ bind(&generic_stub); 6689 __ bind(&generic_stub);
7059 ICCompareStub stub(op_, CompareIC::GENERIC, CompareIC::GENERIC, 6690 ICCompareStub stub(op_, CompareIC::GENERIC, CompareIC::GENERIC,
7060 CompareIC::GENERIC); 6691 CompareIC::GENERIC);
7061 __ Jump(stub.GetCode(masm->isolate()), RelocInfo::CODE_TARGET); 6692 __ Jump(stub.GetCode(masm->isolate()), RelocInfo::CODE_TARGET);
7062 6693
7063 __ bind(&maybe_undefined1); 6694 __ bind(&maybe_undefined1);
7064 if (Token::IsOrderedRelationalCompareOp(op_)) { 6695 if (Token::IsOrderedRelationalCompareOp(op_)) {
7065 __ CompareRoot(r0, Heap::kUndefinedValueRootIndex); 6696 __ CompareRoot(r0, Heap::kUndefinedValueRootIndex);
(...skipping 616 matching lines...) Expand 10 before | Expand all | Expand 10 after
7682 entry->value, 7313 entry->value,
7683 entry->address, 7314 entry->address,
7684 entry->action, 7315 entry->action,
7685 kDontSaveFPRegs); 7316 kDontSaveFPRegs);
7686 stub.GetCode(isolate)->set_is_pregenerated(true); 7317 stub.GetCode(isolate)->set_is_pregenerated(true);
7687 } 7318 }
7688 } 7319 }
7689 7320
7690 7321
7691 bool CodeStub::CanUseFPRegisters() { 7322 bool CodeStub::CanUseFPRegisters() {
7692 return CpuFeatures::IsSupported(VFP2); 7323 return true; // VFP2 is a base requirement for V8
7693 } 7324 }
7694 7325
7695 7326
7696 // Takes the input in 3 registers: address_ value_ and object_. A pointer to 7327 // Takes the input in 3 registers: address_ value_ and object_. A pointer to
7697 // the value has just been written into the object, now this stub makes sure 7328 // the value has just been written into the object, now this stub makes sure
7698 // we keep the GC informed. The word in the object where the value has been 7329 // we keep the GC informed. The word in the object where the value has been
7699 // written is in the address register. 7330 // written is in the address register.
7700 void RecordWriteStub::Generate(MacroAssembler* masm) { 7331 void RecordWriteStub::Generate(MacroAssembler* masm) {
7701 Label skip_to_incremental_noncompacting; 7332 Label skip_to_incremental_noncompacting;
7702 Label skip_to_incremental_compacting; 7333 Label skip_to_incremental_compacting;
(...skipping 245 matching lines...) Expand 10 before | Expand all | Expand 10 after
7948 __ ldr(r5, FieldMemOperand(r1, JSObject::kElementsOffset)); 7579 __ ldr(r5, FieldMemOperand(r1, JSObject::kElementsOffset));
7949 __ StoreNumberToDoubleElements(r0, r3, 7580 __ StoreNumberToDoubleElements(r0, r3,
7950 // Overwrites all regs after this. 7581 // Overwrites all regs after this.
7951 r5, r6, r7, r9, r2, 7582 r5, r6, r7, r9, r2,
7952 &slow_elements); 7583 &slow_elements);
7953 __ Ret(); 7584 __ Ret();
7954 } 7585 }
7955 7586
7956 7587
7957 void StubFailureTrampolineStub::Generate(MacroAssembler* masm) { 7588 void StubFailureTrampolineStub::Generate(MacroAssembler* masm) {
7958 ASSERT(!Serializer::enabled()); 7589 CEntryStub ces(1, kSaveFPRegs);
7959 bool save_fp_regs = CpuFeatures::IsSupported(VFP2);
7960 CEntryStub ces(1, save_fp_regs ? kSaveFPRegs : kDontSaveFPRegs);
7961 __ Call(ces.GetCode(masm->isolate()), RelocInfo::CODE_TARGET); 7590 __ Call(ces.GetCode(masm->isolate()), RelocInfo::CODE_TARGET);
7962 int parameter_count_offset = 7591 int parameter_count_offset =
7963 StubFailureTrampolineFrame::kCallerStackParameterCountFrameOffset; 7592 StubFailureTrampolineFrame::kCallerStackParameterCountFrameOffset;
7964 __ ldr(r1, MemOperand(fp, parameter_count_offset)); 7593 __ ldr(r1, MemOperand(fp, parameter_count_offset));
7965 if (function_mode_ == JS_FUNCTION_STUB_MODE) { 7594 if (function_mode_ == JS_FUNCTION_STUB_MODE) {
7966 __ add(r1, r1, Operand(1)); 7595 __ add(r1, r1, Operand(1));
7967 } 7596 }
7968 masm->LeaveFrame(StackFrame::STUB_FAILURE_TRAMPOLINE); 7597 masm->LeaveFrame(StackFrame::STUB_FAILURE_TRAMPOLINE);
7969 __ mov(r1, Operand(r1, LSL, kPointerSizeLog2)); 7598 __ mov(r1, Operand(r1, LSL, kPointerSizeLog2));
7970 __ add(sp, sp, r1); 7599 __ add(sp, sp, r1);
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
8029 7658
8030 __ Pop(lr, r5, r1); 7659 __ Pop(lr, r5, r1);
8031 __ Ret(); 7660 __ Ret();
8032 } 7661 }
8033 7662
8034 #undef __ 7663 #undef __
8035 7664
8036 } } // namespace v8::internal 7665 } } // namespace v8::internal
8037 7666
8038 #endif // V8_TARGET_ARCH_ARM 7667 #endif // V8_TARGET_ARCH_ARM
OLDNEW
« no previous file with comments | « src/arm/code-stubs-arm.h ('k') | src/arm/codegen-arm.cc » ('j') | src/arm/macro-assembler-arm.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698