ASSERT(args->length() == 2);
VisitForStackValue(args->at(0));
VisitForStackValue(args->at(1));
- MathPowStub stub;
+ MathPowStub stub(MathPowStub::ON_STACK);
__ CallStub(&stub);
context()->Plug(r0);
}
double power_double_double(double x, double y) {
+ // The checks for special cases can be dropped in ia32 because it has already
+ // been done in generated code before bailing out here.
+#if !defined(V8_TARGET_ARCH_IA32)
int y_int = static_cast<int>(y);
if (y == y_int) {
return power_double_int(x, y_int); // Returns 1.0 for exponent 0.
if (y == 0.5) return sqrt(x + 0.0); // -0 must be converted to +0.
if (y == -0.5) return 1.0 / sqrt(x + 0.0);
}
+#endif
if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
return OS::nan_value();
}
class MathPowStub: public CodeStub {
public:
- MathPowStub() {}
+ enum ExponentType { INTEGER, DOUBLE, TAGGED, ON_STACK};
+
+ explicit MathPowStub(ExponentType exponent_type)
+ : exponent_type_(exponent_type) { }
virtual void Generate(MacroAssembler* masm);
private:
virtual CodeStub::Major MajorKey() { return MathPow; }
- virtual int MinorKey() { return 0; }
+ virtual int MinorKey() { return exponent_type_; }
+
+ ExponentType exponent_type_;
};
}
+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) {
EnsureSpace ensure_space(this);
emit_farith(0xDC, 0xC0, i);
}
+void Assembler::extractps(Register dst, XMMRegister src, byte imm8) {
+ ASSERT(CpuFeatures::IsSupported(SSE4_1));
+ ASSERT(is_uint8(imm8));
+ EnsureSpace ensure_space(this);
+ EMIT(0x66);
+ EMIT(0x0F);
+ EMIT(0x3A);
+ EMIT(0x17);
+ emit_sse_operand(dst, src);
+ EMIT(imm8);
+}
+
+
void Assembler::pand(XMMRegister dst, XMMRegister src) {
ASSERT(CpuFeatures::IsEnabled(SSE2));
EnsureSpace ensure_space(this);
void fsin();
void fptan();
void fyl2x();
+ void f2xm1();
+ void fscale();
+ void fninit();
void fadd(int i);
void fsub(int i);
void movss(XMMRegister dst, const Operand& src);
void movss(const Operand& dst, XMMRegister src);
void movss(XMMRegister dst, XMMRegister src);
+ void extractps(Register dst, XMMRegister src, byte imm8);
void pand(XMMRegister dst, XMMRegister src);
void pxor(XMMRegister dst, XMMRegister src);
void MathPowStub::Generate(MacroAssembler* masm) {
- // Registers are used as follows:
- // edx = base
- // eax = exponent
- // ecx = temporary, result
-
CpuFeatures::Scope use_sse2(SSE2);
- Label allocate_return, call_runtime;
-
- // Load input parameters.
- __ mov(edx, Operand(esp, 2 * kPointerSize));
- __ mov(eax, Operand(esp, 1 * kPointerSize));
-
+ Factory* factory = masm->isolate()->factory();
+ Label double_int_runtime, generic_runtime, done;
+ Label base_is_smi, unpack_exponent, exponent_not_smi, int_exponent;
// Save 1 in xmm3 - we need this several times later on.
__ mov(ecx, Immediate(1));
__ cvtsi2sd(xmm3, ecx);
- Label exponent_nonsmi;
- Label base_nonsmi;
- // If the exponent is a heap number go to that specific case.
- __ JumpIfNotSmi(eax, &exponent_nonsmi);
- __ JumpIfNotSmi(edx, &base_nonsmi);
+ switch (exponent_type_) {
+ case ON_STACK:
+ // 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
+ __ mov(edx, Operand(esp, 2 * kPointerSize));
+ __ mov(eax, Operand(esp, 1 * kPointerSize));
+ // edx: base (smi or heap number)
+ // eax: exponent (smi or heap number)
+ __ JumpIfSmi(edx, &base_is_smi, Label::kNear);
+ __ cmp(FieldOperand(edx, HeapObject::kMapOffset),
+ factory->heap_number_map());
+ __ j(not_equal, &generic_runtime);
+
+ // Check base for NaN or +/-Infinity
+ __ mov(ecx, FieldOperand(edx, HeapNumber::kExponentOffset));
+ __ and_(ecx, HeapNumber::kExponentMask);
+ __ cmp(ecx, Immediate(HeapNumber::kExponentMask));
+ __ j(equal, &generic_runtime);
+ __ movdbl(xmm1, FieldOperand(edx, HeapNumber::kValueOffset));
+ __ jmp(&unpack_exponent, Label::kNear);
+
+ __ bind(&base_is_smi);
+ __ SmiUntag(edx);
+ __ cvtsi2sd(xmm1, edx);
+ __ bind(&unpack_exponent);
+
+ __ JumpIfNotSmi(eax, &exponent_not_smi, Label::kNear);
+ __ SmiUntag(eax);
+ __ jmp(&int_exponent);
+
+ __ bind(&exponent_not_smi);
+ __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
+ factory->heap_number_map());
+ __ j(not_equal, &generic_runtime);
+ __ movdbl(xmm2, FieldOperand(eax, HeapNumber::kValueOffset));
+ break;
- // Optimized version when both exponent and base are smis.
- Label powi;
- __ SmiUntag(edx);
- __ cvtsi2sd(xmm0, edx);
- __ jmp(&powi);
- // exponent is smi and base is a heapnumber.
- __ bind(&base_nonsmi);
- Factory* factory = masm->isolate()->factory();
- __ cmp(FieldOperand(edx, HeapObject::kMapOffset),
- factory->heap_number_map());
- __ j(not_equal, &call_runtime);
+ case TAGGED:
+ // xmm1: base as double
+ // eax: exponent (smi or heap number)
+ __ JumpIfNotSmi(eax, &exponent_not_smi, Label::kNear);
+ __ SmiUntag(eax);
+ __ jmp(&int_exponent);
+
+ __ bind(&exponent_not_smi);
+ __ movdbl(xmm2, FieldOperand(eax, HeapNumber::kValueOffset));
+ // Fall through intended
+ case INTEGER:
+ // xmm1: base as double
+ // eax: exponent as untagged integer
+ case DOUBLE:
+ // xmm1: base as double
+ // xmm2: exponent as double
+ // Check base in xmm1 for NaN or +/-Infinity
+ const int kExponentShift = kBitsPerByte *
+ (HeapNumber::kExponentOffset - HeapNumber::kMantissaOffset);
+ if (CpuFeatures::IsSupported(SSE4_1)) {
+ __ extractps(ecx, xmm1, kExponentShift);
+ } else {
+ __ movsd(xmm4, xmm1);
+ __ psrlq(xmm4, kExponentShift);
+ __ movd(ecx, xmm4);
+ }
+ __ and_(ecx, HeapNumber::kExponentMask);
+ __ cmp(ecx, Immediate(HeapNumber::kExponentMask));
+ __ j(equal, &generic_runtime);
+ break;
+ }
- __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset));
+ if (exponent_type_ != INTEGER) {
+ Label not_minus_half, fast_power;
+ // xmm1: base as double that is not +/- Infinity or NaN
+ // xmm2: exponent as double
+ // Detect integer exponents stored as double.
+ __ cvttsd2si(eax, Operand(xmm2));
+ // Skip to runtime if possibly NaN (indicated by the indefinite integer).
+ __ cmp(eax, Immediate(0x80000000u));
+ __ j(equal, &generic_runtime);
+ __ cvtsi2sd(xmm4, eax);
+ __ ucomisd(xmm2, xmm4);
+ __ j(equal, &int_exponent);
+
+ // Detect square root case.
+ // Test for -0.5.
+ // Load xmm4 with -0.5.
+ __ mov(ecx, Immediate(0xBF000000u));
+ __ movd(xmm4, ecx);
+ __ cvtss2sd(xmm4, xmm4);
+ // xmm3 now has -0.5.
+ __ ucomisd(xmm4, xmm2);
+ __ j(not_equal, ¬_minus_half, Label::kNear);
+
+ // Calculates reciprocal of square root.eax
+ // sqrtsd returns -0 when input is -0. ECMA spec requires +0.
+ __ xorps(xmm2, xmm2);
+ __ addsd(xmm2, xmm1);
+ __ sqrtsd(xmm2, xmm2);
+ __ divsd(xmm3, xmm2);
+ __ jmp(&done);
+
+ // Test for 0.5.
+ __ bind(¬_minus_half);
+ // Load xmm2 with 0.5.
+ // Since xmm3 is 1 and xmm4 is -0.5 this is simply xmm4 + xmm3.
+ __ addsd(xmm4, xmm3);
+ // xmm2 now has 0.5.
+ __ ucomisd(xmm4, xmm2);
+ __ j(not_equal, &fast_power, Label::kNear);
+ // Calculates square root.
+ // sqrtsd returns -0 when input is -0. ECMA spec requires +0.
+ __ xorps(xmm4, xmm4);
+ __ addsd(xmm4, xmm1);
+ __ sqrtsd(xmm3, xmm4);
+ __ 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.
+ __ sub(esp, Immediate(kDoubleSize));
+ __ movdbl(Operand(esp, 0), xmm2);
+ __ fld_d(Operand(esp, 0)); // E
+ __ movdbl(Operand(esp, 0), xmm1);
+ __ fld_d(Operand(esp, 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();
+ __ test_b(eax, 0x5F); // We check for all but precision exception.
+ __ j(not_zero, &fast_power_failed, Label::kNear);
+ __ fstp_d(Operand(esp, 0));
+ __ movdbl(xmm3, Operand(esp, 0));
+ __ add(esp, Immediate(kDoubleSize));
+ __ jmp(&done);
- // Optimized version of pow if exponent is a smi.
- // xmm0 contains the base.
- __ bind(&powi);
- __ SmiUntag(eax);
+ __ bind(&fast_power_failed);
+ __ fninit();
+ __ add(esp, Immediate(kDoubleSize));
+ __ jmp(&generic_runtime);
+ }
+
+ // Calculate power with integer exponent.
+ __ bind(&int_exponent);
+ // xmm1: base as double that is not +/- Infinity or NaN
+ // eax: exponent as untagged integer
+ __ mov(ecx, eax); // Back up exponent.
+ __ movsd(xmm4, xmm1); // Back up base.
+ __ movsd(xmm2, xmm3); // Load xmm2 with 1.
- // Save exponent in base as we need to check if exponent is negative later.
- // We know that base and exponent are in different registers.
- __ mov(edx, eax);
// Get absolute value of exponent.
- Label no_neg;
+ Label no_neg, while_true, no_multiply;
__ cmp(eax, 0);
__ j(greater_equal, &no_neg, Label::kNear);
__ neg(eax);
__ bind(&no_neg);
- // Load xmm1 with 1.
- __ movsd(xmm1, xmm3);
- Label while_true;
- Label no_multiply;
-
__ bind(&while_true);
__ shr(eax, 1);
__ j(not_carry, &no_multiply, Label::kNear);
- __ mulsd(xmm1, xmm0);
+ __ mulsd(xmm3, xmm1);
__ bind(&no_multiply);
- __ mulsd(xmm0, xmm0);
+
+ __ mulsd(xmm1, xmm1);
__ j(not_zero, &while_true);
// base has the original value of the exponent - if the exponent is
// negative return 1/result.
- __ test(edx, edx);
- __ j(positive, &allocate_return);
- // Special case if xmm1 has reached infinity.
- __ mov(ecx, Immediate(0x7FB00000));
- __ movd(xmm0, ecx);
- __ cvtss2sd(xmm0, xmm0);
- __ ucomisd(xmm0, xmm1);
- __ j(equal, &call_runtime);
- __ divsd(xmm3, xmm1);
- __ movsd(xmm1, xmm3);
- __ jmp(&allocate_return);
-
- // exponent (or both) is a heapnumber - no matter what we should now work
- // on doubles.
- __ bind(&exponent_nonsmi);
- __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
- factory->heap_number_map());
- __ j(not_equal, &call_runtime);
- __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset));
- // Test if exponent is nan.
- __ ucomisd(xmm1, xmm1);
- __ j(parity_even, &call_runtime);
+ __ test(ecx, ecx);
+ __ j(positive, &done);
+ __ divsd(xmm2, xmm3);
+ __ movsd(xmm3, xmm2);
+ // 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.
+ __ xorps(xmm2, xmm2);
+ __ ucomisd(xmm2, xmm3);
+ __ j(equal, &double_int_runtime);
+
+ // 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);
+ // xmm3: result
+ __ AllocateHeapNumber(eax, ecx, edx, &generic_runtime);
+ __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm3);
+ __ ret(2 * kPointerSize);
- Label base_not_smi;
- Label handle_special_cases;
- __ JumpIfNotSmi(edx, &base_not_smi, Label::kNear);
- __ SmiUntag(edx);
- __ cvtsi2sd(xmm0, edx);
- __ jmp(&handle_special_cases, Label::kNear);
-
- __ bind(&base_not_smi);
- __ cmp(FieldOperand(edx, HeapObject::kMapOffset),
- factory->heap_number_map());
- __ j(not_equal, &call_runtime);
- __ mov(ecx, FieldOperand(edx, HeapNumber::kExponentOffset));
- __ and_(ecx, HeapNumber::kExponentMask);
- __ cmp(ecx, Immediate(HeapNumber::kExponentMask));
- // base is NaN or +/-Infinity
- __ j(greater_equal, &call_runtime);
- __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset));
+ // The arguments are still on the stack.
+ __ bind(&generic_runtime);
+ __ bind(&double_int_runtime);
+ __ TailCallRuntime(Runtime::kMath_pow_cfunction, 2, 1);
+ } else {
+ __ jmp(&done);
- // base is in xmm0 and exponent is in xmm1.
- __ bind(&handle_special_cases);
- Label not_minus_half;
- // Test for -0.5.
- // Load xmm2 with -0.5.
- __ mov(ecx, Immediate(0xBF000000));
- __ movd(xmm2, ecx);
- __ cvtss2sd(xmm2, xmm2);
- // xmm2 now has -0.5.
- __ ucomisd(xmm2, xmm1);
- __ j(not_equal, ¬_minus_half, Label::kNear);
-
- // Calculates reciprocal of square root.
- // sqrtsd returns -0 when input is -0. ECMA spec requires +0.
- __ xorps(xmm1, xmm1);
- __ addsd(xmm1, xmm0);
- __ sqrtsd(xmm1, xmm1);
- __ divsd(xmm3, xmm1);
- __ movsd(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);
- __ sqrtsd(xmm1, xmm1);
-
- __ bind(&allocate_return);
- __ AllocateHeapNumber(ecx, eax, edx, &call_runtime);
- __ movdbl(FieldOperand(ecx, HeapNumber::kValueOffset), xmm1);
- __ mov(eax, ecx);
- __ ret(2 * kPointerSize);
+ Label return_from_runtime;
+ StubRuntimeCallHelper callhelper;
+ __ bind(&generic_runtime);
+ // xmm1: base
+ // xmm2: exponent
+ {
+ AllowExternalCallThatCantCauseGC scope(masm);
+ __ PrepareCallCFunction(4, eax);
+ __ movdbl(Operand(esp, 0 * kDoubleSize), xmm1);
+ __ movdbl(Operand(esp, 1 * kDoubleSize), xmm2);
+ __ CallCFunction(
+ ExternalReference::power_double_double_function(masm->isolate()), 4);
+ }
+ __ jmp(&return_from_runtime, Label::kNear);
- __ bind(&call_runtime);
- __ TailCallRuntime(Runtime::kMath_pow_cfunction, 2, 1);
+ __ bind(&double_int_runtime);
+ // xmm4: base
+ // ecx: exponent
+ {
+ AllowExternalCallThatCantCauseGC scope(masm);
+ __ PrepareCallCFunction(4, eax);
+ __ movdbl(Operand(esp, 0 * kDoubleSize), xmm4);
+ __ mov(Operand(esp, 1 * kDoubleSize), ecx);
+ __ CallCFunction(
+ ExternalReference::power_double_int_function(masm->isolate()), 4);
+ }
+
+ __ bind(&return_from_runtime);
+ // Return value is in st(0) on ia32.
+ // Store it into the (fixed) result register.
+ __ sub(esp, Immediate(kDoubleSize));
+ __ fstp_d(Operand(esp, 0));
+ __ movdbl(xmm3, Operand(esp, 0));
+ __ add(esp, Immediate(kDoubleSize));
+
+ // xmm3: result
+ __ bind(&done);
+ __ ret(0);
+ }
}
case 0xEB: mnem = "fldpi"; break;
case 0xED: mnem = "fldln2"; break;
case 0xEE: mnem = "fldz"; break;
+ case 0xF0: mnem = "f2xm1"; break;
case 0xF1: mnem = "fyl2x"; break;
case 0xF5: mnem = "fprem1"; break;
case 0xF7: mnem = "fincstp"; break;
case 0xF8: mnem = "fprem"; break;
+ case 0xFC: mnem = "frndint"; break;
+ case 0xFD: mnem = "fscale"; break;
case 0xFE: mnem = "fsin"; break;
case 0xFF: mnem = "fcos"; break;
default: UnimplementedInstruction();
has_register = true;
} else if (modrm_byte == 0xE2) {
mnem = "fclex";
+ } else if (modrm_byte == 0xE3) {
+ mnem = "fninit";
} else {
UnimplementedInstruction();
}
NameOfXMMRegister(rm),
static_cast<int>(imm8));
data += 2;
+ } else if (*data == 0x17){
+ data++;
+ int mod, regop, rm;
+ get_modrm(*data, &mod, ®op, &rm);
+ int8_t imm8 = static_cast<int8_t>(data[1]);
+ AppendToBuffer("extractps %s,%s,%d",
+ NameOfCPURegister(regop),
+ NameOfXMMRegister(rm),
+ static_cast<int>(imm8));
+ data += 2;
} else if (*data == 0x22) {
data++;
int mod, regop, rm;
VisitForStackValue(args->at(1));
if (CpuFeatures::IsSupported(SSE2)) {
- MathPowStub stub;
+ MathPowStub stub(MathPowStub::ON_STACK);
__ CallStub(&stub);
} else {
__ CallRuntime(Runtime::kMath_pow, 2);
void LCodeGen::DoPower(LPower* instr) {
- LOperand* left = instr->InputAt(0);
- LOperand* right = instr->InputAt(1);
- DoubleRegister result_reg = ToDoubleRegister(instr->result());
Representation exponent_type = instr->hydrogen()->right()->representation();
-
- if (exponent_type.IsDouble()) {
- // It is safe to use ebx directly since the instruction is marked
- // as a call.
- __ PrepareCallCFunction(4, ebx);
- __ movdbl(Operand(esp, 0 * kDoubleSize), ToDoubleRegister(left));
- __ movdbl(Operand(esp, 1 * kDoubleSize), ToDoubleRegister(right));
- __ CallCFunction(ExternalReference::power_double_double_function(isolate()),
- 4);
+ // Having marked this as a call, we can use any registers.
+ // Just make sure that the input registers are the expected ones.
+ ASSERT(!instr->InputAt(1)->IsDoubleRegister() ||
+ ToDoubleRegister(instr->InputAt(1)).is(xmm2));
+ ASSERT(!instr->InputAt(1)->IsRegister() ||
+ ToRegister(instr->InputAt(1)).is(eax));
+ ASSERT(ToDoubleRegister(instr->InputAt(0)).is(xmm1));
+ ASSERT(ToDoubleRegister(instr->result()).is(xmm3));
+
+ if (exponent_type.IsTagged()) {
+ Label no_deopt;
+ __ JumpIfSmi(eax, &no_deopt);
+ __ CmpObjectType(eax, HEAP_NUMBER_TYPE, ecx);
+ DeoptimizeIf(not_equal, instr->environment());
+ __ bind(&no_deopt);
+ MathPowStub stub(MathPowStub::TAGGED);
+ __ CallStub(&stub);
} else if (exponent_type.IsInteger32()) {
- // It is safe to use ebx directly since the instruction is marked
- // as a call.
- ASSERT(!ToRegister(right).is(ebx));
- __ PrepareCallCFunction(4, ebx);
- __ movdbl(Operand(esp, 0 * kDoubleSize), ToDoubleRegister(left));
- __ mov(Operand(esp, 1 * kDoubleSize), ToRegister(right));
- __ CallCFunction(ExternalReference::power_double_int_function(isolate()),
- 4);
+ MathPowStub stub(MathPowStub::INTEGER);
+ __ CallStub(&stub);
} else {
- ASSERT(exponent_type.IsTagged());
- CpuFeatures::Scope scope(SSE2);
- Register right_reg = ToRegister(right);
-
- Label non_smi, call;
- __ JumpIfNotSmi(right_reg, &non_smi);
- __ SmiUntag(right_reg);
- __ cvtsi2sd(result_reg, Operand(right_reg));
- __ jmp(&call);
-
- __ bind(&non_smi);
- // It is safe to use ebx directly since the instruction is marked
- // as a call.
- ASSERT(!right_reg.is(ebx));
- __ CmpObjectType(right_reg, HEAP_NUMBER_TYPE , ebx);
- DeoptimizeIf(not_equal, instr->environment());
- __ movdbl(result_reg, FieldOperand(right_reg, HeapNumber::kValueOffset));
-
- __ bind(&call);
- __ PrepareCallCFunction(4, ebx);
- __ movdbl(Operand(esp, 0 * kDoubleSize), ToDoubleRegister(left));
- __ movdbl(Operand(esp, 1 * kDoubleSize), result_reg);
- __ CallCFunction(ExternalReference::power_double_double_function(isolate()),
- 4);
+ ASSERT(exponent_type.IsDouble());
+ MathPowStub stub(MathPowStub::DOUBLE);
+ __ CallStub(&stub);
}
-
- // Return value is in st(0) on ia32.
- // Store it into the (fixed) result register.
- __ sub(Operand(esp), Immediate(kDoubleSize));
- __ fstp_d(Operand(esp, 0));
- __ movdbl(result_reg, Operand(esp, 0));
- __ add(Operand(esp), Immediate(kDoubleSize));
}
ASSERT(args->length() == 2);
VisitForStackValue(args->at(0));
VisitForStackValue(args->at(1));
- MathPowStub stub;
+ MathPowStub stub(MathPowStub::ON_STACK);
__ CallStub(&stub);
context()->Plug(v0);
}
void Assembler::extractps(Register dst, XMMRegister src, byte imm8) {
- ASSERT(is_uint2(imm8));
+ ASSERT(CpuFeatures::IsSupported(SSE4_1));
+ ASSERT(is_uint8(imm8));
EnsureSpace ensure_space(this);
emit(0x66);
emit_optional_rex_32(dst, src);
ASSERT(args->length() == 2);
VisitForStackValue(args->at(0));
VisitForStackValue(args->at(1));
- MathPowStub stub;
+ MathPowStub stub(MathPowStub::ON_STACK);
__ CallStub(&stub);
context()->Plug(rax);
}
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+// Flags: --allow-natives-syntax
// Tests the special cases specified by ES 15.8.2.13
-// Simple sanity check
-assertEquals(4, Math.pow(2, 2));
-assertEquals(2147483648, Math.pow(2, 31));
-assertEquals(0.25, Math.pow(2, -2));
-assertEquals(0.0625, Math.pow(2, -4));
-assertEquals(1, Math.pow(1, 100));
-assertEquals(0, Math.pow(0, 1000));
-
-// Spec tests
-assertEquals(NaN, Math.pow(2, NaN));
-assertEquals(NaN, Math.pow(+0, NaN));
-assertEquals(NaN, Math.pow(-0, NaN));
-assertEquals(NaN, Math.pow(Infinity, NaN));
-assertEquals(NaN, Math.pow(-Infinity, NaN));
-
-assertEquals(1, Math.pow(NaN, +0));
-assertEquals(1, Math.pow(NaN, -0));
-
-assertEquals(NaN, Math.pow(NaN, NaN));
-assertEquals(NaN, Math.pow(NaN, 2.2));
-assertEquals(NaN, Math.pow(NaN, 1));
-assertEquals(NaN, Math.pow(NaN, -1));
-assertEquals(NaN, Math.pow(NaN, -2.2));
-assertEquals(NaN, Math.pow(NaN, Infinity));
-assertEquals(NaN, Math.pow(NaN, -Infinity));
-
-assertEquals(Infinity, Math.pow(1.1, Infinity));
-assertEquals(Infinity, Math.pow(-1.1, Infinity));
-assertEquals(Infinity, Math.pow(2, Infinity));
-assertEquals(Infinity, Math.pow(-2, Infinity));
-
-// Because +0 == -0, we need to compare 1/{+,-}0 to {+,-}Infinity
-assertEquals(+Infinity, 1/Math.pow(1.1, -Infinity));
-assertEquals(+Infinity, 1/Math.pow(-1.1, -Infinity));
-assertEquals(+Infinity, 1/Math.pow(2, -Infinity));
-assertEquals(+Infinity, 1/Math.pow(-2, -Infinity));
-
-assertEquals(NaN, Math.pow(1, Infinity));
-assertEquals(NaN, Math.pow(1, -Infinity));
-assertEquals(NaN, Math.pow(-1, Infinity));
-assertEquals(NaN, Math.pow(-1, -Infinity));
-
-assertEquals(+0, Math.pow(0.1, Infinity));
-assertEquals(+0, Math.pow(-0.1, Infinity));
-assertEquals(+0, Math.pow(0.999, Infinity));
-assertEquals(+0, Math.pow(-0.999, Infinity));
-
-assertEquals(Infinity, Math.pow(0.1, -Infinity));
-assertEquals(Infinity, Math.pow(-0.1, -Infinity));
-assertEquals(Infinity, Math.pow(0.999, -Infinity));
-assertEquals(Infinity, Math.pow(-0.999, -Infinity));
-
-assertEquals(Infinity, Math.pow(Infinity, 0.1));
-assertEquals(Infinity, Math.pow(Infinity, 2));
-
-assertEquals(+Infinity, 1/Math.pow(Infinity, -0.1));
-assertEquals(+Infinity, 1/Math.pow(Infinity, -2));
-
-assertEquals(-Infinity, Math.pow(-Infinity, 3));
-assertEquals(-Infinity, Math.pow(-Infinity, 13));
-
-assertEquals(Infinity, Math.pow(-Infinity, 3.1));
-assertEquals(Infinity, Math.pow(-Infinity, 2));
-
-assertEquals(-Infinity, 1/Math.pow(-Infinity, -3));
-assertEquals(-Infinity, 1/Math.pow(-Infinity, -13));
-
-assertEquals(+Infinity, 1/Math.pow(-Infinity, -3.1));
-assertEquals(+Infinity, 1/Math.pow(-Infinity, -2));
-
-assertEquals(+Infinity, 1/Math.pow(+0, 1.1));
-assertEquals(+Infinity, 1/Math.pow(+0, 2));
-
-assertEquals(Infinity, Math.pow(+0, -1.1));
-assertEquals(Infinity, Math.pow(+0, -2));
-
-assertEquals(-Infinity, 1/Math.pow(-0, 3));
-assertEquals(-Infinity, 1/Math.pow(-0, 13));
-
-assertEquals(+Infinity, 1/Math.pow(-0, 3.1));
-assertEquals(+Infinity, 1/Math.pow(-0, 2));
-
-assertEquals(-Infinity, Math.pow(-0, -3));
-assertEquals(-Infinity, Math.pow(-0, -13));
-
-assertEquals(Infinity, Math.pow(-0, -3.1));
-assertEquals(Infinity, Math.pow(-0, -2));
-
-assertEquals(NaN, Math.pow(-0.00001, 1.1));
-assertEquals(NaN, Math.pow(-0.00001, -1.1));
-assertEquals(NaN, Math.pow(-1.1, 1.1));
-assertEquals(NaN, Math.pow(-1.1, -1.1));
-assertEquals(NaN, Math.pow(-2, 1.1));
-assertEquals(NaN, Math.pow(-2, -1.1));
-assertEquals(NaN, Math.pow(-1000, 1.1));
-assertEquals(NaN, Math.pow(-1000, -1.1));
-
-assertEquals(+Infinity, 1/Math.pow(-0, 0.5));
-assertEquals(+Infinity, 1/Math.pow(-0, 0.6));
-assertEquals(-Infinity, 1/Math.pow(-0, 1));
-assertEquals(-Infinity, 1/Math.pow(-0, 10000000001));
-
-assertEquals(+Infinity, Math.pow(-0, -0.5));
-assertEquals(+Infinity, Math.pow(-0, -0.6));
-assertEquals(-Infinity, Math.pow(-0, -1));
-assertEquals(-Infinity, Math.pow(-0, -10000000001));
-
-
-
-// Tests from Sputnik S8.5_A13_T1.
-assertTrue((1*((Math.pow(2,53))-1)*(Math.pow(2,-1074))) === 4.4501477170144023e-308);
-assertTrue((1*(Math.pow(2,52))*(Math.pow(2,-1074))) === 2.2250738585072014e-308);
-assertTrue((-1*(Math.pow(2,52))*(Math.pow(2,-1074))) === -2.2250738585072014e-308);
+function test() {
+ // Simple sanity check
+ assertEquals(4, Math.pow(2, 2));
+ assertEquals(2147483648, Math.pow(2, 31));
+ assertEquals(0.25, Math.pow(2, -2));
+ assertEquals(0.0625, Math.pow(2, -4));
+ assertEquals(1, Math.pow(1, 100));
+ assertEquals(0, Math.pow(0, 1000));
+
+ // Spec tests
+ assertEquals(NaN, Math.pow(2, NaN));
+ assertEquals(NaN, Math.pow(+0, NaN));
+ assertEquals(NaN, Math.pow(-0, NaN));
+ assertEquals(NaN, Math.pow(Infinity, NaN));
+ assertEquals(NaN, Math.pow(-Infinity, NaN));
+
+ assertEquals(1, Math.pow(NaN, +0));
+ assertEquals(1, Math.pow(NaN, -0));
+
+ assertEquals(NaN, Math.pow(NaN, NaN));
+ assertEquals(NaN, Math.pow(NaN, 2.2));
+ assertEquals(NaN, Math.pow(NaN, 1));
+ assertEquals(NaN, Math.pow(NaN, -1));
+ assertEquals(NaN, Math.pow(NaN, -2.2));
+ assertEquals(NaN, Math.pow(NaN, Infinity));
+ assertEquals(NaN, Math.pow(NaN, -Infinity));
+
+ assertEquals(Infinity, Math.pow(1.1, Infinity));
+ assertEquals(Infinity, Math.pow(-1.1, Infinity));
+ assertEquals(Infinity, Math.pow(2, Infinity));
+ assertEquals(Infinity, Math.pow(-2, Infinity));
+
+ // Because +0 == -0, we need to compare 1/{+,-}0 to {+,-}Infinity
+ assertEquals(+Infinity, 1/Math.pow(1.1, -Infinity));
+ assertEquals(+Infinity, 1/Math.pow(-1.1, -Infinity));
+ assertEquals(+Infinity, 1/Math.pow(2, -Infinity));
+ assertEquals(+Infinity, 1/Math.pow(-2, -Infinity));
+
+ assertEquals(NaN, Math.pow(1, Infinity));
+ assertEquals(NaN, Math.pow(1, -Infinity));
+ assertEquals(NaN, Math.pow(-1, Infinity));
+ assertEquals(NaN, Math.pow(-1, -Infinity));
+
+ assertEquals(+0, Math.pow(0.1, Infinity));
+ assertEquals(+0, Math.pow(-0.1, Infinity));
+ assertEquals(+0, Math.pow(0.999, Infinity));
+ assertEquals(+0, Math.pow(-0.999, Infinity));
+
+ assertEquals(Infinity, Math.pow(0.1, -Infinity));
+ assertEquals(Infinity, Math.pow(-0.1, -Infinity));
+ assertEquals(Infinity, Math.pow(0.999, -Infinity));
+ assertEquals(Infinity, Math.pow(-0.999, -Infinity));
+
+ assertEquals(Infinity, Math.pow(Infinity, 0.1));
+ assertEquals(Infinity, Math.pow(Infinity, 2));
+
+ assertEquals(+Infinity, 1/Math.pow(Infinity, -0.1));
+ assertEquals(+Infinity, 1/Math.pow(Infinity, -2));
+
+ assertEquals(-Infinity, Math.pow(-Infinity, 3));
+ assertEquals(-Infinity, Math.pow(-Infinity, 13));
+
+ assertEquals(Infinity, Math.pow(-Infinity, 3.1));
+ assertEquals(Infinity, Math.pow(-Infinity, 2));
+
+ assertEquals(-Infinity, 1/Math.pow(-Infinity, -3));
+ assertEquals(-Infinity, 1/Math.pow(-Infinity, -13));
+
+ assertEquals(+Infinity, 1/Math.pow(-Infinity, -3.1));
+ assertEquals(+Infinity, 1/Math.pow(-Infinity, -2));
+
+ assertEquals(+Infinity, 1/Math.pow(+0, 1.1));
+ assertEquals(+Infinity, 1/Math.pow(+0, 2));
+
+ assertEquals(Infinity, Math.pow(+0, -1.1));
+ assertEquals(Infinity, Math.pow(+0, -2));
+
+ assertEquals(-Infinity, 1/Math.pow(-0, 3));
+ assertEquals(-Infinity, 1/Math.pow(-0, 13));
+
+ assertEquals(+Infinity, 1/Math.pow(-0, 3.1));
+ assertEquals(+Infinity, 1/Math.pow(-0, 2));
+
+ assertEquals(-Infinity, Math.pow(-0, -3));
+ assertEquals(-Infinity, Math.pow(-0, -13));
+
+ assertEquals(Infinity, Math.pow(-0, -3.1));
+ assertEquals(Infinity, Math.pow(-0, -2));
+
+ assertEquals(NaN, Math.pow(-0.00001, 1.1));
+ assertEquals(NaN, Math.pow(-0.00001, -1.1));
+ assertEquals(NaN, Math.pow(-1.1, 1.1));
+ assertEquals(NaN, Math.pow(-1.1, -1.1));
+ assertEquals(NaN, Math.pow(-2, 1.1));
+ assertEquals(NaN, Math.pow(-2, -1.1));
+ assertEquals(NaN, Math.pow(-1000, 1.1));
+ assertEquals(NaN, Math.pow(-1000, -1.1));
+
+ assertEquals(+Infinity, 1/Math.pow(-0, 0.5));
+ assertEquals(+Infinity, 1/Math.pow(-0, 0.6));
+ assertEquals(-Infinity, 1/Math.pow(-0, 1));
+ assertEquals(-Infinity, 1/Math.pow(-0, 10000000001));
+
+ assertEquals(+Infinity, Math.pow(-0, -0.5));
+ assertEquals(+Infinity, Math.pow(-0, -0.6));
+ assertEquals(-Infinity, Math.pow(-0, -1));
+ assertEquals(-Infinity, Math.pow(-0, -10000000001));
+
+ // Tests from Sputnik S8.5_A13_T1.
+ assertTrue(
+ (1*((Math.pow(2,53))-1)*(Math.pow(2,-1074))) === 4.4501477170144023e-308);
+ assertTrue(
+ (1*(Math.pow(2,52))*(Math.pow(2,-1074))) === 2.2250738585072014e-308);
+ assertTrue(
+ (-1*(Math.pow(2,52))*(Math.pow(2,-1074))) === -2.2250738585072014e-308);
+}
+
+test();
+test();
+%OptimizeFunctionOnNextCall(test);
+test();
\ No newline at end of file