summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/assembler
diff options
context:
space:
mode:
Diffstat (limited to 'Source/JavaScriptCore/assembler')
-rw-r--r--Source/JavaScriptCore/assembler/MIPSAssembler.h109
-rw-r--r--Source/JavaScriptCore/assembler/MacroAssembler.h7
-rw-r--r--Source/JavaScriptCore/assembler/MacroAssemblerMIPS.h480
3 files changed, 553 insertions, 43 deletions
diff --git a/Source/JavaScriptCore/assembler/MIPSAssembler.h b/Source/JavaScriptCore/assembler/MIPSAssembler.h
index 026f87e52..7f553bb9a 100644
--- a/Source/JavaScriptCore/assembler/MIPSAssembler.h
+++ b/Source/JavaScriptCore/assembler/MIPSAssembler.h
@@ -152,6 +152,8 @@ public:
typedef SegmentedVector<AssemblerLabel, 64> Jumps;
MIPSAssembler()
+ : m_indexOfLastWatchpoint(INT_MIN)
+ , m_indexOfTailOfLastWatchpoint(INT_MIN)
{
}
@@ -325,7 +327,7 @@ public:
emitInst(0x00000000 | (rd << OP_SH_RD) | (rt << OP_SH_RT) | ((shamt & 0x1f) << OP_SH_SHAMT));
}
- void sllv(RegisterID rd, RegisterID rt, int rs)
+ void sllv(RegisterID rd, RegisterID rt, RegisterID rs)
{
emitInst(0x00000004 | (rd << OP_SH_RD) | (rt << OP_SH_RT) | (rs << OP_SH_RS));
}
@@ -527,6 +529,16 @@ public:
emitInst(0x46200004 | (fd << OP_SH_FD) | (fs << OP_SH_FS));
}
+ void movd(FPRegisterID fd, FPRegisterID fs)
+ {
+ emitInst(0x46200006 | (fd << OP_SH_FD) | (fs << OP_SH_FS));
+ }
+
+ void negd(FPRegisterID fd, FPRegisterID fs)
+ {
+ emitInst(0x46200007 | (fd << OP_SH_FD) | (fs << OP_SH_FS));
+ }
+
void truncwd(FPRegisterID fd, FPRegisterID fs)
{
emitInst(0x4620000d | (fd << OP_SH_FD) | (fs << OP_SH_FS));
@@ -619,9 +631,24 @@ public:
return m_buffer.label();
}
+ AssemblerLabel labelForWatchpoint()
+ {
+ AssemblerLabel result = m_buffer.label();
+ if (static_cast<int>(result.m_offset) != m_indexOfLastWatchpoint)
+ result = label();
+ m_indexOfLastWatchpoint = result.m_offset;
+ m_indexOfTailOfLastWatchpoint = result.m_offset + maxJumpReplacementSize();
+ return result;
+ }
+
AssemblerLabel label()
{
- return m_buffer.label();
+ AssemblerLabel result = m_buffer.label();
+ while (UNLIKELY(static_cast<int>(result.m_offset) < m_indexOfTailOfLastWatchpoint)) {
+ nop();
+ result = m_buffer.label();
+ }
+ return result;
}
AssemblerLabel align(int alignment)
@@ -664,14 +691,24 @@ public:
// Assembly helpers for moving data between fp and registers.
void vmov(RegisterID rd1, RegisterID rd2, FPRegisterID rn)
{
+#if WTF_MIPS_ISA_REV(2) && WTF_MIPS_FP64
+ mfc1(rd1, rn);
+ mfhc1(rd2, rn);
+#else
mfc1(rd1, rn);
mfc1(rd2, FPRegisterID(rn + 1));
+#endif
}
void vmov(FPRegisterID rd, RegisterID rn1, RegisterID rn2)
{
+#if WTF_MIPS_ISA_REV(2) && WTF_MIPS_FP64
+ mtc1(rn1, rd);
+ mthc1(rn2, rd);
+#else
mtc1(rn1, rd);
mtc1(rn2, FPRegisterID(rd + 1));
+#endif
}
static unsigned getCallReturnOffset(AssemblerLabel call)
@@ -688,6 +725,35 @@ public:
// writable region of memory; to modify the code in an execute-only execuable
// pool the 'repatch' and 'relink' methods should be used.
+ static size_t linkDirectJump(void* code, void* to)
+ {
+ MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(code));
+ size_t ops = 0;
+ int32_t slotAddr = reinterpret_cast<int>(insn) + 4;
+ int32_t toAddr = reinterpret_cast<int>(to);
+
+ if ((slotAddr & 0xf0000000) != (toAddr & 0xf0000000)) {
+ // lui
+ *insn = 0x3c000000 | (MIPSRegisters::t9 << OP_SH_RT) | ((toAddr >> 16) & 0xffff);
+ ++insn;
+ // ori
+ *insn = 0x34000000 | (MIPSRegisters::t9 << OP_SH_RT) | (MIPSRegisters::t9 << OP_SH_RS) | (toAddr & 0xffff);
+ ++insn;
+ // jr
+ *insn = 0x00000008 | (MIPSRegisters::t9 << OP_SH_RS);
+ ++insn;
+ ops = 4 * sizeof(MIPSWord);
+ } else {
+ // j
+ *insn = 0x08000000 | ((toAddr & 0x0fffffff) >> 2);
+ ++insn;
+ ops = 2 * sizeof(MIPSWord);
+ }
+ // nop
+ *insn = 0x00000000;
+ return ops;
+ }
+
void linkJump(AssemblerLabel from, AssemblerLabel to)
{
ASSERT(to.isSet());
@@ -825,29 +891,36 @@ public:
#endif
}
- static void revertJumpToMove(void* instructionStart, RegisterID rt, int imm)
+ static ptrdiff_t maxJumpReplacementSize()
{
- MIPSWord* insn = static_cast<MIPSWord*>(instructionStart) + 1;
- ASSERT((*insn & 0xfc000000) == 0x34000000);
- *insn = (*insn & 0xfc1f0000) | (imm & 0xffff);
- cacheFlush(insn, sizeof(MIPSWord));
+ return sizeof(MIPSWord) * 4;
}
- static void replaceWithJump(void* instructionStart, void* to)
+ static void revertJumpToMove(void* instructionStart, RegisterID rt, int imm)
{
- MIPSWord* instruction = reinterpret_cast<MIPSWord*>(instructionStart);
- intptr_t jumpTo = reinterpret_cast<intptr_t>(to);
+ MIPSWord* insn = static_cast<MIPSWord*>(instructionStart);
+ size_t codeSize = 2 * sizeof(MIPSWord);
// lui
- instruction[0] = 0x3c000000 | (MIPSRegisters::t9 << OP_SH_RT) | ((jumpTo >> 16) & 0xffff);
+ *insn = 0x3c000000 | (rt << OP_SH_RT) | ((imm >> 16) & 0xffff);
+ ++insn;
// ori
- instruction[1] = 0x34000000 | (MIPSRegisters::t9 << OP_SH_RT) | (MIPSRegisters::t9 << OP_SH_RS) | (jumpTo & 0xffff);
- // jr
- instruction[2] = 0x00000008 | (MIPSRegisters::t9 << OP_SH_RS);
- // nop
- instruction[3] = 0x0;
+ *insn = 0x34000000 | (rt << OP_SH_RS) | (rt << OP_SH_RT) | (imm & 0xffff);
+ ++insn;
+ // if jr $t9
+ if (*insn == 0x03200008) {
+ *insn = 0x00000000;
+ codeSize += sizeof(MIPSWord);
+ }
+ cacheFlush(insn, codeSize);
+ }
- cacheFlush(instruction, sizeof(MIPSWord) * 4);
+ static void replaceWithJump(void* instructionStart, void* to)
+ {
+ ASSERT(!(bitwise_cast<uintptr_t>(instructionStart) & 3));
+ ASSERT(!(bitwise_cast<uintptr_t>(to) & 3));
+ size_t ops = linkDirectJump(instructionStart, to);
+ cacheFlush(instructionStart, ops);
}
static void replaceWithLoad(void* instructionStart)
@@ -1023,6 +1096,8 @@ private:
AssemblerBuffer m_buffer;
Jumps m_jumps;
+ int m_indexOfLastWatchpoint;
+ int m_indexOfTailOfLastWatchpoint;
};
} // namespace JSC
diff --git a/Source/JavaScriptCore/assembler/MacroAssembler.h b/Source/JavaScriptCore/assembler/MacroAssembler.h
index 3d57340f9..2f26ff281 100644
--- a/Source/JavaScriptCore/assembler/MacroAssembler.h
+++ b/Source/JavaScriptCore/assembler/MacroAssembler.h
@@ -200,6 +200,13 @@ public:
}
#endif
+#if CPU(MIPS)
+ void poke(FPRegisterID src, int index = 0)
+ {
+ ASSERT(!(index & 1));
+ storeDouble(src, addressForPoke(index));
+ }
+#endif
// Backwards banches, these are currently all implemented using existing forwards branch mechanisms.
void branchPtr(RelationalCondition cond, RegisterID op1, TrustedImmPtr imm, Label target)
diff --git a/Source/JavaScriptCore/assembler/MacroAssemblerMIPS.h b/Source/JavaScriptCore/assembler/MacroAssemblerMIPS.h
index 44f94caec..f5298a0ab 100644
--- a/Source/JavaScriptCore/assembler/MacroAssemblerMIPS.h
+++ b/Source/JavaScriptCore/assembler/MacroAssemblerMIPS.h
@@ -114,6 +114,11 @@ public:
m_assembler.addu(dest, dest, src);
}
+ void add32(RegisterID op1, RegisterID op2, RegisterID dest)
+ {
+ m_assembler.addu(dest, op1, op2);
+ }
+
void add32(TrustedImm32 imm, RegisterID dest)
{
add32(imm, dest, dest);
@@ -249,6 +254,11 @@ public:
m_assembler.andInsn(dest, dest, src);
}
+ void and32(RegisterID op1, RegisterID op2, RegisterID dest)
+ {
+ m_assembler.andInsn(dest, op1, op2);
+ }
+
void and32(TrustedImm32 imm, RegisterID dest)
{
if (!imm.m_value && !m_fixedWidth)
@@ -265,9 +275,16 @@ public:
}
}
- void lshift32(TrustedImm32 imm, RegisterID dest)
+ void and32(TrustedImm32 imm, RegisterID src, RegisterID dest)
{
- m_assembler.sll(dest, dest, imm.m_value);
+ if (!imm.m_value && !m_fixedWidth)
+ move(MIPSRegisters::zero, dest);
+ else if (imm.m_value > 0 && imm.m_value < 65535 && !m_fixedWidth)
+ m_assembler.andi(dest, src, imm.m_value);
+ else {
+ move(imm, immTempRegister);
+ m_assembler.andInsn(dest, src, immTempRegister);
+ }
}
void lshift32(RegisterID shiftAmount, RegisterID dest)
@@ -275,11 +292,33 @@ public:
m_assembler.sllv(dest, dest, shiftAmount);
}
+ void lshift32(RegisterID src, RegisterID shiftAmount, RegisterID dest)
+ {
+ m_assembler.sllv(dest, src, shiftAmount);
+ }
+
+ void lshift32(TrustedImm32 imm, RegisterID dest)
+ {
+ move(imm, immTempRegister);
+ m_assembler.sllv(dest, dest, immTempRegister);
+ }
+
+ void lshift32(RegisterID src, TrustedImm32 imm, RegisterID dest)
+ {
+ move(imm, immTempRegister);
+ m_assembler.sllv(dest, src, immTempRegister);
+ }
+
void mul32(RegisterID src, RegisterID dest)
{
m_assembler.mul(dest, dest, src);
}
+ void mul32(RegisterID op1, RegisterID op2, RegisterID dest)
+ {
+ m_assembler.mul(dest, op1, op2);
+ }
+
void mul32(TrustedImm32 imm, RegisterID src, RegisterID dest)
{
if (!imm.m_value && !m_fixedWidth)
@@ -330,6 +369,24 @@ public:
m_assembler.orInsn(dest, dest, dataTempRegister);
}
+ void or32(TrustedImm32 imm, RegisterID src, RegisterID dest)
+ {
+ if (!imm.m_value && !m_fixedWidth)
+ return;
+
+ if (imm.m_value > 0 && imm.m_value < 65535 && !m_fixedWidth) {
+ m_assembler.ori(dest, src, imm.m_value);
+ return;
+ }
+
+ /*
+ li dataTemp, imm
+ or dest, src, dataTemp
+ */
+ move(imm, dataTempRegister);
+ m_assembler.orInsn(dest, src, dataTempRegister);
+ }
+
void or32(RegisterID src, AbsoluteAddress dest)
{
load32(dest.m_ptr, dataTempRegister);
@@ -342,6 +399,11 @@ public:
m_assembler.srav(dest, dest, shiftAmount);
}
+ void rshift32(RegisterID src, RegisterID shiftAmount, RegisterID dest)
+ {
+ m_assembler.srav(dest, src, shiftAmount);
+ }
+
void rshift32(TrustedImm32 imm, RegisterID dest)
{
m_assembler.sra(dest, dest, imm.m_value);
@@ -357,16 +419,31 @@ public:
m_assembler.srlv(dest, dest, shiftAmount);
}
+ void urshift32(RegisterID src, RegisterID shiftAmount, RegisterID dest)
+ {
+ m_assembler.srlv(dest, src, shiftAmount);
+ }
+
void urshift32(TrustedImm32 imm, RegisterID dest)
{
m_assembler.srl(dest, dest, imm.m_value);
}
+ void urshift32(RegisterID src, TrustedImm32 imm, RegisterID dest)
+ {
+ m_assembler.srl(dest, src, imm.m_value);
+ }
+
void sub32(RegisterID src, RegisterID dest)
{
m_assembler.subu(dest, dest, src);
}
+ void sub32(RegisterID op1, RegisterID op2, RegisterID dest)
+ {
+ m_assembler.subu(dest, op1, op2);
+ }
+
void sub32(TrustedImm32 imm, RegisterID dest)
{
if (imm.m_value >= -32767 && imm.m_value <= 32768
@@ -477,6 +554,11 @@ public:
m_assembler.xorInsn(dest, dest, src);
}
+ void xor32(RegisterID op1, RegisterID op2, RegisterID dest)
+ {
+ m_assembler.xorInsn(dest, op1, op2);
+ }
+
void xor32(TrustedImm32 imm, RegisterID dest)
{
if (imm.m_value == -1) {
@@ -492,6 +574,21 @@ public:
m_assembler.xorInsn(dest, dest, immTempRegister);
}
+ void xor32(TrustedImm32 imm, RegisterID src, RegisterID dest)
+ {
+ if (imm.m_value == -1) {
+ m_assembler.nor(dest, src, MIPSRegisters::zero);
+ return;
+ }
+
+ /*
+ li immTemp, imm
+ xor dest, dest, immTemp
+ */
+ move(imm, immTempRegister);
+ m_assembler.xorInsn(dest, src, immTempRegister);
+ }
+
void sqrtDouble(FPRegisterID src, FPRegisterID dst)
{
m_assembler.sqrtd(dst, src);
@@ -971,6 +1068,44 @@ public:
}
}
+ void store32(TrustedImm32 imm, BaseIndex address)
+ {
+ if (address.offset >= -32768 && address.offset <= 32767 && !m_fixedWidth) {
+ /*
+ sll addrTemp, address.index, address.scale
+ addu addrTemp, addrTemp, address.base
+ sw src, address.offset(addrTemp)
+ */
+ m_assembler.sll(addrTempRegister, address.index, address.scale);
+ m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
+ if (!imm.m_value)
+ m_assembler.sw(MIPSRegisters::zero, addrTempRegister, address.offset);
+ else {
+ move(imm, immTempRegister);
+ m_assembler.sw(immTempRegister, addrTempRegister, address.offset);
+ }
+ } else {
+ /*
+ sll addrTemp, address.index, address.scale
+ addu addrTemp, addrTemp, address.base
+ lui immTemp, (address.offset + 0x8000) >> 16
+ addu addrTemp, addrTemp, immTemp
+ sw src, (address.offset & 0xffff)(at)
+ */
+ m_assembler.sll(addrTempRegister, address.index, address.scale);
+ m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
+ m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16);
+ m_assembler.addu(addrTempRegister, addrTempRegister, immTempRegister);
+ if (!imm.m_value && !m_fixedWidth)
+ m_assembler.sw(MIPSRegisters::zero, addrTempRegister, address.offset);
+ else {
+ move(imm, immTempRegister);
+ m_assembler.sw(immTempRegister, addrTempRegister, address.offset);
+ }
+ }
+ }
+
+
void store32(RegisterID src, const void* address)
{
/*
@@ -1318,6 +1453,15 @@ public:
m_fixedWidth = false;
}
+ void jump(AbsoluteAddress address)
+ {
+ m_fixedWidth = true;
+ load32(address.m_ptr, MIPSRegisters::t9);
+ m_assembler.jr(MIPSRegisters::t9);
+ m_assembler.nop();
+ m_fixedWidth = false;
+ }
+
void moveDoubleToInts(FPRegisterID src, RegisterID dest1, RegisterID dest2)
{
m_assembler.vmov(dest1, dest2, src);
@@ -1386,6 +1530,53 @@ public:
return Jump();
}
+ Jump branchAdd32(ResultCondition cond, RegisterID op1, RegisterID op2, RegisterID dest)
+ {
+ ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
+ if (cond == Overflow) {
+ /*
+ move dataTemp, op1
+ xor cmpTemp, dataTemp, op2
+ bltz cmpTemp, No_overflow # diff sign bit -> no overflow
+ addu dest, dataTemp, op2
+ xor cmpTemp, dest, dataTemp
+ bgez cmpTemp, No_overflow # same sign big -> no overflow
+ nop
+ b Overflow
+ nop
+ nop
+ nop
+ nop
+ nop
+ No_overflow:
+ */
+ move(op1, dataTempRegister);
+ m_assembler.xorInsn(cmpTempRegister, dataTempRegister, op2);
+ m_assembler.bltz(cmpTempRegister, 10);
+ m_assembler.addu(dest, dataTempRegister, op2);
+ m_assembler.xorInsn(cmpTempRegister, dest, dataTempRegister);
+ m_assembler.bgez(cmpTempRegister, 7);
+ m_assembler.nop();
+ return jump();
+ }
+ if (cond == Signed) {
+ add32(op1, op2, dest);
+ // Check if dest is negative.
+ m_assembler.slt(cmpTempRegister, dest, MIPSRegisters::zero);
+ return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
+ }
+ if (cond == Zero) {
+ add32(op1, op2, dest);
+ return branchEqual(dest, MIPSRegisters::zero);
+ }
+ if (cond == NonZero) {
+ add32(op1, op2, dest);
+ return branchNotEqual(dest, MIPSRegisters::zero);
+ }
+ ASSERT(0);
+ return Jump();
+ }
+
Jump branchAdd32(ResultCondition cond, TrustedImm32 imm, RegisterID dest)
{
move(imm, immTempRegister);
@@ -1399,6 +1590,111 @@ public:
return branchAdd32(cond, immTempRegister, dest);
}
+ Jump branchAdd32(ResultCondition cond, TrustedImm32 imm, AbsoluteAddress dest)
+ {
+ ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
+ if (cond == Overflow) {
+ /*
+ move dataTemp, dest
+ xori cmpTemp, dataTemp, imm
+ bltz cmpTemp, No_overflow # diff sign bit -> no overflow
+ addiu dataTemp, dataTemp, imm
+ move dest, dataTemp
+ xori cmpTemp, dataTemp, imm
+ bgez cmpTemp, No_overflow # same sign big -> no overflow
+ nop
+ b Overflow
+ nop
+ nop
+ nop
+ nop
+ nop
+ No_overflow:
+ */
+ if (imm.m_value >= -32768 && imm.m_value <= 32767 && !m_fixedWidth) {
+ load32(dest.m_ptr, dataTempRegister);
+ m_assembler.xori(cmpTempRegister, dataTempRegister, imm.m_value);
+ m_assembler.bltz(cmpTempRegister, 10);
+ m_assembler.addiu(dataTempRegister, dataTempRegister, imm.m_value);
+ store32(dataTempRegister, dest.m_ptr);
+ m_assembler.xori(cmpTempRegister, dataTempRegister, imm.m_value);
+ m_assembler.bgez(cmpTempRegister, 7);
+ m_assembler.nop();
+ } else {
+ load32(dest.m_ptr, dataTempRegister);
+ move(imm, immTempRegister);
+ m_assembler.xorInsn(cmpTempRegister, dataTempRegister, immTempRegister);
+ m_assembler.bltz(cmpTempRegister, 10);
+ m_assembler.addiu(dataTempRegister, dataTempRegister, immTempRegister);
+ store32(dataTempRegister, dest.m_ptr);
+ m_assembler.xori(cmpTempRegister, dataTempRegister, immTempRegister);
+ m_assembler.bgez(cmpTempRegister, 7);
+ m_assembler.nop();
+ }
+ return jump();
+ }
+ move(imm, immTempRegister);
+ load32(dest.m_ptr, dataTempRegister);
+ add32(immTempRegister, dataTempRegister);
+ store32(dataTempRegister, dest.m_ptr);
+ if (cond == Signed) {
+ // Check if dest is negative.
+ m_assembler.slt(cmpTempRegister, dataTempRegister, MIPSRegisters::zero);
+ return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
+ }
+ if (cond == Zero)
+ return branchEqual(dataTempRegister, MIPSRegisters::zero);
+ if (cond == NonZero)
+ return branchNotEqual(dataTempRegister, MIPSRegisters::zero);
+ ASSERT(0);
+ return Jump();
+ }
+
+ Jump branchMul32(ResultCondition cond, RegisterID src1, RegisterID src2, RegisterID dest)
+ {
+ ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
+ if (cond == Overflow) {
+ /*
+ mult src, dest
+ mfhi dataTemp
+ mflo dest
+ sra addrTemp, dest, 31
+ beq dataTemp, addrTemp, No_overflow # all sign bits (bit 63 to bit 31) are the same -> no overflow
+ nop
+ b Overflow
+ nop
+ nop
+ nop
+ nop
+ nop
+ No_overflow:
+ */
+ m_assembler.mult(src1, src2);
+ m_assembler.mfhi(dataTempRegister);
+ m_assembler.mflo(dest);
+ m_assembler.sra(addrTempRegister, dest, 31);
+ m_assembler.beq(dataTempRegister, addrTempRegister, 7);
+ m_assembler.nop();
+ return jump();
+ }
+ if (cond == Signed) {
+ mul32(src1, src2, dest);
+ // Check if dest is negative.
+ m_assembler.slt(cmpTempRegister, dest, MIPSRegisters::zero);
+ return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
+ }
+ if (cond == Zero) {
+ mul32(src1, src2, dest);
+ return branchEqual(dest, MIPSRegisters::zero);
+ }
+ if (cond == NonZero) {
+ mul32(src1, src2, dest);
+ return branchNotEqual(dest, MIPSRegisters::zero);
+ }
+ ASSERT(0);
+ return Jump();
+ }
+
Jump branchMul32(ResultCondition cond, RegisterID src, RegisterID dest)
{
ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
@@ -1447,8 +1743,7 @@ public:
Jump branchMul32(ResultCondition cond, TrustedImm32 imm, RegisterID src, RegisterID dest)
{
move(imm, immTempRegister);
- move(src, dest);
- return branchMul32(cond, immTempRegister, dest);
+ return branchMul32(cond, immTempRegister, src, dest);
}
Jump branchSub32(ResultCondition cond, RegisterID src, RegisterID dest)
@@ -1507,8 +1802,60 @@ public:
Jump branchSub32(ResultCondition cond, RegisterID src, TrustedImm32 imm, RegisterID dest)
{
move(imm, immTempRegister);
- move(src, dest);
- return branchSub32(cond, immTempRegister, dest);
+ return branchSub32(cond, src, immTempRegister, dest);
+ }
+
+ Jump branchSub32(ResultCondition cond, RegisterID op1, RegisterID op2, RegisterID dest)
+ {
+ ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
+ if (cond == Overflow) {
+ /*
+ move dataTemp, op1
+ xor cmpTemp, dataTemp, op2
+ bgez cmpTemp, No_overflow # same sign bit -> no overflow
+ subu dest, dataTemp, op2
+ xor cmpTemp, dest, dataTemp
+ bgez cmpTemp, No_overflow # same sign bit -> no overflow
+ nop
+ b Overflow
+ nop
+ nop
+ nop
+ nop
+ nop
+ No_overflow:
+ */
+ move(op1, dataTempRegister);
+ m_assembler.xorInsn(cmpTempRegister, dataTempRegister, op2);
+ m_assembler.bgez(cmpTempRegister, 10);
+ m_assembler.subu(dest, dataTempRegister, op2);
+ m_assembler.xorInsn(cmpTempRegister, dest, dataTempRegister);
+ m_assembler.bgez(cmpTempRegister, 7);
+ m_assembler.nop();
+ return jump();
+ }
+ if (cond == Signed) {
+ sub32(op1, op2, dest);
+ // Check if dest is negative.
+ m_assembler.slt(cmpTempRegister, dest, MIPSRegisters::zero);
+ return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
+ }
+ if (cond == Zero) {
+ sub32(op1, op2, dest);
+ return branchEqual(dest, MIPSRegisters::zero);
+ }
+ if (cond == NonZero) {
+ sub32(op1, op2, dest);
+ return branchNotEqual(dest, MIPSRegisters::zero);
+ }
+ ASSERT(0);
+ return Jump();
+ }
+
+ Jump branchNeg32(ResultCondition cond, RegisterID srcDest)
+ {
+ m_assembler.li(dataTempRegister, -1);
+ return branchMul32(cond, dataTempRegister, srcDest);
}
Jump branchOr32(ResultCondition cond, RegisterID src, RegisterID dest)
@@ -1560,7 +1907,8 @@ public:
Call call(RegisterID target)
{
- m_assembler.jalr(target);
+ move(target, MIPSRegisters::t9);
+ m_assembler.jalr(MIPSRegisters::t9);
m_assembler.nop();
return Call(m_assembler.label(), Call::None);
}
@@ -1804,7 +2152,7 @@ public:
lui immTemp, (address.offset + 0x8000) >> 16
addu addrTemp, addrTemp, immTemp
lwc1 dest, (address.offset & 0xffff)(at)
- lwc1 dest+4, (address.offset & 0xffff + 4)(at)
+ lwc1 dest+1, (address.offset & 0xffff + 4)(at)
*/
m_assembler.sll(addrTempRegister, address.index, address.scale);
m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
@@ -1991,6 +2339,19 @@ public:
#endif
}
+ void moveDouble(FPRegisterID src, FPRegisterID dest)
+ {
+ if (src != dest || m_fixedWidth)
+ m_assembler.movd(dest, src);
+ }
+
+ void swapDouble(FPRegisterID fr1, FPRegisterID fr2)
+ {
+ moveDouble(fr1, fpTempRegister);
+ moveDouble(fr2, fr1);
+ moveDouble(fpTempRegister, fr2);
+ }
+
void addDouble(FPRegisterID src, FPRegisterID dest)
{
m_assembler.addd(dest, dest, src);
@@ -2018,6 +2379,11 @@ public:
m_assembler.subd(dest, dest, src);
}
+ void subDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
+ {
+ m_assembler.subd(dest, op1, op2);
+ }
+
void subDouble(Address src, FPRegisterID dest)
{
loadDouble(src, fpTempRegister);
@@ -2035,11 +2401,32 @@ public:
m_assembler.muld(dest, dest, fpTempRegister);
}
+ void mulDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
+ {
+ m_assembler.muld(dest, op1, op2);
+ }
+
void divDouble(FPRegisterID src, FPRegisterID dest)
{
m_assembler.divd(dest, dest, src);
}
+ void divDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
+ {
+ m_assembler.divd(dest, op1, op2);
+ }
+
+ void divDouble(Address src, FPRegisterID dest)
+ {
+ loadDouble(src, fpTempRegister);
+ m_assembler.divd(dest, dest, fpTempRegister);
+ }
+
+ void negateDouble(FPRegisterID src, FPRegisterID dest)
+ {
+ m_assembler.negd(dest, src);
+ }
+
void convertInt32ToDouble(RegisterID src, FPRegisterID dest)
{
m_assembler.mtc1(src, fpTempRegister);
@@ -2099,6 +2486,8 @@ public:
Jump branchEqual(RegisterID rs, RegisterID rt)
{
+ m_assembler.nop();
+ m_assembler.nop();
m_assembler.appendJump();
m_assembler.beq(rs, rt, 0);
m_assembler.nop();
@@ -2108,6 +2497,8 @@ public:
Jump branchNotEqual(RegisterID rs, RegisterID rt)
{
+ m_assembler.nop();
+ m_assembler.nop();
m_assembler.appendJump();
m_assembler.bne(rs, rt, 0);
m_assembler.nop();
@@ -2174,11 +2565,33 @@ public:
// If the result is not representable as a 32 bit value, branch.
// May also branch for some values that are representable in 32 bits
// (specifically, in this case, INT_MAX 0x7fffffff).
- Jump branchTruncateDoubleToInt32(FPRegisterID src, RegisterID dest)
+ enum BranchTruncateType { BranchIfTruncateFailed, BranchIfTruncateSuccessful };
+ Jump branchTruncateDoubleToInt32(FPRegisterID src, RegisterID dest, BranchTruncateType branchType = BranchIfTruncateFailed)
+ {
+ m_assembler.truncwd(fpTempRegister, src);
+ m_assembler.mfc1(dest, fpTempRegister);
+ return branch32(branchType == BranchIfTruncateFailed ? Equal : NotEqual, dest, TrustedImm32(0x7fffffff));
+ }
+
+ Jump branchTruncateDoubleToUint32(FPRegisterID src, RegisterID dest, BranchTruncateType branchType = BranchIfTruncateFailed)
+ {
+ m_assembler.truncwd(fpTempRegister, src);
+ m_assembler.mfc1(dest, fpTempRegister);
+ return branch32(branchType == BranchIfTruncateFailed ? Equal : NotEqual, dest, TrustedImm32(0));
+ }
+
+ // Result is undefined if the value is outside of the integer range.
+ void truncateDoubleToInt32(FPRegisterID src, RegisterID dest)
+ {
+ m_assembler.truncwd(fpTempRegister, src);
+ m_assembler.mfc1(dest, fpTempRegister);
+ }
+
+ // Result is undefined if src > 2^31
+ void truncateDoubleToUint32(FPRegisterID src, RegisterID dest)
{
m_assembler.truncwd(fpTempRegister, src);
m_assembler.mfc1(dest, fpTempRegister);
- return branch32(Equal, dest, TrustedImm32(0x7fffffff));
}
// Convert 'src' to an integer, and places the resulting 'dest'.
@@ -2200,28 +2613,43 @@ public:
Jump branchDoubleNonZero(FPRegisterID reg, FPRegisterID scratch)
{
-#if WTF_MIPS_ISA_REV(2) && WTF_MIPS_FP64
- m_assembler.mtc1(MIPSRegisters::zero, scratch);
- m_assembler.mthc1(MIPSRegisters::zero, scratch);
-#else
- m_assembler.mtc1(MIPSRegisters::zero, scratch);
- m_assembler.mtc1(MIPSRegisters::zero, FPRegisterID(scratch + 1));
-#endif
+ m_assembler.vmov(scratch, MIPSRegisters::zero, MIPSRegisters::zero);
return branchDouble(DoubleNotEqual, reg, scratch);
}
Jump branchDoubleZeroOrNaN(FPRegisterID reg, FPRegisterID scratch)
{
-#if WTF_MIPS_ISA_REV(2) && WTF_MIPS_FP64
- m_assembler.mtc1(MIPSRegisters::zero, scratch);
- m_assembler.mthc1(MIPSRegisters::zero, scratch);
-#else
- m_assembler.mtc1(MIPSRegisters::zero, scratch);
- m_assembler.mtc1(MIPSRegisters::zero, FPRegisterID(scratch + 1));
-#endif
+ m_assembler.vmov(scratch, MIPSRegisters::zero, MIPSRegisters::zero);
return branchDouble(DoubleEqualOrUnordered, reg, scratch);
}
+ // Invert a relational condition, e.g. == becomes !=, < becomes >=, etc.
+ static RelationalCondition invert(RelationalCondition cond)
+ {
+ RelationalCondition r;
+ if (cond == Equal)
+ r = NotEqual;
+ else if (cond == NotEqual)
+ r = Equal;
+ else if (cond == Above)
+ r = BelowOrEqual;
+ else if (cond == AboveOrEqual)
+ r = Below;
+ else if (cond == Below)
+ r = AboveOrEqual;
+ else if (cond == BelowOrEqual)
+ r = Above;
+ else if (cond == GreaterThan)
+ r = LessThanOrEqual;
+ else if (cond == GreaterThanOrEqual)
+ r = LessThan;
+ else if (cond == LessThan)
+ r = GreaterThanOrEqual;
+ else if (cond == LessThanOrEqual)
+ r = GreaterThan;
+ return r;
+ }
+
void nop()
{
m_assembler.nop();
@@ -2234,12 +2662,12 @@ public:
static void replaceWithJump(CodeLocationLabel instructionStart, CodeLocationLabel destination)
{
- ASSERT_NOT_REACHED();
+ MIPSAssembler::replaceWithJump(instructionStart.dataLocation(), destination.dataLocation());
}
static ptrdiff_t maxJumpReplacementSize()
{
- ASSERT_NOT_REACHED();
+ MIPSAssembler::maxJumpReplacementSize();
return 0;
}