Porting Math.pow changes to x64.
TEST=math-pow.js, regress-397.js Review URL: http://codereview.chromium.org/8821019 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@10185 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
b5b91b5add
commit
c9c9ea676b
@ -2940,64 +2940,72 @@ void FloatingPointHelper::CheckFloatOperandsAreInt32(MacroAssembler* masm,
|
|||||||
void MathPowStub::Generate(MacroAssembler* masm) {
|
void MathPowStub::Generate(MacroAssembler* masm) {
|
||||||
CpuFeatures::Scope use_sse2(SSE2);
|
CpuFeatures::Scope use_sse2(SSE2);
|
||||||
Factory* factory = masm->isolate()->factory();
|
Factory* factory = masm->isolate()->factory();
|
||||||
|
const Register exponent = eax;
|
||||||
|
const Register base = edx;
|
||||||
|
const Register scratch = ecx;
|
||||||
|
const XMMRegister double_result = xmm3;
|
||||||
|
const XMMRegister double_base = xmm2;
|
||||||
|
const XMMRegister double_exponent = xmm1;
|
||||||
|
const XMMRegister double_scratch = xmm4;
|
||||||
|
|
||||||
Label double_int_runtime, generic_runtime, done;
|
Label double_int_runtime, generic_runtime, done;
|
||||||
Label base_is_smi, unpack_exponent, exponent_not_smi, int_exponent;
|
Label exponent_not_smi, int_exponent;
|
||||||
// Save 1 in xmm3 - we need this several times later on.
|
|
||||||
__ mov(ecx, Immediate(1));
|
// Save 1 in double_result - we need this several times later on.
|
||||||
__ cvtsi2sd(xmm3, ecx);
|
__ mov(scratch, Immediate(1));
|
||||||
|
__ cvtsi2sd(double_result, scratch);
|
||||||
|
|
||||||
if (exponent_type_ == ON_STACK) {
|
if (exponent_type_ == ON_STACK) {
|
||||||
// The exponent (and base) are supplied as arguments on the stack.
|
Label base_is_smi, unpack_exponent;
|
||||||
|
// The exponent and base are supplied as arguments on the stack.
|
||||||
// This can only happen if the stub is called from non-optimized code.
|
// This can only happen if the stub is called from non-optimized code.
|
||||||
// Load input parameters from stack
|
// Load input parameters from stack.
|
||||||
__ mov(edx, Operand(esp, 2 * kPointerSize));
|
__ mov(base, Operand(esp, 2 * kPointerSize));
|
||||||
__ mov(eax, Operand(esp, 1 * kPointerSize));
|
__ mov(exponent, Operand(esp, 1 * kPointerSize));
|
||||||
// edx: base (smi or heap number)
|
|
||||||
// eax: exponent (smi or heap number)
|
__ JumpIfSmi(base, &base_is_smi, Label::kNear);
|
||||||
__ JumpIfSmi(edx, &base_is_smi, Label::kNear);
|
__ cmp(FieldOperand(base, HeapObject::kMapOffset),
|
||||||
__ cmp(FieldOperand(edx, HeapObject::kMapOffset),
|
|
||||||
factory->heap_number_map());
|
factory->heap_number_map());
|
||||||
__ j(not_equal, &generic_runtime);
|
__ j(not_equal, &generic_runtime);
|
||||||
|
|
||||||
__ movdbl(xmm1, FieldOperand(edx, HeapNumber::kValueOffset));
|
__ movdbl(double_base, FieldOperand(base, HeapNumber::kValueOffset));
|
||||||
__ jmp(&unpack_exponent, Label::kNear);
|
__ jmp(&unpack_exponent, Label::kNear);
|
||||||
|
|
||||||
__ bind(&base_is_smi);
|
__ bind(&base_is_smi);
|
||||||
__ SmiUntag(edx);
|
__ SmiUntag(base);
|
||||||
__ cvtsi2sd(xmm1, edx);
|
__ cvtsi2sd(double_base, base);
|
||||||
__ bind(&unpack_exponent);
|
|
||||||
|
|
||||||
__ JumpIfNotSmi(eax, &exponent_not_smi, Label::kNear);
|
__ bind(&unpack_exponent);
|
||||||
__ SmiUntag(eax);
|
__ JumpIfNotSmi(exponent, &exponent_not_smi, Label::kNear);
|
||||||
|
__ SmiUntag(exponent);
|
||||||
__ jmp(&int_exponent);
|
__ jmp(&int_exponent);
|
||||||
|
|
||||||
__ bind(&exponent_not_smi);
|
__ bind(&exponent_not_smi);
|
||||||
__ cmp(FieldOperand(eax, HeapObject::kMapOffset),
|
__ cmp(FieldOperand(exponent, HeapObject::kMapOffset),
|
||||||
factory->heap_number_map());
|
factory->heap_number_map());
|
||||||
__ j(not_equal, &generic_runtime);
|
__ j(not_equal, &generic_runtime);
|
||||||
__ movdbl(xmm2, FieldOperand(eax, HeapNumber::kValueOffset));
|
__ movdbl(double_exponent,
|
||||||
|
FieldOperand(exponent, HeapNumber::kValueOffset));
|
||||||
} else if (exponent_type_ == TAGGED) {
|
} else if (exponent_type_ == TAGGED) {
|
||||||
// xmm1: base as double
|
__ JumpIfNotSmi(exponent, &exponent_not_smi, Label::kNear);
|
||||||
// eax: exponent (smi or heap number)
|
__ SmiUntag(exponent);
|
||||||
__ JumpIfNotSmi(eax, &exponent_not_smi, Label::kNear);
|
|
||||||
__ SmiUntag(eax);
|
|
||||||
__ jmp(&int_exponent);
|
__ jmp(&int_exponent);
|
||||||
|
|
||||||
__ bind(&exponent_not_smi);
|
__ bind(&exponent_not_smi);
|
||||||
__ movdbl(xmm2, FieldOperand(eax, HeapNumber::kValueOffset));
|
__ movdbl(double_exponent,
|
||||||
|
FieldOperand(exponent, HeapNumber::kValueOffset));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (exponent_type_ != INTEGER) {
|
if (exponent_type_ != INTEGER) {
|
||||||
Label fast_power;
|
Label fast_power;
|
||||||
// xmm1: base as double that is not +/- Infinity or NaN
|
|
||||||
// xmm2: exponent as double
|
|
||||||
// Detect integer exponents stored as double.
|
// Detect integer exponents stored as double.
|
||||||
__ cvttsd2si(eax, Operand(xmm2));
|
__ cvttsd2si(exponent, Operand(double_exponent));
|
||||||
// Skip to runtime if possibly NaN (indicated by the indefinite integer).
|
// Skip to runtime if possibly NaN (indicated by the indefinite integer).
|
||||||
__ cmp(eax, Immediate(0x80000000u));
|
__ cmp(exponent, Immediate(0x80000000u));
|
||||||
__ j(equal, &generic_runtime);
|
__ j(equal, &generic_runtime);
|
||||||
__ cvtsi2sd(xmm4, eax);
|
__ cvtsi2sd(double_scratch, exponent);
|
||||||
__ ucomisd(xmm2, xmm4); // Already ruled out NaNs for exponent.
|
// Already ruled out NaNs for exponent.
|
||||||
|
__ ucomisd(double_exponent, double_scratch);
|
||||||
__ j(equal, &int_exponent);
|
__ j(equal, &int_exponent);
|
||||||
|
|
||||||
if (exponent_type_ == ON_STACK) {
|
if (exponent_type_ == ON_STACK) {
|
||||||
@ -3006,71 +3014,70 @@ void MathPowStub::Generate(MacroAssembler* masm) {
|
|||||||
// for non-constant cases of +/-0.5 as these hardly occur.
|
// for non-constant cases of +/-0.5 as these hardly occur.
|
||||||
Label continue_sqrt, continue_rsqrt, not_plus_half;
|
Label continue_sqrt, continue_rsqrt, not_plus_half;
|
||||||
// Test for 0.5.
|
// Test for 0.5.
|
||||||
// Load xmm4 with 0.5.
|
// Load double_scratch with 0.5.
|
||||||
__ mov(ecx, Immediate(0x3F000000u));
|
__ mov(scratch, Immediate(0x3F000000u));
|
||||||
__ movd(xmm4, ecx);
|
__ movd(double_scratch, scratch);
|
||||||
__ cvtss2sd(xmm4, xmm4);
|
__ cvtss2sd(double_scratch, double_scratch);
|
||||||
// xmm4 now has 0.5.
|
// Already ruled out NaNs for exponent.
|
||||||
__ ucomisd(xmm4, xmm2); // Already ruled out NaNs for exponent.
|
__ ucomisd(double_scratch, double_exponent);
|
||||||
__ j(not_equal, ¬_plus_half, Label::kNear);
|
__ j(not_equal, ¬_plus_half, Label::kNear);
|
||||||
|
|
||||||
// Calculates square root of base. Check for the special case of
|
// Calculates square root of base. Check for the special case of
|
||||||
// Math.pow(-Infinity, 0.5) == Infinity (ECMA spec, 15.8.2.13).
|
// Math.pow(-Infinity, 0.5) == Infinity (ECMA spec, 15.8.2.13).
|
||||||
// According to IEEE-754, single-precision -Infinity has the highest
|
// According to IEEE-754, single-precision -Infinity has the highest
|
||||||
// 9 bits set and the lowest 23 bits cleared.
|
// 9 bits set and the lowest 23 bits cleared.
|
||||||
__ mov(ecx, 0xFF800000u);
|
__ mov(scratch, 0xFF800000u);
|
||||||
__ movd(xmm4, ecx);
|
__ movd(double_scratch, scratch);
|
||||||
__ cvtss2sd(xmm4, xmm4);
|
__ cvtss2sd(double_scratch, double_scratch);
|
||||||
__ ucomisd(xmm1, xmm4);
|
__ ucomisd(double_base, double_scratch);
|
||||||
// Comparing -Infinity with NaN results in "unordered", which sets the
|
// Comparing -Infinity with NaN results in "unordered", which sets the
|
||||||
// zero flag as if both were equal. However, it also sets the carry flag.
|
// zero flag as if both were equal. However, it also sets the carry flag.
|
||||||
__ j(not_equal, &continue_sqrt, Label::kNear);
|
__ j(not_equal, &continue_sqrt, Label::kNear);
|
||||||
__ j(carry, &continue_sqrt, Label::kNear);
|
__ j(carry, &continue_sqrt, Label::kNear);
|
||||||
|
|
||||||
// Set result to Infinity in the special case.
|
// Set result to Infinity in the special case.
|
||||||
__ xorps(xmm3, xmm3);
|
__ xorps(double_result, double_result);
|
||||||
__ subsd(xmm3, xmm4);
|
__ subsd(double_result, double_scratch);
|
||||||
__ jmp(&done);
|
__ jmp(&done);
|
||||||
|
|
||||||
__ bind(&continue_sqrt);
|
__ bind(&continue_sqrt);
|
||||||
// sqrtsd returns -0 when input is -0. ECMA spec requires +0.
|
// sqrtsd returns -0 when input is -0. ECMA spec requires +0.
|
||||||
__ xorps(xmm4, xmm4);
|
__ xorps(double_scratch, double_scratch);
|
||||||
__ addsd(xmm4, xmm1); // Convert -0 to +0.
|
__ addsd(double_scratch, double_base); // Convert -0 to +0.
|
||||||
__ sqrtsd(xmm3, xmm4);
|
__ sqrtsd(double_result, double_scratch);
|
||||||
__ jmp(&done);
|
__ jmp(&done);
|
||||||
|
|
||||||
// Test for -0.5.
|
// Test for -0.5.
|
||||||
__ bind(¬_plus_half);
|
__ bind(¬_plus_half);
|
||||||
// Load xmm2 with -0.5.
|
// Load double_exponent with -0.5 by substracting 1.
|
||||||
// Since xmm3 is 1 and xmm4 is 0.5 this is simply xmm4 - xmm3.
|
__ subsd(double_scratch, double_result);
|
||||||
__ subsd(xmm4, xmm3);
|
// Already ruled out NaNs for exponent.
|
||||||
// xmm4 now has -0.5.
|
__ ucomisd(double_scratch, double_exponent);
|
||||||
__ ucomisd(xmm4, xmm2); // Already ruled out NaNs for exponent.
|
|
||||||
__ j(not_equal, &fast_power, Label::kNear);
|
__ j(not_equal, &fast_power, Label::kNear);
|
||||||
|
|
||||||
// Calculates reciprocal of square root of base. Check for the special
|
// Calculates reciprocal of square root of base. Check for the special
|
||||||
// case of Math.pow(-Infinity, -0.5) == 0 (ECMA spec, 15.8.2.13).
|
// case of Math.pow(-Infinity, -0.5) == 0 (ECMA spec, 15.8.2.13).
|
||||||
// According to IEEE-754, single-precision -Infinity has the highest
|
// According to IEEE-754, single-precision -Infinity has the highest
|
||||||
// 9 bits set and the lowest 23 bits cleared.
|
// 9 bits set and the lowest 23 bits cleared.
|
||||||
__ mov(ecx, 0xFF800000u);
|
__ mov(scratch, 0xFF800000u);
|
||||||
__ movd(xmm4, ecx);
|
__ movd(double_scratch, scratch);
|
||||||
__ cvtss2sd(xmm4, xmm4);
|
__ cvtss2sd(double_scratch, double_scratch);
|
||||||
__ ucomisd(xmm1, xmm4);
|
__ ucomisd(double_base, double_scratch);
|
||||||
// Comparing -Infinity with NaN results in "unordered", which sets the
|
// Comparing -Infinity with NaN results in "unordered", which sets the
|
||||||
// zero flag as if both were equal. However, it also sets the carry flag.
|
// zero flag as if both were equal. However, it also sets the carry flag.
|
||||||
__ j(not_equal, &continue_rsqrt, Label::kNear);
|
__ j(not_equal, &continue_rsqrt, Label::kNear);
|
||||||
__ j(carry, &continue_rsqrt, Label::kNear);
|
__ j(carry, &continue_rsqrt, Label::kNear);
|
||||||
|
|
||||||
// Set result to 0 in the special case.
|
// Set result to 0 in the special case.
|
||||||
__ xorps(xmm3, xmm3);
|
__ xorps(double_result, double_result);
|
||||||
__ jmp(&done);
|
__ jmp(&done);
|
||||||
|
|
||||||
__ bind(&continue_rsqrt);
|
__ bind(&continue_rsqrt);
|
||||||
// sqrtsd returns -0 when input is -0. ECMA spec requires +0.
|
// sqrtsd returns -0 when input is -0. ECMA spec requires +0.
|
||||||
__ xorps(xmm2, xmm2);
|
__ xorps(double_exponent, double_exponent);
|
||||||
__ addsd(xmm2, xmm1); // Convert -0 to +0.
|
__ addsd(double_exponent, double_base); // Convert -0 to +0.
|
||||||
__ sqrtsd(xmm2, xmm2);
|
__ sqrtsd(double_exponent, double_exponent);
|
||||||
__ divsd(xmm3, xmm2);
|
__ divsd(double_result, double_exponent);
|
||||||
__ jmp(&done);
|
__ jmp(&done);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3080,9 +3087,9 @@ void MathPowStub::Generate(MacroAssembler* masm) {
|
|||||||
__ fnclex(); // Clear flags to catch exceptions later.
|
__ fnclex(); // Clear flags to catch exceptions later.
|
||||||
// Transfer (B)ase and (E)xponent onto the FPU register stack.
|
// Transfer (B)ase and (E)xponent onto the FPU register stack.
|
||||||
__ sub(esp, Immediate(kDoubleSize));
|
__ sub(esp, Immediate(kDoubleSize));
|
||||||
__ movdbl(Operand(esp, 0), xmm2);
|
__ movdbl(Operand(esp, 0), double_exponent);
|
||||||
__ fld_d(Operand(esp, 0)); // E
|
__ fld_d(Operand(esp, 0)); // E
|
||||||
__ movdbl(Operand(esp, 0), xmm1);
|
__ movdbl(Operand(esp, 0), double_base);
|
||||||
__ fld_d(Operand(esp, 0)); // B, E
|
__ fld_d(Operand(esp, 0)); // B, E
|
||||||
|
|
||||||
// Exponent is in st(1) and base is in st(0)
|
// Exponent is in st(1) and base is in st(0)
|
||||||
@ -3105,7 +3112,7 @@ void MathPowStub::Generate(MacroAssembler* masm) {
|
|||||||
__ test_b(eax, 0x5F); // We check for all but precision exception.
|
__ test_b(eax, 0x5F); // We check for all but precision exception.
|
||||||
__ j(not_zero, &fast_power_failed, Label::kNear);
|
__ j(not_zero, &fast_power_failed, Label::kNear);
|
||||||
__ fstp_d(Operand(esp, 0));
|
__ fstp_d(Operand(esp, 0));
|
||||||
__ movdbl(xmm3, Operand(esp, 0));
|
__ movdbl(double_result, Operand(esp, 0));
|
||||||
__ add(esp, Immediate(kDoubleSize));
|
__ add(esp, Immediate(kDoubleSize));
|
||||||
__ jmp(&done);
|
__ jmp(&done);
|
||||||
|
|
||||||
@ -3117,49 +3124,46 @@ void MathPowStub::Generate(MacroAssembler* masm) {
|
|||||||
|
|
||||||
// Calculate power with integer exponent.
|
// Calculate power with integer exponent.
|
||||||
__ bind(&int_exponent);
|
__ bind(&int_exponent);
|
||||||
// xmm1: base as double that is not +/- Infinity or NaN
|
const XMMRegister double_scratch2 = double_exponent;
|
||||||
// eax: exponent as untagged integer
|
__ mov(scratch, exponent); // Back up exponent.
|
||||||
__ mov(ecx, eax); // Back up exponent.
|
__ movsd(double_scratch, double_base); // Back up base.
|
||||||
__ movsd(xmm4, xmm1); // Back up base.
|
__ movsd(double_scratch2, double_result); // Load double_exponent with 1.
|
||||||
__ movsd(xmm2, xmm3); // Load xmm2 with 1.
|
|
||||||
|
|
||||||
|
|
||||||
// Get absolute value of exponent.
|
// Get absolute value of exponent.
|
||||||
Label no_neg, while_true, no_multiply;
|
Label no_neg, while_true, no_multiply;
|
||||||
__ cmp(eax, 0);
|
__ cmp(exponent, 0);
|
||||||
__ j(greater_equal, &no_neg, Label::kNear);
|
__ j(greater_equal, &no_neg, Label::kNear);
|
||||||
__ neg(eax);
|
__ neg(exponent);
|
||||||
__ bind(&no_neg);
|
__ bind(&no_neg);
|
||||||
|
|
||||||
__ bind(&while_true);
|
__ bind(&while_true);
|
||||||
__ shr(eax, 1);
|
__ shr(exponent, 1);
|
||||||
__ j(not_carry, &no_multiply, Label::kNear);
|
__ j(not_carry, &no_multiply, Label::kNear);
|
||||||
__ mulsd(xmm3, xmm1);
|
__ mulsd(double_result, double_base);
|
||||||
__ bind(&no_multiply);
|
__ bind(&no_multiply);
|
||||||
|
|
||||||
__ mulsd(xmm1, xmm1);
|
__ mulsd(double_base, double_base);
|
||||||
__ j(not_zero, &while_true);
|
__ j(not_zero, &while_true);
|
||||||
|
|
||||||
// base has the original value of the exponent - if the exponent is
|
// scratch has the original value of the exponent - if the exponent is
|
||||||
// negative return 1/result.
|
// negative, return 1/result.
|
||||||
__ test(ecx, ecx);
|
__ test(scratch, scratch);
|
||||||
__ j(positive, &done);
|
__ j(positive, &done);
|
||||||
__ divsd(xmm2, xmm3);
|
__ divsd(double_scratch2, double_result);
|
||||||
__ movsd(xmm3, xmm2);
|
__ movsd(double_result, double_scratch2);
|
||||||
// Test whether result is zero. Bail out to check for subnormal result.
|
// Test whether result is zero. Bail out to check for subnormal result.
|
||||||
// Due to subnormals, x^-y == (1/x)^y does not hold in all cases.
|
// Due to subnormals, x^-y == (1/x)^y does not hold in all cases.
|
||||||
__ xorps(xmm2, xmm2);
|
__ xorps(double_scratch2, double_scratch2);
|
||||||
__ ucomisd(xmm2, xmm3); // Result cannot be NaN.
|
__ ucomisd(double_scratch2, double_result); // Result cannot be NaN.
|
||||||
__ j(equal, &double_int_runtime);
|
__ j(equal, &double_int_runtime);
|
||||||
|
|
||||||
// Returning or bailing out.
|
// Returning or bailing out.
|
||||||
if (exponent_type_ == ON_STACK) {
|
if (exponent_type_ == ON_STACK) {
|
||||||
// The stub is called from non-optimized code, which expects the result
|
// The stub is called from non-optimized code, which expects the result
|
||||||
// as heap number in eax.
|
// as heap number in exponent.
|
||||||
__ bind(&done);
|
__ bind(&done);
|
||||||
// xmm3: result
|
__ AllocateHeapNumber(exponent, scratch, base, &generic_runtime);
|
||||||
__ AllocateHeapNumber(eax, ecx, edx, &generic_runtime);
|
__ movdbl(FieldOperand(exponent, HeapNumber::kValueOffset), double_result);
|
||||||
__ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm3);
|
|
||||||
__ ret(2 * kPointerSize);
|
__ ret(2 * kPointerSize);
|
||||||
|
|
||||||
// The arguments are still on the stack.
|
// The arguments are still on the stack.
|
||||||
@ -3170,28 +3174,23 @@ void MathPowStub::Generate(MacroAssembler* masm) {
|
|||||||
__ jmp(&done);
|
__ jmp(&done);
|
||||||
|
|
||||||
Label return_from_runtime;
|
Label return_from_runtime;
|
||||||
StubRuntimeCallHelper callhelper;
|
|
||||||
__ bind(&generic_runtime);
|
__ bind(&generic_runtime);
|
||||||
// xmm1: base
|
|
||||||
// xmm2: exponent
|
|
||||||
{
|
{
|
||||||
AllowExternalCallThatCantCauseGC scope(masm);
|
AllowExternalCallThatCantCauseGC scope(masm);
|
||||||
__ PrepareCallCFunction(4, eax);
|
__ PrepareCallCFunction(4, exponent);
|
||||||
__ movdbl(Operand(esp, 0 * kDoubleSize), xmm1);
|
__ movdbl(Operand(esp, 0 * kDoubleSize), double_base);
|
||||||
__ movdbl(Operand(esp, 1 * kDoubleSize), xmm2);
|
__ movdbl(Operand(esp, 1 * kDoubleSize), double_exponent);
|
||||||
__ CallCFunction(
|
__ CallCFunction(
|
||||||
ExternalReference::power_double_double_function(masm->isolate()), 4);
|
ExternalReference::power_double_double_function(masm->isolate()), 4);
|
||||||
}
|
}
|
||||||
__ jmp(&return_from_runtime, Label::kNear);
|
__ jmp(&return_from_runtime, Label::kNear);
|
||||||
|
|
||||||
__ bind(&double_int_runtime);
|
__ bind(&double_int_runtime);
|
||||||
// xmm4: base
|
|
||||||
// ecx: exponent
|
|
||||||
{
|
{
|
||||||
AllowExternalCallThatCantCauseGC scope(masm);
|
AllowExternalCallThatCantCauseGC scope(masm);
|
||||||
__ PrepareCallCFunction(4, eax);
|
__ PrepareCallCFunction(4, exponent);
|
||||||
__ movdbl(Operand(esp, 0 * kDoubleSize), xmm4);
|
__ movdbl(Operand(esp, 0 * kDoubleSize), double_scratch);
|
||||||
__ mov(Operand(esp, 1 * kDoubleSize), ecx);
|
__ mov(Operand(esp, 1 * kDoubleSize), scratch);
|
||||||
__ CallCFunction(
|
__ CallCFunction(
|
||||||
ExternalReference::power_double_int_function(masm->isolate()), 4);
|
ExternalReference::power_double_int_function(masm->isolate()), 4);
|
||||||
}
|
}
|
||||||
@ -3201,10 +3200,9 @@ void MathPowStub::Generate(MacroAssembler* masm) {
|
|||||||
// Store it into the (fixed) result register.
|
// Store it into the (fixed) result register.
|
||||||
__ sub(esp, Immediate(kDoubleSize));
|
__ sub(esp, Immediate(kDoubleSize));
|
||||||
__ fstp_d(Operand(esp, 0));
|
__ fstp_d(Operand(esp, 0));
|
||||||
__ movdbl(xmm3, Operand(esp, 0));
|
__ movdbl(double_result, Operand(esp, 0));
|
||||||
__ add(esp, Immediate(kDoubleSize));
|
__ add(esp, Immediate(kDoubleSize));
|
||||||
|
|
||||||
// xmm3: result
|
|
||||||
__ bind(&done);
|
__ bind(&done);
|
||||||
__ ret(0);
|
__ ret(0);
|
||||||
}
|
}
|
||||||
|
@ -2991,12 +2991,12 @@ void LCodeGen::DoMathPowHalf(LMathPowHalf* instr) {
|
|||||||
void LCodeGen::DoPower(LPower* instr) {
|
void LCodeGen::DoPower(LPower* instr) {
|
||||||
Representation exponent_type = instr->hydrogen()->right()->representation();
|
Representation exponent_type = instr->hydrogen()->right()->representation();
|
||||||
// Having marked this as a call, we can use any registers.
|
// Having marked this as a call, we can use any registers.
|
||||||
// Just make sure that the input registers are the expected ones.
|
// Just make sure that the input/output registers are the expected ones.
|
||||||
ASSERT(!instr->InputAt(1)->IsDoubleRegister() ||
|
ASSERT(!instr->InputAt(1)->IsDoubleRegister() ||
|
||||||
ToDoubleRegister(instr->InputAt(1)).is(xmm2));
|
ToDoubleRegister(instr->InputAt(1)).is(xmm1));
|
||||||
ASSERT(!instr->InputAt(1)->IsRegister() ||
|
ASSERT(!instr->InputAt(1)->IsRegister() ||
|
||||||
ToRegister(instr->InputAt(1)).is(eax));
|
ToRegister(instr->InputAt(1)).is(eax));
|
||||||
ASSERT(ToDoubleRegister(instr->InputAt(0)).is(xmm1));
|
ASSERT(ToDoubleRegister(instr->InputAt(0)).is(xmm2));
|
||||||
ASSERT(ToDoubleRegister(instr->result()).is(xmm3));
|
ASSERT(ToDoubleRegister(instr->result()).is(xmm3));
|
||||||
|
|
||||||
if (exponent_type.IsTagged()) {
|
if (exponent_type.IsTagged()) {
|
||||||
|
@ -1446,9 +1446,9 @@ LInstruction* LChunkBuilder::DoPower(HPower* instr) {
|
|||||||
// We need to use fixed result register for the call.
|
// We need to use fixed result register for the call.
|
||||||
Representation exponent_type = instr->right()->representation();
|
Representation exponent_type = instr->right()->representation();
|
||||||
ASSERT(instr->left()->representation().IsDouble());
|
ASSERT(instr->left()->representation().IsDouble());
|
||||||
LOperand* left = UseFixedDouble(instr->left(), xmm1);
|
LOperand* left = UseFixedDouble(instr->left(), xmm2);
|
||||||
LOperand* right = exponent_type.IsDouble() ?
|
LOperand* right = exponent_type.IsDouble() ?
|
||||||
UseFixedDouble(instr->right(), xmm2) :
|
UseFixedDouble(instr->right(), xmm1) :
|
||||||
UseFixed(instr->right(), eax);
|
UseFixed(instr->right(), eax);
|
||||||
LPower* result = new(zone()) LPower(left, right);
|
LPower* result = new(zone()) LPower(left, right);
|
||||||
return MarkAsCall(DefineFixedDouble(result, xmm3), instr,
|
return MarkAsCall(DefineFixedDouble(result, xmm3), instr,
|
||||||
|
@ -2307,6 +2307,27 @@ void Assembler::fyl2x() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Assembler::f2xm1() {
|
||||||
|
EnsureSpace ensure_space(this);
|
||||||
|
emit(0xD9);
|
||||||
|
emit(0xF0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Assembler::fscale() {
|
||||||
|
EnsureSpace ensure_space(this);
|
||||||
|
emit(0xD9);
|
||||||
|
emit(0xFD);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Assembler::fninit() {
|
||||||
|
EnsureSpace ensure_space(this);
|
||||||
|
emit(0xDB);
|
||||||
|
emit(0xE3);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Assembler::fadd(int i) {
|
void Assembler::fadd(int i) {
|
||||||
EnsureSpace ensure_space(this);
|
EnsureSpace ensure_space(this);
|
||||||
emit_farith(0xDC, 0xC0, i);
|
emit_farith(0xDC, 0xC0, i);
|
||||||
|
@ -1277,6 +1277,9 @@ class Assembler : public AssemblerBase {
|
|||||||
void fcos();
|
void fcos();
|
||||||
void fptan();
|
void fptan();
|
||||||
void fyl2x();
|
void fyl2x();
|
||||||
|
void f2xm1();
|
||||||
|
void fscale();
|
||||||
|
void fninit();
|
||||||
|
|
||||||
void frndint();
|
void frndint();
|
||||||
|
|
||||||
|
@ -1991,152 +1991,274 @@ void FloatingPointHelper::NumbersToSmis(MacroAssembler* masm,
|
|||||||
|
|
||||||
|
|
||||||
void MathPowStub::Generate(MacroAssembler* masm) {
|
void MathPowStub::Generate(MacroAssembler* masm) {
|
||||||
// Registers are used as follows:
|
// Choose register conforming to calling convention (when bailing out).
|
||||||
// rdx = base
|
#ifdef _WIN64
|
||||||
// rax = exponent
|
const Register exponent = rdx;
|
||||||
// rcx = temporary, result
|
#else
|
||||||
|
const Register exponent = rdi;
|
||||||
|
#endif
|
||||||
|
const Register base = rax;
|
||||||
|
const Register scratch = rcx;
|
||||||
|
const XMMRegister double_result = xmm3;
|
||||||
|
const XMMRegister double_base = xmm2;
|
||||||
|
const XMMRegister double_exponent = xmm1;
|
||||||
|
const XMMRegister double_scratch = xmm4;
|
||||||
|
|
||||||
Label allocate_return, call_runtime;
|
Label double_int_runtime, generic_runtime, done;
|
||||||
|
Label exponent_not_smi, int_exponent;
|
||||||
|
|
||||||
// Load input parameters.
|
// Save 1 in double_result - we need this several times later on.
|
||||||
__ movq(rdx, Operand(rsp, 2 * kPointerSize));
|
__ movq(scratch, Immediate(1));
|
||||||
__ movq(rax, Operand(rsp, 1 * kPointerSize));
|
__ cvtlsi2sd(double_result, scratch);
|
||||||
|
|
||||||
// Save 1 in xmm3 - we need this several times later on.
|
if (exponent_type_ == ON_STACK) {
|
||||||
__ Set(rcx, 1);
|
Label base_is_smi, unpack_exponent;
|
||||||
__ cvtlsi2sd(xmm3, rcx);
|
// The exponent and base are supplied as arguments on the stack.
|
||||||
|
// This can only happen if the stub is called from non-optimized code.
|
||||||
|
// Load input parameters from stack.
|
||||||
|
__ movq(base, Operand(rsp, 2 * kPointerSize));
|
||||||
|
__ movq(exponent, Operand(rsp, 1 * kPointerSize));
|
||||||
|
__ JumpIfSmi(base, &base_is_smi, Label::kNear);
|
||||||
|
__ CompareRoot(FieldOperand(base, HeapObject::kMapOffset),
|
||||||
|
Heap::kHeapNumberMapRootIndex);
|
||||||
|
__ j(not_equal, &generic_runtime);
|
||||||
|
|
||||||
Label exponent_nonsmi;
|
__ movsd(double_base, FieldOperand(base, HeapNumber::kValueOffset));
|
||||||
Label base_nonsmi;
|
__ jmp(&unpack_exponent, Label::kNear);
|
||||||
// If the exponent is a heap number go to that specific case.
|
|
||||||
__ JumpIfNotSmi(rax, &exponent_nonsmi);
|
|
||||||
__ JumpIfNotSmi(rdx, &base_nonsmi);
|
|
||||||
|
|
||||||
// Optimized version when both exponent and base are smis.
|
__ bind(&base_is_smi);
|
||||||
Label powi;
|
__ SmiToInteger32(base, base);
|
||||||
__ SmiToInteger32(rdx, rdx);
|
__ cvtlsi2sd(double_base, base);
|
||||||
__ cvtlsi2sd(xmm0, rdx);
|
__ bind(&unpack_exponent);
|
||||||
__ jmp(&powi);
|
|
||||||
// Exponent is a smi and base is a heapnumber.
|
|
||||||
__ bind(&base_nonsmi);
|
|
||||||
__ CompareRoot(FieldOperand(rdx, HeapObject::kMapOffset),
|
|
||||||
Heap::kHeapNumberMapRootIndex);
|
|
||||||
__ j(not_equal, &call_runtime);
|
|
||||||
|
|
||||||
__ movsd(xmm0, FieldOperand(rdx, HeapNumber::kValueOffset));
|
__ JumpIfNotSmi(exponent, &exponent_not_smi, Label::kNear);
|
||||||
|
__ SmiToInteger32(exponent, exponent);
|
||||||
|
__ jmp(&int_exponent);
|
||||||
|
|
||||||
// Optimized version of pow if exponent is a smi.
|
__ bind(&exponent_not_smi);
|
||||||
// xmm0 contains the base.
|
__ CompareRoot(FieldOperand(exponent, HeapObject::kMapOffset),
|
||||||
__ bind(&powi);
|
Heap::kHeapNumberMapRootIndex);
|
||||||
__ SmiToInteger32(rax, rax);
|
__ j(not_equal, &generic_runtime);
|
||||||
|
__ movsd(double_exponent, FieldOperand(exponent, HeapNumber::kValueOffset));
|
||||||
|
} else if (exponent_type_ == TAGGED) {
|
||||||
|
__ JumpIfNotSmi(exponent, &exponent_not_smi, Label::kNear);
|
||||||
|
__ SmiToInteger32(exponent, exponent);
|
||||||
|
__ jmp(&int_exponent);
|
||||||
|
|
||||||
// Save exponent in base as we need to check if exponent is negative later.
|
__ bind(&exponent_not_smi);
|
||||||
// We know that base and exponent are in different registers.
|
__ movsd(double_exponent, FieldOperand(exponent, HeapNumber::kValueOffset));
|
||||||
__ movq(rdx, rax);
|
}
|
||||||
|
|
||||||
|
if (exponent_type_ != INTEGER) {
|
||||||
|
Label fast_power;
|
||||||
|
// Detect integer exponents stored as double.
|
||||||
|
__ cvttsd2si(exponent, double_exponent);
|
||||||
|
// Skip to runtime if possibly NaN (indicated by the indefinite integer).
|
||||||
|
__ cmpl(exponent, Immediate(0x80000000u));
|
||||||
|
__ j(equal, &generic_runtime);
|
||||||
|
__ cvtlsi2sd(double_scratch, exponent);
|
||||||
|
// Already ruled out NaNs for exponent.
|
||||||
|
__ ucomisd(double_exponent, double_scratch);
|
||||||
|
__ j(equal, &int_exponent);
|
||||||
|
|
||||||
|
if (exponent_type_ == ON_STACK) {
|
||||||
|
// Detect square root case. Crankshaft detects constant +/-0.5 at
|
||||||
|
// compile time and uses DoMathPowHalf instead. We then skip this check
|
||||||
|
// for non-constant cases of +/-0.5 as these hardly occur.
|
||||||
|
Label continue_sqrt, continue_rsqrt, not_plus_half;
|
||||||
|
// Test for 0.5.
|
||||||
|
// Load double_scratch with 0.5.
|
||||||
|
__ movq(scratch, V8_UINT64_C(0x3FE0000000000000), RelocInfo::NONE);
|
||||||
|
__ movq(double_scratch, scratch);
|
||||||
|
// Already ruled out NaNs for exponent.
|
||||||
|
__ ucomisd(double_scratch, double_exponent);
|
||||||
|
__ j(not_equal, ¬_plus_half, Label::kNear);
|
||||||
|
|
||||||
|
// Calculates square root of base. Check for the special case of
|
||||||
|
// Math.pow(-Infinity, 0.5) == Infinity (ECMA spec, 15.8.2.13).
|
||||||
|
// According to IEEE-754, double-precision -Infinity has the highest
|
||||||
|
// 12 bits set and the lowest 52 bits cleared.
|
||||||
|
__ movq(scratch, V8_UINT64_C(0xFFF0000000000000), RelocInfo::NONE);
|
||||||
|
__ movq(double_scratch, scratch);
|
||||||
|
__ ucomisd(double_scratch, double_base);
|
||||||
|
// Comparing -Infinity with NaN results in "unordered", which sets the
|
||||||
|
// zero flag as if both were equal. However, it also sets the carry flag.
|
||||||
|
__ j(not_equal, &continue_sqrt, Label::kNear);
|
||||||
|
__ j(carry, &continue_sqrt, Label::kNear);
|
||||||
|
|
||||||
|
// Set result to Infinity in the special case.
|
||||||
|
__ xorps(double_result, double_result);
|
||||||
|
__ subsd(double_result, double_scratch);
|
||||||
|
__ jmp(&done);
|
||||||
|
|
||||||
|
__ bind(&continue_sqrt);
|
||||||
|
// sqrtsd returns -0 when input is -0. ECMA spec requires +0.
|
||||||
|
__ xorps(double_scratch, double_scratch);
|
||||||
|
__ addsd(double_scratch, double_base); // Convert -0 to 0.
|
||||||
|
__ sqrtsd(double_result, double_scratch);
|
||||||
|
__ jmp(&done);
|
||||||
|
|
||||||
|
// Test for -0.5.
|
||||||
|
__ bind(¬_plus_half);
|
||||||
|
// Load double_scratch with -0.5 by substracting 1.
|
||||||
|
__ subsd(double_scratch, double_result);
|
||||||
|
// Already ruled out NaNs for exponent.
|
||||||
|
__ ucomisd(double_scratch, double_exponent);
|
||||||
|
__ j(not_equal, &fast_power, Label::kNear);
|
||||||
|
|
||||||
|
// Calculates reciprocal of square root of base. Check for the special
|
||||||
|
// case of Math.pow(-Infinity, -0.5) == 0 (ECMA spec, 15.8.2.13).
|
||||||
|
// According to IEEE-754, double-precision -Infinity has the highest
|
||||||
|
// 12 bits set and the lowest 52 bits cleared.
|
||||||
|
__ movq(scratch, V8_UINT64_C(0xFFF0000000000000), RelocInfo::NONE);
|
||||||
|
__ movq(double_scratch, scratch);
|
||||||
|
__ ucomisd(double_scratch, double_base);
|
||||||
|
// Comparing -Infinity with NaN results in "unordered", which sets the
|
||||||
|
// zero flag as if both were equal. However, it also sets the carry flag.
|
||||||
|
__ j(not_equal, &continue_rsqrt, Label::kNear);
|
||||||
|
__ j(carry, &continue_rsqrt, Label::kNear);
|
||||||
|
|
||||||
|
// Set result to 0 in the special case.
|
||||||
|
__ xorps(double_result, double_result);
|
||||||
|
__ jmp(&done);
|
||||||
|
|
||||||
|
__ bind(&continue_rsqrt);
|
||||||
|
// sqrtsd returns -0 when input is -0. ECMA spec requires +0.
|
||||||
|
__ xorps(double_exponent, double_exponent);
|
||||||
|
__ addsd(double_exponent, double_base); // Convert -0 to +0.
|
||||||
|
__ sqrtsd(double_exponent, double_exponent);
|
||||||
|
__ divsd(double_result, double_exponent);
|
||||||
|
__ jmp(&done);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Using FPU instructions to calculate power.
|
||||||
|
Label fast_power_failed;
|
||||||
|
__ bind(&fast_power);
|
||||||
|
__ fnclex(); // Clear flags to catch exceptions later.
|
||||||
|
// Transfer (B)ase and (E)xponent onto the FPU register stack.
|
||||||
|
__ subq(rsp, Immediate(kDoubleSize));
|
||||||
|
__ movsd(Operand(rsp, 0), double_exponent);
|
||||||
|
__ fld_d(Operand(rsp, 0)); // E
|
||||||
|
__ movsd(Operand(rsp, 0), double_base);
|
||||||
|
__ fld_d(Operand(rsp, 0)); // B, E
|
||||||
|
|
||||||
|
// Exponent is in st(1) and base is in st(0)
|
||||||
|
// B ^ E = (2^(E * log2(B)) - 1) + 1 = (2^X - 1) + 1 for X = E * log2(B)
|
||||||
|
// FYL2X calculates st(1) * log2(st(0))
|
||||||
|
__ fyl2x(); // X
|
||||||
|
__ fld(0); // X, X
|
||||||
|
__ frndint(); // rnd(X), X
|
||||||
|
__ fsub(1); // rnd(X), X-rnd(X)
|
||||||
|
__ fxch(1); // X - rnd(X), rnd(X)
|
||||||
|
// F2XM1 calculates 2^st(0) - 1 for -1 < st(0) < 1
|
||||||
|
__ f2xm1(); // 2^(X-rnd(X)) - 1, rnd(X)
|
||||||
|
__ fld1(); // 1, 2^(X-rnd(X)) - 1, rnd(X)
|
||||||
|
__ faddp(1); // 1, 2^(X-rnd(X)), rnd(X)
|
||||||
|
// FSCALE calculates st(0) * 2^st(1)
|
||||||
|
__ fscale(); // 2^X, rnd(X)
|
||||||
|
__ fstp(1);
|
||||||
|
// Bail out to runtime in case of exceptions in the status word.
|
||||||
|
__ fnstsw_ax();
|
||||||
|
__ testb(rax, Immediate(0x5F)); // Check for all but precision exception.
|
||||||
|
__ j(not_zero, &fast_power_failed, Label::kNear);
|
||||||
|
__ fstp_d(Operand(rsp, 0));
|
||||||
|
__ movsd(double_result, Operand(rsp, 0));
|
||||||
|
__ addq(rsp, Immediate(kDoubleSize));
|
||||||
|
__ jmp(&done);
|
||||||
|
|
||||||
|
__ bind(&fast_power_failed);
|
||||||
|
__ fninit();
|
||||||
|
__ addq(rsp, Immediate(kDoubleSize));
|
||||||
|
__ jmp(&generic_runtime);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate power with integer exponent.
|
||||||
|
__ bind(&int_exponent);
|
||||||
|
const XMMRegister double_scratch2 = double_exponent;
|
||||||
|
// Back up exponent as we need to check if exponent is negative later.
|
||||||
|
__ movq(scratch, exponent); // Back up exponent.
|
||||||
|
__ movsd(double_scratch, double_base); // Back up base.
|
||||||
|
__ movsd(double_scratch2, double_result); // Load double_exponent with 1.
|
||||||
|
|
||||||
// Get absolute value of exponent.
|
// Get absolute value of exponent.
|
||||||
Label no_neg;
|
Label no_neg, while_true, no_multiply;
|
||||||
__ cmpl(rax, Immediate(0));
|
__ cmpl(scratch, Immediate(0));
|
||||||
__ j(greater_equal, &no_neg, Label::kNear);
|
__ j(positive, &no_neg, Label::kNear);
|
||||||
__ negl(rax);
|
__ negl(scratch);
|
||||||
__ bind(&no_neg);
|
__ bind(&no_neg);
|
||||||
|
|
||||||
// Load xmm1 with 1.
|
|
||||||
__ movaps(xmm1, xmm3);
|
|
||||||
Label while_true;
|
|
||||||
Label no_multiply;
|
|
||||||
|
|
||||||
__ bind(&while_true);
|
__ bind(&while_true);
|
||||||
__ shrl(rax, Immediate(1));
|
__ shrl(scratch, Immediate(1));
|
||||||
__ j(not_carry, &no_multiply, Label::kNear);
|
__ j(not_carry, &no_multiply, Label::kNear);
|
||||||
__ mulsd(xmm1, xmm0);
|
__ mulsd(double_result, double_scratch);
|
||||||
__ bind(&no_multiply);
|
__ bind(&no_multiply);
|
||||||
__ mulsd(xmm0, xmm0);
|
|
||||||
|
__ mulsd(double_scratch, double_scratch);
|
||||||
__ j(not_zero, &while_true);
|
__ j(not_zero, &while_true);
|
||||||
|
|
||||||
// Base has the original value of the exponent - if the exponent is
|
// scratch has the original value of the exponent - if the exponent is
|
||||||
// negative return 1/result.
|
// negative, return 1/result.
|
||||||
__ testl(rdx, rdx);
|
__ testl(exponent, exponent);
|
||||||
__ j(positive, &allocate_return);
|
__ j(greater, &done);
|
||||||
// Special case if xmm1 has reached infinity.
|
__ divsd(double_scratch2, double_result);
|
||||||
__ divsd(xmm3, xmm1);
|
__ movsd(double_result, double_scratch2);
|
||||||
__ movaps(xmm1, xmm3);
|
// Test whether result is zero. Bail out to check for subnormal result.
|
||||||
__ xorps(xmm0, xmm0);
|
// Due to subnormals, x^-y == (1/x)^y does not hold in all cases.
|
||||||
__ ucomisd(xmm0, xmm1);
|
__ xorps(double_scratch2, double_scratch2);
|
||||||
__ j(equal, &call_runtime);
|
__ ucomisd(double_scratch2, double_result);
|
||||||
|
__ j(equal, &double_int_runtime);
|
||||||
|
|
||||||
__ jmp(&allocate_return);
|
// Returning or bailing out.
|
||||||
|
if (exponent_type_ == ON_STACK) {
|
||||||
|
// The stub is called from non-optimized code, which expects the result
|
||||||
|
// as heap number in eax.
|
||||||
|
__ bind(&done);
|
||||||
|
__ AllocateHeapNumber(rax, rcx, &generic_runtime);
|
||||||
|
__ movsd(FieldOperand(rax, HeapNumber::kValueOffset), double_result);
|
||||||
|
__ ret(2 * kPointerSize);
|
||||||
|
|
||||||
// Exponent (or both) is a heapnumber - no matter what we should now work
|
// The arguments are still on the stack.
|
||||||
// on doubles.
|
__ bind(&generic_runtime);
|
||||||
__ bind(&exponent_nonsmi);
|
__ bind(&double_int_runtime);
|
||||||
__ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset),
|
__ TailCallRuntime(Runtime::kMath_pow_cfunction, 2, 1);
|
||||||
Heap::kHeapNumberMapRootIndex);
|
} else {
|
||||||
__ j(not_equal, &call_runtime);
|
__ jmp(&done);
|
||||||
__ movsd(xmm1, FieldOperand(rax, HeapNumber::kValueOffset));
|
|
||||||
// Test if exponent is nan.
|
|
||||||
__ ucomisd(xmm1, xmm1);
|
|
||||||
__ j(parity_even, &call_runtime);
|
|
||||||
|
|
||||||
Label base_not_smi, handle_special_cases;
|
Label return_from_runtime;
|
||||||
__ JumpIfNotSmi(rdx, &base_not_smi, Label::kNear);
|
StubRuntimeCallHelper callhelper;
|
||||||
__ SmiToInteger32(rdx, rdx);
|
__ bind(&generic_runtime);
|
||||||
__ cvtlsi2sd(xmm0, rdx);
|
// Move base to the correct argument register. Exponent is already in xmm1.
|
||||||
__ jmp(&handle_special_cases, Label::kNear);
|
__ movsd(xmm0, double_base);
|
||||||
|
ASSERT(double_exponent.is(xmm1));
|
||||||
|
{
|
||||||
|
AllowExternalCallThatCantCauseGC scope(masm);
|
||||||
|
__ PrepareCallCFunction(2);
|
||||||
|
__ CallCFunction(
|
||||||
|
ExternalReference::power_double_double_function(masm->isolate()), 2);
|
||||||
|
}
|
||||||
|
__ jmp(&return_from_runtime, Label::kNear);
|
||||||
|
|
||||||
__ bind(&base_not_smi);
|
__ bind(&double_int_runtime);
|
||||||
__ CompareRoot(FieldOperand(rdx, HeapObject::kMapOffset),
|
// Move base to the correct argument register.
|
||||||
Heap::kHeapNumberMapRootIndex);
|
__ movsd(xmm0, double_base);
|
||||||
__ j(not_equal, &call_runtime);
|
// Exponent is already in the correct argument register:
|
||||||
__ movl(rcx, FieldOperand(rdx, HeapNumber::kExponentOffset));
|
// edi (not rdi) on Linux and edx on Windows.
|
||||||
__ andl(rcx, Immediate(HeapNumber::kExponentMask));
|
{
|
||||||
__ cmpl(rcx, Immediate(HeapNumber::kExponentMask));
|
AllowExternalCallThatCantCauseGC scope(masm);
|
||||||
// base is NaN or +/-Infinity
|
__ PrepareCallCFunction(2);
|
||||||
__ j(greater_equal, &call_runtime);
|
__ CallCFunction(
|
||||||
__ movsd(xmm0, FieldOperand(rdx, HeapNumber::kValueOffset));
|
ExternalReference::power_double_int_function(masm->isolate()), 2);
|
||||||
|
}
|
||||||
|
|
||||||
// base is in xmm0 and exponent is in xmm1.
|
__ bind(&return_from_runtime);
|
||||||
__ bind(&handle_special_cases);
|
// Return value is in xmm0.
|
||||||
Label not_minus_half;
|
__ movsd(double_result, xmm0);
|
||||||
// Test for -0.5.
|
// Restore context register.
|
||||||
// Load xmm2 with -0.5.
|
__ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
|
||||||
__ movq(rcx, V8_UINT64_C(0xBFE0000000000000), RelocInfo::NONE);
|
|
||||||
__ movq(xmm2, rcx);
|
|
||||||
// xmm2 now has -0.5.
|
|
||||||
__ ucomisd(xmm2, xmm1);
|
|
||||||
__ j(not_equal, ¬_minus_half, Label::kNear);
|
|
||||||
|
|
||||||
// Calculates reciprocal of square root.
|
__ bind(&done);
|
||||||
// sqrtsd returns -0 when input is -0. ECMA spec requires +0.
|
__ ret(0);
|
||||||
__ xorps(xmm1, xmm1);
|
}
|
||||||
__ addsd(xmm1, xmm0);
|
|
||||||
__ sqrtsd(xmm1, xmm1);
|
|
||||||
__ divsd(xmm3, xmm1);
|
|
||||||
__ movaps(xmm1, xmm3);
|
|
||||||
__ jmp(&allocate_return);
|
|
||||||
|
|
||||||
// Test for 0.5.
|
|
||||||
__ bind(¬_minus_half);
|
|
||||||
// Load xmm2 with 0.5.
|
|
||||||
// Since xmm3 is 1 and xmm2 is -0.5 this is simply xmm2 + xmm3.
|
|
||||||
__ addsd(xmm2, xmm3);
|
|
||||||
// xmm2 now has 0.5.
|
|
||||||
__ ucomisd(xmm2, xmm1);
|
|
||||||
__ j(not_equal, &call_runtime);
|
|
||||||
// Calculates square root.
|
|
||||||
// sqrtsd returns -0 when input is -0. ECMA spec requires +0.
|
|
||||||
__ xorps(xmm1, xmm1);
|
|
||||||
__ addsd(xmm1, xmm0); // Convert -0 to 0.
|
|
||||||
__ sqrtsd(xmm1, xmm1);
|
|
||||||
|
|
||||||
__ bind(&allocate_return);
|
|
||||||
__ AllocateHeapNumber(rcx, rax, &call_runtime);
|
|
||||||
__ movsd(FieldOperand(rcx, HeapNumber::kValueOffset), xmm1);
|
|
||||||
__ movq(rax, rcx);
|
|
||||||
__ ret(2 * kPointerSize);
|
|
||||||
|
|
||||||
__ bind(&call_runtime);
|
|
||||||
__ TailCallRuntime(Runtime::kMath_pow_cfunction, 2, 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -911,15 +911,19 @@ int DisassemblerX64::RegisterFPUInstruction(int escape_opcode,
|
|||||||
switch (modrm_byte) {
|
switch (modrm_byte) {
|
||||||
case 0xE0: mnem = "fchs"; break;
|
case 0xE0: mnem = "fchs"; break;
|
||||||
case 0xE1: mnem = "fabs"; break;
|
case 0xE1: mnem = "fabs"; break;
|
||||||
|
case 0xE3: mnem = "fninit"; break;
|
||||||
case 0xE4: mnem = "ftst"; break;
|
case 0xE4: mnem = "ftst"; break;
|
||||||
case 0xE8: mnem = "fld1"; break;
|
case 0xE8: mnem = "fld1"; break;
|
||||||
case 0xEB: mnem = "fldpi"; break;
|
case 0xEB: mnem = "fldpi"; break;
|
||||||
case 0xED: mnem = "fldln2"; break;
|
case 0xED: mnem = "fldln2"; break;
|
||||||
case 0xEE: mnem = "fldz"; break;
|
case 0xEE: mnem = "fldz"; break;
|
||||||
|
case 0xF0: mnem = "f2xm1"; break;
|
||||||
case 0xF1: mnem = "fyl2x"; break;
|
case 0xF1: mnem = "fyl2x"; break;
|
||||||
|
case 0xF2: mnem = "fptan"; break;
|
||||||
case 0xF5: mnem = "fprem1"; break;
|
case 0xF5: mnem = "fprem1"; break;
|
||||||
case 0xF7: mnem = "fincstp"; break;
|
case 0xF7: mnem = "fincstp"; break;
|
||||||
case 0xF8: mnem = "fprem"; break;
|
case 0xF8: mnem = "fprem"; break;
|
||||||
|
case 0xFD: mnem = "fscale"; break;
|
||||||
case 0xFE: mnem = "fsin"; break;
|
case 0xFE: mnem = "fsin"; break;
|
||||||
case 0xFF: mnem = "fcos"; break;
|
case 0xFF: mnem = "fcos"; break;
|
||||||
default: UnimplementedInstruction();
|
default: UnimplementedInstruction();
|
||||||
|
@ -2880,58 +2880,39 @@ void LCodeGen::DoMathPowHalf(LUnaryMathOperation* instr) {
|
|||||||
|
|
||||||
|
|
||||||
void LCodeGen::DoPower(LPower* instr) {
|
void LCodeGen::DoPower(LPower* instr) {
|
||||||
LOperand* left = instr->InputAt(0);
|
|
||||||
XMMRegister left_reg = ToDoubleRegister(left);
|
|
||||||
ASSERT(!left_reg.is(xmm1));
|
|
||||||
LOperand* right = instr->InputAt(1);
|
|
||||||
XMMRegister result_reg = ToDoubleRegister(instr->result());
|
|
||||||
Representation exponent_type = instr->hydrogen()->right()->representation();
|
Representation exponent_type = instr->hydrogen()->right()->representation();
|
||||||
if (exponent_type.IsDouble()) {
|
// Having marked this as a call, we can use any registers.
|
||||||
__ PrepareCallCFunction(2);
|
// Just make sure that the input/output registers are the expected ones.
|
||||||
// Move arguments to correct registers
|
|
||||||
__ movaps(xmm0, left_reg);
|
// Choose register conforming to calling convention (when bailing out).
|
||||||
ASSERT(ToDoubleRegister(right).is(xmm1));
|
|
||||||
__ CallCFunction(
|
|
||||||
ExternalReference::power_double_double_function(isolate()), 2);
|
|
||||||
} else if (exponent_type.IsInteger32()) {
|
|
||||||
__ PrepareCallCFunction(2);
|
|
||||||
// Move arguments to correct registers: xmm0 and edi (not rdi).
|
|
||||||
// On Windows, the registers are xmm0 and edx.
|
|
||||||
__ movaps(xmm0, left_reg);
|
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
ASSERT(ToRegister(right).is(rdx));
|
Register exponent = rdx;
|
||||||
#else
|
#else
|
||||||
ASSERT(ToRegister(right).is(rdi));
|
Register exponent = rdi;
|
||||||
#endif
|
#endif
|
||||||
__ CallCFunction(
|
ASSERT(!instr->InputAt(1)->IsRegister() ||
|
||||||
ExternalReference::power_double_int_function(isolate()), 2);
|
ToRegister(instr->InputAt(1)).is(exponent));
|
||||||
} else {
|
ASSERT(!instr->InputAt(1)->IsDoubleRegister() ||
|
||||||
ASSERT(exponent_type.IsTagged());
|
ToDoubleRegister(instr->InputAt(1)).is(xmm1));
|
||||||
Register right_reg = ToRegister(right);
|
ASSERT(ToDoubleRegister(instr->InputAt(0)).is(xmm2));
|
||||||
|
ASSERT(ToDoubleRegister(instr->result()).is(xmm3));
|
||||||
|
|
||||||
Label non_smi, call;
|
if (exponent_type.IsTagged()) {
|
||||||
__ JumpIfNotSmi(right_reg, &non_smi);
|
Label no_deopt;
|
||||||
__ SmiToInteger32(right_reg, right_reg);
|
__ JumpIfSmi(exponent, &no_deopt);
|
||||||
__ cvtlsi2sd(xmm1, right_reg);
|
__ CmpObjectType(exponent, HEAP_NUMBER_TYPE, rcx);
|
||||||
__ jmp(&call);
|
|
||||||
|
|
||||||
__ bind(&non_smi);
|
|
||||||
__ CmpObjectType(right_reg, HEAP_NUMBER_TYPE , kScratchRegister);
|
|
||||||
DeoptimizeIf(not_equal, instr->environment());
|
DeoptimizeIf(not_equal, instr->environment());
|
||||||
__ movsd(xmm1, FieldOperand(right_reg, HeapNumber::kValueOffset));
|
__ bind(&no_deopt);
|
||||||
|
MathPowStub stub(MathPowStub::TAGGED);
|
||||||
__ bind(&call);
|
__ CallStub(&stub);
|
||||||
__ PrepareCallCFunction(2);
|
} else if (exponent_type.IsInteger32()) {
|
||||||
// Move arguments to correct registers xmm0 and xmm1.
|
MathPowStub stub(MathPowStub::INTEGER);
|
||||||
__ movaps(xmm0, left_reg);
|
__ CallStub(&stub);
|
||||||
// Right argument is already in xmm1.
|
} else {
|
||||||
__ CallCFunction(
|
ASSERT(exponent_type.IsDouble());
|
||||||
ExternalReference::power_double_double_function(isolate()), 2);
|
MathPowStub stub(MathPowStub::DOUBLE);
|
||||||
|
__ CallStub(&stub);
|
||||||
}
|
}
|
||||||
// Return value is in xmm0.
|
|
||||||
__ movaps(result_reg, xmm0);
|
|
||||||
// Restore context register.
|
|
||||||
__ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1397,7 +1397,7 @@ LInstruction* LChunkBuilder::DoPower(HPower* instr) {
|
|||||||
UseFixed(instr->right(), rdi);
|
UseFixed(instr->right(), rdi);
|
||||||
#endif
|
#endif
|
||||||
LPower* result = new LPower(left, right);
|
LPower* result = new LPower(left, right);
|
||||||
return MarkAsCall(DefineFixedDouble(result, xmm1), instr,
|
return MarkAsCall(DefineFixedDouble(result, xmm3), instr,
|
||||||
CAN_DEOPTIMIZE_EAGERLY);
|
CAN_DEOPTIMIZE_EAGERLY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user