X-Git-Url: https://git.saurik.com/apple/javascriptcore.git/blobdiff_plain/6fe7ccc865dc7d7541b93c5bcaf6368d2c98a174..8b637bb680022adfddad653280734877951535a9:/assembler/SH4Assembler.h diff --git a/assembler/SH4Assembler.h b/assembler/SH4Assembler.h index 59d0422..a6d3382 100644 --- a/assembler/SH4Assembler.h +++ b/assembler/SH4Assembler.h @@ -1,4 +1,5 @@ /* + * Copyright (C) 2013 Cisco Systems, Inc. All rights reserved. * Copyright (C) 2009-2011 STMicroelectronics. All rights reserved. * Copyright (C) 2008 Apple Inc. All rights reserved. * @@ -114,7 +115,9 @@ enum { MOVL_READ_OFFPC_OPCODE = 0xd000, MOVL_READ_OFFRM_OPCODE = 0x5000, MOVW_WRITE_RN_OPCODE = 0x2001, + MOVW_WRITE_R0RN_OPCODE = 0x0005, MOVW_READ_RM_OPCODE = 0x6001, + MOVW_READ_RMINC_OPCODE = 0x6005, MOVW_READ_R0RM_OPCODE = 0x000d, MOVW_READ_OFFRM_OPCODE = 0x8500, MOVW_READ_OFFPC_OPCODE = 0x9000, @@ -166,6 +169,7 @@ enum { FMOVS_WRITE_RN_DEC_OPCODE = 0xf00b, FMOVS_WRITE_R0RN_OPCODE = 0xf007, FCNVDS_DRM_FPUL_OPCODE = 0xf0bd, + FCNVSD_FPUL_DRN_OPCODE = 0xf0ad, LDS_RM_FPUL_OPCODE = 0x405a, FLDS_FRM_FPUL_OPCODE = 0xf01d, STS_FPUL_RN_OPCODE = 0x005a, @@ -174,6 +178,7 @@ enum { STSFPSCR_OPCODE = 0x006a, LDSRMFPUL_OPCODE = 0x405a, FSTSFPULFRN_OPCODE = 0xf00d, + FABS_OPCODE = 0xf05d, FSQRT_OPCODE = 0xf06d, FSCHG_OPCODE = 0xf3fd, CLRT_OPCODE = 8, @@ -326,8 +331,9 @@ public: padForAlign32 = 0x00090009, }; - enum JumpType { JumpFar, - JumpNear + enum JumpType { + JumpFar, + JumpNear }; SH4Assembler() @@ -339,22 +345,23 @@ public: typedef enum { EQ = 0x0, // Equal NE = 0x1, // Not Equal - HS = 0x2, // Unsigend Greater Than equal - HI = 0x3, // Unsigend Greater Than - LS = 0x4, // Unsigend Lower or Same - LI = 0x5, // Unsigend Lower + HS = 0x2, // Unsigned Greater Than equal + HI = 0x3, // Unsigned Greater Than + LS = 0x4, // Unsigned Lower or Same + LI = 0x5, // Unsigned Lower GE = 0x6, // Greater or Equal LT = 0x7, // Less Than GT = 0x8, // Greater Than LE = 0x9, // Less or Equal OF = 0xa, // OverFlow SI = 0xb, // Signed - EQU= 0xc, // Equal or unordered(NaN) - NEU= 0xd, - GTU= 0xe, - GEU= 0xf, - LTU= 0x10, - LEU= 0x11, + NS = 0xc, // Not Signed + EQU= 0xd, // Equal or unordered(NaN) + NEU= 0xe, + GTU= 0xf, + GEU= 0x10, + LTU= 0x11, + LEU= 0x12, } Condition; // Opaque label types @@ -491,14 +498,14 @@ public: void sublRegReg(RegisterID src, RegisterID dst) { - uint16_t opc = getOpcodeGroup1(SUB_OPCODE, dst, src); - oneShortOp(opc); + uint16_t opc = getOpcodeGroup1(SUB_OPCODE, dst, src); + oneShortOp(opc); } void subvlRegReg(RegisterID src, RegisterID dst) { - uint16_t opc = getOpcodeGroup1(SUBV_OPCODE, dst, src); - oneShortOp(opc); + uint16_t opc = getOpcodeGroup1(SUBV_OPCODE, dst, src); + oneShortOp(opc); } void xorlRegReg(RegisterID src, RegisterID dst) @@ -532,7 +539,7 @@ public: oneShortOp(getOpcodeGroup2(SHLL16_OPCODE, dst)); break; default: - ASSERT_NOT_REACHED(); + RELEASE_ASSERT_NOT_REACHED(); } } @@ -542,28 +549,14 @@ public: oneShortOp(opc); } - void shllRegReg(RegisterID dst, RegisterID rShift) + void shldRegReg(RegisterID dst, RegisterID rShift) { - uint16_t opc = getOpcodeGroup1(SHLD_OPCODE, dst, rShift); - oneShortOp(opc); + oneShortOp(getOpcodeGroup1(SHLD_OPCODE, dst, rShift)); } - void shlrRegReg(RegisterID dst, RegisterID rShift) + void shadRegReg(RegisterID dst, RegisterID rShift) { - neg(rShift, rShift); - shllRegReg(dst, rShift); - } - - void sharRegReg(RegisterID dst, RegisterID rShift) - { - neg(rShift, rShift); - shaRegReg(dst, rShift); - } - - void shaRegReg(RegisterID dst, RegisterID rShift) - { - uint16_t opc = getOpcodeGroup1(SHAD_OPCODE, dst, rShift); - oneShortOp(opc); + oneShortOp(getOpcodeGroup1(SHAD_OPCODE, dst, rShift)); } void shlrImm8r(int imm, RegisterID dst) @@ -582,7 +575,29 @@ public: oneShortOp(getOpcodeGroup2(SHLR16_OPCODE, dst)); break; default: - ASSERT_NOT_REACHED(); + RELEASE_ASSERT_NOT_REACHED(); + } + } + + void shalImm8r(int imm, RegisterID dst) + { + switch (imm) { + case 1: + oneShortOp(getOpcodeGroup2(SHAL_OPCODE, dst)); + break; + default: + RELEASE_ASSERT_NOT_REACHED(); + } + } + + void sharImm8r(int imm, RegisterID dst) + { + switch (imm) { + case 1: + oneShortOp(getOpcodeGroup2(SHAR_OPCODE, dst)); + break; + default: + RELEASE_ASSERT_NOT_REACHED(); } } @@ -652,7 +667,7 @@ public: oneShortOp(getOpcodeGroup1(CMPGT_OPCODE, left, right)); break; default: - ASSERT_NOT_REACHED(); + RELEASE_ASSERT_NOT_REACHED(); } } @@ -729,7 +744,7 @@ public: oneShortOp(getOpcodeGroup5(BF_OPCODE, label)); break; default: - ASSERT_NOT_REACHED(); + RELEASE_ASSERT_NOT_REACHED(); } } @@ -749,7 +764,7 @@ public: oneShortOp(getOpcodeGroup2(BSRF_OPCODE, reg)); break; default: - ASSERT_NOT_REACHED(); + RELEASE_ASSERT_NOT_REACHED(); } } @@ -803,7 +818,7 @@ public: oneShortOp(opc); } - void floatfpulfrn(RegisterID src) + void floatfpulfrn(FPRegisterID src) { uint16_t opc = getOpcodeGroup2(FLOAT_OPCODE, src); oneShortOp(opc, true, false); @@ -815,6 +830,12 @@ public: oneShortOp(opc, true, false); } + void fmovsRegReg(FPRegisterID src, FPRegisterID dst) + { + uint16_t opc = getOpcodeGroup1(FMOV_OPCODE, dst, src); + oneShortOp(opc, true, false); + } + void fmovsReadrm(RegisterID src, FPRegisterID dst) { uint16_t opc = getOpcodeGroup1(FMOVS_READ_RM_OPCODE, dst, src); @@ -857,13 +878,13 @@ public: oneShortOp(opc, true, false); } - void fldsfpul(RegisterID src) + void fldsfpul(FPRegisterID src) { uint16_t opc = getOpcodeGroup2(FLDS_FRM_FPUL_OPCODE, src); oneShortOp(opc); } - void fstsfpul(RegisterID src) + void fstsfpul(FPRegisterID src) { uint16_t opc = getOpcodeGroup2(FSTS_FPUL_FRN_OPCODE, src); oneShortOp(opc); @@ -889,6 +910,12 @@ public: oneShortOp(opc); } + void dcnvsd(FPRegisterID dst) + { + uint16_t opc = getOpcodeGroup7(FCNVSD_FPUL_DRN_OPCODE, dst >> 1); + oneShortOp(opc); + } + void dcmppeq(FPRegisterID src, FPRegisterID dst) { uint16_t opc = getOpcodeGroup8(FCMPEQ_OPCODE, dst >> 1, src >> 1); @@ -931,6 +958,12 @@ public: oneShortOp(opc); } + void dabs(FPRegisterID dst) + { + uint16_t opc = getOpcodeGroup7(FABS_OPCODE, dst >> 1); + oneShortOp(opc); + } + void dsqrt(FPRegisterID dst) { uint16_t opc = getOpcodeGroup7(FSQRT_OPCODE, dst >> 1); @@ -1019,6 +1052,12 @@ public: oneShortOp(opc); } + void movwMemRegIn(RegisterID base, RegisterID dst) + { + uint16_t opc = getOpcodeGroup1(MOVW_READ_RMINC_OPCODE, dst, base); + oneShortOp(opc); + } + void movwPCReg(int offset, RegisterID base, RegisterID dst) { ASSERT(base == SH4Registers::pc); @@ -1042,6 +1081,12 @@ public: oneShortOp(opc); } + void movwRegMemr0(RegisterID src, RegisterID dst) + { + uint16_t opc = getOpcodeGroup1(MOVW_WRITE_R0RN_OPCODE, dst, src); + oneShortOp(opc); + } + void movlRegMem(RegisterID src, int offset, RegisterID base) { ASSERT((offset <= 15) && (offset >= 0)); @@ -1082,6 +1127,12 @@ public: oneShortOp(getOpcodeGroup4(MOVL_READ_OFFRM_OPCODE, dst, base, offset)); } + void movbRegMem(RegisterID src, RegisterID base) + { + uint16_t opc = getOpcodeGroup1(MOVB_WRITE_RN_OPCODE, base, src); + oneShortOp(opc); + } + void movbMemReg(int offset, RegisterID base, RegisterID dst) { ASSERT(dst == SH4Registers::r0); @@ -1102,6 +1153,18 @@ public: oneShortOp(opc); } + void movbMemRegIn(RegisterID base, RegisterID dst) + { + uint16_t opc = getOpcodeGroup1(MOVB_READ_RMINC_OPCODE, dst, base); + oneShortOp(opc); + } + + void movbRegMemr0(RegisterID src, RegisterID dst) + { + uint16_t opc = getOpcodeGroup1(MOVB_WRITE_R0RN_OPCODE, dst, src); + oneShortOp(opc); + } + void movlMemReg(RegisterID base, RegisterID dst) { uint16_t opc = getOpcodeGroup1(MOVL_READ_RM_OPCODE, dst, base); @@ -1239,15 +1302,21 @@ public: oneShortOp(RTS_OPCODE, false); } + AssemblerLabel labelIgnoringWatchpoints() + { + m_buffer.ensureSpaceForAnyInstruction(); + return m_buffer.label(); + } + AssemblerLabel label() { - m_buffer.ensureSpaceForAnyOneInstruction(); + m_buffer.ensureSpaceForAnyInstruction(); return m_buffer.label(); } int sizeOfConstantPool() { - return m_buffer.sizeOfConstantPool(); + return m_buffer.sizeOfConstantPool(); } AssemblerLabel align(int alignment) @@ -1299,7 +1368,7 @@ public: *instructionPtr = instruction; printBlockInstr(instructionPtr - 2, from.m_offset, 3); return; - } + } /* MOV #imm, reg => LDR reg braf @reg braf @reg @@ -1350,7 +1419,7 @@ public: static SH4Buffer::TwoShorts placeConstantPoolBarrier(int offset) { - ASSERT(((offset >> 1) <=2047) && ((offset >> 1) >= -2048)); + ASSERT(((offset >> 1) <= 2047) && ((offset >> 1) >= -2048)); SH4Buffer::TwoShorts m_barrier; m_barrier.high = (BRA_OPCODE | (offset >> 1)); @@ -1442,6 +1511,43 @@ public: // Linking & patching + static ptrdiff_t maxJumpReplacementSize() + { + return sizeof(SH4Word) * 6; + } + + static void replaceWithJump(void *instructionStart, void *to) + { + SH4Word* instruction = reinterpret_cast(instructionStart); + intptr_t difference = reinterpret_cast(to) - (reinterpret_cast(instruction) + 2 * sizeof(SH4Word)); + int nbinst = 0; + + if ((difference >= -4096) && (difference <= 4094)) { + instruction[0] = getOpcodeGroup6(BRA_OPCODE, difference >> 1); + instruction[1] = NOP_OPCODE; + cacheFlush(instruction, sizeof(SH4Word) * 2); + return; + } + + instruction[nbinst++] = getOpcodeGroup3(MOVL_READ_OFFPC_OPCODE, scratchReg2, 1); + instruction[nbinst++] = getOpcodeGroup2(JMP_OPCODE, scratchReg2); + instruction[nbinst++] = NOP_OPCODE; + + if (!(reinterpret_cast(instruction) & 3)) + instruction[nbinst++] = NOP_OPCODE; + + instruction[nbinst++] = reinterpret_cast(to) & 0xffff; + instruction[nbinst++] = reinterpret_cast(to) >> 16; + cacheFlush(instruction, sizeof(SH4Word) * nbinst); + } + + static void revertJump(void* instructionStart, void *immptr) + { + SH4Word *insn = reinterpret_cast(instructionStart); + ASSERT((insn[0] & 0xf000) == MOVL_READ_OFFPC_OPCODE); + changePCrelativeAddress(insn[0] & 0x00ff, insn, reinterpret_cast(immptr)); + } + void linkJump(AssemblerLabel from, AssemblerLabel to, JumpType type = JumpFar) { ASSERT(to.isSet()); @@ -1493,7 +1599,7 @@ public: } instruction = *instructionPtr; - if ((instruction & 0xf000) == 0xe000) { + if ((instruction & 0xf000) == 0xe000) { uint32_t* addr = getLdrImmAddressOnPool(instructionPtr, m_buffer.poolAddress()); *addr = offsetBits - 2; printInstr(*instructionPtr, from.m_offset + 2); @@ -1541,19 +1647,27 @@ public: return reinterpret_cast(readPCrelativeAddress((*instructionPtr & 0xff), instructionPtr)); } - PassRefPtr executableCopy(JSGlobalData& globalData, void* ownerUID, JITCompilationEffort effort) + PassRefPtr executableCopy(VM& vm, void* ownerUID, JITCompilationEffort effort) { - return m_buffer.executableCopy(globalData, ownerUID, effort); + return m_buffer.executableCopy(vm, ownerUID, effort); } static void cacheFlush(void* code, size_t size) { -#if !OS(LINUX) -#error "The cacheFlush support is missing on this platform." -#elif defined CACHEFLUSH_D_L2 - syscall(__NR_cacheflush, reinterpret_cast(code), size, CACHEFLUSH_D_WB | CACHEFLUSH_I | CACHEFLUSH_D_L2); +#if OS(LINUX) + // Flush each page separately, otherwise the whole flush will fail if an uncommited page is in the area. + unsigned currentPage = reinterpret_cast(code) & ~(pageSize() - 1); + unsigned lastPage = (reinterpret_cast(code) + size - 1) & ~(pageSize() - 1); + do { +#if defined CACHEFLUSH_D_L2 + syscall(__NR_cacheflush, currentPage, pageSize(), CACHEFLUSH_D_WB | CACHEFLUSH_I | CACHEFLUSH_D_L2); +#else + syscall(__NR_cacheflush, currentPage, pageSize(), CACHEFLUSH_D_WB | CACHEFLUSH_I); +#endif + currentPage += pageSize(); + } while (lastPage >= currentPage); #else - syscall(__NR_cacheflush, reinterpret_cast(code), size, CACHEFLUSH_D_WB | CACHEFLUSH_I); +#error "The cacheFlush support is missing on this platform." #endif } @@ -1586,7 +1700,7 @@ public: size_t codeSize() const { return m_buffer.codeSize(); } #ifdef SH4_ASSEMBLER_TRACING - static void printInstr(uint16_t opc, unsigned int size, bool isdoubleInst = true) + static void printInstr(uint16_t opc, unsigned size, bool isdoubleInst = true) { if (!getenv("JavaScriptCoreDumpJIT")) return; @@ -1729,12 +1843,18 @@ public: case FTRC_OPCODE: format = " FTRC FR%d, FPUL\n"; break; + case FABS_OPCODE: + format = " FABS FR%d\n"; + break; case FSQRT_OPCODE: format = " FSQRT FR%d\n"; break; case FCNVDS_DRM_FPUL_OPCODE: format = " FCNVDS FR%d, FPUL\n"; break; + case FCNVSD_FPUL_DRN_OPCODE: + format = " FCNVSD FPUL, FR%d\n"; + break; } if (format) { if (isdoubleInst) @@ -1860,9 +1980,15 @@ public: case MOVW_READ_RM_OPCODE: format = " MOV.W @R%d, R%d\n"; break; + case MOVW_READ_RMINC_OPCODE: + format = " MOV.W @R%d+, R%d\n"; + break; case MOVW_READ_R0RM_OPCODE: format = " MOV.W @(R0, R%d), R%d\n"; break; + case MOVW_WRITE_R0RN_OPCODE: + format = " MOV.W R%d, @(R0, R%d)\n"; + break; case EXTUB_OPCODE: format = " EXTU.B R%d, R%d\n"; break; @@ -2064,21 +2190,45 @@ public: static void vprintfStdoutInstr(const char* format, va_list args) { if (getenv("JavaScriptCoreDumpJIT")) - WTF::dataLogV(format, args); + WTF::dataLogFV(format, args); } - static void printBlockInstr(uint16_t* first, unsigned int offset, int nbInstr) + static void printBlockInstr(uint16_t* first, unsigned offset, int nbInstr) { printfStdoutInstr(">> repatch instructions after link\n"); for (int i = 0; i <= nbInstr; i++) - printInstr(*(first + i), offset + i); + printInstr(*(first + i), offset + i); printfStdoutInstr(">> end repatch\n"); } #else - static void printInstr(uint16_t opc, unsigned int size, bool isdoubleInst = true) {}; - static void printBlockInstr(uint16_t* first, unsigned int offset, int nbInstr) {}; + static void printInstr(uint16_t opc, unsigned size, bool isdoubleInst = true) { }; + static void printBlockInstr(uint16_t* first, unsigned offset, int nbInstr) { }; #endif + static void replaceWithLoad(void* instructionStart) + { + SH4Word* insPtr = reinterpret_cast(instructionStart); + + insPtr += 2; // skip MOV and ADD opcodes + + if (((*insPtr) & 0xf00f) != MOVL_READ_RM_OPCODE) { + *insPtr = MOVL_READ_RM_OPCODE | (*insPtr & 0x0ff0); + cacheFlush(insPtr, sizeof(SH4Word)); + } + } + + static void replaceWithAddressComputation(void* instructionStart) + { + SH4Word* insPtr = reinterpret_cast(instructionStart); + + insPtr += 2; // skip MOV and ADD opcodes + + if (((*insPtr) & 0xf00f) != MOV_OPCODE) { + *insPtr = MOV_OPCODE | (*insPtr & 0x0ff0); + cacheFlush(insPtr, sizeof(SH4Word)); + } + } + private: SH4Buffer m_buffer; int m_claimscratchReg;