diff --git a/src/mips/code-stubs-mips.cc b/src/mips/code-stubs-mips.cc index bfb705be87..47f24a0ddf 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; + 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; - 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); + 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)); - __ bind(&convert_exponent); + __ 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); + __ 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); - // 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); - __ CallCFunction( - ExternalReference::power_double_double_function(masm->isolate()), - 0, - 2); - __ pop(ra); - __ GetCFunctionDoubleResult(double_result); - } - __ sdc1(double_result, - FieldMemOperand(heapnumber, HeapNumber::kValueOffset)); - __ mov(v0, heapnumber); - __ DropAndRet(2 * kPointerSize); + __ bind(&exponent_not_smi); + __ ldc1(double_exponent, + FieldMemOperand(exponent, HeapNumber::kValueOffset)); } - __ bind(&call_runtime); - __ TailCallRuntime(Runtime::kMath_pow_cfunction, 2, 1); + 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); + } + + __ 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); + __ 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)); + 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(&done); + __ IncrementCounter(counters->math_pow(), 1, scratch, scratch2); + __ Ret(); + } } diff --git a/src/mips/full-codegen-mips.cc b/src/mips/full-codegen-mips.cc index 0798d48f44..1e950e5f51 100644 --- a/src/mips/full-codegen-mips.cc +++ b/src/mips/full-codegen-mips.cc @@ -2958,8 +2958,12 @@ void FullCodeGenerator::EmitMathPow(CallRuntime* expr) { ASSERT(args->length() == 2); VisitForStackValue(args->at(0)); VisitForStackValue(args->at(1)); - MathPowStub stub(MathPowStub::ON_STACK); - __ CallStub(&stub); + if (CpuFeatures::IsSupported(FPU)) { + MathPowStub stub(MathPowStub::ON_STACK); + __ CallStub(&stub); + } else { + __ CallRuntime(Runtime::kMath_pow, 2); + } context()->Plug(v0); } diff --git a/src/mips/lithium-codegen-mips.cc b/src/mips/lithium-codegen-mips.cc index 7ccde79ac6..c160db4a27 100644 --- a/src/mips/lithium-codegen-mips.cc +++ b/src/mips/lithium-codegen-mips.cc @@ -3024,58 +3024,32 @@ void LCodeGen::DoMathPowHalf(LUnaryMathOperation* instr) { void LCodeGen::DoPower(LPower* instr) { - LOperand* left = instr->InputAt(0); - LOperand* right = instr->InputAt(1); - Register scratch = scratch0(); - DoubleRegister result_reg = ToDoubleRegister(instr->result()); Representation exponent_type = instr->hydrogen()->right()->representation(); - if (exponent_type.IsDouble()) { - // Prepare arguments and call C function. - __ PrepareCallCFunction(0, 2, scratch); - __ SetCallCDoubleArguments(ToDoubleRegister(left), - ToDoubleRegister(right)); - __ CallCFunction( - ExternalReference::power_double_double_function(isolate()), 0, 2); + // Having marked this as a call, we can use any registers. + // Just make sure that the input/output registers are the expected ones. + ASSERT(!instr->InputAt(1)->IsDoubleRegister() || + ToDoubleRegister(instr->InputAt(1)).is(f4)); + ASSERT(!instr->InputAt(1)->IsRegister() || + ToRegister(instr->InputAt(1)).is(a2)); + ASSERT(ToDoubleRegister(instr->InputAt(0)).is(f2)); + ASSERT(ToDoubleRegister(instr->result()).is(f0)); + + if (exponent_type.IsTagged()) { + Label no_deopt; + __ JumpIfSmi(a2, &no_deopt); + __ lw(t3, FieldMemOperand(a2, HeapObject::kMapOffset)); + DeoptimizeIf(ne, instr->environment(), t3, Operand(at)); + __ bind(&no_deopt); + MathPowStub stub(MathPowStub::TAGGED); + __ CallStub(&stub); } else if (exponent_type.IsInteger32()) { - ASSERT(ToRegister(right).is(a0)); - // Prepare arguments and call C function. - __ PrepareCallCFunction(1, 1, scratch); - __ SetCallCDoubleArguments(ToDoubleRegister(left), ToRegister(right)); - __ CallCFunction( - ExternalReference::power_double_int_function(isolate()), 1, 1); + MathPowStub stub(MathPowStub::INTEGER); + __ CallStub(&stub); } else { - ASSERT(exponent_type.IsTagged()); - ASSERT(instr->hydrogen()->left()->representation().IsDouble()); - - Register right_reg = ToRegister(right); - - // Check for smi on the right hand side. - Label non_smi, call; - __ JumpIfNotSmi(right_reg, &non_smi); - - // Untag smi and convert it to a double. - __ SmiUntag(right_reg); - FPURegister single_scratch = double_scratch0(); - __ mtc1(right_reg, single_scratch); - __ cvt_d_w(result_reg, single_scratch); - __ Branch(&call); - - // Heap number map check. - __ bind(&non_smi); - __ lw(scratch, FieldMemOperand(right_reg, HeapObject::kMapOffset)); - __ LoadRoot(at, Heap::kHeapNumberMapRootIndex); - DeoptimizeIf(ne, instr->environment(), scratch, Operand(at)); - __ ldc1(result_reg, FieldMemOperand(right_reg, HeapNumber::kValueOffset)); - - // Prepare arguments and call C function. - __ bind(&call); - __ PrepareCallCFunction(0, 2, scratch); - __ SetCallCDoubleArguments(ToDoubleRegister(left), result_reg); - __ CallCFunction( - ExternalReference::power_double_double_function(isolate()), 0, 2); + ASSERT(exponent_type.IsDouble()); + MathPowStub stub(MathPowStub::DOUBLE); + __ CallStub(&stub); } - // Store the result in the result register. - __ GetCFunctionDoubleResult(result_reg); } diff --git a/src/mips/lithium-mips.cc b/src/mips/lithium-mips.cc index d824deea91..071e62d508 100644 --- a/src/mips/lithium-mips.cc +++ b/src/mips/lithium-mips.cc @@ -1406,9 +1406,9 @@ LInstruction* LChunkBuilder::DoPower(HPower* instr) { LOperand* left = UseFixedDouble(instr->left(), f2); LOperand* right = exponent_type.IsDouble() ? UseFixedDouble(instr->right(), f4) : - UseFixed(instr->right(), a0); + UseFixed(instr->right(), a2); LPower* result = new LPower(left, right); - return MarkAsCall(DefineFixedDouble(result, f6), + return MarkAsCall(DefineFixedDouble(result, f0), instr, CAN_DEOPTIMIZE_EAGERLY); }