diff options
Diffstat (limited to 'Source/JavaScriptCore')
21 files changed, 1970 insertions, 93 deletions
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog index d21e34a30..df3f15070 100644 --- a/Source/JavaScriptCore/ChangeLog +++ b/Source/JavaScriptCore/ChangeLog @@ -1,3 +1,140 @@ +2013-04-09 Balazs Kilvady <kilvadyb@homejinni.com> + + LLInt conditional branch compilation fault on MIPS. + https://bugs.webkit.org/show_bug.cgi?id=114264 + + Reviewed by Filip Pizlo. + + Fix conditional branch compilation in LLInt offlineasm. + + * offlineasm/mips.rb: + +2013-02-18 Balazs Kilvady <kilvadyb@homejinni.com> + + MIPS DFG implementation. + https://bugs.webkit.org/show_bug.cgi?id=101328 + + Reviewed by Oliver Hunt. + + DFG implementation for MIPS. + + * assembler/MIPSAssembler.h: + (JSC::MIPSAssembler::MIPSAssembler): + (JSC::MIPSAssembler::sllv): + (JSC::MIPSAssembler::movd): + (MIPSAssembler): + (JSC::MIPSAssembler::negd): + (JSC::MIPSAssembler::labelForWatchpoint): + (JSC::MIPSAssembler::label): + (JSC::MIPSAssembler::vmov): + (JSC::MIPSAssembler::linkDirectJump): + (JSC::MIPSAssembler::maxJumpReplacementSize): + (JSC::MIPSAssembler::revertJumpToMove): + (JSC::MIPSAssembler::replaceWithJump): + * assembler/MacroAssembler.h: + (MacroAssembler): + (JSC::MacroAssembler::poke): + * assembler/MacroAssemblerMIPS.h: + (JSC::MacroAssemblerMIPS::add32): + (MacroAssemblerMIPS): + (JSC::MacroAssemblerMIPS::and32): + (JSC::MacroAssemblerMIPS::lshift32): + (JSC::MacroAssemblerMIPS::mul32): + (JSC::MacroAssemblerMIPS::or32): + (JSC::MacroAssemblerMIPS::rshift32): + (JSC::MacroAssemblerMIPS::urshift32): + (JSC::MacroAssemblerMIPS::sub32): + (JSC::MacroAssemblerMIPS::xor32): + (JSC::MacroAssemblerMIPS::store32): + (JSC::MacroAssemblerMIPS::jump): + (JSC::MacroAssemblerMIPS::branchAdd32): + (JSC::MacroAssemblerMIPS::branchMul32): + (JSC::MacroAssemblerMIPS::branchSub32): + (JSC::MacroAssemblerMIPS::branchNeg32): + (JSC::MacroAssemblerMIPS::call): + (JSC::MacroAssemblerMIPS::loadDouble): + (JSC::MacroAssemblerMIPS::moveDouble): + (JSC::MacroAssemblerMIPS::swapDouble): + (JSC::MacroAssemblerMIPS::subDouble): + (JSC::MacroAssemblerMIPS::mulDouble): + (JSC::MacroAssemblerMIPS::divDouble): + (JSC::MacroAssemblerMIPS::negateDouble): + (JSC::MacroAssemblerMIPS::branchEqual): + (JSC::MacroAssemblerMIPS::branchNotEqual): + (JSC::MacroAssemblerMIPS::branchTruncateDoubleToInt32): + (JSC::MacroAssemblerMIPS::branchTruncateDoubleToUint32): + (JSC::MacroAssemblerMIPS::truncateDoubleToInt32): + (JSC::MacroAssemblerMIPS::truncateDoubleToUint32): + (JSC::MacroAssemblerMIPS::branchDoubleNonZero): + (JSC::MacroAssemblerMIPS::branchDoubleZeroOrNaN): + (JSC::MacroAssemblerMIPS::invert): + (JSC::MacroAssemblerMIPS::replaceWithJump): + (JSC::MacroAssemblerMIPS::maxJumpReplacementSize): + * dfg/DFGAssemblyHelpers.h: + (AssemblyHelpers): + (JSC::DFG::AssemblyHelpers::preserveReturnAddressAfterCall): + (JSC::DFG::AssemblyHelpers::restoreReturnAddressBeforeReturn): + (JSC::DFG::AssemblyHelpers::debugCall): + * dfg/DFGCCallHelpers.h: + (CCallHelpers): + (JSC::DFG::CCallHelpers::setupArguments): + (JSC::DFG::CCallHelpers::setupArgumentsWithExecState): + * dfg/DFGFPRInfo.h: + (DFG): + (FPRInfo): + (JSC::DFG::FPRInfo::toRegister): + (JSC::DFG::FPRInfo::toIndex): + (JSC::DFG::FPRInfo::debugName): + * dfg/DFGGPRInfo.h: + (DFG): + (GPRInfo): + (JSC::DFG::GPRInfo::toRegister): + (JSC::DFG::GPRInfo::toIndex): + (JSC::DFG::GPRInfo::debugName): + * dfg/DFGSpeculativeJIT.h: + (SpeculativeJIT): + * jit/JSInterfaceJIT.h: + (JSInterfaceJIT): + * runtime/JSGlobalData.h: + (JSC::ScratchBuffer::allocationSize): + (ScratchBuffer): + +2013-02-01 Balazs Kilvady <kilvadyb@homejinni.com> + + offlineasm BaseIndex handling is broken on ARM due to MIPS changes + https://bugs.webkit.org/show_bug.cgi?id=108261 + + Reviewed by Filip Pizlo. + + offlineasm BaseIndex handling fix on MIPS. + + * offlineasm/mips.rb: + * offlineasm/risc.rb: + +2013-01-07 Balazs Kilvady <kilvadyb@homejinni.com> + + MIPS LLInt implementation. + https://bugs.webkit.org/show_bug.cgi?id=99706 + + Reviewed by Filip Pizlo. + + LLInt implementation for MIPS. + + * assembler/MacroAssemblerMIPS.h: + (JSC::MacroAssemblerMIPS::jump): + * dfg/DFGOperations.cpp: + (JSC): + * jit/JITStubs.cpp: + (JSC): + * jit/JITStubs.h: + (JITStackFrame): + * llint/LLIntOfflineAsmConfig.h: + * llint/LowLevelInterpreter.asm: + * llint/LowLevelInterpreter32_64.asm: + * offlineasm/backends.rb: + * offlineasm/instructions.rb: + * offlineasm/mips.rb: Added. + 2013-02-27 Simon Hausmann <simon.hausmann@digia.com> [Qt][Mac] Fix massive parallel builds 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 4f81b4599..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) { /* @@ -1304,7 +1439,8 @@ public: void jump(RegisterID target) { - m_assembler.jr(target); + move(target, MIPSRegisters::t9); + m_assembler.jr(MIPSRegisters::t9); m_assembler.nop(); } @@ -1317,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); @@ -1385,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); @@ -1398,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)); @@ -1446,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) @@ -1506,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) @@ -1559,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); } @@ -1803,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); @@ -1990,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); @@ -2017,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); @@ -2034,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); @@ -2098,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(); @@ -2107,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(); @@ -2173,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'. @@ -2199,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(); @@ -2233,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; } diff --git a/Source/JavaScriptCore/dfg/DFGAssemblyHelpers.h b/Source/JavaScriptCore/dfg/DFGAssemblyHelpers.h index 75b9c7072..c060179a8 100644 --- a/Source/JavaScriptCore/dfg/DFGAssemblyHelpers.h +++ b/Source/JavaScriptCore/dfg/DFGAssemblyHelpers.h @@ -93,6 +93,23 @@ public: } #endif +#if CPU(MIPS) + ALWAYS_INLINE void preserveReturnAddressAfterCall(RegisterID reg) + { + move(returnAddressRegister, reg); + } + + ALWAYS_INLINE void restoreReturnAddressBeforeReturn(RegisterID reg) + { + move(reg, returnAddressRegister); + } + + ALWAYS_INLINE void restoreReturnAddressBeforeReturn(Address address) + { + loadPtr(address, returnAddressRegister); + } +#endif + void emitGetFromCallFrameHeaderPtr(JSStack::CallFrameHeaderEntry entry, GPRReg to) { loadPtr(Address(GPRInfo::callFrameRegister, entry * sizeof(Register)), to); @@ -193,7 +210,7 @@ public: move(TrustedImmPtr(scratchBuffer->activeLengthPtr()), GPRInfo::regT0); storePtr(TrustedImmPtr(scratchSize), GPRInfo::regT0); -#if CPU(X86_64) || CPU(ARM) +#if CPU(X86_64) || CPU(ARM) || CPU(MIPS) move(TrustedImmPtr(argument), GPRInfo::argumentGPR1); move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0); GPRReg scratch = selectScratchGPR(GPRInfo::argumentGPR0, GPRInfo::argumentGPR1); diff --git a/Source/JavaScriptCore/dfg/DFGCCallHelpers.h b/Source/JavaScriptCore/dfg/DFGCCallHelpers.h index 8adde0598..3d99f6feb 100644 --- a/Source/JavaScriptCore/dfg/DFGCCallHelpers.h +++ b/Source/JavaScriptCore/dfg/DFGCCallHelpers.h @@ -576,6 +576,39 @@ public: poke(GPRInfo::nonArgGPR0); } #endif // CPU(ARM_HARDFP) +#elif CPU(MIPS) + ALWAYS_INLINE void setupArguments(FPRReg arg1) + { + moveDouble(arg1, FPRInfo::argumentFPR0); + } + + ALWAYS_INLINE void setupArguments(FPRReg arg1, FPRReg arg2) + { + if (arg2 != FPRInfo::argumentFPR0) { + moveDouble(arg1, FPRInfo::argumentFPR0); + moveDouble(arg2, FPRInfo::argumentFPR1); + } else if (arg1 != FPRInfo::argumentFPR1) { + moveDouble(arg2, FPRInfo::argumentFPR1); + moveDouble(arg1, FPRInfo::argumentFPR0); + } else { + // Swap arg1, arg2. + swapDouble(FPRInfo::argumentFPR0, FPRInfo::argumentFPR1); + } + } + + ALWAYS_INLINE void setupArgumentsWithExecState(FPRReg arg1, GPRReg arg2) + { + assembler().vmov(GPRInfo::argumentGPR2, GPRInfo::argumentGPR3, arg1); + move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0); + poke(arg2, 4); + } + + ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, FPRReg arg3) + { + setupStubArguments(arg1, arg2); + move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0); + poke(arg3, 4); + } #else #error "DFG JIT not supported on this platform." #endif @@ -803,119 +836,126 @@ public: // These methods are suitable for any calling convention that provides for // exactly 4 argument registers, e.g. ARMv7. #if NUMBER_OF_ARGUMENT_REGISTERS == 4 + +#if CPU(MIPS) +#define POKE_ARGUMENT_OFFSET 4 +#else +#define POKE_ARGUMENT_OFFSET 0 +#endif + ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, GPRReg arg3, GPRReg arg4) { - poke(arg4); + poke(arg4, POKE_ARGUMENT_OFFSET); setupArgumentsWithExecState(arg1, arg2, arg3); } ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, GPRReg arg3, TrustedImm32 arg4) { - poke(arg4); + poke(arg4, POKE_ARGUMENT_OFFSET); setupArgumentsWithExecState(arg1, arg2, arg3); } ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, TrustedImmPtr arg2, TrustedImm32 arg3, GPRReg arg4) { - poke(arg4); + poke(arg4, POKE_ARGUMENT_OFFSET); setupArgumentsWithExecState(arg1, arg2, arg3); } ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, TrustedImmPtr arg2, TrustedImm32 arg3, GPRReg arg4, GPRReg arg5) { - poke(arg5, 1); - poke(arg4); + poke(arg5, POKE_ARGUMENT_OFFSET + 1); + poke(arg4, POKE_ARGUMENT_OFFSET); setupArgumentsWithExecState(arg1, arg2, arg3); } ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, TrustedImm32 arg3, TrustedImm32 arg4) { - poke(arg4); + poke(arg4, POKE_ARGUMENT_OFFSET); setupArgumentsWithExecState(arg1, arg2, arg3); } ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImm32 arg1, TrustedImm32 arg2, GPRReg arg3, GPRReg arg4) { - poke(arg4); + poke(arg4, POKE_ARGUMENT_OFFSET); setupArgumentsWithExecState(arg1, arg2, arg3); } ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, GPRReg arg3, TrustedImmPtr arg4) { - poke(arg4); + poke(arg4, POKE_ARGUMENT_OFFSET); setupArgumentsWithExecState(arg1, arg2, arg3); } ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, GPRReg arg3, GPRReg arg4, GPRReg arg5) { - poke(arg5, 1); - poke(arg4); + poke(arg5, POKE_ARGUMENT_OFFSET + 1); + poke(arg4, POKE_ARGUMENT_OFFSET); setupArgumentsWithExecState(arg1, arg2, arg3); } ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImm32 arg1, GPRReg arg2, GPRReg arg3, GPRReg arg4) { - poke(arg4); + poke(arg4, POKE_ARGUMENT_OFFSET); setupArgumentsWithExecState(arg1, arg2, arg3); } ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImm32 arg1, GPRReg arg2, GPRReg arg3, TrustedImmPtr arg4) { - poke(arg4); + poke(arg4, POKE_ARGUMENT_OFFSET); setupArgumentsWithExecState(arg1, arg2, arg3); } ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImm32 arg1, GPRReg arg2, TrustedImm32 arg3, TrustedImmPtr arg4) { - poke(arg4); + poke(arg4, POKE_ARGUMENT_OFFSET); setupArgumentsWithExecState(arg1, arg2, arg3); } ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImm32 arg1, GPRReg arg2, TrustedImm32 arg3, GPRReg arg4) { - poke(arg4); + poke(arg4, POKE_ARGUMENT_OFFSET); setupArgumentsWithExecState(arg1, arg2, arg3); } ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, TrustedImm32 arg3, GPRReg arg4, GPRReg arg5) { - poke(arg5, 1); - poke(arg4); + poke(arg5, POKE_ARGUMENT_OFFSET + 1); + poke(arg4, POKE_ARGUMENT_OFFSET); setupArgumentsWithExecState(arg1, arg2, arg3); } ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, TrustedImm32 arg3, GPRReg arg4, TrustedImm32 arg5) { - poke(arg5, 1); - poke(arg4); + poke(arg5, POKE_ARGUMENT_OFFSET + 1); + poke(arg4, POKE_ARGUMENT_OFFSET); setupArgumentsWithExecState(arg1, arg2, arg3); } ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImm32 arg1, GPRReg arg2, GPRReg arg3, GPRReg arg4, TrustedImmPtr arg5) { - poke(arg5, 1); - poke(arg4); + poke(arg5, POKE_ARGUMENT_OFFSET + 1); + poke(arg4, POKE_ARGUMENT_OFFSET); setupArgumentsWithExecState(arg1, arg2, arg3); } ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImm32 arg1, GPRReg arg2, GPRReg arg3, TrustedImm32 arg4, TrustedImm32 arg5) { - poke(arg5, 1); - poke(arg4); + poke(arg5, POKE_ARGUMENT_OFFSET + 1); + poke(arg4, POKE_ARGUMENT_OFFSET); setupArgumentsWithExecState(arg1, arg2, arg3); } ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImm32 arg1, TrustedImm32 arg2, TrustedImm32 arg3, GPRReg arg4, GPRReg arg5) { - poke(arg5, 1); - poke(arg4); + poke(arg5, POKE_ARGUMENT_OFFSET + 1); + poke(arg4, POKE_ARGUMENT_OFFSET); setupArgumentsWithExecState(arg1, arg2, arg3); } ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImm32 arg1, GPRReg arg2, GPRReg arg3, GPRReg arg4, GPRReg arg5) { - poke(arg5, 1); - poke(arg4); + poke(arg5, POKE_ARGUMENT_OFFSET + 1); + poke(arg4, POKE_ARGUMENT_OFFSET); setupArgumentsWithExecState(arg1, arg2, arg3); } diff --git a/Source/JavaScriptCore/dfg/DFGFPRInfo.h b/Source/JavaScriptCore/dfg/DFGFPRInfo.h index d6a038a99..6f968e282 100644 --- a/Source/JavaScriptCore/dfg/DFGFPRInfo.h +++ b/Source/JavaScriptCore/dfg/DFGFPRInfo.h @@ -164,6 +164,74 @@ public: #endif +#if CPU(MIPS) + +class FPRInfo { +public: + typedef FPRReg RegisterType; + static const unsigned numberOfRegisters = 6; + + // Temporary registers. + static const FPRReg fpRegT0 = MIPSRegisters::f0; + static const FPRReg fpRegT1 = MIPSRegisters::f4; + static const FPRReg fpRegT2 = MIPSRegisters::f6; + static const FPRReg fpRegT3 = MIPSRegisters::f8; + static const FPRReg fpRegT4 = MIPSRegisters::f10; + static const FPRReg fpRegT5 = MIPSRegisters::f18; + + static const FPRReg returnValueFPR = MIPSRegisters::f0; + + static const FPRReg argumentFPR0 = MIPSRegisters::f12; + static const FPRReg argumentFPR1 = MIPSRegisters::f14; + + static FPRReg toRegister(unsigned index) + { + static const FPRReg registerForIndex[numberOfRegisters] = { + fpRegT0, fpRegT1, fpRegT2, fpRegT3, fpRegT4, fpRegT5 }; + + ASSERT(index < numberOfRegisters); + return registerForIndex[index]; + } + + static unsigned toIndex(FPRReg reg) + { + ASSERT(reg != InvalidFPRReg); + ASSERT(reg < 20); + static const unsigned indexForRegister[20] = { + 0, InvalidIndex, InvalidIndex, InvalidIndex, + 1, InvalidIndex, 2, InvalidIndex, + 3, InvalidIndex, 4, InvalidIndex, + InvalidIndex, InvalidIndex, InvalidIndex, InvalidIndex, + InvalidIndex, InvalidIndex, 5, InvalidIndex, + }; + unsigned result = indexForRegister[reg]; + ASSERT(result != InvalidIndex); + return result; + } + + static const char* debugName(FPRReg reg) + { + ASSERT(reg != InvalidFPRReg); + ASSERT(reg < 32); + static const char* nameForRegister[32] = { + "f0", "f1", "f2", "f3", + "f4", "f5", "f6", "f7", + "f8", "f9", "f10", "f11", + "f12", "f13", "f14", "f15" + "f16", "f17", "f18", "f19" + "f20", "f21", "f22", "f23" + "f24", "f25", "f26", "f27" + "f28", "f29", "f30", "f31" + }; + return nameForRegister[reg]; + } +private: + + static const unsigned InvalidIndex = 0xffffffff; +}; + +#endif + typedef RegisterBank<FPRInfo>::iterator fpr_iterator; } } // namespace JSC::DFG diff --git a/Source/JavaScriptCore/dfg/DFGGPRInfo.h b/Source/JavaScriptCore/dfg/DFGGPRInfo.h index 3d07556cc..aa634cd15 100644 --- a/Source/JavaScriptCore/dfg/DFGGPRInfo.h +++ b/Source/JavaScriptCore/dfg/DFGGPRInfo.h @@ -461,6 +461,73 @@ private: #endif +#if CPU(MIPS) +#define NUMBER_OF_ARGUMENT_REGISTERS 4 + +class GPRInfo { +public: + typedef GPRReg RegisterType; + static const unsigned numberOfRegisters = 6; + + // Temporary registers. + static const GPRReg regT0 = MIPSRegisters::v0; + static const GPRReg regT1 = MIPSRegisters::v1; + static const GPRReg regT2 = MIPSRegisters::t4; + static const GPRReg regT3 = MIPSRegisters::t5; + static const GPRReg regT4 = MIPSRegisters::t6; + static const GPRReg regT5 = MIPSRegisters::t7; + // These registers match the baseline JIT. + static const GPRReg cachedResultRegister = regT0; + static const GPRReg cachedResultRegister2 = regT1; + static const GPRReg callFrameRegister = MIPSRegisters::s0; + // These constants provide the names for the general purpose argument & return value registers. + static const GPRReg argumentGPR0 = MIPSRegisters::a0; + static const GPRReg argumentGPR1 = MIPSRegisters::a1; + static const GPRReg argumentGPR2 = MIPSRegisters::a2; + static const GPRReg argumentGPR3 = MIPSRegisters::a3; + static const GPRReg nonArgGPR0 = regT2; + static const GPRReg nonArgGPR1 = regT3; + static const GPRReg nonArgGPR2 = regT4; + static const GPRReg returnValueGPR = regT0; + static const GPRReg returnValueGPR2 = regT1; + static const GPRReg nonPreservedNonReturnGPR = regT5; + + static GPRReg toRegister(unsigned index) + { + ASSERT(index < numberOfRegisters); + static const GPRReg registerForIndex[numberOfRegisters] = { regT0, regT1, regT2, regT3, regT4, regT5 }; + return registerForIndex[index]; + } + + static unsigned toIndex(GPRReg reg) + { + ASSERT(reg != InvalidGPRReg); + ASSERT(reg < 16); + static const unsigned indexForRegister[16] = { InvalidIndex, InvalidIndex, 0, 1, InvalidIndex, InvalidIndex, InvalidIndex, InvalidIndex, InvalidIndex, InvalidIndex, InvalidIndex, InvalidIndex, 2, 3, 4, 5 }; + unsigned result = indexForRegister[reg]; + ASSERT(result != InvalidIndex); + return result; + } + + static const char* debugName(GPRReg reg) + { + ASSERT(reg != InvalidGPRReg); + ASSERT(reg < 16); + static const char* nameForRegister[16] = { + "zero", "at", "v0", "v1", + "a0", "a1", "a2", "a3", + "t0", "t1", "t2", "t3", + "t4", "t5", "t6", "t7" + }; + return nameForRegister[reg]; + } +private: + + static const unsigned InvalidIndex = 0xffffffff; +}; + +#endif + typedef RegisterBank<GPRInfo>::iterator gpr_iterator; } } // namespace JSC::DFG diff --git a/Source/JavaScriptCore/dfg/DFGOperations.cpp b/Source/JavaScriptCore/dfg/DFGOperations.cpp index ad595ae1b..bb9ccc37d 100644 --- a/Source/JavaScriptCore/dfg/DFGOperations.cpp +++ b/Source/JavaScriptCore/dfg/DFGOperations.cpp @@ -47,6 +47,18 @@ #if ENABLE(JIT) +#if CPU(MIPS) +#if WTF_MIPS_PIC +#define LOAD_FUNCTION_TO_T9(function) \ + ".set noreorder" "\n" \ + ".cpload $25" "\n" \ + ".set reorder" "\n" \ + "la $t9, " LOCAL_REFERENCE(function) "\n" +#else +#define LOAD_FUNCTION_TO_T9(function) "" "\n" +#endif +#endif + #if ENABLE(DFG_JIT) #if COMPILER(GCC) && CPU(X86_64) @@ -201,6 +213,52 @@ "b " LOCAL_REFERENCE(function) "WithReturnAddress" "\n" \ ); +#elif COMPILER(GCC) && CPU(MIPS) + +#define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_E(function) \ + asm( \ + ".text" "\n" \ + ".globl " SYMBOL_STRING(function) "\n" \ + HIDE_SYMBOL(function) "\n" \ + SYMBOL_STRING(function) ":" "\n" \ + LOAD_FUNCTION_TO_T9(function##WithReturnAddress) \ + "move $a1, $ra" "\n" \ + "b " LOCAL_REFERENCE(function) "WithReturnAddress" "\n" \ + ); + +#define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_ECI(function) \ + asm( \ + ".text" "\n" \ + ".globl " SYMBOL_STRING(function) "\n" \ + HIDE_SYMBOL(function) "\n" \ + SYMBOL_STRING(function) ":" "\n" \ + LOAD_FUNCTION_TO_T9(function##WithReturnAddress) \ + "move $a3, $ra" "\n" \ + "b " LOCAL_REFERENCE(function) "WithReturnAddress" "\n" \ + ); + +#define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJI(function) \ + asm( \ + ".text" "\n" \ + ".globl " SYMBOL_STRING(function) "\n" \ + HIDE_SYMBOL(function) "\n" \ + SYMBOL_STRING(function) ":" "\n" \ + LOAD_FUNCTION_TO_T9(function##WithReturnAddress) \ + "sw $ra, 20($sp)" "\n" \ + "b " LOCAL_REFERENCE(function) "WithReturnAddress" "\n" \ + ); + +#define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJCI(function) \ + asm( \ + ".text" "\n" \ + ".globl " SYMBOL_STRING(function) "\n" \ + HIDE_SYMBOL(function) "\n" \ + SYMBOL_STRING(function) ":" "\n" \ + LOAD_FUNCTION_TO_T9(function##WithReturnAddress) \ + "sw $ra, 24($sp)" "\n" \ + "b " LOCAL_REFERENCE(function) "WithReturnAddress" "\n" \ + ); + #endif #define P_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_E(function) \ @@ -1607,6 +1665,17 @@ SYMBOL_STRING(getHostCallReturnValue) ":" "\n" "mov r0, r5" "\n" "b " LOCAL_REFERENCE(getHostCallReturnValueWithExecState) "\n" ); +#elif COMPILER(GCC) && CPU(MIPS) +asm( +".text" "\n" +".globl " SYMBOL_STRING(getHostCallReturnValue) "\n" +HIDE_SYMBOL(getHostCallReturnValue) "\n" +SYMBOL_STRING(getHostCallReturnValue) ":" "\n" + LOAD_FUNCTION_TO_T9(getHostCallReturnValueWithExecState) + "lw $s0, -40($s0)" "\n" + "move $a0, $s0" "\n" + "b " LOCAL_REFERENCE(getHostCallReturnValueWithExecState) "\n" +); #endif extern "C" EncodedJSValue HOST_CALL_RETURN_VALUE_OPTION getHostCallReturnValueWithExecState(ExecState* exec) diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h index 5f6fe842c..949ddfe20 100644 --- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h +++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h @@ -1528,7 +1528,7 @@ public: // EncodedJSValue in JSVALUE32_64 is a 64-bit integer. When being compiled in ARM EABI, it must be aligned even-numbered register (r0, r2 or [sp]). // To avoid assemblies from using wrong registers, let's occupy r1 or r3 with a dummy argument when necessary. -#if COMPILER_SUPPORTS(EABI) && CPU(ARM) +#if (COMPILER_SUPPORTS(EABI) && CPU(ARM)) || CPU(MIPS) #define EABI_32BIT_DUMMY_ARG TrustedImm32(0), #else #define EABI_32BIT_DUMMY_ARG @@ -1963,7 +1963,7 @@ public: } #endif -#if !defined(NDEBUG) && !CPU(ARM) +#if !defined(NDEBUG) && !CPU(ARM) && !CPU(MIPS) void prepareForExternalCall() { // We're about to call out to a "native" helper function. The helper diff --git a/Source/JavaScriptCore/jit/JITStubs.cpp b/Source/JavaScriptCore/jit/JITStubs.cpp index 64acfeef5..168769c12 100644 --- a/Source/JavaScriptCore/jit/JITStubs.cpp +++ b/Source/JavaScriptCore/jit/JITStubs.cpp @@ -280,11 +280,13 @@ extern "C" { #define PRESERVED_S0_OFFSET 64 #define PRESERVED_S1_OFFSET 68 #define PRESERVED_S2_OFFSET 72 -#define PRESERVED_RETURN_ADDRESS_OFFSET 76 -#define THUNK_RETURN_ADDRESS_OFFSET 80 -#define REGISTER_FILE_OFFSET 84 -#define GLOBAL_DATA_OFFSET 100 -#define STACK_LENGTH 104 +#define PRESERVED_S3_OFFSET 76 +#define PRESERVED_S4_OFFSET 80 +#define PRESERVED_RETURN_ADDRESS_OFFSET 84 +#define THUNK_RETURN_ADDRESS_OFFSET 88 +#define REGISTER_FILE_OFFSET 92 +#define GLOBAL_DATA_OFFSET 108 +#define STACK_LENGTH 112 #elif CPU(SH4) #define SYMBOL_STRING(name) #name /* code (r4), JSStack* (r5), CallFrame* (r6), void* unused1 (r7), void* unused2(sp), JSGlobalData (sp)*/ @@ -527,6 +529,8 @@ asm ( SYMBOL_STRING(ctiTrampoline) ":" "\n" "addiu $29,$29,-" STRINGIZE_VALUE_OF(STACK_LENGTH) "\n" "sw $31," STRINGIZE_VALUE_OF(PRESERVED_RETURN_ADDRESS_OFFSET) "($29)" "\n" + "sw $20," STRINGIZE_VALUE_OF(PRESERVED_S4_OFFSET) "($29)" "\n" + "sw $19," STRINGIZE_VALUE_OF(PRESERVED_S3_OFFSET) "($29)" "\n" "sw $18," STRINGIZE_VALUE_OF(PRESERVED_S2_OFFSET) "($29)" "\n" "sw $17," STRINGIZE_VALUE_OF(PRESERVED_S1_OFFSET) "($29)" "\n" "sw $16," STRINGIZE_VALUE_OF(PRESERVED_S0_OFFSET) "($29)" "\n" @@ -543,12 +547,17 @@ SYMBOL_STRING(ctiTrampoline) ":" "\n" "lw $16," STRINGIZE_VALUE_OF(PRESERVED_S0_OFFSET) "($29)" "\n" "lw $17," STRINGIZE_VALUE_OF(PRESERVED_S1_OFFSET) "($29)" "\n" "lw $18," STRINGIZE_VALUE_OF(PRESERVED_S2_OFFSET) "($29)" "\n" + "lw $19," STRINGIZE_VALUE_OF(PRESERVED_S3_OFFSET) "($29)" "\n" + "lw $20," STRINGIZE_VALUE_OF(PRESERVED_S4_OFFSET) "($29)" "\n" "lw $31," STRINGIZE_VALUE_OF(PRESERVED_RETURN_ADDRESS_OFFSET) "($29)" "\n" "jr $31" "\n" "addiu $29,$29," STRINGIZE_VALUE_OF(STACK_LENGTH) "\n" ".set reorder" "\n" ".set macro" "\n" ".end " SYMBOL_STRING(ctiTrampoline) "\n" +".globl " SYMBOL_STRING(ctiTrampolineEnd) "\n" +HIDE_SYMBOL(ctiTrampolineEnd) "\n" +SYMBOL_STRING(ctiTrampolineEnd) ":" "\n" ); asm ( @@ -561,8 +570,8 @@ asm ( ".ent " SYMBOL_STRING(ctiVMThrowTrampoline) "\n" SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n" #if WTF_MIPS_PIC - "lw $28," STRINGIZE_VALUE_OF(PRESERVED_GP_OFFSET) "($29)" "\n" ".set macro" "\n" +".cpload $31" "\n" "la $25," SYMBOL_STRING(cti_vm_throw) "\n" ".set nomacro" "\n" "bal " SYMBOL_STRING(cti_vm_throw) "\n" @@ -574,6 +583,8 @@ SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n" "lw $16," STRINGIZE_VALUE_OF(PRESERVED_S0_OFFSET) "($29)" "\n" "lw $17," STRINGIZE_VALUE_OF(PRESERVED_S1_OFFSET) "($29)" "\n" "lw $18," STRINGIZE_VALUE_OF(PRESERVED_S2_OFFSET) "($29)" "\n" + "lw $19," STRINGIZE_VALUE_OF(PRESERVED_S3_OFFSET) "($29)" "\n" + "lw $20," STRINGIZE_VALUE_OF(PRESERVED_S4_OFFSET) "($29)" "\n" "lw $31," STRINGIZE_VALUE_OF(PRESERVED_RETURN_ADDRESS_OFFSET) "($29)" "\n" "jr $31" "\n" "addiu $29,$29," STRINGIZE_VALUE_OF(STACK_LENGTH) "\n" @@ -594,6 +605,8 @@ SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n" "lw $16," STRINGIZE_VALUE_OF(PRESERVED_S0_OFFSET) "($29)" "\n" "lw $17," STRINGIZE_VALUE_OF(PRESERVED_S1_OFFSET) "($29)" "\n" "lw $18," STRINGIZE_VALUE_OF(PRESERVED_S2_OFFSET) "($29)" "\n" + "lw $19," STRINGIZE_VALUE_OF(PRESERVED_S3_OFFSET) "($29)" "\n" + "lw $20," STRINGIZE_VALUE_OF(PRESERVED_S4_OFFSET) "($29)" "\n" "lw $31," STRINGIZE_VALUE_OF(PRESERVED_RETURN_ADDRESS_OFFSET) "($29)" "\n" "jr $31" "\n" "addiu $29,$29," STRINGIZE_VALUE_OF(STACK_LENGTH) "\n" @@ -1194,9 +1207,9 @@ template<typename T> static T throwExceptionFromOpCall(JITStackFrame& jitStackFr ".globl " SYMBOL_STRING(cti_##op) "\n" \ ".ent " SYMBOL_STRING(cti_##op) "\n" \ SYMBOL_STRING(cti_##op) ":" "\n" \ - "lw $28," STRINGIZE_VALUE_OF(PRESERVED_GP_OFFSET) "($29)" "\n" \ - "sw $31," STRINGIZE_VALUE_OF(THUNK_RETURN_ADDRESS_OFFSET) "($29)" "\n" \ ".set macro" "\n" \ + ".cpload $25" "\n" \ + "sw $31," STRINGIZE_VALUE_OF(THUNK_RETURN_ADDRESS_OFFSET) "($29)" "\n" \ "la $25," SYMBOL_STRING(JITStubThunked_##op) "\n" \ ".set nomacro" "\n" \ ".reloc 1f,R_MIPS_JALR," SYMBOL_STRING(JITStubThunked_##op) "\n" \ diff --git a/Source/JavaScriptCore/jit/JITStubs.h b/Source/JavaScriptCore/jit/JITStubs.h index fe64cd9bc..c03bc929e 100644 --- a/Source/JavaScriptCore/jit/JITStubs.h +++ b/Source/JavaScriptCore/jit/JITStubs.h @@ -256,6 +256,8 @@ namespace JSC { void* preservedS0; void* preservedS1; void* preservedS2; + void* preservedS3; + void* preservedS4; void* preservedReturnAddress; ReturnAddressPtr thunkReturnAddress; diff --git a/Source/JavaScriptCore/jit/JSInterfaceJIT.h b/Source/JavaScriptCore/jit/JSInterfaceJIT.h index ad546d963..7afdc06dc 100644 --- a/Source/JavaScriptCore/jit/JSInterfaceJIT.h +++ b/Source/JavaScriptCore/jit/JSInterfaceJIT.h @@ -129,6 +129,10 @@ namespace JSC { static const RegisterID cachedResultRegister = MIPSRegisters::v0; static const RegisterID firstArgumentRegister = MIPSRegisters::a0; +#if ENABLE(VALUE_PROFILER) + static const RegisterID bucketCounterRegister = MIPSRegisters::s3; +#endif + // regT0 must be v0 for returning a 32-bit value. static const RegisterID regT0 = MIPSRegisters::v0; diff --git a/Source/JavaScriptCore/llint/LLIntOfflineAsmConfig.h b/Source/JavaScriptCore/llint/LLIntOfflineAsmConfig.h index da2d510b5..157521373 100644 --- a/Source/JavaScriptCore/llint/LLIntOfflineAsmConfig.h +++ b/Source/JavaScriptCore/llint/LLIntOfflineAsmConfig.h @@ -38,6 +38,7 @@ #define OFFLINE_ASM_ARMv7 0 #define OFFLINE_ASM_X86_64 0 #define OFFLINE_ASM_ARMv7s 0 +#define OFFLINE_ASM_MIPS 0 #else // !ENABLE(LLINT_C_LOOP) @@ -67,6 +68,12 @@ #define OFFLINE_ASM_X86_64 0 #endif +#if CPU(MIPS) +#define OFFLINE_ASM_MIPS 1 +#else +#define OFFLINE_ASM_MIPS 0 +#endif + #endif // !ENABLE(LLINT_C_LOOP) #if USE(JSVALUE64) @@ -111,4 +118,17 @@ #define OFFLINE_ASM_VALUE_PROFILER 0 #endif +#if CPU(MIPS) +#ifdef WTF_MIPS_PIC +#define S(x) #x +#define SX(x) S(x) +#define OFFLINE_ASM_CPLOAD(reg) \ + ".set noreorder\n" \ + ".cpload " SX(reg) "\n" \ + ".set reorder\n" +#else +#define OFFLINE_ASM_CPLOAD(reg) +#endif +#endif + #endif // LLIntOfflineAsmConfig_h diff --git a/Source/JavaScriptCore/llint/LowLevelInterpreter.asm b/Source/JavaScriptCore/llint/LowLevelInterpreter.asm index 00d5c4f6f..9de48f1f6 100644 --- a/Source/JavaScriptCore/llint/LowLevelInterpreter.asm +++ b/Source/JavaScriptCore/llint/LowLevelInterpreter.asm @@ -182,10 +182,8 @@ macro assert(assertion) end macro preserveReturnAddressAfterCall(destinationRegister) - if C_LOOP - # In our case, we're only preserving the bytecode vPC. - move lr, destinationRegister - elsif ARMv7 + if C_LOOP or ARMv7 or MIPS + # In C_LOOP case, we're only preserving the bytecode vPC. move lr, destinationRegister elsif X86 or X86_64 pop destinationRegister @@ -195,10 +193,8 @@ macro preserveReturnAddressAfterCall(destinationRegister) end macro restoreReturnAddressBeforeReturn(sourceRegister) - if C_LOOP - # In our case, we're only restoring the bytecode vPC. - move sourceRegister, lr - elsif ARMv7 + if C_LOOP or ARMv7 or MIPS + # In C_LOOP case, we're only restoring the bytecode vPC. move sourceRegister, lr elsif X86 or X86_64 push sourceRegister diff --git a/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm b/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm index 8d5cdf108..9a17985bc 100644 --- a/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm +++ b/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm @@ -113,6 +113,10 @@ macro cCall2(function, arg1, arg2) poke arg1, 0 poke arg2, 1 call function + elsif MIPS + move arg1, a0 + move arg2, a1 + call function elsif C_LOOP cloopCallSlowPath function, arg1, arg2 else @@ -134,6 +138,12 @@ macro cCall4(function, arg1, arg2, arg3, arg4) poke arg3, 2 poke arg4, 3 call function + elsif MIPS + move arg1, a0 + move arg2, a1 + move arg3, a2 + move arg4, a3 + call function elsif C_LOOP error else @@ -1818,6 +1828,20 @@ macro nativeCallTrampoline(executableOffsetToFunction) call executableOffsetToFunction[t1] restoreReturnAddressBeforeReturn(t3) loadp JITStackFrame::globalData[sp], t3 + elsif MIPS + loadp JITStackFrame::globalData[sp], t3 + storep cfr, JSGlobalData::topCallFrame[t3] + move t0, t2 + preserveReturnAddressAfterCall(t3) + storep t3, ReturnPC[cfr] + move cfr, t0 + loadi Callee + PayloadOffset[cfr], t1 + loadp JSFunction::m_executable[t1], t1 + move t2, cfr + move t0, a0 + call executableOffsetToFunction[t1] + restoreReturnAddressBeforeReturn(t3) + loadp JITStackFrame::globalData[sp], t3 elsif C_LOOP loadp JITStackFrame::globalData[sp], t3 storep cfr, JSGlobalData::topCallFrame[t3] diff --git a/Source/JavaScriptCore/offlineasm/backends.rb b/Source/JavaScriptCore/offlineasm/backends.rb index 78e545738..ef9358c0b 100644 --- a/Source/JavaScriptCore/offlineasm/backends.rb +++ b/Source/JavaScriptCore/offlineasm/backends.rb @@ -25,6 +25,7 @@ require "config" require "armv7" require "ast" require "x86" +require "mips" require "cloop" BACKENDS = @@ -32,6 +33,7 @@ BACKENDS = "X86", "X86_64", "ARMv7", + "MIPS", "C_LOOP" ] @@ -45,6 +47,7 @@ WORKING_BACKENDS = "X86", "X86_64", "ARMv7", + "MIPS", "C_LOOP" ] diff --git a/Source/JavaScriptCore/offlineasm/instructions.rb b/Source/JavaScriptCore/offlineasm/instructions.rb index e047b2a16..4e70625c2 100644 --- a/Source/JavaScriptCore/offlineasm/instructions.rb +++ b/Source/JavaScriptCore/offlineasm/instructions.rb @@ -265,6 +265,16 @@ ARMv7_INSTRUCTIONS = "oris" ] +MIPS_INSTRUCTIONS = + [ + "movz", + "movn", + "slt", + "sltu", + "pichdr", + "pichdrra" + ] + CXX_INSTRUCTIONS = [ "cloopCrash", # no operands @@ -281,7 +291,7 @@ CXX_INSTRUCTIONS = "cloopDo", # no operands ] -INSTRUCTIONS = MACRO_INSTRUCTIONS + X86_INSTRUCTIONS + ARMv7_INSTRUCTIONS + CXX_INSTRUCTIONS +INSTRUCTIONS = MACRO_INSTRUCTIONS + X86_INSTRUCTIONS + ARMv7_INSTRUCTIONS + MIPS_INSTRUCTIONS + CXX_INSTRUCTIONS INSTRUCTION_PATTERN = Regexp.new('\\A((' + INSTRUCTIONS.join(')|(') + '))\\Z') diff --git a/Source/JavaScriptCore/offlineasm/mips.rb b/Source/JavaScriptCore/offlineasm/mips.rb new file mode 100644 index 000000000..c6daa3c7d --- /dev/null +++ b/Source/JavaScriptCore/offlineasm/mips.rb @@ -0,0 +1,892 @@ +# Copyright (C) 2012 Apple Inc. All rights reserved. +# Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY MIPS TECHNOLOGIES, INC. ``AS IS'' AND ANY +# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MIPS TECHNOLOGIES, INC. OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +require 'risc' + +class Assembler + def putStr(str) + @outp.puts str + end +end + +class Node + def mipsSingleHi + doubleOperand = mipsOperand + raise "Bogus register name #{doubleOperand}" unless doubleOperand =~ /^\$f/ + "$f" + ($~.post_match.to_i + 1).to_s + end + def mipsSingleLo + doubleOperand = mipsOperand + raise "Bogus register name #{doubleOperand}" unless doubleOperand =~ /^\$f/ + doubleOperand + end +end + +class SpecialRegister < NoChildren + def mipsOperand + @name + end + + def dump + @name + end + + def register? + true + end +end + +MIPS_TEMP_GPRS = [SpecialRegister.new("$t5"), SpecialRegister.new("$t6"), SpecialRegister.new("$t7"), + SpecialRegister.new("$t8")] +MIPS_ZERO_REG = SpecialRegister.new("$zero") +MIPS_GP_REG = SpecialRegister.new("$gp") +MIPS_GPSAVE_REG = SpecialRegister.new("$s4") +MIPS_JUMP_REG = SpecialRegister.new("$ra") +MIPS_CALL_REG = SpecialRegister.new("$t9") +MIPS_TEMP_FPRS = [SpecialRegister.new("$f16")] +MIPS_SCRATCH_FPR = SpecialRegister.new("$f18") + +def mipsMoveImmediate(value, register) + if value == 0 + $asm.puts "add #{register.mipsOperand}, $zero, $zero" + else + $asm.puts "li #{register.mipsOperand}, #{value}" + end +end + +class RegisterID + def mipsOperand + case name + when "a0" + "$a0" + when "a1" + "$a1" + when "r0", "t0" + "$v0" + when "r1", "t1" + "$v1" + when "t2" + "$t2" + when "t3" + "$s3" + when "t4" # PC reg in llint + "$s2" + when "t5" + "$t5" + when "t6" + "$t6" + when "t7" + "$t7" + when "t8" + "$t8" + when "cfr" + "$s0" + when "lr" + "$ra" + when "sp" + "$sp" + else + raise "Bad register #{name} for MIPS at #{codeOriginString}" + end + end +end + +class FPRegisterID + def mipsOperand + case name + when "ft0", "fr" + "$f0" + when "ft1" + "$f2" + when "ft2" + "$f4" + when "ft3" + "$f6" + when "ft4" + "$f8" + when "ft5" + "$f10" + when "fa0" + "$f12" + when "fa1" + "$f14" + else + raise "Bad register #{name} for MIPS at #{codeOriginString}" + end + end +end + +class Immediate + def mipsOperand + raise "Invalid immediate #{value} at #{codeOriginString}" if value < -0x7fff or value > 0x7fff + "#{value}" + end +end + +class Address + def mipsOperand + raise "Bad offset at #{codeOriginString}" if offset.value < -0x7fff or offset.value > 0x7fff + "#{offset.value}(#{base.mipsOperand})" + end +end + +class AbsoluteAddress + def mipsOperand + raise "Unconverted absolute address at #{codeOriginString}" + end +end + +# +# Lower 'and' masked branches +# + +def lowerMIPSCondBranch(list, condOp, node) + if node.operands.size == 2 + list << Instruction.new(node.codeOrigin, + condOp, + [node.operands[0], MIPS_ZERO_REG, node.operands[-1]], + node.annotation) + elsif node.operands.size == 3 + tmp = Tmp.new(node.codeOrigin, :gpr) + list << Instruction.new(node.codeOrigin, + "andi", + [node.operands[0], node.operands[1], tmp], + node.annotation) + list << Instruction.new(node.codeOrigin, + condOp, + [tmp, MIPS_ZERO_REG, node.operands[-1]]) + else + raise "Expected 2 or 3 operands but got #{node.operands.size} at #{node.codeOriginString}" + end +end + +# +# Lowering of branch ops. For example: +# +# baddiz foo, bar, baz +# +# will become: +# +# addi foo, bar +# bz baz +# + +def mipsLowerSimpleBranchOps(list) + newList = [] + list.each { + | node | + if node.is_a? Instruction + annotation = node.annotation + case node.opcode + when /^b(addi|subi|ori|addp)/ + op = $1 + bc = $~.post_match + branch = "b" + bc + + case op + when "addi", "addp" + op = "addi" + when "subi" + op = "subi" + when "ori" + op = "ori" + end + + if bc == "o" + case op + when "addi" + # addu $s0, $s1, $s2 + # xor $t0, $s1, $s2 + # blt $t0, $zero, no overflow + # xor $t0, $s0, $s1 + # blt $t0, $zero, overflow + # no overflow: + # + tr = Tmp.new(node.codeOrigin, :gpr) + tmp = Tmp.new(node.codeOrigin, :gpr) + noFlow = LocalLabel.unique("noflow") + noFlowRef = LocalLabelReference.new(node.codeOrigin, noFlow) + newList << Instruction.new(node.codeOrigin, op, [node.operands[0], node.operands[1], tr], annotation) + newList << Instruction.new(node.codeOrigin, "xori", [node.operands[0], node.operands[1], tmp]) + newList << Instruction.new(node.codeOrigin, "bilt", [tmp, MIPS_ZERO_REG, noFlowRef]) + newList << Instruction.new(node.codeOrigin, "xori", [tr, node.operands[0], tmp]) + newList << Instruction.new(node.codeOrigin, "bilt", [tmp, MIPS_ZERO_REG, node.operands[2]]) + newList << noFlow + newList << Instruction.new(node.codeOrigin, "move", [tr, node.operands[1]]) + when "subi" + # subu $s0, $s1, $s2 + # xor $t0, $s1, $s2 + # bge $t0, $zero, no overflow + # xor $t0, $s0, $s1 + # blt $t0, $zero, overflow + # no overflow: + # + tr = Tmp.new(node.codeOrigin, :gpr) + tmp = Tmp.new(node.codeOrigin, :gpr) + noFlow = LocalLabel.unique("noflow") + noFlowRef = LocalLabelReference.new(node.codeOrigin, noFlow) + newList << Instruction.new(node.codeOrigin, op, [node.operands[1], node.operands[0], tr], annotation) + newList << Instruction.new(node.codeOrigin, "xori", [node.operands[1], node.operands[0], tmp]) + newList << Instruction.new(node.codeOrigin, "bigteq", [tmp, MIPS_ZERO_REG, noFlowRef]) + newList << Instruction.new(node.codeOrigin, "xori", [tr, node.operands[1], tmp]) + newList << Instruction.new(node.codeOrigin, "bilt", [tmp, MIPS_ZERO_REG, node.operands[2]]) + newList << noFlow + newList << Instruction.new(node.codeOrigin, "move", [tr, node.operands[1]]) + when "ori" + # no ovwerflow at ori + newList << Instruction.new(node.codeOrigin, op, node.operands[0..1], annotation) + end + else + if node.operands[1].is_a? Address + addr = node.operands[1] + tr = Tmp.new(node.codeOrigin, :gpr) + newList << Instruction.new(node.codeOrigin, "loadp", [addr, tr], annotation) + newList << Instruction.new(node.codeOrigin, op, [node.operands[0], tr]) + newList << Instruction.new(node.codeOrigin, "storep", [tr, addr]) + else + tr = node.operands[1] + newList << Instruction.new(node.codeOrigin, op, node.operands[0..-2], annotation) + end + newList << Instruction.new(node.codeOrigin, branch, [tr, MIPS_ZERO_REG, node.operands[-1]]) + end + when "bia", "bpa", "bba" + tmp = Tmp.new(node.codeOrigin, :gpr) + comp = node.opcode[1] == ?b ? "sltub" : "sltu" + newList << Instruction.new(node.codeOrigin, comp, [tmp, node.operands[1], node.operands[0]], annotation) + newList << Instruction.new(node.codeOrigin, "bnz", [tmp, MIPS_ZERO_REG, node.operands[2]]) + when "biaeq", "bpaeq", "bbaeq" + tmp = Tmp.new(node.codeOrigin, :gpr) + comp = node.opcode[1] == ?b ? "sltub" : "sltu" + newList << Instruction.new(node.codeOrigin, comp, [tmp, node.operands[0], node.operands[1]], annotation) + newList << Instruction.new(node.codeOrigin, "bz", [tmp, MIPS_ZERO_REG, node.operands[2]]) + when "bib", "bpb", "bbb" + tmp = Tmp.new(node.codeOrigin, :gpr) + comp = node.opcode[1] == ?b ? "sltub" : "sltu" + newList << Instruction.new(node.codeOrigin, comp, [tmp, node.operands[0], node.operands[1]], annotation) + newList << Instruction.new(node.codeOrigin, "bnz", [tmp, MIPS_ZERO_REG, node.operands[2]]) + when "bibeq", "bpbeq", "bbbeq" + tmp = Tmp.new(node.codeOrigin, :gpr) + comp = node.opcode[1] == ?b ? "sltub" : "sltu" + newList << Instruction.new(node.codeOrigin, comp, [tmp, node.operands[1], node.operands[0]], annotation) + newList << Instruction.new(node.codeOrigin, "bz", [tmp, MIPS_ZERO_REG, node.operands[2]]) + when /^bt(i|p|b)/ + lowerMIPSCondBranch(newList, "b" + $~.post_match + $1, node) + else + newList << node + end + else + newList << node + end + } + newList +end + +# +# Specialization of lowering of malformed BaseIndex addresses. +# + +class Node + def mipsLowerMalformedAddressesRecurse(list, topLevelNode, &block) + mapChildren { + | subNode | + subNode.mipsLowerMalformedAddressesRecurse(list, topLevelNode, &block) + } + end +end + +class Address + def mipsLowerMalformedAddressesRecurse(list, node, &block) + riscLowerMalformedAddressesRecurse(list, node, &block) + end +end + +class BaseIndex + def mipsLowerMalformedAddressesRecurse(list, node, &block) + if scaleShift == 0 + tmp0 = Tmp.new(codeOrigin, :gpr) + list << Instruction.new(codeOrigin, "addp", [base, index, tmp0]) + Address.new(codeOrigin, tmp0, Immediate.new(codeOrigin, offset.value)); + else + tmp0 = Tmp.new(codeOrigin, :gpr) + list << Instruction.new(codeOrigin, "lshifti", [index, Immediate.new(codeOrigin, scaleShift), tmp0]); + list << Instruction.new(codeOrigin, "addp", [base, tmp0]) + Address.new(codeOrigin, tmp0, Immediate.new(codeOrigin, offset.value)); + end + end +end + +class AbsoluteAddress + def mipsLowerMalformedAddressesRecurse(list, node, &block) + riscLowerMalformedAddressesRecurse(list, node, &block) + end +end + +def mipsLowerMalformedAddresses(list, &block) + newList = [] + list.each { + | node | + newList << node.mipsLowerMalformedAddressesRecurse(newList, node, &block) + } + newList +end + +# +# Lowering of misplaced immediates of MIPS specific instructions. For example: +# +# sltu reg, 4, 2 +# +# will become: +# +# move 4, tmp +# sltu reg, tmp, 2 +# + +def mipsLowerMisplacedImmediates(list) + newList = [] + list.each { + | node | + if node.is_a? Instruction + case node.opcode + when "slt", "sltu", "sltb", "sltub" + if node.operands[1].is_a? Immediate + tmp = Tmp.new(node.codeOrigin, :gpr) + newList << Instruction.new(node.codeOrigin, "move", [node.operands[1], tmp], node.annotation) + newList << Instruction.new(node.codeOrigin, node.opcode, + [node.operands[0], tmp, node.operands[2]], + node.annotation) + else + newList << node + end + else + newList << node + end + else + newList << node + end + } + newList +end + +# +# Specialization of lowering of misplaced addresses. +# + +def mipsLowerMisplacedAddresses(list) + newList = [] + list.each { + | node | + if node.is_a? Instruction + postInstructions = [] + annotation = node.annotation + case node.opcode + when "jmp" + if node.operands[0].address? + newList << Instruction.new(node.operands[0].codeOrigin, "loadi", [node.operands[0], MIPS_JUMP_REG]) + newList << Instruction.new(node.codeOrigin, node.opcode, [MIPS_JUMP_REG]) + else + newList << Instruction.new(node.codeOrigin, + node.opcode, + [riscAsRegister(newList, postInstructions, node.operands[0], "p", false)]) + end + when "call" + restoreGP = false; + tmp = MIPS_CALL_REG + if node.operands[0].address? + newList << Instruction.new(node.operands[0].codeOrigin, "loadp", [node.operands[0], MIPS_CALL_REG]) + restoreGP = true; + elsif node.operands[0].is_a? LabelReference + tmp = node.operands[0] + restoreGP = true; + elsif node.operands[0].register? + newList << Instruction.new(node.operands[0].codeOrigin, "move", [node.operands[0], MIPS_CALL_REG]) + restoreGP = true; + else + tmp = node.operands[0] + end + newList << Instruction.new(node.codeOrigin, node.opcode, [tmp]) + if restoreGP + newList << Instruction.new(node.codeOrigin, "move", [MIPS_GPSAVE_REG, MIPS_GP_REG]) + end + when "slt", "sltu" + newList << Instruction.new(node.codeOrigin, + node.opcode, + riscAsRegisters(newList, [], node.operands, "i")) + when "sltub", "sltb" + newList << Instruction.new(node.codeOrigin, + node.opcode, + riscAsRegisters(newList, [], node.operands, "b")) + when /^(bz|bnz|bs|bo)/ + tl = $~.post_match == "" ? "i" : $~.post_match + newList << Instruction.new(node.codeOrigin, + node.opcode, + riscAsRegisters(newList, [], node.operands, tl)) + else + newList << node + end + newList += postInstructions + else + newList << node + end + } + newList +end + +# +# Lowering compares and tests. +# + +def mipsLowerCompareTemplate(list, node, opCmp, opMov) + tmp0 = Tmp.new(node.codeOrigin, :gpr) + tmp1 = Tmp.new(node.codeOrigin, :gpr) + list << Instruction.new(node.codeOrigin, "move", [Immediate.new(nil, 0), node.operands[2]]) + list << Instruction.new(node.codeOrigin, opCmp, [node.operands[1], node.operands[0], tmp0]) + list << Instruction.new(node.codeOrigin, "move", [Immediate.new(nil, 1), tmp1]) + list << Instruction.new(node.codeOrigin, opMov, [node.operands[2], tmp1, tmp0]) +end + +def mipsLowerCompares(list) + newList = [] + list.each { + | node | + if node.is_a? Instruction + case node.opcode + when "cieq", "cpeq", "cbeq" + mipsLowerCompareTemplate(newList, node, "subp", "movz") + when "cineq", "cpneq", "cbneq" + mipsLowerCompareTemplate(newList, node, "subp", "movn") + when "tiz", "tbz", "tpz" + mipsLowerCompareTemplate(newList, node, "andp", "movz") + when "tinz", "tbnz", "tpnz" + mipsLowerCompareTemplate(newList, node, "andp", "movn") + when "tio", "tbo", "tpo" + tmp = Tmp.new(node.codeOrigin, :gpr) + list << Instruction.new(node.codeOrigin, "andp", [node.operands[1], node.operands[0], tmp]) + list << Instruction.new(node.codeOrigin, "slt", [node.operands[2], MIPS_ZERO_REG, tmp]) + when "tis", "tbs", "tps" + tmp = Tmp.new(node.codeOrigin, :gpr) + list << Instruction.new(node.codeOrigin, "andp", [node.operands[1], node.operands[0], tmp]) + list << Instruction.new(node.codeOrigin, "slt", [node.operands[2], tmp, MIPS_ZERO_REG]) + else + newList << node + end + else + newList << node + end + } + newList +end + +# +# Lea support. +# + +class Address + def mipsEmitLea(destination) + if destination == base + $asm.puts "addiu #{destination.mipsOperand}, #{offset.value}" + else + $asm.puts "addiu #{destination.mipsOperand}, #{base.mipsOperand}, #{offset.value}" + end + end +end + +# +# Add PIC compatible header code to prologue/entry rutins. +# + +def mipsAddPICCode(list) + myList = [] + list.each { + | node | + myList << node + if node.is_a? Label + if /_prologue$/.match(node.name) || /^_llint_function_/.match(node.name) + # Functions called from trampoline/JIT codes. + myList << Instruction.new(node.codeOrigin, "pichdr", []) + elsif /_llint_op_catch/.match(node.name) + # Exception cactcher entry point function. + myList << Instruction.new(node.codeOrigin, "pichdrra", []) + end + end + } + myList +end + +# +# Actual lowering code follows. +# + +class Sequence + def getModifiedListMIPS + result = @list + + # Verify that we will only see instructions and labels. + result.each { + | node | + unless node.is_a? Instruction or + node.is_a? Label or + node.is_a? LocalLabel or + node.is_a? Skip + raise "Unexpected #{node.inspect} at #{node.codeOrigin}" + end + } + + result = mipsAddPICCode(result) + result = mipsLowerSimpleBranchOps(result) + result = riscLowerSimpleBranchOps(result) + result = riscLowerHardBranchOps(result) + result = riscLowerShiftOps(result) + result = mipsLowerMalformedAddresses(result) { + | node, address | + if address.is_a? Address + (-0xffff..0xffff).include? address.offset.value + else + false + end + } + result = riscLowerMalformedAddressesDouble(result) + result = riscLowerMisplacedImmediates(result) + result = mipsLowerMisplacedImmediates(result) + result = riscLowerMalformedImmediates(result, -0xffff..0xffff) + result = mipsLowerMisplacedAddresses(result) + result = riscLowerMisplacedAddresses(result) + result = riscLowerRegisterReuse(result) + result = mipsLowerCompares(result) + result = assignRegistersToTemporaries(result, :gpr, MIPS_TEMP_GPRS) + result = assignRegistersToTemporaries(result, :fpr, MIPS_TEMP_FPRS) + + return result + end +end + +def mipsOperands(operands) + operands.map{|v| v.mipsOperand}.join(", ") +end + +def mipsFlippedOperands(operands) + mipsOperands([operands[-1]] + operands[0..-2]) +end + +def getMIPSOpcode(opcode, suffix) + +end + +def emitMIPSCompact(opcode, opcodei, operands) + postfix = "" + if opcode == "sub" + if operands[0].is_a? Immediate + opcode = "add" + operands[0] = Immediate.new(operands[0].codeOrigin, -1 * operands[0].value) + elsif operands[1].is_a? Immediate + opcode = "add" + operands[1] = Immediate.new(operands[1].codeOrigin, -1 * operands[1].value) + end + postfix = "u" + elsif opcode == "add" + postfix = "u" + end + if operands.size == 3 + if operands[0].is_a? Immediate + $asm.puts "#{opcode}i#{postfix} #{operands[2].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].value}" + elsif operands[1].is_a? Immediate + $asm.puts "#{opcode}i#{postfix} #{operands[2].mipsOperand}, #{operands[0].mipsOperand}, #{operands[1].value}" + else + $asm.puts "#{opcode}#{postfix} #{mipsFlippedOperands(operands)}" + end + else + raise unless operands.size == 2 + raise unless operands[1].register? + if operands[0].is_a? Immediate + $asm.puts "#{opcode}i#{postfix} #{operands[1].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}" + else + $asm.puts "#{opcode}#{postfix} #{operands[1].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}" + end + end +end + +def emitMIPSShiftCompact(opcode, operands) + if operands.size == 3 + if (operands[1].is_a? Immediate) + $asm.puts "#{opcode} #{operands[2].mipsOperand}, #{operands[0].mipsOperand}, #{operands[1].value}" + else + $asm.puts "#{opcode}v #{mipsFlippedOperands(operands)}" + end + else + raise unless operands.size == 2 + if operands[0].register? + $asm.puts "#{opcode}v #{operands[1].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}" + else + $asm.puts "#{opcode} #{operands[1].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].value}" + end + end +end + +def emitMIPS(opcode, operands) + if operands.size == 3 + $asm.puts "#{opcode} #{mipsFlippedOperands(operands)}" + else + raise unless operands.size == 2 + $asm.puts "#{opcode} #{operands[1].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}" + end +end + +def emitMIPSDoubleBranch(branchOpcode, neg, operands) + $asm.puts "c.#{branchOpcode}.d #{mipsOperands(operands[0..1])}" + if (!neg) + $asm.puts "bc1t #{operands[2].asmLabel}" + else + $asm.puts "bc1f #{operands[2].asmLabel}" + end +end + +class Instruction + def lowerMIPS + $asm.comment codeOriginString + case opcode + when "addi", "addp", "addis" + if operands.size == 3 and operands[0].is_a? Immediate + raise unless operands[1].register? + raise unless operands[2].register? + if operands[0].value == 0 #and suffix.empty? + unless operands[1] == operands[2] + $asm.puts "move #{operands[2].mipsOperand}, #{operands[1].mipsOperand}" + end + else + $asm.puts "addiu #{operands[2].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}" + end + elsif operands.size == 3 and operands[0].register? + raise unless operands[1].register? + raise unless operands[2].register? + $asm.puts "addu #{mipsFlippedOperands(operands)}" + else + if operands[0].is_a? Immediate + unless Immediate.new(nil, 0) == operands[0] + $asm.puts "addiu #{operands[1].mipsOperand}, #{mipsFlippedOperands(operands)}" + end + else + $asm.puts "addu #{operands[1].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}" + end + end + when "andi", "andp" + emitMIPSCompact("and", "and", operands) + when "ori", "orp" + emitMIPSCompact("or", "orr", operands) + when "oris" + emitMIPSCompact("or", "orrs", operands) + when "xori", "xorp" + emitMIPSCompact("xor", "eor", operands) + when "lshifti", "lshiftp" + emitMIPSShiftCompact("sll", operands) + when "rshifti", "rshiftp" + emitMIPSShiftCompact("sra", operands) + when "urshifti", "urshiftp" + emitMIPSShiftCompact("srl", operands) + when "muli", "mulp" + emitMIPS("mul", operands) + when "subi", "subp", "subis" + emitMIPSCompact("sub", "subs", operands) + when "negi", "negp" + $asm.puts "negu #{operands[0].mipsOperand}, #{operands[0].mipsOperand}" + when "noti" + $asm.puts "nor #{operands[0].mipsOperand}, #{operands[0].mipsOperand}, $zero" + when "loadi", "loadis", "loadp" + $asm.puts "lw #{mipsFlippedOperands(operands)}" + when "storei", "storep" + $asm.puts "sw #{mipsOperands(operands)}" + when "loadb" + $asm.puts "lbu #{mipsFlippedOperands(operands)}" + when "loadbs" + $asm.puts "lb #{mipsFlippedOperands(operands)}" + when "storeb" + $asm.puts "sb #{mipsOperands(operands)}" + when "loadh" + $asm.puts "lhu #{mipsFlippedOperands(operands)}" + when "loadhs" + $asm.puts "lh #{mipsFlippedOperands(operands)}" + when "storeh" + $asm.puts "shv #{mipsOperands(operands)}" + when "loadd" + $asm.puts "ldc1 #{mipsFlippedOperands(operands)}" + when "stored" + $asm.puts "sdc1 #{mipsOperands(operands)}" + when "addd" + emitMIPS("add.d", operands) + when "divd" + emitMIPS("div.d", operands) + when "subd" + emitMIPS("sub.d", operands) + when "muld" + emitMIPS("mul.d", operands) + when "sqrtd" + $asm.puts "sqrt.d #{mipsFlippedOperands(operands)}" + when "ci2d" + raise "invalid ops of #{self.inspect} at #{codeOriginString}" unless operands[1].is_a? FPRegisterID and operands[0].register? + $asm.puts "mtc1 #{operands[0].mipsOperand}, #{operands[1].mipsOperand}" + $asm.puts "cvt.d.w #{operands[1].mipsOperand}, #{operands[1].mipsOperand}" + when "bdeq" + emitMIPSDoubleBranch("eq", false, operands) + when "bdneq" + emitMIPSDoubleBranch("ueq", true, operands) + when "bdgt" + emitMIPSDoubleBranch("ule", true, operands) + when "bdgteq" + emitMIPSDoubleBranch("ult", true, operands) + when "bdlt" + emitMIPSDoubleBranch("olt", false, operands) + when "bdlteq" + emitMIPSDoubleBranch("ole", false, operands) + when "bdequn" + emitMIPSDoubleBranch("ueq", false, operands) + when "bdnequn" + emitMIPSDoubleBranch("eq", true, operands) + when "bdgtun" + emitMIPSDoubleBranch("ole", true, operands) + when "bdgtequn" + emitMIPSDoubleBranch("olt", true, operands) + when "bdltun" + emitMIPSDoubleBranch("ult", false, operands) + when "bdltequn" + emitMIPSDoubleBranch("ule", false, operands) + when "btd2i" + # FIXME: may be a good idea to just get rid of this instruction, since the interpreter + # currently does not use it. + raise "MIPS does not support this opcode yet, #{codeOrigin}" + when "td2i" + $asm.puts "cvt.w.d #{MIPS_SCRATCH_FPR.mipsSingleLo}, #{operands[0].mipsOperand}" + $asm.puts "mfc1 #{operands[1].mipsOperand}, #{MIPS_SCRATCH_FPR.mipsSingleLo}" + when "bcd2i" + $asm.puts "cvt.w.d #{MIPS_SCRATCH_FPR.mipsSingleLo}, #{operands[0].mipsOperand}" + $asm.puts "mfc1 #{operands[1].mipsOperand}, #{MIPS_SCRATCH_FPR.mipsSingleLo}" + $asm.puts "cvt.d.w #{MIPS_SCRATCH_FPR.mipsOperand}, #{MIPS_SCRATCH_FPR.mipsSingleLo}" + emitMIPSDoubleBranch("eq", true, [MIPS_SCRATCH_FPR, operands[0], operands[2]]) + $asm.puts "beq #{operands[1].mipsOperand}, $zero, #{operands[2].asmLabel}" + when "movdz" + # FIXME: either support this or remove it. + raise "MIPS does not support this opcode yet, #{codeOrigin}" + when "pop" + $asm.puts "lw #{operands[0].mipsOperand}, 0($sp)" + $asm.puts "addiu $sp, $sp, 4" + when "push" + $asm.puts "addiu $sp, $sp, -4" + $asm.puts "sw #{operands[0].mipsOperand}, 0($sp)" + when "move", "sxi2p", "zxi2p" + if operands[0].is_a? Immediate + mipsMoveImmediate(operands[0].value, operands[1]) + else + $asm.puts "move #{mipsFlippedOperands(operands)}" + end + when "nop" + $asm.puts "nop" + when "bieq", "bpeq", "bbeq" + $asm.puts "beq #{mipsOperands(operands[0..1])}, #{operands[2].asmLabel}" + when "bineq", "bpneq", "bbneq" + $asm.puts "bne #{mipsOperands(operands[0..1])}, #{operands[2].asmLabel}" + when "bigt", "bpgt", "bbgt" + $asm.puts "bgt #{mipsOperands(operands[0..1])}, #{operands[2].asmLabel}" + when "bigteq", "bpgteq", "bbgteq" + $asm.puts "bge #{mipsOperands(operands[0..1])}, #{operands[2].asmLabel}" + when "bilt", "bplt", "bblt" + $asm.puts "blt #{mipsOperands(operands[0..1])}, #{operands[2].asmLabel}" + when "bilteq", "bplteq", "bblteq" + $asm.puts "ble #{mipsOperands(operands[0..1])}, #{operands[2].asmLabel}" + when "jmp" + if operands[0].label? + $asm.puts "j #{operands[0].asmLabel}" + else + $asm.puts "jr #{operands[0].mipsOperand}" + end + when "call" + if operands[0].label? + $asm.puts "jal #{operands[0].asmLabel}" + else + $asm.puts "jalr #{operands[0].mipsOperand}" + end + when "break" + $asm.puts "break" + when "ret" + $asm.puts "jr $ra" + when "cia", "cpa", "cba" + $asm.puts "sltu #{operands[2].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}" + when "ciaeq", "cpaeq", "cbaeq" + $asm.puts "sltu #{operands[2].mipsOperand}, #{operands[0].mipsOperand}, #{operands[1].mipsOperand}" + $asm.puts "xori #{operands[2].mipsOperand}, 1" + when "cib", "cpb", "cbb" + $asm.puts "sltu #{operands[2].mipsOperand}, #{operands[0].mipsOperand}, #{operands[1].mipsOperand}" + when "cibeq", "cpbeq", "cbbeq" + $asm.puts "sltu #{operands[2].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}" + $asm.puts "xori #{operands[2].mipsOperand}, 1" + when "cigt", "cpgt", "cbgt" + $asm.puts "slt #{operands[2].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}" + when "cigteq", "cpgteq", "cbgteq" + $asm.puts "slt #{operands[2].mipsOperand}, #{operands[0].mipsOperand}, #{operands[1].mipsOperand}" + $asm.puts "xori #{operands[2].mipsOperand}, 1" + when "cilt", "cplt", "cblt" + $asm.puts "slt #{operands[2].mipsOperand}, #{operands[0].mipsOperand}, #{operands[1].mipsOperand}" + when "cilteq", "cplteq", "cblteq" + $asm.puts "slt #{operands[2].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}" + $asm.puts "xori #{operands[2].mipsOperand}, 1" + when "peek" + $asm.puts "lw #{operands[1].mipsOperand}, #{operands[0].value * 4}($sp)" + when "poke" + $asm.puts "sw #{operands[1].mipsOperand}, #{operands[0].value * 4}($sp)" + when "fii2d" + $asm.puts "mtc1 #{operands[0].mipsOperand}, #{operands[2].mipsSingleLo}" + $asm.puts "mtc1 #{operands[1].mipsOperand}, #{operands[2].mipsSingleHi}" + when "fd2ii" + $asm.puts "mfc1 #{operands[1].mipsOperand}, #{operands[0].mipsSingleLo}" + $asm.puts "mfc1 #{operands[2].mipsOperand}, #{operands[0].mipsSingleHi}" + when /^bo/ + $asm.puts "bgt #{operands[0].mipsOperand}, #{operands[1].mipsOperand}, #{operands[2].asmLabel}" + when /^bs/ + $asm.puts "blt #{operands[0].mipsOperand}, #{operands[1].mipsOperand}, #{operands[2].asmLabel}" + when /^bz/ + $asm.puts "beq #{operands[0].mipsOperand}, #{operands[1].mipsOperand}, #{operands[2].asmLabel}" + when /^bnz/ + $asm.puts "bne #{operands[0].mipsOperand}, #{operands[1].mipsOperand}, #{operands[2].asmLabel}" + when "leai", "leap" + operands[0].mipsEmitLea(operands[1]) + when "smulli" + raise "Wrong number of arguments to smull in #{self.inspect} at #{codeOriginString}" unless operands.length == 4 + $asm.puts "mult #{operands[0].mipsOperand}, #{operands[1].mipsOperand}" + $asm.puts "mflo #{operands[2].mipsOperand}" + $asm.puts "mfhi #{operands[3].mipsOperand}" + when "movz" + $asm.puts "movz #{operands[0].mipsOperand}, #{operands[1].mipsOperand}, #{operands[2].mipsOperand}" + when "movn" + $asm.puts "movn #{operands[0].mipsOperand}, #{operands[1].mipsOperand}, #{operands[2].mipsOperand}" + when "slt", "sltb" + $asm.puts "slt #{operands[0].mipsOperand}, #{operands[1].mipsOperand}, #{operands[2].mipsOperand}" + when "sltu", "sltub" + $asm.puts "sltu #{operands[0].mipsOperand}, #{operands[1].mipsOperand}, #{operands[2].mipsOperand}" + when "pichdr" + $asm.putStr("OFFLINE_ASM_CPLOAD($25)") + $asm.puts "move $s4, $gp" + when "pichdrra" + $asm.putStr("OFFLINE_ASM_CPLOAD($31)") + $asm.puts "move $s4, $gp" + else + raise "Unhandled opcode #{opcode} at #{codeOriginString}" + end + end +end diff --git a/Source/JavaScriptCore/offlineasm/risc.rb b/Source/JavaScriptCore/offlineasm/risc.rb index 44b4dbd71..7408253af 100644 --- a/Source/JavaScriptCore/offlineasm/risc.rb +++ b/Source/JavaScriptCore/offlineasm/risc.rb @@ -187,7 +187,7 @@ class Node end class Address - def riscLowerMalformedAddressesRecurse(list, node) + def riscLowerMalformedAddressesRecurse(list, node, &block) return self if yield node, self tmp = Tmp.new(codeOrigin, :gpr) @@ -208,7 +208,7 @@ class BaseIndex end class AbsoluteAddress - def riscLowerMalformedAddressesRecurse(list, node) + def riscLowerMalformedAddressesRecurse(list, node, &block) return self if yield node, self tmp = Tmp.new(codeOrigin, :gpr) diff --git a/Source/JavaScriptCore/runtime/JSGlobalData.h b/Source/JavaScriptCore/runtime/JSGlobalData.h index 0ffaccb6a..01e6059da 100644 --- a/Source/JavaScriptCore/runtime/JSGlobalData.h +++ b/Source/JavaScriptCore/runtime/JSGlobalData.h @@ -129,14 +129,18 @@ namespace JSC { return result; } - static size_t allocationSize(size_t bufferSize) { return sizeof(size_t) + bufferSize; } + static size_t allocationSize(size_t bufferSize) { return sizeof(ScratchBuffer) + bufferSize; } void setActiveLength(size_t activeLength) { m_activeLength = activeLength; } size_t activeLength() const { return m_activeLength; }; size_t* activeLengthPtr() { return &m_activeLength; }; void* dataBuffer() { return m_buffer; } size_t m_activeLength; +#if CPU(MIPS) && (defined WTF_MIPS_ARCH_REV && WTF_MIPS_ARCH_REV == 2) + void* m_buffer[0] __attribute__((aligned(8))); +#else void* m_buffer[0]; +#endif }; #if COMPILER(MSVC) #pragma warning(pop) |
