diff --git a/src/arm/lithium-arm.cc b/src/arm/lithium-arm.cc index 033042c1b9..7847a5b2a9 100644 --- a/src/arm/lithium-arm.cc +++ b/src/arm/lithium-arm.cc @@ -1417,8 +1417,19 @@ 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); } diff --git a/src/arm/lithium-arm.h b/src/arm/lithium-arm.h index 57338f16d5..bd625aa560 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) diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc index e544d28eba..94f5116415 100644 --- a/src/arm/lithium-codegen-arm.cc +++ b/src/arm/lithium-codegen-arm.cc @@ -1226,7 +1226,7 @@ void LCodeGen::DoArithmeticD(LArithmeticD* instr) { __ vmov(r2, r3, right); __ CallCFunction(ExternalReference::double_fp_operation(Token::MOD), 4); // Move the result in the double result register. - __ vmov(ToDoubleRegister(instr->result()), r0, r1); + __ GetCFunctionDoubleResult(ToDoubleRegister(instr->result())); // Restore r0-r3. __ ldm(ia_w, sp, r0.bit() | r1.bit() | r2.bit() | r3.bit()); @@ -2684,6 +2684,64 @@ 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()) { + // Prepare arguments and call C function. + __ 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)); + // Prepare arguments and call C function. + __ 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()); + + 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); + 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)); + __ vldr(result_reg, scratch, 0); + + // Prepare arguments and call C function. + __ bind(&call); + __ 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. + __ GetCFunctionDoubleResult(result_reg); +} + + void LCodeGen::DoUnaryMathOperation(LUnaryMathOperation* instr) { switch (instr->op()) { case kMathAbs: diff --git a/src/arm/macro-assembler-arm.cc b/src/arm/macro-assembler-arm.cc index aa5822fa54..4abf02b797 100644 --- a/src/arm/macro-assembler-arm.cc +++ b/src/arm/macro-assembler-arm.cc @@ -746,6 +746,14 @@ void MacroAssembler::LeaveExitFrame(bool save_doubles, } } +void MacroAssembler::GetCFunctionDoubleResult(const DoubleRegister dst) { +#if !defined(USE_ARM_EABI) + UNREACHABLE(); +#else + vmov(dst, r0, r1); +#endif +} + void MacroAssembler::InvokePrologue(const ParameterCount& expected, const ParameterCount& actual, diff --git a/src/arm/macro-assembler-arm.h b/src/arm/macro-assembler-arm.h index 06709f4354..83c59a6f65 100644 --- a/src/arm/macro-assembler-arm.h +++ b/src/arm/macro-assembler-arm.h @@ -684,6 +684,8 @@ class MacroAssembler: public Assembler { void CallCFunction(ExternalReference function, int num_arguments); void CallCFunction(Register function, int num_arguments); + void GetCFunctionDoubleResult(const DoubleRegister dst); + // Calls an API function. Allocates HandleScope, extracts returned value // from handle and propagates exceptions. Restores context. // stack_space - space to be unwound on exit (includes the call js diff --git a/src/assembler.cc b/src/assembler.cc index 893ce56159..a323ecaa44 100644 --- a/src/assembler.cc +++ b/src/assembler.cc @@ -852,12 +852,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)); } diff --git a/src/v8.cc b/src/v8.cc index 0ff7649340..945043da9b 100644 --- a/src/v8.cc +++ b/src/v8.cc @@ -54,7 +54,12 @@ bool V8::Initialize(Deserializer* des) { if (has_been_disposed_ || has_fatal_error_) return false; if (IsRunning()) return true; +#if defined(V8_TARGET_ARCH_ARM) && !defined(USE_ARM_EABI) + use_crankshaft_ = false; +#else use_crankshaft_ = FLAG_crankshaft; +#endif + // Peephole optimization might interfere with deoptimization. FLAG_peephole_optimization = !use_crankshaft_; is_running_ = true;