Added fast support for Math.pow. This simply calculates the result using the
authorricow@chromium.org <ricow@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 26 Feb 2010 10:24:58 +0000 (10:24 +0000)
committerricow@chromium.org <ricow@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 26 Feb 2010 10:24:58 +0000 (10:24 +0000)
same method as the old powi version in runtime.cc and also checks if
the exponent is 0.5 or -0.5 in which case we calculate the square root or
reciprocal value of the square root.

Review URL: http://codereview.chromium.org/660072

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

14 files changed:
src/arm/codegen-arm.cc
src/arm/codegen-arm.h
src/codegen.cc
src/ia32/assembler-ia32.cc
src/ia32/assembler-ia32.h
src/ia32/codegen-ia32.cc
src/ia32/codegen-ia32.h
src/math.js
src/mips/codegen-mips.cc
src/mips/codegen-mips.h
src/runtime.cc
src/runtime.h
src/x64/codegen-x64.cc
src/x64/codegen-x64.h

index df1db69765f17a29531bebba7c2bb182310f7585..6126898bbee446cd3dc47ba2fbfb953a65351a5a 100644 (file)
@@ -3322,6 +3322,15 @@ void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) {
 }
 
 
+// Generates the Math.pow method - currently just calls runtime.
+void CodeGenerator::GeneratePow(ZoneList<Expression*>* args) {
+  ASSERT(args->length() == 2);
+  Load(args->at(0));
+  Load(args->at(1));
+  frame_->CallRuntime(Runtime::kMath_pow, 2);
+  frame_->EmitPush(r0);
+}
+
 // This should generate code that performs a charCodeAt() call or returns
 // undefined in order to trigger the slow case, Runtime_StringCharCodeAt.
 // It is not yet implemented on ARM, so it always goes to the slow case.
index 9bbf37b23ebdebf383c8e02751d59104fdd5380a..5ddd45e196d4491f1f868c2835447b3626d51afc 100644 (file)
@@ -393,6 +393,9 @@ class CodeGenerator: public AstVisitor {
   // Fast support for number to string.
   void GenerateNumberToString(ZoneList<Expression*>* args);
 
+  // Fast support for Math.pow().
+  void GeneratePow(ZoneList<Expression*>* args);
+
   // Fast call to sine function.
   void GenerateMathSin(ZoneList<Expression*>* args);
   void GenerateMathCos(ZoneList<Expression*>* args);
index e56de7a02b84c82e4f0f1feca52a4d621dcab544..dc9f517158dd9d69e0ce1e6784b1b41e4f344a8a 100644 (file)
@@ -380,6 +380,7 @@ CodeGenerator::InlineRuntimeLUT CodeGenerator::kInlineRuntimeLUT[] = {
   {&CodeGenerator::GenerateStringCompare, "_StringCompare"},
   {&CodeGenerator::GenerateRegExpExec, "_RegExpExec"},
   {&CodeGenerator::GenerateNumberToString, "_NumberToString"},
+  {&CodeGenerator::GeneratePow, "_Pow"},
   {&CodeGenerator::GenerateMathSin, "_Math_sin"},
   {&CodeGenerator::GenerateMathCos, "_Math_cos"},
 };
index 89708aae5918b4109bcdcf66d1089a29af92d299..1365ac2be3c1d98bd044c4daee9f9fe9cc536398 100644 (file)
@@ -2035,6 +2035,17 @@ void Assembler::cvtsi2sd(XMMRegister dst, const Operand& src) {
 }
 
 
+void Assembler::cvtss2sd(XMMRegister dst, XMMRegister src) {
+  ASSERT(CpuFeatures::IsEnabled(SSE2));
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0xF3);
+  EMIT(0x0F);
+  EMIT(0x5A);
+  emit_sse_operand(dst, src);
+}
+
+
 void Assembler::addsd(XMMRegister dst, XMMRegister src) {
   ASSERT(CpuFeatures::IsEnabled(SSE2));
   EnsureSpace ensure_space(this);
@@ -2090,6 +2101,16 @@ void Assembler::xorpd(XMMRegister dst, XMMRegister src) {
 }
 
 
+void Assembler::sqrtsd(XMMRegister dst, XMMRegister src) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0xF2);
+  EMIT(0x0F);
+  EMIT(0x51);
+  emit_sse_operand(dst, src);
+}
+
+
 void Assembler::comisd(XMMRegister dst, XMMRegister src) {
   ASSERT(CpuFeatures::IsEnabled(SSE2));
   EnsureSpace ensure_space(this);
@@ -2101,6 +2122,17 @@ void Assembler::comisd(XMMRegister dst, XMMRegister src) {
 }
 
 
+void Assembler::ucomisd(XMMRegister dst, XMMRegister src) {
+  ASSERT(CpuFeatures::IsEnabled(SSE2));
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0x66);
+  EMIT(0x0F);
+  EMIT(0x2E);
+  emit_sse_operand(dst, src);
+}
+
+
 void Assembler::movdqa(const Operand& dst, XMMRegister src ) {
   ASSERT(CpuFeatures::IsEnabled(SSE2));
   EnsureSpace ensure_space(this);
@@ -2180,6 +2212,50 @@ void Assembler::movsd(XMMRegister dst, const Operand& src) {
   emit_sse_operand(dst, src);
 }
 
+void Assembler::movsd(XMMRegister dst, XMMRegister src) {
+  ASSERT(CpuFeatures::IsEnabled(SSE2));
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0xF2);
+  EMIT(0x0F);
+  EMIT(0x10);
+  emit_sse_operand(dst, src);
+}
+
+
+void Assembler::movd(XMMRegister dst, const Operand& src) {
+  ASSERT(CpuFeatures::IsEnabled(SSE2));
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0x66);
+  EMIT(0x0F);
+  EMIT(0x6E);
+  emit_sse_operand(dst, src);
+}
+
+
+void Assembler::pxor(XMMRegister dst, XMMRegister src) {
+  ASSERT(CpuFeatures::IsEnabled(SSE2));
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0x66);
+  EMIT(0x0F);
+  EMIT(0xEF);
+  emit_sse_operand(dst, src);
+}
+
+
+void Assembler::ptest(XMMRegister dst, XMMRegister src) {
+  ASSERT(CpuFeatures::IsEnabled(SSE2));
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0x66);
+  EMIT(0x0F);
+  EMIT(0x38);
+  EMIT(0x17);
+  emit_sse_operand(dst, src);
+}
+
 
 void Assembler::emit_sse_operand(XMMRegister reg, const Operand& adr) {
   Register ireg = { reg.code() };
index 36aad5e533c84bf1056cd05149ba4cf7ce8800c6..ce07dd790fb125f383905352a1eb18d6accaf573 100644 (file)
@@ -93,7 +93,7 @@ const Register no_reg = { -1 };
 
 
 struct XMMRegister {
-  bool is_valid() const  { return 0 <= code_ && code_ < 2; }  // currently
+  bool is_valid() const  { return 0 <= code_ && code_ < 8; }
   int code() const  {
     ASSERT(is_valid());
     return code_;
@@ -754,14 +754,17 @@ class Assembler : public Malloced {
   void cvttsd2si(Register dst, const Operand& src);
 
   void cvtsi2sd(XMMRegister dst, const Operand& src);
+  void cvtss2sd(XMMRegister dst, XMMRegister src);
 
   void addsd(XMMRegister dst, XMMRegister src);
   void subsd(XMMRegister dst, XMMRegister src);
   void mulsd(XMMRegister dst, XMMRegister src);
   void divsd(XMMRegister dst, XMMRegister src);
   void xorpd(XMMRegister dst, XMMRegister src);
+  void sqrtsd(XMMRegister dst, XMMRegister src);
 
   void comisd(XMMRegister dst, XMMRegister src);
+  void ucomisd(XMMRegister dst, XMMRegister src);
 
   void movdqa(XMMRegister dst, const Operand& src);
   void movdqa(const Operand& dst, XMMRegister src);
@@ -772,6 +775,12 @@ class Assembler : public Malloced {
   void movdbl(XMMRegister dst, const Operand& src);
   void movdbl(const Operand& dst, XMMRegister src);
 
+  void movd(XMMRegister dst, const Operand& src);
+  void movsd(XMMRegister dst, XMMRegister src);
+
+  void pxor(XMMRegister dst, XMMRegister src);
+  void ptest(XMMRegister dst, XMMRegister src);
+
   // Debugging
   void Print();
 
index ec17f289697fd3fbc53e5599667d87e2b0c37b09..f869fec4fe57c5abe3023a6e6cd64de9bafc74e5 100644 (file)
@@ -5275,6 +5275,181 @@ void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) {
 }
 
 
+// Generates the Math.pow method - only handles special cases and branches to
+// the runtime system if not. Uses eax to store result and as temporary reg.
+void CodeGenerator::GeneratePow(ZoneList<Expression*>* args) {
+  ASSERT(args->length() == 2);
+  if (CpuFeatures::IsSupported(SSE2)) {
+    CpuFeatures::Scope use_sse2(SSE2);
+    Load(args->at(0));
+    Load(args->at(1));
+    Label go_runtime;
+    Label return_preg;
+    Result p = allocator()->Allocate(eax);
+    Result y = frame_->Pop();
+    Result x= frame_->Pop();
+    if (p.is_valid() && p.reg().is(eax)) {
+      x.ToRegister();
+      y.ToRegister();
+      frame_->Spill(x.reg());
+      frame_->Spill(y.reg());
+      ASSERT(x.is_valid());
+      ASSERT(y.is_valid());
+
+      Label y_nonsmi;
+      Label x_is_double;
+      // If y is a heap number go to that specific case.
+      __ test(y.reg(), Immediate(kSmiTagMask));
+      __ j(not_zero, &y_nonsmi);
+      __ test(x.reg(), Immediate(kSmiTagMask));
+      __ j(not_zero, &x_is_double);
+
+      // Bot numbers are smis.
+      Label powi;
+      __ SmiUntag(x.reg());
+      __ cvtsi2sd(xmm0, Operand(x.reg()));
+      __ jmp(&powi);
+      // Y is smi and x is a double.
+      __ bind(&x_is_double);
+      __ cmp(FieldOperand(x.reg(), HeapObject::kMapOffset),
+             Factory::heap_number_map());
+      __ j(not_equal, &go_runtime);
+      __ movdbl(xmm0, FieldOperand(x.reg(), HeapNumber::kValueOffset));
+
+      __ bind(&powi);
+      __ SmiUntag(y.reg());
+
+      // Save y in x as we need to check if y is negative later.
+      __ mov(x.reg(), y.reg());
+      // Save 1 in xmm3 - we need this several times later on
+      __ mov(p.reg(), Immediate(1));
+      __ cvtsi2sd(xmm3, Operand(p.reg()));
+
+      // Get absolute value of y.
+      Label no_neg;
+      __ cmp(y.reg(), 0);
+      __ j(greater_equal, &no_neg);
+      __ neg(y.reg());
+      __ bind(&no_neg);
+
+      // Optimized version of pow if y is an integer.
+      // Load xmm1 with 1.
+      __ movsd(xmm1, xmm3);
+      Label while_true;
+      Label no_multiply;
+      Label powi_done;
+      Label allocate_and_return;
+      __ bind(&while_true);
+      __ shr(y.reg(), 1);
+      __ j(not_carry, &no_multiply);
+      __ mulsd(xmm1, xmm0);
+      __ bind(&no_multiply);
+      __ test(y.reg(), Operand(y.reg()));
+      __ mulsd(xmm0, xmm0);
+      __ j(not_zero, &while_true);
+
+      __ bind(&powi_done);
+      // x has the original value of y - if y is negative return 1/result.
+      __ test(x.reg(), Operand(x.reg()));
+      __ j(positive, &allocate_and_return);
+      // Special case if xmm1 has reached infinity
+      __ mov(p.reg(), Immediate(0x7FB00000));
+      __ movd(xmm0, Operand(p.reg()));
+      __ cvtss2sd(xmm0, xmm0);
+      __ ucomisd(xmm0, xmm1);
+      __ j(equal, &go_runtime);
+      __ divsd(xmm3, xmm1);
+      __ movsd(xmm1, xmm3);
+      __ jmp(&allocate_and_return);
+
+      // y (or both) is a double - no matter what we should now work
+      // on doubles.
+      __ bind(&y_nonsmi);
+      __ cmp(FieldOperand(y.reg(), HeapObject::kMapOffset),
+             Factory::heap_number_map());
+      __ j(not_equal, &go_runtime);
+      // Test if y is nan.
+      __ ucomisd(xmm1, xmm1);
+      __ j(parity_even, &go_runtime);
+
+      // Y must be a double.
+      __ movdbl(xmm1, FieldOperand(y.reg(), HeapNumber::kValueOffset));
+
+      Label x_not_smi;
+      Label handle_special_cases;
+      __ test(x.reg(), Immediate(kSmiTagMask));
+      __ j(not_zero, &x_not_smi);
+      __ SmiUntag(x.reg());
+      __ cvtsi2sd(xmm0, Operand(x.reg()));
+      __ jmp(&handle_special_cases);
+      __ bind(&x_not_smi);
+      __ cmp(FieldOperand(x.reg(), HeapObject::kMapOffset),
+             Factory::heap_number_map());
+      __ j(not_equal, &go_runtime);
+      __ mov(p.reg(), FieldOperand(x.reg(), HeapNumber::kExponentOffset));
+      __ and_(p.reg(), HeapNumber::kExponentMask);
+      __ cmp(Operand(p.reg()), Immediate(HeapNumber::kExponentMask));
+      // x is NaN or +/-Infinity
+      __ j(greater_equal, &go_runtime);
+      __ movdbl(xmm0, FieldOperand(x.reg(), HeapNumber::kValueOffset));
+
+      // x is in xmm0 and y is in xmm1.
+      __ bind(&handle_special_cases);
+      Label not_minus_half;
+      // Test for -0.5.
+      // Load xmm2 with -0.5.
+      __ mov(p.reg(), Immediate(0xBF000000));
+      __ movd(xmm2, Operand(p.reg()));
+      __ cvtss2sd(xmm2, xmm2);
+      // xmm2 now has -0.5.
+      __ ucomisd(xmm2, xmm1);
+      __ j(not_equal, &not_minus_half);
+
+      // Calculates reciprocal of square root.
+      // Note that 1/sqrt(x) = sqrt(1/x))
+      __ divsd(xmm3, xmm0);
+      __ movsd(xmm1, xmm3);
+      __ sqrtsd(xmm1, xmm1);
+      __ jmp(&allocate_and_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, &go_runtime);
+      // Calculates square root.
+      __ movsd(xmm1, xmm0);
+      __ sqrtsd(xmm1, xmm1);
+
+      __ bind(&allocate_and_return);
+      __ AllocateHeapNumber(p.reg(), y.reg(), x.reg(), &go_runtime);
+      __ movdbl(FieldOperand(p.reg(), HeapNumber::kValueOffset), xmm1);
+      __ jmp(&return_preg);
+    }
+    __ bind(&go_runtime);
+    x.Unuse();
+    y.Unuse();
+    p.Unuse();
+    Load(args->at(0));
+    Load(args->at(1));
+    frame_->CallRuntime(Runtime::kMath_pow_cfunction, 2);
+
+    // Since we store the result in p.reg() which is eax - return this value.
+    // If we called runtime the result is also in eax.
+    __ bind(&return_preg);
+    frame_->Push(eax);
+  } else {  // Simply call runtime.
+      Load(args->at(0));
+      Load(args->at(1));
+      Result res = frame_->CallRuntime(Runtime::kMath_pow, 2);
+      frame_->Push(&res);
+  }
+}
+
+
 // This generates code that performs a charCodeAt() call or returns
 // undefined in order to trigger the slow case, Runtime_StringCharCodeAt.
 // It can handle flat, 8 and 16 bit characters and cons strings where the
index 34e602ad548433dd9f33806884da8ba6d881e5bd..06066115ddef834609c494577ee3c094fce4b50c 100644 (file)
@@ -588,6 +588,9 @@ class CodeGenerator: public AstVisitor {
   // Fast support for number to string.
   void GenerateNumberToString(ZoneList<Expression*>* args);
 
+  // Fast support for Math.pow().
+  void GeneratePow(ZoneList<Expression*>* args);
+
   // Fast call to transcendental functions.
   void GenerateMathSin(ZoneList<Expression*>* args);
   void GenerateMathCos(ZoneList<Expression*>* args);
index 4c9de6741678d343a303e4f656bfdc092645be75..380d687f9eec61568dd11c9829f0bca0dcfae071 100644 (file)
@@ -159,7 +159,7 @@ function MathMin(arg1, arg2) {  // length == 2
 function MathPow(x, y) {
   if (!IS_NUMBER(x)) x = ToNumber(x);
   if (!IS_NUMBER(y)) y = ToNumber(y);
-  return %Math_pow(x, y);
+  return %_Pow(x, y);
 }
 
 // ECMA 262 - 15.8.2.14
index 2de45f67f0ac4e7d623e1ad4975a6ded30325d8e..1446ff5f63579127940991dd0ead357f40e17d18 100644 (file)
@@ -292,6 +292,11 @@ void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) {
 }
 
 
+void CodeGenerator::GeneratePow(ZoneList<Expression*>* args) {
+  UNIMPLEMENTED_MIPS();
+}
+
+
 // This should generate code that performs a charCodeAt() call or returns
 // undefined in order to trigger the slow case, Runtime_StringCharCodeAt.
 // It is not yet implemented on ARM, so it always goes to the slow case.
index 147b8724eddec9af4767655267b7f0f3b644f0fb..c6abb8231c87b166877b55fc00b31d7b93423523 100644 (file)
@@ -244,6 +244,8 @@ class CodeGenerator: public AstVisitor {
   void GenerateRegExpExec(ZoneList<Expression*>* args);
   void GenerateNumberToString(ZoneList<Expression*>* args);
 
+  // Fast support for Math.pow().
+  void GeneratePow(ZoneList<Expression*>* args);
 
   // Fast support for Math.sin and Math.cos.
   inline void GenerateMathSin(ZoneList<Expression*>* args);
index fe6b9a8ba769e1a0444ed6d7e2d0fa948a97b45c..fb12a1aee6333f8369b4f60a6297d8061acc3356 100644 (file)
@@ -4870,6 +4870,22 @@ static Object* Runtime_Math_pow(Arguments args) {
   }
 }
 
+// Fast version of Math.pow if we know that y is not an integer and
+// y is not -0.5 or 0.5. Used as slowcase from codegen.
+static Object* Runtime_Math_pow_cfunction(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 2);
+  CONVERT_DOUBLE_CHECKED(x, args[0]);
+  CONVERT_DOUBLE_CHECKED(y, args[1]);
+  if (y == 0) {
+      return Smi::FromInt(1);
+  } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
+      return Heap::nan_value();
+  } else {
+      return Heap::AllocateHeapNumber(pow(x, y));
+  }
+}
+
 
 static Object* Runtime_Math_round(Arguments args) {
   NoHandleAllocation ha;
index e2e5c22124d59949100d609b81442d55c4b9919d..e786a9e93472d5ce71b8551c118b2720cfa898e1 100644 (file)
@@ -142,6 +142,7 @@ namespace internal {
   F(Math_floor, 1, 1) \
   F(Math_log, 1, 1) \
   F(Math_pow, 2, 1) \
+  F(Math_pow_cfunction, 2, 1) \
   F(Math_round, 1, 1) \
   F(Math_sin, 1, 1) \
   F(Math_sqrt, 1, 1) \
index dd0f44455475f889f0cc8e7e4f5c91c3b86f0141..d2df5a875fe962c57d3d01d7d1f3b5ff806787c6 100644 (file)
@@ -3889,6 +3889,16 @@ void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) {
 }
 
 
+// Generates the Math.pow method - currently just calls runtime.
+void CodeGenerator::GeneratePow(ZoneList<Expression*>* args) {
+  ASSERT(args->length() == 2);
+  Load(args->at(0));
+  Load(args->at(1));
+  Result res = frame_->CallRuntime(Runtime::kMath_pow, 2);
+  frame_->Push(&res);
+}
+
+
 void CodeGenerator::GenerateIsSmi(ZoneList<Expression*>* args) {
   ASSERT(args->length() == 1);
   Load(args->at(0));
index 6561a817c7f534d748c5ab0b73ef9bdd3b4b6e2c..744be57be535a228cee3beda30fda53dd988303b 100644 (file)
@@ -572,6 +572,9 @@ class CodeGenerator: public AstVisitor {
   // Fast support for number to string.
   void GenerateNumberToString(ZoneList<Expression*>* args);
 
+  // Fast support for Math.pow().
+  void GeneratePow(ZoneList<Expression*>* args);
+
   // Fast call to math functions.
   void GenerateMathSin(ZoneList<Expression*>* args);
   void GenerateMathCos(ZoneList<Expression*>* args);