Implement Math.pow using FPU instructions and inline it in crankshaft (ia32).
authoryangguo@chromium.org <yangguo@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 2 Dec 2011 08:06:37 +0000 (08:06 +0000)
committeryangguo@chromium.org <yangguo@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 2 Dec 2011 08:06:37 +0000 (08:06 +0000)
Review URL: http://codereview.chromium.org/8749002

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@10133 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

13 files changed:
src/arm/full-codegen-arm.cc
src/assembler.cc
src/code-stubs.h
src/ia32/assembler-ia32.cc
src/ia32/assembler-ia32.h
src/ia32/code-stubs-ia32.cc
src/ia32/disasm-ia32.cc
src/ia32/full-codegen-ia32.cc
src/ia32/lithium-codegen-ia32.cc
src/mips/full-codegen-mips.cc
src/x64/assembler-x64.cc
src/x64/full-codegen-x64.cc
test/mjsunit/math-pow.js

index fdd326618f263cbd8828887ffbf1285b351d230e..17289e8f0ac54c9b166f04b4abefbf4eae3f22ae 100644 (file)
@@ -2938,7 +2938,7 @@ void FullCodeGenerator::EmitMathPow(CallRuntime* expr) {
   ASSERT(args->length() == 2);
   VisitForStackValue(args->at(0));
   VisitForStackValue(args->at(1));
-  MathPowStub stub;
+  MathPowStub stub(MathPowStub::ON_STACK);
   __ CallStub(&stub);
   context()->Plug(r0);
 }
index bc05c01800dc51889ee58e31264d533045be84ff..e1cf13ff71a6a53604c0137d50784859f12e1c30 100644 (file)
@@ -1113,6 +1113,9 @@ double power_double_int(double x, int y) {
 
 
 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.
@@ -1121,6 +1124,7 @@ double power_double_double(double x, double y) {
     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();
   }
index 6bda5da709e8de9e1c4b0edfea73ebc63a83fe59..dc07e5d67d8775e14a37e2381015c55e2e5ff884 100644 (file)
@@ -442,12 +442,17 @@ class InstanceofStub: public CodeStub {
 
 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_;
 };
 
 
index fb625fb24d7248762dff832f177110f9d2c4d57b..72e2bf8f261ed4d69b79f9159c6d6fe3de79be21 100644 (file)
@@ -1640,6 +1640,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) {
   EnsureSpace ensure_space(this);
   emit_farith(0xDC, 0xC0, i);
@@ -2158,6 +2179,19 @@ void Assembler::movd(const Operand& dst, XMMRegister src) {
 }
 
 
+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);
index d798f818ada454741fd2ba4fc69cca345500adbe..7195895f34c5d88912fafeaf518b72dfcc041b74 100644 (file)
@@ -926,6 +926,9 @@ class Assembler : public AssemblerBase {
   void fsin();
   void fptan();
   void fyl2x();
+  void f2xm1();
+  void fscale();
+  void fninit();
 
   void fadd(int i);
   void fsub(int i);
@@ -1017,6 +1020,7 @@ class Assembler : public AssemblerBase {
   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);
index 68eebd3a040f239d2ba721117aed017a6b734e0b..855720c80a48bd2030938205253906182048252f 100644 (file)
@@ -2938,157 +2938,264 @@ void FloatingPointHelper::CheckFloatOperandsAreInt32(MacroAssembler* masm,
 
 
 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, &not_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(&not_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, &not_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(&not_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);
+  }
 }
 
 
index da223901193f77234ad7be857477b0a36cc2e8a8..643789f4c7f6c0bf4cf408293b47014e3436cdca 100644 (file)
@@ -763,10 +763,13 @@ int DisassemblerIA32::RegisterFPUInstruction(int escape_opcode,
             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();
@@ -788,6 +791,8 @@ int DisassemblerIA32::RegisterFPUInstruction(int escape_opcode,
         has_register = true;
       } else if (modrm_byte  == 0xE2) {
         mnem = "fclex";
+      } else if (modrm_byte == 0xE3) {
+        mnem = "fninit";
       } else {
         UnimplementedInstruction();
       }
@@ -1185,6 +1190,16 @@ int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
                              NameOfXMMRegister(rm),
                              static_cast<int>(imm8));
               data += 2;
+            } else if (*data == 0x17){
+              data++;
+              int mod, regop, rm;
+              get_modrm(*data, &mod, &regop, &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;
index ef4f0c5f2b662e0f7a5a86a1213043202b01db13..919cca23e047b1ec535f08d367a057f89f9dc277 100644 (file)
@@ -2883,7 +2883,7 @@ void FullCodeGenerator::EmitMathPow(CallRuntime* expr) {
   VisitForStackValue(args->at(1));
 
   if (CpuFeatures::IsSupported(SSE2)) {
-    MathPowStub stub;
+    MathPowStub stub(MathPowStub::ON_STACK);
     __ CallStub(&stub);
   } else {
     __ CallRuntime(Runtime::kMath_pow, 2);
index d5ef4d95a10f973c5b48faf88c3614c0100283de..236991633cc71738f9213da7474e53333ab604b3 100644 (file)
@@ -2945,61 +2945,32 @@ void LCodeGen::DoMathPowHalf(LUnaryMathOperation* instr) {
 
 
 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));
 }
 
 
index f5b851ddb91bc593b098bff2128ee7062561e2d1..0798d48f445d780ab5b31593429d669b8208145b 100644 (file)
@@ -2958,7 +2958,7 @@ void FullCodeGenerator::EmitMathPow(CallRuntime* expr) {
   ASSERT(args->length() == 2);
   VisitForStackValue(args->at(0));
   VisitForStackValue(args->at(1));
-  MathPowStub stub;
+  MathPowStub stub(MathPowStub::ON_STACK);
   __ CallStub(&stub);
   context()->Plug(v0);
 }
index d578bf9c57b7fd7e84927b1f760f0f5f41a49e6c..26b449c524690ee69b4a71a227b7790f8a0faa06 100644 (file)
@@ -2572,7 +2572,8 @@ void Assembler::movdqa(XMMRegister dst, const Operand& src) {
 
 
 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);
index 963912f66a9a74dc73ad74b8af32efabf514cccb..24df20ba767bd76df3fe06cbae9109d56afe6512 100644 (file)
@@ -2820,7 +2820,7 @@ void FullCodeGenerator::EmitMathPow(CallRuntime* expr) {
   ASSERT(args->length() == 2);
   VisitForStackValue(args->at(0));
   VisitForStackValue(args->at(1));
-  MathPowStub stub;
+  MathPowStub stub(MathPowStub::ON_STACK);
   __ CallStub(&stub);
   context()->Plug(rax);
 }
index 30d0cbdced45cd101096bea891260229da4fc4d3..abc99bebcd98a9937ab24751b0eb60a08b52c5ad 100644 (file)
 // (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