diff --git a/js/src/jit/mips32/Architecture-mips32.h b/js/src/jit/mips32/Architecture-mips32.h index e2ddfdbd45d..dc00b8c43fd 100644 --- a/js/src/jit/mips32/Architecture-mips32.h +++ b/js/src/jit/mips32/Architecture-mips32.h @@ -534,6 +534,12 @@ hasMultiAlias() { return true; } +// In order to handle functions such as int(*)(int, double) where the first +// argument is a general purpose register, and the second argument is a floating +// point register, we have to store the double content into 2 general purpose +// registers, namely a2 and a3. +#define JS_CODEGEN_REGISTER_PAIR 1 + // See the comments above AsmJSMappedSize in AsmJSValidate.h for more info. // TODO: Implement this for MIPS. Note that it requires Codegen to respect the // offset field of AsmJSHeapAccess. diff --git a/js/src/jit/mips32/Assembler-mips32.cpp b/js/src/jit/mips32/Assembler-mips32.cpp index 6875ec6f377..cff988a8206 100644 --- a/js/src/jit/mips32/Assembler-mips32.cpp +++ b/js/src/jit/mips32/Assembler-mips32.cpp @@ -23,18 +23,18 @@ using namespace js::jit; ABIArgGenerator::ABIArgGenerator() : usedArgSlots_(0), - firstArgFloat(false), + firstArgFloatSize_(0), + useGPRForFloats_(false), current_() {} ABIArg ABIArgGenerator::next(MIRType type) { - FloatRegister::RegType regType; + Register destReg; switch (type) { case MIRType_Int32: case MIRType_Pointer: - Register destReg; if (GetIntArgReg(usedArgSlots_, &destReg)) current_ = ABIArg(destReg); else @@ -42,19 +42,34 @@ ABIArgGenerator::next(MIRType type) usedArgSlots_++; break; case MIRType_Float32: - case MIRType_Double: - regType = (type == MIRType_Double ? FloatRegister::Double : FloatRegister::Single); if (!usedArgSlots_) { - current_ = ABIArg(FloatRegister(FloatRegisters::f12, regType)); - usedArgSlots_ += 2; - firstArgFloat = true; - } else if (usedArgSlots_ <= 2) { - // NOTE: We will use f14 always. This is not compatible with - // system ABI. We will have to introduce some infrastructure - // changes if we have to use system ABI here. - current_ = ABIArg(FloatRegister(FloatRegisters::f14, regType)); + current_ = ABIArg(f12.asSingle()); + firstArgFloatSize_ = 1; + } else if (usedArgSlots_ == firstArgFloatSize_) { + current_ = ABIArg(f14.asSingle()); + } else if (useGPRForFloats_ && GetIntArgReg(usedArgSlots_, &destReg)) { + current_ = ABIArg(destReg); + } else { + if (usedArgSlots_ < NumIntArgRegs) + usedArgSlots_ = NumIntArgRegs; + current_ = ABIArg(usedArgSlots_ * sizeof(intptr_t)); + } + usedArgSlots_++; + break; + case MIRType_Double: + if (!usedArgSlots_) { + current_ = ABIArg(f12); + usedArgSlots_ = 2; + firstArgFloatSize_ = 2; + } else if (usedArgSlots_ == firstArgFloatSize_) { + current_ = ABIArg(f14); + usedArgSlots_ = 4; + } else if (useGPRForFloats_ && usedArgSlots_ <= 2) { + current_ = ABIArg(a2, a3); usedArgSlots_ = 4; } else { + if (usedArgSlots_ < NumIntArgRegs) + usedArgSlots_ = NumIntArgRegs; usedArgSlots_ += usedArgSlots_ % 2; current_ = ABIArg(usedArgSlots_ * sizeof(intptr_t)); usedArgSlots_ += 2; @@ -64,8 +79,8 @@ ABIArgGenerator::next(MIRType type) MOZ_CRASH("Unexpected argument type"); } return current_; - } + const Register ABIArgGenerator::NonArgReturnReg0 = t0; const Register ABIArgGenerator::NonArgReturnReg1 = t1; const Register ABIArgGenerator::NonArg_VolatileReg = v0; diff --git a/js/src/jit/mips32/Assembler-mips32.h b/js/src/jit/mips32/Assembler-mips32.h index 44f874d1fcb..7a25d1ead90 100644 --- a/js/src/jit/mips32/Assembler-mips32.h +++ b/js/src/jit/mips32/Assembler-mips32.h @@ -80,7 +80,10 @@ static const uint32_t NumCallTempNonArgRegs = mozilla::ArrayLength(CallTempNonAr class ABIArgGenerator { unsigned usedArgSlots_; - bool firstArgFloat; + unsigned firstArgFloatSize_; + // Note: This is not compliant with the system ABI. The Lowering phase + // expects to lower an MAsmJSParameter to only one register. + bool useGPRForFloats_; ABIArg current_; public: @@ -88,6 +91,10 @@ class ABIArgGenerator ABIArg next(MIRType argType); ABIArg& current() { return current_; } + void enforceO32ABI() { + useGPRForFloats_ = true; + } + uint32_t stackBytesConsumedSoFar() const { if (usedArgSlots_ <= 4) return ShadowStackSpace; diff --git a/js/src/jit/mips32/MoveEmitter-mips32.cpp b/js/src/jit/mips32/MoveEmitter-mips32.cpp index cfa397f0026..82453c070d2 100644 --- a/js/src/jit/mips32/MoveEmitter-mips32.cpp +++ b/js/src/jit/mips32/MoveEmitter-mips32.cpp @@ -255,16 +255,14 @@ MoveEmitterMIPS::emitDoubleMove(const MoveOperand& from, const MoveOperand& to) if (from.isFloatReg()) { if (to.isFloatReg()) { masm.moveDouble(from.floatReg(), to.floatReg()); - } else if (to.isGeneralReg()) { + } else if (to.isGeneralRegPair()) { // Used for passing double parameter in a2,a3 register pair. // Two moves are added for one double parameter by - // MacroAssemblerMIPSCompat::passABIArg - if(to.reg() == a2) - masm.moveFromDoubleLo(from.floatReg(), a2); - else if(to.reg() == a3) - masm.moveFromDoubleHi(from.floatReg(), a3); - else - MOZ_CRASH("Invalid emitDoubleMove arguments."); + // MacroAssembler::passABIArg + MOZ_ASSERT(to.evenReg() == a2 && to.oddReg() == a3, + "Invalid emitDoubleMove arguments."); + masm.moveFromDoubleLo(from.floatReg(), a2); + masm.moveFromDoubleHi(from.floatReg(), a3); } else { MOZ_ASSERT(to.isMemory()); masm.storeDouble(from.floatReg(), getAdjustedAddress(to)); @@ -272,24 +270,15 @@ MoveEmitterMIPS::emitDoubleMove(const MoveOperand& from, const MoveOperand& to) } else if (to.isFloatReg()) { MOZ_ASSERT(from.isMemory()); masm.loadDouble(getAdjustedAddress(from), to.floatReg()); - } else if (to.isGeneralReg()) { + } else if (to.isGeneralRegPair()) { // Used for passing double parameter in a2,a3 register pair. // Two moves are added for one double parameter by - // MacroAssemblerMIPSCompat::passABIArg - if (from.isMemory()) { - if(to.reg() == a2) - masm.loadPtr(getAdjustedAddress(from), a2); - else if(to.reg() == a3) - masm.loadPtr(Address(from.base(), getAdjustedOffset(from) + sizeof(uint32_t)), a3); - else - MOZ_CRASH("Invalid emitDoubleMove arguments."); - } else { - // Used for moving a double parameter from the same source. See Bug 1123874. - if(to.reg() == a2 || to.reg() == a3) - masm.ma_move(to.reg(), from.reg()); - else - MOZ_CRASH("Invalid emitDoubleMove arguments."); - } + // MacroAssembler::passABIArg + MOZ_ASSERT(from.isMemory()); + MOZ_ASSERT(to.evenReg() == a2 && to.oddReg() == a3, + "Invalid emitDoubleMove arguments."); + masm.loadPtr(getAdjustedAddress(from), a2); + masm.loadPtr(Address(from.base(), getAdjustedOffset(from) + sizeof(uint32_t)), a3); } else { MOZ_ASSERT(from.isMemory()); MOZ_ASSERT(to.isMemory());