Bug 972836 - IonMonkey MIPS: Add odd float registers to the enum, but don't allocate them yet. r=froydnj,nbp

This commit is contained in:
Branislav Rankov 2014-04-07 17:36:06 +02:00
parent 83e2568195
commit 20985e40e8
6 changed files with 191 additions and 108 deletions

View File

@ -113,7 +113,7 @@ class Registers
return Names[code]; return Names[code];
} }
static const char *GetName(uint32_t i) { static const char *GetName(uint32_t i) {
MOZ_ASSERT(i < Total); JS_ASSERT(i < Total);
return GetName(Code(i)); return GetName(Code(i));
} }
@ -191,38 +191,62 @@ class Registers
typedef uint32_t PackedRegisterMask; typedef uint32_t PackedRegisterMask;
// MIPS32 uses pairs of even and odd float registers as double precision // MIPS32 can have two types of floating-point coprocessors:
// registers. Example: f0 (double) is composed of f0 and f1 (single). // - 32 bit floating-point coprocessor - In this case, there are 32 single
// This port only uses even registers to avoid allocation problems. // precision registers and pairs of even and odd float registers are used as
// double precision registers. Example: f0 (double) is composed of
// f0 and f1 (single).
// - 64 bit floating-point coprocessor - In this case, there are 32 double
// precision register which can also be used as single precision registers.
// When using O32 ABI, floating-point coprocessor is 32 bit
// When using N32 ABI, floating-point coprocessor is 64 bit.
class FloatRegisters class FloatRegisters
{ {
public: public:
enum FPRegisterID { enum FPRegisterID {
f0 = 0, // f0, f2 - Return values f0 = 0,
f1,
f2, f2,
f4, // f4 - f10, f16, f18 - Temporaries f3,
f4,
f5,
f6, f6,
f7,
f8, f8,
f9,
f10, f10,
f12, // f12, f14 - Arguments f11,
f12,
f13,
f14, f14,
f15,
f16, f16,
f17,
f18, f18,
f20, // f20 - f30 - Saved registers f19,
f20,
f21,
f22, f22,
f23,
f24, f24,
f25,
f26, f26,
f27,
f28, f28,
f29,
f30, f30,
f31,
invalid_freg invalid_freg
}; };
typedef FPRegisterID Code; typedef FPRegisterID Code;
static const char *GetName(Code code) { static const char *GetName(Code code) {
static const char * const Names[] = { "f0", "f2", "f4", "f6", static const char * const Names[] = { "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
"f8", "f10", "f12", "f14", "f8", "f9", "f10", "f11", "f12", "f13",
"f16", "f18", "f20", "f22", "f14", "f15", "f16", "f17", "f18", "f19",
"f24", "f26", "f28", "f30"}; "f20", "f21", "f22", "f23", "f24", "f25",
"f26", "f27", "f28", "f29", "f30", "f31"};
return Names[code]; return Names[code];
} }
static const char *GetName(uint32_t i) { static const char *GetName(uint32_t i) {
@ -234,10 +258,12 @@ class FloatRegisters
static const Code Invalid = invalid_freg; static const Code Invalid = invalid_freg;
static const uint32_t Total = 16; static const uint32_t Total = 32;
// :TODO: (Bug 972836) // Fix this once odd regs can be used as float32
// only. For now we don't allocate odd regs for O32 ABI.
static const uint32_t Allocatable = 14; static const uint32_t Allocatable = 14;
static const uint32_t AllMask = 0xffff; static const uint32_t AllMask = 0xffffffff;
static const uint32_t VolatileMask = static const uint32_t VolatileMask =
(1 << FloatRegisters::f0) | (1 << FloatRegisters::f0) |
@ -260,10 +286,28 @@ class FloatRegisters
static const uint32_t WrapperMask = VolatileMask; static const uint32_t WrapperMask = VolatileMask;
// f18 and f16 are MIPS scratch float registers. // :TODO: (Bug 972836) // Fix this once odd regs can be used as float32
// only. For now we don't allocate odd regs for O32 ABI.
static const uint32_t NonAllocatableMask = static const uint32_t NonAllocatableMask =
(1 << f16) | (1 << FloatRegisters::f1) |
(1 << f18); (1 << FloatRegisters::f3) |
(1 << FloatRegisters::f5) |
(1 << FloatRegisters::f7) |
(1 << FloatRegisters::f9) |
(1 << FloatRegisters::f11) |
(1 << FloatRegisters::f13) |
(1 << FloatRegisters::f15) |
(1 << FloatRegisters::f17) |
(1 << FloatRegisters::f19) |
(1 << FloatRegisters::f21) |
(1 << FloatRegisters::f23) |
(1 << FloatRegisters::f25) |
(1 << FloatRegisters::f27) |
(1 << FloatRegisters::f29) |
(1 << FloatRegisters::f31) |
// f18 and f16 are MIPS scratch float registers.
(1 << FloatRegisters::f16) |
(1 << FloatRegisters::f18);
// Registers that can be allocated without being saved, generally. // Registers that can be allocated without being saved, generally.
static const uint32_t TempMask = VolatileMask & ~NonAllocatableMask; static const uint32_t TempMask = VolatileMask & ~NonAllocatableMask;

View File

@ -56,16 +56,7 @@ uint32_t
js::jit::RT(FloatRegister r) js::jit::RT(FloatRegister r)
{ {
JS_ASSERT(r.code() < FloatRegisters::Total); JS_ASSERT(r.code() < FloatRegisters::Total);
return (2 * r.code()) << RTShift; return r.code() << RTShift;
}
// Use to code odd float registers.
// :TODO: Bug 972836, It will be removed once we can use odd regs.
uint32_t
js::jit::RT(uint32_t regCode)
{
JS_ASSERT((regCode & ~RegMask) == 0);
return regCode << RTShift;
} }
uint32_t uint32_t
@ -79,16 +70,7 @@ uint32_t
js::jit::RD(FloatRegister r) js::jit::RD(FloatRegister r)
{ {
JS_ASSERT(r.code() < FloatRegisters::Total); JS_ASSERT(r.code() < FloatRegisters::Total);
return (2 * r.code()) << RDShift; return r.code() << RDShift;
}
// Use to code odd float registers.
// :TODO: Bug 972836, It will be removed once we can use odd regs.
uint32_t
js::jit::RD(uint32_t regCode)
{
JS_ASSERT((regCode & ~RegMask) == 0);
return regCode << RDShift;
} }
uint32_t uint32_t
@ -102,7 +84,7 @@ uint32_t
js::jit::SA(FloatRegister r) js::jit::SA(FloatRegister r)
{ {
JS_ASSERT(r.code() < FloatRegisters::Total); JS_ASSERT(r.code() < FloatRegisters::Total);
return (2 * r.code()) << SAShift; return r.code() << SAShift;
} }
Register Register
@ -973,39 +955,6 @@ Assembler::as_mfc1(Register rt, FloatRegister fs)
return writeInst(InstReg(op_cop1, rs_mfc1, rt, fs).encode()); return writeInst(InstReg(op_cop1, rs_mfc1, rt, fs).encode());
} }
// :TODO: Bug 972836, Remove _Odd functions once we can use odd regs.
BufferOffset
Assembler::as_ls_Odd(FloatRegister fd, Register base, int32_t off)
{
JS_ASSERT(Imm16::isInSignedRange(off));
// Hardcoded because it will be removed once we can use odd regs.
return writeInst(op_lwc1 | RS(base) | RT(fd.code() * 2 + 1) | Imm16(off).encode());
}
BufferOffset
Assembler::as_ss_Odd(FloatRegister fd, Register base, int32_t off)
{
JS_ASSERT(Imm16::isInSignedRange(off));
// Hardcoded because it will be removed once we can use odd regs.
return writeInst(op_swc1 | RS(base) | RT(fd.code() * 2 + 1) | Imm16(off).encode());
}
BufferOffset
Assembler::as_mtc1_Odd(Register rt, FloatRegister fs)
{
// Hardcoded because it will be removed once we can use odd regs.
return writeInst(op_cop1 | rs_mtc1 | RT(rt) | RD(fs.code() * 2 + 1));
}
BufferOffset
Assembler::as_mfc1_Odd(Register rt, FloatRegister fs)
{
// Hardcoded because it will be removed once we can use odd regs.
return writeInst(op_cop1 | rs_mfc1 | RT(rt) | RD(fs.code() * 2 + 1));
}
// FP convert instructions // FP convert instructions
BufferOffset BufferOffset
Assembler::as_ceilws(FloatRegister fd, FloatRegister fs) Assembler::as_ceilws(FloatRegister fd, FloatRegister fs)

View File

@ -861,16 +861,14 @@ class Assembler
BufferOffset as_mfc1(Register rt, FloatRegister fs); BufferOffset as_mfc1(Register rt, FloatRegister fs);
protected: protected:
// These instructions should only be used to access the odd part of // This is used to access the odd regiter form the pair of single
// 64-bit register pair. Do not use odd registers as 32-bit registers. // precision registers that make one double register.
// :TODO: Bug 972836, Remove _Odd functions once we can use odd regs. FloatRegister getOddPair(FloatRegister reg) {
BufferOffset as_ls_Odd(FloatRegister fd, Register base, int32_t off); JS_ASSERT(reg.code() % 2 == 0);
BufferOffset as_ss_Odd(FloatRegister fd, Register base, int32_t off); return FloatRegister::FromCode(reg.code() + 1);
BufferOffset as_mtc1_Odd(Register rt, FloatRegister fs); }
public:
// Made public because CodeGenerator uses it to check for -0
BufferOffset as_mfc1_Odd(Register rt, FloatRegister fs);
public:
// FP convert instructions // FP convert instructions
BufferOffset as_ceilws(FloatRegister fd, FloatRegister fs); BufferOffset as_ceilws(FloatRegister fd, FloatRegister fs);
BufferOffset as_floorws(FloatRegister fd, FloatRegister fs); BufferOffset as_floorws(FloatRegister fd, FloatRegister fs);

View File

@ -114,7 +114,7 @@ MacroAssemblerMIPS::convertDoubleToInt32(const FloatRegister &src, const Registe
// Test and bail for -0.0, when integer result is 0 // Test and bail for -0.0, when integer result is 0
// Move the top word of the double into the output reg, if it is // Move the top word of the double into the output reg, if it is
// non-zero, then the original value was -0.0 // non-zero, then the original value was -0.0
as_mfc1_Odd(dest, src); moveFromDoubleHi(src, dest);
ma_b(dest, Imm32(INT32_MIN), fail, Assembler::Equal); ma_b(dest, Imm32(INT32_MIN), fail, Assembler::Equal);
bind(&notZero); bind(&notZero);
} }
@ -141,7 +141,7 @@ MacroAssemblerMIPS::convertFloat32ToInt32(const FloatRegister &src, const Regist
// Test and bail for -0.0, when integer result is 0 // Test and bail for -0.0, when integer result is 0
// Move the top word of the double into the output reg, // Move the top word of the double into the output reg,
// if it is non-zero, then the original value was -0.0 // if it is non-zero, then the original value was -0.0
as_mfc1_Odd(dest, src); moveFromDoubleHi(src, dest);
ma_b(dest, Imm32(INT32_MIN), fail, Assembler::Equal); ma_b(dest, Imm32(INT32_MIN), fail, Assembler::Equal);
bind(&notZero); bind(&notZero);
} }
@ -1296,7 +1296,7 @@ MacroAssemblerMIPS::ma_lis(FloatRegister dest, float value)
Imm32 imm(mozilla::BitwiseCast<uint32_t>(value)); Imm32 imm(mozilla::BitwiseCast<uint32_t>(value));
ma_li(ScratchRegister, imm); ma_li(ScratchRegister, imm);
as_mtc1(ScratchRegister, dest); moveToFloat32(ScratchRegister, dest);
} }
void void
@ -1310,41 +1310,41 @@ MacroAssemblerMIPS::ma_lid(FloatRegister dest, double value)
// put hi part of 64 bit value into the odd register // put hi part of 64 bit value into the odd register
if (intStruct.hi == 0) { if (intStruct.hi == 0) {
as_mtc1_Odd(zero, dest); moveToDoubleHi(zero, dest);
} else { } else {
ma_li(ScratchRegister, Imm32(intStruct.hi)); ma_li(ScratchRegister, Imm32(intStruct.hi));
as_mtc1_Odd(ScratchRegister, dest); moveToDoubleHi(ScratchRegister, dest);
} }
// put low part of 64 bit value into the even register // put low part of 64 bit value into the even register
if (intStruct.lo == 0) { if (intStruct.lo == 0) {
as_mtc1(zero, dest); moveToDoubleLo(zero, dest);
} else { } else {
ma_li(ScratchRegister, Imm32(intStruct.lo)); ma_li(ScratchRegister, Imm32(intStruct.lo));
as_mtc1(ScratchRegister, dest); moveToDoubleLo(ScratchRegister, dest);
} }
} }
void void
MacroAssemblerMIPS::ma_liNegZero(FloatRegister dest) MacroAssemblerMIPS::ma_liNegZero(FloatRegister dest)
{ {
as_mtc1(zero, dest); moveToDoubleLo(zero, dest);
ma_li(ScratchRegister, Imm32(INT_MIN)); ma_li(ScratchRegister, Imm32(INT_MIN));
as_mtc1_Odd(ScratchRegister, dest); moveToDoubleHi(ScratchRegister, dest);
} }
void void
MacroAssemblerMIPS::ma_mv(FloatRegister src, ValueOperand dest) MacroAssemblerMIPS::ma_mv(FloatRegister src, ValueOperand dest)
{ {
as_mfc1(dest.payloadReg(), src); moveFromDoubleLo(src, dest.payloadReg());
as_mfc1_Odd(dest.typeReg(), src); moveFromDoubleHi(src, dest.typeReg());
} }
void void
MacroAssemblerMIPS::ma_mv(ValueOperand src, FloatRegister dest) MacroAssemblerMIPS::ma_mv(ValueOperand src, FloatRegister dest)
{ {
as_mtc1(src.payloadReg(), dest); moveToDoubleLo(src.payloadReg(), dest);
as_mtc1_Odd(src.typeReg(), dest); moveToDoubleHi(src.typeReg(), dest);
} }
void void
@ -1369,12 +1369,12 @@ MacroAssemblerMIPS::ma_ld(FloatRegister ft, Address address)
int32_t off2 = address.offset + TAG_OFFSET; int32_t off2 = address.offset + TAG_OFFSET;
if (Imm16::isInSignedRange(address.offset) && Imm16::isInSignedRange(off2)) { if (Imm16::isInSignedRange(address.offset) && Imm16::isInSignedRange(off2)) {
as_ls(ft, address.base, Imm16(address.offset).encode()); as_ls(ft, address.base, Imm16(address.offset).encode());
as_ls_Odd(ft, address.base, Imm16(off2).encode()); as_ls(getOddPair(ft), address.base, Imm16(off2).encode());
} else { } else {
ma_li(ScratchRegister, Imm32(address.offset)); ma_li(ScratchRegister, Imm32(address.offset));
as_addu(ScratchRegister, address.base, ScratchRegister); as_addu(ScratchRegister, address.base, ScratchRegister);
as_ls(ft, ScratchRegister, PAYLOAD_OFFSET); as_ls(ft, ScratchRegister, PAYLOAD_OFFSET);
as_ls_Odd(ft, ScratchRegister, TAG_OFFSET); as_ls(getOddPair(ft), ScratchRegister, TAG_OFFSET);
} }
} }
@ -1384,12 +1384,12 @@ MacroAssemblerMIPS::ma_sd(FloatRegister ft, Address address)
int32_t off2 = address.offset + TAG_OFFSET; int32_t off2 = address.offset + TAG_OFFSET;
if (Imm16::isInSignedRange(address.offset) && Imm16::isInSignedRange(off2)) { if (Imm16::isInSignedRange(address.offset) && Imm16::isInSignedRange(off2)) {
as_ss(ft, address.base, Imm16(address.offset).encode()); as_ss(ft, address.base, Imm16(address.offset).encode());
as_ss_Odd(ft, address.base, Imm16(off2).encode()); as_ss(getOddPair(ft), address.base, Imm16(off2).encode());
} else { } else {
ma_li(ScratchRegister, Imm32(address.offset)); ma_li(ScratchRegister, Imm32(address.offset));
as_addu(ScratchRegister, address.base, ScratchRegister); as_addu(ScratchRegister, address.base, ScratchRegister);
as_ss(ft, ScratchRegister, PAYLOAD_OFFSET); as_ss(ft, ScratchRegister, PAYLOAD_OFFSET);
as_ss_Odd(ft, ScratchRegister, TAG_OFFSET); as_ss(getOddPair(ft), ScratchRegister, TAG_OFFSET);
} }
} }
@ -1540,6 +1540,72 @@ MacroAssemblerMIPSCompat::freeStack(Register amount)
as_addu(StackPointer, StackPointer, amount); as_addu(StackPointer, StackPointer, amount);
} }
void
MacroAssembler::PushRegsInMask(RegisterSet set)
{
int32_t diffF = set.fpus().size() * sizeof(double);
int32_t diffG = set.gprs().size() * sizeof(intptr_t);
reserveStack(diffG);
for (GeneralRegisterBackwardIterator iter(set.gprs()); iter.more(); iter++) {
diffG -= sizeof(intptr_t);
storePtr(*iter, Address(StackPointer, diffG));
}
MOZ_ASSERT(diffG == 0);
// Double values have to be aligned. We reserve extra space so that we can
// start writing from the first aligned location.
// We reserve a whole extra double so that the buffer has even size.
ma_and(SecondScratchReg, sp, Imm32(~(StackAlignment - 1)));
reserveStack(diffF + sizeof(double));
for (FloatRegisterForwardIterator iter(set.fpus()); iter.more(); iter++) {
// Use assembly s.d because we have alligned the stack.
// :TODO: (Bug 972836) Fix this once odd regs can be used as
// float32 only. For now we skip saving odd regs for O32 ABI.
// :TODO: (Bug 985881) Make a switch for N32 ABI.
if ((*iter).code() % 2 == 0)
as_sd(*iter, SecondScratchReg, -diffF);
diffF -= sizeof(double);
}
MOZ_ASSERT(diffF == 0);
}
void
MacroAssembler::PopRegsInMaskIgnore(RegisterSet set, RegisterSet ignore)
{
int32_t diffG = set.gprs().size() * sizeof(intptr_t);
int32_t diffF = set.fpus().size() * sizeof(double);
const int32_t reservedG = diffG;
const int32_t reservedF = diffF;
// Read the buffer form the first aligned location.
ma_addu(SecondScratchReg, sp, Imm32(reservedF + sizeof(double)));
ma_and(SecondScratchReg, SecondScratchReg, Imm32(~(StackAlignment - 1)));
for (FloatRegisterForwardIterator iter(set.fpus()); iter.more(); iter++) {
// :TODO: (Bug 972836) Fix this once odd regs can be used as
// float32 only. For now we skip loading odd regs for O32 ABI.
// :TODO: (Bug 985881) Make a switch for N32 ABI.
if (!ignore.has(*iter) && ((*iter).code() % 2 == 0))
// Use assembly l.d because we have alligned the stack.
as_ld(*iter, SecondScratchReg, -diffF);
diffF -= sizeof(double);
}
freeStack(reservedF + sizeof(double));
MOZ_ASSERT(diffF == 0);
for (GeneralRegisterBackwardIterator iter(set.gprs()); iter.more(); iter++) {
diffG -= sizeof(intptr_t);
if (!ignore.has(*iter))
loadPtr(Address(StackPointer, diffG), *iter);
}
freeStack(reservedG);
MOZ_ASSERT(diffG == 0);
}
void void
MacroAssemblerMIPSCompat::add32(Register src, Register dest) MacroAssemblerMIPSCompat::add32(Register src, Register dest)
{ {
@ -2324,17 +2390,17 @@ void
MacroAssemblerMIPSCompat::unboxDouble(const ValueOperand &operand, const FloatRegister &dest) MacroAssemblerMIPSCompat::unboxDouble(const ValueOperand &operand, const FloatRegister &dest)
{ {
MOZ_ASSERT(dest != ScratchFloatReg); MOZ_ASSERT(dest != ScratchFloatReg);
as_mtc1(operand.payloadReg(), dest); moveToDoubleLo(operand.payloadReg(), dest);
as_mtc1_Odd(operand.typeReg(), dest); moveToDoubleHi(operand.typeReg(), dest);
} }
void void
MacroAssemblerMIPSCompat::unboxDouble(const Address &src, const FloatRegister &dest) MacroAssemblerMIPSCompat::unboxDouble(const Address &src, const FloatRegister &dest)
{ {
ma_lw(ScratchRegister, Address(src.base, src.offset + PAYLOAD_OFFSET)); ma_lw(ScratchRegister, Address(src.base, src.offset + PAYLOAD_OFFSET));
as_mtc1(ScratchRegister, dest); moveToDoubleLo(ScratchRegister, dest);
ma_lw(ScratchRegister, Address(src.base, src.offset + TAG_OFFSET)); ma_lw(ScratchRegister, Address(src.base, src.offset + TAG_OFFSET));
as_mtc1_Odd(ScratchRegister, dest); moveToDoubleHi(ScratchRegister, dest);
} }
void void
@ -2380,8 +2446,8 @@ MacroAssemblerMIPSCompat::unboxPrivate(const ValueOperand &src, Register dest)
void void
MacroAssemblerMIPSCompat::boxDouble(const FloatRegister &src, const ValueOperand &dest) MacroAssemblerMIPSCompat::boxDouble(const FloatRegister &src, const ValueOperand &dest)
{ {
as_mfc1(dest.payloadReg(), src); moveFromDoubleLo(src, dest.payloadReg());
as_mfc1_Odd(dest.typeReg(), src); moveFromDoubleHi(src, dest.typeReg());
} }
void void

View File

@ -234,6 +234,32 @@ class MacroAssemblerMIPS : public Assembler
void ma_bc1d(FloatRegister lhs, FloatRegister rhs, Label *label, DoubleCondition c, void ma_bc1d(FloatRegister lhs, FloatRegister rhs, Label *label, DoubleCondition c,
JumpKind jumpKind = LongJump, FPConditionBit fcc = FCC0); JumpKind jumpKind = LongJump, FPConditionBit fcc = FCC0);
// These fuctions abstract the access to high part of the double precision
// float register. It is intended to work on both 32 bit and 64 bit
// floating point coprocessor.
// :TODO: (Bug 985881) Modify this for N32 ABI to use mthc1 and mfhc1
void moveToDoubleHi(Register src, FloatRegister dest) {
as_mtc1(src, getOddPair(dest));
}
void moveFromDoubleHi(FloatRegister src, Register dest) {
as_mfc1(dest, getOddPair(src));
}
void moveToDoubleLo(Register src, FloatRegister dest) {
as_mtc1(src, dest);
}
void moveFromDoubleLo(FloatRegister src, Register dest) {
as_mfc1(dest, src);
}
void moveToFloat32(Register src, FloatRegister dest) {
as_mtc1(src, dest);
}
void moveFromFloat32(FloatRegister src, Register dest) {
as_mfc1(dest, src);
}
protected: protected:
void branchWithCode(InstImm code, Label *label, JumpKind jumpKind); void branchWithCode(InstImm code, Label *label, JumpKind jumpKind);
Condition ma_cmp(Register rd, Register lhs, Register rhs, Condition c); Condition ma_cmp(Register rd, Register lhs, Register rhs, Condition c);
@ -993,8 +1019,8 @@ public:
} }
void zeroDouble(FloatRegister reg) { void zeroDouble(FloatRegister reg) {
as_mtc1(zero, reg); moveToDoubleLo(zero, reg);
as_mtc1_Odd(zero, reg); moveToDoubleHi(zero, reg);
} }
void clampIntToUint8(Register reg) { void clampIntToUint8(Register reg) {

View File

@ -212,7 +212,7 @@ MoveEmitterMIPS::emitFloat32Move(const MoveOperand &from, const MoveOperand &to)
} else if (to.isGeneralReg()) { } else if (to.isGeneralReg()) {
// This should only be used when passing float parameter in a1,a2,a3 // This should only be used when passing float parameter in a1,a2,a3
MOZ_ASSERT(to.reg() == a1 || to.reg() == a2 || to.reg() == a3); MOZ_ASSERT(to.reg() == a1 || to.reg() == a2 || to.reg() == a3);
masm.as_mfc1(to.reg(), from.floatReg()); masm.moveFromFloat32(from.floatReg(), to.reg());
} else { } else {
MOZ_ASSERT(to.isMemory()); MOZ_ASSERT(to.isMemory());
masm.storeFloat32(from.floatReg(), getAdjustedAddress(to)); masm.storeFloat32(from.floatReg(), getAdjustedAddress(to));
@ -248,9 +248,9 @@ MoveEmitterMIPS::emitDoubleMove(const MoveOperand &from, const MoveOperand &to)
// Two moves are added for one double parameter by // Two moves are added for one double parameter by
// MacroAssemblerMIPSCompat::passABIArg // MacroAssemblerMIPSCompat::passABIArg
if(to.reg() == a2) if(to.reg() == a2)
masm.as_mfc1(a2, from.floatReg()); masm.moveFromDoubleLo(from.floatReg(), a2);
else if(to.reg() == a3) else if(to.reg() == a3)
masm.as_mfc1_Odd(a3, from.floatReg()); masm.moveFromDoubleHi(from.floatReg(), a3);
else else
MOZ_ASSUME_UNREACHABLE("Invalid emitDoubleMove arguments."); MOZ_ASSUME_UNREACHABLE("Invalid emitDoubleMove arguments.");
} else { } else {