| Index: src/arm/simulator-arm.cc
|
| diff --git a/src/arm/simulator-arm.cc b/src/arm/simulator-arm.cc
|
| index 1f55f73a0203fd3c33c5e7ca069e16378523241c..801b63f44e7608b9f092bd14d4acc715a215deda 100644
|
| --- a/src/arm/simulator-arm.cc
|
| +++ b/src/arm/simulator-arm.cc
|
| @@ -1009,26 +1009,74 @@ double Simulator::get_double_from_d_register(int dreg) {
|
| }
|
|
|
|
|
| -// For use in calls that take two double values, constructed from r0, r1, r2
|
| -// and r3.
|
| +// For use in calls that take two double values, constructed either
|
| +// from r0-r3 or d0 and d1.
|
| void Simulator::GetFpArgs(double* x, double* y) {
|
| - // We use a char buffer to get around the strict-aliasing rules which
|
| - // otherwise allow the compiler to optimize away the copy.
|
| - char buffer[2 * sizeof(registers_[0])];
|
| - // Registers 0 and 1 -> x.
|
| - memcpy(buffer, registers_, sizeof(buffer));
|
| - memcpy(x, buffer, sizeof(buffer));
|
| - // Registers 2 and 3 -> y.
|
| - memcpy(buffer, registers_ + 2, sizeof(buffer));
|
| - memcpy(y, buffer, sizeof(buffer));
|
| + if (FLAG_hardfloat) {
|
| + *x = vfp_register[0];
|
| + *y = vfp_register[1];
|
| + } else {
|
| + // We use a char buffer to get around the strict-aliasing rules which
|
| + // otherwise allow the compiler to optimize away the copy.
|
| + char buffer[2 * sizeof(registers_[0])];
|
| + // Registers 0 and 1 -> x.
|
| + memcpy(buffer, registers_, sizeof(buffer));
|
| + memcpy(x, buffer, sizeof(buffer));
|
| + // Registers 2 and 3 -> y.
|
| + memcpy(buffer, registers_ + 2, sizeof(buffer));
|
| + memcpy(y, buffer, sizeof(buffer));
|
| + }
|
| +}
|
| +
|
| +// For use in calls that take one double value, constructed either
|
| +// from r0 and r1 or d0.
|
| +void Simulator::GetFpArgs(double* x) {
|
| + if (FLAG_hardfloat) {
|
| + *x = vfp_register[0];
|
| + } else {
|
| + // We use a char buffer to get around the strict-aliasing rules which
|
| + // otherwise allow the compiler to optimize away the copy.
|
| + char buffer[2 * sizeof(registers_[0])];
|
| + // Registers 0 and 1 -> x.
|
| + memcpy(buffer, registers_, sizeof(buffer));
|
| + memcpy(x, buffer, sizeof(buffer));
|
| + }
|
| +}
|
| +
|
| +
|
| +// For use in calls that take two double values, constructed either
|
| +// from r0-r3 or d0 and d1.
|
| +void Simulator::GetFpArgs(double* x, int32_t* y) {
|
| + if (FLAG_hardfloat) {
|
| + *x = vfp_register[0];
|
| + *y = registers_[1];
|
| + } else {
|
| + // We use a char buffer to get around the strict-aliasing rules which
|
| + // otherwise allow the compiler to optimize away the copy.
|
| + char buffer[2 * sizeof(registers_[0])];
|
| + // Registers 0 and 1 -> x.
|
| + memcpy(buffer, registers_, sizeof(buffer));
|
| + memcpy(x, buffer, sizeof(buffer));
|
| + // Registers 2 and 3 -> y.
|
| + memcpy(buffer, registers_ + 2, sizeof(buffer));
|
| + memcpy(y, buffer, sizeof(buffer));
|
| + }
|
| }
|
|
|
|
|
| +// The return value is either in r0/r1 or d0.
|
| void Simulator::SetFpResult(const double& result) {
|
| - char buffer[2 * sizeof(registers_[0])];
|
| - memcpy(buffer, &result, sizeof(buffer));
|
| - // result -> registers 0 and 1.
|
| - memcpy(registers_, buffer, sizeof(buffer));
|
| + if (FLAG_hardfloat) {
|
| + char buffer[2 * sizeof(vfp_register[0])];
|
| + memcpy(buffer, &result, sizeof(buffer));
|
| + // Copy result to d0.
|
| + memcpy(vfp_register, buffer, sizeof(buffer));
|
| + } else {
|
| + char buffer[2 * sizeof(registers_[0])];
|
| + memcpy(buffer, &result, sizeof(buffer));
|
| + // Copy result to r0 and r1.
|
| + memcpy(registers_, buffer, sizeof(buffer));
|
| + }
|
| }
|
|
|
|
|
| @@ -1685,19 +1733,69 @@ void Simulator::SoftwareInterrupt(Instruction* instr) {
|
| int32_t* stack_pointer = reinterpret_cast<int32_t*>(get_register(sp));
|
| int32_t arg4 = stack_pointer[0];
|
| int32_t arg5 = stack_pointer[1];
|
| + bool fp_call =
|
| + (redirection->type() == ExternalReference::BUILTIN_FP_FP_CALL) ||
|
| + (redirection->type() == ExternalReference::BUILTIN_COMPARE_CALL) ||
|
| + (redirection->type() == ExternalReference::BUILTIN_FP_CALL) ||
|
| + (redirection->type() == ExternalReference::BUILTIN_FP_INT_CALL);
|
| + if (FLAG_hardfloat) {
|
| + // With the hard floating point calling convention, double
|
| + // arguments are passed in VFP registers. Fetch the arguments
|
| + // from there and call the builtin using soft floating point
|
| + // convention.
|
| + switch (redirection->type()) {
|
| + case ExternalReference::BUILTIN_FP_FP_CALL:
|
| + case ExternalReference::BUILTIN_COMPARE_CALL:
|
| + arg0 = vfp_register[0];
|
| + arg1 = vfp_register[1];
|
| + arg2 = vfp_register[2];
|
| + arg3 = vfp_register[3];
|
| + break;
|
| + case ExternalReference::BUILTIN_FP_CALL:
|
| + arg0 = vfp_register[0];
|
| + arg1 = vfp_register[1];
|
| + break;
|
| + case ExternalReference::BUILTIN_FP_INT_CALL:
|
| + arg0 = vfp_register[0];
|
| + arg1 = vfp_register[1];
|
| + arg2 = get_register(0);
|
| + break;
|
| + default:
|
| + break;
|
| + }
|
| + }
|
| // This is dodgy but it works because the C entry stubs are never moved.
|
| // See comment in codegen-arm.cc and bug 1242173.
|
| int32_t saved_lr = get_register(lr);
|
| intptr_t external =
|
| reinterpret_cast<intptr_t>(redirection->external_function());
|
| - if (redirection->type() == ExternalReference::FP_RETURN_CALL) {
|
| + if (fp_call) {
|
| SimulatorRuntimeFPCall target =
|
| reinterpret_cast<SimulatorRuntimeFPCall>(external);
|
| if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
|
| - double x, y;
|
| - GetFpArgs(&x, &y);
|
| - PrintF("Call to host function at %p with args %f, %f",
|
| - FUNCTION_ADDR(target), x, y);
|
| + double dval0, dval1;
|
| + int32_t ival;
|
| + switch (redirection->type()) {
|
| + case ExternalReference::BUILTIN_FP_FP_CALL:
|
| + case ExternalReference::BUILTIN_COMPARE_CALL:
|
| + GetFpArgs(&dval0, &dval1);
|
| + PrintF("Call to host function at %p with args %f, %f",
|
| + FUNCTION_ADDR(target), dval0, dval1);
|
| + break;
|
| + case ExternalReference::BUILTIN_FP_CALL:
|
| + GetFpArgs(&dval0);
|
| + PrintF("Call to host function at %p with arg %f",
|
| + FUNCTION_ADDR(target), dval1);
|
| + break;
|
| + case ExternalReference::BUILTIN_FP_INT_CALL:
|
| + GetFpArgs(&dval0, &ival);
|
| + PrintF("Call to host function at %p with args %f, %d",
|
| + FUNCTION_ADDR(target), dval0, ival);
|
| + break;
|
| + default:
|
| + UNREACHABLE();
|
| + break;
|
| + }
|
| if (!stack_aligned) {
|
| PrintF(" with unaligned stack %08x\n", get_register(sp));
|
| }
|
| @@ -1705,7 +1803,9 @@ void Simulator::SoftwareInterrupt(Instruction* instr) {
|
| }
|
| CHECK(stack_aligned);
|
| double result = target(arg0, arg1, arg2, arg3);
|
| - SetFpResult(result);
|
| + if (redirection->type() != ExternalReference::BUILTIN_COMPARE_CALL) {
|
| + SetFpResult(result);
|
| + }
|
| } else if (redirection->type() == ExternalReference::DIRECT_API_CALL) {
|
| SimulatorRuntimeDirectApiCall target =
|
| reinterpret_cast<SimulatorRuntimeDirectApiCall>(external);
|
|
|