Chromium Code Reviews| Index: src/ia32/codegen-ia32.cc |
| =================================================================== |
| --- src/ia32/codegen-ia32.cc (revision 3937) |
| +++ src/ia32/codegen-ia32.cc (working copy) |
| @@ -5277,6 +5277,184 @@ |
| } |
| +// 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); |
| + __ test(y.reg(), Immediate(1)); |
|
Lasse Reichstein
2010/02/26 09:06:20
If you shr(y.reg(),1) here, then the bit that was
Rico
2010/03/04 06:39:29
Done.
|
| + __ j(zero, &no_multiply); |
| + __ mulsd(xmm1, xmm0); |
| + __ bind(&no_multiply); |
| + __ shr(y.reg(), 1); |
| + __ test(y.reg(), Operand(y.reg())); |
| + __ j(zero, &powi_done); |
|
Lasse Reichstein
2010/02/26 09:06:20
Just do:
mulsd(xmm0, xmm0);
j(not_zero, &while_t
Rico
2010/03/04 06:39:29
Done.
|
| + __ mulsd(xmm0, xmm0); |
| + __ jmp(&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(0x7FF00000)); |
|
Lasse Reichstein
2010/02/26 09:06:20
I don't think this is single-precission infinity.
Rico
2010/03/04 06:39:29
As discussed offline this will always branch to ru
|
| + __ movd(xmm0, Operand(p.reg())); |
| + __ cvtss2sd(xmm0, xmm0); |
| + __ comisd(xmm0, xmm1); |
|
Lasse Reichstein
2010/02/26 09:06:20
Use ucomisd instead of comisd.
Rico
2010/03/04 06:39:29
Done - added ucomisd to assembler-ia32
|
| + __ 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. |
| + __ comisd(xmm1, xmm1); |
|
Lasse Reichstein
2010/02/26 09:06:20
ucomisd
Rico
2010/03/04 06:39:29
Done.
|
| + __ 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)); |
|
Lasse Reichstein
2010/02/26 09:06:20
Add comment here saying something like "p is NaN o
Rico
2010/03/04 06:39:29
Done.
|
| + __ 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. |
| + __ comisd(xmm2, xmm1); |
|
Lasse Reichstein
2010/02/26 09:06:20
ucomisd
Rico
2010/03/04 06:39:29
Done.
|
| + __ j(not_equal, ¬_minus_half); |
| + |
| + // Calculates reciprocal of square root. |
| + __ sqrt(xmm0, xmm0); |
|
Lasse Reichstein
2010/02/26 09:06:20
Why isn't sqrt called sqrtsd?
Rico
2010/03/04 06:39:29
Changed name and moved down to sse2 instructions.
|
| + __ divsd(xmm3, xmm0); |
| + __ movsd(xmm1, xmm3); |
|
Lasse Reichstein
2010/02/26 09:06:20
Move sqrt to the end (i.e., sqrt(xmm1,xmm1)) since
Rico
2010/03/04 06:39:29
Done.
|
| + __ jmp(&allocate_and_return); |
| + |
| + // Test for 0.5. |
| + __ bind(¬_minus_half); |
| + // Load xmm2 with 0.5. |
| + __ mov(p.reg(), Immediate(0x3F000000)); |
|
Lasse Reichstein
2010/02/26 09:06:20
You have -0.5 in xmm2 already, and 1.0 in xmm3, so
Rico
2010/03/04 06:39:29
Done.
|
| + __ movd(xmm2, Operand(p.reg())); |
| + __ cvtss2sd(xmm2, xmm2); |
| + // xmm2 now has 0.5. |
| + __ comisd(xmm2, xmm1); |
|
Lasse Reichstein
2010/02/26 09:06:20
ucomisd
Rico
2010/03/04 06:39:29
Done.
|
| + __ j(not_equal, &go_runtime); |
| + // Calculates square root. |
| + __ sqrt(xmm0, xmm0); |
|
Lasse Reichstein
2010/02/26 09:06:20
do
movsd(xmm1, xmm0);
sqrt(xmm1, xmm1);
instead
Rico
2010/03/04 06:39:29
Done.
|
| + __ movsd(xmm1, xmm0); |
| + |
| + |
| + __ 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 |