Bug 965229 - ARM simulator: Scratch volatile registers across system ABI calls. r=nbp

This commit is contained in:
Douglas Crosher 2014-02-08 17:21:53 +11:00
parent 4c5e3939e4
commit 0bdc2c1945
2 changed files with 52 additions and 0 deletions

View File

@ -2043,6 +2043,35 @@ typedef double (*Prototype_Double_IntDouble)(int32_t arg0, double arg1);
typedef double (*Prototype_Double_DoubleDouble)(double arg0, double arg1);
typedef int32_t (*Prototype_Int_IntDouble)(int32_t arg0, double arg1);
// Fill the volatile registers with scratch values.
//
// Some of the ABI calls assume that the float registers are not scratched, even
// though the ABI defines them as volatile - a performance optimization. These are
// all calls passing operands in integer registers, so for now the simulator does not
// scratch any float registers for these calls. Should try to narrow it further in
// future.
//
void
Simulator::scratchVolatileRegisters(bool scratchFloat)
{
int32_t scratch_value = 0xa5a5a5a5 ^ uint32_t(icount_);
set_register(r0, scratch_value);
set_register(r1, scratch_value);
set_register(r2, scratch_value);
set_register(r3, scratch_value);
set_register(r12, scratch_value); // Intra-Procedure-call scratch register
set_register(r14, scratch_value); // Link register
if (scratchFloat) {
uint64_t scratch_value_d = 0x5a5a5a5a5a5a5a5aLU ^ uint64_t(icount_) ^ (uint64_t(icount_) << 30);
for (uint32_t i = d0; i < d8; i++)
set_d_register(i, &scratch_value_d);
for (uint32_t i = d16; i < FloatRegisters::Total; i++)
set_d_register(i, &scratch_value_d);
}
}
// Software interrupt instructions are used by the simulator to call into C++.
void
Simulator::softwareInterrupt(SimInstruction *instr)
@ -2072,42 +2101,53 @@ Simulator::softwareInterrupt(SimInstruction *instr)
case Args_General0: {
Prototype_General0 target = reinterpret_cast<Prototype_General0>(external);
int64_t result = target();
scratchVolatileRegisters(/* scratchFloat = true */);
setCallResult(result);
break;
}
case Args_General1: {
Prototype_General1 target = reinterpret_cast<Prototype_General1>(external);
int64_t result = target(arg0);
scratchVolatileRegisters(/* scratchFloat = true */);
setCallResult(result);
break;
}
case Args_General2: {
Prototype_General2 target = reinterpret_cast<Prototype_General2>(external);
int64_t result = target(arg0, arg1);
// The ARM backend makes calls to __aeabi_idivmod and __aeabi_uidivmod assuming
// that the float registers are non-volatile as a performance optimization, so the
// float registers must not be scratch when calling these.
bool scratchFloat = target != __aeabi_idivmod && target != __aeabi_uidivmod;
scratchVolatileRegisters(/* scratchFloat = */ scratchFloat);
setCallResult(result);
break;
}
case Args_General3: {
Prototype_General3 target = reinterpret_cast<Prototype_General3>(external);
int64_t result = target(arg0, arg1, arg2);
scratchVolatileRegisters(/* scratchFloat = true*/);
setCallResult(result);
break;
}
case Args_General4: {
Prototype_General4 target = reinterpret_cast<Prototype_General4>(external);
int64_t result = target(arg0, arg1, arg2, arg3);
scratchVolatileRegisters(/* scratchFloat = true*/);
setCallResult(result);
break;
}
case Args_General5: {
Prototype_General5 target = reinterpret_cast<Prototype_General5>(external);
int64_t result = target(arg0, arg1, arg2, arg3, arg4);
scratchVolatileRegisters(/* scratchFloat = true */);
setCallResult(result);
break;
}
case Args_General6: {
Prototype_General6 target = reinterpret_cast<Prototype_General6>(external);
int64_t result = target(arg0, arg1, arg2, arg3, arg4, arg5);
scratchVolatileRegisters(/* scratchFloat = true */);
setCallResult(result);
break;
}
@ -2115,6 +2155,7 @@ Simulator::softwareInterrupt(SimInstruction *instr)
Prototype_General7 target = reinterpret_cast<Prototype_General7>(external);
int32_t arg6 = stack_pointer[2];
int64_t result = target(arg0, arg1, arg2, arg3, arg4, arg5, arg6);
scratchVolatileRegisters(/* scratchFloat = true */);
setCallResult(result);
break;
}
@ -2123,12 +2164,14 @@ Simulator::softwareInterrupt(SimInstruction *instr)
int32_t arg6 = stack_pointer[2];
int32_t arg7 = stack_pointer[3];
int64_t result = target(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
scratchVolatileRegisters(/* scratchFloat = true */);
setCallResult(result);
break;
}
case Args_Double_None: {
Prototype_Double_None target = reinterpret_cast<Prototype_Double_None>(external);
double dresult = target();
scratchVolatileRegisters(/* scratchFloat = true */);
setCallResultDouble(dresult);
break;
}
@ -2138,6 +2181,7 @@ Simulator::softwareInterrupt(SimInstruction *instr)
getFpArgs(&dval0, &dval1, &ival);
Prototype_Int_Double target = reinterpret_cast<Prototype_Int_Double>(external);
int32_t res = target(dval0);
scratchVolatileRegisters(/* scratchFloat = true */);
set_register(r0, res);
break;
}
@ -2147,6 +2191,7 @@ Simulator::softwareInterrupt(SimInstruction *instr)
getFpArgs(&dval0, &dval1, &ival);
Prototype_Double_Double target = reinterpret_cast<Prototype_Double_Double>(external);
double dresult = target(dval0);
scratchVolatileRegisters(/* scratchFloat = true */);
setCallResultDouble(dresult);
break;
}
@ -2154,12 +2199,14 @@ Simulator::softwareInterrupt(SimInstruction *instr)
float fval0 = mozilla::BitwiseCast<float>(arg0);
Prototype_Float32_Float32 target = reinterpret_cast<Prototype_Float32_Float32>(external);
float fresult = target(fval0);
scratchVolatileRegisters(/* scratchFloat = true */);
setCallResultFloat(fresult);
break;
}
case Args_Double_Int: {
Prototype_Double_Int target = reinterpret_cast<Prototype_Double_Int>(external);
double dresult = target(arg0);
scratchVolatileRegisters(/* scratchFloat = true */);
setCallResultDouble(dresult);
break;
}
@ -2169,6 +2216,7 @@ Simulator::softwareInterrupt(SimInstruction *instr)
getFpArgs(&dval0, &dval1, &ival);
Prototype_DoubleInt target = reinterpret_cast<Prototype_DoubleInt>(external);
double dresult = target(dval0, ival);
scratchVolatileRegisters(/* scratchFloat = true */);
setCallResultDouble(dresult);
break;
}
@ -2178,6 +2226,7 @@ Simulator::softwareInterrupt(SimInstruction *instr)
getFpArgs(&dval0, &dval1, &ival);
Prototype_Double_DoubleDouble target = reinterpret_cast<Prototype_Double_DoubleDouble>(external);
double dresult = target(dval0, dval1);
scratchVolatileRegisters(/* scratchFloat = true */);
setCallResultDouble(dresult);
break;
}
@ -2187,6 +2236,7 @@ Simulator::softwareInterrupt(SimInstruction *instr)
double dval0 = get_double_from_register_pair(2);
Prototype_Double_IntDouble target = reinterpret_cast<Prototype_Double_IntDouble>(external);
double dresult = target(ival, dval0);
scratchVolatileRegisters(/* scratchFloat = true */);
setCallResultDouble(dresult);
break;
}
@ -2196,6 +2246,7 @@ Simulator::softwareInterrupt(SimInstruction *instr)
double dval0 = get_double_from_register_pair(2);
Prototype_Int_IntDouble target = reinterpret_cast<Prototype_Int_IntDouble>(external);
int32_t result = target(ival, dval0);
scratchVolatileRegisters(/* scratchFloat = true */);
set_register(r0, result);
break;
}

View File

@ -281,6 +281,7 @@ class Simulator
void setCallResultDouble(double result);
void setCallResultFloat(float result);
void setCallResult(int64_t res);
void scratchVolatileRegisters(bool scratchFloat = true);
template<class ReturnType, int register_size>
ReturnType getFromVFPRegister(int reg_index);