OLD | NEW |
1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 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 25 matching lines...) Expand all Loading... |
36 #include "regexp-macro-assembler.h" | 36 #include "regexp-macro-assembler.h" |
37 #include "register-allocator-inl.h" | 37 #include "register-allocator-inl.h" |
38 #include "scopes.h" | 38 #include "scopes.h" |
39 #include "virtual-frame-inl.h" | 39 #include "virtual-frame-inl.h" |
40 | 40 |
41 namespace v8 { | 41 namespace v8 { |
42 namespace internal { | 42 namespace internal { |
43 | 43 |
44 #define __ ACCESS_MASM(masm_) | 44 #define __ ACCESS_MASM(masm_) |
45 | 45 |
46 static int64_t kNaNValue = V8_INT64_C(0x7ff8000000000000); | |
47 | |
48 // ------------------------------------------------------------------------- | 46 // ------------------------------------------------------------------------- |
49 // Platform-specific DeferredCode functions. | 47 // Platform-specific DeferredCode functions. |
50 | 48 |
51 void DeferredCode::SaveRegisters() { | 49 void DeferredCode::SaveRegisters() { |
52 for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) { | 50 for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) { |
53 int action = registers_[i]; | 51 int action = registers_[i]; |
54 if (action == kPush) { | 52 if (action == kPush) { |
55 __ push(RegisterAllocator::ToRegister(i)); | 53 __ push(RegisterAllocator::ToRegister(i)); |
56 } else if (action != kIgnore && (action & kSyncedFlag) == 0) { | 54 } else if (action != kIgnore && (action & kSyncedFlag) == 0) { |
57 __ movq(Operand(rbp, action), RegisterAllocator::ToRegister(i)); | 55 __ movq(Operand(rbp, action), RegisterAllocator::ToRegister(i)); |
(...skipping 7492 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7550 Label cache_miss; | 7548 Label cache_miss; |
7551 __ cmpq(rbx, Operand(rcx, 0)); | 7549 __ cmpq(rbx, Operand(rcx, 0)); |
7552 __ j(not_equal, &cache_miss); | 7550 __ j(not_equal, &cache_miss); |
7553 // Cache hit! | 7551 // Cache hit! |
7554 __ movq(rax, Operand(rcx, 2 * kIntSize)); | 7552 __ movq(rax, Operand(rcx, 2 * kIntSize)); |
7555 __ fstp(0); // Clear FPU stack. | 7553 __ fstp(0); // Clear FPU stack. |
7556 __ ret(kPointerSize); | 7554 __ ret(kPointerSize); |
7557 | 7555 |
7558 __ bind(&cache_miss); | 7556 __ bind(&cache_miss); |
7559 // Update cache with new value. | 7557 // Update cache with new value. |
| 7558 Label nan_result; |
| 7559 GenerateOperation(masm, &nan_result); |
7560 __ AllocateHeapNumber(rax, rdi, &runtime_call_clear_stack); | 7560 __ AllocateHeapNumber(rax, rdi, &runtime_call_clear_stack); |
7561 GenerateOperation(masm); | |
7562 __ movq(Operand(rcx, 0), rbx); | 7561 __ movq(Operand(rcx, 0), rbx); |
7563 __ movq(Operand(rcx, 2 * kIntSize), rax); | 7562 __ movq(Operand(rcx, 2 * kIntSize), rax); |
7564 __ fstp_d(FieldOperand(rax, HeapNumber::kValueOffset)); | 7563 __ fstp_d(FieldOperand(rax, HeapNumber::kValueOffset)); |
7565 __ ret(kPointerSize); | 7564 __ ret(kPointerSize); |
7566 | 7565 |
7567 __ bind(&runtime_call_clear_stack); | 7566 __ bind(&runtime_call_clear_stack); |
7568 __ fstp(0); | 7567 __ fstp(0); |
7569 __ bind(&runtime_call); | 7568 __ bind(&runtime_call); |
7570 __ TailCallExternalReference(ExternalReference(RuntimeFunction()), 1, 1); | 7569 __ TailCallExternalReference(ExternalReference(RuntimeFunction()), 1, 1); |
| 7570 |
| 7571 __ bind(&nan_result); |
| 7572 __ fstp(0); // Remove argument from FPU stack. |
| 7573 __ LoadRoot(rax, Heap::kNanValueRootIndex); |
| 7574 __ movq(Operand(rcx, 0), rbx); |
| 7575 __ movq(Operand(rcx, 2 * kIntSize), rax); |
| 7576 __ ret(kPointerSize); |
7571 } | 7577 } |
7572 | 7578 |
7573 | 7579 |
7574 Runtime::FunctionId TranscendentalCacheStub::RuntimeFunction() { | 7580 Runtime::FunctionId TranscendentalCacheStub::RuntimeFunction() { |
7575 switch (type_) { | 7581 switch (type_) { |
7576 // Add more cases when necessary. | 7582 // Add more cases when necessary. |
7577 case TranscendentalCache::SIN: return Runtime::kMath_sin; | 7583 case TranscendentalCache::SIN: return Runtime::kMath_sin; |
7578 case TranscendentalCache::COS: return Runtime::kMath_cos; | 7584 case TranscendentalCache::COS: return Runtime::kMath_cos; |
7579 default: | 7585 default: |
7580 UNIMPLEMENTED(); | 7586 UNIMPLEMENTED(); |
7581 return Runtime::kAbort; | 7587 return Runtime::kAbort; |
7582 } | 7588 } |
7583 } | 7589 } |
7584 | 7590 |
7585 | 7591 |
7586 void TranscendentalCacheStub::GenerateOperation(MacroAssembler* masm) { | 7592 void TranscendentalCacheStub::GenerateOperation(MacroAssembler* masm, |
7587 // Only free register is rdi. | 7593 Label* on_nan_result) { |
| 7594 // Registers: |
| 7595 // rbx: Bits of input double. Must be preserved. |
| 7596 // rcx: Pointer to cache entry. Must be preserved. |
| 7597 // st(0): Input double |
7588 Label done; | 7598 Label done; |
7589 ASSERT(type_ == TranscendentalCache::SIN || | 7599 ASSERT(type_ == TranscendentalCache::SIN || |
7590 type_ == TranscendentalCache::COS); | 7600 type_ == TranscendentalCache::COS); |
7591 // More transcendental types can be added later. | 7601 // More transcendental types can be added later. |
7592 | 7602 |
7593 // Both fsin and fcos require arguments in the range +/-2^63 and | 7603 // Both fsin and fcos require arguments in the range +/-2^63 and |
7594 // return NaN for infinities and NaN. They can share all code except | 7604 // return NaN for infinities and NaN. They can share all code except |
7595 // the actual fsin/fcos operation. | 7605 // the actual fsin/fcos operation. |
7596 Label in_range; | 7606 Label in_range; |
7597 // If argument is outside the range -2^63..2^63, fsin/cos doesn't | 7607 // If argument is outside the range -2^63..2^63, fsin/cos doesn't |
7598 // work. We must reduce it to the appropriate range. | 7608 // work. We must reduce it to the appropriate range. |
7599 __ movq(rdi, rbx); | 7609 __ movq(rdi, rbx); |
7600 // Move exponent and sign bits to low bits. | 7610 // Move exponent and sign bits to low bits. |
7601 __ shr(rdi, Immediate(HeapNumber::kMantissaBits)); | 7611 __ shr(rdi, Immediate(HeapNumber::kMantissaBits)); |
7602 // Remove sign bit. | 7612 // Remove sign bit. |
7603 __ andl(rdi, Immediate((1 << HeapNumber::KExponentBits) - 1)); | 7613 __ andl(rdi, Immediate((1 << HeapNumber::KExponentBits) - 1)); |
7604 int supported_exponent_limit = (63 + HeapNumber::kExponentBias); | 7614 int supported_exponent_limit = (63 + HeapNumber::kExponentBias); |
7605 __ cmpl(rdi, Immediate(supported_exponent_limit)); | 7615 __ cmpl(rdi, Immediate(supported_exponent_limit)); |
7606 __ j(below, &in_range); | 7616 __ j(below, &in_range); |
7607 // Check for infinity and NaN. Both return NaN for sin. | 7617 // Check for infinity and NaN. Both return NaN for sin. |
7608 __ cmpl(rdi, Immediate(0x7ff)); | 7618 __ cmpl(rdi, Immediate(0x7ff)); |
7609 Label non_nan_result; | 7619 __ j(equal, on_nan_result); |
7610 __ j(not_equal, &non_nan_result); | |
7611 // Input is +/-Infinity or NaN. Result is NaN. | |
7612 __ fstp(0); // Clear fpu stack. | |
7613 // NaN is represented by 0x7ff8000000000000. | |
7614 __ movq(rdi, kNaNValue, RelocInfo::NONE); | |
7615 __ push(rdi); | |
7616 __ fld_d(Operand(rsp, 0)); | |
7617 __ addq(rsp, Immediate(kPointerSize)); | |
7618 __ jmp(&done); | |
7619 | |
7620 __ bind(&non_nan_result); | |
7621 | 7620 |
7622 // Use fpmod to restrict argument to the range +/-2*PI. | 7621 // Use fpmod to restrict argument to the range +/-2*PI. |
7623 __ movq(rdi, rax); // Save rax before using fnstsw_ax. | |
7624 __ fldpi(); | 7622 __ fldpi(); |
7625 __ fadd(0); | 7623 __ fadd(0); |
7626 __ fld(1); | 7624 __ fld(1); |
7627 // FPU Stack: input, 2*pi, input. | 7625 // FPU Stack: input, 2*pi, input. |
7628 { | 7626 { |
7629 Label no_exceptions; | 7627 Label no_exceptions; |
7630 __ fwait(); | 7628 __ fwait(); |
7631 __ fnstsw_ax(); | 7629 __ fnstsw_ax(); |
7632 // Clear if Illegal Operand or Zero Division exceptions are set. | 7630 // Clear if Illegal Operand or Zero Division exceptions are set. |
7633 __ testl(rax, Immediate(5)); | 7631 __ testl(rax, Immediate(5)); // #IO and #ZD flags of FPU status word. |
7634 __ j(zero, &no_exceptions); | 7632 __ j(zero, &no_exceptions); |
7635 __ fnclex(); | 7633 __ fnclex(); |
7636 __ bind(&no_exceptions); | 7634 __ bind(&no_exceptions); |
7637 } | 7635 } |
7638 | 7636 |
7639 // Compute st(0) % st(1) | 7637 // Compute st(0) % st(1) |
7640 { | 7638 { |
7641 Label partial_remainder_loop; | 7639 Label partial_remainder_loop; |
7642 __ bind(&partial_remainder_loop); | 7640 __ bind(&partial_remainder_loop); |
7643 __ fprem1(); | 7641 __ fprem1(); |
7644 __ fwait(); | 7642 __ fwait(); |
7645 __ fnstsw_ax(); | 7643 __ fnstsw_ax(); |
7646 __ testl(rax, Immediate(0x400)); // Check C2 bit of FPU status word. | 7644 __ testl(rax, Immediate(0x400)); // Check C2 bit of FPU status word. |
7647 // If C2 is set, computation only has partial result. Loop to | 7645 // If C2 is set, computation only has partial result. Loop to |
7648 // continue computation. | 7646 // continue computation. |
7649 __ j(not_zero, &partial_remainder_loop); | 7647 __ j(not_zero, &partial_remainder_loop); |
7650 } | 7648 } |
7651 // FPU Stack: input, 2*pi, input % 2*pi | 7649 // FPU Stack: input, 2*pi, input % 2*pi |
7652 __ fstp(2); | 7650 __ fstp(2); |
7653 // FPU Stack: input % 2*pi, 2*pi, | 7651 // FPU Stack: input % 2*pi, 2*pi, |
7654 __ fstp(0); | 7652 __ fstp(0); |
7655 // FPU Stack: input % 2*pi | 7653 // FPU Stack: input % 2*pi |
7656 __ movq(rax, rdi); // Restore rax (allocated HeapNumber pointer). | |
7657 | |
7658 // FPU Stack: input % 2*pi | |
7659 __ bind(&in_range); | 7654 __ bind(&in_range); |
7660 switch (type_) { | 7655 switch (type_) { |
7661 case TranscendentalCache::SIN: | 7656 case TranscendentalCache::SIN: |
7662 __ fsin(); | 7657 __ fsin(); |
7663 break; | 7658 break; |
7664 case TranscendentalCache::COS: | 7659 case TranscendentalCache::COS: |
7665 __ fcos(); | 7660 __ fcos(); |
7666 break; | 7661 break; |
7667 default: | 7662 default: |
7668 UNREACHABLE(); | 7663 UNREACHABLE(); |
(...skipping 3531 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
11200 __ j(not_zero, &partial_remainder_loop); | 11195 __ j(not_zero, &partial_remainder_loop); |
11201 } | 11196 } |
11202 | 11197 |
11203 Label valid_result; | 11198 Label valid_result; |
11204 Label return_result; | 11199 Label return_result; |
11205 // If Invalid Operand or Zero Division exceptions are set, | 11200 // If Invalid Operand or Zero Division exceptions are set, |
11206 // return NaN. | 11201 // return NaN. |
11207 __ testb(rax, Immediate(5)); | 11202 __ testb(rax, Immediate(5)); |
11208 __ j(zero, &valid_result); | 11203 __ j(zero, &valid_result); |
11209 __ fstp(0); // Drop result in st(0). | 11204 __ fstp(0); // Drop result in st(0). |
| 11205 int64_t kNaNValue = V8_INT64_C(0x7ff8000000000000); |
11210 __ movq(rcx, kNaNValue, RelocInfo::NONE); | 11206 __ movq(rcx, kNaNValue, RelocInfo::NONE); |
11211 __ movq(Operand(rsp, kPointerSize), rcx); | 11207 __ movq(Operand(rsp, kPointerSize), rcx); |
11212 __ movsd(xmm0, Operand(rsp, kPointerSize)); | 11208 __ movsd(xmm0, Operand(rsp, kPointerSize)); |
11213 __ jmp(&return_result); | 11209 __ jmp(&return_result); |
11214 | 11210 |
11215 // If result is valid, return that. | 11211 // If result is valid, return that. |
11216 __ bind(&valid_result); | 11212 __ bind(&valid_result); |
11217 __ fstp_d(Operand(rsp, kPointerSize)); | 11213 __ fstp_d(Operand(rsp, kPointerSize)); |
11218 __ movsd(xmm0, Operand(rsp, kPointerSize)); | 11214 __ movsd(xmm0, Operand(rsp, kPointerSize)); |
11219 | 11215 |
(...skipping 14 matching lines...) Expand all Loading... |
11234 // Call the function from C++. | 11230 // Call the function from C++. |
11235 return FUNCTION_CAST<ModuloFunction>(buffer); | 11231 return FUNCTION_CAST<ModuloFunction>(buffer); |
11236 } | 11232 } |
11237 | 11233 |
11238 #endif | 11234 #endif |
11239 | 11235 |
11240 | 11236 |
11241 #undef __ | 11237 #undef __ |
11242 | 11238 |
11243 } } // namespace v8::internal | 11239 } } // namespace v8::internal |
OLD | NEW |