From cd014beba14af3f55736d4b613c46a1dfef6eae9 Mon Sep 17 00:00:00 2001 From: Chris Leary Date: Fri, 2 Jul 2010 23:57:51 -0700 Subject: [PATCH] Push-and-pray to try to fix ARM build breaks. (r=red). --- js/src/assembler/assembler/ARMAssembler.cpp | 21 +- js/src/assembler/assembler/ARMAssembler.h | 200 +++++++++++++----- js/src/assembler/assembler/ARMv7Assembler.h | 70 +++++- .../assembler/AbstractMacroAssembler.h | 6 + .../assembler/assembler/MacroAssemblerARM.h | 138 ++++++++++-- .../assembler/assembler/MacroAssemblerARMv7.h | 85 ++++++++ js/src/assembler/moco/MocoStubs.h | 3 + 7 files changed, 442 insertions(+), 81 deletions(-) diff --git a/js/src/assembler/assembler/ARMAssembler.cpp b/js/src/assembler/assembler/ARMAssembler.cpp index 1a31434667c4..735214c832f1 100644 --- a/js/src/assembler/assembler/ARMAssembler.cpp +++ b/js/src/assembler/assembler/ARMAssembler.cpp @@ -278,13 +278,13 @@ void ARMAssembler::dataTransfer32(bool isLoad, RegisterID srcDst, RegisterID bas } else { offset = -offset; if (offset <= 0xfff) - dtr_d(isLoad, srcDst, base, offset); + dtr_d(isLoad, srcDst, base, offset | transferFlag); else if (offset <= 0xfffff) { sub_r(ARMRegisters::S0, base, OP2_IMM | (offset >> 12) | (10 << 8)); - dtr_d(isLoad, srcDst, ARMRegisters::S0, offset & 0xfff); + dtr_d(isLoad, srcDst, ARMRegisters::S0, (offset & 0xfff) | transferFlag); } else { ARMWord reg = getImm(offset, ARMRegisters::S0); - dtr_dr(isLoad, srcDst, base, reg); + dtr_dr(isLoad, srcDst, base, reg | transferFlag); } } } @@ -356,10 +356,17 @@ void* ARMAssembler::executableCopy(ExecutablePool* allocator) // The last bit is set if the constant must be placed on constant pool. int pos = (*iter) & (~0x1); ARMWord* ldrAddr = reinterpret_cast(data + pos); - ARMWord offset = *getLdrImmAddress(ldrAddr); - if (offset != 0xffffffff) { - JmpSrc jmpSrc(pos); - linkBranch(data, jmpSrc, data + offset, ((*iter) & 1)); + ARMWord* addr = getLdrImmAddress(ldrAddr); + if (*addr != InvalidBranchTarget) { + if (!(*iter & 1)) { + int diff = reinterpret_cast(data + *addr) - (ldrAddr + DefaultPrefetching); + + if ((diff <= BOFFSET_MAX && diff >= BOFFSET_MIN)) { + *ldrAddr = B | getConditionalField(*ldrAddr) | (diff & BRANCH_MASK); + continue; + } + } + *addr = reinterpret_cast(data + *addr); } } diff --git a/js/src/assembler/assembler/ARMAssembler.h b/js/src/assembler/assembler/ARMAssembler.h index 837f4fede43b..f5938d6c0330 100644 --- a/js/src/assembler/assembler/ARMAssembler.h +++ b/js/src/assembler/assembler/ARMAssembler.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 University of Szeged + * Copyright (C) 2009, 2010 University of Szeged * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -37,7 +37,6 @@ #include "AssemblerBufferWithConstantPool.h" #include "assembler/wtf/Assertions.h" -#define IPFX " " namespace JSC { @@ -74,13 +73,46 @@ namespace JSC { d1, d2, d3, - SD0 = d3 + SD0 = d3, + d4, + d5, + d6, + d7, + d8, + d9, + d10, + d11, + d12, + d13, + d14, + d15, + d16, + d17, + d18, + d19, + d20, + d21, + d22, + d23, + d24, + d25, + d26, + d27, + d28, + d29, + d30, + d31 } FPRegisterID; } // namespace ARMRegisters class ARMAssembler { public: + +#ifdef DEBUG + bool isOOLPath; +#endif + typedef ARMRegisters::RegisterID RegisterID; typedef ARMRegisters::FPRegisterID FPRegisterID; typedef AssemblerBufferWithConstantPool<2048, 4, 4, ARMAssembler> ARMBuffer; @@ -88,6 +120,8 @@ namespace JSC { ARMAssembler() { } + unsigned char *buffer() const { return m_buffer.buffer(); } + // ARM conditional constants typedef enum { EQ = 0x00000000, // Zero @@ -128,10 +162,12 @@ namespace JSC { MUL = 0x00000090, MULL = 0x00c00090, FADDD = 0x0e300b00, + FNEGD = 0x0eb10b40, FDIVD = 0x0e800b00, FSUBD = 0x0e300b40, FMULD = 0x0e200b00, FCMPD = 0x0eb40b40, + FSQRTD = 0x0eb10bc0, DTR = 0x05000000, LDRH = 0x00100090, STRH = 0x00000090, @@ -139,11 +175,11 @@ namespace JSC { LDMIA = 0x08b00000, FDTR = 0x0d000b00, B = 0x0a000000, - BL = 0x0b000000, -#ifndef __ARM_ARCH_4__ - BX = 0x012fff10, // Only on ARMv4T+! + BL = 0x0b000000 +#if WTF_ARM_ARCH_VERSION >= 5 || defined(__ARM_ARCH_4T__) + ,BX = 0x012fff10 #endif - FMSR = 0x0e000a10, + ,FMSR = 0x0e000a10, FMRS = 0x0e100a10, FSITOD = 0x0eb80bc0, FTOSID = 0x0ebd0b40, @@ -151,7 +187,7 @@ namespace JSC { #if WTF_ARM_ARCH_VERSION >= 5 ,CLZ = 0x016f0f10, BKPT = 0xe120070, - BLX_R = 0x012fff30 + BLX = 0x012fff30 #endif #if WTF_ARM_ARCH_VERSION >= 7 ,MOVW = 0x03000000, @@ -166,6 +202,7 @@ namespace JSC { SET_CC = (1 << 20), OP2_OFSREG = (1 << 25), DT_UP = (1 << 23), + DT_BYTE = (1 << 22), DT_WB = (1 << 21), // This flag is inlcuded in LDR and STR DT_PRE = (1 << 24), @@ -201,6 +238,8 @@ namespace JSC { } Shift; static const ARMWord INVALID_IMM = 0xf0000000; + static const ARMWord InvalidBranchTarget = 0xffffffff; + static const int DefaultPrefetching = 2; class JmpSrc { friend class ARMAssembler; @@ -446,34 +485,36 @@ namespace JSC { void faddd_r(int dd, int dn, int dm, Condition cc = AL) { - FIXME_INSN_PRINTING; emitInst(static_cast(cc) | FADDD, dd, dn, dm); } void fdivd_r(int dd, int dn, int dm, Condition cc = AL) { - FIXME_INSN_PRINTING; emitInst(static_cast(cc) | FDIVD, dd, dn, dm); } void fsubd_r(int dd, int dn, int dm, Condition cc = AL) { - FIXME_INSN_PRINTING; emitInst(static_cast(cc) | FSUBD, dd, dn, dm); } void fmuld_r(int dd, int dn, int dm, Condition cc = AL) { - FIXME_INSN_PRINTING; emitInst(static_cast(cc) | FMULD, dd, dn, dm); } void fcmpd_r(int dd, int dm, Condition cc = AL) { - FIXME_INSN_PRINTING; emitInst(static_cast(cc) | FCMPD, dd, 0, dm); } + void fsqrtd_r(int dd, int dm, Condition cc = AL) + { + // TODO: emitInst doesn't work for VFP instructions, though it + // seems to work for current usage. + emitInst(static_cast(cc) | FSQRTD, dd, 0, dm); + } + void ldr_imm(int rd, ARMWord imm, Condition cc = AL) { char mnemonic[16]; @@ -546,14 +587,12 @@ namespace JSC { void fdtr_u(bool isLoad, int rd, int rb, ARMWord op2, Condition cc = AL) { - FIXME_INSN_PRINTING; ASSERT(op2 <= 0xff); emitInst(static_cast(cc) | FDTR | DT_UP | (isLoad ? DT_LOAD : 0), rd, rb, op2); } void fdtr_d(bool isLoad, int rd, int rb, ARMWord op2, Condition cc = AL) { - FIXME_INSN_PRINTING; ASSERT(op2 <= 0xff); emitInst(static_cast(cc) | FDTR | (isLoad ? DT_LOAD : 0), rd, rb, op2); } @@ -582,31 +621,26 @@ namespace JSC { void fmsr_r(int dd, int rn, Condition cc = AL) { - FIXME_INSN_PRINTING; emitInst(static_cast(cc) | FMSR, rn, dd, 0); } void fmrs_r(int rd, int dn, Condition cc = AL) { - FIXME_INSN_PRINTING; emitInst(static_cast(cc) | FMRS, rd, dn, 0); } void fsitod_r(int dd, int dm, Condition cc = AL) { - FIXME_INSN_PRINTING; emitInst(static_cast(cc) | FSITOD, dd, 0, dm); } void ftosid_r(int fd, int dm, Condition cc = AL) { - FIXME_INSN_PRINTING; emitInst(static_cast(cc) | FTOSID, fd, 0, dm); } void fmstat(Condition cc = AL) { - FIXME_INSN_PRINTING; m_buffer.putInt(static_cast(cc) | FMSTAT); } @@ -628,37 +662,28 @@ namespace JSC { #endif } - // BX is emitted where possible, or an equivalent sequence on ARMv4. - void bx_r(int rm, Condition cc = AL) + void bx(int rm, Condition cc = AL) { -#if (WTF_ARM_ARCH_VERSION >= 5) || defined(__ARM_ARCH_4T__) - // ARMv4T+ has BX . - m_buffer.putInt(static_cast(cc) | BX | RM(rm)); -#else // defined(__ARM_ARCH_4__) - // ARMv4 has to do "MOV pc, rm". This works on newer architectures - // too, but breaks return stack prediction and doesn't interwork on - // ARMv4T, so this becomes a special case of ARMv4. - mov_r(ARMRegisters::pc, rm, cc); +#if WTF_ARM_ARCH_VERSION >= 5 || defined(__ARM_ARCH_4T__) + emitInst(static_cast(cc) | BX, 0, 0, RM(rm)); +#else + mov_r(ARMRegisters::pc, RM(rm), cc); #endif } - // BLX is emitted where possible, or an equivalent (slower) sequence on - // ARMv4 or ARMv4T. - void blx_r(int rm, Condition cc = AL) + JmpSrc blx(int rm, Condition cc = AL) { - ASSERT((rm >= 0) && (rm <= 14)); -#if WTF_ARM_ARCH_VERSION >= 5 - // ARMv5+ is the ideal (fast) case, and can use a proper "BLX rm". - m_buffer.putInt(static_cast(cc) | BLX_R | RM(rm)); -#else // defined(__ARM_ARCH_4__) || defined(__ARM_ARCH_4T__) - // ARMv4T must do "MOV lr, pc; BX rm". - // ARMv4 must do "MOV lr, pc; MOV pc, rm". - // Both cases are handled here and by bx_r. +#if WTF_ARM_ARCH_AT_LEAST(5) + int s = m_buffer.uncheckedSize(); + emitInst(static_cast(cc) | BLX, 0, 0, RM(rm)); +#else ASSERT(rm != 14); ensureSpace(2 * sizeof(ARMWord), 0); mov_r(ARMRegisters::lr, ARMRegisters::pc, cc); - bx_r(rm, cc); + int s = m_buffer.uncheckedSize(); + bx(rm, cc); #endif + return JmpSrc(s); } static ARMWord lsl(int reg, ARMWord value) @@ -737,7 +762,7 @@ namespace JSC { { ensureSpace(sizeof(ARMWord), sizeof(ARMWord)); int s = m_buffer.uncheckedSize(); - ldr_un_imm(rd, 0xffffffff, cc); + ldr_un_imm(rd, InvalidBranchTarget, cc); m_jumps.append(s | (useConstantPool & 0x1)); return JmpSrc(s); } @@ -751,15 +776,40 @@ namespace JSC { // Patching helpers - static ARMWord* getLdrImmAddress(ARMWord* insn, uint32_t* constPool = 0); - static void linkBranch(void* code, JmpSrc from, void* to, int useConstantPool = 0); + static ARMWord* getLdrImmAddress(ARMWord* insn) + { +#if WTF_ARM_ARCH_AT_LEAST(5) + // Check for call + if ((*insn & 0x0f7f0000) != 0x051f0000) { + // Must be BLX + ASSERT((*insn & 0x012fff30) == 0x012fff30); + insn--; + } +#endif + // Must be an ldr ..., [pc +/- imm] + ASSERT((*insn & 0x0f7f0000) == 0x051f0000); + + ARMWord addr = reinterpret_cast(insn) + DefaultPrefetching * sizeof(ARMWord); + if (*insn & DT_UP) + return reinterpret_cast(addr + (*insn & SDT_OFFSET_MASK)); + return reinterpret_cast(addr - (*insn & SDT_OFFSET_MASK)); + } + + static ARMWord* getLdrImmAddressOnPool(ARMWord* insn, uint32_t* constPool) + { + // Must be an ldr ..., [pc +/- imm] + ASSERT((*insn & 0x0f7f0000) == 0x051f0000); + + if (*insn & 0x1) + return reinterpret_cast(constPool + ((*insn & SDT_OFFSET_MASK) >> 1)); + return getLdrImmAddress(insn); + } static void patchPointerInternal(intptr_t from, void* to) { ARMWord* insn = reinterpret_cast(from); ARMWord* addr = getLdrImmAddress(insn); *addr = reinterpret_cast(to); - ExecutableAllocator::cacheFlush(addr, sizeof(ARMWord)); } static ARMWord patchConstantPoolLoad(ARMWord load, ARMWord value) @@ -816,12 +866,13 @@ namespace JSC { void linkJump(JmpSrc from, JmpDst to) { ARMWord* insn = reinterpret_cast(m_buffer.data()) + (from.m_offset / sizeof(ARMWord)); - *getLdrImmAddress(insn, m_buffer.poolAddress()) = static_cast(to.m_offset); + ARMWord* addr = getLdrImmAddressOnPool(insn, m_buffer.poolAddress()); + *addr = static_cast(to.m_offset); } static void linkJump(void* code, JmpSrc from, void* to) { - linkBranch(code, from, to); + patchPointerInternal(reinterpret_cast(code) + from.m_offset, to); } static void relinkJump(void* from, void* to) @@ -831,12 +882,12 @@ namespace JSC { static void linkCall(void* code, JmpSrc from, void* to) { - linkBranch(code, from, to, true); + patchPointerInternal(reinterpret_cast(code) + from.m_offset, to); } static void relinkCall(void* from, void* to) { - relinkJump(from, to); + patchPointerInternal(reinterpret_cast(from) - sizeof(ARMWord), to); } // Address operations @@ -890,9 +941,18 @@ namespace JSC { void moveImm(ARMWord imm, int dest); ARMWord encodeComplexImm(ARMWord imm, int dest); + ARMWord getOffsetForHalfwordDataTransfer(ARMWord imm, int tmpReg) + { + // Encode immediate data in the instruction if it is possible + if (imm <= 0xff) + return getOp2Byte(imm); + // Otherwise, store the data in a temporary register + return encodeComplexImm(imm, tmpReg); + } + // Memory load/store helpers - void dataTransfer32(bool isLoad, RegisterID srcDst, RegisterID base, int32_t offset); + void dataTransfer32(bool isLoad, RegisterID srcDst, RegisterID base, int32_t offset, bool bytes = false); void baseIndexTransfer32(bool isLoad, RegisterID srcDst, RegisterID base, RegisterID index, int scale, int32_t offset); void doubleTransfer(bool isLoad, FPRegisterID srcDst, RegisterID base, int32_t offset); @@ -919,6 +979,23 @@ namespace JSC { return names[reg]; } + static char const * nameFpRegD(int reg) + { + ASSERT(reg <= 31); + ASSERT(reg >= 0); + static char const * names[] = { + "d0", "d1", "d2", "d3", + "d4", "d5", "d6", "d7", + "d8", "d9", "d10", "d11", + "d12", "d13", "d14", "d15", + "d16", "d17", "d18", "d19", + "d20", "d21", "d22", "d23", + "d24", "d25", "d26", "d27", + "d28", "d29", "d30", "d31" + }; + return names[reg]; + } + static char const * nameCC(Condition cc) { ASSERT(cc <= AL); @@ -1046,6 +1123,27 @@ namespace JSC { return reg << 16; } + ARMWord DD(int reg) + { + ASSERT(reg <= ARMRegisters::d31); + // Endoded as bits [22,15:12]. + return ((reg << 12) | (reg << 18)) & 0x0040f000; + } + + ARMWord DN(int reg) + { + ASSERT(reg <= ARMRegisters::d31); + // Endoded as bits [7,19:16]. + return ((reg << 16) | (reg << 3)) & 0x000f0080; + } + + ARMWord DM(int reg) + { + ASSERT(reg <= ARMRegisters::d31); + // Encoded as bits [5,3:0]. + return ((reg << 1) & 0x20) | (reg & 0xf); + } + static ARMWord getConditionalField(ARMWord i) { return i & 0xf0000000; diff --git a/js/src/assembler/assembler/ARMv7Assembler.h b/js/src/assembler/assembler/ARMv7Assembler.h index b894a8adef47..4de9a2a46f96 100644 --- a/js/src/assembler/assembler/ARMv7Assembler.h +++ b/js/src/assembler/assembler/ARMv7Assembler.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2009 Apple Inc. All rights reserved. + * Copyright (C) 2010 University of Szeged * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -33,6 +34,7 @@ #include "AssemblerBuffer.h" #include "assembler/wtf/Assertions.h" #include "assembler/wtf/Vector.h" +#include namespace JSC { @@ -581,11 +583,13 @@ private: OP_MOV_reg_T1 = 0x4600, OP_BLX = 0x4700, OP_BX = 0x4700, - OP_LDRH_reg_T1 = 0x5A00, OP_STR_reg_T1 = 0x5000, OP_LDR_reg_T1 = 0x5800, + OP_LDRH_reg_T1 = 0x5A00, + OP_LDRB_reg_T1 = 0x5C00, OP_STR_imm_T1 = 0x6000, OP_LDR_imm_T1 = 0x6800, + OP_LDRB_imm_T1 = 0x7800, OP_LDRH_imm_T1 = 0x8800, OP_STR_imm_T2 = 0x9000, OP_LDR_imm_T2 = 0x9800, @@ -630,12 +634,15 @@ private: OP_SUB_imm_T4 = 0xF2A0, OP_MOVT = 0xF2C0, OP_NOP_T2a = 0xF3AF, + OP_LDRB_imm_T3 = 0xF810, + OP_LDRB_reg_T2 = 0xF810, OP_LDRH_reg_T2 = 0xF830, OP_LDRH_imm_T3 = 0xF830, OP_STR_imm_T4 = 0xF840, OP_STR_reg_T2 = 0xF840, OP_LDR_imm_T4 = 0xF850, OP_LDR_reg_T2 = 0xF850, + OP_LDRB_imm_T2 = 0xF890, OP_LDRH_imm_T2 = 0xF8B0, OP_STR_imm_T3 = 0xF8C0, OP_LDR_imm_T3 = 0xF8D0, @@ -1079,6 +1086,52 @@ public: m_formatter.twoWordOp12Reg4FourFours(OP_LDRH_reg_T2, rn, FourFours(rt, 0, shift, rm)); } + void ldrb(RegisterID rt, RegisterID rn, ARMThumbImmediate imm) + { + ASSERT(rn != ARMRegisters::pc); // LDR (literal) + ASSERT(imm.isUInt12()); + + if (!((rt | rn) & 8) && imm.isUInt5()) + m_formatter.oneWordOp5Imm5Reg3Reg3(OP_LDRB_imm_T1, imm.getUInt5(), rn, rt); + else + m_formatter.twoWordOp12Reg4Reg4Imm12(OP_LDRB_imm_T2, rn, rt, imm.getUInt12()); + } + + void ldrb(RegisterID rt, RegisterID rn, int offset, bool index, bool wback) + { + ASSERT(rt != ARMRegisters::pc); + ASSERT(rn != ARMRegisters::pc); + ASSERT(index || wback); + ASSERT(!wback | (rt != rn)); + + bool add = true; + if (offset < 0) { + add = false; + offset = -offset; + } + + ASSERT(!(offset & ~0xff)); + + offset |= (wback << 8); + offset |= (add << 9); + offset |= (index << 10); + offset |= (1 << 11); + + m_formatter.twoWordOp12Reg4Reg4Imm12(OP_LDRB_imm_T3, rn, rt, offset); + } + + void ldrb(RegisterID rt, RegisterID rn, RegisterID rm, unsigned shift = 0) + { + ASSERT(rn != ARMRegisters::pc); // LDR (literal) + ASSERT(!BadReg(rm)); + ASSERT(shift <= 3); + + if (!shift && !((rt | rn | rm) & 8)) + m_formatter.oneWordOp7Reg3Reg3Reg3(OP_LDRB_reg_T1, rm, rn, rt); + else + m_formatter.twoWordOp12Reg4FourFours(OP_LDRB_reg_T2, rn, FourFours(rt, 0, shift, rm)); + } + void lsl(RegisterID rd, RegisterID rm, int32_t shiftAmount) { ASSERT(!BadReg(rd)); @@ -1717,7 +1770,20 @@ private: || (isNOP_T1(instruction - 5) && isNOP_T2(instruction - 4) && isB(instruction - 2)) ); intptr_t relative = reinterpret_cast(target) - (reinterpret_cast(instruction)); - if (((relative << 7) >> 7) == relative) { + + // From Cortex-A8 errata: + // If the 32-bit Thumb-2 branch instruction spans two 4KiB regions and + // the target of the branch falls within the first region it is + // possible for the processor to incorrectly determine the branch + // instruction, and it is also possible in some cases for the processor + // to enter a deadlock state. + // The instruction is spanning two pages if it ends at an address ending 0x002 + bool spansTwo4K = ((reinterpret_cast(instruction) & 0xfff) == 0x002); + // The target is in the first page if the jump branch back by [3..0x1002] bytes + bool targetInFirstPage = (relative >= -0x1002) && (relative < -2); + bool wouldTriggerA8Errata = spansTwo4K && targetInFirstPage; + + if (((relative << 7) >> 7) == relative && !wouldTriggerA8Errata) { // ARM encoding for the top two bits below the sign bit is 'peculiar'. if (relative >= 0) relative ^= 0xC00000; diff --git a/js/src/assembler/assembler/AbstractMacroAssembler.h b/js/src/assembler/assembler/AbstractMacroAssembler.h index 814257282df6..df61e6728fef 100644 --- a/js/src/assembler/assembler/AbstractMacroAssembler.h +++ b/js/src/assembler/assembler/AbstractMacroAssembler.h @@ -53,6 +53,12 @@ public: typedef typename AssemblerType::JmpSrc JmpSrc; typedef typename AssemblerType::JmpDst JmpDst; +#ifdef DEBUG + void setSpewPath(bool isOOLPath) + { + m_assembler.isOOLPath = isOOLPath; + } +#endif // Section 1: MacroAssembler operand types // diff --git a/js/src/assembler/assembler/MacroAssemblerARM.h b/js/src/assembler/assembler/MacroAssemblerARM.h index ad191763e05c..5fc482daabeb 100644 --- a/js/src/assembler/assembler/MacroAssemblerARM.h +++ b/js/src/assembler/assembler/MacroAssemblerARM.h @@ -187,6 +187,20 @@ public: { m_assembler.movs_r(dest, m_assembler.asr(dest, imm.m_value & 0x1f)); } + + void urshift32(RegisterID shift_amount, RegisterID dest) + { + ARMWord w = ARMAssembler::getOp2(0x1f); + ASSERT(w != ARMAssembler::INVALID_IMM); + m_assembler.and_r(ARMRegisters::S0, shift_amount, w); + + m_assembler.movs_r(dest, m_assembler.lsr_r(dest, ARMRegisters::S0)); + } + + void urshift32(Imm32 imm, RegisterID dest) + { + m_assembler.movs_r(dest, m_assembler.lsr(dest, imm.m_value & 0x1f)); + } void sub32(RegisterID src, RegisterID dest) { @@ -227,6 +241,17 @@ public: m_assembler.eors_r(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0)); } + void xor32(Address src, RegisterID dest) + { + load32(src, ARMRegisters::S1); + m_assembler.eors_r(dest, dest, ARMRegisters::S1); + } + + void load8(ImplicitAddress address, RegisterID dest) + { + m_assembler.dataTransfer32(true, dest, address.base, address.offset, true); + } + void load32(ImplicitAddress address, RegisterID dest) { m_assembler.dataTransfer32(true, dest, address.base, address.offset); @@ -263,11 +288,16 @@ public: void load16(BaseIndex address, RegisterID dest) { - m_assembler.add_r(ARMRegisters::S0, address.base, m_assembler.lsl(address.index, address.scale)); - if (address.offset>=0) - m_assembler.ldrh_u(dest, ARMRegisters::S0, ARMAssembler::getOp2Byte(address.offset)); + m_assembler.add_r(ARMRegisters::S1, address.base, m_assembler.lsl(address.index, address.scale)); + load16(Address(ARMRegisters::S1, address.offset), dest); + } + + void load16(ImplicitAddress address, RegisterID dest) + { + if (address.offset >= 0) + m_assembler.ldrh_u(dest, address.base, m_assembler.getOffsetForHalfwordDataTransfer(address.offset, ARMRegisters::S0)); else - m_assembler.ldrh_d(dest, ARMRegisters::S0, ARMAssembler::getOp2Byte(-address.offset)); + m_assembler.ldrh_d(dest, address.base, m_assembler.getOffsetForHalfwordDataTransfer(-address.offset, ARMRegisters::S0)); } DataLabel32 store32WithAddressOffsetPatch(RegisterID src, Address address) @@ -381,6 +411,12 @@ public: move(src, dest); } + Jump branch8(Condition cond, Address left, Imm32 right) + { + load8(left, ARMRegisters::S1); + return branch32(cond, ARMRegisters::S1, right); + } + Jump branch32(Condition cond, RegisterID left, RegisterID right, int useConstantPool = 0) { m_assembler.cmp_r(left, right); @@ -444,6 +480,12 @@ public: return m_assembler.jmp(ARMCondition(cond)); } + Jump branchTest8(Condition cond, Address address, Imm32 mask = Imm32(-1)) + { + load8(address, ARMRegisters::S1); + return branchTest32(cond, ARMRegisters::S1, mask); + } + Jump branchTest32(Condition cond, RegisterID reg, RegisterID mask) { ASSERT((cond == Zero) || (cond == NonZero)); @@ -481,7 +523,7 @@ public: void jump(RegisterID target) { - m_assembler.bx_r(target); + m_assembler.bx(target); } void jump(Address address) @@ -503,6 +545,13 @@ public: return Jump(m_assembler.jmp(ARMCondition(cond))); } + Jump branchAdd32(Condition cond, Address src, RegisterID dest) + { + ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); + add32(src, dest); + return Jump(m_assembler.jmp(ARMCondition(cond))); + } + void mull32(RegisterID src1, RegisterID src2, RegisterID dest) { if (src1 == dest) { @@ -552,6 +601,20 @@ public: return Jump(m_assembler.jmp(ARMCondition(cond))); } + Jump branchSub32(Condition cond, Address src, RegisterID dest) + { + ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); + sub32(src, dest); + return Jump(m_assembler.jmp(ARMCondition(cond))); + } + + Jump branchNeg32(Condition cond, RegisterID srcDest) + { + ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); + neg32(srcDest); + return Jump(m_assembler.jmp(ARMCondition(cond))); + } + Jump branchOr32(Condition cond, RegisterID src, RegisterID dest) { ASSERT((cond == Signed) || (cond == Zero) || (cond == NonZero)); @@ -568,7 +631,7 @@ public: { #if WTF_ARM_ARCH_VERSION >= 5 Call call(m_assembler.loadBranchTarget(ARMRegisters::S1, ARMAssembler::AL, true), Call::LinkableNear); - m_assembler.blx_r(ARMRegisters::S1); + m_assembler.blx(ARMRegisters::S1); return call; #else prepareCall(); @@ -578,7 +641,7 @@ public: Call call(RegisterID target) { - m_assembler.blx_r(target); + m_assembler.blx(target); JmpSrc jmpSrc; return Call(jmpSrc, Call::None); } @@ -590,7 +653,7 @@ public: void ret() { - m_assembler.bx_r(linkRegister); + m_assembler.bx(linkRegister); } void set32(Condition cond, Address left, RegisterID right, RegisterID dest) @@ -619,6 +682,12 @@ public: m_assembler.mov_r(dest, ARMAssembler::getOp2(1), ARMCondition(cond)); } + void set32(Condition cond, Address left, Imm32 right, RegisterID dest) + { + load32(left, ARMRegisters::S1); + set32(cond, ARMRegisters::S1, right, dest); + } + void set8(Condition cond, RegisterID left, RegisterID right, RegisterID dest) { // ARM doesn't have byte registers @@ -717,7 +786,7 @@ public: { #if WTF_ARM_ARCH_VERSION >= 5 Call call(m_assembler.loadBranchTarget(ARMRegisters::S1, ARMAssembler::AL, true), Call::Linkable); - m_assembler.blx_r(ARMRegisters::S1); + m_assembler.blx(ARMRegisters::S1); return call; #else prepareCall(); @@ -780,12 +849,17 @@ public: return false; } + bool supportsFloatingPointSqrt() const + { + return s_isVFPPresent; + } + void loadDouble(ImplicitAddress address, FPRegisterID dest) { m_assembler.doubleTransfer(true, dest, address.base, address.offset); } - void loadDouble(void* address, FPRegisterID dest) + void loadDouble(const void* address, FPRegisterID dest) { m_assembler.ldr_un_imm(ARMRegisters::S0, (ARMWord)address); m_assembler.fdtr_u(true, dest, ARMRegisters::S0, 0); @@ -841,6 +915,16 @@ public: mulDouble(ARMRegisters::SD0, dest); } + void negDouble(FPRegisterID src, FPRegisterID dest) + { + m_assembler.fnegd_r(dest, src); + } + + void sqrtDouble(FPRegisterID src, FPRegisterID dest) + { + m_assembler.fsqrtd_r(dest, src); + } + void convertInt32ToDouble(RegisterID src, FPRegisterID dest) { m_assembler.fmsr_r(dest, src); @@ -927,46 +1011,58 @@ protected: #if WTF_ARM_ARCH_VERSION < 5 void prepareCall() { +#if WTF_ARM_ARCH_VERSION < 5 ensureSpace(2 * sizeof(ARMWord), sizeof(ARMWord)); m_assembler.mov_r(linkRegister, ARMRegisters::pc); +#endif } #endif #if WTF_ARM_ARCH_VERSION < 5 void call32(RegisterID base, int32_t offset) { +#if WTF_ARM_ARCH_VERSION >= 5 + int targetReg = ARMRegisters::S1; +#else + int targetReg = ARMRegisters::pc; +#endif + int tmpReg = ARMRegisters::S1; + if (base == ARMRegisters::sp) offset += 4; if (offset >= 0) { if (offset <= 0xfff) { prepareCall(); - m_assembler.dtr_u(true, ARMRegisters::pc, base, offset); + m_assembler.dtr_u(true, targetReg, base, offset); } else if (offset <= 0xfffff) { - m_assembler.add_r(ARMRegisters::S0, base, ARMAssembler::OP2_IMM | (offset >> 12) | (10 << 8)); + m_assembler.add_r(tmpReg, base, ARMAssembler::OP2_IMM | (offset >> 12) | (10 << 8)); prepareCall(); - m_assembler.dtr_u(true, ARMRegisters::pc, ARMRegisters::S0, offset & 0xfff); + m_assembler.dtr_u(true, targetReg, tmpReg, offset & 0xfff); } else { - ARMWord reg = m_assembler.getImm(offset, ARMRegisters::S0); + ARMWord reg = m_assembler.getImm(offset, tmpReg); prepareCall(); - m_assembler.dtr_ur(true, ARMRegisters::pc, base, reg); + m_assembler.dtr_ur(true, targetReg, base, reg); } } else { offset = -offset; if (offset <= 0xfff) { prepareCall(); - m_assembler.dtr_d(true, ARMRegisters::pc, base, offset); + m_assembler.dtr_d(true, targetReg, base, offset); } else if (offset <= 0xfffff) { - m_assembler.sub_r(ARMRegisters::S0, base, ARMAssembler::OP2_IMM | (offset >> 12) | (10 << 8)); + m_assembler.sub_r(tmpReg, base, ARMAssembler::OP2_IMM | (offset >> 12) | (10 << 8)); prepareCall(); - m_assembler.dtr_d(true, ARMRegisters::pc, ARMRegisters::S0, offset & 0xfff); + m_assembler.dtr_d(true, targetReg, tmpReg, offset & 0xfff); } else { - ARMWord reg = m_assembler.getImm(offset, ARMRegisters::S0); + ARMWord reg = m_assembler.getImm(offset, tmpReg); prepareCall(); - m_assembler.dtr_dr(true, ARMRegisters::pc, base, reg); + m_assembler.dtr_dr(true, targetReg, base, reg); } } +#if WTF_ARM_ARCH_VERSION >= 5 + m_assembler.blx(targetReg); +#endif } #else void call32(RegisterID base, int32_t offset) @@ -1011,7 +1107,7 @@ protected: m_assembler.dtr_dr(true, ARMRegisters::S0, base, reg); } } - m_assembler.blx_r(ARMRegisters::S0); + m_assembler.blx(ARMRegisters::S0); } #endif diff --git a/js/src/assembler/assembler/MacroAssemblerARMv7.h b/js/src/assembler/assembler/MacroAssemblerARMv7.h index ab61865be0cd..089caf44b291 100644 --- a/js/src/assembler/assembler/MacroAssemblerARMv7.h +++ b/js/src/assembler/assembler/MacroAssemblerARMv7.h @@ -259,6 +259,21 @@ public: { m_assembler.asr(dest, dest, imm.m_value & 0x1f); } + + void urshift32(RegisterID shift_amount, RegisterID dest) + { + // Clamp the shift to the range 0..31 + ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(0x1f); + ASSERT(armImm.isValid()); + m_assembler.ARM_and(dataTempRegister, shift_amount, armImm); + + m_assembler.lsr(dest, dest, dataTempRegister); + } + + void urshift32(Imm32 imm, RegisterID dest) + { + m_assembler.lsr(dest, dest, imm.m_value & 0x1f); + } void sub32(RegisterID src, RegisterID dest) { @@ -369,6 +384,20 @@ private: } } + void load8(ArmAddress address, RegisterID dest) + { + if (address.type == ArmAddress::HasIndex) + m_assembler.ldrb(dest, address.base, address.u.index, address.u.scale); + else if (address.u.offset >= 0) { + ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset); + ASSERT(armImm.isValid()); + m_assembler.ldrb(dest, address.base, armImm); + } else { + ASSERT(address.u.offset >= -255); + m_assembler.ldrb(dest, address.base, address.u.offset, true, false); + } + } + void store32(RegisterID src, ArmAddress address) { if (address.type == ArmAddress::HasIndex) @@ -405,6 +434,11 @@ public: m_assembler.ldr(dest, addressTempRegister, ARMThumbImmediate::makeUInt16(0)); } + void load8(ImplicitAddress address, RegisterID dest) + { + load8(setupArmAddress(address), dest); + } + DataLabel32 load32WithAddressOffsetPatch(Address address, RegisterID dest) { DataLabel32 label = moveWithPatch(Imm32(address.offset), dataTempRegister); @@ -424,6 +458,11 @@ public: { m_assembler.ldrh(dest, makeBaseIndexBase(address), address.index, address.scale); } + + void load16(ImplicitAddress address, RegisterID dest) + { + m_assembler.ldrh(dest, address.base, address.offset); + } DataLabel32 store32WithAddressOffsetPatch(RegisterID src, Address address) { @@ -477,6 +516,11 @@ public: // In short, FIXME:. bool supportsFloatingPointTruncate() const { return false; } + bool supportsFloatingPointSqrt() const + { + return false; + } + void loadDouble(ImplicitAddress address, FPRegisterID dest) { RegisterID base = address.base; @@ -540,6 +584,11 @@ public: mulDouble(fpTempRegister, dest); } + void sqrtDouble(FPRegisterID, FPRegisterID) + { + ASSERT_NOT_REACHED(); + } + void convertInt32ToDouble(RegisterID src, FPRegisterID dest) { m_assembler.vmov(fpTempRegister, src); @@ -794,6 +843,19 @@ public: return branch32(cond, addressTempRegister, Imm32(right.m_value << 16)); } + Jump branch8(Condition cond, RegisterID left, Imm32 right) + { + compare32(left, right); + return Jump(makeBranch(cond)); + } + + Jump branch8(Condition cond, Address left, Imm32 right) + { + // use addressTempRegister incase the branch8 we call uses dataTempRegister. :-/ + load8(left, addressTempRegister); + return branch8(cond, addressTempRegister, right); + } + Jump branchTest32(Condition cond, RegisterID reg, RegisterID mask) { ASSERT((cond == Zero) || (cond == NonZero)); @@ -824,6 +886,21 @@ public: return branchTest32(cond, addressTempRegister, mask); } + Jump branchTest8(Condition cond, RegisterID reg, Imm32 mask = Imm32(-1)) + { + ASSERT((cond == Zero) || (cond == NonZero)); + test32(reg, mask); + return Jump(makeBranch(cond)); + } + + Jump branchTest8(Condition cond, Address address, Imm32 mask = Imm32(-1)) + { + ASSERT((cond == Zero) || (cond == NonZero)); + // use addressTempRegister incase the branchTest8 we call uses dataTempRegister. :-/ + load8(address, addressTempRegister); + return branchTest8(cond, addressTempRegister, mask); + } + Jump jump() { return Jump(makeJump()); @@ -974,6 +1051,14 @@ public: m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0)); } + void setTest8(Condition cond, Address address, Imm32 mask, RegisterID dest) + { + load8(address, dataTempRegister); + test32(dataTempRegister, mask); + m_assembler.it(armV7Condition(cond), false); + m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(1)); + m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0)); + } DataLabel32 moveWithPatch(Imm32 imm, RegisterID dst) { diff --git a/js/src/assembler/moco/MocoStubs.h b/js/src/assembler/moco/MocoStubs.h index e699c7a2ba48..0386906420d3 100644 --- a/js/src/assembler/moco/MocoStubs.h +++ b/js/src/assembler/moco/MocoStubs.h @@ -69,3 +69,6 @@ private: }; } // namespace JSC + +#endif /* _include_assembler_moco_stubs_h_ */ +