123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445 |
- /*
- * Copyright (C) 2009 University of Szeged
- * 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 UNIVERSITY OF SZEGED ``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 UNIVERSITY OF SZEGED 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.
- */
- #include "config.h"
- #if ENABLE(ASSEMBLER) && CPU(ARM_TRADITIONAL)
- #include "ARMAssembler.h"
- namespace JSC {
- // Patching helpers
- void ARMAssembler::patchConstantPoolLoad(void* loadAddr, void* constPoolAddr)
- {
- ARMWord *ldr = reinterpret_cast<ARMWord*>(loadAddr);
- ARMWord diff = reinterpret_cast<ARMWord*>(constPoolAddr) - ldr;
- ARMWord index = (*ldr & 0xfff) >> 1;
- ASSERT(diff >= 1);
- if (diff >= 2 || index > 0) {
- diff = (diff + index - 2) * sizeof(ARMWord);
- ASSERT(diff <= 0xfff);
- *ldr = (*ldr & ~0xfff) | diff;
- } else
- *ldr = (*ldr & ~(0xfff | ARMAssembler::DataTransferUp)) | sizeof(ARMWord);
- }
- // Handle immediates
- ARMWord ARMAssembler::getOp2(ARMWord imm)
- {
- int rol;
- if (imm <= 0xff)
- return Op2Immediate | imm;
- if ((imm & 0xff000000) == 0) {
- imm <<= 8;
- rol = 8;
- }
- else {
- imm = (imm << 24) | (imm >> 8);
- rol = 0;
- }
- if ((imm & 0xff000000) == 0) {
- imm <<= 8;
- rol += 4;
- }
- if ((imm & 0xf0000000) == 0) {
- imm <<= 4;
- rol += 2;
- }
- if ((imm & 0xc0000000) == 0) {
- imm <<= 2;
- rol += 1;
- }
- if ((imm & 0x00ffffff) == 0)
- return Op2Immediate | (imm >> 24) | (rol << 8);
- return InvalidImmediate;
- }
- int ARMAssembler::genInt(int reg, ARMWord imm, bool positive)
- {
- // Step1: Search a non-immediate part
- ARMWord mask;
- ARMWord imm1;
- ARMWord imm2;
- int rol;
- mask = 0xff000000;
- rol = 8;
- while(1) {
- if ((imm & mask) == 0) {
- imm = (imm << rol) | (imm >> (32 - rol));
- rol = 4 + (rol >> 1);
- break;
- }
- rol += 2;
- mask >>= 2;
- if (mask & 0x3) {
- // rol 8
- imm = (imm << 8) | (imm >> 24);
- mask = 0xff00;
- rol = 24;
- while (1) {
- if ((imm & mask) == 0) {
- imm = (imm << rol) | (imm >> (32 - rol));
- rol = (rol >> 1) - 8;
- break;
- }
- rol += 2;
- mask >>= 2;
- if (mask & 0x3)
- return 0;
- }
- break;
- }
- }
- ASSERT((imm & 0xff) == 0);
- if ((imm & 0xff000000) == 0) {
- imm1 = Op2Immediate | ((imm >> 16) & 0xff) | (((rol + 4) & 0xf) << 8);
- imm2 = Op2Immediate | ((imm >> 8) & 0xff) | (((rol + 8) & 0xf) << 8);
- } else if (imm & 0xc0000000) {
- imm1 = Op2Immediate | ((imm >> 24) & 0xff) | ((rol & 0xf) << 8);
- imm <<= 8;
- rol += 4;
- if ((imm & 0xff000000) == 0) {
- imm <<= 8;
- rol += 4;
- }
- if ((imm & 0xf0000000) == 0) {
- imm <<= 4;
- rol += 2;
- }
- if ((imm & 0xc0000000) == 0) {
- imm <<= 2;
- rol += 1;
- }
- if ((imm & 0x00ffffff) == 0)
- imm2 = Op2Immediate | (imm >> 24) | ((rol & 0xf) << 8);
- else
- return 0;
- } else {
- if ((imm & 0xf0000000) == 0) {
- imm <<= 4;
- rol += 2;
- }
- if ((imm & 0xc0000000) == 0) {
- imm <<= 2;
- rol += 1;
- }
- imm1 = Op2Immediate | ((imm >> 24) & 0xff) | ((rol & 0xf) << 8);
- imm <<= 8;
- rol += 4;
- if ((imm & 0xf0000000) == 0) {
- imm <<= 4;
- rol += 2;
- }
- if ((imm & 0xc0000000) == 0) {
- imm <<= 2;
- rol += 1;
- }
- if ((imm & 0x00ffffff) == 0)
- imm2 = Op2Immediate | (imm >> 24) | ((rol & 0xf) << 8);
- else
- return 0;
- }
- if (positive) {
- mov(reg, imm1);
- orr(reg, reg, imm2);
- } else {
- mvn(reg, imm1);
- bic(reg, reg, imm2);
- }
- return 1;
- }
- ARMWord ARMAssembler::getImm(ARMWord imm, int tmpReg, bool invert)
- {
- ARMWord tmp;
- // Do it by 1 instruction
- tmp = getOp2(imm);
- if (tmp != InvalidImmediate)
- return tmp;
- tmp = getOp2(~imm);
- if (tmp != InvalidImmediate) {
- if (invert)
- return tmp | Op2InvertedImmediate;
- mvn(tmpReg, tmp);
- return tmpReg;
- }
- return encodeComplexImm(imm, tmpReg);
- }
- void ARMAssembler::moveImm(ARMWord imm, int dest)
- {
- ARMWord tmp;
- // Do it by 1 instruction
- tmp = getOp2(imm);
- if (tmp != InvalidImmediate) {
- mov(dest, tmp);
- return;
- }
- tmp = getOp2(~imm);
- if (tmp != InvalidImmediate) {
- mvn(dest, tmp);
- return;
- }
- encodeComplexImm(imm, dest);
- }
- ARMWord ARMAssembler::encodeComplexImm(ARMWord imm, int dest)
- {
- #if WTF_ARM_ARCH_AT_LEAST(7)
- ARMWord tmp = getImm16Op2(imm);
- if (tmp != InvalidImmediate) {
- movw(dest, tmp);
- return dest;
- }
- movw(dest, getImm16Op2(imm & 0xffff));
- movt(dest, getImm16Op2(imm >> 16));
- return dest;
- #else
- // Do it by 2 instruction
- if (genInt(dest, imm, true))
- return dest;
- if (genInt(dest, ~imm, false))
- return dest;
- ldrImmediate(dest, imm);
- return dest;
- #endif
- }
- // Memory load/store helpers
- void ARMAssembler::dataTransfer32(DataTransferTypeA transferType, RegisterID srcDst, RegisterID base, int32_t offset)
- {
- if (offset >= 0) {
- if (offset <= 0xfff)
- dtrUp(transferType, srcDst, base, offset);
- else if (offset <= 0xfffff) {
- add(ARMRegisters::S0, base, Op2Immediate | (offset >> 12) | (10 << 8));
- dtrUp(transferType, srcDst, ARMRegisters::S0, (offset & 0xfff));
- } else {
- moveImm(offset, ARMRegisters::S0);
- dtrUpRegister(transferType, srcDst, base, ARMRegisters::S0);
- }
- } else {
- if (offset >= -0xfff)
- dtrDown(transferType, srcDst, base, -offset);
- else if (offset >= -0xfffff) {
- sub(ARMRegisters::S0, base, Op2Immediate | (-offset >> 12) | (10 << 8));
- dtrDown(transferType, srcDst, ARMRegisters::S0, (-offset & 0xfff));
- } else {
- moveImm(offset, ARMRegisters::S0);
- dtrUpRegister(transferType, srcDst, base, ARMRegisters::S0);
- }
- }
- }
- void ARMAssembler::baseIndexTransfer32(DataTransferTypeA transferType, RegisterID srcDst, RegisterID base, RegisterID index, int scale, int32_t offset)
- {
- ASSERT(scale >= 0 && scale <= 3);
- ARMWord op2 = lsl(index, scale);
- if (!offset) {
- dtrUpRegister(transferType, srcDst, base, op2);
- return;
- }
- if (offset <= 0xfffff && offset >= -0xfffff) {
- add(ARMRegisters::S0, base, op2);
- dataTransfer32(transferType, srcDst, ARMRegisters::S0, offset);
- return;
- }
- moveImm(offset, ARMRegisters::S0);
- add(ARMRegisters::S0, ARMRegisters::S0, op2);
- dtrUpRegister(transferType, srcDst, base, ARMRegisters::S0);
- }
- void ARMAssembler::dataTransfer16(DataTransferTypeB transferType, RegisterID srcDst, RegisterID base, int32_t offset)
- {
- if (offset >= 0) {
- if (offset <= 0xff)
- halfDtrUp(transferType, srcDst, base, getOp2Half(offset));
- else if (offset <= 0xffff) {
- add(ARMRegisters::S0, base, Op2Immediate | (offset >> 8) | (12 << 8));
- halfDtrUp(transferType, srcDst, ARMRegisters::S0, getOp2Half(offset & 0xff));
- } else {
- moveImm(offset, ARMRegisters::S0);
- halfDtrUpRegister(transferType, srcDst, base, ARMRegisters::S0);
- }
- } else {
- if (offset >= -0xff)
- halfDtrDown(transferType, srcDst, base, getOp2Half(-offset));
- else if (offset >= -0xffff) {
- sub(ARMRegisters::S0, base, Op2Immediate | (-offset >> 8) | (12 << 8));
- halfDtrDown(transferType, srcDst, ARMRegisters::S0, getOp2Half(-offset & 0xff));
- } else {
- moveImm(offset, ARMRegisters::S0);
- halfDtrUpRegister(transferType, srcDst, base, ARMRegisters::S0);
- }
- }
- }
- void ARMAssembler::baseIndexTransfer16(DataTransferTypeB transferType, RegisterID srcDst, RegisterID base, RegisterID index, int scale, int32_t offset)
- {
- if (!scale && !offset) {
- halfDtrUpRegister(transferType, srcDst, base, index);
- return;
- }
- ARMWord op2 = lsl(index, scale);
- if (offset <= 0xffff && offset >= -0xffff) {
- add(ARMRegisters::S0, base, op2);
- dataTransfer16(transferType, srcDst, ARMRegisters::S0, offset);
- return;
- }
- moveImm(offset, ARMRegisters::S0);
- add(ARMRegisters::S0, ARMRegisters::S0, op2);
- halfDtrUpRegister(transferType, srcDst, base, ARMRegisters::S0);
- }
- void ARMAssembler::dataTransferFloat(DataTransferTypeFloat transferType, FPRegisterID srcDst, RegisterID base, int32_t offset)
- {
- // VFP cannot directly access memory that is not four-byte-aligned
- if (!(offset & 0x3)) {
- if (offset <= 0x3ff && offset >= 0) {
- doubleDtrUp(transferType, srcDst, base, offset >> 2);
- return;
- }
- if (offset <= 0x3ffff && offset >= 0) {
- add(ARMRegisters::S0, base, Op2Immediate | (offset >> 10) | (11 << 8));
- doubleDtrUp(transferType, srcDst, ARMRegisters::S0, (offset >> 2) & 0xff);
- return;
- }
- offset = -offset;
- if (offset <= 0x3ff && offset >= 0) {
- doubleDtrDown(transferType, srcDst, base, offset >> 2);
- return;
- }
- if (offset <= 0x3ffff && offset >= 0) {
- sub(ARMRegisters::S0, base, Op2Immediate | (offset >> 10) | (11 << 8));
- doubleDtrDown(transferType, srcDst, ARMRegisters::S0, (offset >> 2) & 0xff);
- return;
- }
- offset = -offset;
- }
- moveImm(offset, ARMRegisters::S0);
- add(ARMRegisters::S0, ARMRegisters::S0, base);
- doubleDtrUp(transferType, srcDst, ARMRegisters::S0, 0);
- }
- void ARMAssembler::baseIndexTransferFloat(DataTransferTypeFloat transferType, FPRegisterID srcDst, RegisterID base, RegisterID index, int scale, int32_t offset)
- {
- add(ARMRegisters::S1, base, lsl(index, scale));
- dataTransferFloat(transferType, srcDst, ARMRegisters::S1, offset);
- }
- PassRefPtr<ExecutableMemoryHandle> ARMAssembler::executableCopy(VM& vm, void* ownerUID, JITCompilationEffort effort)
- {
- // 64-bit alignment is required for next constant pool and JIT code as well
- m_buffer.flushWithoutBarrier(true);
- if (!m_buffer.isAligned(8))
- bkpt(0);
- RefPtr<ExecutableMemoryHandle> result = m_buffer.executableCopy(vm, ownerUID, effort);
- char* data = reinterpret_cast<char*>(result->start());
- for (Jumps::Iterator iter = m_jumps.begin(); iter != m_jumps.end(); ++iter) {
- // The last bit is set if the constant must be placed on constant pool.
- int pos = (iter->m_offset) & (~0x1);
- ARMWord* ldrAddr = reinterpret_cast_ptr<ARMWord*>(data + pos);
- ARMWord* addr = getLdrImmAddress(ldrAddr);
- if (*addr != InvalidBranchTarget) {
- if (!(iter->m_offset & 1)) {
- intptr_t difference = reinterpret_cast_ptr<ARMWord*>(data + *addr) - (ldrAddr + DefaultPrefetchOffset);
- if ((difference <= MaximumBranchOffsetDistance && difference >= MinimumBranchOffsetDistance)) {
- *ldrAddr = B | getConditionalField(*ldrAddr) | (difference & BranchOffsetMask);
- continue;
- }
- }
- *addr = reinterpret_cast<ARMWord>(data + *addr);
- }
- }
- return result;
- }
- #if OS(LINUX) && COMPILER(RVCT)
- __asm void ARMAssembler::cacheFlush(void* code, size_t size)
- {
- ARM
- push {r7}
- add r1, r1, r0
- mov r7, #0xf0000
- add r7, r7, #0x2
- mov r2, #0x0
- svc #0x0
- pop {r7}
- bx lr
- }
- #endif
- } // namespace JSC
- #endif // ENABLE(ASSEMBLER) && CPU(ARM_TRADITIONAL)
|