Revision: 3964
Author: [email protected]
Date: Fri Feb 26 02:24:58 2010
Log: Added fast support for Math.pow. This simply calculates the result
using the
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
http://code.google.com/p/v8/source/detail?r=3964
Modified:
/branches/bleeding_edge/src/arm/codegen-arm.cc
/branches/bleeding_edge/src/arm/codegen-arm.h
/branches/bleeding_edge/src/codegen.cc
/branches/bleeding_edge/src/ia32/assembler-ia32.cc
/branches/bleeding_edge/src/ia32/assembler-ia32.h
/branches/bleeding_edge/src/ia32/codegen-ia32.cc
/branches/bleeding_edge/src/ia32/codegen-ia32.h
/branches/bleeding_edge/src/math.js
/branches/bleeding_edge/src/mips/codegen-mips.cc
/branches/bleeding_edge/src/mips/codegen-mips.h
/branches/bleeding_edge/src/runtime.cc
/branches/bleeding_edge/src/runtime.h
/branches/bleeding_edge/src/x64/codegen-x64.cc
/branches/bleeding_edge/src/x64/codegen-x64.h
=======================================
--- /branches/bleeding_edge/src/arm/codegen-arm.cc Fri Feb 26 01:32:48 2010
+++ /branches/bleeding_edge/src/arm/codegen-arm.cc Fri Feb 26 02:24:58 2010
@@ -3321,6 +3321,15 @@
cc_reg_ = eq;
}
+
+// 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.
=======================================
--- /branches/bleeding_edge/src/arm/codegen-arm.h Fri Feb 26 01:32:48 2010
+++ /branches/bleeding_edge/src/arm/codegen-arm.h Fri Feb 26 02:24:58 2010
@@ -393,6 +393,9 @@
// 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);
=======================================
--- /branches/bleeding_edge/src/codegen.cc Fri Feb 26 01:32:48 2010
+++ /branches/bleeding_edge/src/codegen.cc Fri Feb 26 02:24:58 2010
@@ -380,6 +380,7 @@
{&CodeGenerator::GenerateStringCompare, "_StringCompare"},
{&CodeGenerator::GenerateRegExpExec, "_RegExpExec"},
{&CodeGenerator::GenerateNumberToString, "_NumberToString"},
+ {&CodeGenerator::GeneratePow, "_Pow"},
{&CodeGenerator::GenerateMathSin, "_Math_sin"},
{&CodeGenerator::GenerateMathCos, "_Math_cos"},
};
=======================================
--- /branches/bleeding_edge/src/ia32/assembler-ia32.cc Tue Feb 23 02:29:02
2010
+++ /branches/bleeding_edge/src/ia32/assembler-ia32.cc Fri Feb 26 02:24:58
2010
@@ -2033,6 +2033,17 @@
EMIT(0x2A);
emit_sse_operand(dst, 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) {
@@ -2088,6 +2099,16 @@
EMIT(0x57);
emit_sse_operand(dst, 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) {
@@ -2099,6 +2120,17 @@
EMIT(0x2F);
emit_sse_operand(dst, 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 ) {
@@ -2179,6 +2211,50 @@
EMIT(0x10); // load
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) {
=======================================
--- /branches/bleeding_edge/src/ia32/assembler-ia32.h Tue Feb 23 02:29:02
2010
+++ /branches/bleeding_edge/src/ia32/assembler-ia32.h Fri Feb 26 02:24:58
2010
@@ -93,7 +93,7 @@
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 @@
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 @@
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();
=======================================
--- /branches/bleeding_edge/src/ia32/codegen-ia32.cc Fri Feb 26 01:32:48
2010
+++ /branches/bleeding_edge/src/ia32/codegen-ia32.cc Fri Feb 26 02:24:58
2010
@@ -5273,6 +5273,181 @@
value.Unuse();
destination()->Split(zero);
}
+
+
+// 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, ¬_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(¬_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
=======================================
--- /branches/bleeding_edge/src/ia32/codegen-ia32.h Fri Feb 26 01:32:48 2010
+++ /branches/bleeding_edge/src/ia32/codegen-ia32.h Fri Feb 26 02:24:58 2010
@@ -588,6 +588,9 @@
// 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);
=======================================
--- /branches/bleeding_edge/src/math.js Tue Feb 23 02:29:02 2010
+++ /branches/bleeding_edge/src/math.js Fri Feb 26 02:24:58 2010
@@ -159,7 +159,7 @@
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
=======================================
--- /branches/bleeding_edge/src/mips/codegen-mips.cc Fri Feb 19 05:07:37
2010
+++ /branches/bleeding_edge/src/mips/codegen-mips.cc Fri Feb 26 02:24:58
2010
@@ -290,6 +290,11 @@
void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) {
UNIMPLEMENTED_MIPS();
}
+
+
+void CodeGenerator::GeneratePow(ZoneList<Expression*>* args) {
+ UNIMPLEMENTED_MIPS();
+}
// This should generate code that performs a charCodeAt() call or returns
=======================================
--- /branches/bleeding_edge/src/mips/codegen-mips.h Fri Feb 19 05:07:37 2010
+++ /branches/bleeding_edge/src/mips/codegen-mips.h Fri Feb 26 02:24:58 2010
@@ -244,6 +244,8 @@
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);
=======================================
--- /branches/bleeding_edge/src/runtime.cc Thu Feb 25 10:26:36 2010
+++ /branches/bleeding_edge/src/runtime.cc Fri Feb 26 02:24:58 2010
@@ -4869,6 +4869,22 @@
return Heap::AllocateHeapNumber(pow(x, y));
}
}
+
+// 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) {
=======================================
--- /branches/bleeding_edge/src/runtime.h Wed Feb 17 05:23:46 2010
+++ /branches/bleeding_edge/src/runtime.h Fri Feb 26 02:24:58 2010
@@ -142,6 +142,7 @@
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) \
=======================================
--- /branches/bleeding_edge/src/x64/codegen-x64.cc Fri Feb 26 01:32:48 2010
+++ /branches/bleeding_edge/src/x64/codegen-x64.cc Fri Feb 26 02:24:58 2010
@@ -3887,6 +3887,16 @@
value.Unuse();
destination()->Split(positive_smi);
}
+
+
+// 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) {
=======================================
--- /branches/bleeding_edge/src/x64/codegen-x64.h Fri Feb 26 01:32:48 2010
+++ /branches/bleeding_edge/src/x64/codegen-x64.h Fri Feb 26 02:24:58 2010
@@ -572,6 +572,9 @@
// 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);
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev