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 |