Index: src/mips/code-stubs-mips.cc |
diff --git a/src/mips/code-stubs-mips.cc b/src/mips/code-stubs-mips.cc |
index a1cf9211ea51042dfc9f7d4f21b9590f5d0fd891..84c3896bb744440002d42b0fa309c21b12c60565 100644 |
--- a/src/mips/code-stubs-mips.cc |
+++ b/src/mips/code-stubs-mips.cc |
@@ -3592,113 +3592,218 @@ void StackCheckStub::Generate(MacroAssembler* masm) { |
void MathPowStub::Generate(MacroAssembler* masm) { |
- Label call_runtime; |
- |
- if (CpuFeatures::IsSupported(FPU)) { |
- CpuFeatures::Scope scope(FPU); |
- |
- Label base_not_smi; |
- Label exponent_not_smi; |
- Label convert_exponent; |
- |
- const Register base = a0; |
- const Register exponent = a2; |
- const Register heapnumbermap = t1; |
- const Register heapnumber = s0; // Callee-saved register. |
- const Register scratch = t2; |
- const Register scratch2 = t3; |
- |
- // Alocate FP values in the ABI-parameter-passing regs. |
- const DoubleRegister double_base = f12; |
- const DoubleRegister double_exponent = f14; |
- const DoubleRegister double_result = f0; |
- const DoubleRegister double_scratch = f2; |
- |
- __ LoadRoot(heapnumbermap, Heap::kHeapNumberMapRootIndex); |
+ CpuFeatures::Scope fpu_scope(FPU); |
+ const Register base = a1; |
+ const Register exponent = a2; |
+ const Register heapnumbermap = t1; |
+ const Register heapnumber = v0; |
+ const DoubleRegister double_base = f2; |
+ const DoubleRegister double_exponent = f4; |
+ const DoubleRegister double_result = f0; |
+ const DoubleRegister double_scratch = f6; |
+ const FPURegister single_scratch = f8; |
+ const Register scratch = t5; |
+ const Register scratch2 = t3; |
+ |
+ Label call_runtime, done, exponent_not_smi, int_exponent; |
+ if (exponent_type_ == ON_STACK) { |
+ Label base_is_smi, unpack_exponent; |
+ // The exponent and base are supplied as arguments on the stack. |
+ // This can only happen if the stub is called from non-optimized code. |
+ // Load input parameters from stack to double registers. |
__ lw(base, MemOperand(sp, 1 * kPointerSize)); |
__ lw(exponent, MemOperand(sp, 0 * kPointerSize)); |
- // Convert base to double value and store it in f0. |
- __ JumpIfNotSmi(base, &base_not_smi); |
- // Base is a Smi. Untag and convert it. |
- __ SmiUntag(base); |
- __ mtc1(base, double_scratch); |
- __ cvt_d_w(double_base, double_scratch); |
- __ Branch(&convert_exponent); |
+ __ LoadRoot(heapnumbermap, Heap::kHeapNumberMapRootIndex); |
- __ bind(&base_not_smi); |
+ __ JumpIfSmi(base, &base_is_smi); |
__ lw(scratch, FieldMemOperand(base, JSObject::kMapOffset)); |
__ Branch(&call_runtime, ne, scratch, Operand(heapnumbermap)); |
- // Base is a heapnumber. Load it into double register. |
+ |
__ ldc1(double_base, FieldMemOperand(base, HeapNumber::kValueOffset)); |
+ __ jmp(&unpack_exponent); |
+ |
+ __ bind(&base_is_smi); |
+ __ SmiUntag(base); |
+ __ mtc1(base, single_scratch); |
+ __ cvt_d_w(double_base, single_scratch); |
+ __ bind(&unpack_exponent); |
- __ bind(&convert_exponent); |
__ JumpIfNotSmi(exponent, &exponent_not_smi); |
__ SmiUntag(exponent); |
- |
- // The base is in a double register and the exponent is |
- // an untagged smi. Allocate a heap number and call a |
- // C function for integer exponents. The register containing |
- // the heap number is callee-saved. |
- __ AllocateHeapNumber(heapnumber, |
- scratch, |
- scratch2, |
- heapnumbermap, |
- &call_runtime); |
- __ push(ra); |
- __ PrepareCallCFunction(1, 1, scratch); |
- __ SetCallCDoubleArguments(double_base, exponent); |
- { |
- AllowExternalCallThatCantCauseGC scope(masm); |
- __ CallCFunction( |
- ExternalReference::power_double_int_function(masm->isolate()), 1, 1); |
- __ pop(ra); |
- __ GetCFunctionDoubleResult(double_result); |
- } |
- __ sdc1(double_result, |
- FieldMemOperand(heapnumber, HeapNumber::kValueOffset)); |
- __ mov(v0, heapnumber); |
- __ DropAndRet(2 * kPointerSize); |
+ __ jmp(&int_exponent); |
__ bind(&exponent_not_smi); |
__ lw(scratch, FieldMemOperand(exponent, JSObject::kMapOffset)); |
__ Branch(&call_runtime, ne, scratch, Operand(heapnumbermap)); |
- // Exponent is a heapnumber. Load it into double register. |
__ ldc1(double_exponent, |
FieldMemOperand(exponent, HeapNumber::kValueOffset)); |
+ } else if (exponent_type_ == TAGGED) { |
+ // Base is already in double_base. |
+ __ JumpIfNotSmi(exponent, &exponent_not_smi); |
+ __ SmiUntag(exponent); |
+ __ jmp(&int_exponent); |
+ |
+ __ bind(&exponent_not_smi); |
+ __ ldc1(double_exponent, |
+ FieldMemOperand(exponent, HeapNumber::kValueOffset)); |
+ } |
+ |
+ if (exponent_type_ != INTEGER) { |
+ Label int_exponent_convert; |
+ // Detect integer exponents stored as double. |
+ __ EmitFPUTruncate(kRoundToMinusInf, |
+ single_scratch, |
+ double_exponent, |
+ scratch, |
+ scratch2, |
+ kCheckForInexactConversion); |
+ // scratch2 == 0 means there was no conversion error. |
+ __ Branch(&int_exponent_convert, eq, scratch2, Operand(zero_reg)); |
+ |
+ if (exponent_type_ == ON_STACK) { |
+ // Detect square root case. Crankshaft detects constant +/-0.5 at |
+ // compile time and uses DoMathPowHalf instead. We then skip this check |
+ // for non-constant cases of +/-0.5 as these hardly occur. |
+ Label not_plus_half; |
+ |
+ // Test for 0.5. |
+ __ Move(double_scratch, 0.5); |
+ __ BranchF(USE_DELAY_SLOT, |
+ ¬_plus_half, |
+ NULL, |
+ ne, |
+ double_exponent, |
+ double_scratch); |
+ |
+ // Calculates square root of base. Check for the special case of |
+ // Math.pow(-Infinity, 0.5) == Infinity (ECMA spec, 15.8.2.13). |
+ __ Move(double_scratch, -V8_INFINITY); |
+ __ BranchF(USE_DELAY_SLOT, &done, NULL, eq, double_base, double_scratch); |
+ __ neg_d(double_result, double_scratch); |
+ |
+ // Add +0 to convert -0 to +0. |
+ __ add_d(double_scratch, double_base, kDoubleRegZero); |
+ __ sqrt_d(double_result, double_scratch); |
+ __ jmp(&done); |
+ |
+ __ bind(¬_plus_half); |
+ __ Move(double_scratch, -0.5); |
+ __ BranchF(USE_DELAY_SLOT, |
+ &call_runtime, |
+ NULL, |
+ ne, |
+ double_exponent, |
+ double_scratch); |
+ |
+ // Calculates square root of base. Check for the special case of |
+ // Math.pow(-Infinity, -0.5) == 0 (ECMA spec, 15.8.2.13). |
+ __ Move(double_scratch, -V8_INFINITY); |
+ __ BranchF(USE_DELAY_SLOT, &done, NULL, eq, double_base, double_scratch); |
+ __ Move(double_result, kDoubleRegZero); |
+ |
+ // Add +0 to convert -0 to +0. |
+ __ add_d(double_scratch, double_base, kDoubleRegZero); |
+ __ Move(double_result, 1); |
+ __ sqrt_d(double_scratch, double_scratch); |
+ __ div_d(double_result, double_result, double_scratch); |
+ __ jmp(&done); |
+ } |
- // The base and the exponent are in double registers. |
- // Allocate a heap number and call a C function for |
- // double exponents. The register containing |
- // the heap number is callee-saved. |
- __ AllocateHeapNumber(heapnumber, |
- scratch, |
- scratch2, |
- heapnumbermap, |
- &call_runtime); |
__ push(ra); |
- __ PrepareCallCFunction(0, 2, scratch); |
- // ABI (o32) for func(double a, double b): a in f12, b in f14. |
- ASSERT(double_base.is(f12)); |
- ASSERT(double_exponent.is(f14)); |
- __ SetCallCDoubleArguments(double_base, double_exponent); |
{ |
AllowExternalCallThatCantCauseGC scope(masm); |
+ __ PrepareCallCFunction(0, 2, scratch); |
+ __ SetCallCDoubleArguments(double_base, double_exponent); |
__ CallCFunction( |
ExternalReference::power_double_double_function(masm->isolate()), |
- 0, |
- 2); |
- __ pop(ra); |
- __ GetCFunctionDoubleResult(double_result); |
+ 0, 2); |
} |
+ __ pop(ra); |
+ __ GetCFunctionDoubleResult(double_result); |
+ __ jmp(&done); |
+ |
+ __ bind(&int_exponent_convert); |
+ __ mfc1(exponent, single_scratch); |
+ } |
+ |
+ // Calculate power with integer exponent. |
+ __ bind(&int_exponent); |
+ |
+ __ mov(scratch, exponent); // Back up exponent. |
+ __ mov_d(double_scratch, double_base); // Back up base. |
+ __ Move(double_result, 1.0); |
+ |
+ // Get absolute value of exponent. |
+ Label positive_exponent; |
+ __ Branch(&positive_exponent, ge, scratch, Operand(zero_reg)); |
+ __ Subu(scratch, zero_reg, scratch); |
+ __ bind(&positive_exponent); |
+ |
+ Label while_true, no_carry, loop_end; |
+ __ bind(&while_true); |
+ |
+ __ And(scratch2, scratch, 1); |
+ |
+ __ Branch(&no_carry, eq, scratch2, Operand(zero_reg)); |
+ __ mul_d(double_result, double_result, double_scratch); |
+ __ bind(&no_carry); |
+ |
+ __ sra(scratch, scratch, 1); |
+ |
+ __ Branch(&loop_end, eq, scratch, Operand(zero_reg)); |
+ __ mul_d(double_scratch, double_scratch, double_scratch); |
+ |
+ __ Branch(&while_true); |
+ |
+ __ bind(&loop_end); |
+ |
+ __ Branch(&done, ge, exponent, Operand(zero_reg)); |
+ __ Move(double_scratch, 1.0); |
+ __ div_d(double_result, double_scratch, double_result); |
+ // Test whether result is zero. Bail out to check for subnormal result. |
+ // Due to subnormals, x^-y == (1/x)^y does not hold in all cases. |
+ __ BranchF(&done, NULL, ne, double_result, kDoubleRegZero); |
+ |
+ // double_exponent may not contain the exponent value if the input was a |
+ // smi. We set it with exponent value before bailing out. |
+ __ mtc1(exponent, single_scratch); |
+ __ cvt_d_w(double_exponent, single_scratch); |
+ |
+ // Returning or bailing out. |
+ Counters* counters = masm->isolate()->counters(); |
+ if (exponent_type_ == ON_STACK) { |
+ // The arguments are still on the stack. |
+ __ bind(&call_runtime); |
+ __ TailCallRuntime(Runtime::kMath_pow_cfunction, 2, 1); |
+ |
+ // The stub is called from non-optimized code, which expects the result |
+ // as heap number in exponent. |
+ __ bind(&done); |
+ __ AllocateHeapNumber( |
+ heapnumber, scratch, scratch2, heapnumbermap, &call_runtime); |
__ sdc1(double_result, |
FieldMemOperand(heapnumber, HeapNumber::kValueOffset)); |
- __ mov(v0, heapnumber); |
- __ DropAndRet(2 * kPointerSize); |
- } |
+ ASSERT(heapnumber.is(v0)); |
+ __ IncrementCounter(counters->math_pow(), 1, scratch, scratch2); |
+ __ DropAndRet(2); |
+ } else { |
+ __ push(ra); |
+ { |
+ AllowExternalCallThatCantCauseGC scope(masm); |
+ __ PrepareCallCFunction(0, 2, scratch); |
+ __ SetCallCDoubleArguments(double_base, double_exponent); |
+ __ CallCFunction( |
+ ExternalReference::power_double_double_function(masm->isolate()), |
+ 0, 2); |
+ } |
+ __ pop(ra); |
+ __ GetCFunctionDoubleResult(double_result); |
- __ bind(&call_runtime); |
- __ TailCallRuntime(Runtime::kMath_pow_cfunction, 2, 1); |
+ __ bind(&done); |
+ __ IncrementCounter(counters->math_pow(), 1, scratch, scratch2); |
+ __ Ret(); |
+ } |
} |