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

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

Issue 18612005: Implement truncated d-to-i with a stub on x86 (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Merge with ToT Created 7 years, 5 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
« no previous file with comments | « src/code-stubs.h ('k') | src/ia32/lithium-codegen-ia32.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 644 matching lines...) Expand 10 before | Expand all | Expand 10 after
655 // from |scratch|, it will contain that int32 value. 655 // from |scratch|, it will contain that int32 value.
656 static void CheckSSE2OperandIsInt32(MacroAssembler* masm, 656 static void CheckSSE2OperandIsInt32(MacroAssembler* masm,
657 Label* non_int32, 657 Label* non_int32,
658 XMMRegister operand, 658 XMMRegister operand,
659 Register int32_result, 659 Register int32_result,
660 Register scratch, 660 Register scratch,
661 XMMRegister xmm_scratch); 661 XMMRegister xmm_scratch);
662 }; 662 };
663 663
664 664
665 // Get the integer part of a heap number. Surprisingly, all this bit twiddling 665 void DoubleToIStub::Generate(MacroAssembler* masm) {
666 // is faster than using the built-in instructions on floating point registers. 666 Register input_reg = this->source();
667 // Trashes edi and ebx. Dest is ecx. Source cannot be ecx or one of the 667 Register final_result_reg = this->destination();
668 // trashed registers. 668 ASSERT(is_truncating());
669 static void IntegerConvert(MacroAssembler* masm, 669
670 Register source, 670 Label check_negative, process_64_bits, done, done_no_stash;
671 bool use_sse3, 671
672 Label* conversion_failure) { 672 int double_offset = offset();
673 ASSERT(!source.is(ecx) && !source.is(edi) && !source.is(ebx)); 673
674 Label done, right_exponent, normal_exponent; 674 // Account for return address and saved regs if input is esp.
675 Register scratch = ebx; 675 if (input_reg.is(esp)) double_offset += 3 * kPointerSize;
676 Register scratch2 = edi; 676
677 // Get exponent word. 677 MemOperand mantissa_operand(MemOperand(input_reg, double_offset));
678 __ mov(scratch, FieldOperand(source, HeapNumber::kExponentOffset)); 678 MemOperand exponent_operand(MemOperand(input_reg,
679 // Get exponent alone in scratch2. 679 double_offset + kPointerSize));
680 __ mov(scratch2, scratch); 680
681 __ and_(scratch2, HeapNumber::kExponentMask); 681 Register scratch1;
682 __ shr(scratch2, HeapNumber::kExponentShift); 682 {
683 __ sub(scratch2, Immediate(HeapNumber::kExponentBias)); 683 Register scratch_candidates[3] = { ebx, edx, edi };
684 // Load ecx with zero. We use this either for the final shift or 684 for (int i = 0; i < 3; i++) {
685 // for the answer. 685 scratch1 = scratch_candidates[i];
686 __ xor_(ecx, ecx); 686 if (!final_result_reg.is(scratch1) && !input_reg.is(scratch1)) break;
687 // If the exponent is above 83, the number contains no significant 687 }
688 // bits in the range 0..2^31, so the result is zero. 688 }
689 static const uint32_t kResultIsZeroExponent = 83; 689 // Since we must use ecx for shifts below, use some other register (eax)
690 __ cmp(scratch2, Immediate(kResultIsZeroExponent)); 690 // to calculate the result if ecx is the requested return register.
691 Register result_reg = final_result_reg.is(ecx) ? eax : final_result_reg;
692 // Save ecx if it isn't the return register and therefore volatile, or if it
693 // is the return register, then save the temp register we use in its stead for
694 // the result.
695 Register save_reg = final_result_reg.is(ecx) ? eax : ecx;
696 __ push(scratch1);
697 __ push(save_reg);
698
699 bool stash_exponent_copy = !input_reg.is(esp);
700 __ mov(scratch1, mantissa_operand);
701 if (CpuFeatures::IsSupported(SSE3)) {
702 CpuFeatureScope scope(masm, SSE3);
703 // Load x87 register with heap number.
704 __ fld_d(mantissa_operand);
705 }
706 __ mov(ecx, exponent_operand);
707 if (stash_exponent_copy) __ push(ecx);
708
709 __ and_(ecx, HeapNumber::kExponentMask);
710 __ shr(ecx, HeapNumber::kExponentShift);
711 __ lea(result_reg, MemOperand(ecx, -HeapNumber::kExponentBias));
712 __ cmp(result_reg, Immediate(HeapNumber::kMantissaBits));
713 __ j(below, &process_64_bits);
714
715 // Result is entirely in lower 32-bits of mantissa
716 int delta = HeapNumber::kExponentBias + Double::kPhysicalSignificandSize;
717 if (CpuFeatures::IsSupported(SSE3)) {
718 __ fstp(0);
719 }
720 __ sub(ecx, Immediate(delta));
721 __ xor_(result_reg, result_reg);
722 __ cmp(ecx, Immediate(31));
691 __ j(above, &done); 723 __ j(above, &done);
692 if (use_sse3) { 724 __ shl_cl(scratch1);
725 __ jmp(&check_negative);
726
727 __ bind(&process_64_bits);
728 if (CpuFeatures::IsSupported(SSE3)) {
693 CpuFeatureScope scope(masm, SSE3); 729 CpuFeatureScope scope(masm, SSE3);
694 // Check whether the exponent is too big for a 64 bit signed integer. 730 if (stash_exponent_copy) {
695 static const uint32_t kTooBigExponent = 63; 731 // Already a copy of the exponent on the stack, overwrite it.
696 __ cmp(scratch2, Immediate(kTooBigExponent)); 732 STATIC_ASSERT(kDoubleSize == 2 * kPointerSize);
697 __ j(greater_equal, conversion_failure); 733 __ sub(esp, Immediate(kDoubleSize / 2));
698 // Load x87 register with heap number. 734 } else {
699 __ fld_d(FieldOperand(source, HeapNumber::kValueOffset)); 735 // Reserve space for 64 bit answer.
700 // Reserve space for 64 bit answer. 736 __ sub(esp, Immediate(kDoubleSize)); // Nolint.
701 __ sub(esp, Immediate(sizeof(uint64_t))); // Nolint. 737 }
702 // Do conversion, which cannot fail because we checked the exponent. 738 // Do conversion, which cannot fail because we checked the exponent.
703 __ fisttp_d(Operand(esp, 0)); 739 __ fisttp_d(Operand(esp, 0));
704 __ mov(ecx, Operand(esp, 0)); // Load low word of answer into ecx. 740 __ mov(result_reg, Operand(esp, 0)); // Load low word of answer as result
705 __ add(esp, Immediate(sizeof(uint64_t))); // Nolint. 741 __ add(esp, Immediate(kDoubleSize));
742 __ jmp(&done_no_stash);
706 } else { 743 } else {
707 // Check whether the exponent matches a 32 bit signed int that cannot be 744 // Result must be extracted from shifted 32-bit mantissa
708 // represented by a Smi. A non-smi 32 bit integer is 1.xxx * 2^30 so the 745 __ sub(ecx, Immediate(delta));
709 // exponent is 30 (biased). This is the exponent that we are fastest at and 746 __ neg(ecx);
710 // also the highest exponent we can handle here. 747 if (stash_exponent_copy) {
711 const uint32_t non_smi_exponent = 30; 748 __ mov(result_reg, MemOperand(esp, 0));
712 __ cmp(scratch2, Immediate(non_smi_exponent)); 749 } else {
713 // If we have a match of the int32-but-not-Smi exponent then skip some 750 __ mov(result_reg, exponent_operand);
714 // logic. 751 }
715 __ j(equal, &right_exponent, Label::kNear); 752 __ and_(result_reg,
716 // If the exponent is higher than that then go to slow case. This catches 753 Immediate(static_cast<uint32_t>(Double::kSignificandMask >> 32)));
717 // numbers that don't fit in a signed int32, infinities and NaNs. 754 __ add(result_reg,
718 __ j(less, &normal_exponent, Label::kNear); 755 Immediate(static_cast<uint32_t>(Double::kHiddenBit >> 32)));
756 __ shrd(result_reg, scratch1);
757 __ shr_cl(result_reg);
758 __ test(ecx, Immediate(32));
759 if (CpuFeatures::IsSupported(CMOV)) {
760 CpuFeatureScope use_cmov(masm, CMOV);
761 __ cmov(not_equal, scratch1, result_reg);
762 } else {
763 Label skip_mov;
764 __ j(equal, &skip_mov, Label::kNear);
765 __ mov(scratch1, result_reg);
766 __ bind(&skip_mov);
767 }
768 }
719 769
720 { 770 // If the double was negative, negate the integer result.
721 // Handle a big exponent. The only reason we have this code is that the 771 __ bind(&check_negative);
722 // >>> operator has a tendency to generate numbers with an exponent of 31. 772 __ mov(result_reg, scratch1);
723 const uint32_t big_non_smi_exponent = 31; 773 __ neg(result_reg);
724 __ cmp(scratch2, Immediate(big_non_smi_exponent)); 774 if (stash_exponent_copy) {
725 __ j(not_equal, conversion_failure); 775 __ cmp(MemOperand(esp, 0), Immediate(0));
726 // We have the big exponent, typically from >>>. This means the number is 776 } else {
727 // in the range 2^31 to 2^32 - 1. Get the top bits of the mantissa. 777 __ cmp(exponent_operand, Immediate(0));
728 __ mov(scratch2, scratch); 778 }
729 __ and_(scratch2, HeapNumber::kMantissaMask); 779 if (CpuFeatures::IsSupported(CMOV)) {
730 // Put back the implicit 1. 780 CpuFeatureScope use_cmov(masm, CMOV);
731 __ or_(scratch2, 1 << HeapNumber::kExponentShift); 781 __ cmov(greater, result_reg, scratch1);
732 // Shift up the mantissa bits to take up the space the exponent used to 782 } else {
733 // take. We just orred in the implicit bit so that took care of one and 783 Label skip_mov;
734 // we want to use the full unsigned range so we subtract 1 bit from the 784 __ j(less_equal, &skip_mov, Label::kNear);
735 // shift distance. 785 __ mov(result_reg, scratch1);
736 const int big_shift_distance = HeapNumber::kNonMantissaBitsInTopWord - 1; 786 __ bind(&skip_mov);
737 __ shl(scratch2, big_shift_distance); 787 }
738 // Get the second half of the double.
739 __ mov(ecx, FieldOperand(source, HeapNumber::kMantissaOffset));
740 // Shift down 21 bits to get the most significant 11 bits or the low
741 // mantissa word.
742 __ shr(ecx, 32 - big_shift_distance);
743 __ or_(ecx, scratch2);
744 // We have the answer in ecx, but we may need to negate it.
745 __ test(scratch, scratch);
746 __ j(positive, &done, Label::kNear);
747 __ neg(ecx);
748 __ jmp(&done, Label::kNear);
749 }
750 788
751 __ bind(&normal_exponent); 789 // Restore registers
752 // Exponent word in scratch, exponent in scratch2. Zero in ecx. 790 __ bind(&done);
753 // We know that 0 <= exponent < 30. 791 if (stash_exponent_copy) {
754 __ mov(ecx, Immediate(30)); 792 __ add(esp, Immediate(kDoubleSize / 2));
755 __ sub(ecx, scratch2);
756
757 __ bind(&right_exponent);
758 // Here ecx is the shift, scratch is the exponent word.
759 // Get the top bits of the mantissa.
760 __ and_(scratch, HeapNumber::kMantissaMask);
761 // Put back the implicit 1.
762 __ or_(scratch, 1 << HeapNumber::kExponentShift);
763 // Shift up the mantissa bits to take up the space the exponent used to
764 // take. We have kExponentShift + 1 significant bits int he low end of the
765 // word. Shift them to the top bits.
766 const int shift_distance = HeapNumber::kNonMantissaBitsInTopWord - 2;
767 __ shl(scratch, shift_distance);
768 // Get the second half of the double. For some exponents we don't
769 // actually need this because the bits get shifted out again, but
770 // it's probably slower to test than just to do it.
771 __ mov(scratch2, FieldOperand(source, HeapNumber::kMantissaOffset));
772 // Shift down 22 bits to get the most significant 10 bits or the low
773 // mantissa word.
774 __ shr(scratch2, 32 - shift_distance);
775 __ or_(scratch2, scratch);
776 // Move down according to the exponent.
777 __ shr_cl(scratch2);
778 // Now the unsigned answer is in scratch2. We need to move it to ecx and
779 // we may need to fix the sign.
780 Label negative;
781 __ xor_(ecx, ecx);
782 __ cmp(ecx, FieldOperand(source, HeapNumber::kExponentOffset));
783 __ j(greater, &negative, Label::kNear);
784 __ mov(ecx, scratch2);
785 __ jmp(&done, Label::kNear);
786 __ bind(&negative);
787 __ sub(ecx, scratch2);
788 } 793 }
789 __ bind(&done); 794 __ bind(&done_no_stash);
795 if (!final_result_reg.is(result_reg)) {
796 ASSERT(final_result_reg.is(ecx));
797 __ mov(final_result_reg, result_reg);
798 }
799 __ pop(save_reg);
800 __ pop(scratch1);
801 __ ret(0);
790 } 802 }
791 803
792 804
793 // Uses SSE2 to convert the heap number in |source| to an integer. Jumps to 805 // Uses SSE2 to convert the heap number in |source| to an integer. Jumps to
794 // |conversion_failure| if the heap number did not contain an int32 value. 806 // |conversion_failure| if the heap number did not contain an int32 value.
795 // Result is in ecx. Trashes ebx, xmm0, and xmm1. 807 // Result is in ecx. Trashes ebx, xmm0, and xmm1.
796 static void ConvertHeapNumberToInt32(MacroAssembler* masm, 808 static void ConvertHeapNumberToInt32(MacroAssembler* masm,
797 Register source, 809 Register source,
798 Label* conversion_failure) { 810 Label* conversion_failure) {
799 __ movdbl(xmm0, FieldOperand(source, HeapNumber::kValueOffset)); 811 __ movdbl(xmm0, FieldOperand(source, HeapNumber::kValueOffset));
(...skipping 1600 matching lines...) Expand 10 before | Expand all | Expand 10 after
2400 __ bind(&arg1_is_object); 2412 __ bind(&arg1_is_object);
2401 __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset)); 2413 __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
2402 __ cmp(ebx, factory->heap_number_map()); 2414 __ cmp(ebx, factory->heap_number_map());
2403 __ j(not_equal, &check_undefined_arg1); 2415 __ j(not_equal, &check_undefined_arg1);
2404 2416
2405 // Get the untagged integer version of the edx heap number in ecx. 2417 // Get the untagged integer version of the edx heap number in ecx.
2406 if (left_type == BinaryOpIC::INT32 && CpuFeatures::IsSupported(SSE2)) { 2418 if (left_type == BinaryOpIC::INT32 && CpuFeatures::IsSupported(SSE2)) {
2407 CpuFeatureScope use_sse2(masm, SSE2); 2419 CpuFeatureScope use_sse2(masm, SSE2);
2408 ConvertHeapNumberToInt32(masm, edx, conversion_failure); 2420 ConvertHeapNumberToInt32(masm, edx, conversion_failure);
2409 } else { 2421 } else {
2410 IntegerConvert(masm, edx, use_sse3, conversion_failure); 2422 DoubleToIStub stub(edx, ecx, HeapNumber::kValueOffset - kHeapObjectTag,
2423 true);
2424 __ call(stub.GetCode(masm->isolate()), RelocInfo::CODE_TARGET);
2411 } 2425 }
2412 __ mov(edx, ecx); 2426 __ mov(edx, ecx);
2413 2427
2414 // Here edx has the untagged integer, eax has a Smi or a heap number. 2428 // Here edx has the untagged integer, eax has a Smi or a heap number.
2415 __ bind(&load_arg2); 2429 __ bind(&load_arg2);
2416 2430
2417 // Test if arg2 is a Smi. 2431 // Test if arg2 is a Smi.
2418 if (right_type == BinaryOpIC::SMI) { 2432 if (right_type == BinaryOpIC::SMI) {
2419 __ JumpIfNotSmi(eax, conversion_failure); 2433 __ JumpIfNotSmi(eax, conversion_failure);
2420 } else { 2434 } else {
(...skipping 14 matching lines...) Expand all
2435 __ bind(&arg2_is_object); 2449 __ bind(&arg2_is_object);
2436 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); 2450 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
2437 __ cmp(ebx, factory->heap_number_map()); 2451 __ cmp(ebx, factory->heap_number_map());
2438 __ j(not_equal, &check_undefined_arg2); 2452 __ j(not_equal, &check_undefined_arg2);
2439 // Get the untagged integer version of the eax heap number in ecx. 2453 // Get the untagged integer version of the eax heap number in ecx.
2440 2454
2441 if (right_type == BinaryOpIC::INT32 && CpuFeatures::IsSupported(SSE2)) { 2455 if (right_type == BinaryOpIC::INT32 && CpuFeatures::IsSupported(SSE2)) {
2442 CpuFeatureScope use_sse2(masm, SSE2); 2456 CpuFeatureScope use_sse2(masm, SSE2);
2443 ConvertHeapNumberToInt32(masm, eax, conversion_failure); 2457 ConvertHeapNumberToInt32(masm, eax, conversion_failure);
2444 } else { 2458 } else {
2445 IntegerConvert(masm, eax, use_sse3, conversion_failure); 2459 DoubleToIStub stub(eax, ecx, HeapNumber::kValueOffset - kHeapObjectTag,
2460 true);
2461 __ call(stub.GetCode(masm->isolate()), RelocInfo::CODE_TARGET);
2446 } 2462 }
2447 2463
2448 __ bind(&done); 2464 __ bind(&done);
2449 __ mov(eax, edx); 2465 __ mov(eax, edx);
2450 } 2466 }
2451 2467
2452 2468
2453 void FloatingPointHelper::LoadFloatOperand(MacroAssembler* masm, 2469 void FloatingPointHelper::LoadFloatOperand(MacroAssembler* masm,
2454 Register number) { 2470 Register number) {
2455 Label load_smi, done; 2471 Label load_smi, done;
(...skipping 5309 matching lines...) Expand 10 before | Expand all | Expand 10 after
7765 __ bind(&fast_elements_case); 7781 __ bind(&fast_elements_case);
7766 GenerateCase(masm, FAST_ELEMENTS); 7782 GenerateCase(masm, FAST_ELEMENTS);
7767 } 7783 }
7768 7784
7769 7785
7770 #undef __ 7786 #undef __
7771 7787
7772 } } // namespace v8::internal 7788 } } // namespace v8::internal
7773 7789
7774 #endif // V8_TARGET_ARCH_IA32 7790 #endif // V8_TARGET_ARCH_IA32
OLDNEW
« no previous file with comments | « src/code-stubs.h ('k') | src/ia32/lithium-codegen-ia32.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698