Bug 1184959 part 2 - ARM ABIArgGenerator: Add support for soft-fp. r=h4writer

This commit is contained in:
Nicolas B. Pierron 2015-08-17 11:32:15 +02:00
parent 58c3e4a6fe
commit a98bebcec7
5 changed files with 131 additions and 8 deletions

View File

@ -10987,6 +10987,11 @@ GenerateEntry(ModuleCompiler& m, unsigned exportIndex)
case ABIArg::GPR:
masm.load32(src, iter->gpr());
break;
#ifdef JS_CODEGEN_REGISTER_PAIR
case ABIArg::GPR_PAIR:
MOZ_CRASH("AsmJS uses hardfp for function calls.");
break;
#endif
case ABIArg::FPU: {
static_assert(sizeof(AsmJSModule::EntryArg) >= jit::Simd128DataSize,
"EntryArg must be big enough to store SIMD values");
@ -11099,6 +11104,11 @@ FillArgumentArray(ModuleCompiler& m, const VarTypeVector& argTypes,
case ABIArg::GPR:
masm.storeValue(JSVAL_TYPE_INT32, i->gpr(), dstAddr);
break;
#ifdef JS_CODEGEN_REGISTER_PAIR
case ABIArg::GPR_PAIR:
MOZ_CRASH("AsmJS uses hardfp for function calls.");
break;
#endif
case ABIArg::FPU:
masm.canonicalizeDouble(i->fpu());
masm.storeDouble(i->fpu(), dstAddr);

View File

@ -1220,7 +1220,14 @@ class AnyRegisterIterator
class ABIArg
{
public:
enum Kind { GPR, FPU, Stack };
enum Kind {
GPR,
#ifdef JS_CODEGEN_REGISTER_PAIR
GPR_PAIR,
#endif
FPU,
Stack
};
private:
Kind kind_;
@ -1233,11 +1240,39 @@ class ABIArg
public:
ABIArg() : kind_(Kind(-1)) { u.offset_ = -1; }
explicit ABIArg(Register gpr) : kind_(GPR) { u.gpr_ = gpr.code(); }
explicit ABIArg(Register gprLow, Register gprHigh)
{
#if defined(JS_CODEGEN_REGISTER_PAIR)
kind_ = GPR_PAIR;
#else
MOZ_CRASH("Unsupported type of ABI argument.");
#endif
u.gpr_ = gprLow.code();
MOZ_ASSERT(u.gpr_ % 2 == 0);
MOZ_ASSERT(u.gpr_ + 1 == gprHigh.code());
}
explicit ABIArg(FloatRegister fpu) : kind_(FPU) { u.fpu_ = fpu.code(); }
explicit ABIArg(uint32_t offset) : kind_(Stack) { u.offset_ = offset; }
Kind kind() const { return kind_; }
Register gpr() const { MOZ_ASSERT(kind() == GPR); return Register::FromCode(u.gpr_); }
#ifdef JS_CODEGEN_REGISTER_PAIR
bool isGeneralRegPair() const { return kind_ == GPR_PAIR; }
#else
bool isGeneralRegPair() const { return false; }
#endif
Register gpr() const {
MOZ_ASSERT(kind() == GPR);
return Register::FromCode(u.gpr_);
}
Register evenGpr() const {
MOZ_ASSERT(isGeneralRegPair());
return Register::FromCode(u.gpr_);
}
Register oddGpr() const {
MOZ_ASSERT(isGeneralRegPair());
return Register::FromCode(u.gpr_ + 1);
}
FloatRegister fpu() const { MOZ_ASSERT(kind() == FPU); return FloatRegister::FromCode(u.fpu_); }
uint32_t offsetFromArgBase() const { MOZ_ASSERT(kind() == Stack); return u.offset_; }

View File

@ -639,6 +639,10 @@ static inline bool UseHardFpABI()
}
#endif
// In order to handle SoftFp ABI calls, we need to be able to express that we
// have ABIArg which are represented by pair of general purpose registers.
#define JS_CODEGEN_REGISTER_PAIR 1
// See the comments above AsmJSMappedSize in AsmJSValidate.h for more info.
// TODO: Implement this for ARM. Note that it requires Codegen to respect the
// offset field of AsmJSHeapAccess.

View File

@ -24,17 +24,67 @@ using mozilla::CountLeadingZeroes32;
void dbg_break() {}
// Note this is used for inter-AsmJS calls and may pass arguments and results in
// floating point registers even if the system ABI does not.
// The ABIArgGenerator is used for making system ABI calls and for inter-AsmJS
// calls. The system ABI can either be SoftFp or HardFp, and inter-AsmJS calls
// are always HardFp calls. The initialization defaults to HardFp, and the ABI
// choice is made before any system ABI calls with the method "setUseHardFp".
ABIArgGenerator::ABIArgGenerator()
: intRegIndex_(0),
floatRegIndex_(0),
stackOffset_(0),
current_()
current_(),
useHardFp_(true)
{ }
// See the "Parameter Passing" section of the "Procedure Call Standard for the
// ARM Architecture" documentation.
ABIArg
ABIArgGenerator::next(MIRType type)
ABIArgGenerator::softNext(MIRType type)
{
switch (type) {
case MIRType_Int32:
case MIRType_Pointer:
if (intRegIndex_ == NumIntArgRegs) {
current_ = ABIArg(stackOffset_);
stackOffset_ += sizeof(uint32_t);
break;
}
current_ = ABIArg(Register::FromCode(intRegIndex_));
intRegIndex_++;
break;
case MIRType_Float32:
if (intRegIndex_ == NumIntArgRegs) {
current_ = ABIArg(stackOffset_);
stackOffset_ += sizeof(uint32_t);
break;
}
current_ = ABIArg(Register::FromCode(intRegIndex_));
intRegIndex_++;
break;
case MIRType_Double:
// Make sure to use an even register index. Increase to next even number
// when odd.
intRegIndex_ = (intRegIndex_ + 1) & ~1;
if (intRegIndex_ == NumIntArgRegs) {
// Align the stack on 8 bytes.
static const int align = sizeof(double) - 1;
stackOffset_ = (stackOffset_ + align) & ~align;
current_ = ABIArg(stackOffset_);
stackOffset_ += sizeof(double);
break;
}
current_ = ABIArg(Register::FromCode(intRegIndex_), Register::FromCode(intRegIndex_ + 1));
intRegIndex_ += 2;
break;
default:
MOZ_CRASH("Unexpected argument type");
}
return current_;
}
ABIArg
ABIArgGenerator::hardNext(MIRType type)
{
switch (type) {
case MIRType_Int32:
@ -59,7 +109,9 @@ ABIArgGenerator::next(MIRType type)
floatRegIndex_++;
break;
case MIRType_Double:
// Bump the number of used registers up to the next multiple of two.
// Double register are composed of 2 float registers, thus we have to
// skip any float register which cannot be used in a pair of float
// registers in which a double value can be stored.
floatRegIndex_ = (floatRegIndex_ + 1) & ~1;
if (floatRegIndex_ == NumFloatArgRegs) {
static const int align = sizeof(double) - 1;
@ -69,7 +121,7 @@ ABIArgGenerator::next(MIRType type)
break;
}
current_ = ABIArg(VFPRegister(floatRegIndex_ >> 1, VFPRegister::Double));
floatRegIndex_+=2;
floatRegIndex_ += 2;
break;
default:
MOZ_CRASH("Unexpected argument type");
@ -78,6 +130,14 @@ ABIArgGenerator::next(MIRType type)
return current_;
}
ABIArg
ABIArgGenerator::next(MIRType type)
{
if (useHardFp_)
return hardNext(type);
return softNext(type);
}
const Register ABIArgGenerator::NonArgReturnReg0 = r4;
const Register ABIArgGenerator::NonArgReturnReg1 = r5;
const Register ABIArgGenerator::NonReturn_VolatileReg0 = r2;

View File

@ -72,9 +72,23 @@ class ABIArgGenerator
uint32_t stackOffset_;
ABIArg current_;
// ARM can either use HardFp (use float registers for float arguments), or
// SoftFp (use general registers for float arguments) ABI. We keep this
// switch as a runtime switch because AsmJS always use the HardFp back-end
// while the calls to native functions have to use the one provided by the
// system.
bool useHardFp_;
ABIArg softNext(MIRType argType);
ABIArg hardNext(MIRType argType);
public:
ABIArgGenerator();
void setUseHardFp(bool useHardFp) {
MOZ_ASSERT(intRegIndex_ == 0 && floatRegIndex_ == 0);
useHardFp_ = useHardFp;
}
ABIArg next(MIRType argType);
ABIArg& current() { return current_; }
uint32_t stackBytesConsumedSoFar() const { return stackOffset_; }