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:
parent
42a85ce584
commit
6fdf50c040
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user