Commit 49686872 authored by ricow@chromium.org's avatar ricow@chromium.org

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3964 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 893637a0
......@@ -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.
......
......@@ -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);
......
......@@ -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"},
};
......
......@@ -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() };
......
......@@ -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();
......
......@@ -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
......
......@@ -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);
......
......@@ -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
......
......@@ -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.
......
......@@ -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);
......
......@@ -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;
......
......@@ -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) \
......
......@@ -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));
......
......@@ -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);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment