MIPS: Port Math.pow inlining to ARM.

Port r10210 (6b15398) and r10226 (cdc75a453).

BUG=
TEST=

Review URL: http://codereview.chromium.org/8896021
Patch from Daniel Kalmar <kalmard@homejinni.com>.

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@10234 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
yangguo@chromium.org 2011-12-12 08:26:42 +00:00
parent 42a85ce584
commit 6fdf50c040
4 changed files with 223 additions and 140 deletions

View File

@ -3592,113 +3592,218 @@ void StackCheckStub::Generate(MacroAssembler* masm) {
void MathPowStub::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)) { Label call_runtime, done, exponent_not_smi, int_exponent;
CpuFeatures::Scope scope(FPU); if (exponent_type_ == ON_STACK) {
Label base_is_smi, unpack_exponent;
Label base_not_smi; // The exponent and base are supplied as arguments on the stack.
Label exponent_not_smi; // This can only happen if the stub is called from non-optimized code.
Label convert_exponent; // Load input parameters from stack to double registers.
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);
__ lw(base, MemOperand(sp, 1 * kPointerSize)); __ lw(base, MemOperand(sp, 1 * kPointerSize));
__ lw(exponent, MemOperand(sp, 0 * kPointerSize)); __ lw(exponent, MemOperand(sp, 0 * kPointerSize));
// Convert base to double value and store it in f0. __ LoadRoot(heapnumbermap, Heap::kHeapNumberMapRootIndex);
__ 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);
__ bind(&base_not_smi); __ JumpIfSmi(base, &base_is_smi);
__ lw(scratch, FieldMemOperand(base, JSObject::kMapOffset)); __ lw(scratch, FieldMemOperand(base, JSObject::kMapOffset));
__ Branch(&call_runtime, ne, scratch, Operand(heapnumbermap)); __ 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); __ JumpIfNotSmi(exponent, &exponent_not_smi);
__ SmiUntag(exponent); __ SmiUntag(exponent);
__ jmp(&int_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);
__ bind(&exponent_not_smi); __ bind(&exponent_not_smi);
__ lw(scratch, FieldMemOperand(exponent, JSObject::kMapOffset)); __ lw(scratch, FieldMemOperand(exponent, JSObject::kMapOffset));
__ Branch(&call_runtime, ne, scratch, Operand(heapnumbermap)); __ Branch(&call_runtime, ne, scratch, Operand(heapnumbermap));
// Exponent is a heapnumber. Load it into double register.
__ ldc1(double_exponent, __ ldc1(double_exponent,
FieldMemOperand(exponent, HeapNumber::kValueOffset)); 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. __ bind(&exponent_not_smi);
// Allocate a heap number and call a C function for __ ldc1(double_exponent,
// double exponents. The register containing FieldMemOperand(exponent, HeapNumber::kValueOffset));
// 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(&call_runtime); if (exponent_type_ != INTEGER) {
__ TailCallRuntime(Runtime::kMath_pow_cfunction, 2, 1); 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,
&not_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(&not_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();
}
} }

View File

@ -2958,8 +2958,12 @@ void FullCodeGenerator::EmitMathPow(CallRuntime* expr) {
ASSERT(args->length() == 2); ASSERT(args->length() == 2);
VisitForStackValue(args->at(0)); VisitForStackValue(args->at(0));
VisitForStackValue(args->at(1)); VisitForStackValue(args->at(1));
MathPowStub stub(MathPowStub::ON_STACK); if (CpuFeatures::IsSupported(FPU)) {
__ CallStub(&stub); MathPowStub stub(MathPowStub::ON_STACK);
__ CallStub(&stub);
} else {
__ CallRuntime(Runtime::kMath_pow, 2);
}
context()->Plug(v0); context()->Plug(v0);
} }

View File

@ -3024,58 +3024,32 @@ void LCodeGen::DoMathPowHalf(LUnaryMathOperation* instr) {
void LCodeGen::DoPower(LPower* 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(); Representation exponent_type = instr->hydrogen()->right()->representation();
if (exponent_type.IsDouble()) { // Having marked this as a call, we can use any registers.
// Prepare arguments and call C function. // Just make sure that the input/output registers are the expected ones.
__ PrepareCallCFunction(0, 2, scratch); ASSERT(!instr->InputAt(1)->IsDoubleRegister() ||
__ SetCallCDoubleArguments(ToDoubleRegister(left), ToDoubleRegister(instr->InputAt(1)).is(f4));
ToDoubleRegister(right)); ASSERT(!instr->InputAt(1)->IsRegister() ||
__ CallCFunction( ToRegister(instr->InputAt(1)).is(a2));
ExternalReference::power_double_double_function(isolate()), 0, 2); 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()) { } else if (exponent_type.IsInteger32()) {
ASSERT(ToRegister(right).is(a0)); MathPowStub stub(MathPowStub::INTEGER);
// Prepare arguments and call C function. __ CallStub(&stub);
__ PrepareCallCFunction(1, 1, scratch);
__ SetCallCDoubleArguments(ToDoubleRegister(left), ToRegister(right));
__ CallCFunction(
ExternalReference::power_double_int_function(isolate()), 1, 1);
} else { } else {
ASSERT(exponent_type.IsTagged()); ASSERT(exponent_type.IsDouble());
ASSERT(instr->hydrogen()->left()->representation().IsDouble()); MathPowStub stub(MathPowStub::DOUBLE);
__ CallStub(&stub);
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);
} }
// Store the result in the result register.
__ GetCFunctionDoubleResult(result_reg);
} }

View File

@ -1406,9 +1406,9 @@ LInstruction* LChunkBuilder::DoPower(HPower* instr) {
LOperand* left = UseFixedDouble(instr->left(), f2); LOperand* left = UseFixedDouble(instr->left(), f2);
LOperand* right = exponent_type.IsDouble() ? LOperand* right = exponent_type.IsDouble() ?
UseFixedDouble(instr->right(), f4) : UseFixedDouble(instr->right(), f4) :
UseFixed(instr->right(), a0); UseFixed(instr->right(), a2);
LPower* result = new LPower(left, right); LPower* result = new LPower(left, right);
return MarkAsCall(DefineFixedDouble(result, f6), return MarkAsCall(DefineFixedDouble(result, f0),
instr, instr,
CAN_DEOPTIMIZE_EAGERLY); CAN_DEOPTIMIZE_EAGERLY);
} }