Chromium Code Reviews| Index: src/ia32/codegen-ia32.cc |
| =================================================================== |
| --- src/ia32/codegen-ia32.cc (revision 4002) |
| +++ src/ia32/codegen-ia32.cc (working copy) |
| @@ -5276,182 +5276,6 @@ |
| } |
| -// 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()); |
| - |
| - // Save 1 in xmm3 - we need this several times later on |
| - __ mov(p.reg(), Immediate(1)); |
| - __ cvtsi2sd(xmm3, Operand(p.reg())); |
| - |
| - 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()); |
| - |
| - |
| - // 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); |
| - // Y must be a double. |
| - __ movdbl(xmm1, FieldOperand(y.reg(), HeapNumber::kValueOffset)); |
| - // Test if y is nan. |
| - __ ucomisd(xmm1, xmm1); |
| - __ j(parity_even, &go_runtime); |
| - |
| - 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 |
| // undefined in order to trigger the slow case, Runtime_StringCharCodeAt. |
| // It can handle flat, 8 and 16 bit characters and cons strings where the |
| @@ -6040,6 +5864,194 @@ |
| } |
| +// Generates the Math.pow method - only handles special cases and branches to |
| +// the runtime system if not.Please note - this function assumes that |
| +// the callsite has executed ToNumber on both arguments and that the |
| +// arguments are not the same identifier. |
| +void CodeGenerator::GenerateMathPow(ZoneList<Expression*>* args) { |
| + ASSERT(args->length() == 2); |
| + Load(args->at(0)); |
| + Load(args->at(1)); |
| + if (!CpuFeatures::IsSupported(SSE2)) { |
| + Result res = frame_->CallRuntime(Runtime::kMath_pow, 2); |
| + frame_->Push(&res); |
| + } else { |
| + CpuFeatures::Scope use_sse2(SSE2); |
| + Label allocate_return; |
| + // Load the two operands while leaving the values on the frame. |
| + frame()->Dup(); |
| + Result exponent = frame()->Pop(); |
| + exponent.ToRegister(); |
| + frame()->Spill(exponent.reg()); |
| + frame()->PushElementAt(1); |
| + Result base = frame()->Pop(); |
| + base.ToRegister(); |
| + frame()->Spill(base.reg()); |
| + |
| + Result answer = allocator()->Allocate(); |
| + ASSERT(answer.is_valid()); |
| + // We can safely assume that the base and exponent is not in the same |
| + // register since we only call this from one callsite (math.js). |
| + ASSERT(!exponent.reg().is(base.reg())); |
| + JumpTarget call_runtime; |
| + |
| + // Save 1 in xmm3 - we need this several times later on. |
| + __ mov(answer.reg(), Immediate(1)); |
| + __ cvtsi2sd(xmm3, Operand(answer.reg())); |
| + |
| + Label exponent_nonsmi; |
| + Label base_nonsmi; |
| + // If the exponent is a heap number go to that specific case. |
| + __ test(exponent.reg(), Immediate(kSmiTagMask)); |
| + __ j(not_zero, &exponent_nonsmi); |
| + __ test(base.reg(), Immediate(kSmiTagMask)); |
| + __ j(not_zero, &base_nonsmi); |
| + |
| + // Optimized version when y is an integer. |
| + Label powi; |
| + __ SmiUntag(base.reg()); |
| + __ cvtsi2sd(xmm0, Operand(base.reg())); |
| + __ jmp(&powi); |
| + // exponent is smi and base is a heapnumber. |
| + __ bind(&base_nonsmi); |
| + __ cmp(FieldOperand(base.reg(), HeapObject::kMapOffset), |
| + Factory::heap_number_map()); |
|
Lasse Reichstein
2010/03/08 13:17:01
Indentation? Ditto for other two.
|
| + call_runtime.Branch(not_zero); |
|
Lasse Reichstein
2010/03/08 13:17:01
not_zero->not_equal (I know they are identical, bu
|
| + |
| + __ movdbl(xmm0, FieldOperand(base.reg(), HeapNumber::kValueOffset)); |
| + |
| + // Optimized version of pow if y is an integer. |
| + __ bind(&powi); |
| + __ SmiUntag(exponent.reg()); |
| + |
| + // Save exponent in base as we need to check if exponent is negative later. |
| + // We know that base and exponent are in different registers. |
| + __ mov(base.reg(), exponent.reg()); |
| + |
| + // Get absolute value of exponent. |
| + Label no_neg; |
| + __ cmp(exponent.reg(), 0); |
| + __ j(greater_equal, &no_neg); |
| + __ neg(exponent.reg()); |
| + __ bind(&no_neg); |
| + |
| + // Load xmm1 with 1. |
| + __ movsd(xmm1, xmm3); |
| + Label while_true; |
| + Label no_multiply; |
| + |
| + // Label allocate_and_return; |
| + __ bind(&while_true); |
| + __ shr(exponent.reg(), 1); |
| + __ j(not_carry, &no_multiply); |
| + __ mulsd(xmm1, xmm0); |
| + __ bind(&no_multiply); |
| + __ test(exponent.reg(), Operand(exponent.reg())); |
| + __ mulsd(xmm0, xmm0); |
| + __ j(not_zero, &while_true); |
| + |
| + // x has the original value of y - if y is negative return 1/result. |
| + __ test(base.reg(), Operand(base.reg())); |
| + __ j(positive, &allocate_return); |
| + // Special case if xmm1 has reached infinity. |
| + __ mov(answer.reg(), Immediate(0x7FB00000)); |
| + __ movd(xmm0, Operand(answer.reg())); |
| + __ cvtss2sd(xmm0, xmm0); |
| + __ ucomisd(xmm0, xmm1); |
| + call_runtime.Branch(equal); |
| + __ divsd(xmm3, xmm1); |
| + __ movsd(xmm1, xmm3); |
| + __ jmp(&allocate_return); |
| + |
| + // exponent (or both) is a heapnumber - no matter what we should now work |
| + // on doubles. |
| + __ bind(&exponent_nonsmi); |
| + __ cmp(FieldOperand(exponent.reg(), HeapObject::kMapOffset), |
| + Factory::heap_number_map()); |
| + call_runtime.Branch(not_zero); |
| + __ movdbl(xmm1, FieldOperand(exponent.reg(), HeapNumber::kValueOffset)); |
| + // Test if exponent is nan. |
| + __ ucomisd(xmm1, xmm1); |
| + call_runtime.Branch(parity_even); |
| + |
| + Label base_not_smi; |
| + Label handle_special_cases; |
| + __ test(base.reg(), Immediate(kSmiTagMask)); |
| + __ j(not_zero, &base_not_smi); |
| + __ SmiUntag(base.reg()); |
| + __ cvtsi2sd(xmm0, Operand(base.reg())); |
| + __ jmp(&handle_special_cases); |
| + __ bind(&base_not_smi); |
| + __ cmp(FieldOperand(base.reg(), HeapObject::kMapOffset), |
| + Factory::heap_number_map()); |
| + call_runtime.Branch(not_zero); |
| + __ mov(answer.reg(), FieldOperand(base.reg(), HeapNumber::kExponentOffset)); |
| + __ and_(answer.reg(), HeapNumber::kExponentMask); |
| + __ cmp(Operand(answer.reg()), Immediate(HeapNumber::kExponentMask)); |
| + // base is NaN or +/-Infinity |
| + call_runtime.Branch(greater_equal); |
| + __ movdbl(xmm0, FieldOperand(base.reg(), HeapNumber::kValueOffset)); |
| + |
| + // base is in xmm0 and exponent is in xmm1. |
| + __ bind(&handle_special_cases); |
| + Label not_minus_half; |
| + // Test for -0.5. |
| + // Load xmm2 with -0.5. |
| + __ mov(answer.reg(), Immediate(0xBF000000)); |
| + __ movd(xmm2, Operand(answer.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_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. |
| + __ comisd(xmm2, xmm1); |
| + call_runtime.Branch(not_equal); |
| + // Calculates square root. |
| + __ movsd(xmm1, xmm0); |
| + __ sqrtsd(xmm1, xmm1); |
| + |
| + JumpTarget done; |
| + Label failure, success; |
| + __ bind(&allocate_return); |
| + // Make a copy of the frame to enable us to handle allocation |
| + // failure after the JumpTarget jump. |
| + VirtualFrame* clone = new VirtualFrame(frame()); |
| + __ AllocateHeapNumber(answer.reg(), exponent.reg(), |
| + base.reg(), &failure); |
| + __ movdbl(FieldOperand(answer.reg(), HeapNumber::kValueOffset), xmm1); |
| + // Remove the two original values from the frame - we only need those |
| + // in the case where we branch to runtime. |
| + frame()->Drop(2); |
| + exponent.Unuse(); |
| + base.Unuse(); |
| + done.Jump(&answer); |
| + // Use the copy of the original frame as our current frame. |
| + RegisterFile empty_regs; |
| + SetFrame(clone, &empty_regs); |
| + // If we experience an allocation failure we branch to runtime. |
| + __ bind(&failure); |
| + call_runtime.Bind(); |
| + answer = frame()->CallRuntime(Runtime::kMath_pow_cfunction, 2); |
| + |
| + done.Bind(&answer); |
| + frame()->Push(&answer); |
| + } |
| +} |
| + |
| + |
| void CodeGenerator::GenerateMathSin(ZoneList<Expression*>* args) { |
| ASSERT_EQ(args->length(), 1); |
| Load(args->at(0)); |
| @@ -6058,6 +6070,63 @@ |
| } |
| +// Generates the Math.sqrt method. Please note - this function assumes that |
| +// the callsite has executed ToNumber on the argument. |
| +void CodeGenerator::GenerateMathSqrt(ZoneList<Expression*>* args) { |
| + ASSERT_EQ(args->length(), 1); |
| + Load(args->at(0)); |
| + |
| + if (!CpuFeatures::IsSupported(SSE2)) { |
| + Result result = frame()->CallRuntime(Runtime::kMath_sqrt, 1); |
| + frame()->Push(&result); |
| + } else { |
| + CpuFeatures::Scope use_sse2(SSE2); |
| + // Leave original value on the frame if we need to call runtime. |
| + frame()->Dup(); |
| + Result result = frame()->Pop(); |
| + result.ToRegister(); |
| + frame()->Spill(result.reg()); |
| + Label runtime; |
| + Label non_smi; |
| + Label load_done; |
| + JumpTarget end; |
| + |
| + __ test(result.reg(), Immediate(kSmiTagMask)); |
| + __ j(not_zero, &non_smi); |
| + __ SmiUntag(result.reg()); |
| + __ cvtsi2sd(xmm0, Operand(result.reg())); |
| + __ jmp(&load_done); |
| + __ bind(&non_smi); |
| + __ cmp(FieldOperand(result.reg(), HeapObject::kMapOffset), |
| + Factory::heap_number_map()); |
| + __ j(not_zero, &runtime); |
| + __ movdbl(xmm0, FieldOperand(result.reg(), HeapNumber::kValueOffset)); |
| + |
| + __ bind(&load_done); |
| + __ sqrtsd(xmm0, xmm0); |
| + // A copy of the virtual frame to allow us to go to runtime after the |
| + // JumpTarget jump. |
| + Result scratch = allocator()->Allocate(); |
| + VirtualFrame* clone = new VirtualFrame(frame()); |
| + __ AllocateHeapNumber(result.reg(), scratch.reg(), no_reg, &runtime); |
| + |
| + __ movdbl(FieldOperand(result.reg(), HeapNumber::kValueOffset), xmm0); |
| + frame()->Drop(1); |
| + scratch.Unuse(); |
| + end.Jump(&result); |
| + // We only branch to runtime if we have an allocation error. |
| + // Use the copy of the original frame as our current frame. |
| + RegisterFile empty_regs; |
| + SetFrame(clone, &empty_regs); |
| + __ bind(&runtime); |
| + result = frame()->CallRuntime(Runtime::kMath_sqrt, 1); |
| + |
| + end.Bind(&result); |
| + frame()->Push(&result); |
| + } |
| +} |
| + |
| + |
| void CodeGenerator::VisitCallRuntime(CallRuntime* node) { |
| if (CheckForInlineRuntimeCall(node)) { |
| return; |