Reviewers: Søren Gjesse,
Description:
ARM: Implement DoPower in the lithium code generator.
Please review this at http://codereview.chromium.org/6532020/
SVN Base: https://v8.googlecode.com/svn/branches/bleeding_edge/src
Affected files:
M src/arm/lithium-arm.h
M src/arm/lithium-arm.cc
M src/arm/lithium-codegen-arm.cc
M src/arm/simulator-arm.cc
M src/assembler.cc
Index: src/arm/lithium-arm.cc
diff --git a/src/arm/lithium-arm.cc b/src/arm/lithium-arm.cc
index
786ceeb3cac0b52afa0500645679d174ee08ca5d..1278e98f327451bc672141275973272cfd3df277
100644
--- a/src/arm/lithium-arm.cc
+++ b/src/arm/lithium-arm.cc
@@ -1418,8 +1418,18 @@ LInstruction* LChunkBuilder::DoAdd(HAdd* instr) {
LInstruction* LChunkBuilder::DoPower(HPower* instr) {
- Abort("LPower instruction not implemented on ARM");
- return NULL;
+ ASSERT(instr->representation().IsDouble());
+ // We call a C function for double power. It can't trigger a GC.
+ // We need to use fixed result register for the call.
+ Representation exponent_type = instr->right()->representation();
+ ASSERT(instr->left()->representation().IsDouble());
+ LOperand* left = UseFixedDouble(instr->left(), d1);
+ LOperand* right = exponent_type.IsDouble() ?
+ UseFixedDouble(instr->right(), d2) :
+ UseFixed(instr->right(), r0);
+ LPower* result = new LPower(left, right);
+ return MarkAsCall(DefineFixedDouble(result, d3), instr,
+ CAN_DEOPTIMIZE_EAGERLY);
}
Index: src/arm/lithium-arm.h
diff --git a/src/arm/lithium-arm.h b/src/arm/lithium-arm.h
index
57338f16d5557cca4f7d8fe08fd6d29bca805b1e..bd625aa56046207fa6a9289686fc81cb3c682ca4
100644
--- a/src/arm/lithium-arm.h
+++ b/src/arm/lithium-arm.h
@@ -135,6 +135,7 @@ class LCodeGen;
V(OuterContext) \
V(Parameter) \
V(PixelArrayLength) \
+ V(Power) \
V(PushArgument) \
V(RegExpLiteral) \
V(Return) \
@@ -1058,6 +1059,18 @@ class LAddI: public LTemplateInstruction<1, 2, 0> {
};
+class LPower: public LTemplateInstruction<1, 2, 0> {
+ public:
+ LPower(LOperand* left, LOperand* right) {
+ inputs_[0] = left;
+ inputs_[1] = right;
+ }
+
+ DECLARE_CONCRETE_INSTRUCTION(Power, "power")
+ DECLARE_HYDROGEN_ACCESSOR(Power)
+};
+
+
class LArithmeticD: public LTemplateInstruction<1, 2, 0> {
public:
LArithmeticD(Token::Value op, LOperand* left, LOperand* right)
Index: src/arm/lithium-codegen-arm.cc
diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc
index
2c916f6ad67b847376a3656a5189f25d1cb0c18c..02e22b22e6acac2570b3df9fa5fe8791b875747c
100644
--- a/src/arm/lithium-codegen-arm.cc
+++ b/src/arm/lithium-codegen-arm.cc
@@ -2861,6 +2861,70 @@ void LCodeGen::DoMathSqrt(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()) {
+ // Save r0-r3 on the stack, prepare arguments and call C function.
+ __ stm(db_w, sp, r0.bit() | r1.bit() | r2.bit() | r3.bit());
+ __ PrepareCallCFunction(4, scratch);
+ __ vmov(r0, r1, ToDoubleRegister(left));
+ __ vmov(r2, r3, ToDoubleRegister(right));
+ __ CallCFunction(ExternalReference::power_double_double_function(), 4);
+ } else if (exponent_type.IsInteger32()) {
+ ASSERT(ToRegister(right).is(r0));
+ // Save r0-r3 on the stack, prepare arguments and call C function.
+ __ stm(db_w, sp, r0.bit() | r1.bit() | r2.bit() | r3.bit());
+ __ PrepareCallCFunction(4, scratch);
+ __ mov(r2, ToRegister(right));
+ __ vmov(r0, r1, ToDoubleRegister(left));
+ __ CallCFunction(ExternalReference::power_double_int_function(), 4);
+ } else {
+ ASSERT(exponent_type.IsTagged());
+ ASSERT(instr->hydrogen()->left()->representation().IsDouble());
+ ASSERT(CpuFeatures::IsSupported(VFP3));
+
+ Register right_reg = ToRegister(right);
+
+ // Check for smi on the right hand side.
+ Label non_smi, call;
+ __ tst(right_reg, Operand(kSmiTagMask));
+ __ b(ne, &non_smi);
+
+ // Untag smi and convert it to a double.
+ __ SmiUntag(right_reg);
+ SwVfpRegister single_scratch = double_scratch0().low();
+ __ vmov(single_scratch, right_reg);
+ __ vcvt_f64_s32(result_reg, single_scratch);
+ __ jmp(&call);
+
+ // Heap number map check.
+ __ bind(&non_smi);
+ __ ldr(scratch, FieldMemOperand(right_reg, HeapObject::kMapOffset));
+ __ LoadRoot(ip, Heap::kHeapNumberMapRootIndex);
+ __ cmp(scratch, Operand(ip));
+ DeoptimizeIf(ne, instr->environment());
+ int32_t value_offset = HeapNumber::kValueOffset - kHeapObjectTag;
+ __ add(scratch, right_reg, Operand(value_offset), LeaveCC);
+ __ vldr(result_reg, scratch, 0);
+
+ // Save r0-r3 on the stack, prepare arguments and call C function.
+ __ bind(&call);
+ __ stm(db_w, sp, r0.bit() | r1.bit() | r2.bit() | r3.bit());
+ __ PrepareCallCFunction(4, scratch);
+ __ vmov(r0, r1, ToDoubleRegister(left));
+ __ vmov(r2, r3, result_reg);
+ __ CallCFunction(ExternalReference::power_double_double_function(), 4);
+ }
+ // Store the result in the result register and restore r0-r3.
+ __ vmov(result_reg, r0, r1);
+ __ ldm(ia_w, sp, r0.bit() | r1.bit() | r2.bit() | r3.bit());
+}
+
+
void LCodeGen::DoUnaryMathOperation(LUnaryMathOperation* instr) {
switch (instr->op()) {
case kMathAbs:
Index: src/arm/simulator-arm.cc
diff --git a/src/arm/simulator-arm.cc b/src/arm/simulator-arm.cc
index
8104747f14d49d861d86f97b5550c66e512a9a70..e96c05307f17d522fb3f66f8ab7e115dca907870
100644
--- a/src/arm/simulator-arm.cc
+++ b/src/arm/simulator-arm.cc
@@ -316,7 +316,7 @@ void Debugger::Debug() {
}
for (int i = 0; i < kNumVFPDoubleRegisters; i++) {
dvalue = GetVFPDoubleRegisterValue(i);
- PrintF("%3s: %f\n",
+ PrintF("%3s: %f \n",
VFPRegisters::Name(i, true), dvalue);
}
} else {
Index: src/assembler.cc
diff --git a/src/assembler.cc b/src/assembler.cc
index
42a61c2b8d0656cbcafe10167a4873d0df07821a..8094997b03d96fd87012fcb752d2fdf32c599ce1
100644
--- a/src/assembler.cc
+++ b/src/assembler.cc
@@ -850,12 +850,14 @@ double power_double_double(double x, double y) {
ExternalReference ExternalReference::power_double_double_function() {
- return ExternalReference(Redirect(FUNCTION_ADDR(power_double_double)));
+ return ExternalReference(Redirect(FUNCTION_ADDR(power_double_double),
+ FP_RETURN_CALL));
}
ExternalReference ExternalReference::power_double_int_function() {
- return ExternalReference(Redirect(FUNCTION_ADDR(power_double_int)));
+ return ExternalReference(Redirect(FUNCTION_ADDR(power_double_int),
+ FP_RETURN_CALL));
}
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev