| Index: src/arm/codegen-arm.cc
|
| diff --git a/src/arm/codegen-arm.cc b/src/arm/codegen-arm.cc
|
| index a7b38ffee64e637a82f051c940c02f79c653933d..4014aba10ebc902bb6855635453f38d3300c6f00 100644
|
| --- a/src/arm/codegen-arm.cc
|
| +++ b/src/arm/codegen-arm.cc
|
| @@ -15,6 +15,68 @@
|
|
|
|
|
| #define __ masm.
|
| +
|
| +
|
| +#if defined(USE_SIMULATOR)
|
| +byte* fast_exp_arm_machine_code = nullptr;
|
| +double fast_exp_simulator(double x, Isolate* isolate) {
|
| + return Simulator::current(isolate)
|
| + ->CallFPReturnsDouble(fast_exp_arm_machine_code, x, 0);
|
| +}
|
| +#endif
|
| +
|
| +
|
| +UnaryMathFunctionWithIsolate CreateExpFunction(Isolate* isolate) {
|
| + size_t actual_size;
|
| + byte* buffer =
|
| + static_cast<byte*>(base::OS::Allocate(1 * KB, &actual_size, true));
|
| + if (buffer == nullptr) return nullptr;
|
| + ExternalReference::InitializeMathExpData();
|
| +
|
| + MacroAssembler masm(isolate, buffer, static_cast<int>(actual_size),
|
| + CodeObjectRequired::kNo);
|
| +
|
| + {
|
| + DwVfpRegister input = d0;
|
| + DwVfpRegister result = d1;
|
| + DwVfpRegister double_scratch1 = d2;
|
| + DwVfpRegister double_scratch2 = d3;
|
| + Register temp1 = r4;
|
| + Register temp2 = r5;
|
| + Register temp3 = r6;
|
| +
|
| + if (masm.use_eabi_hardfloat()) {
|
| + // Input value is in d0 anyway, nothing to do.
|
| + } else {
|
| + __ vmov(input, r0, r1);
|
| + }
|
| + __ Push(temp3, temp2, temp1);
|
| + MathExpGenerator::EmitMathExp(
|
| + &masm, input, result, double_scratch1, double_scratch2,
|
| + temp1, temp2, temp3);
|
| + __ Pop(temp3, temp2, temp1);
|
| + if (masm.use_eabi_hardfloat()) {
|
| + __ vmov(d0, result);
|
| + } else {
|
| + __ vmov(r0, r1, result);
|
| + }
|
| + __ Ret();
|
| + }
|
| +
|
| + CodeDesc desc;
|
| + masm.GetCode(&desc);
|
| + DCHECK(!RelocInfo::RequiresRelocation(desc));
|
| +
|
| + Assembler::FlushICache(isolate, buffer, actual_size);
|
| + base::OS::ProtectCode(buffer, actual_size);
|
| +
|
| +#if !defined(USE_SIMULATOR)
|
| + return FUNCTION_CAST<UnaryMathFunctionWithIsolate>(buffer);
|
| +#else
|
| + fast_exp_arm_machine_code = buffer;
|
| + return &fast_exp_simulator;
|
| +#endif
|
| +}
|
|
|
| #if defined(V8_HOST_ARCH_ARM)
|
| MemCopyUint8Function CreateMemCopyUint8Function(Isolate* isolate,
|
| @@ -732,6 +794,94 @@
|
| __ bind(&done);
|
| }
|
|
|
| +
|
| +static MemOperand ExpConstant(int index, Register base) {
|
| + return MemOperand(base, index * kDoubleSize);
|
| +}
|
| +
|
| +
|
| +void MathExpGenerator::EmitMathExp(MacroAssembler* masm,
|
| + DwVfpRegister input,
|
| + DwVfpRegister result,
|
| + DwVfpRegister double_scratch1,
|
| + DwVfpRegister double_scratch2,
|
| + Register temp1,
|
| + Register temp2,
|
| + Register temp3) {
|
| + DCHECK(!input.is(result));
|
| + DCHECK(!input.is(double_scratch1));
|
| + DCHECK(!input.is(double_scratch2));
|
| + DCHECK(!result.is(double_scratch1));
|
| + DCHECK(!result.is(double_scratch2));
|
| + DCHECK(!double_scratch1.is(double_scratch2));
|
| + DCHECK(!temp1.is(temp2));
|
| + DCHECK(!temp1.is(temp3));
|
| + DCHECK(!temp2.is(temp3));
|
| + DCHECK(ExternalReference::math_exp_constants(0).address() != NULL);
|
| + DCHECK(!masm->serializer_enabled()); // External references not serializable.
|
| +
|
| + Label zero, infinity, done;
|
| +
|
| + __ mov(temp3, Operand(ExternalReference::math_exp_constants(0)));
|
| +
|
| + __ vldr(double_scratch1, ExpConstant(0, temp3));
|
| + __ VFPCompareAndSetFlags(double_scratch1, input);
|
| + __ b(ge, &zero);
|
| +
|
| + __ vldr(double_scratch2, ExpConstant(1, temp3));
|
| + __ VFPCompareAndSetFlags(input, double_scratch2);
|
| + __ b(ge, &infinity);
|
| +
|
| + __ vldr(double_scratch1, ExpConstant(3, temp3));
|
| + __ vldr(result, ExpConstant(4, temp3));
|
| + __ vmul(double_scratch1, double_scratch1, input);
|
| + __ vadd(double_scratch1, double_scratch1, result);
|
| + __ VmovLow(temp2, double_scratch1);
|
| + __ vsub(double_scratch1, double_scratch1, result);
|
| + __ vldr(result, ExpConstant(6, temp3));
|
| + __ vldr(double_scratch2, ExpConstant(5, temp3));
|
| + __ vmul(double_scratch1, double_scratch1, double_scratch2);
|
| + __ vsub(double_scratch1, double_scratch1, input);
|
| + __ vsub(result, result, double_scratch1);
|
| + __ vmul(double_scratch2, double_scratch1, double_scratch1);
|
| + __ vmul(result, result, double_scratch2);
|
| + __ vldr(double_scratch2, ExpConstant(7, temp3));
|
| + __ vmul(result, result, double_scratch2);
|
| + __ vsub(result, result, double_scratch1);
|
| + // Mov 1 in double_scratch2 as math_exp_constants_array[8] == 1.
|
| + DCHECK(*reinterpret_cast<double*>
|
| + (ExternalReference::math_exp_constants(8).address()) == 1);
|
| + __ vmov(double_scratch2, 1);
|
| + __ vadd(result, result, double_scratch2);
|
| + __ mov(temp1, Operand(temp2, LSR, 11));
|
| + __ Ubfx(temp2, temp2, 0, 11);
|
| + __ add(temp1, temp1, Operand(0x3ff));
|
| +
|
| + // Must not call ExpConstant() after overwriting temp3!
|
| + __ mov(temp3, Operand(ExternalReference::math_exp_log_table()));
|
| + __ add(temp3, temp3, Operand(temp2, LSL, 3));
|
| + __ ldm(ia, temp3, temp2.bit() | temp3.bit());
|
| + // The first word is loaded is the lower number register.
|
| + if (temp2.code() < temp3.code()) {
|
| + __ orr(temp1, temp3, Operand(temp1, LSL, 20));
|
| + __ vmov(double_scratch1, temp2, temp1);
|
| + } else {
|
| + __ orr(temp1, temp2, Operand(temp1, LSL, 20));
|
| + __ vmov(double_scratch1, temp3, temp1);
|
| + }
|
| + __ vmul(result, result, double_scratch1);
|
| + __ b(&done);
|
| +
|
| + __ bind(&zero);
|
| + __ vmov(result, kDoubleRegZero);
|
| + __ b(&done);
|
| +
|
| + __ bind(&infinity);
|
| + __ vldr(result, ExpConstant(2, temp3));
|
| +
|
| + __ bind(&done);
|
| +}
|
| +
|
| #undef __
|
|
|
| #ifdef DEBUG
|
|
|