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

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

Issue 6594009: Implement int32 TypeRecordingBinaryOp on ARM. (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: Created 9 years, 10 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 2011 the V8 project authors. All rights reserved. 1 // Copyright 2011 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 380 matching lines...) Expand 10 before | Expand all | Expand 10 after
391 // either r0 or r1 is not a number (not smi and not heap number object) the 391 // either r0 or r1 is not a number (not smi and not heap number object) the
392 // not_number label is jumped to with r0 and r1 intact. 392 // not_number label is jumped to with r0 and r1 intact.
393 static void LoadOperands(MacroAssembler* masm, 393 static void LoadOperands(MacroAssembler* masm,
394 FloatingPointHelper::Destination destination, 394 FloatingPointHelper::Destination destination,
395 Register heap_number_map, 395 Register heap_number_map,
396 Register scratch1, 396 Register scratch1,
397 Register scratch2, 397 Register scratch2,
398 Label* not_number); 398 Label* not_number);
399 399
400 // Loads the number from object into dst as a 32-bit integer if possible. If 400 // Loads the number from object into dst as a 32-bit integer if possible. If
401 // the object is not a 32-bit integer control continues at the label 401 // the object cannot be converted to a 32-bit integer control continues at
402 // not_int32. If VFP is supported double_scratch is used but not scratch2. 402 // the label not_int32. If VFP is supported double_scratch is used
403 // but not scratch2.
404 // Floating point value in the 32bit integer range will be rounded
405 // to an integer.
403 static void LoadNumberAsInteger(MacroAssembler* masm, 406 static void LoadNumberAsInteger(MacroAssembler* masm,
404 Register object, 407 Register object,
405 Register dst, 408 Register dst,
406 Register heap_number_map, 409 Register heap_number_map,
407 Register scratch1, 410 Register scratch1,
408 Register scratch2, 411 Register scratch2,
409 DwVfpRegister double_scratch, 412 DwVfpRegister double_scratch,
410 Label* not_int32); 413 Label* not_int32);
411 414
415 // Load the number from object into double_dst in the double format.
416 // Control will jump to not_int32 if the value cannot be exactly represented
417 // by a 32bit integer.
418 // Floating point value in the 32bit integer range that are not exact integer
419 // won't be loaded.
420 static void LoadNumberAsInt32Double(MacroAssembler* masm,
421 Register object,
422 Destination destination,
423 DwVfpRegister double_dst,
424 Register dst1,
425 Register dst2,
426 Register heap_number_map,
427 Register scratch1,
428 Register scratch2,
429 SwVfpRegister single_scratch,
430 Label* not_int32);
431
432 // Loads the number from object into dst as a 32bit integer.
433 // Control will jump to not_int32 if the object cannot be exactly represented
434 // by a 32bit integer.
435 // Floating point value in the 32bit integer range that are not exact integer
436 // won't be converted.
437 // scratch3 is not used when VFP3 is supported.
438 static void LoadNumberAsInt32(MacroAssembler* masm,
439 Register object,
440 Register dst,
441 Register heap_number_map,
442 Register scratch1,
443 Register scratch2,
444 Register scratch3,
445 DwVfpRegister double_scratch,
446 Label* not_int32);
447
448 // Generate non VFP3 code to check if a double can be exactly represented by a
449 // 32bit integer. This does not check for 0 or -0, which need
450 // to be checked for separately.
451 // Control jumps to not_int32 if the value is not a 32bit integer, and falls
452 // through otherwise.
453 // src1 and src2 will be cloberred.
454 //
455 // Expected input:
456 // - src1: higher (exponent) part of the double value.
457 // - src2: lower (mantissa) part of the double value.
458 // Output status:
459 // - dst: 32 higher bits of the mantissa. (mantissa[51:20])
460 // - src2: contains 1.
461 // - other registers are clobbered.
462 static void DoubleIs32BitInteger(MacroAssembler* masm,
463 Register src1,
464 Register src2,
465 Register dst,
466 Register scratch,
467 Label* not_int32);
468
469 // Generates code to call a C function to do a double operation using core
470 // registers. (Used when VFP3 is not supported.)
471 // This code never falls through, but returns with a heap number containing
472 // the result in r0.
473 // Register heapnumber_result must be a heap number in which the
474 // result of the operation will be stored.
475 // Requires the following layout on entry:
476 // r0: Left value (least significant part of mantissa).
477 // r1: Left value (sign, exponent, top of mantissa).
478 // r2: Right value (least significant part of mantissa).
479 // r3: Right value (sign, exponent, top of mantissa).
480 static void CallCCodeForDoubleOperation(MacroAssembler* masm,
481 Token::Value op,
482 Register heap_number_result,
483 Register scratch);
484
412 private: 485 private:
413 static void LoadNumber(MacroAssembler* masm, 486 static void LoadNumber(MacroAssembler* masm,
414 FloatingPointHelper::Destination destination, 487 FloatingPointHelper::Destination destination,
415 Register object, 488 Register object,
416 DwVfpRegister dst, 489 DwVfpRegister dst,
417 Register dst1, 490 Register dst1,
418 Register dst2, 491 Register dst2,
419 Register heap_number_map, 492 Register heap_number_map,
420 Register scratch1, 493 Register scratch1,
421 Register scratch2, 494 Register scratch2,
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after
553 __ b(ne, not_int32); 626 __ b(ne, not_int32);
554 __ ConvertToInt32( 627 __ ConvertToInt32(
555 object, dst, scratch1, scratch2, double_scratch, not_int32); 628 object, dst, scratch1, scratch2, double_scratch, not_int32);
556 __ jmp(&done); 629 __ jmp(&done);
557 __ bind(&is_smi); 630 __ bind(&is_smi);
558 __ SmiUntag(dst, object); 631 __ SmiUntag(dst, object);
559 __ bind(&done); 632 __ bind(&done);
560 } 633 }
561 634
562 635
636 void FloatingPointHelper::LoadNumberAsInt32Double(MacroAssembler* masm,
637 Register object,
638 Destination destination,
639 DwVfpRegister double_dst,
640 Register dst1,
641 Register dst2,
642 Register heap_number_map,
643 Register scratch1,
644 Register scratch2,
645 SwVfpRegister single_scratch,
646 Label* not_int32) {
647 ASSERT(!scratch1.is(object) && !scratch2.is(object));
648 ASSERT(!scratch1.is(scratch2));
649 ASSERT(!heap_number_map.is(object) &&
650 !heap_number_map.is(scratch1) &&
651 !heap_number_map.is(scratch2));
652
653 Label done, obj_is_heap_number;
654
655 __ JumpIfNotSmi(object, &obj_is_heap_number);
656 __ SmiUntag(scratch1, object);
657 if (CpuFeatures::IsSupported(VFP3)) {
658 CpuFeatures::Scope scope(VFP3);
659 __ vmov(single_scratch, scratch1);
660 __ vcvt_f64_s32(double_dst, single_scratch);
661 if (destination == kCoreRegisters) {
662 __ vmov(dst1, dst2, double_dst);
663 }
664 } else {
665 Label fewer_than_20_useful_bits;
666 // Expected output:
667 // | dst1 | dst2 |
668 // | s | exp | mantissa |
669
670 // Check for zero.
671 __ cmp(scratch1, Operand(0));
672 __ mov(dst1, scratch1);
673 __ mov(dst2, scratch1);
674 __ b(eq, &done);
675
676 // Preload the sign of the value.
677 __ and_(dst1, scratch1, Operand(HeapNumber::kSignMask), SetCC);
678 // Get the absolute value of the object (as an unsigned integer).
679 __ rsb(scratch1, scratch1, Operand(0), SetCC, mi);
680
681 // Get mantisssa[51:20].
682
683 // Get the position of the first set bit.
684 __ CountLeadingZeros(dst2, scratch1, scratch2);
685 __ rsb(dst2, dst2, Operand(31));
686
687 // Set the exponent.
688 __ add(scratch2, dst2, Operand(HeapNumber::kExponentBias));
689 __ Bfi(dst1, scratch2, scratch2,
690 HeapNumber::kExponentShift, HeapNumber::kExponentBits);
691
692 // Clear the first non null bit.
693 __ mov(scratch2, Operand(1));
694 __ bic(scratch1, scratch1, Operand(scratch2, LSL, dst2));
695
696 __ cmp(dst2, Operand(HeapNumber::kMantissaBitsInTopWord));
697 // Get the number of bits to set in the lower part of the mantissa.
698 __ sub(scratch2, dst2, Operand(HeapNumber::kMantissaBitsInTopWord), SetCC);
699 __ b(mi, &fewer_than_20_useful_bits);
700 // Set the higher 20 bits of the mantissa.
701 __ orr(dst1, dst1, Operand(scratch1, LSR, scratch2));
702 __ rsb(scratch2, scratch2, Operand(32));
703 __ mov(dst2, Operand(scratch1, LSL, scratch2));
704 __ b(&done);
705
706 __ bind(&fewer_than_20_useful_bits);
707 __ rsb(scratch2, dst2, Operand(HeapNumber::kMantissaBitsInTopWord));
708 __ mov(scratch2, Operand(scratch1, LSL, scratch2));
709 __ orr(dst1, dst1, scratch2);
710 // Set dst2 to 0.
711 __ mov(dst2, Operand(0));
712 }
713
714 __ b(&done);
715
716 __ bind(&obj_is_heap_number);
Søren Thygesen Gjesse 2011/02/28 09:54:32 Please change this label to obj_is_not_smi.
Søren Thygesen Gjesse 2011/03/02 09:33:08 Done.
717 if (FLAG_debug_code) {
718 __ AbortIfNotRootValue(heap_number_map,
719 Heap::kHeapNumberMapRootIndex,
720 "HeapNumberMap register clobbered.");
721 }
722 __ JumpIfNotHeapNumber(object, heap_number_map, scratch1, not_int32);
723
724 // Load the number.
725 if (CpuFeatures::IsSupported(VFP3)) {
726 CpuFeatures::Scope scope(VFP3);
727 // Load the double value.
728 __ sub(scratch1, object, Operand(kHeapObjectTag));
729 __ vldr(double_dst, scratch1, HeapNumber::kValueOffset);
730
731 __ EmitVFPTruncate(kRoundToZero,
732 single_scratch,
733 double_dst,
734 scratch1,
735 scratch2,
736 kCheckForInexactConversion);
737
738 // Jump to not_int32 if the operation did not succeed.
739 __ b(ne, not_int32);
740
741 if (destination == kCoreRegisters) {
742 __ vmov(dst1, dst2, double_dst);
743 }
744
745 } else {
746 ASSERT(!scratch1.is(object) && !scratch2.is(object));
747 // Load the double value in the destination registers..
748 __ Ldrd(dst1, dst2, FieldMemOperand(object, HeapNumber::kValueOffset));
749
750 // Check for 0 and -0.
751 __ bic(scratch1, dst1, Operand(HeapNumber::kSignMask));
752 __ orr(scratch1, scratch1, Operand(dst2));
753 __ cmp(scratch1, Operand(0));
754 __ b(eq, &done);
755
756 // Check that the value can be exactly represented by a 32bit integer.
757 // Jump to not_int32 if that's not the case.
758 DoubleIs32BitInteger(masm, dst1, dst2, scratch1, scratch2, not_int32);
759
760 // dst1 and dst2 were trashed. Reload the double value.
761 __ Ldrd(dst1, dst2, FieldMemOperand(object, HeapNumber::kValueOffset));
762 }
763
764 __ bind(&done);
765 }
766
767
768 void FloatingPointHelper::LoadNumberAsInt32(MacroAssembler* masm,
769 Register object,
770 Register dst,
771 Register heap_number_map,
772 Register scratch1,
773 Register scratch2,
774 Register scratch3,
775 DwVfpRegister double_scratch,
776 Label* not_int32) {
777 ASSERT(!dst.is(object));
778 ASSERT(!scratch1.is(object) && !scratch2.is(object) && !scratch3.is(object));
779 ASSERT(!scratch1.is(scratch2) &&
780 !scratch1.is(scratch3) &&
781 !scratch2.is(scratch3));
782
783 Label done;
784
785 // Untag the object in the destination register.
Søren Thygesen Gjesse 2011/02/28 09:54:32 in -> into
Søren Thygesen Gjesse 2011/03/02 09:33:08 Done.
786 __ SmiUntag(dst, object);
787 // Just return if the object is a smi.
788 __ JumpIfSmi(object, &done);
789
790 if (FLAG_debug_code) {
791 __ AbortIfNotRootValue(heap_number_map,
792 Heap::kHeapNumberMapRootIndex,
793 "HeapNumberMap register clobbered.");
794 }
795 __ JumpIfNotHeapNumber(object, heap_number_map, scratch1, not_int32);
796
797 // Object is a heap number.
798 // Convert the floating point value to a 32bit integer.
799 if (CpuFeatures::IsSupported(VFP3)) {
800 CpuFeatures::Scope scope(VFP3);
801 SwVfpRegister single_scratch = double_scratch.low();
802 // Load the double value.
803 __ sub(scratch1, object, Operand(kHeapObjectTag));
804 __ vldr(double_scratch, scratch1, HeapNumber::kValueOffset);
805
806 __ EmitVFPTruncate(kRoundToZero,
807 single_scratch,
808 double_scratch,
809 scratch1,
810 scratch2,
811 kCheckForInexactConversion);
812
813 // Jump to not_int32 if the operation did not succeed.
814 __ b(ne, not_int32);
815 // Get the result in the destination register.
816 __ vmov(dst, single_scratch);
817
818 } else {
819 // Load the double value in the destination registers..
Søren Thygesen Gjesse 2011/02/28 09:54:32 .. -> .
Søren Thygesen Gjesse 2011/03/02 09:33:08 Done.
820 __ ldr(scratch1, FieldMemOperand(object, HeapNumber::kExponentOffset));
821 __ ldr(scratch2, FieldMemOperand(object, HeapNumber::kMantissaOffset));
822
823 // Check for 0 and -0.
824 __ bic(dst, scratch1, Operand(HeapNumber::kSignMask));
825 __ orr(dst, scratch2, Operand(dst));
826 __ cmp(dst, Operand(0));
827 __ b(eq, &done);
828
829 DoubleIs32BitInteger(masm, scratch1, scratch2, dst, scratch3, not_int32);
830
831 // Registers state after DoubleIs32BitInteger.
832 // dst: mantissa[51:20].
833 // scratch2: 1
834
835 // Shift back the higher bits of the mantissa.
836 __ mov(dst, Operand(dst, LSR, scratch3));
837 // Set the implicit first bit.
838 __ rsb(scratch3, scratch3, Operand(32));
839 __ orr(dst, dst, Operand(scratch2, LSL, scratch3));
840 // Set the sign.
841 __ ldr(scratch1, FieldMemOperand(object, HeapNumber::kExponentOffset));
842 __ tst(scratch1, Operand(HeapNumber::kSignMask));
843 __ rsb(dst, dst, Operand(0), LeaveCC, mi);
844 }
845
846 __ bind(&done);
847 }
848
849
850 void FloatingPointHelper::DoubleIs32BitInteger(MacroAssembler* masm,
851 Register src1,
852 Register src2,
853 Register dst,
854 Register scratch,
855 Label* not_int32) {
856 // Get exponent alone in scratch.
857 __ Ubfx(scratch,
858 src1,
859 HeapNumber::kExponentShift,
860 HeapNumber::kExponentBits);
861
862 // Substract the bias from the exponent.
863 __ sub(scratch, scratch, Operand(HeapNumber::kExponentBias), SetCC);
864
865 // src1: higher (exponent) part of the double value.
866 // src2: lower (mantissa) part of the double value.
867 // scratch: unbiased exponent.
868
869 // Fast cases. Check for obvious non 32bit integer values.
870 // Negative exponent cannot yield 32bit integers.
871 __ b(mi, not_int32);
872 // Exponent greater than 31 cannot yield 32bit integers.
873 // Also, a positive value with an exponent equal to 31 is outside of the
874 // signed 32bit integer range.
875 __ tst(src1, Operand(HeapNumber::kSignMask));
Søren Thygesen Gjesse 2011/02/28 09:54:32 Maybe add a bit more commenting here would be nice
Søren Thygesen Gjesse 2011/03/02 09:33:08 Done.
876 __ cmp(scratch, Operand(30), eq);
877 __ cmp(scratch, Operand(31), ne);
878 __ b(gt, not_int32);
879 // - Bits [21:0] in the mantissa are not null.
880 __ tst(src2, Operand(0x3fffff));
881 __ b(ne, not_int32);
882
883 // Otherwise the exponent needs to be big enough to shift left all the
884 // non zero bits left. So we need the (30 - exponent) last bits of the
885 // 31 higher bits of the mantissa to be null.
886 // Because bits [21:20] are null, we can check instead that the
Søren Thygesen Gjesse 2011/02/28 09:54:32 20 -> 0?
Søren Thygesen Gjesse 2011/03/02 09:33:08 Done.
887 // (32 - exponent) last bits of the 32 higher bits of the mantisssa are null.
888
889 // Get the 32 higher bits of the mantissa in dst.
890 __ Ubfx(dst, src2, HeapNumber::kMantissaBitsInTopWord, 12);
Søren Thygesen Gjesse 2011/02/28 09:54:32 12 -> 32 - HeapNumber::kMantissaBitsInTopWord
Søren Thygesen Gjesse 2011/03/02 09:33:08 Done.
891 __ orr(dst,
892 dst,
893 Operand(src1, LSL, HeapNumber::kNonMantissaBitsInTopWord));
894
895 // Create the mask and test the lower bits (of the higher bits).
896 __ rsb(scratch, scratch, Operand(32));
897 __ mov(src2, Operand(1));
898 __ mov(src1, Operand(src2, LSL, scratch));
899 __ sub(src1, src1, Operand(1));
900 __ tst(dst, src1);
901 __ b(ne, not_int32);
902 }
903
904
905 void FloatingPointHelper::CallCCodeForDoubleOperation(
906 MacroAssembler* masm,
907 Token::Value op,
908 Register heap_number_result,
909 Register scratch) {
910 // Using core registers:
911 // r0: Left value (least significant part of mantissa).
912 // r1: Left value (sign, exponent, top of mantissa).
913 // r2: Right value (least significant part of mantissa).
914 // r3: Right value (sign, exponent, top of mantissa).
915
916 // Assert that heap_number_result is callee-saved.
917 // We currently always use r5 to pass it.
918 ASSERT(heap_number_result.is(r5));
919
920 // Push the current return address before the C call. Return will be
921 // through pop(pc) below.
922 __ push(lr);
923 __ PrepareCallCFunction(4, scratch); // Two doubles are 4 arguments.
924 // Call C routine that may not cause GC or other trouble.
925 __ CallCFunction(ExternalReference::double_fp_operation(op), 4);
926 // Store answer in the overwritable heap number.
927 #if !defined(USE_ARM_EABI)
928 // Double returned in fp coprocessor register 0 and 1, encoded as
929 // register cr8. Offsets must be divisible by 4 for coprocessor so we
930 // need to substract the tag from heap_number_result.
931 __ sub(scratch, heap_number_result, Operand(kHeapObjectTag));
932 __ stc(p1, cr8, MemOperand(scratch, HeapNumber::kValueOffset));
933 #else
934 // Double returned in registers 0 and 1.
935 __ Strd(r0, r1, FieldMemOperand(heap_number_result,
936 HeapNumber::kValueOffset));
937 #endif
938 // Place heap_number_result in r0 and return to the pushed return address.
939 __ mov(r0, Operand(heap_number_result));
940 __ pop(pc);
941 }
942
563 943
564 // See comment for class. 944 // See comment for class.
565 void WriteInt32ToHeapNumberStub::Generate(MacroAssembler* masm) { 945 void WriteInt32ToHeapNumberStub::Generate(MacroAssembler* masm) {
566 Label max_negative_int; 946 Label max_negative_int;
567 // the_int_ has the answer which is a signed int32 but not a Smi. 947 // the_int_ has the answer which is a signed int32 but not a Smi.
568 // We test for the special value that has a different exponent. This test 948 // We test for the special value that has a different exponent. This test
569 // has the neat side effect of setting the flags according to the sign. 949 // has the neat side effect of setting the flags according to the sign.
570 STATIC_ASSERT(HeapNumber::kSignMask == 0x80000000u); 950 STATIC_ASSERT(HeapNumber::kSignMask == 0x80000000u);
571 __ cmp(the_int_, Operand(0x80000000u)); 951 __ cmp(the_int_, Operand(0x80000000u));
572 __ b(eq, &max_negative_int); 952 __ b(eq, &max_negative_int);
(...skipping 2124 matching lines...) Expand 10 before | Expand all | Expand 10 after
2697 break; 3077 break;
2698 default: 3078 default:
2699 UNREACHABLE(); 3079 UNREACHABLE();
2700 } 3080 }
2701 3081
2702 __ sub(r0, result, Operand(kHeapObjectTag)); 3082 __ sub(r0, result, Operand(kHeapObjectTag));
2703 __ vstr(d5, r0, HeapNumber::kValueOffset); 3083 __ vstr(d5, r0, HeapNumber::kValueOffset);
2704 __ add(r0, r0, Operand(kHeapObjectTag)); 3084 __ add(r0, r0, Operand(kHeapObjectTag));
2705 __ Ret(); 3085 __ Ret();
2706 } else { 3086 } else {
2707 // Using core registers: 3087 // Call the C function to handle the double operation.
2708 // r0: Left value (least significant part of mantissa). 3088 FloatingPointHelper::CallCCodeForDoubleOperation(masm,
2709 // r1: Left value (sign, exponent, top of mantissa). 3089 op_,
2710 // r2: Right value (least significant part of mantissa). 3090 result,
2711 // r3: Right value (sign, exponent, top of mantissa). 3091 scratch1);
2712
2713 // Push the current return address before the C call. Return will be
2714 // through pop(pc) below.
2715 __ push(lr);
2716 __ PrepareCallCFunction(4, scratch1); // Two doubles are 4 arguments.
2717 // Call C routine that may not cause GC or other trouble. r5 is callee
2718 // save.
2719 __ CallCFunction(ExternalReference::double_fp_operation(op_), 4);
2720 // Store answer in the overwritable heap number.
2721 #if !defined(USE_ARM_EABI)
2722 // Double returned in fp coprocessor register 0 and 1, encoded as
2723 // register cr8. Offsets must be divisible by 4 for coprocessor so we
2724 // need to substract the tag from r5.
2725 __ sub(scratch1, result, Operand(kHeapObjectTag));
2726 __ stc(p1, cr8, MemOperand(scratch1, HeapNumber::kValueOffset));
2727 #else
2728 // Double returned in registers 0 and 1.
2729 __ Strd(r0, r1, FieldMemOperand(result, HeapNumber::kValueOffset));
2730 #endif
2731 // Plase result in r0 and return to the pushed return address.
2732 __ mov(r0, Operand(result));
2733 __ pop(pc);
2734 } 3092 }
2735 break; 3093 break;
2736 } 3094 }
2737 case Token::BIT_OR: 3095 case Token::BIT_OR:
2738 case Token::BIT_XOR: 3096 case Token::BIT_XOR:
2739 case Token::BIT_AND: 3097 case Token::BIT_AND:
2740 case Token::SAR: 3098 case Token::SAR:
2741 case Token::SHR: 3099 case Token::SHR:
2742 case Token::SHL: { 3100 case Token::SHL: {
2743 if (smi_operands) { 3101 if (smi_operands) {
(...skipping 25 matching lines...) Expand all
2769 __ orr(r2, r3, Operand(r2)); 3127 __ orr(r2, r3, Operand(r2));
2770 break; 3128 break;
2771 case Token::BIT_XOR: 3129 case Token::BIT_XOR:
2772 __ eor(r2, r3, Operand(r2)); 3130 __ eor(r2, r3, Operand(r2));
2773 break; 3131 break;
2774 case Token::BIT_AND: 3132 case Token::BIT_AND:
2775 __ and_(r2, r3, Operand(r2)); 3133 __ and_(r2, r3, Operand(r2));
2776 break; 3134 break;
2777 case Token::SAR: 3135 case Token::SAR:
2778 // Use only the 5 least significant bits of the shift count. 3136 // Use only the 5 least significant bits of the shift count.
2779 __ and_(r2, r2, Operand(0x1f));
2780 __ GetLeastBitsFromInt32(r2, r2, 5); 3137 __ GetLeastBitsFromInt32(r2, r2, 5);
2781 __ mov(r2, Operand(r3, ASR, r2)); 3138 __ mov(r2, Operand(r3, ASR, r2));
2782 break; 3139 break;
2783 case Token::SHR: 3140 case Token::SHR:
2784 // Use only the 5 least significant bits of the shift count. 3141 // Use only the 5 least significant bits of the shift count.
2785 __ GetLeastBitsFromInt32(r2, r2, 5); 3142 __ GetLeastBitsFromInt32(r2, r2, 5);
2786 __ mov(r2, Operand(r3, LSR, r2), SetCC); 3143 __ mov(r2, Operand(r3, LSR, r2), SetCC);
2787 // SHR is special because it is required to produce a positive answer. 3144 // SHR is special because it is required to produce a positive answer.
2788 // The code below for writing into heap numbers isn't capable of 3145 // The code below for writing into heap numbers isn't capable of
2789 // writing the register as an unsigned int so we go to slow case if we 3146 // writing the register as an unsigned int so we go to slow case if we
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after
2914 // Try to add arguments as strings, otherwise, transition to the generic 3271 // Try to add arguments as strings, otherwise, transition to the generic
2915 // TRBinaryOpIC type. 3272 // TRBinaryOpIC type.
2916 GenerateAddStrings(masm); 3273 GenerateAddStrings(masm);
2917 GenerateTypeTransition(masm); 3274 GenerateTypeTransition(masm);
2918 } 3275 }
2919 3276
2920 3277
2921 void TypeRecordingBinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) { 3278 void TypeRecordingBinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) {
2922 ASSERT(operands_type_ == TRBinaryOpIC::INT32); 3279 ASSERT(operands_type_ == TRBinaryOpIC::INT32);
2923 3280
3281 Register left = r1;
3282 Register right = r0;
3283 Register scratch1 = r7;
3284 Register scratch2 = r9;
3285 DwVfpRegister double_scratch = d0;
3286 SwVfpRegister single_scratch = s3;
3287
3288 Register heap_number_result = no_reg;
3289 Register heap_number_map = r6;
3290 __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
3291
3292 Label call_runtime, restore_left_and_call_runtime;
3293 // Labels for type transition, used for wrong input or output types.
3294 // Both label are currently actually bound to the same position. We use two
3295 // different label to differentiate the cause leading to type transition.
3296 Label input_transition, output_transition;
3297
3298 // Smi-smi fast case.
3299 Label skip;
3300 __ orr(scratch1, left, right);
3301 __ JumpIfNotSmi(scratch1, &skip);
3302 GenerateSmiSmiOperation(masm);
3303 // Fall through if the result is not a smi.
3304 __ bind(&skip);
3305
3306 switch (op_) {
3307 case Token::ADD:
3308 case Token::SUB:
3309 case Token::MUL:
3310 case Token::DIV:
3311 case Token::MOD: {
3312 // Load both operands and chech that they are 32bit integer.
3313 // Jump to type transition if they are not.
3314 FloatingPointHelper::Destination destination =
3315 CpuFeatures::IsSupported(VFP3) && op_ != Token::MOD ?
3316 FloatingPointHelper::kVFPRegisters :
3317 FloatingPointHelper::kCoreRegisters;
3318
Søren Thygesen Gjesse 2011/02/28 09:54:32 Maybe add a comment here that r0 and r1 are preser
Søren Thygesen Gjesse 2011/03/02 09:33:08 Done.
3319 FloatingPointHelper::LoadNumberAsInt32Double(masm,
3320 right,
3321 destination,
3322 d7,
3323 r2,
3324 r3,
3325 heap_number_map,
3326 scratch1,
3327 scratch2,
3328 s0,
3329 &input_transition);
3330 FloatingPointHelper::LoadNumberAsInt32Double(masm,
3331 left,
3332 destination,
3333 d6,
3334 r4,
3335 r5,
3336 heap_number_map,
3337 scratch1,
3338 scratch2,
3339 s0,
3340 &input_transition);
3341
3342 if (destination == FloatingPointHelper::kVFPRegisters) {
3343 CpuFeatures::Scope scope(VFP3);
3344 Label return_heap_number;
3345 switch (op_) {
3346 case Token::ADD:
3347 __ vadd(d5, d6, d7);
3348 break;
3349 case Token::SUB:
3350 __ vsub(d5, d6, d7);
3351 break;
3352 case Token::MUL:
3353 __ vmul(d5, d6, d7);
3354 break;
3355 case Token::DIV:
3356 __ vdiv(d5, d6, d7);
3357 break;
3358 default:
3359 UNREACHABLE();
3360 }
3361
3362 if (op_ != Token::DIV) {
3363 // These operations produce an integer result.
3364 // Try to return a smi if we can.
3365 // Otherwise return a heap number if allowed, or jump to type
3366 // transition.
3367
3368 __ EmitVFPTruncate(kRoundToZero,
3369 single_scratch,
3370 d5,
3371 scratch1,
3372 scratch2);
3373
3374 if (result_type_ <= TRBinaryOpIC::INT32) {
3375 // If the ne condition is set, result does
3376 // not fit in a 32bit integer.
3377 __ b(ne, &output_transition);
3378 }
3379
3380 // Check if the result fits in a smi.
3381 __ vmov(scratch1, single_scratch);
3382 __ add(scratch2, scratch1, Operand(0x40000000), SetCC);
3383 // If not try to return a heap number.
3384 __ b(mi, &return_heap_number);
3385 // Tag the result and return.
3386 __ SmiTag(r0, scratch1);
3387 __ Ret();
3388 }
3389
3390 if (result_type_ >= (op_ == Token::DIV) ? TRBinaryOpIC::HEAP_NUMBER
3391 : TRBinaryOpIC::INT32) {
3392 __ bind(&return_heap_number);
3393 // We are using vfp registers so r5 is available.
3394 heap_number_result = r5;
3395 GenerateHeapResultAllocation(masm,
3396 heap_number_result,
3397 heap_number_map,
3398 scratch1,
3399 scratch2,
3400 &call_runtime);
3401 __ sub(r0, heap_number_result, Operand(kHeapObjectTag));
3402 __ vstr(d5, r0, HeapNumber::kValueOffset);
3403 __ mov(r0, heap_number_result);
3404 __ Ret();
3405 }
3406
3407 // A DIV operation expecting an integer result falls through
3408 // to type transition.
3409
3410 } else {
3411 // We preserved r0 and r1 to be able to call runtime.
3412 // Save the left value on the stack.
3413 __ Push(r5, r4);
3414
3415 // Allocate a heap number to store the result.
3416 heap_number_result = r5;
3417 GenerateHeapResultAllocation(masm,
3418 heap_number_result,
3419 heap_number_map,
3420 scratch1,
3421 scratch2,
3422 &call_runtime);
3423
3424 // Load the left value from the value saved on the stack.
3425 __ Pop(r1, r0);
3426
3427 // Call the C function to handle the double operation.
3428 FloatingPointHelper::CallCCodeForDoubleOperation(
3429 masm, op_, heap_number_result, scratch1);
3430 }
3431
3432 break;
3433 }
3434
3435 case Token::BIT_OR:
3436 case Token::BIT_XOR:
3437 case Token::BIT_AND:
3438 case Token::SAR:
3439 case Token::SHR:
3440 case Token::SHL: {
3441 Label return_heap_number;
3442 Register scratch3 = r5;
3443 // Convert operands to 32-bit integers. Right in r2 and left in r3.
Søren Thygesen Gjesse 2011/02/28 09:54:32 Add "Preserve r0 and r1 for the runtime call to th
Søren Thygesen Gjesse 2011/03/02 09:33:08 Done.
3444 FloatingPointHelper::LoadNumberAsInt32(masm,
3445 left,
3446 r3,
3447 heap_number_map,
3448 scratch1,
3449 scratch2,
3450 scratch3,
3451 d0,
3452 &input_transition);
3453 FloatingPointHelper::LoadNumberAsInt32(masm,
3454 right,
3455 r2,
3456 heap_number_map,
3457 scratch1,
3458 scratch2,
3459 scratch3,
3460 d0,
3461 &input_transition);
3462
3463 // The ECMA-262 standard specifies that, for shift operations, only the
3464 // 5 least significant bits of the shift value should be used.
3465 switch (op_) {
3466 case Token::BIT_OR:
3467 __ orr(r2, r3, Operand(r2));
3468 break;
3469 case Token::BIT_XOR:
3470 __ eor(r2, r3, Operand(r2));
3471 break;
3472 case Token::BIT_AND:
3473 __ and_(r2, r3, Operand(r2));
3474 break;
3475 case Token::SAR:
3476 __ and_(r2, r2, Operand(0x1f));
3477 __ mov(r2, Operand(r3, ASR, r2));
3478 break;
3479 case Token::SHR:
3480 __ and_(r2, r2, Operand(0x1f));
3481 __ mov(r2, Operand(r3, LSR, r2), SetCC);
3482 // SHR is special because it is required to produce a positive answer.
3483 // We only get a negative result if the shift value (r2) is 0.
3484 // This result cannot be respresented as a signed 32bit integer, try
3485 // to return a heap number if we can.
3486 // The non vfp3 code does not support this special case, so jump to
Søren Thygesen Gjesse 2011/02/28 09:54:32 Can we fix WriteInt32ToHeapNumberStub to avoid a r
Søren Thygesen Gjesse 2011/03/02 09:33:08 Postponed.
3487 // runtime if we don't support it.
3488 if (CpuFeatures::IsSupported(VFP3)) {
Søren Thygesen Gjesse 2011/02/28 09:54:32 No need to actually enter VFP3 scope here, as the
Søren Thygesen Gjesse 2011/03/02 09:33:08 Done.
3489 CpuFeatures::Scope scope(VFP3);
3490 __ b(mi,
3491 (result_type_ <= TRBinaryOpIC::INT32) ? &output_transition
3492 : &return_heap_number);
3493 } else {
3494 __ b(mi, (result_type_ <= TRBinaryOpIC::INT32) ? &output_transition
3495 : &call_runtime);
3496 }
3497 break;
3498 case Token::SHL:
3499 __ and_(r2, r2, Operand(0x1f));
3500 __ mov(r2, Operand(r3, LSL, r2));
3501 break;
3502 default:
3503 UNREACHABLE();
3504 }
3505
3506 // Check if the result fits in a smi.
3507 __ add(scratch1, r2, Operand(0x40000000), SetCC);
3508 // If not try to return a heap number. (We know the result is an int32.)
3509 __ b(mi, &return_heap_number);
3510 // Tag the result and return.
3511 __ SmiTag(r0, r2);
3512 __ Ret();
3513
3514 __ bind(&return_heap_number);
3515 if (CpuFeatures::IsSupported(VFP3)) {
3516 CpuFeatures::Scope scope(VFP3);
3517 heap_number_result = r5;
3518 GenerateHeapResultAllocation(masm,
3519 heap_number_result,
3520 heap_number_map,
3521 scratch1,
3522 scratch2,
3523 &call_runtime);
3524
3525 if (op_ != Token::SHR) {
3526 // Convert the result to a floating point value.
3527 __ vmov(double_scratch.low(), r2);
3528 __ vcvt_f64_s32(double_scratch, double_scratch.low());
3529 } else {
3530 // The result must be interpreted as an unsigned 32bit integer.
3531 __ vmov(double_scratch.low(), r2);
3532 __ vcvt_f64_u32(double_scratch, double_scratch.low());
3533 }
3534
3535 // Store the result.
3536 __ sub(r0, heap_number_result, Operand(kHeapObjectTag));
3537 __ vstr(double_scratch, r0, HeapNumber::kValueOffset);
3538 __ mov(r0, heap_number_result);
3539 __ Ret();
3540 } else {
3541 // Tail call that writes the int32 in r2 to the heap number in r0, using
3542 // r3 as scratch. r0 is preserved and returned.
3543 WriteInt32ToHeapNumberStub stub(r2, r0, r3);
3544 __ TailCallStub(&stub);
3545 }
3546
3547 break;
3548 }
3549
3550 default:
3551 UNREACHABLE();
3552 }
3553
3554 __ bind(&input_transition);
3555 __ bind(&output_transition);
2924 GenerateTypeTransition(masm); 3556 GenerateTypeTransition(masm);
3557
Søren Thygesen Gjesse 2011/02/28 09:54:32 I see no jump to this label - dead code?
Søren Thygesen Gjesse 2011/03/02 09:33:08 Removed.
3558 __ bind(&restore_left_and_call_runtime);
3559 __ Pop(r1, r0);
3560 __ bind(&call_runtime);
3561 GenerateCallRuntime(masm);
2925 } 3562 }
2926 3563
2927 3564
2928 void TypeRecordingBinaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) { 3565 void TypeRecordingBinaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) {
2929 Label not_numbers, call_runtime; 3566 Label not_numbers, call_runtime;
2930 ASSERT(operands_type_ == TRBinaryOpIC::HEAP_NUMBER); 3567 ASSERT(operands_type_ == TRBinaryOpIC::HEAP_NUMBER);
2931 3568
2932 GenerateFPOperation(masm, false, &not_numbers, &call_runtime); 3569 GenerateFPOperation(masm, false, &not_numbers, &call_runtime);
2933 3570
2934 __ bind(&not_numbers); 3571 __ bind(&not_numbers);
(...skipping 3192 matching lines...) Expand 10 before | Expand all | Expand 10 after
6127 __ strb(untagged_value, MemOperand(external_pointer, untagged_key)); 6764 __ strb(untagged_value, MemOperand(external_pointer, untagged_key));
6128 __ Ret(); 6765 __ Ret();
6129 } 6766 }
6130 6767
6131 6768
6132 #undef __ 6769 #undef __
6133 6770
6134 } } // namespace v8::internal 6771 } } // namespace v8::internal
6135 6772
6136 #endif // V8_TARGET_ARCH_ARM 6773 #endif // V8_TARGET_ARCH_ARM
OLDNEW
« no previous file with comments | « src/arm/assembler-arm.h ('k') | src/arm/constants-arm.h » ('j') | src/arm/lithium-codegen-arm.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698