How V8 computes Math.cos
and Math.sin
, on an ia32 system.
Created
March 2, 2013 02:14
-
-
Save tmcw/5069385 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
void Assembler::fcos() { | |
EnsureSpace ensure_space(this); | |
EMIT(0xD9); | |
EMIT(0xFF); | |
} | |
void Assembler::fsin() { | |
EnsureSpace ensure_space(this); | |
EMIT(0xD9); | |
EMIT(0xFE); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
void TranscendentalCacheStub::GenerateOperation( | |
MacroAssembler* masm, TranscendentalCache::Type type) { | |
// Only free register is edi. | |
// Input value is on FP stack, and also in ebx/edx. | |
// Input value is possibly in xmm1. | |
// Address of result (a newly allocated HeapNumber) may be in eax. | |
if (type == TranscendentalCache::SIN || | |
type == TranscendentalCache::COS || | |
type == TranscendentalCache::TAN) { | |
// Both fsin and fcos require arguments in the range +/-2^63 and | |
// return NaN for infinities and NaN. They can share all code except | |
// the actual fsin/fcos operation. | |
Label in_range, done; | |
// If argument is outside the range -2^63..2^63, fsin/cos doesn't | |
// work. We must reduce it to the appropriate range. | |
__ mov(edi, edx); | |
__ and_(edi, Immediate(0x7ff00000)); // Exponent only. | |
int supported_exponent_limit = | |
(63 + HeapNumber::kExponentBias) << HeapNumber::kExponentShift; | |
__ cmp(edi, Immediate(supported_exponent_limit)); | |
__ j(below, &in_range, Label::kNear); | |
// Check for infinity and NaN. Both return NaN for sin. | |
__ cmp(edi, Immediate(0x7ff00000)); | |
Label non_nan_result; | |
__ j(not_equal, &non_nan_result, Label::kNear); | |
// Input is +/-Infinity or NaN. Result is NaN. | |
__ fstp(0); | |
// NaN is represented by 0x7ff8000000000000. | |
__ push(Immediate(0x7ff80000)); | |
__ push(Immediate(0)); | |
__ fld_d(Operand(esp, 0)); | |
__ add(esp, Immediate(2 * kPointerSize)); | |
__ jmp(&done, Label::kNear); | |
__ bind(&non_nan_result); | |
// Use fpmod to restrict argument to the range +/-2*PI. | |
__ mov(edi, eax); // Save eax before using fnstsw_ax. | |
__ fldpi(); | |
__ fadd(0); | |
__ fld(1); | |
// FPU Stack: input, 2*pi, input. | |
{ | |
Label no_exceptions; | |
__ fwait(); | |
__ fnstsw_ax(); | |
// Clear if Illegal Operand or Zero Division exceptions are set. | |
__ test(eax, Immediate(5)); | |
__ j(zero, &no_exceptions, Label::kNear); | |
__ fnclex(); | |
__ bind(&no_exceptions); | |
} | |
// Compute st(0) % st(1) | |
{ | |
Label partial_remainder_loop; | |
__ bind(&partial_remainder_loop); | |
__ fprem1(); | |
__ fwait(); | |
__ fnstsw_ax(); | |
__ test(eax, Immediate(0x400 /* C2 */)); | |
// If C2 is set, computation only has partial result. Loop to | |
// continue computation. | |
__ j(not_zero, &partial_remainder_loop); | |
} | |
// FPU Stack: input, 2*pi, input % 2*pi | |
__ fstp(2); | |
__ fstp(0); | |
__ mov(eax, edi); // Restore eax (allocated HeapNumber pointer). | |
// FPU Stack: input % 2*pi | |
__ bind(&in_range); | |
switch (type) { | |
case TranscendentalCache::SIN: | |
__ fsin(); | |
break; | |
case TranscendentalCache::COS: | |
__ fcos(); | |
break; | |
case TranscendentalCache::TAN: | |
// FPTAN calculates tangent onto st(0) and pushes 1.0 onto the | |
// FP register stack. | |
__ fptan(); | |
__ fstp(0); // Pop FP register stack. | |
break; | |
default: | |
UNREACHABLE(); | |
} | |
__ bind(&done); | |
} else { | |
ASSERT(type == TranscendentalCache::LOG); | |
__ fldln2(); | |
__ fxch(); | |
__ fyl2x(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
void LCodeGen::DoMathCos(LUnaryMathOperation* instr) { | |
ASSERT(ToDoubleRegister(instr->result()).is(xmm1)); | |
TranscendentalCacheStub stub(TranscendentalCache::COS, | |
TranscendentalCacheStub::UNTAGGED); | |
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); | |
} | |
void LCodeGen::DoMathSin(LUnaryMathOperation* instr) { | |
ASSERT(ToDoubleRegister(instr->result()).is(xmm1)); | |
TranscendentalCacheStub stub(TranscendentalCache::SIN, | |
TranscendentalCacheStub::UNTAGGED); | |
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment